diff options
author | Balaji T K <balajitk@ti.com> | 2015-04-29 18:12:33 -0400 |
---|---|---|
committer | Chris Ball <chris@printf.net> | 2015-05-01 08:38:06 -0400 |
commit | 7891236d62ccd201054324b5298dd9529c6a764f (patch) | |
tree | 0de477a014dd569045a4e618856661ccb19da0b3 | |
parent | 4afc8c81685825461677311e79059cda15fba9d8 (diff) | |
download | mmc-utils-7891236d62ccd201054324b5298dd9529c6a764f.tar.gz |
mmc-utils: add support to create gp partition
create gp partition if needed with enhanced / extended attribute.
Signed-off-by: Balaji T K <balajitk@ti.com>
Signed-off-by: Chris Ball <chris@printf.net>
-rw-r--r-- | mmc.c | 5 | ||||
-rw-r--r-- | mmc.h | 2 | ||||
-rw-r--r-- | mmc_cmds.c | 135 | ||||
-rw-r--r-- | mmc_cmds.h | 1 |
4 files changed, 143 insertions, 0 deletions
@@ -70,6 +70,11 @@ static struct Command commands[] = { "Set the eMMC data sector size to 4KB by disabling emulation on\n<device>.", NULL }, + { do_create_gp_partition, -6, + "gp create", "<-y|-n> " "<length KiB> " "<partition> " "<enh_attr> " "<ext_attr> " "<device>\n" + "create general purpose partition for the <device>.\nDry-run only unless -y is passed.\nNOTE! This is a one-time programmable (unreversible) change.\nTo set enhanced attribute to general partition being created set\n <enh_attr> to 1 else set it to 0.\nTo set extended attribute to general partition\n set <ext_attr> to 1,2 else set it to 0", + NULL + }, { do_enh_area_set, -4, "enh_area set", "<-y|-n> " "<start KiB> " "<length KiB> " "<device>\n" "Enable the enhanced user area for the <device>.\nDry-run only unless -y is passed.\nNOTE! This is a one-time programmable (unreversible) change.", @@ -85,6 +85,8 @@ #define EXT_CSD_NATIVE_SECTOR_SIZE 63 /* R */ #define EXT_CSD_USE_NATIVE_SECTOR 62 /* R/W */ #define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */ +#define EXT_CSD_EXT_PARTITIONS_ATTRIBUTE_1 53 +#define EXT_CSD_EXT_PARTITIONS_ATTRIBUTE_0 52 /* * WR_REL_PARAM field definitions @@ -504,6 +504,7 @@ int check_enhanced_area_total_limit(const char * const device, int fd) __u32 regl; unsigned long max_enh_area_sz, user_area_sz, enh_area_sz = 0; unsigned long gp4_part_sz, gp3_part_sz, gp2_part_sz, gp1_part_sz; + unsigned long total_sz, total_gp_user_sz; unsigned int wp_sz, erase_sz; int ret; @@ -577,6 +578,140 @@ int check_enhanced_area_total_limit(const char * const device, int fd) enh_area_sz, max_enh_area_sz, device); return 1; } + total_sz = get_sector_count(ext_csd) / 2; + total_gp_user_sz = gp4_part_sz + gp3_part_sz + gp2_part_sz + + gp1_part_sz + user_area_sz; + if (total_gp_user_sz > total_sz) { + fprintf(stderr, + "requested total partition size %lu KiB cannot exceed card capacity %lu KiB %s\n", + total_gp_user_sz, total_sz, device); + return 1; + } + + return 0; +} + +int do_create_gp_partition(int nargs, char **argv) +{ + __u8 value; + __u8 ext_csd[512]; + __u8 address; + int fd, ret; + char *device; + int dry_run = 1; + int partition, enh_attr, ext_attr; + unsigned int length_kib, gp_size_mult; + unsigned long align; + + CHECK(nargs != 7, "Usage: mmc gp create <-y|-n> <length KiB> " + "<partition> <enh_attr> <ext_attr> </path/to/mmcblkX>\n", exit(1)); + + if (!strcmp("-y", argv[1])) + dry_run = 0; + + length_kib = strtol(argv[2], NULL, 10); + partition = strtol(argv[3], NULL, 10); + enh_attr = strtol(argv[4], NULL, 10); + ext_attr = strtol(argv[5], NULL, 10); + device = argv[6]; + + if (partition < 0 || partition > 4) { + printf("Invalid gp parition number valid range [1-4]\n"); + exit(1); + } + + if (enh_attr && ext_attr) { + printf("Not allowed to set both enhanced attribute and extended attribute\n"); + exit(1); + } + + fd = open(device, O_RDWR); + if (fd < 0) { + perror("open"); + exit(1); + } + + ret = read_extcsd(fd, ext_csd); + if (ret) { + fprintf(stderr, "Could not read EXT_CSD from %s\n", device); + exit(1); + } + + /* assert not PARTITION_SETTING_COMPLETED */ + if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED]) { + printf(" Device is already partitioned\n"); + exit(1); + } + + align = 512l * get_hc_wp_grp_size(ext_csd) * get_hc_erase_grp_size(ext_csd); + gp_size_mult = (length_kib + align/2l) / align; + + /* set EXT_CSD_ERASE_GROUP_DEF bit 0 */ + ret = write_extcsd_value(fd, EXT_CSD_ERASE_GROUP_DEF, 0x1); + if (ret) { + fprintf(stderr, "Could not write 0x1 to EXT_CSD[%d] in %s\n", + EXT_CSD_ERASE_GROUP_DEF, device); + exit(1); + } + + value = (gp_size_mult >> 16) & 0xff; + address = EXT_CSD_GP_SIZE_MULT_1_2 + (partition - 1) * 3; + ret = write_extcsd_value(fd, address, value); + if (ret) { + fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n", + value, address, device); + exit(1); + } + value = (gp_size_mult >> 8) & 0xff; + address = EXT_CSD_GP_SIZE_MULT_1_1 + (partition - 1) * 3; + ret = write_extcsd_value(fd, address, value); + if (ret) { + fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n", + value, address, device); + exit(1); + } + value = gp_size_mult & 0xff; + address = EXT_CSD_GP_SIZE_MULT_1_0 + (partition - 1) * 3; + ret = write_extcsd_value(fd, address, value); + if (ret) { + fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n", + value, address, device); + exit(1); + } + + value = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; + if (enh_attr) + value |= (1 << partition); + else + value &= ~(1 << partition); + + ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, value); + if (ret) { + fprintf(stderr, "Could not write EXT_CSD_ENH_%x to EXT_CSD[%d] in %s\n", + partition, EXT_CSD_PARTITIONS_ATTRIBUTE, device); + exit(1); + } + + address = EXT_CSD_EXT_PARTITIONS_ATTRIBUTE_0 + (partition - 1) / 2; + value = ext_csd[address]; + if (ext_attr) + value |= (ext_attr << (4 * ((partition - 1) % 2))); + else + value &= (0xF << (4 * ((partition % 2)))); + + ret = write_extcsd_value(fd, address, value); + if (ret) { + fprintf(stderr, "Could not write 0x%x to EXT_CSD[%d] in %s\n", + value, address, device); + exit(1); + } + + ret = check_enhanced_area_total_limit(device, fd); + if (ret) + exit(1); + + if (!set_partitioning_setting_completed(dry_run, device, fd)) + exit(1); return 0; } @@ -26,6 +26,7 @@ int do_hwreset_en(int nargs, char **argv); int do_hwreset_dis(int nargs, char **argv); int do_sanitize(int nargs, char **argv); int do_status_get(int nargs, char **argv); +int do_create_gp_partition(int nargs, char **argv); int do_enh_area_set(int nargs, char **argv); int do_write_reliability_set(int nargs, char **argv); int do_rpmb_write_key(int nargs, char **argv); |