pcibr_error.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,874 行 · 第 1/4 页

C
1,874
字号
		if ((pciaddr >= base) && (pciaddr < (base + size))) {		    if (spacep)			*spacep = PCIIO_SPACE_WIN(w);		    if (offsetp)			*offsetp = pciaddr - base;		    if (funcp)			*funcp = f;		    return s;		}			/* endif match */	    }				/* next window */	}				/* next func */    }					/* next slot */    /*     * Check if the address was allocated as part of the     * pcibr_piospace_alloc calls.     */    for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) {	int                     nf = pcibr_soft->bs_slot[s].bss_ninfo;	pcibr_info_h            pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos;	for (f = 0; f < nf; f++) {	    pcibr_info_t            pcibr_info = pcibr_infoh[f];	    if (!pcibr_info)		continue;	    piosp = pcibr_info->f_piospace;	    while (piosp) {		if ((piosp->start <= pciaddr) &&		    ((piosp->count + piosp->start) > pciaddr)) {		    if (spacep)			*spacep = piosp->space;		    if (offsetp)			*offsetp = pciaddr - piosp->start;		    return s;		}			/* endif match */		piosp = piosp->next;	    }				/* next piosp */	}				/* next func */    }					/* next slot */    /*     * Some other random address on the PCI bus ...     * we have no way of knowing whether this was     * a MEM or I/O access; so, for now, we just     * assume that the low 1G is MEM, the next     * 3G is I/O, and anything above the 4G limit     * is obviously MEM.     */    if (spacep)	*spacep = ((pciaddr < (1ul << 30)) ? PCIIO_SPACE_MEM :		   (pciaddr < (4ul << 30)) ? PCIIO_SPACE_IO :		   PCIIO_SPACE_MEM);    if (offsetp)	*offsetp = pciaddr;    return PCIIO_SLOT_NONE;}voidpcibr_error_cleanup(pcibr_soft_t pcibr_soft, int error_code){    uint64_t	clr_bits = BRIDGE_IRR_ALL_CLR;    ASSERT(error_code & IOECODE_PIO);    error_code = error_code;    pcireg_intr_reset_set(pcibr_soft, clr_bits);    pcireg_tflush_get(pcibr_soft);	/* flushbus */}/* * pcibr_error_extract *      Given the 'pcibr vertex handle' find out which slot *      the bridge status error address (from pcibr_soft info *      hanging off the vertex) *      allocated to, and return the slot number. *      While we have the info handy, construct the *      space code and offset as well. * * NOTE: if this routine is called, we don't know whether * the address is in CFG, MEM, or I/O space. We have to guess. * This will be the case on PIO stores, where the only way * we have of getting the address is to check the Bridge, which * stores the PCI address but not the space and not the xtalk * address (from which we could get it). * * XXX- this interface has no way to return the function * number on a multifunction card, even though that data * is available. */pciio_slot_tpcibr_error_extract(vertex_hdl_t pcibr_vhdl,		    pciio_space_t *spacep,		    iopaddr_t *offsetp){    pcibr_soft_t            pcibr_soft = 0;    iopaddr_t               bserr_addr;    pciio_slot_t            slot = PCIIO_SLOT_NONE;    arbitrary_info_t	    rev;    /* Do a sanity check as to whether we really got a      * bridge vertex handle.     */    if (hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &rev) !=	GRAPH_SUCCESS) 	return(slot);    pcibr_soft = pcibr_soft_get(pcibr_vhdl);    if (pcibr_soft) {	bserr_addr = pcireg_pci_bus_addr_get(pcibr_soft);	slot = pcibr_addr_toslot(pcibr_soft, bserr_addr,				 spacep, offsetp, NULL);    }    return slot;}/*ARGSUSED */voidpcibr_device_disable(pcibr_soft_t pcibr_soft, int devnum){    /*     * XXX     * Device failed to handle error. Take steps to     * disable this device ? HOW TO DO IT ?     *     * If there are any Read response buffers associated     * with this device, it's time to get them back!!     *     * We can disassociate any interrupt level associated     * with this device, and disable that interrupt level     *     * For now it's just a place holder     */}/* * pcibr_pioerror *      Handle PIO error that happened at the bridge pointed by pcibr_soft. * *      Queries the Bus interface attached to see if the device driver *      mapping the device-number that caused error can handle the *      situation. If so, it will clean up any error, and return *      indicating the error was handled. If the device driver is unable *      to handle the error, it expects the bus-interface to disable that *      device, and takes any steps needed here to take away any resources *      associated with this device. * * A note about slots: * * 	PIC-based bridges use zero-based device numbering when devices to * 	internal registers.  However, the physical slots are numbered using a *	one-based scheme because in PCI-X, device 0 is reserved (see comments * 	in pcibr_private.h for a better description). * * 	When building up the hwgraph, we use the external (one-based) number *	scheme when numbering slot components so that hwgraph more accuratly * 	reflects what is silkscreened on the bricks. * * 	Since pciio_error_handler() needs to ultimatly be able to do a hwgraph *	lookup, the ioerror that gets built up in pcibr_pioerror() encodes the *	external (one-based) slot number.  However, loops in pcibr_pioerror()  * 	which attempt to translate the virtual address into the correct * 	PCI physical address use the device (zero-based) numbering when  * 	walking through bridge structures. * * 	To that end, pcibr_pioerror() uses device to denote the  *	zero-based device number, and external_slot to denote the corresponding *	one-based slot number.  Loop counters (eg. cs) are always device based. *//* BEM_ADD_IOE doesn't dump the whole ioerror, it just * decodes the PCI specific portions -- we count on our * callers to dump the raw IOE data. */#define BEM_ADD_IOE(ioe)						\	do {								\	    if (IOERROR_FIELDVALID(ioe, busspace)) {			\		iopaddr_t		spc;				\		iopaddr_t		win;				\		short			widdev;				\		iopaddr_t		busaddr;			\									\		IOERROR_GETVALUE(spc, ioe, busspace);			\		win = spc - PCIIO_SPACE_WIN(0);				\		IOERROR_GETVALUE(busaddr, ioe, busaddr);		\		IOERROR_GETVALUE(widdev, ioe, widgetdev);		\									\		switch (spc) {						\		case PCIIO_SPACE_CFG:					\		    printk("\tPCI Slot %d Func %d CFG space Offset 0x%lx\n",\			    	pciio_widgetdev_slot_get(widdev),	\	    			pciio_widgetdev_func_get(widdev),	\				busaddr);				\		    break;						\		case PCIIO_SPACE_IO:					\		    printk("\tPCI I/O space  Offset 0x%lx\n", busaddr);	\		    break;						\		case PCIIO_SPACE_MEM:					\		case PCIIO_SPACE_MEM32:					\		case PCIIO_SPACE_MEM64:					\		    printk("\tPCI MEM space Offset 0x%lx\n", busaddr);	\		    break;						\		default:						\		    if (win < 6) {					\		    printk("\tPCI Slot %d Func %d Window %ld Offset 0x%lx\n",\	    			pciio_widgetdev_slot_get(widdev),	\	    			pciio_widgetdev_func_get(widdev),	\			    	win,					\			    	busaddr);				\		    }							\		    break;						\		}							\	    }								\	} while (0)/*ARGSUSED */intpcibr_pioerror(		  pcibr_soft_t pcibr_soft,		  int error_code,		  ioerror_mode_t mode,		  ioerror_t *ioe){    int                     retval = IOERROR_HANDLED;    vertex_hdl_t            pcibr_vhdl = pcibr_soft->bs_vhdl;    iopaddr_t               bad_xaddr;    pciio_space_t           raw_space;	/* raw PCI space */    iopaddr_t               raw_paddr;	/* raw PCI address */    pciio_space_t           space;	/* final PCI space */    pciio_slot_t            device;	/* final PCI device if appropriate */    pciio_slot_t            external_slot;/* external slot for device */    pciio_function_t        func;	/* final PCI func, if appropriate */    iopaddr_t               offset;	/* final PCI offset */        int                     cs, cw, cf;    pciio_space_t           wx;    iopaddr_t               wb;    size_t                  ws;    iopaddr_t               wl;    /*     * We expect to have an "xtalkaddr" coming in,     * and need to construct the slot/space/offset.     */    IOERROR_GETVALUE(bad_xaddr, ioe, xtalkaddr);    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn,                "pcibr_pioerror: pcibr_soft=0x%lx, bad_xaddr=0x%lx\n",		pcibr_soft, bad_xaddr));    device = PCIIO_SLOT_NONE;    func = PCIIO_FUNC_NONE;    raw_space = PCIIO_SPACE_NONE;    raw_paddr = 0;    if ((bad_xaddr >= PCIBR_BUS_TYPE0_CFG_DEV(pcibr_soft, 0)) &&	(bad_xaddr < PCIBR_TYPE1_CFG(pcibr_soft))) {	raw_paddr = bad_xaddr - PCIBR_BUS_TYPE0_CFG_DEV(pcibr_soft, 0);	device = raw_paddr / BRIDGE_CONFIG_SLOT_SIZE;	raw_paddr = raw_paddr % BRIDGE_CONFIG_SLOT_SIZE;	raw_space = PCIIO_SPACE_CFG;    }    if ((bad_xaddr >= PCIBR_TYPE1_CFG(pcibr_soft)) &&	(bad_xaddr < (PCIBR_TYPE1_CFG(pcibr_soft) + 0x1000))) {	/* Type 1 config space:	 * slot and function numbers not known.	 * Perhaps we can read them back?	 */	raw_paddr = bad_xaddr - PCIBR_TYPE1_CFG(pcibr_soft);	raw_space = PCIIO_SPACE_CFG;    }    if ((bad_xaddr >= PCIBR_BRIDGE_DEVIO(pcibr_soft, 0)) &&	(bad_xaddr < PCIBR_BRIDGE_DEVIO(pcibr_soft, BRIDGE_DEV_CNT))) {	int                     x;	raw_paddr = bad_xaddr - PCIBR_BRIDGE_DEVIO(pcibr_soft, 0);	x = raw_paddr / BRIDGE_DEVIO_OFF;	raw_paddr %= BRIDGE_DEVIO_OFF;	/* first two devio windows are double-sized */	if ((x == 1) || (x == 3))	    raw_paddr += BRIDGE_DEVIO_OFF;	if (x > 0)	    x--;	if (x > 1)	    x--;	/* x is which devio reg; no guarantee	 * PCI slot x will be responding.	 * still need to figure out who decodes	 * space/offset on the bus.	 */	raw_space = pcibr_soft->bs_slot[x].bss_devio.bssd_space;	if (raw_space == PCIIO_SPACE_NONE) {	    /* Someone got an error because they	     * accessed the PCI bus via a DevIO(x)	     * window that pcibr has not yet assigned	     * to any specific PCI address. It is	     * quite possible that the Device(x)	     * register has been changed since they	     * made their access, but we will give it	     * our best decode shot.	     */	    raw_space = pcibr_soft->bs_slot[x].bss_device		& BRIDGE_DEV_DEV_IO_MEM		? PCIIO_SPACE_MEM		: PCIIO_SPACE_IO;	    raw_paddr +=		(pcibr_soft->bs_slot[x].bss_device &		 BRIDGE_DEV_OFF_MASK) <<		BRIDGE_DEV_OFF_ADDR_SHFT;	} else	    raw_paddr += pcibr_soft->bs_slot[x].bss_devio.bssd_base;    }    if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 0)) {    	if ((bad_xaddr >= PICBRIDGE0_PCI_MEM32_BASE) &&	    (bad_xaddr <= PICBRIDGE0_PCI_MEM32_LIMIT)) {	    raw_space = PCIIO_SPACE_MEM32;	    raw_paddr = bad_xaddr - PICBRIDGE0_PCI_MEM32_BASE;    	}    	if ((bad_xaddr >= PICBRIDGE0_PCI_MEM64_BASE) &&	    (bad_xaddr <= PICBRIDGE0_PCI_MEM64_LIMIT)) {	    raw_space = PCIIO_SPACE_MEM64;	    raw_paddr = bad_xaddr - PICBRIDGE0_PCI_MEM64_BASE;    	}    } else if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 1)) {    	if ((bad_xaddr >= PICBRIDGE1_PCI_MEM32_BASE) &&	    (bad_xaddr <= PICBRIDGE1_PCI_MEM32_LIMIT)) {	    raw_space = PCIIO_SPACE_MEM32;	    raw_paddr = bad_xaddr - PICBRIDGE1_PCI_MEM32_BASE;    	}    	if ((bad_xaddr >= PICBRIDGE1_PCI_MEM64_BASE) &&	    (bad_xaddr <= PICBRIDGE1_PCI_MEM64_LIMIT)) {	    raw_space = PCIIO_SPACE_MEM64;	    raw_paddr = bad_xaddr - PICBRIDGE1_PCI_MEM64_BASE;    	}    } else {	printk("pcibr_pioerror(): unknown bridge type");	return IOERROR_UNHANDLED;    }    space = raw_space;    offset = raw_paddr;    if ((device == PCIIO_SLOT_NONE) && (space != PCIIO_SPACE_NONE)) {	/* we've got a space/offset but not which	 * PCI slot decodes it. Check through our	 * notions of which devices decode where.	 *	 * Yes, this "duplicates" some logic in	 * pcibr_addr_toslot; the difference is,	 * this code knows which space we are in,	 * and can really really tell what is	 * going on (no guessing).	 */	for (cs = pcibr_soft->bs_min_slot; 		(cs < PCIBR_NUM_SLOTS(pcibr_soft)) && 				(device == PCIIO_SLOT_NONE); cs++) {	    int                     nf = pcibr_soft->bs_slot[cs].bss_ninfo;	    pcibr_info_h            pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos;	    for (cf = 0; (cf < nf) && (device == PCIIO_SLOT_NONE); cf++) {		pcibr_info_t            pcibr_info = pcibr_infoh[cf];		if (!pcibr_info)		    continue;		for (cw = 0; (cw < 6) && (device == PCIIO_SLOT_NONE); ++cw) {		    if (((wx = pcibr_info->f_window[cw].w_space) != PCIIO_SPACE_NONE) &&			((wb = pcibr_info->f_window[cw].w_base) != 0) &&			((ws = pcibr_info->f_window[cw].w_size) != 0) &&			((wl = wb + ws) > wb) &&			((wb <= offset) && (wl > offset))) {			/* MEM, MEM32 and MEM64 need to			 * compare as equal ...			 */			if ((wx == space) ||			    (((wx == PCIIO_SPACE_MEM) ||			      (wx == PCIIO_SPACE_MEM32) ||			      (wx == PCIIO_SPACE_MEM64)) &&			     ((space == PCIIO_SPACE_MEM) ||			      (space == PCIIO_SPACE_MEM32) ||			      (space == PCIIO_SPACE_MEM64)))) {			    device = cs;			    func = cf;			    space = PCIIO_SPACE_WIN(cw);			    offset -= wb;			}		/* endif window space match */		    }			/* endif window valid and addr match */		}			/* next window unless slot set */	    }				/* next func unless slot set */	}				/* next slot unless slot set */	/* XXX- if slot is still -1, no PCI devices are	 * decoding here using their standard PCI BASE	 * registers. This would be a really good place	 * to cross-coordinate with the pciio PCI	 * address space allocation routines, to find	 * out if this address is "allocated" by any of	 * our subsidiary devices.	 */    }    /* Scan all piomap records on this PCI bus to update     * the TimeOut Counters on all matching maps. If we     * don't already know the slot number, take it from     * the first matching piomap. Note that we have to     * compare maps against raw_space and raw_paddr     * since space and offset could already be     * window-relative.     *     * There is a chance that one CPU could update     * through this path, and another CPU could also     * update due to an interrupt. Closing this hole     * would only result in the possibility of some     * errors never getting logged at all, and since the     * use for bp_toc is as a logical test rather than a     * strict count, the excess counts are not a     * problem.     */    for (cs = pcibr_soft->bs_min_slot; 				cs < PCIBR_NUM_SLOTS(pcibr_soft); ++cs) {	int 		nf = pcibr_soft->bs_slot[cs].bss_ninfo;	pcibr_info_h	pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos;	for (cf = 0; cf < nf; cf++) {	    pcibr_info_t 	pcibr_info = pcibr_infoh[cf];	    pcibr_piomap_t	map;    	    if (!pcibr_info)		continue;	    for (map = pcibr_info->f_piomap;	     map != NULL; map = map->bp_next) {	    wx = map->bp_space;	    wb = map->bp_pciaddr;	    ws = map->bp_mapsz;	    cw = wx - PCIIO_SPACE_WIN(0);	    if (cw >= 0 && 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);		if (device == PCIIO_SLOT_NONE) {		    device = cs;		    func = cf;		    space = map->bp_space;		    if (cw >= 0 && cw < 6)			offset -= pcibr_soft->bs_slot[device].bss_window[cw].bssw_base;		}		break;

⌨️ 快捷键说明

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