diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-08-30 22:27:28 -0700 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-08-30 23:06:51 -0700 |
commit | 5f92c329364c0bf2d3a356da5e8759fbe349f9d1 (patch) | |
tree | 2bf27d77009229a26c371102655c5f81c7e68d1e /arch/sparc64/kernel/irq.c | |
parent | 6e69d6068cc2aa545544189a1ee4d2e1a32ad591 (diff) | |
download | op-kernel-dev-5f92c329364c0bf2d3a356da5e8759fbe349f9d1.zip op-kernel-dev-5f92c329364c0bf2d3a356da5e8759fbe349f9d1.tar.gz |
[SPARC64]: Fix several bugs in MSI handling.
1) sun4{u,v}_build_msi() have improper return value handling.
We should always return negative error codes, instead of
using the magic value "0" which could in fact be a valid
MSI number.
2) sun4{u,v}_build_msi() should return -ENOMEM instead of
calling prom_prom() halt with kzalloc() of the interrupt
data fails.
3) We 'remembered' the MSI number using a singleton in the
struct device archdata area, this doesn't work for MSI-X
which can cause multiple MSIs assosciated with one device.
Delete that archdata member, and instead store the MSI
number in the IRQ chip data area.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/irq.c')
-rw-r--r-- | arch/sparc64/kernel/irq.c | 25 |
1 files changed, 22 insertions, 3 deletions
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 51b8875..2395609 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -217,8 +217,27 @@ struct irq_handler_data { void (*pre_handler)(unsigned int, void *, void *); void *pre_handler_arg1; void *pre_handler_arg2; + + u32 msi; }; +void sparc64_set_msi(unsigned int virt_irq, u32 msi) +{ + struct irq_handler_data *data = get_irq_chip_data(virt_irq); + + if (data) + data->msi = msi; +} + +u32 sparc64_get_msi(unsigned int virt_irq) +{ + struct irq_handler_data *data = get_irq_chip_data(virt_irq); + + if (data) + return data->msi; + return 0xffffffff; +} + static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq) { unsigned int real_irq = virt_to_real_irq(virt_irq); @@ -741,7 +760,7 @@ unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p, break; } if (devino >= msi_end) - return 0; + return -ENOSPC; sysino = sun4v_devino_to_sysino(devhandle, devino); bucket = &ivector_table[sysino]; @@ -755,8 +774,8 @@ unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p, data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); if (unlikely(!data)) { - prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n"); - prom_halt(); + virt_irq_free(*virt_irq_p); + return -ENOMEM; } set_irq_chip_data(bucket->virt_irq, data); |