static inline uint64_t shub_mmr_read_iospace(cnodeid_t cnode, shubreg_t reg) { int nasid = cnodeid_to_nasid(cnode); return REMOTE_HUB_L(nasid, reg); }
/* * 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); }
xwidgetnum_t hub_widget_id(nasid_t nasid) { hubii_wcr_t ii_wcr; /* the control status register */ ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid,IIO_WCR); return ii_wcr.wcr_fields_s.wcr_widget_id; }
/* * io_get_sh_swapper: Return current Swap mode. * 1 = Swap on, 0 = Swap off. */ int io_get_sh_swapper(nasid_t nasid) { ii_iwc_u_t ii_iwc; ii_iwc.ii_iwc_regval = REMOTE_HUB_L(nasid, IIO_IWC); return(ii_iwc.ii_iwc_fld_s.i_dma_byte_swap); }
/* * 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 int bitstream_loaded(nasid_t nasid) { u64 cx_credits; cx_credits = REMOTE_HUB_L(nasid, TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3); cx_credits &= TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK; DBG("cx_credits= 0x%lx\n", cx_credits); return (cx_credits == 0xf) ? 1 : 0; }
static inline int __init is_shub_1_1(int nasid) { unsigned long id; int rev; if (is_shub2()) return 0; id = REMOTE_HUB_L(nasid, SH1_SHUB_ID); rev = (id & SH1_SHUB_ID_REVISION_MASK) >> SH1_SHUB_ID_REVISION_SHFT; return rev <= 2; }
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); }
/* * 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(struct hubdev_info *hubdev_info, 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(hubdev_info->hdi_nasid, IIO_ICRB_B(crbnum)); icrbb.b_mark = 0; REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICRB_B(crbnum), icrbb.ii_icrb0_b_regval); /* * Deallocate the register wait till hub indicates it's done. */ REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum)); while (REMOTE_HUB_L(hubdev_info->hdi_nasid, IIO_ICDR) & IIO_ICDR_PND) cpu_relax(); }
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 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 |= d
/* * 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)) /* */ return; ice_frz &= ~disable_cb; } else { if (ice_frz & disable_cb) /* */ 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); }
/* * Probe to see if this hub's xtalk link is active. If so, * return the Crosstalk Identification of the widget that we talk to. * This is called before any of the Crosstalk infrastructure for * this hub is set up. It's usually called on the node that we're * probing, but not always. * * TBD: Prom code should actually do this work, and pass through * hwid for our use. */ static void early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid) { hubreg_t llp_csr_reg; nasid_t nasid; hubinfo_t hubinfo; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); /* * If link is up, read the widget's part number. * A direct connect widget must respond to widgetnum=0. */ if (llp_csr_reg & IIO_LLP_CSR_IS_UP) { /* TBD: Put hub into "indirect" mode */ /* * We're able to read from a widget because our hub's * WIDGET_ID was set up earlier. */ widgetreg_t widget_id = *(volatile widgetreg_t *) (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id, (volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) ); hwid->part_num = XWIDGET_PART_NUM(widget_id); hwid->rev_num = XWIDGET_REV_NUM(widget_id); hwid->mfg_num = XWIDGET_MFG_NUM(widget_id); /* TBD: link reset */ } else { hwid->part_num = XWIDGET_PART_NUM_NONE; hwid->rev_num = XWIDGET_REV_NUM_NONE; hwid->mfg_num = XWIDGET_MFG_NUM_NONE; } }
int hubii_ixtt_get(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; ixtt->ii_ixtt_regval = REMOTE_HUB_L(nasid, IIO_IXTT); mutex_spinunlock(&hub_info->h_bwlock, s); return 0; }
/* * Probe to see if this hub's xtalk link is active. If so, * return the Crosstalk Identification of the widget that we talk to. * This is called before any of the Crosstalk infrastructure for * this hub is set up. It's usually called on the node that we're * probing, but not always. * * TBD: Prom code should actually do this work, and pass through * hwid for our use. */ static void early_probe_for_widget(vertex_hdl_t hubv, xwidget_hwid_t hwid) { nasid_t nasid; hubinfo_t hubinfo; hubreg_t llp_csr_reg; widgetreg_t widget_id; int result = 0; hwid->part_num = XWIDGET_PART_NUM_NONE; hwid->rev_num = XWIDGET_REV_NUM_NONE; hwid->mfg_num = XWIDGET_MFG_NUM_NONE; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); if (!(llp_csr_reg & IIO_LLP_CSR_IS_UP)) return; /* Read the Cross-Talk Widget Id on the other end */ result = snia_badaddr_val((volatile void *) (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID), 4, (void *) &widget_id); if (result == 0) { /* Found something connected */ hwid->part_num = XWIDGET_PART_NUM(widget_id); hwid->rev_num = XWIDGET_REV_NUM(widget_id); hwid->mfg_num = XWIDGET_MFG_NUM(widget_id); /* TBD: link reset */ } else { hwid->part_num = XWIDGET_PART_NUM_NONE; hwid->rev_num = XWIDGET_REV_NUM_NONE; hwid->mfg_num = XWIDGET_MFG_NUM_NONE; } }
/* * 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; }
/* * >>> 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; }
void hub_error_init(cnodeid_t cnode) { nasid_t nasid; nasid = cnodeid_to_nasid(cnode); hub_error_clear(nasid); #ifdef ajm if (cnode == 0) { /* * Allocate log for storing the node specific error info */ for (i = 0; i < numnodes; i++) { kl_error_log[i] = kmem_zalloc_node(sizeof(sn0_error_log_t), KM_NOSLEEP, i); hub_err_count[i] = kmem_zalloc_node(sizeof(hub_errcnt_t), VM_DIRECT | KM_NOSLEEP, i); ASSERT_ALWAYS(kl_error_log[i] && hub_err_count[i]); } } /* * Assumption: There will be only one cpu who will initialize * a hub. we need to setup the ii and each pi error interrupts. * The SN1 hub (bedrock) has two PI, one for up to two processors. */ if (cpuid_to_cnodeid(smp_processor_id()) == cnode) { int generic_intr_mask = PI_ERR_GENERIC; /* These interrupts are sent to only 1 CPU per NODE */ ASSERT_ALWAYS(kl_error_log[cnode]); ASSERT_ALWAYS(hub_err_count[cnode]); MD_ERR_LOG_INIT(kl_error_log[cnode]); /* One for each CPU */ recover_error_init(RECOVER_ERROR_TABLE(cnode, 0)); recover_error_init(RECOVER_ERROR_TABLE(cnode, 1)); recover_error_init(RECOVER_ERROR_TABLE(cnode, 2)); recover_error_init(RECOVER_ERROR_TABLE(cnode, 3)); /* * Setup error intr masks. */ for(sn=0; sn<NUM_SUBNODES; sn++) { int cpuA_present = REMOTE_HUB_PI_L(nasid, sn, PI_CPU_ENABLE_A); int cpuB_present = REMOTE_HUB_PI_L(nasid, sn, PI_CPU_ENABLE_B); if (cpuA_present) { if (cpuB_present) { /* A && B */ REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A, (PI_FATAL_ERR_CPU_B | PI_MISC_ERR_CPU_A|generic_intr_mask)); REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B, (PI_FATAL_ERR_CPU_A | PI_MISC_ERR_CPU_B)); } else { /* A && !B */ REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A, (PI_FATAL_ERR_CPU_A | PI_MISC_ERR_CPU_A|generic_intr_mask)); } generic_intr_mask = 0; } else { if (cpuB_present) { /* !A && B */ REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B, (PI_FATAL_ERR_CPU_B | PI_MISC_ERR_CPU_B|generic_intr_mask)); generic_intr_mask = 0; } else { /* !A && !B */ /* nothing to set up */ } } } /* * Turn off UNCAC_UNCORR interrupt in the masks. Anyone interested * in these errors will peek at the int pend register to see if its * set. */ for(sn=0; sn<NUM_SUBNODES; sn++) { misc = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_INT_MASK_A); REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A, (misc & ~PI_ERR_UNCAC_UNCORR_A)); misc = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_INT_MASK_B); REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B, (misc & ~PI_ERR_UNCAC_UNCORR_B)); } /* * enable all error indicators to turn on, in case of errors. * * This is not good on single cpu node boards. **** LOCAL_HUB_S(PI_SYSAD_ERRCHK_EN, PI_SYSAD_CHECK_ALL); */ for(sn=0; sn<NUM_SUBNODES; sn++) { REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS1_A_CLR, 0); REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS1_B_CLR, 0); } /* Set up stack for each present processor */ for(sn=0; sn<NUM_SUBNODES; sn++) { if (REMOTE_HUB_PI_L(nasid, sn, PI_CPU_PRESENT_A)) { SN0_ERROR_LOG(cnode)->el_spool_cur_addr[0] = SN0_ERROR_LOG(cnode)->el_spool_last_addr[0] = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_A); } if (REMOTE_HUB_PI_L(nasid, sn, PI_CPU_PRESENT_B)) { SN0_ERROR_LOG(cnode)->el_spool_cur_addr[1] = SN0_ERROR_LOG(cnode)->el_spool_last_addr[1] = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_B); } } PI_SPOOL_SIZE_BYTES = ERR_STACK_SIZE_BYTES(REMOTE_HUB_L(nasid, PI_ERR_STACK_SIZE)); #ifdef BRINGUP /* BRINGUP: The following code looks like a check to make sure the prom set up the error spool correctly for 2 processors. I don't think it is needed. */ for(sn=0; sn<NUM_SUBNODES; sn++) { if (REMOTE_HUB_PI_L(nasid, sn, PI_CPU_PRESENT_B)) { __psunsigned_t addr_a = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_A); __psunsigned_t addr_b = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_B); if ((addr_a & ~0xff) == (addr_b & ~0xff)) { REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STACK_ADDR_B, addr_b + PI_SPOOL_SIZE_BYTES); SN0_ERROR_LOG(cnode)->el_spool_cur_addr[1] = SN0_ERROR_LOG(cnode)->el_spool_last_addr[1] = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_B); } } } #endif /* BRINGUP */ /* programming our own hub. Enable error_int_pend intr. * If both present, CPU A takes CPU b's error interrupts and any * generic ones. CPU B takes CPU A error ints. */ if (cause_intr_connect (SRB_ERR_IDX, (intr_func_t)(hubpi_eint_handler), SR_ALL_MASK|SR_IE)) { cmn_err(ERR_WARN, "hub_error_init: cause_intr_connect failed on %d", cnode); } } else { /* programming remote hub. The only valid reason that this * is called will be on headless hubs. No interrupts */ for(sn=0; sn<NUM_SUBNODES; sn++) { REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A, 0); /* not necessary */ REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B, 0); /* not necessary */ } } #endif /* ajm */ /* * Now setup the hub ii and ni error interrupt handler. */ hubii_eint_init(cnode); hubni_eint_init(cnode); #ifdef ajm /*** XXX FIXME XXX resolve the following***/ /* INT_PEND1 bits set up for one hub only: * SHUTDOWN_INTR * MD_COR_ERR_INTR * COR_ERR_INTR_A and COR_ERR_INTR_B should be sent to the * appropriate CPU only. */ if (cnode == 0) { error_consistency_check.eps_state = 0; error_consistency_check.eps_cpuid = -1; spinlock_init(&error_consistency_check.eps_lock, "error_dump_lock"); } #endif nodepda->huberror_ticks = HUB_ERROR_PERIOD; return; }
unsigned long ip27_do_gettimeoffset(void) { unsigned long ct_cur1; ct_cur1 = REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT) + CYCLES_PER_JIFFY; return (ct_cur1 - ct_cur[0]) * NSEC_PER_CYCLE / 1000; }
/*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 */ }
void hubiio_crb_error_handler(struct hubdev_info *hubdev_info) { nasid_t nasid; ii_icrb0_a_u_t icrba; /* II CRB Register A */ ii_icrb0_b_u_t icrbb; /* II CRB Register B */ ii_icrb0_c_u_t icrbc; /* II CRB Register C */ ii_icrb0_d_u_t icrbd; /* II CRB Register D */ ii_icrb0_e_u_t icrbe; /* II CRB Register D */ int i; int num_errors = 0; /* Num of errors handled */ ioerror_t ioerror; nasid = hubdev_info->hdi_nasid; /* * XXX - Add locking for any recovery actions */ /* * Scan through all CRBs in the Hub, and handle the errors * in any of the CRBs marked. */ for (i = 0; i < IIO_NUM_CRBS; i++) { /* Check this crb entry to see if it is in error. */ icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i)); if (icrbb.b_mark == 0) { continue; } icrba.ii_icrb0_a_regval = REMOTE_HUB_L(nasid, IIO_ICRB_A(i)); IOERROR_INIT(&ioerror); /* read other CRB error registers. */ icrbc.ii_icrb0_c_regval = REMOTE_HUB_L(nasid, IIO_ICRB_C(i)); icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i)); icrbe.ii_icrb0_e_regval = REMOTE_HUB_L(nasid, IIO_ICRB_E(i)); IOERROR_SETVALUE(&ioerror, errortype, icrbb.b_ecode); /* Check if this error is due to BTE operation, * and handle it separately. */ if (icrbd.d_bteop || ((icrbb.b_initiator == IIO_ICRB_INIT_BTE0 || icrbb.b_initiator == IIO_ICRB_INIT_BTE1) && (icrbb.b_imsgtype == IIO_ICRB_IMSGT_BTE || icrbb.b_imsgtype == IIO_ICRB_IMSGT_SN1NET))) { int bte_num; if (icrbd.d_bteop) bte_num = icrbc.c_btenum; else /* b_initiator bit 2 gives BTE number */ bte_num = (icrbb.b_initiator & 0x4) >> 2; hubiio_crb_free(hubdev_info, i); bte_crb_error_handler(nasid_to_cnodeid(nasid), bte_num, i, &ioerror, icrbd.d_bteop); num_errors++; continue; } }
int hubiio_crb_error_handler(vertex_hdl_t hub_v, hubinfo_t hinfo) { cnodeid_t cnode; nasid_t nasid; ii_icrb0_a_u_t icrba; /* II CRB Register A */ ii_icrb0_b_u_t icrbb; /* II CRB Register B */ ii_icrb0_c_u_t icrbc; /* II CRB Register C */ ii_icrb0_d_u_t icrbd; /* II CRB Register D */ ii_icrb0_e_u_t icrbe; /* II CRB Register D */ int i; int num_errors = 0; /* Num of errors handled */ ioerror_t ioerror; int rc; nasid = hinfo->h_nasid; cnode = NASID_TO_COMPACT_NODEID(nasid); /* * XXX - Add locking for any recovery actions */ /* * Scan through all CRBs in the Hub, and handle the errors * in any of the CRBs marked. */ for (i = 0; i < IIO_NUM_CRBS; i++) { /* Check this crb entry to see if it is in error. */ icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i)); if (icrbb.b_mark == 0) { continue; } icrba.ii_icrb0_a_regval = REMOTE_HUB_L(nasid, IIO_ICRB_A(i)); IOERROR_INIT(&ioerror); /* read other CRB error registers. */ icrbc.ii_icrb0_c_regval = REMOTE_HUB_L(nasid, IIO_ICRB_C(i)); icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i)); icrbe.ii_icrb0_e_regval = REMOTE_HUB_L(nasid, IIO_ICRB_E(i)); IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); /* Check if this error is due to BTE operation, * and handle it separately. */ if (icrbd.d_bteop || ((icrbb.b_initiator == IIO_ICRB_INIT_BTE0 || icrbb.b_initiator == IIO_ICRB_INIT_BTE1) && (icrbb.b_imsgtype == IIO_ICRB_IMSGT_BTE || icrbb.b_imsgtype == IIO_ICRB_IMSGT_SN1NET))){ int bte_num; if (icrbd.d_bteop) bte_num = icrbc.c_btenum; else /* b_initiator bit 2 gives BTE number */ bte_num = (icrbb.b_initiator & 0x4) >> 2; hubiio_crb_free(hinfo, i); bte_crb_error_handler(hub_v, bte_num, i, &ioerror, icrbd.d_bteop); num_errors++; continue; } /* * XXX * Assuming the only other error that would reach here is * crosstalk errors. * If CRB times out on a message from Xtalk, it changes * the message type to CRB. * * If we get here due to other errors (SN0net/CRB) * what's the action ? */ /* * Pick out the useful fields in CRB, and * tuck them away into ioerror structure. */ IOERROR_SETVALUE(&ioerror,xtalkaddr,icrba.a_addr << IIO_ICRB_ADDR_SHFT); IOERROR_SETVALUE(&ioerror,widgetnum,icrba.a_sidn); if (icrba.a_iow){ /* * XXX We shouldn't really have BRIDGE-specific code * here, but alas.... * * The BRIDGE (or XBRIDGE) sets the upper bit of TNUM * to indicate a WRITE operation. It sets the next * bit to indicate an INTERRUPT operation. The bottom * 3 bits of TNUM indicate which device was responsible. */ IOERROR_SETVALUE(&ioerror,widgetdev, TNUM_TO_WIDGET_DEV(icrba.a_tnum)); /* * The encoding of TNUM (see comments above) is * different for PIC. So we'll save TNUM here and * deal with the differences later when we can * determine if we're using a Bridge or the PIC. * * XXX: We may be able to remove saving the widgetdev * above and just sort it out of TNUM later. */ IOERROR_SETVALUE(&ioerror, tnum, icrba.a_tnum); } if (icrbb.b_error) { /* * CRB 'i' has some error. Identify the type of error, * and try to handle it. * */ switch(icrbb.b_ecode) { case IIO_ICRB_ECODE_PERR: case IIO_ICRB_ECODE_WERR: case IIO_ICRB_ECODE_AERR: case IIO_ICRB_ECODE_PWERR: case IIO_ICRB_ECODE_TOUT: case IIO_ICRB_ECODE_XTERR: printk("Shub II CRB %d: error %s on hub cnodeid: %d", i, hubiio_crb_errors[icrbb.b_ecode], cnode); /* * Any sort of write error is mostly due * bad programming (Note it's not a timeout.) * So, invoke hub_iio_error_handler with * appropriate information. */ IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); /* Go through the error bit lookup phase */ if (error_state_set(hub_v, ERROR_STATE_LOOKUP) == ERROR_RETURN_CODE_CANNOT_SET_STATE) return(IOERROR_UNHANDLED); rc = hub_ioerror_handler( hub_v, DMA_WRITE_ERROR, MODE_DEVERROR, &ioerror); if (rc == IOERROR_HANDLED) { rc = hub_ioerror_handler( hub_v, DMA_WRITE_ERROR, MODE_DEVREENABLE, &ioerror); }else { printk("Unable to handle %s on hub %d", hubiio_crb_errors[icrbb.b_ecode], cnode); /* panic; */ } /* Go to Next error */ print_crb_fields(i, icrba, icrbb, icrbc, icrbd, icrbe); hubiio_crb_free(hinfo, i); continue; case IIO_ICRB_ECODE_PRERR: case IIO_ICRB_ECODE_DERR: printk("Shub II CRB %d: error %s on hub : %d", i, hubiio_crb_errors[icrbb.b_ecode], cnode); /* panic */ default: printk("Shub II CRB error (code : %d) on hub : %d", icrbb.b_ecode, cnode); /* panic */ } } /* * Error is not indicated via the errcode field * Check other error indications in this register. */ if (icrbb.b_xerr) { printk("Shub II CRB %d: Xtalk Packet with error bit set to hub %d", i, cnode); /* panic */ } if (icrbb.b_lnetuce) { printk("Shub II CRB %d: Uncorrectable data error detected on data " " from NUMAlink to node %d", i, cnode); /* panic */ } print_crb_fields(i, icrba, icrbb, icrbc, icrbd, icrbe); if (icrbb.b_error) { /* * CRB 'i' has some error. Identify the type of error, * and try to handle it. */ switch(icrbb.b_ecode) { case IIO_ICRB_ECODE_PERR: case IIO_ICRB_ECODE_WERR: case IIO_ICRB_ECODE_AERR: case IIO_ICRB_ECODE_PWERR: printk("%s on hub cnodeid: %d", hubiio_crb_errors[icrbb.b_ecode], cnode); /* * Any sort of write error is mostly due * bad programming (Note it's not a timeout.) * So, invoke hub_iio_error_handler with * appropriate information. */ IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); rc = hub_ioerror_handler( hub_v, DMA_WRITE_ERROR, MODE_DEVERROR, &ioerror); if (rc == IOERROR_HANDLED) { rc = hub_ioerror_handler( hub_v, DMA_WRITE_ERROR, MODE_DEVREENABLE, &ioerror); ASSERT(rc == IOERROR_HANDLED); }else { panic("Unable to handle %s on hub %d", hubiio_crb_errors[icrbb.b_ecode], cnode); /*NOTREACHED*/ } /* Go to Next error */ hubiio_crb_free(hinfo, i); continue; case IIO_ICRB_ECODE_PRERR: case IIO_ICRB_ECODE_TOUT: case IIO_ICRB_ECODE_XTERR: case IIO_ICRB_ECODE_DERR: panic("Fatal %s on hub : %d", hubiio_crb_errors[icrbb.b_ecode], cnode); /*NOTREACHED*/ default: panic("Fatal error (code : %d) on hub : %d", icrbb.b_ecode, cnode); /*NOTREACHED*/ } } /* if (icrbb.b_error) */ /* * Error is not indicated via the errcode field * Check other error indications in this register. */ if (icrbb.b_xerr) { panic("Xtalk Packet with error bit set to hub %d", cnode); /*NOTREACHED*/ } if (icrbb.b_lnetuce) { panic("Uncorrectable data error detected on data " " from Craylink to node %d", cnode); /*NOTREACHED*/ } }
void __init pcibr_setup(cnodeid_t nid) { int i, start, num; unsigned long masterwid; bridge_t *bridge; volatile u64 hubreg; nasid_t nasid, masternasid; xwidget_part_num_t partnum; widgetreg_t widget_id; static spinlock_t pcibr_setup_lock = SPIN_LOCK_UNLOCKED; /* * If the master is doing this for headless node, nothing to do. * This is because currently we require at least one of the hubs * (master hub) connected to the xbow to have at least one enabled * cpu to receive intrs. Else we need an array bus_to_intrnasid[] * that bridge_startup() needs to use to target intrs. All dma is * routed thru the widget of the master hub. The master hub wid * is selectable by WIDGET_A below. */ if (nid != get_compact_nodeid()) return; /* * find what's on our local node */ spin_lock(&pcibr_setup_lock); start = num_bridges; /* Remember where we start from */ nasid = COMPACT_TO_NASID_NODEID(nid); hubreg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); if (hubreg & IIO_LLP_CSR_IS_UP) { /* link is up */ widget_id = *(volatile widgetreg_t *) (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); partnum = XWIDGET_PART_NUM(widget_id); printk("Cpu %d, Nasid 0x%x, pcibr_setup(): found partnum= 0x%x", smp_processor_id(), nasid, partnum); if (partnum == BRIDGE_WIDGET_PART_NUM) { /* * found direct connected bridge so must be Origin200 */ printk("...is bridge\n"); num_bridges = 1; bus_to_wid[0] = 0x8; bus_to_nid[0] = 0; masterwid = 0xa; bus_to_baddr[0] = 0xa100000000000000UL; } else if (partnum == XBOW_WIDGET_PART_NUM) { lboard_t *brd; klxbow_t *xbow_p; /* * found xbow, so may have multiple bridges * need to probe xbow */ printk("...is xbow\n"); if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_MIDPLANE8)) == NULL) printk("argh\n"); else printk("brd = 0x%lx\n", (unsigned long) brd); if ((xbow_p = (klxbow_t *) find_component(brd, NULL, KLSTRUCT_XBOW)) == NULL) printk("argh\n"); else { /* * Okay, here's a xbow. Lets arbitrate and find * out if we should initialize it. Set enabled * hub connected at highest or lowest widget as * master. */ #ifdef WIDGET_A i = HUB_WIDGET_ID_MAX + 1; do { i--; } while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) || (!XBOW_PORT_IS_ENABLED(xbow_p, i))); #else i = HUB_WIDGET_ID_MIN - 1; do { i++; } while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) || (!XBOW_PORT_IS_ENABLED(xbow_p, i))); #endif masterwid = i; masternasid = XBOW_PORT_NASID(xbow_p, i); if (nasid == masternasid) for (i=HUB_WIDGET_ID_MIN; i<=HUB_WIDGET_ID_MAX; i++) { if (!XBOW_PORT_IS_ENABLED(xbow_p, i)) continue; if (XBOW_PORT_TYPE_IO(xbow_p, i)) { widget_id = *(volatile widgetreg_t *) (RAW_NODE_SWIN_BASE(nasid, i) + WIDGET_ID); partnum = XWIDGET_PART_NUM(widget_id); if (partnum == BRIDGE_WIDGET_PART_NUM) { printk("widget 0x%x is a bridge\n", i); bus_to_wid[num_bridges] = i; bus_to_nid[num_bridges] = nasid; bus_to_baddr[num_bridges] = ((masterwid << 60) | (1UL << 56)); /* Barrier set */ num_bridges++; } } } } } else if (partnum == XXBOW_WIDGET_PART_NUM) { /* * found xbridge, assume ibrick for now */ printk("...is xbridge\n"); bus_to_wid[0] = 0xb; bus_to_wid[1] = 0xe; bus_to_wid[2] = 0xf; bus_to_nid[0] = 0; bus_to_nid[1] = 0; bus_to_nid[2] = 0; bus_to_baddr[0] = 0xa100000000000000UL; bus_to_baddr[1] = 0xa100000000000000UL; bus_to_baddr[2] = 0xa100000000000000UL; masterwid = 0xa; num_bridges = 3; } } num = num_bridges - start; spin_unlock(&pcibr_setup_lock); /* * set bridge registers */ for (i = start; i < (start + num); i++) { DBG("pcibr_setup: bus= %d bus_to_wid[%2d]= %d bus_to_nid[%2d]= %d\n", i, i, bus_to_wid[i], i, bus_to_nid[i]); bus_to_cpu[i] = smp_processor_id(); /* * point to this bridge */ bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[i],bus_to_wid[i]); /* * Clear all pending interrupts. */ bridge->b_int_rst_stat = (BRIDGE_IRR_ALL_CLR); /* * Until otherwise set up, assume all interrupts are from slot 0 */ bridge->b_int_device = (u32) 0x0; /* * swap pio's to pci mem and io space (big windows) */ bridge->b_wid_control |= BRIDGE_CTRL_IO_SWAP; bridge->b_wid_control |= BRIDGE_CTRL_MEM_SWAP; /* * Hmm... IRIX sets additional bits in the address which * are documented as reserved in the bridge docs. */ bridge->b_int_mode = 0x0; /* Don't clear ints */ bridge->b_wid_int_upper = 0x8000 | (masterwid << 16); bridge->b_wid_int_lower = 0x01800090; /* PI_INT_PEND_MOD off*/ bridge->b_dir_map = (masterwid << 20); /* DMA */ bridge->b_int_enable = 0; bridge->b_wid_tflush; /* wait until Bridge PIO complete */ } }
/*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; }
static cycle_t hub_rt_read(void) { return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT); }
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); } }
/* * 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); }
static cycle_t hub_rt_read(struct clocksource *cs) { return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT); }