aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPhilip Rakity <prakity@marvell.com>2011-07-07 12:04:55 -0400
committerChris Ball <cjb@laptop.org>2011-07-13 14:54:37 -0400
commitf39b2dd9d065151a04f5996656d1f27a7eb32d45 (patch)
tree3801f7d6793529d737fcbfd6af05b6900ef2cd06 /drivers
parentc31b55cd4eaf050bb5a15bd8251da1b3c7edeb1c (diff)
mmc: core: Bus width testing needs to handle suspend/resume
On reading the ext_csd for the first time (in 1 bit mode), save the ext_csd information needed for bus width compare. On every pass we make re-reading the ext_csd, compare the data against the saved ext_csd data. This fixes a regression introduced in 3.0-rc1 by 08ee80cc397ac1a3 ("mmc: core: eMMC bus width may not work on all platforms"), which incorrectly assumed we would be re-reading the ext_csd at resume- time. Signed-off-by: Philip Rakity <prakity@marvell.com> Tested-by: Jaehoon Chung <jh80.chung@samsung.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/core/mmc.c77
1 files changed, 50 insertions, 27 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 2a7e43bc796d..aa7d1d79b8c5 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -247,12 +247,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
247 return 0; 247 return 0;
248 248
249 /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ 249 /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
250 card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE];
250 if (card->csd.structure == 3) { 251 if (card->csd.structure == 3) {
251 int ext_csd_struct = ext_csd[EXT_CSD_STRUCTURE]; 252 if (card->ext_csd.raw_ext_csd_structure > 2) {
252 if (ext_csd_struct > 2) {
253 printk(KERN_ERR "%s: unrecognised EXT_CSD structure " 253 printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
254 "version %d\n", mmc_hostname(card->host), 254 "version %d\n", mmc_hostname(card->host),
255 ext_csd_struct); 255 card->ext_csd.raw_ext_csd_structure);
256 err = -EINVAL; 256 err = -EINVAL;
257 goto out; 257 goto out;
258 } 258 }
@@ -266,6 +266,10 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
266 goto out; 266 goto out;
267 } 267 }
268 268
269 card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0];
270 card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1];
271 card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2];
272 card->ext_csd.raw_sectors[3] = ext_csd[EXT_CSD_SEC_CNT + 3];
269 if (card->ext_csd.rev >= 2) { 273 if (card->ext_csd.rev >= 2) {
270 card->ext_csd.sectors = 274 card->ext_csd.sectors =
271 ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | 275 ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
@@ -277,7 +281,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
277 if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512) 281 if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512)
278 mmc_card_set_blockaddr(card); 282 mmc_card_set_blockaddr(card);
279 } 283 }
280 284 card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
281 switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) { 285 switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
282 case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 | 286 case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
283 EXT_CSD_CARD_TYPE_26: 287 EXT_CSD_CARD_TYPE_26:
@@ -307,6 +311,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
307 mmc_hostname(card->host)); 311 mmc_hostname(card->host));
308 } 312 }
309 313
314 card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT];
315 card->ext_csd.raw_erase_timeout_mult =
316 ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
317 card->ext_csd.raw_hc_erase_grp_size =
318 ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
310 if (card->ext_csd.rev >= 3) { 319 if (card->ext_csd.rev >= 3) {
311 u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; 320 u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
312 card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG]; 321 card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG];
@@ -334,6 +343,16 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
334 card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; 343 card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
335 } 344 }
336 345
346 card->ext_csd.raw_hc_erase_gap_size =
347 ext_csd[EXT_CSD_PARTITION_ATTRIBUTE];
348 card->ext_csd.raw_sec_trim_mult =
349 ext_csd[EXT_CSD_SEC_TRIM_MULT];
350 card->ext_csd.raw_sec_erase_mult =
351 ext_csd[EXT_CSD_SEC_ERASE_MULT];
352 card->ext_csd.raw_sec_feature_support =
353 ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
354 card->ext_csd.raw_trim_mult =
355 ext_csd[EXT_CSD_TRIM_MULT];
337 if (card->ext_csd.rev >= 4) { 356 if (card->ext_csd.rev >= 4) {
338 /* 357 /*
339 * Enhanced area feature support -- check whether the eMMC 358 * Enhanced area feature support -- check whether the eMMC
@@ -341,7 +360,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
341 * area offset and size to user by adding sysfs interface. 360 * area offset and size to user by adding sysfs interface.
342 */ 361 */
343 if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && 362 if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
344 (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { 363 (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
345 u8 hc_erase_grp_sz = 364 u8 hc_erase_grp_sz =
346 ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 365 ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
347 u8 hc_wp_grp_sz = 366 u8 hc_wp_grp_sz =
@@ -401,17 +420,17 @@ static inline void mmc_free_ext_csd(u8 *ext_csd)
401} 420}
402 421
403 422
404static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd, 423static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
405 unsigned bus_width)
406{ 424{
407 u8 *bw_ext_csd; 425 u8 *bw_ext_csd;
408 int err; 426 int err;
409 427
428 if (bus_width == MMC_BUS_WIDTH_1)
429 return 0;
430
410 err = mmc_get_ext_csd(card, &bw_ext_csd); 431 err = mmc_get_ext_csd(card, &bw_ext_csd);
411 if (err)
412 return err;
413 432
414 if ((ext_csd == NULL || bw_ext_csd == NULL)) { 433 if (err || bw_ext_csd == NULL) {
415 if (bus_width != MMC_BUS_WIDTH_1) 434 if (bus_width != MMC_BUS_WIDTH_1)
416 err = -EINVAL; 435 err = -EINVAL;
417 goto out; 436 goto out;
@@ -421,35 +440,40 @@ static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
421 goto out; 440 goto out;
422 441
423 /* only compare read only fields */ 442 /* only compare read only fields */
424 err = (!(ext_csd[EXT_CSD_PARTITION_SUPPORT] == 443 err = (!(card->ext_csd.raw_partition_support ==
425 bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) && 444 bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
426 (ext_csd[EXT_CSD_ERASED_MEM_CONT] == 445 (card->ext_csd.raw_erased_mem_count ==
427 bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) && 446 bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
428 (ext_csd[EXT_CSD_REV] == 447 (card->ext_csd.rev ==
429 bw_ext_csd[EXT_CSD_REV]) && 448 bw_ext_csd[EXT_CSD_REV]) &&
430 (ext_csd[EXT_CSD_STRUCTURE] == 449 (card->ext_csd.raw_ext_csd_structure ==
431 bw_ext_csd[EXT_CSD_STRUCTURE]) && 450 bw_ext_csd[EXT_CSD_STRUCTURE]) &&
432 (ext_csd[EXT_CSD_CARD_TYPE] == 451 (card->ext_csd.raw_card_type ==
433 bw_ext_csd[EXT_CSD_CARD_TYPE]) && 452 bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
434 (ext_csd[EXT_CSD_S_A_TIMEOUT] == 453 (card->ext_csd.raw_s_a_timeout ==
435 bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) && 454 bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
436 (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == 455 (card->ext_csd.raw_hc_erase_gap_size ==
437 bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) && 456 bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
438 (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] == 457 (card->ext_csd.raw_erase_timeout_mult ==
439 bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) && 458 bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
440 (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == 459 (card->ext_csd.raw_hc_erase_grp_size ==
441 bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) && 460 bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
442 (ext_csd[EXT_CSD_SEC_TRIM_MULT] == 461 (card->ext_csd.raw_sec_trim_mult ==
443 bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) && 462 bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
444 (ext_csd[EXT_CSD_SEC_ERASE_MULT] == 463 (card->ext_csd.raw_sec_erase_mult ==
445 bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) && 464 bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
446 (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] == 465 (card->ext_csd.raw_sec_feature_support ==
447 bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) && 466 bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
448 (ext_csd[EXT_CSD_TRIM_MULT] == 467 (card->ext_csd.raw_trim_mult ==
449 bw_ext_csd[EXT_CSD_TRIM_MULT]) && 468 bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
450 memcmp(&ext_csd[EXT_CSD_SEC_CNT], 469 (card->ext_csd.raw_sectors[0] ==
451 &bw_ext_csd[EXT_CSD_SEC_CNT], 470 bw_ext_csd[EXT_CSD_SEC_CNT + 0]) &&
452 4) != 0); 471 (card->ext_csd.raw_sectors[1] ==
472 bw_ext_csd[EXT_CSD_SEC_CNT + 1]) &&
473 (card->ext_csd.raw_sectors[2] ==
474 bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
475 (card->ext_csd.raw_sectors[3] ==
476 bw_ext_csd[EXT_CSD_SEC_CNT + 3]));
453 if (err) 477 if (err)
454 err = -EINVAL; 478 err = -EINVAL;
455 479
@@ -770,7 +794,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
770 */ 794 */
771 if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST)) 795 if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
772 err = mmc_compare_ext_csds(card, 796 err = mmc_compare_ext_csds(card,
773 ext_csd,
774 bus_width); 797 bus_width);
775 else 798 else
776 err = mmc_bus_test(card, bus_width); 799 err = mmc_bus_test(card, bus_width);