libertas_sdio doesn't work after reloading

Dan Williams dcbw at redhat.com
Tue Feb 3 14:44:58 EST 2009


On Tue, 2009-02-03 at 14:27 -0500, Dan Williams wrote:
> On Tue, 2009-02-03 at 11:09 -0800, Matt Reimer wrote:
> > On Tue, Feb 3, 2009 at 7:42 AM, Dan Williams <dcbw at redhat.com> wrote:
> > > On Tue, 2009-02-03 at 11:20 +0000, Jonathan Cameron wrote:
> > >> Matt Reimer wrote:
> > >> > On Mon, Feb 2, 2009 at 1:58 PM, Andrey Yurovsky <andrey at cozybit.com> wrote:
> > >> >> Hi Matt.  Is this on an embedded system or on a desktop PC with some
> > >> >> host controller?  If so, which one?  I'm curious because module reload
> > >> >> seems to work fine with my Ricoh host controller.
> > >> >
> > >> > This is on an embedded system, using the SD controller on a pxa320.
> > >> >
> > >> > Matt
> > >> >
> > >> I ran into exactly the same issue with a pxa271 board, but never figured
> > >> out what was going on.  Very interested to hear if you do!
> > >
> > > The only method I have found to reset the libertas chip is to pull the
> > > power from the card or unplug it.  There hasn't been any other method
> > > that we can figure out to hard-reset the card, either with SDIO commands
> > > or with CMD_802_11_RESET.  I'd be quite interested if anyone found a
> > > mechanism for doing a full reset while the card's plugged in.
> > 
> > Do you think the problem could be that after reset the libertas chip
> > is talking to the controller at the wrong bus speed and bus width?
> 
> It could well be.  Pierre, I and Philip Rakity are having a side
> conversation right now about this sort of thing.  Let me see if Philip
> would mind if I pasted in his debugging patch for that.  Basically,
> issue an SDIO ABORT/reset during MMC bus rescan.  That could kick the
> card hard enough for it to be re-enumerated and take firmware upload
> again.

Philip's patch is below.  The mmc/core/core.c stuff doesn't apply
directly any more, but the function getting patched is mmc_rescan() as
far as I can tell.  Give it a shot and see if it helps you.

Pierre tried something similar a while ago but noticed problems with the
cards getting wedged because they saw the SDIO ABORT on the bus before
being fully enumerated, or something like that.

Dan


diff -Nur linux-2.6.22.18-feroceon_4_1_4_KW/drivers/mmc/core/core.c inux-2.6.22.18-feroceon_4_1_4_KW-PATCHED/drivers/mmc/core/core.c
--- linux-2.6.22.18-feroceon_4_1_4_KW/drivers/mmc/core/core.c   2008-11-13 02:55:47.000000000 -0800
+++ inux-2.6.22.18-feroceon_4_1_4_KW-PATCHED/drivers/mmc/core/core.c    2009-01-20 13:14:31.000000000 -0800
@@ -659,6 +659,10 @@
                host->mode = MMC_MODE_SDIO;
 
                mmc_set_ios(host);
+               
+               /* reset sdio hardware */
+               mmc_force_reset(host);
+
                err = mmc_send_io_op_cond(host, 0, &ocr);
                if (!err) {
                        if (mmc_attach_sdio(host, ocr))
diff -Nur linux-2.6.22.18-feroceon_4_1_4_KW/drivers/mmc/core/mmc_ops.c inux-2.6.22.18-feroceon_4_1_4_KW-PATCHED/drivers/mmc/core/mmc_ops.c
--- linux-2.6.22.18-feroceon_4_1_4_KW/drivers/mmc/core/mmc_ops.c        2008-08-26 21:01:15.000000000 -0700
+++ inux-2.6.22.18-feroceon_4_1_4_KW-PATCHED/drivers/mmc/core/mmc_ops.c 2009-01-20 13:17:21.000000000 -0800
@@ -20,6 +20,38 @@
 #include "core.h"
 #include "mmc_ops.h"
 
+int mmc_force_reset (struct mmc_host *host)
+
+{
+        struct mmc_command cmd;
+        int err = 0;
+        
+        BUG_ON(!host);
+        
+#ifndef SD_IO_RW_DIRECT
+#define SD_IO_RW_DIRECT 52
+#endif
+
+#ifndef SDIO_CCCR_ABORT
+#define SDIO_CCCR_ABORT  0x06
+#endif
+
+#ifndef PMR_WRITE
+#define PMR_WRITE 1
+#endif
+
+       memset(&cmd, 0, sizeof(struct mmc_command));
+       cmd.opcode = SD_IO_RW_DIRECT;
+       cmd.arg = PMR_WRITE ? 0x80000000 : 0x00000000;
+       cmd.arg |= 0<<28;
+       cmd.arg |= 0x00000000;
+       cmd.arg |= SDIO_CCCR_ABORT << 9;
+       cmd.arg |= (1<<3) ;
+       cmd.flags = MMC_RSP_NONE;
+       err = mmc_wait_for_cmd(host, &cmd, 0);
+       return err;
+}
+
 static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
 {
        int err;
diff -Nur linux-2.6.22.18-feroceon_4_1_4_KW/drivers/mmc/core/mmc_ops.h inux-2.6.22.18-feroceon_4_1_4_KW-PATCHED/drivers/mmc/core/mmc_ops.h
--- linux-2.6.22.18-feroceon_4_1_4_KW/drivers/mmc/core/mmc_ops.h        2008-08-26 21:01:15.000000000 -0700
+++ inux-2.6.22.18-feroceon_4_1_4_KW-PATCHED/drivers/mmc/core/mmc_ops.h 2009-01-20 13:17:30.000000000 -0800
@@ -12,6 +12,7 @@
 #ifndef _MMC_MMC_OPS_H
 #define _MMC_MMC_OPS_H
 
+int mmc_force_reset (struct mmc_host *host);
 int mmc_select_card(struct mmc_card *card);
 int mmc_deselect_cards(struct mmc_host *host);
 int mmc_go_idle(struct mmc_host *host);





More information about the libertas-dev mailing list