patch-2.1.132 linux/arch/arm/kernel/ecard.c

Next file: linux/arch/arm/kernel/entry-armo.S
Previous file: linux/arch/arm/kernel/dma.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.131/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c
@@ -3,7 +3,7 @@
  *
  *  Find all installed expansion cards, and handle interrupts from them.
  *
- * Copyright 1995,1996,1997 Russell King
+ * Copyright 1995-1998 Russell King
  *
  * Created from information from Acorns RiscOS3 PRMs
  *
@@ -14,6 +14,7 @@
  * 29-Sep-1997	RMK	Expansion card interrupt hardware not being re-enabled on reset from
  *			Linux. (Caused cards not to respond under RiscOS without hard reset).
  * 15-Feb-1998	RMK	Added DMA support
+ * 12-Sep-1998	RMK	Added EASI support
  */
 
 #define ECARD_C
@@ -79,7 +80,7 @@
 static unsigned int ecard_numcards, ecard_numirqcards;
 static unsigned int have_expmask;
 
-static void ecard_def_irq_enable (ecard_t *ec, int irqnr)
+static void ecard_def_irq_enable(ecard_t *ec, int irqnr)
 {
 #ifdef HAS_EXPMASK
 	if (irqnr < 4 && have_expmask) {
@@ -89,7 +90,7 @@
 #endif
 }
 
-static void ecard_def_irq_disable (ecard_t *ec, int irqnr)
+static void ecard_def_irq_disable(ecard_t *ec, int irqnr)
 {
 #ifdef HAS_EXPMASK
 	if (irqnr < 4 && have_expmask) {
@@ -99,14 +100,14 @@
 #endif
 }
 
-static void ecard_def_fiq_enable (ecard_t *ec, int fiqnr)
+static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
 {
-	panic ("ecard_def_fiq_enable called - impossible");
+	panic("ecard_def_fiq_enable called - impossible");
 }
 
-static void ecard_def_fiq_disable (ecard_t *ec, int fiqnr)
+static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr)
 {
-	panic ("ecard_def_fiq_disable called - impossible");
+	panic("ecard_def_fiq_disable called - impossible");
 }
 
 static expansioncard_ops_t ecard_default_ops = {
@@ -122,7 +123,7 @@
  *
  * They are not meant to be called directly, but via enable/disable_irq.
  */
-void ecard_enableirq (unsigned int irqnr)
+void ecard_enableirq(unsigned int irqnr)
 {
 	irqnr &= 7;
 	if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) {
@@ -132,14 +133,14 @@
 			ec->ops = &ecard_default_ops;
 
 		if (ec->claimed && ec->ops->irqenable)
-			ec->ops->irqenable (ec, irqnr);
+			ec->ops->irqenable(ec, irqnr);
 		else
-			printk (KERN_ERR "ecard: rejecting request to "
+			printk(KERN_ERR "ecard: rejecting request to "
 				"enable IRQs for %d\n", irqnr);
 	}
 }
 
-void ecard_disableirq (unsigned int irqnr)
+void ecard_disableirq(unsigned int irqnr)
 {
 	irqnr &= 7;
 	if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) {
@@ -149,11 +150,11 @@
 			ec->ops = &ecard_default_ops;
 
 		if (ec->ops && ec->ops->irqdisable)
-			ec->ops->irqdisable (ec, irqnr);
+			ec->ops->irqdisable(ec, irqnr);
 	}
 }
 
-void ecard_enablefiq (unsigned int fiqnr)
+void ecard_enablefiq(unsigned int fiqnr)
 {
 	fiqnr &= 7;
 	if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) {
@@ -163,14 +164,14 @@
 			ec->ops = &ecard_default_ops;
 
 		if (ec->claimed && ec->ops->fiqenable)
-			ec->ops->fiqenable (ec, fiqnr);
+			ec->ops->fiqenable(ec, fiqnr);
 		else
-			printk (KERN_ERR "ecard: rejecting request to "
+			printk(KERN_ERR "ecard: rejecting request to "
 				"enable FIQs for %d\n", fiqnr);
 	}
 }
 
-void ecard_disablefiq (unsigned int fiqnr)
+void ecard_disablefiq(unsigned int fiqnr)
 {
 	fiqnr &= 7;
 	if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) {
@@ -180,7 +181,7 @@
 			ec->ops = &ecard_default_ops;
 
 		if (ec->ops->fiqdisable)
-			ec->ops->fiqdisable (ec, fiqnr);
+			ec->ops->fiqdisable(ec, fiqnr);
 	}
 }
 
@@ -198,8 +199,27 @@
 		}
 	}
 	cli();
-	if (called == 0)
-		printk (KERN_WARNING "Wild interrupt from backplane?\n");
+	if (called == 0) {
+		static int last, lockup;
+
+		if (last == jiffies) {
+			lockup += 1;
+			if (lockup > 1000000) {
+				printk(KERN_ERR "\nInterrupt lockup detected - disabling expansion card IRQs\n");
+				disable_irq(intr_no);
+				printk("Expansion card IRQ state:\n");
+				for (i = 0; i < num_cards; i++)
+					printk("  %d: %sclaimed, irqaddr = %p, irqmask = %X, status=%X\n", expcard[i].irq - 32,
+						expcard[i].claimed ? "" : "not", expcard[i].irqaddr, expcard[i].irqmask, *expcard[i].irqaddr);
+			}
+		} else
+			lockup = 0;
+
+		if (!last || last + 500 < jiffies) {
+			last = jiffies;
+			printk(KERN_ERR "\nUnrecognised interrupt from backplane\n");
+		}
+	}
 }
 
 #ifdef HAS_EXPMASK
@@ -214,7 +234,7 @@
 	0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00
 };
 
-static void ecard_irq_expmask (int intr_no, void *dev_id, struct pt_regs *regs)
+static void ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs)
 {
 	const unsigned int statusmask = 15;
 	unsigned int status;
@@ -239,22 +259,22 @@
 			 */
 			oldexpmask = have_expmask;
 			EXPMASK_ENABLE = (have_expmask &= priority_masks[irqno]);
-			sti ();
-			do_ecard_IRQ (ec->irq, regs);
-			cli ();
+			sti();
+			do_ecard_IRQ(ec->irq, regs);
+			cli();
 			EXPMASK_ENABLE = have_expmask = oldexpmask;
 			status = EXPMASK_STATUS & statusmask;
 			if (status)
 				goto again;
 		} else {
-			printk (KERN_WARNING "card%d: interrupt from unclaimed card???\n", irqno);
+			printk(KERN_WARNING "card%d: interrupt from unclaimed card???\n", irqno);
 			EXPMASK_ENABLE = (have_expmask &= ~(1 << irqno));
 		}
 	} else
-		printk (KERN_WARNING "Wild interrupt from backplane (masks)\n");
+		printk(KERN_WARNING "Wild interrupt from backplane (masks)\n");
 }
 
-static int ecard_checkirqhw (void)
+static int ecard_checkirqhw(void)
 {
 	int found;
 
@@ -267,7 +287,7 @@
 }
 #endif
 
-static void ecard_readbytes (void *addr, ecard_t *ec, int off, int len, int useld)
+static void ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
 {
 	extern int ecard_loader_read(int off, volatile unsigned int pa, loader_t loader);
 	unsigned char *a = (unsigned char *)addr;
@@ -287,7 +307,7 @@
 		 * If we require a low address or address 0, then reset, and start again...
 		 */
 		if (!off || lowaddress > laddr) {
-			outb (0, ec->podaddr);
+			outb(0, ec->podaddr);
 			lowaddress = 0;
 		}
 		while (lowaddress <= laddr) {
@@ -314,15 +334,136 @@
 	}
 }
 
+static int ecard_prints(char *buffer, ecard_t *ec)
+{
+	char *start = buffer;
+
+	buffer += sprintf(buffer, "\n  %d: ", ec->slot_no);
+
+	if (ec->cid.id == 0) {
+		struct in_chunk_dir incd;
+
+		buffer += sprintf(buffer, "[%04X:%04X] ",
+			ec->cid.manufacturer, ec->cid.product);
+
+		if (!ec->card_desc && ec->cid.is && ec->cid.cd &&
+		    ecard_readchunk(&incd, ec, 0xf5, 0))
+			ec->card_desc = incd.d.string;
+
+		if (!ec->card_desc)
+			ec->card_desc = "*unknown*";
+
+		buffer += sprintf(buffer, "%s", ec->card_desc);
+	} else
+		buffer += sprintf(buffer, "Simple card %d", ec->cid.id);
+
+	return buffer - start;
+}
+
+static inline unsigned short ecard_getu16(unsigned char *v)
+{
+	return v[0] | v[1] << 8;
+}
+
+static inline signed long ecard_gets24(unsigned char *v)
+{
+	return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
+}
+
+/*
+ * Probe for an expansion card.
+ *
+ * If bit 1 of the first byte of the card is set, then the
+ * card does not exist.
+ */
+__initfunc(static int ecard_probe(int card, int freeslot, card_type_t type))
+{
+	ecard_t *ec = expcard + freeslot;
+	struct ex_ecid cid;
+	char buffer[200];
+	int i;
+
+	irqno_to_expcard[card] = -1;
+
+	ec->slot_no	= card;
+	ec->irq		= NO_IRQ;
+	ec->fiq		= NO_IRQ;
+	ec->dma		= NO_DMA;
+	ec->card_desc	= NULL;
+	ec->ops		= &ecard_default_ops;
+
+	if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0)
+		return 0;
+
+	cid.r_zero = 1;
+	ecard_readbytes(&cid, ec, 0, 16, 0);
+	if (cid.r_zero)
+		return 0;
+
+	irqno_to_expcard[card] = freeslot;
+
+	ec->type	= type;
+	ec->cid.id	= cid.r_id;
+	ec->cid.cd	= cid.r_cd;
+	ec->cid.is	= cid.r_is;
+	ec->cid.w	= cid.r_w;
+	ec->cid.manufacturer = ecard_getu16(cid.r_manu);
+	ec->cid.product = ecard_getu16(cid.r_prod);
+	ec->cid.country = cid.r_country;
+	ec->cid.irqmask = cid.r_irqmask;
+	ec->cid.irqoff  = ecard_gets24(cid.r_irqoff);
+	ec->cid.fiqmask = cid.r_fiqmask;
+	ec->cid.fiqoff  = ecard_gets24(cid.r_fiqoff);
+	ec->fiqaddr	=
+	ec->irqaddr	= (unsigned char *)BUS_ADDR(ec->podaddr);
+
+	if (ec->cid.cd && ec->cid.is) {
+		ec->irqmask = ec->cid.irqmask;
+		ec->irqaddr += ec->cid.irqoff;
+		ec->fiqmask = ec->cid.fiqmask;
+		ec->fiqaddr += ec->cid.fiqoff;
+	} else {
+		ec->irqmask = 1;
+		ec->fiqmask = 4;
+	}
+
+	for (i = 0; i < sizeof(blacklist) / sizeof(*blacklist); i++)
+		if (blacklist[i].manufacturer == ec->cid.manufacturer &&
+		    blacklist[i].product == ec->cid.product) {
+			ec->loader = blacklist[i].loader;
+			ec->card_desc = blacklist[i].type;
+			break;
+		}
+
+	ecard_prints(buffer, ec);
+	printk("%s", buffer);
+
+	ec->irq = 32 + card;
+#ifdef IO_EC_MEMC8_BASE
+	if (card == 8)
+		ec->irq = 11;
+#endif
+#ifdef CONFIG_ARCH_RPC
+	/* On RiscPC, only first two slots have DMA capability */
+	if (card < 2)
+		ec->dma = 2 + card;
+#endif
+#if 0	/* We don't support FIQs on expansion cards at the moment */
+	ec->fiq = 96 + card;
+#endif
+
+	return 1;
+}
+
 /*
  * This is called to reset the loaders for each expansion card on reboot.
  *
  * This is required to make sure that the card is in the correct state
  * that RiscOS expects it to be.
  */
-void ecard_reset (int card)
+void ecard_reset(int card)
 {
-	extern int ecard_loader_reset (volatile unsigned int pa, loader_t loader);
+	extern int ecard_loader_reset(volatile unsigned int pa, loader_t loader);
 
 	if (card >= ecard_numcards)
 		return;
@@ -330,11 +471,11 @@
 	if (card < 0) {
 		for (card = 0; card < ecard_numcards; card++)
 			if (expcard[card].loader)
-				ecard_loader_reset (BUS_ADDR(expcard[card].podaddr),
+				ecard_loader_reset(BUS_ADDR(expcard[card].podaddr),
 							expcard[card].loader);
 	} else
 		if (expcard[card].loader)
-			ecard_loader_reset (BUS_ADDR(expcard[card].podaddr),
+			ecard_loader_reset(BUS_ADDR(expcard[card].podaddr),
 						expcard[card].loader);
 
 #ifdef HAS_EXPMASK
@@ -347,18 +488,19 @@
 
 static unsigned int ecard_startcard;
 
-void ecard_startfind (void)
+void ecard_startfind(void)
 {
 	ecard_startcard = 0;
 }
 
-ecard_t *ecard_find (int cld, const card_ids *cids)
+ecard_t *ecard_find(int cid, const card_ids *cids)
 {
 	int card;
+
 	if (!cids) {
 		for (card = ecard_startcard; card < ecard_numcards; card++)
 			if (!expcard[card].claimed &&
-			    ((expcard[card].cld.ecld ^ cld) & 0x78) == 0)
+			    (expcard[card].cid.id ^ cid) == 0)
 				break;
 	} else {
 		for (card = ecard_startcard; card < ecard_numcards; card++) {
@@ -368,8 +510,8 @@
 			if (expcard[card].claimed)
 				continue;
 
-			manufacturer = expcard[card].cld.manufacturer;
-			product = expcard[card].cld.product;
+			manufacturer = expcard[card].cid.manufacturer;
+			product = expcard[card].cid.product;
 
 			for (i = 0; cids[i].manufacturer != 65535; i++)
 				if (manufacturer == cids[i].manufacturer &&
@@ -380,16 +522,21 @@
 				break;
 		}
 	}
+
 	ecard_startcard = card + 1;
+
 	return card < ecard_numcards ? &expcard[card] : NULL;
 }
 
-int ecard_readchunk (struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
+int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
 {
 	struct ex_chunk_dir excd;
 	int index = 16;
 	int useld = 0;
 
+	if (!ec->cid.is || !ec->cid.cd)
+		return 0;
+
 	while(1) {
 		ecard_readbytes(&excd, ec, index, 8, useld);
 		index += 8;
@@ -427,124 +574,49 @@
 		}
 	}
 	cd->start_offset = c_start(&excd);
-	memcpy (cd->d.string, excd.d.string, 256);
+	memcpy(cd->d.string, excd.d.string, 256);
 	return 1;
 }
 
-unsigned int ecard_address (ecard_t *ec, card_type_t type, card_speed_t speed)
+unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
 {
 	switch (ec->slot_no) {
 	case 0 ... 3:
 		switch (type) {
 		case ECARD_MEMC:
-			return MEMCECIO_BASE + (ec->slot_no << 12);
+			return IO_EC_MEMC_BASE + (ec->slot_no << 12);
 
 		case ECARD_IOC:
-			return IOCECIO_BASE + (speed << 17) + (ec->slot_no << 12);
+			return IO_EC_IOC_BASE + (speed << 17) + (ec->slot_no << 12);
 
-		default:
-			return 0;
+#ifdef IO_EC_EASI_BASE
+		case ECARD_EASI:
+			return IO_EC_EASI_BASE + (ec->slot_no << 22);
+#endif
 		}
+		break;
 
-#ifdef IOCEC4IO_BASE
 	case 4 ... 7:
-		if (type != ECARD_IOC)
-			return 0;
-
-		return IOCEC4IO_BASE + (speed << 17) + ((ec->slot_no - 4) << 12);
+		switch (type) {
+#ifdef IO_EC_IOC4_BASE
+		case ECARD_IOC:
+			return IO_EC_IOC4_BASE + (speed << 17) + ((ec->slot_no - 4) << 12);
 #endif
-#ifdef MEMCEC8IO_BASE
-	case 8:
-		return MEMCEC8IO_BASE;
+#ifdef IO_EC_EASI_BASE
+		case ECARD_EASI:
+			return IO_EC_EASI_BASE + (ec->slot_no << 22);
 #endif
-	}
-	return 0;
-}
-
-/*
- * Probe for an expansion card.
- *
- * If bit 1 of the first byte of the card is set,
- * then the card does not exist.
- */
-__initfunc(static int ecard_probe (int card, int freeslot))
-{
-	ecard_t *ec = expcard + freeslot;
-	struct ex_ecld excld;
-	const char *card_desc = NULL;
-	int i;
-
-	irqno_to_expcard[card] = -1;
-
-	ec->slot_no = card;
-	if ((ec->podaddr = ecard_address (ec, ECARD_IOC, ECARD_SYNC)) == 0)
-		return 0;
-
-	excld.r_ecld = 2;
-	ecard_readbytes (&excld, ec, 0, 16, 0);
-	if (excld.r_ecld & 2)
-		return 0;
-
-	irqno_to_expcard[card] = freeslot;
-
-	ec->irq = NO_IRQ;
-	ec->fiq = NO_IRQ;
-	ec->dma = NO_DMA;
-	ec->cld.ecld = e_ecld(&excld);
-	ec->cld.manufacturer = e_manu(&excld);
-	ec->cld.product = e_prod(&excld);
-	ec->cld.country = e_country(&excld);
-	ec->cld.fiqmask = e_fiqmask(&excld);
-	ec->cld.irqmask = e_irqmask(&excld);
-	ec->cld.fiqaddr = e_fiqaddr(&excld);
-	ec->cld.irqaddr = e_irqaddr(&excld);
-	ec->fiqaddr =
-	ec->irqaddr = (unsigned char *)BUS_ADDR(ec->podaddr);
-	ec->fiqmask = 4;
-	ec->irqmask = 1;
-	ec->ops = &ecard_default_ops;
-
-	for (i = 0; i < sizeof (blacklist) / sizeof (*blacklist); i++)
-		if (blacklist[i].manufacturer == ec->cld.manufacturer &&
-		    blacklist[i].product == ec->cld.product) {
-			ec->loader = blacklist[i].loader;
-			card_desc = blacklist[i].type;
+		default:
 			break;
 		}
+		break;
 
-	ec->irq = 32 + card;
-#if 0
-	/* We don't support FIQs on expansion cards at the moment */
-	ec->fiq = 96 + card;
-#endif
-#ifdef CONFIG_ARCH_RPC
-	if (card != 8) {
-		/* On RiscPC, only first two slots have DMA capability
-		 */
-		if (card < 2)
-			ec->dma = 2 + card;
-	} else
-		ec->irq = 11;
+#ifdef IO_EC_MEMC8_BASE
+	case 8:
+		return IO_EC_MEMC8_BASE;
 #endif
-
-	if ((ec->cld.ecld & 0x78) == 0) {
-		struct in_chunk_dir incd;
-		printk ("\n  %d: [%04X:%04X] ", card, ec->cld.manufacturer, ec->cld.product);
-		if (e_is (&excld)) {
-			ec->fiqmask = e_fiqmask (&excld);
-			ec->irqmask = e_irqmask (&excld);
-			ec->fiqaddr += e_fiqaddr (&excld);
-			ec->irqaddr += e_irqaddr (&excld);
-		}
-		if (!card_desc && e_cd (&excld) && ecard_readchunk (&incd, ec, 0xf5, 0))
-			card_desc = incd.d.string;
-		if (card_desc)
-			printk ("%s", card_desc);
-		else
-			printk ("*Unknown*");
-	} else
-		printk("\n  %d: Simple card %d\n", card, (ec->cld.ecld >> 3) & 15);
-	return 1;
+	}
+	return 0;
 }
 
 static struct irqaction irqexpansioncard = {
@@ -565,11 +637,11 @@
 {
 	int i, nc = 0;
 
-	memset (expcard, 0, sizeof (expcard));
+	memset(expcard, 0, sizeof(expcard));
 
 #ifdef HAS_EXPMASK
 	if (ecard_checkirqhw()) {
-		printk (KERN_DEBUG "Expansion card interrupt management hardware found\n");
+		printk(KERN_DEBUG "Expansion card interrupt management hardware found\n");
 		irqexpansioncard.handler = ecard_irq_expmask;
 		irqexpansioncard.flags |= SA_IRQNOMASK;
 		have_expmask = -1;
@@ -581,8 +653,8 @@
 	/*
 	 * First of all, probe all cards on the expansion card interrupt line
 	 */
-	for (i = 0; i < 4; i++)
-		if (ecard_probe (i, nc))
+	for (i = 0; i < 8; i++)
+		if (ecard_probe(i, nc, ECARD_IOC) || ecard_probe(i, nc, ECARD_EASI))
 			nc += 1;
 		else
 			have_expmask &= ~(1<<i);
@@ -591,8 +663,8 @@
 
 	/* Now probe other cards with different interrupt lines
 	 */
-#ifdef MEMCEC8IO_BASE
-	if (ecard_probe (8, nc))
+#ifdef IO_EC_MEMC8_BASE
+	if (ecard_probe(8, nc, ECARD_IOC))
 		nc += 1;
 #endif
 
@@ -600,7 +672,7 @@
 	ecard_numcards = nc;
 
 	if (nc && setup_arm_irq(IRQ_EXPANSIONCARD, &irqexpansioncard)) {
-		printk ("Could not allocate interrupt for expansion cards\n");
+		printk("Could not allocate interrupt for expansion cards\n");
 		return;
 	}
 	
@@ -609,5 +681,5 @@
 		EXPMASK_ENABLE = have_expmask;
 #endif
 
-	oldlatch_init ();
+	oldlatch_init();
 }

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