Coverage Report

Created: 2026-10-17 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/barebox/drivers/mtd/core.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
 * (C) Copyright 2005
4
 * 2N Telekomunikace, a.s. <www.2n.cz>
5
 * Ladislav Michl <michl@2n.cz>
6
 */
7
#include <common.h>
8
#include <linux/mtd/nand.h>
9
#include <linux/mtd/mtd.h>
10
#include <linux/mtd/partitions.h>
11
#include <mtd/mtd-peb.h>
12
#include <mtd/ubi-user.h>
13
#include <cmdlinepart.h>
14
#include <filetype.h>
15
#include <init.h>
16
#include <xfuncs.h>
17
#include <driver.h>
18
#include <malloc.h>
19
#include <ioctl.h>
20
#include <nand.h>
21
#include <errno.h>
22
#include <of.h>
23
24
#include "mtd.h"
25
26
static LIST_HEAD(mtd_register_hooks);
27
28
DEFINE_DEV_CLASS(mtd_class, "mtd");
29
EXPORT_SYMBOL(mtd_class);
30
31
/**
32
 * mtd_buf_all_ff - check if buffer contains only 0xff
33
 * @buf: buffer to check
34
 * @size: buffer size in bytes
35
 *
36
 * This function returns %1 if there are only 0xff bytes in @buf, and %0 if
37
 * something else was also found.
38
 */
39
int mtd_buf_all_ff(const void *buf, unsigned int len)
40
0
{
41
0
  while ((unsigned long)buf & 0x3) {
42
0
    if (*(const uint8_t *)buf != 0xff)
43
0
      return 0;
44
0
    len--;
45
0
    if (!len)
46
0
      return 1;
47
0
    buf++;
48
0
  }
49
50
0
  while (len > 0x3) {
51
0
    if (*(const uint32_t *)buf != 0xffffffff)
52
0
      return 0;
53
54
0
    len -= sizeof(uint32_t);
55
0
    if (!len)
56
0
      return 1;
57
58
0
    buf += sizeof(uint32_t);
59
0
  }
60
61
0
  while (len) {
62
0
    if (*(const uint8_t *)buf != 0xff)
63
0
      return 0;
64
0
    len--;
65
0
    buf++;
66
0
  }
67
68
0
  return 1;
69
0
}
70
71
/**
72
 * mtd_buf_check_pattern - check if buffer contains only a certain byte pattern.
73
 * @buf: buffer to check
74
 * @patt: the pattern to check
75
 * @size: buffer size in bytes
76
 *
77
 * This function returns %1 in there are only @patt bytes in @buf, and %0 if
78
 * something else was also found.
79
 */
80
int mtd_buf_check_pattern(const void *buf, uint8_t patt, int size)
81
0
{
82
0
  int i;
83
84
0
  for (i = 0; i < size; i++)
85
0
    if (((const uint8_t *)buf)[i] != patt)
86
0
      return 0;
87
0
  return 1;
88
0
}
89
90
static ssize_t mtd_op_read(struct cdev *cdev, void* buf, size_t count,
91
        loff_t offset, ulong flags)
92
0
{
93
0
  struct mtd_info *mtd = cdev->priv;
94
0
  size_t retlen;
95
0
  int ret;
96
97
0
  dev_dbg(cdev->dev, "read ofs: 0x%08llx count: 0x%08zx\n",
98
0
      offset, count);
99
100
0
  ret = mtd_read(mtd, offset, count, &retlen, buf);
101
0
  if (ret < 0 && ret != -EUCLEAN)
102
0
    return ret;
103
104
0
  return retlen;
105
0
}
106
107
#define NOTALIGNED(x) (x & (mtd->writesize - 1)) != 0
108
#define MTDPGALG(x) ((x) & ~(mtd->writesize - 1))
109
110
#ifdef CONFIG_MTD_WRITE
111
static ssize_t mtd_op_write(struct cdev* cdev, const void *buf, size_t _count,
112
        loff_t _offset, ulong flags)
113
0
{
114
0
  struct mtd_info *mtd = cdev->priv;
115
0
  size_t retlen;
116
0
  int ret;
117
118
0
  ret = mtd_write(mtd, _offset, _count, &retlen, buf);
119
120
0
  return ret ? ret : _count;
121
0
}
122
123
static struct mtd_erase_region_info *mtd_find_erase_region(struct mtd_info *mtd, loff_t offset)
124
0
{
125
0
  int i;
126
127
0
  for (i = 0; i < mtd->numeraseregions; i++) {
128
0
    struct mtd_erase_region_info *e = &mtd->eraseregions[i];
129
0
    if (offset > e->offset + (loff_t)e->erasesize * e->numblocks)
130
0
      continue;
131
0
    return e;
132
0
  }
133
134
0
  return NULL;
135
0
}
136
137
static loff_t __mtd_erase_round(loff_t x, uint32_t esize, int up)
138
0
{
139
0
  uint64_t dividend = x;
140
0
  uint32_t mod = do_div(dividend, esize);
141
0
  if (mod == 0)
142
0
    return x;
143
0
  if (up)
144
0
    x += esize;
145
0
  return x - mod;
146
0
}
147
0
#define mtd_erase_round_up(x, esize)  __mtd_erase_round(x, esize, 1)
148
0
#define mtd_erase_round_down(x, esize)  __mtd_erase_round(x, esize, 0)
149
150
static int mtd_erase_align(struct mtd_info *mtd, loff_t *count, loff_t *offset)
151
0
{
152
0
  struct mtd_erase_region_info *e;
153
0
  loff_t ofs;
154
155
0
  if (mtd->numeraseregions == 0) {
156
0
    ofs = mtd_erase_round_down(*offset, mtd->erasesize);
157
0
    *count += *offset - ofs;
158
0
    *count = mtd_erase_round_up(*count, mtd->erasesize);
159
0
    *offset = ofs;
160
0
    return 0;
161
0
  }
162
163
0
  e = mtd_find_erase_region(mtd, *offset);
164
0
  if (!e)
165
0
    return -EINVAL;
166
167
0
  ofs = mtd_erase_round_down(*offset, e->erasesize);
168
0
  *count += *offset - ofs;
169
170
0
  e = mtd_find_erase_region(mtd, *offset + *count);
171
0
  if (!e)
172
0
    return -EINVAL;
173
174
0
  *count = mtd_erase_round_up(*count, e->erasesize);
175
0
  *offset = ofs;
176
177
0
  return 0;
178
0
}
179
180
static int mtd_op_erase(struct cdev *cdev, loff_t count, loff_t offset)
181
0
{
182
0
  struct mtd_info *mtd = cdev->priv;
183
0
  struct erase_info erase;
184
0
  loff_t addr;
185
0
  int ret;
186
187
0
  if (mtd->flags & MTD_NO_ERASE)
188
0
    return -EOPNOTSUPP;
189
190
0
  ret = mtd_erase_align(mtd, &count, &offset);
191
0
  if (ret)
192
0
    return ret;
193
194
0
  memset(&erase, 0, sizeof(erase));
195
0
  erase.mtd = mtd;
196
0
  addr = offset;
197
198
0
  if (!mtd->_block_isbad) {
199
0
    erase.addr = addr;
200
0
    erase.len = count;
201
0
    return mtd_erase(mtd, &erase);
202
0
  }
203
204
0
  erase.len = mtd->erasesize;
205
206
0
  while (count > 0) {
207
0
    dev_dbg(cdev->dev, "erase 0x%08llx len: 0x%08llx\n", addr, erase.len);
208
209
0
    if (mtd->allow_erasebad || (mtd->parent && mtd->parent->allow_erasebad))
210
0
      ret = 0;
211
0
    else
212
0
      ret = mtd_block_isbad(mtd, addr);
213
214
0
    erase.addr = addr;
215
216
0
    if (ret > 0) {
217
0
      printf("Skipping bad block at 0x%08llx\n", addr);
218
0
    } else {
219
0
      ret = mtd_erase(mtd, &erase);
220
0
      if (ret) {
221
0
        printf("%s: failed to erase block at 0x%08llx\n",
222
0
          __func__, addr);
223
0
        return ret;
224
0
      }
225
0
    }
226
227
0
    addr += mtd->erasesize;
228
0
    count -= count > mtd->erasesize ? mtd->erasesize : count;
229
0
  }
230
231
0
  return 0;
232
0
}
233
234
static int mtd_op_protect(struct cdev *cdev, size_t count, loff_t offset, int prot)
235
0
{
236
0
  struct mtd_info *mtd = cdev->priv;
237
238
0
  if (!mtd->_unlock || !mtd->_lock)
239
0
    return -ENOSYS;
240
241
0
  if (prot)
242
0
    return mtd_lock(mtd, offset, count);
243
0
  else
244
0
    return mtd_unlock(mtd, offset, count);
245
0
}
246
247
#endif /* CONFIG_MTD_WRITE */
248
249
int mtd_ioctl(struct cdev *cdev, unsigned int request, void *buf)
250
0
{
251
0
  int ret = 0;
252
0
  struct mtd_info *mtd = cdev->priv;
253
0
  struct mtd_info_user *user = buf;
254
0
  struct mtd_ecc_stats *ecc = buf;
255
0
  struct region_info_user *reg = buf;
256
0
#ifdef CONFIG_MTD_WRITE
257
0
  struct erase_info_user *ei = buf;
258
0
#endif
259
0
  loff_t *offset = buf;
260
261
0
  switch (request) {
262
0
  case MEMGETBADBLOCK:
263
0
    dev_dbg(cdev->dev, "MEMGETBADBLOCK: 0x%08llx\n", *offset);
264
0
    ret = mtd_block_isbad(mtd, *offset);
265
0
    break;
266
0
#ifdef CONFIG_MTD_WRITE
267
0
  case MEMSETBADBLOCK:
268
0
    dev_dbg(cdev->dev, "MEMSETBADBLOCK: 0x%08llx\n", *offset);
269
0
    ret = mtd_block_markbad(mtd, *offset);
270
0
    break;
271
0
  case MEMSETGOODBLOCK:
272
0
    dev_dbg(cdev->dev, "MEMSETGOODBLOCK: 0x%08llx\n", *offset);
273
0
    ret = mtd_block_markgood(mtd, *offset);
274
0
    break;
275
0
  case MEMERASE:
276
0
    ret = mtd_op_erase(cdev, ei->length, ei->start + cdev->offset);
277
0
    break;
278
0
#endif
279
0
  case MEMGETINFO:
280
0
    user->type  = mtd->type;
281
0
    user->flags = mtd->flags;
282
0
    user->size  = mtd->size;
283
0
    user->erasesize = mtd->erasesize;
284
0
    user->writesize = mtd->writesize;
285
0
    user->oobsize = mtd->oobsize;
286
0
    user->subpagesize = mtd->writesize >> mtd->subpage_sft;
287
0
    user->mtd = mtd;
288
    /* The below fields are obsolete */
289
0
    user->ecctype = -1;
290
0
    user->eccsize = 0;
291
0
    break;
292
0
  case ECCGETSTATS:
293
0
    ecc->corrected = mtd->ecc_stats.corrected;
294
0
    ecc->failed = mtd->ecc_stats.failed;
295
0
    ecc->badblocks = mtd->ecc_stats.badblocks;
296
0
    ecc->bbtblocks = mtd->ecc_stats.bbtblocks;
297
0
    break;
298
0
  case MEMGETREGIONINFO:
299
0
    if (cdev->mtd) {
300
0
      unsigned long size = cdev->size;
301
0
      reg->offset = cdev->offset;
302
0
      reg->erasesize = cdev->mtd->erasesize;
303
0
      reg->numblocks = size / reg->erasesize;
304
0
      reg->regionindex = cdev->mtd->index;
305
0
    }
306
0
    break;
307
0
  default:
308
0
    ret = -EINVAL;
309
0
  }
310
311
0
  return ret;
312
0
}
313
314
int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
315
0
{
316
0
  if (!mtd->_lock)
317
0
    return -EOPNOTSUPP;
318
0
  if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
319
0
    return -EINVAL;
320
0
  if (!len)
321
0
    return 0;
322
0
  return mtd->_lock(mtd, ofs, len);
323
0
}
324
325
int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
326
0
{
327
0
  if (!mtd->_unlock)
328
0
    return -EOPNOTSUPP;
329
0
  if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
330
0
    return -EINVAL;
331
0
  if (!len)
332
0
    return 0;
333
0
  return mtd->_unlock(mtd, ofs, len);
334
0
}
335
336
int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
337
0
{
338
0
  if (!mtd->_block_isbad)
339
0
    return 0;
340
341
0
  if (ofs < 0 || ofs > mtd->size)
342
0
    return -EINVAL;
343
344
0
  return mtd->_block_isbad(mtd, ofs);
345
0
}
346
347
int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
348
0
{
349
0
  int ret;
350
351
0
  if (ofs < 0 || ofs >= mtd->size)
352
0
    return -EINVAL;
353
354
0
  if (mtd->_block_markbad)
355
0
    ret = mtd->_block_markbad(mtd, ofs);
356
0
  else
357
0
    ret = -ENOSYS;
358
359
0
  return ret;
360
0
}
361
362
int mtd_block_markgood(struct mtd_info *mtd, loff_t ofs)
363
0
{
364
0
  int ret;
365
366
0
  if (mtd->_block_markgood)
367
0
    ret = mtd->_block_markgood(mtd, ofs);
368
0
  else
369
0
    ret = -ENOSYS;
370
371
0
  return ret;
372
0
}
373
374
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
375
       u_char *buf)
376
0
{
377
0
  struct mtd_oob_ops ops = {
378
0
    .len = len,
379
0
    .datbuf = buf,
380
0
  };
381
0
  int ret = 0;
382
383
0
  if (from < 0 || from >= mtd->size || len > mtd->size - from)
384
0
    return -EINVAL;
385
386
0
  if (len)
387
0
    ret = mtd_read_oob(mtd, from, &ops);
388
389
0
  *retlen = ops.retlen;
390
0
  return ret;
391
0
}
392
393
int mtd_write_oob(struct mtd_info *mtd, loff_t to,
394
        struct mtd_oob_ops *ops)
395
0
{
396
0
  int ret;
397
398
0
  ops->retlen = ops->oobretlen = 0;
399
400
0
  if (!(mtd->flags & MTD_WRITEABLE))
401
0
    return -EROFS;
402
403
  /* Check the validity of a potential fallback on mtd->_write */
404
0
  if (!mtd->_write_oob && (!mtd->_write || ops->oobbuf))
405
0
    return -EOPNOTSUPP;
406
407
0
  if (mtd->_write_oob)
408
0
    ret = mtd->_write_oob(mtd, to, ops);
409
0
  else
410
0
    ret = mtd->_write(mtd, to, ops->len, &ops->retlen,
411
0
             ops->datbuf);
412
413
0
  return ret;
414
0
}
415
416
int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
417
        const u_char *buf)
418
0
{
419
0
  struct mtd_oob_ops ops = {
420
0
    .len = len,
421
0
    .datbuf = (u8 *)buf,
422
0
  };
423
0
  int ret;
424
425
0
  if (to < 0 || to >= mtd->size || len > mtd->size - to)
426
0
    return -EINVAL;
427
0
  if (!len)
428
0
    return 0;
429
430
0
  ret = mtd_write_oob(mtd, to, &ops);
431
0
  *retlen = ops.retlen;
432
433
0
  return ret;
434
0
}
435
436
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
437
0
{
438
0
  if (instr->addr >= mtd->size || instr->len > mtd->size - instr->addr)
439
0
    return -EINVAL;
440
0
  if (!IS_ENABLED(CONFIG_MTD_WRITE))
441
0
    return -ENOSYS;
442
0
  if (!(mtd->flags & MTD_WRITEABLE))
443
0
    return -EROFS;
444
0
  instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
445
0
  if (!instr->len)
446
0
    return 0;
447
448
0
  return mtd->_erase(mtd, instr);
449
0
}
450
451
int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
452
0
{
453
0
  int ret_code;
454
455
0
  ops->retlen = ops->oobretlen = 0;
456
457
  /* Check the validity of a potential fallback on mtd->_read */
458
0
  if (!mtd->_read_oob && (!mtd->_read || ops->oobbuf))
459
0
    return -EOPNOTSUPP;
460
461
  /*
462
   * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
463
   * similar to mtd->_read(), returning a non-negative integer
464
   * representing max bitflips. In other cases, mtd->_read_oob() may
465
   * return -EUCLEAN. In all cases, perform similar logic to mtd_read().
466
   */
467
0
  if (mtd->_read_oob)
468
0
    ret_code = mtd->_read_oob(mtd, from, ops);
469
0
  else
470
0
    ret_code = mtd->_read(mtd, from, ops->len, &ops->retlen,
471
0
            ops->datbuf);
472
473
0
  if (unlikely(ret_code < 0))
474
0
    return ret_code;
475
0
  if (mtd->ecc_strength == 0)
476
0
    return 0; /* device lacks ecc */
477
0
  return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
478
0
}
479
480
static struct cdev_operations mtd_ops = {
481
  .read   = mtd_op_read,
482
#ifdef CONFIG_MTD_WRITE
483
  .write  = mtd_op_write,
484
  .erase  = mtd_op_erase,
485
  .protect = mtd_op_protect,
486
#endif
487
  .ioctl  = mtd_ioctl,
488
};
489
490
static int mtd_partition_set(struct param_d *p, void *priv)
491
0
{
492
0
  struct mtd_info *mtd = priv;
493
0
  struct mtd_info *mtdpart, *tmp;
494
0
  int ret;
495
496
0
  if (!mtd->partition_string)
497
0
    return -EINVAL;
498
499
0
  list_for_each_entry_safe(mtdpart, tmp, &mtd->partitions, partitions_entry) {
500
0
    ret = mtd_del_partition(mtdpart);
501
0
    if (ret)
502
0
      return ret;
503
0
  }
504
505
0
  return cmdlinepart_do_parse(mtd->cdev.name, mtd->partition_string, mtd->size, CMDLINEPART_ADD_DEVNAME);
506
0
}
507
508
static char *print_size(uint64_t s)
509
0
{
510
0
  if (!(s & ((1 << 20) - 1)))
511
0
    return basprintf("%lldM", s >> 20);
512
0
  if (!(s & ((1 << 10) - 1)))
513
0
    return basprintf("%lldk", s >> 10);
514
0
  return basprintf("0x%llx", s);
515
0
}
516
517
static int print_part(char *buf, int bufsize, struct mtd_info *mtd, uint64_t last_ofs,
518
    int is_last)
519
0
{
520
0
  char *size = print_size(mtd->size);
521
0
  char *ofs = print_size(mtd->master_offset);
522
0
  int ret;
523
524
0
  if (!size || !ofs) {
525
0
    ret = -ENOMEM;
526
0
    goto out;
527
0
  }
528
529
0
  if (mtd->master_offset == last_ofs)
530
0
    ret = snprintf(buf, bufsize, "%s(%s)%s", size,
531
0
        mtd->cdev.partname,
532
0
        is_last ? "" : ",");
533
0
  else
534
0
    ret = snprintf(buf, bufsize, "%s@%s(%s)%s", size,
535
0
        ofs,
536
0
        mtd->cdev.partname,
537
0
        is_last ? "" : ",");
538
0
out:
539
0
  free(size);
540
0
  free(ofs);
541
542
0
  return ret;
543
0
}
544
545
static int print_parts(char *buf, int bufsize, struct mtd_info *mtd)
546
0
{
547
0
  struct mtd_info *mtdpart;
548
0
  uint64_t last_ofs = 0;
549
0
  int ret = 0;
550
551
0
  list_for_each_entry(mtdpart, &mtd->partitions, partitions_entry) {
552
0
    int now;
553
0
    int is_last = list_is_last(&mtdpart->partitions_entry,
554
0
          &mtd->partitions);
555
556
0
    now = print_part(buf, bufsize, mtdpart, last_ofs, is_last);
557
0
    if (now < 0)
558
0
      return now;
559
560
0
    if (buf && bufsize) {
561
0
      buf += now;
562
0
      bufsize -= now;
563
0
    }
564
0
    ret += now;
565
0
    last_ofs = mtdpart->master_offset + mtdpart->size;
566
0
  }
567
568
0
  return ret;
569
0
}
570
571
static int mtd_partition_get(struct param_d *p, void *priv)
572
0
{
573
0
  struct mtd_info *mtd = priv;
574
0
  int len = 0;
575
576
0
  free(mtd->partition_string);
577
578
0
  len = print_parts(NULL, 0, mtd);
579
0
  mtd->partition_string = xzalloc(len + 1);
580
0
  print_parts(mtd->partition_string, len + 1, mtd);
581
582
0
  return 0;
583
0
}
584
585
static int mtd_part_compare(struct list_head *a, struct list_head *b)
586
0
{
587
0
  struct mtd_info *mtda = container_of(a, struct mtd_info, partitions_entry);
588
0
  struct mtd_info *mtdb = container_of(b, struct mtd_info, partitions_entry);
589
590
0
  if (mtda->master_offset > mtdb->master_offset)
591
0
    return 1;
592
0
  if (mtda->master_offset < mtdb->master_offset)
593
0
    return -1;
594
0
  return 0;
595
0
}
596
597
static int mtd_detect(struct device *dev)
598
0
{
599
0
  struct mtd_info *mtd = container_of(dev, struct mtd_info, dev);
600
0
  int bufsize = 512;
601
0
  void *buf;
602
0
  int ret = 0, i;
603
0
  enum filetype filetype;
604
0
  int npebs = mtd_div_by_eb(mtd->size, mtd);
605
0
606
0
  /* No point in looking for UBI on a partition that's too small */
607
0
  npebs = min(npebs, 64);
608
0
  if (npebs < 5)
609
0
    return 0;
610
0
611
0
  /*
612
0
   * Do not try to attach an UBI device if this device has partitions
613
0
   * as it's not a good idea to attach UBI on a raw device when the
614
0
   * real UBI only spans the first partition.
615
0
   */
616
0
  if (!list_empty(&mtd->partitions))
617
0
    return -EBUSY;
618
0
619
0
  buf = xmalloc(bufsize);
620
0
621
0
  for (i = 0; i < npebs; i++) {
622
0
    if (mtd_peb_is_bad(mtd, i))
623
0
      continue;
624
0
625
0
    ret = mtd_peb_read(mtd, buf, i, 0, 512);
626
0
    if (ret)
627
0
      continue;
628
0
629
0
    if (mtd_buf_all_ff(buf, 512))
630
0
      continue;
631
0
632
0
    filetype = file_detect_type(buf, bufsize);
633
0
    if (filetype == filetype_ubi && ubi_num_get_by_mtd(mtd) < 0)
634
0
      ret = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 20);
635
0
636
0
    break;
637
0
  }
638
0
639
0
  free(buf);
640
0
641
0
  return ret;
642
0
}
643
644
static int mtd_partition_fixup_generic(struct mtd_info *mtd, struct device_node *root)
645
0
{
646
0
  struct cdev *cdev = &mtd->cdev;
647
0
  struct device_node *np, *mtdnp = mtd_get_of_node(mtd);
648
0
  char *name;
649
650
0
  name = of_get_reproducible_name(mtdnp);
651
0
  np = of_find_node_by_reproducible_name(root, name);
652
0
  free(name);
653
0
  if (!np) {
654
0
    dev_err(&mtd->dev, "Cannot find nodepath %pOF, cannot fixup\n",
655
0
        mtdnp);
656
0
    return -EINVAL;
657
0
  }
658
659
0
  return of_fixup_partitions(np, cdev);
660
0
}
661
662
static int mtd_partition_fixup(struct device_node *root, void *ctx)
663
0
{
664
0
  struct mtd_info *mtd = ctx;
665
666
0
  if (mtd->of_fixup)
667
0
    return mtd->of_fixup(mtd, root);
668
669
0
  return mtd_partition_fixup_generic(mtd, root);
670
0
}
671
672
int add_mtd_device(struct mtd_info *mtd, const char *devname, int device_id)
673
0
{
674
0
  struct mtddev_hook *hook;
675
0
  int ret;
676
677
0
  if (!devname)
678
0
    devname = "mtd";
679
0
  dev_set_name(&mtd->dev, "%s", devname);
680
0
  mtd->dev.id = device_id;
681
682
0
  if (IS_ENABLED(CONFIG_MTD_UBI))
683
0
    mtd->dev.detect = mtd_detect;
684
685
0
  ret = register_device(&mtd->dev);
686
0
  if (ret)
687
0
    return ret;
688
689
0
  class_add_device(&mtd_class, &mtd->dev);
690
691
0
  mtd->cdev.ops = &mtd_ops;
692
0
  mtd->cdev.size = mtd->size;
693
0
  if (device_id == DEVICE_ID_SINGLE)
694
0
    mtd->cdev.name = xstrdup(devname);
695
0
  else
696
0
    mtd->cdev.name = basprintf("%s%d", devname,
697
0
               mtd->dev.id);
698
699
0
  INIT_LIST_HEAD(&mtd->partitions);
700
0
  INIT_LIST_HEAD(&mtd->partitions_entry);
701
702
0
  mtd->cdev.priv = mtd;
703
0
  mtd->cdev.dev = &mtd->dev;
704
0
  mtd->cdev.mtd = mtd;
705
706
0
  if (IS_ENABLED(CONFIG_PARAMETER)) {
707
0
    dev_add_param_uint64_ro(&mtd->dev, "size", &mtd->size, "%llu");
708
0
    dev_add_param_uint32_ro(&mtd->dev, "erasesize", &mtd->erasesize, "%u");
709
0
    dev_add_param_uint32_ro(&mtd->dev, "writesize", &mtd->writesize, "%u");
710
0
    dev_add_param_uint32_ro(&mtd->dev, "oobsize", &mtd->oobsize, "%u");
711
0
  }
712
713
0
  ret = devfs_create(&mtd->cdev);
714
0
  if (ret)
715
0
    goto err;
716
717
0
  if (mtd->parent && !(mtd->cdev.flags & DEVFS_PARTITION_FIXED)) {
718
0
    struct mtd_info *mtdpart;
719
720
0
    list_for_each_entry(mtdpart, &mtd->parent->partitions, partitions_entry) {
721
0
      if (mtdpart->master_offset + mtdpart->size <= mtd->master_offset)
722
0
        continue;
723
0
      if (mtd->master_offset + mtd->size <= mtdpart->master_offset)
724
0
        continue;
725
0
      dev_err(&mtd->dev, "New partition %s conflicts with %s\n",
726
0
          mtd->name, mtdpart->name);
727
0
      goto err1;
728
0
    }
729
730
0
    list_add_sort(&mtd->partitions_entry, &mtd->parent->partitions, mtd_part_compare);
731
0
  }
732
733
0
  if (mtd_can_have_bb(mtd))
734
0
    mtd->cdev_bb = mtd_add_bb(mtd, NULL);
735
736
0
  if (!mtd->parent) {
737
0
    struct device_node *np = mtd_get_of_node(mtd);
738
739
0
    dev_add_param_string(&mtd->dev, "partitions", mtd_partition_set, mtd_partition_get, &mtd->partition_string, mtd);
740
0
    if (IS_ENABLED(CONFIG_OFDEVICE) && np) {
741
0
      of_parse_partitions(&mtd->cdev, np);
742
0
      ret = of_register_fixup(mtd_partition_fixup, mtd);
743
0
      if (ret)
744
0
        goto err1;
745
0
    }
746
0
  }
747
748
0
  list_for_each_entry(hook, &mtd_register_hooks, hook)
749
0
    if (hook->add_mtd_device)
750
0
      hook->add_mtd_device(mtd, devname, &hook->priv);
751
752
0
  return 0;
753
0
err1:
754
0
  devfs_remove(&mtd->cdev);
755
0
err:
756
0
  free(mtd->cdev.name);
757
0
  unregister_device(&mtd->dev);
758
759
0
  return ret;
760
0
}
761
762
int del_mtd_device(struct mtd_info *mtd)
763
0
{
764
0
  struct mtddev_hook *hook;
765
766
0
  list_for_each_entry(hook, &mtd_register_hooks, hook)
767
0
    if (hook->del_mtd_device)
768
0
      hook->del_mtd_device(mtd, &hook->priv);
769
770
0
  devfs_remove(&mtd->cdev);
771
0
  if (mtd->cdev_bb)
772
0
    mtd_del_bb(mtd);
773
0
  unregister_device(&mtd->dev);
774
0
  free(mtd->param_size.value);
775
0
  free(mtd->cdev.name);
776
0
  list_del(&mtd->partitions_entry);
777
778
0
  return 0;
779
0
}
780
781
void mtdcore_add_hook(struct mtddev_hook *hook)
782
26
{
783
26
  list_add(&hook->hook, &mtd_register_hooks);
784
26
}
785
786
const char *mtd_type_str(struct mtd_info *mtd)
787
0
{
788
0
  switch (mtd->type) {
789
0
  case MTD_ABSENT:
790
0
    return "absent";
791
0
  case MTD_RAM:
792
0
    return "ram";
793
0
  case MTD_ROM:
794
0
    return "rom";
795
0
  case MTD_NORFLASH:
796
0
    return "nor";
797
0
  case MTD_NANDFLASH:
798
0
    return "nand";
799
0
  case MTD_DATAFLASH:
800
0
    return"dataflash";
801
0
  case MTD_UBIVOLUME:
802
0
    return "ubi";
803
0
  default:
804
0
    return "unknown";
805
0
  }
806
0
}
807
808
/**
809
 * mtd_ooblayout_ecc - Get the OOB region definition of a specific ECC section
810
 * @mtd: MTD device structure
811
 * @section: ECC section. Depending on the layout you may have all the ECC
812
 *       bytes stored in a single contiguous section, or one section
813
 *       per ECC chunk (and sometime several sections for a single ECC
814
 *       ECC chunk)
815
 * @oobecc: OOB region struct filled with the appropriate ECC position
816
 *      information
817
 *
818
 * This function returns ECC section information in the OOB area. If you want
819
 * to get all the ECC bytes information, then you should call
820
 * mtd_ooblayout_ecc(mtd, section++, oobecc) until it returns -ERANGE.
821
 *
822
 * Returns zero on success, a negative error code otherwise.
823
 */
824
int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
825
          struct mtd_oob_region *oobecc)
826
0
{
827
0
  memset(oobecc, 0, sizeof(*oobecc));
828
829
0
  if (section < 0)
830
0
    return -EINVAL;
831
832
0
  if (!mtd->ooblayout || !mtd->ooblayout->ecc)
833
0
    return -ENOTSUPP;
834
835
0
  return mtd->ooblayout->ecc(mtd, section, oobecc);
836
0
}
837
EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc);
838
839
/**
840
 * mtd_ooblayout_free - Get the OOB region definition of a specific free
841
 *      section
842
 * @mtd: MTD device structure
843
 * @section: Free section you are interested in. Depending on the layout
844
 *       you may have all the free bytes stored in a single contiguous
845
 *       section, or one section per ECC chunk plus an extra section
846
 *       for the remaining bytes (or other funky layout).
847
 * @oobfree: OOB region struct filled with the appropriate free position
848
 *       information
849
 *
850
 * This function returns free bytes position in the OOB area. If you want
851
 * to get all the free bytes information, then you should call
852
 * mtd_ooblayout_free(mtd, section++, oobfree) until it returns -ERANGE.
853
 *
854
 * Returns zero on success, a negative error code otherwise.
855
 */
856
int mtd_ooblayout_free(struct mtd_info *mtd, int section,
857
           struct mtd_oob_region *oobfree)
858
0
{
859
0
  memset(oobfree, 0, sizeof(*oobfree));
860
861
0
  if (section < 0)
862
0
    return -EINVAL;
863
864
0
  if (!mtd->ooblayout || !mtd->ooblayout->free)
865
0
    return -ENOTSUPP;
866
867
0
  return mtd->ooblayout->free(mtd, section, oobfree);
868
0
}
869
EXPORT_SYMBOL_GPL(mtd_ooblayout_free);
870
871
/**
872
 * mtd_ooblayout_find_region - Find the region attached to a specific byte
873
 * @mtd: mtd info structure
874
 * @byte: the byte we are searching for
875
 * @sectionp: pointer where the section id will be stored
876
 * @oobregion: used to retrieve the ECC position
877
 * @iter: iterator function. Should be either mtd_ooblayout_free or
878
 *    mtd_ooblayout_ecc depending on the region type you're searching for
879
 *
880
 * This function returns the section id and oobregion information of a
881
 * specific byte. For example, say you want to know where the 4th ECC byte is
882
 * stored, you'll use:
883
 *
884
 * mtd_ooblayout_find_region(mtd, 3, &section, &oobregion, mtd_ooblayout_ecc);
885
 *
886
 * Returns zero on success, a negative error code otherwise.
887
 */
888
static int mtd_ooblayout_find_region(struct mtd_info *mtd, int byte,
889
        int *sectionp, struct mtd_oob_region *oobregion,
890
        int (*iter)(struct mtd_info *,
891
              int section,
892
              struct mtd_oob_region *oobregion))
893
0
{
894
0
  int pos = 0, ret, section = 0;
895
896
0
  memset(oobregion, 0, sizeof(*oobregion));
897
898
0
  while (1) {
899
0
    ret = iter(mtd, section, oobregion);
900
0
    if (ret)
901
0
      return ret;
902
903
0
    if (pos + oobregion->length > byte)
904
0
      break;
905
906
0
    pos += oobregion->length;
907
0
    section++;
908
0
  }
909
910
  /*
911
   * Adjust region info to make it start at the beginning at the
912
   * 'start' ECC byte.
913
   */
914
0
  oobregion->offset += byte - pos;
915
0
  oobregion->length -= byte - pos;
916
0
  *sectionp = section;
917
918
0
  return 0;
919
0
}
920
921
/**
922
 * mtd_ooblayout_find_eccregion - Find the ECC region attached to a specific
923
 *          ECC byte
924
 * @mtd: mtd info structure
925
 * @eccbyte: the byte we are searching for
926
 * @sectionp: pointer where the section id will be stored
927
 * @oobregion: OOB region information
928
 *
929
 * Works like mtd_ooblayout_find_region() except it searches for a specific ECC
930
 * byte.
931
 *
932
 * Returns zero on success, a negative error code otherwise.
933
 */
934
int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
935
         int *section,
936
         struct mtd_oob_region *oobregion)
937
0
{
938
0
  return mtd_ooblayout_find_region(mtd, eccbyte, section, oobregion,
939
0
           mtd_ooblayout_ecc);
940
0
}
941
EXPORT_SYMBOL_GPL(mtd_ooblayout_find_eccregion);
942
943
/**
944
 * mtd_ooblayout_get_bytes - Extract OOB bytes from the oob buffer
945
 * @mtd: mtd info structure
946
 * @buf: destination buffer to store OOB bytes
947
 * @oobbuf: OOB buffer
948
 * @start: first byte to retrieve
949
 * @nbytes: number of bytes to retrieve
950
 * @iter: section iterator
951
 *
952
 * Extract bytes attached to a specific category (ECC or free)
953
 * from the OOB buffer and copy them into buf.
954
 *
955
 * Returns zero on success, a negative error code otherwise.
956
 */
957
static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
958
        const u8 *oobbuf, int start, int nbytes,
959
        int (*iter)(struct mtd_info *,
960
              int section,
961
              struct mtd_oob_region *oobregion))
962
0
{
963
0
  struct mtd_oob_region oobregion;
964
0
  int section, ret;
965
966
0
  ret = mtd_ooblayout_find_region(mtd, start, &section,
967
0
          &oobregion, iter);
968
969
0
  while (!ret) {
970
0
    int cnt;
971
972
0
    cnt = min_t(int, nbytes, oobregion.length);
973
0
    memcpy(buf, oobbuf + oobregion.offset, cnt);
974
0
    buf += cnt;
975
0
    nbytes -= cnt;
976
977
0
    if (!nbytes)
978
0
      break;
979
980
0
    ret = iter(mtd, ++section, &oobregion);
981
0
  }
982
983
0
  return ret;
984
0
}
985
986
/**
987
 * mtd_ooblayout_set_bytes - put OOB bytes into the oob buffer
988
 * @mtd: mtd info structure
989
 * @buf: source buffer to get OOB bytes from
990
 * @oobbuf: OOB buffer
991
 * @start: first OOB byte to set
992
 * @nbytes: number of OOB bytes to set
993
 * @iter: section iterator
994
 *
995
 * Fill the OOB buffer with data provided in buf. The category (ECC or free)
996
 * is selected by passing the appropriate iterator.
997
 *
998
 * Returns zero on success, a negative error code otherwise.
999
 */
1000
static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
1001
        u8 *oobbuf, int start, int nbytes,
1002
        int (*iter)(struct mtd_info *,
1003
              int section,
1004
              struct mtd_oob_region *oobregion))
1005
0
{
1006
0
  struct mtd_oob_region oobregion;
1007
0
  int section, ret;
1008
1009
0
  ret = mtd_ooblayout_find_region(mtd, start, &section,
1010
0
          &oobregion, iter);
1011
1012
0
  while (!ret) {
1013
0
    int cnt;
1014
1015
0
    cnt = min_t(int, nbytes, oobregion.length);
1016
0
    memcpy(oobbuf + oobregion.offset, buf, cnt);
1017
0
    buf += cnt;
1018
0
    nbytes -= cnt;
1019
1020
0
    if (!nbytes)
1021
0
      break;
1022
1023
0
    ret = iter(mtd, ++section, &oobregion);
1024
0
  }
1025
1026
0
  return ret;
1027
0
}
1028
1029
/**
1030
 * mtd_ooblayout_count_bytes - count the number of bytes in a OOB category
1031
 * @mtd: mtd info structure
1032
 * @iter: category iterator
1033
 *
1034
 * Count the number of bytes in a given category.
1035
 *
1036
 * Returns a positive value on success, a negative error code otherwise.
1037
 */
1038
static int mtd_ooblayout_count_bytes(struct mtd_info *mtd,
1039
        int (*iter)(struct mtd_info *,
1040
              int section,
1041
              struct mtd_oob_region *oobregion))
1042
0
{
1043
0
  struct mtd_oob_region oobregion;
1044
0
  int section = 0, ret, nbytes = 0;
1045
1046
0
  while (1) {
1047
0
    ret = iter(mtd, section++, &oobregion);
1048
0
    if (ret) {
1049
0
      if (ret == -ERANGE)
1050
0
        ret = nbytes;
1051
0
      break;
1052
0
    }
1053
1054
0
    nbytes += oobregion.length;
1055
0
  }
1056
1057
0
  return ret;
1058
0
}
1059
1060
/**
1061
 * mtd_ooblayout_get_eccbytes - extract ECC bytes from the oob buffer
1062
 * @mtd: mtd info structure
1063
 * @eccbuf: destination buffer to store ECC bytes
1064
 * @oobbuf: OOB buffer
1065
 * @start: first ECC byte to retrieve
1066
 * @nbytes: number of ECC bytes to retrieve
1067
 *
1068
 * Works like mtd_ooblayout_get_bytes(), except it acts on ECC bytes.
1069
 *
1070
 * Returns zero on success, a negative error code otherwise.
1071
 */
1072
int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf,
1073
             const u8 *oobbuf, int start, int nbytes)
1074
0
{
1075
0
  return mtd_ooblayout_get_bytes(mtd, eccbuf, oobbuf, start, nbytes,
1076
0
               mtd_ooblayout_ecc);
1077
0
}
1078
EXPORT_SYMBOL_GPL(mtd_ooblayout_get_eccbytes);
1079
1080
/**
1081
 * mtd_ooblayout_set_eccbytes - set ECC bytes into the oob buffer
1082
 * @mtd: mtd info structure
1083
 * @eccbuf: source buffer to get ECC bytes from
1084
 * @oobbuf: OOB buffer
1085
 * @start: first ECC byte to set
1086
 * @nbytes: number of ECC bytes to set
1087
 *
1088
 * Works like mtd_ooblayout_set_bytes(), except it acts on ECC bytes.
1089
 *
1090
 * Returns zero on success, a negative error code otherwise.
1091
 */
1092
int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf,
1093
             u8 *oobbuf, int start, int nbytes)
1094
0
{
1095
0
  return mtd_ooblayout_set_bytes(mtd, eccbuf, oobbuf, start, nbytes,
1096
0
               mtd_ooblayout_ecc);
1097
0
}
1098
EXPORT_SYMBOL_GPL(mtd_ooblayout_set_eccbytes);
1099
1100
/**
1101
 * mtd_ooblayout_get_databytes - extract data bytes from the oob buffer
1102
 * @mtd: mtd info structure
1103
 * @databuf: destination buffer to store ECC bytes
1104
 * @oobbuf: OOB buffer
1105
 * @start: first ECC byte to retrieve
1106
 * @nbytes: number of ECC bytes to retrieve
1107
 *
1108
 * Works like mtd_ooblayout_get_bytes(), except it acts on free bytes.
1109
 *
1110
 * Returns zero on success, a negative error code otherwise.
1111
 */
1112
int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf,
1113
        const u8 *oobbuf, int start, int nbytes)
1114
0
{
1115
0
  return mtd_ooblayout_get_bytes(mtd, databuf, oobbuf, start, nbytes,
1116
0
               mtd_ooblayout_free);
1117
0
}
1118
EXPORT_SYMBOL_GPL(mtd_ooblayout_get_databytes);
1119
1120
/**
1121
 * mtd_ooblayout_set_databytes - set data bytes into the oob buffer
1122
 * @mtd: mtd info structure
1123
 * @databuf: source buffer to get data bytes from
1124
 * @oobbuf: OOB buffer
1125
 * @start: first ECC byte to set
1126
 * @nbytes: number of ECC bytes to set
1127
 *
1128
 * Works like mtd_ooblayout_set_bytes(), except it acts on free bytes.
1129
 *
1130
 * Returns zero on success, a negative error code otherwise.
1131
 */
1132
int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
1133
        u8 *oobbuf, int start, int nbytes)
1134
0
{
1135
0
  return mtd_ooblayout_set_bytes(mtd, databuf, oobbuf, start, nbytes,
1136
0
               mtd_ooblayout_free);
1137
0
}
1138
EXPORT_SYMBOL_GPL(mtd_ooblayout_set_databytes);
1139
1140
/**
1141
 * mtd_ooblayout_count_freebytes - count the number of free bytes in OOB
1142
 * @mtd: mtd info structure
1143
 *
1144
 * Works like mtd_ooblayout_count_bytes(), except it count free bytes.
1145
 *
1146
 * Returns zero on success, a negative error code otherwise.
1147
 */
1148
int mtd_ooblayout_count_freebytes(struct mtd_info *mtd)
1149
0
{
1150
0
  return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_free);
1151
0
}
1152
EXPORT_SYMBOL_GPL(mtd_ooblayout_count_freebytes);
1153
1154
/**
1155
 * mtd_ooblayout_count_eccbytes - count the number of ECC bytes in OOB
1156
 * @mtd: mtd info structure
1157
 *
1158
 * Works like mtd_ooblayout_count_bytes(), except it count ECC bytes.
1159
 *
1160
 * Returns zero on success, a negative error code otherwise.
1161
 */
1162
int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd)
1163
0
{
1164
0
  return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_ecc);
1165
0
}
1166
EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes);
1167
1168
1169
/**
1170
 * mtd_ecclayout_ecc - Default ooblayout_ecc iterator implementation
1171
 * @mtd: MTD device structure
1172
 * @section: ECC section. Depending on the layout you may have all the ECC
1173
 *       bytes stored in a single contiguous section, or one section
1174
 *       per ECC chunk (and sometime several sections for a single ECC
1175
 *       ECC chunk)
1176
 * @oobecc: OOB region struct filled with the appropriate ECC position
1177
 *      information
1178
 *
1179
 * This function is just a wrapper around the mtd->ecclayout field and is
1180
 * here to ease the transition to the mtd_ooblayout_ops approach.
1181
 * All it does is convert the layout->eccpos information into proper oob
1182
 * region definitions.
1183
 *
1184
 * Returns zero on success, a negative error code otherwise.
1185
 */
1186
static int mtd_ecclayout_ecc(struct mtd_info *mtd, int section,
1187
           struct mtd_oob_region *oobecc)
1188
0
{
1189
0
  int eccbyte = 0, cursection = 0, length = 0, eccpos = 0;
1190
1191
0
  if (!mtd->ecclayout)
1192
0
    return -ENOTSUPP;
1193
1194
  /*
1195
   * This logic allows us to reuse the ->ecclayout information and
1196
   * expose them as ECC regions (as done for the OOB free regions).
1197
   *
1198
   * TODO: this should be dropped as soon as we get rid of the
1199
   * ->ecclayout field.
1200
   */
1201
0
  for (eccbyte = 0; eccbyte < mtd->ecclayout->eccbytes; eccbyte++) {
1202
0
    eccpos = mtd->ecclayout->eccpos[eccbyte];
1203
1204
0
    if (eccbyte < mtd->ecclayout->eccbytes - 1) {
1205
0
      int neccpos = mtd->ecclayout->eccpos[eccbyte + 1];
1206
1207
0
      if (eccpos + 1 == neccpos) {
1208
0
        length++;
1209
0
        continue;
1210
0
      }
1211
0
    }
1212
1213
0
    if (section == cursection)
1214
0
      break;
1215
1216
0
    length = 0;
1217
0
    cursection++;
1218
0
  }
1219
1220
0
  if (cursection != section || eccbyte >= mtd->ecclayout->eccbytes)
1221
0
    return -ERANGE;
1222
1223
0
  oobecc->length = length + 1;
1224
0
  oobecc->offset = eccpos - length;
1225
1226
0
  return 0;
1227
0
}
1228
1229
/**
1230
 * mtd_ecclayout_ecc - Default ooblayout_free iterator implementation
1231
 * @mtd: MTD device structure
1232
 * @section: Free section. Depending on the layout you may have all the free
1233
 *       bytes stored in a single contiguous section, or one section
1234
 *       per ECC chunk (and sometime several sections for a single ECC
1235
 *       ECC chunk)
1236
 * @oobfree: OOB region struct filled with the appropriate free position
1237
 *       information
1238
 *
1239
 * This function is just a wrapper around the mtd->ecclayout field and is
1240
 * here to ease the transition to the mtd_ooblayout_ops approach.
1241
 * All it does is convert the layout->oobfree information into proper oob
1242
 * region definitions.
1243
 *
1244
 * Returns zero on success, a negative error code otherwise.
1245
 */
1246
static int mtd_ecclayout_free(struct mtd_info *mtd, int section,
1247
            struct mtd_oob_region *oobfree)
1248
0
{
1249
0
  struct nand_ecclayout *layout = mtd->ecclayout;
1250
1251
0
  if (!layout)
1252
0
    return -ENOTSUPP;
1253
1254
0
  if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE ||
1255
0
      !layout->oobfree[section].length)
1256
0
    return -ERANGE;
1257
1258
0
  oobfree->offset = layout->oobfree[section].offset;
1259
0
  oobfree->length = layout->oobfree[section].length;
1260
1261
0
  return 0;
1262
0
}
1263
1264
static const struct mtd_ooblayout_ops mtd_ecclayout_wrapper_ops = {
1265
  .ecc = mtd_ecclayout_ecc,
1266
  .free = mtd_ecclayout_free,
1267
};
1268
1269
/**
1270
 * mtd_set_ecclayout - Attach an ecclayout to an MTD device
1271
 * @mtd: MTD device structure
1272
 * @ecclayout: The ecclayout to attach to the device
1273
 *
1274
 * Returns zero on success, a negative error code otherwise.
1275
 */
1276
void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout)
1277
0
{
1278
0
  if (!mtd || !ecclayout)
1279
0
    return;
1280
1281
0
  mtd->ecclayout = ecclayout;
1282
0
  mtd_set_ooblayout(mtd, &mtd_ecclayout_wrapper_ops);
1283
0
}
1284
EXPORT_SYMBOL_GPL(mtd_set_ecclayout);
1285
1286
void mtd_print_oob_info(struct mtd_info *mtd)
1287
0
{
1288
0
  struct mtd_oob_region region;
1289
0
  int ret, i = 0, j, rowsize;
1290
0
  unsigned char *oob;
1291
1292
0
  if (!mtd->ooblayout)
1293
0
    return;
1294
1295
0
  oob = malloc(mtd->oobsize);
1296
0
  if (!oob)
1297
0
    return;
1298
1299
0
  memset(oob, ' ', mtd->oobsize);
1300
1301
0
  printf("---- ECC regions ----\n");
1302
0
  while (1) {
1303
0
    ret = mtd->ooblayout->ecc(mtd, i, &region);
1304
0
    if (ret)
1305
0
      break;
1306
0
    printf("ecc:  offset: %4d length: %4d\n",
1307
0
           region.offset, region.length);
1308
0
    i++;
1309
1310
0
    for (j = 0; j < region.length; j++) {
1311
0
      unsigned char *p = oob + region.offset + j;
1312
1313
0
      if (*p != ' ')
1314
0
        printf("oob offset %d already set to '%c'\n",
1315
0
               region.offset + j, *p);
1316
0
      *p = 'e';
1317
0
    }
1318
0
  }
1319
1320
0
  i = 0;
1321
1322
0
  printf("---- free regions ----\n");
1323
0
  while (1) {
1324
0
    ret = mtd->ooblayout->free(mtd, i, &region);
1325
0
    if (ret)
1326
0
      break;
1327
1328
0
    printf("free: offset: %4d length: %4d\n",
1329
0
           region.offset, region.length);
1330
0
    i++;
1331
1332
0
    for (j = 0; j < region.length; j++) {
1333
0
      unsigned char *p = oob + region.offset + j;
1334
1335
0
      if (*p != ' ')
1336
0
        printf("oob offset %d already set to '%c'\n",
1337
0
               region.offset + j, *p);
1338
0
      *p = 'f';
1339
0
    }
1340
0
  }
1341
1342
0
  j = 0;
1343
0
  rowsize = 16;
1344
1345
0
  printf("---- OOB area ----\n");
1346
0
  while (1) {
1347
0
    printf("%-4d", j);
1348
1349
0
    for (i = 0; i < rowsize; i++) {
1350
0
      if (i + j >= mtd->oobsize)
1351
0
        break;
1352
0
      if (i == rowsize / 2)
1353
0
        printf(" ");
1354
0
      printf(" %c", oob[j + i]);
1355
0
    }
1356
1357
0
    printf("\n");
1358
0
    j += rowsize;
1359
1360
0
    if (j >= mtd->oobsize)
1361
0
      break;
1362
0
  }
1363
1364
0
  free(oob);
1365
0
}