ia64/linux-2.6.18-xen.hg

view drivers/pci/remove.c @ 882:8dec4aa9b8b9

PCI pass through: PCIe IO space multiplexing

This is required for more than 16 HVM domain to boot from
PCIe pass through device.

Linux as dom0 exclusively assigns IO space to downstream PCI bridges
and the assignment unit of PCI bridge IO space is 4K. So the only up
to 16 PCIe device can be accessed via IO space within 64K IO ports.
PCI expansion ROM BIOS often uses IO port access to boot from the
device, so on virtualized environment, it means only up to 16 guest
domain can boot from pass-through device.

This patch allows PCIe IO space sharing of pass-through device.
- reassign IO space of PCIe devices specified by
"guestiomuldev=[<segment>:]<bus>:<dev>[,[<segment:><bus>:dev]][,...]"
to be shared.
This is implemented as Linux PCI quirk fixup.

The sharing unit is PCIe switch. Ie IO space of the end point
devices under the same switch will be shared. If there are more than
one switches, two areas of IO space will be used.

- And the driver which arbitrates the accesses to the multiplexed PCIe
IO space. Later qemu-dm will use this.

Limitation:
IO port of IO shared devices can't be accessed from dom0 Linux device
driver. But this wouldn't be a big issue because PCIe specification
discourages the use of IO space and recommends that IO space should be
used only for bootable device with ROM code. OS device driver should
work without IO space access.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Keir Fraser <keir.fraser@citrix.com>
date Thu May 28 09:57:49 2009 +0100 (2009-05-28)
parents 831230e53067
children
line source
1 #include <linux/pci.h>
2 #include <linux/module.h>
3 #include "pci.h"
5 static void pci_free_resources(struct pci_dev *dev)
6 {
7 int i;
9 msi_remove_pci_irq_vectors(dev);
11 pci_cleanup_rom(dev);
12 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
13 struct resource *res = dev->resource + i;
14 if (res->parent)
15 release_resource(res);
16 }
17 }
19 static void pci_destroy_dev(struct pci_dev *dev)
20 {
21 if (!list_empty(&dev->global_list)) {
22 pci_proc_detach_device(dev);
23 pci_remove_sysfs_dev_files(dev);
24 device_unregister(&dev->dev);
25 down_write(&pci_bus_sem);
26 list_del(&dev->global_list);
27 dev->global_list.next = dev->global_list.prev = NULL;
28 up_write(&pci_bus_sem);
29 }
31 /* Remove the device from the device lists, and prevent any further
32 * list accesses from this device */
33 down_write(&pci_bus_sem);
34 list_del(&dev->bus_list);
35 dev->bus_list.next = dev->bus_list.prev = NULL;
36 up_write(&pci_bus_sem);
38 pci_free_resources(dev);
39 pci_dev_put(dev);
40 }
42 /**
43 * pci_remove_device_safe - remove an unused hotplug device
44 * @dev: the device to remove
45 *
46 * Delete the device structure from the device lists and
47 * notify userspace (/sbin/hotplug), but only if the device
48 * in question is not being used by a driver.
49 * Returns 0 on success.
50 */
51 #if 0
52 int pci_remove_device_safe(struct pci_dev *dev)
53 {
54 if (pci_dev_driver(dev))
55 return -EBUSY;
56 pci_destroy_dev(dev);
57 return 0;
58 }
59 #endif /* 0 */
61 void pci_remove_bus(struct pci_bus *pci_bus)
62 {
63 pci_proc_detach_bus(pci_bus);
65 down_write(&pci_bus_sem);
66 list_del(&pci_bus->node);
67 up_write(&pci_bus_sem);
68 pci_remove_legacy_files(pci_bus);
69 class_device_remove_file(&pci_bus->class_dev,
70 &class_device_attr_cpuaffinity);
71 sysfs_remove_link(&pci_bus->class_dev.kobj, "bridge");
72 class_device_unregister(&pci_bus->class_dev);
73 }
74 EXPORT_SYMBOL(pci_remove_bus);
76 /**
77 * pci_remove_bus_device - remove a PCI device and any children
78 * @dev: the device to remove
79 *
80 * Remove a PCI device from the device lists, informing the drivers
81 * that the device has been removed. We also remove any subordinate
82 * buses and children in a depth-first manner.
83 *
84 * For each device we remove, delete the device structure from the
85 * device lists, remove the /proc entry, and notify userspace
86 * (/sbin/hotplug).
87 */
88 void pci_remove_bus_device(struct pci_dev *dev)
89 {
90 if (dev->subordinate) {
91 struct pci_bus *b = dev->subordinate;
93 pci_remove_behind_bridge(dev);
94 pci_remove_bus(b);
95 dev->subordinate = NULL;
96 }
98 pci_destroy_dev(dev);
99 }
101 /**
102 * pci_remove_behind_bridge - remove all devices behind a PCI bridge
103 * @dev: PCI bridge device
104 *
105 * Remove all devices on the bus, except for the parent bridge.
106 * This also removes any child buses, and any devices they may
107 * contain in a depth-first manner.
108 */
109 void pci_remove_behind_bridge(struct pci_dev *dev)
110 {
111 struct list_head *l, *n;
113 if (dev->subordinate) {
114 list_for_each_safe(l, n, &dev->subordinate->devices) {
115 struct pci_dev *dev = pci_dev_b(l);
117 pci_remove_bus_device(dev);
118 }
119 }
120 }
122 EXPORT_SYMBOL(pci_remove_bus_device);
123 EXPORT_SYMBOL(pci_remove_behind_bridge);