Skip to content

Commit 4d4a2c7

Browse files
linuswstorulf
authored andcommitted
mmc: sh_mmcif: Advance sg_miter before reading blocks
The introduction of sg_miter was a bit sloppy as it didn't exactly mimic the semantics of the old code on multiblock reads and writes: these like you to: - Advance to the first sglist entry *before* starting to read any blocks from the card. - Advance and check availability of the next entry *right after* processing one block. Not checking if we have more sglist entries right after reading a block will lead to this not being checked until we return to the callback to read out more blocks, i.e. until the next interrupt arrives. Since the last block is the last one (no more data will arrive) there will not be a next interrupt, and we will be waiting forever resulting in a timeout for command 18 when reading multiple blocks. The same bug was fixed also in the writing of multiple blocks. Reported-by: Geert Uytterhoeven <geert@linux-m68k.org> Fixes: 27b5727 ("mmc: sh_mmcif: Use sg_miter for PIO") Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be> Link: https://lore.kernel.org/r/20240221-fix-sh-mmcif-v2-2-5e521eb25ae4@linaro.org Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent 727cba7 commit 4d4a2c7

File tree

1 file changed

+26
-12
lines changed

1 file changed

+26
-12
lines changed

drivers/mmc/host/sh_mmcif.c

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,7 @@ static bool sh_mmcif_read_block(struct sh_mmcif_host *host)
653653
static void sh_mmcif_multi_read(struct sh_mmcif_host *host,
654654
struct mmc_request *mrq)
655655
{
656+
struct sg_mapping_iter *sgm = &host->sg_miter;
656657
struct mmc_data *data = mrq->data;
657658

658659
if (!data->sg_len || !data->sg->length)
@@ -661,9 +662,15 @@ static void sh_mmcif_multi_read(struct sh_mmcif_host *host,
661662
host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
662663
BLOCK_SIZE_MASK;
663664

664-
sg_miter_start(&host->sg_miter, data->sg, data->sg_len,
665+
sg_miter_start(sgm, data->sg, data->sg_len,
665666
SG_MITER_TO_SG);
666667

668+
/* Advance to the first sglist entry */
669+
if (!sg_miter_next(sgm)) {
670+
sg_miter_stop(sgm);
671+
return;
672+
}
673+
667674
host->wait_for = MMCIF_WAIT_FOR_MREAD;
668675

669676
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
@@ -684,11 +691,6 @@ static bool sh_mmcif_mread_block(struct sh_mmcif_host *host)
684691
return false;
685692
}
686693

687-
if (!sg_miter_next(sgm)) {
688-
sg_miter_stop(sgm);
689-
return false;
690-
}
691-
692694
p = sgm->addr;
693695

694696
for (i = 0; i < host->blocksize / 4; i++)
@@ -698,6 +700,11 @@ static bool sh_mmcif_mread_block(struct sh_mmcif_host *host)
698700

699701
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
700702

703+
if (!sg_miter_next(sgm)) {
704+
sg_miter_stop(sgm);
705+
return false;
706+
}
707+
701708
return true;
702709
}
703710

@@ -756,6 +763,7 @@ static bool sh_mmcif_write_block(struct sh_mmcif_host *host)
756763
static void sh_mmcif_multi_write(struct sh_mmcif_host *host,
757764
struct mmc_request *mrq)
758765
{
766+
struct sg_mapping_iter *sgm = &host->sg_miter;
759767
struct mmc_data *data = mrq->data;
760768

761769
if (!data->sg_len || !data->sg->length)
@@ -764,9 +772,15 @@ static void sh_mmcif_multi_write(struct sh_mmcif_host *host,
764772
host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
765773
BLOCK_SIZE_MASK;
766774

767-
sg_miter_start(&host->sg_miter, data->sg, data->sg_len,
775+
sg_miter_start(sgm, data->sg, data->sg_len,
768776
SG_MITER_FROM_SG);
769777

778+
/* Advance to the first sglist entry */
779+
if (!sg_miter_next(sgm)) {
780+
sg_miter_stop(sgm);
781+
return;
782+
}
783+
770784
host->wait_for = MMCIF_WAIT_FOR_MWRITE;
771785

772786
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
@@ -787,18 +801,18 @@ static bool sh_mmcif_mwrite_block(struct sh_mmcif_host *host)
787801
return false;
788802
}
789803

790-
if (!sg_miter_next(sgm)) {
791-
sg_miter_stop(sgm);
792-
return false;
793-
}
794-
795804
p = sgm->addr;
796805

797806
for (i = 0; i < host->blocksize / 4; i++)
798807
sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++);
799808

800809
sgm->consumed = host->blocksize;
801810

811+
if (!sg_miter_next(sgm)) {
812+
sg_miter_stop(sgm);
813+
return false;
814+
}
815+
802816
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
803817

804818
return true;

0 commit comments

Comments
 (0)