mmc: core: Adjust ACMD22 to SDUC

[ Upstream commit 449f34a34088d02457fa0f3216747e8a35bc03ae ]

ACMD22 is used to verify the previously write operation.  Normally, it
returns the number of written sectors as u32.  SDUC, however, returns it
as u64.  This is not a superfluous requirement, because SDUC writes may
exceeds 2TB.  For Linux mmc however, the previously write operation
could not be more than the block layer limits, thus we make room for a
u64 and cast the returning value to u32.

Reviewed-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Avri Altman <avri.altman@wdc.com>
Link: https://lore.kernel.org/r/20241006051148.160278-8-avri.altman@wdc.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
[Stephen Rothwell: Fix build error when moving to new rc from Linus's tree]
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Stable-dep-of: 869d37475788 ("mmc: core: Use GFP_NOIO in ACMD22")
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Avri Altman
2024-10-06 08:11:45 +03:00
committed by Greg Kroah-Hartman
parent c00372e41b
commit 19e22f1e68

View File

@@ -50,6 +50,7 @@
#include <linux/mmc/sd.h>
#include <linux/uaccess.h>
#include <linux/unaligned.h>
#include "queue.h"
#include "block.h"
@@ -993,11 +994,10 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks)
int err;
u32 result;
__be32 *blocks;
u8 resp_sz = mmc_card_ult_capacity(card) ? 8 : 4;
struct mmc_request mrq = {};
struct mmc_command cmd = {};
struct mmc_data data = {};
struct scatterlist sg;
err = mmc_app_cmd(card->host, card);
@@ -1008,7 +1008,7 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks)
cmd.arg = 0;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = 4;
data.blksz = resp_sz;
data.blocks = 1;
data.flags = MMC_DATA_READ;
data.sg = &sg;
@@ -1018,15 +1018,27 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks)
mrq.cmd = &cmd;
mrq.data = &data;
blocks = kmalloc(4, GFP_KERNEL);
blocks = kmalloc(resp_sz, GFP_KERNEL);
if (!blocks)
return -ENOMEM;
sg_init_one(&sg, blocks, 4);
sg_init_one(&sg, blocks, resp_sz);
mmc_wait_for_req(card->host, &mrq);
result = ntohl(*blocks);
if (mmc_card_ult_capacity(card)) {
/*
* Normally, ACMD22 returns the number of written sectors as
* u32. SDUC, however, returns it as u64. This is not a
* superfluous requirement, because SDUC writes may exceed 2TB.
* For Linux mmc however, the previously write operation could
* not be more than the block layer limits, thus just make room
* for a u64 and cast the response back to u32.
*/
result = clamp_val(get_unaligned_be64(blocks), 0, UINT_MAX);
} else {
result = ntohl(*blocks);
}
kfree(blocks);
if (cmd.error || data.error)