2014-11-24 19:44 GMT+08:00 Ulf Hansson <ulf.hansson@xxxxxxxxxx>: > On 21 November 2014 at 15:46, Barry Song <21cnbao@xxxxxxxxx> wrote: >> From: Minda Chen <Minda.Chen@xxxxxxx> >> >> According to the SD card spec, Add a manual tuning command function >> for SDR104/HS200 by sending command 19 or command 21 to read data >> and compare with the tuning block pattern. >> >> this patch will help to decrease some platform private codes in >> SDHCI platform_execute_tuning() callbacks. >> >> Signed-off-by: Minda Chen <Minda.Chen@xxxxxxx> >> Signed-off-by: Barry Song <Baohua.Song@xxxxxxx> >> --- >> drivers/mmc/core/mmc_ops.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++ >> include/linux/mmc/core.h | 1 + >> 2 files changed, 66 insertions(+) >> >> diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c >> index 7911e05..ecc7789 100644 >> --- a/drivers/mmc/core/mmc_ops.c >> +++ b/drivers/mmc/core/mmc_ops.c >> @@ -543,6 +543,71 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, >> } >> EXPORT_SYMBOL_GPL(mmc_switch); >> >> +int mmc_send_tuning(struct mmc_card *card, u32 opcode) >> +{ >> + struct mmc_request mrq = {NULL}; >> + struct mmc_command cmd = {0}; >> + struct mmc_data data = {0}; >> + struct scatterlist sg; >> + struct mmc_host *mmc = card->host; >> + struct mmc_ios *ios = &mmc->ios; >> + const u8 *tuning_block_pattern; >> + int size, err = 0; >> + u8 *data_buf; >> + >> + if (opcode == MMC_SEND_TUNING_BLOCK_HS200) { > > I don't think we need to care about the opcode. Let's just check the bus_width. > >> + if (ios->bus_width == MMC_BUS_WIDTH_8) { >> + tuning_block_pattern = tuning_blk_pattern_8bit; >> + size = sizeof(tuning_blk_pattern_8bit); >> + } else if (ios->bus_width == MMC_BUS_WIDTH_4) { >> + tuning_block_pattern = tuning_blk_pattern_4bit; >> + size = sizeof(tuning_blk_pattern_4bit); >> + } else >> + return -EINVAL; >> + } else if (opcode == MMC_SEND_TUNING_BLOCK) { >> + tuning_block_pattern = tuning_blk_pattern_4bit; >> + size = sizeof(tuning_blk_pattern_4bit); >> + } else >> + return -EINVAL; >> + >> + data_buf = kmalloc(size, GFP_KERNEL); > > You should use kzalloc() to get the zeroed buffer you want. > >> + if (!data_buf) >> + return -ENOMEM; >> + >> + mrq.cmd = &cmd; >> + mrq.data = &data; >> + >> + cmd.opcode = opcode; >> + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; >> + >> + data.blksz = size; >> + data.blocks = 1; >> + data.flags = MMC_DATA_READ; > > These needs to be assigned as well: > > data.sg = &sg; > data.sg_len = 1; > >> + >> + mmc_set_data_timeout(&data, card); > > mmc_set_data_timeout() doesn't handle CMD21/19. > > The specs tells us about 40 commands should be executed within 150ms. > I would pick a value of 150ms, just to be sure we are inside that > range. Also, assign "data->timeout_ns" here, instead of relying on > mmc_set_data_timeout(). > >> + sg_init_one(&sg, data_buf, size); >> + memset(data_buf, 0, size); >> + mmc_wait_for_req(mmc, &mrq); >> + >> + if (cmd.error) { >> + err = cmd.error; >> + goto out; >> + } >> + >> + if (data.error) { >> + err = data.error; >> + goto out; >> + } >> + >> + if (memcmp(data_buf, tuning_block_pattern, size)) >> + err = -EIO; >> + >> +out: >> + kfree(data_buf); >> + return err; >> +} >> +EXPORT_SYMBOL_GPL(mmc_send_tuning); >> + >> static int >> mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, >> u8 len) >> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h >> index f206e29..82a0119 100644 >> --- a/include/linux/mmc/core.h >> +++ b/include/linux/mmc/core.h >> @@ -154,6 +154,7 @@ extern void mmc_start_bkops(struct mmc_card *card, bool from_exception); >> extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool, >> bool, bool); >> extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); >> +extern int mmc_send_tuning(struct mmc_card *, u32); >> extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); >> >> #define MMC_ERASE_ARG 0x00000000 >> -- >> 2.1.1 >> What about? 546 int mmc_send_tuning(struct mmc_card *card) 547 { 548 struct mmc_request mrq = {NULL}; 549 struct mmc_command cmd = {0}; 550 struct mmc_data data = {0}; 551 struct scatterlist sg; 552 struct mmc_host *mmc = card->host; 553 struct mmc_ios *ios = &mmc->ios; 554 const u8 *tuning_block_pattern; 555 int size, err = 0; 556 u8 *data_buf; 557 u32 opcode; 558 559 if (ios->bus_width == MMC_BUS_WIDTH_8) { 560 tuning_block_pattern = tuning_blk_pattern_8bit; 561 size = sizeof(tuning_blk_pattern_8bit); 562 opcode = MMC_SEND_TUNING_BLOCK_HS200; 563 } else if (ios->bus_width == MMC_BUS_WIDTH_4) { 564 tuning_block_pattern = tuning_blk_pattern_4bit; 565 size = sizeof(tuning_blk_pattern_4bit); 566 opcode = MMC_SEND_TUNING_BLOCK; 567 } else 568 return -EINVAL; 569 570 data_buf = kzalloc(size, GFP_KERNEL); 571 if (!data_buf) 572 return -ENOMEM; 573 574 mrq.cmd = &cmd; 575 mrq.data = &data; 576 577 cmd.opcode = opcode; 578 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; 579 580 data.blksz = size; 581 data.blocks = 1; 582 data.flags = MMC_DATA_READ; 583 584 /* 585 * According to the tuning specs, Tuning process 586 * is normally shorter 40 executions of CMD19, 587 * and timeout value should be shorter than 150 ms 588 */ 589 data.timeout_ns = 150 * NSEC_PER_MSEC; 590 591 data.sg = &sg; 592 data.sg_len = 1; 593 sg_init_one(&sg, data_buf, size); 594 595 mmc_wait_for_req(mmc, &mrq); 596 597 if (cmd.error) { 598 err = cmd.error; 599 goto out; 600 } 601 602 if (data.error) { 603 err = data.error; 604 goto out; 605 } 606 607 if (memcmp(data_buf, tuning_block_pattern, size)) 608 err = -EIO; 609 610 out: 611 kfree(data_buf); 612 return err; 613 } 614 EXPORT_SYMBOL_GPL(mmc_send_tuning); > > Kind regards > Uffe -barry -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html