diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/msi-altix.c | 81 | ||||
-rw-r--r-- | drivers/pci/msi-apic.c | 86 | ||||
-rw-r--r-- | drivers/pci/msi.c | 150 | ||||
-rw-r--r-- | drivers/pci/msi.h | 27 |
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 */ |