Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: check status after MMC SWITCH command

According to the standard, the SWITCH command should be followed by a
SEND_STATUS command to check for errors.

Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com>
Acked-by: Matt Fleming <matt@console-pimps.org>
Cc: Ian Molton <ian@mnementh.co.uk>
Cc: "Roberto A. Foglietta" <roberto.foglietta@gmail.com>
Cc: Jarkko Lavinen <jarkko.lavinen@nokia.com>
Cc: Denis Karpov <ext-denis.2.karpov@nokia.com>
Cc: Pierre Ossman <pierre@ossman.eu>
Cc: Philip Langdale <philipl@overt.org>
Cc: "Madhusudhan" <madhu.cr@ti.com>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Adrian Hunter and committed by
Linus Torvalds
ef0b27d4 53509f0f

+42 -6
+18 -6
drivers/mmc/core/mmc.c
··· 416 416 (host->caps & MMC_CAP_MMC_HIGHSPEED)) { 417 417 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 418 418 EXT_CSD_HS_TIMING, 1); 419 - if (err) 419 + if (err && err != -EBADMSG) 420 420 goto free_card; 421 421 422 - mmc_card_set_highspeed(card); 423 - 424 - mmc_set_timing(card->host, MMC_TIMING_MMC_HS); 422 + if (err) { 423 + printk(KERN_WARNING "%s: switch to highspeed failed\n", 424 + mmc_hostname(card->host)); 425 + err = 0; 426 + } else { 427 + mmc_card_set_highspeed(card); 428 + mmc_set_timing(card->host, MMC_TIMING_MMC_HS); 429 + } 425 430 } 426 431 427 432 /* ··· 461 456 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 462 457 EXT_CSD_BUS_WIDTH, ext_csd_bit); 463 458 464 - if (err) 459 + if (err && err != -EBADMSG) 465 460 goto free_card; 466 461 467 - mmc_set_bus_width(card->host, bus_width); 462 + if (err) { 463 + printk(KERN_WARNING "%s: switch to bus width %d " 464 + "failed\n", mmc_hostname(card->host), 465 + 1 << bus_width); 466 + err = 0; 467 + } else { 468 + mmc_set_bus_width(card->host, bus_width); 469 + } 468 470 } 469 471 470 472 if (!oldcard)
+23
drivers/mmc/core/mmc_ops.c
··· 390 390 { 391 391 int err; 392 392 struct mmc_command cmd; 393 + u32 status; 393 394 394 395 BUG_ON(!card); 395 396 BUG_ON(!card->host); ··· 407 406 err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); 408 407 if (err) 409 408 return err; 409 + 410 + /* Must check status to be sure of no errors */ 411 + do { 412 + err = mmc_send_status(card, &status); 413 + if (err) 414 + return err; 415 + if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) 416 + break; 417 + if (mmc_host_is_spi(card->host)) 418 + break; 419 + } while (R1_CURRENT_STATE(status) == 7); 420 + 421 + if (mmc_host_is_spi(card->host)) { 422 + if (status & R1_SPI_ILLEGAL_COMMAND) 423 + return -EBADMSG; 424 + } else { 425 + if (status & 0xFDFFA000) 426 + printk(KERN_WARNING "%s: unexpected status %#x after " 427 + "switch", mmc_hostname(card->host), status); 428 + if (status & R1_SWITCH_ERROR) 429 + return -EBADMSG; 430 + } 410 431 411 432 return 0; 412 433 }
+1
include/linux/mmc/mmc.h
··· 128 128 #define R1_STATUS(x) (x & 0xFFFFE000) 129 129 #define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ 130 130 #define R1_READY_FOR_DATA (1 << 8) /* sx, a */ 131 + #define R1_SWITCH_ERROR (1 << 7) /* sx, c */ 131 132 #define R1_APP_CMD (1 << 5) /* sr, c */ 132 133 133 134 /*