⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcibr_error.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
     * could make much progress. (NOTE: interrupd does     * come in _after_ bus error processing starts. But it's     * completed by the time bus error code reaches PCI PIO     * error handling.     * Similarly write error results in just an interrupt,     * and error handling has to be done at interrupt level.     * There is no way to distinguish at interrupt time, if an     * error interrupt is due to read/write error..     */    /* We know the xtalk addr, the raw PCI bus space,     * the raw PCI bus address, the decoded PCI bus     * space, the offset within that space, and the     * decoded PCI slot (which may be "PCIIO_SLOT_NONE" if no slot     * is known to be involved).     */    /*     * Hand the error off to the handler registered     * for the slot that should have decoded the error,     * or to generic PCI handling (if pciio decides that     * such is appropriate).     */    retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe);    if (retval != IOERROR_HANDLED) {	/* Generate a generic message for IOERROR_UNHANDLED	 * since the subsidiary handlers were silent, and	 * did no recovery.	 */	if (retval == IOERROR_UNHANDLED) {	    retval = IOERROR_PANIC;	    /* we may or may not want to print some of this,	     * depending on debug level and which error code.	     */	    printk(KERN_ALERT		    "PIO Error on PCI Bus %s",		    pcibr_soft->bs_name);	    /* this decodes part of the ioe; our caller	     * will dump the raw details in DEBUG and	     * kdebug kernels.	     */	    BEM_ADD_IOE(ioe);	}#if defined(FORCE_ERRORS)	if (0) {	    /*	     * Dump raw data from Bridge/PCI layer.	     */	    BEM_ADD_STR("Raw info from Bridge/PCI layer:\n");	    if (IS_PIC_SOFT(pcibr_soft)) {		if (bridge->p_int_status_64 & (picreg_t)BRIDGE_ISR_PCIBUS_PIOERR)		    pcibr_error_dump(pcibr_soft);	    } else {		if (bridge->b_int_status & (bridgereg_t)BRIDGE_ISR_PCIBUS_PIOERR)		    pcibr_error_dump(pcibr_soft);	    }	    BEM_ADD_SPC(raw_space);	    BEM_ADD_VAR(raw_paddr);	    if (IOERROR_FIELDVALID(ioe, widgetdev)) {		short widdev;		IOERROR_GETVALUE(widdev, ioe, widgetdev);		slot = pciio_widgetdev_slot_get(widdev);		func = pciio_widgetdev_func_get(widdev);		if (slot < PCIBR_NUM_SLOTS(pcibr_soft)) {		    bridgereg_t             device = bridge->b_device[slot].reg;		    BEM_ADD_VAR(slot);		    BEM_ADD_VAR(func);		    BEM_ADD_REG(device);		}	    }	}#endif	/* FORCE_ERRORS */	/*	 * Since error could not be handled at lower level,	 * error data logged has not  been cleared.	 * Clean up errors, and	 * re-enable bridge to interrupt on error conditions.	 * NOTE: Wheather we get the interrupt on PCI_ABORT or not is	 * dependent on INT_ENABLE register. This write just makes sure	 * that if the interrupt was enabled, we do get the interrupt.	 *	 * CAUTION: Resetting bit BRIDGE_IRR_PCI_GRP_CLR, acknowledges	 *      a group of interrupts. If while handling this error,	 *      some other error has occurred, that would be	 *      implicitly cleared by this write.	 *      Need a way to ensure we don't inadvertently clear some	 *      other errors.	 */	if (IOERROR_FIELDVALID(ioe, widgetdev)) {		short widdev;		IOERROR_GETVALUE(widdev, ioe, widgetdev);		pcibr_device_disable(pcibr_soft, 				 pciio_widgetdev_slot_get(widdev));	}	if (mode == MODE_DEVUSERERROR)	    pcibr_error_cleanup(pcibr_soft, error_code);    }    return retval;}/* * bridge_dmaerror *      Some error was identified in a DMA transaction. *      This routine will identify the <device, address> that caused the error, *      and try to invoke the appropriate bus service to handle this. */intpcibr_dmard_error(		     pcibr_soft_t pcibr_soft,		     int error_code,		     ioerror_mode_t mode,		     ioerror_t *ioe){    vertex_hdl_t            pcibr_vhdl = pcibr_soft->bs_vhdl;    bridge_t               *bridge = pcibr_soft->bs_base;    bridgereg_t             bus_lowaddr, bus_uppraddr;    int                     retval = 0;    int                     bufnum;    /*     * In case of DMA errors, bridge should have logged the     * address that caused the error.     * Look up the address, in the bridge error registers, and     * take appropriate action     */    {	short tmp;	IOERROR_GETVALUE(tmp, ioe, widgetnum);	ASSERT(tmp == pcibr_soft->bs_xid);    }    ASSERT(bridge);    /*     * read error log registers     */    bus_lowaddr = bridge->b_wid_resp_lower;    bus_uppraddr = bridge->b_wid_resp_upper;    bufnum = BRIDGE_RESP_ERRUPPR_BUFNUM(bus_uppraddr);    IOERROR_SETVALUE(ioe, widgetdev, 		     pciio_widgetdev_create(				    BRIDGE_RESP_ERRUPPR_DEVICE(bus_uppraddr),				    0));    IOERROR_SETVALUE(ioe, busaddr,		     (bus_lowaddr |		      ((iopaddr_t)		       (bus_uppraddr &			BRIDGE_ERRUPPR_ADDRMASK) << 32)));    /*     * need to ensure that the xtalk address in ioe     * maps to PCI error address read from bridge.     * How to convert PCI address back to Xtalk address ?     * (better idea: convert XTalk address to PCI address     * and then do the compare!)     */    retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe);    if (retval != IOERROR_HANDLED) {	short tmp;	IOERROR_GETVALUE(tmp, ioe, widgetdev);	pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get(tmp));    }    /*     * Re-enable bridge to interrupt on BRIDGE_IRR_RESP_BUF_GRP_CLR     * NOTE: Wheather we get the interrupt on BRIDGE_IRR_RESP_BUF_GRP_CLR or     * not is dependent on INT_ENABLE register. This write just makes sure     * that if the interrupt was enabled, we do get the interrupt.     */    bridge->b_int_rst_stat = BRIDGE_IRR_RESP_BUF_GRP_CLR;    /*     * Also, release the "bufnum" back to buffer pool that could be re-used.     * This is done by "disabling" the buffer for a moment, then restoring     * the original assignment.     */    {	reg_p                   regp;	bridgereg_t             regv;	bridgereg_t             mask;	regp = (bufnum & 1)	    ? &bridge->b_odd_resp	    : &bridge->b_even_resp;	mask = 0xF << ((bufnum >> 1) * 4);	regv = *regp;	*regp = regv & ~mask;	*regp = regv;    }    return retval;}/* * pcibr_dmawr_error: *      Handle a dma write error caused by a device attached to this bridge. * *      ioe has the widgetnum, widgetdev, and memaddr fields updated *      But we don't know the PCI address that corresponds to "memaddr" *      nor do we know which device driver is generating this address. * *      There is no easy way to find out the PCI address(es) that map *      to a specific system memory address. Bus handling code is also *      of not much help, since they don't keep track of the DMA mapping *      that have been handed out. *      So it's a dead-end at this time. * *      If translation is available, we could invoke the error handling *      interface of the device driver. *//*ARGSUSED */intpcibr_dmawr_error(		     pcibr_soft_t pcibr_soft,		     int error_code,		     ioerror_mode_t mode,		     ioerror_t *ioe){    vertex_hdl_t            pcibr_vhdl = pcibr_soft->bs_vhdl;    int                     retval;    retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe);    if (retval != IOERROR_HANDLED) {	short tmp;	IOERROR_GETVALUE(tmp, ioe, widgetdev);	pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get(tmp));    }    return retval;}/* * Bridge error handler. *      Interface to handle all errors that involve bridge in some way. * *      This normally gets called from xtalk error handler. *      ioe has different set of fields set depending on the error that *      was encountered. So, we have a bit field indicating which of the *      fields are valid. * * NOTE: This routine could be operating in interrupt context. So, *      don't try to sleep here (till interrupt threads work!!) */intpcibr_error_handler(		       error_handler_arg_t einfo,		       int error_code,		       ioerror_mode_t mode,		       ioerror_t *ioe){    pcibr_soft_t            pcibr_soft;    int                     retval = IOERROR_BADERRORCODE;    pcibr_soft = (pcibr_soft_t) einfo;    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn,		"pcibr_error_handler: pcibr_soft=0x%x, error_code=0x%x\n",		pcibr_soft, error_code));#if DEBUG && ERROR_DEBUG    printk( "%s: pcibr_error_handler\n", pcibr_soft->bs_name);#endif    ASSERT(pcibr_soft != NULL);    if (error_code & IOECODE_PIO)	retval = pcibr_pioerror(pcibr_soft, error_code, mode, ioe);    if (error_code & IOECODE_DMA) {	if (error_code & IOECODE_READ) {	    /*	     * DMA read error occurs when a device attached to the bridge	     * tries to read some data from system memory, and this	     * either results in a timeout or access error.	     * First case is indicated by the bit "XREAD_REQ_TOUT"	     * and second case by "RESP_XTALK_ERROR" bit in bridge error	     * interrupt status register.	     *	     * pcibr_error_intr_handler would get invoked first, and it has	     * the responsibility of calling pcibr_error_handler with	     * suitable parameters.	     */	    retval = pcibr_dmard_error(pcibr_soft, error_code, MODE_DEVERROR, ioe);	}	if (error_code & IOECODE_WRITE) {	    /*	     * A device attached to this bridge has been generating	     * bad DMA writes. Find out the device attached, and	     * slap on it's wrist.	     */	    retval = pcibr_dmawr_error(pcibr_soft, error_code, MODE_DEVERROR, ioe);	}    }    return retval;}/* * PIC has 2 busses under a single widget so pcibr_attach2 registers this * wrapper function rather than pcibr_error_handler() for PIC.  It's upto * this wrapper to call pcibr_error_handler() with the correct pcibr_soft * struct (ie. the pcibr_soft struct for the bus that saw the error). * * NOTE: this wrapper function is only registered for PIC ASICs and will * only be called for a PIC */intpcibr_error_handler_wrapper(		       error_handler_arg_t einfo,		       int error_code,		       ioerror_mode_t mode,		       ioerror_t *ioe){    pcibr_soft_t       pcibr_soft = (pcibr_soft_t) einfo;    int                pio_retval = -1;     int		       dma_retval = -1;    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn,                "pcibr_error_handler_wrapper: pcibr_soft=0x%x, "		"error_code=0x%x\n", pcibr_soft, error_code));    /*     * It is possible that both a IOECODE_PIO and a IOECODE_DMA, and both     * IOECODE_READ and IOECODE_WRITE could be set in error_code so we must     * process all.  Since we are a wrapper for pcibr_error_handler(), and     * will be calling it several times within this routine, we turn off the     * error_code bits we don't want it to be processing during that call.     */    /*      * If the error was a result of a PIO, we tell what bus on the PIC saw     * the error from the PIO address.     */    if (error_code & IOECODE_PIO) {	iopaddr_t               bad_xaddr;	/*	 * PIC bus0 PIO space 0x000000 - 0x7fffff or 0x40000000 - 0xbfffffff	 *     bus1 PIO space 0x800000 - 0xffffff or 0xc0000000 - 0x13fffffff	 */	IOERROR_GETVALUE(bad_xaddr, ioe, xtalkaddr);	if ((bad_xaddr <= 0x7fffff) ||	    ((bad_xaddr >= 0x40000000) && (bad_xaddr <= 0xbfffffff))) {	    /* bus 0 saw the error */	    pio_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft,			 (error_code & ~IOECODE_DMA), mode, ioe);	} else if (((bad_xaddr >= 0x800000) && (bad_xaddr <= 0xffffff)) ||	    ((bad_xaddr >= 0xc0000000) && (bad_xaddr <= 0x13fffffff))) {	    /* bus 1 saw the error */	    pcibr_soft = pcibr_soft->bs_peers_soft;	    if (!pcibr_soft) {#if DEBUG		printk(KERN_WARNING "pcibr_error_handler: "			"bs_peers_soft==NULL. bad_xaddr= 0x%x mode= 0x%x\n",						bad_xaddr, mode);#endif  		pio_retval = IOERROR_HANDLED;	    } else	        pio_retval= pcibr_error_handler((error_handler_arg_t)pcibr_soft,			 (error_code & ~IOECODE_DMA), mode, ioe);	} else {	    printk(KERN_WARNING "pcibr_error_handler_wrapper(): IOECODE_PIO: "		    "saw an invalid pio address: 0x%lx\n", bad_xaddr);	    pio_retval = IOERROR_UNHANDLED;	}    }     /*      * If the error was a result of a DMA Write, we tell what bus on the PIC     * saw the error by looking at tnum.     */    if ((error_code & IOECODE_DMA) && (error_code & IOECODE_WRITE)) {	short tmp;	/*         * For DMA writes [X]Bridge encodes the TNUM field of a Xtalk         * packet like this:         *              bits  value         *              4:3   10b         *              2:0   device number         *         * BUT PIC needs the bus number so it does this:         *              bits  value         *              4:3   10b         *              2     busnumber         *              1:0   device number	 *	 * Pull out the bus number from `tnum' and reset the `widgetdev'	 * since when hubiio_crb_error_handler() set `widgetdev' it had	 * no idea if it was a PIC or a BRIDGE ASIC so it set it based	 * off bits 2:0	 */	IOERROR_GETVALUE(tmp, ioe, tnum);	IOERROR_SETVALUE(ioe, widgetdev, (tmp & 0x3));	if ((tmp & 0x4) == 0) {	    /* bus 0 saw the error. */	    dma_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft,			 (error_code & ~(IOECODE_PIO|IOECODE_READ)), mode, ioe);	} else {	    /* bus 1 saw the error */	    pcibr_soft = pcibr_soft->bs_peers_soft;	    dma_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft,			 (error_code & ~(IOECODE_PIO|IOECODE_READ)), mode, ioe);	}    }         /*      * If the error was a result of a DMA READ, XXX ???     */    if ((error_code & IOECODE_DMA) && (error_code & IOECODE_READ)) {	/*	 * A DMA Read error will result in a BRIDGE_ISR_RESP_XTLK_ERR	 * or BRIDGE_ISR_BAD_XRESP_PKT bridge error interrupt which 	 * are fatal interrupts (ie. BRIDGE_ISR_ERROR_FATAL) causing	 * pcibr_error_intr_handler() to panic the system.  So is the	 * error handler even going to get called???  It appears that	 * the pcibr_dmard_error() attempts to clear the interrupts	 * so pcibr_error_intr_handler() won't see them, but there	 * appears to be nothing to prevent pcibr_error_intr_handler()	 * from running before pcibr_dmard_error() has a chance to	 * clear the interrupt.	 *	 * Since we'll be panicing anyways, don't bother handling the	 * error for now until we can fix this race condition mentioned	 * above.	 */	dma_retval = IOERROR_UNHANDLED;    }         /* XXX: pcibr_error_handler() should probably do the same thing, it over-     * write it's return value as it processes the different "error_code"s.     */    if ((pio_retval == -1) && (dma_retval == -1)) {    	return IOERROR_BADERRORCODE;    } else if (dma_retval != IOERROR_HANDLED) {	return dma_retval;    } else if (pio_retval != IOERROR_HANDLED) {	return pio_retval;    } else {	return IOERROR_HANDLED;    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -