aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core/mmc.c
diff options
context:
space:
mode:
authorPierre Ossman <drzeus@drzeus.cx>2007-05-01 10:00:02 -0400
committerPierre Ossman <drzeus@drzeus.cx>2007-05-01 10:00:02 -0400
commit6abaa0c9fec563538f2a28a682af8c89bb9b125c (patch)
tree1da7fb5a0b37bd57b38ca52c77ccc72b099fcbae /drivers/mmc/core/mmc.c
parent89a73cf52ba2ae4402c53487b71ec4475544f139 (diff)
mmc: support unsafe resume of cards
Since many have the system root on MMC/SD we must allow some foot shooting when it comes to resume. We cannot detect if a card is removed and reinserted during suspend, so the safe approach would be to assume it was, avoiding potential filesystem corruption. This will of course not work if you cannot release the card before suspend. This commit adds a compile time option that makes the MMC layer assume the card wasn't touched if it is redetected upon resume. Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/core/mmc.c')
-rw-r--r--drivers/mmc/core/mmc.c289
1 files changed, 192 insertions, 97 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 47449e870131..619581e49163 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -229,55 +229,13 @@ out:
229} 229}
230 230
231/* 231/*
232 * Host is being removed. Free up the current card. 232 * Handle the detection and initialisation of a card.
233 */ 233 *
234static void mmc_remove(struct mmc_host *host) 234 * In the case of a resume, "curcard" will contain the card
235{ 235 * we're trying to reinitialise.
236 BUG_ON(!host);
237 BUG_ON(!host->card);
238
239 mmc_remove_card(host->card);
240 host->card = NULL;
241}
242
243/*
244 * Card detection callback from host.
245 */
246static void mmc_detect(struct mmc_host *host)
247{
248 int err;
249
250 BUG_ON(!host);
251 BUG_ON(!host->card);
252
253 mmc_claim_host(host);
254
255 /*
256 * Just check if our card has been removed.
257 */
258 err = mmc_send_status(host->card, NULL);
259
260 mmc_release_host(host);
261
262 if (err != MMC_ERR_NONE) {
263 mmc_remove_card(host->card);
264 host->card = NULL;
265
266 mmc_claim_host(host);
267 mmc_detach_bus(host);
268 mmc_release_host(host);
269 }
270}
271
272static const struct mmc_bus_ops mmc_ops = {
273 .remove = mmc_remove,
274 .detect = mmc_detect,
275};
276
277/*
278 * Starting point for MMC card init.
279 */ 236 */
280int mmc_attach_mmc(struct mmc_host *host, u32 ocr) 237static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
238 struct mmc_card *oldcard)
281{ 239{
282 struct mmc_card *card; 240 struct mmc_card *card;
283 int err; 241 int err;
@@ -287,27 +245,6 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
287 BUG_ON(!host); 245 BUG_ON(!host);
288 BUG_ON(!host->claimed); 246 BUG_ON(!host->claimed);
289 247
290 mmc_attach_bus(host, &mmc_ops);
291
292 /*
293 * Sanity check the voltages that the card claims to
294 * support.
295 */
296 if (ocr & 0x7F) {
297 printk(KERN_WARNING "%s: card claims to support voltages "
298 "below the defined range. These will be ignored.\n",
299 mmc_hostname(host));
300 ocr &= ~0x7F;
301 }
302
303 host->ocr = mmc_select_voltage(host, ocr);
304
305 /*
306 * Can we support the voltage of the card?
307 */
308 if (!host->ocr)
309 goto err;
310
311 /* 248 /*
312 * Since we're changing the OCR value, we seem to 249 * Since we're changing the OCR value, we seem to
313 * need to tell some cards to go back to the idle 250 * need to tell some cards to go back to the idle
@@ -317,7 +254,9 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
317 mmc_go_idle(host); 254 mmc_go_idle(host);
318 255
319 /* The extra bit indicates that we support high capacity */ 256 /* The extra bit indicates that we support high capacity */
320 mmc_send_op_cond(host, host->ocr | (1 << 30), NULL); 257 err = mmc_send_op_cond(host, ocr | (1 << 30), NULL);
258 if (err != MMC_ERR_NONE)
259 goto err;
321 260
322 /* 261 /*
323 * Fetch CID from card. 262 * Fetch CID from card.
@@ -326,16 +265,23 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
326 if (err != MMC_ERR_NONE) 265 if (err != MMC_ERR_NONE)
327 goto err; 266 goto err;
328 267
329 /* 268 if (oldcard) {
330 * Allocate card structure. 269 if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
331 */ 270 goto err;
332 card = mmc_alloc_card(host); 271
333 if (IS_ERR(card)) 272 card = oldcard;
334 goto err; 273 } else {
274 /*
275 * Allocate card structure.
276 */
277 card = mmc_alloc_card(host);
278 if (IS_ERR(card))
279 goto err;
335 280
336 card->type = MMC_TYPE_MMC; 281 card->type = MMC_TYPE_MMC;
337 card->rca = 1; 282 card->rca = 1;
338 memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); 283 memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
284 }
339 285
340 /* 286 /*
341 * Set card RCA. 287 * Set card RCA.
@@ -346,15 +292,17 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
346 292
347 mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); 293 mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
348 294
349 /* 295 if (!oldcard) {
350 * Fetch CSD from card. 296 /*
351 */ 297 * Fetch CSD from card.
352 err = mmc_send_csd(card, card->raw_csd); 298 */
353 if (err != MMC_ERR_NONE) 299 err = mmc_send_csd(card, card->raw_csd);
354 goto free_card; 300 if (err != MMC_ERR_NONE)
301 goto free_card;
355 302
356 mmc_decode_csd(card); 303 mmc_decode_csd(card);
357 mmc_decode_cid(card); 304 mmc_decode_cid(card);
305 }
358 306
359 /* 307 /*
360 * Select card, as all following commands rely on that. 308 * Select card, as all following commands rely on that.
@@ -363,12 +311,14 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
363 if (err != MMC_ERR_NONE) 311 if (err != MMC_ERR_NONE)
364 goto free_card; 312 goto free_card;
365 313
366 /* 314 if (!oldcard) {
367 * Fetch and process extened CSD. 315 /*
368 */ 316 * Fetch and process extened CSD.
369 err = mmc_read_ext_csd(card); 317 */
370 if (err != MMC_ERR_NONE) 318 err = mmc_read_ext_csd(card);
371 goto free_card; 319 if (err != MMC_ERR_NONE)
320 goto free_card;
321 }
372 322
373 /* 323 /*
374 * Activate high speed (if supported) 324 * Activate high speed (if supported)
@@ -412,11 +362,157 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
412 mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); 362 mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
413 } 363 }
414 364
415 host->card = card; 365 if (!oldcard)
366 host->card = card;
367
368 return MMC_ERR_NONE;
369
370free_card:
371 if (!oldcard)
372 mmc_remove_card(card);
373err:
374
375 return MMC_ERR_FAILED;
376}
377
378/*
379 * Host is being removed. Free up the current card.
380 */
381static void mmc_remove(struct mmc_host *host)
382{
383 BUG_ON(!host);
384 BUG_ON(!host->card);
385
386 mmc_remove_card(host->card);
387 host->card = NULL;
388}
389
390/*
391 * Card detection callback from host.
392 */
393static void mmc_detect(struct mmc_host *host)
394{
395 int err;
396
397 BUG_ON(!host);
398 BUG_ON(!host->card);
399
400 mmc_claim_host(host);
401
402 /*
403 * Just check if our card has been removed.
404 */
405 err = mmc_send_status(host->card, NULL);
406
407 mmc_release_host(host);
408
409 if (err != MMC_ERR_NONE) {
410 mmc_remove_card(host->card);
411 host->card = NULL;
412
413 mmc_claim_host(host);
414 mmc_detach_bus(host);
415 mmc_release_host(host);
416 }
417}
418
419#ifdef CONFIG_MMC_UNSAFE_RESUME
420
421/*
422 * Suspend callback from host.
423 */
424static void mmc_suspend(struct mmc_host *host)
425{
426 BUG_ON(!host);
427 BUG_ON(!host->card);
416 428
429 mmc_claim_host(host);
430 mmc_deselect_cards(host);
431 host->card->state &= ~MMC_STATE_HIGHSPEED;
417 mmc_release_host(host); 432 mmc_release_host(host);
433}
418 434
419 err = mmc_register_card(card); 435/*
436 * Resume callback from host.
437 *
438 * This function tries to determine if the same card is still present
439 * and, if so, restore all state to it.
440 */
441static void mmc_resume(struct mmc_host *host)
442{
443 int err;
444
445 BUG_ON(!host);
446 BUG_ON(!host->card);
447
448 mmc_claim_host(host);
449
450 err = mmc_sd_init_card(host, host->ocr, host->card);
451 if (err != MMC_ERR_NONE) {
452 mmc_remove_card(host->card);
453 host->card = NULL;
454
455 mmc_detach_bus(host);
456 }
457
458 mmc_release_host(host);
459}
460
461#else
462
463#define mmc_suspend NULL
464#define mmc_resume NULL
465
466#endif
467
468static const struct mmc_bus_ops mmc_ops = {
469 .remove = mmc_remove,
470 .detect = mmc_detect,
471 .suspend = mmc_suspend,
472 .resume = mmc_resume,
473};
474
475/*
476 * Starting point for MMC card init.
477 */
478int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
479{
480 int err;
481
482 BUG_ON(!host);
483 BUG_ON(!host->claimed);
484
485 mmc_attach_bus(host, &mmc_ops);
486
487 /*
488 * Sanity check the voltages that the card claims to
489 * support.
490 */
491 if (ocr & 0x7F) {
492 printk(KERN_WARNING "%s: card claims to support voltages "
493 "below the defined range. These will be ignored.\n",
494 mmc_hostname(host));
495 ocr &= ~0x7F;
496 }
497
498 host->ocr = mmc_select_voltage(host, ocr);
499
500 /*
501 * Can we support the voltage of the card?
502 */
503 if (!host->ocr)
504 goto err;
505
506 /*
507 * Detect and init the card.
508 */
509 err = mmc_sd_init_card(host, host->ocr, NULL);
510 if (err != MMC_ERR_NONE)
511 goto err;
512
513 mmc_release_host(host);
514
515 err = mmc_register_card(host->card);
420 if (err) 516 if (err)
421 goto reclaim_host; 517 goto reclaim_host;
422 518
@@ -424,8 +520,7 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
424 520
425reclaim_host: 521reclaim_host:
426 mmc_claim_host(host); 522 mmc_claim_host(host);
427free_card: 523 mmc_remove_card(host->card);
428 mmc_remove_card(card);
429 host->card = NULL; 524 host->card = NULL;
430err: 525err:
431 mmc_detach_bus(host); 526 mmc_detach_bus(host);