xref: /freebsd/sys/powerpc/powernv/opal_flash.c (revision daceb336172a6b0572de864b97e70b28451ca636)
1 /*-
2  * Copyright (c) 2019 Justin Hibbits
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/bio.h>
32 #include <sys/bus.h>
33 #include <sys/kernel.h>
34 #include <sys/kthread.h>
35 #include <sys/module.h>
36 #include <sys/mutex.h>
37 #include <sys/proc.h>
38 #include <geom/geom_disk.h>
39 
40 #include <vm/vm.h>
41 #include <vm/pmap.h>
42 
43 #include <dev/ofw/ofw_bus.h>
44 #include <dev/ofw/ofw_bus_subr.h>
45 #include <dev/ofw/openfirm.h>
46 #include "opal.h"
47 
48 /*
49  * OPAL System flash driver, using OPAL firmware calls to access the device.
50  *
51  * This just presents the base block interface.  The fdt_slicer can be used on
52  * top to present the partitions listed in the fdt.
53  *
54  * There are three OPAL methods used: OPAL_FLASH_READ, OPAL_FLASH_WRITE, and
55  * OPAL_FLASH_ERASE.  At the firmware layer, READ and WRITE can be on arbitrary
56  * boundaries, but ERASE is only at flash-block-size block alignments and sizes.
57  * To account for this, the following restrictions are in place:
58  *
59  * - Reads are on a 512-byte block boundary and size
60  * - Writes and Erases are aligned and sized on flash-block-size bytes.
61  *
62  * In order to support the fdt_slicer we present a type attribute of
63  * NAND::device.
64  */
65 struct opalflash_softc {
66 	device_t		 sc_dev;
67 	struct mtx		 sc_mtx;
68 	struct disk		*sc_disk;
69 	struct proc		*sc_p;
70 	struct bio_queue_head	 sc_bio_queue;
71 	int		 	 sc_opal_id;
72 	bool			 sc_erase; /* Erase is needed before write. */
73 };
74 
75 #define	OPALFLASH_LOCK(sc)		mtx_lock(&(sc)->sc_mtx)
76 #define	OPALFLASH_UNLOCK(sc)		mtx_unlock(&(sc)->sc_mtx)
77 #define	OPALFLASH_LOCK_INIT(sc) \
78 	mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->sc_dev), \
79 	    "opalflash", MTX_DEF)
80 
81 #define	FLASH_BLOCKSIZE			512
82 
83 static int	opalflash_probe(device_t);
84 static int	opalflash_attach(device_t);
85 
86 static device_method_t  opalflash_methods[] = {
87 	/* Device interface */
88 	DEVMETHOD(device_probe,		opalflash_probe),
89 	DEVMETHOD(device_attach,	opalflash_attach),
90 
91 	DEVMETHOD_END
92 };
93 
94 static driver_t opalflash_driver = {
95 	"opalflash",
96 	opalflash_methods,
97 	sizeof(struct opalflash_softc)
98 };
99 
100 static devclass_t opalflash_devclass;
101 
102 DRIVER_MODULE(opalflash, opal, opalflash_driver, opalflash_devclass, 0, 0);
103 
104 /* GEOM Disk interfaces. */
105 static int
106 opalflash_open(struct disk *dp)
107 {
108 
109 	return (0);
110 }
111 
112 static int
113 opalflash_close(struct disk *dp)
114 {
115 
116 	return (0);
117 }
118 
119 static int
120 opalflash_ioctl(struct disk *dp, u_long cmd, void *data, int fflag,
121 	struct thread *td)
122 {
123 
124 	return (EINVAL);
125 }
126 
127 /* Handle the one attribute we need to play nice with geom_flashmap. */
128 static int
129 opalflash_getattr(struct bio *bp)
130 {
131 	struct opalflash_softc *sc;
132 	device_t dev;
133 
134 	if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL)
135 		return (ENXIO);
136 
137 	sc = bp->bio_disk->d_drv1;
138 	dev = sc->sc_dev;
139 
140 	if (strcmp(bp->bio_attribute, "NAND::device") == 0) {
141 		if (bp->bio_length != sizeof(dev))
142 			return (EFAULT);
143 		bcopy(&dev, bp->bio_data, sizeof(dev));
144 	} else
145 		return (-1);
146 	return (0);
147 }
148 
149 static void
150 opalflash_strategy(struct bio *bp)
151 {
152 	struct opalflash_softc *sc;
153 
154 	sc = (struct opalflash_softc *)bp->bio_disk->d_drv1;
155 	OPALFLASH_LOCK(sc);
156 	bioq_disksort(&sc->sc_bio_queue, bp);
157 	wakeup(sc);
158 	OPALFLASH_UNLOCK(sc);
159 }
160 
161 static int
162 opalflash_read(struct opalflash_softc *sc, off_t off,
163     caddr_t data, off_t count)
164 {
165 	struct opal_msg msg;
166 	int rv, size, token;
167 
168 	/* Ensure we write aligned to a full block size. */
169 	if (off % sc->sc_disk->d_sectorsize != 0 ||
170 	    count % sc->sc_disk->d_sectorsize != 0)
171 		return (EIO);
172 
173 	token = opal_alloc_async_token();
174 
175 	/*
176 	 * Read one page at a time.  It's not guaranteed that the buffer is
177 	 * physically contiguous.
178 	 */
179 	rv = 0;
180 	while (count > 0) {
181 		size = MIN(count, PAGE_SIZE);
182 		size = MIN(size, PAGE_SIZE - ((u_long)data & PAGE_MASK));
183 		rv = opal_call(OPAL_FLASH_READ, sc->sc_opal_id, off,
184 		    vtophys(data), size, token);
185 		if (rv == OPAL_ASYNC_COMPLETION) {
186 			rv = opal_wait_completion(&msg, sizeof(msg), token);
187 			if (rv == OPAL_SUCCESS)
188 				rv = msg.params[1];
189 		}
190 		if (rv != OPAL_SUCCESS)
191 			break;
192 		count -= size;
193 		off += size;
194 		data += size;
195 	}
196 	opal_free_async_token(token);
197 	if (rv == OPAL_SUCCESS)
198 		rv = 0;
199 	else
200 		rv = EIO;
201 
202 	return (rv);
203 }
204 
205 static int
206 opalflash_erase(struct opalflash_softc *sc, off_t off, off_t count)
207 {
208 	struct opal_msg msg;
209 	int rv, token;
210 
211 	/* Ensure we write aligned to a full block size. */
212 	if (off % sc->sc_disk->d_stripesize != 0 ||
213 	    count % sc->sc_disk->d_stripesize != 0)
214 		return (EIO);
215 
216 	token = opal_alloc_async_token();
217 
218 	rv = opal_call(OPAL_FLASH_ERASE, sc->sc_opal_id, off, count, token);
219 	if (rv == OPAL_ASYNC_COMPLETION) {
220 		rv = opal_wait_completion(&msg, sizeof(msg), token);
221 		if (rv == OPAL_SUCCESS)
222 			rv = msg.params[1];
223 	}
224 	opal_free_async_token(token);
225 
226 	if (rv == OPAL_SUCCESS)
227 		rv = 0;
228 	else
229 		rv = EIO;
230 
231 	return (rv);
232 }
233 
234 static int
235 opalflash_write(struct opalflash_softc *sc, off_t off,
236     caddr_t data, off_t count)
237 {
238 	struct opal_msg msg;
239 	int rv, size, token;
240 
241 	/* Ensure we write aligned to a full block size. */
242 	if (off % sc->sc_disk->d_sectorsize != 0 ||
243 	    count % sc->sc_disk->d_sectorsize != 0)
244 		return (EIO);
245 
246 	if (sc->sc_erase) {
247 	    /* Erase the full block first, then write in page chunks. */
248 	    rv = opalflash_erase(sc, off, count);
249 	    if (rv != 0)
250 		    return (rv);
251 	}
252 
253 	token = opal_alloc_async_token();
254 
255 	/*
256 	 * Write one page at a time.  It's not guaranteed that the buffer is
257 	 * physically contiguous.
258 	 */
259 	while (count > 0) {
260 		size = MIN(count, PAGE_SIZE);
261 		size = MIN(size, PAGE_SIZE - ((u_long)data & PAGE_MASK));
262 		rv = opal_call(OPAL_FLASH_WRITE, sc->sc_opal_id, off,
263 		    vtophys(data), size, token);
264 		if (rv == OPAL_ASYNC_COMPLETION) {
265 			rv = opal_wait_completion(&msg, sizeof(msg), token);
266 			if (rv == OPAL_SUCCESS)
267 				rv = msg.params[1];
268 		}
269 		if (rv != OPAL_SUCCESS)
270 			break;
271 		count -= size;
272 		off += size;
273 		data += size;
274 	}
275 	opal_free_async_token(token);
276 
277 	if (rv == OPAL_SUCCESS)
278 		rv = 0;
279 	else
280 		rv = EIO;
281 
282 	return (rv);
283 }
284 
285 /* Main flash handling task. */
286 static void
287 opalflash_task(void *arg)
288 {
289 	struct opalflash_softc *sc;
290 	struct bio *bp;
291 	device_t dev;
292 
293 	sc = arg;
294 
295 	for (;;) {
296 		dev = sc->sc_dev;
297 		OPALFLASH_LOCK(sc);
298 		do {
299 			bp = bioq_first(&sc->sc_bio_queue);
300 			if (bp == NULL)
301 				msleep(sc, &sc->sc_mtx, PRIBIO, "opalflash", 0);
302 		} while (bp == NULL);
303 		bioq_remove(&sc->sc_bio_queue, bp);
304 		OPALFLASH_UNLOCK(sc);
305 
306 		switch (bp->bio_cmd) {
307 		case BIO_DELETE:
308 			bp->bio_error = opalflash_erase(sc, bp->bio_offset,
309 			    bp->bio_bcount);
310 			break;
311 		case BIO_READ:
312 			bp->bio_error = opalflash_read(sc, bp->bio_offset,
313 			    bp->bio_data, bp->bio_bcount);
314 			break;
315 		case BIO_WRITE:
316 			bp->bio_error = opalflash_write(sc, bp->bio_offset,
317 			    bp->bio_data, bp->bio_bcount);
318 			break;
319 		default:
320 			bp->bio_error = EINVAL;
321 		}
322 		biodone(bp);
323 	}
324 }
325 
326 
327 /* Device driver interfaces. */
328 
329 static int
330 opalflash_probe(device_t dev)
331 {
332 	if (!ofw_bus_is_compatible(dev, "ibm,opal-flash"))
333 		return (ENXIO);
334 
335 	device_set_desc(dev, "OPAL System Flash");
336 
337 	return (BUS_PROBE_GENERIC);
338 }
339 
340 static int
341 opalflash_attach(device_t dev)
342 {
343 	struct opalflash_softc *sc;
344 	phandle_t node;
345 	cell_t flash_blocksize, opal_id;
346 	uint32_t regs[2];
347 
348 	sc = device_get_softc(dev);
349 	sc->sc_dev = dev;
350 
351 	node = ofw_bus_get_node(dev);
352 	OF_getencprop(node, "ibm,opal-id", &opal_id, sizeof(opal_id));
353 	sc->sc_opal_id = opal_id;
354 
355 	if (OF_getencprop(node, "ibm,flash-block-size",
356 	    &flash_blocksize, sizeof(flash_blocksize)) < 0) {
357 		device_printf(dev, "Cannot determine flash block size.\n");
358 		return (ENXIO);
359 	}
360 
361 	if (!OF_hasprop(node, "no-erase"))
362 		sc->sc_erase = true;
363 
364 	OPALFLASH_LOCK_INIT(sc);
365 
366 	if (OF_getencprop(node, "reg", regs, sizeof(regs)) < 0) {
367 		device_printf(dev, "Unable to get flash size.\n");
368 		return (ENXIO);
369 	}
370 
371 	sc->sc_disk = disk_alloc();
372 	sc->sc_disk->d_name = "opalflash";
373 	sc->sc_disk->d_open = opalflash_open;
374 	sc->sc_disk->d_close = opalflash_close;
375 	sc->sc_disk->d_strategy = opalflash_strategy;
376 	sc->sc_disk->d_ioctl = opalflash_ioctl;
377 	sc->sc_disk->d_getattr = opalflash_getattr;
378 	sc->sc_disk->d_drv1 = sc;
379 	sc->sc_disk->d_maxsize = DFLTPHYS;
380 	sc->sc_disk->d_mediasize = regs[1];
381 	sc->sc_disk->d_unit = device_get_unit(sc->sc_dev);
382 	sc->sc_disk->d_sectorsize = FLASH_BLOCKSIZE;
383 	    sc->sc_disk->d_stripesize = flash_blocksize;
384 	sc->sc_disk->d_dump = NULL;
385 
386 	disk_create(sc->sc_disk, DISK_VERSION);
387 	bioq_init(&sc->sc_bio_queue);
388 
389 	kproc_create(&opalflash_task, sc, &sc->sc_p, 0, 0, "task: OPAL Flash");
390 
391 	return (0);
392 }
393