2009-11-13 19:56:33

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 00/16] iwlwifi updates 11/13/2009


Ben M Cahill (2):
iwl3945: Reset saved POWER_TABLE_CMD in "up"
iwlwifi: Add comments about CSR registers

Daniel C Halperin (2):
iwlwifi: fix bugs in beacon configuration
iwlwifi: make iwlwifi send beacons

Johannes Berg (3):
iwlwifi: report PS filtered status
iwlwifi: add sleep_tx_count ucode station API
iwlwifi: handle unicast PS buffering

Reinette Chatre (1):
iwlagn: power up device before initializing EEPROM

Wey-Yi Guy (8):
iwlwifi: validate enhanced tx power entry
iwlwifi: disable coex until implementation ready for 6x50
iwlwifi: remove unused parameter from iwl_channel_info
iwlwifi: drop non-production PCI-IDs for 6x50 series
iwlwifi: remove external reference for non-exist data structure
iwlwifi: update reply_statistics_cmd with 'clear' parameter
iwlwifi: eliminate the possible 1/2 dBm tx power loss in 6x00 & 6x50 series
iwlwifi: align tx/rx statistics debugfs format

drivers/net/wireless/iwlwifi/iwl-4965.c | 7 +-
drivers/net/wireless/iwlwifi/iwl-5000.c | 22 +++-
drivers/net/wireless/iwlwifi/iwl-6000.c | 34 -----
drivers/net/wireless/iwlwifi/iwl-agn.c | 139 +++++++++++++++++----
drivers/net/wireless/iwlwifi/iwl-calib.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-commands.h | 38 ++++++-
drivers/net/wireless/iwlwifi/iwl-core.c | 30 ++++--
drivers/net/wireless/iwlwifi/iwl-core.h | 5 +-
drivers/net/wireless/iwlwifi/iwl-csr.h | 177 +++++++++++++++++++++++----
drivers/net/wireless/iwlwifi/iwl-debug.h | 1 +
drivers/net/wireless/iwlwifi/iwl-debugfs.c | 54 ++++++---
drivers/net/wireless/iwlwifi/iwl-dev.h | 18 +--
drivers/net/wireless/iwlwifi/iwl-eeprom.c | 75 ++++++++----
drivers/net/wireless/iwlwifi/iwl-eeprom.h | 6 +-
drivers/net/wireless/iwlwifi/iwl-power.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-rx.c | 35 +++---
drivers/net/wireless/iwlwifi/iwl-sta.c | 29 ++---
drivers/net/wireless/iwlwifi/iwl-sta.h | 3 +-
drivers/net/wireless/iwlwifi/iwl-tx.c | 51 ++++++++-
drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 +-
20 files changed, 532 insertions(+), 200 deletions(-)



2009-11-16 15:27:37

by Wey-Yi Guy

[permalink] [raw]
Subject: Re: [PATCH 04/16] iwlwifi: drop non-production PCI-IDs for 6x50 series

On Sat, 2009-11-14 at 07:26 -0800, Gábor Stefanik wrote:
> Does that mean, Centrino 6350AGN cancelled?
yes

>
> On Fri, Nov 13, 2009 at 8:56 PM, Reinette Chatre
> <[email protected]> wrote:
> > From: Wey-Yi Guy <[email protected]>
> >
> > drop the non-production PCI-IDs for 6x50 series
> >
> > Signed-off-by: Wey-Yi Guy <[email protected]>
> > Signed-off-by: Reinette Chatre <[email protected]>
> > ---
> > drivers/net/wireless/iwlwifi/iwl-6000.c | 32 -------------------------------
> > drivers/net/wireless/iwlwifi/iwl-agn.c | 3 --
> > drivers/net/wireless/iwlwifi/iwl-dev.h | 1 -
> > 3 files changed, 0 insertions(+), 36 deletions(-)
> >
> > diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
> > index 72ed944..4ab9897 100644
> > --- a/drivers/net/wireless/iwlwifi/iwl-6000.c
> > +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
> > @@ -456,37 +456,5 @@ struct iwl_cfg iwl6000_3agn_cfg = {
> > .support_ct_kill_exit = true,
> > };
> >
> > -struct iwl_cfg iwl6050_3agn_cfg = {
> > - .name = "6050 Series 3x3 AGN",
> > - .fw_name_pre = IWL6050_FW_PRE,
> > - .ucode_api_max = IWL6050_UCODE_API_MAX,
> > - .ucode_api_min = IWL6050_UCODE_API_MIN,
> > - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
> > - .ops = &iwl6050_ops,
> > - .eeprom_size = OTP_LOW_IMAGE_SIZE,
> > - .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
> > - .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
> > - .num_of_queues = IWL50_NUM_QUEUES,
> > - .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
> > - .mod_params = &iwl50_mod_params,
> > - .valid_tx_ant = ANT_ABC,
> > - .valid_rx_ant = ANT_ABC,
> > - .pll_cfg_val = 0,
> > - .set_l0s = true,
> > - .use_bsm = false,
> > - .pa_type = IWL_PA_SYSTEM,
> > - .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
> > - .shadow_ram_support = true,
> > - .ht_greenfield_support = true,
> > - .led_compensation = 51,
> > - .use_rts_for_ht = true, /* use rts/cts protection */
> > - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
> > - .supports_idle = true,
> > - .adv_thermal_throttle = true,
> > - .support_ct_kill_exit = true,
> > - .support_sm_ps = true,
> > - .support_wimax_coexist = true,
> > -};
> > -
> > MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
> > MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
> > diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
> > index 29f7510..24baf2c 100644
> > --- a/drivers/net/wireless/iwlwifi/iwl-agn.c
> > +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
> > @@ -3485,13 +3485,10 @@ static struct pci_device_id iwl_hw_card_ids[] = {
> > {IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
> >
> > /* 6x50 WiFi/WiMax Series */
> > - {IWL_PCI_DEVICE(0x0086, 0x1101, iwl6050_3agn_cfg)},
> > - {IWL_PCI_DEVICE(0x0086, 0x1121, iwl6050_3agn_cfg)},
> > {IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
> > {IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)},
> > {IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)},
> > {IWL_PCI_DEVICE(0x0087, 0x1326, iwl6050_2abg_cfg)},
> > - {IWL_PCI_DEVICE(0x0088, 0x1111, iwl6050_3agn_cfg)},
> > {IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
> > {IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
> >
> > diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
> > index d0f0915..273adee 100644
> > --- a/drivers/net/wireless/iwlwifi/iwl-dev.h
> > +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
> > @@ -64,7 +64,6 @@ extern struct iwl_cfg iwl6000i_2bg_cfg;
> > extern struct iwl_cfg iwl6000_3agn_cfg;
> > extern struct iwl_cfg iwl6050_2agn_cfg;
> > extern struct iwl_cfg iwl6050_2abg_cfg;
> > -extern struct iwl_cfg iwl6050_3agn_cfg;
> > extern struct iwl_cfg iwl1000_bgn_cfg;
> > extern struct iwl_cfg iwl1000_bg_cfg;
> >
> > --
> > 1.5.6.3
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> > the body of a message to [email protected]
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
>
>
>


2009-11-13 19:56:39

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 03/16] iwlwifi: remove unused parameter from iwl_channel_info

From: Wey-Yi Guy <[email protected]>

Number of HT40 power parameters are not used; remove those from
iwl_channel_info data structure

Signed-off-by: Wey-Yi Guy <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-dev.h | 3 ---
drivers/net/wireless/iwlwifi/iwl-eeprom.c | 7 -------
2 files changed, 0 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 9dea8fa..d0f0915 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -295,9 +295,6 @@ struct iwl_channel_info {

/* HT40 channel info */
s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
- s8 ht40_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */
- s8 ht40_min_power; /* always 0 */
- s8 ht40_scan_power; /* (dBm) eeprom, direct scans, any rate */
u8 ht40_flags; /* flags copied from EEPROM */
u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */

diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 143728c..e42eb64 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -751,9 +751,6 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,

ch_info->ht40_eeprom = *eeprom_ch;
ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg;
- ch_info->ht40_curr_txpow = eeprom_ch->max_power_avg;
- ch_info->ht40_min_power = 0;
- ch_info->ht40_scan_power = eeprom_ch->max_power_avg;
ch_info->ht40_flags = eeprom_ch->flags;
ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel;

@@ -840,8 +837,6 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv,
(ch_info->ht40_max_power_avg < max_txpower_avg)) {
/* Update regulatory-based run-time data */
ch_info->ht40_max_power_avg = max_txpower_avg;
- ch_info->ht40_curr_txpow = max_txpower_avg;
- ch_info->ht40_scan_power = max_txpower_avg;
}
ch_info++;
}
@@ -881,8 +876,6 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
(ch_info->ht40_max_power_avg < max_txpower_avg)) {
/* Update regulatory-based run-time data */
ch_info->ht40_max_power_avg = max_txpower_avg;
- ch_info->ht40_curr_txpow = max_txpower_avg;
- ch_info->ht40_scan_power = max_txpower_avg;
}
break;
}
--
1.5.6.3


2009-11-13 19:56:54

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 14/16] iwlwifi: add sleep_tx_count ucode station API

From: Johannes Berg <[email protected]>

This field was marked as reserved before since we didn't
use it, but is present in all released firmwares afaict.
We're going to need it soon, so add it now.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-4965.c | 1 +
drivers/net/wireless/iwlwifi/iwl-commands.h | 18 ++++++++++++++++--
2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 39e7244..a5f7916 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -1818,6 +1818,7 @@ static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid;
addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid;
addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn;
+ addsta->sleep_tx_count = cmd->sleep_tx_count;
addsta->reserved1 = cpu_to_le16(0);
addsta->reserved2 = cpu_to_le32(0);

diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 87a7f28..aa4e38c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -1107,7 +1107,14 @@ struct iwl4965_addsta_cmd {
* Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
__le16 add_immediate_ba_ssn;

- __le32 reserved2;
+ /*
+ * Number of packets OK to transmit to station even though
+ * it is asleep -- used to synchronise PS-poll and u-APSD
+ * responses while ucode keeps track of STA sleep state.
+ */
+ __le16 sleep_tx_count;
+
+ __le16 reserved2;
} __attribute__ ((packed));

/* 5000 */
@@ -1138,7 +1145,14 @@ struct iwl_addsta_cmd {
* Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
__le16 add_immediate_ba_ssn;

- __le32 reserved2;
+ /*
+ * Number of packets OK to transmit to station even though
+ * it is asleep -- used to synchronise PS-poll and u-APSD
+ * responses while ucode keeps track of STA sleep state.
+ */
+ __le16 sleep_tx_count;
+
+ __le16 reserved2;
} __attribute__ ((packed));


--
1.5.6.3


2009-11-13 20:41:23

by Reinette Chatre

[permalink] [raw]
Subject: Re: [PATCH 00/16] iwlwifi updates 11/13/2009

Hi Luis,

On Fri, 2009-11-13 at 12:12 -0800, Luis R. Rodriguez wrote:
> On Fri, Nov 13, 2009 at 11:56 AM, Reinette Chatre
> <[email protected]> wrote:
>
> A general description of what this series addresses would be nice.

Usually I do. In this case most of the patches stand on their own and
commenting on them would essentially just be the subject line rewritten.

Reinette





2009-11-13 19:56:43

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 06/16] iwlwifi: update reply_statistics_cmd with 'clear' parameter

From: Wey-Yi Guy <[email protected]>

When issue REPLY_STATISTICS_CMD to uCode, two possible flag
can be set in the configuration flags

bit 0: Clear statistics
0: Do not clear Statistics counters
1: Clear to zero Statistics counters

Allow "clear" parameter to be set from the caller.

Add debugfs file to clear the statistics counters to help monitor and
debug the uCode behavior.

Signed-off-by: Wey-Yi Guy <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-agn.c | 6 ++--
drivers/net/wireless/iwlwifi/iwl-calib.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-commands.h | 4 +++
drivers/net/wireless/iwlwifi/iwl-core.c | 21 +++++++++-----
drivers/net/wireless/iwlwifi/iwl-core.h | 5 +++-
drivers/net/wireless/iwlwifi/iwl-debug.h | 1 +
drivers/net/wireless/iwlwifi/iwl-debugfs.c | 39 +++++++++++++++++++++-----
drivers/net/wireless/iwlwifi/iwl-power.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-rx.c | 18 ++++++++++++
drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +-
10 files changed, 77 insertions(+), 23 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 24baf2c..d2050d0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -613,7 +613,7 @@ static void iwl_bg_statistics_periodic(unsigned long data)
if (!iwl_is_ready_rf(priv))
return;

- iwl_send_statistics_request(priv, CMD_ASYNC);
+ iwl_send_statistics_request(priv, CMD_ASYNC, false);
}

static void iwl_rx_beacon_notif(struct iwl_priv *priv,
@@ -730,7 +730,7 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
* statistics request from the host as well as for the periodic
* statistics notifications (after received beacons) from the uCode.
*/
- priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics;
+ priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_reply_statistics;
priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics;

iwl_setup_spectrum_handlers(priv);
@@ -2893,7 +2893,7 @@ static ssize_t show_statistics(struct device *d,
return -EAGAIN;

mutex_lock(&priv->mutex);
- rc = iwl_send_statistics_request(priv, 0);
+ rc = iwl_send_statistics_request(priv, CMD_SYNC, false);
mutex_unlock(&priv->mutex);

if (rc) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index d994de7..95a57b3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -900,7 +900,7 @@ void iwl_reset_run_time_calib(struct iwl_priv *priv)

/* Ask for statistics now, the uCode will send notification
* periodically after association */
- iwl_send_statistics_request(priv, CMD_ASYNC);
+ iwl_send_statistics_request(priv, CMD_ASYNC, true);
}
EXPORT_SYMBOL(iwl_reset_run_time_calib);

diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 2857287..6e23a2b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -3071,6 +3071,10 @@ struct statistics_general {
__le32 reserved3;
} __attribute__ ((packed));

+#define UCODE_STATISTICS_CLEAR_MSK (0x1 << 0)
+#define UCODE_STATISTICS_FREQUENCY_MSK (0x1 << 1)
+#define UCODE_STATISTICS_NARROW_BAND_MSK (0x1 << 2)
+
/*
* REPLY_STATISTICS_CMD = 0x9c,
* 3945 and 4965 identical.
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 6b18aab..83b7f60 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1991,16 +1991,21 @@ int iwl_send_bt_config(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_send_bt_config);

-int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags)
+int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
{
- u32 stat_flags = 0;
- struct iwl_host_cmd cmd = {
- .id = REPLY_STATISTICS_CMD,
- .flags = flags,
- .len = sizeof(stat_flags),
- .data = (u8 *) &stat_flags,
+ struct iwl_statistics_cmd statistics_cmd = {
+ .configuration_flags =
+ clear ? IWL_STATS_CONF_CLEAR_STATS : 0,
};
- return iwl_send_cmd(priv, &cmd);
+
+ if (flags & CMD_ASYNC)
+ return iwl_send_cmd_pdu_async(priv, REPLY_STATISTICS_CMD,
+ sizeof(struct iwl_statistics_cmd),
+ &statistics_cmd, NULL);
+ else
+ return iwl_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
+ sizeof(struct iwl_statistics_cmd),
+ &statistics_cmd);
}
EXPORT_SYMBOL(iwl_send_statistics_request);

diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 3f97036..584a376 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -425,6 +425,8 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
void iwl_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
+void iwl_reply_statistics(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb);
void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);

/* TX helpers */
@@ -669,7 +671,8 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv)

extern void iwl_rf_kill_ct_config(struct iwl_priv *priv);
extern int iwl_send_bt_config(struct iwl_priv *priv);
-extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags);
+extern int iwl_send_statistics_request(struct iwl_priv *priv,
+ u8 flags, bool clear);
extern int iwl_verify_ucode(struct iwl_priv *priv);
extern int iwl_send_lq_cmd(struct iwl_priv *priv,
struct iwl_link_quality_cmd *lq, u8 flags);
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 96c92ea..25a0e73 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -107,6 +107,7 @@ struct iwl_debugfs {
struct dentry *file_chain_noise;
struct dentry *file_tx_power;
struct dentry *file_power_save_status;
+ struct dentry *file_clear_statistics;
} dbgfs_debug_files;
u32 sram_offset;
u32 sram_len;
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 8784911..45a5edd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -1042,10 +1042,6 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}

-#define UCODE_STATISTICS_CLEAR_MSK (0x1 << 0)
-#define UCODE_STATISTICS_FREQUENCY_MSK (0x1 << 1)
-#define UCODE_STATISTICS_NARROW_BAND_MSK (0x1 << 2)
-
static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf,
int bufsz)
{
@@ -1092,7 +1088,7 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,

/* make request to uCode to retrieve statistics information */
mutex_lock(&priv->mutex);
- ret = iwl_send_statistics_request(priv, 0);
+ ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
mutex_unlock(&priv->mutex);

if (ret) {
@@ -1398,7 +1394,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,

/* make request to uCode to retrieve statistics information */
mutex_lock(&priv->mutex);
- ret = iwl_send_statistics_request(priv, 0);
+ ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
mutex_unlock(&priv->mutex);

if (ret) {
@@ -1542,7 +1538,7 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,

/* make request to uCode to retrieve statistics information */
mutex_lock(&priv->mutex);
- ret = iwl_send_statistics_request(priv, 0);
+ ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
mutex_unlock(&priv->mutex);

if (ret) {
@@ -1770,7 +1766,7 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file,
else {
/* make request to uCode to retrieve statistics information */
mutex_lock(&priv->mutex);
- ret = iwl_send_statistics_request(priv, 0);
+ ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
mutex_unlock(&priv->mutex);

if (ret) {
@@ -1828,6 +1824,30 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}

+static ssize_t iwl_dbgfs_clear_statistics_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int buf_size;
+ int clear;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%d", &clear) != 1)
+ return -EFAULT;
+
+ /* make request to uCode to retrieve statistics information */
+ mutex_lock(&priv->mutex);
+ iwl_send_statistics_request(priv, CMD_SYNC, true);
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -1840,6 +1860,7 @@ DEBUGFS_READ_FILE_OPS(sensitivity);
DEBUGFS_READ_FILE_OPS(chain_noise);
DEBUGFS_READ_FILE_OPS(tx_power);
DEBUGFS_READ_FILE_OPS(power_save_status);
+DEBUGFS_WRITE_FILE_OPS(clear_statistics);

/*
* Create the debugfs files and directories
@@ -1888,6 +1909,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(tx_queue, debug);
DEBUGFS_ADD_FILE(tx_power, debug);
DEBUGFS_ADD_FILE(power_save_status, debug);
+ DEBUGFS_ADD_FILE(clear_statistics, debug);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_ADD_FILE(ucode_rx_stats, debug);
DEBUGFS_ADD_FILE(ucode_tx_stats, debug);
@@ -1941,6 +1963,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_clear_statistics);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
file_ucode_rx_stats);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 9bce2c1..8ccc0bb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -506,7 +506,7 @@ static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
{
IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n");
/* make request to retrieve statistics information */
- iwl_send_statistics_request(priv, 0);
+ iwl_send_statistics_request(priv, CMD_SYNC, false);
/* Reschedule the ct_kill wait timer */
mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 61b3b0e..9d010a0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -635,6 +635,24 @@ void iwl_rx_statistics(struct iwl_priv *priv,
}
EXPORT_SYMBOL(iwl_rx_statistics);

+void iwl_reply_statistics(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
+ if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
+ memset(&priv->statistics, 0,
+ sizeof(struct iwl_notif_statistics));
+#ifdef CONFIG_IWLWIFI_DEBUG
+ memset(&priv->accum_statistics, 0,
+ sizeof(struct iwl_notif_statistics));
+#endif
+ IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
+ }
+ iwl_rx_statistics(priv, rxb);
+}
+EXPORT_SYMBOL(iwl_reply_statistics);
+
#define PERFECT_RSSI (-20) /* dBm */
#define WORST_RSSI (-95) /* dBm */
#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 5d26330..1e05c91 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -3650,7 +3650,7 @@ static ssize_t show_statistics(struct device *d,
return -EAGAIN;

mutex_lock(&priv->mutex);
- rc = iwl_send_statistics_request(priv, 0);
+ rc = iwl_send_statistics_request(priv, CMD_SYNC, false);
mutex_unlock(&priv->mutex);

if (rc) {
--
1.5.6.3


2009-11-13 19:56:49

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 13/16] iwlwifi: report PS filtered status

From: Johannes Berg <[email protected]>

When a frame is sent to a sleeping station, the
microcode reports TX_STATUS_FAIL_DEST_PS as its
status -- we need to translate that to the flag
that mac80211 expects.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-4965.c | 6 ++----
drivers/net/wireless/iwlwifi/iwl-5000.c | 6 ++----
drivers/net/wireless/iwlwifi/iwl-commands.h | 15 +++++++++++++++
3 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index cc39424..39e7244 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -1865,8 +1865,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
info->status.rates[0].count = tx_resp->failure_frame + 1;
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
- info->flags |= iwl_is_tx_success(status) ?
- IEEE80211_TX_STAT_ACK : 0;
+ info->flags |= iwl_tx_status_to_mac80211(status);
iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
/* FIXME: code repetition end */

@@ -2021,8 +2020,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
}
} else {
info->status.rates[0].count = tx_resp->failure_frame + 1;
- info->flags |= iwl_is_tx_success(status) ?
- IEEE80211_TX_STAT_ACK : 0;
+ info->flags |= iwl_tx_status_to_mac80211(status);
iwl_hwrate_to_tx_control(priv,
le32_to_cpu(tx_resp->rate_n_flags),
info);
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 60b1a7e..30b1d66 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -994,8 +994,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
info->status.rates[0].count = tx_resp->failure_frame + 1;
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
- info->flags |= iwl_is_tx_success(status) ?
- IEEE80211_TX_STAT_ACK : 0;
+ info->flags |= iwl_tx_status_to_mac80211(status);
iwl_hwrate_to_tx_control(priv, rate_n_flags, info);

/* FIXME: code repetition end */
@@ -1140,8 +1139,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
BUG_ON(txq_id != txq->swq_id);

info->status.rates[0].count = tx_resp->failure_frame + 1;
- info->flags |= iwl_is_tx_success(status) ?
- IEEE80211_TX_STAT_ACK : 0;
+ info->flags |= iwl_tx_status_to_mac80211(status);
iwl_hwrate_to_tx_control(priv,
le32_to_cpu(tx_resp->rate_n_flags),
info);
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 6e23a2b..87a7f28 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -1690,6 +1690,21 @@ enum {
TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */
};

+static inline u32 iwl_tx_status_to_mac80211(u32 status)
+{
+ status &= TX_STATUS_MSK;
+
+ switch (status) {
+ case TX_STATUS_SUCCESS:
+ case TX_STATUS_DIRECT_DONE:
+ return IEEE80211_TX_STAT_ACK;
+ case TX_STATUS_FAIL_DEST_PS:
+ return IEEE80211_TX_STAT_TX_FILTERED;
+ default:
+ return 0;
+ }
+}
+
static inline bool iwl_is_tx_success(u32 status)
{
status &= TX_STATUS_MSK;
--
1.5.6.3


2009-11-13 19:56:37

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 02/16] iwlwifi: disable coex until implementation ready for 6x50

From: Wey-Yi Guy <[email protected]>

Temporary disable the coex function for wifi/wimax for 6x50
series until the full implementation ready.

Signed-off-by: Wey-Yi Guy <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-6000.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index f732f6d..72ed944 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -395,7 +395,6 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.support_sm_ps = true,
- .support_wimax_coexist = true,
};

struct iwl_cfg iwl6050_2abg_cfg = {
@@ -425,7 +424,6 @@ struct iwl_cfg iwl6050_2abg_cfg = {
.supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
- .support_wimax_coexist = true,
};

struct iwl_cfg iwl6000_3agn_cfg = {
--
1.5.6.3


2009-11-13 19:56:35

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 01/16] iwlwifi: validate enhanced tx power entry

From: Wey-Yi Guy <[email protected]>

Validate enhanced tx power entry read from EEPROM before applying the
tx power value. Different versions of EEPROM might contain different size
of table; always a good idea to make sure the entry is valid before
applying to the targeted channel.

Signed-off-by: Wey-Yi Guy <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-eeprom.c | 10 ++++++++++
drivers/net/wireless/iwlwifi/iwl-eeprom.h | 6 ++++--
2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 8a0709e..143728c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -913,6 +913,16 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *)
iwl_eeprom_query_addr(priv, offset);

+ /*
+ * check for valid entry -
+ * different version of EEPROM might contain different set
+ * of enhanced tx power table
+ * always check for valid entry before process
+ * the information
+ */
+ if (!enhanced_txpower->common || enhanced_txpower->reserved)
+ continue;
+
for (element = 0; element < eeprom_section_count; element++) {
if (enhinfo[section].is_common)
max_txpower_avg =
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 5ba5a4e..5cd2b66 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -127,19 +127,21 @@ struct iwl_eeprom_channel {
* Enhanced regulatory tx power portion of eeprom image can be broken down
* into individual structures; each one is 8 bytes in size and contain the
* following information
+ * @common: (desc + channel) not used by driver, should _NOT_ be "zero"
* @chain_a_max_pwr: chain a max power in 1/2 dBm
* @chain_b_max_pwr: chain b max power in 1/2 dBm
* @chain_c_max_pwr: chain c max power in 1/2 dBm
+ * @reserved: not used, should be "zero"
* @mimo2_max_pwr: mimo2 max power in 1/2 dBm
* @mimo3_max_pwr: mimo3 max power in 1/2 dBm
*
*/
struct iwl_eeprom_enhanced_txpwr {
- u16 reserved;
+ u16 common;
s8 chain_a_max;
s8 chain_b_max;
s8 chain_c_max;
- s8 reserved1;
+ s8 reserved;
s8 mimo2_max;
s8 mimo3_max;
} __attribute__ ((packed));
--
1.5.6.3


2009-11-13 19:56:53

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 16/16] iwlwifi: Add comments about CSR registers

From: Ben Cahill <[email protected]>

Also regroup CSR_EEPROM and CSR_OTP bit field definitions.

Signed-off-by: Ben Cahill <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-csr.h | 177 +++++++++++++++++++++++++++-----
1 files changed, 150 insertions(+), 27 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index b6ed5a3..68ed822 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -62,11 +62,29 @@
*****************************************************************************/
#ifndef __iwl_csr_h__
#define __iwl_csr_h__
-/*=== CSR (control and status registers) ===*/
+/*
+ * CSR (control and status registers)
+ *
+ * CSR registers are mapped directly into PCI bus space, and are accessible
+ * whenever platform supplies power to device, even when device is in
+ * low power states due to driver-invoked device resets
+ * (e.g. CSR_RESET_REG_FLAG_SW_RESET) or uCode-driven power-saving modes.
+ *
+ * Use iwl_write32() and iwl_read32() family to access these registers;
+ * these provide simple PCI bus access, without waking up the MAC.
+ * Do not use iwl_write_direct32() family for these registers;
+ * no need to "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ.
+ * The MAC (uCode processor, etc.) does not need to be powered up for accessing
+ * the CSR registers.
+ *
+ * NOTE: Newer devices using one-time-programmable (OTP) memory
+ * require device to be awake in order to read this memory
+ * via CSR_EEPROM and CSR_OTP registers
+ */
#define CSR_BASE (0x000)

#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */
-#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */
+#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */
#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */
#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */
#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/
@@ -74,42 +92,65 @@
#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
#define CSR_GP_CNTRL (CSR_BASE+0x024)

+/* 2nd byte of CSR_INT_COALESCING, not accessible via iwl_write32()! */
+#define CSR_INT_PERIODIC_REG (CSR_BASE+0x005)
+
/*
* Hardware revision info
* Bit fields:
* 31-8: Reserved
- * 7-4: Type of device: 0x0 = 4965, 0xd = 3945
+ * 7-4: Type of device: see CSR_HW_REV_TYPE_xxx definitions
* 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D
- * 1-0: "Dash" value, as in A-1, etc.
+ * 1-0: "Dash" (-) value, as in A-1, etc.
*
* NOTE: Revision step affects calculation of CCK txpower for 4965.
+ * NOTE: See also CSR_HW_REV_WA_REG (work-around for bug in 4965).
*/
#define CSR_HW_REV (CSR_BASE+0x028)

-/* EEPROM reads */
+/*
+ * EEPROM and OTP (one-time-programmable) memory reads
+ *
+ * NOTE: For (newer) devices using OTP, device must be awake, initialized via
+ * apm_ops.init() in order to read. Older devices (3945/4965/5000)
+ * use EEPROM and do not require this.
+ */
#define CSR_EEPROM_REG (CSR_BASE+0x02c)
#define CSR_EEPROM_GP (CSR_BASE+0x030)
#define CSR_OTP_GP_REG (CSR_BASE+0x034)
+
#define CSR_GIO_REG (CSR_BASE+0x03C)
#define CSR_GP_UCODE_REG (CSR_BASE+0x048)
#define CSR_GP_DRIVER_REG (CSR_BASE+0x050)
+
+/*
+ * UCODE-DRIVER GP (general purpose) mailbox registers.
+ * SET/CLR registers set/clear bit(s) if "1" is written.
+ */
#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054)
#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058)
#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060)
+
#define CSR_LED_REG (CSR_BASE+0x094)
#define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0)
+
+/* GIO Chicken Bits (PCI Express bus link power management) */
#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)

-#define CSR_INT_PERIODIC_REG (CSR_BASE+0x005)
/* Analog phase-lock-loop configuration */
#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c)
+
/*
- * Indicates hardware rev, to determine CCK backoff for txpower calculation.
+ * CSR Hardware Revision Workaround Register. Indicates hardware rev;
+ * "step" determines CCK backoff for txpower calculation. Used for 4965 only.
+ * See also CSR_HW_REV register.
* Bit fields:
* 3-2: 0 = A, 1 = B, 2 = C, 3 = D step
+ * 1-0: "Dash" (-) value, as in C-1, etc.
*/
#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C)
+
#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240)
#define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250)

@@ -126,11 +167,11 @@
#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000)
#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000)

-#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000)
-#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
-#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000)
-#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000)
-#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000)
+#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000)
+#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
+#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */
+#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */
+#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */

#define CSR_INT_PERIODIC_DIS (0x00)
#define CSR_INT_PERIODIC_ENA (0xFF)
@@ -198,7 +239,44 @@
#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200)
#define CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000)

-/* GP (general purpose) CONTROL */
+/*
+ * GP (general purpose) CONTROL REGISTER
+ * Bit fields:
+ * 27: HW_RF_KILL_SW
+ * Indicates state of (platform's) hardware RF-Kill switch
+ * 26-24: POWER_SAVE_TYPE
+ * Indicates current power-saving mode:
+ * 000 -- No power saving
+ * 001 -- MAC power-down
+ * 010 -- PHY (radio) power-down
+ * 011 -- Error
+ * 9-6: SYS_CONFIG
+ * Indicates current system configuration, reflecting pins on chip
+ * as forced high/low by device circuit board.
+ * 4: GOING_TO_SLEEP
+ * Indicates MAC is entering a power-saving sleep power-down.
+ * Not a good time to access device-internal resources.
+ * 3: MAC_ACCESS_REQ
+ * Host sets this to request and maintain MAC wakeup, to allow host
+ * access to device-internal resources. Host must wait for
+ * MAC_CLOCK_READY (and !GOING_TO_SLEEP) before accessing non-CSR
+ * device registers.
+ * 2: INIT_DONE
+ * Host sets this to put device into fully operational D0 power mode.
+ * Host resets this after SW_RESET to put device into low power mode.
+ * 0: MAC_CLOCK_READY
+ * Indicates MAC (ucode processor, etc.) is powered up and can run.
+ * Internal resources are accessible.
+ * NOTE: This does not indicate that the processor is actually running.
+ * NOTE: This does not indicate that 4965 or 3945 has completed
+ * init or post-power-down restore of internal SRAM memory.
+ * Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that
+ * SRAM is restored and uCode is in normal operation mode.
+ * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and
+ * do not need to save/restore it.
+ * NOTE: After device reset, this bit remains "0" until host sets
+ * INIT_DONE
+ */
#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001)
#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004)
#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008)
@@ -231,28 +309,58 @@
#define CSR_EEPROM_REG_MSK_DATA (0xFFFF0000)

/* EEPROM GP */
-#define CSR_EEPROM_GP_VALID_MSK (0x00000007)
+#define CSR_EEPROM_GP_VALID_MSK (0x00000007) /* signature */
#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180)
+#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000)
+#define CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP (0x00000001)
+#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002)
+#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004)
+
+/* One-time-programmable memory general purpose reg */
#define CSR_OTP_GP_REG_DEVICE_SELECT (0x00010000) /* 0 - EEPROM, 1 - OTP */
#define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */
#define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */
#define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */
+
+/* GP REG */
#define CSR_GP_REG_POWER_SAVE_STATUS_MSK (0x03000000) /* bit 24/25 */
#define CSR_GP_REG_NO_POWER_SAVE (0x00000000)
#define CSR_GP_REG_MAC_POWER_SAVE (0x01000000)
#define CSR_GP_REG_PHY_POWER_SAVE (0x02000000)
#define CSR_GP_REG_POWER_SAVE_ERROR (0x03000000)

-/* EEPROM signature */
-#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000)
-#define CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP (0x00000001)
-#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002)
-#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004)

/* CSR GIO */
#define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002)

-/* UCODE DRV GP */
+/*
+ * UCODE-DRIVER GP (general purpose) mailbox register 1
+ * Host driver and uCode write and/or read this register to communicate with
+ * each other.
+ * Bit fields:
+ * 4: UCODE_DISABLE
+ * Host sets this to request permanent halt of uCode, same as
+ * sending CARD_STATE command with "halt" bit set.
+ * 3: CT_KILL_EXIT
+ * Host sets this to request exit from CT_KILL state, i.e. host thinks
+ * device temperature is low enough to continue normal operation.
+ * 2: CMD_BLOCKED
+ * Host sets this during RF KILL power-down sequence (HW, SW, CT KILL)
+ * to release uCode to clear all Tx and command queues, enter
+ * unassociated mode, and power down.
+ * NOTE: Some devices also use HBUS_TARG_MBX_C register for this bit.
+ * 1: SW_BIT_RFKILL
+ * Host sets this when issuing CARD_STATE command to request
+ * device sleep.
+ * 0: MAC_SLEEP
+ * uCode sets this when preparing a power-saving power-down.
+ * uCode resets this when power-up is complete and SRAM is sane.
+ * NOTE: 3945/4965 saves internal SRAM data to host when powering down,
+ * and must restore this data after powering back up.
+ * MAC_SLEEP is the best indication that restore is complete.
+ * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and
+ * do not need to save/restore it.
+ */
#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001)
#define CSR_UCODE_SW_BIT_RFKILL (0x00000002)
#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004)
@@ -265,7 +373,7 @@
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002)


-/* GI Chicken Bits */
+/* GIO Chicken Bits (PCI Express bus link power management) */
#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000)

@@ -285,8 +393,23 @@
#define CSR_DRAM_INT_TBL_ENABLE (1 << 31)
#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27)

-/*=== HBUS (Host-side Bus) ===*/
+/*
+ * HBUS (Host-side Bus)
+ *
+ * HBUS registers are mapped directly into PCI bus space, but are used
+ * to indirectly access device's internal memory or registers that
+ * may be powered-down.
+ *
+ * Use iwl_write_direct32()/iwl_read_direct32() family for these registers;
+ * host must "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ
+ * to make sure the MAC (uCode processor, etc.) is powered up for accessing
+ * internal resources.
+ *
+ * Do not use iwl_write32()/iwl_read32() family to access these registers;
+ * these provide only simple PCI bus access, without waking up the MAC.
+ */
#define HBUS_BASE (0x400)
+
/*
* Registers for accessing device's internal SRAM memory (e.g. SCD SRAM
* structures, error log, event log, verifying uCode load).
@@ -301,6 +424,10 @@
#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018)
#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c)

+/* Mailbox C, used as workaround alternative to CSR_UCODE_DRV_GP1 mailbox */
+#define HBUS_TARG_MBX_C (HBUS_BASE+0x030)
+#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004)
+
/*
* Registers for accessing device's internal peripheral registers
* (e.g. SCD, BSM, etc.). First write to address register,
@@ -315,16 +442,12 @@
#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050)

/*
- * Per-Tx-queue write pointer (index, really!) (3945 and 4965).
+ * Per-Tx-queue write pointer (index, really!)
* Indicates index to next TFD that driver will fill (1 past latest filled).
* Bit usage:
* 0-7: queue write index
* 11-8: queue selector
*/
#define HBUS_TARG_WRPTR (HBUS_BASE+0x060)
-#define HBUS_TARG_MBX_C (HBUS_BASE+0x030)
-
-#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004)
-

#endif /* !__iwl_csr_h__ */
--
1.5.6.3


2009-11-18 23:47:15

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 15/16] iwlwifi: handle unicast PS buffering

On Thu, 2009-11-19 at 01:34 +0200, Maxim Levitsky wrote:

> So, the multicast/unicast buffering is the sole problem that forbids AP
> mode, right?

No, unicast buffering is actually working after this patch :)

So multicast remains. I cannot make it send multicast after DTIM count
== 0 beacons, it either sends multicast too late or too early. Haven't
tried 3945 of course, those don't seem to work in my machine.

johannes


Attachments:
signature.asc (801.00 B)
This is a digitally signed message part

2009-11-13 19:56:43

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 08/16] iwlwifi: eliminate the possible 1/2 dBm tx power loss in 6x00 & 6x50 series

From: Wey-Yi Guy <[email protected]>

In both 6x00 and 6x50 series, the enhanced/extended tx power table in
EEPROM is used to set the max. tx power limit.
This new tx power table is in 1/2 dBm format, which creates an issue of
possibility of 1/2 dBm loss when driver set the tx power limit; because
of driver keep track and report the tx power in dBm format.

In order to prevent the 1/2 dBm loss, keep track of the true max tx
power in 1/2 dBm format in driver; do the comparison and adjust the tx
power if needed when send tx power command to uCode.

Signed-off-by: Wey-Yi Guy <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-5000.c | 16 +++++++++
drivers/net/wireless/iwlwifi/iwl-dev.h | 1 +
drivers/net/wireless/iwlwifi/iwl-eeprom.c | 49 ++++++++++++++++++++--------
3 files changed, 52 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index e23d301..60b1a7e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1251,6 +1251,22 @@ int iwl5000_send_tx_power(struct iwl_priv *priv)

/* half dBm need to multiply */
tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
+
+ if (priv->tx_power_lmt_in_half_dbm &&
+ priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) {
+ /*
+ * For the newer devices which using enhanced/extend tx power
+ * table in EEPROM, the format is in half dBm. driver need to
+ * convert to dBm format before report to mac80211.
+ * By doing so, there is a possibility of 1/2 dBm resolution
+ * lost. driver will perform "round-up" operation before
+ * reporting, but it will cause 1/2 dBm tx power over the
+ * regulatory limit. Perform the checking here, if the
+ * "tx_power_user_lmt" is higher than EEPROM value (in
+ * half-dBm format), lower the tx power based on EEPROM
+ */
+ tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm;
+ }
tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED;
tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO;

diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 774a315..a474383 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1247,6 +1247,7 @@ struct iwl_priv {
/* TX Power */
s8 tx_power_user_lmt;
s8 tx_power_device_lmt;
+ s8 tx_power_lmt_in_half_dbm; /* max tx power in half-dBm format */


#ifdef CONFIG_IWLWIFI_DEBUG
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index e42eb64..ac88ff0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -762,7 +762,8 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,
* find the highest tx power from all chains for the channel
*/
static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
- struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element)
+ struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
+ int element, s8 *max_txpower_in_half_dbm)
{
s8 max_txpower_avg = 0; /* (dBm) */

@@ -794,10 +795,14 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
(enhanced_txpower[element].mimo3_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].mimo3_max;

- /* max. tx power in EEPROM is in 1/2 dBm format
- * convert from 1/2 dBm to dBm
+ /*
+ * max. tx power in EEPROM is in 1/2 dBm format
+ * convert from 1/2 dBm to dBm (round-up convert)
+ * but we also do not want to loss 1/2 dBm resolution which
+ * will impact performance
*/
- return max_txpower_avg >> 1;
+ *max_txpower_in_half_dbm = max_txpower_avg;
+ return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1);
}

/**
@@ -806,7 +811,7 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
*/
static s8 iwl_update_common_txpower(struct iwl_priv *priv,
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
- int section, int element)
+ int section, int element, s8 *max_txpower_in_half_dbm)
{
struct iwl_channel_info *ch_info;
int ch;
@@ -820,20 +825,22 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv,
if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX)
is_ht40 = true;
max_txpower_avg =
- iwl_get_max_txpower_avg(priv, enhanced_txpower, element);
+ iwl_get_max_txpower_avg(priv, enhanced_txpower,
+ element, max_txpower_in_half_dbm);
+
ch_info = priv->channel_info;

for (ch = 0; ch < priv->channel_count; ch++) {
/* find matching band and update tx power if needed */
if ((ch_info->band == enhinfo[section].band) &&
- (ch_info->max_power_avg < max_txpower_avg) && (!is_ht40)) {
+ (ch_info->max_power_avg < max_txpower_avg) &&
+ (!is_ht40)) {
/* Update regulatory-based run-time data */
ch_info->max_power_avg = ch_info->curr_txpow =
- max_txpower_avg;
+ max_txpower_avg;
ch_info->scan_power = max_txpower_avg;
}
if ((ch_info->band == enhinfo[section].band) && is_ht40 &&
- ch_info->ht40_max_power_avg &&
(ch_info->ht40_max_power_avg < max_txpower_avg)) {
/* Update regulatory-based run-time data */
ch_info->ht40_max_power_avg = max_txpower_avg;
@@ -849,7 +856,7 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv,
*/
static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
- int section, int element)
+ int section, int element, s8 *max_txpower_in_half_dbm)
{
struct iwl_channel_info *ch_info;
int ch;
@@ -858,7 +865,8 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv,

channel = enhinfo[section].iwl_eeprom_section_channel[element];
max_txpower_avg =
- iwl_get_max_txpower_avg(priv, enhanced_txpower, element);
+ iwl_get_max_txpower_avg(priv, enhanced_txpower,
+ element, max_txpower_in_half_dbm);

ch_info = priv->channel_info;
for (ch = 0; ch < priv->channel_count; ch++) {
@@ -872,7 +880,6 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
ch_info->scan_power = max_txpower_avg;
}
if ((enhinfo[section].is_ht40) &&
- (ch_info->ht40_max_power_avg) &&
(ch_info->ht40_max_power_avg < max_txpower_avg)) {
/* Update regulatory-based run-time data */
ch_info->ht40_max_power_avg = max_txpower_avg;
@@ -894,6 +901,7 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower;
u32 offset;
s8 max_txpower_avg; /* (dBm) */
+ s8 max_txpower_in_half_dbm; /* (half-dBm) */

/* Loop through all the sections
* adjust bands and channel's max tx power
@@ -920,16 +928,29 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
if (enhinfo[section].is_common)
max_txpower_avg =
iwl_update_common_txpower(priv,
- enhanced_txpower, section, element);
+ enhanced_txpower, section,
+ element,
+ &max_txpower_in_half_dbm);
else
max_txpower_avg =
iwl_update_channel_txpower(priv,
- enhanced_txpower, section, element);
+ enhanced_txpower, section,
+ element,
+ &max_txpower_in_half_dbm);

/* Update the tx_power_user_lmt to the highest power
* supported by any channel */
if (max_txpower_avg > priv->tx_power_user_lmt)
priv->tx_power_user_lmt = max_txpower_avg;
+
+ /*
+ * Update the tx_power_lmt_in_half_dbm to
+ * the highest power supported by any channel
+ */
+ if (max_txpower_in_half_dbm >
+ priv->tx_power_lmt_in_half_dbm)
+ priv->tx_power_lmt_in_half_dbm =
+ max_txpower_in_half_dbm;
}
}
}
--
1.5.6.3


2009-11-13 22:14:51

by Maxim Levitsky

[permalink] [raw]
Subject: Re: [PATCH 15/16] iwlwifi: handle unicast PS buffering

On Fri, 2009-11-13 at 11:56 -0800, Reinette Chatre wrote:
> From: Johannes Berg <[email protected]>
>
> Using the new mac80211 functionality, this makes
> iwlwifi handle unicast PS buffering correctly.
> The device works like this:
>
> * when a station goes to sleep, the microcode notices
> this and marks the station as asleep
> * when the station is marked asleep, the microcode
> refuses to transmit to the station and rejects all
> frames queued to it with the failure status code
> TX_STATUS_FAIL_DEST_PS (a previous patch handled
> this correctly)
> * when we need to send frames to the station _although_
> it is asleep, we need to tell the ucode how many,
> and this is asynchronous with sending so we cannot
> just send the frames, we need to wait for all other
> frames to be flushed, and then update the counter
> before sending out the poll response frames. This
> is handled partially in the driver and partially in
> mac80211.
>
> In order to do all this correctly, we need to
> * keep track of how many frames are pending for each
> associated client station (avoid doing it for other
> stations to avoid the atomic ops)
> * tell mac80211 that we driver-block the PS status
> while there are still frames pending on the queues,
> and once they are all rejected (due to the dest sta
> being in PS) unblock mac80211

Does this cover iwl3945?
If so, AP mode would be possible?

Best regards,
Maxim Levitsky




2009-11-13 19:56:46

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 10/16] iwlagn: power up device before initializing EEPROM

From: Reinette Chatre <[email protected]>

A recent change optimized the power usage by the device by only powering it
up during EEPROM load if it is required (for OTP devices). This change causes
an error on the 1000 series devices during module load.

The error looks as follows:
[ 1624.024524] iwlagn: Intel(R) Wireless WiFi Link AGN driver for Linux, 1.3.27kds
[ 1624.024527] iwlagn: Copyright(c) 2003-2009 Intel Corporation
[ 1624.024711] iwlagn 0000:01:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
[ 1624.024749] iwlagn 0000:01:00.0: setting latency timer to 64
[ 1624.024909] iwlagn 0000:01:00.0: Detected Intel Wireless WiFi Link 1000 Series BGN REV=0x6C
[ 1624.081263] iwlagn 0000:01:00.0: MAC is in deep sleep!. CSR_GP_CNTRL = 0x080003D8
[ 1624.092967] iwlagn 0000:01:00.0: OTP is empty
[ 1624.092988] iwlagn 0000:01:00.0: Unable to init EEPROM
[ 1624.093033] iwlagn 0000:01:00.0: PCI INT A disabled
[ 1624.093065] iwlagn: probe of 0000:01:00.0 failed with error -2

Adding a dump_stack() to where that error is printed shows the following:

[ 1624.024524] iwlagn: Intel(R) Wireless WiFi Link AGN driver for Linux, 1.3.27kds
[ 1624.024527] iwlagn: Copyright(c) 2003-2009 Intel Corporation
[ 1624.024711] iwlagn 0000:01:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
[ 1624.024749] iwlagn 0000:01:00.0: setting latency timer to 64
[ 1624.024909] iwlagn 0000:01:00.0: Detected Intel Wireless WiFi Link 1000 Series BGN REV=0x6C
[ 1624.081263] iwlagn 0000:01:00.0: MAC is in deep sleep!. CSR_GP_CNTRL = 0x080003D8
[ 1624.081263] Pid: 3073, comm: work_for_cpu Tainted: G W 2.6.31.5 #4
[ 1624.081263] Call Trace:
[ 1624.081263] [<ffffffffa02395db>] T.726+0x22b/0x420 [iwlcore]
[ 1624.081263] [<ffffffffa023985a>] iwlcore_eeprom_acquire_semaphore+0x8a/0x190 [iwlcore]
[ 1624.081263] [<ffffffff81110c94>] ? __kmalloc+0x194/0x1c0
[ 1624.081263] [<ffffffffa02391f5>] ? iwlcore_eeprom_verify_signature+0x25/0xf0 [iwlcore]
[ 1624.081263] [<ffffffffa0239c67>] iwl_eeprom_init+0x107/0xf40 [iwlcore]
[ 1624.081263] [<ffffffffa026ab9c>] ? iwl_prepare_card_hw+0x11c/0x470 [iwlagn]
[ 1624.081263] [<ffffffff8127e2a4>] ? pci_bus_write_config_byte+0x64/0x80
[ 1624.081263] [<ffffffffa026b1f8>] iwl_pci_probe+0x308/0xac0 [iwlagn]
[ 1624.081263] [<ffffffff810710a0>] ? do_work_for_cpu+0x0/0x30
[ 1624.081263] [<ffffffff81284912>] local_pci_probe+0x12/0x20
[ 1624.081263] [<ffffffff810710b3>] do_work_for_cpu+0x13/0x30
[ 1624.081263] [<ffffffff81075826>] kthread+0xa6/0xb0
[ 1624.081263] [<ffffffff81012fea>] child_rip+0xa/0x20
[ 1624.081263] [<ffffffff81075780>] ? kthread+0x0/0xb0
[ 1624.081263] [<ffffffff81012fe0>] ? child_rip+0x0/0x20
[ 1624.092967] iwlagn 0000:01:00.0: OTP is empty
[ 1624.092988] iwlagn 0000:01:00.0: Unable to init EEPROM
[ 1624.093033] iwlagn 0000:01:00.0: PCI INT A disabled
[ 1624.093065] iwlagn: probe of 0000:01:00.0 failed with error -2

We know that the routines in this trace, iwlcore_eeprom_acquire_semaphore
and iwlcore_eeprom_verify_signature, only access CSR registers and thus do
not need the device to be awake if it is EEPROM. But for OTP it is required
for the device to be awake to read these registers. Ensure device is awake
before accessing these registers.

Signed-off-by: Reinette Chatre <[email protected]>
Acked-by: Ben Cahill <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-eeprom.c | 9 ++++++---
1 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index ac88ff0..3946e5c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -518,6 +518,11 @@ int iwl_eeprom_init(struct iwl_priv *priv)
}
e = (u16 *)priv->eeprom;

+ if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
+ /* OTP reads require powered-up chip */
+ priv->cfg->ops->lib->apm_ops.init(priv);
+ }
+
ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv);
if (ret < 0) {
IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
@@ -532,10 +537,8 @@ int iwl_eeprom_init(struct iwl_priv *priv)
ret = -ENOENT;
goto err;
}
- if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {

- /* OTP reads require powered-up chip */
- priv->cfg->ops->lib->apm_ops.init(priv);
+ if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {

ret = iwl_init_otp_access(priv);
if (ret) {
--
1.5.6.3


2009-11-14 15:26:50

by Gábor Stefanik

[permalink] [raw]
Subject: Re: [PATCH 04/16] iwlwifi: drop non-production PCI-IDs for 6x50 series

Does that mean, Centrino 6350AGN cancelled?

On Fri, Nov 13, 2009 at 8:56 PM, Reinette Chatre
<[email protected]> wrote:
> From: Wey-Yi Guy <[email protected]>
>
> drop the non-production PCI-IDs for 6x50 series
>
> Signed-off-by: Wey-Yi Guy <[email protected]>
> Signed-off-by: Reinette Chatre <[email protected]>
> ---
> ?drivers/net/wireless/iwlwifi/iwl-6000.c | ? 32 -------------------------------
> ?drivers/net/wireless/iwlwifi/iwl-agn.c ?| ? ?3 --
> ?drivers/net/wireless/iwlwifi/iwl-dev.h ?| ? ?1 -
> ?3 files changed, 0 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
> index 72ed944..4ab9897 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-6000.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
> @@ -456,37 +456,5 @@ struct iwl_cfg iwl6000_3agn_cfg = {
> ? ? ? ?.support_ct_kill_exit = true,
> ?};
>
> -struct iwl_cfg iwl6050_3agn_cfg = {
> - ? ? ? .name = "6050 Series 3x3 AGN",
> - ? ? ? .fw_name_pre = IWL6050_FW_PRE,
> - ? ? ? .ucode_api_max = IWL6050_UCODE_API_MAX,
> - ? ? ? .ucode_api_min = IWL6050_UCODE_API_MIN,
> - ? ? ? .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
> - ? ? ? .ops = &iwl6050_ops,
> - ? ? ? .eeprom_size = OTP_LOW_IMAGE_SIZE,
> - ? ? ? .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
> - ? ? ? .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
> - ? ? ? .num_of_queues = IWL50_NUM_QUEUES,
> - ? ? ? .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
> - ? ? ? .mod_params = &iwl50_mod_params,
> - ? ? ? .valid_tx_ant = ANT_ABC,
> - ? ? ? .valid_rx_ant = ANT_ABC,
> - ? ? ? .pll_cfg_val = 0,
> - ? ? ? .set_l0s = true,
> - ? ? ? .use_bsm = false,
> - ? ? ? .pa_type = IWL_PA_SYSTEM,
> - ? ? ? .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
> - ? ? ? .shadow_ram_support = true,
> - ? ? ? .ht_greenfield_support = true,
> - ? ? ? .led_compensation = 51,
> - ? ? ? .use_rts_for_ht = true, /* use rts/cts protection */
> - ? ? ? .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
> - ? ? ? .supports_idle = true,
> - ? ? ? .adv_thermal_throttle = true,
> - ? ? ? .support_ct_kill_exit = true,
> - ? ? ? .support_sm_ps = true,
> - ? ? ? .support_wimax_coexist = true,
> -};
> -
> ?MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
> ?MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
> diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
> index 29f7510..24baf2c 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-agn.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
> @@ -3485,13 +3485,10 @@ static struct pci_device_id iwl_hw_card_ids[] = {
> ? ? ? ?{IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
>
> ?/* 6x50 WiFi/WiMax Series */
> - ? ? ? {IWL_PCI_DEVICE(0x0086, 0x1101, iwl6050_3agn_cfg)},
> - ? ? ? {IWL_PCI_DEVICE(0x0086, 0x1121, iwl6050_3agn_cfg)},
> ? ? ? ?{IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
> ? ? ? ?{IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)},
> ? ? ? ?{IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)},
> ? ? ? ?{IWL_PCI_DEVICE(0x0087, 0x1326, iwl6050_2abg_cfg)},
> - ? ? ? {IWL_PCI_DEVICE(0x0088, 0x1111, iwl6050_3agn_cfg)},
> ? ? ? ?{IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
> ? ? ? ?{IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
>
> diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
> index d0f0915..273adee 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-dev.h
> +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
> @@ -64,7 +64,6 @@ extern struct iwl_cfg iwl6000i_2bg_cfg;
> ?extern struct iwl_cfg iwl6000_3agn_cfg;
> ?extern struct iwl_cfg iwl6050_2agn_cfg;
> ?extern struct iwl_cfg iwl6050_2abg_cfg;
> -extern struct iwl_cfg iwl6050_3agn_cfg;
> ?extern struct iwl_cfg iwl1000_bgn_cfg;
> ?extern struct iwl_cfg iwl1000_bg_cfg;
>
> --
> 1.5.6.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>



--
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)

2009-11-13 20:12:56

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: [PATCH 00/16] iwlwifi updates 11/13/2009

On Fri, Nov 13, 2009 at 11:56 AM, Reinette Chatre
<[email protected]> wrote:

A general description of what this series addresses would be nice.

Luis

2009-11-18 23:34:10

by Maxim Levitsky

[permalink] [raw]
Subject: Re: [PATCH 15/16] iwlwifi: handle unicast PS buffering

On Fri, 2009-11-13 at 23:20 +0100, Johannes Berg wrote:
> On Sat, 2009-11-14 at 00:14 +0200, Maxim Levitsky wrote:
>
> > Does this cover iwl3945?
>
> No, and I don't know if this functionality is present in 3945 devices...
> Maybe, but I think station handling is somewhat different... You can
> test it by allowing AP mode, connecting a PS station like an N810 (good
> test device!) and adding its mac addr with arp _manually_, see below.
>
> > If so, AP mode would be possible?
>
> No, because multicast buffering isn't working properly and I can't
> figure out how to do it. John's patch doesn't work at all. And if you
> want to test PS you need to use arp to add the mac addr manually since
> the arps either don't or do go out etc.

I understand now.
Still let me ask if I understand correctly this:

An AP has to do following things:


1) - send beacons (with DTIM data embedded)
2) - be capable sending frames that target several different stations.
3) - buffer frames for stations that are in sleep, and buffer multicast
frames, as long as any station is sleeping.

4) - handle regular association, handshaking, etc


1) & 2) are have to be done in hardware, but IBSS requires this feature.
I have never seen my iwl3945 sending beacons, but it should do so.

4) also needs hardware support, but any card that supports injection,
will work. My iwl3945 supports injection perfectly.


So, the multicast/unicast buffering is the sole problem that forbids AP
mode, right?

Now, there is need to know if any station is in PS mode, but to enter PS
mode, station should send something, right?
If it does, why not to implement multi-cast buffering in software?
In addition to that, I think it might be OK for users to use AP mode,
even if it doesn't work with power saving, it can be ensured that all
stations aren't using this feature. (Its usually broken anyway...)


Best regards,
Maxim Levitsky





2009-11-13 19:56:41

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 05/16] iwlwifi: remove external reference for non-exist data structure

From: Wey-Yi Guy <[email protected]>

Number of data structure for 6000 series no longer in production, the
data structure already being removed; also need to remove the external
reference define in iwl-dev.h

Signed-off-by: Wey-Yi Guy <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-dev.h | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 273adee..774a315 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -55,9 +55,6 @@ extern struct iwl_cfg iwl5350_agn_cfg;
extern struct iwl_cfg iwl5100_bg_cfg;
extern struct iwl_cfg iwl5100_abg_cfg;
extern struct iwl_cfg iwl5150_agn_cfg;
-extern struct iwl_cfg iwl6000h_2agn_cfg;
-extern struct iwl_cfg iwl6000h_2abg_cfg;
-extern struct iwl_cfg iwl6000h_2bg_cfg;
extern struct iwl_cfg iwl6000i_2agn_cfg;
extern struct iwl_cfg iwl6000i_2abg_cfg;
extern struct iwl_cfg iwl6000i_2bg_cfg;
--
1.5.6.3


2009-11-13 19:56:40

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 04/16] iwlwifi: drop non-production PCI-IDs for 6x50 series

From: Wey-Yi Guy <[email protected]>

drop the non-production PCI-IDs for 6x50 series

Signed-off-by: Wey-Yi Guy <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-6000.c | 32 -------------------------------
drivers/net/wireless/iwlwifi/iwl-agn.c | 3 --
drivers/net/wireless/iwlwifi/iwl-dev.h | 1 -
3 files changed, 0 insertions(+), 36 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 72ed944..4ab9897 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -456,37 +456,5 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.support_ct_kill_exit = true,
};

-struct iwl_cfg iwl6050_3agn_cfg = {
- .name = "6050 Series 3x3 AGN",
- .fw_name_pre = IWL6050_FW_PRE,
- .ucode_api_max = IWL6050_UCODE_API_MAX,
- .ucode_api_min = IWL6050_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl6050_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
- .num_of_queues = IWL50_NUM_QUEUES,
- .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
- .mod_params = &iwl50_mod_params,
- .valid_tx_ant = ANT_ABC,
- .valid_rx_ant = ANT_ABC,
- .pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
- .pa_type = IWL_PA_SYSTEM,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
- .shadow_ram_support = true,
- .ht_greenfield_support = true,
- .led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .supports_idle = true,
- .adv_thermal_throttle = true,
- .support_ct_kill_exit = true,
- .support_sm_ps = true,
- .support_wimax_coexist = true,
-};
-
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 29f7510..24baf2c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -3485,13 +3485,10 @@ static struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},

/* 6x50 WiFi/WiMax Series */
- {IWL_PCI_DEVICE(0x0086, 0x1101, iwl6050_3agn_cfg)},
- {IWL_PCI_DEVICE(0x0086, 0x1121, iwl6050_3agn_cfg)},
{IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
{IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)},
{IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)},
{IWL_PCI_DEVICE(0x0087, 0x1326, iwl6050_2abg_cfg)},
- {IWL_PCI_DEVICE(0x0088, 0x1111, iwl6050_3agn_cfg)},
{IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
{IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},

diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index d0f0915..273adee 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -64,7 +64,6 @@ extern struct iwl_cfg iwl6000i_2bg_cfg;
extern struct iwl_cfg iwl6000_3agn_cfg;
extern struct iwl_cfg iwl6050_2agn_cfg;
extern struct iwl_cfg iwl6050_2abg_cfg;
-extern struct iwl_cfg iwl6050_3agn_cfg;
extern struct iwl_cfg iwl1000_bgn_cfg;
extern struct iwl_cfg iwl1000_bg_cfg;

--
1.5.6.3


2009-11-13 22:21:00

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 15/16] iwlwifi: handle unicast PS buffering

On Sat, 2009-11-14 at 00:14 +0200, Maxim Levitsky wrote:

> Does this cover iwl3945?

No, and I don't know if this functionality is present in 3945 devices...
Maybe, but I think station handling is somewhat different... You can
test it by allowing AP mode, connecting a PS station like an N810 (good
test device!) and adding its mac addr with arp _manually_, see below.

> If so, AP mode would be possible?

No, because multicast buffering isn't working properly and I can't
figure out how to do it. John's patch doesn't work at all. And if you
want to test PS you need to use arp to add the mac addr manually since
the arps either don't or do go out etc.

johannes


Attachments:
signature.asc (801.00 B)
This is a digitally signed message part

2009-11-13 19:56:44

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 09/16] iwlwifi: align tx/rx statistics debugfs format

From: Wey-Yi Guy <[email protected]>

Align the format for tx_statistics and rx_statistics debugfs output for
better readability

Signed-off-by: Wey-Yi Guy <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-debugfs.c | 13 +++++++------
1 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 45a5edd..ba9c96f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -131,21 +131,22 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,

int cnt;
ssize_t ret;
- const size_t bufsz = 100 + sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX);
+ const size_t bufsz = 100 +
+ sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf)
return -ENOMEM;
pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
pos += scnprintf(buf + pos, bufsz - pos,
- "\t%s\t\t: %u\n",
+ "\t%25s\t\t: %u\n",
get_mgmt_string(cnt),
priv->tx_stats.mgmt[cnt]);
}
pos += scnprintf(buf + pos, bufsz - pos, "Control\n");
for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
pos += scnprintf(buf + pos, bufsz - pos,
- "\t%s\t\t: %u\n",
+ "\t%25s\t\t: %u\n",
get_ctrl_string(cnt),
priv->tx_stats.ctrl[cnt]);
}
@@ -190,7 +191,7 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
int cnt;
ssize_t ret;
const size_t bufsz = 100 +
- sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX);
+ sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -198,14 +199,14 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
pos += scnprintf(buf + pos, bufsz - pos,
- "\t%s\t\t: %u\n",
+ "\t%25s\t\t: %u\n",
get_mgmt_string(cnt),
priv->rx_stats.mgmt[cnt]);
}
pos += scnprintf(buf + pos, bufsz - pos, "Control:\n");
for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
pos += scnprintf(buf + pos, bufsz - pos,
- "\t%s\t\t: %u\n",
+ "\t%25s\t\t: %u\n",
get_ctrl_string(cnt),
priv->rx_stats.ctrl[cnt]);
}
--
1.5.6.3


2009-11-13 19:56:47

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 12/16] iwlwifi: make iwlwifi send beacons

From: Daniel C Halperin <[email protected]>

Handle BSS_CHANGED_BEACON_ENABLED to enable the sending
of beacons. Also set the correct HT RXON and QoS config.

Signed-off-by: Daniel C Halperin <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-agn.c | 5 +++++
drivers/net/wireless/iwlwifi/iwl-core.c | 8 ++++++++
2 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 24f3192..6db7447 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2564,6 +2564,10 @@ void iwl_config_ap(struct iwl_priv *priv)
IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
"Attempting to continue.\n");

+ /* AP has all antennas */
+ priv->chain_noise_data.active_chains =
+ priv->hw_params.valid_rx_ant;
+ iwl_set_rxon_ht(priv, &priv->current_ht_config);
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);

@@ -2592,6 +2596,7 @@ void iwl_config_ap(struct iwl_priv *priv)
/* restore RXON assoc */
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
iwlcore_commit_rxon(priv);
+ iwl_reset_qos(priv);
spin_lock_irqsave(&priv->lock, flags);
iwl_activate_qos(priv, 1);
spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 294d50c..3d49a65 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -2498,6 +2498,14 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
}
}

+ if ((changes & BSS_CHANGED_BEACON_ENABLED) &&
+ vif->bss_conf.enable_beacon) {
+ memcpy(priv->staging_rxon.bssid_addr,
+ bss_conf->bssid, ETH_ALEN);
+ memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
+ iwlcore_config_ap(priv);
+ }
+
mutex_unlock(&priv->mutex);

IWL_DEBUG_MAC80211(priv, "leave\n");
--
1.5.6.3


2009-11-13 19:56:43

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 07/16] iwl3945: Reset saved POWER_TABLE_CMD in "up"

From: Ben Cahill <[email protected]>

Power-saving logic will not re-issue a POWER_TABLE_CMD if a new command
matches the prior one. This can be bad if we re-start the device due to
e.g. uCode error; the new POWER_TABLE_CMD (required to invoke power-saving)
may match the prior POWER_TABLE_CMD issued before the uCode error.

Ensure the POWER_TABLE_CMD is sent to device when uCode is up.

Signed-off-by: Ben Cahill <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 1e05c91..4325dbf 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2494,7 +2494,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
priv->active_rate = priv->rates_mask;
priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;

- iwl_power_update_mode(priv, false);
+ iwl_power_update_mode(priv, true);

if (iwl_is_associated(priv)) {
struct iwl3945_rxon_cmd *active_rxon =
--
1.5.6.3


2009-11-13 19:56:47

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 11/16] iwlwifi: fix bugs in beacon configuration

From: Daniel C Halperin <[email protected]>

When sending beacon commands to the uCode, we must
inform it of the offset in the beacon frame of the
TIM Element so it can transmit packets from the
correct queue. This functionality is implemented
in iwl_set_beacon_tim().

Fix a bug setting the rate_n_flags for the beacon
packet. First, it should not use the station table's
rate (it's a management frame), and second it needs
to properly configure the TX antennas.

Finally, also, clean up and comment relevant functions.

Signed-off-by: Daniel C Halperin <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-agn.c | 83 +++++++++++++++++++++++--------
drivers/net/wireless/iwlwifi/iwl-core.c | 1 +
2 files changed, 63 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index d2050d0..24f3192 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -311,7 +311,7 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
list_add(&frame->list, &priv->free_frames);
}

-static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+static u32 iwl_fill_beacon_frame(struct iwl_priv *priv,
struct ieee80211_hdr *hdr,
int left)
{
@@ -328,34 +328,74 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
return priv->ibss_beacon->len;
}

+/* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */
+static void iwl_set_beacon_tim(struct iwl_priv *priv,
+ struct iwl_tx_beacon_cmd *tx_beacon_cmd,
+ u8 *beacon, u32 frame_size)
+{
+ u16 tim_idx;
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon;
+
+ /*
+ * The index is relative to frame start but we start looking at the
+ * variable-length part of the beacon.
+ */
+ tim_idx = mgmt->u.beacon.variable - beacon;
+
+ /* Parse variable-length elements of beacon to find WLAN_EID_TIM */
+ while ((tim_idx < (frame_size - 2)) &&
+ (beacon[tim_idx] != WLAN_EID_TIM))
+ tim_idx += beacon[tim_idx+1] + 2;
+
+ /* If TIM field was found, set variables */
+ if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) {
+ tx_beacon_cmd->tim_idx = cpu_to_le16(tim_idx);
+ tx_beacon_cmd->tim_size = beacon[tim_idx+1];
+ } else
+ IWL_WARN(priv, "Unable to find TIM Element in beacon\n");
+}
+
static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
- struct iwl_frame *frame, u8 rate)
+ struct iwl_frame *frame)
{
struct iwl_tx_beacon_cmd *tx_beacon_cmd;
- unsigned int frame_size;
+ u32 frame_size;
+ u32 rate_flags;
+ u32 rate;
+ /*
+ * We have to set up the TX command, the TX Beacon command, and the
+ * beacon contents.
+ */

+ /* Initialize memory */
tx_beacon_cmd = &frame->u.beacon;
memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));

- tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
- tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-
+ /* Set up TX beacon contents */
frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
sizeof(frame->u) - sizeof(*tx_beacon_cmd));
+ if (WARN_ON_ONCE(frame_size > MAX_MPDU_SIZE))
+ return 0;

- BUG_ON(frame_size > MAX_MPDU_SIZE);
+ /* Set up TX command fields */
tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
+ tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
+ tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+ tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
+ TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;

- if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP))
- tx_beacon_cmd->tx.rate_n_flags =
- iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK);
- else
- tx_beacon_cmd->tx.rate_n_flags =
- iwl_hw_set_rate_n_flags(rate, 0);
+ /* Set up TX beacon command fields */
+ iwl_set_beacon_tim(priv, tx_beacon_cmd, (u8 *)tx_beacon_cmd->frame,
+ frame_size);

- tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
- TX_CMD_FLG_TSF_MSK |
- TX_CMD_FLG_STA_RATE_MSK;
+ /* Set up packet rate and flags */
+ rate = iwl_rate_get_lowest_plcp(priv);
+ priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
+ rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
+ if ((rate >= IWL_FIRST_CCK_RATE) && (rate <= IWL_LAST_CCK_RATE))
+ rate_flags |= RATE_MCS_CCK_MSK;
+ tx_beacon_cmd->tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate,
+ rate_flags);

return sizeof(*tx_beacon_cmd) + frame_size;
}
@@ -364,19 +404,20 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv)
struct iwl_frame *frame;
unsigned int frame_size;
int rc;
- u8 rate;

frame = iwl_get_free_frame(priv);
-
if (!frame) {
IWL_ERR(priv, "Could not obtain free frame buffer for beacon "
"command.\n");
return -ENOMEM;
}

- rate = iwl_rate_get_lowest_plcp(priv);
-
- frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
+ frame_size = iwl_hw_get_beacon_cmd(priv, frame);
+ if (!frame_size) {
+ IWL_ERR(priv, "Error configuring the beacon command\n");
+ iwl_free_frame(priv, frame);
+ return -EINVAL;
+ }

rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
&frame->u.cmd[0]);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 83b7f60..294d50c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -209,6 +209,7 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant)
}
return ant;
}
+EXPORT_SYMBOL(iwl_toggle_tx_ant);

const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
EXPORT_SYMBOL(iwl_bcast_addr);
--
1.5.6.3


2009-11-13 19:56:51

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 15/16] iwlwifi: handle unicast PS buffering

From: Johannes Berg <[email protected]>

Using the new mac80211 functionality, this makes
iwlwifi handle unicast PS buffering correctly.
The device works like this:

* when a station goes to sleep, the microcode notices
this and marks the station as asleep
* when the station is marked asleep, the microcode
refuses to transmit to the station and rejects all
frames queued to it with the failure status code
TX_STATUS_FAIL_DEST_PS (a previous patch handled
this correctly)
* when we need to send frames to the station _although_
it is asleep, we need to tell the ucode how many,
and this is asynchronous with sending so we cannot
just send the frames, we need to wait for all other
frames to be flushed, and then update the counter
before sending out the poll response frames. This
is handled partially in the driver and partially in
mac80211.

In order to do all this correctly, we need to
* keep track of how many frames are pending for each
associated client station (avoid doing it for other
stations to avoid the atomic ops)
* tell mac80211 that we driver-block the PS status
while there are still frames pending on the queues,
and once they are all rejected (due to the dest sta
being in PS) unblock mac80211

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-agn.c | 42 +++++++++++++++++++++-
drivers/net/wireless/iwlwifi/iwl-commands.h | 1 +
drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 -
drivers/net/wireless/iwlwifi/iwl-dev.h | 10 ++----
drivers/net/wireless/iwlwifi/iwl-rx.c | 17 +--------
drivers/net/wireless/iwlwifi/iwl-sta.c | 29 +++++++--------
drivers/net/wireless/iwlwifi/iwl-sta.h | 3 +-
drivers/net/wireless/iwlwifi/iwl-tx.c | 51 ++++++++++++++++++++++++++-
8 files changed, 113 insertions(+), 42 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 6db7447..9223397 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2745,6 +2745,45 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
return 0;
}

+static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd,
+ struct ieee80211_sta *sta)
+{
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+ int sta_id;
+
+ /*
+ * TODO: We really should use this callback to
+ * actually maintain the station table in
+ * the device.
+ */
+
+ switch (cmd) {
+ case STA_NOTIFY_ADD:
+ atomic_set(&sta_priv->pending_frames, 0);
+ if (vif->type == NL80211_IFTYPE_AP)
+ sta_priv->client = true;
+ break;
+ case STA_NOTIFY_SLEEP:
+ WARN_ON(!sta_priv->client);
+ sta_priv->asleep = true;
+ if (atomic_read(&sta_priv->pending_frames) > 0)
+ ieee80211_sta_block_awake(hw, sta, true);
+ break;
+ case STA_NOTIFY_AWAKE:
+ WARN_ON(!sta_priv->client);
+ sta_priv->asleep = false;
+ sta_id = iwl_find_station(priv, sta->addr);
+ if (sta_id != IWL_INVALID_STATION)
+ iwl_sta_modify_ps_wake(priv, sta_id);
+ break;
+ default:
+ break;
+ }
+}
+
/*****************************************************************************
*
* sysfs attributes
@@ -3176,7 +3215,8 @@ static struct ieee80211_ops iwl_hw_ops = {
.reset_tsf = iwl_mac_reset_tsf,
.bss_info_changed = iwl_bss_info_changed,
.ampdu_action = iwl_mac_ampdu_action,
- .hw_scan = iwl_mac_hw_scan
+ .hw_scan = iwl_mac_hw_scan,
+ .sta_notify = iwl_mac_sta_notify,
};

static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index aa4e38c..e915075 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -977,6 +977,7 @@ struct iwl_qosparam_cmd {
#define STA_MODIFY_TX_RATE_MSK 0x04
#define STA_MODIFY_ADDBA_TID_MSK 0x08
#define STA_MODIFY_DELBA_TID_MSK 0x10
+#define STA_MODIFY_SLEEP_TX_COUNT_MSK 0x20

/* Receiver address (actually, Rx station's index into station table),
* combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index ba9c96f..9a5ca25 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -336,8 +336,6 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
pos += scnprintf(buf + pos, bufsz - pos,
"flags: 0x%x\n",
station->sta.station_flags_msk);
- pos += scnprintf(buf + pos, bufsz - pos,
- "ps_status: %u\n", station->ps_status);
pos += scnprintf(buf + pos, bufsz - pos, "tid data:\n");
pos += scnprintf(buf + pos, bufsz - pos,
"seq_num\t\ttxq_id");
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index a474383..f1601cf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -545,15 +545,11 @@ struct iwl_qos_info {
struct iwl_qosparam_cmd def_qos_parm;
};

-#define STA_PS_STATUS_WAKE 0
-#define STA_PS_STATUS_SLEEP 1
-

struct iwl3945_station_entry {
struct iwl3945_addsta_cmd sta;
struct iwl_tid_data tid[MAX_TID_COUNT];
u8 used;
- u8 ps_status;
struct iwl_hw_key keyinfo;
};

@@ -561,7 +557,6 @@ struct iwl_station_entry {
struct iwl_addsta_cmd sta;
struct iwl_tid_data tid[MAX_TID_COUNT];
u8 used;
- u8 ps_status;
struct iwl_hw_key keyinfo;
};

@@ -571,11 +566,12 @@ struct iwl_station_entry {
* When mac80211 creates a station it reserves some space (hw->sta_data_size)
* in the structure for use by driver. This structure is places in that
* space.
- *
- * At the moment use it for the station's rate scaling information.
*/
struct iwl_station_priv {
struct iwl_lq_sta lq_sta;
+ atomic_t pending_frames;
+ bool client;
+ bool asleep;
};

/* one for each uCode image (inst/data, boot/init/runtime) */
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 9d010a0..cc980d5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -1028,7 +1028,6 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
struct iwl4965_rx_mpdu_res_start *amsdu;
u32 len;
u32 ampdu_status;
- u16 fc;
u32 rate_n_flags;

/**
@@ -1161,20 +1160,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
priv->last_tsf = le64_to_cpu(phy_res->timestamp);
}

- fc = le16_to_cpu(header->frame_control);
- switch (fc & IEEE80211_FCTL_FTYPE) {
- case IEEE80211_FTYPE_MGMT:
- case IEEE80211_FTYPE_DATA:
- if (priv->iw_mode == NL80211_IFTYPE_AP)
- iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM,
- header->addr2);
- /* fall through */
- default:
- iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status,
- rxb, &rx_status);
- break;
-
- }
+ iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status,
+ rxb, &rx_status);
}
EXPORT_SYMBOL(iwl_rx_reply_rx);

diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index eba36f7..cd6a690 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -1216,7 +1216,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
}
EXPORT_SYMBOL(iwl_sta_rx_agg_stop);

-static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
{
unsigned long flags;

@@ -1224,27 +1224,26 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
priv->stations[sta_id].sta.sta.modify_mask = 0;
+ priv->stations[sta_id].sta.sleep_tx_count = 0;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
spin_unlock_irqrestore(&priv->sta_lock, flags);

iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
+EXPORT_SYMBOL(iwl_sta_modify_ps_wake);

-void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
+void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
{
- /* FIXME: need locking over ps_status ??? */
- u8 sta_id = iwl_find_station(priv, addr);
+ unsigned long flags;

- if (sta_id != IWL_INVALID_STATION) {
- u8 sta_awake = priv->stations[sta_id].
- ps_status == STA_PS_STATUS_WAKE;
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].sta.station_flags |= STA_FLG_PWR_SAVE_MSK;
+ priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
+ priv->stations[sta_id].sta.sta.modify_mask =
+ STA_MODIFY_SLEEP_TX_COUNT_MSK;
+ priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt);
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);

- if (sta_awake && ps_bit)
- priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
- else if (!sta_awake && !ps_bit) {
- iwl_sta_modify_ps_wake(priv, sta_id);
- priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
- }
- }
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index 1c382de..8d052de 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -66,5 +66,6 @@ void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
int iwl_sta_rx_agg_start(struct iwl_priv *priv,
const u8 *addr, int tid, u16 ssn);
int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
-void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr);
+void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id);
+void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
#endif /* __iwl_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 6199bf6..5f1e5f3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -710,6 +710,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_sta *sta = info->control.sta;
+ struct iwl_station_priv *sta_priv = NULL;
struct iwl_tx_queue *txq;
struct iwl_queue *q;
struct iwl_device_cmd *out_cmd;
@@ -772,6 +774,24 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)

IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);

+ if (sta)
+ sta_priv = (void *)sta->drv_priv;
+
+ if (sta_priv && sta_id != priv->hw_params.bcast_sta_id &&
+ sta_priv->asleep) {
+ WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE));
+ /*
+ * This sends an asynchronous command to the device,
+ * but we can rely on it being processed before the
+ * next frame is processed -- and the next frame to
+ * this station is the one that will consume this
+ * counter.
+ * For now set the counter to just 1 since we do not
+ * support uAPSD yet.
+ */
+ iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
+ }
+
txq_id = skb_get_queue_mapping(skb);
if (ieee80211_is_data_qos(fc)) {
qc = ieee80211_get_qos_ctl(hdr);
@@ -931,6 +951,17 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
ret = iwl_txq_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->lock, flags);

+ /*
+ * At this point the frame is "transmitted" successfully
+ * and we will get a TX status notification eventually,
+ * regardless of the value of ret. "ret" only indicates
+ * whether or not we should update the write pointer.
+ */
+
+ /* avoid atomic ops if it isn't an associated client */
+ if (sta_priv && sta_priv->client)
+ atomic_inc(&sta_priv->pending_frames);
+
if (ret)
return ret;

@@ -1075,6 +1106,24 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
return ret ? ret : idx;
}

+static void iwl_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_sta *sta;
+ struct iwl_station_priv *sta_priv;
+
+ sta = ieee80211_find_sta(priv->vif, hdr->addr1);
+ if (sta) {
+ sta_priv = (void *)sta->drv_priv;
+ /* avoid atomic ops if this isn't a client */
+ if (sta_priv->client &&
+ atomic_dec_return(&sta_priv->pending_frames) == 0)
+ ieee80211_sta_block_awake(priv->hw, sta, false);
+ }
+
+ ieee80211_tx_status_irqsafe(priv->hw, skb);
+}
+
int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
{
struct iwl_tx_queue *txq = &priv->txq[txq_id];
@@ -1094,7 +1143,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {

tx_info = &txq->txb[txq->q.read_ptr];
- ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
+ iwl_tx_status(priv, tx_info->skb[0]);
tx_info->skb[0] = NULL;

if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
--
1.5.6.3