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