📄 pcibr_slot.c
字号:
* 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;#ifdef PIC_LATER vertex_hdl_t scsi_vhdl;#endif int nfunc; int error_func; int error_slot = 0; int error = ENODEV;#ifdef PIC_LATER int hwg_err;#endif 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);#ifdef PIC_LATER /* * Try to assign well-known SCSI controller numbers for hot-plug * insert */ if (drv_flags) { hwg_err = hwgraph_path_lookup(conn_vhdl, EDGE_LBL_SCSI_CTLR "/0", &scsi_vhdl, NULL); if (hwg_err == GRAPH_SUCCESS) scsi_ctlr_nums_add(baseio_pci_vhdl, scsi_vhdl); /* scsi_vhdl will be the final vertex in either the complete path * on success or a partial path on failure; in either case, * unreference that vertex. */ hwgraph_vertex_unref(scsi_vhdl); hwg_err = hwgraph_path_lookup(conn_vhdl, EDGE_LBL_SCSI_CTLR "/1", &scsi_vhdl, NULL); if (hwg_err == GRAPH_SUCCESS) scsi_ctlr_nums_add(baseio_pci_vhdl, scsi_vhdl); /* scsi_vhdl will be the final vertex in either the complete path * on success or a partial path on failure; in either case, * unreference that vertex. */ hwgraph_vertex_unref(scsi_vhdl); }#endif /* PIC_LATER */ pcibr_info->f_att_det_error = error_func; if (error_func) error_slot = error_func; error = error_slot; } /* next func */ 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; } 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_info->f_att_det_error = error_func; if (error_func) error_slot = error_func; error = error_slot; } /* next func */ 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; } return(error);}/* * pcibr_slot_attach * This is a place holder routine to keep track of all the * slot-specific initialization that needs to be done. * This is usually called when we want to initialize a new * PCI card on the bus. */intpcibr_slot_attach(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);#ifdef PIC_LATER timespec_t ts;#endif int error; /* Do not allow a multi-function card to be hot-plug inserted */ if (pcibr_soft->bs_slot[slot].bss_ninfo > 1) { if (sub_errorp) *sub_errorp = EPERM; return(PCI_MULTI_FUNC_ERR); } /* Call the device attach */ error = pcibr_slot_call_device_attach(pcibr_vhdl, slot, drv_flags); if (error) { if (sub_errorp) *sub_errorp = error; if (error == EUNATCH) return(PCI_NO_DRIVER); else return(PCI_SLOT_DRV_ATTACH_ERR); } return(0);}/* * 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; 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_pic(bridge_t *bridge, cfg_p cfg, unsigned *valp){ int rv; picreg_t p_old_enable = (picreg_t)0, p_new_enable; p_old_enable = bridge->p_int_enable_64; p_new_enable = p_old_enable & ~(BRIDGE_IMR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT); bridge->p_int_enable_64 = p_new_enable; if (bridge->p_err_int_view_64 & (BRIDGE_ISR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT)) bridge->p_int_rst_stat_64 = BRIDGE_IRR_MULTI_CLR; if (bridge->p_int_status_64 & (BRIDGE_IRR_PCI_GRP | PIC_PCIX_GRP_CLR)) { bridge->p_int_rst_stat_64 = (BRIDGE_IRR_PCI_GRP_CLR | PIC_PCIX_GRP_CLR); (void) bridge->b_wid_tflush; /* flushbus */ } rv = snia_badaddr_val((void *) cfg, 4, valp); if (bridge->p_err_int_view_64 & (BRIDGE_ISR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT)) { bridge->p_int_rst_stat_64 = BRIDGE_IRR_MULTI_CLR; rv = 1; /* unoccupied slot */ } bridge->p_int_enable_64 = p_old_enable; bridge->b_wid_tflush; /* wait until Bridge PIO complete */ return(rv);}/* * 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_slot(bridge_t *bridge, cfg_p cfg, unsigned *valp){ return(pcibr_probe_slot_pic(bridge, cfg, valp));}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]; bridge_t *bridge = pcibr_soft->bs_base; cfg_p cfgw; int nfunc = slotp->bss_ninfo; int bar; int devio_index; int 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(bridge, 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 */ pciibr_bus_addr_free(pcibr_soft, &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) { pciibr_bus_addr_free(pcibr_soft, &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); DEL(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; /* Clear out shadow info necessary for the external SSRAM workaround */ slotp->bss_ext_ates_active = ATOMIC_INIT(0); slotp->bss_cmd_pointer = 0; slotp->bss_cmd_shadow = 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);}voidpciibr_bus_addr_free(pcibr_soft_t pcibr_soft, 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 = pcibr_soft->bs_busnum; /* * For PIC there are 2 busses per widget and pcibr_soft->bs_busnum * will be 0 or 1. For [X]BRIDGE there is 1 bus per widget and * pcibr_soft->bs_busnum will always be zero. So we add bs_busnum * to what io_brick_map_widget returns to get the bus number. */ if ((bus += io_brick_map_widget(bricktype, widget)) > 0) { return bus; } else { return 0; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -