diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r-- | drivers/net/wireless/wl12xx/acx.c | 28 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/acx.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/init.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/main.c | 151 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/ps.c | 78 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/ps.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/rx.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/rx.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/tx.c | 237 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/tx.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl12xx.h | 37 |
11 files changed, 479 insertions, 80 deletions
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 33840d95d17d..3badc6bb7866 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c | |||
@@ -1328,10 +1328,9 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, | |||
1328 | /* get data from A-MPDU parameters field */ | 1328 | /* get data from A-MPDU parameters field */ |
1329 | acx->ampdu_max_length = ht_cap->ampdu_factor; | 1329 | acx->ampdu_max_length = ht_cap->ampdu_factor; |
1330 | acx->ampdu_min_spacing = ht_cap->ampdu_density; | 1330 | acx->ampdu_min_spacing = ht_cap->ampdu_density; |
1331 | |||
1332 | memcpy(acx->mac_address, mac_address, ETH_ALEN); | ||
1333 | } | 1331 | } |
1334 | 1332 | ||
1333 | memcpy(acx->mac_address, mac_address, ETH_ALEN); | ||
1335 | acx->ht_capabilites = cpu_to_le32(ht_capabilites); | 1334 | acx->ht_capabilites = cpu_to_le32(ht_capabilites); |
1336 | 1335 | ||
1337 | ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); | 1336 | ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); |
@@ -1542,3 +1541,28 @@ out: | |||
1542 | kfree(config_ps); | 1541 | kfree(config_ps); |
1543 | return ret; | 1542 | return ret; |
1544 | } | 1543 | } |
1544 | |||
1545 | int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr) | ||
1546 | { | ||
1547 | struct wl1271_acx_inconnection_sta *acx = NULL; | ||
1548 | int ret; | ||
1549 | |||
1550 | wl1271_debug(DEBUG_ACX, "acx set inconnaction sta %pM", addr); | ||
1551 | |||
1552 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1553 | if (!acx) | ||
1554 | return -ENOMEM; | ||
1555 | |||
1556 | memcpy(acx->addr, addr, ETH_ALEN); | ||
1557 | |||
1558 | ret = wl1271_cmd_configure(wl, ACX_UPDATE_INCONNECTION_STA_LIST, | ||
1559 | acx, sizeof(*acx)); | ||
1560 | if (ret < 0) { | ||
1561 | wl1271_warning("acx set inconnaction sta failed: %d", ret); | ||
1562 | goto out; | ||
1563 | } | ||
1564 | |||
1565 | out: | ||
1566 | kfree(acx); | ||
1567 | return ret; | ||
1568 | } | ||
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 4e301de916bb..dd19b01d807b 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h | |||
@@ -1155,6 +1155,13 @@ struct wl1271_acx_config_ps { | |||
1155 | __le32 null_data_rate; | 1155 | __le32 null_data_rate; |
1156 | } __packed; | 1156 | } __packed; |
1157 | 1157 | ||
1158 | struct wl1271_acx_inconnection_sta { | ||
1159 | struct acx_header header; | ||
1160 | |||
1161 | u8 addr[ETH_ALEN]; | ||
1162 | u8 padding1[2]; | ||
1163 | } __packed; | ||
1164 | |||
1158 | enum { | 1165 | enum { |
1159 | ACX_WAKE_UP_CONDITIONS = 0x0002, | 1166 | ACX_WAKE_UP_CONDITIONS = 0x0002, |
1160 | ACX_MEM_CFG = 0x0003, | 1167 | ACX_MEM_CFG = 0x0003, |
@@ -1215,6 +1222,7 @@ enum { | |||
1215 | ACX_GEN_FW_CMD = 0x0070, | 1222 | ACX_GEN_FW_CMD = 0x0070, |
1216 | ACX_HOST_IF_CFG_BITMAP = 0x0071, | 1223 | ACX_HOST_IF_CFG_BITMAP = 0x0071, |
1217 | ACX_MAX_TX_FAILURE = 0x0072, | 1224 | ACX_MAX_TX_FAILURE = 0x0072, |
1225 | ACX_UPDATE_INCONNECTION_STA_LIST = 0x0073, | ||
1218 | DOT11_RX_MSDU_LIFE_TIME = 0x1004, | 1226 | DOT11_RX_MSDU_LIFE_TIME = 0x1004, |
1219 | DOT11_CUR_TX_PWR = 0x100D, | 1227 | DOT11_CUR_TX_PWR = 0x100D, |
1220 | DOT11_RX_DOT11_MODE = 0x1012, | 1228 | DOT11_RX_DOT11_MODE = 0x1012, |
@@ -1290,5 +1298,6 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, | |||
1290 | int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); | 1298 | int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); |
1291 | int wl1271_acx_max_tx_retry(struct wl1271 *wl); | 1299 | int wl1271_acx_max_tx_retry(struct wl1271 *wl); |
1292 | int wl1271_acx_config_ps(struct wl1271 *wl); | 1300 | int wl1271_acx_config_ps(struct wl1271 *wl); |
1301 | int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); | ||
1293 | 1302 | ||
1294 | #endif /* __WL1271_ACX_H__ */ | 1303 | #endif /* __WL1271_ACX_H__ */ |
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 62dc9839dd31..6072fe457135 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c | |||
@@ -483,7 +483,7 @@ static void wl1271_check_ba_support(struct wl1271 *wl) | |||
483 | static int wl1271_set_ba_policies(struct wl1271 *wl) | 483 | static int wl1271_set_ba_policies(struct wl1271 *wl) |
484 | { | 484 | { |
485 | u8 tid_index; | 485 | u8 tid_index; |
486 | u8 ret = 0; | 486 | int ret = 0; |
487 | 487 | ||
488 | /* Reset the BA RX indicators */ | 488 | /* Reset the BA RX indicators */ |
489 | wl->ba_rx_bitmap = 0; | 489 | wl->ba_rx_bitmap = 0; |
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 61dea73f5fdc..947491a1d9cc 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c | |||
@@ -482,6 +482,10 @@ static int wl1271_plt_init(struct wl1271 *wl) | |||
482 | if (ret < 0) | 482 | if (ret < 0) |
483 | goto out_free_memmap; | 483 | goto out_free_memmap; |
484 | 484 | ||
485 | ret = wl1271_acx_sta_mem_cfg(wl); | ||
486 | if (ret < 0) | ||
487 | goto out_free_memmap; | ||
488 | |||
485 | /* Default fragmentation threshold */ | 489 | /* Default fragmentation threshold */ |
486 | ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold); | 490 | ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold); |
487 | if (ret < 0) | 491 | if (ret < 0) |
@@ -533,6 +537,57 @@ static int wl1271_plt_init(struct wl1271 *wl) | |||
533 | return ret; | 537 | return ret; |
534 | } | 538 | } |
535 | 539 | ||
540 | static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks) | ||
541 | { | ||
542 | bool fw_ps; | ||
543 | |||
544 | /* only regulate station links */ | ||
545 | if (hlid < WL1271_AP_STA_HLID_START) | ||
546 | return; | ||
547 | |||
548 | fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); | ||
549 | |||
550 | /* | ||
551 | * Wake up from high level PS if the STA is asleep with too little | ||
552 | * blocks in FW or if the STA is awake. | ||
553 | */ | ||
554 | if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS) | ||
555 | wl1271_ps_link_end(wl, hlid); | ||
556 | |||
557 | /* Start high-level PS if the STA is asleep with enough blocks in FW */ | ||
558 | else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS) | ||
559 | wl1271_ps_link_start(wl, hlid, true); | ||
560 | } | ||
561 | |||
562 | static void wl1271_irq_update_links_status(struct wl1271 *wl, | ||
563 | struct wl1271_fw_ap_status *status) | ||
564 | { | ||
565 | u32 cur_fw_ps_map; | ||
566 | u8 hlid; | ||
567 | |||
568 | cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap); | ||
569 | if (wl->ap_fw_ps_map != cur_fw_ps_map) { | ||
570 | wl1271_debug(DEBUG_PSM, | ||
571 | "link ps prev 0x%x cur 0x%x changed 0x%x", | ||
572 | wl->ap_fw_ps_map, cur_fw_ps_map, | ||
573 | wl->ap_fw_ps_map ^ cur_fw_ps_map); | ||
574 | |||
575 | wl->ap_fw_ps_map = cur_fw_ps_map; | ||
576 | } | ||
577 | |||
578 | for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) { | ||
579 | u8 cnt = status->tx_lnk_free_blks[hlid] - | ||
580 | wl->links[hlid].prev_freed_blks; | ||
581 | |||
582 | wl->links[hlid].prev_freed_blks = | ||
583 | status->tx_lnk_free_blks[hlid]; | ||
584 | wl->links[hlid].allocated_blks -= cnt; | ||
585 | |||
586 | wl1271_irq_ps_regulate_link(wl, hlid, | ||
587 | wl->links[hlid].allocated_blks); | ||
588 | } | ||
589 | } | ||
590 | |||
536 | static void wl1271_fw_status(struct wl1271 *wl, | 591 | static void wl1271_fw_status(struct wl1271 *wl, |
537 | struct wl1271_fw_full_status *full_status) | 592 | struct wl1271_fw_full_status *full_status) |
538 | { | 593 | { |
@@ -570,6 +625,10 @@ static void wl1271_fw_status(struct wl1271 *wl, | |||
570 | if (total) | 625 | if (total) |
571 | clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); | 626 | clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); |
572 | 627 | ||
628 | /* for AP update num of allocated TX blocks per link and ps status */ | ||
629 | if (wl->bss_type == BSS_TYPE_AP_BSS) | ||
630 | wl1271_irq_update_links_status(wl, &full_status->ap); | ||
631 | |||
573 | /* update the host-chipset time offset */ | 632 | /* update the host-chipset time offset */ |
574 | getnstimeofday(&ts); | 633 | getnstimeofday(&ts); |
575 | wl->time_offset = (timespec_to_ns(&ts) >> 10) - | 634 | wl->time_offset = (timespec_to_ns(&ts) >> 10) - |
@@ -975,19 +1034,37 @@ int wl1271_plt_stop(struct wl1271 *wl) | |||
975 | return ret; | 1034 | return ret; |
976 | } | 1035 | } |
977 | 1036 | ||
978 | static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | 1037 | static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) |
979 | { | 1038 | { |
980 | struct wl1271 *wl = hw->priv; | 1039 | struct wl1271 *wl = hw->priv; |
981 | unsigned long flags; | 1040 | unsigned long flags; |
982 | int q; | 1041 | int q; |
1042 | u8 hlid = 0; | ||
983 | 1043 | ||
984 | spin_lock_irqsave(&wl->wl_lock, flags); | 1044 | spin_lock_irqsave(&wl->wl_lock, flags); |
985 | wl->tx_queue_count++; | 1045 | wl->tx_queue_count++; |
1046 | |||
1047 | /* | ||
1048 | * The workqueue is slow to process the tx_queue and we need stop | ||
1049 | * the queue here, otherwise the queue will get too long. | ||
1050 | */ | ||
1051 | if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) { | ||
1052 | wl1271_debug(DEBUG_TX, "op_tx: stopping queues"); | ||
1053 | ieee80211_stop_queues(wl->hw); | ||
1054 | set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); | ||
1055 | } | ||
1056 | |||
986 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 1057 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
987 | 1058 | ||
988 | /* queue the packet */ | 1059 | /* queue the packet */ |
989 | q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | 1060 | q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); |
990 | skb_queue_tail(&wl->tx_queue[q], skb); | 1061 | if (wl->bss_type == BSS_TYPE_AP_BSS) { |
1062 | hlid = wl1271_tx_get_hlid(skb); | ||
1063 | wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q); | ||
1064 | skb_queue_tail(&wl->links[hlid].tx_queue[q], skb); | ||
1065 | } else { | ||
1066 | skb_queue_tail(&wl->tx_queue[q], skb); | ||
1067 | } | ||
991 | 1068 | ||
992 | /* | 1069 | /* |
993 | * The chip specific setup must run before the first TX packet - | 1070 | * The chip specific setup must run before the first TX packet - |
@@ -996,21 +1073,6 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
996 | 1073 | ||
997 | if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) | 1074 | if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) |
998 | ieee80211_queue_work(wl->hw, &wl->tx_work); | 1075 | ieee80211_queue_work(wl->hw, &wl->tx_work); |
999 | |||
1000 | /* | ||
1001 | * The workqueue is slow to process the tx_queue and we need stop | ||
1002 | * the queue here, otherwise the queue will get too long. | ||
1003 | */ | ||
1004 | if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) { | ||
1005 | wl1271_debug(DEBUG_TX, "op_tx: stopping queues"); | ||
1006 | |||
1007 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
1008 | ieee80211_stop_queues(wl->hw); | ||
1009 | set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); | ||
1010 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
1011 | } | ||
1012 | |||
1013 | return NETDEV_TX_OK; | ||
1014 | } | 1076 | } |
1015 | 1077 | ||
1016 | static struct notifier_block wl1271_dev_notifier = { | 1078 | static struct notifier_block wl1271_dev_notifier = { |
@@ -1221,6 +1283,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) | |||
1221 | wl->filters = 0; | 1283 | wl->filters = 0; |
1222 | wl1271_free_ap_keys(wl); | 1284 | wl1271_free_ap_keys(wl); |
1223 | memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); | 1285 | memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); |
1286 | wl->ap_fw_ps_map = 0; | ||
1287 | wl->ap_ps_map = 0; | ||
1224 | 1288 | ||
1225 | for (i = 0; i < NUM_TX_QUEUES; i++) | 1289 | for (i = 0; i < NUM_TX_QUEUES; i++) |
1226 | wl->tx_blocks_freed[i] = 0; | 1290 | wl->tx_blocks_freed[i] = 0; |
@@ -2218,6 +2282,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, | |||
2218 | u32 sta_rate_set = 0; | 2282 | u32 sta_rate_set = 0; |
2219 | int ret; | 2283 | int ret; |
2220 | struct ieee80211_sta *sta; | 2284 | struct ieee80211_sta *sta; |
2285 | bool sta_exists = false; | ||
2286 | struct ieee80211_sta_ht_cap sta_ht_cap; | ||
2221 | 2287 | ||
2222 | if (is_ibss) { | 2288 | if (is_ibss) { |
2223 | ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, | 2289 | ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, |
@@ -2289,16 +2355,20 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, | |||
2289 | if (sta->ht_cap.ht_supported) | 2355 | if (sta->ht_cap.ht_supported) |
2290 | sta_rate_set |= | 2356 | sta_rate_set |= |
2291 | (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET); | 2357 | (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET); |
2358 | sta_ht_cap = sta->ht_cap; | ||
2359 | sta_exists = true; | ||
2360 | } | ||
2361 | rcu_read_unlock(); | ||
2292 | 2362 | ||
2363 | if (sta_exists) { | ||
2293 | /* handle new association with HT and HT information change */ | 2364 | /* handle new association with HT and HT information change */ |
2294 | if ((changed & BSS_CHANGED_HT) && | 2365 | if ((changed & BSS_CHANGED_HT) && |
2295 | (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { | 2366 | (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { |
2296 | ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, | 2367 | ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap, |
2297 | true); | 2368 | true); |
2298 | if (ret < 0) { | 2369 | if (ret < 0) { |
2299 | wl1271_warning("Set ht cap true failed %d", | 2370 | wl1271_warning("Set ht cap true failed %d", |
2300 | ret); | 2371 | ret); |
2301 | rcu_read_unlock(); | ||
2302 | goto out; | 2372 | goto out; |
2303 | } | 2373 | } |
2304 | ret = wl1271_acx_set_ht_information(wl, | 2374 | ret = wl1271_acx_set_ht_information(wl, |
@@ -2306,23 +2376,20 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, | |||
2306 | if (ret < 0) { | 2376 | if (ret < 0) { |
2307 | wl1271_warning("Set ht information failed %d", | 2377 | wl1271_warning("Set ht information failed %d", |
2308 | ret); | 2378 | ret); |
2309 | rcu_read_unlock(); | ||
2310 | goto out; | 2379 | goto out; |
2311 | } | 2380 | } |
2312 | } | 2381 | } |
2313 | /* handle new association without HT and disassociation */ | 2382 | /* handle new association without HT and disassociation */ |
2314 | else if (changed & BSS_CHANGED_ASSOC) { | 2383 | else if (changed & BSS_CHANGED_ASSOC) { |
2315 | ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, | 2384 | ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap, |
2316 | false); | 2385 | false); |
2317 | if (ret < 0) { | 2386 | if (ret < 0) { |
2318 | wl1271_warning("Set ht cap false failed %d", | 2387 | wl1271_warning("Set ht cap false failed %d", |
2319 | ret); | 2388 | ret); |
2320 | rcu_read_unlock(); | ||
2321 | goto out; | 2389 | goto out; |
2322 | } | 2390 | } |
2323 | } | 2391 | } |
2324 | } | 2392 | } |
2325 | rcu_read_unlock(); | ||
2326 | 2393 | ||
2327 | if ((changed & BSS_CHANGED_ASSOC)) { | 2394 | if ((changed & BSS_CHANGED_ASSOC)) { |
2328 | if (bss_conf->assoc) { | 2395 | if (bss_conf->assoc) { |
@@ -2612,7 +2679,7 @@ static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx, | |||
2612 | return 0; | 2679 | return 0; |
2613 | } | 2680 | } |
2614 | 2681 | ||
2615 | static int wl1271_allocate_hlid(struct wl1271 *wl, | 2682 | static int wl1271_allocate_sta(struct wl1271 *wl, |
2616 | struct ieee80211_sta *sta, | 2683 | struct ieee80211_sta *sta, |
2617 | u8 *hlid) | 2684 | u8 *hlid) |
2618 | { | 2685 | { |
@@ -2626,18 +2693,25 @@ static int wl1271_allocate_hlid(struct wl1271 *wl, | |||
2626 | } | 2693 | } |
2627 | 2694 | ||
2628 | wl_sta = (struct wl1271_station *)sta->drv_priv; | 2695 | wl_sta = (struct wl1271_station *)sta->drv_priv; |
2629 | |||
2630 | __set_bit(id, wl->ap_hlid_map); | 2696 | __set_bit(id, wl->ap_hlid_map); |
2631 | wl_sta->hlid = WL1271_AP_STA_HLID_START + id; | 2697 | wl_sta->hlid = WL1271_AP_STA_HLID_START + id; |
2632 | *hlid = wl_sta->hlid; | 2698 | *hlid = wl_sta->hlid; |
2699 | memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN); | ||
2633 | return 0; | 2700 | return 0; |
2634 | } | 2701 | } |
2635 | 2702 | ||
2636 | static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid) | 2703 | static void wl1271_free_sta(struct wl1271 *wl, u8 hlid) |
2637 | { | 2704 | { |
2638 | int id = hlid - WL1271_AP_STA_HLID_START; | 2705 | int id = hlid - WL1271_AP_STA_HLID_START; |
2639 | 2706 | ||
2707 | if (WARN_ON(!test_bit(id, wl->ap_hlid_map))) | ||
2708 | return; | ||
2709 | |||
2640 | __clear_bit(id, wl->ap_hlid_map); | 2710 | __clear_bit(id, wl->ap_hlid_map); |
2711 | memset(wl->links[hlid].addr, 0, ETH_ALEN); | ||
2712 | wl1271_tx_reset_link_queues(wl, hlid); | ||
2713 | __clear_bit(hlid, &wl->ap_ps_map); | ||
2714 | __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); | ||
2641 | } | 2715 | } |
2642 | 2716 | ||
2643 | static int wl1271_op_sta_add(struct ieee80211_hw *hw, | 2717 | static int wl1271_op_sta_add(struct ieee80211_hw *hw, |
@@ -2658,13 +2732,13 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw, | |||
2658 | 2732 | ||
2659 | wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid); | 2733 | wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid); |
2660 | 2734 | ||
2661 | ret = wl1271_allocate_hlid(wl, sta, &hlid); | 2735 | ret = wl1271_allocate_sta(wl, sta, &hlid); |
2662 | if (ret < 0) | 2736 | if (ret < 0) |
2663 | goto out; | 2737 | goto out; |
2664 | 2738 | ||
2665 | ret = wl1271_ps_elp_wakeup(wl, false); | 2739 | ret = wl1271_ps_elp_wakeup(wl, false); |
2666 | if (ret < 0) | 2740 | if (ret < 0) |
2667 | goto out; | 2741 | goto out_free_sta; |
2668 | 2742 | ||
2669 | ret = wl1271_cmd_add_sta(wl, sta, hlid); | 2743 | ret = wl1271_cmd_add_sta(wl, sta, hlid); |
2670 | if (ret < 0) | 2744 | if (ret < 0) |
@@ -2673,6 +2747,10 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw, | |||
2673 | out_sleep: | 2747 | out_sleep: |
2674 | wl1271_ps_elp_sleep(wl); | 2748 | wl1271_ps_elp_sleep(wl); |
2675 | 2749 | ||
2750 | out_free_sta: | ||
2751 | if (ret < 0) | ||
2752 | wl1271_free_sta(wl, hlid); | ||
2753 | |||
2676 | out: | 2754 | out: |
2677 | mutex_unlock(&wl->mutex); | 2755 | mutex_unlock(&wl->mutex); |
2678 | return ret; | 2756 | return ret; |
@@ -2709,7 +2787,7 @@ static int wl1271_op_sta_remove(struct ieee80211_hw *hw, | |||
2709 | if (ret < 0) | 2787 | if (ret < 0) |
2710 | goto out_sleep; | 2788 | goto out_sleep; |
2711 | 2789 | ||
2712 | wl1271_free_hlid(wl, wl_sta->hlid); | 2790 | wl1271_free_sta(wl, wl_sta->hlid); |
2713 | 2791 | ||
2714 | out_sleep: | 2792 | out_sleep: |
2715 | wl1271_ps_elp_sleep(wl); | 2793 | wl1271_ps_elp_sleep(wl); |
@@ -3212,7 +3290,9 @@ int wl1271_init_ieee80211(struct wl1271 *wl) | |||
3212 | IEEE80211_HW_SUPPORTS_UAPSD | | 3290 | IEEE80211_HW_SUPPORTS_UAPSD | |
3213 | IEEE80211_HW_HAS_RATE_CONTROL | | 3291 | IEEE80211_HW_HAS_RATE_CONTROL | |
3214 | IEEE80211_HW_CONNECTION_MONITOR | | 3292 | IEEE80211_HW_CONNECTION_MONITOR | |
3215 | IEEE80211_HW_SUPPORTS_CQM_RSSI; | 3293 | IEEE80211_HW_SUPPORTS_CQM_RSSI | |
3294 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | ||
3295 | IEEE80211_HW_AP_LINK_PS; | ||
3216 | 3296 | ||
3217 | wl->hw->wiphy->cipher_suites = cipher_suites; | 3297 | wl->hw->wiphy->cipher_suites = cipher_suites; |
3218 | wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | 3298 | wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); |
@@ -3264,7 +3344,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) | |||
3264 | struct ieee80211_hw *hw; | 3344 | struct ieee80211_hw *hw; |
3265 | struct platform_device *plat_dev = NULL; | 3345 | struct platform_device *plat_dev = NULL; |
3266 | struct wl1271 *wl; | 3346 | struct wl1271 *wl; |
3267 | int i, ret; | 3347 | int i, j, ret; |
3268 | unsigned int order; | 3348 | unsigned int order; |
3269 | 3349 | ||
3270 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); | 3350 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); |
@@ -3292,6 +3372,10 @@ struct ieee80211_hw *wl1271_alloc_hw(void) | |||
3292 | for (i = 0; i < NUM_TX_QUEUES; i++) | 3372 | for (i = 0; i < NUM_TX_QUEUES; i++) |
3293 | skb_queue_head_init(&wl->tx_queue[i]); | 3373 | skb_queue_head_init(&wl->tx_queue[i]); |
3294 | 3374 | ||
3375 | for (i = 0; i < NUM_TX_QUEUES; i++) | ||
3376 | for (j = 0; j < AP_MAX_LINKS; j++) | ||
3377 | skb_queue_head_init(&wl->links[j].tx_queue[i]); | ||
3378 | |||
3295 | INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); | 3379 | INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); |
3296 | INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work); | 3380 | INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work); |
3297 | INIT_WORK(&wl->irq_work, wl1271_irq_work); | 3381 | INIT_WORK(&wl->irq_work, wl1271_irq_work); |
@@ -3317,6 +3401,9 @@ struct ieee80211_hw *wl1271_alloc_hw(void) | |||
3317 | wl->bss_type = MAX_BSS_TYPE; | 3401 | wl->bss_type = MAX_BSS_TYPE; |
3318 | wl->set_bss_type = MAX_BSS_TYPE; | 3402 | wl->set_bss_type = MAX_BSS_TYPE; |
3319 | wl->fw_bss_type = MAX_BSS_TYPE; | 3403 | wl->fw_bss_type = MAX_BSS_TYPE; |
3404 | wl->last_tx_hlid = 0; | ||
3405 | wl->ap_ps_map = 0; | ||
3406 | wl->ap_fw_ps_map = 0; | ||
3320 | 3407 | ||
3321 | memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); | 3408 | memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); |
3322 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) | 3409 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) |
@@ -3412,5 +3499,5 @@ module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR); | |||
3412 | MODULE_PARM_DESC(debug_level, "wl12xx debugging level"); | 3499 | MODULE_PARM_DESC(debug_level, "wl12xx debugging level"); |
3413 | 3500 | ||
3414 | MODULE_LICENSE("GPL"); | 3501 | MODULE_LICENSE("GPL"); |
3415 | MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); | 3502 | MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); |
3416 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); | 3503 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); |
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index 2d3086ae6338..5c347b1bd17f 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "reg.h" | 24 | #include "reg.h" |
25 | #include "ps.h" | 25 | #include "ps.h" |
26 | #include "io.h" | 26 | #include "io.h" |
27 | #include "tx.h" | ||
27 | 28 | ||
28 | #define WL1271_WAKEUP_TIMEOUT 500 | 29 | #define WL1271_WAKEUP_TIMEOUT 500 |
29 | 30 | ||
@@ -173,4 +174,81 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, | |||
173 | return ret; | 174 | return ret; |
174 | } | 175 | } |
175 | 176 | ||
177 | static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) | ||
178 | { | ||
179 | int i, filtered = 0; | ||
180 | struct sk_buff *skb; | ||
181 | struct ieee80211_tx_info *info; | ||
182 | unsigned long flags; | ||
183 | |||
184 | /* filter all frames currently the low level queus for this hlid */ | ||
185 | for (i = 0; i < NUM_TX_QUEUES; i++) { | ||
186 | while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { | ||
187 | info = IEEE80211_SKB_CB(skb); | ||
188 | info->flags |= IEEE80211_TX_STAT_TX_FILTERED; | ||
189 | info->status.rates[0].idx = -1; | ||
190 | ieee80211_tx_status(wl->hw, skb); | ||
191 | filtered++; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
196 | wl->tx_queue_count -= filtered; | ||
197 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
198 | |||
199 | wl1271_handle_tx_low_watermark(wl); | ||
200 | } | ||
201 | |||
202 | void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues) | ||
203 | { | ||
204 | struct ieee80211_sta *sta; | ||
205 | |||
206 | if (test_bit(hlid, &wl->ap_ps_map)) | ||
207 | return; | ||
208 | |||
209 | wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d blks %d " | ||
210 | "clean_queues %d", hlid, wl->links[hlid].allocated_blks, | ||
211 | clean_queues); | ||
212 | |||
213 | rcu_read_lock(); | ||
214 | sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr); | ||
215 | if (!sta) { | ||
216 | wl1271_error("could not find sta %pM for starting ps", | ||
217 | wl->links[hlid].addr); | ||
218 | rcu_read_unlock(); | ||
219 | return; | ||
220 | } | ||
176 | 221 | ||
222 | ieee80211_sta_ps_transition_ni(sta, true); | ||
223 | rcu_read_unlock(); | ||
224 | |||
225 | /* do we want to filter all frames from this link's queues? */ | ||
226 | if (clean_queues) | ||
227 | wl1271_ps_filter_frames(wl, hlid); | ||
228 | |||
229 | __set_bit(hlid, &wl->ap_ps_map); | ||
230 | } | ||
231 | |||
232 | void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid) | ||
233 | { | ||
234 | struct ieee80211_sta *sta; | ||
235 | |||
236 | if (!test_bit(hlid, &wl->ap_ps_map)) | ||
237 | return; | ||
238 | |||
239 | wl1271_debug(DEBUG_PSM, "end mac80211 PSM on hlid %d", hlid); | ||
240 | |||
241 | __clear_bit(hlid, &wl->ap_ps_map); | ||
242 | |||
243 | rcu_read_lock(); | ||
244 | sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr); | ||
245 | if (!sta) { | ||
246 | wl1271_error("could not find sta %pM for ending ps", | ||
247 | wl->links[hlid].addr); | ||
248 | goto end; | ||
249 | } | ||
250 | |||
251 | ieee80211_sta_ps_transition_ni(sta, false); | ||
252 | end: | ||
253 | rcu_read_unlock(); | ||
254 | } | ||
diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h index 8415060f08e5..fc1f4c193593 100644 --- a/drivers/net/wireless/wl12xx/ps.h +++ b/drivers/net/wireless/wl12xx/ps.h | |||
@@ -32,5 +32,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, | |||
32 | void wl1271_ps_elp_sleep(struct wl1271 *wl); | 32 | void wl1271_ps_elp_sleep(struct wl1271 *wl); |
33 | int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake); | 33 | int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake); |
34 | void wl1271_elp_work(struct work_struct *work); | 34 | void wl1271_elp_work(struct work_struct *work); |
35 | void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues); | ||
36 | void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid); | ||
35 | 37 | ||
36 | #endif /* __WL1271_PS_H__ */ | 38 | #endif /* __WL1271_PS_H__ */ |
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 00d250d8da18..3d13d7a83ea1 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c | |||
@@ -92,7 +92,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) | |||
92 | { | 92 | { |
93 | struct wl1271_rx_descriptor *desc; | 93 | struct wl1271_rx_descriptor *desc; |
94 | struct sk_buff *skb; | 94 | struct sk_buff *skb; |
95 | u16 *fc; | 95 | struct ieee80211_hdr *hdr; |
96 | u8 *buf; | 96 | u8 *buf; |
97 | u8 beacon = 0; | 97 | u8 beacon = 0; |
98 | 98 | ||
@@ -118,8 +118,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) | |||
118 | /* now we pull the descriptor out of the buffer */ | 118 | /* now we pull the descriptor out of the buffer */ |
119 | skb_pull(skb, sizeof(*desc)); | 119 | skb_pull(skb, sizeof(*desc)); |
120 | 120 | ||
121 | fc = (u16 *)skb->data; | 121 | hdr = (struct ieee80211_hdr *)skb->data; |
122 | if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) | 122 | if (ieee80211_is_beacon(hdr->frame_control)) |
123 | beacon = 1; | 123 | beacon = 1; |
124 | 124 | ||
125 | wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); | 125 | wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); |
diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h index 4cef8fa3dee1..75fabf836491 100644 --- a/drivers/net/wireless/wl12xx/rx.h +++ b/drivers/net/wireless/wl12xx/rx.h | |||
@@ -30,10 +30,6 @@ | |||
30 | #define WL1271_RX_MAX_RSSI -30 | 30 | #define WL1271_RX_MAX_RSSI -30 |
31 | #define WL1271_RX_MIN_RSSI -95 | 31 | #define WL1271_RX_MIN_RSSI -95 |
32 | 32 | ||
33 | #define WL1271_RX_ALIGN_TO 4 | ||
34 | #define WL1271_RX_ALIGN(len) (((len) + WL1271_RX_ALIGN_TO - 1) & \ | ||
35 | ~(WL1271_RX_ALIGN_TO - 1)) | ||
36 | |||
37 | #define SHORT_PREAMBLE_BIT BIT(0) | 33 | #define SHORT_PREAMBLE_BIT BIT(0) |
38 | #define OFDM_RATE_BIT BIT(6) | 34 | #define OFDM_RATE_BIT BIT(6) |
39 | #define PBCC_RATE_BIT BIT(7) | 35 | #define PBCC_RATE_BIT BIT(7) |
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 67a00946e3dd..ac60d577319f 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c | |||
@@ -70,8 +70,65 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id) | |||
70 | } | 70 | } |
71 | } | 71 | } |
72 | 72 | ||
73 | static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, | ||
74 | struct sk_buff *skb) | ||
75 | { | ||
76 | struct ieee80211_hdr *hdr; | ||
77 | |||
78 | /* | ||
79 | * add the station to the known list before transmitting the | ||
80 | * authentication response. this way it won't get de-authed by FW | ||
81 | * when transmitting too soon. | ||
82 | */ | ||
83 | hdr = (struct ieee80211_hdr *)(skb->data + | ||
84 | sizeof(struct wl1271_tx_hw_descr)); | ||
85 | if (ieee80211_is_auth(hdr->frame_control)) | ||
86 | wl1271_acx_set_inconnection_sta(wl, hdr->addr1); | ||
87 | } | ||
88 | |||
89 | static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) | ||
90 | { | ||
91 | bool fw_ps; | ||
92 | u8 tx_blks; | ||
93 | |||
94 | /* only regulate station links */ | ||
95 | if (hlid < WL1271_AP_STA_HLID_START) | ||
96 | return; | ||
97 | |||
98 | fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); | ||
99 | tx_blks = wl->links[hlid].allocated_blks; | ||
100 | |||
101 | /* | ||
102 | * if in FW PS and there is enough data in FW we can put the link | ||
103 | * into high-level PS and clean out its TX queues. | ||
104 | */ | ||
105 | if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS) | ||
106 | wl1271_ps_link_start(wl, hlid, true); | ||
107 | } | ||
108 | |||
109 | u8 wl1271_tx_get_hlid(struct sk_buff *skb) | ||
110 | { | ||
111 | struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb); | ||
112 | |||
113 | if (control->control.sta) { | ||
114 | struct wl1271_station *wl_sta; | ||
115 | |||
116 | wl_sta = (struct wl1271_station *) | ||
117 | control->control.sta->drv_priv; | ||
118 | return wl_sta->hlid; | ||
119 | } else { | ||
120 | struct ieee80211_hdr *hdr; | ||
121 | |||
122 | hdr = (struct ieee80211_hdr *)skb->data; | ||
123 | if (ieee80211_is_mgmt(hdr->frame_control)) | ||
124 | return WL1271_AP_GLOBAL_HLID; | ||
125 | else | ||
126 | return WL1271_AP_BROADCAST_HLID; | ||
127 | } | ||
128 | } | ||
129 | |||
73 | static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, | 130 | static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, |
74 | u32 buf_offset) | 131 | u32 buf_offset, u8 hlid) |
75 | { | 132 | { |
76 | struct wl1271_tx_hw_descr *desc; | 133 | struct wl1271_tx_hw_descr *desc; |
77 | u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; | 134 | u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; |
@@ -100,6 +157,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, | |||
100 | 157 | ||
101 | wl->tx_blocks_available -= total_blocks; | 158 | wl->tx_blocks_available -= total_blocks; |
102 | 159 | ||
160 | if (wl->bss_type == BSS_TYPE_AP_BSS) | ||
161 | wl->links[hlid].allocated_blks += total_blocks; | ||
162 | |||
103 | ret = 0; | 163 | ret = 0; |
104 | 164 | ||
105 | wl1271_debug(DEBUG_TX, | 165 | wl1271_debug(DEBUG_TX, |
@@ -113,7 +173,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, | |||
113 | } | 173 | } |
114 | 174 | ||
115 | static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, | 175 | static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, |
116 | u32 extra, struct ieee80211_tx_info *control) | 176 | u32 extra, struct ieee80211_tx_info *control, |
177 | u8 hlid) | ||
117 | { | 178 | { |
118 | struct timespec ts; | 179 | struct timespec ts; |
119 | struct wl1271_tx_hw_descr *desc; | 180 | struct wl1271_tx_hw_descr *desc; |
@@ -149,7 +210,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, | |||
149 | desc->tid = ac; | 210 | desc->tid = ac; |
150 | 211 | ||
151 | if (wl->bss_type != BSS_TYPE_AP_BSS) { | 212 | if (wl->bss_type != BSS_TYPE_AP_BSS) { |
152 | desc->aid = TX_HW_DEFAULT_AID; | 213 | desc->aid = hlid; |
153 | 214 | ||
154 | /* if the packets are destined for AP (have a STA entry) | 215 | /* if the packets are destined for AP (have a STA entry) |
155 | send them with AP rate policies, otherwise use default | 216 | send them with AP rate policies, otherwise use default |
@@ -159,25 +220,17 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, | |||
159 | else | 220 | else |
160 | rate_idx = ACX_TX_BASIC_RATE; | 221 | rate_idx = ACX_TX_BASIC_RATE; |
161 | } else { | 222 | } else { |
162 | if (control->control.sta) { | 223 | desc->hlid = hlid; |
163 | struct wl1271_station *wl_sta; | 224 | switch (hlid) { |
164 | 225 | case WL1271_AP_GLOBAL_HLID: | |
165 | wl_sta = (struct wl1271_station *) | 226 | rate_idx = ACX_TX_AP_MODE_MGMT_RATE; |
166 | control->control.sta->drv_priv; | 227 | break; |
167 | desc->hlid = wl_sta->hlid; | 228 | case WL1271_AP_BROADCAST_HLID: |
229 | rate_idx = ACX_TX_AP_MODE_BCST_RATE; | ||
230 | break; | ||
231 | default: | ||
168 | rate_idx = ac; | 232 | rate_idx = ac; |
169 | } else { | 233 | break; |
170 | struct ieee80211_hdr *hdr; | ||
171 | |||
172 | hdr = (struct ieee80211_hdr *) | ||
173 | (skb->data + sizeof(*desc)); | ||
174 | if (ieee80211_is_mgmt(hdr->frame_control)) { | ||
175 | desc->hlid = WL1271_AP_GLOBAL_HLID; | ||
176 | rate_idx = ACX_TX_AP_MODE_MGMT_RATE; | ||
177 | } else { | ||
178 | desc->hlid = WL1271_AP_BROADCAST_HLID; | ||
179 | rate_idx = ACX_TX_AP_MODE_BCST_RATE; | ||
180 | } | ||
181 | } | 234 | } |
182 | } | 235 | } |
183 | 236 | ||
@@ -185,7 +238,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, | |||
185 | desc->reserved = 0; | 238 | desc->reserved = 0; |
186 | 239 | ||
187 | /* align the length (and store in terms of words) */ | 240 | /* align the length (and store in terms of words) */ |
188 | pad = WL1271_TX_ALIGN(skb->len); | 241 | pad = ALIGN(skb->len, WL1271_TX_ALIGN_TO); |
189 | desc->length = cpu_to_le16(pad >> 2); | 242 | desc->length = cpu_to_le16(pad >> 2); |
190 | 243 | ||
191 | /* calculate number of padding bytes */ | 244 | /* calculate number of padding bytes */ |
@@ -208,6 +261,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, | |||
208 | u32 extra = 0; | 261 | u32 extra = 0; |
209 | int ret = 0; | 262 | int ret = 0; |
210 | u32 total_len; | 263 | u32 total_len; |
264 | u8 hlid; | ||
211 | 265 | ||
212 | if (!skb) | 266 | if (!skb) |
213 | return -EINVAL; | 267 | return -EINVAL; |
@@ -234,18 +288,28 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, | |||
234 | } | 288 | } |
235 | } | 289 | } |
236 | 290 | ||
237 | ret = wl1271_tx_allocate(wl, skb, extra, buf_offset); | 291 | if (wl->bss_type == BSS_TYPE_AP_BSS) |
292 | hlid = wl1271_tx_get_hlid(skb); | ||
293 | else | ||
294 | hlid = TX_HW_DEFAULT_AID; | ||
295 | |||
296 | ret = wl1271_tx_allocate(wl, skb, extra, buf_offset, hlid); | ||
238 | if (ret < 0) | 297 | if (ret < 0) |
239 | return ret; | 298 | return ret; |
240 | 299 | ||
241 | wl1271_tx_fill_hdr(wl, skb, extra, info); | 300 | if (wl->bss_type == BSS_TYPE_AP_BSS) { |
301 | wl1271_tx_ap_update_inconnection_sta(wl, skb); | ||
302 | wl1271_tx_regulate_link(wl, hlid); | ||
303 | } | ||
304 | |||
305 | wl1271_tx_fill_hdr(wl, skb, extra, info, hlid); | ||
242 | 306 | ||
243 | /* | 307 | /* |
244 | * The length of each packet is stored in terms of words. Thus, we must | 308 | * The length of each packet is stored in terms of words. Thus, we must |
245 | * pad the skb data to make sure its length is aligned. | 309 | * pad the skb data to make sure its length is aligned. |
246 | * The number of padding bytes is computed and set in wl1271_tx_fill_hdr | 310 | * The number of padding bytes is computed and set in wl1271_tx_fill_hdr |
247 | */ | 311 | */ |
248 | total_len = WL1271_TX_ALIGN(skb->len); | 312 | total_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO); |
249 | memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); | 313 | memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); |
250 | memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); | 314 | memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); |
251 | 315 | ||
@@ -279,7 +343,7 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) | |||
279 | return enabled_rates; | 343 | return enabled_rates; |
280 | } | 344 | } |
281 | 345 | ||
282 | static void handle_tx_low_watermark(struct wl1271 *wl) | 346 | void wl1271_handle_tx_low_watermark(struct wl1271 *wl) |
283 | { | 347 | { |
284 | unsigned long flags; | 348 | unsigned long flags; |
285 | 349 | ||
@@ -293,7 +357,7 @@ static void handle_tx_low_watermark(struct wl1271 *wl) | |||
293 | } | 357 | } |
294 | } | 358 | } |
295 | 359 | ||
296 | static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) | 360 | static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl) |
297 | { | 361 | { |
298 | struct sk_buff *skb = NULL; | 362 | struct sk_buff *skb = NULL; |
299 | unsigned long flags; | 363 | unsigned long flags; |
@@ -319,12 +383,69 @@ out: | |||
319 | return skb; | 383 | return skb; |
320 | } | 384 | } |
321 | 385 | ||
386 | static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) | ||
387 | { | ||
388 | struct sk_buff *skb = NULL; | ||
389 | unsigned long flags; | ||
390 | int i, h, start_hlid; | ||
391 | |||
392 | /* start from the link after the last one */ | ||
393 | start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS; | ||
394 | |||
395 | /* dequeue according to AC, round robin on each link */ | ||
396 | for (i = 0; i < AP_MAX_LINKS; i++) { | ||
397 | h = (start_hlid + i) % AP_MAX_LINKS; | ||
398 | |||
399 | skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VO]); | ||
400 | if (skb) | ||
401 | goto out; | ||
402 | skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VI]); | ||
403 | if (skb) | ||
404 | goto out; | ||
405 | skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BE]); | ||
406 | if (skb) | ||
407 | goto out; | ||
408 | skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BK]); | ||
409 | if (skb) | ||
410 | goto out; | ||
411 | } | ||
412 | |||
413 | out: | ||
414 | if (skb) { | ||
415 | wl->last_tx_hlid = h; | ||
416 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
417 | wl->tx_queue_count--; | ||
418 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
419 | } else { | ||
420 | wl->last_tx_hlid = 0; | ||
421 | } | ||
422 | |||
423 | return skb; | ||
424 | } | ||
425 | |||
426 | static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) | ||
427 | { | ||
428 | if (wl->bss_type == BSS_TYPE_AP_BSS) | ||
429 | return wl1271_ap_skb_dequeue(wl); | ||
430 | |||
431 | return wl1271_sta_skb_dequeue(wl); | ||
432 | } | ||
433 | |||
322 | static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) | 434 | static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) |
323 | { | 435 | { |
324 | unsigned long flags; | 436 | unsigned long flags; |
325 | int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | 437 | int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); |
326 | 438 | ||
327 | skb_queue_head(&wl->tx_queue[q], skb); | 439 | if (wl->bss_type == BSS_TYPE_AP_BSS) { |
440 | u8 hlid = wl1271_tx_get_hlid(skb); | ||
441 | skb_queue_head(&wl->links[hlid].tx_queue[q], skb); | ||
442 | |||
443 | /* make sure we dequeue the same packet next time */ | ||
444 | wl->last_tx_hlid = (hlid + AP_MAX_LINKS - 1) % AP_MAX_LINKS; | ||
445 | } else { | ||
446 | skb_queue_head(&wl->tx_queue[q], skb); | ||
447 | } | ||
448 | |||
328 | spin_lock_irqsave(&wl->wl_lock, flags); | 449 | spin_lock_irqsave(&wl->wl_lock, flags); |
329 | wl->tx_queue_count++; | 450 | wl->tx_queue_count++; |
330 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 451 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
@@ -387,7 +508,7 @@ out_ack: | |||
387 | if (sent_packets) { | 508 | if (sent_packets) { |
388 | /* interrupt the firmware with the new packets */ | 509 | /* interrupt the firmware with the new packets */ |
389 | wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); | 510 | wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); |
390 | handle_tx_low_watermark(wl); | 511 | wl1271_handle_tx_low_watermark(wl); |
391 | } | 512 | } |
392 | 513 | ||
393 | out: | 514 | out: |
@@ -504,32 +625,76 @@ void wl1271_tx_complete(struct wl1271 *wl) | |||
504 | } | 625 | } |
505 | } | 626 | } |
506 | 627 | ||
628 | void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) | ||
629 | { | ||
630 | struct sk_buff *skb; | ||
631 | int i, total = 0; | ||
632 | unsigned long flags; | ||
633 | struct ieee80211_tx_info *info; | ||
634 | |||
635 | for (i = 0; i < NUM_TX_QUEUES; i++) { | ||
636 | while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { | ||
637 | wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); | ||
638 | info = IEEE80211_SKB_CB(skb); | ||
639 | info->status.rates[0].idx = -1; | ||
640 | info->status.rates[0].count = 0; | ||
641 | ieee80211_tx_status(wl->hw, skb); | ||
642 | total++; | ||
643 | } | ||
644 | } | ||
645 | |||
646 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
647 | wl->tx_queue_count -= total; | ||
648 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
649 | |||
650 | wl1271_handle_tx_low_watermark(wl); | ||
651 | } | ||
652 | |||
507 | /* caller must hold wl->mutex */ | 653 | /* caller must hold wl->mutex */ |
508 | void wl1271_tx_reset(struct wl1271 *wl) | 654 | void wl1271_tx_reset(struct wl1271 *wl) |
509 | { | 655 | { |
510 | int i; | 656 | int i; |
511 | struct sk_buff *skb; | 657 | struct sk_buff *skb; |
658 | struct ieee80211_tx_info *info; | ||
512 | 659 | ||
513 | /* TX failure */ | 660 | /* TX failure */ |
514 | for (i = 0; i < NUM_TX_QUEUES; i++) { | 661 | if (wl->bss_type == BSS_TYPE_AP_BSS) { |
515 | while ((skb = skb_dequeue(&wl->tx_queue[i]))) { | 662 | for (i = 0; i < AP_MAX_LINKS; i++) { |
516 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); | 663 | wl1271_tx_reset_link_queues(wl, i); |
517 | ieee80211_tx_status(wl->hw, skb); | 664 | wl->links[i].allocated_blks = 0; |
665 | wl->links[i].prev_freed_blks = 0; | ||
666 | } | ||
667 | |||
668 | wl->last_tx_hlid = 0; | ||
669 | } else { | ||
670 | for (i = 0; i < NUM_TX_QUEUES; i++) { | ||
671 | while ((skb = skb_dequeue(&wl->tx_queue[i]))) { | ||
672 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", | ||
673 | skb); | ||
674 | info = IEEE80211_SKB_CB(skb); | ||
675 | info->status.rates[0].idx = -1; | ||
676 | info->status.rates[0].count = 0; | ||
677 | ieee80211_tx_status(wl->hw, skb); | ||
678 | } | ||
518 | } | 679 | } |
519 | } | 680 | } |
681 | |||
520 | wl->tx_queue_count = 0; | 682 | wl->tx_queue_count = 0; |
521 | 683 | ||
522 | /* | 684 | /* |
523 | * Make sure the driver is at a consistent state, in case this | 685 | * Make sure the driver is at a consistent state, in case this |
524 | * function is called from a context other than interface removal. | 686 | * function is called from a context other than interface removal. |
525 | */ | 687 | */ |
526 | handle_tx_low_watermark(wl); | 688 | wl1271_handle_tx_low_watermark(wl); |
527 | 689 | ||
528 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) | 690 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) |
529 | if (wl->tx_frames[i] != NULL) { | 691 | if (wl->tx_frames[i] != NULL) { |
530 | skb = wl->tx_frames[i]; | 692 | skb = wl->tx_frames[i]; |
531 | wl1271_free_tx_id(wl, i); | 693 | wl1271_free_tx_id(wl, i); |
532 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); | 694 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); |
695 | info = IEEE80211_SKB_CB(skb); | ||
696 | info->status.rates[0].idx = -1; | ||
697 | info->status.rates[0].count = 0; | ||
533 | ieee80211_tx_status(wl->hw, skb); | 698 | ieee80211_tx_status(wl->hw, skb); |
534 | } | 699 | } |
535 | } | 700 | } |
@@ -544,8 +709,8 @@ void wl1271_tx_flush(struct wl1271 *wl) | |||
544 | 709 | ||
545 | while (!time_after(jiffies, timeout)) { | 710 | while (!time_after(jiffies, timeout)) { |
546 | mutex_lock(&wl->mutex); | 711 | mutex_lock(&wl->mutex); |
547 | wl1271_debug(DEBUG_TX, "flushing tx buffer: %d", | 712 | wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", |
548 | wl->tx_frames_cnt); | 713 | wl->tx_frames_cnt, wl->tx_queue_count); |
549 | if ((wl->tx_frames_cnt == 0) && (wl->tx_queue_count == 0)) { | 714 | if ((wl->tx_frames_cnt == 0) && (wl->tx_queue_count == 0)) { |
550 | mutex_unlock(&wl->mutex); | 715 | mutex_unlock(&wl->mutex); |
551 | return; | 716 | return; |
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index 05722a560d91..02f07fa66e82 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h | |||
@@ -53,8 +53,6 @@ | |||
53 | #define TX_HW_RESULT_QUEUE_LEN_MASK 0xf | 53 | #define TX_HW_RESULT_QUEUE_LEN_MASK 0xf |
54 | 54 | ||
55 | #define WL1271_TX_ALIGN_TO 4 | 55 | #define WL1271_TX_ALIGN_TO 4 |
56 | #define WL1271_TX_ALIGN(len) (((len) + WL1271_TX_ALIGN_TO - 1) & \ | ||
57 | ~(WL1271_TX_ALIGN_TO - 1)) | ||
58 | #define WL1271_TKIP_IV_SPACE 4 | 56 | #define WL1271_TKIP_IV_SPACE 4 |
59 | 57 | ||
60 | struct wl1271_tx_hw_descr { | 58 | struct wl1271_tx_hw_descr { |
@@ -152,5 +150,8 @@ void wl1271_tx_flush(struct wl1271 *wl); | |||
152 | u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); | 150 | u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); |
153 | u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); | 151 | u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); |
154 | u32 wl1271_tx_min_rate_get(struct wl1271 *wl); | 152 | u32 wl1271_tx_min_rate_get(struct wl1271 *wl); |
153 | u8 wl1271_tx_get_hlid(struct sk_buff *skb); | ||
154 | void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid); | ||
155 | void wl1271_handle_tx_low_watermark(struct wl1271 *wl); | ||
155 | 156 | ||
156 | #endif | 157 | #endif |
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 1d6c94304b1a..338acc9f60b3 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h | |||
@@ -153,6 +153,17 @@ extern u32 wl12xx_debug_level; | |||
153 | #define WL1271_AP_BROADCAST_HLID 1 | 153 | #define WL1271_AP_BROADCAST_HLID 1 |
154 | #define WL1271_AP_STA_HLID_START 2 | 154 | #define WL1271_AP_STA_HLID_START 2 |
155 | 155 | ||
156 | /* | ||
157 | * When in AP-mode, we allow (at least) this number of mem-blocks | ||
158 | * to be transmitted to FW for a STA in PS-mode. Only when packets are | ||
159 | * present in the FW buffers it will wake the sleeping STA. We want to put | ||
160 | * enough packets for the driver to transmit all of its buffered data before | ||
161 | * the STA goes to sleep again. But we don't want to take too much mem-blocks | ||
162 | * as it might hurt the throughput of active STAs. | ||
163 | * The number of blocks (18) is enough for 2 large packets. | ||
164 | */ | ||
165 | #define WL1271_PS_STA_MAX_BLOCKS (2 * 9) | ||
166 | |||
156 | #define WL1271_AP_BSS_INDEX 0 | 167 | #define WL1271_AP_BSS_INDEX 0 |
157 | #define WL1271_AP_DEF_INACTIV_SEC 300 | 168 | #define WL1271_AP_DEF_INACTIV_SEC 300 |
158 | #define WL1271_AP_DEF_BEACON_EXP 20 | 169 | #define WL1271_AP_DEF_BEACON_EXP 20 |
@@ -319,6 +330,17 @@ enum wl12xx_flags { | |||
319 | WL1271_FLAG_AP_STARTED | 330 | WL1271_FLAG_AP_STARTED |
320 | }; | 331 | }; |
321 | 332 | ||
333 | struct wl1271_link { | ||
334 | /* AP-mode - TX queue per AC in link */ | ||
335 | struct sk_buff_head tx_queue[NUM_TX_QUEUES]; | ||
336 | |||
337 | /* accounting for allocated / available TX blocks in FW */ | ||
338 | u8 allocated_blks; | ||
339 | u8 prev_freed_blks; | ||
340 | |||
341 | u8 addr[ETH_ALEN]; | ||
342 | }; | ||
343 | |||
322 | struct wl1271 { | 344 | struct wl1271 { |
323 | struct platform_device *plat_dev; | 345 | struct platform_device *plat_dev; |
324 | struct ieee80211_hw *hw; | 346 | struct ieee80211_hw *hw; |
@@ -498,6 +520,21 @@ struct wl1271 { | |||
498 | /* RX BA constraint value */ | 520 | /* RX BA constraint value */ |
499 | bool ba_support; | 521 | bool ba_support; |
500 | u8 ba_rx_bitmap; | 522 | u8 ba_rx_bitmap; |
523 | |||
524 | /* | ||
525 | * AP-mode - links indexed by HLID. The global and broadcast links | ||
526 | * are always active. | ||
527 | */ | ||
528 | struct wl1271_link links[AP_MAX_LINKS]; | ||
529 | |||
530 | /* the hlid of the link where the last transmitted skb came from */ | ||
531 | int last_tx_hlid; | ||
532 | |||
533 | /* AP-mode - a bitmap of links currently in PS mode according to FW */ | ||
534 | u32 ap_fw_ps_map; | ||
535 | |||
536 | /* AP-mode - a bitmap of links currently in PS mode in mac80211 */ | ||
537 | unsigned long ap_ps_map; | ||
501 | }; | 538 | }; |
502 | 539 | ||
503 | struct wl1271_station { | 540 | struct wl1271_station { |