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> 166842bc34SLaurent Vivier 176842bc34SLaurent Vivier static struct { 186842bc34SLaurent Vivier void (*func)(struct pt_regs *, void *data); 196842bc34SLaurent Vivier void *data; 200ec01e27SNicholas Piggin } handlers[128]; 216842bc34SLaurent Vivier 220ec01e27SNicholas Piggin /* 230ec01e27SNicholas Piggin * Exception handlers span from 0x100 to 0x1000 and can have a granularity 240ec01e27SNicholas Piggin * of 0x20 bytes in some cases. Indexing spans 0-0x1000 with 0x20 increments 250ec01e27SNicholas Piggin * resulting in 128 slots. 260ec01e27SNicholas Piggin */ 276842bc34SLaurent Vivier void handle_exception(int trap, void (*func)(struct pt_regs *, void *), 286842bc34SLaurent Vivier void * data) 296842bc34SLaurent Vivier { 300ec01e27SNicholas Piggin assert(!(trap & ~0xfe0)); 315d571097SNicholas Piggin 320ec01e27SNicholas Piggin trap >>= 5; 336842bc34SLaurent Vivier 345d571097SNicholas Piggin if (func && handlers[trap].func) { 358791cea0SNicholas Piggin printf("exception handler installed twice %#x\n", trap << 5); 365d571097SNicholas Piggin abort(); 375d571097SNicholas Piggin } 380ec01e27SNicholas Piggin 396842bc34SLaurent Vivier handlers[trap].func = func; 406842bc34SLaurent Vivier handlers[trap].data = data; 416842bc34SLaurent Vivier } 426842bc34SLaurent Vivier 436842bc34SLaurent Vivier void do_handle_exception(struct pt_regs *regs) 446842bc34SLaurent Vivier { 456842bc34SLaurent Vivier unsigned char v; 466842bc34SLaurent Vivier 470ec01e27SNicholas Piggin v = regs->trap >> 5; 486842bc34SLaurent Vivier 490ec01e27SNicholas Piggin if (v < 128 && handlers[v].func) { 506842bc34SLaurent Vivier handlers[v].func(regs, handlers[v].data); 516842bc34SLaurent Vivier return; 526842bc34SLaurent Vivier } 536842bc34SLaurent Vivier 54ac6e1abfSNicholas Piggin printf("Unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", 55ac6e1abfSNicholas Piggin regs->trap, regs->nip, regs->msr); 56ac6e1abfSNicholas Piggin dump_frame_stack((void *)regs->nip, (void *)regs->gpr[1]); 576842bc34SLaurent Vivier abort(); 586842bc34SLaurent Vivier } 59f4d8d939SSuraj Jitindar Singh 608b10d4faSNicholas Piggin uint64_t get_clock_us(void) 618b10d4faSNicholas Piggin { 628b10d4faSNicholas Piggin return get_tb() * 1000000 / tb_hz; 638b10d4faSNicholas Piggin } 648b10d4faSNicholas Piggin 658b10d4faSNicholas Piggin uint64_t get_clock_ms(void) 668b10d4faSNicholas Piggin { 678b10d4faSNicholas Piggin return get_tb() * 1000 / tb_hz; 688b10d4faSNicholas Piggin } 698b10d4faSNicholas Piggin 70f4d8d939SSuraj Jitindar Singh void delay(uint64_t cycles) 71f4d8d939SSuraj Jitindar Singh { 72f4d8d939SSuraj Jitindar Singh uint64_t start = get_tb(); 73f4d8d939SSuraj Jitindar Singh 74f4d8d939SSuraj Jitindar Singh while ((get_tb() - start) < cycles) 75f4d8d939SSuraj Jitindar Singh cpu_relax(); 76f4d8d939SSuraj Jitindar Singh } 77f4d8d939SSuraj Jitindar Singh 78f4d8d939SSuraj Jitindar Singh void udelay(uint64_t us) 79f4d8d939SSuraj Jitindar Singh { 80f4d8d939SSuraj Jitindar Singh delay((us * tb_hz) / 1000000); 81f4d8d939SSuraj Jitindar Singh } 82ba33a96fSNicholas Piggin 83ba33a96fSNicholas Piggin void sleep_tb(uint64_t cycles) 84ba33a96fSNicholas Piggin { 85ba33a96fSNicholas Piggin uint64_t start, end, now; 86ba33a96fSNicholas Piggin 87*610c5a9cSNicholas Piggin if (!machine_is_pseries()) { 88*610c5a9cSNicholas Piggin /* 89*610c5a9cSNicholas Piggin * P9/10 Could use 'stop' to sleep here which would be 90*610c5a9cSNicholas Piggin * interesting. stop with ESL=0 should be simple enough, ESL=1 91*610c5a9cSNicholas Piggin * would require SRESET based wakeup which is more involved. 92*610c5a9cSNicholas Piggin */ 93*610c5a9cSNicholas Piggin delay(cycles); 94*610c5a9cSNicholas Piggin return; 95*610c5a9cSNicholas Piggin } 96*610c5a9cSNicholas Piggin 97ba33a96fSNicholas Piggin start = now = get_tb(); 98ba33a96fSNicholas Piggin end = start + cycles; 99ba33a96fSNicholas Piggin 100ba33a96fSNicholas Piggin while (end > now) { 101ba33a96fSNicholas Piggin uint64_t left = end - now; 102ba33a96fSNicholas Piggin 103ba33a96fSNicholas Piggin /* TODO: Could support large decrementer */ 104ba33a96fSNicholas Piggin if (left > 0x7fffffff) 105ba33a96fSNicholas Piggin left = 0x7fffffff; 106ba33a96fSNicholas Piggin 107ba33a96fSNicholas Piggin /* DEC won't fire until H_CEDE is called because EE=0 */ 108ba33a96fSNicholas Piggin asm volatile ("mtdec %0" : : "r" (left)); 109ba33a96fSNicholas Piggin handle_exception(0x900, &dec_handler_oneshot, NULL); 110ba33a96fSNicholas Piggin /* 111ba33a96fSNicholas Piggin * H_CEDE is called with MSR[EE] clear and enables it as part 112ba33a96fSNicholas Piggin * of the hcall, returning with EE enabled. The dec interrupt 113ba33a96fSNicholas Piggin * is then taken immediately and the handler disables EE. 114ba33a96fSNicholas Piggin * 115ba33a96fSNicholas Piggin * If H_CEDE returned for any other interrupt than dec 116ba33a96fSNicholas Piggin * expiring, that is considered an unhandled interrupt and 117ba33a96fSNicholas Piggin * the test case would be stopped. 118ba33a96fSNicholas Piggin */ 119ba33a96fSNicholas Piggin if (hcall(H_CEDE) != H_SUCCESS) { 120ba33a96fSNicholas Piggin printf("H_CEDE failed\n"); 121ba33a96fSNicholas Piggin abort(); 122ba33a96fSNicholas Piggin } 123ba33a96fSNicholas Piggin handle_exception(0x900, NULL, NULL); 124ba33a96fSNicholas Piggin 125ba33a96fSNicholas Piggin now = get_tb(); 126ba33a96fSNicholas Piggin } 127ba33a96fSNicholas Piggin } 128ba33a96fSNicholas Piggin 129ba33a96fSNicholas Piggin void usleep(uint64_t us) 130ba33a96fSNicholas Piggin { 131ba33a96fSNicholas Piggin sleep_tb((us * tb_hz) / 1000000); 132ba33a96fSNicholas Piggin } 133*610c5a9cSNicholas Piggin 134*610c5a9cSNicholas Piggin static void rfid_msr(uint64_t msr) 135*610c5a9cSNicholas Piggin { 136*610c5a9cSNicholas Piggin uint64_t tmp; 137*610c5a9cSNicholas Piggin 138*610c5a9cSNicholas Piggin asm volatile( 139*610c5a9cSNicholas Piggin "mtsrr1 %1 \n\ 140*610c5a9cSNicholas Piggin bl 0f \n\ 141*610c5a9cSNicholas Piggin 0: \n\ 142*610c5a9cSNicholas Piggin mflr %0 \n\ 143*610c5a9cSNicholas Piggin addi %0,%0,1f-0b \n\ 144*610c5a9cSNicholas Piggin mtsrr0 %0 \n\ 145*610c5a9cSNicholas Piggin rfid \n\ 146*610c5a9cSNicholas Piggin 1: \n" 147*610c5a9cSNicholas Piggin : "=r"(tmp) : "r"(msr) : "lr"); 148*610c5a9cSNicholas Piggin } 149*610c5a9cSNicholas Piggin 150*610c5a9cSNicholas Piggin void enable_mcheck(void) 151*610c5a9cSNicholas Piggin { 152*610c5a9cSNicholas Piggin /* This is a no-op on pseries */ 153*610c5a9cSNicholas Piggin rfid_msr(mfmsr() | MSR_ME); 154*610c5a9cSNicholas Piggin } 155*610c5a9cSNicholas Piggin 156*610c5a9cSNicholas Piggin void disable_mcheck(void) 157*610c5a9cSNicholas Piggin { 158*610c5a9cSNicholas Piggin rfid_msr(mfmsr() & ~MSR_ME); 159*610c5a9cSNicholas Piggin } 160