iwlwifi: generic init calibrations framework
authorTomas Winkler <tomas.winkler@intel.com>
Wed, 3 Sep 2008 03:26:37 +0000 (11:26 +0800)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 8 Sep 2008 18:23:18 +0000 (14:23 -0400)
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>
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 cbc01a00eaf4416e42ea3b2261df33506fe52d14..8b6a72949ac011af5d930cc94f1bea88097b0142 100644 (file)
@@ -444,48 +444,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;
@@ -510,33 +468,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,
@@ -834,7 +789,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 0f9f8b65bf5710e9f555c64c5279b1e7f93dd0d3..1c5406487b1182ff75b97e8dfa94e6f9fcca7160 100644 (file)
@@ -937,22 +937,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;
@@ -980,10 +964,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 ff86abc668ba367ff3ee4965cdc20e4fbd93c0f8..b5db050b22d1aea7cc990759b43e87c600763376 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, struct ieee80211_channel *ch);
@@ -289,6 +288,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 0711b35b9ade02b04adbbed499f67706aa679b40..5a55c876917d8ac4ef69101e7f509a5ee99fa357 100644 (file)
@@ -728,13 +728,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 {
@@ -796,6 +793,7 @@ enum {
 
 
 #define IWL_MAX_NUM_QUEUES     20 /* FIXME: do dynamic allocation */
+#define IWL_CALIB_MAX  3
 
 struct iwl_priv {
 
@@ -839,7 +837,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;