Commit 3b7d1921 authored by Eric W. Biederman's avatar Eric W. Biederman Committed by Linus Torvalds
Browse files

[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: default avatarEric 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: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 277bc33b
......@@ -32,6 +32,7 @@
#include <linux/module.h>
#include <linux/sysdev.h>
#include <linux/pci.h>
#include <linux/msi.h>
#include <asm/io.h>
#include <asm/smp.h>
......@@ -2455,11 +2456,8 @@ void destroy_irq(unsigned int irq)
* MSI mesage composition
*/
#ifdef CONFIG_PCI_MSI
static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
{
/* For now always this code always uses physical delivery
* mode.
*/
int vector;
unsigned dest;
......@@ -2489,34 +2487,71 @@ static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg
return vector;
}
static void msi_msg_teardown(unsigned int irq)
{
return;
}
static void msi_msg_set_affinity(unsigned int irq, cpumask_t mask, struct msi_msg *msg)
#ifdef CONFIG_SMP
static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
{
struct msi_msg msg;
unsigned int dest;
cpumask_t tmp;
int vector;
unsigned dest;
cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
tmp = TARGET_CPUS;
vector = assign_irq_vector(irq);
if (vector > 0) {
dest = cpu_mask_to_apicid(mask);
if (vector < 0)
return;
msg->data &= ~MSI_DATA_VECTOR_MASK;
msg->data |= MSI_DATA_VECTOR(vector);
msg->address_lo &= ~MSI_ADDR_DEST_ID_MASK;
msg->address_lo |= MSI_ADDR_DEST_ID(dest);
}
dest = cpu_mask_to_apicid(mask);
read_msi_msg(irq, &msg);
msg.data &= ~MSI_DATA_VECTOR_MASK;
msg.data |= MSI_DATA_VECTOR(vector);
msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
write_msi_msg(irq, &msg);
set_native_irq_info(irq, mask);
}
#endif /* CONFIG_SMP */
struct msi_ops arch_msi_ops = {
.needs_64bit_address = 0,
.setup = msi_msg_setup,
.teardown = msi_msg_teardown,
.target = msi_msg_set_affinity,
/*
* 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_ioapic_irq,
#ifdef CONFIG_SMP
.set_affinity = set_msi_irq_affinity,
#endif
.retrigger = ioapic_retrigger_irq,
};
int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
{
struct msi_msg msg;
int ret;
ret = msi_compose_msg(dev, irq, &msg);
if (ret < 0)
return ret;
write_msi_msg(irq, &msg);
set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq);
return 0;
}
void arch_teardown_msi_irq(unsigned int irq)
{
return;
}
#endif /* CONFIG_PCI_MSI */
/*
......
......@@ -30,6 +30,7 @@
#include <linux/mc146818rtc.h>
#include <linux/acpi.h>
#include <linux/sysdev.h>
#include <linux/msi.h>
#ifdef CONFIG_ACPI
#include <acpi/acpi_bus.h>
#endif
......@@ -1701,11 +1702,8 @@ void destroy_irq(unsigned int irq)
* MSI mesage composition
*/
#ifdef CONFIG_PCI_MSI
static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
{
/* For now always this code always uses physical delivery
* mode.
*/
int vector;
unsigned dest;
......@@ -1739,39 +1737,76 @@ static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg
return vector;
}
static void msi_msg_teardown(unsigned int irq)
{
return;
}
static void msi_msg_set_affinity(unsigned int irq, cpumask_t mask, struct msi_msg *msg)
#ifdef CONFIG_SMP
static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
{
struct msi_msg msg;
unsigned int dest;
cpumask_t tmp;
int vector;
unsigned dest;
cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
tmp = TARGET_CPUS;
cpus_and(mask, tmp, CPU_MASK_ALL);
vector = assign_irq_vector(irq, mask);
if (vector > 0) {
cpumask_t tmp;
if (vector < 0)
return;
cpus_clear(tmp);
cpu_set(vector >> 8, tmp);
dest = cpu_mask_to_apicid(tmp);
cpus_clear(tmp);
cpu_set(vector >> 8, tmp);
dest = cpu_mask_to_apicid(tmp);
msg->data &= ~MSI_DATA_VECTOR_MASK;
msg->data |= MSI_DATA_VECTOR(vector);
msg->address_lo &= ~MSI_ADDR_DEST_ID_MASK;
msg->address_lo |= MSI_ADDR_DEST_ID(dest);
}
read_msi_msg(irq, &msg);
msg.data &= ~MSI_DATA_VECTOR_MASK;
msg.data |= MSI_DATA_VECTOR(vector);
msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
write_msi_msg(irq, &msg);
set_native_irq_info(irq, mask);
}
#endif /* CONFIG_SMP */
struct msi_ops arch_msi_ops = {
.needs_64bit_address = 0,
.setup = msi_msg_setup,
.teardown = msi_msg_teardown,
.target = msi_msg_set_affinity,
/*
* 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_apic_edge,
#ifdef CONFIG_SMP
.set_affinity = set_msi_irq_affinity,
#endif
.retrigger = ioapic_retrigger_irq,
};
#endif
int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
{
struct msi_msg msg;
int ret;
ret = msi_compose_msg(dev, irq, &msg);
if (ret < 0)
return ret;
write_msi_msg(irq, &msg);
set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq);
return 0;
}
void arch_teardown_msi_irq(unsigned int irq)
{
return;
}
#endif /* CONFIG_PCI_MSI */
/*
* Hypertransport interrupt support
......
......@@ -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,
};
......@@ -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);
}
<
......@@ -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
};