diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2010-01-08 12:30:58 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-01-12 14:02:09 -0500 |
commit | 3f5610ff560aeaccf051a6f93f25535c219599a0 (patch) | |
tree | 8c013f41bab780a944b8d1cc2727e162c7441908 /drivers/net/wireless/mwl8k.c | |
parent | 088aab8b62666a002907c912cd346ae6dc9f42b7 (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.c | 134 |
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 | ||
286 | static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) | 287 | static 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 | */ | ||
2667 | struct 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 | |||
2692 | static 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 | |||
2727 | static 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 | */ |
2665 | struct ewc_ht_info { | 2751 | struct 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 | ||
3336 | static void | ||
3337 | mwl8k_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 | |||
3250 | static void mwl8k_sta_notify_worker(struct work_struct *work) | 3366 | static 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); |