Search Linux Wireless

Re: [PATCH 3/4] ath5k: Wakeup fixes

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

 



On Fri, Jul 31, 2009 at 11:08 AM, NickKossifidis<mick@xxxxxxxxxxxxxxxxxxx> wrote:>  * Don't put chip to full sleep because there are problems during>   wakeup. Instead hold MAC/Baseband on warm reset state via a new>   function ath5k_hw_on_hold.>>  * Durring attach preserve pcicfg bits when enabling pci core>   sw retry fix.>>  * Minor cleanups
Can you address these changes separately? I see you tend to itemizethe things you change, even when you just make one change. Pleaseconsider addressing one change per commit and just ensure the why iscrystal clear.
  Luis
> --->  drivers/net/wireless/ath/ath5k/ath5k.h  |    1 +>  drivers/net/wireless/ath/ath5k/attach.c |    4 +->  drivers/net/wireless/ath/ath5k/base.c   |   44 +++++---->  drivers/net/wireless/ath/ath5k/reset.c  |  155 +++++++++++++++++++++++-------->  4 files changed, 141 insertions(+), 63 deletions(-)>> diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h> index 9137511..1047a6c 100644> --- a/drivers/net/wireless/ath/ath5k/ath5k.h> +++ b/drivers/net/wireless/ath/ath5k/ath5k.h> @@ -1157,6 +1157,7 @@ extern void ath5k_unregister_leds(struct ath5k_softc *sc);>>  /* Reset Functions */>  extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);> +extern int ath5k_hw_on_hold(struct ath5k_hw *ah);>  extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel);>  /* Power management functions */>  extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration);> diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c> index 6263065..65d438b 100644> --- a/drivers/net/wireless/ath/ath5k/attach.c> +++ b/drivers/net/wireless/ath/ath5k/attach.c> @@ -145,7 +145,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)>                goto err_free;>>        /* Bring device out of sleep and reset it's units */> -       ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, true);> +       ret = ath5k_hw_nic_wakeup(ah, 0, true);>        if (ret)>                goto err_free;>> @@ -261,7 +261,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)>>        /* Enable pci core retry fix on Hainan (5213A) and later chips */>        if (srev >= AR5K_SREV_AR5213A)> -               ath5k_hw_reg_write(ah, AR5K_PCICFG_RETRY_FIX, AR5K_PCICFG);> +               AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_RETRY_FIX);>>        /*>         * Get card capabilities, calibration values etc> diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c> index 7db32ce..b64731b 100644> --- a/drivers/net/wireless/ath/ath5k/base.c> +++ b/drivers/net/wireless/ath/ath5k/base.c> @@ -2448,27 +2448,29 @@ ath5k_stop_hw(struct ath5k_softc *sc)>        ret = ath5k_stop_locked(sc);>        if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) {>                /*> -                * Set the chip in full sleep mode.  Note that we are> -                * careful to do this only when bringing the interface> -                * completely to a stop.  When the chip is in this state> -                * it must be carefully woken up or references to> -                * registers in the PCI clock domain may freeze the bus> -                * (and system).  This varies by chip and is mostly an> -                * issue with newer parts that go to sleep more quickly.> -                */> -               if (sc->ah->ah_mac_srev >= 0x78) {> -                       /*> -                        * XXX> -                        * don't put newer MAC revisions > 7.8 to sleep because> -                        * of the above mentioned problems> -                        */> -                       ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, "> -                               "not putting device to sleep\n");> -               } else {> -                       ATH5K_DBG(sc, ATH5K_DEBUG_RESET,> -                               "putting device to full sleep\n");> -                       ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0);> -               }> +                * Don't set the card in full sleep mode!> +                *> +                * a) When the device is in this state it must be carefully> +                * woken up or references to registers in the PCI clock> +                * domain may freeze the bus (and system).  This varies> +                * by chip and is mostly an issue with newer parts> +                * (madwifi sources mentioned srev >= 0x78) that go to> +                * sleep more quickly.> +                *> +                * b) On older chips full sleep results a weird behaviour> +                * during wakeup. I tested various cards with srev < 0x78> +                * and they don't wake up after module reload, a second> +                * module reload is needed to bring the card up again.> +                *> +                * Until we figure out what's going on don't enable> +                * full chip reset on any chip (this is what Legacy HAL> +                * and Sam's HAL do anyway). Instead Perform a full reset> +                * on the device (same as initial state after attach) and> +                * leave it idle (keep MAC/BB on warm reset) */> +               ret = ath5k_hw_on_hold(sc->ah);> +> +               ATH5K_DBG(sc, ATH5K_DEBUG_RESET,> +                               "putting device to sleep\n");>        }>        ath5k_txbuf_free(sc, sc->bbuf);>> diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c> index 86733fd..34e13c7 100644> --- a/drivers/net/wireless/ath/ath5k/reset.c> +++ b/drivers/net/wireless/ath/ath5k/reset.c> @@ -258,29 +258,35 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,>                if (!set_chip)>                        goto commit;>> -               /* Preserve sleep duration */>                data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);> +> +               /* If card is down we 'll get 0xffff... so we> +                * need to clean this up before we write the register> +                */>                if (data & 0xffc00000)>                        data = 0;>                else> -                       data = data & 0xfffcffff;> +                       /* Preserve sleep duration etc */> +                       data = data & ~AR5K_SLEEP_CTL_SLE;>> -               ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);> +               ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,> +                                                       AR5K_SLEEP_CTL);>                udelay(15);>> -               for (i = 50; i > 0; i--) {> +               for (i = 200; i > 0; i--) {>                        /* Check if the chip did wake up */>                        if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &>                                        AR5K_PCICFG_SPWR_DN) == 0)>                                break;>>                        /* Wait a bit and retry */> -                       udelay(200);> -                       ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);> +                       udelay(50);> +                       ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,> +                                                       AR5K_SLEEP_CTL);>                }>>                /* Fail if the chip didn't wake up */> -               if (i <= 0)> +               if (i == 0)>                        return -EIO;>>                break;> @@ -296,6 +302,64 @@ commit:>  }>>  /*> + * Put device on hold> + *> + * Put MAC and Baseband on warm reset and> + * keep that state (don't clean sleep control> + * register). After this MAC and Baseband are> + * disabled and a full reset is needed to come> + * back. This way we save as much power as possible> + * without puting the card on full sleep.> + */> +int ath5k_hw_on_hold(struct ath5k_hw *ah)> +{> +       struct pci_dev *pdev = ah->ah_sc->pdev;> +       u32 bus_flags;> +       int ret;> +> +       /* Make sure device is awake */> +       ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);> +       if (ret) {> +               ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");> +               return ret;> +       }> +> +       /*> +        * Put chipset on warm reset...> +        *> +        * Note: puting PCI core on warm reset on PCI-E cards> +        * results card to hang and always return 0xffff... so> +        * we ingore that flag for PCI-E cards. On PCI cards> +        * this flag gets cleared after 64 PCI clocks.> +        */> +       bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;> +> +       if (ah->ah_version == AR5K_AR5210) {> +               ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |> +                       AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |> +                       AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);> +                       mdelay(2);> +       } else {> +               ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |> +                       AR5K_RESET_CTL_BASEBAND | bus_flags);> +       }> +> +       if (ret) {> +               ATH5K_ERR(ah->ah_sc, "failed to put device on warm reset\n");> +               return -EIO;> +       }> +> +       /* ...wakeup again!*/> +       ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);> +       if (ret) {> +               ATH5K_ERR(ah->ah_sc, "failed to put device on hold\n");> +               return ret;> +       }> +> +       return ret;> +}> +> +/*>  * Bring up MAC + PHY Chips and program PLL>  * TODO: Half/Quarter rate support>  */> @@ -318,6 +382,50 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)>                return ret;>        }>> +       /*> +        * Put chipset on warm reset...> +        *> +        * Note: puting PCI core on warm reset on PCI-E cards> +        * results card to hang and always return 0xffff... so> +        * we ingore that flag for PCI-E cards. On PCI cards> +        * this flag gets cleared after 64 PCI clocks.> +        */> +       bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;> +> +       if (ah->ah_version == AR5K_AR5210) {> +               ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |> +                       AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |> +                       AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);> +                       mdelay(2);> +       } else {> +               ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |> +                       AR5K_RESET_CTL_BASEBAND | bus_flags);> +       }> +> +       if (ret) {> +               ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");> +               return -EIO;> +       }> +> +       /* ...wakeup again!...*/> +       ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);> +       if (ret) {> +               ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");> +               return ret;> +       }> +> +       /* ...clear reset control register and pull device out of> +        * warm reset */> +       if (ath5k_hw_nic_reset(ah, 0)) {> +               ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");> +               return -EIO;> +       }> +> +       /* On initialization skip PLL programming since we don't have> +        * a channel / mode set yet */> +       if (initial)> +               return 0;> +>        if (ah->ah_version != AR5K_AR5210) {>                /*>                 * Get channel mode flags> @@ -383,39 +491,6 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)>                                        AR5K_PHY_TURBO);>        }>> -       /* reseting PCI on PCI-E cards results card to hang> -        * and always return 0xffff... so we ingore that flag> -        * for PCI-E cards */> -       bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;> -> -       /* Reset chipset */> -       if (ah->ah_version == AR5K_AR5210) {> -               ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |> -                       AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |> -                       AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);> -                       mdelay(2);> -       } else {> -               ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |> -                       AR5K_RESET_CTL_BASEBAND | bus_flags);> -       }> -       if (ret) {> -               ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");> -               return -EIO;> -       }> -> -       /* ...wakeup again!*/> -       ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);> -       if (ret) {> -               ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");> -               return ret;> -       }> -> -       /* ...final warm reset */> -       if (ath5k_hw_nic_reset(ah, 0)) {> -               ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");> -               return -EIO;> -       }> ->        if (ah->ah_version != AR5K_AR5210) {>>                /* ...update PLL if needed */>��.n��������+%������w��{.n�����{���zW����ܨ}���Ơz�j:+v�����w����ޙ��&�)ߡ�a����z�ޗ���ݢj��w�f


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux