diff options
author | Winkler, Tomas <tomas.winkler@intel.com> | 2009-01-27 17:27:58 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-02-09 15:03:34 -0500 |
commit | d25aabb0a1a2f659206ba21f6ac8ec28047e5595 (patch) | |
tree | 2ac07193062fbeb1ac8b784f33dce21a9a668230 /drivers/net/wireless/iwlwifi/iwl3945-base.c | |
parent | e1623446bb1de1834ff1c57b3e8ed341d5d4a927 (diff) |
iwlwifi: unify iwlagn and 3945 power save management
This patch unifies 3945 and iwlagn power save management
This patch also better separates system state from user setting.
System state shall be removed later as this shall be shifted to user space
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Acked-by: Mohamed Abbas <mohamed.abbas@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl3945-base.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 261 |
1 files changed, 48 insertions, 213 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index ac337177fdb3..800e46c9a68b 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -656,162 +656,6 @@ static void iwl3945_activate_qos(struct iwl_priv *priv, u8 force) | |||
656 | } | 656 | } |
657 | } | 657 | } |
658 | 658 | ||
659 | /* | ||
660 | * Power management (not Tx power!) functions | ||
661 | */ | ||
662 | #define MSEC_TO_USEC 1024 | ||
663 | |||
664 | |||
665 | /* default power management (not Tx power) table values */ | ||
666 | /* for TIM 0-10 */ | ||
667 | static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { | ||
668 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, | ||
669 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, | ||
670 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0}, | ||
671 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0}, | ||
672 | {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1}, | ||
673 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1} | ||
674 | }; | ||
675 | |||
676 | /* for TIM > 10 */ | ||
677 | static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { | ||
678 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, | ||
679 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, | ||
680 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, | ||
681 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 6, 9, 9, 0xFF)}, 0}, | ||
682 | {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, | ||
683 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} | ||
684 | }; | ||
685 | |||
686 | int iwl3945_power_init_handle(struct iwl_priv *priv) | ||
687 | { | ||
688 | int rc = 0, i; | ||
689 | struct iwl_power_mgr *pow_data; | ||
690 | int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX; | ||
691 | u16 pci_pm; | ||
692 | |||
693 | IWL_DEBUG_POWER(priv, "Initialize power \n"); | ||
694 | |||
695 | pow_data = &priv->power_data; | ||
696 | |||
697 | memset(pow_data, 0, sizeof(*pow_data)); | ||
698 | |||
699 | pow_data->dtim_period = 1; | ||
700 | |||
701 | memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); | ||
702 | memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); | ||
703 | |||
704 | rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm); | ||
705 | if (rc != 0) | ||
706 | return 0; | ||
707 | else { | ||
708 | struct iwl_powertable_cmd *cmd; | ||
709 | |||
710 | IWL_DEBUG_POWER(priv, "adjust power command flags\n"); | ||
711 | |||
712 | for (i = 0; i < IWL_POWER_MAX; i++) { | ||
713 | cmd = &pow_data->pwr_range_0[i].cmd; | ||
714 | |||
715 | if (pci_pm & 0x1) | ||
716 | cmd->flags &= ~IWL_POWER_PCI_PM_MSK; | ||
717 | else | ||
718 | cmd->flags |= IWL_POWER_PCI_PM_MSK; | ||
719 | } | ||
720 | } | ||
721 | return rc; | ||
722 | } | ||
723 | |||
724 | static int iwl3945_update_power_cmd(struct iwl_priv *priv, | ||
725 | struct iwl_powertable_cmd *cmd, u32 mode) | ||
726 | { | ||
727 | struct iwl_power_mgr *pow_data; | ||
728 | struct iwl_power_vec_entry *range; | ||
729 | u32 max_sleep = 0; | ||
730 | int i; | ||
731 | u8 period = 0; | ||
732 | bool skip; | ||
733 | |||
734 | if (mode > IWL_POWER_INDEX_5) { | ||
735 | IWL_DEBUG_POWER(priv, "Error invalid power mode \n"); | ||
736 | return -EINVAL; | ||
737 | } | ||
738 | pow_data = &priv->power_data; | ||
739 | |||
740 | if (pow_data->dtim_period < 10) | ||
741 | range = &pow_data->pwr_range_0[0]; | ||
742 | else | ||
743 | range = &pow_data->pwr_range_1[1]; | ||
744 | |||
745 | memcpy(cmd, &range[mode].cmd, sizeof(struct iwl3945_powertable_cmd)); | ||
746 | |||
747 | |||
748 | if (period == 0) { | ||
749 | period = 1; | ||
750 | skip = false; | ||
751 | } else { | ||
752 | skip = !!range[mode].no_dtim; | ||
753 | } | ||
754 | |||
755 | if (skip) { | ||
756 | __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; | ||
757 | max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; | ||
758 | cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; | ||
759 | } else { | ||
760 | max_sleep = period; | ||
761 | cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; | ||
762 | } | ||
763 | |||
764 | for (i = 0; i < IWL_POWER_VEC_SIZE; i++) | ||
765 | if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) | ||
766 | cmd->sleep_interval[i] = cpu_to_le32(max_sleep); | ||
767 | |||
768 | IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags); | ||
769 | IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); | ||
770 | IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); | ||
771 | IWL_DEBUG_POWER(priv, "Sleep interval vector = { %d , %d , %d , %d , %d }\n", | ||
772 | le32_to_cpu(cmd->sleep_interval[0]), | ||
773 | le32_to_cpu(cmd->sleep_interval[1]), | ||
774 | le32_to_cpu(cmd->sleep_interval[2]), | ||
775 | le32_to_cpu(cmd->sleep_interval[3]), | ||
776 | le32_to_cpu(cmd->sleep_interval[4])); | ||
777 | |||
778 | return 0; | ||
779 | } | ||
780 | |||
781 | static int iwl3945_send_power_mode(struct iwl_priv *priv, u32 mode) | ||
782 | { | ||
783 | u32 uninitialized_var(final_mode); | ||
784 | int rc; | ||
785 | struct iwl_powertable_cmd cmd; | ||
786 | |||
787 | /* If on battery, set to 3, | ||
788 | * if plugged into AC power, set to CAM ("continuously aware mode"), | ||
789 | * else user level */ | ||
790 | switch (mode) { | ||
791 | case IWL39_POWER_BATTERY: | ||
792 | final_mode = IWL_POWER_INDEX_3; | ||
793 | break; | ||
794 | case IWL39_POWER_AC: | ||
795 | final_mode = IWL_POWER_MODE_CAM; | ||
796 | break; | ||
797 | default: | ||
798 | final_mode = mode; | ||
799 | break; | ||
800 | } | ||
801 | |||
802 | iwl3945_update_power_cmd(priv, &cmd, final_mode); | ||
803 | |||
804 | /* FIXME use get_hcmd_size 3945 command is 4 bytes shorter */ | ||
805 | rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, | ||
806 | sizeof(struct iwl3945_powertable_cmd), &cmd); | ||
807 | |||
808 | if (final_mode == IWL_POWER_MODE_CAM) | ||
809 | clear_bit(STATUS_POWER_PMI, &priv->status); | ||
810 | else | ||
811 | set_bit(STATUS_POWER_PMI, &priv->status); | ||
812 | |||
813 | return rc; | ||
814 | } | ||
815 | 659 | ||
816 | #define MAX_UCODE_BEACON_INTERVAL 1024 | 660 | #define MAX_UCODE_BEACON_INTERVAL 1024 |
817 | #define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA) | 661 | #define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA) |
@@ -3467,7 +3311,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) | |||
3467 | priv->active_rate = priv->rates_mask; | 3311 | priv->active_rate = priv->rates_mask; |
3468 | priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; | 3312 | priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; |
3469 | 3313 | ||
3470 | iwl3945_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode)); | 3314 | iwl_power_update_mode(priv, false); |
3471 | 3315 | ||
3472 | if (iwl_is_associated(priv)) { | 3316 | if (iwl_is_associated(priv)) { |
3473 | struct iwl3945_rxon_cmd *active_rxon = | 3317 | struct iwl3945_rxon_cmd *active_rxon = |
@@ -5136,44 +4980,70 @@ static ssize_t show_retry_rate(struct device *d, | |||
5136 | static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, | 4980 | static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, |
5137 | store_retry_rate); | 4981 | store_retry_rate); |
5138 | 4982 | ||
4983 | |||
5139 | static ssize_t store_power_level(struct device *d, | 4984 | static ssize_t store_power_level(struct device *d, |
5140 | struct device_attribute *attr, | 4985 | struct device_attribute *attr, |
5141 | const char *buf, size_t count) | 4986 | const char *buf, size_t count) |
5142 | { | 4987 | { |
5143 | struct iwl_priv *priv = dev_get_drvdata(d); | 4988 | struct iwl_priv *priv = dev_get_drvdata(d); |
5144 | int rc; | 4989 | int ret; |
5145 | int mode; | 4990 | unsigned long mode; |
4991 | |||
5146 | 4992 | ||
5147 | mode = simple_strtoul(buf, NULL, 0); | ||
5148 | mutex_lock(&priv->mutex); | 4993 | mutex_lock(&priv->mutex); |
5149 | 4994 | ||
5150 | if (!iwl_is_ready(priv)) { | 4995 | if (!iwl_is_ready(priv)) { |
5151 | rc = -EAGAIN; | 4996 | ret = -EAGAIN; |
5152 | goto out; | 4997 | goto out; |
5153 | } | 4998 | } |
5154 | 4999 | ||
5155 | if ((mode < 1) || (mode > IWL39_POWER_LIMIT) || | 5000 | ret = strict_strtoul(buf, 10, &mode); |
5156 | (mode == IWL39_POWER_AC)) | 5001 | if (ret) |
5157 | mode = IWL39_POWER_AC; | 5002 | goto out; |
5158 | else | ||
5159 | mode |= IWL_POWER_ENABLED; | ||
5160 | 5003 | ||
5161 | if (mode != priv->power_mode) { | 5004 | ret = iwl_power_set_user_mode(priv, mode); |
5162 | rc = iwl3945_send_power_mode(priv, IWL_POWER_LEVEL(mode)); | 5005 | if (ret) { |
5163 | if (rc) { | 5006 | IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n"); |
5164 | IWL_DEBUG_MAC80211(priv, "failed setting power mode\n"); | 5007 | goto out; |
5165 | goto out; | ||
5166 | } | ||
5167 | priv->power_mode = mode; | ||
5168 | } | 5008 | } |
5169 | 5009 | ret = count; | |
5170 | rc = count; | ||
5171 | 5010 | ||
5172 | out: | 5011 | out: |
5173 | mutex_unlock(&priv->mutex); | 5012 | mutex_unlock(&priv->mutex); |
5174 | return rc; | 5013 | return ret; |
5175 | } | 5014 | } |
5176 | 5015 | ||
5016 | static ssize_t show_power_level(struct device *d, | ||
5017 | struct device_attribute *attr, char *buf) | ||
5018 | { | ||
5019 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
5020 | int mode = priv->power_data.user_power_setting; | ||
5021 | int system = priv->power_data.system_power_setting; | ||
5022 | int level = priv->power_data.power_mode; | ||
5023 | char *p = buf; | ||
5024 | |||
5025 | switch (system) { | ||
5026 | case IWL_POWER_SYS_AUTO: | ||
5027 | p += sprintf(p, "SYSTEM:auto"); | ||
5028 | break; | ||
5029 | case IWL_POWER_SYS_AC: | ||
5030 | p += sprintf(p, "SYSTEM:ac"); | ||
5031 | break; | ||
5032 | case IWL_POWER_SYS_BATTERY: | ||
5033 | p += sprintf(p, "SYSTEM:battery"); | ||
5034 | break; | ||
5035 | } | ||
5036 | |||
5037 | p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ? | ||
5038 | "fixed" : "auto"); | ||
5039 | p += sprintf(p, "\tINDEX:%d", level); | ||
5040 | p += sprintf(p, "\n"); | ||
5041 | return p - buf + 1; | ||
5042 | } | ||
5043 | |||
5044 | static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, | ||
5045 | show_power_level, store_power_level); | ||
5046 | |||
5177 | #define MAX_WX_STRING 80 | 5047 | #define MAX_WX_STRING 80 |
5178 | 5048 | ||
5179 | /* Values are in microsecond */ | 5049 | /* Values are in microsecond */ |
@@ -5192,41 +5062,6 @@ static const s32 period_duration[] = { | |||
5192 | 1000000 | 5062 | 1000000 |
5193 | }; | 5063 | }; |
5194 | 5064 | ||
5195 | static ssize_t show_power_level(struct device *d, | ||
5196 | struct device_attribute *attr, char *buf) | ||
5197 | { | ||
5198 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
5199 | int level = IWL_POWER_LEVEL(priv->power_mode); | ||
5200 | char *p = buf; | ||
5201 | |||
5202 | p += sprintf(p, "%d ", level); | ||
5203 | switch (level) { | ||
5204 | case IWL_POWER_MODE_CAM: | ||
5205 | case IWL39_POWER_AC: | ||
5206 | p += sprintf(p, "(AC)"); | ||
5207 | break; | ||
5208 | case IWL39_POWER_BATTERY: | ||
5209 | p += sprintf(p, "(BATTERY)"); | ||
5210 | break; | ||
5211 | default: | ||
5212 | p += sprintf(p, | ||
5213 | "(Timeout %dms, Period %dms)", | ||
5214 | timeout_duration[level - 1] / 1000, | ||
5215 | period_duration[level - 1] / 1000); | ||
5216 | } | ||
5217 | |||
5218 | if (!(priv->power_mode & IWL_POWER_ENABLED)) | ||
5219 | p += sprintf(p, " OFF\n"); | ||
5220 | else | ||
5221 | p += sprintf(p, " \n"); | ||
5222 | |||
5223 | return p - buf + 1; | ||
5224 | |||
5225 | } | ||
5226 | |||
5227 | static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, | ||
5228 | store_power_level); | ||
5229 | |||
5230 | static ssize_t show_channels(struct device *d, | 5065 | static ssize_t show_channels(struct device *d, |
5231 | struct device_attribute *attr, char *buf) | 5066 | struct device_attribute *attr, char *buf) |
5232 | { | 5067 | { |
@@ -5469,8 +5304,8 @@ static int iwl3945_init_drv(struct iwl_priv *priv) | |||
5469 | priv->qos_data.qos_cap.val = 0; | 5304 | priv->qos_data.qos_cap.val = 0; |
5470 | 5305 | ||
5471 | priv->rates_mask = IWL_RATES_MASK; | 5306 | priv->rates_mask = IWL_RATES_MASK; |
5472 | /* If power management is turned on, default to AC mode */ | 5307 | /* If power management is turned on, default to CAM mode */ |
5473 | priv->power_mode = IWL39_POWER_AC; | 5308 | priv->power_mode = IWL_POWER_MODE_CAM; |
5474 | priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER; | 5309 | priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER; |
5475 | 5310 | ||
5476 | if (eeprom->version < EEPROM_3945_EEPROM_VERSION) { | 5311 | if (eeprom->version < EEPROM_3945_EEPROM_VERSION) { |