1 /* 2 * processor control and status function 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU Library General Public License version 2. 6 */ 7 8 #include <libcflat.h> 9 #include <asm/processor.h> 10 #include <asm/time.h> 11 #include <asm/ptrace.h> 12 #include <asm/setup.h> 13 #include <asm/barrier.h> 14 #include <asm/hcall.h> 15 #include <asm/handlers.h> 16 17 static struct { 18 void (*func)(struct pt_regs *, void *data); 19 void *data; 20 } handlers[128]; 21 22 /* 23 * Exception handlers span from 0x100 to 0x1000 and can have a granularity 24 * of 0x20 bytes in some cases. Indexing spans 0-0x1000 with 0x20 increments 25 * resulting in 128 slots. 26 */ 27 void handle_exception(int trap, void (*func)(struct pt_regs *, void *), 28 void * data) 29 { 30 assert(!(trap & ~0xfe0)); 31 32 trap >>= 5; 33 34 if (func && handlers[trap].func) { 35 printf("exception handler installed twice %#x\n", trap << 5); 36 abort(); 37 } 38 39 handlers[trap].func = func; 40 handlers[trap].data = data; 41 } 42 43 void do_handle_exception(struct pt_regs *regs) 44 { 45 unsigned char v; 46 47 v = regs->trap >> 5; 48 49 if (v < 128 && handlers[v].func) { 50 handlers[v].func(regs, handlers[v].data); 51 return; 52 } 53 54 printf("unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", regs->trap, regs->nip, regs->msr); 55 abort(); 56 } 57 58 uint64_t get_clock_us(void) 59 { 60 return get_tb() * 1000000 / tb_hz; 61 } 62 63 uint64_t get_clock_ms(void) 64 { 65 return get_tb() * 1000 / tb_hz; 66 } 67 68 void delay(uint64_t cycles) 69 { 70 uint64_t start = get_tb(); 71 72 while ((get_tb() - start) < cycles) 73 cpu_relax(); 74 } 75 76 void udelay(uint64_t us) 77 { 78 delay((us * tb_hz) / 1000000); 79 } 80 81 void sleep_tb(uint64_t cycles) 82 { 83 uint64_t start, end, now; 84 85 start = now = get_tb(); 86 end = start + cycles; 87 88 while (end > now) { 89 uint64_t left = end - now; 90 91 /* TODO: Could support large decrementer */ 92 if (left > 0x7fffffff) 93 left = 0x7fffffff; 94 95 /* DEC won't fire until H_CEDE is called because EE=0 */ 96 asm volatile ("mtdec %0" : : "r" (left)); 97 handle_exception(0x900, &dec_handler_oneshot, NULL); 98 /* 99 * H_CEDE is called with MSR[EE] clear and enables it as part 100 * of the hcall, returning with EE enabled. The dec interrupt 101 * is then taken immediately and the handler disables EE. 102 * 103 * If H_CEDE returned for any other interrupt than dec 104 * expiring, that is considered an unhandled interrupt and 105 * the test case would be stopped. 106 */ 107 if (hcall(H_CEDE) != H_SUCCESS) { 108 printf("H_CEDE failed\n"); 109 abort(); 110 } 111 handle_exception(0x900, NULL, NULL); 112 113 now = get_tb(); 114 } 115 } 116 117 void usleep(uint64_t us) 118 { 119 sleep_tb((us * tb_hz) / 1000000); 120 } 121