Skip to content

Commit e270cec

Browse files
author
Phil Elwell
committed
bcm2835-sdhost: Further improve overclock back-off
1 parent 009c97b commit e270cec

File tree

1 file changed

+78
-66
lines changed

1 file changed

+78
-66
lines changed

drivers/mmc/host/bcm2835-sdhost.c

Lines changed: 78 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,6 @@ struct bcm2835_host {
161161

162162
unsigned int use_busy:1; /* Wait for busy interrupt */
163163

164-
unsigned int reduce_overclock:1; /* ...at the next opportunity */
165-
166164
unsigned int debug:1; /* Enable debug output */
167165

168166
u32 thread_isr;
@@ -466,36 +464,25 @@ static void bcm2835_sdhost_dma_complete(void *param)
466464
spin_unlock_irqrestore(&host->lock, flags);
467465
}
468466

469-
static bool data_transfer_wait(struct bcm2835_host *host, const char *caller)
467+
static bool data_transfer_wait(struct bcm2835_host *host)
470468
{
471469
unsigned long timeout = 1000000;
472-
u32 hsts;
473470
while (timeout)
474471
{
475-
hsts = bcm2835_sdhost_read(host, SDHSTS);
476-
if (hsts & (SDHSTS_TRANSFER_ERROR_MASK |
477-
SDHSTS_DATA_FLAG)) {
478-
bcm2835_sdhost_write(host, SDHSTS_TRANSFER_ERROR_MASK,
479-
SDHSTS);
472+
u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
473+
if (sdhsts & SDHSTS_DATA_FLAG) {
474+
bcm2835_sdhost_write(host, SDHSTS_DATA_FLAG, SDHSTS);
480475
break;
481476
}
482477
timeout--;
483478
}
484-
485-
if (hsts & (SDHSTS_CRC16_ERROR |
486-
SDHSTS_CRC7_ERROR |
487-
SDHSTS_FIFO_ERROR)) {
488-
pr_err("%s: data error in %s - HSTS %x\n",
489-
mmc_hostname(host->mmc), caller, hsts);
490-
host->data->error = -EILSEQ;
491-
return false;
492-
} else if ((timeout == 0) ||
493-
(hsts & (SDHSTS_CMD_TIME_OUT |
494-
SDHSTS_REW_TIME_OUT))) {
495-
pr_err("%s: timeout in %s - HSTS %x\n",
496-
mmc_hostname(host->mmc), caller, hsts);
497-
host->data->error = -ETIMEDOUT;
498-
return false;
479+
if (timeout == 0) {
480+
pr_err("%s: Data %s timeout\n",
481+
mmc_hostname(host->mmc),
482+
(host->data->flags & MMC_DATA_READ) ? "read" : "write");
483+
bcm2835_sdhost_dumpregs(host);
484+
host->data->error = -ETIMEDOUT;
485+
return false;
499486
}
500487
return true;
501488
}
@@ -523,7 +510,7 @@ static void bcm2835_sdhost_read_block_pio(struct bcm2835_host *host)
523510
buf = (u32 *)host->sg_miter.addr;
524511

525512
while (len) {
526-
if (!data_transfer_wait(host, "read_block_pio"))
513+
if (!data_transfer_wait(host))
527514
break;
528515

529516
*(buf++) = bcm2835_sdhost_read(host, SDDATA);
@@ -562,7 +549,7 @@ static void bcm2835_sdhost_write_block_pio(struct bcm2835_host *host)
562549
buf = host->sg_miter.addr;
563550

564551
while (len) {
565-
if (!data_transfer_wait(host, "write_block_pio"))
552+
if (!data_transfer_wait(host))
566553
break;
567554

568555
bcm2835_sdhost_write(host, *(buf++), SDDATA);
@@ -581,13 +568,33 @@ static void bcm2835_sdhost_write_block_pio(struct bcm2835_host *host)
581568

582569
static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host)
583570
{
571+
u32 sdhsts;
572+
bool is_read;
584573
BUG_ON(!host->data);
585574

586-
if (host->data->flags & MMC_DATA_READ) {
575+
is_read = (host->data->flags & MMC_DATA_READ) != 0;
576+
if (is_read)
587577
bcm2835_sdhost_read_block_pio(host);
588-
} else {
578+
else
589579
bcm2835_sdhost_write_block_pio(host);
590580

581+
sdhsts = bcm2835_sdhost_read(host, SDHSTS);
582+
if (sdhsts & (SDHSTS_CRC16_ERROR |
583+
SDHSTS_CRC7_ERROR |
584+
SDHSTS_FIFO_ERROR)) {
585+
pr_err("%s: %s transfer error - HSTS %x\n",
586+
mmc_hostname(host->mmc),
587+
is_read ? "read" : "write",
588+
sdhsts);
589+
host->data->error = -EILSEQ;
590+
} else if ((sdhsts & (SDHSTS_CMD_TIME_OUT |
591+
SDHSTS_REW_TIME_OUT))) {
592+
pr_err("%s: %s timeout error - HSTS %x\n",
593+
mmc_hostname(host->mmc),
594+
is_read ? "read" : "write",
595+
sdhsts);
596+
host->data->error = -ETIMEDOUT;
597+
} else if (!is_read && !host->data->error) {
591598
/* Start a timer in case a transfer error occurs because
592599
there is no error interrupt */
593600
mod_timer(&host->pio_timer, jiffies + host->pio_timeout);
@@ -701,8 +708,9 @@ static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_co
701708

702709
void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *cmd)
703710
{
704-
u32 sdcmd;
711+
u32 sdcmd, sdhsts;
705712
unsigned long timeout;
713+
int delay;
706714

707715
WARN_ON(host->cmd);
708716

@@ -719,8 +727,8 @@ void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *
719727
mmc_hostname(host->mmc),
720728
cmd->opcode, cmd->arg, cmd->flags);
721729

722-
/* Wait max 10 ms */
723-
timeout = 1000;
730+
/* Wait max 100 ms */
731+
timeout = 10000;
724732

725733
while (bcm2835_sdhost_read(host, SDCMD) & SDCMD_NEW_FLAG) {
726734
if (timeout == 0) {
@@ -735,8 +743,9 @@ void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *
735743
udelay(10);
736744
}
737745

738-
if ((1000-timeout)/100 > 1 && (1000-timeout)/100 > host->max_delay) {
739-
host->max_delay = (1000-timeout)/100;
746+
delay = (10000 - timeout)/100;
747+
if (delay > host->max_delay) {
748+
host->max_delay = delay;
740749
pr_warning("%s: controller hung for %d ms\n",
741750
mmc_hostname(host->mmc),
742751
host->max_delay);
@@ -751,6 +760,11 @@ void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *
751760

752761
host->cmd = cmd;
753762

763+
/* Clear any error flags */
764+
sdhsts = bcm2835_sdhost_read(host, SDHSTS);
765+
if (sdhsts & SDHSTS_ERROR_MASK)
766+
bcm2835_sdhost_write(host, sdhsts, SDHSTS);
767+
754768
bcm2835_sdhost_prepare_data(host, cmd);
755769

756770
bcm2835_sdhost_write(host, cmd->arg, SDARG);
@@ -876,7 +890,7 @@ static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host)
876890
static void bcm2835_sdhost_finish_command(struct bcm2835_host *host)
877891
{
878892
u32 sdcmd;
879-
int timeout = 1000;
893+
unsigned long timeout;
880894
#ifdef DEBUG
881895
struct timeval before, after;
882896
int timediff = 0;
@@ -889,6 +903,8 @@ static void bcm2835_sdhost_finish_command(struct bcm2835_host *host)
889903
#ifdef DEBUG
890904
do_gettimeofday(&before);
891905
#endif
906+
/* Wait max 100 ms */
907+
timeout = 10000;
892908
for (sdcmd = bcm2835_sdhost_read(host, SDCMD);
893909
(sdcmd & SDCMD_NEW_FLAG) && timeout;
894910
timeout--) {
@@ -1049,9 +1065,9 @@ static void bcm2835_sdhost_pio_timeout(unsigned long data)
10491065
spin_lock_irqsave(&host->lock, flags);
10501066

10511067
if (host->data) {
1052-
u32 hsts = bcm2835_sdhost_read(host, SDHSTS);
1068+
u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
10531069

1054-
if (hsts & SDHSTS_REW_TIME_OUT) {
1070+
if (sdhsts & SDHSTS_REW_TIME_OUT) {
10551071
pr_err("%s: transfer timeout\n",
10561072
mmc_hostname(host->mmc));
10571073
if (host->debug)
@@ -1380,19 +1396,10 @@ void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock)
13801396
if (host->debug)
13811397
pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
13821398

1383-
if ((clock == 0) && host->reduce_overclock) {
1384-
/* This is a reset following data corruption - reduce any
1385-
overclock */
1386-
host->reduce_overclock = 0;
1387-
if (host->overclock_50 > 50) {
1388-
pr_warn("%s: reducing overclock due to errors\n",
1389-
mmc_hostname(host->mmc));
1390-
host->overclock_50--;
1391-
}
1392-
}
1393-
1394-
if (host->overclock_50 && (clock == 50*MHZ))
1399+
if ((host->overclock_50 > 50) &&
1400+
(clock == 50*MHZ)) {
13951401
clock = host->overclock_50 * MHZ + (MHZ - 1);
1402+
}
13961403

13971404
/* The SDCDIV register has 11 bits, and holds (div - 2).
13981405
But in data mode the max is 50MHz wihout a minimum, and only the
@@ -1450,11 +1457,12 @@ void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock)
14501457
host->overclock = clock;
14511458
}
14521459
}
1453-
else if ((clock == 50 * MHZ) && host->overclock)
1460+
else if (host->overclock)
14541461
{
1455-
pr_warn("%s: cancelling overclock\n",
1456-
mmc_hostname(host->mmc));
14571462
host->overclock = 0;
1463+
if (clock == 50 * MHZ)
1464+
pr_warn("%s: cancelling overclock\n",
1465+
mmc_hostname(host->mmc));
14581466
}
14591467

14601468
host->cdiv = div;
@@ -1492,6 +1500,14 @@ static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq
14921500
cmd->opcode, cmd->arg, cmd->flags);
14931501
}
14941502

1503+
/* Reset the error statuses in case this is a retry */
1504+
if (mrq->cmd)
1505+
mrq->cmd->error = 0;
1506+
if (mrq->data)
1507+
mrq->data->error = 0;
1508+
if (mrq->stop)
1509+
mrq->stop->error = 0;
1510+
14951511
if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
14961512
pr_err("%s: unsupported block size (%d bytes)\n",
14971513
mmc_hostname(mmc), mrq->data->blksz);
@@ -1613,21 +1629,16 @@ static void bcm2835_sdhost_tasklet_finish(unsigned long param)
16131629

16141630
/* Drop the overclock after any data corruption, or after any
16151631
error overclocked */
1616-
if (mrq->data && (mrq->data->error == -EILSEQ))
1617-
host->reduce_overclock = 1;
1618-
else if (host->overclock) {
1619-
/* Convert timeout errors while overclocked to data errors,
1620-
because the system recovers better. */
1621-
if (mrq->cmd && mrq->cmd->error) {
1622-
host->reduce_overclock = 1;
1623-
if (mrq->cmd->error == -ETIMEDOUT)
1624-
mrq->cmd->error = -EILSEQ;
1625-
}
1626-
1627-
if (mrq->data && mrq->data->error) {
1628-
host->reduce_overclock = 1;
1629-
if (mrq->data->error == -ETIMEDOUT)
1630-
mrq->data->error = -EILSEQ;
1632+
if (host->overclock) {
1633+
if ((mrq->cmd && mrq->cmd->error) ||
1634+
(mrq->data && mrq->data->error) ||
1635+
(mrq->stop && mrq->stop->error)) {
1636+
host->overclock_50--;
1637+
pr_warn("%s: reducing overclock due to errors\n",
1638+
mmc_hostname(host->mmc));
1639+
bcm2835_sdhost_set_clock(host,50*MHZ);
1640+
mrq->cmd->error = -EILSEQ;
1641+
mrq->cmd->retries = 1;
16311642
}
16321643
}
16331644

@@ -1769,6 +1780,7 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev)
17691780
host = mmc_priv(mmc);
17701781
host->mmc = mmc;
17711782
host->pio_timeout = msecs_to_jiffies(500);
1783+
host->max_delay = 1; /* Warn if over 1ms */
17721784
spin_lock_init(&host->lock);
17731785

17741786
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);

0 commit comments

Comments
 (0)