diff options
-rw-r--r-- | drivers/pci/msi.c | 66 | ||||
-rw-r--r-- | drivers/pci/pci.h | 2 | ||||
-rw-r--r-- | drivers/pci/probe.c | 2 | ||||
-rw-r--r-- | include/linux/msi.h | 8 | ||||
-rw-r--r-- | include/linux/pci.h | 1 |
5 files changed, 33 insertions, 46 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 5902c00f4fce..434c7182d926 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -218,7 +218,8 @@ static struct msi_desc* alloc_msi_entry(void) | |||
218 | if (!entry) | 218 | if (!entry) |
219 | return NULL; | 219 | return NULL; |
220 | 220 | ||
221 | entry->link.tail = entry->link.head = 0; /* single message */ | 221 | INIT_LIST_HEAD(&entry->list); |
222 | entry->irq = 0; | ||
222 | entry->dev = NULL; | 223 | entry->dev = NULL; |
223 | 224 | ||
224 | return entry; | 225 | return entry; |
@@ -253,7 +254,6 @@ static void __pci_restore_msi_state(struct pci_dev *dev) | |||
253 | static void __pci_restore_msix_state(struct pci_dev *dev) | 254 | static void __pci_restore_msix_state(struct pci_dev *dev) |
254 | { | 255 | { |
255 | int pos; | 256 | int pos; |
256 | int irq, head, tail = 0; | ||
257 | struct msi_desc *entry; | 257 | struct msi_desc *entry; |
258 | u16 control; | 258 | u16 control; |
259 | 259 | ||
@@ -263,18 +263,14 @@ static void __pci_restore_msix_state(struct pci_dev *dev) | |||
263 | /* route the table */ | 263 | /* route the table */ |
264 | pci_intx(dev, 0); /* disable intx */ | 264 | pci_intx(dev, 0); /* disable intx */ |
265 | msix_set_enable(dev, 0); | 265 | msix_set_enable(dev, 0); |
266 | irq = head = dev->first_msi_irq; | ||
267 | entry = get_irq_msi(irq); | ||
268 | pos = entry->msi_attrib.pos; | ||
269 | while (head != tail) { | ||
270 | entry = get_irq_msi(irq); | ||
271 | write_msi_msg(irq, &entry->msg); | ||
272 | msi_set_mask_bit(irq, entry->msi_attrib.masked); | ||
273 | 266 | ||
274 | tail = entry->link.tail; | 267 | list_for_each_entry(entry, &dev->msi_list, list) { |
275 | irq = tail; | 268 | write_msi_msg(entry->irq, &entry->msg); |
269 | msi_set_mask_bit(entry->irq, entry->msi_attrib.masked); | ||
276 | } | 270 | } |
277 | 271 | ||
272 | entry = get_irq_msi(dev->first_msi_irq); | ||
273 | pos = entry->msi_attrib.pos; | ||
278 | pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); | 274 | pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); |
279 | control &= ~PCI_MSIX_FLAGS_MASKALL; | 275 | control &= ~PCI_MSIX_FLAGS_MASKALL; |
280 | control |= PCI_MSIX_FLAGS_ENABLE; | 276 | control |= PCI_MSIX_FLAGS_ENABLE; |
@@ -343,8 +339,8 @@ static int msi_capability_init(struct pci_dev *dev) | |||
343 | kfree(entry); | 339 | kfree(entry); |
344 | return irq; | 340 | return irq; |
345 | } | 341 | } |
346 | entry->link.head = irq; | 342 | entry->irq = irq; |
347 | entry->link.tail = irq; | 343 | list_add(&entry->list, &dev->msi_list); |
348 | dev->first_msi_irq = irq; | 344 | dev->first_msi_irq = irq; |
349 | set_irq_msi(irq, entry); | 345 | set_irq_msi(irq, entry); |
350 | 346 | ||
@@ -370,8 +366,8 @@ static int msi_capability_init(struct pci_dev *dev) | |||
370 | static int msix_capability_init(struct pci_dev *dev, | 366 | static int msix_capability_init(struct pci_dev *dev, |
371 | struct msix_entry *entries, int nvec) | 367 | struct msix_entry *entries, int nvec) |
372 | { | 368 | { |
373 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; | 369 | struct msi_desc *entry; |
374 | int irq, pos, i, j, nr_entries, temp = 0; | 370 | int irq, pos, i, j, nr_entries; |
375 | unsigned long phys_addr; | 371 | unsigned long phys_addr; |
376 | u32 table_offset; | 372 | u32 table_offset; |
377 | u16 control; | 373 | u16 control; |
@@ -416,19 +412,9 @@ static int msix_capability_init(struct pci_dev *dev, | |||
416 | kfree(entry); | 412 | kfree(entry); |
417 | break; | 413 | break; |
418 | } | 414 | } |
415 | entry->irq = irq; | ||
419 | entries[i].vector = irq; | 416 | entries[i].vector = irq; |
420 | if (!head) { | 417 | list_add(&entry->list, &dev->msi_list); |
421 | entry->link.head = irq; | ||
422 | entry->link.tail = irq; | ||
423 | head = entry; | ||
424 | } else { | ||
425 | entry->link.head = temp; | ||
426 | entry->link.tail = tail->link.tail; | ||
427 | tail->link.tail = irq; | ||
428 | head->link.head = irq; | ||
429 | } | ||
430 | temp = irq; | ||
431 | tail = entry; | ||
432 | 418 | ||
433 | set_irq_msi(irq, entry); | 419 | set_irq_msi(irq, entry); |
434 | } | 420 | } |
@@ -557,7 +543,7 @@ EXPORT_SYMBOL(pci_disable_msi); | |||
557 | static int msi_free_irq(struct pci_dev* dev, int irq) | 543 | static int msi_free_irq(struct pci_dev* dev, int irq) |
558 | { | 544 | { |
559 | struct msi_desc *entry; | 545 | struct msi_desc *entry; |
560 | int head, entry_nr, type; | 546 | int entry_nr, type; |
561 | void __iomem *base; | 547 | void __iomem *base; |
562 | 548 | ||
563 | BUG_ON(irq_has_action(irq)); | 549 | BUG_ON(irq_has_action(irq)); |
@@ -568,10 +554,8 @@ static int msi_free_irq(struct pci_dev* dev, int irq) | |||
568 | } | 554 | } |
569 | type = entry->msi_attrib.type; | 555 | type = entry->msi_attrib.type; |
570 | entry_nr = entry->msi_attrib.entry_nr; | 556 | entry_nr = entry->msi_attrib.entry_nr; |
571 | head = entry->link.head; | ||
572 | base = entry->mask_base; | 557 | base = entry->mask_base; |
573 | get_irq_msi(entry->link.head)->link.tail = entry->link.tail; | 558 | list_del(&entry->list); |
574 | get_irq_msi(entry->link.tail)->link.head = entry->link.head; | ||
575 | 559 | ||
576 | arch_teardown_msi_irq(irq); | 560 | arch_teardown_msi_irq(irq); |
577 | kfree(entry); | 561 | kfree(entry); |
@@ -580,7 +564,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq) | |||
580 | writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE + | 564 | writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE + |
581 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); | 565 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); |
582 | 566 | ||
583 | if (head == irq) | 567 | if (list_empty(&dev->msi_list)) |
584 | iounmap(base); | 568 | iounmap(base); |
585 | } | 569 | } |
586 | 570 | ||
@@ -646,17 +630,10 @@ EXPORT_SYMBOL(pci_enable_msix); | |||
646 | 630 | ||
647 | static void msix_free_all_irqs(struct pci_dev *dev) | 631 | static void msix_free_all_irqs(struct pci_dev *dev) |
648 | { | 632 | { |
649 | int irq, head, tail = 0; | 633 | struct msi_desc *entry; |
650 | |||
651 | irq = head = dev->first_msi_irq; | ||
652 | while (head != tail) { | ||
653 | tail = get_irq_msi(irq)->link.tail; | ||
654 | 634 | ||
655 | if (irq != head) | 635 | list_for_each_entry(entry, &dev->msi_list, list) |
656 | msi_free_irq(dev, irq); | 636 | msi_free_irq(dev, entry->irq); |
657 | irq = tail; | ||
658 | } | ||
659 | msi_free_irq(dev, irq); | ||
660 | dev->first_msi_irq = 0; | 637 | dev->first_msi_irq = 0; |
661 | } | 638 | } |
662 | 639 | ||
@@ -699,6 +676,11 @@ void pci_no_msi(void) | |||
699 | pci_msi_enable = 0; | 676 | pci_msi_enable = 0; |
700 | } | 677 | } |
701 | 678 | ||
679 | void pci_msi_init_pci_dev(struct pci_dev *dev) | ||
680 | { | ||
681 | INIT_LIST_HEAD(&dev->msi_list); | ||
682 | } | ||
683 | |||
702 | 684 | ||
703 | /* Arch hooks */ | 685 | /* Arch hooks */ |
704 | 686 | ||
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 62ea04c8af64..3fec13d3add7 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
@@ -47,8 +47,10 @@ extern unsigned int pci_pm_d3_delay; | |||
47 | 47 | ||
48 | #ifdef CONFIG_PCI_MSI | 48 | #ifdef CONFIG_PCI_MSI |
49 | void pci_no_msi(void); | 49 | void pci_no_msi(void); |
50 | extern void pci_msi_init_pci_dev(struct pci_dev *dev); | ||
50 | #else | 51 | #else |
51 | static inline void pci_no_msi(void) { } | 52 | static inline void pci_no_msi(void) { } |
53 | static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } | ||
52 | #endif | 54 | #endif |
53 | 55 | ||
54 | #if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) | 56 | #if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index c659f8ae441a..e48fcf089621 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -857,6 +857,8 @@ struct pci_dev *alloc_pci_dev(void) | |||
857 | INIT_LIST_HEAD(&dev->global_list); | 857 | INIT_LIST_HEAD(&dev->global_list); |
858 | INIT_LIST_HEAD(&dev->bus_list); | 858 | INIT_LIST_HEAD(&dev->bus_list); |
859 | 859 | ||
860 | pci_msi_init_pci_dev(dev); | ||
861 | |||
860 | return dev; | 862 | return dev; |
861 | } | 863 | } |
862 | EXPORT_SYMBOL(alloc_pci_dev); | 864 | EXPORT_SYMBOL(alloc_pci_dev); |
diff --git a/include/linux/msi.h b/include/linux/msi.h index d2a200048b22..931e013f1db5 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef LINUX_MSI_H | 1 | #ifndef LINUX_MSI_H |
2 | #define LINUX_MSI_H | 2 | #define LINUX_MSI_H |
3 | 3 | ||
4 | #include <linux/list.h> | ||
5 | |||
4 | struct msi_msg { | 6 | struct msi_msg { |
5 | u32 address_lo; /* low 32 bits of msi message address */ | 7 | u32 address_lo; /* low 32 bits of msi message address */ |
6 | u32 address_hi; /* high 32 bits of msi message address */ | 8 | u32 address_hi; /* high 32 bits of msi message address */ |
@@ -24,10 +26,8 @@ struct msi_desc { | |||
24 | unsigned default_irq; /* default pre-assigned irq */ | 26 | unsigned default_irq; /* default pre-assigned irq */ |
25 | }msi_attrib; | 27 | }msi_attrib; |
26 | 28 | ||
27 | struct { | 29 | unsigned int irq; |
28 | __u16 head; | 30 | struct list_head list; |
29 | __u16 tail; | ||
30 | }link; | ||
31 | 31 | ||
32 | void __iomem *mask_base; | 32 | void __iomem *mask_base; |
33 | struct pci_dev *dev; | 33 | struct pci_dev *dev; |
diff --git a/include/linux/pci.h b/include/linux/pci.h index c02074785d40..d43097dc8672 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -190,6 +190,7 @@ struct pci_dev { | |||
190 | struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ | 190 | struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ |
191 | #ifdef CONFIG_PCI_MSI | 191 | #ifdef CONFIG_PCI_MSI |
192 | unsigned int first_msi_irq; | 192 | unsigned int first_msi_irq; |
193 | struct list_head msi_list; | ||
193 | #endif | 194 | #endif |
194 | }; | 195 | }; |
195 | 196 | ||