📄 pcibr_slot.c
字号:
pciio_slot_t slot){ pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; int nfunc; pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) return(EINVAL); nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; pcibr_device_info_free(pcibr_vhdl, slot); pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; DELA(pcibr_infoh,nfunc); pcibr_soft->bs_slot[slot].bss_ninfo = 0; return(0);}int as_debug = 0;/* * pcibr_slot_addr_space_init * Reserve chunks of PCI address space as required by * the base registers in the card. */intpcibr_slot_addr_space_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; iopaddr_t pci_io_fb, pci_io_fl; iopaddr_t pci_lo_fb, pci_lo_fl; iopaddr_t pci_hi_fb, pci_hi_fl; size_t align; iopaddr_t mask; int nbars; int nfunc; int func; int win; pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) return(EINVAL); bridge = pcibr_soft->bs_base; /* Get the current values for the allocated PCI address spaces */ PCI_ADDR_SPACE_LIMITS_LOAD(); if (as_debug)#ifdef LATER PCI_ADDR_SPACE_LIMITS_PRINT();#endif /* allocate address space, * for windows that have not been * previously assigned. */ if (pcibr_soft->bs_slot[slot].has_host) { return(0); } nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; if (nfunc < 1) return(EINVAL); pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; if (!pcibr_infoh) return(EINVAL); /* * Try to make the DevIO windows not * overlap by pushing the "io" and "hi" * allocation areas up to the next one * or two megabyte bound. This also * keeps them from being zero. * * DO NOT do this with "pci_lo" since * the entire "lo" area is only a * megabyte, total ... */ align = (slot < 2) ? 0x200000 : 0x100000; mask = -align; pci_io_fb = (pci_io_fb + align - 1) & mask; pci_hi_fb = (pci_hi_fb + align - 1) & mask; for (func = 0; func < nfunc; ++func) { cfg_p cfgw; cfg_p wptr; pciio_space_t space; iopaddr_t base; size_t size; cfg_p pci_cfg_cmd_reg_p; unsigned pci_cfg_cmd_reg; unsigned pci_cfg_cmd_reg_add = 0; pcibr_info = pcibr_infoh[func]; if (!pcibr_info) continue; if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) continue; cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; nbars = PCI_CFG_BASE_ADDRS; for (win = 0; win < nbars; ++win) { space = pcibr_info->f_window[win].w_space; base = pcibr_info->f_window[win].w_base; size = pcibr_info->f_window[win].w_size; if (size < 1) continue; if (base >= size) {#if DEBUG && PCI_DEBUG printk("pcibr: slot %d func %d window %d is in %d[0x%x..0x%x], alloc by prom\n", slot, func, win, space, base, base + size - 1);#endif continue; /* already allocated */ } align = size; /* ie. 0x00001000 */ if (align < _PAGESZ) align = _PAGESZ; /* ie. 0x00004000 */ mask = -align; /* ie. 0xFFFFC000 */ switch (space) { case PCIIO_SPACE_IO: base = (pci_io_fb + align - 1) & mask; if ((base + size) > pci_io_fl) { base = 0; break; } pci_io_fb = base + size; break; case PCIIO_SPACE_MEM:#ifdef SN1_LITTLE_ENDIAN if ((wptr[((win*4)^4)/4] & PCI_BA_MEM_LOCATION) ==#else if ((wptr[win] & PCI_BA_MEM_LOCATION) ==#endif /* LITTLE_ENDIAN */ PCI_BA_MEM_1MEG) { /* allocate from 20-bit PCI space */ base = (pci_lo_fb + align - 1) & mask; if ((base + size) > pci_lo_fl) { base = 0; break; } pci_lo_fb = base + size; } else { /* allocate from 32-bit or 64-bit PCI space */ base = (pci_hi_fb + align - 1) & mask; if ((base + size) > pci_hi_fl) { base = 0; break; } pci_hi_fb = base + size; } break; default: base = 0;#if DEBUG && PCI_DEBUG printk("pcibr: slot %d window %d had bad space code %d\n", slot, win, space);#endif } pcibr_info->f_window[win].w_base = base;#ifdef SN1_LITTLE_ENDIAN wptr[((win*4)^4)/4] = base;#if DEBUG && PCI_DEBUG printk("Setting base address 0x%p base 0x%x\n", &(wptr[((win*4)^4)/4]), base);#endif#else wptr[win] = base;#endif /* LITTLE_ENDIAN */#if DEBUG && PCI_DEBUG if (base >= size) printk("pcibr: slot %d func %d window %d is in %d [0x%x..0x%x], alloc by pcibr\n", slot, func, win, space, base, base + size - 1); else printk("pcibr: slot %d func %d window %d, unable to alloc 0x%x in 0x%p\n", slot, func, win, size, space);#endif } /* next base */ /* * Allocate space for the EXPANSION ROM * NOTE: DO NOT DO THIS ON AN IOC3, * as it blows the system away. */ base = size = 0; if ((pcibr_soft->bs_slot[slot].bss_vendor_id != IOC3_VENDOR_ID_NUM) || (pcibr_soft->bs_slot[slot].bss_device_id != IOC3_DEVICE_ID_NUM)) { wptr = cfgw + PCI_EXPANSION_ROM / 4;#ifdef SN1_LITTLE_ENDIAN wptr[1] = 0xFFFFF000; mask = wptr[1];#else *wptr = 0xFFFFF000; mask = *wptr;#endif /* LITTLE_ENDIAN */ if (mask & 0xFFFFF000) { size = mask & -mask; align = size; if (align < _PAGESZ) align = _PAGESZ; mask = -align; base = (pci_hi_fb + align - 1) & mask; if ((base + size) > pci_hi_fl) base = size = 0; else { pci_hi_fb = base + size;#ifdef SN1_LITTLE_ENDIAN wptr[1] = base;#else *wptr = base;#endif /* LITTLE_ENDIAN */#if DEBUG && PCI_DEBUG printk("%s/%d ROM in 0x%lx..0x%lx (alloc by pcibr)\n", pcibr_soft->bs_name, slot, base, base + size - 1);#endif } } } pcibr_info->f_rbase = base; pcibr_info->f_rsize = size; /* * if necessary, update the board's * command register to enable decoding * in the windows we added. * * There are some bits we always want to * be sure are set. */ pci_cfg_cmd_reg_add |= PCI_CMD_IO_SPACE; /* * The Adaptec 1160 FC Controller WAR #767995: * The part incorrectly ignores the upper 32 bits of a 64 bit * address when decoding references to it's registers so to * keep it from responding to a bus cycle that it shouldn't * we only use I/O space to get at it's registers. Don't * enable memory space accesses on that PCI device. */ #define FCADP_VENDID 0x9004 /* Adaptec Vendor ID from fcadp.h */ #define FCADP_DEVID 0x1160 /* Adaptec 1160 Device ID from fcadp.h */ if ((pcibr_info->f_vendor != FCADP_VENDID) || (pcibr_info->f_device != FCADP_DEVID)) pci_cfg_cmd_reg_add |= PCI_CMD_MEM_SPACE; pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER; pci_cfg_cmd_reg_p = cfgw + PCI_CFG_COMMAND / 4; pci_cfg_cmd_reg = *pci_cfg_cmd_reg_p;#if PCI_FBBE /* XXX- check here to see if dev can do fast-back-to-back */ if (!((pci_cfg_cmd_reg >> 16) & PCI_STAT_F_BK_BK_CAP)) fast_back_to_back_enable = 0;#endif pci_cfg_cmd_reg &= 0xFFFF; if (pci_cfg_cmd_reg_add & ~pci_cfg_cmd_reg) *pci_cfg_cmd_reg_p = pci_cfg_cmd_reg | pci_cfg_cmd_reg_add; } /* next func */ /* Now that we have allocated new chunks of PCI address spaces to this * card we need to update the bookkeeping values which indicate * the current PCI address space allocations. */ PCI_ADDR_SPACE_LIMITS_STORE(); return(0);}/* * pcibr_slot_device_init * Setup the device register in the bridge for this PCI slot. */intpcibr_slot_device_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot){ pcibr_soft_t pcibr_soft; bridge_t *bridge; bridgereg_t devreg; pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) return(EINVAL); bridge = pcibr_soft->bs_base; /* * Adjustments to Device(x) * and init of bss_device shadow */ devreg = bridge->b_device[slot].reg; devreg &= ~BRIDGE_DEV_PAGE_CHK_DIS; devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN;#ifdef LITTLE_ENDIAN devreg |= BRIDGE_DEV_DEV_SWAP;#endif pcibr_soft->bs_slot[slot].bss_device = devreg; bridge->b_device[slot].reg = devreg;#if DEBUG && PCI_DEBUG printk("pcibr Device(%d): 0x%lx\n", slot, bridge->b_device[slot].reg);#endif#if DEBUG && PCI_DEBUG printk("pcibr: PCI space allocation done.\n");#endif return(0);}/* * pcibr_slot_guest_info_init * Setup the host/guest relations for a PCI slot. */intpcibr_slot_guest_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; pcibr_soft_slot_t slotp; pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) return(EINVAL); slotp = &pcibr_soft->bs_slot[slot]; /* create info and verticies for guest slots; * for compatibilitiy macros, create info * for even unpopulated slots (but do not * build verticies for them). */ if (pcibr_soft->bs_slot[slot].bss_ninfo < 1) { NEWA(pcibr_infoh, 1); pcibr_soft->bs_slot[slot].bss_ninfo = 1; pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh; pcibr_info = pcibr_device_info_new (pcibr_soft, slot, PCIIO_FUNC_NONE, PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); if (pcibr_soft->bs_slot[slot].has_host) { slotp->slot_conn = pciio_device_info_register (pcibr_vhdl, &pcibr_info->f_c); } } /* generate host/guest relations */ if (pcibr_soft->bs_slot[slot].has_host) { int host = pcibr_soft->bs_slot[slot].host_slot; pcibr_soft_slot_t host_slotp = &pcibr_soft->bs_slot[host]; hwgraph_edge_add(slotp->slot_conn, host_slotp->slot_conn, EDGE_LBL_HOST); /* XXX- only gives us one guest edge per * host. If/when we have a host with more than * one guest, we will need to figure out how * the host finds all its guests, and sorts * out which one is which. */ hwgraph_edge_add(host_slotp->slot_conn, slotp->slot_conn, EDGE_LBL_GUEST); } return(0);}/* * pcibr_slot_call_device_attach * This calls the associated driver attach routine for the PCI * card in this slot. */intpcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, int drv_flags){ pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; async_attach_t aa = NULL; int func; devfs_handle_t xconn_vhdl,conn_vhdl; int nfunc; int error_func; int error_slot = 0; int error = ENODEV; pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) return(EINVAL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -