diff options
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]; |