diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2006-10-04 05:16:59 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-04 10:55:29 -0400 |
commit | 3b7d1921f4cdd6d6ddb7899ae7a8d413991c5cf4 (patch) | |
tree | 5f809e0c4310f60dfa6f65d54fbaf9f01e2ebff9 /drivers/pci/msi.c | |
parent | 277bc33bc2479707e88b0b2ae6fe56e8e4aabe81 (diff) |
[PATCH] msi: refactor and move the msi irq_chip into the arch code
It turns out msi_ops was simply not enough to abstract the architecture
specific details of msi. So I have moved the resposibility of constructing
the struct irq_chip to the architectures, and have two architecture specific
functions arch_setup_msi_irq, and arch_teardown_msi_irq.
For simple architectures those functions can do all of the work. For
architectures with platform dependencies they can call into the appropriate
platform code.
With this msi.c is finally free of assuming you have an apic, and this
actually takes less code.
The helpers for the architecture specific code are declared in the linux/msi.h
to keep them separate from the msi functions used by drivers in linux/pci.h
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Andi Kleen <ak@suse.de>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Greg KH <greg@kroah.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/pci/msi.c')
-rw-r--r-- | drivers/pci/msi.c | 150 |
1 files changed, 31 insertions, 119 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index fc7dd2a239dd..f9fdc54473c4 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/smp_lock.h> | 15 | #include <linux/smp_lock.h> |
16 | #include <linux/pci.h> | 16 | #include <linux/pci.h> |
17 | #include <linux/proc_fs.h> | 17 | #include <linux/proc_fs.h> |
18 | #include <linux/msi.h> | ||
18 | 19 | ||
19 | #include <asm/errno.h> | 20 | #include <asm/errno.h> |
20 | #include <asm/io.h> | 21 | #include <asm/io.h> |
@@ -29,15 +30,6 @@ static kmem_cache_t* msi_cachep; | |||
29 | 30 | ||
30 | static int pci_msi_enable = 1; | 31 | static int pci_msi_enable = 1; |
31 | 32 | ||
32 | static struct msi_ops *msi_ops; | ||
33 | |||
34 | int | ||
35 | msi_register(struct msi_ops *ops) | ||
36 | { | ||
37 | msi_ops = ops; | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static int msi_cache_init(void) | 33 | static int msi_cache_init(void) |
42 | { | 34 | { |
43 | msi_cachep = kmem_cache_create("msi_cache", sizeof(struct msi_desc), | 35 | msi_cachep = kmem_cache_create("msi_cache", sizeof(struct msi_desc), |
@@ -80,8 +72,9 @@ static void msi_set_mask_bit(unsigned int irq, int flag) | |||
80 | } | 72 | } |
81 | } | 73 | } |
82 | 74 | ||
83 | static void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) | 75 | void read_msi_msg(unsigned int irq, struct msi_msg *msg) |
84 | { | 76 | { |
77 | struct msi_desc *entry = get_irq_data(irq); | ||
85 | switch(entry->msi_attrib.type) { | 78 | switch(entry->msi_attrib.type) { |
86 | case PCI_CAP_ID_MSI: | 79 | case PCI_CAP_ID_MSI: |
87 | { | 80 | { |
@@ -118,8 +111,9 @@ static void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) | |||
118 | } | 111 | } |
119 | } | 112 | } |
120 | 113 | ||
121 | static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) | 114 | void write_msi_msg(unsigned int irq, struct msi_msg *msg) |
122 | { | 115 | { |
116 | struct msi_desc *entry = get_irq_data(irq); | ||
123 | switch (entry->msi_attrib.type) { | 117 | switch (entry->msi_attrib.type) { |
124 | case PCI_CAP_ID_MSI: | 118 | case PCI_CAP_ID_MSI: |
125 | { | 119 | { |
@@ -157,53 +151,16 @@ static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) | |||
157 | } | 151 | } |
158 | } | 152 | } |
159 | 153 | ||
160 | #ifdef CONFIG_SMP | 154 | void mask_msi_irq(unsigned int irq) |
161 | static void set_msi_affinity(unsigned int irq, cpumask_t cpu_mask) | ||
162 | { | ||
163 | struct msi_desc *entry; | ||
164 | struct msi_msg msg; | ||
165 | |||
166 | entry = msi_desc[irq]; | ||
167 | if (!entry || !entry->dev) | ||
168 | return; | ||
169 | |||
170 | read_msi_msg(entry, &msg); | ||
171 | msi_ops->target(irq, cpu_mask, &msg); | ||
172 | write_msi_msg(entry, &msg); | ||
173 | set_native_irq_info(irq, cpu_mask); | ||
174 | } | ||
175 | #else | ||
176 | #define set_msi_affinity NULL | ||
177 | #endif /* CONFIG_SMP */ | ||
178 | |||
179 | static void mask_MSI_irq(unsigned int irq) | ||
180 | { | 155 | { |
181 | msi_set_mask_bit(irq, 1); | 156 | msi_set_mask_bit(irq, 1); |
182 | } | 157 | } |
183 | 158 | ||
184 | static void unmask_MSI_irq(unsigned int irq) | 159 | void unmask_msi_irq(unsigned int irq) |
185 | { | 160 | { |
186 | msi_set_mask_bit(irq, 0); | 161 | msi_set_mask_bit(irq, 0); |
187 | } | 162 | } |
188 | 163 | ||
189 | static void ack_msi_irq(unsigned int irq) | ||
190 | { | ||
191 | move_native_irq(irq); | ||
192 | ack_APIC_irq(); | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, | ||
197 | * which implement the MSI or MSI-X Capability Structure. | ||
198 | */ | ||
199 | static struct irq_chip msi_chip = { | ||
200 | .name = "PCI-MSI", | ||
201 | .unmask = unmask_MSI_irq, | ||
202 | .mask = mask_MSI_irq, | ||
203 | .ack = ack_msi_irq, | ||
204 | .set_affinity = set_msi_affinity | ||
205 | }; | ||
206 | |||
207 | static int msi_free_irq(struct pci_dev* dev, int irq); | 164 | static int msi_free_irq(struct pci_dev* dev, int irq); |
208 | static int msi_init(void) | 165 | static int msi_init(void) |
209 | { | 166 | { |
@@ -219,22 +176,6 @@ static int msi_init(void) | |||
219 | return status; | 176 | return status; |
220 | } | 177 | } |
221 | 178 | ||
222 | status = msi_arch_init(); | ||
223 | if (status < 0) { | ||
224 | pci_msi_enable = 0; | ||
225 | printk(KERN_WARNING | ||
226 | "PCI: MSI arch init failed. MSI disabled.\n"); | ||
227 | return status; | ||
228 | } | ||
229 | |||
230 | if (! msi_ops) { | ||
231 | pci_msi_enable = 0; | ||
232 | printk(KERN_WARNING | ||
233 | "PCI: MSI ops not registered. MSI disabled.\n"); | ||
234 | status = -EINVAL; | ||
235 | return status; | ||
236 | } | ||
237 | |||
238 | status = msi_cache_init(); | 179 | status = msi_cache_init(); |
239 | if (status < 0) { | 180 | if (status < 0) { |
240 | pci_msi_enable = 0; | 181 | pci_msi_enable = 0; |
@@ -268,7 +209,7 @@ static void attach_msi_entry(struct msi_desc *entry, int irq) | |||
268 | spin_unlock_irqrestore(&msi_lock, flags); | 209 | spin_unlock_irqrestore(&msi_lock, flags); |
269 | } | 210 | } |
270 | 211 | ||
271 | static int create_msi_irq(struct irq_chip *chip) | 212 | static int create_msi_irq(void) |
272 | { | 213 | { |
273 | struct msi_desc *entry; | 214 | struct msi_desc *entry; |
274 | int irq; | 215 | int irq; |
@@ -283,7 +224,6 @@ static int create_msi_irq(struct irq_chip *chip) | |||
283 | return -EBUSY; | 224 | return -EBUSY; |
284 | } | 225 | } |
285 | 226 | ||
286 | set_irq_chip_and_handler(irq, chip, handle_edge_irq); | ||
287 | set_irq_data(irq, entry); | 227 | set_irq_data(irq, entry); |
288 | 228 | ||
289 | return irq; | 229 | return irq; |
@@ -473,7 +413,7 @@ int pci_save_msix_state(struct pci_dev *dev) | |||
473 | struct msi_desc *entry; | 413 | struct msi_desc *entry; |
474 | 414 | ||
475 | entry = msi_desc[irq]; | 415 | entry = msi_desc[irq]; |
476 | read_msi_msg(entry, &entry->msg_save); | 416 | read_msi_msg(irq, &entry->msg_save); |
477 | 417 | ||
478 | tail = msi_desc[irq]->link.tail; | 418 | tail = msi_desc[irq]->link.tail; |
479 | irq = tail; | 419 | irq = tail; |
@@ -512,7 +452,7 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
512 | irq = head = dev->irq; | 452 | irq = head = dev->irq; |
513 | while (head != tail) { | 453 | while (head != tail) { |
514 | entry = msi_desc[irq]; | 454 | entry = msi_desc[irq]; |
515 | write_msi_msg(entry, &entry->msg_save); | 455 | write_msi_msg(irq, &entry->msg_save); |
516 | 456 | ||
517 | tail = msi_desc[irq]->link.tail; | 457 | tail = msi_desc[irq]->link.tail; |
518 | irq = tail; | 458 | irq = tail; |
@@ -524,39 +464,6 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
524 | } | 464 | } |
525 | #endif | 465 | #endif |
526 | 466 | ||
527 | static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | ||
528 | { | ||
529 | int status; | ||
530 | struct msi_msg msg; | ||
531 | int pos; | ||
532 | u16 control; | ||
533 | |||
534 | pos = entry->msi_attrib.pos; | ||
535 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
536 | |||
537 | /* Configure MSI capability structure */ | ||
538 | status = msi_ops->setup(dev, dev->irq, &msg); | ||
539 | if (status < 0) | ||
540 | return status; | ||
541 | |||
542 | write_msi_msg(entry, &msg); | ||
543 | if (entry->msi_attrib.maskbit) { | ||
544 | unsigned int maskbits, temp; | ||
545 | /* All MSIs are unmasked by default, Mask them all */ | ||
546 | pci_read_config_dword(dev, | ||
547 | msi_mask_bits_reg(pos, is_64bit_address(control)), | ||
548 | &maskbits); | ||
549 | temp = (1 << multi_msi_capable(control)); | ||
550 | temp = ((temp - 1) & ~temp); | ||
551 | maskbits |= temp; | ||
552 | pci_write_config_dword(dev, | ||
553 | msi_mask_bits_reg(pos, is_64bit_address(control)), | ||
554 | maskbits); | ||
555 | } | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | /** | 467 | /** |
561 | * msi_capability_init - configure device's MSI capability structure | 468 | * msi_capability_init - configure device's MSI capability structure |
562 | * @dev: pointer to the pci_dev data structure of MSI device function | 469 | * @dev: pointer to the pci_dev data structure of MSI device function |
@@ -576,7 +483,7 @@ static int msi_capability_init(struct pci_dev *dev) | |||
576 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 483 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); |
577 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 484 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
578 | /* MSI Entry Initialization */ | 485 | /* MSI Entry Initialization */ |
579 | irq = create_msi_irq(&msi_chip); | 486 | irq = create_msi_irq(); |
580 | if (irq < 0) | 487 | if (irq < 0) |
581 | return irq; | 488 | return irq; |
582 | 489 | ||
@@ -589,16 +496,27 @@ static int msi_capability_init(struct pci_dev *dev) | |||
589 | entry->msi_attrib.maskbit = is_mask_bit_support(control); | 496 | entry->msi_attrib.maskbit = is_mask_bit_support(control); |
590 | entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ | 497 | entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ |
591 | entry->msi_attrib.pos = pos; | 498 | entry->msi_attrib.pos = pos; |
592 | dev->irq = irq; | ||
593 | entry->dev = dev; | ||
594 | if (is_mask_bit_support(control)) { | 499 | if (is_mask_bit_support(control)) { |
595 | entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos, | 500 | entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos, |
596 | is_64bit_address(control)); | 501 | is_64bit_address(control)); |
597 | } | 502 | } |
503 | entry->dev = dev; | ||
504 | if (entry->msi_attrib.maskbit) { | ||
505 | unsigned int maskbits, temp; | ||
506 | /* All MSIs are unmasked by default, Mask them all */ | ||
507 | pci_read_config_dword(dev, | ||
508 | msi_mask_bits_reg(pos, is_64bit_address(control)), | ||
509 | &maskbits); | ||
510 | temp = (1 << multi_msi_capable(control)); | ||
511 | temp = ((temp - 1) & ~temp); | ||
512 | maskbits |= temp; | ||
513 | pci_write_config_dword(dev, | ||
514 | msi_mask_bits_reg(pos, is_64bit_address(control)), | ||
515 | maskbits); | ||
516 | } | ||
598 | /* Configure MSI capability structure */ | 517 | /* Configure MSI capability structure */ |
599 | status = msi_register_init(dev, entry); | 518 | status = arch_setup_msi_irq(irq, dev); |
600 | if (status != 0) { | 519 | if (status < 0) { |
601 | dev->irq = entry->msi_attrib.default_irq; | ||
602 | destroy_msi_irq(irq); | 520 | destroy_msi_irq(irq); |
603 | return status; | 521 | return status; |
604 | } | 522 | } |
@@ -607,6 +525,7 @@ static int msi_capability_init(struct pci_dev *dev) | |||
607 | /* Set MSI enabled bits */ | 525 | /* Set MSI enabled bits */ |
608 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | 526 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); |
609 | 527 | ||
528 | dev->irq = irq; | ||
610 | return 0; | 529 | return 0; |
611 | } | 530 | } |
612 | 531 | ||
@@ -624,7 +543,6 @@ static int msix_capability_init(struct pci_dev *dev, | |||
624 | struct msix_entry *entries, int nvec) | 543 | struct msix_entry *entries, int nvec) |
625 | { | 544 | { |
626 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; | 545 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; |
627 | struct msi_msg msg; | ||
628 | int status; | 546 | int status; |
629 | int irq, pos, i, j, nr_entries, temp = 0; | 547 | int irq, pos, i, j, nr_entries, temp = 0; |
630 | unsigned long phys_addr; | 548 | unsigned long phys_addr; |
@@ -648,7 +566,7 @@ static int msix_capability_init(struct pci_dev *dev, | |||
648 | 566 | ||
649 | /* MSI-X Table Initialization */ | 567 | /* MSI-X Table Initialization */ |
650 | for (i = 0; i < nvec; i++) { | 568 | for (i = 0; i < nvec; i++) { |
651 | irq = create_msi_irq(&msi_chip); | 569 | irq = create_msi_irq(); |
652 | if (irq < 0) | 570 | if (irq < 0) |
653 | break; | 571 | break; |
654 | 572 | ||
@@ -676,13 +594,12 @@ static int msix_capability_init(struct pci_dev *dev, | |||
676 | temp = irq; | 594 | temp = irq; |
677 | tail = entry; | 595 | tail = entry; |
678 | /* Configure MSI-X capability structure */ | 596 | /* Configure MSI-X capability structure */ |
679 | status = msi_ops->setup(dev, irq, &msg); | 597 | status = arch_setup_msi_irq(irq, dev); |
680 | if (status < 0) { | 598 | if (status < 0) { |
681 | destroy_msi_irq(irq); | 599 | destroy_msi_irq(irq); |
682 | break; | 600 | break; |
683 | } | 601 | } |
684 | 602 | ||
685 | write_msi_msg(entry, &msg); | ||
686 | attach_msi_entry(entry, irq); | 603 | attach_msi_entry(entry, irq); |
687 | } | 604 | } |
688 | if (i != nvec) { | 605 | if (i != nvec) { |
@@ -746,7 +663,6 @@ int pci_msi_supported(struct pci_dev * dev) | |||
746 | int pci_enable_msi(struct pci_dev* dev) | 663 | int pci_enable_msi(struct pci_dev* dev) |
747 | { | 664 | { |
748 | int pos, temp, status; | 665 | int pos, temp, status; |
749 | u16 control; | ||
750 | 666 | ||
751 | if (pci_msi_supported(dev) < 0) | 667 | if (pci_msi_supported(dev) < 0) |
752 | return -EINVAL; | 668 | return -EINVAL; |
@@ -761,10 +677,6 @@ int pci_enable_msi(struct pci_dev* dev) | |||
761 | if (!pos) | 677 | if (!pos) |
762 | return -EINVAL; | 678 | return -EINVAL; |
763 | 679 | ||
764 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
765 | if (!is_64bit_address(control) && msi_ops->needs_64bit_address) | ||
766 | return -EINVAL; | ||
767 | |||
768 | WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI)); | 680 | WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI)); |
769 | 681 | ||
770 | /* Check whether driver already requested for MSI-X irqs */ | 682 | /* Check whether driver already requested for MSI-X irqs */ |
@@ -831,7 +743,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq) | |||
831 | void __iomem *base; | 743 | void __iomem *base; |
832 | unsigned long flags; | 744 | unsigned long flags; |
833 | 745 | ||
834 | msi_ops->teardown(irq); | 746 | arch_teardown_msi_irq(irq); |
835 | 747 | ||
836 | spin_lock_irqsave(&msi_lock, flags); | 748 | spin_lock_irqsave(&msi_lock, flags); |
837 | entry = msi_desc[irq]; | 749 | entry = msi_desc[irq]; |