mmc: core: Adjust ACMD22 to SDUC

BugLink: https://bugs.launchpad.net/bugs/2102118

[ 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>
[koichiroden: #include <asm/unaligned.h> instead of <linux/unaligned.h>
as upstream commit 5f60d5f6bbc1 ("move asm/unaligned.h to
linux/unaligned.h") is missing]
Signed-off-by: Koichiro Den <koichiro.den@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
This commit is contained in:
Avri Altman
2025-03-12 22:51:00 +09:00
committed by Stefan Bader
parent 39586b18b5
commit ec8c9d05e7
+18 -6
View File
@@ -48,6 +48,7 @@
#include <linux/mmc/sd.h>
#include <linux/uaccess.h>
#include <asm/unaligned.h>
#include "queue.h"
#include "block.h"
@@ -947,11 +948,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);
@@ -962,7 +962,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;
@@ -972,15 +972,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)