1e705c121SKalle Valo /****************************************************************************** 2e705c121SKalle Valo * 3e705c121SKalle Valo * This file is provided under a dual BSD/GPLv2 license. When using or 4e705c121SKalle Valo * redistributing this file, you may do so under either license. 5e705c121SKalle Valo * 6e705c121SKalle Valo * GPL LICENSE SUMMARY 7e705c121SKalle Valo * 8e705c121SKalle Valo * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. 90ec84d1dSSara Sharon * Copyright(c) 2016 Intel Deutschland GmbH 10e705c121SKalle Valo * 11e705c121SKalle Valo * This program is free software; you can redistribute it and/or modify 12e705c121SKalle Valo * it under the terms of version 2 of the GNU General Public License as 13e705c121SKalle Valo * published by the Free Software Foundation. 14e705c121SKalle Valo * 15e705c121SKalle Valo * This program is distributed in the hope that it will be useful, but 16e705c121SKalle Valo * WITHOUT ANY WARRANTY; without even the implied warranty of 17e705c121SKalle Valo * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18e705c121SKalle Valo * General Public License for more details. 19e705c121SKalle Valo * 20e705c121SKalle Valo * You should have received a copy of the GNU General Public License 21e705c121SKalle Valo * along with this program; if not, write to the Free Software 22e705c121SKalle Valo * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, 23e705c121SKalle Valo * USA 24e705c121SKalle Valo * 25e705c121SKalle Valo * The full GNU General Public License is included in this distribution 26e705c121SKalle Valo * in the file called COPYING. 27e705c121SKalle Valo * 28e705c121SKalle Valo * Contact Information: 29cb2f8277SEmmanuel Grumbach * Intel Linux Wireless <linuxwifi@intel.com> 30e705c121SKalle Valo * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 31e705c121SKalle Valo * 32e705c121SKalle Valo * BSD LICENSE 33e705c121SKalle Valo * 34e705c121SKalle Valo * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. 35e705c121SKalle Valo * All rights reserved. 36e705c121SKalle Valo * 37e705c121SKalle Valo * Redistribution and use in source and binary forms, with or without 38e705c121SKalle Valo * modification, are permitted provided that the following conditions 39e705c121SKalle Valo * are met: 40e705c121SKalle Valo * 41e705c121SKalle Valo * * Redistributions of source code must retain the above copyright 42e705c121SKalle Valo * notice, this list of conditions and the following disclaimer. 43e705c121SKalle Valo * * Redistributions in binary form must reproduce the above copyright 44e705c121SKalle Valo * notice, this list of conditions and the following disclaimer in 45e705c121SKalle Valo * the documentation and/or other materials provided with the 46e705c121SKalle Valo * distribution. 47e705c121SKalle Valo * * Neither the name Intel Corporation nor the names of its 48e705c121SKalle Valo * contributors may be used to endorse or promote products derived 49e705c121SKalle Valo * from this software without specific prior written permission. 50e705c121SKalle Valo * 51e705c121SKalle Valo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 52e705c121SKalle Valo * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 53e705c121SKalle Valo * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 54e705c121SKalle Valo * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 55e705c121SKalle Valo * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 56e705c121SKalle Valo * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 57e705c121SKalle Valo * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 58e705c121SKalle Valo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 59e705c121SKalle Valo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 60e705c121SKalle Valo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 61e705c121SKalle Valo * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62e705c121SKalle Valo * 63e705c121SKalle Valo *****************************************************************************/ 64e705c121SKalle Valo 65e705c121SKalle Valo #include <linux/slab.h> 66e705c121SKalle Valo #include <linux/string.h> 67e705c121SKalle Valo #include <linux/export.h> 68e705c121SKalle Valo 69e705c121SKalle Valo #include "iwl-drv.h" 70e705c121SKalle Valo #include "iwl-phy-db.h" 71e705c121SKalle Valo #include "iwl-debug.h" 72e705c121SKalle Valo #include "iwl-op-mode.h" 73e705c121SKalle Valo #include "iwl-trans.h" 74e705c121SKalle Valo 75e705c121SKalle Valo #define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */ 76e705c121SKalle Valo 77e705c121SKalle Valo struct iwl_phy_db_entry { 78e705c121SKalle Valo u16 size; 79e705c121SKalle Valo u8 *data; 80e705c121SKalle Valo }; 81e705c121SKalle Valo 82e705c121SKalle Valo /** 83e705c121SKalle Valo * struct iwl_phy_db - stores phy configuration and calibration data. 84e705c121SKalle Valo * 85e705c121SKalle Valo * @cfg: phy configuration. 86e705c121SKalle Valo * @calib_nch: non channel specific calibration data. 87e705c121SKalle Valo * @calib_ch: channel specific calibration data. 880ec84d1dSSara Sharon * @n_group_papd: number of entries in papd channel group. 89e705c121SKalle Valo * @calib_ch_group_papd: calibration data related to papd channel group. 900ec84d1dSSara Sharon * @n_group_txp: number of entries in tx power channel group. 91e705c121SKalle Valo * @calib_ch_group_txp: calibration data related to tx power chanel group. 92e705c121SKalle Valo */ 93e705c121SKalle Valo struct iwl_phy_db { 94e705c121SKalle Valo struct iwl_phy_db_entry cfg; 95e705c121SKalle Valo struct iwl_phy_db_entry calib_nch; 960ec84d1dSSara Sharon int n_group_papd; 970ec84d1dSSara Sharon struct iwl_phy_db_entry *calib_ch_group_papd; 980ec84d1dSSara Sharon int n_group_txp; 990ec84d1dSSara Sharon struct iwl_phy_db_entry *calib_ch_group_txp; 100e705c121SKalle Valo 101e705c121SKalle Valo struct iwl_trans *trans; 102e705c121SKalle Valo }; 103e705c121SKalle Valo 104e705c121SKalle Valo enum iwl_phy_db_section_type { 105e705c121SKalle Valo IWL_PHY_DB_CFG = 1, 106e705c121SKalle Valo IWL_PHY_DB_CALIB_NCH, 107e705c121SKalle Valo IWL_PHY_DB_UNUSED, 108e705c121SKalle Valo IWL_PHY_DB_CALIB_CHG_PAPD, 109e705c121SKalle Valo IWL_PHY_DB_CALIB_CHG_TXP, 110e705c121SKalle Valo IWL_PHY_DB_MAX 111e705c121SKalle Valo }; 112e705c121SKalle Valo 113*176aa60bSSara Sharon #define PHY_DB_CMD 0x6c 114e705c121SKalle Valo 115e705c121SKalle Valo /* 116e705c121SKalle Valo * phy db - configure operational ucode 117e705c121SKalle Valo */ 118e705c121SKalle Valo struct iwl_phy_db_cmd { 119e705c121SKalle Valo __le16 type; 120e705c121SKalle Valo __le16 length; 121e705c121SKalle Valo u8 data[]; 122e705c121SKalle Valo } __packed; 123e705c121SKalle Valo 124e705c121SKalle Valo /* for parsing of tx power channel group data that comes from the firmware*/ 125e705c121SKalle Valo struct iwl_phy_db_chg_txp { 126e705c121SKalle Valo __le32 space; 127e705c121SKalle Valo __le16 max_channel_idx; 128e705c121SKalle Valo } __packed; 129e705c121SKalle Valo 130e705c121SKalle Valo /* 131e705c121SKalle Valo * phy db - Receive phy db chunk after calibrations 132e705c121SKalle Valo */ 133e705c121SKalle Valo struct iwl_calib_res_notif_phy_db { 134e705c121SKalle Valo __le16 type; 135e705c121SKalle Valo __le16 length; 136e705c121SKalle Valo u8 data[]; 137e705c121SKalle Valo } __packed; 138e705c121SKalle Valo 139e705c121SKalle Valo struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans) 140e705c121SKalle Valo { 141e705c121SKalle Valo struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), 142e705c121SKalle Valo GFP_KERNEL); 143e705c121SKalle Valo 144e705c121SKalle Valo if (!phy_db) 145e705c121SKalle Valo return phy_db; 146e705c121SKalle Valo 147e705c121SKalle Valo phy_db->trans = trans; 148e705c121SKalle Valo 1490ec84d1dSSara Sharon phy_db->n_group_txp = -1; 1500ec84d1dSSara Sharon phy_db->n_group_papd = -1; 1510ec84d1dSSara Sharon 152e705c121SKalle Valo /* TODO: add default values of the phy db. */ 153e705c121SKalle Valo return phy_db; 154e705c121SKalle Valo } 155e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_phy_db_init); 156e705c121SKalle Valo 157e705c121SKalle Valo /* 158e705c121SKalle Valo * get phy db section: returns a pointer to a phy db section specified by 159e705c121SKalle Valo * type and channel group id. 160e705c121SKalle Valo */ 161e705c121SKalle Valo static struct iwl_phy_db_entry * 162e705c121SKalle Valo iwl_phy_db_get_section(struct iwl_phy_db *phy_db, 163e705c121SKalle Valo enum iwl_phy_db_section_type type, 164e705c121SKalle Valo u16 chg_id) 165e705c121SKalle Valo { 166e705c121SKalle Valo if (!phy_db || type >= IWL_PHY_DB_MAX) 167e705c121SKalle Valo return NULL; 168e705c121SKalle Valo 169e705c121SKalle Valo switch (type) { 170e705c121SKalle Valo case IWL_PHY_DB_CFG: 171e705c121SKalle Valo return &phy_db->cfg; 172e705c121SKalle Valo case IWL_PHY_DB_CALIB_NCH: 173e705c121SKalle Valo return &phy_db->calib_nch; 174e705c121SKalle Valo case IWL_PHY_DB_CALIB_CHG_PAPD: 1750ec84d1dSSara Sharon if (chg_id >= phy_db->n_group_papd) 176e705c121SKalle Valo return NULL; 177e705c121SKalle Valo return &phy_db->calib_ch_group_papd[chg_id]; 178e705c121SKalle Valo case IWL_PHY_DB_CALIB_CHG_TXP: 1790ec84d1dSSara Sharon if (chg_id >= phy_db->n_group_txp) 180e705c121SKalle Valo return NULL; 181e705c121SKalle Valo return &phy_db->calib_ch_group_txp[chg_id]; 182e705c121SKalle Valo default: 183e705c121SKalle Valo return NULL; 184e705c121SKalle Valo } 185e705c121SKalle Valo return NULL; 186e705c121SKalle Valo } 187e705c121SKalle Valo 188e705c121SKalle Valo static void iwl_phy_db_free_section(struct iwl_phy_db *phy_db, 189e705c121SKalle Valo enum iwl_phy_db_section_type type, 190e705c121SKalle Valo u16 chg_id) 191e705c121SKalle Valo { 192e705c121SKalle Valo struct iwl_phy_db_entry *entry = 193e705c121SKalle Valo iwl_phy_db_get_section(phy_db, type, chg_id); 194e705c121SKalle Valo if (!entry) 195e705c121SKalle Valo return; 196e705c121SKalle Valo 197e705c121SKalle Valo kfree(entry->data); 198e705c121SKalle Valo entry->data = NULL; 199e705c121SKalle Valo entry->size = 0; 200e705c121SKalle Valo } 201e705c121SKalle Valo 202e705c121SKalle Valo void iwl_phy_db_free(struct iwl_phy_db *phy_db) 203e705c121SKalle Valo { 204e705c121SKalle Valo int i; 205e705c121SKalle Valo 206e705c121SKalle Valo if (!phy_db) 207e705c121SKalle Valo return; 208e705c121SKalle Valo 209e705c121SKalle Valo iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CFG, 0); 210e705c121SKalle Valo iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_NCH, 0); 2110ec84d1dSSara Sharon 2120ec84d1dSSara Sharon for (i = 0; i < phy_db->n_group_papd; i++) 213e705c121SKalle Valo iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_PAPD, i); 2140ec84d1dSSara Sharon kfree(phy_db->calib_ch_group_papd); 2150ec84d1dSSara Sharon 2160ec84d1dSSara Sharon for (i = 0; i < phy_db->n_group_txp; i++) 217e705c121SKalle Valo iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_TXP, i); 2180ec84d1dSSara Sharon kfree(phy_db->calib_ch_group_txp); 219e705c121SKalle Valo 220e705c121SKalle Valo kfree(phy_db); 221e705c121SKalle Valo } 222e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_phy_db_free); 223e705c121SKalle Valo 224ce1f2778SSara Sharon int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, 225ce1f2778SSara Sharon struct iwl_rx_packet *pkt) 226e705c121SKalle Valo { 227e705c121SKalle Valo struct iwl_calib_res_notif_phy_db *phy_db_notif = 228e705c121SKalle Valo (struct iwl_calib_res_notif_phy_db *)pkt->data; 229e705c121SKalle Valo enum iwl_phy_db_section_type type = le16_to_cpu(phy_db_notif->type); 230e705c121SKalle Valo u16 size = le16_to_cpu(phy_db_notif->length); 231e705c121SKalle Valo struct iwl_phy_db_entry *entry; 232e705c121SKalle Valo u16 chg_id = 0; 233e705c121SKalle Valo 234e705c121SKalle Valo if (!phy_db) 235e705c121SKalle Valo return -EINVAL; 236e705c121SKalle Valo 2370ec84d1dSSara Sharon if (type == IWL_PHY_DB_CALIB_CHG_PAPD) { 238e705c121SKalle Valo chg_id = le16_to_cpup((__le16 *)phy_db_notif->data); 2390ec84d1dSSara Sharon if (phy_db && !phy_db->calib_ch_group_papd) { 2400ec84d1dSSara Sharon /* 2410ec84d1dSSara Sharon * Firmware sends the largest index first, so we can use 2420ec84d1dSSara Sharon * it to know how much we should allocate. 2430ec84d1dSSara Sharon */ 2440ec84d1dSSara Sharon phy_db->calib_ch_group_papd = kcalloc(chg_id + 1, 2450ec84d1dSSara Sharon sizeof(struct iwl_phy_db_entry), 2460ec84d1dSSara Sharon GFP_ATOMIC); 2470ec84d1dSSara Sharon if (!phy_db->calib_ch_group_papd) 2480ec84d1dSSara Sharon return -ENOMEM; 2490ec84d1dSSara Sharon phy_db->n_group_papd = chg_id + 1; 2500ec84d1dSSara Sharon } 2510ec84d1dSSara Sharon } else if (type == IWL_PHY_DB_CALIB_CHG_TXP) { 2520ec84d1dSSara Sharon chg_id = le16_to_cpup((__le16 *)phy_db_notif->data); 2530ec84d1dSSara Sharon if (phy_db && !phy_db->calib_ch_group_txp) { 2540ec84d1dSSara Sharon /* 2550ec84d1dSSara Sharon * Firmware sends the largest index first, so we can use 2560ec84d1dSSara Sharon * it to know how much we should allocate. 2570ec84d1dSSara Sharon */ 2580ec84d1dSSara Sharon phy_db->calib_ch_group_txp = kcalloc(chg_id + 1, 2590ec84d1dSSara Sharon sizeof(struct iwl_phy_db_entry), 2600ec84d1dSSara Sharon GFP_ATOMIC); 2610ec84d1dSSara Sharon if (!phy_db->calib_ch_group_txp) 2620ec84d1dSSara Sharon return -ENOMEM; 2630ec84d1dSSara Sharon phy_db->n_group_txp = chg_id + 1; 2640ec84d1dSSara Sharon } 2650ec84d1dSSara Sharon } 266e705c121SKalle Valo 267e705c121SKalle Valo entry = iwl_phy_db_get_section(phy_db, type, chg_id); 268e705c121SKalle Valo if (!entry) 269e705c121SKalle Valo return -EINVAL; 270e705c121SKalle Valo 271e705c121SKalle Valo kfree(entry->data); 272ce1f2778SSara Sharon entry->data = kmemdup(phy_db_notif->data, size, GFP_ATOMIC); 273e705c121SKalle Valo if (!entry->data) { 274e705c121SKalle Valo entry->size = 0; 275e705c121SKalle Valo return -ENOMEM; 276e705c121SKalle Valo } 277e705c121SKalle Valo 278e705c121SKalle Valo entry->size = size; 279e705c121SKalle Valo 280e705c121SKalle Valo IWL_DEBUG_INFO(phy_db->trans, 281e705c121SKalle Valo "%s(%d): [PHYDB]SET: Type %d , Size: %d\n", 282e705c121SKalle Valo __func__, __LINE__, type, size); 283e705c121SKalle Valo 284e705c121SKalle Valo return 0; 285e705c121SKalle Valo } 286e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_phy_db_set_section); 287e705c121SKalle Valo 288e705c121SKalle Valo static int is_valid_channel(u16 ch_id) 289e705c121SKalle Valo { 290e705c121SKalle Valo if (ch_id <= 14 || 291e705c121SKalle Valo (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) || 292e705c121SKalle Valo (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) || 293e705c121SKalle Valo (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1)) 294e705c121SKalle Valo return 1; 295e705c121SKalle Valo return 0; 296e705c121SKalle Valo } 297e705c121SKalle Valo 298e705c121SKalle Valo static u8 ch_id_to_ch_index(u16 ch_id) 299e705c121SKalle Valo { 300e705c121SKalle Valo if (WARN_ON(!is_valid_channel(ch_id))) 301e705c121SKalle Valo return 0xff; 302e705c121SKalle Valo 303e705c121SKalle Valo if (ch_id <= 14) 304e705c121SKalle Valo return ch_id - 1; 305e705c121SKalle Valo if (ch_id <= 64) 306e705c121SKalle Valo return (ch_id + 20) / 4; 307e705c121SKalle Valo if (ch_id <= 140) 308e705c121SKalle Valo return (ch_id - 12) / 4; 309e705c121SKalle Valo return (ch_id - 13) / 4; 310e705c121SKalle Valo } 311e705c121SKalle Valo 312e705c121SKalle Valo 313e705c121SKalle Valo static u16 channel_id_to_papd(u16 ch_id) 314e705c121SKalle Valo { 315e705c121SKalle Valo if (WARN_ON(!is_valid_channel(ch_id))) 316e705c121SKalle Valo return 0xff; 317e705c121SKalle Valo 318e705c121SKalle Valo if (1 <= ch_id && ch_id <= 14) 319e705c121SKalle Valo return 0; 320e705c121SKalle Valo if (36 <= ch_id && ch_id <= 64) 321e705c121SKalle Valo return 1; 322e705c121SKalle Valo if (100 <= ch_id && ch_id <= 140) 323e705c121SKalle Valo return 2; 324e705c121SKalle Valo return 3; 325e705c121SKalle Valo } 326e705c121SKalle Valo 327e705c121SKalle Valo static u16 channel_id_to_txp(struct iwl_phy_db *phy_db, u16 ch_id) 328e705c121SKalle Valo { 329e705c121SKalle Valo struct iwl_phy_db_chg_txp *txp_chg; 330e705c121SKalle Valo int i; 331e705c121SKalle Valo u8 ch_index = ch_id_to_ch_index(ch_id); 332e705c121SKalle Valo if (ch_index == 0xff) 333e705c121SKalle Valo return 0xff; 334e705c121SKalle Valo 3350ec84d1dSSara Sharon for (i = 0; i < phy_db->n_group_txp; i++) { 336e705c121SKalle Valo txp_chg = (void *)phy_db->calib_ch_group_txp[i].data; 337e705c121SKalle Valo if (!txp_chg) 338e705c121SKalle Valo return 0xff; 339e705c121SKalle Valo /* 340e705c121SKalle Valo * Looking for the first channel group that its max channel is 341e705c121SKalle Valo * higher then wanted channel. 342e705c121SKalle Valo */ 343e705c121SKalle Valo if (le16_to_cpu(txp_chg->max_channel_idx) >= ch_index) 344e705c121SKalle Valo return i; 345e705c121SKalle Valo } 346e705c121SKalle Valo return 0xff; 347e705c121SKalle Valo } 348e705c121SKalle Valo static 349e705c121SKalle Valo int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db, 350e705c121SKalle Valo u32 type, u8 **data, u16 *size, u16 ch_id) 351e705c121SKalle Valo { 352e705c121SKalle Valo struct iwl_phy_db_entry *entry; 353e705c121SKalle Valo u16 ch_group_id = 0; 354e705c121SKalle Valo 355e705c121SKalle Valo if (!phy_db) 356e705c121SKalle Valo return -EINVAL; 357e705c121SKalle Valo 358e705c121SKalle Valo /* find wanted channel group */ 359e705c121SKalle Valo if (type == IWL_PHY_DB_CALIB_CHG_PAPD) 360e705c121SKalle Valo ch_group_id = channel_id_to_papd(ch_id); 361e705c121SKalle Valo else if (type == IWL_PHY_DB_CALIB_CHG_TXP) 362e705c121SKalle Valo ch_group_id = channel_id_to_txp(phy_db, ch_id); 363e705c121SKalle Valo 364e705c121SKalle Valo entry = iwl_phy_db_get_section(phy_db, type, ch_group_id); 365e705c121SKalle Valo if (!entry) 366e705c121SKalle Valo return -EINVAL; 367e705c121SKalle Valo 368e705c121SKalle Valo *data = entry->data; 369e705c121SKalle Valo *size = entry->size; 370e705c121SKalle Valo 371e705c121SKalle Valo IWL_DEBUG_INFO(phy_db->trans, 372e705c121SKalle Valo "%s(%d): [PHYDB] GET: Type %d , Size: %d\n", 373e705c121SKalle Valo __func__, __LINE__, type, *size); 374e705c121SKalle Valo 375e705c121SKalle Valo return 0; 376e705c121SKalle Valo } 377e705c121SKalle Valo 378e705c121SKalle Valo static int iwl_send_phy_db_cmd(struct iwl_phy_db *phy_db, u16 type, 379e705c121SKalle Valo u16 length, void *data) 380e705c121SKalle Valo { 381e705c121SKalle Valo struct iwl_phy_db_cmd phy_db_cmd; 382e705c121SKalle Valo struct iwl_host_cmd cmd = { 383e705c121SKalle Valo .id = PHY_DB_CMD, 384e705c121SKalle Valo }; 385e705c121SKalle Valo 386e705c121SKalle Valo IWL_DEBUG_INFO(phy_db->trans, 387e705c121SKalle Valo "Sending PHY-DB hcmd of type %d, of length %d\n", 388e705c121SKalle Valo type, length); 389e705c121SKalle Valo 390e705c121SKalle Valo /* Set phy db cmd variables */ 391e705c121SKalle Valo phy_db_cmd.type = cpu_to_le16(type); 392e705c121SKalle Valo phy_db_cmd.length = cpu_to_le16(length); 393e705c121SKalle Valo 394e705c121SKalle Valo /* Set hcmd variables */ 395e705c121SKalle Valo cmd.data[0] = &phy_db_cmd; 396e705c121SKalle Valo cmd.len[0] = sizeof(struct iwl_phy_db_cmd); 397e705c121SKalle Valo cmd.data[1] = data; 398e705c121SKalle Valo cmd.len[1] = length; 399e705c121SKalle Valo cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY; 400e705c121SKalle Valo 401e705c121SKalle Valo return iwl_trans_send_cmd(phy_db->trans, &cmd); 402e705c121SKalle Valo } 403e705c121SKalle Valo 404e705c121SKalle Valo static int iwl_phy_db_send_all_channel_groups( 405e705c121SKalle Valo struct iwl_phy_db *phy_db, 406e705c121SKalle Valo enum iwl_phy_db_section_type type, 407e705c121SKalle Valo u8 max_ch_groups) 408e705c121SKalle Valo { 409e705c121SKalle Valo u16 i; 410e705c121SKalle Valo int err; 411e705c121SKalle Valo struct iwl_phy_db_entry *entry; 412e705c121SKalle Valo 413e705c121SKalle Valo /* Send all the channel specific groups to operational fw */ 414e705c121SKalle Valo for (i = 0; i < max_ch_groups; i++) { 415e705c121SKalle Valo entry = iwl_phy_db_get_section(phy_db, 416e705c121SKalle Valo type, 417e705c121SKalle Valo i); 418e705c121SKalle Valo if (!entry) 419e705c121SKalle Valo return -EINVAL; 420e705c121SKalle Valo 421e705c121SKalle Valo if (!entry->size) 422e705c121SKalle Valo continue; 423e705c121SKalle Valo 424e705c121SKalle Valo /* Send the requested PHY DB section */ 425e705c121SKalle Valo err = iwl_send_phy_db_cmd(phy_db, 426e705c121SKalle Valo type, 427e705c121SKalle Valo entry->size, 428e705c121SKalle Valo entry->data); 429e705c121SKalle Valo if (err) { 430e705c121SKalle Valo IWL_ERR(phy_db->trans, 431e705c121SKalle Valo "Can't SEND phy_db section %d (%d), err %d\n", 432e705c121SKalle Valo type, i, err); 433e705c121SKalle Valo return err; 434e705c121SKalle Valo } 435e705c121SKalle Valo 436e705c121SKalle Valo IWL_DEBUG_INFO(phy_db->trans, 437e705c121SKalle Valo "Sent PHY_DB HCMD, type = %d num = %d\n", 438e705c121SKalle Valo type, i); 439e705c121SKalle Valo } 440e705c121SKalle Valo 441e705c121SKalle Valo return 0; 442e705c121SKalle Valo } 443e705c121SKalle Valo 444e705c121SKalle Valo int iwl_send_phy_db_data(struct iwl_phy_db *phy_db) 445e705c121SKalle Valo { 446e705c121SKalle Valo u8 *data = NULL; 447e705c121SKalle Valo u16 size = 0; 448e705c121SKalle Valo int err; 449e705c121SKalle Valo 450e705c121SKalle Valo IWL_DEBUG_INFO(phy_db->trans, 451e705c121SKalle Valo "Sending phy db data and configuration to runtime image\n"); 452e705c121SKalle Valo 453e705c121SKalle Valo /* Send PHY DB CFG section */ 454e705c121SKalle Valo err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CFG, 455e705c121SKalle Valo &data, &size, 0); 456e705c121SKalle Valo if (err) { 457e705c121SKalle Valo IWL_ERR(phy_db->trans, "Cannot get Phy DB cfg section\n"); 458e705c121SKalle Valo return err; 459e705c121SKalle Valo } 460e705c121SKalle Valo 461e705c121SKalle Valo err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CFG, size, data); 462e705c121SKalle Valo if (err) { 463e705c121SKalle Valo IWL_ERR(phy_db->trans, 464e705c121SKalle Valo "Cannot send HCMD of Phy DB cfg section\n"); 465e705c121SKalle Valo return err; 466e705c121SKalle Valo } 467e705c121SKalle Valo 468e705c121SKalle Valo err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CALIB_NCH, 469e705c121SKalle Valo &data, &size, 0); 470e705c121SKalle Valo if (err) { 471e705c121SKalle Valo IWL_ERR(phy_db->trans, 472e705c121SKalle Valo "Cannot get Phy DB non specific channel section\n"); 473e705c121SKalle Valo return err; 474e705c121SKalle Valo } 475e705c121SKalle Valo 476e705c121SKalle Valo err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CALIB_NCH, size, data); 477e705c121SKalle Valo if (err) { 478e705c121SKalle Valo IWL_ERR(phy_db->trans, 479e705c121SKalle Valo "Cannot send HCMD of Phy DB non specific channel section\n"); 480e705c121SKalle Valo return err; 481e705c121SKalle Valo } 482e705c121SKalle Valo 483e705c121SKalle Valo /* Send all the TXP channel specific data */ 484e705c121SKalle Valo err = iwl_phy_db_send_all_channel_groups(phy_db, 485e705c121SKalle Valo IWL_PHY_DB_CALIB_CHG_PAPD, 4860ec84d1dSSara Sharon phy_db->n_group_papd); 487e705c121SKalle Valo if (err) { 488e705c121SKalle Valo IWL_ERR(phy_db->trans, 489e705c121SKalle Valo "Cannot send channel specific PAPD groups\n"); 490e705c121SKalle Valo return err; 491e705c121SKalle Valo } 492e705c121SKalle Valo 493e705c121SKalle Valo /* Send all the TXP channel specific data */ 494e705c121SKalle Valo err = iwl_phy_db_send_all_channel_groups(phy_db, 495e705c121SKalle Valo IWL_PHY_DB_CALIB_CHG_TXP, 4960ec84d1dSSara Sharon phy_db->n_group_txp); 497e705c121SKalle Valo if (err) { 498e705c121SKalle Valo IWL_ERR(phy_db->trans, 499e705c121SKalle Valo "Cannot send channel specific TX power groups\n"); 500e705c121SKalle Valo return err; 501e705c121SKalle Valo } 502e705c121SKalle Valo 503e705c121SKalle Valo IWL_DEBUG_INFO(phy_db->trans, 504e705c121SKalle Valo "Finished sending phy db non channel data\n"); 505e705c121SKalle Valo return 0; 506e705c121SKalle Valo } 507e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_send_phy_db_data); 508