mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-22 00:40:03 +00:00
![Benjamin Herrenschmidt](/assets/img/avatar_default.png)
On machines using the Apple U4 bridge (AKA IBM CPC945) PCIe interface such as the latest generation G5 machines x16 slot or the x16 slot of the PowerStation, MSIs are currently broken (and will oops when enabling). This fixes the oops and implements proper support for those. Instead of using the PCIe <-> HT bridge conversion, on such slots we need to use a bunch of magic registers in the bridge as the MSI target, encoding the interrupt number in the low bits of the address itself Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
103 lines
2.4 KiB
C
103 lines
2.4 KiB
C
/*
|
|
* Copyright 2006-2007, Michael Ellerman, IBM Corporation.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; version 2 of the
|
|
* License.
|
|
*
|
|
*/
|
|
|
|
#include <linux/irq.h>
|
|
#include <linux/bitmap.h>
|
|
#include <linux/msi.h>
|
|
#include <asm/mpic.h>
|
|
#include <asm/prom.h>
|
|
#include <asm/hw_irq.h>
|
|
#include <asm/ppc-pci.h>
|
|
#include <asm/msi_bitmap.h>
|
|
|
|
#include <sysdev/mpic.h>
|
|
|
|
void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
|
|
{
|
|
/* The mpic calls this even when there is no allocator setup */
|
|
if (!mpic->msi_bitmap.bitmap)
|
|
return;
|
|
|
|
msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq);
|
|
}
|
|
|
|
#ifdef CONFIG_MPIC_U3_HT_IRQS
|
|
static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
|
|
{
|
|
irq_hw_number_t hwirq;
|
|
struct irq_host_ops *ops = mpic->irqhost->ops;
|
|
struct device_node *np;
|
|
int flags, index, i;
|
|
struct of_irq oirq;
|
|
|
|
pr_debug("mpic: found U3, guessing msi allocator setup\n");
|
|
|
|
/* Reserve source numbers we know are reserved in the HW.
|
|
*
|
|
* This is a bit of a mix of U3 and U4 reserves but that's going
|
|
* to work fine, we have plenty enugh numbers left so let's just
|
|
* mark anything we don't like reserved.
|
|
*/
|
|
for (i = 0; i < 8; i++)
|
|
msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
|
|
|
|
for (i = 42; i < 46; i++)
|
|
msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
|
|
|
|
for (i = 100; i < 105; i++)
|
|
msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
|
|
|
|
for (i = 124; i < mpic->irq_count; i++)
|
|
msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
|
|
|
|
|
|
np = NULL;
|
|
while ((np = of_find_all_nodes(np))) {
|
|
pr_debug("mpic: mapping hwirqs for %s\n", np->full_name);
|
|
|
|
index = 0;
|
|
while (of_irq_map_one(np, index++, &oirq) == 0) {
|
|
ops->xlate(mpic->irqhost, NULL, oirq.specifier,
|
|
oirq.size, &hwirq, &flags);
|
|
msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#else
|
|
static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
|
|
{
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
int mpic_msi_init_allocator(struct mpic *mpic)
|
|
{
|
|
int rc;
|
|
|
|
rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count,
|
|
mpic->irqhost->of_node);
|
|
if (rc)
|
|
return 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) {
|
|
msi_bitmap_free(&mpic->msi_bitmap);
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|