static int vtpci_attach(device_t dev) { struct vtpci_softc *sc; device_t child; int rid; sc = device_get_softc(dev); sc->vtpci_dev = dev; pci_enable_busmaster(dev); rid = PCIR_BAR(0); sc->vtpci_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); if (sc->vtpci_res == NULL) { device_printf(dev, "cannot map I/O space\n"); return (ENXIO); } if (pci_find_cap(dev, PCIY_MSI, NULL) != 0) sc->vtpci_flags |= VTPCI_FLAG_NO_MSI; if (pci_find_cap(dev, PCIY_MSIX, NULL) == 0) { rid = PCIR_BAR(1); sc->vtpci_msix_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); } if (sc->vtpci_msix_res == NULL) sc->vtpci_flags |= VTPCI_FLAG_NO_MSIX; vtpci_reset(sc); /* Tell the host we've noticed this device. */ vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK); if ((child = device_add_child(dev, NULL, -1)) == NULL) { device_printf(dev, "cannot create child device\n"); vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_FAILED); vtpci_detach(dev); return (ENOMEM); } sc->vtpci_child_dev = child; vtpci_probe_and_attach_child(sc); return (0); }
static void pci_scan_ext_caps(struct pci_dev *d) { byte been_there[0x1000]; int where = 0x100; if (!pci_find_cap(d, PCI_CAP_ID_EXP, PCI_CAP_NORMAL)) return; memset(been_there, 0, 0x1000); do { u32 header; int id; header = pci_read_long(d, where); if (!header || header == 0xffffffff) break; id = header & 0xffff; if (been_there[where]++) break; pci_add_cap(d, where, id, PCI_CAP_EXTENDED); where = header >> 20; } while (where); }
void list_errors(int fd, struct pci_conf *p) { uint32_t mask, severity; uint16_t sta, aer; uint8_t pcie; /* First check for standard PCI errors. */ sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); print_bits("PCI errors", pci_status, sta & PCI_ERRORS); /* See if this is a PCI-express device. */ pcie = pci_find_cap(fd, p, PCIY_EXPRESS); if (pcie == 0) return; /* Check for PCI-e errors. */ sta = read_config(fd, &p->pc_sel, pcie + PCIR_EXPRESS_DEVICE_STA, 2); print_bits("PCI-e errors", pcie_device_status, sta & PCIE_ERRORS); /* See if this device supports AER. */ aer = pcie_find_cap(fd, p, PCIZ_AER); if (aer == 0) return; /* Check for uncorrected errors. */ mask = read_config(fd, &p->pc_sel, aer + PCIR_AER_UC_STATUS, 4); severity = read_config(fd, &p->pc_sel, aer + PCIR_AER_UC_SEVERITY, 4); print_bits("Fatal", aer_uc, mask & severity); print_bits("Non-fatal", aer_uc, mask & ~severity); /* Check for corrected errors. */ mask = read_config(fd, &p->pc_sel, aer + PCIR_AER_COR_STATUS, 4); print_bits("Corrected", aer_cor, mask); }
static int vga_pci_find_cap(device_t dev, device_t child, int capability, int *capreg) { return (pci_find_cap(dev, capability, capreg)); }
/** * Return true if the bridge device @p dev is attached via PCIe, * false otherwise. * * @param dev The bhndb bridge device */ static bool bhndb_is_pcie_attached(device_t dev) { int reg; if (pci_find_cap(device_get_parent(dev), PCIY_EXPRESS, ®) == 0) return (true); return (false); }
/* * Write the PCI Express capabilities */ int32_t e1000_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) { device_t dev = ((struct e1000_osdep *)hw->back)->dev; u32 offset; pci_find_cap(dev, PCIY_EXPRESS, &offset); pci_write_config(dev, offset + reg, *value, 2); return (E1000_SUCCESS); }
int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask) { device_t root; int pos; u32 lnkcap = 0, lnkcap2 = 0; *mask = 0; if (!drm_device_is_pcie(dev)) return -EINVAL; root = device_get_parent( /* pcib */ device_get_parent( /* `-- pci */ device_get_parent( /* `-- vgapci */ dev->device))); /* `-- drmn */ pos = 0; pci_find_cap(root, PCIY_EXPRESS, &pos); if (!pos) return -EINVAL; /* we've been informed via and serverworks don't make the cut */ if (pci_get_vendor(root) == PCI_VENDOR_ID_VIA || pci_get_vendor(root) == PCI_VENDOR_ID_SERVERWORKS) return -EINVAL; lnkcap = pci_read_config(root, pos + PCIER_LINK_CAP, 4); lnkcap2 = pci_read_config(root, pos + PCIER_LINK_CAP2, 4); lnkcap &= PCIEM_LINK_CAP_MAX_SPEED; lnkcap2 &= 0xfe; #define PCI_EXP_LNKCAP2_SLS_2_5GB 0x02 /* Supported Link Speed 2.5GT/s */ #define PCI_EXP_LNKCAP2_SLS_5_0GB 0x04 /* Supported Link Speed 5.0GT/s */ #define PCI_EXP_LNKCAP2_SLS_8_0GB 0x08 /* Supported Link Speed 8.0GT/s */ if (lnkcap2) { /* PCIE GEN 3.0 */ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB) *mask |= DRM_PCIE_SPEED_25; if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB) *mask |= DRM_PCIE_SPEED_50; if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB) *mask |= DRM_PCIE_SPEED_80; } else { if (lnkcap & 1) *mask |= DRM_PCIE_SPEED_25; if (lnkcap & 2) *mask |= DRM_PCIE_SPEED_50; } DRM_INFO("probing gen 2 caps for device %x:%x = %x/%x\n", pci_get_vendor(root), pci_get_device(root), lnkcap, lnkcap2); return 0; }
/*===========================================================================* * atl2_get_vpd_hwaddr * *===========================================================================*/ static int atl2_get_vpd_hwaddr(void) { /* Read the MAC address from the EEPROM, using the Vital Product Data * register interface. */ u32_t key, val; int i, n, found[2]; /* No idea, copied from FreeBSD which copied it from Linux. */ val = ATL2_READ_U32(ATL2_SPICTL_REG); if (val & ATL2_SPICTL_VPD_EN) { val &= ~ATL2_SPICTL_VPD_EN; ATL2_WRITE_U32(ATL2_SPICTL_REG, val); } /* Is VPD supported? */ #ifdef PCI_CAP_VPD /* FIXME: just a guess at the future name */ if (!pci_find_cap(state.devind, PCI_CAP_VPD, &n)) return FALSE; #endif /* Read out the set of key/value pairs. Look for the two parts that * make up the MAC address. */ found[0] = found[1] = FALSE; for (i = 0; i < ATL2_VPD_NREGS; i += 2) { if (!atl2_read_vpd(i, &key)) break; if ((key & ATL2_VPD_SIG_MASK) != ATL2_VPD_SIG) break; key >>= ATL2_VPD_REG_SHIFT; if (key != ATL2_HWADDR0_REG && key != ATL2_HWADDR1_REG) continue; if (!atl2_read_vpd(i + 1, &val)) break; n = (key == ATL2_HWADDR1_REG); state.hwaddr[n] = val; found[n] = TRUE; if (found[1 - n]) break; } return found[0] && found[1]; }
static int pci_hostb_attach(device_t dev) { bus_generic_probe(dev); /* * If AGP capabilities are present on this device, then create * an AGP child. */ if (pci_find_cap(dev, PCIY_AGP, NULL) == 0) device_add_child(dev, "agp", -1); bus_generic_attach(dev); return (0); }
static int bhndb_pci_attach(device_t dev) { struct bhndb_pci_softc *sc; int error, reg; sc = device_get_softc(dev); sc->dev = dev; /* Enable PCI bus mastering */ pci_enable_busmaster(device_get_parent(dev)); /* Determine our bridge device class */ sc->pci_devclass = BHND_DEVCLASS_PCI; if (pci_find_cap(device_get_parent(dev), PCIY_EXPRESS, ®) == 0) sc->pci_devclass = BHND_DEVCLASS_PCIE; /* Determine the basic set of applicable quirks. This will be updated * in bhndb_pci_init_full_config() once the PCI device core has * been enumerated. */ sc->quirks = bhndb_pci_discover_quirks(sc, NULL); /* Using the discovered quirks, apply any WARs required for basic * register access. */ if ((error = bhndb_pci_wars_register_access(sc))) return (error); /* Use siba(4)-compatible regwin handling until we know * what kind of bus is attached */ sc->set_regwin = bhndb_pci_compat_setregwin; /* Perform full bridge attach. This should call back into our * bhndb_pci_init_full_config() implementation once the bridged * bhnd(4) bus has been enumerated, but before any devices have been * probed or attached. */ if ((error = bhndb_attach(dev, sc->pci_devclass))) return (error); /* If supported, switch to the faster regwin handling */ if (sc->bhndb.chipid.chip_type != BHND_CHIPTYPE_SIBA) { atomic_store_rel_ptr((volatile void *) &sc->set_regwin, (uintptr_t) &bhndb_pci_fast_setregwin); } return (0); }
void pci_msi_set_vector(u16 bdf, unsigned int vector) { int cap = pci_find_cap(bdf, PCI_CAP_MSI); u16 ctl, data; if (cap < 0) return; pci_write_config(bdf, cap + 0x04, 0xfee00000 | (cpu_id() << 12), 4); ctl = pci_read_config(bdf, cap + 0x02, 2); if (ctl & (1 << 7)) { pci_write_config(bdf, cap + 0x08, 0, 4); data = cap + 0x0c; } else data = cap + 0x08; pci_write_config(bdf, data, vector, 2); pci_write_config(bdf, cap + 0x02, 0x0001, 2); }
void pci_msix_set_vector(u16 bdf, unsigned int vector, u32 index) { int cap = pci_find_cap(bdf, PCI_CAP_MSIX); unsigned int bar; u64 msix_table = 0; u32 addr; u16 ctrl; u32 table; if (cap < 0) return; ctrl = pci_read_config(bdf, cap + 2, 2); /* bounds check */ if (index > (ctrl & 0x3ff)) return; table = pci_read_config(bdf, cap + 4, 4); bar = (table & 7) * 4 + PCI_CFG_BAR; addr = pci_read_config(bdf, bar, 4); if ((addr & 6) == PCI_BAR_64BIT) { msix_table = pci_read_config(bdf, bar + 4, 4); msix_table <<= 32; } msix_table |= addr & ~0xf; msix_table += table & ~7; /* enable and mask */ ctrl |= (MSIX_CTRL_ENABLE | MSIX_CTRL_FMASK); pci_write_config(bdf, cap + 2, ctrl, 2); msix_table += 16 * index; mmio_write32((u32 *)msix_table, 0xfee00000 | cpu_id() << 12); mmio_write32((u32 *)(msix_table + 4), 0); mmio_write32((u32 *)(msix_table + 8), vector); mmio_write32((u32 *)(msix_table + 12), 0); /* enable and unmask */ ctrl &= ~MSIX_CTRL_FMASK; pci_write_config(bdf, cap + 2, ctrl, 2); }
/* Returns 1 if AGP or 0 if not. */ static int drm_device_find_capability(struct drm_device *dev, int cap) { #if __FreeBSD_version >= 602102 return (pci_find_cap(dev->device, cap, NULL) == 0); #else /* Code taken from agp.c. IWBNI that was a public interface. */ u_int32_t status; u_int8_t ptr, next; /* * Check the CAP_LIST bit of the PCI status register first. */ status = pci_read_config(dev->device, PCIR_STATUS, 2); if (!(status & 0x10)) return 0; /* * Traverse the capabilities list. */ for (ptr = pci_read_config(dev->device, AGP_CAPPTR, 1); ptr != 0; ptr = next) { u_int32_t capid = pci_read_config(dev->device, ptr, 4); next = AGP_CAPID_GET_NEXT_PTR(capid); /* * If this capability entry ID is cap, then we are done. */ if (AGP_CAPID_GET_CAP_ID(capid) == cap) return 1; } return 0; #endif }
static int rtwn_pci_attach(device_t dev) { const struct rtwn_pci_ident *ident; struct rtwn_pci_softc *pc = device_get_softc(dev); struct rtwn_softc *sc = &pc->pc_sc; struct ieee80211com *ic = &sc->sc_ic; uint32_t lcsr; int cap_off, i, error, rid; ident = rtwn_pci_probe_sub(dev); if (ident == NULL) return (ENXIO); /* * Get the offset of the PCI Express Capability Structure in PCI * Configuration Space. */ error = pci_find_cap(dev, PCIY_EXPRESS, &cap_off); if (error != 0) { device_printf(dev, "PCIe capability structure not found!\n"); return (error); } /* Enable bus-mastering. */ pci_enable_busmaster(dev); rid = PCIR_BAR(2); pc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (pc->mem == NULL) { device_printf(dev, "can't map mem space\n"); return (ENOMEM); } pc->pc_st = rman_get_bustag(pc->mem); pc->pc_sh = rman_get_bushandle(pc->mem); /* Install interrupt handler. */ rid = 1; if (pci_alloc_msi(dev, &rid) == 0) rid = 1; else rid = 0; pc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | (rid != 0 ? 0 : RF_SHAREABLE)); if (pc->irq == NULL) { device_printf(dev, "can't map interrupt\n"); goto detach; } /* Disable PCIe Active State Power Management (ASPM). */ lcsr = pci_read_config(dev, cap_off + PCIER_LINK_CTL, 4); lcsr &= ~PCIEM_LINK_CTL_ASPMC; pci_write_config(dev, cap_off + PCIER_LINK_CTL, lcsr, 4); sc->sc_dev = dev; ic->ic_name = device_get_nameunit(dev); /* Need to be initialized early. */ rtwn_sysctlattach(sc); mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF); rtwn_pci_attach_methods(sc); rtwn_pci_attach_private(pc, ident->chip); /* Allocate Tx/Rx buffers. */ error = rtwn_pci_alloc_rx_list(sc); if (error != 0) { device_printf(dev, "could not allocate Rx buffers, error %d\n", error); goto detach; } for (i = 0; i < RTWN_PCI_NTXQUEUES; i++) { error = rtwn_pci_alloc_tx_list(sc, i); if (error != 0) { device_printf(dev, "could not allocate Tx buffers, error %d\n", error); goto detach; } } /* Generic attach. */ error = rtwn_attach(sc); if (error != 0) goto detach; /* * Hook our interrupt after all initialization is complete. */ error = bus_setup_intr(dev, pc->irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, rtwn_pci_intr, sc, &pc->pc_ih); if (error != 0) { device_printf(dev, "can't establish interrupt, error %d\n", error); goto detach; } return (0); detach: rtwn_pci_detach(dev); /* failure */ return (ENXIO); }
static int hwloc_look_pci(struct hwloc_backend *backend) { struct hwloc_topology *topology = backend->topology; struct hwloc_obj *first_obj = NULL, *last_obj = NULL; #ifdef HWLOC_HAVE_LIBPCIACCESS int ret; struct pci_device_iterator *iter; struct pci_device *pcidev; #else /* HWLOC_HAVE_PCIUTILS */ struct pci_access *pciaccess; struct pci_dev *pcidev; #endif if (!(hwloc_topology_get_flags(topology) & (HWLOC_TOPOLOGY_FLAG_IO_DEVICES|HWLOC_TOPOLOGY_FLAG_WHOLE_IO))) return 0; if (hwloc_get_next_pcidev(topology, NULL)) { hwloc_debug("%s", "PCI objects already added, ignoring pci backend.\n"); return 0; } if (!hwloc_topology_is_thissystem(topology)) { hwloc_debug("%s", "\nno PCI detection (not thissystem)\n"); return 0; } hwloc_debug("%s", "\nScanning PCI buses...\n"); /* initialize PCI scanning */ #ifdef HWLOC_HAVE_LIBPCIACCESS ret = pci_system_init(); if (ret) { hwloc_debug("%s", "Can not initialize libpciaccess\n"); return -1; } iter = pci_slot_match_iterator_create(NULL); #else /* HWLOC_HAVE_PCIUTILS */ pciaccess = pci_alloc(); pciaccess->error = hwloc_pci_error; pciaccess->warning = hwloc_pci_warning; if (setjmp(err_buf)) { pci_cleanup(pciaccess); return -1; } pci_init(pciaccess); pci_scan_bus(pciaccess); #endif /* iterate over devices */ #ifdef HWLOC_HAVE_LIBPCIACCESS for (pcidev = pci_device_next(iter); pcidev; pcidev = pci_device_next(iter)) #else /* HWLOC_HAVE_PCIUTILS */ for (pcidev = pciaccess->devices; pcidev; pcidev = pcidev->next) #endif { const char *vendorname, *devicename, *fullname; unsigned char config_space_cache[CONFIG_SPACE_CACHESIZE]; struct hwloc_obj *obj; unsigned os_index; unsigned domain; unsigned device_class; unsigned short tmp16; char name[128]; unsigned offset; #ifdef HWLOC_HAVE_PCI_FIND_CAP struct pci_cap *cap; #endif /* initialize the config space in case we fail to read it (missing permissions, etc). */ memset(config_space_cache, 0xff, CONFIG_SPACE_CACHESIZE); #ifdef HWLOC_HAVE_LIBPCIACCESS pci_device_probe(pcidev); pci_device_cfg_read(pcidev, config_space_cache, 0, CONFIG_SPACE_CACHESIZE, NULL); #else /* HWLOC_HAVE_PCIUTILS */ pci_read_block(pcidev, 0, config_space_cache, CONFIG_SPACE_CACHESIZE); /* doesn't even tell how much it actually reads */ #endif /* try to read the domain */ #if (defined HWLOC_HAVE_LIBPCIACCESS) || (defined HWLOC_HAVE_PCIDEV_DOMAIN) domain = pcidev->domain; #else domain = 0; /* default domain number */ #endif /* try to read the device_class */ #ifdef HWLOC_HAVE_LIBPCIACCESS device_class = pcidev->device_class >> 8; #else /* HWLOC_HAVE_PCIUTILS */ #ifdef HWLOC_HAVE_PCIDEV_DEVICE_CLASS device_class = pcidev->device_class; #else device_class = config_space_cache[PCI_CLASS_DEVICE] | (config_space_cache[PCI_CLASS_DEVICE+1] << 8); #endif #endif /* might be useful for debugging (note that domain might be truncated) */ os_index = (domain << 20) + (pcidev->bus << 12) + (pcidev->dev << 4) + pcidev->func; obj = hwloc_alloc_setup_object(HWLOC_OBJ_PCI_DEVICE, os_index); obj->attr->pcidev.domain = domain; obj->attr->pcidev.bus = pcidev->bus; obj->attr->pcidev.dev = pcidev->dev; obj->attr->pcidev.func = pcidev->func; obj->attr->pcidev.vendor_id = pcidev->vendor_id; obj->attr->pcidev.device_id = pcidev->device_id; obj->attr->pcidev.class_id = device_class; obj->attr->pcidev.revision = config_space_cache[PCI_REVISION_ID]; obj->attr->pcidev.linkspeed = 0; /* unknown */ #ifdef HWLOC_HAVE_PCI_FIND_CAP cap = pci_find_cap(pcidev, PCI_CAP_ID_EXP, PCI_CAP_NORMAL); offset = cap ? cap->addr : 0; #else offset = hwloc_pci_find_cap(config_space_cache, PCI_CAP_ID_EXP); #endif /* HWLOC_HAVE_PCI_FIND_CAP */ if (0xffff == pcidev->vendor_id && 0xffff == pcidev->device_id) { /* SR-IOV puts ffff:ffff in Virtual Function config space. * The actual VF device ID is stored at a special (dynamic) location in the Physical Function config space. * VF and PF have the same vendor ID. * * libpciaccess just returns ffff:ffff, needs to be fixed. * linuxpci is OK because sysfs files are already fixed the kernel. * pciutils is OK when it uses those Linux sysfs files. * * Reading these files is an easy way to work around the libpciaccess issue on Linux, * but we have no way to know if this is caused by SR-IOV or not. * * TODO: * If PF has CAP_ID_PCIX or CAP_ID_EXP (offset>0), * look for extended capability PCI_EXT_CAP_ID_SRIOV (need extended config space (more than 256 bytes)), * then read the VF device ID after it (PCI_IOV_DID bytes later). * Needs access to extended config space (needs root on Linux). * TODO: * Add string info attributes in VF and PF objects? */ #ifdef HWLOC_LINUX_SYS /* Workaround for Linux (the kernel returns the VF device/vendor IDs). */ char path[64]; char value[16]; FILE *file; snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/vendor", domain, pcidev->bus, pcidev->dev, pcidev->func); file = fopen(path, "r"); if (file) { fread(value, sizeof(value), 1, file); fclose(file); obj->attr->pcidev.vendor_id = strtoul(value, NULL, 16); } snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/device", domain, pcidev->bus, pcidev->dev, pcidev->func); file = fopen(path, "r"); if (file) { fread(value, sizeof(value), 1, file); fclose(file); obj->attr->pcidev.device_id = strtoul(value, NULL, 16); } #endif } if (offset > 0 && offset + 20 /* size of PCI express block up to link status */ <= CONFIG_SPACE_CACHESIZE) hwloc_pci_find_linkspeed(config_space_cache, offset, &obj->attr->pcidev.linkspeed); hwloc_pci_prepare_bridge(obj, config_space_cache); if (obj->type == HWLOC_OBJ_PCI_DEVICE) { memcpy(&tmp16, &config_space_cache[PCI_SUBSYSTEM_VENDOR_ID], sizeof(tmp16)); obj->attr->pcidev.subvendor_id = tmp16; memcpy(&tmp16, &config_space_cache[PCI_SUBSYSTEM_ID], sizeof(tmp16)); obj->attr->pcidev.subdevice_id = tmp16; } else { /* TODO: * bridge must lookup PCI_CAP_ID_SSVID and then look at offset+PCI_SSVID_VENDOR/DEVICE_ID * cardbus must look at PCI_CB_SUBSYSTEM_VENDOR_ID and PCI_CB_SUBSYSTEM_ID */ } /* starting from pciutils 2.2, pci_lookup_name() takes a variable number * of arguments, and supports the PCI_LOOKUP_NO_NUMBERS flag. */ /* get the vendor name */ #ifdef HWLOC_HAVE_LIBPCIACCESS vendorname = pci_device_get_vendor_name(pcidev); #else /* HWLOC_HAVE_PCIUTILS */ vendorname = pci_lookup_name(pciaccess, name, sizeof(name), #if HAVE_DECL_PCI_LOOKUP_NO_NUMBERS PCI_LOOKUP_VENDOR|PCI_LOOKUP_NO_NUMBERS, pcidev->vendor_id #else PCI_LOOKUP_VENDOR, pcidev->vendor_id, 0, 0, 0 #endif ); #endif /* HWLOC_HAVE_PCIUTILS */ if (vendorname && *vendorname) hwloc_obj_add_info(obj, "PCIVendor", vendorname); /* get the device name */ #ifdef HWLOC_HAVE_LIBPCIACCESS devicename = pci_device_get_device_name(pcidev); #else /* HWLOC_HAVE_PCIUTILS */ devicename = pci_lookup_name(pciaccess, name, sizeof(name), #if HAVE_DECL_PCI_LOOKUP_NO_NUMBERS PCI_LOOKUP_DEVICE|PCI_LOOKUP_NO_NUMBERS, pcidev->vendor_id, pcidev->device_id #else PCI_LOOKUP_DEVICE, pcidev->vendor_id, pcidev->device_id, 0, 0 #endif ); #endif /* HWLOC_HAVE_PCIUTILS */ if (devicename && *devicename) hwloc_obj_add_info(obj, "PCIDevice", devicename); /* generate or get the fullname */ #ifdef HWLOC_HAVE_LIBPCIACCESS snprintf(name, sizeof(name), "%s%s%s", vendorname ? vendorname : "", vendorname && devicename ? " " : "", devicename ? devicename : ""); fullname = name; if (*name) obj->name = strdup(name); #else /* HWLOC_HAVE_PCIUTILS */ fullname = pci_lookup_name(pciaccess, name, sizeof(name), #if HAVE_DECL_PCI_LOOKUP_NO_NUMBERS PCI_LOOKUP_VENDOR|PCI_LOOKUP_DEVICE|PCI_LOOKUP_NO_NUMBERS, pcidev->vendor_id, pcidev->device_id #else PCI_LOOKUP_VENDOR|PCI_LOOKUP_DEVICE, pcidev->vendor_id, pcidev->device_id, 0, 0 #endif ); if (fullname && *fullname) obj->name = strdup(fullname); #endif /* HWLOC_HAVE_PCIUTILS */ hwloc_debug(" %04x:%02x:%02x.%01x %04x %04x:%04x %s\n", domain, pcidev->bus, pcidev->dev, pcidev->func, device_class, pcidev->vendor_id, pcidev->device_id, fullname && *fullname ? fullname : "??"); /* queue the object for now */ if (first_obj) last_obj->next_sibling = obj; else first_obj = obj; last_obj = obj; } /* finalize device scanning */ #ifdef HWLOC_HAVE_LIBPCIACCESS pci_iterator_destroy(iter); pci_system_cleanup(); #else /* HWLOC_HAVE_PCIUTILS */ pci_cleanup(pciaccess); #endif return hwloc_insert_pci_device_list(backend, first_obj); }
static void exec_op(struct op *op, struct pci_dev *dev) { const char * const formats[] = { NULL, " %02x", " %04x", NULL, " %08x" }; const char * const mask_formats[] = { NULL, " %02x->(%02x:%02x)->%02x", " %04x->(%04x:%04x)->%04x", NULL, " %08x->(%08x:%08x)->%08x" }; unsigned int i, x, y; int addr = 0; int width = op->width; char slot[16]; sprintf(slot, "%04x:%02x:%02x.%x", dev->domain, dev->bus, dev->dev, dev->func); trace("%s ", slot); if (op->cap_type) { struct pci_cap *cap; cap = pci_find_cap(dev, op->cap_id, op->cap_type); if (cap) addr = cap->addr; else die("%s: %s %04x not found", slot, ((op->cap_type == PCI_CAP_NORMAL) ? "Capability" : "Extended capability"), op->cap_id); trace(((op->cap_type == PCI_CAP_NORMAL) ? "(cap %02x @%02x) " : "(ecap %04x @%03x) "), op->cap_id, addr); } addr += op->addr; trace("@%02x", addr); /* We have already checked it when parsing, but addressing relative to capabilities can change the address. */ if (addr & (width-1)) die("%s: Unaligned access of width %d to register %04x", slot, width, addr); if (addr + width > 0x1000) die("%s: Access of width %d to register %04x out of range", slot, width, addr); if (op->num_values) { for (i=0; i<op->num_values; i++) { if ((op->values[i].mask & max_values[width]) == max_values[width]) { x = op->values[i].value; trace(formats[width], op->values[i].value); } else { switch (width) { case 1: y = pci_read_byte(dev, addr); break; case 2: y = pci_read_word(dev, addr); break; default: y = pci_read_long(dev, addr); break; } x = (y & ~op->values[i].mask) | op->values[i].value; trace(mask_formats[width], y, op->values[i].value, op->values[i].mask, x); } if (!demo_mode) { switch (width) { case 1: pci_write_byte(dev, addr, x); break; case 2: pci_write_word(dev, addr, x); break; default: pci_write_long(dev, addr, x); break; } } addr += width; } trace("\n"); } else { trace(" = "); switch (width) { case 1: x = pci_read_byte(dev, addr); break; case 2: x = pci_read_word(dev, addr); break; default: x = pci_read_long(dev, addr); break; } printf(formats[width]+1, x); putchar('\n'); } }
/* * Allocate resources for our device, set up the bus interface. */ static int aac_pci_attach(device_t dev) { struct aac_softc *sc; const struct aac_ident *id; int count, error, reg, rid; fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); /* * Initialise softc. */ sc = device_get_softc(dev); sc->aac_dev = dev; /* assume failure is 'not configured' */ error = ENXIO; /* * Verify that the adapter is correctly set up in PCI space. */ pci_enable_busmaster(dev); if (!(pci_read_config(dev, PCIR_COMMAND, 2) & PCIM_CMD_BUSMASTEREN)) { device_printf(dev, "can't enable bus-master feature\n"); goto out; } /* * Allocate the PCI register window(s). */ rid = PCIR_BAR(0); if ((sc->aac_regs_res0 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE)) == NULL) { device_printf(dev, "can't allocate register window 0\n"); goto out; } sc->aac_btag0 = rman_get_bustag(sc->aac_regs_res0); sc->aac_bhandle0 = rman_get_bushandle(sc->aac_regs_res0); if (sc->aac_hwif == AAC_HWIF_NARK) { rid = PCIR_BAR(1); if ((sc->aac_regs_res1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE)) == NULL) { device_printf(dev, "can't allocate register window 1\n"); goto out; } sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1); sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1); } else { sc->aac_regs_res1 = sc->aac_regs_res0; sc->aac_btag1 = sc->aac_btag0; sc->aac_bhandle1 = sc->aac_bhandle0; } /* * Allocate the interrupt. */ rid = 0; count = 0; if (aac_enable_msi != 0 && pci_find_cap(dev, PCIY_MSI, ®) == 0) { count = pci_msi_count(dev); if (count > 1) count = 1; else count = 0; if (count == 1 && pci_alloc_msi(dev, &count) == 0) rid = 1; } if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ, &rid, RF_ACTIVE | (count != 0 ? 0 : RF_SHAREABLE))) == NULL) { device_printf(dev, "can't allocate interrupt\n"); goto out; } /* * Allocate the parent bus DMA tag appropriate for our PCI interface. * * Note that some of these controllers are 64-bit capable. */ if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ PAGE_SIZE, 0, /* algnmnt, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ BUS_SPACE_UNRESTRICTED, /* nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* No locking needed */ &sc->aac_parent_dmat)) { device_printf(dev, "can't allocate parent DMA tag\n"); goto out; } /* * Detect the hardware interface version, set up the bus interface * indirection. */ id = aac_find_ident(dev); sc->aac_hwif = id->hwif; switch(sc->aac_hwif) { case AAC_HWIF_I960RX: case AAC_HWIF_NARK: fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "set hardware up for i960Rx/NARK"); sc->aac_if = &aac_rx_interface; break; case AAC_HWIF_STRONGARM: fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "set hardware up for StrongARM"); sc->aac_if = &aac_sa_interface; break; case AAC_HWIF_RKT: fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "set hardware up for Rocket/MIPS"); sc->aac_if = &aac_rkt_interface; break; default: sc->aac_hwif = AAC_HWIF_UNKNOWN; device_printf(dev, "unknown hardware type\n"); error = ENXIO; goto out; } /* Set up quirks */ sc->flags = id->quirks; /* * Do bus-independent initialisation. */ error = aac_attach(sc); out: if (error) aac_free(sc); return(error); }
static int malo_pci_attach(device_t dev) { int error = ENXIO, i, msic, reg; struct malo_pci_softc *psc = device_get_softc(dev); struct malo_softc *sc = &psc->malo_sc; sc->malo_dev = dev; pci_enable_busmaster(dev); /* * Setup memory-mapping of PCI registers. */ psc->malo_mem_spec = malo_res_spec_mem; error = bus_alloc_resources(dev, psc->malo_mem_spec, psc->malo_res_mem); if (error) { device_printf(dev, "couldn't allocate memory resources\n"); return (ENXIO); } /* * Arrange and allocate interrupt line. */ sc->malo_invalid = 1; if (pci_find_cap(dev, PCIY_EXPRESS, ®) == 0) { msic = pci_msi_count(dev); if (bootverbose) device_printf(dev, "MSI count : %d\n", msic); } else msic = 0; psc->malo_irq_spec = malo_res_spec_legacy; if (msic == MALO_MSI_MESSAGES && msi_disable == 0) { if (pci_alloc_msi(dev, &msic) == 0) { if (msic == MALO_MSI_MESSAGES) { device_printf(dev, "Using %d MSI messages\n", msic); psc->malo_irq_spec = malo_res_spec_msi; psc->malo_msi = 1; } else pci_release_msi(dev); } } error = bus_alloc_resources(dev, psc->malo_irq_spec, psc->malo_res_irq); if (error) { device_printf(dev, "couldn't allocate IRQ resources\n"); goto bad; } if (psc->malo_msi == 0) error = bus_setup_intr(dev, psc->malo_res_irq[0], INTR_TYPE_NET | INTR_MPSAFE, malo_intr, NULL, sc, &psc->malo_intrhand[0]); else { for (i = 0; i < MALO_MSI_MESSAGES; i++) { error = bus_setup_intr(dev, psc->malo_res_irq[i], INTR_TYPE_NET | INTR_MPSAFE, malo_intr, NULL, sc, &psc->malo_intrhand[i]); if (error != 0) break; } } /* * Setup DMA descriptor area. */ if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 1, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ BUS_SPACE_MAXADDR, /* maxsize */ 0, /* nsegments */ BUS_SPACE_MAXADDR, /* maxsegsize */ 0, /* flags */ NULL, /* lockfunc */ NULL, /* lockarg */ &sc->malo_dmat)) { device_printf(dev, "cannot allocate DMA tag\n"); goto bad1; } sc->malo_io0t = rman_get_bustag(psc->malo_res_mem[0]); sc->malo_io0h = rman_get_bushandle(psc->malo_res_mem[0]); sc->malo_io1t = rman_get_bustag(psc->malo_res_mem[1]); sc->malo_io1h = rman_get_bushandle(psc->malo_res_mem[1]); error = malo_attach(pci_get_device(dev), sc); if (error != 0) goto bad2; return (error); bad2: bus_dma_tag_destroy(sc->malo_dmat); bad1: if (psc->malo_msi == 0) bus_teardown_intr(dev, psc->malo_res_irq[0], psc->malo_intrhand[0]); else { for (i = 0; i < MALO_MSI_MESSAGES; i++) bus_teardown_intr(dev, psc->malo_res_irq[i], psc->malo_intrhand[i]); } bus_release_resources(dev, psc->malo_irq_spec, psc->malo_res_irq); bad: if (psc->malo_msi != 0) pci_release_msi(dev); bus_release_resources(dev, psc->malo_mem_spec, psc->malo_res_mem); return (error); }
/* Returns 1 if AGP or 0 if not. */ static int drm_device_find_capability(struct drm_device *dev, int cap) { return (pci_find_cap(dev->device, cap, NULL) == 0); }
int ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry) { struct scb_data *shared_scb_data; u_int command; uint32_t devconfig; uint16_t device; uint16_t subvendor; int error; shared_scb_data = NULL; ahd->description = entry->name; /* * Record if this is a HostRAID board. */ device = aic_pci_read_config(ahd->dev_softc, PCIR_DEVICE, /*bytes*/2); if (DEVID_9005_HOSTRAID(device)) ahd->flags |= AHD_HOSTRAID_BOARD; /* * Record if this is an HP board. */ subvendor = aic_pci_read_config(ahd->dev_softc, PCIR_SUBVEND_0, /*bytes*/2); if (subvendor == SUBID_HP) ahd->flags |= AHD_HP_BOARD; error = entry->setup(ahd); if (error != 0) return (error); /* * Find the PCI-X cap pointer. If we don't find it, * pcix_ptr will be 0. */ pci_find_cap(ahd->dev_softc, PCIY_PCIX, &ahd->pcix_ptr); devconfig = aic_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4); if ((devconfig & PCIXINITPAT) == PCIXINIT_PCI33_66) { ahd->chip |= AHD_PCI; /* Disable PCIX workarounds when running in PCI mode. */ ahd->bugs &= ~AHD_PCIX_BUG_MASK; } else { ahd->chip |= AHD_PCIX; if (ahd->pcix_ptr == 0) return (ENXIO); } ahd->bus_description = pci_bus_modes[PCI_BUS_MODES_INDEX(devconfig)]; aic_power_state_change(ahd, AIC_POWER_STATE_D0); error = ahd_pci_map_registers(ahd); if (error != 0) return (error); /* * If we need to support high memory, enable dual * address cycles. This bit must be set to enable * high address bit generation even if we are on a * 64bit bus (PCI64BIT set in devconfig). */ if ((ahd->flags & (AHD_39BIT_ADDRESSING|AHD_64BIT_ADDRESSING)) != 0) { uint32_t devconfig; if (bootverbose) printf("%s: Enabling 39Bit Addressing\n", ahd_name(ahd)); devconfig = aic_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4); devconfig |= DACEN; aic_pci_write_config(ahd->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); } /* Ensure busmastering is enabled */ command = aic_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); command |= PCIM_CMD_BUSMASTEREN; aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/2); error = ahd_softc_init(ahd); if (error != 0) return (error); ahd->bus_intr = ahd_pci_intr; error = ahd_reset(ahd, /*reinit*/FALSE); if (error != 0) return (ENXIO); ahd->pci_cachesize = aic_pci_read_config(ahd->dev_softc, CSIZE_LATTIME, /*bytes*/1) & CACHESIZE; ahd->pci_cachesize *= 4; ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); /* See if we have a SEEPROM and perform auto-term */ error = ahd_check_extport(ahd); if (error != 0) return (error); /* Core initialization */ error = ahd_init(ahd); if (error != 0) return (error); /* * Allow interrupts now that we are completely setup. */ error = ahd_pci_map_int(ahd); if (error != 0) return (error); ahd_lock(ahd); /* * Link this softc in with all other ahd instances. */ ahd_softc_insert(ahd); ahd_unlock(ahd); return (0); }
static int athp_pci_attach(device_t dev) { struct ath10k_pci *ar_pci = device_get_softc(dev); struct ath10k *ar = &ar_pci->sc_sc; int rid, i; int err = 0; int ret; ar->sc_dev = dev; ar->sc_invalid = 1; /* XXX TODO: initialize sc_debug from TUNABLE */ #if 0 ar->sc_debug = ATH10K_DBG_BOOT | ATH10K_DBG_PCI | ATH10K_DBG_HTC | ATH10K_DBG_PCI_DUMP | ATH10K_DBG_WMI | ATH10K_DBG_BMI | ATH10K_DBG_MAC | ATH10K_DBG_WMI_PRINT | ATH10K_DBG_MGMT | ATH10K_DBG_DATA | ATH10K_DBG_HTT; #endif ar->sc_psc = ar_pci; /* Load-time tunable/sysctl tree */ athp_attach_sysctl(ar); /* Enable WMI/HTT RX for now */ ar->sc_rx_wmi = 1; ar->sc_rx_htt = 1; /* Fetch pcie capability offset */ ret = pci_find_cap(dev, PCIY_EXPRESS, &ar_pci->sc_cap_off); if (ret != 0) { device_printf(dev, "%s: failed to find pci-express capability offset\n", __func__); return (ret); } /* * Initialise ath10k core bits. */ if (ath10k_core_init(ar) < 0) goto bad0; /* * Initialise ath10k freebsd bits. */ sprintf(ar->sc_mtx_buf, "%s:def", device_get_nameunit(dev)); mtx_init(&ar->sc_mtx, ar->sc_mtx_buf, MTX_NETWORK_LOCK, MTX_DEF); sprintf(ar->sc_buf_mtx_buf, "%s:buf", device_get_nameunit(dev)); mtx_init(&ar->sc_buf_mtx, ar->sc_buf_mtx_buf, "athp buf", MTX_DEF); sprintf(ar->sc_dma_mtx_buf, "%s:dma", device_get_nameunit(dev)); mtx_init(&ar->sc_dma_mtx, ar->sc_dma_mtx_buf, "athp dma", MTX_DEF); sprintf(ar->sc_conf_mtx_buf, "%s:conf", device_get_nameunit(dev)); mtx_init(&ar->sc_conf_mtx, ar->sc_conf_mtx_buf, "athp conf", MTX_DEF | MTX_RECURSE); sprintf(ar_pci->ps_mtx_buf, "%s:ps", device_get_nameunit(dev)); mtx_init(&ar_pci->ps_mtx, ar_pci->ps_mtx_buf, "athp ps", MTX_DEF); sprintf(ar_pci->ce_mtx_buf, "%s:ce", device_get_nameunit(dev)); mtx_init(&ar_pci->ce_mtx, ar_pci->ce_mtx_buf, "athp ce", MTX_DEF); sprintf(ar->sc_data_mtx_buf, "%s:data", device_get_nameunit(dev)); mtx_init(&ar->sc_data_mtx, ar->sc_data_mtx_buf, "athp data", MTX_DEF); /* * Initialise ath10k BMI/PCIDIAG bits. */ ret = athp_descdma_alloc(ar, &ar_pci->sc_bmi_txbuf, "bmi_msg_req", 4, 1024); ret |= athp_descdma_alloc(ar, &ar_pci->sc_bmi_rxbuf, "bmi_msg_resp", 4, 1024); if (ret != 0) { device_printf(dev, "%s: failed to allocate BMI TX/RX buffer\n", __func__); goto bad0; } /* * Initialise HTT descriptors/memory. */ ret = ath10k_htt_rx_alloc_desc(ar, &ar->htt); if (ret != 0) { device_printf(dev, "%s: failed to alloc HTT RX descriptors\n", __func__); goto bad; } /* XXX here instead of in core_init because we need the lock init'ed */ callout_init_mtx(&ar->scan.timeout, &ar->sc_data_mtx, 0); ar_pci->pipe_taskq = taskqueue_create("athp pipe taskq", M_NOWAIT, NULL, ar_pci); (void) taskqueue_start_threads(&ar_pci->pipe_taskq, 1, PI_NET, "%s pipe taskq", device_get_nameunit(dev)); if (ar_pci->pipe_taskq == NULL) { device_printf(dev, "%s: couldn't create pipe taskq\n", __func__); err = ENXIO; goto bad; } /* * Look at the device/vendor ID and choose which register offset * mapping to use. This is used by a lot of the register access * pieces to get the correct device-specific windows. */ ar_pci->sc_vendorid = pci_get_vendor(dev); ar_pci->sc_deviceid = pci_get_device(dev); if (athp_pci_hw_lookup(ar_pci) != 0) { device_printf(dev, "%s: hw lookup failed\n", __func__); err = ENXIO; goto bad; } /* * Enable bus mastering. */ pci_enable_busmaster(dev); /* * Setup memory-mapping of PCI registers. */ rid = BS_BAR; ar_pci->sc_sr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (ar_pci->sc_sr == NULL) { device_printf(dev, "cannot map register space\n"); err = ENXIO; goto bad; } /* Driver copy; hopefully we can delete this */ ar->sc_st = rman_get_bustag(ar_pci->sc_sr); ar->sc_sh = rman_get_bushandle(ar_pci->sc_sr); /* Local copy for bus operations */ ar_pci->sc_st = rman_get_bustag(ar_pci->sc_sr); ar_pci->sc_sh = rman_get_bushandle(ar_pci->sc_sr); /* * Mark device invalid so any interrupts (shared or otherwise) * that arrive before the HAL is setup are discarded. */ ar->sc_invalid = 1; printf("%s: msicount=%d, msixcount=%d\n", __func__, pci_msi_count(dev), pci_msix_count(dev)); /* * Arrange interrupt line. * * XXX TODO: this is effictively ath10k_pci_init_irq(). * Refactor it out later. * * First - attempt MSI. If we get it, then use it. */ i = MSI_NUM_REQUEST; if (pci_alloc_msi(dev, &i) == 0) { device_printf(dev, "%s: %d MSI interrupts\n", __func__, i); ar_pci->num_msi_intrs = MSI_NUM_REQUEST; } else { i = 1; if (pci_alloc_msi(dev, &i) == 0) { device_printf(dev, "%s: 1 MSI interrupt\n", __func__); ar_pci->num_msi_intrs = 1; } else { device_printf(dev, "%s: legacy interrupts\n", __func__); ar_pci->num_msi_intrs = 0; } } err = ath10k_pci_request_irq(ar_pci); if (err != 0) goto bad1; /* * Attach register ops - needed for the caller to do register IO. */ ar->sc_regio.reg_read = athp_pci_regio_read_reg; ar->sc_regio.reg_write = athp_pci_regio_write_reg; ar->sc_regio.reg_s_read = athp_pci_regio_s_read_reg; ar->sc_regio.reg_s_write = athp_pci_regio_s_write_reg; ar->sc_regio.reg_flush = athp_pci_regio_flush_reg; ar->sc_regio.reg_arg = ar_pci; /* * TODO: abstract this out to be a bus/hif specific * attach path. * * I'm not sure what USB/SDIO will look like here, but * I'm pretty sure it won't involve PCI/CE setup. * It'll still have WME/HIF/BMI, but it'll be done over * USB endpoints. */ if (athp_pci_setup_bufs(ar_pci) != 0) { err = ENXIO; goto bad4; } /* HIF ops attach */ ar->hif.ops = &ath10k_pci_hif_ops; ar->hif.bus = ATH10K_BUS_PCI; /* Alloc pipes */ ret = ath10k_pci_alloc_pipes(ar); if (ret) { device_printf(ar->sc_dev, "%s: pci_alloc_pipes failed: %d\n", __func__, ret); /* XXX cleanup */ err = ENXIO; goto bad4; } /* deinit ce */ ath10k_pci_ce_deinit(ar); /* disable irq */ ret = ath10k_pci_irq_disable(ar_pci); if (ret) { device_printf(ar->sc_dev, "%s: irq_disable failed: %d\n", __func__, ret); err = ENXIO; goto bad4; } /* init IRQ */ ret = ath10k_pci_init_irq(ar_pci); if (ret) { device_printf(ar->sc_dev, "%s: init_irq failed: %d\n", __func__, ret); err = ENXIO; goto bad4; } /* Ok, gate open the interrupt handler */ ar->sc_invalid = 0; /* pci_chip_reset */ ret = ath10k_pci_chip_reset(ar_pci); if (ret) { device_printf(ar->sc_dev, "%s: chip_reset failed: %d\n", __func__, ret); err = ENXIO; goto bad4; } /* read SoC/chip version */ ar->sc_chipid = athp_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS(ar->sc_regofs)); /* Verify chip version is something we can use */ device_printf(ar->sc_dev, "%s: chipid: 0x%08x\n", __func__, ar->sc_chipid); if (! ath10k_pci_chip_is_supported(ar_pci->sc_deviceid, ar->sc_chipid)) { device_printf(ar->sc_dev, "%s: unsupported chip; chipid: 0x%08x\n", __func__, ar->sc_chipid); err = ENXIO; goto bad4; } /* Call main attach method with given info */ ar->sc_preinit_hook.ich_func = athp_attach_preinit; ar->sc_preinit_hook.ich_arg = ar; if (config_intrhook_establish(&ar->sc_preinit_hook) != 0) { device_printf(ar->sc_dev, "%s: couldn't establish preinit hook\n", __func__); goto bad4; } return (0); /* Fallthrough for setup failure */ bad4: athp_pci_free_bufs(ar_pci); /* Ensure we disable interrupts from the device */ ath10k_pci_deinit_irq(ar_pci); ath10k_pci_free_irq(ar_pci); bad1: bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, ar_pci->sc_sr); bad: ath10k_htt_rx_free_desc(ar, &ar->htt); athp_descdma_free(ar, &ar_pci->sc_bmi_txbuf); athp_descdma_free(ar, &ar_pci->sc_bmi_rxbuf); /* XXX disable busmaster? */ mtx_destroy(&ar_pci->ps_mtx); mtx_destroy(&ar_pci->ce_mtx); mtx_destroy(&ar->sc_conf_mtx); mtx_destroy(&ar->sc_data_mtx); mtx_destroy(&ar->sc_buf_mtx); mtx_destroy(&ar->sc_dma_mtx); mtx_destroy(&ar->sc_mtx); if (ar_pci->pipe_taskq) { taskqueue_drain_all(ar_pci->pipe_taskq); taskqueue_free(ar_pci->pipe_taskq); } /* Shutdown ioctl handler */ athp_ioctl_teardown(ar); ath10k_core_destroy(ar); bad0: return (err); }
void pci::probe(void) { pci_scan_bus(_pacc); uint8_t buf[CONFIG_SPACE_SIZE] = {0}; char classbuf[128] = {0}, vendorbuf[128] {0}, devbuf[128] = {0}; for (struct pci_dev *dev = _pacc->devices; dev && _entries.size() < MAX_DEVICES; dev = dev->next) { _entries.push_back(pciEntry()); pciEntry &e = _entries.back(); memset(buf, 0, sizeof(buf)); memset(classbuf, 0, sizeof(classbuf)); memset(vendorbuf, 0, sizeof(vendorbuf)); memset(devbuf, 0, sizeof(devbuf)); pci_setup_cache(dev, buf, CONFIG_SPACE_SIZE); pci_read_block(dev, 0, buf, CONFIG_SPACE_SIZE); pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_CAPS); pci_lookup_name(_pacc, vendorbuf, sizeof(vendorbuf), PCI_LOOKUP_VENDOR, dev->vendor_id, dev->device_id); pci_lookup_name(_pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id); e.text.append(vendorbuf).append("|").append(devbuf); e.class_type += classbuf; e.vendor = dev->vendor_id; e.device = dev->device_id; e.pci_domain = dev->domain; e.bus = dev->bus; e.pciusb_device = dev->dev; e.pci_function = dev->func; e.class_id = dev->device_class; e.subvendor = pci_read_word(dev, PCI_SUBSYSTEM_VENDOR_ID); e.subdevice = pci_read_word(dev, PCI_SUBSYSTEM_ID); e.pci_revision = pci_read_byte(dev, PCI_REVISION_ID); if ((e.subvendor == 0 && e.subdevice == 0) || (e.subvendor == e.vendor && e.subdevice == e.device)) { e.subvendor = 0xffff; e.subdevice = 0xffff; } if (pci_find_cap(dev,PCI_CAP_ID_EXP, PCI_CAP_NORMAL)) e.is_pciexpress = true; /* special case for realtek 8139 that has two drivers */ if (e.vendor == 0x10ec && e.device == 0x8139) { if (e.pci_revision < 0x20) e.module = "8139too"; else e.module = "8139cp"; } } // fake two PCI controllers for xen struct stat sb; if (!stat("/sys/bus/xen", &sb)) { // FIXME: use C++ streams.. FILE *f; if ((f = fopen("/sys/hypervisor/uuid", "r"))) { char buf[38]; fgets(buf, sizeof(buf) - 1, f); fclose(f); if (strncmp(buf, "00000000-0000-0000-0000-000000000000", sizeof(buf))) { // We're now sure to be in a Xen guest: { _entries.push_back(pciEntry()); pciEntry &e = _entries.back(); e.text.append("XenSource, Inc.|Block Frontend"); e.class_id = 0x0106; // STORAGE_SATA e.vendor = 0x1a71; // XenSource e.device = 0xfffa; // fake e.subvendor = 0; e.subdevice = 0; e.class_id = 0x0106; e.module = "xen_blkfront"; } { _entries.push_back(pciEntry()); pciEntry &e = _entries.back(); e.text.append("XenSource, Inc.|Network Frontend"); e.class_id = 0x0200; // NETWORK_ETHERNET e.vendor = 0x1a71; // XenSource e.device = 0xfffb; // fake e.subvendor = 0; e.subdevice = 0; e.class_id = 0x0200; e.module = "xen_netfront"; } } } } findModules("pcitable", false); }