📄 pcibr_slot.c
字号:
slotp->resp_p_int_host = bridge->p_int_addr_64[slot]; } else { slotp->resp_b_int_enable = bridge->b_int_enable; slotp->resp_b_int_host = bridge->b_int_addr[slot].addr; } if (COPYOUT(slotp, respp, sizeof(*respp))) { return(EFAULT); } snia_kmem_free(slotp, sizeof(*slotp)); return(0);}/* * pcibr_slot_query * Return information about the PCI slot maintained by the infrastructure. * Information is requested in the request structure. * * Information returned in the response structure: * Slot hwgraph name * Vendor/Device info * Base register info * Interrupt mapping from device pins to the bridge pins * Devio register * Software RRB info * RRB register info * Host/Gues info * PCI Bus #,slot #, function # * Slot provider hwgraph name * Provider Functions * Error handler * DMA mapping usage counters * DMA direct translation info * External SSRAM workaround info */intpcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp){ pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); pciio_slot_t slot; pciio_slot_t tmp_slot; pcibr_slot_info_resp_t respp = reqp->req_respp.query; int size = reqp->req_size; int error = 0; /* Make sure that we are dealing with a bridge device vertex */ if (!pcibr_soft) { return(PCI_NOT_A_BRIDGE); } /* req_slot is the 'external' slot number, convert for internal use */ slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HOTPLUG, pcibr_vhdl, "pcibr_slot_query: pcibr_soft=0x%x, slot=%d, reqp=0x%x\n", pcibr_soft, slot, reqp)); /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */ if ((!PCIBR_VALID_SLOT(pcibr_soft, slot)) && (slot != PCIIO_SLOT_NONE)) { return(PCI_NOT_A_SLOT); } /* Do not allow a query of a slot in a shoehorn */ if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) { return(PCI_SLOT_IN_SHOEHORN); } /* Return information for the requested PCI slot */ if (slot != PCIIO_SLOT_NONE) { if (size < sizeof(*respp)) { return(PCI_RESP_AREA_TOO_SMALL); }#ifdef PIC_LATER /* Acquire read access to the bus */ mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO);#endif error = pcibr_slot_info_return(pcibr_soft, slot, respp);#ifdef PIC_LATER /* Release the bus lock */ mrunlock(pcibr_soft->bs_bus_lock);#endif return(error); } /* Return information for all the slots */ for (tmp_slot = pcibr_soft->bs_min_slot; tmp_slot < PCIBR_NUM_SLOTS(pcibr_soft); tmp_slot++) { if (size < sizeof(*respp)) { return(PCI_RESP_AREA_TOO_SMALL); }#ifdef PIC_LATER /* Acquire read access to the bus */ mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO);#endif error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp);#ifdef PCI_LATER /* Release the bus lock */ mrunlock(pcibr_soft->bs_bus_lock);#endif if (error) { return(error); } ++respp; size -= sizeof(*respp); } return(error);}#if 0/* * pcibr_slot_reset * Reset the PCI device in the particular slot. * * The Xbridge does not comply with the PCI Specification * when resetting an indiviaudl slot. An individual slot is * is reset by toggling the slot's bit in the Xbridge Control * Register. The Xbridge will assert the target slot's * (non-bussed) RST signal, but does not assert the (bussed) * REQ64 signal as required by the specification. As * designed, the Xbridge cannot assert the REQ64 signal * becuase it may interfere with a bus transaction in progress. * The practical effects of this Xbridge implementation is * device dependent; it probably will not adversely effect * 32-bit cards, but may disable 64-bit data transfers by those * cards that normally support 64-bit data transfers. * * The Xbridge will assert REQ64 when all four slots are reset * by simultaneously toggling all four slot reset bits in the * Xbridge Control Register. This is basically a PCI bus reset * and asserting the (bussed) REQ64 signal will not interfere * with any bus transactions in progress. * * The Xbridge (and the SN0 Bridge) support resetting only * four PCI bus slots via the (X)bridge Control Register. * * To reset an individual slot for the PCI Hot-Plug feature * use the L1 console commands to power-down and then * power-up the slot, or use the kernel infrastructure * functions to power-down/up the slot when they are * implemented for SN1. */intpcibr_slot_reset(devfs_handle_t pcibr_vhdl, pciio_slot_t slot){ pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); bridge_t *bridge; bridgereg_t ctrlreg,tmp; volatile bridgereg_t *wrb_flush; if (!pcibr_soft) return(EINVAL); if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return(EINVAL); /* Enable the DMA operations from this device of the xtalk widget * (PCI host bridge in this case). */ xtalk_widgetdev_enable(pcibr_soft->bs_conn, slot); /* Set the reset slot bit in the bridge's wid control register * to reset the PCI slot */ bridge = pcibr_soft->bs_base; /* Read the bridge widget control and clear out the reset pin * bit for the corresponding slot. */ tmp = ctrlreg = bridge->b_wid_control; tmp &= ~BRIDGE_CTRL_RST_PIN(slot); bridge->b_wid_control = tmp; tmp = bridge->b_wid_control; /* Restore the old control register back. * NOTE : PCI card gets reset when the reset pin bit * changes from 0 (set above) to 1 (going to be set now). */ bridge->b_wid_control = ctrlreg; /* Flush the write buffers if any !! */ wrb_flush = &(bridge->b_wr_req_buf[slot].reg); while (*wrb_flush); return(0);}#endif#define PROBE_LOCK 0 /* FIXME: we're attempting to lock around accesses * to b_int_enable. This hangs pcibr_probe_slot() *//* * pcibr_slot_info_init * Probe for this slot and see if it is populated. * If it is populated initialize the generic PCI infrastructural * information associated with this particular PCI device. */intpcibr_slot_info_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot){ pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; bridge_t *bridge; cfg_p cfgw; unsigned idword; unsigned pfail; unsigned idwords[8]; pciio_vendor_id_t vendor; pciio_device_id_t device; unsigned htype; unsigned lt_time; int nbars; cfg_p wptr; cfg_p pcix_cap; int win; pciio_space_t space; int nfunc; pciio_function_t rfunc; int func; devfs_handle_t conn_vhdl; pcibr_soft_slot_t slotp; /* Get the basic software information required to proceed */ pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) return(EINVAL); bridge = pcibr_soft->bs_base; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return(EINVAL); /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization * is done by the host slot then we are done. */ if (pcibr_soft->bs_slot[slot].has_host) { return(0); } /* Check for a slot with any system critical functions */ if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) return(EPERM); /* Try to read the device-id/vendor-id from the config space */ cfgw = pcibr_slot_config_addr(bridge, slot, 0);#if PROBE_LOCK s = pcibr_lock(pcibr_soft);#endif if (pcibr_probe_slot(bridge, cfgw, &idword)) return(ENODEV);#if PROBE_LOCK pcibr_unlock(pcibr_soft, s);#endif slotp = &pcibr_soft->bs_slot[slot]; slotp->slot_status |= SLOT_POWER_UP; vendor = 0xFFFF & idword; device = 0xFFFF & (idword >> 16); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PROBE, pcibr_vhdl, "pcibr_slot_info_init: slot=%d, vendor=0x%x, device=0x%x\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vendor, device)); /* If the vendor id is not valid then the slot is not populated * and we are done. */ if (vendor == 0xFFFF) return(ENODEV); htype = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1); nfunc = 1; rfunc = PCIIO_FUNC_NONE; pfail = 0; /* NOTE: if a card claims to be multifunction * but only responds to config space 0, treat * it as a unifunction card. */ if (htype & 0x80) { /* MULTIFUNCTION */ for (func = 1; func < 8; ++func) { cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);#if PROBE_LOCK s = pcibr_lock(pcibr_soft);#endif if (pcibr_probe_slot(bridge, cfgw, &idwords[func])) { pfail |= 1 << func; continue; }#if PROBE_LOCK pcibr_unlock(pcibr_soft, s);#endif vendor = 0xFFFF & idwords[func]; if (vendor == 0xFFFF) { pfail |= 1 << func; continue; } nfunc = func + 1; rfunc = 0; } cfgw = pcibr_slot_config_addr(bridge, slot, 0); } NEWA(pcibr_infoh, nfunc); pcibr_soft->bs_slot[slot].bss_ninfo = nfunc; pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh; for (func = 0; func < nfunc; ++func) { unsigned cmd_reg; if (func) { if (pfail & (1 << func)) continue; idword = idwords[func]; cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); device = 0xFFFF & (idword >> 16); htype = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1); rfunc = func; } htype &= 0x7f; if (htype != 0x00) { printk(KERN_WARNING "%s pcibr: pci slot %d func %d has strange header type 0x%x\n", pcibr_soft->bs_name, slot, func, htype); nbars = 2; } else { nbars = PCI_CFG_BASE_ADDRS; } PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl, "pcibr_slot_info_init: slot=%d, func=%d, cfgw=0x%x\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), func, cfgw));#ifdef PIC_LATER /* * Check for a Quad ATM PCI "card" and return all the PCI bus * memory and I/O space. This will work-around an apparent * hardware problem with the Quad ATM XIO card handling large * PIO addresses. Releasing all the space for use by the card * will lower the PIO addresses with the PCI bus address space. * This is OK since the PROM did not assign any BAR addresses. * * Only release all the PCI bus addresses once. * */ if ((vendor == LINC_VENDOR_ID_NUM) && (device == LINC_DEVICE_ID_NUM)) { iopaddr_t prom_base_addr = pcibr_soft->bs_xid << 24; int prom_base_size = 0x1000000; if (!(pcibr_soft->bs_bus_addr_status & PCIBR_BUS_ADDR_MEM_FREED)) { pciio_device_win_populate(&pcibr_soft->bs_mem_win_map, prom_base_addr, prom_base_size); pcibr_soft->bs_bus_addr_status |= PCIBR_BUS_ADDR_MEM_FREED; } if (!(pcibr_soft->bs_bus_addr_status & PCIBR_BUS_ADDR_IO_FREED)) { pciio_device_win_populate(&pcibr_soft->bs_io_win_map, prom_base_addr, prom_base_size); pcibr_soft->bs_bus_addr_status |= PCIBR_BUS_ADDR_IO_FREED; } }#endif /* PIC_LATER */ /* * If the latency timer has already been set, by prom or by the * card itself, use that value. Otherwise look at the device's * 'min_gnt' and attempt to calculate a latency time. * * NOTE: For now if the device is on the 'real time' arbitration * ring we dont set the latency timer. * * WAR: SGI's IOC3 and RAD devices target abort if you write a * single byte into their config space. So don't set the Latency * Timer for these devices */ lt_time = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_LATENCY_TIMER, 1); if ((lt_time == 0) && !(bridge->b_device[slot].reg & BRIDGE_DEV_RT) && !((vendor == IOC3_VENDOR_ID_NUM) && (#ifdef PIC_LATER (device == IOC3_DEVICE_ID_NUM) || (device == LINC_DEVICE_ID_NUM) ||#endif (device == 0x5 /* RAD_DEV */)))) { unsigned min_gnt; unsigned min_gnt_mult; /* 'min_gnt' indicates how long of a burst period a device * needs in increments of 250ns. But latency timer is in * PCI clock cycles, so a conversion is needed. */ min_gnt = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_MIN_GNT, 1); if (IS_133MHZ(pcibr_soft)) min_gnt_mult = 32; /* 250ns @ 133MHz in clocks */ else if (IS_100MHZ(pcibr_soft)) min_gnt_mult = 24; /* 250ns @ 100MHz in clocks */ else if (IS_66MHZ(pcibr_soft)) min_gnt_mult = 16; /* 250ns @ 66MHz, in clocks */ else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -