freebsd-dev/sys/dev/ath/if_ath_led.c
Adrian Chadd f5c30c4e8d Bring over some initial power save management support, reset path
fixes and beacon programming / debugging into the ath(4) driver.

The basic power save tracking:

* Add some new code to track the current desired powersave state; and
* Add some reference count tracking so we know when the NIC is awake; then
* Add code in all the points where we're about to touch the hardware and
  push it to force-wake.

Then, how things are moved into power save:

* Only move into network-sleep during a RUN->SLEEP transition;
* Force wake the hardware up everywhere that we're about to touch
  the hardware.

The net80211 stack takes care of doing RUN<->SLEEP<->(other) state
transitions so we don't have to do it in the driver.

Next, when to wake things up:

* In short - everywhere we touch the hardware.
* The hardware will take care of staying awake if things are queued
  in the transmit queue(s); it'll then transit down to sleep if
  there's nothing left.  This way we don't have to track the
  software / hardware transmit queue(s) and keep the hardware
  awake for those.

Then, some transmit path fixes that aren't related but useful:

* Force EAPOL frames to go out at the lowest rate.  This improves
  reliability during the encryption handshake after 802.11
  negotiation.

Next, some reset path fixes!

* Fix the overlap between reset and transmit pause so we don't
  transmit frames during a reset.
* Some noisy environments will end up taking a lot longer to reset
  than normal, so extend the reset period and drop the raise the
  reset interval to be more realistic and give the hardware some
  time to finish calibration.
* Skip calibration during the reset path.  Tsk!

Then, beacon fixes in station mode!

* Add a _lot_ more debugging in the station beacon reset path.
  This is all quite fluid right now.
* Modify the STA beacon programming code to try and take
  the TU gap between desired TSF and the target TU into
  account.  (Lifted from QCA.)

Tested:

* AR5210
* AR5211
* AR5212
* AR5413
* AR5416
* AR9280
* AR9285

TODO:

* More AP, IBSS, mesh, TDMA testing
* Thorough AR9380 and later testing!
* AR9160 and AR9287 testing

Obtained from:	QCA
2014-04-30 02:19:41 +00:00

200 lines
5.3 KiB
C

/*-
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* Driver for the Atheros Wireless LAN controller.
*
* This software is derived from work of Atsushi Onoe; his contribution
* is greatly appreciated.
*/
#include "opt_inet.h"
#include "opt_ath.h"
/*
* This is needed for register operations which are performed
* by the driver - eg, calls to ath_hal_gettsf32().
*/
#include "opt_ah.h"
#include "opt_wlan.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/errno.h>
#include <sys/callout.h>
#include <sys/bus.h>
#include <sys/endian.h>
#include <sys/kthread.h>
#include <sys/taskqueue.h>
#include <sys/priv.h>
#include <sys/module.h>
#include <sys/ktr.h>
#include <sys/smp.h> /* for mp_ncpus */
#include <machine/bus.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
#include <net/if_llc.h>
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_regdomain.h>
#ifdef IEEE80211_SUPPORT_SUPERG
#include <net80211/ieee80211_superg.h>
#endif
#ifdef IEEE80211_SUPPORT_TDMA
#include <net80211/ieee80211_tdma.h>
#endif
#include <net/bpf.h>
#ifdef INET
#include <netinet/in.h>
#include <netinet/if_ether.h>
#endif
#include <dev/ath/if_athvar.h>
#include <dev/ath/ath_hal/ah_devid.h> /* XXX for softled */
#include <dev/ath/ath_hal/ah_diagcodes.h>
#include <dev/ath/if_ath_debug.h>
#include <dev/ath/if_ath_misc.h>
#include <dev/ath/if_ath_led.h>
/*
* Software LED driver routines.
*/
/*
* XXX TODO: move the LED sysctls here.
*/
/*
* Configure the hardware for software and LED blinking.
* The user may choose to configure part of each, depending upon the
* NIC being used.
*
* This requires the configuration to be set before this function
* is called.
*/
void
ath_led_config(struct ath_softc *sc)
{
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
ATH_UNLOCK(sc);
/* Software LED blinking - GPIO controlled LED */
if (sc->sc_softled) {
ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin,
HAL_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon);
}
/* Hardware LED blinking - MAC controlled LED */
if (sc->sc_hardled) {
/*
* Only enable each LED if required.
*
* Some NICs only have one LED connected; others may
* have GPIO1/GPIO2 connected to other hardware.
*/
if (sc->sc_led_pwr_pin > 0)
ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_led_pwr_pin,
HAL_GPIO_OUTPUT_MUX_MAC_POWER_LED);
if (sc->sc_led_net_pin > 0)
ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_led_net_pin,
HAL_GPIO_OUTPUT_MUX_MAC_NETWORK_LED);
}
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
}
static void
ath_led_done(void *arg)
{
struct ath_softc *sc = arg;
sc->sc_blinking = 0;
}
/*
* Turn the LED off: flip the pin and then set a timer so no
* update will happen for the specified duration.
*/
static void
ath_led_off(void *arg)
{
struct ath_softc *sc = arg;
ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon);
callout_reset(&sc->sc_ledtimer, sc->sc_ledoff, ath_led_done, sc);
}
/*
* Blink the LED according to the specified on/off times.
*/
static void
ath_led_blink(struct ath_softc *sc, int on, int off)
{
DPRINTF(sc, ATH_DEBUG_LED, "%s: on %u off %u\n", __func__, on, off);
ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, sc->sc_ledon);
sc->sc_blinking = 1;
sc->sc_ledoff = off;
callout_reset(&sc->sc_ledtimer, on, ath_led_off, sc);
}
void
ath_led_event(struct ath_softc *sc, int rix)
{
sc->sc_ledevent = ticks; /* time of last event */
if (sc->sc_blinking) /* don't interrupt active blink */
return;
ath_led_blink(sc, sc->sc_hwmap[rix].ledon, sc->sc_hwmap[rix].ledoff);
}