msi.c revision 032de8e2fe3c0eec5fb0ffe4d38aa602dad397dc
1/* 2 * File: msi.c 3 * Purpose: PCI Message Signaled Interrupt (MSI) 4 * 5 * Copyright (C) 2003-2004 Intel 6 * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) 7 */ 8 9#include <linux/err.h> 10#include <linux/mm.h> 11#include <linux/irq.h> 12#include <linux/interrupt.h> 13#include <linux/init.h> 14#include <linux/ioport.h> 15#include <linux/smp_lock.h> 16#include <linux/pci.h> 17#include <linux/proc_fs.h> 18#include <linux/msi.h> 19 20#include <asm/errno.h> 21#include <asm/io.h> 22#include <asm/smp.h> 23 24#include "pci.h" 25#include "msi.h" 26 27static int pci_msi_enable = 1; 28 29static void msi_set_enable(struct pci_dev *dev, int enable) 30{ 31 int pos; 32 u16 control; 33 34 pos = pci_find_capability(dev, PCI_CAP_ID_MSI); 35 if (pos) { 36 pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); 37 control &= ~PCI_MSI_FLAGS_ENABLE; 38 if (enable) 39 control |= PCI_MSI_FLAGS_ENABLE; 40 pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); 41 } 42} 43 44static void msix_set_enable(struct pci_dev *dev, int enable) 45{ 46 int pos; 47 u16 control; 48 49 pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); 50 if (pos) { 51 pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); 52 control &= ~PCI_MSIX_FLAGS_ENABLE; 53 if (enable) 54 control |= PCI_MSIX_FLAGS_ENABLE; 55 pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); 56 } 57} 58 59static void msix_flush_writes(unsigned int irq) 60{ 61 struct msi_desc *entry; 62 63 entry = get_irq_msi(irq); 64 BUG_ON(!entry || !entry->dev); 65 switch (entry->msi_attrib.type) { 66 case PCI_CAP_ID_MSI: 67 /* nothing to do */ 68 break; 69 case PCI_CAP_ID_MSIX: 70 { 71 int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + 72 PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; 73 readl(entry->mask_base + offset); 74 break; 75 } 76 default: 77 BUG(); 78 break; 79 } 80} 81 82static void msi_set_mask_bit(unsigned int irq, int flag) 83{ 84 struct msi_desc *entry; 85 86 entry = get_irq_msi(irq); 87 BUG_ON(!entry || !entry->dev); 88 switch (entry->msi_attrib.type) { 89 case PCI_CAP_ID_MSI: 90 if (entry->msi_attrib.maskbit) { 91 int pos; 92 u32 mask_bits; 93 94 pos = (long)entry->mask_base; 95 pci_read_config_dword(entry->dev, pos, &mask_bits); 96 mask_bits &= ~(1); 97 mask_bits |= flag; 98 pci_write_config_dword(entry->dev, pos, mask_bits); 99 } else { 100 msi_set_enable(entry->dev, !flag); 101 } 102 break; 103 case PCI_CAP_ID_MSIX: 104 { 105 int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + 106 PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; 107 writel(flag, entry->mask_base + offset); 108 readl(entry->mask_base + offset); 109 break; 110 } 111 default: 112 BUG(); 113 break; 114 } 115 entry->msi_attrib.masked = !!flag; 116} 117 118void read_msi_msg(unsigned int irq, struct msi_msg *msg) 119{ 120 struct msi_desc *entry = get_irq_msi(irq); 121 switch(entry->msi_attrib.type) { 122 case PCI_CAP_ID_MSI: 123 { 124 struct pci_dev *dev = entry->dev; 125 int pos = entry->msi_attrib.pos; 126 u16 data; 127 128 pci_read_config_dword(dev, msi_lower_address_reg(pos), 129 &msg->address_lo); 130 if (entry->msi_attrib.is_64) { 131 pci_read_config_dword(dev, msi_upper_address_reg(pos), 132 &msg->address_hi); 133 pci_read_config_word(dev, msi_data_reg(pos, 1), &data); 134 } else { 135 msg->address_hi = 0; 136 pci_read_config_word(dev, msi_data_reg(pos, 1), &data); 137 } 138 msg->data = data; 139 break; 140 } 141 case PCI_CAP_ID_MSIX: 142 { 143 void __iomem *base; 144 base = entry->mask_base + 145 entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; 146 147 msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); 148 msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); 149 msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET); 150 break; 151 } 152 default: 153 BUG(); 154 } 155} 156 157void write_msi_msg(unsigned int irq, struct msi_msg *msg) 158{ 159 struct msi_desc *entry = get_irq_msi(irq); 160 switch (entry->msi_attrib.type) { 161 case PCI_CAP_ID_MSI: 162 { 163 struct pci_dev *dev = entry->dev; 164 int pos = entry->msi_attrib.pos; 165 166 pci_write_config_dword(dev, msi_lower_address_reg(pos), 167 msg->address_lo); 168 if (entry->msi_attrib.is_64) { 169 pci_write_config_dword(dev, msi_upper_address_reg(pos), 170 msg->address_hi); 171 pci_write_config_word(dev, msi_data_reg(pos, 1), 172 msg->data); 173 } else { 174 pci_write_config_word(dev, msi_data_reg(pos, 0), 175 msg->data); 176 } 177 break; 178 } 179 case PCI_CAP_ID_MSIX: 180 { 181 void __iomem *base; 182 base = entry->mask_base + 183 entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; 184 185 writel(msg->address_lo, 186 base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); 187 writel(msg->address_hi, 188 base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); 189 writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET); 190 break; 191 } 192 default: 193 BUG(); 194 } 195 entry->msg = *msg; 196} 197 198void mask_msi_irq(unsigned int irq) 199{ 200 msi_set_mask_bit(irq, 1); 201 msix_flush_writes(irq); 202} 203 204void unmask_msi_irq(unsigned int irq) 205{ 206 msi_set_mask_bit(irq, 0); 207 msix_flush_writes(irq); 208} 209 210static int msi_free_irqs(struct pci_dev* dev); 211 212 213static struct msi_desc* alloc_msi_entry(void) 214{ 215 struct msi_desc *entry; 216 217 entry = kzalloc(sizeof(struct msi_desc), GFP_KERNEL); 218 if (!entry) 219 return NULL; 220 221 INIT_LIST_HEAD(&entry->list); 222 entry->irq = 0; 223 entry->dev = NULL; 224 225 return entry; 226} 227 228#ifdef CONFIG_PM 229static void __pci_restore_msi_state(struct pci_dev *dev) 230{ 231 int pos; 232 u16 control; 233 struct msi_desc *entry; 234 235 if (!dev->msi_enabled) 236 return; 237 238 entry = get_irq_msi(dev->irq); 239 pos = entry->msi_attrib.pos; 240 241 pci_intx(dev, 0); /* disable intx */ 242 msi_set_enable(dev, 0); 243 write_msi_msg(dev->irq, &entry->msg); 244 if (entry->msi_attrib.maskbit) 245 msi_set_mask_bit(dev->irq, entry->msi_attrib.masked); 246 247 pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); 248 control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); 249 if (entry->msi_attrib.maskbit || !entry->msi_attrib.masked) 250 control |= PCI_MSI_FLAGS_ENABLE; 251 pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); 252} 253 254static void __pci_restore_msix_state(struct pci_dev *dev) 255{ 256 int pos; 257 struct msi_desc *entry; 258 u16 control; 259 260 if (!dev->msix_enabled) 261 return; 262 263 /* route the table */ 264 pci_intx(dev, 0); /* disable intx */ 265 msix_set_enable(dev, 0); 266 267 list_for_each_entry(entry, &dev->msi_list, list) { 268 write_msi_msg(entry->irq, &entry->msg); 269 msi_set_mask_bit(entry->irq, entry->msi_attrib.masked); 270 } 271 272 BUG_ON(list_empty(&dev->msi_list)); 273 entry = list_entry(dev->msi_list.next, struct msi_desc, list); 274 pos = entry->msi_attrib.pos; 275 pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); 276 control &= ~PCI_MSIX_FLAGS_MASKALL; 277 control |= PCI_MSIX_FLAGS_ENABLE; 278 pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); 279} 280 281void pci_restore_msi_state(struct pci_dev *dev) 282{ 283 __pci_restore_msi_state(dev); 284 __pci_restore_msix_state(dev); 285} 286#endif /* CONFIG_PM */ 287 288/** 289 * msi_capability_init - configure device's MSI capability structure 290 * @dev: pointer to the pci_dev data structure of MSI device function 291 * 292 * Setup the MSI capability structure of device function with a single 293 * MSI irq, regardless of device function is capable of handling 294 * multiple messages. A return of zero indicates the successful setup 295 * of an entry zero with the new MSI irq or non-zero for otherwise. 296 **/ 297static int msi_capability_init(struct pci_dev *dev) 298{ 299 struct msi_desc *entry; 300 int pos, ret; 301 u16 control; 302 303 msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ 304 305 pos = pci_find_capability(dev, PCI_CAP_ID_MSI); 306 pci_read_config_word(dev, msi_control_reg(pos), &control); 307 /* MSI Entry Initialization */ 308 entry = alloc_msi_entry(); 309 if (!entry) 310 return -ENOMEM; 311 312 entry->msi_attrib.type = PCI_CAP_ID_MSI; 313 entry->msi_attrib.is_64 = is_64bit_address(control); 314 entry->msi_attrib.entry_nr = 0; 315 entry->msi_attrib.maskbit = is_mask_bit_support(control); 316 entry->msi_attrib.masked = 1; 317 entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ 318 entry->msi_attrib.pos = pos; 319 if (is_mask_bit_support(control)) { 320 entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos, 321 is_64bit_address(control)); 322 } 323 entry->dev = dev; 324 if (entry->msi_attrib.maskbit) { 325 unsigned int maskbits, temp; 326 /* All MSIs are unmasked by default, Mask them all */ 327 pci_read_config_dword(dev, 328 msi_mask_bits_reg(pos, is_64bit_address(control)), 329 &maskbits); 330 temp = (1 << multi_msi_capable(control)); 331 temp = ((temp - 1) & ~temp); 332 maskbits |= temp; 333 pci_write_config_dword(dev, 334 msi_mask_bits_reg(pos, is_64bit_address(control)), 335 maskbits); 336 } 337 list_add(&entry->list, &dev->msi_list); 338 339 /* Configure MSI capability structure */ 340 ret = arch_setup_msi_irqs(dev, 1, PCI_CAP_ID_MSI); 341 if (ret) { 342 msi_free_irqs(dev); 343 return ret; 344 } 345 346 /* Set MSI enabled bits */ 347 pci_intx(dev, 0); /* disable intx */ 348 msi_set_enable(dev, 1); 349 dev->msi_enabled = 1; 350 351 dev->irq = entry->irq; 352 return 0; 353} 354 355/** 356 * msix_capability_init - configure device's MSI-X capability 357 * @dev: pointer to the pci_dev data structure of MSI-X device function 358 * @entries: pointer to an array of struct msix_entry entries 359 * @nvec: number of @entries 360 * 361 * Setup the MSI-X capability structure of device function with a 362 * single MSI-X irq. A return of zero indicates the successful setup of 363 * requested MSI-X entries with allocated irqs or non-zero for otherwise. 364 **/ 365static int msix_capability_init(struct pci_dev *dev, 366 struct msix_entry *entries, int nvec) 367{ 368 struct msi_desc *entry; 369 int pos, i, j, nr_entries, ret; 370 unsigned long phys_addr; 371 u32 table_offset; 372 u16 control; 373 u8 bir; 374 void __iomem *base; 375 376 msix_set_enable(dev, 0);/* Ensure msix is disabled as I set it up */ 377 378 pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); 379 /* Request & Map MSI-X table region */ 380 pci_read_config_word(dev, msi_control_reg(pos), &control); 381 nr_entries = multi_msix_capable(control); 382 383 pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset); 384 bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); 385 table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; 386 phys_addr = pci_resource_start (dev, bir) + table_offset; 387 base = ioremap_nocache(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE); 388 if (base == NULL) 389 return -ENOMEM; 390 391 /* MSI-X Table Initialization */ 392 for (i = 0; i < nvec; i++) { 393 entry = alloc_msi_entry(); 394 if (!entry) 395 break; 396 397 j = entries[i].entry; 398 entry->msi_attrib.type = PCI_CAP_ID_MSIX; 399 entry->msi_attrib.is_64 = 1; 400 entry->msi_attrib.entry_nr = j; 401 entry->msi_attrib.maskbit = 1; 402 entry->msi_attrib.masked = 1; 403 entry->msi_attrib.default_irq = dev->irq; 404 entry->msi_attrib.pos = pos; 405 entry->dev = dev; 406 entry->mask_base = base; 407 408 list_add(&entry->list, &dev->msi_list); 409 } 410 411 ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX); 412 if (ret) { 413 int avail = 0; 414 list_for_each_entry(entry, &dev->msi_list, list) { 415 if (entry->irq != 0) { 416 avail++; 417 } 418 } 419 420 msi_free_irqs(dev); 421 422 /* If we had some success report the number of irqs 423 * we succeeded in setting up. 424 */ 425 if (avail == 0) 426 avail = ret; 427 return avail; 428 } 429 430 i = 0; 431 list_for_each_entry(entry, &dev->msi_list, list) { 432 entries[i].vector = entry->irq; 433 set_irq_msi(entry->irq, entry); 434 i++; 435 } 436 /* Set MSI-X enabled bits */ 437 pci_intx(dev, 0); /* disable intx */ 438 msix_set_enable(dev, 1); 439 dev->msix_enabled = 1; 440 441 return 0; 442} 443 444/** 445 * pci_msi_check_device - check whether MSI may be enabled on a device 446 * @dev: pointer to the pci_dev data structure of MSI device function 447 * @nvec: how many MSIs have been requested ? 448 * @type: are we checking for MSI or MSI-X ? 449 * 450 * Look at global flags, the device itself, and its parent busses 451 * to determine if MSI/-X are supported for the device. If MSI/-X is 452 * supported return 0, else return an error code. 453 **/ 454static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type) 455{ 456 struct pci_bus *bus; 457 int ret; 458 459 /* MSI must be globally enabled and supported by the device */ 460 if (!pci_msi_enable || !dev || dev->no_msi) 461 return -EINVAL; 462 463 /* 464 * You can't ask to have 0 or less MSIs configured. 465 * a) it's stupid .. 466 * b) the list manipulation code assumes nvec >= 1. 467 */ 468 if (nvec < 1) 469 return -ERANGE; 470 471 /* Any bridge which does NOT route MSI transactions from it's 472 * secondary bus to it's primary bus must set NO_MSI flag on 473 * the secondary pci_bus. 474 * We expect only arch-specific PCI host bus controller driver 475 * or quirks for specific PCI bridges to be setting NO_MSI. 476 */ 477 for (bus = dev->bus; bus; bus = bus->parent) 478 if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) 479 return -EINVAL; 480 481 ret = arch_msi_check_device(dev, nvec, type); 482 if (ret) 483 return ret; 484 485 if (!pci_find_capability(dev, type)) 486 return -EINVAL; 487 488 return 0; 489} 490 491/** 492 * pci_enable_msi - configure device's MSI capability structure 493 * @dev: pointer to the pci_dev data structure of MSI device function 494 * 495 * Setup the MSI capability structure of device function with 496 * a single MSI irq upon its software driver call to request for 497 * MSI mode enabled on its hardware device function. A return of zero 498 * indicates the successful setup of an entry zero with the new MSI 499 * irq or non-zero for otherwise. 500 **/ 501int pci_enable_msi(struct pci_dev* dev) 502{ 503 int status; 504 505 status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI); 506 if (status) 507 return status; 508 509 WARN_ON(!!dev->msi_enabled); 510 511 /* Check whether driver already requested for MSI-X irqs */ 512 if (dev->msix_enabled) { 513 printk(KERN_INFO "PCI: %s: Can't enable MSI. " 514 "Device already has MSI-X enabled\n", 515 pci_name(dev)); 516 return -EINVAL; 517 } 518 status = msi_capability_init(dev); 519 return status; 520} 521EXPORT_SYMBOL(pci_enable_msi); 522 523void pci_disable_msi(struct pci_dev* dev) 524{ 525 struct msi_desc *entry; 526 int default_irq; 527 528 if (!pci_msi_enable || !dev || !dev->msi_enabled) 529 return; 530 531 msi_set_enable(dev, 0); 532 pci_intx(dev, 1); /* enable intx */ 533 dev->msi_enabled = 0; 534 535 BUG_ON(list_empty(&dev->msi_list)); 536 entry = list_entry(dev->msi_list.next, struct msi_desc, list); 537 if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { 538 return; 539 } 540 541 default_irq = entry->msi_attrib.default_irq; 542 msi_free_irqs(dev); 543 544 /* Restore dev->irq to its default pin-assertion irq */ 545 dev->irq = default_irq; 546} 547EXPORT_SYMBOL(pci_disable_msi); 548 549static int msi_free_irqs(struct pci_dev* dev) 550{ 551 struct msi_desc *entry, *tmp; 552 553 list_for_each_entry(entry, &dev->msi_list, list) 554 BUG_ON(irq_has_action(entry->irq)); 555 556 arch_teardown_msi_irqs(dev); 557 558 list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) { 559 if (entry->msi_attrib.type == PCI_CAP_ID_MSIX) { 560 if (list_is_last(&entry->list, &dev->msi_list)) 561 iounmap(entry->mask_base); 562 563 writel(1, entry->mask_base + entry->msi_attrib.entry_nr 564 * PCI_MSIX_ENTRY_SIZE 565 + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); 566 } 567 list_del(&entry->list); 568 kfree(entry); 569 } 570 571 return 0; 572} 573 574/** 575 * pci_enable_msix - configure device's MSI-X capability structure 576 * @dev: pointer to the pci_dev data structure of MSI-X device function 577 * @entries: pointer to an array of MSI-X entries 578 * @nvec: number of MSI-X irqs requested for allocation by device driver 579 * 580 * Setup the MSI-X capability structure of device function with the number 581 * of requested irqs upon its software driver call to request for 582 * MSI-X mode enabled on its hardware device function. A return of zero 583 * indicates the successful configuration of MSI-X capability structure 584 * with new allocated MSI-X irqs. A return of < 0 indicates a failure. 585 * Or a return of > 0 indicates that driver request is exceeding the number 586 * of irqs available. Driver should use the returned value to re-send 587 * its request. 588 **/ 589int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) 590{ 591 int status, pos, nr_entries; 592 int i, j; 593 u16 control; 594 595 if (!entries) 596 return -EINVAL; 597 598 status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX); 599 if (status) 600 return status; 601 602 pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); 603 pci_read_config_word(dev, msi_control_reg(pos), &control); 604 nr_entries = multi_msix_capable(control); 605 if (nvec > nr_entries) 606 return -EINVAL; 607 608 /* Check for any invalid entries */ 609 for (i = 0; i < nvec; i++) { 610 if (entries[i].entry >= nr_entries) 611 return -EINVAL; /* invalid entry */ 612 for (j = i + 1; j < nvec; j++) { 613 if (entries[i].entry == entries[j].entry) 614 return -EINVAL; /* duplicate entry */ 615 } 616 } 617 WARN_ON(!!dev->msix_enabled); 618 619 /* Check whether driver already requested for MSI irq */ 620 if (dev->msi_enabled) { 621 printk(KERN_INFO "PCI: %s: Can't enable MSI-X. " 622 "Device already has an MSI irq assigned\n", 623 pci_name(dev)); 624 return -EINVAL; 625 } 626 status = msix_capability_init(dev, entries, nvec); 627 return status; 628} 629EXPORT_SYMBOL(pci_enable_msix); 630 631static void msix_free_all_irqs(struct pci_dev *dev) 632{ 633 msi_free_irqs(dev); 634} 635 636void pci_disable_msix(struct pci_dev* dev) 637{ 638 if (!pci_msi_enable || !dev || !dev->msix_enabled) 639 return; 640 641 msix_set_enable(dev, 0); 642 pci_intx(dev, 1); /* enable intx */ 643 dev->msix_enabled = 0; 644 645 msix_free_all_irqs(dev); 646} 647EXPORT_SYMBOL(pci_disable_msix); 648 649/** 650 * msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state 651 * @dev: pointer to the pci_dev data structure of MSI(X) device function 652 * 653 * Being called during hotplug remove, from which the device function 654 * is hot-removed. All previous assigned MSI/MSI-X irqs, if 655 * allocated for this device function, are reclaimed to unused state, 656 * which may be used later on. 657 **/ 658void msi_remove_pci_irq_vectors(struct pci_dev* dev) 659{ 660 if (!pci_msi_enable || !dev) 661 return; 662 663 if (dev->msi_enabled) 664 msi_free_irqs(dev); 665 666 if (dev->msix_enabled) 667 msix_free_all_irqs(dev); 668} 669 670void pci_no_msi(void) 671{ 672 pci_msi_enable = 0; 673} 674 675void pci_msi_init_pci_dev(struct pci_dev *dev) 676{ 677 INIT_LIST_HEAD(&dev->msi_list); 678} 679 680 681/* Arch hooks */ 682 683int __attribute__ ((weak)) 684arch_msi_check_device(struct pci_dev* dev, int nvec, int type) 685{ 686 return 0; 687} 688 689int __attribute__ ((weak)) 690arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry) 691{ 692 return 0; 693} 694 695int __attribute__ ((weak)) 696arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) 697{ 698 struct msi_desc *entry; 699 int ret; 700 701 list_for_each_entry(entry, &dev->msi_list, list) { 702 ret = arch_setup_msi_irq(dev, entry); 703 if (ret) 704 return ret; 705 } 706 707 return 0; 708} 709 710void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq) 711{ 712 return; 713} 714 715void __attribute__ ((weak)) 716arch_teardown_msi_irqs(struct pci_dev *dev) 717{ 718 struct msi_desc *entry; 719 720 list_for_each_entry(entry, &dev->msi_list, list) { 721 if (entry->irq != 0) 722 arch_teardown_msi_irq(entry->irq); 723 } 724} 725