Search Linux Wireless

[RFT] [PATCH] bcm43xx: ACI fixes

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

 



Please test the following patch. It syncs ACI (Adjacent Channels
Interference) code to specs. I can't test it right now. Will port to
mac80211 branch ASAP.


Signed-off-by: Stefano Brivio <stefano.brivio@xxxxxxxxx>
----

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 95ff175..7023327 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -398,6 +398,9 @@
 #define BCM43xx_DEFAULT_SHORT_RETRY_LIMIT	7
 #define BCM43xx_DEFAULT_LONG_RETRY_LIMIT	4
 
+/* Statscounter offsets. */
+#define BCM43xx_SC_ACI		0x2E
+
 /* FIXME: the next line is a guess as to what the maximum RSSI value might be */
 #define RX_RSSI_MAX				60
 
@@ -550,7 +553,11 @@ struct bcm43xx_phyinfo {
 	u8 connected:1,
 	   calibrated:1,
 	   is_locked:1, /* used in bcm43xx_phy_{un}lock() */
-	   dyn_tssi_tbl:1; /* used in bcm43xx_phy_init_tssi2dbm_table() */
+	   dyn_tssi_tbl:1, /* used in bcm43xx_phy_init_tssi2dbm_table() */
+	   g_interfmode:1; /* bit 4000 in PHY_G_CRS, used in periodic tasks */
+	u8 g_interfmode_timer; /* how much time ago g_interfmode was unset */
+	u16 g_sc_saved; /* used in periodic tasks for ACI */
+
 	/* LO Measurement Data.
 	 * Use bcm43xx_get_lopair() to get a value.
 	 */
@@ -629,7 +636,9 @@ struct bcm43xx_radioinfo {
 	/* ACI (adjacent channel interference) flags. */
 	u8 aci_enable:1,
 	   aci_wlan_automatic:1,
-	   aci_hw_rssi:1;
+	   aci_hw_rssi:1,
+	   aci_delay:5;
+	u8 aci_start;
 };
 
 /* Data structures for DMA transmission, per 80211 core. */
@@ -699,6 +708,18 @@ struct bcm43xx_noise_calculation {
 	s8 samples[8][4];
 };
 
+/* Statscounter data (currently ACI only). */
+struct bcm43xx_statscounter_saved {
+	u16 aci;
+};
+
+/* Values for ACI moving average calculation. */
+struct bcm43xx_aci_saved {
+	u16 value[8];
+	u8 next:3,
+	   set:3;
+};
+
 struct bcm43xx_stats {
 	u8 noise;
 	struct iw_statistics wstats;
@@ -812,6 +833,10 @@ struct bcm43xx_private {
 	u32 irq_savedstate;
 	/* Link Quality calculation context. */
 	struct bcm43xx_noise_calculation noisecalc;
+	/* Statscounter tracking. */
+	struct bcm43xx_statscounter_saved sc;
+	/* ACI tracking. */
+	struct bcm43xx_aci_saved aci;
 	/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
 	int mac_suspended;
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index e594af4..27ec519 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -3059,6 +3059,44 @@ static void bcm43xx_pcie_mdio_write(stru
 	bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_CTL, 0);
 }
 
+/* We don't use any statscounter other than ACI for now */
+static u16 bcm43xx_sc_read(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_statscounter_saved *sc = &bcm->sc;
+	u16 tmp;
+
+	tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x80 + BCM43xx_SC_ACI)
+		- sc->aci;
+	if (tmp)
+		sc->aci += tmp;
+
+	return tmp;
+}
+
+static u16 bcm43xx_aci_moving_average(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_aci_saved *aci = &bcm->aci;
+
+	u8 i;
+	u16 avg;
+	u32 sum = 0;
+
+	aci->value[aci->next] = bcm43xx_sc_read(bcm);
+	if (unlikely(aci->set < 7))
+		aci->set++;
+	for (i = 0; i < aci->set; i++)
+		sum += aci->value[i];
+	avg = sum / (u16)8;
+	if ((sum % 8) > 3)
+		avg++;
+	if (aci->next < 7)
+		aci->next++;
+	else
+		aci->next = 0;
+
+	return avg;
+}
+
 /* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable.
  * To enable core 0, pass a core_mask of 1<<0
  */
@@ -3182,6 +3220,8 @@ static void bcm43xx_periodic_every1sec(s
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
 	int radio_hw_enable;
+	unsigned long phylock_flags;
+	u16 tmp;
 
 	/* check if radio hardware enabled status changed */
 	radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
@@ -3191,27 +3231,56 @@ static void bcm43xx_periodic_every1sec(s
 		       (radio_hw_enable == 0) ? "disabled" : "enabled");
 		bcm43xx_leds_update(bcm, 0);
 	}
+
 	if (phy->type == BCM43xx_PHYTYPE_G) {
-		//TODO: update_aci_moving_average
-		if (radio->aci_enable && radio->aci_wlan_automatic) {
+		
+		if (radio->aci_start < 60)
+			radio->aci_start++;
+		if (radio->aci_delay)
+			radio->aci_delay--;
+		if (phy->g_interfmode && phy->g_interfmode_timer < 30)
+			phy->g_interfmode_timer++;
+
+		if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN &&
+				!radio->aci_delay) {
 			bcm43xx_mac_suspend(bcm);
-			if (!radio->aci_enable && 1 /*TODO: not scanning? */) {
-				if (0 /*TODO: bunch of conditions*/) {
-					bcm43xx_radio_set_interference_mitigation(bcm,
-										  BCM43xx_RADIO_INTERFMODE_MANUALWLAN);
-				}
-			} else if (1/*TODO*/) {
-				/*
-				if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) {
-					bcm43xx_radio_set_interference_mitigation(bcm,
-										  BCM43xx_RADIO_INTERFMODE_NONE);
+			if (!radio->aci_enable)
+			{
+				if (bcm43xx_aci_moving_average(bcm) < 200) {
+					if (bcm43xx_radio_aci_scan(bcm)) {
+						bcm43xx_radio_set_interference_mitigation(bcm,
+							BCM43xx_RADIO_INTERFMODE_MANUALWLAN);
+						radio->aci_start = 0;
+					} else
+						radio->aci_delay = 20;
 				}
-				*/
+			} else if (radio->aci_start == 60) {
+				if (bcm43xx_aci_moving_average(bcm) > 1000)
+					if (!bcm43xx_radio_aci_scan(bcm))
+						bcm43xx_radio_set_interference_mitigation(bcm,
+							BCM43xx_RADIO_INTERFMODE_NONE);
 			}
 			bcm43xx_mac_enable(bcm);
 		} else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN &&
-			   phy->rev == 1) {
-			//TODO: implement rev1 workaround
+				phy->rev == 1) {
+			tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x00AE);
+			if (phy->g_interfmode) {
+				if (tmp && ((tmp - phy->g_sc_saved) > 1500)) {
+					bcm43xx_phy_lock(bcm, phylock_flags);
+					bcm43xx_phy_write(bcm, 0x00AE,
+						bcm43xx_phy_read(bcm, 0x00AE) & ~0x4000);
+					bcm43xx_phy_unlock(bcm, phylock_flags);
+					phy->g_interfmode = 1;
+					phy->g_interfmode_timer = 0;
+				}
+			} else if (phy->g_interfmode_timer == 30) {
+						bcm43xx_phy_lock(bcm, phylock_flags);
+						bcm43xx_phy_write(bcm, 0x00AE,
+							bcm43xx_phy_read(bcm, 0x00AE & 0x4000));
+						bcm43xx_phy_unlock(bcm, phylock_flags);
+						phy->g_interfmode = 0;
+			}
+			phy->g_sc_saved = tmp;
 		}
 	}
 }
@@ -3297,10 +3366,16 @@ void bcm43xx_periodic_tasks_delete(struc
 void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
 {
 	struct delayed_work *work = &bcm->periodic_work;
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 
 	assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
 	INIT_DELAYED_WORK(work, bcm43xx_periodic_work_handler);
 	schedule_delayed_work(work, 0);
+	
+	if (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x4000)
+		phy->g_interfmode = 1;
+	else
+		phy->g_interfmode = 0;
 }
 
 static void bcm43xx_security_init(struct bcm43xx_private *bcm)
@@ -3429,6 +3504,8 @@ static void prepare_radiodata_for_init(s
 	radio->aci_enable = 0;
 	radio->aci_wlan_automatic = 0;
 	radio->aci_hw_rssi = 0;
+	radio->aci_start = 0;
+	radio->aci_delay = 0;
 }
 
 static void prepare_priv_for_init(struct bcm43xx_private *bcm)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
-
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[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