wl1271: 11n Support, Add Definitions
[linux-2.6.git] / drivers / net / wireless / wl12xx / wl1271_main.c
index c131758..5d5f4c6 100644 (file)
@@ -214,7 +214,9 @@ static struct conf_drv_settings default_conf = {
                .ps_poll_recovery_period     = 700,
                .bet_enable                  = CONF_BET_MODE_ENABLE,
                .bet_max_consecutive         = 10,
-               .psm_entry_retries           = 3,
+               .psm_entry_retries           = 5,
+               .psm_entry_nullfunc_retries  = 3,
+               .psm_entry_hangover_period   = 1,
                .keep_alive_interval         = 55000,
                .max_listen_interval         = 20,
        },
@@ -232,7 +234,24 @@ static struct conf_drv_settings default_conf = {
                .avg_weight_rssi_data         = 10,
                .avg_weight_snr_beacon        = 20,
                .avg_weight_snr_data          = 10
-       }
+       },
+       .scan = {
+               .min_dwell_time_active        = 7500,
+               .max_dwell_time_active        = 30000,
+               .min_dwell_time_passive       = 30000,
+               .max_dwell_time_passive       = 60000,
+               .num_probe_reqs               = 2,
+       },
+       .rf = {
+               .tx_per_channel_power_compensation_2 = {
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               },
+               .tx_per_channel_power_compensation_5 = {
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               },
+       },
 };
 
 static void __wl1271_op_remove_interface(struct wl1271 *wl);
@@ -348,6 +367,10 @@ static int wl1271_plt_init(struct wl1271 *wl)
        if (ret < 0)
                return ret;
 
+       ret = wl1271_cmd_ext_radio_parms(wl);
+       if (ret < 0)
+               return ret;
+
        ret = wl1271_init_templates_config(wl);
        if (ret < 0)
                return ret;
@@ -458,9 +481,9 @@ static void wl1271_fw_status(struct wl1271 *wl,
                total += cnt;
        }
 
-       /* if more blocks are available now, schedule some tx work */
-       if (total && !skb_queue_empty(&wl->tx_queue))
-               ieee80211_queue_work(wl->hw, &wl->tx_work);
+       /* if more blocks are available now, tx work can be scheduled */
+       if (total)
+               clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
 
        /* update the host-chipset time offset */
        getnstimeofday(&ts);
@@ -514,6 +537,16 @@ static void wl1271_irq_work(struct work_struct *work)
                            (wl->tx_results_count & 0xff))
                                wl1271_tx_complete(wl);
 
+                       /* Check if any tx blocks were freed */
+                       if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
+                                       !skb_queue_empty(&wl->tx_queue)) {
+                               /*
+                                * In order to avoid starvation of the TX path,
+                                * call the work function directly.
+                                */
+                               wl1271_tx_work_locked(wl);
+                       }
+
                        wl1271_rx(wl, wl->fw_status);
                }
 
@@ -627,6 +660,9 @@ static void wl1271_recovery_work(struct work_struct *work)
 
        wl1271_info("Hardware recovery in progress.");
 
+       if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+               ieee80211_connection_loss(wl->vif);
+
        /* reboot the chipset */
        __wl1271_op_remove_interface(wl);
        ieee80211_restart_hw(wl->hw);
@@ -655,11 +691,6 @@ static int wl1271_setup(struct wl1271 *wl)
                return -ENOMEM;
        }
 
-       INIT_WORK(&wl->irq_work, wl1271_irq_work);
-       INIT_WORK(&wl->tx_work, wl1271_tx_work);
-       INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
-       INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
-
        return 0;
 }
 
@@ -846,7 +877,8 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
         * before that, the tx_work will not be initialized!
         */
 
-       ieee80211_queue_work(wl->hw, &wl->tx_work);
+       if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
+               ieee80211_queue_work(wl->hw, &wl->tx_work);
 
        /*
         * The workqueue is slow to process the tx_queue and we need stop
@@ -1353,7 +1385,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
                if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
                        wl1271_debug(DEBUG_PSM, "psm enabled");
                        ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
-                                                wl->basic_rate_set, true);
+                                                wl->basic_rate, true);
                }
        } else if (!(conf->flags & IEEE80211_CONF_PS) &&
                   test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
@@ -1363,7 +1395,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 
                if (test_bit(WL1271_FLAG_PSM, &wl->flags))
                        ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
-                                                wl->basic_rate_set, true);
+                                                wl->basic_rate, true);
        }
 
        if (conf->power_level != wl->power_level) {
@@ -1540,6 +1572,11 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
                tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
                break;
+       case WL1271_CIPHER_SUITE_GEM:
+               key_type = KEY_GEM;
+               tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
+               tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
+               break;
        default:
                wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
 
@@ -1839,7 +1876,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                            !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
                                mode = STATION_POWER_SAVE_MODE;
                                ret = wl1271_ps_set_mode(wl, mode,
-                                                        wl->basic_rate_set,
+                                                        wl->basic_rate,
                                                         true);
                                if (ret < 0)
                                        goto out_sleep;
@@ -2108,6 +2145,21 @@ static const u8 wl1271_rate_to_idx_2ghz[] = {
        0                              /* CONF_HW_RXTX_RATE_1    */
 };
 
+/* 11n STA capabilities */
+#define HW_RX_HIGHEST_RATE     72
+
+#define WL1271_HT_CAP { \
+       .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
+       .ht_supported = true, \
+       .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
+       .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
+       .mcs = { \
+               .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
+               .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
+               .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
+               }, \
+}
+
 /* can't be const, mac80211 writes to this */
 static struct ieee80211_supported_band wl1271_band_2ghz = {
        .channels = wl1271_channels,
@@ -2394,6 +2446,14 @@ EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
 
 int wl1271_init_ieee80211(struct wl1271 *wl)
 {
+       static const u32 cipher_suites[] = {
+               WLAN_CIPHER_SUITE_WEP40,
+               WLAN_CIPHER_SUITE_WEP104,
+               WLAN_CIPHER_SUITE_TKIP,
+               WLAN_CIPHER_SUITE_CCMP,
+               WL1271_CIPHER_SUITE_GEM,
+       };
+
        /* The tx descriptor buffer and the TKIP space. */
        wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
                sizeof(struct wl1271_tx_hw_descr);
@@ -2411,6 +2471,9 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
                IEEE80211_HW_CONNECTION_MONITOR |
                IEEE80211_HW_SUPPORTS_CQM_RSSI;
 
+       wl->hw->wiphy->cipher_suites = cipher_suites;
+       wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
        wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_ADHOC);
        wl->hw->wiphy->max_scan_ssids = 1;
@@ -2434,6 +2497,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
        struct platform_device *plat_dev = NULL;
        struct wl1271 *wl;
        int i, ret;
+       unsigned int order;
 
        hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
        if (!hw) {
@@ -2461,6 +2525,10 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 
        INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
        INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
+       INIT_WORK(&wl->irq_work, wl1271_irq_work);
+       INIT_WORK(&wl->tx_work, wl1271_tx_work);
+       INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
+       INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
        wl->channel = WL1271_DEFAULT_CHANNEL;
        wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
        wl->default_key = 0;
@@ -2479,6 +2547,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
        wl->sg_enabled = true;
        wl->hw_pg_ver = -1;
 
+       memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
        for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
                wl->tx_frames[i] = NULL;
 
@@ -2492,11 +2561,18 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 
        wl1271_debugfs_init(wl);
 
+       order = get_order(WL1271_AGGR_BUFFER_SIZE);
+       wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
+       if (!wl->aggr_buf) {
+               ret = -ENOMEM;
+               goto err_hw;
+       }
+
        /* Register platform device */
        ret = platform_device_register(wl->plat_dev);
        if (ret) {
                wl1271_error("couldn't register platform device");
-               goto err_hw;
+               goto err_aggr;
        }
        dev_set_drvdata(&wl->plat_dev->dev, wl);
 
@@ -2522,6 +2598,9 @@ err_bt_coex_state:
 err_platform:
        platform_device_unregister(wl->plat_dev);
 
+err_aggr:
+       free_pages((unsigned long)wl->aggr_buf, order);
+
 err_hw:
        wl1271_debugfs_exit(wl);
        kfree(plat_dev);
@@ -2538,6 +2617,8 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
 int wl1271_free_hw(struct wl1271 *wl)
 {
        platform_device_unregister(wl->plat_dev);
+       free_pages((unsigned long)wl->aggr_buf,
+                       get_order(WL1271_AGGR_BUFFER_SIZE));
        kfree(wl->plat_dev);
 
        wl1271_debugfs_exit(wl);