ia64/linux-2.6.18-xen.hg

view drivers/pci/bus.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 f7a2c0985f99
children
line source
1 /*
2 * drivers/pci/bus.c
3 *
4 * From setup-res.c, by:
5 * Dave Rusling (david.rusling@reo.mts.dec.com)
6 * David Mosberger (davidm@cs.arizona.edu)
7 * David Miller (davem@redhat.com)
8 * Ivan Kokshaysky (ink@jurassic.park.msu.ru)
9 */
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/pci.h>
13 #include <linux/errno.h>
14 #include <linux/ioport.h>
15 #include <linux/proc_fs.h>
16 #include <linux/init.h>
18 #include "pci.h"
20 /**
21 * pci_bus_alloc_resource - allocate a resource from a parent bus
22 * @bus: PCI bus
23 * @res: resource to allocate
24 * @size: size of resource to allocate
25 * @align: alignment of resource to allocate
26 * @min: minimum /proc/iomem address to allocate
27 * @type_mask: IORESOURCE_* type flags
28 * @alignf: resource alignment function
29 * @alignf_data: data argument for resource alignment function
30 *
31 * Given the PCI bus a device resides on, the size, minimum address,
32 * alignment and type, try to find an acceptable resource allocation
33 * for a specific device resource.
34 */
35 int
36 pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
37 resource_size_t size, resource_size_t align,
38 resource_size_t min, unsigned int type_mask,
39 void (*alignf)(void *, struct resource *, resource_size_t,
40 resource_size_t),
41 void *alignf_data)
42 {
43 int i, ret = -ENOMEM;
45 type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
47 for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
48 struct resource *r = bus->resource[i];
49 if (!r)
50 continue;
52 /* type_mask must match */
53 if ((res->flags ^ r->flags) & type_mask)
54 continue;
56 /* We cannot allocate a non-prefetching resource
57 from a pre-fetching area */
58 if ((r->flags & IORESOURCE_PREFETCH) &&
59 !(res->flags & IORESOURCE_PREFETCH))
60 continue;
62 /* Ok, try it out.. */
63 ret = allocate_resource(r, res, size,
64 r->start ? : min,
65 -1, align,
66 alignf, alignf_data);
67 if (ret == 0)
68 break;
69 }
70 return ret;
71 }
73 /**
74 * add a single device
75 * @dev: device to add
76 *
77 * This adds a single pci device to the global
78 * device list and adds sysfs and procfs entries
79 */
80 void __devinit pci_bus_add_device(struct pci_dev *dev)
81 {
82 device_add(&dev->dev);
84 down_write(&pci_bus_sem);
85 list_add_tail(&dev->global_list, &pci_devices);
86 up_write(&pci_bus_sem);
88 pci_proc_attach_device(dev);
89 pci_create_sysfs_dev_files(dev);
90 }
92 /**
93 * pci_bus_add_devices - insert newly discovered PCI devices
94 * @bus: bus to check for new devices
95 *
96 * Add newly discovered PCI devices (which are on the bus->devices
97 * list) to the global PCI device list, add the sysfs and procfs
98 * entries. Where a bridge is found, add the discovered bus to
99 * the parents list of child buses, and recurse (breadth-first
100 * to be compatible with 2.4)
101 *
102 * Call hotplug for each new devices.
103 */
104 void __devinit pci_bus_add_devices(struct pci_bus *bus)
105 {
106 struct pci_dev *dev;
108 list_for_each_entry(dev, &bus->devices, bus_list) {
109 /*
110 * Skip already-present devices (which are on the
111 * global device list.)
112 */
113 if (!list_empty(&dev->global_list))
114 continue;
115 pci_bus_add_device(dev);
116 }
118 list_for_each_entry(dev, &bus->devices, bus_list) {
120 BUG_ON(list_empty(&dev->global_list));
122 /*
123 * If there is an unattached subordinate bus, attach
124 * it and then scan for unattached PCI devices.
125 */
126 if (dev->subordinate) {
127 if (list_empty(&dev->subordinate->node)) {
128 down_write(&pci_bus_sem);
129 list_add_tail(&dev->subordinate->node,
130 &dev->bus->children);
131 up_write(&pci_bus_sem);
132 }
133 pci_bus_add_devices(dev->subordinate);
135 sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge");
136 }
137 }
138 }
140 void pci_enable_bridges(struct pci_bus *bus)
141 {
142 struct pci_dev *dev;
143 int retval;
145 list_for_each_entry(dev, &bus->devices, bus_list) {
146 if (dev->subordinate) {
147 retval = pci_enable_device(dev);
148 pci_set_master(dev);
149 pci_enable_bridges(dev->subordinate);
150 }
151 }
152 }
154 /** pci_walk_bus - walk devices on/under bus, calling callback.
155 * @top bus whose devices should be walked
156 * @cb callback to be called for each device found
157 * @userdata arbitrary pointer to be passed to callback.
158 *
159 * Walk the given bus, including any bridged devices
160 * on buses under this bus. Call the provided callback
161 * on each device found.
162 */
163 void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
164 void *userdata)
165 {
166 struct pci_dev *dev;
167 struct pci_bus *bus;
168 struct list_head *next;
170 bus = top;
171 down_read(&pci_bus_sem);
172 next = top->devices.next;
173 for (;;) {
174 if (next == &bus->devices) {
175 /* end of this bus, go up or finish */
176 if (bus == top)
177 break;
178 next = bus->self->bus_list.next;
179 bus = bus->self->bus;
180 continue;
181 }
182 dev = list_entry(next, struct pci_dev, bus_list);
183 if (dev->subordinate) {
184 /* this is a pci-pci bridge, do its devices next */
185 next = dev->subordinate->devices.next;
186 bus = dev->subordinate;
187 } else
188 next = dev->bus_list.next;
190 /* Run device routines with the device locked */
191 down(&dev->dev.sem);
192 cb(dev, userdata);
193 up(&dev->dev.sem);
194 }
195 up_read(&pci_bus_sem);
196 }
197 EXPORT_SYMBOL_GPL(pci_walk_bus);
199 EXPORT_SYMBOL(pci_bus_alloc_resource);
200 EXPORT_SYMBOL_GPL(pci_bus_add_device);
201 EXPORT_SYMBOL(pci_bus_add_devices);
202 EXPORT_SYMBOL(pci_enable_bridges);