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> 108b10d4faSNicholas Piggin #include <asm/time.h> 116842bc34SLaurent Vivier #include <asm/ptrace.h> 12f4d8d939SSuraj Jitindar Singh #include <asm/setup.h> 13f4d8d939SSuraj Jitindar Singh #include <asm/barrier.h> 14ba33a96fSNicholas Piggin #include <asm/hcall.h> 15ba33a96fSNicholas Piggin #include <asm/handlers.h> 16*c76b0d0aSNicholas Piggin #include <asm/smp.h> 176842bc34SLaurent Vivier 186842bc34SLaurent Vivier static struct { 196842bc34SLaurent Vivier void (*func)(struct pt_regs *, void *data); 206842bc34SLaurent Vivier void *data; 210ec01e27SNicholas Piggin } handlers[128]; 226842bc34SLaurent Vivier 230ec01e27SNicholas Piggin /* 240ec01e27SNicholas Piggin * Exception handlers span from 0x100 to 0x1000 and can have a granularity 250ec01e27SNicholas Piggin * of 0x20 bytes in some cases. Indexing spans 0-0x1000 with 0x20 increments 260ec01e27SNicholas Piggin * resulting in 128 slots. 270ec01e27SNicholas Piggin */ 286842bc34SLaurent Vivier void handle_exception(int trap, void (*func)(struct pt_regs *, void *), 296842bc34SLaurent Vivier void * data) 306842bc34SLaurent Vivier { 310ec01e27SNicholas Piggin assert(!(trap & ~0xfe0)); 325d571097SNicholas Piggin 330ec01e27SNicholas Piggin trap >>= 5; 346842bc34SLaurent Vivier 355d571097SNicholas Piggin if (func && handlers[trap].func) { 368791cea0SNicholas Piggin printf("exception handler installed twice %#x\n", trap << 5); 375d571097SNicholas Piggin abort(); 385d571097SNicholas Piggin } 390ec01e27SNicholas Piggin 406842bc34SLaurent Vivier handlers[trap].func = func; 416842bc34SLaurent Vivier handlers[trap].data = data; 426842bc34SLaurent Vivier } 436842bc34SLaurent Vivier 446842bc34SLaurent Vivier void do_handle_exception(struct pt_regs *regs) 456842bc34SLaurent Vivier { 466842bc34SLaurent Vivier unsigned char v; 476842bc34SLaurent Vivier 48*c76b0d0aSNicholas Piggin __current_cpu = (struct cpu *)mfspr(SPR_SPRG0); 49*c76b0d0aSNicholas Piggin 500ec01e27SNicholas Piggin v = regs->trap >> 5; 516842bc34SLaurent Vivier 520ec01e27SNicholas Piggin if (v < 128 && handlers[v].func) { 536842bc34SLaurent Vivier handlers[v].func(regs, handlers[v].data); 546842bc34SLaurent Vivier return; 556842bc34SLaurent Vivier } 566842bc34SLaurent Vivier 57*c76b0d0aSNicholas Piggin printf("Unhandled CPU%d exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", 58*c76b0d0aSNicholas Piggin smp_processor_id(), regs->trap, regs->nip, regs->msr); 59ac6e1abfSNicholas Piggin dump_frame_stack((void *)regs->nip, (void *)regs->gpr[1]); 606842bc34SLaurent Vivier abort(); 616842bc34SLaurent Vivier } 62f4d8d939SSuraj Jitindar Singh 638b10d4faSNicholas Piggin uint64_t get_clock_us(void) 648b10d4faSNicholas Piggin { 658b10d4faSNicholas Piggin return get_tb() * 1000000 / tb_hz; 668b10d4faSNicholas Piggin } 678b10d4faSNicholas Piggin 688b10d4faSNicholas Piggin uint64_t get_clock_ms(void) 698b10d4faSNicholas Piggin { 708b10d4faSNicholas Piggin return get_tb() * 1000 / tb_hz; 718b10d4faSNicholas Piggin } 728b10d4faSNicholas Piggin 73f4d8d939SSuraj Jitindar Singh void delay(uint64_t cycles) 74f4d8d939SSuraj Jitindar Singh { 75f4d8d939SSuraj Jitindar Singh uint64_t start = get_tb(); 76f4d8d939SSuraj Jitindar Singh 77f4d8d939SSuraj Jitindar Singh while ((get_tb() - start) < cycles) 78f4d8d939SSuraj Jitindar Singh cpu_relax(); 79f4d8d939SSuraj Jitindar Singh } 80f4d8d939SSuraj Jitindar Singh 81f4d8d939SSuraj Jitindar Singh void udelay(uint64_t us) 82f4d8d939SSuraj Jitindar Singh { 83f4d8d939SSuraj Jitindar Singh delay((us * tb_hz) / 1000000); 84f4d8d939SSuraj Jitindar Singh } 85ba33a96fSNicholas Piggin 86ba33a96fSNicholas Piggin void sleep_tb(uint64_t cycles) 87ba33a96fSNicholas Piggin { 88ba33a96fSNicholas Piggin uint64_t start, end, now; 89ba33a96fSNicholas Piggin 90610c5a9cSNicholas Piggin if (!machine_is_pseries()) { 91610c5a9cSNicholas Piggin /* 92610c5a9cSNicholas Piggin * P9/10 Could use 'stop' to sleep here which would be 93610c5a9cSNicholas Piggin * interesting. stop with ESL=0 should be simple enough, ESL=1 94610c5a9cSNicholas Piggin * would require SRESET based wakeup which is more involved. 95610c5a9cSNicholas Piggin */ 96610c5a9cSNicholas Piggin delay(cycles); 97610c5a9cSNicholas Piggin return; 98610c5a9cSNicholas Piggin } 99610c5a9cSNicholas Piggin 100ba33a96fSNicholas Piggin start = now = get_tb(); 101ba33a96fSNicholas Piggin end = start + cycles; 102ba33a96fSNicholas Piggin 103ba33a96fSNicholas Piggin while (end > now) { 104ba33a96fSNicholas Piggin uint64_t left = end - now; 105ba33a96fSNicholas Piggin 106ba33a96fSNicholas Piggin /* TODO: Could support large decrementer */ 107ba33a96fSNicholas Piggin if (left > 0x7fffffff) 108ba33a96fSNicholas Piggin left = 0x7fffffff; 109ba33a96fSNicholas Piggin 110ba33a96fSNicholas Piggin /* DEC won't fire until H_CEDE is called because EE=0 */ 111ba33a96fSNicholas Piggin asm volatile ("mtdec %0" : : "r" (left)); 112ba33a96fSNicholas Piggin handle_exception(0x900, &dec_handler_oneshot, NULL); 113ba33a96fSNicholas Piggin /* 114ba33a96fSNicholas Piggin * H_CEDE is called with MSR[EE] clear and enables it as part 115ba33a96fSNicholas Piggin * of the hcall, returning with EE enabled. The dec interrupt 116ba33a96fSNicholas Piggin * is then taken immediately and the handler disables EE. 117ba33a96fSNicholas Piggin * 118ba33a96fSNicholas Piggin * If H_CEDE returned for any other interrupt than dec 119ba33a96fSNicholas Piggin * expiring, that is considered an unhandled interrupt and 120ba33a96fSNicholas Piggin * the test case would be stopped. 121ba33a96fSNicholas Piggin */ 122ba33a96fSNicholas Piggin if (hcall(H_CEDE) != H_SUCCESS) { 123ba33a96fSNicholas Piggin printf("H_CEDE failed\n"); 124ba33a96fSNicholas Piggin abort(); 125ba33a96fSNicholas Piggin } 126ba33a96fSNicholas Piggin handle_exception(0x900, NULL, NULL); 127ba33a96fSNicholas Piggin 128ba33a96fSNicholas Piggin now = get_tb(); 129ba33a96fSNicholas Piggin } 130ba33a96fSNicholas Piggin } 131ba33a96fSNicholas Piggin 132ba33a96fSNicholas Piggin void usleep(uint64_t us) 133ba33a96fSNicholas Piggin { 134ba33a96fSNicholas Piggin sleep_tb((us * tb_hz) / 1000000); 135ba33a96fSNicholas Piggin } 136610c5a9cSNicholas Piggin 137610c5a9cSNicholas Piggin static void rfid_msr(uint64_t msr) 138610c5a9cSNicholas Piggin { 139610c5a9cSNicholas Piggin uint64_t tmp; 140610c5a9cSNicholas Piggin 141610c5a9cSNicholas Piggin asm volatile( 142610c5a9cSNicholas Piggin "mtsrr1 %1 \n\ 143610c5a9cSNicholas Piggin bl 0f \n\ 144610c5a9cSNicholas Piggin 0: \n\ 145610c5a9cSNicholas Piggin mflr %0 \n\ 146610c5a9cSNicholas Piggin addi %0,%0,1f-0b \n\ 147610c5a9cSNicholas Piggin mtsrr0 %0 \n\ 148610c5a9cSNicholas Piggin rfid \n\ 149610c5a9cSNicholas Piggin 1: \n" 150610c5a9cSNicholas Piggin : "=r"(tmp) : "r"(msr) : "lr"); 151610c5a9cSNicholas Piggin } 152610c5a9cSNicholas Piggin 153610c5a9cSNicholas Piggin void enable_mcheck(void) 154610c5a9cSNicholas Piggin { 155610c5a9cSNicholas Piggin /* This is a no-op on pseries */ 156610c5a9cSNicholas Piggin rfid_msr(mfmsr() | MSR_ME); 157610c5a9cSNicholas Piggin } 158610c5a9cSNicholas Piggin 159610c5a9cSNicholas Piggin void disable_mcheck(void) 160610c5a9cSNicholas Piggin { 161610c5a9cSNicholas Piggin rfid_msr(mfmsr() & ~MSR_ME); 162610c5a9cSNicholas Piggin } 163