· 7 years ago · Nov 22, 2018, 05:58 PM
1/*
2 * BML over MTD compatibility layer.
3 * Copyright © 2011 Tomasz Figa <tomasz.figa at gmail.com>
4 *
5 * Based on Direct MTD block device access (mtdblock):
6 * Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org>
7 * Copyright © 2000-2003 Nicolas Pitre <nico@fluxnic.net>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <linux/bitmap.h>
25#include <linux/fs.h>
26#include <linux/init.h>
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/sched.h>
30#include <linux/slab.h>
31#include <linux/types.h>
32#include <linux/vmalloc.h>
33#include <linux/platform_device.h>
34#include <linux/sort.h>
35#include <linux/bsearch.h>
36#include <linux/suspend.h>
37
38#include <linux/mtd/partitions.h>
39#include <linux/mtd/bml.h>
40#include <linux/mtd/mtd.h>
41#include <linux/mtd/blktrans.h>
42#include <linux/mutex.h>
43
44/*
45 * Structures used by BML
46 */
47
48#define BML_SECT_SIZE (512)
49#define SECT_PER_BMS (3)
50#define SECT_PER_BMI (4)
51
52#define TYPE_INIT_CREATE (0xFCFE)
53#define TYPE_UPDATE_PIEXT (0xFAFE)
54#define TYPE_WRITE_ERR (0xFDFE)
55#define TYPE_ERASE_ERR (0xFEFE)
56
57#define BML_UPCB_HDR "UPCH"
58/**
59 * @brief Data structure to save device info used in the BBM for compatibility
60 */
61typedef struct
62{
63 u32 nNumOfPlane; /**< number of plane (1 or 2) */
64 u32 nNumOfDieInDev; /**< number of die (1 or 2) */
65 u32 nNumOfBlksInDie; /**< number of blocks in a die */
66 u32 nNumOfBlksInDev; /**< number of blocks in a device */
67} BmlDevInfo;
68
69#if 0
70struct bml_pcb_header {
71 UINT8 sig[4];
72 u16 age;
73 u16 alt_pcb;
74 char erase_sig[8];
75} __attribute__((packed));
76#endif
77struct bml_pcb_header {
78 u8 sig[4];
79 u16 nREFPbn; /**< Pbn of REF block */
80 u16 nTPCBPbn; /**< Pbn of TPCB block */
81 u16 nNumOfMLCRsvr; /**< number of MLC reservoir */
82 u16 nRsv; /**< Reserved area (Unused) */
83 u32 age;
84 u32 alt_pcb;
85 BmlDevInfo stDevInfo; /**< device info for compatibility */
86 char erase_sig[8];
87 u8 padding[468];
88} __attribute__((packed));
89
90#if 0
91typedef struct
92{
93 UINT8 aSig[BML_MAX_PCH_SIG]; /**< "LPCH" / "UPCH" */
94 UINT16 nREFPbn; /**< Pbn of REF block */
95 UINT16 nTPCBPbn; /**< Pbn of TPCB block */
96 UINT16 nNumOfMLCRsvr; /**< number of MLC reservoir */
97 UINT16 nRsv; /**< Reserved area (Unused) */
98 UINT32 nAge; /**< Age of PCH */
99 UINT32 nGlobalAge; /**< Global age of PCH */
100 BmlDevInfo stDevInfo; /**< device info for compatibility */
101 UINT8 aPad[FSR_SECTOR_SIZE - BML_MAX_PCH_SIG - 4 * 8];
102 /** reserved area (not used) */
103} BmlPoolCtlHdr;
104#endif
105
106struct bml_bms_entry {
107 u16 sbn;
108 u16 rbn;
109} __attribute__((packed));
110
111struct bml_bms_header {
112 u16 inf;
113 u16 age;
114} __attribute__((packed));
115
116#define BMS_ENTRY_COUNT \
117 ((BML_SECT_SIZE - sizeof(struct bml_bms_header)) \
118 / sizeof(struct bml_bms_entry))
119
120struct bml_bms_sector {
121 struct bml_bms_header hdr;
122 struct bml_bms_entry entries[BMS_ENTRY_COUNT];
123} __attribute__((packed));
124
125/*
126 * Driver data
127 */
128struct bml_map_entry {
129 size_t from;
130 size_t to_offs;
131};
132
133struct bml_map_info {
134 struct mtd_info *mtd;
135 u32 length;
136 struct bml_map_entry table[];
137};
138
139struct bml_dev {
140 struct mtd_blktrans_dev mbd;
141 int count;
142 struct mutex cache_mutex;
143 unsigned char *cache_data;
144 unsigned long cache_offset;
145 unsigned int cache_size;
146 enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
147 unsigned long *bad_bitmap;
148 size_t offset;
149};
150
151static struct bml_map_info *bml_map_info;
152static const struct bml_platform_data *bml_pdata;
153static struct mutex bmls_lock;
154
155/*
156 * BML stuff...
157 */
158
159static inline bool bms_inf_valid(struct bml_bms_header *bms)
160{
161 switch (bms->inf) {
162 case TYPE_INIT_CREATE:
163 case TYPE_WRITE_ERR:
164 case TYPE_ERASE_ERR:
165 case TYPE_UPDATE_PIEXT:
166 case 0:
167 return true;
168 default:
169 return false;
170 }
171}
172
173static ssize_t find_last_upcb(struct mtd_info *mtd)
174{
175 struct bml_pcb_header pch;
176 size_t last_upcb;
177 size_t retlen;
178 size_t offset;
179 size_t size;
180 u16 max_age;
181 int ret;
182
183 retlen = 0;
184 max_age = 0;
185 for (offset = 0, size = mtd->size; size >= mtd->erasesize;
186 size -= mtd->erasesize, offset += mtd->erasesize) {
187 ret = mtd->block_isbad(mtd, offset);
188 if (ret)
189 continue;
190
191 ret = mtd->read(mtd, offset, sizeof(pch),
192 &retlen, (u_char *)&pch);
193 if (ret || retlen != sizeof(pch))
194 continue;
195
196 if (strncmp(pch.sig, BML_UPCB_HDR, sizeof(pch.sig)))
197 continue;
198
199 if (pch.age <= max_age)
200 continue;
201
202 max_age = pch.age;
203 last_upcb = offset;
204 }
205
206 if (max_age == 0)
207 return -ENOENT;
208
209 if (max_age == 0xffff)
210 return -EINVAL;
211
212 return last_upcb;
213}
214
215static int find_last_bms(struct mtd_info *mtd, size_t upcb_pos,
216 size_t *bms_pos)
217{
218 struct bml_bms_header bms;
219 size_t last_bms;
220 size_t retlen;
221 size_t offset;
222 u16 max_age;
223 u16 last_age;
224 int ret;
225 int count;
226
227 count = 0;
228 retlen = 0;
229 max_age = 0;
230 last_age = 0;
231
232
233 for (offset = upcb_pos; offset < upcb_pos + mtd->erasesize;
234 offset += SECT_PER_BMI*BML_SECT_SIZE) {
235
236 ret = mtd->read(mtd, offset, sizeof(bms),
237 &retlen, (u_char *)&bms);
238
239 if (ret || retlen != sizeof(bms))
240 continue;
241
242 if (!bms_inf_valid(&bms))
243 continue;
244
245 ret = mtd->read(mtd, offset + SECT_PER_BMS*BML_SECT_SIZE,
246 sizeof(bms), &retlen, (u_char *)&bms);
247
248 if (ret || retlen != sizeof(bms))
249 continue;
250
251 if (!bms_inf_valid(&bms))
252 continue;
253
254 //if (bms.age == last_age)
255 ++count;
256
257 //if (bms.age <= max_age)
258 // continue;
259
260 max_age = bms.age;
261 last_age = bms.age;
262 last_bms = offset;
263 count = 1;
264 }
265
266 //if (max_age == 0)
267 // return -ENOENT;
268
269 //if (max_age == 0xffff)
270 // return -EINVAL;
271
272 *bms_pos = last_bms;
273
274 return count;
275}
276
277static int bml_map_cmp(const void *a, const void *b)
278{
279 const struct bml_map_entry *entry_a = a;
280 const struct bml_map_entry *entry_b = b;
281
282 return entry_a->from - entry_b->from;
283}
284
285static void bml_map_swap(void *a, void *b, int size)
286{
287 struct bml_map_entry *entry_a = a;
288 struct bml_map_entry *entry_b = b;
289 struct bml_map_entry tmp;
290
291 tmp = *entry_a;
292 *entry_a = *entry_b;
293 *entry_b = tmp;
294}
295
296static struct bml_map_info *create_block_mapping(struct mtd_info *mtd,
297 size_t bms_pos, int bms_count)
298{
299 struct bml_map_info *map;
300 struct bml_bms_sector bms;
301 struct bml_map_entry *entry;
302 size_t retlen;
303 size_t offset;
304 u32 bmi_count;
305 int count;
306 int ret;
307 int i;
308
309 bmi_count = 0;
310 count = bms_count;
311 for (offset = bms_pos; count; --count,
312 offset += SECT_PER_BMS*BML_SECT_SIZE) {
313 ret = mtd->read(mtd, offset, sizeof(bms),
314 &retlen, (u_char *)&bms);
315 if (ret || retlen != sizeof(bms))
316 return NULL;
317
318 for (i = 0; i < ARRAY_SIZE(bms.entries); ++i) {
319 if (bms.entries[i].rbn == 0xffff)
320 goto scan_last;
321 ++bmi_count;
322 }
323 }
324
325scan_last:
326 map = vmalloc(sizeof(struct bml_map_info)
327 + bmi_count * sizeof(struct bml_map_entry));
328 if (!map)
329 return ERR_PTR(-ENOMEM);
330
331 map->length = bmi_count;
332 entry = map->table;
333 count = bms_count;
334 for (offset = bms_pos; count; --count,
335 offset += SECT_PER_BMS*BML_SECT_SIZE) {
336 ret = mtd->read(mtd, offset, sizeof(bms),
337 &retlen, (u_char *)&bms);
338 if (ret || retlen != sizeof(bms)) {
339 vfree(map);
340 return ERR_PTR(-EIO);
341 }
342
343 for (i = 0; i < ARRAY_SIZE(bms.entries); ++i) {
344 if (bms.entries[i].rbn == 0xffff)
345 goto build_last;
346 if (mtd->erasesize_shift) {
347 entry->from = bms.entries[i].sbn <<
348 mtd->erasesize_shift;
349 entry->to_offs = bms.entries[i].rbn <<
350 mtd->erasesize_shift;
351 } else {
352 entry->from = bms.entries[i].sbn *
353 mtd->erasesize;
354 entry->to_offs = bms.entries[i].rbn *
355 mtd->erasesize;
356 }
357 ++entry;
358 }
359 }
360
361build_last:
362 sort(map->table, map->length, sizeof(struct bml_map_entry),
363 bml_map_cmp, bml_map_swap);
364
365 return map;
366}
367
368static int build_map_info(void)
369{
370 struct bml_map_entry *entry;
371 struct mtd_info *mtd;
372 ssize_t last_upcb;
373 size_t last_bms;
374 int bms_count;
375 int ret;
376 int i;
377
378 mtd = get_mtd_device_nm("reservoir");
379 if (IS_ERR(mtd)) {
380 pr_err("mtd-bml: Could not find UPCA partition.\n");
381 return PTR_ERR(mtd);
382 }
383
384 if (!mtd->lock || !mtd->unlock) {
385 pr_err("mtd-bml: Block lock and unlock functionality is required.\n");
386 put_mtd_device(mtd);
387 return -EINVAL;
388 }
389
390 last_upcb = find_last_upcb(mtd);
391 if (last_upcb < 0) {
392 pr_err("mtd-bml: Could not find UPCB block.\n");
393 ret = last_upcb;
394 goto error;
395 }
396
397 bms_count = find_last_bms(mtd, last_upcb, &last_bms);
398 if (bms_count <= 0) {
399 pr_err("mtd-bml: Could not find BMS block.\n");
400 ret = bms_count;
401 goto error;
402 }
403
404 bml_map_info = create_block_mapping(mtd, last_bms, bms_count);
405 if (IS_ERR(bml_map_info)) {
406 pr_err("mtd-bml: Failed to create block mapping.\n");
407 ret = PTR_ERR(bml_map_info);
408 goto error;
409 }
410
411 entry = bml_map_info->table;
412 for (i = 0; i < bml_map_info->length; ++i, ++entry) {
413 u32 bad, res;
414 if (mtd->erasesize_shift) {
415 bad = entry->from >> mtd->erasesize_shift;
416 res = entry->to_offs >> mtd->erasesize_shift;
417 } else {
418 bad = entry->from / mtd->erasesize_shift;
419 res = entry->to_offs / mtd->erasesize_shift;
420 }
421 pr_info("mtd-bml: Found mapping of bad block %u to reserved block %u.\n",
422 bad, res);
423 mtd->unlock(mtd, entry->to_offs, mtd->erasesize);
424 }
425
426 bml_map_info->mtd = mtd;
427 return 0;
428
429error:
430 put_mtd_device(mtd);
431 return ret;
432}
433
434static ssize_t bml_lookup(size_t offset, size_t pos)
435{
436 struct bml_map_entry key = { .from = offset + pos };
437 struct bml_map_entry *entry;
438
439 entry = bsearch(&key, bml_map_info->table, bml_map_info->length,
440 sizeof(struct bml_map_entry), bml_map_cmp);
441
442 if (!entry)
443 return -ENOENT;
444
445 return entry->to_offs;
446}
447
448static int bml_read_block(struct bml_dev *bml, u32 block, size_t offset,
449 size_t len, u_char *buf)
450{
451 struct mtd_info *mtd = bml->mbd.mtd;
452 size_t retlen = 0;
453 size_t pos;
454 int ret;
455
456 if (mtd->erasesize_shift)
457 pos = block << mtd->erasesize_shift;
458 else
459 pos = block * mtd->erasesize;
460
461 if (test_bit(block, bml->bad_bitmap)) {
462 mtd = bml_map_info->mtd;
463 pos = bml_lookup(bml->offset, pos);
464 BUG_ON(pos < 0);
465 }
466
467 ret = mtd->read(mtd, pos + offset, len, &retlen, buf);
468 if (ret)
469 return ret;
470 if (retlen != len)
471 return -EIO;
472
473 return 0;
474}
475
476static int bml_read(struct bml_dev *bml, size_t pos, size_t size, u_char *buf)
477{
478 struct mtd_info *mtd = bml->mbd.mtd;
479 u32 block;
480 size_t offset;
481 ssize_t ssize = size;
482 int ret;
483
484 if (mtd->erasesize_shift)
485 block = pos >> mtd->erasesize_shift;
486 else
487 block = pos / mtd->erasesize;
488
489 if (mtd->erasesize_mask)
490 offset = pos & mtd->erasesize_mask;
491 else
492 offset = pos % mtd->erasesize;
493
494 if (offset) {
495 size_t len = mtd->erasesize - offset;
496 if (len > ssize)
497 len = ssize;
498
499 ret = bml_read_block(bml, block, offset, len, buf);
500 if (ret)
501 return ret;
502
503 ssize -= len;
504 pos += len;
505 buf += len;
506 ++block;
507 }
508
509 while(ssize > 0) {
510 size_t len = (ssize > mtd->erasesize) ? mtd->erasesize : ssize;
511
512 ret = bml_read_block(bml, block, 0, len, buf);
513 if (ret)
514 return ret;
515
516 ssize -= len;
517 pos += len;
518 buf += len;
519 ++block;
520 }
521
522 return 0;
523}
524
525static void erase_callback(struct erase_info *done)
526{
527 wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
528 wake_up(wait_q);
529}
530
531static int bml_erase_write (struct bml_dev *bml, unsigned long pos,
532 int len, const char *buf)
533{
534 struct mtd_info *mtd = bml->mbd.mtd;
535 struct erase_info erase;
536 DECLARE_WAITQUEUE(wait, current);
537 wait_queue_head_t wait_q;
538 size_t retlen;
539 u32 block;
540 int ret;
541
542 if (mtd->erasesize_shift)
543 block = pos >> mtd->erasesize_shift;
544 else
545 block = pos / mtd->erasesize;
546
547 if (test_bit(block, bml->bad_bitmap)) {
548 mtd = bml_map_info->mtd;
549 pos = bml_lookup(bml->offset, pos);
550 BUG_ON(pos < 0);
551 }
552
553 /*
554 * First, let's erase the flash block.
555 */
556
557 init_waitqueue_head(&wait_q);
558 erase.mtd = mtd;
559 erase.callback = erase_callback;
560 erase.addr = pos;
561 erase.len = len;
562 erase.priv = (u_long)&wait_q;
563
564 set_current_state(TASK_INTERRUPTIBLE);
565 add_wait_queue(&wait_q, &wait);
566
567 ret = mtd->erase(mtd, &erase);
568 if (ret) {
569 set_current_state(TASK_RUNNING);
570 remove_wait_queue(&wait_q, &wait);
571 printk (KERN_WARNING "bml: erase of region [0x%lx, 0x%x] "
572 "on \"%s\" failed\n",
573 pos, len, mtd->name);
574 return ret;
575 }
576
577 schedule(); /* Wait for erase to finish. */
578 remove_wait_queue(&wait_q, &wait);
579
580 /*
581 * Next, write the data to flash.
582 */
583
584 ret = mtd->write(mtd, pos, len, &retlen, buf);
585 if (ret)
586 return ret;
587 if (retlen != len)
588 return -EIO;
589 return 0;
590}
591
592static int build_bad_bitmap(struct bml_dev *bml)
593{
594 struct mtd_info *mtd = bml->mbd.mtd;
595 struct bml_map_entry *entry = bml_map_info->table;
596 size_t offset;
597 int block;
598 int blocks;
599 int i;
600
601 if (mtd->erasesize_shift) {
602 blocks = mtd->size >> mtd->erasesize_shift;
603 } else {
604 blocks = 0;
605 for (offset = 0; offset < mtd->size; offset += mtd->erasesize)
606 ++blocks;
607 }
608
609 bml->bad_bitmap = vmalloc(BITS_TO_LONGS(blocks));
610 if (!bml->bad_bitmap)
611 return -ENOMEM;
612
613 bitmap_zero(bml->bad_bitmap, blocks);
614
615 for (i = 0; i < bml_map_info->length; ++i, ++entry) {
616 if (entry->from < bml->offset)
617 continue;
618
619 if (entry->from >= bml->offset + mtd->size)
620 break;
621
622 offset = entry->from - bml->offset;
623
624 if (mtd->erasesize_shift)
625 block = offset >> mtd->erasesize_shift;
626 else
627 block = offset / mtd->erasesize;
628
629 set_bit(block, bml->bad_bitmap);
630 }
631
632 return 0;
633}
634
635/*
636 * Cache stuff...
637 *
638 * Since typical flash erasable sectors are much larger than what Linux's
639 * buffer cache can handle, we must implement read-modify-write on flash
640 * sectors for each block write requests. To avoid over-erasing flash sectors
641 * and to speed things up, we locally cache a whole flash sector while it is
642 * being written to until a different sector is required.
643 */
644
645static int write_cached_data (struct bml_dev *bmldev)
646{
647 struct mtd_info *mtd = bmldev->mbd.mtd;
648 int ret;
649
650 if (bmldev->cache_state != STATE_DIRTY)
651 return 0;
652
653 DEBUG(MTD_DEBUG_LEVEL2, "bml: writing cached data for \"%s\" "
654 "at 0x%lx, size 0x%x\n", mtd->name,
655 bmldev->cache_offset, bmldev->cache_size);
656
657 ret = bml_erase_write (bmldev, bmldev->cache_offset,
658 bmldev->cache_size, bmldev->cache_data);
659 if (ret)
660 return ret;
661
662 /*
663 * Here we could arguably set the cache state to STATE_CLEAN.
664 * However this could lead to inconsistency since we will not
665 * be notified if this content is altered on the flash by other
666 * means. Let's declare it empty and leave buffering tasks to
667 * the buffer cache instead.
668 */
669 bmldev->cache_state = STATE_EMPTY;
670 return 0;
671}
672
673
674static int do_cached_write (struct bml_dev *bmldev, unsigned long pos,
675 int len, const char *buf)
676{
677 struct mtd_info *mtd = bmldev->mbd.mtd;
678 unsigned int sect_size = bmldev->cache_size;
679 int ret;
680
681 DEBUG(MTD_DEBUG_LEVEL2, "bml: write on \"%s\" at 0x%lx, size 0x%x\n",
682 mtd->name, pos, len);
683
684 while (len > 0) {
685 unsigned long sect_start = (pos/sect_size)*sect_size;
686 unsigned int offset = pos - sect_start;
687 unsigned int size = sect_size - offset;
688 if( size > len )
689 size = len;
690
691 if (size == sect_size) {
692 /*
693 * We are covering a whole sector. Thus there is no
694 * need to bother with the cache while it may still be
695 * useful for other partial writes.
696 */
697 ret = bml_erase_write(bmldev, pos, size, buf);
698 if (ret)
699 return ret;
700 } else {
701 /* Partial sector: need to use the cache */
702
703 if (bmldev->cache_state == STATE_DIRTY &&
704 bmldev->cache_offset != sect_start) {
705 ret = write_cached_data(bmldev);
706 if (ret)
707 return ret;
708 }
709
710 if (bmldev->cache_state == STATE_EMPTY ||
711 bmldev->cache_offset != sect_start) {
712 /* fill the cache with the current sector */
713 bmldev->cache_state = STATE_EMPTY;
714 ret = bml_read(bmldev, sect_start, sect_size,
715 bmldev->cache_data);
716 if (ret)
717 return ret;
718
719 bmldev->cache_offset = sect_start;
720 bmldev->cache_size = sect_size;
721 bmldev->cache_state = STATE_CLEAN;
722 }
723
724 /* write data to our local cache */
725 memcpy (bmldev->cache_data + offset, buf, size);
726 bmldev->cache_state = STATE_DIRTY;
727 }
728
729 buf += size;
730 pos += size;
731 len -= size;
732 }
733
734 return 0;
735}
736
737
738static int do_cached_read (struct bml_dev *bmldev, unsigned long pos,
739 int len, char *buf)
740{
741 struct mtd_info *mtd = bmldev->mbd.mtd;
742 unsigned int sect_size = bmldev->cache_size;
743 int ret;
744
745 DEBUG(MTD_DEBUG_LEVEL2, "bml: read on \"%s\" at 0x%lx, size 0x%x\n",
746 mtd->name, pos, len);
747
748 while (len > 0) {
749 unsigned long sect_start = (pos/sect_size)*sect_size;
750 unsigned int offset = pos - sect_start;
751 unsigned int size = sect_size - offset;
752 if (size > len)
753 size = len;
754
755 /*
756 * Check if the requested data is already cached
757 * Read the requested amount of data from our internal cache if it
758 * contains what we want, otherwise we read the data directly
759 * from flash.
760 */
761 if (bmldev->cache_state != STATE_EMPTY &&
762 bmldev->cache_offset == sect_start) {
763 memcpy (buf, bmldev->cache_data + offset, size);
764 } else {
765 ret = bml_read(bmldev, pos, size, buf);
766 if (ret)
767 return ret;
768 }
769
770 buf += size;
771 pos += size;
772 len -= size;
773 }
774
775 return 0;
776}
777
778static int bml_readsect(struct mtd_blktrans_dev *dev,
779 unsigned long block, char *buf)
780{
781 struct bml_dev *bmldev = container_of(dev, struct bml_dev, mbd);
782 return do_cached_read(bmldev, block<<9, 512, buf);
783}
784
785static int bml_writesect(struct mtd_blktrans_dev *dev,
786 unsigned long block, char *buf)
787{
788 struct bml_dev *bmldev = container_of(dev, struct bml_dev, mbd);
789 if (unlikely(!bmldev->cache_data)) {
790 bmldev->cache_data = vmalloc(bmldev->mbd.mtd->erasesize);
791 if (!bmldev->cache_data)
792 return -EINTR;
793 /* -EINTR is not really correct, but it is the best match
794 * documented in man 2 write for all cases. We could also
795 * return -EAGAIN sometimes, but why bother?
796 */
797 }
798 return do_cached_write(bmldev, block<<9, 512, buf);
799}
800
801static int bml_open(struct mtd_blktrans_dev *mbd)
802{
803 struct bml_dev *bmldev = container_of(mbd, struct bml_dev, mbd);
804 int ret = 0;
805
806 DEBUG(MTD_DEBUG_LEVEL1,"bml_open\n");
807
808 mutex_lock(&bmls_lock);
809 if (bmldev->count) {
810 bmldev->count++;
811 mutex_unlock(&bmls_lock);
812 return 0;
813 }
814
815 /* OK, it's not open. Create cache info for it */
816 bmldev->count = 1;
817 mutex_init(&bmldev->cache_mutex);
818 bmldev->cache_state = STATE_EMPTY;
819 bmldev->cache_size = mbd->mtd->erasesize;
820 bmldev->cache_data = NULL;
821 if (unlikely(!bml_map_info))
822 if((ret = build_map_info()) != 0)
823 goto error;
824 if (unlikely(!bmldev->bad_bitmap))
825 ret = build_bad_bitmap(bmldev);
826
827error:
828 mutex_unlock(&bmls_lock);
829
830 DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
831
832 return ret;
833}
834
835static int bml_release(struct mtd_blktrans_dev *mbd)
836{
837 struct bml_dev *bmldev = container_of(mbd, struct bml_dev, mbd);
838
839 DEBUG(MTD_DEBUG_LEVEL1, "bml_release\n");
840
841 mutex_lock(&bmls_lock);
842
843 mutex_lock(&bmldev->cache_mutex);
844 write_cached_data(bmldev);
845 mutex_unlock(&bmldev->cache_mutex);
846
847 if (!--bmldev->count) {
848 /* It was the last usage. Free the cache */
849 if (mbd->mtd->sync)
850 mbd->mtd->sync(mbd->mtd);
851 vfree(bmldev->cache_data);
852 }
853
854 mutex_unlock(&bmls_lock);
855
856 DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
857
858 return 0;
859}
860
861static int bml_flush(struct mtd_blktrans_dev *dev)
862{
863 struct bml_dev *bmldev = container_of(dev, struct bml_dev, mbd);
864
865 mutex_lock(&bmldev->cache_mutex);
866 write_cached_data(bmldev);
867 mutex_unlock(&bmldev->cache_mutex);
868
869 if (dev->mtd->sync)
870 dev->mtd->sync(dev->mtd);
871 return 0;
872}
873
874static void bml_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
875{
876 struct bml_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
877 int i;
878
879 if (!dev)
880 return;
881
882 for (i = 0; i < bml_pdata->nr_parts; ++i)
883 if (!strcmp(mtd->name, bml_pdata->parts[i].name))
884 break;
885
886 if (i == bml_pdata->nr_parts)
887 return;
888
889 if (!mtd->erasesize) {
890 pr_err("mtd-bml: Unspecified eraseblock size for '%s'.\n",
891 mtd->name);
892 return;
893 }
894
895 if (mtd->flags & MTD_NO_ERASE) {
896 pr_err("mtd-bml: Unsupported flag MTD_NO_ERASE for '%s'.\n",
897 mtd->name);
898 return;
899 }
900
901 dev->offset = bml_pdata->parts[i].offset;
902
903 dev->mbd.mtd = mtd;
904 dev->mbd.devnum = mtd->index;
905
906 dev->mbd.size = mtd->size >> 9;
907 dev->mbd.tr = tr;
908
909 if (!(mtd->flags & MTD_WRITEABLE))
910 dev->mbd.readonly = 1;
911
912 if (add_mtd_blktrans_dev(&dev->mbd))
913 kfree(dev);
914}
915
916static void bml_remove_dev(struct mtd_blktrans_dev *dev)
917{
918 struct bml_dev *bmldev = container_of(dev, struct bml_dev, mbd);
919
920 del_mtd_blktrans_dev(dev);
921
922 vfree(bmldev->bad_bitmap);
923 kfree(bmldev);
924}
925
926static struct mtd_blktrans_ops bml_tr = {
927 .name = "bml",
928 .major = 137,
929 .part_bits = 0,
930 .blksize = 512,
931 .open = bml_open,
932 .flush = bml_flush,
933 .release = bml_release,
934 .readsect = bml_readsect,
935 .writesect = bml_writesect,
936 .add_mtd = bml_add_mtd,
937 .remove_dev = bml_remove_dev,
938 .owner = THIS_MODULE,
939};
940
941static int bml_pm_notification(struct notifier_block *nb,
942 unsigned long mode, void *_unused)
943{
944 struct bml_map_entry *entry;
945 struct mtd_info *mtd;
946 int i;
947
948 switch (mode) {
949 case PM_POST_SUSPEND:
950 if (!bml_map_info) {
951 mtd = get_mtd_device_nm("reservoir");
952 if (!mtd)
953 return 0;
954 mtd->lock(mtd, 0, mtd->size);
955 put_mtd_device(mtd);
956 return 0;
957 }
958
959 mtd = bml_map_info->mtd;
960 entry = bml_map_info->table;
961 for (i = 0; i < bml_map_info->length; ++i, ++entry)
962 mtd->unlock(mtd, entry->to_offs, mtd->erasesize);
963 break;
964 }
965
966 return 0;
967}
968
969static struct notifier_block bml_pm_notifier = {
970 .notifier_call = bml_pm_notification,
971};
972
973static int __devinit bml_probe(struct platform_device *pdev)
974{
975 int ret;
976
977 if (pdev->id != -1) {
978 dev_err(&pdev->dev, "Only a single instance is allowed.\n");
979 return -ENODEV;
980 }
981
982 if (!pdev->dev.platform_data) {
983 dev_err(&pdev->dev, "No platform data provided.\n");
984 return -EINVAL;
985 }
986
987 bml_pdata = pdev->dev.platform_data;
988 mutex_init(&bmls_lock);
989
990 register_pm_notifier(&bml_pm_notifier);
991
992 if ((ret = register_mtd_blktrans(&bml_tr)) != 0) {
993 dev_err(&pdev->dev, "Failed to register mtd blktrans.\n");
994 return ret;
995 }
996
997 return 0;
998}
999
1000static int __devexit bml_remove(struct platform_device *pdev)
1001{
1002 deregister_mtd_blktrans(&bml_tr);
1003
1004 unregister_pm_notifier(&bml_pm_notifier);
1005
1006 if (bml_map_info) {
1007 put_mtd_device(bml_map_info->mtd);
1008 vfree(bml_map_info);
1009 bml_map_info = 0;
1010 }
1011
1012 return 0;
1013}
1014
1015static struct platform_driver bml_driver = {
1016 .probe = bml_probe,
1017 .remove = __devexit_p(bml_remove),
1018 .driver = {
1019 .name = "mtd-bml",
1020 },
1021};
1022
1023static int __init init_bml(void)
1024{
1025 return platform_driver_register(&bml_driver);
1026}
1027
1028static void __exit cleanup_bml(void)
1029{
1030 platform_driver_unregister(&bml_driver);
1031}
1032
1033module_init(init_bml);
1034module_exit(cleanup_bml);
1035
1036MODULE_LICENSE("GPL");
1037MODULE_AUTHOR("Tomasz Figa <tomasz.figa at gmail.com>");
1038MODULE_DESCRIPTION("BML over MTD compatibility layer.");