Commit 25235f71 authored by Michael Ellerman's avatar Michael Ellerman Committed by Paul Mackerras

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: default avatarMichael Ellerman <michael@ellerman.id.au>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 7e7ab367
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/sysdev.h> #include <linux/sysdev.h>
#include <asm/dcr.h> #include <asm/dcr.h>
#include <asm/msi_bitmap.h>
/* /*
* Global registers * Global registers
...@@ -301,8 +302,7 @@ struct mpic ...@@ -301,8 +302,7 @@ struct mpic
#endif #endif
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
spinlock_t bitmap_lock; struct msi_bitmap msi_bitmap;
unsigned long *hwirq_bitmap;
#endif #endif
#ifdef CONFIG_MPIC_BROKEN_REGREAD #ifdef CONFIG_MPIC_BROKEN_REGREAD
......
...@@ -14,8 +14,6 @@ ...@@ -14,8 +14,6 @@
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq); extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq);
extern int mpic_msi_init_allocator(struct mpic *mpic); 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_u3msi_init(struct mpic *mpic);
extern int mpic_pasemi_msi_init(struct mpic *mpic); extern int mpic_pasemi_msi_init(struct mpic *mpic);
#else #else
......
...@@ -15,59 +15,17 @@ ...@@ -15,59 +15,17 @@
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/hw_irq.h> #include <asm/hw_irq.h>
#include <asm/ppc-pci.h> #include <asm/ppc-pci.h>
#include <asm/msi_bitmap.h>
#include <sysdev/mpic.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) 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 */ /* The mpic calls this even when there is no allocator setup */
if (!mpic->hwirq_bitmap) if (!mpic->msi_bitmap.bitmap)
return; return;
spin_lock_irqsave(&mpic->bitmap_lock, flags); msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq);
__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);
} }
#ifdef CONFIG_MPIC_U3_HT_IRQS #ifdef CONFIG_MPIC_U3_HT_IRQS
...@@ -83,13 +41,13 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) ...@@ -83,13 +41,13 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
/* Reserve source numbers we know are reserved in the HW */ /* Reserve source numbers we know are reserved in the HW */
for (i = 0; i < 8; i++) 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++) 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++) for (i = 100; i < 105; i++)
__mpic_msi_reserve_hwirq(mpic, i); msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
np = NULL; np = NULL;
while ((np = of_find_all_nodes(np))) { while ((np = of_find_all_nodes(np))) {
...@@ -99,7 +57,7 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) ...@@ -99,7 +57,7 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
while (of_irq_map_one(np, index++, &oirq) == 0) { while (of_irq_map_one(np, index++, &oirq) == 0) {
ops->xlate(mpic->irqhost, NULL, oirq.specifier, ops->xlate(mpic->irqhost, NULL, oirq.specifier,
oirq.size, &hwirq, &flags); 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) ...@@ -112,70 +70,25 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
} }
#endif #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 mpic_msi_init_allocator(struct mpic *mpic)
{ {
int rc, size; int rc;
BUG_ON(mpic->hwirq_bitmap);
spin_lock_init(&mpic->bitmap_lock);
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 = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count,
mpic->irqhost->of_node);
if (rc)
return rc;
rc = mpic_msi_reserve_dt_hwirqs(mpic); rc = msi_bitmap_reserve_dt_hwirqs(&mpic->msi_bitmap);
if (rc) { if (rc > 0) {
if (mpic->flags & MPIC_U3_HT_IRQS) if (mpic->flags & MPIC_U3_HT_IRQS)
rc = mpic_msi_reserve_u3_hwirqs(mpic); rc = mpic_msi_reserve_u3_hwirqs(mpic);
if (rc) if (rc) {
goto out_free; msi_bitmap_free(&mpic->msi_bitmap);
return rc;
}
} }
return 0; return 0;
out_free:
if (mem_init_done)
kfree(mpic->hwirq_bitmap);
mpic->hwirq_bitmap = NULL;
return rc;
} }
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/hw_irq.h> #include <asm/hw_irq.h>
#include <asm/ppc-pci.h> #include <asm/ppc-pci.h>
#include <asm/msi_bitmap.h>
#include "mpic.h" #include "mpic.h"
...@@ -81,8 +82,8 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev) ...@@ -81,8 +82,8 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev)
continue; continue;
set_irq_msi(entry->irq, NULL); set_irq_msi(entry->irq, NULL);
mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap,
ALLOC_CHUNK); virq_to_hw(entry->irq), ALLOC_CHUNK);
irq_dispose_mapping(entry->irq); irq_dispose_mapping(entry->irq);
} }
...@@ -91,11 +92,10 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev) ...@@ -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) static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
{ {
irq_hw_number_t hwirq;
unsigned int virq; unsigned int virq;
struct msi_desc *entry; struct msi_desc *entry;
struct msi_msg msg; struct msi_msg msg;
int ret; int hwirq;
pr_debug("pasemi_msi_setup_msi_irqs, pdev %p nvec %d type %d\n", pr_debug("pasemi_msi_setup_msi_irqs, pdev %p nvec %d type %d\n",
pdev, nvec, type); pdev, nvec, type);
...@@ -109,17 +109,19 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int 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 * few MSIs for someone, but restrictions will apply to how the
* sources can be changed independently. * sources can be changed independently.
*/ */
ret = mpic_msi_alloc_hwirqs(msi_mpic, ALLOC_CHUNK); hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap,
hwirq = ret; ALLOC_CHUNK);
if (ret < 0) { if (hwirq < 0) {
pr_debug("pasemi_msi: failed allocating hwirq\n"); pr_debug("pasemi_msi: failed allocating hwirq\n");
return hwirq; return hwirq;
} }
virq = irq_create_mapping(msi_mpic->irqhost, hwirq); virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
if (virq == NO_IRQ) { if (virq == NO_IRQ) {
pr_debug("pasemi_msi: failed mapping hwirq 0x%lx\n", hwirq); pr_debug("pasemi_msi: failed mapping hwirq 0x%x\n",
mpic_msi_free_hwirqs(msi_mpic, hwirq, ALLOC_CHUNK); hwirq);
msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq,
ALLOC_CHUNK);
return -ENOSPC; return -ENOSPC;
} }
...@@ -133,8 +135,8 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) ...@@ -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_chip(virq, &mpic_pasemi_msi_chip);
set_irq_type(virq, IRQ_TYPE_EDGE_RISING); set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%lx) addr 0x%x\n", pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%x) " \
virq, hwirq, msg.address_lo); "addr 0x%x\n", virq, hwirq, msg.address_lo);
/* Likewise, the device writes [0...511] into the target /* Likewise, the device writes [0...511] into the target
* register to generate MSI [512...1023] * register to generate MSI [512...1023]
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/hw_irq.h> #include <asm/hw_irq.h>
#include <asm/ppc-pci.h> #include <asm/ppc-pci.h>
#include <asm/msi_bitmap.h>
#include "mpic.h" #include "mpic.h"
...@@ -101,7 +102,8 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) ...@@ -101,7 +102,8 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
continue; continue;
set_irq_msi(entry->irq, NULL); 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); irq_dispose_mapping(entry->irq);
} }
...@@ -110,29 +112,27 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) ...@@ -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) static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
{ {
irq_hw_number_t hwirq;
unsigned int virq; unsigned int virq;
struct msi_desc *entry; struct msi_desc *entry;
struct msi_msg msg; struct msi_msg msg;
u64 addr; u64 addr;
int ret; int hwirq;
addr = find_ht_magic_addr(pdev); addr = find_ht_magic_addr(pdev);
msg.address_lo = addr & 0xFFFFFFFF; msg.address_lo = addr & 0xFFFFFFFF;
msg.address_hi = addr >> 32; msg.address_hi = addr >> 32;
list_for_each_entry(entry, &pdev->msi_list, list) { list_for_each_entry(entry, &pdev->msi_list, list) {
ret = mpic_msi_alloc_hwirqs(msi_mpic, 1); hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, 1);
if (ret < 0) { if (hwirq < 0) {
pr_debug("u3msi: failed allocating hwirq\n"); pr_debug("u3msi: failed allocating hwirq\n");
return ret; return hwirq;
} }
hwirq = ret;
virq = irq_create_mapping(msi_mpic->irqhost, hwirq); virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
if (virq == NO_IRQ) { if (virq == NO_IRQ) {
pr_debug("u3msi: failed mapping hwirq 0x%lx\n", hwirq); pr_debug("u3msi: failed mapping hwirq 0x%x\n", hwirq);
mpic_msi_free_hwirqs(msi_mpic, hwirq, 1); msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, 1);
return -ENOSPC; return -ENOSPC;
} }
...@@ -140,8 +140,8 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) ...@@ -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_chip(virq, &mpic_u3msi_chip);
set_irq_type(virq, IRQ_TYPE_EDGE_RISING); set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) addr 0x%lx\n", pr_debug("u3msi: allocated virq 0x%x (hw 0x%x) addr 0x%lx\n",
virq, hwirq, addr); virq, hwirq, (unsigned long)addr);
msg.data = hwirq; msg.data = hwirq;
write_msi_msg(virq, &msg); write_msi_msg(virq, &msg);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment