patch-2.1.115 linux/arch/sparc64/kernel/irq.c

Next file: linux/arch/sparc64/kernel/itlb_base.S
Previous file: linux/arch/sparc64/kernel/ioport.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.114/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c
@@ -1,8 +1,9 @@
-/* $Id: irq.c,v 1.53 1998/04/20 07:14:58 ecd Exp $
+/* $Id: irq.c,v 1.61 1998/08/02 14:51:38 ecd Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997  David S. Miller  (davem@caip.rutgers.edu)
  * Copyright (C) 1998  Eddie C. Dost    (ecd@skynet.be)
+ * Copyright (C) 1998  Jakub Jelinek    (jj@ultra.linux.cz)
  */
 
 #include <linux/config.h>
@@ -54,35 +55,6 @@
 
 unsigned long ivector_to_mask[NUM_IVECS];
 
-struct ino_bucket {
-	struct ino_bucket *next;
-	unsigned int ino;
-	unsigned int *imap;
-	unsigned int *iclr;
-	unsigned char *imap_refcnt;
-};
-
-#define INO_HASHSZ	(NUM_HARD_IVECS >> 2)
-#define NUM_INO_STATIC	4
-static struct ino_bucket *ino_hash[INO_HASHSZ] = { NULL, };
-static struct ino_bucket static_ino_buckets[NUM_INO_STATIC];
-static int static_ino_bucket_count = 0;
-
-static inline struct ino_bucket *__ino_lookup(unsigned int hash, unsigned int ino)
-{
-	struct ino_bucket *ret = ino_hash[hash];
-
-	for(ret = ino_hash[hash]; ret && ret->ino != ino; ret = ret->next)
-		;
-
-	return ret;
-}
-
-static inline struct ino_bucket *ino_lookup(unsigned int ino)
-{
-	return __ino_lookup((ino & (INO_HASHSZ - 1)), ino);
-}
-
 /* This is based upon code in the 32-bit Sparc kernel written mostly by
  * David Redman (djhr@tadpole.co.uk).
  */
@@ -96,6 +68,24 @@
 	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
 };
 
+#define IBF_DMA_SYNC	0x01
+#define IBF_PCI		0x02
+#define IBF_ACTIVE	0x04
+
+#define __imap(bucket) ((bucket)->iclr + (bucket)->imap_off)
+#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq))
+#define __irq(bucket) ((unsigned int)(unsigned long)(bucket))
+
+static struct ino_bucket *bucket_base, *buckets, *endbuckets;
+
+__initfunc(unsigned long irq_init(unsigned long start_mem, unsigned long end_mem))
+{
+	start_mem = (start_mem + 15) & ~15;
+	bucket_base = buckets = (struct ino_bucket *)start_mem;
+	endbuckets = buckets + 2048;
+	return (unsigned long)endbuckets;
+}
+
 int get_irq_list(char *buf)
 {
 	int i, len = 0;
@@ -188,22 +178,6 @@
 
 #define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0]))
 
-/* XXX Old compatability cruft, get rid of me when all drivers have been
- * XXX converted to dcookie registry calls... -DaveM
- */
-static unsigned int *sysio_irq_to_imap(unsigned int irq)
-{
-	unsigned long offset;
-	struct sysio_regs *sregs;
-
-	if((irq >= NUM_SYSIO_OFFSETS) ||
-	   ((offset = sysio_irq_offsets[irq]) == ((unsigned long)-1)))
-		return NULL;
-	sregs = SBus_chain->iommu->sysio_regs;
-	offset += ((unsigned long) sregs);
-	return ((unsigned int *)offset);
-}
-
 /* Convert Interrupt Mapping register pointer to assosciated
  * Interrupt Clear register pointer, SYSIO specific version.
  */
@@ -220,10 +194,10 @@
 #ifdef CONFIG_PCI
 /* PCI PSYCHO INO number to Sparc PIL level. */
 unsigned char psycho_ino_to_pil[] = {
-	7, 5, 5, 2,			/* PCI A slot 0  Int A, B, C, D */
-	7, 5, 5, 2,			/* PCI A slot 1  Int A, B, C, D */
-	7, 5, 5, 2,			/* PCI A slot 2  Int A, B, C, D */
-	7, 5, 5, 2,			/* PCI A slot 3  Int A, B, C, D */
+	7, 5, 4, 2,			/* PCI A slot 0  Int A, B, C, D */
+	7, 5, 4, 2,			/* PCI A slot 1  Int A, B, C, D */
+	7, 5, 4, 2,			/* PCI A slot 2  Int A, B, C, D */
+	7, 5, 4, 2,			/* PCI A slot 3  Int A, B, C, D */
 	6, 4, 3, 1,			/* PCI B slot 0  Int A, B, C, D */
 	6, 4, 3, 1,			/* PCI B slot 1  Int A, B, C, D */
 	6, 4, 3, 1,			/* PCI B slot 2  Int A, B, C, D */
@@ -264,21 +238,14 @@
 #endif
 
 /* Now these are always passed a true fully specified sun4u INO. */
-void enable_irq(unsigned int ino)
+void enable_irq(unsigned int irq)
 {
-	struct ino_bucket *bucket;
+	struct ino_bucket *bucket = __bucket(irq);
 	unsigned long tid;
 	unsigned int *imap;
 
-#ifdef CONFIG_PCI
-	if(PCI_IRQ_P(ino))
-		ino &= (PCI_IRQ_IGN | PCI_IRQ_INO);
-#endif
-	bucket = ino_lookup(ino);
-	if(!bucket)
-		return;
-
-	imap = bucket->imap;
+	imap = __imap(bucket);
+	if (!imap) return;
 
 	/* We send it to our UPA MID, for SMP this will be different. */
 	__asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG));
@@ -290,26 +257,19 @@
 	 * However for Graphics and UPA Slave devices the full
 	 * SYSIO_IMAP_INR field can be set by the programmer here.
 	 *
-	 * Things like FFB can now be handled via the dcookie mechanism.
+	 * Things like FFB can now be handled via the new IRQ mechanism.
 	 */
 	*imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
 }
 
 /* This now gets passed true ino's as well. */
-void disable_irq(unsigned int ino)
+void disable_irq(unsigned int irq)
 {
-	struct ino_bucket *bucket;
+	struct ino_bucket *bucket = __bucket(irq);
 	unsigned int *imap;
 
-#ifdef CONFIG_PCI
-	if(PCI_IRQ_P(ino))
-		ino &= (PCI_IRQ_IGN | PCI_IRQ_INO);
-#endif
-	bucket = ino_lookup(ino);
-	if(!bucket)
-		return;
-
-	imap = bucket->imap;
+	imap = __imap(bucket);
+	if (!imap) return;
 
 	/* NOTE: We do not want to futz with the IRQ clear registers
 	 *       and move the state to IDLE, the SCSI code does call
@@ -319,267 +279,156 @@
 	*imap &= ~(SYSIO_IMAP_VALID);
 }
 
-static void get_irq_translations(int *cpu_irq, int *ivindex_fixup,
-				 unsigned int **imap, unsigned int **iclr,
-				 void *busp, unsigned long flags,
-				 unsigned int irq)
+unsigned int build_irq(int pil, int inofixup, unsigned int *iclr, unsigned int *imap)
 {
-	if(*cpu_irq != -1 && *imap != NULL && *iclr != NULL)
-		return;
-
-	if(*cpu_irq != -1 || *imap != NULL || *iclr != NULL || busp == NULL) {
-		printk("get_irq_translations: Partial specification, this is bad.\n");
-		printk("get_irq_translations: cpu_irq[%d] imap[%p] iclr[%p] busp[%p]\n",
-		       *cpu_irq, *imap, *iclr, busp);
-		panic("Bad IRQ translations...");
-	}
-
-	if(SA_BUS(flags) == SA_SBUS) {
-		struct linux_sbus *sbusp = busp;
-		struct sysio_regs *sregs = sbusp->iommu->sysio_regs;
-		unsigned long offset;
-
-		*cpu_irq = sysio_ino_to_pil[irq];
-		if(*cpu_irq == 0) {
-			printk("get_irq_translations: Bad SYSIO INO[%x]\n", irq);
-			panic("Bad SYSIO IRQ translations...");
-		}
-		offset = sysio_irq_offsets[irq];
-		if(offset == ((unsigned long)-1)) {
-			printk("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
-			       irq, *cpu_irq);
-			panic("BAD SYSIO IRQ offset...");
-		}
-		offset += ((unsigned long)sregs);
-		*imap = ((unsigned int *)offset);
-
-		/* SYSIO inconsistancy.  For external SLOTS, we have to select
-		 * the right ICLR register based upon the lower SBUS irq level
-		 * bits.
-		 */
-		if(irq >= 0x20) {
-			*iclr = sysio_imap_to_iclr(*imap);
-		} else {
-			unsigned long iclraddr;
-			int sbus_slot = (irq & 0x18)>>3;
-			int sbus_level = irq & 0x7;
-
-			switch(sbus_slot) {
-			case 0:
-				*iclr = &sregs->iclr_slot0;
-				break;
-			case 1:
-				*iclr = &sregs->iclr_slot1;
-				break;
-			case 2:
-				*iclr = &sregs->iclr_slot2;
-				break;
-			case 3:
-				*iclr = &sregs->iclr_slot3;
-				break;
-			};
+	if (buckets == endbuckets)
+		panic("Out of IRQ buckets. Should not happen.\n");
+	buckets->pil = pil;
+	if (pil && (!iclr || !imap)) {
+		prom_printf("Invalid build_irq %d %d %016lx %016lx\n", pil, inofixup, iclr, imap);
+		prom_halt();
+	}
+	if (imap)
+		buckets->ino = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)) + inofixup;
+	else
+		buckets->ino = 0;
+		
+	buckets->iclr = iclr;
+	buckets->flags = 0;
+	buckets->imap_off = imap - iclr;
+	return __irq(buckets++);
+}
 
-			iclraddr = (unsigned long) *iclr;
-			iclraddr += ((sbus_level - 1) * 8);
-			*iclr = (unsigned int *) iclraddr;
-
-#if 0 /* DEBUGGING */
-			printk("SYSIO_FIXUP: slot[%x] level[%x] iclr[%p] ",
-			       sbus_slot, sbus_level, *iclr);
-#endif
+unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
+{
+	struct linux_sbus *sbus = (struct linux_sbus *)buscookie;
+	struct sysio_regs *sregs = sbus->iommu->sysio_regs;
+	unsigned long offset;
+	int pil;
+	unsigned int *imap, *iclr;
+	int sbus_level = 0;
 
-			/* Also, make sure this is accounted for in ivindex
-			 * computations done by the caller.
-			 */
-			*ivindex_fixup = sbus_level;
-		}
-		return;
-	}
-#ifdef CONFIG_PCI
-	if(SA_BUS(flags) == SA_PCI) {
-		struct pci_bus *pbusp = busp;
-		struct linux_pbm_info *pbm = pbusp->sysdata;
-		struct psycho_regs *pregs = pbm->parent->psycho_regs;
-		unsigned long offset;
-
-		*cpu_irq = psycho_ino_to_pil[irq & 0x3f];
-		if(*cpu_irq == 0) {
-			printk("get_irq_translations: Bad PSYCHO INO[%x]\n", irq);
-			panic("Bad PSYCHO IRQ translations...");
-		}
-		offset = psycho_imap_offset(irq);
-		if(offset == ((unsigned long)-1)) {
-			printk("get_irq_translations: Bad PSYCHO INO[%x] cpu[%d]\n",
-			       irq, *cpu_irq);
-			panic("Bad PSYCHO IRQ offset...");
-		}
-		offset += ((unsigned long)pregs);
-		*imap = ((unsigned int *)offset) + 1;
-		*iclr = (unsigned int *)
-			(((unsigned long)pregs) + psycho_iclr_offset(irq));
-		return;
-	}
-#endif
-#if 0	/* XXX More to do before we can use this. -DaveM */
-	if(SA_BUS(flags) == SA_FHC) {
-		struct fhc_bus *fbusp = busp;
-		struct fhc_regs *fregs = fbusp->regs;
-		unsigned long offset;
-
-		*cpu_irq = fhc_ino_to_pil[irq];
-		if(*cpu_irq == 0) {
-			printk("get_irq_translations: Bad FHC INO[%x]\n", irq);
-			panic("Bad FHC IRQ translations...");
-		}
-		offset = fhc_irq_offset[*cpu_irq];
-		if(offset == ((unsigned long)-1)) {
-			printk("get_irq_translations: Bad FHC INO[%x] cpu[%d]\n",
-			       irq, *cpu_irq);
-			panic("Bad FHC IRQ offset...");
-		}
-		offset += ((unsigned long)pregs);
-		*imap = (((unsigned int *)offset)+1);
-		*iclr = fhc_imap_to_iclr(*imap);
-		return;
+	pil = sysio_ino_to_pil[ino];
+	if(!pil) {
+		printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino);
+		panic("Bad SYSIO IRQ translations...");
+	}
+	offset = sysio_irq_offsets[ino];
+	if(offset == ((unsigned long)-1)) {
+		printk("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
+			ino, pil);
+		panic("BAD SYSIO IRQ offset...");
+	}
+	offset += ((unsigned long)sregs);
+	imap = ((unsigned int *)offset);
+
+	/* SYSIO inconsistancy.  For external SLOTS, we have to select
+	 * the right ICLR register based upon the lower SBUS irq level
+	 * bits.
+	 */
+	if(ino >= 0x20) {
+		iclr = sysio_imap_to_iclr(imap);
+	} else {
+		unsigned long iclraddr;
+		int sbus_slot = (ino & 0x18)>>3;
+		
+		sbus_level = ino & 0x7;
+
+		switch(sbus_slot) {
+		case 0:
+			iclr = &sregs->iclr_slot0;
+			break;
+		case 1:
+			iclr = &sregs->iclr_slot1;
+			break;
+		case 2:
+			iclr = &sregs->iclr_slot2;
+			break;
+		default:
+		case 3:
+			iclr = &sregs->iclr_slot3;
+			break;
+		};
+
+		iclraddr = (unsigned long) iclr;
+		iclraddr += ((sbus_level - 1) * 8);
+		iclr = (unsigned int *) iclraddr;
 	}
-#endif
-	printk("get_irq_translations: IRQ register for unknown bus type.\n");
-	printk("get_irq_translations: BUS[%lx] IRQ[%x]\n",
-	       SA_BUS(flags), irq);
-	panic("Bad IRQ bus type...");
+	return build_irq(pil, sbus_level, iclr, imap);
 }
 
 #ifdef CONFIG_PCI
-static void pci_irq_frobnicate(int *cpu_irq, int *ivindex_fixup,
-			       unsigned int **imap, unsigned int **iclr,
-			       unsigned int irq)
-{
-	struct linux_psycho *psycho;
-	struct psycho_regs *pregs;
-	unsigned long addr, imoff;
-
-	psycho = psycho_by_index((irq & PCI_IRQ_BUSNO) >> PCI_IRQ_BUSNO_SHFT);
-	if (!psycho) {
-		printk("get_irq_translations: BAD PSYCHO BUSNO[%x]\n", irq);
-		panic("Bad PSYCHO IRQ frobnication...");
-	}
-	pregs = psycho->psycho_regs;
+unsigned int psycho_build_irq(void *buscookie, int imap_off, int ino, int need_dma_sync)
+{
+	struct linux_psycho *psycho = (struct linux_psycho *)buscookie;
+	struct psycho_regs *pregs = psycho->psycho_regs;
+	unsigned long addr;
+	struct ino_bucket *bucket;
+	int pil;
+	unsigned int *imap, *iclr;
+	int inofixup = 0;
 
+	pil = psycho_ino_to_pil[ino & PCI_IRQ_INO];
+	
 	addr = (unsigned long) &pregs->imap_a_slot0;
-	imoff = (irq & PCI_IRQ_IMAP_OFF) >> PCI_IRQ_IMAP_OFF_SHFT;
-	addr = addr + imoff;
-
-	*imap = ((unsigned int *)addr) + 1;
+	addr = addr + imap_off;
+	imap = ((unsigned int *)addr) + 1;
 
 	addr = (unsigned long) pregs;
-	addr += psycho_iclr_offset(irq & (PCI_IRQ_INO));
-	*iclr = ((unsigned int *)addr) + 1;
+	addr += psycho_iclr_offset(ino & (PCI_IRQ_INO));
+	iclr = ((unsigned int *)addr) + 1;
 
-	*cpu_irq = psycho_ino_to_pil[irq & (PCI_IRQ_INO)];
-	if(*cpu_irq == 0) {
-		printk("get_irq_translations: BAD PSYCHO INO[%x]\n", irq);
-		panic("Bad PSYCHO IRQ frobnication...");
-	}
+	if(!(ino & 0x20))
+		inofixup = ino & 0x03;
 
-	/* IVINDEX fixup only needed for PCI slot irq lines. */
-	if(!(irq & 0x20))
-		*ivindex_fixup = irq & 0x03;
+	bucket = __bucket(build_irq(pil, inofixup, iclr, imap));
+	
+	if (need_dma_sync)
+		bucket->flags |= IBF_DMA_SYNC;
+		
+	bucket->flags |= IBF_PCI;
+	return __irq(bucket);
 }
 #endif
 
-/* Once added, they are never removed. */
-static struct ino_bucket *add_ino_hash(unsigned int ivindex,
-				       unsigned int *imap, unsigned int *iclr,
-				       unsigned long flags)
-{
-	struct ino_bucket *new = NULL, **hashp;
-	unsigned int hash = (ivindex & (INO_HASHSZ - 1));
-
-	new = __ino_lookup(hash, ivindex);
-	if(new)
-		return new;
-	if(flags & SA_STATIC_ALLOC) {
-		if(static_ino_bucket_count < NUM_INO_STATIC)
-			new = &static_ino_buckets[static_ino_bucket_count++];
-		else
-			printk("Request for ino bucket SA_STATIC_ALLOC failed "
-			       "using kmalloc\n");
-	}
-	if(new == NULL)
-		new = kmalloc(sizeof(struct ino_bucket), GFP_KERNEL);
-	if(new) {
-		hashp = &ino_hash[hash];
-		new->imap = imap;
-		new->iclr = iclr;
-		new->ino  = ivindex;
-		new->next = *hashp;
-		*hashp = new;
-	}
-	return new;
-}
-
 int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
 		unsigned long irqflags, const char *name, void *dev_id)
 {
 	struct irqaction *action, *tmp = NULL;
-	struct devid_cookie *dcookie = NULL;
-	struct ino_bucket *bucket = NULL;
+	struct ino_bucket *bucket = __bucket(irq);
 	unsigned long flags;
-	unsigned int *imap, *iclr;
-	void *bus_id = NULL;
-	int ivindex = -1, ivindex_fixup, cpu_irq = -1, pending = 0;
+	int pending = 0;
+
+	if (irq < 0x400000 || (irq & 0x80000000)) {
+		prom_printf("request_irq with old style irq %08x %016lx\n", irq, handler);
+		prom_halt();
+	}
 	
 	if(!handler)
 	    return -EINVAL;
 
-	imap = iclr = NULL;
-
-	ivindex_fixup = 0;
-
-	if (irq == 0) {
-		cpu_irq = irq;
-		irqflags &= ~(SA_IMAP_MASKED);
-	} else {
+	if (!bucket->pil)
+		irqflags &= ~SA_IMAP_MASKED;
+	else {
 		irqflags |= SA_IMAP_MASKED;
-#ifdef CONFIG_PCI
-		if(PCI_IRQ_P(irq)) {
-			pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq);
-			if (irq & PCI_IRQ_DMA_SYNC)
-				irqflags |= SA_DMA_SYNC;
-		} else
-#endif
-		if(irqflags & SA_DCOOKIE) {
-			if(!dev_id) {
-				printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n");
-				panic("Bogus irq registry.");
-			}
-			dcookie		= dev_id;
-			dev_id		= dcookie->real_dev_id;
-			cpu_irq		= dcookie->pil;
-			imap		= dcookie->imap;
-			iclr		= dcookie->iclr;
-			bus_id		= dcookie->bus_cookie;
-			get_irq_translations(&cpu_irq, &ivindex_fixup, &imap,
-					     &iclr, bus_id, irqflags, irq);
-		} else {
-			/* XXX NOTE: This code is maintained for compatability until I can
-			 * XXX       verify that all drivers sparc64 will use are updated
-			 * XXX       to use the new IRQ registry dcookie interface.  -DaveM
+		if (bucket->flags & IBF_PCI) {
+			/*
+			 * PCI IRQs should never use SA_INTERRUPT.
 			 */
-			cpu_irq = sysio_ino_to_pil[irq];
-			imap = sysio_irq_to_imap(irq);
-			if(!imap) {
-				printk("request_irq: BAD, null imap for old style "
-				       "irq registry IRQ[%x].\n", irq);
-				panic("Bad IRQ registery...");
-			}
-			iclr = sysio_imap_to_iclr(imap);
+			irqflags &= ~(SA_INTERRUPT);
+
+			/*
+			 * Check wether we _should_ use DMA Write Sync
+			 * (for devices behind bridges behind APB). 
+			 *
+			 * XXX: Not implemented, yet.
+			 */
+			if (bucket->flags & IBF_DMA_SYNC)
+				irqflags |= SA_DMA_SYNC;
 		}
-		ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
-		ivindex += ivindex_fixup;
 	}
 
-	action = *(cpu_irq + irq_action);
+	action = *(bucket->pil + irq_action);
 	if(action) {
 		if((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ))
 			for (tmp = action; tmp->next; tmp = tmp->next)
@@ -589,7 +438,7 @@
 
 		if((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
 			printk("Attempt to mix fast and slow interrupts on IRQ%d "
-			       "denied\n", irq);
+			       "denied\n", bucket->pil);
 			return -EBUSY;
 		}   
 		action = NULL;		/* Or else! */
@@ -617,22 +466,11 @@
 	}
 
 	if (irqflags & SA_IMAP_MASKED) {
-		bucket = add_ino_hash(ivindex, imap, iclr, irqflags);
-		if(!bucket) {
-			kfree(action);
-			restore_flags(flags);
-			return -ENOMEM;
-		}
-
-		pending = ((ivector_to_mask[ivindex] & 0x80000000) != 0);
-		ivector_to_mask[ivindex] = (1 << cpu_irq);
+		pending = ((ivector_to_mask[bucket->ino] & 0x80000000) != 0);
+		ivector_to_mask[bucket->ino] = (1 << bucket->pil);
 		if(pending)
-			ivector_to_mask[ivindex] |= 0x80000000;
-
-		if(dcookie) {
-			dcookie->ret_ino = ivindex;
-			dcookie->ret_pil = cpu_irq;
-		}
+			ivector_to_mask[bucket->ino] |= 0x80000000;
+		bucket->flags |= IBF_ACTIVE;
 	}
 
 	action->mask = (unsigned long) bucket;
@@ -645,13 +483,13 @@
 	if(tmp)
 		tmp->next = action;
 	else
-		*(cpu_irq + irq_action) = action;
+		*(bucket->pil + irq_action) = action;
 
-	enable_irq(ivindex);
+	enable_irq(irq);
 
 	/* We ate the IVEC already, this makes sure it does not get lost. */
 	if(pending)
-		set_softint(1 << cpu_irq);
+		set_softint(1 << bucket->pil);
 
 	restore_flags(flags);
 #ifdef __SMP__
@@ -666,23 +504,16 @@
 	struct irqaction *action;
 	struct irqaction *tmp = NULL;
 	unsigned long flags;
-	unsigned int *imap = NULL;
-	unsigned int cpu_irq;
-	int ivindex = -1;
+	struct ino_bucket *bucket = __bucket(irq), *bp;
 
-	if(irq == 0) {
-		cpu_irq = irq;
-	} else {
-#ifdef CONFIG_PCI
-		if(PCI_IRQ_P(irq))
-			cpu_irq = psycho_ino_to_pil[irq & PCI_IRQ_INO];
-		else
-#endif
-			cpu_irq = sysio_ino_to_pil[irq];
+	if (irq < 0x400000 || (irq & 0x80000000)) {
+		prom_printf("free_irq with old style irq %08x\n", irq);
+		prom_halt();
 	}
-	action = *(cpu_irq + irq_action);
+	
+	action = *(bucket->pil + irq_action);
 	if(!action->handler) {
-		printk("Freeing free IRQ %d\n", irq);
+		printk("Freeing free IRQ %d\n", bucket->pil);
 		return;
 	}
 	if(dev_id) {
@@ -692,17 +523,17 @@
 			tmp = action;
 		}
 		if(!action) {
-			printk("Trying to free free shared IRQ %d\n", irq);
+			printk("Trying to free free shared IRQ %d\n", bucket->pil);
 			return;
 		}
 	} else if(action->flags & SA_SHIRQ) {
-		printk("Trying to free shared IRQ %d with NULL device ID\n", irq);
+		printk("Trying to free shared IRQ %d with NULL device ID\n", bucket->pil);
 		return;
 	}
 
 	if(action->flags & SA_STATIC_ALLOC) {
 		printk("Attempt to free statically allocated IRQ %d (%s)\n",
-		       irq, action->name);
+		       bucket->pil, action->name);
 		return;
 	}
 
@@ -710,43 +541,35 @@
 	if(action && tmp)
 		tmp->next = action->next;
 	else
-		*(cpu_irq + irq_action) = action->next;
+		*(bucket->pil + irq_action) = action->next;
 
 	if(action->flags & SA_IMAP_MASKED) {
-		struct ino_bucket *bucket = (struct ino_bucket *)action->mask;
+		unsigned int *imap = __imap(bucket);
 
-		imap = bucket->imap;
-		if(imap != NULL) {
-			ivindex = bucket->ino;
-			ivector_to_mask[ivindex] = 0;
-		}
-		else
-			printk("free_irq: WHeee, SYSIO_MASKED yet no imap reg.\n");
-	}
-
-	kfree(action);
-
-	if(ivindex != -1) {
-		struct ino_bucket *bp;
-		int i, count = 0;
-
-		/* The trick is that we can't turn the thing off when there
-		 * are potentially other sub-irq level references.
+		/*
+		 * Only free when no other shared irq uses this bucket.
 		 */
-		if(imap != NULL) {
-			for(i = 0; i < INO_HASHSZ; i++) {
-				bp = ino_hash[i];
-				while(bp) {
-					if(bp->imap == imap)
-						count++;
-					bp = bp->next;
-				}
-			}
-		}
-		if(count < 2)
-			disable_irq(ivindex);
+		tmp = *(bucket->pil + irq_action);
+		for( ; tmp; tmp = tmp->next)
+			if ((struct ino_bucket *)tmp->mask == bucket)
+				goto out;
+
+		ivector_to_mask[bucket->ino] = 0;
+
+		bucket->flags &= ~IBF_ACTIVE;
+		for (bp = bucket_base; bp < endbuckets; bp++)
+			if (__imap(bp) == imap && (bp->flags & IBF_ACTIVE))
+				break;
+		/*
+		 * Only disable when no other sub-irq levels of
+		 * the same imap are active.
+		 */
+		if (bp == endbuckets)
+			disable_irq(irq);
 	}
 
+out:
+	kfree(action);
 	restore_flags(flags);
 }
 
@@ -982,7 +805,7 @@
 				if(!(ivector_to_mask[bucket->ino] & 0x80000000))
 					continue;
 			}
-			act->handler(irq, act->dev_id, regs);
+			act->handler(__irq(bucket), act->dev_id, regs);
 		} while((act = act->next) != NULL);
 		act = action;
 		do {
@@ -1047,61 +870,23 @@
 		     unsigned long irqflags, const char *name, void *dev_id)
 {
 	struct irqaction *action;
-	struct devid_cookie *dcookie = NULL;
-	struct ino_bucket *bucket = NULL;
+	struct ino_bucket *bucket = __bucket(irq);
 	unsigned long flags;
-	unsigned int *imap, *iclr;
-	void *bus_id = NULL;
-	int ivindex = -1, ivindex_fixup, cpu_irq = -1;
 
+	if (irq < 0x400000 || (irq & 0x80000000)) {
+		prom_printf("request_irq with old style irq %08x %016lx\n", irq, handler);
+		prom_halt();
+	}
+	
 	if(!handler)
 		return -EINVAL;
 
-	imap = iclr = NULL;
-	ivindex_fixup = 0;
-
-	if ((irq == 0) || (irq == 14)) {
+	if ((bucket->pil == 0) || (bucket->pil == 14)) {
 		printk("request_fast_irq: Trying to register shared IRQ 0 or 14.\n");
 		return -EBUSY;
 	}
 
-#ifdef CONFIG_PCI
-	if(PCI_IRQ_P(irq)) {
-		pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq);
-	} else
-#endif
-	if(irqflags & SA_DCOOKIE) {
-		if(!dev_id) {
-			printk("request_fast_irq: SA_DCOOKIE but dev_id is NULL!\n");
-			panic("Bogus irq registry.");
-		}
-		dcookie		= dev_id;
-		dev_id		= dcookie->real_dev_id;
-		cpu_irq		= dcookie->pil;
-		imap		= dcookie->imap;
-		iclr		= dcookie->iclr;
-		bus_id		= dcookie->bus_cookie;
-		get_irq_translations(&cpu_irq, &ivindex_fixup, &imap,
-				     &iclr, bus_id, irqflags, irq);
-	} else {
-		/* XXX NOTE: This code is maintained for compatability until I can
-		 * XXX       verify that all drivers sparc64 will use are updated
-		 * XXX       to use the new IRQ registry dcookie interface.  -DaveM
-		 */
-		cpu_irq = sysio_ino_to_pil[irq];
-		imap = sysio_irq_to_imap(irq);
-		if(!imap) {
-			printk("request_irq: BAD, null imap for old style "
-			       "irq registry IRQ[%x].\n", irq);
-			panic("Bad IRQ registery...");
-		}
-		iclr = sysio_imap_to_iclr(imap);
-	}
-
-	ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
-	ivindex += ivindex_fixup;
-
-	action = *(cpu_irq + irq_action);
+	action = *(bucket->pil + irq_action);
 	if(action) {
 		if(action->flags & SA_SHIRQ)
 			panic("Trying to register fast irq when already shared.\n");
@@ -1116,7 +901,7 @@
 			action = &static_irqaction[static_irq_count++];
 		else
 			printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed "
-			       "using kmalloc\n", irq, name);
+			       "using kmalloc\n", bucket->pil, name);
 	}
 	if(action == NULL)
 		action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
@@ -1125,21 +910,9 @@
 		restore_flags(flags);
 		return -ENOMEM;
 	}
-	install_fast_irq(cpu_irq, handler);
-
-	bucket = add_ino_hash(ivindex, imap, iclr, irqflags);
-	if(!bucket) {
-		kfree(action);
-		restore_flags(flags);
-		return -ENOMEM;
-	}
+	install_fast_irq(bucket->pil, handler);
 
-	ivector_to_mask[ivindex] = (1 << cpu_irq);
-
-	if(dcookie) {
-		dcookie->ret_ino = ivindex;
-		dcookie->ret_pil = cpu_irq;
-	}
+	ivector_to_mask[bucket->ino] = (1 << bucket->pil);
 
 	action->mask = (unsigned long) bucket;
 	action->handler = handler;
@@ -1148,8 +921,8 @@
 	action->name = name;
 	action->next = NULL;
 
-	*(cpu_irq + irq_action) = action;
-	enable_irq(ivindex);
+	*(bucket->pil + irq_action) = action;
+	enable_irq(irq);
 
 	restore_flags(flags);
 #ifdef __SMP__
@@ -1177,15 +950,21 @@
 		 unsigned long *clock)
 {
 	unsigned long flags;
-	unsigned long timer_tick_offset;
+	extern unsigned long timer_tick_offset;
 	int node, err;
+#ifdef __SMP__
+	extern void smp_tick_init(void);
+#endif
 
 	node = linux_cpus[0].prom_node;
 	*clock = prom_getint(node, "clock-frequency");
 	timer_tick_offset = *clock / HZ;
+#ifdef __SMP__
+	smp_tick_init();
+#endif
 
 	/* Register IRQ handler. */
-	err = request_irq(0, cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC),
+	err = request_irq(build_irq(0, 0, NULL, NULL), cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC),
 			  "timer", NULL);
 
 	if(err) {
@@ -1239,7 +1018,7 @@
 		while(p) {
 			if(p->flags & SA_IMAP_MASKED) {
 				struct ino_bucket *bucket = (struct ino_bucket *)p->mask;
-				unsigned int *imap = bucket->imap;
+				unsigned int *imap = __imap(bucket);
 				unsigned int val;
 				unsigned long tid = __cpu_logical_map[cpu] << 9;
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov