On Thu, Jul 10, 2014 at 4:40 PM, Alex Lemberg <alex.lemb...@sandisk.com> wrote:
> Thanks Gwendal!
> We will test your changes.
>
> Are you still experiencing the "request_firmware" failure?
no, since I added the mmc_put_card(). But enclosing request_firmware()
betwen put()/get() is not to my opinion not the right thing to do: the
caller called us with the lock held, we should not release it behind
its back.
We also need to revisit the eMMC reset, I had to drop the lock there as well.
>
> Alex
>
>> -----Original Message-----
>> From: Gwendal Grignou [mailto:gwen...@chromium.org]
>> Sent: Thursday, July 10, 2014 4:08 PM
>> To: Avi Shchislowski; ch...@printf.net; ulf.hans...@linaro.org
>> Cc: ol...@chromium.org; Alex Lemberg; linux-mmc@vger.kernel.org;
>> c...@laptop.org; grund...@chromium.org; Yaniv Iarovici; Gwendal Grignou
>> Subject: [PATCH] Fix on top of sandisk patches.
>>
>> To apply on top of
>> [RFC PATCH 1/1 v7]mmc: Support-FFU-for-eMMC-v5.0
>>
>> Signed-off-by: Gwendal Grignou <gwen...@chromium.org>
>> ---
>>
>> Avi,
>>
>> As I mentioned earlier, I found several problems with your patch.
>> Here is a patch that allows to go further.
>> It is still not working reliably. The eMMC I am using has a problem being
>> reseted after upgrade, and I am still hitting what appears to be memory
>> corruptions. I believe the issues I am still having are due to the kernel 
>> code,
>> not the eMMC I am testing.
>>
>> Gwendal.
>>
>>  drivers/mmc/card/block.c |   3 +-
>>  drivers/mmc/card/ffu.c   | 121 +++++++++++++++++++++++--------------------
>> ----
>>  drivers/mmc/core/mmc.c   |   8 ++++
>>  include/linux/mmc/card.h |   1 +
>>  include/linux/mmc/ffu.h  |  13 +----
>>  5 files changed, 71 insertions(+), 75 deletions(-)
>>
>> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index
>> fc65a6c..9d866fb 100644
>> --- a/drivers/mmc/card/block.c
>> +++ b/drivers/mmc/card/block.c
>> @@ -504,8 +504,7 @@ static int mmc_blk_ioctl_cmd(struct block_device
>> *bdev,
>>       mmc_get_card(card);
>>
>>       if (cmd.opcode == MMC_FFU_DOWNLOAD_OP) {
>> -             err = mmc_ffu_download(card, &cmd , idata->buf,
>> -                     idata->buf_bytes);
>> +             err = mmc_ffu_download(card, idata->buf);
>>               goto cmd_rel_host;
>>       }
>>
>> diff --git a/drivers/mmc/card/ffu.c b/drivers/mmc/card/ffu.c index
>> 04e07a5..0e85b2b 100644
>> --- a/drivers/mmc/card/ffu.c
>> +++ b/drivers/mmc/card/ffu.c
>> @@ -63,15 +63,13 @@ struct mmc_ffu_area {
>>
>>  static void mmc_ffu_prepare_mrq(struct mmc_card *card,
>>       struct mmc_request *mrq, struct scatterlist *sg, unsigned int sg_len,
>> -     u32 arg, unsigned int blocks, unsigned int blksz, int write) {
>> +     u32 arg, unsigned int blocks, unsigned int blksz) {
>>       BUG_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop);
>>
>>       if (blocks > 1) {
>> -             mrq->cmd->opcode = write ?
>> -                     MMC_WRITE_MULTIPLE_BLOCK :
>> MMC_READ_MULTIPLE_BLOCK;
>> +             mrq->cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
>>       } else {
>> -             mrq->cmd->opcode = write ? MMC_WRITE_BLOCK :
>> -                     MMC_READ_SINGLE_BLOCK;
>> +             mrq->cmd->opcode = MMC_WRITE_BLOCK;
>>       }
>>
>>       mrq->cmd->arg = arg;
>> @@ -89,11 +87,12 @@ static void mmc_ffu_prepare_mrq(struct mmc_card
>> *card,
>>
>>       mrq->data->blksz = blksz;
>>       mrq->data->blocks = blocks;
>> -     mrq->data->flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
>> +     mrq->data->flags = MMC_DATA_WRITE;
>>       mrq->data->sg = sg;
>>       mrq->data->sg_len = sg_len;
>>
>> -     mmc_set_data_timeout(mrq->data, card); }
>> +     mmc_set_data_timeout(mrq->data, card); }
>>
>>  /*
>>   * Checks that a normal transfer didn't have any errors @@ -153,7 +152,7
>> @@ static int mmc_ffu_wait_busy(struct mmc_card *card) {
>>   */
>>  static int mmc_ffu_simple_transfer(struct mmc_card *card,
>>       struct scatterlist *sg, unsigned int sg_len, u32 arg,
>> -     unsigned int blocks, unsigned int blksz, int write) {
>> +     unsigned int blocks, unsigned int blksz) {
>>       struct mmc_request mrq = {0};
>>       struct mmc_command cmd = {0};
>>       struct mmc_command stop = {0};
>> @@ -162,8 +161,7 @@ static int mmc_ffu_simple_transfer(struct mmc_card
>> *card,
>>       mrq.cmd = &cmd;
>>       mrq.data = &data;
>>       mrq.stop = &stop;
>> -     mmc_ffu_prepare_mrq(card, &mrq, sg, sg_len, arg, blocks, blksz,
>> -             write);
>> +     mmc_ffu_prepare_mrq(card, &mrq, sg, sg_len, arg, blocks, blksz);
>>       mmc_wait_for_req(card->host, &mrq);
>>
>>       mmc_ffu_wait_busy(card);
>> @@ -175,19 +173,17 @@ static int mmc_ffu_simple_transfer(struct
>> mmc_card *card,
>>   * Map memory into a scatterlist.
>>   */
>>  static unsigned int mmc_ffu_map_sg(struct mmc_ffu_mem *mem, int size,
>> -     struct scatterlist *sglist, unsigned int max_segs,
>> -     unsigned int max_seg_sz)
>> +     struct scatterlist *sglist)
>>  {
>>       struct scatterlist *sg = sglist;
>>       unsigned int i;
>>       unsigned long sz = size;
>> -     unsigned int sctr_len = 0;
>>       unsigned long len;
>>
>> -     sg_init_table(sglist, max_segs);
>> +     sg_init_table(sglist, mem->cnt);
>>
>> -     for (i = 0; i < mem->cnt && sz; i++, sz -= len) {
>> -             len = PAGE_SIZE * (1 << mem->arr[i].order);
>> +     for (i = 0; i < mem->cnt && sz; i++, sg++, sz -= len) {
>> +             len = PAGE_SIZE << mem->arr[i].order;
>>
>>               if (len > sz) {
>>                       len = sz;
>> @@ -195,12 +191,10 @@ static unsigned int mmc_ffu_map_sg(struct
>> mmc_ffu_mem *mem, int size,
>>               }
>>
>>               sg_set_page(sg, mem->arr[i].page, len, 0);
>> -             sg = sg_next(sg);
>> -             sctr_len += 1;
>>       }
>>       sg_mark_end(sg);
>>
>> -     return sctr_len;
>> +     return mem->cnt;
>>  }
>>
>>  static void mmc_ffu_free_mem(struct mmc_ffu_mem *mem) { @@ -277,6
>> +271,8 @@ static struct mmc_ffu_mem *mmc_ffu_alloc_mem(unsigned
>> long min_sz,
>>               mem->arr[mem->cnt].page = page;
>>               mem->arr[mem->cnt].order = order;
>>               mem->cnt += 1;
>> +             pr_debug("FFU: cnt: %d - order %d\n", mem->cnt, order);
>> +
>>               if (max_page_cnt <= (1UL << order))
>>                       break;
>>               max_page_cnt -= 1UL << order;
>> @@ -298,11 +294,11 @@ out_free:
>>   * Copy the data to the allocated pages.
>>   */
>>  static int mmc_ffu_area_init(struct mmc_ffu_area *area, struct mmc_card
>> *card,
>> -     u8 *data, int size)
>> +     const u8 *data, int size)
>>  {
>>       int ret;
>>       int i;
>> -     int length = 0;
>> +     int length = 0, page_length;
>>
>>       area->max_tfr = size;
>>
>> @@ -323,20 +319,20 @@ static int mmc_ffu_area_init(struct mmc_ffu_area
>> *area, struct mmc_card *card,
>>                       goto out_free;
>>               }
>>
>> +             page_length = PAGE_SIZE << area->mem->arr[i].order;
>>               memcpy(page_address(area->mem->arr[i].page), data +
>> length,
>> -                     min(size - length, (int)area->max_seg_sz));
>> -             length += area->max_seg_sz;
>> +                     min(size - length, page_length));
>> +             length += page_length;
>>       }
>>
>>       area->sg = kmalloc(sizeof(struct scatterlist) * area->mem->cnt,
>> -             GFP_KERNEL);
>> +                        GFP_KERNEL);
>>       if (!area->sg) {
>>               ret = -ENOMEM;
>>               goto out_free;
>>       }
>>
>> -     area->sg_len = mmc_ffu_map_sg(area->mem, size, area->sg,
>> -             area->max_segs, area->mem->cnt);
>> +     area->sg_len = mmc_ffu_map_sg(area->mem, size, area->sg);
>>
>>       return 0;
>>
>> @@ -345,7 +341,7 @@ out_free:
>>       return ret;
>>  }
>>
>> -static int mmc_ffu_write(struct mmc_card *card, u8 *src, u32 arg,
>> +static int mmc_ffu_write(struct mmc_card *card, const u8 *src, u32 arg,
>>       int size)
>>  {
>>       int rc;
>> @@ -370,7 +366,8 @@ static int mmc_ffu_write(struct mmc_card *card, u8
>> *src, u32 arg,
>>                       goto exit;
>>
>>               rc = mmc_ffu_simple_transfer(card, area.sg, area.sg_len, arg,
>> -                     max_tfr / CARD_BLOCK_SIZE, CARD_BLOCK_SIZE, 1);
>> +                     max_tfr / CARD_BLOCK_SIZE, CARD_BLOCK_SIZE);
>> +             mmc_ffu_area_cleanup(&area);
>>               if (rc != 0)
>>                       goto exit;
>>
>> @@ -379,7 +376,6 @@ static int mmc_ffu_write(struct mmc_card *card, u8
>> *src, u32 arg,
>>       } while (size > 0);
>>
>>  exit:
>> -     mmc_ffu_area_cleanup(&area);
>>       return rc;
>>  }
>>
>> @@ -406,47 +402,39 @@ exit:
>>       return err;
>>  }
>>
>> -int mmc_ffu_download(struct mmc_card *card, struct mmc_command
>> *cmd,
>> -     u8 *data, int buf_bytes)
>> +int mmc_ffu_download(struct mmc_card *card, const char *name)
>>  {
>>       u8 ext_csd[CARD_BLOCK_SIZE];
>>       int err;
>>       int ret;
>> -     u8 *buf = NULL;
>> +     u32 arg;
>>       const struct firmware *fw;
>>
>> -     /* Read the EXT_CSD */
>> -     err = mmc_send_ext_csd(card, ext_csd);
>> -     if (err) {
>> -             pr_err("FFU: %s: error %d sending ext_csd\n",
>> -                     mmc_hostname(card->host), err);
>> +     pr_debug("FFU: %s uploading firmware %.20s to device\n",
>> +              mmc_hostname(card->host), name);
>> +
>> +     if (strlen(name) > 512) {
>> +             err = -EINVAL;
>> +             pr_err("FFU: %s: %.20s is not a valid argument\n",
>> +                    mmc_hostname(card->host), name);
>>               goto exit;
>>       }
>>
>> -     /* check if card is eMMC 5.0 or higher */
>> -     if (card->ext_csd.rev < 7)
>> -             return -EINVAL;
>> -
>>       /* Check if FFU is supported */
>> -     if (!FFU_SUPPORTED_MODE(ext_csd[EXT_CSD_SUPPORTED_MODE])
>> ||
>> -             FFU_CONFIG(ext_csd[EXT_CSD_FW_CONFIG])) {
>> -             err = -EINVAL;
>> +     if (!card->ext_csd.ffu_capable) {
>> +             err = -EOPNOTSUPP;
>>               pr_err("FFU: %s: error %d FFU is not supported\n",
>>                       mmc_hostname(card->host), err);
>>               goto exit;
>>       }
>>
>> -     /* setup FW data buffer */
>> -     err = request_firmware(&fw, data, &card->dev);
>> +     /* setup FW name buffer */
>> +     mmc_put_card(card);
>> +     err = request_firmware(&fw, name, &card->dev);
>> +     mmc_get_card(card);
>>       if (err) {
>>               pr_err("Firmware request failed %d\n", err);
>> -             goto exit_normal;
>> -     }
>> -
>> -     buf = kmalloc(fw->size, GFP_KERNEL);
>> -     if (buf == NULL) {
>> -             pr_err("Allocating memory for firmware failed!\n");
>> -             goto exit_normal;
>> +             goto exit;
>>       }
>>
>>       if ((fw->size % CARD_BLOCK_SIZE)) {
>> @@ -454,9 +442,16 @@ int mmc_ffu_download(struct mmc_card *card,
>> struct mmc_command *cmd,
>>                       mmc_hostname(card->host), fw->size);
>>       }
>>
>> -     memcpy(buf, fw->data, fw->size);
>> +     /* Read the EXT_CSD */
>> +     err = mmc_send_ext_csd(card, ext_csd);
>> +     if (err) {
>> +             pr_err("FFU: %s: error %d sending ext_csd\n",
>> +                     mmc_hostname(card->host), err);
>> +             goto exit;
>> +     }
>>
>>       /* set device to FFU mode */
>> +     pr_debug("FFU: %s switch to FFU mode\n", mmc_hostname(card-
>> >host));
>>       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> EXT_CSD_MODE_CONFIG,
>>               MMC_FFU_MODE_SET, card->ext_csd.generic_cmd6_time);
>>       if (err) {
>> @@ -466,18 +461,18 @@ int mmc_ffu_download(struct mmc_card *card,
>> struct mmc_command *cmd,
>>       }
>>
>>       /* set CMD ARG */
>> -     cmd->arg = ext_csd[EXT_CSD_FFU_ARG] |
>> +     arg = ext_csd[EXT_CSD_FFU_ARG] |
>>               ext_csd[EXT_CSD_FFU_ARG + 1] << 8 |
>>               ext_csd[EXT_CSD_FFU_ARG + 2] << 16 |
>>               ext_csd[EXT_CSD_FFU_ARG + 3] << 24;
>>
>> -     err = mmc_ffu_write(card, buf, cmd->arg, (int)fw->size);
>> +     err = mmc_ffu_write(card, fw->data, arg, (int)fw->size);
>>
>>  exit_normal:
>>       release_firmware(fw);
>> -     kfree(buf);
>>
>>       /* host switch back to work in normal MMC Read/Write commands
>> */
>> +     pr_debug("FFU: %s switch to normal mode\n", mmc_hostname(card-
>> >host));
>>       ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>               EXT_CSD_MODE_CONFIG, MMC_FFU_MODE_NORMAL,
>>               card->ext_csd.generic_cmd6_time);
>> @@ -495,6 +490,8 @@ int mmc_ffu_install(struct mmc_card *card)
>>       u32 ffu_data_len;
>>       u32 timeout;
>>
>> +     pr_debug("FFU: %s installing firmware to device\n",
>> +              mmc_hostname(card->host));
>>       err = mmc_send_ext_csd(card, ext_csd);
>>       if (err) {
>>               pr_err("FFU: %s: error %d sending ext_csd\n", @@ -503,9
>> +500,8 @@ int mmc_ffu_install(struct mmc_card *card)
>>       }
>>
>>       /* Check if FFU is supported */
>> -     if (!FFU_SUPPORTED_MODE(ext_csd[EXT_CSD_SUPPORTED_MODE])
>> ||
>> -             FFU_CONFIG(ext_csd[EXT_CSD_FW_CONFIG])) {
>> -             err = -EINVAL;
>> +     if (!card->ext_csd.ffu_capable) {
>> +             err = -EOPNOTSUPP;
>>               pr_err("FFU: %s: error %d FFU is not supported\n",
>>                       mmc_hostname(card->host), err);
>>               goto exit;
>> @@ -514,19 +510,20 @@ int mmc_ffu_install(struct mmc_card *card)
>>       /* check mode operation */
>>       if (!FFU_FEATURES(ext_csd[EXT_CSD_FFU_FEATURES])) {
>>               /* restart the eMMC */
>> +             mmc_put_card(card);
>>               err = mmc_ffu_restart(card);
>> +             mmc_get_card(card);
>>               if (err) {
>>                       pr_err("FFU: %s: error %d FFU install:\n",
>>                               mmc_hostname(card->host), err);
>>               }
>>       } else {
>> -
>>               ffu_data_len =
>> ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG]|
>>                       ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG + 1] <<
>> 8 |
>>                       ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG + 2] <<
>> 16 |
>>                       ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG + 3] <<
>> 24;
>>
>> -             if (!ffu_data_len) {
>> +             if (ffu_data_len == 0) {
>>                       err = -EPERM;
>>                       return err;
>>               }
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index
>> 4099424..ace9123 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -552,6 +552,14 @@ static int mmc_read_ext_csd(struct mmc_card
>> *card, u8 *ext_csd)
>>               card->ext_csd.data_sector_size = 512;
>>       }
>>
>> +     /* eMMC v5 or later */
>> +     if (card->ext_csd.rev >= 7) {
>> +             card->ext_csd.ffu_capable =
>> +                     ((ext_csd[EXT_CSD_SUPPORTED_MODE] & 1) == 1)
>> &&
>> +                     ((ext_csd[EXT_CSD_FW_CONFIG] & 1) == 0);
>> +     } else {
>> +             card->ext_csd.ffu_capable = false;
>> +     }
>>  out:
>>       return err;
>>  }
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index
>> 6a5c754..6a7de8d 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -87,6 +87,7 @@ struct mmc_ext_csd {
>>       unsigned int            data_tag_unit_size;     /* DATA TAG UNIT size 
>> */
>>       unsigned int            boot_ro_lock;           /* ro lock support */
>>       bool                    boot_ro_lockable;
>> +     bool                    ffu_capable;  /* support Firmware Field
>> Upgrade */
>>       u8                      raw_exception_status;   /* 54 */
>>       u8                      raw_partition_support;  /* 160 */
>>       u8                      raw_rpmb_size_mult;     /* 168 */
>> diff --git a/include/linux/mmc/ffu.h b/include/linux/mmc/ffu.h index
>> f5dcedb..a0ade1b 100644
>> --- a/include/linux/mmc/ffu.h
>> +++ b/include/linux/mmc/ffu.h
>> @@ -34,19 +34,10 @@
>>  #define MMC_FFU_INSTALL_SET 0x1
>>
>>  #ifdef CONFIG_MMC_FFU
>> -#define MMC_FFU_ENABLE 0x0
>> -#define MMC_FFU_CONFIG 0x1
>> -#define MMC_FFU_SUPPORTED_MODES 0x1
>>  #define MMC_FFU_FEATURES 0x1
>> +#define FFU_FEATURES(ffu_features) (ffu_features & MMC_FFU_FEATURES)
>>
>> -#define FFU_ENABLED(ffu_enable)      (ffu_enable & MMC_FFU_CONFIG)
>> -#define FFU_SUPPORTED_MODE(ffu_sup_mode) \
>> -     (ffu_sup_mode && MMC_FFU_SUPPORTED_MODES)
>> -#define FFU_CONFIG(ffu_config) (ffu_config & MMC_FFU_CONFIG) -
>> #define FFU_FEATURES(ffu_fetures) (ffu_fetures & MMC_FFU_FEATURES)
>> -
>> -int mmc_ffu_download(struct mmc_card *card, struct mmc_command
>> *cmd,
>> -     u8 *data, int buf_bytes);
>> +int mmc_ffu_download(struct mmc_card *card, const char *name);
>>  int mmc_ffu_install(struct mmc_card *card);  #else  static inline int
>> mmc_ffu_download(struct mmc_card *card,
>> --
>> 2.0.0.526.g5318336
>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to