Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4aa9bc95 authored by Michael Ellerman's avatar Michael Ellerman Committed by Greg Kroah-Hartman
Browse files

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: default avatarMichael Ellerman <michael@ellerman.id.au>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent bab41e9b
Loading
Loading
Loading
Loading
+24 −42
Original line number Diff line number Diff line
@@ -218,7 +218,8 @@ static struct msi_desc* alloc_msi_entry(void)
	if (!entry)
		return NULL;

	entry->link.tail = entry->link.head = 0;	/* single message */
	INIT_LIST_HEAD(&entry->list);
	entry->irq = 0;
	entry->dev = NULL;

	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)
{
	int pos;
	int irq, head, tail = 0;
	struct msi_desc *entry;
	u16 control;

@@ -263,18 +263,14 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
	/* route the table */
	pci_intx(dev, 0);		/* disable intx */
	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;
		irq = tail;
	list_for_each_entry(entry, &dev->msi_list, list) {
		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);
	control &= ~PCI_MSIX_FLAGS_MASKALL;
	control |= PCI_MSIX_FLAGS_ENABLE;
@@ -343,8 +339,8 @@ static int msi_capability_init(struct pci_dev *dev)
		kfree(entry);
		return irq;
	}
	entry->link.head = irq;
	entry->link.tail = irq;
	entry->irq = irq;
	list_add(&entry->list, &dev->msi_list);
	dev->first_msi_irq = irq;
	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,
				struct msix_entry *entries, int nvec)
{
	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
	int irq, pos, i, j, nr_entries, temp = 0;
	struct msi_desc *entry;
	int irq, pos, i, j, nr_entries;
	unsigned long phys_addr;
	u32 table_offset;
 	u16 control;
@@ -416,19 +412,9 @@ static int msix_capability_init(struct pci_dev *dev,
			kfree(entry);
			break;
		}
		entry->irq = irq;
 		entries[i].vector = irq;
		if (!head) {
			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;
		list_add(&entry->list, &dev->msi_list);

		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)
{
	struct msi_desc *entry;
	int head, entry_nr, type;
	int entry_nr, type;
	void __iomem *base;

	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;
	entry_nr = entry->msi_attrib.entry_nr;
	head = entry->link.head;
	base = entry->mask_base;
	get_irq_msi(entry->link.head)->link.tail = entry->link.tail;
	get_irq_msi(entry->link.tail)->link.head = entry->link.head;
	list_del(&entry->list);

	arch_teardown_msi_irq(irq);
	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 +
			PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);

		if (head == irq)
		if (list_empty(&dev->msi_list))
			iounmap(base);
	}

@@ -646,17 +630,10 @@ EXPORT_SYMBOL(pci_enable_msix);

static void msix_free_all_irqs(struct pci_dev *dev)
{
	int irq, head, tail = 0;

	irq = head = dev->first_msi_irq;
	while (head != tail) {
		tail = get_irq_msi(irq)->link.tail;
	struct msi_desc *entry;

		if (irq != head)
			msi_free_irq(dev, irq);
		irq = tail;
	}
	msi_free_irq(dev, irq);
	list_for_each_entry(entry, &dev->msi_list, list)
		msi_free_irq(dev, entry->irq);
	dev->first_msi_irq = 0;
}

@@ -699,6 +676,11 @@ void pci_no_msi(void)
	pci_msi_enable = 0;
}

void pci_msi_init_pci_dev(struct pci_dev *dev)
{
	INIT_LIST_HEAD(&dev->msi_list);
}


/* Arch hooks */

+2 −0
Original line number Diff line number Diff line
@@ -47,8 +47,10 @@ extern unsigned int pci_pm_d3_delay;

#ifdef CONFIG_PCI_MSI
void pci_no_msi(void);
extern void pci_msi_init_pci_dev(struct pci_dev *dev);
#else
static inline void pci_no_msi(void) { }
static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
#endif

#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
+2 −0
Original line number Diff line number Diff line
@@ -857,6 +857,8 @@ struct pci_dev *alloc_pci_dev(void)
	INIT_LIST_HEAD(&dev->global_list);
	INIT_LIST_HEAD(&dev->bus_list);

	pci_msi_init_pci_dev(dev);

	return dev;
}
EXPORT_SYMBOL(alloc_pci_dev);
+4 −4
Original line number Diff line number Diff line
#ifndef LINUX_MSI_H
#define LINUX_MSI_H

#include <linux/list.h>

struct msi_msg {
	u32	address_lo;	/* low 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	  */
	}msi_attrib;

	struct {
		__u16	head;
		__u16	tail;
	}link;
	unsigned int irq;
	struct list_head list;

	void __iomem *mask_base;
	struct pci_dev *dev;
+1 −0
Original line number Diff line number Diff line
@@ -190,6 +190,7 @@ struct pci_dev {
	struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
#ifdef CONFIG_PCI_MSI
	unsigned int first_msi_irq;
	struct list_head msi_list;
#endif
};