Update Linux to v5.4.2

Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/arch/mips/sgi-ip27/Kconfig b/arch/mips/sgi-ip27/Kconfig
index ef3847e..e5b6cad 100644
--- a/arch/mips/sgi-ip27/Kconfig
+++ b/arch/mips/sgi-ip27/Kconfig
@@ -38,10 +38,3 @@
 	  Say Y here to enable replicating the kernel text across multiple
 	  nodes in a NUMA cluster.  This trades memory for speed.
 
-config REPLICATE_EXHANDLERS
-	bool "Exception handler replication support"
-	depends on SGI_IP27
-	help
-	  Say Y here to enable replicating the kernel exception handlers
-	  across multiple nodes in a NUMA cluster. This trades memory for
-	  speed.
diff --git a/arch/mips/sgi-ip27/Makefile b/arch/mips/sgi-ip27/Makefile
index 73502fd..27c14ed 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-berr.c b/arch/mips/sgi-ip27/ip27-berr.c
index 83efe03..73ad29b 100644
--- a/arch/mips/sgi-ip27/ip27-berr.c
+++ b/arch/mips/sgi-ip27/ip27-berr.c
@@ -74,7 +74,7 @@
 	show_regs(regs);
 	dump_tlb_all();
 	while(1);
-	force_sig(SIGBUS, current);
+	force_sig(SIGBUS);
 }
 
 void __init ip27_be_init(void)
diff --git a/arch/mips/sgi-ip27/ip27-console.c b/arch/mips/sgi-ip27/ip27-console.c
index 6bdb48d..5886bee 100644
--- a/arch/mips/sgi-ip27/ip27-console.c
+++ b/arch/mips/sgi-ip27/ip27-console.c
@@ -35,6 +35,7 @@
 {
 	struct ioc3_uartregs *uart = console_uart();
 
-	while ((uart->iu_lsr & 0x20) == 0);
-	uart->iu_thr = c;
+	while ((readb(&uart->iu_lsr) & 0x20) == 0)
+		;
+	writeb(c, &uart->iu_thr);
 }
diff --git a/arch/mips/sgi-ip27/ip27-hubio.c b/arch/mips/sgi-ip27/ip27-hubio.c
index 2abe016..6ebb884 100644
--- a/arch/mips/sgi-ip27/ip27-hubio.c
+++ b/arch/mips/sgi-ip27/ip27-hubio.c
@@ -1,7 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc.
  * Copyright (C) 2004 Christoph Hellwig.
- *	Released under GPL v2.
  *
  * Support functions for the HUB ASIC - mostly PIO mapping related.
  */
@@ -63,7 +63,7 @@
 		 * 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_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 e501c43..79a52c4 100644
--- a/arch/mips/sgi-ip27/ip27-init.c
+++ b/arch/mips/sgi-ip27/ip27-init.c
@@ -52,13 +52,10 @@
 
 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);
 	nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
-	int i;
 
 	cpumask_set_cpu(smp_processor_id(), &hub->h_cpus);
 
@@ -71,42 +68,14 @@
 	REMOTE_HUB_S(nasid, IIO_ICTO, 0xff);
 
 	hub_rtc_init(cnode);
-	xtalk_probe_node(cnode);
 
-#ifdef CONFIG_REPLICATE_EXHANDLERS
-	/*
-	 * If this is not a headless node initialization,
-	 * copy over the caliased exception handlers.
-	 */
-	if (get_compact_nodeid() == cnode) {
-		extern char except_vec2_generic, except_vec3_generic;
-		extern void build_tlb_refill_handler(void);
-
-		memcpy((void *)(CKSEG0 + 0x100), &except_vec2_generic, 0x80);
-		memcpy((void *)(CKSEG0 + 0x180), &except_vec3_generic, 0x80);
-		build_tlb_refill_handler();
-		memcpy((void *)(CKSEG0 + 0x100), (void *) CKSEG0, 0x80);
-		memcpy((void *)(CKSEG0 + 0x180), &except_vec3_generic, 0x100);
+	if (nasid) {
+		/* copy exception handlers from first node to current node */
+		memcpy((void *)NODE_OFFSET_TO_K0(nasid, 0),
+		       (void *)CKSEG0, 0x200);
 		__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);
+		/* switch to node local exception handlers */
+		REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_8K);
 	}
 }
 
@@ -116,8 +85,6 @@
 	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;
@@ -126,22 +93,14 @@
 
 	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);
 }
 
 /*
@@ -162,22 +121,11 @@
 	return NASID_TO_COMPACT_NODEID(get_nasid());
 }
 
-static inline void ioc3_eth_init(void)
-{
-	struct ioc3 *ioc3;
-	nasid_t nid;
-
-	nid = get_nasid();
-	ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base;
-
-	ioc3->eier = 0;
-}
-
 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();
@@ -214,8 +162,7 @@
 		panic("Kernel compiled for N mode.");
 #endif
 
-	ioc3_eth_init();
-	per_cpu_init();
-
+	ioport_resource.start = 0;
+	ioport_resource.end = ~0UL;
 	set_io_port_base(IO_BASE);
 }
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 cd449e9..0000000
--- a/arch/mips/sgi-ip27/ip27-irq-pci.c
+++ /dev/null
@@ -1,266 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ip27-irq.c: Highlevel interrupt handling for IP27 architecture.
- *
- * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
- * 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;
-	bridgereg_t device;
-	bridge_t *bridge;
-	int pin, swlevel;
-	cpuid_t cpu;
-
-	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);
-	/*
-	 * "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->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 */
-
-	/*
-	 * 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->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 &= ~(7 << (pin*3));
-	device |= (pin << (pin*3));
-	bridge->b_int_device = device;
-
-	bridge->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);
-	bridge_t *bridge = bc->base;
-	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->b_int_enable &= ~(1 << pin);
-	bridge->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 0dde616..37be049 100644
--- a/arch/mips/sgi-ip27/ip27-irq.c
+++ b/arch/mips/sgi-ip27/ip27-irq.c
@@ -7,69 +7,167 @@
  * 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 <linux/sched.h>
 
-#include <asm/bootinfo.h>
 #include <asm/io.h>
-#include <asm/mipsregs.h>
-
-#include <asm/processor.h>
+#include <asm/irq_cpu.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>
+#include <asm/sn/irq_alloc.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 {
+	u64	*irq_mask[2];
+	cpuid_t	cpu;
+};
 
-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 b = 0, s;
+	int level;
 
-	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;
+again:
+	level = find_first_zero_bit(hub_irq_map, IP27_HUB_IRQ_COUNT);
+	if (level >= IP27_HUB_IRQ_COUNT)
+		return -ENOSPC;
 
-	return b;
+	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(d->hwirq, 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(d->hwirq, mask);
+	__raw_writeq(mask[0], hd->irq_mask[0]);
+	__raw_writeq(mask[1], hd->irq_mask[1]);
+}
+
+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);
+	}
+}
+
+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))
+		enable_hub_irq(d);
+
+	irq_data_update_effective_affinity(d, cpumask_of(hd->cpu));
+
+	return 0;
+}
+
+static struct irq_chip hub_irq_type = {
+	.name		  = "HUB",
+	.irq_mask	  = disable_hub_irq,
+	.irq_unmask	  = enable_hub_irq,
+	.irq_set_affinity = set_affinity_hub_irq,
+};
+
+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;
+
+	if (nr_irqs > 1 || !info)
+		return -EINVAL;
+
+	hd = kzalloc(sizeof(*hd), GFP_KERNEL);
+	if (!hd)
+		return -ENOMEM;
+
+	swlevel = alloc_level();
+	if (unlikely(swlevel < 0)) {
+		kfree(hd);
+		return -EAGAIN;
+	}
+	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(info->nasid));
+	setup_hub_mask(hd, &hub->h_cpus);
+
+	/* Make sure it's not already pending when we connect it. */
+	REMOTE_HUB_CLR_INTR(info->nasid, swlevel);
+
+	desc = irq_to_desc(virq);
+	desc->irq_common_data.node = info->nasid;
+	cpumask_copy(desc->irq_common_data.affinity, &hub->h_cpus);
+
+	return 0;
+}
+
+static void hub_domain_free(struct irq_domain *domain,
+			    unsigned int virq, unsigned int nr_irqs)
+{
+	struct irq_data *irqd;
+
+	if (nr_irqs > 1)
+		return;
+
+	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
@@ -82,23 +180,21 @@
  * Kanoj 05.13.00
  */
 
-static void ip27_do_irq_mask0(void)
+static void ip27_do_irq_mask0(struct irq_desc *desc)
 {
-	int irq, swlevel;
-	hubreg_t 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);
+	struct irq_domain *domain;
+	u64 pend0;
+	int irq;
 
 	/* 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 +204,110 @@
 		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);
+		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);
 }
 
-static void ip27_do_irq_mask1(void)
+static void ip27_do_irq_mask1(struct irq_desc *desc)
 {
-	int irq, swlevel;
-	hubreg_t 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);
+	struct irq_domain *domain;
+	u64 pend1;
+	int irq;
 
 	/* 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);
+	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);
 }
 
-static void ip27_prof_timer(void)
+void install_ipi(void)
 {
-	panic("CPU %d got a profiling interrupt", smp_processor_id());
-}
+	int cpu = smp_processor_id();
+	unsigned long *mask = per_cpu(irq_enable_mask, cpu);
+	int slice = LOCAL_HUB_L(PI_CPU_NUM);
+	int resched, call;
 
-static void ip27_hub_error(void)
-{
-	panic("CPU %d got a hub error interrupt", smp_processor_id());
-}
+	resched = CPU_RESCHED_A_IRQ + slice;
+	set_bit(resched, mask);
+	LOCAL_HUB_CLR_INTR(resched);
 
-asmlinkage void plat_irq_dispatch(void)
-{
-	unsigned long pending = read_c0_cause() & read_c0_status();
-	extern unsigned int rt_timer_irq;
+	call = CPU_CALL_A_IRQ + slice;
+	set_bit(call, mask);
+	LOCAL_HUB_CLR_INTR(call);
 
-	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();
+	if (slice == 0) {
+		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, mask[0]);
+		LOCAL_HUB_S(PI_INT_MASK1_B, mask[1]);
+	}
 }
 
 void __init arch_init_irq(void)
 {
-}
+	struct irq_domain *domain;
+	struct fwnode_handle *fn;
+	int i;
 
-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));
-	int resched, call;
+	mips_cpu_irq_init();
 
-	resched = CPU_RESCHED_A_IRQ + slice;
-	__set_bit(resched, hub->irq_alloc_mask);
-	__set_bit(resched, si->irq_enable_mask);
-	LOCAL_HUB_CLR_INTR(resched);
+	/*
+	 * 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);
 
-	call = CPU_CALL_A_IRQ + slice;
-	__set_bit(call, hub->irq_alloc_mask);
-	__set_bit(call, si->irq_enable_mask);
-	LOCAL_HUB_CLR_INTR(call);
+	set_bit(IP_PEND0_6_63, hub_irq_map);
 
-	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]);
-	} 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]);
-	}
+	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_and_data(IP27_HUB_PEND0_IRQ, ip27_do_irq_mask0,
+					 domain);
+	irq_set_percpu_devid(IP27_HUB_PEND1_IRQ);
+	irq_set_chained_handler_and_data(IP27_HUB_PEND1_IRQ, ip27_do_irq_mask1,
+					 domain);
 }
diff --git a/arch/mips/sgi-ip27/ip27-irqno.c b/arch/mips/sgi-ip27/ip27-irqno.c
deleted file mode 100644
index 957ab58..0000000
--- 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-memory.c b/arch/mips/sgi-ip27/ip27-memory.c
index 59133d0..8624a88 100644
--- a/arch/mips/sgi-ip27/ip27-memory.c
+++ b/arch/mips/sgi-ip27/ip27-memory.c
@@ -18,7 +18,6 @@
 #include <linux/export.h>
 #include <linux/nodemask.h>
 #include <linux/swap.h>
-#include <linux/bootmem.h>
 #include <linux/pfn.h>
 #include <linux/highmem.h>
 #include <asm/page.h>
@@ -45,7 +44,7 @@
 	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;
@@ -53,9 +52,9 @@
 		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;
 
@@ -155,11 +154,11 @@
 	}
 
 	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;
 	}
 
@@ -204,17 +203,17 @@
 	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) {
@@ -231,7 +230,7 @@
 		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]);
@@ -245,11 +244,11 @@
 					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)) );
 	}
@@ -333,11 +332,7 @@
 		 * thinks it is a node 0 address.
 		 */
 		REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1));
-#ifdef CONFIG_REPLICATE_EXHANDLERS
-		REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_8K);
-#else
 		REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0);
-#endif
 
 #ifdef LATER
 		/*
@@ -374,7 +369,7 @@
 
 			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;
@@ -389,7 +384,6 @@
 {
 	unsigned long slot_firstpfn = slot_getbasepfn(node, 0);
 	unsigned long slot_freepfn = node_getfirstfree(node);
-	unsigned long bootmap_size;
 	unsigned long start_pfn, end_pfn;
 
 	get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
@@ -400,7 +394,6 @@
 	__node_data[node] = __va(slot_freepfn << PAGE_SHIFT);
 	memset(__node_data[node], 0, PAGE_SIZE);
 
-	NODE_DATA(node)->bdata = &bootmem_node_data[node];
 	NODE_DATA(node)->node_start_pfn = start_pfn;
 	NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn;
 
@@ -409,12 +402,11 @@
 	slot_freepfn += PFN_UP(sizeof(struct pglist_data) +
 			       sizeof(struct hub_data));
 
-	bootmap_size = init_bootmem_node(NODE_DATA(node), slot_freepfn,
-					start_pfn, end_pfn);
 	free_bootmem_with_active_regions(node, end_pfn);
-	reserve_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
-		((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size,
-		BOOTMEM_DEFAULT);
+
+	memblock_reserve(slot_firstpfn << PAGE_SHIFT,
+			 ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT));
+
 	sparse_memory_present_with_active_regions(node);
 }
 
@@ -439,6 +431,7 @@
 
 	mlreset();
 	szmem();
+	max_low_pfn = PHYS_PFN(memblock_end_of_DRAM());
 
 	for (node = 0; node < MAX_COMPACT_NODES; node++) {
 		if (node_online(node)) {
@@ -459,18 +452,8 @@
 void __init paging_init(void)
 {
 	unsigned long zones_size[MAX_NR_ZONES] = {0, };
-	unsigned node;
 
 	pagetable_init();
-
-	for_each_online_node(node) {
-		unsigned long start_pfn, end_pfn;
-
-		get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
-
-		if (end_pfn > max_low_pfn)
-			max_low_pfn = end_pfn;
-	}
 	zones_size[ZONE_NORMAL] = max_low_pfn;
 	free_area_init_nodes(zones_size);
 }
@@ -478,7 +461,7 @@
 void __init mem_init(void)
 {
 	high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT);
-	free_all_bootmem();
+	memblock_free_all();
 	setup_zero_pages();	/* This comes from node 0 */
 	mem_init_print_info(NULL);
 }
diff --git a/arch/mips/sgi-ip27/ip27-nmi.c b/arch/mips/sgi-ip27/ip27-nmi.c
index 8ac2bfa..3aae388 100644
--- a/arch/mips/sgi-ip27/ip27-nmi.c
+++ b/arch/mips/sgi-ip27/ip27-nmi.c
@@ -62,75 +62,75 @@
 		(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)
 {
-	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);
@@ -143,9 +143,9 @@
 	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");
 }
 
 /*
diff --git a/arch/mips/sgi-ip27/ip27-smp.c b/arch/mips/sgi-ip27/ip27-smp.c
index 545446d..20b8120 100644
--- a/arch/mips/sgi-ip27/ip27-smp.c
+++ b/arch/mips/sgi-ip27/ip27-smp.c
@@ -177,7 +177,7 @@
 		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 @@
 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,
 };
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
index 9d55247..9b4b9ac 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 @@
 	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 @@
 
 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 @@
 	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 @@
 	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 @@
 		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)
diff --git a/arch/mips/sgi-ip27/ip27-xtalk.c b/arch/mips/sgi-ip27/ip27-xtalk.c
index 4fe5678..4a1f0b0 100644
--- a/arch/mips/sgi-ip27/ip27-xtalk.c
+++ b/arch/mips/sgi-ip27/ip27-xtalk.c
@@ -1,14 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
  * Copyright (C) 1999, 2000 Silcon Graphics, Inc.
  * Copyright (C) 2004 Christoph Hellwig.
- *	Released under GPL v2.
  *
  * Generic XTALK initialization code
  */
 
 #include <linux/kernel.h>
 #include <linux/smp.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/xtalk-bridge.h>
+#include <asm/sn/addrs.h>
 #include <asm/sn/types.h>
 #include <asm/sn/klconfig.h>
 #include <asm/sn/hub.h>
@@ -20,7 +23,48 @@
 #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 xtalk_bridge_platform_data *bd;
+	struct platform_device *pdev;
+	unsigned long offset;
+
+	bd = kzalloc(sizeof(*bd), GFP_KERNEL);
+	if (!bd)
+		goto no_mem;
+	pdev = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
+	if (!pdev) {
+		kfree(bd);
+		goto no_mem;
+	}
+
+	offset = NODE_OFFSET(nasid);
+
+	bd->bridge_addr = RAW_NODE_SWIN_BASE(nasid, widget);
+	bd->intr_addr	= BIT_ULL(47) + 0x01800000 + PI_INT_PEND_MOD;
+	bd->nasid	= nasid;
+	bd->masterwid	= masterwid;
+
+	bd->mem.name	= "Bridge PCI MEM";
+	bd->mem.start	= offset + (widget << SWIN_SIZE_BITS);
+	bd->mem.end	= bd->mem.start + SWIN_SIZE - 1;
+	bd->mem.flags	= IORESOURCE_MEM;
+	bd->mem_offset	= offset;
+
+	bd->io.name	= "Bridge PCI IO";
+	bd->io.start	= offset + (widget << SWIN_SIZE_BITS);
+	bd->io.end	= bd->io.start + SWIN_SIZE - 1;
+	bd->io.flags	= IORESOURCE_IO;
+	bd->io_offset	= offset;
+
+	platform_device_add_data(pdev, bd, sizeof(*bd));
+	platform_device_add(pdev);
+	pr_info("xtalk:n%d/%x bridge widget\n", nasid, widget);
+	return;
+
+no_mem:
+	pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget);
+}
 
 static int probe_one_port(nasid_t nasid, int widget, int masterwid)
 {
@@ -31,13 +75,10 @@
 		(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 +93,6 @@
 	klxbow_t *xbow_p;
 	unsigned masterwid, i;
 
-	printk("is xbow\n");
-
 	/*
 	 * found xbow, so may have multiple bridges
 	 * need to probe xbow
@@ -99,7 +138,7 @@
 	return 0;
 }
 
-void xtalk_probe_node(cnodeid_t nid)
+static void xtalk_probe_node(cnodeid_t nid)
 {
 	volatile u64		hubreg;
 	nasid_t			nasid;
@@ -117,19 +156,28 @@
 		       (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;
 	}
 }
+
+static int __init xtalk_init(void)
+{
+	cnodeid_t cnode;
+
+	for_each_online_node(cnode)
+		xtalk_probe_node(cnode);
+
+	return 0;
+}
+arch_initcall(xtalk_init);