ia64/linux-2.6.18-xen.hg

annotate drivers/pci/iomulti.c @ 883:b998614e2e2a

pci/guestdev: enhance guestdev to accept +iomul.

enhance guestdev to accept +iomul and use it.

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