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>
diff --git a/mmc_cmds.c b/mmc_cmds.c
index 2fc8d4a..2471eb0 100644
--- a/mmc_cmds.c
+++ b/mmc_cmds.c
@@ -504,6 +504,7 @@
__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 @@
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;
}