[U-Boot] [PATCH 03/10] mmc: rpmb: add mmc_rpmb_route_frames()

Igor Opaniuk igor.opaniuk at linaro.org
Thu Aug 16 12:13:39 UTC 2018


As I didn't have any available Hikey board, tested this on Poplar:

Tested-by: Igor Opaniuk <igor.opaniuk at linaro.org>

BTW, we've had it up for discussion already, but just to clarify and summarize:
As ID of eMMC is hardcoded in the OP-TEE OS core (CFG_RPMB_FS_DEV_ID),
we will probably have issues on some platforms, where there is a
difference in the probe order of MMC controllers (for example, on
Poplar eMMC is 0 in U-boot, but in Linux it's 1, as SD is enumerated
as 0).
I guess it's unlikely that people will introduce changes to
U-boot/Linux to make this order conform to each other, so instead, we
should let the Normal World-part to decide what eMMC id to use from
these RPMB frames.

Added Joakim and Jerome so they can follow this thread.

Thanks

On 13 August 2018 at 18:53, Jens Wiklander <jens.wiklander at linaro.org> wrote:
> Adds mmc_rpmb_route_frames() to route RPMB data frames from/to an
> external entity.
>
> Signed-off-by: Jens Wiklander <jens.wiklander at linaro.org>
> ---
>  drivers/mmc/rpmb.c | 160 +++++++++++++++++++++++++++++++++++++++++++++
>  include/mmc.h      |   2 +
>  2 files changed, 162 insertions(+)
>
> diff --git a/drivers/mmc/rpmb.c b/drivers/mmc/rpmb.c
> index dfbdb0deb107..908f19208955 100644
> --- a/drivers/mmc/rpmb.c
> +++ b/drivers/mmc/rpmb.c
> @@ -321,3 +321,163 @@ int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk,
>         }
>         return i;
>  }
> +
> +static int send_write_mult_block(struct mmc *mmc, const struct s_rpmb *frm,
> +                                unsigned short cnt)
> +{
> +       struct mmc_cmd cmd = {
> +               .cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK,
> +               .resp_type = MMC_RSP_R1b,
> +       };
> +       struct mmc_data data = {
> +               .src = (const void *)frm,
> +               .blocks = cnt,
> +               .blocksize = sizeof(*frm),
> +               .flags = MMC_DATA_WRITE,
> +       };
> +
> +       return mmc_send_cmd(mmc, &cmd, &data);
> +}
> +
> +static int send_read_mult_block(struct mmc *mmc, struct s_rpmb *frm,
> +                               unsigned short cnt)
> +{
> +       struct mmc_cmd cmd = {
> +               .cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK,
> +               .resp_type = MMC_RSP_R1,
> +       };
> +       struct mmc_data data = {
> +               .dest = (void *)frm,
> +               .blocks = cnt,
> +               .blocksize = sizeof(*frm),
> +               .flags = MMC_DATA_READ,
> +       };
> +
> +       return mmc_send_cmd(mmc, &cmd, &data);
> +}
> +
> +static int rpmb_route_write_req(struct mmc *mmc, struct s_rpmb *req,
> +                               unsigned short req_cnt, struct s_rpmb *rsp,
> +                               unsigned short rsp_cnt)
> +{
> +       int ret;
> +
> +       /*
> +        * Send the write request.
> +        */
> +       ret = mmc_set_blockcount(mmc, req_cnt, true);
> +       if (ret)
> +               return ret;
> +
> +       ret = send_write_mult_block(mmc, req, req_cnt);
> +       if (ret)
> +               return ret;
> +
> +       /*
> +        * Read the result of the request.
> +        */
> +       ret = mmc_set_blockcount(mmc, 1, false);
> +       if (ret)
> +               return ret;
> +
> +       memset(rsp, 0, sizeof(*rsp));
> +       rsp->request = cpu_to_be16(RPMB_REQ_STATUS);
> +       ret = send_write_mult_block(mmc, rsp, 1);
> +       if (ret)
> +               return ret;
> +
> +       ret = mmc_set_blockcount(mmc, 1, false);
> +       if (ret)
> +               return ret;
> +
> +       return send_read_mult_block(mmc, rsp, 1);
> +}
> +
> +static int rpmb_route_read_req(struct mmc *mmc, struct s_rpmb *req,
> +                              unsigned short req_cnt, struct s_rpmb *rsp,
> +                              unsigned short rsp_cnt)
> +{
> +       int ret;
> +
> +       /*
> +        * Send the read request.
> +        */
> +       ret = mmc_set_blockcount(mmc, 1, false);
> +       if (ret)
> +               return ret;
> +
> +       ret = send_write_mult_block(mmc, req, 1);
> +       if (ret)
> +               return ret;
> +
> +       /*
> +        * Read the result of the request.
> +        */
> +
> +       ret = mmc_set_blockcount(mmc, rsp_cnt, false);
> +       if (ret)
> +               return ret;
> +
> +       return send_read_mult_block(mmc, rsp, rsp_cnt);
> +}
> +
> +static int rpmb_route_frames(struct mmc *mmc, struct s_rpmb *req,
> +                            unsigned short req_cnt, struct s_rpmb *rsp,
> +                            unsigned short rsp_cnt)
> +{
> +       unsigned short n;
> +
> +       /*
> +        * If multiple request frames are provided, make sure that all are
> +        * of the same type.
> +        */
> +       for (n = 1; n < req_cnt; n++)
> +               if (req[n].request != req->request)
> +                       return -EINVAL;
> +
> +       switch (be16_to_cpu(req->request)) {
> +       case RPMB_REQ_KEY:
> +               if (req_cnt != 1 || rsp_cnt != 1)
> +                       return -EINVAL;
> +               return rpmb_route_write_req(mmc, req, req_cnt, rsp, rsp_cnt);
> +
> +       case RPMB_REQ_WRITE_DATA:
> +               if (!req_cnt || rsp_cnt != 1)
> +                       return -EINVAL;
> +               return rpmb_route_write_req(mmc, req, req_cnt, rsp, rsp_cnt);
> +
> +       case RPMB_REQ_WCOUNTER:
> +               if (req_cnt != 1 || rsp_cnt != 1)
> +                       return -EINVAL;
> +               return rpmb_route_read_req(mmc, req, req_cnt, rsp, rsp_cnt);
> +
> +       case RPMB_REQ_READ_DATA:
> +               if (req_cnt != 1 || !req_cnt)
> +                       return -EINVAL;
> +               return rpmb_route_read_req(mmc, req, req_cnt, rsp, rsp_cnt);
> +
> +       default:
> +               debug("Unsupported message type: %d\n",
> +                     be16_to_cpu(req->request));
> +               return -EINVAL;
> +       }
> +}
> +
> +int mmc_rpmb_route_frames(struct mmc *mmc, void *req, unsigned long reqlen,
> +                         void *rsp, unsigned long rsplen)
> +{
> +       /*
> +        * Whoever crafted the data supplied to this function knows how to
> +        * format the PRMB frames and which response is expected. If
> +        * there's some unexpected mismatch it's more helpful to report an
> +        * error immediately than trying to guess what was the intention
> +        * and possibly just delay an eventual error which will be harder
> +        * to track down.
> +        */
> +
> +       if (reqlen % sizeof(struct s_rpmb) || rsplen % sizeof(struct s_rpmb))
> +               return -EINVAL;
> +
> +       return rpmb_route_frames(mmc, req, reqlen / sizeof(struct s_rpmb),
> +                                rsp, rsplen / sizeof(struct s_rpmb));
> +}
> diff --git a/include/mmc.h b/include/mmc.h
> index df4255b828a7..d6e02af4edea 100644
> --- a/include/mmc.h
> +++ b/include/mmc.h
> @@ -748,6 +748,8 @@ int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk,
>                   unsigned short cnt, unsigned char *key);
>  int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk,
>                    unsigned short cnt, unsigned char *key);
> +int mmc_rpmb_route_frames(struct mmc *mmc, void *req, unsigned long reqlen,
> +                         void *rsp, unsigned long rsplen);
>  #ifdef CONFIG_CMD_BKOPS_ENABLE
>  int mmc_set_bkops_enable(struct mmc *mmc);
>  #endif
> --
> 2.17.1
>



-- 
Regards,
Igor Opaniuk


More information about the U-Boot mailing list