MSI: Use a list instead of the custom link structure

The msi descriptors are linked together with what looks a lot like
a linked list, but isn't a struct list_head list. Make it one.

The only complication is that previously we walked a list of irqs, and
got the descriptor for each with get_irq_msi(). Now we have a list of
descriptors and need to get the irq out of it, so it needs to be in the
actual struct msi_desc. We use 0 to indicate no irq is setup.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Michael Ellerman 2007-04-05 17:19:10 +10:00 коммит произвёл Greg Kroah-Hartman
Родитель bab41e9be7
Коммит 4aa9bc955d
5 изменённых файлов: 33 добавлений и 46 удалений

Просмотреть файл

@ -218,7 +218,8 @@ static struct msi_desc* alloc_msi_entry(void)
if (!entry) if (!entry)
return NULL; return NULL;
entry->link.tail = entry->link.head = 0; /* single message */ INIT_LIST_HEAD(&entry->list);
entry->irq = 0;
entry->dev = NULL; entry->dev = NULL;
return entry; return entry;
@ -253,7 +254,6 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
static void __pci_restore_msix_state(struct pci_dev *dev) static void __pci_restore_msix_state(struct pci_dev *dev)
{ {
int pos; int pos;
int irq, head, tail = 0;
struct msi_desc *entry; struct msi_desc *entry;
u16 control; u16 control;
@ -263,18 +263,14 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
/* route the table */ /* route the table */
pci_intx(dev, 0); /* disable intx */ pci_intx(dev, 0); /* disable intx */
msix_set_enable(dev, 0); msix_set_enable(dev, 0);
irq = head = dev->first_msi_irq;
entry = get_irq_msi(irq);
pos = entry->msi_attrib.pos;
while (head != tail) {
entry = get_irq_msi(irq);
write_msi_msg(irq, &entry->msg);
msi_set_mask_bit(irq, entry->msi_attrib.masked);
tail = entry->link.tail; list_for_each_entry(entry, &dev->msi_list, list) {
irq = tail; write_msi_msg(entry->irq, &entry->msg);
msi_set_mask_bit(entry->irq, entry->msi_attrib.masked);
} }
entry = get_irq_msi(dev->first_msi_irq);
pos = entry->msi_attrib.pos;
pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
control &= ~PCI_MSIX_FLAGS_MASKALL; control &= ~PCI_MSIX_FLAGS_MASKALL;
control |= PCI_MSIX_FLAGS_ENABLE; control |= PCI_MSIX_FLAGS_ENABLE;
@ -343,8 +339,8 @@ static int msi_capability_init(struct pci_dev *dev)
kfree(entry); kfree(entry);
return irq; return irq;
} }
entry->link.head = irq; entry->irq = irq;
entry->link.tail = irq; list_add(&entry->list, &dev->msi_list);
dev->first_msi_irq = irq; dev->first_msi_irq = irq;
set_irq_msi(irq, entry); set_irq_msi(irq, entry);
@ -370,8 +366,8 @@ static int msi_capability_init(struct pci_dev *dev)
static int msix_capability_init(struct pci_dev *dev, static int msix_capability_init(struct pci_dev *dev,
struct msix_entry *entries, int nvec) struct msix_entry *entries, int nvec)
{ {
struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; struct msi_desc *entry;
int irq, pos, i, j, nr_entries, temp = 0; int irq, pos, i, j, nr_entries;
unsigned long phys_addr; unsigned long phys_addr;
u32 table_offset; u32 table_offset;
u16 control; u16 control;
@ -416,19 +412,9 @@ static int msix_capability_init(struct pci_dev *dev,
kfree(entry); kfree(entry);
break; break;
} }
entry->irq = irq;
entries[i].vector = irq; entries[i].vector = irq;
if (!head) { list_add(&entry->list, &dev->msi_list);
entry->link.head = irq;
entry->link.tail = irq;
head = entry;
} else {
entry->link.head = temp;
entry->link.tail = tail->link.tail;
tail->link.tail = irq;
head->link.head = irq;
}
temp = irq;
tail = entry;
set_irq_msi(irq, entry); set_irq_msi(irq, entry);
} }
@ -557,7 +543,7 @@ EXPORT_SYMBOL(pci_disable_msi);
static int msi_free_irq(struct pci_dev* dev, int irq) static int msi_free_irq(struct pci_dev* dev, int irq)
{ {
struct msi_desc *entry; struct msi_desc *entry;
int head, entry_nr, type; int entry_nr, type;
void __iomem *base; void __iomem *base;
BUG_ON(irq_has_action(irq)); BUG_ON(irq_has_action(irq));
@ -568,10 +554,8 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
} }
type = entry->msi_attrib.type; type = entry->msi_attrib.type;
entry_nr = entry->msi_attrib.entry_nr; entry_nr = entry->msi_attrib.entry_nr;
head = entry->link.head;
base = entry->mask_base; base = entry->mask_base;
get_irq_msi(entry->link.head)->link.tail = entry->link.tail; list_del(&entry->list);
get_irq_msi(entry->link.tail)->link.head = entry->link.head;
arch_teardown_msi_irq(irq); arch_teardown_msi_irq(irq);
kfree(entry); kfree(entry);
@ -580,7 +564,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE + writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
if (head == irq) if (list_empty(&dev->msi_list))
iounmap(base); iounmap(base);
} }
@ -646,17 +630,10 @@ EXPORT_SYMBOL(pci_enable_msix);
static void msix_free_all_irqs(struct pci_dev *dev) static void msix_free_all_irqs(struct pci_dev *dev)
{ {
int irq, head, tail = 0; struct msi_desc *entry;
irq = head = dev->first_msi_irq; list_for_each_entry(entry, &dev->msi_list, list)
while (head != tail) { msi_free_irq(dev, entry->irq);
tail = get_irq_msi(irq)->link.tail;
if (irq != head)
msi_free_irq(dev, irq);
irq = tail;
}
msi_free_irq(dev, irq);
dev->first_msi_irq = 0; dev->first_msi_irq = 0;
} }
@ -699,6 +676,11 @@ void pci_no_msi(void)
pci_msi_enable = 0; pci_msi_enable = 0;
} }
void pci_msi_init_pci_dev(struct pci_dev *dev)
{
INIT_LIST_HEAD(&dev->msi_list);
}
/* Arch hooks */ /* Arch hooks */

Просмотреть файл

@ -47,8 +47,10 @@ extern unsigned int pci_pm_d3_delay;
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
void pci_no_msi(void); void pci_no_msi(void);
extern void pci_msi_init_pci_dev(struct pci_dev *dev);
#else #else
static inline void pci_no_msi(void) { } static inline void pci_no_msi(void) { }
static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
#endif #endif
#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) #if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)

Просмотреть файл

@ -857,6 +857,8 @@ struct pci_dev *alloc_pci_dev(void)
INIT_LIST_HEAD(&dev->global_list); INIT_LIST_HEAD(&dev->global_list);
INIT_LIST_HEAD(&dev->bus_list); INIT_LIST_HEAD(&dev->bus_list);
pci_msi_init_pci_dev(dev);
return dev; return dev;
} }
EXPORT_SYMBOL(alloc_pci_dev); EXPORT_SYMBOL(alloc_pci_dev);

Просмотреть файл

@ -1,6 +1,8 @@
#ifndef LINUX_MSI_H #ifndef LINUX_MSI_H
#define LINUX_MSI_H #define LINUX_MSI_H
#include <linux/list.h>
struct msi_msg { struct msi_msg {
u32 address_lo; /* low 32 bits of msi message address */ u32 address_lo; /* low 32 bits of msi message address */
u32 address_hi; /* high 32 bits of msi message address */ u32 address_hi; /* high 32 bits of msi message address */
@ -24,10 +26,8 @@ struct msi_desc {
unsigned default_irq; /* default pre-assigned irq */ unsigned default_irq; /* default pre-assigned irq */
}msi_attrib; }msi_attrib;
struct { unsigned int irq;
__u16 head; struct list_head list;
__u16 tail;
}link;
void __iomem *mask_base; void __iomem *mask_base;
struct pci_dev *dev; struct pci_dev *dev;

Просмотреть файл

@ -190,6 +190,7 @@ struct pci_dev {
struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
unsigned int first_msi_irq; unsigned int first_msi_irq;
struct list_head msi_list;
#endif #endif
}; };