summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2007-04-19 14:07:09 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2007-04-19 14:07:09 +0000
commite597d17a58cadd3c3ef1cf84746578b165d0eeaa (patch)
treedb277626b81f3310b8da5a353e9b1d8995fd9715 /sys
parent38e441da69ac5acf55af8609ec0c4c7c0fe5fdbf (diff)
this is two (and a half) changes, but im too lazy to split them up.
the first is the addition of handlers for the fifos. you can now check if there the fifo is ready to be used, pre sync it for use, do many incremental updates to it, then post sync it to tell the hardware that you've done something. the ready, pre, and post funcs are done for both the reader and writer fifos, but only updates to the writer fifos is implemented so far. the second change is the firmware loading. i needed the above changes to do this, and i needed firmware loading to test them, so this change gets both. so we have a mountroot hook (that was the half change) that allocates the tx task fifo, reads the firmware from disk, and then pushes the firmware onto the fifo. once that is done it spins till the firmware is ready, then cleans up everything it allocated for loading the firmware. this diff wont time out if anything goes wrong during fw_load. if anyone wants to look at a nice way of doing it, please do.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/if_tht.c219
1 files changed, 187 insertions, 32 deletions
diff --git a/sys/dev/pci/if_tht.c b/sys/dev/pci/if_tht.c
index fe419598226..3974fd84e4d 100644
--- a/sys/dev/pci/if_tht.c
+++ b/sys/dev/pci/if_tht.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_tht.c,v 1.27 2007/04/18 13:35:59 dlg Exp $ */
+/* $OpenBSD: if_tht.c,v 1.28 2007/04/19 14:07:08 dlg Exp $ */
/*
* Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
@@ -161,6 +161,8 @@
#define THT_FIFO_SIZE_16k 0x2
#define THT_FIFO_SIZE_32k 0x3
#define THT_FIFO_SIZE(_r) (4096 * (1<<(_r)))
+#define THT_FIFO_GAP 8 /* keep 8 bytes between ptrs */
+#define THT_FIFO_PTR_MASK 0x00007ff8 /* rptr/wptr mask */
/* hardware structures (we're using the 64 bit variants) */
@@ -269,10 +271,38 @@ struct tht_attach_args {
};
/* tht itself */
-struct tht_dmamem;
+
+struct tht_dmamem {
+ bus_dmamap_t tdm_map;
+ bus_dma_segment_t tdm_seg;
+ size_t tdm_size;
+ caddr_t tdm_kva;
+};
+#define THT_DMA_MAP(_tdm) ((_tdm)->tdm_map)
+#define THT_DMA_DVA(_tdm) ((_tdm)->tdm_map->dm_segs[0].ds_addr)
+#define THT_DMA_KVA(_tdm) ((void *)(_tdm)->tdm_kva)
+
+struct tht_fifo_desc {
+ bus_size_t tfd_cfg0;
+ bus_size_t tfd_cfg1;
+ bus_size_t tfd_rptr;
+ bus_size_t tfd_wptr;
+ u_int32_t tfd_size;
+ int tfd_write;
+};
+#define THT_FIFO_PRE_SYNC(_d) ((_d)->tfd_write ? \
+ BUS_DMASYNC_PREWRITE : \
+ BUS_DMASYNC_PREREAD)
+#define THT_FIFO_POST_SYNC(_d) ((_d)->tfd_write ? \
+ BUS_DMASYNC_POSTWRITE : \
+ BUS_DMASYNC_POSTREAD)
struct tht_fifo {
+ struct tht_fifo_desc *tf_desc;
struct tht_dmamem *tf_mem;
+ int tf_len;
+ int tf_rptr;
+ int tf_wptr;
};
struct tht_softc {
@@ -288,14 +318,15 @@ struct tht_softc {
u_int16_t sc_lladdr[3];
- struct tht_fifo sc_txt_fifo;
- struct tht_fifo sc_rxf_fifo;
- struct tht_fifo sc_rxd_fifo;
- struct tht_fifo sc_txf_fifo;
+ struct tht_fifo sc_txt;
+ struct tht_fifo sc_rxf;
+ struct tht_fifo sc_rxd;
+ struct tht_fifo sc_txf;
};
int tht_match(struct device *, void *, void *);
void tht_attach(struct device *, struct device *, void *);
+void tht_mountroot(void *);
int tht_intr(void *);
struct cfattach tht_ca = {
@@ -307,37 +338,42 @@ struct cfdriver tht_cd = {
};
/* fifos */
-struct tht_fifo_desc {
- bus_size_t tfd_cfg0;
- bus_size_t tfd_cfg1;
- bus_size_t tfd_rptr;
- bus_size_t tfd_wptr;
- u_int32_t tfd_size;
-};
-const struct tht_fifo_desc tht_txt_fifo = {
+struct tht_fifo_desc tht_txt_desc = {
THT_REG_TXT_CFG0(0),
THT_REG_TXT_CFG1(0),
THT_REG_TXT_RPTR(0),
THT_REG_TXT_WPTR(0),
- THT_FIFO_SIZE_16k
+ THT_FIFO_SIZE_16k,
+ 1
};
-const struct tht_fifo_desc tht_txf_fifo = {
+struct tht_fifo_desc tht_txf_desc = {
THT_REG_TXF_CFG0(0),
THT_REG_TXF_CFG1(0),
THT_REG_TXF_RPTR(0),
THT_REG_TXF_WPTR(0),
- THT_FIFO_SIZE_4k
+ THT_FIFO_SIZE_4k,
+ 0
};
int tht_fifo_alloc(struct tht_softc *, struct tht_fifo *,
- const struct tht_fifo_desc *);
+ struct tht_fifo_desc *);
void tht_fifo_free(struct tht_softc *, struct tht_fifo *);
+size_t tht_fifo_ready(struct tht_softc *,
+ struct tht_fifo *);
+void tht_fifo_pre(struct tht_softc *,
+ struct tht_fifo *);
+void tht_fifo_write(struct tht_softc *, struct tht_fifo *,
+ void *, size_t);
+void tht_fifo_post(struct tht_softc *,
+ struct tht_fifo *);
+
/* port operations */
void tht_read_lladdr(struct tht_softc *);
int tht_sw_reset(struct tht_softc *);
+int tht_fw_load(struct tht_softc *);
/* interface operations */
int tht_ioctl(struct ifnet *, u_long, caddr_t);
@@ -349,16 +385,6 @@ int tht_media_change(struct ifnet *);
void tht_media_status(struct ifnet *, struct ifmediareq *);
/* wrapper around dma memory */
-struct tht_dmamem {
- bus_dmamap_t tdm_map;
- bus_dma_segment_t tdm_seg;
- size_t tdm_size;
- caddr_t tdm_kva;
-};
-#define THT_DMA_MAP(_tdm) ((_tdm)->tdm_map)
-#define THT_DMA_DVA(_tdm) ((_tdm)->tdm_map->dm_segs[0].ds_addr)
-#define THT_DMA_KVA(_tdm) ((void *)(_tdm)->tdm_kva)
-
struct tht_dmamem *tht_dmamem_alloc(struct tht_softc *, bus_size_t,
bus_size_t);
void tht_dmamem_free(struct tht_softc *,
@@ -540,6 +566,24 @@ tht_attach(struct device *parent, struct device *self, void *aux)
ether_ifattach(ifp);
printf(" address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr));
+
+ mountroothook_establish(tht_mountroot, sc);
+}
+
+void
+tht_mountroot(void *arg)
+{
+ struct tht_softc *sc = arg;
+
+ if (tht_fifo_alloc(sc, &sc->sc_txt, &tht_txt_desc) != 0)
+ return;
+
+ printf("%s: firmware load %s\n", DEVNAME(sc),
+ (tht_fw_load(sc) == 0) ? "succeeded" : "failed");
+
+ tht_fifo_free(sc, &sc->sc_txt);
+
+ tht_sw_reset(sc);
}
int
@@ -610,16 +654,21 @@ tht_media_status(struct ifnet *ifp, struct ifmediareq *imr)
int
tht_fifo_alloc(struct tht_softc *sc, struct tht_fifo *tf,
- const struct tht_fifo_desc *tfd)
+ struct tht_fifo_desc *tfd)
{
- bus_size_t size;
u_int64_t dva;
- size = THT_FIFO_SIZE(tfd->tfd_size);
- tf->tf_mem = tht_dmamem_alloc(sc, size, THT_FIFO_ALIGN);
+ tf->tf_len = THT_FIFO_SIZE(tfd->tfd_size);
+ tf->tf_mem = tht_dmamem_alloc(sc, tf->tf_len, THT_FIFO_ALIGN);
if (tf->tf_mem == NULL)
return (1);
+ tf->tf_desc = tfd;
+ tf->tf_rptr = tf->tf_wptr = 0;
+
+ bus_dmamap_sync(sc->sc_thtc->sc_dmat, THT_DMA_MAP(tf->tf_mem),
+ 0, tf->tf_len, THT_FIFO_PRE_SYNC(tfd));
+
dva = THT_DMA_DVA(tf->tf_mem);
tht_write(sc, tfd->tfd_cfg0, (u_int32_t)dva | tfd->tfd_size);
tht_write(sc, tfd->tfd_cfg1, (u_int32_t)(dva >> 32));
@@ -630,9 +679,73 @@ tht_fifo_alloc(struct tht_softc *sc, struct tht_fifo *tf,
void
tht_fifo_free(struct tht_softc *sc, struct tht_fifo *tf)
{
+ bus_dmamap_sync(sc->sc_thtc->sc_dmat, THT_DMA_MAP(tf->tf_mem),
+ 0, tf->tf_len, THT_FIFO_POST_SYNC(tf->tf_desc));
tht_dmamem_free(sc, tf->tf_mem);
}
+size_t
+tht_fifo_ready(struct tht_softc *sc, struct tht_fifo *tf)
+{
+ int ready;
+
+ if (tf->tf_desc->tfd_write) {
+ tf->tf_rptr = tht_read(sc, tf->tf_desc->tfd_rptr);
+ tf->tf_rptr &= THT_FIFO_PTR_MASK;
+ ready = tf->tf_rptr - tf->tf_wptr;
+ } else {
+ tf->tf_wptr = tht_read(sc, tf->tf_desc->tfd_wptr);
+ tf->tf_wptr &= THT_FIFO_PTR_MASK;
+ ready = tf->tf_wptr - tf->tf_rptr;
+ }
+
+ if (ready <= 0)
+ ready += tf->tf_len;
+
+ return (ready);
+}
+
+void
+tht_fifo_pre(struct tht_softc *sc, struct tht_fifo *tf)
+{
+ bus_dmamap_sync(sc->sc_thtc->sc_dmat, THT_DMA_MAP(tf->tf_mem),
+ 0, tf->tf_len, THT_FIFO_POST_SYNC(tf->tf_desc));
+}
+
+void
+tht_fifo_write(struct tht_softc *sc, struct tht_fifo *tf,
+ void *buf, size_t buflen)
+{
+ u_int8_t *fifo = THT_DMA_KVA(tf->tf_mem);
+ u_int8_t *desc = buf;
+ size_t len;
+
+ len = tf->tf_len - tf->tf_wptr;
+
+ if (len < buflen) {
+ bcopy(desc, fifo + tf->tf_wptr, len);
+
+ buflen -= len;
+ desc += len;
+
+ tf->tf_wptr = 0;
+ }
+
+ bcopy(desc, fifo + tf->tf_wptr, buflen);
+ tf->tf_wptr += buflen;
+}
+
+void
+tht_fifo_post(struct tht_softc *sc, struct tht_fifo *tf)
+{
+ bus_dmamap_sync(sc->sc_thtc->sc_dmat, THT_DMA_MAP(tf->tf_mem),
+ 0, tf->tf_len, THT_FIFO_POST_SYNC(tf->tf_desc));
+ if (tf->tf_desc->tfd_write)
+ tht_write(sc, tf->tf_desc->tfd_wptr, tf->tf_wptr);
+ else
+ tht_write(sc, tf->tf_desc->tfd_rptr, tf->tf_rptr);
+}
+
void
tht_read_lladdr(struct tht_softc *sc)
{
@@ -716,6 +829,48 @@ tht_sw_reset(struct tht_softc *sc)
return (0);
}
+int
+tht_fw_load(struct tht_softc *sc)
+{
+ u_int8_t *fw, *buf;
+ size_t fwlen, wrlen;
+ int error = 1;
+
+ if (loadfirmware("tht", &fw, &fwlen) != 0)
+ return (1);
+
+ if ((fwlen % 8) != 0)
+ goto err;
+
+ buf = fw;
+ while (fwlen > 0) {
+ while ((wrlen = tht_fifo_ready(sc, &sc->sc_txt) -
+ THT_FIFO_GAP) <= 0) {
+ if (tsleep(sc, PCATCH, "thtfw", 1) == EINTR)
+ goto err;
+ }
+
+ wrlen = MIN(wrlen, fwlen);
+ tht_fifo_pre(sc, &sc->sc_txt);
+ tht_fifo_write(sc, &sc->sc_txt, buf, wrlen);
+ tht_fifo_post(sc, &sc->sc_txt);
+
+ fwlen -= wrlen;
+ buf += wrlen;
+ }
+
+ while (tht_read(sc, THT_REG_INIT_STATUS)) {
+ if (tsleep(sc, PCATCH, "thtinit", 1) == EINTR)
+ goto err;
+ }
+
+ error = 0;
+
+err:
+ free(fw, M_DEVBUF);
+ return (error);
+}
+
u_int32_t
tht_read(struct tht_softc *sc, bus_size_t r)
{