b43: implement short slot and basic rate handling
authorJohannes Berg <johannes@sipsolutions.net>
Wed, 29 Oct 2008 19:02:12 +0000 (20:02 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 10 Nov 2008 20:17:35 +0000 (15:17 -0500)
This implements proper short slot handling and adds code to
program the hardware for the correct response rates derived
from the basic rate set for the current BSS.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/main.c

index 427b8203e3f96af2d8367d5ef1e8b2fa0386ab4a..a53c378e74844ebdca86dd83fb3b5c9104511b27 100644 (file)
@@ -718,7 +718,6 @@ struct b43_wldev {
 
        bool bad_frames_preempt;        /* Use "Bad Frames Preemption" (default off) */
        bool dfq_valid;         /* Directed frame queue valid (IBSS PS mode, ATIM) */
-       bool short_slot;        /* TRUE, if short slot timing is enabled. */
        bool radio_hw_enable;   /* saved state of radio hardware enabled state */
        bool suspend_in_progress;       /* TRUE, if we are in a suspend/resume cycle */
 
index 9d1768d5fbad6029257b6d781b1ef3f0b89f27fb..ba7a5ab7fe1d8f9c44bd5d961bff1b06a4eb8bda 100644 (file)
@@ -703,13 +703,11 @@ static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
 static void b43_short_slot_timing_enable(struct b43_wldev *dev)
 {
        b43_set_slot_time(dev, 9);
-       dev->short_slot = 1;
 }
 
 static void b43_short_slot_timing_disable(struct b43_wldev *dev)
 {
        b43_set_slot_time(dev, 20);
-       dev->short_slot = 0;
 }
 
 /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
@@ -3361,16 +3359,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
        if (conf->channel->hw_value != phy->channel)
                b43_switch_channel(dev, conf->channel->hw_value);
 
-       /* Enable/Disable ShortSlot timing. */
-       if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
-           dev->short_slot) {
-               B43_WARN_ON(phy->type != B43_PHYTYPE_G);
-               if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
-                       b43_short_slot_timing_enable(dev);
-               else
-                       b43_short_slot_timing_disable(dev);
-       }
-
        dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
 
        /* Adjust the desired TX power level. */
@@ -3421,6 +3409,104 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
        return err;
 }
 
+static void b43_update_basic_rates(struct b43_wldev *dev, u64 brates)
+{
+       struct ieee80211_supported_band *sband =
+               dev->wl->hw->wiphy->bands[b43_current_band(dev->wl)];
+       struct ieee80211_rate *rate;
+       int i;
+       u16 basic, direct, offset, basic_offset, rateptr;
+
+       for (i = 0; i < sband->n_bitrates; i++) {
+               rate = &sband->bitrates[i];
+
+               if (b43_is_cck_rate(rate->hw_value)) {
+                       direct = B43_SHM_SH_CCKDIRECT;
+                       basic = B43_SHM_SH_CCKBASIC;
+                       offset = b43_plcp_get_ratecode_cck(rate->hw_value);
+                       offset &= 0xF;
+               } else {
+                       direct = B43_SHM_SH_OFDMDIRECT;
+                       basic = B43_SHM_SH_OFDMBASIC;
+                       offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
+                       offset &= 0xF;
+               }
+
+               rate = ieee80211_get_response_rate(sband, brates, rate->bitrate);
+
+               if (b43_is_cck_rate(rate->hw_value)) {
+                       basic_offset = b43_plcp_get_ratecode_cck(rate->hw_value);
+                       basic_offset &= 0xF;
+               } else {
+                       basic_offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
+                       basic_offset &= 0xF;
+               }
+
+               /*
+                * Get the pointer that we need to point to
+                * from the direct map
+                */
+               rateptr = b43_shm_read16(dev, B43_SHM_SHARED,
+                                        direct + 2 * basic_offset);
+               /* and write it to the basic map */
+               b43_shm_write16(dev, B43_SHM_SHARED, basic + 2 * offset,
+                               rateptr);
+       }
+}
+
+static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
+                                   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);
+               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) {
+               if (conf->use_short_slot)
+                       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:
+       mutex_unlock(&wl->mutex);
+
+       return;
+}
+
 static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                           const u8 *local_addr, const u8 *addr,
                           struct ieee80211_key_conf *key)
@@ -4210,6 +4296,7 @@ static const struct ieee80211_ops b43_hw_ops = {
        .add_interface          = b43_op_add_interface,
        .remove_interface       = b43_op_remove_interface,
        .config                 = b43_op_config,
+       .bss_info_changed       = b43_op_bss_info_changed,
        .config_interface       = b43_op_config_interface,
        .configure_filter       = b43_op_configure_filter,
        .set_key                = b43_op_set_key,