Module Name: src Committed By: jmcneill Date: Mon Sep 8 23:51:48 UTC 2014
Modified Files: src/sys/arch/arm/allwinner: awin_mmc.c Log Message: eliminate most of the polling from awin_mmc_exec_command To generate a diff of this commit: cvs rdiff -u -r1.6 -r1.7 src/sys/arch/arm/allwinner/awin_mmc.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/allwinner/awin_mmc.c diff -u src/sys/arch/arm/allwinner/awin_mmc.c:1.6 src/sys/arch/arm/allwinner/awin_mmc.c:1.7 --- src/sys/arch/arm/allwinner/awin_mmc.c:1.6 Mon Sep 8 11:06:03 2014 +++ src/sys/arch/arm/allwinner/awin_mmc.c Mon Sep 8 23:51:48 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: awin_mmc.c,v 1.6 2014/09/08 11:06:03 jmcneill Exp $ */ +/* $NetBSD: awin_mmc.c,v 1.7 2014/09/08 23:51:48 jmcneill Exp $ */ /*- * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca> @@ -29,7 +29,7 @@ #include "locators.h" #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: awin_mmc.c,v 1.6 2014/09/08 11:06:03 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: awin_mmc.c,v 1.7 2014/09/08 23:51:48 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -50,6 +50,7 @@ __KERNEL_RCSID(0, "$NetBSD: awin_mmc.c,v static int awin_mmc_match(device_t, cfdata_t, void *); static void awin_mmc_attach(device_t, device_t, void *); +static void awin_mmc_attach_i(device_t); static int awin_mmc_intr(void *); @@ -91,6 +92,7 @@ struct awin_mmc_softc { void *sc_ih; kmutex_t sc_intr_lock; kcondvar_t sc_intr_cv; + kcondvar_t sc_idst_cv; int sc_mmc_number; int sc_mmc_width; @@ -108,6 +110,8 @@ struct awin_mmc_softc { int sc_idma_ndesc; void *sc_idma_desc; + uint32_t sc_intr_rint; + uint32_t sc_intr_mint; uint32_t sc_idma_idst; bool sc_has_gpio_detect; @@ -219,7 +223,6 @@ awin_mmc_attach(device_t parent, device_ struct awin_mmc_softc * const sc = device_private(self); struct awinio_attach_args * const aio = aux; const struct awin_locators * const loc = &aio->aio_loc; - struct sdmmcbus_attach_args saa; prop_dictionary_t cfg = device_properties(self); const char *pin_name; @@ -228,7 +231,8 @@ awin_mmc_attach(device_t parent, device_ sc->sc_dmat = aio->aio_dmat; sc->sc_mmc_number = loc->loc_port; mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO); - cv_init(&sc->sc_intr_cv, "awinmmcio"); + cv_init(&sc->sc_intr_cv, "awinmmcirq"); + cv_init(&sc->sc_idst_cv, "awinmmcdma"); bus_space_subregion(sc->sc_bst, aio->aio_core_bsh, loc->loc_offset, loc->loc_size, &sc->sc_bsh); @@ -276,6 +280,15 @@ awin_mmc_attach(device_t parent, device_ } aprint_normal_dev(self, "interrupting at irq %d\n", loc->loc_intr); + config_interrupts(self, awin_mmc_attach_i); +} + +static void +awin_mmc_attach_i(device_t self) +{ + struct awin_mmc_softc *sc = device_private(self); + struct sdmmcbus_attach_args saa; + awin_mmc_host_reset(sc); awin_mmc_bus_width(sc, 1); @@ -304,24 +317,59 @@ static int awin_mmc_intr(void *priv) { struct awin_mmc_softc *sc = priv; - uint32_t idst; + uint32_t idst, rint, mint; mutex_enter(&sc->sc_intr_lock); idst = MMC_READ(sc, AWIN_MMC_IDST); - if (!idst) { + rint = MMC_READ(sc, AWIN_MMC_RINT); + mint = MMC_READ(sc, AWIN_MMC_MINT); + if (!idst && !rint && !mint) { mutex_exit(&sc->sc_intr_lock); return 0; } MMC_WRITE(sc, AWIN_MMC_IDST, idst); + MMC_WRITE(sc, AWIN_MMC_RINT, rint); + MMC_WRITE(sc, AWIN_MMC_MINT, mint); - sc->sc_idma_idst |= idst; - cv_broadcast(&sc->sc_intr_cv); + if (idst) { + sc->sc_idma_idst |= idst; + cv_broadcast(&sc->sc_idst_cv); + } + + if (rint) { + sc->sc_intr_rint |= rint; + cv_broadcast(&sc->sc_intr_cv); + } mutex_exit(&sc->sc_intr_lock); return 1; } +static int +awin_mmc_wait_rint(struct awin_mmc_softc *sc, uint32_t mask, int timeout) +{ + int retry = timeout; + int error; + + KASSERT(mutex_owned(&sc->sc_intr_lock)); + + if (sc->sc_intr_rint & mask) + return 0; + + while (retry > 0) { + error = cv_timedwait(&sc->sc_intr_cv, + &sc->sc_intr_lock, hz); + if (error && error != EWOULDBLOCK) + return error; + if (sc->sc_intr_rint & mask) + return 0; + --retry; + } + + return ETIMEDOUT; +} + static void awin_mmc_led(struct awin_mmc_softc *sc, int on) { @@ -342,6 +390,14 @@ awin_mmc_host_reset(sdmmc_chipset_handle MMC_WRITE(sc, AWIN_MMC_GCTRL, MMC_READ(sc, AWIN_MMC_GCTRL) | AWIN_MMC_GCTRL_RESET); + MMC_WRITE(sc, AWIN_MMC_IMASK, + AWIN_MMC_INT_CMD_DONE | AWIN_MMC_INT_ERROR | + AWIN_MMC_INT_DATA_OVER | AWIN_MMC_INT_AUTO_CMD_DONE); + + MMC_WRITE(sc, AWIN_MMC_GCTRL, + MMC_READ(sc, AWIN_MMC_GCTRL) | AWIN_MMC_GCTRL_INTEN); + + return 0; } @@ -418,11 +474,12 @@ awin_mmc_update_clock(struct awin_mmc_so break; delay(10); } + if (retry == 0) { - aprint_error_dev(sc->sc_dev, "timeout updating clk\n"); + aprint_error_dev(sc->sc_dev, "timeout updating clock\n"); return ETIMEDOUT; } - MMC_WRITE(sc, AWIN_MMC_RINT, MMC_READ(sc, AWIN_MMC_RINT)); + return 0; } @@ -578,8 +635,6 @@ awin_mmc_exec_command(sdmmc_chipset_hand { struct awin_mmc_softc *sc = sch; uint32_t cmdval = AWIN_MMC_CMD_START; - uint32_t status; - int retry; #ifdef AWIN_MMC_DEBUG aprint_normal_dev(sc->sc_dev, @@ -588,6 +643,8 @@ awin_mmc_exec_command(sdmmc_chipset_hand cmd->c_blklen); #endif + mutex_enter(&sc->sc_intr_lock); + if (cmd->c_opcode == 0) cmdval |= AWIN_MMC_CMD_SEND_INIT_SEQ; if (cmd->c_flags & SCF_RSP_PRESENT) @@ -617,21 +674,23 @@ awin_mmc_exec_command(sdmmc_chipset_hand MMC_WRITE(sc, AWIN_MMC_BYTECNT, nblks * cmd->c_blklen); } + sc->sc_intr_rint = 0; + MMC_WRITE(sc, AWIN_MMC_ARG, cmd->c_arg); #ifdef AWIN_MMC_DEBUG aprint_normal_dev(sc->sc_dev, "cmdval = %08x\n", cmdval); #endif + if (cmd->c_datalen == 0) { MMC_WRITE(sc, AWIN_MMC_CMD, cmdval | cmd->c_opcode); } else { - mutex_enter(&sc->sc_intr_lock); cmd->c_resid = cmd->c_datalen; cmd->c_error = awin_mmc_dma_prepare(sc, cmd); awin_mmc_led(sc, 0); MMC_WRITE(sc, AWIN_MMC_CMD, cmdval | cmd->c_opcode); if (cmd->c_error == 0) { - cmd->c_error = cv_timedwait(&sc->sc_intr_cv, + cmd->c_error = cv_timedwait(&sc->sc_idst_cv, &sc->sc_intr_lock, hz*10); } if (sc->sc_idma_idst & AWIN_MMC_IDST_ERROR) { @@ -640,66 +699,49 @@ awin_mmc_exec_command(sdmmc_chipset_hand cmd->c_error = ETIMEDOUT; } awin_mmc_led(sc, 1); - mutex_exit(&sc->sc_intr_lock); if (cmd->c_error) { +#ifdef AWIN_MMC_DEBUG aprint_error_dev(sc->sc_dev, "xfer failed, error %d\n", cmd->c_error); +#endif goto done; } } - retry = 0xfffff; - while (--retry > 0) { - status = MMC_READ(sc, AWIN_MMC_RINT); - if (status & AWIN_MMC_INT_ERROR) { - retry = 0; - break; - } - if (status & AWIN_MMC_INT_CMD_DONE) - break; - delay(10); - } - if (retry == 0) { + cmd->c_error = awin_mmc_wait_rint(sc, + AWIN_MMC_INT_ERROR|AWIN_MMC_INT_CMD_DONE, hz * 10); + if (cmd->c_error == 0 && (sc->sc_intr_rint & AWIN_MMC_INT_ERROR)) + cmd->c_error = EIO; + if (cmd->c_error) { #ifdef AWIN_MMC_DEBUG aprint_error_dev(sc->sc_dev, - "RINT (1) timeout, status = %08x\n", status); + "cmd failed, error %d\n", cmd->c_error); #endif - cmd->c_error = ETIMEDOUT; goto done; } -#ifdef AWIN_MMC_DEBUG - aprint_normal_dev(sc->sc_dev, "status = %08x\n", status); -#endif - + if (cmd->c_datalen > 0) { - retry = 0xffff; - while (--retry > 0) { - uint32_t done; - status = MMC_READ(sc, AWIN_MMC_RINT); - if (status & AWIN_MMC_INT_ERROR) { - retry = 0; - break; - } - if (cmd->c_blklen < cmd->c_datalen) - done = status & AWIN_MMC_INT_AUTO_CMD_DONE; - else - done = status & AWIN_MMC_INT_DATA_OVER; - if (done) - break; - delay(10); + cmd->c_error = awin_mmc_wait_rint(sc, + AWIN_MMC_INT_ERROR| + AWIN_MMC_INT_AUTO_CMD_DONE| + AWIN_MMC_INT_DATA_OVER, + hz*10); + if (cmd->c_error == 0 && + (sc->sc_intr_rint & AWIN_MMC_INT_ERROR)) { + cmd->c_error = ETIMEDOUT; } - if (retry == 0) { + if (cmd->c_error) { #ifdef AWIN_MMC_DEBUG aprint_error_dev(sc->sc_dev, - "RINT (2) timeout, status = %08x\n", status); + "data timeout, rint = %08x\n", + sc->sc_intr_rint); #endif cmd->c_error = ETIMEDOUT; goto done; } - } - - if (cmd->c_flags & SCF_RSP_BSY) { - retry = 0xfffff; + } else if (cmd->c_flags & SCF_RSP_BSY) { + uint32_t status; + int retry = 0xfffff; while (--retry > 0) { status = MMC_READ(sc, AWIN_MMC_STATUS); if (status & AWIN_MMC_STATUS_CARD_DATA_BUSY) @@ -708,7 +750,7 @@ awin_mmc_exec_command(sdmmc_chipset_hand if (retry == 0) { #ifdef AWIN_MMC_DEBUG aprint_error_dev(sc->sc_dev, - "RINT (3) timeout, status = %08x\n", status); + "BSY timeout, status = %08x\n", status); #endif cmd->c_error = ETIMEDOUT; goto done; @@ -737,15 +779,15 @@ awin_mmc_exec_command(sdmmc_chipset_hand done: cmd->c_flags |= SCF_ITSDONE; + mutex_exit(&sc->sc_intr_lock); if (cmd->c_error) { +#ifdef AWIN_MMC_DEBUG aprint_error_dev(sc->sc_dev, "i/o error %d\n", cmd->c_error); - MMC_WRITE(sc, AWIN_MMC_GCTRL, AWIN_MMC_GCTRL_RESET); +#endif + awin_mmc_host_reset(sc); awin_mmc_update_clock(sc); } - MMC_WRITE(sc, AWIN_MMC_RINT, 0xffffffff); - MMC_WRITE(sc, AWIN_MMC_GCTRL, - MMC_READ(sc, AWIN_MMC_GCTRL) | AWIN_MMC_GCTRL_FIFORESET); } static void