diff options
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 119 |
1 files changed, 67 insertions, 52 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ed666b7e7e41..5b5cf9357dbf 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -211,15 +211,17 @@ struct mwl8k_vif { | |||
211 | /* Local MAC address. */ | 211 | /* Local MAC address. */ |
212 | u8 mac_addr[ETH_ALEN]; | 212 | u8 mac_addr[ETH_ALEN]; |
213 | 213 | ||
214 | /* Index into station database. Returned by UPDATE_STADB. */ | ||
215 | u8 peer_id; | ||
216 | |||
217 | /* Non AMPDU sequence number assigned by driver */ | 214 | /* Non AMPDU sequence number assigned by driver */ |
218 | u16 seqno; | 215 | u16 seqno; |
219 | }; | 216 | }; |
220 | |||
221 | #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) | 217 | #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) |
222 | 218 | ||
219 | struct mwl8k_sta { | ||
220 | /* Index into station database. Returned by UPDATE_STADB. */ | ||
221 | u8 peer_id; | ||
222 | }; | ||
223 | #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) | ||
224 | |||
223 | static const struct ieee80211_channel mwl8k_channels[] = { | 225 | static const struct ieee80211_channel mwl8k_channels[] = { |
224 | { .center_freq = 2412, .hw_value = 1, }, | 226 | { .center_freq = 2412, .hw_value = 1, }, |
225 | { .center_freq = 2417, .hw_value = 2, }, | 227 | { .center_freq = 2417, .hw_value = 2, }, |
@@ -1402,7 +1404,10 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1402 | tx->pkt_phys_addr = cpu_to_le32(dma); | 1404 | tx->pkt_phys_addr = cpu_to_le32(dma); |
1403 | tx->pkt_len = cpu_to_le16(skb->len); | 1405 | tx->pkt_len = cpu_to_le16(skb->len); |
1404 | tx->rate_info = 0; | 1406 | tx->rate_info = 0; |
1405 | tx->peer_id = mwl8k_vif->peer_id; | 1407 | if (!priv->ap_fw && tx_info->control.sta != NULL) |
1408 | tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; | ||
1409 | else | ||
1410 | tx->peer_id = 0; | ||
1406 | wmb(); | 1411 | wmb(); |
1407 | tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); | 1412 | tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); |
1408 | 1413 | ||
@@ -2582,14 +2587,6 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) | |||
2582 | /* | 2587 | /* |
2583 | * CMD_UPDATE_STADB. | 2588 | * CMD_UPDATE_STADB. |
2584 | */ | 2589 | */ |
2585 | #define MWL8K_STA_DB_ADD_ENTRY 0 | ||
2586 | #define MWL8K_STA_DB_MODIFY_ENTRY 1 | ||
2587 | #define MWL8K_STA_DB_DEL_ENTRY 2 | ||
2588 | #define MWL8K_STA_DB_FLUSH 3 | ||
2589 | |||
2590 | /* Peer Entry flags - used to define the type of the peer node */ | ||
2591 | #define MWL8K_PEER_TYPE_ACCESSPOINT 2 | ||
2592 | |||
2593 | struct ewc_ht_info { | 2590 | struct ewc_ht_info { |
2594 | __le16 control1; | 2591 | __le16 control1; |
2595 | __le16 control2; | 2592 | __le16 control2; |
@@ -2640,12 +2637,17 @@ struct mwl8k_cmd_update_stadb { | |||
2640 | struct peer_capability_info peer_info; | 2637 | struct peer_capability_info peer_info; |
2641 | } __attribute__((packed)); | 2638 | } __attribute__((packed)); |
2642 | 2639 | ||
2643 | static int mwl8k_cmd_update_stadb(struct ieee80211_hw *hw, | 2640 | #define MWL8K_STA_DB_MODIFY_ENTRY 1 |
2644 | struct ieee80211_vif *vif, __u32 action, u8 *addr) | 2641 | #define MWL8K_STA_DB_DEL_ENTRY 2 |
2642 | |||
2643 | /* Peer Entry flags - used to define the type of the peer node */ | ||
2644 | #define MWL8K_PEER_TYPE_ACCESSPOINT 2 | ||
2645 | |||
2646 | static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, | ||
2647 | struct ieee80211_vif *vif, u8 *addr) | ||
2645 | { | 2648 | { |
2646 | struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); | ||
2647 | struct mwl8k_cmd_update_stadb *cmd; | 2649 | struct mwl8k_cmd_update_stadb *cmd; |
2648 | struct peer_capability_info *peer_info; | 2650 | struct peer_capability_info *p; |
2649 | int rc; | 2651 | int rc; |
2650 | 2652 | ||
2651 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | 2653 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
@@ -2654,37 +2656,38 @@ static int mwl8k_cmd_update_stadb(struct ieee80211_hw *hw, | |||
2654 | 2656 | ||
2655 | cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); | 2657 | cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); |
2656 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | 2658 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
2659 | cmd->action = cpu_to_le32(MWL8K_STA_DB_MODIFY_ENTRY); | ||
2660 | memcpy(cmd->peer_addr, addr, ETH_ALEN); | ||
2657 | 2661 | ||
2658 | cmd->action = cpu_to_le32(action); | 2662 | p = &cmd->peer_info; |
2659 | peer_info = &cmd->peer_info; | 2663 | p->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; |
2664 | p->basic_caps = cpu_to_le16(vif->bss_conf.assoc_capability); | ||
2665 | memcpy(p->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids)); | ||
2666 | p->interop = 1; | ||
2667 | p->amsdu_enabled = 0; | ||
2668 | |||
2669 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
2670 | kfree(cmd); | ||
2671 | |||
2672 | return rc ? rc : p->station_id; | ||
2673 | } | ||
2674 | |||
2675 | static int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw, | ||
2676 | struct ieee80211_vif *vif, u8 *addr) | ||
2677 | { | ||
2678 | struct mwl8k_cmd_update_stadb *cmd; | ||
2679 | int rc; | ||
2680 | |||
2681 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
2682 | if (cmd == NULL) | ||
2683 | return -ENOMEM; | ||
2684 | |||
2685 | cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); | ||
2686 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
2687 | cmd->action = cpu_to_le32(MWL8K_STA_DB_DEL_ENTRY); | ||
2660 | memcpy(cmd->peer_addr, addr, ETH_ALEN); | 2688 | memcpy(cmd->peer_addr, addr, ETH_ALEN); |
2661 | 2689 | ||
2662 | switch (action) { | 2690 | rc = mwl8k_post_cmd(hw, &cmd->header); |
2663 | case MWL8K_STA_DB_ADD_ENTRY: | ||
2664 | case MWL8K_STA_DB_MODIFY_ENTRY: | ||
2665 | /* Build peer_info block */ | ||
2666 | peer_info->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; | ||
2667 | peer_info->basic_caps = | ||
2668 | cpu_to_le16(vif->bss_conf.assoc_capability); | ||
2669 | memcpy(peer_info->legacy_rates, mwl8k_rateids, | ||
2670 | sizeof(mwl8k_rateids)); | ||
2671 | peer_info->interop = 1; | ||
2672 | peer_info->amsdu_enabled = 0; | ||
2673 | |||
2674 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
2675 | if (rc == 0) | ||
2676 | mv_vif->peer_id = peer_info->station_id; | ||
2677 | |||
2678 | break; | ||
2679 | |||
2680 | case MWL8K_STA_DB_DEL_ENTRY: | ||
2681 | case MWL8K_STA_DB_FLUSH: | ||
2682 | default: | ||
2683 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
2684 | if (rc == 0) | ||
2685 | mv_vif->peer_id = 0; | ||
2686 | break; | ||
2687 | } | ||
2688 | kfree(cmd); | 2691 | kfree(cmd); |
2689 | 2692 | ||
2690 | return rc; | 2693 | return rc; |
@@ -3142,11 +3145,11 @@ static void mwl8k_sta_notify_worker(struct work_struct *work) | |||
3142 | { | 3145 | { |
3143 | struct mwl8k_priv *priv = | 3146 | struct mwl8k_priv *priv = |
3144 | container_of(work, struct mwl8k_priv, sta_notify_worker); | 3147 | container_of(work, struct mwl8k_priv, sta_notify_worker); |
3148 | struct ieee80211_hw *hw = priv->hw; | ||
3145 | 3149 | ||
3146 | spin_lock_bh(&priv->sta_notify_list_lock); | 3150 | spin_lock_bh(&priv->sta_notify_list_lock); |
3147 | while (!list_empty(&priv->sta_notify_list)) { | 3151 | while (!list_empty(&priv->sta_notify_list)) { |
3148 | struct mwl8k_sta_notify_item *s; | 3152 | struct mwl8k_sta_notify_item *s; |
3149 | int action; | ||
3150 | 3153 | ||
3151 | s = list_entry(priv->sta_notify_list.next, | 3154 | s = list_entry(priv->sta_notify_list.next, |
3152 | struct mwl8k_sta_notify_item, list); | 3155 | struct mwl8k_sta_notify_item, list); |
@@ -3154,11 +3157,22 @@ static void mwl8k_sta_notify_worker(struct work_struct *work) | |||
3154 | 3157 | ||
3155 | spin_unlock_bh(&priv->sta_notify_list_lock); | 3158 | spin_unlock_bh(&priv->sta_notify_list_lock); |
3156 | 3159 | ||
3157 | if (s->cmd == STA_NOTIFY_ADD) | 3160 | if (s->cmd == STA_NOTIFY_ADD) { |
3158 | action = MWL8K_STA_DB_MODIFY_ENTRY; | 3161 | int rc; |
3159 | else | 3162 | |
3160 | action = MWL8K_STA_DB_DEL_ENTRY; | 3163 | rc = mwl8k_cmd_update_stadb_add(hw, s->vif, s->addr); |
3161 | mwl8k_cmd_update_stadb(priv->hw, s->vif, action, s->addr); | 3164 | if (rc >= 0) { |
3165 | struct ieee80211_sta *sta; | ||
3166 | |||
3167 | rcu_read_lock(); | ||
3168 | sta = ieee80211_find_sta(s->vif, s->addr); | ||
3169 | if (sta != NULL) | ||
3170 | MWL8K_STA(sta)->peer_id = rc; | ||
3171 | rcu_read_unlock(); | ||
3172 | } | ||
3173 | } else { | ||
3174 | mwl8k_cmd_update_stadb_del(hw, s->vif, s->addr); | ||
3175 | } | ||
3162 | 3176 | ||
3163 | kfree(s); | 3177 | kfree(s); |
3164 | 3178 | ||
@@ -3448,6 +3462,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
3448 | /* Set rssi and noise values to dBm */ | 3462 | /* Set rssi and noise values to dBm */ |
3449 | hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; | 3463 | hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; |
3450 | hw->vif_data_size = sizeof(struct mwl8k_vif); | 3464 | hw->vif_data_size = sizeof(struct mwl8k_vif); |
3465 | hw->sta_data_size = sizeof(struct mwl8k_sta); | ||
3451 | priv->vif = NULL; | 3466 | priv->vif = NULL; |
3452 | 3467 | ||
3453 | /* Set default radio state and preamble */ | 3468 | /* Set default radio state and preamble */ |