xbow.c

来自「Linux Kernel 2.6.9 for OMAP1710」· 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 + -
显示快捷键?