| From 964b4eb785ead4ecd55eb876114390f8ac5d856f Mon Sep 17 00:00:00 2001 |
| From: Raul E Rangel <rrangel@chromium.org> |
| Date: Mon, 29 Apr 2019 11:32:39 -0600 |
| Subject: mmc: core: Verify SD bus width |
| |
| [ Upstream commit 9e4be8d03f50d1b25c38e2b59e73b194c130df7d ] |
| |
| The SD Physical Layer Spec says the following: Since the SD Memory Card |
| shall support at least the two bus modes 1-bit or 4-bit width, then any SD |
| Card shall set at least bits 0 and 2 (SD_BUS_WIDTH="0101"). |
| |
| This change verifies the card has specified a bus width. |
| |
| AMD SDHC Device 7806 can get into a bad state after a card disconnect |
| where anything transferred via the DATA lines will always result in a |
| zero filled buffer. Currently the driver will continue without error if |
| the HC is in this condition. A block device will be created, but reading |
| from it will result in a zero buffer. This makes it seem like the SD |
| device has been erased, when in actuality the data is never getting |
| copied from the DATA lines to the data buffer. |
| |
| SCR is the first command in the SD initialization sequence that uses the |
| DATA lines. By checking that the response was invalid, we can abort |
| mounting the card. |
| |
| Reviewed-by: Avri Altman <avri.altman@wdc.com> |
| Signed-off-by: Raul E Rangel <rrangel@chromium.org> |
| Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/mmc/core/sd.c | 8 ++++++++ |
| 1 file changed, 8 insertions(+) |
| |
| diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c |
| index 265e1aeeb9d88..d3d32f9a2cb18 100644 |
| --- a/drivers/mmc/core/sd.c |
| +++ b/drivers/mmc/core/sd.c |
| @@ -221,6 +221,14 @@ static int mmc_decode_scr(struct mmc_card *card) |
| |
| if (scr->sda_spec3) |
| scr->cmds = UNSTUFF_BITS(resp, 32, 2); |
| + |
| + /* SD Spec says: any SD Card shall set at least bits 0 and 2 */ |
| + if (!(scr->bus_widths & SD_SCR_BUS_WIDTH_1) || |
| + !(scr->bus_widths & SD_SCR_BUS_WIDTH_4)) { |
| + pr_err("%s: invalid bus width\n", mmc_hostname(card->host)); |
| + return -EINVAL; |
| + } |
| + |
| return 0; |
| } |
| |
| -- |
| 2.20.1 |
| |