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