]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
iwlwifi: generic init calibrations framework
authorTomas Winkler <tomas.winkler@intel.com>
Wed, 3 Sep 2008 03:26:37 +0000 (11:26 +0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 13 Nov 2008 17:56:02 +0000 (09:56 -0800)
commit 6e21f2c109edd746a10e08186484bae8168cdd0c upstream

This patch allows variable number of init calibrations and allows
addition new HW.

This patch also fixes critical bug. Only last calibration result
was applied. On reception of one calibration result all the calibration
was freed.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/net/wireless/iwlwifi/iwl-5000-hw.h
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-calib.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-dev.h

index 17d4f31c59345ce9c2883ef01afd44820bb1d931..c479ee211c5cf14d322db770c0c9e91a17a9e27a 100644 (file)
@@ -129,6 +129,13 @@ struct iwl5000_shared {
        __le32 padding2;
 } __attribute__ ((packed));
 
+/* calibrations defined for 5000 */
+/* defines the order in which results should be sent to the runtime uCode */
+enum iwl5000_calib {
+       IWL5000_CALIB_LO,
+       IWL5000_CALIB_TX_IQ,
+       IWL5000_CALIB_TX_IQ_PERD,
+};
 
 #endif /* __iwl_5000_hw_h__ */
 
index b08036a9d8945555efca52e64df7a87e69270d97..79ff288cd82a2b0ffdf2ec6be82d1caef408ffcd 100644 (file)
@@ -445,48 +445,6 @@ static int iwl5000_send_Xtal_calib(struct iwl_priv *priv)
                                sizeof(cal_cmd), &cal_cmd);
 }
 
-static int iwl5000_send_calib_results(struct iwl_priv *priv)
-{
-       int ret = 0;
-
-       struct iwl_host_cmd hcmd = {
-               .id = REPLY_PHY_CALIBRATION_CMD,
-               .meta.flags = CMD_SIZE_HUGE,
-       };
-
-       if (priv->calib_results.lo_res) {
-               hcmd.len = priv->calib_results.lo_res_len;
-               hcmd.data = priv->calib_results.lo_res;
-               ret = iwl_send_cmd_sync(priv, &hcmd);
-
-               if (ret)
-                       goto err;
-       }
-
-       if (priv->calib_results.tx_iq_res) {
-               hcmd.len = priv->calib_results.tx_iq_res_len;
-               hcmd.data = priv->calib_results.tx_iq_res;
-               ret = iwl_send_cmd_sync(priv, &hcmd);
-
-               if (ret)
-                       goto err;
-       }
-
-       if (priv->calib_results.tx_iq_perd_res) {
-               hcmd.len = priv->calib_results.tx_iq_perd_res_len;
-               hcmd.data = priv->calib_results.tx_iq_perd_res;
-               ret = iwl_send_cmd_sync(priv, &hcmd);
-
-               if (ret)
-                       goto err;
-       }
-
-       return 0;
-err:
-       IWL_ERROR("Error %d\n", ret);
-       return ret;
-}
-
 static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
 {
        struct iwl5000_calib_cfg_cmd calib_cfg_cmd;
@@ -511,33 +469,30 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv,
        struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
        struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw;
        int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK;
-
-       iwl_free_calib_results(priv);
+       int index;
 
        /* reduce the size of the length field itself */
        len -= 4;
 
+       /* Define the order in which the results will be sent to the runtime
+        * uCode. iwl_send_calib_results sends them in a row according to their
+        * index. We sort them here */
        switch (hdr->op_code) {
        case IWL5000_PHY_CALIBRATE_LO_CMD:
-               priv->calib_results.lo_res = kzalloc(len, GFP_ATOMIC);
-               priv->calib_results.lo_res_len = len;
-               memcpy(priv->calib_results.lo_res, pkt->u.raw, len);
+               index = IWL5000_CALIB_LO;
                break;
        case IWL5000_PHY_CALIBRATE_TX_IQ_CMD:
-               priv->calib_results.tx_iq_res = kzalloc(len, GFP_ATOMIC);
-               priv->calib_results.tx_iq_res_len = len;
-               memcpy(priv->calib_results.tx_iq_res, pkt->u.raw, len);
+               index = IWL5000_CALIB_TX_IQ;
                break;
        case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD:
-               priv->calib_results.tx_iq_perd_res = kzalloc(len, GFP_ATOMIC);
-               priv->calib_results.tx_iq_perd_res_len = len;
-               memcpy(priv->calib_results.tx_iq_perd_res, pkt->u.raw, len);
+               index = IWL5000_CALIB_TX_IQ_PERD;
                break;
        default:
                IWL_ERROR("Unknown calibration notification %d\n",
                          hdr->op_code);
                return;
        }
+       iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
 }
 
 static void iwl5000_rx_calib_complete(struct iwl_priv *priv,
@@ -832,7 +787,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
        iwl5000_send_Xtal_calib(priv);
 
        if (priv->ucode_type == UCODE_RT)
-               iwl5000_send_calib_results(priv);
+               iwl_send_calib_results(priv);
 
        return 0;
 }
index ef49440bd7f6ac71c9fbb3a1f79316c0148ede2b..35fb4a4f737daba64f8c3a06eb6c7cb470343968 100644 (file)
 #include "iwl-core.h"
 #include "iwl-calib.h"
 
+/*****************************************************************************
+ * INIT calibrations framework
+ *****************************************************************************/
+
+ int iwl_send_calib_results(struct iwl_priv *priv)
+{
+       int ret = 0;
+       int i = 0;
+
+       struct iwl_host_cmd hcmd = {
+               .id = REPLY_PHY_CALIBRATION_CMD,
+               .meta.flags = CMD_SIZE_HUGE,
+       };
+
+       for (i = 0; i < IWL_CALIB_MAX; i++)
+               if (priv->calib_results[i].buf) {
+                       hcmd.len = priv->calib_results[i].buf_len;
+                       hcmd.data = priv->calib_results[i].buf;
+                       ret = iwl_send_cmd_sync(priv, &hcmd);
+                       if (ret)
+                               goto err;
+               }
+
+       return 0;
+err:
+       IWL_ERROR("Error %d iteration %d\n", ret, i);
+       return ret;
+}
+EXPORT_SYMBOL(iwl_send_calib_results);
+
+int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len)
+{
+       if (res->buf_len != len) {
+               kfree(res->buf);
+               res->buf = kzalloc(len, GFP_ATOMIC);
+       }
+       if (unlikely(res->buf == NULL))
+               return -ENOMEM;
+
+       res->buf_len = len;
+       memcpy(res->buf, buf, len);
+       return 0;
+}
+EXPORT_SYMBOL(iwl_calib_set);
+
+void iwl_calib_free_results(struct iwl_priv *priv)
+{
+       int i;
+
+       for (i = 0; i < IWL_CALIB_MAX; i++) {
+               kfree(priv->calib_results[i].buf);
+               priv->calib_results[i].buf = NULL;
+               priv->calib_results[i].buf_len = 0;
+       }
+}
+
+/*****************************************************************************
+ * RUNTIME calibrations framework
+ *****************************************************************************/
+
 /* "false alarms" are signals that our DSP tries to lock onto,
  *   but then determines that they are either noise, or transmissions
  *   from a distant wireless network (also "noise", really) that get
index 53b3e27db70be7d0356511115ff2f78e33fd4328..1383fd14031173700ad584c017035b71c4b514b6 100644 (file)
@@ -956,22 +956,6 @@ err:
 }
 EXPORT_SYMBOL(iwl_init_drv);
 
-void iwl_free_calib_results(struct iwl_priv *priv)
-{
-       kfree(priv->calib_results.lo_res);
-       priv->calib_results.lo_res = NULL;
-       priv->calib_results.lo_res_len = 0;
-
-       kfree(priv->calib_results.tx_iq_res);
-       priv->calib_results.tx_iq_res = NULL;
-       priv->calib_results.tx_iq_res_len = 0;
-
-       kfree(priv->calib_results.tx_iq_perd_res);
-       priv->calib_results.tx_iq_perd_res = NULL;
-       priv->calib_results.tx_iq_perd_res_len = 0;
-}
-EXPORT_SYMBOL(iwl_free_calib_results);
-
 int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
 {
        int ret = 0;
@@ -999,10 +983,9 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
 }
 EXPORT_SYMBOL(iwl_set_tx_power);
 
-
 void iwl_uninit_drv(struct iwl_priv *priv)
 {
-       iwl_free_calib_results(priv);
+       iwl_calib_free_results(priv);
        iwlcore_free_geos(priv);
        iwl_free_channel_map(priv);
        kfree(priv->scan);
index 64f139e97444f264b938b67956a77e836edcd747..51b36b1186e9a50e2865b4b306af3904d2e828bd 100644 (file)
@@ -186,7 +186,6 @@ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
 void iwl_hw_detect(struct iwl_priv *priv);
 
 void iwl_clear_stations_table(struct iwl_priv *priv);
-void iwl_free_calib_results(struct iwl_priv *priv);
 void iwl_reset_qos(struct iwl_priv *priv);
 void iwl_set_rxon_chain(struct iwl_priv *priv);
 int iwl_set_rxon_channel(struct iwl_priv *priv,
@@ -291,6 +290,13 @@ int iwl_scan_initiate(struct iwl_priv *priv);
 void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
 void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
 
+/*******************************************************************************
+ * Calibrations - implemented in iwl-calib.c
+ ******************************************************************************/
+int iwl_send_calib_results(struct iwl_priv *priv);
+int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len);
+void iwl_calib_free_results(struct iwl_priv *priv);
+
 /*****************************************************
  *   S e n d i n g     H o s t     C o m m a n d s   *
  *****************************************************/
index 9267b5755f4a2093f9201b6c41d9383e75f8dbc1..09bdf8e0ebedffe7ca7c52bb10cd943bc97cc444 100644 (file)
@@ -745,13 +745,10 @@ struct statistics_general_data {
        u32 beacon_energy_c;
 };
 
-struct iwl_calib_results {
-       void *tx_iq_res;
-       void *tx_iq_perd_res;
-       void *lo_res;
-       u32 tx_iq_res_len;
-       u32 tx_iq_perd_res_len;
-       u32 lo_res_len;
+/* Opaque calibration results */
+struct iwl_calib_result {
+       void *buf;
+       size_t buf_len;
 };
 
 enum ucode_type {
@@ -813,6 +810,7 @@ enum {
 
 
 #define IWL_MAX_NUM_QUEUES     20 /* FIXME: do dynamic allocation */
+#define IWL_CALIB_MAX  3
 
 struct iwl_priv {
 
@@ -857,7 +855,7 @@ struct iwl_priv {
        s32 last_temperature;
 
        /* init calibration results */
-       struct iwl_calib_results calib_results;
+       struct iwl_calib_result calib_results[IWL_CALIB_MAX];
 
        /* Scan related variables */
        unsigned long last_scan_jiffies;