powerpc: Convert the MPIC MSI code to use msi_bitmap

This affects the U3 MSI code as well as the PASEMI MSI code.  We keep
some of the MPIC routines as helpers, and also the U3 best-guess
reservation logic.  The rest is replaced by the generic code.

And a few printk format changes due to hwirq type change.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
Michael Ellerman 2008-08-06 09:10:03 +10:00 committed by Paul Mackerras
parent 7e7ab36775
commit 25235f712b
5 changed files with 44 additions and 131 deletions

View file

@ -5,6 +5,7 @@
#include <linux/irq.h>
#include <linux/sysdev.h>
#include <asm/dcr.h>
#include <asm/msi_bitmap.h>
/*
* Global registers
@ -301,8 +302,7 @@ struct mpic
#endif
#ifdef CONFIG_PCI_MSI
spinlock_t bitmap_lock;
unsigned long *hwirq_bitmap;
struct msi_bitmap msi_bitmap;
#endif
#ifdef CONFIG_MPIC_BROKEN_REGREAD

View file

@ -14,8 +14,6 @@
#ifdef CONFIG_PCI_MSI
extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq);
extern int mpic_msi_init_allocator(struct mpic *mpic);
extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num);
extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num);
extern int mpic_u3msi_init(struct mpic *mpic);
extern int mpic_pasemi_msi_init(struct mpic *mpic);
#else

View file

@ -15,59 +15,17 @@
#include <asm/prom.h>
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>
#include <asm/msi_bitmap.h>
#include <sysdev/mpic.h>
static void __mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
{
pr_debug("mpic: reserving hwirq 0x%lx\n", hwirq);
bitmap_allocate_region(mpic->hwirq_bitmap, hwirq, 0);
}
void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
{
unsigned long flags;
/* The mpic calls this even when there is no allocator setup */
if (!mpic->hwirq_bitmap)
if (!mpic->msi_bitmap.bitmap)
return;
spin_lock_irqsave(&mpic->bitmap_lock, flags);
__mpic_msi_reserve_hwirq(mpic, hwirq);
spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
}
irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num)
{
unsigned long flags;
int offset, order = get_count_order(num);
spin_lock_irqsave(&mpic->bitmap_lock, flags);
/*
* This is fast, but stricter than we need. We might want to add
* a fallback routine which does a linear search with no alignment.
*/
offset = bitmap_find_free_region(mpic->hwirq_bitmap, mpic->irq_count,
order);
spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
pr_debug("mpic: allocated 0x%x (2^%d) at offset 0x%x\n",
num, order, offset);
return offset;
}
void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num)
{
unsigned long flags;
int order = get_count_order(num);
pr_debug("mpic: freeing 0x%x (2^%d) at offset 0x%x\n",
num, order, offset);
spin_lock_irqsave(&mpic->bitmap_lock, flags);
bitmap_release_region(mpic->hwirq_bitmap, offset, order);
spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq);
}
#ifdef CONFIG_MPIC_U3_HT_IRQS
@ -83,13 +41,13 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
/* Reserve source numbers we know are reserved in the HW */
for (i = 0; i < 8; i++)
__mpic_msi_reserve_hwirq(mpic, i);
msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
for (i = 42; i < 46; i++)
__mpic_msi_reserve_hwirq(mpic, i);
msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
for (i = 100; i < 105; i++)
__mpic_msi_reserve_hwirq(mpic, i);
msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
np = NULL;
while ((np = of_find_all_nodes(np))) {
@ -99,7 +57,7 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
while (of_irq_map_one(np, index++, &oirq) == 0) {
ops->xlate(mpic->irqhost, NULL, oirq.specifier,
oirq.size, &hwirq, &flags);
__mpic_msi_reserve_hwirq(mpic, hwirq);
msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq);
}
}
@ -112,70 +70,25 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
}
#endif
static int mpic_msi_reserve_dt_hwirqs(struct mpic *mpic)
{
int i, len;
const u32 *p;
p = of_get_property(mpic->irqhost->of_node,
"msi-available-ranges", &len);
if (!p) {
pr_debug("mpic: no msi-available-ranges property found on %s\n",
mpic->irqhost->of_node->full_name);
return -ENODEV;
}
if (len % 8 != 0) {
printk(KERN_WARNING "mpic: Malformed msi-available-ranges "
"property on %s\n", mpic->irqhost->of_node->full_name);
return -EINVAL;
}
bitmap_allocate_region(mpic->hwirq_bitmap, 0,
get_count_order(mpic->irq_count));
/* Format is: (<u32 start> <u32 count>)+ */
len /= sizeof(u32);
for (i = 0; i < len / 2; i++, p += 2)
mpic_msi_free_hwirqs(mpic, *p, *(p + 1));
return 0;
}
int mpic_msi_init_allocator(struct mpic *mpic)
{
int rc, size;
int rc;
BUG_ON(mpic->hwirq_bitmap);
spin_lock_init(&mpic->bitmap_lock);
rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count,
mpic->irqhost->of_node);
if (rc)
return rc;
size = BITS_TO_LONGS(mpic->irq_count) * sizeof(long);
pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size);
mpic->hwirq_bitmap = alloc_maybe_bootmem(size, GFP_KERNEL);
if (!mpic->hwirq_bitmap) {
pr_debug("mpic: ENOMEM allocating allocator bitmap!\n");
return -ENOMEM;
}
memset(mpic->hwirq_bitmap, 0, size);
rc = mpic_msi_reserve_dt_hwirqs(mpic);
if (rc) {
rc = msi_bitmap_reserve_dt_hwirqs(&mpic->msi_bitmap);
if (rc > 0) {
if (mpic->flags & MPIC_U3_HT_IRQS)
rc = mpic_msi_reserve_u3_hwirqs(mpic);
if (rc)
goto out_free;
if (rc) {
msi_bitmap_free(&mpic->msi_bitmap);
return rc;
}
}
return 0;
out_free:
if (mem_init_done)
kfree(mpic->hwirq_bitmap);
mpic->hwirq_bitmap = NULL;
return rc;
}

View file

@ -22,6 +22,7 @@
#include <asm/prom.h>
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>
#include <asm/msi_bitmap.h>
#include "mpic.h"
@ -81,8 +82,8 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev)
continue;
set_irq_msi(entry->irq, NULL);
mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq),
ALLOC_CHUNK);
msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap,
virq_to_hw(entry->irq), ALLOC_CHUNK);
irq_dispose_mapping(entry->irq);
}
@ -91,11 +92,10 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev)
static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
{
irq_hw_number_t hwirq;
unsigned int virq;
struct msi_desc *entry;
struct msi_msg msg;
int ret;
int hwirq;
pr_debug("pasemi_msi_setup_msi_irqs, pdev %p nvec %d type %d\n",
pdev, nvec, type);
@ -109,17 +109,19 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
* few MSIs for someone, but restrictions will apply to how the
* sources can be changed independently.
*/
ret = mpic_msi_alloc_hwirqs(msi_mpic, ALLOC_CHUNK);
hwirq = ret;
if (ret < 0) {
hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap,
ALLOC_CHUNK);
if (hwirq < 0) {
pr_debug("pasemi_msi: failed allocating hwirq\n");
return hwirq;
}
virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
if (virq == NO_IRQ) {
pr_debug("pasemi_msi: failed mapping hwirq 0x%lx\n", hwirq);
mpic_msi_free_hwirqs(msi_mpic, hwirq, ALLOC_CHUNK);
pr_debug("pasemi_msi: failed mapping hwirq 0x%x\n",
hwirq);
msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq,
ALLOC_CHUNK);
return -ENOSPC;
}
@ -133,8 +135,8 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
set_irq_chip(virq, &mpic_pasemi_msi_chip);
set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%lx) addr 0x%x\n",
virq, hwirq, msg.address_lo);
pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%x) " \
"addr 0x%x\n", virq, hwirq, msg.address_lo);
/* Likewise, the device writes [0...511] into the target
* register to generate MSI [512...1023]

View file

@ -16,6 +16,7 @@
#include <asm/prom.h>
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>
#include <asm/msi_bitmap.h>
#include "mpic.h"
@ -101,7 +102,8 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
continue;
set_irq_msi(entry->irq, NULL);
mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), 1);
msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap,
virq_to_hw(entry->irq), 1);
irq_dispose_mapping(entry->irq);
}
@ -110,29 +112,27 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
{
irq_hw_number_t hwirq;
unsigned int virq;
struct msi_desc *entry;
struct msi_msg msg;
u64 addr;
int ret;
int hwirq;
addr = find_ht_magic_addr(pdev);
msg.address_lo = addr & 0xFFFFFFFF;
msg.address_hi = addr >> 32;
list_for_each_entry(entry, &pdev->msi_list, list) {
ret = mpic_msi_alloc_hwirqs(msi_mpic, 1);
if (ret < 0) {
hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, 1);
if (hwirq < 0) {
pr_debug("u3msi: failed allocating hwirq\n");
return ret;
return hwirq;
}
hwirq = ret;
virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
if (virq == NO_IRQ) {
pr_debug("u3msi: failed mapping hwirq 0x%lx\n", hwirq);
mpic_msi_free_hwirqs(msi_mpic, hwirq, 1);
pr_debug("u3msi: failed mapping hwirq 0x%x\n", hwirq);
msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, 1);
return -ENOSPC;
}
@ -140,8 +140,8 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
set_irq_chip(virq, &mpic_u3msi_chip);
set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) addr 0x%lx\n",
virq, hwirq, addr);
pr_debug("u3msi: allocated virq 0x%x (hw 0x%x) addr 0x%lx\n",
virq, hwirq, (unsigned long)addr);
msg.data = hwirq;
write_msi_msg(virq, &msg);