diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2007-01-28 14:56:37 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-02-07 18:50:08 -0500 |
commit | f7feaca77d6ad6bcfcc88ac54e3188970448d6fe (patch) | |
tree | 3002076ed2b6ab497b3b90232ff11b08de2eca5d /drivers/pci | |
parent | 5b912c108c8b1fcecbfe13d6d9a183db97b682d3 (diff) |
msi: Make MSI useable more architectures
The arch hooks arch_setup_msi_irq and arch_teardown_msi_irq are now
responsible for allocating and freeing the linux irq in addition to
setting up the the linux irq to work with the interrupt.
arch_setup_msi_irq now takes a pci_device and a msi_desc and returns
an irq.
With this change in place this code should be useable by all platforms
except those that won't let the OS touch the hardware like ppc RTAS.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
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 + |