summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2004-10-06 19:46:08 +0000
committersos <sos@FreeBSD.org>2004-10-06 19:46:08 +0000
commit96967ead83ac146ed77418a53a20c0426c6e3509 (patch)
tree35505cebf9f8bde09fbc920edb9ffd9f8f06201f /sys
parent49a5dba557356d7fa1c24a370083976174461d4c (diff)
downloadFreeBSD-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')
-rw-r--r--sys/dev/ata/ata-all.c14
-rw-r--r--sys/dev/ata/ata-all.h5
-rw-r--r--sys/dev/ata/ata-card.c3
-rw-r--r--sys/dev/ata/ata-cbus.c59
-rw-r--r--sys/dev/ata/ata-chipset.c62
-rw-r--r--sys/dev/ata/ata-isa.c3
-rw-r--r--sys/dev/ata/ata-pci.c5
-rw-r--r--sys/dev/ata/ata-pci.h37
-rw-r--r--sys/dev/ata/ata-queue.c17
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 */
OpenPOWER on IntegriCloud