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

Commit d10d0e57 authored by Michael Buesch's avatar Michael Buesch Committed by John W. Linville
Browse files

b43: Fix some MAC locking



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: default avatarMichael Buesch <mb@bu3sch.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 0e7690f1
Loading
Loading
Loading
Loading
+8 −42
Original line number Diff line number Diff line
@@ -3324,7 +3324,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
	unsigned long flags;
	int antenna;
	int err = 0;
	u32 savedirqs;

	mutex_lock(&wl->mutex);

@@ -3335,24 +3334,14 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
	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. */
@@ -3399,10 +3388,8 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
		}
	}

	spin_lock_irqsave(&wl->irq_lock, flags);
	b43_interrupt_enable(dev, savedirqs);
	mmiowb();
	spin_unlock_irqrestore(&wl->irq_lock, flags);
out_mac_enable:
	b43_mac_enable(dev);
out_unlock_mutex:
	mutex_unlock(&wl->mutex);

@@ -3461,27 +3448,12 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
{
	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)
@@ -3495,12 +3467,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
	}

	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:
	mutex_unlock(&wl->mutex);

+16 −0
Original line number Diff line number Diff line
@@ -178,13 +178,27 @@ void b43_phy_unlock(struct b43_wldev *dev)
		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);
}

@@ -208,11 +222,13 @@ void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 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);
}

+6 −2
Original line number Diff line number Diff line
@@ -3047,6 +3047,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
	int rfatt, bbatt;
	u8 tx_control;

	b43_mac_suspend(dev);

	spin_lock_irq(&dev->wl->irq_lock);

	/* Calculate the new attenuation values. */
@@ -3103,6 +3105,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
			  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,
@@ -3215,9 +3219,9 @@ 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,
@@ -3227,12 +3231,12 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev)
			   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)