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