diff options
author | Søren Schmidt <sos@FreeBSD.org> | 2004-10-06 19:46:08 +0000 |
---|---|---|
committer | Søren Schmidt <sos@FreeBSD.org> | 2004-10-06 19:46:08 +0000 |
commit | 6192895db835a1e9a34444ca69db66565715f77f (patch) | |
tree | 35505cebf9f8bde09fbc920edb9ffd9f8f06201f /sys/dev/ata/ata-cbus.c | |
parent | dd12956ac7c81cacd8408c302f1f200b19f32bab (diff) | |
download | src-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.c | 59 |
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 |