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/ptrace.h> 11 #include <asm/setup.h> 12 #include <asm/barrier.h> 13 #include <asm/hcall.h> 14 #include <asm/handlers.h> 15 16 static struct { 17 void (*func)(struct pt_regs *, void *data); 18 void *data; 19 } handlers[16]; 20 21 void handle_exception(int trap, void (*func)(struct pt_regs *, void *), 22 void * data) 23 { 24 assert(!(trap & ~0xf00)); 25 26 trap >>= 8; 27 28 if (func && handlers[trap].func) { 29 printf("exception handler installed twice %#x\n", trap); 30 abort(); 31 } 32 handlers[trap].func = func; 33 handlers[trap].data = data; 34 } 35 36 void do_handle_exception(struct pt_regs *regs) 37 { 38 unsigned char v; 39 40 v = regs->trap >> 8; 41 42 if (v < 16 && handlers[v].func) { 43 handlers[v].func(regs, handlers[v].data); 44 return; 45 } 46 47 printf("unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", regs->trap, regs->nip, regs->msr); 48 abort(); 49 } 50 51 void delay(uint64_t cycles) 52 { 53 uint64_t start = get_tb(); 54 55 while ((get_tb() - start) < cycles) 56 cpu_relax(); 57 } 58 59 void udelay(uint64_t us) 60 { 61 delay((us * tb_hz) / 1000000); 62 } 63 64 void sleep_tb(uint64_t cycles) 65 { 66 uint64_t start, end, now; 67 68 start = now = get_tb(); 69 end = start + cycles; 70 71 while (end > now) { 72 uint64_t left = end - now; 73 74 /* TODO: Could support large decrementer */ 75 if (left > 0x7fffffff) 76 left = 0x7fffffff; 77 78 /* DEC won't fire until H_CEDE is called because EE=0 */ 79 asm volatile ("mtdec %0" : : "r" (left)); 80 handle_exception(0x900, &dec_handler_oneshot, NULL); 81 /* 82 * H_CEDE is called with MSR[EE] clear and enables it as part 83 * of the hcall, returning with EE enabled. The dec interrupt 84 * is then taken immediately and the handler disables EE. 85 * 86 * If H_CEDE returned for any other interrupt than dec 87 * expiring, that is considered an unhandled interrupt and 88 * the test case would be stopped. 89 */ 90 if (hcall(H_CEDE) != H_SUCCESS) { 91 printf("H_CEDE failed\n"); 92 abort(); 93 } 94 handle_exception(0x900, NULL, NULL); 95 96 now = get_tb(); 97 } 98 } 99 100 void usleep(uint64_t us) 101 { 102 sleep_tb((us * tb_hz) / 1000000); 103 } 104