summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2018-05-18 08:40:12 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2018-05-18 08:40:12 +0000
commit6418b658781aefb087ae29c81d8ad378a4c4e57d (patch)
treeb4a814ed33128c9952dd1a1a7f9ef31a9e52a1b1 /sys/dev
parentaa90a55ace7d39eb0841b18bcea4635518cb4a49 (diff)
After reading the first frame, which we can do in two reads (software
plus hardware header, which tell us the length of the following data), we can issue full packet reads. The software header contains a field that informs us of the full length of the next frame that we can read, so we can do that in a single sitting. This brings us down from three SDIO read invocation to a single one per packet for a given RX stream.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/sdmmc/if_bwfm_sdio.c95
1 files changed, 61 insertions, 34 deletions
diff --git a/sys/dev/sdmmc/if_bwfm_sdio.c b/sys/dev/sdmmc/if_bwfm_sdio.c
index c19c63a25f4..bb552271b91 100644
--- a/sys/dev/sdmmc/if_bwfm_sdio.c
+++ b/sys/dev/sdmmc/if_bwfm_sdio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bwfm_sdio.c,v 1.10 2018/05/17 21:59:26 patrick Exp $ */
+/* $OpenBSD: if_bwfm_sdio.c,v 1.11 2018/05/18 08:40:11 patrick Exp $ */
/*
* Copyright (c) 2010-2016 Broadcom Corporation
* Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
@@ -139,7 +139,8 @@ int bwfm_sdio_tx_ok(struct bwfm_sdio_softc *);
void bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *);
void bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *);
void bwfm_sdio_rx_frames(struct bwfm_sdio_softc *);
-void bwfm_sdio_rx_glom(struct bwfm_sdio_softc *, uint16_t *, int);
+void bwfm_sdio_rx_glom(struct bwfm_sdio_softc *, uint16_t *, int,
+ uint16_t *);
int bwfm_sdio_txcheck(struct bwfm_softc *);
int bwfm_sdio_txdata(struct bwfm_softc *, struct mbuf *);
@@ -210,7 +211,8 @@ bwfm_sdio_attach(struct device *parent, struct device *self, void *aux)
task_set(&sc->sc_task, bwfm_sdio_task, sc);
mq_init(&sc->sc_txdata_queue, 16, IPL_SOFTNET);
- sc->sc_rxdata_buf = malloc(64 * 1024, M_DEVBUF, M_WAITOK);
+ sc->sc_rxdata_buf = malloc(64 * 1024 + sizeof(struct bwfm_sdio_hwhdr) +
+ sizeof(struct bwfm_sdio_swhdr), M_DEVBUF, M_WAITOK);
sc->sc_tx_seq = 0xff;
rw_assert_wrlock(&sf->sc->sc_lock);
@@ -1018,61 +1020,78 @@ bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *sc)
void
bwfm_sdio_rx_frames(struct bwfm_sdio_softc *sc)
{
- struct bwfm_sdio_hwhdr hwhdr;
- struct bwfm_sdio_swhdr swhdr;
- uint16_t *sublen;
+ struct bwfm_sdio_hwhdr *hwhdr;
+ struct bwfm_sdio_swhdr *swhdr;
+ uint16_t *sublen, nextlen = 0;
struct mbuf *m;
- int nsub;
size_t flen;
+ char *data;
off_t off;
- char *buf;
+ int nsub;
+
+ hwhdr = (struct bwfm_sdio_hwhdr *)sc->sc_rxdata_buf;
+ swhdr = (struct bwfm_sdio_swhdr *)&hwhdr[1];
+ data = (char *)&swhdr[1];
do {
- if (bwfm_sdio_frame_read_write(sc, (char *)&hwhdr,
- sizeof(hwhdr), 0))
- break;
+ /* If we know the next size, just read ahead. */
+ if (nextlen) {
+ if (bwfm_sdio_frame_read_write(sc, sc->sc_rxdata_buf,
+ nextlen, 0))
+ break;
+ } else {
+ if (bwfm_sdio_frame_read_write(sc, sc->sc_rxdata_buf,
+ sizeof(*hwhdr) + sizeof(*swhdr), 0))
+ break;
+ }
- hwhdr.frmlen = letoh16(hwhdr.frmlen);
- hwhdr.cksum = letoh16(hwhdr.cksum);
+ hwhdr->frmlen = letoh16(hwhdr->frmlen);
+ hwhdr->cksum = letoh16(hwhdr->cksum);
- if (hwhdr.frmlen == 0 && hwhdr.cksum == 0)
+ if (hwhdr->frmlen == 0 && hwhdr->cksum == 0)
break;
- if ((hwhdr.frmlen ^ hwhdr.cksum) != 0xffff) {
+ if ((hwhdr->frmlen ^ hwhdr->cksum) != 0xffff) {
printf("%s: checksum error\n", DEVNAME(sc));
break;
}
- if (hwhdr.frmlen < sizeof(hwhdr) + sizeof(swhdr)) {
+ if (hwhdr->frmlen < sizeof(*hwhdr) + sizeof(*swhdr)) {
printf("%s: length error\n", DEVNAME(sc));
break;
}
- if (bwfm_sdio_frame_read_write(sc, (char *)&swhdr,
- sizeof(swhdr), 0))
+ if (nextlen && hwhdr->frmlen > nextlen) {
+ printf("%s: read ahead length error (%u > %u)\n",
+ DEVNAME(sc), hwhdr->frmlen, nextlen);
break;
+ }
- sc->sc_tx_max_seq = swhdr.maxseqnr;
+ sc->sc_tx_max_seq = swhdr->maxseqnr;
- flen = hwhdr.frmlen - (sizeof(hwhdr) + sizeof(swhdr));
- if (flen == 0)
+ flen = hwhdr->frmlen - (sizeof(*hwhdr) + sizeof(*swhdr));
+ if (flen == 0) {
+ nextlen = swhdr->nextlen << 4;
continue;
+ }
- buf = sc->sc_rxdata_buf;
- if (bwfm_sdio_frame_read_write(sc, buf, flen, 0))
- break;
+ if (!nextlen) {
+ if (bwfm_sdio_frame_read_write(sc, data, flen, 0))
+ break;
+ }
- if (swhdr.dataoff < (sizeof(hwhdr) + sizeof(swhdr)))
+ if (swhdr->dataoff < (sizeof(*hwhdr) + sizeof(*swhdr)))
break;
- off = swhdr.dataoff - (sizeof(hwhdr) + sizeof(swhdr));
+ off = swhdr->dataoff - (sizeof(*hwhdr) + sizeof(*swhdr));
if (off > flen)
break;
- switch (swhdr.chanflag & BWFM_SDIO_SWHDR_CHANNEL_MASK) {
+ switch (swhdr->chanflag & BWFM_SDIO_SWHDR_CHANNEL_MASK) {
case BWFM_SDIO_SWHDR_CHANNEL_CONTROL:
sc->sc_sc.sc_proto_ops->proto_rxctl(&sc->sc_sc,
- buf + off, flen - off);
+ data + off, flen - off);
+ nextlen = swhdr->nextlen << 4;
break;
case BWFM_SDIO_SWHDR_CHANNEL_EVENT:
case BWFM_SDIO_SWHDR_CHANNEL_DATA:
@@ -1086,8 +1105,9 @@ bwfm_sdio_rx_frames(struct bwfm_sdio_softc *sc)
break;
}
m->m_len = m->m_pkthdr.len = flen - off;
- memcpy(mtod(m, char *), buf + off, flen - off);
+ memcpy(mtod(m, char *), data + off, flen - off);
sc->sc_sc.sc_proto_ops->proto_rx(&sc->sc_sc, m);
+ nextlen = swhdr->nextlen << 4;
break;
case BWFM_SDIO_SWHDR_CHANNEL_GLOM:
if ((flen % sizeof(uint16_t)) != 0)
@@ -1095,19 +1115,20 @@ bwfm_sdio_rx_frames(struct bwfm_sdio_softc *sc)
nsub = flen / sizeof(uint16_t);
sublen = mallocarray(nsub, sizeof(uint16_t),
M_DEVBUF, M_WAITOK | M_ZERO);
- memcpy(sublen, buf, nsub * sizeof(uint16_t));
- bwfm_sdio_rx_glom(sc, sublen, nsub);
+ memcpy(sublen, data, nsub * sizeof(uint16_t));
+ bwfm_sdio_rx_glom(sc, sublen, nsub, &nextlen);
free(sublen, M_DEVBUF, nsub * sizeof(uint16_t));
break;
default:
printf("%s: unknown channel\n", DEVNAME(sc));
break;
}
- } while (swhdr.nextlen);
+ } while (nextlen);
}
void
-bwfm_sdio_rx_glom(struct bwfm_sdio_softc *sc, uint16_t *sublen, int nsub)
+bwfm_sdio_rx_glom(struct bwfm_sdio_softc *sc, uint16_t *sublen, int nsub,
+ uint16_t *nextlen)
{
struct bwfm_sdio_hwhdr hwhdr;
struct bwfm_sdio_swhdr swhdr;
@@ -1144,7 +1165,13 @@ bwfm_sdio_rx_glom(struct bwfm_sdio_softc *sc, uint16_t *sublen, int nsub)
/* TODO: Verify actual superframe header */
m = MBUF_LIST_FIRST(&ml);
- m_adj(m, sizeof(struct bwfm_sdio_hwhdr) + sizeof(struct bwfm_sdio_swhdr));
+ if (m->m_len >= sizeof(hwhdr) + sizeof(swhdr)) {
+ m_copydata(m, 0, sizeof(hwhdr), (caddr_t)&hwhdr);
+ m_copydata(m, sizeof(hwhdr), sizeof(swhdr), (caddr_t)&swhdr);
+ *nextlen = swhdr.nextlen << 4;
+ m_adj(m, sizeof(struct bwfm_sdio_hwhdr) +
+ sizeof(struct bwfm_sdio_swhdr));
+ }
while ((m = ml_dequeue(&ml)) != NULL) {
if (m->m_len < sizeof(hwhdr) + sizeof(swhdr))