16842bc34SLaurent Vivier /* 26842bc34SLaurent Vivier * processor control and status function 3b1a6fd7dSThomas Huth * 4b1a6fd7dSThomas Huth * This code is free software; you can redistribute it and/or modify it 5b1a6fd7dSThomas Huth * under the terms of the GNU Library General Public License version 2. 66842bc34SLaurent Vivier */ 76842bc34SLaurent Vivier 86842bc34SLaurent Vivier #include <libcflat.h> 96842bc34SLaurent Vivier #include <asm/processor.h> 106842bc34SLaurent Vivier #include <asm/ptrace.h> 11f4d8d939SSuraj Jitindar Singh #include <asm/setup.h> 12f4d8d939SSuraj Jitindar Singh #include <asm/barrier.h> 13ba33a96fSNicholas Piggin #include <asm/hcall.h> 14ba33a96fSNicholas Piggin #include <asm/handlers.h> 156842bc34SLaurent Vivier 166842bc34SLaurent Vivier static struct { 176842bc34SLaurent Vivier void (*func)(struct pt_regs *, void *data); 186842bc34SLaurent Vivier void *data; 190ec01e27SNicholas Piggin } handlers[128]; 206842bc34SLaurent Vivier 210ec01e27SNicholas Piggin /* 220ec01e27SNicholas Piggin * Exception handlers span from 0x100 to 0x1000 and can have a granularity 230ec01e27SNicholas Piggin * of 0x20 bytes in some cases. Indexing spans 0-0x1000 with 0x20 increments 240ec01e27SNicholas Piggin * resulting in 128 slots. 250ec01e27SNicholas Piggin */ 266842bc34SLaurent Vivier void handle_exception(int trap, void (*func)(struct pt_regs *, void *), 276842bc34SLaurent Vivier void * data) 286842bc34SLaurent Vivier { 290ec01e27SNicholas Piggin assert(!(trap & ~0xfe0)); 305d571097SNicholas Piggin 310ec01e27SNicholas Piggin trap >>= 5; 326842bc34SLaurent Vivier 335d571097SNicholas Piggin if (func && handlers[trap].func) { 34*8791cea0SNicholas Piggin printf("exception handler installed twice %#x\n", trap << 5); 355d571097SNicholas Piggin abort(); 365d571097SNicholas Piggin } 370ec01e27SNicholas Piggin 386842bc34SLaurent Vivier handlers[trap].func = func; 396842bc34SLaurent Vivier handlers[trap].data = data; 406842bc34SLaurent Vivier } 416842bc34SLaurent Vivier 426842bc34SLaurent Vivier void do_handle_exception(struct pt_regs *regs) 436842bc34SLaurent Vivier { 446842bc34SLaurent Vivier unsigned char v; 456842bc34SLaurent Vivier 460ec01e27SNicholas Piggin v = regs->trap >> 5; 476842bc34SLaurent Vivier 480ec01e27SNicholas Piggin if (v < 128 && handlers[v].func) { 496842bc34SLaurent Vivier handlers[v].func(regs, handlers[v].data); 506842bc34SLaurent Vivier return; 516842bc34SLaurent Vivier } 526842bc34SLaurent Vivier 538e458b76SNicholas Piggin printf("unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", regs->trap, regs->nip, regs->msr); 546842bc34SLaurent Vivier abort(); 556842bc34SLaurent Vivier } 56f4d8d939SSuraj Jitindar Singh 57f4d8d939SSuraj Jitindar Singh void delay(uint64_t cycles) 58f4d8d939SSuraj Jitindar Singh { 59f4d8d939SSuraj Jitindar Singh uint64_t start = get_tb(); 60f4d8d939SSuraj Jitindar Singh 61f4d8d939SSuraj Jitindar Singh while ((get_tb() - start) < cycles) 62f4d8d939SSuraj Jitindar Singh cpu_relax(); 63f4d8d939SSuraj Jitindar Singh } 64f4d8d939SSuraj Jitindar Singh 65f4d8d939SSuraj Jitindar Singh void udelay(uint64_t us) 66f4d8d939SSuraj Jitindar Singh { 67f4d8d939SSuraj Jitindar Singh delay((us * tb_hz) / 1000000); 68f4d8d939SSuraj Jitindar Singh } 69ba33a96fSNicholas Piggin 70ba33a96fSNicholas Piggin void sleep_tb(uint64_t cycles) 71ba33a96fSNicholas Piggin { 72ba33a96fSNicholas Piggin uint64_t start, end, now; 73ba33a96fSNicholas Piggin 74ba33a96fSNicholas Piggin start = now = get_tb(); 75ba33a96fSNicholas Piggin end = start + cycles; 76ba33a96fSNicholas Piggin 77ba33a96fSNicholas Piggin while (end > now) { 78ba33a96fSNicholas Piggin uint64_t left = end - now; 79ba33a96fSNicholas Piggin 80ba33a96fSNicholas Piggin /* TODO: Could support large decrementer */ 81ba33a96fSNicholas Piggin if (left > 0x7fffffff) 82ba33a96fSNicholas Piggin left = 0x7fffffff; 83ba33a96fSNicholas Piggin 84ba33a96fSNicholas Piggin /* DEC won't fire until H_CEDE is called because EE=0 */ 85ba33a96fSNicholas Piggin asm volatile ("mtdec %0" : : "r" (left)); 86ba33a96fSNicholas Piggin handle_exception(0x900, &dec_handler_oneshot, NULL); 87ba33a96fSNicholas Piggin /* 88ba33a96fSNicholas Piggin * H_CEDE is called with MSR[EE] clear and enables it as part 89ba33a96fSNicholas Piggin * of the hcall, returning with EE enabled. The dec interrupt 90ba33a96fSNicholas Piggin * is then taken immediately and the handler disables EE. 91ba33a96fSNicholas Piggin * 92ba33a96fSNicholas Piggin * If H_CEDE returned for any other interrupt than dec 93ba33a96fSNicholas Piggin * expiring, that is considered an unhandled interrupt and 94ba33a96fSNicholas Piggin * the test case would be stopped. 95ba33a96fSNicholas Piggin */ 96ba33a96fSNicholas Piggin if (hcall(H_CEDE) != H_SUCCESS) { 97ba33a96fSNicholas Piggin printf("H_CEDE failed\n"); 98ba33a96fSNicholas Piggin abort(); 99ba33a96fSNicholas Piggin } 100ba33a96fSNicholas Piggin handle_exception(0x900, NULL, NULL); 101ba33a96fSNicholas Piggin 102ba33a96fSNicholas Piggin now = get_tb(); 103ba33a96fSNicholas Piggin } 104ba33a96fSNicholas Piggin } 105ba33a96fSNicholas Piggin 106ba33a96fSNicholas Piggin void usleep(uint64_t us) 107ba33a96fSNicholas Piggin { 108ba33a96fSNicholas Piggin sleep_tb((us * tb_hz) / 1000000); 109ba33a96fSNicholas Piggin } 110