18e99ea8dSJohannes Berg // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 28e99ea8dSJohannes Berg /* 3*86371b73SJohannes Berg * Copyright (C) 2005-2014, 2020-2021 Intel Corporation 48e99ea8dSJohannes Berg * Copyright (C) 2016 Intel Deutschland GmbH 58e99ea8dSJohannes Berg */ 6e705c121SKalle Valo #include <linux/slab.h> 7e705c121SKalle Valo #include <linux/string.h> 8e705c121SKalle Valo #include <linux/export.h> 9e705c121SKalle Valo 10e705c121SKalle Valo #include "iwl-drv.h" 11e705c121SKalle Valo #include "iwl-phy-db.h" 12e705c121SKalle Valo #include "iwl-debug.h" 13e705c121SKalle Valo #include "iwl-op-mode.h" 14e705c121SKalle Valo #include "iwl-trans.h" 15e705c121SKalle Valo 16e705c121SKalle Valo struct iwl_phy_db_entry { 17e705c121SKalle Valo u16 size; 18e705c121SKalle Valo u8 *data; 19e705c121SKalle Valo }; 20e705c121SKalle Valo 21e705c121SKalle Valo /** 22e705c121SKalle Valo * struct iwl_phy_db - stores phy configuration and calibration data. 23e705c121SKalle Valo * 24e705c121SKalle Valo * @cfg: phy configuration. 25e705c121SKalle Valo * @calib_nch: non channel specific calibration data. 260ec84d1dSSara Sharon * @n_group_papd: number of entries in papd channel group. 27e705c121SKalle Valo * @calib_ch_group_papd: calibration data related to papd channel group. 280ec84d1dSSara Sharon * @n_group_txp: number of entries in tx power channel group. 29e705c121SKalle Valo * @calib_ch_group_txp: calibration data related to tx power chanel group. 305a2e2f91SLee Jones * @trans: transport layer 31e705c121SKalle Valo */ 32e705c121SKalle Valo struct iwl_phy_db { 33e705c121SKalle Valo struct iwl_phy_db_entry cfg; 34e705c121SKalle Valo struct iwl_phy_db_entry calib_nch; 350ec84d1dSSara Sharon int n_group_papd; 360ec84d1dSSara Sharon struct iwl_phy_db_entry *calib_ch_group_papd; 370ec84d1dSSara Sharon int n_group_txp; 380ec84d1dSSara Sharon struct iwl_phy_db_entry *calib_ch_group_txp; 39e705c121SKalle Valo 40e705c121SKalle Valo struct iwl_trans *trans; 41e705c121SKalle Valo }; 42e705c121SKalle Valo 43e705c121SKalle Valo enum iwl_phy_db_section_type { 44e705c121SKalle Valo IWL_PHY_DB_CFG = 1, 45e705c121SKalle Valo IWL_PHY_DB_CALIB_NCH, 46e705c121SKalle Valo IWL_PHY_DB_UNUSED, 47e705c121SKalle Valo IWL_PHY_DB_CALIB_CHG_PAPD, 48e705c121SKalle Valo IWL_PHY_DB_CALIB_CHG_TXP, 49e705c121SKalle Valo IWL_PHY_DB_MAX 50e705c121SKalle Valo }; 51e705c121SKalle Valo 52176aa60bSSara Sharon #define PHY_DB_CMD 0x6c 53e705c121SKalle Valo 54e705c121SKalle Valo /* for parsing of tx power channel group data that comes from the firmware*/ 55e705c121SKalle Valo struct iwl_phy_db_chg_txp { 56e705c121SKalle Valo __le32 space; 57e705c121SKalle Valo __le16 max_channel_idx; 58e705c121SKalle Valo } __packed; 59e705c121SKalle Valo 60e705c121SKalle Valo struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans) 61e705c121SKalle Valo { 62e705c121SKalle Valo struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), 63e705c121SKalle Valo GFP_KERNEL); 64e705c121SKalle Valo 65e705c121SKalle Valo if (!phy_db) 66e705c121SKalle Valo return phy_db; 67e705c121SKalle Valo 68e705c121SKalle Valo phy_db->trans = trans; 69e705c121SKalle Valo 700ec84d1dSSara Sharon phy_db->n_group_txp = -1; 710ec84d1dSSara Sharon phy_db->n_group_papd = -1; 720ec84d1dSSara Sharon 73e705c121SKalle Valo /* TODO: add default values of the phy db. */ 74e705c121SKalle Valo return phy_db; 75e705c121SKalle Valo } 76e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_phy_db_init); 77e705c121SKalle Valo 78e705c121SKalle Valo /* 79e705c121SKalle Valo * get phy db section: returns a pointer to a phy db section specified by 80e705c121SKalle Valo * type and channel group id. 81e705c121SKalle Valo */ 82e705c121SKalle Valo static struct iwl_phy_db_entry * 83e705c121SKalle Valo iwl_phy_db_get_section(struct iwl_phy_db *phy_db, 84e705c121SKalle Valo enum iwl_phy_db_section_type type, 85e705c121SKalle Valo u16 chg_id) 86e705c121SKalle Valo { 87e705c121SKalle Valo if (!phy_db || type >= IWL_PHY_DB_MAX) 88e705c121SKalle Valo return NULL; 89e705c121SKalle Valo 90e705c121SKalle Valo switch (type) { 91e705c121SKalle Valo case IWL_PHY_DB_CFG: 92e705c121SKalle Valo return &phy_db->cfg; 93e705c121SKalle Valo case IWL_PHY_DB_CALIB_NCH: 94e705c121SKalle Valo return &phy_db->calib_nch; 95e705c121SKalle Valo case IWL_PHY_DB_CALIB_CHG_PAPD: 960ec84d1dSSara Sharon if (chg_id >= phy_db->n_group_papd) 97e705c121SKalle Valo return NULL; 98e705c121SKalle Valo return &phy_db->calib_ch_group_papd[chg_id]; 99e705c121SKalle Valo case IWL_PHY_DB_CALIB_CHG_TXP: 1000ec84d1dSSara Sharon if (chg_id >= phy_db->n_group_txp) 101e705c121SKalle Valo return NULL; 102e705c121SKalle Valo return &phy_db->calib_ch_group_txp[chg_id]; 103e705c121SKalle Valo default: 104e705c121SKalle Valo return NULL; 105e705c121SKalle Valo } 106e705c121SKalle Valo return NULL; 107e705c121SKalle Valo } 108e705c121SKalle Valo 109e705c121SKalle Valo static void iwl_phy_db_free_section(struct iwl_phy_db *phy_db, 110e705c121SKalle Valo enum iwl_phy_db_section_type type, 111e705c121SKalle Valo u16 chg_id) 112e705c121SKalle Valo { 113e705c121SKalle Valo struct iwl_phy_db_entry *entry = 114e705c121SKalle Valo iwl_phy_db_get_section(phy_db, type, chg_id); 115e705c121SKalle Valo if (!entry) 116e705c121SKalle Valo return; 117e705c121SKalle Valo 118e705c121SKalle Valo kfree(entry->data); 119e705c121SKalle Valo entry->data = NULL; 120e705c121SKalle Valo entry->size = 0; 121e705c121SKalle Valo } 122e705c121SKalle Valo 123e705c121SKalle Valo void iwl_phy_db_free(struct iwl_phy_db *phy_db) 124e705c121SKalle Valo { 125e705c121SKalle Valo int i; 126e705c121SKalle Valo 127e705c121SKalle Valo if (!phy_db) 128e705c121SKalle Valo return; 129e705c121SKalle Valo 130e705c121SKalle Valo iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CFG, 0); 131e705c121SKalle Valo iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_NCH, 0); 1320ec84d1dSSara Sharon 1330ec84d1dSSara Sharon for (i = 0; i < phy_db->n_group_papd; i++) 134e705c121SKalle Valo iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_PAPD, i); 1350ec84d1dSSara Sharon kfree(phy_db->calib_ch_group_papd); 1360ec84d1dSSara Sharon 1370ec84d1dSSara Sharon for (i = 0; i < phy_db->n_group_txp; i++) 138e705c121SKalle Valo iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_TXP, i); 1390ec84d1dSSara Sharon kfree(phy_db->calib_ch_group_txp); 140e705c121SKalle Valo 141e705c121SKalle Valo kfree(phy_db); 142e705c121SKalle Valo } 143e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_phy_db_free); 144e705c121SKalle Valo 145ce1f2778SSara Sharon int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, 146ce1f2778SSara Sharon struct iwl_rx_packet *pkt) 147e705c121SKalle Valo { 148fd1c3318SJohannes Berg unsigned int pkt_len = iwl_rx_packet_payload_len(pkt); 149e705c121SKalle Valo struct iwl_calib_res_notif_phy_db *phy_db_notif = 150e705c121SKalle Valo (struct iwl_calib_res_notif_phy_db *)pkt->data; 151fd1c3318SJohannes Berg enum iwl_phy_db_section_type type; 152fd1c3318SJohannes Berg u16 size; 153e705c121SKalle Valo struct iwl_phy_db_entry *entry; 154e705c121SKalle Valo u16 chg_id = 0; 155e705c121SKalle Valo 156fd1c3318SJohannes Berg if (pkt_len < sizeof(*phy_db_notif)) 157fd1c3318SJohannes Berg return -EINVAL; 158fd1c3318SJohannes Berg 159fd1c3318SJohannes Berg type = le16_to_cpu(phy_db_notif->type); 160fd1c3318SJohannes Berg size = le16_to_cpu(phy_db_notif->length); 161fd1c3318SJohannes Berg 162fd1c3318SJohannes Berg if (pkt_len < sizeof(*phy_db_notif) + size) 163fd1c3318SJohannes Berg return -EINVAL; 164fd1c3318SJohannes Berg 165e705c121SKalle Valo if (!phy_db) 166e705c121SKalle Valo return -EINVAL; 167e705c121SKalle Valo 1680ec84d1dSSara Sharon if (type == IWL_PHY_DB_CALIB_CHG_PAPD) { 169e705c121SKalle Valo chg_id = le16_to_cpup((__le16 *)phy_db_notif->data); 1700ec84d1dSSara Sharon if (phy_db && !phy_db->calib_ch_group_papd) { 1710ec84d1dSSara Sharon /* 1720ec84d1dSSara Sharon * Firmware sends the largest index first, so we can use 1730ec84d1dSSara Sharon * it to know how much we should allocate. 1740ec84d1dSSara Sharon */ 1750ec84d1dSSara Sharon phy_db->calib_ch_group_papd = kcalloc(chg_id + 1, 1760ec84d1dSSara Sharon sizeof(struct iwl_phy_db_entry), 1770ec84d1dSSara Sharon GFP_ATOMIC); 1780ec84d1dSSara Sharon if (!phy_db->calib_ch_group_papd) 1790ec84d1dSSara Sharon return -ENOMEM; 1800ec84d1dSSara Sharon phy_db->n_group_papd = chg_id + 1; 1810ec84d1dSSara Sharon } 1820ec84d1dSSara Sharon } else if (type == IWL_PHY_DB_CALIB_CHG_TXP) { 1830ec84d1dSSara Sharon chg_id = le16_to_cpup((__le16 *)phy_db_notif->data); 1840ec84d1dSSara Sharon if (phy_db && !phy_db->calib_ch_group_txp) { 1850ec84d1dSSara Sharon /* 1860ec84d1dSSara Sharon * Firmware sends the largest index first, so we can use 1870ec84d1dSSara Sharon * it to know how much we should allocate. 1880ec84d1dSSara Sharon */ 1890ec84d1dSSara Sharon phy_db->calib_ch_group_txp = kcalloc(chg_id + 1, 1900ec84d1dSSara Sharon sizeof(struct iwl_phy_db_entry), 1910ec84d1dSSara Sharon GFP_ATOMIC); 1920ec84d1dSSara Sharon if (!phy_db->calib_ch_group_txp) 1930ec84d1dSSara Sharon return -ENOMEM; 1940ec84d1dSSara Sharon phy_db->n_group_txp = chg_id + 1; 1950ec84d1dSSara Sharon } 1960ec84d1dSSara Sharon } 197e705c121SKalle Valo 198e705c121SKalle Valo entry = iwl_phy_db_get_section(phy_db, type, chg_id); 199e705c121SKalle Valo if (!entry) 200e705c121SKalle Valo return -EINVAL; 201e705c121SKalle Valo 202e705c121SKalle Valo kfree(entry->data); 203ce1f2778SSara Sharon entry->data = kmemdup(phy_db_notif->data, size, GFP_ATOMIC); 204e705c121SKalle Valo if (!entry->data) { 205e705c121SKalle Valo entry->size = 0; 206e705c121SKalle Valo return -ENOMEM; 207e705c121SKalle Valo } 208e705c121SKalle Valo 209e705c121SKalle Valo entry->size = size; 210e705c121SKalle Valo 211e705c121SKalle Valo IWL_DEBUG_INFO(phy_db->trans, 212e705c121SKalle Valo "%s(%d): [PHYDB]SET: Type %d , Size: %d\n", 213e705c121SKalle Valo __func__, __LINE__, type, size); 214e705c121SKalle Valo 215e705c121SKalle Valo return 0; 216e705c121SKalle Valo } 217e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_phy_db_set_section); 218e705c121SKalle Valo 219e705c121SKalle Valo static int is_valid_channel(u16 ch_id) 220e705c121SKalle Valo { 221e705c121SKalle Valo if (ch_id <= 14 || 222e705c121SKalle Valo (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) || 223e705c121SKalle Valo (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) || 224e705c121SKalle Valo (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1)) 225e705c121SKalle Valo return 1; 226e705c121SKalle Valo return 0; 227e705c121SKalle Valo } 228e705c121SKalle Valo 229e705c121SKalle Valo static u8 ch_id_to_ch_index(u16 ch_id) 230e705c121SKalle Valo { 231e705c121SKalle Valo if (WARN_ON(!is_valid_channel(ch_id))) 232e705c121SKalle Valo return 0xff; 233e705c121SKalle Valo 234e705c121SKalle Valo if (ch_id <= 14) 235e705c121SKalle Valo return ch_id - 1; 236e705c121SKalle Valo if (ch_id <= 64) 237e705c121SKalle Valo return (ch_id + 20) / 4; 238e705c121SKalle Valo if (ch_id <= 140) 239e705c121SKalle Valo return (ch_id - 12) / 4; 240e705c121SKalle Valo return (ch_id - 13) / 4; 241e705c121SKalle Valo } 242e705c121SKalle Valo 243e705c121SKalle Valo 244e705c121SKalle Valo static u16 channel_id_to_papd(u16 ch_id) 245e705c121SKalle Valo { 246e705c121SKalle Valo if (WARN_ON(!is_valid_channel(ch_id))) 247e705c121SKalle Valo return 0xff; 248e705c121SKalle Valo 249e705c121SKalle Valo if (1 <= ch_id && ch_id <= 14) 250e705c121SKalle Valo return 0; 251e705c121SKalle Valo if (36 <= ch_id && ch_id <= 64) 252e705c121SKalle Valo return 1; 253e705c121SKalle Valo if (100 <= ch_id && ch_id <= 140) 254e705c121SKalle Valo return 2; 255e705c121SKalle Valo return 3; 256e705c121SKalle Valo } 257e705c121SKalle Valo 258e705c121SKalle Valo static u16 channel_id_to_txp(struct iwl_phy_db *phy_db, u16 ch_id) 259e705c121SKalle Valo { 260e705c121SKalle Valo struct iwl_phy_db_chg_txp *txp_chg; 261e705c121SKalle Valo int i; 262e705c121SKalle Valo u8 ch_index = ch_id_to_ch_index(ch_id); 263e705c121SKalle Valo if (ch_index == 0xff) 264e705c121SKalle Valo return 0xff; 265e705c121SKalle Valo 2660ec84d1dSSara Sharon for (i = 0; i < phy_db->n_group_txp; i++) { 267e705c121SKalle Valo txp_chg = (void *)phy_db->calib_ch_group_txp[i].data; 268e705c121SKalle Valo if (!txp_chg) 269e705c121SKalle Valo return 0xff; 270e705c121SKalle Valo /* 271e705c121SKalle Valo * Looking for the first channel group that its max channel is 272e705c121SKalle Valo * higher then wanted channel. 273e705c121SKalle Valo */ 274e705c121SKalle Valo if (le16_to_cpu(txp_chg->max_channel_idx) >= ch_index) 275e705c121SKalle Valo return i; 276e705c121SKalle Valo } 277e705c121SKalle Valo return 0xff; 278e705c121SKalle Valo } 279e705c121SKalle Valo static 280e705c121SKalle Valo int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db, 281e705c121SKalle Valo u32 type, u8 **data, u16 *size, u16 ch_id) 282e705c121SKalle Valo { 283e705c121SKalle Valo struct iwl_phy_db_entry *entry; 284e705c121SKalle Valo u16 ch_group_id = 0; 285e705c121SKalle Valo 286e705c121SKalle Valo if (!phy_db) 287e705c121SKalle Valo return -EINVAL; 288e705c121SKalle Valo 289e705c121SKalle Valo /* find wanted channel group */ 290e705c121SKalle Valo if (type == IWL_PHY_DB_CALIB_CHG_PAPD) 291e705c121SKalle Valo ch_group_id = channel_id_to_papd(ch_id); 292e705c121SKalle Valo else if (type == IWL_PHY_DB_CALIB_CHG_TXP) 293e705c121SKalle Valo ch_group_id = channel_id_to_txp(phy_db, ch_id); 294e705c121SKalle Valo 295e705c121SKalle Valo entry = iwl_phy_db_get_section(phy_db, type, ch_group_id); 296e705c121SKalle Valo if (!entry) 297e705c121SKalle Valo return -EINVAL; 298e705c121SKalle Valo 299e705c121SKalle Valo *data = entry->data; 300e705c121SKalle Valo *size = entry->size; 301e705c121SKalle Valo 302e705c121SKalle Valo IWL_DEBUG_INFO(phy_db->trans, 303e705c121SKalle Valo "%s(%d): [PHYDB] GET: Type %d , Size: %d\n", 304e705c121SKalle Valo __func__, __LINE__, type, *size); 305e705c121SKalle Valo 306e705c121SKalle Valo return 0; 307e705c121SKalle Valo } 308e705c121SKalle Valo 309e705c121SKalle Valo static int iwl_send_phy_db_cmd(struct iwl_phy_db *phy_db, u16 type, 310e705c121SKalle Valo u16 length, void *data) 311e705c121SKalle Valo { 312e705c121SKalle Valo struct iwl_phy_db_cmd phy_db_cmd; 313e705c121SKalle Valo struct iwl_host_cmd cmd = { 314e705c121SKalle Valo .id = PHY_DB_CMD, 315e705c121SKalle Valo }; 316e705c121SKalle Valo 317e705c121SKalle Valo IWL_DEBUG_INFO(phy_db->trans, 318e705c121SKalle Valo "Sending PHY-DB hcmd of type %d, of length %d\n", 319e705c121SKalle Valo type, length); 320e705c121SKalle Valo 321e705c121SKalle Valo /* Set phy db cmd variables */ 322e705c121SKalle Valo phy_db_cmd.type = cpu_to_le16(type); 323e705c121SKalle Valo phy_db_cmd.length = cpu_to_le16(length); 324e705c121SKalle Valo 325e705c121SKalle Valo /* Set hcmd variables */ 326e705c121SKalle Valo cmd.data[0] = &phy_db_cmd; 327e705c121SKalle Valo cmd.len[0] = sizeof(struct iwl_phy_db_cmd); 328e705c121SKalle Valo cmd.data[1] = data; 329e705c121SKalle Valo cmd.len[1] = length; 330e705c121SKalle Valo cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY; 331e705c121SKalle Valo 332e705c121SKalle Valo return iwl_trans_send_cmd(phy_db->trans, &cmd); 333e705c121SKalle Valo } 334e705c121SKalle Valo 335e705c121SKalle Valo static int iwl_phy_db_send_all_channel_groups( 336e705c121SKalle Valo struct iwl_phy_db *phy_db, 337e705c121SKalle Valo enum iwl_phy_db_section_type type, 338e705c121SKalle Valo u8 max_ch_groups) 339e705c121SKalle Valo { 340e705c121SKalle Valo u16 i; 341e705c121SKalle Valo int err; 342e705c121SKalle Valo struct iwl_phy_db_entry *entry; 343e705c121SKalle Valo 344e705c121SKalle Valo /* Send all the channel specific groups to operational fw */ 345e705c121SKalle Valo for (i = 0; i < max_ch_groups; i++) { 346e705c121SKalle Valo entry = iwl_phy_db_get_section(phy_db, 347e705c121SKalle Valo type, 348e705c121SKalle Valo i); 349e705c121SKalle Valo if (!entry) 350e705c121SKalle Valo return -EINVAL; 351e705c121SKalle Valo 352e705c121SKalle Valo if (!entry->size) 353e705c121SKalle Valo continue; 354e705c121SKalle Valo 355e705c121SKalle Valo /* Send the requested PHY DB section */ 356e705c121SKalle Valo err = iwl_send_phy_db_cmd(phy_db, 357e705c121SKalle Valo type, 358e705c121SKalle Valo entry->size, 359e705c121SKalle Valo entry->data); 360e705c121SKalle Valo if (err) { 361e705c121SKalle Valo IWL_ERR(phy_db->trans, 362e705c121SKalle Valo "Can't SEND phy_db section %d (%d), err %d\n", 363e705c121SKalle Valo type, i, err); 364e705c121SKalle Valo return err; 365e705c121SKalle Valo } 366e705c121SKalle Valo 367e705c121SKalle Valo IWL_DEBUG_INFO(phy_db->trans, 368e705c121SKalle Valo "Sent PHY_DB HCMD, type = %d num = %d\n", 369e705c121SKalle Valo type, i); 370e705c121SKalle Valo } 371e705c121SKalle Valo 372e705c121SKalle Valo return 0; 373e705c121SKalle Valo } 374e705c121SKalle Valo 375e705c121SKalle Valo int iwl_send_phy_db_data(struct iwl_phy_db *phy_db) 376e705c121SKalle Valo { 377e705c121SKalle Valo u8 *data = NULL; 378e705c121SKalle Valo u16 size = 0; 379e705c121SKalle Valo int err; 380e705c121SKalle Valo 381e705c121SKalle Valo IWL_DEBUG_INFO(phy_db->trans, 382e705c121SKalle Valo "Sending phy db data and configuration to runtime image\n"); 383e705c121SKalle Valo 384e705c121SKalle Valo /* Send PHY DB CFG section */ 385e705c121SKalle Valo err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CFG, 386e705c121SKalle Valo &data, &size, 0); 387e705c121SKalle Valo if (err) { 388e705c121SKalle Valo IWL_ERR(phy_db->trans, "Cannot get Phy DB cfg section\n"); 389e705c121SKalle Valo return err; 390e705c121SKalle Valo } 391e705c121SKalle Valo 392e705c121SKalle Valo err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CFG, size, data); 393e705c121SKalle Valo if (err) { 394e705c121SKalle Valo IWL_ERR(phy_db->trans, 395e705c121SKalle Valo "Cannot send HCMD of Phy DB cfg section\n"); 396e705c121SKalle Valo return err; 397e705c121SKalle Valo } 398e705c121SKalle Valo 399e705c121SKalle Valo err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CALIB_NCH, 400e705c121SKalle Valo &data, &size, 0); 401e705c121SKalle Valo if (err) { 402e705c121SKalle Valo IWL_ERR(phy_db->trans, 403e705c121SKalle Valo "Cannot get Phy DB non specific channel section\n"); 404e705c121SKalle Valo return err; 405e705c121SKalle Valo } 406e705c121SKalle Valo 407e705c121SKalle Valo err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CALIB_NCH, size, data); 408e705c121SKalle Valo if (err) { 409e705c121SKalle Valo IWL_ERR(phy_db->trans, 410e705c121SKalle Valo "Cannot send HCMD of Phy DB non specific channel section\n"); 411e705c121SKalle Valo return err; 412e705c121SKalle Valo } 413e705c121SKalle Valo 414e705c121SKalle Valo /* Send all the TXP channel specific data */ 415e705c121SKalle Valo err = iwl_phy_db_send_all_channel_groups(phy_db, 416e705c121SKalle Valo IWL_PHY_DB_CALIB_CHG_PAPD, 4170ec84d1dSSara Sharon phy_db->n_group_papd); 418e705c121SKalle Valo if (err) { 419e705c121SKalle Valo IWL_ERR(phy_db->trans, 420e705c121SKalle Valo "Cannot send channel specific PAPD groups\n"); 421e705c121SKalle Valo return err; 422e705c121SKalle Valo } 423e705c121SKalle Valo 424e705c121SKalle Valo /* Send all the TXP channel specific data */ 425e705c121SKalle Valo err = iwl_phy_db_send_all_channel_groups(phy_db, 426e705c121SKalle Valo IWL_PHY_DB_CALIB_CHG_TXP, 4270ec84d1dSSara Sharon phy_db->n_group_txp); 428e705c121SKalle Valo if (err) { 429e705c121SKalle Valo IWL_ERR(phy_db->trans, 430e705c121SKalle Valo "Cannot send channel specific TX power groups\n"); 431e705c121SKalle Valo return err; 432e705c121SKalle Valo } 433e705c121SKalle Valo 434e705c121SKalle Valo IWL_DEBUG_INFO(phy_db->trans, 435e705c121SKalle Valo "Finished sending phy db non channel data\n"); 436e705c121SKalle Valo return 0; 437e705c121SKalle Valo } 438e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_send_phy_db_data); 439