mmcsd.c revision 170002
1163516Simp/*-
2163516Simp * Copyright (c) 2006 Bernd Walter.  All rights reserved.
3163516Simp * Copyright (c) 2006 M. Warner Losh.  All rights reserved.
4163516Simp *
5163516Simp * Redistribution and use in source and binary forms, with or without
6163516Simp * modification, are permitted provided that the following conditions
7163516Simp * are met:
8163516Simp * 1. Redistributions of source code must retain the above copyright
9163516Simp *    notice, this list of conditions and the following disclaimer.
10163516Simp * 2. Redistributions in binary form must reproduce the above copyright
11163516Simp *    notice, this list of conditions and the following disclaimer in the
12163516Simp *    documentation and/or other materials provided with the distribution.
13163516Simp *
14163516Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15163516Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16163516Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17163516Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18163516Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19163516Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20163516Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21163516Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22163516Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23163516Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24170002Simp *
25170002Simp * Portions of this software may have been developed with reference to
26170002Simp * the SD Simplified Specification.  The following disclaimer may apply:
27170002Simp *
28170002Simp * The following conditions apply to the release of the simplified
29170002Simp * specification ("Simplified Specification") by the SD Card Association and
30170002Simp * the SD Group. The Simplified Specification is a subset of the complete SD
31170002Simp * Specification which is owned by the SD Card Association and the SD
32170002Simp * Group. This Simplified Specification is provided on a non-confidential
33170002Simp * basis subject to the disclaimers below. Any implementation of the
34170002Simp * Simplified Specification may require a license from the SD Card
35170002Simp * Association, SD Group, SD-3C LLC or other third parties.
36170002Simp *
37170002Simp * Disclaimers:
38170002Simp *
39170002Simp * The information contained in the Simplified Specification is presented only
40170002Simp * as a standard specification for SD Cards and SD Host/Ancillary products and
41170002Simp * is provided "AS-IS" without any representations or warranties of any
42170002Simp * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
43170002Simp * Card Association for any damages, any infringements of patents or other
44170002Simp * right of the SD Group, SD-3C LLC, the SD Card Association or any third
45170002Simp * parties, which may result from its use. No license is granted by
46170002Simp * implication, estoppel or otherwise under any patent or other rights of the
47170002Simp * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
48170002Simp * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
49170002Simp * or the SD Card Association to disclose or distribute any technical
50170002Simp * information, know-how or other confidential information to any third party.
51163516Simp */
52163516Simp
53163516Simp#include <sys/cdefs.h>
54163516Simp__FBSDID("$FreeBSD: head/sys/dev/mmc/mmcsd.c 170002 2007-05-26 05:23:36Z imp $");
55163516Simp
56163516Simp#include <sys/param.h>
57163516Simp#include <sys/systm.h>
58163516Simp#include <sys/bio.h>
59163516Simp#include <sys/bus.h>
60163516Simp#include <sys/conf.h>
61163516Simp#include <sys/kernel.h>
62163516Simp#include <sys/kthread.h>
63163516Simp#include <sys/lock.h>
64163516Simp#include <sys/malloc.h>
65163516Simp#include <sys/module.h>
66163516Simp#include <sys/mutex.h>
67163516Simp#include <geom/geom_disk.h>
68163516Simp
69163516Simp#include <dev/mmc/mmcvar.h>
70163516Simp#include <dev/mmc/mmcreg.h>
71163516Simp
72163516Simp#include "mmcbus_if.h"
73163516Simp
74163516Simpstruct mmcsd_softc {
75163516Simp	device_t dev;
76163516Simp	struct mtx sc_mtx;
77163516Simp	struct disk *disk;
78163516Simp	struct proc *p;
79163516Simp	struct bio_queue_head bio_queue;
80169567Simp	int running;
81163516Simp};
82163516Simp
83163516Simp#define	MULTI_BLOCK_READ_BROKEN
84163516Simp
85163516Simp/* bus entry points */
86163516Simpstatic int mmcsd_probe(device_t dev);
87163516Simpstatic int mmcsd_attach(device_t dev);
88163516Simpstatic int mmcsd_detach(device_t dev);
89163516Simp
90163516Simp/* disk routines */
91163516Simpstatic int mmcsd_open(struct disk *dp);
92163516Simpstatic int mmcsd_close(struct disk *dp);
93163516Simpstatic void mmcsd_strategy(struct bio *bp);
94163516Simpstatic void mmcsd_task(void *arg);
95163516Simp
96163516Simp#define MMCSD_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
97163516Simp#define	MMCSD_UNLOCK(_sc)	mtx_unlock(&(_sc)->sc_mtx)
98163516Simp#define MMCSD_LOCK_INIT(_sc) \
99163516Simp	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
100163516Simp	    "mmcsd", MTX_DEF)
101163516Simp#define MMCSD_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
102163516Simp#define MMCSD_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
103163516Simp#define MMCSD_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
104163516Simp
105163516Simpstatic int
106163516Simpmmcsd_probe(device_t dev)
107163516Simp{
108163516Simp
109163516Simp	device_set_desc(dev, "mmc or sd flash card");
110163516Simp	return (0);
111163516Simp}
112163516Simp
113163516Simpstatic int
114163516Simpmmcsd_attach(device_t dev)
115163516Simp{
116163516Simp	struct mmcsd_softc *sc;
117163516Simp
118163516Simp	sc = device_get_softc(dev);
119163516Simp	sc->dev = dev;
120163516Simp	MMCSD_LOCK_INIT(sc);
121163516Simp
122163516Simp	sc->disk = disk_alloc();
123163516Simp	sc->disk->d_open = mmcsd_open;
124163516Simp	sc->disk->d_close = mmcsd_close;
125163516Simp	sc->disk->d_strategy = mmcsd_strategy;
126163516Simp	// sc->disk->d_dump = mmcsd_dump;	Need polling mmc layer
127163516Simp	sc->disk->d_name = "mmcsd";
128163516Simp	sc->disk->d_drv1 = sc;
129163516Simp	sc->disk->d_maxsize = DFLTPHYS;
130163516Simp	sc->disk->d_sectorsize = mmc_get_sector_size(dev);
131163516Simp	sc->disk->d_mediasize = mmc_get_media_size(dev);
132163516Simp	sc->disk->d_unit = device_get_unit(dev);
133163516Simp	disk_create(sc->disk, DISK_VERSION);
134163516Simp	bioq_init(&sc->bio_queue);
135169567Simp
136169567Simp	sc->running = 1;
137163516Simp	kthread_create(&mmcsd_task, sc, &sc->p, 0, 0, "task: mmc/sd card");
138163516Simp
139163516Simp	return (0);
140163516Simp}
141163516Simp
142163516Simpstatic int
143163516Simpmmcsd_detach(device_t dev)
144163516Simp{
145169567Simp	struct mmcsd_softc *sc = device_get_softc(dev);
146169567Simp
147169567Simp	/* kill thread */
148169567Simp	MMCSD_LOCK(sc);
149169567Simp	sc->running = 0;
150169567Simp	wakeup(sc);
151169567Simp	MMCSD_UNLOCK(sc);
152169567Simp
153169567Simp	/* wait for thread to finish.  XXX probably want timeout.  -sorbo */
154169567Simp	MMCSD_LOCK(sc);
155169567Simp	while (sc->running != -1)
156169567Simp		msleep(sc, &sc->sc_mtx, PRIBIO, "detach", 0);
157169567Simp	MMCSD_UNLOCK(sc);
158169567Simp
159169567Simp	/* kill disk */
160169567Simp	disk_destroy(sc->disk);
161169567Simp	/* XXX destroy anything in queue */
162169567Simp
163169567Simp	MMCSD_LOCK_DESTROY(sc);
164169567Simp
165169567Simp	return 0;
166163516Simp}
167163516Simp
168163516Simpstatic int
169163516Simpmmcsd_open(struct disk *dp)
170163516Simp{
171163516Simp	return 0;
172163516Simp}
173163516Simp
174163516Simpstatic int
175163516Simpmmcsd_close(struct disk *dp)
176163516Simp{
177163516Simp	return 0;
178163516Simp}
179163516Simp
180163516Simpstatic void
181163516Simpmmcsd_strategy(struct bio *bp)
182163516Simp{
183163516Simp	struct mmcsd_softc *sc;
184163516Simp
185163516Simp	sc = (struct mmcsd_softc *)bp->bio_disk->d_drv1;
186163516Simp	MMCSD_LOCK(sc);
187163516Simp	bioq_disksort(&sc->bio_queue, bp);
188163516Simp	wakeup(sc);
189163516Simp	MMCSD_UNLOCK(sc);
190163516Simp}
191163516Simp
192163516Simpstatic void
193163516Simpmmcsd_task(void *arg)
194163516Simp{
195163516Simp	struct mmcsd_softc *sc = (struct mmcsd_softc*)arg;
196163516Simp	struct bio *bp;
197163516Simp	int sz;
198163516Simp	daddr_t block, end;
199163516Simp	struct mmc_command cmd;
200163516Simp	struct mmc_command stop;
201163516Simp	struct mmc_request req;
202163516Simp	struct mmc_data data;
203163516Simp	device_t dev;
204163516Simp
205163516Simp	dev = sc->dev;
206169567Simp	while (sc->running) {
207163516Simp		MMCSD_LOCK(sc);
208163516Simp		do {
209163516Simp			bp = bioq_first(&sc->bio_queue);
210163516Simp			if (bp == NULL)
211163516Simp				msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0);
212169567Simp		} while (bp == NULL && sc->running);
213169567Simp		if (bp)
214169567Simp			bioq_remove(&sc->bio_queue, bp);
215163516Simp		MMCSD_UNLOCK(sc);
216169567Simp		if (!sc->running)
217169567Simp			break;
218163516Simp		MMCBUS_ACQUIRE_BUS(device_get_parent(dev), dev);
219163516Simp//		printf("mmc_task: request %p for block %lld\n", bp, bp->bio_pblkno);
220163516Simp		sz = sc->disk->d_sectorsize;
221163516Simp		end = bp->bio_pblkno + (bp->bio_bcount / sz);
222163516Simp		// XXX should use read/write_mulit
223163516Simp		for (block = bp->bio_pblkno; block < end;) {
224163516Simp			char *vaddr = bp->bio_data + (block - bp->bio_pblkno) * sz;
225163516Simp			memset(&req, 0, sizeof(req));
226163516Simp			memset(&cmd, 0, sizeof(cmd));
227163516Simp			memset(&stop, 0, sizeof(stop));
228163516Simp			req.cmd = &cmd;
229163516Simp			cmd.data = &data;
230163516Simp			if (bp->bio_cmd == BIO_READ) {
231163516Simp#ifdef MULTI_BLOCK_READ
232163516Simp				if (end - block > 1)
233163516Simp					cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
234163516Simp				else
235163516Simp					cmd.opcode = MMC_READ_SINGLE_BLOCK;
236163516Simp#else
237163516Simp				cmd.opcode = MMC_READ_SINGLE_BLOCK;
238163516Simp#endif
239163516Simp			} else
240163516Simp				cmd.opcode = MMC_WRITE_BLOCK;
241163516Simp			cmd.arg = block << 9;
242163516Simp			cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
243163516Simp			// data.timeout_ns = ;
244163516Simp			// data.timeout_clks = ;
245163516Simp			data.data = vaddr;
246163516Simp			data.mrq = &req;
247163516Simp			if (bp->bio_cmd == BIO_READ) {
248163516Simp				data.flags = MMC_DATA_READ;
249163516Simp#ifdef MULTI_BLOCK_READ
250163516Simp				data.len = bp->bio_bcount;
251163516Simp				if (end - block > 1) {
252163516Simp					req.stop = &stop;
253163516Simp					data.flags |= MMC_DATA_MULTI;
254163516Simp				}
255163516Simp				printf("Len %d  %lld-%lld flags %#x sz %d\n",
256163516Simp				    data.len, block, end, data.flags, sz);
257163516Simp				block = end;
258163516Simp#else
259163516Simp				data.len = sz;
260163516Simp				block++;
261163516Simp#endif
262163516Simp			} else {
263163516Simp				data.flags = MMC_DATA_WRITE;
264163516Simp				data.len = sz;
265163516Simp				block++;
266163516Simp			}
267163516Simp			stop.opcode = MMC_STOP_TRANSMISSION;
268163516Simp			stop.arg = 0;
269163516Simp			stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
270163516Simp			MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev,
271163516Simp			    &req);
272163516Simp			// XXX error handling
273163516Simp//XXX			while (!(mmc_send_status(dev) & R1_READY_FOR_DATA))
274163516Simp//				continue;
275163516Simp			// XXX decode mmc status
276163516Simp		}
277163516Simp		MMCBUS_RELEASE_BUS(device_get_parent(dev), dev);
278163516Simp		biodone(bp);
279163516Simp	}
280169567Simp
281169567Simp	/* tell parent we're done */
282169567Simp	MMCSD_LOCK(sc);
283169567Simp	sc->running = -1;
284169567Simp	wakeup(sc);
285169567Simp	MMCSD_UNLOCK(sc);
286169567Simp
287169567Simp	kthread_exit(0);
288163516Simp}
289163516Simp
290163516Simpstatic device_method_t mmcsd_methods[] = {
291163516Simp	DEVMETHOD(device_probe, mmcsd_probe),
292163516Simp	DEVMETHOD(device_attach, mmcsd_attach),
293163516Simp	DEVMETHOD(device_detach, mmcsd_detach),
294163516Simp	{0, 0},
295163516Simp};
296163516Simp
297163516Simpstatic driver_t mmcsd_driver = {
298163516Simp	"mmcsd",
299163516Simp	mmcsd_methods,
300163516Simp	sizeof(struct mmcsd_softc),
301163516Simp};
302163516Simpstatic devclass_t mmcsd_devclass;
303163516Simp
304163516Simp
305163516SimpDRIVER_MODULE(mmcsd, mmc, mmcsd_driver, mmcsd_devclass, 0, 0);
306