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