Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/ic Rewrite data transfer path to take advantage of t...
details: https://anonhg.NetBSD.org/src/rev/c84e243464a3
branches: trunk
changeset: 829954:c84e243464a3
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Mon Feb 19 19:00:42 2018 +0000
description:
Rewrite data transfer path to take advantage of the PL181's 64-byte FIFO.
Before: 134217728 bytes transferred in 43.683 secs (3072539 bytes/sec)
After: 134217728 bytes transferred in 23.789 secs (5642007 bytes/sec)
diffstat:
sys/dev/ic/pl181.c | 242 +++++++++++++++++++++++++++++++------------------
sys/dev/ic/pl181var.h | 10 +-
2 files changed, 157 insertions(+), 95 deletions(-)
diffs (truncated from 411 to 300 lines):
diff -r 2713c8f7ff5d -r c84e243464a3 sys/dev/ic/pl181.c
--- a/sys/dev/ic/pl181.c Mon Feb 19 16:21:36 2018 +0000
+++ b/sys/dev/ic/pl181.c Mon Feb 19 19:00:42 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pl181.c,v 1.4 2017/06/04 15:08:30 jmcneill Exp $ */
+/* $NetBSD: pl181.c,v 1.5 2018/02/19 19:00:42 jmcneill Exp $ */
/*-
* Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pl181.c,v 1.4 2017/06/04 15:08:30 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pl181.c,v 1.5 2018/02/19 19:00:42 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -49,6 +49,22 @@
*/
#define PLMMC_MAXXFER rounddown(65535, SDMMC_SECTOR_SIZE)
+/*
+ * PL181 FIFO is 16 words deep (64 bytes)
+ */
+#define PL181_FIFO_DEPTH 64
+
+/*
+ * Data transfer IRQ status bits
+ */
+#define PLMMC_INT_DATA_MASK \
+ (MMCI_INT_DATA_TIMEOUT|MMCI_INT_DATA_CRC_FAIL| \
+ MMCI_INT_TX_FIFO_EMPTY|MMCI_INT_TX_FIFO_HALF_EMPTY| \
+ MMCI_INT_RX_FIFO_FULL|MMCI_INT_RX_FIFO_HALF_FULL| \
+ MMCI_INT_DATA_END|MMCI_INT_DATA_BLOCK_END)
+#define PLMMC_INT_CMD_MASK \
+ (MMCI_INT_CMD_TIMEOUT|MMCI_INT_CMD_RESP_END)
+
static int plmmc_host_reset(sdmmc_chipset_handle_t);
static uint32_t plmmc_host_ocr(sdmmc_chipset_handle_t);
static int plmmc_host_maxblklen(sdmmc_chipset_handle_t);
@@ -63,9 +79,7 @@
static void plmmc_card_enable_intr(sdmmc_chipset_handle_t, int);
static void plmmc_card_intr_ack(sdmmc_chipset_handle_t);
-static int plmmc_wait_status(struct plmmc_softc *, uint32_t, int);
-static int plmmc_pio_wait(struct plmmc_softc *,
- struct sdmmc_command *);
+static int plmmc_wait_cmd(struct plmmc_softc *);
static int plmmc_pio_transfer(struct plmmc_softc *,
struct sdmmc_command *, int);
@@ -86,15 +100,19 @@
#define MMCI_WRITE(sc, reg, val) \
bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+#define MMCI_WRITE_MULTI(sc, reg, datap, cnt) \
+ bus_space_write_multi_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (datap), (cnt))
#define MMCI_READ(sc, reg) \
bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define MMCI_READ_MULTI(sc, reg, datap, cnt) \
+ bus_space_read_multi_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (datap), (cnt))
void
plmmc_init(struct plmmc_softc *sc)
{
struct sdmmcbus_attach_args saa;
- mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO);
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_BIO);
cv_init(&sc->sc_intr_cv, "plmmcirq");
#ifdef PLMMC_DEBUG
@@ -130,81 +148,125 @@
sc->sc_sdmmc_dev = config_found(sc->sc_dev, &saa, NULL);
}
+static int
+plmmc_intr_xfer(struct plmmc_softc *sc, struct sdmmc_command *cmd)
+{
+ uint32_t len;
+
+ if (cmd == NULL) {
+ device_printf(sc->sc_dev, "TX/RX interrupt with no active transfer\n");
+ return EINVAL;
+ }
+
+ if (cmd->c_buf == NULL) {
+ return EINVAL;
+ }
+
+ const uint32_t fifo_cnt =
+ __SHIFTOUT(MMCI_READ(sc, MMCI_FIFO_CNT_REG), MMCI_FIFO_CNT) * 4;
+ if (fifo_cnt > sc->sc_fifo_resid) {
+ device_printf(sc->sc_dev, "FIFO counter is out of sync with active transfer\n");
+ return EIO;
+ }
+
+ if (cmd->c_flags & SCF_CMD_READ)
+ len = sc->sc_fifo_resid - fifo_cnt;
+ else
+ len = min(sc->sc_fifo_resid, PL181_FIFO_DEPTH);
+
+ if (len == 0)
+ return 0;
+
+ if (cmd->c_flags & SCF_CMD_READ)
+ MMCI_READ_MULTI(sc, MMCI_FIFO_REG, (uint32_t *)cmd->c_buf, len / 4);
+ else
+ MMCI_WRITE_MULTI(sc, MMCI_FIFO_REG, (uint32_t *)cmd->c_buf, len / 4);
+
+ sc->sc_fifo_resid -= len;
+ cmd->c_resid -= len;
+ cmd->c_buf += len;
+
+ return 0;
+}
+
int
plmmc_intr(void *priv)
{
struct plmmc_softc *sc = priv;
- uint32_t status;
+ uint32_t status, mask;
+ int retry = 100000;
- mutex_enter(&sc->sc_intr_lock);
- status = MMCI_READ(sc, MMCI_STATUS_REG);
+ mutex_enter(&sc->sc_lock);
+
+ while (--retry > 0) {
+ status = MMCI_READ(sc, MMCI_STATUS_REG);
#ifdef PLMMC_DEBUG
- printf("%s: MMCI_STATUS_REG = %#x\n", __func__, status);
+ printf("%s: MMCI_STATUS_REG = %#x\n", __func__, status);
#endif
- if (!status) {
- mutex_exit(&sc->sc_intr_lock);
- return 0;
+ if ((status & sc->sc_status_mask) == 0)
+ break;
+ MMCI_WRITE(sc, MMCI_CLEAR_REG, status);
+ sc->sc_intr_status |= status;
+
+ if (status & MMCI_INT_CMD_TIMEOUT)
+ break;
+
+ if (status & (MMCI_INT_DATA_TIMEOUT|MMCI_INT_DATA_CRC_FAIL)) {
+ device_printf(sc->sc_dev,
+ "data xfer error, status %08x\n", status);
+ break;
+ }
+
+ if (status & (MMCI_INT_TX_FIFO_EMPTY|MMCI_INT_TX_FIFO_HALF_EMPTY|
+ MMCI_INT_RX_FIFO_FULL|MMCI_INT_RX_FIFO_HALF_FULL|
+ MMCI_INT_DATA_END|MMCI_INT_DATA_BLOCK_END)) {
+
+ /* Data transfer in progress */
+ if (plmmc_intr_xfer(sc, sc->sc_cmd) == 0 &&
+ sc->sc_fifo_resid == 0) {
+ /* Disable data IRQs */
+ mask = MMCI_READ(sc, MMCI_MASK0_REG);
+ mask &= ~PLMMC_INT_DATA_MASK;
+ MMCI_WRITE(sc, MMCI_MASK0_REG, mask);
+ /* Ignore data status bits after transfer */
+ sc->sc_status_mask &= ~PLMMC_INT_DATA_MASK;
+ }
+ }
+
+ if (status & MMCI_INT_CMD_RESP_END)
+ cv_broadcast(&sc->sc_intr_cv);
+ }
+ if (retry == 0) {
+ device_printf(sc->sc_dev, "intr handler stuck, fifo resid %d, status %08x\n",
+ sc->sc_fifo_resid, MMCI_READ(sc, MMCI_STATUS_REG));
}
- sc->sc_intr_status |= status;
cv_broadcast(&sc->sc_intr_cv);
-
- mutex_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_lock);
return 1;
}
static int
-plmmc_wait_status(struct plmmc_softc *sc, uint32_t mask, int timeout)
+plmmc_wait_cmd(struct plmmc_softc *sc)
{
- int retry, error;
-
- KASSERT(mutex_owned(&sc->sc_intr_lock));
+ int error = 0;
- if (sc->sc_intr_status & mask)
- return 0;
-
- retry = timeout / hz;
- if (sc->sc_ih == NULL)
- retry *= 1000;
+ KASSERT(mutex_owned(&sc->sc_lock));
- while (retry > 0) {
- if (sc->sc_ih == NULL) {
- sc->sc_intr_status |= MMCI_READ(sc, MMCI_STATUS_REG);
- if (sc->sc_intr_status & mask)
- return 0;
- delay(10000);
- } else {
- error = cv_timedwait(&sc->sc_intr_cv,
- &sc->sc_intr_lock, hz);
- if (error && error != EWOULDBLOCK) {
- device_printf(sc->sc_dev,
- "cv_timedwait returned %d\n", error);
- return error;
- }
- if (sc->sc_intr_status & mask)
- return 0;
+ while (error == 0) {
+ if (sc->sc_intr_status & MMCI_INT_CMD_TIMEOUT) {
+ error = ETIMEDOUT;
+ break;
+ } else if (sc->sc_intr_status & MMCI_INT_CMD_RESP_END) {
+ break;
}
- --retry;
+
+ error = cv_timedwait(&sc->sc_intr_cv, &sc->sc_lock, hz * 2);
+ if (error != 0)
+ break;
}
- device_printf(sc->sc_dev, "%s timeout, MMCI_STATUS_REG = %#x\n",
- __func__, MMCI_READ(sc, MMCI_STATUS_REG));
-
- return ETIMEDOUT;
-}
-
-static int
-plmmc_pio_wait(struct plmmc_softc *sc, struct sdmmc_command *cmd)
-{
- uint32_t bit = (cmd->c_flags & SCF_CMD_READ) ?
- MMCI_INT_RX_DATA_AVAIL : MMCI_INT_TX_FIFO_EMPTY;
-
- MMCI_WRITE(sc, MMCI_CLEAR_REG, bit);
- const int error = plmmc_wait_status(sc,
- bit | MMCI_INT_DATA_END | MMCI_INT_DATA_BLOCK_END, hz*2);
- sc->sc_intr_status &= ~bit;
-
return error;
}
@@ -212,22 +274,21 @@
plmmc_pio_transfer(struct plmmc_softc *sc, struct sdmmc_command *cmd,
int xferlen)
{
- uint32_t *datap = (uint32_t *)cmd->c_buf;
- int i;
+ int error = 0;
- for (i = 0; i < xferlen / 4; i++) {
- if (plmmc_pio_wait(sc, cmd))
- return ETIMEDOUT;
- if (cmd->c_flags & SCF_CMD_READ) {
- datap[i] = MMCI_READ(sc, MMCI_FIFO_REG);
- } else {
- MMCI_WRITE(sc, MMCI_FIFO_REG, datap[i]);
- }
- cmd->c_resid -= 4;
- cmd->c_buf += 4;
+ while (sc->sc_fifo_resid > 0 && error == 0) {
+ error = cv_timedwait(&sc->sc_intr_cv,
+ &sc->sc_lock, hz * 5);
+ if (error != 0)
+ break;
+
+ if (sc->sc_intr_status & MMCI_INT_DATA_TIMEOUT)
+ error = ETIMEDOUT;
+ else if (sc->sc_intr_status & MMCI_INT_DATA_CRC_FAIL)
+ error = EIO;
}
- return 0;
+ return error;
}
static int
@@ -321,10 +382,15 @@
struct plmmc_softc *sc = sch;
uint32_t cmdval = MMCI_COMMAND_ENABLE;
- KASSERT(mutex_owned(&sc->sc_intr_lock));
+ KASSERT(mutex_owned(&sc->sc_lock));
const int xferlen = min(cmd->c_resid, PLMMC_MAXXFER);
+ sc->sc_cmd = cmd;
+ sc->sc_fifo_resid = xferlen;
+ sc->sc_status_mask = ~0U;
Home |
Main Index |
Thread Index |
Old Index