diff options
Diffstat (limited to 'drivers/net/wireless/ath')
72 files changed, 3270 insertions, 622 deletions
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index a889fd66fc63..fd9e5305e77f 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h | |||
| @@ -63,6 +63,7 @@ enum ath_op_flags { | |||
| 63 | ATH_OP_PRIM_STA_VIF, | 63 | ATH_OP_PRIM_STA_VIF, |
| 64 | ATH_OP_HW_RESET, | 64 | ATH_OP_HW_RESET, |
| 65 | ATH_OP_SCANNING, | 65 | ATH_OP_SCANNING, |
| 66 | ATH_OP_MULTI_CHANNEL, | ||
| 66 | }; | 67 | }; |
| 67 | 68 | ||
| 68 | enum ath_bus_type { | 69 | enum ath_bus_type { |
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index d185dc0cd12b..4333107ecf37 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c | |||
| @@ -603,16 +603,19 @@ static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, | |||
| 603 | if (ret) | 603 | if (ret) |
| 604 | return ret; | 604 | return ret; |
| 605 | 605 | ||
| 606 | src_ring->hw_index = | 606 | read_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); |
| 607 | ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); | 607 | if (read_index == 0xffffffff) |
| 608 | src_ring->hw_index &= nentries_mask; | 608 | return -ENODEV; |
| 609 | |||
| 610 | read_index &= nentries_mask; | ||
| 611 | src_ring->hw_index = read_index; | ||
| 609 | 612 | ||
| 610 | ath10k_pci_sleep(ar); | 613 | ath10k_pci_sleep(ar); |
| 611 | } | 614 | } |
| 612 | 615 | ||
| 613 | read_index = src_ring->hw_index; | 616 | read_index = src_ring->hw_index; |
| 614 | 617 | ||
| 615 | if ((read_index == sw_index) || (read_index == 0xffffffff)) | 618 | if (read_index == sw_index) |
| 616 | return -EIO; | 619 | return -EIO; |
| 617 | 620 | ||
| 618 | sbase = src_ring->shadow_base; | 621 | sbase = src_ring->shadow_base; |
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index e6c56c5bb0f6..93adb8c58969 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c | |||
| @@ -802,7 +802,7 @@ int ath10k_core_start(struct ath10k *ar) | |||
| 802 | 802 | ||
| 803 | INIT_LIST_HEAD(&ar->arvifs); | 803 | INIT_LIST_HEAD(&ar->arvifs); |
| 804 | 804 | ||
| 805 | if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) | 805 | if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) { |
| 806 | ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n", | 806 | ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n", |
| 807 | ar->hw_params.name, | 807 | ar->hw_params.name, |
| 808 | ar->target_version, | 808 | ar->target_version, |
| @@ -811,6 +811,12 @@ int ath10k_core_start(struct ath10k *ar) | |||
| 811 | ar->fw_api, | 811 | ar->fw_api, |
| 812 | ar->htt.target_version_major, | 812 | ar->htt.target_version_major, |
| 813 | ar->htt.target_version_minor); | 813 | ar->htt.target_version_minor); |
| 814 | ath10k_info("debug %d debugfs %d tracing %d dfs %d\n", | ||
| 815 | config_enabled(CONFIG_ATH10K_DEBUG), | ||
| 816 | config_enabled(CONFIG_ATH10K_DEBUGFS), | ||
| 817 | config_enabled(CONFIG_ATH10K_TRACING), | ||
| 818 | config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)); | ||
| 819 | } | ||
| 814 | 820 | ||
| 815 | __set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags); | 821 | __set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags); |
| 816 | 822 | ||
| @@ -988,7 +994,9 @@ err_unregister_mac: | |||
| 988 | err_release_fw: | 994 | err_release_fw: |
| 989 | ath10k_core_free_firmware_files(ar); | 995 | ath10k_core_free_firmware_files(ar); |
| 990 | err: | 996 | err: |
| 991 | device_release_driver(ar->dev); | 997 | /* TODO: It's probably a good idea to release device from the driver |
| 998 | * but calling device_release_driver() here will cause a deadlock. | ||
| 999 | */ | ||
| 992 | return; | 1000 | return; |
| 993 | } | 1001 | } |
| 994 | 1002 | ||
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 68ceef61933d..83a5fa91531d 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h | |||
| @@ -290,6 +290,9 @@ struct ath10k_debug { | |||
| 290 | struct ath_dfs_pool_stats dfs_pool_stats; | 290 | struct ath_dfs_pool_stats dfs_pool_stats; |
| 291 | 291 | ||
| 292 | u32 fw_dbglog_mask; | 292 | u32 fw_dbglog_mask; |
| 293 | |||
| 294 | u8 htt_max_amsdu; | ||
| 295 | u8 htt_max_ampdu; | ||
| 293 | }; | 296 | }; |
| 294 | 297 | ||
| 295 | enum ath10k_state { | 298 | enum ath10k_state { |
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 1b7ff4ba122c..3030158c478e 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c | |||
| @@ -671,6 +671,72 @@ static const struct file_operations fops_htt_stats_mask = { | |||
| 671 | .llseek = default_llseek, | 671 | .llseek = default_llseek, |
| 672 | }; | 672 | }; |
| 673 | 673 | ||
| 674 | static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file, | ||
| 675 | char __user *user_buf, | ||
| 676 | size_t count, loff_t *ppos) | ||
| 677 | { | ||
| 678 | struct ath10k *ar = file->private_data; | ||
| 679 | char buf[64]; | ||
| 680 | u8 amsdu = 3, ampdu = 64; | ||
| 681 | unsigned int len; | ||
| 682 | |||
| 683 | mutex_lock(&ar->conf_mutex); | ||
| 684 | |||
| 685 | if (ar->debug.htt_max_amsdu) | ||
| 686 | amsdu = ar->debug.htt_max_amsdu; | ||
| 687 | |||
| 688 | if (ar->debug.htt_max_ampdu) | ||
| 689 | ampdu = ar->debug.htt_max_ampdu; | ||
| 690 | |||
| 691 | mutex_unlock(&ar->conf_mutex); | ||
| 692 | |||
| 693 | len = scnprintf(buf, sizeof(buf), "%u %u\n", amsdu, ampdu); | ||
| 694 | |||
| 695 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
| 696 | } | ||
| 697 | |||
| 698 | static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file, | ||
| 699 | const char __user *user_buf, | ||
| 700 | size_t count, loff_t *ppos) | ||
| 701 | { | ||
| 702 | struct ath10k *ar = file->private_data; | ||
| 703 | int res; | ||
| 704 | char buf[64]; | ||
| 705 | unsigned int amsdu, ampdu; | ||
| 706 | |||
| 707 | simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); | ||
| 708 | |||
| 709 | /* make sure that buf is null terminated */ | ||
| 710 | buf[sizeof(buf) - 1] = 0; | ||
| 711 | |||
| 712 | res = sscanf(buf, "%u %u", &amsdu, &du); | ||
| 713 | |||
| 714 | if (res != 2) | ||
| 715 | return -EINVAL; | ||
| 716 | |||
| 717 | mutex_lock(&ar->conf_mutex); | ||
| 718 | |||
| 719 | res = ath10k_htt_h2t_aggr_cfg_msg(&ar->htt, ampdu, amsdu); | ||
| 720 | if (res) | ||
| 721 | goto out; | ||
| 722 | |||
| 723 | res = count; | ||
| 724 | ar->debug.htt_max_amsdu = amsdu; | ||
| 725 | ar->debug.htt_max_ampdu = ampdu; | ||
| 726 | |||
| 727 | out: | ||
| 728 | mutex_unlock(&ar->conf_mutex); | ||
| 729 | return res; | ||
| 730 | } | ||
| 731 | |||
| 732 | static const struct file_operations fops_htt_max_amsdu_ampdu = { | ||
| 733 | .read = ath10k_read_htt_max_amsdu_ampdu, | ||
| 734 | .write = ath10k_write_htt_max_amsdu_ampdu, | ||
| 735 | .open = simple_open, | ||
| 736 | .owner = THIS_MODULE, | ||
| 737 | .llseek = default_llseek, | ||
| 738 | }; | ||
| 739 | |||
| 674 | static ssize_t ath10k_read_fw_dbglog(struct file *file, | 740 | static ssize_t ath10k_read_fw_dbglog(struct file *file, |
| 675 | char __user *user_buf, | 741 | char __user *user_buf, |
| 676 | size_t count, loff_t *ppos) | 742 | size_t count, loff_t *ppos) |
| @@ -757,6 +823,9 @@ void ath10k_debug_stop(struct ath10k *ar) | |||
| 757 | * warning from del_timer(). */ | 823 | * warning from del_timer(). */ |
| 758 | if (ar->debug.htt_stats_mask != 0) | 824 | if (ar->debug.htt_stats_mask != 0) |
| 759 | cancel_delayed_work(&ar->debug.htt_stats_dwork); | 825 | cancel_delayed_work(&ar->debug.htt_stats_dwork); |
| 826 | |||
| 827 | ar->debug.htt_max_amsdu = 0; | ||
| 828 | ar->debug.htt_max_ampdu = 0; | ||
| 760 | } | 829 | } |
| 761 | 830 | ||
| 762 | static ssize_t ath10k_write_simulate_radar(struct file *file, | 831 | static ssize_t ath10k_write_simulate_radar(struct file *file, |
| @@ -867,6 +936,10 @@ int ath10k_debug_create(struct ath10k *ar) | |||
| 867 | debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy, | 936 | debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy, |
| 868 | ar, &fops_htt_stats_mask); | 937 | ar, &fops_htt_stats_mask); |
| 869 | 938 | ||
| 939 | debugfs_create_file("htt_max_amsdu_ampdu", S_IRUSR | S_IWUSR, | ||
| 940 | ar->debug.debugfs_phy, ar, | ||
| 941 | &fops_htt_max_amsdu_ampdu); | ||
| 942 | |||
| 870 | debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy, | 943 | debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy, |
| 871 | ar, &fops_fw_dbglog); | 944 | ar, &fops_fw_dbglog); |
| 872 | 945 | ||
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index e493db4b4a41..5fdc40d3b378 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c | |||
| @@ -546,7 +546,7 @@ static u8 ath10k_htc_get_credit_allocation(struct ath10k_htc *htc, | |||
| 546 | 546 | ||
| 547 | int ath10k_htc_wait_target(struct ath10k_htc *htc) | 547 | int ath10k_htc_wait_target(struct ath10k_htc *htc) |
| 548 | { | 548 | { |
| 549 | int status = 0; | 549 | int i, status = 0; |
| 550 | struct ath10k_htc_svc_conn_req conn_req; | 550 | struct ath10k_htc_svc_conn_req conn_req; |
| 551 | struct ath10k_htc_svc_conn_resp conn_resp; | 551 | struct ath10k_htc_svc_conn_resp conn_resp; |
| 552 | struct ath10k_htc_msg *msg; | 552 | struct ath10k_htc_msg *msg; |
| @@ -556,10 +556,26 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) | |||
| 556 | 556 | ||
| 557 | status = wait_for_completion_timeout(&htc->ctl_resp, | 557 | status = wait_for_completion_timeout(&htc->ctl_resp, |
| 558 | ATH10K_HTC_WAIT_TIMEOUT_HZ); | 558 | ATH10K_HTC_WAIT_TIMEOUT_HZ); |
| 559 | if (status <= 0) { | 559 | if (status == 0) { |
| 560 | /* Workaround: In some cases the PCI HIF doesn't | ||
| 561 | * receive interrupt for the control response message | ||
| 562 | * even if the buffer was completed. It is suspected | ||
| 563 | * iomap writes unmasking PCI CE irqs aren't propagated | ||
| 564 | * properly in KVM PCI-passthrough sometimes. | ||
| 565 | */ | ||
| 566 | ath10k_warn("failed to receive control response completion, polling..\n"); | ||
| 567 | |||
| 568 | for (i = 0; i < CE_COUNT; i++) | ||
| 569 | ath10k_hif_send_complete_check(htc->ar, i, 1); | ||
| 570 | |||
| 571 | status = wait_for_completion_timeout(&htc->ctl_resp, | ||
| 572 | ATH10K_HTC_WAIT_TIMEOUT_HZ); | ||
| 573 | |||
| 560 | if (status == 0) | 574 | if (status == 0) |
| 561 | status = -ETIMEDOUT; | 575 | status = -ETIMEDOUT; |
| 576 | } | ||
| 562 | 577 | ||
| 578 | if (status < 0) { | ||
| 563 | ath10k_err("ctl_resp never came in (%d)\n", status); | 579 | ath10k_err("ctl_resp never came in (%d)\n", status); |
| 564 | return status; | 580 | return status; |
| 565 | } | 581 | } |
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 9a263462c793..6c93f3885ee5 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h | |||
| @@ -240,16 +240,10 @@ struct htt_oob_sync_req { | |||
| 240 | __le16 rsvd0; | 240 | __le16 rsvd0; |
| 241 | } __packed; | 241 | } __packed; |
| 242 | 242 | ||
| 243 | #define HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_MASK 0x1F | ||
| 244 | #define HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_LSB 0 | ||
| 245 | |||
| 246 | struct htt_aggr_conf { | 243 | struct htt_aggr_conf { |
| 247 | u8 max_num_ampdu_subframes; | 244 | u8 max_num_ampdu_subframes; |
| 248 | union { | 245 | /* amsdu_subframes is limited by 0x1F mask */ |
| 249 | /* dont use bitfields; undefined behaviour */ | 246 | u8 max_num_amsdu_subframes; |
| 250 | u8 flags; /* see %HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_ */ | ||
| 251 | u8 max_num_amsdu_subframes:5; | ||
| 252 | } __packed; | ||
| 253 | } __packed; | 247 | } __packed; |
| 254 | 248 | ||
| 255 | #define HTT_MGMT_FRM_HDR_DOWNLOAD_LEN 32 | 249 | #define HTT_MGMT_FRM_HDR_DOWNLOAD_LEN 32 |
| @@ -1343,6 +1337,9 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb); | |||
| 1343 | int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt); | 1337 | int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt); |
| 1344 | int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie); | 1338 | int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie); |
| 1345 | int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt); | 1339 | int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt); |
| 1340 | int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, | ||
| 1341 | u8 max_subfrms_ampdu, | ||
| 1342 | u8 max_subfrms_amsdu); | ||
| 1346 | 1343 | ||
| 1347 | void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt); | 1344 | void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt); |
| 1348 | int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt); | 1345 | int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt); |
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index eebc860c3655..80cdac15588a 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include "txrx.h" | 21 | #include "txrx.h" |
| 22 | #include "debug.h" | 22 | #include "debug.h" |
| 23 | #include "trace.h" | 23 | #include "trace.h" |
| 24 | #include "mac.h" | ||
| 24 | 25 | ||
| 25 | #include <linux/log2.h> | 26 | #include <linux/log2.h> |
| 26 | 27 | ||
| @@ -307,7 +308,8 @@ static void ath10k_htt_rx_free_msdu_chain(struct sk_buff *skb) | |||
| 307 | static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, | 308 | static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, |
| 308 | u8 **fw_desc, int *fw_desc_len, | 309 | u8 **fw_desc, int *fw_desc_len, |
| 309 | struct sk_buff **head_msdu, | 310 | struct sk_buff **head_msdu, |
| 310 | struct sk_buff **tail_msdu) | 311 | struct sk_buff **tail_msdu, |
| 312 | u32 *attention) | ||
| 311 | { | 313 | { |
| 312 | int msdu_len, msdu_chaining = 0; | 314 | int msdu_len, msdu_chaining = 0; |
| 313 | struct sk_buff *msdu; | 315 | struct sk_buff *msdu; |
| @@ -357,6 +359,11 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, | |||
| 357 | break; | 359 | break; |
| 358 | } | 360 | } |
| 359 | 361 | ||
| 362 | *attention |= __le32_to_cpu(rx_desc->attention.flags) & | ||
| 363 | (RX_ATTENTION_FLAGS_TKIP_MIC_ERR | | ||
| 364 | RX_ATTENTION_FLAGS_DECRYPT_ERR | | ||
| 365 | RX_ATTENTION_FLAGS_FCS_ERR | | ||
| 366 | RX_ATTENTION_FLAGS_MGMT_TYPE); | ||
| 360 | /* | 367 | /* |
| 361 | * Copy the FW rx descriptor for this MSDU from the rx | 368 | * Copy the FW rx descriptor for this MSDU from the rx |
| 362 | * indication message into the MSDU's netbuf. HL uses the | 369 | * indication message into the MSDU's netbuf. HL uses the |
| @@ -1215,13 +1222,15 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, | |||
| 1215 | for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) { | 1222 | for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) { |
| 1216 | struct sk_buff *msdu_head, *msdu_tail; | 1223 | struct sk_buff *msdu_head, *msdu_tail; |
| 1217 | 1224 | ||
| 1225 | attention = 0; | ||
| 1218 | msdu_head = NULL; | 1226 | msdu_head = NULL; |
| 1219 | msdu_tail = NULL; | 1227 | msdu_tail = NULL; |
| 1220 | ret = ath10k_htt_rx_amsdu_pop(htt, | 1228 | ret = ath10k_htt_rx_amsdu_pop(htt, |
| 1221 | &fw_desc, | 1229 | &fw_desc, |
| 1222 | &fw_desc_len, | 1230 | &fw_desc_len, |
| 1223 | &msdu_head, | 1231 | &msdu_head, |
| 1224 | &msdu_tail); | 1232 | &msdu_tail, |
| 1233 | &attention); | ||
| 1225 | 1234 | ||
| 1226 | if (ret < 0) { | 1235 | if (ret < 0) { |
| 1227 | ath10k_warn("failed to pop amsdu from htt rx ring %d\n", | 1236 | ath10k_warn("failed to pop amsdu from htt rx ring %d\n", |
| @@ -1233,7 +1242,6 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, | |||
| 1233 | rxd = container_of((void *)msdu_head->data, | 1242 | rxd = container_of((void *)msdu_head->data, |
| 1234 | struct htt_rx_desc, | 1243 | struct htt_rx_desc, |
| 1235 | msdu_payload); | 1244 | msdu_payload); |
| 1236 | attention = __le32_to_cpu(rxd->attention.flags); | ||
| 1237 | 1245 | ||
| 1238 | if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head, | 1246 | if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head, |
| 1239 | status, | 1247 | status, |
| @@ -1286,6 +1294,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, | |||
| 1286 | u8 *fw_desc; | 1294 | u8 *fw_desc; |
| 1287 | int fw_desc_len, hdrlen, paramlen; | 1295 | int fw_desc_len, hdrlen, paramlen; |
| 1288 | int trim; | 1296 | int trim; |
| 1297 | u32 attention = 0; | ||
| 1289 | 1298 | ||
| 1290 | fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes); | 1299 | fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes); |
| 1291 | fw_desc = (u8 *)frag->fw_msdu_rx_desc; | 1300 | fw_desc = (u8 *)frag->fw_msdu_rx_desc; |
| @@ -1295,7 +1304,8 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, | |||
| 1295 | 1304 | ||
| 1296 | spin_lock_bh(&htt->rx_ring.lock); | 1305 | spin_lock_bh(&htt->rx_ring.lock); |
| 1297 | ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, | 1306 | ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, |
| 1298 | &msdu_head, &msdu_tail); | 1307 | &msdu_head, &msdu_tail, |
| 1308 | &attention); | ||
| 1299 | spin_unlock_bh(&htt->rx_ring.lock); | 1309 | spin_unlock_bh(&htt->rx_ring.lock); |
| 1300 | 1310 | ||
| 1301 | ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); | 1311 | ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); |
| @@ -1312,10 +1322,8 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, | |||
| 1312 | 1322 | ||
| 1313 | hdr = (struct ieee80211_hdr *)msdu_head->data; | 1323 | hdr = (struct ieee80211_hdr *)msdu_head->data; |
| 1314 | rxd = (void *)msdu_head->data - sizeof(*rxd); | 1324 | rxd = (void *)msdu_head->data - sizeof(*rxd); |
| 1315 | tkip_mic_err = !!(__le32_to_cpu(rxd->attention.flags) & | 1325 | tkip_mic_err = !!(attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR); |
| 1316 | RX_ATTENTION_FLAGS_TKIP_MIC_ERR); | 1326 | decrypt_err = !!(attention & RX_ATTENTION_FLAGS_DECRYPT_ERR); |
| 1317 | decrypt_err = !!(__le32_to_cpu(rxd->attention.flags) & | ||
| 1318 | RX_ATTENTION_FLAGS_DECRYPT_ERR); | ||
| 1319 | fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), | 1327 | fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), |
| 1320 | RX_MSDU_START_INFO1_DECAP_FORMAT); | 1328 | RX_MSDU_START_INFO1_DECAP_FORMAT); |
| 1321 | 1329 | ||
| @@ -1422,6 +1430,86 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar, | |||
| 1422 | } | 1430 | } |
| 1423 | } | 1431 | } |
| 1424 | 1432 | ||
| 1433 | static void ath10k_htt_rx_addba(struct ath10k *ar, struct htt_resp *resp) | ||
| 1434 | { | ||
| 1435 | struct htt_rx_addba *ev = &resp->rx_addba; | ||
| 1436 | struct ath10k_peer *peer; | ||
| 1437 | struct ath10k_vif *arvif; | ||
| 1438 | u16 info0, tid, peer_id; | ||
| 1439 | |||
| 1440 | info0 = __le16_to_cpu(ev->info0); | ||
| 1441 | tid = MS(info0, HTT_RX_BA_INFO0_TID); | ||
| 1442 | peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID); | ||
| 1443 | |||
| 1444 | ath10k_dbg(ATH10K_DBG_HTT, | ||
| 1445 | "htt rx addba tid %hu peer_id %hu size %hhu\n", | ||
| 1446 | tid, peer_id, ev->window_size); | ||
| 1447 | |||
| 1448 | spin_lock_bh(&ar->data_lock); | ||
| 1449 | peer = ath10k_peer_find_by_id(ar, peer_id); | ||
| 1450 | if (!peer) { | ||
| 1451 | ath10k_warn("received addba event for invalid peer_id: %hu\n", | ||
| 1452 | peer_id); | ||
| 1453 | spin_unlock_bh(&ar->data_lock); | ||
| 1454 | return; | ||
| 1455 | } | ||
| 1456 | |||
| 1457 | arvif = ath10k_get_arvif(ar, peer->vdev_id); | ||
| 1458 | if (!arvif) { | ||
| 1459 | ath10k_warn("received addba event for invalid vdev_id: %u\n", | ||
| 1460 | peer->vdev_id); | ||
| 1461 | spin_unlock_bh(&ar->data_lock); | ||
| 1462 | return; | ||
| 1463 | } | ||
| 1464 | |||
| 1465 | ath10k_dbg(ATH10K_DBG_HTT, | ||
| 1466 | "htt rx start rx ba session sta %pM tid %hu size %hhu\n", | ||
| 1467 | peer->addr, tid, ev->window_size); | ||
| 1468 | |||
| 1469 | ieee80211_start_rx_ba_session_offl(arvif->vif, peer->addr, tid); | ||
| 1470 | spin_unlock_bh(&ar->data_lock); | ||
| 1471 | } | ||
| 1472 | |||
| 1473 | static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp) | ||
| 1474 | { | ||
| 1475 | struct htt_rx_delba *ev = &resp->rx_delba; | ||
| 1476 | struct ath10k_peer *peer; | ||
| 1477 | struct ath10k_vif *arvif; | ||
| 1478 | u16 info0, tid, peer_id; | ||
| 1479 | |||
| 1480 | info0 = __le16_to_cpu(ev->info0); | ||
| 1481 | tid = MS(info0, HTT_RX_BA_INFO0_TID); | ||
| 1482 | peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID); | ||
| 1483 | |||
| 1484 | ath10k_dbg(ATH10K_DBG_HTT, | ||
| 1485 | "htt rx delba tid %hu peer_id %hu\n", | ||
| 1486 | tid, peer_id); | ||
| 1487 | |||
| 1488 | spin_lock_bh(&ar->data_lock); | ||
| 1489 | peer = ath10k_peer_find_by_id(ar, peer_id); | ||
| 1490 | if (!peer) { | ||
| 1491 | ath10k_warn("received addba event for invalid peer_id: %hu\n", | ||
| 1492 | peer_id); | ||
| 1493 | spin_unlock_bh(&ar->data_lock); | ||
| 1494 | return; | ||
| 1495 | } | ||
| 1496 | |||
| 1497 | arvif = ath10k_get_arvif(ar, peer->vdev_id); | ||
| 1498 | if (!arvif) { | ||
| 1499 | ath10k_warn("received addba event for invalid vdev_id: %u\n", | ||
| 1500 | peer->vdev_id); | ||
| 1501 | spin_unlock_bh(&ar->data_lock); | ||
| 1502 | return; | ||
| 1503 | } | ||
| 1504 | |||
| 1505 | ath10k_dbg(ATH10K_DBG_HTT, | ||
| 1506 | "htt rx stop rx ba session sta %pM tid %hu\n", | ||
| 1507 | peer->addr, tid); | ||
| 1508 | |||
| 1509 | ieee80211_stop_rx_ba_session_offl(arvif->vif, peer->addr, tid); | ||
| 1510 | spin_unlock_bh(&ar->data_lock); | ||
| 1511 | } | ||
| 1512 | |||
| 1425 | void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) | 1513 | void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) |
| 1426 | { | 1514 | { |
| 1427 | struct ath10k_htt *htt = &ar->htt; | 1515 | struct ath10k_htt *htt = &ar->htt; |
| @@ -1516,9 +1604,25 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) | |||
| 1516 | trace_ath10k_htt_stats(skb->data, skb->len); | 1604 | trace_ath10k_htt_stats(skb->data, skb->len); |
| 1517 | break; | 1605 | break; |
| 1518 | case HTT_T2H_MSG_TYPE_TX_INSPECT_IND: | 1606 | case HTT_T2H_MSG_TYPE_TX_INSPECT_IND: |
| 1607 | /* Firmware can return tx frames if it's unable to fully | ||
| 1608 | * process them and suspects host may be able to fix it. ath10k | ||
| 1609 | * sends all tx frames as already inspected so this shouldn't | ||
| 1610 | * happen unless fw has a bug. | ||
| 1611 | */ | ||
| 1612 | ath10k_warn("received an unexpected htt tx inspect event\n"); | ||
| 1613 | break; | ||
| 1519 | case HTT_T2H_MSG_TYPE_RX_ADDBA: | 1614 | case HTT_T2H_MSG_TYPE_RX_ADDBA: |
| 1615 | ath10k_htt_rx_addba(ar, resp); | ||
| 1616 | break; | ||
| 1520 | case HTT_T2H_MSG_TYPE_RX_DELBA: | 1617 | case HTT_T2H_MSG_TYPE_RX_DELBA: |
| 1521 | case HTT_T2H_MSG_TYPE_RX_FLUSH: | 1618 | ath10k_htt_rx_delba(ar, resp); |
| 1619 | break; | ||
| 1620 | case HTT_T2H_MSG_TYPE_RX_FLUSH: { | ||
| 1621 | /* Ignore this event because mac80211 takes care of Rx | ||
| 1622 | * aggregation reordering. | ||
| 1623 | */ | ||
| 1624 | break; | ||
| 1625 | } | ||
| 1522 | default: | 1626 | default: |
| 1523 | ath10k_dbg(ATH10K_DBG_HTT, "htt event (%d) not handled\n", | 1627 | ath10k_dbg(ATH10K_DBG_HTT, "htt event (%d) not handled\n", |
| 1524 | resp->hdr.msg_type); | 1628 | resp->hdr.msg_type); |
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 7064354d1f4f..8b27bfcc1de3 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c | |||
| @@ -307,6 +307,52 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt) | |||
| 307 | return 0; | 307 | return 0; |
| 308 | } | 308 | } |
| 309 | 309 | ||
| 310 | int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, | ||
| 311 | u8 max_subfrms_ampdu, | ||
| 312 | u8 max_subfrms_amsdu) | ||
| 313 | { | ||
| 314 | struct htt_aggr_conf *aggr_conf; | ||
| 315 | struct sk_buff *skb; | ||
| 316 | struct htt_cmd *cmd; | ||
| 317 | int len; | ||
| 318 | int ret; | ||
| 319 | |||
| 320 | /* Firmware defaults are: amsdu = 3 and ampdu = 64 */ | ||
| 321 | |||
| 322 | if (max_subfrms_ampdu == 0 || max_subfrms_ampdu > 64) | ||
| 323 | return -EINVAL; | ||
| 324 | |||
| 325 | if (max_subfrms_amsdu == 0 || max_subfrms_amsdu > 31) | ||
| 326 | return -EINVAL; | ||
| 327 | |||
| 328 | len = sizeof(cmd->hdr); | ||
| 329 | len += sizeof(cmd->aggr_conf); | ||
| 330 | |||
| 331 | skb = ath10k_htc_alloc_skb(len); | ||
| 332 | if (!skb) | ||
| 333 | return -ENOMEM; | ||
| 334 | |||
| 335 | skb_put(skb, len); | ||
| 336 | cmd = (struct htt_cmd *)skb->data; | ||
| 337 | cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_AGGR_CFG; | ||
| 338 | |||
| 339 | aggr_conf = &cmd->aggr_conf; | ||
| 340 | aggr_conf->max_num_ampdu_subframes = max_subfrms_ampdu; | ||
| 341 | aggr_conf->max_num_amsdu_subframes = max_subfrms_amsdu; | ||
| 342 | |||
| 343 | ath10k_dbg(ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d", | ||
| 344 | aggr_conf->max_num_amsdu_subframes, | ||
| 345 | aggr_conf->max_num_ampdu_subframes); | ||
| 346 | |||
| 347 | ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); | ||
| 348 | if (ret) { | ||
| 349 | dev_kfree_skb_any(skb); | ||
| 350 | return ret; | ||
| 351 | } | ||
| 352 | |||
| 353 | return 0; | ||
| 354 | } | ||
| 355 | |||
| 310 | int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | 356 | int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) |
| 311 | { | 357 | { |
| 312 | struct device *dev = htt->ar->dev; | 358 | struct device *dev = htt->ar->dev; |
| @@ -485,6 +531,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | |||
| 485 | flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; | 531 | flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; |
| 486 | flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; | 532 | flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; |
| 487 | 533 | ||
| 534 | /* Prevent firmware from sending up tx inspection requests. There's | ||
| 535 | * nothing ath10k can do with frames requested for inspection so force | ||
| 536 | * it to simply rely a regular tx completion with discard status. | ||
| 537 | */ | ||
| 538 | flags1 |= HTT_DATA_TX_DESC_FLAGS1_POSTPONED; | ||
| 539 | |||
| 488 | skb_cb->htt.txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; | 540 | skb_cb->htt.txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; |
| 489 | skb_cb->htt.txbuf->cmd_tx.flags0 = flags0; | 541 | skb_cb->htt.txbuf->cmd_tx.flags0 = flags0; |
| 490 | skb_cb->htt.txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1); | 542 | skb_cb->htt.txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1); |
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a21080028c54..9d61bb157189 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
| @@ -1865,15 +1865,13 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, | |||
| 1865 | return 0; | 1865 | return 0; |
| 1866 | } | 1866 | } |
| 1867 | 1867 | ||
| 1868 | /* | 1868 | /* HTT Tx uses Native Wifi tx mode which expects 802.11 frames without QoS |
| 1869 | * Frames sent to the FW have to be in "Native Wifi" format. | 1869 | * Control in the header. |
| 1870 | * Strip the QoS field from the 802.11 header. | ||
| 1871 | */ | 1870 | */ |
| 1872 | static void ath10k_tx_h_qos_workaround(struct ieee80211_hw *hw, | 1871 | static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb) |
| 1873 | struct ieee80211_tx_control *control, | ||
| 1874 | struct sk_buff *skb) | ||
| 1875 | { | 1872 | { |
| 1876 | struct ieee80211_hdr *hdr = (void *)skb->data; | 1873 | struct ieee80211_hdr *hdr = (void *)skb->data; |
| 1874 | struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb); | ||
| 1877 | u8 *qos_ctl; | 1875 | u8 *qos_ctl; |
| 1878 | 1876 | ||
| 1879 | if (!ieee80211_is_data_qos(hdr->frame_control)) | 1877 | if (!ieee80211_is_data_qos(hdr->frame_control)) |
| @@ -1883,6 +1881,16 @@ static void ath10k_tx_h_qos_workaround(struct ieee80211_hw *hw, | |||
| 1883 | memmove(skb->data + IEEE80211_QOS_CTL_LEN, | 1881 | memmove(skb->data + IEEE80211_QOS_CTL_LEN, |
| 1884 | skb->data, (void *)qos_ctl - (void *)skb->data); | 1882 | skb->data, (void *)qos_ctl - (void *)skb->data); |
| 1885 | skb_pull(skb, IEEE80211_QOS_CTL_LEN); | 1883 | skb_pull(skb, IEEE80211_QOS_CTL_LEN); |
| 1884 | |||
| 1885 | /* Fw/Hw generates a corrupted QoS Control Field for QoS NullFunc | ||
| 1886 | * frames. Powersave is handled by the fw/hw so QoS NyllFunc frames are | ||
| 1887 | * used only for CQM purposes (e.g. hostapd station keepalive ping) so | ||
| 1888 | * it is safe to downgrade to NullFunc. | ||
| 1889 | */ | ||
| 1890 | if (ieee80211_is_qos_nullfunc(hdr->frame_control)) { | ||
| 1891 | hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA); | ||
| 1892 | cb->htt.tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST; | ||
| 1893 | } | ||
| 1886 | } | 1894 | } |
| 1887 | 1895 | ||
| 1888 | static void ath10k_tx_wep_key_work(struct work_struct *work) | 1896 | static void ath10k_tx_wep_key_work(struct work_struct *work) |
| @@ -1919,14 +1927,13 @@ unlock: | |||
| 1919 | mutex_unlock(&arvif->ar->conf_mutex); | 1927 | mutex_unlock(&arvif->ar->conf_mutex); |
| 1920 | } | 1928 | } |
| 1921 | 1929 | ||
| 1922 | static void ath10k_tx_h_update_wep_key(struct sk_buff *skb) | 1930 | static void ath10k_tx_h_update_wep_key(struct ieee80211_vif *vif, |
| 1931 | struct ieee80211_key_conf *key, | ||
| 1932 | struct sk_buff *skb) | ||
| 1923 | { | 1933 | { |
| 1924 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 1925 | struct ieee80211_vif *vif = info->control.vif; | ||
| 1926 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | 1934 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); |
| 1927 | struct ath10k *ar = arvif->ar; | 1935 | struct ath10k *ar = arvif->ar; |
| 1928 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 1936 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
| 1929 | struct ieee80211_key_conf *key = info->control.hw_key; | ||
| 1930 | 1937 | ||
| 1931 | if (!ieee80211_has_protected(hdr->frame_control)) | 1938 | if (!ieee80211_has_protected(hdr->frame_control)) |
| 1932 | return; | 1939 | return; |
| @@ -1948,11 +1955,11 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb) | |||
| 1948 | ieee80211_queue_work(ar->hw, &arvif->wep_key_work); | 1955 | ieee80211_queue_work(ar->hw, &arvif->wep_key_work); |
| 1949 | } | 1956 | } |
| 1950 | 1957 | ||
| 1951 | static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct sk_buff *skb) | 1958 | static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, |
| 1959 | struct ieee80211_vif *vif, | ||
| 1960 | struct sk_buff *skb) | ||
| 1952 | { | 1961 | { |
| 1953 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 1962 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
| 1954 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 1955 | struct ieee80211_vif *vif = info->control.vif; | ||
| 1956 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | 1963 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); |
| 1957 | 1964 | ||
| 1958 | /* This is case only for P2P_GO */ | 1965 | /* This is case only for P2P_GO */ |
| @@ -2254,33 +2261,28 @@ static void ath10k_tx(struct ieee80211_hw *hw, | |||
| 2254 | struct ieee80211_tx_control *control, | 2261 | struct ieee80211_tx_control *control, |
| 2255 | struct sk_buff *skb) | 2262 | struct sk_buff *skb) |
| 2256 | { | 2263 | { |
| 2264 | struct ath10k *ar = hw->priv; | ||
| 2257 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 2265 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 2266 | struct ieee80211_vif *vif = info->control.vif; | ||
| 2267 | struct ieee80211_key_conf *key = info->control.hw_key; | ||
| 2258 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 2268 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
| 2259 | struct ath10k *ar = hw->priv; | ||
| 2260 | u8 tid, vdev_id; | ||
| 2261 | 2269 | ||
| 2262 | /* We should disable CCK RATE due to P2P */ | 2270 | /* We should disable CCK RATE due to P2P */ |
| 2263 | if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE) | 2271 | if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE) |
| 2264 | ath10k_dbg(ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n"); | 2272 | ath10k_dbg(ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n"); |
| 2265 | 2273 | ||
| 2266 | /* we must calculate tid before we apply qos workaround | 2274 | ATH10K_SKB_CB(skb)->htt.is_offchan = false; |
| 2267 | * as we'd lose the qos control field */ | 2275 | ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr); |
| 2268 | tid = ath10k_tx_h_get_tid(hdr); | 2276 | ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, info); |
| 2269 | vdev_id = ath10k_tx_h_get_vdev_id(ar, info); | ||
| 2270 | 2277 | ||
| 2271 | /* it makes no sense to process injected frames like that */ | 2278 | /* it makes no sense to process injected frames like that */ |
| 2272 | if (info->control.vif && | 2279 | if (vif && vif->type != NL80211_IFTYPE_MONITOR) { |
| 2273 | info->control.vif->type != NL80211_IFTYPE_MONITOR) { | 2280 | ath10k_tx_h_nwifi(hw, skb); |
| 2274 | ath10k_tx_h_qos_workaround(hw, control, skb); | 2281 | ath10k_tx_h_update_wep_key(vif, key, skb); |
| 2275 | ath10k_tx_h_update_wep_key(skb); | 2282 | ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb); |
| 2276 | ath10k_tx_h_add_p2p_noa_ie(ar, skb); | 2283 | ath10k_tx_h_seq_no(vif, skb); |
| 2277 | ath10k_tx_h_seq_no(skb); | ||
| 2278 | } | 2284 | } |
| 2279 | 2285 | ||
| 2280 | ATH10K_SKB_CB(skb)->vdev_id = vdev_id; | ||
| 2281 | ATH10K_SKB_CB(skb)->htt.is_offchan = false; | ||
| 2282 | ATH10K_SKB_CB(skb)->htt.tid = tid; | ||
| 2283 | |||
| 2284 | if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { | 2286 | if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { |
| 2285 | spin_lock_bh(&ar->data_lock); | 2287 | spin_lock_bh(&ar->data_lock); |
| 2286 | ATH10K_SKB_CB(skb)->htt.is_offchan = true; | 2288 | ATH10K_SKB_CB(skb)->htt.is_offchan = true; |
| @@ -3137,10 +3139,11 @@ exit: | |||
| 3137 | 3139 | ||
| 3138 | static int ath10k_hw_scan(struct ieee80211_hw *hw, | 3140 | static int ath10k_hw_scan(struct ieee80211_hw *hw, |
| 3139 | struct ieee80211_vif *vif, | 3141 | struct ieee80211_vif *vif, |
| 3140 | struct cfg80211_scan_request *req) | 3142 | struct ieee80211_scan_request *hw_req) |
| 3141 | { | 3143 | { |
| 3142 | struct ath10k *ar = hw->priv; | 3144 | struct ath10k *ar = hw->priv; |
| 3143 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | 3145 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); |
| 3146 | struct cfg80211_scan_request *req = &hw_req->req; | ||
| 3144 | struct wmi_start_scan_arg arg; | 3147 | struct wmi_start_scan_arg arg; |
| 3145 | int ret = 0; | 3148 | int ret = 0; |
| 3146 | int i; | 3149 | int i; |
| @@ -4330,6 +4333,38 @@ static u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
| 4330 | return 0; | 4333 | return 0; |
| 4331 | } | 4334 | } |
| 4332 | 4335 | ||
| 4336 | static int ath10k_ampdu_action(struct ieee80211_hw *hw, | ||
| 4337 | struct ieee80211_vif *vif, | ||
| 4338 | enum ieee80211_ampdu_mlme_action action, | ||
| 4339 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, | ||
| 4340 | u8 buf_size) | ||
| 4341 | { | ||
| 4342 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | ||
| 4343 | |||
| 4344 | ath10k_dbg(ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n", | ||
| 4345 | arvif->vdev_id, sta->addr, tid, action); | ||
| 4346 | |||
| 4347 | switch (action) { | ||
| 4348 | case IEEE80211_AMPDU_RX_START: | ||
| 4349 | case IEEE80211_AMPDU_RX_STOP: | ||
| 4350 | /* HTT AddBa/DelBa events trigger mac80211 Rx BA session | ||
| 4351 | * creation/removal. Do we need to verify this? | ||
| 4352 | */ | ||
| 4353 | return 0; | ||
| 4354 | case IEEE80211_AMPDU_TX_START: | ||
| 4355 | case IEEE80211_AMPDU_TX_STOP_CONT: | ||
| 4356 | case IEEE80211_AMPDU_TX_STOP_FLUSH: | ||
| 4357 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: | ||
| 4358 | case IEEE80211_AMPDU_TX_OPERATIONAL: | ||
| 4359 | /* Firmware offloads Tx aggregation entirely so deny mac80211 | ||
| 4360 | * Tx aggregation requests. | ||
| 4361 | */ | ||
| 4362 | return -EOPNOTSUPP; | ||
| 4363 | } | ||
| 4364 | |||
| 4365 | return -EINVAL; | ||
| 4366 | } | ||
| 4367 | |||
| 4333 | static const struct ieee80211_ops ath10k_ops = { | 4368 | static const struct ieee80211_ops ath10k_ops = { |
| 4334 | .tx = ath10k_tx, | 4369 | .tx = ath10k_tx, |
| 4335 | .start = ath10k_start, | 4370 | .start = ath10k_start, |
| @@ -4357,6 +4392,7 @@ static const struct ieee80211_ops ath10k_ops = { | |||
| 4357 | .set_bitrate_mask = ath10k_set_bitrate_mask, | 4392 | .set_bitrate_mask = ath10k_set_bitrate_mask, |
| 4358 | .sta_rc_update = ath10k_sta_rc_update, | 4393 | .sta_rc_update = ath10k_sta_rc_update, |
| 4359 | .get_tsf = ath10k_get_tsf, | 4394 | .get_tsf = ath10k_get_tsf, |
| 4395 | .ampdu_action = ath10k_ampdu_action, | ||
| 4360 | #ifdef CONFIG_PM | 4396 | #ifdef CONFIG_PM |
| 4361 | .suspend = ath10k_suspend, | 4397 | .suspend = ath10k_suspend, |
| 4362 | .resume = ath10k_resume, | 4398 | .resume = ath10k_resume, |
| @@ -4697,7 +4733,6 @@ int ath10k_mac_register(struct ath10k *ar) | |||
| 4697 | 4733 | ||
| 4698 | ar->hw->wiphy->interface_modes = | 4734 | ar->hw->wiphy->interface_modes = |
| 4699 | BIT(NL80211_IFTYPE_STATION) | | 4735 | BIT(NL80211_IFTYPE_STATION) | |
| 4700 | BIT(NL80211_IFTYPE_ADHOC) | | ||
| 4701 | BIT(NL80211_IFTYPE_AP); | 4736 | BIT(NL80211_IFTYPE_AP); |
| 4702 | 4737 | ||
| 4703 | if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { | 4738 | if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { |
| @@ -4767,6 +4802,8 @@ int ath10k_mac_register(struct ath10k *ar) | |||
| 4767 | ar->hw->wiphy->iface_combinations = ath10k_if_comb; | 4802 | ar->hw->wiphy->iface_combinations = ath10k_if_comb; |
| 4768 | ar->hw->wiphy->n_iface_combinations = | 4803 | ar->hw->wiphy->n_iface_combinations = |
| 4769 | ARRAY_SIZE(ath10k_if_comb); | 4804 | ARRAY_SIZE(ath10k_if_comb); |
| 4805 | |||
| 4806 | ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); | ||
| 4770 | } | 4807 | } |
| 4771 | 4808 | ||
| 4772 | ar->hw->netdev_features = NETIF_F_HW_CSUM; | 4809 | ar->hw->netdev_features = NETIF_F_HW_CSUM; |
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index ba1021997b8f..ef4f84376d7c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h | |||
| @@ -43,11 +43,11 @@ static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif) | |||
| 43 | return (struct ath10k_vif *)vif->drv_priv; | 43 | return (struct ath10k_vif *)vif->drv_priv; |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | static inline void ath10k_tx_h_seq_no(struct sk_buff *skb) | 46 | static inline void ath10k_tx_h_seq_no(struct ieee80211_vif *vif, |
| 47 | struct sk_buff *skb) | ||
| 47 | { | 48 | { |
| 48 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 49 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 49 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 50 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
| 50 | struct ieee80211_vif *vif = info->control.vif; | ||
| 51 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | 51 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); |
| 52 | 52 | ||
| 53 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | 53 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { |
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index d0004d59c97e..3376963a4862 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c | |||
| @@ -63,7 +63,7 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); | |||
| 63 | 63 | ||
| 64 | #define QCA988X_2_0_DEVICE_ID (0x003c) | 64 | #define QCA988X_2_0_DEVICE_ID (0x003c) |
| 65 | 65 | ||
| 66 | static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = { | 66 | static const struct pci_device_id ath10k_pci_id_table[] = { |
| 67 | { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ | 67 | { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ |
| 68 | {0} | 68 | {0} |
| 69 | }; | 69 | }; |
| @@ -726,18 +726,12 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) | |||
| 726 | unsigned int nbytes, max_nbytes; | 726 | unsigned int nbytes, max_nbytes; |
| 727 | unsigned int transfer_id; | 727 | unsigned int transfer_id; |
| 728 | unsigned int flags; | 728 | unsigned int flags; |
| 729 | int err; | 729 | int err, num_replenish = 0; |
| 730 | 730 | ||
| 731 | while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, | 731 | while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, |
| 732 | &ce_data, &nbytes, &transfer_id, | 732 | &ce_data, &nbytes, &transfer_id, |
| 733 | &flags) == 0) { | 733 | &flags) == 0) { |
| 734 | err = ath10k_pci_post_rx_pipe(pipe_info, 1); | 734 | num_replenish++; |
| 735 | if (unlikely(err)) { | ||
| 736 | /* FIXME: retry */ | ||
| 737 | ath10k_warn("failed to replenish CE rx ring %d: %d\n", | ||
| 738 | pipe_info->pipe_num, err); | ||
| 739 | } | ||
| 740 | |||
| 741 | skb = transfer_context; | 735 | skb = transfer_context; |
| 742 | max_nbytes = skb->len + skb_tailroom(skb); | 736 | max_nbytes = skb->len + skb_tailroom(skb); |
| 743 | dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, | 737 | dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, |
| @@ -753,6 +747,13 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) | |||
| 753 | skb_put(skb, nbytes); | 747 | skb_put(skb, nbytes); |
| 754 | cb->rx_completion(ar, skb, pipe_info->pipe_num); | 748 | cb->rx_completion(ar, skb, pipe_info->pipe_num); |
| 755 | } | 749 | } |
| 750 | |||
| 751 | err = ath10k_pci_post_rx_pipe(pipe_info, num_replenish); | ||
| 752 | if (unlikely(err)) { | ||
| 753 | /* FIXME: retry */ | ||
| 754 | ath10k_warn("failed to replenish CE rx ring %d (%d bufs): %d\n", | ||
| 755 | pipe_info->pipe_num, num_replenish, err); | ||
| 756 | } | ||
| 756 | } | 757 | } |
| 757 | 758 | ||
| 758 | static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, | 759 | static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, |
| @@ -1362,8 +1363,6 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, | |||
| 1362 | ath10k_ce_recv_buf_enqueue(ce_rx, &xfer, resp_paddr); | 1363 | ath10k_ce_recv_buf_enqueue(ce_rx, &xfer, resp_paddr); |
| 1363 | } | 1364 | } |
| 1364 | 1365 | ||
| 1365 | init_completion(&xfer.done); | ||
| 1366 | |||
| 1367 | ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0); | 1366 | ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0); |
| 1368 | if (ret) | 1367 | if (ret) |
| 1369 | goto err_resp; | 1368 | goto err_resp; |
| @@ -1414,10 +1413,7 @@ static void ath10k_pci_bmi_send_done(struct ath10k_ce_pipe *ce_state) | |||
| 1414 | &nbytes, &transfer_id)) | 1413 | &nbytes, &transfer_id)) |
| 1415 | return; | 1414 | return; |
| 1416 | 1415 | ||
| 1417 | if (xfer->wait_for_resp) | 1416 | xfer->tx_done = true; |
| 1418 | return; | ||
| 1419 | |||
| 1420 | complete(&xfer->done); | ||
| 1421 | } | 1417 | } |
| 1422 | 1418 | ||
| 1423 | static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) | 1419 | static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) |
| @@ -1438,7 +1434,7 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) | |||
| 1438 | } | 1434 | } |
| 1439 | 1435 | ||
| 1440 | xfer->resp_len = nbytes; | 1436 | xfer->resp_len = nbytes; |
| 1441 | complete(&xfer->done); | 1437 | xfer->rx_done = true; |
| 1442 | } | 1438 | } |
| 1443 | 1439 | ||
| 1444 | static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, | 1440 | static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, |
| @@ -1451,7 +1447,7 @@ static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, | |||
| 1451 | ath10k_pci_bmi_send_done(tx_pipe); | 1447 | ath10k_pci_bmi_send_done(tx_pipe); |
| 1452 | ath10k_pci_bmi_recv_data(rx_pipe); | 1448 | ath10k_pci_bmi_recv_data(rx_pipe); |
| 1453 | 1449 | ||
| 1454 | if (completion_done(&xfer->done)) | 1450 | if (xfer->tx_done && (xfer->rx_done == xfer->wait_for_resp)) |
| 1455 | return 0; | 1451 | return 0; |
| 1456 | 1452 | ||
| 1457 | schedule(); | 1453 | schedule(); |
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index dfdebb4157aa..940129209990 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h | |||
| @@ -38,7 +38,8 @@ | |||
| 38 | #define DIAG_TRANSFER_LIMIT 2048 | 38 | #define DIAG_TRANSFER_LIMIT 2048 |
| 39 | 39 | ||
| 40 | struct bmi_xfer { | 40 | struct bmi_xfer { |
| 41 | struct completion done; | 41 | bool tx_done; |
| 42 | bool rx_done; | ||
| 42 | bool wait_for_resp; | 43 | bool wait_for_resp; |
| 43 | u32 resp_len; | 44 | u32 resp_len; |
| 44 | }; | 45 | }; |
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 82669a77e553..f4fa22d1d591 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c | |||
| @@ -119,8 +119,7 @@ struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, | |||
| 119 | return NULL; | 119 | return NULL; |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | static struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, | 122 | struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id) |
| 123 | int peer_id) | ||
| 124 | { | 123 | { |
| 125 | struct ath10k_peer *peer; | 124 | struct ath10k_peer *peer; |
| 126 | 125 | ||
diff --git a/drivers/net/wireless/ath/ath10k/txrx.h b/drivers/net/wireless/ath/ath10k/txrx.h index aee3e20058f8..a90e09f5c7f2 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.h +++ b/drivers/net/wireless/ath/ath10k/txrx.h | |||
| @@ -24,6 +24,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, | |||
| 24 | 24 | ||
| 25 | struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, | 25 | struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, |
| 26 | const u8 *addr); | 26 | const u8 *addr); |
| 27 | struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id); | ||
| 27 | int ath10k_wait_for_peer_created(struct ath10k *ar, int vdev_id, | 28 | int ath10k_wait_for_peer_created(struct ath10k *ar, int vdev_id, |
| 28 | const u8 *addr); | 29 | const u8 *addr); |
| 29 | int ath10k_wait_for_peer_deleted(struct ath10k *ar, int vdev_id, | 30 | int ath10k_wait_for_peer_deleted(struct ath10k *ar, int vdev_id, |
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 4b7782a529ac..c2c87c916b5a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c | |||
| @@ -1432,7 +1432,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) | |||
| 1432 | continue; | 1432 | continue; |
| 1433 | } | 1433 | } |
| 1434 | 1434 | ||
| 1435 | ath10k_tx_h_seq_no(bcn); | 1435 | ath10k_tx_h_seq_no(arvif->vif, bcn); |
| 1436 | ath10k_wmi_update_tim(ar, arvif, bcn, bcn_info); | 1436 | ath10k_wmi_update_tim(ar, arvif, bcn, bcn_info); |
| 1437 | ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); | 1437 | ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); |
| 1438 | 1438 | ||
| @@ -2106,7 +2106,6 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb) | |||
| 2106 | { | 2106 | { |
| 2107 | struct wmi_cmd_hdr *cmd_hdr; | 2107 | struct wmi_cmd_hdr *cmd_hdr; |
| 2108 | enum wmi_event_id id; | 2108 | enum wmi_event_id id; |
| 2109 | u16 len; | ||
| 2110 | 2109 | ||
| 2111 | cmd_hdr = (struct wmi_cmd_hdr *)skb->data; | 2110 | cmd_hdr = (struct wmi_cmd_hdr *)skb->data; |
| 2112 | id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); | 2111 | id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); |
| @@ -2114,8 +2113,6 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb) | |||
| 2114 | if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) | 2113 | if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) |
| 2115 | return; | 2114 | return; |
| 2116 | 2115 | ||
| 2117 | len = skb->len; | ||
| 2118 | |||
| 2119 | trace_ath10k_wmi_event(id, skb->data, skb->len); | 2116 | trace_ath10k_wmi_event(id, skb->data, skb->len); |
| 2120 | 2117 | ||
| 2121 | switch (id) { | 2118 | switch (id) { |
| @@ -2225,7 +2222,6 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb) | |||
| 2225 | { | 2222 | { |
| 2226 | struct wmi_cmd_hdr *cmd_hdr; | 2223 | struct wmi_cmd_hdr *cmd_hdr; |
| 2227 | enum wmi_10x_event_id id; | 2224 | enum wmi_10x_event_id id; |
| 2228 | u16 len; | ||
| 2229 | 2225 | ||
| 2230 | cmd_hdr = (struct wmi_cmd_hdr *)skb->data; | 2226 | cmd_hdr = (struct wmi_cmd_hdr *)skb->data; |
| 2231 | id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); | 2227 | id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); |
| @@ -2233,8 +2229,6 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb) | |||
| 2233 | if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) | 2229 | if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) |
| 2234 | return; | 2230 | return; |
| 2235 | 2231 | ||
| 2236 | len = skb->len; | ||
| 2237 | |||
| 2238 | trace_ath10k_wmi_event(id, skb->data, skb->len); | 2232 | trace_ath10k_wmi_event(id, skb->data, skb->len); |
| 2239 | 2233 | ||
| 2240 | switch (id) { | 2234 | switch (id) { |
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 74bd54d6aceb..85316bb3f8c6 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h | |||
| @@ -1285,6 +1285,7 @@ struct ath5k_hw { | |||
| 1285 | #define ATH_STAT_STARTED 3 /* opened & irqs enabled */ | 1285 | #define ATH_STAT_STARTED 3 /* opened & irqs enabled */ |
| 1286 | 1286 | ||
| 1287 | unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ | 1287 | unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ |
| 1288 | unsigned int fif_filter_flags; /* Current FIF_* filter flags */ | ||
| 1288 | struct ieee80211_channel *curchan; /* current h/w channel */ | 1289 | struct ieee80211_channel *curchan; /* current h/w channel */ |
| 1289 | 1290 | ||
| 1290 | u16 nvifs; | 1291 | u16 nvifs; |
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 4b18434ba697..8ad2550bce7f 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
| @@ -1382,6 +1382,9 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb, | |||
| 1382 | rxs->flag = 0; | 1382 | rxs->flag = 0; |
| 1383 | if (unlikely(rs->rs_status & AR5K_RXERR_MIC)) | 1383 | if (unlikely(rs->rs_status & AR5K_RXERR_MIC)) |
| 1384 | rxs->flag |= RX_FLAG_MMIC_ERROR; | 1384 | rxs->flag |= RX_FLAG_MMIC_ERROR; |
| 1385 | if (unlikely(rs->rs_status & AR5K_RXERR_CRC)) | ||
| 1386 | rxs->flag |= RX_FLAG_FAILED_FCS_CRC; | ||
| 1387 | |||
| 1385 | 1388 | ||
| 1386 | /* | 1389 | /* |
| 1387 | * always extend the mac timestamp, since this information is | 1390 | * always extend the mac timestamp, since this information is |
| @@ -1449,6 +1452,8 @@ ath5k_receive_frame_ok(struct ath5k_hw *ah, struct ath5k_rx_status *rs) | |||
| 1449 | ah->stats.rx_bytes_count += rs->rs_datalen; | 1452 | ah->stats.rx_bytes_count += rs->rs_datalen; |
| 1450 | 1453 | ||
| 1451 | if (unlikely(rs->rs_status)) { | 1454 | if (unlikely(rs->rs_status)) { |
| 1455 | unsigned int filters; | ||
| 1456 | |||
| 1452 | if (rs->rs_status & AR5K_RXERR_CRC) | 1457 | if (rs->rs_status & AR5K_RXERR_CRC) |
| 1453 | ah->stats.rxerr_crc++; | 1458 | ah->stats.rxerr_crc++; |
| 1454 | if (rs->rs_status & AR5K_RXERR_FIFO) | 1459 | if (rs->rs_status & AR5K_RXERR_FIFO) |
| @@ -1457,7 +1462,20 @@ ath5k_receive_frame_ok(struct ath5k_hw *ah, struct ath5k_rx_status *rs) | |||
| 1457 | ah->stats.rxerr_phy++; | 1462 | ah->stats.rxerr_phy++; |
| 1458 | if (rs->rs_phyerr > 0 && rs->rs_phyerr < 32) | 1463 | if (rs->rs_phyerr > 0 && rs->rs_phyerr < 32) |
| 1459 | ah->stats.rxerr_phy_code[rs->rs_phyerr]++; | 1464 | ah->stats.rxerr_phy_code[rs->rs_phyerr]++; |
| 1460 | return false; | 1465 | |
| 1466 | /* | ||
| 1467 | * Treat packets that underwent a CCK or OFDM reset as having a bad CRC. | ||
| 1468 | * These restarts happen when the radio resynchronizes to a stronger frame | ||
| 1469 | * while receiving a weaker frame. Here we receive the prefix of the weak | ||
| 1470 | * frame. Since these are incomplete packets, mark their CRC as invalid. | ||
| 1471 | */ | ||
| 1472 | if (rs->rs_phyerr == AR5K_RX_PHY_ERROR_OFDM_RESTART || | ||
| 1473 | rs->rs_phyerr == AR5K_RX_PHY_ERROR_CCK_RESTART) { | ||
| 1474 | rs->rs_status |= AR5K_RXERR_CRC; | ||
| 1475 | rs->rs_status &= ~AR5K_RXERR_PHY; | ||
| 1476 | } else { | ||
| 1477 | return false; | ||
| 1478 | } | ||
| 1461 | } | 1479 | } |
| 1462 | if (rs->rs_status & AR5K_RXERR_DECRYPT) { | 1480 | if (rs->rs_status & AR5K_RXERR_DECRYPT) { |
| 1463 | /* | 1481 | /* |
| @@ -1480,8 +1498,15 @@ ath5k_receive_frame_ok(struct ath5k_hw *ah, struct ath5k_rx_status *rs) | |||
| 1480 | return true; | 1498 | return true; |
| 1481 | } | 1499 | } |
| 1482 | 1500 | ||
| 1483 | /* reject any frames with non-crypto errors */ | 1501 | /* |
| 1484 | if (rs->rs_status & ~(AR5K_RXERR_DECRYPT)) | 1502 | * Reject any frames with non-crypto errors, and take into account the |
| 1503 | * current FIF_* filters. | ||
| 1504 | */ | ||
| 1505 | filters = AR5K_RXERR_DECRYPT; | ||
| 1506 | if (ah->fif_filter_flags & FIF_FCSFAIL) | ||
| 1507 | filters |= AR5K_RXERR_CRC; | ||
| 1508 | |||
| 1509 | if (rs->rs_status & ~filters) | ||
| 1485 | return false; | 1510 | return false; |
| 1486 | } | 1511 | } |
| 1487 | 1512 | ||
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index f77ef36acf87..48a6a69b57bc 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c | |||
| @@ -53,7 +53,7 @@ | |||
| 53 | #define ATH_POLARITY(data) ((data) & 0xff) | 53 | #define ATH_POLARITY(data) ((data) & 0xff) |
| 54 | 54 | ||
| 55 | /* Devices we match on for LED config info (typically laptops) */ | 55 | /* Devices we match on for LED config info (typically laptops) */ |
| 56 | static DEFINE_PCI_DEVICE_TABLE(ath5k_led_devices) = { | 56 | static const struct pci_device_id ath5k_led_devices[] = { |
| 57 | /* AR5211 */ | 57 | /* AR5211 */ |
| 58 | { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5211), ATH_LED(0, 0) }, | 58 | { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5211), ATH_LED(0, 0) }, |
| 59 | /* HP Compaq nc6xx, nc4000, nx6000 */ | 59 | /* HP Compaq nc6xx, nc4000, nx6000 */ |
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index afb23b3cc7be..b65c38fdaa4b 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c | |||
| @@ -473,6 +473,8 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, | |||
| 473 | /* Set the cached hw filter flags, this will later actually | 473 | /* Set the cached hw filter flags, this will later actually |
| 474 | * be set in HW */ | 474 | * be set in HW */ |
| 475 | ah->filter_flags = rfilt; | 475 | ah->filter_flags = rfilt; |
| 476 | /* Store current FIF filter flags */ | ||
| 477 | ah->fif_filter_flags = *new_flags; | ||
| 476 | 478 | ||
| 477 | mutex_unlock(&ah->lock); | 479 | mutex_unlock(&ah->lock); |
| 478 | } | 480 | } |
diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index 859db7c34f87..c6156cc38940 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c | |||
| @@ -28,7 +28,7 @@ | |||
| 28 | #include "reg.h" | 28 | #include "reg.h" |
| 29 | 29 | ||
| 30 | /* Known PCI ids */ | 30 | /* Known PCI ids */ |
| 31 | static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = { | 31 | static const struct pci_device_id ath5k_pci_id_table[] = { |
| 32 | { PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */ | 32 | { PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */ |
| 33 | { PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */ | 33 | { PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */ |
| 34 | { PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/ | 34 | { PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/ |
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.h b/drivers/net/wireless/ath/ath6kl/bmi.h index 18fdd69e1f71..397a52f2628b 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.h +++ b/drivers/net/wireless/ath/ath6kl/bmi.h | |||
| @@ -242,7 +242,8 @@ struct ath6kl_bmi_target_info { | |||
| 242 | (void) (check_type == val); \ | 242 | (void) (check_type == val); \ |
| 243 | addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \ | 243 | addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \ |
| 244 | ret = ath6kl_bmi_read(ar, addr, (u8 *) &tmp, 4); \ | 244 | ret = ath6kl_bmi_read(ar, addr, (u8 *) &tmp, 4); \ |
| 245 | *val = le32_to_cpu(tmp); \ | 245 | if (!ret) \ |
| 246 | *val = le32_to_cpu(tmp); \ | ||
| 246 | ret; \ | 247 | ret; \ |
| 247 | }) | 248 | }) |
| 248 | 249 | ||
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 0e26f4a34fda..e535807c3d89 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
| @@ -2899,7 +2899,8 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 2899 | if (info->inactivity_timeout) { | 2899 | if (info->inactivity_timeout) { |
| 2900 | inactivity_timeout = info->inactivity_timeout; | 2900 | inactivity_timeout = info->inactivity_timeout; |
| 2901 | 2901 | ||
| 2902 | if (ar->hw.flags & ATH6KL_HW_AP_INACTIVITY_MINS) | 2902 | if (test_bit(ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS, |
| 2903 | ar->fw_capabilities)) | ||
| 2903 | inactivity_timeout = DIV_ROUND_UP(inactivity_timeout, | 2904 | inactivity_timeout = DIV_ROUND_UP(inactivity_timeout, |
| 2904 | 60); | 2905 | 60); |
| 2905 | 2906 | ||
| @@ -3636,7 +3637,7 @@ struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, | |||
| 3636 | struct net_device *ndev; | 3637 | struct net_device *ndev; |
| 3637 | struct ath6kl_vif *vif; | 3638 | struct ath6kl_vif *vif; |
| 3638 | 3639 | ||
| 3639 | ndev = alloc_netdev(sizeof(*vif), name, ether_setup); | 3640 | ndev = alloc_netdev(sizeof(*vif), name, NET_NAME_UNKNOWN, ether_setup); |
| 3640 | if (!ndev) | 3641 | if (!ndev) |
| 3641 | return NULL; | 3642 | return NULL; |
| 3642 | 3643 | ||
| @@ -3782,7 +3783,8 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) | |||
| 3782 | ath6kl_band_5ghz.ht_cap.ht_supported = false; | 3783 | ath6kl_band_5ghz.ht_cap.ht_supported = false; |
| 3783 | } | 3784 | } |
| 3784 | 3785 | ||
| 3785 | if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) { | 3786 | if (test_bit(ATH6KL_FW_CAPABILITY_64BIT_RATES, |
| 3787 | ar->fw_capabilities)) { | ||
| 3786 | ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff; | 3788 | ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff; |
| 3787 | ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff; | 3789 | ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff; |
| 3788 | ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff; | 3790 | ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff; |
diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index b0b652042760..0df74b245af4 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c | |||
| @@ -123,6 +123,22 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) | |||
| 123 | 123 | ||
| 124 | /* FIXME: we should free all firmwares in the error cases below */ | 124 | /* FIXME: we should free all firmwares in the error cases below */ |
| 125 | 125 | ||
| 126 | /* | ||
| 127 | * Backwards compatibility support for older ar6004 firmware images | ||
| 128 | * which do not set these feature flags. | ||
| 129 | */ | ||
| 130 | if (ar->target_type == TARGET_TYPE_AR6004 && | ||
| 131 | ar->fw_api <= 4) { | ||
| 132 | __set_bit(ATH6KL_FW_CAPABILITY_64BIT_RATES, | ||
| 133 | ar->fw_capabilities); | ||
| 134 | __set_bit(ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS, | ||
| 135 | ar->fw_capabilities); | ||
| 136 | |||
| 137 | if (ar->hw.id == AR6004_HW_1_3_VERSION) | ||
| 138 | __set_bit(ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, | ||
| 139 | ar->fw_capabilities); | ||
| 140 | } | ||
| 141 | |||
| 126 | /* Indicate that WMI is enabled (although not ready yet) */ | 142 | /* Indicate that WMI is enabled (although not ready yet) */ |
| 127 | set_bit(WMI_ENABLED, &ar->flag); | 143 | set_bit(WMI_ENABLED, &ar->flag); |
| 128 | ar->wmi = ath6kl_wmi_init(ar); | 144 | ar->wmi = ath6kl_wmi_init(ar); |
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 26b0f92424e1..2b78c863d030 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h | |||
| @@ -136,6 +136,21 @@ enum ath6kl_fw_capability { | |||
| 136 | */ | 136 | */ |
| 137 | ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, | 137 | ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, |
| 138 | 138 | ||
| 139 | /* WMI_SET_TX_SELECT_RATES_CMDID uses 64 bit size rate table */ | ||
| 140 | ATH6KL_FW_CAPABILITY_64BIT_RATES, | ||
| 141 | |||
| 142 | /* WMI_AP_CONN_INACT_CMDID uses minutes as units */ | ||
| 143 | ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS, | ||
| 144 | |||
| 145 | /* use low priority endpoint for all data */ | ||
| 146 | ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, | ||
| 147 | |||
| 148 | /* ratetable is the 2 stream version (max MCS15) */ | ||
| 149 | ATH6KL_FW_CAPABILITY_RATETABLE_MCS15, | ||
| 150 | |||
| 151 | /* firmare doesn't support IP checksumming */ | ||
| 152 | ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM, | ||
| 153 | |||
| 139 | /* this needs to be last */ | 154 | /* this needs to be last */ |
| 140 | ATH6KL_FW_CAPABILITY_MAX, | 155 | ATH6KL_FW_CAPABILITY_MAX, |
| 141 | }; | 156 | }; |
| @@ -149,15 +164,13 @@ struct ath6kl_fw_ie { | |||
| 149 | }; | 164 | }; |
| 150 | 165 | ||
| 151 | enum ath6kl_hw_flags { | 166 | enum ath6kl_hw_flags { |
| 152 | ATH6KL_HW_64BIT_RATES = BIT(0), | ||
| 153 | ATH6KL_HW_AP_INACTIVITY_MINS = BIT(1), | ||
| 154 | ATH6KL_HW_MAP_LP_ENDPOINT = BIT(2), | ||
| 155 | ATH6KL_HW_SDIO_CRC_ERROR_WAR = BIT(3), | 167 | ATH6KL_HW_SDIO_CRC_ERROR_WAR = BIT(3), |
| 156 | }; | 168 | }; |
| 157 | 169 | ||
| 158 | #define ATH6KL_FW_API2_FILE "fw-2.bin" | 170 | #define ATH6KL_FW_API2_FILE "fw-2.bin" |
| 159 | #define ATH6KL_FW_API3_FILE "fw-3.bin" | 171 | #define ATH6KL_FW_API3_FILE "fw-3.bin" |
| 160 | #define ATH6KL_FW_API4_FILE "fw-4.bin" | 172 | #define ATH6KL_FW_API4_FILE "fw-4.bin" |
| 173 | #define ATH6KL_FW_API5_FILE "fw-5.bin" | ||
| 161 | 174 | ||
| 162 | /* AR6003 1.0 definitions */ | 175 | /* AR6003 1.0 definitions */ |
| 163 | #define AR6003_HW_1_0_VERSION 0x300002ba | 176 | #define AR6003_HW_1_0_VERSION 0x300002ba |
| @@ -215,8 +228,21 @@ enum ath6kl_hw_flags { | |||
| 215 | #define AR6004_HW_1_3_VERSION 0x31c8088a | 228 | #define AR6004_HW_1_3_VERSION 0x31c8088a |
| 216 | #define AR6004_HW_1_3_FW_DIR "ath6k/AR6004/hw1.3" | 229 | #define AR6004_HW_1_3_FW_DIR "ath6k/AR6004/hw1.3" |
| 217 | #define AR6004_HW_1_3_FIRMWARE_FILE "fw.ram.bin" | 230 | #define AR6004_HW_1_3_FIRMWARE_FILE "fw.ram.bin" |
| 218 | #define AR6004_HW_1_3_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin" | 231 | #define AR6004_HW_1_3_TCMD_FIRMWARE_FILE "utf.bin" |
| 219 | #define AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin" | 232 | #define AR6004_HW_1_3_UTF_FIRMWARE_FILE "utf.bin" |
| 233 | #define AR6004_HW_1_3_TESTSCRIPT_FILE "nullTestFlow.bin" | ||
| 234 | #define AR6004_HW_1_3_BOARD_DATA_FILE AR6004_HW_1_3_FW_DIR "/bdata.bin" | ||
| 235 | #define AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE AR6004_HW_1_3_FW_DIR "/bdata.bin" | ||
| 236 | |||
| 237 | /* AR6004 3.0 definitions */ | ||
| 238 | #define AR6004_HW_3_0_VERSION 0x31C809F8 | ||
| 239 | #define AR6004_HW_3_0_FW_DIR "ath6k/AR6004/hw3.0" | ||
| 240 | #define AR6004_HW_3_0_FIRMWARE_FILE "fw.ram.bin" | ||
| 241 | #define AR6004_HW_3_0_TCMD_FIRMWARE_FILE "utf.bin" | ||
| 242 | #define AR6004_HW_3_0_UTF_FIRMWARE_FILE "utf.bin" | ||
| 243 | #define AR6004_HW_3_0_TESTSCRIPT_FILE "nullTestFlow.bin" | ||
| 244 | #define AR6004_HW_3_0_BOARD_DATA_FILE AR6004_HW_3_0_FW_DIR "/bdata.bin" | ||
| 245 | #define AR6004_HW_3_0_DEFAULT_BOARD_DATA_FILE AR6004_HW_3_0_FW_DIR "/bdata.bin" | ||
| 220 | 246 | ||
| 221 | /* Per STA data, used in AP mode */ | 247 | /* Per STA data, used in AP mode */ |
| 222 | #define STA_PS_AWAKE BIT(0) | 248 | #define STA_PS_AWAKE BIT(0) |
diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index 756fe52a12c8..ca1a18c86c0d 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c | |||
| @@ -1170,8 +1170,12 @@ static int htc_wait_recv_ctrl_message(struct htc_target *target) | |||
| 1170 | static void htc_rxctrl_complete(struct htc_target *context, | 1170 | static void htc_rxctrl_complete(struct htc_target *context, |
| 1171 | struct htc_packet *packet) | 1171 | struct htc_packet *packet) |
| 1172 | { | 1172 | { |
| 1173 | /* TODO, can't really receive HTC control messages yet.... */ | 1173 | struct sk_buff *skb = packet->skb; |
| 1174 | ath6kl_dbg(ATH6KL_DBG_HTC, "%s: invalid call function\n", __func__); | 1174 | |
| 1175 | if (packet->endpoint == ENDPOINT_0 && | ||
| 1176 | packet->status == -ECANCELED && | ||
| 1177 | skb != NULL) | ||
| 1178 | dev_kfree_skb(skb); | ||
| 1175 | } | 1179 | } |
| 1176 | 1180 | ||
| 1177 | /* htc pipe initialization */ | 1181 | /* htc pipe initialization */ |
| @@ -1678,7 +1682,29 @@ static void ath6kl_htc_pipe_activity_changed(struct htc_target *target, | |||
| 1678 | 1682 | ||
| 1679 | static void ath6kl_htc_pipe_flush_rx_buf(struct htc_target *target) | 1683 | static void ath6kl_htc_pipe_flush_rx_buf(struct htc_target *target) |
| 1680 | { | 1684 | { |
| 1681 | /* TODO */ | 1685 | struct htc_endpoint *endpoint; |
| 1686 | struct htc_packet *packet, *tmp_pkt; | ||
| 1687 | int i; | ||
| 1688 | |||
| 1689 | for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { | ||
| 1690 | endpoint = &target->endpoint[i]; | ||
| 1691 | |||
| 1692 | spin_lock_bh(&target->rx_lock); | ||
| 1693 | |||
| 1694 | list_for_each_entry_safe(packet, tmp_pkt, | ||
| 1695 | &endpoint->rx_bufq, list) { | ||
| 1696 | list_del(&packet->list); | ||
| 1697 | spin_unlock_bh(&target->rx_lock); | ||
| 1698 | ath6kl_dbg(ATH6KL_DBG_HTC, | ||
| 1699 | "htc rx flush pkt 0x%p len %d ep %d\n", | ||
| 1700 | packet, packet->buf_len, | ||
| 1701 | packet->endpoint); | ||
| 1702 | dev_kfree_skb(packet->pkt_cntxt); | ||
| 1703 | spin_lock_bh(&target->rx_lock); | ||
| 1704 | } | ||
| 1705 | |||
| 1706 | spin_unlock_bh(&target->rx_lock); | ||
| 1707 | } | ||
| 1682 | } | 1708 | } |
| 1683 | 1709 | ||
| 1684 | static int ath6kl_htc_pipe_credit_setup(struct htc_target *target, | 1710 | static int ath6kl_htc_pipe_credit_setup(struct htc_target *target, |
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index d5ef211f261c..fffd52355123 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c | |||
| @@ -93,8 +93,7 @@ static const struct ath6kl_hw hw_list[] = { | |||
| 93 | .board_addr = 0x433900, | 93 | .board_addr = 0x433900, |
| 94 | .refclk_hz = 26000000, | 94 | .refclk_hz = 26000000, |
| 95 | .uarttx_pin = 11, | 95 | .uarttx_pin = 11, |
| 96 | .flags = ATH6KL_HW_64BIT_RATES | | 96 | .flags = 0, |
| 97 | ATH6KL_HW_AP_INACTIVITY_MINS, | ||
| 98 | 97 | ||
| 99 | .fw = { | 98 | .fw = { |
| 100 | .dir = AR6004_HW_1_0_FW_DIR, | 99 | .dir = AR6004_HW_1_0_FW_DIR, |
| @@ -114,8 +113,7 @@ static const struct ath6kl_hw hw_list[] = { | |||
| 114 | .board_addr = 0x43d400, | 113 | .board_addr = 0x43d400, |
| 115 | .refclk_hz = 40000000, | 114 | .refclk_hz = 40000000, |
| 116 | .uarttx_pin = 11, | 115 | .uarttx_pin = 11, |
| 117 | .flags = ATH6KL_HW_64BIT_RATES | | 116 | .flags = 0, |
| 118 | ATH6KL_HW_AP_INACTIVITY_MINS, | ||
| 119 | .fw = { | 117 | .fw = { |
| 120 | .dir = AR6004_HW_1_1_FW_DIR, | 118 | .dir = AR6004_HW_1_1_FW_DIR, |
| 121 | .fw = AR6004_HW_1_1_FIRMWARE_FILE, | 119 | .fw = AR6004_HW_1_1_FIRMWARE_FILE, |
| @@ -134,8 +132,7 @@ static const struct ath6kl_hw hw_list[] = { | |||
| 134 | .board_addr = 0x435c00, | 132 | .board_addr = 0x435c00, |
| 135 | .refclk_hz = 40000000, | 133 | .refclk_hz = 40000000, |
| 136 | .uarttx_pin = 11, | 134 | .uarttx_pin = 11, |
| 137 | .flags = ATH6KL_HW_64BIT_RATES | | 135 | .flags = 0, |
| 138 | ATH6KL_HW_AP_INACTIVITY_MINS, | ||
| 139 | 136 | ||
| 140 | .fw = { | 137 | .fw = { |
| 141 | .dir = AR6004_HW_1_2_FW_DIR, | 138 | .dir = AR6004_HW_1_2_FW_DIR, |
| @@ -152,20 +149,43 @@ static const struct ath6kl_hw hw_list[] = { | |||
| 152 | .board_ext_data_addr = 0x437000, | 149 | .board_ext_data_addr = 0x437000, |
| 153 | .reserved_ram_size = 7168, | 150 | .reserved_ram_size = 7168, |
| 154 | .board_addr = 0x436400, | 151 | .board_addr = 0x436400, |
| 155 | .refclk_hz = 40000000, | 152 | .refclk_hz = 0, |
| 156 | .uarttx_pin = 11, | 153 | .uarttx_pin = 11, |
| 157 | .flags = ATH6KL_HW_64BIT_RATES | | 154 | .flags = 0, |
| 158 | ATH6KL_HW_AP_INACTIVITY_MINS | | ||
| 159 | ATH6KL_HW_MAP_LP_ENDPOINT, | ||
| 160 | 155 | ||
| 161 | .fw = { | 156 | .fw = { |
| 162 | .dir = AR6004_HW_1_3_FW_DIR, | 157 | .dir = AR6004_HW_1_3_FW_DIR, |
| 163 | .fw = AR6004_HW_1_3_FIRMWARE_FILE, | 158 | .fw = AR6004_HW_1_3_FIRMWARE_FILE, |
| 159 | .tcmd = AR6004_HW_1_3_TCMD_FIRMWARE_FILE, | ||
| 160 | .utf = AR6004_HW_1_3_UTF_FIRMWARE_FILE, | ||
| 161 | .testscript = AR6004_HW_1_3_TESTSCRIPT_FILE, | ||
| 164 | }, | 162 | }, |
| 165 | 163 | ||
| 166 | .fw_board = AR6004_HW_1_3_BOARD_DATA_FILE, | 164 | .fw_board = AR6004_HW_1_3_BOARD_DATA_FILE, |
| 167 | .fw_default_board = AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE, | 165 | .fw_default_board = AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE, |
| 168 | }, | 166 | }, |
| 167 | { | ||
| 168 | .id = AR6004_HW_3_0_VERSION, | ||
| 169 | .name = "ar6004 hw 3.0", | ||
| 170 | .dataset_patch_addr = 0, | ||
| 171 | .app_load_addr = 0x1234, | ||
| 172 | .board_ext_data_addr = 0, | ||
| 173 | .reserved_ram_size = 7168, | ||
| 174 | .board_addr = 0x436400, | ||
| 175 | .testscript_addr = 0, | ||
| 176 | .flags = 0, | ||
| 177 | |||
| 178 | .fw = { | ||
| 179 | .dir = AR6004_HW_3_0_FW_DIR, | ||
| 180 | .fw = AR6004_HW_3_0_FIRMWARE_FILE, | ||
| 181 | .tcmd = AR6004_HW_3_0_TCMD_FIRMWARE_FILE, | ||
| 182 | .utf = AR6004_HW_3_0_UTF_FIRMWARE_FILE, | ||
| 183 | .testscript = AR6004_HW_3_0_TESTSCRIPT_FILE, | ||
| 184 | }, | ||
| 185 | |||
| 186 | .fw_board = AR6004_HW_3_0_BOARD_DATA_FILE, | ||
| 187 | .fw_default_board = AR6004_HW_3_0_DEFAULT_BOARD_DATA_FILE, | ||
| 188 | }, | ||
| 169 | }; | 189 | }; |
| 170 | 190 | ||
| 171 | /* | 191 | /* |
| @@ -601,7 +621,9 @@ int ath6kl_configure_target(struct ath6kl *ar) | |||
| 601 | * but possible in theory. | 621 | * but possible in theory. |
| 602 | */ | 622 | */ |
| 603 | 623 | ||
| 604 | if (ar->target_type == TARGET_TYPE_AR6003) { | 624 | if ((ar->target_type == TARGET_TYPE_AR6003) || |
| 625 | (ar->version.target_ver == AR6004_HW_1_3_VERSION) || | ||
| 626 | (ar->version.target_ver == AR6004_HW_3_0_VERSION)) { | ||
| 605 | param = ar->hw.board_ext_data_addr; | 627 | param = ar->hw.board_ext_data_addr; |
| 606 | ram_reserved_size = ar->hw.reserved_ram_size; | 628 | ram_reserved_size = ar->hw.reserved_ram_size; |
| 607 | 629 | ||
| @@ -629,9 +651,12 @@ int ath6kl_configure_target(struct ath6kl *ar) | |||
| 629 | return status; | 651 | return status; |
| 630 | 652 | ||
| 631 | /* Configure target refclk_hz */ | 653 | /* Configure target refclk_hz */ |
| 632 | status = ath6kl_bmi_write_hi32(ar, hi_refclk_hz, ar->hw.refclk_hz); | 654 | if (ar->hw.refclk_hz != 0) { |
| 633 | if (status) | 655 | status = ath6kl_bmi_write_hi32(ar, hi_refclk_hz, |
| 634 | return status; | 656 | ar->hw.refclk_hz); |
| 657 | if (status) | ||
| 658 | return status; | ||
| 659 | } | ||
| 635 | 660 | ||
| 636 | return 0; | 661 | return 0; |
| 637 | } | 662 | } |
| @@ -1112,6 +1137,12 @@ int ath6kl_init_fetch_firmwares(struct ath6kl *ar) | |||
| 1112 | if (ret) | 1137 | if (ret) |
| 1113 | return ret; | 1138 | return ret; |
| 1114 | 1139 | ||
| 1140 | ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API5_FILE); | ||
| 1141 | if (ret == 0) { | ||
| 1142 | ar->fw_api = 5; | ||
| 1143 | goto out; | ||
| 1144 | } | ||
| 1145 | |||
| 1115 | ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE); | 1146 | ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE); |
| 1116 | if (ret == 0) { | 1147 | if (ret == 0) { |
| 1117 | ar->fw_api = 4; | 1148 | ar->fw_api = 4; |
| @@ -1161,11 +1192,19 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) | |||
| 1161 | ath6kl_bmi_write_hi32(ar, hi_board_data, | 1192 | ath6kl_bmi_write_hi32(ar, hi_board_data, |
| 1162 | board_address); | 1193 | board_address); |
| 1163 | } else { | 1194 | } else { |
| 1164 | ath6kl_bmi_read_hi32(ar, hi_board_data, &board_address); | 1195 | ret = ath6kl_bmi_read_hi32(ar, hi_board_data, &board_address); |
| 1196 | if (ret) { | ||
| 1197 | ath6kl_err("Failed to get board file target address.\n"); | ||
| 1198 | return ret; | ||
| 1199 | } | ||
| 1165 | } | 1200 | } |
| 1166 | 1201 | ||
| 1167 | /* determine where in target ram to write extended board data */ | 1202 | /* determine where in target ram to write extended board data */ |
| 1168 | ath6kl_bmi_read_hi32(ar, hi_board_ext_data, &board_ext_address); | 1203 | ret = ath6kl_bmi_read_hi32(ar, hi_board_ext_data, &board_ext_address); |
| 1204 | if (ret) { | ||
| 1205 | ath6kl_err("Failed to get extended board file target address.\n"); | ||
| 1206 | return ret; | ||
| 1207 | } | ||
| 1169 | 1208 | ||
| 1170 | if (ar->target_type == TARGET_TYPE_AR6003 && | 1209 | if (ar->target_type == TARGET_TYPE_AR6003 && |
| 1171 | board_ext_address == 0) { | 1210 | board_ext_address == 0) { |
| @@ -1187,7 +1226,6 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) | |||
| 1187 | default: | 1226 | default: |
| 1188 | WARN_ON(1); | 1227 | WARN_ON(1); |
| 1189 | return -EINVAL; | 1228 | return -EINVAL; |
| 1190 | break; | ||
| 1191 | } | 1229 | } |
| 1192 | 1230 | ||
| 1193 | if (board_ext_address && | 1231 | if (board_ext_address && |
| @@ -1230,7 +1268,13 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) | |||
| 1230 | } | 1268 | } |
| 1231 | 1269 | ||
| 1232 | /* record the fact that Board Data IS initialized */ | 1270 | /* record the fact that Board Data IS initialized */ |
| 1233 | ath6kl_bmi_write_hi32(ar, hi_board_data_initialized, 1); | 1271 | if ((ar->version.target_ver == AR6004_HW_1_3_VERSION) || |
| 1272 | (ar->version.target_ver == AR6004_HW_3_0_VERSION)) | ||
| 1273 | param = board_data_size; | ||
| 1274 | else | ||
| 1275 | param = 1; | ||
| 1276 | |||
| 1277 | ath6kl_bmi_write_hi32(ar, hi_board_data_initialized, param); | ||
| 1234 | 1278 | ||
| 1235 | return ret; | 1279 | return ret; |
| 1236 | } | 1280 | } |
| @@ -1361,7 +1405,11 @@ static int ath6kl_upload_testscript(struct ath6kl *ar) | |||
| 1361 | } | 1405 | } |
| 1362 | 1406 | ||
| 1363 | ath6kl_bmi_write_hi32(ar, hi_ota_testscript, address); | 1407 | ath6kl_bmi_write_hi32(ar, hi_ota_testscript, address); |
| 1364 | ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, 4096); | 1408 | |
| 1409 | if ((ar->version.target_ver != AR6004_HW_1_3_VERSION) && | ||
| 1410 | (ar->version.target_ver != AR6004_HW_3_0_VERSION)) | ||
| 1411 | ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, 4096); | ||
| 1412 | |||
| 1365 | ath6kl_bmi_write_hi32(ar, hi_test_apps_related, 1); | 1413 | ath6kl_bmi_write_hi32(ar, hi_test_apps_related, 1); |
| 1366 | 1414 | ||
| 1367 | return 0; | 1415 | return 0; |
| @@ -1567,6 +1615,11 @@ static const struct fw_capa_str_map { | |||
| 1567 | { ATH6KL_FW_CAPABILITY_REGDOMAIN, "regdomain" }, | 1615 | { ATH6KL_FW_CAPABILITY_REGDOMAIN, "regdomain" }, |
| 1568 | { ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, "sched-scan-v2" }, | 1616 | { ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, "sched-scan-v2" }, |
| 1569 | { ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, "hb-poll" }, | 1617 | { ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, "hb-poll" }, |
| 1618 | { ATH6KL_FW_CAPABILITY_64BIT_RATES, "64bit-rates" }, | ||
| 1619 | { ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS, "ap-inactivity-mins" }, | ||
| 1620 | { ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, "map-lp-endpoint" }, | ||
| 1621 | { ATH6KL_FW_CAPABILITY_RATETABLE_MCS15, "ratetable-mcs15" }, | ||
| 1622 | { ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM, "no-ip-checksum" }, | ||
| 1570 | }; | 1623 | }; |
| 1571 | 1624 | ||
| 1572 | static const char *ath6kl_init_get_fw_capa_name(unsigned int id) | 1625 | static const char *ath6kl_init_get_fw_capa_name(unsigned int id) |
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index d56554674da4..21516bc65785 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c | |||
| @@ -702,6 +702,7 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) | |||
| 702 | struct ath6kl *ar = vif->ar; | 702 | struct ath6kl *ar = vif->ar; |
| 703 | struct target_stats *stats = &vif->target_stats; | 703 | struct target_stats *stats = &vif->target_stats; |
| 704 | struct tkip_ccmp_stats *ccmp_stats; | 704 | struct tkip_ccmp_stats *ccmp_stats; |
| 705 | s32 rate; | ||
| 705 | u8 ac; | 706 | u8 ac; |
| 706 | 707 | ||
| 707 | if (len < sizeof(*tgt_stats)) | 708 | if (len < sizeof(*tgt_stats)) |
| @@ -731,8 +732,9 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) | |||
| 731 | le32_to_cpu(tgt_stats->stats.tx.mult_retry_cnt); | 732 | le32_to_cpu(tgt_stats->stats.tx.mult_retry_cnt); |
| 732 | stats->tx_rts_fail_cnt += | 733 | stats->tx_rts_fail_cnt += |
| 733 | le32_to_cpu(tgt_stats->stats.tx.rts_fail_cnt); | 734 | le32_to_cpu(tgt_stats->stats.tx.rts_fail_cnt); |
| 734 | stats->tx_ucast_rate = | 735 | |
| 735 | ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.tx.ucast_rate)); | 736 | rate = a_sle32_to_cpu(tgt_stats->stats.tx.ucast_rate); |
| 737 | stats->tx_ucast_rate = ath6kl_wmi_get_rate(ar->wmi, rate); | ||
| 736 | 738 | ||
| 737 | stats->rx_pkt += le32_to_cpu(tgt_stats->stats.rx.pkt); | 739 | stats->rx_pkt += le32_to_cpu(tgt_stats->stats.rx.pkt); |
| 738 | stats->rx_byte += le32_to_cpu(tgt_stats->stats.rx.byte); | 740 | stats->rx_byte += le32_to_cpu(tgt_stats->stats.rx.byte); |
| @@ -749,8 +751,9 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) | |||
| 749 | le32_to_cpu(tgt_stats->stats.rx.key_cache_miss); | 751 | le32_to_cpu(tgt_stats->stats.rx.key_cache_miss); |
| 750 | stats->rx_decrypt_err += le32_to_cpu(tgt_stats->stats.rx.decrypt_err); | 752 | stats->rx_decrypt_err += le32_to_cpu(tgt_stats->stats.rx.decrypt_err); |
| 751 | stats->rx_dupl_frame += le32_to_cpu(tgt_stats->stats.rx.dupl_frame); | 753 | stats->rx_dupl_frame += le32_to_cpu(tgt_stats->stats.rx.dupl_frame); |
| 752 | stats->rx_ucast_rate = | 754 | |
| 753 | ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.rx.ucast_rate)); | 755 | rate = a_sle32_to_cpu(tgt_stats->stats.rx.ucast_rate); |
| 756 | stats->rx_ucast_rate = ath6kl_wmi_get_rate(ar->wmi, rate); | ||
| 754 | 757 | ||
| 755 | ccmp_stats = &tgt_stats->stats.tkip_ccmp_stats; | 758 | ccmp_stats = &tgt_stats->stats.tkip_ccmp_stats; |
| 756 | 759 | ||
| @@ -1290,6 +1293,8 @@ static const struct net_device_ops ath6kl_netdev_ops = { | |||
| 1290 | 1293 | ||
| 1291 | void init_netdev(struct net_device *dev) | 1294 | void init_netdev(struct net_device *dev) |
| 1292 | { | 1295 | { |
| 1296 | struct ath6kl *ar = ath6kl_priv(dev); | ||
| 1297 | |||
| 1293 | dev->netdev_ops = &ath6kl_netdev_ops; | 1298 | dev->netdev_ops = &ath6kl_netdev_ops; |
| 1294 | dev->destructor = free_netdev; | 1299 | dev->destructor = free_netdev; |
| 1295 | dev->watchdog_timeo = ATH6KL_TX_TIMEOUT; | 1300 | dev->watchdog_timeo = ATH6KL_TX_TIMEOUT; |
| @@ -1301,7 +1306,9 @@ void init_netdev(struct net_device *dev) | |||
| 1301 | WMI_MAX_TX_META_SZ + | 1306 | WMI_MAX_TX_META_SZ + |
| 1302 | ATH6KL_HTC_ALIGN_BYTES, 4); | 1307 | ATH6KL_HTC_ALIGN_BYTES, 4); |
| 1303 | 1308 | ||
| 1304 | dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; | 1309 | if (!test_bit(ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM, |
| 1310 | ar->fw_capabilities)) | ||
| 1311 | dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; | ||
| 1305 | 1312 | ||
| 1306 | return; | 1313 | return; |
| 1307 | } | 1314 | } |
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 3afc5a463d06..c44325856b81 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c | |||
| @@ -802,7 +802,8 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id, | |||
| 802 | break; | 802 | break; |
| 803 | case WMI_DATA_VI_SVC: | 803 | case WMI_DATA_VI_SVC: |
| 804 | 804 | ||
| 805 | if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT) | 805 | if (test_bit(ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, |
| 806 | ar->fw_capabilities)) | ||
| 806 | *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; | 807 | *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; |
| 807 | else | 808 | else |
| 808 | *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; | 809 | *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; |
| @@ -814,7 +815,8 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id, | |||
| 814 | break; | 815 | break; |
| 815 | case WMI_DATA_VO_SVC: | 816 | case WMI_DATA_VO_SVC: |
| 816 | 817 | ||
| 817 | if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT) | 818 | if (test_bit(ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, |
| 819 | ar->fw_capabilities)) | ||
| 818 | *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; | 820 | *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; |
| 819 | else | 821 | else |
| 820 | *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; | 822 | *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; |
| @@ -1208,6 +1210,7 @@ static int ath6kl_usb_pm_reset_resume(struct usb_interface *intf) | |||
| 1208 | 1210 | ||
| 1209 | /* table of devices that work with this driver */ | 1211 | /* table of devices that work with this driver */ |
| 1210 | static struct usb_device_id ath6kl_usb_ids[] = { | 1212 | static struct usb_device_id ath6kl_usb_ids[] = { |
| 1213 | {USB_DEVICE(0x0cf3, 0x9375)}, | ||
| 1211 | {USB_DEVICE(0x0cf3, 0x9374)}, | 1214 | {USB_DEVICE(0x0cf3, 0x9374)}, |
| 1212 | { /* Terminating entry */ }, | 1215 | { /* Terminating entry */ }, |
| 1213 | }; | 1216 | }; |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 4d7f9e4712e9..94df345d08c2 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c | |||
| @@ -59,6 +59,55 @@ static const s32 wmi_rate_tbl[][2] = { | |||
| 59 | {0, 0} | 59 | {0, 0} |
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | static const s32 wmi_rate_tbl_mcs15[][2] = { | ||
| 63 | /* {W/O SGI, with SGI} */ | ||
| 64 | {1000, 1000}, | ||
| 65 | {2000, 2000}, | ||
| 66 | {5500, 5500}, | ||
| 67 | {11000, 11000}, | ||
| 68 | {6000, 6000}, | ||
| 69 | {9000, 9000}, | ||
| 70 | {12000, 12000}, | ||
| 71 | {18000, 18000}, | ||
| 72 | {24000, 24000}, | ||
| 73 | {36000, 36000}, | ||
| 74 | {48000, 48000}, | ||
| 75 | {54000, 54000}, | ||
| 76 | {6500, 7200}, /* HT 20, MCS 0 */ | ||
| 77 | {13000, 14400}, | ||
| 78 | {19500, 21700}, | ||
| 79 | {26000, 28900}, | ||
| 80 | {39000, 43300}, | ||
| 81 | {52000, 57800}, | ||
| 82 | {58500, 65000}, | ||
| 83 | {65000, 72200}, | ||
| 84 | {13000, 14400}, /* HT 20, MCS 8 */ | ||
| 85 | {26000, 28900}, | ||
| 86 | {39000, 43300}, | ||
| 87 | {52000, 57800}, | ||
| 88 | {78000, 86700}, | ||
| 89 | {104000, 115600}, | ||
| 90 | {117000, 130000}, | ||
| 91 | {130000, 144400}, /* HT 20, MCS 15 */ | ||
| 92 | {13500, 15000}, /*HT 40, MCS 0 */ | ||
| 93 | {27000, 30000}, | ||
| 94 | {40500, 45000}, | ||
| 95 | {54000, 60000}, | ||
| 96 | {81000, 90000}, | ||
| 97 | {108000, 120000}, | ||
| 98 | {121500, 135000}, | ||
| 99 | {135000, 150000}, | ||
| 100 | {27000, 30000}, /*HT 40, MCS 8 */ | ||
| 101 | {54000, 60000}, | ||
| 102 | {81000, 90000}, | ||
| 103 | {108000, 120000}, | ||
| 104 | {162000, 180000}, | ||
| 105 | {216000, 240000}, | ||
| 106 | {243000, 270000}, | ||
| 107 | {270000, 300000}, /*HT 40, MCS 15 */ | ||
| 108 | {0, 0} | ||
| 109 | }; | ||
| 110 | |||
| 62 | /* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */ | 111 | /* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */ |
| 63 | static const u8 up_to_ac[] = { | 112 | static const u8 up_to_ac[] = { |
| 64 | WMM_AC_BE, | 113 | WMM_AC_BE, |
| @@ -2838,7 +2887,8 @@ int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx, | |||
| 2838 | { | 2887 | { |
| 2839 | struct ath6kl *ar = wmi->parent_dev; | 2888 | struct ath6kl *ar = wmi->parent_dev; |
| 2840 | 2889 | ||
| 2841 | if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) | 2890 | if (test_bit(ATH6KL_FW_CAPABILITY_64BIT_RATES, |
| 2891 | ar->fw_capabilities)) | ||
| 2842 | return ath6kl_set_bitrate_mask64(wmi, if_idx, mask); | 2892 | return ath6kl_set_bitrate_mask64(wmi, if_idx, mask); |
| 2843 | else | 2893 | else |
| 2844 | return ath6kl_set_bitrate_mask32(wmi, if_idx, mask); | 2894 | return ath6kl_set_bitrate_mask32(wmi, if_idx, mask); |
| @@ -3279,9 +3329,11 @@ int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2) | |||
| 3279 | NO_SYNC_WMIFLAG); | 3329 | NO_SYNC_WMIFLAG); |
| 3280 | } | 3330 | } |
| 3281 | 3331 | ||
| 3282 | s32 ath6kl_wmi_get_rate(s8 rate_index) | 3332 | s32 ath6kl_wmi_get_rate(struct wmi *wmi, s8 rate_index) |
| 3283 | { | 3333 | { |
| 3334 | struct ath6kl *ar = wmi->parent_dev; | ||
| 3284 | u8 sgi = 0; | 3335 | u8 sgi = 0; |
| 3336 | s32 ret; | ||
| 3285 | 3337 | ||
| 3286 | if (rate_index == RATE_AUTO) | 3338 | if (rate_index == RATE_AUTO) |
| 3287 | return 0; | 3339 | return 0; |
| @@ -3292,10 +3344,20 @@ s32 ath6kl_wmi_get_rate(s8 rate_index) | |||
| 3292 | sgi = 1; | 3344 | sgi = 1; |
| 3293 | } | 3345 | } |
| 3294 | 3346 | ||
| 3295 | if (WARN_ON(rate_index > RATE_MCS_7_40)) | 3347 | if (test_bit(ATH6KL_FW_CAPABILITY_RATETABLE_MCS15, |
| 3296 | rate_index = RATE_MCS_7_40; | 3348 | ar->fw_capabilities)) { |
| 3349 | if (WARN_ON(rate_index >= ARRAY_SIZE(wmi_rate_tbl_mcs15))) | ||
| 3350 | return 0; | ||
| 3351 | |||
| 3352 | ret = wmi_rate_tbl_mcs15[(u32) rate_index][sgi]; | ||
| 3353 | } else { | ||
| 3354 | if (WARN_ON(rate_index >= ARRAY_SIZE(wmi_rate_tbl))) | ||
| 3355 | return 0; | ||
| 3297 | 3356 | ||
| 3298 | return wmi_rate_tbl[(u32) rate_index][sgi]; | 3357 | ret = wmi_rate_tbl[(u32) rate_index][sgi]; |
| 3358 | } | ||
| 3359 | |||
| 3360 | return ret; | ||
| 3299 | } | 3361 | } |
| 3300 | 3362 | ||
| 3301 | static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap, | 3363 | static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap, |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index bb23fc00111d..19f88b4a24fb 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h | |||
| @@ -2632,7 +2632,7 @@ int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx, | |||
| 2632 | struct ath6kl_htcap *htcap); | 2632 | struct ath6kl_htcap *htcap); |
| 2633 | int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len); | 2633 | int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len); |
| 2634 | 2634 | ||
| 2635 | s32 ath6kl_wmi_get_rate(s8 rate_index); | 2635 | s32 ath6kl_wmi_get_rate(struct wmi *wmi, s8 rate_index); |
| 2636 | 2636 | ||
| 2637 | int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx, | 2637 | int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx, |
| 2638 | __be32 ips0, __be32 ips1); | 2638 | __be32 ips0, __be32 ips1); |
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 8fcd586d1c39..6b4020a57984 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile | |||
| @@ -5,7 +5,8 @@ ath9k-y += beacon.o \ | |||
| 5 | recv.o \ | 5 | recv.o \ |
| 6 | xmit.o \ | 6 | xmit.o \ |
| 7 | link.o \ | 7 | link.o \ |
| 8 | antenna.o | 8 | antenna.o \ |
| 9 | channel.o | ||
| 9 | 10 | ||
| 10 | ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o | 11 | ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o |
| 11 | ath9k-$(CONFIG_ATH9K_PCI) += pci.o | 12 | ath9k-$(CONFIG_ATH9K_PCI) += pci.o |
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index be3eb2a8d602..4173838f4684 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c | |||
| @@ -113,6 +113,7 @@ static int ath_ahb_probe(struct platform_device *pdev) | |||
| 113 | 113 | ||
| 114 | irq = res->start; | 114 | irq = res->start; |
| 115 | 115 | ||
| 116 | ath9k_fill_chanctx_ops(); | ||
| 116 | hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); | 117 | hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); |
| 117 | if (hw == NULL) { | 118 | if (hw == NULL) { |
| 118 | dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); | 119 | dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); |
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 741b38ddcb37..59af9f9712da 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c | |||
| @@ -281,7 +281,7 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | |||
| 281 | 281 | ||
| 282 | ACCESS_ONCE(ads->ds_ctl0) = (i->pkt_len & AR_FrameLen) | 282 | ACCESS_ONCE(ads->ds_ctl0) = (i->pkt_len & AR_FrameLen) |
| 283 | | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | 283 | | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) |
| 284 | | SM(i->txpower, AR_XmitPower) | 284 | | SM(i->txpower, AR_XmitPower0) |
| 285 | | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | 285 | | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) |
| 286 | | (i->flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) | 286 | | (i->flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) |
| 287 | | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) | 287 | | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) |
| @@ -306,6 +306,10 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | |||
| 306 | | set11nRateFlags(i->rates, 2) | 306 | | set11nRateFlags(i->rates, 2) |
| 307 | | set11nRateFlags(i->rates, 3) | 307 | | set11nRateFlags(i->rates, 3) |
| 308 | | SM(i->rtscts_rate, AR_RTSCTSRate); | 308 | | SM(i->rtscts_rate, AR_RTSCTSRate); |
| 309 | |||
| 310 | ACCESS_ONCE(ads->ds_ctl9) = SM(i->txpower, AR_XmitPower1); | ||
| 311 | ACCESS_ONCE(ads->ds_ctl10) = SM(i->txpower, AR_XmitPower2); | ||
| 312 | ACCESS_ONCE(ads->ds_ctl11) = SM(i->txpower, AR_XmitPower3); | ||
| 309 | } | 313 | } |
| 310 | 314 | ||
| 311 | static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, | 315 | static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 235053ba7737..80c6eacbda53 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | |||
| @@ -3535,7 +3535,8 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) | |||
| 3535 | { | 3535 | { |
| 3536 | int bias = ar9003_modal_header(ah, is2ghz)->xpaBiasLvl; | 3536 | int bias = ar9003_modal_header(ah, is2ghz)->xpaBiasLvl; |
| 3537 | 3537 | ||
| 3538 | if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) | 3538 | if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah) || |
| 3539 | AR_SREV_9531(ah)) | ||
| 3539 | REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); | 3540 | REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); |
| 3540 | else if (AR_SREV_9462(ah) || AR_SREV_9550(ah) || AR_SREV_9565(ah)) | 3541 | else if (AR_SREV_9462(ah) || AR_SREV_9550(ah) || AR_SREV_9565(ah)) |
| 3541 | REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); | 3542 | REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index ec1da0cc25f5..ddef9eedbac6 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c | |||
| @@ -314,10 +314,17 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) | |||
| 314 | qca953x_1p0_mac_core); | 314 | qca953x_1p0_mac_core); |
| 315 | INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], | 315 | INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], |
| 316 | qca953x_1p0_mac_postamble); | 316 | qca953x_1p0_mac_postamble); |
| 317 | INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], | 317 | if (AR_SREV_9531_20(ah)) { |
| 318 | qca953x_1p0_baseband_core); | 318 | INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], |
| 319 | INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], | 319 | qca953x_2p0_baseband_core); |
| 320 | qca953x_1p0_baseband_postamble); | 320 | INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], |
| 321 | qca953x_2p0_baseband_postamble); | ||
| 322 | } else { | ||
| 323 | INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], | ||
| 324 | qca953x_1p0_baseband_core); | ||
| 325 | INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], | ||
| 326 | qca953x_1p0_baseband_postamble); | ||
| 327 | } | ||
| 321 | INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], | 328 | INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], |
| 322 | qca953x_1p0_radio_core); | 329 | qca953x_1p0_radio_core); |
| 323 | INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], | 330 | INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 729ffbf07343..71e38e85aa99 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c | |||
| @@ -101,7 +101,7 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | |||
| 101 | 101 | ||
| 102 | ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen) | 102 | ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen) |
| 103 | | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | 103 | | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) |
| 104 | | SM(i->txpower, AR_XmitPower) | 104 | | SM(i->txpower, AR_XmitPower0) |
| 105 | | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | 105 | | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) |
| 106 | | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) | 106 | | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) |
| 107 | | (i->flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0) | 107 | | (i->flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0) |
| @@ -151,6 +151,10 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | |||
| 151 | | SM(i->rtscts_rate, AR_RTSCTSRate); | 151 | | SM(i->rtscts_rate, AR_RTSCTSRate); |
| 152 | 152 | ||
| 153 | ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding; | 153 | ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding; |
| 154 | |||
| 155 | ACCESS_ONCE(ads->ctl20) = SM(i->txpower, AR_XmitPower1); | ||
| 156 | ACCESS_ONCE(ads->ctl21) = SM(i->txpower, AR_XmitPower2); | ||
| 157 | ACCESS_ONCE(ads->ctl22) = SM(i->txpower, AR_XmitPower3); | ||
| 154 | } | 158 | } |
| 155 | 159 | ||
| 156 | static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads) | 160 | static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads) |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 8927fc34d84c..542a8d51d3b0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c | |||
| @@ -1552,13 +1552,15 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah, | |||
| 1552 | u8 *ini_reloaded) | 1552 | u8 *ini_reloaded) |
| 1553 | { | 1553 | { |
| 1554 | unsigned int regWrites = 0; | 1554 | unsigned int regWrites = 0; |
| 1555 | u32 modesIndex; | 1555 | u32 modesIndex, txgain_index; |
| 1556 | 1556 | ||
| 1557 | if (IS_CHAN_5GHZ(chan)) | 1557 | if (IS_CHAN_5GHZ(chan)) |
| 1558 | modesIndex = IS_CHAN_HT40(chan) ? 2 : 1; | 1558 | modesIndex = IS_CHAN_HT40(chan) ? 2 : 1; |
| 1559 | else | 1559 | else |
| 1560 | modesIndex = IS_CHAN_HT40(chan) ? 3 : 4; | 1560 | modesIndex = IS_CHAN_HT40(chan) ? 3 : 4; |
| 1561 | 1561 | ||
| 1562 | txgain_index = AR_SREV_9531(ah) ? 1 : modesIndex; | ||
| 1563 | |||
| 1562 | if (modesIndex == ah->modes_index) { | 1564 | if (modesIndex == ah->modes_index) { |
| 1563 | *ini_reloaded = false; | 1565 | *ini_reloaded = false; |
| 1564 | goto set_rfmode; | 1566 | goto set_rfmode; |
| @@ -1573,7 +1575,7 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah, | |||
| 1573 | ar9003_hw_prog_ini(ah, &ah->ini_radio_post_sys2ant, | 1575 | ar9003_hw_prog_ini(ah, &ah->ini_radio_post_sys2ant, |
| 1574 | modesIndex); | 1576 | modesIndex); |
| 1575 | 1577 | ||
| 1576 | REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); | 1578 | REG_WRITE_ARRAY(&ah->iniModesTxGain, txgain_index, regWrites); |
| 1577 | 1579 | ||
| 1578 | if (AR_SREV_9462_20_OR_LATER(ah)) { | 1580 | if (AR_SREV_9462_20_OR_LATER(ah)) { |
| 1579 | /* | 1581 | /* |
diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h index 8e5c3b9786e3..812a9d787bf3 100644 --- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h | |||
| @@ -219,7 +219,7 @@ static const u32 qca953x_1p0_baseband_core[][2] = { | |||
| 219 | {0x00009d04, 0x40206c10}, | 219 | {0x00009d04, 0x40206c10}, |
| 220 | {0x00009d08, 0x009c4060}, | 220 | {0x00009d08, 0x009c4060}, |
| 221 | {0x00009d0c, 0x9883800a}, | 221 | {0x00009d0c, 0x9883800a}, |
| 222 | {0x00009d10, 0x01884061}, | 222 | {0x00009d10, 0x018848c6}, |
| 223 | {0x00009d14, 0x00c0040b}, | 223 | {0x00009d14, 0x00c0040b}, |
| 224 | {0x00009d18, 0x00000000}, | 224 | {0x00009d18, 0x00000000}, |
| 225 | {0x00009e08, 0x0038230c}, | 225 | {0x00009e08, 0x0038230c}, |
| @@ -715,4 +715,203 @@ static const u32 qca953x_1p1_modes_no_xpa_tx_gain_table[][2] = { | |||
| 715 | {0x00016448, 0x6c927a70}, | 715 | {0x00016448, 0x6c927a70}, |
| 716 | }; | 716 | }; |
| 717 | 717 | ||
| 718 | static const u32 qca953x_2p0_baseband_core[][2] = { | ||
| 719 | /* Addr allmodes */ | ||
| 720 | {0x00009800, 0xafe68e30}, | ||
| 721 | {0x00009804, 0xfd14e000}, | ||
| 722 | {0x00009808, 0x9c0a9f6b}, | ||
| 723 | {0x0000980c, 0x04900000}, | ||
| 724 | {0x00009814, 0x0280c00a}, | ||
| 725 | {0x00009818, 0x00000000}, | ||
| 726 | {0x0000981c, 0x00020028}, | ||
| 727 | {0x00009834, 0x6400a190}, | ||
| 728 | {0x00009838, 0x0108ecff}, | ||
| 729 | {0x0000983c, 0x14000600}, | ||
| 730 | {0x00009880, 0x201fff00}, | ||
| 731 | {0x00009884, 0x00001042}, | ||
| 732 | {0x000098a4, 0x00200400}, | ||
| 733 | {0x000098b0, 0x32840bbe}, | ||
| 734 | {0x000098bc, 0x00000002}, | ||
| 735 | {0x000098d0, 0x004b6a8e}, | ||
| 736 | {0x000098d4, 0x00000820}, | ||
| 737 | {0x000098dc, 0x00000000}, | ||
| 738 | {0x000098f0, 0x00000000}, | ||
| 739 | {0x000098f4, 0x00000000}, | ||
| 740 | {0x00009c04, 0xff55ff55}, | ||
| 741 | {0x00009c08, 0x0320ff55}, | ||
| 742 | {0x00009c0c, 0x00000000}, | ||
| 743 | {0x00009c10, 0x00000000}, | ||
| 744 | {0x00009c14, 0x00046384}, | ||
| 745 | {0x00009c18, 0x05b6b440}, | ||
| 746 | {0x00009c1c, 0x00b6b440}, | ||
| 747 | {0x00009d00, 0xc080a333}, | ||
| 748 | {0x00009d04, 0x40206c10}, | ||
| 749 | {0x00009d08, 0x009c4060}, | ||
| 750 | {0x00009d0c, 0x9883800a}, | ||
| 751 | {0x00009d10, 0x018848c6}, | ||
| 752 | {0x00009d14, 0x00c0040b}, | ||
| 753 | {0x00009d18, 0x00000000}, | ||
| 754 | {0x00009e08, 0x0038230c}, | ||
| 755 | {0x00009e24, 0x990bb515}, | ||
| 756 | {0x00009e28, 0x0c6f0000}, | ||
| 757 | {0x00009e30, 0x06336f77}, | ||
| 758 | {0x00009e34, 0x6af6532f}, | ||
| 759 | {0x00009e38, 0x0cc80c00}, | ||
| 760 | {0x00009e40, 0x0d261820}, | ||
| 761 | {0x00009e4c, 0x00001004}, | ||
| 762 | {0x00009e50, 0x00ff03f1}, | ||
| 763 | {0x00009fc0, 0x813e4788}, | ||
| 764 | {0x00009fc4, 0x0001efb5}, | ||
| 765 | {0x00009fcc, 0x40000014}, | ||
| 766 | {0x00009fd0, 0x02993b93}, | ||
| 767 | {0x0000a20c, 0x00000000}, | ||
| 768 | {0x0000a220, 0x00000000}, | ||
| 769 | {0x0000a224, 0x00000000}, | ||
| 770 | {0x0000a228, 0x10002310}, | ||
| 771 | {0x0000a23c, 0x00000000}, | ||
| 772 | {0x0000a244, 0x0c000000}, | ||
| 773 | {0x0000a248, 0x00000140}, | ||
| 774 | {0x0000a2a0, 0x00000007}, | ||
| 775 | {0x0000a2c0, 0x00000007}, | ||
| 776 | {0x0000a2c8, 0x00000000}, | ||
| 777 | {0x0000a2d4, 0x00000000}, | ||
| 778 | {0x0000a2ec, 0x00000000}, | ||
| 779 | {0x0000a2f0, 0x00000000}, | ||
| 780 | {0x0000a2f4, 0x00000000}, | ||
| 781 | {0x0000a2f8, 0x00000000}, | ||
| 782 | {0x0000a344, 0x00000000}, | ||
| 783 | {0x0000a34c, 0x00000000}, | ||
| 784 | {0x0000a350, 0x0000a000}, | ||
| 785 | {0x0000a364, 0x00000000}, | ||
| 786 | {0x0000a370, 0x00000000}, | ||
| 787 | {0x0000a390, 0x00000001}, | ||
| 788 | {0x0000a394, 0x00000444}, | ||
| 789 | {0x0000a398, 0x001f0e0f}, | ||
| 790 | {0x0000a39c, 0x0075393f}, | ||
| 791 | {0x0000a3a0, 0xb79f6427}, | ||
| 792 | {0x0000a3a4, 0x000400ff}, | ||
| 793 | {0x0000a3a8, 0x6a6a6a6a}, | ||
| 794 | {0x0000a3ac, 0x6a6a6a6a}, | ||
| 795 | {0x0000a3b0, 0x00c8641a}, | ||
| 796 | {0x0000a3b4, 0x0000001a}, | ||
| 797 | {0x0000a3b8, 0x0088642a}, | ||
| 798 | {0x0000a3bc, 0x000001fa}, | ||
| 799 | {0x0000a3c0, 0x20202020}, | ||
| 800 | {0x0000a3c4, 0x22222220}, | ||
| 801 | {0x0000a3c8, 0x20200020}, | ||
| 802 | {0x0000a3cc, 0x20202020}, | ||
| 803 | {0x0000a3d0, 0x20202020}, | ||
| 804 | {0x0000a3d4, 0x20202020}, | ||
| 805 | {0x0000a3d8, 0x20202020}, | ||
| 806 | {0x0000a3dc, 0x20202020}, | ||
| 807 | {0x0000a3e0, 0x20202020}, | ||
| 808 | {0x0000a3e4, 0x20202020}, | ||
| 809 | {0x0000a3e8, 0x20202020}, | ||
| 810 | {0x0000a3ec, 0x20202020}, | ||
| 811 | {0x0000a3f0, 0x00000000}, | ||
| 812 | {0x0000a3f4, 0x00000000}, | ||
| 813 | {0x0000a3f8, 0x0c9bd380}, | ||
| 814 | {0x0000a3fc, 0x000f0f01}, | ||
| 815 | {0x0000a400, 0x8fa91f01}, | ||
| 816 | {0x0000a404, 0x00000000}, | ||
| 817 | {0x0000a408, 0x0e79e5c6}, | ||
| 818 | {0x0000a40c, 0x00820820}, | ||
| 819 | {0x0000a414, 0x1ce42108}, | ||
| 820 | {0x0000a418, 0x2d001dce}, | ||
| 821 | {0x0000a41c, 0x1ce73908}, | ||
| 822 | {0x0000a420, 0x000001ce}, | ||
| 823 | {0x0000a424, 0x1ce738e7}, | ||
| 824 | {0x0000a428, 0x000001ce}, | ||
| 825 | {0x0000a42c, 0x1ce739ce}, | ||
| 826 | {0x0000a430, 0x1ce739ce}, | ||
| 827 | {0x0000a434, 0x00000000}, | ||
| 828 | {0x0000a438, 0x00001801}, | ||
| 829 | {0x0000a43c, 0x00100000}, | ||
| 830 | {0x0000a444, 0x00000000}, | ||
| 831 | {0x0000a448, 0x05000080}, | ||
| 832 | {0x0000a44c, 0x00000001}, | ||
| 833 | {0x0000a450, 0x00010000}, | ||
| 834 | {0x0000a458, 0x00000000}, | ||
| 835 | {0x0000a644, 0xbfad9d74}, | ||
| 836 | {0x0000a648, 0x0048060a}, | ||
| 837 | {0x0000a64c, 0x00003c37}, | ||
| 838 | {0x0000a670, 0x03020100}, | ||
| 839 | {0x0000a674, 0x09080504}, | ||
| 840 | {0x0000a678, 0x0d0c0b0a}, | ||
| 841 | {0x0000a67c, 0x13121110}, | ||
| 842 | {0x0000a680, 0x31301514}, | ||
| 843 | {0x0000a684, 0x35343332}, | ||
| 844 | {0x0000a688, 0x00000036}, | ||
| 845 | {0x0000a690, 0x08000838}, | ||
| 846 | {0x0000a7cc, 0x00000000}, | ||
| 847 | {0x0000a7d0, 0x00000000}, | ||
| 848 | {0x0000a7d4, 0x00000004}, | ||
| 849 | {0x0000a7dc, 0x00000000}, | ||
| 850 | {0x0000a8d0, 0x004b6a8e}, | ||
| 851 | {0x0000a8d4, 0x00000820}, | ||
| 852 | {0x0000a8dc, 0x00000000}, | ||
| 853 | {0x0000a8f0, 0x00000000}, | ||
| 854 | {0x0000a8f4, 0x00000000}, | ||
| 855 | {0x0000b2d0, 0x00000080}, | ||
| 856 | {0x0000b2d4, 0x00000000}, | ||
| 857 | {0x0000b2ec, 0x00000000}, | ||
| 858 | {0x0000b2f0, 0x00000000}, | ||
| 859 | {0x0000b2f4, 0x00000000}, | ||
| 860 | {0x0000b2f8, 0x00000000}, | ||
| 861 | {0x0000b408, 0x0e79e5c0}, | ||
| 862 | {0x0000b40c, 0x00820820}, | ||
| 863 | {0x0000b420, 0x00000000}, | ||
| 864 | }; | ||
| 865 | |||
| 866 | static const u32 qca953x_2p0_baseband_postamble[][5] = { | ||
| 867 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
| 868 | {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, | ||
| 869 | {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, | ||
| 870 | {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, | ||
| 871 | {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, | ||
| 872 | {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, | ||
| 873 | {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, | ||
| 874 | {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, | ||
| 875 | {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, | ||
| 876 | {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, | ||
| 877 | {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, | ||
| 878 | {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e}, | ||
| 879 | {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, | ||
| 880 | {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
| 881 | {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, | ||
| 882 | {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, | ||
| 883 | {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, | ||
| 884 | {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcf946222, 0xcf946222}, | ||
| 885 | {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, | ||
| 886 | {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, | ||
| 887 | {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, | ||
| 888 | {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0}, | ||
| 889 | {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, | ||
| 890 | {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f}, | ||
| 891 | {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, | ||
| 892 | {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, | ||
| 893 | {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018}, | ||
| 894 | {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, | ||
| 895 | {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, | ||
| 896 | {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, | ||
| 897 | {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e}, | ||
| 898 | {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, | ||
| 899 | {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e}, | ||
| 900 | {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, | ||
| 901 | {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, | ||
| 902 | {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, | ||
| 903 | {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, | ||
| 904 | {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, | ||
| 905 | {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, | ||
| 906 | {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, | ||
| 907 | {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, | ||
| 908 | {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
| 909 | {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, | ||
| 910 | {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, | ||
| 911 | {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
| 912 | {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, | ||
| 913 | {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, | ||
| 914 | {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, | ||
| 915 | }; | ||
| 916 | |||
| 718 | #endif /* INITVALS_953X_H */ | 917 | #endif /* INITVALS_953X_H */ |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 2ca8f7e06174..7fc13a8da675 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
| 23 | #include <linux/leds.h> | 23 | #include <linux/leds.h> |
| 24 | #include <linux/completion.h> | 24 | #include <linux/completion.h> |
| 25 | #include <linux/time.h> | ||
| 25 | 26 | ||
| 26 | #include "common.h" | 27 | #include "common.h" |
| 27 | #include "debug.h" | 28 | #include "debug.h" |
| @@ -35,10 +36,7 @@ extern struct ieee80211_ops ath9k_ops; | |||
| 35 | extern int ath9k_modparam_nohwcrypt; | 36 | extern int ath9k_modparam_nohwcrypt; |
| 36 | extern int led_blink; | 37 | extern int led_blink; |
| 37 | extern bool is_ath9k_unloaded; | 38 | extern bool is_ath9k_unloaded; |
| 38 | 39 | extern int ath9k_use_chanctx; | |
| 39 | struct ath_config { | ||
| 40 | u16 txpowlimit; | ||
| 41 | }; | ||
| 42 | 40 | ||
| 43 | /*************************/ | 41 | /*************************/ |
| 44 | /* Descriptor Management */ | 42 | /* Descriptor Management */ |
| @@ -167,7 +165,6 @@ struct ath_txq { | |||
| 167 | u32 axq_ampdu_depth; | 165 | u32 axq_ampdu_depth; |
| 168 | bool stopped; | 166 | bool stopped; |
| 169 | bool axq_tx_inprogress; | 167 | bool axq_tx_inprogress; |
| 170 | struct list_head axq_acq; | ||
| 171 | struct list_head txq_fifo[ATH_TXFIFO_DEPTH]; | 168 | struct list_head txq_fifo[ATH_TXFIFO_DEPTH]; |
| 172 | u8 txq_headidx; | 169 | u8 txq_headidx; |
| 173 | u8 txq_tailidx; | 170 | u8 txq_tailidx; |
| @@ -185,7 +182,8 @@ struct ath_atx_ac { | |||
| 185 | 182 | ||
| 186 | struct ath_frame_info { | 183 | struct ath_frame_info { |
| 187 | struct ath_buf *bf; | 184 | struct ath_buf *bf; |
| 188 | int framelen; | 185 | u16 framelen; |
| 186 | s8 txq; | ||
| 189 | enum ath9k_key_type keytype; | 187 | enum ath9k_key_type keytype; |
| 190 | u8 keyix; | 188 | u8 keyix; |
| 191 | u8 rtscts_rate; | 189 | u8 rtscts_rate; |
| @@ -280,8 +278,9 @@ struct ath_node { | |||
| 280 | struct ath_tx_control { | 278 | struct ath_tx_control { |
| 281 | struct ath_txq *txq; | 279 | struct ath_txq *txq; |
| 282 | struct ath_node *an; | 280 | struct ath_node *an; |
| 283 | u8 paprd; | ||
| 284 | struct ieee80211_sta *sta; | 281 | struct ieee80211_sta *sta; |
| 282 | u8 paprd; | ||
| 283 | bool force_channel; | ||
| 285 | }; | 284 | }; |
| 286 | 285 | ||
| 287 | 286 | ||
| @@ -325,6 +324,116 @@ struct ath_rx { | |||
| 325 | u32 ampdu_ref; | 324 | u32 ampdu_ref; |
| 326 | }; | 325 | }; |
| 327 | 326 | ||
| 327 | struct ath_chanctx { | ||
| 328 | struct cfg80211_chan_def chandef; | ||
| 329 | struct list_head vifs; | ||
| 330 | struct list_head acq[IEEE80211_NUM_ACS]; | ||
| 331 | int hw_queue_base; | ||
| 332 | |||
| 333 | /* do not dereference, use for comparison only */ | ||
| 334 | struct ieee80211_vif *primary_sta; | ||
| 335 | |||
| 336 | struct ath_beacon_config beacon; | ||
| 337 | struct ath9k_hw_cal_data caldata; | ||
| 338 | struct timespec tsf_ts; | ||
| 339 | u64 tsf_val; | ||
| 340 | u32 last_beacon; | ||
| 341 | |||
| 342 | u16 txpower; | ||
| 343 | bool offchannel; | ||
| 344 | bool stopped; | ||
| 345 | bool active; | ||
| 346 | bool assigned; | ||
| 347 | bool switch_after_beacon; | ||
| 348 | }; | ||
| 349 | |||
| 350 | enum ath_chanctx_event { | ||
| 351 | ATH_CHANCTX_EVENT_BEACON_PREPARE, | ||
| 352 | ATH_CHANCTX_EVENT_BEACON_SENT, | ||
| 353 | ATH_CHANCTX_EVENT_TSF_TIMER, | ||
| 354 | ATH_CHANCTX_EVENT_BEACON_RECEIVED, | ||
| 355 | ATH_CHANCTX_EVENT_ASSOC, | ||
| 356 | ATH_CHANCTX_EVENT_SWITCH, | ||
| 357 | ATH_CHANCTX_EVENT_UNASSIGN, | ||
| 358 | ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL, | ||
| 359 | }; | ||
| 360 | |||
| 361 | enum ath_chanctx_state { | ||
| 362 | ATH_CHANCTX_STATE_IDLE, | ||
| 363 | ATH_CHANCTX_STATE_WAIT_FOR_BEACON, | ||
| 364 | ATH_CHANCTX_STATE_WAIT_FOR_TIMER, | ||
| 365 | ATH_CHANCTX_STATE_SWITCH, | ||
| 366 | ATH_CHANCTX_STATE_FORCE_ACTIVE, | ||
| 367 | }; | ||
| 368 | |||
| 369 | struct ath_chanctx_sched { | ||
| 370 | bool beacon_pending; | ||
| 371 | bool offchannel_pending; | ||
| 372 | enum ath_chanctx_state state; | ||
| 373 | u8 beacon_miss; | ||
| 374 | |||
| 375 | u32 next_tbtt; | ||
| 376 | u32 switch_start_time; | ||
| 377 | unsigned int offchannel_duration; | ||
| 378 | unsigned int channel_switch_time; | ||
| 379 | |||
| 380 | /* backup, in case the hardware timer fails */ | ||
| 381 | struct timer_list timer; | ||
| 382 | }; | ||
| 383 | |||
| 384 | enum ath_offchannel_state { | ||
| 385 | ATH_OFFCHANNEL_IDLE, | ||
| 386 | ATH_OFFCHANNEL_PROBE_SEND, | ||
| 387 | ATH_OFFCHANNEL_PROBE_WAIT, | ||
| 388 | ATH_OFFCHANNEL_SUSPEND, | ||
| 389 | ATH_OFFCHANNEL_ROC_START, | ||
| 390 | ATH_OFFCHANNEL_ROC_WAIT, | ||
| 391 | ATH_OFFCHANNEL_ROC_DONE, | ||
| 392 | }; | ||
| 393 | |||
| 394 | struct ath_offchannel { | ||
| 395 | struct ath_chanctx chan; | ||
| 396 | struct timer_list timer; | ||
| 397 | struct cfg80211_scan_request *scan_req; | ||
| 398 | struct ieee80211_vif *scan_vif; | ||
| 399 | int scan_idx; | ||
| 400 | enum ath_offchannel_state state; | ||
| 401 | struct ieee80211_channel *roc_chan; | ||
| 402 | struct ieee80211_vif *roc_vif; | ||
| 403 | int roc_duration; | ||
| 404 | int duration; | ||
| 405 | }; | ||
| 406 | #define ath_for_each_chanctx(_sc, _ctx) \ | ||
| 407 | for (ctx = &sc->chanctx[0]; \ | ||
| 408 | ctx <= &sc->chanctx[ARRAY_SIZE(sc->chanctx) - 1]; \ | ||
| 409 | ctx++) | ||
| 410 | |||
| 411 | void ath9k_fill_chanctx_ops(void); | ||
| 412 | void ath9k_chanctx_force_active(struct ieee80211_hw *hw, | ||
| 413 | struct ieee80211_vif *vif); | ||
| 414 | static inline struct ath_chanctx * | ||
| 415 | ath_chanctx_get(struct ieee80211_chanctx_conf *ctx) | ||
| 416 | { | ||
| 417 | struct ath_chanctx **ptr = (void *) ctx->drv_priv; | ||
| 418 | return *ptr; | ||
| 419 | } | ||
| 420 | void ath_chanctx_init(struct ath_softc *sc); | ||
| 421 | void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, | ||
| 422 | struct cfg80211_chan_def *chandef); | ||
| 423 | void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, | ||
| 424 | struct cfg80211_chan_def *chandef); | ||
| 425 | void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); | ||
| 426 | void ath_offchannel_timer(unsigned long data); | ||
| 427 | void ath_offchannel_channel_change(struct ath_softc *sc); | ||
| 428 | void ath_chanctx_offchan_switch(struct ath_softc *sc, | ||
| 429 | struct ieee80211_channel *chan); | ||
| 430 | struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, | ||
| 431 | bool active); | ||
| 432 | void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, | ||
| 433 | enum ath_chanctx_event ev); | ||
| 434 | void ath_chanctx_timer(unsigned long data); | ||
| 435 | |||
| 436 | int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); | ||
| 328 | int ath_startrecv(struct ath_softc *sc); | 437 | int ath_startrecv(struct ath_softc *sc); |
| 329 | bool ath_stoprecv(struct ath_softc *sc); | 438 | bool ath_stoprecv(struct ath_softc *sc); |
| 330 | u32 ath_calcrxfilter(struct ath_softc *sc); | 439 | u32 ath_calcrxfilter(struct ath_softc *sc); |
| @@ -341,6 +450,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq); | |||
| 341 | void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); | 450 | void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); |
| 342 | void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); | 451 | void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); |
| 343 | void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); | 452 | void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); |
| 453 | void ath_txq_schedule_all(struct ath_softc *sc); | ||
| 344 | int ath_tx_init(struct ath_softc *sc, int nbufs); | 454 | int ath_tx_init(struct ath_softc *sc, int nbufs); |
| 345 | int ath_txq_update(struct ath_softc *sc, int qnum, | 455 | int ath_txq_update(struct ath_softc *sc, int qnum, |
| 346 | struct ath9k_tx_queue_info *q); | 456 | struct ath9k_tx_queue_info *q); |
| @@ -370,32 +480,47 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, | |||
| 370 | /********/ | 480 | /********/ |
| 371 | 481 | ||
| 372 | struct ath_vif { | 482 | struct ath_vif { |
| 483 | struct list_head list; | ||
| 484 | |||
| 373 | struct ieee80211_vif *vif; | 485 | struct ieee80211_vif *vif; |
| 374 | struct ath_node mcast_node; | 486 | struct ath_node mcast_node; |
| 375 | int av_bslot; | 487 | int av_bslot; |
| 376 | bool primary_sta_vif; | ||
| 377 | __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ | 488 | __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ |
| 378 | struct ath_buf *av_bcbuf; | 489 | struct ath_buf *av_bcbuf; |
| 490 | struct ath_chanctx *chanctx; | ||
| 379 | 491 | ||
| 380 | /* P2P Client */ | 492 | /* P2P Client */ |
| 381 | struct ieee80211_noa_data noa; | 493 | struct ieee80211_noa_data noa; |
| 494 | |||
| 495 | /* P2P GO */ | ||
| 496 | u8 noa_index; | ||
| 497 | u32 offchannel_start; | ||
| 498 | u32 offchannel_duration; | ||
| 499 | |||
| 500 | u32 periodic_noa_start; | ||
| 501 | u32 periodic_noa_duration; | ||
| 382 | }; | 502 | }; |
| 383 | 503 | ||
| 384 | struct ath9k_vif_iter_data { | 504 | struct ath9k_vif_iter_data { |
| 385 | u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */ | 505 | u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */ |
| 386 | u8 mask[ETH_ALEN]; /* bssid mask */ | 506 | u8 mask[ETH_ALEN]; /* bssid mask */ |
| 387 | bool has_hw_macaddr; | 507 | bool has_hw_macaddr; |
| 508 | u8 slottime; | ||
| 509 | bool beacons; | ||
| 388 | 510 | ||
| 389 | int naps; /* number of AP vifs */ | 511 | int naps; /* number of AP vifs */ |
| 390 | int nmeshes; /* number of mesh vifs */ | 512 | int nmeshes; /* number of mesh vifs */ |
| 391 | int nstations; /* number of station vifs */ | 513 | int nstations; /* number of station vifs */ |
| 392 | int nwds; /* number of WDS vifs */ | 514 | int nwds; /* number of WDS vifs */ |
| 393 | int nadhocs; /* number of adhoc vifs */ | 515 | int nadhocs; /* number of adhoc vifs */ |
| 516 | struct ieee80211_vif *primary_sta; | ||
| 394 | }; | 517 | }; |
| 395 | 518 | ||
| 396 | void ath9k_calculate_iter_data(struct ieee80211_hw *hw, | 519 | void ath9k_calculate_iter_data(struct ath_softc *sc, |
| 397 | struct ieee80211_vif *vif, | 520 | struct ath_chanctx *ctx, |
| 398 | struct ath9k_vif_iter_data *iter_data); | 521 | struct ath9k_vif_iter_data *iter_data); |
| 522 | void ath9k_calculate_summary_state(struct ath_softc *sc, | ||
| 523 | struct ath_chanctx *ctx); | ||
| 399 | 524 | ||
| 400 | /*******************/ | 525 | /*******************/ |
| 401 | /* Beacon Handling */ | 526 | /* Beacon Handling */ |
| @@ -458,6 +583,7 @@ void ath9k_csa_update(struct ath_softc *sc); | |||
| 458 | #define ATH_PAPRD_TIMEOUT 100 /* msecs */ | 583 | #define ATH_PAPRD_TIMEOUT 100 /* msecs */ |
| 459 | #define ATH_PLL_WORK_INTERVAL 100 | 584 | #define ATH_PLL_WORK_INTERVAL 100 |
| 460 | 585 | ||
| 586 | void ath_chanctx_work(struct work_struct *work); | ||
| 461 | void ath_tx_complete_poll_work(struct work_struct *work); | 587 | void ath_tx_complete_poll_work(struct work_struct *work); |
| 462 | void ath_reset_work(struct work_struct *work); | 588 | void ath_reset_work(struct work_struct *work); |
| 463 | bool ath_hw_check(struct ath_softc *sc); | 589 | bool ath_hw_check(struct ath_softc *sc); |
| @@ -473,6 +599,7 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); | |||
| 473 | void ath_ps_full_sleep(unsigned long data); | 599 | void ath_ps_full_sleep(unsigned long data); |
| 474 | void ath9k_p2p_ps_timer(void *priv); | 600 | void ath9k_p2p_ps_timer(void *priv); |
| 475 | void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif); | 601 | void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif); |
| 602 | void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop); | ||
| 476 | 603 | ||
| 477 | /**********/ | 604 | /**********/ |
| 478 | /* BTCOEX */ | 605 | /* BTCOEX */ |
| @@ -702,6 +829,8 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); | |||
| 702 | #define PS_BEACON_SYNC BIT(4) | 829 | #define PS_BEACON_SYNC BIT(4) |
| 703 | #define PS_WAIT_FOR_ANI BIT(5) | 830 | #define PS_WAIT_FOR_ANI BIT(5) |
| 704 | 831 | ||
| 832 | #define ATH9K_NUM_CHANCTX 2 /* supports 2 operating channels */ | ||
| 833 | |||
| 705 | struct ath_softc { | 834 | struct ath_softc { |
| 706 | struct ieee80211_hw *hw; | 835 | struct ieee80211_hw *hw; |
| 707 | struct device *dev; | 836 | struct device *dev; |
| @@ -720,6 +849,7 @@ struct ath_softc { | |||
| 720 | struct mutex mutex; | 849 | struct mutex mutex; |
| 721 | struct work_struct paprd_work; | 850 | struct work_struct paprd_work; |
| 722 | struct work_struct hw_reset_work; | 851 | struct work_struct hw_reset_work; |
| 852 | struct work_struct chanctx_work; | ||
| 723 | struct completion paprd_complete; | 853 | struct completion paprd_complete; |
| 724 | wait_queue_head_t tx_wait; | 854 | wait_queue_head_t tx_wait; |
| 725 | 855 | ||
| @@ -738,23 +868,27 @@ struct ath_softc { | |||
| 738 | short nvifs; | 868 | short nvifs; |
| 739 | unsigned long ps_usecount; | 869 | unsigned long ps_usecount; |
| 740 | 870 | ||
| 741 | struct ath_config config; | ||
| 742 | struct ath_rx rx; | 871 | struct ath_rx rx; |
| 743 | struct ath_tx tx; | 872 | struct ath_tx tx; |
| 744 | struct ath_beacon beacon; | 873 | struct ath_beacon beacon; |
| 745 | 874 | ||
| 875 | struct cfg80211_chan_def cur_chandef; | ||
| 876 | struct ath_chanctx chanctx[ATH9K_NUM_CHANCTX]; | ||
| 877 | struct ath_chanctx *cur_chan; | ||
| 878 | struct ath_chanctx *next_chan; | ||
| 879 | spinlock_t chan_lock; | ||
| 880 | struct ath_offchannel offchannel; | ||
| 881 | struct ath_chanctx_sched sched; | ||
| 882 | |||
| 746 | #ifdef CONFIG_MAC80211_LEDS | 883 | #ifdef CONFIG_MAC80211_LEDS |
| 747 | bool led_registered; | 884 | bool led_registered; |
| 748 | char led_name[32]; | 885 | char led_name[32]; |
| 749 | struct led_classdev led_cdev; | 886 | struct led_classdev led_cdev; |
| 750 | #endif | 887 | #endif |
| 751 | 888 | ||
| 752 | struct ath9k_hw_cal_data caldata; | ||
| 753 | |||
| 754 | #ifdef CONFIG_ATH9K_DEBUGFS | 889 | #ifdef CONFIG_ATH9K_DEBUGFS |
| 755 | struct ath9k_debug debug; | 890 | struct ath9k_debug debug; |
| 756 | #endif | 891 | #endif |
| 757 | struct ath_beacon_config cur_beacon_conf; | ||
| 758 | struct delayed_work tx_complete_work; | 892 | struct delayed_work tx_complete_work; |
| 759 | struct delayed_work hw_pll_work; | 893 | struct delayed_work hw_pll_work; |
| 760 | struct timer_list sleep_timer; | 894 | struct timer_list sleep_timer; |
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index e387f0b2954a..eaf8f058c151 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
| @@ -80,7 +80,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
| 80 | u8 chainmask = ah->txchainmask; | 80 | u8 chainmask = ah->txchainmask; |
| 81 | u8 rate = 0; | 81 | u8 rate = 0; |
| 82 | 82 | ||
| 83 | sband = &common->sbands[common->hw->conf.chandef.chan->band]; | 83 | sband = &common->sbands[sc->cur_chandef.chan->band]; |
| 84 | rate = sband->bitrates[rateidx].hw_value; | 84 | rate = sband->bitrates[rateidx].hw_value; |
| 85 | if (vif->bss_conf.use_short_preamble) | 85 | if (vif->bss_conf.use_short_preamble) |
| 86 | rate |= sband->bitrates[rateidx].hw_value_short; | 86 | rate |= sband->bitrates[rateidx].hw_value_short; |
| @@ -108,6 +108,55 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
| 108 | ath9k_hw_set_txdesc(ah, bf->bf_desc, &info); | 108 | ath9k_hw_set_txdesc(ah, bf->bf_desc, &info); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | static void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, | ||
| 112 | struct sk_buff *skb) | ||
| 113 | { | ||
| 114 | static const u8 noa_ie_hdr[] = { | ||
| 115 | WLAN_EID_VENDOR_SPECIFIC, /* type */ | ||
| 116 | 0, /* length */ | ||
| 117 | 0x50, 0x6f, 0x9a, /* WFA OUI */ | ||
| 118 | 0x09, /* P2P subtype */ | ||
| 119 | 0x0c, /* Notice of Absence */ | ||
| 120 | 0x00, /* LSB of little-endian len */ | ||
| 121 | 0x00, /* MSB of little-endian len */ | ||
| 122 | }; | ||
| 123 | |||
| 124 | struct ieee80211_p2p_noa_attr *noa; | ||
| 125 | int noa_len, noa_desc, i = 0; | ||
| 126 | u8 *hdr; | ||
| 127 | |||
| 128 | if (!avp->offchannel_duration && !avp->periodic_noa_duration) | ||
| 129 | return; | ||
| 130 | |||
| 131 | noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration; | ||
| 132 | noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc; | ||
| 133 | |||
| 134 | hdr = skb_put(skb, sizeof(noa_ie_hdr)); | ||
| 135 | memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr)); | ||
| 136 | hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2; | ||
| 137 | hdr[7] = noa_len; | ||
| 138 | |||
| 139 | noa = (void *) skb_put(skb, noa_len); | ||
| 140 | memset(noa, 0, noa_len); | ||
| 141 | |||
| 142 | noa->index = avp->noa_index; | ||
| 143 | if (avp->periodic_noa_duration) { | ||
| 144 | u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); | ||
| 145 | |||
| 146 | noa->desc[i].count = 255; | ||
| 147 | noa->desc[i].start_time = cpu_to_le32(avp->periodic_noa_start); | ||
| 148 | noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration); | ||
| 149 | noa->desc[i].interval = cpu_to_le32(interval); | ||
| 150 | i++; | ||
| 151 | } | ||
| 152 | |||
| 153 | if (avp->offchannel_duration) { | ||
| 154 | noa->desc[i].count = 1; | ||
| 155 | noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start); | ||
| 156 | noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration); | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 111 | static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, | 160 | static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, |
| 112 | struct ieee80211_vif *vif) | 161 | struct ieee80211_vif *vif) |
| 113 | { | 162 | { |
| @@ -155,6 +204,9 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, | |||
| 155 | hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); | 204 | hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); |
| 156 | } | 205 | } |
| 157 | 206 | ||
| 207 | if (vif->p2p) | ||
| 208 | ath9k_beacon_add_noa(sc, avp, skb); | ||
| 209 | |||
| 158 | bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, | 210 | bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, |
| 159 | skb->len, DMA_TO_DEVICE); | 211 | skb->len, DMA_TO_DEVICE); |
| 160 | if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { | 212 | if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { |
| @@ -249,7 +301,7 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif) | |||
| 249 | static int ath9k_beacon_choose_slot(struct ath_softc *sc) | 301 | static int ath9k_beacon_choose_slot(struct ath_softc *sc) |
| 250 | { | 302 | { |
| 251 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 303 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 252 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | 304 | struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; |
| 253 | u16 intval; | 305 | u16 intval; |
| 254 | u32 tsftu; | 306 | u32 tsftu; |
| 255 | u64 tsf; | 307 | u64 tsf; |
| @@ -277,8 +329,8 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc) | |||
| 277 | static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif) | 329 | static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif) |
| 278 | { | 330 | { |
| 279 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 331 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 280 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | ||
| 281 | struct ath_vif *avp = (void *)vif->drv_priv; | 332 | struct ath_vif *avp = (void *)vif->drv_priv; |
| 333 | struct ath_beacon_config *cur_conf = &avp->chanctx->beacon; | ||
| 282 | u32 tsfadjust; | 334 | u32 tsfadjust; |
| 283 | 335 | ||
| 284 | if (avp->av_bslot == 0) | 336 | if (avp->av_bslot == 0) |
| @@ -374,12 +426,19 @@ void ath9k_beacon_tasklet(unsigned long data) | |||
| 374 | vif = sc->beacon.bslot[slot]; | 426 | vif = sc->beacon.bslot[slot]; |
| 375 | 427 | ||
| 376 | /* EDMA devices check that in the tx completion function. */ | 428 | /* EDMA devices check that in the tx completion function. */ |
| 377 | if (!edma && ath9k_csa_is_finished(sc, vif)) | 429 | if (!edma) { |
| 378 | return; | 430 | if (sc->sched.beacon_pending) |
| 431 | ath_chanctx_event(sc, NULL, | ||
| 432 | ATH_CHANCTX_EVENT_BEACON_SENT); | ||
| 433 | |||
| 434 | if (ath9k_csa_is_finished(sc, vif)) | ||
| 435 | return; | ||
| 436 | } | ||
| 379 | 437 | ||
| 380 | if (!vif || !vif->bss_conf.enable_beacon) | 438 | if (!vif || !vif->bss_conf.enable_beacon) |
| 381 | return; | 439 | return; |
| 382 | 440 | ||
| 441 | ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE); | ||
| 383 | bf = ath9k_beacon_generate(sc->hw, vif); | 442 | bf = ath9k_beacon_generate(sc->hw, vif); |
| 384 | 443 | ||
| 385 | if (sc->beacon.bmisscnt != 0) { | 444 | if (sc->beacon.bmisscnt != 0) { |
| @@ -500,7 +559,6 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, | |||
| 500 | struct ieee80211_vif *vif) | 559 | struct ieee80211_vif *vif) |
| 501 | { | 560 | { |
| 502 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 561 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 503 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
| 504 | 562 | ||
| 505 | if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { | 563 | if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { |
| 506 | if ((vif->type != NL80211_IFTYPE_AP) || | 564 | if ((vif->type != NL80211_IFTYPE_AP) || |
| @@ -514,7 +572,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, | |||
| 514 | if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { | 572 | if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { |
| 515 | if ((vif->type == NL80211_IFTYPE_STATION) && | 573 | if ((vif->type == NL80211_IFTYPE_STATION) && |
| 516 | test_bit(ATH_OP_BEACONS, &common->op_flags) && | 574 | test_bit(ATH_OP_BEACONS, &common->op_flags) && |
| 517 | !avp->primary_sta_vif) { | 575 | vif != sc->cur_chan->primary_sta) { |
| 518 | ath_dbg(common, CONFIG, | 576 | ath_dbg(common, CONFIG, |
| 519 | "Beacon already configured for a station interface\n"); | 577 | "Beacon already configured for a station interface\n"); |
| 520 | return false; | 578 | return false; |
| @@ -525,10 +583,11 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, | |||
| 525 | } | 583 | } |
| 526 | 584 | ||
| 527 | static void ath9k_cache_beacon_config(struct ath_softc *sc, | 585 | static void ath9k_cache_beacon_config(struct ath_softc *sc, |
| 586 | struct ath_chanctx *ctx, | ||
| 528 | struct ieee80211_bss_conf *bss_conf) | 587 | struct ieee80211_bss_conf *bss_conf) |
| 529 | { | 588 | { |
| 530 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 589 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 531 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | 590 | struct ath_beacon_config *cur_conf = &ctx->beacon; |
| 532 | 591 | ||
| 533 | ath_dbg(common, BEACON, | 592 | ath_dbg(common, BEACON, |
| 534 | "Caching beacon data for BSS: %pM\n", bss_conf->bssid); | 593 | "Caching beacon data for BSS: %pM\n", bss_conf->bssid); |
| @@ -564,20 +623,29 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
| 564 | u32 changed) | 623 | u32 changed) |
| 565 | { | 624 | { |
| 566 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | 625 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
| 567 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | ||
| 568 | struct ath_hw *ah = sc->sc_ah; | 626 | struct ath_hw *ah = sc->sc_ah; |
| 569 | struct ath_common *common = ath9k_hw_common(ah); | 627 | struct ath_common *common = ath9k_hw_common(ah); |
| 628 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
| 629 | struct ath_chanctx *ctx = avp->chanctx; | ||
| 630 | struct ath_beacon_config *cur_conf; | ||
| 570 | unsigned long flags; | 631 | unsigned long flags; |
| 571 | bool skip_beacon = false; | 632 | bool skip_beacon = false; |
| 572 | 633 | ||
| 634 | if (!ctx) | ||
| 635 | return; | ||
| 636 | |||
| 637 | cur_conf = &avp->chanctx->beacon; | ||
| 573 | if (vif->type == NL80211_IFTYPE_AP) | 638 | if (vif->type == NL80211_IFTYPE_AP) |
| 574 | ath9k_set_tsfadjust(sc, vif); | 639 | ath9k_set_tsfadjust(sc, vif); |
| 575 | 640 | ||
| 576 | if (!ath9k_allow_beacon_config(sc, vif)) | 641 | if (!ath9k_allow_beacon_config(sc, vif)) |
| 577 | return; | 642 | return; |
| 578 | 643 | ||
| 579 | if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { | 644 | if (vif->type == NL80211_IFTYPE_STATION) { |
| 580 | ath9k_cache_beacon_config(sc, bss_conf); | 645 | ath9k_cache_beacon_config(sc, ctx, bss_conf); |
| 646 | if (ctx != sc->cur_chan) | ||
| 647 | return; | ||
| 648 | |||
| 581 | ath9k_set_beacon(sc); | 649 | ath9k_set_beacon(sc); |
| 582 | set_bit(ATH_OP_BEACONS, &common->op_flags); | 650 | set_bit(ATH_OP_BEACONS, &common->op_flags); |
| 583 | return; | 651 | return; |
| @@ -593,10 +661,13 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
| 593 | cur_conf->enable_beacon = false; | 661 | cur_conf->enable_beacon = false; |
| 594 | } else if (bss_conf->enable_beacon) { | 662 | } else if (bss_conf->enable_beacon) { |
| 595 | cur_conf->enable_beacon = true; | 663 | cur_conf->enable_beacon = true; |
| 596 | ath9k_cache_beacon_config(sc, bss_conf); | 664 | ath9k_cache_beacon_config(sc, ctx, bss_conf); |
| 597 | } | 665 | } |
| 598 | } | 666 | } |
| 599 | 667 | ||
| 668 | if (ctx != sc->cur_chan) | ||
| 669 | return; | ||
| 670 | |||
| 600 | /* | 671 | /* |
| 601 | * Configure the HW beacon registers only when we have a valid | 672 | * Configure the HW beacon registers only when we have a valid |
| 602 | * beacon interval. | 673 | * beacon interval. |
| @@ -631,7 +702,7 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
| 631 | void ath9k_set_beacon(struct ath_softc *sc) | 702 | void ath9k_set_beacon(struct ath_softc *sc) |
| 632 | { | 703 | { |
| 633 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 704 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 634 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | 705 | struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; |
| 635 | 706 | ||
| 636 | switch (sc->sc_ah->opmode) { | 707 | switch (sc->sc_ah->opmode) { |
| 637 | case NL80211_IFTYPE_AP: | 708 | case NL80211_IFTYPE_AP: |
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c new file mode 100644 index 000000000000..ba214ebdcd16 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/channel.c | |||
| @@ -0,0 +1,685 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Qualcomm Atheros, Inc. | ||
| 3 | * | ||
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
| 5 | * purpose with or without fee is hereby granted, provided that the above | ||
| 6 | * copyright notice and this permission notice appear in all copies. | ||
| 7 | * | ||
| 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "ath9k.h" | ||
| 18 | |||
| 19 | /* Set/change channels. If the channel is really being changed, it's done | ||
| 20 | * by reseting the chip. To accomplish this we must first cleanup any pending | ||
| 21 | * DMA, then restart stuff. | ||
| 22 | */ | ||
| 23 | static int ath_set_channel(struct ath_softc *sc) | ||
| 24 | { | ||
| 25 | struct ath_hw *ah = sc->sc_ah; | ||
| 26 | struct ath_common *common = ath9k_hw_common(ah); | ||
| 27 | struct ieee80211_hw *hw = sc->hw; | ||
| 28 | struct ath9k_channel *hchan; | ||
| 29 | struct cfg80211_chan_def *chandef = &sc->cur_chan->chandef; | ||
| 30 | struct ieee80211_channel *chan = chandef->chan; | ||
| 31 | int pos = chan->hw_value; | ||
| 32 | int old_pos = -1; | ||
| 33 | int r; | ||
| 34 | |||
| 35 | if (test_bit(ATH_OP_INVALID, &common->op_flags)) | ||
| 36 | return -EIO; | ||
| 37 | |||
| 38 | if (ah->curchan) | ||
| 39 | old_pos = ah->curchan - &ah->channels[0]; | ||
| 40 | |||
| 41 | ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", | ||
| 42 | chan->center_freq, chandef->width); | ||
| 43 | |||
| 44 | /* update survey stats for the old channel before switching */ | ||
| 45 | spin_lock_bh(&common->cc_lock); | ||
| 46 | ath_update_survey_stats(sc); | ||
| 47 | spin_unlock_bh(&common->cc_lock); | ||
| 48 | |||
| 49 | ath9k_cmn_get_channel(hw, ah, chandef); | ||
| 50 | |||
| 51 | /* If the operating channel changes, change the survey in-use flags | ||
| 52 | * along with it. | ||
| 53 | * Reset the survey data for the new channel, unless we're switching | ||
| 54 | * back to the operating channel from an off-channel operation. | ||
| 55 | */ | ||
| 56 | if (!sc->cur_chan->offchannel && sc->cur_survey != &sc->survey[pos]) { | ||
| 57 | if (sc->cur_survey) | ||
| 58 | sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; | ||
| 59 | |||
| 60 | sc->cur_survey = &sc->survey[pos]; | ||
| 61 | |||
| 62 | memset(sc->cur_survey, 0, sizeof(struct survey_info)); | ||
| 63 | sc->cur_survey->filled |= SURVEY_INFO_IN_USE; | ||
| 64 | } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { | ||
| 65 | memset(&sc->survey[pos], 0, sizeof(struct survey_info)); | ||
| 66 | } | ||
| 67 | |||
| 68 | hchan = &sc->sc_ah->channels[pos]; | ||
| 69 | r = ath_reset_internal(sc, hchan); | ||
| 70 | if (r) | ||
| 71 | return r; | ||
| 72 | |||
| 73 | /* The most recent snapshot of channel->noisefloor for the old | ||
| 74 | * channel is only available after the hardware reset. Copy it to | ||
| 75 | * the survey stats now. | ||
| 76 | */ | ||
| 77 | if (old_pos >= 0) | ||
| 78 | ath_update_survey_nf(sc, old_pos); | ||
| 79 | |||
| 80 | /* Enable radar pulse detection if on a DFS channel. Spectral | ||
| 81 | * scanning and radar detection can not be used concurrently. | ||
| 82 | */ | ||
| 83 | if (hw->conf.radar_enabled) { | ||
| 84 | u32 rxfilter; | ||
| 85 | |||
| 86 | /* set HW specific DFS configuration */ | ||
| 87 | ath9k_hw_set_radar_params(ah); | ||
| 88 | rxfilter = ath9k_hw_getrxfilter(ah); | ||
| 89 | rxfilter |= ATH9K_RX_FILTER_PHYRADAR | | ||
| 90 | ATH9K_RX_FILTER_PHYERR; | ||
| 91 | ath9k_hw_setrxfilter(ah, rxfilter); | ||
| 92 | ath_dbg(common, DFS, "DFS enabled at freq %d\n", | ||
| 93 | chan->center_freq); | ||
| 94 | } else { | ||
| 95 | /* perform spectral scan if requested. */ | ||
| 96 | if (test_bit(ATH_OP_SCANNING, &common->op_flags) && | ||
| 97 | sc->spectral_mode == SPECTRAL_CHANSCAN) | ||
| 98 | ath9k_spectral_scan_trigger(hw); | ||
| 99 | } | ||
| 100 | |||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | |||
| 104 | static bool | ||
| 105 | ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp, | ||
| 106 | bool powersave) | ||
| 107 | { | ||
| 108 | struct ieee80211_vif *vif = avp->vif; | ||
| 109 | struct ieee80211_sta *sta = NULL; | ||
| 110 | struct ieee80211_hdr_3addr *nullfunc; | ||
| 111 | struct ath_tx_control txctl; | ||
| 112 | struct sk_buff *skb; | ||
| 113 | int band = sc->cur_chan->chandef.chan->band; | ||
| 114 | |||
| 115 | switch (vif->type) { | ||
| 116 | case NL80211_IFTYPE_STATION: | ||
| 117 | if (!vif->bss_conf.assoc) | ||
| 118 | return false; | ||
| 119 | |||
| 120 | skb = ieee80211_nullfunc_get(sc->hw, vif); | ||
| 121 | if (!skb) | ||
| 122 | return false; | ||
| 123 | |||
| 124 | nullfunc = (struct ieee80211_hdr_3addr *) skb->data; | ||
| 125 | if (powersave) | ||
| 126 | nullfunc->frame_control |= | ||
| 127 | cpu_to_le16(IEEE80211_FCTL_PM); | ||
| 128 | |||
| 129 | skb_set_queue_mapping(skb, IEEE80211_AC_VO); | ||
| 130 | if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) { | ||
| 131 | dev_kfree_skb_any(skb); | ||
| 132 | return false; | ||
| 133 | } | ||
| 134 | break; | ||
| 135 | default: | ||
| 136 | return false; | ||
| 137 | } | ||
| 138 | |||
| 139 | memset(&txctl, 0, sizeof(txctl)); | ||
| 140 | txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; | ||
| 141 | txctl.sta = sta; | ||
| 142 | txctl.force_channel = true; | ||
| 143 | if (ath_tx_start(sc->hw, skb, &txctl)) { | ||
| 144 | ieee80211_free_txskb(sc->hw, skb); | ||
| 145 | return false; | ||
| 146 | } | ||
| 147 | |||
| 148 | return true; | ||
| 149 | } | ||
| 150 | |||
| 151 | void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) | ||
| 152 | { | ||
| 153 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
| 154 | struct ath_vif *avp; | ||
| 155 | bool active = false; | ||
| 156 | u8 n_active = 0; | ||
| 157 | |||
| 158 | if (!ctx) | ||
| 159 | return; | ||
| 160 | |||
| 161 | list_for_each_entry(avp, &ctx->vifs, list) { | ||
| 162 | struct ieee80211_vif *vif = avp->vif; | ||
| 163 | |||
| 164 | switch (vif->type) { | ||
| 165 | case NL80211_IFTYPE_P2P_CLIENT: | ||
| 166 | case NL80211_IFTYPE_STATION: | ||
| 167 | if (vif->bss_conf.assoc) | ||
| 168 | active = true; | ||
| 169 | break; | ||
| 170 | default: | ||
| 171 | active = true; | ||
| 172 | break; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | ctx->active = active; | ||
| 176 | |||
| 177 | ath_for_each_chanctx(sc, ctx) { | ||
| 178 | if (!ctx->assigned || list_empty(&ctx->vifs)) | ||
| 179 | continue; | ||
| 180 | n_active++; | ||
| 181 | } | ||
| 182 | |||
| 183 | if (n_active <= 1) { | ||
| 184 | clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags); | ||
| 185 | return; | ||
| 186 | } | ||
| 187 | if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) | ||
| 188 | return; | ||
| 189 | ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL); | ||
| 190 | } | ||
| 191 | |||
| 192 | static bool | ||
| 193 | ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave) | ||
| 194 | { | ||
| 195 | struct ath_vif *avp; | ||
| 196 | bool sent = false; | ||
| 197 | |||
| 198 | rcu_read_lock(); | ||
| 199 | list_for_each_entry(avp, &sc->cur_chan->vifs, list) { | ||
| 200 | if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave)) | ||
| 201 | sent = true; | ||
| 202 | } | ||
| 203 | rcu_read_unlock(); | ||
| 204 | |||
| 205 | return sent; | ||
| 206 | } | ||
| 207 | |||
| 208 | static bool ath_chanctx_defer_switch(struct ath_softc *sc) | ||
| 209 | { | ||
| 210 | if (sc->cur_chan == &sc->offchannel.chan) | ||
| 211 | return false; | ||
| 212 | |||
| 213 | switch (sc->sched.state) { | ||
| 214 | case ATH_CHANCTX_STATE_SWITCH: | ||
| 215 | return false; | ||
| 216 | case ATH_CHANCTX_STATE_IDLE: | ||
| 217 | if (!sc->cur_chan->switch_after_beacon) | ||
| 218 | return false; | ||
| 219 | |||
| 220 | sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; | ||
| 221 | break; | ||
| 222 | default: | ||
| 223 | break; | ||
| 224 | } | ||
| 225 | |||
| 226 | return true; | ||
| 227 | } | ||
| 228 | |||
| 229 | static void ath_chanctx_set_next(struct ath_softc *sc, bool force) | ||
| 230 | { | ||
| 231 | struct timespec ts; | ||
| 232 | bool measure_time = false; | ||
| 233 | bool send_ps = false; | ||
| 234 | |||
| 235 | spin_lock_bh(&sc->chan_lock); | ||
| 236 | if (!sc->next_chan) { | ||
| 237 | spin_unlock_bh(&sc->chan_lock); | ||
| 238 | return; | ||
| 239 | } | ||
| 240 | |||
| 241 | if (!force && ath_chanctx_defer_switch(sc)) { | ||
| 242 | spin_unlock_bh(&sc->chan_lock); | ||
| 243 | return; | ||
| 244 | } | ||
| 245 | |||
| 246 | if (sc->cur_chan != sc->next_chan) { | ||
| 247 | sc->cur_chan->stopped = true; | ||
| 248 | spin_unlock_bh(&sc->chan_lock); | ||
| 249 | |||
| 250 | if (sc->next_chan == &sc->offchannel.chan) { | ||
| 251 | getrawmonotonic(&ts); | ||
| 252 | measure_time = true; | ||
| 253 | } | ||
| 254 | __ath9k_flush(sc->hw, ~0, true); | ||
| 255 | |||
| 256 | if (ath_chanctx_send_ps_frame(sc, true)) | ||
| 257 | __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false); | ||
| 258 | |||
| 259 | send_ps = true; | ||
| 260 | spin_lock_bh(&sc->chan_lock); | ||
| 261 | |||
| 262 | if (sc->cur_chan != &sc->offchannel.chan) { | ||
| 263 | getrawmonotonic(&sc->cur_chan->tsf_ts); | ||
| 264 | sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | sc->cur_chan = sc->next_chan; | ||
| 268 | sc->cur_chan->stopped = false; | ||
| 269 | sc->next_chan = NULL; | ||
| 270 | sc->sched.offchannel_duration = 0; | ||
| 271 | if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE) | ||
| 272 | sc->sched.state = ATH_CHANCTX_STATE_IDLE; | ||
| 273 | |||
| 274 | spin_unlock_bh(&sc->chan_lock); | ||
| 275 | |||
| 276 | if (sc->sc_ah->chip_fullsleep || | ||
| 277 | memcmp(&sc->cur_chandef, &sc->cur_chan->chandef, | ||
| 278 | sizeof(sc->cur_chandef))) { | ||
| 279 | ath_set_channel(sc); | ||
| 280 | if (measure_time) | ||
| 281 | sc->sched.channel_switch_time = | ||
| 282 | ath9k_hw_get_tsf_offset(&ts, NULL); | ||
| 283 | } | ||
| 284 | if (send_ps) | ||
| 285 | ath_chanctx_send_ps_frame(sc, false); | ||
| 286 | |||
| 287 | ath_offchannel_channel_change(sc); | ||
| 288 | ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH); | ||
| 289 | } | ||
| 290 | |||
| 291 | void ath_chanctx_work(struct work_struct *work) | ||
| 292 | { | ||
| 293 | struct ath_softc *sc = container_of(work, struct ath_softc, | ||
| 294 | chanctx_work); | ||
| 295 | mutex_lock(&sc->mutex); | ||
| 296 | ath_chanctx_set_next(sc, false); | ||
| 297 | mutex_unlock(&sc->mutex); | ||
| 298 | } | ||
| 299 | |||
| 300 | void ath_chanctx_init(struct ath_softc *sc) | ||
| 301 | { | ||
| 302 | struct ath_chanctx *ctx; | ||
| 303 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
| 304 | struct ieee80211_supported_band *sband; | ||
| 305 | struct ieee80211_channel *chan; | ||
| 306 | int i, j; | ||
| 307 | |||
| 308 | sband = &common->sbands[IEEE80211_BAND_2GHZ]; | ||
| 309 | if (!sband->n_channels) | ||
| 310 | sband = &common->sbands[IEEE80211_BAND_5GHZ]; | ||
| 311 | |||
| 312 | chan = &sband->channels[0]; | ||
| 313 | for (i = 0; i < ATH9K_NUM_CHANCTX; i++) { | ||
| 314 | ctx = &sc->chanctx[i]; | ||
| 315 | cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20); | ||
| 316 | INIT_LIST_HEAD(&ctx->vifs); | ||
| 317 | ctx->txpower = ATH_TXPOWER_MAX; | ||
| 318 | for (j = 0; j < ARRAY_SIZE(ctx->acq); j++) | ||
| 319 | INIT_LIST_HEAD(&ctx->acq[j]); | ||
| 320 | } | ||
| 321 | ctx = &sc->offchannel.chan; | ||
| 322 | cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20); | ||
| 323 | INIT_LIST_HEAD(&ctx->vifs); | ||
| 324 | ctx->txpower = ATH_TXPOWER_MAX; | ||
| 325 | for (j = 0; j < ARRAY_SIZE(ctx->acq); j++) | ||
| 326 | INIT_LIST_HEAD(&ctx->acq[j]); | ||
| 327 | sc->offchannel.chan.offchannel = true; | ||
| 328 | |||
| 329 | } | ||
| 330 | |||
| 331 | void ath9k_chanctx_force_active(struct ieee80211_hw *hw, | ||
| 332 | struct ieee80211_vif *vif) | ||
| 333 | { | ||
| 334 | struct ath_softc *sc = hw->priv; | ||
| 335 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
| 336 | struct ath_vif *avp = (struct ath_vif *) vif->drv_priv; | ||
| 337 | bool changed = false; | ||
| 338 | |||
| 339 | if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) | ||
| 340 | return; | ||
| 341 | |||
| 342 | if (!avp->chanctx) | ||
| 343 | return; | ||
| 344 | |||
| 345 | mutex_lock(&sc->mutex); | ||
| 346 | |||
| 347 | spin_lock_bh(&sc->chan_lock); | ||
| 348 | if (sc->next_chan || (sc->cur_chan != avp->chanctx)) { | ||
| 349 | sc->next_chan = avp->chanctx; | ||
| 350 | changed = true; | ||
| 351 | } | ||
| 352 | sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE; | ||
| 353 | spin_unlock_bh(&sc->chan_lock); | ||
| 354 | |||
| 355 | if (changed) | ||
| 356 | ath_chanctx_set_next(sc, true); | ||
| 357 | |||
| 358 | mutex_unlock(&sc->mutex); | ||
| 359 | } | ||
| 360 | |||
| 361 | void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, | ||
| 362 | struct cfg80211_chan_def *chandef) | ||
| 363 | { | ||
| 364 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
| 365 | |||
| 366 | spin_lock_bh(&sc->chan_lock); | ||
| 367 | |||
| 368 | if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) && | ||
| 369 | (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) { | ||
| 370 | sc->sched.offchannel_pending = true; | ||
| 371 | spin_unlock_bh(&sc->chan_lock); | ||
| 372 | return; | ||
| 373 | } | ||
| 374 | |||
| 375 | sc->next_chan = ctx; | ||
| 376 | if (chandef) | ||
| 377 | ctx->chandef = *chandef; | ||
| 378 | |||
| 379 | if (sc->next_chan == &sc->offchannel.chan) { | ||
| 380 | sc->sched.offchannel_duration = | ||
| 381 | TU_TO_USEC(sc->offchannel.duration) + | ||
| 382 | sc->sched.channel_switch_time; | ||
| 383 | } | ||
| 384 | spin_unlock_bh(&sc->chan_lock); | ||
| 385 | ieee80211_queue_work(sc->hw, &sc->chanctx_work); | ||
| 386 | } | ||
| 387 | |||
| 388 | void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, | ||
| 389 | struct cfg80211_chan_def *chandef) | ||
| 390 | { | ||
| 391 | bool cur_chan; | ||
| 392 | |||
| 393 | spin_lock_bh(&sc->chan_lock); | ||
| 394 | if (chandef) | ||
| 395 | memcpy(&ctx->chandef, chandef, sizeof(*chandef)); | ||
| 396 | cur_chan = sc->cur_chan == ctx; | ||
| 397 | spin_unlock_bh(&sc->chan_lock); | ||
| 398 | |||
| 399 | if (!cur_chan) | ||
| 400 | return; | ||
| 401 | |||
| 402 | ath_set_channel(sc); | ||
| 403 | } | ||
| 404 | |||
| 405 | struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active) | ||
| 406 | { | ||
| 407 | struct ath_chanctx *ctx; | ||
| 408 | |||
| 409 | ath_for_each_chanctx(sc, ctx) { | ||
| 410 | if (!ctx->assigned || list_empty(&ctx->vifs)) | ||
| 411 | continue; | ||
| 412 | if (active && !ctx->active) | ||
| 413 | continue; | ||
| 414 | |||
| 415 | if (ctx->switch_after_beacon) | ||
| 416 | return ctx; | ||
| 417 | } | ||
| 418 | |||
| 419 | return &sc->chanctx[0]; | ||
| 420 | } | ||
| 421 | |||
| 422 | void ath_chanctx_offchan_switch(struct ath_softc *sc, | ||
| 423 | struct ieee80211_channel *chan) | ||
| 424 | { | ||
| 425 | struct cfg80211_chan_def chandef; | ||
| 426 | |||
| 427 | cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); | ||
| 428 | |||
| 429 | ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef); | ||
| 430 | } | ||
| 431 | |||
| 432 | static struct ath_chanctx * | ||
| 433 | ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx) | ||
| 434 | { | ||
| 435 | int idx = ctx - &sc->chanctx[0]; | ||
| 436 | |||
| 437 | return &sc->chanctx[!idx]; | ||
| 438 | } | ||
| 439 | |||
| 440 | static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc) | ||
| 441 | { | ||
| 442 | struct ath_chanctx *prev, *cur; | ||
| 443 | struct timespec ts; | ||
| 444 | u32 cur_tsf, prev_tsf, beacon_int; | ||
| 445 | s32 offset; | ||
| 446 | |||
| 447 | beacon_int = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); | ||
| 448 | |||
| 449 | cur = sc->cur_chan; | ||
| 450 | prev = ath_chanctx_get_next(sc, cur); | ||
| 451 | |||
| 452 | getrawmonotonic(&ts); | ||
| 453 | cur_tsf = (u32) cur->tsf_val + | ||
| 454 | ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts); | ||
| 455 | |||
| 456 | prev_tsf = prev->last_beacon - (u32) prev->tsf_val + cur_tsf; | ||
| 457 | prev_tsf -= ath9k_hw_get_tsf_offset(&prev->tsf_ts, &ts); | ||
| 458 | |||
| 459 | /* Adjust the TSF time of the AP chanctx to keep its beacons | ||
| 460 | * at half beacon interval offset relative to the STA chanctx. | ||
| 461 | */ | ||
| 462 | offset = cur_tsf - prev_tsf; | ||
| 463 | |||
| 464 | /* Ignore stale data or spurious timestamps */ | ||
| 465 | if (offset < 0 || offset > 3 * beacon_int) | ||
| 466 | return; | ||
| 467 | |||
| 468 | offset = beacon_int / 2 - (offset % beacon_int); | ||
| 469 | prev->tsf_val += offset; | ||
| 470 | } | ||
| 471 | |||
| 472 | void ath_chanctx_timer(unsigned long data) | ||
| 473 | { | ||
| 474 | struct ath_softc *sc = (struct ath_softc *) data; | ||
| 475 | |||
| 476 | ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER); | ||
| 477 | } | ||
| 478 | |||
| 479 | /* Configure the TSF based hardware timer for a channel switch. | ||
| 480 | * Also set up backup software timer, in case the gen timer fails. | ||
| 481 | * This could be caused by a hardware reset. | ||
| 482 | */ | ||
| 483 | static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time) | ||
| 484 | { | ||
| 485 | struct ath_hw *ah = sc->sc_ah; | ||
| 486 | |||
| 487 | ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000); | ||
| 488 | tsf_time -= ath9k_hw_gettsf32(ah); | ||
| 489 | tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1; | ||
| 490 | mod_timer(&sc->sched.timer, tsf_time); | ||
| 491 | } | ||
| 492 | |||
| 493 | void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, | ||
| 494 | enum ath_chanctx_event ev) | ||
| 495 | { | ||
| 496 | struct ath_hw *ah = sc->sc_ah; | ||
| 497 | struct ath_common *common = ath9k_hw_common(ah); | ||
| 498 | struct ath_beacon_config *cur_conf; | ||
| 499 | struct ath_vif *avp = NULL; | ||
| 500 | struct ath_chanctx *ctx; | ||
| 501 | u32 tsf_time; | ||
| 502 | u32 beacon_int; | ||
| 503 | bool noa_changed = false; | ||
| 504 | |||
| 505 | if (vif) | ||
| 506 | avp = (struct ath_vif *) vif->drv_priv; | ||
| 507 | |||
| 508 | spin_lock_bh(&sc->chan_lock); | ||
| 509 | |||
| 510 | switch (ev) { | ||
| 511 | case ATH_CHANCTX_EVENT_BEACON_PREPARE: | ||
| 512 | if (avp->offchannel_duration) | ||
| 513 | avp->offchannel_duration = 0; | ||
| 514 | |||
| 515 | if (avp->chanctx != sc->cur_chan) | ||
| 516 | break; | ||
| 517 | |||
| 518 | if (sc->sched.offchannel_pending) { | ||
| 519 | sc->sched.offchannel_pending = false; | ||
| 520 | sc->next_chan = &sc->offchannel.chan; | ||
| 521 | sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; | ||
| 522 | } | ||
| 523 | |||
| 524 | ctx = ath_chanctx_get_next(sc, sc->cur_chan); | ||
| 525 | if (ctx->active && sc->sched.state == ATH_CHANCTX_STATE_IDLE) { | ||
| 526 | sc->next_chan = ctx; | ||
| 527 | sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; | ||
| 528 | } | ||
| 529 | |||
| 530 | /* if the timer missed its window, use the next interval */ | ||
| 531 | if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER) | ||
| 532 | sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; | ||
| 533 | |||
| 534 | if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) | ||
| 535 | break; | ||
| 536 | |||
| 537 | sc->sched.beacon_pending = true; | ||
| 538 | sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER); | ||
| 539 | |||
| 540 | cur_conf = &sc->cur_chan->beacon; | ||
| 541 | beacon_int = TU_TO_USEC(cur_conf->beacon_interval); | ||
| 542 | |||
| 543 | /* defer channel switch by a quarter beacon interval */ | ||
| 544 | tsf_time = sc->sched.next_tbtt + beacon_int / 4; | ||
| 545 | sc->sched.switch_start_time = tsf_time; | ||
| 546 | sc->cur_chan->last_beacon = sc->sched.next_tbtt; | ||
| 547 | |||
| 548 | /* Prevent wrap-around issues */ | ||
| 549 | if (avp->periodic_noa_duration && | ||
| 550 | tsf_time - avp->periodic_noa_start > BIT(30)) | ||
| 551 | avp->periodic_noa_duration = 0; | ||
| 552 | |||
| 553 | if (ctx->active && !avp->periodic_noa_duration) { | ||
| 554 | avp->periodic_noa_start = tsf_time; | ||
| 555 | avp->periodic_noa_duration = | ||
| 556 | TU_TO_USEC(cur_conf->beacon_interval) / 2 - | ||
| 557 | sc->sched.channel_switch_time; | ||
| 558 | noa_changed = true; | ||
| 559 | } else if (!ctx->active && avp->periodic_noa_duration) { | ||
| 560 | avp->periodic_noa_duration = 0; | ||
| 561 | noa_changed = true; | ||
| 562 | } | ||
| 563 | |||
| 564 | /* If at least two consecutive beacons were missed on the STA | ||
| 565 | * chanctx, stay on the STA channel for one extra beacon period, | ||
| 566 | * to resync the timer properly. | ||
| 567 | */ | ||
| 568 | if (ctx->active && sc->sched.beacon_miss >= 2) | ||
| 569 | sc->sched.offchannel_duration = 3 * beacon_int / 2; | ||
| 570 | |||
| 571 | if (sc->sched.offchannel_duration) { | ||
| 572 | noa_changed = true; | ||
| 573 | avp->offchannel_start = tsf_time; | ||
| 574 | avp->offchannel_duration = | ||
| 575 | sc->sched.offchannel_duration; | ||
| 576 | } | ||
| 577 | |||
| 578 | if (noa_changed) | ||
| 579 | avp->noa_index++; | ||
| 580 | break; | ||
| 581 | case ATH_CHANCTX_EVENT_BEACON_SENT: | ||
| 582 | if (!sc->sched.beacon_pending) | ||
| 583 | break; | ||
| 584 | |||
| 585 | sc->sched.beacon_pending = false; | ||
| 586 | if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) | ||
| 587 | break; | ||
| 588 | |||
| 589 | sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; | ||
| 590 | ath_chanctx_setup_timer(sc, sc->sched.switch_start_time); | ||
| 591 | break; | ||
| 592 | case ATH_CHANCTX_EVENT_TSF_TIMER: | ||
| 593 | if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_TIMER) | ||
| 594 | break; | ||
| 595 | |||
| 596 | if (!sc->cur_chan->switch_after_beacon && | ||
| 597 | sc->sched.beacon_pending) | ||
| 598 | sc->sched.beacon_miss++; | ||
| 599 | |||
| 600 | sc->sched.state = ATH_CHANCTX_STATE_SWITCH; | ||
| 601 | ieee80211_queue_work(sc->hw, &sc->chanctx_work); | ||
| 602 | break; | ||
| 603 | case ATH_CHANCTX_EVENT_BEACON_RECEIVED: | ||
| 604 | if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) || | ||
| 605 | sc->cur_chan == &sc->offchannel.chan) | ||
| 606 | break; | ||
| 607 | |||
| 608 | ath_chanctx_adjust_tbtt_delta(sc); | ||
| 609 | sc->sched.beacon_pending = false; | ||
| 610 | sc->sched.beacon_miss = 0; | ||
| 611 | |||
| 612 | /* TSF time might have been updated by the incoming beacon, | ||
| 613 | * need update the channel switch timer to reflect the change. | ||
| 614 | */ | ||
| 615 | tsf_time = sc->sched.switch_start_time; | ||
| 616 | tsf_time -= (u32) sc->cur_chan->tsf_val + | ||
| 617 | ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL); | ||
| 618 | tsf_time += ath9k_hw_gettsf32(ah); | ||
| 619 | |||
| 620 | |||
| 621 | ath_chanctx_setup_timer(sc, tsf_time); | ||
| 622 | break; | ||
| 623 | case ATH_CHANCTX_EVENT_ASSOC: | ||
| 624 | if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE || | ||
| 625 | avp->chanctx != sc->cur_chan) | ||
| 626 | break; | ||
| 627 | |||
| 628 | sc->sched.state = ATH_CHANCTX_STATE_IDLE; | ||
| 629 | /* fall through */ | ||
| 630 | case ATH_CHANCTX_EVENT_SWITCH: | ||
| 631 | if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) || | ||
| 632 | sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE || | ||
| 633 | sc->cur_chan->switch_after_beacon || | ||
| 634 | sc->cur_chan == &sc->offchannel.chan) | ||
| 635 | break; | ||
| 636 | |||
| 637 | /* If this is a station chanctx, stay active for a half | ||
| 638 | * beacon period (minus channel switch time) | ||
| 639 | */ | ||
| 640 | sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan); | ||
| 641 | cur_conf = &sc->cur_chan->beacon; | ||
| 642 | |||
| 643 | sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; | ||
| 644 | |||
| 645 | tsf_time = TU_TO_USEC(cur_conf->beacon_interval) / 2; | ||
| 646 | if (sc->sched.beacon_miss >= 2) { | ||
| 647 | sc->sched.beacon_miss = 0; | ||
| 648 | tsf_time *= 3; | ||
| 649 | } | ||
| 650 | |||
| 651 | tsf_time -= sc->sched.channel_switch_time; | ||
| 652 | tsf_time += ath9k_hw_gettsf32(sc->sc_ah); | ||
| 653 | sc->sched.switch_start_time = tsf_time; | ||
| 654 | |||
| 655 | ath_chanctx_setup_timer(sc, tsf_time); | ||
| 656 | sc->sched.beacon_pending = true; | ||
| 657 | break; | ||
| 658 | case ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL: | ||
| 659 | if (sc->cur_chan == &sc->offchannel.chan || | ||
| 660 | sc->cur_chan->switch_after_beacon) | ||
| 661 | break; | ||
| 662 | |||
| 663 | sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan); | ||
| 664 | ieee80211_queue_work(sc->hw, &sc->chanctx_work); | ||
| 665 | break; | ||
| 666 | case ATH_CHANCTX_EVENT_UNASSIGN: | ||
| 667 | if (sc->cur_chan->assigned) { | ||
| 668 | if (sc->next_chan && !sc->next_chan->assigned && | ||
| 669 | sc->next_chan != &sc->offchannel.chan) | ||
| 670 | sc->sched.state = ATH_CHANCTX_STATE_IDLE; | ||
| 671 | break; | ||
| 672 | } | ||
| 673 | |||
| 674 | ctx = ath_chanctx_get_next(sc, sc->cur_chan); | ||
| 675 | sc->sched.state = ATH_CHANCTX_STATE_IDLE; | ||
| 676 | if (!ctx->assigned) | ||
| 677 | break; | ||
| 678 | |||
| 679 | sc->next_chan = ctx; | ||
| 680 | ieee80211_queue_work(sc->hw, &sc->chanctx_work); | ||
| 681 | break; | ||
| 682 | } | ||
| 683 | |||
| 684 | spin_unlock_bh(&sc->chan_lock); | ||
| 685 | } | ||
diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c index 775d1d20ce0b..733be5178481 100644 --- a/drivers/net/wireless/ath/ath9k/common-beacon.c +++ b/drivers/net/wireless/ath/ath9k/common-beacon.c | |||
| @@ -57,7 +57,7 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, | |||
| 57 | struct ath9k_beacon_state *bs) | 57 | struct ath9k_beacon_state *bs) |
| 58 | { | 58 | { |
| 59 | struct ath_common *common = ath9k_hw_common(ah); | 59 | struct ath_common *common = ath9k_hw_common(ah); |
| 60 | int dtim_intval; | 60 | int dtim_intval, sleepduration; |
| 61 | u64 tsf; | 61 | u64 tsf; |
| 62 | 62 | ||
| 63 | /* No need to configure beacon if we are not associated */ | 63 | /* No need to configure beacon if we are not associated */ |
| @@ -75,6 +75,7 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, | |||
| 75 | * last beacon we received (which may be none). | 75 | * last beacon we received (which may be none). |
| 76 | */ | 76 | */ |
| 77 | dtim_intval = conf->intval * conf->dtim_period; | 77 | dtim_intval = conf->intval * conf->dtim_period; |
| 78 | sleepduration = ah->hw->conf.listen_interval * conf->intval; | ||
| 78 | 79 | ||
| 79 | /* | 80 | /* |
| 80 | * Pull nexttbtt forward to reflect the current | 81 | * Pull nexttbtt forward to reflect the current |
| @@ -112,7 +113,7 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, | |||
| 112 | */ | 113 | */ |
| 113 | 114 | ||
| 114 | bs->bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), | 115 | bs->bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), |
| 115 | conf->intval)); | 116 | sleepduration)); |
| 116 | if (bs->bs_sleepduration > bs->bs_dtimperiod) | 117 | if (bs->bs_sleepduration > bs->bs_dtimperiod) |
| 117 | bs->bs_sleepduration = bs->bs_dtimperiod; | 118 | bs->bs_sleepduration = bs->bs_dtimperiod; |
| 118 | 119 | ||
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 6cc42be48d4e..d2279365be6f 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c | |||
| @@ -202,7 +202,7 @@ static ssize_t write_file_ani(struct file *file, | |||
| 202 | if (kstrtoul(buf, 0, &ani)) | 202 | if (kstrtoul(buf, 0, &ani)) |
| 203 | return -EINVAL; | 203 | return -EINVAL; |
| 204 | 204 | ||
| 205 | if (ani < 0 || ani > 1) | 205 | if (ani > 1) |
| 206 | return -EINVAL; | 206 | return -EINVAL; |
| 207 | 207 | ||
| 208 | common->disable_ani = !ani; | 208 | common->disable_ani = !ani; |
| @@ -750,13 +750,13 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, | |||
| 750 | { | 750 | { |
| 751 | struct ath_softc *sc = file->private_data; | 751 | struct ath_softc *sc = file->private_data; |
| 752 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 752 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 753 | struct ieee80211_hw *hw = sc->hw; | ||
| 754 | struct ath9k_vif_iter_data iter_data; | 753 | struct ath9k_vif_iter_data iter_data; |
| 754 | struct ath_chanctx *ctx; | ||
| 755 | char buf[512]; | 755 | char buf[512]; |
| 756 | unsigned int len = 0; | 756 | unsigned int len = 0; |
| 757 | ssize_t retval = 0; | 757 | ssize_t retval = 0; |
| 758 | unsigned int reg; | 758 | unsigned int reg; |
| 759 | u32 rxfilter; | 759 | u32 rxfilter, i; |
| 760 | 760 | ||
| 761 | len += scnprintf(buf + len, sizeof(buf) - len, | 761 | len += scnprintf(buf + len, sizeof(buf) - len, |
| 762 | "BSSID: %pM\n", common->curbssid); | 762 | "BSSID: %pM\n", common->curbssid); |
| @@ -826,14 +826,20 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, | |||
| 826 | 826 | ||
| 827 | len += scnprintf(buf + len, sizeof(buf) - len, "\n"); | 827 | len += scnprintf(buf + len, sizeof(buf) - len, "\n"); |
| 828 | 828 | ||
| 829 | ath9k_calculate_iter_data(hw, NULL, &iter_data); | 829 | i = 0; |
| 830 | 830 | ath_for_each_chanctx(sc, ctx) { | |
| 831 | len += scnprintf(buf + len, sizeof(buf) - len, | 831 | if (!ctx->assigned || list_empty(&ctx->vifs)) |
| 832 | "VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i" | 832 | continue; |
| 833 | " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n", | 833 | ath9k_calculate_iter_data(sc, ctx, &iter_data); |
| 834 | iter_data.naps, iter_data.nstations, iter_data.nmeshes, | 834 | |
| 835 | iter_data.nwds, iter_data.nadhocs, | 835 | len += scnprintf(buf + len, sizeof(buf) - len, |
| 836 | sc->nvifs, sc->nbcnvifs); | 836 | "VIF-COUNTS: CTX %i AP: %i STA: %i MESH: %i WDS: %i", |
| 837 | i++, iter_data.naps, iter_data.nstations, | ||
| 838 | iter_data.nmeshes, iter_data.nwds); | ||
| 839 | len += scnprintf(buf + len, sizeof(buf) - len, | ||
| 840 | " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n", | ||
| 841 | iter_data.nadhocs, sc->nvifs, sc->nbcnvifs); | ||
| 842 | } | ||
| 837 | 843 | ||
| 838 | if (len > sizeof(buf)) | 844 | if (len > sizeof(buf)) |
| 839 | len = sizeof(buf); | 845 | len = sizeof(buf); |
| @@ -1080,7 +1086,7 @@ static ssize_t read_file_dump_nfcal(struct file *file, char __user *user_buf, | |||
| 1080 | { | 1086 | { |
| 1081 | struct ath_softc *sc = file->private_data; | 1087 | struct ath_softc *sc = file->private_data; |
| 1082 | struct ath_hw *ah = sc->sc_ah; | 1088 | struct ath_hw *ah = sc->sc_ah; |
| 1083 | struct ath9k_nfcal_hist *h = sc->caldata.nfCalHist; | 1089 | struct ath9k_nfcal_hist *h = sc->cur_chan->caldata.nfCalHist; |
| 1084 | struct ath_common *common = ath9k_hw_common(ah); | 1090 | struct ath_common *common = ath9k_hw_common(ah); |
| 1085 | struct ieee80211_conf *conf = &common->hw->conf; | 1091 | struct ieee80211_conf *conf = &common->hw->conf; |
| 1086 | u32 len = 0, size = 1500; | 1092 | u32 len = 0, size = 1500; |
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2a8ed8375ec0..69bbea1184d2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
| @@ -791,7 +791,8 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, | |||
| 791 | refdiv = 5; | 791 | refdiv = 5; |
| 792 | } else { | 792 | } else { |
| 793 | pll2_divint = 0x11; | 793 | pll2_divint = 0x11; |
| 794 | pll2_divfrac = 0x26666; | 794 | pll2_divfrac = |
| 795 | AR_SREV_9531(ah) ? 0x26665 : 0x26666; | ||
| 795 | refdiv = 1; | 796 | refdiv = 1; |
| 796 | } | 797 | } |
| 797 | } | 798 | } |
| @@ -1730,11 +1731,27 @@ fail: | |||
| 1730 | return -EINVAL; | 1731 | return -EINVAL; |
| 1731 | } | 1732 | } |
| 1732 | 1733 | ||
| 1734 | u32 ath9k_hw_get_tsf_offset(struct timespec *last, struct timespec *cur) | ||
| 1735 | { | ||
| 1736 | struct timespec ts; | ||
| 1737 | s64 usec; | ||
| 1738 | |||
| 1739 | if (!cur) { | ||
| 1740 | getrawmonotonic(&ts); | ||
| 1741 | cur = &ts; | ||
| 1742 | } | ||
| 1743 | |||
| 1744 | usec = cur->tv_sec * 1000000ULL + cur->tv_nsec / 1000; | ||
| 1745 | usec -= last->tv_sec * 1000000ULL + last->tv_nsec / 1000; | ||
| 1746 | |||
| 1747 | return (u32) usec; | ||
| 1748 | } | ||
| 1749 | EXPORT_SYMBOL(ath9k_hw_get_tsf_offset); | ||
| 1750 | |||
| 1733 | int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | 1751 | int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, |
| 1734 | struct ath9k_hw_cal_data *caldata, bool fastcc) | 1752 | struct ath9k_hw_cal_data *caldata, bool fastcc) |
| 1735 | { | 1753 | { |
| 1736 | struct ath_common *common = ath9k_hw_common(ah); | 1754 | struct ath_common *common = ath9k_hw_common(ah); |
| 1737 | struct timespec ts; | ||
| 1738 | u32 saveLedState; | 1755 | u32 saveLedState; |
| 1739 | u32 saveDefAntenna; | 1756 | u32 saveDefAntenna; |
| 1740 | u32 macStaId1; | 1757 | u32 macStaId1; |
| @@ -1784,8 +1801,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
| 1784 | 1801 | ||
| 1785 | /* Save TSF before chip reset, a cold reset clears it */ | 1802 | /* Save TSF before chip reset, a cold reset clears it */ |
| 1786 | tsf = ath9k_hw_gettsf64(ah); | 1803 | tsf = ath9k_hw_gettsf64(ah); |
| 1787 | getrawmonotonic(&ts); | 1804 | usec = ktime_to_us(ktime_get_raw()); |
| 1788 | usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000; | ||
| 1789 | 1805 | ||
| 1790 | saveLedState = REG_READ(ah, AR_CFG_LED) & | 1806 | saveLedState = REG_READ(ah, AR_CFG_LED) & |
| 1791 | (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | | 1807 | (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | |
| @@ -1818,8 +1834,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
| 1818 | } | 1834 | } |
| 1819 | 1835 | ||
| 1820 | /* Restore TSF */ | 1836 | /* Restore TSF */ |
| 1821 | getrawmonotonic(&ts); | 1837 | usec = ktime_to_us(ktime_get_raw()) - usec; |
| 1822 | usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000 - usec; | ||
| 1823 | ath9k_hw_settsf64(ah, tsf + usec); | 1838 | ath9k_hw_settsf64(ah, tsf + usec); |
| 1824 | 1839 | ||
| 1825 | if (AR_SREV_9280_20_OR_LATER(ah)) | 1840 | if (AR_SREV_9280_20_OR_LATER(ah)) |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 0acd4b5a4892..51b4ebe04c04 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
| @@ -1000,6 +1000,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah); | |||
| 1000 | u64 ath9k_hw_gettsf64(struct ath_hw *ah); | 1000 | u64 ath9k_hw_gettsf64(struct ath_hw *ah); |
| 1001 | void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); | 1001 | void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); |
| 1002 | void ath9k_hw_reset_tsf(struct ath_hw *ah); | 1002 | void ath9k_hw_reset_tsf(struct ath_hw *ah); |
| 1003 | u32 ath9k_hw_get_tsf_offset(struct timespec *last, struct timespec *cur); | ||
| 1003 | void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set); | 1004 | void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set); |
| 1004 | void ath9k_hw_init_global_settings(struct ath_hw *ah); | 1005 | void ath9k_hw_init_global_settings(struct ath_hw *ah); |
| 1005 | u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); | 1006 | u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); |
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 0246b990fe87..39419ea845cc 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
| @@ -61,7 +61,7 @@ static int ath9k_ps_enable; | |||
| 61 | module_param_named(ps_enable, ath9k_ps_enable, int, 0444); | 61 | module_param_named(ps_enable, ath9k_ps_enable, int, 0444); |
| 62 | MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); | 62 | MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); |
| 63 | 63 | ||
| 64 | static int ath9k_use_chanctx; | 64 | int ath9k_use_chanctx; |
| 65 | module_param_named(use_chanctx, ath9k_use_chanctx, int, 0444); | 65 | module_param_named(use_chanctx, ath9k_use_chanctx, int, 0444); |
| 66 | MODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency"); | 66 | MODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency"); |
| 67 | 67 | ||
| @@ -169,9 +169,9 @@ static void ath9k_reg_notifier(struct wiphy *wiphy, | |||
| 169 | 169 | ||
| 170 | /* Set tx power */ | 170 | /* Set tx power */ |
| 171 | if (ah->curchan) { | 171 | if (ah->curchan) { |
| 172 | sc->config.txpowlimit = 2 * ah->curchan->chan->max_power; | 172 | sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power; |
| 173 | ath9k_ps_wakeup(sc); | 173 | ath9k_ps_wakeup(sc); |
| 174 | ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); | 174 | ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); |
| 175 | sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit; | 175 | sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit; |
| 176 | /* synchronize DFS detector if regulatory domain changed */ | 176 | /* synchronize DFS detector if regulatory domain changed */ |
| 177 | if (sc->dfs_detector != NULL) | 177 | if (sc->dfs_detector != NULL) |
| @@ -335,7 +335,6 @@ static void ath9k_init_misc(struct ath_softc *sc) | |||
| 335 | setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); | 335 | setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); |
| 336 | 336 | ||
| 337 | common->last_rssi = ATH_RSSI_DUMMY_MARKER; | 337 | common->last_rssi = ATH_RSSI_DUMMY_MARKER; |
| 338 | sc->config.txpowlimit = ATH_TXPOWER_MAX; | ||
| 339 | memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); | 338 | memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); |
| 340 | sc->beacon.slottime = ATH9K_SLOT_TIME_9; | 339 | sc->beacon.slottime = ATH9K_SLOT_TIME_9; |
| 341 | 340 | ||
| @@ -511,6 +510,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, | |||
| 511 | sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET); | 510 | sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET); |
| 512 | sc->tx99_power = MAX_RATE_POWER + 1; | 511 | sc->tx99_power = MAX_RATE_POWER + 1; |
| 513 | init_waitqueue_head(&sc->tx_wait); | 512 | init_waitqueue_head(&sc->tx_wait); |
| 513 | sc->cur_chan = &sc->chanctx[0]; | ||
| 514 | if (!ath9k_use_chanctx) | ||
| 515 | sc->cur_chan->hw_queue_base = 0; | ||
| 514 | 516 | ||
| 515 | if (!pdata || pdata->use_eeprom) { | 517 | if (!pdata || pdata->use_eeprom) { |
| 516 | ah->ah_flags |= AH_USE_EEPROM; | 518 | ah->ah_flags |= AH_USE_EEPROM; |
| @@ -556,6 +558,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, | |||
| 556 | spin_lock_init(&common->cc_lock); | 558 | spin_lock_init(&common->cc_lock); |
| 557 | spin_lock_init(&sc->sc_serial_rw); | 559 | spin_lock_init(&sc->sc_serial_rw); |
| 558 | spin_lock_init(&sc->sc_pm_lock); | 560 | spin_lock_init(&sc->sc_pm_lock); |
| 561 | spin_lock_init(&sc->chan_lock); | ||
| 559 | mutex_init(&sc->mutex); | 562 | mutex_init(&sc->mutex); |
| 560 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); | 563 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); |
| 561 | tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, | 564 | tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, |
| @@ -564,7 +567,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, | |||
| 564 | setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc); | 567 | setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc); |
| 565 | INIT_WORK(&sc->hw_reset_work, ath_reset_work); | 568 | INIT_WORK(&sc->hw_reset_work, ath_reset_work); |
| 566 | INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); | 569 | INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); |
| 570 | INIT_WORK(&sc->chanctx_work, ath_chanctx_work); | ||
| 567 | INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); | 571 | INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); |
| 572 | setup_timer(&sc->offchannel.timer, ath_offchannel_timer, | ||
| 573 | (unsigned long)sc); | ||
| 574 | setup_timer(&sc->sched.timer, ath_chanctx_timer, (unsigned long)sc); | ||
| 568 | 575 | ||
| 569 | /* | 576 | /* |
| 570 | * Cache line size is used to size and align various | 577 | * Cache line size is used to size and align various |
| @@ -599,6 +606,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, | |||
| 599 | ath9k_cmn_init_crypto(sc->sc_ah); | 606 | ath9k_cmn_init_crypto(sc->sc_ah); |
| 600 | ath9k_init_misc(sc); | 607 | ath9k_init_misc(sc); |
| 601 | ath_fill_led_pin(sc); | 608 | ath_fill_led_pin(sc); |
| 609 | ath_chanctx_init(sc); | ||
| 602 | 610 | ||
| 603 | if (common->bus_ops->aspm_init) | 611 | if (common->bus_ops->aspm_init) |
| 604 | common->bus_ops->aspm_init(common); | 612 | common->bus_ops->aspm_init(common); |
| @@ -664,6 +672,12 @@ static const struct ieee80211_iface_limit wds_limits[] = { | |||
| 664 | { .max = 2048, .types = BIT(NL80211_IFTYPE_WDS) }, | 672 | { .max = 2048, .types = BIT(NL80211_IFTYPE_WDS) }, |
| 665 | }; | 673 | }; |
| 666 | 674 | ||
| 675 | static const struct ieee80211_iface_limit if_limits_multi[] = { | ||
| 676 | { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) }, | ||
| 677 | { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
| 678 | BIT(NL80211_IFTYPE_P2P_GO) }, | ||
| 679 | }; | ||
| 680 | |||
| 667 | static const struct ieee80211_iface_limit if_dfs_limits[] = { | 681 | static const struct ieee80211_iface_limit if_dfs_limits[] = { |
| 668 | { .max = 1, .types = BIT(NL80211_IFTYPE_AP) | | 682 | { .max = 1, .types = BIT(NL80211_IFTYPE_AP) | |
| 669 | #ifdef CONFIG_MAC80211_MESH | 683 | #ifdef CONFIG_MAC80211_MESH |
| @@ -672,6 +686,16 @@ static const struct ieee80211_iface_limit if_dfs_limits[] = { | |||
| 672 | BIT(NL80211_IFTYPE_ADHOC) }, | 686 | BIT(NL80211_IFTYPE_ADHOC) }, |
| 673 | }; | 687 | }; |
| 674 | 688 | ||
| 689 | static const struct ieee80211_iface_combination if_comb_multi[] = { | ||
| 690 | { | ||
| 691 | .limits = if_limits_multi, | ||
| 692 | .n_limits = ARRAY_SIZE(if_limits_multi), | ||
| 693 | .max_interfaces = 2, | ||
| 694 | .num_different_channels = 2, | ||
| 695 | .beacon_int_infra_match = true, | ||
| 696 | }, | ||
| 697 | }; | ||
| 698 | |||
| 675 | static const struct ieee80211_iface_combination if_comb[] = { | 699 | static const struct ieee80211_iface_combination if_comb[] = { |
| 676 | { | 700 | { |
| 677 | .limits = if_limits, | 701 | .limits = if_limits, |
| @@ -712,6 +736,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
| 712 | IEEE80211_HW_SPECTRUM_MGMT | | 736 | IEEE80211_HW_SPECTRUM_MGMT | |
| 713 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | 737 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | |
| 714 | IEEE80211_HW_SUPPORTS_RC_TABLE | | 738 | IEEE80211_HW_SUPPORTS_RC_TABLE | |
| 739 | IEEE80211_HW_QUEUE_CONTROL | | ||
| 715 | IEEE80211_HW_SUPPORTS_HT_CCK_RATES; | 740 | IEEE80211_HW_SUPPORTS_HT_CCK_RATES; |
| 716 | 741 | ||
| 717 | if (ath9k_ps_enable) | 742 | if (ath9k_ps_enable) |
| @@ -739,12 +764,21 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
| 739 | BIT(NL80211_IFTYPE_STATION) | | 764 | BIT(NL80211_IFTYPE_STATION) | |
| 740 | BIT(NL80211_IFTYPE_ADHOC) | | 765 | BIT(NL80211_IFTYPE_ADHOC) | |
| 741 | BIT(NL80211_IFTYPE_MESH_POINT); | 766 | BIT(NL80211_IFTYPE_MESH_POINT); |
| 742 | hw->wiphy->iface_combinations = if_comb; | ||
| 743 | if (!ath9k_use_chanctx) { | 767 | if (!ath9k_use_chanctx) { |
| 768 | hw->wiphy->iface_combinations = if_comb; | ||
| 744 | hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); | 769 | hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); |
| 745 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_WDS); | 770 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_WDS); |
| 746 | } else | 771 | } else { |
| 747 | hw->wiphy->n_iface_combinations = 1; | 772 | hw->wiphy->iface_combinations = if_comb_multi; |
| 773 | hw->wiphy->n_iface_combinations = | ||
| 774 | ARRAY_SIZE(if_comb_multi); | ||
| 775 | hw->wiphy->max_scan_ssids = 255; | ||
| 776 | hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; | ||
| 777 | hw->wiphy->max_remain_on_channel_duration = 10000; | ||
| 778 | hw->chanctx_data_size = sizeof(void *); | ||
| 779 | hw->extra_beacon_tailroom = | ||
| 780 | sizeof(struct ieee80211_p2p_noa_attr) + 9; | ||
| 781 | } | ||
| 748 | } | 782 | } |
| 749 | 783 | ||
| 750 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | 784 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; |
| @@ -756,9 +790,14 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
| 756 | hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; | 790 | hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; |
| 757 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; | 791 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; |
| 758 | 792 | ||
| 759 | hw->queues = 4; | 793 | /* allow 4 queues per channel context + |
| 794 | * 1 cab queue + 1 offchannel tx queue | ||
| 795 | */ | ||
| 796 | hw->queues = 10; | ||
| 797 | /* last queue for offchannel */ | ||
| 798 | hw->offchannel_tx_hw_queue = hw->queues - 1; | ||
| 760 | hw->max_rates = 4; | 799 | hw->max_rates = 4; |
| 761 | hw->max_listen_interval = 1; | 800 | hw->max_listen_interval = 10; |
| 762 | hw->max_rate_tries = 10; | 801 | hw->max_rate_tries = 10; |
| 763 | hw->sta_data_size = sizeof(struct ath_node); | 802 | hw->sta_data_size = sizeof(struct ath_node); |
| 764 | hw->vif_data_size = sizeof(struct ath_vif); | 803 | hw->vif_data_size = sizeof(struct ath_vif); |
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 72a715fe8f24..2343f56e6498 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c | |||
| @@ -178,7 +178,7 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int | |||
| 178 | txctl.txq = sc->tx.txq_map[IEEE80211_AC_BE]; | 178 | txctl.txq = sc->tx.txq_map[IEEE80211_AC_BE]; |
| 179 | 179 | ||
| 180 | memset(tx_info, 0, sizeof(*tx_info)); | 180 | memset(tx_info, 0, sizeof(*tx_info)); |
| 181 | tx_info->band = hw->conf.chandef.chan->band; | 181 | tx_info->band = sc->cur_chandef.chan->band; |
| 182 | tx_info->flags |= IEEE80211_TX_CTL_NO_ACK; | 182 | tx_info->flags |= IEEE80211_TX_CTL_NO_ACK; |
| 183 | tx_info->control.rates[0].idx = 0; | 183 | tx_info->control.rates[0].idx = 0; |
| 184 | tx_info->control.rates[0].count = 1; | 184 | tx_info->control.rates[0].count = 1; |
| @@ -416,7 +416,7 @@ void ath_start_ani(struct ath_softc *sc) | |||
| 416 | 416 | ||
| 417 | if (common->disable_ani || | 417 | if (common->disable_ani || |
| 418 | !test_bit(ATH_OP_ANI_RUN, &common->op_flags) || | 418 | !test_bit(ATH_OP_ANI_RUN, &common->op_flags) || |
| 419 | (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) | 419 | sc->cur_chan->offchannel) |
| 420 | return; | 420 | return; |
| 421 | 421 | ||
| 422 | common->ani.longcal_timer = timestamp; | 422 | common->ani.longcal_timer = timestamp; |
| @@ -440,7 +440,7 @@ void ath_check_ani(struct ath_softc *sc) | |||
| 440 | { | 440 | { |
| 441 | struct ath_hw *ah = sc->sc_ah; | 441 | struct ath_hw *ah = sc->sc_ah; |
| 442 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 442 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 443 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | 443 | struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; |
| 444 | 444 | ||
| 445 | /* | 445 | /* |
| 446 | * Check for the various conditions in which ANI has to | 446 | * Check for the various conditions in which ANI has to |
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index da7686757535..6c56cafa5ca4 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h | |||
| @@ -346,8 +346,14 @@ struct ar5416_desc { | |||
| 346 | #define AR_FrameLen 0x00000fff | 346 | #define AR_FrameLen 0x00000fff |
| 347 | #define AR_VirtMoreFrag 0x00001000 | 347 | #define AR_VirtMoreFrag 0x00001000 |
| 348 | #define AR_TxCtlRsvd00 0x0000e000 | 348 | #define AR_TxCtlRsvd00 0x0000e000 |
| 349 | #define AR_XmitPower 0x003f0000 | 349 | #define AR_XmitPower0 0x003f0000 |
| 350 | #define AR_XmitPower_S 16 | 350 | #define AR_XmitPower0_S 16 |
| 351 | #define AR_XmitPower1 0x3f000000 | ||
| 352 | #define AR_XmitPower1_S 24 | ||
| 353 | #define AR_XmitPower2 0x3f000000 | ||
| 354 | #define AR_XmitPower2_S 24 | ||
| 355 | #define AR_XmitPower3 0x3f000000 | ||
| 356 | #define AR_XmitPower3_S 24 | ||
| 351 | #define AR_RTSEnable 0x00400000 | 357 | #define AR_RTSEnable 0x00400000 |
| 352 | #define AR_VEOL 0x00800000 | 358 | #define AR_VEOL 0x00800000 |
| 353 | #define AR_ClrDestMask 0x01000000 | 359 | #define AR_ClrDestMask 0x01000000 |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 62ac95d6bb9d..e6ac8d2e610c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
| @@ -19,9 +19,6 @@ | |||
| 19 | #include "ath9k.h" | 19 | #include "ath9k.h" |
| 20 | #include "btcoex.h" | 20 | #include "btcoex.h" |
| 21 | 21 | ||
| 22 | static void ath9k_set_assoc_state(struct ath_softc *sc, | ||
| 23 | struct ieee80211_vif *vif); | ||
| 24 | |||
| 25 | u8 ath9k_parse_mpdudensity(u8 mpdudensity) | 22 | u8 ath9k_parse_mpdudensity(u8 mpdudensity) |
| 26 | { | 23 | { |
| 27 | /* | 24 | /* |
| @@ -63,9 +60,16 @@ static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq) | |||
| 63 | 60 | ||
| 64 | spin_lock_bh(&txq->axq_lock); | 61 | spin_lock_bh(&txq->axq_lock); |
| 65 | 62 | ||
| 66 | if (txq->axq_depth || !list_empty(&txq->axq_acq)) | 63 | if (txq->axq_depth) |
| 67 | pending = true; | 64 | pending = true; |
| 68 | 65 | ||
| 66 | if (txq->mac80211_qnum >= 0) { | ||
| 67 | struct list_head *list; | ||
| 68 | |||
| 69 | list = &sc->cur_chan->acq[txq->mac80211_qnum]; | ||
| 70 | if (!list_empty(list)) | ||
| 71 | pending = true; | ||
| 72 | } | ||
| 69 | spin_unlock_bh(&txq->axq_lock); | 73 | spin_unlock_bh(&txq->axq_lock); |
| 70 | return pending; | 74 | return pending; |
| 71 | } | 75 | } |
| @@ -227,13 +231,22 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) | |||
| 227 | } | 231 | } |
| 228 | 232 | ||
| 229 | ath9k_cmn_update_txpow(ah, sc->curtxpow, | 233 | ath9k_cmn_update_txpow(ah, sc->curtxpow, |
| 230 | sc->config.txpowlimit, &sc->curtxpow); | 234 | sc->cur_chan->txpower, &sc->curtxpow); |
| 231 | 235 | ||
| 232 | clear_bit(ATH_OP_HW_RESET, &common->op_flags); | 236 | clear_bit(ATH_OP_HW_RESET, &common->op_flags); |
| 233 | ath9k_hw_set_interrupts(ah); | 237 | ath9k_calculate_summary_state(sc, sc->cur_chan); |
| 234 | ath9k_hw_enable_interrupts(ah); | 238 | |
| 239 | if (!sc->cur_chan->offchannel && start) { | ||
| 240 | /* restore per chanctx TSF timer */ | ||
| 241 | if (sc->cur_chan->tsf_val) { | ||
| 242 | u32 offset; | ||
| 243 | |||
| 244 | offset = ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, | ||
| 245 | NULL); | ||
| 246 | ath9k_hw_settsf64(ah, sc->cur_chan->tsf_val + offset); | ||
| 247 | } | ||
| 248 | |||
| 235 | 249 | ||
| 236 | if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && start) { | ||
| 237 | if (!test_bit(ATH_OP_BEACONS, &common->op_flags)) | 250 | if (!test_bit(ATH_OP_BEACONS, &common->op_flags)) |
| 238 | goto work; | 251 | goto work; |
| 239 | 252 | ||
| @@ -247,26 +260,35 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) | |||
| 247 | } | 260 | } |
| 248 | work: | 261 | work: |
| 249 | ath_restart_work(sc); | 262 | ath_restart_work(sc); |
| 263 | ath_txq_schedule_all(sc); | ||
| 264 | } | ||
| 250 | 265 | ||
| 251 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { | 266 | sc->gtt_cnt = 0; |
| 252 | if (!ATH_TXQ_SETUP(sc, i)) | ||
| 253 | continue; | ||
| 254 | 267 | ||
| 255 | spin_lock_bh(&sc->tx.txq[i].axq_lock); | 268 | ath9k_hw_set_interrupts(ah); |
| 256 | ath_txq_schedule(sc, &sc->tx.txq[i]); | 269 | ath9k_hw_enable_interrupts(ah); |
| 257 | spin_unlock_bh(&sc->tx.txq[i].axq_lock); | 270 | |
| 271 | if (!ath9k_use_chanctx) | ||
| 272 | ieee80211_wake_queues(sc->hw); | ||
| 273 | else { | ||
| 274 | if (sc->cur_chan == &sc->offchannel.chan) | ||
| 275 | ieee80211_wake_queue(sc->hw, | ||
| 276 | sc->hw->offchannel_tx_hw_queue); | ||
| 277 | else { | ||
| 278 | for (i = 0; i < IEEE80211_NUM_ACS; i++) | ||
| 279 | ieee80211_wake_queue(sc->hw, | ||
| 280 | sc->cur_chan->hw_queue_base + i); | ||
| 258 | } | 281 | } |
| 282 | if (ah->opmode == NL80211_IFTYPE_AP) | ||
| 283 | ieee80211_wake_queue(sc->hw, sc->hw->queues - 2); | ||
| 259 | } | 284 | } |
| 260 | 285 | ||
| 261 | sc->gtt_cnt = 0; | ||
| 262 | ieee80211_wake_queues(sc->hw); | ||
| 263 | |||
| 264 | ath9k_p2p_ps_timer(sc); | 286 | ath9k_p2p_ps_timer(sc); |
| 265 | 287 | ||
| 266 | return true; | 288 | return true; |
| 267 | } | 289 | } |
| 268 | 290 | ||
| 269 | static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) | 291 | int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) |
| 270 | { | 292 | { |
| 271 | struct ath_hw *ah = sc->sc_ah; | 293 | struct ath_hw *ah = sc->sc_ah; |
| 272 | struct ath_common *common = ath9k_hw_common(ah); | 294 | struct ath_common *common = ath9k_hw_common(ah); |
| @@ -279,9 +301,9 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) | |||
| 279 | tasklet_disable(&sc->intr_tq); | 301 | tasklet_disable(&sc->intr_tq); |
| 280 | spin_lock_bh(&sc->sc_pcu_lock); | 302 | spin_lock_bh(&sc->sc_pcu_lock); |
| 281 | 303 | ||
| 282 | if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) { | 304 | if (!sc->cur_chan->offchannel) { |
| 283 | fastcc = false; | 305 | fastcc = false; |
| 284 | caldata = &sc->caldata; | 306 | caldata = &sc->cur_chan->caldata; |
| 285 | } | 307 | } |
| 286 | 308 | ||
| 287 | if (!hchan) { | 309 | if (!hchan) { |
| @@ -292,6 +314,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) | |||
| 292 | if (!ath_prepare_reset(sc)) | 314 | if (!ath_prepare_reset(sc)) |
| 293 | fastcc = false; | 315 | fastcc = false; |
| 294 | 316 | ||
| 317 | spin_lock_bh(&sc->chan_lock); | ||
| 318 | sc->cur_chandef = sc->cur_chan->chandef; | ||
| 319 | spin_unlock_bh(&sc->chan_lock); | ||
| 320 | |||
| 295 | ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", | 321 | ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", |
| 296 | hchan->channel, IS_CHAN_HT40(hchan), fastcc); | 322 | hchan->channel, IS_CHAN_HT40(hchan), fastcc); |
| 297 | 323 | ||
| @@ -307,7 +333,7 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) | |||
| 307 | } | 333 | } |
| 308 | 334 | ||
| 309 | if (ath9k_hw_mci_is_enabled(sc->sc_ah) && | 335 | if (ath9k_hw_mci_is_enabled(sc->sc_ah) && |
| 310 | (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) | 336 | sc->cur_chan->offchannel) |
| 311 | ath9k_mci_set_txpower(sc, true, false); | 337 | ath9k_mci_set_txpower(sc, true, false); |
| 312 | 338 | ||
| 313 | if (!ath_complete_reset(sc, true)) | 339 | if (!ath_complete_reset(sc, true)) |
| @@ -320,98 +346,6 @@ out: | |||
| 320 | return r; | 346 | return r; |
| 321 | } | 347 | } |
| 322 | 348 | ||
| 323 | |||
| 324 | /* | ||
| 325 | * Set/change channels. If the channel is really being changed, it's done | ||
| 326 | * by reseting the chip. To accomplish this we must first cleanup any pending | ||
| 327 | * DMA, then restart stuff. | ||
| 328 | */ | ||
| 329 | static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chandef) | ||
| 330 | { | ||
| 331 | struct ath_hw *ah = sc->sc_ah; | ||
| 332 | struct ath_common *common = ath9k_hw_common(ah); | ||
| 333 | struct ieee80211_hw *hw = sc->hw; | ||
| 334 | struct ath9k_channel *hchan; | ||
| 335 | struct ieee80211_channel *chan = chandef->chan; | ||
| 336 | bool offchannel; | ||
| 337 | int pos = chan->hw_value; | ||
| 338 | int old_pos = -1; | ||
| 339 | int r; | ||
| 340 | |||
| 341 | if (test_bit(ATH_OP_INVALID, &common->op_flags)) | ||
| 342 | return -EIO; | ||
| 343 | |||
| 344 | offchannel = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); | ||
| 345 | |||
| 346 | if (ah->curchan) | ||
| 347 | old_pos = ah->curchan - &ah->channels[0]; | ||
| 348 | |||
| 349 | ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", | ||
| 350 | chan->center_freq, chandef->width); | ||
| 351 | |||
| 352 | /* update survey stats for the old channel before switching */ | ||
| 353 | spin_lock_bh(&common->cc_lock); | ||
| 354 | ath_update_survey_stats(sc); | ||
| 355 | spin_unlock_bh(&common->cc_lock); | ||
| 356 | |||
| 357 | ath9k_cmn_get_channel(hw, ah, chandef); | ||
| 358 | |||
| 359 | /* | ||
| 360 | * If the operating channel changes, change the survey in-use flags | ||
| 361 | * along with it. | ||
| 362 | * Reset the survey data for the new channel, unless we're switching | ||
| 363 | * back to the operating channel from an off-channel operation. | ||
| 364 | */ | ||
| 365 | if (!offchannel && sc->cur_survey != &sc->survey[pos]) { | ||
| 366 | if (sc->cur_survey) | ||
| 367 | sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; | ||
| 368 | |||
| 369 | sc->cur_survey = &sc->survey[pos]; | ||
| 370 | |||
| 371 | memset(sc->cur_survey, 0, sizeof(struct survey_info)); | ||
| 372 | sc->cur_survey->filled |= SURVEY_INFO_IN_USE; | ||
| 373 | } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { | ||
| 374 | memset(&sc->survey[pos], 0, sizeof(struct survey_info)); | ||
| 375 | } | ||
| 376 | |||
| 377 | hchan = &sc->sc_ah->channels[pos]; | ||
| 378 | r = ath_reset_internal(sc, hchan); | ||
| 379 | if (r) | ||
| 380 | return r; | ||
| 381 | |||
| 382 | /* | ||
| 383 | * The most recent snapshot of channel->noisefloor for the old | ||
| 384 | * channel is only available after the hardware reset. Copy it to | ||
| 385 | * the survey stats now. | ||
| 386 | */ | ||
| 387 | if (old_pos >= 0) | ||
| 388 | ath_update_survey_nf(sc, old_pos); | ||
| 389 | |||
| 390 | /* | ||
| 391 | * Enable radar pulse detection if on a DFS channel. Spectral | ||
| 392 | * scanning and radar detection can not be used concurrently. | ||
| 393 | */ | ||
| 394 | if (hw->conf.radar_enabled) { | ||
| 395 | u32 rxfilter; | ||
| 396 | |||
| 397 | /* set HW specific DFS configuration */ | ||
| 398 | ath9k_hw_set_radar_params(ah); | ||
| 399 | rxfilter = ath9k_hw_getrxfilter(ah); | ||
| 400 | rxfilter |= ATH9K_RX_FILTER_PHYRADAR | | ||
| 401 | ATH9K_RX_FILTER_PHYERR; | ||
| 402 | ath9k_hw_setrxfilter(ah, rxfilter); | ||
| 403 | ath_dbg(common, DFS, "DFS enabled at freq %d\n", | ||
| 404 | chan->center_freq); | ||
| 405 | } else { | ||
| 406 | /* perform spectral scan if requested. */ | ||
| 407 | if (test_bit(ATH_OP_SCANNING, &common->op_flags) && | ||
| 408 | sc->spectral_mode == SPECTRAL_CHANSCAN) | ||
| 409 | ath9k_spectral_scan_trigger(hw); | ||
| 410 | } | ||
| 411 | |||
| 412 | return 0; | ||
| 413 | } | ||
| 414 | |||
| 415 | static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, | 349 | static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, |
| 416 | struct ieee80211_vif *vif) | 350 | struct ieee80211_vif *vif) |
| 417 | { | 351 | { |
| @@ -712,7 +646,8 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
| 712 | struct ath_softc *sc = hw->priv; | 646 | struct ath_softc *sc = hw->priv; |
| 713 | struct ath_hw *ah = sc->sc_ah; | 647 | struct ath_hw *ah = sc->sc_ah; |
| 714 | struct ath_common *common = ath9k_hw_common(ah); | 648 | struct ath_common *common = ath9k_hw_common(ah); |
| 715 | struct ieee80211_channel *curchan = hw->conf.chandef.chan; | 649 | struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan; |
| 650 | struct ath_chanctx *ctx = sc->cur_chan; | ||
| 716 | struct ath9k_channel *init_channel; | 651 | struct ath9k_channel *init_channel; |
| 717 | int r; | 652 | int r; |
| 718 | 653 | ||
| @@ -723,7 +658,8 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
| 723 | ath9k_ps_wakeup(sc); | 658 | ath9k_ps_wakeup(sc); |
| 724 | mutex_lock(&sc->mutex); | 659 | mutex_lock(&sc->mutex); |
| 725 | 660 | ||
| 726 | init_channel = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef); | 661 | init_channel = ath9k_cmn_get_channel(hw, ah, &ctx->chandef); |
| 662 | sc->cur_chandef = hw->conf.chandef; | ||
| 727 | 663 | ||
| 728 | /* Reset SERDES registers */ | 664 | /* Reset SERDES registers */ |
| 729 | ath9k_hw_configpcipowersave(ah, false); | 665 | ath9k_hw_configpcipowersave(ah, false); |
| @@ -886,6 +822,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
| 886 | struct ath_common *common = ath9k_hw_common(ah); | 822 | struct ath_common *common = ath9k_hw_common(ah); |
| 887 | bool prev_idle; | 823 | bool prev_idle; |
| 888 | 824 | ||
| 825 | cancel_work_sync(&sc->chanctx_work); | ||
| 889 | mutex_lock(&sc->mutex); | 826 | mutex_lock(&sc->mutex); |
| 890 | 827 | ||
| 891 | ath_cancel_work(sc); | 828 | ath_cancel_work(sc); |
| @@ -934,7 +871,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
| 934 | } | 871 | } |
| 935 | 872 | ||
| 936 | if (!ah->curchan) | 873 | if (!ah->curchan) |
| 937 | ah->curchan = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef); | 874 | ah->curchan = ath9k_cmn_get_channel(hw, ah, |
| 875 | &sc->cur_chan->chandef); | ||
| 938 | 876 | ||
| 939 | ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); | 877 | ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); |
| 940 | ath9k_hw_phy_disable(ah); | 878 | ath9k_hw_phy_disable(ah); |
| @@ -979,18 +917,29 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | |||
| 979 | iter_data->has_hw_macaddr = true; | 917 | iter_data->has_hw_macaddr = true; |
| 980 | } | 918 | } |
| 981 | 919 | ||
| 920 | if (!vif->bss_conf.use_short_slot) | ||
| 921 | iter_data->slottime = ATH9K_SLOT_TIME_20; | ||
| 922 | |||
| 982 | switch (vif->type) { | 923 | switch (vif->type) { |
| 983 | case NL80211_IFTYPE_AP: | 924 | case NL80211_IFTYPE_AP: |
| 984 | iter_data->naps++; | 925 | iter_data->naps++; |
| 926 | if (vif->bss_conf.enable_beacon) | ||
| 927 | iter_data->beacons = true; | ||
| 985 | break; | 928 | break; |
| 986 | case NL80211_IFTYPE_STATION: | 929 | case NL80211_IFTYPE_STATION: |
| 987 | iter_data->nstations++; | 930 | iter_data->nstations++; |
| 931 | if (vif->bss_conf.assoc && !iter_data->primary_sta) | ||
| 932 | iter_data->primary_sta = vif; | ||
| 988 | break; | 933 | break; |
| 989 | case NL80211_IFTYPE_ADHOC: | 934 | case NL80211_IFTYPE_ADHOC: |
| 990 | iter_data->nadhocs++; | 935 | iter_data->nadhocs++; |
| 936 | if (vif->bss_conf.enable_beacon) | ||
| 937 | iter_data->beacons = true; | ||
| 991 | break; | 938 | break; |
| 992 | case NL80211_IFTYPE_MESH_POINT: | 939 | case NL80211_IFTYPE_MESH_POINT: |
| 993 | iter_data->nmeshes++; | 940 | iter_data->nmeshes++; |
| 941 | if (vif->bss_conf.enable_beacon) | ||
| 942 | iter_data->beacons = true; | ||
| 994 | break; | 943 | break; |
| 995 | case NL80211_IFTYPE_WDS: | 944 | case NL80211_IFTYPE_WDS: |
| 996 | iter_data->nwds++; | 945 | iter_data->nwds++; |
| @@ -1000,26 +949,12 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | |||
| 1000 | } | 949 | } |
| 1001 | } | 950 | } |
| 1002 | 951 | ||
| 1003 | static void ath9k_sta_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | ||
| 1004 | { | ||
| 1005 | struct ath_softc *sc = data; | ||
| 1006 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
| 1007 | |||
| 1008 | if (vif->type != NL80211_IFTYPE_STATION) | ||
| 1009 | return; | ||
| 1010 | |||
| 1011 | if (avp->primary_sta_vif) | ||
| 1012 | ath9k_set_assoc_state(sc, vif); | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | /* Called with sc->mutex held. */ | 952 | /* Called with sc->mutex held. */ |
| 1016 | void ath9k_calculate_iter_data(struct ieee80211_hw *hw, | 953 | void ath9k_calculate_iter_data(struct ath_softc *sc, |
| 1017 | struct ieee80211_vif *vif, | 954 | struct ath_chanctx *ctx, |
| 1018 | struct ath9k_vif_iter_data *iter_data) | 955 | struct ath9k_vif_iter_data *iter_data) |
| 1019 | { | 956 | { |
| 1020 | struct ath_softc *sc = hw->priv; | 957 | struct ath_vif *avp; |
| 1021 | struct ath_hw *ah = sc->sc_ah; | ||
| 1022 | struct ath_common *common = ath9k_hw_common(ah); | ||
| 1023 | 958 | ||
| 1024 | /* | 959 | /* |
| 1025 | * Pick the MAC address of the first interface as the new hardware | 960 | * Pick the MAC address of the first interface as the new hardware |
| @@ -1028,29 +963,80 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, | |||
| 1028 | */ | 963 | */ |
| 1029 | memset(iter_data, 0, sizeof(*iter_data)); | 964 | memset(iter_data, 0, sizeof(*iter_data)); |
| 1030 | memset(&iter_data->mask, 0xff, ETH_ALEN); | 965 | memset(&iter_data->mask, 0xff, ETH_ALEN); |
| 966 | iter_data->slottime = ATH9K_SLOT_TIME_9; | ||
| 967 | |||
| 968 | list_for_each_entry(avp, &ctx->vifs, list) | ||
| 969 | ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif); | ||
| 970 | |||
| 971 | if (ctx == &sc->offchannel.chan) { | ||
| 972 | struct ieee80211_vif *vif; | ||
| 973 | |||
| 974 | if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START) | ||
| 975 | vif = sc->offchannel.scan_vif; | ||
| 976 | else | ||
| 977 | vif = sc->offchannel.roc_vif; | ||
| 978 | |||
| 979 | if (vif) | ||
| 980 | ath9k_vif_iter(iter_data, vif->addr, vif); | ||
| 981 | iter_data->beacons = false; | ||
| 982 | } | ||
| 983 | } | ||
| 984 | |||
| 985 | static void ath9k_set_assoc_state(struct ath_softc *sc, | ||
| 986 | struct ieee80211_vif *vif, bool changed) | ||
| 987 | { | ||
| 988 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
| 989 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
| 990 | unsigned long flags; | ||
| 1031 | 991 | ||
| 1032 | if (vif) | 992 | set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); |
| 1033 | ath9k_vif_iter(iter_data, vif->addr, vif); | 993 | /* Set the AID, BSSID and do beacon-sync only when |
| 994 | * the HW opmode is STATION. | ||
| 995 | * | ||
| 996 | * But the primary bit is set above in any case. | ||
| 997 | */ | ||
| 998 | if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) | ||
| 999 | return; | ||
| 1000 | |||
| 1001 | ether_addr_copy(common->curbssid, bss_conf->bssid); | ||
| 1002 | common->curaid = bss_conf->aid; | ||
| 1003 | ath9k_hw_write_associd(sc->sc_ah); | ||
| 1034 | 1004 | ||
| 1035 | /* Get list of all active MAC addresses */ | 1005 | if (changed) { |
| 1036 | ieee80211_iterate_active_interfaces_atomic( | 1006 | common->last_rssi = ATH_RSSI_DUMMY_MARKER; |
| 1037 | sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | 1007 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; |
| 1038 | ath9k_vif_iter, iter_data); | ||
| 1039 | 1008 | ||
| 1040 | memcpy(common->macaddr, iter_data->hw_macaddr, ETH_ALEN); | 1009 | spin_lock_irqsave(&sc->sc_pm_lock, flags); |
| 1010 | sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; | ||
| 1011 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | if (ath9k_hw_mci_is_enabled(sc->sc_ah)) | ||
| 1015 | ath9k_mci_update_wlan_channels(sc, false); | ||
| 1016 | |||
| 1017 | ath_dbg(common, CONFIG, | ||
| 1018 | "Primary Station interface: %pM, BSSID: %pM\n", | ||
| 1019 | vif->addr, common->curbssid); | ||
| 1041 | } | 1020 | } |
| 1042 | 1021 | ||
| 1043 | /* Called with sc->mutex held. */ | 1022 | /* Called with sc->mutex held. */ |
| 1044 | static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, | 1023 | void ath9k_calculate_summary_state(struct ath_softc *sc, |
| 1045 | struct ieee80211_vif *vif) | 1024 | struct ath_chanctx *ctx) |
| 1046 | { | 1025 | { |
| 1047 | struct ath_softc *sc = hw->priv; | ||
| 1048 | struct ath_hw *ah = sc->sc_ah; | 1026 | struct ath_hw *ah = sc->sc_ah; |
| 1049 | struct ath_common *common = ath9k_hw_common(ah); | 1027 | struct ath_common *common = ath9k_hw_common(ah); |
| 1050 | struct ath9k_vif_iter_data iter_data; | 1028 | struct ath9k_vif_iter_data iter_data; |
| 1051 | enum nl80211_iftype old_opmode = ah->opmode; | ||
| 1052 | 1029 | ||
| 1053 | ath9k_calculate_iter_data(hw, vif, &iter_data); | 1030 | ath_chanctx_check_active(sc, ctx); |
| 1031 | |||
| 1032 | if (ctx != sc->cur_chan) | ||
| 1033 | return; | ||
| 1034 | |||
| 1035 | ath9k_ps_wakeup(sc); | ||
| 1036 | ath9k_calculate_iter_data(sc, ctx, &iter_data); | ||
| 1037 | |||
| 1038 | if (iter_data.has_hw_macaddr) | ||
| 1039 | ether_addr_copy(common->macaddr, iter_data.hw_macaddr); | ||
| 1054 | 1040 | ||
| 1055 | memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); | 1041 | memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); |
| 1056 | ath_hw_setbssidmask(common); | 1042 | ath_hw_setbssidmask(common); |
| @@ -1073,24 +1059,57 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, | |||
| 1073 | 1059 | ||
| 1074 | ath9k_hw_setopmode(ah); | 1060 | ath9k_hw_setopmode(ah); |
| 1075 | 1061 | ||
| 1062 | ctx->switch_after_beacon = false; | ||
| 1076 | if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) | 1063 | if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) |
| 1077 | ah->imask |= ATH9K_INT_TSFOOR; | 1064 | ah->imask |= ATH9K_INT_TSFOOR; |
| 1078 | else | 1065 | else { |
| 1079 | ah->imask &= ~ATH9K_INT_TSFOOR; | 1066 | ah->imask &= ~ATH9K_INT_TSFOOR; |
| 1067 | if (iter_data.naps == 1 && iter_data.beacons) | ||
| 1068 | ctx->switch_after_beacon = true; | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | ah->imask &= ~ATH9K_INT_SWBA; | ||
| 1072 | if (ah->opmode == NL80211_IFTYPE_STATION) { | ||
| 1073 | bool changed = (iter_data.primary_sta != ctx->primary_sta); | ||
| 1080 | 1074 | ||
| 1075 | iter_data.beacons = true; | ||
| 1076 | if (iter_data.primary_sta) { | ||
| 1077 | ath9k_set_assoc_state(sc, iter_data.primary_sta, | ||
| 1078 | changed); | ||
| 1079 | if (!ctx->primary_sta || | ||
| 1080 | !ctx->primary_sta->bss_conf.assoc) | ||
| 1081 | ctx->primary_sta = iter_data.primary_sta; | ||
| 1082 | } else { | ||
| 1083 | ctx->primary_sta = NULL; | ||
| 1084 | memset(common->curbssid, 0, ETH_ALEN); | ||
| 1085 | common->curaid = 0; | ||
| 1086 | ath9k_hw_write_associd(sc->sc_ah); | ||
| 1087 | if (ath9k_hw_mci_is_enabled(sc->sc_ah)) | ||
| 1088 | ath9k_mci_update_wlan_channels(sc, true); | ||
| 1089 | } | ||
| 1090 | } else if (iter_data.beacons) { | ||
| 1091 | ah->imask |= ATH9K_INT_SWBA; | ||
| 1092 | } | ||
| 1081 | ath9k_hw_set_interrupts(ah); | 1093 | ath9k_hw_set_interrupts(ah); |
| 1082 | 1094 | ||
| 1083 | /* | 1095 | if (iter_data.beacons) |
| 1084 | * If we are changing the opmode to STATION, | 1096 | set_bit(ATH_OP_BEACONS, &common->op_flags); |
| 1085 | * a beacon sync needs to be done. | 1097 | else |
| 1086 | */ | 1098 | clear_bit(ATH_OP_BEACONS, &common->op_flags); |
| 1087 | if (ah->opmode == NL80211_IFTYPE_STATION && | 1099 | |
| 1088 | old_opmode == NL80211_IFTYPE_AP && | 1100 | if (ah->slottime != iter_data.slottime) { |
| 1089 | test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { | 1101 | ah->slottime = iter_data.slottime; |
| 1090 | ieee80211_iterate_active_interfaces_atomic( | 1102 | ath9k_hw_init_global_settings(ah); |
| 1091 | sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | ||
| 1092 | ath9k_sta_vif_iter, sc); | ||
| 1093 | } | 1103 | } |
| 1104 | |||
| 1105 | if (iter_data.primary_sta) | ||
| 1106 | set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); | ||
| 1107 | else | ||
| 1108 | clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); | ||
| 1109 | |||
| 1110 | ctx->primary_sta = iter_data.primary_sta; | ||
| 1111 | |||
| 1112 | ath9k_ps_restore(sc); | ||
| 1094 | } | 1113 | } |
| 1095 | 1114 | ||
| 1096 | static int ath9k_add_interface(struct ieee80211_hw *hw, | 1115 | static int ath9k_add_interface(struct ieee80211_hw *hw, |
| @@ -1101,6 +1120,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
| 1101 | struct ath_common *common = ath9k_hw_common(ah); | 1120 | struct ath_common *common = ath9k_hw_common(ah); |
| 1102 | struct ath_vif *avp = (void *)vif->drv_priv; | 1121 | struct ath_vif *avp = (void *)vif->drv_priv; |
| 1103 | struct ath_node *an = &avp->mcast_node; | 1122 | struct ath_node *an = &avp->mcast_node; |
| 1123 | int i; | ||
| 1104 | 1124 | ||
| 1105 | mutex_lock(&sc->mutex); | 1125 | mutex_lock(&sc->mutex); |
| 1106 | 1126 | ||
| @@ -1115,14 +1135,20 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
| 1115 | ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type); | 1135 | ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type); |
| 1116 | sc->nvifs++; | 1136 | sc->nvifs++; |
| 1117 | 1137 | ||
| 1118 | ath9k_ps_wakeup(sc); | ||
| 1119 | ath9k_calculate_summary_state(hw, vif); | ||
| 1120 | ath9k_ps_restore(sc); | ||
| 1121 | |||
| 1122 | if (ath9k_uses_beacons(vif->type)) | 1138 | if (ath9k_uses_beacons(vif->type)) |
| 1123 | ath9k_beacon_assign_slot(sc, vif); | 1139 | ath9k_beacon_assign_slot(sc, vif); |
| 1124 | 1140 | ||
| 1125 | avp->vif = vif; | 1141 | avp->vif = vif; |
| 1142 | if (!ath9k_use_chanctx) { | ||
| 1143 | avp->chanctx = sc->cur_chan; | ||
| 1144 | list_add_tail(&avp->list, &avp->chanctx->vifs); | ||
| 1145 | } | ||
| 1146 | for (i = 0; i < IEEE80211_NUM_ACS; i++) | ||
| 1147 | vif->hw_queue[i] = i; | ||
| 1148 | if (vif->type == NL80211_IFTYPE_AP) | ||
| 1149 | vif->cab_queue = hw->queues - 2; | ||
| 1150 | else | ||
| 1151 | vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; | ||
| 1126 | 1152 | ||
| 1127 | an->sc = sc; | 1153 | an->sc = sc; |
| 1128 | an->sta = NULL; | 1154 | an->sta = NULL; |
| @@ -1141,6 +1167,8 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, | |||
| 1141 | { | 1167 | { |
| 1142 | struct ath_softc *sc = hw->priv; | 1168 | struct ath_softc *sc = hw->priv; |
| 1143 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1169 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 1170 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
| 1171 | int i; | ||
| 1144 | 1172 | ||
| 1145 | mutex_lock(&sc->mutex); | 1173 | mutex_lock(&sc->mutex); |
| 1146 | 1174 | ||
| @@ -1157,13 +1185,19 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, | |||
| 1157 | vif->type = new_type; | 1185 | vif->type = new_type; |
| 1158 | vif->p2p = p2p; | 1186 | vif->p2p = p2p; |
| 1159 | 1187 | ||
| 1160 | ath9k_ps_wakeup(sc); | ||
| 1161 | ath9k_calculate_summary_state(hw, vif); | ||
| 1162 | ath9k_ps_restore(sc); | ||
| 1163 | |||
| 1164 | if (ath9k_uses_beacons(vif->type)) | 1188 | if (ath9k_uses_beacons(vif->type)) |
| 1165 | ath9k_beacon_assign_slot(sc, vif); | 1189 | ath9k_beacon_assign_slot(sc, vif); |
| 1166 | 1190 | ||
| 1191 | for (i = 0; i < IEEE80211_NUM_ACS; i++) | ||
| 1192 | vif->hw_queue[i] = i; | ||
| 1193 | |||
| 1194 | if (vif->type == NL80211_IFTYPE_AP) | ||
| 1195 | vif->cab_queue = hw->queues - 2; | ||
| 1196 | else | ||
| 1197 | vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; | ||
| 1198 | |||
| 1199 | ath9k_calculate_summary_state(sc, avp->chanctx); | ||
| 1200 | |||
| 1167 | mutex_unlock(&sc->mutex); | 1201 | mutex_unlock(&sc->mutex); |
| 1168 | return 0; | 1202 | return 0; |
| 1169 | } | 1203 | } |
| @@ -1211,14 +1245,12 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, | |||
| 1211 | 1245 | ||
| 1212 | sc->nvifs--; | 1246 | sc->nvifs--; |
| 1213 | sc->tx99_vif = NULL; | 1247 | sc->tx99_vif = NULL; |
| 1248 | if (!ath9k_use_chanctx) | ||
| 1249 | list_del(&avp->list); | ||
| 1214 | 1250 | ||
| 1215 | if (ath9k_uses_beacons(vif->type)) | 1251 | if (ath9k_uses_beacons(vif->type)) |
| 1216 | ath9k_beacon_remove_slot(sc, vif); | 1252 | ath9k_beacon_remove_slot(sc, vif); |
| 1217 | 1253 | ||
| 1218 | ath9k_ps_wakeup(sc); | ||
| 1219 | ath9k_calculate_summary_state(hw, NULL); | ||
| 1220 | ath9k_ps_restore(sc); | ||
| 1221 | |||
| 1222 | ath_tx_node_cleanup(sc, &avp->mcast_node); | 1254 | ath_tx_node_cleanup(sc, &avp->mcast_node); |
| 1223 | 1255 | ||
| 1224 | mutex_unlock(&sc->mutex); | 1256 | mutex_unlock(&sc->mutex); |
| @@ -1345,7 +1377,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
| 1345 | struct ath_hw *ah = sc->sc_ah; | 1377 | struct ath_hw *ah = sc->sc_ah; |
| 1346 | struct ath_common *common = ath9k_hw_common(ah); | 1378 | struct ath_common *common = ath9k_hw_common(ah); |
| 1347 | struct ieee80211_conf *conf = &hw->conf; | 1379 | struct ieee80211_conf *conf = &hw->conf; |
| 1348 | bool reset_channel = false; | 1380 | struct ath_chanctx *ctx = sc->cur_chan; |
| 1349 | 1381 | ||
| 1350 | ath9k_ps_wakeup(sc); | 1382 | ath9k_ps_wakeup(sc); |
| 1351 | mutex_lock(&sc->mutex); | 1383 | mutex_lock(&sc->mutex); |
| @@ -1361,7 +1393,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
| 1361 | * The chip needs a reset to properly wake up from | 1393 | * The chip needs a reset to properly wake up from |
| 1362 | * full sleep | 1394 | * full sleep |
| 1363 | */ | 1395 | */ |
| 1364 | reset_channel = ah->chip_fullsleep; | 1396 | ath_chanctx_set_channel(sc, ctx, &ctx->chandef); |
| 1365 | } | 1397 | } |
| 1366 | } | 1398 | } |
| 1367 | 1399 | ||
| @@ -1391,20 +1423,16 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
| 1391 | } | 1423 | } |
| 1392 | } | 1424 | } |
| 1393 | 1425 | ||
| 1394 | if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) { | 1426 | if (!ath9k_use_chanctx && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { |
| 1395 | if (ath_set_channel(sc, &hw->conf.chandef) < 0) { | 1427 | ctx->offchannel = !!(conf->flags & IEEE80211_CONF_OFFCHANNEL); |
| 1396 | ath_err(common, "Unable to set channel\n"); | 1428 | ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef); |
| 1397 | mutex_unlock(&sc->mutex); | ||
| 1398 | ath9k_ps_restore(sc); | ||
| 1399 | return -EINVAL; | ||
| 1400 | } | ||
| 1401 | } | 1429 | } |
| 1402 | 1430 | ||
| 1403 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | 1431 | if (changed & IEEE80211_CONF_CHANGE_POWER) { |
| 1404 | ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level); | 1432 | ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level); |
| 1405 | sc->config.txpowlimit = 2 * conf->power_level; | 1433 | sc->cur_chan->txpower = 2 * conf->power_level; |
| 1406 | ath9k_cmn_update_txpow(ah, sc->curtxpow, | 1434 | ath9k_cmn_update_txpow(ah, sc->curtxpow, |
| 1407 | sc->config.txpowlimit, &sc->curtxpow); | 1435 | sc->cur_chan->txpower, &sc->curtxpow); |
| 1408 | } | 1436 | } |
| 1409 | 1437 | ||
| 1410 | mutex_unlock(&sc->mutex); | 1438 | mutex_unlock(&sc->mutex); |
| @@ -1659,58 +1687,6 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
| 1659 | return ret; | 1687 | return ret; |
| 1660 | } | 1688 | } |
| 1661 | 1689 | ||
| 1662 | static void ath9k_set_assoc_state(struct ath_softc *sc, | ||
| 1663 | struct ieee80211_vif *vif) | ||
| 1664 | { | ||
| 1665 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
| 1666 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
| 1667 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
| 1668 | unsigned long flags; | ||
| 1669 | |||
| 1670 | set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); | ||
| 1671 | avp->primary_sta_vif = true; | ||
| 1672 | |||
| 1673 | /* | ||
| 1674 | * Set the AID, BSSID and do beacon-sync only when | ||
| 1675 | * the HW opmode is STATION. | ||
| 1676 | * | ||
| 1677 | * But the primary bit is set above in any case. | ||
| 1678 | */ | ||
| 1679 | if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) | ||
| 1680 | return; | ||
| 1681 | |||
| 1682 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); | ||
| 1683 | common->curaid = bss_conf->aid; | ||
| 1684 | ath9k_hw_write_associd(sc->sc_ah); | ||
| 1685 | |||
| 1686 | common->last_rssi = ATH_RSSI_DUMMY_MARKER; | ||
| 1687 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; | ||
| 1688 | |||
| 1689 | spin_lock_irqsave(&sc->sc_pm_lock, flags); | ||
| 1690 | sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; | ||
| 1691 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | ||
| 1692 | |||
| 1693 | if (ath9k_hw_mci_is_enabled(sc->sc_ah)) | ||
| 1694 | ath9k_mci_update_wlan_channels(sc, false); | ||
| 1695 | |||
| 1696 | ath_dbg(common, CONFIG, | ||
| 1697 | "Primary Station interface: %pM, BSSID: %pM\n", | ||
| 1698 | vif->addr, common->curbssid); | ||
| 1699 | } | ||
| 1700 | |||
| 1701 | static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | ||
| 1702 | { | ||
| 1703 | struct ath_softc *sc = data; | ||
| 1704 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
| 1705 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
| 1706 | |||
| 1707 | if (test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) | ||
| 1708 | return; | ||
| 1709 | |||
| 1710 | if (bss_conf->assoc) | ||
| 1711 | ath9k_set_assoc_state(sc, vif); | ||
| 1712 | } | ||
| 1713 | |||
| 1714 | void ath9k_p2p_ps_timer(void *priv) | 1690 | void ath9k_p2p_ps_timer(void *priv) |
| 1715 | { | 1691 | { |
| 1716 | struct ath_softc *sc = priv; | 1692 | struct ath_softc *sc = priv; |
| @@ -1720,7 +1696,11 @@ void ath9k_p2p_ps_timer(void *priv) | |||
| 1720 | struct ath_node *an; | 1696 | struct ath_node *an; |
| 1721 | u32 tsf; | 1697 | u32 tsf; |
| 1722 | 1698 | ||
| 1723 | if (!avp) | 1699 | del_timer_sync(&sc->sched.timer); |
| 1700 | ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer); | ||
| 1701 | ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER); | ||
| 1702 | |||
| 1703 | if (!avp || avp->chanctx != sc->cur_chan) | ||
| 1724 | return; | 1704 | return; |
| 1725 | 1705 | ||
| 1726 | tsf = ath9k_hw_gettsf32(sc->sc_ah); | 1706 | tsf = ath9k_hw_gettsf32(sc->sc_ah); |
| @@ -1795,26 +1775,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | |||
| 1795 | ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n", | 1775 | ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n", |
| 1796 | bss_conf->bssid, bss_conf->assoc); | 1776 | bss_conf->bssid, bss_conf->assoc); |
| 1797 | 1777 | ||
| 1798 | if (avp->primary_sta_vif && !bss_conf->assoc) { | 1778 | ath9k_calculate_summary_state(sc, avp->chanctx); |
| 1799 | clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); | 1779 | if (bss_conf->assoc) |
| 1800 | avp->primary_sta_vif = false; | 1780 | ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_ASSOC); |
| 1801 | |||
| 1802 | if (ah->opmode == NL80211_IFTYPE_STATION) | ||
| 1803 | clear_bit(ATH_OP_BEACONS, &common->op_flags); | ||
| 1804 | } | ||
| 1805 | |||
| 1806 | ieee80211_iterate_active_interfaces_atomic( | ||
| 1807 | sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | ||
| 1808 | ath9k_bss_assoc_iter, sc); | ||
| 1809 | |||
| 1810 | if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags) && | ||
| 1811 | ah->opmode == NL80211_IFTYPE_STATION) { | ||
| 1812 | memset(common->curbssid, 0, ETH_ALEN); | ||
| 1813 | common->curaid = 0; | ||
| 1814 | ath9k_hw_write_associd(sc->sc_ah); | ||
| 1815 | if (ath9k_hw_mci_is_enabled(sc->sc_ah)) | ||
| 1816 | ath9k_mci_update_wlan_channels(sc, true); | ||
| 1817 | } | ||
| 1818 | } | 1781 | } |
| 1819 | 1782 | ||
| 1820 | if (changed & BSS_CHANGED_IBSS) { | 1783 | if (changed & BSS_CHANGED_IBSS) { |
| @@ -1824,10 +1787,15 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | |||
| 1824 | } | 1787 | } |
| 1825 | 1788 | ||
| 1826 | if ((changed & BSS_CHANGED_BEACON_ENABLED) || | 1789 | if ((changed & BSS_CHANGED_BEACON_ENABLED) || |
| 1827 | (changed & BSS_CHANGED_BEACON_INT)) | 1790 | (changed & BSS_CHANGED_BEACON_INT) || |
| 1791 | (changed & BSS_CHANGED_BEACON_INFO)) { | ||
| 1792 | if (changed & BSS_CHANGED_BEACON_ENABLED) | ||
| 1793 | ath9k_calculate_summary_state(sc, avp->chanctx); | ||
| 1828 | ath9k_beacon_config(sc, vif, changed); | 1794 | ath9k_beacon_config(sc, vif, changed); |
| 1795 | } | ||
| 1829 | 1796 | ||
| 1830 | if (changed & BSS_CHANGED_ERP_SLOT) { | 1797 | if ((avp->chanctx == sc->cur_chan) && |
| 1798 | (changed & BSS_CHANGED_ERP_SLOT)) { | ||
| 1831 | if (bss_conf->use_short_slot) | 1799 | if (bss_conf->use_short_slot) |
| 1832 | slottime = 9; | 1800 | slottime = 9; |
| 1833 | else | 1801 | else |
| @@ -2032,23 +2000,30 @@ static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
| 2032 | u32 queues, bool drop) | 2000 | u32 queues, bool drop) |
| 2033 | { | 2001 | { |
| 2034 | struct ath_softc *sc = hw->priv; | 2002 | struct ath_softc *sc = hw->priv; |
| 2003 | |||
| 2004 | mutex_lock(&sc->mutex); | ||
| 2005 | __ath9k_flush(hw, queues, drop); | ||
| 2006 | mutex_unlock(&sc->mutex); | ||
| 2007 | } | ||
| 2008 | |||
| 2009 | void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) | ||
| 2010 | { | ||
| 2011 | struct ath_softc *sc = hw->priv; | ||
| 2035 | struct ath_hw *ah = sc->sc_ah; | 2012 | struct ath_hw *ah = sc->sc_ah; |
| 2036 | struct ath_common *common = ath9k_hw_common(ah); | 2013 | struct ath_common *common = ath9k_hw_common(ah); |
| 2037 | int timeout = HZ / 5; /* 200 ms */ | 2014 | int timeout = HZ / 5; /* 200 ms */ |
| 2038 | bool drain_txq; | 2015 | bool drain_txq; |
| 2016 | int i; | ||
| 2039 | 2017 | ||
| 2040 | mutex_lock(&sc->mutex); | ||
| 2041 | cancel_delayed_work_sync(&sc->tx_complete_work); | 2018 | cancel_delayed_work_sync(&sc->tx_complete_work); |
| 2042 | 2019 | ||
| 2043 | if (ah->ah_flags & AH_UNPLUGGED) { | 2020 | if (ah->ah_flags & AH_UNPLUGGED) { |
| 2044 | ath_dbg(common, ANY, "Device has been unplugged!\n"); | 2021 | ath_dbg(common, ANY, "Device has been unplugged!\n"); |
| 2045 | mutex_unlock(&sc->mutex); | ||
| 2046 | return; | 2022 | return; |
| 2047 | } | 2023 | } |
| 2048 | 2024 | ||
| 2049 | if (test_bit(ATH_OP_INVALID, &common->op_flags)) { | 2025 | if (test_bit(ATH_OP_INVALID, &common->op_flags)) { |
| 2050 | ath_dbg(common, ANY, "Device not present\n"); | 2026 | ath_dbg(common, ANY, "Device not present\n"); |
| 2051 | mutex_unlock(&sc->mutex); | ||
| 2052 | return; | 2027 | return; |
| 2053 | } | 2028 | } |
| 2054 | 2029 | ||
| @@ -2066,11 +2041,13 @@ static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
| 2066 | ath_reset(sc); | 2041 | ath_reset(sc); |
| 2067 | 2042 | ||
| 2068 | ath9k_ps_restore(sc); | 2043 | ath9k_ps_restore(sc); |
| 2069 | ieee80211_wake_queues(hw); | 2044 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { |
| 2045 | ieee80211_wake_queue(sc->hw, | ||
| 2046 | sc->cur_chan->hw_queue_base + i); | ||
| 2047 | } | ||
| 2070 | } | 2048 | } |
| 2071 | 2049 | ||
| 2072 | ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); | 2050 | ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); |
| 2073 | mutex_unlock(&sc->mutex); | ||
| 2074 | } | 2051 | } |
| 2075 | 2052 | ||
| 2076 | static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) | 2053 | static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) |
| @@ -2230,6 +2207,403 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) | |||
| 2230 | clear_bit(ATH_OP_SCANNING, &common->op_flags); | 2207 | clear_bit(ATH_OP_SCANNING, &common->op_flags); |
| 2231 | } | 2208 | } |
| 2232 | 2209 | ||
| 2210 | static int ath_scan_channel_duration(struct ath_softc *sc, | ||
| 2211 | struct ieee80211_channel *chan) | ||
| 2212 | { | ||
| 2213 | struct cfg80211_scan_request *req = sc->offchannel.scan_req; | ||
| 2214 | |||
| 2215 | if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR)) | ||
| 2216 | return (HZ / 9); /* ~110 ms */ | ||
| 2217 | |||
| 2218 | return (HZ / 16); /* ~60 ms */ | ||
| 2219 | } | ||
| 2220 | |||
| 2221 | static void | ||
| 2222 | ath_scan_next_channel(struct ath_softc *sc) | ||
| 2223 | { | ||
| 2224 | struct cfg80211_scan_request *req = sc->offchannel.scan_req; | ||
| 2225 | struct ieee80211_channel *chan; | ||
| 2226 | |||
| 2227 | if (sc->offchannel.scan_idx >= req->n_channels) { | ||
| 2228 | sc->offchannel.state = ATH_OFFCHANNEL_IDLE; | ||
| 2229 | ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false), | ||
| 2230 | NULL); | ||
| 2231 | return; | ||
| 2232 | } | ||
| 2233 | |||
| 2234 | chan = req->channels[sc->offchannel.scan_idx++]; | ||
| 2235 | sc->offchannel.duration = ath_scan_channel_duration(sc, chan); | ||
| 2236 | sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND; | ||
| 2237 | ath_chanctx_offchan_switch(sc, chan); | ||
| 2238 | } | ||
| 2239 | |||
| 2240 | static void ath_offchannel_next(struct ath_softc *sc) | ||
| 2241 | { | ||
| 2242 | struct ieee80211_vif *vif; | ||
| 2243 | |||
| 2244 | if (sc->offchannel.scan_req) { | ||
| 2245 | vif = sc->offchannel.scan_vif; | ||
| 2246 | sc->offchannel.chan.txpower = vif->bss_conf.txpower; | ||
| 2247 | ath_scan_next_channel(sc); | ||
| 2248 | } else if (sc->offchannel.roc_vif) { | ||
| 2249 | vif = sc->offchannel.roc_vif; | ||
| 2250 | sc->offchannel.chan.txpower = vif->bss_conf.txpower; | ||
| 2251 | sc->offchannel.duration = sc->offchannel.roc_duration; | ||
| 2252 | sc->offchannel.state = ATH_OFFCHANNEL_ROC_START; | ||
| 2253 | ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan); | ||
| 2254 | } else { | ||
| 2255 | ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false), | ||
| 2256 | NULL); | ||
| 2257 | sc->offchannel.state = ATH_OFFCHANNEL_IDLE; | ||
| 2258 | if (sc->ps_idle) | ||
| 2259 | ath_cancel_work(sc); | ||
| 2260 | } | ||
| 2261 | } | ||
| 2262 | |||
| 2263 | static void ath_roc_complete(struct ath_softc *sc, bool abort) | ||
| 2264 | { | ||
| 2265 | sc->offchannel.roc_vif = NULL; | ||
| 2266 | sc->offchannel.roc_chan = NULL; | ||
| 2267 | if (!abort) | ||
| 2268 | ieee80211_remain_on_channel_expired(sc->hw); | ||
| 2269 | ath_offchannel_next(sc); | ||
| 2270 | ath9k_ps_restore(sc); | ||
| 2271 | } | ||
| 2272 | |||
| 2273 | static void ath_scan_complete(struct ath_softc *sc, bool abort) | ||
| 2274 | { | ||
| 2275 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
| 2276 | |||
| 2277 | sc->offchannel.scan_req = NULL; | ||
| 2278 | sc->offchannel.scan_vif = NULL; | ||
| 2279 | sc->offchannel.state = ATH_OFFCHANNEL_IDLE; | ||
| 2280 | ieee80211_scan_completed(sc->hw, abort); | ||
| 2281 | clear_bit(ATH_OP_SCANNING, &common->op_flags); | ||
| 2282 | ath_offchannel_next(sc); | ||
| 2283 | ath9k_ps_restore(sc); | ||
| 2284 | } | ||
| 2285 | |||
| 2286 | static void ath_scan_send_probe(struct ath_softc *sc, | ||
| 2287 | struct cfg80211_ssid *ssid) | ||
| 2288 | { | ||
| 2289 | struct cfg80211_scan_request *req = sc->offchannel.scan_req; | ||
| 2290 | struct ieee80211_vif *vif = sc->offchannel.scan_vif; | ||
| 2291 | struct ath_tx_control txctl = {}; | ||
| 2292 | struct sk_buff *skb; | ||
| 2293 | struct ieee80211_tx_info *info; | ||
| 2294 | int band = sc->offchannel.chan.chandef.chan->band; | ||
| 2295 | |||
| 2296 | skb = ieee80211_probereq_get(sc->hw, vif, | ||
| 2297 | ssid->ssid, ssid->ssid_len, req->ie_len); | ||
| 2298 | if (!skb) | ||
| 2299 | return; | ||
| 2300 | |||
| 2301 | info = IEEE80211_SKB_CB(skb); | ||
| 2302 | if (req->no_cck) | ||
| 2303 | info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE; | ||
| 2304 | |||
| 2305 | if (req->ie_len) | ||
| 2306 | memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len); | ||
| 2307 | |||
| 2308 | skb_set_queue_mapping(skb, IEEE80211_AC_VO); | ||
| 2309 | |||
| 2310 | if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL)) | ||
| 2311 | goto error; | ||
| 2312 | |||
| 2313 | txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; | ||
| 2314 | txctl.force_channel = true; | ||
| 2315 | if (ath_tx_start(sc->hw, skb, &txctl)) | ||
| 2316 | goto error; | ||
| 2317 | |||
| 2318 | return; | ||
| 2319 | |||
| 2320 | error: | ||
| 2321 | ieee80211_free_txskb(sc->hw, skb); | ||
| 2322 | } | ||
| 2323 | |||
| 2324 | static void ath_scan_channel_start(struct ath_softc *sc) | ||
| 2325 | { | ||
| 2326 | struct cfg80211_scan_request *req = sc->offchannel.scan_req; | ||
| 2327 | int i; | ||
| 2328 | |||
| 2329 | if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) && | ||
| 2330 | req->n_ssids) { | ||
| 2331 | for (i = 0; i < req->n_ssids; i++) | ||
| 2332 | ath_scan_send_probe(sc, &req->ssids[i]); | ||
| 2333 | |||
| 2334 | } | ||
| 2335 | |||
| 2336 | sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT; | ||
| 2337 | mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration); | ||
| 2338 | } | ||
| 2339 | |||
| 2340 | void ath_offchannel_channel_change(struct ath_softc *sc) | ||
| 2341 | { | ||
| 2342 | switch (sc->offchannel.state) { | ||
| 2343 | case ATH_OFFCHANNEL_PROBE_SEND: | ||
| 2344 | if (!sc->offchannel.scan_req) | ||
| 2345 | return; | ||
| 2346 | |||
| 2347 | if (sc->cur_chan->chandef.chan != | ||
| 2348 | sc->offchannel.chan.chandef.chan) | ||
| 2349 | return; | ||
| 2350 | |||
| 2351 | ath_scan_channel_start(sc); | ||
| 2352 | break; | ||
| 2353 | case ATH_OFFCHANNEL_IDLE: | ||
| 2354 | if (!sc->offchannel.scan_req) | ||
| 2355 | return; | ||
| 2356 | |||
| 2357 | ath_scan_complete(sc, false); | ||
| 2358 | break; | ||
| 2359 | case ATH_OFFCHANNEL_ROC_START: | ||
| 2360 | if (sc->cur_chan != &sc->offchannel.chan) | ||
| 2361 | break; | ||
| 2362 | |||
| 2363 | sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT; | ||
| 2364 | mod_timer(&sc->offchannel.timer, jiffies + | ||
| 2365 | msecs_to_jiffies(sc->offchannel.duration)); | ||
| 2366 | ieee80211_ready_on_channel(sc->hw); | ||
| 2367 | break; | ||
| 2368 | case ATH_OFFCHANNEL_ROC_DONE: | ||
| 2369 | ath_roc_complete(sc, false); | ||
| 2370 | break; | ||
| 2371 | default: | ||
| 2372 | break; | ||
| 2373 | } | ||
| 2374 | } | ||
| 2375 | |||
| 2376 | void ath_offchannel_timer(unsigned long data) | ||
| 2377 | { | ||
| 2378 | struct ath_softc *sc = (struct ath_softc *)data; | ||
| 2379 | struct ath_chanctx *ctx; | ||
| 2380 | |||
| 2381 | switch (sc->offchannel.state) { | ||
| 2382 | case ATH_OFFCHANNEL_PROBE_WAIT: | ||
| 2383 | if (!sc->offchannel.scan_req) | ||
| 2384 | return; | ||
| 2385 | |||
| 2386 | /* get first active channel context */ | ||
| 2387 | ctx = ath_chanctx_get_oper_chan(sc, true); | ||
| 2388 | if (ctx->active) { | ||
| 2389 | sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND; | ||
| 2390 | ath_chanctx_switch(sc, ctx, NULL); | ||
| 2391 | mod_timer(&sc->offchannel.timer, jiffies + HZ / 10); | ||
| 2392 | break; | ||
| 2393 | } | ||
| 2394 | /* fall through */ | ||
| 2395 | case ATH_OFFCHANNEL_SUSPEND: | ||
| 2396 | if (!sc->offchannel.scan_req) | ||
| 2397 | return; | ||
| 2398 | |||
| 2399 | ath_scan_next_channel(sc); | ||
| 2400 | break; | ||
| 2401 | case ATH_OFFCHANNEL_ROC_START: | ||
| 2402 | case ATH_OFFCHANNEL_ROC_WAIT: | ||
| 2403 | ctx = ath_chanctx_get_oper_chan(sc, false); | ||
| 2404 | sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE; | ||
| 2405 | ath_chanctx_switch(sc, ctx, NULL); | ||
| 2406 | break; | ||
| 2407 | default: | ||
| 2408 | break; | ||
| 2409 | } | ||
| 2410 | } | ||
| 2411 | |||
| 2412 | static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
| 2413 | struct ieee80211_scan_request *hw_req) | ||
| 2414 | { | ||
| 2415 | struct cfg80211_scan_request *req = &hw_req->req; | ||
| 2416 | struct ath_softc *sc = hw->priv; | ||
| 2417 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
| 2418 | int ret = 0; | ||
| 2419 | |||
| 2420 | mutex_lock(&sc->mutex); | ||
| 2421 | |||
| 2422 | if (WARN_ON(sc->offchannel.scan_req)) { | ||
| 2423 | ret = -EBUSY; | ||
| 2424 | goto out; | ||
| 2425 | } | ||
| 2426 | |||
| 2427 | ath9k_ps_wakeup(sc); | ||
| 2428 | set_bit(ATH_OP_SCANNING, &common->op_flags); | ||
| 2429 | sc->offchannel.scan_vif = vif; | ||
| 2430 | sc->offchannel.scan_req = req; | ||
| 2431 | sc->offchannel.scan_idx = 0; | ||
| 2432 | |||
| 2433 | if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) | ||
| 2434 | ath_offchannel_next(sc); | ||
| 2435 | |||
| 2436 | out: | ||
| 2437 | mutex_unlock(&sc->mutex); | ||
| 2438 | |||
| 2439 | return ret; | ||
| 2440 | } | ||
| 2441 | |||
| 2442 | static void ath9k_cancel_hw_scan(struct ieee80211_hw *hw, | ||
| 2443 | struct ieee80211_vif *vif) | ||
| 2444 | { | ||
| 2445 | struct ath_softc *sc = hw->priv; | ||
| 2446 | |||
| 2447 | mutex_lock(&sc->mutex); | ||
| 2448 | del_timer_sync(&sc->offchannel.timer); | ||
| 2449 | ath_scan_complete(sc, true); | ||
| 2450 | mutex_unlock(&sc->mutex); | ||
| 2451 | } | ||
| 2452 | |||
| 2453 | static int ath9k_remain_on_channel(struct ieee80211_hw *hw, | ||
| 2454 | struct ieee80211_vif *vif, | ||
| 2455 | struct ieee80211_channel *chan, int duration, | ||
| 2456 | enum ieee80211_roc_type type) | ||
| 2457 | { | ||
| 2458 | struct ath_softc *sc = hw->priv; | ||
| 2459 | int ret = 0; | ||
| 2460 | |||
| 2461 | mutex_lock(&sc->mutex); | ||
| 2462 | |||
| 2463 | if (WARN_ON(sc->offchannel.roc_vif)) { | ||
| 2464 | ret = -EBUSY; | ||
| 2465 | goto out; | ||
| 2466 | } | ||
| 2467 | |||
| 2468 | ath9k_ps_wakeup(sc); | ||
| 2469 | sc->offchannel.roc_vif = vif; | ||
| 2470 | sc->offchannel.roc_chan = chan; | ||
| 2471 | sc->offchannel.roc_duration = duration; | ||
| 2472 | |||
| 2473 | if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) | ||
| 2474 | ath_offchannel_next(sc); | ||
| 2475 | |||
| 2476 | out: | ||
| 2477 | mutex_unlock(&sc->mutex); | ||
| 2478 | |||
| 2479 | return ret; | ||
| 2480 | } | ||
| 2481 | |||
| 2482 | static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw) | ||
| 2483 | { | ||
| 2484 | struct ath_softc *sc = hw->priv; | ||
| 2485 | |||
| 2486 | mutex_lock(&sc->mutex); | ||
| 2487 | |||
| 2488 | del_timer_sync(&sc->offchannel.timer); | ||
| 2489 | |||
| 2490 | if (sc->offchannel.roc_vif) { | ||
| 2491 | if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START) | ||
| 2492 | ath_roc_complete(sc, true); | ||
| 2493 | } | ||
| 2494 | |||
| 2495 | mutex_unlock(&sc->mutex); | ||
| 2496 | |||
| 2497 | return 0; | ||
| 2498 | } | ||
| 2499 | |||
| 2500 | static int ath9k_add_chanctx(struct ieee80211_hw *hw, | ||
| 2501 | struct ieee80211_chanctx_conf *conf) | ||
| 2502 | { | ||
| 2503 | struct ath_softc *sc = hw->priv; | ||
| 2504 | struct ath_chanctx *ctx, **ptr; | ||
| 2505 | int pos; | ||
| 2506 | |||
| 2507 | mutex_lock(&sc->mutex); | ||
| 2508 | |||
| 2509 | ath_for_each_chanctx(sc, ctx) { | ||
| 2510 | if (ctx->assigned) | ||
| 2511 | continue; | ||
| 2512 | |||
| 2513 | ptr = (void *) conf->drv_priv; | ||
| 2514 | *ptr = ctx; | ||
| 2515 | ctx->assigned = true; | ||
| 2516 | pos = ctx - &sc->chanctx[0]; | ||
| 2517 | ctx->hw_queue_base = pos * IEEE80211_NUM_ACS; | ||
| 2518 | ath_chanctx_set_channel(sc, ctx, &conf->def); | ||
| 2519 | mutex_unlock(&sc->mutex); | ||
| 2520 | return 0; | ||
| 2521 | } | ||
| 2522 | mutex_unlock(&sc->mutex); | ||
| 2523 | return -ENOSPC; | ||
| 2524 | } | ||
| 2525 | |||
| 2526 | |||
| 2527 | static void ath9k_remove_chanctx(struct ieee80211_hw *hw, | ||
| 2528 | struct ieee80211_chanctx_conf *conf) | ||
| 2529 | { | ||
| 2530 | struct ath_softc *sc = hw->priv; | ||
| 2531 | struct ath_chanctx *ctx = ath_chanctx_get(conf); | ||
| 2532 | |||
| 2533 | mutex_lock(&sc->mutex); | ||
| 2534 | ctx->assigned = false; | ||
| 2535 | ctx->hw_queue_base = -1; | ||
| 2536 | ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN); | ||
| 2537 | mutex_unlock(&sc->mutex); | ||
| 2538 | } | ||
| 2539 | |||
| 2540 | static void ath9k_change_chanctx(struct ieee80211_hw *hw, | ||
| 2541 | struct ieee80211_chanctx_conf *conf, | ||
| 2542 | u32 changed) | ||
| 2543 | { | ||
| 2544 | struct ath_softc *sc = hw->priv; | ||
| 2545 | struct ath_chanctx *ctx = ath_chanctx_get(conf); | ||
| 2546 | |||
| 2547 | mutex_lock(&sc->mutex); | ||
| 2548 | ath_chanctx_set_channel(sc, ctx, &conf->def); | ||
| 2549 | mutex_unlock(&sc->mutex); | ||
| 2550 | } | ||
| 2551 | |||
| 2552 | static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, | ||
| 2553 | struct ieee80211_vif *vif, | ||
| 2554 | struct ieee80211_chanctx_conf *conf) | ||
| 2555 | { | ||
| 2556 | struct ath_softc *sc = hw->priv; | ||
| 2557 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
| 2558 | struct ath_chanctx *ctx = ath_chanctx_get(conf); | ||
| 2559 | int i; | ||
| 2560 | |||
| 2561 | mutex_lock(&sc->mutex); | ||
| 2562 | avp->chanctx = ctx; | ||
| 2563 | list_add_tail(&avp->list, &ctx->vifs); | ||
| 2564 | ath9k_calculate_summary_state(sc, ctx); | ||
| 2565 | for (i = 0; i < IEEE80211_NUM_ACS; i++) | ||
| 2566 | vif->hw_queue[i] = ctx->hw_queue_base + i; | ||
| 2567 | mutex_unlock(&sc->mutex); | ||
| 2568 | |||
| 2569 | return 0; | ||
| 2570 | } | ||
| 2571 | |||
| 2572 | static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, | ||
| 2573 | struct ieee80211_vif *vif, | ||
| 2574 | struct ieee80211_chanctx_conf *conf) | ||
| 2575 | { | ||
| 2576 | struct ath_softc *sc = hw->priv; | ||
| 2577 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
| 2578 | struct ath_chanctx *ctx = ath_chanctx_get(conf); | ||
| 2579 | int ac; | ||
| 2580 | |||
| 2581 | mutex_lock(&sc->mutex); | ||
| 2582 | avp->chanctx = NULL; | ||
| 2583 | list_del(&avp->list); | ||
| 2584 | ath9k_calculate_summary_state(sc, ctx); | ||
| 2585 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
| 2586 | vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE; | ||
| 2587 | mutex_unlock(&sc->mutex); | ||
| 2588 | } | ||
| 2589 | |||
| 2590 | void ath9k_fill_chanctx_ops(void) | ||
| 2591 | { | ||
| 2592 | if (!ath9k_use_chanctx) | ||
| 2593 | return; | ||
| 2594 | |||
| 2595 | ath9k_ops.hw_scan = ath9k_hw_scan; | ||
| 2596 | ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan; | ||
| 2597 | ath9k_ops.remain_on_channel = ath9k_remain_on_channel; | ||
| 2598 | ath9k_ops.cancel_remain_on_channel = ath9k_cancel_remain_on_channel; | ||
| 2599 | ath9k_ops.add_chanctx = ath9k_add_chanctx; | ||
| 2600 | ath9k_ops.remove_chanctx = ath9k_remove_chanctx; | ||
| 2601 | ath9k_ops.change_chanctx = ath9k_change_chanctx; | ||
| 2602 | ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx; | ||
| 2603 | ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx; | ||
| 2604 | ath9k_ops.mgd_prepare_tx = ath9k_chanctx_force_active; | ||
| 2605 | } | ||
| 2606 | |||
| 2233 | struct ieee80211_ops ath9k_ops = { | 2607 | struct ieee80211_ops ath9k_ops = { |
| 2234 | .tx = ath9k_tx, | 2608 | .tx = ath9k_tx, |
| 2235 | .start = ath9k_start, | 2609 | .start = ath9k_start, |
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index a0dbcc412384..3f7a11edb82a 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c | |||
| @@ -706,7 +706,7 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel, | |||
| 706 | return; | 706 | return; |
| 707 | 707 | ||
| 708 | if (setchannel) { | 708 | if (setchannel) { |
| 709 | struct ath9k_hw_cal_data *caldata = &sc->caldata; | 709 | struct ath9k_hw_cal_data *caldata = &sc->cur_chan->caldata; |
| 710 | if (IS_CHAN_HT40PLUS(ah->curchan) && | 710 | if (IS_CHAN_HT40PLUS(ah->curchan) && |
| 711 | (ah->curchan->channel > caldata->channel) && | 711 | (ah->curchan->channel > caldata->channel) && |
| 712 | (ah->curchan->channel <= caldata->channel + 20)) | 712 | (ah->curchan->channel <= caldata->channel + 20)) |
| @@ -720,7 +720,7 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel, | |||
| 720 | mci_hw->concur_tx = concur_tx; | 720 | mci_hw->concur_tx = concur_tx; |
| 721 | 721 | ||
| 722 | if (old_concur_tx != mci_hw->concur_tx) | 722 | if (old_concur_tx != mci_hw->concur_tx) |
| 723 | ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); | 723 | ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); |
| 724 | } | 724 | } |
| 725 | 725 | ||
| 726 | static void ath9k_mci_stomp_audio(struct ath_softc *sc) | 726 | static void ath9k_mci_stomp_audio(struct ath_softc *sc) |
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 4dec09e565ed..c018dea0b2e8 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c | |||
| @@ -23,7 +23,7 @@ | |||
| 23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
| 24 | #include "ath9k.h" | 24 | #include "ath9k.h" |
| 25 | 25 | ||
| 26 | static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { | 26 | static const struct pci_device_id ath_pci_id_table[] = { |
| 27 | { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ | 27 | { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ |
| 28 | { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ | 28 | { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ |
| 29 | { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ | 29 | { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ |
| @@ -843,6 +843,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 843 | return -ENODEV; | 843 | return -ENODEV; |
| 844 | } | 844 | } |
| 845 | 845 | ||
| 846 | ath9k_fill_chanctx_ops(); | ||
| 846 | hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); | 847 | hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); |
| 847 | if (!hw) { | 848 | if (!hw) { |
| 848 | dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); | 849 | dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 9105a92364f7..74ab1d02013b 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
| @@ -259,7 +259,7 @@ static void ath_edma_start_recv(struct ath_softc *sc) | |||
| 259 | ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP); | 259 | ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP); |
| 260 | ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP); | 260 | ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP); |
| 261 | ath_opmode_init(sc); | 261 | ath_opmode_init(sc); |
| 262 | ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)); | 262 | ath9k_hw_startpcureceive(sc->sc_ah, sc->cur_chan->offchannel); |
| 263 | } | 263 | } |
| 264 | 264 | ||
| 265 | static void ath_edma_stop_recv(struct ath_softc *sc) | 265 | static void ath_edma_stop_recv(struct ath_softc *sc) |
| @@ -374,6 +374,7 @@ void ath_rx_cleanup(struct ath_softc *sc) | |||
| 374 | 374 | ||
| 375 | u32 ath_calcrxfilter(struct ath_softc *sc) | 375 | u32 ath_calcrxfilter(struct ath_softc *sc) |
| 376 | { | 376 | { |
| 377 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
| 377 | u32 rfilt; | 378 | u32 rfilt; |
| 378 | 379 | ||
| 379 | if (config_enabled(CONFIG_ATH9K_TX99)) | 380 | if (config_enabled(CONFIG_ATH9K_TX99)) |
| @@ -424,6 +425,10 @@ u32 ath_calcrxfilter(struct ath_softc *sc) | |||
| 424 | if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah)) | 425 | if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah)) |
| 425 | rfilt |= ATH9K_RX_FILTER_4ADDRESS; | 426 | rfilt |= ATH9K_RX_FILTER_4ADDRESS; |
| 426 | 427 | ||
| 428 | if (ath9k_use_chanctx && | ||
| 429 | test_bit(ATH_OP_SCANNING, &common->op_flags)) | ||
| 430 | rfilt |= ATH9K_RX_FILTER_BEACON; | ||
| 431 | |||
| 427 | return rfilt; | 432 | return rfilt; |
| 428 | 433 | ||
| 429 | } | 434 | } |
| @@ -457,7 +462,7 @@ int ath_startrecv(struct ath_softc *sc) | |||
| 457 | 462 | ||
| 458 | start_recv: | 463 | start_recv: |
| 459 | ath_opmode_init(sc); | 464 | ath_opmode_init(sc); |
| 460 | ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)); | 465 | ath9k_hw_startpcureceive(ah, sc->cur_chan->offchannel); |
| 461 | 466 | ||
| 462 | return 0; | 467 | return 0; |
| 463 | } | 468 | } |
| @@ -540,7 +545,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) | |||
| 540 | sc->ps_flags &= ~PS_BEACON_SYNC; | 545 | sc->ps_flags &= ~PS_BEACON_SYNC; |
| 541 | ath_dbg(common, PS, | 546 | ath_dbg(common, PS, |
| 542 | "Reconfigure beacon timers based on synchronized timestamp\n"); | 547 | "Reconfigure beacon timers based on synchronized timestamp\n"); |
| 543 | if (!(WARN_ON_ONCE(sc->cur_beacon_conf.beacon_interval == 0))) | 548 | if (!(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0))) |
| 544 | ath9k_set_beacon(sc); | 549 | ath9k_set_beacon(sc); |
| 545 | if (sc->p2p_ps_vif) | 550 | if (sc->p2p_ps_vif) |
| 546 | ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif); | 551 | ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif); |
| @@ -887,6 +892,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, | |||
| 887 | return -EINVAL; | 892 | return -EINVAL; |
| 888 | } | 893 | } |
| 889 | 894 | ||
| 895 | if (rx_stats->is_mybeacon) { | ||
| 896 | sc->sched.next_tbtt = rx_stats->rs_tstamp; | ||
| 897 | ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_BEACON_RECEIVED); | ||
| 898 | } | ||
| 899 | |||
| 890 | ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); | 900 | ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); |
| 891 | 901 | ||
| 892 | rx_status->band = ah->curchan->chan->band; | 902 | rx_status->band = ah->curchan->chan->band; |
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index f1bbce3f7774..a1499700bcf2 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h | |||
| @@ -813,6 +813,7 @@ | |||
| 813 | #define AR_SREV_VERSION_9531 0x500 | 813 | #define AR_SREV_VERSION_9531 0x500 |
| 814 | #define AR_SREV_REVISION_9531_10 0 | 814 | #define AR_SREV_REVISION_9531_10 0 |
| 815 | #define AR_SREV_REVISION_9531_11 1 | 815 | #define AR_SREV_REVISION_9531_11 1 |
| 816 | #define AR_SREV_REVISION_9531_20 2 | ||
| 816 | 817 | ||
| 817 | #define AR_SREV_5416(_ah) \ | 818 | #define AR_SREV_5416(_ah) \ |
| 818 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ | 819 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ |
| @@ -958,6 +959,9 @@ | |||
| 958 | #define AR_SREV_9531_11(_ah) \ | 959 | #define AR_SREV_9531_11(_ah) \ |
| 959 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ | 960 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ |
| 960 | ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_11)) | 961 | ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_11)) |
| 962 | #define AR_SREV_9531_20(_ah) \ | ||
| 963 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ | ||
| 964 | ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_20)) | ||
| 961 | 965 | ||
| 962 | /* NOTE: When adding chips newer than Peacock, add chip check here */ | 966 | /* NOTE: When adding chips newer than Peacock, add chip check here */ |
| 963 | #define AR_SREV_9580_10_OR_LATER(_ah) \ | 967 | #define AR_SREV_9580_10_OR_LATER(_ah) \ |
diff --git a/drivers/net/wireless/ath/ath9k/spectral.c b/drivers/net/wireless/ath/ath9k/spectral.c index 99f4de95c264..5fe29b9f8fa2 100644 --- a/drivers/net/wireless/ath/ath9k/spectral.c +++ b/drivers/net/wireless/ath/ath9k/spectral.c | |||
| @@ -313,7 +313,7 @@ static ssize_t write_file_spectral_short_repeat(struct file *file, | |||
| 313 | if (kstrtoul(buf, 0, &val)) | 313 | if (kstrtoul(buf, 0, &val)) |
| 314 | return -EINVAL; | 314 | return -EINVAL; |
| 315 | 315 | ||
| 316 | if (val < 0 || val > 1) | 316 | if (val > 1) |
| 317 | return -EINVAL; | 317 | return -EINVAL; |
| 318 | 318 | ||
| 319 | sc->spec_config.short_repeat = val; | 319 | sc->spec_config.short_repeat = val; |
| @@ -361,7 +361,7 @@ static ssize_t write_file_spectral_count(struct file *file, | |||
| 361 | if (kstrtoul(buf, 0, &val)) | 361 | if (kstrtoul(buf, 0, &val)) |
| 362 | return -EINVAL; | 362 | return -EINVAL; |
| 363 | 363 | ||
| 364 | if (val < 0 || val > 255) | 364 | if (val > 255) |
| 365 | return -EINVAL; | 365 | return -EINVAL; |
| 366 | 366 | ||
| 367 | sc->spec_config.count = val; | 367 | sc->spec_config.count = val; |
| @@ -409,7 +409,7 @@ static ssize_t write_file_spectral_period(struct file *file, | |||
| 409 | if (kstrtoul(buf, 0, &val)) | 409 | if (kstrtoul(buf, 0, &val)) |
| 410 | return -EINVAL; | 410 | return -EINVAL; |
| 411 | 411 | ||
| 412 | if (val < 0 || val > 255) | 412 | if (val > 255) |
| 413 | return -EINVAL; | 413 | return -EINVAL; |
| 414 | 414 | ||
| 415 | sc->spec_config.period = val; | 415 | sc->spec_config.period = val; |
| @@ -457,7 +457,7 @@ static ssize_t write_file_spectral_fft_period(struct file *file, | |||
| 457 | if (kstrtoul(buf, 0, &val)) | 457 | if (kstrtoul(buf, 0, &val)) |
| 458 | return -EINVAL; | 458 | return -EINVAL; |
| 459 | 459 | ||
| 460 | if (val < 0 || val > 15) | 460 | if (val > 15) |
| 461 | return -EINVAL; | 461 | return -EINVAL; |
| 462 | 462 | ||
| 463 | sc->spec_config.fft_period = val; | 463 | sc->spec_config.fft_period = val; |
diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index a65cfb91adca..23972924c774 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c | |||
| @@ -76,7 +76,7 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) | |||
| 76 | tx_info = IEEE80211_SKB_CB(skb); | 76 | tx_info = IEEE80211_SKB_CB(skb); |
| 77 | memset(tx_info, 0, sizeof(*tx_info)); | 77 | memset(tx_info, 0, sizeof(*tx_info)); |
| 78 | rate = &tx_info->control.rates[0]; | 78 | rate = &tx_info->control.rates[0]; |
| 79 | tx_info->band = hw->conf.chandef.chan->band; | 79 | tx_info->band = sc->cur_chan->chandef.chan->band; |
| 80 | tx_info->flags = IEEE80211_TX_CTL_NO_ACK; | 80 | tx_info->flags = IEEE80211_TX_CTL_NO_ACK; |
| 81 | tx_info->control.vif = sc->tx99_vif; | 81 | tx_info->control.vif = sc->tx99_vif; |
| 82 | rate->count = 1; | 82 | rate->count = 1; |
diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 2879887f5691..a4f4f0da81f6 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c | |||
| @@ -193,6 +193,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, | |||
| 193 | u32 wow_triggers_enabled = 0; | 193 | u32 wow_triggers_enabled = 0; |
| 194 | int ret = 0; | 194 | int ret = 0; |
| 195 | 195 | ||
| 196 | cancel_work_sync(&sc->chanctx_work); | ||
| 196 | mutex_lock(&sc->mutex); | 197 | mutex_lock(&sc->mutex); |
| 197 | 198 | ||
| 198 | ath_cancel_work(sc); | 199 | ath_cancel_work(sc); |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 66acb2cbd9df..704fcbcbe20b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
| @@ -103,9 +103,16 @@ void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) | |||
| 103 | ieee80211_tx_status(sc->hw, skb); | 103 | ieee80211_tx_status(sc->hw, skb); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) | 106 | static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq, |
| 107 | struct ath_atx_tid *tid) | ||
| 107 | { | 108 | { |
| 108 | struct ath_atx_ac *ac = tid->ac; | 109 | struct ath_atx_ac *ac = tid->ac; |
| 110 | struct list_head *list; | ||
| 111 | struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv; | ||
| 112 | struct ath_chanctx *ctx = avp->chanctx; | ||
| 113 | |||
| 114 | if (!ctx) | ||
| 115 | return; | ||
| 109 | 116 | ||
| 110 | if (tid->sched) | 117 | if (tid->sched) |
| 111 | return; | 118 | return; |
| @@ -117,7 +124,9 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) | |||
| 117 | return; | 124 | return; |
| 118 | 125 | ||
| 119 | ac->sched = true; | 126 | ac->sched = true; |
| 120 | list_add_tail(&ac->list, &txq->axq_acq); | 127 | |
| 128 | list = &ctx->acq[TID_TO_WME_AC(tid->tidno)]; | ||
| 129 | list_add_tail(&ac->list, list); | ||
| 121 | } | 130 | } |
| 122 | 131 | ||
| 123 | static struct ath_frame_info *get_frame_info(struct sk_buff *skb) | 132 | static struct ath_frame_info *get_frame_info(struct sk_buff *skb) |
| @@ -147,21 +156,22 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta, | |||
| 147 | static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, | 156 | static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, |
| 148 | struct sk_buff *skb) | 157 | struct sk_buff *skb) |
| 149 | { | 158 | { |
| 150 | int q; | 159 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 151 | 160 | struct ath_frame_info *fi = get_frame_info(skb); | |
| 152 | q = skb_get_queue_mapping(skb); | 161 | int hw_queue; |
| 153 | if (txq == sc->tx.uapsdq) | 162 | int q = fi->txq; |
| 154 | txq = sc->tx.txq_map[q]; | ||
| 155 | 163 | ||
| 156 | if (txq != sc->tx.txq_map[q]) | 164 | if (q < 0) |
| 157 | return; | 165 | return; |
| 158 | 166 | ||
| 167 | txq = sc->tx.txq_map[q]; | ||
| 159 | if (WARN_ON(--txq->pending_frames < 0)) | 168 | if (WARN_ON(--txq->pending_frames < 0)) |
| 160 | txq->pending_frames = 0; | 169 | txq->pending_frames = 0; |
| 161 | 170 | ||
| 171 | hw_queue = (info->hw_queue >= sc->hw->queues - 2) ? q : info->hw_queue; | ||
| 162 | if (txq->stopped && | 172 | if (txq->stopped && |
| 163 | txq->pending_frames < sc->tx.txq_max_pending[q]) { | 173 | txq->pending_frames < sc->tx.txq_max_pending[q]) { |
| 164 | ieee80211_wake_queue(sc->hw, q); | 174 | ieee80211_wake_queue(sc->hw, hw_queue); |
| 165 | txq->stopped = false; | 175 | txq->stopped = false; |
| 166 | } | 176 | } |
| 167 | } | 177 | } |
| @@ -626,7 +636,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
| 626 | 636 | ||
| 627 | skb_queue_splice_tail(&bf_pending, &tid->retry_q); | 637 | skb_queue_splice_tail(&bf_pending, &tid->retry_q); |
| 628 | if (!an->sleeping) { | 638 | if (!an->sleeping) { |
| 629 | ath_tx_queue_tid(txq, tid); | 639 | ath_tx_queue_tid(sc, txq, tid); |
| 630 | 640 | ||
| 631 | if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) | 641 | if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) |
| 632 | tid->ac->clear_ps_filter = true; | 642 | tid->ac->clear_ps_filter = true; |
| @@ -887,6 +897,15 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, | |||
| 887 | 897 | ||
| 888 | tx_info = IEEE80211_SKB_CB(skb); | 898 | tx_info = IEEE80211_SKB_CB(skb); |
| 889 | tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT; | 899 | tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT; |
| 900 | |||
| 901 | /* | ||
| 902 | * No aggregation session is running, but there may be frames | ||
| 903 | * from a previous session or a failed attempt in the queue. | ||
| 904 | * Send them out as normal data frames | ||
| 905 | */ | ||
| 906 | if (!tid->active) | ||
| 907 | tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU; | ||
| 908 | |||
| 890 | if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) { | 909 | if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) { |
| 891 | bf->bf_state.bf_type = 0; | 910 | bf->bf_state.bf_type = 0; |
| 892 | return bf; | 911 | return bf; |
| @@ -1483,7 +1502,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) | |||
| 1483 | ac->clear_ps_filter = true; | 1502 | ac->clear_ps_filter = true; |
| 1484 | 1503 | ||
| 1485 | if (ath_tid_has_buffered(tid)) { | 1504 | if (ath_tid_has_buffered(tid)) { |
| 1486 | ath_tx_queue_tid(txq, tid); | 1505 | ath_tx_queue_tid(sc, txq, tid); |
| 1487 | ath_txq_schedule(sc, txq); | 1506 | ath_txq_schedule(sc, txq); |
| 1488 | } | 1507 | } |
| 1489 | 1508 | ||
| @@ -1507,7 +1526,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, | |||
| 1507 | tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; | 1526 | tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; |
| 1508 | 1527 | ||
| 1509 | if (ath_tid_has_buffered(tid)) { | 1528 | if (ath_tid_has_buffered(tid)) { |
| 1510 | ath_tx_queue_tid(txq, tid); | 1529 | ath_tx_queue_tid(sc, txq, tid); |
| 1511 | ath_txq_schedule(sc, txq); | 1530 | ath_txq_schedule(sc, txq); |
| 1512 | } | 1531 | } |
| 1513 | 1532 | ||
| @@ -1642,7 +1661,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) | |||
| 1642 | txq->axq_link = NULL; | 1661 | txq->axq_link = NULL; |
| 1643 | __skb_queue_head_init(&txq->complete_q); | 1662 | __skb_queue_head_init(&txq->complete_q); |
| 1644 | INIT_LIST_HEAD(&txq->axq_q); | 1663 | INIT_LIST_HEAD(&txq->axq_q); |
| 1645 | INIT_LIST_HEAD(&txq->axq_acq); | ||
| 1646 | spin_lock_init(&txq->axq_lock); | 1664 | spin_lock_init(&txq->axq_lock); |
| 1647 | txq->axq_depth = 0; | 1665 | txq->axq_depth = 0; |
| 1648 | txq->axq_ampdu_depth = 0; | 1666 | txq->axq_ampdu_depth = 0; |
| @@ -1686,7 +1704,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum, | |||
| 1686 | int ath_cabq_update(struct ath_softc *sc) | 1704 | int ath_cabq_update(struct ath_softc *sc) |
| 1687 | { | 1705 | { |
| 1688 | struct ath9k_tx_queue_info qi; | 1706 | struct ath9k_tx_queue_info qi; |
| 1689 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | 1707 | struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; |
| 1690 | int qnum = sc->beacon.cabq->axq_qnum; | 1708 | int qnum = sc->beacon.cabq->axq_qnum; |
| 1691 | 1709 | ||
| 1692 | ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); | 1710 | ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); |
| @@ -1804,7 +1822,7 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) | |||
| 1804 | sc->tx.txqsetup &= ~(1<<txq->axq_qnum); | 1822 | sc->tx.txqsetup &= ~(1<<txq->axq_qnum); |
| 1805 | } | 1823 | } |
| 1806 | 1824 | ||
| 1807 | /* For each axq_acq entry, for each tid, try to schedule packets | 1825 | /* For each acq entry, for each tid, try to schedule packets |
| 1808 | * for transmit until ampdu_depth has reached min Q depth. | 1826 | * for transmit until ampdu_depth has reached min Q depth. |
| 1809 | */ | 1827 | */ |
| 1810 | void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) | 1828 | void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) |
| @@ -1812,19 +1830,31 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) | |||
| 1812 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1830 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 1813 | struct ath_atx_ac *ac, *last_ac; | 1831 | struct ath_atx_ac *ac, *last_ac; |
| 1814 | struct ath_atx_tid *tid, *last_tid; | 1832 | struct ath_atx_tid *tid, *last_tid; |
| 1833 | struct list_head *ac_list; | ||
| 1815 | bool sent = false; | 1834 | bool sent = false; |
| 1816 | 1835 | ||
| 1836 | if (txq->mac80211_qnum < 0) | ||
| 1837 | return; | ||
| 1838 | |||
| 1839 | spin_lock_bh(&sc->chan_lock); | ||
| 1840 | ac_list = &sc->cur_chan->acq[txq->mac80211_qnum]; | ||
| 1841 | spin_unlock_bh(&sc->chan_lock); | ||
| 1842 | |||
| 1817 | if (test_bit(ATH_OP_HW_RESET, &common->op_flags) || | 1843 | if (test_bit(ATH_OP_HW_RESET, &common->op_flags) || |
| 1818 | list_empty(&txq->axq_acq)) | 1844 | list_empty(ac_list)) |
| 1819 | return; | 1845 | return; |
| 1820 | 1846 | ||
| 1847 | spin_lock_bh(&sc->chan_lock); | ||
| 1821 | rcu_read_lock(); | 1848 | rcu_read_lock(); |
| 1822 | 1849 | ||
| 1823 | last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list); | 1850 | last_ac = list_entry(ac_list->prev, struct ath_atx_ac, list); |
| 1824 | while (!list_empty(&txq->axq_acq)) { | 1851 | while (!list_empty(ac_list)) { |
| 1825 | bool stop = false; | 1852 | bool stop = false; |
| 1826 | 1853 | ||
| 1827 | ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); | 1854 | if (sc->cur_chan->stopped) |
| 1855 | break; | ||
| 1856 | |||
| 1857 | ac = list_first_entry(ac_list, struct ath_atx_ac, list); | ||
| 1828 | last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list); | 1858 | last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list); |
| 1829 | list_del(&ac->list); | 1859 | list_del(&ac->list); |
| 1830 | ac->sched = false; | 1860 | ac->sched = false; |
| @@ -1844,7 +1874,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) | |||
| 1844 | * are pending for the tid | 1874 | * are pending for the tid |
| 1845 | */ | 1875 | */ |
| 1846 | if (ath_tid_has_buffered(tid)) | 1876 | if (ath_tid_has_buffered(tid)) |
| 1847 | ath_tx_queue_tid(txq, tid); | 1877 | ath_tx_queue_tid(sc, txq, tid); |
| 1848 | 1878 | ||
| 1849 | if (stop || tid == last_tid) | 1879 | if (stop || tid == last_tid) |
| 1850 | break; | 1880 | break; |
| @@ -1852,7 +1882,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) | |||
| 1852 | 1882 | ||
| 1853 | if (!list_empty(&ac->tid_q) && !ac->sched) { | 1883 | if (!list_empty(&ac->tid_q) && !ac->sched) { |
| 1854 | ac->sched = true; | 1884 | ac->sched = true; |
| 1855 | list_add_tail(&ac->list, &txq->axq_acq); | 1885 | list_add_tail(&ac->list, ac_list); |
| 1856 | } | 1886 | } |
| 1857 | 1887 | ||
| 1858 | if (stop) | 1888 | if (stop) |
| @@ -1863,12 +1893,27 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) | |||
| 1863 | break; | 1893 | break; |
| 1864 | 1894 | ||
| 1865 | sent = false; | 1895 | sent = false; |
| 1866 | last_ac = list_entry(txq->axq_acq.prev, | 1896 | last_ac = list_entry(ac_list->prev, |
| 1867 | struct ath_atx_ac, list); | 1897 | struct ath_atx_ac, list); |
| 1868 | } | 1898 | } |
| 1869 | } | 1899 | } |
| 1870 | 1900 | ||
| 1871 | rcu_read_unlock(); | 1901 | rcu_read_unlock(); |
| 1902 | spin_unlock_bh(&sc->chan_lock); | ||
| 1903 | } | ||
| 1904 | |||
| 1905 | void ath_txq_schedule_all(struct ath_softc *sc) | ||
| 1906 | { | ||
| 1907 | struct ath_txq *txq; | ||
| 1908 | int i; | ||
| 1909 | |||
| 1910 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { | ||
| 1911 | txq = sc->tx.txq_map[i]; | ||
| 1912 | |||
| 1913 | spin_lock_bh(&txq->axq_lock); | ||
| 1914 | ath_txq_schedule(sc, txq); | ||
| 1915 | spin_unlock_bh(&txq->axq_lock); | ||
| 1916 | } | ||
| 1872 | } | 1917 | } |
| 1873 | 1918 | ||
| 1874 | /***********/ | 1919 | /***********/ |
| @@ -1999,6 +2044,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, | |||
| 1999 | an = (struct ath_node *) sta->drv_priv; | 2044 | an = (struct ath_node *) sta->drv_priv; |
| 2000 | 2045 | ||
| 2001 | memset(fi, 0, sizeof(*fi)); | 2046 | memset(fi, 0, sizeof(*fi)); |
| 2047 | fi->txq = -1; | ||
| 2002 | if (hw_key) | 2048 | if (hw_key) |
| 2003 | fi->keyix = hw_key->hw_key_idx; | 2049 | fi->keyix = hw_key->hw_key_idx; |
| 2004 | else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0) | 2050 | else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0) |
| @@ -2150,13 +2196,22 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
| 2150 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 2196 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 2151 | struct ieee80211_sta *sta = txctl->sta; | 2197 | struct ieee80211_sta *sta = txctl->sta; |
| 2152 | struct ieee80211_vif *vif = info->control.vif; | 2198 | struct ieee80211_vif *vif = info->control.vif; |
| 2199 | struct ath_frame_info *fi = get_frame_info(skb); | ||
| 2200 | struct ath_vif *avp = NULL; | ||
| 2153 | struct ath_softc *sc = hw->priv; | 2201 | struct ath_softc *sc = hw->priv; |
| 2154 | struct ath_txq *txq = txctl->txq; | 2202 | struct ath_txq *txq = txctl->txq; |
| 2155 | struct ath_atx_tid *tid = NULL; | 2203 | struct ath_atx_tid *tid = NULL; |
| 2156 | struct ath_buf *bf; | 2204 | struct ath_buf *bf; |
| 2157 | int q; | 2205 | bool queue; |
| 2206 | int q, hw_queue; | ||
| 2158 | int ret; | 2207 | int ret; |
| 2159 | 2208 | ||
| 2209 | if (vif) | ||
| 2210 | avp = (void *)vif->drv_priv; | ||
| 2211 | |||
| 2212 | if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) | ||
| 2213 | txctl->force_channel = true; | ||
| 2214 | |||
| 2160 | ret = ath_tx_prepare(hw, skb, txctl); | 2215 | ret = ath_tx_prepare(hw, skb, txctl); |
| 2161 | if (ret) | 2216 | if (ret) |
| 2162 | return ret; | 2217 | return ret; |
| @@ -2168,24 +2223,41 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
| 2168 | */ | 2223 | */ |
| 2169 | 2224 | ||
| 2170 | q = skb_get_queue_mapping(skb); | 2225 | q = skb_get_queue_mapping(skb); |
| 2226 | hw_queue = (info->hw_queue >= sc->hw->queues - 2) ? q : info->hw_queue; | ||
| 2171 | 2227 | ||
| 2172 | ath_txq_lock(sc, txq); | 2228 | ath_txq_lock(sc, txq); |
| 2173 | if (txq == sc->tx.txq_map[q] && | 2229 | if (txq == sc->tx.txq_map[q]) { |
| 2174 | ++txq->pending_frames > sc->tx.txq_max_pending[q] && | 2230 | fi->txq = q; |
| 2175 | !txq->stopped) { | 2231 | if (++txq->pending_frames > sc->tx.txq_max_pending[q] && |
| 2176 | ieee80211_stop_queue(sc->hw, q); | 2232 | !txq->stopped) { |
| 2177 | txq->stopped = true; | 2233 | ieee80211_stop_queue(sc->hw, hw_queue); |
| 2234 | txq->stopped = true; | ||
| 2235 | } | ||
| 2236 | } | ||
| 2237 | |||
| 2238 | queue = ieee80211_is_data_present(hdr->frame_control); | ||
| 2239 | |||
| 2240 | /* Force queueing of all frames that belong to a virtual interface on | ||
| 2241 | * a different channel context, to ensure that they are sent on the | ||
| 2242 | * correct channel. | ||
| 2243 | */ | ||
| 2244 | if (((avp && avp->chanctx != sc->cur_chan) || | ||
| 2245 | sc->cur_chan->stopped) && !txctl->force_channel) { | ||
| 2246 | if (!txctl->an) | ||
| 2247 | txctl->an = &avp->mcast_node; | ||
| 2248 | info->flags &= ~IEEE80211_TX_CTL_PS_RESPONSE; | ||
| 2249 | queue = true; | ||
| 2178 | } | 2250 | } |
| 2179 | 2251 | ||
| 2180 | if (txctl->an && ieee80211_is_data_present(hdr->frame_control)) | 2252 | if (txctl->an && queue) |
| 2181 | tid = ath_get_skb_tid(sc, txctl->an, skb); | 2253 | tid = ath_get_skb_tid(sc, txctl->an, skb); |
| 2182 | 2254 | ||
| 2183 | if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) { | 2255 | if (info->flags & (IEEE80211_TX_CTL_PS_RESPONSE | |
| 2256 | IEEE80211_TX_CTL_TX_OFFCHAN)) { | ||
| 2184 | ath_txq_unlock(sc, txq); | 2257 | ath_txq_unlock(sc, txq); |
| 2185 | txq = sc->tx.uapsdq; | 2258 | txq = sc->tx.uapsdq; |
| 2186 | ath_txq_lock(sc, txq); | 2259 | ath_txq_lock(sc, txq); |
| 2187 | } else if (txctl->an && | 2260 | } else if (txctl->an && queue) { |
| 2188 | ieee80211_is_data_present(hdr->frame_control)) { | ||
| 2189 | WARN_ON(tid->ac->txq != txctl->txq); | 2261 | WARN_ON(tid->ac->txq != txctl->txq); |
| 2190 | 2262 | ||
| 2191 | if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) | 2263 | if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) |
| @@ -2198,7 +2270,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
| 2198 | TX_STAT_INC(txq->axq_qnum, a_queued_sw); | 2270 | TX_STAT_INC(txq->axq_qnum, a_queued_sw); |
| 2199 | __skb_queue_tail(&tid->buf_q, skb); | 2271 | __skb_queue_tail(&tid->buf_q, skb); |
| 2200 | if (!txctl->an->sleeping) | 2272 | if (!txctl->an->sleeping) |
| 2201 | ath_tx_queue_tid(txq, tid); | 2273 | ath_tx_queue_tid(sc, txq, tid); |
| 2202 | 2274 | ||
| 2203 | ath_txq_schedule(sc, txq); | 2275 | ath_txq_schedule(sc, txq); |
| 2204 | goto out; | 2276 | goto out; |
| @@ -2244,8 +2316,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
| 2244 | int max_duration; | 2316 | int max_duration; |
| 2245 | 2317 | ||
| 2246 | max_duration = | 2318 | max_duration = |
| 2247 | sc->cur_beacon_conf.beacon_interval * 1000 * | 2319 | sc->cur_chan->beacon.beacon_interval * 1000 * |
| 2248 | sc->cur_beacon_conf.dtim_period / ATH_BCBUF; | 2320 | sc->cur_chan->beacon.dtim_period / ATH_BCBUF; |
| 2249 | 2321 | ||
| 2250 | do { | 2322 | do { |
| 2251 | struct ath_frame_info *fi = get_frame_info(skb); | 2323 | struct ath_frame_info *fi = get_frame_info(skb); |
| @@ -2560,6 +2632,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) | |||
| 2560 | sc->beacon.tx_processed = true; | 2632 | sc->beacon.tx_processed = true; |
| 2561 | sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); | 2633 | sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); |
| 2562 | 2634 | ||
| 2635 | ath_chanctx_event(sc, NULL, | ||
| 2636 | ATH_CHANCTX_EVENT_BEACON_SENT); | ||
| 2563 | ath9k_csa_update(sc); | 2637 | ath9k_csa_update(sc); |
| 2564 | continue; | 2638 | continue; |
| 2565 | } | 2639 | } |
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 8596aba34f96..237d0cda1bcb 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h | |||
| @@ -256,6 +256,7 @@ struct ar9170 { | |||
| 256 | atomic_t rx_work_urbs; | 256 | atomic_t rx_work_urbs; |
| 257 | atomic_t rx_pool_urbs; | 257 | atomic_t rx_pool_urbs; |
| 258 | kernel_ulong_t features; | 258 | kernel_ulong_t features; |
| 259 | bool usb_ep_cmd_is_bulk; | ||
| 259 | 260 | ||
| 260 | /* firmware settings */ | 261 | /* firmware settings */ |
| 261 | struct completion fw_load_wait; | 262 | struct completion fw_load_wait; |
diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c index ab4ee7d39ad3..b80b2138ce3c 100644 --- a/drivers/net/wireless/ath/carl9170/phy.c +++ b/drivers/net/wireless/ath/carl9170/phy.c | |||
| @@ -1139,7 +1139,6 @@ static int carl9170_set_freq_cal_data(struct ar9170 *ar, | |||
| 1139 | 1139 | ||
| 1140 | default: | 1140 | default: |
| 1141 | return -EINVAL; | 1141 | return -EINVAL; |
| 1142 | break; | ||
| 1143 | } | 1142 | } |
| 1144 | 1143 | ||
| 1145 | for (; i >= 0; i--) { | 1144 | for (; i >= 0; i--) { |
diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index f35c7f30f9a6..c9f93310c0d6 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c | |||
| @@ -621,9 +621,16 @@ int __carl9170_exec_cmd(struct ar9170 *ar, struct carl9170_cmd *cmd, | |||
| 621 | goto err_free; | 621 | goto err_free; |
| 622 | } | 622 | } |
| 623 | 623 | ||
| 624 | usb_fill_int_urb(urb, ar->udev, usb_sndintpipe(ar->udev, | 624 | if (ar->usb_ep_cmd_is_bulk) |
| 625 | AR9170_USB_EP_CMD), cmd, cmd->hdr.len + 4, | 625 | usb_fill_bulk_urb(urb, ar->udev, |
| 626 | carl9170_usb_cmd_complete, ar, 1); | 626 | usb_sndbulkpipe(ar->udev, AR9170_USB_EP_CMD), |
| 627 | cmd, cmd->hdr.len + 4, | ||
| 628 | carl9170_usb_cmd_complete, ar); | ||
| 629 | else | ||
| 630 | usb_fill_int_urb(urb, ar->udev, | ||
| 631 | usb_sndintpipe(ar->udev, AR9170_USB_EP_CMD), | ||
| 632 | cmd, cmd->hdr.len + 4, | ||
| 633 | carl9170_usb_cmd_complete, ar, 1); | ||
| 627 | 634 | ||
| 628 | if (free_buf) | 635 | if (free_buf) |
| 629 | urb->transfer_flags |= URB_FREE_BUFFER; | 636 | urb->transfer_flags |= URB_FREE_BUFFER; |
| @@ -1032,9 +1039,10 @@ static void carl9170_usb_firmware_step2(const struct firmware *fw, | |||
| 1032 | static int carl9170_usb_probe(struct usb_interface *intf, | 1039 | static int carl9170_usb_probe(struct usb_interface *intf, |
| 1033 | const struct usb_device_id *id) | 1040 | const struct usb_device_id *id) |
| 1034 | { | 1041 | { |
| 1042 | struct usb_endpoint_descriptor *ep; | ||
| 1035 | struct ar9170 *ar; | 1043 | struct ar9170 *ar; |
| 1036 | struct usb_device *udev; | 1044 | struct usb_device *udev; |
| 1037 | int err; | 1045 | int i, err; |
| 1038 | 1046 | ||
| 1039 | err = usb_reset_device(interface_to_usbdev(intf)); | 1047 | err = usb_reset_device(interface_to_usbdev(intf)); |
| 1040 | if (err) | 1048 | if (err) |
| @@ -1050,6 +1058,21 @@ static int carl9170_usb_probe(struct usb_interface *intf, | |||
| 1050 | ar->intf = intf; | 1058 | ar->intf = intf; |
| 1051 | ar->features = id->driver_info; | 1059 | ar->features = id->driver_info; |
| 1052 | 1060 | ||
| 1061 | /* We need to remember the type of endpoint 4 because it differs | ||
| 1062 | * between high- and full-speed configuration. The high-speed | ||
| 1063 | * configuration specifies it as interrupt and the full-speed | ||
| 1064 | * configuration as bulk endpoint. This information is required | ||
| 1065 | * later when sending urbs to that endpoint. | ||
| 1066 | */ | ||
| 1067 | for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; ++i) { | ||
| 1068 | ep = &intf->cur_altsetting->endpoint[i].desc; | ||
| 1069 | |||
| 1070 | if (usb_endpoint_num(ep) == AR9170_USB_EP_CMD && | ||
| 1071 | usb_endpoint_dir_out(ep) && | ||
| 1072 | usb_endpoint_type(ep) == USB_ENDPOINT_XFER_BULK) | ||
| 1073 | ar->usb_ep_cmd_is_bulk = true; | ||
| 1074 | } | ||
| 1075 | |||
| 1053 | usb_set_intfdata(intf, ar); | 1076 | usb_set_intfdata(intf, ar); |
| 1054 | SET_IEEE80211_DEV(ar->hw, &intf->dev); | 1077 | SET_IEEE80211_DEV(ar->hw, &intf->dev); |
| 1055 | 1078 | ||
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 4ab5370ab7a6..b71d2b33532d 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c | |||
| @@ -488,7 +488,6 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
| 488 | wcn36xx_err("Unsupported key cmd 0x%x\n", cmd); | 488 | wcn36xx_err("Unsupported key cmd 0x%x\n", cmd); |
| 489 | ret = -EOPNOTSUPP; | 489 | ret = -EOPNOTSUPP; |
| 490 | goto out; | 490 | goto out; |
| 491 | break; | ||
| 492 | } | 491 | } |
| 493 | 492 | ||
| 494 | out: | 493 | out: |
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 820d4ebd9322..4ac2c208c9ba 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c | |||
| @@ -104,8 +104,8 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type) | |||
| 104 | return -EOPNOTSUPP; | 104 | return -EOPNOTSUPP; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, | 107 | int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, |
| 108 | struct station_info *sinfo) | 108 | struct station_info *sinfo) |
| 109 | { | 109 | { |
| 110 | struct wmi_notify_req_cmd cmd = { | 110 | struct wmi_notify_req_cmd cmd = { |
| 111 | .cid = cid, | 111 | .cid = cid, |
| @@ -287,6 +287,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, | |||
| 287 | return -EBUSY; | 287 | return -EBUSY; |
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | wil_dbg_misc(wil, "Start scan_request 0x%p\n", request); | ||
| 290 | wil->scan_request = request; | 291 | wil->scan_request = request; |
| 291 | mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO); | 292 | mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO); |
| 292 | 293 | ||
| @@ -443,15 +444,15 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, | |||
| 443 | return rc; | 444 | return rc; |
| 444 | } | 445 | } |
| 445 | 446 | ||
| 446 | static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, | 447 | int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 447 | struct wireless_dev *wdev, | 448 | struct cfg80211_mgmt_tx_params *params, |
| 448 | struct cfg80211_mgmt_tx_params *params, | 449 | u64 *cookie) |
| 449 | u64 *cookie) | ||
| 450 | { | 450 | { |
| 451 | const u8 *buf = params->buf; | 451 | const u8 *buf = params->buf; |
| 452 | size_t len = params->len; | 452 | size_t len = params->len; |
| 453 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | 453 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); |
| 454 | int rc; | 454 | int rc; |
| 455 | bool tx_status = false; | ||
| 455 | struct ieee80211_mgmt *mgmt_frame = (void *)buf; | 456 | struct ieee80211_mgmt *mgmt_frame = (void *)buf; |
| 456 | struct wmi_sw_tx_req_cmd *cmd; | 457 | struct wmi_sw_tx_req_cmd *cmd; |
| 457 | struct { | 458 | struct { |
| @@ -460,8 +461,10 @@ static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, | |||
| 460 | } __packed evt; | 461 | } __packed evt; |
| 461 | 462 | ||
| 462 | cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); | 463 | cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); |
| 463 | if (!cmd) | 464 | if (!cmd) { |
| 464 | return -ENOMEM; | 465 | rc = -ENOMEM; |
| 466 | goto out; | ||
| 467 | } | ||
| 465 | 468 | ||
| 466 | memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); | 469 | memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); |
| 467 | cmd->len = cpu_to_le16(len); | 470 | cmd->len = cpu_to_le16(len); |
| @@ -470,10 +473,12 @@ static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, | |||
| 470 | rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len, | 473 | rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len, |
| 471 | WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); | 474 | WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); |
| 472 | if (rc == 0) | 475 | if (rc == 0) |
| 473 | rc = evt.evt.status; | 476 | tx_status = !evt.evt.status; |
| 474 | 477 | ||
| 475 | kfree(cmd); | 478 | kfree(cmd); |
| 476 | 479 | out: | |
| 480 | cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len, | ||
| 481 | tx_status, GFP_KERNEL); | ||
| 477 | return rc; | 482 | return rc; |
| 478 | } | 483 | } |
| 479 | 484 | ||
| @@ -562,6 +567,34 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy, | |||
| 562 | return rc; | 567 | return rc; |
| 563 | } | 568 | } |
| 564 | 569 | ||
| 570 | static void wil_print_bcon_data(struct cfg80211_beacon_data *b) | ||
| 571 | { | ||
| 572 | print_hex_dump_bytes("head ", DUMP_PREFIX_OFFSET, | ||
| 573 | b->head, b->head_len); | ||
| 574 | print_hex_dump_bytes("tail ", DUMP_PREFIX_OFFSET, | ||
| 575 | b->tail, b->tail_len); | ||
| 576 | print_hex_dump_bytes("BCON IE ", DUMP_PREFIX_OFFSET, | ||
| 577 | b->beacon_ies, b->beacon_ies_len); | ||
| 578 | print_hex_dump_bytes("PROBE ", DUMP_PREFIX_OFFSET, | ||
| 579 | b->probe_resp, b->probe_resp_len); | ||
| 580 | print_hex_dump_bytes("PROBE IE ", DUMP_PREFIX_OFFSET, | ||
| 581 | b->proberesp_ies, b->proberesp_ies_len); | ||
| 582 | print_hex_dump_bytes("ASSOC IE ", DUMP_PREFIX_OFFSET, | ||
| 583 | b->assocresp_ies, b->assocresp_ies_len); | ||
| 584 | } | ||
| 585 | |||
| 586 | static void wil_print_crypto(struct wil6210_priv *wil, | ||
| 587 | struct cfg80211_crypto_settings *c) | ||
| 588 | { | ||
| 589 | wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n", | ||
| 590 | c->wpa_versions, c->cipher_group); | ||
| 591 | wil_dbg_misc(wil, "Pairwise ciphers [%d]\n", c->n_ciphers_pairwise); | ||
| 592 | wil_dbg_misc(wil, "AKM suites [%d]\n", c->n_akm_suites); | ||
| 593 | wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n", | ||
| 594 | c->control_port, be16_to_cpu(c->control_port_ethertype), | ||
| 595 | c->control_port_no_encrypt); | ||
| 596 | } | ||
| 597 | |||
| 565 | static int wil_fix_bcon(struct wil6210_priv *wil, | 598 | static int wil_fix_bcon(struct wil6210_priv *wil, |
| 566 | struct cfg80211_beacon_data *bcon) | 599 | struct cfg80211_beacon_data *bcon) |
| 567 | { | 600 | { |
| @@ -595,8 +628,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, | |||
| 595 | struct wireless_dev *wdev = ndev->ieee80211_ptr; | 628 | struct wireless_dev *wdev = ndev->ieee80211_ptr; |
| 596 | struct ieee80211_channel *channel = info->chandef.chan; | 629 | struct ieee80211_channel *channel = info->chandef.chan; |
| 597 | struct cfg80211_beacon_data *bcon = &info->beacon; | 630 | struct cfg80211_beacon_data *bcon = &info->beacon; |
| 631 | struct cfg80211_crypto_settings *crypto = &info->crypto; | ||
| 598 | u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); | 632 | u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); |
| 599 | 633 | ||
| 634 | wil_dbg_misc(wil, "%s()\n", __func__); | ||
| 635 | |||
| 600 | if (!channel) { | 636 | if (!channel) { |
| 601 | wil_err(wil, "AP: No channel???\n"); | 637 | wil_err(wil, "AP: No channel???\n"); |
| 602 | return -EINVAL; | 638 | return -EINVAL; |
| @@ -604,11 +640,19 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, | |||
| 604 | 640 | ||
| 605 | wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, | 641 | wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, |
| 606 | channel->center_freq, info->privacy ? "secure" : "open"); | 642 | channel->center_freq, info->privacy ? "secure" : "open"); |
| 643 | wil_dbg_misc(wil, "Privacy: %d auth_type %d\n", | ||
| 644 | info->privacy, info->auth_type); | ||
| 645 | wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval, | ||
| 646 | info->dtim_period); | ||
| 607 | print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, | 647 | print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, |
| 608 | info->ssid, info->ssid_len); | 648 | info->ssid, info->ssid_len); |
| 649 | wil_print_bcon_data(bcon); | ||
| 650 | wil_print_crypto(wil, crypto); | ||
| 609 | 651 | ||
| 610 | if (wil_fix_bcon(wil, bcon)) | 652 | if (wil_fix_bcon(wil, bcon)) { |
| 611 | wil_dbg_misc(wil, "Fixed bcon\n"); | 653 | wil_dbg_misc(wil, "Fixed bcon\n"); |
| 654 | wil_print_bcon_data(bcon); | ||
| 655 | } | ||
| 612 | 656 | ||
| 613 | mutex_lock(&wil->mutex); | 657 | mutex_lock(&wil->mutex); |
| 614 | 658 | ||
| @@ -663,6 +707,8 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, | |||
| 663 | int rc = 0; | 707 | int rc = 0; |
| 664 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | 708 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); |
| 665 | 709 | ||
| 710 | wil_dbg_misc(wil, "%s()\n", __func__); | ||
| 711 | |||
| 666 | mutex_lock(&wil->mutex); | 712 | mutex_lock(&wil->mutex); |
| 667 | 713 | ||
| 668 | rc = wmi_pcp_stop(wil); | 714 | rc = wmi_pcp_stop(wil); |
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 8d4bc4bfb664..8f66186adb8c 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/seq_file.h> | 19 | #include <linux/seq_file.h> |
| 20 | #include <linux/pci.h> | 20 | #include <linux/pci.h> |
| 21 | #include <linux/rtnetlink.h> | 21 | #include <linux/rtnetlink.h> |
| 22 | #include <linux/power_supply.h> | ||
| 22 | 23 | ||
| 23 | #include "wil6210.h" | 24 | #include "wil6210.h" |
| 24 | #include "txrx.h" | 25 | #include "txrx.h" |
| @@ -69,14 +70,32 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) | |||
| 69 | 70 | ||
| 70 | for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { | 71 | for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { |
| 71 | struct vring *vring = &(wil->vring_tx[i]); | 72 | struct vring *vring = &(wil->vring_tx[i]); |
| 73 | struct vring_tx_data *txdata = &wil->vring_tx_data[i]; | ||
| 74 | |||
| 72 | if (vring->va) { | 75 | if (vring->va) { |
| 73 | int cid = wil->vring2cid_tid[i][0]; | 76 | int cid = wil->vring2cid_tid[i][0]; |
| 74 | int tid = wil->vring2cid_tid[i][1]; | 77 | int tid = wil->vring2cid_tid[i][1]; |
| 78 | u32 swhead = vring->swhead; | ||
| 79 | u32 swtail = vring->swtail; | ||
| 80 | int used = (vring->size + swhead - swtail) | ||
| 81 | % vring->size; | ||
| 82 | int avail = vring->size - used - 1; | ||
| 75 | char name[10]; | 83 | char name[10]; |
| 84 | /* performance monitoring */ | ||
| 85 | cycles_t now = get_cycles(); | ||
| 86 | cycles_t idle = txdata->idle * 100; | ||
| 87 | cycles_t total = now - txdata->begin; | ||
| 88 | |||
| 89 | do_div(idle, total); | ||
| 90 | txdata->begin = now; | ||
| 91 | txdata->idle = 0ULL; | ||
| 92 | |||
| 76 | snprintf(name, sizeof(name), "tx_%2d", i); | 93 | snprintf(name, sizeof(name), "tx_%2d", i); |
| 77 | 94 | ||
| 78 | seq_printf(s, "\n%pM CID %d TID %d\n", | 95 | seq_printf(s, "\n%pM CID %d TID %d [%3d|%3d] idle %3d%%\n", |
| 79 | wil->sta[cid].addr, cid, tid); | 96 | wil->sta[cid].addr, cid, tid, used, avail, |
| 97 | (int)idle); | ||
| 98 | |||
| 80 | wil_print_vring(s, wil, name, vring, '_', 'H'); | 99 | wil_print_vring(s, wil, name, vring, '_', 'H'); |
| 81 | } | 100 | } |
| 82 | } | 101 | } |
| @@ -231,6 +250,26 @@ static struct dentry *wil_debugfs_create_iomem_x32(const char *name, | |||
| 231 | &fops_iomem_x32); | 250 | &fops_iomem_x32); |
| 232 | } | 251 | } |
| 233 | 252 | ||
| 253 | static int wil_debugfs_ulong_set(void *data, u64 val) | ||
| 254 | { | ||
| 255 | *(ulong *)data = val; | ||
| 256 | return 0; | ||
| 257 | } | ||
| 258 | static int wil_debugfs_ulong_get(void *data, u64 *val) | ||
| 259 | { | ||
| 260 | *val = *(ulong *)data; | ||
| 261 | return 0; | ||
| 262 | } | ||
| 263 | DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get, | ||
| 264 | wil_debugfs_ulong_set, "%llu\n"); | ||
| 265 | |||
| 266 | static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode, | ||
| 267 | struct dentry *parent, | ||
| 268 | ulong *value) | ||
| 269 | { | ||
| 270 | return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong); | ||
| 271 | } | ||
| 272 | |||
| 234 | static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil, | 273 | static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil, |
| 235 | const char *name, | 274 | const char *name, |
| 236 | struct dentry *parent, u32 off) | 275 | struct dentry *parent, u32 off) |
| @@ -284,11 +323,11 @@ static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil, | |||
| 284 | if (IS_ERR_OR_NULL(d)) | 323 | if (IS_ERR_OR_NULL(d)) |
| 285 | return -ENODEV; | 324 | return -ENODEV; |
| 286 | 325 | ||
| 287 | wil_debugfs_create_iomem_x32("TRSH", S_IRUGO, d, wil->csr + | 326 | wil_debugfs_create_iomem_x32("TRSH", S_IRUGO | S_IWUSR, d, wil->csr + |
| 288 | HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); | 327 | HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); |
| 289 | wil_debugfs_create_iomem_x32("DATA", S_IRUGO, d, wil->csr + | 328 | wil_debugfs_create_iomem_x32("DATA", S_IRUGO | S_IWUSR, d, wil->csr + |
| 290 | HOSTADDR(RGF_DMA_ITR_CNT_DATA)); | 329 | HOSTADDR(RGF_DMA_ITR_CNT_DATA)); |
| 291 | wil_debugfs_create_iomem_x32("CTL", S_IRUGO, d, wil->csr + | 330 | wil_debugfs_create_iomem_x32("CTL", S_IRUGO | S_IWUSR, d, wil->csr + |
| 292 | HOSTADDR(RGF_DMA_ITR_CNT_CRL)); | 331 | HOSTADDR(RGF_DMA_ITR_CNT_CRL)); |
| 293 | 332 | ||
| 294 | return 0; | 333 | return 0; |
| @@ -397,6 +436,126 @@ static const struct file_operations fops_reset = { | |||
| 397 | .write = wil_write_file_reset, | 436 | .write = wil_write_file_reset, |
| 398 | .open = simple_open, | 437 | .open = simple_open, |
| 399 | }; | 438 | }; |
| 439 | /*---write channel 1..4 to rxon for it, 0 to rxoff---*/ | ||
| 440 | static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf, | ||
| 441 | size_t len, loff_t *ppos) | ||
| 442 | { | ||
| 443 | struct wil6210_priv *wil = file->private_data; | ||
| 444 | int rc; | ||
| 445 | long channel; | ||
| 446 | bool on; | ||
| 447 | |||
| 448 | char *kbuf = kmalloc(len + 1, GFP_KERNEL); | ||
| 449 | if (!kbuf) | ||
| 450 | return -ENOMEM; | ||
| 451 | if (copy_from_user(kbuf, buf, len)) { | ||
| 452 | kfree(kbuf); | ||
| 453 | return -EIO; | ||
| 454 | } | ||
| 455 | |||
| 456 | kbuf[len] = '\0'; | ||
| 457 | rc = kstrtol(kbuf, 0, &channel); | ||
| 458 | kfree(kbuf); | ||
| 459 | if (rc) | ||
| 460 | return rc; | ||
| 461 | |||
| 462 | if ((channel < 0) || (channel > 4)) { | ||
| 463 | wil_err(wil, "Invalid channel %ld\n", channel); | ||
| 464 | return -EINVAL; | ||
| 465 | } | ||
| 466 | on = !!channel; | ||
| 467 | |||
| 468 | if (on) { | ||
| 469 | rc = wmi_set_channel(wil, (int)channel); | ||
| 470 | if (rc) | ||
| 471 | return rc; | ||
| 472 | } | ||
| 473 | |||
| 474 | rc = wmi_rxon(wil, on); | ||
| 475 | if (rc) | ||
| 476 | return rc; | ||
| 477 | |||
| 478 | return len; | ||
| 479 | } | ||
| 480 | |||
| 481 | static const struct file_operations fops_rxon = { | ||
| 482 | .write = wil_write_file_rxon, | ||
| 483 | .open = simple_open, | ||
| 484 | }; | ||
| 485 | /*---tx_mgmt---*/ | ||
| 486 | /* Write mgmt frame to this file to send it */ | ||
| 487 | static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, | ||
| 488 | size_t len, loff_t *ppos) | ||
| 489 | { | ||
| 490 | struct wil6210_priv *wil = file->private_data; | ||
| 491 | struct wiphy *wiphy = wil_to_wiphy(wil); | ||
| 492 | struct wireless_dev *wdev = wil_to_wdev(wil); | ||
| 493 | struct cfg80211_mgmt_tx_params params; | ||
| 494 | int rc; | ||
| 495 | |||
| 496 | void *frame = kmalloc(len, GFP_KERNEL); | ||
| 497 | if (!frame) | ||
| 498 | return -ENOMEM; | ||
| 499 | |||
| 500 | if (copy_from_user(frame, buf, len)) | ||
| 501 | return -EIO; | ||
| 502 | |||
| 503 | params.buf = frame; | ||
| 504 | params.len = len; | ||
| 505 | params.chan = wdev->preset_chandef.chan; | ||
| 506 | |||
| 507 | rc = wil_cfg80211_mgmt_tx(wiphy, wdev, ¶ms, NULL); | ||
| 508 | |||
| 509 | kfree(frame); | ||
| 510 | wil_info(wil, "%s() -> %d\n", __func__, rc); | ||
| 511 | |||
| 512 | return len; | ||
| 513 | } | ||
| 514 | |||
| 515 | static const struct file_operations fops_txmgmt = { | ||
| 516 | .write = wil_write_file_txmgmt, | ||
| 517 | .open = simple_open, | ||
| 518 | }; | ||
| 519 | |||
| 520 | /* Write WMI command (w/o mbox header) to this file to send it | ||
| 521 | * WMI starts from wil6210_mbox_hdr_wmi header | ||
| 522 | */ | ||
| 523 | static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, | ||
| 524 | size_t len, loff_t *ppos) | ||
| 525 | { | ||
| 526 | struct wil6210_priv *wil = file->private_data; | ||
| 527 | struct wil6210_mbox_hdr_wmi *wmi; | ||
| 528 | void *cmd; | ||
| 529 | int cmdlen = len - sizeof(struct wil6210_mbox_hdr_wmi); | ||
| 530 | u16 cmdid; | ||
| 531 | int rc, rc1; | ||
| 532 | |||
| 533 | if (cmdlen <= 0) | ||
| 534 | return -EINVAL; | ||
| 535 | |||
| 536 | wmi = kmalloc(len, GFP_KERNEL); | ||
| 537 | if (!wmi) | ||
| 538 | return -ENOMEM; | ||
| 539 | |||
| 540 | rc = simple_write_to_buffer(wmi, len, ppos, buf, len); | ||
| 541 | if (rc < 0) | ||
| 542 | return rc; | ||
| 543 | |||
| 544 | cmd = &wmi[1]; | ||
| 545 | cmdid = le16_to_cpu(wmi->id); | ||
| 546 | |||
| 547 | rc1 = wmi_send(wil, cmdid, cmd, cmdlen); | ||
| 548 | kfree(wmi); | ||
| 549 | |||
| 550 | wil_info(wil, "%s(0x%04x[%d]) -> %d\n", __func__, cmdid, cmdlen, rc1); | ||
| 551 | |||
| 552 | return rc; | ||
| 553 | } | ||
| 554 | |||
| 555 | static const struct file_operations fops_wmi = { | ||
| 556 | .write = wil_write_file_wmi, | ||
| 557 | .open = simple_open, | ||
| 558 | }; | ||
| 400 | 559 | ||
| 401 | static void wil_seq_hexdump(struct seq_file *s, void *p, int len, | 560 | static void wil_seq_hexdump(struct seq_file *s, void *p, int len, |
| 402 | const char *prefix) | 561 | const char *prefix) |
| @@ -600,8 +759,8 @@ static int wil_temp_debugfs_show(struct seq_file *s, void *data) | |||
| 600 | return 0; | 759 | return 0; |
| 601 | } | 760 | } |
| 602 | 761 | ||
| 603 | print_temp(s, "MAC temperature :", t_m); | 762 | print_temp(s, "T_mac =", t_m); |
| 604 | print_temp(s, "Radio temperature :", t_r); | 763 | print_temp(s, "T_radio =", t_r); |
| 605 | 764 | ||
| 606 | return 0; | 765 | return 0; |
| 607 | } | 766 | } |
| @@ -618,6 +777,130 @@ static const struct file_operations fops_temp = { | |||
| 618 | .llseek = seq_lseek, | 777 | .llseek = seq_lseek, |
| 619 | }; | 778 | }; |
| 620 | 779 | ||
| 780 | /*---------freq------------*/ | ||
| 781 | static int wil_freq_debugfs_show(struct seq_file *s, void *data) | ||
| 782 | { | ||
| 783 | struct wil6210_priv *wil = s->private; | ||
| 784 | struct wireless_dev *wdev = wil_to_wdev(wil); | ||
| 785 | u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0; | ||
| 786 | |||
| 787 | seq_printf(s, "Freq = %d\n", freq); | ||
| 788 | |||
| 789 | return 0; | ||
| 790 | } | ||
| 791 | |||
| 792 | static int wil_freq_seq_open(struct inode *inode, struct file *file) | ||
| 793 | { | ||
| 794 | return single_open(file, wil_freq_debugfs_show, inode->i_private); | ||
| 795 | } | ||
| 796 | |||
| 797 | static const struct file_operations fops_freq = { | ||
| 798 | .open = wil_freq_seq_open, | ||
| 799 | .release = single_release, | ||
| 800 | .read = seq_read, | ||
| 801 | .llseek = seq_lseek, | ||
| 802 | }; | ||
| 803 | |||
| 804 | /*---------link------------*/ | ||
| 805 | static int wil_link_debugfs_show(struct seq_file *s, void *data) | ||
| 806 | { | ||
| 807 | struct wil6210_priv *wil = s->private; | ||
| 808 | struct station_info sinfo; | ||
| 809 | int i, rc; | ||
| 810 | |||
| 811 | for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { | ||
| 812 | struct wil_sta_info *p = &wil->sta[i]; | ||
| 813 | char *status = "unknown"; | ||
| 814 | switch (p->status) { | ||
| 815 | case wil_sta_unused: | ||
| 816 | status = "unused "; | ||
| 817 | break; | ||
| 818 | case wil_sta_conn_pending: | ||
| 819 | status = "pending "; | ||
| 820 | break; | ||
| 821 | case wil_sta_connected: | ||
| 822 | status = "connected"; | ||
| 823 | break; | ||
| 824 | } | ||
| 825 | seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, | ||
| 826 | (p->data_port_open ? " data_port_open" : "")); | ||
| 827 | |||
| 828 | if (p->status == wil_sta_connected) { | ||
| 829 | rc = wil_cid_fill_sinfo(wil, i, &sinfo); | ||
| 830 | if (rc) | ||
| 831 | return rc; | ||
| 832 | |||
| 833 | seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs); | ||
| 834 | seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs); | ||
| 835 | seq_printf(s, " SQ = %d\n", sinfo.signal); | ||
| 836 | } | ||
| 837 | } | ||
| 838 | |||
| 839 | return 0; | ||
| 840 | } | ||
| 841 | |||
| 842 | static int wil_link_seq_open(struct inode *inode, struct file *file) | ||
| 843 | { | ||
| 844 | return single_open(file, wil_link_debugfs_show, inode->i_private); | ||
| 845 | } | ||
| 846 | |||
| 847 | static const struct file_operations fops_link = { | ||
| 848 | .open = wil_link_seq_open, | ||
| 849 | .release = single_release, | ||
| 850 | .read = seq_read, | ||
| 851 | .llseek = seq_lseek, | ||
| 852 | }; | ||
| 853 | |||
| 854 | /*---------info------------*/ | ||
| 855 | static int wil_info_debugfs_show(struct seq_file *s, void *data) | ||
| 856 | { | ||
| 857 | struct wil6210_priv *wil = s->private; | ||
| 858 | struct net_device *ndev = wil_to_ndev(wil); | ||
| 859 | int is_ac = power_supply_is_system_supplied(); | ||
| 860 | int rx = atomic_xchg(&wil->isr_count_rx, 0); | ||
| 861 | int tx = atomic_xchg(&wil->isr_count_tx, 0); | ||
| 862 | static ulong rxf_old, txf_old; | ||
| 863 | ulong rxf = ndev->stats.rx_packets; | ||
| 864 | ulong txf = ndev->stats.tx_packets; | ||
| 865 | unsigned int i; | ||
| 866 | |||
| 867 | /* >0 : AC; 0 : battery; <0 : error */ | ||
| 868 | seq_printf(s, "AC powered : %d\n", is_ac); | ||
| 869 | seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old); | ||
| 870 | seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old); | ||
| 871 | rxf_old = rxf; | ||
| 872 | txf_old = txf; | ||
| 873 | |||
| 874 | |||
| 875 | #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \ | ||
| 876 | " " __stringify(x) : "" | ||
| 877 | |||
| 878 | for (i = 0; i < ndev->num_tx_queues; i++) { | ||
| 879 | struct netdev_queue *txq = netdev_get_tx_queue(ndev, i); | ||
| 880 | unsigned long state = txq->state; | ||
| 881 | |||
| 882 | seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state, | ||
| 883 | CHECK_QSTATE(DRV_XOFF), | ||
| 884 | CHECK_QSTATE(STACK_XOFF), | ||
| 885 | CHECK_QSTATE(FROZEN) | ||
| 886 | ); | ||
| 887 | } | ||
| 888 | #undef CHECK_QSTATE | ||
| 889 | return 0; | ||
| 890 | } | ||
| 891 | |||
| 892 | static int wil_info_seq_open(struct inode *inode, struct file *file) | ||
| 893 | { | ||
| 894 | return single_open(file, wil_info_debugfs_show, inode->i_private); | ||
| 895 | } | ||
| 896 | |||
| 897 | static const struct file_operations fops_info = { | ||
| 898 | .open = wil_info_seq_open, | ||
| 899 | .release = single_release, | ||
| 900 | .read = seq_read, | ||
| 901 | .llseek = seq_lseek, | ||
| 902 | }; | ||
| 903 | |||
| 621 | /*---------Station matrix------------*/ | 904 | /*---------Station matrix------------*/ |
| 622 | static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) | 905 | static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) |
| 623 | { | 906 | { |
| @@ -630,7 +913,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) | |||
| 630 | else | 913 | else |
| 631 | seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); | 914 | seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); |
| 632 | } | 915 | } |
| 633 | seq_puts(s, "]\n"); | 916 | seq_printf(s, "] last drop 0x%03x\n", r->ssn_last_drop); |
| 634 | } | 917 | } |
| 635 | 918 | ||
| 636 | static int wil_sta_debugfs_show(struct seq_file *s, void *data) | 919 | static int wil_sta_debugfs_show(struct seq_file *s, void *data) |
| @@ -682,6 +965,26 @@ static const struct file_operations fops_sta = { | |||
| 682 | }; | 965 | }; |
| 683 | 966 | ||
| 684 | /*----------------*/ | 967 | /*----------------*/ |
| 968 | static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil, | ||
| 969 | struct dentry *dbg) | ||
| 970 | { | ||
| 971 | int i; | ||
| 972 | char name[32]; | ||
| 973 | |||
| 974 | for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { | ||
| 975 | struct debugfs_blob_wrapper *blob = &wil->blobs[i]; | ||
| 976 | const struct fw_map *map = &fw_mapping[i]; | ||
| 977 | |||
| 978 | if (!map->name) | ||
| 979 | continue; | ||
| 980 | |||
| 981 | blob->data = (void * __force)wil->csr + HOSTADDR(map->host); | ||
| 982 | blob->size = map->to - map->from; | ||
| 983 | snprintf(name, sizeof(name), "blob_%s", map->name); | ||
| 984 | wil_debugfs_create_ioblob(name, S_IRUGO, dbg, blob); | ||
| 985 | } | ||
| 986 | } | ||
| 987 | |||
| 685 | int wil6210_debugfs_init(struct wil6210_priv *wil) | 988 | int wil6210_debugfs_init(struct wil6210_priv *wil) |
| 686 | { | 989 | { |
| 687 | struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME, | 990 | struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME, |
| @@ -703,6 +1006,10 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) | |||
| 703 | debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid); | 1006 | debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid); |
| 704 | debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, | 1007 | debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, |
| 705 | &wil->secure_pcp); | 1008 | &wil->secure_pcp); |
| 1009 | wil_debugfs_create_ulong("status", S_IRUGO | S_IWUSR, dbg, | ||
| 1010 | &wil->status); | ||
| 1011 | debugfs_create_u32("fw_version", S_IRUGO, dbg, &wil->fw_version); | ||
| 1012 | debugfs_create_x32("hw_version", S_IRUGO, dbg, &wil->hw_version); | ||
| 706 | 1013 | ||
| 707 | wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg, | 1014 | wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg, |
| 708 | HOSTADDR(RGF_USER_USER_ICR)); | 1015 | HOSTADDR(RGF_USER_USER_ICR)); |
| @@ -715,40 +1022,22 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) | |||
| 715 | wil6210_debugfs_create_pseudo_ISR(wil, dbg); | 1022 | wil6210_debugfs_create_pseudo_ISR(wil, dbg); |
| 716 | wil6210_debugfs_create_ITR_CNT(wil, dbg); | 1023 | wil6210_debugfs_create_ITR_CNT(wil, dbg); |
| 717 | 1024 | ||
| 1025 | wil_debugfs_create_iomem_x32("RGF_USER_USAGE_1", S_IRUGO, dbg, | ||
| 1026 | wil->csr + | ||
| 1027 | HOSTADDR(RGF_USER_USAGE_1)); | ||
| 718 | debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr); | 1028 | debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr); |
| 719 | debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread); | 1029 | debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread); |
| 720 | 1030 | ||
| 721 | debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset); | 1031 | debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset); |
| 1032 | debugfs_create_file("rxon", S_IWUSR, dbg, wil, &fops_rxon); | ||
| 1033 | debugfs_create_file("tx_mgmt", S_IWUSR, dbg, wil, &fops_txmgmt); | ||
| 1034 | debugfs_create_file("wmi_send", S_IWUSR, dbg, wil, &fops_wmi); | ||
| 722 | debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp); | 1035 | debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp); |
| 1036 | debugfs_create_file("freq", S_IRUGO, dbg, wil, &fops_freq); | ||
| 1037 | debugfs_create_file("link", S_IRUGO, dbg, wil, &fops_link); | ||
| 1038 | debugfs_create_file("info", S_IRUGO, dbg, wil, &fops_info); | ||
| 723 | 1039 | ||
| 724 | wil->rgf_blob.data = (void * __force)wil->csr + 0; | 1040 | wil6210_debugfs_init_blobs(wil, dbg); |
| 725 | wil->rgf_blob.size = 0xa000; | ||
| 726 | wil_debugfs_create_ioblob("blob_rgf", S_IRUGO, dbg, &wil->rgf_blob); | ||
| 727 | |||
| 728 | wil->fw_code_blob.data = (void * __force)wil->csr + 0x40000; | ||
| 729 | wil->fw_code_blob.size = 0x40000; | ||
| 730 | wil_debugfs_create_ioblob("blob_fw_code", S_IRUGO, dbg, | ||
| 731 | &wil->fw_code_blob); | ||
| 732 | |||
| 733 | wil->fw_data_blob.data = (void * __force)wil->csr + 0x80000; | ||
| 734 | wil->fw_data_blob.size = 0x8000; | ||
| 735 | wil_debugfs_create_ioblob("blob_fw_data", S_IRUGO, dbg, | ||
| 736 | &wil->fw_data_blob); | ||
| 737 | |||
| 738 | wil->fw_peri_blob.data = (void * __force)wil->csr + 0x88000; | ||
| 739 | wil->fw_peri_blob.size = 0x18000; | ||
| 740 | wil_debugfs_create_ioblob("blob_fw_peri", S_IRUGO, dbg, | ||
| 741 | &wil->fw_peri_blob); | ||
| 742 | |||
| 743 | wil->uc_code_blob.data = (void * __force)wil->csr + 0xa0000; | ||
| 744 | wil->uc_code_blob.size = 0x10000; | ||
| 745 | wil_debugfs_create_ioblob("blob_uc_code", S_IRUGO, dbg, | ||
| 746 | &wil->uc_code_blob); | ||
| 747 | |||
| 748 | wil->uc_data_blob.data = (void * __force)wil->csr + 0xb0000; | ||
| 749 | wil->uc_data_blob.size = 0x4000; | ||
| 750 | wil_debugfs_create_ioblob("blob_uc_data", S_IRUGO, dbg, | ||
| 751 | &wil->uc_data_blob); | ||
| 752 | 1041 | ||
| 753 | return 0; | 1042 | return 0; |
| 754 | } | 1043 | } |
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 73593aa3cd98..67f1002a03a1 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c | |||
| @@ -208,6 +208,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) | |||
| 208 | 208 | ||
| 209 | /* Rx IRQ will be enabled when NAPI processing finished */ | 209 | /* Rx IRQ will be enabled when NAPI processing finished */ |
| 210 | 210 | ||
| 211 | atomic_inc(&wil->isr_count_rx); | ||
| 211 | return IRQ_HANDLED; | 212 | return IRQ_HANDLED; |
| 212 | } | 213 | } |
| 213 | 214 | ||
| @@ -246,6 +247,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) | |||
| 246 | 247 | ||
| 247 | /* Tx IRQ will be enabled when NAPI processing finished */ | 248 | /* Tx IRQ will be enabled when NAPI processing finished */ |
| 248 | 249 | ||
| 250 | atomic_inc(&wil->isr_count_tx); | ||
| 249 | return IRQ_HANDLED; | 251 | return IRQ_HANDLED; |
| 250 | } | 252 | } |
| 251 | 253 | ||
| @@ -257,6 +259,7 @@ static void wil_notify_fw_error(struct wil6210_priv *wil) | |||
| 257 | [1] = "EVENT=FW_ERROR", | 259 | [1] = "EVENT=FW_ERROR", |
| 258 | [2] = NULL, | 260 | [2] = NULL, |
| 259 | }; | 261 | }; |
| 262 | wil_err(wil, "Notify about firmware error\n"); | ||
| 260 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); | 263 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); |
| 261 | } | 264 | } |
| 262 | 265 | ||
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 11e6d9d22eae..3704d2a434f3 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c | |||
| @@ -61,11 +61,24 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, | |||
| 61 | static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) | 61 | static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) |
| 62 | { | 62 | { |
| 63 | uint i; | 63 | uint i; |
| 64 | struct net_device *ndev = wil_to_ndev(wil); | ||
| 65 | struct wireless_dev *wdev = wil->wdev; | ||
| 64 | struct wil_sta_info *sta = &wil->sta[cid]; | 66 | struct wil_sta_info *sta = &wil->sta[cid]; |
| 67 | wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid, | ||
| 68 | sta->status); | ||
| 65 | 69 | ||
| 66 | sta->data_port_open = false; | 70 | sta->data_port_open = false; |
| 67 | if (sta->status != wil_sta_unused) { | 71 | if (sta->status != wil_sta_unused) { |
| 68 | wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING); | 72 | wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING); |
| 73 | switch (wdev->iftype) { | ||
| 74 | case NL80211_IFTYPE_AP: | ||
| 75 | case NL80211_IFTYPE_P2P_GO: | ||
| 76 | /* AP-like interface */ | ||
| 77 | cfg80211_del_sta(ndev, sta->addr, GFP_KERNEL); | ||
| 78 | break; | ||
| 79 | default: | ||
| 80 | break; | ||
| 81 | } | ||
| 69 | sta->status = wil_sta_unused; | 82 | sta->status = wil_sta_unused; |
| 70 | } | 83 | } |
| 71 | 84 | ||
| @@ -119,11 +132,6 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid) | |||
| 119 | clear_bit(wil_status_fwconnecting, &wil->status); | 132 | clear_bit(wil_status_fwconnecting, &wil->status); |
| 120 | break; | 133 | break; |
| 121 | default: | 134 | default: |
| 122 | /* AP-like interface and monitor: | ||
| 123 | * never scan, always connected | ||
| 124 | */ | ||
| 125 | if (bssid) | ||
| 126 | cfg80211_del_sta(ndev, bssid, GFP_KERNEL); | ||
| 127 | break; | 135 | break; |
| 128 | } | 136 | } |
| 129 | } | 137 | } |
| @@ -306,8 +314,9 @@ static void wil_target_reset(struct wil6210_priv *wil) | |||
| 306 | int delay = 0; | 314 | int delay = 0; |
| 307 | u32 hw_state; | 315 | u32 hw_state; |
| 308 | u32 rev_id; | 316 | u32 rev_id; |
| 317 | bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW); | ||
| 309 | 318 | ||
| 310 | wil_dbg_misc(wil, "Resetting...\n"); | 319 | wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name); |
| 311 | 320 | ||
| 312 | /* register read */ | 321 | /* register read */ |
| 313 | #define R(a) ioread32(wil->csr + HOSTADDR(a)) | 322 | #define R(a) ioread32(wil->csr + HOSTADDR(a)) |
| @@ -320,35 +329,59 @@ static void wil_target_reset(struct wil6210_priv *wil) | |||
| 320 | 329 | ||
| 321 | wil->hw_version = R(RGF_USER_FW_REV_ID); | 330 | wil->hw_version = R(RGF_USER_FW_REV_ID); |
| 322 | rev_id = wil->hw_version & 0xff; | 331 | rev_id = wil->hw_version & 0xff; |
| 332 | |||
| 333 | /* Clear MAC link up */ | ||
| 334 | S(RGF_HP_CTRL, BIT(15)); | ||
| 323 | /* hpal_perst_from_pad_src_n_mask */ | 335 | /* hpal_perst_from_pad_src_n_mask */ |
| 324 | S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6)); | 336 | S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6)); |
| 325 | /* car_perst_rst_src_n_mask */ | 337 | /* car_perst_rst_src_n_mask */ |
| 326 | S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7)); | 338 | S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7)); |
| 327 | wmb(); /* order is important here */ | 339 | wmb(); /* order is important here */ |
| 328 | 340 | ||
| 341 | if (is_sparrow) { | ||
| 342 | W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); | ||
| 343 | wmb(); /* order is important here */ | ||
| 344 | } | ||
| 345 | |||
| 329 | W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ | 346 | W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ |
| 330 | W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */ | 347 | W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */ |
| 331 | wmb(); /* order is important here */ | 348 | wmb(); /* order is important here */ |
| 332 | 349 | ||
| 333 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); | 350 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); |
| 334 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); | 351 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); |
| 335 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170); | 352 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000B0 : 0x00000170); |
| 336 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00); | 353 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00); |
| 337 | wmb(); /* order is important here */ | 354 | wmb(); /* order is important here */ |
| 338 | 355 | ||
| 356 | if (is_sparrow) { | ||
| 357 | W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); | ||
| 358 | wmb(); /* order is important here */ | ||
| 359 | } | ||
| 360 | |||
| 339 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); | 361 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); |
| 340 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); | 362 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); |
| 341 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); | 363 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); |
| 342 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); | 364 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); |
| 343 | wmb(); /* order is important here */ | 365 | wmb(); /* order is important here */ |
| 344 | 366 | ||
| 345 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); | 367 | if (is_sparrow) { |
| 346 | if (rev_id == 1) { | 368 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); |
| 347 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); | 369 | /* reset A2 PCIE AHB */ |
| 348 | } else { | ||
| 349 | W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); | ||
| 350 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); | 370 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); |
| 371 | |||
| 372 | } else { | ||
| 373 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); | ||
| 374 | if (rev_id == 1) { | ||
| 375 | /* reset A1 BOTH PCIE AHB & PCIE RGF */ | ||
| 376 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); | ||
| 377 | } else { | ||
| 378 | W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); | ||
| 379 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); | ||
| 380 | } | ||
| 381 | |||
| 351 | } | 382 | } |
| 383 | |||
| 384 | /* TODO: check order here!!! Erez code is different */ | ||
| 352 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); | 385 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); |
| 353 | wmb(); /* order is important here */ | 386 | wmb(); /* order is important here */ |
| 354 | 387 | ||
| @@ -363,7 +396,8 @@ static void wil_target_reset(struct wil6210_priv *wil) | |||
| 363 | } | 396 | } |
| 364 | } while (hw_state != HW_MACHINE_BOOT_DONE); | 397 | } while (hw_state != HW_MACHINE_BOOT_DONE); |
| 365 | 398 | ||
| 366 | if (rev_id == 2) | 399 | /* TODO: Erez check rev_id != 1 */ |
| 400 | if (!is_sparrow && (rev_id != 1)) | ||
| 367 | W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); | 401 | W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); |
| 368 | 402 | ||
| 369 | C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); | 403 | C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); |
| @@ -465,6 +499,7 @@ void wil_link_on(struct wil6210_priv *wil) | |||
| 465 | wil_dbg_misc(wil, "%s()\n", __func__); | 499 | wil_dbg_misc(wil, "%s()\n", __func__); |
| 466 | 500 | ||
| 467 | netif_carrier_on(ndev); | 501 | netif_carrier_on(ndev); |
| 502 | wil_dbg_misc(wil, "netif_tx_wake : link on\n"); | ||
| 468 | netif_tx_wake_all_queues(ndev); | 503 | netif_tx_wake_all_queues(ndev); |
| 469 | } | 504 | } |
| 470 | 505 | ||
| @@ -475,6 +510,7 @@ void wil_link_off(struct wil6210_priv *wil) | |||
| 475 | wil_dbg_misc(wil, "%s()\n", __func__); | 510 | wil_dbg_misc(wil, "%s()\n", __func__); |
| 476 | 511 | ||
| 477 | netif_tx_stop_all_queues(ndev); | 512 | netif_tx_stop_all_queues(ndev); |
| 513 | wil_dbg_misc(wil, "netif_tx_stop : link off\n"); | ||
| 478 | netif_carrier_off(ndev); | 514 | netif_carrier_off(ndev); |
| 479 | } | 515 | } |
| 480 | 516 | ||
| @@ -552,6 +588,8 @@ static int __wil_down(struct wil6210_priv *wil) | |||
| 552 | napi_disable(&wil->napi_tx); | 588 | napi_disable(&wil->napi_tx); |
| 553 | 589 | ||
| 554 | if (wil->scan_request) { | 590 | if (wil->scan_request) { |
| 591 | wil_dbg_misc(wil, "Abort scan_request 0x%p\n", | ||
| 592 | wil->scan_request); | ||
| 555 | del_timer_sync(&wil->scan_timer); | 593 | del_timer_sync(&wil->scan_timer); |
| 556 | cfg80211_scan_done(wil->scan_request, true); | 594 | cfg80211_scan_done(wil->scan_request, true); |
| 557 | wil->scan_request = NULL; | 595 | wil->scan_request = NULL; |
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 106b6dcb773a..7afce6e8c507 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c | |||
| @@ -132,7 +132,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) | |||
| 132 | ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; | 132 | ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; |
| 133 | cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); | 133 | cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); |
| 134 | 134 | ||
| 135 | ndev = alloc_netdev(0, "wlan%d", ether_setup); | 135 | ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, ether_setup); |
| 136 | if (!ndev) { | 136 | if (!ndev) { |
| 137 | dev_err(dev, "alloc_netdev_mqs failed\n"); | 137 | dev_err(dev, "alloc_netdev_mqs failed\n"); |
| 138 | rc = -ENOMEM; | 138 | rc = -ENOMEM; |
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 1e2e07b9d13d..d3fbfa28db62 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c | |||
| @@ -15,7 +15,6 @@ | |||
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 18 | #include <linux/debugfs.h> | ||
| 19 | #include <linux/pci.h> | 18 | #include <linux/pci.h> |
| 20 | #include <linux/moduleparam.h> | 19 | #include <linux/moduleparam.h> |
| 21 | 20 | ||
| @@ -27,11 +26,22 @@ MODULE_PARM_DESC(use_msi, | |||
| 27 | " Use MSI interrupt: " | 26 | " Use MSI interrupt: " |
| 28 | "0 - don't, 1 - (default) - single, or 3"); | 27 | "0 - don't, 1 - (default) - single, or 3"); |
| 29 | 28 | ||
| 29 | static bool debug_fw; /* = false; */ | ||
| 30 | module_param(debug_fw, bool, S_IRUGO); | ||
| 31 | MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug"); | ||
| 32 | |||
| 30 | /* Bus ops */ | 33 | /* Bus ops */ |
| 31 | static int wil_if_pcie_enable(struct wil6210_priv *wil) | 34 | static int wil_if_pcie_enable(struct wil6210_priv *wil) |
| 32 | { | 35 | { |
| 33 | struct pci_dev *pdev = wil->pdev; | 36 | struct pci_dev *pdev = wil->pdev; |
| 34 | int rc; | 37 | int rc; |
| 38 | /* on platforms with buggy ACPI, pdev->msi_enabled may be set to | ||
| 39 | * allow pci_enable_device to work. This indicates INTx was not routed | ||
| 40 | * and only MSI should be used | ||
| 41 | */ | ||
| 42 | int msi_only = pdev->msi_enabled; | ||
| 43 | |||
| 44 | pdev->msi_enabled = 0; | ||
| 35 | 45 | ||
| 36 | pci_set_master(pdev); | 46 | pci_set_master(pdev); |
| 37 | 47 | ||
| @@ -63,6 +73,12 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) | |||
| 63 | 73 | ||
| 64 | wil->n_msi = use_msi; | 74 | wil->n_msi = use_msi; |
| 65 | 75 | ||
| 76 | if ((wil->n_msi == 0) && msi_only) { | ||
| 77 | wil_err(wil, "Interrupt pin not routed, unable to use INTx\n"); | ||
| 78 | rc = -ENODEV; | ||
| 79 | goto stop_master; | ||
| 80 | } | ||
| 81 | |||
| 66 | rc = wil6210_init_irq(wil, pdev->irq); | 82 | rc = wil6210_init_irq(wil, pdev->irq); |
| 67 | if (rc) | 83 | if (rc) |
| 68 | goto stop_master; | 84 | goto stop_master; |
| @@ -71,6 +87,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) | |||
| 71 | mutex_lock(&wil->mutex); | 87 | mutex_lock(&wil->mutex); |
| 72 | rc = wil_reset(wil); | 88 | rc = wil_reset(wil); |
| 73 | mutex_unlock(&wil->mutex); | 89 | mutex_unlock(&wil->mutex); |
| 90 | if (debug_fw) | ||
| 91 | rc = 0; | ||
| 74 | if (rc) | 92 | if (rc) |
| 75 | goto release_irq; | 93 | goto release_irq; |
| 76 | 94 | ||
| @@ -104,10 +122,12 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 104 | struct wil6210_priv *wil; | 122 | struct wil6210_priv *wil; |
| 105 | struct device *dev = &pdev->dev; | 123 | struct device *dev = &pdev->dev; |
| 106 | void __iomem *csr; | 124 | void __iomem *csr; |
| 125 | struct wil_board *board = (struct wil_board *)id->driver_data; | ||
| 107 | int rc; | 126 | int rc; |
| 108 | 127 | ||
| 109 | /* check HW */ | 128 | /* check HW */ |
| 110 | dev_info(&pdev->dev, WIL_NAME " device found [%04x:%04x] (rev %x)\n", | 129 | dev_info(&pdev->dev, WIL_NAME |
| 130 | " \"%s\" device found [%04x:%04x] (rev %x)\n", board->name, | ||
| 111 | (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); | 131 | (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); |
| 112 | 132 | ||
| 113 | if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) { | 133 | if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) { |
| @@ -119,9 +139,16 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 119 | 139 | ||
| 120 | rc = pci_enable_device(pdev); | 140 | rc = pci_enable_device(pdev); |
| 121 | if (rc) { | 141 | if (rc) { |
| 122 | dev_err(&pdev->dev, "pci_enable_device failed\n"); | 142 | dev_err(&pdev->dev, |
| 123 | return -ENODEV; | 143 | "pci_enable_device failed, retry with MSI only\n"); |
| 144 | /* Work around for platforms that can't allocate IRQ: | ||
| 145 | * retry with MSI only | ||
| 146 | */ | ||
| 147 | pdev->msi_enabled = 1; | ||
| 148 | rc = pci_enable_device(pdev); | ||
| 124 | } | 149 | } |
| 150 | if (rc) | ||
| 151 | return -ENODEV; | ||
| 125 | /* rollback to err_disable_pdev */ | 152 | /* rollback to err_disable_pdev */ |
| 126 | 153 | ||
| 127 | rc = pci_request_region(pdev, 0, WIL_NAME); | 154 | rc = pci_request_region(pdev, 0, WIL_NAME); |
| @@ -150,6 +177,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 150 | 177 | ||
| 151 | pci_set_drvdata(pdev, wil); | 178 | pci_set_drvdata(pdev, wil); |
| 152 | wil->pdev = pdev; | 179 | wil->pdev = pdev; |
| 180 | wil->board = board; | ||
| 153 | 181 | ||
| 154 | wil6210_clear_irq(wil); | 182 | wil6210_clear_irq(wil); |
| 155 | /* FW should raise IRQ when ready */ | 183 | /* FW should raise IRQ when ready */ |
| @@ -200,8 +228,21 @@ static void wil_pcie_remove(struct pci_dev *pdev) | |||
| 200 | pci_disable_device(pdev); | 228 | pci_disable_device(pdev); |
| 201 | } | 229 | } |
| 202 | 230 | ||
| 203 | static DEFINE_PCI_DEVICE_TABLE(wil6210_pcie_ids) = { | 231 | static const struct wil_board wil_board_marlon = { |
| 204 | { PCI_DEVICE(0x1ae9, 0x0301) }, | 232 | .board = WIL_BOARD_MARLON, |
| 233 | .name = "marlon", | ||
| 234 | }; | ||
| 235 | |||
| 236 | static const struct wil_board wil_board_sparrow = { | ||
| 237 | .board = WIL_BOARD_SPARROW, | ||
| 238 | .name = "sparrow", | ||
| 239 | }; | ||
| 240 | |||
| 241 | static const struct pci_device_id wil6210_pcie_ids[] = { | ||
| 242 | { PCI_DEVICE(0x1ae9, 0x0301), | ||
| 243 | .driver_data = (kernel_ulong_t)&wil_board_marlon }, | ||
| 244 | { PCI_DEVICE(0x1ae9, 0x0310), | ||
| 245 | .driver_data = (kernel_ulong_t)&wil_board_sparrow }, | ||
| 205 | { /* end: all zeroes */ }, | 246 | { /* end: all zeroes */ }, |
| 206 | }; | 247 | }; |
| 207 | MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); | 248 | MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); |
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 747ae1275877..180ca4793904 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c | |||
| @@ -116,6 +116,7 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) | |||
| 116 | 116 | ||
| 117 | /* frame with out of date sequence number */ | 117 | /* frame with out of date sequence number */ |
| 118 | if (seq_less(seq, r->head_seq_num)) { | 118 | if (seq_less(seq, r->head_seq_num)) { |
| 119 | r->ssn_last_drop = seq; | ||
| 119 | dev_kfree_skb(skb); | 120 | dev_kfree_skb(skb); |
| 120 | goto out; | 121 | goto out; |
| 121 | } | 122 | } |
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 0784ef3d4ce2..d3467943d39d 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c | |||
| @@ -525,6 +525,17 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) | |||
| 525 | ndev->stats.rx_bytes += len; | 525 | ndev->stats.rx_bytes += len; |
| 526 | stats->rx_bytes += len; | 526 | stats->rx_bytes += len; |
| 527 | } | 527 | } |
| 528 | { | ||
| 529 | static const char * const gro_res_str[] = { | ||
| 530 | [GRO_MERGED] = "GRO_MERGED", | ||
| 531 | [GRO_MERGED_FREE] = "GRO_MERGED_FREE", | ||
| 532 | [GRO_HELD] = "GRO_HELD", | ||
| 533 | [GRO_NORMAL] = "GRO_NORMAL", | ||
| 534 | [GRO_DROP] = "GRO_DROP", | ||
| 535 | }; | ||
| 536 | wil_dbg_txrx(wil, "Rx complete %d bytes => %s,\n", | ||
| 537 | len, gro_res_str[rc]); | ||
| 538 | } | ||
| 528 | } | 539 | } |
| 529 | 540 | ||
| 530 | /** | 541 | /** |
| @@ -760,7 +771,7 @@ static struct vring *wil_tx_bcast(struct wil6210_priv *wil, | |||
| 760 | goto found; | 771 | goto found; |
| 761 | } | 772 | } |
| 762 | 773 | ||
| 763 | wil_err(wil, "Tx while no vrings active?\n"); | 774 | wil_dbg_txrx(wil, "Tx while no vrings active?\n"); |
| 764 | 775 | ||
| 765 | return NULL; | 776 | return NULL; |
| 766 | 777 | ||
| @@ -881,6 +892,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
| 881 | int nr_frags = skb_shinfo(skb)->nr_frags; | 892 | int nr_frags = skb_shinfo(skb)->nr_frags; |
| 882 | uint f = 0; | 893 | uint f = 0; |
| 883 | int vring_index = vring - wil->vring_tx; | 894 | int vring_index = vring - wil->vring_tx; |
| 895 | struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; | ||
| 884 | uint i = swhead; | 896 | uint i = swhead; |
| 885 | dma_addr_t pa; | 897 | dma_addr_t pa; |
| 886 | 898 | ||
| @@ -953,6 +965,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
| 953 | wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, | 965 | wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, |
| 954 | (const void *)d, sizeof(*d), false); | 966 | (const void *)d, sizeof(*d), false); |
| 955 | 967 | ||
| 968 | if (wil_vring_is_empty(vring)) /* performance monitoring */ | ||
| 969 | txdata->idle += get_cycles() - txdata->last_idle; | ||
| 970 | |||
| 956 | /* advance swhead */ | 971 | /* advance swhead */ |
| 957 | wil_vring_advance_head(vring, nr_frags + 1); | 972 | wil_vring_advance_head(vring, nr_frags + 1); |
| 958 | wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); | 973 | wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); |
| @@ -1016,15 +1031,17 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
| 1016 | vring = wil_tx_bcast(wil, skb); | 1031 | vring = wil_tx_bcast(wil, skb); |
| 1017 | } | 1032 | } |
| 1018 | if (!vring) { | 1033 | if (!vring) { |
| 1019 | wil_err(wil, "No Tx VRING found for %pM\n", eth->h_dest); | 1034 | wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest); |
| 1020 | goto drop; | 1035 | goto drop; |
| 1021 | } | 1036 | } |
| 1022 | /* set up vring entry */ | 1037 | /* set up vring entry */ |
| 1023 | rc = wil_tx_vring(wil, vring, skb); | 1038 | rc = wil_tx_vring(wil, vring, skb); |
| 1024 | 1039 | ||
| 1025 | /* do we still have enough room in the vring? */ | 1040 | /* do we still have enough room in the vring? */ |
| 1026 | if (wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring)) | 1041 | if (wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring)) { |
| 1027 | netif_tx_stop_all_queues(wil_to_ndev(wil)); | 1042 | netif_tx_stop_all_queues(wil_to_ndev(wil)); |
| 1043 | wil_dbg_txrx(wil, "netif_tx_stop : ring full\n"); | ||
| 1044 | } | ||
| 1028 | 1045 | ||
| 1029 | switch (rc) { | 1046 | switch (rc) { |
| 1030 | case 0: | 1047 | case 0: |
| @@ -1091,8 +1108,10 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) | |||
| 1091 | while (vring->swtail != new_swtail) { | 1108 | while (vring->swtail != new_swtail) { |
| 1092 | struct vring_tx_desc dd, *d = ⅆ | 1109 | struct vring_tx_desc dd, *d = ⅆ |
| 1093 | u16 dmalen; | 1110 | u16 dmalen; |
| 1094 | struct wil_ctx *ctx = &vring->ctx[vring->swtail]; | 1111 | struct sk_buff *skb; |
| 1095 | struct sk_buff *skb = ctx->skb; | 1112 | |
| 1113 | ctx = &vring->ctx[vring->swtail]; | ||
| 1114 | skb = ctx->skb; | ||
| 1096 | _d = &vring->va[vring->swtail].tx; | 1115 | _d = &vring->va[vring->swtail].tx; |
| 1097 | 1116 | ||
| 1098 | *d = *_d; | 1117 | *d = *_d; |
| @@ -1132,8 +1151,16 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) | |||
| 1132 | done++; | 1151 | done++; |
| 1133 | } | 1152 | } |
| 1134 | } | 1153 | } |
| 1135 | if (wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring)) | 1154 | |
| 1155 | if (wil_vring_is_empty(vring)) { /* performance monitoring */ | ||
| 1156 | wil_dbg_txrx(wil, "Ring[%2d] empty\n", ringid); | ||
| 1157 | txdata->last_idle = get_cycles(); | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | if (wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring)) { | ||
| 1161 | wil_dbg_txrx(wil, "netif_tx_wake : ring not full\n"); | ||
| 1136 | netif_tx_wake_all_queues(wil_to_ndev(wil)); | 1162 | netif_tx_wake_all_queues(wil_to_ndev(wil)); |
| 1163 | } | ||
| 1137 | 1164 | ||
| 1138 | return done; | 1165 | return done; |
| 1139 | } | 1166 | } |
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index e25edc52398f..67e9624f7111 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h | |||
| @@ -20,9 +20,17 @@ | |||
| 20 | #include <linux/netdevice.h> | 20 | #include <linux/netdevice.h> |
| 21 | #include <linux/wireless.h> | 21 | #include <linux/wireless.h> |
| 22 | #include <net/cfg80211.h> | 22 | #include <net/cfg80211.h> |
| 23 | #include <linux/timex.h> | ||
| 23 | 24 | ||
| 24 | #define WIL_NAME "wil6210" | 25 | #define WIL_NAME "wil6210" |
| 25 | 26 | ||
| 27 | struct wil_board { | ||
| 28 | int board; | ||
| 29 | #define WIL_BOARD_MARLON (1) | ||
| 30 | #define WIL_BOARD_SPARROW (2) | ||
| 31 | const char * const name; | ||
| 32 | }; | ||
| 33 | |||
| 26 | /** | 34 | /** |
| 27 | * extract bits [@b0:@b1] (inclusive) from the value @x | 35 | * extract bits [@b0:@b1] (inclusive) from the value @x |
| 28 | * it should be @b0 <= @b1, or result is incorrect | 36 | * it should be @b0 <= @b1, or result is incorrect |
| @@ -77,6 +85,7 @@ struct RGF_ICR { | |||
| 77 | } __packed; | 85 | } __packed; |
| 78 | 86 | ||
| 79 | /* registers - FW addresses */ | 87 | /* registers - FW addresses */ |
| 88 | #define RGF_USER_USAGE_1 (0x880004) | ||
| 80 | #define RGF_USER_HW_MACHINE_STATE (0x8801dc) | 89 | #define RGF_USER_HW_MACHINE_STATE (0x8801dc) |
| 81 | #define HW_MACHINE_BOOT_DONE (0x3fffffd) | 90 | #define HW_MACHINE_BOOT_DONE (0x3fffffd) |
| 82 | #define RGF_USER_USER_CPU_0 (0x8801e0) | 91 | #define RGF_USER_USER_CPU_0 (0x8801e0) |
| @@ -92,6 +101,7 @@ struct RGF_ICR { | |||
| 92 | #define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14) | 101 | #define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14) |
| 93 | #define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */ | 102 | #define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */ |
| 94 | #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) | 103 | #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) |
| 104 | #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0 (0x880c18) | ||
| 95 | 105 | ||
| 96 | #define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */ | 106 | #define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */ |
| 97 | #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) | 107 | #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) |
| @@ -120,6 +130,7 @@ struct RGF_ICR { | |||
| 120 | #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1) | 130 | #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1) |
| 121 | #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2) | 131 | #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2) |
| 122 | 132 | ||
| 133 | #define RGF_HP_CTRL (0x88265c) | ||
| 123 | #define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4) | 134 | #define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4) |
| 124 | 135 | ||
| 125 | /* popular locations */ | 136 | /* popular locations */ |
| @@ -134,6 +145,14 @@ struct RGF_ICR { | |||
| 134 | #define ISR_MISC_FW_ERROR BIT_DMA_EP_MISC_ICR_FW_INT(3) | 145 | #define ISR_MISC_FW_ERROR BIT_DMA_EP_MISC_ICR_FW_INT(3) |
| 135 | 146 | ||
| 136 | /* Hardware definitions end */ | 147 | /* Hardware definitions end */ |
| 148 | struct fw_map { | ||
| 149 | u32 from; /* linker address - from, inclusive */ | ||
| 150 | u32 to; /* linker address - to, exclusive */ | ||
| 151 | u32 host; /* PCI/Host address - BAR0 + 0x880000 */ | ||
| 152 | const char *name; /* for debugfs */ | ||
| 153 | }; | ||
| 154 | /* array size should be in sync with actual definition in the wmi.c */ | ||
| 155 | extern const struct fw_map fw_mapping[7]; | ||
| 137 | 156 | ||
| 138 | /** | 157 | /** |
| 139 | * mk_cidxtid - construct @cidxtid field | 158 | * mk_cidxtid - construct @cidxtid field |
| @@ -251,7 +270,7 @@ struct vring { | |||
| 251 | */ | 270 | */ |
| 252 | struct vring_tx_data { | 271 | struct vring_tx_data { |
| 253 | int enabled; | 272 | int enabled; |
| 254 | 273 | cycles_t idle, last_idle, begin; | |
| 255 | }; | 274 | }; |
| 256 | 275 | ||
| 257 | enum { /* for wil6210_priv.status */ | 276 | enum { /* for wil6210_priv.status */ |
| @@ -303,6 +322,7 @@ struct wil_tid_ampdu_rx { | |||
| 303 | u16 ssn; | 322 | u16 ssn; |
| 304 | u16 buf_size; | 323 | u16 buf_size; |
| 305 | u16 timeout; | 324 | u16 timeout; |
| 325 | u16 ssn_last_drop; | ||
| 306 | u8 dialog_token; | 326 | u8 dialog_token; |
| 307 | bool first_time; /* is it 1-st time this buffer used? */ | 327 | bool first_time; /* is it 1-st time this buffer used? */ |
| 308 | }; | 328 | }; |
| @@ -363,6 +383,7 @@ struct wil6210_priv { | |||
| 363 | ulong status; | 383 | ulong status; |
| 364 | u32 fw_version; | 384 | u32 fw_version; |
| 365 | u32 hw_version; | 385 | u32 hw_version; |
| 386 | struct wil_board *board; | ||
| 366 | u8 n_mids; /* number of additional MIDs as reported by FW */ | 387 | u8 n_mids; /* number of additional MIDs as reported by FW */ |
| 367 | int recovery_count; /* num of FW recovery attempts in a short time */ | 388 | int recovery_count; /* num of FW recovery attempts in a short time */ |
| 368 | unsigned long last_fw_recovery; /* jiffies of last fw recovery */ | 389 | unsigned long last_fw_recovery; /* jiffies of last fw recovery */ |
| @@ -410,14 +431,10 @@ struct wil6210_priv { | |||
| 410 | struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */ | 431 | struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */ |
| 411 | /* statistics */ | 432 | /* statistics */ |
| 412 | struct wil6210_stats stats; | 433 | struct wil6210_stats stats; |
| 434 | atomic_t isr_count_rx, isr_count_tx; | ||
| 413 | /* debugfs */ | 435 | /* debugfs */ |
| 414 | struct dentry *debug; | 436 | struct dentry *debug; |
| 415 | struct debugfs_blob_wrapper fw_code_blob; | 437 | struct debugfs_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)]; |
| 416 | struct debugfs_blob_wrapper fw_data_blob; | ||
| 417 | struct debugfs_blob_wrapper fw_peri_blob; | ||
| 418 | struct debugfs_blob_wrapper uc_code_blob; | ||
| 419 | struct debugfs_blob_wrapper uc_data_blob; | ||
| 420 | struct debugfs_blob_wrapper rgf_blob; | ||
| 421 | }; | 438 | }; |
| 422 | 439 | ||
| 423 | #define wil_to_wiphy(i) (i->wdev->wiphy) | 440 | #define wil_to_wiphy(i) (i->wdev->wiphy) |
| @@ -504,9 +521,14 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq); | |||
| 504 | void wil6210_fini_irq(struct wil6210_priv *wil, int irq); | 521 | void wil6210_fini_irq(struct wil6210_priv *wil, int irq); |
| 505 | void wil6210_disable_irq(struct wil6210_priv *wil); | 522 | void wil6210_disable_irq(struct wil6210_priv *wil); |
| 506 | void wil6210_enable_irq(struct wil6210_priv *wil); | 523 | void wil6210_enable_irq(struct wil6210_priv *wil); |
| 524 | int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
| 525 | struct cfg80211_mgmt_tx_params *params, | ||
| 526 | u64 *cookie); | ||
| 507 | 527 | ||
| 508 | int wil6210_debugfs_init(struct wil6210_priv *wil); | 528 | int wil6210_debugfs_init(struct wil6210_priv *wil); |
| 509 | void wil6210_debugfs_remove(struct wil6210_priv *wil); | 529 | void wil6210_debugfs_remove(struct wil6210_priv *wil); |
| 530 | int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, | ||
| 531 | struct station_info *sinfo); | ||
| 510 | 532 | ||
| 511 | struct wireless_dev *wil_cfg80211_init(struct device *dev); | 533 | struct wireless_dev *wil_cfg80211_init(struct device *dev); |
| 512 | void wil_wdev_free(struct wil6210_priv *wil); | 534 | void wil_wdev_free(struct wil6210_priv *wil); |
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 6cc0e182cc70..1d1d0afdd2e1 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c | |||
| @@ -65,17 +65,17 @@ | |||
| 65 | 65 | ||
| 66 | /** | 66 | /** |
| 67 | * @fw_mapping provides memory remapping table | 67 | * @fw_mapping provides memory remapping table |
| 68 | * | ||
| 69 | * array size should be in sync with the declaration in the wil6210.h | ||
| 68 | */ | 70 | */ |
| 69 | static const struct { | 71 | const struct fw_map fw_mapping[] = { |
| 70 | u32 from; /* linker address - from, inclusive */ | 72 | {0x000000, 0x040000, 0x8c0000, "fw_code"}, /* FW code RAM 256k */ |
| 71 | u32 to; /* linker address - to, exclusive */ | 73 | {0x800000, 0x808000, 0x900000, "fw_data"}, /* FW data RAM 32k */ |
| 72 | u32 host; /* PCI/Host address - BAR0 + 0x880000 */ | 74 | {0x840000, 0x860000, 0x908000, "fw_peri"}, /* periph. data RAM 128k */ |
| 73 | } fw_mapping[] = { | 75 | {0x880000, 0x88a000, 0x880000, "rgf"}, /* various RGF 40k */ |
| 74 | {0x000000, 0x040000, 0x8c0000}, /* FW code RAM 256k */ | 76 | {0x88a000, 0x88b000, 0x88a000, "AGC_tbl"}, /* AGC table 4k */ |
| 75 | {0x800000, 0x808000, 0x900000}, /* FW data RAM 32k */ | 77 | {0x88b000, 0x88c000, 0x88b000, "rgf_ext"}, /* Pcie_ext_rgf 4k */ |
| 76 | {0x840000, 0x860000, 0x908000}, /* peripheral data RAM 128k/96k used */ | 78 | {0x8c0000, 0x949000, 0x8c0000, "upper"}, /* upper area 548k */ |
| 77 | {0x880000, 0x88a000, 0x880000}, /* various RGF */ | ||
| 78 | {0x8c0000, 0x949000, 0x8c0000}, /* trivial mapping for upper area */ | ||
| 79 | /* | 79 | /* |
| 80 | * 920000..930000 ucode code RAM | 80 | * 920000..930000 ucode code RAM |
| 81 | * 930000..932000 ucode data RAM | 81 | * 930000..932000 ucode data RAM |
| @@ -327,6 +327,17 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) | |||
| 327 | 327 | ||
| 328 | if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) { | 328 | if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) { |
| 329 | struct cfg80211_bss *bss; | 329 | struct cfg80211_bss *bss; |
| 330 | u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp); | ||
| 331 | u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info); | ||
| 332 | u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int); | ||
| 333 | const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable; | ||
| 334 | size_t ie_len = d_len - offsetof(struct ieee80211_mgmt, | ||
| 335 | u.beacon.variable); | ||
| 336 | wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap); | ||
| 337 | wil_dbg_wmi(wil, "TSF : 0x%016llx\n", tsf); | ||
| 338 | wil_dbg_wmi(wil, "Beacon interval : %d\n", bi); | ||
| 339 | wil_hex_dump_wmi("IE ", DUMP_PREFIX_OFFSET, 16, 1, ie_buf, | ||
| 340 | ie_len, true); | ||
| 330 | 341 | ||
| 331 | bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame, | 342 | bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame, |
| 332 | d_len, signal, GFP_KERNEL); | 343 | d_len, signal, GFP_KERNEL); |
| @@ -351,6 +362,9 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, | |||
| 351 | bool aborted = (data->status != WMI_SCAN_SUCCESS); | 362 | bool aborted = (data->status != WMI_SCAN_SUCCESS); |
| 352 | 363 | ||
| 353 | wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); | 364 | wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); |
| 365 | wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n", | ||
| 366 | wil->scan_request, aborted); | ||
| 367 | |||
| 354 | del_timer_sync(&wil->scan_timer); | 368 | del_timer_sync(&wil->scan_timer); |
| 355 | cfg80211_scan_done(wil->scan_request, aborted); | 369 | cfg80211_scan_done(wil->scan_request, aborted); |
| 356 | wil->scan_request = NULL; | 370 | wil->scan_request = NULL; |
| @@ -668,14 +682,12 @@ void wmi_recv_cmd(struct wil6210_priv *wil) | |||
| 668 | 682 | ||
| 669 | for (n = 0;; n++) { | 683 | for (n = 0;; n++) { |
| 670 | u16 len; | 684 | u16 len; |
| 685 | bool q; | ||
| 671 | 686 | ||
| 672 | r->head = ioread32(wil->csr + HOST_MBOX + | 687 | r->head = ioread32(wil->csr + HOST_MBOX + |
| 673 | offsetof(struct wil6210_mbox_ctl, rx.head)); | 688 | offsetof(struct wil6210_mbox_ctl, rx.head)); |
| 674 | if (r->tail == r->head) { | 689 | if (r->tail == r->head) |
| 675 | if (n == 0) | 690 | break; |
| 676 | wil_dbg_wmi(wil, "No events?\n"); | ||
| 677 | return; | ||
| 678 | } | ||
| 679 | 691 | ||
| 680 | wil_dbg_wmi(wil, "Mbox head %08x tail %08x\n", | 692 | wil_dbg_wmi(wil, "Mbox head %08x tail %08x\n", |
| 681 | r->head, r->tail); | 693 | r->head, r->tail); |
| @@ -684,14 +696,14 @@ void wmi_recv_cmd(struct wil6210_priv *wil) | |||
| 684 | sizeof(struct wil6210_mbox_ring_desc)); | 696 | sizeof(struct wil6210_mbox_ring_desc)); |
| 685 | if (d_tail.sync == 0) { | 697 | if (d_tail.sync == 0) { |
| 686 | wil_err(wil, "Mbox evt not owned by FW?\n"); | 698 | wil_err(wil, "Mbox evt not owned by FW?\n"); |
| 687 | return; | 699 | break; |
| 688 | } | 700 | } |
| 689 | 701 | ||
| 690 | /* read cmd header from descriptor */ | 702 | /* read cmd header from descriptor */ |
| 691 | if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) { | 703 | if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) { |
| 692 | wil_err(wil, "Mbox evt at 0x%08x?\n", | 704 | wil_err(wil, "Mbox evt at 0x%08x?\n", |
| 693 | le32_to_cpu(d_tail.addr)); | 705 | le32_to_cpu(d_tail.addr)); |
| 694 | return; | 706 | break; |
| 695 | } | 707 | } |
| 696 | len = le16_to_cpu(hdr.len); | 708 | len = le16_to_cpu(hdr.len); |
| 697 | wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n", | 709 | wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n", |
| @@ -705,7 +717,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) | |||
| 705 | event.wmi) + len, 4), | 717 | event.wmi) + len, 4), |
| 706 | GFP_KERNEL); | 718 | GFP_KERNEL); |
| 707 | if (!evt) | 719 | if (!evt) |
| 708 | return; | 720 | break; |
| 709 | 721 | ||
| 710 | evt->event.hdr = hdr; | 722 | evt->event.hdr = hdr; |
| 711 | cmd = (void *)&evt->event.wmi; | 723 | cmd = (void *)&evt->event.wmi; |
| @@ -737,14 +749,11 @@ void wmi_recv_cmd(struct wil6210_priv *wil) | |||
| 737 | spin_lock_irqsave(&wil->wmi_ev_lock, flags); | 749 | spin_lock_irqsave(&wil->wmi_ev_lock, flags); |
| 738 | list_add_tail(&evt->list, &wil->pending_wmi_ev); | 750 | list_add_tail(&evt->list, &wil->pending_wmi_ev); |
| 739 | spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); | 751 | spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); |
| 740 | { | 752 | q = queue_work(wil->wmi_wq, &wil->wmi_event_worker); |
| 741 | int q = queue_work(wil->wmi_wq, | 753 | wil_dbg_wmi(wil, "queue_work -> %d\n", q); |
| 742 | &wil->wmi_event_worker); | ||
| 743 | wil_dbg_wmi(wil, "queue_work -> %d\n", q); | ||
| 744 | } | ||
| 745 | } | 754 | } |
| 746 | if (n > 1) | 755 | /* normally, 1 event per IRQ should be processed */ |
| 747 | wil_dbg_wmi(wil, "%s -> %d events processed\n", __func__, n); | 756 | wil_dbg_wmi(wil, "%s -> %d events queued\n", __func__, n); |
| 748 | } | 757 | } |
| 749 | 758 | ||
| 750 | int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, | 759 | int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, |
