📄 pcibr_error.c
字号:
for (f = 0; f < nf; f++) { pcibr_info_t pcibr_info = pcibr_infoh[f]; if (!pcibr_info) continue; for (w = 0; w < 6; w++) { if (pcibr_info->f_window[w].w_space == PCIIO_SPACE_NONE) { continue; } base = pcibr_info->f_window[w].w_base; size = pcibr_info->f_window[w].w_size; 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 = 0; s < 8; 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){ bridge_t *bridge = pcibr_soft->bs_base; ASSERT(error_code & IOECODE_PIO); error_code = error_code; bridge->b_int_rst_stat = (BRIDGE_IRR_PCI_GRP_CLR | BRIDGE_IRR_MULTI_CLR); (void) bridge->b_wid_tflush; /* 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(devfs_handle_t pcibr_vhdl, pciio_space_t *spacep, iopaddr_t *offsetp){ pcibr_soft_t pcibr_soft = 0; iopaddr_t bserr_addr; bridge_t *bridge; 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) { bridge = pcibr_soft->bs_base; bserr_addr = bridge->b_pci_err_lower | ((uint64_t) (bridge->b_pci_err_upper & BRIDGE_ERRUPPR_ADDRMASK) << 32); 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. */#define BEM_ADD_STR(s) printk("%s", (s))#define BEM_ADD_VAR(v) printk("\t%20s: 0x%x\n", #v, (v))#define BEM_ADD_REG(r) printk("\t%20s: %R\n", #r, (r), r ## _desc)#define BEM_ADD_NSPC(n,s) printk("\t%20s: %R\n", n, s, space_desc)#define BEM_ADD_SPC(s) BEM_ADD_NSPC(#s, s)/* 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)) { \ unsigned spc; \ unsigned win; \ \ spc = IOERROR_GETVALUE(ioe, busspace); \ win = spc - PCIIO_SPACE_WIN(0); \ \ switch (spc) { \ case PCIIO_SPACE_CFG: \ printk( \ "\tPCI Slot %d Func %d CFG space Offset 0x%x\n", \ pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, widgetdev)), \ pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, widgetdev)), \ IOERROR_GETVALUE(ioe, busaddr)); \ break; \ case PCIIO_SPACE_IO: \ printk( \ "\tPCI I/O space Offset 0x%x\n", \ IOERROR_GETVALUE(ioe, busaddr)); \ break; \ case PCIIO_SPACE_MEM: \ case PCIIO_SPACE_MEM32: \ case PCIIO_SPACE_MEM64: \ printk( \ "\tPCI MEM space Offset 0x%x\n", \ IOERROR_GETVALUE(ioe, busaddr)); \ break; \ default: \ if (win < 6) { \ printk( \ "\tPCI Slot %d Func %d Window %d Offset 0x%x\n",\ pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, widgetdev)), \ pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, widgetdev)), \ win, \ IOERROR_GETVALUE(ioe, 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; devfs_handle_t pcibr_vhdl = pcibr_soft->bs_vhdl; bridge_t *bridge = pcibr_soft->bs_base; 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 slot; /* final PCI slot, if appropriate */ 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. */ bad_xaddr = IOERROR_GETVALUE(ioe, xtalkaddr); slot = PCIIO_SLOT_NONE; func = PCIIO_FUNC_NONE; raw_space = PCIIO_SPACE_NONE; raw_paddr = 0; if ((bad_xaddr >= BRIDGE_TYPE0_CFG_DEV0) && (bad_xaddr < BRIDGE_TYPE1_CFG)) { raw_paddr = bad_xaddr - BRIDGE_TYPE0_CFG_DEV0; slot = raw_paddr / BRIDGE_TYPE0_CFG_SLOT_OFF; raw_paddr = raw_paddr % BRIDGE_TYPE0_CFG_SLOT_OFF; raw_space = PCIIO_SPACE_CFG; } if ((bad_xaddr >= BRIDGE_TYPE1_CFG) && (bad_xaddr < (BRIDGE_TYPE1_CFG + 0x1000))) { /* Type 1 config space: * slot and function numbers not known. * Perhaps we can read them back? */ raw_paddr = bad_xaddr - BRIDGE_TYPE1_CFG; raw_space = PCIIO_SPACE_CFG; } if ((bad_xaddr >= BRIDGE_DEVIO0) && (bad_xaddr < BRIDGE_DEVIO(BRIDGE_DEV_CNT))) { int x; raw_paddr = bad_xaddr - BRIDGE_DEVIO0; 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 ((bad_xaddr >= BRIDGE_PCI_MEM32_BASE) && (bad_xaddr <= BRIDGE_PCI_MEM32_LIMIT)) { raw_space = PCIIO_SPACE_MEM32; raw_paddr = bad_xaddr - BRIDGE_PCI_MEM32_BASE; } if ((bad_xaddr >= BRIDGE_PCI_MEM64_BASE) && (bad_xaddr <= BRIDGE_PCI_MEM64_LIMIT)) { raw_space = PCIIO_SPACE_MEM64; raw_paddr = bad_xaddr - BRIDGE_PCI_MEM64_BASE; } if ((bad_xaddr >= BRIDGE_PCI_IO_BASE) && (bad_xaddr <= BRIDGE_PCI_IO_LIMIT)) { raw_space = PCIIO_SPACE_IO; raw_paddr = bad_xaddr - BRIDGE_PCI_IO_BASE; } space = raw_space; offset = raw_paddr; if ((slot == 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 = 0; (cs < 8) && (slot == 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) && (slot == PCIIO_SLOT_NONE); cf++) { pcibr_info_t pcibr_info = pcibr_infoh[cf]; if (!pcibr_info) continue; for (cw = 0; (cw < 6) && (slot == 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)))) { slot = 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 = 0; cs < 8; ++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 < 6) { wb += pcibr_soft->bs_slot[cs].bss_window[cw].bssw_base; wx = pcibr_soft->bs_slot[cs].bss_window[cw].bssw_space;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -