aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWinkler, Tomas <tomas.winkler@intel.com>2009-01-27 17:27:58 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-02-09 15:03:34 -0500
commitd25aabb0a1a2f659206ba21f6ac8ec28047e5595 (patch)
tree2ac07193062fbeb1ac8b784f33dce21a9a668230
parente1623446bb1de1834ff1c57b3e8ed341d5d4a927 (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>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c261
5 files changed, 60 insertions, 242 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 8ff5798ad641..cb6db4525dc3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -1063,7 +1063,7 @@ static int iwl3945_apm_init(struct iwl_priv *priv)
1063{ 1063{
1064 int ret = 0; 1064 int ret = 0;
1065 1065
1066 iwl3945_power_init_handle(priv); 1066 iwl_power_initialize(priv);
1067 1067
1068 iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, 1068 iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
1069 CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); 1069 CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
@@ -2372,7 +2372,9 @@ static u16 iwl3945_get_hcmd_size(u8 cmd_id, u16 len)
2372{ 2372{
2373 switch (cmd_id) { 2373 switch (cmd_id) {
2374 case REPLY_RXON: 2374 case REPLY_RXON:
2375 return (u16) sizeof(struct iwl3945_rxon_cmd); 2375 return sizeof(struct iwl3945_rxon_cmd);
2376 case POWER_TABLE_CMD:
2377 return sizeof(struct iwl3945_powertable_cmd);
2376 default: 2378 default:
2377 return len; 2379 return len;
2378 } 2380 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 5f92cfbe9267..e18c3f326f71 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1355,8 +1355,8 @@ int iwl_init_drv(struct iwl_priv *priv)
1355 priv->qos_data.qos_cap.val = 0; 1355 priv->qos_data.qos_cap.val = 0;
1356 1356
1357 priv->rates_mask = IWL_RATES_MASK; 1357 priv->rates_mask = IWL_RATES_MASK;
1358 /* If power management is turned on, default to AC mode */ 1358 /* If power management is turned on, default to CAM mode */
1359 priv->power_mode = IWL_POWER_AC; 1359 priv->power_mode = IWL_POWER_MODE_CAM;
1360 priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX; 1360 priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX;
1361 1361
1362 ret = iwl_init_channel_map(priv); 1362 ret = iwl_init_channel_map(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index abe0d2966a56..4c5a775f48b7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -102,6 +102,7 @@ static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = {
102 {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} 102 {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
103}; 103};
104 104
105
105/* set card power command */ 106/* set card power command */
106static int iwl_set_power(struct iwl_priv *priv, void *cmd) 107static int iwl_set_power(struct iwl_priv *priv, void *cmd)
107{ 108{
@@ -126,13 +127,6 @@ static u16 iwl_get_auto_power_mode(struct iwl_priv *priv)
126 else 127 else
127 mode = IWL_POWER_ON_AC_DISASSOC; 128 mode = IWL_POWER_ON_AC_DISASSOC;
128 break; 129 break;
129 /* FIXME: remove battery and ac from here */
130 case IWL_POWER_BATTERY:
131 mode = IWL_POWER_INDEX_3;
132 break;
133 case IWL_POWER_AC:
134 mode = IWL_POWER_MODE_CAM;
135 break;
136 default: 130 default:
137 mode = priv->power_data.user_power_setting; 131 mode = priv->power_data.user_power_setting;
138 break; 132 break;
@@ -357,7 +351,7 @@ EXPORT_SYMBOL(iwl_power_enable_management);
357/* set user_power_setting */ 351/* set user_power_setting */
358int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) 352int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
359{ 353{
360 if (mode > IWL_POWER_LIMIT) 354 if (mode > IWL_POWER_MAX)
361 return -EINVAL; 355 return -EINVAL;
362 356
363 priv->power_data.user_power_setting = mode; 357 priv->power_data.user_power_setting = mode;
@@ -371,11 +365,10 @@ EXPORT_SYMBOL(iwl_power_set_user_mode);
371 */ 365 */
372int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode) 366int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode)
373{ 367{
374 if (mode > IWL_POWER_LIMIT) 368 if (mode < IWL_POWER_SYS_MAX)
369 priv->power_data.system_power_setting = mode;
370 else
375 return -EINVAL; 371 return -EINVAL;
376
377 priv->power_data.system_power_setting = mode;
378
379 return iwl_power_update_mode(priv, 0); 372 return iwl_power_update_mode(priv, 0);
380} 373}
381EXPORT_SYMBOL(iwl_power_set_system_mode); 374EXPORT_SYMBOL(iwl_power_set_system_mode);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index 859b60b5335c..879eafdd7369 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -42,27 +42,15 @@ enum {
42 IWL_POWER_INDEX_5, 42 IWL_POWER_INDEX_5,
43 IWL_POWER_AUTO, 43 IWL_POWER_AUTO,
44 IWL_POWER_MAX = IWL_POWER_AUTO, 44 IWL_POWER_MAX = IWL_POWER_AUTO,
45 IWL39_POWER_AC = IWL_POWER_AUTO, /* 0x06 */
46 IWL_POWER_AC,
47 IWL39_POWER_BATTERY = IWL_POWER_AC, /* 0x07 */
48 IWL39_POWER_LIMIT = IWL_POWER_AC,
49 IWL_POWER_BATTERY,
50}; 45};
51 46
52enum { 47enum {
53 IWL_POWER_SYS_AUTO, 48 IWL_POWER_SYS_AUTO,
54 IWL_POWER_SYS_AC, 49 IWL_POWER_SYS_AC,
55 IWL_POWER_SYS_BATTERY, 50 IWL_POWER_SYS_BATTERY,
51 IWL_POWER_SYS_MAX,
56}; 52};
57 53
58#define IWL_POWER_LIMIT 0x08
59#define IWL_POWER_MASK 0x0F
60#define IWL_POWER_ENABLED 0x10
61
62#define IWL_POWER_RANGE_0 (0)
63#define IWL_POWER_RANGE_1 (1)
64
65#define IWL_POWER_LEVEL(x) ((x) & IWL_POWER_MASK)
66 54
67/* Power management (not Tx power) structures */ 55/* Power management (not Tx power) structures */
68 56
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 */
667static 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 */
677static 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
686int 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
724static 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
781static 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,
5136static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, 4980static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate,
5137 store_retry_rate); 4981 store_retry_rate);
5138 4982
4983
5139static ssize_t store_power_level(struct device *d, 4984static 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
5016static 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
5044static 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
5195static 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
5227static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
5228 store_power_level);
5229
5230static ssize_t show_channels(struct device *d, 5065static 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) {