freebsd-skq/sys/dev/ath/if_ath_sysctl.c
glebius 619aca846f Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.

Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.

Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:

- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
  the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
  driver about any changes: number of wlan(4) interfaces, number of them
  in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
  driver experiences errors and can not attribute them to any specific
  interface, driver updates ic_oerrors or ic_ierrors counters.

Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
  now provided by net.wlan.devices sysctl.

Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.

Reviewed by:	adrian
Sponsored by:	Netflix
Sponsored by:	Nginx, Inc.
2015-08-27 08:56:39 +00:00

1347 lines
43 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"
#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 <machine/bus.h>
#include <net/if.h>
#include <net/if_var.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_led.h>
#include <dev/ath/if_ath_misc.h>
#include <dev/ath/if_ath_tx.h>
#include <dev/ath/if_ath_sysctl.h>
#ifdef ATH_TX99_DIAG
#include <dev/ath/ath_tx99/ath_tx99.h>
#endif
#ifdef ATH_DEBUG_ALQ
#include <dev/ath/if_ath_alq.h>
#endif
static int
ath_sysctl_slottime(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
u_int slottime;
int error;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
slottime = ath_hal_getslottime(sc->sc_ah);
ATH_UNLOCK(sc);
error = sysctl_handle_int(oidp, &slottime, 0, req);
if (error || !req->newptr)
goto finish;
error = !ath_hal_setslottime(sc->sc_ah, slottime) ? EINVAL : 0;
finish:
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return error;
}
static int
ath_sysctl_acktimeout(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
u_int acktimeout;
int error;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
acktimeout = ath_hal_getacktimeout(sc->sc_ah);
ATH_UNLOCK(sc);
error = sysctl_handle_int(oidp, &acktimeout, 0, req);
if (error || !req->newptr)
goto finish;
error = !ath_hal_setacktimeout(sc->sc_ah, acktimeout) ? EINVAL : 0;
finish:
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return (error);
}
static int
ath_sysctl_ctstimeout(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
u_int ctstimeout;
int error;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
ctstimeout = ath_hal_getctstimeout(sc->sc_ah);
ATH_UNLOCK(sc);
error = sysctl_handle_int(oidp, &ctstimeout, 0, req);
if (error || !req->newptr)
goto finish;
error = !ath_hal_setctstimeout(sc->sc_ah, ctstimeout) ? EINVAL : 0;
finish:
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return (error);
}
static int
ath_sysctl_softled(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
int softled = sc->sc_softled;
int error;
error = sysctl_handle_int(oidp, &softled, 0, req);
if (error || !req->newptr)
return error;
softled = (softled != 0);
if (softled != sc->sc_softled) {
if (softled) {
/* NB: handle any sc_ledpin change */
ath_led_config(sc);
}
sc->sc_softled = softled;
}
return 0;
}
static int
ath_sysctl_ledpin(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
int ledpin = sc->sc_ledpin;
int error;
error = sysctl_handle_int(oidp, &ledpin, 0, req);
if (error || !req->newptr)
return error;
if (ledpin != sc->sc_ledpin) {
sc->sc_ledpin = ledpin;
if (sc->sc_softled) {
ath_led_config(sc);
}
}
return 0;
}
static int
ath_sysctl_hardled(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
int hardled = sc->sc_hardled;
int error;
error = sysctl_handle_int(oidp, &hardled, 0, req);
if (error || !req->newptr)
return error;
hardled = (hardled != 0);
if (hardled != sc->sc_hardled) {
if (hardled) {
/* NB: handle any sc_ledpin change */
ath_led_config(sc);
}
sc->sc_hardled = hardled;
}
return 0;
}
static int
ath_sysctl_txantenna(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
u_int txantenna;
int error;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
ATH_UNLOCK(sc);
txantenna = ath_hal_getantennaswitch(sc->sc_ah);
error = sysctl_handle_int(oidp, &txantenna, 0, req);
if (!error && req->newptr) {
/* XXX assumes 2 antenna ports */
if (txantenna < HAL_ANT_VARIABLE || txantenna > HAL_ANT_FIXED_B) {
error = EINVAL;
goto finish;
}
ath_hal_setantennaswitch(sc->sc_ah, txantenna);
/*
* NB: with the switch locked this isn't meaningful,
* but set it anyway so things like radiotap get
* consistent info in their data.
*/
sc->sc_txantenna = txantenna;
}
finish:
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return (error);
}
static int
ath_sysctl_rxantenna(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
u_int defantenna;
int error;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
defantenna = ath_hal_getdefantenna(sc->sc_ah);
ATH_UNLOCK(sc);
error = sysctl_handle_int(oidp, &defantenna, 0, req);
if (!error && req->newptr)
ath_hal_setdefantenna(sc->sc_ah, defantenna);
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return (error);
}
static int
ath_sysctl_diversity(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
u_int diversity;
int error;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
ATH_UNLOCK(sc);
diversity = ath_hal_getdiversity(sc->sc_ah);
error = sysctl_handle_int(oidp, &diversity, 0, req);
if (error || !req->newptr)
goto finish;
if (!ath_hal_setdiversity(sc->sc_ah, diversity)) {
error = EINVAL;
goto finish;
}
sc->sc_diversity = diversity;
error = 0;
finish:
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return (error);
}
static int
ath_sysctl_diag(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
u_int32_t diag;
int error;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
ATH_UNLOCK(sc);
if (!ath_hal_getdiag(sc->sc_ah, &diag)) {
error = EINVAL;
goto finish;
}
error = sysctl_handle_int(oidp, &diag, 0, req);
if (error || !req->newptr)
goto finish;
error = !ath_hal_setdiag(sc->sc_ah, diag) ? EINVAL : 0;
finish:
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return (error);
}
static int
ath_sysctl_tpscale(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
u_int32_t scale;
int error;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
ATH_UNLOCK(sc);
(void) ath_hal_gettpscale(sc->sc_ah, &scale);
error = sysctl_handle_int(oidp, &scale, 0, req);
if (error || !req->newptr)
goto finish;
error = !ath_hal_settpscale(sc->sc_ah, scale) ? EINVAL :
(sc->sc_running) ? ath_reset(sc, ATH_RESET_NOLOSS) : 0;
finish:
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return (error);
}
static int
ath_sysctl_tpc(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
u_int tpc;
int error;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
ATH_UNLOCK(sc);
tpc = ath_hal_gettpc(sc->sc_ah);
error = sysctl_handle_int(oidp, &tpc, 0, req);
if (error || !req->newptr)
goto finish;
error = !ath_hal_settpc(sc->sc_ah, tpc) ? EINVAL : 0;
finish:
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return (error);
}
static int
ath_sysctl_rfkill(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
struct ath_hal *ah = sc->sc_ah;
u_int rfkill;
int error;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
ATH_UNLOCK(sc);
rfkill = ath_hal_getrfkill(ah);
error = sysctl_handle_int(oidp, &rfkill, 0, req);
if (error || !req->newptr)
goto finish;
if (rfkill == ath_hal_getrfkill(ah)) { /* unchanged */
error = 0;
goto finish;
}
if (!ath_hal_setrfkill(ah, rfkill)) {
error = EINVAL;
goto finish;
}
error = sc->sc_running ? ath_reset(sc, ATH_RESET_FULL) : 0;
finish:
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return (error);
}
static int
ath_sysctl_txagg(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
int i, t, param = 0;
int error;
struct ath_buf *bf;
error = sysctl_handle_int(oidp, &param, 0, req);
if (error || !req->newptr)
return error;
if (param != 1)
return 0;
printf("no tx bufs (empty list): %d\n", sc->sc_stats.ast_tx_getnobuf);
printf("no tx bufs (was busy): %d\n", sc->sc_stats.ast_tx_getbusybuf);
printf("aggr single packet: %d\n",
sc->sc_aggr_stats.aggr_single_pkt);
printf("aggr single packet w/ BAW closed: %d\n",
sc->sc_aggr_stats.aggr_baw_closed_single_pkt);
printf("aggr non-baw packet: %d\n",
sc->sc_aggr_stats.aggr_nonbaw_pkt);
printf("aggr aggregate packet: %d\n",
sc->sc_aggr_stats.aggr_aggr_pkt);
printf("aggr single packet low hwq: %d\n",
sc->sc_aggr_stats.aggr_low_hwq_single_pkt);
printf("aggr single packet RTS aggr limited: %d\n",
sc->sc_aggr_stats.aggr_rts_aggr_limited);
printf("aggr sched, no work: %d\n",
sc->sc_aggr_stats.aggr_sched_nopkt);
for (i = 0; i < 64; i++) {
printf("%2d: %10d ", i, sc->sc_aggr_stats.aggr_pkts[i]);
if (i % 4 == 3)
printf("\n");
}
printf("\n");
for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(sc, i)) {
printf("HW TXQ %d: axq_depth=%d, axq_aggr_depth=%d, "
"axq_fifo_depth=%d, holdingbf=%p\n",
i,
sc->sc_txq[i].axq_depth,
sc->sc_txq[i].axq_aggr_depth,
sc->sc_txq[i].axq_fifo_depth,
sc->sc_txq[i].axq_holdingbf);
}
}
i = t = 0;
ATH_TXBUF_LOCK(sc);
TAILQ_FOREACH(bf, &sc->sc_txbuf, bf_list) {
if (bf->bf_flags & ATH_BUF_BUSY) {
printf("Busy: %d\n", t);
i++;
}
t++;
}
ATH_TXBUF_UNLOCK(sc);
printf("Total TX buffers: %d; Total TX buffers busy: %d (%d)\n",
t, i, sc->sc_txbuf_cnt);
i = t = 0;
ATH_TXBUF_LOCK(sc);
TAILQ_FOREACH(bf, &sc->sc_txbuf_mgmt, bf_list) {
if (bf->bf_flags & ATH_BUF_BUSY) {
printf("Busy: %d\n", t);
i++;
}
t++;
}
ATH_TXBUF_UNLOCK(sc);
printf("Total mgmt TX buffers: %d; Total mgmt TX buffers busy: %d\n",
t, i);
ATH_RX_LOCK(sc);
for (i = 0; i < 2; i++) {
printf("%d: fifolen: %d/%d; head=%d; tail=%d; m_pending=%p, m_holdbf=%p\n",
i,
sc->sc_rxedma[i].m_fifo_depth,
sc->sc_rxedma[i].m_fifolen,
sc->sc_rxedma[i].m_fifo_head,
sc->sc_rxedma[i].m_fifo_tail,
sc->sc_rxedma[i].m_rxpending,
sc->sc_rxedma[i].m_holdbf);
}
i = 0;
TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
i++;
}
printf("Total RX buffers in free list: %d buffers\n",
i);
ATH_RX_UNLOCK(sc);
return 0;
}
static int
ath_sysctl_rfsilent(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
u_int rfsilent;
int error;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
ATH_UNLOCK(sc);
(void) ath_hal_getrfsilent(sc->sc_ah, &rfsilent);
error = sysctl_handle_int(oidp, &rfsilent, 0, req);
if (error || !req->newptr)
goto finish;
if (!ath_hal_setrfsilent(sc->sc_ah, rfsilent)) {
error = EINVAL;
goto finish;
}
/*
* Earlier chips (< AR5212) have up to 8 GPIO
* pins exposed.
*
* AR5416 and later chips have many more GPIO
* pins (up to 16) so the mask is expanded to
* four bits.
*/
sc->sc_rfsilentpin = rfsilent & 0x3c;
sc->sc_rfsilentpol = (rfsilent & 0x2) != 0;
error = 0;
finish:
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return (error);
}
static int
ath_sysctl_tpack(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
u_int32_t tpack;
int error;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
ATH_UNLOCK(sc);
(void) ath_hal_gettpack(sc->sc_ah, &tpack);
error = sysctl_handle_int(oidp, &tpack, 0, req);
if (error || !req->newptr)
goto finish;
error = !ath_hal_settpack(sc->sc_ah, tpack) ? EINVAL : 0;
finish:
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return (error);
}
static int
ath_sysctl_tpcts(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
u_int32_t tpcts;
int error;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
ATH_UNLOCK(sc);
(void) ath_hal_gettpcts(sc->sc_ah, &tpcts);
error = sysctl_handle_int(oidp, &tpcts, 0, req);
if (error || !req->newptr)
goto finish;
error = !ath_hal_settpcts(sc->sc_ah, tpcts) ? EINVAL : 0;
finish:
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return (error);
}
static int
ath_sysctl_intmit(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
int intmit, error;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
ATH_UNLOCK(sc);
intmit = ath_hal_getintmit(sc->sc_ah);
error = sysctl_handle_int(oidp, &intmit, 0, req);
if (error || !req->newptr)
goto finish;
/* reusing error; 1 here means "good"; 0 means "fail" */
error = ath_hal_setintmit(sc->sc_ah, intmit);
if (! error) {
error = EINVAL;
goto finish;
}
/*
* Reset the hardware here - disabling ANI in the HAL
* doesn't reset ANI related registers, so it'll leave
* things in an inconsistent state.
*/
if (sc->sc_running)
ath_reset(sc, ATH_RESET_NOLOSS);
error = 0;
finish:
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return (error);
}
#ifdef IEEE80211_SUPPORT_TDMA
static int
ath_sysctl_setcca(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
int setcca, error;
setcca = sc->sc_setcca;
error = sysctl_handle_int(oidp, &setcca, 0, req);
if (error || !req->newptr)
return error;
sc->sc_setcca = (setcca != 0);
return 0;
}
#endif /* IEEE80211_SUPPORT_TDMA */
static int
ath_sysctl_forcebstuck(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
int val = 0;
int error;
error = sysctl_handle_int(oidp, &val, 0, req);
if (error || !req->newptr)
return error;
if (val == 0)
return 0;
taskqueue_enqueue_fast(sc->sc_tq, &sc->sc_bstucktask);
val = 0;
return 0;
}
static int
ath_sysctl_hangcheck(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
int val = 0;
int error;
uint32_t mask = 0xffffffff;
uint32_t *sp;
uint32_t rsize;
struct ath_hal *ah = sc->sc_ah;
error = sysctl_handle_int(oidp, &val, 0, req);
if (error || !req->newptr)
return error;
if (val == 0)
return 0;
ATH_LOCK(sc);
ath_power_set_power_state(sc, HAL_PM_AWAKE);
ATH_UNLOCK(sc);
/* Do a hang check */
if (!ath_hal_getdiagstate(ah, HAL_DIAG_CHECK_HANGS,
&mask, sizeof(mask),
(void *) &sp, &rsize)) {
error = 0;
goto finish;
}
device_printf(sc->sc_dev, "%s: sp=0x%08x\n", __func__, *sp);
val = 0;
error = 0;
finish:
ATH_LOCK(sc);
ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return (error);
}
#ifdef ATH_DEBUG_ALQ
static int
ath_sysctl_alq_log(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
int error, enable;
enable = (sc->sc_alq.sc_alq_isactive);
error = sysctl_handle_int(oidp, &enable, 0, req);
if (error || !req->newptr)
return (error);
else if (enable)
error = if_ath_alq_start(&sc->sc_alq);
else
error = if_ath_alq_stop(&sc->sc_alq);
return (error);
}
/*
* Attach the ALQ debugging if required.
*/
static void
ath_sysctl_alq_attach(struct ath_softc *sc)
{
struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "alq", CTLFLAG_RD,
NULL, "Atheros ALQ logging parameters");
child = SYSCTL_CHILDREN(tree);
SYSCTL_ADD_STRING(ctx, child, OID_AUTO, "filename",
CTLFLAG_RW, sc->sc_alq.sc_alq_filename, 0, "ALQ filename");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"enable", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_alq_log, "I", "");
SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"debugmask", CTLFLAG_RW, &sc->sc_alq.sc_alq_debug, 0,
"ALQ debug mask");
SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"numlost", CTLFLAG_RW, &sc->sc_alq.sc_alq_numlost, 0,
"number lost");
}
#endif /* ATH_DEBUG_ALQ */
void
ath_sysctlattach(struct ath_softc *sc)
{
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
struct ath_hal *ah = sc->sc_ah;
SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"countrycode", CTLFLAG_RD, &sc->sc_eecc, 0,
"EEPROM country code");
SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"regdomain", CTLFLAG_RD, &sc->sc_eerd, 0,
"EEPROM regdomain code");
#ifdef ATH_DEBUG
SYSCTL_ADD_QUAD(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"debug", CTLFLAG_RW, &sc->sc_debug,
"control debugging printfs");
#endif
#ifdef ATH_DEBUG_ALQ
SYSCTL_ADD_QUAD(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"ktrdebug", CTLFLAG_RW, &sc->sc_ktrdebug,
"control debugging KTR");
#endif /* ATH_DEBUG_ALQ */
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"slottime", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_slottime, "I", "802.11 slot time (us)");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"acktimeout", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_acktimeout, "I", "802.11 ACK timeout (us)");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"ctstimeout", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_ctstimeout, "I", "802.11 CTS timeout (us)");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"softled", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_softled, "I", "enable/disable software LED support");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"ledpin", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_ledpin, "I", "GPIO pin connected to LED");
SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"ledon", CTLFLAG_RW, &sc->sc_ledon, 0,
"setting to turn LED on");
SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"ledidle", CTLFLAG_RW, &sc->sc_ledidle, 0,
"idle time for inactivity LED (ticks)");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"hardled", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_hardled, "I", "enable/disable hardware LED support");
/* XXX Laziness - configure pins, then flip hardled off/on */
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"led_net_pin", CTLFLAG_RW, &sc->sc_led_net_pin, 0,
"MAC Network LED pin, or -1 to disable");
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"led_pwr_pin", CTLFLAG_RW, &sc->sc_led_pwr_pin, 0,
"MAC Power LED pin, or -1 to disable");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"txantenna", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_txantenna, "I", "antenna switch");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"rxantenna", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_rxantenna, "I", "default/rx antenna");
if (ath_hal_hasdiversity(ah))
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"diversity", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_diversity, "I", "antenna diversity");
sc->sc_txintrperiod = ATH_TXINTR_PERIOD;
SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"txintrperiod", CTLFLAG_RW, &sc->sc_txintrperiod, 0,
"tx descriptor batching");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"diag", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_diag, "I", "h/w diagnostic control");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"tpscale", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_tpscale, "I", "tx power scaling");
if (ath_hal_hastpc(ah)) {
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"tpc", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_tpc, "I", "enable/disable per-packet TPC");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"tpack", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_tpack, "I", "tx power for ack frames");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"tpcts", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_tpcts, "I", "tx power for cts frames");
}
if (ath_hal_hasrfsilent(ah)) {
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"rfsilent", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_rfsilent, "I", "h/w RF silent config");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"rfkill", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_rfkill, "I", "enable/disable RF kill switch");
}
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"txagg", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_txagg, "I", "");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"forcebstuck", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_forcebstuck, "I", "");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"hangcheck", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_hangcheck, "I", "");
if (ath_hal_hasintmit(ah)) {
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"intmit", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_intmit, "I", "interference mitigation");
}
sc->sc_monpass = HAL_RXERR_DECRYPT | HAL_RXERR_MIC;
SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"monpass", CTLFLAG_RW, &sc->sc_monpass, 0,
"mask of error frames to pass when monitoring");
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"hwq_limit_nonaggr", CTLFLAG_RW, &sc->sc_hwq_limit_nonaggr, 0,
"Hardware non-AMPDU queue depth before software-queuing TX frames");
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"hwq_limit_aggr", CTLFLAG_RW, &sc->sc_hwq_limit_aggr, 0,
"Hardware AMPDU queue depth before software-queuing TX frames");
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"tid_hwq_lo", CTLFLAG_RW, &sc->sc_tid_hwq_lo, 0,
"");
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"tid_hwq_hi", CTLFLAG_RW, &sc->sc_tid_hwq_hi, 0,
"");
/* Aggregate length twiddles */
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"aggr_limit", CTLFLAG_RW, &sc->sc_aggr_limit, 0,
"Maximum A-MPDU size, or 0 for 'default'");
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"rts_aggr_limit", CTLFLAG_RW, &sc->sc_rts_aggr_limit, 0,
"Maximum A-MPDU size for RTS-protected frames, or '0' "
"for default");
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"delim_min_pad", CTLFLAG_RW, &sc->sc_delim_min_pad, 0,
"Enforce a minimum number of delimiters per A-MPDU "
" sub-frame");
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"txq_data_minfree", CTLFLAG_RW, &sc->sc_txq_data_minfree,
0, "Minimum free buffers before adding a data frame"
" to the TX queue");
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"txq_mcastq_maxdepth", CTLFLAG_RW,
&sc->sc_txq_mcastq_maxdepth, 0,
"Maximum buffer depth for multicast/broadcast frames");
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"txq_node_maxdepth", CTLFLAG_RW,
&sc->sc_txq_node_maxdepth, 0,
"Maximum buffer depth for a single node");
#if 0
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"cabq_enable", CTLFLAG_RW,
&sc->sc_cabq_enable, 0,
"Whether to transmit on the CABQ or not");
#endif
#ifdef IEEE80211_SUPPORT_TDMA
if (ath_hal_macversion(ah) > 0x78) {
sc->sc_tdmadbaprep = 2;
SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"dbaprep", CTLFLAG_RW, &sc->sc_tdmadbaprep, 0,
"TDMA DBA preparation time");
sc->sc_tdmaswbaprep = 10;
SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"swbaprep", CTLFLAG_RW, &sc->sc_tdmaswbaprep, 0,
"TDMA SWBA preparation time");
SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"guardtime", CTLFLAG_RW, &sc->sc_tdmaguard, 0,
"TDMA slot guard time");
SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"superframe", CTLFLAG_RD, &sc->sc_tdmabintval, 0,
"TDMA calculated super frame");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"setcca", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_setcca, "I", "enable CCA control");
}
#endif
#ifdef ATH_DEBUG_ALQ
ath_sysctl_alq_attach(sc);
#endif
}
static int
ath_sysctl_clearstats(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
int val = 0;
int error;
error = sysctl_handle_int(oidp, &val, 0, req);
if (error || !req->newptr)
return error;
if (val == 0)
return 0; /* Not clearing the stats is still valid */
memset(&sc->sc_stats, 0, sizeof(sc->sc_stats));
memset(&sc->sc_aggr_stats, 0, sizeof(sc->sc_aggr_stats));
memset(&sc->sc_intr_stats, 0, sizeof(sc->sc_intr_stats));
val = 0;
return 0;
}
static void
ath_sysctl_stats_attach_rxphyerr(struct ath_softc *sc, struct sysctl_oid_list *parent)
{
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
int i;
char sn[8];
tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx_phy_err", CTLFLAG_RD, NULL, "Per-code RX PHY Errors");
child = SYSCTL_CHILDREN(tree);
for (i = 0; i < 64; i++) {
snprintf(sn, sizeof(sn), "%d", i);
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, sn, CTLFLAG_RD, &sc->sc_stats.ast_rx_phy[i], 0, "");
}
}
static void
ath_sysctl_stats_attach_intr(struct ath_softc *sc,
struct sysctl_oid_list *parent)
{
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
int i;
char sn[8];
tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "sync_intr",
CTLFLAG_RD, NULL, "Sync interrupt statistics");
child = SYSCTL_CHILDREN(tree);
for (i = 0; i < 32; i++) {
snprintf(sn, sizeof(sn), "%d", i);
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, sn, CTLFLAG_RD,
&sc->sc_intr_stats.sync_intr[i], 0, "");
}
}
void
ath_sysctl_stats_attach(struct ath_softc *sc)
{
struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
/* Create "clear" node */
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"clear_stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_clearstats, "I", "clear stats");
/* Create stats node */
tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD,
NULL, "Statistics");
child = SYSCTL_CHILDREN(tree);
/* This was generated from if_athioctl.h */
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_watchdog", CTLFLAG_RD,
&sc->sc_stats.ast_watchdog, 0, "device reset by watchdog");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_hardware", CTLFLAG_RD,
&sc->sc_stats.ast_hardware, 0, "fatal hardware error interrupts");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_bmiss", CTLFLAG_RD,
&sc->sc_stats.ast_bmiss, 0, "beacon miss interrupts");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_bmiss_phantom", CTLFLAG_RD,
&sc->sc_stats.ast_bmiss_phantom, 0, "beacon miss interrupts");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_bstuck", CTLFLAG_RD,
&sc->sc_stats.ast_bstuck, 0, "beacon stuck interrupts");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rxorn", CTLFLAG_RD,
&sc->sc_stats.ast_rxorn, 0, "rx overrun interrupts");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rxeol", CTLFLAG_RD,
&sc->sc_stats.ast_rxeol, 0, "rx eol interrupts");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_txurn", CTLFLAG_RD,
&sc->sc_stats.ast_txurn, 0, "tx underrun interrupts");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_mib", CTLFLAG_RD,
&sc->sc_stats.ast_mib, 0, "mib interrupts");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_intrcoal", CTLFLAG_RD,
&sc->sc_stats.ast_intrcoal, 0, "interrupts coalesced");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_packets", CTLFLAG_RD,
&sc->sc_stats.ast_tx_packets, 0, "packet sent on the interface");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_mgmt", CTLFLAG_RD,
&sc->sc_stats.ast_tx_mgmt, 0, "management frames transmitted");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_discard", CTLFLAG_RD,
&sc->sc_stats.ast_tx_discard, 0, "frames discarded prior to assoc");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_qstop", CTLFLAG_RD,
&sc->sc_stats.ast_tx_qstop, 0, "output stopped 'cuz no buffer");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_encap", CTLFLAG_RD,
&sc->sc_stats.ast_tx_encap, 0, "tx encapsulation failed");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_nonode", CTLFLAG_RD,
&sc->sc_stats.ast_tx_nonode, 0, "tx failed 'cuz no node");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_nombuf", CTLFLAG_RD,
&sc->sc_stats.ast_tx_nombuf, 0, "tx failed 'cuz no mbuf");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_nomcl", CTLFLAG_RD,
&sc->sc_stats.ast_tx_nomcl, 0, "tx failed 'cuz no cluster");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_linear", CTLFLAG_RD,
&sc->sc_stats.ast_tx_linear, 0, "tx linearized to cluster");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_nodata", CTLFLAG_RD,
&sc->sc_stats.ast_tx_nodata, 0, "tx discarded empty frame");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_busdma", CTLFLAG_RD,
&sc->sc_stats.ast_tx_busdma, 0, "tx failed for dma resrcs");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_xretries", CTLFLAG_RD,
&sc->sc_stats.ast_tx_xretries, 0, "tx failed 'cuz too many retries");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_fifoerr", CTLFLAG_RD,
&sc->sc_stats.ast_tx_fifoerr, 0, "tx failed 'cuz FIFO underrun");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_filtered", CTLFLAG_RD,
&sc->sc_stats.ast_tx_filtered, 0, "tx failed 'cuz xmit filtered");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_shortretry", CTLFLAG_RD,
&sc->sc_stats.ast_tx_shortretry, 0, "tx on-chip retries (short)");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_longretry", CTLFLAG_RD,
&sc->sc_stats.ast_tx_longretry, 0, "tx on-chip retries (long)");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_badrate", CTLFLAG_RD,
&sc->sc_stats.ast_tx_badrate, 0, "tx failed 'cuz bogus xmit rate");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_noack", CTLFLAG_RD,
&sc->sc_stats.ast_tx_noack, 0, "tx frames with no ack marked");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_rts", CTLFLAG_RD,
&sc->sc_stats.ast_tx_rts, 0, "tx frames with rts enabled");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_cts", CTLFLAG_RD,
&sc->sc_stats.ast_tx_cts, 0, "tx frames with cts enabled");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_shortpre", CTLFLAG_RD,
&sc->sc_stats.ast_tx_shortpre, 0, "tx frames with short preamble");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_altrate", CTLFLAG_RD,
&sc->sc_stats.ast_tx_altrate, 0, "tx frames with alternate rate");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_protect", CTLFLAG_RD,
&sc->sc_stats.ast_tx_protect, 0, "tx frames with protection");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_ctsburst", CTLFLAG_RD,
&sc->sc_stats.ast_tx_ctsburst, 0, "tx frames with cts and bursting");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_ctsext", CTLFLAG_RD,
&sc->sc_stats.ast_tx_ctsext, 0, "tx frames with cts extension");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_nombuf", CTLFLAG_RD,
&sc->sc_stats.ast_rx_nombuf, 0, "rx setup failed 'cuz no mbuf");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_busdma", CTLFLAG_RD,
&sc->sc_stats.ast_rx_busdma, 0, "rx setup failed for dma resrcs");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_orn", CTLFLAG_RD,
&sc->sc_stats.ast_rx_orn, 0, "rx failed 'cuz of desc overrun");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_crcerr", CTLFLAG_RD,
&sc->sc_stats.ast_rx_crcerr, 0, "rx failed 'cuz of bad CRC");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_fifoerr", CTLFLAG_RD,
&sc->sc_stats.ast_rx_fifoerr, 0, "rx failed 'cuz of FIFO overrun");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_badcrypt", CTLFLAG_RD,
&sc->sc_stats.ast_rx_badcrypt, 0, "rx failed 'cuz decryption");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_badmic", CTLFLAG_RD,
&sc->sc_stats.ast_rx_badmic, 0, "rx failed 'cuz MIC failure");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_phyerr", CTLFLAG_RD,
&sc->sc_stats.ast_rx_phyerr, 0, "rx failed 'cuz of PHY err");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_tooshort", CTLFLAG_RD,
&sc->sc_stats.ast_rx_tooshort, 0, "rx discarded 'cuz frame too short");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_toobig", CTLFLAG_RD,
&sc->sc_stats.ast_rx_toobig, 0, "rx discarded 'cuz frame too large");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_packets", CTLFLAG_RD,
&sc->sc_stats.ast_rx_packets, 0, "packet recv on the interface");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_mgt", CTLFLAG_RD,
&sc->sc_stats.ast_rx_mgt, 0, "management frames received");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_ctl", CTLFLAG_RD,
&sc->sc_stats.ast_rx_ctl, 0, "rx discarded 'cuz ctl frame");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_be_xmit", CTLFLAG_RD,
&sc->sc_stats.ast_be_xmit, 0, "beacons transmitted");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_be_nombuf", CTLFLAG_RD,
&sc->sc_stats.ast_be_nombuf, 0, "beacon setup failed 'cuz no mbuf");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_per_cal", CTLFLAG_RD,
&sc->sc_stats.ast_per_cal, 0, "periodic calibration calls");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_per_calfail", CTLFLAG_RD,
&sc->sc_stats.ast_per_calfail, 0, "periodic calibration failed");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_per_rfgain", CTLFLAG_RD,
&sc->sc_stats.ast_per_rfgain, 0, "periodic calibration rfgain reset");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rate_calls", CTLFLAG_RD,
&sc->sc_stats.ast_rate_calls, 0, "rate control checks");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rate_raise", CTLFLAG_RD,
&sc->sc_stats.ast_rate_raise, 0, "rate control raised xmit rate");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rate_drop", CTLFLAG_RD,
&sc->sc_stats.ast_rate_drop, 0, "rate control dropped xmit rate");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_ant_defswitch", CTLFLAG_RD,
&sc->sc_stats.ast_ant_defswitch, 0, "rx/default antenna switches");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_ant_txswitch", CTLFLAG_RD,
&sc->sc_stats.ast_ant_txswitch, 0, "tx antenna switches");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_cabq_xmit", CTLFLAG_RD,
&sc->sc_stats.ast_cabq_xmit, 0, "cabq frames transmitted");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_cabq_busy", CTLFLAG_RD,
&sc->sc_stats.ast_cabq_busy, 0, "cabq found busy");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_raw", CTLFLAG_RD,
&sc->sc_stats.ast_tx_raw, 0, "tx frames through raw api");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_ff_txok", CTLFLAG_RD,
&sc->sc_stats.ast_ff_txok, 0, "fast frames tx'd successfully");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_ff_txerr", CTLFLAG_RD,
&sc->sc_stats.ast_ff_txerr, 0, "fast frames tx'd w/ error");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_ff_rx", CTLFLAG_RD,
&sc->sc_stats.ast_ff_rx, 0, "fast frames rx'd");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_ff_flush", CTLFLAG_RD,
&sc->sc_stats.ast_ff_flush, 0, "fast frames flushed from staging q");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_qfull", CTLFLAG_RD,
&sc->sc_stats.ast_tx_qfull, 0, "tx dropped 'cuz of queue limit");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_nobuf", CTLFLAG_RD,
&sc->sc_stats.ast_tx_nobuf, 0, "tx dropped 'cuz no ath buffer");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tdma_update", CTLFLAG_RD,
&sc->sc_stats.ast_tdma_update, 0, "TDMA slot timing updates");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tdma_timers", CTLFLAG_RD,
&sc->sc_stats.ast_tdma_timers, 0, "TDMA slot update set beacon timers");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tdma_tsf", CTLFLAG_RD,
&sc->sc_stats.ast_tdma_tsf, 0, "TDMA slot update set TSF");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tdma_ack", CTLFLAG_RD,
&sc->sc_stats.ast_tdma_ack, 0, "TDMA tx failed 'cuz ACK required");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_raw_fail", CTLFLAG_RD,
&sc->sc_stats.ast_tx_raw_fail, 0, "raw tx failed 'cuz h/w down");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_nofrag", CTLFLAG_RD,
&sc->sc_stats.ast_tx_nofrag, 0, "tx dropped 'cuz no ath frag buffer");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_be_missed", CTLFLAG_RD,
&sc->sc_stats.ast_be_missed, 0, "number of -missed- beacons");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_ani_cal", CTLFLAG_RD,
&sc->sc_stats.ast_ani_cal, 0, "number of ANI polls");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_agg", CTLFLAG_RD,
&sc->sc_stats.ast_rx_agg, 0, "number of aggregate frames received");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_halfgi", CTLFLAG_RD,
&sc->sc_stats.ast_rx_halfgi, 0, "number of frames received with half-GI");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_2040", CTLFLAG_RD,
&sc->sc_stats.ast_rx_2040, 0, "number of HT/40 frames received");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_pre_crc_err", CTLFLAG_RD,
&sc->sc_stats.ast_rx_pre_crc_err, 0, "number of delimeter-CRC errors detected");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_post_crc_err", CTLFLAG_RD,
&sc->sc_stats.ast_rx_post_crc_err, 0, "number of post-delimiter CRC errors detected");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_decrypt_busy_err", CTLFLAG_RD,
&sc->sc_stats.ast_rx_decrypt_busy_err, 0, "number of frames received w/ busy decrypt engine");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_hi_rx_chain", CTLFLAG_RD,
&sc->sc_stats.ast_rx_hi_rx_chain, 0, "");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_htprotect", CTLFLAG_RD,
&sc->sc_stats.ast_tx_htprotect, 0, "HT tx frames with protection");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_hitqueueend", CTLFLAG_RD,
&sc->sc_stats.ast_rx_hitqueueend, 0, "RX hit queue end");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_timeout", CTLFLAG_RD,
&sc->sc_stats.ast_tx_timeout, 0, "TX Global Timeout");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_cst", CTLFLAG_RD,
&sc->sc_stats.ast_tx_cst, 0, "TX Carrier Sense Timeout");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_xtxop", CTLFLAG_RD,
&sc->sc_stats.ast_tx_xtxop, 0, "TX exceeded TXOP");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_timerexpired", CTLFLAG_RD,
&sc->sc_stats.ast_tx_timerexpired, 0, "TX exceeded TX_TIMER register");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_desccfgerr", CTLFLAG_RD,
&sc->sc_stats.ast_tx_desccfgerr, 0, "TX Descriptor Cfg Error");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_swretries", CTLFLAG_RD,
&sc->sc_stats.ast_tx_swretries, 0, "TX software retry count");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_swretrymax", CTLFLAG_RD,
&sc->sc_stats.ast_tx_swretrymax, 0, "TX software retry max reached");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_data_underrun", CTLFLAG_RD,
&sc->sc_stats.ast_tx_data_underrun, 0, "");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_delim_underrun", CTLFLAG_RD,
&sc->sc_stats.ast_tx_delim_underrun, 0, "");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_aggr_failall", CTLFLAG_RD,
&sc->sc_stats.ast_tx_aggr_failall, 0,
"Number of aggregate TX failures (whole frame)");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_aggr_ok", CTLFLAG_RD,
&sc->sc_stats.ast_tx_aggr_ok, 0,
"Number of aggregate TX OK completions (subframe)");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_aggr_fail", CTLFLAG_RD,
&sc->sc_stats.ast_tx_aggr_fail, 0,
"Number of aggregate TX failures (subframe)");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_intr", CTLFLAG_RD,
&sc->sc_stats.ast_rx_intr, 0, "RX interrupts");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_intr", CTLFLAG_RD,
&sc->sc_stats.ast_tx_intr, 0, "TX interrupts");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_mcastq_overflow",
CTLFLAG_RD, &sc->sc_stats.ast_tx_mcastq_overflow, 0,
"Number of multicast frames exceeding maximum mcast queue depth");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_keymiss", CTLFLAG_RD,
&sc->sc_stats.ast_rx_keymiss, 0, "");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_swfiltered", CTLFLAG_RD,
&sc->sc_stats.ast_tx_swfiltered, 0, "");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_stbc",
CTLFLAG_RD, &sc->sc_stats.ast_rx_stbc, 0,
"Number of STBC frames received");
/* Attach the RX phy error array */
ath_sysctl_stats_attach_rxphyerr(sc, child);
/* Attach the interrupt statistics array */
ath_sysctl_stats_attach_intr(sc, child);
}
/*
* This doesn't necessarily belong here (because it's HAL related, not
* driver related).
*/
void
ath_sysctl_hal_attach(struct ath_softc *sc)
{
struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "hal", CTLFLAG_RD,
NULL, "Atheros HAL parameters");
child = SYSCTL_CHILDREN(tree);
sc->sc_ah->ah_config.ah_debug = 0;
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "debug", CTLFLAG_RW,
&sc->sc_ah->ah_config.ah_debug, 0, "Atheros HAL debugging printfs");
sc->sc_ah->ah_config.ah_ar5416_biasadj = 0;
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "ar5416_biasadj", CTLFLAG_RW,
&sc->sc_ah->ah_config.ah_ar5416_biasadj, 0,
"Enable 2GHz AR5416 direction sensitivity bias adjust");
sc->sc_ah->ah_config.ah_dma_beacon_response_time = 2;
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "dma_brt", CTLFLAG_RW,
&sc->sc_ah->ah_config.ah_dma_beacon_response_time, 0,
"Atheros HAL DMA beacon response time");
sc->sc_ah->ah_config.ah_sw_beacon_response_time = 10;
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "sw_brt", CTLFLAG_RW,
&sc->sc_ah->ah_config.ah_sw_beacon_response_time, 0,
"Atheros HAL software beacon response time");
sc->sc_ah->ah_config.ah_additional_swba_backoff = 0;
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "swba_backoff", CTLFLAG_RW,
&sc->sc_ah->ah_config.ah_additional_swba_backoff, 0,
"Atheros HAL additional SWBA backoff time");
sc->sc_ah->ah_config.ah_force_full_reset = 0;
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "force_full_reset", CTLFLAG_RW,
&sc->sc_ah->ah_config.ah_force_full_reset, 0,
"Force full chip reset rather than a warm reset");
/*
* This is initialised by the driver.
*/
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "serialise_reg_war", CTLFLAG_RW,
&sc->sc_ah->ah_config.ah_serialise_reg_war, 0,
"Force register access serialisation");
}