]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
MIPS: SGI-IP27: rework HUB interrupts
authorThomas Bogendoerfer <tbogendoerfer@suse.de>
Tue, 19 Feb 2019 15:57:20 +0000 (16:57 +0100)
committerPaul Burton <paul.burton@mips.com>
Tue, 19 Feb 2019 20:46:03 +0000 (12:46 -0800)
This commit rearranges the HUB interrupt code by using MIPS_IRQ_CPU
interrupt handling code and modern Linux IRQ framework features to get
rid of global arrays. It also adds support for irq affinity setting.

Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
Signed-off-by: Paul Burton <paul.burton@mips.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: James Hogan <jhogan@kernel.org>
Cc: linux-mips@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
arch/mips/Kconfig
arch/mips/include/asm/mach-ip27/irq.h
arch/mips/include/asm/mach-ip27/mmzone.h
arch/mips/include/asm/pci/bridge.h
arch/mips/pci/pci-ip27.c
arch/mips/sgi-ip27/Makefile
arch/mips/sgi-ip27/ip27-init.c
arch/mips/sgi-ip27/ip27-irq-pci.c [deleted file]
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sgi-ip27/ip27-irqno.c [deleted file]
arch/mips/sgi-ip27/ip27-timer.c

index 25266d1fc8365397e08bbc22f49a63007957c075..b19f179f3f03b67c2fa9de5a204902df9b7ea839 100644 (file)
@@ -675,6 +675,7 @@ config SGI_IP27
        select DEFAULT_SGI_PARTITION
        select SYS_HAS_EARLY_PRINTK
        select HAVE_PCI
+       select IRQ_MIPS_CPU
        select NR_CPUS_DEFAULT_64
        select SYS_HAS_CPU_R10000
        select SYS_SUPPORTS_64BIT_KERNEL
index b0b7261ff3ad26fa8c98bfcff1ae1c868f64c5ab..fd91c58aaf7dc6f94f6e611c84059d0237315e5d 100644 (file)
 #ifndef __ASM_MACH_IP27_IRQ_H
 #define __ASM_MACH_IP27_IRQ_H
 
-/*
- * A hardwired interrupt number is completely stupid for this system - a
- * large configuration might have thousands if not tenthousands of
- * interrupts.
- */
 #define NR_IRQS 256
 
 #include_next <irq.h>
 
+#define IP27_HUB_PEND0_IRQ     (MIPS_CPU_IRQ_BASE + 2)
+#define IP27_HUB_PEND1_IRQ     (MIPS_CPU_IRQ_BASE + 3)
+#define IP27_RT_TIMER_IRQ      (MIPS_CPU_IRQ_BASE + 4)
+
+#define IP27_HUB_IRQ_BASE      (MIPS_CPU_IRQ_BASE + 8)
+#define IP27_HUB_IRQ_COUNT     128
+
 #endif /* __ASM_MACH_IP27_IRQ_H */
index 2ed3094dee078ddc8de19a41da8ead05ed8550ca..1cd6a23a84f231a9d62133521840e8193509fe01 100644 (file)
@@ -8,20 +8,11 @@
 
 #define pa_to_nid(addr)                NASID_TO_COMPACT_NODEID(NASID_GET(addr))
 
-#define LEVELS_PER_SLICE       128
-
-struct slice_data {
-       unsigned long irq_enable_mask[2];
-       int level_to_irq[LEVELS_PER_SLICE];
-};
-
 struct hub_data {
        kern_vars_t     kern_vars;
        DECLARE_BITMAP(h_bigwin_used, HUB_NUM_BIG_WINDOW);
        cpumask_t       h_cpus;
        unsigned long slice_map;
-       unsigned long irq_alloc_mask[2];
-       struct slice_data slice[2];
 };
 
 struct node_data {
index 0c5fe3a2d2a9fbaeff52eb086b916b93594f6b87..23574c27eb40f97b40a51d10d2dac960579e3072 100644 (file)
@@ -808,7 +808,6 @@ struct bridge_controller {
        struct bridge_regs      *base;
        nasid_t                 nasid;
        unsigned int            widget_id;
-       unsigned int            irq_cpu;
        u64                     baddr;
        unsigned int            pci_int[8];
 };
@@ -823,8 +822,7 @@ struct bridge_controller {
 #define bridge_clr(bc, reg, val)       \
        __raw_writel(__raw_readl(&bc->base->reg) & ~(val), &bc->base->reg)
 
-extern void register_bridge_irq(unsigned int irq);
-extern int request_bridge_irq(struct bridge_controller *bc);
+extern int request_bridge_irq(struct bridge_controller *bc, int pin);
 
 extern struct pci_ops bridge_pci_ops;
 
index 7cf50290a6d9387bb401021e3d58f088863078fb..3c177b4d0609154836080b1e4b623f769e0a12c6 100644 (file)
  */
 #define MAX_PCI_BUSSES         40
 
-/*
- * Max #PCI devices (like scsi controllers) we handle on a bus.
- */
-#define MAX_DEVICES_PER_PCIBUS 8
-
 /*
  * XXX: No kmalloc available when we do our crosstalk scan,
  *     we should try to move it later in the boot process.
  */
 static struct bridge_controller bridges[MAX_PCI_BUSSES];
 
-/*
- * Translate from irq to software PCI bus number and PCI slot.
- */
-struct bridge_controller *irq_to_bridge[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS];
-int irq_to_slot[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS];
-
 extern struct pci_ops bridge_pci_ops;
 
 int bridge_probe(nasid_t nasid, int widget_id, int masterwid)
@@ -77,7 +66,6 @@ int bridge_probe(nasid_t nasid, int widget_id, int masterwid)
        bc->io.end              = ~0UL;
        bc->io.flags            = IORESOURCE_IO;
 
-       bc->irq_cpu = smp_processor_id();
        bc->widget_id = widget_id;
        bc->nasid = nasid;
 
@@ -165,16 +153,12 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
 
        irq = bc->pci_int[slot];
        if (irq == -1) {
-               irq = request_bridge_irq(bc);
+               irq = request_bridge_irq(bc, slot);
                if (irq < 0)
                        return irq;
 
                bc->pci_int[slot] = irq;
        }
-
-       irq_to_bridge[irq] = bc;
-       irq_to_slot[irq] = slot;
-
        dev->irq = irq;
 
        return 0;
index 73502fda13ee170193a28af0e9b9aaa89ac962d3..27c14ede191eb7b1353e3a2cedd6d9d80bc2b385 100644 (file)
@@ -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
index e6fa9d0c708a04299eed9c086419a1a8200cc3c3..6074efeff894f7f24b91c3b9f9c2d174481c7499 100644 (file)
@@ -56,7 +56,6 @@ static void per_hub_init(cnodeid_t cnode)
 {
        struct hub_data *hub = hub_data(cnode);
        nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
-       int i;
 
        cpumask_set_cpu(smp_processor_id(), &hub->h_cpus);
 
@@ -87,24 +86,6 @@ static void per_hub_init(cnodeid_t cnode)
                __flush_cache_all();
        }
 #endif
-
-       /*
-        * Some interrupts are reserved by hardware or by software convention.
-        * Mark these as reserved right away so they won't be used accidentally
-        * later.
-        */
-       for (i = 0; i <= BASE_PCI_IRQ; i++) {
-               __set_bit(i, hub->irq_alloc_mask);
-               LOCAL_HUB_CLR_INTR(INT_PEND0_BASELVL + i);
-       }
-
-       __set_bit(IP_PEND0_6_63, hub->irq_alloc_mask);
-       LOCAL_HUB_S(PI_INT_PEND_MOD, IP_PEND0_6_63);
-
-       for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++) {
-               __set_bit(i, hub->irq_alloc_mask);
-               LOCAL_HUB_CLR_INTR(INT_PEND1_BASELVL + i);
-       }
 }
 
 void per_cpu_init(void)
@@ -113,8 +94,6 @@ void per_cpu_init(void)
        int slice = LOCAL_HUB_L(PI_CPU_NUM);
        cnodeid_t cnode = get_compact_nodeid();
        struct hub_data *hub = hub_data(cnode);
-       struct slice_data *si = hub->slice + slice;
-       int i;
 
        if (test_and_set_bit(slice, &hub->slice_map))
                return;
@@ -123,22 +102,14 @@ void per_cpu_init(void)
 
        per_hub_init(cnode);
 
-       for (i = 0; i < LEVELS_PER_SLICE; i++)
-               si->level_to_irq[i] = -1;
-
-       /*
-        * We use this so we can find the local hub's data as fast as only
-        * possible.
-        */
-       cpu_data[cpu].data = si;
-
        cpu_time_init();
        install_ipi();
 
        /* Install our NMI handler if symmon hasn't installed one. */
        install_cpu_nmi_handler(cputoslice(cpu));
 
-       set_c0_status(SRB_DEV0 | SRB_DEV1);
+       enable_percpu_irq(IP27_HUB_PEND0_IRQ, IRQ_TYPE_NONE);
+       enable_percpu_irq(IP27_HUB_PEND1_IRQ, IRQ_TYPE_NONE);
 }
 
 /*
diff --git a/arch/mips/sgi-ip27/ip27-irq-pci.c b/arch/mips/sgi-ip27/ip27-irq-pci.c
deleted file mode 100644 (file)
index a00a23b..0000000
+++ /dev/null
@@ -1,264 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ip27-irq.c: Highlevel interrupt handling for IP27 architecture.
- *
- * Copyright (C) 1999, 2000 Ralf Baechle (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;
-       int pin, swlevel;
-       cpuid_t cpu;
-       u64 device;
-
-       pin = SLOT_FROM_PCI_IRQ(d->irq);
-       bc = IRQ_TO_BRIDGE(d->irq);
-
-       pr_debug("bridge_startup(): irq= 0x%x  pin=%d\n", d->irq, pin);
-       /*
-        * "map" irq to a swlevel greater than 6 since the first 6 bits
-        * of INT_PEND0 are taken
-        */
-       swlevel = find_level(&cpu, d->irq);
-       bridge_write(bc, b_int_addr[pin].addr,
-                    (0x20000 | swlevel | (bc->nasid << 8)));
-       bridge_set(bc, b_int_enable, (1 << pin));
-       bridge_set(bc, b_int_enable, 0x7ffffe00); /* more stuff in int_enable */
-
-       /*
-        * Enable sending of an interrupt clear packt to the hub on a high to
-        * low transition of the interrupt pin.
-        *
-        * IRIX sets additional bits in the address which are documented as
-        * reserved in the bridge docs.
-        */
-       bridge_set(bc, b_int_mode, (1UL << pin));
-
-       /*
-        * We assume the bridge to have a 1:1 mapping between devices
-        * (slots) and intr pins.
-        */
-       device = bridge_read(bc, b_int_device);
-       device &= ~(7 << (pin*3));
-       device |= (pin << (pin*3));
-       bridge_write(bc, b_int_device, device);
-
-       bridge_read(bc, b_wid_tflush);
-
-       intr_connect_level(cpu, swlevel);
-
-       return 0;       /* Never anything pending.  */
-}
-
-/* Shutdown one of the (PCI ...) IRQs routes over a bridge.  */
-static void shutdown_bridge_irq(struct irq_data *d)
-{
-       struct bridge_controller *bc = IRQ_TO_BRIDGE(d->irq);
-       int pin, swlevel;
-       cpuid_t cpu;
-
-       pr_debug("bridge_shutdown: irq 0x%x\n", d->irq);
-       pin = SLOT_FROM_PCI_IRQ(d->irq);
-
-       /*
-        * map irq to a swlevel greater than 6 since the first 6 bits
-        * of INT_PEND0 are taken
-        */
-       swlevel = find_level(&cpu, d->irq);
-       intr_disconnect_level(cpu, swlevel);
-
-       bridge_clr(bc, b_int_enable, (1 << pin));
-       bridge_read(bc, b_wid_tflush);
-}
-
-static inline void enable_bridge_irq(struct irq_data *d)
-{
-       cpuid_t cpu;
-       int swlevel;
-
-       swlevel = find_level(&cpu, d->irq);     /* Criminal offence */
-       intr_connect_level(cpu, swlevel);
-}
-
-static inline void disable_bridge_irq(struct irq_data *d)
-{
-       cpuid_t cpu;
-       int swlevel;
-
-       swlevel = find_level(&cpu, d->irq);     /* Criminal offence */
-       intr_disconnect_level(cpu, swlevel);
-}
-
-static struct irq_chip bridge_irq_type = {
-       .name           = "bridge",
-       .irq_startup    = startup_bridge_irq,
-       .irq_shutdown   = shutdown_bridge_irq,
-       .irq_mask       = disable_bridge_irq,
-       .irq_unmask     = enable_bridge_irq,
-};
-
-void register_bridge_irq(unsigned int irq)
-{
-       irq_set_chip_and_handler(irq, &bridge_irq_type, handle_level_irq);
-}
-
-int request_bridge_irq(struct bridge_controller *bc)
-{
-       int irq = allocate_irqno();
-       int swlevel, cpu;
-       nasid_t nasid;
-
-       if (irq < 0)
-               return irq;
-
-       /*
-        * "map" irq to a swlevel greater than 6 since the first 6 bits
-        * of INT_PEND0 are taken
-        */
-       cpu = bc->irq_cpu;
-       swlevel = alloc_level(cpu, irq);
-       if (unlikely(swlevel < 0)) {
-               free_irqno(irq);
-
-               return -EAGAIN;
-       }
-
-       /* Make sure it's not already pending when we connect it. */
-       nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
-       REMOTE_HUB_CLR_INTR(nasid, swlevel);
-
-       intr_connect_level(cpu, swlevel);
-
-       register_bridge_irq(irq);
-
-       return irq;
-}
index f37155ef7ed959a27c991bc13ba86c453d93b3e7..710a59764b01c164d3ffae92f18a394224bdc153 100644 (file)
  * Copyright (C) 1999 - 2001 Kanoj Sarcar
  */
 
-#undef DEBUG
-
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/smp.h>
-#include <linux/random.h>
 #include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/delay.h>
 #include <linux/bitops.h>
 
-#include <asm/bootinfo.h>
 #include <asm/io.h>
-#include <asm/mipsregs.h>
-
-#include <asm/processor.h>
+#include <asm/irq_cpu.h>
+#include <asm/pci/bridge.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/agent.h>
 #include <asm/sn/arch.h>
 #include <asm/sn/hub.h>
 #include <asm/sn/intr.h>
 
-/*
- * Linux has a controller-independent x86 interrupt architecture.
- * every controller has a 'controller-template', that is used
- * by the main code to do the right thing. Each driver-visible
- * interrupt source is transparently wired to the appropriate
- * controller. Thus drivers need not be aware of the
- * interrupt-controller.
- *
- * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
- * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
- * (IO-APICs assumed to be messaging to Pentium local-APICs)
- *
- * the code is designed to be easily extended with new/different
- * interrupt controllers, without having to do assembly magic.
- */
+struct hub_irq_data {
+       struct bridge_controller *bc;
+       u64     *irq_mask[2];
+       cpuid_t cpu;
+       int     bit;
+       int     pin;
+};
 
-extern asmlinkage void ip27_irq(void);
+static DECLARE_BITMAP(hub_irq_map, IP27_HUB_IRQ_COUNT);
 
-/*
- * Find first bit set
- */
-static int ms1bit(unsigned long x)
+static DEFINE_PER_CPU(unsigned long [2], irq_enable_mask);
+
+static inline int alloc_level(void)
+{
+       int level;
+
+again:
+       level = find_first_zero_bit(hub_irq_map, IP27_HUB_IRQ_COUNT);
+       if (level >= IP27_HUB_IRQ_COUNT)
+               return -ENOSPC;
+
+       if (test_and_set_bit(level, hub_irq_map))
+               goto again;
+
+       return level;
+}
+
+static void enable_hub_irq(struct irq_data *d)
+{
+       struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
+       unsigned long *mask = per_cpu(irq_enable_mask, hd->cpu);
+
+       set_bit(hd->bit, mask);
+       __raw_writeq(mask[0], hd->irq_mask[0]);
+       __raw_writeq(mask[1], hd->irq_mask[1]);
+}
+
+static void disable_hub_irq(struct irq_data *d)
+{
+       struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
+       unsigned long *mask = per_cpu(irq_enable_mask, hd->cpu);
+
+       clear_bit(hd->bit, mask);
+       __raw_writeq(mask[0], hd->irq_mask[0]);
+       __raw_writeq(mask[1], hd->irq_mask[1]);
+}
+
+static unsigned int startup_bridge_irq(struct irq_data *d)
+{
+       struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
+       struct bridge_controller *bc;
+       nasid_t nasid;
+       u32 device;
+       int pin;
+
+       if (!hd)
+               return -EINVAL;
+
+       pin = hd->pin;
+       bc = hd->bc;
+
+       nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(hd->cpu));
+       bridge_write(bc, b_int_addr[pin].addr,
+                    (0x20000 | hd->bit | (nasid << 8)));
+       bridge_set(bc, b_int_enable, (1 << pin));
+       bridge_set(bc, b_int_enable, 0x7ffffe00); /* more stuff in int_enable */
+
+       /*
+        * Enable sending of an interrupt clear packt to the hub on a high to
+        * low transition of the interrupt pin.
+        *
+        * IRIX sets additional bits in the address which are documented as
+        * reserved in the bridge docs.
+        */
+       bridge_set(bc, b_int_mode, (1UL << pin));
+
+       /*
+        * We assume the bridge to have a 1:1 mapping between devices
+        * (slots) and intr pins.
+        */
+       device = bridge_read(bc, b_int_device);
+       device &= ~(7 << (pin*3));
+       device |= (pin << (pin*3));
+       bridge_write(bc, b_int_device, device);
+
+       bridge_read(bc, b_wid_tflush);
+
+       enable_hub_irq(d);
+
+       return 0;       /* Never anything pending.  */
+}
+
+static void shutdown_bridge_irq(struct irq_data *d)
+{
+       struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
+       struct bridge_controller *bc;
+       int pin = hd->pin;
+
+       if (!hd)
+               return;
+
+       disable_hub_irq(d);
+
+       bc = hd->bc;
+       bridge_clr(bc, b_int_enable, (1 << pin));
+       bridge_read(bc, b_wid_tflush);
+}
+
+static void setup_hub_mask(struct hub_irq_data *hd, const struct cpumask *mask)
+{
+       nasid_t nasid;
+       int cpu;
+
+       cpu = cpumask_first_and(mask, cpu_online_mask);
+       nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
+       hd->cpu = cpu;
+       if (!cputoslice(cpu)) {
+               hd->irq_mask[0] = REMOTE_HUB_PTR(nasid, PI_INT_MASK0_A);
+               hd->irq_mask[1] = REMOTE_HUB_PTR(nasid, PI_INT_MASK1_A);
+       } else {
+               hd->irq_mask[0] = REMOTE_HUB_PTR(nasid, PI_INT_MASK0_B);
+               hd->irq_mask[1] = REMOTE_HUB_PTR(nasid, PI_INT_MASK1_B);
+       }
+
+       /* Make sure it's not already pending when we connect it. */
+       REMOTE_HUB_CLR_INTR(nasid, hd->bit);
+}
+
+static int set_affinity_hub_irq(struct irq_data *d, const struct cpumask *mask,
+                               bool force)
+{
+       struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
+
+       if (!hd)
+               return -EINVAL;
+
+       if (irqd_is_started(d))
+               disable_hub_irq(d);
+
+       setup_hub_mask(hd, mask);
+
+       if (irqd_is_started(d))
+               startup_bridge_irq(d);
+
+       irq_data_update_effective_affinity(d, cpumask_of(hd->cpu));
+
+       return 0;
+}
+
+static struct irq_chip hub_irq_type = {
+       .name             = "HUB",
+       .irq_startup      = startup_bridge_irq,
+       .irq_shutdown     = shutdown_bridge_irq,
+       .irq_mask         = disable_hub_irq,
+       .irq_unmask       = enable_hub_irq,
+       .irq_set_affinity = set_affinity_hub_irq,
+};
+
+int request_bridge_irq(struct bridge_controller *bc, int pin)
 {
-       int b = 0, s;
+       struct hub_irq_data *hd;
+       struct hub_data *hub;
+       struct irq_desc *desc;
+       int swlevel;
+       int irq;
+
+       hd = kzalloc(sizeof(*hd), GFP_KERNEL);
+       if (!hd)
+               return -ENOMEM;
+
+       swlevel = alloc_level();
+       if (unlikely(swlevel < 0)) {
+               kfree(hd);
+               return -EAGAIN;
+       }
+       irq = swlevel + IP27_HUB_IRQ_BASE;
+
+       hd->bc = bc;
+       hd->bit = swlevel;
+       hd->pin = pin;
+       irq_set_chip_data(irq, hd);
+
+       /* use CPU connected to nearest hub */
+       hub = hub_data(NASID_TO_COMPACT_NODEID(bc->nasid));
+       setup_hub_mask(hd, &hub->h_cpus);
 
-       s = 16; if (x >> 16 == 0) s = 0; b += s; x >>= s;
-       s =  8; if (x >>  8 == 0) s = 0; b += s; x >>= s;
-       s =  4; if (x >>  4 == 0) s = 0; b += s; x >>= s;
-       s =  2; if (x >>  2 == 0) s = 0; b += s; x >>= s;
-       s =  1; if (x >>  1 == 0) s = 0; b += s;
+       desc = irq_to_desc(irq);
+       desc->irq_common_data.node = bc->nasid;
+       cpumask_copy(desc->irq_common_data.affinity, &hub->h_cpus);
 
-       return b;
+       return irq;
+}
+
+void ip27_hub_irq_init(void)
+{
+       int i;
+
+       for (i = IP27_HUB_IRQ_BASE;
+            i < (IP27_HUB_IRQ_BASE + IP27_HUB_IRQ_COUNT); i++)
+               irq_set_chip_and_handler(i, &hub_irq_type, handle_level_irq);
+
+       /*
+        * Some interrupts are reserved by hardware or by software convention.
+        * Mark these as reserved right away so they won't be used accidentally
+        * later.
+        */
+       for (i = 0; i <= BASE_PCI_IRQ; i++)
+               set_bit(i, hub_irq_map);
+
+       set_bit(IP_PEND0_6_63, hub_irq_map);
+
+       for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++)
+               set_bit(i, hub_irq_map);
 }
 
 /*
@@ -82,23 +249,19 @@ static int ms1bit(unsigned long x)
  * Kanoj 05.13.00
  */
 
-static void ip27_do_irq_mask0(void)
+static void ip27_do_irq_mask0(struct irq_desc *desc)
 {
-       int irq, swlevel;
-       u64 pend0, mask0;
        cpuid_t cpu = smp_processor_id();
-       int pi_int_mask0 =
-               (cputoslice(cpu) == 0) ?  PI_INT_MASK0_A : PI_INT_MASK0_B;
+       unsigned long *mask = per_cpu(irq_enable_mask, cpu);
+       u64 pend0;
 
        /* copied from Irix intpend0() */
        pend0 = LOCAL_HUB_L(PI_INT_PEND0);
-       mask0 = LOCAL_HUB_L(pi_int_mask0);
 
-       pend0 &= mask0;         /* Pick intrs we should look at */
+       pend0 &= mask[0];               /* Pick intrs we should look at */
        if (!pend0)
                return;
 
-       swlevel = ms1bit(pend0);
 #ifdef CONFIG_SMP
        if (pend0 & (1UL << CPU_RESCHED_A_IRQ)) {
                LOCAL_HUB_CLR_INTR(CPU_RESCHED_A_IRQ);
@@ -108,106 +271,66 @@ static void ip27_do_irq_mask0(void)
                scheduler_ipi();
        } else if (pend0 & (1UL << CPU_CALL_A_IRQ)) {
                LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ);
-               irq_enter();
                generic_smp_call_function_interrupt();
-               irq_exit();
        } else if (pend0 & (1UL << CPU_CALL_B_IRQ)) {
                LOCAL_HUB_CLR_INTR(CPU_CALL_B_IRQ);
-               irq_enter();
                generic_smp_call_function_interrupt();
-               irq_exit();
        } else
 #endif
-       {
-               /* "map" swlevel to irq */
-               struct slice_data *si = cpu_data[cpu].data;
-
-               irq = si->level_to_irq[swlevel];
-               do_IRQ(irq);
-       }
+               generic_handle_irq(__ffs(pend0) + IP27_HUB_IRQ_BASE);
 
        LOCAL_HUB_L(PI_INT_PEND0);
 }
 
-static void ip27_do_irq_mask1(void)
+static void ip27_do_irq_mask1(struct irq_desc *desc)
 {
-       int irq, swlevel;
-       u64 pend1, mask1;
        cpuid_t cpu = smp_processor_id();
-       int pi_int_mask1 = (cputoslice(cpu) == 0) ?  PI_INT_MASK1_A : PI_INT_MASK1_B;
-       struct slice_data *si = cpu_data[cpu].data;
+       unsigned long *mask = per_cpu(irq_enable_mask, cpu);
+       u64 pend1;
 
        /* copied from Irix intpend0() */
        pend1 = LOCAL_HUB_L(PI_INT_PEND1);
-       mask1 = LOCAL_HUB_L(pi_int_mask1);
 
-       pend1 &= mask1;         /* Pick intrs we should look at */
+       pend1 &= mask[1];               /* Pick intrs we should look at */
        if (!pend1)
                return;
 
-       swlevel = ms1bit(pend1);
-       /* "map" swlevel to irq */
-       irq = si->level_to_irq[swlevel];
-       LOCAL_HUB_CLR_INTR(swlevel);
-       do_IRQ(irq);
+       generic_handle_irq(__ffs(pend1) + IP27_HUB_IRQ_BASE + 64);
 
        LOCAL_HUB_L(PI_INT_PEND1);
 }
 
-static void ip27_prof_timer(void)
-{
-       panic("CPU %d got a profiling interrupt", smp_processor_id());
-}
-
-static void ip27_hub_error(void)
-{
-       panic("CPU %d got a hub error interrupt", smp_processor_id());
-}
-
-asmlinkage void plat_irq_dispatch(void)
-{
-       unsigned long pending = read_c0_cause() & read_c0_status();
-       extern unsigned int rt_timer_irq;
-
-       if (pending & CAUSEF_IP4)
-               do_IRQ(rt_timer_irq);
-       else if (pending & CAUSEF_IP2)  /* PI_INT_PEND_0 or CC_PEND_{A|B} */
-               ip27_do_irq_mask0();
-       else if (pending & CAUSEF_IP3)  /* PI_INT_PEND_1 */
-               ip27_do_irq_mask1();
-       else if (pending & CAUSEF_IP5)
-               ip27_prof_timer();
-       else if (pending & CAUSEF_IP6)
-               ip27_hub_error();
-}
-
-void __init arch_init_irq(void)
-{
-}
-
 void install_ipi(void)
 {
-       int slice = LOCAL_HUB_L(PI_CPU_NUM);
        int cpu = smp_processor_id();
-       struct slice_data *si = cpu_data[cpu].data;
-       struct hub_data *hub = hub_data(cpu_to_node(cpu));
+       unsigned long *mask = per_cpu(irq_enable_mask, cpu);
+       int slice = LOCAL_HUB_L(PI_CPU_NUM);
        int resched, call;
 
        resched = CPU_RESCHED_A_IRQ + slice;
-       __set_bit(resched, hub->irq_alloc_mask);
-       __set_bit(resched, si->irq_enable_mask);
+       set_bit(resched, mask);
        LOCAL_HUB_CLR_INTR(resched);
 
        call = CPU_CALL_A_IRQ + slice;
-       __set_bit(call, hub->irq_alloc_mask);
-       __set_bit(call, si->irq_enable_mask);
+       set_bit(call, mask);
        LOCAL_HUB_CLR_INTR(call);
 
        if (slice == 0) {
-               LOCAL_HUB_S(PI_INT_MASK0_A, si->irq_enable_mask[0]);
-               LOCAL_HUB_S(PI_INT_MASK1_A, si->irq_enable_mask[1]);
+               LOCAL_HUB_S(PI_INT_MASK0_A, mask[0]);
+               LOCAL_HUB_S(PI_INT_MASK1_A, mask[1]);
        } else {
-               LOCAL_HUB_S(PI_INT_MASK0_B, si->irq_enable_mask[0]);
-               LOCAL_HUB_S(PI_INT_MASK1_B, si->irq_enable_mask[1]);
+               LOCAL_HUB_S(PI_INT_MASK0_B, mask[0]);
+               LOCAL_HUB_S(PI_INT_MASK1_B, mask[1]);
        }
 }
+
+void __init arch_init_irq(void)
+{
+       mips_cpu_irq_init();
+       ip27_hub_irq_init();
+
+       irq_set_percpu_devid(IP27_HUB_PEND0_IRQ);
+       irq_set_chained_handler(IP27_HUB_PEND0_IRQ, ip27_do_irq_mask0);
+       irq_set_percpu_devid(IP27_HUB_PEND1_IRQ);
+       irq_set_chained_handler(IP27_HUB_PEND1_IRQ, ip27_do_irq_mask1);
+}
diff --git a/arch/mips/sgi-ip27/ip27-irqno.c b/arch/mips/sgi-ip27/ip27-irqno.c
deleted file mode 100644 (file)
index 957ab58..0000000
+++ /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();
-}
index 9d55247533a5f0acc85e0d5d36b719c7c2ed7ad3..9b4b9ac621a3111c627c486031b248e33365148a 100644 (file)
 #include <asm/sn/sn0/hubio.h>
 #include <asm/pci/bridge.h>
 
-static void enable_rt_irq(struct irq_data *d)
-{
-}
-
-static void disable_rt_irq(struct irq_data *d)
-{
-}
-
-static struct irq_chip rt_irq_type = {
-       .name           = "SN HUB RT timer",
-       .irq_mask       = disable_rt_irq,
-       .irq_unmask     = enable_rt_irq,
-};
-
 static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
 {
        unsigned int cpu = smp_processor_id();
@@ -65,8 +51,6 @@ static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
        return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0;
 }
 
-unsigned int rt_timer_irq;
-
 static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent);
 static DEFINE_PER_CPU(char [11], hub_rt_name);
 
@@ -87,6 +71,7 @@ static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id)
 
 struct irqaction hub_rt_irqaction = {
        .handler        = hub_rt_counter_handler,
+       .percpu_dev_id  = &hub_rt_clockevent,
        .flags          = IRQF_PERCPU | IRQF_TIMER,
        .name           = "hub-rt",
 };
@@ -107,7 +92,6 @@ void hub_rt_clock_event_init(void)
        unsigned int cpu = smp_processor_id();
        struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu);
        unsigned char *name = per_cpu(hub_rt_name, cpu);
-       int irq = rt_timer_irq;
 
        sprintf(name, "hub-rt %d", cpu);
        cd->name                = name;
@@ -118,29 +102,19 @@ void hub_rt_clock_event_init(void)
        cd->min_delta_ns        = clockevent_delta2ns(0x300, cd);
        cd->min_delta_ticks     = 0x300;
        cd->rating              = 200;
-       cd->irq                 = irq;
+       cd->irq                 = IP27_RT_TIMER_IRQ;
        cd->cpumask             = cpumask_of(cpu);
        cd->set_next_event      = rt_next_event;
        clockevents_register_device(cd);
+
+       enable_percpu_irq(IP27_RT_TIMER_IRQ, IRQ_TYPE_NONE);
 }
 
 static void __init hub_rt_clock_event_global_init(void)
 {
-       int irq;
-
-       do {
-               smp_wmb();
-               irq = rt_timer_irq;
-               if (irq)
-                       break;
-
-               irq = allocate_irqno();
-               if (irq < 0)
-                       panic("Allocation of irq number for timer failed");
-       } while (xchg(&rt_timer_irq, irq));
-
-       irq_set_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq);
-       setup_irq(irq, &hub_rt_irqaction);
+       irq_set_handler(IP27_RT_TIMER_IRQ, handle_percpu_devid_irq);
+       irq_set_percpu_devid(IP27_RT_TIMER_IRQ);
+       setup_percpu_irq(IP27_RT_TIMER_IRQ, &hub_rt_irqaction);
 }
 
 static u64 hub_rt_read(struct clocksource *cs)
@@ -194,8 +168,6 @@ void cpu_time_init(void)
                panic("No information about myself?");
 
        printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed);
-
-       set_c0_status(SRB_TIMOCLK);
 }
 
 void hub_rtc_init(cnodeid_t cnode)