linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/10] MIPS: SGI-IP27 rework
@ 2019-02-19 15:57 Thomas Bogendoerfer
  2019-02-19 15:57 ` [PATCH v2 07/10] PCI: call add_bus method also for root bus Thomas Bogendoerfer
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Thomas Bogendoerfer @ 2019-02-19 15:57 UTC (permalink / raw)
  To: Ralf Baechle, Paul Burton, James Hogan, Lorenzo Pieralisi,
	Bjorn Helgaas, Marc Zyngier, Thomas Gleixner, linux-mips,
	linux-kernel, linux-pci

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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 07/10] PCI: call add_bus method also for root bus
  2019-02-19 15:57 [PATCH v2 00/10] MIPS: SGI-IP27 rework Thomas Bogendoerfer
@ 2019-02-19 15:57 ` Thomas Bogendoerfer
  2019-02-21 23:37   ` Bjorn Helgaas
  2019-02-19 15:57 ` [PATCH v2 08/10] MIPS: SGI-IP27: use generic PCI driver Thomas Bogendoerfer
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 13+ messages in thread
From: Thomas Bogendoerfer @ 2019-02-19 15:57 UTC (permalink / raw)
  To: Bjorn Helgaas, linux-pci, linux-kernel

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 <tbogendoerfer@suse.de>
---
 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


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 08/10] MIPS: SGI-IP27: use generic PCI driver
  2019-02-19 15:57 [PATCH v2 00/10] MIPS: SGI-IP27 rework Thomas Bogendoerfer
  2019-02-19 15:57 ` [PATCH v2 07/10] PCI: call add_bus method also for root bus Thomas Bogendoerfer
@ 2019-02-19 15:57 ` Thomas Bogendoerfer
  2019-02-22 14:46   ` Christoph Hellwig
  2019-02-19 15:57 ` [PATCH v2 10/10] MIPS: SGI-IP27: abstract chipset irq from bridge Thomas Bogendoerfer
  2019-02-21 20:50 ` [PATCH v2 00/10] MIPS: SGI-IP27 rework Paul Burton
  3 siblings, 1 reply; 13+ messages in thread
From: Thomas Bogendoerfer @ 2019-02-19 15:57 UTC (permalink / raw)
  To: Ralf Baechle, Paul Burton, James Hogan, Lorenzo Pieralisi,
	Bjorn Helgaas, linux-mips, linux-kernel, linux-pci

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 <tbogendoerfer@suse.de>
---
 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 (hch@lst.de)
- * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org)
- * 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 (ralf@linux-mips.org)
+ * Copyright (C) 2003 Christoph Hellwig (hch@lst.de)
+ * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org)
  * 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


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 10/10] MIPS: SGI-IP27: abstract chipset irq from bridge
  2019-02-19 15:57 [PATCH v2 00/10] MIPS: SGI-IP27 rework Thomas Bogendoerfer
  2019-02-19 15:57 ` [PATCH v2 07/10] PCI: call add_bus method also for root bus Thomas Bogendoerfer
  2019-02-19 15:57 ` [PATCH v2 08/10] MIPS: SGI-IP27: use generic PCI driver Thomas Bogendoerfer
@ 2019-02-19 15:57 ` Thomas Bogendoerfer
  2019-02-21 20:50 ` [PATCH v2 00/10] MIPS: SGI-IP27 rework Paul Burton
  3 siblings, 0 replies; 13+ messages in thread
From: Thomas Bogendoerfer @ 2019-02-19 15:57 UTC (permalink / raw)
  To: Ralf Baechle, Paul Burton, James Hogan, Lorenzo Pieralisi,
	Bjorn Helgaas, linux-mips, linux-kernel, linux-pci

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 <tbogendoerfer@suse.de>
---
 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


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 00/10] MIPS: SGI-IP27 rework
  2019-02-19 15:57 [PATCH v2 00/10] MIPS: SGI-IP27 rework Thomas Bogendoerfer
                   ` (2 preceding siblings ...)
  2019-02-19 15:57 ` [PATCH v2 10/10] MIPS: SGI-IP27: abstract chipset irq from bridge Thomas Bogendoerfer
@ 2019-02-21 20:50 ` Paul Burton
  2019-02-22  8:14   ` Thomas Bogendoerfer
  3 siblings, 1 reply; 13+ messages in thread
From: Paul Burton @ 2019-02-21 20:50 UTC (permalink / raw)
  To: Thomas Bogendoerfer
  Cc: Ralf Baechle, James Hogan, Lorenzo Pieralisi, Bjorn Helgaas,
	Marc Zyngier, Thomas Gleixner, linux-mips, linux-kernel,
	linux-pci

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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 07/10] PCI: call add_bus method also for root bus
  2019-02-19 15:57 ` [PATCH v2 07/10] PCI: call add_bus method also for root bus Thomas Bogendoerfer
@ 2019-02-21 23:37   ` Bjorn Helgaas
  2019-02-23 11:04     ` Thomas Bogendoerfer
  2019-02-28 13:03     ` Thomas Bogendoerfer
  0 siblings, 2 replies; 13+ messages in thread
From: Bjorn Helgaas @ 2019-02-21 23:37 UTC (permalink / raw)
  To: Thomas Bogendoerfer; +Cc: linux-pci, linux-kernel

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 <tbogendoerfer@suse.de>
> ---
>  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
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 00/10] MIPS: SGI-IP27 rework
  2019-02-21 20:50 ` [PATCH v2 00/10] MIPS: SGI-IP27 rework Paul Burton
@ 2019-02-22  8:14   ` Thomas Bogendoerfer
  2019-02-22 14:49     ` Christoph Hellwig
  2019-02-25 19:17     ` Paul Burton
  0 siblings, 2 replies; 13+ messages in thread
From: Thomas Bogendoerfer @ 2019-02-22  8:14 UTC (permalink / raw)
  To: Paul Burton
  Cc: Ralf Baechle, James Hogan, Lorenzo Pieralisi, Bjorn Helgaas,
	Marc Zyngier, Thomas Gleixner, linux-mips, linux-kernel,
	linux-pci

On Thu, 21 Feb 2019 20:50:39 +0000
Paul Burton <paul.burton@mips.com> 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)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 08/10] MIPS: SGI-IP27: use generic PCI driver
  2019-02-19 15:57 ` [PATCH v2 08/10] MIPS: SGI-IP27: use generic PCI driver Thomas Bogendoerfer
@ 2019-02-22 14:46   ` Christoph Hellwig
  2019-02-27 17:10     ` Thomas Bogendoerfer
  0 siblings, 1 reply; 13+ messages in thread
From: Christoph Hellwig @ 2019-02-22 14:46 UTC (permalink / raw)
  To: Thomas Bogendoerfer
  Cc: Ralf Baechle, Paul Burton, James Hogan, Lorenzo Pieralisi,
	Bjorn Helgaas, linux-mips, linux-kernel, linux-pci

> 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?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 00/10] MIPS: SGI-IP27 rework
  2019-02-22  8:14   ` Thomas Bogendoerfer
@ 2019-02-22 14:49     ` Christoph Hellwig
  2019-02-25 19:17     ` Paul Burton
  1 sibling, 0 replies; 13+ messages in thread
From: Christoph Hellwig @ 2019-02-22 14:49 UTC (permalink / raw)
  To: Thomas Bogendoerfer
  Cc: Paul Burton, Ralf Baechle, James Hogan, Lorenzo Pieralisi,
	Bjorn Helgaas, Marc Zyngier, Thomas Gleixner, linux-mips,
	linux-kernel, linux-pci

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).

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 07/10] PCI: call add_bus method also for root bus
  2019-02-21 23:37   ` Bjorn Helgaas
@ 2019-02-23 11:04     ` Thomas Bogendoerfer
  2019-02-28 13:03     ` Thomas Bogendoerfer
  1 sibling, 0 replies; 13+ messages in thread
From: Thomas Bogendoerfer @ 2019-02-23 11:04 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: linux-pci, linux-kernel

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 <tbogendoerfer@suse.de>
> > ---
> >  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 ]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 00/10] MIPS: SGI-IP27 rework
  2019-02-22  8:14   ` Thomas Bogendoerfer
  2019-02-22 14:49     ` Christoph Hellwig
@ 2019-02-25 19:17     ` Paul Burton
  1 sibling, 0 replies; 13+ messages in thread
From: Paul Burton @ 2019-02-25 19:17 UTC (permalink / raw)
  To: Thomas Bogendoerfer
  Cc: Ralf Baechle, James Hogan, Lorenzo Pieralisi, Bjorn Helgaas,
	Marc Zyngier, Thomas Gleixner, linux-mips, linux-kernel,
	linux-pci

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 <paul.burton@mips.com> 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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 08/10] MIPS: SGI-IP27: use generic PCI driver
  2019-02-22 14:46   ` Christoph Hellwig
@ 2019-02-27 17:10     ` Thomas Bogendoerfer
  0 siblings, 0 replies; 13+ messages in thread
From: Thomas Bogendoerfer @ 2019-02-27 17:10 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Ralf Baechle, Paul Burton, James Hogan, Lorenzo Pieralisi,
	Bjorn Helgaas, linux-mips, linux-kernel, linux-pci

On Fri, 22 Feb 2019 06:46:29 -0800
Christoph Hellwig <hch@infradead.org> 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)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 07/10] PCI: call add_bus method also for root bus
  2019-02-21 23:37   ` Bjorn Helgaas
  2019-02-23 11:04     ` Thomas Bogendoerfer
@ 2019-02-28 13:03     ` Thomas Bogendoerfer
  1 sibling, 0 replies; 13+ messages in thread
From: Thomas Bogendoerfer @ 2019-02-28 13:03 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: linux-pci, linux-kernel

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 ]

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2019-02-28 13:03 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-19 15:57 [PATCH v2 00/10] MIPS: SGI-IP27 rework Thomas Bogendoerfer
2019-02-19 15:57 ` [PATCH v2 07/10] PCI: call add_bus method also for root bus Thomas Bogendoerfer
2019-02-21 23:37   ` Bjorn Helgaas
2019-02-23 11:04     ` Thomas Bogendoerfer
2019-02-28 13:03     ` Thomas Bogendoerfer
2019-02-19 15:57 ` [PATCH v2 08/10] MIPS: SGI-IP27: use generic PCI driver Thomas Bogendoerfer
2019-02-22 14:46   ` Christoph Hellwig
2019-02-27 17:10     ` Thomas Bogendoerfer
2019-02-19 15:57 ` [PATCH v2 10/10] MIPS: SGI-IP27: abstract chipset irq from bridge Thomas Bogendoerfer
2019-02-21 20:50 ` [PATCH v2 00/10] MIPS: SGI-IP27 rework Paul Burton
2019-02-22  8:14   ` Thomas Bogendoerfer
2019-02-22 14:49     ` Christoph Hellwig
2019-02-25 19:17     ` Paul Burton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).