emmc: add dtb backup machinisim
authorRuixuan Li <ruixuan.li@amlogic.com>
Mon, 2 Apr 2018 03:37:27 +0000 (11:37 +0800)
committerYixun Lan <yixun.lan@amlogic.com>
Mon, 9 Apr 2018 06:00:31 +0000 (22:00 -0800)
PD#162119: emmc: add dtb backup machinisim

Change-Id: Ie8fd8f1a72f0e04c2ceacf5338add3c5c3862b84
Signed-off-by: Ruixuan Li <ruixuan.li@amlogic.com>
drivers/amlogic/mmc/emmc_partitions.c

index f804f1d..a6f6180 100755 (executable)
@@ -27,8 +27,7 @@
 #include <linux/cdev.h>
 #include <linux/device.h>
 #include <linux/uaccess.h>
-#include <linux/dma-contiguous.h>
-
+#include <linux/vmalloc.h>
 #include <linux/mmc/emmc_partitions.h>
 #include <linux/amlogic/cpu_version.h>
 #include <linux/amlogic/iomap.h>
 #define                EMMC_BLOCK_SIZE         (0x100)
 #define                MAX_EMMC_BLOCK_SIZE             (128*1024)
 
-static dev_t amlmmc_dtb_no;
-struct cdev amlmmc_dtb;
-struct device *dtb_dev;
-struct class *amlmmc_dtb_class;
-struct mmc_card *card_dtb;
-struct mmc_partitions_fmt *pt_fmt;
-
-/*
- * 2 copies dtb were stored in dtb area.
- * each is 256K.
- * timestamp&checksum are in the tail.
- * |<--------------DTB Area-------------->|
- * |<------DTB1------->|<------DTB2------>|
- */
-
 #define DTB_RESERVE_OFFSET (4 * SZ_1M)
 #define        DTB_BLK_SIZE            (0x200)
 #define        DTB_BLK_CNT                     (512)
@@ -66,6 +50,7 @@ struct mmc_partitions_fmt *pt_fmt;
 #define MAX_TRANS_BLK          (256)
 #define        MAX_TRANS_SIZE          (MAX_TRANS_BLK * DTB_BLK_SIZE)
 #define stamp_after(a, b)   ((int)(b) - (int)(a)  < 0)
+
 struct aml_dtb_rsv {
        u8 data[DTB_BLK_SIZE*DTB_BLK_CNT - 4*sizeof(unsigned int)];
        unsigned int magic;
@@ -79,7 +64,14 @@ struct aml_dtb_info {
        u8 valid[2];
 };
 
+static dev_t amlmmc_dtb_no;
+struct cdev amlmmc_dtb;
+struct device *dtb_dev;
+struct class *amlmmc_dtb_class;
+struct mmc_card *card_dtb;
 static struct aml_dtb_info dtb_infos = {{0, 0}, {0, 0} };
+struct mmc_partitions_fmt *pt_fmt;
+
 /* dtb read&write operation with backup updates */
 static unsigned int _calc_dtb_checksum(struct aml_dtb_rsv *dtb)
 {
@@ -92,6 +84,7 @@ static unsigned int _calc_dtb_checksum(struct aml_dtb_rsv *dtb)
        buffer = (unsigned int *) dtb;
        while (i < size)
                checksum += buffer[i++];
+
        return checksum;
 }
 
@@ -105,6 +98,32 @@ static int _verify_dtb_checksum(struct aml_dtb_rsv *dtb)
        return !(checksum == dtb->checksum);
 }
 
+static int _dtb_write(struct mmc_card *mmc,
+                               int blk, unsigned char *buf)
+{
+       int ret = 0;
+       unsigned char *src = NULL;
+       int bit = mmc->csd.read_blkbits;
+       int cnt = CONFIG_DTB_SIZE >> bit;
+
+       src = (unsigned char *)buf;
+
+       mmc_claim_host(mmc->host);
+       do {
+               ret = mmc_write_internal(mmc, blk, MAX_TRANS_BLK, src);
+               if (ret) {
+                       pr_err("%s: save dtb error", __func__);
+                       ret = -EFAULT;
+                       break;
+               }
+               blk += MAX_TRANS_BLK;
+               cnt -= MAX_TRANS_BLK;
+               src = (unsigned char *)buf + MAX_TRANS_SIZE;
+       } while (cnt != 0);
+       mmc_release_host(mmc->host);
+
+       return ret;
+}
 
 static int _dtb_read(struct mmc_card *mmc,
                                int blk, unsigned char *buf)
@@ -139,17 +158,14 @@ static int _dtb_init(struct mmc_card *mmc)
        int cpy = 1, valid = 0;
        int bit = mmc->csd.read_blkbits;
        int blk;
-       unsigned int pgcnt;
-       struct page *page = NULL;
 
-       pgcnt = PAGE_ALIGN(CONFIG_DTB_SIZE) >> PAGE_SHIFT;
 
-       page = dma_alloc_from_contiguous(NULL,
-                       pgcnt, get_order(CONFIG_DTB_SIZE));
-
-       if (!page)
+       /* malloc a buffer. */
+       dtb = kmalloc(CONFIG_DTB_SIZE, GFP_KERNEL);
+       if (dtb == NULL) {
+               /*pr_err("%s: malloc buf failed", __func__);*/
                return -ENOMEM;
-       dtb = page_address(page);
+       }
 
        /* read dtb2 1st, for compatibility without checksum. */
        while (cpy >= 0) {
@@ -172,56 +188,56 @@ static int _dtb_init(struct mmc_card *mmc)
        }
        pr_info("total valid %d\n", valid);
 
-       dma_release_from_contiguous(NULL, page, pgcnt);
+       kfree(dtb);
 
        return ret;
 }
 
-int amlmmc_dtb_write(struct mmc_card *card,
+int amlmmc_dtb_write(struct mmc_card *mmc,
                unsigned char *buf, int len)
 {
-       int ret = 0, start_blk, size, blk_cnt;
-       int bit = card->csd.read_blkbits;
-       unsigned char *src = NULL;
-       unsigned char *buffer = NULL;
+       int ret = 0, blk;
+       int bit = mmc->csd.read_blkbits;
+       int cpy, valid;
+       struct aml_dtb_rsv *dtb = (struct aml_dtb_rsv *) buf;
+       struct aml_dtb_info *info = &dtb_infos;
 
        if (len > CONFIG_DTB_SIZE) {
                pr_err("%s dtb data len too much", __func__);
                return -EFAULT;
        }
-       start_blk = MMC_DTB_PART_OFFSET;
-       if (start_blk < 0) {
-               ret = -EINVAL;
-               return ret;
-       }
-
-       buffer = kmalloc(DTB_CELL_SIZE, GFP_KERNEL);
-       if (buffer == NULL) {
-               pr_err("%s kmalloc dtb cell failed\n", __func__);
-               buffer = kmalloc(DTB_CELL_SIZE, GFP_DMA);
-               if (buffer == NULL) {
-                       pr_err("%s retry kmalloc dtb cell failed\n", __func__);
-                       return -ENOMEM;
-               }
+       /* set info */
+       valid = info->valid[0] + info->valid[1];
+       if (valid == 0)
+               dtb->timestamp = 0;
+       else if (valid == 1) {
+               dtb->timestamp = 1 + info->stamp[info->valid[0]?0:1];
+       } else {
+               /* both are valid */
+               if (info->stamp[0] != info->stamp[1]) {
+                       pr_info("timestamp are not same %d:%d\n",
+                               info->stamp[0], info->stamp[1]);
+                       dtb->timestamp = 1 +
+                               stamp_after(info->stamp[1], info->stamp[0]) ?
+                               info->stamp[1]:info->stamp[0];
+               } else
+                       dtb->timestamp = 1 + info->stamp[0];
        }
-       start_blk >>= bit;
-       size = CONFIG_DTB_SIZE;
-       blk_cnt = size>>bit;
-       src = (unsigned char *)buffer;
-       while (blk_cnt != 0) {
-               memcpy(src, buf, DTB_CELL_SIZE);
-               ret = mmc_write_internal(card, start_blk, (DTB_CELL_SIZE>>bit), src);
-               if (ret) {
-                       pr_err("%s: save dtb error", __func__);
-                       ret = -EFAULT;
-                       kfree(buffer);
-                       return ret;
-               }
-               start_blk += (DTB_CELL_SIZE>>bit);
-               blk_cnt -= (DTB_CELL_SIZE>>bit);
-               buf += DTB_CELL_SIZE;
+       /*setting version and magic*/
+       dtb->version = 1; /* base version */
+       dtb->magic = 0x00447e41; /*A~D\0*/
+       dtb->checksum = _calc_dtb_checksum(dtb);
+       pr_info("stamp %d, checksum 0x%x, version %d, magic %s\n",
+               dtb->timestamp, dtb->checksum,
+               dtb->version, (char *)&dtb->magic);
+       /* write down... */
+       for (cpy = 0; cpy < DTB_COPIES; cpy++) {
+               blk = ((get_reserve_partition_off_from_tbl()
+                                       + DTB_RESERVE_OFFSET) >> bit)
+                       + cpy * DTB_BLK_CNT;
+               ret |= _dtb_write(mmc, blk, buf);
        }
-       kfree(buffer);
+
        return ret;
 }
 
@@ -290,8 +306,6 @@ ssize_t mmc_dtb_read(struct file *file,
        unsigned char *dtb_ptr = NULL;
        ssize_t read_size = 0;
        int ret = 0;
-       unsigned int pgcnt;
-       struct page *page = NULL;
 
        if (*ppos == CONFIG_DTB_SIZE)
                return 0;
@@ -301,13 +315,9 @@ ssize_t mmc_dtb_read(struct file *file,
                return -EFAULT;
        }
 
-       pgcnt = PAGE_ALIGN(CONFIG_DTB_SIZE) >> PAGE_SHIFT;
-
-       page = dma_alloc_from_contiguous(NULL,
-                       pgcnt, get_order(CONFIG_DTB_SIZE));
-       if (!page)
+       dtb_ptr = vmalloc(CONFIG_DTB_SIZE);
+       if (dtb_ptr == NULL)
                return -ENOMEM;
-       dtb_ptr = page_address(page);
 
        mmc_claim_host(card_dtb->host);
        ret = amlmmc_dtb_read(card_dtb,
@@ -326,7 +336,8 @@ ssize_t mmc_dtb_read(struct file *file,
        *ppos += read_size;
 
 exit:
-       dma_release_from_contiguous(NULL, page, pgcnt);
+       mmc_release_host(card_dtb->host);
+       vfree(dtb_ptr);
        return read_size;
 }
 
@@ -337,8 +348,6 @@ ssize_t mmc_dtb_write(struct file *file,
        unsigned char *dtb_ptr = NULL;
        ssize_t write_size = 0;
        int ret = 0;
-       unsigned int pgcnt = PAGE_ALIGN(CONFIG_DTB_SIZE) >> PAGE_SHIFT;
-       struct page *page = NULL;
 
        if (*ppos == CONFIG_DTB_SIZE)
                return 0;
@@ -348,11 +357,11 @@ ssize_t mmc_dtb_write(struct file *file,
                return -EFAULT;
        }
 
-       page = dma_alloc_from_contiguous(NULL,
-                       pgcnt, get_order(CONFIG_DTB_SIZE));
-       if (!page)
+       dtb_ptr = kmalloc(CONFIG_DTB_SIZE, GFP_KERNEL);
+       if (dtb_ptr == NULL)
                return -ENOMEM;
-       dtb_ptr = page_address(page);
+
+       mmc_claim_host(card_dtb->host);
 
        if ((*ppos + count) > CONFIG_DTB_SIZE)
                write_size = CONFIG_DTB_SIZE - *ppos;
@@ -371,7 +380,8 @@ ssize_t mmc_dtb_write(struct file *file,
 
        *ppos += write_size;
 exit:
-       dma_release_from_contiguous(NULL, page, pgcnt);
+       mmc_release_host(card_dtb->host);
+       kfree(dtb_ptr);
        return write_size;
 }
 
@@ -390,7 +400,6 @@ static const struct file_operations dtb_ops = {
 int amlmmc_dtb_init(struct mmc_card *card)
 {
        int ret = 0;
-
        card_dtb = card;
        pr_info("%s: register dtb chardev", __func__);
 
@@ -528,6 +537,10 @@ unsigned int mmc_capacity(struct mmc_card *card)
 static int mmc_transfer(struct mmc_card *card, unsigned int dev_addr,
                unsigned int blocks, void *buf, int write)
 {
+       u8 original_part_config;
+       u8 user_part_number = 0;
+       u8 cur_part_number;
+       bool switch_partition = false;
        unsigned int size;
        struct scatterlist sg;
        struct mmc_request mrq = {0};
@@ -535,7 +548,21 @@ static int mmc_transfer(struct mmc_card *card, unsigned int dev_addr,
        struct mmc_command stop = {0};
        struct mmc_data data = {0};
        int ret;
+       cur_part_number = card->ext_csd.part_config
+               &EXT_CSD_PART_CONFIG_ACC_MASK;
+       if (cur_part_number != user_part_number) {
+               switch_partition = true;
+               original_part_config = card->ext_csd.part_config;
+               cur_part_number = original_part_config
+                       &(~EXT_CSD_PART_CONFIG_ACC_MASK);
+               ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                               EXT_CSD_PART_CONFIG, cur_part_number,
+                               card->ext_csd.part_time);
+               if (ret)
+                       return ret;
 
+               card->ext_csd.part_config = cur_part_number;
+       }
        if ((dev_addr + blocks) >= mmc_capacity(card)) {
                pr_info("[%s] %s range exceeds device capacity!\n",
                                __func__, write?"write":"read");
@@ -556,6 +583,15 @@ static int mmc_transfer(struct mmc_card *card, unsigned int dev_addr,
        mmc_wait_for_req(card->host, &mrq);
 
        ret = mmc_check_result(&mrq);
+       if (switch_partition == true) {
+               ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                               EXT_CSD_PART_CONFIG, original_part_config,
+                               card->ext_csd.part_time);
+               if (ret)
+                       return ret;
+               card->ext_csd.part_config = original_part_config;
+       }
+
        return ret;
 }