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