void ip27_rt_timer_interrupt(void) { int cpu = smp_processor_id(); int cpuA = cputoslice(cpu) == 0; unsigned int irq = rt_timer_irq; irq_enter(); write_seqlock(&xtime_lock); again: LOCAL_HUB_S(cpuA ? PI_RT_PEND_A : PI_RT_PEND_B, 0); /* Ack */ ct_cur[cpu] += CYCLES_PER_JIFFY; LOCAL_HUB_S(cpuA ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, ct_cur[cpu]); if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur[cpu]) goto again; kstat_this_cpu.irqs[irq]++; /* kstat only for bootcpu? */ if (cpu == 0) do_timer(1); update_process_times(user_mode(get_irq_regs())); write_sequnlock(&xtime_lock); irq_exit(); }
void __init per_cpu_init(void) { int cpu = smp_processor_id(); int slice = LOCAL_HUB_L(PI_CPU_NUM); cnodeid_t cnode = get_compact_nodeid(); struct hub_data *hub = hub_data(cnode); struct slice_data *si = hub->slice + slice; int i; if (test_and_set_bit(slice, &hub->slice_map)) return; clear_c0_status(ST0_IM); for (i = 0; i < LEVELS_PER_SLICE; i++) si->level_to_irq[i] = -1; /* * Some interrupts are reserved by hardware or by software convention. * Mark these as reserved right away so they won't be used accidently * later. */ for (i = 0; i <= BASE_PCI_IRQ; i++) { __set_bit(i, si->irq_alloc_mask); LOCAL_HUB_S(PI_INT_PEND_MOD, i); } __set_bit(IP_PEND0_6_63, si->irq_alloc_mask); LOCAL_HUB_S(PI_INT_PEND_MOD, IP_PEND0_6_63); for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++) { __set_bit(i, si->irq_alloc_mask + 1); LOCAL_HUB_S(PI_INT_PEND_MOD, i); } LOCAL_HUB_L(PI_INT_PEND0); /* * We use this so we can find the local hub's data as fast as only * possible. */ cpu_data[cpu].data = si; cpu_time_init(); install_ipi(); /* Install our NMI handler if symmon hasn't installed one. */ install_cpu_nmi_handler(cputoslice(cpu)); set_c0_status(SRB_DEV0 | SRB_DEV1); per_hub_init(cnode); }
void rt_timer_interrupt(struct pt_regs *regs) { int cpu = smp_processor_id(); int cpuA = ((cputoslice(cpu)) == 0); int irq = IP27_TIMER_IRQ; irq_enter(cpu, irq); write_lock(&xtime_lock); again: LOCAL_HUB_S(cpuA ? PI_RT_PEND_A : PI_RT_PEND_B, 0); /* Ack */ ct_cur[cpu] += CYCLES_PER_JIFFY; LOCAL_HUB_S(cpuA ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, ct_cur[cpu]); if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur[cpu]) goto again; kstat.irqs[cpu][irq]++; /* kstat only for bootcpu? */ if (cpu == 0) do_timer(regs); #ifdef CONFIG_SMP update_process_times(user_mode(regs)); #endif /* CONFIG_SMP */ /* * If we have an externally synchronized Linux clock, then update * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * called as close as possible to when a second starts. */ if ((time_status & STA_UNSYNC) == 0 && xtime.tv_sec > last_rtc_update + 660) { if (xtime.tv_usec >= 1000000 - ((unsigned) tick) / 2) { if (set_rtc_mmss(xtime.tv_sec + 1) == 0) last_rtc_update = xtime.tv_sec; else last_rtc_update = xtime.tv_sec - 600; } else if (xtime.tv_usec <= ((unsigned) tick) / 2) { if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else last_rtc_update = xtime.tv_sec - 600; } } write_unlock(&xtime_lock); irq_exit(cpu, irq); if (softirq_pending(cpu)) do_softirq(); }
void __init ip27_be_init(void) { int cpu = LOCAL_HUB_L(PI_CPU_NUM); int cpuoff = cpu << 8; board_be_handler = ip27_be_handler; LOCAL_HUB_S(PI_ERR_INT_PEND, cpu ? PI_ERR_CLEAR_ALL_B : PI_ERR_CLEAR_ALL_A); LOCAL_HUB_S(PI_ERR_INT_MASK_A + cpuoff, 0); LOCAL_HUB_S(PI_ERR_STACK_ADDR_A + cpuoff, 0); LOCAL_HUB_S(PI_ERR_STACK_SIZE, 0); LOCAL_HUB_S(PI_SYSAD_ERRCHK_EN, PI_SYSAD_CHECK_ALL); }
void __init ip27_be_init(void) { /* XXX Initialize all the Hub & Bridge error handling here. */ int cpu = LOCAL_HUB_L(PI_CPU_NUM); int cpuoff = cpu << 8; board_be_handler = ip27_be_handler; LOCAL_HUB_S(PI_ERR_INT_PEND, cpu ? PI_ERR_CLEAR_ALL_B : PI_ERR_CLEAR_ALL_A); LOCAL_HUB_S(PI_ERR_INT_MASK_A + cpuoff, 0); LOCAL_HUB_S(PI_ERR_STACK_ADDR_A + cpuoff, 0); LOCAL_HUB_S(PI_ERR_STACK_SIZE, 0); /* Disable error stack */ LOCAL_HUB_S(PI_SYSAD_ERRCHK_EN, PI_SYSAD_CHECK_ALL); }
void __init bus_error_init(void) { /* XXX Initialize all the Hub & Bridge error handling here. */ int cpu = LOCAL_HUB_L(PI_CPU_NUM); int cpuoff = cpu << 8; set_except_vector(6, handle_ip27_ibe); set_except_vector(7, handle_ip27_dbe); LOCAL_HUB_S(PI_ERR_INT_PEND, cpu ? PI_ERR_CLEAR_ALL_B : PI_ERR_CLEAR_ALL_A); LOCAL_HUB_S(PI_ERR_INT_MASK_A + cpuoff, 0); LOCAL_HUB_S(PI_ERR_STACK_ADDR_A + cpuoff, 0); LOCAL_HUB_S(PI_ERR_STACK_SIZE, 0); /* Disable error stack */ LOCAL_HUB_S(PI_SYSAD_ERRCHK_EN, PI_SYSAD_CHECK_ALL); }
void rt_timer_interrupt(struct pt_regs *regs) { int cpu = smp_processor_id(); int cpuA = ((cputoslice(cpu)) == 0); int irq = 9; /* XXX Assign number */ irq_enter(); write_seqlock(&xtime_lock); again: LOCAL_HUB_S(cpuA ? PI_RT_PEND_A : PI_RT_PEND_B, 0); /* Ack */ ct_cur[cpu] += CYCLES_PER_JIFFY; LOCAL_HUB_S(cpuA ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, ct_cur[cpu]); if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur[cpu]) goto again; kstat_this_cpu.irqs[irq]++; /* kstat only for bootcpu? */ if (cpu == 0) do_timer(regs); #ifdef CONFIG_SMP update_process_times(user_mode(regs)); #endif /* CONFIG_SMP */ /* * If we have an externally synchronized Linux clock, then update * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * called as close as possible to when a second starts. */ if ((time_status & STA_UNSYNC) == 0 && xtime.tv_sec > last_rtc_update + 660 && (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { if (rtc_set_time(xtime.tv_sec) == 0) { last_rtc_update = xtime.tv_sec; } else { last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ } } write_sequnlock(&xtime_lock); irq_exit(); }
static void ip27_machine_restart(char *command) { printk("Reboot started from CPU %d\n", smp_processor_id()); #ifdef CONFIG_SMP smp_send_stop(); #endif LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET); noreturn; }
static void __cpuinit per_hub_init(cnodeid_t cnode) { struct hub_data *hub = hub_data(cnode); nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); int i; cpu_set(smp_processor_id(), hub->h_cpus); if (test_and_set_bit(cnode, hub_init_mask)) return; /* * Set CRB timeout at 5ms, (< PI timeout of 10ms) */ REMOTE_HUB_S(nasid, IIO_ICTP, 0x800); REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); hub_rtc_init(cnode); xtalk_probe_node(cnode); #ifdef CONFIG_REPLICATE_EXHANDLERS /* * If this is not a headless node initialization, * copy over the caliased exception handlers. */ if (get_compact_nodeid() == cnode) { extern char except_vec2_generic, except_vec3_generic; extern void build_tlb_refill_handler(void); memcpy((void *)(CKSEG0 + 0x100), &except_vec2_generic, 0x80); memcpy((void *)(CKSEG0 + 0x180), &except_vec3_generic, 0x80); build_tlb_refill_handler(); memcpy((void *)(CKSEG0 + 0x100), (void *) CKSEG0, 0x80); memcpy((void *)(CKSEG0 + 0x180), &except_vec3_generic, 0x100); __flush_cache_all(); } #endif /* * Some interrupts are reserved by hardware or by software convention. * Mark these as reserved right away so they won't be used accidently * later. */ for (i = 0; i <= BASE_PCI_IRQ; i++) { __set_bit(i, hub->irq_alloc_mask); LOCAL_HUB_CLR_INTR(INT_PEND0_BASELVL + i); } __set_bit(IP_PEND0_6_63, hub->irq_alloc_mask); LOCAL_HUB_S(PI_INT_PEND_MOD, IP_PEND0_6_63); for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++) { __set_bit(i, hub->irq_alloc_mask); LOCAL_HUB_CLR_INTR(INT_PEND1_BASELVL + i); } }
static void __cpuinit per_hub_init(cnodeid_t cnode) { struct hub_data *hub = hub_data(cnode); nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); int i; cpu_set(smp_processor_id(), hub->h_cpus); if (test_and_set_bit(cnode, hub_init_mask)) return; /* */ REMOTE_HUB_S(nasid, IIO_ICTP, 0x800); REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); hub_rtc_init(cnode); xtalk_probe_node(cnode); #ifdef CONFIG_REPLICATE_EXHANDLERS /* */ if (get_compact_nodeid() == cnode) { extern char except_vec2_generic, except_vec3_generic; extern void build_tlb_refill_handler(void); memcpy((void *)(CKSEG0 + 0x100), &except_vec2_generic, 0x80); memcpy((void *)(CKSEG0 + 0x180), &except_vec3_generic, 0x80); build_tlb_refill_handler(); memcpy((void *)(CKSEG0 + 0x100), (void *) CKSEG0, 0x80); memcpy((void *)(CKSEG0 + 0x180), &except_vec3_generic, 0x100); __flush_cache_all(); } #endif /* */ for (i = 0; i <= BASE_PCI_IRQ; i++) { __set_bit(i, hub->irq_alloc_mask); LOCAL_HUB_CLR_INTR(INT_PEND0_BASELVL + i); } __set_bit(IP_PEND0_6_63, hub->irq_alloc_mask); LOCAL_HUB_S(PI_INT_PEND_MOD, IP_PEND0_6_63); for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++) { __set_bit(i, hub->irq_alloc_mask); LOCAL_HUB_CLR_INTR(INT_PEND1_BASELVL + i); } }
static int rt_next_event(unsigned long delta, struct clock_event_device *evt) { unsigned int cpu = smp_processor_id(); int slice = cputoslice(cpu); unsigned long cnt; cnt = LOCAL_HUB_L(PI_RT_COUNT); cnt += delta; LOCAL_HUB_S(PI_RT_COMPARE_A + PI_COUNT_OFFSET * slice, cnt); return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0; }
void __init hub_rtc_init(cnodeid_t cnode) { /* * We only need to initialize the current node. * If this is not the current node then it is a cpuless * node and timeouts will not happen there. */ if (get_compact_nodeid() == cnode) { int cpu = smp_processor_id(); LOCAL_HUB_S(PI_RT_EN_A, 1); LOCAL_HUB_S(PI_RT_EN_B, 1); LOCAL_HUB_S(PI_PROF_EN_A, 0); LOCAL_HUB_S(PI_PROF_EN_B, 0); ct_cur[cpu] = CYCLES_PER_JIFFY; LOCAL_HUB_S(PI_RT_COMPARE_A, ct_cur[cpu]); LOCAL_HUB_S(PI_RT_COUNT, 0); LOCAL_HUB_S(PI_RT_PEND_A, 0); LOCAL_HUB_S(PI_RT_COMPARE_B, ct_cur[cpu]); LOCAL_HUB_S(PI_RT_COUNT, 0); LOCAL_HUB_S(PI_RT_PEND_B, 0); } }
static void ip27_machine_halt(void) { int i; #ifdef CONFIG_SMP smp_send_stop(); #endif for (i = 0; i < numnodes; i++) REMOTE_HUB_S(COMPACT_TO_NASID_NODEID(i), PROMOP_REG, PROMOP_RESTART); LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET); noreturn; }
static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id) { struct clock_event_device *cd = dev_id; unsigned int cpu = smp_processor_id(); int slice = cputoslice(cpu); /* * Ack */ LOCAL_HUB_S(PI_RT_PEND_A + PI_COUNT_OFFSET * slice, 0); cd->event_handler(cd); return IRQ_HANDLED; }
void install_ipi(void) { int cpu = smp_processor_id(); unsigned long *mask = per_cpu(irq_enable_mask, cpu); int slice = LOCAL_HUB_L(PI_CPU_NUM); int resched, call; resched = CPU_RESCHED_A_IRQ + slice; set_bit(resched, mask); LOCAL_HUB_CLR_INTR(resched); call = CPU_CALL_A_IRQ + slice; set_bit(call, mask); LOCAL_HUB_CLR_INTR(call); if (slice == 0) { LOCAL_HUB_S(PI_INT_MASK0_A, mask[0]); LOCAL_HUB_S(PI_INT_MASK1_A, mask[1]); } else { LOCAL_HUB_S(PI_INT_MASK0_B, mask[0]); LOCAL_HUB_S(PI_INT_MASK1_B, mask[1]); } }
void __init hub_rtc_init(cnodeid_t cnode) { /* * We only need to initialize the current node. * If this is not the current node then it is a cpuless * node and timeouts will not happen there. */ if (get_compact_nodeid() == cnode) { LOCAL_HUB_S(PI_RT_EN_A, 1); LOCAL_HUB_S(PI_RT_EN_B, 1); LOCAL_HUB_S(PI_PROF_EN_A, 0); LOCAL_HUB_S(PI_PROF_EN_B, 0); LOCAL_HUB_S(PI_RT_COUNT, 0); LOCAL_HUB_S(PI_RT_PEND_A, 0); LOCAL_HUB_S(PI_RT_PEND_B, 0); } }
/* XXX How to pass the reboot command to the firmware??? */ static void ip27_machine_restart(char *command) { #if 0 int i; #endif printk("Reboot started from CPU %d\n", smp_processor_id()); #ifdef CONFIG_SMP smp_send_stop(); #endif #if 0 for (i = 0; i < numnodes; i++) REMOTE_HUB_S(COMPACT_TO_NASID_NODEID(i), PROMOP_REG, PROMOP_REBOOT); #else LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET); #endif noreturn; }
void rt_timer_interrupt(struct pt_regs *regs) { int cpu = smp_processor_id(); int cpuA = ((cputoslice(cpu)) == 0); int irq = 7; /* XXX Assign number */ write_lock(&xtime_lock); again: LOCAL_HUB_S(cpuA ? PI_RT_PEND_A : PI_RT_PEND_B, 0); /* Ack */ ct_cur[cpu] += CYCLES_PER_JIFFY; LOCAL_HUB_S(cpuA ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, ct_cur[cpu]); if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur[cpu]) goto again; kstat.irqs[cpu][irq]++; /* kstat only for bootcpu? */ if (cpu == 0) do_timer(regs); #ifdef CONFIG_SMP { int user = user_mode(regs); /* * update_process_times() expects us to have done irq_enter(). * Besides, if we don't timer interrupts ignore the global * interrupt lock, which is the WrongThing (tm) to do. * Picked from i386 code. */ irq_enter(cpu, 0); update_process_times(user); irq_exit(cpu, 0); } #endif /* CONFIG_SMP */ /* * If we have an externally synchronized Linux clock, then update * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * called as close as possible to when a second starts. */ if ((time_status & STA_UNSYNC) == 0 && xtime.tv_sec > last_rtc_update + 660) { if (xtime.tv_usec >= 1000000 - ((unsigned) tick) / 2) { if (set_rtc_mmss(xtime.tv_sec + 1) == 0) last_rtc_update = xtime.tv_sec; else last_rtc_update = xtime.tv_sec - 600; } else if (xtime.tv_usec <= ((unsigned) tick) / 2) { if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else last_rtc_update = xtime.tv_sec - 600; } } write_unlock(&xtime_lock); if (softirq_pending(cpu)) do_softirq(); }
void ni_reset_port(void) { LOCAL_HUB_S(NI_RESET_ENABLE, NRE_RESETOK); LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET); }