Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / net / wireless / ath / ath9k / htc_drv_init.c
index fc67c93..3bea7ea 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -117,6 +117,21 @@ static struct ieee80211_rate ath9k_legacy_rates[] = {
        RATE(540, 0x0c, 0),
 };
 
+#ifdef CONFIG_MAC80211_LEDS
+static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = {
+       { .throughput = 0 * 1024, .blink_time = 334 },
+       { .throughput = 1 * 1024, .blink_time = 260 },
+       { .throughput = 5 * 1024, .blink_time = 220 },
+       { .throughput = 10 * 1024, .blink_time = 190 },
+       { .throughput = 20 * 1024, .blink_time = 170 },
+       { .throughput = 50 * 1024, .blink_time = 150 },
+       { .throughput = 70 * 1024, .blink_time = 130 },
+       { .throughput = 100 * 1024, .blink_time = 110 },
+       { .throughput = 200 * 1024, .blink_time = 80 },
+       { .throughput = 300 * 1024, .blink_time = 50 },
+};
+#endif
+
 static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
 {
        int time_left;
@@ -140,7 +155,6 @@ static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
 
 static void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
 {
-       ath9k_htc_exit_debug(priv->ah);
        ath9k_hw_deinit(priv->ah);
        kfree(priv->ah);
        priv->ah = NULL;
@@ -430,13 +444,16 @@ static void ath9k_regwrite_flush(void *hw_priv)
        mutex_unlock(&priv->wmi->multi_write_mutex);
 }
 
-static const struct ath_ops ath9k_common_ops = {
-       .read = ath9k_regread,
-       .multi_read = ath9k_multi_regread,
-       .write = ath9k_regwrite,
-       .enable_write_buffer = ath9k_enable_regwrite_buffer,
-       .write_flush = ath9k_regwrite_flush,
-};
+static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
+{
+       u32 val;
+
+       val = ath9k_regread(hw_priv, reg_offset);
+       val &= ~clr;
+       val |= set;
+       ath9k_regwrite(hw_priv, val, reg_offset);
+       return val;
+}
 
 static void ath_usb_read_cachesize(struct ath_common *common, int *csz)
 {
@@ -561,13 +578,7 @@ static void ath9k_init_crypto(struct ath9k_htc_priv *priv)
        int i = 0;
 
        /* Get the hardware key cache size. */
-       common->keymax = priv->ah->caps.keycache_size;
-       if (common->keymax > ATH_KEYMAX) {
-               ath_dbg(common, ATH_DBG_ANY,
-                       "Warning, using only %u entries in %u key cache\n",
-                       ATH_KEYMAX, common->keymax);
-               common->keymax = ATH_KEYMAX;
-       }
+       common->keymax = AR_KEYTABLE_SIZE;
 
        if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
                common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
@@ -646,7 +657,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
 {
        struct ath_hw *ah = NULL;
        struct ath_common *common;
-       int ret = 0, csz = 0;
+       int i, ret = 0, csz = 0;
 
        priv->op_flags |= OP_INVALID;
 
@@ -658,30 +669,35 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
        ah->hw_version.subsysid = 0; /* FIXME */
        ah->hw_version.usbdev = drv_info;
        ah->ah_flags |= AH_USE_EEPROM;
+       ah->reg_ops.read = ath9k_regread;
+       ah->reg_ops.multi_read = ath9k_multi_regread;
+       ah->reg_ops.write = ath9k_regwrite;
+       ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer;
+       ah->reg_ops.write_flush = ath9k_regwrite_flush;
+       ah->reg_ops.rmw = ath9k_reg_rmw;
        priv->ah = ah;
 
        common = ath9k_hw_common(ah);
-       common->ops = &ath9k_common_ops;
+       common->ops = &ah->reg_ops;
        common->bus_ops = &ath9k_usb_bus_ops;
        common->ah = ah;
        common->hw = priv->hw;
        common->priv = priv;
        common->debug_mask = ath9k_debug;
 
-       spin_lock_init(&priv->wmi->wmi_lock);
        spin_lock_init(&priv->beacon_lock);
-       spin_lock_init(&priv->tx_lock);
+       spin_lock_init(&priv->tx.tx_lock);
        mutex_init(&priv->mutex);
        mutex_init(&priv->htc_pm_lock);
-       tasklet_init(&priv->swba_tasklet, ath9k_swba_tasklet,
-                    (unsigned long)priv);
        tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
                     (unsigned long)priv);
-       tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet,
+       tasklet_init(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet,
                     (unsigned long)priv);
        INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work);
        INIT_WORK(&priv->ps_work, ath9k_ps_work);
        INIT_WORK(&priv->fatal_work, ath9k_fatal_work);
+       setup_timer(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer,
+                   (unsigned long)priv);
 
        /*
         * Cache line size is used to size and align various
@@ -698,16 +714,13 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
                goto err_hw;
        }
 
-       ret = ath9k_htc_init_debug(ah);
-       if (ret) {
-               ath_err(common, "Unable to create debugfs files\n");
-               goto err_debug;
-       }
-
        ret = ath9k_init_queues(priv);
        if (ret)
                goto err_queues;
 
+       for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
+               priv->cur_beacon_conf.bslot[i] = NULL;
+
        ath9k_init_crypto(priv);
        ath9k_init_channels_rates(priv);
        ath9k_init_misc(priv);
@@ -720,8 +733,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
        return 0;
 
 err_queues:
-       ath9k_htc_exit_debug(ah);
-err_debug:
        ath9k_hw_deinit(ah);
 err_hw:
 
@@ -742,17 +753,23 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
                IEEE80211_HW_HAS_RATE_CONTROL |
                IEEE80211_HW_RX_INCLUDES_FCS |
                IEEE80211_HW_SUPPORTS_PS |
-               IEEE80211_HW_PS_NULLFUNC_STACK;
+               IEEE80211_HW_PS_NULLFUNC_STACK |
+               IEEE80211_HW_REPORTS_TX_ACK_STATUS |
+               IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
 
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_STATION) |
-               BIT(NL80211_IFTYPE_ADHOC);
+               BIT(NL80211_IFTYPE_ADHOC) |
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_P2P_GO) |
+               BIT(NL80211_IFTYPE_P2P_CLIENT);
 
        hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
        hw->queues = 4;
        hw->channel_change_time = 5000;
        hw->max_listen_interval = 10;
+
        hw->vif_data_size = sizeof(struct ath9k_htc_vif);
        hw->sta_data_size = sizeof(struct ath9k_htc_sta);
 
@@ -779,6 +796,43 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
        SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
 }
 
+static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
+{
+       struct ieee80211_hw *hw = priv->hw;
+       struct wmi_fw_version cmd_rsp;
+       int ret;
+
+       memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+
+       WMI_CMD(WMI_GET_FW_VERSION);
+       if (ret)
+               return -EINVAL;
+
+       priv->fw_version_major = be16_to_cpu(cmd_rsp.major);
+       priv->fw_version_minor = be16_to_cpu(cmd_rsp.minor);
+
+       snprintf(hw->wiphy->fw_version, ETHTOOL_BUSINFO_LEN, "%d.%d",
+                priv->fw_version_major,
+                priv->fw_version_minor);
+
+       dev_info(priv->dev, "ath9k_htc: FW Version: %d.%d\n",
+                priv->fw_version_major,
+                priv->fw_version_minor);
+
+       /*
+        * Check if the available FW matches the driver's
+        * required version.
+        */
+       if (priv->fw_version_major != MAJOR_VERSION_REQ ||
+           priv->fw_version_minor != MINOR_VERSION_REQ) {
+               dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n",
+                       MAJOR_VERSION_REQ, MINOR_VERSION_REQ);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int ath9k_init_device(struct ath9k_htc_priv *priv,
                             u16 devid, char *product, u32 drv_info)
 {
@@ -798,6 +852,10 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
        common = ath9k_hw_common(ah);
        ath9k_set_hw_capab(priv, hw);
 
+       error = ath9k_init_firmware_version(priv);
+       if (error != 0)
+               goto err_fw;
+
        /* Initialize regulatory */
        error = ath_regd_init(&common->regulatory, priv->hw->wiphy,
                              ath9k_reg_notifier);
@@ -816,6 +874,13 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
        if (error != 0)
                goto err_rx;
 
+#ifdef CONFIG_MAC80211_LEDS
+       /* must be initialized before ieee80211_register_hw */
+       priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw,
+               IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_htc_tpt_blink,
+               ARRAY_SIZE(ath9k_htc_tpt_blink));
+#endif
+
        /* Register with mac80211 */
        error = ieee80211_register_hw(hw);
        if (error)
@@ -828,6 +893,12 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
                        goto err_world;
        }
 
+       error = ath9k_htc_init_debug(priv->ah);
+       if (error) {
+               ath_err(common, "Unable to create debugfs files\n");
+               goto err_world;
+       }
+
        ath_dbg(common, ATH_DBG_CONFIG,
                "WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, "
                "BE:%d, BK:%d, VI:%d, VO:%d\n",
@@ -858,6 +929,8 @@ err_rx:
 err_tx:
        /* Nothing */
 err_regd:
+       /* Nothing */
+err_fw:
        ath9k_deinit_priv(priv);
 err_init:
        return error;
@@ -946,38 +1019,20 @@ int ath9k_htc_resume(struct htc_target *htc_handle)
 
 static int __init ath9k_htc_init(void)
 {
-       int error;
-
-       error = ath9k_htc_debug_create_root();
-       if (error < 0) {
-               printk(KERN_ERR
-                       "ath9k_htc: Unable to create debugfs root: %d\n",
-                       error);
-               goto err_dbg;
-       }
-
-       error = ath9k_hif_usb_init();
-       if (error < 0) {
+       if (ath9k_hif_usb_init() < 0) {
                printk(KERN_ERR
                        "ath9k_htc: No USB devices found,"
                        " driver not installed.\n");
-               error = -ENODEV;
-               goto err_usb;
+               return -ENODEV;
        }
 
        return 0;
-
-err_usb:
-       ath9k_htc_debug_remove_root();
-err_dbg:
-       return error;
 }
 module_init(ath9k_htc_init);
 
 static void __exit ath9k_htc_exit(void)
 {
        ath9k_hif_usb_exit();
-       ath9k_htc_debug_remove_root();
        printk(KERN_INFO "ath9k_htc: Driver unloaded\n");
 }
 module_exit(ath9k_htc_exit);