pcibr_slot.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:48k
- /*
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved.
- */
- #include <linux/types.h>
- #include <linux/slab.h>
- #include <linux/module.h>
- #include <asm/sn/sgi.h>
- #include <asm/sn/sn_cpuid.h>
- #include <asm/sn/addrs.h>
- #include <asm/sn/arch.h>
- #include <asm/sn/iograph.h>
- #include <asm/sn/invent.h>
- #include <asm/sn/hcl.h>
- #include <asm/sn/labelcl.h>
- #include <asm/sn/xtalk/xwidget.h>
- #include <asm/sn/pci/bridge.h>
- #include <asm/sn/pci/pciio.h>
- #include <asm/sn/pci/pcibr.h>
- #include <asm/sn/pci/pcibr_private.h>
- #include <asm/sn/pci/pci_defs.h>
- #include <asm/sn/prio.h>
- #include <asm/sn/xtalk/xbow.h>
- #include <asm/sn/ioc3.h>
- #include <asm/sn/eeprom.h>
- #include <asm/sn/io.h>
- #include <asm/sn/sn_private.h>
- extern pcibr_info_t pcibr_info_get(devfs_handle_t);
- extern int pcibr_widget_to_bus(int);
- extern pcibr_info_t pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);
- extern void pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t);
- extern int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t);
- #if 0
- int pcibr_slot_reset(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
- #endif
- int pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
- int pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
- int pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
- int pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
- int pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
- int pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl,
- pciio_slot_t slot, int drv_flags);
- int pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl,
- pciio_slot_t slot, int drv_flags);
- int pcibr_slot_detach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, int drv_flags);
- int pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
- int pcibr_probe_slot(bridge_t *, cfg_p, unsigned int *);
- void pcibr_device_info_free(devfs_handle_t, pciio_slot_t);
- extern uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned);
- #ifdef LATER
- int pcibr_slot_attach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot,
- int drv_flags, char *l1_msg, int *sub_errorp);
- int pcibr_slot_pwr(devfs_handle_t, pciio_slot_t, int, char *);
- int pcibr_slot_startup(devfs_handle_t, pcibr_slot_req_t);
- int pcibr_slot_shutdown(devfs_handle_t, pcibr_slot_req_t);
- void pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh, int func,
- pcibr_slot_func_info_resp_t funcp);
- int pcibr_slot_info_return(pcibr_soft_t pcibr_soft, pciio_slot_t slot,
- pcibr_slot_info_resp_t respp);
- int pcibr_slot_query(devfs_handle_t, pcibr_slot_req_t);
- #endif /* LATER */
- extern devfs_handle_t baseio_pci_vhdl;
- int scsi_ctlr_nums_add(devfs_handle_t, devfs_handle_t);
- /* For now .... */
- /*
- * PCI Hot-Plug Capability Flags
- */
- #define D_PCI_HOT_PLUG_ATTACH 0x200 /* Driver supports PCI hot-plug attach */
- #define D_PCI_HOT_PLUG_DETACH 0x400 /* Driver supports PCI hot-plug detach */
- /*==========================================================================
- * BRIDGE PCI SLOT RELATED IOCTLs
- */
- #ifdef LATER
- /*
- * pcibr_slot_startup
- * Software start-up the PCI slot.
- */
- int
- pcibr_slot_startup(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp)
- {
- pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl);
- pciio_slot_t slot = reqp->req_slot;
- int error = 0;
- char l1_msg[BRL1_QSIZE+1];
- struct pcibr_slot_up_resp_s tmp_up_resp;
- /* Make sure that we are dealing with a bridge device vertex */
- if (!pcibr_soft) {
- return(PCI_NOT_A_BRIDGE);
- }
- /* Do not allow start-up of a slot in a shoehorn */
- if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) {
- return(PCI_SLOT_IN_SHOEHORN);
- }
-
- /* Check for the valid slot */
- if (!PCIBR_VALID_SLOT(slot))
- return(PCI_NOT_A_SLOT);
- /* Acquire update access to the bus */
- mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO);
- if (pcibr_soft->bs_slot[slot].slot_status & SLOT_STARTUP_CMPLT) {
- error = PCI_SLOT_ALREADY_UP;
- goto startup_unlock;
- }
- error = pcibr_slot_attach(pcibr_vhdl, slot, D_PCI_HOT_PLUG_ATTACH,
- l1_msg, &tmp_up_resp.resp_sub_errno);
- strncpy(tmp_up_resp.resp_l1_msg, l1_msg, L1_QSIZE);
- tmp_up_resp.resp_l1_msg[L1_QSIZE] = '';
- if (COPYOUT(&tmp_up_resp, reqp->req_respp.up, reqp->req_size)) {
- return(EFAULT);
- }
- startup_unlock:
- /* Release the bus lock */
- mrunlock(pcibr_soft->bs_bus_lock);
- return(error);
- }
- /*
- * pcibr_slot_shutdown
- * Software shut-down the PCI slot
- */
- int
- pcibr_slot_shutdown(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp)
- {
- pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl);
- bridge_t *bridge;
- pciio_slot_t slot = reqp->req_slot;
- int error = 0;
- char l1_msg[BRL1_QSIZE+1];
- struct pcibr_slot_down_resp_s tmp_down_resp;
- pciio_slot_t tmp_slot;
- /* Make sure that we are dealing with a bridge device vertex */
- if (!pcibr_soft) {
- return(PCI_NOT_A_BRIDGE);
- }
- bridge = pcibr_soft->bs_base;
- /* Check for valid slot */
- if (!PCIBR_VALID_SLOT(slot))
- return(PCI_NOT_A_SLOT);
- /* Do not allow shut-down of a slot in a shoehorn */
- if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) {
- return(PCI_SLOT_IN_SHOEHORN);
- }
- /* Acquire update access to the bus */
- mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO);
- if ((pcibr_soft->bs_slot[slot].slot_status & SLOT_SHUTDOWN_CMPLT) ||
- ((pcibr_soft->bs_slot[slot].slot_status & SLOT_STATUS_MASK) == 0)) {
- error = PCI_SLOT_ALREADY_DOWN;
- /*
- * RJR - Should we invoke an L1 slot power-down command just in case
- * a previous shut-down failed to power-down the slot?
- */
- goto shutdown_unlock;
- }
- /* Do not allow the last 33 MHz card to be removed */
- if ((bridge->b_wid_control & BRIDGE_CTRL_BUS_SPEED_MASK) ==
- BRIDGE_CTRL_BUS_SPEED_33) {
- for (tmp_slot = pcibr_soft->bs_first_slot;
- tmp_slot <= pcibr_soft->bs_last_slot; tmp_slot++)
- if (tmp_slot != slot)
- if (pcibr_soft->bs_slot[tmp_slot].slot_status & SLOT_POWER_UP) {
- error++;
- break;
- }
- if (!error) {
- error = PCI_EMPTY_33MHZ;
- goto shutdown_unlock;
- }
- }
- error = pcibr_slot_detach(pcibr_vhdl, slot, D_PCI_HOT_PLUG_DETACH,
- l1_msg, &tmp_down_resp.resp_sub_errno);
- strncpy(tmp_down_resp.resp_l1_msg, l1_msg, L1_QSIZE);
- tmp_down_resp.resp_l1_msg[L1_QSIZE] = '';
- if (COPYOUT(&tmp_down_resp, reqp->req_respp.down, reqp->req_size)) {
- return(EFAULT);
- }
- shutdown_unlock:
- /* Release the bus lock */
- mrunlock(pcibr_soft->bs_bus_lock);
- return(error);
- }
- char *pci_space_name[] = {"NONE",
- "ROM",
- "IO",
- "",
- "MEM",
- "MEM32",
- "MEM64",
- "CFG",
- "WIN0",
- "WIN1",
- "WIN2",
- "WIN3",
- "WIN4",
- "WIN5",
- "",
- "BAD"};
- void
- pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh,
- int func,
- pcibr_slot_func_info_resp_t funcp)
- {
- pcibr_info_t pcibr_info = pcibr_infoh[func];
- int win;
- funcp->resp_f_status = 0;
- if (!pcibr_info) {
- return;
- }
- funcp->resp_f_status |= FUNC_IS_VALID;
- sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex);
- if(is_sys_critical_vertex(pcibr_info->f_vertex)) {
- funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL;
- }
- funcp->resp_f_bus = pcibr_info->f_bus;
- funcp->resp_f_slot = pcibr_info->f_slot;
- funcp->resp_f_func = pcibr_info->f_func;
- sprintf(funcp->resp_f_master_name, "%v", pcibr_info->f_master);
- funcp->resp_f_pops = pcibr_info->f_pops;
- funcp->resp_f_efunc = pcibr_info->f_efunc;
- funcp->resp_f_einfo = pcibr_info->f_einfo;
- funcp->resp_f_vendor = pcibr_info->f_vendor;
- funcp->resp_f_device = pcibr_info->f_device;
- for(win = 0 ; win < 6 ; win++) {
- funcp->resp_f_window[win].resp_w_base =
- pcibr_info->f_window[win].w_base;
- funcp->resp_f_window[win].resp_w_size =
- pcibr_info->f_window[win].w_size;
- sprintf(funcp->resp_f_window[win].resp_w_space,
- "%s",
- pci_space_name[pcibr_info->f_window[win].w_space]);
- }
- funcp->resp_f_rbase = pcibr_info->f_rbase;
- funcp->resp_f_rsize = pcibr_info->f_rsize;
- for (win = 0 ; win < 4; win++) {
- funcp->resp_f_ibit[win] = pcibr_info->f_ibit[win];
- }
- funcp->resp_f_att_det_error = pcibr_info->f_att_det_error;
- }
- int
- pcibr_slot_info_return(pcibr_soft_t pcibr_soft,
- pciio_slot_t slot,
- pcibr_slot_info_resp_t respp)
- {
- pcibr_soft_slot_t pss;
- int func;
- bridge_t *bridge = pcibr_soft->bs_base;
- reg_p b_respp;
- pcibr_slot_info_resp_t slotp;
- pcibr_slot_func_info_resp_t funcp;
- slotp = kmem_zalloc(sizeof(*slotp), KM_SLEEP);
- if (slotp == NULL) {
- return(ENOMEM);
- }
- pss = &pcibr_soft->bs_slot[slot];
- slotp->resp_has_host = pss->has_host;
- slotp->resp_host_slot = pss->host_slot;
- sprintf(slotp->resp_slot_conn_name, "%v", pss->slot_conn);
- slotp->resp_slot_status = pss->slot_status;
- slotp->resp_l1_bus_num = io_path_map_widget(pcibr_soft->bs_vhdl);
- if (is_sys_critical_vertex(pss->slot_conn)) {
- slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL;
- }
- slotp->resp_bss_ninfo = pss->bss_ninfo;
- for (func = 0; func < pss->bss_ninfo; func++) {
- funcp = &(slotp->resp_func[func]);
- pcibr_slot_func_info_return(pss->bss_infos, func, funcp);
- }
- sprintf(slotp->resp_bss_devio_bssd_space, "%s",
- pci_space_name[pss->bss_devio.bssd_space]);
- slotp->resp_bss_devio_bssd_base = pss->bss_devio.bssd_base;
- slotp->resp_bss_device = pss->bss_device;
- slotp->resp_bss_pmu_uctr = pss->bss_pmu_uctr;
- slotp->resp_bss_d32_uctr = pss->bss_d32_uctr;
- slotp->resp_bss_d64_uctr = pss->bss_d64_uctr;
- slotp->resp_bss_d64_base = pss->bss_d64_base;
- slotp->resp_bss_d64_flags = pss->bss_d64_flags;
- slotp->resp_bss_d32_base = pss->bss_d32_base;
- slotp->resp_bss_d32_flags = pss->bss_d32_flags;
- slotp->resp_bss_ext_ates_active = pss->bss_ext_ates_active;
- slotp->resp_bss_cmd_pointer = pss->bss_cmd_pointer;
- slotp->resp_bss_cmd_shadow = pss->bss_cmd_shadow;
- slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot];
- slotp->resp_bs_rrb_valid_v = pcibr_soft->bs_rrb_valid[slot +
- PCIBR_RRB_SLOT_VIRTUAL];
- slotp->resp_bs_rrb_res = pcibr_soft->bs_rrb_res[slot];
- if (slot & 1) {
- b_respp = &bridge->b_odd_resp;
- } else {
- b_respp = &bridge->b_even_resp;
- }
- slotp->resp_b_resp = *b_respp;
- slotp->resp_b_wid_control = bridge->b_wid_control;
- slotp->resp_b_int_device = bridge->b_int_device;
- slotp->resp_b_int_enable = bridge->b_int_enable;
- slotp->resp_b_int_host = bridge->b_int_addr[slot].addr;
- if (COPYOUT(slotp, respp, sizeof(*respp))) {
- return(EFAULT);
- }
- kmem_free(slotp, sizeof(*slotp));
- return(0);
- }
- /*
- * pcibr_slot_query
- * Return information about the PCI slot maintained by the infrastructure.
- * Information is requested in the request structure.
- *
- * Information returned in the response structure:
- * Slot hwgraph name
- * Vendor/Device info
- * Base register info
- * Interrupt mapping from device pins to the bridge pins
- * Devio register
- * Software RRB info
- * RRB register info
- * Host/Gues info
- * PCI Bus #,slot #, function #
- * Slot provider hwgraph name
- * Provider Functions
- * Error handler
- * DMA mapping usage counters
- * DMA direct translation info
- * External SSRAM workaround info
- */
- int
- pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp)
- {
- pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl);
- pciio_slot_t slot = reqp->req_slot;
- pciio_slot_t tmp_slot;
- pcibr_slot_info_resp_t respp = reqp->req_respp.query;
- int size = reqp->req_size;
- int error;
- /* Make sure that we are dealing with a bridge device vertex */
- if (!pcibr_soft) {
- return(PCI_NOT_A_BRIDGE);
- }
- /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */
- if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) {
- return(PCI_NOT_A_SLOT);
- }
- /* Do not allow a query of a slot in a shoehorn */
- if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) {
- return(PCI_SLOT_IN_SHOEHORN);
- }
- /* Return information for the requested PCI slot */
- if (slot != PCIIO_SLOT_NONE) {
- if (size < sizeof(*respp)) {
- return(PCI_RESP_AREA_TOO_SMALL);
- }
- /* Acquire read access to the bus */
- mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO);
- error = pcibr_slot_info_return(pcibr_soft, slot, respp);
- /* Release the bus lock */
- mrunlock(pcibr_soft->bs_bus_lock);
- return(error);
- }
- /* Return information for all the slots */
- for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) {
- if (size < sizeof(*respp)) {
- return(PCI_RESP_AREA_TOO_SMALL);
- }
- /* Acquire read access to the bus */
- mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO);
- error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp);
- /* Release the bus lock */
- mrunlock(pcibr_soft->bs_bus_lock);
- if (error) {
- return(error);
- }
- ++respp;
- size -= sizeof(*respp);
- }
- return(error);
- }
- #endif /* LATER */
- /* FIXME: there should be a better way to do this.
- * pcibr_attach() needs PCI_ADDR_SPACE_LIMITS_STORE
- */
- /*
- * PCI_ADDR_SPACE_LIMITS_LOAD
- * Gets the current values of
- * pci io base,
- * pci io last,
- * pci low memory base,
- * pci low memory last,
- * pci high memory base,
- * pci high memory last
- */
- #define PCI_ADDR_SPACE_LIMITS_LOAD()
- pci_io_fb = pcibr_soft->bs_spinfo.pci_io_base;
- pci_io_fl = pcibr_soft->bs_spinfo.pci_io_last;
- pci_lo_fb = pcibr_soft->bs_spinfo.pci_swin_base;
- pci_lo_fl = pcibr_soft->bs_spinfo.pci_swin_last;
- pci_hi_fb = pcibr_soft->bs_spinfo.pci_mem_base;
- pci_hi_fl = pcibr_soft->bs_spinfo.pci_mem_last;
- /*
- * PCI_ADDR_SPACE_LIMITS_STORE
- * Sets the current values of
- * pci io base,
- * pci io last,
- * pci low memory base,
- * pci low memory last,
- * pci high memory base,
- * pci high memory last
- */
- #define PCI_ADDR_SPACE_LIMITS_STORE()
- pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb;
- pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl;
- pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb;
- pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl;
- pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb;
- pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl;
- #define PCI_ADDR_SPACE_LIMITS_PRINT()
- printf("+++++++++++++++++++++++n"
- "IO base 0x%x last 0x%xn"
- "SWIN base 0x%x last 0x%xn"
- "MEM base 0x%x last 0x%xn"
- "+++++++++++++++++++++++n",
- pcibr_soft->bs_spinfo.pci_io_base,
- pcibr_soft->bs_spinfo.pci_io_last,
- pcibr_soft->bs_spinfo.pci_swin_base,
- pcibr_soft->bs_spinfo.pci_swin_last,
- pcibr_soft->bs_spinfo.pci_mem_base,
- pcibr_soft->bs_spinfo.pci_mem_last);
- /*
- * pcibr_slot_info_init
- * Probe for this slot and see if it is populated.
- * If it is populated initialize the generic PCI infrastructural
- * information associated with this particular PCI device.
- */
- int
- pcibr_slot_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;
- bridge_t *bridge;
- cfg_p cfgw;
- unsigned idword;
- unsigned pfail;
- unsigned idwords[8];
- pciio_vendor_id_t vendor;
- pciio_device_id_t device;
- unsigned htype;
- cfg_p wptr;
- int win;
- pciio_space_t space;
- iopaddr_t pci_io_fb, pci_io_fl;
- iopaddr_t pci_lo_fb, pci_lo_fl;
- iopaddr_t pci_hi_fb, pci_hi_fl;
- int nfunc;
- pciio_function_t rfunc;
- int func;
- devfs_handle_t conn_vhdl;
- pcibr_soft_slot_t slotp;
-
- /* Get the basic software information required to proceed */
- pcibr_soft = pcibr_soft_get(pcibr_vhdl);
- if (!pcibr_soft)
- return(EINVAL);
- bridge = pcibr_soft->bs_base;
- if (!PCIBR_VALID_SLOT(slot))
- return(EINVAL);
- /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization
- * is done by the host slot then we are done.
- */
- if (pcibr_soft->bs_slot[slot].has_host) {
- return(0);
- }
- /* Check for a slot with any system critical functions */
- if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot))
- return(EPERM);
- /* Load the current values of allocated PCI address spaces */
- PCI_ADDR_SPACE_LIMITS_LOAD();
-
- /* Try to read the device-id/vendor-id from the config space */
- cfgw = bridge->b_type0_cfg_dev[slot].l;
- if (pcibr_probe_slot(bridge, cfgw, &idword))
- return(ENODEV);
- slotp = &pcibr_soft->bs_slot[slot];
- slotp->slot_status |= SLOT_POWER_UP;
- vendor = 0xFFFF & idword;
- /* If the vendor id is not valid then the slot is not populated
- * and we are done.
- */
- if (vendor == 0xFFFF)
- return(ENODEV);
-
- device = 0xFFFF & (idword >> 16);
- htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1);
- nfunc = 1;
- rfunc = PCIIO_FUNC_NONE;
- pfail = 0;
- /* NOTE: if a card claims to be multifunction
- * but only responds to config space 0, treat
- * it as a unifunction card.
- */
- if (htype & 0x80) { /* MULTIFUNCTION */
- for (func = 1; func < 8; ++func) {
- cfgw = bridge->b_type0_cfg_dev[slot].f[func].l;
- if (pcibr_probe_slot(bridge, cfgw, &idwords[func])) {
- pfail |= 1 << func;
- continue;
- }
- vendor = 0xFFFF & idwords[func];
- if (vendor == 0xFFFF) {
- pfail |= 1 << func;
- continue;
- }
- nfunc = func + 1;
- rfunc = 0;
- }
- cfgw = bridge->b_type0_cfg_dev[slot].l;
- }
- NEWA(pcibr_infoh, nfunc);
-
- pcibr_soft->bs_slot[slot].bss_ninfo = nfunc;
- pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh;
- for (func = 0; func < nfunc; ++func) {
- unsigned cmd_reg;
-
- if (func) {
- if (pfail & (1 << func))
- continue;
-
- idword = idwords[func];
- cfgw = bridge->b_type0_cfg_dev[slot].f[func].l;
-
- device = 0xFFFF & (idword >> 16);
- htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1);
- rfunc = func;
- }
- htype &= 0x7f;
- if (htype != 0x00) {
- printk(KERN_WARNING "%s pcibr: pci slot %d func %d has strange header type 0x%xn",
- pcibr_soft->bs_name, slot, func, htype);
- continue;
- }
- #if DEBUG && ATTACH_DEBUG
- printk(KERN_NOTICE
- "%s pcibr: pci slot %d func %d: vendor 0x%x device 0x%x",
- pcibr_soft->bs_name, slot, func, vendor, device);
- #endif
- pcibr_info = pcibr_device_info_new
- (pcibr_soft, slot, rfunc, vendor, device);
- conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c);
- if (func == 0)
- slotp->slot_conn = conn_vhdl;
- #ifdef SN1_LITTLE_ENDIAN
- cmd_reg = cfgw[(PCI_CFG_COMMAND ^ 4) / 4];
- #else
- cmd_reg = cfgw[PCI_CFG_COMMAND / 4];
- #endif
-
- wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4;
- for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) {
- iopaddr_t base, mask, code;
- size_t size;
- /*
- * GET THE BASE & SIZE OF THIS WINDOW:
- *
- * The low two or four bits of the BASE register
- * determines which address space we are in; the
- * rest is a base address. BASE registers
- * determine windows that are power-of-two sized
- * and naturally aligned, so we can get the size
- * of a window by writing all-ones to the
- * register, reading it back, and seeing which
- * bits are used for decode; the least
- * significant nonzero bit is also the size of
- * the window.
- *
- * WARNING: someone may already have allocated
- * some PCI space to this window, and in fact
- * PIO may be in process at this very moment
- * from another processor (or even from this
- * one, if we get interrupted)! So, if the BASE
- * already has a nonzero address, be generous
- * and use the LSBit of that address as the
- * size; this could overstate the window size.
- * Usually, when one card is set up, all are set
- * up; so, since we don't bitch about
- * overlapping windows, we are ok.
- *
- * UNFORTUNATELY, some cards do not clear their
- * BASE registers on reset. I have two heuristics
- * that can detect such cards: first, if the
- * decode enable is turned off for the space
- * that the window uses, we can disregard the
- * initial value. second, if the address is
- * outside the range that we use, we can disregard
- * it as well.
- *
- * This is looking very PCI generic. Except for
- * knowing how many slots and where their config
- * spaces are, this window loop and the next one
- * could probably be shared with other PCI host
- * adapters. It would be interesting to see if
- * this could be pushed up into pciio, when we
- * start supporting more PCI providers.
- */
- #ifdef SN1_LITTLE_ENDIAN
- base = wptr[((win*4)^4)/4];
- #else
- base = wptr[win];
- #endif
- if (base & PCI_BA_IO_SPACE) {
- /* BASE is in I/O space. */
- space = PCIIO_SPACE_IO;
- mask = -4;
- code = base & 3;
- base = base & mask;
- if (base == 0) {
- ; /* not assigned */
- } else if (!(cmd_reg & PCI_CMD_IO_SPACE)) {
- base = 0; /* decode not enabled */
- }
- } else {
- /* BASE is in MEM space. */
- space = PCIIO_SPACE_MEM;
- mask = -16;
- code = base & PCI_BA_MEM_LOCATION; /* extract BAR type */
- base = base & mask;
- if (base == 0) {
- ; /* not assigned */
- } else if (!(cmd_reg & PCI_CMD_MEM_SPACE)) {
- base = 0; /* decode not enabled */
- } else if (base & 0xC0000000) {
- base = 0; /* outside permissable range */
- } else if ((code == PCI_BA_MEM_64BIT) &&
- #ifdef SN1_LITTLE_ENDIAN
- (wptr[(((win + 1)*4)^4)/4] != 0)) {
- #else
- (wptr[win + 1] != 0)) {
- #endif /* LITTLE_ENDIAN */
- base = 0; /* outside permissable range */
- }
- }
- if (base != 0) { /* estimate size */
- size = base & -base;
- } else { /* calculate size */
- #ifdef SN1_LITTLE_ENDIAN
- wptr[((win*4)^4)/4] = ~0; /* turn on all bits */
- size = wptr[((win*4)^4)/4]; /* get stored bits */
- #else
- wptr[win] = ~0; /* turn on all bits */
- size = wptr[win]; /* get stored bits */
- #endif /* LITTLE_ENDIAN */
- size &= mask; /* keep addr */
- size &= -size; /* keep lsbit */
- if (size == 0)
- continue;
- }
- pcibr_info->f_window[win].w_space = space;
- pcibr_info->f_window[win].w_base = base;
- pcibr_info->f_window[win].w_size = size;
- /*
- * If this window already has PCI space
- * allocated for it, "subtract" that space from
- * our running freeblocks. Don't worry about
- * overlaps in existing allocated windows; we
- * may be overstating their sizes anyway.
- */
- if (base && size) {
- if (space == PCIIO_SPACE_IO) {
- pcibr_freeblock_sub(&pci_io_fb,
- &pci_io_fl,
- base, size);
- } else {
- pcibr_freeblock_sub(&pci_lo_fb,
- &pci_lo_fl,
- base, size);
- pcibr_freeblock_sub(&pci_hi_fb,
- &pci_hi_fl,
- base, size);
- }
- }
- #if defined(IOC3_VENDOR_ID_NUM) && defined(IOC3_DEVICE_ID_NUM)
- /*
- * IOC3 BASE_ADDR* BUG WORKAROUND
- *
-
- * If we write to BASE1 on the IOC3, the
- * data in BASE0 is replaced. The
- * original workaround was to remember
- * the value of BASE0 and restore it
- * when we ran off the end of the BASE
- * registers; however, a later
- * workaround was added (I think it was
- * rev 1.44) to avoid setting up
- * anything but BASE0, with the comment
- * that writing all ones to BASE1 set
- * the enable-parity-error test feature
- * in IOC3's SCR bit 14.
- *
- * So, unless we defer doing any PCI
- * space allocation until drivers
- * attach, and set up a way for drivers
- * (the IOC3 in paricular) to tell us
- * generically to keep our hands off
- * BASE registers, we gotta "know" about
- * the IOC3 here.
- *
- * Too bad the PCI folks didn't reserve the
- * all-zero value for 'no BASE here' (it is a
- * valid code for an uninitialized BASE in
- * 32-bit PCI memory space).
- */
-
- if ((vendor == IOC3_VENDOR_ID_NUM) &&
- (device == IOC3_DEVICE_ID_NUM))
- break;
- #endif
- if (code == PCI_BA_MEM_64BIT) {
- win++; /* skip upper half */
- #ifdef SN1_LITTLE_ENDIAN
- wptr[((win*4)^4)/4] = 0; /* which must be zero */
- #else
- wptr[win] = 0; /* which must be zero */
- #endif /* LITTLE_ENDIAN */
- }
- } /* next win */
- } /* next func */
- /* Store back the values for allocated PCI address spaces */
- PCI_ADDR_SPACE_LIMITS_STORE();
- return(0);
- }
- /*
- * pcibr_slot_info_free
- * Remove all the PCI infrastructural information associated
- * with a particular PCI device.
- */
- int
- pcibr_slot_info_free(devfs_handle_t pcibr_vhdl,
- 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.
- */
- int
- pcibr_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 promn",
- 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 %dn",
- 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%xn", &(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 pcibrn",
- slot, func, win, space, base, base + size - 1);
- else
- printk("pcibr: slot %d func %d window %d, unable to alloc 0x%x in 0x%pn",
- 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.
- */
- int
- pcibr_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%lxn", 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.
- */
- int
- pcibr_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.
- */
- int
- pcibr_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);
- if (pcibr_soft->bs_slot[slot].has_host) {
- return(EPERM);
- }
-
- xconn_vhdl = pcibr_soft->bs_conn;
- aa = async_attach_get_info(xconn_vhdl);
- 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;
- #ifdef LATER
- /*
- * Activate if and when we support cdl.
- */
- if (aa)
- async_attach_add_info(conn_vhdl, aa);
- #endif /* LATER */
- error_func = pciio_device_attach(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))
- pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT;
- } else {
- 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.
- */
- int
- pcibr_slot_call_device_detach(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;
- int func;
- devfs_handle_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 || !PCIBR_VALID_SLOT(slot))
- return(EINVAL);
- if (pcibr_soft->bs_slot[slot].has_host)
- return(EPERM);
- /* Make sure that we do not detach a system critical function vertex */
- if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot))
- 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;
- 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 */
- pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
- if (error) {
- if ((error != ENODEV) && (error != EUNATCH))
- 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_SHUTDOWN_CMPLT;
- }
-
- return(error);
- }
- #ifdef LATER
- /*
- * 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.
- */
- int
- pcibr_slot_attach(devfs_handle_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);
- timespec_t ts;
- int error;
- if (!(pcibr_soft->bs_slot[slot].slot_status & SLOT_POWER_UP)) {
- /* Power-up the slot */
- error = pcibr_slot_pwr(pcibr_vhdl, slot, L1_REQ_PCI_UP, l1_msg);
- if (error) {
- if (sub_errorp)
- *sub_errorp = error;
- return(PCI_L1_ERR);
- } else {
- pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_POWER_MASK;
- pcibr_soft->bs_slot[slot].slot_status |= SLOT_POWER_UP;
- }
- #ifdef LATER
- /*
- * Allow cards like the Alteon Gigabit Ethernet Adapter to complete
- * on-card initialization following the slot reset
- */
- ts.tv_sec = 0; /* 0 secs */
- ts.tv_nsec = 500 * (1000 * 1000); /* 500 msecs */
- nano_delay(&ts);
- #else
- #endif
- #if 0
- /* Reset the slot */
- error = pcibr_slot_reset(pcibr_vhdl, slot)
- if (error) {
- if (sub_errorp)
- *sub_errorp = error;
- return(PCI_SLOT_RESET_ERR);
- }
- #endif
- /* Find out what is out there */
- error = pcibr_slot_info_init(pcibr_vhdl, slot);
- if (error) {
- if (sub_errorp)
- *sub_errorp = error;
- return(PCI_SLOT_INFO_INIT_ERR);
- }
- /* Set up the address space for this slot in the PCI land */
- error = pcibr_slot_addr_space_init(pcibr_vhdl, slot);
- if (error) {
- if (sub_errorp)
- *sub_errorp = error;
- return(PCI_SLOT_ADDR_INIT_ERR);
- }
- /* Setup the device register */
- error = pcibr_slot_device_init(pcibr_vhdl, slot);
- if (error) {
- if (sub_errorp)
- *sub_errorp = error;
- return(PCI_SLOT_DEV_INIT_ERR);
- }
- /* Setup host/guest relations */
- error = pcibr_slot_guest_info_init(pcibr_vhdl, slot);
- if (error) {
- if (sub_errorp)
- *sub_errorp = error;
- return(PCI_SLOT_GUEST_INIT_ERR);
- }
- /* Initial RRB management */
- error = pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot);
- if (error) {
- if (sub_errorp)
- *sub_errorp = error;
- return(PCI_SLOT_RRB_ALLOC_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);
- }
- #endif /* LATER */
- /*
- * pcibr_slot_detach
- * This is a place holder routine to keep track of all the
- * slot-specific freeing that needs to be done.
- */
- int
- pcibr_slot_detach(devfs_handle_t pcibr_vhdl,
- pciio_slot_t slot,
- int drv_flags)
- {
- int error;
-
- /* Call the device detach function */
- error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags));
- return (error);
- }
- /*
- * pcibr_is_slot_sys_critical
- * Check slot for any functions that are system critical.
- * Return 1 if any are system critical or 0 otherwise.
- *
- * This function will always return 0 when called by
- * pcibr_attach() because the system critical vertices
- * have not yet been set in the hwgraph.
- */
- int
- pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl,
- pciio_slot_t slot)
- {
- pcibr_soft_t pcibr_soft;
- pcibr_info_h pcibr_infoh;
- pcibr_info_t pcibr_info;
- devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE;
- int nfunc;
- int func;
- boolean_t is_sys_critical_vertex(devfs_handle_t);
- pcibr_soft = pcibr_soft_get(pcibr_vhdl);
- if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
- return(0);
- 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;
- if (is_sys_critical_vertex(conn_vhdl)) {
- #if defined(SUPPORT_PRINTING_V_FORMAT)
- printk(KERN_WARNING "%v is a system critical device vertexn", conn_vhdl);
- #else
- printk(KERN_WARNING "%p is a system critical device vertexn", (void *)conn_vhdl);
- #endif
- return(1);
- }
- }
- return(0);
- }
- /*
- * pcibr_probe_slot: read a config space word
- * while trapping any errors; reutrn zero if
- * all went OK, or nonzero if there was an error.
- * The value read, if any, is passed back
- * through the valp parameter.
- */
- int
- pcibr_probe_slot(bridge_t *bridge,
- cfg_p cfg,
- unsigned *valp)
- {
- int rv;
- bridgereg_t old_enable, new_enable;
- int badaddr_val(volatile void *, int, volatile void *);
- old_enable = bridge->b_int_enable;
- new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
- bridge->b_int_enable = new_enable;
- /*
- * The xbridge doesn't clear b_err_int_view unless
- * multi-err is cleared...
- */
- if (is_xbridge(bridge))
- if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) {
- bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR;
- }
- if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) {
- bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR;
- (void) bridge->b_wid_tflush; /* flushbus */
- }
- rv = badaddr_val((void *) cfg, 4, valp);
- /*
- * The xbridge doesn't set master timeout in b_int_status
- * here. Fortunately it's in error_interrupt_view.
- */
- if (is_xbridge(bridge))
- if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) {
- bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR;
- rv = 1; /* unoccupied slot */
- }
- bridge->b_int_enable = old_enable;
- bridge->b_wid_tflush; /* wait until Bridge PIO complete */
- return rv;
- }
- void
- pcibr_device_info_free(devfs_handle_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];
- int nfunc = slotp->bss_ninfo;
- int bar;
- int devio_index;
- int s;
- for (func = 0; func < nfunc; func++) {
- pcibr_info = slotp->bss_infos[func];
- if (!pcibr_info)
- continue;
- s = pcibr_lock(pcibr_soft);
- for (bar = 0; bar < PCI_CFG_BASE_ADDRS; bar++) {
- if (pcibr_info->f_window[bar].w_space == PCIIO_SPACE_NONE)
- continue;
- /* 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;
- }
- }
- 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;
- }