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

📄 pcibr_error.c

📁 microwindows移植到S3C44B0的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	    }	    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)) {		atomicAddInt(map->bp_toc, 1);		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;		}	    }	    }	}    }    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%x\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 (bridge->b_int_status & BRIDGE_ISR_PCIBUS_PIOERR)		pcibr_error_dump(pcibr_soft);	    BEM_ADD_SPC(raw_space);	    BEM_ADD_VAR(raw_paddr);	    if (IOERROR_FIELDVALID(ioe, widgetdev)) {		slot = pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, 								 widgetdev));		func = pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, 								 widgetdev));		if (slot < 8) {		    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))	    pcibr_device_disable(pcibr_soft, 				 pciio_widgetdev_slot_get(					  IOERROR_GETVALUE(ioe, widgetdev)));	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. */#define BRIDGE_DMA_READ_ERROR (BRIDGE_ISR_RESP_XTLK_ERR|BRIDGE_ISR_XREAD_REQ_TIMEOUT)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     */    ASSERT(IOERROR_GETVALUE(ioe, widgetnum) == 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)	pcibr_device_disable(pcibr_soft, 			     pciio_widgetdev_slot_get(				      IOERROR_GETVALUE(ioe,widgetdev)));    /*     * 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) {	pcibr_device_disable(pcibr_soft, 			     pciio_widgetdev_slot_get(				      IOERROR_GETVALUE(ioe, widgetdev)));    }    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;#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 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;}/* * Reenable a device after handling the error. * This is called by the lower layers when they wish to be reenabled * after an error. * Note that each layer would be calling the previous layer to reenable * first, before going ahead with their own re-enabling. */intpcibr_error_devenable(devfs_handle_t pconn_vhdl, int error_code){    pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);    pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);    ASSERT(error_code & IOECODE_PIO);    /* If the error is not known to be a write,     * we have to call devenable.     * write errors are isolated to the bridge.     */    if (!(error_code & IOECODE_WRITE)) {	devfs_handle_t            xconn_vhdl = pcibr_soft->bs_conn;	int                     rc;	rc = xtalk_error_devenable(xconn_vhdl, pciio_slot, error_code);	if (rc != IOERROR_HANDLED)	    return rc;    }    pcibr_error_cleanup(pcibr_soft, error_code);    return IOERROR_HANDLED;}

⌨️ 快捷键说明

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