diff options
author | sos <sos@FreeBSD.org> | 2004-10-06 19:46:08 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2004-10-06 19:46:08 +0000 |
commit | 96967ead83ac146ed77418a53a20c0426c6e3509 (patch) | |
tree | 35505cebf9f8bde09fbc920edb9ffd9f8f06201f /sys/dev/ata | |
parent | 49a5dba557356d7fa1c24a370083976174461d4c (diff) | |
download | FreeBSD-src-96967ead83ac146ed77418a53a20c0426c6e3509.zip FreeBSD-src-96967ead83ac146ed77418a53a20c0426c6e3509.tar.gz |
Fix the PC98 lockups on boot.
The interchannel locking for PC98 needed to be updated to match the
rest of the locking in ATA.
Diffstat (limited to 'sys/dev/ata')
-rw-r--r-- | sys/dev/ata/ata-all.c | 14 | ||||
-rw-r--r-- | sys/dev/ata/ata-all.h | 5 | ||||
-rw-r--r-- | sys/dev/ata/ata-card.c | 3 | ||||
-rw-r--r-- | sys/dev/ata/ata-cbus.c | 59 | ||||
-rw-r--r-- | sys/dev/ata/ata-chipset.c | 62 | ||||
-rw-r--r-- | sys/dev/ata/ata-isa.c | 3 | ||||
-rw-r--r-- | sys/dev/ata/ata-pci.c | 5 | ||||
-rw-r--r-- | sys/dev/ata/ata-pci.h | 37 | ||||
-rw-r--r-- | sys/dev/ata/ata-queue.c | 17 |
9 files changed, 135 insertions, 70 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index 1c4b0d6..6bc631d 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -138,7 +138,8 @@ ata_attach(device_t dev) mtx_init(&ch->state_mtx, "ATA state lock", NULL, MTX_DEF); /* initialise device(s) on this channel */ - ch->locking(ch, ATA_LF_LOCK); + while (ch->locking(ch, ATA_LF_LOCK) != ch->unit) + tsleep(&error, PRIBIO, "ataatch", 1); ch->hw.reset(ch); ch->locking(ch, ATA_LF_UNLOCK); @@ -243,6 +244,10 @@ ata_reinit(struct ata_channel *ch) if (bootverbose) ata_printf(ch, -1, "reiniting channel ..\n"); + /* poll for locking of this channel */ + while (ch->locking(ch, ATA_LF_LOCK) != ch->unit) + tsleep(&devices, PRIBIO, "atarint", 1); + /* grap the channel lock no matter what */ mtx_lock(&ch->state_mtx); ch->state = ATA_ACTIVE; @@ -321,6 +326,7 @@ ata_reinit(struct ata_channel *ch) mtx_lock(&ch->state_mtx); ch->state = ATA_IDLE; mtx_unlock(&ch->state_mtx); + ch->locking(ch, ATA_LF_UNLOCK); ata_start(ch); return 0; @@ -335,8 +341,6 @@ ata_suspend(device_t dev) if (!dev || !(ch = device_get_softc(dev))) return ENXIO; - ch->locking(ch, ATA_LF_LOCK); - while (!gotit) { mtx_lock(&ch->state_mtx); if (ch->state == ATA_IDLE) { @@ -346,6 +350,7 @@ ata_suspend(device_t dev) tsleep(&gotit, PRIBIO, "atasusp", hz/10); mtx_unlock(&ch->state_mtx); } + ch->locking(ch, ATA_LF_UNLOCK); return 0; } @@ -358,9 +363,7 @@ ata_resume(device_t dev) if (!dev || !(ch = device_get_softc(dev))) return ENXIO; - ch->locking(ch, ATA_LF_LOCK); error = ata_reinit(ch); - ch->locking(ch, ATA_LF_UNLOCK); ata_start(ch); return error; } @@ -433,6 +436,7 @@ ata_interrupt(void *data) else ch->state = ATA_IDLE; mtx_unlock(&ch->state_mtx); + ch->locking(ch, ATA_LF_UNLOCK); ata_finish(request); } } diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index e44ac1a..e12b579 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -366,10 +366,11 @@ struct ata_channel { #define ATA_INTERRUPT 0x0002 #define ATA_TIMEOUT 0x0004 - void (*reset)(struct ata_channel *); - void (*locking)(struct ata_channel *, int); + void (*reset)(struct ata_channel *); + int (*locking)(struct ata_channel *, int); #define ATA_LF_LOCK 0x0001 #define ATA_LF_UNLOCK 0x0002 +#define ATA_LF_WHICH 0x0004 struct mtx queue_mtx; /* queue lock */ TAILQ_HEAD(, ata_request) ata_queue; /* head of ATA queue */ diff --git a/sys/dev/ata/ata-card.c b/sys/dev/ata/ata-card.c index 118c818..68d8bde 100644 --- a/sys/dev/ata/ata-card.c +++ b/sys/dev/ata/ata-card.c @@ -88,9 +88,10 @@ ata_pccard_match(device_t dev) return(ENXIO); } -static void +static int ata_pccard_locknoop(struct ata_channel *ch, int type) { + return 1; } static void diff --git a/sys/dev/ata/ata-cbus.c b/sys/dev/ata/ata-cbus.c index cb5c160..925b30f 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 diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c index b10fab6..4a56f73 100644 --- a/sys/dev/ata/ata-chipset.c +++ b/sys/dev/ata/ata-chipset.c @@ -120,7 +120,7 @@ static int ata_check_80pin(struct ata_device *, int); static struct ata_chip_id *ata_find_chip(device_t, struct ata_chip_id *, int); static struct ata_chip_id *ata_match_chip(device_t, struct ata_chip_id *); static int ata_setup_interrupt(device_t); -static void ata_serialize(struct ata_channel *, int); +static int ata_serialize(struct ata_channel *, int); static int ata_mode2idx(int); /* generic or unknown ATA chipset init code */ @@ -261,10 +261,10 @@ ata_acard_intr(void *data) /* implement this as a toggle instead to balance load XXX */ for (unit = 0; unit < 2; unit++) { - if (ctlr->chip->cfg1 == ATPOLD && ctlr->locked_ch != unit) - continue; if (!(ch = ctlr->interrupt[unit].argument)) continue; + if (ctlr->chip->cfg1 == ATPOLD && ch->locking(ch, ATA_LF_WHICH) != unit) + continue; if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; @@ -2797,28 +2797,62 @@ ata_setup_interrupt(device_t dev) return 0; } -static void +struct ata_serialize { + struct mtx locked_mtx; + int locked_ch; + int restart_ch; +}; + +static int ata_serialize(struct ata_channel *ch, int flags) { - struct ata_pci_controller *scp = + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(ch->dev)); + struct ata_serialize *serial; + static int inited = 0; + int res; + + if (!inited) { + ctlr->driver = malloc(sizeof(struct ata_serialize), + M_TEMP, M_NOWAIT | M_ZERO); + serial = ctlr->driver; + mtx_init(&serial->locked_mtx, "ATA serialize lock", NULL, MTX_DEF); + serial->locked_ch = -1; + serial->restart_ch = -1; + inited = 1; + } + else + serial = ctlr->driver; + mtx_lock(&serial->locked_mtx); switch (flags) { case ATA_LF_LOCK: - if (scp->locked_ch == ch->unit) - break; - while (!atomic_cmpset_acq_int(&scp->locked_ch, -1, ch->unit)) - tsleep(ch->locking, PRIBIO, "atasrl", 1); + if (serial->locked_ch == -1) + serial->locked_ch = ch->unit; + if (serial->locked_ch != ch->unit) + serial->restart_ch = ch->unit; break; case ATA_LF_UNLOCK: - if (scp->locked_ch == -1 || scp->locked_ch != ch->unit) - break; - atomic_store_rel_int(&scp->locked_ch, -1); - wakeup(ch->locking); + if (serial->locked_ch == ch->unit) { + serial->locked_ch = -1; + if (serial->restart_ch != -1) { + if (ctlr->interrupt[serial->restart_ch].argument) { + mtx_unlock(&serial->locked_mtx); + ata_start(ctlr->interrupt[serial->restart_ch].argument); + mtx_lock(&serial->locked_mtx); + } + serial->restart_ch = -1; + } + } + break; + + case ATA_LF_WHICH: break; } - return; + res = serial->locked_ch; + mtx_unlock(&serial->locked_mtx); + return res; } static int diff --git a/sys/dev/ata/ata-isa.c b/sys/dev/ata/ata-isa.c index e793643..4fadd2d 100644 --- a/sys/dev/ata/ata-isa.c +++ b/sys/dev/ata/ata-isa.c @@ -58,9 +58,10 @@ static struct isa_pnp_id ata_ids[] = { {0} }; -static void +static int ata_isa_locknoop(struct ata_channel *ch, int type) { + return ch->unit; } static void diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c index 416afbe..b5d7388 100644 --- a/sys/dev/ata/ata-pci.c +++ b/sys/dev/ata/ata-pci.c @@ -60,7 +60,7 @@ static MALLOC_DEFINE(M_ATAPCI, "ATA PCI", "ATA driver PCI"); /* prototypes */ static int ata_pci_allocate(device_t, struct ata_channel *); static void ata_pci_dmainit(struct ata_channel *); -static void ata_pci_locknoop(struct ata_channel *, int); +static int ata_pci_locknoop(struct ata_channel *, int); int ata_legacy(device_t dev) @@ -467,9 +467,10 @@ ata_pci_dmainit(struct ata_channel *ch) } } -static void +static int ata_pci_locknoop(struct ata_channel *ch, int flags) { + return ch->unit; } static device_method_t ata_pci_methods[] = { diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h index 1ffb7c7..0dc6787 100644 --- a/sys/dev/ata/ata-pci.h +++ b/sys/dev/ata/ata-pci.h @@ -30,38 +30,37 @@ /* structure holding chipset config info */ struct ata_chip_id { - u_int32_t chipid; - u_int8_t chiprev; - int cfg1; - int cfg2; - u_int8_t max_dma; + u_int32_t chipid; + u_int8_t chiprev; + int cfg1; + int cfg2; + u_int8_t max_dma; char *text; }; /* structure describing a PCI ATA controller */ struct ata_pci_controller { - int r_type1; - int r_rid1; - struct resource *r_res1; - int r_type2; - int r_rid2; - struct resource *r_res2; - struct resource *r_irq; - void *handle; - struct ata_chip_id *chip; + int r_type1; + int r_rid1; + struct resource *r_res1; + int r_type2; + int r_rid2; + struct resource *r_res2; + struct resource *r_irq; + void *handle; + struct ata_chip_id *chip; + int channels; int (*chipinit)(device_t); int (*allocate)(device_t, struct ata_channel *); void (*reset)(struct ata_channel *); void (*dmainit)(struct ata_channel *); void (*setmode)(struct ata_device *, int); - void (*locking)(struct ata_channel *, int); - int locked_ch; - int channels; + int (*locking)(struct ata_channel *, int); struct { void (*function)(void *); - void *argument; + void *argument; } interrupt[8]; /* SOS max ch# for now XXX */ - void *driver; + void *driver; }; /* defines for known chipset PCI id's */ diff --git a/sys/dev/ata/ata-queue.c b/sys/dev/ata/ata-queue.c index fb77e83..ac9b578 100644 --- a/sys/dev/ata/ata-queue.c +++ b/sys/dev/ata/ata-queue.c @@ -176,13 +176,14 @@ ata_start(struct ata_channel *ch) /* if we have work todo, try to grap the ATA HW and start transaction */ if ((request = TAILQ_FIRST(&ch->ata_queue))) { - ch->locking(ch, ATA_LF_LOCK); - mtx_lock(&ch->state_mtx); - if (ch->state == ATA_IDLE) { - ch->state = ATA_ACTIVE; - gotit = 1; + if (ch->locking(ch, ATA_LF_LOCK) == ch->unit) { + mtx_lock(&ch->state_mtx); + if (ch->state == ATA_IDLE) { + ch->state = ATA_ACTIVE; + gotit = 1; + } + mtx_unlock(&ch->state_mtx); } - mtx_unlock(&ch->state_mtx); if (!gotit) { mtx_unlock(&ch->queue_mtx); return; @@ -203,8 +204,8 @@ ata_start(struct ata_channel *ch) mtx_lock(&ch->state_mtx); ch->state = ATA_IDLE; mtx_unlock(&ch->state_mtx); - ch->locking(ch, ATA_LF_UNLOCK); ata_finish(request); + ch->locking(ch, ATA_LF_UNLOCK); } } else @@ -412,8 +413,6 @@ ata_timeout(struct ata_request *request) /* mark request as no longer running we'll shoot it down shortly */ ch->running = NULL; - /* debug on */ - request->flags |= ATA_R_DEBUG; ATA_DEBUG_RQ(request, "timeout"); /* if we saw an interrupt before the timeout, shout and re_arm timeout */ |