diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c')
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c | 68 |
1 files changed, 52 insertions, 16 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c index 4a4dea087..7beba9ae5 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -72,8 +73,6 @@ #include "iwl-trans.h" #define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */ -#define IWL_NUM_PAPD_CH_GROUPS 9 -#define IWL_NUM_TXP_CH_GROUPS 9 struct iwl_phy_db_entry { u16 size; @@ -86,14 +85,18 @@ struct iwl_phy_db_entry { * @cfg: phy configuration. * @calib_nch: non channel specific calibration data. * @calib_ch: channel specific calibration data. + * @n_group_papd: number of entries in papd channel group. * @calib_ch_group_papd: calibration data related to papd channel group. + * @n_group_txp: number of entries in tx power channel group. * @calib_ch_group_txp: calibration data related to tx power chanel group. */ struct iwl_phy_db { struct iwl_phy_db_entry cfg; struct iwl_phy_db_entry calib_nch; - struct iwl_phy_db_entry calib_ch_group_papd[IWL_NUM_PAPD_CH_GROUPS]; - struct iwl_phy_db_entry calib_ch_group_txp[IWL_NUM_TXP_CH_GROUPS]; + int n_group_papd; + struct iwl_phy_db_entry *calib_ch_group_papd; + int n_group_txp; + struct iwl_phy_db_entry *calib_ch_group_txp; struct iwl_trans *trans; }; @@ -143,6 +146,9 @@ struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans) phy_db->trans = trans; + phy_db->n_group_txp = -1; + phy_db->n_group_papd = -1; + /* TODO: add default values of the phy db. */ return phy_db; } @@ -166,11 +172,11 @@ iwl_phy_db_get_section(struct iwl_phy_db *phy_db, case IWL_PHY_DB_CALIB_NCH: return &phy_db->calib_nch; case IWL_PHY_DB_CALIB_CHG_PAPD: - if (chg_id >= IWL_NUM_PAPD_CH_GROUPS) + if (chg_id >= phy_db->n_group_papd) return NULL; return &phy_db->calib_ch_group_papd[chg_id]; case IWL_PHY_DB_CALIB_CHG_TXP: - if (chg_id >= IWL_NUM_TXP_CH_GROUPS) + if (chg_id >= phy_db->n_group_txp) return NULL; return &phy_db->calib_ch_group_txp[chg_id]; default: @@ -202,17 +208,21 @@ void iwl_phy_db_free(struct iwl_phy_db *phy_db) iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CFG, 0); iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_NCH, 0); - for (i = 0; i < IWL_NUM_PAPD_CH_GROUPS; i++) + + for (i = 0; i < phy_db->n_group_papd; i++) iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_PAPD, i); - for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++) + kfree(phy_db->calib_ch_group_papd); + + for (i = 0; i < phy_db->n_group_txp; i++) iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_TXP, i); + kfree(phy_db->calib_ch_group_txp); kfree(phy_db); } IWL_EXPORT_SYMBOL(iwl_phy_db_free); -int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt, - gfp_t alloc_ctx) +int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, + struct iwl_rx_packet *pkt) { struct iwl_calib_res_notif_phy_db *phy_db_notif = (struct iwl_calib_res_notif_phy_db *)pkt->data; @@ -224,16 +234,42 @@ int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt, if (!phy_db) return -EINVAL; - if (type == IWL_PHY_DB_CALIB_CHG_PAPD || - type == IWL_PHY_DB_CALIB_CHG_TXP) + if (type == IWL_PHY_DB_CALIB_CHG_PAPD) { chg_id = le16_to_cpup((__le16 *)phy_db_notif->data); + if (phy_db && !phy_db->calib_ch_group_papd) { + /* + * Firmware sends the largest index first, so we can use + * it to know how much we should allocate. + */ + phy_db->calib_ch_group_papd = kcalloc(chg_id + 1, + sizeof(struct iwl_phy_db_entry), + GFP_ATOMIC); + if (!phy_db->calib_ch_group_papd) + return -ENOMEM; + phy_db->n_group_papd = chg_id + 1; + } + } else if (type == IWL_PHY_DB_CALIB_CHG_TXP) { + chg_id = le16_to_cpup((__le16 *)phy_db_notif->data); + if (phy_db && !phy_db->calib_ch_group_txp) { + /* + * Firmware sends the largest index first, so we can use + * it to know how much we should allocate. + */ + phy_db->calib_ch_group_txp = kcalloc(chg_id + 1, + sizeof(struct iwl_phy_db_entry), + GFP_ATOMIC); + if (!phy_db->calib_ch_group_txp) + return -ENOMEM; + phy_db->n_group_txp = chg_id + 1; + } + } entry = iwl_phy_db_get_section(phy_db, type, chg_id); if (!entry) return -EINVAL; kfree(entry->data); - entry->data = kmemdup(phy_db_notif->data, size, alloc_ctx); + entry->data = kmemdup(phy_db_notif->data, size, GFP_ATOMIC); if (!entry->data) { entry->size = 0; return -ENOMEM; @@ -296,7 +332,7 @@ static u16 channel_id_to_txp(struct iwl_phy_db *phy_db, u16 ch_id) if (ch_index == 0xff) return 0xff; - for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++) { + for (i = 0; i < phy_db->n_group_txp; i++) { txp_chg = (void *)phy_db->calib_ch_group_txp[i].data; if (!txp_chg) return 0xff; @@ -447,7 +483,7 @@ int iwl_send_phy_db_data(struct iwl_phy_db *phy_db) /* Send all the TXP channel specific data */ err = iwl_phy_db_send_all_channel_groups(phy_db, IWL_PHY_DB_CALIB_CHG_PAPD, - IWL_NUM_PAPD_CH_GROUPS); + phy_db->n_group_papd); if (err) { IWL_ERR(phy_db->trans, "Cannot send channel specific PAPD groups\n"); @@ -457,7 +493,7 @@ int iwl_send_phy_db_data(struct iwl_phy_db *phy_db) /* Send all the TXP channel specific data */ err = iwl_phy_db_send_all_channel_groups(phy_db, IWL_PHY_DB_CALIB_CHG_TXP, - IWL_NUM_TXP_CH_GROUPS); + phy_db->n_group_txp); if (err) { IWL_ERR(phy_db->trans, "Cannot send channel specific TX power groups\n"); |