mmc: fsl_esdhc: Fix SDR104 and HS200 support
[oweals/u-boot.git] / disk / part.c
index c67fdacc79257f12b64583de2bd845cb98445151..f6a31025dc8a0a1a1a484105285ae060b8765b2d 100644 (file)
@@ -1,14 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2001
  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
+#include <blk.h>
 #include <command.h>
+#include <env.h>
 #include <errno.h>
 #include <ide.h>
+#include <log.h>
 #include <malloc.h>
 #include <part.h>
 #include <ubifs_uboot.h>
 #define PRINTF(fmt,args...)
 #endif
 
-DECLARE_GLOBAL_DATA_PTR;
+/* Check all partition types */
+#define PART_TYPE_ALL          -1
 
-#ifdef HAVE_BLOCK_DEVICE
-static struct part_driver *part_driver_lookup_type(int part_type)
+static struct part_driver *part_driver_lookup_type(struct blk_desc *dev_desc)
 {
        struct part_driver *drv =
                ll_entry_start(struct part_driver, part_driver);
        const int n_ents = ll_entry_count(struct part_driver, part_driver);
        struct part_driver *entry;
 
-       for (entry = drv; entry != drv + n_ents; entry++) {
-               if (part_type == entry->part_type)
-                       return entry;
+       if (dev_desc->part_type == PART_TYPE_UNKNOWN) {
+               for (entry = drv; entry != drv + n_ents; entry++) {
+                       int ret;
+
+                       ret = entry->test(dev_desc);
+                       if (!ret) {
+                               dev_desc->part_type = entry->part_type;
+                               return entry;
+                       }
+               }
+       } else {
+               for (entry = drv; entry != drv + n_ents; entry++) {
+                       if (dev_desc->part_type == entry->part_type)
+                               return entry;
+               }
        }
 
        /* Not found */
        return NULL;
 }
 
+#ifdef CONFIG_HAVE_BLOCK_DEVICE
 static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
 {
        struct blk_desc *dev_desc;
@@ -77,7 +92,7 @@ struct blk_desc *blk_get_dev(const char *ifname, int dev)
 }
 #endif
 
-#ifdef HAVE_BLOCK_DEVICE
+#ifdef CONFIG_HAVE_BLOCK_DEVICE
 
 /* ------------------------------------------------------------------------- */
 /*
@@ -91,17 +106,18 @@ typedef lbaint_t lba512_t;
 #endif
 
 /*
- * Overflowless variant of (block_count * mul_by / div_by)
- * when div_by > mul_by
+ * Overflowless variant of (block_count * mul_by / 2**right_shift)
+ * when 2**right_shift > mul_by
  */
-static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by, lba512_t div_by)
+static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by,
+                             int right_shift)
 {
        lba512_t bc_quot, bc_rem;
 
        /* x * m / d == x / d * m + (x % d) * m / d */
-       bc_quot = block_count / div_by;
-       bc_rem  = block_count - div_by * bc_quot;
-       return bc_quot * mul_by + (bc_rem * mul_by) / div_by;
+       bc_quot = block_count >> right_shift;
+       bc_rem  = block_count - (bc_quot << right_shift);
+       return bc_quot * mul_by + ((bc_rem * mul_by) >> right_shift);
 }
 
 void dev_print (struct blk_desc *dev_desc)
@@ -138,6 +154,9 @@ void dev_print (struct blk_desc *dev_desc)
                        dev_desc->revision,
                        dev_desc->product);
                break;
+       case IF_TYPE_VIRTIO:
+               printf("%s VirtIO Block Device\n", dev_desc->vendor);
+               break;
        case IF_TYPE_DOC:
                puts("device type DOC\n");
                return;
@@ -178,7 +197,7 @@ void dev_print (struct blk_desc *dev_desc)
                lba512 = (lba * (dev_desc->blksz/512));
                /* round to 1 digit */
                /* 2048 = (1024 * 1024) / 512 MB */
-               mb = lba512_muldiv(lba512, 10, 2048);
+               mb = lba512_muldiv(lba512, 10, 11);
 
                mb_quot = mb / 10;
                mb_rem  = mb - (10 * mb_quot);
@@ -209,7 +228,7 @@ void dev_print (struct blk_desc *dev_desc)
 }
 #endif
 
-#ifdef HAVE_BLOCK_DEVICE
+#ifdef CONFIG_HAVE_BLOCK_DEVICE
 
 void part_init(struct blk_desc *dev_desc)
 {
@@ -269,6 +288,9 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc)
        case IF_TYPE_NVME:
                puts ("NVMe");
                break;
+       case IF_TYPE_VIRTIO:
+               puts("VirtIO");
+               break;
        default:
                puts ("UNKNOWN");
                break;
@@ -282,7 +304,7 @@ void part_print(struct blk_desc *dev_desc)
 {
        struct part_driver *drv;
 
-       drv = part_driver_lookup_type(dev_desc->part_type);
+       drv = part_driver_lookup_type(dev_desc);
        if (!drv) {
                printf("## Unknown partition table type %x\n",
                       dev_desc->part_type);
@@ -295,12 +317,12 @@ void part_print(struct blk_desc *dev_desc)
                drv->print(dev_desc);
 }
 
-#endif /* HAVE_BLOCK_DEVICE */
+#endif /* CONFIG_HAVE_BLOCK_DEVICE */
 
 int part_get_info(struct blk_desc *dev_desc, int part,
-                      disk_partition_t *info)
+                      struct disk_partition *info)
 {
-#ifdef HAVE_BLOCK_DEVICE
+#ifdef CONFIG_HAVE_BLOCK_DEVICE
        struct part_driver *drv;
 
 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
@@ -311,7 +333,7 @@ int part_get_info(struct blk_desc *dev_desc, int part,
        info->type_guid[0] = 0;
 #endif
 
-       drv = part_driver_lookup_type(dev_desc->part_type);
+       drv = part_driver_lookup_type(dev_desc);
        if (!drv) {
                debug("## Unknown partition table type %x\n",
                      dev_desc->part_type);
@@ -326,11 +348,30 @@ int part_get_info(struct blk_desc *dev_desc, int part,
                PRINTF("## Valid %s partition found ##\n", drv->name);
                return 0;
        }
-#endif /* HAVE_BLOCK_DEVICE */
+#endif /* CONFIG_HAVE_BLOCK_DEVICE */
 
        return -1;
 }
 
+int part_get_info_whole_disk(struct blk_desc *dev_desc,
+                            struct disk_partition *info)
+{
+       info->start = 0;
+       info->size = dev_desc->lba;
+       info->blksz = dev_desc->blksz;
+       info->bootable = 0;
+       strcpy((char *)info->type, BOOT_PART_TYPE);
+       strcpy((char *)info->name, "Whole Disk");
+#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
+       info->uuid[0] = 0;
+#endif
+#ifdef CONFIG_PARTITION_TYPE_GUID
+       info->type_guid[0] = 0;
+#endif
+
+       return 0;
+}
+
 int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str,
                          struct blk_desc **dev_desc)
 {
@@ -370,19 +411,18 @@ int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str,
 
        *dev_desc = get_dev_hwpart(ifname, dev, hwpart);
        if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
-               printf("** Bad device %s %s **\n", ifname, dev_hwpart_str);
+               debug("** Bad device %s %s **\n", ifname, dev_hwpart_str);
                dev = -ENOENT;
                goto cleanup;
        }
 
-#ifdef HAVE_BLOCK_DEVICE
+#ifdef CONFIG_HAVE_BLOCK_DEVICE
        /*
         * Updates the partition table for the specified hw partition.
-        * Does not need to be done for hwpart 0 since it is default and
-        * already loaded.
+        * Always should be done, otherwise hw partition 0 will return stale
+        * data after displaying a non-zero hw partition.
         */
-       if(hwpart != 0)
-               part_init(*dev_desc);
+       part_init(*dev_desc);
 #endif
 
 cleanup:
@@ -394,7 +434,7 @@ cleanup:
 #define PART_AUTO -1
 int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
                             struct blk_desc **dev_desc,
-                            disk_partition_t *info, int allow_whole_dev)
+                            struct disk_partition *info, int allow_whole_dev)
 {
        int ret = -1;
        const char *part_str;
@@ -404,7 +444,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
        char *ep;
        int p;
        int part;
-       disk_partition_t tmpinfo;
+       struct disk_partition tmpinfo;
 
 #ifdef CONFIG_SANDBOX
        /*
@@ -432,7 +472,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
 
 #ifdef CONFIG_CMD_UBIFS
        /*
-        * Special-case ubi, ubi goes through a mtd, rathen then through
+        * Special-case ubi, ubi goes through a mtd, rather than through
         * a regular block device.
         */
        if (0 == strcmp(ifname, "ubi")) {
@@ -523,18 +563,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
 
                (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
 
-               info->start = 0;
-               info->size = (*dev_desc)->lba;
-               info->blksz = (*dev_desc)->blksz;
-               info->bootable = 0;
-               strcpy((char *)info->type, BOOT_PART_TYPE);
-               strcpy((char *)info->name, "Whole Disk");
-#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
-               info->uuid[0] = 0;
-#endif
-#ifdef CONFIG_PARTITION_TYPE_GUID
-               info->type_guid[0] = 0;
-#endif
+               part_get_info_whole_disk(*dev_desc, info);
 
                ret = 0;
                goto cleanup;
@@ -619,32 +648,105 @@ cleanup:
        return ret;
 }
 
-int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
-       disk_partition_t *info)
+int part_get_info_by_name_type(struct blk_desc *dev_desc, const char *name,
+                              struct disk_partition *info, int part_type)
 {
-       struct part_driver *first_drv =
-               ll_entry_start(struct part_driver, part_driver);
-       const int n_drvs = ll_entry_count(struct part_driver, part_driver);
        struct part_driver *part_drv;
-
-       for (part_drv = first_drv; part_drv != first_drv + n_drvs; part_drv++) {
-               int ret;
-               int i;
-               for (i = 1; i < part_drv->max_entries; i++) {
-                       ret = part_drv->get_info(dev_desc, i, info);
-                       if (ret != 0) {
-                               /* no more entries in table */
-                               break;
-                       }
-                       if (strcmp(name, (const char *)info->name) == 0) {
-                               /* matched */
-                               return i;
-                       }
+       int ret;
+       int i;
+
+       part_drv = part_driver_lookup_type(dev_desc);
+       if (!part_drv)
+               return -1;
+       for (i = 1; i < part_drv->max_entries; i++) {
+               ret = part_drv->get_info(dev_desc, i, info);
+               if (ret != 0) {
+                       /* no more entries in table */
+                       break;
+               }
+               if (strcmp(name, (const char *)info->name) == 0) {
+                       /* matched */
+                       return i;
                }
        }
+
        return -1;
 }
 
+int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
+                         struct disk_partition *info)
+{
+       return part_get_info_by_name_type(dev_desc, name, info, PART_TYPE_ALL);
+}
+
+/**
+ * Get partition info from device number and partition name.
+ *
+ * Parse a device number and partition name string in the form of
+ * "device_num#partition_name", for example "0#misc". If the partition
+ * is found, sets dev_desc and part_info accordingly with the information
+ * of the partition with the given partition_name.
+ *
+ * @param[in] dev_iface Device interface
+ * @param[in] dev_part_str Input string argument, like "0#misc"
+ * @param[out] dev_desc Place to store the device description pointer
+ * @param[out] part_info Place to store the partition information
+ * @return 0 on success, or a negative on error
+ */
+static int part_get_info_by_dev_and_name(const char *dev_iface,
+                                        const char *dev_part_str,
+                                        struct blk_desc **dev_desc,
+                                        struct disk_partition *part_info)
+{
+       char *ep;
+       const char *part_str;
+       int dev_num;
+
+       part_str = strchr(dev_part_str, '#');
+       if (!part_str || part_str == dev_part_str)
+               return -EINVAL;
+
+       dev_num = simple_strtoul(dev_part_str, &ep, 16);
+       if (ep != part_str) {
+               /* Not all the first part before the # was parsed. */
+               return -EINVAL;
+       }
+       part_str++;
+
+       *dev_desc = blk_get_dev(dev_iface, dev_num);
+       if (!*dev_desc) {
+               printf("Could not find %s %d\n", dev_iface, dev_num);
+               return -EINVAL;
+       }
+       if (part_get_info_by_name(*dev_desc, part_str, part_info) < 0) {
+               printf("Could not find \"%s\" partition\n", part_str);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int part_get_info_by_dev_and_name_or_num(const char *dev_iface,
+                                        const char *dev_part_str,
+                                        struct blk_desc **dev_desc,
+                                        struct disk_partition *part_info)
+{
+       /* Split the part_name if passed as "$dev_num#part_name". */
+       if (!part_get_info_by_dev_and_name(dev_iface, dev_part_str,
+                                          dev_desc, part_info))
+               return 0;
+       /*
+        * Couldn't lookup by name, try looking up the partition description
+        * directly.
+        */
+       if (blk_get_device_part_str(dev_iface, dev_part_str,
+                                   dev_desc, part_info, 1) < 0) {
+               printf("Couldn't find partition %s %s\n",
+                      dev_iface, dev_part_str);
+               return -EINVAL;
+       }
+       return 0;
+}
+
 void part_set_generic_name(const struct blk_desc *dev_desc,
        int part_num, char *name)
 {