Skip to content

Commit

Permalink
powerpc: Convert the MPIC MSI code to use msi_bitmap
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Michael Ellerman authored and Paul Mackerras committed Aug 20, 2008
1 parent 7e7ab36 commit 25235f7
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 131 deletions.
4 changes: 2 additions & 2 deletions arch/powerpc/include/asm/mpic.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <linux/irq.h>
#include <linux/sysdev.h>
#include <asm/dcr.h>
#include <asm/msi_bitmap.h>

/*
* Global registers
Expand Down Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions arch/powerpc/sysdev/mpic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
123 changes: 18 additions & 105 deletions arch/powerpc/sysdev/mpic_msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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))) {
Expand All @@ -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);
}
}

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

BUG_ON(mpic->hwirq_bitmap);
spin_lock_init(&mpic->bitmap_lock);
int rc;

size = BITS_TO_LONGS(mpic->irq_count) * sizeof(long);
pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size);
rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count,
mpic->irqhost->of_node);
if (rc)
return rc;

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;
}
24 changes: 13 additions & 11 deletions arch/powerpc/sysdev/mpic_pasemi_msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

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

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

Expand All @@ -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]
Expand Down
22 changes: 11 additions & 11 deletions arch/powerpc/sysdev/mpic_u3msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

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

Expand All @@ -110,38 +112,36 @@ 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;
}

set_irq_msi(virq, entry);
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);
Expand Down

0 comments on commit 25235f7

Please sign in to comment.