[PATCH, take 3] libertas: fix compact flash interrupt handling
Dan Williams
dcbw at redhat.com
Tue May 27 16:20:28 EDT 2008
On Tue, 2008-05-27 at 16:14 -0400, Dan Williams wrote:
> On Mon, 2008-05-26 at 12:50 +0200, Holger Schurig wrote:
> > The old code misbehaved because it polled card status and always called the
> > "tx over" code-path.
> >
> > This also fixes a hard lockup by not allowing and card interrupts while
> > transferring a TX frame or a command into the card.
>
> So I still get stalls with this latest set on my Fujitsu, but that
> doesn't mean the patch shouldn't be applied. It doesn't work any
> _worse_ than before. It also worked better than before the first time I
> tried it. I have logs.
>
> Behavior is basically that the TX watchdog timer fires, then the
> libertas TX timeout handler tries to send the RSSI command, which also
> times out and gets requeued forever.
>
> The first time I got a few hundred MBs into an ISO before the stall, and
> got an interesting WARNING from the kernel while in the TX timeout
> handler when attempting to send the RSSI command.
>
> The second time I started a ping of machine B (where the Libertas CF
> card is) from the machine B (on which the ISO image is), while scp-ing
"from machine A" that should read...
> the ISO from machine A to machine B. This got only a few MB in before
> the same behavior occurred.
>
> I really don't know what to do to trace it further. Is there a way to
> reset the CF card and kick the firmware in the head that I can try from
> the TX handler, like a USB port reset or something? I also might be
and that should be "that I can try from the TX timeout handler"
> able to set this machine up for remote access so you can play with it if
> you like.
>
> But again; if the patch works better for you, I'll ack it because it
> doesn't work any worse for me. Logs with libertas_debug=0x443af
> available if you want to see them.
>
> Dan
>
> > Signed-off-by: Holger Schurig <hs4233 at mail.mn-solutions.de>
> >
> > Index: wireless-testing/drivers/net/wireless/libertas/if_cs.c
> > ===================================================================
> > --- wireless-testing.orig/drivers/net/wireless/libertas/if_cs.c 2008-05-26 08:53:27.000000000 +0200
> > +++ wireless-testing/drivers/net/wireless/libertas/if_cs.c 2008-05-26 10:27:24.000000000 +0200
> > @@ -215,9 +215,21 @@ static int if_cs_poll_while_fw_download(
> >
> >
> > /********************************************************************/
> > -/* I/O */
> > +/* I/O and interrupt handling */
> > /********************************************************************/
> >
> > +static inline void if_cs_enable_ints(struct if_cs_card *card)
> > +{
> > + lbs_deb_enter(LBS_DEB_CS);
> > + if_cs_write16(card, IF_CS_H_INT_MASK, 0);
> > +}
> > +
> > +static inline void if_cs_disable_ints(struct if_cs_card *card)
> > +{
> > + lbs_deb_enter(LBS_DEB_CS);
> > + if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
> > +}
> > +
> > /*
> > * Called from if_cs_host_to_card to send a command to the hardware
> > */
> > @@ -228,6 +240,7 @@ static int if_cs_send_cmd(struct lbs_pri
> > int loops = 0;
> >
> > lbs_deb_enter(LBS_DEB_CS);
> > + if_cs_disable_ints(card);
> >
> > /* Is hardware ready? */
> > while (1) {
> > @@ -258,19 +271,24 @@ static int if_cs_send_cmd(struct lbs_pri
> > ret = 0;
> >
> > done:
> > + if_cs_enable_ints(card);
> > lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
> > return ret;
> > }
> >
> > -
> > /*
> > * Called from if_cs_host_to_card to send a data to the hardware
> > */
> > static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
> > {
> > struct if_cs_card *card = (struct if_cs_card *)priv->card;
> > + u16 status;
> >
> > lbs_deb_enter(LBS_DEB_CS);
> > + if_cs_disable_ints(card);
> > +
> > + status = if_cs_read16(card, IF_CS_C_STATUS);
> > + BUG_ON((status & IF_CS_C_S_TX_DNLD_RDY) == 0);
> >
> > if_cs_write16(card, IF_CS_H_WRITE_LEN, nb);
> >
> > @@ -281,11 +299,11 @@ static void if_cs_send_data(struct lbs_p
> >
> > if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER);
> > if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER);
> > + if_cs_enable_ints(card);
> >
> > lbs_deb_leave(LBS_DEB_CS);
> > }
> >
> > -
> > /*
> > * Get the command result out of the card.
> > */
> > @@ -330,7 +348,6 @@ out:
> > return ret;
> > }
> >
> > -
> > static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
> > {
> > struct sk_buff *skb = NULL;
> > @@ -367,25 +384,6 @@ out:
> > return skb;
> > }
> >
> > -
> > -
> > -/********************************************************************/
> > -/* Interrupts */
> > -/********************************************************************/
> > -
> > -static inline void if_cs_enable_ints(struct if_cs_card *card)
> > -{
> > - lbs_deb_enter(LBS_DEB_CS);
> > - if_cs_write16(card, IF_CS_H_INT_MASK, 0);
> > -}
> > -
> > -static inline void if_cs_disable_ints(struct if_cs_card *card)
> > -{
> > - lbs_deb_enter(LBS_DEB_CS);
> > - if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
> > -}
> > -
> > -
> > static irqreturn_t if_cs_interrupt(int irq, void *data)
> > {
> > struct if_cs_card *card = data;
> > @@ -394,10 +392,8 @@ static irqreturn_t if_cs_interrupt(int i
> >
> > lbs_deb_enter(LBS_DEB_CS);
> >
> > + /* Ask card interrupt cause register if there is something for us */
> > cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
> > - if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK);
> > -
> > - lbs_deb_cs("cause 0x%04x\n", cause);
> > if (cause == 0) {
> > /* Not for us */
> > return IRQ_NONE;
> > @@ -409,9 +405,9 @@ static irqreturn_t if_cs_interrupt(int i
> > return IRQ_HANDLED;
> > }
> >
> > - /* TODO: I'm not sure what the best ordering is */
> > -
> > - cause = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
> > + /* Clear interrupt cause */
> > + if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK);
> > + lbs_deb_cs("cause 0x%04x\n", cause);
> >
> > if (cause & IF_CS_C_S_RX_UPLD_RDY) {
> > struct sk_buff *skb;
> > @@ -422,7 +418,7 @@ static irqreturn_t if_cs_interrupt(int i
> > }
> >
> > if (cause & IF_CS_H_IC_TX_OVER) {
> > - lbs_deb_cs("tx over\n");
> > + lbs_deb_cs("tx done\n");
> > lbs_host_to_card_done(priv);
> > }
> >
> > @@ -430,7 +426,7 @@ static irqreturn_t if_cs_interrupt(int i
> > unsigned long flags;
> > u8 i;
> >
> > - lbs_deb_cs("cmd upload ready\n");
> > + lbs_deb_cs("cmd resp\n");
> > spin_lock_irqsave(&priv->driver_lock, flags);
> > i = (priv->resp_idx == 0) ? 1 : 0;
> > spin_unlock_irqrestore(&priv->driver_lock, flags);
> > @@ -449,10 +445,11 @@ static irqreturn_t if_cs_interrupt(int i
> > & IF_CS_C_S_STATUS_MASK;
> > if_cs_write16(priv->card, IF_CS_H_INT_CAUSE,
> > IF_CS_H_IC_HOST_EVENT);
> > - lbs_deb_cs("eventcause 0x%04x\n", event);
> > + lbs_deb_cs("host event 0x%04x\n", event);
> > lbs_queue_event(priv, event >> 8 & 0xff);
> > }
> >
> > + lbs_deb_leave(LBS_DEB_CS);
> > return IRQ_HANDLED;
> > }
> >
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the libertas-dev
mailing list