📄 pcibr_slot.c
字号:
/* * pcibr_slot_pcix_rbar_init * Allocate RBARs to the PCI-X functions on a given device */intpcibr_slot_pcix_rbar_init(pcibr_soft_t pcibr_soft, pciio_slot_t slot){ pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; char tmp_str[256]; int nfunc; int func; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return(EINVAL); if ((nfunc = pcibr_soft->bs_slot[slot].bss_ninfo) < 1) return(EINVAL); if (!(pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos)) return(EINVAL); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl, "pcibr_slot_pcix_rbar_init for slot %d\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot))); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl, "\tslot/func\trequested\tgiven\tinuse\tavail\n")); for (func = 0; func < nfunc; ++func) { cap_pcix_type0_t *pcix_cap_p; cap_pcix_stat_reg_t *pcix_statreg_p; cap_pcix_cmd_reg_t *pcix_cmdreg_p; int num_rbar; if (!(pcibr_info = pcibr_infoh[func])) continue; if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) continue; if (!(pcix_cap_p = pcibr_info->f_pcix_cap)) continue; pcix_statreg_p = &pcix_cap_p->pcix_type0_status; pcix_cmdreg_p = &pcix_cap_p->pcix_type0_command; /* If there are enough RBARs to satify the number of "max outstanding * transactions" each function requested (bs_pcix_rbar_percent_allowed * is 100%), then give each function what it requested, otherwise give * the functions a "percentage of what they requested". */ if (pcibr_soft->bs_pcix_rbar_percent_allowed >= 100) { pcix_cmdreg_p->max_split = pcix_statreg_p->max_out_split; num_rbar = max_splittrans_to_numbuf[pcix_cmdreg_p->max_split]; pcibr_soft->bs_pcix_rbar_inuse += num_rbar; pcibr_soft->bs_pcix_rbar_avail -= num_rbar; pcix_cmdreg_p->max_mem_read_cnt = pcix_statreg_p->max_mem_read_cnt; } else { int index; /* index into max_splittrans_to_numbuf table */ int max_out; /* max outstanding transactions given to func */ /* Calculate the percentage of RBARs this function can have. * NOTE: Every function gets at least 1 RBAR (thus the "+1"). * bs_pcix_rbar_percent_allowed is the percentage of what was * requested less this 1 RBAR that all functions automatically * gets */ max_out = ((max_splittrans_to_numbuf[pcix_statreg_p->max_out_split] * pcibr_soft->bs_pcix_rbar_percent_allowed) / 100) + 1; /* round down the newly caclulated max_out to a valid number in * max_splittrans_to_numbuf[] */ for (index = 0; index < MAX_SPLIT_TABLE-1; index++) if (max_splittrans_to_numbuf[index + 1] > max_out) break; pcix_cmdreg_p->max_split = index; num_rbar = max_splittrans_to_numbuf[pcix_cmdreg_p->max_split]; pcibr_soft->bs_pcix_rbar_inuse += num_rbar; pcibr_soft->bs_pcix_rbar_avail -= num_rbar; pcix_cmdreg_p->max_mem_read_cnt = pcix_statreg_p->max_mem_read_cnt; } /* * The kernel only allows functions to have so many variable args, * attempting to call PCIBR_DEBUG_ALWAYS() with more than 5 printf * arguments fails so sprintf() it into a temporary string. */ if (pcibr_debug_mask & PCIBR_DEBUG_RBAR) { sprintf(tmp_str,"\t %d/%d \t %d \t %d \t %d \t %d\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, max_splittrans_to_numbuf[pcix_statreg_p->max_out_split], max_splittrans_to_numbuf[pcix_cmdreg_p->max_split], pcibr_soft->bs_pcix_rbar_inuse, pcibr_soft->bs_pcix_rbar_avail); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl, "%s", tmp_str)); } } 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(vertex_hdl_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 mask; int nbars; int nfunc; int func; int win; int rc = 0; int align; int align_slot; pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) return(EINVAL); if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return(EINVAL); bridge = pcibr_soft->bs_base; /* 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 = 0x100000; align = align_slot; for (func = 0; func < nfunc; ++func) { cfg_p cfgw; cfg_p wptr; pciio_space_t space; iopaddr_t base; size_t size;#ifdef PCI_LATER char tmp_str[256];#endif 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 = pcibr_func_config_addr(bridge, 0, slot, func, 0); wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; if ((do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0) nbars = 2; else 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) { /* * The kernel only allows functions to have so many variable * args attempting to call PCIBR_DEBUG_ALWAYS() with more than * 5 printf arguments fails so sprintf() it into a temporary * string (tmp_str). */#if defined(SUPPORT_PRINTING_R_FORMAT) if (pcibr_debug_mask & PCIBR_DEBUG_BAR) { sprintf(tmp_str, "pcibr_slot_addr_space_init: slot=%d, " "func=%d win %d is in %r [0x%x..0x%x], allocated by " "prom\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, win, space, space_desc, base, base + size - 1); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, "%s",tmp_str)); }#endif /* SUPPORT_PRINTING_R_FORMAT */ continue; /* already allocated */ } align = (win) ? size : align_slot; if (align < PAGE_SIZE) align = PAGE_SIZE; /* ie. 0x00004000 */ switch (space) { case PCIIO_SPACE_IO: base = pcibr_bus_addr_alloc(pcibr_soft, &pcibr_info->f_window[win], PCIIO_SPACE_IO, 0, size, align); if (!base) rc = ENOSPC; break; case PCIIO_SPACE_MEM: if ((do_pcibr_config_get(wptr, (win * 4), 4) & PCI_BA_MEM_LOCATION) == PCI_BA_MEM_1MEG) { /* allocate from 20-bit PCI space */ base = pcibr_bus_addr_alloc(pcibr_soft, &pcibr_info->f_window[win], PCIIO_SPACE_MEM, 0, size, align); if (!base) rc = ENOSPC; } else { /* allocate from 32-bit or 64-bit PCI space */ base = pcibr_bus_addr_alloc(pcibr_soft, &pcibr_info->f_window[win], PCIIO_SPACE_MEM32, 0, size, align); if (!base) rc = ENOSPC; } break; default: base = 0; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, "pcibr_slot_addr_space_init: slot=%d, window %d " "had bad space code %d\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), win, space)); } pcibr_info->f_window[win].w_base = base; do_pcibr_config_set(wptr, (win * 4), 4, base);#if defined(SUPPORT_PRINTING_R_FORMAT) if (pcibr_debug_mask & PCIBR_DEBUG_BAR) { if (base >= size) { sprintf(tmp_str,"pcibr_slot_addr_space_init: slot=%d, func=" "%d, win %d is in %r[0x%x..0x%x], " "allocated by pcibr\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, win, space, space_desc, base, base + size - 1); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, "%s",tmp_str)); } else { sprintf(tmp_str,"pcibr_slot_addr_space_init: slot=%d, func=" "%d, win %d, unable to alloc 0x%x in %r\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, win, size, space, space_desc); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, "%s",tmp_str)); } }#endif /* SUPPORT_PRINTING_R_FORMAT */ } /* next base */ /* * Allocate space for the EXPANSION ROM */ base = size = 0; { wptr = cfgw + PCI_EXPANSION_ROM / 4; do_pcibr_config_set(wptr, 0, 4, 0xFFFFF000); mask = do_pcibr_config_get(wptr, 0, 4); if (mask & 0xFFFFF000) { size = mask & -mask; base = pcibr_bus_addr_alloc(pcibr_soft, &pcibr_info->f_rwindow, PCIIO_SPACE_MEM32, 0, size, align); if (!base) rc = ENOSPC; else { do_pcibr_config_set(wptr, 0, 4, base); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, "pcibr_slot_addr_space_init: slot=%d, func=%d, " "ROM in [0x%X..0x%X], allocated by pcibr\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, base, base + size - 1)); } } } 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 its 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 = do_pcibr_config_get(cfgw, PCI_CFG_COMMAND, 4);#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) do_pcibr_config_set(cfgw, PCI_CFG_COMMAND, 4, pci_cfg_cmd_reg | pci_cfg_cmd_reg_add); } /* next func */ return(rc);}/* * pcibr_slot_device_init * Setup the device register in the bridge for this PCI slot. */intpcibr_slot_device_init(vertex_hdl_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) return(EINVAL); if (!PCIBR_VALID_SLOT(pcibr_soft, 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; /* * PIC WAR. PV# 855271 * Don't enable virtual channels in the PIC by default. * Can cause problems with 32-bit devices. (The bit is only intended * for 64-bit devices). We set the bit in pcibr_try_set_device() * if we're 64-bit and requesting virtual channels. */ if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) devreg |= BRIDGE_DEV_COH; else devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN; pcibr_soft->bs_slot[slot].bss_device = devreg; bridge->b_device[slot].reg = devreg;#ifdef PIC_LATER PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pcibr_vhdl, "pcibr_slot_device_init: Device(%d): %R\n", slot, devreg, device_bits));#endif return(0);}/* * pcibr_slot_guest_info_init * Setup the host/guest relations for a PCI slot. */intpcibr_slot_guest_info_init(vertex_hdl_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) return(EINVAL); if (!PCIBR_VALID_SLOT(pcibr_soft, 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);}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -