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

📄 pcibr_error.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 5 页
字号:
	    wb = map->bp_pciaddr;	    ws = map->bp_mapsz;	    cw = wx - PCIIO_SPACE_WIN(0);	    if (cw < 6) {		wb += pcibr_soft->bs_slot[cs].bss_window[cw].bssw_base;		wx = pcibr_soft->bs_slot[cs].bss_window[cw].bssw_space;	    }	    if (wx == PCIIO_SPACE_ROM) {		wb += pcibr_info->f_rbase;		wx = PCIIO_SPACE_MEM;	    }	    if ((wx == PCIIO_SPACE_MEM32) ||		(wx == PCIIO_SPACE_MEM64))		wx = PCIIO_SPACE_MEM;	    wl = wb + ws;	    if ((wx == raw_space) && (raw_paddr >= wb) && (raw_paddr < wl)) {		atomic_inc(&map->bp_toc[0]);		if (slot == PCIIO_SLOT_NONE) {		    slot = cs;		    space = map->bp_space;		    if (cw < 6)			offset -= pcibr_soft->bs_slot[cs].bss_window[cw].bssw_base;		}	    }	    }	}    }    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn,                "pcibr_pioerror: offset=0x%x, slot=0x%x, func=0x%x\n",		offset, slot, func));    if (space != PCIIO_SPACE_NONE) {	if (slot != PCIIO_SLOT_NONE) {	    if (func != PCIIO_FUNC_NONE) {		IOERROR_SETVALUE(ioe, widgetdev, 				 pciio_widgetdev_create(slot,func));	    }	    else {    		IOERROR_SETVALUE(ioe, widgetdev, 				 pciio_widgetdev_create(slot,0));	    }	}	IOERROR_SETVALUE(ioe, busspace, space);	IOERROR_SETVALUE(ioe, busaddr, offset);    }    if (mode == MODE_DEVPROBE) {	/*	 * During probing, we don't really care what the	 * error is. Clean up the error in Bridge, notify	 * subsidiary devices, and return success.	 */	pcibr_error_cleanup(pcibr_soft, error_code);	/* if appropriate, give the error handler for this slot	 * a shot at this probe access as well.	 */	return (slot == PCIIO_SLOT_NONE) ? IOERROR_HANDLED :	    pciio_error_handler(pcibr_vhdl, error_code, mode, ioe);    }    /*     * If we don't know what "PCI SPACE" the access     * was targeting, we may have problems at the     * Bridge itself. Don't touch any bridge registers,     * and do complain loudly.     */    if (space == PCIIO_SPACE_NONE) {	printk("XIO Bus Error at %s\n"		"\taccess to XIO bus offset 0x%lx\n"		"\tdoes not correspond to any PCI address\n",		pcibr_soft->bs_name, bad_xaddr);	/* caller will dump contents of ioe struct */	return IOERROR_XTALKLEVEL;    }    /*     * Actual PCI Error handling situation.     * Typically happens when a user level process accesses     * PCI space, and it causes some error.     *     * Due to PCI Bridge implementation, we get two indication     * for a read error: an interrupt and a Bus error.     * We like to handle read error in the bus error context.     * But the interrupt comes and goes before bus error     * 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) {#elif !DEBUG	if (kdebug) {#endif	    /*	     * 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);		}	    }#if !DEBUG || defined(FORCE_ERRORS)	}#endif	/*	 * 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 occured, 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){    devfs_handle_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 adress 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){    devfs_handle_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;#ifdef EHE_ENABLE    devfs_handle_t	    xconn_vhdl,pcibr_vhdl;    error_state_t	    e_state;#endif /* EHE_ENABLE */    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));#ifdef EHE_ENABLE    xconn_vhdl = pcibr_soft->bs_conn;    pcibr_vhdl = pcibr_soft->bs_vhdl;    e_state = error_state_get(xconn_vhdl);        if (error_state_set(pcibr_vhdl, e_state) == 	ERROR_RETURN_CODE_CANNOT_SET_STATE)	return(IOERROR_UNHANDLED);    /* If we are in the action handling phase clean out the error state     * on the xswitch.     */    if (e_state == ERROR_STATE_ACTION)	(void)error_state_set(xconn_vhdl, ERROR_STATE_NONE);#endif /* EHE_ENABLE */#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 

⌨️ 快捷键说明

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