aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-01-28 14:56:37 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-02-07 18:50:08 -0500
commitf7feaca77d6ad6bcfcc88ac54e3188970448d6fe (patch)
tree3002076ed2b6ab497b3b90232ff11b08de2eca5d
parent5b912c108c8b1fcecbfe13d6d9a183db97b682d3 (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>
-rw-r--r--arch/i386/kernel/io_apic.c17
-rw-r--r--arch/ia64/kernel/msi_ia64.c19
-rw-r--r--arch/ia64/sn/kernel/msi_sn.c20
-rw-r--r--arch/x86_64/kernel/io_apic.c17
-rw-r--r--drivers/pci/msi.c80
-rw-r--r--include/asm-ia64/machvec.h3
-rw-r--r--include/linux/msi.h2
7 files changed, 75 insertions, 83 deletions
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 6a3875f81a0a..5592fa6e1fa1 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -2606,25 +2606,32 @@ static struct irq_chip msi_chip = {
2606 .retrigger = ioapic_retrigger_irq, 2606 .retrigger = ioapic_retrigger_irq,
2607}; 2607};
2608 2608
2609int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) 2609int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
2610{ 2610{
2611 struct msi_msg msg; 2611 struct msi_msg msg;
2612 int ret; 2612 int irq, ret;
2613 irq = create_irq();
2614 if (irq < 0)
2615 return irq;
2616
2617 set_irq_msi(irq, desc);
2613 ret = msi_compose_msg(dev, irq, &msg); 2618 ret = msi_compose_msg(dev, irq, &msg);
2614 if (ret < 0) 2619 if (ret < 0) {
2620 destroy_irq(irq);
2615 return ret; 2621 return ret;
2622 }
2616 2623
2617 write_msi_msg(irq, &msg); 2624 write_msi_msg(irq, &msg);
2618 2625
2619 set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, 2626 set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq,
2620 "edge"); 2627 "edge");
2621 2628
2622 return 0; 2629 return irq;
2623} 2630}
2624 2631
2625void arch_teardown_msi_irq(unsigned int irq) 2632void arch_teardown_msi_irq(unsigned int irq)
2626{ 2633{
2627 return; 2634 destroy_irq(irq);
2628} 2635}
2629 2636
2630#endif /* CONFIG_PCI_MSI */ 2637#endif /* CONFIG_PCI_MSI */
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
index 822e59a1b822..0d05450c91c4 100644
--- a/arch/ia64/kernel/msi_ia64.c
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -64,12 +64,17 @@ static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
64} 64}
65#endif /* CONFIG_SMP */ 65#endif /* CONFIG_SMP */
66 66
67int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) 67int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
68{ 68{
69 struct msi_msg msg; 69 struct msi_msg msg;
70 unsigned long dest_phys_id; 70 unsigned long dest_phys_id;
71 unsigned int vector; 71 unsigned int irq, vector;
72 72
73 irq = create_irq();
74 if (irq < 0)
75 return irq;
76
77 set_irq_msi(irq, desc);
73 dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); 78 dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
74 vector = irq; 79 vector = irq;
75 80
@@ -89,12 +94,12 @@ int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
89 write_msi_msg(irq, &msg); 94 write_msi_msg(irq, &msg);
90 set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq); 95 set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
91 96
92 return 0; 97 return irq;
93} 98}
94 99
95void ia64_teardown_msi_irq(unsigned int irq) 100void ia64_teardown_msi_irq(unsigned int irq)
96{ 101{
97 return; /* no-op */ 102 destroy_irq(irq);
98} 103}
99 104
100static void ia64_ack_msi_irq(unsigned int irq) 105static void ia64_ack_msi_irq(unsigned int irq)
@@ -126,12 +131,12 @@ static struct irq_chip ia64_msi_chip = {
126}; 131};
127 132
128 133
129int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) 134int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
130{ 135{
131 if (platform_setup_msi_irq) 136 if (platform_setup_msi_irq)
132 return platform_setup_msi_irq(irq, pdev); 137 return platform_setup_msi_irq(pdev, desc);
133 138
134 return ia64_setup_msi_irq(irq, pdev); 139 return ia64_setup_msi_irq(pdev, desc);
135} 140}
136 141
137void arch_teardown_msi_irq(unsigned int irq) 142void arch_teardown_msi_irq(unsigned int irq)
diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c
index 31fbb859b67e..ea3dc38d73fd 100644
--- a/arch/ia64/sn/kernel/msi_sn.c
+++ b/arch/ia64/sn/kernel/msi_sn.c
@@ -59,13 +59,12 @@ void sn_teardown_msi_irq(unsigned int irq)
59 sn_intr_free(nasid, widget, sn_irq_info); 59 sn_intr_free(nasid, widget, sn_irq_info);
60 sn_msi_info[irq].sn_irq_info = NULL; 60 sn_msi_info[irq].sn_irq_info = NULL;
61 61
62 return; 62 destroy_irq(irq);
63} 63}
64 64
65int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) 65int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry)
66{ 66{
67 struct msi_msg msg; 67 struct msi_msg msg;
68 struct msi_desc *entry;
69 int widget; 68 int widget;
70 int status; 69 int status;
71 nasid_t nasid; 70 nasid_t nasid;
@@ -73,8 +72,8 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
73 struct sn_irq_info *sn_irq_info; 72 struct sn_irq_info *sn_irq_info;
74 struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); 73 struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
75 struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); 74 struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
75 int irq;
76 76
77 entry = get_irq_msi(irq);
78 if (!entry->msi_attrib.is_64) 77 if (!entry->msi_attrib.is_64)
79 return -EINVAL; 78 return -EINVAL;
80 79
@@ -84,6 +83,11 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
84 if (provider == NULL || provider->dma_map_consistent == NULL) 83 if (provider == NULL || provider->dma_map_consistent == NULL)
85 return -EINVAL; 84 return -EINVAL;
86 85
86 irq = create_irq();
87 if (irq < 0)
88 return irq;
89
90 set_irq_msi(irq, entry);
87 /* 91 /*
88 * Set up the vector plumbing. Let the prom (via sn_intr_alloc) 92 * Set up the vector plumbing. Let the prom (via sn_intr_alloc)
89 * decide which cpu to direct this msi at by default. 93 * decide which cpu to direct this msi at by default.
@@ -95,12 +99,15 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
95 SWIN_WIDGETNUM(bussoft->bs_base); 99 SWIN_WIDGETNUM(bussoft->bs_base);
96 100
97 sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); 101 sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
98 if (! sn_irq_info) 102 if (! sn_irq_info) {
103 destroy_irq(irq);
99 return -ENOMEM; 104 return -ENOMEM;
105 }
100 106
101 status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1); 107 status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1);
102 if (status) { 108 if (status) {
103 kfree(sn_irq_info); 109 kfree(sn_irq_info);
110 destroy_irq(irq);
104 return -ENOMEM; 111 return -ENOMEM;
105 } 112 }
106 113
@@ -121,6 +128,7 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
121 if (! bus_addr) { 128 if (! bus_addr) {
122 sn_intr_free(nasid, widget, sn_irq_info); 129 sn_intr_free(nasid, widget, sn_irq_info);
123 kfree(sn_irq_info); 130 kfree(sn_irq_info);
131 destroy_irq(irq);
124 return -ENOMEM; 132 return -ENOMEM;
125 } 133 }
126 134
@@ -139,7 +147,7 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
139 write_msi_msg(irq, &msg); 147 write_msi_msg(irq, &msg);
140 set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq); 148 set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
141 149
142 return 0; 150 return irq;
143} 151}
144 152
145#ifdef CONFIG_SMP 153#ifdef CONFIG_SMP
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index d7bad90a5ad8..6be6730acb5c 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -1956,24 +1956,31 @@ static struct irq_chip msi_chip = {
1956 .retrigger = ioapic_retrigger_irq, 1956 .retrigger = ioapic_retrigger_irq,
1957}; 1957};
1958 1958
1959int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) 1959int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
1960{ 1960{
1961 struct msi_msg msg; 1961 struct msi_msg msg;
1962 int ret; 1962 int irq, ret;
1963 irq = create_irq();
1964 if (irq < 0)
1965 return irq;
1966
1967 set_irq_msi(irq, desc);
1963 ret = msi_compose_msg(dev, irq, &msg); 1968 ret = msi_compose_msg(dev, irq, &msg);
1964 if (ret < 0) 1969 if (ret < 0) {
1970 destroy_irq(irq);
1965 return ret; 1971 return ret;
1972 }
1966 1973
1967 write_msi_msg(irq, &msg); 1974 write_msi_msg(irq, &msg);
1968 1975
1969 set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); 1976 set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
1970 1977
1971 return 0; 1978 return irq;
1972} 1979}
1973 1980
1974void arch_teardown_msi_irq(unsigned int irq) 1981void arch_teardown_msi_irq(unsigned int irq)
1975{ 1982{
1976 return; 1983 destroy_irq(irq);
1977} 1984}
1978 1985
1979#endif /* CONFIG_PCI_MSI */ 1986#endif /* CONFIG_PCI_MSI */
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
195static 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
215static 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
226static void enable_msi_mode(struct pci_dev *dev, int pos, int type) 195static 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 **/
439static int msi_capability_init(struct pci_dev *dev) 408static 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 +
diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
index a3891eb3f217..3c96ac19154e 100644
--- a/include/asm-ia64/machvec.h
+++ b/include/asm-ia64/machvec.h
@@ -21,6 +21,7 @@ struct mm_struct;
21struct pci_bus; 21struct pci_bus;
22struct task_struct; 22struct task_struct;
23struct pci_dev; 23struct pci_dev;
24struct msi_desc;
24 25
25typedef void ia64_mv_setup_t (char **); 26typedef void ia64_mv_setup_t (char **);
26typedef void ia64_mv_cpu_init_t (void); 27typedef void ia64_mv_cpu_init_t (void);
@@ -79,7 +80,7 @@ typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
79typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *); 80typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
80typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *); 81typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
81 82
82typedef int ia64_mv_setup_msi_irq_t (unsigned int irq, struct pci_dev *pdev); 83typedef int ia64_mv_setup_msi_irq_t (struct pci_dev *pdev, struct msi_desc *);
83typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq); 84typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq);
84 85
85static inline void 86static inline void
diff --git a/include/linux/msi.h b/include/linux/msi.h
index b99976b1536e..74c8a2ecc9dd 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -41,7 +41,7 @@ struct msi_desc {
41/* 41/*
42 * The arch hook for setup up msi irqs 42 * The arch hook for setup up msi irqs
43 */ 43 */
44int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev); 44int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
45void arch_teardown_msi_irq(unsigned int irq); 45void arch_teardown_msi_irq(unsigned int irq);
46 46
47 47