[BACK]Return to ld_sdmmc.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / sdmmc

Annotation of src/sys/dev/sdmmc/ld_sdmmc.c, Revision 1.28

1.28    ! jmcneill    1: /*     $NetBSD: ld_sdmmc.c,v 1.27 2017/06/06 21:01:07 jmcneill Exp $   */
1.1       nonaka      2:
                      3: /*
                      4:  * Copyright (c) 2008 KIYOHARA Takashi
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     18:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     19:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     20:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     21:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     22:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     24:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     25:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     26:  * POSSIBILITY OF SUCH DAMAGE.
                     27:  *
                     28:  */
                     29:
                     30: #include <sys/cdefs.h>
1.28    ! jmcneill   31: __KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.27 2017/06/06 21:01:07 jmcneill Exp $");
1.1       nonaka     32:
1.9       matt       33: #ifdef _KERNEL_OPT
                     34: #include "opt_sdmmc.h"
                     35: #endif
1.1       nonaka     36:
                     37: #include <sys/param.h>
                     38: #include <sys/systm.h>
                     39: #include <sys/kernel.h>
                     40: #include <sys/device.h>
                     41: #include <sys/buf.h>
                     42: #include <sys/bufq.h>
                     43: #include <sys/bus.h>
                     44: #include <sys/endian.h>
                     45: #include <sys/dkio.h>
                     46: #include <sys/disk.h>
1.25      martin     47: #include <sys/disklabel.h>
1.3       nonaka     48: #include <sys/kthread.h>
1.25      martin     49: #include <sys/syslog.h>
1.23      pgoyette   50: #include <sys/module.h>
1.27      jmcneill   51: #include <sys/pcq.h>
1.1       nonaka     52:
                     53: #include <dev/ldvar.h>
                     54:
                     55: #include <dev/sdmmc/sdmmcvar.h>
                     56:
1.23      pgoyette   57: #include "ioconf.h"
                     58:
1.14      jmcneill   59: #ifdef LD_SDMMC_DEBUG
1.1       nonaka     60: #define DPRINTF(s)     printf s
                     61: #else
                     62: #define DPRINTF(s)     /**/
                     63: #endif
                     64:
1.24      kiyohara   65: #define        LD_SDMMC_IORETRIES      5       /* number of retries before giving up */
                     66: #define        RECOVERYTIME            hz/2    /* time to wait before retrying a cmd */
                     67:
1.1       nonaka     68: struct ld_sdmmc_softc;
                     69:
                     70: struct ld_sdmmc_task {
                     71:        struct sdmmc_task task;
                     72:
                     73:        struct ld_sdmmc_softc *task_sc;
                     74:        struct buf *task_bp;
1.24      kiyohara   75:        int task_retries; /* number of xfer retry */
                     76:        struct callout task_restart_ch;
1.1       nonaka     77: };
                     78:
                     79: struct ld_sdmmc_softc {
                     80:        struct ld_softc sc_ld;
                     81:        int sc_hwunit;
                     82:
                     83:        struct sdmmc_function *sc_sf;
1.20      mlelstv    84: #define LD_SDMMC_MAXQUEUECNT 4
                     85:        struct ld_sdmmc_task sc_task[LD_SDMMC_MAXQUEUECNT];
1.27      jmcneill   86:        pcq_t *sc_freeq;
1.1       nonaka     87: };
                     88:
1.2       cegger     89: static int ld_sdmmc_match(device_t, cfdata_t, void *);
1.1       nonaka     90: static void ld_sdmmc_attach(device_t, device_t, void *);
                     91: static int ld_sdmmc_detach(device_t, int);
                     92:
                     93: static int ld_sdmmc_dump(struct ld_softc *, void *, int, int);
                     94: static int ld_sdmmc_start(struct ld_softc *, struct buf *);
1.24      kiyohara   95: static void ld_sdmmc_restart(void *);
1.28    ! jmcneill   96: static int ld_sdmmc_discard(struct ld_softc *, off_t, off_t);
1.1       nonaka     97:
1.3       nonaka     98: static void ld_sdmmc_doattach(void *);
1.1       nonaka     99: static void ld_sdmmc_dobio(void *);
                    100:
                    101: CFATTACH_DECL_NEW(ld_sdmmc, sizeof(struct ld_sdmmc_softc),
                    102:     ld_sdmmc_match, ld_sdmmc_attach, ld_sdmmc_detach, NULL);
                    103:
                    104:
                    105: /* ARGSUSED */
                    106: static int
1.2       cegger    107: ld_sdmmc_match(device_t parent, cfdata_t match, void *aux)
1.1       nonaka    108: {
                    109:        struct sdmmc_softc *sdmsc = device_private(parent);
                    110:
                    111:        if (ISSET(sdmsc->sc_flags, SMF_MEM_MODE))
                    112:                return 1;
                    113:        return 0;
                    114: }
                    115:
                    116: /* ARGSUSED */
                    117: static void
                    118: ld_sdmmc_attach(device_t parent, device_t self, void *aux)
                    119: {
                    120:        struct ld_sdmmc_softc *sc = device_private(self);
                    121:        struct sdmmc_attach_args *sa = aux;
                    122:        struct ld_softc *ld = &sc->sc_ld;
1.24      kiyohara  123:        struct ld_sdmmc_task *task;
1.3       nonaka    124:        struct lwp *lwp;
1.24      kiyohara  125:        int i;
1.1       nonaka    126:
                    127:        ld->sc_dv = self;
                    128:
1.11      jakllsch  129:        aprint_normal(": <0x%02x:0x%04x:%s:0x%02x:0x%08x:0x%03x>\n",
                    130:            sa->sf->cid.mid, sa->sf->cid.oid, sa->sf->cid.pnm,
                    131:            sa->sf->cid.rev, sa->sf->cid.psn, sa->sf->cid.mdt);
1.1       nonaka    132:        aprint_naive("\n");
                    133:
1.27      jmcneill  134:        const int ntask = __arraycount(sc->sc_task);
                    135:        sc->sc_freeq = pcq_create(ntask, KM_SLEEP);
                    136:        for (i = 0; i < ntask; i++) {
1.24      kiyohara  137:                task = &sc->sc_task[i];
                    138:                task->task_sc = sc;
1.27      jmcneill  139:                callout_init(&task->task_restart_ch, CALLOUT_MPSAFE);
                    140:                pcq_put(sc->sc_freeq, task);
1.24      kiyohara  141:        }
1.20      mlelstv   142:
1.1       nonaka    143:        sc->sc_hwunit = 0;      /* always 0? */
                    144:        sc->sc_sf = sa->sf;
                    145:
                    146:        ld->sc_flags = LDF_ENABLED;
                    147:        ld->sc_secperunit = sc->sc_sf->csd.capacity;
1.4       nonaka    148:        ld->sc_secsize = SDMMC_SECTOR_SIZE;
1.1       nonaka    149:        ld->sc_maxxfer = MAXPHYS;
1.20      mlelstv   150:        ld->sc_maxqueuecnt = LD_SDMMC_MAXQUEUECNT;
1.1       nonaka    151:        ld->sc_dump = ld_sdmmc_dump;
                    152:        ld->sc_start = ld_sdmmc_start;
1.28    ! jmcneill  153:        ld->sc_discard = ld_sdmmc_discard;
1.1       nonaka    154:
1.3       nonaka    155:        /*
1.11      jakllsch  156:         * It is avoided that the error occurs when the card attaches it,
1.3       nonaka    157:         * when wedge is supported.
                    158:         */
1.12      christos  159:        config_pending_incr(self);
1.3       nonaka    160:        if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
                    161:            ld_sdmmc_doattach, sc, &lwp, "%sattach", device_xname(self))) {
                    162:                aprint_error_dev(self, "couldn't create thread\n");
                    163:        }
                    164: }
                    165:
                    166: static void
                    167: ld_sdmmc_doattach(void *arg)
                    168: {
                    169:        struct ld_sdmmc_softc *sc = (struct ld_sdmmc_softc *)arg;
                    170:        struct ld_softc *ld = &sc->sc_ld;
1.6       kiyohara  171:        struct sdmmc_softc *ssc = device_private(device_parent(ld->sc_dv));
1.3       nonaka    172:
1.22      jdolecek  173:        ldattach(ld, BUFQ_DISK_DEFAULT_STRAT);
1.19      jmcneill  174:        aprint_normal_dev(ld->sc_dv, "%d-bit width,", sc->sc_sf->width);
                    175:        if (ssc->sc_transfer_mode != NULL)
                    176:                aprint_normal(" %s,", ssc->sc_transfer_mode);
1.6       kiyohara  177:        if ((ssc->sc_busclk / 1000) != 0)
                    178:                aprint_normal(" %u.%03u MHz\n",
                    179:                    ssc->sc_busclk / 1000, ssc->sc_busclk % 1000);
                    180:        else
                    181:                aprint_normal(" %u KHz\n", ssc->sc_busclk % 1000);
1.12      christos  182:        config_pending_decr(ld->sc_dv);
1.3       nonaka    183:        kthread_exit(0);
1.1       nonaka    184: }
                    185:
                    186: static int
                    187: ld_sdmmc_detach(device_t dev, int flags)
                    188: {
                    189:        struct ld_sdmmc_softc *sc = device_private(dev);
                    190:        struct ld_softc *ld = &sc->sc_ld;
1.24      kiyohara  191:        int rv, i;
1.1       nonaka    192:
                    193:        if ((rv = ldbegindetach(ld, flags)) != 0)
                    194:                return rv;
                    195:        ldenddetach(ld);
                    196:
1.24      kiyohara  197:        for (i = 0; i < __arraycount(sc->sc_task); i++)
                    198:                callout_destroy(&sc->sc_task[i].task_restart_ch);
                    199:
1.27      jmcneill  200:        pcq_destroy(sc->sc_freeq);
                    201:
1.1       nonaka    202:        return 0;
                    203: }
                    204:
                    205: static int
                    206: ld_sdmmc_start(struct ld_softc *ld, struct buf *bp)
                    207: {
                    208:        struct ld_sdmmc_softc *sc = device_private(ld->sc_dv);
1.27      jmcneill  209:        struct ld_sdmmc_task *task = pcq_get(sc->sc_freeq);
1.20      mlelstv   210:
1.27      jmcneill  211:        if (task == NULL)
                    212:                return EAGAIN;
1.1       nonaka    213:
                    214:        task->task_bp = bp;
1.24      kiyohara  215:        task->task_retries = 0;
1.1       nonaka    216:        sdmmc_init_task(&task->task, ld_sdmmc_dobio, task);
                    217:
                    218:        sdmmc_add_task(sc->sc_sf->sc, &task->task);
                    219:
                    220:        return 0;
                    221: }
                    222:
                    223: static void
1.24      kiyohara  224: ld_sdmmc_restart(void *arg)
                    225: {
                    226:        struct ld_sdmmc_task *task = (struct ld_sdmmc_task *)arg;
                    227:        struct ld_sdmmc_softc *sc = task->task_sc;
                    228:        struct buf *bp = task->task_bp;
                    229:
                    230:        bp->b_resid = bp->b_bcount;
                    231:
                    232:        sdmmc_add_task(sc->sc_sf->sc, &task->task);
                    233: }
                    234:
                    235: static void
1.1       nonaka    236: ld_sdmmc_dobio(void *arg)
                    237: {
                    238:        struct ld_sdmmc_task *task = (struct ld_sdmmc_task *)arg;
                    239:        struct ld_sdmmc_softc *sc = task->task_sc;
                    240:        struct buf *bp = task->task_bp;
1.18      mlelstv   241:        int error;
1.1       nonaka    242:
                    243:        /*
                    244:         * I/O operation
                    245:         */
                    246:        DPRINTF(("%s: I/O operation (dir=%s, blkno=0x%jx, bcnt=0x%x)\n",
                    247:            device_xname(sc->sc_ld.sc_dv), bp->b_flags & B_READ ? "IN" : "OUT",
                    248:            bp->b_rawblkno, bp->b_bcount));
                    249:
                    250:        /* is everything done in terms of blocks? */
                    251:        if (bp->b_rawblkno >= sc->sc_sf->csd.capacity) {
                    252:                /* trying to read or write past end of device */
1.13      mlelstv   253:                aprint_error_dev(sc->sc_ld.sc_dv,
                    254:                    "blkno 0x%" PRIu64 " exceeds capacity %d\n",
                    255:                    bp->b_rawblkno, sc->sc_sf->csd.capacity);
                    256:                bp->b_error = EINVAL;
1.1       nonaka    257:                bp->b_resid = bp->b_bcount;
1.26      jmcneill  258:
                    259:                goto done;
1.1       nonaka    260:        }
                    261:
                    262:        if (bp->b_flags & B_READ)
                    263:                error = sdmmc_mem_read_block(sc->sc_sf, bp->b_rawblkno,
                    264:                    bp->b_data, bp->b_bcount);
                    265:        else
                    266:                error = sdmmc_mem_write_block(sc->sc_sf, bp->b_rawblkno,
                    267:                    bp->b_data, bp->b_bcount);
                    268:        if (error) {
1.24      kiyohara  269:                if (task->task_retries < LD_SDMMC_IORETRIES) {
                    270:                        struct dk_softc *dksc = &sc->sc_ld.sc_dksc;
                    271:                        struct cfdriver *cd = device_cfdriver(dksc->sc_dev);
                    272:
                    273:                        diskerr(bp, cd->cd_name, "error", LOG_PRINTF, 0,
                    274:                                dksc->sc_dkdev.dk_label);
                    275:                        printf(", retrying\n");
                    276:                        task->task_retries++;
                    277:                        callout_reset(&task->task_restart_ch, RECOVERYTIME,
                    278:                            ld_sdmmc_restart, task);
                    279:                        return;
                    280:                }
1.13      mlelstv   281:                bp->b_error = error;
1.1       nonaka    282:                bp->b_resid = bp->b_bcount;
                    283:        } else {
                    284:                bp->b_resid = 0;
                    285:        }
                    286:
1.26      jmcneill  287: done:
1.27      jmcneill  288:        pcq_put(sc->sc_freeq, task);
1.24      kiyohara  289:
1.1       nonaka    290:        lddone(&sc->sc_ld, bp);
                    291: }
                    292:
                    293: static int
                    294: ld_sdmmc_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt)
                    295: {
                    296:        struct ld_sdmmc_softc *sc = device_private(ld->sc_dv);
                    297:
                    298:        return sdmmc_mem_write_block(sc->sc_sf, blkno, data,
                    299:            blkcnt * ld->sc_secsize);
                    300: }
1.23      pgoyette  301:
1.28    ! jmcneill  302: static int
        !           303: ld_sdmmc_discard(struct ld_softc *ld, off_t pos, off_t len)
        !           304: {
        !           305:        struct ld_sdmmc_softc *sc = device_private(ld->sc_dv);
        !           306:
        !           307:        return sdmmc_mem_discard(sc->sc_sf, pos, len);
        !           308: }
        !           309:
1.23      pgoyette  310: MODULE(MODULE_CLASS_DRIVER, ld_sdmmc, "ld");
                    311:
                    312: #ifdef _MODULE
                    313: /*
                    314:  * XXX Don't allow ioconf.c to redefine the "struct cfdriver ld_cd"
                    315:  * XXX it will be defined in the common-code module
                    316:  */
                    317: #undef  CFDRIVER_DECL
                    318: #define CFDRIVER_DECL(name, class, attr)
                    319: #include "ioconf.c"
                    320: #endif
                    321:
                    322: static int
                    323: ld_sdmmc_modcmd(modcmd_t cmd, void *opaque)
                    324: {
                    325: #ifdef _MODULE
                    326:        /*
                    327:         * We ignore the cfdriver_vec[] that ioconf provides, since
                    328:         * the cfdrivers are attached already.
                    329:         */
                    330:        static struct cfdriver * const no_cfdriver_vec[] = { NULL };
                    331: #endif
                    332:        int error = 0;
                    333:
                    334: #ifdef _MODULE
                    335:        switch (cmd) {
                    336:        case MODULE_CMD_INIT:
                    337:                error = config_init_component(no_cfdriver_vec,
                    338:                    cfattach_ioconf_ld_sdmmc, cfdata_ioconf_ld_sdmmc);
                    339:                break;
                    340:        case MODULE_CMD_FINI:
                    341:                error = config_fini_component(no_cfdriver_vec,
                    342:                    cfattach_ioconf_ld_sdmmc, cfdata_ioconf_ld_sdmmc);
                    343:                break;
                    344:        default:
                    345:                error = ENOTTY;
                    346:                break;
                    347:        }
                    348: #endif
                    349:
                    350:        return error;
                    351: }

CVSweb <webmaster@jp.NetBSD.org>