aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl3945-base.c
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 /drivers/net/wireless/iwlwifi/iwl3945-base.c
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>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl3945-base.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c261
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 */
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) {