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