📄 xbow.c
字号:
{ xswitch_info_t xswitch_info; vertex_hdl_t conn; xswitch_info = xswitch_info_get(vhdl); conn = xswitch_info_vhdl_get(xswitch_info, widgetnum); return conn;}/* * xbow_setwidint: called when xtalk * is establishing or migrating our * interrupt service. */static voidxbow_setwidint(xtalk_intr_t intr){ xwidgetnum_t targ = xtalk_intr_target_get(intr); iopaddr_t addr = xtalk_intr_addr_get(intr); xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr); xbow_t *xbow = (xbow_t *) xtalk_intr_sfarg_get(intr); xbow_intr_preset((void *) xbow, 0, targ, addr, vect);}/* * xbow_intr_preset: called during mlreset time * if the platform specific code needs to route * an xbow interrupt before the xtalk infrastructure * is available for use. * * Also called from xbow_setwidint, so we don't * replicate the guts of the routine. * * XXX- probably should be renamed xbow_wid_intr_set or * something to reduce confusion. *//*ARGSUSED3 */voidxbow_intr_preset(void *which_widget, int which_widget_intr, xwidgetnum_t targ, iopaddr_t addr, xtalk_intr_vector_t vect){ xbow_t *xbow = (xbow_t *) which_widget; xbow->xb_wid_int_upper = ((0xFF000000 & (vect << 24)) | (0x000F0000 & (targ << 16)) | XTALK_ADDR_TO_UPPER(addr)); xbow->xb_wid_int_lower = XTALK_ADDR_TO_LOWER(addr);}#define XEM_ADD_STR(s) printk("%s", (s))#define XEM_ADD_NVAR(n,v) printk("\t%20s: 0x%llx\n", (n), ((unsigned long long)v))#define XEM_ADD_VAR(v) XEM_ADD_NVAR(#v,(v))#define XEM_ADD_IOEF(p,n) if (IOERROR_FIELDVALID(ioe,n)) { \ IOERROR_GETVALUE(p,ioe,n); \ XEM_ADD_NVAR("ioe." #n, p); \ }int xbow_xmit_retry_errors;intxbow_xmit_retry_error(xbow_soft_t soft, int port){ xswitch_info_t info; vertex_hdl_t vhdl; widget_cfg_t *wid; widgetreg_t id; int part; int mfgr; wid = soft->wpio[port - BASE_XBOW_PORT]; if (wid == NULL) { /* If we can't track down a PIO * pointer to our widget yet, * leave our caller knowing that * we are interested in this * interrupt if it occurs in * the future. */ info = xswitch_info_get(soft->busv); if (!info) return 1; vhdl = xswitch_info_vhdl_get(info, port); if (vhdl == GRAPH_VERTEX_NONE) return 1; wid = (widget_cfg_t *) xtalk_piotrans_addr (vhdl, 0, 0, sizeof *wid, 0); if (!wid) return 1; soft->wpio[port - BASE_XBOW_PORT] = wid; } id = wid->w_id; part = XWIDGET_PART_NUM(id); mfgr = XWIDGET_MFG_NUM(id); /* If this thing is not a Bridge, * do not activate the WAR, and * tell our caller we do not need * to be called again. */ if ((part != BRIDGE_WIDGET_PART_NUM) || (mfgr != BRIDGE_WIDGET_MFGR_NUM)) { /* FIXME: add Xbridge to the WAR. * Shouldn't hurt anything. Later need to * check if we can remove this. */ if ((part != XBRIDGE_WIDGET_PART_NUM) || (mfgr != XBRIDGE_WIDGET_MFGR_NUM)) return 0; } /* count how many times we * have picked up after * LLP Transmit problems. */ xbow_xmit_retry_errors++; /* rewrite the control register * to fix things up. */ wid->w_control = wid->w_control; wid->w_control; return 1;}/* * xbow_errintr_handler will be called if the xbow * sends an interrupt request to report an error. */static voidxbow_errintr_handler(int irq, void *arg, struct pt_regs *ep){ ioerror_t ioe[1]; xbow_soft_t soft = (xbow_soft_t) arg; xbow_t *xbow = soft->base; xbowreg_t wid_control; xbowreg_t wid_stat; xbowreg_t wid_err_cmdword; xbowreg_t wid_err_upper; xbowreg_t wid_err_lower; w_err_cmd_word_u wid_err; unsigned long long wid_err_addr; int fatal = 0; int dump_ioe = 0; static int xbow_error_handler(void *, int, ioerror_mode_t, ioerror_t *); wid_control = xbow->xb_wid_control; wid_stat = xbow->xb_wid_stat_clr; wid_err_cmdword = xbow->xb_wid_err_cmdword; wid_err_upper = xbow->xb_wid_err_upper; wid_err_lower = xbow->xb_wid_err_lower; xbow->xb_wid_err_cmdword = 0; wid_err_addr = wid_err_lower | (((iopaddr_t) wid_err_upper & WIDGET_ERR_UPPER_ADDR_ONLY) << 32); if (wid_stat & XB_WID_STAT_LINK_INTR_MASK) { int port; wid_err.r = wid_err_cmdword; for (port = MAX_PORT_NUM - MAX_XBOW_PORTS; port < MAX_PORT_NUM; port++) { if (wid_stat & XB_WID_STAT_LINK_INTR(port)) { xb_linkregs_t *link = &(xbow->xb_link(port)); xbowreg_t link_control = link->link_control; xbowreg_t link_status = link->link_status_clr; xbowreg_t link_aux_status = link->link_aux_status; xbowreg_t link_pend; link_pend = link_status & link_control & (XB_STAT_ILLEGAL_DST_ERR | XB_STAT_OALLOC_IBUF_ERR | XB_STAT_RCV_CNT_OFLOW_ERR | XB_STAT_XMT_CNT_OFLOW_ERR | XB_STAT_XMT_MAX_RTRY_ERR | XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_MAXREQ_TOUT_ERR | XB_STAT_SRC_TOUT_ERR ); if (link_pend & XB_STAT_ILLEGAL_DST_ERR) { if (wid_err.f.sidn == port) { IOERROR_INIT(ioe); IOERROR_SETVALUE(ioe, widgetnum, port); IOERROR_SETVALUE(ioe, xtalkaddr, wid_err_addr); if (IOERROR_HANDLED == xbow_error_handler(soft, IOECODE_DMA, MODE_DEVERROR, ioe)) { link_pend &= ~XB_STAT_ILLEGAL_DST_ERR; } else { dump_ioe++; } } } /* Xbow/Bridge WAR: * if the bridge signals an LLP Transmitter Retry, * rewrite its control register. * If someone else triggers this interrupt, * ignore (and disable) the interrupt. */ if (link_pend & XB_STAT_XMT_RTRY_ERR) { if (!xbow_xmit_retry_error(soft, port)) { link_control &= ~XB_CTRL_XMT_RTRY_IE; link->link_control = link_control; link->link_control; /* stall until written */ } link_pend &= ~XB_STAT_XMT_RTRY_ERR; } if (link_pend) { vertex_hdl_t xwidget_vhdl; char *xwidget_name; /* Get the widget name corresponding to the current * xbow link. */ xwidget_vhdl = xbow_widget_lookup(soft->busv,port); xwidget_name = xwidget_name_get(xwidget_vhdl); printk("%s port %X[%s] XIO Bus Error", soft->name, port, xwidget_name); if (link_status & XB_STAT_MULTI_ERR) XEM_ADD_STR("\tMultiple Errors\n"); if (link_status & XB_STAT_ILLEGAL_DST_ERR) XEM_ADD_STR("\tInvalid Packet Destination\n"); if (link_status & XB_STAT_OALLOC_IBUF_ERR) XEM_ADD_STR("\tInput Overallocation Error\n"); if (link_status & XB_STAT_RCV_CNT_OFLOW_ERR) XEM_ADD_STR("\tLLP receive error counter overflow\n"); if (link_status & XB_STAT_XMT_CNT_OFLOW_ERR) XEM_ADD_STR("\tLLP transmit retry counter overflow\n"); if (link_status & XB_STAT_XMT_MAX_RTRY_ERR) XEM_ADD_STR("\tLLP Max Transmitter Retry\n"); if (link_status & XB_STAT_RCV_ERR) XEM_ADD_STR("\tLLP Receiver error\n"); if (link_status & XB_STAT_XMT_RTRY_ERR) XEM_ADD_STR("\tLLP Transmitter Retry\n"); if (link_status & XB_STAT_MAXREQ_TOUT_ERR) XEM_ADD_STR("\tMaximum Request Timeout\n"); if (link_status & XB_STAT_SRC_TOUT_ERR) XEM_ADD_STR("\tSource Timeout Error\n"); { int other_port; for (other_port = 8; other_port < 16; ++other_port) { if (link_aux_status & (1 << other_port)) { /* XXX- need to go to "other_port" * and clean up after the timeout? */ XEM_ADD_VAR(other_port); } } }#if !DEBUG if (kdebug) {#endif XEM_ADD_VAR(link_control); XEM_ADD_VAR(link_status); XEM_ADD_VAR(link_aux_status);#if !DEBUG }#endif fatal++; } } } } if (wid_stat & wid_control & XB_WID_STAT_WIDGET0_INTR) { /* we have a "widget zero" problem */ if (wid_stat & (XB_WID_STAT_MULTI_ERR | XB_WID_STAT_XTALK_ERR | XB_WID_STAT_REG_ACC_ERR)) { printk("%s Port 0 XIO Bus Error", soft->name); if (wid_stat & XB_WID_STAT_MULTI_ERR) XEM_ADD_STR("\tMultiple Error\n"); if (wid_stat & XB_WID_STAT_XTALK_ERR) XEM_ADD_STR("\tXIO Error\n"); if (wid_stat & XB_WID_STAT_REG_ACC_ERR) XEM_ADD_STR("\tRegister Access Error\n"); fatal++; } } if (fatal) { XEM_ADD_VAR(wid_stat); XEM_ADD_VAR(wid_control); XEM_ADD_VAR(wid_err_cmdword); XEM_ADD_VAR(wid_err_upper); XEM_ADD_VAR(wid_err_lower); XEM_ADD_VAR(wid_err_addr); panic("XIO Bus Error"); }}/* * XBOW ERROR Handling routines. * These get invoked as part of walking down the error handling path * from hub/heart towards the I/O device that caused the error. *//* * xbow_error_handler * XBow error handling dispatch routine. * This is the primary interface used by external world to invoke * in case of an error related to a xbow. * Only functionality in this layer is to identify the widget handle * given the widgetnum. Otherwise, xbow does not gathers any error * data. */static intxbow_error_handler( void *einfo, int error_code, ioerror_mode_t mode, ioerror_t *ioerror){ int retval = IOERROR_WIDGETLEVEL; xbow_soft_t soft = (xbow_soft_t) einfo; int port; vertex_hdl_t conn; vertex_hdl_t busv; xbow_t *xbow = soft->base; xbowreg_t wid_stat; xbowreg_t wid_err_cmdword; xbowreg_t wid_err_upper; xbowreg_t wid_err_lower; unsigned long long wid_err_addr; xb_linkregs_t *link; xbowreg_t link_control; xbowreg_t link_status; xbowreg_t link_aux_status; ASSERT(soft != 0); busv = soft->busv;#if DEBUG && ERROR_DEBUG printk("%s: xbow_error_handler\n", soft->name, busv);#endif IOERROR_GETVALUE(port, ioerror, widgetnum); if (port == 0) { /* error during access to xbow: * do NOT attempt to access xbow regs. */ if (mode == MODE_DEVPROBE) return IOERROR_HANDLED; if (error_code & IOECODE_DMA) { printk(KERN_ALERT "DMA error blamed on Crossbow at %s\n" "\tbut Crosbow never initiates DMA!", soft->name); } if (error_code & IOECODE_PIO) { iopaddr_t tmp; IOERROR_GETVALUE(tmp, ioerror, xtalkaddr); printk(KERN_ALERT "PIO Error on XIO Bus %s\n" "\tattempting to access XIO controller\n" "\twith offset 0x%lx", soft->name, tmp); } /* caller will dump contents of ioerror * in DEBUG and kdebug kernels. */ return retval; } /* * error not on port zero: * safe to read xbow registers. */ wid_stat = xbow->xb_wid_stat; wid_err_cmdword = xbow->xb_wid_err_cmdword; wid_err_upper = xbow->xb_wid_err_upper; wid_err_lower = xbow->xb_wid_err_lower; wid_err_addr = wid_err_lower | (((iopaddr_t) wid_err_upper & WIDGET_ERR_UPPER_ADDR_ONLY) << 32); if ((port < BASE_XBOW_PORT) || (port >= MAX_PORT_NUM)) { if (mode == MODE_DEVPROBE) return IOERROR_HANDLED; if (error_code & IOECODE_DMA) { printk(KERN_ALERT "DMA error blamed on XIO port at %s/%d\n" "\tbut Crossbow does not support that port", soft->name, port); } if (error_code & IOECODE_PIO) { iopaddr_t tmp; IOERROR_GETVALUE(tmp, ioerror, xtalkaddr); printk(KERN_ALERT "PIO Error on XIO Bus %s\n" "\tattempting to access XIO port %d\n" "\t(which Crossbow does not support)" "\twith offset 0x%lx", soft->name, port, tmp); }#if !DEBUG if (kdebug) {#endif XEM_ADD_STR("Raw status values for Crossbow:\n"); XEM_ADD_VAR(wid_stat); XEM_ADD_VAR(wid_err_cmdword); XEM_ADD_VAR(wid_err_upper); XEM_ADD_VAR(wid_err_lower); XEM_ADD_VAR(wid_err_addr);#if !DEBUG }#endif /* caller will dump contents of ioerror * in DEBUG and kdebug kernels. */ return retval; } /* access to valid port: * ok to check port status. */ link = &(xbow->xb_link(port)); link_control = link->link_control; link_status = link->link_status; link_aux_status = link->link_aux_status; /* Check that there is something present * in that XIO port. */ /* WAR: PIC widget 0xf is missing prescense bit */ if (XBOW_WAR_ENABLED(PV854827, xbow->xb_wid_id) && IS_PIC_XBOW(xbow->xb_wid_id) && (port==0xf)) ; else if (IS_PIC_XBOW(xbow->xb_wid_id) && (port==0xb)) ; /* WAR for opus this is missing on 0xb */ else if (!(link_aux_status & XB_AUX_STAT_PRESENT)) { /* nobody connected. */ if (mode == MODE_DEVPROBE) return IOERROR_HANDLED; if (error_code & IOECODE_DMA) { printk(KERN_ALERT "DMA error blamed on XIO port at %s/%d\n" "\tbut there is no device connected there.", soft->name, port); } if (error_code & IOECODE_PIO) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -