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:
committed by
Greg Kroah-Hartman
parent
c00372e41b
commit
19e22f1e68
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user