probe.c
来自「linux 内核源代码」· C语言 代码 · 共 1,257 行 · 第 1/3 页
C
1,257 行
if (pci_read_config_dword(dev, 256, &status) != PCIBIOS_SUCCESSFUL) goto fail; if (status == 0xffffffff) goto fail; return PCI_CFG_SPACE_EXP_SIZE; fail: return PCI_CFG_SPACE_SIZE;}static void pci_release_bus_bridge_dev(struct device *dev){ kfree(dev);}struct pci_dev *alloc_pci_dev(void){ struct pci_dev *dev; dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); if (!dev) return NULL; INIT_LIST_HEAD(&dev->global_list); INIT_LIST_HEAD(&dev->bus_list); pci_msi_init_pci_dev(dev); return dev;}EXPORT_SYMBOL(alloc_pci_dev);/* * Read the config data for a PCI device, sanity-check it * and fill in the dev structure... */static struct pci_dev * __devinitpci_scan_device(struct pci_bus *bus, int devfn){ struct pci_dev *dev; u32 l; u8 hdr_type; int delay = 1; if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l)) return NULL; /* some broken boards return 0 or ~0 if a slot is empty: */ if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) return NULL; /* Configuration request Retry Status */ while (l == 0xffff0001) { msleep(delay); delay *= 2; if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l)) return NULL; /* Card hasn't responded in 60 seconds? Must be stuck. */ if (delay > 60 * 1000) { printk(KERN_WARNING "Device %04x:%02x:%02x.%d not " "responding\n", pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); return NULL; } } if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type)) return NULL; dev = alloc_pci_dev(); if (!dev) return NULL; dev->bus = bus; dev->sysdata = bus->sysdata; dev->dev.parent = bus->bridge; dev->dev.bus = &pci_bus_type; dev->devfn = devfn; dev->hdr_type = hdr_type & 0x7f; dev->multifunction = !!(hdr_type & 0x80); dev->vendor = l & 0xffff; dev->device = (l >> 16) & 0xffff; dev->cfg_size = pci_cfg_space_size(dev); dev->error_state = pci_channel_io_normal; set_pcie_port_type(dev); /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer) set this higher, assuming the system even supports it. */ dev->dma_mask = 0xffffffff; if (pci_setup_device(dev) < 0) { kfree(dev); return NULL; } return dev;}void pci_device_add(struct pci_dev *dev, struct pci_bus *bus){ device_initialize(&dev->dev); dev->dev.release = pci_release_dev; pci_dev_get(dev); set_dev_node(&dev->dev, pcibus_to_node(bus)); dev->dev.dma_mask = &dev->dma_mask; dev->dev.coherent_dma_mask = 0xffffffffull; /* Fix up broken headers */ pci_fixup_device(pci_fixup_header, dev); /* * Add the device to our list of discovered devices * and the bus list for fixup functions, etc. */ INIT_LIST_HEAD(&dev->global_list); down_write(&pci_bus_sem); list_add_tail(&dev->bus_list, &bus->devices); up_write(&pci_bus_sem);}struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn){ struct pci_dev *dev; dev = pci_scan_device(bus, devfn); if (!dev) return NULL; pci_device_add(dev, bus); return dev;}/** * pci_scan_slot - scan a PCI slot on a bus for devices. * @bus: PCI bus to scan * @devfn: slot number to scan (must have zero function.) * * Scan a PCI slot on the specified PCI bus for devices, adding * discovered devices to the @bus->devices list. New devices * will have an empty dev->global_list head. */int pci_scan_slot(struct pci_bus *bus, int devfn){ int func, nr = 0; int scan_all_fns; scan_all_fns = pcibios_scan_all_fns(bus, devfn); for (func = 0; func < 8; func++, devfn++) { struct pci_dev *dev; dev = pci_scan_single_device(bus, devfn); if (dev) { nr++; /* * If this is a single function device, * don't scan past the first function. */ if (!dev->multifunction) { if (func > 0) { dev->multifunction = 1; } else { break; } } } else { if (func == 0 && !scan_all_fns) break; } } return nr;}unsigned int pci_scan_child_bus(struct pci_bus *bus){ unsigned int devfn, pass, max = bus->secondary; struct pci_dev *dev; pr_debug("PCI: Scanning bus %04x:%02x\n", pci_domain_nr(bus), bus->number); /* Go find them, Rover! */ for (devfn = 0; devfn < 0x100; devfn += 8) pci_scan_slot(bus, devfn); /* * After performing arch-dependent fixup of the bus, look behind * all PCI-to-PCI bridges on this bus. */ pr_debug("PCI: Fixups for bus %04x:%02x\n", pci_domain_nr(bus), bus->number); pcibios_fixup_bus(bus); for (pass=0; pass < 2; pass++) list_for_each_entry(dev, &bus->devices, bus_list) { if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) max = pci_scan_bridge(bus, dev, max, pass); } /* * We've scanned the bus and so we know all about what's on * the other side of any bridges that may be on this bus plus * any devices. * * Return how far we've got finding sub-buses. */ pr_debug("PCI: Bus scan for %04x:%02x returning with max=%02x\n", pci_domain_nr(bus), bus->number, max); return max;}unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus){ unsigned int max; max = pci_scan_child_bus(bus); /* * Make the discovered devices available. */ pci_bus_add_devices(bus); return max;}struct pci_bus * pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata){ int error; struct pci_bus *b; struct device *dev; b = pci_alloc_bus(); if (!b) return NULL; dev = kmalloc(sizeof(*dev), GFP_KERNEL); if (!dev){ kfree(b); return NULL; } b->sysdata = sysdata; b->ops = ops; if (pci_find_bus(pci_domain_nr(b), bus)) { /* If we already got to this bus through a different bridge, ignore it */ pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); goto err_out; } down_write(&pci_bus_sem); list_add_tail(&b->node, &pci_root_buses); up_write(&pci_bus_sem); memset(dev, 0, sizeof(*dev)); dev->parent = parent; dev->release = pci_release_bus_bridge_dev; sprintf(dev->bus_id, "pci%04x:%02x", pci_domain_nr(b), bus); error = device_register(dev); if (error) goto dev_reg_err; b->bridge = get_device(dev); b->class_dev.class = &pcibus_class; sprintf(b->class_dev.class_id, "%04x:%02x", pci_domain_nr(b), bus); error = class_device_register(&b->class_dev); if (error) goto class_dev_reg_err; error = class_device_create_file(&b->class_dev, &class_device_attr_cpuaffinity); if (error) goto class_dev_create_file_err; /* Create legacy_io and legacy_mem files for this bus */ pci_create_legacy_files(b); error = sysfs_create_link(&b->class_dev.kobj, &b->bridge->kobj, "bridge"); if (error) goto sys_create_link_err; b->number = b->secondary = bus; b->resource[0] = &ioport_resource; b->resource[1] = &iomem_resource; return b;sys_create_link_err: class_device_remove_file(&b->class_dev, &class_device_attr_cpuaffinity);class_dev_create_file_err: class_device_unregister(&b->class_dev);class_dev_reg_err: device_unregister(dev);dev_reg_err: down_write(&pci_bus_sem); list_del(&b->node); up_write(&pci_bus_sem);err_out: kfree(dev); kfree(b); return NULL;}EXPORT_SYMBOL_GPL(pci_create_bus);struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata){ struct pci_bus *b; b = pci_create_bus(parent, bus, ops, sysdata); if (b) b->subordinate = pci_scan_child_bus(b); return b;}EXPORT_SYMBOL(pci_scan_bus_parented);#ifdef CONFIG_HOTPLUGEXPORT_SYMBOL(pci_add_new_bus);EXPORT_SYMBOL(pci_do_scan_bus);EXPORT_SYMBOL(pci_scan_slot);EXPORT_SYMBOL(pci_scan_bridge);EXPORT_SYMBOL(pci_scan_single_device);EXPORT_SYMBOL_GPL(pci_scan_child_bus);#endifstatic int __init pci_sort_bf_cmp(const struct pci_dev *a, const struct pci_dev *b){ if (pci_domain_nr(a->bus) < pci_domain_nr(b->bus)) return -1; else if (pci_domain_nr(a->bus) > pci_domain_nr(b->bus)) return 1; if (a->bus->number < b->bus->number) return -1; else if (a->bus->number > b->bus->number) return 1; if (a->devfn < b->devfn) return -1; else if (a->devfn > b->devfn) return 1; return 0;}/* * Yes, this forcably breaks the klist abstraction temporarily. It * just wants to sort the klist, not change reference counts and * take/drop locks rapidly in the process. It does all this while * holding the lock for the list, so objects can't otherwise be * added/removed while we're swizzling. */static void __init pci_insertion_sort_klist(struct pci_dev *a, struct list_head *list){ struct list_head *pos; struct klist_node *n; struct device *dev; struct pci_dev *b; list_for_each(pos, list) { n = container_of(pos, struct klist_node, n_node); dev = container_of(n, struct device, knode_bus); b = to_pci_dev(dev); if (pci_sort_bf_cmp(a, b) <= 0) { list_move_tail(&a->dev.knode_bus.n_node, &b->dev.knode_bus.n_node); return; } } list_move_tail(&a->dev.knode_bus.n_node, list);}static void __init pci_sort_breadthfirst_klist(void){ LIST_HEAD(sorted_devices); struct list_head *pos, *tmp; struct klist_node *n; struct device *dev; struct pci_dev *pdev; spin_lock(&pci_bus_type.klist_devices.k_lock); list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) { n = container_of(pos, struct klist_node, n_node); dev = container_of(n, struct device, knode_bus); pdev = to_pci_dev(dev); pci_insertion_sort_klist(pdev, &sorted_devices); } list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list); spin_unlock(&pci_bus_type.klist_devices.k_lock);}static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list){ struct pci_dev *b; list_for_each_entry(b, list, global_list) { if (pci_sort_bf_cmp(a, b) <= 0) { list_move_tail(&a->global_list, &b->global_list); return; } } list_move_tail(&a->global_list, list);}static void __init pci_sort_breadthfirst_devices(void){ LIST_HEAD(sorted_devices); struct pci_dev *dev, *tmp; down_write(&pci_bus_sem); list_for_each_entry_safe(dev, tmp, &pci_devices, global_list) { pci_insertion_sort_devices(dev, &sorted_devices); } list_splice(&sorted_devices, &pci_devices); up_write(&pci_bus_sem);}void __init pci_sort_breadthfirst(void){ pci_sort_breadthfirst_devices(); pci_sort_breadthfirst_klist();}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?