ia64/linux-2.6.18-xen.hg

annotate drivers/pci/iomulti.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
children b998614e2e2a
rev   line source
keir@882 1 /*
keir@882 2 * This program is free software; you can redistribute it and/or modify
keir@882 3 * it under the terms of the GNU General Public License as published by
keir@882 4 * the Free Software Foundation; either version 2 of the License, or
keir@882 5 * (at your option) any later version.
keir@882 6 *
keir@882 7 * This program is distributed in the hope that it will be useful,
keir@882 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
keir@882 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
keir@882 10 * GNU General Public License for more details.
keir@882 11 *
keir@882 12 * You should have received a copy of the GNU General Public License
keir@882 13 * along with this program; if not, write to the Free Software
keir@882 14 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
keir@882 15 *
keir@882 16 * Copyright (c) 2009 Isaku Yamahata
keir@882 17 * VA Linux Systems Japan K.K.
keir@882 18 *
keir@882 19 */
keir@882 20
keir@882 21 #include <linux/kernel.h>
keir@882 22 #include <linux/list.h>
keir@882 23 #include <linux/miscdevice.h>
keir@882 24 #include <linux/pci.h>
keir@882 25 #include <linux/sort.h>
keir@882 26
keir@882 27 #include <asm/setup.h>
keir@882 28 #include <asm/uaccess.h>
keir@882 29
keir@882 30 #include "iomulti.h"
keir@882 31
keir@882 32 #define PCI_NUM_BARS 6
keir@882 33 #define PCI_BUS_MAX 255
keir@882 34 #define PCI_DEV_MAX 31
keir@882 35 #define PCI_FUNC_MAX 7
keir@882 36 #define PCI_NUM_FUNC 8
keir@882 37
keir@882 38 /* see pci_resource_len */
keir@882 39 static inline resource_size_t pci_iomul_len(const struct resource* r)
keir@882 40 {
keir@882 41 if (r->start == 0 && r->start == r->end)
keir@882 42 return 0;
keir@882 43 return r->end - r->start + 1;
keir@882 44 }
keir@882 45
keir@882 46 #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
keir@882 47 /* stolen from pbus_size_io() */
keir@882 48 static unsigned long pdev_size_io(struct pci_dev *pdev)
keir@882 49 {
keir@882 50 unsigned long size = 0, size1 = 0;
keir@882 51 int i;
keir@882 52
keir@882 53 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
keir@882 54 struct resource *r = &pdev->resource[i];
keir@882 55 unsigned long r_size;
keir@882 56
keir@882 57 if (!(r->flags & IORESOURCE_IO))
keir@882 58 continue;
keir@882 59
keir@882 60 r_size = r->end - r->start + 1;
keir@882 61
keir@882 62 if (r_size < 0x400)
keir@882 63 /* Might be re-aligned for ISA */
keir@882 64 size += r_size;
keir@882 65 else
keir@882 66 size1 += r_size;
keir@882 67 }
keir@882 68
keir@882 69 /* To be fixed in 2.5: we should have sort of HAVE_ISA
keir@882 70 flag in the struct pci_bus. */
keir@882 71 #if defined(CONFIG_ISA) || defined(CONFIG_EISA)
keir@882 72 size = (size & 0xff) + ((size & ~0xffUL) << 2);
keir@882 73 #endif
keir@882 74 size = ROUND_UP(size + size1, 4096);
keir@882 75 return size;
keir@882 76 }
keir@882 77
keir@882 78 /*
keir@882 79 * primary bus number of PCI-PCI bridge in switch on which
keir@882 80 * this slots sits.
keir@882 81 * i.e. the primary bus number of PCI-PCI bridge of downstream port
keir@882 82 * or root port in switch.
keir@882 83 * the secondary bus number of PCI-PCI bridge of upstream port
keir@882 84 * in switch.
keir@882 85 */
keir@882 86 static inline unsigned char pci_dev_switch_busnr(struct pci_dev *pdev)
keir@882 87 {
keir@882 88 if (pci_find_capability(pdev, PCI_CAP_ID_EXP))
keir@882 89 return pdev->bus->primary;
keir@882 90 return pdev->bus->number;
keir@882 91 }
keir@882 92
keir@882 93 struct pci_iomul_func {
keir@882 94 int segment;
keir@882 95 uint8_t bus;
keir@882 96 uint8_t devfn;
keir@882 97
keir@882 98 /* only start and end are used */
keir@882 99 unsigned long io_size;
keir@882 100 uint8_t io_bar;
keir@882 101 struct resource resource[PCI_NUM_BARS];
keir@882 102 struct resource dummy_parent;
keir@882 103 };
keir@882 104
keir@882 105 struct pci_iomul_switch {
keir@882 106 struct list_head list; /* bus_list_lock protects */
keir@882 107
keir@882 108 /*
keir@882 109 * This lock the following entry and following
keir@882 110 * pci_iomul_slot/pci_iomul_func.
keir@882 111 */
keir@882 112 struct mutex lock;
keir@882 113 struct kref kref;
keir@882 114
keir@882 115 struct resource io_resource;
keir@882 116 struct resource *io_region;
keir@882 117 unsigned int count;
keir@882 118 struct pci_dev *current_pdev;
keir@882 119
keir@882 120 int segment;
keir@882 121 uint8_t bus;
keir@882 122
keir@882 123 uint32_t io_base;
keir@882 124 uint32_t io_limit;
keir@882 125
keir@882 126 /* func which has the largeset io size*/
keir@882 127 struct pci_iomul_func *func;
keir@882 128
keir@882 129 struct list_head slots;
keir@882 130 };
keir@882 131
keir@882 132 struct pci_iomul_slot {
keir@882 133 struct list_head sibling;
keir@882 134 struct kref kref;
keir@882 135 /*
keir@882 136 * busnr
keir@882 137 * when pcie, the primary busnr of the PCI-PCI bridge on which
keir@882 138 * this devices sits.
keir@882 139 */
keir@882 140 uint8_t switch_busnr;
keir@882 141 struct resource dummy_parent[PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES];
keir@882 142
keir@882 143 /* device */
keir@882 144 int segment;
keir@882 145 uint8_t bus;
keir@882 146 uint8_t dev;
keir@882 147
keir@882 148 struct pci_iomul_func *func[PCI_NUM_FUNC];
keir@882 149 };
keir@882 150
keir@882 151 static LIST_HEAD(switch_list);
keir@882 152 static DEFINE_MUTEX(switch_list_lock);
keir@882 153
keir@882 154 /*****************************************************************************/
keir@882 155 static int inline pci_iomul_switch_io_allocated(
keir@882 156 const struct pci_iomul_switch *sw)
keir@882 157 {
keir@882 158 return !(sw->io_base == 0 || sw->io_base > sw->io_limit);
keir@882 159 }
keir@882 160
keir@882 161 static struct pci_iomul_switch *pci_iomul_find_switch_locked(int segment,
keir@882 162 uint8_t bus)
keir@882 163 {
keir@882 164 struct pci_iomul_switch *sw;
keir@882 165
keir@882 166 BUG_ON(!mutex_is_locked(&switch_list_lock));
keir@882 167 list_for_each_entry(sw, &switch_list, list) {
keir@882 168 if (sw->segment == segment && sw->bus == bus)
keir@882 169 return sw;
keir@882 170 }
keir@882 171 return NULL;
keir@882 172 }
keir@882 173
keir@882 174 static struct pci_iomul_slot *pci_iomul_find_slot_locked(
keir@882 175 struct pci_iomul_switch *sw, uint8_t busnr, uint8_t dev)
keir@882 176 {
keir@882 177 struct pci_iomul_slot *slot;
keir@882 178
keir@882 179 BUG_ON(!mutex_is_locked(&sw->lock));
keir@882 180 list_for_each_entry(slot, &sw->slots, sibling) {
keir@882 181 if (slot->bus == busnr && slot->dev == dev)
keir@882 182 return slot;
keir@882 183 }
keir@882 184 return NULL;
keir@882 185 }
keir@882 186
keir@882 187 static void pci_iomul_switch_get(struct pci_iomul_switch *sw);
keir@882 188 /* on successfull exit, sw->lock is locked for use slot and
keir@882 189 * refrence count of sw is incremented.
keir@882 190 */
keir@882 191 static void pci_iomul_get_lock_switch(struct pci_dev *pdev,
keir@882 192 struct pci_iomul_switch **swp,
keir@882 193 struct pci_iomul_slot **slot)
keir@882 194 {
keir@882 195 mutex_lock(&switch_list_lock);
keir@882 196
keir@882 197 *swp = pci_iomul_find_switch_locked(pci_domain_nr(pdev->bus),
keir@882 198 pci_dev_switch_busnr(pdev));
keir@882 199 if (*swp == NULL) {
keir@882 200 *slot = NULL;
keir@882 201 goto out;
keir@882 202 }
keir@882 203
keir@882 204 mutex_lock(&(*swp)->lock);
keir@882 205 *slot = pci_iomul_find_slot_locked(*swp, pdev->bus->number,
keir@882 206 PCI_SLOT(pdev->devfn));
keir@882 207 if (*slot == NULL) {
keir@882 208 mutex_unlock(&(*swp)->lock);
keir@882 209 *swp = NULL;
keir@882 210 } else {
keir@882 211 pci_iomul_switch_get(*swp);
keir@882 212 }
keir@882 213 out:
keir@882 214 mutex_unlock(&switch_list_lock);
keir@882 215 }
keir@882 216
keir@882 217 static struct pci_iomul_switch *pci_iomul_switch_alloc(int segment,
keir@882 218 uint8_t bus)
keir@882 219 {
keir@882 220 struct pci_iomul_switch *sw;
keir@882 221
keir@882 222 BUG_ON(!mutex_is_locked(&switch_list_lock));
keir@882 223
keir@882 224 sw = kmalloc(sizeof(*sw), GFP_KERNEL);
keir@882 225
keir@882 226 mutex_init(&sw->lock);
keir@882 227 kref_init(&sw->kref);
keir@882 228 sw->io_region = NULL;
keir@882 229 sw->count = 0;
keir@882 230 sw->current_pdev = NULL;
keir@882 231 sw->segment = segment;
keir@882 232 sw->bus = bus;
keir@882 233 sw->io_base = 0;
keir@882 234 sw->io_limit = 0;
keir@882 235 sw->func = NULL;
keir@882 236 INIT_LIST_HEAD(&sw->slots);
keir@882 237
keir@882 238 return sw;
keir@882 239 }
keir@882 240
keir@882 241 static void pci_iomul_switch_add_locked(struct pci_iomul_switch *sw)
keir@882 242 {
keir@882 243 BUG_ON(!mutex_is_locked(&switch_list_lock));
keir@882 244 list_add(&sw->list, &switch_list);
keir@882 245 }
keir@882 246
keir@882 247 #ifdef CONFIG_HOTPLUG_PCI
keir@882 248 static void pci_iomul_switch_del_locked(struct pci_iomul_switch *sw)
keir@882 249 {
keir@882 250 BUG_ON(!mutex_is_locked(&switch_list_lock));
keir@882 251 list_del(&sw->list);
keir@882 252 }
keir@882 253 #endif
keir@882 254
keir@882 255 static void pci_iomul_switch_get(struct pci_iomul_switch *sw)
keir@882 256 {
keir@882 257 kref_get(&sw->kref);
keir@882 258 }
keir@882 259
keir@882 260 static void pci_iomul_switch_release(struct kref *kref)
keir@882 261 {
keir@882 262 struct pci_iomul_switch *sw = container_of(kref,
keir@882 263 struct pci_iomul_switch,
keir@882 264 kref);
keir@882 265 kfree(sw);
keir@882 266 }
keir@882 267
keir@882 268 static void pci_iomul_switch_put(struct pci_iomul_switch *sw)
keir@882 269 {
keir@882 270 kref_put(&sw->kref, &pci_iomul_switch_release);
keir@882 271 }
keir@882 272
keir@882 273 static int __devinit pci_iomul_slot_init(struct pci_dev *pdev,
keir@882 274 struct pci_iomul_slot *slot)
keir@882 275 {
keir@882 276 u16 rpcap;
keir@882 277 u16 cap;
keir@882 278
keir@882 279 rpcap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
keir@882 280 if (!rpcap) {
keir@882 281 /* pci device isn't supported */
keir@882 282 printk(KERN_INFO
keir@882 283 "PCI: sharing io port of non PCIe device %s "
keir@882 284 "isn't supported. ignoring.\n",
keir@882 285 pci_name(pdev));
keir@882 286 return -ENOSYS;
keir@882 287 }
keir@882 288
keir@882 289 pci_read_config_word(pdev, rpcap + PCI_CAP_FLAGS, &cap);
keir@882 290 switch ((cap & PCI_EXP_FLAGS_TYPE) >> 4) {
keir@882 291 case PCI_EXP_TYPE_RC_END:
keir@882 292 printk(KERN_INFO
keir@882 293 "PCI: io port sharing of root complex integrated "
keir@882 294 "endpoint %s isn't supported. ignoring.\n",
keir@882 295 pci_name(pdev));
keir@882 296 return -ENOSYS;
keir@882 297 case PCI_EXP_TYPE_ENDPOINT:
keir@882 298 case PCI_EXP_TYPE_LEG_END:
keir@882 299 break;
keir@882 300 default:
keir@882 301 printk(KERN_INFO
keir@882 302 "PCI: io port sharing of non endpoint %s "
keir@882 303 "doesn't make sense. ignoring.\n",
keir@882 304 pci_name(pdev));
keir@882 305 return -EINVAL;
keir@882 306 }
keir@882 307
keir@882 308 kref_init(&slot->kref);
keir@882 309 slot->switch_busnr = pci_dev_switch_busnr(pdev);
keir@882 310 slot->segment = pci_domain_nr(pdev->bus);
keir@882 311 slot->bus = pdev->bus->number;
keir@882 312 slot->dev = PCI_SLOT(pdev->devfn);
keir@882 313
keir@882 314 return 0;
keir@882 315 }
keir@882 316
keir@882 317 static struct pci_iomul_slot *pci_iomul_slot_alloc(struct pci_dev *pdev)
keir@882 318 {
keir@882 319 struct pci_iomul_slot *slot;
keir@882 320
keir@882 321 slot = kzalloc(sizeof(*slot), GFP_KERNEL);
keir@882 322 if (slot == NULL)
keir@882 323 return NULL;
keir@882 324
keir@882 325 if (pci_iomul_slot_init(pdev, slot) != 0) {
keir@882 326 kfree(slot);
keir@882 327 return NULL;
keir@882 328 }
keir@882 329 return slot;
keir@882 330 }
keir@882 331
keir@882 332 static void pci_iomul_slot_add_locked(struct pci_iomul_switch *sw,
keir@882 333 struct pci_iomul_slot *slot)
keir@882 334 {
keir@882 335 BUG_ON(!mutex_is_locked(&sw->lock));
keir@882 336 list_add(&slot->sibling, &sw->slots);
keir@882 337 }
keir@882 338
keir@882 339 #ifdef CONFIG_HOTPLUG_PCI
keir@882 340 static void pci_iomul_slot_del_locked(struct pci_iomul_switch *sw,
keir@882 341 struct pci_iomul_slot *slot)
keir@882 342 {
keir@882 343 BUG_ON(!mutex_is_locked(&sw->lock));
keir@882 344 list_del(&slot->sibling);
keir@882 345 }
keir@882 346 #endif
keir@882 347
keir@882 348 static void pci_iomul_slot_get(struct pci_iomul_slot *slot)
keir@882 349 {
keir@882 350 kref_get(&slot->kref);
keir@882 351 }
keir@882 352
keir@882 353 static void pci_iomul_slot_release(struct kref *kref)
keir@882 354 {
keir@882 355 struct pci_iomul_slot *slot = container_of(kref, struct pci_iomul_slot,
keir@882 356 kref);
keir@882 357 kfree(slot);
keir@882 358 }
keir@882 359
keir@882 360 static void pci_iomul_slot_put(struct pci_iomul_slot *slot)
keir@882 361 {
keir@882 362 kref_put(&slot->kref, &pci_iomul_slot_release);
keir@882 363 }
keir@882 364
keir@882 365 /*****************************************************************************/
keir@882 366 static int pci_get_sbd(const char *str,
keir@882 367 int *segment__, uint8_t *bus__, uint8_t *dev__)
keir@882 368 {
keir@882 369 int segment;
keir@882 370 int bus;
keir@882 371 int dev;
keir@882 372
keir@882 373 if (sscanf(str, "%x:%x:%x", &segment, &bus, &dev) != 3) {
keir@882 374 if (sscanf(str, "%x:%x", &bus, &dev) == 2)
keir@882 375 segment = 0;
keir@882 376 else
keir@882 377 return -EINVAL;
keir@882 378 }
keir@882 379
keir@882 380 if (segment < 0 || INT_MAX <= segment)
keir@882 381 return -EINVAL;
keir@882 382 if (bus < 0 || PCI_BUS_MAX < bus)
keir@882 383 return -EINVAL;
keir@882 384 if (dev < 0 || PCI_DEV_MAX < dev)
keir@882 385 return -EINVAL;
keir@882 386
keir@882 387 *segment__ = segment;
keir@882 388 *bus__ = bus;
keir@882 389 *dev__ = dev;
keir@882 390 return 0;
keir@882 391 }
keir@882 392
keir@882 393 static char iomul_param[COMMAND_LINE_SIZE];
keir@882 394 #define TOKEN_MAX 10 /* SSSS:BB:DD length is 10 */
keir@882 395 static int pci_is_iomul_dev_param(struct pci_dev *pdev)
keir@882 396 {
keir@882 397 int len;
keir@882 398 char *p;
keir@882 399 char *next_str;
keir@882 400
keir@882 401 for (p = &iomul_param[0]; *p != '\0'; p = next_str + 1) {
keir@882 402 next_str = strchr(p, ',');
keir@882 403 if (next_str != NULL)
keir@882 404 len = next_str - p;
keir@882 405 else
keir@882 406 len = strlen(p);
keir@882 407
keir@882 408 if (len > 0 && len <= TOKEN_MAX) {
keir@882 409 char tmp[TOKEN_MAX+1];
keir@882 410 int seg;
keir@882 411 uint8_t bus;
keir@882 412 uint8_t dev;
keir@882 413
keir@882 414 strncpy(tmp, p, len);
keir@882 415 *(tmp + len) = '\0';
keir@882 416 if (pci_get_sbd(tmp, &seg, &bus, &dev) == 0 &&
keir@882 417 pci_domain_nr(pdev->bus) == seg &&
keir@882 418 pdev->bus->number == bus &&
keir@882 419 PCI_SLOT(pdev->devfn) == dev)
keir@882 420 return 1;
keir@882 421 }
keir@882 422 if (next_str == NULL)
keir@882 423 break;
keir@882 424 }
keir@882 425
keir@882 426 return 0;
keir@882 427 }
keir@882 428
keir@882 429 /*
keir@882 430 * Format: [<segment>:]<bus>:<dev>[,[<segment>:]<bus>:<dev>[,...]
keir@882 431 */
keir@882 432 static int __init pci_iomul_param_setup(char *str)
keir@882 433 {
keir@882 434 if (strlen(str) >= COMMAND_LINE_SIZE)
keir@882 435 return 0;
keir@882 436
keir@882 437 /* parse it after pci bus scanning */
keir@882 438 strncpy(iomul_param, str, sizeof(iomul_param));
keir@882 439 return 1;
keir@882 440 }
keir@882 441 __setup("guestiomuldev=", pci_iomul_param_setup);
keir@882 442
keir@882 443 /*****************************************************************************/
keir@882 444 static void __devinit pci_iomul_set_bridge_io_window(struct pci_dev *bridge,
keir@882 445 uint32_t io_base,
keir@882 446 uint32_t io_limit)
keir@882 447 {
keir@882 448 uint16_t l;
keir@882 449 uint32_t upper16;
keir@882 450
keir@882 451 io_base >>= 12;
keir@882 452 io_base <<= 4;
keir@882 453 io_limit >>= 12;
keir@882 454 io_limit <<= 4;
keir@882 455 l = (io_base & 0xff) | ((io_limit & 0xff) << 8);
keir@882 456 upper16 = ((io_base & 0xffff00) >> 8) |
keir@882 457 (((io_limit & 0xffff00) >> 8) << 16);
keir@882 458
keir@882 459 /* Temporarily disable the I/O range before updating PCI_IO_BASE. */
keir@882 460 pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff);
keir@882 461 /* Update lower 16 bits of I/O base/limit. */
keir@882 462 pci_write_config_word(bridge, PCI_IO_BASE, l);
keir@882 463 /* Update upper 16 bits of I/O base/limit. */
keir@882 464 pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, upper16);
keir@882 465 }
keir@882 466
keir@882 467 static void __devinit pci_disable_bridge_io_window(struct pci_dev *bridge)
keir@882 468 {
keir@882 469 /* set base = 0xffffff limit = 0x0 */
keir@882 470 pci_iomul_set_bridge_io_window(bridge, 0xffffff, 0);
keir@882 471 }
keir@882 472
keir@882 473 static int __devinit pci_iomul_func_scan(struct pci_dev *pdev,
keir@882 474 struct pci_iomul_slot *slot,
keir@882 475 uint8_t func)
keir@882 476 {
keir@882 477 struct pci_iomul_func *f;
keir@882 478 unsigned int i;
keir@882 479
keir@882 480 f = kzalloc(sizeof(*f), GFP_KERNEL);
keir@882 481 if (f == NULL)
keir@882 482 return -ENOMEM;
keir@882 483
keir@882 484 f->segment = slot->segment;
keir@882 485 f->bus = slot->bus;
keir@882 486 f->devfn = PCI_DEVFN(slot->dev, func);
keir@882 487 f->io_size = pdev_size_io(pdev);
keir@882 488
keir@882 489 for (i = 0; i < PCI_NUM_BARS; i++) {
keir@882 490 if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO))
keir@882 491 continue;
keir@882 492 if (pci_resource_len(pdev, i) == 0)
keir@882 493 continue;
keir@882 494
keir@882 495 f->io_bar |= 1 << i;
keir@882 496 f->resource[i] = pdev->resource[i];
keir@882 497 }
keir@882 498
keir@882 499 if (f->io_bar)
keir@882 500 slot->func[func] = f;
keir@882 501 else
keir@882 502 kfree(f);
keir@882 503 return 0;
keir@882 504 }
keir@882 505
keir@882 506 /*
keir@882 507 * This is tricky part.
keir@882 508 * fake PCI resource assignment routines by setting flags to 0.
keir@882 509 * PCI resource allocate routines think the resource should
keir@882 510 * be allocated by checking flags. 0 means this resource isn't used.
keir@882 511 * See pbus_size_io() and pdev_sort_resources().
keir@882 512 *
keir@882 513 * After allocated resources, flags (IORESOURCE_IO) is exported
keir@882 514 * to other part including user process.
keir@882 515 * So we have to set flags to IORESOURCE_IO, but at the same time
keir@882 516 * we must prevent those resources from reassigning when pci hot plug.
keir@882 517 * To achieve that, set r->parent to dummy resource.
keir@882 518 */
keir@882 519 static void __devinit pci_iomul_disable_resource(struct resource *r)
keir@882 520 {
keir@882 521 /* don't allocate this resource */
keir@882 522 r->flags = 0;
keir@882 523 }
keir@882 524
keir@882 525 static void __devinit pci_iomul_reenable_resource(
keir@882 526 struct resource *dummy_parent, struct resource *r)
keir@882 527 {
keir@882 528 int ret;
keir@882 529
keir@882 530 dummy_parent->start = r->start;
keir@882 531 dummy_parent->end = r->end;
keir@882 532 dummy_parent->flags = r->flags;
keir@882 533 dummy_parent->name = "PCI IOMUL dummy resource";
keir@882 534
keir@882 535 ret = request_resource(dummy_parent, r);
keir@882 536 BUG_ON(ret);
keir@882 537 }
keir@882 538
keir@882 539 static void __devinit pci_iomul_fixup_ioresource(struct pci_dev *pdev,
keir@882 540 struct pci_iomul_func *func,
keir@882 541 int reassign, int dealloc)
keir@882 542 {
keir@882 543 uint8_t i;
keir@882 544 struct resource *r;
keir@882 545
keir@882 546 printk(KERN_INFO "PCI: deallocating io resource[%s]. io size 0x%lx\n",
keir@882 547 pci_name(pdev), func->io_size);
keir@882 548 for (i = 0; i < PCI_NUM_BARS; i++) {
keir@882 549 r = &pdev->resource[i];
keir@882 550 if (!(func->io_bar & (1 << i)))
keir@882 551 continue;
keir@882 552
keir@882 553 if (reassign) {
keir@882 554 r->end -= r->start;
keir@882 555 r->start = 0;
keir@882 556 pci_update_resource(pdev, i);
keir@882 557 func->resource[i] = *r;
keir@882 558 }
keir@882 559
keir@882 560 if (dealloc)
keir@882 561 /* don't allocate this resource */
keir@882 562 pci_iomul_disable_resource(r);
keir@882 563 }
keir@882 564
keir@882 565 /* parent PCI-PCI bridge */
keir@882 566 if (!reassign)
keir@882 567 return;
keir@882 568 pdev = pdev->bus->self;
keir@882 569 if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
keir@882 570 return;
keir@882 571 pci_disable_bridge_io_window(pdev);
keir@882 572 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
keir@882 573 r = &pdev->resource[i];
keir@882 574 if (!(r->flags & IORESOURCE_IO))
keir@882 575 continue;
keir@882 576
keir@882 577 r->end -= r->start;
keir@882 578 r->start = 0;
keir@882 579 if (i < PCI_BRIDGE_RESOURCES)
keir@882 580 pci_update_resource(pdev, i);
keir@882 581 }
keir@882 582 }
keir@882 583
keir@882 584 static void __devinit __quirk_iomul_dealloc_ioresource(
keir@882 585 struct pci_iomul_switch *sw,
keir@882 586 struct pci_dev *pdev, struct pci_iomul_slot *slot)
keir@882 587 {
keir@882 588 struct pci_iomul_func *f;
keir@882 589 struct pci_iomul_func *__f;
keir@882 590
keir@882 591 if (pci_iomul_func_scan(pdev, slot, PCI_FUNC(pdev->devfn)) != 0)
keir@882 592 return;
keir@882 593
keir@882 594 f = slot->func[PCI_FUNC(pdev->devfn)];
keir@882 595 if (f == NULL)
keir@882 596 return;
keir@882 597
keir@882 598 __f = sw->func;
keir@882 599 /* sw->io_base == 0 means that we are called at boot time.
keir@882 600 * != 0 means that we are called by php after boot. */
keir@882 601 if (sw->io_base == 0 &&
keir@882 602 (__f == NULL || __f->io_size < f->io_size)) {
keir@882 603 if (__f != NULL) {
keir@882 604 struct pci_bus *__pbus;
keir@882 605 struct pci_dev *__pdev;
keir@882 606
keir@882 607 __pbus = pci_find_bus(__f->segment, __f->bus);
keir@882 608 BUG_ON(__pbus == NULL);
keir@882 609 __pdev = pci_get_slot(__pbus, __f->devfn);
keir@882 610 BUG_ON(__pdev == NULL);
keir@882 611 pci_iomul_fixup_ioresource(__pdev, __f, 0, 1);
keir@882 612 pci_dev_put(__pdev);
keir@882 613 }
keir@882 614
keir@882 615 pci_iomul_fixup_ioresource(pdev, f, 1, 0);
keir@882 616 sw->func = f;
keir@882 617 } else {
keir@882 618 pci_iomul_fixup_ioresource(pdev, f, 1, 1);
keir@882 619 }
keir@882 620 }
keir@882 621
keir@882 622 static void __devinit quirk_iomul_dealloc_ioresource(struct pci_dev *pdev)
keir@882 623 {
keir@882 624 struct pci_iomul_switch *sw;
keir@882 625 struct pci_iomul_slot *slot;
keir@882 626
keir@882 627 if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL)
keir@882 628 return;
keir@882 629 if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
keir@882 630 return; /* PCI Host Bridge isn't a target device */
keir@882 631 if (!pci_is_iomul_dev_param(pdev))
keir@882 632 return;
keir@882 633
keir@882 634 mutex_lock(&switch_list_lock);
keir@882 635 sw = pci_iomul_find_switch_locked(pci_domain_nr(pdev->bus),
keir@882 636 pci_dev_switch_busnr(pdev));
keir@882 637 if (sw == NULL) {
keir@882 638 sw = pci_iomul_switch_alloc(pci_domain_nr(pdev->bus),
keir@882 639 pci_dev_switch_busnr(pdev));
keir@882 640 if (sw == NULL) {
keir@882 641 mutex_unlock(&switch_list_lock);
keir@882 642 printk(KERN_WARNING
keir@882 643 "PCI: can't allocate memory "
keir@882 644 "for sw of IO mulplexing %s", pci_name(pdev));
keir@882 645 return;
keir@882 646 }
keir@882 647 pci_iomul_switch_add_locked(sw);
keir@882 648 }
keir@882 649 pci_iomul_switch_get(sw);
keir@882 650 mutex_unlock(&switch_list_lock);
keir@882 651
keir@882 652 mutex_lock(&sw->lock);
keir@882 653 slot = pci_iomul_find_slot_locked(sw, pdev->bus->number,
keir@882 654 PCI_SLOT(pdev->devfn));
keir@882 655 if (slot == NULL) {
keir@882 656 slot = pci_iomul_slot_alloc(pdev);
keir@882 657 if (slot == NULL) {
keir@882 658 mutex_unlock(&sw->lock);
keir@882 659 pci_iomul_switch_put(sw);
keir@882 660 printk(KERN_WARNING "PCI: can't allocate memory "
keir@882 661 "for IO mulplexing %s", pci_name(pdev));
keir@882 662 return;
keir@882 663 }
keir@882 664 pci_iomul_slot_add_locked(sw, slot);
keir@882 665 }
keir@882 666
keir@882 667 printk(KERN_INFO "PCI: disable device and release io resource[%s].\n",
keir@882 668 pci_name(pdev));
keir@882 669 pci_disable_device(pdev);
keir@882 670
keir@882 671 __quirk_iomul_dealloc_ioresource(sw, pdev, slot);
keir@882 672
keir@882 673 mutex_unlock(&sw->lock);
keir@882 674 pci_iomul_switch_put(sw);
keir@882 675 }
keir@882 676 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID,
keir@882 677 quirk_iomul_dealloc_ioresource);
keir@882 678
keir@882 679 static void __devinit pci_iomul_read_bridge_io(struct pci_iomul_switch *sw)
keir@882 680 {
keir@882 681 struct pci_iomul_func *f = sw->func;
keir@882 682
keir@882 683 struct pci_bus *pbus;
keir@882 684 struct pci_dev *pdev;
keir@882 685 struct pci_dev *bridge;
keir@882 686
keir@882 687 uint16_t l;
keir@882 688 uint16_t base_upper16;
keir@882 689 uint16_t limit_upper16;
keir@882 690 uint32_t io_base;
keir@882 691 uint32_t io_limit;
keir@882 692
keir@882 693 pbus = pci_find_bus(f->segment, f->bus);
keir@882 694 BUG_ON(pbus == NULL);
keir@882 695
keir@882 696 pdev = pci_get_slot(pbus, f->devfn);
keir@882 697 BUG_ON(pdev == NULL);
keir@882 698
keir@882 699 bridge = pdev->bus->self;
keir@882 700 pci_read_config_word(bridge, PCI_IO_BASE, &l);
keir@882 701 pci_read_config_word(bridge, PCI_IO_BASE_UPPER16, &base_upper16);
keir@882 702 pci_read_config_word(bridge, PCI_IO_LIMIT_UPPER16, &limit_upper16);
keir@882 703
keir@882 704 io_base = (l & 0xf0) | ((uint32_t)base_upper16 << 8);
keir@882 705 io_base <<= 8;
keir@882 706 io_limit = (l >> 8) | ((uint32_t)limit_upper16 << 8);
keir@882 707 io_limit <<= 8;
keir@882 708 io_limit |= 0xfff;
keir@882 709
keir@882 710 sw->io_base = io_base;
keir@882 711 sw->io_limit = io_limit;
keir@882 712
keir@882 713 pci_dev_put(pdev);
keir@882 714 printk(KERN_INFO "PCI: bridge %s base 0x%x limit 0x%x\n",
keir@882 715 pci_name(bridge), sw->io_base, sw->io_limit);
keir@882 716 }
keir@882 717
keir@882 718 static void __devinit pci_iomul_setup_brige(struct pci_dev *bridge,
keir@882 719 uint32_t io_base,
keir@882 720 uint32_t io_limit)
keir@882 721 {
keir@882 722 uint16_t cmd;
keir@882 723
keir@882 724 if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_HOST)
keir@882 725 return;
keir@882 726
keir@882 727 pci_iomul_set_bridge_io_window(bridge, io_base, io_limit);
keir@882 728
keir@882 729 /* and forcibly enables IO */
keir@882 730 pci_read_config_word(bridge, PCI_COMMAND, &cmd);
keir@882 731 if (!(cmd & PCI_COMMAND_IO)) {
keir@882 732 cmd |= PCI_COMMAND_IO;
keir@882 733 printk(KERN_INFO "PCI: Forcibly Enabling IO %s\n",
keir@882 734 pci_name(bridge));
keir@882 735 pci_write_config_word(bridge, PCI_COMMAND, cmd);
keir@882 736 }
keir@882 737 }
keir@882 738
keir@882 739 struct __bar {
keir@882 740 unsigned long size;
keir@882 741 uint8_t bar;
keir@882 742 };
keir@882 743
keir@882 744 /* decending order */
keir@882 745 static int __devinit pci_iomul_bar_cmp(const void *lhs__, const void *rhs__)
keir@882 746 {
keir@882 747 const struct __bar *lhs = (struct __bar*)lhs__;
keir@882 748 const struct __bar *rhs = (struct __bar*)rhs__;
keir@882 749 return - (lhs->size - rhs->size);
keir@882 750 }
keir@882 751
keir@882 752 static void __devinit pci_iomul_setup_dev(struct pci_dev *pdev,
keir@882 753 struct pci_iomul_func *f,
keir@882 754 uint32_t io_base)
keir@882 755 {
keir@882 756 struct __bar bars[PCI_NUM_BARS];
keir@882 757 int i;
keir@882 758 uint8_t num_bars = 0;
keir@882 759 struct resource *r;
keir@882 760
keir@882 761 printk(KERN_INFO "PCI: Forcibly assign IO %s from 0x%x\n",
keir@882 762 pci_name(pdev), io_base);
keir@882 763
keir@882 764 for (i = 0; i < PCI_NUM_BARS; i++) {
keir@882 765 if (!(f->io_bar & (1 << i)))
keir@882 766 continue;
keir@882 767
keir@882 768 r = &f->resource[i];
keir@882 769 bars[num_bars].size = pci_iomul_len(r);
keir@882 770 bars[num_bars].bar = i;
keir@882 771
keir@882 772 num_bars++;
keir@882 773 }
keir@882 774
keir@882 775 sort(bars, num_bars, sizeof(bars[0]), &pci_iomul_bar_cmp, NULL);
keir@882 776
keir@882 777 for (i = 0; i < num_bars; i++) {
keir@882 778 struct resource *fr = &f->resource[bars[i].bar];
keir@882 779 r = &pdev->resource[bars[i].bar];
keir@882 780
keir@882 781 BUG_ON(r->start != 0);
keir@882 782 r->start += io_base;
keir@882 783 r->end += io_base;
keir@882 784
keir@882 785 fr->start = r->start;
keir@882 786 fr->end = r->end;
keir@882 787
keir@882 788 /* pci_update_resource() check flags. */
keir@882 789 r->flags = fr->flags;
keir@882 790 pci_update_resource(pdev, bars[i].bar);
keir@882 791 pci_iomul_reenable_resource(&f->dummy_parent, r);
keir@882 792
keir@882 793 io_base += bars[i].size;
keir@882 794 }
keir@882 795 }
keir@882 796
keir@882 797 static void __devinit pci_iomul_release_io_resource(
keir@882 798 struct pci_dev *pdev, struct pci_iomul_switch *sw,
keir@882 799 struct pci_iomul_slot *slot, struct pci_iomul_func *f)
keir@882 800 {
keir@882 801 int i;
keir@882 802 struct resource *r;
keir@882 803
keir@882 804 for (i = 0; i < PCI_NUM_BARS; i++) {
keir@882 805 if (pci_resource_flags(pdev, i) & IORESOURCE_IO &&
keir@882 806 pdev->resource[i].parent != NULL) {
keir@882 807 r = &pdev->resource[i];
keir@882 808 f->resource[i] = *r;
keir@882 809 release_resource(r);
keir@882 810 pci_iomul_reenable_resource(&f->dummy_parent, r);
keir@882 811 }
keir@882 812 }
keir@882 813
keir@882 814 /* parent PCI-PCI bridge */
keir@882 815 pdev = pdev->bus->self;
keir@882 816 if ((pdev->class >> 8) != PCI_CLASS_BRIDGE_HOST) {
keir@882 817 for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
keir@882 818 struct resource *parent = pdev->resource[i].parent;
keir@882 819
keir@882 820 if (pci_resource_flags(pdev, i) & IORESOURCE_IO &&
keir@882 821 parent != NULL) {
keir@882 822 r = &pdev->resource[i];
keir@882 823
keir@882 824 sw->io_resource.flags = r->flags;
keir@882 825 sw->io_resource.start = sw->io_base;
keir@882 826 sw->io_resource.end = sw->io_limit;
keir@882 827 sw->io_resource.name = "PCI IO Multiplexer";
keir@882 828
keir@882 829 release_resource(r);
keir@882 830 pci_iomul_reenable_resource(
keir@882 831 &slot->dummy_parent[i - PCI_BRIDGE_RESOURCES], r);
keir@882 832
keir@882 833 if (request_resource(parent,
keir@882 834 &sw->io_resource))
keir@882 835 printk(KERN_ERR
keir@882 836 "PCI IOMul: can't allocate "
keir@882 837 "resource. [0x%x, 0x%x]",
keir@882 838 sw->io_base, sw->io_limit);
keir@882 839 }
keir@882 840 }
keir@882 841 }
keir@882 842 }
keir@882 843
keir@882 844 static void __devinit quirk_iomul_reassign_ioresource(struct pci_dev *pdev)
keir@882 845 {
keir@882 846 struct pci_iomul_switch *sw;
keir@882 847 struct pci_iomul_slot *slot;
keir@882 848 struct pci_iomul_func *sf;
keir@882 849 struct pci_iomul_func *f;
keir@882 850
keir@882 851 pci_iomul_get_lock_switch(pdev, &sw, &slot);
keir@882 852 if (sw == NULL || slot == NULL)
keir@882 853 return;
keir@882 854
keir@882 855 if (sw->io_base == 0)
keir@882 856 pci_iomul_read_bridge_io(sw);
keir@882 857 if (!pci_iomul_switch_io_allocated(sw))
keir@882 858 goto out;
keir@882 859
keir@882 860 sf = sw->func;
keir@882 861 f = slot->func[PCI_FUNC(pdev->devfn)];
keir@882 862 if (f == NULL)
keir@882 863 /* (sf == NULL || f == NULL) case
keir@882 864 * can happen when all the specified devices
keir@882 865 * don't have io space
keir@882 866 */
keir@882 867 goto out;
keir@882 868
keir@882 869 if (sf != NULL &&
keir@882 870 (pci_domain_nr(pdev->bus) != sf->segment ||
keir@882 871 pdev->bus->number != sf->bus ||
keir@882 872 PCI_SLOT(pdev->devfn) != PCI_SLOT(sf->devfn)) &&
keir@882 873 PCI_FUNC(pdev->devfn) == 0) {
keir@882 874 pci_iomul_setup_brige(pdev->bus->self,
keir@882 875 sw->io_base, sw->io_limit);
keir@882 876 }
keir@882 877
keir@882 878 BUG_ON(f->io_size > sw->io_limit - sw->io_base + 1);
keir@882 879 if (/* f == sf */
keir@882 880 sf != NULL &&
keir@882 881 pci_domain_nr(pdev->bus) == sf->segment &&
keir@882 882 pdev->bus->number == sf->bus &&
keir@882 883 pdev->devfn == sf->devfn)
keir@882 884 pci_iomul_release_io_resource(pdev, sw, slot, f);
keir@882 885 else
keir@882 886 pci_iomul_setup_dev(pdev, f, sw->io_base);
keir@882 887
keir@882 888 out:
keir@882 889 mutex_unlock(&sw->lock);
keir@882 890 pci_iomul_switch_put(sw);
keir@882 891 }
keir@882 892
keir@882 893 DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID,
keir@882 894 quirk_iomul_reassign_ioresource);
keir@882 895
keir@882 896 /*****************************************************************************/
keir@882 897 #ifdef CONFIG_HOTPLUG_PCI
keir@882 898 static int __devinit __pci_iomul_notifier_del_device(struct pci_dev *pdev)
keir@882 899 {
keir@882 900 struct pci_iomul_switch *sw;
keir@882 901 struct pci_iomul_slot *slot;
keir@882 902 int i;
keir@882 903
keir@882 904 pci_iomul_get_lock_switch(pdev, &sw, &slot);
keir@882 905 if (sw == NULL || slot == NULL)
keir@882 906 return 0;
keir@882 907
keir@882 908 if (sw->func == slot->func[PCI_FUNC(pdev->devfn)])
keir@882 909 sw->func = NULL;
keir@882 910 kfree(slot->func[PCI_FUNC(pdev->devfn)]);
keir@882 911 slot->func[PCI_FUNC(pdev->devfn)] = NULL;
keir@882 912 for (i = 0; i < PCI_NUM_FUNC; i++) {
keir@882 913 if (slot->func[i] != NULL)
keir@882 914 goto out;
keir@882 915 }
keir@882 916
keir@882 917 pci_iomul_slot_del_locked(sw, slot);
keir@882 918 pci_iomul_slot_put(slot);
keir@882 919
keir@882 920 out:
keir@882 921 mutex_unlock(&sw->lock);
keir@882 922 pci_iomul_switch_put(sw);
keir@882 923 return 0;
keir@882 924 }
keir@882 925
keir@882 926 static int __devinit __pci_iomul_notifier_del_switch(struct pci_dev *pdev)
keir@882 927 {
keir@882 928 struct pci_iomul_switch *sw;
keir@882 929
keir@882 930 mutex_lock(&switch_list_lock);
keir@882 931 sw = pci_iomul_find_switch_locked(pci_domain_nr(pdev->bus),
keir@882 932 pdev->bus->number);
keir@882 933 if (sw == NULL)
keir@882 934 goto out;
keir@882 935
keir@882 936 pci_iomul_switch_del_locked(sw);
keir@882 937
keir@882 938 mutex_lock(&sw->lock);
keir@882 939 if (sw->io_resource.parent)
keir@882 940 release_resource(&sw->io_resource);
keir@882 941 sw->io_base = 0; /* to tell this switch is removed */
keir@882 942 sw->io_limit = 0;
keir@882 943 BUG_ON(!list_empty(&sw->slots));
keir@882 944 mutex_unlock(&sw->lock);
keir@882 945
keir@882 946 out:
keir@882 947 mutex_unlock(&switch_list_lock);
keir@882 948 pci_iomul_switch_put(sw);
keir@882 949 return 0;
keir@882 950 }
keir@882 951
keir@882 952 static int __devinit pci_iomul_notifier_del_device(struct pci_dev *pdev)
keir@882 953 {
keir@882 954 int ret;
keir@882 955 switch (pdev->hdr_type) {
keir@882 956 case PCI_HEADER_TYPE_NORMAL:
keir@882 957 ret = __pci_iomul_notifier_del_device(pdev);
keir@882 958 break;
keir@882 959 case PCI_HEADER_TYPE_BRIDGE:
keir@882 960 ret = __pci_iomul_notifier_del_switch(pdev);
keir@882 961 break;
keir@882 962 default:
keir@882 963 printk(KERN_WARNING "PCI IOMUL: "
keir@882 964 "device %s has unknown header type %02x, ignoring.\n",
keir@882 965 pci_name(pdev), pdev->hdr_type);
keir@882 966 ret = -EIO;
keir@882 967 break;
keir@882 968 }
keir@882 969 return ret;
keir@882 970 }
keir@882 971
keir@882 972 static int __devinit pci_iomul_notifier(struct notifier_block *nb,
keir@882 973 unsigned long action, void *data)
keir@882 974 {
keir@882 975 struct device *dev = data;
keir@882 976 struct pci_dev *pdev = to_pci_dev(dev);
keir@882 977
keir@882 978 switch (action) {
keir@882 979 case BUS_NOTIFY_ADD_DEVICE:
keir@882 980 quirk_iomul_reassign_ioresource(pdev);
keir@882 981 break;
keir@882 982 case BUS_NOTIFY_DEL_DEVICE:
keir@882 983 return pci_iomul_notifier_del_device(pdev);
keir@882 984 default:
keir@882 985 /* nothing */
keir@882 986 break;
keir@882 987 }
keir@882 988
keir@882 989 return 0;
keir@882 990 }
keir@882 991
keir@882 992 static struct notifier_block pci_iomul_nb = {
keir@882 993 .notifier_call = pci_iomul_notifier,
keir@882 994 };
keir@882 995
keir@882 996 static int __init pci_iomul_hotplug_init(void)
keir@882 997 {
keir@882 998 bus_register_notifier(&pci_bus_type, &pci_iomul_nb);
keir@882 999 return 0;
keir@882 1000 }
keir@882 1001
keir@882 1002 late_initcall(pci_iomul_hotplug_init);
keir@882 1003 #endif
keir@882 1004
keir@882 1005 /*****************************************************************************/
keir@882 1006 struct pci_iomul_data {
keir@882 1007 struct mutex lock;
keir@882 1008
keir@882 1009 struct pci_dev *pdev;
keir@882 1010 struct pci_iomul_switch *sw;
keir@882 1011 struct pci_iomul_slot *slot; /* slot::kref */
keir@882 1012 struct pci_iomul_func **func; /* when dereferencing,
keir@882 1013 sw->lock is necessary */
keir@882 1014 };
keir@882 1015
keir@882 1016 static int pci_iomul_func_ioport(struct pci_iomul_func *func,
keir@882 1017 uint8_t bar, uint64_t offset, int *port)
keir@882 1018 {
keir@882 1019 if (!(func->io_bar & (1 << bar)))
keir@882 1020 return -EINVAL;
keir@882 1021
keir@882 1022 *port = func->resource[bar].start + offset;
keir@882 1023 if (*port < func->resource[bar].start ||
keir@882 1024 *port > func->resource[bar].end)
keir@882 1025 return -EINVAL;
keir@882 1026
keir@882 1027 return 0;
keir@882 1028 }
keir@882 1029
keir@882 1030 static inline int pci_iomul_valid(struct pci_iomul_data *iomul)
keir@882 1031 {
keir@882 1032 BUG_ON(!mutex_is_locked(&iomul->lock));
keir@882 1033 BUG_ON(!mutex_is_locked(&iomul->sw->lock));
keir@882 1034 return pci_iomul_switch_io_allocated(iomul->sw) &&
keir@882 1035 *iomul->func != NULL;
keir@882 1036 }
keir@882 1037
keir@882 1038 static void __pci_iomul_enable_io(struct pci_dev *pdev)
keir@882 1039 {
keir@882 1040 uint16_t cmd;
keir@882 1041
keir@882 1042 pci_dev_get(pdev);
keir@882 1043 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
keir@882 1044 cmd |= PCI_COMMAND_IO;
keir@882 1045 pci_write_config_word(pdev, PCI_COMMAND, cmd);
keir@882 1046 }
keir@882 1047
keir@882 1048 static void __pci_iomul_disable_io(struct pci_iomul_data *iomul,
keir@882 1049 struct pci_dev *pdev)
keir@882 1050 {
keir@882 1051 uint16_t cmd;
keir@882 1052
keir@882 1053 if (!pci_iomul_valid(iomul))
keir@882 1054 return;
keir@882 1055
keir@882 1056 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
keir@882 1057 cmd &= ~PCI_COMMAND_IO;
keir@882 1058 pci_write_config_word(pdev, PCI_COMMAND, cmd);
keir@882 1059 pci_dev_put(pdev);
keir@882 1060 }
keir@882 1061
keir@882 1062 static int pci_iomul_open(struct inode *inode, struct file *filp)
keir@882 1063 {
keir@882 1064 struct pci_iomul_data *iomul;
keir@882 1065 iomul = kmalloc(sizeof(*iomul), GFP_KERNEL);
keir@882 1066 if (iomul == NULL)
keir@882 1067 return -ENOMEM;
keir@882 1068
keir@882 1069 mutex_init(&iomul->lock);
keir@882 1070 iomul->pdev = NULL;
keir@882 1071 iomul->sw = NULL;
keir@882 1072 iomul->slot = NULL;
keir@882 1073 iomul->func = NULL;
keir@882 1074 filp->private_data = (void*)iomul;
keir@882 1075
keir@882 1076 return 0;
keir@882 1077 }
keir@882 1078
keir@882 1079 static int pci_iomul_release(struct inode *inode, struct file *filp)
keir@882 1080 {
keir@882 1081 struct pci_iomul_data *iomul =
keir@882 1082 (struct pci_iomul_data*)filp->private_data;
keir@882 1083 struct pci_iomul_switch *sw;
keir@882 1084 struct pci_iomul_slot *slot = NULL;
keir@882 1085
keir@882 1086 mutex_lock(&iomul->lock);
keir@882 1087 sw = iomul->sw;
keir@882 1088 slot = iomul->slot;
keir@882 1089 if (iomul->pdev != NULL) {
keir@882 1090 if (sw != NULL) {
keir@882 1091 mutex_lock(&sw->lock);
keir@882 1092 if (sw->current_pdev == iomul->pdev) {
keir@882 1093 __pci_iomul_disable_io(iomul,
keir@882 1094 sw->current_pdev);
keir@882 1095 sw->current_pdev = NULL;
keir@882 1096 }
keir@882 1097 sw->count--;
keir@882 1098 if (sw->count == 0) {
keir@882 1099 release_region(sw->io_region->start, sw->io_region->end - sw->io_region->start + 1);
keir@882 1100 sw->io_region = NULL;
keir@882 1101 }
keir@882 1102 mutex_unlock(&sw->lock);
keir@882 1103 }
keir@882 1104 pci_dev_put(iomul->pdev);
keir@882 1105 }
keir@882 1106 mutex_unlock(&iomul->lock);
keir@882 1107
keir@882 1108 if (slot != NULL)
keir@882 1109 pci_iomul_slot_put(slot);
keir@882 1110 if (sw != NULL)
keir@882 1111 pci_iomul_switch_put(sw);
keir@882 1112 kfree(iomul);
keir@882 1113 return 0;
keir@882 1114 }
keir@882 1115
keir@882 1116 static long pci_iomul_setup(struct pci_iomul_data *iomul,
keir@882 1117 struct pci_iomul_setup __user *arg)
keir@882 1118 {
keir@882 1119 long error = 0;
keir@882 1120 struct pci_iomul_setup setup;
keir@882 1121 struct pci_iomul_switch *sw = NULL;
keir@882 1122 struct pci_iomul_slot *slot;
keir@882 1123 struct pci_bus *pbus;
keir@882 1124 struct pci_dev *pdev;
keir@882 1125
keir@882 1126 if (copy_from_user(&setup, arg, sizeof(setup)))
keir@882 1127 return -EFAULT;
keir@882 1128
keir@882 1129 pbus = pci_find_bus(setup.segment, setup.bus);
keir@882 1130 if (pbus == NULL)
keir@882 1131 return -ENODEV;
keir@882 1132 pdev = pci_get_slot(pbus, setup.dev);
keir@882 1133 if (pdev == NULL)
keir@882 1134 return -ENODEV;
keir@882 1135
keir@882 1136 mutex_lock(&iomul->lock);
keir@882 1137 if (iomul->sw != NULL) {
keir@882 1138 error = -EBUSY;
keir@882 1139 goto out0;
keir@882 1140 }
keir@882 1141
keir@882 1142 pci_iomul_get_lock_switch(pdev, &sw, &slot);
keir@882 1143 if (sw == NULL || slot == NULL) {
keir@882 1144 error = -ENODEV;
keir@882 1145 goto out0;
keir@882 1146 }
keir@882 1147 if (!pci_iomul_switch_io_allocated(sw)) {
keir@882 1148 error = -ENODEV;
keir@882 1149 goto out;
keir@882 1150 }
keir@882 1151
keir@882 1152 if (slot->func[setup.func] == NULL) {
keir@882 1153 error = -ENODEV;
keir@882 1154 goto out;
keir@882 1155 }
keir@882 1156
keir@882 1157 if (sw->count == 0) {
keir@882 1158 BUG_ON(sw->io_region != NULL);
keir@882 1159 sw->io_region =
keir@882 1160 request_region(sw->io_base,
keir@882 1161 sw->io_limit - sw->io_base + 1,
keir@882 1162 "PCI IO Multiplexer driver");
keir@882 1163 if (sw->io_region == NULL) {
keir@882 1164 mutex_unlock(&sw->lock);
keir@882 1165 error = -EBUSY;
keir@882 1166 goto out;
keir@882 1167 }
keir@882 1168 }
keir@882 1169 sw->count++;
keir@882 1170 pci_iomul_slot_get(slot);
keir@882 1171
keir@882 1172 iomul->pdev = pdev;
keir@882 1173 iomul->sw = sw;
keir@882 1174 iomul->slot = slot;
keir@882 1175 iomul->func = &slot->func[setup.func];
keir@882 1176
keir@882 1177 out:
keir@882 1178 mutex_unlock(&sw->lock);
keir@882 1179 out0:
keir@882 1180 mutex_unlock(&iomul->lock);
keir@882 1181 if (error != 0) {
keir@882 1182 if (sw != NULL)
keir@882 1183 pci_iomul_switch_put(sw);
keir@882 1184 pci_dev_put(pdev);
keir@882 1185 }
keir@882 1186 return error;
keir@882 1187 }
keir@882 1188
keir@882 1189 static int pci_iomul_lock(struct pci_iomul_data *iomul,
keir@882 1190 struct pci_iomul_switch **sw,
keir@882 1191 struct pci_iomul_func **func)
keir@882 1192 {
keir@882 1193 mutex_lock(&iomul->lock);
keir@882 1194 *sw = iomul->sw;
keir@882 1195 if (*sw == NULL) {
keir@882 1196 mutex_unlock(&iomul->lock);
keir@882 1197 return -ENODEV;
keir@882 1198 }
keir@882 1199 mutex_lock(&(*sw)->lock);
keir@882 1200 if (!pci_iomul_valid(iomul)) {
keir@882 1201 mutex_unlock(&(*sw)->lock);
keir@882 1202 mutex_unlock(&iomul->lock);
keir@882 1203 return -ENODEV;
keir@882 1204 }
keir@882 1205 *func = *iomul->func;
keir@882 1206
keir@882 1207 return 0;
keir@882 1208 }
keir@882 1209
keir@882 1210 static long pci_iomul_disable_io(struct pci_iomul_data *iomul)
keir@882 1211 {
keir@882 1212 long error = 0;
keir@882 1213 struct pci_iomul_switch *sw;
keir@882 1214 struct pci_iomul_func *dummy_func;
keir@882 1215 struct pci_dev *pdev;
keir@882 1216
keir@882 1217 if (pci_iomul_lock(iomul, &sw, &dummy_func) < 0)
keir@882 1218 return -ENODEV;
keir@882 1219
keir@882 1220 pdev = iomul->pdev;
keir@882 1221 if (pdev == NULL)
keir@882 1222 error = -ENODEV;
keir@882 1223
keir@882 1224 if (pdev != NULL && sw->current_pdev == pdev) {
keir@882 1225 __pci_iomul_disable_io(iomul, pdev);
keir@882 1226 sw->current_pdev = NULL;
keir@882 1227 }
keir@882 1228
keir@882 1229 mutex_unlock(&sw->lock);
keir@882 1230 mutex_unlock(&iomul->lock);
keir@882 1231 return error;
keir@882 1232 }
keir@882 1233
keir@882 1234 static void pci_iomul_switch_to(
keir@882 1235 struct pci_iomul_data *iomul, struct pci_iomul_switch *sw,
keir@882 1236 struct pci_dev *next_pdev)
keir@882 1237 {
keir@882 1238 if (sw->current_pdev == next_pdev)
keir@882 1239 /* nothing to do */
keir@882 1240 return;
keir@882 1241
keir@882 1242 if (sw->current_pdev != NULL)
keir@882 1243 __pci_iomul_disable_io(iomul, sw->current_pdev);
keir@882 1244
keir@882 1245 __pci_iomul_enable_io(next_pdev);
keir@882 1246 sw->current_pdev = next_pdev;
keir@882 1247 }
keir@882 1248
keir@882 1249 static long pci_iomul_in(struct pci_iomul_data *iomul,
keir@882 1250 struct pci_iomul_in __user *arg)
keir@882 1251 {
keir@882 1252 struct pci_iomul_in in;
keir@882 1253 struct pci_iomul_switch *sw;
keir@882 1254 struct pci_iomul_func *func;
keir@882 1255
keir@882 1256 long error = 0;
keir@882 1257 int port;
keir@882 1258 uint32_t value = 0;
keir@882 1259
keir@882 1260 if (copy_from_user(&in, arg, sizeof(in)))
keir@882 1261 return -EFAULT;
keir@882 1262
keir@882 1263 if (pci_iomul_lock(iomul, &sw, &func) < 0)
keir@882 1264 return -ENODEV;
keir@882 1265
keir@882 1266 error = pci_iomul_func_ioport(func, in.bar, in.offset, &port);
keir@882 1267 if (error)
keir@882 1268 goto out;
keir@882 1269
keir@882 1270 pci_iomul_switch_to(iomul, sw, iomul->pdev);
keir@882 1271 switch (in.size) {
keir@882 1272 case 4:
keir@882 1273 value = inl(port);
keir@882 1274 break;
keir@882 1275 case 2:
keir@882 1276 value = inw(port);
keir@882 1277 break;
keir@882 1278 case 1:
keir@882 1279 value = inb(port);
keir@882 1280 break;
keir@882 1281 default:
keir@882 1282 error = -EINVAL;
keir@882 1283 break;
keir@882 1284 }
keir@882 1285
keir@882 1286 out:
keir@882 1287 mutex_unlock(&sw->lock);
keir@882 1288 mutex_unlock(&iomul->lock);
keir@882 1289
keir@882 1290 if (error == 0 && put_user(value, &arg->value))
keir@882 1291 return -EFAULT;
keir@882 1292 return error;
keir@882 1293 }
keir@882 1294
keir@882 1295 static long pci_iomul_out(struct pci_iomul_data *iomul,
keir@882 1296 struct pci_iomul_out __user *arg)
keir@882 1297 {
keir@882 1298 struct pci_iomul_in out;
keir@882 1299 struct pci_iomul_switch *sw;
keir@882 1300 struct pci_iomul_func *func;
keir@882 1301
keir@882 1302 long error = 0;
keir@882 1303 int port;
keir@882 1304
keir@882 1305 if (copy_from_user(&out, arg, sizeof(out)))
keir@882 1306 return -EFAULT;
keir@882 1307
keir@882 1308 if (pci_iomul_lock(iomul, &sw, &func) < 0)
keir@882 1309 return -ENODEV;
keir@882 1310
keir@882 1311 error = pci_iomul_func_ioport(func, out.bar, out.offset, &port);
keir@882 1312 if (error)
keir@882 1313 goto out;
keir@882 1314
keir@882 1315 pci_iomul_switch_to(iomul, sw, iomul->pdev);
keir@882 1316 switch (out.size) {
keir@882 1317 case 4:
keir@882 1318 outl(out.value, port);
keir@882 1319 break;
keir@882 1320 case 2:
keir@882 1321 outw(out.value, port);
keir@882 1322 break;
keir@882 1323 case 1:
keir@882 1324 outb(out.value, port);
keir@882 1325 break;
keir@882 1326 default:
keir@882 1327 error = -EINVAL;
keir@882 1328 break;
keir@882 1329 }
keir@882 1330
keir@882 1331 out:
keir@882 1332 mutex_unlock(&sw->lock);
keir@882 1333 mutex_unlock(&iomul->lock);
keir@882 1334 return error;
keir@882 1335 }
keir@882 1336
keir@882 1337 static long pci_iomul_ioctl(struct file *filp,
keir@882 1338 unsigned int cmd, unsigned long arg)
keir@882 1339 {
keir@882 1340 long error;
keir@882 1341 struct pci_iomul_data *iomul =
keir@882 1342 (struct pci_iomul_data*)filp->private_data;
keir@882 1343
keir@882 1344 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
keir@882 1345 return -EPERM;
keir@882 1346
keir@882 1347 switch (cmd) {
keir@882 1348 case PCI_IOMUL_SETUP:
keir@882 1349 error = pci_iomul_setup(iomul,
keir@882 1350 (struct pci_iomul_setup __user *)arg);
keir@882 1351 break;
keir@882 1352 case PCI_IOMUL_DISABLE_IO:
keir@882 1353 error = pci_iomul_disable_io(iomul);
keir@882 1354 break;
keir@882 1355 case PCI_IOMUL_IN:
keir@882 1356 error = pci_iomul_in(iomul, (struct pci_iomul_in __user *)arg);
keir@882 1357 break;
keir@882 1358 case PCI_IOMUL_OUT:
keir@882 1359 error = pci_iomul_out(iomul,
keir@882 1360 (struct pci_iomul_out __user *)arg);
keir@882 1361 break;
keir@882 1362 default:
keir@882 1363 error = -ENOSYS;
keir@882 1364 break;
keir@882 1365 }
keir@882 1366
keir@882 1367 return error;
keir@882 1368 }
keir@882 1369
keir@882 1370 static const struct file_operations pci_iomul_fops = {
keir@882 1371 .owner = THIS_MODULE,
keir@882 1372
keir@882 1373 .open = pci_iomul_open, /* nonseekable_open */
keir@882 1374 .release = pci_iomul_release,
keir@882 1375
keir@882 1376 .unlocked_ioctl = pci_iomul_ioctl,
keir@882 1377 };
keir@882 1378
keir@882 1379 static struct miscdevice pci_iomul_miscdev = {
keir@882 1380 .minor = MISC_DYNAMIC_MINOR,
keir@882 1381 .name = "pci_iomul",
keir@882 1382 .fops = &pci_iomul_fops,
keir@882 1383 };
keir@882 1384
keir@882 1385 static int pci_iomul_init(void)
keir@882 1386 {
keir@882 1387 int error;
keir@882 1388 error = misc_register(&pci_iomul_miscdev);
keir@882 1389 if (error != 0) {
keir@882 1390 printk(KERN_ALERT "Couldn't register /dev/misc/pci_iomul");
keir@882 1391 return error;
keir@882 1392 }
keir@882 1393 printk("PCI IO multiplexer device installed.\n");
keir@882 1394 return 0;
keir@882 1395 }
keir@882 1396
keir@882 1397 #if 0
keir@882 1398 static void pci_iomul_cleanup(void)
keir@882 1399 {
keir@882 1400 misc_deregister(&pci_iomul_miscdev);
keir@882 1401 }
keir@882 1402 #endif
keir@882 1403
keir@882 1404 /*
keir@882 1405 * This must be called after pci fixup final which is called by
keir@882 1406 * device_initcall(pci_init).
keir@882 1407 */
keir@882 1408 late_initcall(pci_iomul_init);
keir@882 1409
keir@882 1410 MODULE_LICENSE("GPL");
keir@882 1411 MODULE_AUTHOR("Isaku Yamahata <yamahata@valinux.co.jp>");
keir@882 1412 MODULE_DESCRIPTION("PCI IO space multiplexing driver");