b43legacy: implement short slot and basic rate handling
authorJohannes Berg <johannes@sipsolutions.net>
Thu, 6 Nov 2008 14:18:11 +0000 (15:18 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 21 Nov 2008 16:06:06 +0000 (11:06 -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.

(port from b43)

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

index c40078e..97b0e06 100644 (file)
 #define B43legacy_SHM_SH_PRMAXTIME     0x0074 /* Probe Response max time */
 #define B43legacy_SHM_SH_PRPHYCTL      0x0188 /* Probe Resp PHY TX control */
 /* SHM_SHARED rate tables */
+#define B43legacy_SHM_SH_OFDMDIRECT    0x0480 /* Pointer to OFDM direct map */
+#define B43legacy_SHM_SH_OFDMBASIC     0x04A0 /* Pointer to OFDM basic rate map */
+#define B43legacy_SHM_SH_CCKDIRECT     0x04C0 /* Pointer to CCK direct map */
+#define B43legacy_SHM_SH_CCKBASIC      0x04E0 /* Pointer to CCK basic rate map */
 /* SHM_SHARED microcode soft registers */
 #define B43legacy_SHM_SH_UCODEREV      0x0000 /* Microcode revision */
 #define B43legacy_SHM_SH_UCODEPATCH    0x0002 /* Microcode patchlevel */
@@ -663,7 +667,6 @@ struct b43legacy_wldev {
        bool bad_frames_preempt;/* Use "Bad Frames Preemption". */
        bool dfq_valid;         /* Directed frame queue valid (IBSS PS mode, ATIM). */
        bool short_preamble;    /* TRUE if using short preamble. */
-       bool short_slot;        /* TRUE if using short slot timing. */
        bool radio_hw_enable;   /* State of radio hardware enable bit. */
 
        /* PHY/Radio device. */
index 6c8eb4d..c1324e3 100644 (file)
@@ -576,13 +576,11 @@ static void b43legacy_set_slot_time(struct b43legacy_wldev *dev,
 static void b43legacy_short_slot_timing_enable(struct b43legacy_wldev *dev)
 {
        b43legacy_set_slot_time(dev, 9);
-       dev->short_slot = 1;
 }
 
 static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev)
 {
        b43legacy_set_slot_time(dev, 20);
-       dev->short_slot = 0;
 }
 
 /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
@@ -2608,16 +2606,6 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
        if (conf->channel->hw_value != phy->channel)
                b43legacy_radio_selectchannel(dev, conf->channel->hw_value, 0);
 
-       /* Enable/Disable ShortSlot timing. */
-       if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME))
-            != dev->short_slot) {
-               B43legacy_WARN_ON(phy->type != B43legacy_PHYTYPE_G);
-               if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
-                       b43legacy_short_slot_timing_enable(dev);
-               else
-                       b43legacy_short_slot_timing_disable(dev);
-       }
-
        dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
 
        /* Adjust the desired TX power level. */
@@ -2662,6 +2650,104 @@ out_unlock_mutex:
        return err;
 }
 
+static void b43legacy_update_basic_rates(struct b43legacy_wldev *dev, u64 brates)
+{
+       struct ieee80211_supported_band *sband =
+               dev->wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
+       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 (b43legacy_is_cck_rate(rate->hw_value)) {
+                       direct = B43legacy_SHM_SH_CCKDIRECT;
+                       basic = B43legacy_SHM_SH_CCKBASIC;
+                       offset = b43legacy_plcp_get_ratecode_cck(rate->hw_value);
+                       offset &= 0xF;
+               } else {
+                       direct = B43legacy_SHM_SH_OFDMDIRECT;
+                       basic = B43legacy_SHM_SH_OFDMBASIC;
+                       offset = b43legacy_plcp_get_ratecode_ofdm(rate->hw_value);
+                       offset &= 0xF;
+               }
+
+               rate = ieee80211_get_response_rate(sband, brates, rate->bitrate);
+
+               if (b43legacy_is_cck_rate(rate->hw_value)) {
+                       basic_offset = b43legacy_plcp_get_ratecode_cck(rate->hw_value);
+                       basic_offset &= 0xF;
+               } else {
+                       basic_offset = b43legacy_plcp_get_ratecode_ofdm(rate->hw_value);
+                       basic_offset &= 0xF;
+               }
+
+               /*
+                * Get the pointer that we need to point to
+                * from the direct map
+                */
+               rateptr = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+                                              direct + 2 * basic_offset);
+               /* and write it to the basic map */
+               b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+                                     basic + 2 * offset, rateptr);
+       }
+}
+
+static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw,
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_bss_conf *conf,
+                                   u32 changed)
+{
+       struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+       struct b43legacy_wldev *dev;
+       struct b43legacy_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 (b43legacy_status(dev) < B43legacy_STAT_STARTED) {
+               spin_unlock_irqrestore(&wl->irq_lock, flags);
+               goto out_unlock_mutex;
+       }
+       savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+       b43legacy_synchronize_irq(dev);
+
+       b43legacy_mac_suspend(dev);
+
+       if (changed & BSS_CHANGED_BASIC_RATES)
+               b43legacy_update_basic_rates(dev, conf->basic_rates);
+
+       if (changed & BSS_CHANGED_ERP_SLOT) {
+               if (conf->use_short_slot)
+                       b43legacy_short_slot_timing_enable(dev);
+               else
+                       b43legacy_short_slot_timing_disable(dev);
+       }
+
+       b43legacy_mac_enable(dev);
+
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       b43legacy_interrupt_enable(dev, savedirqs);
+       /* XXX: why? */
+       mmiowb();
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+ out_unlock_mutex:
+       mutex_unlock(&wl->mutex);
+
+       return;
+}
+
 static void b43legacy_op_configure_filter(struct ieee80211_hw *hw,
                                          unsigned int changed,
                                          unsigned int *fflags,
@@ -3370,6 +3456,7 @@ static const struct ieee80211_ops b43legacy_hw_ops = {
        .add_interface          = b43legacy_op_add_interface,
        .remove_interface       = b43legacy_op_remove_interface,
        .config                 = b43legacy_op_dev_config,
+       .bss_info_changed       = b43legacy_op_bss_info_changed,
        .config_interface       = b43legacy_op_config_interface,
        .configure_filter       = b43legacy_op_configure_filter,
        .get_stats              = b43legacy_op_get_stats,