static void ip27_do_irq_mask0(struct irq_desc *desc) { cpuid_t cpu = smp_processor_id(); unsigned long *mask = per_cpu(irq_enable_mask, cpu); u64 pend0; /* copied from Irix intpend0() */ pend0 = LOCAL_HUB_L(PI_INT_PEND0); pend0 &= mask[0]; /* Pick intrs we should look at */ if (!pend0) return; #ifdef CONFIG_SMP if (pend0 & (1UL << CPU_RESCHED_A_IRQ)) { LOCAL_HUB_CLR_INTR(CPU_RESCHED_A_IRQ); scheduler_ipi(); } else if (pend0 & (1UL << CPU_RESCHED_B_IRQ)) { LOCAL_HUB_CLR_INTR(CPU_RESCHED_B_IRQ); scheduler_ipi(); } else if (pend0 & (1UL << CPU_CALL_A_IRQ)) { LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ); generic_smp_call_function_interrupt(); } else if (pend0 & (1UL << CPU_CALL_B_IRQ)) { LOCAL_HUB_CLR_INTR(CPU_CALL_B_IRQ); generic_smp_call_function_interrupt(); } else #endif generic_handle_irq(__ffs(pend0) + IP27_HUB_IRQ_BASE); LOCAL_HUB_L(PI_INT_PEND0); }
void do_ip27_dbe(struct pt_regs *regs) { unsigned long fixup, errst0, errst1; int cpu = LOCAL_HUB_L(PI_CPU_NUM); fixup = search_dbe_table(regs->cp0_epc); if (fixup) { long new_epc; new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc); regs->cp0_epc = new_epc; return; } printk("Slice %c got dbe at 0x%lx\n", 'A' + cpu, regs->cp0_epc); printk("Hub information:\n"); printk("ERR_INT_PEND = 0x%06lx\n", LOCAL_HUB_L(PI_ERR_INT_PEND)); errst0 = LOCAL_HUB_L(cpu ? PI_ERR_STATUS0_B : PI_ERR_STATUS0_A); errst1 = LOCAL_HUB_L(cpu ? PI_ERR_STATUS1_B : PI_ERR_STATUS1_A); dump_hub_information(errst0, errst1); show_regs(regs); dump_tlb_all(); while(1); force_sig(SIGBUS, current); }
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 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); }
static int __init ip27_setup(void) { hubreg_t p, e, n_mode; nasid_t nid; ip27_setup_console(); ip27_reboot_setup(); /* * hub_rtc init and cpu clock intr enabled for later calibrate_delay. */ nid = get_nasid(); printk("IP27: Running on node %d.\n", nid); p = LOCAL_HUB_L(PI_CPU_PRESENT_A) & 1; e = LOCAL_HUB_L(PI_CPU_ENABLE_A) & 1; printk("Node %d has %s primary CPU%s.\n", nid, p ? "a" : "no", e ? ", CPU is running" : ""); p = LOCAL_HUB_L(PI_CPU_PRESENT_B) & 1; e = LOCAL_HUB_L(PI_CPU_ENABLE_B) & 1; printk("Node %d has %s secondary CPU%s.\n", nid, p ? "a" : "no", e ? ", CPU is running" : ""); /* * Try to catch kernel missconfigurations and give user an * indication what option to select. */ n_mode = LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_MORENODES_MASK; printk("Machine is in %c mode.\n", n_mode ? 'N' : 'M'); #ifdef CONFIG_SGI_SN0_N_MODE if (!n_mode) panic("Kernel compiled for M mode."); #else if (n_mode) panic("Kernel compiled for N mode."); #endif ioc3_sio_init(); ioc3_eth_init(); per_cpu_init(); set_io_port_base(IO_BASE); board_time_init = ip27_time_init; return 0; }
int is_fine_dirmode(void) { return (((LOCAL_HUB_L(LB_REV_ID) & LRI_SYSTEM_SIZE_MASK) >> LRI_SYSTEM_SIZE_SHFT) == SYSTEM_SIZE_SMALL); }
void __cpuinit 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); per_hub_init(cnode); for (i = 0; i < LEVELS_PER_SLICE; i++) si->level_to_irq[i] = -1; /* */ cpu_data[cpu].data = si; cpu_time_init(); install_ipi(); /* */ install_cpu_nmi_handler(cputoslice(cpu)); set_c0_status(SRB_DEV0 | SRB_DEV1); }
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 __cpuinit 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); per_hub_init(cnode); for (i = 0; i < LEVELS_PER_SLICE; i++) si->level_to_irq[i] = -1; /* * 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); }
static void ip27_do_irq_mask1(struct irq_desc *desc) { cpuid_t cpu = smp_processor_id(); unsigned long *mask = per_cpu(irq_enable_mask, cpu); u64 pend1; /* copied from Irix intpend0() */ pend1 = LOCAL_HUB_L(PI_INT_PEND1); pend1 &= mask[1]; /* Pick intrs we should look at */ if (!pend1) return; generic_handle_irq(__ffs(pend1) + IP27_HUB_IRQ_BASE + 64); LOCAL_HUB_L(PI_INT_PEND1); }
void __init plat_mem_setup(void) { hubreg_t p, e, n_mode; nasid_t nid; ip27_reboot_setup(); /* */ nid = get_nasid(); printk("IP27: Running on node %d.\n", nid); p = LOCAL_HUB_L(PI_CPU_PRESENT_A) & 1; e = LOCAL_HUB_L(PI_CPU_ENABLE_A) & 1; printk("Node %d has %s primary CPU%s.\n", nid, p ? "a" : "no", e ? ", CPU is running" : ""); p = LOCAL_HUB_L(PI_CPU_PRESENT_B) & 1; e = LOCAL_HUB_L(PI_CPU_ENABLE_B) & 1; printk("Node %d has %s secondary CPU%s.\n", nid, p ? "a" : "no", e ? ", CPU is running" : ""); /* */ n_mode = LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_MORENODES_MASK; printk("Machine is in %c mode.\n", n_mode ? 'N' : 'M'); #ifdef CONFIG_SGI_SN_N_MODE if (!n_mode) panic("Kernel compiled for M mode."); #else if (n_mode) panic("Kernel compiled for N mode."); #endif ioc3_eth_init(); per_cpu_init(); set_io_port_base(IO_BASE); }
int ip27_be_handler(struct pt_regs *regs, int is_fixup) { unsigned long errst0, errst1; int data = regs->cp0_cause & 4; int cpu = LOCAL_HUB_L(PI_CPU_NUM); if (is_fixup) return MIPS_BE_FIXUP; printk("Slice %c got %cbe at 0x%lx\n", 'A' + cpu, data ? 'd' : 'i', regs->cp0_epc); printk("Hub information:\n"); printk("ERR_INT_PEND = 0x%06llx\n", LOCAL_HUB_L(PI_ERR_INT_PEND)); errst0 = LOCAL_HUB_L(cpu ? PI_ERR_STATUS0_B : PI_ERR_STATUS0_A); errst1 = LOCAL_HUB_L(cpu ? PI_ERR_STATUS1_B : PI_ERR_STATUS1_A); dump_hub_information(errst0, errst1); show_regs(regs); dump_tlb_all(); while(1); force_sig(SIGBUS, current); }
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_setup(void) { nasid_t nid; hubreg_t p, e; ip27_setup_console(); ip27_reboot_setup(); num_bridges = 0; /* * hub_rtc init and cpu clock intr enabled for later calibrate_delay. */ DBG("ip27_setup(): Entered.\n"); nid = get_nasid(); printk("IP27: Running on node %d.\n", nid); p = LOCAL_HUB_L(PI_CPU_PRESENT_A) & 1; e = LOCAL_HUB_L(PI_CPU_ENABLE_A) & 1; printk("Node %d has %s primary CPU%s.\n", nid, p ? "a" : "no", e ? ", CPU is running" : ""); p = LOCAL_HUB_L(PI_CPU_PRESENT_B) & 1; e = LOCAL_HUB_L(PI_CPU_ENABLE_B) & 1; printk("Node %d has %s secondary CPU%s.\n", nid, p ? "a" : "no", e ? ", CPU is running" : ""); verify_mode(); ioc3_sio_init(); ioc3_eth_init(); per_cpu_init(); set_io_port_base(IO_BASE); board_be_init = ip27_be_init; board_time_init = ip27_time_init; }
/* Try to catch kernel missconfigurations and give user an indication what option to select. */ static void __init verify_mode(void) { int n_mode; n_mode = LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_MORENODES_MASK; printk("Machine is in %c mode.\n", n_mode ? 'N' : 'M'); #ifdef CONFIG_SGI_SN0_N_MODE if (!n_mode) panic("Kernel compiled for M mode."); #else if (n_mode) panic("Kernel compiled for N mode."); #endif }
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(); }
void __init cpu_time_init(void) { lboard_t *board; klcpu_t *cpu; int cpuid; /* Don't use ARCS. ARCS is fragile. Klconfig is simple and sane. */ board = find_lboard(KL_CONFIG_INFO(get_nasid()), KLTYPE_IP27); if (!board) panic("Can't find board info for myself."); cpuid = LOCAL_HUB_L(PI_CPU_NUM) ? IP27_CPU0_INDEX : IP27_CPU1_INDEX; cpu = (klcpu_t *) KLCF_COMP(board, cpuid); if (!cpu) panic("No information about myself?"); printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed); set_c0_status(SRB_TIMOCLK); }
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 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(); }
/* * get_nasid() returns the physical node id number of the caller. */ nasid_t get_nasid(void) { return (nasid_t)((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_NODEID_MASK) >> NSRI_NODEID_SHFT); }
static int is_fine_dirmode(void) { return (((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK) >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE); }