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 114 115 /* for parsing of tx power channel group data that comes from the firmware*/ 116 struct iwl_phy_db_chg_txp { 117 __le32 space; 118 __le16 max_channel_idx; 119 } __packed; 120 121 struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans) 122 { 123 struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), 124 GFP_KERNEL); 125 126 if (!phy_db) 127 return phy_db; 128 129 phy_db->trans = trans; 130 131 phy_db->n_group_txp = -1; 132 phy_db->n_group_papd = -1; 133 134 /* TODO: add default values of the phy db. */ 135 return phy_db; 136 } 137 IWL_EXPORT_SYMBOL(iwl_phy_db_init); 138 139 /* 140 * get phy db section: returns a pointer to a phy db section specified by 141 * type and channel group id. 142 */ 143 static struct iwl_phy_db_entry * 144 iwl_phy_db_get_section(struct iwl_phy_db *phy_db, 145 enum iwl_phy_db_section_type type, 146 u16 chg_id) 147 { 148 if (!phy_db || type >= IWL_PHY_DB_MAX) 149 return NULL; 150 151 switch (type) { 152 case IWL_PHY_DB_CFG: 153 return &phy_db->cfg; 154 case IWL_PHY_DB_CALIB_NCH: 155 return &phy_db->calib_nch; 156 case IWL_PHY_DB_CALIB_CHG_PAPD: 157 if (chg_id >= phy_db->n_group_papd) 158 return NULL; 159 return &phy_db->calib_ch_group_papd[chg_id]; 160 case IWL_PHY_DB_CALIB_CHG_TXP: 161 if (chg_id >= phy_db->n_group_txp) 162 return NULL; 163 return &phy_db->calib_ch_group_txp[chg_id]; 164 default: 165 return NULL; 166 } 167 return NULL; 168 } 169 170 static void iwl_phy_db_free_section(struct iwl_phy_db *phy_db, 171 enum iwl_phy_db_section_type type, 172 u16 chg_id) 173 { 174 struct iwl_phy_db_entry *entry = 175 iwl_phy_db_get_section(phy_db, type, chg_id); 176 if (!entry) 177 return; 178 179 kfree(entry->data); 180 entry->data = NULL; 181 entry->size = 0; 182 } 183 184 void iwl_phy_db_free(struct iwl_phy_db *phy_db) 185 { 186 int i; 187 188 if (!phy_db) 189 return; 190 191 iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CFG, 0); 192 iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_NCH, 0); 193 194 for (i = 0; i < phy_db->n_group_papd; i++) 195 iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_PAPD, i); 196 kfree(phy_db->calib_ch_group_papd); 197 198 for (i = 0; i < phy_db->n_group_txp; i++) 199 iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_TXP, i); 200 kfree(phy_db->calib_ch_group_txp); 201 202 kfree(phy_db); 203 } 204 IWL_EXPORT_SYMBOL(iwl_phy_db_free); 205 206 int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, 207 struct iwl_rx_packet *pkt) 208 { 209 struct iwl_calib_res_notif_phy_db *phy_db_notif = 210 (struct iwl_calib_res_notif_phy_db *)pkt->data; 211 enum iwl_phy_db_section_type type = le16_to_cpu(phy_db_notif->type); 212 u16 size = le16_to_cpu(phy_db_notif->length); 213 struct iwl_phy_db_entry *entry; 214 u16 chg_id = 0; 215 216 if (!phy_db) 217 return -EINVAL; 218 219 if (type == IWL_PHY_DB_CALIB_CHG_PAPD) { 220 chg_id = le16_to_cpup((__le16 *)phy_db_notif->data); 221 if (phy_db && !phy_db->calib_ch_group_papd) { 222 /* 223 * Firmware sends the largest index first, so we can use 224 * it to know how much we should allocate. 225 */ 226 phy_db->calib_ch_group_papd = kcalloc(chg_id + 1, 227 sizeof(struct iwl_phy_db_entry), 228 GFP_ATOMIC); 229 if (!phy_db->calib_ch_group_papd) 230 return -ENOMEM; 231 phy_db->n_group_papd = chg_id + 1; 232 } 233 } else if (type == IWL_PHY_DB_CALIB_CHG_TXP) { 234 chg_id = le16_to_cpup((__le16 *)phy_db_notif->data); 235 if (phy_db && !phy_db->calib_ch_group_txp) { 236 /* 237 * Firmware sends the largest index first, so we can use 238 * it to know how much we should allocate. 239 */ 240 phy_db->calib_ch_group_txp = kcalloc(chg_id + 1, 241 sizeof(struct iwl_phy_db_entry), 242 GFP_ATOMIC); 243 if (!phy_db->calib_ch_group_txp) 244 return -ENOMEM; 245 phy_db->n_group_txp = chg_id + 1; 246 } 247 } 248 249 entry = iwl_phy_db_get_section(phy_db, type, chg_id); 250 if (!entry) 251 return -EINVAL; 252 253 kfree(entry->data); 254 entry->data = kmemdup(phy_db_notif->data, size, GFP_ATOMIC); 255 if (!entry->data) { 256 entry->size = 0; 257 return -ENOMEM; 258 } 259 260 entry->size = size; 261 262 IWL_DEBUG_INFO(phy_db->trans, 263 "%s(%d): [PHYDB]SET: Type %d , Size: %d\n", 264 __func__, __LINE__, type, size); 265 266 return 0; 267 } 268 IWL_EXPORT_SYMBOL(iwl_phy_db_set_section); 269 270 static int is_valid_channel(u16 ch_id) 271 { 272 if (ch_id <= 14 || 273 (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) || 274 (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) || 275 (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1)) 276 return 1; 277 return 0; 278 } 279 280 static u8 ch_id_to_ch_index(u16 ch_id) 281 { 282 if (WARN_ON(!is_valid_channel(ch_id))) 283 return 0xff; 284 285 if (ch_id <= 14) 286 return ch_id - 1; 287 if (ch_id <= 64) 288 return (ch_id + 20) / 4; 289 if (ch_id <= 140) 290 return (ch_id - 12) / 4; 291 return (ch_id - 13) / 4; 292 } 293 294 295 static u16 channel_id_to_papd(u16 ch_id) 296 { 297 if (WARN_ON(!is_valid_channel(ch_id))) 298 return 0xff; 299 300 if (1 <= ch_id && ch_id <= 14) 301 return 0; 302 if (36 <= ch_id && ch_id <= 64) 303 return 1; 304 if (100 <= ch_id && ch_id <= 140) 305 return 2; 306 return 3; 307 } 308 309 static u16 channel_id_to_txp(struct iwl_phy_db *phy_db, u16 ch_id) 310 { 311 struct iwl_phy_db_chg_txp *txp_chg; 312 int i; 313 u8 ch_index = ch_id_to_ch_index(ch_id); 314 if (ch_index == 0xff) 315 return 0xff; 316 317 for (i = 0; i < phy_db->n_group_txp; i++) { 318 txp_chg = (void *)phy_db->calib_ch_group_txp[i].data; 319 if (!txp_chg) 320 return 0xff; 321 /* 322 * Looking for the first channel group that its max channel is 323 * higher then wanted channel. 324 */ 325 if (le16_to_cpu(txp_chg->max_channel_idx) >= ch_index) 326 return i; 327 } 328 return 0xff; 329 } 330 static 331 int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db, 332 u32 type, u8 **data, u16 *size, u16 ch_id) 333 { 334 struct iwl_phy_db_entry *entry; 335 u16 ch_group_id = 0; 336 337 if (!phy_db) 338 return -EINVAL; 339 340 /* find wanted channel group */ 341 if (type == IWL_PHY_DB_CALIB_CHG_PAPD) 342 ch_group_id = channel_id_to_papd(ch_id); 343 else if (type == IWL_PHY_DB_CALIB_CHG_TXP) 344 ch_group_id = channel_id_to_txp(phy_db, ch_id); 345 346 entry = iwl_phy_db_get_section(phy_db, type, ch_group_id); 347 if (!entry) 348 return -EINVAL; 349 350 *data = entry->data; 351 *size = entry->size; 352 353 IWL_DEBUG_INFO(phy_db->trans, 354 "%s(%d): [PHYDB] GET: Type %d , Size: %d\n", 355 __func__, __LINE__, type, *size); 356 357 return 0; 358 } 359 360 static int iwl_send_phy_db_cmd(struct iwl_phy_db *phy_db, u16 type, 361 u16 length, void *data) 362 { 363 struct iwl_phy_db_cmd phy_db_cmd; 364 struct iwl_host_cmd cmd = { 365 .id = PHY_DB_CMD, 366 }; 367 368 IWL_DEBUG_INFO(phy_db->trans, 369 "Sending PHY-DB hcmd of type %d, of length %d\n", 370 type, length); 371 372 /* Set phy db cmd variables */ 373 phy_db_cmd.type = cpu_to_le16(type); 374 phy_db_cmd.length = cpu_to_le16(length); 375 376 /* Set hcmd variables */ 377 cmd.data[0] = &phy_db_cmd; 378 cmd.len[0] = sizeof(struct iwl_phy_db_cmd); 379 cmd.data[1] = data; 380 cmd.len[1] = length; 381 cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY; 382 383 return iwl_trans_send_cmd(phy_db->trans, &cmd); 384 } 385 386 static int iwl_phy_db_send_all_channel_groups( 387 struct iwl_phy_db *phy_db, 388 enum iwl_phy_db_section_type type, 389 u8 max_ch_groups) 390 { 391 u16 i; 392 int err; 393 struct iwl_phy_db_entry *entry; 394 395 /* Send all the channel specific groups to operational fw */ 396 for (i = 0; i < max_ch_groups; i++) { 397 entry = iwl_phy_db_get_section(phy_db, 398 type, 399 i); 400 if (!entry) 401 return -EINVAL; 402 403 if (!entry->size) 404 continue; 405 406 /* Send the requested PHY DB section */ 407 err = iwl_send_phy_db_cmd(phy_db, 408 type, 409 entry->size, 410 entry->data); 411 if (err) { 412 IWL_ERR(phy_db->trans, 413 "Can't SEND phy_db section %d (%d), err %d\n", 414 type, i, err); 415 return err; 416 } 417 418 IWL_DEBUG_INFO(phy_db->trans, 419 "Sent PHY_DB HCMD, type = %d num = %d\n", 420 type, i); 421 } 422 423 return 0; 424 } 425 426 int iwl_send_phy_db_data(struct iwl_phy_db *phy_db) 427 { 428 u8 *data = NULL; 429 u16 size = 0; 430 int err; 431 432 IWL_DEBUG_INFO(phy_db->trans, 433 "Sending phy db data and configuration to runtime image\n"); 434 435 /* Send PHY DB CFG section */ 436 err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CFG, 437 &data, &size, 0); 438 if (err) { 439 IWL_ERR(phy_db->trans, "Cannot get Phy DB cfg section\n"); 440 return err; 441 } 442 443 err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CFG, size, data); 444 if (err) { 445 IWL_ERR(phy_db->trans, 446 "Cannot send HCMD of Phy DB cfg section\n"); 447 return err; 448 } 449 450 err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CALIB_NCH, 451 &data, &size, 0); 452 if (err) { 453 IWL_ERR(phy_db->trans, 454 "Cannot get Phy DB non specific channel section\n"); 455 return err; 456 } 457 458 err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CALIB_NCH, size, data); 459 if (err) { 460 IWL_ERR(phy_db->trans, 461 "Cannot send HCMD of Phy DB non specific channel section\n"); 462 return err; 463 } 464 465 /* Send all the TXP channel specific data */ 466 err = iwl_phy_db_send_all_channel_groups(phy_db, 467 IWL_PHY_DB_CALIB_CHG_PAPD, 468 phy_db->n_group_papd); 469 if (err) { 470 IWL_ERR(phy_db->trans, 471 "Cannot send channel specific PAPD groups\n"); 472 return err; 473 } 474 475 /* Send all the TXP channel specific data */ 476 err = iwl_phy_db_send_all_channel_groups(phy_db, 477 IWL_PHY_DB_CALIB_CHG_TXP, 478 phy_db->n_group_txp); 479 if (err) { 480 IWL_ERR(phy_db->trans, 481 "Cannot send channel specific TX power groups\n"); 482 return err; 483 } 484 485 IWL_DEBUG_INFO(phy_db->trans, 486 "Finished sending phy db non channel data\n"); 487 return 0; 488 } 489 IWL_EXPORT_SYMBOL(iwl_send_phy_db_data); 490