diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/wireless/iwlwifi/iwl-eeprom.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-eeprom.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-eeprom.c | 153 |
1 files changed, 111 insertions, 42 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index e14c9952a935..fb5bb487f3bc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 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 | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -63,6 +63,7 @@ | |||
63 | 63 | ||
64 | #include <linux/kernel.h> | 64 | #include <linux/kernel.h> |
65 | #include <linux/module.h> | 65 | #include <linux/module.h> |
66 | #include <linux/slab.h> | ||
66 | #include <linux/init.h> | 67 | #include <linux/init.h> |
67 | 68 | ||
68 | #include <net/mac80211.h> | 69 | #include <net/mac80211.h> |
@@ -215,12 +216,35 @@ static const struct iwl_txpwr_section enhinfo[] = { | |||
215 | 216 | ||
216 | int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) | 217 | int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) |
217 | { | 218 | { |
218 | u32 gp = iwl_read32(priv, CSR_EEPROM_GP); | 219 | u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; |
219 | if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { | 220 | int ret = 0; |
220 | IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); | 221 | |
221 | return -ENOENT; | 222 | IWL_DEBUG_INFO(priv, "EEPROM signature=0x%08x\n", gp); |
223 | switch (gp) { | ||
224 | case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP: | ||
225 | if (priv->nvm_device_type != NVM_DEVICE_TYPE_OTP) { | ||
226 | IWL_ERR(priv, "EEPROM with bad signature: 0x%08x\n", | ||
227 | gp); | ||
228 | ret = -ENOENT; | ||
229 | } | ||
230 | break; | ||
231 | case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K: | ||
232 | case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K: | ||
233 | if (priv->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) { | ||
234 | IWL_ERR(priv, "OTP with bad signature: 0x%08x\n", gp); | ||
235 | ret = -ENOENT; | ||
236 | } | ||
237 | break; | ||
238 | case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP: | ||
239 | default: | ||
240 | IWL_ERR(priv, "bad EEPROM/OTP signature, type=%s, " | ||
241 | "EEPROM_GP=0x%08x\n", | ||
242 | (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) | ||
243 | ? "OTP" : "EEPROM", gp); | ||
244 | ret = -ENOENT; | ||
245 | break; | ||
222 | } | 246 | } |
223 | return 0; | 247 | return ret; |
224 | } | 248 | } |
225 | EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); | 249 | EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); |
226 | 250 | ||
@@ -283,7 +307,8 @@ int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) | |||
283 | CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); | 307 | CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); |
284 | 308 | ||
285 | /* See if we got it */ | 309 | /* See if we got it */ |
286 | ret = iwl_poll_direct_bit(priv, CSR_HW_IF_CONFIG_REG, | 310 | ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, |
311 | CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, | ||
287 | CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, | 312 | CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, |
288 | EEPROM_SEM_TIMEOUT); | 313 | EEPROM_SEM_TIMEOUT); |
289 | if (ret >= 0) { | 314 | if (ret >= 0) { |
@@ -322,7 +347,8 @@ static int iwl_init_otp_access(struct iwl_priv *priv) | |||
322 | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | 347 | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); |
323 | 348 | ||
324 | /* wait for clock to be ready */ | 349 | /* wait for clock to be ready */ |
325 | ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, | 350 | ret = iwl_poll_bit(priv, CSR_GP_CNTRL, |
351 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | ||
326 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | 352 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, |
327 | 25000); | 353 | 25000); |
328 | if (ret < 0) | 354 | if (ret < 0) |
@@ -333,11 +359,19 @@ static int iwl_init_otp_access(struct iwl_priv *priv) | |||
333 | udelay(5); | 359 | udelay(5); |
334 | iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, | 360 | iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, |
335 | APMG_PS_CTRL_VAL_RESET_REQ); | 361 | APMG_PS_CTRL_VAL_RESET_REQ); |
362 | |||
363 | /* | ||
364 | * CSR auto clock gate disable bit - | ||
365 | * this is only applicable for HW with OTP shadow RAM | ||
366 | */ | ||
367 | if (priv->cfg->shadow_ram_support) | ||
368 | iwl_set_bit(priv, CSR_DBG_LINK_PWR_MGMT_REG, | ||
369 | CSR_RESET_LINK_PWR_MGMT_DISABLED); | ||
336 | } | 370 | } |
337 | return ret; | 371 | return ret; |
338 | } | 372 | } |
339 | 373 | ||
340 | static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) | 374 | static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_data) |
341 | { | 375 | { |
342 | int ret = 0; | 376 | int ret = 0; |
343 | u32 r; | 377 | u32 r; |
@@ -345,7 +379,8 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) | |||
345 | 379 | ||
346 | _iwl_write32(priv, CSR_EEPROM_REG, | 380 | _iwl_write32(priv, CSR_EEPROM_REG, |
347 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); | 381 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); |
348 | ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, | 382 | ret = iwl_poll_bit(priv, CSR_EEPROM_REG, |
383 | CSR_EEPROM_REG_READ_VALID_MSK, | ||
349 | CSR_EEPROM_REG_READ_VALID_MSK, | 384 | CSR_EEPROM_REG_READ_VALID_MSK, |
350 | IWL_EEPROM_ACCESS_TIMEOUT); | 385 | IWL_EEPROM_ACCESS_TIMEOUT); |
351 | if (ret < 0) { | 386 | if (ret < 0) { |
@@ -370,7 +405,7 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) | |||
370 | CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); | 405 | CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); |
371 | IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); | 406 | IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); |
372 | } | 407 | } |
373 | *eeprom_data = le16_to_cpu((__force __le16)(r >> 16)); | 408 | *eeprom_data = cpu_to_le16(r >> 16); |
374 | return 0; | 409 | return 0; |
375 | } | 410 | } |
376 | 411 | ||
@@ -379,7 +414,8 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) | |||
379 | */ | 414 | */ |
380 | static bool iwl_is_otp_empty(struct iwl_priv *priv) | 415 | static bool iwl_is_otp_empty(struct iwl_priv *priv) |
381 | { | 416 | { |
382 | u16 next_link_addr = 0, link_value; | 417 | u16 next_link_addr = 0; |
418 | __le16 link_value; | ||
383 | bool is_empty = false; | 419 | bool is_empty = false; |
384 | 420 | ||
385 | /* locate the beginning of OTP link list */ | 421 | /* locate the beginning of OTP link list */ |
@@ -409,7 +445,8 @@ static bool iwl_is_otp_empty(struct iwl_priv *priv) | |||
409 | static int iwl_find_otp_image(struct iwl_priv *priv, | 445 | static int iwl_find_otp_image(struct iwl_priv *priv, |
410 | u16 *validblockaddr) | 446 | u16 *validblockaddr) |
411 | { | 447 | { |
412 | u16 next_link_addr = 0, link_value = 0, valid_addr; | 448 | u16 next_link_addr = 0, valid_addr; |
449 | __le16 link_value = 0; | ||
413 | int usedblocks = 0; | 450 | int usedblocks = 0; |
414 | 451 | ||
415 | /* set addressing mode to absolute to traverse the link list */ | 452 | /* set addressing mode to absolute to traverse the link list */ |
@@ -429,7 +466,7 @@ static int iwl_find_otp_image(struct iwl_priv *priv, | |||
429 | * check for more block on the link list | 466 | * check for more block on the link list |
430 | */ | 467 | */ |
431 | valid_addr = next_link_addr; | 468 | valid_addr = next_link_addr; |
432 | next_link_addr = link_value * sizeof(u16); | 469 | next_link_addr = le16_to_cpu(link_value) * sizeof(u16); |
433 | IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n", | 470 | IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n", |
434 | usedblocks, next_link_addr); | 471 | usedblocks, next_link_addr); |
435 | if (iwl_read_otp_word(priv, next_link_addr, &link_value)) | 472 | if (iwl_read_otp_word(priv, next_link_addr, &link_value)) |
@@ -463,7 +500,7 @@ static int iwl_find_otp_image(struct iwl_priv *priv, | |||
463 | */ | 500 | */ |
464 | int iwl_eeprom_init(struct iwl_priv *priv) | 501 | int iwl_eeprom_init(struct iwl_priv *priv) |
465 | { | 502 | { |
466 | u16 *e; | 503 | __le16 *e; |
467 | u32 gp = iwl_read32(priv, CSR_EEPROM_GP); | 504 | u32 gp = iwl_read32(priv, CSR_EEPROM_GP); |
468 | int sz; | 505 | int sz; |
469 | int ret; | 506 | int ret; |
@@ -482,7 +519,9 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
482 | ret = -ENOMEM; | 519 | ret = -ENOMEM; |
483 | goto alloc_err; | 520 | goto alloc_err; |
484 | } | 521 | } |
485 | e = (u16 *)priv->eeprom; | 522 | e = (__le16 *)priv->eeprom; |
523 | |||
524 | priv->cfg->ops->lib->apm_ops.init(priv); | ||
486 | 525 | ||
487 | ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv); | 526 | ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv); |
488 | if (ret < 0) { | 527 | if (ret < 0) { |
@@ -498,7 +537,9 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
498 | ret = -ENOENT; | 537 | ret = -ENOENT; |
499 | goto err; | 538 | goto err; |
500 | } | 539 | } |
540 | |||
501 | if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { | 541 | if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { |
542 | |||
502 | ret = iwl_init_otp_access(priv); | 543 | ret = iwl_init_otp_access(priv); |
503 | if (ret) { | 544 | if (ret) { |
504 | IWL_ERR(priv, "Failed to initialize OTP access.\n"); | 545 | IWL_ERR(priv, "Failed to initialize OTP access.\n"); |
@@ -521,7 +562,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
521 | } | 562 | } |
522 | for (addr = validblockaddr; addr < validblockaddr + sz; | 563 | for (addr = validblockaddr; addr < validblockaddr + sz; |
523 | addr += sizeof(u16)) { | 564 | addr += sizeof(u16)) { |
524 | u16 eeprom_data; | 565 | __le16 eeprom_data; |
525 | 566 | ||
526 | ret = iwl_read_otp_word(priv, addr, &eeprom_data); | 567 | ret = iwl_read_otp_word(priv, addr, &eeprom_data); |
527 | if (ret) | 568 | if (ret) |
@@ -537,7 +578,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
537 | _iwl_write32(priv, CSR_EEPROM_REG, | 578 | _iwl_write32(priv, CSR_EEPROM_REG, |
538 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); | 579 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); |
539 | 580 | ||
540 | ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, | 581 | ret = iwl_poll_bit(priv, CSR_EEPROM_REG, |
582 | CSR_EEPROM_REG_READ_VALID_MSK, | ||
541 | CSR_EEPROM_REG_READ_VALID_MSK, | 583 | CSR_EEPROM_REG_READ_VALID_MSK, |
542 | IWL_EEPROM_ACCESS_TIMEOUT); | 584 | IWL_EEPROM_ACCESS_TIMEOUT); |
543 | if (ret < 0) { | 585 | if (ret < 0) { |
@@ -545,7 +587,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
545 | goto done; | 587 | goto done; |
546 | } | 588 | } |
547 | r = _iwl_read_direct32(priv, CSR_EEPROM_REG); | 589 | r = _iwl_read_direct32(priv, CSR_EEPROM_REG); |
548 | e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); | 590 | e[addr / 2] = cpu_to_le16(r >> 16); |
549 | } | 591 | } |
550 | } | 592 | } |
551 | ret = 0; | 593 | ret = 0; |
@@ -554,6 +596,8 @@ done: | |||
554 | err: | 596 | err: |
555 | if (ret) | 597 | if (ret) |
556 | iwl_eeprom_free(priv); | 598 | iwl_eeprom_free(priv); |
599 | /* Reset chip to save power until we load uCode during "up". */ | ||
600 | priv->cfg->ops->lib->apm_ops.stop(priv); | ||
557 | alloc_err: | 601 | alloc_err: |
558 | return ret; | 602 | return ret; |
559 | } | 603 | } |
@@ -705,11 +749,9 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, | |||
705 | 749 | ||
706 | ch_info->ht40_eeprom = *eeprom_ch; | 750 | ch_info->ht40_eeprom = *eeprom_ch; |
707 | ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg; | 751 | ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg; |
708 | ch_info->ht40_curr_txpow = eeprom_ch->max_power_avg; | ||
709 | ch_info->ht40_min_power = 0; | ||
710 | ch_info->ht40_scan_power = eeprom_ch->max_power_avg; | ||
711 | ch_info->ht40_flags = eeprom_ch->flags; | 752 | ch_info->ht40_flags = eeprom_ch->flags; |
712 | ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel; | 753 | if (eeprom_ch->flags & EEPROM_CHANNEL_VALID) |
754 | ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel; | ||
713 | 755 | ||
714 | return 0; | 756 | return 0; |
715 | } | 757 | } |
@@ -719,7 +761,8 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, | |||
719 | * find the highest tx power from all chains for the channel | 761 | * find the highest tx power from all chains for the channel |
720 | */ | 762 | */ |
721 | static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, | 763 | static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, |
722 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element) | 764 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, |
765 | int element, s8 *max_txpower_in_half_dbm) | ||
723 | { | 766 | { |
724 | s8 max_txpower_avg = 0; /* (dBm) */ | 767 | s8 max_txpower_avg = 0; /* (dBm) */ |
725 | 768 | ||
@@ -751,10 +794,14 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, | |||
751 | (enhanced_txpower[element].mimo3_max > max_txpower_avg)) | 794 | (enhanced_txpower[element].mimo3_max > max_txpower_avg)) |
752 | max_txpower_avg = enhanced_txpower[element].mimo3_max; | 795 | max_txpower_avg = enhanced_txpower[element].mimo3_max; |
753 | 796 | ||
754 | /* max. tx power in EEPROM is in 1/2 dBm format | 797 | /* |
755 | * convert from 1/2 dBm to dBm | 798 | * max. tx power in EEPROM is in 1/2 dBm format |
799 | * convert from 1/2 dBm to dBm (round-up convert) | ||
800 | * but we also do not want to loss 1/2 dBm resolution which | ||
801 | * will impact performance | ||
756 | */ | 802 | */ |
757 | return max_txpower_avg >> 1; | 803 | *max_txpower_in_half_dbm = max_txpower_avg; |
804 | return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1); | ||
758 | } | 805 | } |
759 | 806 | ||
760 | /** | 807 | /** |
@@ -763,7 +810,7 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, | |||
763 | */ | 810 | */ |
764 | static s8 iwl_update_common_txpower(struct iwl_priv *priv, | 811 | static s8 iwl_update_common_txpower(struct iwl_priv *priv, |
765 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, | 812 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, |
766 | int section, int element) | 813 | int section, int element, s8 *max_txpower_in_half_dbm) |
767 | { | 814 | { |
768 | struct iwl_channel_info *ch_info; | 815 | struct iwl_channel_info *ch_info; |
769 | int ch; | 816 | int ch; |
@@ -777,25 +824,25 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv, | |||
777 | if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX) | 824 | if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX) |
778 | is_ht40 = true; | 825 | is_ht40 = true; |
779 | max_txpower_avg = | 826 | max_txpower_avg = |
780 | iwl_get_max_txpower_avg(priv, enhanced_txpower, element); | 827 | iwl_get_max_txpower_avg(priv, enhanced_txpower, |
828 | element, max_txpower_in_half_dbm); | ||
829 | |||
781 | ch_info = priv->channel_info; | 830 | ch_info = priv->channel_info; |
782 | 831 | ||
783 | for (ch = 0; ch < priv->channel_count; ch++) { | 832 | for (ch = 0; ch < priv->channel_count; ch++) { |
784 | /* find matching band and update tx power if needed */ | 833 | /* find matching band and update tx power if needed */ |
785 | if ((ch_info->band == enhinfo[section].band) && | 834 | if ((ch_info->band == enhinfo[section].band) && |
786 | (ch_info->max_power_avg < max_txpower_avg) && (!is_ht40)) { | 835 | (ch_info->max_power_avg < max_txpower_avg) && |
836 | (!is_ht40)) { | ||
787 | /* Update regulatory-based run-time data */ | 837 | /* Update regulatory-based run-time data */ |
788 | ch_info->max_power_avg = ch_info->curr_txpow = | 838 | ch_info->max_power_avg = ch_info->curr_txpow = |
789 | max_txpower_avg; | 839 | max_txpower_avg; |
790 | ch_info->scan_power = max_txpower_avg; | 840 | ch_info->scan_power = max_txpower_avg; |
791 | } | 841 | } |
792 | if ((ch_info->band == enhinfo[section].band) && is_ht40 && | 842 | if ((ch_info->band == enhinfo[section].band) && is_ht40 && |
793 | ch_info->ht40_max_power_avg && | ||
794 | (ch_info->ht40_max_power_avg < max_txpower_avg)) { | 843 | (ch_info->ht40_max_power_avg < max_txpower_avg)) { |
795 | /* Update regulatory-based run-time data */ | 844 | /* Update regulatory-based run-time data */ |
796 | ch_info->ht40_max_power_avg = max_txpower_avg; | 845 | ch_info->ht40_max_power_avg = max_txpower_avg; |
797 | ch_info->ht40_curr_txpow = max_txpower_avg; | ||
798 | ch_info->ht40_scan_power = max_txpower_avg; | ||
799 | } | 846 | } |
800 | ch_info++; | 847 | ch_info++; |
801 | } | 848 | } |
@@ -808,7 +855,7 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv, | |||
808 | */ | 855 | */ |
809 | static s8 iwl_update_channel_txpower(struct iwl_priv *priv, | 856 | static s8 iwl_update_channel_txpower(struct iwl_priv *priv, |
810 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, | 857 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, |
811 | int section, int element) | 858 | int section, int element, s8 *max_txpower_in_half_dbm) |
812 | { | 859 | { |
813 | struct iwl_channel_info *ch_info; | 860 | struct iwl_channel_info *ch_info; |
814 | int ch; | 861 | int ch; |
@@ -817,7 +864,8 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv, | |||
817 | 864 | ||
818 | channel = enhinfo[section].iwl_eeprom_section_channel[element]; | 865 | channel = enhinfo[section].iwl_eeprom_section_channel[element]; |
819 | max_txpower_avg = | 866 | max_txpower_avg = |
820 | iwl_get_max_txpower_avg(priv, enhanced_txpower, element); | 867 | iwl_get_max_txpower_avg(priv, enhanced_txpower, |
868 | element, max_txpower_in_half_dbm); | ||
821 | 869 | ||
822 | ch_info = priv->channel_info; | 870 | ch_info = priv->channel_info; |
823 | for (ch = 0; ch < priv->channel_count; ch++) { | 871 | for (ch = 0; ch < priv->channel_count; ch++) { |
@@ -831,12 +879,9 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv, | |||
831 | ch_info->scan_power = max_txpower_avg; | 879 | ch_info->scan_power = max_txpower_avg; |
832 | } | 880 | } |
833 | if ((enhinfo[section].is_ht40) && | 881 | if ((enhinfo[section].is_ht40) && |
834 | (ch_info->ht40_max_power_avg) && | ||
835 | (ch_info->ht40_max_power_avg < max_txpower_avg)) { | 882 | (ch_info->ht40_max_power_avg < max_txpower_avg)) { |
836 | /* Update regulatory-based run-time data */ | 883 | /* Update regulatory-based run-time data */ |
837 | ch_info->ht40_max_power_avg = max_txpower_avg; | 884 | ch_info->ht40_max_power_avg = max_txpower_avg; |
838 | ch_info->ht40_curr_txpow = max_txpower_avg; | ||
839 | ch_info->ht40_scan_power = max_txpower_avg; | ||
840 | } | 885 | } |
841 | break; | 886 | break; |
842 | } | 887 | } |
@@ -855,6 +900,7 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) | |||
855 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower; | 900 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower; |
856 | u32 offset; | 901 | u32 offset; |
857 | s8 max_txpower_avg; /* (dBm) */ | 902 | s8 max_txpower_avg; /* (dBm) */ |
903 | s8 max_txpower_in_half_dbm; /* (half-dBm) */ | ||
858 | 904 | ||
859 | /* Loop through all the sections | 905 | /* Loop through all the sections |
860 | * adjust bands and channel's max tx power | 906 | * adjust bands and channel's max tx power |
@@ -867,20 +913,43 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) | |||
867 | enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *) | 913 | enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *) |
868 | iwl_eeprom_query_addr(priv, offset); | 914 | iwl_eeprom_query_addr(priv, offset); |
869 | 915 | ||
916 | /* | ||
917 | * check for valid entry - | ||
918 | * different version of EEPROM might contain different set | ||
919 | * of enhanced tx power table | ||
920 | * always check for valid entry before process | ||
921 | * the information | ||
922 | */ | ||
923 | if (!enhanced_txpower->common || enhanced_txpower->reserved) | ||
924 | continue; | ||
925 | |||
870 | for (element = 0; element < eeprom_section_count; element++) { | 926 | for (element = 0; element < eeprom_section_count; element++) { |
871 | if (enhinfo[section].is_common) | 927 | if (enhinfo[section].is_common) |
872 | max_txpower_avg = | 928 | max_txpower_avg = |
873 | iwl_update_common_txpower(priv, | 929 | iwl_update_common_txpower(priv, |
874 | enhanced_txpower, section, element); | 930 | enhanced_txpower, section, |
931 | element, | ||
932 | &max_txpower_in_half_dbm); | ||
875 | else | 933 | else |
876 | max_txpower_avg = | 934 | max_txpower_avg = |
877 | iwl_update_channel_txpower(priv, | 935 | iwl_update_channel_txpower(priv, |
878 | enhanced_txpower, section, element); | 936 | enhanced_txpower, section, |
937 | element, | ||
938 | &max_txpower_in_half_dbm); | ||
879 | 939 | ||
880 | /* Update the tx_power_user_lmt to the highest power | 940 | /* Update the tx_power_user_lmt to the highest power |
881 | * supported by any channel */ | 941 | * supported by any channel */ |
882 | if (max_txpower_avg > priv->tx_power_user_lmt) | 942 | if (max_txpower_avg > priv->tx_power_user_lmt) |
883 | priv->tx_power_user_lmt = max_txpower_avg; | 943 | priv->tx_power_user_lmt = max_txpower_avg; |
944 | |||
945 | /* | ||
946 | * Update the tx_power_lmt_in_half_dbm to | ||
947 | * the highest power supported by any channel | ||
948 | */ | ||
949 | if (max_txpower_in_half_dbm > | ||
950 | priv->tx_power_lmt_in_half_dbm) | ||
951 | priv->tx_power_lmt_in_half_dbm = | ||
952 | max_txpower_in_half_dbm; | ||
884 | } | 953 | } |
885 | } | 954 | } |
886 | } | 955 | } |