mwifiex: add calibration data download feature
authorAmitkumar Karwar <akarwar@marvell.com>
Sat, 18 May 2013 00:50:25 +0000 (17:50 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 22 May 2013 19:08:58 +0000 (15:08 -0400)
User can provide a text file containing calibration data in hex
format while loading mwifiex module. It will be downloaded to
firmware.
eg. insmod mwifiex.ko cal_data_cfg=cal_data.conf

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/sta_cmdresp.c

index d3c1e01..d6ada73 100644 (file)
@@ -271,6 +271,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define HostCmd_CMD_802_11_SUBSCRIBE_EVENT            0x0075
 #define HostCmd_CMD_802_11_TX_RATE_QUERY              0x007f
 #define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS     0x0083
+#define HostCmd_CMD_CFG_DATA                          0x008f
 #define HostCmd_CMD_VERSION_EXT                       0x0097
 #define HostCmd_CMD_MEF_CFG                           0x009a
 #define HostCmd_CMD_RSSI_INFO                         0x00a4
@@ -465,6 +466,8 @@ enum P2P_MODES {
 #define MWIFIEX_CRITERIA_UNICAST       BIT(1)
 #define MWIFIEX_CRITERIA_MULTICAST     BIT(3)
 
+#define CFG_DATA_TYPE_CAL              2
+
 struct mwifiex_ie_types_header {
        __le16 type;
        __le16 len;
@@ -1579,6 +1582,12 @@ struct mwifiex_ie_list {
        struct mwifiex_ie ie_list[MAX_MGMT_IE_INDEX];
 } __packed;
 
+struct host_cmd_ds_802_11_cfg_data {
+       __le16 action;
+       __le16 type;
+       __le16 data_len;
+} __packed;
+
 struct host_cmd_ds_command {
        __le16 command;
        __le16 size;
@@ -1638,6 +1647,7 @@ struct host_cmd_ds_command {
                struct host_cmd_ds_sys_config uap_sys_config;
                struct host_cmd_ds_sta_deauth sta_deauth;
                struct host_cmd_11ac_vht_cfg vht_cfg;
+               struct host_cmd_ds_802_11_cfg_data cfg_data;
        } params;
 } __packed;
 
index eb85186..29d83f0 100644 (file)
@@ -25,6 +25,8 @@
 #define VERSION        "1.0"
 
 const char driver_version[] = "mwifiex " VERSION " (%s) ";
+static char *cal_data_cfg;
+module_param(cal_data_cfg, charp, 0);
 
 /*
  * This function registers the device and performs all the necessary
@@ -336,6 +338,13 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
 
        dev_notice(adapter->dev, "WLAN FW is active\n");
 
+       if (cal_data_cfg) {
+               if ((request_firmware(&adapter->cal_data, cal_data_cfg,
+                                     adapter->dev)) < 0)
+                       dev_err(adapter->dev,
+                               "Cal data request_firmware() failed\n");
+       }
+
        adapter->init_wait_q_woken = false;
        ret = mwifiex_init_fw(adapter);
        if (ret == -1) {
@@ -390,6 +399,10 @@ err_init_fw:
        pr_debug("info: %s: unregister device\n", __func__);
        adapter->if_ops.unregister_dev(adapter);
 done:
+       if (adapter->cal_data) {
+               release_firmware(adapter->cal_data);
+               adapter->cal_data = NULL;
+       }
        release_firmware(adapter->firmware);
        complete(&adapter->fw_load);
        return;
index 9cf6852..0832c24 100644 (file)
@@ -730,6 +730,7 @@ struct mwifiex_adapter {
        u16 max_mgmt_ie_index;
        u8 scan_delay_cnt;
        u8 empty_tx_q_cnt;
+       const struct firmware *cal_data;
 
        /* 11AC */
        u32 is_hw_11ac_capable;
index b193e25..8ece485 100644 (file)
@@ -1134,6 +1134,55 @@ mwifiex_cmd_mef_cfg(struct mwifiex_private *priv,
        return 0;
 }
 
+/* This function parse cal data from ASCII to hex */
+static u32 mwifiex_parse_cal_cfg(u8 *src, size_t len, u8 *dst)
+{
+       u8 *s = src, *d = dst;
+
+       while (s - src < len) {
+               if (*s && (isspace(*s) || *s == '\t')) {
+                       s++;
+                       continue;
+               }
+               if (isxdigit(*s)) {
+                       *d++ = simple_strtol(s, NULL, 16);
+                       s += 2;
+               } else {
+                       s++;
+               }
+       }
+
+       return d - dst;
+}
+
+/* This function prepares command of set_cfg_data. */
+static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv,
+                               struct host_cmd_ds_command *cmd,
+                               u16 cmd_action)
+{
+       struct host_cmd_ds_802_11_cfg_data *cfg_data = &cmd->params.cfg_data;
+       struct mwifiex_adapter *adapter = priv->adapter;
+       u32 len, cal_data_offset;
+       u8 *tmp_cmd = (u8 *)cmd;
+
+       cal_data_offset = S_DS_GEN + sizeof(*cfg_data);
+       if ((adapter->cal_data->data) && (adapter->cal_data->size > 0))
+               len = mwifiex_parse_cal_cfg((u8 *)adapter->cal_data->data,
+                                           adapter->cal_data->size,
+                                           (u8 *)(tmp_cmd + cal_data_offset));
+       else
+               return -1;
+
+       cfg_data->action = cpu_to_le16(cmd_action);
+       cfg_data->type = cpu_to_le16(CFG_DATA_TYPE_CAL);
+       cfg_data->data_len = cpu_to_le16(len);
+
+       cmd->command = cpu_to_le16(HostCmd_CMD_CFG_DATA);
+       cmd->size = cpu_to_le16(S_DS_GEN + sizeof(*cfg_data) + len);
+
+       return 0;
+}
+
 /*
  * This function prepares the commands before sending them to the firmware.
  *
@@ -1152,6 +1201,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
        case HostCmd_CMD_GET_HW_SPEC:
                ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr);
                break;
+       case HostCmd_CMD_CFG_DATA:
+               ret = mwifiex_cmd_cfg_data(priv, cmd_ptr, cmd_action);
+               break;
        case HostCmd_CMD_MAC_CONTROL:
                ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action,
                                              data_buf);
@@ -1384,6 +1436,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
  */
 int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
 {
+       struct mwifiex_adapter *adapter = priv->adapter;
        int ret;
        u16 enable = true;
        struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
@@ -1404,6 +1457,15 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
                                            HostCmd_ACT_GEN_SET, 0, NULL);
                if (ret)
                        return -1;
+
+               /* Download calibration data to firmware */
+               if (adapter->cal_data) {
+                       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA,
+                                               HostCmd_ACT_GEN_SET, 0, NULL);
+                       if (ret)
+                               return -1;
+               }
+
                /* Read MAC address from HW */
                ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_GET_HW_SPEC,
                                            HostCmd_ACT_GEN_GET, 0, NULL);
index c710a1b..d85df15 100644 (file)
@@ -818,6 +818,18 @@ static int mwifiex_ret_subsc_evt(struct mwifiex_private *priv,
        return 0;
 }
 
+/* This function handles the command response of set_cfg_data */
+static int mwifiex_ret_cfg_data(struct mwifiex_private *priv,
+                               struct host_cmd_ds_command *resp)
+{
+       if (resp->result != HostCmd_RESULT_OK) {
+               dev_err(priv->adapter->dev, "Cal data cmd resp failed\n");
+               return -1;
+       }
+
+       return 0;
+}
+
 /*
  * This function handles the command responses.
  *
@@ -841,6 +853,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
        case HostCmd_CMD_GET_HW_SPEC:
                ret = mwifiex_ret_get_hw_spec(priv, resp);
                break;
+       case HostCmd_CMD_CFG_DATA:
+               ret = mwifiex_ret_cfg_data(priv, resp);
+               break;
        case HostCmd_CMD_MAC_CONTROL:
                break;
        case HostCmd_CMD_802_11_MAC_ADDRESS: