pcibr_slot.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,843 行 · 第 1/4 页
C
1,843 行
int error = ENODEV; pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) return -EINVAL; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return -EINVAL; if (pcibr_soft->bs_slot[slot].has_host) { return -EPERM; } xconn_vhdl = pcibr_soft->bs_conn; nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; for (func = 0; func < nfunc; ++func) { pcibr_info = pcibr_infoh[func]; if (!pcibr_info) continue; if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) continue; conn_vhdl = pcibr_info->f_vertex; error_func = pciio_device_attach(conn_vhdl, drv_flags); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEV_ATTACH, pcibr_vhdl, "pcibr_slot_call_device_attach: slot=%d, func=%d " "drv_flags=0x%x, pciio_device_attach returned %d\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, drv_flags, error_func)); pcibr_info->f_att_det_error = error_func; if (error_func) error_slot = error_func; error = error_slot; } /* next func */#ifdef CONFIG_HOTPLUG_PCI_SGI if (error) { if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) { pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT; } } else { pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; }#endif /* CONFIG_HOTPLUG_PCI_SGI */ return error;}/* * pcibr_slot_call_device_detach * This calls the associated driver detach routine for the PCI * card in this slot. */intpcibr_slot_call_device_detach(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 conn_vhdl = GRAPH_VERTEX_NONE; int nfunc; int error_func; int error_slot = 0; int error = ENODEV; pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) return -EINVAL; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return -EINVAL; if (pcibr_soft->bs_slot[slot].has_host) return -EPERM; nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; for (func = 0; func < nfunc; ++func) { pcibr_info = pcibr_infoh[func]; if (!pcibr_info) continue; if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) continue; if (IS_PCIX(pcibr_soft) && pcibr_info->f_pcix_cap) { int max_out; pcibr_soft->bs_pcix_num_funcs--; max_out = pcibr_info->f_pcix_cap->pcix_type0_status.max_out_split; pcibr_soft->bs_pcix_split_tot -= max_splittrans_to_numbuf[max_out]; } conn_vhdl = pcibr_info->f_vertex; error_func = pciio_device_detach(conn_vhdl, drv_flags); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEV_DETACH, pcibr_vhdl, "pcibr_slot_call_device_detach: slot=%d, func=%d " "drv_flags=0x%x, pciio_device_detach returned %d\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, drv_flags, error_func)); pcibr_info->f_att_det_error = error_func; if (error_func) error_slot = error_func; error = error_slot; } /* next func */#ifdef CONFIG_HOTPLUG_PCI_SGI if (error) { if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) { pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT; } } else { if (conn_vhdl != GRAPH_VERTEX_NONE) pcibr_device_unregister(conn_vhdl); pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; }#endif /* CONFIG_HOTPLUG_PCI_SGI */ return error;}/* * pcibr_slot_detach * This is a place holder routine to keep track of all the * slot-specific freeing that needs to be done. */intpcibr_slot_detach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags, char *l1_msg, int *sub_errorp){ pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); int error; /* Call the device detach function */ error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags)); if (error) { if (sub_errorp) *sub_errorp = error; if (l1_msg) ; return PCI_SLOT_DRV_DETACH_ERR; } /* Recalculate the RBARs for all the devices on the bus since we've * just freed some up and some of the devices could use them. */ if (IS_PCIX(pcibr_soft)) { int tmp_slot; pcibr_soft->bs_pcix_rbar_inuse = 0; pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR; pcibr_soft->bs_pcix_rbar_percent_allowed = pcibr_pcix_rbars_calc(pcibr_soft); for (tmp_slot = pcibr_soft->bs_min_slot; tmp_slot < PCIBR_NUM_SLOTS(pcibr_soft); ++tmp_slot) (void)pcibr_slot_pcix_rbar_init(pcibr_soft, tmp_slot); } return 0;}/* * pcibr_probe_slot_pic: read a config space word * while trapping any errors; return zero if * all went OK, or nonzero if there was an error. * The value read, if any, is passed back * through the valp parameter. */static intpcibr_probe_slot(pcibr_soft_t pcibr_soft, cfg_p cfg, unsigned *valp){ return pcibr_probe_work(pcibr_soft, (void *)cfg, 4, (void *)valp);}/* * Probe an offset within a piomap with errors disabled. * len must be 1, 2, 4, or 8. The probed address must be a multiple of * len. * * Returns: 0 if the offset was probed and put valid data in valp * -1 if there was a usage error such as improper alignment * or out of bounds offset/len combination. In this * case, the map was not probed * 1 if the offset was probed but resulted in an error * such as device not responding, bus error, etc. */intpcibr_piomap_probe(pcibr_piomap_t piomap, off_t offset, int len, void *valp){ if (offset + len > piomap->bp_mapsz) { return -1; } return pcibr_probe_work(piomap->bp_soft, piomap->bp_kvaddr + offset, len, valp);}static uint64_tpcibr_disable_mst_timeout(pcibr_soft_t pcibr_soft){ uint64_t old_enable; uint64_t new_enable; uint64_t intr_bits; intr_bits = PIC_ISR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT | PIC_ISR_PCIX_SPLIT_EMSG; old_enable = pcireg_intr_enable_get(pcibr_soft); pcireg_intr_enable_bit_clr(pcibr_soft, intr_bits); new_enable = pcireg_intr_enable_get(pcibr_soft); if (old_enable == new_enable) { return 0; /* was already disabled */ } else { return 1; }}static intpcibr_enable_mst_timeout(pcibr_soft_t pcibr_soft){ uint64_t old_enable; uint64_t new_enable; uint64_t intr_bits; intr_bits = PIC_ISR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT | PIC_ISR_PCIX_SPLIT_EMSG; old_enable = pcireg_intr_enable_get(pcibr_soft); pcireg_intr_enable_bit_set(pcibr_soft, intr_bits); new_enable = pcireg_intr_enable_get(pcibr_soft); if (old_enable == new_enable) { return 0; /* was alread enabled */ } else { return 1; }}/* * pcibr_probe_slot: read a config space word * while trapping any errors; return zero if * all went OK, or nonzero if there was an error. * The value read, if any, is passed back * through the valp parameter. */static intpcibr_probe_work(pcibr_soft_t pcibr_soft, void *addr, int len, void *valp){ int rv, changed; /* * Sanity checks ... */ if (len != 1 && len != 2 && len != 4 && len != 8) { return -1; /* invalid len */ } if ((uint64_t)addr & (len-1)) { return -1; /* invalid alignment */ } changed = pcibr_disable_mst_timeout(pcibr_soft); rv = snia_badaddr_val((void *)addr, len, valp); /* Clear the int_view register incase it was set */ pcireg_intr_reset_set(pcibr_soft, BRIDGE_IRR_MULTI_CLR); if (changed) { pcibr_enable_mst_timeout(pcibr_soft); } return (rv ? 1 : 0); /* return 1 for snia_badaddr_val error, 0 if ok */}voidpcibr_device_info_free(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot){ pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); pcibr_info_t pcibr_info; pciio_function_t func; pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[slot]; cfg_p cfgw; int nfunc = slotp->bss_ninfo; int bar; int devio_index; unsigned long s; unsigned cmd_reg; for (func = 0; func < nfunc; func++) { pcibr_info = slotp->bss_infos[func]; if (!pcibr_info) continue; s = pcibr_lock(pcibr_soft); /* Disable memory and I/O BARs */ cfgw = pcibr_func_config_addr(pcibr_soft, 0, slot, func, 0); cmd_reg = do_pcibr_config_get(cfgw, PCI_CFG_COMMAND, 4); cmd_reg &= (PCI_CMD_MEM_SPACE | PCI_CMD_IO_SPACE); do_pcibr_config_set(cfgw, PCI_CFG_COMMAND, 4, cmd_reg); for (bar = 0; bar < PCI_CFG_BASE_ADDRS; bar++) { if (pcibr_info->f_window[bar].w_space == PCIIO_SPACE_NONE) continue; /* Free the PCI bus space */ pcibr_bus_addr_free(&pcibr_info->f_window[bar]); /* Get index of the DevIO(x) register used to access this BAR */ devio_index = pcibr_info->f_window[bar].w_devio_index; /* On last use, clear the DevIO(x) used to access this BAR */ if (! --pcibr_soft->bs_slot[devio_index].bss_devio.bssd_ref_cnt) { pcibr_soft->bs_slot[devio_index].bss_devio.bssd_space = PCIIO_SPACE_NONE; pcibr_soft->bs_slot[devio_index].bss_devio.bssd_base = PCIBR_D32_BASE_UNSET; pcibr_soft->bs_slot[devio_index].bss_device = 0; } } /* Free the Expansion ROM PCI bus space */ if(pcibr_info->f_rbase && pcibr_info->f_rsize) { pcibr_bus_addr_free(&pcibr_info->f_rwindow); } pcibr_unlock(pcibr_soft, s); slotp->bss_infos[func] = 0; pciio_device_info_unregister(pcibr_vhdl, &pcibr_info->f_c); pciio_device_info_free(&pcibr_info->f_c); kfree(pcibr_info); } /* Reset the mapping usage counters */ slotp->bss_pmu_uctr = 0; slotp->bss_d32_uctr = 0; slotp->bss_d64_uctr = 0; /* Clear the Direct translation info */ slotp->bss_d64_base = PCIBR_D64_BASE_UNSET; slotp->bss_d64_flags = 0; slotp->bss_d32_base = PCIBR_D32_BASE_UNSET; slotp->bss_d32_flags = 0;}iopaddr_tpcibr_bus_addr_alloc(pcibr_soft_t pcibr_soft, pciio_win_info_t win_info_p, pciio_space_t space, int start, int size, int align){ pciio_win_map_t win_map_p; struct resource *root_resource = NULL; iopaddr_t iopaddr = 0; switch (space) { case PCIIO_SPACE_IO: win_map_p = &pcibr_soft->bs_io_win_map; root_resource = &pcibr_soft->bs_io_win_root_resource; break; case PCIIO_SPACE_MEM: win_map_p = &pcibr_soft->bs_swin_map; root_resource = &pcibr_soft->bs_swin_root_resource; break; case PCIIO_SPACE_MEM32: win_map_p = &pcibr_soft->bs_mem_win_map; root_resource = &pcibr_soft->bs_mem_win_root_resource; break; default: return 0; } iopaddr = pciio_device_win_alloc(root_resource, win_info_p ? &win_info_p->w_win_alloc : NULL, start, size, align); return iopaddr;}voidpcibr_bus_addr_free(pciio_win_info_t win_info_p){ pciio_device_win_free(&win_info_p->w_win_alloc);}/* * given a vertex_hdl to the pcibr_vhdl, return the brick's bus number * associated with that vertex_hdl. The true mapping happens from the * io_brick_tab[] array defined in ml/SN/iograph.c */intpcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); xwidgetnum_t widget = pcibr_soft->bs_xid; int bricktype = pcibr_soft->bs_bricktype; int bus; if ((bus = io_brick_map_widget(bricktype, widget)) <= 0) { printk(KERN_WARNING "pcibr_widget_to_bus() bad bricktype %d\n", bricktype); return 0; } /* For PIC there are 2 busses per widget and pcibr_soft->bs_busnum * will be 0 or 1. Add in the correct PIC bus offset. */ bus += pcibr_soft->bs_busnum; return bus;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?