aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwl8k.c
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2010-01-08 12:30:58 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-12 14:02:09 -0500
commit3f5610ff560aeaccf051a6f93f25535c219599a0 (patch)
tree8c013f41bab780a944b8d1cc2727e162c7441908 /drivers/net/wireless/mwl8k.c
parent088aab8b62666a002907c912cd346ae6dc9f42b7 (diff)
mwl8k: implement AP firmware station database maintenance
STA firmware uses UPDATE_STADB to manipulate the hardware station database, whereas AP firmware uses SET_NEW_STN -- this implements the latter, and hooks it into mwl8k_sta_notify(), to be used if we're running on AP firmware. Signed-off-by: Lennert Buytenhek <buytenh@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r--drivers/net/wireless/mwl8k.c134
1 files changed, 117 insertions, 17 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index ec79033801ab..f0026f33232d 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -281,6 +281,7 @@ static const struct ieee80211_rate mwl8k_rates[] = {
281#define MWL8K_CMD_ENABLE_SNIFFER 0x0150 281#define MWL8K_CMD_ENABLE_SNIFFER 0x0150
282#define MWL8K_CMD_SET_MAC_ADDR 0x0202 282#define MWL8K_CMD_SET_MAC_ADDR 0x0202
283#define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 283#define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203
284#define MWL8K_CMD_SET_NEW_STN 0x1111
284#define MWL8K_CMD_UPDATE_STADB 0x1123 285#define MWL8K_CMD_UPDATE_STADB 0x1123
285 286
286static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) 287static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
@@ -313,6 +314,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
313 MWL8K_CMDNAME(ENABLE_SNIFFER); 314 MWL8K_CMDNAME(ENABLE_SNIFFER);
314 MWL8K_CMDNAME(SET_MAC_ADDR); 315 MWL8K_CMDNAME(SET_MAC_ADDR);
315 MWL8K_CMDNAME(SET_RATEADAPT_MODE); 316 MWL8K_CMDNAME(SET_RATEADAPT_MODE);
317 MWL8K_CMDNAME(SET_NEW_STN);
316 MWL8K_CMDNAME(UPDATE_STADB); 318 MWL8K_CMDNAME(UPDATE_STADB);
317 default: 319 default:
318 snprintf(buf, bufsize, "0x%x", cmd); 320 snprintf(buf, bufsize, "0x%x", cmd);
@@ -2660,6 +2662,90 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode)
2660} 2662}
2661 2663
2662/* 2664/*
2665 * CMD_SET_NEW_STN.
2666 */
2667struct mwl8k_cmd_set_new_stn {
2668 struct mwl8k_cmd_pkt header;
2669 __le16 aid;
2670 __u8 mac_addr[6];
2671 __le16 stn_id;
2672 __le16 action;
2673 __le16 rsvd;
2674 __le32 legacy_rates;
2675 __u8 ht_rates[4];
2676 __le16 cap_info;
2677 __le16 ht_capabilities_info;
2678 __u8 mac_ht_param_info;
2679 __u8 rev;
2680 __u8 control_channel;
2681 __u8 add_channel;
2682 __le16 op_mode;
2683 __le16 stbc;
2684 __u8 add_qos_info;
2685 __u8 is_qos_sta;
2686 __le32 fw_sta_ptr;
2687} __attribute__((packed));
2688
2689#define MWL8K_STA_ACTION_ADD 0
2690#define MWL8K_STA_ACTION_REMOVE 2
2691
2692static int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw,
2693 struct ieee80211_vif *vif,
2694 struct ieee80211_sta *sta)
2695{
2696 struct mwl8k_cmd_set_new_stn *cmd;
2697 int rc;
2698
2699 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2700 if (cmd == NULL)
2701 return -ENOMEM;
2702
2703 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN);
2704 cmd->header.length = cpu_to_le16(sizeof(*cmd));
2705 cmd->aid = cpu_to_le16(sta->aid);
2706 memcpy(cmd->mac_addr, sta->addr, ETH_ALEN);
2707 cmd->stn_id = cpu_to_le16(sta->aid);
2708 cmd->action = cpu_to_le16(MWL8K_STA_ACTION_ADD);
2709 cmd->legacy_rates = cpu_to_le32(sta->supp_rates[IEEE80211_BAND_2GHZ]);
2710 if (sta->ht_cap.ht_supported) {
2711 cmd->ht_rates[0] = sta->ht_cap.mcs.rx_mask[0];
2712 cmd->ht_rates[1] = sta->ht_cap.mcs.rx_mask[1];
2713 cmd->ht_rates[2] = sta->ht_cap.mcs.rx_mask[2];
2714 cmd->ht_rates[3] = sta->ht_cap.mcs.rx_mask[3];
2715 cmd->ht_capabilities_info = cpu_to_le16(sta->ht_cap.cap);
2716 cmd->mac_ht_param_info = (sta->ht_cap.ampdu_factor & 3) |
2717 ((sta->ht_cap.ampdu_density & 7) << 2);
2718 cmd->is_qos_sta = 1;
2719 }
2720
2721 rc = mwl8k_post_cmd(hw, &cmd->header);
2722 kfree(cmd);
2723
2724 return rc;
2725}
2726
2727static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw,
2728 struct ieee80211_vif *vif, u8 *addr)
2729{
2730 struct mwl8k_cmd_set_new_stn *cmd;
2731 int rc;
2732
2733 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2734 if (cmd == NULL)
2735 return -ENOMEM;
2736
2737 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN);
2738 cmd->header.length = cpu_to_le16(sizeof(*cmd));
2739 memcpy(cmd->mac_addr, addr, ETH_ALEN);
2740 cmd->action = cpu_to_le16(MWL8K_STA_ACTION_REMOVE);
2741
2742 rc = mwl8k_post_cmd(hw, &cmd->header);
2743 kfree(cmd);
2744
2745 return rc;
2746}
2747
2748/*
2663 * CMD_UPDATE_STADB. 2749 * CMD_UPDATE_STADB.
2664 */ 2750 */
2665struct ewc_ht_info { 2751struct ewc_ht_info {
@@ -3247,6 +3333,36 @@ struct mwl8k_sta_notify_item
3247 struct ieee80211_sta sta; 3333 struct ieee80211_sta sta;
3248}; 3334};
3249 3335
3336static void
3337mwl8k_do_sta_notify(struct ieee80211_hw *hw, struct mwl8k_sta_notify_item *s)
3338{
3339 struct mwl8k_priv *priv = hw->priv;
3340
3341 /*
3342 * STA firmware uses UPDATE_STADB, AP firmware uses SET_NEW_STN.
3343 */
3344 if (!priv->ap_fw && s->cmd == STA_NOTIFY_ADD) {
3345 int rc;
3346
3347 rc = mwl8k_cmd_update_stadb_add(hw, s->vif, &s->sta);
3348 if (rc >= 0) {
3349 struct ieee80211_sta *sta;
3350
3351 rcu_read_lock();
3352 sta = ieee80211_find_sta(s->vif, s->sta.addr);
3353 if (sta != NULL)
3354 MWL8K_STA(sta)->peer_id = rc;
3355 rcu_read_unlock();
3356 }
3357 } else if (!priv->ap_fw && s->cmd == STA_NOTIFY_REMOVE) {
3358 mwl8k_cmd_update_stadb_del(hw, s->vif, s->sta.addr);
3359 } else if (priv->ap_fw && s->cmd == STA_NOTIFY_ADD) {
3360 mwl8k_cmd_set_new_stn_add(hw, s->vif, &s->sta);
3361 } else if (priv->ap_fw && s->cmd == STA_NOTIFY_REMOVE) {
3362 mwl8k_cmd_set_new_stn_del(hw, s->vif, s->sta.addr);
3363 }
3364}
3365
3250static void mwl8k_sta_notify_worker(struct work_struct *work) 3366static void mwl8k_sta_notify_worker(struct work_struct *work)
3251{ 3367{
3252 struct mwl8k_priv *priv = 3368 struct mwl8k_priv *priv =
@@ -3263,23 +3379,7 @@ static void mwl8k_sta_notify_worker(struct work_struct *work)
3263 3379
3264 spin_unlock_bh(&priv->sta_notify_list_lock); 3380 spin_unlock_bh(&priv->sta_notify_list_lock);
3265 3381
3266 if (s->cmd == STA_NOTIFY_ADD) { 3382 mwl8k_do_sta_notify(hw, s);
3267 int rc;
3268
3269 rc = mwl8k_cmd_update_stadb_add(hw, s->vif, &s->sta);
3270 if (rc >= 0) {
3271 struct ieee80211_sta *sta;
3272
3273 rcu_read_lock();
3274 sta = ieee80211_find_sta(s->vif, s->sta.addr);
3275 if (sta != NULL)
3276 MWL8K_STA(sta)->peer_id = rc;
3277 rcu_read_unlock();
3278 }
3279 } else {
3280 mwl8k_cmd_update_stadb_del(hw, s->vif, s->sta.addr);
3281 }
3282
3283 kfree(s); 3383 kfree(s);
3284 3384
3285 spin_lock_bh(&priv->sta_notify_list_lock); 3385 spin_lock_bh(&priv->sta_notify_list_lock);