Commit 8f7b8db6 authored by Johannes Berg's avatar Johannes Berg

iwlwifi: fix 6000 series channel switch command

The channel switch command for 6000 series devices
is larger than the maximum inline command size of
320 bytes. The command is therefore refused with a
warning. Fix this by allocating the command and
using the NOCOPY mechanism.

Cc: stable@kernel.org
Reviewed-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent bf11315e
...@@ -518,7 +518,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, ...@@ -518,7 +518,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
* See iwlagn_mac_channel_switch. * See iwlagn_mac_channel_switch.
*/ */
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
struct iwl6000_channel_switch_cmd cmd; struct iwl6000_channel_switch_cmd *cmd;
u32 switch_time_in_usec, ucode_switch_time; u32 switch_time_in_usec, ucode_switch_time;
u16 ch; u16 ch;
u32 tsf_low; u32 tsf_low;
...@@ -527,18 +527,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, ...@@ -527,18 +527,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
struct ieee80211_vif *vif = ctx->vif; struct ieee80211_vif *vif = ctx->vif;
struct iwl_host_cmd hcmd = { struct iwl_host_cmd hcmd = {
.id = REPLY_CHANNEL_SWITCH, .id = REPLY_CHANNEL_SWITCH,
.len = { sizeof(cmd), }, .len = { sizeof(*cmd), },
.flags = CMD_SYNC, .flags = CMD_SYNC,
.data = { &cmd, }, .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
}; };
int err;
cmd.band = priv->band == IEEE80211_BAND_2GHZ; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
hcmd.data[0] = cmd;
cmd->band = priv->band == IEEE80211_BAND_2GHZ;
ch = ch_switch->channel->hw_value; ch = ch_switch->channel->hw_value;
IWL_DEBUG_11H(priv, "channel switch from %u to %u\n", IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
ctx->active.channel, ch); ctx->active.channel, ch);
cmd.channel = cpu_to_le16(ch); cmd->channel = cpu_to_le16(ch);
cmd.rxon_flags = ctx->staging.flags; cmd->rxon_flags = ctx->staging.flags;
cmd.rxon_filter_flags = ctx->staging.filter_flags; cmd->rxon_filter_flags = ctx->staging.filter_flags;
switch_count = ch_switch->count; switch_count = ch_switch->count;
tsf_low = ch_switch->timestamp & 0x0ffffffff; tsf_low = ch_switch->timestamp & 0x0ffffffff;
/* /*
...@@ -554,23 +561,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, ...@@ -554,23 +561,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
switch_count = 0; switch_count = 0;
} }
if (switch_count <= 1) if (switch_count <= 1)
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); cmd->switch_time = cpu_to_le32(priv->ucode_beacon_time);
else { else {
switch_time_in_usec = switch_time_in_usec =
vif->bss_conf.beacon_int * switch_count * TIME_UNIT; vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
ucode_switch_time = iwl_usecs_to_beacons(priv, ucode_switch_time = iwl_usecs_to_beacons(priv,
switch_time_in_usec, switch_time_in_usec,
beacon_interval); beacon_interval);
cmd.switch_time = iwl_add_beacon_time(priv, cmd->switch_time = iwl_add_beacon_time(priv,
priv->ucode_beacon_time, priv->ucode_beacon_time,
ucode_switch_time, ucode_switch_time,
beacon_interval); beacon_interval);
} }
IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
cmd.switch_time); cmd->switch_time);
cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR; cmd->expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR;
return iwl_dvm_send_cmd(priv, &hcmd); err = iwl_dvm_send_cmd(priv, &hcmd);
kfree(cmd);
return err;
} }
struct iwl_lib_ops iwl6000_lib = { struct iwl_lib_ops iwl6000_lib = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment