summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorKanoj Sarcar <kanoj@engr.sgi.com>2000-05-19 03:15:26 +0000
committerKanoj Sarcar <kanoj@engr.sgi.com>2000-05-19 03:15:26 +0000
commit70410127358947fc7a75b7610f88181336c959ff (patch)
treef317daad7ef419d161e5c0cced8fb68190789234 /arch
parentac599b8199968fd92e0d986f8cfdebb535b8887c (diff)
Implement a more dynamic method of associating IRQs with PCI devices.
Instead of encoding bus/slot numbers in the IRQ, have seperate arrays to store that information.
Diffstat (limited to 'arch')
-rw-r--r--arch/mips64/sgi-ip27/ip27-irq.c65
-rw-r--r--arch/mips64/sgi-ip27/ip27-pci.c67
2 files changed, 78 insertions, 54 deletions
diff --git a/arch/mips64/sgi-ip27/ip27-irq.c b/arch/mips64/sgi-ip27/ip27-irq.c
index db5099a55..ccff1f09f 100644
--- a/arch/mips64/sgi-ip27/ip27-irq.c
+++ b/arch/mips64/sgi-ip27/ip27-irq.c
@@ -63,6 +63,7 @@
irq_cpustat_t irq_stat [NR_CPUS];
extern asmlinkage void ip27_irq(void);
+extern int irq_to_bus[], irq_to_slot[];
int (*irq_cannonicalize)(int irq);
int intr_connect_level(cpuid_t cpu, int bit);
int intr_disconnect_level(cpuid_t cpu, int bit);
@@ -75,16 +76,17 @@ unsigned long spurious_count = 0;
* we need to map irq's up to at least bit 7 of the INT_MASK0_A register
* since bits 0-6 are pre-allocated for other purposes.
*/
-#define IRQ_TO_SWLEVEL(i) i + 7
-#define SWLEVEL_TO_IRQ(s) s - 7
+#define IRQ_TO_SWLEVEL(cpu, i) i + 7
+#define SWLEVEL_TO_IRQ(cpu, s) s - 7
/*
- * use these macros to get the encoded nasid, widget id, and real irq
+ * use these macros to get the encoded nasid and widget id
* from the irq value
*/
-#define NASID_FROM_PCI_IRQ(i) (((i - BASE_PCI_IRQ) >> 16) & (0xff))
-#define WID_FROM_PCI_IRQ(i) (((i - BASE_PCI_IRQ) >> 8) & (0xff))
-#define SLOT_FROM_PCI_IRQ(i) ((i - BASE_PCI_IRQ) & 7)
-#define IRQ_FROM_IRQ(i) ((i) & (0xff))
+#define NASID_FROM_PCI_IRQ(i) \
+ (((i) == IOC3_ETH_INT) ? 0 : bus_to_nid[irq_to_bus[(i)]])
+#define WID_FROM_PCI_IRQ(i) \
+ (((i) == IOC3_ETH_INT) ? 8 : bus_to_wid[irq_to_bus[(i)]])
+#define SLOT_FROM_PCI_IRQ(i) irq_to_slot[i]
void disable_irq(unsigned int irq_nr)
{
@@ -126,20 +128,18 @@ int get_irq_list(char *buf)
* do_IRQ handles all normal device IRQ's (the special SMP cross-CPU interrupts
* have their own specific handlers).
*/
-asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
+static void do_IRQ(cpuid_t thiscpu, int irq, struct pt_regs * regs)
{
struct irqaction *action;
- int do_random, cpu;
+ int do_random;
- cpu = smp_processor_id();
- irq_enter(cpu, irq);
- kstat.irqs[cpu][irq]++;
+ irq_enter(thiscpu, irq);
+ kstat.irqs[thiscpu][irq]++;
action = *(irq + irq_action);
if (action) {
if (!(action->flags & SA_INTERRUPT))
__sti();
- action = *(irq + irq_action);
do_random = 0;
do {
do_random |= action->flags;
@@ -150,7 +150,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
add_interrupt_randomness(irq);
__cli();
}
- irq_exit(cpu, irq);
+ irq_exit(thiscpu, irq);
/* unmasking and bottom half handling is done magically for us. */
}
@@ -187,7 +187,8 @@ void ip27_do_irq(struct pt_regs *regs)
{
int irq, swlevel;
hubreg_t pend0, mask0;
- int pi_int_mask0 = ((cputoslice(smp_processor_id()) == 0) ?
+ cpuid_t thiscpu = smp_processor_id();
+ int pi_int_mask0 = ((cputoslice(thiscpu) == 0) ?
PI_INT_MASK0_A : PI_INT_MASK0_B);
/* copied from Irix intpend0() */
@@ -201,8 +202,8 @@ void ip27_do_irq(struct pt_regs *regs)
swlevel = ms1bit(pend0);
LOCAL_HUB_CLR_INTR(swlevel);
/* "map" swlevel to irq */
- irq = SWLEVEL_TO_IRQ(swlevel);
- do_IRQ(irq, regs);
+ irq = SWLEVEL_TO_IRQ(thiscpu, swlevel);
+ do_IRQ(thiscpu, irq, regs);
/* clear bit in pend0 */
pend0 ^= 1ULL << swlevel;
} while(pend0);
@@ -219,23 +220,19 @@ static unsigned int bridge_startup(unsigned int irq)
{
bridge_t *bridge;
int pin, swlevel;
- int real_irq = IRQ_FROM_IRQ(irq);
cpuid_t cpu = 0;
bridge = (bridge_t *) NODE_SWIN_BASE(NASID_FROM_PCI_IRQ(irq),
WID_FROM_PCI_IRQ(irq));
- if (real_irq == IRQ_FROM_IRQ(IOC3_ETH_INT))
- pin = 2;
- else
- pin = SLOT_FROM_PCI_IRQ(irq);
+ pin = SLOT_FROM_PCI_IRQ(irq);
DBG("bridge_startup(): irq= 0x%x real_irq= %d pin=%d\n", irq, real_irq, pin);
/*
* "map" irq to a swlevel greater than 6 since the first 6 bits
* of INT_PEND0 are taken
*/
- swlevel = IRQ_TO_SWLEVEL(real_irq);
+ swlevel = IRQ_TO_SWLEVEL(cpu, irq);
intr_connect_level(cpu, swlevel);
bridge->b_int_addr[pin].addr = 0x20000 | swlevel;
@@ -243,7 +240,7 @@ static unsigned int bridge_startup(unsigned int irq)
/* set more stuff in int_enable reg */
bridge->b_int_enable |= 0x7ffffe00;
- if (real_irq != IRQ_FROM_IRQ(IOC3_ETH_INT)) {
+ if (irq != IOC3_ETH_INT) {
bridgereg_t device;
#if 0
/*
@@ -280,21 +277,17 @@ static unsigned int bridge_shutdown(unsigned int irq)
{
bridge_t *bridge;
int pin, swlevel;
- int real_irq = IRQ_FROM_IRQ(irq);
bridge = (bridge_t *) NODE_SWIN_BASE(NASID_FROM_PCI_IRQ(irq),
WID_FROM_PCI_IRQ(irq));
DBG("bridge_shutdown: irq 0x%x\n", irq);
- if (real_irq == IRQ_FROM_IRQ(IOC3_ETH_INT))
- pin = 2;
- else
- pin = SLOT_FROM_PCI_IRQ(irq);
+ pin = SLOT_FROM_PCI_IRQ(irq);
/*
* map irq to a swlevel greater than 6 since the first 6 bits
* of INT_PEND0 are taken
*/
- swlevel = IRQ_TO_SWLEVEL(real_irq);
+ swlevel = IRQ_TO_SWLEVEL(cpu, irq);
intr_disconnect_level(smp_processor_id(), swlevel);
bridge->b_int_enable &= ~(1 << pin);
@@ -344,7 +337,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
unsigned long flags;
DBG("setup_irq: 0x%x\n", irq);
- if (IRQ_FROM_IRQ(irq) >= NR_IRQS) {
+ if (irq >= NR_IRQS) {
printk("IRQ array overflow %d\n", irq);
while(1);
}
@@ -352,7 +345,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
rand_initialize_irq(irq);
save_and_cli(flags);
- p = irq_action + IRQ_FROM_IRQ(irq);
+ p = irq_action + irq;
if ((old = *p) != NULL) {
/* Can't share interrupts unless both agree to */
if (!(old->flags & new->flags & SA_SHIRQ)) {
@@ -413,11 +406,11 @@ void free_irq(unsigned int irq, void *dev_id)
struct irqaction * action, **p;
unsigned long flags;
- if (IRQ_FROM_IRQ(irq) >= NR_IRQS) {
+ if (irq >= NR_IRQS) {
printk("Trying to free IRQ%d\n", irq);
return;
}
- for (p = IRQ_FROM_IRQ(irq) + irq_action; (action = *p) != NULL; p = &action->next) {
+ for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
if (action->dev_id != dev_id)
continue;
@@ -732,12 +725,12 @@ void install_cpuintr(cpuid_t cpu)
#ifdef CONFIG_SMP
#if (CPUS_PER_NODE == 2)
irq = CPU_RESCHED_A_IRQ + cputoslice(cpu);
- intr_connect_level(cpu, IRQ_TO_SWLEVEL(irq));
+ intr_connect_level(cpu, IRQ_TO_SWLEVEL(cpu, irq));
if (done == 0)
if (request_irq(irq, handle_resched_intr, 0, "resched", 0))
panic("intercpu intr unconnectible\n");
irq = CPU_CALL_A_IRQ + cputoslice(cpu);
- intr_connect_level(cpu, IRQ_TO_SWLEVEL(irq));
+ intr_connect_level(cpu, IRQ_TO_SWLEVEL(cpu, irq));
if (done == 0)
if (request_irq(irq, smp_call_function_interrupt, 0,
"callfunc", 0))
diff --git a/arch/mips64/sgi-ip27/ip27-pci.c b/arch/mips64/sgi-ip27/ip27-pci.c
index cbdd6a5c4..4892fa1ec 100644
--- a/arch/mips64/sgi-ip27/ip27-pci.c
+++ b/arch/mips64/sgi-ip27/ip27-pci.c
@@ -17,6 +17,28 @@
#include <asm/sn/sn0/hub.h>
/*
+ * Max #PCI busses we can handle; ie, max #PCI bridges.
+ */
+#define MAX_PCI_BUSSES 20
+
+/*
+ * Max #PCI devices (like scsi controllers) we handle on a bus.
+ */
+#define MAX_DEVICES_PER_PCIBUS 8
+
+/*
+ * No locking needed until PCI initialization is done parallely.
+ */
+int irqstore[MAX_PCI_BUSSES][MAX_DEVICES_PER_PCIBUS];
+int lastirq = BASE_PCI_IRQ;
+
+/*
+ * Translate from irq to software PCI bus number and PCI slot.
+ */
+int irq_to_bus[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS];
+int irq_to_slot[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS];
+
+/*
* 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.
* Therefore we use type 0 accesses for now even though they won't work
@@ -123,13 +145,17 @@ static struct pci_ops bridge_pci_ops = {
void __init pcibios_init(void)
{
struct pci_ops *ops = &bridge_pci_ops;
- nasid_t nid = get_nasid();
int i;
ioport_resource.end = ~0UL;
+ /*
+ * Hacks for ioc3 eth. Make sure we associate IOC3_ETH_INT
+ * with nasid 0, widget 8, slot 2.
+ */
+ irq_to_slot[IOC3_ETH_INT] = 2;
for (i=0; i<num_bridges; i++) {
- printk("PCI: Probing PCI hardware on host bus %2d, node %d.\n", i, nid);
+ printk("PCI: Probing PCI hardware on host bus %2d.\n", i);
pci_scan_bus(i, ops, NULL);
}
}
@@ -158,29 +184,34 @@ pci_swizzle(struct pci_dev *dev, u8 *pinp)
* 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..3].
- * The format of the returned irq is:
- * NASID WID BUS PIN SLOT
- * 8 8 4 1 3
- * Just to make sure the interpcu intrs do not collide with any irq's
- * assigned this way, we keep the intercpu intrs at a low value, and
- * add in the offset. IOC3_ETH_INT does not collide with other pci irqs
- * as it has a pin = 0 in the interpreted irq value.
+ * 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 __init
pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
int rv;
- if ((dev->bus->number > 16) || (slot > 7) || (pin > 1)) {
- printk("PCI_MAP_IRQ: Time to change IRQ format %d, %d, %d\n", dev->bus->number, slot, pin);
- while(0);
+ if ((dev->bus->number >= MAX_PCI_BUSSES) || (pin != 1) || \
+ (slot >= MAX_DEVICES_PER_PCIBUS)) {
+ printk("Increase supported PCI busses %d,%d,%d\n", \
+ dev->bus->number, slot, pin);
+ while(1);
+ }
+
+ /*
+ * Already assigned? Then return previously assigned value ...
+ */
+ if (irqstore[dev->bus->number][slot])
+ return(irqstore[dev->bus->number][slot]);
+ else {
+ lastirq++; /* IOC3_ETH_INT hack */
+ irq_to_bus[lastirq] = dev->bus->number;
+ irq_to_slot[lastirq] = slot;
+ return(irqstore[dev->bus->number][slot] = lastirq);
}
- rv = (dev->bus->number << 4) + (slot + (((pin-1) & 1) << 3));
- rv |= (bus_to_wid[dev->bus->number] << 8);
- rv |= (bus_to_nid[dev->bus->number] << 16);
- rv += BASE_PCI_IRQ;
- return rv;
}
void __init