Annotation of src/sys/dev/sdmmc/ld_sdmmc.c, Revision 1.26
1.26 ! jmcneill 1: /* $NetBSD: ld_sdmmc.c,v 1.25 2017/01/07 16:24:40 martin 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.26 ! jmcneill 31: __KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.25 2017/01/07 16:24:40 martin 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.1 nonaka 51:
52: #include <dev/ldvar.h>
53:
54: #include <dev/sdmmc/sdmmcvar.h>
55:
1.23 pgoyette 56: #include "ioconf.h"
57:
1.14 jmcneill 58: #ifdef LD_SDMMC_DEBUG
1.1 nonaka 59: #define DPRINTF(s) printf s
60: #else
61: #define DPRINTF(s) /**/
62: #endif
63:
1.24 kiyohara 64: #define LD_SDMMC_IORETRIES 5 /* number of retries before giving up */
65: #define RECOVERYTIME hz/2 /* time to wait before retrying a cmd */
66:
1.1 nonaka 67: struct ld_sdmmc_softc;
68:
69: struct ld_sdmmc_task {
70: struct sdmmc_task task;
71:
72: struct ld_sdmmc_softc *task_sc;
73: struct buf *task_bp;
1.24 kiyohara 74: int task_retries; /* number of xfer retry */
75: struct callout task_restart_ch;
1.1 nonaka 76: };
77:
78: struct ld_sdmmc_softc {
79: struct ld_softc sc_ld;
80: int sc_hwunit;
81:
82: struct sdmmc_function *sc_sf;
1.20 mlelstv 83: #define LD_SDMMC_MAXQUEUECNT 4
84: struct ld_sdmmc_task sc_task[LD_SDMMC_MAXQUEUECNT];
1.24 kiyohara 85: TAILQ_HEAD(, sdmmc_task) sc_freeq;
1.1 nonaka 86: };
87:
1.2 cegger 88: static int ld_sdmmc_match(device_t, cfdata_t, void *);
1.1 nonaka 89: static void ld_sdmmc_attach(device_t, device_t, void *);
90: static int ld_sdmmc_detach(device_t, int);
91:
92: static int ld_sdmmc_dump(struct ld_softc *, void *, int, int);
93: static int ld_sdmmc_start(struct ld_softc *, struct buf *);
1.24 kiyohara 94: static void ld_sdmmc_restart(void *);
1.1 nonaka 95:
1.3 nonaka 96: static void ld_sdmmc_doattach(void *);
1.1 nonaka 97: static void ld_sdmmc_dobio(void *);
98:
99: CFATTACH_DECL_NEW(ld_sdmmc, sizeof(struct ld_sdmmc_softc),
100: ld_sdmmc_match, ld_sdmmc_attach, ld_sdmmc_detach, NULL);
101:
102:
103: /* ARGSUSED */
104: static int
1.2 cegger 105: ld_sdmmc_match(device_t parent, cfdata_t match, void *aux)
1.1 nonaka 106: {
107: struct sdmmc_softc *sdmsc = device_private(parent);
108:
109: if (ISSET(sdmsc->sc_flags, SMF_MEM_MODE))
110: return 1;
111: return 0;
112: }
113:
114: /* ARGSUSED */
115: static void
116: ld_sdmmc_attach(device_t parent, device_t self, void *aux)
117: {
118: struct ld_sdmmc_softc *sc = device_private(self);
119: struct sdmmc_attach_args *sa = aux;
120: struct ld_softc *ld = &sc->sc_ld;
1.24 kiyohara 121: struct ld_sdmmc_task *task;
1.3 nonaka 122: struct lwp *lwp;
1.24 kiyohara 123: int i;
1.1 nonaka 124:
125: ld->sc_dv = self;
126:
1.11 jakllsch 127: aprint_normal(": <0x%02x:0x%04x:%s:0x%02x:0x%08x:0x%03x>\n",
128: sa->sf->cid.mid, sa->sf->cid.oid, sa->sf->cid.pnm,
129: sa->sf->cid.rev, sa->sf->cid.psn, sa->sf->cid.mdt);
1.1 nonaka 130: aprint_naive("\n");
131:
1.24 kiyohara 132: TAILQ_INIT(&sc->sc_freeq);
133: for (i = 0; i < __arraycount(sc->sc_task); i++) {
134: task = &sc->sc_task[i];
135: task->task_sc = sc;
136: callout_init(&task->task_restart_ch, 0);
137: TAILQ_INSERT_TAIL(&sc->sc_freeq, &task->task, next);
138: }
1.20 mlelstv 139:
1.1 nonaka 140: sc->sc_hwunit = 0; /* always 0? */
141: sc->sc_sf = sa->sf;
142:
143: ld->sc_flags = LDF_ENABLED;
144: ld->sc_secperunit = sc->sc_sf->csd.capacity;
1.4 nonaka 145: ld->sc_secsize = SDMMC_SECTOR_SIZE;
1.1 nonaka 146: ld->sc_maxxfer = MAXPHYS;
1.20 mlelstv 147: ld->sc_maxqueuecnt = LD_SDMMC_MAXQUEUECNT;
1.1 nonaka 148: ld->sc_dump = ld_sdmmc_dump;
149: ld->sc_start = ld_sdmmc_start;
150:
1.3 nonaka 151: /*
1.11 jakllsch 152: * It is avoided that the error occurs when the card attaches it,
1.3 nonaka 153: * when wedge is supported.
154: */
1.12 christos 155: config_pending_incr(self);
1.3 nonaka 156: if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
157: ld_sdmmc_doattach, sc, &lwp, "%sattach", device_xname(self))) {
158: aprint_error_dev(self, "couldn't create thread\n");
159: }
160: }
161:
162: static void
163: ld_sdmmc_doattach(void *arg)
164: {
165: struct ld_sdmmc_softc *sc = (struct ld_sdmmc_softc *)arg;
166: struct ld_softc *ld = &sc->sc_ld;
1.6 kiyohara 167: struct sdmmc_softc *ssc = device_private(device_parent(ld->sc_dv));
1.3 nonaka 168:
1.22 jdolecek 169: ldattach(ld, BUFQ_DISK_DEFAULT_STRAT);
1.19 jmcneill 170: aprint_normal_dev(ld->sc_dv, "%d-bit width,", sc->sc_sf->width);
171: if (ssc->sc_transfer_mode != NULL)
172: aprint_normal(" %s,", ssc->sc_transfer_mode);
1.6 kiyohara 173: if ((ssc->sc_busclk / 1000) != 0)
174: aprint_normal(" %u.%03u MHz\n",
175: ssc->sc_busclk / 1000, ssc->sc_busclk % 1000);
176: else
177: aprint_normal(" %u KHz\n", ssc->sc_busclk % 1000);
1.12 christos 178: config_pending_decr(ld->sc_dv);
1.3 nonaka 179: kthread_exit(0);
1.1 nonaka 180: }
181:
182: static int
183: ld_sdmmc_detach(device_t dev, int flags)
184: {
185: struct ld_sdmmc_softc *sc = device_private(dev);
186: struct ld_softc *ld = &sc->sc_ld;
1.24 kiyohara 187: int rv, i;
1.1 nonaka 188:
189: if ((rv = ldbegindetach(ld, flags)) != 0)
190: return rv;
191: ldenddetach(ld);
192:
1.24 kiyohara 193: for (i = 0; i < __arraycount(sc->sc_task); i++)
194: callout_destroy(&sc->sc_task[i].task_restart_ch);
195:
1.1 nonaka 196: return 0;
197: }
198:
199: static int
200: ld_sdmmc_start(struct ld_softc *ld, struct buf *bp)
201: {
202: struct ld_sdmmc_softc *sc = device_private(ld->sc_dv);
1.24 kiyohara 203: struct ld_sdmmc_task *task = (void *)TAILQ_FIRST(&sc->sc_freeq);
1.20 mlelstv 204:
1.24 kiyohara 205: TAILQ_REMOVE(&sc->sc_freeq, &task->task, next);
1.1 nonaka 206:
207: task->task_bp = bp;
1.24 kiyohara 208: task->task_retries = 0;
1.1 nonaka 209: sdmmc_init_task(&task->task, ld_sdmmc_dobio, task);
210:
211: sdmmc_add_task(sc->sc_sf->sc, &task->task);
212:
213: return 0;
214: }
215:
216: static void
1.24 kiyohara 217: ld_sdmmc_restart(void *arg)
218: {
219: struct ld_sdmmc_task *task = (struct ld_sdmmc_task *)arg;
220: struct ld_sdmmc_softc *sc = task->task_sc;
221: struct buf *bp = task->task_bp;
222:
223: bp->b_resid = bp->b_bcount;
224:
225: sdmmc_add_task(sc->sc_sf->sc, &task->task);
226: }
227:
228: static void
1.1 nonaka 229: ld_sdmmc_dobio(void *arg)
230: {
231: struct ld_sdmmc_task *task = (struct ld_sdmmc_task *)arg;
232: struct ld_sdmmc_softc *sc = task->task_sc;
233: struct buf *bp = task->task_bp;
1.18 mlelstv 234: int error;
1.1 nonaka 235:
236: /*
237: * I/O operation
238: */
239: DPRINTF(("%s: I/O operation (dir=%s, blkno=0x%jx, bcnt=0x%x)\n",
240: device_xname(sc->sc_ld.sc_dv), bp->b_flags & B_READ ? "IN" : "OUT",
241: bp->b_rawblkno, bp->b_bcount));
242:
243: /* is everything done in terms of blocks? */
244: if (bp->b_rawblkno >= sc->sc_sf->csd.capacity) {
245: /* trying to read or write past end of device */
1.13 mlelstv 246: aprint_error_dev(sc->sc_ld.sc_dv,
247: "blkno 0x%" PRIu64 " exceeds capacity %d\n",
248: bp->b_rawblkno, sc->sc_sf->csd.capacity);
249: bp->b_error = EINVAL;
1.1 nonaka 250: bp->b_resid = bp->b_bcount;
1.26 ! jmcneill 251:
! 252: goto done;
1.1 nonaka 253: }
254:
255: if (bp->b_flags & B_READ)
256: error = sdmmc_mem_read_block(sc->sc_sf, bp->b_rawblkno,
257: bp->b_data, bp->b_bcount);
258: else
259: error = sdmmc_mem_write_block(sc->sc_sf, bp->b_rawblkno,
260: bp->b_data, bp->b_bcount);
261: if (error) {
1.24 kiyohara 262: if (task->task_retries < LD_SDMMC_IORETRIES) {
263: struct dk_softc *dksc = &sc->sc_ld.sc_dksc;
264: struct cfdriver *cd = device_cfdriver(dksc->sc_dev);
265:
266: diskerr(bp, cd->cd_name, "error", LOG_PRINTF, 0,
267: dksc->sc_dkdev.dk_label);
268: printf(", retrying\n");
269: task->task_retries++;
270: callout_reset(&task->task_restart_ch, RECOVERYTIME,
271: ld_sdmmc_restart, task);
272: return;
273: }
1.13 mlelstv 274: bp->b_error = error;
1.1 nonaka 275: bp->b_resid = bp->b_bcount;
276: } else {
277: bp->b_resid = 0;
278: }
279:
1.26 ! jmcneill 280: done:
1.24 kiyohara 281: TAILQ_INSERT_TAIL(&sc->sc_freeq, &task->task, next);
282:
1.1 nonaka 283: lddone(&sc->sc_ld, bp);
284: }
285:
286: static int
287: ld_sdmmc_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt)
288: {
289: struct ld_sdmmc_softc *sc = device_private(ld->sc_dv);
290:
291: return sdmmc_mem_write_block(sc->sc_sf, blkno, data,
292: blkcnt * ld->sc_secsize);
293: }
1.23 pgoyette 294:
295: MODULE(MODULE_CLASS_DRIVER, ld_sdmmc, "ld");
296:
297: #ifdef _MODULE
298: /*
299: * XXX Don't allow ioconf.c to redefine the "struct cfdriver ld_cd"
300: * XXX it will be defined in the common-code module
301: */
302: #undef CFDRIVER_DECL
303: #define CFDRIVER_DECL(name, class, attr)
304: #include "ioconf.c"
305: #endif
306:
307: static int
308: ld_sdmmc_modcmd(modcmd_t cmd, void *opaque)
309: {
310: #ifdef _MODULE
311: /*
312: * We ignore the cfdriver_vec[] that ioconf provides, since
313: * the cfdrivers are attached already.
314: */
315: static struct cfdriver * const no_cfdriver_vec[] = { NULL };
316: #endif
317: int error = 0;
318:
319: #ifdef _MODULE
320: switch (cmd) {
321: case MODULE_CMD_INIT:
322: error = config_init_component(no_cfdriver_vec,
323: cfattach_ioconf_ld_sdmmc, cfdata_ioconf_ld_sdmmc);
324: break;
325: case MODULE_CMD_FINI:
326: error = config_fini_component(no_cfdriver_vec,
327: cfattach_ioconf_ld_sdmmc, cfdata_ioconf_ld_sdmmc);
328: break;
329: default:
330: error = ENOTTY;
331: break;
332: }
333: #endif
334:
335: return error;
336: }
CVSweb <webmaster@jp.NetBSD.org>