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", 55 regs->trap, regs->nip, regs->msr); 56 dump_frame_stack((void *)regs->nip, (void *)regs->gpr[1]); 57 abort(); 58 } 59 60 uint64_t get_clock_us(void) 61 { 62 return get_tb() * 1000000 / tb_hz; 63 } 64 65 uint64_t get_clock_ms(void) 66 { 67 return get_tb() * 1000 / tb_hz; 68 } 69 70 void delay(uint64_t cycles) 71 { 72 uint64_t start = get_tb(); 73 74 while ((get_tb() - start) < cycles) 75 cpu_relax(); 76 } 77 78 void udelay(uint64_t us) 79 { 80 delay((us * tb_hz) / 1000000); 81 } 82 83 void sleep_tb(uint64_t cycles) 84 { 85 uint64_t start, end, now; 86 87 start = now = get_tb(); 88 end = start + cycles; 89 90 while (end > now) { 91 uint64_t left = end - now; 92 93 /* TODO: Could support large decrementer */ 94 if (left > 0x7fffffff) 95 left = 0x7fffffff; 96 97 /* DEC won't fire until H_CEDE is called because EE=0 */ 98 asm volatile ("mtdec %0" : : "r" (left)); 99 handle_exception(0x900, &dec_handler_oneshot, NULL); 100 /* 101 * H_CEDE is called with MSR[EE] clear and enables it as part 102 * of the hcall, returning with EE enabled. The dec interrupt 103 * is then taken immediately and the handler disables EE. 104 * 105 * If H_CEDE returned for any other interrupt than dec 106 * expiring, that is considered an unhandled interrupt and 107 * the test case would be stopped. 108 */ 109 if (hcall(H_CEDE) != H_SUCCESS) { 110 printf("H_CEDE failed\n"); 111 abort(); 112 } 113 handle_exception(0x900, NULL, NULL); 114 115 now = get_tb(); 116 } 117 } 118 119 void usleep(uint64_t us) 120 { 121 sleep_tb((us * tb_hz) / 1000000); 122 } 123