xbow.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,021 行 · 第 1/2 页
C
1,021 行
/* * xbow_errintr_handler will be called if the xbow * sends an interrupt request to report an error. */static irqreturn_txbow_errintr_handler(int irq, void *arg, struct pt_regs *ep){ ioerror_t ioe[1]; struct xbow_soft_s *soft = (struct xbow_soft_s *)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"); } return IRQ_HANDLED;}/* * 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; struct xbow_soft_s *soft = (struct xbow_soft_s *) 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) { 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 has no device connected)" "\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); XEM_ADD_VAR(port); XEM_ADD_VAR(link_control); XEM_ADD_VAR(link_status); XEM_ADD_VAR(link_aux_status);#if !DEBUG }#endif return retval; } /* Check that the link is alive. */ if (!(link_status & XB_STAT_LINKALIVE)) { iopaddr_t tmp; /* nobody connected. */ if (mode == MODE_DEVPROBE) return IOERROR_HANDLED; printk(KERN_ALERT "%s%sError on XIO Bus %s port %d", (error_code & IOECODE_DMA) ? "DMA " : "", (error_code & IOECODE_PIO) ? "PIO " : "", soft->name, port); IOERROR_GETVALUE(tmp, ioerror, xtalkaddr); if ((error_code & IOECODE_PIO) && (IOERROR_FIELDVALID(ioerror, xtalkaddr))) { printk("\tAccess attempted to offset 0x%lx\n", tmp); } if (link_aux_status & XB_AUX_LINKFAIL_RST_BAD) XEM_ADD_STR("\tLink never came out of reset\n"); else XEM_ADD_STR("\tLink failed while transferring data\n"); } /* get the connection point for the widget * involved in this error; if it exists and * is not our connectpoint, cycle back through * xtalk_error_handler to deliver control to * the proper handler (or to report a generic * crosstalk error). * * If the downstream handler won't handle * the problem, we let our upstream caller * deal with it, after (in DEBUG and kdebug * kernels) dumping the xbow state for this * port. */ conn = xbow_widget_lookup(busv, port); if ((conn != GRAPH_VERTEX_NONE) && (conn != soft->conn)) { retval = xtalk_error_handler(conn, error_code, mode, ioerror); if (retval == IOERROR_HANDLED) return IOERROR_HANDLED; } if (mode == MODE_DEVPROBE) return IOERROR_HANDLED; if (retval == IOERROR_UNHANDLED) { iopaddr_t tmp; retval = IOERROR_PANIC; printk(KERN_ALERT "%s%sError on XIO Bus %s port %d", (error_code & IOECODE_DMA) ? "DMA " : "", (error_code & IOECODE_PIO) ? "PIO " : "", soft->name, port); IOERROR_GETVALUE(tmp, ioerror, xtalkaddr); if ((error_code & IOECODE_PIO) && (IOERROR_FIELDVALID(ioerror, xtalkaddr))) { printk("\tAccess attempted to offset 0x%lx\n", 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); XEM_ADD_VAR(port); XEM_ADD_VAR(link_control); XEM_ADD_VAR(link_status); XEM_ADD_VAR(link_aux_status);#if !DEBUG }#endif /* caller will dump raw ioerror data * in DEBUG and kdebug kernels. */ return retval;}intxbow_reset_link(vertex_hdl_t xconn_vhdl){ xwidget_info_t widget_info; xwidgetnum_t port; xbow_t *xbow; xbowreg_t ctrl; xbwX_stat_t stat; unsigned long itick; unsigned int dtick; static long ticks_to_wait = HZ / 1000; widget_info = xwidget_info_get(xconn_vhdl); port = xwidget_info_id_get(widget_info);#ifdef XBOW_K1PTR /* defined if we only have one xbow ... */ xbow = XBOW_K1PTR;#else { vertex_hdl_t xbow_vhdl; struct xbow_soft_s *xbow_soft; hwgraph_traverse(xconn_vhdl, ".master/xtalk/0/xbow", &xbow_vhdl); xbow_soft = xbow_soft_get(xbow_vhdl); xbow = xbow_soft->base; }#endif /* * This requires three PIOs (reset the link, check for the * reset, restore the control register for the link) plus * 10us to wait for the reset. We allow up to 1ms for the * widget to come out of reset before giving up and * returning a failure. */ ctrl = xbow->xb_link(port).link_control; xbow->xb_link(port).link_reset = 0; itick = jiffies; while (1) { stat.linkstatus = xbow->xb_link(port).link_status; if (stat.link_alive) break; dtick = jiffies - itick; if (dtick > ticks_to_wait) { return -1; /* never came out of reset */ } udelay(2); /* don't beat on link_status */ } xbow->xb_link(port).link_control = ctrl; return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?