Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/pci Separate the AEN fetching path into its own spec...
details: https://anonhg.NetBSD.org/src/rev/6834d4184a21
branches: trunk
changeset: 552358:6834d4184a21
user: thorpej <thorpej%NetBSD.org@localhost>
date: Tue Sep 23 23:08:54 2003 +0000
description:
Separate the AEN fetching path into its own special path that uses the
reserved CCB. This means that all remaining callers of twe_param_get*()
are called from a valid thread context, and thus have no need to use a
reserved CCB. This will allow for further cleanup in a future commit.
diffstat:
sys/dev/pci/twe.c | 141 +++++++++++++++++++++++++++++++++++++++++++-------
sys/dev/pci/twevar.h | 5 +-
2 files changed, 123 insertions(+), 23 deletions(-)
diffs (truncated from 319 to 300 lines):
diff -r 63e1a939ae01 -r 6834d4184a21 sys/dev/pci/twe.c
--- a/sys/dev/pci/twe.c Tue Sep 23 23:07:35 2003 +0000
+++ b/sys/dev/pci/twe.c Tue Sep 23 23:08:54 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: twe.c,v 1.46 2003/09/22 18:31:11 thorpej Exp $ */
+/* $NetBSD: twe.c,v 1.47 2003/09/23 23:08:54 thorpej Exp $ */
/*-
* Copyright (c) 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: twe.c,v 1.46 2003/09/22 18:31:11 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: twe.c,v 1.47 2003/09/23 23:08:54 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -98,6 +98,7 @@
#define PCI_CBIO 0x10
+static int twe_aen_get(struct twe_softc *, uint16_t *);
static void twe_aen_handler(struct twe_ccb *, int);
static void twe_aen_enqueue(struct twe_softc *sc, uint16_t, int);
static uint16_t twe_aen_dequeue(struct twe_softc *);
@@ -303,7 +304,7 @@
pci_intr_handle_t ih;
pcireg_t csr;
const char *intrstr;
- int size, i, rv, rseg;
+ int s, size, i, rv, rseg;
size_t max_segs, max_xfer;
bus_dma_segment_t seg;
struct twe_cmd *tc;
@@ -412,7 +413,8 @@
sc->sc_dv.dv_xname, rv);
return;
}
- /* Save one CCB for parameter retrieval. */
+
+ /* Save the first CCB for AEN retrieval. */
if (i != 0)
SLIST_INSERT_HEAD(&sc->sc_ccb_freelist, ccb,
ccb_chain.slist);
@@ -428,7 +430,10 @@
twe_outl(sc, TWE_REG_CTL, TWE_CTL_DISABLE_INTRS);
/* Reset the controller. */
- if (twe_reset(sc)) {
+ s = splbio();
+ rv = twe_reset(sc);
+ splx(s);
+ if (rv) {
aprint_error("%s: reset failed\n", sc->sc_dv.dv_xname);
return;
}
@@ -614,8 +619,8 @@
}
/*
- * Reset the controller. Currently only useful at attach time; must be
- * called with interrupts blocked.
+ * Reset the controller.
+ * MUST BE CALLED AT splbio()!
*/
static int
twe_reset(struct twe_softc *sc)
@@ -649,9 +654,9 @@
* Open code this, since we want to detect reset even if the
* queue for management tools is full.
*/
+ sc->sc_flags &= ~TWEF_AEN;
for (got = 0;;) {
- rv = twe_param_get_2(sc, TWE_PARAM_AEN, TWE_PARAM_AEN_UnitCode,
- &aen);
+ rv = twe_aen_get(sc, &aen);
if (rv != 0)
printf("%s: error %d while draining event queue\n",
sc->sc_dv.dv_xname, rv);
@@ -753,9 +758,7 @@
* state change has occurred.
*/
if ((status & TWE_STS_ATTN_INTR) != 0) {
- rv = twe_param_get(sc, TWE_PARAM_AEN,
- TWE_PARAM_AEN_UnitCode, 2, twe_aen_handler,
- NULL);
+ rv = twe_aen_get(sc, NULL);
if (rv != 0)
printf("%s: unable to retrieve AEN (%d)\n",
sc->sc_dv.dv_xname, rv);
@@ -787,7 +790,92 @@
}
/*
+ * Fetch an AEN. Even though this is really like parameter
+ * retrieval, we handle this specially, because we issue this
+ * AEN retrieval command from interrupt context, and thus
+ * reserve a CCB for it to avoid resource shortage.
+ *
+ * XXX There are still potential resource shortages we could
+ * XXX encounter. Consider pre-allocating all AEN-related
+ * XXX resources.
+ *
+ * MUST BE CALLED AT splbio()!
+ */
+static int
+twe_aen_get(struct twe_softc *sc, uint16_t *aenp)
+{
+ struct twe_ccb *ccb;
+ struct twe_cmd *tc;
+ struct twe_param *tp;
+ int rv;
+
+ /*
+ * If we're already retrieving an AEN, just wait; another
+ * retrieval will be chained after the current one completes.
+ */
+ if (sc->sc_flags & TWEF_AEN) {
+ /*
+ * It is a fatal software programming error to attempt
+ * to fetch an AEN synchronously when an AEN fetch is
+ * already pending.
+ */
+ KASSERT(aenp == NULL);
+ return (0);
+ }
+
+ tp = malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT);
+ if (tp == NULL)
+ return (ENOMEM);
+
+ rv = twe_ccb_alloc(sc, &ccb,
+ TWE_CCB_AEN | TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT);
+ if (rv != 0)
+ goto done;
+
+ ccb->ccb_data = tp;
+ ccb->ccb_datasize = TWE_SECTOR_SIZE;
+ ccb->ccb_tx.tx_handler = (aenp == NULL) ? twe_aen_handler : NULL;
+ ccb->ccb_tx.tx_context = tp;
+ ccb->ccb_tx.tx_dv = &sc->sc_dv;
+
+ tc = ccb->ccb_cmd;
+ tc->tc_size = 2;
+ tc->tc_opcode = TWE_OP_GET_PARAM | (tc->tc_size << 5);
+ tc->tc_unit = 0;
+ tc->tc_count = htole16(1);
+
+ /* Fill in the outbound parameter data. */
+ tp->tp_table_id = htole16(TWE_PARAM_AEN);
+ tp->tp_param_id = TWE_PARAM_AEN_UnitCode;
+ tp->tp_param_size = 2;
+
+ /* Map the transfer. */
+ if ((rv = twe_ccb_map(sc, ccb)) != 0) {
+ twe_ccb_free(sc, ccb);
+ goto done;
+ }
+
+ /* Enqueue the command and wait. */
+ if (aenp != NULL) {
+ rv = twe_ccb_poll(sc, ccb, 5);
+ twe_ccb_unmap(sc, ccb);
+ twe_ccb_free(sc, ccb);
+ if (rv == 0)
+ *aenp = le16toh(*(uint16_t *)tp->tp_data);
+ free(tp, M_DEVBUF);
+ } else {
+ sc->sc_flags |= TWEF_AEN;
+ twe_ccb_enqueue(sc, ccb);
+ rv = 0;
+ }
+
+ done:
+ return (rv);
+}
+
+/*
* Handle an AEN returned by the controller.
+ * MUST BE CALLED AT splbio()!
*/
static void
twe_aen_handler(struct twe_ccb *ccb, int error)
@@ -801,6 +889,8 @@
tp = ccb->ccb_tx.tx_context;
twe_ccb_unmap(sc, ccb);
+ sc->sc_flags &= ~TWEF_AEN;
+
if (error) {
printf("%s: error retrieving AEN\n", sc->sc_dv.dv_xname);
aen = TWE_AEN_QUEUE_EMPTY;
@@ -820,8 +910,7 @@
* Chain another retrieval in case interrupts have been
* coalesced.
*/
- rv = twe_param_get(sc, TWE_PARAM_AEN, TWE_PARAM_AEN_UnitCode, 2,
- twe_aen_handler, NULL);
+ rv = twe_aen_get(sc, NULL);
if (rv != 0)
printf("%s: unable to retrieve AEN (%d)\n",
sc->sc_dv.dv_xname, rv);
@@ -972,8 +1061,7 @@
if (tp == NULL)
return ENOMEM;
- rv = twe_ccb_alloc(sc, &ccb,
- TWE_CCB_PARAM | TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT);
+ rv = twe_ccb_alloc(sc, &ccb, TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT);
if (rv != 0)
goto done;
@@ -1040,8 +1128,7 @@
if (tp == NULL)
return ENOMEM;
- rv = twe_ccb_alloc(sc, &ccb,
- TWE_CCB_PARAM | TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT);
+ rv = twe_ccb_alloc(sc, &ccb, TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT);
if (rv != 0)
goto done;
@@ -1215,9 +1302,10 @@
int s;
s = splbio();
- if ((flags & TWE_CCB_PARAM) != 0)
+ if ((flags & TWE_CCB_AEN) != 0) {
+ /* Use the reserved CCB. */
ccb = sc->sc_ccbs;
- else {
+ } else {
/* Allocate a CCB and command block. */
if (SLIST_FIRST(&sc->sc_ccb_freelist) == NULL) {
splx(s);
@@ -1254,7 +1342,7 @@
int s;
s = splbio();
- if ((ccb->ccb_flags & TWE_CCB_PARAM) == 0)
+ if ((ccb->ccb_flags & TWE_CCB_AEN) == 0)
SLIST_INSERT_HEAD(&sc->sc_ccb_freelist, ccb, ccb_chain.slist);
ccb->ccb_flags = 0;
splx(s);
@@ -1502,14 +1590,18 @@
tweioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
struct twe_softc *twe;
+#if 0
struct twe_ccb *ccb;
+#endif
struct twe_param *param;
struct twe_usercommand *tu;
struct twe_paramcommand *tp;
union twe_statrequest *ts;
void *pdata = NULL;
int rv, s, error = 0;
+#if 0
u_int8_t cmdid;
+#endif
if (securelevel >= 2)
return (EPERM);
@@ -1522,6 +1614,8 @@
/* Hmm, compatible with FreeBSD */
switch (cmd) {
case TWEIO_COMMAND:
+#if 0
+ /* XXXJRT This whole path needs to be cleaned up. */
if (tu->tu_size > 0) {
if (tu->tu_size > TWE_SECTOR_SIZE)
return EINVAL;
@@ -1561,6 +1655,9 @@
if (tu->tu_size > 0)
error = copyout(pdata, tu->tu_data, tu->tu_size);
+#else
+ rv = EOPNOTSUPP;
+#endif
goto done;
case TWEIO_STATS:
@@ -1609,7 +1706,9 @@
goto done;
case TWEIO_RESET:
+ s = splbio();
twe_reset(twe);
+ splx(s);
return (0);
case TWEIO_ADD_UNIT:
diff -r 63e1a939ae01 -r 6834d4184a21 sys/dev/pci/twevar.h
--- a/sys/dev/pci/twevar.h Tue Sep 23 23:07:35 2003 +0000
+++ b/sys/dev/pci/twevar.h Tue Sep 23 23:08:54 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: twevar.h,v 1.18 2003/09/22 18:31:11 thorpej Exp $ */
+/* $NetBSD: twevar.h,v 1.19 2003/09/23 23:08:54 thorpej Exp $ */
Home |
Main Index |
Thread Index |
Old Index