From d4249d08d980df9425b62bcb11e960c2132fac36 Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Sat, 2 Mar 2019 20:58:51 +0000 Subject: [PATCH] Bugfix: use a dummy buffer for the inactive side of a transfer. This is especially important for writes. SPI is inherently a bidirectional bus; you receive data (even if it's garbage) while writing. We should not receive that data into the same buffer we're writing to the device. When reading it doesn't matter what we send to the device, but using the dummy buffer for that as well is pleasingly symmetrical. --- sys/dev/flash/at45d.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/sys/dev/flash/at45d.c b/sys/dev/flash/at45d.c index d04aad472f8..854b29a36fe 100644 --- a/sys/dev/flash/at45d.c +++ b/sys/dev/flash/at45d.c @@ -95,6 +95,7 @@ struct at45d_softc uint16_t pagecount; uint16_t pageoffset; uint16_t pagesize; + void *dummybuf; }; #define TSTATE_STOPPED 0 @@ -285,6 +286,7 @@ at45d_detach(device_t dev) if (err == 0 && sc->taskstate == TSTATE_STOPPED) { disk_destroy(sc->disk); bioq_flush(&sc->bio_queue, NULL, ENXIO); + free(sc->dummybuf, M_DEVBUF); AT45D_LOCK_DESTROY(sc); } return (err); @@ -334,6 +336,8 @@ at45d_delayed_attach(void *xsc) pagesize = ident->pagesize; sc->pagesize = pagesize; + sc->dummybuf = malloc(pagesize, M_DEVBUF, M_WAITOK | M_ZERO); + sc->disk = disk_alloc(); sc->disk->d_open = at45d_open; sc->disk->d_close = at45d_close; @@ -444,11 +448,13 @@ at45d_task(void *arg) case BIO_READ: txBuf[0] = CONTINUOUS_ARRAY_READ; cmd.tx_cmd_sz = cmd.rx_cmd_sz = 8; - cmd.tx_data = cmd.rx_data = buf; + cmd.tx_data = sc->dummybuf; + cmd.rx_data = buf; break; case BIO_WRITE: cmd.tx_cmd_sz = cmd.rx_cmd_sz = 4; - cmd.tx_data = cmd.rx_data = buf; + cmd.tx_data = buf; + cmd.rx_data = sc->dummybuf; if (resid + offset > sc->pagesize) len = sc->pagesize - offset; break; @@ -524,7 +530,10 @@ at45d_task(void *arg) len = sc->pagesize; else len = resid; - cmd.tx_data = cmd.rx_data = buf; + if (bp->bio_cmd == BIO_READ) + cmd.rx_data = buf; + else + cmd.tx_data = buf; } out: if (berr != 0) {