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*d4c8e725SNicholas Piggin #include <asm/mmu.h> 17c76b0d0aSNicholas Piggin #include <asm/smp.h> 186842bc34SLaurent Vivier 196842bc34SLaurent Vivier static struct { 206842bc34SLaurent Vivier void (*func)(struct pt_regs *, void *data); 216842bc34SLaurent Vivier void *data; 220ec01e27SNicholas Piggin } handlers[128]; 236842bc34SLaurent Vivier 240ec01e27SNicholas Piggin /* 250ec01e27SNicholas Piggin * Exception handlers span from 0x100 to 0x1000 and can have a granularity 260ec01e27SNicholas Piggin * of 0x20 bytes in some cases. Indexing spans 0-0x1000 with 0x20 increments 270ec01e27SNicholas Piggin * resulting in 128 slots. 280ec01e27SNicholas Piggin */ 296842bc34SLaurent Vivier void handle_exception(int trap, void (*func)(struct pt_regs *, void *), 306842bc34SLaurent Vivier void * data) 316842bc34SLaurent Vivier { 320ec01e27SNicholas Piggin assert(!(trap & ~0xfe0)); 335d571097SNicholas Piggin 340ec01e27SNicholas Piggin trap >>= 5; 356842bc34SLaurent Vivier 365d571097SNicholas Piggin if (func && handlers[trap].func) { 378791cea0SNicholas Piggin printf("exception handler installed twice %#x\n", trap << 5); 385d571097SNicholas Piggin abort(); 395d571097SNicholas Piggin } 400ec01e27SNicholas Piggin 416842bc34SLaurent Vivier handlers[trap].func = func; 426842bc34SLaurent Vivier handlers[trap].data = data; 436842bc34SLaurent Vivier } 446842bc34SLaurent Vivier 456842bc34SLaurent Vivier void do_handle_exception(struct pt_regs *regs) 466842bc34SLaurent Vivier { 476842bc34SLaurent Vivier unsigned char v; 486842bc34SLaurent Vivier 49c76b0d0aSNicholas Piggin __current_cpu = (struct cpu *)mfspr(SPR_SPRG0); 50c76b0d0aSNicholas Piggin 51*d4c8e725SNicholas Piggin /* 52*d4c8e725SNicholas Piggin * We run with AIL=0, so interrupts taken with MMU disabled. 53*d4c8e725SNicholas Piggin * Enable here. 54*d4c8e725SNicholas Piggin */ 55*d4c8e725SNicholas Piggin assert(!(mfmsr() & (MSR_IR|MSR_DR))); 56*d4c8e725SNicholas Piggin if (mmu_enabled()) 57*d4c8e725SNicholas Piggin mtmsr(mfmsr() | (MSR_IR|MSR_DR)); 58*d4c8e725SNicholas Piggin 590ec01e27SNicholas Piggin v = regs->trap >> 5; 606842bc34SLaurent Vivier 610ec01e27SNicholas Piggin if (v < 128 && handlers[v].func) { 626842bc34SLaurent Vivier handlers[v].func(regs, handlers[v].data); 636842bc34SLaurent Vivier return; 646842bc34SLaurent Vivier } 656842bc34SLaurent Vivier 66c76b0d0aSNicholas Piggin printf("Unhandled CPU%d exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", 67c76b0d0aSNicholas Piggin smp_processor_id(), regs->trap, regs->nip, regs->msr); 68ac6e1abfSNicholas Piggin dump_frame_stack((void *)regs->nip, (void *)regs->gpr[1]); 696842bc34SLaurent Vivier abort(); 706842bc34SLaurent Vivier } 71f4d8d939SSuraj Jitindar Singh 728b10d4faSNicholas Piggin uint64_t get_clock_us(void) 738b10d4faSNicholas Piggin { 748b10d4faSNicholas Piggin return get_tb() * 1000000 / tb_hz; 758b10d4faSNicholas Piggin } 768b10d4faSNicholas Piggin 778b10d4faSNicholas Piggin uint64_t get_clock_ms(void) 788b10d4faSNicholas Piggin { 798b10d4faSNicholas Piggin return get_tb() * 1000 / tb_hz; 808b10d4faSNicholas Piggin } 818b10d4faSNicholas Piggin 82f4d8d939SSuraj Jitindar Singh void delay(uint64_t cycles) 83f4d8d939SSuraj Jitindar Singh { 84f4d8d939SSuraj Jitindar Singh uint64_t start = get_tb(); 85f4d8d939SSuraj Jitindar Singh 86f4d8d939SSuraj Jitindar Singh while ((get_tb() - start) < cycles) 87f4d8d939SSuraj Jitindar Singh cpu_relax(); 88f4d8d939SSuraj Jitindar Singh } 89f4d8d939SSuraj Jitindar Singh 90f4d8d939SSuraj Jitindar Singh void udelay(uint64_t us) 91f4d8d939SSuraj Jitindar Singh { 92f4d8d939SSuraj Jitindar Singh delay((us * tb_hz) / 1000000); 93f4d8d939SSuraj Jitindar Singh } 94ba33a96fSNicholas Piggin 95ba33a96fSNicholas Piggin void sleep_tb(uint64_t cycles) 96ba33a96fSNicholas Piggin { 97ba33a96fSNicholas Piggin uint64_t start, end, now; 98ba33a96fSNicholas Piggin 99610c5a9cSNicholas Piggin if (!machine_is_pseries()) { 100610c5a9cSNicholas Piggin /* 101610c5a9cSNicholas Piggin * P9/10 Could use 'stop' to sleep here which would be 102610c5a9cSNicholas Piggin * interesting. stop with ESL=0 should be simple enough, ESL=1 103610c5a9cSNicholas Piggin * would require SRESET based wakeup which is more involved. 104610c5a9cSNicholas Piggin */ 105610c5a9cSNicholas Piggin delay(cycles); 106610c5a9cSNicholas Piggin return; 107610c5a9cSNicholas Piggin } 108610c5a9cSNicholas Piggin 109ba33a96fSNicholas Piggin start = now = get_tb(); 110ba33a96fSNicholas Piggin end = start + cycles; 111ba33a96fSNicholas Piggin 112ba33a96fSNicholas Piggin while (end > now) { 113ba33a96fSNicholas Piggin uint64_t left = end - now; 114ba33a96fSNicholas Piggin 115ba33a96fSNicholas Piggin /* TODO: Could support large decrementer */ 116ba33a96fSNicholas Piggin if (left > 0x7fffffff) 117ba33a96fSNicholas Piggin left = 0x7fffffff; 118ba33a96fSNicholas Piggin 119ba33a96fSNicholas Piggin /* DEC won't fire until H_CEDE is called because EE=0 */ 120ba33a96fSNicholas Piggin asm volatile ("mtdec %0" : : "r" (left)); 121ba33a96fSNicholas Piggin handle_exception(0x900, &dec_handler_oneshot, NULL); 122ba33a96fSNicholas Piggin /* 123ba33a96fSNicholas Piggin * H_CEDE is called with MSR[EE] clear and enables it as part 124ba33a96fSNicholas Piggin * of the hcall, returning with EE enabled. The dec interrupt 125ba33a96fSNicholas Piggin * is then taken immediately and the handler disables EE. 126ba33a96fSNicholas Piggin * 127ba33a96fSNicholas Piggin * If H_CEDE returned for any other interrupt than dec 128ba33a96fSNicholas Piggin * expiring, that is considered an unhandled interrupt and 129ba33a96fSNicholas Piggin * the test case would be stopped. 130ba33a96fSNicholas Piggin */ 131ba33a96fSNicholas Piggin if (hcall(H_CEDE) != H_SUCCESS) { 132ba33a96fSNicholas Piggin printf("H_CEDE failed\n"); 133ba33a96fSNicholas Piggin abort(); 134ba33a96fSNicholas Piggin } 135ba33a96fSNicholas Piggin handle_exception(0x900, NULL, NULL); 136ba33a96fSNicholas Piggin 137ba33a96fSNicholas Piggin now = get_tb(); 138ba33a96fSNicholas Piggin } 139ba33a96fSNicholas Piggin } 140ba33a96fSNicholas Piggin 141ba33a96fSNicholas Piggin void usleep(uint64_t us) 142ba33a96fSNicholas Piggin { 143ba33a96fSNicholas Piggin sleep_tb((us * tb_hz) / 1000000); 144ba33a96fSNicholas Piggin } 145610c5a9cSNicholas Piggin 146610c5a9cSNicholas Piggin static void rfid_msr(uint64_t msr) 147610c5a9cSNicholas Piggin { 148610c5a9cSNicholas Piggin uint64_t tmp; 149610c5a9cSNicholas Piggin 150610c5a9cSNicholas Piggin asm volatile( 151610c5a9cSNicholas Piggin "mtsrr1 %1 \n\ 152610c5a9cSNicholas Piggin bl 0f \n\ 153610c5a9cSNicholas Piggin 0: \n\ 154610c5a9cSNicholas Piggin mflr %0 \n\ 155610c5a9cSNicholas Piggin addi %0,%0,1f-0b \n\ 156610c5a9cSNicholas Piggin mtsrr0 %0 \n\ 157610c5a9cSNicholas Piggin rfid \n\ 158610c5a9cSNicholas Piggin 1: \n" 159610c5a9cSNicholas Piggin : "=r"(tmp) : "r"(msr) : "lr"); 160610c5a9cSNicholas Piggin } 161610c5a9cSNicholas Piggin 162610c5a9cSNicholas Piggin void enable_mcheck(void) 163610c5a9cSNicholas Piggin { 164610c5a9cSNicholas Piggin /* This is a no-op on pseries */ 165610c5a9cSNicholas Piggin rfid_msr(mfmsr() | MSR_ME); 166610c5a9cSNicholas Piggin } 167610c5a9cSNicholas Piggin 168610c5a9cSNicholas Piggin void disable_mcheck(void) 169610c5a9cSNicholas Piggin { 170610c5a9cSNicholas Piggin rfid_msr(mfmsr() & ~MSR_ME); 171610c5a9cSNicholas Piggin } 172