aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/msi.c66
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/probe.c2
-rw-r--r--include/linux/msi.h8
-rw-r--r--include/linux/pci.h1
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)
253static void __pci_restore_msix_state(struct pci_dev *dev) 254static 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)
370static int msix_capability_init(struct pci_dev *dev, 366static 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);
557static int msi_free_irq(struct pci_dev* dev, int irq) 543static 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
647static void msix_free_all_irqs(struct pci_dev *dev) 631static 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
679void 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
49void pci_no_msi(void); 49void pci_no_msi(void);
50extern void pci_msi_init_pci_dev(struct pci_dev *dev);
50#else 51#else
51static inline void pci_no_msi(void) { } 52static inline void pci_no_msi(void) { }
53static 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}
862EXPORT_SYMBOL(alloc_pci_dev); 864EXPORT_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
4struct msi_msg { 6struct 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