aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl4965-base.c
diff options
context:
space:
mode:
authorMohamed Abbas <mabbas@linux.intel.com>2008-04-21 18:41:51 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-05-07 15:02:15 -0400
commit5da4b55f78fb2ed40926b775d4f7c791594ecbd7 (patch)
treea12ecf0d26552869151738998e88e03e65bcb7c3 /drivers/net/wireless/iwlwifi/iwl4965-base.c
parent7eafd25d9559bd0f652449c222d38d63412e3d4a (diff)
iwlwifi: Add power level support
Add power level support Signed-off-by: Mohamed Abbas <mabbas@linux.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/iwl4965-base.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c217
1 files changed, 20 insertions, 197 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 50f12a6133e8..6cb54580fe6b 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -879,6 +879,13 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
879 return 0; 879 return 0;
880} 880}
881 881
882void iwl4965_update_chain_flags(struct iwl_priv *priv)
883{
884
885 iwl4965_set_rxon_chain(priv);
886 iwl4965_commit_rxon(priv);
887}
888
882static int iwl4965_send_bt_config(struct iwl_priv *priv) 889static int iwl4965_send_bt_config(struct iwl_priv *priv)
883{ 890{
884 struct iwl4965_bt_cmd bt_cmd = { 891 struct iwl4965_bt_cmd bt_cmd = {
@@ -1366,184 +1373,6 @@ static void iwl4965_activate_qos(struct iwl_priv *priv, u8 force)
1366 } 1373 }
1367} 1374}
1368 1375
1369/*
1370 * Power management (not Tx power!) functions
1371 */
1372#define MSEC_TO_USEC 1024
1373
1374#define NOSLP __constant_cpu_to_le16(0), 0, 0
1375#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
1376#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC)
1377#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \
1378 __constant_cpu_to_le32(X1), \
1379 __constant_cpu_to_le32(X2), \
1380 __constant_cpu_to_le32(X3), \
1381 __constant_cpu_to_le32(X4)}
1382
1383
1384/* default power management (not Tx power) table values */
1385/* for tim 0-10 */
1386static struct iwl4965_power_vec_entry range_0[IWL_POWER_AC] = {
1387 {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
1388 {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
1389 {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
1390 {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0},
1391 {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1},
1392 {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1}
1393};
1394
1395/* for tim > 10 */
1396static struct iwl4965_power_vec_entry range_1[IWL_POWER_AC] = {
1397 {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
1398 {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
1399 SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
1400 {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300),
1401 SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
1402 {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100),
1403 SLP_VEC(2, 6, 9, 9, 0xFF)}, 0},
1404 {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
1405 {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25),
1406 SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
1407};
1408
1409int iwl4965_power_init_handle(struct iwl_priv *priv)
1410{
1411 int rc = 0, i;
1412 struct iwl4965_power_mgr *pow_data;
1413 int size = sizeof(struct iwl4965_power_vec_entry) * IWL_POWER_AC;
1414 u16 pci_pm;
1415
1416 IWL_DEBUG_POWER("Initialize power \n");
1417
1418 pow_data = &(priv->power_data);
1419
1420 memset(pow_data, 0, sizeof(*pow_data));
1421
1422 pow_data->active_index = IWL_POWER_RANGE_0;
1423 pow_data->dtim_val = 0xffff;
1424
1425 memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
1426 memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
1427
1428 rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm);
1429 if (rc != 0)
1430 return 0;
1431 else {
1432 struct iwl4965_powertable_cmd *cmd;
1433
1434 IWL_DEBUG_POWER("adjust power command flags\n");
1435
1436 for (i = 0; i < IWL_POWER_AC; i++) {
1437 cmd = &pow_data->pwr_range_0[i].cmd;
1438
1439 if (pci_pm & 0x1)
1440 cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
1441 else
1442 cmd->flags |= IWL_POWER_PCI_PM_MSK;
1443 }
1444 }
1445 return rc;
1446}
1447
1448static int iwl4965_update_power_cmd(struct iwl_priv *priv,
1449 struct iwl4965_powertable_cmd *cmd, u32 mode)
1450{
1451 int rc = 0, i;
1452 u8 skip;
1453 u32 max_sleep = 0;
1454 struct iwl4965_power_vec_entry *range;
1455 u8 period = 0;
1456 struct iwl4965_power_mgr *pow_data;
1457
1458 if (mode > IWL_POWER_INDEX_5) {
1459 IWL_DEBUG_POWER("Error invalid power mode \n");
1460 return -1;
1461 }
1462 pow_data = &(priv->power_data);
1463
1464 if (pow_data->active_index == IWL_POWER_RANGE_0)
1465 range = &pow_data->pwr_range_0[0];
1466 else
1467 range = &pow_data->pwr_range_1[1];
1468
1469 memcpy(cmd, &range[mode].cmd, sizeof(struct iwl4965_powertable_cmd));
1470
1471#ifdef IWL_MAC80211_DISABLE
1472 if (priv->assoc_network != NULL) {
1473 unsigned long flags;
1474
1475 period = priv->assoc_network->tim.tim_period;
1476 }
1477#endif /*IWL_MAC80211_DISABLE */
1478 skip = range[mode].no_dtim;
1479
1480 if (period == 0) {
1481 period = 1;
1482 skip = 0;
1483 }
1484
1485 if (skip == 0) {
1486 max_sleep = period;
1487 cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
1488 } else {
1489 __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
1490 max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
1491 cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
1492 }
1493
1494 for (i = 0; i < IWL_POWER_VEC_SIZE; i++) {
1495 if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
1496 cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
1497 }
1498
1499 IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
1500 IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
1501 IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
1502 IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
1503 le32_to_cpu(cmd->sleep_interval[0]),
1504 le32_to_cpu(cmd->sleep_interval[1]),
1505 le32_to_cpu(cmd->sleep_interval[2]),
1506 le32_to_cpu(cmd->sleep_interval[3]),
1507 le32_to_cpu(cmd->sleep_interval[4]));
1508
1509 return rc;
1510}
1511
1512static int iwl4965_send_power_mode(struct iwl_priv *priv, u32 mode)
1513{
1514 u32 uninitialized_var(final_mode);
1515 int rc;
1516 struct iwl4965_powertable_cmd cmd;
1517
1518 /* If on battery, set to 3,
1519 * if plugged into AC power, set to CAM ("continuously aware mode"),
1520 * else user level */
1521 switch (mode) {
1522 case IWL_POWER_BATTERY:
1523 final_mode = IWL_POWER_INDEX_3;
1524 break;
1525 case IWL_POWER_AC:
1526 final_mode = IWL_POWER_MODE_CAM;
1527 break;
1528 default:
1529 final_mode = mode;
1530 break;
1531 }
1532
1533 cmd.keep_alive_beacons = 0;
1534
1535 iwl4965_update_power_cmd(priv, &cmd, final_mode);
1536
1537 rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
1538
1539 if (final_mode == IWL_POWER_MODE_CAM)
1540 clear_bit(STATUS_POWER_PMI, &priv->status);
1541 else
1542 set_bit(STATUS_POWER_PMI, &priv->status);
1543
1544 return rc;
1545}
1546
1547int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) 1376int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
1548{ 1377{
1549 /* Filter incoming packets to determine if they are targeted toward 1378 /* Filter incoming packets to determine if they are targeted toward
@@ -5304,8 +5133,6 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
5304 priv->active_rate = priv->rates_mask; 5133 priv->active_rate = priv->rates_mask;
5305 priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; 5134 priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
5306 5135
5307 iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
5308
5309 if (iwl_is_associated(priv)) { 5136 if (iwl_is_associated(priv)) {
5310 struct iwl4965_rxon_cmd *active_rxon = 5137 struct iwl4965_rxon_cmd *active_rxon =
5311 (struct iwl4965_rxon_cmd *)(&priv->active_rxon); 5138 (struct iwl4965_rxon_cmd *)(&priv->active_rxon);
@@ -5838,6 +5665,8 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
5838 direct_mask, 5665 direct_mask,
5839 (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); 5666 (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
5840 5667
5668 scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
5669 RXON_FILTER_BCON_AWARE_MSK);
5841 cmd.len += le16_to_cpu(scan->tx_cmd.len) + 5670 cmd.len += le16_to_cpu(scan->tx_cmd.len) +
5842 scan->channel_count * sizeof(struct iwl4965_scan_channel); 5671 scan->channel_count * sizeof(struct iwl4965_scan_channel);
5843 cmd.data = scan; 5672 cmd.data = scan;
@@ -6000,6 +5829,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
6000 5829
6001 iwl4965_activate_qos(priv, 0); 5830 iwl4965_activate_qos(priv, 0);
6002 5831
5832 iwl_power_update_mode(priv, 0);
6003 /* we have just associated, don't start scan too early */ 5833 /* we have just associated, don't start scan too early */
6004 priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; 5834 priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
6005} 5835}
@@ -6990,6 +6820,8 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
6990 iwl4965_commit_rxon(priv); 6820 iwl4965_commit_rxon(priv);
6991 } 6821 }
6992 6822
6823 iwl_power_update_mode(priv, 0);
6824
6993 /* Per mac80211.h: This is only used in IBSS mode... */ 6825 /* Per mac80211.h: This is only used in IBSS mode... */
6994 if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { 6826 if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
6995 6827
@@ -7321,20 +7153,11 @@ static ssize_t store_power_level(struct device *d,
7321 goto out; 7153 goto out;
7322 } 7154 }
7323 7155
7324 if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC)) 7156 rc = iwl_power_set_user_mode(priv, mode);
7325 mode = IWL_POWER_AC; 7157 if (rc) {
7326 else 7158 IWL_DEBUG_MAC80211("failed setting power mode.\n");
7327 mode |= IWL_POWER_ENABLED; 7159 goto out;
7328
7329 if (mode != priv->power_mode) {
7330 rc = iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(mode));
7331 if (rc) {
7332 IWL_DEBUG_MAC80211("failed setting power mode.\n");
7333 goto out;
7334 }
7335 priv->power_mode = mode;
7336 } 7160 }
7337
7338 rc = count; 7161 rc = count;
7339 7162
7340 out: 7163 out:
@@ -7364,7 +7187,7 @@ static ssize_t show_power_level(struct device *d,
7364 struct device_attribute *attr, char *buf) 7187 struct device_attribute *attr, char *buf)
7365{ 7188{
7366 struct iwl_priv *priv = dev_get_drvdata(d); 7189 struct iwl_priv *priv = dev_get_drvdata(d);
7367 int level = IWL_POWER_LEVEL(priv->power_mode); 7190 int level = priv->power_data.power_mode;
7368 char *p = buf; 7191 char *p = buf;
7369 7192
7370 p += sprintf(p, "%d ", level); 7193 p += sprintf(p, "%d ", level);
@@ -7382,14 +7205,14 @@ static ssize_t show_power_level(struct device *d,
7382 timeout_duration[level - 1] / 1000, 7205 timeout_duration[level - 1] / 1000,
7383 period_duration[level - 1] / 1000); 7206 period_duration[level - 1] / 1000);
7384 } 7207 }
7385 7208/*
7386 if (!(priv->power_mode & IWL_POWER_ENABLED)) 7209 if (!(priv->power_mode & IWL_POWER_ENABLED))
7387 p += sprintf(p, " OFF\n"); 7210 p += sprintf(p, " OFF\n");
7388 else 7211 else
7389 p += sprintf(p, " \n"); 7212 p += sprintf(p, " \n");
7390 7213*/
7214 p += sprintf(p, " \n");
7391 return (p - buf + 1); 7215 return (p - buf + 1);
7392
7393} 7216}
7394 7217
7395static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, 7218static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,