aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-07-13 19:47:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-07-13 19:47:31 -0400
commit51414d41084496aaefd06d7f19eb8206e8bfac2d (patch)
tree31c7624d28a564e1cc918a30b8570a3c001a9c7c
parent201f92e2ca789d529418da8fa027d5457f0df024 (diff)
parentf39b2dd9d065151a04f5996656d1f27a7eb32d45 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: mmc: core: Bus width testing needs to handle suspend/resume
-rw-r--r--drivers/mmc/core/mmc.c77
-rw-r--r--include/linux/mmc/card.h13
2 files changed, 63 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);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c6927a4d157f..6ad43554ac05 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -64,6 +64,19 @@ struct mmc_ext_csd {
64 unsigned long long enhanced_area_offset; /* Units: Byte */ 64 unsigned long long enhanced_area_offset; /* Units: Byte */
65 unsigned int enhanced_area_size; /* Units: KB */ 65 unsigned int enhanced_area_size; /* Units: KB */
66 unsigned int boot_size; /* in bytes */ 66 unsigned int boot_size; /* in bytes */
67 u8 raw_partition_support; /* 160 */
68 u8 raw_erased_mem_count; /* 181 */
69 u8 raw_ext_csd_structure; /* 194 */
70 u8 raw_card_type; /* 196 */
71 u8 raw_s_a_timeout; /* 217 */
72 u8 raw_hc_erase_gap_size; /* 221 */
73 u8 raw_erase_timeout_mult; /* 223 */
74 u8 raw_hc_erase_grp_size; /* 224 */
75 u8 raw_sec_trim_mult; /* 229 */
76 u8 raw_sec_erase_mult; /* 230 */
77 u8 raw_sec_feature_support;/* 231 */
78 u8 raw_trim_mult; /* 232 */
79 u8 raw_sectors[4]; /* 212 - 4 bytes */
67}; 80};
68 81
69struct sd_scr { 82struct sd_scr {