]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/nand/nand_cdev.c
sys/dev: further adoption of SPDX licensing ID tags.
[FreeBSD/FreeBSD.git] / sys / dev / nand / nand_cdev.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 2009-2012 Semihalf
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 AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/conf.h>
35 #include <sys/bus.h>
36 #include <sys/malloc.h>
37 #include <sys/uio.h>
38 #include <sys/bio.h>
39
40 #include <dev/nand/nand.h>
41 #include <dev/nand/nandbus.h>
42 #include <dev/nand/nand_dev.h>
43 #include "nand_if.h"
44 #include "nandbus_if.h"
45
46 static int nand_page_stat(struct nand_chip *, struct page_stat_io *);
47 static int nand_block_stat(struct nand_chip *, struct block_stat_io *);
48
49 static d_ioctl_t nand_ioctl;
50 static d_open_t nand_open;
51 static d_strategy_t nand_strategy;
52
53 static struct cdevsw nand_cdevsw = {
54         .d_version      = D_VERSION,
55         .d_name         = "nand",
56         .d_open         = nand_open,
57         .d_read         = physread,
58         .d_write        = physwrite,
59         .d_ioctl        = nand_ioctl,
60         .d_strategy =   nand_strategy,
61 };
62
63 static int
64 offset_to_page(struct chip_geom *cg, uint32_t offset)
65 {
66
67         return (offset / cg->page_size);
68 }
69
70 static int
71 offset_to_page_off(struct chip_geom *cg, uint32_t offset)
72 {
73
74         return (offset % cg->page_size);
75 }
76
77 int
78 nand_make_dev(struct nand_chip *chip)
79 {
80         struct nandbus_ivar *ivar;
81         device_t parent, nandbus;
82         int parent_unit, unit;
83         char *name;
84
85         ivar = device_get_ivars(chip->dev);
86         nandbus = device_get_parent(chip->dev);
87
88         if (ivar->chip_cdev_name) {
89                 name = ivar->chip_cdev_name;
90
91                 /*
92                  * If we got distinct name for chip device we can enumarete it
93                  * based on contoller number.
94                  */
95                 parent = device_get_parent(nandbus);
96         } else {
97                 name = "nand";
98                 parent = nandbus;
99         }
100
101         parent_unit = device_get_unit(parent);
102         unit = parent_unit * 4 + chip->num;
103         chip->cdev = make_dev(&nand_cdevsw, unit, UID_ROOT, GID_WHEEL,
104             0666, "%s%d.%d", name, parent_unit, chip->num);
105
106         if (chip->cdev == NULL)
107                 return (ENXIO);
108
109         if (bootverbose)
110                 device_printf(chip->dev, "Created cdev %s%d.%d for chip "
111                     "[0x%0x, 0x%0x]\n", name, parent_unit, chip->num,
112                     ivar->man_id, ivar->dev_id);
113
114         chip->cdev->si_drv1 = chip;
115
116         return (0);
117 }
118
119 void
120 nand_destroy_dev(struct nand_chip *chip)
121 {
122
123         if (chip->cdev)
124                 destroy_dev(chip->cdev);
125 }
126
127 static int
128 nand_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
129 {
130
131         return (0);
132 }
133
134 static int
135 nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len)
136 {
137         struct chip_geom *cg;
138         device_t nandbus;
139         int start_page, count, off, err = 0;
140         uint8_t *ptr, *tmp;
141
142         nand_debug(NDBG_CDEV, "Read from chip%d [%p] at %d\n", chip->num,
143             chip, offset);
144
145         nandbus = device_get_parent(chip->dev);
146         NANDBUS_LOCK(nandbus);
147         NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num);
148
149         cg = &chip->chip_geom;
150         start_page = offset_to_page(cg, offset);
151         off = offset_to_page_off(cg, offset);
152         count = (len > cg->page_size - off) ? cg->page_size - off : len;
153
154         ptr = (uint8_t *)buf;
155         while (len > 0) {
156                 if (len < cg->page_size) {
157                         tmp = malloc(cg->page_size, M_NAND, M_WAITOK);
158                         if (!tmp) {
159                                 err = ENOMEM;
160                                 break;
161                         }
162                         err = NAND_READ_PAGE(chip->dev, start_page,
163                             tmp, cg->page_size, 0);
164                         if (err) {
165                                 free(tmp, M_NAND);
166                                 break;
167                         }
168                         bcopy(tmp + off, ptr, count);
169                         free(tmp, M_NAND);
170                 } else {
171                         err = NAND_READ_PAGE(chip->dev, start_page,
172                             ptr, cg->page_size, 0);
173                         if (err)
174                                 break;
175                 }
176
177                 len -= count;
178                 start_page++;
179                 ptr += count;
180                 count = (len > cg->page_size) ? cg->page_size : len;
181                 off = 0;
182         }
183
184         NANDBUS_UNLOCK(nandbus);
185         return (err);
186 }
187
188 static int
189 nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len)
190 {
191         struct chip_geom *cg;
192         device_t nandbus;
193         int off, start_page, err = 0;
194         uint8_t *ptr;
195
196         nand_debug(NDBG_CDEV, "Write to chip %d [%p] at %d\n", chip->num,
197             chip, offset);
198
199         nandbus = device_get_parent(chip->dev);
200         NANDBUS_LOCK(nandbus);
201         NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num);
202
203         cg = &chip->chip_geom;
204         start_page = offset_to_page(cg, offset);
205         off = offset_to_page_off(cg, offset);
206
207         if (off != 0 || (len % cg->page_size) != 0) {
208                 printf("Not aligned write start [0x%08x] size [0x%08x]\n",
209                     off, len);
210                 NANDBUS_UNLOCK(nandbus);
211                 return (EINVAL);
212         }
213
214         ptr = (uint8_t *)buf;
215         while (len > 0) {
216                 err = NAND_PROGRAM_PAGE(chip->dev, start_page, ptr,
217                     cg->page_size, 0);
218                 if (err)
219                         break;
220
221                 len -= cg->page_size;
222                 start_page++;
223                 ptr += cg->page_size;
224         }
225
226         NANDBUS_UNLOCK(nandbus);
227         return (err);
228 }
229
230 static void
231 nand_strategy(struct bio *bp)
232 {
233         struct nand_chip *chip;
234         struct cdev *dev;
235         int err = 0;
236
237         dev = bp->bio_dev;
238         chip = dev->si_drv1;
239
240         nand_debug(NDBG_CDEV, "Strategy %s on chip %d [%p]\n",
241             bp->bio_cmd == BIO_READ ? "READ" : "WRITE",
242             chip->num, chip);
243
244         if (bp->bio_cmd == BIO_READ) {
245                 err = nand_read(chip,
246                     bp->bio_offset & 0xffffffff,
247                     bp->bio_data, bp->bio_bcount);
248         } else {
249                 err = nand_write(chip,
250                     bp->bio_offset & 0xffffffff,
251                     bp->bio_data, bp->bio_bcount);
252         }
253
254         if (err == 0)
255                 bp->bio_resid = 0;
256         else {
257                 bp->bio_error = EIO;
258                 bp->bio_flags |= BIO_ERROR;
259                 bp->bio_resid = bp->bio_bcount;
260         }
261
262         biodone(bp);
263 }
264
265 static int
266 nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset,
267     uint32_t len, uint8_t *data, uint8_t write)
268 {
269         struct chip_geom *cg;
270         uint8_t *buf = NULL;
271         int ret = 0;
272
273         cg = &chip->chip_geom;
274
275         buf = malloc(cg->oob_size, M_NAND, M_WAITOK);
276         if (!buf)
277                 return (ENOMEM);
278
279         memset(buf, 0xff, cg->oob_size);
280
281         if (!write) {
282                 ret = nand_read_oob(chip, page, buf, cg->oob_size);
283                 copyout(buf, data, len);
284         } else {
285                 copyin(data, buf, len);
286                 ret = nand_prog_oob(chip, page, buf, cg->oob_size);
287         }
288
289         free(buf, M_NAND);
290
291         return (ret);
292 }
293
294 static int
295 nand_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
296     struct thread *td)
297 {
298         struct nand_chip *chip;
299         struct chip_geom  *cg;
300         struct nand_oob_rw *oob_rw = NULL;
301         struct nand_raw_rw *raw_rw = NULL;
302         device_t nandbus;
303         size_t bufsize = 0, len = 0;
304         size_t raw_size;
305         off_t off;
306         uint8_t *buf = NULL;
307         int ret = 0;
308         uint8_t status;
309
310         chip = (struct nand_chip *)dev->si_drv1;
311         cg = &chip->chip_geom;
312         nandbus = device_get_parent(chip->dev);
313
314         if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) {
315                 raw_rw = (struct nand_raw_rw *)data;
316                 raw_size =  cg->pgs_per_blk * (cg->page_size + cg->oob_size);
317
318                 /* Check if len is not bigger than chip size */
319                 if (raw_rw->len > raw_size)
320                         return (EFBIG);
321
322                 /*
323                  * Do not ask for too much memory, in case of large transfers
324                  * read/write in 16-pages chunks
325                  */
326                 bufsize = 16 * (cg->page_size + cg->oob_size);
327                 if (raw_rw->len < bufsize)
328                         bufsize = raw_rw->len;
329
330                 buf = malloc(bufsize, M_NAND, M_WAITOK);
331                 len = raw_rw->len;
332                 off = 0;
333         }
334         switch(cmd) {
335         case NAND_IO_ERASE:
336                 ret = nand_erase_blocks(chip, ((off_t *)data)[0],
337                     ((off_t *)data)[1]);
338                 break;
339
340         case NAND_IO_OOB_READ:
341                 oob_rw = (struct nand_oob_rw *)data;
342                 ret = nand_oob_access(chip, oob_rw->page, 0,
343                     oob_rw->len, oob_rw->data, 0);
344                 break;
345
346         case NAND_IO_OOB_PROG:
347                 oob_rw = (struct nand_oob_rw *)data;
348                 ret = nand_oob_access(chip, oob_rw->page, 0,
349                     oob_rw->len, oob_rw->data, 1);
350                 break;
351
352         case NAND_IO_GET_STATUS:
353                 NANDBUS_LOCK(nandbus);
354                 ret = NANDBUS_GET_STATUS(nandbus, &status);
355                 if (ret == 0)
356                         *(uint8_t *)data = status;
357                 NANDBUS_UNLOCK(nandbus);
358                 break;
359
360         case NAND_IO_RAW_PROG:
361                 while (len > 0) {
362                         if (len < bufsize)
363                                 bufsize = len;
364                         ret = copyin(raw_rw->data + off, buf, bufsize);
365                         if (ret)
366                                 break;
367                         ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf,
368                             bufsize);
369                         if (ret)
370                                 break;
371                         len -= bufsize;
372                         off += bufsize;
373                 }
374                 break;
375
376         case NAND_IO_RAW_READ:
377                 while (len > 0) {
378                         if (len < bufsize)
379                                 bufsize = len;
380
381                         ret = nand_read_pages_raw(chip, raw_rw->off + off, buf,
382                             bufsize);
383                         if (ret)
384                                 break;
385
386                         ret = copyout(buf, raw_rw->data + off, bufsize);
387                         if (ret)
388                                 break;
389                         len -= bufsize;
390                         off += bufsize;
391                 }
392                 break;
393
394         case NAND_IO_PAGE_STAT:
395                 ret = nand_page_stat(chip, (struct page_stat_io *)data);
396                 break;
397
398         case NAND_IO_BLOCK_STAT:
399                 ret = nand_block_stat(chip, (struct block_stat_io *)data);
400                 break;
401
402         case NAND_IO_GET_CHIP_PARAM:
403                 nand_get_chip_param(chip, (struct chip_param_io *)data);
404                 break;
405
406         default:
407                 printf("Unknown nand_ioctl request \n");
408                 ret = EIO;
409         }
410
411         if (buf)
412                 free(buf, M_NAND);
413
414         return (ret);
415 }
416
417 static int
418 nand_page_stat(struct nand_chip *chip, struct page_stat_io *page_stat)
419 {
420         struct chip_geom *cg;
421         struct page_stat *stat;
422         int num_pages;
423
424         cg = &chip->chip_geom;
425         num_pages = cg->pgs_per_blk * cg->blks_per_lun * cg->luns;
426         if (page_stat->page_num >= num_pages)
427                 return (EINVAL);
428
429         stat = &chip->pg_stat[page_stat->page_num];
430         page_stat->page_read = stat->page_read;
431         page_stat->page_written = stat->page_written;
432         page_stat->page_raw_read = stat->page_raw_read;
433         page_stat->page_raw_written = stat->page_raw_written;
434         page_stat->ecc_succeded = stat->ecc_stat.ecc_succeded;
435         page_stat->ecc_corrected = stat->ecc_stat.ecc_corrected;
436         page_stat->ecc_failed = stat->ecc_stat.ecc_failed;
437
438         return (0);
439 }
440
441 static int
442 nand_block_stat(struct nand_chip *chip, struct block_stat_io *block_stat)
443 {
444         struct chip_geom *cg;
445         uint32_t block_num = block_stat->block_num;
446
447         cg = &chip->chip_geom;
448         if (block_num >= cg->blks_per_lun * cg->luns)
449                 return (EINVAL);
450
451         block_stat->block_erased = chip->blk_stat[block_num].block_erased;
452
453         return (0);
454 }