Search Linux Wireless

[PATCH] b43: Fix some MAC locking

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

 



This fixes some locking w.r.t. the lower MAC (firmware).
It also removes a lot of ancient IRQ-locking that's not needed anymore.
We simply suspend the MAC. That's easier and causes less trouble.

Signed-off-by: Michael Buesch <mb@xxxxxxxxx>

-- 

Stuff for the next feature release.


Index: wireless-testing/drivers/net/wireless/b43/main.c
===================================================================
--- wireless-testing.orig/drivers/net/wireless/b43/main.c	2008-11-05 23:02:57.000000000 +0100
+++ wireless-testing/drivers/net/wireless/b43/main.c	2008-12-18 21:43:50.000000000 +0100
@@ -3321,41 +3321,30 @@ static int b43_op_config(struct ieee8021
 	struct b43_wldev *dev;
 	struct b43_phy *phy;
 	struct ieee80211_conf *conf = &hw->conf;
 	unsigned long flags;
 	int antenna;
 	int err = 0;
-	u32 savedirqs;
 
 	mutex_lock(&wl->mutex);
 
 	/* Switch the band (if necessary). This might change the active core. */
 	err = b43_switch_band(wl, conf->channel);
 	if (err)
 		goto out_unlock_mutex;
 	dev = wl->current_dev;
 	phy = &dev->phy;
 
+	b43_mac_suspend(dev);
+
 	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
 		b43_set_retry_limits(dev, conf->short_frame_max_tx_count,
 					  conf->long_frame_max_tx_count);
 	changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
 	if (!changed)
-		goto out_unlock_mutex;
-
-	/* Disable IRQs while reconfiguring the device.
-	 * This makes it possible to drop the spinlock throughout
-	 * the reconfiguration process. */
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	if (b43_status(dev) < B43_STAT_STARTED) {
-		spin_unlock_irqrestore(&wl->irq_lock, flags);
-		goto out_unlock_mutex;
-	}
-	savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL);
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
-	b43_synchronize_irq(dev);
+		goto out_mac_enable;
 
 	/* Switch to the requested channel.
 	 * The firmware takes care of races with the TX handler. */
 	if (conf->channel->hw_value != phy->channel)
 		b43_switch_channel(dev, conf->channel->hw_value);
 
@@ -3396,17 +3385,15 @@ static int b43_op_config(struct ieee8021
 		} else {
 			b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
 			b43info(dev->wl, "Radio turned off by software\n");
 		}
 	}
 
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	b43_interrupt_enable(dev, savedirqs);
-	mmiowb();
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
-      out_unlock_mutex:
+out_mac_enable:
+	b43_mac_enable(dev);
+out_unlock_mutex:
 	mutex_unlock(&wl->mutex);
 
 	return err;
 }
 
 static void b43_update_basic_rates(struct b43_wldev *dev, u64 brates)
@@ -3458,33 +3445,18 @@ static void b43_op_bss_info_changed(stru
 				    struct ieee80211_vif *vif,
 				    struct ieee80211_bss_conf *conf,
 				    u32 changed)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev;
-	struct b43_phy *phy;
-	unsigned long flags;
-	u32 savedirqs;
 
 	mutex_lock(&wl->mutex);
 
 	dev = wl->current_dev;
-	phy = &dev->phy;
-
-	/* Disable IRQs while reconfiguring the device.
-	 * This makes it possible to drop the spinlock throughout
-	 * the reconfiguration process. */
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	if (b43_status(dev) < B43_STAT_STARTED) {
-		spin_unlock_irqrestore(&wl->irq_lock, flags);
+	if (!dev || b43_status(dev) < B43_STAT_STARTED)
 		goto out_unlock_mutex;
-	}
-	savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL);
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
-	b43_synchronize_irq(dev);
-
 	b43_mac_suspend(dev);
 
 	if (changed & BSS_CHANGED_BASIC_RATES)
 		b43_update_basic_rates(dev, conf->basic_rates);
 
 	if (changed & BSS_CHANGED_ERP_SLOT) {
@@ -3492,19 +3464,13 @@ static void b43_op_bss_info_changed(stru
 			b43_short_slot_timing_enable(dev);
 		else
 			b43_short_slot_timing_disable(dev);
 	}
 
 	b43_mac_enable(dev);
-
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	b43_interrupt_enable(dev, savedirqs);
-	/* XXX: why? */
-	mmiowb();
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
- out_unlock_mutex:
+out_unlock_mutex:
 	mutex_unlock(&wl->mutex);
 
 	return;
 }
 
 static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
Index: wireless-testing/drivers/net/wireless/b43/phy_g.c
===================================================================
--- wireless-testing.orig/drivers/net/wireless/b43/phy_g.c	2008-09-26 22:51:28.000000000 +0200
+++ wireless-testing/drivers/net/wireless/b43/phy_g.c	2008-12-18 21:49:12.000000000 +0100
@@ -3044,12 +3044,14 @@ static void b43_gphy_op_adjust_txpower(s
 {
 	struct b43_phy *phy = &dev->phy;
 	struct b43_phy_g *gphy = phy->g;
 	int rfatt, bbatt;
 	u8 tx_control;
 
+	b43_mac_suspend(dev);
+
 	spin_lock_irq(&dev->wl->irq_lock);
 
 	/* Calculate the new attenuation values. */
 	bbatt = gphy->bbatt.att;
 	bbatt += gphy->bbatt_delta;
 	rfatt = gphy->rfatt.att;
@@ -3100,12 +3102,14 @@ static void b43_gphy_op_adjust_txpower(s
 	b43_phy_lock(dev);
 	b43_radio_lock(dev);
 	b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt,
 			  gphy->tx_control);
 	b43_radio_unlock(dev);
 	b43_phy_unlock(dev);
+
+	b43_mac_enable(dev);
 }
 
 static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev,
 							bool ignore_tssi)
 {
 	struct b43_phy *phy = &dev->phy;
@@ -3212,30 +3216,30 @@ no_adjustment_needed:
 
 static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
 	struct b43_phy_g *gphy = phy->g;
 
+	b43_mac_suspend(dev);
 	//TODO: update_aci_moving_average
 	if (gphy->aci_enable && gphy->aci_wlan_automatic) {
-		b43_mac_suspend(dev);
 		if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) {
 			if (0 /*TODO: bunch of conditions */ ) {
 				phy->ops->interf_mitigation(dev,
 					B43_INTERFMODE_MANUALWLAN);
 			}
 		} else if (0 /*TODO*/) {
 			   if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev))
 				phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
 		}
-		b43_mac_enable(dev);
 	} else if (gphy->interfmode == B43_INTERFMODE_NONWLAN &&
 		   phy->rev == 1) {
 		//TODO: implement rev1 workaround
 	}
 	b43_lo_g_maintanance_work(dev);
+	b43_mac_enable(dev);
 }
 
 static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
 
Index: wireless-testing/drivers/net/wireless/b43/phy_common.c
===================================================================
--- wireless-testing.orig/drivers/net/wireless/b43/phy_common.c	2008-10-11 16:13:24.000000000 +0200
+++ wireless-testing/drivers/net/wireless/b43/phy_common.c	2008-12-18 21:52:28.000000000 +0100
@@ -175,19 +175,33 @@ void b43_phy_unlock(struct b43_wldev *de
 	B43_WARN_ON(dev->dev->id.revision < 3);
 
 	if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
 		b43_power_saving_ctl_bits(dev, 0);
 }
 
+static inline void assert_mac_suspended(struct b43_wldev *dev)
+{
+	if (!B43_DEBUG)
+		return;
+	if ((b43_status(dev) >= B43_STAT_INITIALIZED) &&
+	    (dev->mac_suspended <= 0)) {
+		b43dbg(dev->wl, "PHY/RADIO register access with "
+		       "enabled MAC.\n");
+		dump_stack();
+	}
+}
+
 u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
 {
+	assert_mac_suspended(dev);
 	return dev->phy.ops->radio_read(dev, reg);
 }
 
 void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
 {
+	assert_mac_suspended(dev);
 	dev->phy.ops->radio_write(dev, reg, value);
 }
 
 void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask)
 {
 	b43_radio_write16(dev, offset,
@@ -205,17 +219,19 @@ void b43_radio_maskset(struct b43_wldev 
 	b43_radio_write16(dev, offset,
 			  (b43_radio_read16(dev, offset) & mask) | set);
 }
 
 u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
 {
+	assert_mac_suspended(dev);
 	return dev->phy.ops->phy_read(dev, reg);
 }
 
 void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
 {
+	assert_mac_suspended(dev);
 	dev->phy.ops->phy_write(dev, reg, value);
 }
 
 void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
 {
 	b43_phy_write(dev, offset,

-- 
Greetings, Michael.
--
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