pcibr_slot.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,843 行 · 第 1/4 页
C
1,843 行
pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; 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; } PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl, "\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)); } 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; iopaddr_t mask; int nbars; int nfunc; int func; int win; int rc = 0; int align = 0; int align_slot; pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) return -EINVAL; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return -EINVAL; /* 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 = (slot < 2) ? 0x200000 : 0x100000; for (func = 0; func < nfunc; ++func) { cfg_p cfgw; cfg_p wptr; pciio_space_t space; iopaddr_t base; size_t size; 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(pcibr_soft, 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) { PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, "pcibr_slot_addr_space_init: slot=%d, " "func=%d win %d is in space %s [0x%lx..0x%lx], " "allocated by prom\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, win, pci_space[space], (uint64_t)base, (uint64_t)(base + size - 1))); 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 (base >= size) { PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, "pcibr_slot_addr_space_init: slot=%d, func=%d. win %d " "is in space %s [0x%lx..0x%lx], allocated by pcibr\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, win, pci_space[space], (uint64_t)base, (uint64_t)(base + size - 1))); } else { PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, "pcibr_slot_addr_space_init: slot=%d, func=%d, win %d, " "unable to alloc 0x%lx in space %s\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, win, (uint64_t)size, pci_space[space])); } } /* 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); 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; uint64_t devreg; pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) return -EINVAL; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return -EINVAL; /* * Adjustments to Device(x) and init of bss_device shadow */ devreg = pcireg_device_get(pcibr_soft, slot); devreg &= ~BRIDGE_DEV_PAGE_CHK_DIS; /* * Enable virtual channels by default (exception: see PIC WAR below) */ devreg |= BRIDGE_DEV_VIRTUAL_EN; /* * PIC WAR. PV# 855271: Disable virtual channels in the PIC since * it can cause problems with 32-bit devices. We'll set the bit in * pcibr_try_set_device() iff we're 64-bit and requesting virtual * channels. */ if (PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) { devreg &= ~BRIDGE_DEV_VIRTUAL_EN; } devreg |= BRIDGE_DEV_COH; pcibr_soft->bs_slot[slot].bss_device = devreg; pcireg_device_set(pcibr_soft, slot, devreg); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pcibr_vhdl, "pcibr_slot_device_init: Device(%d): 0x%x\n", slot, devreg)); 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) { pcibr_infoh = kmalloc(sizeof (*(pcibr_infoh)), GFP_KERNEL); if ( !pcibr_infoh ) { return -ENOMEM; } memset(pcibr_infoh, 0, sizeof (*(pcibr_infoh))); 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(vertex_hdl_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; int func; vertex_hdl_t xconn_vhdl, conn_vhdl; int nfunc; int error_func; int error_slot = 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?