ia64/linux-2.6.18-xen.hg

annotate drivers/pci/setup-res.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 dfd2adc58740
children
rev   line source
ian@0 1 /*
ian@0 2 * drivers/pci/setup-res.c
ian@0 3 *
ian@0 4 * Extruded from code written by
ian@0 5 * Dave Rusling (david.rusling@reo.mts.dec.com)
ian@0 6 * David Mosberger (davidm@cs.arizona.edu)
ian@0 7 * David Miller (davem@redhat.com)
ian@0 8 *
ian@0 9 * Support routines for initializing a PCI subsystem.
ian@0 10 */
ian@0 11
ian@0 12 /* fixed for multiple pci buses, 1999 Andrea Arcangeli <andrea@suse.de> */
ian@0 13
ian@0 14 /*
ian@0 15 * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
ian@0 16 * Resource sorting
ian@0 17 */
ian@0 18
ian@0 19 #include <linux/init.h>
ian@0 20 #include <linux/kernel.h>
ian@0 21 #include <linux/pci.h>
ian@0 22 #include <linux/errno.h>
ian@0 23 #include <linux/ioport.h>
ian@0 24 #include <linux/cache.h>
ian@0 25 #include <linux/slab.h>
ian@0 26 #include "pci.h"
ian@0 27
ian@0 28
ian@0 29 void
keir@815 30 pci_update_resource(struct pci_dev *dev, int resno)
ian@0 31 {
ian@0 32 struct pci_bus_region region;
ian@0 33 u32 new, check, mask;
ian@0 34 int reg;
keir@818 35 enum pci_bar_type type;
keir@815 36 struct resource *res = dev->resource + resno;
ian@0 37
ian@0 38 /* Ignore resources for unimplemented BARs and unused resource slots
ian@0 39 for 64 bit BARs. */
ian@0 40 if (!res->flags)
ian@0 41 return;
ian@0 42
ian@0 43 pcibios_resource_to_bus(dev, &region, res);
ian@0 44
ian@0 45 pr_debug(" got res [%llx:%llx] bus [%lx:%lx] flags %lx for "
ian@0 46 "BAR %d of %s\n", (unsigned long long)res->start,
ian@0 47 (unsigned long long)res->end,
ian@0 48 region.start, region.end, res->flags, resno, pci_name(dev));
ian@0 49
ian@0 50 new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
ian@0 51 if (res->flags & IORESOURCE_IO)
ian@0 52 mask = (u32)PCI_BASE_ADDRESS_IO_MASK;
ian@0 53 else
ian@0 54 mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
ian@0 55
keir@818 56 reg = pci_resource_bar(dev, resno, &type);
keir@818 57 if (!reg)
keir@818 58 return;
keir@818 59 if (type != pci_bar_unknown) {
ian@0 60 if (!(res->flags & IORESOURCE_ROM_ENABLE))
ian@0 61 return;
ian@0 62 new |= PCI_ROM_ADDRESS_ENABLE;
ian@0 63 }
ian@0 64
ian@0 65 pci_write_config_dword(dev, reg, new);
ian@0 66 pci_read_config_dword(dev, reg, &check);
ian@0 67
ian@0 68 if ((new ^ check) & mask) {
ian@0 69 printk(KERN_ERR "PCI: Error while updating region "
ian@0 70 "%s/%d (%08x != %08x)\n", pci_name(dev), resno,
ian@0 71 new, check);
ian@0 72 }
ian@0 73
ian@0 74 if ((new & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
ian@0 75 (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) {
ian@0 76 new = region.start >> 16 >> 16;
ian@0 77 pci_write_config_dword(dev, reg + 4, new);
ian@0 78 pci_read_config_dword(dev, reg + 4, &check);
ian@0 79 if (check != new) {
ian@0 80 printk(KERN_ERR "PCI: Error updating region "
ian@0 81 "%s/%d (high %08x != %08x)\n",
ian@0 82 pci_name(dev), resno, new, check);
ian@0 83 }
ian@0 84 }
ian@0 85 res->flags &= ~IORESOURCE_UNSET;
ian@0 86 pr_debug("PCI: moved device %s resource %d (%lx) to %x\n",
ian@0 87 pci_name(dev), resno, res->flags,
ian@0 88 new & ~PCI_REGION_FLAG_MASK);
ian@0 89 }
ian@0 90
ian@0 91 int __devinit
ian@0 92 pci_claim_resource(struct pci_dev *dev, int resource)
ian@0 93 {
ian@0 94 struct resource *res = &dev->resource[resource];
ian@0 95 struct resource *root = NULL;
ian@0 96 char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
ian@0 97 int err;
ian@0 98
ian@0 99 root = pcibios_select_root(dev, res);
ian@0 100
ian@0 101 err = -EINVAL;
ian@0 102 if (root != NULL)
ian@0 103 err = insert_resource(root, res);
ian@0 104
ian@0 105 if (err) {
ian@0 106 printk(KERN_ERR "PCI: %s region %d of %s %s [%llx:%llx]\n",
ian@0 107 root ? "Address space collision on" :
ian@0 108 "No parent found for",
ian@0 109 resource, dtype, pci_name(dev),
ian@0 110 (unsigned long long)res->start,
ian@0 111 (unsigned long long)res->end);
ian@0 112 }
ian@0 113
ian@0 114 return err;
ian@0 115 }
ian@0 116 EXPORT_SYMBOL_GPL(pci_claim_resource);
ian@0 117
keir@701 118 #ifdef CONFIG_PCI_REASSIGN
keir@702 119 void pci_disable_bridge_window(struct pci_dev *dev)
keir@696 120 {
keir@702 121 printk(KERN_DEBUG "PCI: Disable bridge window on %s\n", pci_name(dev));
keir@702 122
keir@702 123 /* MMIO Base/Limit */
keir@702 124 pci_write_config_dword(dev, PCI_MEMORY_BASE, 0x0000fff0);
keir@702 125
keir@702 126 /* Prefetchable MMIO Base/Limit */
keir@702 127 pci_write_config_dword(dev, PCI_PREF_LIMIT_UPPER32, 0);
keir@702 128 pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0x0000fff0);
keir@702 129 pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0xffffffff);
keir@696 130 }
keir@701 131 #endif
keir@696 132
ian@0 133 int pci_assign_resource(struct pci_dev *dev, int resno)
ian@0 134 {
ian@0 135 struct pci_bus *bus = dev->bus;
ian@0 136 struct resource *res = dev->resource + resno;
ian@0 137 resource_size_t size, min, align;
ian@0 138 int ret;
keir@771 139 int reassigndev = pci_is_reassigndev(dev);
ian@0 140
ian@0 141 size = res->end - res->start + 1;
ian@0 142 min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
ian@0 143 /* The bridge resources are special, as their
ian@0 144 size != alignment. Sizing routines return
ian@0 145 required alignment in the "start" field. */
keir@696 146 if (resno < PCI_BRIDGE_RESOURCES) {
keir@696 147 align = size;
keir@696 148 if ((reassigndev) &&
keir@696 149 (res->flags & IORESOURCE_MEM)) {
keir@701 150 align = ALIGN(align, PAGE_SIZE);
keir@696 151 }
keir@696 152 } else {
keir@696 153 align = res->start;
keir@696 154 }
ian@0 155
ian@0 156 /* First, try exact prefetching match.. */
ian@0 157 ret = pci_bus_alloc_resource(bus, res, size, align, min,
ian@0 158 IORESOURCE_PREFETCH,
ian@0 159 pcibios_align_resource, dev);
ian@0 160
ian@0 161 if (ret < 0 && (res->flags & IORESOURCE_PREFETCH)) {
ian@0 162 /*
ian@0 163 * That failed.
ian@0 164 *
ian@0 165 * But a prefetching area can handle a non-prefetching
ian@0 166 * window (it will just not perform as well).
ian@0 167 */
ian@0 168 ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
ian@0 169 pcibios_align_resource, dev);
ian@0 170 }
ian@0 171
ian@0 172 if (ret) {
ian@0 173 printk(KERN_ERR "PCI: Failed to allocate %s resource "
ian@0 174 "#%d:%llx@%llx for %s\n",
ian@0 175 res->flags & IORESOURCE_IO ? "I/O" : "mem",
ian@0 176 resno, (unsigned long long)size,
ian@0 177 (unsigned long long)res->start, pci_name(dev));
ian@0 178 } else if (resno < PCI_BRIDGE_RESOURCES) {
keir@703 179 if (reassigndev)
keir@701 180 printk(KERN_DEBUG "PCI: Assign resource(%d) on %s "
keir@701 181 "%016llx - %016llx\n", resno, pci_name(dev),
keir@701 182 (unsigned long long)res->start,
keir@701 183 (unsigned long long)res->end);
keir@815 184 pci_update_resource(dev, resno);
ian@0 185 }
ian@0 186
ian@0 187 return ret;
ian@0 188 }
ian@0 189
ian@0 190 #ifdef CONFIG_EMBEDDED
ian@0 191 int pci_assign_resource_fixed(struct pci_dev *dev, int resno)
ian@0 192 {
ian@0 193 struct pci_bus *bus = dev->bus;
ian@0 194 struct resource *res = dev->resource + resno;
ian@0 195 unsigned int type_mask;
ian@0 196 int i, ret = -EBUSY;
ian@0 197
ian@0 198 type_mask = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH;
ian@0 199
ian@0 200 for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
ian@0 201 struct resource *r = bus->resource[i];
ian@0 202 if (!r)
ian@0 203 continue;
ian@0 204
ian@0 205 /* type_mask must match */
ian@0 206 if ((res->flags ^ r->flags) & type_mask)
ian@0 207 continue;
ian@0 208
ian@0 209 ret = request_resource(r, res);
ian@0 210
ian@0 211 if (ret == 0)
ian@0 212 break;
ian@0 213 }
ian@0 214
ian@0 215 if (ret) {
ian@0 216 printk(KERN_ERR "PCI: Failed to allocate %s resource "
ian@0 217 "#%d:%llx@%llx for %s\n",
ian@0 218 res->flags & IORESOURCE_IO ? "I/O" : "mem",
ian@0 219 resno, (unsigned long long)(res->end - res->start + 1),
ian@0 220 (unsigned long long)res->start, pci_name(dev));
ian@0 221 } else if (resno < PCI_BRIDGE_RESOURCES) {
keir@815 222 pci_update_resource(dev, resno);
ian@0 223 }
ian@0 224
ian@0 225 return ret;
ian@0 226 }
ian@0 227 EXPORT_SYMBOL_GPL(pci_assign_resource_fixed);
ian@0 228 #endif
ian@0 229
ian@0 230 /* Sort resources by alignment */
ian@0 231 void __devinit
ian@0 232 pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
ian@0 233 {
ian@0 234 int i;
keir@771 235 int reassigndev = pci_is_reassigndev(dev);
ian@0 236
ian@0 237 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
ian@0 238 struct resource *r;
ian@0 239 struct resource_list *list, *tmp;
ian@0 240 resource_size_t r_align;
ian@0 241
ian@0 242 r = &dev->resource[i];
ian@0 243 r_align = r->end - r->start;
ian@0 244
ian@0 245 if (!(r->flags) || r->parent)
ian@0 246 continue;
keir@746 247
ian@0 248 if (!r_align) {
ian@0 249 printk(KERN_WARNING "PCI: Ignore bogus resource %d "
ian@0 250 "[%llx:%llx] of %s\n",
ian@0 251 i, (unsigned long long)r->start,
ian@0 252 (unsigned long long)r->end, pci_name(dev));
ian@0 253 continue;
ian@0 254 }
ian@0 255 r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start;
keir@862 256
keir@862 257 if (i < PCI_BRIDGE_RESOURCES && (r->flags & IORESOURCE_MEM) &&
keir@862 258 reassigndev)
keir@862 259 r_align = ALIGN(r_align, PAGE_SIZE);
keir@862 260
ian@0 261 for (list = head; ; list = list->next) {
ian@0 262 resource_size_t align = 0;
ian@0 263 struct resource_list *ln = list->next;
ian@0 264 int idx;
ian@0 265
ian@0 266 if (ln) {
ian@0 267 idx = ln->res - &ln->dev->resource[0];
ian@0 268 align = (idx < PCI_BRIDGE_RESOURCES) ?
ian@0 269 ln->res->end - ln->res->start + 1 :
ian@0 270 ln->res->start;
keir@746 271 if ((idx < PCI_BRIDGE_RESOURCES) &&
keir@746 272 (ln->res->flags & IORESOURCE_MEM) &&
keir@771 273 pci_is_reassigndev(ln->dev))
keir@746 274 align = ALIGN(align, PAGE_SIZE);
ian@0 275 }
ian@0 276 if (r_align > align) {
ian@0 277 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
ian@0 278 if (!tmp)
ian@0 279 panic("pdev_sort_resources(): "
ian@0 280 "kmalloc() failed!\n");
ian@0 281 tmp->next = ln;
ian@0 282 tmp->res = r;
ian@0 283 tmp->dev = dev;
ian@0 284 list->next = tmp;
ian@0 285 break;
ian@0 286 }
ian@0 287 }
ian@0 288 }
ian@0 289 }