mmc: store hwpart in the block device
authorStephen Warren <swarren@nvidia.com>
Mon, 7 Dec 2015 18:38:49 +0000 (11:38 -0700)
committerTom Rini <trini@konsulko.com>
Thu, 14 Jan 2016 02:05:19 +0000 (21:05 -0500)
This will allow us to have multiple block device structs each referring
to the same eMMC device, yet different HW partitions.

For now, there is still a single block device per eMMC device. As before,
this block device always accesses whichever HW partition was most recently
selected. Clients wishing to make use of multiple block devices referring
to different HW partitions can simply take a copy of this block device
once it points at the correct HW partition, and use each one as they wish.
This feature will be used by the next patch.

In the future, perhaps get_device() could be enhanced to return a
dynamically allocated block device struct, to avoid the client needing to
copy it in order to maintain multiple block devices. However, this would
require all users to be updated to free those block device structs at some
point, which is rather a large change.

Most callers of mmc_switch_part() wish to permanently switch the default
MMC block device's HW partition. Enhance mmc_switch_part() so that it does
this. This removes the need for callers to do this. However,
common/env_mmc.c needs to save and restore the current HW partition. Make
it do this more explicitly.

Replace use of mmc_switch_part() with mmc_select_hwpart() in order to
remove duplicate code that skips the call if that HW partition is already
selected.

Signed-off-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
common/cmd_mmc.c
common/env_mmc.c
drivers/dfu/dfu_mmc.c
drivers/mmc/mmc.c
drivers/mmc/mmc_write.c
include/mmc.h
include/part.h

index 6b5c1ac1109eb6e10c27ad7fb88ddd0e8a8fa2f8..1c7156f19c5939867c30d52fdba0ffdcf3583c55 100644 (file)
@@ -312,20 +312,14 @@ static int do_mmcrpmb(cmd_tbl_t *cmdtp, int flag,
                return CMD_RET_FAILURE;
        }
        /* Switch to the RPMB partition */
-       original_part = mmc->part_num;
-       if (mmc->part_num != MMC_PART_RPMB) {
-               if (mmc_switch_part(curr_device, MMC_PART_RPMB) != 0)
-                       return CMD_RET_FAILURE;
-               mmc->part_num = MMC_PART_RPMB;
-       }
+       original_part = mmc->block_dev.part_num;
+       if (mmc_select_hwpart(curr_device, MMC_PART_RPMB) != 0)
+               return CMD_RET_FAILURE;
        ret = cp->cmd(cmdtp, flag, argc, argv);
 
        /* Return to original partition */
-       if (mmc->part_num != original_part) {
-               if (mmc_switch_part(curr_device, original_part) != 0)
-                       return CMD_RET_FAILURE;
-               mmc->part_num = original_part;
-       }
+       if (mmc_select_hwpart(curr_device, original_part) != 0)
+               return CMD_RET_FAILURE;
        return ret;
 }
 #endif
@@ -483,7 +477,7 @@ static int do_mmc_dev(cmd_tbl_t *cmdtp, int flag,
                printf("mmc%d is current device\n", curr_device);
        else
                printf("mmc%d(part %d) is current device\n",
-                      curr_device, mmc->part_num);
+                      curr_device, mmc->block_dev.hwpart);
 
        return CMD_RET_SUCCESS;
 }
index f182749e8b88931ec18075e95653e8c2d397340b..15aa43d5e1628bcc0ab8508c0b36922565bc06f3 100644 (file)
@@ -69,6 +69,8 @@ __weak uint mmc_get_env_part(struct mmc *mmc)
        return CONFIG_SYS_MMC_ENV_PART;
 }
 
+static unsigned char env_mmc_orig_hwpart;
+
 static int mmc_set_env_part(struct mmc *mmc)
 {
        uint part = mmc_get_env_part(mmc);
@@ -79,11 +81,10 @@ static int mmc_set_env_part(struct mmc *mmc)
        dev = 0;
 #endif
 
-       if (part != mmc->part_num) {
-               ret = mmc_switch_part(dev, part);
-               if (ret)
-                       puts("MMC partition switch failed\n");
-       }
+       env_mmc_orig_hwpart = mmc->block_dev.hwpart;
+       ret = mmc_select_hwpart(dev, part);
+       if (ret)
+               puts("MMC partition switch failed\n");
 
        return ret;
 }
@@ -113,8 +114,7 @@ static void fini_mmc_for_env(struct mmc *mmc)
 #ifdef CONFIG_SPL_BUILD
        dev = 0;
 #endif
-       if (mmc_get_env_part(mmc) != mmc->part_num)
-               mmc_switch_part(dev, mmc->part_num);
+       mmc_select_hwpart(dev, env_mmc_orig_hwpart);
 #endif
 }
 
index 7ff2a810f303f9b3551934f3661a537730e30d88..395d472e0bd995e7a7e863f786ae0c7fdfa1ca24 100644 (file)
@@ -20,23 +20,6 @@ static unsigned char *dfu_file_buf;
 static long dfu_file_buf_len;
 static long dfu_file_buf_filled;
 
-static int mmc_access_part(struct dfu_entity *dfu, struct mmc *mmc, int part)
-{
-       int ret;
-
-       if (part == mmc->part_num)
-               return 0;
-
-       ret = mmc_switch_part(dfu->data.mmc.dev_num, part);
-       if (ret) {
-               error("Cannot switch to partition %d\n", part);
-               return ret;
-       }
-       mmc->part_num = part;
-
-       return 0;
-}
-
 static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
                        u64 offset, void *buf, long *len)
 {
@@ -66,8 +49,9 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
        }
 
        if (dfu->data.mmc.hw_partition >= 0) {
-               part_num_bkp = mmc->part_num;
-               ret = mmc_access_part(dfu, mmc, dfu->data.mmc.hw_partition);
+               part_num_bkp = mmc->block_dev.hwpart;
+               ret = mmc_select_hwpart(dfu->data.mmc.dev_num,
+                                       dfu->data.mmc.hw_partition);
                if (ret)
                        return ret;
        }
@@ -91,12 +75,12 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
        if (n != blk_count) {
                error("MMC operation failed");
                if (dfu->data.mmc.hw_partition >= 0)
-                       mmc_access_part(dfu, mmc, part_num_bkp);
+                       mmc_select_hwpart(dfu->data.mmc.dev_num, part_num_bkp);
                return -EIO;
        }
 
        if (dfu->data.mmc.hw_partition >= 0) {
-               ret = mmc_access_part(dfu, mmc, part_num_bkp);
+               ret = mmc_select_hwpart(dfu->data.mmc.dev_num, part_num_bkp);
                if (ret)
                        return ret;
        }
index 6d88db4bb6dd2fd3a29e7d7d78a5fc458d7ab31d..e6028d503f279ee6617b29e9657d1c8a17e39a85 100644 (file)
@@ -238,6 +238,7 @@ static ulong mmc_bread(block_dev_desc_t *block_dev, lbaint_t start,
                       lbaint_t blkcnt, void *dst)
 {
        int dev_num = block_dev->dev;
+       int err;
        lbaint_t cur, blocks_todo = blkcnt;
 
        if (blkcnt == 0)
@@ -247,6 +248,10 @@ static ulong mmc_bread(block_dev_desc_t *block_dev, lbaint_t start,
        if (!mmc)
                return 0;
 
+       err = mmc_select_hwpart(dev_num, block_dev->hwpart);
+       if (err < 0)
+               return 0;
+
        if ((start + blkcnt) > mmc->block_dev.lba) {
 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
                printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
@@ -581,7 +586,7 @@ int mmc_select_hwpart(int dev_num, int hwpart)
        if (!mmc)
                return -ENODEV;
 
-       if (mmc->part_num == hwpart)
+       if (mmc->block_dev.hwpart == hwpart)
                return 0;
 
        if (mmc->part_config == MMCPART_NOAVAILABLE) {
@@ -593,8 +598,6 @@ int mmc_select_hwpart(int dev_num, int hwpart)
        if (ret)
                return ret;
 
-       mmc->part_num = hwpart;
-
        return 0;
 }
 
@@ -615,8 +618,10 @@ int mmc_switch_part(int dev_num, unsigned int part_num)
         * Set the capacity if the switch succeeded or was intended
         * to return to representing the raw device.
         */
-       if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0)))
+       if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
                ret = mmc_set_capacity(mmc, part_num);
+               mmc->block_dev.hwpart = part_num;
+       }
 
        return ret;
 }
@@ -1326,7 +1331,7 @@ static int mmc_startup(struct mmc *mmc)
                mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
        }
 
-       err = mmc_set_capacity(mmc, mmc->part_num);
+       err = mmc_set_capacity(mmc, mmc->block_dev.hwpart);
        if (err)
                return err;
 
@@ -1467,6 +1472,7 @@ static int mmc_startup(struct mmc *mmc)
 
        /* fill in device description */
        mmc->block_dev.lun = 0;
+       mmc->block_dev.hwpart = 0;
        mmc->block_dev.type = 0;
        mmc->block_dev.blksz = mmc->read_bl_len;
        mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
@@ -1626,7 +1632,7 @@ int mmc_start_init(struct mmc *mmc)
                return err;
 
        /* The internal partition reset to user partition(0) at every CMD0*/
-       mmc->part_num = 0;
+       mmc->block_dev.hwpart = 0;
 
        /* Test for SD version 2 */
        err = mmc_send_if_cond(mmc);
index 6733314942ea4fd4ad67d2b5643878dece2ba343..79b8c4d808fb32c79605dc046417135aed1def9c 100644 (file)
@@ -78,6 +78,10 @@ unsigned long mmc_berase(block_dev_desc_t *block_dev, lbaint_t start,
        if (!mmc)
                return -1;
 
+       err = mmc_select_hwpart(dev_num, block_dev->hwpart);
+       if (err < 0)
+               return -1;
+
        /*
         * We want to see if the requested start or total block count are
         * unaligned.  We discard the whole numbers and only care about the
@@ -172,11 +176,16 @@ ulong mmc_bwrite(block_dev_desc_t *block_dev, lbaint_t start, lbaint_t blkcnt,
 {
        int dev_num = block_dev->dev;
        lbaint_t cur, blocks_todo = blkcnt;
+       int err;
 
        struct mmc *mmc = find_mmc_device(dev_num);
        if (!mmc)
                return 0;
 
+       err = mmc_select_hwpart(dev_num, block_dev->hwpart);
+       if (err < 0)
+               return 0;
+
        if (mmc_set_blocklen(mmc, mmc->write_bl_len))
                return 0;
 
index 9254b716b959785c7e17c128b2e78b78aada14c5..465daeb0852a4f1168bb09f2603bea8afec3cd28 100644 (file)
@@ -364,7 +364,6 @@ struct mmc {
        u8 part_attr;
        u8 wr_rel_set;
        char part_config;
-       char part_num;
        uint tran_speed;
        uint read_bl_len;
        uint write_bl_len;
index 8396ed178eead1f367ccfae281d2d015257b2b24..4d00e220e4c8867c6312044c05a497ec77aaf262 100644 (file)
@@ -18,6 +18,7 @@ struct block_dev_desc {
        unsigned char   part_type;      /* partition type */
        unsigned char   target;         /* target SCSI ID */
        unsigned char   lun;            /* target LUN */
+       unsigned char   hwpart;         /* HW partition, e.g. for eMMC */
        unsigned char   type;           /* device type */
        unsigned char   removable;      /* removable device */
 #ifdef CONFIG_LBA48