From b24884eeffd49ba4a0253e1c673a74a5c4b1a0a9 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@openwrt.org>
Date: Fri, 11 Dec 2009 02:12:15 +0000
Subject: [PATCH] madwifi: fix noise level display and make the cca threshold
 configurable through sysctl

SVN-Revision: 18739
---
 package/madwifi/patches/454-cca.patch | 186 ++++++++++++++++++++++++++
 1 file changed, 186 insertions(+)
 create mode 100644 package/madwifi/patches/454-cca.patch

diff --git a/package/madwifi/patches/454-cca.patch b/package/madwifi/patches/454-cca.patch
new file mode 100644
index 00000000000..53792cc8fa0
--- /dev/null
+++ b/package/madwifi/patches/454-cca.patch
@@ -0,0 +1,186 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -383,6 +383,8 @@ static void ath_poll_disable(struct net_
+ static void ath_poll_enable(struct net_device *dev);
+ static void ath_fetch_idle_time(struct ath_softc *sc);
+ static void ath_set_timing(struct ath_softc *sc);
++static void ath_update_cca_thresh(struct ath_softc *sc);
++static int ath_hw_read_nf(struct ath_softc *sc);
+ 
+ /* calibrate every 30 secs in steady state but check every second at first. */
+ static int ath_calinterval = ATH_SHORT_CALINTERVAL;
+@@ -2623,6 +2625,10 @@ ath_init(struct net_device *dev)
+ 		goto done;
+ 	}
+ 
++	ath_hal_process_noisefloor(ah);
++	ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
++	ath_update_cca_thresh(sc);
++
+ 	if (sc->sc_softled)
+ 		ath_hal_gpioCfgOutput(ah, sc->sc_ledpin);
+ 
+@@ -3024,6 +3030,10 @@ ath_reset(struct net_device *dev)
+ 		EPRINTF(sc, "Unable to reset hardware: '%s' (HAL status %u)\n",
+ 			ath_get_hal_status_desc(status), status);
+ 
++	ath_hal_process_noisefloor(ah);
++	ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
++	ath_update_cca_thresh(sc);
++
+ 	ath_setintmit(sc);
+ 	ath_update_txpow(sc);		/* update tx power state */
+ 	ath_radar_update(sc);
+@@ -9374,9 +9384,11 @@ ath_calibrate(unsigned long arg)
+ 			sc->sc_curchan.channel);
+ 		sc->sc_stats.ast_per_calfail++;
+ 	}
+-	ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
+ 
+ 	ath_hal_process_noisefloor(ah);
++	ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
++	ath_update_cca_thresh(sc);
++
+ 	if (isIQdone == AH_TRUE) {
+ 		/* Unless user has overridden calibration interval,
+ 		 * upgrade to less frequent calibration */
+@@ -9711,8 +9723,6 @@ ath_newstate(struct ieee80211vap *vap, e
+ 			break;
+ 		}
+ 
+-		ath_hal_process_noisefloor(ah);
+-		ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
+ 		/*
+ 		 * Reset rssi stats; maybe not the best place...
+ 		 */
+@@ -10968,6 +10978,7 @@ enum {
+ 	ATH_INTMIT,
+ 	ATH_NOISE_IMMUNITY,
+ 	ATH_OFDM_WEAK_DET,
++	ATH_CCA_THRESH,
+ 	ATH_CHANBW,
+ 	ATH_OUTDOOR,
+ 	ATH_DISTANCE,
+@@ -11110,6 +11121,66 @@ ath_sysctl_get_intmit(struct ath_softc *
+ 	return 0;
+ }
+ 
++#define AR_PHY_CCA              0x9864
++#define AR_PHY_MINCCA_PWR       0x0FF80000
++#define AR_PHY_MINCCA_PWR_S     19
++#define AR_PHY_CCA_THRESH62     0x0007F000
++#define AR_PHY_CCA_THRESH62_S   12
++
++static int
++ath_nf_from_cca(u32 phy_cca)
++{
++	int nf = (phy_cca >> 19) & 0x1ff;
++	nf = -((nf ^ 0x1ff) + 1);
++	return nf;
++}
++
++static int
++ath_hw_read_nf(struct ath_softc *sc)
++{
++	return ath_nf_from_cca(OS_REG_READ(sc->sc_ah, AR_PHY_CCA));
++}
++
++static void
++ath_update_cca_thresh(struct ath_softc *sc)
++{
++	struct ath_hal *ah = sc->sc_ah;
++	int newthr = 0;
++	u32 phy_cca;
++	int nf;
++
++	phy_cca = OS_REG_READ(ah, AR_PHY_CCA);
++	if (sc->sc_cca_thresh < 0) {
++		newthr = sc->sc_cca_thresh - ath_nf_from_cca(phy_cca);
++
++		/* 0xf is a typical eeprom value for thresh62,
++		 * use it as minimum for signal based thresholds
++		 * to prevent complete connection drops */
++		if (newthr < 0xf)
++			newthr = 0xf;
++	} else {
++		newthr = sc->sc_cca_thresh;
++	}
++
++	if ((newthr < 4) || (newthr >= 127))
++		return;
++
++	phy_cca &= ~AR_PHY_CCA_THRESH62;
++	phy_cca |= newthr << AR_PHY_CCA_THRESH62_S;
++	OS_REG_WRITE(ah, AR_PHY_CCA, phy_cca);
++}
++
++static int
++ath_get_cca_thresh(struct ath_softc *sc)
++{
++	struct ath_hal *ah = sc->sc_ah;
++	u32 phy_cca;
++
++	phy_cca = OS_REG_READ(ah, AR_PHY_CCA);
++	return ath_nf_from_cca(phy_cca) +
++		((phy_cca & AR_PHY_CCA_THRESH62) >> AR_PHY_CCA_THRESH62_S);
++}
++
+ static int
+ ATH_SYSCTL_DECL(ath_sysctl_hwinfo, ctl, write, filp, buffer, lenp, ppos)
+ {
+@@ -11356,6 +11427,10 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+ 			case ATH_OFDM_WEAK_DET:
+ 				ret = ath_sysctl_set_intmit(sc, (long)ctl->extra2, val);
+ 				break;
++			case ATH_CCA_THRESH:
++				sc->sc_cca_thresh = val;
++				ath_update_cca_thresh(sc);
++				break;
+ 			default:
+ 				ret = -EINVAL;
+ 				break;
+@@ -11436,6 +11511,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+ 		case ATH_OFDM_WEAK_DET:
+ 			ret = ath_sysctl_get_intmit(sc, (long)ctl->extra2, &val);
+ 			break;
++		case ATH_CCA_THRESH:
++			val = ath_get_cca_thresh(sc);
++			break;
+ 		default:
+ 			ret = -EINVAL;
+ 			break;
+@@ -11667,6 +11745,12 @@ static const ctl_table ath_sysctl_templa
+ 	  .proc_handler = ath_sysctl_halparam,
+ 	  .extra2	= (void *)ATH_OFDM_WEAK_DET,
+ 	},
++	{ .ctl_name	= CTL_AUTO,
++	  .procname     = "cca_thresh",
++	  .mode         = 0644,
++	  .proc_handler = ath_sysctl_halparam,
++	  .extra2	= (void *)ATH_CCA_THRESH,
++	},
+ 	{ 0 }
+ };
+ 
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -844,6 +844,7 @@ struct ath_softc {
+ 	int sc_cal_interval;			/* current calibration interval */
+ 	struct timer_list sc_cal_ch;		/* calibration timer */
+ 	HAL_NODE_STATS sc_halstats;		/* station-mode rssi stats */
++	int sc_cca_thresh;				/* configured CCA threshold */
+ 
+ 	struct ctl_table_header *sc_sysctl_header;
+ 	struct ctl_table *sc_sysctls;
+--- a/ath/ath_wprobe.c
++++ b/ath/ath_wprobe.c
+@@ -133,8 +133,7 @@ ath_wprobe_sync(struct wprobe_iface *dev
+ 	rx = READ_CLR(ah, AR5K_RXFC);
+ 	tx = READ_CLR(ah, AR5K_TXFC);
+ 	OS_REG_WRITE(ah, AR5K_MIBC, 0);
+-	noise = ath_hal_get_channel_noise(sc->sc_ah, &(sc->sc_curchan));
+-	ic->ic_channoise = noise;
++	noise = ath_hw_read_nf(sc);
+ 
+ 	WPROBE_FILL_BEGIN(val, ath_wprobe_globals);
+ 	if (cc & 0xf0000000) {