SGI IP27 (Origin/Onyx2) and SGI IP30 (Octane) have a similair
architecture and share some hardware (ioc3/bridge). To share
the software parts this patchset reworks SGI IP27 interrupt
and pci bridge code. By using features Linux gained during the
many years since SGI IP27 code was integrated this even results
in code reduction and IMHO cleaner code.
Tests have been done on a two module O200 (4 CPUs) and an
Origin 2000 (8 CPUs).
My next step in integrating SGI IP30 support is splitting ioc3eth
into a MFD and subdevice drivers. Prototype is working, but needs
still more clean ups.
Changes in v2:
- replaced HUB_L/HUB_S by __raw_readq/__raw_writeq
- removed union bridge_ate
- replaced remaing fields in slice_data by per_cpu data
- use generic_handle_irq instead of do_IRQ
- use hierarchy irq domain for stacking bridge and hub interrupt
- moved __dma_to_phys/__phy_to_dma to mach-ip27/dma-direct.h
- use dev_to_node() for pcibus_to_node() implementation
Thomas Bogendoerfer (10):
MIPS: SGI-IP27: get rid of volatile and hubreg_t
MIPS: SGI-IP27: clean up bridge access and header files
MIPS: SGI-IP27: use pr_info/pr_emerg and pr_cont to fix output
MIPS: SGI-IP27: do xtalk scanning later
MIPS: SGI-IP27: do boot CPU init later
MIPS: SGI-IP27: rework HUB interrupts
PCI: call add_bus method also for root bus
MIPS: SGI-IP27: use generic PCI driver
genirq/irqdomain: fall back to default domain when creating hierarchy
domain
MIPS: SGI-IP27: abstract chipset irq from bridge
arch/mips/Kconfig | 4 +
arch/mips/include/asm/dma-direct.h | 2 +
arch/mips/include/asm/mach-generic/dma-direct.h | 7 +
arch/mips/include/asm/mach-ip27/dma-direct.h | 20 +
arch/mips/include/asm/mach-ip27/irq.h | 12 +-
arch/mips/include/asm/mach-ip27/mmzone.h | 9 -
arch/mips/include/asm/mach-ip27/topology.h | 13 +-
arch/mips/include/asm/pci.h | 8 +
arch/mips/include/asm/pci/bridge.h | 211 ++++----
arch/mips/include/asm/smp-ops.h | 1 +
arch/mips/include/asm/sn/addrs.h | 72 +--
arch/mips/include/asm/sn/arch.h | 2 -
arch/mips/include/asm/sn/intr.h | 6 +
arch/mips/include/asm/sn/io.h | 2 +-
arch/mips/include/asm/sn/sn0/addrs.h | 5 -
arch/mips/include/asm/xtalk/xtalk.h | 9 -
arch/mips/kernel/smp.c | 2 +
arch/mips/pci/Makefile | 1 -
arch/mips/pci/ops-bridge.c | 322 ------------
arch/mips/pci/pci-ip27.c | 233 ---------
arch/mips/sgi-ip27/Makefile | 3 +-
arch/mips/sgi-ip27/ip27-hubio.c | 4 +-
arch/mips/sgi-ip27/ip27-init.c | 41 +-
arch/mips/sgi-ip27/ip27-irq-pci.c | 266 ----------
arch/mips/sgi-ip27/ip27-irq.c | 331 ++++++++-----
arch/mips/sgi-ip27/ip27-irqno.c | 48 --
arch/mips/sgi-ip27/ip27-memory.c | 34 +-
arch/mips/sgi-ip27/ip27-nmi.c | 64 +--
arch/mips/sgi-ip27/ip27-smp.c | 5 +-
arch/mips/sgi-ip27/ip27-timer.c | 42 +-
arch/mips/sgi-ip27/ip27-xtalk.c | 44 +-
drivers/pci/controller/Kconfig | 3 +
drivers/pci/controller/Makefile | 1 +
drivers/pci/controller/pci-xtalk-bridge.c | 623 ++++++++++++++++++++++++
drivers/pci/probe.c | 6 +
include/linux/platform_data/xtalk-bridge.h | 17 +
kernel/irq/irqdomain.c | 5 +-
37 files changed, 1126 insertions(+), 1352 deletions(-)
create mode 100644 arch/mips/include/asm/mach-generic/dma-direct.h
create mode 100644 arch/mips/include/asm/mach-ip27/dma-direct.h
delete mode 100644 arch/mips/pci/ops-bridge.c
delete mode 100644 arch/mips/pci/pci-ip27.c
delete mode 100644 arch/mips/sgi-ip27/ip27-irq-pci.c
delete mode 100644 arch/mips/sgi-ip27/ip27-irqno.c
create mode 100644 drivers/pci/controller/pci-xtalk-bridge.c
create mode 100644 include/linux/platform_data/xtalk-bridge.h
--
2.13.7
Bridge ASIC is widely used in different SGI systems, but the connected
chipset is either HUB, HEART or BEDROCK. This commit switches to
irq domain hierarchy for hub and bridge interrupts to get bridge
setup out of hub interrupt code.
Signed-off-by: Thomas Bogendoerfer <[email protected]>
---
arch/mips/Kconfig | 1 +
arch/mips/include/asm/pci/bridge.h | 3 +-
arch/mips/include/asm/sn/intr.h | 6 +
arch/mips/sgi-ip27/ip27-irq.c | 178 +++++++++++++-----------------
drivers/pci/controller/pci-xtalk-bridge.c | 145 +++++++++++++++++++++++-
5 files changed, 229 insertions(+), 104 deletions(-)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 57a424e82a18..ba55c4af8798 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -677,6 +677,7 @@ config SGI_IP27
select SYS_HAS_EARLY_PRINTK
select HAVE_PCI
select IRQ_MIPS_CPU
+ select IRQ_DOMAIN_HIERARCHY
select NR_CPUS_DEFAULT_64
select PCI_DRIVERS_GENERIC
select PCI_XTALK_BRIDGE
diff --git a/arch/mips/include/asm/pci/bridge.h b/arch/mips/include/asm/pci/bridge.h
index 457ff868a027..4b8570e4fb48 100644
--- a/arch/mips/include/asm/pci/bridge.h
+++ b/arch/mips/include/asm/pci/bridge.h
@@ -806,6 +806,7 @@ struct bridge_controller {
struct resource busn;
struct bridge_regs *base;
u64 baddr;
+ struct irq_domain *domain;
unsigned int pci_int[8];
nasid_t nasid;
};
@@ -820,6 +821,4 @@ struct bridge_controller {
#define bridge_clr(bc, reg, val) \
__raw_writel(__raw_readl(&bc->base->reg) & ~(val), &bc->base->reg)
-extern int request_bridge_irq(struct bridge_controller *bc, int pin);
-
#endif /* _ASM_PCI_BRIDGE_H */
diff --git a/arch/mips/include/asm/sn/intr.h b/arch/mips/include/asm/sn/intr.h
index fc1348193957..bdb8ca95183a 100644
--- a/arch/mips/include/asm/sn/intr.h
+++ b/arch/mips/include/asm/sn/intr.h
@@ -126,4 +126,10 @@ do { \
#define NI_ERROR_INTR 62
#define MSC_PANIC_INTR 63
+struct irq_alloc_info {
+ void *ctrl;
+ nasid_t nasid;
+ int pin;
+};
+
#endif /* __ASM_SN_INTR_H */
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
index 710a59764b01..b992c2b08e3b 100644
--- a/arch/mips/sgi-ip27/ip27-irq.c
+++ b/arch/mips/sgi-ip27/ip27-irq.c
@@ -12,10 +12,10 @@
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
+#include <linux/sched.h>
#include <asm/io.h>
#include <asm/irq_cpu.h>
-#include <asm/pci/bridge.h>
#include <asm/sn/addrs.h>
#include <asm/sn/agent.h>
#include <asm/sn/arch.h>
@@ -23,11 +23,9 @@
#include <asm/sn/intr.h>
struct hub_irq_data {
- struct bridge_controller *bc;
u64 *irq_mask[2];
cpuid_t cpu;
int bit;
- int pin;
};
static DECLARE_BITMAP(hub_irq_map, IP27_HUB_IRQ_COUNT);
@@ -69,67 +67,6 @@ static void disable_hub_irq(struct irq_data *d)
__raw_writeq(mask[1], hd->irq_mask[1]);
}
-static unsigned int startup_bridge_irq(struct irq_data *d)
-{
- struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
- struct bridge_controller *bc;
- nasid_t nasid;
- u32 device;
- int pin;
-
- if (!hd)
- return -EINVAL;
-
- pin = hd->pin;
- bc = hd->bc;
-
- nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(hd->cpu));
- bridge_write(bc, b_int_addr[pin].addr,
- (0x20000 | hd->bit | (nasid << 8)));
- bridge_set(bc, b_int_enable, (1 << pin));
- bridge_set(bc, b_int_enable, 0x7ffffe00); /* more stuff in int_enable */
-
- /*
- * Enable sending of an interrupt clear packt to the hub on a high to
- * low transition of the interrupt pin.
- *
- * IRIX sets additional bits in the address which are documented as
- * reserved in the bridge docs.
- */
- bridge_set(bc, b_int_mode, (1UL << pin));
-
- /*
- * We assume the bridge to have a 1:1 mapping between devices
- * (slots) and intr pins.
- */
- device = bridge_read(bc, b_int_device);
- device &= ~(7 << (pin*3));
- device |= (pin << (pin*3));
- bridge_write(bc, b_int_device, device);
-
- bridge_read(bc, b_wid_tflush);
-
- enable_hub_irq(d);
-
- return 0; /* Never anything pending. */
-}
-
-static void shutdown_bridge_irq(struct irq_data *d)
-{
- struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
- struct bridge_controller *bc;
- int pin = hd->pin;
-
- if (!hd)
- return;
-
- disable_hub_irq(d);
-
- bc = hd->bc;
- bridge_clr(bc, b_int_enable, (1 << pin));
- bridge_read(bc, b_wid_tflush);
-}
-
static void setup_hub_mask(struct hub_irq_data *hd, const struct cpumask *mask)
{
nasid_t nasid;
@@ -164,7 +101,7 @@ static int set_affinity_hub_irq(struct irq_data *d, const struct cpumask *mask,
setup_hub_mask(hd, mask);
if (irqd_is_started(d))
- startup_bridge_irq(d);
+ enable_hub_irq(d);
irq_data_update_effective_affinity(d, cpumask_of(hd->cpu));
@@ -173,20 +110,22 @@ static int set_affinity_hub_irq(struct irq_data *d, const struct cpumask *mask,
static struct irq_chip hub_irq_type = {
.name = "HUB",
- .irq_startup = startup_bridge_irq,
- .irq_shutdown = shutdown_bridge_irq,
.irq_mask = disable_hub_irq,
.irq_unmask = enable_hub_irq,
.irq_set_affinity = set_affinity_hub_irq,
};
-int request_bridge_irq(struct bridge_controller *bc, int pin)
+static int hub_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
{
+ struct irq_alloc_info *info = arg;
struct hub_irq_data *hd;
struct hub_data *hub;
struct irq_desc *desc;
int swlevel;
- int irq;
+
+ if (nr_irqs > 1 || !info)
+ return -EINVAL;
hd = kzalloc(sizeof(*hd), GFP_KERNEL);
if (!hd)
@@ -197,46 +136,39 @@ int request_bridge_irq(struct bridge_controller *bc, int pin)
kfree(hd);
return -EAGAIN;
}
- irq = swlevel + IP27_HUB_IRQ_BASE;
-
- hd->bc = bc;
hd->bit = swlevel;
- hd->pin = pin;
- irq_set_chip_data(irq, hd);
+ irq_domain_set_info(domain, virq, swlevel, &hub_irq_type, hd,
+ handle_level_irq, NULL, NULL);
/* use CPU connected to nearest hub */
- hub = hub_data(NASID_TO_COMPACT_NODEID(bc->nasid));
+ hub = hub_data(NASID_TO_COMPACT_NODEID(info->nasid));
setup_hub_mask(hd, &hub->h_cpus);
- desc = irq_to_desc(irq);
- desc->irq_common_data.node = bc->nasid;
+ desc = irq_to_desc(virq);
+ desc->irq_common_data.node = info->nasid;
cpumask_copy(desc->irq_common_data.affinity, &hub->h_cpus);
- return irq;
+ return 0;
}
-void ip27_hub_irq_init(void)
+static void hub_domain_free(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs)
{
- int i;
+ struct irq_data *irqd;
- for (i = IP27_HUB_IRQ_BASE;
- i < (IP27_HUB_IRQ_BASE + IP27_HUB_IRQ_COUNT); i++)
- irq_set_chip_and_handler(i, &hub_irq_type, handle_level_irq);
-
- /*
- * Some interrupts are reserved by hardware or by software convention.
- * Mark these as reserved right away so they won't be used accidentally
- * later.
- */
- for (i = 0; i <= BASE_PCI_IRQ; i++)
- set_bit(i, hub_irq_map);
-
- set_bit(IP_PEND0_6_63, hub_irq_map);
+ if (nr_irqs > 1)
+ return;
- for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++)
- set_bit(i, hub_irq_map);
+ irqd = irq_domain_get_irq_data(domain, virq);
+ if (irqd && irqd->chip_data)
+ kfree(irqd->chip_data);
}
+static const struct irq_domain_ops hub_domain_ops = {
+ .alloc = hub_domain_alloc,
+ .free = hub_domain_free,
+};
+
/*
* This code is unnecessarily complex, because we do
* intr enabling. Basically, once we grab the set of intrs we need
@@ -253,7 +185,9 @@ static void ip27_do_irq_mask0(struct irq_desc *desc)
{
cpuid_t cpu = smp_processor_id();
unsigned long *mask = per_cpu(irq_enable_mask, cpu);
+ struct irq_domain *domain;
u64 pend0;
+ int irq;
/* copied from Irix intpend0() */
pend0 = LOCAL_HUB_L(PI_INT_PEND0);
@@ -277,7 +211,14 @@ static void ip27_do_irq_mask0(struct irq_desc *desc)
generic_smp_call_function_interrupt();
} else
#endif
- generic_handle_irq(__ffs(pend0) + IP27_HUB_IRQ_BASE);
+ {
+ domain = irq_desc_get_handler_data(desc);
+ irq = irq_linear_revmap(domain, __ffs(pend0));
+ if (irq)
+ generic_handle_irq(irq);
+ else
+ spurious_interrupt();
+ }
LOCAL_HUB_L(PI_INT_PEND0);
}
@@ -286,7 +227,9 @@ static void ip27_do_irq_mask1(struct irq_desc *desc)
{
cpuid_t cpu = smp_processor_id();
unsigned long *mask = per_cpu(irq_enable_mask, cpu);
+ struct irq_domain *domain;
u64 pend1;
+ int irq;
/* copied from Irix intpend0() */
pend1 = LOCAL_HUB_L(PI_INT_PEND1);
@@ -295,7 +238,12 @@ static void ip27_do_irq_mask1(struct irq_desc *desc)
if (!pend1)
return;
- generic_handle_irq(__ffs(pend1) + IP27_HUB_IRQ_BASE + 64);
+ domain = irq_desc_get_handler_data(desc);
+ irq = irq_linear_revmap(domain, __ffs(pend1) + 64);
+ if (irq)
+ generic_handle_irq(irq);
+ else
+ spurious_interrupt();
LOCAL_HUB_L(PI_INT_PEND1);
}
@@ -326,11 +274,41 @@ void install_ipi(void)
void __init arch_init_irq(void)
{
+ struct irq_domain *domain;
+ struct fwnode_handle *fn;
+ int i;
+
mips_cpu_irq_init();
- ip27_hub_irq_init();
+
+ /*
+ * Some interrupts are reserved by hardware or by software convention.
+ * Mark these as reserved right away so they won't be used accidentally
+ * later.
+ */
+ for (i = 0; i <= BASE_PCI_IRQ; i++)
+ set_bit(i, hub_irq_map);
+
+ set_bit(IP_PEND0_6_63, hub_irq_map);
+
+ for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++)
+ set_bit(i, hub_irq_map);
+
+ fn = irq_domain_alloc_named_fwnode("HUB");
+ WARN_ON(fn == NULL);
+ if (!fn)
+ return;
+ domain = irq_domain_create_linear(fn, IP27_HUB_IRQ_COUNT,
+ &hub_domain_ops, NULL);
+ WARN_ON(domain == NULL);
+ if (!domain)
+ return;
+
+ irq_set_default_host(domain);
irq_set_percpu_devid(IP27_HUB_PEND0_IRQ);
- irq_set_chained_handler(IP27_HUB_PEND0_IRQ, ip27_do_irq_mask0);
+ irq_set_chained_handler_and_data(IP27_HUB_PEND0_IRQ, ip27_do_irq_mask0,
+ domain);
irq_set_percpu_devid(IP27_HUB_PEND1_IRQ);
- irq_set_chained_handler(IP27_HUB_PEND1_IRQ, ip27_do_irq_mask1);
+ irq_set_chained_handler_and_data(IP27_HUB_PEND1_IRQ, ip27_do_irq_mask1,
+ domain);
}
diff --git a/drivers/pci/controller/pci-xtalk-bridge.c b/drivers/pci/controller/pci-xtalk-bridge.c
index 77e42c46937b..0e3a4bd9484d 100644
--- a/drivers/pci/controller/pci-xtalk-bridge.c
+++ b/drivers/pci/controller/pci-xtalk-bridge.c
@@ -324,6 +324,129 @@ static struct pci_ops bridge_pci_ops = {
.write = pci_write_config,
};
+struct bridge_irq_chip_data {
+ struct bridge_controller *bc;
+ nasid_t nasid;
+};
+
+static int bridge_set_affinity(struct irq_data *d, const struct cpumask *mask,
+ bool force)
+{
+ struct bridge_irq_chip_data *data = d->chip_data;
+ int bit = d->parent_data->hwirq;
+ int pin = d->hwirq;
+ nasid_t nasid;
+ int ret, cpu;
+
+ ret = irq_chip_set_affinity_parent(d, mask, force);
+ if (ret >= 0) {
+ cpu = cpumask_first_and(mask, cpu_online_mask);
+ nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
+ bridge_write(data->bc, b_int_addr[pin].addr,
+ (0x20000 | bit | (nasid << 8)));
+ bridge_read(data->bc, b_wid_tflush);
+ }
+ return ret;
+}
+
+struct irq_chip bridge_irq_chip = {
+ .name = "BRIDGE",
+ .irq_mask = irq_chip_mask_parent,
+ .irq_unmask = irq_chip_unmask_parent,
+ .irq_set_affinity = bridge_set_affinity
+};
+
+static int bridge_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ struct bridge_irq_chip_data *data;
+ struct irq_alloc_info *info = arg;
+ int ret;
+
+ if (nr_irqs > 1 || !info)
+ return -EINVAL;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+ if (ret >= 0) {
+ data->bc = info->ctrl;
+ data->nasid = info->nasid;
+ irq_domain_set_info(domain, virq, info->pin, &bridge_irq_chip,
+ data, handle_level_irq, NULL, NULL);
+ } else {
+ kfree(data);
+ }
+
+ return ret;
+}
+
+static void bridge_domain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct irq_data *irqd = irq_domain_get_irq_data(domain, virq);
+
+ if (nr_irqs)
+ return;
+
+ kfree(irqd->chip_data);
+ irq_domain_free_irqs_top(domain, virq, nr_irqs);
+}
+
+static int bridge_domain_activate(struct irq_domain *domain,
+ struct irq_data *irqd, bool reserve)
+{
+ struct bridge_irq_chip_data *data = irqd->chip_data;
+ struct bridge_controller *bc = data->bc;
+ int bit = irqd->parent_data->hwirq;
+ int pin = irqd->hwirq;
+ u32 device;
+
+ bridge_write(bc, b_int_addr[pin].addr,
+ (0x20000 | bit | (data->nasid << 8)));
+ bridge_set(bc, b_int_enable, (1 << pin));
+ bridge_set(bc, b_int_enable, 0x7ffffe00); /* more stuff in int_enable */
+
+ /*
+ * Enable sending of an interrupt clear packt to the hub on a high to
+ * low transition of the interrupt pin.
+ *
+ * IRIX sets additional bits in the address which are documented as
+ * reserved in the bridge docs.
+ */
+ bridge_set(bc, b_int_mode, (1UL << pin));
+
+ /*
+ * We assume the bridge to have a 1:1 mapping between devices
+ * (slots) and intr pins.
+ */
+ device = bridge_read(bc, b_int_device);
+ device &= ~(7 << (pin*3));
+ device |= (pin << (pin*3));
+ bridge_write(bc, b_int_device, device);
+
+ bridge_read(bc, b_wid_tflush);
+ return 0;
+}
+
+static void bridge_domain_deactivate(struct irq_domain *domain,
+ struct irq_data *irqd)
+{
+ struct bridge_irq_chip_data *data = irqd->chip_data;
+
+ bridge_clr(data->bc, b_int_enable, (1 << irqd->hwirq));
+ bridge_read(data->bc, b_wid_tflush);
+}
+
+static const struct irq_domain_ops bridge_domain_ops = {
+ .alloc = bridge_domain_alloc,
+ .free = bridge_domain_free,
+ .activate = bridge_domain_activate,
+ .deactivate = bridge_domain_deactivate
+};
+
/*
* All observed requests have pin == 1. We could have a global here, that
* gets incremented and returned every time - unfortunately, pci_map_irq
@@ -336,11 +459,16 @@ static struct pci_ops bridge_pci_ops = {
static int bridge_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
+ struct irq_alloc_info info;
int irq;
irq = bc->pci_int[slot];
if (irq == -1) {
- irq = request_bridge_irq(bc, slot);
+ info.ctrl = bc;
+ info.nasid = bc->nasid;
+ info.pin = slot;
+
+ irq = irq_domain_alloc_irqs(bc->domain, 1, bc->nasid, &info);
if (irq < 0)
return irq;
@@ -351,13 +479,22 @@ static int bridge_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
static int bridge_probe(struct platform_device *pdev)
{
+ struct xtalk_bridge_platform_data *bd = dev_get_platdata(&pdev->dev);
struct device *dev = &pdev->dev;
struct bridge_controller *bc;
struct pci_host_bridge *host;
+ struct irq_domain *domain;
+ struct fwnode_handle *fn;
unsigned long offset;
int slot;
int err;
- struct xtalk_bridge_platform_data *bd = dev_get_platdata(&pdev->dev);
+
+ fn = irq_domain_alloc_named_fwnode("BRIDGE");
+ domain = irq_domain_create_hierarchy(NULL, 0, 8, fn,
+ &bridge_domain_ops, NULL);
+ irq_domain_free_fwnode(fn);
+ if (!domain)
+ return -ENOMEM;
offset = NODE_OFFSET(bd->nasid);
@@ -384,6 +521,8 @@ static int bridge_probe(struct platform_device *pdev)
bc->busn.end = 0xff;
bc->busn.flags = IORESOURCE_BUS;
+ bc->domain = domain;
+
pci_add_resource_offset(&host->windows, &bc->mem, offset);
pci_add_resource_offset(&host->windows, &bc->io, offset);
pci_add_resource(&host->windows, &bc->busn);
@@ -462,7 +601,9 @@ static int bridge_probe(struct platform_device *pdev)
static int bridge_remove(struct platform_device *pdev)
{
struct pci_bus *bus = platform_get_drvdata(pdev);
+ struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+ irq_domain_remove(bc->domain);
pci_lock_rescan_remove();
pci_stop_root_bus(bus);
pci_remove_root_bus(bus);
--
2.13.7
Converted bridge code to a platform driver using the PCI generic driver
framework and use adding platform devices during xtalk scan. This allows
easier sharing bridge driver for other SGI platforms like IP30 (Octane) and
IP35 (Origin 3k, Fuel, Tezro).
Signed-off-by: Thomas Bogendoerfer <[email protected]>
---
arch/mips/Kconfig | 2 +
arch/mips/include/asm/dma-direct.h | 2 +
arch/mips/include/asm/mach-generic/dma-direct.h | 7 +
arch/mips/include/asm/mach-ip27/dma-direct.h | 20 ++
arch/mips/include/asm/mach-ip27/topology.h | 13 +-
arch/mips/include/asm/pci.h | 8 +
arch/mips/include/asm/pci/bridge.h | 6 +-
arch/mips/include/asm/xtalk/xtalk.h | 9 -
arch/mips/pci/Makefile | 1 -
arch/mips/pci/pci-ip27.c | 214 ----------------
arch/mips/sgi-ip27/ip27-init.c | 2 +
arch/mips/sgi-ip27/ip27-xtalk.c | 31 ++-
drivers/pci/controller/Kconfig | 3 +
drivers/pci/controller/Makefile | 1 +
.../pci/controller/pci-xtalk-bridge.c | 278 +++++++++++++++++----
include/linux/platform_data/xtalk-bridge.h | 17 ++
16 files changed, 312 insertions(+), 302 deletions(-)
create mode 100644 arch/mips/include/asm/mach-generic/dma-direct.h
create mode 100644 arch/mips/include/asm/mach-ip27/dma-direct.h
delete mode 100644 arch/mips/pci/pci-ip27.c
rename arch/mips/pci/ops-bridge.c => drivers/pci/controller/pci-xtalk-bridge.c (52%)
create mode 100644 include/linux/platform_data/xtalk-bridge.h
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 93b88e8e72d0..57a424e82a18 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -678,6 +678,8 @@ config SGI_IP27
select HAVE_PCI
select IRQ_MIPS_CPU
select NR_CPUS_DEFAULT_64
+ select PCI_DRIVERS_GENERIC
+ select PCI_XTALK_BRIDGE
select SYS_HAS_CPU_R10000
select SYS_SUPPORTS_64BIT_KERNEL
select SYS_SUPPORTS_BIG_ENDIAN
diff --git a/arch/mips/include/asm/dma-direct.h b/arch/mips/include/asm/dma-direct.h
index b5c240806e1b..bd11e7934df1 100644
--- a/arch/mips/include/asm/dma-direct.h
+++ b/arch/mips/include/asm/dma-direct.h
@@ -2,6 +2,8 @@
#ifndef _MIPS_DMA_DIRECT_H
#define _MIPS_DMA_DIRECT_H 1
+#include <dma-direct.h>
+
static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
{
if (!dev->dma_mask)
diff --git a/arch/mips/include/asm/mach-generic/dma-direct.h b/arch/mips/include/asm/mach-generic/dma-direct.h
new file mode 100644
index 000000000000..2d2c187dcd42
--- /dev/null
+++ b/arch/mips/include/asm/mach-generic/dma-direct.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_MACH_GENERIC_DMA_DIRECT_H
+#define __ASM_MACH_GENERIC_DMA_DIRECT_H
+
+/* Intentionally empty file ... */
+
+#endif /* __ASM_MACH_GENERIC_DMA_DIRECT_H */
diff --git a/arch/mips/include/asm/mach-ip27/dma-direct.h b/arch/mips/include/asm/mach-ip27/dma-direct.h
new file mode 100644
index 000000000000..ec9856dfe2db
--- /dev/null
+++ b/arch/mips/include/asm/mach-ip27/dma-direct.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_MACH_IP27_DMA_DIRECT_H
+#define __ASM_MACH_IP27_DMA_DIRECT_H
+
+#include <asm/pci/bridge.h>
+
+static inline dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct bridge_controller *bc = BRIDGE_CONTROLLER(pdev->bus);
+
+ return bc->baddr + paddr;
+}
+
+static inline phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t dma_addr)
+{
+ return dma_addr & ~(0xffUL << 56);
+}
+
+#endif /* __ASM_MACH_IP27_DMA_DIRECT_H */
diff --git a/arch/mips/include/asm/mach-ip27/topology.h b/arch/mips/include/asm/mach-ip27/topology.h
index 42ea1313626c..3cd03a74187e 100644
--- a/arch/mips/include/asm/mach-ip27/topology.h
+++ b/arch/mips/include/asm/mach-ip27/topology.h
@@ -7,18 +7,9 @@
#include <asm/mmzone.h>
struct cpuinfo_ip27 {
-// cpuid_t p_cpuid; /* PROM assigned cpuid */
cnodeid_t p_nodeid; /* my node ID in compact-id-space */
nasid_t p_nasid; /* my node ID in numa-as-id-space */
unsigned char p_slice; /* Physical position on node board */
-#if 0
- unsigned long loops_per_sec;
- unsigned long ipi_count;
- unsigned long irq_attempt[NR_IRQS];
- unsigned long smp_local_irq_count;
- unsigned long prof_multiplier;
- unsigned long prof_counter;
-#endif
};
extern struct cpuinfo_ip27 sn_cpu_info[NR_CPUS];
@@ -27,10 +18,8 @@ extern struct cpuinfo_ip27 sn_cpu_info[NR_CPUS];
#define cpumask_of_node(node) ((node) == -1 ? \
cpu_all_mask : \
&hub_data(node)->h_cpus)
-struct pci_bus;
-extern int pcibus_to_node(struct pci_bus *);
-#define cpumask_of_pcibus(bus) (cpu_online_mask)
+#define cpumask_of_pcibus(bus) (cpumask_of_node(pcibus_to_node(bus)))
extern unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index 436099883022..70d1e51a7ca2 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -147,4 +147,12 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
return channel ? 15 : 14;
}
+#ifdef CONFIG_SGI_IP27
+/* Returns the node based on pci bus */
+static inline int pcibus_to_node(struct pci_bus *bus)
+{
+ return dev_to_node(&bus->dev);
+}
+#endif
+
#endif /* _ASM_PCI_H */
diff --git a/arch/mips/include/asm/pci/bridge.h b/arch/mips/include/asm/pci/bridge.h
index 23574c27eb40..457ff868a027 100644
--- a/arch/mips/include/asm/pci/bridge.h
+++ b/arch/mips/include/asm/pci/bridge.h
@@ -801,15 +801,13 @@ struct bridge_err_cmdword {
#define PCI64_ATTR_RMF_SHFT 48
struct bridge_controller {
- struct pci_controller pc;
struct resource mem;
struct resource io;
struct resource busn;
struct bridge_regs *base;
- nasid_t nasid;
- unsigned int widget_id;
u64 baddr;
unsigned int pci_int[8];
+ nasid_t nasid;
};
#define BRIDGE_CONTROLLER(bus) \
@@ -824,6 +822,4 @@ struct bridge_controller {
extern int request_bridge_irq(struct bridge_controller *bc, int pin);
-extern struct pci_ops bridge_pci_ops;
-
#endif /* _ASM_PCI_BRIDGE_H */
diff --git a/arch/mips/include/asm/xtalk/xtalk.h b/arch/mips/include/asm/xtalk/xtalk.h
index 26d2ed1fa917..680e7efebbaf 100644
--- a/arch/mips/include/asm/xtalk/xtalk.h
+++ b/arch/mips/include/asm/xtalk/xtalk.h
@@ -47,15 +47,6 @@ typedef struct xtalk_piomap_s *xtalk_piomap_t;
#define XIO_PORT(x) ((xwidgetnum_t)(((x)&XIO_PORT_BITS) >> XIO_PORT_SHIFT))
#define XIO_PACK(p, o) ((((uint64_t)(p))<<XIO_PORT_SHIFT) | ((o)&XIO_ADDR_BITS))
-#ifdef CONFIG_PCI
-extern int bridge_probe(nasid_t nasid, int widget, int masterwid);
-#else
-static inline int bridge_probe(nasid_t nasid, int widget, int masterwid)
-{
- return 0;
-}
-#endif
-
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_XTALK_XTALK_H */
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index 8185a2bfaf09..0225d83d6681 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -38,7 +38,6 @@ obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o
obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o
obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o
obj-$(CONFIG_PMC_MSP7120_FPGA) += fixup-pmcmsp.o ops-pmcmsp.o
-obj-$(CONFIG_SGI_IP27) += ops-bridge.o pci-ip27.o
obj-$(CONFIG_SGI_IP32) += fixup-ip32.o ops-mace.o pci-ip32.o
obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o
obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o
diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c
deleted file mode 100644
index 3c177b4d0609..000000000000
--- a/arch/mips/pci/pci-ip27.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2003 Christoph Hellwig ([email protected])
- * Copyright (C) 1999, 2000, 04 Ralf Baechle ([email protected])
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- */
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/pci.h>
-#include <linux/smp.h>
-#include <linux/dma-direct.h>
-#include <asm/sn/arch.h>
-#include <asm/pci/bridge.h>
-#include <asm/paccess.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/sn0/hub.h>
-
-/*
- * Max #PCI busses we can handle; ie, max #PCI bridges.
- */
-#define MAX_PCI_BUSSES 40
-
-/*
- * XXX: No kmalloc available when we do our crosstalk scan,
- * we should try to move it later in the boot process.
- */
-static struct bridge_controller bridges[MAX_PCI_BUSSES];
-
-extern struct pci_ops bridge_pci_ops;
-
-int bridge_probe(nasid_t nasid, int widget_id, int masterwid)
-{
- unsigned long offset = NODE_OFFSET(nasid);
- struct bridge_controller *bc;
- static int num_bridges = 0;
- int slot;
-
- pci_set_flags(PCI_PROBE_ONLY);
-
- printk("a bridge\n");
-
- /* XXX: kludge alert.. */
- if (!num_bridges)
- ioport_resource.end = ~0UL;
-
- bc = &bridges[num_bridges];
-
- bc->pc.pci_ops = &bridge_pci_ops;
- bc->pc.mem_resource = &bc->mem;
- bc->pc.io_resource = &bc->io;
-
- bc->pc.index = num_bridges;
-
- bc->mem.name = "Bridge PCI MEM";
- bc->pc.mem_offset = offset;
- bc->mem.start = 0;
- bc->mem.end = ~0UL;
- bc->mem.flags = IORESOURCE_MEM;
-
- bc->io.name = "Bridge IO MEM";
- bc->pc.io_offset = offset;
- bc->io.start = 0UL;
- bc->io.end = ~0UL;
- bc->io.flags = IORESOURCE_IO;
-
- bc->widget_id = widget_id;
- bc->nasid = nasid;
-
- bc->baddr = (u64)masterwid << 60 | PCI64_ATTR_BAR;
-
- /*
- * point to this bridge
- */
- bc->base = (struct bridge_regs *)RAW_NODE_SWIN_BASE(nasid, widget_id);
-
- /*
- * Clear all pending interrupts.
- */
- bridge_write(bc, b_int_rst_stat, BRIDGE_IRR_ALL_CLR);
-
- /*
- * Until otherwise set up, assume all interrupts are from slot 0
- */
- bridge_write(bc, b_int_device, 0x0);
-
- /*
- * swap pio's to pci mem and io space (big windows)
- */
- bridge_set(bc, b_wid_control, BRIDGE_CTRL_IO_SWAP |
- BRIDGE_CTRL_MEM_SWAP);
-#ifdef CONFIG_PAGE_SIZE_4KB
- bridge_clr(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
-#else /* 16kB or larger */
- bridge_set(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
-#endif
-
- /*
- * Hmm... IRIX sets additional bits in the address which
- * are documented as reserved in the bridge docs.
- */
- bridge_write(bc, b_wid_int_upper, 0x8000 | (masterwid << 16));
- bridge_write(bc, b_wid_int_lower, 0x01800090); /* PI_INT_PEND_MOD off*/
- bridge_write(bc, b_dir_map, (masterwid << 20)); /* DMA */
- bridge_write(bc, b_int_enable, 0);
-
- for (slot = 0; slot < 8; slot ++) {
- bridge_set(bc, b_device[slot].reg, BRIDGE_DEV_SWAP_DIR);
- bc->pci_int[slot] = -1;
- }
- bridge_read(bc, b_wid_tflush); /* wait until Bridge PIO complete */
-
- register_pci_controller(&bc->pc);
-
- num_bridges++;
-
- return 0;
-}
-
-/*
- * All observed requests have pin == 1. We could have a global here, that
- * gets incremented and returned every time - unfortunately, pci_map_irq
- * may be called on the same device over and over, and need to return the
- * same value. On O2000, pin can be 0 or 1, and PCI slots can be [0..7].
- *
- * A given PCI device, in general, should be able to intr any of the cpus
- * on any one of the hubs connected to its xbow.
- */
-int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
- return 0;
-}
-
-static inline struct pci_dev *bridge_root_dev(struct pci_dev *dev)
-{
- while (dev->bus->parent) {
- /* Move up the chain of bridges. */
- dev = dev->bus->self;
- }
-
- return dev;
-}
-
-/* Do platform specific device initialization at pci_enable_device() time */
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
- struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
- struct pci_dev *rdev = bridge_root_dev(dev);
- int slot = PCI_SLOT(rdev->devfn);
- int irq;
-
- irq = bc->pci_int[slot];
- if (irq == -1) {
- irq = request_bridge_irq(bc, slot);
- if (irq < 0)
- return irq;
-
- bc->pci_int[slot] = irq;
- }
- dev->irq = irq;
-
- return 0;
-}
-
-dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct bridge_controller *bc = BRIDGE_CONTROLLER(pdev->bus);
-
- return bc->baddr + paddr;
-}
-
-phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t dma_addr)
-{
- return dma_addr & ~(0xffUL << 56);
-}
-
-/*
- * Device might live on a subordinate PCI bus. XXX Walk up the chain of buses
- * to find the slot number in sense of the bridge device register.
- * XXX This also means multiple devices might rely on conflicting bridge
- * settings.
- */
-
-static inline void pci_disable_swapping(struct pci_dev *dev)
-{
- struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
- struct bridge_regs *bridge = bc->base;
- int slot = PCI_SLOT(dev->devfn);
-
- /* Turn off byte swapping */
- bridge->b_device[slot].reg &= ~BRIDGE_DEV_SWAP_DIR;
- bridge->b_widget.w_tflush; /* Flush */
-}
-
-static void pci_fixup_ioc3(struct pci_dev *d)
-{
- pci_disable_swapping(d);
-}
-
-#ifdef CONFIG_NUMA
-int pcibus_to_node(struct pci_bus *bus)
-{
- struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
-
- return bc->nasid;
-}
-EXPORT_SYMBOL(pcibus_to_node);
-#endif /* CONFIG_NUMA */
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
- pci_fixup_ioc3);
diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c
index 6074efeff894..066b33f50bcc 100644
--- a/arch/mips/sgi-ip27/ip27-init.c
+++ b/arch/mips/sgi-ip27/ip27-init.c
@@ -184,5 +184,7 @@ void __init plat_mem_setup(void)
ioc3_eth_init();
+ ioport_resource.start = 0;
+ ioport_resource.end = ~0UL;
set_io_port_base(IO_BASE);
}
diff --git a/arch/mips/sgi-ip27/ip27-xtalk.c b/arch/mips/sgi-ip27/ip27-xtalk.c
index ce06aaa115ae..8579b651d862 100644
--- a/arch/mips/sgi-ip27/ip27-xtalk.c
+++ b/arch/mips/sgi-ip27/ip27-xtalk.c
@@ -9,6 +9,8 @@
#include <linux/kernel.h>
#include <linux/smp.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/xtalk-bridge.h>
#include <asm/sn/types.h>
#include <asm/sn/klconfig.h>
#include <asm/sn/hub.h>
@@ -20,7 +22,19 @@
#define XXBOW_WIDGET_PART_NUM 0xd000 /* Xbow in Xbridge */
#define BASE_XBOW_PORT 8 /* Lowest external port */
-extern int bridge_probe(nasid_t nasid, int widget, int masterwid);
+static void bridge_platform_create(nasid_t nasid, int widget, int masterwid)
+{
+ struct platform_device *pdev;
+ struct xtalk_bridge_platform_data bridge_data;
+
+ pdev = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
+ bridge_data.nasid = nasid;
+ bridge_data.widget = widget;
+ bridge_data.masterwid = masterwid;
+ platform_device_add_data(pdev, &bridge_data, sizeof(bridge_data));
+ platform_device_add(pdev);
+ pr_info("xtalk:n%d/%x bridge widget\n", nasid, widget);
+}
static int probe_one_port(nasid_t nasid, int widget, int masterwid)
{
@@ -31,13 +45,10 @@ static int probe_one_port(nasid_t nasid, int widget, int masterwid)
(RAW_NODE_SWIN_BASE(nasid, widget) + WIDGET_ID);
partnum = XWIDGET_PART_NUM(widget_id);
- printk(KERN_INFO "Cpu %d, Nasid 0x%x, widget 0x%x (partnum 0x%x) is ",
- smp_processor_id(), nasid, widget, partnum);
-
switch (partnum) {
case BRIDGE_WIDGET_PART_NUM:
case XBRIDGE_WIDGET_PART_NUM:
- bridge_probe(nasid, widget, masterwid);
+ bridge_platform_create(nasid, widget, masterwid);
break;
default:
break;
@@ -52,8 +63,6 @@ static int xbow_probe(nasid_t nasid)
klxbow_t *xbow_p;
unsigned masterwid, i;
- printk("is xbow\n");
-
/*
* found xbow, so may have multiple bridges
* need to probe xbow
@@ -117,19 +126,17 @@ static void xtalk_probe_node(cnodeid_t nid)
(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
partnum = XWIDGET_PART_NUM(widget_id);
- printk(KERN_INFO "Cpu %d, Nasid 0x%x: partnum 0x%x is ",
- smp_processor_id(), nasid, partnum);
-
switch (partnum) {
case BRIDGE_WIDGET_PART_NUM:
- bridge_probe(nasid, 0x8, 0xa);
+ bridge_platform_create(nasid, 0x8, 0xa);
break;
case XBOW_WIDGET_PART_NUM:
case XXBOW_WIDGET_PART_NUM:
+ pr_info("xtalk:n%d/0 xbow widget\n", nasid);
xbow_probe(nasid);
break;
default:
- printk(" unknown widget??\n");
+ pr_info("xtalk:n%d/0 unknown widget (0x%x)\n", nasid, partnum);
break;
}
}
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 6671946dbf66..c3815353f2f8 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -265,6 +265,9 @@ config PCIE_TANGO_SMP8759
This can lead to data corruption if drivers perform concurrent
config and MMIO accesses.
+config PCI_XTALK_BRIDGE
+ bool
+
config VMD
depends on PCI_MSI && X86_64 && SRCU
tristate "Intel Volume Management Device Driver"
diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index d56a507495c5..bcbd740f878c 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o
obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
+obj-$(CONFIG_PCI_XTALK_BRIDGE) += pci-xtalk-bridge.o
obj-$(CONFIG_VMD) += vmd.o
# pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
obj-y += dwc/
diff --git a/arch/mips/pci/ops-bridge.c b/drivers/pci/controller/pci-xtalk-bridge.c
similarity index 52%
rename from arch/mips/pci/ops-bridge.c
rename to drivers/pci/controller/pci-xtalk-bridge.c
index df95b0da08f2..77e42c46937b 100644
--- a/arch/mips/pci/ops-bridge.c
+++ b/drivers/pci/controller/pci-xtalk-bridge.c
@@ -3,13 +3,21 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1999, 2000, 04, 06 Ralf Baechle ([email protected])
+ * Copyright (C) 2003 Christoph Hellwig ([email protected])
+ * Copyright (C) 1999, 2000, 04 Ralf Baechle ([email protected])
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/
+#include <linux/kernel.h>
+#include <linux/export.h>
#include <linux/pci.h>
-#include <asm/paccess.h>
-#include <asm/pci/bridge.h>
+#include <linux/smp.h>
+#include <linux/dma-direct.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/xtalk-bridge.h>
+
#include <asm/sn/arch.h>
+#include <asm/pci/bridge.h>
+#include <asm/paccess.h>
#include <asm/sn/intr.h>
#include <asm/sn/sn0/hub.h>
@@ -29,6 +37,20 @@ static u32 emulate_ioc3_cfg(int where, int size)
return 0;
}
+static void bridge_disable_swapping(struct pci_dev *dev)
+{
+ struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
+ int slot = PCI_SLOT(dev->devfn);
+
+ /* Turn off byte swapping */
+ bridge_clr(bc, b_device[slot].reg, BRIDGE_DEV_SWAP_DIR);
+ bridge_read(bc, b_widget.w_tflush); /* Flush */
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+ bridge_disable_swapping);
+
+
/*
* The Bridge ASIC supports both type 0 and type 1 access. Type 1 is
* not really documented, so right now I can't write code which uses it.
@@ -39,20 +61,19 @@ static u32 emulate_ioc3_cfg(int where, int size)
* which is used in SGI systems. The IOC3 can only handle 32-bit PCI
* accesses and does only decode parts of it's address space.
*/
-
static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 * value)
+ int where, int size, u32 *value)
{
struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
struct bridge_regs *bridge = bc->base;
int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn);
- volatile void *addr;
+ void *addr;
u32 cf, shift, mask;
int res;
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID];
- if (get_dbe(cf, (u32 *) addr))
+ if (get_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND;
/*
@@ -65,11 +86,11 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
if (size == 1)
- res = get_dbe(*value, (u8 *) addr);
+ res = get_dbe(*value, (u8 *)addr);
else if (size == 2)
- res = get_dbe(*value, (u16 *) addr);
+ res = get_dbe(*value, (u16 *)addr);
else
- res = get_dbe(*value, (u32 *) addr);
+ res = get_dbe(*value, (u32 *)addr);
return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
@@ -84,8 +105,7 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
}
addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
-
- if (get_dbe(cf, (u32 *) addr))
+ if (get_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND;
shift = ((where & 3) << 3);
@@ -96,20 +116,20 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
}
static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 * value)
+ int where, int size, u32 *value)
{
struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
struct bridge_regs *bridge = bc->base;
int busno = bus->number;
int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn);
- volatile void *addr;
+ void *addr;
u32 cf, shift, mask;
int res;
bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
- if (get_dbe(cf, (u32 *) addr))
+ if (get_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND;
/*
@@ -119,15 +139,14 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
goto is_ioc3;
- bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
if (size == 1)
- res = get_dbe(*value, (u8 *) addr);
+ res = get_dbe(*value, (u8 *)addr);
else if (size == 2)
- res = get_dbe(*value, (u16 *) addr);
+ res = get_dbe(*value, (u16 *)addr);
else
- res = get_dbe(*value, (u32 *) addr);
+ res = get_dbe(*value, (u32 *)addr);
return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
@@ -141,10 +160,8 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_SUCCESSFUL;
}
- bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
addr = &bridge->b_type1_cfg.c[(fn << 8) | where];
-
- if (get_dbe(cf, (u32 *) addr))
+ if (get_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND;
shift = ((where & 3) << 3);
@@ -155,7 +172,7 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
}
static int pci_read_config(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 * value)
+ int where, int size, u32 *value)
{
if (!pci_is_root_bus(bus))
return pci_conf1_read_config(bus, devfn, where, size, value);
@@ -170,12 +187,12 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
struct bridge_regs *bridge = bc->base;
int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn);
- volatile void *addr;
+ void *addr;
u32 cf, shift, mask, smask;
int res;
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID];
- if (get_dbe(cf, (u32 *) addr))
+ if (get_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND;
/*
@@ -187,13 +204,12 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
- if (size == 1) {
- res = put_dbe(value, (u8 *) addr);
- } else if (size == 2) {
- res = put_dbe(value, (u16 *) addr);
- } else {
- res = put_dbe(value, (u32 *) addr);
- }
+ if (size == 1)
+ res = put_dbe(value, (u8 *)addr);
+ else if (size == 2)
+ res = put_dbe(value, (u16 *)addr);
+ else
+ res = put_dbe(value, (u32 *)addr);
if (res)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -210,7 +226,7 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
- if (get_dbe(cf, (u32 *) addr))
+ if (get_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND;
shift = ((where & 3) << 3);
@@ -218,7 +234,7 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
smask = mask << shift;
cf = (cf & ~smask) | ((value & mask) << shift);
- if (put_dbe(cf, (u32 *) addr))
+ if (put_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND;
return PCIBIOS_SUCCESSFUL;
@@ -232,13 +248,13 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn);
int busno = bus->number;
- volatile void *addr;
+ void *addr;
u32 cf, shift, mask, smask;
int res;
bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
- if (get_dbe(cf, (u32 *) addr))
+ if (get_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND;
/*
@@ -250,13 +266,12 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
- if (size == 1) {
- res = put_dbe(value, (u8 *) addr);
- } else if (size == 2) {
- res = put_dbe(value, (u16 *) addr);
- } else {
- res = put_dbe(value, (u32 *) addr);
- }
+ if (size == 1)
+ res = put_dbe(value, (u8 *)addr);
+ else if (size == 2)
+ res = put_dbe(value, (u16 *)addr);
+ else
+ res = put_dbe(value, (u32 *)addr);
if (res)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -272,8 +287,7 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_SUCCESSFUL;
addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
-
- if (get_dbe(cf, (u32 *) addr))
+ if (get_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND;
shift = ((where & 3) << 3);
@@ -281,7 +295,7 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
smask = mask << shift;
cf = (cf & ~smask) | ((value & mask) << shift);
- if (put_dbe(cf, (u32 *) addr))
+ if (put_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND;
return PCIBIOS_SUCCESSFUL;
@@ -296,7 +310,173 @@ static int pci_write_config(struct pci_bus *bus, unsigned int devfn,
return pci_conf0_write_config(bus, devfn, where, size, value);
}
-struct pci_ops bridge_pci_ops = {
- .read = pci_read_config,
- .write = pci_write_config,
+static int bridge_add_bus(struct pci_bus *bus)
+{
+ struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+
+ set_dev_node(&bus->dev, bc->nasid);
+ return 0;
+}
+
+static struct pci_ops bridge_pci_ops = {
+ .add_bus = bridge_add_bus,
+ .read = pci_read_config,
+ .write = pci_write_config,
+};
+
+/*
+ * All observed requests have pin == 1. We could have a global here, that
+ * gets incremented and returned every time - unfortunately, pci_map_irq
+ * may be called on the same device over and over, and need to return the
+ * same value. On O2000, pin can be 0 or 1, and PCI slots can be [0..7].
+ *
+ * A given PCI device, in general, should be able to intr any of the cpus
+ * on any one of the hubs connected to its xbow.
+ */
+static int bridge_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
+ int irq;
+
+ irq = bc->pci_int[slot];
+ if (irq == -1) {
+ irq = request_bridge_irq(bc, slot);
+ if (irq < 0)
+ return irq;
+
+ bc->pci_int[slot] = irq;
+ }
+ return irq;
+}
+
+static int bridge_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct bridge_controller *bc;
+ struct pci_host_bridge *host;
+ unsigned long offset;
+ int slot;
+ int err;
+ struct xtalk_bridge_platform_data *bd = dev_get_platdata(&pdev->dev);
+
+ offset = NODE_OFFSET(bd->nasid);
+
+ pci_set_flags(PCI_PROBE_ONLY);
+
+ host = devm_pci_alloc_host_bridge(dev, sizeof(*bc));
+ if (!host)
+ return -ENOMEM;
+
+ bc = pci_host_bridge_priv(host);
+
+ bc->mem.name = "Bridge PCI MEM";
+ bc->mem.start = offset + (bd->widget << SWIN_SIZE_BITS);
+ bc->mem.end = bc->mem.start + SWIN_SIZE;
+ bc->mem.flags = IORESOURCE_MEM;
+
+ bc->io.name = "Bridge PCI IO";
+ bc->io.start = offset + (bd->widget << SWIN_SIZE_BITS);
+ bc->io.end = bc->io.start + SWIN_SIZE;
+ bc->io.flags = IORESOURCE_IO;
+
+ bc->busn.name = "Bridge PCI busn";
+ bc->busn.start = 0;
+ bc->busn.end = 0xff;
+ bc->busn.flags = IORESOURCE_BUS;
+
+ pci_add_resource_offset(&host->windows, &bc->mem, offset);
+ pci_add_resource_offset(&host->windows, &bc->io, offset);
+ pci_add_resource(&host->windows, &bc->busn);
+
+ err = devm_request_pci_bus_resources(dev, &host->windows);
+ if (err < 0) {
+ pci_free_resource_list(&host->windows);
+ return err;
+ }
+
+ bc->nasid = bd->nasid;
+
+ bc->baddr = (u64)bd->masterwid << 60 | PCI64_ATTR_BAR;
+
+ /*
+ * point to this bridge
+ */
+ bc->base = (struct bridge_regs *)RAW_NODE_SWIN_BASE(bd->nasid,
+ bd->widget);
+
+ /*
+ * Clear all pending interrupts.
+ */
+ bridge_write(bc, b_int_rst_stat, BRIDGE_IRR_ALL_CLR);
+
+ /*
+ * Until otherwise set up, assume all interrupts are from slot 0
+ */
+ bridge_write(bc, b_int_device, 0x0);
+
+ /*
+ * disable swapping for big windows
+ */
+ bridge_clr(bc, b_wid_control,
+ BRIDGE_CTRL_IO_SWAP | BRIDGE_CTRL_MEM_SWAP);
+#ifdef CONFIG_PAGE_SIZE_4KB
+ bridge_clr(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
+#else /* 16kB or larger */
+ bridge_set(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
+#endif
+
+ /*
+ * Hmm... IRIX sets additional bits in the address which
+ * are documented as reserved in the bridge docs.
+ */
+ bridge_write(bc, b_wid_int_upper, 0x8000 | (bd->masterwid << 16));
+ bridge_write(bc, b_wid_int_lower, 0x01800090); /* PI_INT_PEND_MOD off*/
+ bridge_write(bc, b_dir_map, (bd->masterwid << 20)); /* DMA */
+ bridge_write(bc, b_int_enable, 0);
+
+ for (slot = 0; slot < 8; slot++) {
+ bridge_set(bc, b_device[slot].reg, BRIDGE_DEV_SWAP_DIR);
+ bc->pci_int[slot] = -1;
+ }
+ bridge_read(bc, b_wid_tflush); /* wait until Bridge PIO complete */
+
+ host->dev.parent = dev;
+ host->sysdata = bc;
+ host->busnr = 0;
+ host->ops = &bridge_pci_ops;
+ host->map_irq = bridge_map_irq;
+ host->swizzle_irq = pci_common_swizzle;
+
+ err = pci_scan_root_bus_bridge(host);
+ if (err < 0)
+ return err;
+
+ pci_bus_claim_resources(host->bus);
+ pci_bus_add_devices(host->bus);
+
+ platform_set_drvdata(pdev, host->bus);
+
+ return 0;
+}
+
+static int bridge_remove(struct platform_device *pdev)
+{
+ struct pci_bus *bus = platform_get_drvdata(pdev);
+
+ pci_lock_rescan_remove();
+ pci_stop_root_bus(bus);
+ pci_remove_root_bus(bus);
+ pci_unlock_rescan_remove();
+
+ return 0;
+}
+
+static struct platform_driver bridge_driver = {
+ .probe = bridge_probe,
+ .remove = bridge_remove,
+ .driver = {
+ .name = "xtalk-bridge",
+ }
};
+
+builtin_platform_driver(bridge_driver);
diff --git a/include/linux/platform_data/xtalk-bridge.h b/include/linux/platform_data/xtalk-bridge.h
new file mode 100644
index 000000000000..818d4b457429
--- /dev/null
+++ b/include/linux/platform_data/xtalk-bridge.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SGI PCI Xtalk Bridge
+ */
+
+#ifndef PLATFORM_DATA_XTALK_BRIDGE_H
+#define PLATFORM_DATA_XTALK_BRIDGE_H
+
+#include <asm/sn/types.h>
+
+struct xtalk_bridge_platform_data {
+ nasid_t nasid;
+ int widget;
+ int masterwid;
+};
+
+#endif /* PLATFORM_DATA_XTALK_BRIDGE_H */
--
2.13.7
When creating hierarchy domains use irq_default_domain as parent, if no
parent was given by the caller. This avoids adding helper code for
querying the underlying platform irq domain.
Signed-off-by: Thomas Bogendoerfer <[email protected]>
---
kernel/irq/irqdomain.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 8b0be4bd6565..617c482d0778 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -1021,7 +1021,10 @@ struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent,
else
domain = irq_domain_create_tree(fwnode, ops, host_data);
if (domain) {
- domain->parent = parent;
+ if (parent)
+ domain->parent = parent;
+ else
+ domain->parent = irq_default_domain;
domain->flags |= flags;
}
--
2.13.7
This commit rearranges the HUB interrupt code by using MIPS_IRQ_CPU
interrupt handling code and modern Linux IRQ framework features to get
rid of global arrays. It also adds support for irq affinity setting.
Signed-off-by: Thomas Bogendoerfer <[email protected]>
---
arch/mips/Kconfig | 1 +
arch/mips/include/asm/mach-ip27/irq.h | 12 +-
arch/mips/include/asm/mach-ip27/mmzone.h | 9 -
arch/mips/include/asm/pci/bridge.h | 4 +-
arch/mips/pci/pci-ip27.c | 18 +-
arch/mips/sgi-ip27/Makefile | 3 +-
arch/mips/sgi-ip27/ip27-init.c | 33 +--
arch/mips/sgi-ip27/ip27-irq-pci.c | 264 -----------------------
arch/mips/sgi-ip27/ip27-irq.c | 357 +++++++++++++++++++++----------
arch/mips/sgi-ip27/ip27-irqno.c | 48 -----
arch/mips/sgi-ip27/ip27-timer.c | 42 +---
11 files changed, 260 insertions(+), 531 deletions(-)
delete mode 100644 arch/mips/sgi-ip27/ip27-irq-pci.c
delete mode 100644 arch/mips/sgi-ip27/ip27-irqno.c
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index a84c24d894aa..93b88e8e72d0 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -676,6 +676,7 @@ config SGI_IP27
select DEFAULT_SGI_PARTITION
select SYS_HAS_EARLY_PRINTK
select HAVE_PCI
+ select IRQ_MIPS_CPU
select NR_CPUS_DEFAULT_64
select SYS_HAS_CPU_R10000
select SYS_SUPPORTS_64BIT_KERNEL
diff --git a/arch/mips/include/asm/mach-ip27/irq.h b/arch/mips/include/asm/mach-ip27/irq.h
index b0b7261ff3ad..fd91c58aaf7d 100644
--- a/arch/mips/include/asm/mach-ip27/irq.h
+++ b/arch/mips/include/asm/mach-ip27/irq.h
@@ -10,13 +10,15 @@
#ifndef __ASM_MACH_IP27_IRQ_H
#define __ASM_MACH_IP27_IRQ_H
-/*
- * A hardwired interrupt number is completely stupid for this system - a
- * large configuration might have thousands if not tenthousands of
- * interrupts.
- */
#define NR_IRQS 256
#include_next <irq.h>
+#define IP27_HUB_PEND0_IRQ (MIPS_CPU_IRQ_BASE + 2)
+#define IP27_HUB_PEND1_IRQ (MIPS_CPU_IRQ_BASE + 3)
+#define IP27_RT_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 4)
+
+#define IP27_HUB_IRQ_BASE (MIPS_CPU_IRQ_BASE + 8)
+#define IP27_HUB_IRQ_COUNT 128
+
#endif /* __ASM_MACH_IP27_IRQ_H */
diff --git a/arch/mips/include/asm/mach-ip27/mmzone.h b/arch/mips/include/asm/mach-ip27/mmzone.h
index 2ed3094dee07..1cd6a23a84f2 100644
--- a/arch/mips/include/asm/mach-ip27/mmzone.h
+++ b/arch/mips/include/asm/mach-ip27/mmzone.h
@@ -8,20 +8,11 @@
#define pa_to_nid(addr) NASID_TO_COMPACT_NODEID(NASID_GET(addr))
-#define LEVELS_PER_SLICE 128
-
-struct slice_data {
- unsigned long irq_enable_mask[2];
- int level_to_irq[LEVELS_PER_SLICE];
-};
-
struct hub_data {
kern_vars_t kern_vars;
DECLARE_BITMAP(h_bigwin_used, HUB_NUM_BIG_WINDOW);
cpumask_t h_cpus;
unsigned long slice_map;
- unsigned long irq_alloc_mask[2];
- struct slice_data slice[2];
};
struct node_data {
diff --git a/arch/mips/include/asm/pci/bridge.h b/arch/mips/include/asm/pci/bridge.h
index 0c5fe3a2d2a9..23574c27eb40 100644
--- a/arch/mips/include/asm/pci/bridge.h
+++ b/arch/mips/include/asm/pci/bridge.h
@@ -808,7 +808,6 @@ struct bridge_controller {
struct bridge_regs *base;
nasid_t nasid;
unsigned int widget_id;
- unsigned int irq_cpu;
u64 baddr;
unsigned int pci_int[8];
};
@@ -823,8 +822,7 @@ struct bridge_controller {
#define bridge_clr(bc, reg, val) \
__raw_writel(__raw_readl(&bc->base->reg) & ~(val), &bc->base->reg)
-extern void register_bridge_irq(unsigned int irq);
-extern int request_bridge_irq(struct bridge_controller *bc);
+extern int request_bridge_irq(struct bridge_controller *bc, int pin);
extern struct pci_ops bridge_pci_ops;
diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c
index 7cf50290a6d9..3c177b4d0609 100644
--- a/arch/mips/pci/pci-ip27.c
+++ b/arch/mips/pci/pci-ip27.c
@@ -24,22 +24,11 @@
#define MAX_PCI_BUSSES 40
/*
- * Max #PCI devices (like scsi controllers) we handle on a bus.
- */
-#define MAX_DEVICES_PER_PCIBUS 8
-
-/*
* XXX: No kmalloc available when we do our crosstalk scan,
* we should try to move it later in the boot process.
*/
static struct bridge_controller bridges[MAX_PCI_BUSSES];
-/*
- * Translate from irq to software PCI bus number and PCI slot.
- */
-struct bridge_controller *irq_to_bridge[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS];
-int irq_to_slot[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS];
-
extern struct pci_ops bridge_pci_ops;
int bridge_probe(nasid_t nasid, int widget_id, int masterwid)
@@ -77,7 +66,6 @@ int bridge_probe(nasid_t nasid, int widget_id, int masterwid)
bc->io.end = ~0UL;
bc->io.flags = IORESOURCE_IO;
- bc->irq_cpu = smp_processor_id();
bc->widget_id = widget_id;
bc->nasid = nasid;
@@ -165,16 +153,12 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
irq = bc->pci_int[slot];
if (irq == -1) {
- irq = request_bridge_irq(bc);
+ irq = request_bridge_irq(bc, slot);
if (irq < 0)
return irq;
bc->pci_int[slot] = irq;
}
-
- irq_to_bridge[irq] = bc;
- irq_to_slot[irq] = slot;
-
dev->irq = irq;
return 0;
diff --git a/arch/mips/sgi-ip27/Makefile b/arch/mips/sgi-ip27/Makefile
index 73502fda13ee..27c14ede191e 100644
--- a/arch/mips/sgi-ip27/Makefile
+++ b/arch/mips/sgi-ip27/Makefile
@@ -3,10 +3,9 @@
# Makefile for the IP27 specific kernel interface routines under Linux.
#
-obj-y := ip27-berr.o ip27-irq.o ip27-irqno.o ip27-init.o ip27-klconfig.o \
+obj-y := ip27-berr.o ip27-irq.o ip27-init.o ip27-klconfig.o \
ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-reset.o ip27-timer.o \
ip27-hubio.o ip27-xtalk.o
obj-$(CONFIG_EARLY_PRINTK) += ip27-console.o
-obj-$(CONFIG_PCI) += ip27-irq-pci.o
obj-$(CONFIG_SMP) += ip27-smp.o
diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c
index e6fa9d0c708a..6074efeff894 100644
--- a/arch/mips/sgi-ip27/ip27-init.c
+++ b/arch/mips/sgi-ip27/ip27-init.c
@@ -56,7 +56,6 @@ static void per_hub_init(cnodeid_t cnode)
{
struct hub_data *hub = hub_data(cnode);
nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
- int i;
cpumask_set_cpu(smp_processor_id(), &hub->h_cpus);
@@ -87,24 +86,6 @@ static void per_hub_init(cnodeid_t cnode)
__flush_cache_all();
}
#endif
-
- /*
- * Some interrupts are reserved by hardware or by software convention.
- * Mark these as reserved right away so they won't be used accidentally
- * later.
- */
- for (i = 0; i <= BASE_PCI_IRQ; i++) {
- __set_bit(i, hub->irq_alloc_mask);
- LOCAL_HUB_CLR_INTR(INT_PEND0_BASELVL + i);
- }
-
- __set_bit(IP_PEND0_6_63, hub->irq_alloc_mask);
- LOCAL_HUB_S(PI_INT_PEND_MOD, IP_PEND0_6_63);
-
- for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++) {
- __set_bit(i, hub->irq_alloc_mask);
- LOCAL_HUB_CLR_INTR(INT_PEND1_BASELVL + i);
- }
}
void per_cpu_init(void)
@@ -113,8 +94,6 @@ void per_cpu_init(void)
int slice = LOCAL_HUB_L(PI_CPU_NUM);
cnodeid_t cnode = get_compact_nodeid();
struct hub_data *hub = hub_data(cnode);
- struct slice_data *si = hub->slice + slice;
- int i;
if (test_and_set_bit(slice, &hub->slice_map))
return;
@@ -123,22 +102,14 @@ void per_cpu_init(void)
per_hub_init(cnode);
- for (i = 0; i < LEVELS_PER_SLICE; i++)
- si->level_to_irq[i] = -1;
-
- /*
- * We use this so we can find the local hub's data as fast as only
- * possible.
- */
- cpu_data[cpu].data = si;
-
cpu_time_init();
install_ipi();
/* Install our NMI handler if symmon hasn't installed one. */
install_cpu_nmi_handler(cputoslice(cpu));
- set_c0_status(SRB_DEV0 | SRB_DEV1);
+ enable_percpu_irq(IP27_HUB_PEND0_IRQ, IRQ_TYPE_NONE);
+ enable_percpu_irq(IP27_HUB_PEND1_IRQ, IRQ_TYPE_NONE);
}
/*
diff --git a/arch/mips/sgi-ip27/ip27-irq-pci.c b/arch/mips/sgi-ip27/ip27-irq-pci.c
deleted file mode 100644
index a00a23b32a2a..000000000000
--- a/arch/mips/sgi-ip27/ip27-irq-pci.c
+++ /dev/null
@@ -1,264 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ip27-irq.c: Highlevel interrupt handling for IP27 architecture.
- *
- * Copyright (C) 1999, 2000 Ralf Baechle ([email protected])
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- * Copyright (C) 1999 - 2001 Kanoj Sarcar
- */
-
-#undef DEBUG
-
-#include <linux/irq.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/smp.h>
-#include <linux/random.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/mipsregs.h>
-
-#include <asm/processor.h>
-#include <asm/pci/bridge.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/agent.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/hub.h>
-#include <asm/sn/intr.h>
-
-/*
- * Linux has a controller-independent x86 interrupt architecture.
- * every controller has a 'controller-template', that is used
- * by the main code to do the right thing. Each driver-visible
- * interrupt source is transparently wired to the appropriate
- * controller. Thus drivers need not be aware of the
- * interrupt-controller.
- *
- * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
- * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
- * (IO-APICs assumed to be messaging to Pentium local-APICs)
- *
- * the code is designed to be easily extended with new/different
- * interrupt controllers, without having to do assembly magic.
- */
-
-extern struct bridge_controller *irq_to_bridge[];
-extern int irq_to_slot[];
-
-/*
- * use these macros to get the encoded nasid and widget id
- * from the irq value
- */
-#define IRQ_TO_BRIDGE(i) irq_to_bridge[(i)]
-#define SLOT_FROM_PCI_IRQ(i) irq_to_slot[i]
-
-static inline int alloc_level(int cpu, int irq)
-{
- struct hub_data *hub = hub_data(cpu_to_node(cpu));
- struct slice_data *si = cpu_data[cpu].data;
- int level;
-
- level = find_first_zero_bit(hub->irq_alloc_mask, LEVELS_PER_SLICE);
- if (level >= LEVELS_PER_SLICE)
- panic("Cpu %d flooded with devices", cpu);
-
- __set_bit(level, hub->irq_alloc_mask);
- si->level_to_irq[level] = irq;
-
- return level;
-}
-
-static inline int find_level(cpuid_t *cpunum, int irq)
-{
- int cpu, i;
-
- for_each_online_cpu(cpu) {
- struct slice_data *si = cpu_data[cpu].data;
-
- for (i = BASE_PCI_IRQ; i < LEVELS_PER_SLICE; i++)
- if (si->level_to_irq[i] == irq) {
- *cpunum = cpu;
-
- return i;
- }
- }
-
- panic("Could not identify cpu/level for irq %d", irq);
-}
-
-static int intr_connect_level(int cpu, int bit)
-{
- nasid_t nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
- struct slice_data *si = cpu_data[cpu].data;
-
- set_bit(bit, si->irq_enable_mask);
-
- if (!cputoslice(cpu)) {
- REMOTE_HUB_S(nasid, PI_INT_MASK0_A, si->irq_enable_mask[0]);
- REMOTE_HUB_S(nasid, PI_INT_MASK1_A, si->irq_enable_mask[1]);
- } else {
- REMOTE_HUB_S(nasid, PI_INT_MASK0_B, si->irq_enable_mask[0]);
- REMOTE_HUB_S(nasid, PI_INT_MASK1_B, si->irq_enable_mask[1]);
- }
-
- return 0;
-}
-
-static int intr_disconnect_level(int cpu, int bit)
-{
- nasid_t nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
- struct slice_data *si = cpu_data[cpu].data;
-
- clear_bit(bit, si->irq_enable_mask);
-
- if (!cputoslice(cpu)) {
- REMOTE_HUB_S(nasid, PI_INT_MASK0_A, si->irq_enable_mask[0]);
- REMOTE_HUB_S(nasid, PI_INT_MASK1_A, si->irq_enable_mask[1]);
- } else {
- REMOTE_HUB_S(nasid, PI_INT_MASK0_B, si->irq_enable_mask[0]);
- REMOTE_HUB_S(nasid, PI_INT_MASK1_B, si->irq_enable_mask[1]);
- }
-
- return 0;
-}
-
-/* Startup one of the (PCI ...) IRQs routes over a bridge. */
-static unsigned int startup_bridge_irq(struct irq_data *d)
-{
- struct bridge_controller *bc;
- int pin, swlevel;
- cpuid_t cpu;
- u64 device;
-
- pin = SLOT_FROM_PCI_IRQ(d->irq);
- bc = IRQ_TO_BRIDGE(d->irq);
-
- pr_debug("bridge_startup(): irq= 0x%x pin=%d\n", d->irq, pin);
- /*
- * "map" irq to a swlevel greater than 6 since the first 6 bits
- * of INT_PEND0 are taken
- */
- swlevel = find_level(&cpu, d->irq);
- bridge_write(bc, b_int_addr[pin].addr,
- (0x20000 | swlevel | (bc->nasid << 8)));
- bridge_set(bc, b_int_enable, (1 << pin));
- bridge_set(bc, b_int_enable, 0x7ffffe00); /* more stuff in int_enable */
-
- /*
- * Enable sending of an interrupt clear packt to the hub on a high to
- * low transition of the interrupt pin.
- *
- * IRIX sets additional bits in the address which are documented as
- * reserved in the bridge docs.
- */
- bridge_set(bc, b_int_mode, (1UL << pin));
-
- /*
- * We assume the bridge to have a 1:1 mapping between devices
- * (slots) and intr pins.
- */
- device = bridge_read(bc, b_int_device);
- device &= ~(7 << (pin*3));
- device |= (pin << (pin*3));
- bridge_write(bc, b_int_device, device);
-
- bridge_read(bc, b_wid_tflush);
-
- intr_connect_level(cpu, swlevel);
-
- return 0; /* Never anything pending. */
-}
-
-/* Shutdown one of the (PCI ...) IRQs routes over a bridge. */
-static void shutdown_bridge_irq(struct irq_data *d)
-{
- struct bridge_controller *bc = IRQ_TO_BRIDGE(d->irq);
- int pin, swlevel;
- cpuid_t cpu;
-
- pr_debug("bridge_shutdown: irq 0x%x\n", d->irq);
- pin = SLOT_FROM_PCI_IRQ(d->irq);
-
- /*
- * map irq to a swlevel greater than 6 since the first 6 bits
- * of INT_PEND0 are taken
- */
- swlevel = find_level(&cpu, d->irq);
- intr_disconnect_level(cpu, swlevel);
-
- bridge_clr(bc, b_int_enable, (1 << pin));
- bridge_read(bc, b_wid_tflush);
-}
-
-static inline void enable_bridge_irq(struct irq_data *d)
-{
- cpuid_t cpu;
- int swlevel;
-
- swlevel = find_level(&cpu, d->irq); /* Criminal offence */
- intr_connect_level(cpu, swlevel);
-}
-
-static inline void disable_bridge_irq(struct irq_data *d)
-{
- cpuid_t cpu;
- int swlevel;
-
- swlevel = find_level(&cpu, d->irq); /* Criminal offence */
- intr_disconnect_level(cpu, swlevel);
-}
-
-static struct irq_chip bridge_irq_type = {
- .name = "bridge",
- .irq_startup = startup_bridge_irq,
- .irq_shutdown = shutdown_bridge_irq,
- .irq_mask = disable_bridge_irq,
- .irq_unmask = enable_bridge_irq,
-};
-
-void register_bridge_irq(unsigned int irq)
-{
- irq_set_chip_and_handler(irq, &bridge_irq_type, handle_level_irq);
-}
-
-int request_bridge_irq(struct bridge_controller *bc)
-{
- int irq = allocate_irqno();
- int swlevel, cpu;
- nasid_t nasid;
-
- if (irq < 0)
- return irq;
-
- /*
- * "map" irq to a swlevel greater than 6 since the first 6 bits
- * of INT_PEND0 are taken
- */
- cpu = bc->irq_cpu;
- swlevel = alloc_level(cpu, irq);
- if (unlikely(swlevel < 0)) {
- free_irqno(irq);
-
- return -EAGAIN;
- }
-
- /* Make sure it's not already pending when we connect it. */
- nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
- REMOTE_HUB_CLR_INTR(nasid, swlevel);
-
- intr_connect_level(cpu, swlevel);
-
- register_bridge_irq(irq);
-
- return irq;
-}
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
index f37155ef7ed9..710a59764b01 100644
--- a/arch/mips/sgi-ip27/ip27-irq.c
+++ b/arch/mips/sgi-ip27/ip27-irq.c
@@ -7,67 +7,234 @@
* Copyright (C) 1999 - 2001 Kanoj Sarcar
*/
-#undef DEBUG
-
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/smp.h>
-#include <linux/random.h>
#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/delay.h>
#include <linux/bitops.h>
-#include <asm/bootinfo.h>
#include <asm/io.h>
-#include <asm/mipsregs.h>
-
-#include <asm/processor.h>
+#include <asm/irq_cpu.h>
+#include <asm/pci/bridge.h>
#include <asm/sn/addrs.h>
#include <asm/sn/agent.h>
#include <asm/sn/arch.h>
#include <asm/sn/hub.h>
#include <asm/sn/intr.h>
-/*
- * Linux has a controller-independent x86 interrupt architecture.
- * every controller has a 'controller-template', that is used
- * by the main code to do the right thing. Each driver-visible
- * interrupt source is transparently wired to the appropriate
- * controller. Thus drivers need not be aware of the
- * interrupt-controller.
- *
- * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
- * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
- * (IO-APICs assumed to be messaging to Pentium local-APICs)
- *
- * the code is designed to be easily extended with new/different
- * interrupt controllers, without having to do assembly magic.
- */
+struct hub_irq_data {
+ struct bridge_controller *bc;
+ u64 *irq_mask[2];
+ cpuid_t cpu;
+ int bit;
+ int pin;
+};
-extern asmlinkage void ip27_irq(void);
+static DECLARE_BITMAP(hub_irq_map, IP27_HUB_IRQ_COUNT);
-/*
- * Find first bit set
- */
-static int ms1bit(unsigned long x)
+static DEFINE_PER_CPU(unsigned long [2], irq_enable_mask);
+
+static inline int alloc_level(void)
+{
+ int level;
+
+again:
+ level = find_first_zero_bit(hub_irq_map, IP27_HUB_IRQ_COUNT);
+ if (level >= IP27_HUB_IRQ_COUNT)
+ return -ENOSPC;
+
+ if (test_and_set_bit(level, hub_irq_map))
+ goto again;
+
+ return level;
+}
+
+static void enable_hub_irq(struct irq_data *d)
+{
+ struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
+ unsigned long *mask = per_cpu(irq_enable_mask, hd->cpu);
+
+ set_bit(hd->bit, mask);
+ __raw_writeq(mask[0], hd->irq_mask[0]);
+ __raw_writeq(mask[1], hd->irq_mask[1]);
+}
+
+static void disable_hub_irq(struct irq_data *d)
+{
+ struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
+ unsigned long *mask = per_cpu(irq_enable_mask, hd->cpu);
+
+ clear_bit(hd->bit, mask);
+ __raw_writeq(mask[0], hd->irq_mask[0]);
+ __raw_writeq(mask[1], hd->irq_mask[1]);
+}
+
+static unsigned int startup_bridge_irq(struct irq_data *d)
+{
+ struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
+ struct bridge_controller *bc;
+ nasid_t nasid;
+ u32 device;
+ int pin;
+
+ if (!hd)
+ return -EINVAL;
+
+ pin = hd->pin;
+ bc = hd->bc;
+
+ nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(hd->cpu));
+ bridge_write(bc, b_int_addr[pin].addr,
+ (0x20000 | hd->bit | (nasid << 8)));
+ bridge_set(bc, b_int_enable, (1 << pin));
+ bridge_set(bc, b_int_enable, 0x7ffffe00); /* more stuff in int_enable */
+
+ /*
+ * Enable sending of an interrupt clear packt to the hub on a high to
+ * low transition of the interrupt pin.
+ *
+ * IRIX sets additional bits in the address which are documented as
+ * reserved in the bridge docs.
+ */
+ bridge_set(bc, b_int_mode, (1UL << pin));
+
+ /*
+ * We assume the bridge to have a 1:1 mapping between devices
+ * (slots) and intr pins.
+ */
+ device = bridge_read(bc, b_int_device);
+ device &= ~(7 << (pin*3));
+ device |= (pin << (pin*3));
+ bridge_write(bc, b_int_device, device);
+
+ bridge_read(bc, b_wid_tflush);
+
+ enable_hub_irq(d);
+
+ return 0; /* Never anything pending. */
+}
+
+static void shutdown_bridge_irq(struct irq_data *d)
+{
+ struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
+ struct bridge_controller *bc;
+ int pin = hd->pin;
+
+ if (!hd)
+ return;
+
+ disable_hub_irq(d);
+
+ bc = hd->bc;
+ bridge_clr(bc, b_int_enable, (1 << pin));
+ bridge_read(bc, b_wid_tflush);
+}
+
+static void setup_hub_mask(struct hub_irq_data *hd, const struct cpumask *mask)
+{
+ nasid_t nasid;
+ int cpu;
+
+ cpu = cpumask_first_and(mask, cpu_online_mask);
+ nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
+ hd->cpu = cpu;
+ if (!cputoslice(cpu)) {
+ hd->irq_mask[0] = REMOTE_HUB_PTR(nasid, PI_INT_MASK0_A);
+ hd->irq_mask[1] = REMOTE_HUB_PTR(nasid, PI_INT_MASK1_A);
+ } else {
+ hd->irq_mask[0] = REMOTE_HUB_PTR(nasid, PI_INT_MASK0_B);
+ hd->irq_mask[1] = REMOTE_HUB_PTR(nasid, PI_INT_MASK1_B);
+ }
+
+ /* Make sure it's not already pending when we connect it. */
+ REMOTE_HUB_CLR_INTR(nasid, hd->bit);
+}
+
+static int set_affinity_hub_irq(struct irq_data *d, const struct cpumask *mask,
+ bool force)
+{
+ struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
+
+ if (!hd)
+ return -EINVAL;
+
+ if (irqd_is_started(d))
+ disable_hub_irq(d);
+
+ setup_hub_mask(hd, mask);
+
+ if (irqd_is_started(d))
+ startup_bridge_irq(d);
+
+ irq_data_update_effective_affinity(d, cpumask_of(hd->cpu));
+
+ return 0;
+}
+
+static struct irq_chip hub_irq_type = {
+ .name = "HUB",
+ .irq_startup = startup_bridge_irq,
+ .irq_shutdown = shutdown_bridge_irq,
+ .irq_mask = disable_hub_irq,
+ .irq_unmask = enable_hub_irq,
+ .irq_set_affinity = set_affinity_hub_irq,
+};
+
+int request_bridge_irq(struct bridge_controller *bc, int pin)
{
- int b = 0, s;
+ struct hub_irq_data *hd;
+ struct hub_data *hub;
+ struct irq_desc *desc;
+ int swlevel;
+ int irq;
+
+ hd = kzalloc(sizeof(*hd), GFP_KERNEL);
+ if (!hd)
+ return -ENOMEM;
+
+ swlevel = alloc_level();
+ if (unlikely(swlevel < 0)) {
+ kfree(hd);
+ return -EAGAIN;
+ }
+ irq = swlevel + IP27_HUB_IRQ_BASE;
+
+ hd->bc = bc;
+ hd->bit = swlevel;
+ hd->pin = pin;
+ irq_set_chip_data(irq, hd);
+
+ /* use CPU connected to nearest hub */
+ hub = hub_data(NASID_TO_COMPACT_NODEID(bc->nasid));
+ setup_hub_mask(hd, &hub->h_cpus);
- s = 16; if (x >> 16 == 0) s = 0; b += s; x >>= s;
- s = 8; if (x >> 8 == 0) s = 0; b += s; x >>= s;
- s = 4; if (x >> 4 == 0) s = 0; b += s; x >>= s;
- s = 2; if (x >> 2 == 0) s = 0; b += s; x >>= s;
- s = 1; if (x >> 1 == 0) s = 0; b += s;
+ desc = irq_to_desc(irq);
+ desc->irq_common_data.node = bc->nasid;
+ cpumask_copy(desc->irq_common_data.affinity, &hub->h_cpus);
- return b;
+ return irq;
+}
+
+void ip27_hub_irq_init(void)
+{
+ int i;
+
+ for (i = IP27_HUB_IRQ_BASE;
+ i < (IP27_HUB_IRQ_BASE + IP27_HUB_IRQ_COUNT); i++)
+ irq_set_chip_and_handler(i, &hub_irq_type, handle_level_irq);
+
+ /*
+ * Some interrupts are reserved by hardware or by software convention.
+ * Mark these as reserved right away so they won't be used accidentally
+ * later.
+ */
+ for (i = 0; i <= BASE_PCI_IRQ; i++)
+ set_bit(i, hub_irq_map);
+
+ set_bit(IP_PEND0_6_63, hub_irq_map);
+
+ for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++)
+ set_bit(i, hub_irq_map);
}
/*
@@ -82,23 +249,19 @@ static int ms1bit(unsigned long x)
* Kanoj 05.13.00
*/
-static void ip27_do_irq_mask0(void)
+static void ip27_do_irq_mask0(struct irq_desc *desc)
{
- int irq, swlevel;
- u64 pend0, mask0;
cpuid_t cpu = smp_processor_id();
- int pi_int_mask0 =
- (cputoslice(cpu) == 0) ? PI_INT_MASK0_A : PI_INT_MASK0_B;
+ unsigned long *mask = per_cpu(irq_enable_mask, cpu);
+ u64 pend0;
/* copied from Irix intpend0() */
pend0 = LOCAL_HUB_L(PI_INT_PEND0);
- mask0 = LOCAL_HUB_L(pi_int_mask0);
- pend0 &= mask0; /* Pick intrs we should look at */
+ pend0 &= mask[0]; /* Pick intrs we should look at */
if (!pend0)
return;
- swlevel = ms1bit(pend0);
#ifdef CONFIG_SMP
if (pend0 & (1UL << CPU_RESCHED_A_IRQ)) {
LOCAL_HUB_CLR_INTR(CPU_RESCHED_A_IRQ);
@@ -108,106 +271,66 @@ static void ip27_do_irq_mask0(void)
scheduler_ipi();
} else if (pend0 & (1UL << CPU_CALL_A_IRQ)) {
LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ);
- irq_enter();
generic_smp_call_function_interrupt();
- irq_exit();
} else if (pend0 & (1UL << CPU_CALL_B_IRQ)) {
LOCAL_HUB_CLR_INTR(CPU_CALL_B_IRQ);
- irq_enter();
generic_smp_call_function_interrupt();
- irq_exit();
} else
#endif
- {
- /* "map" swlevel to irq */
- struct slice_data *si = cpu_data[cpu].data;
-
- irq = si->level_to_irq[swlevel];
- do_IRQ(irq);
- }
+ generic_handle_irq(__ffs(pend0) + IP27_HUB_IRQ_BASE);
LOCAL_HUB_L(PI_INT_PEND0);
}
-static void ip27_do_irq_mask1(void)
+static void ip27_do_irq_mask1(struct irq_desc *desc)
{
- int irq, swlevel;
- u64 pend1, mask1;
cpuid_t cpu = smp_processor_id();
- int pi_int_mask1 = (cputoslice(cpu) == 0) ? PI_INT_MASK1_A : PI_INT_MASK1_B;
- struct slice_data *si = cpu_data[cpu].data;
+ unsigned long *mask = per_cpu(irq_enable_mask, cpu);
+ u64 pend1;
/* copied from Irix intpend0() */
pend1 = LOCAL_HUB_L(PI_INT_PEND1);
- mask1 = LOCAL_HUB_L(pi_int_mask1);
- pend1 &= mask1; /* Pick intrs we should look at */
+ pend1 &= mask[1]; /* Pick intrs we should look at */
if (!pend1)
return;
- swlevel = ms1bit(pend1);
- /* "map" swlevel to irq */
- irq = si->level_to_irq[swlevel];
- LOCAL_HUB_CLR_INTR(swlevel);
- do_IRQ(irq);
+ generic_handle_irq(__ffs(pend1) + IP27_HUB_IRQ_BASE + 64);
LOCAL_HUB_L(PI_INT_PEND1);
}
-static void ip27_prof_timer(void)
-{
- panic("CPU %d got a profiling interrupt", smp_processor_id());
-}
-
-static void ip27_hub_error(void)
-{
- panic("CPU %d got a hub error interrupt", smp_processor_id());
-}
-
-asmlinkage void plat_irq_dispatch(void)
-{
- unsigned long pending = read_c0_cause() & read_c0_status();
- extern unsigned int rt_timer_irq;
-
- if (pending & CAUSEF_IP4)
- do_IRQ(rt_timer_irq);
- else if (pending & CAUSEF_IP2) /* PI_INT_PEND_0 or CC_PEND_{A|B} */
- ip27_do_irq_mask0();
- else if (pending & CAUSEF_IP3) /* PI_INT_PEND_1 */
- ip27_do_irq_mask1();
- else if (pending & CAUSEF_IP5)
- ip27_prof_timer();
- else if (pending & CAUSEF_IP6)
- ip27_hub_error();
-}
-
-void __init arch_init_irq(void)
-{
-}
-
void install_ipi(void)
{
- int slice = LOCAL_HUB_L(PI_CPU_NUM);
int cpu = smp_processor_id();
- struct slice_data *si = cpu_data[cpu].data;
- struct hub_data *hub = hub_data(cpu_to_node(cpu));
+ unsigned long *mask = per_cpu(irq_enable_mask, cpu);
+ int slice = LOCAL_HUB_L(PI_CPU_NUM);
int resched, call;
resched = CPU_RESCHED_A_IRQ + slice;
- __set_bit(resched, hub->irq_alloc_mask);
- __set_bit(resched, si->irq_enable_mask);
+ set_bit(resched, mask);
LOCAL_HUB_CLR_INTR(resched);
call = CPU_CALL_A_IRQ + slice;
- __set_bit(call, hub->irq_alloc_mask);
- __set_bit(call, si->irq_enable_mask);
+ set_bit(call, mask);
LOCAL_HUB_CLR_INTR(call);
if (slice == 0) {
- LOCAL_HUB_S(PI_INT_MASK0_A, si->irq_enable_mask[0]);
- LOCAL_HUB_S(PI_INT_MASK1_A, si->irq_enable_mask[1]);
+ LOCAL_HUB_S(PI_INT_MASK0_A, mask[0]);
+ LOCAL_HUB_S(PI_INT_MASK1_A, mask[1]);
} else {
- LOCAL_HUB_S(PI_INT_MASK0_B, si->irq_enable_mask[0]);
- LOCAL_HUB_S(PI_INT_MASK1_B, si->irq_enable_mask[1]);
+ LOCAL_HUB_S(PI_INT_MASK0_B, mask[0]);
+ LOCAL_HUB_S(PI_INT_MASK1_B, mask[1]);
}
}
+
+void __init arch_init_irq(void)
+{
+ mips_cpu_irq_init();
+ ip27_hub_irq_init();
+
+ irq_set_percpu_devid(IP27_HUB_PEND0_IRQ);
+ irq_set_chained_handler(IP27_HUB_PEND0_IRQ, ip27_do_irq_mask0);
+ irq_set_percpu_devid(IP27_HUB_PEND1_IRQ);
+ irq_set_chained_handler(IP27_HUB_PEND1_IRQ, ip27_do_irq_mask1);
+}
diff --git a/arch/mips/sgi-ip27/ip27-irqno.c b/arch/mips/sgi-ip27/ip27-irqno.c
deleted file mode 100644
index 957ab58e1c00..000000000000
--- a/arch/mips/sgi-ip27/ip27-irqno.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/types.h>
-
-#include <asm/barrier.h>
-
-static DECLARE_BITMAP(irq_map, NR_IRQS);
-
-int allocate_irqno(void)
-{
- int irq;
-
-again:
- irq = find_first_zero_bit(irq_map, NR_IRQS);
-
- if (irq >= NR_IRQS)
- return -ENOSPC;
-
- if (test_and_set_bit(irq, irq_map))
- goto again;
-
- return irq;
-}
-
-/*
- * Allocate the 16 legacy interrupts for i8259 devices. This happens early
- * in the kernel initialization so treating allocation failure as BUG() is
- * ok.
- */
-void __init alloc_legacy_irqno(void)
-{
- int i;
-
- for (i = 0; i <= 16; i++)
- BUG_ON(test_and_set_bit(i, irq_map));
-}
-
-void free_irqno(unsigned int irq)
-{
- smp_mb__before_atomic();
- clear_bit(irq, irq_map);
- smp_mb__after_atomic();
-}
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
index 9d55247533a5..9b4b9ac621a3 100644
--- a/arch/mips/sgi-ip27/ip27-timer.c
+++ b/arch/mips/sgi-ip27/ip27-timer.c
@@ -38,20 +38,6 @@
#include <asm/sn/sn0/hubio.h>
#include <asm/pci/bridge.h>
-static void enable_rt_irq(struct irq_data *d)
-{
-}
-
-static void disable_rt_irq(struct irq_data *d)
-{
-}
-
-static struct irq_chip rt_irq_type = {
- .name = "SN HUB RT timer",
- .irq_mask = disable_rt_irq,
- .irq_unmask = enable_rt_irq,
-};
-
static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
{
unsigned int cpu = smp_processor_id();
@@ -65,8 +51,6 @@ static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0;
}
-unsigned int rt_timer_irq;
-
static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent);
static DEFINE_PER_CPU(char [11], hub_rt_name);
@@ -87,6 +71,7 @@ static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id)
struct irqaction hub_rt_irqaction = {
.handler = hub_rt_counter_handler,
+ .percpu_dev_id = &hub_rt_clockevent,
.flags = IRQF_PERCPU | IRQF_TIMER,
.name = "hub-rt",
};
@@ -107,7 +92,6 @@ void hub_rt_clock_event_init(void)
unsigned int cpu = smp_processor_id();
struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu);
unsigned char *name = per_cpu(hub_rt_name, cpu);
- int irq = rt_timer_irq;
sprintf(name, "hub-rt %d", cpu);
cd->name = name;
@@ -118,29 +102,19 @@ void hub_rt_clock_event_init(void)
cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
cd->min_delta_ticks = 0x300;
cd->rating = 200;
- cd->irq = irq;
+ cd->irq = IP27_RT_TIMER_IRQ;
cd->cpumask = cpumask_of(cpu);
cd->set_next_event = rt_next_event;
clockevents_register_device(cd);
+
+ enable_percpu_irq(IP27_RT_TIMER_IRQ, IRQ_TYPE_NONE);
}
static void __init hub_rt_clock_event_global_init(void)
{
- int irq;
-
- do {
- smp_wmb();
- irq = rt_timer_irq;
- if (irq)
- break;
-
- irq = allocate_irqno();
- if (irq < 0)
- panic("Allocation of irq number for timer failed");
- } while (xchg(&rt_timer_irq, irq));
-
- irq_set_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq);
- setup_irq(irq, &hub_rt_irqaction);
+ irq_set_handler(IP27_RT_TIMER_IRQ, handle_percpu_devid_irq);
+ irq_set_percpu_devid(IP27_RT_TIMER_IRQ);
+ setup_percpu_irq(IP27_RT_TIMER_IRQ, &hub_rt_irqaction);
}
static u64 hub_rt_read(struct clocksource *cs)
@@ -194,8 +168,6 @@ void cpu_time_init(void)
panic("No information about myself?");
printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed);
-
- set_c0_status(SRB_TIMOCLK);
}
void hub_rtc_init(cnodeid_t cnode)
--
2.13.7
Move xtalk scanning to a later boot stage to be able using things like
kmalloc and friends.
Signed-off-by: Thomas Bogendoerfer <[email protected]>
---
arch/mips/sgi-ip27/ip27-init.c | 3 ---
arch/mips/sgi-ip27/ip27-xtalk.c | 13 ++++++++++++-
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c
index 83399e578b61..aba985cf07c0 100644
--- a/arch/mips/sgi-ip27/ip27-init.c
+++ b/arch/mips/sgi-ip27/ip27-init.c
@@ -52,8 +52,6 @@ EXPORT_SYMBOL_GPL(sn_cpu_info);
extern void pcibr_setup(cnodeid_t);
-extern void xtalk_probe_node(cnodeid_t nid);
-
static void per_hub_init(cnodeid_t cnode)
{
struct hub_data *hub = hub_data(cnode);
@@ -71,7 +69,6 @@ static void per_hub_init(cnodeid_t cnode)
REMOTE_HUB_S(nasid, IIO_ICTO, 0xff);
hub_rtc_init(cnode);
- xtalk_probe_node(cnode);
#ifdef CONFIG_REPLICATE_EXHANDLERS
/*
diff --git a/arch/mips/sgi-ip27/ip27-xtalk.c b/arch/mips/sgi-ip27/ip27-xtalk.c
index 4fe5678ba74d..ce06aaa115ae 100644
--- a/arch/mips/sgi-ip27/ip27-xtalk.c
+++ b/arch/mips/sgi-ip27/ip27-xtalk.c
@@ -99,7 +99,7 @@ static int xbow_probe(nasid_t nasid)
return 0;
}
-void xtalk_probe_node(cnodeid_t nid)
+static void xtalk_probe_node(cnodeid_t nid)
{
volatile u64 hubreg;
nasid_t nasid;
@@ -133,3 +133,14 @@ void xtalk_probe_node(cnodeid_t nid)
break;
}
}
+
+static int __init xtalk_init(void)
+{
+ cnodeid_t cnode;
+
+ for_each_online_node(cnode)
+ xtalk_probe_node(cnode);
+
+ return 0;
+}
+arch_initcall(xtalk_init);
--
2.13.7
pci-xtalk controller code uses the add_bus method to set node of
the bus device, which then is used for pcibus_to_node() implementation.
Signed-off-by: Thomas Bogendoerfer <[email protected]>
---
drivers/pci/probe.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 257b9f6f2ebb..456448d5f46d 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -837,6 +837,12 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
pcibios_add_bus(bus);
+ if (bus->ops->add_bus) {
+ err = bus->ops->add_bus(bus);
+ if (WARN_ON(err < 0))
+ dev_err(&bus->dev, "failed to add bus: %d\n", err);
+ }
+
/* Create legacy_io and legacy_mem files for this bus */
pci_create_legacy_files(bus);
--
2.13.7
Replace hub register access with __raw_readq/__raw_writeq and get
rid of hubreg_t completely. Also remove no longer (probably never
used) used defines
Signed-off-by: Thomas Bogendoerfer <[email protected]>
---
arch/mips/include/asm/sn/addrs.h | 72 +++++-----------------------------------
arch/mips/include/asm/sn/arch.h | 2 --
arch/mips/include/asm/sn/io.h | 2 +-
arch/mips/sgi-ip27/ip27-hubio.c | 4 +--
arch/mips/sgi-ip27/ip27-init.c | 2 +-
arch/mips/sgi-ip27/ip27-irq.c | 4 +--
arch/mips/sgi-ip27/ip27-memory.c | 6 ++--
arch/mips/sgi-ip27/ip27-nmi.c | 2 +-
8 files changed, 19 insertions(+), 75 deletions(-)
diff --git a/arch/mips/include/asm/sn/addrs.h b/arch/mips/include/asm/sn/addrs.h
index 66814f8ba8e8..837d23e24976 100644
--- a/arch/mips/include/asm/sn/addrs.h
+++ b/arch/mips/include/asm/sn/addrs.h
@@ -27,16 +27,11 @@
#ifndef __ASSEMBLY__
-#define PS_UINT_CAST (unsigned long)
#define UINT64_CAST (unsigned long)
-#define HUBREG_CAST (volatile hubreg_t *)
-
#else /* __ASSEMBLY__ */
-#define PS_UINT_CAST
#define UINT64_CAST
-#define HUBREG_CAST
#endif /* __ASSEMBLY__ */
@@ -256,42 +251,23 @@
* Otherwise, the recommended approach is to use *_HUB_L() and *_HUB_S().
* They're always safe.
*/
-#define LOCAL_HUB_ADDR(_x) (HUBREG_CAST (IALIAS_BASE + (_x)))
-#define REMOTE_HUB_ADDR(_n, _x) (HUBREG_CAST (NODE_SWIN_BASE(_n, 1) + \
- 0x800000 + (_x)))
-#ifdef CONFIG_SGI_IP27
-#define REMOTE_HUB_PI_ADDR(_n, _sn, _x) (HUBREG_CAST (NODE_SWIN_BASE(_n, 1) + \
- 0x800000 + (_x)))
-#endif /* CONFIG_SGI_IP27 */
+#define LOCAL_HUB_ADDR(_x) (IALIAS_BASE + (_x))
+#define REMOTE_HUB_ADDR(_n, _x) ((NODE_SWIN_BASE(_n, 1) + 0x800000 + (_x)))
#ifndef __ASSEMBLY__
-#define HUB_L(_a) *(_a)
-#define HUB_S(_a, _d) *(_a) = (_d)
+#define LOCAL_HUB_PTR(_x) ((u64 *)LOCAL_HUB_ADDR((_x)))
+#define REMOTE_HUB_PTR(_n, _x) ((u64 *)REMOTE_HUB_ADDR((_n), (_x)))
-#define LOCAL_HUB_L(_r) HUB_L(LOCAL_HUB_ADDR(_r))
-#define LOCAL_HUB_S(_r, _d) HUB_S(LOCAL_HUB_ADDR(_r), (_d))
-#define REMOTE_HUB_L(_n, _r) HUB_L(REMOTE_HUB_ADDR((_n), (_r)))
-#define REMOTE_HUB_S(_n, _r, _d) HUB_S(REMOTE_HUB_ADDR((_n), (_r)), (_d))
-#define REMOTE_HUB_PI_L(_n, _sn, _r) HUB_L(REMOTE_HUB_PI_ADDR((_n), (_sn), (_r)))
-#define REMOTE_HUB_PI_S(_n, _sn, _r, _d) HUB_S(REMOTE_HUB_PI_ADDR((_n), (_sn), (_r)), (_d))
+#define LOCAL_HUB_L(_r) __raw_readq(LOCAL_HUB_PTR(_r))
+#define LOCAL_HUB_S(_r, _d) __raw_writeq((_d), LOCAL_HUB_PTR(_r))
+#define REMOTE_HUB_L(_n, _r) __raw_readq(REMOTE_HUB_PTR((_n), (_r)))
+#define REMOTE_HUB_S(_n, _r, _d) __raw_writeq((_d), \
+ REMOTE_HUB_PTR((_n), (_r)))
#endif /* !__ASSEMBLY__ */
/*
- * The following macros are used to get to a hub/bridge register, given
- * the base of the register space.
- */
-#define HUB_REG_PTR(_base, _off) \
- (HUBREG_CAST((__psunsigned_t)(_base) + (__psunsigned_t)(_off)))
-
-#define HUB_REG_PTR_L(_base, _off) \
- HUB_L(HUB_REG_PTR((_base), (_off)))
-
-#define HUB_REG_PTR_S(_base, _off, _data) \
- HUB_S(HUB_REG_PTR((_base), (_off)), (_data))
-
-/*
* Software structure locations -- permanently fixed
* See diagram in kldir.h
*/
@@ -387,44 +363,14 @@
#define SYMMON_STK_END(nasid) (SYMMON_STK_ADDR(nasid, 0) + KLD_SYMMON_STK(nasid)->size)
-/* loading symmon 4k below UNIX. the arcs loader needs the topaddr for a
- * relocatable program
- */
-#define UNIX_DEBUG_LOADADDR 0x300000
-#define SYMMON_LOADADDR(nasid) \
- TO_NODE(nasid, PHYS_TO_K0(UNIX_DEBUG_LOADADDR - 0x1000))
-
-#define FREEMEM_OFFSET(nasid) KLD_FREEMEM(nasid)->offset
-#define FREEMEM_ADDR(nasid) SYMMON_STK_END(nasid)
-/*
- * XXX
- * Fix this. FREEMEM_ADDR should be aware of if symmon is loaded.
- * Also, it should take into account what prom thinks to be a safe
- * address
- PHYS_TO_K0(NODE_OFFSET(nasid) + FREEMEM_OFFSET(nasid))
- */
-#define FREEMEM_SIZE(nasid) KLD_FREEMEM(nasid)->size
-
-#define PI_ERROR_OFFSET(nasid) KLD_PI_ERROR(nasid)->offset
-#define PI_ERROR_ADDR(nasid) \
- TO_NODE_UNCAC((nasid), PI_ERROR_OFFSET(nasid))
-#define PI_ERROR_SIZE(nasid) KLD_PI_ERROR(nasid)->size
-
#define NODE_OFFSET_TO_K0(_nasid, _off) \
PHYS_TO_K0((NODE_OFFSET(_nasid) + (_off)) | CAC_BASE)
#define NODE_OFFSET_TO_K1(_nasid, _off) \
TO_UNCAC((NODE_OFFSET(_nasid) + (_off)) | UNCAC_BASE)
-#define K0_TO_NODE_OFFSET(_k0addr) \
- ((__psunsigned_t)(_k0addr) & NODE_ADDRSPACE_MASK)
#define KERN_VARS_ADDR(nasid) KLD_KERN_VARS(nasid)->pointer
#define KERN_VARS_SIZE(nasid) KLD_KERN_VARS(nasid)->size
-#define KERN_XP_ADDR(nasid) KLD_KERN_XP(nasid)->pointer
-#define KERN_XP_SIZE(nasid) KLD_KERN_XP(nasid)->size
-
-#define GPDA_ADDR(nasid) TO_NODE_CAC(nasid, GPDA_OFFSET)
-
#endif /* !__ASSEMBLY__ */
diff --git a/arch/mips/include/asm/sn/arch.h b/arch/mips/include/asm/sn/arch.h
index 471e6870d876..3f1fb1454749 100644
--- a/arch/mips/include/asm/sn/arch.h
+++ b/arch/mips/include/asm/sn/arch.h
@@ -17,8 +17,6 @@
#include <asm/sn/sn0/arch.h>
#endif
-typedef u64 hubreg_t;
-
#define cputonasid(cpu) (sn_cpu_info[(cpu)].p_nasid)
#define cputoslice(cpu) (sn_cpu_info[(cpu)].p_slice)
#define makespnum(_nasid, _slice) \
diff --git a/arch/mips/include/asm/sn/io.h b/arch/mips/include/asm/sn/io.h
index d5174d04538c..211f1e83b523 100644
--- a/arch/mips/include/asm/sn/io.h
+++ b/arch/mips/include/asm/sn/io.h
@@ -44,7 +44,7 @@
IIO_ITTE_PUT((nasid), HUB_PIO_MAP_TO_MEM, \
(bigwin), IIO_ITTE_INVALID_WIDGET, 0)
-#define IIO_ITTE_GET(nasid, bigwin) REMOTE_HUB_ADDR((nasid), IIO_ITTE(bigwin))
+#define IIO_ITTE_GET(nasid, bigwin) REMOTE_HUB_PTR((nasid), IIO_ITTE(bigwin))
/*
* Macro which takes the widget number, and returns the
diff --git a/arch/mips/sgi-ip27/ip27-hubio.c b/arch/mips/sgi-ip27/ip27-hubio.c
index 2abe016a0ffc..68fb0cb89d9d 100644
--- a/arch/mips/sgi-ip27/ip27-hubio.c
+++ b/arch/mips/sgi-ip27/ip27-hubio.c
@@ -63,7 +63,7 @@ unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget,
* after we write it.
*/
IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr);
- (void) HUB_L(IIO_ITTE_GET(nasid, i));
+ __raw_readq(IIO_ITTE_GET(nasid, i));
return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE);
}
@@ -135,7 +135,7 @@ static void hub_setup_prb(nasid_t nasid, int prbnum, int credits)
**/
static void hub_set_piomode(nasid_t nasid)
{
- hubreg_t ii_iowa;
+ u64 ii_iowa;
hubii_wcr_t ii_wcr;
unsigned i;
diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c
index e501c43c02db..83399e578b61 100644
--- a/arch/mips/sgi-ip27/ip27-init.c
+++ b/arch/mips/sgi-ip27/ip27-init.c
@@ -177,7 +177,7 @@ extern void ip27_reboot_setup(void);
void __init plat_mem_setup(void)
{
- hubreg_t p, e, n_mode;
+ u64 p, e, n_mode;
nasid_t nid;
ip27_reboot_setup();
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
index 0dde6164a06f..f37155ef7ed9 100644
--- a/arch/mips/sgi-ip27/ip27-irq.c
+++ b/arch/mips/sgi-ip27/ip27-irq.c
@@ -85,7 +85,7 @@ static int ms1bit(unsigned long x)
static void ip27_do_irq_mask0(void)
{
int irq, swlevel;
- hubreg_t pend0, mask0;
+ u64 pend0, mask0;
cpuid_t cpu = smp_processor_id();
int pi_int_mask0 =
(cputoslice(cpu) == 0) ? PI_INT_MASK0_A : PI_INT_MASK0_B;
@@ -132,7 +132,7 @@ static void ip27_do_irq_mask0(void)
static void ip27_do_irq_mask1(void)
{
int irq, swlevel;
- hubreg_t pend1, mask1;
+ u64 pend1, mask1;
cpuid_t cpu = smp_processor_id();
int pi_int_mask1 = (cputoslice(cpu) == 0) ? PI_INT_MASK1_A : PI_INT_MASK1_B;
struct slice_data *si = cpu_data[cpu].data;
diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c
index 813d13f92957..87ef4181934e 100644
--- a/arch/mips/sgi-ip27/ip27-memory.c
+++ b/arch/mips/sgi-ip27/ip27-memory.c
@@ -44,7 +44,7 @@ static int is_fine_dirmode(void)
return ((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK) >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE;
}
-static hubreg_t get_region(cnodeid_t cnode)
+static u64 get_region(cnodeid_t cnode)
{
if (fine_mode)
return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_FINEREG_SHFT;
@@ -52,9 +52,9 @@ static hubreg_t get_region(cnodeid_t cnode)
return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_COARSEREG_SHFT;
}
-static hubreg_t region_mask;
+static u64 region_mask;
-static void gen_region_mask(hubreg_t *region_mask)
+static void gen_region_mask(u64 *region_mask)
{
cnodeid_t cnode;
diff --git a/arch/mips/sgi-ip27/ip27-nmi.c b/arch/mips/sgi-ip27/ip27-nmi.c
index 8ac2bfa35fb6..8cb3a5d6d7d1 100644
--- a/arch/mips/sgi-ip27/ip27-nmi.c
+++ b/arch/mips/sgi-ip27/ip27-nmi.c
@@ -130,7 +130,7 @@ void nmi_cpu_eframe_save(nasid_t nasid, int slice)
void nmi_dump_hub_irq(nasid_t nasid, int slice)
{
- hubreg_t mask0, mask1, pend0, pend1;
+ u64 mask0, mask1, pend0, pend1;
if (slice == 0) { /* Slice A */
mask0 = REMOTE_HUB_L(nasid, PI_INT_MASK0_A);
--
2.13.7
Introduced bridge_read/bridge_write/bridge_set/bridge_clr for accessing
bridge register and get rid of volatile declarations. Also removed
all typedefs from arch/mips/include/asm/pci/bridge.h and cleaned up
language in arch/mips/pci/ops-bridge.c
Signed-off-by: Thomas Bogendoerfer <[email protected]>
---
arch/mips/include/asm/pci/bridge.h | 202 +++++++++++++++--------------------
arch/mips/include/asm/sn/sn0/addrs.h | 5 -
arch/mips/pci/ops-bridge.c | 68 +++++-------
arch/mips/pci/pci-ip27.c | 31 +++---
arch/mips/sgi-ip27/ip27-irq-pci.c | 24 ++---
5 files changed, 138 insertions(+), 192 deletions(-)
diff --git a/arch/mips/include/asm/pci/bridge.h b/arch/mips/include/asm/pci/bridge.h
index 3206245d1ed6..0c5fe3a2d2a9 100644
--- a/arch/mips/include/asm/pci/bridge.h
+++ b/arch/mips/include/asm/pci/bridge.h
@@ -45,18 +45,21 @@
#ifndef __ASSEMBLY__
-/*
- * All accesses to bridge hardware registers must be done
- * using 32-bit loads and stores.
- */
-typedef u32 bridgereg_t;
+#define ATE_V 0x01
+#define ATE_CO 0x02
+#define ATE_PREC 0x04
+#define ATE_PREF 0x08
+#define ATE_BAR 0x10
+
+#define ATE_PFNSHIFT 12
+#define ATE_TIDSHIFT 8
+#define ATE_RMFSHIFT 48
-typedef u64 bridge_ate_t;
+#define mkate(xaddr, xid, attr) (((xaddr) & 0x0000fffffffff000ULL) | \
+ ((xid)<<ATE_TIDSHIFT) | \
+ (attr))
-/* pointers to bridge ATEs
- * are always "pointer to volatile"
- */
-typedef volatile bridge_ate_t *bridge_ate_p;
+#define BRIDGE_INTERNAL_ATES 128
/*
* It is generally preferred that hardware registers on the bridge
@@ -65,7 +68,7 @@ typedef volatile bridge_ate_t *bridge_ate_p;
* Generated from Bridge spec dated 04oct95
*/
-typedef volatile struct bridge_s {
+struct bridge_regs {
/* Local Registers 0x000000-0x00FFFF */
/* standard widget configuration 0x000000-0x000057 */
@@ -86,105 +89,105 @@ typedef volatile struct bridge_s {
#define b_wid_tflush b_widget.w_tflush
/* bridge-specific widget configuration 0x000058-0x00007F */
- bridgereg_t _pad_000058;
- bridgereg_t b_wid_aux_err; /* 0x00005C */
- bridgereg_t _pad_000060;
- bridgereg_t b_wid_resp_upper; /* 0x000064 */
- bridgereg_t _pad_000068;
- bridgereg_t b_wid_resp_lower; /* 0x00006C */
- bridgereg_t _pad_000070;
- bridgereg_t b_wid_tst_pin_ctrl; /* 0x000074 */
- bridgereg_t _pad_000078[2];
+ u32 _pad_000058;
+ u32 b_wid_aux_err; /* 0x00005C */
+ u32 _pad_000060;
+ u32 b_wid_resp_upper; /* 0x000064 */
+ u32 _pad_000068;
+ u32 b_wid_resp_lower; /* 0x00006C */
+ u32 _pad_000070;
+ u32 b_wid_tst_pin_ctrl; /* 0x000074 */
+ u32 _pad_000078[2];
/* PMU & Map 0x000080-0x00008F */
- bridgereg_t _pad_000080;
- bridgereg_t b_dir_map; /* 0x000084 */
- bridgereg_t _pad_000088[2];
+ u32 _pad_000080;
+ u32 b_dir_map; /* 0x000084 */
+ u32 _pad_000088[2];
/* SSRAM 0x000090-0x00009F */
- bridgereg_t _pad_000090;
- bridgereg_t b_ram_perr; /* 0x000094 */
- bridgereg_t _pad_000098[2];
+ u32 _pad_000090;
+ u32 b_ram_perr; /* 0x000094 */
+ u32 _pad_000098[2];
/* Arbitration 0x0000A0-0x0000AF */
- bridgereg_t _pad_0000A0;
- bridgereg_t b_arb; /* 0x0000A4 */
- bridgereg_t _pad_0000A8[2];
+ u32 _pad_0000A0;
+ u32 b_arb; /* 0x0000A4 */
+ u32 _pad_0000A8[2];
/* Number In A Can 0x0000B0-0x0000BF */
- bridgereg_t _pad_0000B0;
- bridgereg_t b_nic; /* 0x0000B4 */
- bridgereg_t _pad_0000B8[2];
+ u32 _pad_0000B0;
+ u32 b_nic; /* 0x0000B4 */
+ u32 _pad_0000B8[2];
/* PCI/GIO 0x0000C0-0x0000FF */
- bridgereg_t _pad_0000C0;
- bridgereg_t b_bus_timeout; /* 0x0000C4 */
+ u32 _pad_0000C0;
+ u32 b_bus_timeout; /* 0x0000C4 */
#define b_pci_bus_timeout b_bus_timeout
- bridgereg_t _pad_0000C8;
- bridgereg_t b_pci_cfg; /* 0x0000CC */
- bridgereg_t _pad_0000D0;
- bridgereg_t b_pci_err_upper; /* 0x0000D4 */
- bridgereg_t _pad_0000D8;
- bridgereg_t b_pci_err_lower; /* 0x0000DC */
- bridgereg_t _pad_0000E0[8];
+ u32 _pad_0000C8;
+ u32 b_pci_cfg; /* 0x0000CC */
+ u32 _pad_0000D0;
+ u32 b_pci_err_upper; /* 0x0000D4 */
+ u32 _pad_0000D8;
+ u32 b_pci_err_lower; /* 0x0000DC */
+ u32 _pad_0000E0[8];
#define b_gio_err_lower b_pci_err_lower
#define b_gio_err_upper b_pci_err_upper
/* Interrupt 0x000100-0x0001FF */
- bridgereg_t _pad_000100;
- bridgereg_t b_int_status; /* 0x000104 */
- bridgereg_t _pad_000108;
- bridgereg_t b_int_enable; /* 0x00010C */
- bridgereg_t _pad_000110;
- bridgereg_t b_int_rst_stat; /* 0x000114 */
- bridgereg_t _pad_000118;
- bridgereg_t b_int_mode; /* 0x00011C */
- bridgereg_t _pad_000120;
- bridgereg_t b_int_device; /* 0x000124 */
- bridgereg_t _pad_000128;
- bridgereg_t b_int_host_err; /* 0x00012C */
+ u32 _pad_000100;
+ u32 b_int_status; /* 0x000104 */
+ u32 _pad_000108;
+ u32 b_int_enable; /* 0x00010C */
+ u32 _pad_000110;
+ u32 b_int_rst_stat; /* 0x000114 */
+ u32 _pad_000118;
+ u32 b_int_mode; /* 0x00011C */
+ u32 _pad_000120;
+ u32 b_int_device; /* 0x000124 */
+ u32 _pad_000128;
+ u32 b_int_host_err; /* 0x00012C */
struct {
- bridgereg_t __pad; /* 0x0001{30,,,68} */
- bridgereg_t addr; /* 0x0001{34,,,6C} */
+ u32 __pad; /* 0x0001{30,,,68} */
+ u32 addr; /* 0x0001{34,,,6C} */
} b_int_addr[8]; /* 0x000130 */
- bridgereg_t _pad_000170[36];
+ u32 _pad_000170[36];
/* Device 0x000200-0x0003FF */
struct {
- bridgereg_t __pad; /* 0x0002{00,,,38} */
- bridgereg_t reg; /* 0x0002{04,,,3C} */
+ u32 __pad; /* 0x0002{00,,,38} */
+ u32 reg; /* 0x0002{04,,,3C} */
} b_device[8]; /* 0x000200 */
struct {
- bridgereg_t __pad; /* 0x0002{40,,,78} */
- bridgereg_t reg; /* 0x0002{44,,,7C} */
+ u32 __pad; /* 0x0002{40,,,78} */
+ u32 reg; /* 0x0002{44,,,7C} */
} b_wr_req_buf[8]; /* 0x000240 */
struct {
- bridgereg_t __pad; /* 0x0002{80,,,88} */
- bridgereg_t reg; /* 0x0002{84,,,8C} */
+ u32 __pad; /* 0x0002{80,,,88} */
+ u32 reg; /* 0x0002{84,,,8C} */
} b_rrb_map[2]; /* 0x000280 */
#define b_even_resp b_rrb_map[0].reg /* 0x000284 */
#define b_odd_resp b_rrb_map[1].reg /* 0x00028C */
- bridgereg_t _pad_000290;
- bridgereg_t b_resp_status; /* 0x000294 */
- bridgereg_t _pad_000298;
- bridgereg_t b_resp_clear; /* 0x00029C */
+ u32 _pad_000290;
+ u32 b_resp_status; /* 0x000294 */
+ u32 _pad_000298;
+ u32 b_resp_clear; /* 0x00029C */
- bridgereg_t _pad_0002A0[24];
+ u32 _pad_0002A0[24];
char _pad_000300[0x10000 - 0x000300];
/* Internal Address Translation Entry RAM 0x010000-0x0103FF */
union {
- bridge_ate_t wr; /* write-only */
+ u64 wr; /* write-only */
struct {
- bridgereg_t _p_pad;
- bridgereg_t rd; /* read-only */
+ u32 _p_pad;
+ u32 rd; /* read-only */
} hi;
} b_int_ate_ram[128];
@@ -192,8 +195,8 @@ typedef volatile struct bridge_s {
/* Internal Address Translation Entry RAM LOW 0x011000-0x0113FF */
struct {
- bridgereg_t _p_pad;
- bridgereg_t rd; /* read-only */
+ u32 _p_pad;
+ u32 rd; /* read-only */
} b_int_ate_ram_lo[128];
char _pad_011400[0x20000 - 0x011400];
@@ -212,7 +215,7 @@ typedef volatile struct bridge_s {
} f[8];
} b_type0_cfg_dev[8]; /* 0x020000 */
- /* PCI Type 1 Configuration Space 0x028000-0x028FFF */
+ /* PCI Type 1 Configuration Space 0x028000-0x028FFF */
union { /* make all access sizes available. */
u8 c[0x1000 / 1];
u16 s[0x1000 / 2];
@@ -233,7 +236,7 @@ typedef volatile struct bridge_s {
u8 _pad_030007[0x04fff8]; /* 0x030008-0x07FFFF */
/* External Address Translation Entry RAM 0x080000-0x0FFFFF */
- bridge_ate_t b_ext_ate_ram[0x10000];
+ u64 b_ext_ate_ram[0x10000];
/* Reserved 0x100000-0x1FFFFF */
char _pad_100000[0x200000-0x100000];
@@ -259,13 +262,13 @@ typedef volatile struct bridge_s {
u32 l[0x400000 / 4]; /* read-only */
u64 d[0x400000 / 8]; /* read-only */
} b_external_flash; /* 0xC00000 */
-} bridge_t;
+};
/*
* Field formats for Error Command Word and Auxiliary Error Command Word
* of bridge.
*/
-typedef struct bridge_err_cmdword_s {
+struct bridge_err_cmdword {
union {
u32 cmd_word;
struct {
@@ -282,7 +285,7 @@ typedef struct bridge_err_cmdword_s {
rsvd:8;
} berr_st;
} berr_un;
-} bridge_err_cmdword_t;
+};
#define berr_field berr_un.berr_st
#endif /* !__ASSEMBLY__ */
@@ -290,7 +293,7 @@ typedef struct bridge_err_cmdword_s {
/*
* The values of these macros can and should be crosschecked
* regularly against the offsets of the like-named fields
- * within the "bridge_t" structure above.
+ * within the bridge_regs structure above.
*/
/* Byte offset macros for Bridge internal registers */
@@ -797,46 +800,12 @@ typedef struct bridge_err_cmdword_s {
#define PCI64_ATTR_RMF_MASK 0x00ff000000000000
#define PCI64_ATTR_RMF_SHFT 48
-#ifndef __ASSEMBLY__
-/* Address translation entry for mapped pci32 accesses */
-typedef union ate_u {
- u64 ent;
- struct ate_s {
- u64 rmf:16;
- u64 addr:36;
- u64 targ:4;
- u64 reserved:3;
- u64 barrier:1;
- u64 prefetch:1;
- u64 precise:1;
- u64 coherent:1;
- u64 valid:1;
- } field;
-} ate_t;
-#endif /* !__ASSEMBLY__ */
-
-#define ATE_V 0x01
-#define ATE_CO 0x02
-#define ATE_PREC 0x04
-#define ATE_PREF 0x08
-#define ATE_BAR 0x10
-
-#define ATE_PFNSHIFT 12
-#define ATE_TIDSHIFT 8
-#define ATE_RMFSHIFT 48
-
-#define mkate(xaddr, xid, attr) ((xaddr) & 0x0000fffffffff000ULL) | \
- ((xid)<<ATE_TIDSHIFT) | \
- (attr)
-
-#define BRIDGE_INTERNAL_ATES 128
-
struct bridge_controller {
struct pci_controller pc;
struct resource mem;
struct resource io;
struct resource busn;
- bridge_t *base;
+ struct bridge_regs *base;
nasid_t nasid;
unsigned int widget_id;
unsigned int irq_cpu;
@@ -847,6 +816,13 @@ struct bridge_controller {
#define BRIDGE_CONTROLLER(bus) \
((struct bridge_controller *)((bus)->sysdata))
+#define bridge_read(bc, reg) __raw_readl(&bc->base->reg)
+#define bridge_write(bc, reg, val) __raw_writel(val, &bc->base->reg)
+#define bridge_set(bc, reg, val) \
+ __raw_writel(__raw_readl(&bc->base->reg) | (val), &bc->base->reg)
+#define bridge_clr(bc, reg, val) \
+ __raw_writel(__raw_readl(&bc->base->reg) & ~(val), &bc->base->reg)
+
extern void register_bridge_irq(unsigned int irq);
extern int request_bridge_irq(struct bridge_controller *bc);
diff --git a/arch/mips/include/asm/sn/sn0/addrs.h b/arch/mips/include/asm/sn/sn0/addrs.h
index 6b53070f400f..f13df84edfdd 100644
--- a/arch/mips/include/asm/sn/sn0/addrs.h
+++ b/arch/mips/include/asm/sn/sn0/addrs.h
@@ -134,11 +134,6 @@
#define CALIAS_BASE CAC_BASE
-
-
-#define BRIDGE_REG_PTR(_base, _off) ((volatile bridgereg_t *) \
- ((__psunsigned_t)(_base) + (__psunsigned_t)(_off)))
-
#define SN0_WIDGET_BASE(_nasid, _wid) (NODE_SWIN_BASE((_nasid), (_wid)))
/* Turn on sable logging for the processors whose bits are set. */
diff --git a/arch/mips/pci/ops-bridge.c b/arch/mips/pci/ops-bridge.c
index a1d2c4ae0d1b..df95b0da08f2 100644
--- a/arch/mips/pci/ops-bridge.c
+++ b/arch/mips/pci/ops-bridge.c
@@ -44,7 +44,7 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 * value)
{
struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
- bridge_t *bridge = bc->base;
+ struct bridge_regs *bridge = bc->base;
int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn);
volatile void *addr;
@@ -56,11 +56,11 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_DEVICE_NOT_FOUND;
/*
- * IOC3 is fucking fucked beyond belief ... Don't even give the
+ * IOC3 is broken beyond belief ... Don't even give the
* generic PCI code a chance to look at it for real ...
*/
if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
- goto oh_my_gawd;
+ goto is_ioc3;
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
@@ -73,21 +73,16 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-oh_my_gawd:
+is_ioc3:
/*
- * IOC3 is fucking fucked beyond belief ... Don't even give the
- * generic PCI code a chance to look at the wrong register.
+ * IOC3 special handling
*/
if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) {
*value = emulate_ioc3_cfg(where, size);
return PCIBIOS_SUCCESSFUL;
}
- /*
- * IOC3 is fucking fucked beyond belief ... Don't try to access
- * anything but 32-bit words ...
- */
addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
if (get_dbe(cf, (u32 *) addr))
@@ -104,7 +99,7 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 * value)
{
struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
- bridge_t *bridge = bc->base;
+ struct bridge_regs *bridge = bc->base;
int busno = bus->number;
int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn);
@@ -112,19 +107,19 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
u32 cf, shift, mask;
int res;
- bridge->b_pci_cfg = (busno << 16) | (slot << 11);
+ bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
if (get_dbe(cf, (u32 *) addr))
return PCIBIOS_DEVICE_NOT_FOUND;
/*
- * IOC3 is fucking fucked beyond belief ... Don't even give the
+ * IOC3 is broken beyond belief ... Don't even give the
* generic PCI code a chance to look at it for real ...
*/
if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
- goto oh_my_gawd;
+ goto is_ioc3;
- bridge->b_pci_cfg = (busno << 16) | (slot << 11);
+ bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
if (size == 1)
@@ -136,22 +131,17 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-oh_my_gawd:
+is_ioc3:
/*
- * IOC3 is fucking fucked beyond belief ... Don't even give the
- * generic PCI code a chance to look at the wrong register.
+ * IOC3 special handling
*/
if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) {
*value = emulate_ioc3_cfg(where, size);
return PCIBIOS_SUCCESSFUL;
}
- /*
- * IOC3 is fucking fucked beyond belief ... Don't try to access
- * anything but 32-bit words ...
- */
- bridge->b_pci_cfg = (busno << 16) | (slot << 11);
+ bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
addr = &bridge->b_type1_cfg.c[(fn << 8) | where];
if (get_dbe(cf, (u32 *) addr))
@@ -177,7 +167,7 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 value)
{
struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
- bridge_t *bridge = bc->base;
+ struct bridge_regs *bridge = bc->base;
int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn);
volatile void *addr;
@@ -189,11 +179,11 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_DEVICE_NOT_FOUND;
/*
- * IOC3 is fucking fucked beyond belief ... Don't even give the
+ * IOC3 is broken beyond belief ... Don't even give the
* generic PCI code a chance to look at it for real ...
*/
if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
- goto oh_my_gawd;
+ goto is_ioc3;
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
@@ -210,19 +200,14 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_SUCCESSFUL;
-oh_my_gawd:
+is_ioc3:
/*
- * IOC3 is fucking fucked beyond belief ... Don't even give the
- * generic PCI code a chance to touch the wrong register.
+ * IOC3 special handling
*/
if ((where >= 0x14 && where < 0x40) || (where >= 0x48))
return PCIBIOS_SUCCESSFUL;
- /*
- * IOC3 is fucking fucked beyond belief ... Don't try to access
- * anything but 32-bit words ...
- */
addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
if (get_dbe(cf, (u32 *) addr))
@@ -243,7 +228,7 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 value)
{
struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
- bridge_t *bridge = bc->base;
+ struct bridge_regs *bridge = bc->base;
int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn);
int busno = bus->number;
@@ -251,17 +236,17 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
u32 cf, shift, mask, smask;
int res;
- bridge->b_pci_cfg = (busno << 16) | (slot << 11);
+ bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
if (get_dbe(cf, (u32 *) addr))
return PCIBIOS_DEVICE_NOT_FOUND;
/*
- * IOC3 is fucking fucked beyond belief ... Don't even give the
+ * IOC3 is broken beyond belief ... Don't even give the
* generic PCI code a chance to look at it for real ...
*/
if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
- goto oh_my_gawd;
+ goto is_ioc3;
addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
@@ -278,19 +263,14 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_SUCCESSFUL;
-oh_my_gawd:
+is_ioc3:
/*
- * IOC3 is fucking fucked beyond belief ... Don't even give the
- * generic PCI code a chance to touch the wrong register.
+ * IOC3 special handling
*/
if ((where >= 0x14 && where < 0x40) || (where >= 0x48))
return PCIBIOS_SUCCESSFUL;
- /*
- * IOC3 is fucking fucked beyond belief ... Don't try to access
- * anything but 32-bit words ...
- */
addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
if (get_dbe(cf, (u32 *) addr))
diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c
index c94a66070a60..7cf50290a6d9 100644
--- a/arch/mips/pci/pci-ip27.c
+++ b/arch/mips/pci/pci-ip27.c
@@ -47,7 +47,6 @@ int bridge_probe(nasid_t nasid, int widget_id, int masterwid)
unsigned long offset = NODE_OFFSET(nasid);
struct bridge_controller *bc;
static int num_bridges = 0;
- bridge_t *bridge;
int slot;
pci_set_flags(PCI_PROBE_ONLY);
@@ -87,45 +86,43 @@ int bridge_probe(nasid_t nasid, int widget_id, int masterwid)
/*
* point to this bridge
*/
- bridge = (bridge_t *) RAW_NODE_SWIN_BASE(nasid, widget_id);
+ bc->base = (struct bridge_regs *)RAW_NODE_SWIN_BASE(nasid, widget_id);
/*
* Clear all pending interrupts.
*/
- bridge->b_int_rst_stat = BRIDGE_IRR_ALL_CLR;
+ bridge_write(bc, b_int_rst_stat, BRIDGE_IRR_ALL_CLR);
/*
* Until otherwise set up, assume all interrupts are from slot 0
*/
- bridge->b_int_device = 0x0;
+ bridge_write(bc, b_int_device, 0x0);
/*
* swap pio's to pci mem and io space (big windows)
*/
- bridge->b_wid_control |= BRIDGE_CTRL_IO_SWAP |
- BRIDGE_CTRL_MEM_SWAP;
+ bridge_set(bc, b_wid_control, BRIDGE_CTRL_IO_SWAP |
+ BRIDGE_CTRL_MEM_SWAP);
#ifdef CONFIG_PAGE_SIZE_4KB
- bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE;
+ bridge_clr(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
#else /* 16kB or larger */
- bridge->b_wid_control |= BRIDGE_CTRL_PAGE_SIZE;
+ bridge_set(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
#endif
/*
* Hmm... IRIX sets additional bits in the address which
* are documented as reserved in the bridge docs.
*/
- bridge->b_wid_int_upper = 0x8000 | (masterwid << 16);
- bridge->b_wid_int_lower = 0x01800090; /* PI_INT_PEND_MOD off*/
- bridge->b_dir_map = (masterwid << 20); /* DMA */
- bridge->b_int_enable = 0;
+ bridge_write(bc, b_wid_int_upper, 0x8000 | (masterwid << 16));
+ bridge_write(bc, b_wid_int_lower, 0x01800090); /* PI_INT_PEND_MOD off*/
+ bridge_write(bc, b_dir_map, (masterwid << 20)); /* DMA */
+ bridge_write(bc, b_int_enable, 0);
for (slot = 0; slot < 8; slot ++) {
- bridge->b_device[slot].reg |= BRIDGE_DEV_SWAP_DIR;
+ bridge_set(bc, b_device[slot].reg, BRIDGE_DEV_SWAP_DIR);
bc->pci_int[slot] = -1;
}
- bridge->b_wid_tflush; /* wait until Bridge PIO complete */
-
- bc->base = bridge;
+ bridge_read(bc, b_wid_tflush); /* wait until Bridge PIO complete */
register_pci_controller(&bc->pc);
@@ -206,7 +203,7 @@ phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t dma_addr)
static inline void pci_disable_swapping(struct pci_dev *dev)
{
struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
- bridge_t *bridge = bc->base;
+ struct bridge_regs *bridge = bc->base;
int slot = PCI_SLOT(dev->devfn);
/* Turn off byte swapping */
diff --git a/arch/mips/sgi-ip27/ip27-irq-pci.c b/arch/mips/sgi-ip27/ip27-irq-pci.c
index cd449e90b917..a00a23b32a2a 100644
--- a/arch/mips/sgi-ip27/ip27-irq-pci.c
+++ b/arch/mips/sgi-ip27/ip27-irq-pci.c
@@ -136,14 +136,12 @@ static int intr_disconnect_level(int cpu, int bit)
static unsigned int startup_bridge_irq(struct irq_data *d)
{
struct bridge_controller *bc;
- bridgereg_t device;
- bridge_t *bridge;
int pin, swlevel;
cpuid_t cpu;
+ u64 device;
pin = SLOT_FROM_PCI_IRQ(d->irq);
bc = IRQ_TO_BRIDGE(d->irq);
- bridge = bc->base;
pr_debug("bridge_startup(): irq= 0x%x pin=%d\n", d->irq, pin);
/*
@@ -151,9 +149,10 @@ static unsigned int startup_bridge_irq(struct irq_data *d)
* of INT_PEND0 are taken
*/
swlevel = find_level(&cpu, d->irq);
- bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (bc->nasid << 8));
- bridge->b_int_enable |= (1 << pin);
- bridge->b_int_enable |= 0x7ffffe00; /* more stuff in int_enable */
+ bridge_write(bc, b_int_addr[pin].addr,
+ (0x20000 | swlevel | (bc->nasid << 8)));
+ bridge_set(bc, b_int_enable, (1 << pin));
+ bridge_set(bc, b_int_enable, 0x7ffffe00); /* more stuff in int_enable */
/*
* Enable sending of an interrupt clear packt to the hub on a high to
@@ -162,18 +161,18 @@ static unsigned int startup_bridge_irq(struct irq_data *d)
* IRIX sets additional bits in the address which are documented as
* reserved in the bridge docs.
*/
- bridge->b_int_mode |= (1UL << pin);
+ bridge_set(bc, b_int_mode, (1UL << pin));
/*
* We assume the bridge to have a 1:1 mapping between devices
* (slots) and intr pins.
*/
- device = bridge->b_int_device;
+ device = bridge_read(bc, b_int_device);
device &= ~(7 << (pin*3));
device |= (pin << (pin*3));
- bridge->b_int_device = device;
+ bridge_write(bc, b_int_device, device);
- bridge->b_wid_tflush;
+ bridge_read(bc, b_wid_tflush);
intr_connect_level(cpu, swlevel);
@@ -184,7 +183,6 @@ static unsigned int startup_bridge_irq(struct irq_data *d)
static void shutdown_bridge_irq(struct irq_data *d)
{
struct bridge_controller *bc = IRQ_TO_BRIDGE(d->irq);
- bridge_t *bridge = bc->base;
int pin, swlevel;
cpuid_t cpu;
@@ -198,8 +196,8 @@ static void shutdown_bridge_irq(struct irq_data *d)
swlevel = find_level(&cpu, d->irq);
intr_disconnect_level(cpu, swlevel);
- bridge->b_int_enable &= ~(1 << pin);
- bridge->b_wid_tflush;
+ bridge_clr(bc, b_int_enable, (1 << pin));
+ bridge_read(bc, b_wid_tflush);
}
static inline void enable_bridge_irq(struct irq_data *d)
--
2.13.7
To make use of per_cpu variables in interrupt code per_cpu_init() must
be done after setup_per_cpu_areas(). This is achieved by calling it
in smp_prepare_boot_cpu() via a new smp_ops method.
Signed-off-by: Thomas Bogendoerfer <[email protected]>
---
arch/mips/include/asm/smp-ops.h | 1 +
arch/mips/kernel/smp.c | 2 ++
arch/mips/sgi-ip27/ip27-init.c | 1 -
arch/mips/sgi-ip27/ip27-smp.c | 5 +++--
4 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/arch/mips/include/asm/smp-ops.h b/arch/mips/include/asm/smp-ops.h
index b7123f9c0785..65618ff1280c 100644
--- a/arch/mips/include/asm/smp-ops.h
+++ b/arch/mips/include/asm/smp-ops.h
@@ -29,6 +29,7 @@ struct plat_smp_ops {
int (*boot_secondary)(int cpu, struct task_struct *idle);
void (*smp_setup)(void);
void (*prepare_cpus)(unsigned int max_cpus);
+ void (*prepare_boot_cpu)(void);
#ifdef CONFIG_HOTPLUG_CPU
int (*cpu_disable)(void);
void (*cpu_die)(unsigned int cpu);
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index d84b9066b465..3da3ef9a5d5f 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -443,6 +443,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
/* preload SMP state for boot cpu */
void smp_prepare_boot_cpu(void)
{
+ if (mp_ops->prepare_boot_cpu)
+ mp_ops->prepare_boot_cpu();
set_cpu_possible(0, true);
set_cpu_online(0, true);
}
diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c
index aba985cf07c0..e6fa9d0c708a 100644
--- a/arch/mips/sgi-ip27/ip27-init.c
+++ b/arch/mips/sgi-ip27/ip27-init.c
@@ -212,7 +212,6 @@ void __init plat_mem_setup(void)
#endif
ioc3_eth_init();
- per_cpu_init();
set_io_port_base(IO_BASE);
}
diff --git a/arch/mips/sgi-ip27/ip27-smp.c b/arch/mips/sgi-ip27/ip27-smp.c
index 545446dfe7fa..20b81209c6b8 100644
--- a/arch/mips/sgi-ip27/ip27-smp.c
+++ b/arch/mips/sgi-ip27/ip27-smp.c
@@ -177,7 +177,7 @@ static void ip27_send_ipi_mask(const struct cpumask *mask, unsigned int action)
ip27_send_ipi_single(i, action);
}
-static void ip27_init_secondary(void)
+static void ip27_init_cpu(void)
{
per_cpu_init();
}
@@ -235,9 +235,10 @@ static void __init ip27_prepare_cpus(unsigned int max_cpus)
const struct plat_smp_ops ip27_smp_ops = {
.send_ipi_single = ip27_send_ipi_single,
.send_ipi_mask = ip27_send_ipi_mask,
- .init_secondary = ip27_init_secondary,
+ .init_secondary = ip27_init_cpu,
.smp_finish = ip27_smp_finish,
.boot_secondary = ip27_boot_secondary,
.smp_setup = ip27_smp_setup,
.prepare_cpus = ip27_prepare_cpus,
+ .prepare_boot_cpu = ip27_init_cpu,
};
--
2.13.7
Topology and NMI output needs pr_cont() to look the way it was in the
old days of printk.
Signed-off-by: Thomas Bogendoerfer <[email protected]>
---
arch/mips/sgi-ip27/ip27-memory.c | 28 +++++++++---------
arch/mips/sgi-ip27/ip27-nmi.c | 62 ++++++++++++++++++++--------------------
2 files changed, 45 insertions(+), 45 deletions(-)
diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c
index 87ef4181934e..fb077a947575 100644
--- a/arch/mips/sgi-ip27/ip27-memory.c
+++ b/arch/mips/sgi-ip27/ip27-memory.c
@@ -154,11 +154,11 @@ static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b)
}
if (router_a == NULL) {
- printk("node_distance: router_a NULL\n");
+ pr_info("node_distance: router_a NULL\n");
return -1;
}
if (router_b == NULL) {
- printk("node_distance: router_b NULL\n");
+ pr_info("node_distance: router_b NULL\n");
return -1;
}
@@ -203,17 +203,17 @@ static void __init dump_topology(void)
klrou_t *router;
cnodeid_t row, col;
- printk("************** Topology ********************\n");
+ pr_info("************** Topology ********************\n");
- printk(" ");
+ pr_info(" ");
for_each_online_node(col)
- printk("%02d ", col);
- printk("\n");
+ pr_cont("%02d ", col);
+ pr_cont("\n");
for_each_online_node(row) {
- printk("%02d ", row);
+ pr_info("%02d ", row);
for_each_online_node(col)
- printk("%2d ", node_distance(row, col));
- printk("\n");
+ pr_cont("%2d ", node_distance(row, col));
+ pr_cont("\n");
}
for_each_online_node(cnode) {
@@ -230,7 +230,7 @@ static void __init dump_topology(void)
do {
if (brd->brd_flags & DUPLICATE_BOARD)
continue;
- printk("Router %d:", router_num);
+ pr_cont("Router %d:", router_num);
router_num++;
router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
@@ -244,11 +244,11 @@ static void __init dump_topology(void)
router->rou_port[port].port_offset);
if (dest_brd->brd_type == KLTYPE_IP27)
- printk(" %d", dest_brd->brd_nasid);
+ pr_cont(" %d", dest_brd->brd_nasid);
if (dest_brd->brd_type == KLTYPE_ROUTER)
- printk(" r");
+ pr_cont(" r");
}
- printk("\n");
+ pr_cont("\n");
} while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
}
@@ -373,7 +373,7 @@ static void __init szmem(void)
if ((nodebytes >> PAGE_SHIFT) * (sizeof(struct page)) >
(slot0sz << PAGE_SHIFT)) {
- printk("Ignoring slot %d onwards on node %d\n",
+ pr_info("Ignoring slot %d onwards on node %d\n",
slot, node);
slot = MAX_MEM_SLOTS;
continue;
diff --git a/arch/mips/sgi-ip27/ip27-nmi.c b/arch/mips/sgi-ip27/ip27-nmi.c
index 8cb3a5d6d7d1..3aae388561d9 100644
--- a/arch/mips/sgi-ip27/ip27-nmi.c
+++ b/arch/mips/sgi-ip27/ip27-nmi.c
@@ -62,70 +62,70 @@ void nmi_cpu_eframe_save(nasid_t nasid, int slice)
(TO_UNCAC(TO_NODE(nasid, IP27_NMI_KREGS_OFFSET)) +
slice * IP27_NMI_KREGS_CPU_SIZE);
- printk("NMI nasid %d: slice %d\n", nasid, slice);
+ pr_emerg("NMI nasid %d: slice %d\n", nasid, slice);
/*
* Saved main processor registers
*/
for (i = 0; i < 32; ) {
if ((i % 4) == 0)
- printk("$%2d :", i);
- printk(" %016lx", nr->gpr[i]);
+ pr_emerg("$%2d :", i);
+ pr_cont(" %016lx", nr->gpr[i]);
i++;
if ((i % 4) == 0)
- printk("\n");
+ pr_cont("\n");
}
- printk("Hi : (value lost)\n");
- printk("Lo : (value lost)\n");
+ pr_emerg("Hi : (value lost)\n");
+ pr_emerg("Lo : (value lost)\n");
/*
* Saved cp0 registers
*/
- printk("epc : %016lx %pS\n", nr->epc, (void *) nr->epc);
- printk("%s\n", print_tainted());
- printk("ErrEPC: %016lx %pS\n", nr->error_epc, (void *) nr->error_epc);
- printk("ra : %016lx %pS\n", nr->gpr[31], (void *) nr->gpr[31]);
- printk("Status: %08lx ", nr->sr);
+ pr_emerg("epc : %016lx %pS\n", nr->epc, (void *)nr->epc);
+ pr_emerg("%s\n", print_tainted());
+ pr_emerg("ErrEPC: %016lx %pS\n", nr->error_epc, (void *)nr->error_epc);
+ pr_emerg("ra : %016lx %pS\n", nr->gpr[31], (void *)nr->gpr[31]);
+ pr_emerg("Status: %08lx ", nr->sr);
if (nr->sr & ST0_KX)
- printk("KX ");
+ pr_cont("KX ");
if (nr->sr & ST0_SX)
- printk("SX ");
+ pr_cont("SX ");
if (nr->sr & ST0_UX)
- printk("UX ");
+ pr_cont("UX ");
switch (nr->sr & ST0_KSU) {
case KSU_USER:
- printk("USER ");
+ pr_cont("USER ");
break;
case KSU_SUPERVISOR:
- printk("SUPERVISOR ");
+ pr_cont("SUPERVISOR ");
break;
case KSU_KERNEL:
- printk("KERNEL ");
+ pr_cont("KERNEL ");
break;
default:
- printk("BAD_MODE ");
+ pr_cont("BAD_MODE ");
break;
}
if (nr->sr & ST0_ERL)
- printk("ERL ");
+ pr_cont("ERL ");
if (nr->sr & ST0_EXL)
- printk("EXL ");
+ pr_cont("EXL ");
if (nr->sr & ST0_IE)
- printk("IE ");
- printk("\n");
+ pr_cont("IE ");
+ pr_cont("\n");
- printk("Cause : %08lx\n", nr->cause);
- printk("PrId : %08x\n", read_c0_prid());
- printk("BadVA : %016lx\n", nr->badva);
- printk("CErr : %016lx\n", nr->cache_err);
- printk("NMI_SR: %016lx\n", nr->nmi_sr);
+ pr_emerg("Cause : %08lx\n", nr->cause);
+ pr_emerg("PrId : %08x\n", read_c0_prid());
+ pr_emerg("BadVA : %016lx\n", nr->badva);
+ pr_emerg("CErr : %016lx\n", nr->cache_err);
+ pr_emerg("NMI_SR: %016lx\n", nr->nmi_sr);
- printk("\n");
+ pr_emerg("\n");
}
void nmi_dump_hub_irq(nasid_t nasid, int slice)
@@ -143,9 +143,9 @@ void nmi_dump_hub_irq(nasid_t nasid, int slice)
pend0 = REMOTE_HUB_L(nasid, PI_INT_PEND0);
pend1 = REMOTE_HUB_L(nasid, PI_INT_PEND1);
- printk("PI_INT_MASK0: %16Lx PI_INT_MASK1: %16Lx\n", mask0, mask1);
- printk("PI_INT_PEND0: %16Lx PI_INT_PEND1: %16Lx\n", pend0, pend1);
- printk("\n\n");
+ pr_emerg("PI_INT_MASK0: %16llx PI_INT_MASK1: %16llx\n", mask0, mask1);
+ pr_emerg("PI_INT_PEND0: %16llx PI_INT_PEND1: %16llx\n", pend0, pend1);
+ pr_emerg("\n\n");
}
/*
--
2.13.7
On Tue, 19 Feb 2019 16:57:23 +0100
Thomas Bogendoerfer <[email protected]> wrote:
Hi Thomas,
> When creating hierarchy domains use irq_default_domain as parent, if no
> parent was given by the caller. This avoids adding helper code for
> querying the underlying platform irq domain.
>
> Signed-off-by: Thomas Bogendoerfer <[email protected]>
> ---
> kernel/irq/irqdomain.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
> index 8b0be4bd6565..617c482d0778 100644
> --- a/kernel/irq/irqdomain.c
> +++ b/kernel/irq/irqdomain.c
> @@ -1021,7 +1021,10 @@ struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent,
> else
> domain = irq_domain_create_tree(fwnode, ops, host_data);
> if (domain) {
> - domain->parent = parent;
> + if (parent)
> + domain->parent = parent;
> + else
> + domain->parent = irq_default_domain;
> domain->flags |= flags;
> }
>
I'm really not keen on this. The whole "default domain" made sense at a
distant point in time (when irqdomains were new and platform code was
blissfully ignoring it), but it really looks like a sore spot in the
hierarchy code, which assumes that you always know what you're building
your hierarchy on top of.
It also create a small issue in the sense that you can create a root
domain using irq_domain_create_hierarchy() by passing NULL as the
parent. With this patch, the new domain now points to the default one,
with unexpected consequences.
So let's come back to first principles: How comes you can't obtain the
parent domain at creation time? Because I'd rather give you a way to
retrieve it instead if this.
M. (who wish he had an IP27!)
--
Without deviation from the norm, progress is not possible.
On Tue, 19 Feb 2019 16:27:16 +0000
Marc Zyngier <[email protected]> wrote:
> On Tue, 19 Feb 2019 16:57:23 +0100
> Thomas Bogendoerfer <[email protected]> wrote:
>
> Hi Thomas,
>
> > When creating hierarchy domains use irq_default_domain as parent, if no
> > parent was given by the caller. This avoids adding helper code for
> > querying the underlying platform irq domain.
> >
> > Signed-off-by: Thomas Bogendoerfer <[email protected]>
> > ---
> > kernel/irq/irqdomain.c | 5 ++++-
> > 1 file changed, 4 insertions(+), 1 deletion(-)
> >
> > diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
> > index 8b0be4bd6565..617c482d0778 100644
> > --- a/kernel/irq/irqdomain.c
> > +++ b/kernel/irq/irqdomain.c
> > @@ -1021,7 +1021,10 @@ struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent,
> > else
> > domain = irq_domain_create_tree(fwnode, ops, host_data);
> > if (domain) {
> > - domain->parent = parent;
> > + if (parent)
> > + domain->parent = parent;
> > + else
> > + domain->parent = irq_default_domain;
> > domain->flags |= flags;
> > }
> >
>
> I'm really not keen on this. The whole "default domain" made sense at a
> distant point in time (when irqdomains were new and platform code was
> blissfully ignoring it), but it really looks like a sore spot in the
> hierarchy code, which assumes that you always know what you're building
> your hierarchy on top of.
>
> It also create a small issue in the sense that you can create a root
> domain using irq_domain_create_hierarchy() by passing NULL as the
> parent. With this patch, the new domain now points to the default one,
> with unexpected consequences.
>
> So let's come back to first principles: How comes you can't obtain the
> parent domain at creation time? Because I'd rather give you a way to
> retrieve it instead if this.
the bridge irq domain could be stacked on different underlying irq domains
for different platforms (HUB is IP27, HEART for IP30 and BEDROCK for IP35).
And my idea was to set a irq default domain in the IP27/IP30/IP35 platform
code so that bridge code will pick up the correct underlying irq domain.
As there is no device tree I haven't found an already implemented other way.
Right now I have two idea to solve my problem without this patch:
- implement a SGI specific helper for getting the underlying irq domain
- use a helper function to read irq_default_domain
What do you prefer ? Or do you see something else ?
Thomas.
--
SUSE Linux GmbH
GF: Felix Imend?rffer, Jane Smithard, Graham Norton
HRB 21284 (AG N?rnberg)
On Tue, 19 Feb 2019 17:48:29 +0100
Thomas Bogendoerfer <[email protected]> wrote:
> On Tue, 19 Feb 2019 16:27:16 +0000
> Marc Zyngier <[email protected]> wrote:
>
> > On Tue, 19 Feb 2019 16:57:23 +0100
> > Thomas Bogendoerfer <[email protected]> wrote:
> >
> > Hi Thomas,
> >
> > > When creating hierarchy domains use irq_default_domain as parent, if no
> > > parent was given by the caller. This avoids adding helper code for
> > > querying the underlying platform irq domain.
> > >
> > > Signed-off-by: Thomas Bogendoerfer <[email protected]>
> > > ---
> > > kernel/irq/irqdomain.c | 5 ++++-
> > > 1 file changed, 4 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
> > > index 8b0be4bd6565..617c482d0778 100644
> > > --- a/kernel/irq/irqdomain.c
> > > +++ b/kernel/irq/irqdomain.c
> > > @@ -1021,7 +1021,10 @@ struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent,
> > > else
> > > domain = irq_domain_create_tree(fwnode, ops, host_data);
> > > if (domain) {
> > > - domain->parent = parent;
> > > + if (parent)
> > > + domain->parent = parent;
> > > + else
> > > + domain->parent = irq_default_domain;
> > > domain->flags |= flags;
> > > }
> > >
> >
> > I'm really not keen on this. The whole "default domain" made sense at a
> > distant point in time (when irqdomains were new and platform code was
> > blissfully ignoring it), but it really looks like a sore spot in the
> > hierarchy code, which assumes that you always know what you're building
> > your hierarchy on top of.
> >
> > It also create a small issue in the sense that you can create a root
> > domain using irq_domain_create_hierarchy() by passing NULL as the
> > parent. With this patch, the new domain now points to the default one,
> > with unexpected consequences.
> >
> > So let's come back to first principles: How comes you can't obtain the
> > parent domain at creation time? Because I'd rather give you a way to
> > retrieve it instead if this.
>
> the bridge irq domain could be stacked on different underlying irq domains
> for different platforms (HUB is IP27, HEART for IP30 and BEDROCK for IP35).
> And my idea was to set a irq default domain in the IP27/IP30/IP35 platform
> code so that bridge code will pick up the correct underlying irq domain.
> As there is no device tree I haven't found an already implemented other way.
Ah, right. We have ways to solve this kind of problem without DT
(cough... ACPI cough...), but this requires the bridge code to at least
know *something* about the underlying domain (see the use of struct
fwnode in the ACPI IORT code, and the way it uses the routing
informations to build and retrieve fwnodes that are used to match
irq domains).
Do you have such firmware tables that could be used to store sideband
data and allow the bridge code to retrieve the corresponding pointer? I
appreciate this could be quite a lot of work for a platform that has
little future...
> Right now I have two idea to solve my problem without this patch:
>
> - implement a SGI specific helper for getting the underlying irq domain
> - use a helper function to read irq_default_domain
>
> What do you prefer ? Or do you see something else ?
Well, short of doing the above, I'd rather have something in the common
code that allows the default domain to be retrieved. How about the
patch below?
Thanks,
M.
From 3a9e44941c203ef2ed659838f218a0203c963828 Mon Sep 17 00:00:00 2001
From: Marc Zyngier <[email protected]>
Date: Wed, 20 Feb 2019 08:59:23 +0000
Subject: [PATCH] irqdomain: Allow the default irq domain to be retrieved
The default irq domain allows legacy code to create irqdomain
mappings without having to track the domain it is allocating
from. Setting the default domain is a one shot, fire and forget
operation, and no effort was made to be able to retrieve this
information at a later point in time.
Newer irqdomain APIs (the hierarchical stuff) relies on both
the irqchip code to track the irqdomain it is allocating from,
as well as some form of firmware abstraction to easily identify
which piece of HW maps to which irq domain (DT, ACPI).
For systems without such firmware (or legacy platform that are
getting dragged into the 21st century), things are a bit harder.
For these cases (and these cases only!), let's provide a way
to retrieve the default domain, allowing the use of the v2 API
without having to resort to platform-specific hacks.
Signed-off-by: Marc Zyngier <[email protected]>
---
include/linux/irqdomain.h | 1 +
kernel/irq/irqdomain.c | 14 ++++++++++++++
2 files changed, 15 insertions(+)
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 35965f41d7be..d2130dc7c0e6 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -265,6 +265,7 @@ extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token);
extern bool irq_domain_check_msi_remap(void);
extern void irq_set_default_host(struct irq_domain *host);
+extern struct irq_domain *irq_get_default_host(void);
extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs,
irq_hw_number_t hwirq, int node,
const struct irq_affinity_desc *affinity);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 8b0be4bd6565..80818764643d 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -458,6 +458,20 @@ void irq_set_default_host(struct irq_domain *domain)
}
EXPORT_SYMBOL_GPL(irq_set_default_host);
+/**
+ * irq_get_default_host() - Retrieve the "default" irq domain
+ *
+ * Returns: the default domain, if any.
+ *
+ * Modern code should never use this. This should only be used on
+ * systems that cannot implement a firmware->fwnode mapping (which
+ * both DT and ACPI provide).
+ */
+struct irq_domain *irq_get_default_host(void)
+{
+ return irq_default_domain;
+}
+
static void irq_domain_clear_mapping(struct irq_domain *domain,
irq_hw_number_t hwirq)
{
--
2.20.1
--
Without deviation from the norm, progress is not possible.
On Wed, 20 Feb 2019 09:15:37 +0000
Marc Zyngier <[email protected]> wrote:
> Well, short of doing the above, I'd rather have something in the common
> code that allows the default domain to be retrieved. How about the
> patch below?
Works for me:-) Thank you.
Are you going to submit it for v5.1 ?
Thomas.
--
SUSE Linux GmbH
GF: Felix Imend?rffer, Jane Smithard, Graham Norton
HRB 21284 (AG N?rnberg)
On Wed, 20 Feb 2019 16:00:15 +0100
Thomas Bogendoerfer <[email protected]> wrote:
> On Wed, 20 Feb 2019 09:15:37 +0000
> Marc Zyngier <[email protected]> wrote:
>
> > Well, short of doing the above, I'd rather have something in the common
> > code that allows the default domain to be retrieved. How about the
> > patch below?
>
> Works for me:-) Thank you.
>
> Are you going to submit it for v5.1 ?
Yup, now queued. I plan to send a PR tomorrow (still waiting on a few
dangling patches).
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
Hi Thomas,
On Tue, Feb 19, 2019 at 04:57:14PM +0100, Thomas Bogendoerfer wrote:
> SGI IP27 (Origin/Onyx2) and SGI IP30 (Octane) have a similair
> architecture and share some hardware (ioc3/bridge). To share
> the software parts this patchset reworks SGI IP27 interrupt
> and pci bridge code. By using features Linux gained during the
> many years since SGI IP27 code was integrated this even results
> in code reduction and IMHO cleaner code.
>
> Tests have been done on a two module O200 (4 CPUs) and an
> Origin 2000 (8 CPUs).
>
> My next step in integrating SGI IP30 support is splitting ioc3eth
> into a MFD and subdevice drivers. Prototype is working, but needs
> still more clean ups.
>
> Changes in v2:
>
> - replaced HUB_L/HUB_S by __raw_readq/__raw_writeq
> - removed union bridge_ate
> - replaced remaing fields in slice_data by per_cpu data
> - use generic_handle_irq instead of do_IRQ
> - use hierarchy irq domain for stacking bridge and hub interrupt
> - moved __dma_to_phys/__phy_to_dma to mach-ip27/dma-direct.h
> - use dev_to_node() for pcibus_to_node() implementation
>
> Thomas Bogendoerfer (10):
> MIPS: SGI-IP27: get rid of volatile and hubreg_t
> MIPS: SGI-IP27: clean up bridge access and header files
> MIPS: SGI-IP27: use pr_info/pr_emerg and pr_cont to fix output
> MIPS: SGI-IP27: do xtalk scanning later
> MIPS: SGI-IP27: do boot CPU init later
> MIPS: SGI-IP27: rework HUB interrupts
> PCI: call add_bus method also for root bus
> MIPS: SGI-IP27: use generic PCI driver
> genirq/irqdomain: fall back to default domain when creating hierarchy
> domain
> MIPS: SGI-IP27: abstract chipset irq from bridge
I have patches 1-6 applied locally - would you be happy for those to be
pushed to mips-next without 7-10? I know ip27_defconfig still builds but
have no idea whether it still works :)
I don't appear to have received patches 7 or 9 but I see from archives
there'll be a v3 of patch 9 at least.
So I can either apply 1-6 for v5.1 or defer the whole series. Let me
know - I'm happy either way.
Thanks,
Paul
Hi Thomas,
On Tue, Feb 19, 2019 at 04:57:21PM +0100, Thomas Bogendoerfer wrote:
> pci-xtalk controller code uses the add_bus method to set node of
> the bus device, which then is used for pcibus_to_node() implementation.
>
> Signed-off-by: Thomas Bogendoerfer <[email protected]>
> ---
> drivers/pci/probe.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index 257b9f6f2ebb..456448d5f46d 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -837,6 +837,12 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
>
> pcibios_add_bus(bus);
>
> + if (bus->ops->add_bus) {
> + err = bus->ops->add_bus(bus);
> + if (WARN_ON(err < 0))
> + dev_err(&bus->dev, "failed to add bus: %d\n", err);
> + }
Is there something special about pci-xtalk that prevents it from
setting the node the way other platforms do, without using the
add_bus() method?
I haven't researched the details of how other platforms do it, but if
it would be possible for pci-xtalk to do it the same way, that would
be ideal.
> /* Create legacy_io and legacy_mem files for this bus */
> pci_create_legacy_files(bus);
>
> --
> 2.13.7
>
On Thu, 21 Feb 2019 20:50:39 +0000
Paul Burton <[email protected]> wrote:
> I don't appear to have received patches 7 or 9 but I see from archives
> there'll be a v3 of patch 9 at least.
I'm still fighting with git send-email to do proper collecting of addresses...
And the mails to your @mips.com address bounced yesterday.
> So I can either apply 1-6 for v5.1 or defer the whole series. Let me
> know - I'm happy either way.
All changes will happen in patches 7-10, so appreciate, if you could apply 1-6 :-)
Thank you,
Thomas.
--
SUSE Linux GmbH
GF: Felix Imend?rffer, Jane Smithard, Graham Norton
HRB 21284 (AG N?rnberg)
> diff --git a/arch/mips/include/asm/dma-direct.h b/arch/mips/include/asm/dma-direct.h
> index b5c240806e1b..bd11e7934df1 100644
> --- a/arch/mips/include/asm/dma-direct.h
> +++ b/arch/mips/include/asm/dma-direct.h
> @@ -2,6 +2,8 @@
> #ifndef _MIPS_DMA_DIRECT_H
> #define _MIPS_DMA_DIRECT_H 1
>
> +#include <dma-direct.h>
> +
> static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
> {
> if (!dev->dma_mask)
How is your mach dma-direct.h scheme going to work, given that
we already have non-inline declarations of __phys_to_dma / __dma_to_phys
in this file?
Also this really should go into a separate commit, and we should either
have all of these functions inline or none. Having all of them out
of line seemed a lot saner to me to avoid all the mach header mess.
Also there seem to be a lot of randomw whitespace / brace cleanups
in this patch. Shouldn't those be split out as well?
On Fri, Feb 22, 2019 at 09:14:18AM +0100, Thomas Bogendoerfer wrote:
>
> I'm still fighting with git send-email to do proper collecting of addresses...
> And the mails to your @mips.com address bounced yesterday.
FYI, it also bounced for me yesterday (or the day before, depending on
the time zone).
On Thu, Feb 21, 2019 at 05:37:08PM -0600, Bjorn Helgaas wrote:
> On Tue, Feb 19, 2019 at 04:57:21PM +0100, Thomas Bogendoerfer wrote:
> > pci-xtalk controller code uses the add_bus method to set node of
> > the bus device, which then is used for pcibus_to_node() implementation.
> >
> > Signed-off-by: Thomas Bogendoerfer <[email protected]>
> > ---
> > drivers/pci/probe.c | 6 ++++++
> > 1 file changed, 6 insertions(+)
> >
> > diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> > index 257b9f6f2ebb..456448d5f46d 100644
> > --- a/drivers/pci/probe.c
> > +++ b/drivers/pci/probe.c
> > @@ -837,6 +837,12 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
> >
> > pcibios_add_bus(bus);
> >
> > + if (bus->ops->add_bus) {
> > + err = bus->ops->add_bus(bus);
> > + if (WARN_ON(err < 0))
> > + dev_err(&bus->dev, "failed to add bus: %d\n", err);
> > + }
>
> Is there something special about pci-xtalk that prevents it from
> setting the node the way other platforms do, without using the
> add_bus() method?
x86: uses node in common struct pci_sysdata
ia64: uses node in common struct pci_controller
powerpc: uses node in common struct pci_controller
sparc: uses numa_node in common struct pci_pbm_info
arm64: uses dev_to_node(&bus->dev) and node is set via pcibios_add_bus()
MIPS right now has no common struct, which is reachable via bus->sysdata,
if CONFIG_PCI_DRIVERS_LEGACY is not selected (and I want to get away
with that option). So I liked the arm64 way, but I didn't want to implement
pcibios_add_bus just for SGI-IP27 and noticed, that pcibios_add_bus
is called for child and root bus, while add_bus method only for
child buses. So my patch gives add_bus the same power as pcibios_add_bus
already have. Is this good enough as argument ?
> I haven't researched the details of how other platforms do it, but if
> it would be possible for pci-xtalk to do it the same way, that would
> be ideal.
there is always a different way of course. If you don't like my patch
I'll find one ;-)
Thomas.
--
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea. [ RFC1925, 2.3 ]
Hello,
Thomas Bogendoerfer wrote:
> Introduced bridge_read/bridge_write/bridge_set/bridge_clr for accessing
> bridge register and get rid of volatile declarations. Also removed
> all typedefs from arch/mips/include/asm/pci/bridge.h and cleaned up
> language in arch/mips/pci/ops-bridge.c
>
> Signed-off-by: Thomas Bogendoerfer <[email protected]>
Applied to mips-next.
Thanks,
Paul
[ This message was auto-generated; if you believe anything is incorrect
then please email [email protected] to report it. ]
Hello,
Thomas Bogendoerfer wrote:
> Move xtalk scanning to a later boot stage to be able using things like
> kmalloc and friends.
>
> Signed-off-by: Thomas Bogendoerfer <[email protected]>
Applied to mips-next.
Thanks,
Paul
[ This message was auto-generated; if you believe anything is incorrect
then please email [email protected] to report it. ]
Hello,
Thomas Bogendoerfer wrote:
> This commit rearranges the HUB interrupt code by using MIPS_IRQ_CPU
> interrupt handling code and modern Linux IRQ framework features to get
> rid of global arrays. It also adds support for irq affinity setting.
>
> Signed-off-by: Thomas Bogendoerfer <[email protected]>
Applied to mips-next.
Thanks,
Paul
[ This message was auto-generated; if you believe anything is incorrect
then please email [email protected] to report it. ]
Hello,
Thomas Bogendoerfer wrote:
> Topology and NMI output needs pr_cont() to look the way it was in the
> old days of printk.
>
> Signed-off-by: Thomas Bogendoerfer <[email protected]>
Applied to mips-next.
Thanks,
Paul
[ This message was auto-generated; if you believe anything is incorrect
then please email [email protected] to report it. ]
Hello,
Thomas Bogendoerfer wrote:
> To make use of per_cpu variables in interrupt code per_cpu_init() must
> be done after setup_per_cpu_areas(). This is achieved by calling it
> in smp_prepare_boot_cpu() via a new smp_ops method.
>
> Signed-off-by: Thomas Bogendoerfer <[email protected]>
Applied to mips-next.
Thanks,
Paul
[ This message was auto-generated; if you believe anything is incorrect
then please email [email protected] to report it. ]
Hello,
Thomas Bogendoerfer wrote:
> Replace hub register access with __raw_readq/__raw_writeq and get
> rid of hubreg_t completely. Also remove no longer (probably never
> used) used defines
>
> Signed-off-by: Thomas Bogendoerfer <[email protected]>
Applied to mips-next.
Thanks,
Paul
[ This message was auto-generated; if you believe anything is incorrect
then please email [email protected] to report it. ]
Hi Thomas,
On Fri, Feb 22, 2019 at 09:14:18AM +0100, Thomas Bogendoerfer wrote:
> On Thu, 21 Feb 2019 20:50:39 +0000
> Paul Burton <[email protected]> wrote:
>
> > I don't appear to have received patches 7 or 9 but I see from archives
> > there'll be a v3 of patch 9 at least.
>
> I'm still fighting with git send-email to do proper collecting of addresses...
> And the mails to your @mips.com address bounced yesterday.
Interesting - thanks for letting me know. Some of our IT infrastructure
has been physically moved over the weekend so hopefully it's just
fallout from that, and I seem to be able to email myself from gmail at
least. Will keep an eye on it though!
> > So I can either apply 1-6 for v5.1 or defer the whole series. Let me
> > know - I'm happy either way.
>
> All changes will happen in patches 7-10, so appreciate, if you could
> apply 1-6 :-)
Great, I've pushed out mips-next with patches 1-6 applied. My ack email
script isn't yet smart enough to respond to the cover letter for a
series that's only partially applied, so apologies for the 6 separate
acks :)
Thanks,
Paul
On Fri, 22 Feb 2019 06:46:29 -0800
Christoph Hellwig <[email protected]> wrote:
> > diff --git a/arch/mips/include/asm/dma-direct.h b/arch/mips/include/asm/dma-direct.h
> > index b5c240806e1b..bd11e7934df1 100644
> > --- a/arch/mips/include/asm/dma-direct.h
> > +++ b/arch/mips/include/asm/dma-direct.h
> > @@ -2,6 +2,8 @@
> > #ifndef _MIPS_DMA_DIRECT_H
> > #define _MIPS_DMA_DIRECT_H 1
> >
> > +#include <dma-direct.h>
> > +
> > static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
> > {
> > if (!dev->dma_mask)
>
> How is your mach dma-direct.h scheme going to work, given that
> we already have non-inline declarations of __phys_to_dma / __dma_to_phys
> in this file?
the compiler is fine with the declarations, that's why I left the non-inline
prototypes as they are
> Also this really should go into a separate commit, and we should either
> have all of these functions inline or none. Having all of them out
> of line seemed a lot saner to me to avoid all the mach header mess.
hmm, so your inline version in include/linux/dma-direct.h is ok, while
doing the same for MIPS in an other header files isn't ? Sounds inconsistent
to me.
Anyway I'll move __phys_to_dma/__dma_to_phy into a fitting/new .c file in
the next version of the series.
Thomas.
--
SUSE Linux GmbH
GF: Felix Imend?rffer, Jane Smithard, Graham Norton
HRB 21284 (AG N?rnberg)
On Thu, Feb 21, 2019 at 05:37:08PM -0600, Bjorn Helgaas wrote:
> I haven't researched the details of how other platforms do it, but if
> it would be possible for pci-xtalk to do it the same way, that would
> be ideal.
I don't need this patch any longer. So you could just ignore it.
Thomas.
--
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea. [ RFC1925, 2.3 ]