summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2018-05-17 21:59:27 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2018-05-17 21:59:27 +0000
commit9a112347b626ce67d187efcdf6ebeaf20f9b7108 (patch)
tree3cb6ff35acc9b5655451c5ce2ae0e4e0053930e1 /sys/dev
parent7a459338f74d79adc8c1618a92bb09a9f64602b7 (diff)
The Broadcom FullMAC firmware has a few ways of doing flow control. One
of those is a sequence number based window mechanism. Essentially every packet on the SDIO bus has a sequence number. The chip records which sequence number we used last and when it sends us replies, it tells us the maximum sequence number it accepts. This means we can calculate a window of sequence numbers that we are allowed to use. With this I no longer overflow the chip's RX fifo and can do stable network transfers.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/sdmmc/if_bwfm_sdio.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/sys/dev/sdmmc/if_bwfm_sdio.c b/sys/dev/sdmmc/if_bwfm_sdio.c
index 10c402544e2..c19c63a25f4 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.9 2018/05/16 14:10:26 patrick Exp $ */
+/* $OpenBSD: if_bwfm_sdio.c,v 1.10 2018/05/17 21:59:26 patrick Exp $ */
/*
* Copyright (c) 2010-2016 Broadcom Corporation
* Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
@@ -87,6 +87,7 @@ struct bwfm_sdio_softc {
struct bwfm_core *sc_cc;
uint8_t sc_tx_seq;
+ uint8_t sc_tx_max_seq;
char *sc_rxdata_buf;
struct mbuf_queue sc_txdata_queue;
@@ -134,6 +135,7 @@ int bwfm_sdio_buscore_prepare(struct bwfm_softc *);
void bwfm_sdio_buscore_activate(struct bwfm_softc *, uint32_t);
struct mbuf * bwfm_sdio_newbuf(void);
+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 *);
@@ -209,6 +211,7 @@ 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_tx_seq = 0xff;
rw_assert_wrlock(&sf->sc->sc_lock);
sc->sc_lock = &sf->sc->sc_lock;
@@ -913,6 +916,13 @@ bwfm_sdio_newbuf(void)
return (m);
}
+int
+bwfm_sdio_tx_ok(struct bwfm_sdio_softc *sc)
+{
+ return (uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq) != 0 &&
+ ((uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq) & 0x80) == 0;
+}
+
void
bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *sc)
{
@@ -922,6 +932,9 @@ bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *sc)
char *buf;
size_t len;
+ if (!bwfm_sdio_tx_ok(sc))
+ return;
+
TAILQ_FOREACH_SAFE(ctl, &sc->sc_sc.sc_bcdc_txctlq, next, tmp) {
TAILQ_REMOVE(&sc->sc_sc.sc_bcdc_txctlq, ctl, next);
@@ -958,8 +971,13 @@ bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *sc)
struct mbuf *m;
char *buf;
size_t len;
+ int i;
- for (;;) {
+ if (!bwfm_sdio_tx_ok(sc))
+ return;
+
+ i = min((uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq), 32);
+ while (i--) {
m = mq_dequeue(&sc->sc_txdata_queue);
if (m == NULL)
break;
@@ -1034,6 +1052,8 @@ bwfm_sdio_rx_frames(struct bwfm_sdio_softc *sc)
sizeof(swhdr), 0))
break;
+ sc->sc_tx_max_seq = swhdr.maxseqnr;
+
flen = hwhdr.frmlen - (sizeof(hwhdr) + sizeof(swhdr));
if (flen == 0)
continue;