Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e4cf544e authored by Arend van Spriel's avatar Arend van Spriel Committed by Greg Kroah-Hartman
Browse files

staging: brcm80211: enable driver counter functionality



The 802.11 core in the chipsets provides counters that are now
used to provide counter values to mac80211 through get_stats
callback. Counters related to ampdu and wmm (aka. wme) are not
yet incorporated.

Reviewed-by: default avatarRoland Vossen <rvossen@broadcom.com>
Reviewed-by: default avatarBrett Rudley <brudley@broadcom.com>
Reviewed-by: default avatarHenry Ptasinski <henryp@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 8746e2ba
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -3568,7 +3568,7 @@ int
wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
{
	int res = 0;
	wl_cnt_t cnt;
	struct wl_cnt cnt;
	int phy_noise;
	int rssi;
	scb_val_t scb_val;
@@ -3611,11 +3611,13 @@ wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
#endif

#if WIRELESS_EXT > 11
	WL_TRACE("wl_iw_get_wireless_stats counters=%zu\n", sizeof(wl_cnt_t));
	WL_TRACE("wl_iw_get_wireless_stats counters=%zu\n",
		 sizeof(struct wl_cnt));

	memset(&cnt, 0, sizeof(wl_cnt_t));
	memset(&cnt, 0, sizeof(struct wl_cnt));
	res =
	    dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t));
	    dev_wlc_bufvar_get(dev, "counters", (char *)&cnt,
			       sizeof(struct wl_cnt));
	if (res) {
		WL_ERROR("wl_iw_get_wireless_stats counters failed error=%d\n",
			 res);
@@ -3624,7 +3626,7 @@ wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)

	cnt.version = dtoh16(cnt.version);
	if (cnt.version != WL_CNT_T_VERSION) {
		WL_TRACE("\tIncorrect version of counters struct: expected %d; got %d\n",
		WL_TRACE("\tIncorrect counter version: expected %d; got %d\n",
			 WL_CNT_T_VERSION, cnt.version);
		goto done;
	}
+22 −13
Original line number Diff line number Diff line
@@ -461,7 +461,16 @@ static int
wl_ops_get_stats(struct ieee80211_hw *hw,
		 struct ieee80211_low_level_stats *stats)
{
	WL_ERROR("%s: Enter\n", __func__);
	struct wl_info *wl = hw->priv;
	struct wl_cnt *cnt;

	WL_LOCK(wl);
	cnt = wl->pub->_cnt;
	stats->dot11ACKFailureCount = cnt->txnoack;
	stats->dot11RTSFailureCount = cnt->txnocts;
	stats->dot11FCSErrorCount = cnt->rxcrc;
	stats->dot11RTSSuccessCount = cnt->txrts;
	WL_UNLOCK(wl);
	return 0;
}

@@ -1648,34 +1657,34 @@ void wl_free_timer(struct wl_info *wl, wl_timer_t *t)
static int wl_linux_watchdog(void *ctx)
{
	struct wl_info *wl = (struct wl_info *) ctx;
	struct wl_cnt *cnt;
	struct net_device_stats *stats = NULL;
	uint id;
	/* refresh stats */
	if (wl->pub->up) {
		ASSERT(wl->stats_id < 2);

		cnt = wl->pub->_cnt;
		id = 1 - wl->stats_id;

		stats = &wl->stats_watchdog[id];
		stats->rx_packets = WLCNTVAL(wl->pub->_cnt->rxframe);
		stats->tx_packets = WLCNTVAL(wl->pub->_cnt->txframe);
		stats->rx_bytes = WLCNTVAL(wl->pub->_cnt->rxbyte);
		stats->tx_bytes = WLCNTVAL(wl->pub->_cnt->txbyte);
		stats->rx_errors = WLCNTVAL(wl->pub->_cnt->rxerror);
		stats->tx_errors = WLCNTVAL(wl->pub->_cnt->txerror);
		stats->rx_packets = cnt->rxframe;
		stats->tx_packets = cnt->txframe;
		stats->rx_bytes = cnt->rxbyte;
		stats->tx_bytes = cnt->txbyte;
		stats->rx_errors = cnt->rxerror;
		stats->tx_errors = cnt->txerror;
		stats->collisions = 0;

		stats->rx_length_errors = 0;
		stats->rx_over_errors = WLCNTVAL(wl->pub->_cnt->rxoflo);
		stats->rx_crc_errors = WLCNTVAL(wl->pub->_cnt->rxcrc);
		stats->rx_over_errors = cnt->rxoflo;
		stats->rx_crc_errors = cnt->rxcrc;
		stats->rx_frame_errors = 0;
		stats->rx_fifo_errors = WLCNTVAL(wl->pub->_cnt->rxoflo);
		stats->rx_fifo_errors = cnt->rxoflo;
		stats->rx_missed_errors = 0;

		stats->tx_fifo_errors = WLCNTVAL(wl->pub->_cnt->txuflo);
		stats->tx_fifo_errors = cnt->txuflo;

		wl->stats_id = id;

	}

	return 0;
+9 −9
Original line number Diff line number Diff line
@@ -70,13 +70,13 @@ static struct wlc_pub *wlc_pub_malloc(struct osl_info *osh, uint unit,
{
	struct wlc_pub *pub;

	pub = (struct wlc_pub *) wlc_calloc(osh, unit, sizeof(struct wlc_pub));
	pub = wlc_calloc(osh, unit, sizeof(struct wlc_pub));
	if (pub == NULL) {
		*err = 1001;
		goto fail;
	}

	pub->tunables = (wlc_tunables_t *)wlc_calloc(osh, unit,
	pub->tunables = wlc_calloc(osh, unit,
		sizeof(wlc_tunables_t));
	if (pub->tunables == NULL) {
		*err = 1028;
@@ -86,6 +86,10 @@ static struct wlc_pub *wlc_pub_malloc(struct osl_info *osh, uint unit,
	/* need to init the tunables now */
	wlc_tunables_init(pub->tunables, devid);

	pub->_cnt = wlc_calloc(osh, unit, sizeof(struct wl_cnt));
	if (pub->_cnt == NULL)
		goto fail;

	pub->multicast = (u8 *)wlc_calloc(osh, unit,
		(ETH_ALEN * MAXMULTILIST));
	if (pub->multicast == NULL) {
@@ -105,13 +109,9 @@ static void wlc_pub_mfree(struct osl_info *osh, struct wlc_pub *pub)
	if (pub == NULL)
		return;

	if (pub->multicast)
	kfree(pub->multicast);
	if (pub->tunables) {
	kfree(pub->_cnt);
	kfree(pub->tunables);
		pub->tunables = NULL;
	}

	kfree(pub);
}

+8 −3
Original line number Diff line number Diff line
@@ -38,6 +38,11 @@
#include <wl_export.h>
#include <wl_dbg.h>

/*
 *	Disable AMPDU statistics counters for now
 */
#define WLCNTINCR(a)
#define WLCNTADD(a, b)

#define AMPDU_MAX_MPDU		32	/* max number of mpdus in an ampdu */
#define AMPDU_NUM_MPDU_LEGACY	16	/* max number of mpdus in an ampdu to a legacy */
@@ -1043,10 +1048,10 @@ wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
			if (supr_status == TX_STATUS_SUPR_BADCH ||
			    supr_status == TX_STATUS_SUPR_EXPTIME) {
				retry = false;
				WLCNTINCR(wlc->pub->_cnt->txchanrej);
				wlc->pub->_cnt->txchanrej++;
			} else if (supr_status == TX_STATUS_SUPR_EXPTIME) {

				WLCNTINCR(wlc->pub->_cnt->txexptime);
				wlc->pub->_cnt->txexptime++;

				/* TX underflow : try tuning pre-loading or ampdu size */
			} else if (supr_status == TX_STATUS_SUPR_FRAG) {
@@ -1060,7 +1065,7 @@ wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
			}
		} else if (txs->phyerr) {
			update_rate = false;
			WLCNTINCR(wlc->pub->_cnt->txphyerr);
			wlc->pub->_cnt->txphyerr++;
			WL_ERROR("wl%d: wlc_ampdu_dotxstatus: tx phy error (0x%x)\n",
				 wlc->pub->unit, txs->phyerr);

+10 −10
Original line number Diff line number Diff line
@@ -383,7 +383,7 @@ bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded)

	/* phy tx error */
	if (macintstatus & MI_PHYTXERR) {
		WLCNTINCR(wlc->pub->_cnt->txphyerr);
		wlc->pub->_cnt->txphyerr++;
	}

	/* received data or control frame, MI_DMAINT is indication of RX_FIFO interrupt */
@@ -413,7 +413,7 @@ bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded)
					__func__, wlc_hw->sih->chip,
					wlc_hw->sih->chiprev);

		WLCNTINCR(wlc->pub->_cnt->psmwds);
		wlc->pub->_cnt->psmwds++;

		/* big hammer */
		wl_init(wlc->wl);
@@ -427,7 +427,7 @@ bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded)
	if (macintstatus & MI_RFDISABLE) {
		WL_TRACE("wl%d: BMAC Detected a change on the RF Disable Input\n", wlc_hw->unit);

		WLCNTINCR(wlc->pub->_cnt->rfdisable);
		wlc->pub->_cnt->rfdisable++;
		wl_rfkill_set_hw_state(wlc->wl);
	}

@@ -1088,7 +1088,7 @@ void wlc_bmac_reset(struct wlc_hw_info *wlc_hw)
{
	WL_TRACE("wl%d: wlc_bmac_reset\n", wlc_hw->unit);

	WLCNTINCR(wlc_hw->wlc->pub->_cnt->reset);
	wlc_hw->wlc->pub->_cnt->reset++;

	/* reset the core */
	if (!DEVICEREMOVED(wlc_hw->wlc))
@@ -2877,40 +2877,40 @@ void wlc_bmac_fifoerrors(struct wlc_hw_info *wlc_hw)
		if (intstatus & I_RO) {
			WL_ERROR("wl%d: fifo %d: receive fifo overflow\n",
				 unit, idx);
			WLCNTINCR(wlc_hw->wlc->pub->_cnt->rxoflo);
			wlc_hw->wlc->pub->_cnt->rxoflo++;
			fatal = true;
		}

		if (intstatus & I_PC) {
			WL_ERROR("wl%d: fifo %d: descriptor error\n",
				 unit, idx);
			WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmade);
			wlc_hw->wlc->pub->_cnt->dmade++;
			fatal = true;
		}

		if (intstatus & I_PD) {
			WL_ERROR("wl%d: fifo %d: data error\n", unit, idx);
			WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmada);
			wlc_hw->wlc->pub->_cnt->dmada++;
			fatal = true;
		}

		if (intstatus & I_DE) {
			WL_ERROR("wl%d: fifo %d: descriptor protocol error\n",
				 unit, idx);
			WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmape);
			wlc_hw->wlc->pub->_cnt->dmape++;
			fatal = true;
		}

		if (intstatus & I_RU) {
			WL_ERROR("wl%d: fifo %d: receive descriptor underflow\n",
				 idx, unit);
			WLCNTINCR(wlc_hw->wlc->pub->_cnt->rxuflo[idx]);
			wlc_hw->wlc->pub->_cnt->rxuflo[idx]++;
		}

		if (intstatus & I_XU) {
			WL_ERROR("wl%d: fifo %d: transmit fifo underflow\n",
				 idx, unit);
			WLCNTINCR(wlc_hw->wlc->pub->_cnt->txuflo);
			wlc_hw->wlc->pub->_cnt->txuflo++;
			fatal = true;
		}

Loading