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
- Lines: 618
- Date:
Thu Dec 17 09:05:42 1998
- Orig file:
v2.1.131/linux/arch/arm/kernel/ecard.c
- Orig date:
Wed Sep 9 14:51:04 1998
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