From: Jonas Danielsson <jonas@xxxxxxxxxxxxxxxxxxx> This functionality was useful for us while debugging issues with a vendor wifi-driver that misbehaved on the SDIO bus. This will allow you to check how SDIO clients handle mmc command and data errors. Signed-off-by: Jonas Danielsson <jonas@xxxxxxxxxxxxxxxxxxx> --- drivers/mmc/host/atmel-mci.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index a9dad641c..11289c8e5 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -328,6 +328,8 @@ struct atmel_mci { u32 data_status; u32 stop_cmdr; + bool force_cmd_error; + bool force_data_error; struct tasklet_struct tasklet; unsigned long pending_events; unsigned long completed_events; @@ -618,6 +620,14 @@ static void atmci_init_debugfs(struct atmel_mci_slot *slot) if (!node) goto err; + node = debugfs_create_bool("force_cmd_error", 644, root, &host->force_cmd_error); + if (!node) + goto err; + + node = debugfs_create_bool("force_data_error", 644, root, &host->force_data_error); + if (!node) + goto err; + node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); if (!node) goto err; @@ -1807,7 +1817,12 @@ static void atmci_tasklet_func(unsigned long priv) * If there is a command error don't start * data transfer. */ - if (mrq->cmd->error) { + if (mrq->cmd->error || host->force_cmd_error) { + if (host->force_cmd_error) { + dev_info(&host->pdev->dev, "FSM: forced cmd error!\n"); + host->force_cmd_error = false; + mrq->cmd->error = -EINVAL; + } host->stop_transfer(host); host->data = NULL; atmci_writel(host, ATMCI_IDR, @@ -1939,7 +1954,11 @@ static void atmci_tasklet_func(unsigned long priv) atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY | ATMCI_RXRDY | ATMCI_DATA_ERROR_FLAGS); status = host->data_status; - if (unlikely(status)) { + if (unlikely(status) || host->force_data_error) { + if (data && host->force_data_error) { + dev_info(&host->pdev->dev, "FSM: forced data error!\n"); + host->force_data_error = false; + } host->stop_transfer(host); host->data = NULL; if (data) { @@ -2519,6 +2538,7 @@ static int atmci_probe(struct platform_device *pdev) return -ENOMEM; host->pdev = pdev; + host->force_data_error = host->force_cmd_error = false; spin_lock_init(&host->lock); INIT_LIST_HEAD(&host->queue); -- 2.23.0