aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ata/ata-cbus.c
diff options
context:
space:
mode:
authorSøren Schmidt <sos@FreeBSD.org>2004-10-06 19:46:08 +0000
committerSøren Schmidt <sos@FreeBSD.org>2004-10-06 19:46:08 +0000
commit6192895db835a1e9a34444ca69db66565715f77f (patch)
tree35505cebf9f8bde09fbc920edb9ffd9f8f06201f /sys/dev/ata/ata-cbus.c
parentdd12956ac7c81cacd8408c302f1f200b19f32bab (diff)
downloadsrc-6192895db835a1e9a34444ca69db66565715f77f.tar.gz
src-6192895db835a1e9a34444ca69db66565715f77f.zip
Fix the PC98 lockups on boot.
The interchannel locking for PC98 needed to be updated to match the rest of the locking in ATA.
Notes
Notes: svn path=/head/; revision=136198
Diffstat (limited to 'sys/dev/ata/ata-cbus.c')
-rw-r--r--sys/dev/ata/ata-cbus.c59
1 files changed, 42 insertions, 17 deletions
diff --git a/sys/dev/ata/ata-cbus.c b/sys/dev/ata/ata-cbus.c
index cb5c160ce331..925b30f04fbc 100644
--- a/sys/dev/ata/ata-cbus.c
+++ b/sys/dev/ata/ata-cbus.c
@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/malloc.h>
#include <sys/module.h>
+#include <sys/conf.h>
#include <sys/sema.h>
#include <sys/taskqueue.h>
#include <vm/uma.h>
@@ -54,8 +55,10 @@ struct ata_cbus_controller {
struct resource *irq;
void *ih;
void (*setmode)(struct ata_device *, int);
- void (*locking)(struct ata_channel *, int);
+ int (*locking)(struct ata_channel *, int);
+ struct mtx bank_mtx;
int current_bank;
+ int restart_bank;
struct {
void (*function)(void *);
void *argument;
@@ -64,7 +67,7 @@ struct ata_cbus_controller {
/* local prototypes */
static void ata_cbus_intr(void *);
-static void ata_cbus_banking(struct ata_channel *, int);
+static int ata_cbus_banking(struct ata_channel *, int);
static void ata_cbus_setmode(struct ata_device *, int);
static int
@@ -158,8 +161,10 @@ ata_cbus_attach(device_t dev)
return ENXIO;
}
- ctlr->locking = ata_cbus_banking;
+ mtx_init(&ctlr->bank_mtx, "ATA cbus bank lock", NULL, MTX_DEF);
ctlr->current_bank = -1;
+ ctlr->restart_bank = -1;
+ ctlr->locking = ata_cbus_banking;
ctlr->setmode = ata_cbus_setmode;;
if (!device_add_child(dev, "ata", 0))
@@ -220,35 +225,55 @@ static void
ata_cbus_intr(void *data)
{
struct ata_cbus_controller *ctlr = data;
-
- if (ctlr->current_bank != -1 &&
- ctlr->interrupt[ctlr->current_bank].argument)
- ctlr->interrupt[ctlr->current_bank].
- function(ctlr->interrupt[ctlr->current_bank].argument);
+ struct ata_channel *ch;
+ int unit;
+
+ for (unit = 0; unit < 2; unit++) {
+ if (!(ch = ctlr->interrupt[unit].argument))
+ continue;
+ if (ch->locking(ch, ATA_LF_WHICH) == unit)
+ ctlr->interrupt[unit].function(ch);
+ }
}
-static void
+static int
ata_cbus_banking(struct ata_channel *ch, int flags)
{
struct ata_cbus_controller *ctlr =
device_get_softc(device_get_parent(ch->dev));
+ int res;
+ mtx_lock(&ctlr->bank_mtx);
switch (flags) {
case ATA_LF_LOCK:
+ if (ctlr->current_bank == -1)
+ ctlr->current_bank = ch->unit;
if (ctlr->current_bank == ch->unit)
- break;
- while (!atomic_cmpset_acq_int(&ctlr->current_bank, -1, ch->unit))
- tsleep((caddr_t)ch->locking, PRIBIO, "atabnk", 1);
- ATA_OUTB(ctlr->bankio, 0, ch->unit);
+ ATA_OUTB(ctlr->bankio, 0, ch->unit);
+ else
+ ctlr->restart_bank = ch->unit;
break;
case ATA_LF_UNLOCK:
- if (ctlr->current_bank == -1 || ctlr->current_bank != ch->unit)
- break;
- atomic_store_rel_int(&ctlr->current_bank, -1);
+ if (ctlr->current_bank == ch->unit) {
+ ctlr->current_bank = -1;
+ if (ctlr->restart_bank != -1) {
+ if (ctlr->interrupt[ctlr->restart_bank].argument) {
+ mtx_unlock(&ctlr->bank_mtx);
+ ata_start(ctlr->interrupt[ctlr->restart_bank].argument);
+ mtx_lock(&ctlr->bank_mtx);
+ }
+ ctlr->restart_bank = -1;
+ }
+ }
+ break;
+
+ case ATA_LF_WHICH:
break;
}
- return;
+ res = ctlr->current_bank;
+ mtx_unlock(&ctlr->bank_mtx);
+ return res;
}
static void