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 17d4f31..c479ee2 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 cbc01a0..8b6a729 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 ef49440..35fb4a4 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 0f9f8b6..1c54064 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 ff86abc..b5db050 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 0711b35..5a55c87 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;