aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2009-10-23 16:42:29 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-10-27 16:50:02 -0400
commit4a56e9652ec2ffce87b099aa2fc5b4eb2d5b2666 (patch)
treeea7e79e72e86a49c38b73466397013f1dea64998 /drivers/net/wireless
parent480e8407dc0bccdd8d7cfe29b8fcaaa21dd20e68 (diff)
iwlwifi: add channel switch support to 5000 series and up
Support "channel switch" request by issue "channel switch" host command to uCode. There is no separated "channel switch" indication from mac80211, when detected "IEEE80211_CONF_CHANGE_CHANNEL" flag in iwl_mac_config(), if the station is in "associated" state, then assume "channel switch announcement" IE was received by mac80211. Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h1
7 files changed, 89 insertions, 17 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index f5d75288bd2..09a7bd2c0be 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -1982,12 +1982,6 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
1982 return 0; 1982 return 0;
1983} 1983}
1984 1984
1985/* will add 3945 channel switch cmd handling later */
1986int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel)
1987{
1988 return 0;
1989}
1990
1991/** 1985/**
1992 * iwl3945_reg_txpower_periodic - called when time to check our temperature. 1986 * iwl3945_reg_txpower_periodic - called when time to check our temperature.
1993 * 1987 *
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index f3907c1079f..964c01980ac 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -280,8 +280,6 @@ extern void iwl3945_config_ap(struct iwl_priv *priv);
280 */ 280 */
281extern u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *bssid); 281extern u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *bssid);
282 282
283extern int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel);
284
285/* 283/*
286 * Forward declare iwl-3945.c functions for iwl-base.c 284 * Forward declare iwl-3945.c functions for iwl-base.c
287 */ 285 */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index bd856df5b04..1ff465ad40d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -1433,14 +1433,13 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
1433 return ret; 1433 return ret;
1434} 1434}
1435 1435
1436#ifdef IEEE80211_CONF_CHANNEL_SWITCH
1437static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) 1436static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
1438{ 1437{
1439 int rc; 1438 int rc;
1440 u8 band = 0; 1439 u8 band = 0;
1441 bool is_ht40 = false; 1440 bool is_ht40 = false;
1442 u8 ctrl_chan_high = 0; 1441 u8 ctrl_chan_high = 0;
1443 struct iwl4965_channel_switch_cmd cmd = { 0 }; 1442 struct iwl4965_channel_switch_cmd cmd;
1444 const struct iwl_channel_info *ch_info; 1443 const struct iwl_channel_info *ch_info;
1445 1444
1446 band = priv->band == IEEE80211_BAND_2GHZ; 1445 band = priv->band == IEEE80211_BAND_2GHZ;
@@ -1461,8 +1460,11 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
1461 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); 1460 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
1462 if (ch_info) 1461 if (ch_info)
1463 cmd.expect_beacon = is_channel_radar(ch_info); 1462 cmd.expect_beacon = is_channel_radar(ch_info);
1464 else 1463 else {
1465 cmd.expect_beacon = 1; 1464 IWL_ERR(priv, "invalid channel switch from %u to %u\n",
1465 priv->active_rxon.channel, channel);
1466 return -EFAULT;
1467 }
1466 1468
1467 rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40, 1469 rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40,
1468 ctrl_chan_high, &cmd.tx_power); 1470 ctrl_chan_high, &cmd.tx_power);
@@ -1474,7 +1476,6 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
1474 rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); 1476 rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
1475 return rc; 1477 return rc;
1476} 1478}
1477#endif
1478 1479
1479/** 1480/**
1480 * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array 1481 * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
@@ -2171,6 +2172,7 @@ static struct iwl_lib_ops iwl4965_lib = {
2171 .load_ucode = iwl4965_load_bsm, 2172 .load_ucode = iwl4965_load_bsm,
2172 .dump_nic_event_log = iwl_dump_nic_event_log, 2173 .dump_nic_event_log = iwl_dump_nic_event_log,
2173 .dump_nic_error_log = iwl_dump_nic_error_log, 2174 .dump_nic_error_log = iwl_dump_nic_error_log,
2175 .set_channel_switch = iwl4965_hw_channel_switch,
2174 .apm_ops = { 2176 .apm_ops = {
2175 .init = iwl_apm_init, 2177 .init = iwl_apm_init,
2176 .stop = iwl_apm_stop, 2178 .stop = iwl_apm_stop,
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index a6e347b9799..d256fecc6cd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1382,6 +1382,36 @@ IWL5000_UCODE_GET(init_size);
1382IWL5000_UCODE_GET(init_data_size); 1382IWL5000_UCODE_GET(init_data_size);
1383IWL5000_UCODE_GET(boot_size); 1383IWL5000_UCODE_GET(boot_size);
1384 1384
1385static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
1386{
1387 struct iwl5000_channel_switch_cmd cmd;
1388 const struct iwl_channel_info *ch_info;
1389 struct iwl_host_cmd hcmd = {
1390 .id = REPLY_CHANNEL_SWITCH,
1391 .len = sizeof(cmd),
1392 .flags = CMD_SIZE_HUGE,
1393 .data = &cmd,
1394 };
1395
1396 IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
1397 priv->active_rxon.channel, channel);
1398 cmd.band = priv->band == IEEE80211_BAND_2GHZ;
1399 cmd.channel = cpu_to_le16(channel);
1400 cmd.rxon_flags = priv->active_rxon.flags;
1401 cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
1402 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
1403 ch_info = iwl_get_channel_info(priv, priv->band, channel);
1404 if (ch_info)
1405 cmd.expect_beacon = is_channel_radar(ch_info);
1406 else {
1407 IWL_ERR(priv, "invalid channel switch from %u to %u\n",
1408 priv->active_rxon.channel, channel);
1409 return -EFAULT;
1410 }
1411
1412 return iwl_send_cmd_sync(priv, &hcmd);
1413}
1414
1385struct iwl_hcmd_ops iwl5000_hcmd = { 1415struct iwl_hcmd_ops iwl5000_hcmd = {
1386 .rxon_assoc = iwl5000_send_rxon_assoc, 1416 .rxon_assoc = iwl5000_send_rxon_assoc,
1387 .commit_rxon = iwl_commit_rxon, 1417 .commit_rxon = iwl_commit_rxon,
@@ -1429,6 +1459,7 @@ struct iwl_lib_ops iwl5000_lib = {
1429 .alive_notify = iwl5000_alive_notify, 1459 .alive_notify = iwl5000_alive_notify,
1430 .send_tx_power = iwl5000_send_tx_power, 1460 .send_tx_power = iwl5000_send_tx_power,
1431 .update_chain_flags = iwl_update_chain_flags, 1461 .update_chain_flags = iwl_update_chain_flags,
1462 .set_channel_switch = iwl5000_hw_channel_switch,
1432 .apm_ops = { 1463 .apm_ops = {
1433 .init = iwl_apm_init, 1464 .init = iwl_apm_init,
1434 .stop = iwl_apm_stop, 1465 .stop = iwl_apm_stop,
@@ -1480,6 +1511,7 @@ static struct iwl_lib_ops iwl5150_lib = {
1480 .alive_notify = iwl5000_alive_notify, 1511 .alive_notify = iwl5000_alive_notify,
1481 .send_tx_power = iwl5000_send_tx_power, 1512 .send_tx_power = iwl5000_send_tx_power,
1482 .update_chain_flags = iwl_update_chain_flags, 1513 .update_chain_flags = iwl_update_chain_flags,
1514 .set_channel_switch = iwl5000_hw_channel_switch,
1483 .apm_ops = { 1515 .apm_ops = {
1484 .init = iwl_apm_init, 1516 .init = iwl_apm_init,
1485 .stop = iwl_apm_stop, 1517 .stop = iwl_apm_stop,
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index f5855293c76..f5639b47668 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -172,6 +172,37 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
172 return 0; 172 return 0;
173} 173}
174 174
175static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
176{
177 struct iwl6000_channel_switch_cmd cmd;
178 const struct iwl_channel_info *ch_info;
179 struct iwl_host_cmd hcmd = {
180 .id = REPLY_CHANNEL_SWITCH,
181 .len = sizeof(cmd),
182 .flags = CMD_SIZE_HUGE,
183 .data = &cmd,
184 };
185
186 IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
187 priv->active_rxon.channel, channel);
188
189 cmd.band = priv->band == IEEE80211_BAND_2GHZ;
190 cmd.channel = cpu_to_le16(channel);
191 cmd.rxon_flags = priv->active_rxon.flags;
192 cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
193 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
194 ch_info = iwl_get_channel_info(priv, priv->band, channel);
195 if (ch_info)
196 cmd.expect_beacon = is_channel_radar(ch_info);
197 else {
198 IWL_ERR(priv, "invalid channel switch from %u to %u\n",
199 priv->active_rxon.channel, channel);
200 return -EFAULT;
201 }
202
203 return iwl_send_cmd_sync(priv, &hcmd);
204}
205
175static struct iwl_lib_ops iwl6000_lib = { 206static struct iwl_lib_ops iwl6000_lib = {
176 .set_hw_params = iwl6000_hw_set_hw_params, 207 .set_hw_params = iwl6000_hw_set_hw_params,
177 .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, 208 .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
@@ -192,6 +223,7 @@ static struct iwl_lib_ops iwl6000_lib = {
192 .alive_notify = iwl5000_alive_notify, 223 .alive_notify = iwl5000_alive_notify,
193 .send_tx_power = iwl5000_send_tx_power, 224 .send_tx_power = iwl5000_send_tx_power,
194 .update_chain_flags = iwl_update_chain_flags, 225 .update_chain_flags = iwl_update_chain_flags,
226 .set_channel_switch = iwl6000_hw_channel_switch,
195 .apm_ops = { 227 .apm_ops = {
196 .init = iwl_apm_init, 228 .init = iwl_apm_init,
197 .stop = iwl_apm_stop, 229 .stop = iwl_apm_stop,
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index e43469cfbbc..d2b56baf98f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1284,10 +1284,15 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
1284 struct iwl_rx_packet *pkt = rxb_addr(rxb); 1284 struct iwl_rx_packet *pkt = rxb_addr(rxb);
1285 struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; 1285 struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
1286 struct iwl_csa_notification *csa = &(pkt->u.csa_notif); 1286 struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
1287 IWL_DEBUG_11H(priv, "CSA notif: channel %d, status %d\n", 1287
1288 le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); 1288 if (!le32_to_cpu(csa->status)) {
1289 rxon->channel = csa->channel; 1289 rxon->channel = csa->channel;
1290 priv->staging_rxon.channel = csa->channel; 1290 priv->staging_rxon.channel = csa->channel;
1291 IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
1292 le16_to_cpu(csa->channel));
1293 } else
1294 IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
1295 le16_to_cpu(csa->channel));
1291} 1296}
1292EXPORT_SYMBOL(iwl_rx_csa); 1297EXPORT_SYMBOL(iwl_rx_csa);
1293 1298
@@ -2714,6 +2719,14 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
2714 goto set_ch_out; 2719 goto set_ch_out;
2715 } 2720 }
2716 2721
2722 if (iwl_is_associated(priv) &&
2723 (le16_to_cpu(priv->active_rxon.channel) != ch) &&
2724 priv->cfg->ops->lib->set_channel_switch) {
2725 ret = priv->cfg->ops->lib->set_channel_switch(priv,
2726 ch);
2727 goto out;
2728 }
2729
2717 spin_lock_irqsave(&priv->lock, flags); 2730 spin_lock_irqsave(&priv->lock, flags);
2718 2731
2719 /* Configure HT40 channels */ 2732 /* Configure HT40 channels */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 02bacc4975f..b875dcfca2d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -169,6 +169,7 @@ struct iwl_lib_ops {
169 int (*load_ucode)(struct iwl_priv *priv); 169 int (*load_ucode)(struct iwl_priv *priv);
170 void (*dump_nic_event_log)(struct iwl_priv *priv); 170 void (*dump_nic_event_log)(struct iwl_priv *priv);
171 void (*dump_nic_error_log)(struct iwl_priv *priv); 171 void (*dump_nic_error_log)(struct iwl_priv *priv);
172 int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
172 /* power management */ 173 /* power management */
173 struct iwl_apm_ops apm_ops; 174 struct iwl_apm_ops apm_ops;
174 175