tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Atheros AR5212 suspension breaks WPA



I am struggling to preserve the WPA functions of an Atheros AR5212 CardBus
card over a suspend/resume cycle.  I have about run out of things to try,
so I am writing here to see if anyone has advice.

After ath(4) resumes, WPA does not work properly: ath(4) cannot decrypt
the unicast packets sent by the AP.  I print the Rx descriptors for the
undecryptable packets, which are marked HAL_RXERR_DECRYPT, and keyix
ordinarily equals 0.  Occasionally it equals 1.

WPA is not completely broken after the driver resumes.  Hosts on the
same ethernet as the AP receive my ath(4)'s multicast and unicast
transmissions.  My ath(4) receives multicast packets transmitted by
the AP.  It seems like the group crypto key was established in the h/w,
the unicast Tx key was established in the h/w, but the unicast Rx key
was not established.

The trouble seems to be caused by turning off the cardslot's power.
If I patch cardbus_child_suspend() so that it does not turn off the
cardslot power, then ath(4) resumes with WPA functions working.

My current hypothesis is that some hardware initialization occurs in
ath_attach() that I have not been able to replicate in ath_resume().
Below is the bus-independent resume function that I am using.
Incidentally, it reliably prints

ath0: ath_resume: keyix 71 still valid after reset
ath0: ath_resume: keyix 79 still valid after reset
ath0: ath_resume: keyix 87 still valid after reset
ath0: ath_resume: keyix 95 still valid after reset
ath0: ath_resume: keyix 103 still valid after reset
ath0: ath_resume: keyix 111 still valid after reset
ath0: ath_resume: keyix 119 still valid after reset
ath0: ath_resume: keyix 127 still valid after reset

I expect for a "reset" key to be "invalid," and that is so after the keys
are reset in ath_attach(), but maybe I have made an incorrect assumption.

void
ath_resume(struct ath_softc *sc)
{
        int i;
        struct ath_hal *ah = sc->sc_ah;

        ath_hal_setpower(sc->sc_ah, HAL_PM_AWAKE);

        /*
         * Reset the key cache since some parts do not
         * reset the contents on initial power up.
         */
        for (i = 0; i < sc->sc_keymax; i++)
                ath_hal_keyreset(ah, i);

        for (i = 0; i < sc->sc_keymax; i++) {
                if (ath_hal_keyisvalid(ah, i)) {
                        aprint_error_dev(&sc->sc_dev,
                            "%s: keyix %d still valid after reset\n", __func__,
                            i);
                }
        }

        ath_hal_resettxqueue(ah, sc->sc_bhalq);
        for (i = 0; i < HAL_NUM_TX_QUEUES; i++)
                if (ATH_TXQ_SETUP(sc, i))
                        ath_hal_resettxqueue(ah, i);

        if (sc->sc_softled) {
                ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin);
                ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon);
        }
}

Dave

-- 
David Young             OJC Technologies
dyoung%ojctech.com@localhost      Urbana, IL * (217) 278-3933 ext 24


Home | Main Index | Thread Index | Old Index