From e85498b21d0372a00f31ab9f7c0d215c32c9fad5 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:48 +0800 Subject: iwmc3200wifi: CT kill support We set the initial CT (Temperature control) value to 110 degrees. If the chip goes over that threshold, we hard block the device which will turn it down. At the same time we schedule a 30 seconds delayed work that unblock the device (and userspace is supposed to bring it back up), hoping that the chip will have cooled down by then... Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/net/wireless/iwmc3200wifi/commands.c') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 23b52fa2605..aeea909992f 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -274,6 +274,17 @@ int iwm_send_calib_results(struct iwm_priv *iwm) return ret; } +int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit) +{ + struct iwm_ct_kill_cfg_cmd cmd; + + cmd.entry_threshold = entry; + cmd.exit_threshold = exit; + + return iwm_send_lmac_ptrough_cmd(iwm, REPLY_CT_KILL_CONFIG_CMD, &cmd, + sizeof(struct iwm_ct_kill_cfg_cmd), 0); +} + int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp) { struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; -- cgit v1.2.3-70-g09d2 From 88e6195a911bce85adcc14e8377aa619e8054ab2 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:53 +0800 Subject: iwmc3200wifi: Tx power setting We can now set the Tx power from e.g. iwconfig. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 12 +++++++++++- drivers/net/wireless/iwmc3200wifi/commands.c | 13 +++++++++++++ drivers/net/wireless/iwmc3200wifi/commands.h | 6 ++++++ 3 files changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwmc3200wifi/commands.c') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 89edb662942..af72cc746f1 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -670,9 +670,19 @@ static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, enum tx_power_setting type, int dbm) { + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + int ret; + switch (type) { case TX_POWER_AUTOMATIC: return 0; + case TX_POWER_FIXED: + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_TX_PWR_LIMIT_USR, dbm * 2); + if (ret < 0) + return ret; + + return iwm_tx_power_trigger(iwm); default: return -EOPNOTSUPP; } @@ -684,7 +694,7 @@ static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) { struct iwm_priv *iwm = wiphy_to_iwm(wiphy); - *dbm = iwm->txpower; + *dbm = iwm->txpower >> 1; return 0; } diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index aeea909992f..d5125b7659a 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -793,6 +793,19 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) return ret ? 0 : -EBUSY; } +int iwm_tx_power_trigger(struct iwm_priv *iwm) +{ + struct iwm_umac_pwr_trigger pwr_trigger; + + pwr_trigger.hdr.oid = UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER; + pwr_trigger.hdr.buf_size = + cpu_to_le16(sizeof(struct iwm_umac_pwr_trigger) - + sizeof(struct iwm_umac_wifi_if)); + + + return iwm_send_wifi_if_cmd(iwm, &pwr_trigger, sizeof(pwr_trigger), 1); +} + int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) { struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h index 511b6e395ac..b36be2b23a3 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -441,6 +441,11 @@ struct iwm_umac_tx_key_id { u8 reserved[3]; } __attribute__ ((packed)); +struct iwm_umac_pwr_trigger { + struct iwm_umac_wifi_if hdr; + __le32 reseved; +} __attribute__ ((packed)); + struct iwm_umac_cmd_stats_req { __le32 flags; } __attribute__ ((packed)); @@ -467,6 +472,7 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm); int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key); +int iwm_tx_power_trigger(struct iwm_priv *iwm); int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); int iwm_send_umac_channel_list(struct iwm_priv *iwm); int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, -- cgit v1.2.3-70-g09d2 From 56e3f085f5b5e49cca37a3d1b0aa4266b984eb12 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:56 +0800 Subject: iwmc3200wifi: Do not handle wifi command if the interface is not ready When resetting or bringing the interface down, we should just reject any wifi related command. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless/iwmc3200wifi/commands.c') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index d5125b7659a..25fb8dfd83b 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -76,6 +76,11 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, int ret; u8 oid = hdr->oid; + if (!test_bit(IWM_STATUS_READY, &iwm->status)) { + IWM_ERR(iwm, "Interface is not ready yet"); + return -EAGAIN; + } + umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER; umac_cmd.resp = resp; -- cgit v1.2.3-70-g09d2 From 9829e1b510214956bc9d5e278be49d781e1a6fbf Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:57 +0800 Subject: iwmc3200wifi: Try shared auth when open WEP fails When we fail to associate with an open WEP AP, we fall back to shared auth. This allows us to support joining a shared auth WEP AP with iwconfig. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 2 +- drivers/net/wireless/iwmc3200wifi/iwm.h | 1 + drivers/net/wireless/iwmc3200wifi/main.c | 28 ++++++++++++++++++++++++++++ drivers/net/wireless/iwmc3200wifi/rx.c | 28 +++++++++++++++++++++++----- 4 files changed, 53 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/iwmc3200wifi/commands.c') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 25fb8dfd83b..cad511afd90 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -793,7 +793,7 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) return ret; ret = wait_event_interruptible_timeout(iwm->mlme_queue, - (iwm->umac_profile_active == 0), 2 * HZ); + (iwm->umac_profile_active == 0), 5 * HZ); return ret ? 0 : -EBUSY; } diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index fe0ab80994d..c4a01f2a602 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -285,6 +285,7 @@ struct iwm_priv { u8 *eeprom; struct timer_list watchdog; struct work_struct reset_worker; + struct work_struct auth_retry_worker; struct mutex mutex; u8 *req_ie; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 3147fe7b513..952701e6127 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -207,6 +207,33 @@ static void iwm_reset_worker(struct work_struct *work) mutex_unlock(&iwm->mutex); } +static void iwm_auth_retry_worker(struct work_struct *work) +{ + struct iwm_priv *iwm; + int i, ret; + + iwm = container_of(work, struct iwm_priv, auth_retry_worker); + if (iwm->umac_profile_active) { + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) + return; + } + + iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + + ret = iwm_send_mlme_profile(iwm); + if (ret < 0) + return; + + for (i = 0; i < IWM_NUM_KEYS; i++) + if (iwm->keys[i].key_len) + iwm_set_key(iwm, 0, &iwm->keys[i]); + + iwm_set_tx_key(iwm, iwm->default_key); +} + + + static void iwm_watchdog(unsigned long data) { struct iwm_priv *iwm = (struct iwm_priv *)data; @@ -240,6 +267,7 @@ int iwm_priv_init(struct iwm_priv *iwm) INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work); INIT_DELAYED_WORK(&iwm->ct_kill_delay, iwm_ct_kill_work); INIT_WORK(&iwm->reset_worker, iwm_reset_worker); + INIT_WORK(&iwm->auth_retry_worker, iwm_auth_retry_worker); INIT_LIST_HEAD(&iwm->bss_list); skb_queue_head_init(&iwm->rx_list); diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 648f84a8370..5fa0a63ef0b 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -501,6 +501,18 @@ static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf, return 0; } +static u8 iwm_is_open_wep_profile(struct iwm_priv *iwm) +{ + if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 || + iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) && + (iwm->umac_profile->sec.ucast_cipher == + iwm->umac_profile->sec.mcast_cipher) && + (iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN)) + return 1; + + return 0; +} + static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) @@ -566,11 +578,17 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, goto ibss; if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) - cfg80211_connect_result(iwm_to_ndev(iwm), - complete->bssid, - NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); + if (!iwm_is_open_wep_profile(iwm)) { + cfg80211_connect_result(iwm_to_ndev(iwm), + complete->bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + } else { + /* Let's try shared WEP auth */ + IWM_ERR(iwm, "Trying WEP shared auth\n"); + schedule_work(&iwm->auth_retry_worker); + } else cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL); -- cgit v1.2.3-70-g09d2 From a7af530d45969a63e20708417b70c547596ce3a9 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 24 Nov 2009 11:33:31 +0800 Subject: iwmc3200wifi: 802.11n Tx aggregation support To support 802.11n Tx aggregation support with iwmc3200 wifi, we have to handle the UMAC_CMD_OPCODE_STOP_RESUME_STA_TX notification from the UMAC. Before sending an AddBA, the UMAC synchronizes with the host in order to know what is the last Tx frame it's supposed to receive before it will be able to start the actual aggregation session. We thus have to keep track of the last sequence number that is scheduled for transmission on a particular RAxTID, send an answer to the UMAC with this sequence number. The UMAC then does the BA negociation and once it's done with it sends a new UMAC_CMD_OPCODE_STOP_RESUME_STA_TX notification to let us know that we can resume the Tx flow on the specified RAxTID. Signed-off-by: Samuel Ortiz Reviewed-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 31 +++++++++++++ drivers/net/wireless/iwmc3200wifi/commands.h | 10 +++++ drivers/net/wireless/iwmc3200wifi/iwm.h | 10 +++++ drivers/net/wireless/iwmc3200wifi/main.c | 11 ++++- drivers/net/wireless/iwmc3200wifi/netdev.c | 8 ++++ drivers/net/wireless/iwmc3200wifi/rx.c | 66 ++++++++++++++++++++++++++++ drivers/net/wireless/iwmc3200wifi/tx.c | 57 +++++++++++++++++++++--- drivers/net/wireless/iwmc3200wifi/umac.h | 34 +++++++++++++- 8 files changed, 217 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless/iwmc3200wifi/commands.c') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 7e12438551b..46ca7c58f5a 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -929,3 +929,34 @@ int iwm_target_reset(struct iwm_priv *iwm) return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); } + +int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm, + struct iwm_umac_notif_stop_resume_tx *ntf) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; + struct iwm_umac_cmd umac_cmd; + struct iwm_umac_cmd_stop_resume_tx stp_res_cmd; + struct iwm_sta_info *sta_info; + u8 sta_id = STA_ID_N_COLOR_ID(ntf->sta_id); + int i; + + sta_info = &iwm->sta_table[sta_id]; + if (!sta_info->valid) { + IWM_ERR(iwm, "Invalid STA: %d\n", sta_id); + return -EINVAL; + } + + umac_cmd.id = UMAC_CMD_OPCODE_STOP_RESUME_STA_TX; + umac_cmd.resp = 0; + + stp_res_cmd.flags = ntf->flags; + stp_res_cmd.sta_id = ntf->sta_id; + stp_res_cmd.stop_resume_tid_msk = ntf->stop_resume_tid_msk; + for (i = 0; i < IWM_UMAC_TID_NR; i++) + stp_res_cmd.last_seq_num[i] = + sta_info->tid_info[i].last_seq_num; + + return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stp_res_cmd, + sizeof(struct iwm_umac_cmd_stop_resume_tx)); + +} diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h index b36be2b23a3..95cdf941b22 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -450,6 +450,14 @@ struct iwm_umac_cmd_stats_req { __le32 flags; } __attribute__ ((packed)); +struct iwm_umac_cmd_stop_resume_tx { + u8 flags; + u8 sta_id; + __le16 stop_resume_tid_msk; + __le16 last_seq_num[IWM_UMAC_TID_NR]; + u16 reserved; +} __attribute__ ((packed)); + /* LMAC commands */ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac); int iwm_send_prio_table(struct iwm_priv *iwm); @@ -478,6 +486,8 @@ int iwm_send_umac_channel_list(struct iwm_priv *iwm); int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, int ssid_num); int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len); +int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm, + struct iwm_umac_notif_stop_resume_tx *ntf); /* UDMA commands */ int iwm_target_reset(struct iwm_priv *iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index a9bf6bc97be..8d091f918f3 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -131,11 +131,18 @@ struct iwm_notif { unsigned long buf_size; }; +struct iwm_tid_info { + __le16 last_seq_num; + bool stopped; + struct mutex mutex; +}; + struct iwm_sta_info { u8 addr[ETH_ALEN]; bool valid; bool qos; u8 color; + struct iwm_tid_info tid_info[IWM_UMAC_TID_NR]; }; struct iwm_tx_info { @@ -185,6 +192,8 @@ struct iwm_key { struct iwm_tx_queue { int id; struct sk_buff_head queue; + struct sk_buff_head stopped_queue; + spinlock_t lock; struct workqueue_struct *wq; struct work_struct worker; u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE]; @@ -341,6 +350,7 @@ int iwm_up(struct iwm_priv *iwm); int iwm_down(struct iwm_priv *iwm); /* TX API */ +u16 iwm_tid_to_queue(u16 tid); void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages); void iwm_tx_worker(struct work_struct *work); int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev); diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 92e4eaf32ff..087f04355c1 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -248,7 +248,7 @@ static void iwm_watchdog(unsigned long data) int iwm_priv_init(struct iwm_priv *iwm) { - int i; + int i, j; char name[32]; iwm->status = 0; @@ -292,6 +292,8 @@ int iwm_priv_init(struct iwm_priv *iwm) return -EAGAIN; skb_queue_head_init(&iwm->txq[i].queue); + skb_queue_head_init(&iwm->txq[i].stopped_queue); + spin_lock_init(&iwm->txq[i].lock); } for (i = 0; i < IWM_NUM_KEYS; i++) @@ -299,6 +301,12 @@ int iwm_priv_init(struct iwm_priv *iwm) iwm->default_key = -1; + for (i = 0; i < IWM_STA_TABLE_NUM; i++) + for (j = 0; j < IWM_UMAC_TID_NR; j++) { + mutex_init(&iwm->sta_table[i].tid_info[j].mutex); + iwm->sta_table[i].tid_info[j].stopped = false; + } + init_timer(&iwm->watchdog); iwm->watchdog.function = iwm_watchdog; iwm->watchdog.data = (unsigned long)iwm; @@ -572,6 +580,7 @@ void iwm_link_off(struct iwm_priv *iwm) for (i = 0; i < IWM_TX_QUEUES; i++) { skb_queue_purge(&iwm->txq[i].queue); + skb_queue_purge(&iwm->txq[i].stopped_queue); iwm->txq[i].concat_count = 0; iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf; diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index 4f8dbdd7b91..e4f0f8705f6 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -76,6 +76,14 @@ static int iwm_stop(struct net_device *ndev) */ static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; +u16 iwm_tid_to_queue(u16 tid) +{ + if (tid > IWM_UMAC_TID_NR - 2) + return -EINVAL; + + return iwm_1d_to_queue[tid]; +} + static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb) { skb->priority = cfg80211_classify8021d(skb); diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index bdb1d7e7979..72c27a3e552 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -1087,6 +1087,71 @@ static int iwm_ntf_channel_info_list(struct iwm_priv *iwm, u8 *buf, return 0; } +static int iwm_ntf_stop_resume_tx(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_stop_resume_tx *stp_res_tx = + (struct iwm_umac_notif_stop_resume_tx *)buf; + struct iwm_sta_info *sta_info; + struct iwm_tid_info *tid_info; + u8 sta_id = STA_ID_N_COLOR_ID(stp_res_tx->sta_id); + u16 tid_msk = le16_to_cpu(stp_res_tx->stop_resume_tid_msk); + int bit, ret = 0; + bool stop = false; + + IWM_DBG_NTF(iwm, DBG, "stop/resume notification:\n" + "\tflags: 0x%x\n" + "\tSTA id: %d\n" + "\tTID bitmask: 0x%x\n", + stp_res_tx->flags, stp_res_tx->sta_id, + stp_res_tx->stop_resume_tid_msk); + + if (stp_res_tx->flags & UMAC_STOP_TX_FLAG) + stop = true; + + sta_info = &iwm->sta_table[sta_id]; + if (!sta_info->valid) { + IWM_ERR(iwm, "Stoping an invalid STA: %d %d\n", + sta_id, stp_res_tx->sta_id); + return -EINVAL; + } + + for_each_bit(bit, (unsigned long *)&tid_msk, IWM_UMAC_TID_NR) { + tid_info = &sta_info->tid_info[bit]; + + mutex_lock(&tid_info->mutex); + tid_info->stopped = stop; + mutex_unlock(&tid_info->mutex); + + if (!stop) { + struct iwm_tx_queue *txq; + u16 queue = iwm_tid_to_queue(bit); + + if (queue < 0) + continue; + + txq = &iwm->txq[queue]; + /* + * If we resume, we have to move our SKBs + * back to the tx queue and queue some work. + */ + spin_lock_bh(&txq->lock); + skb_queue_splice_init(&txq->queue, &txq->stopped_queue); + spin_unlock_bh(&txq->lock); + + queue_work(txq->wq, &txq->worker); + } + + } + + /* We send an ACK only for the stop case */ + if (stop) + ret = iwm_send_umac_stop_resume_tx(iwm, stp_res_tx); + + return ret; +} + static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) @@ -1371,6 +1436,7 @@ static const iwm_handler iwm_umac_handlers[] = [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics, [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy, [UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST] = iwm_ntf_channel_info_list, + [UMAC_CMD_OPCODE_STOP_RESUME_STA_TX] = iwm_ntf_stop_resume_tx, [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper, }; diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c index e3b4f7902da..01cc2101e68 100644 --- a/drivers/net/wireless/iwmc3200wifi/tx.c +++ b/drivers/net/wireless/iwmc3200wifi/tx.c @@ -329,7 +329,7 @@ static int iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb, memcpy(buf + sizeof(*hdr), skb->data, skb->len); - return 0; + return umac_cmd.seq_num; } static int iwm_tx_send_concat_packets(struct iwm_priv *iwm, @@ -361,9 +361,10 @@ void iwm_tx_worker(struct work_struct *work) struct iwm_priv *iwm; struct iwm_tx_info *tx_info = NULL; struct sk_buff *skb; - int cmdlen, ret; struct iwm_tx_queue *txq; - int pool_id; + struct iwm_sta_info *sta_info; + struct iwm_tid_info *tid_info; + int cmdlen, ret, pool_id; txq = container_of(work, struct iwm_tx_queue, worker); iwm = container_of(txq, struct iwm_priv, txq[txq->id]); @@ -373,8 +374,40 @@ void iwm_tx_worker(struct work_struct *work) while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) && !skb_queue_empty(&txq->queue)) { + spin_lock_bh(&txq->lock); skb = skb_dequeue(&txq->queue); + spin_unlock_bh(&txq->lock); + tx_info = skb_to_tx_info(skb); + sta_info = &iwm->sta_table[tx_info->sta]; + if (!sta_info->valid) { + IWM_ERR(iwm, "Trying to send a frame to unknown STA\n"); + kfree_skb(skb); + continue; + } + + tid_info = &sta_info->tid_info[tx_info->tid]; + + mutex_lock(&tid_info->mutex); + + /* + * If the RAxTID is stopped, we queue the skb to the stopped + * queue. + * Whenever we'll get a UMAC notification to resume the tx flow + * for this RAxTID, we'll merge back the stopped queue into the + * regular queue. See iwm_ntf_stop_resume_tx() from rx.c. + */ + if (tid_info->stopped) { + IWM_DBG_TX(iwm, DBG, "%dx%d stopped\n", + tx_info->sta, tx_info->tid); + spin_lock_bh(&txq->lock); + skb_queue_tail(&txq->stopped_queue, skb); + spin_unlock_bh(&txq->lock); + + mutex_unlock(&tid_info->mutex); + continue; + } + cmdlen = IWM_UDMA_HDR_LEN + skb->len; IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: " @@ -393,13 +426,20 @@ void iwm_tx_worker(struct work_struct *work) if (ret) { IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue " "%d, Tx worker stopped\n", txq->id); + spin_lock_bh(&txq->lock); skb_queue_head(&txq->queue, skb); + spin_unlock_bh(&txq->lock); + + mutex_unlock(&tid_info->mutex); break; } txq->concat_ptr = txq->concat_buf + txq->concat_count; - iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr); + tid_info->last_seq_num = + iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr); txq->concat_count += ALIGN(cmdlen, 16); + + mutex_unlock(&tid_info->mutex); #endif kfree_skb(skb); } @@ -419,14 +459,14 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev) struct iwm_priv *iwm = ndev_to_iwm(netdev); struct net_device *ndev = iwm_to_ndev(iwm); struct wireless_dev *wdev = iwm_to_wdev(iwm); - u8 *dst_addr; struct iwm_tx_info *tx_info; struct iwm_tx_queue *txq; struct iwm_sta_info *sta_info; - u8 sta_id; + u8 *dst_addr, sta_id; u16 queue; int ret; + if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: " "not associated\n"); @@ -440,7 +480,8 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev) txq = &iwm->txq[queue]; /* No free space for Tx, tx_worker is too slow */ - if (skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) { + if ((skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) || + (skb_queue_len(&txq->stopped_queue) > IWM_TX_LIST_SIZE)) { IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue); netif_stop_subqueue(netdev, queue); return NETDEV_TX_BUSY; @@ -477,7 +518,9 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev) else tx_info->tid = IWM_UMAC_MGMT_TID; + spin_lock_bh(&iwm->txq[queue].lock); skb_queue_tail(&iwm->txq[queue].queue, skb); + spin_unlock_bh(&iwm->txq[queue].lock); queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h index be903543bb4..70094bfe7c9 100644 --- a/drivers/net/wireless/iwmc3200wifi/umac.h +++ b/drivers/net/wireless/iwmc3200wifi/umac.h @@ -83,6 +83,20 @@ struct iwm_udma_out_wifi_hdr { ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\ (UMAC_HDI_ACT_TBL_IDX_TID_LMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS)) +/* STA ID and color */ +#define STA_ID_SEED (0x0f) +#define STA_ID_POS (0) +#define STA_ID_MSK (STA_ID_SEED << STA_ID_POS) + +#define STA_COLOR_SEED (0x7) +#define STA_COLOR_POS (4) +#define STA_COLOR_MSK (STA_COLOR_SEED << STA_COLOR_POS) + +#define STA_ID_N_COLOR_COLOR(id_n_color) \ + (((id_n_color) & STA_COLOR_MSK) >> STA_COLOR_POS) +#define STA_ID_N_COLOR_ID(id_n_color) \ + (((id_n_color) & STA_ID_MSK) >> STA_ID_POS) + /* iwm_umac_notif_alive.page_grp_state Group number -- bits [3:0] */ #define UMAC_ALIVE_PAGE_STS_GRP_NUM_POS 0 #define UMAC_ALIVE_PAGE_STS_GRP_NUM_SEED 0xF @@ -260,6 +274,9 @@ struct iwm_udma_out_wifi_hdr { #define UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST 0x16 #define UMAC_CMD_OPCODE_SET_PARAM_LIST 0x17 #define UMAC_CMD_OPCODE_GET_PARAM_LIST 0x18 +#define UMAC_CMD_OPCODE_STOP_RESUME_STA_TX 0x19 +#define UMAC_CMD_OPCODE_TEST_BLOCK_ACK 0x1A + #define UMAC_CMD_OPCODE_BASE_WRAPPER 0xFA #define UMAC_CMD_OPCODE_LMAC_WRAPPER 0xFB #define UMAC_CMD_OPCODE_HW_TEST_WRAPPER 0xFC @@ -691,13 +708,13 @@ struct iwm_umac_notif_rx_ticket { #define UMAC_PHY_NUM_CHAINS 3 #define IWM_UMAC_MGMT_TID 8 -#define IWM_UMAC_TID_NR 8 +#define IWM_UMAC_TID_NR 9 /* 8 TIDs + MGMT */ struct iwm_umac_notif_stats { struct iwm_umac_wifi_in_hdr hdr; __le32 flags; __le32 timestamp; - __le16 tid_load[IWM_UMAC_TID_NR + 2]; /* 1 non-QoS + 1 dword align */ + __le16 tid_load[IWM_UMAC_TID_NR + 1]; /* 1 non-QoS + 1 dword align */ __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR]; __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR]; __le32 chain_energy[UMAC_PHY_NUM_CHAINS]; @@ -742,6 +759,19 @@ struct iwm_umac_notif_stats { __le32 roam_ap_loadblance; } __attribute__ ((packed)); +#define UMAC_STOP_TX_FLAG 0x1 +#define UMAC_RESUME_TX_FLAG 0x2 + +#define LAST_SEQ_NUM_INVALID 0xFFFF + +struct iwm_umac_notif_stop_resume_tx { + struct iwm_umac_wifi_in_hdr hdr; + u8 flags; /* UMAC_*_TX_FLAG_* */ + u8 sta_id; + __le16 stop_resume_tid_msk; /* tid bitmask */ +} __attribute__ ((packed)); + + /* WiFi interface wrapper header */ struct iwm_umac_wifi_if { u8 oid; -- cgit v1.2.3-70-g09d2 From 9bf22f2c4607dbb68beb26153d83fa52b82e2d2f Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 25 Nov 2009 00:02:26 +0100 Subject: iwmc3200wifi: Implement cfg80211 PMKSA API We need to implement the PMKSA API for proper WPA2 pre-auth and fast re-association. Our fullmac device generates all (re-)assoc IEs, and thus it needs the right PMKIDs. With this implementation we now get them from wpa_supplicant. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 31 ++++++++++++++++++++++++++++ drivers/net/wireless/iwmc3200wifi/commands.c | 22 ++++++++++++++++++++ drivers/net/wireless/iwmc3200wifi/commands.h | 13 ++++++++++++ drivers/net/wireless/iwmc3200wifi/umac.h | 2 ++ 4 files changed, 68 insertions(+) (limited to 'drivers/net/wireless/iwmc3200wifi/commands.c') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 7cfc2c0a1fb..7c4f44a9c3e 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -725,6 +725,33 @@ static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy, CFG_POWER_INDEX, iwm->conf.power_index); } +int iwm_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + + return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_ADD); +} + +int iwm_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + + return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_DEL); +} + +int iwm_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + struct cfg80211_pmksa pmksa; + + memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); + + return iwm_send_pmkid_update(iwm, &pmksa, IWM_CMD_PMKID_FLUSH); +} + + static struct cfg80211_ops iwm_cfg80211_ops = { .change_virtual_intf = iwm_cfg80211_change_iface, .add_key = iwm_cfg80211_add_key, @@ -741,6 +768,9 @@ static struct cfg80211_ops iwm_cfg80211_ops = { .set_tx_power = iwm_cfg80211_set_txpower, .get_tx_power = iwm_cfg80211_get_txpower, .set_power_mgmt = iwm_cfg80211_set_power_mgmt, + .set_pmksa = iwm_cfg80211_set_pmksa, + .del_pmksa = iwm_cfg80211_del_pmksa, + .flush_pmksa = iwm_cfg80211_flush_pmksa, }; static const u32 cipher_suites[] = { @@ -786,6 +816,7 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) set_wiphy_dev(wdev->wiphy, dev); wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX; + wdev->wiphy->max_num_pmkids = UMAC_MAX_NUM_PMKIDS; wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz; diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 46ca7c58f5a..bd0630755b3 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -960,3 +960,25 @@ int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm, sizeof(struct iwm_umac_cmd_stop_resume_tx)); } + +int iwm_send_pmkid_update(struct iwm_priv *iwm, + struct cfg80211_pmksa *pmksa, u32 command) +{ + struct iwm_umac_pmkid_update update; + int ret; + + memset(&update, 0, sizeof(struct iwm_umac_pmkid_update)); + + update.command = cpu_to_le32(command); + memcpy(&update.bssid, pmksa->bssid, ETH_ALEN); + memcpy(&update.pmkid, pmksa->pmkid, WLAN_PMKID_LEN); + + ret = iwm_send_wifi_if_cmd(iwm, &update, + sizeof(struct iwm_umac_pmkid_update), 0); + if (ret) { + IWM_ERR(iwm, "PMKID update command failed\n"); + return ret; + } + + return 0; +} diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h index 95cdf941b22..06af0552cd7 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -458,6 +458,17 @@ struct iwm_umac_cmd_stop_resume_tx { u16 reserved; } __attribute__ ((packed)); +#define IWM_CMD_PMKID_ADD 1 +#define IWM_CMD_PMKID_DEL 2 +#define IWM_CMD_PMKID_FLUSH 3 + +struct iwm_umac_pmkid_update { + __le32 command; + u8 bssid[ETH_ALEN]; + __le16 reserved; + u8 pmkid[WLAN_PMKID_LEN]; +} __attribute__ ((packed)); + /* LMAC commands */ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac); int iwm_send_prio_table(struct iwm_priv *iwm); @@ -488,6 +499,8 @@ int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len); int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm, struct iwm_umac_notif_stop_resume_tx *ntf); +int iwm_send_pmkid_update(struct iwm_priv *iwm, + struct cfg80211_pmksa *pmksa, u32 command); /* UDMA commands */ int iwm_target_reset(struct iwm_priv *iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h index 70094bfe7c9..7f54a145ca6 100644 --- a/drivers/net/wireless/iwmc3200wifi/umac.h +++ b/drivers/net/wireless/iwmc3200wifi/umac.h @@ -298,6 +298,7 @@ struct iwm_udma_out_wifi_hdr { #define UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID 0x1B #define UMAC_WIFI_IF_CMD_SET_HOST_EXTENDED_IE 0x1C #define UMAC_WIFI_IF_CMD_GET_SUPPORTED_CHANNELS 0x1E +#define UMAC_WIFI_IF_CMD_PMKID_UPDATE 0x1F #define UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER 0x20 /* UMAC WiFi interface ports */ @@ -771,6 +772,7 @@ struct iwm_umac_notif_stop_resume_tx { __le16 stop_resume_tid_msk; /* tid bitmask */ } __attribute__ ((packed)); +#define UMAC_MAX_NUM_PMKIDS 4 /* WiFi interface wrapper header */ struct iwm_umac_wifi_if { -- cgit v1.2.3-70-g09d2 From 6646a664e3b60bf3e5db676e0626e6ccd71b3363 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 1 Dec 2009 11:48:50 +0800 Subject: iwmc3200wifi: fix NULL pointer dereference in pmkid update When handling IWM_CMD_PMKID_FLUSH command, the bssid and pmkid in pmksa are all NULL. Check it before memcpy. Signed-off-by: Zhu Yi Acked-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwmc3200wifi/commands.c') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index bd0630755b3..89b33fa8d4e 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -970,8 +970,10 @@ int iwm_send_pmkid_update(struct iwm_priv *iwm, memset(&update, 0, sizeof(struct iwm_umac_pmkid_update)); update.command = cpu_to_le32(command); - memcpy(&update.bssid, pmksa->bssid, ETH_ALEN); - memcpy(&update.pmkid, pmksa->pmkid, WLAN_PMKID_LEN); + if (pmksa->bssid) + memcpy(&update.bssid, pmksa->bssid, ETH_ALEN); + if (pmksa->pmkid) + memcpy(&update.pmkid, pmksa->pmkid, WLAN_PMKID_LEN); ret = iwm_send_wifi_if_cmd(iwm, &update, sizeof(struct iwm_umac_pmkid_update), 0); -- cgit v1.2.3-70-g09d2 From f330d4f9dfd50c1870a3c4b4b3f855e78eb9ceaa Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 3 Dec 2009 11:40:15 +0100 Subject: iwmc3200wifi: Update wiwi priority table This update follows the firmware engineers recommendations. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/iwmc3200wifi/commands.c') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 89b33fa8d4e..63d20e0952e 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -122,18 +122,18 @@ static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] = { {1, 1, 0, COEX_UNASSOC_IDLE_FLAGS}, - {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, + {4, 4, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, - {5, 5, 0, COEX_CALIBRATION_FLAGS}, + {6, 6, 0, COEX_CALIBRATION_FLAGS}, {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, - {5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS}, + {6, 5, 0, COEX_CONNECTION_ESTAB_FLAGS}, {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS}, {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, {4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, {4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, {1, 1, 0, COEX_RF_ON_FLAGS}, {1, 1, 0, COEX_RF_OFF_FLAGS}, - {6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, + {7, 7, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, {5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, {1, 1, 0, COEX_RSRVD1_FLAGS}, {1, 1, 0, COEX_RSRVD2_FLAGS} -- cgit v1.2.3-70-g09d2 From 1ee9d426ff8ae8312137fc9407eff23ca81cef26 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 3 Dec 2009 11:40:16 +0100 Subject: iwmc3200wifi: Coex table command does not expect a response When sending the wiwi coexistence priority table, we should not tell the LMAC that we want a response. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwmc3200wifi/commands.c') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 63d20e0952e..f9dc4b58c49 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -192,7 +192,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm) return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD, &coex_table_cmd, - sizeof(struct iwm_coex_prio_table_cmd), 1); + sizeof(struct iwm_coex_prio_table_cmd), 0); } int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) -- cgit v1.2.3-70-g09d2 From 43b5ffe1162a7fbaa89f1c392a28ac54c2e932f7 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 3 Dec 2009 11:40:17 +0100 Subject: iwmc3200wifi: Add wifi-wimax coexistence mode as a module parameter Wifi and wimax coexistence mode is set by wifi at boot time. There can be several modes, defined by priority tables. User space components can decide which one to select by writing to /sys/module/iwmc3200wifi/parameters/wiwi with this patch, before bringing the interface up. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 12 ++++++++---- drivers/net/wireless/iwmc3200wifi/iwm.h | 1 - drivers/net/wireless/iwmc3200wifi/main.c | 1 - 3 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/iwmc3200wifi/commands.c') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index f9dc4b58c49..777584d76a8 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -99,6 +99,10 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, return ret; } +static int modparam_wiwi = COEX_MODE_CM; +module_param_named(wiwi, modparam_wiwi, int, 0644); +MODULE_PARM_DESC(wiwi, "Wifi-WiMAX coexistence: 1=SA, 2=XOR, 3=CM (default)"); + static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = { {4, 3, 0, COEX_UNASSOC_IDLE_FLAGS}, @@ -148,7 +152,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm) coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK; - switch (iwm->conf.coexist_mode) { + switch (modparam_wiwi) { case COEX_MODE_XOR: case COEX_MODE_CM: coex_enabled = 1; @@ -173,7 +177,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm) COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK | COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK; - switch (iwm->conf.coexist_mode) { + switch (modparam_wiwi) { case COEX_MODE_XOR: memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl, sizeof(iwm_sta_xor_prio_tbl)); @@ -184,7 +188,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm) break; default: IWM_ERR(iwm, "Invalid coex_mode 0x%x\n", - iwm->conf.coexist_mode); + modparam_wiwi); break; } } else @@ -396,7 +400,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags) return ret; ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_COEX_MODE, iwm->conf.coexist_mode); + CFG_COEX_MODE, modparam_wiwi); if (ret < 0) return ret; diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 8d091f918f3..5a26bb05a33 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -81,7 +81,6 @@ struct iwm_conf { u32 assoc_timeout; u32 roam_timeout; u32 wireless_mode; - u32 coexist_mode; u8 ibss_band; u8 ibss_channel; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 087f04355c1..0ffb04111a4 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -82,7 +82,6 @@ static struct iwm_conf def_iwm_conf = { .roam_timeout = 10, .wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G | WIRELESS_MODE_11N, - .coexist_mode = COEX_MODE_CM, /* IBSS */ .ibss_band = UMAC_BAND_2GHZ, -- cgit v1.2.3-70-g09d2