diff options
-rw-r--r-- | drivers/net/wireless/wl12xx/boot.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/event.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/event.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/io.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/main.c | 42 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/tx.c | 75 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/tx.h | 6 |
7 files changed, 116 insertions, 21 deletions
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 9d742c1e75a9..34bf2fe47dc7 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c | |||
@@ -482,6 +482,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) | |||
482 | 482 | ||
483 | if (wl->bss_type == BSS_TYPE_AP_BSS) | 483 | if (wl->bss_type == BSS_TYPE_AP_BSS) |
484 | wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; | 484 | wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; |
485 | else | ||
486 | wl->event_mask |= DUMMY_PACKET_EVENT_ID; | ||
485 | 487 | ||
486 | ret = wl1271_event_unmask(wl); | 488 | ret = wl1271_event_unmask(wl); |
487 | if (ret < 0) { | 489 | if (ret < 0) { |
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 1b170c5cc595..413d901985fe 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c | |||
@@ -228,6 +228,12 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) | |||
228 | wl1271_event_rssi_trigger(wl, mbox); | 228 | wl1271_event_rssi_trigger(wl, mbox); |
229 | } | 229 | } |
230 | 230 | ||
231 | if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) { | ||
232 | wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); | ||
233 | if (wl->vif) | ||
234 | wl1271_tx_dummy_packet(wl); | ||
235 | } | ||
236 | |||
231 | if (wl->vif && beacon_loss) | 237 | if (wl->vif && beacon_loss) |
232 | ieee80211_connection_loss(wl->vif); | 238 | ieee80211_connection_loss(wl->vif); |
233 | 239 | ||
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h index 0e80886f3031..b6cf06e565a4 100644 --- a/drivers/net/wireless/wl12xx/event.h +++ b/drivers/net/wireless/wl12xx/event.h | |||
@@ -59,7 +59,10 @@ enum { | |||
59 | BSS_LOSE_EVENT_ID = BIT(18), | 59 | BSS_LOSE_EVENT_ID = BIT(18), |
60 | REGAINED_BSS_EVENT_ID = BIT(19), | 60 | REGAINED_BSS_EVENT_ID = BIT(19), |
61 | ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), | 61 | ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), |
62 | STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), /* AP */ | 62 | /* STA: dummy paket for dynamic mem blocks */ |
63 | DUMMY_PACKET_EVENT_ID = BIT(21), | ||
64 | /* AP: STA remove complete */ | ||
65 | STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), | ||
63 | SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), | 66 | SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), |
64 | SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), | 67 | SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), |
65 | SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), | 68 | SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), |
diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h index 84454f6d8169..e6199eb51936 100644 --- a/drivers/net/wireless/wl12xx/io.h +++ b/drivers/net/wireless/wl12xx/io.h | |||
@@ -170,5 +170,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void); | |||
170 | int wl1271_free_hw(struct wl1271 *wl); | 170 | int wl1271_free_hw(struct wl1271 *wl); |
171 | irqreturn_t wl1271_irq(int irq, void *data); | 171 | irqreturn_t wl1271_irq(int irq, void *data); |
172 | bool wl1271_set_block_size(struct wl1271 *wl); | 172 | bool wl1271_set_block_size(struct wl1271 *wl); |
173 | int wl1271_tx_dummy_packet(struct wl1271 *wl); | ||
173 | 174 | ||
174 | #endif | 175 | #endif |
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 3c381ceadb98..54ac6757c39b 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c | |||
@@ -1174,6 +1174,48 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
1174 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 1174 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
1175 | } | 1175 | } |
1176 | 1176 | ||
1177 | #define TX_DUMMY_PACKET_SIZE 1400 | ||
1178 | int wl1271_tx_dummy_packet(struct wl1271 *wl) | ||
1179 | { | ||
1180 | struct sk_buff *skb = NULL; | ||
1181 | struct ieee80211_hdr_3addr *hdr; | ||
1182 | int ret = 0; | ||
1183 | |||
1184 | skb = dev_alloc_skb( | ||
1185 | sizeof(struct wl1271_tx_hw_descr) + sizeof(*hdr) + | ||
1186 | TX_DUMMY_PACKET_SIZE); | ||
1187 | if (!skb) { | ||
1188 | wl1271_warning("failed to allocate buffer for dummy packet"); | ||
1189 | ret = -ENOMEM; | ||
1190 | goto out; | ||
1191 | } | ||
1192 | |||
1193 | skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr)); | ||
1194 | |||
1195 | hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); | ||
1196 | memset(hdr, 0, sizeof(*hdr)); | ||
1197 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
1198 | IEEE80211_FCTL_TODS | | ||
1199 | IEEE80211_STYPE_NULLFUNC); | ||
1200 | |||
1201 | memcpy(hdr->addr1, wl->bssid, ETH_ALEN); | ||
1202 | memcpy(hdr->addr2, wl->mac_addr, ETH_ALEN); | ||
1203 | memcpy(hdr->addr3, wl->bssid, ETH_ALEN); | ||
1204 | |||
1205 | skb_put(skb, TX_DUMMY_PACKET_SIZE); | ||
1206 | |||
1207 | memset(skb->data, 0, TX_DUMMY_PACKET_SIZE); | ||
1208 | |||
1209 | skb->pkt_type = TX_PKT_TYPE_DUMMY_REQ; | ||
1210 | /* CONF_TX_AC_VO */ | ||
1211 | skb->queue_mapping = 0; | ||
1212 | |||
1213 | wl1271_op_tx(wl->hw, skb); | ||
1214 | |||
1215 | out: | ||
1216 | return ret; | ||
1217 | } | ||
1218 | |||
1177 | static struct notifier_block wl1271_dev_notifier = { | 1219 | static struct notifier_block wl1271_dev_notifier = { |
1178 | .notifier_call = wl1271_dev_notify, | 1220 | .notifier_call = wl1271_dev_notify, |
1179 | }; | 1221 | }; |
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index afc8505abeb6..75222a681296 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c | |||
@@ -215,13 +215,29 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, | |||
215 | else | 215 | else |
216 | desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); | 216 | desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); |
217 | 217 | ||
218 | /* configure the tx attributes */ | ||
219 | tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; | ||
220 | |||
221 | /* queue (we use same identifiers for tid's and ac's */ | 218 | /* queue (we use same identifiers for tid's and ac's */ |
222 | ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | 219 | ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); |
223 | desc->tid = ac; | 220 | desc->tid = ac; |
224 | 221 | ||
222 | if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { | ||
223 | /* | ||
224 | * FW expects the dummy packet to have an invalid session id - | ||
225 | * any session id that is different than the one set in the join | ||
226 | */ | ||
227 | tx_attr = ((~wl->session_counter) << | ||
228 | TX_HW_ATTR_OFST_SESSION_COUNTER) & | ||
229 | TX_HW_ATTR_SESSION_COUNTER; | ||
230 | |||
231 | tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; | ||
232 | |||
233 | /* Dummy packets require the TID to be management */ | ||
234 | desc->tid = WL1271_TID_MGMT; | ||
235 | } else { | ||
236 | /* configure the tx attributes */ | ||
237 | tx_attr = | ||
238 | wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; | ||
239 | } | ||
240 | |||
225 | if (wl->bss_type != BSS_TYPE_AP_BSS) { | 241 | if (wl->bss_type != BSS_TYPE_AP_BSS) { |
226 | desc->aid = hlid; | 242 | desc->aid = hlid; |
227 | 243 | ||
@@ -587,6 +603,12 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, | |||
587 | skb = wl->tx_frames[id]; | 603 | skb = wl->tx_frames[id]; |
588 | info = IEEE80211_SKB_CB(skb); | 604 | info = IEEE80211_SKB_CB(skb); |
589 | 605 | ||
606 | if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { | ||
607 | dev_kfree_skb(skb); | ||
608 | wl1271_free_tx_id(wl, id); | ||
609 | return; | ||
610 | } | ||
611 | |||
590 | /* update the TX status info */ | 612 | /* update the TX status info */ |
591 | if (result->status == TX_SUCCESS) { | 613 | if (result->status == TX_SUCCESS) { |
592 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) | 614 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) |
@@ -716,10 +738,15 @@ void wl1271_tx_reset(struct wl1271 *wl) | |||
716 | while ((skb = skb_dequeue(&wl->tx_queue[i]))) { | 738 | while ((skb = skb_dequeue(&wl->tx_queue[i]))) { |
717 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", | 739 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", |
718 | skb); | 740 | skb); |
719 | info = IEEE80211_SKB_CB(skb); | 741 | |
720 | info->status.rates[0].idx = -1; | 742 | if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { |
721 | info->status.rates[0].count = 0; | 743 | dev_kfree_skb(skb); |
722 | ieee80211_tx_status(wl->hw, skb); | 744 | } else { |
745 | info = IEEE80211_SKB_CB(skb); | ||
746 | info->status.rates[0].idx = -1; | ||
747 | info->status.rates[0].count = 0; | ||
748 | ieee80211_tx_status(wl->hw, skb); | ||
749 | } | ||
723 | } | 750 | } |
724 | } | 751 | } |
725 | } | 752 | } |
@@ -740,21 +767,29 @@ void wl1271_tx_reset(struct wl1271 *wl) | |||
740 | wl1271_free_tx_id(wl, i); | 767 | wl1271_free_tx_id(wl, i); |
741 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); | 768 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); |
742 | 769 | ||
743 | /* Remove private headers before passing the skb to mac80211 */ | 770 | if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { |
744 | info = IEEE80211_SKB_CB(skb); | 771 | dev_kfree_skb(skb); |
745 | skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); | 772 | } else { |
746 | if (info->control.hw_key && | 773 | /* |
747 | info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { | 774 | * Remove private headers before passing the skb to |
748 | int hdrlen = ieee80211_get_hdrlen_from_skb(skb); | 775 | * mac80211 |
749 | memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, | 776 | */ |
750 | hdrlen); | 777 | info = IEEE80211_SKB_CB(skb); |
751 | skb_pull(skb, WL1271_TKIP_IV_SPACE); | 778 | skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); |
752 | } | 779 | if (info->control.hw_key && |
780 | info->control.hw_key->cipher == | ||
781 | WLAN_CIPHER_SUITE_TKIP) { | ||
782 | int hdrlen = ieee80211_get_hdrlen_from_skb(skb); | ||
783 | memmove(skb->data + WL1271_TKIP_IV_SPACE, | ||
784 | skb->data, hdrlen); | ||
785 | skb_pull(skb, WL1271_TKIP_IV_SPACE); | ||
786 | } | ||
753 | 787 | ||
754 | info->status.rates[0].idx = -1; | 788 | info->status.rates[0].idx = -1; |
755 | info->status.rates[0].count = 0; | 789 | info->status.rates[0].count = 0; |
756 | 790 | ||
757 | ieee80211_tx_status(wl->hw, skb); | 791 | ieee80211_tx_status(wl->hw, skb); |
792 | } | ||
758 | } | 793 | } |
759 | } | 794 | } |
760 | 795 | ||
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index e31317717ab2..6f45e9108d9a 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h | |||
@@ -41,6 +41,9 @@ | |||
41 | BIT(8) | BIT(9)) | 41 | BIT(8) | BIT(9)) |
42 | #define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11)) | 42 | #define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11)) |
43 | #define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) | 43 | #define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) |
44 | #define TX_HW_ATTR_TX_DUMMY_REQ BIT(13) | ||
45 | |||
46 | #define TX_PKT_TYPE_DUMMY_REQ 5 | ||
44 | 47 | ||
45 | #define TX_HW_ATTR_OFST_SAVE_RETRIES 0 | 48 | #define TX_HW_ATTR_OFST_SAVE_RETRIES 0 |
46 | #define TX_HW_ATTR_OFST_HEADER_PAD 1 | 49 | #define TX_HW_ATTR_OFST_HEADER_PAD 1 |
@@ -55,6 +58,9 @@ | |||
55 | #define WL1271_TX_ALIGN_TO 4 | 58 | #define WL1271_TX_ALIGN_TO 4 |
56 | #define WL1271_TKIP_IV_SPACE 4 | 59 | #define WL1271_TKIP_IV_SPACE 4 |
57 | 60 | ||
61 | /* Used for management frames and dummy packets */ | ||
62 | #define WL1271_TID_MGMT 7 | ||
63 | |||
58 | struct wl127x_tx_mem { | 64 | struct wl127x_tx_mem { |
59 | /* | 65 | /* |
60 | * Number of extra memory blocks to allocate for this packet | 66 | * Number of extra memory blocks to allocate for this packet |