/* * Free the hub CRB "crbnum" which encountered an error. * Assumption is, error handling was successfully done, * and we now want to return the CRB back to Hub for normal usage. * * In order to free the CRB, all that's needed is to de-allocate it * * Assumption: * No other processor is mucking around with the hub control register. * So, upper layer has to single thread this. */ void hubiio_crb_free(hubinfo_t hinfo, int crbnum) { ii_icrb0_b_u_t icrbb; /* * The hardware does NOT clear the mark bit, so it must get cleared * here to be sure the error is not processed twice. */ icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICRB_B(crbnum)); icrbb.b_mark = 0; REMOTE_HUB_S(hinfo->h_nasid, IIO_ICRB_B(crbnum), icrbb.ii_icrb0_b_regval); /* * Deallocate the register. */ REMOTE_HUB_S(hinfo->h_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum)); /* * Wait till hub indicates it's done. */ while (REMOTE_HUB_L(hinfo->h_nasid, IIO_ICDR) & IIO_ICDR_PND) us_delay(1); }
/** * hub_set_piomode - set pio mode for a given hub * * @nasid: physical node ID for the hub in question * * Put the hub into either "PIO conveyor belt" mode or "fire-and-forget" mode. * To do this, we have to make absolutely sure that no PIOs are in progress * so we turn off access to all widgets for the duration of the function. * * XXX - This code should really check what kind of widget we're talking * to. Bridges can only handle three requests, but XG will do more. * How many can crossbow handle to widget 0? We're assuming 1. * * XXX - There is a bug in the crossbow that link reset PIOs do not * return write responses. The easiest solution to this problem is to * leave widget 0 (xbow) in fire-and-forget mode at all times. This * only affects pio's to xbow registers, which should be rare. **/ static void hub_set_piomode(nasid_t nasid) { hubreg_t ii_iowa; hubii_wcr_t ii_wcr; unsigned i; ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS); REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0); ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR); if (ii_wcr.iwcr_dir_con) { /* * Assume a bridge here. */ hub_setup_prb(nasid, 0, 3); } else { /* * Assume a crossbow here. */ hub_setup_prb(nasid, 0, 1); } /* * XXX - Here's where we should take the widget type into * when account assigning credits. */ for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++) hub_setup_prb(nasid, i, 3); REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa); }
void hub_error_clear(nasid_t nasid) { int i; /* * Make sure spurious write response errors are cleared * (values are from hub_set_prb()) */ for (i = 0; i <= HUB_WIDGET_ID_MAX - HUB_WIDGET_ID_MIN + 1; i++) { iprb_t prb; prb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t))); /* Clear out some fields */ prb.iprb_ovflow = 1; prb.iprb_bnakctr = 0; prb.iprb_anakctr = 0; prb.iprb_xtalkctr = 3; /* approx. PIO credits for the widget */ REMOTE_HUB_S(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t)), prb.iprb_regval); } REMOTE_HUB_S(nasid, IIO_IECLR, -1); }
/* * hub_set_piomode() * * Put the hub into either "PIO conveyor belt" mode or "fire-and-forget" * mode. To do this, we have to make absolutely sure that no PIOs * are in progress so we turn off access to all widgets for the duration * of the function. * * XXX - This code should really check what kind of widget we're talking * to. Bridges can only handle three requests, but XG will do more. * How many can crossbow handle to widget 0? We're assuming 1. * * XXX - There is a bug in the crossbow that link reset PIOs do not * return write responses. The easiest solution to this problem is to * leave widget 0 (xbow) in fire-and-forget mode at all times. This * only affects pio's to xbow registers, which should be rare. */ void hub_set_piomode(nasid_t nasid, int conveyor) { hubreg_t ii_iowa; int direct_connect; hubii_wcr_t ii_wcr; int prbnum; int s, cons_lock = 0; ASSERT(NASID_TO_COMPACT_NODEID(nasid) != INVALID_CNODEID); if (nasid == get_console_nasid()) { PUTBUF_LOCK(s); cons_lock = 1; } ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS); REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0); ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR); direct_connect = ii_wcr.iwcr_dir_con; if (direct_connect) { /* * Assume a bridge here. */ hub_setup_prb(nasid, 0, 3, conveyor); } else { /* * Assume a crossbow here. */ hub_setup_prb(nasid, 0, 1, conveyor); } for (prbnum = HUB_WIDGET_ID_MIN; prbnum <= HUB_WIDGET_ID_MAX; prbnum++) { /* * XXX - Here's where we should take the widget type into * when account assigning credits. */ /* Always set the PRBs in fire-and-forget mode */ hub_setup_prb(nasid, prbnum, 3, conveyor); } #ifdef IRIX /* * In direct connect mode, disable access to all widgets but 0. * Later, the prom will do this for us. */ if (direct_connect) ii_iowa = 1; #endif REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa); if (cons_lock) PUTBUF_UNLOCK(s); }
/* * per_hub_init * * This code is executed once for each Hub chip. */ static void per_hub_init(cnodeid_t cnode) { nasid_t nasid; nodepda_t *npdap; ii_icmr_u_t ii_icmr; ii_ibcr_u_t ii_ibcr; ii_ilcsr_u_t ii_ilcsr; nasid = cnodeid_to_nasid(cnode); ASSERT(nasid != INVALID_NASID); ASSERT(nasid_to_cnodeid(nasid) == cnode); npdap = NODEPDA(cnode); /* Disable the request and reply errors. */ REMOTE_HUB_S(nasid, IIO_IWEIM, 0xC000); /* * Set the total number of CRBs that can be used. */ ii_icmr.ii_icmr_regval = 0x0; ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xf; if (enable_shub_wars_1_1()) { // Set bit one of ICMR to prevent II from sending interrupt for II bug. ii_icmr.ii_icmr_regval |= 0x1; } REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval); /* * Set the number of CRBs that both of the BTEs combined * can use minus 1. */ ii_ibcr.ii_ibcr_regval = 0x0; ii_ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(nasid, IIO_LLP_CSR); if (ii_ilcsr.ii_ilcsr_fld_s.i_llp_stat & LNK_STAT_WORKING) { ii_ibcr.ii_ibcr_fld_s.i_count = 0x8; } else { /* * if the LLP is down, there is no attached I/O, so * give BTE all the CRBs. */ ii_ibcr.ii_ibcr_fld_s.i_count = 0x14; } REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval); /* * Set CRB timeout to be 10ms. */ REMOTE_HUB_S(nasid, IIO_ICTP, 0xffffff); REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); /* Initialize error interrupts for this hub. */ hub_error_init(cnode); }
static void tio_corelet_reset(nasid_t nasid, int corelet) { if (!(nasid & 1)) return; REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 1 << corelet); udelay(2000); REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 0); udelay(2000); }
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 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 intr_clear_all(nasid_t nasid) { REMOTE_HUB_S(nasid, PI_INT_MASK0_A, 0); REMOTE_HUB_S(nasid, PI_INT_MASK0_B, 0); REMOTE_HUB_S(nasid, PI_INT_MASK1_A, 0); REMOTE_HUB_S(nasid, PI_INT_MASK1_B, 0); intr_clear_bits(nasid, REMOTE_HUB_ADDR(nasid, PI_INT_PEND0), INT_PEND0_BASELVL); intr_clear_bits(nasid, REMOTE_HUB_ADDR(nasid, PI_INT_PEND1), INT_PEND1_BASELVL); }
void hubii_eint_init(cnodeid_t cnode) { int bit, rv; ii_iidsr_u_t hubio_eint; hubinfo_t hinfo; cpuid_t intr_cpu; devfs_handle_t hub_v; ii_ilcsr_u_t ilcsr; int bit_pos_to_irq(int bit); int synergy_intr_connect(int bit, int cpuid); hub_v = (devfs_handle_t)cnodeid_to_vertex(cnode); ASSERT_ALWAYS(hub_v); hubinfo_get(hub_v, &hinfo); ASSERT(hinfo); ASSERT(hinfo->h_cnodeid == cnode); ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { /* * HUB II link is not up. * Just disable LLP, and don't connect any interrupts. */ ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); return; } /* Select a possible interrupt target where there is a free interrupt * bit and also reserve the interrupt bit for this IO error interrupt */ intr_cpu = intr_heuristic(hub_v,0,INTRCONNECT_ANYBIT,II_ERRORINT,hub_v, "HUB IO error interrupt",&bit); if (intr_cpu == CPU_NONE) { printk("hubii_eint_init: intr_reserve_level failed, cnode %d", cnode); return; } rv = intr_connect_level(intr_cpu, bit, 0, NULL); synergy_intr_connect(bit, intr_cpu); request_irq(bit_pos_to_irq(bit) + (intr_cpu << 8), hubii_eint_handler, 0, "SN hub error", (void *)hub_v); ASSERT_ALWAYS(rv >= 0); hubio_eint.ii_iidsr_regval = 0; hubio_eint.ii_iidsr_fld_s.i_enable = 1; hubio_eint.ii_iidsr_fld_s.i_level = bit;/* Take the least significant bits*/ hubio_eint.ii_iidsr_fld_s.i_node = COMPACT_TO_NASID_NODEID(cnode); hubio_eint.ii_iidsr_fld_s.i_pi_id = cpuid_to_subnode(intr_cpu); REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, hubio_eint.ii_iidsr_regval); }
static __init void intr_clear_all(nasid_t nasid) { int i; REMOTE_HUB_S(nasid, PI_INT_MASK0_A, 0); REMOTE_HUB_S(nasid, PI_INT_MASK0_B, 0); REMOTE_HUB_S(nasid, PI_INT_MASK1_A, 0); REMOTE_HUB_S(nasid, PI_INT_MASK1_B, 0); for (i = 0; i < 128; i++) REMOTE_HUB_CLR_INTR(nasid, i); }
void hubii_eint_init(cnodeid_t cnode) { int bit, rv; ii_iidsr_u_t hubio_eint; hubinfo_t hinfo; cpuid_t intr_cpu; vertex_hdl_t hub_v; int bit_pos_to_irq(int bit); ii_ilcsr_u_t ilcsr; hub_v = (vertex_hdl_t)cnodeid_to_vertex(cnode); ASSERT_ALWAYS(hub_v); hubinfo_get(hub_v, &hinfo); ASSERT(hinfo); ASSERT(hinfo->h_cnodeid == cnode); ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { /* * HUB II link is not up. Disable LLP. Clear old errors. * Enable interrupts to handle BTE errors. */ ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); } /* Select a possible interrupt target where there is a free interrupt * bit and also reserve the interrupt bit for this IO error interrupt */ intr_cpu = intr_heuristic(hub_v,0,SGI_II_ERROR,0,hub_v, "HUB IO error interrupt",&bit); if (intr_cpu == CPU_NONE) { printk("hubii_eint_init: intr_reserve_level failed, cnode %d", cnode); return; } rv = intr_connect_level(intr_cpu, SGI_II_ERROR, 0, NULL); request_irq(SGI_II_ERROR, hubii_eint_handler, SA_SHIRQ, "SN_hub_error", (void *)hub_v); irq_desc(bit)->status |= SN2_IRQ_PER_HUB; ASSERT_ALWAYS(rv >= 0); hubio_eint.ii_iidsr_regval = 0; hubio_eint.ii_iidsr_fld_s.i_enable = 1; hubio_eint.ii_iidsr_fld_s.i_level = bit;/* Take the least significant bits*/ hubio_eint.ii_iidsr_fld_s.i_node = COMPACT_TO_NASID_NODEID(cnode); hubio_eint.ii_iidsr_fld_s.i_pi_id = cpuid_to_subnode(intr_cpu); REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, hubio_eint.ii_iidsr_regval); }
static inline void shub_mmr_write_iospace(cnodeid_t cnode, shubreg_t reg, uint64_t val) { int nasid = cnodeid_to_nasid(cnode); REMOTE_HUB_S(nasid, reg, val); }
/* * hub_setup_prb(nasid, prbnum, credits, conveyor) * * Put a PRB into fire-and-forget mode if conveyor isn't set. Otherwise, * put it into conveyor belt mode with the specified number of credits. */ static void hub_setup_prb(nasid_t nasid, int prbnum, int credits) { iprb_t prb; int prb_offset; /* * Get the current register value. */ prb_offset = IIO_IOPRB(prbnum); prb.iprb_regval = REMOTE_HUB_L(nasid, prb_offset); /* * Clear out some fields. */ prb.iprb_ovflow = 1; prb.iprb_bnakctr = 0; prb.iprb_anakctr = 0; /* * Enable or disable fire-and-forget mode. */ prb.iprb_ff = force_fire_and_forget ? 1 : 0; /* * Set the appropriate number of PIO cresits for the widget. */ prb.iprb_xtalkctr = credits; /* * Store the new value to the register. */ REMOTE_HUB_S(nasid, prb_offset, prb.iprb_regval); }
static int intr_connect_level(int cpu, int bit) { nasid_t nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu)); struct slice_data *si = cpu_data[cpu].data; set_bit(bit, si->irq_enable_mask); if (!cputoslice(cpu)) { REMOTE_HUB_S(nasid, PI_INT_MASK0_A, si->irq_enable_mask[0]); REMOTE_HUB_S(nasid, PI_INT_MASK1_A, si->irq_enable_mask[1]); } else { REMOTE_HUB_S(nasid, PI_INT_MASK0_B, si->irq_enable_mask[0]); REMOTE_HUB_S(nasid, PI_INT_MASK1_B, si->irq_enable_mask[1]); } return 0; }
static int mmtimer_disable_int(long nasid, int comparator) { switch (comparator) { case 0: nasid == -1 ? HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC1_INT_ENABLE), 0UL) : REMOTE_HUB_S(nasid, SH_RTC1_INT_ENABLE, 0UL); break; case 1: nasid == -1 ? HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_ENABLE), 0UL) : REMOTE_HUB_S(nasid, SH_RTC2_INT_ENABLE, 0UL); break; case 2: nasid == -1 ? HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_ENABLE), 0UL) : REMOTE_HUB_S(nasid, SH_RTC3_INT_ENABLE, 0UL); break; default: return -EFAULT; } return 0; }
/* * io_sh_swapper: Turn on Shub byte swapping. * All data destined to and from Shub to XIO are byte-swapped. */ void io_sh_swapper(nasid_t nasid, int onoff) { ii_iwc_u_t ii_iwc; ii_iwc.ii_iwc_regval = REMOTE_HUB_L(nasid, IIO_IWC); ii_iwc.ii_iwc_fld_s.i_dma_byte_swap = onoff; REMOTE_HUB_S(nasid, IIO_IWC, ii_iwc.ii_iwc_regval); ii_iwc.ii_iwc_regval = REMOTE_HUB_L(nasid, IIO_IWC); }
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 void __init per_hub_init(cnodeid_t cnode) { struct hub_data *hub = hub_data(cnode); nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); 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 }
/* 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; }
/* * hub_setup_prb(nasid, prbnum, credits, conveyor) * * Put a PRB into fire-and-forget mode if conveyor isn't set. Otehrwise, * put it into conveyor belt mode with the specified number of credits. */ void hub_setup_prb(nasid_t nasid, int prbnum, int credits, int conveyor) { iprb_t prb; int prb_offset; #ifdef IRIX extern int force_fire_and_forget; extern volatile int ignore_conveyor_override; if (force_fire_and_forget && !ignore_conveyor_override) if (conveyor == HUB_PIO_CONVEYOR) conveyor = HUB_PIO_FIRE_N_FORGET; #endif /* * Get the current register value. */ prb_offset = IIO_IOPRB(prbnum); prb.iprb_regval = REMOTE_HUB_L(nasid, prb_offset); /* * Clear out some fields. */ prb.iprb_ovflow = 1; prb.iprb_bnakctr = 0; prb.iprb_anakctr = 0; /* * Enable or disable fire-and-forget mode. */ prb.iprb_ff = ((conveyor == HUB_PIO_CONVEYOR) ? 0 : 1); /* * Set the appropriate number of PIO cresits for the widget. */ prb.iprb_xtalkctr = credits; /* * Store the new value to the register. */ REMOTE_HUB_S(nasid, prb_offset, prb.iprb_regval); }
static void tio_conveyor_set(nasid_t nasid, int enable_flag) { u64 ice_frz; u64 disable_cb = (1ull << 61); if (!(nasid & 1)) return; ice_frz = REMOTE_HUB_L(nasid, TIO_ICE_FRZ_CFG); if (enable_flag) { if (!(ice_frz & disable_cb)) /* already enabled */ return; ice_frz &= ~disable_cb; } else { if (ice_frz & disable_cb) /* already disabled */ return; ice_frz |= disable_cb; } DBG(KERN_ALERT "TIO_ICE_FRZ_CFG= 0x%lx\n", ice_frz); REMOTE_HUB_S(nasid, TIO_ICE_FRZ_CFG, ice_frz); }
/* BRINGUP: This ought to be useful for IP27 too but, for now, * make it SN1 only because `ii_ixtt_u_t' is not in IP27/hubio.h * (or anywhere else :-). */ int hubii_ixtt_set(devfs_handle_t widget_vhdl, ii_ixtt_u_t *ixtt) { xwidget_info_t widget_info = xwidget_info_get(widget_vhdl); devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info); hubinfo_t hub_info = 0; nasid_t nasid; int s; /* Use the nasid from the hub info hanging off the hub vertex * and widget number from the widget vertex */ hubinfo_get(hub_vhdl, &hub_info); /* Being over cautious by grabbing a lock */ s = mutex_spinlock(&hub_info->h_bwlock); nasid = hub_info->h_nasid; REMOTE_HUB_S(nasid, IIO_IXTT, ixtt->ii_ixtt_regval); mutex_spinunlock(&hub_info->h_bwlock, s); return 0; }
void hub_error_clear(nasid_t nasid) { int i; hubreg_t idsr; int sn; for(sn=0; sn<NUM_SUBNODES; sn++) { REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_PEND, -1); REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS0_A_CLR, -1); REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS0_B_CLR, -1); REMOTE_HUB_PI_S(nasid, sn, PI_SPURIOUS_HDR_0, 0); REMOTE_HUB_PI_S(nasid, sn, PI_SPURIOUS_HDR_1, 0); } REMOTE_HUB_L(nasid, MD_DIR_ERROR_CLR); REMOTE_HUB_L(nasid, MD_MEM_ERROR_CLR); REMOTE_HUB_L(nasid, MD_MISC1_ERROR_CLR); REMOTE_HUB_L(nasid, MD_PROTOCOL_ERR_CLR); /* * Make sure spurious write response errors are cleared * (values are from hub_set_prb()) */ for (i = 0; i <= HUB_WIDGET_ID_MAX - HUB_WIDGET_ID_MIN + 1; i++) { iprb_t prb; prb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t))); /* Clear out some fields */ prb.iprb_ovflow = 1; prb.iprb_bnakctr = 0; prb.iprb_anakctr = 0; /* * PIO reads in fire-and-forget mode on bedrock 1.0 don't * frob the credit count properly, making the responses appear * spurious. So don't use fire-and-forget mode. Bug 761802. */ prb.iprb_ff = 0; /* disable fire-and-forget mode by default */ prb.iprb_xtalkctr = 3; /* approx. PIO credits for the widget */ REMOTE_HUB_S(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t)), prb.iprb_regval); } REMOTE_HUB_S(nasid, IIO_IO_ERR_CLR, -1); idsr = REMOTE_HUB_L(nasid, IIO_IIDSR); REMOTE_HUB_S(nasid, IIO_IIDSR, (idsr & ~(IIO_IIDSR_SENT_MASK))); REMOTE_HUB_L(nasid, NI_PORT_ERROR_CLEAR); /* No need to clear NI_PORT_HEADER regs; they are continually overwritten*/ REMOTE_HUB_S(nasid, LB_ERROR_MASK_CLR, -1); REMOTE_HUB_S(nasid, LB_ERROR_HDR1, 0); /* Clear XB error regs, in order */ for (i = 0; i <= XB_FIRST_ERROR_CLEAR - XB_POQ0_ERROR_CLEAR; i += sizeof(hubreg_t)) { REMOTE_HUB_S(nasid, XB_POQ0_ERROR_CLEAR + i, 0); } }
/* * Wait until all BTE related CRBs are completed * and then reset the interfaces. */ int shub1_bte_error_handler(unsigned long _nodepda) { struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda; struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer; nasid_t nasid; int i; int valid_crbs; ii_imem_u_t imem; /* II IMEM Register */ ii_icrb0_d_u_t icrbd; /* II CRB Register D */ ii_ibcr_u_t ibcr; ii_icmr_u_t icmr; ii_ieclr_u_t ieclr; BTE_PRINTK(("shub1_bte_error_handler(%p) - %d\n", err_nodepda, smp_processor_id())); if ((err_nodepda->bte_if[0].bh_error == BTE_SUCCESS) && (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) { BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda, smp_processor_id())); return 1; } /* Determine information about our hub */ nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode); /* * A BTE transfer can use multiple CRBs. We need to make sure * that all the BTE CRBs are complete (or timed out) before * attempting to clean up the error. Resetting the BTE while * there are still BTE CRBs active will hang the BTE. * We should look at all the CRBs to see if they are allocated * to the BTE and see if they are still active. When none * are active, we can continue with the cleanup. * * We also want to make sure that the local NI port is up. * When a router resets the NI port can go down, while it * goes through the LLP handshake, but then comes back up. */ icmr.ii_icmr_regval = REMOTE_HUB_L(nasid, IIO_ICMR); if (icmr.ii_icmr_fld_s.i_crb_mark != 0) { /* * There are errors which still need to be cleaned up by * hubiio_crb_error_handler */ mod_timer(recovery_timer, jiffies + (HZ * 5)); BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda, smp_processor_id())); return 1; } if (icmr.ii_icmr_fld_s.i_crb_vld != 0) { valid_crbs = icmr.ii_icmr_fld_s.i_crb_vld; for (i = 0; i < IIO_NUM_CRBS; i++) { if (!((1 << i) & valid_crbs)) { /* This crb was not marked as valid, ignore */ continue; } icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i)); if (icrbd.d_bteop) { mod_timer(recovery_timer, jiffies + (HZ * 5)); BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n", err_nodepda, smp_processor_id(), i)); return 1; } } } BTE_PRINTK(("eh:%p:%d Cleaning up\n", err_nodepda, smp_processor_id())); /* Re-enable both bte interfaces */ imem.ii_imem_regval = REMOTE_HUB_L(nasid, IIO_IMEM); imem.ii_imem_fld_s.i_b0_esd = imem.ii_imem_fld_s.i_b1_esd = 1; REMOTE_HUB_S(nasid, IIO_IMEM, imem.ii_imem_regval); /* Clear BTE0/1 error bits */ ieclr.ii_ieclr_regval = 0; if (err_nodepda->bte_if[0].bh_error != BTE_SUCCESS) ieclr.ii_ieclr_fld_s.i_e_bte_0 = 1; if (err_nodepda->bte_if[1].bh_error != BTE_SUCCESS) ieclr.ii_ieclr_fld_s.i_e_bte_1 = 1; REMOTE_HUB_S(nasid, IIO_IECLR, ieclr.ii_ieclr_regval); /* Reinitialize both BTE state machines. */ ibcr.ii_ibcr_regval = REMOTE_HUB_L(nasid, IIO_IBCR); ibcr.ii_ibcr_fld_s.i_soft_reset = 1; REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval); del_timer(recovery_timer); return 0; }
/*ARGSUSED*/ void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) { devfs_handle_t hub_v; hubinfo_t hinfo; ii_wstat_u_t wstat; hubreg_t idsr; panic("Hubii interrupt\n"); #ifdef ajm /* * If the NI has a problem, everyone has a problem. We shouldn't * even attempt to handle other errors when an NI error is present. */ if (check_ni_errors()) { hubni_error_handler("II interrupt", 1); /* NOTREACHED */ } /* two levels of casting avoids compiler warning.!! */ hub_v = (devfs_handle_t)(long)(arg); ASSERT(hub_v); hubinfo_get(hub_v, &hinfo); /* * Identify the reason for error. */ wstat.ii_wstat_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_WSTAT); if (wstat.ii_wstat_fld_s.w_crazy) { char *reason; /* * We can do a couple of things here. * Look at the fields TX_MX_RTY/XT_TAIL_TO/XT_CRD_TO to check * which of these caused the CRAZY bit to be set. * You may be able to check if the Link is up really. */ if (wstat.ii_wstat_fld_s.w_tx_mx_rty) reason = "Micro Packet Retry Timeout"; else if (wstat.ii_wstat_fld_s.w_xt_tail_to) reason = "Crosstalk Tail Timeout"; else if (wstat.ii_wstat_fld_s.w_xt_crd_to) reason = "Crosstalk Credit Timeout"; else { hubreg_t hubii_imem; /* * Check if widget 0 has been marked as shutdown, or * if BTE 0/1 has been marked. */ hubii_imem = REMOTE_HUB_L(hinfo->h_nasid, IIO_IMEM); if (hubii_imem & IIO_IMEM_W0ESD) reason = "Hub Widget 0 has been Shutdown"; else if (hubii_imem & IIO_IMEM_B0ESD) reason = "BTE 0 has been shutdown"; else if (hubii_imem & IIO_IMEM_B1ESD) reason = "BTE 1 has been shutdown"; else reason = "Unknown"; } /* * Note: we may never be able to print this, if the II talking * to Xbow which hosts the console is dead. */ printk("Hub %d to Xtalk Link failed (II_ECRAZY) Reason: %s", hinfo->h_cnodeid, reason); } /* * It's a toss as to which one among PRB/CRB to check first. * Current decision is based on the severity of the errors. * IO CRB errors tend to be more severe than PRB errors. * * It is possible for BTE errors to have been handled already, so we * may not see any errors handled here. */ (void)hubiio_crb_error_handler(hub_v, hinfo); (void)hubiio_prb_error_handler(hub_v, hinfo); /* * If we reach here, it indicates crb/prb handlers successfully * handled the error. So, re-enable II to send more interrupt * and return. */ REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, 0xffffff); idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR) & ~IIO_IIDSR_SENT_MASK; REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, idsr); #endif /* ajm */ }
/* * Second part error handler. Wait until all BTE related CRBs are completed * and then reset the interfaces. */ void bte_error_handler(unsigned long _nodepda) { struct nodepda_s *err_nodepda = (struct nodepda_s *) _nodepda; spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock; struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer; nasid_t nasid; int i; int valid_crbs; unsigned long irq_flags; volatile u64 *notify; bte_result_t bh_error; ii_imem_u_t imem; /* II IMEM Register */ ii_icrb0_d_u_t icrbd; /* II CRB Register D */ ii_ibcr_u_t ibcr; ii_icmr_u_t icmr; ii_ieclr_u_t ieclr; BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda, smp_processor_id())); spin_lock_irqsave(recovery_lock, irq_flags); if ((err_nodepda->bte_if[0].bh_error == BTE_SUCCESS) && (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) { BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda, smp_processor_id())); spin_unlock_irqrestore(recovery_lock, irq_flags); return; } /* * Lock all interfaces on this node to prevent new transfers * from being queued. */ for (i = 0; i < BTES_PER_NODE; i++) { if (err_nodepda->bte_if[i].cleanup_active) { continue; } spin_lock(&err_nodepda->bte_if[i].spinlock); BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda, smp_processor_id(), i)); err_nodepda->bte_if[i].cleanup_active = 1; } /* Determine information about our hub */ nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode); /* * A BTE transfer can use multiple CRBs. We need to make sure * that all the BTE CRBs are complete (or timed out) before * attempting to clean up the error. Resetting the BTE while * there are still BTE CRBs active will hang the BTE. * We should look at all the CRBs to see if they are allocated * to the BTE and see if they are still active. When none * are active, we can continue with the cleanup. * * We also want to make sure that the local NI port is up. * When a router resets the NI port can go down, while it * goes through the LLP handshake, but then comes back up. */ icmr.ii_icmr_regval = REMOTE_HUB_L(nasid, IIO_ICMR); if (icmr.ii_icmr_fld_s.i_crb_mark != 0) { /* * There are errors which still need to be cleaned up by * hubiio_crb_error_handler */ mod_timer(recovery_timer, HZ * 5); BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda, smp_processor_id())); spin_unlock_irqrestore(recovery_lock, irq_flags); return; } if (icmr.ii_icmr_fld_s.i_crb_vld != 0) { valid_crbs = icmr.ii_icmr_fld_s.i_crb_vld; for (i = 0; i < IIO_NUM_CRBS; i++) { if (!((1 << i) & valid_crbs)) { /* This crb was not marked as valid, ignore */ continue; } icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i)); if (icrbd.d_bteop) { mod_timer(recovery_timer, HZ * 5); BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n", err_nodepda, smp_processor_id(), i)); spin_unlock_irqrestore(recovery_lock, irq_flags); return; } } } BTE_PRINTK(("eh:%p:%d Cleaning up\n", err_nodepda, smp_processor_id())); /* Reenable both bte interfaces */ imem.ii_imem_regval = REMOTE_HUB_L(nasid, IIO_IMEM); imem.ii_imem_fld_s.i_b0_esd = imem.ii_imem_fld_s.i_b1_esd = 1; REMOTE_HUB_S(nasid, IIO_IMEM, imem.ii_imem_regval); /* Clear IBLS0/1 error bits */ ieclr.ii_ieclr_regval = 0; if (err_nodepda->bte_if[0].bh_error != BTE_SUCCESS) ieclr.ii_ieclr_fld_s.i_e_bte_0 = 1; if (err_nodepda->bte_if[1].bh_error != BTE_SUCCESS) ieclr.ii_ieclr_fld_s.i_e_bte_1 = 1; REMOTE_HUB_S(nasid, IIO_IECLR, ieclr.ii_ieclr_regval); /* Reinitialize both BTE state machines. */ ibcr.ii_ibcr_regval = REMOTE_HUB_L(nasid, IIO_IBCR); ibcr.ii_ibcr_fld_s.i_soft_reset = 1; REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval); for (i = 0; i < BTES_PER_NODE; i++) { bh_error = err_nodepda->bte_if[i].bh_error; if (bh_error != BTE_SUCCESS) { /* There is an error which needs to be notified */ notify = err_nodepda->bte_if[i].most_rcnt_na; BTE_PRINTK(("cnode %d bte %d error=0x%lx\n", err_nodepda->bte_if[i].bte_cnode, err_nodepda->bte_if[i].bte_num, IBLS_ERROR | (u64) bh_error)); *notify = IBLS_ERROR | bh_error; err_nodepda->bte_if[i].bh_error = BTE_SUCCESS; } err_nodepda->bte_if[i].cleanup_active = 0; BTE_PRINTK(("eh:%p:%d Unlocked %d\n", err_nodepda, smp_processor_id(), i)); spin_unlock(&err_nodepda->bte_if[i].spinlock); } del_timer(recovery_timer); spin_unlock_irqrestore(recovery_lock, irq_flags); }
/*ARGSUSED*/ irqreturn_t hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) { vertex_hdl_t hub_v; hubinfo_t hinfo; ii_wstat_u_t wstat; hubreg_t idsr; ii_ilcsr_u_t ilcsr; /* two levels of casting avoids compiler warning.!! */ hub_v = (vertex_hdl_t)(long)(arg); ASSERT(hub_v); hubinfo_get(hub_v, &hinfo); idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICMR); #if 0 if (idsr & 0x1) { /* ICMR bit is set .. we are getting into "Spurious Interrupts condition. */ printk("Cnode %d II has seen the ICMR condition\n", hinfo->h_cnodeid); printk("***** Please file PV with the above messages *****\n"); /* panic("We have to panic to prevent further unknown states ..\n"); */ } #endif /* * Identify the reason for error. */ wstat.ii_wstat_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_WSTAT); if (wstat.ii_wstat_fld_s.w_crazy) { char *reason; /* * We can do a couple of things here. * Look at the fields TX_MX_RTY/XT_TAIL_TO/XT_CRD_TO to check * which of these caused the CRAZY bit to be set. * You may be able to check if the Link is up really. */ if (wstat.ii_wstat_fld_s.w_tx_mx_rty) reason = "Micro Packet Retry Timeout"; else if (wstat.ii_wstat_fld_s.w_xt_tail_to) reason = "Crosstalk Tail Timeout"; else if (wstat.ii_wstat_fld_s.w_xt_crd_to) reason = "Crosstalk Credit Timeout"; else { hubreg_t hubii_imem; /* * Check if widget 0 has been marked as shutdown, or * if BTE 0/1 has been marked. */ hubii_imem = REMOTE_HUB_L(hinfo->h_nasid, IIO_IMEM); if (hubii_imem & IIO_IMEM_W0ESD) reason = "Hub Widget 0 has been Shutdown"; else if (hubii_imem & IIO_IMEM_B0ESD) reason = "BTE 0 has been shutdown"; else if (hubii_imem & IIO_IMEM_B1ESD) reason = "BTE 1 has been shutdown"; else reason = "Unknown"; } /* * Note: we may never be able to print this, if the II talking * to Xbow which hosts the console is dead. */ ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); if (ilcsr.ii_ilcsr_fld_s.i_llp_en == 1) { /* Link is enabled */ printk("Hub %d, cnode %d to Xtalk Link failed (II_ECRAZY) Reason: %s", hinfo->h_nasid, hinfo->h_cnodeid, reason); } } /* * Before processing any interrupt related information, clear all * error indication and reenable interrupts. This will prevent * lost interrupts due to the interrupt handler scanning past a PRB/CRB * which has not errorred yet and then the PRB/CRB goes into error. * Note, PRB errors are cleared individually. */ REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, 0xff0000); idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR) & ~IIO_IIDSR_SENT_MASK; REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, idsr); /* * It's a toss as to which one among PRB/CRB to check first. * Current decision is based on the severity of the errors. * IO CRB errors tend to be more severe than PRB errors. * * It is possible for BTE errors to have been handled already, so we * may not see any errors handled here. */ (void)hubiio_crb_error_handler(hub_v, hinfo); (void)hubiio_prb_error_handler(hub_v, hinfo); return IRQ_HANDLED; }
/* * >>> bte_crb_error_handler needs to be broken into two parts. The * first should cleanup the CRB. The second should wait until all bte * related CRB's are complete and then do the error reset. */ void bte_crb_error_handler(devfs_handle_t hub_v, int btenum, int crbnum, ioerror_t *ioe, int bteop) /* * Function: bte_crb_error_handler * Purpose: Process a CRB for a specific HUB/BTE * Parameters: hub_v - vertex of hub in HW graph * btenum - bte number on hub (0 == a, 1 == b) * crbnum - crb number being processed * Notes: * This routine assumes serialization at a higher level. A CRB * should not be processed more than once. The error recovery * follows the following sequence - if you change this, be real * sure about what you are doing. * */ { hubinfo_t hinfo; icrba_t crba; icrbb_t crbb; nasid_t n; hubreg_t iidsr, imem, ieclr; hubinfo_get(hub_v, &hinfo); n = hinfo->h_nasid; /* * The following 10 lines (or so) are adapted from IRIXs * bte_crb_error function. No clear documentation tells * why the crb needs to complete normally in order for * the BTE to resume normal operations. This first step * appears vital! */ /* * Zero error and error code to prevent error_dump complaining * about these CRBs. Copy the CRB to the notification line. * The crb address is in shub format (physical address shifted * right by cacheline size). */ crbb.ii_icrb0_b_regval = REMOTE_HUB_L(n, IIO_ICRB_B(crbnum)); crbb.b_error=0; crbb.b_ecode=0; REMOTE_HUB_S(n, IIO_ICRB_B(crbnum), crbb.ii_icrb0_b_regval); crba.ii_icrb0_a_regval = REMOTE_HUB_L(n, IIO_ICRB_A(crbnum)); crba.a_addr = TO_PHYS((u64)&nodepda->bte_if[btenum].notify) >> 3; crba.a_valid = 1; REMOTE_HUB_S(n, IIO_ICRB_A(crbnum), crba.ii_icrb0_a_regval); REMOTE_HUB_S(n, IIO_ICCR, IIO_ICCR_PENDING | IIO_ICCR_CMD_FLUSH | crbnum); while (REMOTE_HUB_L(n, IIO_ICCR) & IIO_ICCR_PENDING) ; /* Terminate the BTE. */ /* >>> The other bte transfer will need to be restarted. */ HUB_L((shubreg_t *)((nodepda->bte_if[btenum].bte_base_addr + IIO_IBCT0 - IIO_IBLS0))); imem = REMOTE_HUB_L(n, IIO_IMEM); ieclr = REMOTE_HUB_L(n, IIO_IECLR); if (btenum == 0) { imem |= IIO_IMEM_W0ESD | IIO_IMEM_B0ESD; ieclr|= IECLR_BTE0; } else { imem |= IIO_IMEM_W0ESD | IIO_IMEM_B1ESD; ieclr|= IECLR_BTE1; } REMOTE_HUB_S(n, IIO_IMEM, imem); REMOTE_HUB_S(n, IIO_IECLR, ieclr); iidsr = REMOTE_HUB_L(n, IIO_IIDSR); iidsr &= ~IIO_IIDSR_SENT_MASK; iidsr |= IIO_IIDSR_ENB_MASK; REMOTE_HUB_S(n, IIO_IIDSR, iidsr); bte_reset_nasid(n); *nodepda->bte_if[btenum].most_rcnt_na = IBLS_ERROR; }