Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/arm/sunxi Wait for irq instead of polling for cmd c...
details: https://anonhg.NetBSD.org/src/rev/cdc8e9c0549e
branches: trunk
changeset: 357545:cdc8e9c0549e
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Wed Nov 15 00:30:02 2017 +0000
description:
Wait for irq instead of polling for cmd completion.
diffstat:
sys/arch/arm/sunxi/sunxi_nand.c | 105 ++++++++++++++++++++++++++++++++++++---
1 files changed, 96 insertions(+), 9 deletions(-)
diffs (200 lines):
diff -r 150275acf7e2 -r cdc8e9c0549e sys/arch/arm/sunxi/sunxi_nand.c
--- a/sys/arch/arm/sunxi/sunxi_nand.c Tue Nov 14 22:06:40 2017 +0000
+++ b/sys/arch/arm/sunxi/sunxi_nand.c Wed Nov 15 00:30:02 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sunxi_nand.c,v 1.4 2017/11/13 17:37:02 jmcneill Exp $ */
+/* $NetBSD: sunxi_nand.c,v 1.5 2017/11/15 00:30:02 jmcneill Exp $ */
/*-
* Copyright (c) 2017 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sunxi_nand.c,v 1.4 2017/11/13 17:37:02 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sunxi_nand.c,v 1.5 2017/11/15 00:30:02 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -52,8 +52,11 @@
#define NDFC_ST 0x04
#define NDFC_ST_RB_STATE(n) __BIT(8 + (n))
#define NDFC_ST_CMD_FIFO_STATUS __BIT(3)
+#define NDFC_ST_DMA_INT_FLAG __BIT(2)
#define NDFC_ST_CMD_INT_FLAG __BIT(1)
+#define NDFC_ST_INT_MASK __BITS(2,0)
#define NDFC_INT 0x08
+#define NDFC_INT_CMD_INT_ENABLE __BIT(1)
#define NDFC_TIMING_CTL 0x0c
#define NDFC_TIMING_CFG 0x10
#define NDFC_ADDR_LOW 0x14
@@ -130,6 +133,12 @@
int sc_phandle;
bus_space_tag_t sc_bst;
bus_space_handle_t sc_bsh;
+ void *sc_ih;
+
+ kmutex_t sc_lock;
+ kcondvar_t sc_cv;
+
+ uint32_t sc_intr;
struct clk *sc_clk_mod;
struct clk *sc_clk_ahb;
@@ -157,7 +166,7 @@
sunxi_nand_wait_status(struct sunxi_nand_softc *sc, uint32_t mask, uint32_t val)
{
uint32_t status;
- int retry;
+ int retry, error = 0;
for (retry = 1000000; retry > 0; retry--) {
status = NAND_READ(sc, NDFC_ST);
@@ -171,13 +180,42 @@
"device timeout; status=%x mask=%x val=%x\n",
status, mask, val);
#endif
- return ETIMEDOUT;
+ error = ETIMEDOUT;
}
if (mask == NDFC_ST_CMD_INT_FLAG)
NAND_WRITE(sc, NDFC_ST, NDFC_ST_CMD_INT_FLAG);
- return 0;
+ return error;
+}
+
+static int
+sunxi_nand_wait_intr(struct sunxi_nand_softc *sc, uint32_t mask)
+{
+ struct bintime timeo, epsilon;
+ int error = 0;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
+
+ sc->sc_intr = 0;
+
+ /* Enable interrupts */
+ NAND_WRITE(sc, NDFC_INT, mask);
+
+ /* Wait for the command to complete */
+ timeo = ms2bintime(1000);
+ epsilon = ms2bintime(1000);
+ do {
+ if (sc->sc_intr & mask)
+ break;
+ error = cv_timedwaitbt(&sc->sc_cv, &sc->sc_lock, &timeo,
+ &epsilon);
+ } while (error == 0);
+
+ /* Disable interrupts */
+ NAND_WRITE(sc, NDFC_INT, 0);
+
+ return error;
}
static void
@@ -232,8 +270,15 @@
NDFC_CMD_DATA_TRANS | NDFC_CMD_DATA_METHOD);
/* Wait for the command to finish */
- error = sunxi_nand_wait_status(sc, NDFC_ST_CMD_INT_FLAG,
- NDFC_ST_CMD_INT_FLAG);
+ if (cold) {
+ error = sunxi_nand_wait_status(sc, NDFC_ST_CMD_INT_FLAG,
+ NDFC_ST_CMD_INT_FLAG);
+ } else {
+ mutex_enter(&sc->sc_lock);
+ error = sunxi_nand_wait_intr(sc, NDFC_ST_CMD_INT_FLAG);
+ mutex_exit(&sc->sc_lock);
+ }
+
if (error != 0)
return error;
@@ -293,8 +338,14 @@
NDFC_CMD_ACCESS_DIR);
/* Wait for the command to finish */
- error = sunxi_nand_wait_status(sc, NDFC_ST_CMD_INT_FLAG,
- NDFC_ST_CMD_INT_FLAG);
+ if (cold) {
+ error = sunxi_nand_wait_status(sc, NDFC_ST_CMD_INT_FLAG,
+ NDFC_ST_CMD_INT_FLAG);
+ } else {
+ mutex_enter(&sc->sc_lock);
+ error = sunxi_nand_wait_intr(sc, NDFC_ST_CMD_INT_FLAG);
+ mutex_exit(&sc->sc_lock);
+ }
if (error != 0)
return error;
@@ -429,6 +480,26 @@
sunxi_nand_write_buf_n(dev, data, len, 2);
}
+static int
+sunxi_nand_intr(void *priv)
+{
+ struct sunxi_nand_softc * const sc = priv;
+ uint32_t status;
+ int rv = 0;
+
+ mutex_enter(&sc->sc_lock);
+ status = NAND_READ(sc, NDFC_ST) & NDFC_ST_INT_MASK;
+ if (status) {
+ sc->sc_intr |= status;
+ NAND_WRITE(sc, NDFC_ST, status);
+ cv_signal(&sc->sc_cv);
+ rv = 1;
+ }
+ mutex_exit(&sc->sc_lock);
+
+ return rv;
+}
+
static void
sunxi_nand_attach_chip(struct sunxi_nand_softc *sc,
struct sunxi_nand_chip *chip, int phandle)
@@ -569,6 +640,7 @@
struct sunxi_nand_softc * const sc = device_private(self);
struct fdt_attach_args * const faa = aux;
const int phandle = faa->faa_phandle;
+ char intrstr[128];
bus_addr_t addr;
bus_size_t size;
int child;
@@ -577,6 +649,10 @@
aprint_error(": couldn't get registers\n");
return;
}
+ if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
+ aprint_error(": couldn't decode interrupt\n");
+ return;
+ }
sc->sc_dev = self;
sc->sc_phandle = phandle;
@@ -585,10 +661,21 @@
aprint_error(": couldn't map registers\n");
return;
}
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
+ cv_init(&sc->sc_cv, "nandxfer");
aprint_naive("\n");
aprint_normal(": NAND Flash Controller\n");
+ sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_VM, FDT_INTR_MPSAFE,
+ sunxi_nand_intr, sc);
+ if (sc->sc_ih == NULL) {
+ aprint_error_dev(self, "couldn't establish interrupt on %s\n",
+ intrstr);
+ return;
+ }
+ aprint_normal_dev(self, "interrupting on %s\n", intrstr);
+
if (sunxi_nand_init_resources(sc) != 0) {
aprint_error_dev(self, "couldn't initialize resources\n");
return;
Home |
Main Index |
Thread Index |
Old Index