Hi Pierre, Following your announce of future removal of the MMC multiwrite switch and the contributions of several people of the AT91 community, here is a patches series : Those patches should enhance transfer of data and setup a sane base for a working SDIO support. Several of those contributions are around since the beginning of this year. I thank all of you for your patient and valuable testing effort. Here are some discussions that led to this patch series: "mmc: at91_mci: support for block size not modulo 4" http://lists.arm.linux.org.uk/lurker/message/20080107.141550.ea58119f.en.html AT91 SDIO + 8686 http://lists.arm.linux.org.uk/lurker/message/20071114.094824.3ebcbe04.en.html "8686 with SDIO on AT91SAM9263" http://lists.arm.linux.org.uk/lurker/message/20080123.182026.f3c54a8a.en.html "[PATCH 0/2] at91_mci: manage timeouts" http://lists.arm.linux.org.uk/lurker/message/20080125.075058.257a2582.en.html "[PATCH 0/3] at91_mci: fix SD filesystem corruption on sam9261" http://lists.arm.linux.org.uk/lurker/message/20080318.145450.7b443217.en.html Regards, -- Nicolas Ferre --
Modify bytes_xfered value after a write.
That will report, as accurately as possible, the amount of
sectors that are effectively written.
This update introduces the check of the busy signal given by
the card.
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
drivers/mmc/host/at91_mci.c | 40 ++++++++++++++++++++++++++++++++++------
1 files changed, 34 insertions(+), 6 deletions(-)
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index df975e0..b2138f9 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -340,8 +340,6 @@ static void at91_mci_post_dma_read(struct at91mci_host *host)
dma_unmap_page(NULL, sg->dma_address, sg->length, DMA_FROM_DEVICE);
- data->bytes_xfered += sg->length;
-
if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
unsigned int *buffer;
int index;
@@ -357,6 +355,8 @@ static void at91_mci_post_dma_read(struct at91mci_host *host)
}
flush_dcache_page(sg_page(sg));
+
+ data->bytes_xfered += sg->length;
}
/* Is there another transfer to trigger? */
@@ -397,10 +397,32 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host)
at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE);
} else
at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
+}
+
+/*
+ * Update bytes tranfered count during a write operation
+ */
+static void at91_mci_update_bytes_xfered(struct at91mci_host *host)
+{
+ struct mmc_data *data;
- data->bytes_xfered = host->total_length;
+ /* always deal with the effective request (and not the current cmd) */
+
+ if (host->request->cmd && host->request->cmd->error != 0)
+ return;
+
+ if (host->request->data) {
+ data = host->request->data;
+ if (data->flags & MMC_DATA_WRITE) {
+ /* card is in IDLE mode now */
+ pr_debug("-> bytes_xfered %d, total_length = %d\n",
+ data->bytes_xfered, host->total_length);
+ data->bytes_xfered = host->total_length;
+ }
+ }
}
+
/*Handle after command sent ...Doesn't this patch depend on patch 4? IOW, shouldn't you be correcting this before you enable the features which require this to be accurate? --
From: Eric Benard <ebenard@free.fr>
Enable SDIO interrupt handling.
Signed-off-by: Eric Benard <ebenard@free.fr>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
drivers/mmc/host/at91_mci.c | 26 ++++++++++++++++++++++----
1 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index b2138f9..92a0200 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -665,7 +665,7 @@ static void at91_mci_completed_command(struct at91mci_host *host)
struct mmc_command *cmd = host->cmd;
unsigned int status;
- at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
+ at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0));
cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));
@@ -856,6 +856,12 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
}
}
+ if (int_status & AT91_MCI_SDIOIRQA)
+ mmc_signal_sdio_irq(host->mmc);
+
+ if (int_status & AT91_MCI_SDIOIRQB)
+ mmc_signal_sdio_irq(host->mmc);
+
if (int_status & AT91_MCI_TXRDY)
pr_debug("Ready to transmit\n");
@@ -870,10 +876,10 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
if (completed) {
pr_debug("Completed command\n");
- at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
+ at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
at91_mci_completed_command(host);
} else
- at91_mci_write(host, AT91_MCI_IDR, int_status);
+ at91_mci_write(host, AT91_MCI_IDR, int_status & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
return IRQ_HANDLED;
}
@@ -917,10 +923,22 @@ static int at91_mci_get_ro(struct mmc_host *mmc)
return read_only;
}
+static void at91_mci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct at91mci_host *host = mmc_priv(mmc);
+
+ pr_debug("%s: sdio_irq %c : %s\n", mmc_hostname(host->mmc),
+ host->board->slot_b ? ...Reading AT91_MCI_SR again at the end of transfer can corrupt the
error reporting. Some fields in the SR register are read-and-clear.
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
drivers/mmc/host/at91_mci.c | 12 +++++-------
1 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 92a0200..9948fe1 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -660,10 +660,9 @@ static void at91_mci_process_next(struct at91mci_host *host)
/*
* Handle a command that has been completed
*/
-static void at91_mci_completed_command(struct at91mci_host *host)
+static void at91_mci_completed_command(struct at91mci_host *host, unsigned int status)
{
struct mmc_command *cmd = host->cmd;
- unsigned int status;
at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
@@ -677,10 +676,9 @@ static void at91_mci_completed_command(struct at91mci_host *host)
host->buffer = NULL;
}
- status = at91_mci_read(host, AT91_MCI_SR);
-
- pr_debug("Status = %08X [%08X %08X %08X %08X]\n",
- status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+ pr_debug("Status = %08X/%08x [%08X %08X %08X %08X]\n",
+ status, at91_mci_read(host, AT91_MCI_SR),
+ cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
if (status & AT91_MCI_ERRORS) {
if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) {
@@ -877,7 +875,7 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
if (completed) {
pr_debug("Completed command\n");
at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
- at91_mci_completed_command(host);
+ at91_mci_completed_command(host, int_status);
} else
at91_mci_write(host, AT91_MCI_IDR, int_status & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
--
1.5.3.7
--
From: Marc Pignat <marc.pignat@hevs.ch>
Implement transfer with size not modulo 4 for at91sam9*. Please note
that the
at91rm9200 simply can't handle this.
Signed-off-by: Marc Pignat <marc.pignat@hevs.ch>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
drivers/mmc/host/at91_mci.c | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 8979ad3..543b64b 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -233,11 +233,11 @@ static void at91_mci_pre_dma_read(struct
at91mci_host *host)
if (i == 0) {
at91_mci_write(host, ATMEL_PDC_RPR, sg->dma_address);
- at91_mci_write(host, ATMEL_PDC_RCR, sg->length / 4);
}
else {
at91_mci_write(host, ATMEL_PDC_RNPR, sg->dma_address);
- at91_mci_write(host, ATMEL_PDC_RNCR, sg->length / 4);
+ at91_mci_write(host, ATMEL_PDC_RNCR, (data->blksz & 0x3) ?
sg->length : sg->length / 4);
}
}
@@ -430,7 +430,7 @@ static void at91_mci_send_command(struct
at91mci_host *host, struct mmc_command
if (data) {
- if ( data->blksz & 0x3 ) {
+ if ( cpu_is_at91rm9200() && (data->blksz & 0x3) ) {
pr_debug("Unsupported block size\n");
cmd->error = -EINVAL;
mmc_request_done(host->mmc, host->request);
@@ -482,7 +482,10 @@ static void at91_mci_send_command(struct
at91mci_host *host, struct mmc_command
} else {
/* zero block length and PDC mode */
mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff;
- at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) |
AT91_MCI_PDCMODE);
+ mr |= (data->blksz & 0x3) ? AT91_MCI_PDCFBYTE : 0;
+ mr |= (block_length << 16);
+ mr |= AT91_MCI_PDCMODE;
+ at91_mci_write(host, AT91_MCI_MR, mr);
/*
* Disable the PDC controller
@@ -517,7 +520,9 @@ static void at91_mci_send_command(struct
at91mci_host *host, struct mmc_command
pr_debug("Transmitting %d bytes\n", host->total_length);
at91_mci_write(host, ATMEL_PDC_TPR, ...From: Marc Pignat <marc.pignat@hevs.ch>
Detect command timeout (or mci controller hangs).
Signed-off-by: Marc Pignat <marc.pignat@hevs.ch>
Signed-off-by: Hans J Koch <hjk@linutronix.de>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
drivers/mmc/host/at91_mci.c | 35 +++++++++++++++++++++++++++++++++--
1 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 543b64b..4b4518f 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -125,8 +125,33 @@ struct at91mci_host
/* Latest in the scatterlist that has been enabled for transfer */
int transfer_index;
+
+ /* Timer for timeouts */
+ struct timer_list timer;
};
+static void at91_timeout_timer(unsigned long data)
+{
+ struct at91mci_host *host;
+
+ host = (struct at91mci_host *)data;
+
+ if (host->request) {
+ dev_err(host->mmc->parent, "Timeout waiting end of packet\n");
+
+ if (host->cmd && host->cmd->data) {
+ host->cmd->data->error = -ETIMEDOUT;
+ } else {
+ if (host->cmd)
+ host->cmd->error = -ETIMEDOUT;
+ else
+ host->request->cmd->error = -ETIMEDOUT;
+ }
+
+ mmc_request_done(host->mmc, host->request);
+ }
+}
+
/*
* Copy from sg to a dma block - used for transfers
*/
@@ -557,9 +582,10 @@ static void at91_mci_process_next(struct
at91mci_host *host)
else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) {
host->flags |= FL_SENT_STOP;
at91_mci_send_command(host, host->request->stop);
- }
- else
+ } else {
+ del_timer(&host->timer);
mmc_request_done(host->mmc, host->request);
+ }
}
/*
@@ -618,6 +644,8 @@ static void at91_mci_request(struct mmc_host *mmc,
struct mmc_request *mrq)
host->request = mrq;
host->flags = 0;
+ mod_timer(&host->timer, jiffies + HZ);
+
at91_mci_process_next(host);
}
@@ -940,6 +968,8 @@ static int __init at91_mci_probe(struct
platform_device *pdev)
mmc_add_host(mmc);
+ setup_timer(&host->timer, ...From: Marc Pignat <marc.pignat@hevs.ch>
The at91 mci controller internal state machine seems to often crash.
This can
be fixed by resetting the controller after each command for at91rm9200
and by
setting the MCI_BLKR register on at91sam926*.
Signed-off-by: Marc Pignat <marc.pignat@hevs.ch>
Signed-off-by: Hans J Koch <hjk@linutronix.de>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
drivers/mmc/host/at91_mci.c | 48
++++++++++++++++++++++++++++++++++
include/asm-arm/arch-at91/at91_mci.h | 4 +++
2 files changed, 52 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 4b4518f..6b9662e 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -130,6 +130,43 @@ struct at91mci_host
struct timer_list timer;
};
+/*
+ * Reset the controller and restore most of the state
+ */
+static void at91_reset_host(struct at91mci_host *host)
+{
+ unsigned long flags;
+ u32 mr;
+ u32 sdcr;
+ u32 dtor;
+ u32 imr;
+
+ local_irq_save(flags);
+ imr = at91_mci_read(host, AT91_MCI_IMR);
+
+ at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
+
+ /* save current state */
+ mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff;
+ sdcr = at91_mci_read(host, AT91_MCI_SDCR);
+ dtor = at91_mci_read(host, AT91_MCI_DTOR);
+
+ /* reset the controller */
+ at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
+
+ /* restore state */
+ at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
+ at91_mci_write(host, AT91_MCI_MR, mr);
+ at91_mci_write(host, AT91_MCI_SDCR, sdcr);
+ at91_mci_write(host, AT91_MCI_DTOR, dtor);
+ at91_mci_write(host, AT91_MCI_IER, imr);
+
+ /* make sure sdio interrupts will fire */
+ at91_mci_read(host, AT91_MCI_SR);
+
+ local_irq_restore(flags);
+}
+
static void at91_timeout_timer(unsigned long data)
{
struct at91mci_host *host;
@@ -148,6 +185,7 @@ static void at91_timeout_timer(unsigned long data)
host->request->cmd->error = ...at91_mci is capable of multiwrite. Enable it before it disappears. Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> --- drivers/mmc/host/at91_mci.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 6b9662e..df975e0 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -923,6 +923,7 @@ static int __init at91_mci_probe(struct platform_device *pdev) mmc->f_min = 375000; mmc->f_max = 25000000; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + mmc->caps = MMC_CAP_MULTIWRITE; mmc->max_blk_size = 4095; mmc->max_blk_count = mmc->max_req_size; -- 1.5.3.7 --
On Fri, 30 May 2008 13:49:59 +0200 I have no big concerns about the patches. There were some comments from other people though. Do you want to have a look at those first? Rgds Pierre
If you want I can reorder them... or you manage to do it. I will take into account Marc's comment and new Ville patch series in another round ;-) Btw, you can also add the "manage cmd error and data error independently" patch I have just sent. Kind regards, -- Nicolas Ferre --
On Tue, 10 Jun 2008 11:54:41 +0200 Will you redo this series, or are you planning further patches? (i.e. should I merge this set or wait for an update?)
You can merge this patch series (7 patches) You can also merge http://lists.arm.linux.org.uk/lurker/message/20080610.092729.beef9e64.en.html "at91_mci: manage cmd error and data error independently" (1 patch) And 3 patches from Ville Syrjälä that I have just signed: http://lists.arm.linux.org.uk/lurker/message/20080614.172720.dd0e776e.en.html "at91_mci: AT91SAM9260/9263 12 byte write erratum (v2)" http://lists.arm.linux.org.uk/lurker/message/20080609.190644.3f64ff91.en.html "at91_mci: Cover more AT91RM9200 and AT91SAM9261 errata." http://lists.arm.linux.org.uk/lurker/message/20080609.190645.2998e511.en.html "at91_mci: Fix byte mode transitions." => 11 patches. Thanks a lot, regards, -- Nicolas Ferre --
On Wed, Jun 18, 2008 at 12:04:49PM +0200, Nicolas Ferre wrote: [...] Could you all drop =3D?ISO-8859-1?Q?Hans-J=3DFCrgen_?=3D from the Cc list in this thread? The address is invalid because it has no domain part and hence causes quite some bounces on the list because some strict email checkers reject invalid addresses in the Cc list. I'm trying to figure out what went wrong, but in the mean time please drop =3D?ISO-8859-1?Q?Hans-J=3DFCrgen_?=3D from the Cc list. Erik [linux-arm-kernel-owner #2] --=20 Erik Mouw -- mouw@nl.linux.org
Found it, Mailman is to blame. On the linux-kernel mailing list, the address shows up ok: "=3D?ISO-8859-1?Q?Hans-J=3DFCrgen_?=3D =3D?ISO-8859-1?Q?Koch?=3D <hjk@linutronix.de>". What probably happens: Mailman tries to check if the addresses in the To and CC fields are subscribed to the list (linux-arm-kernel). If that is the case and the subscriber enabled "prevent doubles", it won't send that particular subscriber the message. Of course, this should have been implemented by a simple strncmp() on the To and CC fields, but I guess Mailman first breaks up the To and CC fields, then does the "prevent double" check, and then reassembles the To and CC fields. Apparently there is an error in the break up or reassembly. Now how to fix this without breaking Mailman alltogether... In the mean time, could you just use Hans-J=FCrgen's address (hjk@linutronix.de>) and not his name in the CC field? Erik [linux-arm-kernel-owner #2] (thanks to David Woodhouse for helping to debug the problem) --=20 Erik Mouw -- mouw@nl.linux.org
I avoided the German umlaut in my name by using the abbreviation "Hans J. Koch" on mailing lists. Unfortunately, I still have one mail client that uses the full name. I'll fix that to avoid similar trouble. On the other hand, I used that for quite a while now, and didn't have problems. It shouldn't be too difficult to have these programs use UTF-8 (or any other charset) properly these days. Thanks, --
I'm not convinced it's a problem with rfc2047 handling; I think it's simpler brain-damage than that on mailman's part. It's to do with line wrapping, iirc -- if an address spans two lines, like: David Woodhouse <dwmw2@infradead.org>, then mailman will brokenly insert a comma where the line break happened -- or something like that. -- dwmw2 --
It's a bit more complicated cause Mailman gets this right: ARM Linux Mailing List=20 <linux-arm-kernel@lists.arm.linux.org.uk>, It also gets RFC2407 right: =3D?ISO-8859-1?Q?Ville_Syrj=3DE4l=3DE4?=3D <syrjala@sci.fi> I guess it's a combination that goes wrong: =3D?ISO-8859-1?Q?Hans-J=3DFCrgen_?=3D =3D?ISO-8859-1?Q?Koch?=3D=20 <hjk@linutronix.de> Maybe if J=FCrgen's mailer made that something like: =3D?ISO-8859-1Q!Hans-J=3DFCrgen_Koch?=3D Mailman wouldn't have crippled the address? Oh well, rmk isn't available for a few days so I can't really debug the Mailman version on lists.arm.linux.org.uk :( Erik --=20 Erik Mouw -- mouw@nl.linux.org
I can set up a test list for you to screw around with if you like. -- dwmw2 --
No need for that, I can install Mailman on my laptop. Thanks for the offer, though. Erik --=20 Erik Mouw -- mouw@nl.linux.org
On Wed, 18 Jun 2008 12:04:49 +0200
Everything merged up. It'll be hitting kernel.org soon.
Rgds
--=20
-- Pierre Ossman
WARNING: This correspondence is being monitored by the
Swedish government. Use end-to-end encryption where
possible.
