mmc: rpmb: Fix driver routing memory alignment with tmp buffer
authorlitchipi <litchi.pi@protonmail.com>
Tue, 15 Jun 2021 08:53:06 +0000 (08:53 +0000)
committerPeng Fan <peng.fan@nxp.com>
Fri, 30 Jul 2021 09:12:15 +0000 (17:12 +0800)
Fix mmc_rpmb_route_frames() implementation to comply with most MMC
drivers that expect some alignment of MMC data frames in memory.

When called from drivers/tee/optee/rpmb.c, the address passed is not
aligned properly. OP-TEE OS inserts a 6-byte header before a raw RPMB
frame which makes RPMB data buffer not 32bit aligned. To prevent breaking
ABI with OPTEE-OS RPC memrefs, allocate a temporary buffer to copy the
data into an aligned memory.

Many RPMB drivers implicitly expect 32bit alignment of the eMMC frame
including arm_pl180_mmci.c, sandbox_mmc.c and stm32_sdmmc2.c

Signed-off-by: Timothée Cercueil <timothee.cercueil@st.com>
Signed-off-by: Timothée Cercueil <litchi.pi@protonmail.com>
Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>
drivers/mmc/rpmb.c

index ea7e506..b68d985 100644 (file)
@@ -480,10 +480,24 @@ int mmc_rpmb_route_frames(struct mmc *mmc, void *req, unsigned long reqlen,
         * and possibly just delay an eventual error which will be harder
         * to track down.
         */
+       void *rpmb_data = NULL;
+       int ret;
 
        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));
+       if (!IS_ALIGNED((uintptr_t)req, ARCH_DMA_MINALIGN)) {
+               /* Memory alignment is required by MMC driver */
+               rpmb_data = malloc(reqlen);
+               if (!rpmb_data)
+                       return -ENOMEM;
+
+               memcpy(rpmb_data, req, reqlen);
+               req = rpmb_data;
+       }
+
+       ret = rpmb_route_frames(mmc, req, reqlen / sizeof(struct s_rpmb),
+                               rsp, rsplen / sizeof(struct s_rpmb));
+       free(rpmb_data);
+       return ret;
 }