summaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
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 */