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 + -
显示快捷键?