Skip to content

Commit

Permalink
[PATCH] msi: refactor and move the msi irq_chip into the arch code
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Eric W. Biederman authored and Linus Torvalds committed Oct 4, 2006
1 parent 277bc33 commit 3b7d192
Show file tree
Hide file tree
Showing 13 changed files with 335 additions and 395 deletions.
81 changes: 58 additions & 23 deletions arch/i386/kernel/io_apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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 */

/*
Expand Down
89 changes: 62 additions & 27 deletions arch/x86_64/kernel/io_apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand Down
81 changes: 50 additions & 31 deletions drivers/pci/msi-altix.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,27 @@
*/

#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>
#include <asm/sn/pcibus_provider_defs.h>
#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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -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,
};
Loading

0 comments on commit 3b7d192

Please sign in to comment.