cmd: nfsdown: support nfsdown command for Tizen 21/112821/16
authorJiho Chu <jiho.chu@samsung.com>
Thu, 2 Feb 2017 01:47:40 +0000 (10:47 +0900)
committerJiho Chu <jiho.chu@samsung.com>
Thu, 23 Feb 2017 02:30:23 +0000 (11:30 +0900)
nfsdown feature:
- enable USB start if CONFIG_CMD_USB and CONFIG_USB_HOST_ETHER enabled
- connect to nfs server
- download & update Tizen FW according to DFU info

Change-Id: I5d0696b051a8b770349bf28b19735f67b3b089d4
Signed-off-by: Jiho Chu <jiho.chu@samsung.com>
cmd/Makefile
cmd/nfsdown.c [new file with mode: 0644]

index ee76a1d3538f81d9f257bad59a3da95d419c0fab..d0b56a02844c86856c9fa019c044cdeadaed58ed 100644 (file)
@@ -140,6 +140,7 @@ obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o
 
 obj-$(CONFIG_CMD_USB_MASS_STORAGE) += usb_mass_storage.o
 obj-$(CONFIG_CMD_THOR_DOWNLOAD) += thordown.o
+obj-$(CONFIG_CMD_NFS_DOWNLOAD) += nfsdown.o
 obj-$(CONFIG_CMD_XIMG) += ximg.o
 obj-$(CONFIG_YAFFS2) += yaffs2.o
 obj-$(CONFIG_CMD_SPL) += spl.o
diff --git a/cmd/nfsdown.c b/cmd/nfsdown.c
new file mode 100644 (file)
index 0000000..9a036f7
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * cmd_nfsdown.c -- Tizen "nfs" Downloader
+ *
+ * Copyright (C) 2017 Jiho Chu <jiho.chu@samsung.com>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <malloc.h>
+#include <common.h>
+#include <errno.h>
+#include <command.h>
+#include <memalign.h>
+#include <net.h>
+#include <usb.h>
+#include <part.h>
+#include <mmc.h>
+
+#define LEN_BUF                        128
+#define LEN_NAME               32
+
+#ifdef CONFIG_NFS_DOWNLOAD_ADDR
+#define NFS_DOWNLOAD_ADDR      __stringify(CONFIG_NFS_DOWNLOAD_ADDR)
+#else
+#define NFS_DOWNLOAD_ADDR      "0x40000000"
+#endif
+
+enum img_type {
+       IMG_TYPE_RAW,
+       IMG_TYPE_PART,
+};
+
+struct img_info {
+       char name[LEN_NAME];
+       enum img_type type;
+
+       /* mmc info */
+       uint hwpart;
+       uint part;
+
+       /* block info */
+       uint lba_start;
+       uint lba_size;
+       uint lba_blk_size;
+
+       struct list_head list;
+};
+
+struct img_comp {
+       char name[LEN_NAME];
+       uint size;
+
+       struct list_head list;
+};
+
+static char *g_update_image_names[] = {
+       "bl1.bin",
+       "bl2.bin",
+       "u-boot-mmc.bin",
+       "tzsw.bin",
+       "params.bin",
+       "boot.img",
+       "rootfs.img",
+       "system-data.img",
+       "user.img",
+       "modules.img"
+};
+
+#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_HOST_ETHER)
+extern char usb_started;
+
+static void do_usb_ether_start(void)
+{
+       bootstage_mark_name(BOOTSTAGE_ID_USB_START, "usb_start");
+       if (usb_init() < 0)
+               return;
+
+       bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
+       usb_host_eth_scan(1);
+}
+#endif
+
+#ifdef CONFIG_SET_DFU_ALT_INFO
+#ifdef CONFIG_SET_DFU_ALT_BUF_LEN
+#define DFU_ALT_BUF_LEN        CONFIG_SET_DFU_ALT_BUF_LEN
+#else
+#define DFU_ALT_BUF_LEN        (SZ_1K)
+#endif
+
+static void set_dfu_alt_info(void)
+{
+       int buf_used;
+       ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN);
+
+       buf_used = snprintf(buf, DFU_ALT_BUF_LEN, "%s",
+                           CONFIG_DFU_ALT_BOOT_EMMC);
+
+       buf_used += snprintf(buf + buf_used, DFU_ALT_BUF_LEN, "%s%s",
+                            buf_used ? ";" : "",  CONFIG_DFU_ALT_SYSTEM);
+
+       if (buf_used <= 0)
+               return;
+
+       setenv("dfu_alt_info", buf);
+
+       return;
+}
+
+#else /* CONFIG_SET_DFU_ALT_INFO */
+
+static void set_dfu_alt_info(void)
+{
+       return;
+}
+
+#endif /* CONFIG_SET_DFU_ALT_INFO */
+
+static int do_mmc_init(struct mmc **mmc)
+{
+       int ret;
+
+       *mmc = find_mmc_device(0);
+       if (!mmc) {
+               error("Couldn't find MMC device no. 0.\n");
+               return -ENODEV;
+       }
+
+       ret = mmc_init(*mmc);
+       if (ret) {
+               error("Couldn't init MMC device.\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int find_mmc_partition_info(struct mmc *mmc, uint hwpart, uint part,
+                                  disk_partition_t *partinfo)
+{
+       int ret;
+
+       if (!mmc)
+               return -ENODEV;
+
+       ret = mmc_select_hwpart(0, hwpart);
+       if (ret)
+               return ret;
+
+       ret = get_partition_info(&mmc->block_dev, part, partinfo);
+       if (ret) {
+               error("Couldn't find part #%d on mmc device #%d\n",
+                     part, hwpart);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct img_info *create_img_info(struct mmc *mmc, char *str_info)
+{
+       struct img_info *info;
+       char *tok[6];
+       int i;
+       int ret;
+
+       info = calloc(1, sizeof(struct img_info));
+       if (!info) {
+               error("Cannot malloc!!\n");
+               return NULL;
+       }
+
+       for (i = 0; i < 6; i++)
+               tok[i] = strsep(&str_info, " \t");
+
+       if (strlen(tok[0]) >= LEN_NAME - 1) {
+               error("img name is too long: %s\n", tok[0]);
+               goto create_img_err;
+       }
+
+       for (i = 0; i < sizeof(g_update_image_names) / sizeof(char *); i++)
+               if (!strncmp(tok[0], g_update_image_names[i], strlen(tok[0])))
+                       sprintf(info->name, "%s", g_update_image_names[i]);
+
+       if (!info->name[0])
+               goto create_img_err;
+
+       if (!strncmp(tok[1], "raw", 3)) {
+               info->type = IMG_TYPE_RAW;
+               info->lba_start = simple_strtoul(tok[2], NULL, 0);
+               info->lba_size = simple_strtoul(tok[3], NULL, 0);
+               info->lba_blk_size = 512;
+
+               if (tok[4] && !strncmp(tok[4], "mmcpart", 7))
+                       info->hwpart = simple_strtoul(tok[5], NULL, 0);
+               else
+                       info->hwpart = 1;
+       } else if (!strncmp(tok[1], "part", 4)) {
+               disk_partition_t partinfo;
+               uint offset = 0;
+
+               info->type = IMG_TYPE_PART;
+               info->hwpart = simple_strtoul(tok[2], NULL, 0);
+               info->part = simple_strtoul(tok[3], NULL, 0);
+
+               ret = find_mmc_partition_info(mmc, info->hwpart, info->part,
+                                             &partinfo);
+               if (ret) {
+                       error("Cannot get partition info: %d\n", info->hwpart);
+                       goto create_img_err;
+               }
+
+               if (tok[4] && !strcmp(tok[4], "offset"))
+                       offset = simple_strtoul(tok[5], NULL, 0);
+
+               info->lba_start = partinfo.start + offset;
+               info->lba_size  = partinfo.size - offset;
+               info->lba_blk_size = partinfo.blksz;
+       } else if (!strncmp(tok[1], "fat", 3)) {
+               error("nfsdown does not support fat update");
+               goto create_img_err;
+       } else {
+               error("Unrecognized img type: %s", tok[0]);
+               goto create_img_err;
+       }
+
+       return info;
+
+create_img_err:
+       free(info);
+
+       return NULL;
+}
+
+struct img_comp *create_img_comp(const char *name, uint size)
+{
+       struct img_comp *comp;
+
+       comp = malloc(sizeof(struct img_comp));
+       if (!comp) {
+               error("Failed to alloc\n");
+               return NULL;
+       }
+
+       strncpy(comp->name, name, LEN_NAME);
+       comp->size = size;
+
+       return comp;
+}
+
+/**
+ * Donwload from nfs file and write to mmc stroage
+ *
+ * @param buf_addr     Download buffer address from NFS
+ * @param file_path    Download file path from NFS
+ * @param part         MMC partition
+ * @param offset       img block offset
+ * @param size         img block size
+ * @param blk_size     MMC block size
+ * @return file_size   written file size, return -1 if error occurs
+ */
+static int do_nfs_to_mmc(struct mmc *mmc, char *buf_addr, char *file_path,
+                        uint part, uint offset, uint size, uint blk_size)
+{
+       char *_argv[3];
+       uint _size;
+       int repeatable;
+       int ret;
+       void *addr;
+
+       _argv[0] = "nfs";
+       _argv[1] = buf_addr;
+       _argv[2] = file_path;
+
+       ret = cmd_process(0, 3, _argv, &repeatable, NULL);
+       if (ret != CMD_RET_SUCCESS) {
+               puts("nfs download failed!!\n");
+               return -1;
+       }
+
+       _size = (net_boot_file_size % blk_size) ?
+                       net_boot_file_size / blk_size + 1
+                       : net_boot_file_size / blk_size;
+
+       ret = mmc_select_hwpart(0, part);
+       if (ret) {
+               error("Couldn't change to hwpart: %d\n", part);
+               return -1;
+       }
+
+       addr = (void *)simple_strtoul(buf_addr, NULL, 16);
+
+       printf("MMC write: dev # %d, block # %d, count %d ...\n\n",
+              part, offset, _size);
+       ret = mmc->block_dev.block_write(&mmc->block_dev, offset, _size, addr);
+       if (ret != _size) {
+               error("Failed to write MMC: part(%d), start(%d), size(%d)",
+                     part, offset, _size);
+               return -1;
+       }
+
+       return (int)net_boot_file_size;
+}
+
+int do_nfs_down(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       char *nfs_path;
+       char *buf;
+       char *line;
+       char src_path[LEN_BUF];
+       int size;
+       int ret;
+
+       struct img_info *info, *tmp_info;
+       struct img_comp *comp, *tmp_comp;
+       struct mmc      *mmc;
+
+       LIST_HEAD(img_info_list);
+       LIST_HEAD(img_comp_list);
+
+       puts("TIZEN \"nfs\" Downloader\n");
+
+       switch (argc) {
+       case 2:
+               nfs_path = argv[1];
+               break;
+       default:
+               return CMD_RET_USAGE;
+       }
+
+       INIT_LIST_HEAD(&img_info_list);
+       INIT_LIST_HEAD(&img_comp_list);
+
+       set_dfu_alt_info();
+
+       buf = getenv("dfu_alt_info");
+       if (!buf) {
+               puts("No Default dfu_alt_info\n");
+               return CMD_RET_FAILURE;
+       }
+       printf("\ndfu_alt_info = %s\n", buf);
+
+       ret = do_mmc_init(&mmc);
+       if (ret) {
+               error("failed to init mmc\n");
+               ret = CMD_RET_FAILURE;
+               goto error_end;
+       }
+
+#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_HOST_ETHER)
+       if (!usb_started)
+               do_usb_ether_start();
+#endif
+
+       line = strtok(buf, ";\n\0");
+       while (line) {
+               struct img_info *new_info;
+
+               new_info = create_img_info(mmc, line);
+               if (new_info)
+                       list_add_tail(&new_info->list, &img_info_list);
+
+               line = strtok(NULL, ";\n\0");
+       }
+
+       list_for_each_entry(info, &img_info_list, list) {
+               snprintf(src_path, LEN_BUF, "%s/%s", nfs_path, info->name);
+
+               size = do_nfs_to_mmc(mmc, NFS_DOWNLOAD_ADDR, src_path,
+                                    info->hwpart, info->lba_start,
+                                    info->lba_size, info->lba_blk_size);
+               if (size > 0) {
+                       struct img_comp *new_comp;
+
+                       new_comp = create_img_comp(info->name, size);
+                       if (new_comp)
+                               list_add_tail(&new_comp->list, &img_comp_list);
+               } else {
+                       printf("SKIP %s\n\n", src_path);
+               }
+       }
+
+       puts("########################################\n");
+       list_for_each_entry(comp, &img_comp_list, list)
+               printf("%15s\t-\t%10d Byte\n", comp->name, comp->size);
+       puts("########################################\n");
+
+error_end:
+       free(buf);
+
+       list_for_each_entry_safe(comp, tmp_comp, &img_comp_list, list) {
+               list_del(&comp->list);
+               free(comp);
+       }
+
+       list_for_each_entry_safe(info, tmp_info, &img_info_list, list) {
+               list_del(&info->list);
+               free(info);
+       }
+
+       return ret;
+}
+
+U_BOOT_CMD(nfsdown, CONFIG_SYS_MAXARGS, 1, do_nfs_down,
+          "TIZEN \"nfs\" downloader",
+          "<IP_ADDR>:<IMG_PATH>\n"
+          "  - device firmware upgrade via nfs for Tizen\n"
+          "    fusing images from <IP_ADDR>:<IMG_PATH> to MMC.\n"
+          "\n"
+          "(e.g) nfsdown 192.168.0.1:/nfs\n"
+);