diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/msi.c | 80 |
1 files changed, 22 insertions, 58 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 52c253c5ad3d..68555c11f556 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -192,37 +192,6 @@ static struct msi_desc* alloc_msi_entry(void) | |||
192 | return entry; | 192 | return entry; |
193 | } | 193 | } |
194 | 194 | ||
195 | static int create_msi_irq(void) | ||
196 | { | ||
197 | struct msi_desc *entry; | ||
198 | int irq; | ||
199 | |||
200 | entry = alloc_msi_entry(); | ||
201 | if (!entry) | ||
202 | return -ENOMEM; | ||
203 | |||
204 | irq = create_irq(); | ||
205 | if (irq < 0) { | ||
206 | kmem_cache_free(msi_cachep, entry); | ||
207 | return -EBUSY; | ||
208 | } | ||
209 | |||
210 | set_irq_msi(irq, entry); | ||
211 | |||
212 | return irq; | ||
213 | } | ||
214 | |||
215 | static void destroy_msi_irq(unsigned int irq) | ||
216 | { | ||
217 | struct msi_desc *entry; | ||
218 | |||
219 | entry = get_irq_msi(irq); | ||
220 | set_irq_chip(irq, NULL); | ||
221 | set_irq_msi(irq, NULL); | ||
222 | destroy_irq(irq); | ||
223 | kmem_cache_free(msi_cachep, entry); | ||
224 | } | ||
225 | |||
226 | static void enable_msi_mode(struct pci_dev *dev, int pos, int type) | 195 | static void enable_msi_mode(struct pci_dev *dev, int pos, int type) |
227 | { | 196 | { |
228 | u16 control; | 197 | u16 control; |
@@ -438,7 +407,6 @@ void pci_restore_msi_state(struct pci_dev *dev) | |||
438 | **/ | 407 | **/ |
439 | static int msi_capability_init(struct pci_dev *dev) | 408 | static int msi_capability_init(struct pci_dev *dev) |
440 | { | 409 | { |
441 | int status; | ||
442 | struct msi_desc *entry; | 410 | struct msi_desc *entry; |
443 | int pos, irq; | 411 | int pos, irq; |
444 | u16 control; | 412 | u16 control; |
@@ -446,13 +414,10 @@ static int msi_capability_init(struct pci_dev *dev) | |||
446 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 414 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); |
447 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 415 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
448 | /* MSI Entry Initialization */ | 416 | /* MSI Entry Initialization */ |
449 | irq = create_msi_irq(); | 417 | entry = alloc_msi_entry(); |
450 | if (irq < 0) | 418 | if (!entry) |
451 | return irq; | 419 | return -ENOMEM; |
452 | 420 | ||
453 | entry = get_irq_msi(irq); | ||
454 | entry->link.head = irq; | ||
455 | entry->link.tail = irq; | ||
456 | entry->msi_attrib.type = PCI_CAP_ID_MSI; | 421 | entry->msi_attrib.type = PCI_CAP_ID_MSI; |
457 | entry->msi_attrib.is_64 = is_64bit_address(control); | 422 | entry->msi_attrib.is_64 = is_64bit_address(control); |
458 | entry->msi_attrib.entry_nr = 0; | 423 | entry->msi_attrib.entry_nr = 0; |
@@ -478,14 +443,16 @@ static int msi_capability_init(struct pci_dev *dev) | |||
478 | maskbits); | 443 | maskbits); |
479 | } | 444 | } |
480 | /* Configure MSI capability structure */ | 445 | /* Configure MSI capability structure */ |
481 | status = arch_setup_msi_irq(irq, dev); | 446 | irq = arch_setup_msi_irq(dev, entry); |
482 | if (status < 0) { | 447 | if (irq < 0) { |
483 | destroy_msi_irq(irq); | 448 | kmem_cache_free(msi_cachep, entry); |
484 | return status; | 449 | return irq; |
485 | } | 450 | } |
486 | 451 | entry->link.head = irq; | |
452 | entry->link.tail = irq; | ||
487 | dev->first_msi_irq = irq; | 453 | dev->first_msi_irq = irq; |
488 | set_irq_msi(irq, entry); | 454 | set_irq_msi(irq, entry); |
455 | |||
489 | /* Set MSI enabled bits */ | 456 | /* Set MSI enabled bits */ |
490 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | 457 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); |
491 | 458 | ||
@@ -507,7 +474,6 @@ static int msix_capability_init(struct pci_dev *dev, | |||
507 | struct msix_entry *entries, int nvec) | 474 | struct msix_entry *entries, int nvec) |
508 | { | 475 | { |
509 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; | 476 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; |
510 | int status; | ||
511 | int irq, pos, i, j, nr_entries, temp = 0; | 477 | int irq, pos, i, j, nr_entries, temp = 0; |
512 | unsigned long phys_addr; | 478 | unsigned long phys_addr; |
513 | u32 table_offset; | 479 | u32 table_offset; |
@@ -530,13 +496,11 @@ static int msix_capability_init(struct pci_dev *dev, | |||
530 | 496 | ||
531 | /* MSI-X Table Initialization */ | 497 | /* MSI-X Table Initialization */ |
532 | for (i = 0; i < nvec; i++) { | 498 | for (i = 0; i < nvec; i++) { |
533 | irq = create_msi_irq(); | 499 | entry = alloc_msi_entry(); |
534 | if (irq < 0) | 500 | if (!entry) |
535 | break; | 501 | break; |
536 | 502 | ||
537 | entry = get_irq_msi(irq); | ||
538 | j = entries[i].entry; | 503 | j = entries[i].entry; |
539 | entries[i].vector = irq; | ||
540 | entry->msi_attrib.type = PCI_CAP_ID_MSIX; | 504 | entry->msi_attrib.type = PCI_CAP_ID_MSIX; |
541 | entry->msi_attrib.is_64 = 1; | 505 | entry->msi_attrib.is_64 = 1; |
542 | entry->msi_attrib.entry_nr = j; | 506 | entry->msi_attrib.entry_nr = j; |
@@ -545,6 +509,14 @@ static int msix_capability_init(struct pci_dev *dev, | |||
545 | entry->msi_attrib.pos = pos; | 509 | entry->msi_attrib.pos = pos; |
546 | entry->dev = dev; | 510 | entry->dev = dev; |
547 | entry->mask_base = base; | 511 | entry->mask_base = base; |
512 | |||
513 | /* Configure MSI-X capability structure */ | ||
514 | irq = arch_setup_msi_irq(dev, entry); | ||
515 | if (irq < 0) { | ||
516 | kmem_cache_free(msi_cachep, entry); | ||
517 | break; | ||
518 | } | ||
519 | entries[i].vector = irq; | ||
548 | if (!head) { | 520 | if (!head) { |
549 | entry->link.head = irq; | 521 | entry->link.head = irq; |
550 | entry->link.tail = irq; | 522 | entry->link.tail = irq; |
@@ -557,12 +529,6 @@ static int msix_capability_init(struct pci_dev *dev, | |||
557 | } | 529 | } |
558 | temp = irq; | 530 | temp = irq; |
559 | tail = entry; | 531 | tail = entry; |
560 | /* Configure MSI-X capability structure */ | ||
561 | status = arch_setup_msi_irq(irq, dev); | ||
562 | if (status < 0) { | ||
563 | destroy_msi_irq(irq); | ||
564 | break; | ||
565 | } | ||
566 | 532 | ||
567 | set_irq_msi(irq, entry); | 533 | set_irq_msi(irq, entry); |
568 | } | 534 | } |
@@ -706,8 +672,6 @@ static int msi_free_irq(struct pci_dev* dev, int irq) | |||
706 | int head, entry_nr, type; | 672 | int head, entry_nr, type; |
707 | void __iomem *base; | 673 | void __iomem *base; |
708 | 674 | ||
709 | arch_teardown_msi_irq(irq); | ||
710 | |||
711 | entry = get_irq_msi(irq); | 675 | entry = get_irq_msi(irq); |
712 | if (!entry || entry->dev != dev) { | 676 | if (!entry || entry->dev != dev) { |
713 | return -EINVAL; | 677 | return -EINVAL; |
@@ -718,9 +682,9 @@ static int msi_free_irq(struct pci_dev* dev, int irq) | |||
718 | base = entry->mask_base; | 682 | base = entry->mask_base; |
719 | get_irq_msi(entry->link.head)->link.tail = entry->link.tail; | 683 | get_irq_msi(entry->link.head)->link.tail = entry->link.tail; |
720 | get_irq_msi(entry->link.tail)->link.head = entry->link.head; | 684 | get_irq_msi(entry->link.tail)->link.head = entry->link.head; |
721 | entry->dev = NULL; | ||
722 | 685 | ||
723 | destroy_msi_irq(irq); | 686 | arch_teardown_msi_irq(irq); |
687 | kmem_cache_free(msi_cachep, entry); | ||
724 | 688 | ||
725 | if (type == PCI_CAP_ID_MSIX) { | 689 | if (type == PCI_CAP_ID_MSIX) { |
726 | writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE + | 690 | writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE + |