Commit 6e21f2c1 authored by Tomas Winkler's avatar Tomas Winkler Committed by John W. Linville

iwlwifi: generic init calibrations framework

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: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarZhu Yi <yi.zhu@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 7c95168a
......@@ -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__ */
......@@ -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;
}
......
......@@ -66,6 +66,66 @@
#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
......
......@@ -937,22 +937,6 @@ int iwl_init_drv(struct iwl_priv *priv)
}
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);
......
......@@ -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 *
*****************************************************/
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment