patch-1.3.100 linux/drivers/block/ide.c
Next file: linux/drivers/block/ide.h
Previous file: linux/drivers/block/ide-cd.c
Back to the patch index
Back to the overall index
- Lines: 226
- Date:
Fri May 10 08:02:26 1996
- Orig file:
v1.3.99/linux/drivers/block/ide.c
- Orig date:
Sun May 5 08:51:59 1996
diff -u --recursive --new-file v1.3.99/linux/drivers/block/ide.c linux/drivers/block/ide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide.c Version 5.39 May 3, 1996
+ * linux/drivers/block/ide.c Version 5.41 May 9, 1996
*
* Copyright (C) 1994-1996 Linus Torvalds & authors (see below)
*/
@@ -231,6 +231,10 @@
* mask drive irq after use, if sharing with another hwif
* add code to help debug weird cmd640 problems
* Version 5.39 fix horrible error in earlier irq sharing "fix"
+ * Version 5.40 fix serialization -- was broken in 5.39
+ * help sharing by masking device irq after probing
+ * Version 5.41 more fixes to irq sharing/serialize detection
+ * disable io_32bit by default on drive reset
*
* Some additional driver compile-time options are in ide.h
*
@@ -705,8 +709,10 @@
/* For an ATAPI device, first try an ATAPI SRST. */
if (drive->media != ide_disk) {
if (!do_not_try_atapi) {
- if (!drive->keep_settings)
+ if (!drive->keep_settings) {
drive->unmask = 0;
+ drive->io_32bit = 0;
+ }
OUT_BYTE (drive->select.all, IDE_SELECT_REG);
udelay (20);
OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
@@ -732,6 +738,7 @@
if (!rdrive->keep_settings) {
rdrive->mult_req = 0;
rdrive->unmask = 0;
+ rdrive->io_32bit = 0;
if (rdrive->using_dma) {
rdrive->using_dma = 0;
printk("%s: disabled DMA\n", rdrive->name);
@@ -2376,8 +2383,11 @@
#if CONFIG_BLK_DEV_PROMISE
if (IS_PROMISE_DRIVE) {
- if(promise_cmd(drive,PROMISE_IDENTIFY))
+ if (promise_cmd(drive,PROMISE_IDENTIFY)) {
+ if (irqs)
+ (void) probe_irq_off(irqs);
return 1;
+ }
} else
#endif /* CONFIG_BLK_DEV_PROMISE */
OUT_BYTE(cmd,IDE_COMMAND_REG); /* ask drive for ID */
@@ -2385,7 +2395,7 @@
timeout += jiffies;
do {
if (jiffies > timeout) {
- if (!HWIF(drive)->irq)
+ if (irqs)
(void) probe_irq_off(irqs);
return 1; /* drive timed-out */
}
@@ -2409,10 +2419,13 @@
} else
rc = 2; /* drive refused ID */
if (!HWIF(drive)->irq) {
- irqs = probe_irq_off(irqs); /* get irq number */
- if (irqs > 0)
- HWIF(drive)->irq = irqs;
- else { /* Mmmm.. multiple IRQs */
+ irqs = probe_irq_off(irqs); /* get our irq number */
+ if (irqs > 0) {
+ HWIF(drive)->irq = irqs; /* save it for later */
+ irqs = probe_irq_on(); /* grab irqs, to ignore next edge */
+ OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* mask device irq */
+ (void) probe_irq_off(irqs); /* restore irqs again */
+ } else { /* Mmmm.. multiple IRQs.. don't know which was ours */
printk("%s: IRQ probe failed (%d)\n", drive->name, irqs);
#ifdef CONFIG_BLK_DEV_CMD640
if (HWIF(drive)->chipset == ide_cmd640) {
@@ -2998,11 +3011,40 @@
return 1;
}
+#if MAX_HWIFS > 1
+/*
+ * save_match() is used to simplify logic in init_irq() below.
+ *
+ * A loophole here is that we may not know about a particular
+ * hwif's irq until after that hwif is actually probed/initialized..
+ * This could be a problem for the case where an hwif is on a
+ * dual interface that requires serialization (eg. cmd640) and another
+ * hwif using one of the same irqs is initialized beforehand.
+ *
+ * This routine detects and reports such situations, but does not fix them.
+ */
+static void save_match (ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
+{
+ ide_hwif_t *m = *match;
+
+ if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
+ if (!new->hwgroup)
+ return;
+ printk("%s: potential irq problem with %s and %s\n", hwif->name, new->name, m->name);
+ }
+ if (m->irq != hwif->irq) /* don't undo a prior perfect match */
+ *match = new;
+}
+#endif /* MAX_HWIFS > 1 */
/*
* This routine sets up the irq for an ide interface, and creates a new
* hwgroup for the irq/hwif if none was previously assigned.
*
+ * Much of the code is for correctly detecting/handling irq sharing
+ * and irq serialization situations. This is somewhat complex because
+ * it handles static as well as dynamic (PCMCIA) IDE interfaces.
+ *
* The SA_INTERRUPT in sa_flags means ide_intr() is always entered with
* interrupts completely disabled. This can be bad for interrupt latency,
* but anything else has led to problems on some machines. We re-enable
@@ -3011,48 +3053,52 @@
static int init_irq (ide_hwif_t *hwif)
{
unsigned long flags;
- ide_hwgroup_t *hwgroup = hwif->hwgroup;
- ide_hwif_t *mate_hwif;
- unsigned int index, mate_irq = hwif->irq;
+ unsigned int index;
+ ide_hwgroup_t *hwgroup;
+ ide_hwif_t *match = NULL;
save_flags(flags);
cli();
+ hwif->hwgroup = NULL;
+#if MAX_HWIFS > 1
/*
- * Handle serialization, regardless of init sequence
- */
- mate_hwif = &ide_hwifs[hwif->index ^ 1];
- if (hwif->serialized && mate_hwif->present)
- mate_irq = mate_hwif->irq;
-
- /*
- * Group up with any other hwifs that share our irq(s)
+ * Group up with any other hwifs that share our irq(s).
*/
for (index = 0; index < MAX_HWIFS; index++) {
- if (index != hwif->index) {
- ide_hwif_t *h = &ide_hwifs[index];
- if (h->irq == hwif->irq || h->irq == mate_irq) {
+ ide_hwif_t *h = &ide_hwifs[index];
+ if (h->hwgroup) { /* scan only initialized hwif's */
+ if (hwif->irq == h->irq) {
hwif->sharing_irq = h->sharing_irq = 1;
- if (hwgroup && !h->hwgroup)
- h->hwgroup = hwgroup;
- else if (!hwgroup)
- hwgroup = h->hwgroup;
+ save_match(hwif, h, &match);
+ }
+ if (hwif->serialized) {
+ ide_hwif_t *mate = &ide_hwifs[hwif->index^1];
+ if (index == mate->index || h->irq == mate->irq)
+ save_match(hwif, h, &match);
+ }
+ if (h->serialized) {
+ ide_hwif_t *mate = &ide_hwifs[h->index^1];
+ if (hwif->irq == mate->irq)
+ save_match(hwif, h, &match);
}
}
}
-
+#endif /* MAX_HWIFS > 1 */
/*
* If we are still without a hwgroup, then form a new one
*/
- if (hwgroup == NULL) {
- hwgroup = kmalloc (sizeof(ide_hwgroup_t), GFP_KERNEL);
+ if (match) {
+ hwgroup = match->hwgroup;
+ } else {
+ hwgroup = kmalloc(sizeof(ide_hwgroup_t), GFP_KERNEL);
hwgroup->hwif = hwgroup->next_hwif = hwif->next = hwif;
hwgroup->rq = NULL;
hwgroup->handler = NULL;
if (hwif->drives[0].present)
- hwgroup->drive = &hwif->drives[0];
+ hwgroup->drive = &hwif->drives[0];
else
- hwgroup->drive = &hwif->drives[1];
+ hwgroup->drive = &hwif->drives[1];
hwgroup->poll_timeout = 0;
init_timer(&hwgroup->timer);
hwgroup->timer.function = &timer_expiry;
@@ -3062,16 +3108,13 @@
/*
* Allocate the irq, if not already obtained for another hwif
*/
- if (!hwif->got_irq) {
+ if (!match || match->irq != hwif->irq) {
if (request_irq(hwif->irq, ide_intr, SA_INTERRUPT|SA_SAMPLE_RANDOM, hwif->name, hwgroup)) {
+ if (!match)
+ kfree(hwgroup);
restore_flags(flags);
return 1;
}
- for (index = 0; index < MAX_HWIFS; index++) {
- ide_hwif_t *g = &ide_hwifs[index];
- if (g->irq == hwif->irq)
- g->got_irq = 1;
- }
}
/*
@@ -3085,8 +3128,8 @@
printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name,
hwif->io_base, hwif->io_base+7, hwif->ctl_port, hwif->irq);
- if (hwgroup->hwif != hwif)
- printk(" (serialized with %s)", hwgroup->hwif->name);
+ if (match)
+ printk(" (%sed with %s)", hwif->sharing_irq ? "shar" : "serializ", match->name);
printk("\n");
return 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this