aboutsummaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2006-10-04 02:16:59 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-04 07:55:29 -0700
commit3b7d1921f4cdd6d6ddb7899ae7a8d413991c5cf4 (patch)
tree5f809e0c4310f60dfa6f65d54fbaf9f01e2ebff9 /drivers/pci
parent277bc33bc2479707e88b0b2ae6fe56e8e4aabe81 (diff)
[PATCH] msi: refactor and move the msi irq_chip into the arch code
It turns out msi_ops was simply not enough to abstract the architecture specific details of msi. So I have moved the resposibility of constructing the struct irq_chip to the architectures, and have two architecture specific functions arch_setup_msi_irq, and arch_teardown_msi_irq. For simple architectures those functions can do all of the work. For architectures with platform dependencies they can call into the appropriate platform code. With this msi.c is finally free of assuming you have an apic, and this actually takes less code. The helpers for the architecture specific code are declared in the linux/msi.h to keep them separate from the msi functions used by drivers in linux/pci.h Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Tony Luck <tony.luck@intel.com> Cc: Andi Kleen <ak@suse.de> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Greg KH <greg@kroah.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/msi-altix.c81
-rw-r--r--drivers/pci/msi-apic.c86
-rw-r--r--drivers/pci/msi.c150
-rw-r--r--drivers/pci/msi.h27
4 files changed, 145 insertions, 199 deletions
diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c
index 7aedc2ac8c2..6ffd1f850d4 100644
--- a/drivers/pci/msi-altix.c
+++ b/drivers/pci/msi-altix.c
@@ -7,8 +7,10 @@
*/
#include <linux/types.h>
+#include <linux/irq.h>
#include <linux/pci.h>
#include <linux/cpumask.h>
+#include <linux/msi.h>
#include <asm/sn/addrs.h>
#include <asm/sn/intr.h>
@@ -16,17 +18,16 @@
#include <asm/sn/pcidev.h>
#include <asm/sn/nodepda.h>
-#include "msi.h"
-
struct sn_msi_info {
u64 pci_addr;
struct sn_irq_info *sn_irq_info;
};
-static struct sn_msi_info *sn_msi_info;
+static struct sn_msi_info sn_msi_info[NR_IRQS];
+
+static struct irq_chip sn_msi_chip;
-static void
-sn_msi_teardown(unsigned int irq)
+void sn_teardown_msi_irq(unsigned int irq)
{
nasid_t nasid;
int widget;
@@ -61,9 +62,10 @@ sn_msi_teardown(unsigned int irq)
return;
}
-int
-sn_msi_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
+int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
{
+ struct msi_msg msg;
+ struct msi_desc *entry;
int widget;
int status;
nasid_t nasid;
@@ -72,6 +74,10 @@ sn_msi_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
+ entry = get_irq_data(irq);
+ if (!entry->msi_attrib.is_64)
+ return -EINVAL;
+
if (bussoft == NULL)
return -EINVAL;
@@ -121,25 +127,29 @@ sn_msi_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
sn_msi_info[irq].sn_irq_info = sn_irq_info;
sn_msi_info[irq].pci_addr = bus_addr;
- msg->address_hi = (u32)(bus_addr >> 32);
- msg->address_lo = (u32)(bus_addr & 0x00000000ffffffff);
+ msg.address_hi = (u32)(bus_addr >> 32);
+ msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
/*
* In the SN platform, bit 16 is a "send vector" bit which
* must be present in order to move the vector through the system.
*/
- msg->data = 0x100 + irq;
+ msg.data = 0x100 + irq;
#ifdef CONFIG_SMP
set_irq_affinity_info(irq, sn_irq_info->irq_cpuid, 0);
#endif
+ write_msi_msg(irq, &msg);
+ set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
+
return 0;
}
-static void
-sn_msi_target(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg)
+#ifdef CONFIG_SMP
+static void sn_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
{
+ struct msi_msg msg;
int slice;
nasid_t nasid;
u64 bus_addr;
@@ -159,11 +169,12 @@ sn_msi_target(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg)
* Release XIO resources for the old MSI PCI address
*/
+ read_msi_msg(irq, &msg);
sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
pdev = sn_pdev->pdi_linux_pcidev;
provider = SN_PCIDEV_BUSPROVIDER(pdev);
- bus_addr = (u64)(msg->address_hi) << 32 | (u64)(msg->address_lo);
+ bus_addr = (u64)(msg.address_hi) << 32 | (u64)(msg.address_lo);
(*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE);
sn_msi_info[irq].pci_addr = 0;
@@ -185,27 +196,35 @@ sn_msi_target(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg)
SN_DMA_MSI|SN_DMA_ADDR_XIO);
sn_msi_info[irq].pci_addr = bus_addr;
- msg->address_hi = (u32)(bus_addr >> 32);
- msg->address_lo = (u32)(bus_addr & 0x00000000ffffffff);
+ msg.address_hi = (u32)(bus_addr >> 32);
+ msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
+
+ write_msi_msg(irq, &msg);
+ set_native_irq_info(irq, cpu_mask);
}
+#endif /* CONFIG_SMP */
-struct msi_ops sn_msi_ops = {
- .needs_64bit_address = 1,
- .setup = sn_msi_setup,
- .teardown = sn_msi_teardown,
-#ifdef CONFIG_SMP
- .target = sn_msi_target,
-#endif
-};
+static void sn_ack_msi_irq(unsigned int irq)
+{
+ move_native_irq(irq);
+ ia64_eoi();
+}
-int
-sn_msi_init(void)
+static int sn_msi_retrigger_irq(unsigned int irq)
{
- sn_msi_info =
- kzalloc(sizeof(struct sn_msi_info) * NR_IRQS, GFP_KERNEL);
- if (! sn_msi_info)
- return -ENOMEM;
+ unsigned int vector = irq;
+ ia64_resend_irq(vector);
- msi_register(&sn_msi_ops);
- return 0;
+ return 1;
}
+
+static struct irq_chip sn_msi_chip = {
+ .name = "PCI-MSI",
+ .mask = mask_msi_irq,
+ .unmask = unmask_msi_irq,
+ .ack = sn_ack_msi_irq,
+#ifdef CONFIG_SMP
+ .set_affinity = sn_set_msi_irq_affinity,
+#endif
+ .retrigger = sn_msi_retrigger_irq,
+};
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c
index afc0ed13aa8..822e59a1b82 100644
--- a/drivers/pci/msi-apic.c
+++ b/drivers/pci/msi-apic.c
@@ -4,10 +4,9 @@
#include <linux/pci.h>
#include <linux/irq.h>
+#include <linux/msi.h>
#include <asm/smp.h>
-#include "msi.h"
-
/*
* Shifts for APIC-based data
*/
@@ -31,6 +30,7 @@
* Shift/mask fields for APIC-based bus address
*/
+#define MSI_TARGET_CPU_SHIFT 4
#define MSI_ADDR_HEADER 0xfee00000
#define MSI_ADDR_DESTID_MASK 0xfff0000f
@@ -44,58 +44,100 @@
#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT)
#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT)
+static struct irq_chip ia64_msi_chip;
-static void
-msi_target_apic(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg)
+#ifdef CONFIG_SMP
+static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
{
- u32 addr = msg->address_lo;
+ struct msi_msg msg;
+ u32 addr;
+
+ read_msi_msg(irq, &msg);
+ addr = msg.address_lo;
addr &= MSI_ADDR_DESTID_MASK;
addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask)));
+ msg.address_lo = addr;
- msg->address_lo = addr;
+ write_msi_msg(irq, &msg);
+ set_native_irq_info(irq, cpu_mask);
}
+#endif /* CONFIG_SMP */
-static int
-msi_setup_apic(struct pci_dev *pdev, /* unused in generic */
- unsigned int irq,
- struct msi_msg *msg)
+int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
{
+ struct msi_msg msg;
unsigned long dest_phys_id;
unsigned int vector;
dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
vector = irq;
- msg->address_hi = 0;
- msg->address_lo =
+ msg.address_hi = 0;
+ msg.address_lo =
MSI_ADDR_HEADER |
MSI_ADDR_DESTMODE_PHYS |
MSI_ADDR_REDIRECTION_CPU |
MSI_ADDR_DESTID_CPU(dest_phys_id);
- msg->data =
+ msg.data =
MSI_DATA_TRIGGER_EDGE |
MSI_DATA_LEVEL_ASSERT |
MSI_DATA_DELIVERY_FIXED |
MSI_DATA_VECTOR(vector);
+ write_msi_msg(irq, &msg);
+ set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
+
return 0;
}
-static void
-msi_teardown_apic(unsigned int irq)
+void ia64_teardown_msi_irq(unsigned int irq)
{
return; /* no-op */
}
+static void ia64_ack_msi_irq(unsigned int irq)
+{
+ move_native_irq(irq);
+ ia64_eoi();
+}
+
+static int ia64_msi_retrigger_irq(unsigned int irq)
+{
+ unsigned int vector = irq;
+ ia64_resend_irq(vector);
+
+ return 1;
+}
+
/*
- * Generic ops used on most IA archs/platforms. Set with msi_register()
+ * Generic ops used on most IA64 platforms.
*/
-
-struct msi_ops msi_apic_ops = {
- .needs_64bit_address = 0,
- .setup = msi_setup_apic,
- .teardown = msi_teardown_apic,
- .target = msi_target_apic,
+static struct irq_chip ia64_msi_chip = {
+ .name = "PCI-MSI",
+ .mask = mask_msi_irq,
+ .unmask = unmask_msi_irq,
+ .ack = ia64_ack_msi_irq,
+#ifdef CONFIG_SMP
+ .set_affinity = ia64_set_msi_irq_affinity,
+#endif
+ .retrigger = ia64_msi_retrigger_irq,
};
+
+
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+{
+ if (platform_setup_msi_irq)
+ return platform_setup_msi_irq(irq, pdev);
+
+ return ia64_setup_msi_irq(irq, pdev);
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+ if (platform_teardown_msi_irq)
+ return platform_teardown_msi_irq(irq);
+
+ return ia64_teardown_msi_irq(irq);
+}
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index fc7dd2a239d..f9fdc54473c 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -15,6 +15,7 @@
#include <linux/smp_lock.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
+#include <linux/msi.h>
#include <asm/errno.h>
#include <asm/io.h>
@@ -29,15 +30,6 @@ static kmem_cache_t* msi_cachep;
static int pci_msi_enable = 1;
-static struct msi_ops *msi_ops;
-
-int
-msi_register(struct msi_ops *ops)
-{
- msi_ops = ops;
- return 0;
-}
-
static int msi_cache_init(void)
{
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)
}
}
-static void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
+void read_msi_msg(unsigned int irq, struct msi_msg *msg)
{
+ struct msi_desc *entry = get_irq_data(irq);
switch(entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
{
@@ -118,8 +111,9 @@ static void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
}
}
-static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
+void write_msi_msg(unsigned int irq, struct msi_msg *msg)
{
+ struct msi_desc *entry = get_irq_data(irq);
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
{
@@ -157,53 +151,16 @@ static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
}
}
-#ifdef CONFIG_SMP
-static void set_msi_affinity(unsigned int irq, cpumask_t cpu_mask)
-{
- struct msi_desc *entry;
- struct msi_msg msg;
-
- entry = msi_desc[irq];
- if (!entry || !entry->dev)
- return;
-
- read_msi_msg(entry, &msg);
- msi_ops->target(irq, cpu_mask, &msg);
- write_msi_msg(entry, &msg);
- set_native_irq_info(irq, cpu_mask);
-}
-#else
-#define set_msi_affinity NULL
-#endif /* CONFIG_SMP */
-
-static void mask_MSI_irq(unsigned int irq)
+void mask_msi_irq(unsigned int irq)
{
msi_set_mask_bit(irq, 1);
}
-static void unmask_MSI_irq(unsigned int irq)
+void unmask_msi_irq(unsigned int irq)
{
msi_set_mask_bit(irq, 0);
}
-static void ack_msi_irq(unsigned int irq)
-{
- move_native_irq(irq);
- ack_APIC_irq();
-}
-
-/*
- * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI or MSI-X Capability Structure.
- */
-static struct irq_chip msi_chip = {
- .name = "PCI-MSI",
- .unmask = unmask_MSI_irq,
- .mask = mask_MSI_irq,
- .ack = ack_msi_irq,
- .set_affinity = set_msi_affinity
-};
-
static int msi_free_irq(struct pci_dev* dev, int irq);
static int msi_init(void)
{
@@ -219,22 +176,6 @@ static int msi_init(void)
return status;
}
- status = msi_arch_init();
- if (status < 0) {
- pci_msi_enable = 0;
- printk(KERN_WARNING
- "PCI: MSI arch init failed. MSI disabled.\n");
- return status;
- }
-
- if (! msi_ops) {
- pci_msi_enable = 0;
- printk(KERN_WARNING
- "PCI: MSI ops not registered. MSI disabled.\n");
- status = -EINVAL;
- return status;
- }
-
status = msi_cache_init();
if (status < 0) {
pci_msi_enable = 0;
@@ -268,7 +209,7 @@ static void attach_msi_entry(struct msi_desc *entry, int irq)
spin_unlock_irqrestore(&msi_lock, flags);
}
-static int create_msi_irq(struct irq_chip *chip)
+static int create_msi_irq(void)
{
struct msi_desc *entry;
int irq;
@@ -283,7 +224,6 @@ static int create_msi_irq(struct irq_chip *chip)
return -EBUSY;
}
- set_irq_chip_and_handler(irq, chip, handle_edge_irq);
set_irq_data(irq, entry);
return irq;
@@ -473,7 +413,7 @@ int pci_save_msix_state(struct pci_dev *dev)
struct msi_desc *entry;
entry = msi_desc[irq];
- read_msi_msg(entry, &entry->msg_save);
+ read_msi_msg(irq, &entry->msg_save);
tail = msi_desc[irq]->link.tail;
irq = tail;
@@ -512,7 +452,7 @@ void pci_restore_msix_state(struct pci_dev *dev)
irq = head = dev->irq;
while (head != tail) {
entry = msi_desc[irq];
- write_msi_msg(entry, &entry->msg_save);
+ write_msi_msg(irq, &entry->msg_save);
tail = msi_desc[irq]->link.tail;
irq = tail;
@@ -524,39 +464,6 @@ void pci_restore_msix_state(struct pci_dev *dev)
}
#endif
-static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry)
-{
- int status;
- struct msi_msg msg;
- int pos;
- u16 control;
-
- pos = entry->msi_attrib.pos;
- pci_read_config_word(dev, msi_control_reg(pos), &control);
-
- /* Configure MSI capability structure */
- status = msi_ops->setup(dev, dev->irq, &msg);
- if (status < 0)
- return status;
-
- write_msi_msg(entry, &msg);
- if (entry->msi_attrib.maskbit) {
- unsigned int maskbits, temp;
- /* All MSIs are unmasked by default, Mask them all */
- pci_read_config_dword(dev,
- msi_mask_bits_reg(pos, is_64bit_address(control)),
- &maskbits);
- temp = (1 << multi_msi_capable(control));
- temp = ((temp - 1) & ~temp);
- maskbits |= temp;
- pci_write_config_dword(dev,
- msi_mask_bits_reg(pos, is_64bit_address(control)),
- maskbits);
- }
-
- return 0;
-}
-
/**
* msi_capability_init - configure device's MSI capability structure
* @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)
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
pci_read_config_word(dev, msi_control_reg(pos), &control);
/* MSI Entry Initialization */
- irq = create_msi_irq(&msi_chip);
+ irq = create_msi_irq();
if (irq < 0)
return irq;
@@ -589,16 +496,27 @@ static int msi_capability_init(struct pci_dev *dev)
entry->msi_attrib.maskbit = is_mask_bit_support(control);
entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
entry->msi_attrib.pos = pos;
- dev->irq = irq;
- entry->dev = dev;
if (is_mask_bit_support(control)) {
entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
is_64bit_address(control));
}
+ entry->dev = dev;
+ if (entry->msi_attrib.maskbit) {
+ unsigned int maskbits, temp;
+ /* All MSIs are unmasked by default, Mask them all */
+ pci_read_config_dword(dev,
+ msi_mask_bits_reg(pos, is_64bit_address(control)),
+ &maskbits);
+ temp = (1 << multi_msi_capable(control));
+ temp = ((temp - 1) & ~temp);
+ maskbits |= temp;
+ pci_write_config_dword(dev,
+ msi_mask_bits_reg(pos, is_64bit_address(control)),
+ maskbits);
+ }
/* Configure MSI capability structure */
- status = msi_register_init(dev, entry);
- if (status != 0) {
- dev->irq = entry->msi_attrib.default_irq;
+ status = arch_setup_msi_irq(irq, dev);
+ if (status < 0) {
destroy_msi_irq(irq);
return status;
}
@@ -607,6 +525,7 @@ static int msi_capability_init(struct pci_dev *dev)
/* Set MSI enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+ dev->irq = irq;
return 0;
}
@@ -624,7 +543,6 @@ static int msix_capability_init(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{
struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
- struct msi_msg msg;
int status;
int irq, pos, i, j, nr_entries, temp = 0;
unsigned long phys_addr;
@@ -648,7 +566,7 @@ static int msix_capability_init(struct pci_dev *dev,
/* MSI-X Table Initialization */
for (i = 0; i < nvec; i++) {
- irq = create_msi_irq(&msi_chip);
+ irq = create_msi_irq();
if (irq < 0)
break;
@@ -676,13 +594,12 @@ static int msix_capability_init(struct pci_dev *dev,
temp = irq;
tail = entry;
/* Configure MSI-X capability structure */
- status = msi_ops->setup(dev, irq, &msg);
+ status = arch_setup_msi_irq(irq, dev);
if (status < 0) {
destroy_msi_irq(irq);
break;
}
- write_msi_msg(entry, &msg);
attach_msi_entry(entry, irq);
}
if (i != nvec) {
@@ -746,7 +663,6 @@ int pci_msi_supported(struct pci_dev * dev)
int pci_enable_msi(struct pci_dev* dev)
{
int pos, temp, status;
- u16 control;
if (pci_msi_supported(dev) < 0)
return -EINVAL;
@@ -761,10 +677,6 @@ int pci_enable_msi(struct pci_dev* dev)
if (!pos)
return -EINVAL;
- pci_read_config_word(dev, msi_control_reg(pos), &control);
- if (!is_64bit_address(control) && msi_ops->needs_64bit_address)
- return -EINVAL;
-
WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI));
/* Check whether driver already requested for MSI-X irqs */
@@ -831,7 +743,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
void __iomem *base;
unsigned long flags;
- msi_ops->teardown(irq);
+ arch_teardown_msi_irq(irq);
spin_lock_irqsave(&msi_lock, flags);
entry = msi_desc[irq];
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
index 77823bfed5c..f0cca1772f9 100644
--- a/drivers/pci/msi.h
+++ b/drivers/pci/msi.h
@@ -6,8 +6,6 @@
#ifndef MSI_H
#define MSI_H
-#include <asm/msi.h>
-
/*
* MSI-X Address Register
*/
@@ -49,29 +47,4 @@
#define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK)
#define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK)
-struct msi_desc {
- struct {
- __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */
- __u8 maskbit : 1; /* mask-pending bit supported ? */
- __u8 unused : 1;
- __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */
- __u8 pos; /* Location of the msi capability */
- __u16 entry_nr; /* specific enabled entry */
- unsigned default_irq; /* default pre-assigned irq */
- }msi_attrib;
-
- struct {
- __u16 head;
- __u16 tail;
- }link;
-
- void __iomem *mask_base;
- struct pci_dev *dev;
-
-#ifdef CONFIG_PM
- /* PM save area for MSIX address/data */
- struct msi_msg msg_save;
-#endif
-};
-
#endif /* MSI_H */