summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/mtd/mtdswap.c
diff options
context:
space:
mode:
Diffstat (limited to 'ANDROID_3.4.5/drivers/mtd/mtdswap.c')
-rw-r--r--ANDROID_3.4.5/drivers/mtd/mtdswap.c1109
1 files changed, 0 insertions, 1109 deletions
diff --git a/ANDROID_3.4.5/drivers/mtd/mtdswap.c b/ANDROID_3.4.5/drivers/mtd/mtdswap.c
deleted file mode 100644
index 1435f880..00000000
--- a/ANDROID_3.4.5/drivers/mtd/mtdswap.c
+++ /dev/null
@@ -1,1109 +0,0 @@
-/*++
-/some descriptions of this software.
-Copyright ©2014 WonderMediaTechnologies, Inc.
-This program is free software: you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation, either version 2 of the License, or(at your option) any
-later version.
-
-This program is distributed in the hope that it will be useful,but WITHOUT
-ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESSFOR A PARTICULAR PURPOSE. See
-the GNU General Public License for more details.You should have received
-a copy of the GNU General Public License along with this program. If not,
-see <http://www.gnu.org/licenses/>.
-WonderMediaTechnologies, Inc.
-4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
---*/
-
-/*
- * Swap block device support for MTDs
- * Turns an MTD device into a swap device with block wear leveling
- *
- * Copyright 漏 2007,2011 Nokia Corporation. All rights reserved.
- *
- * Authors: Jarkko Lavinen <jarkko.lavinen@nokia.com>
- *
- * Based on Richard Purdie's earlier implementation in 2007. Background
- * support and lock-less operation written by Adrian Hunter.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- */
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/blktrans.h>
-#include <linux/kthread.h>
-#include <linux/blkdev.h>
-#include <linux/rbtree.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/genhd.h>
-#include <linux/swap.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/device.h>
-#include <linux/math64.h>
-#include <linux/random.h>
-#include <linux/suspend.h>
-
-#define MTDSWAP_VERSION "1.0"
-
-#define MTDSWAP_SECTOR_SIZE 4096
-#define MTDSWAP_SECTOR_SHIFT 12
-
-#define STATUS_FREE (0xff)
-#define STATUS_USED (0x55)
-
-#define MTDSWAP_IO_RETRIES 3
-
-int suspend_counts __nosavedata;
-int eba_tbl[1024] __nosavedata;
-
-enum {
- MTDSWAP_SCANNED_FREE,
- MTDSWAP_SCANNED_USED,
- MTDSWAP_SCANNED_BAD,
-};
-
-struct mtdswap_oobdata {
- unsigned int magic;
- unsigned int erase_count;
- unsigned int lnum;
- unsigned int seq_number;
-};
-
-struct mtdswap_eb {
-
- union {
- struct rb_node rb;
- struct rb_root *root;
- } u;
-
- unsigned int erase_count;
- unsigned int lnum;
- unsigned int pnum;
- unsigned int seq_number;
-};
-
-struct mtdswap_dev {
-
- struct mtd_blktrans_dev *mbd;
- struct mtd_info *mtd; /* mtd device */
- struct device *dev;
- struct notifier_block pm_notifier;
-
- struct mtdswap_eb *eb_data;
- spinlock_t mtdswap_lock;
- struct rb_root used;
- struct rb_root free;
-
- unsigned int pblocks;
- unsigned int badblock;
- unsigned int freeblock;
- unsigned int usedblock;
-
- unsigned int page_per_block;
- unsigned int sector_per_block;
- unsigned int mean_count;
- unsigned int seq_number;
-
- struct mutex cache_mutex;
- unsigned char *cache_data;
- unsigned long cache_offset;
- unsigned int cache_size;
- unsigned char *oob_data;
- enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
-
-};
-
-#define MTDSWAP_MBD_TO_MTDSWAP(dev) ((struct mtdswap_dev *)dev->priv)
-
-unsigned char partitions[32] = "16";
-
-extern char resume_file[64]; /*defined in hibernation.c*/
-static char *parts = NULL; /* str: mtd part number defined by resume_file */
-static unsigned long part = 0; /* mtd part number defined by resume_file */
-
-static DEFINE_MUTEX(mtdswap_lock);
-
-extern void print_nand_buffer(char *value, unsigned int length);
-
-static void mtdswap_cleanup(struct mtdswap_dev *d);
-static int mtdswap_check_resume(struct mtdswap_dev *d);
-static int swap_tree_add(struct mtdswap_eb *eb, struct rb_root *root);
-static loff_t mtdswap_eb_offset(struct mtdswap_dev *d, struct mtdswap_eb *eb);
-
-void print_mapping_table(struct mtdswap_dev *d)
-{
- int i;
- for (i = 0; i < d->pblocks; i++)
- printk("\n After checking, lnum%d pnum%d", i, eba_tbl[i]);
-}
-
-static void swaptree_destroy(struct rb_root *root)
-{
- struct rb_node *rb;
- struct mtdswap_eb *e;
-
- rb = root->rb_node;
- while (rb) {
- if (rb->rb_left)
- rb = rb->rb_left;
- else if (rb->rb_right)
- rb = rb->rb_right;
- else {
- e = rb_entry(rb, struct mtdswap_eb, u.rb);
-
- rb = rb_parent(rb);
- if (rb) {
- if (rb->rb_left == &e->u.rb)
- rb->rb_left = NULL;
- else
- rb->rb_right = NULL;
- }
- /* kfree(e); */
- }
- }
-}
-
-static void mtdswap_cleanup(struct mtdswap_dev *d)
-{
- swaptree_destroy(&d->used);
- swaptree_destroy(&d->free);
- vfree(d->eb_data);
- vfree(d->cache_data);
- vfree(d->oob_data);
-}
-
-static unsigned int get_logic_block(struct mtdswap_dev *d, unsigned int pos)
-{
- return pos / d->mtd->erasesize;
-}
-
-static unsigned int get_logic_page(struct mtdswap_dev *d, unsigned int pos)
-{
- return pos % d->mtd->erasesize;
-}
-
-struct mtdswap_eb *find_mtdswap_eb(struct rb_root *root, int diff)
-{
-
- struct rb_node *p;
- struct mtdswap_eb *e;
-
- e = rb_entry(rb_first(root), struct mtdswap_eb, u.rb);
-
- p = root->rb_node;
-
- while (p) {
- struct mtdswap_eb *e1;
-
- e1 = rb_entry(p, struct mtdswap_eb, u.rb);
- if (e1->erase_count > diff)
- p = p->rb_left;
- else {
- p = p->rb_right;
- e = e1;
- }
- }
- return e;
-}
-
-static int find_new_block(struct mtdswap_dev *d, int lnum)
-{
- /* first we find block from free tree */
- int key = 0;
- struct mtdswap_eb *eb;
-
- d->seq_number++;
- eb = find_mtdswap_eb(&d->free, key);
-
- if (eb == NULL) {
- eb = find_mtdswap_eb(&d->used, key);
- if (eb == NULL)
- return -1;
- rb_erase(&eb->u.rb, &d->used);
- eb->erase_count++;
- eb->lnum = lnum;
- eb->seq_number = d->seq_number;
-
- } else {
- rb_erase(&eb->u.rb, &d->free);
- if (eb->erase_count == 0)
- eb->erase_count = d->mean_count;
- eb->lnum = lnum;
- eb->seq_number = d->seq_number;
- }
- eba_tbl[lnum] = eb->pnum;
- return eb->pnum;
-}
-
-static int mtdswap_handle_badblock(struct mtdswap_dev *d, struct mtdswap_eb *eb)
-{
- int ret;
- loff_t offset;
-
- if (!mtd_can_have_bb(d->mtd))
- return 1;
-
- offset = mtdswap_eb_offset(d, eb);
- dev_warn(d->dev, "Marking bad block at %08llx\n", offset);
- ret = mtd_block_markbad(d->mtd, offset);
- if (ret) {
- dev_warn(d->dev, "Mark block bad failed for block at %08llx "
- "error %d\n", offset, ret);
- return ret;
- }
-
- return 1;
-
-}
-
-static int swap_erase(struct mtdswap_dev *d, struct erase_info *erase)
-{
- struct mtd_info *mtd = d->mtd;
- struct mtdswap_eb *eb;
- unsigned long pos = erase->addr;
- int lnum = get_logic_block(d, pos);
- int page = get_logic_page(d, pos);
- int pnum, ret = 0, retries = 0;
-
- if (eba_tbl[lnum] != -1) {
- eb = d->eb_data + eba_tbl[lnum];
- spin_lock(&d->mtdswap_lock);
- swap_tree_add(eb, &d->used);
- spin_unlock(&d->mtdswap_lock);
- }
-
-RETRY:
- spin_lock(&d->mtdswap_lock);
- pnum = find_new_block(d, lnum);
- /*printk("\n lnum %d -> %d", lnum, pnum); */
- spin_unlock(&d->mtdswap_lock);
- if (pnum == -1)
- return -EIO;
-
- eb = d->eb_data + pnum;
- erase->addr = pnum * mtd->erasesize + page;
-
- ret = mtd_erase(mtd, erase);
-
- if (ret) {
- mtdswap_handle_badblock(d, eb);
- retries++;
- if (retries > MTDSWAP_IO_RETRIES)
- return -EIO;
- goto RETRY;
- }
- return 0;
-}
-
-static int mtdswap_write_marker(struct mtdswap_dev *d, struct mtdswap_eb *eb,
- loff_t offset, size_t len, unsigned char *buf)
-{
- struct mtdswap_oobdata *data;
- struct mtd_info *mtd = d->mtd;
- int ret;
- struct mtd_oob_ops ops;
-
- data = (struct mtdswap_oobdata *)d->oob_data;
- ops.len = ((len >= mtd->writesize) ? mtd->writesize : len);
- ops.ooblen = 16;
- ops.oobbuf = d->oob_data;
- ops.ooboffs = 0;
- ops.datbuf = buf;
- ops.mode = MTD_OPS_AUTO_OOB;
-
- data->magic = cpu_to_le32(STATUS_USED);
- data->erase_count = cpu_to_le32(eb->erase_count);
- data->lnum = cpu_to_le32(eb->lnum);
- data->seq_number = cpu_to_le32(eb->seq_number);
-
- ret = mtd_write_oob(mtd, offset, &ops);
-
- return ret;
-}
-
-static int swap_write(struct mtdswap_dev *d, unsigned long pos, size_t len,
- size_t *retlen, unsigned char *buf)
-{
- struct mtd_info *mtd = d->mtd;
- int lnum = get_logic_block(d, pos);
- int page = get_logic_page(d, pos);
- int pnum = eba_tbl[lnum];
- unsigned long addr = pnum * mtd->erasesize + page;
- struct mtdswap_eb *eb = d->eb_data + pnum;
- int ret;
-
- *retlen = len;
- /* First, write datbuf and oobbuf */
- ret = mtdswap_write_marker(d, eb, addr, len, buf);
- if (ret) {
- mtdswap_handle_badblock(d, eb);
- return ret;
- }
- /* Second, just write databuf */
- len -= mtd->writesize;
- if (len <= 0)
- return 0;
- ret =
- mtd_write(mtd, addr + mtd->writesize, len, retlen,
- buf + mtd->writesize);
- /*printk("\nwrite data to %d, %s", pnum, current->comm); */
- if (ret) {
- mtdswap_handle_badblock(d, eb);
- return ret;
- }
- *retlen += mtd->writesize;
-
- return ret;
-}
-
-static int swap_read(struct mtdswap_dev *d, unsigned long pos, size_t len,
- size_t *retlen, unsigned char *buf)
-{
- struct mtd_info *mtd = d->mtd;
- int lnum = get_logic_block(d, pos);
- int page = get_logic_page(d, pos);
- int pnum = eba_tbl[lnum];
- unsigned long addr = pnum * mtd->erasesize + page;
- /*
- printk("\nread data from pos 0x%lx, lnum %d, pnum%d page%d",
- pos, lnum, pnum, page);
- */
- if (pnum == -1) {
- *retlen = len;
- return 0;
- }
-
- return mtd_read(mtd, addr, len, retlen, buf);
-}
-
-static int swap_read_oob(struct mtdswap_dev *d, loff_t from,
- struct mtd_oob_ops *ops)
-{
- int ret = mtd_read_oob(d->mtd, from, ops);
-
- return ret;
-}
-
-static void erase_callback(struct erase_info *done)
-{
- wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv;
- wake_up(wait_q);
-}
-
-static int erase_write(struct mtdswap_dev *d, unsigned long pos,
- int len, unsigned char *buf)
-{
- struct erase_info erase;
- struct mtd_info *mtd = d->mtd;
- DECLARE_WAITQUEUE(wait, current);
- wait_queue_head_t wait_q;
- size_t retlen;
- int ret, retries = 0;
- /*
- * First, let's erase the flash block.
- */
-#if 0
- if (pos == 0x0)
- printk("\n Update Swap Header!");
-#endif
-RETRY:
- init_waitqueue_head(&wait_q);
- erase.mtd = mtd;
- erase.callback = erase_callback;
- erase.len = len;
- erase.addr = pos;
- erase.priv = (u_long) & wait_q;
-
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&wait_q, &wait);
- ret = swap_erase(d, &erase);
- if (ret) {
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&wait_q, &wait);
- return ret;
- }
-
- schedule(); /* Wait for erase to finish. */
- remove_wait_queue(&wait_q, &wait);
- /*
- * Next, write the data to flash.
- */
-
- ret = swap_write(d, pos, len, &retlen, buf);
- if (ret) {
- retries++;
- if (retries > MTDSWAP_IO_RETRIES)
- return -EIO;
- goto RETRY;
- }
- if (retlen != len)
- return -EIO;
- return 0;
-}
-
-static int write_cached_data(struct mtdswap_dev *d)
-{
- int ret;
- if (d->cache_state != STATE_DIRTY)
- return 0;
-
- ret = erase_write(d, d->cache_offset, d->cache_size, d->cache_data);
- if (ret)
- return ret;
- d->cache_state = STATE_EMPTY;
- return 0;
-}
-
-static int do_cached_write(struct mtdswap_dev *d, unsigned long pos,
- unsigned int len, unsigned char *buf)
-{
- unsigned int sect_size = d->cache_size;
- size_t retlen;
- int ret;
- /* print_nand_buffer(buf, len); */
- while (len > 0) {
- unsigned long sect_start = (pos / sect_size) * sect_size;
- unsigned int offset = pos - sect_start;
- unsigned int size = sect_size - offset;
- if (size > len)
- size = len;
- if (size == sect_size) {
- ret = erase_write(d, pos, size, buf);
- if (ret)
- return ret;
- } else {
- if (d->cache_state == STATE_DIRTY &&
- d->cache_offset != sect_start) {
- mutex_lock(&d->cache_mutex);
- ret = write_cached_data(d);
- mutex_unlock(&d->cache_mutex);
- if (ret)
- return ret;
- }
-
- if (d->cache_state == STATE_EMPTY ||
- d->cache_offset != sect_start) {
- d->cache_state = STATE_EMPTY;
- ret = swap_read(d, sect_start, sect_size,
- &retlen, d->cache_data);
- if (ret)
- return ret;
-
- if (retlen != sect_size)
- return -EIO;
-
- d->cache_offset = sect_start;
- d->cache_state = STATE_CLEAN;
- }
- memcpy(d->cache_data + offset, buf, size);
- d->cache_state = STATE_DIRTY;
- }
- buf += size;
- pos += size;
- len -= size;
- }
- return 0;
-}
-
-static int do_cached_read(struct mtdswap_dev *d, unsigned long pos,
- int len, char *buf)
-{
- unsigned int sect_size = d->cache_size;
- size_t retlen;
- int ret;
- /* printk("\n Read data from pos 0x%lx, len 0x%x", pos, len); */
- mutex_lock(&d->cache_mutex);
- while (len > 0) {
-
- unsigned long sect_start = (pos / sect_size) * sect_size;
- unsigned int offset = pos - sect_start;
- unsigned int size = sect_size - offset;
-
- if (size > len)
- size = len;
- if (d->cache_state != STATE_EMPTY &&
- d->cache_offset == sect_start) {
- memcpy(buf, d->cache_data + offset, size);
- } else {
- ret = swap_read(d, pos, size, &retlen, buf);
- if (ret)
- return ret;
- if (retlen != size)
- return -EIO;
- }
- /* print_nand_buffer(buf, len); */
- buf += size;
- pos += size;
- len -= size;
- }
-
- mutex_unlock(&d->cache_mutex);
- return 0;
-}
-
-static int mtdswap_flush(struct mtd_blktrans_dev *dev)
-{
- struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev);
- mutex_lock(&d->cache_mutex);
- write_cached_data(d);
- mutex_unlock(&d->cache_mutex);
- mtd_sync(d->mtd);
- return 0;
-}
-
-static int mtdswap_readsect(struct mtd_blktrans_dev *dev, unsigned long block,
- char *buf)
-{
- struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev);
-
- if (likely(dev->mtd->writesize >= MTDSWAP_SECTOR_SIZE))
- return do_cached_read(d, block << MTDSWAP_SECTOR_SHIFT,
- MTDSWAP_SECTOR_SIZE, buf);
-
- return do_cached_read(d, block << 9, 512, buf);
-}
-
-static int mtdswap_writesect(struct mtd_blktrans_dev *dev, unsigned long block,
- char *buf)
-{
-
- struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev);
- if (likely(dev->mtd->writesize >= MTDSWAP_SECTOR_SIZE))
- return do_cached_write(d, block << MTDSWAP_SECTOR_SHIFT,
- MTDSWAP_SECTOR_SIZE, buf);
-
- return do_cached_write(d, block << 9, 512, buf);
-}
-
-static void mtdswap_remove_dev(struct mtd_blktrans_dev *dev)
-{
- struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev);
- del_mtd_blktrans_dev(dev);
- mtdswap_cleanup(d);
- kfree(d);
-}
-
-static loff_t mtdswap_eb_offset(struct mtdswap_dev *d, struct mtdswap_eb *eb)
-{
- return (loff_t) (eb - d->eb_data) * d->mtd->erasesize;
-}
-
-static int mtdswap_read_markers(struct mtdswap_dev *d, struct mtdswap_eb *eb)
-{
- struct mtdswap_oobdata *data;
- int ret;
- loff_t offset;
- struct mtd_oob_ops ops;
-
- offset = mtdswap_eb_offset(d, eb);
- if (mtd_can_have_bb(d->mtd) && mtd_block_isbad(d->mtd, offset)) {
- d->badblock++;
- return MTDSWAP_SCANNED_BAD;
- }
-
- ops.ooblen = 16;
- ops.oobbuf = d->oob_data;
- ops.ooboffs = 0;
- ops.datbuf = NULL;
- ops.mode = MTD_OPS_AUTO_OOB;
- ret = swap_read_oob(d, offset, &ops);
- data = (struct mtdswap_oobdata *)d->oob_data;
-
- if (le32_to_cpu(data->magic) == STATUS_USED) {
- eb->erase_count = le32_to_cpu(data->erase_count);
- eb->lnum = le32_to_cpu(data->lnum);
- eb->seq_number = le32_to_cpu(data->seq_number);
- d->usedblock++;
- d->mean_count += eb->erase_count;
-
- if (eb->seq_number > d->seq_number)
- d->seq_number = eb->seq_number;
- ret = MTDSWAP_SCANNED_USED;
- } else {
- eb->erase_count = 0;
- d->freeblock++;
- ret = MTDSWAP_SCANNED_FREE;
- }
- eb->pnum = (unsigned int)(eb - d->eb_data);
- return ret;
-
-}
-
-static int swap_tree_add(struct mtdswap_eb *eb, struct rb_root *root)
-{
- struct rb_node **p, *parent = NULL;
-
- p = &root->rb_node;
- while (*p) {
- struct mtdswap_eb *eb1;
- parent = *p;
- eb1 = rb_entry(parent, struct mtdswap_eb, u.rb);
-
- if (eb->erase_count < eb1->erase_count)
- p = &(*p)->rb_left;
- else if (eb->erase_count > eb1->erase_count)
- p = &(*p)->rb_right;
- else {
- if (eb->pnum == eb1->pnum)
- return 0;
-
- if (eb->pnum < eb1->pnum)
- p = &(*p)->rb_left;
- else
- p = &(*p)->rb_right;
- }
-
- }
-
- rb_link_node(&eb->u.rb, parent, p);
- rb_insert_color(&eb->u.rb, root);
-
- return 0;
-}
-
-static int build_mapping_table(struct mtdswap_dev *d, struct mtdswap_eb *eb)
-{
-
- int pnum;
- struct mtdswap_eb *eb1;
- pnum = eba_tbl[eb->lnum];
-
- if (pnum >= 0) {
- eb1 = d->eb_data + pnum;
- if (eb1->seq_number > eb->seq_number)
- return 0;
- }
-
- eba_tbl[eb->lnum] = eb->pnum;
- return 0;
-}
-
-static int mtdswap_check_counts(struct mtdswap_dev *d)
-{
- return (d->pblocks - d->usedblock - d->freeblock - d->badblock) ? 1 : 0;
-}
-
-static int mtdswap_scan_eblks(struct mtdswap_dev *d, unsigned int need_build)
-{
- int status, i;
- struct mtdswap_eb *eb;
-
- for (i = 0; i < d->pblocks; i++) {
- eb = d->eb_data + i;
- eb->pnum = i;
- status = mtdswap_read_markers(d, eb);
- if (status == MTDSWAP_SCANNED_BAD)
- continue;
- switch (status) {
- case MTDSWAP_SCANNED_FREE:
- spin_lock(&d->mtdswap_lock);
- swap_tree_add(eb, &d->free);
- spin_unlock(&d->mtdswap_lock);
- break;
- case MTDSWAP_SCANNED_USED:
- spin_lock(&d->mtdswap_lock);
- swap_tree_add(eb, &d->used);
- spin_unlock(&d->mtdswap_lock);
- if(need_build)
- build_mapping_table(d, eb);
- break;
- }
- }
-
- if (mtdswap_check_counts(d))
- printk(KERN_CRIT "\n NOTICE: MTDSWAP counts are illegal");
-
- return 0;
-}
-
-#if 0
-static void test_swap(struct mtdswap_dev *d)
-{
- unsigned long start_sector = 0x0;
- unsigned long sector_count = 0;
- unsigned long rand_seed = 544;
- unsigned char write_data = 0;
- unsigned int i;
- int ret;
-
- for (i = 0; i < 10000; i++) {
- /* seed the randome: no seed to freeze the test case */
- srandom32(random32() + i + rand_seed);
-
-/* start_sector = (unsigned long)(random32()%(d->sector_per_block * 64)) & (~(32-1));
- rand_seed = (unsigned long)(random32()%(d->sector_per_block * 64-start_sector));
-*/
- write_data = (unsigned char)(random32() % ((unsigned char)-1));
- sector_count = 1;
-
- /* set data */
- memset(sector_buffer, (unsigned char)write_data, 2097152);
-
- /* write */
-/* ret = ONFM_Write(c, start_sector, sector_count, sector_buffer); */
- ret = do_cached_write(d, start_sector, 2097152, sector_buffer);
-/* ret = erase_write(d, start_sector, 512, sector_buffer); */
- if (ret == 0) {
- /* read and check */
- ret =
- do_cached_read(d, start_sector, 2097152,
- read_sector_buffer);
- if (ret == 0) {
- ret =
- memcmp(sector_buffer, read_sector_buffer,
- 2097152);
- }
- }
-
- /* print */
- if (ret != 0) {
- printk
- ("\n%d:*FAIL* start address: %d, sector count: %d, data: %d",
- i, start_sector, sector_count, write_data);
- break;
- } else {
- printk
- ("\n%d-PASS. start address: %d, sector count: %d, data: %d.",
- i, start_sector, sector_count, write_data);
- start_sector += 0x200;
- }
- }
-}
-#endif
-
-static int mtdswap_check_resume(struct mtdswap_dev *d)
-{
- struct mtd_info *mtd = d->mtd;
- struct mtdswap_eb *eb;
-
- spin_lock(&d->mtdswap_lock);
- swaptree_destroy(&d->used);
- swaptree_destroy(&d->free);
- spin_unlock(&d->mtdswap_lock);
- d->mean_count = 1;
- d->used = d->free = RB_ROOT;
- d->badblock = d->freeblock = d->usedblock = 0;
- memset(d->eb_data, 0x00, sizeof(struct mtdswap_eb) * d->pblocks);
-
- mutex_lock(&d->cache_mutex);
- d->cache_size = mtd->erasesize;
- d->cache_state = STATE_EMPTY;
- d->cache_offset = -1;
- memset(d->cache_data, 0xFF, mtd->erasesize);
- mutex_unlock(&d->cache_mutex);
-
- memset(d->oob_data, 0xFF, mtd->oobsize);
- mtdswap_scan_eblks(d, 0);
- eb = d->eb_data + eba_tbl[0];
- spin_lock(&d->mtdswap_lock);
- rb_erase(&eb->u.rb, &d->used);
- spin_unlock(&d->mtdswap_lock);
-#if 0
- for (i = 0; i < d->pblocks; i++) {
- if (eba_tbl[i] != -1) {
- eb = d->eb_data + eba_tbl[i];
- printk("\n Remove %d from used tree", eb->pnum);
- rb_erase(&eb->u.rb, &d->used);
- }
- }
-#endif
- if (d->usedblock)
- d->mean_count = d->mean_count / d->usedblock;
- return 0;
-}
-
-static int mtdswap_check_suspend(struct mtdswap_dev *d)
-{
- struct mtd_info *mtd = d->mtd;
- struct mtdswap_eb *eb;
- int i;
-
- spin_lock(&d->mtdswap_lock);
- swaptree_destroy(&d->used);
- swaptree_destroy(&d->free);
- spin_unlock(&d->mtdswap_lock);
-
- d->mean_count = 1;
- d->used = d->free = RB_ROOT;
- d->badblock = d->freeblock = d->usedblock = 0;
- memset(d->eb_data, 0x00, sizeof(struct mtdswap_eb) * d->pblocks);
- mutex_lock(&d->cache_mutex);
- d->cache_size = mtd->erasesize;
- d->cache_state = STATE_EMPTY;
- d->cache_offset = -1;
- memset(d->cache_data, 0xFF, mtd->erasesize);
- mutex_unlock(&d->cache_mutex);
- memset(d->oob_data, 0xFF, mtd->oobsize);
-
- if(!suspend_counts) {
- for (i = 1; i < d->pblocks; i++)
- eba_tbl[i] = -1;
- }
- mtdswap_scan_eblks(d, 0);
- eb = d->eb_data + eba_tbl[0];
- spin_lock(&d->mtdswap_lock);
- rb_erase(&eb->u.rb, &d->used);
- spin_unlock(&d->mtdswap_lock);
- suspend_counts = 1;
-#if 0
- for (i = 0; i < d->pblocks; i++) {
- if (eba_tbl[i] != -1) {
- eb = d->eb_data + eba_tbl[i];
- rb_erase(&eb->u.rb, &d->used);
- }
- }
-#endif
- if (d->usedblock)
- d->mean_count = d->mean_count / d->usedblock;
- return 0;
-}
-
-static int mtdswap_resume(struct mtdswap_dev *d)
-{
- mtdswap_check_resume(d);
- return 0;
-}
-
-static int mtdswap_suspend(struct mtdswap_dev *d)
-{
- mtdswap_check_suspend(d);
- return 0;
-}
-
-static int swap_power_event(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- struct mtdswap_dev *d =
- container_of(this, struct mtdswap_dev, pm_notifier);
- switch (event) {
- case PM_POST_RESTORE: /* in case hibernation restore fail */
- case PM_POST_HIBERNATION: /* normal case for hibernation finished */
- mtdswap_resume(d);
- break;
- case PM_HIBERNATION_PREPARE:
- mtdswap_suspend(d);
- break;
- case PM_HIBERNATION_FINISH:
- mutex_lock(&d->cache_mutex);
- write_cached_data(d);
- mutex_unlock(&d->cache_mutex);
- break;
- default:
- break;
- }
- return NOTIFY_DONE;
-}
-
-static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks)
-{
- struct mtd_info *mtd = d->mbd->mtd;
- struct mtdswap_eb *eb;
- int i;
-
- d->mtd = mtd;
- d->pblocks = eblocks;
- d->pm_notifier.notifier_call = swap_power_event;
- register_pm_notifier(&d->pm_notifier);
-
- d->page_per_block = mtd->erasesize / mtd->writesize;
- d->sector_per_block = mtd->erasesize >> MTDSWAP_SECTOR_SHIFT;
- d->mean_count = 1;
- d->used = d->free = RB_ROOT;
- spin_lock_init(&d->mtdswap_lock);
- mutex_init(&d->cache_mutex);
-
- d->badblock = d->freeblock = d->usedblock = 0;
-
- d->cache_data = vmalloc(mtd->erasesize);
- d->cache_size = mtd->erasesize;
- d->cache_state = STATE_EMPTY;
- d->cache_offset = -1;
- d->oob_data = vmalloc(mtd->oobsize);
- d->eb_data = vmalloc(sizeof(struct mtdswap_eb) * d->pblocks);
-
- memset(d->eb_data, 0x00, sizeof(struct mtdswap_eb) * d->pblocks);
- memset(d->cache_data, 0xFF, mtd->erasesize);
- memset(d->oob_data, 0xFF, mtd->oobsize);
-
- for (i = 0; i < d->pblocks; i++)
- eba_tbl[i] = -1;
-
- mtdswap_scan_eblks(d, 1);
-
- for (i = 0; i < d->pblocks; i++) {
- if (eba_tbl[i] != -1) {
- eb = d->eb_data + eba_tbl[i];
- rb_erase(&eb->u.rb, &d->used);
- }
- }
-#if 0
- for (i = 0; i < d->pblocks; i++)
- printk("\n lnum%d pnum%d", i, eba_tbl[i]);
-#endif
- if (d->usedblock)
- d->mean_count = d->mean_count / d->usedblock;
- /* test_swap(d); */
-
- return 0;
-}
-
-static int mtdswap_find_mtd(unsigned char *target, unsigned char *source)
-{
- /*extract partition number from string */
- unsigned char *temp;
- unsigned int slen = strlen(source);
- unsigned int tlen=0;
-
- temp = strstr(target, source);
-
- if (temp) {
- tlen = strlen(temp);
- strncpy(partitions, temp + slen, tlen-slen+1);
- /*find mtd = true*/
- return 1;
- }
-
- /*find mtd = false*/
- return 0;
-}
-
-
-static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
-{
- struct mtdswap_dev *d;
- struct mtd_blktrans_dev *mbd_dev;
- struct nand_ecclayout *info;
- unsigned long use_size;
- int eblocks;
-
- if (memcmp(mtd->name, "swap", sizeof("swap"))!=0)
- return;
- if (mtd->index != part){
- printk(KERN_WARNING"\n Find swap partition mtdswap%d != mtdswap%lu\n", mtd->index, part);
- /*replace original resume_file with what we actaully find.*/
- memset(resume_file, 0, sizeof(resume_file));
- strncat(resume_file, "/dev/mtdswap", sizeof("/dev/mtdswap"));
- snprintf(partitions, sizeof(partitions), "%d", mtd->index);
- strncat(resume_file, partitions, sizeof(partitions));
- printk(KERN_WARNING"Replace resume_file As : %s\n", resume_file);
- }
-
- printk(KERN_INFO "Enabling MTD swap on device %d, size %lldMB, ",
- mtd->index, mtd->size / 1024 / 1024);
-
- info = mtd->ecclayout;
-
- use_size = mtd->size;
- eblocks = mtd_div_by_eb(use_size, mtd);
-
- d = kzalloc(sizeof(struct mtdswap_dev), GFP_KERNEL);
-
- if (!d)
- return;
- mbd_dev = kzalloc(sizeof(struct mtd_blktrans_dev), GFP_KERNEL);
- if (!mbd_dev) {
- kfree(d);
- return;
- }
-
- d->mbd = mbd_dev;
- mbd_dev->priv = d;
-
- mbd_dev->mtd = mtd;
- mbd_dev->devnum = mtd->index;
- mbd_dev->size = use_size >> 9;
- mbd_dev->tr = tr;
-
- if (!(mtd->flags & MTD_WRITEABLE))
- mbd_dev->readonly = 1;
-
- if (mtdswap_init(d, eblocks) < 0)
- goto init_failed;
- if (add_mtd_blktrans_dev(mbd_dev) < 0)
- goto cleanup;
- d->dev = disk_to_dev(mbd_dev->disk);
- return;
-
-cleanup:
- mtdswap_cleanup(d);
-
-init_failed:
- kfree(mbd_dev);
- kfree(d);
-}
-
-static int mtdswap_open(struct mtd_blktrans_dev *dev)
-{
- return 0;
-}
-
-static int mtdswap_release(struct mtd_blktrans_dev *dev)
-{
- struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev);
- mutex_lock(&d->cache_mutex);
- write_cached_data(d);
- mutex_unlock(&d->cache_mutex);
- return 0;
-}
-
-static struct mtd_blktrans_ops mtdswap_ops = {
- .name = "mtdswap",
- .major = 0,
- .part_bits = 0,
- .blksize = 512,
- .open = mtdswap_open,
- .flush = mtdswap_flush,
- .release = mtdswap_release,
- .readsect = mtdswap_readsect,
- .writesect = mtdswap_writesect,
- .add_mtd = mtdswap_add_mtd,
- .remove_dev = mtdswap_remove_dev,
- .owner = THIS_MODULE,
-};
-
-static int __init mtdswap_modinit(void)
-{
- /* find if resume_file name contains "mtdswap" */
- int ret = mtdswap_find_mtd(resume_file, "mtdswap");
- if (!ret){
- printk(KERN_WARNING"\n[mtdswap] Resume Partition Is Not mtdswap !!!\n");
- return 0;
- }
- parts = &partitions[0];
- printk(KERN_WARNING"[mtdswap] resume_file:%s, parts=%s\n", resume_file, parts);
- if(kstrtoul(parts, 0, &part) < 0){
- printk(KERN_WARNING"[mtdswap] Invalid MTDSWAP Partition Number!!!\n");
- }
- return register_mtd_blktrans(&mtdswap_ops);
-}
-
-static void __exit mtdswap_modexit(void)
-{
- deregister_mtd_blktrans(&mtdswap_ops);
-}
-
-module_init(mtdswap_modinit);
-module_exit(mtdswap_modexit);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Johnny Liu <johnnyliu@viatech.com.cn>");
-MODULE_DESCRIPTION("Block device access to an MTD suitable for using as "
- "swap space");