diff options
author | Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> | 2015-03-15 10:00:23 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2015-03-20 02:33:23 -0400 |
commit | 41d6b093b7f8f2755a0a64ad4277c01bf78ced3e (patch) | |
tree | 3fa9b570c909db7ae9e4c8709d8aca7aee12d769 | |
parent | 62bfd30031faebcbf25db37bf228eeab0e25b2c3 (diff) |
wil6210: implement broadcast/multicast data
Use dedicated vring for multicast frames; this vring allocated for
AP and PBSS (both P2P GO and client) configurations
For short frames, use MCS0; for long - MCS1
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
-rw-r--r-- | drivers/net/wireless/ath/wil6210/cfg80211.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/debugfs.c | 18 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/main.c | 33 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/txrx.c | 175 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/wil6210.h | 6 |
5 files changed, 167 insertions, 76 deletions
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index c9f362c68c17..8f7596f60263 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c | |||
@@ -783,8 +783,17 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, | |||
783 | rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, | 783 | rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, |
784 | channel->hw_value); | 784 | channel->hw_value); |
785 | if (rc) | 785 | if (rc) |
786 | netif_carrier_off(ndev); | 786 | goto err_pcp_start; |
787 | 787 | ||
788 | rc = wil_bcast_init(wil); | ||
789 | if (rc) | ||
790 | goto err_bcast; | ||
791 | |||
792 | goto out; /* success */ | ||
793 | err_bcast: | ||
794 | wmi_pcp_stop(wil); | ||
795 | err_pcp_start: | ||
796 | netif_carrier_off(ndev); | ||
788 | out: | 797 | out: |
789 | mutex_unlock(&wil->mutex); | 798 | mutex_unlock(&wil->mutex); |
790 | return rc; | 799 | return rc; |
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index a42cb89ff725..bbc22d88f78f 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c | |||
@@ -121,12 +121,18 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) | |||
121 | 121 | ||
122 | snprintf(name, sizeof(name), "tx_%2d", i); | 122 | snprintf(name, sizeof(name), "tx_%2d", i); |
123 | 123 | ||
124 | seq_printf(s, | 124 | if (cid < WIL6210_MAX_CID) |
125 | "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %s\n", | 125 | seq_printf(s, |
126 | wil->sta[cid].addr, cid, tid, | 126 | "\n%pM CID %d TID %d BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n", |
127 | txdata->agg_wsize, txdata->agg_timeout, | 127 | wil->sta[cid].addr, cid, tid, |
128 | txdata->agg_amsdu ? "+" : "-", | 128 | txdata->agg_wsize, |
129 | used, avail, sidle); | 129 | txdata->agg_timeout, |
130 | txdata->agg_amsdu ? "+" : "-", | ||
131 | used, avail, sidle); | ||
132 | else | ||
133 | seq_printf(s, | ||
134 | "\nBroadcast [%3d|%3d] idle %s\n", | ||
135 | used, avail, sidle); | ||
130 | 136 | ||
131 | wil_print_vring(s, wil, name, vring, '_', 'H'); | 137 | wil_print_vring(s, wil, name, vring, '_', 'H'); |
132 | } | 138 | } |
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index a5fd605e52eb..c2a238426425 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c | |||
@@ -68,6 +68,7 @@ MODULE_PARM_DESC(mtu_max, " Max MTU value."); | |||
68 | 68 | ||
69 | static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT; | 69 | static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT; |
70 | static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT; | 70 | static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT; |
71 | static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT; | ||
71 | 72 | ||
72 | static int ring_order_set(const char *val, const struct kernel_param *kp) | 73 | static int ring_order_set(const char *val, const struct kernel_param *kp) |
73 | { | 74 | { |
@@ -216,6 +217,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, | |||
216 | switch (wdev->iftype) { | 217 | switch (wdev->iftype) { |
217 | case NL80211_IFTYPE_STATION: | 218 | case NL80211_IFTYPE_STATION: |
218 | case NL80211_IFTYPE_P2P_CLIENT: | 219 | case NL80211_IFTYPE_P2P_CLIENT: |
220 | wil_bcast_fini(wil); | ||
219 | netif_tx_stop_all_queues(ndev); | 221 | netif_tx_stop_all_queues(ndev); |
220 | netif_carrier_off(ndev); | 222 | netif_carrier_off(ndev); |
221 | 223 | ||
@@ -360,6 +362,35 @@ static int wil_find_free_vring(struct wil6210_priv *wil) | |||
360 | return -EINVAL; | 362 | return -EINVAL; |
361 | } | 363 | } |
362 | 364 | ||
365 | int wil_bcast_init(struct wil6210_priv *wil) | ||
366 | { | ||
367 | int ri = wil->bcast_vring, rc; | ||
368 | |||
369 | if ((ri >= 0) && wil->vring_tx[ri].va) | ||
370 | return 0; | ||
371 | |||
372 | ri = wil_find_free_vring(wil); | ||
373 | if (ri < 0) | ||
374 | return ri; | ||
375 | |||
376 | rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order); | ||
377 | if (rc == 0) | ||
378 | wil->bcast_vring = ri; | ||
379 | |||
380 | return rc; | ||
381 | } | ||
382 | |||
383 | void wil_bcast_fini(struct wil6210_priv *wil) | ||
384 | { | ||
385 | int ri = wil->bcast_vring; | ||
386 | |||
387 | if (ri < 0) | ||
388 | return; | ||
389 | |||
390 | wil->bcast_vring = -1; | ||
391 | wil_vring_fini_tx(wil, ri); | ||
392 | } | ||
393 | |||
363 | static void wil_connect_worker(struct work_struct *work) | 394 | static void wil_connect_worker(struct work_struct *work) |
364 | { | 395 | { |
365 | int rc; | 396 | int rc; |
@@ -407,6 +438,7 @@ int wil_priv_init(struct wil6210_priv *wil) | |||
407 | init_completion(&wil->wmi_call); | 438 | init_completion(&wil->wmi_call); |
408 | 439 | ||
409 | wil->pending_connect_cid = -1; | 440 | wil->pending_connect_cid = -1; |
441 | wil->bcast_vring = -1; | ||
410 | setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil); | 442 | setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil); |
411 | setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil); | 443 | setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil); |
412 | 444 | ||
@@ -656,6 +688,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) | |||
656 | 688 | ||
657 | cancel_work_sync(&wil->disconnect_worker); | 689 | cancel_work_sync(&wil->disconnect_worker); |
658 | wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); | 690 | wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); |
691 | wil_bcast_fini(wil); | ||
659 | 692 | ||
660 | /* prevent NAPI from being scheduled */ | 693 | /* prevent NAPI from being scheduled */ |
661 | bitmap_zero(wil->status, wil_status_last); | 694 | bitmap_zero(wil->status, wil_status_last); |
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 2453470bc191..1fe390f6d7d7 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c | |||
@@ -523,7 +523,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) | |||
523 | struct wireless_dev *wdev = wil_to_wdev(wil); | 523 | struct wireless_dev *wdev = wil_to_wdev(wil); |
524 | unsigned int len = skb->len; | 524 | unsigned int len = skb->len; |
525 | struct vring_rx_desc *d = wil_skb_rxdesc(skb); | 525 | struct vring_rx_desc *d = wil_skb_rxdesc(skb); |
526 | int cid = wil_rxdesc_cid(d); | 526 | int cid = wil_rxdesc_cid(d); /* always 0..7, no need to check */ |
527 | struct ethhdr *eth = (void *)skb->data; | 527 | struct ethhdr *eth = (void *)skb->data; |
528 | /* here looking for DA, not A1, thus Rxdesc's 'mcast' indication | 528 | /* here looking for DA, not A1, thus Rxdesc's 'mcast' indication |
529 | * is not suitable, need to look at data | 529 | * is not suitable, need to look at data |
@@ -749,6 +749,72 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, | |||
749 | return rc; | 749 | return rc; |
750 | } | 750 | } |
751 | 751 | ||
752 | int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size) | ||
753 | { | ||
754 | int rc; | ||
755 | struct wmi_bcast_vring_cfg_cmd cmd = { | ||
756 | .action = cpu_to_le32(WMI_VRING_CMD_ADD), | ||
757 | .vring_cfg = { | ||
758 | .tx_sw_ring = { | ||
759 | .max_mpdu_size = | ||
760 | cpu_to_le16(wil_mtu2macbuf(mtu_max)), | ||
761 | .ring_size = cpu_to_le16(size), | ||
762 | }, | ||
763 | .ringid = id, | ||
764 | .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, | ||
765 | }, | ||
766 | }; | ||
767 | struct { | ||
768 | struct wil6210_mbox_hdr_wmi wmi; | ||
769 | struct wmi_vring_cfg_done_event cmd; | ||
770 | } __packed reply; | ||
771 | struct vring *vring = &wil->vring_tx[id]; | ||
772 | struct vring_tx_data *txdata = &wil->vring_tx_data[id]; | ||
773 | |||
774 | wil_dbg_misc(wil, "%s() max_mpdu_size %d\n", __func__, | ||
775 | cmd.vring_cfg.tx_sw_ring.max_mpdu_size); | ||
776 | |||
777 | if (vring->va) { | ||
778 | wil_err(wil, "Tx ring [%d] already allocated\n", id); | ||
779 | rc = -EINVAL; | ||
780 | goto out; | ||
781 | } | ||
782 | |||
783 | memset(txdata, 0, sizeof(*txdata)); | ||
784 | spin_lock_init(&txdata->lock); | ||
785 | vring->size = size; | ||
786 | rc = wil_vring_alloc(wil, vring); | ||
787 | if (rc) | ||
788 | goto out; | ||
789 | |||
790 | wil->vring2cid_tid[id][0] = WIL6210_MAX_CID; /* CID */ | ||
791 | wil->vring2cid_tid[id][1] = 0; /* TID */ | ||
792 | |||
793 | cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); | ||
794 | |||
795 | rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, &cmd, sizeof(cmd), | ||
796 | WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100); | ||
797 | if (rc) | ||
798 | goto out_free; | ||
799 | |||
800 | if (reply.cmd.status != WMI_FW_STATUS_SUCCESS) { | ||
801 | wil_err(wil, "Tx config failed, status 0x%02x\n", | ||
802 | reply.cmd.status); | ||
803 | rc = -EINVAL; | ||
804 | goto out_free; | ||
805 | } | ||
806 | vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); | ||
807 | |||
808 | txdata->enabled = 1; | ||
809 | |||
810 | return 0; | ||
811 | out_free: | ||
812 | wil_vring_free(wil, vring, 1); | ||
813 | out: | ||
814 | |||
815 | return rc; | ||
816 | } | ||
817 | |||
752 | void wil_vring_fini_tx(struct wil6210_priv *wil, int id) | 818 | void wil_vring_fini_tx(struct wil6210_priv *wil, int id) |
753 | { | 819 | { |
754 | struct vring *vring = &wil->vring_tx[id]; | 820 | struct vring *vring = &wil->vring_tx[id]; |
@@ -772,7 +838,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) | |||
772 | memset(txdata, 0, sizeof(*txdata)); | 838 | memset(txdata, 0, sizeof(*txdata)); |
773 | } | 839 | } |
774 | 840 | ||
775 | static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, | 841 | static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil, |
776 | struct sk_buff *skb) | 842 | struct sk_buff *skb) |
777 | { | 843 | { |
778 | int i; | 844 | int i; |
@@ -805,15 +871,6 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, | |||
805 | return NULL; | 871 | return NULL; |
806 | } | 872 | } |
807 | 873 | ||
808 | static void wil_set_da_for_vring(struct wil6210_priv *wil, | ||
809 | struct sk_buff *skb, int vring_index) | ||
810 | { | ||
811 | struct ethhdr *eth = (void *)skb->data; | ||
812 | int cid = wil->vring2cid_tid[vring_index][0]; | ||
813 | |||
814 | memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN); | ||
815 | } | ||
816 | |||
817 | static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | 874 | static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, |
818 | struct sk_buff *skb); | 875 | struct sk_buff *skb); |
819 | 876 | ||
@@ -834,6 +891,9 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil, | |||
834 | continue; | 891 | continue; |
835 | 892 | ||
836 | cid = wil->vring2cid_tid[i][0]; | 893 | cid = wil->vring2cid_tid[i][0]; |
894 | if (cid >= WIL6210_MAX_CID) /* skip BCAST */ | ||
895 | continue; | ||
896 | |||
837 | if (!wil->sta[cid].data_port_open && | 897 | if (!wil->sta[cid].data_port_open && |
838 | (skb->protocol != cpu_to_be16(ETH_P_PAE))) | 898 | (skb->protocol != cpu_to_be16(ETH_P_PAE))) |
839 | break; | 899 | break; |
@@ -848,57 +908,17 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil, | |||
848 | return NULL; | 908 | return NULL; |
849 | } | 909 | } |
850 | 910 | ||
851 | /* | 911 | static struct vring *wil_find_tx_bcast(struct wil6210_priv *wil, |
852 | * Find 1-st vring and return it; set dest address for this vring in skb | 912 | struct sk_buff *skb) |
853 | * duplicate skb and send it to other active vrings | ||
854 | */ | ||
855 | static struct vring *wil_tx_bcast(struct wil6210_priv *wil, | ||
856 | struct sk_buff *skb) | ||
857 | { | 913 | { |
858 | struct vring *v, *v2; | 914 | struct vring *v; |
859 | struct sk_buff *skb2; | 915 | int i = wil->bcast_vring; |
860 | int i; | ||
861 | u8 cid; | ||
862 | |||
863 | /* find 1-st vring eligible for data */ | ||
864 | for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { | ||
865 | v = &wil->vring_tx[i]; | ||
866 | if (!v->va) | ||
867 | continue; | ||
868 | |||
869 | cid = wil->vring2cid_tid[i][0]; | ||
870 | if (!wil->sta[cid].data_port_open) | ||
871 | continue; | ||
872 | |||
873 | goto found; | ||
874 | } | ||
875 | |||
876 | wil_dbg_txrx(wil, "Tx while no vrings active?\n"); | ||
877 | |||
878 | return NULL; | ||
879 | |||
880 | found: | ||
881 | wil_dbg_txrx(wil, "BCAST -> ring %d\n", i); | ||
882 | wil_set_da_for_vring(wil, skb, i); | ||
883 | |||
884 | /* find other active vrings and duplicate skb for each */ | ||
885 | for (i++; i < WIL6210_MAX_TX_RINGS; i++) { | ||
886 | v2 = &wil->vring_tx[i]; | ||
887 | if (!v2->va) | ||
888 | continue; | ||
889 | cid = wil->vring2cid_tid[i][0]; | ||
890 | if (!wil->sta[cid].data_port_open) | ||
891 | continue; | ||
892 | 916 | ||
893 | skb2 = skb_copy(skb, GFP_ATOMIC); | 917 | if (i < 0) |
894 | if (skb2) { | 918 | return NULL; |
895 | wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i); | 919 | v = &wil->vring_tx[i]; |
896 | wil_set_da_for_vring(wil, skb2, i); | 920 | if (!v->va) |
897 | wil_tx_vring(wil, v2, skb2); | 921 | return NULL; |
898 | } else { | ||
899 | wil_err(wil, "skb_copy failed\n"); | ||
900 | } | ||
901 | } | ||
902 | 922 | ||
903 | return v; | 923 | return v; |
904 | } | 924 | } |
@@ -995,6 +1015,8 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
995 | uint i = swhead; | 1015 | uint i = swhead; |
996 | dma_addr_t pa; | 1016 | dma_addr_t pa; |
997 | int used; | 1017 | int used; |
1018 | bool mcast = (vring_index == wil->bcast_vring); | ||
1019 | uint len = skb_headlen(skb); | ||
998 | 1020 | ||
999 | wil_dbg_txrx(wil, "%s()\n", __func__); | 1021 | wil_dbg_txrx(wil, "%s()\n", __func__); |
1000 | 1022 | ||
@@ -1020,7 +1042,17 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
1020 | return -EINVAL; | 1042 | return -EINVAL; |
1021 | vring->ctx[i].mapped_as = wil_mapped_as_single; | 1043 | vring->ctx[i].mapped_as = wil_mapped_as_single; |
1022 | /* 1-st segment */ | 1044 | /* 1-st segment */ |
1023 | wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index); | 1045 | wil_tx_desc_map(d, pa, len, vring_index); |
1046 | if (unlikely(mcast)) { | ||
1047 | d->mac.d[0] |= BIT(MAC_CFG_DESC_TX_0_MCS_EN_POS); /* MCS 0 */ | ||
1048 | if (unlikely(len > WIL_BCAST_MCS0_LIMIT)) { | ||
1049 | /* set MCS 1 */ | ||
1050 | d->mac.d[0] |= (1 << MAC_CFG_DESC_TX_0_MCS_INDEX_POS); | ||
1051 | /* packet mode 2 */ | ||
1052 | d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_PKT_MODE_EN_POS) | | ||
1053 | (2 << MAC_CFG_DESC_TX_1_PKT_MODE_POS); | ||
1054 | } | ||
1055 | } | ||
1024 | /* Process TCP/UDP checksum offloading */ | 1056 | /* Process TCP/UDP checksum offloading */ |
1025 | if (unlikely(wil_tx_desc_offload_cksum_set(wil, d, skb))) { | 1057 | if (unlikely(wil_tx_desc_offload_cksum_set(wil, d, skb))) { |
1026 | wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n", | 1058 | wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n", |
@@ -1126,6 +1158,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
1126 | { | 1158 | { |
1127 | struct wil6210_priv *wil = ndev_to_wil(ndev); | 1159 | struct wil6210_priv *wil = ndev_to_wil(ndev); |
1128 | struct ethhdr *eth = (void *)skb->data; | 1160 | struct ethhdr *eth = (void *)skb->data; |
1161 | bool bcast = is_multicast_ether_addr(eth->h_dest); | ||
1129 | struct vring *vring; | 1162 | struct vring *vring; |
1130 | static bool pr_once_fw; | 1163 | static bool pr_once_fw; |
1131 | int rc; | 1164 | int rc; |
@@ -1153,10 +1186,8 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
1153 | /* in STA mode (ESS), all to same VRING */ | 1186 | /* in STA mode (ESS), all to same VRING */ |
1154 | vring = wil_find_tx_vring_sta(wil, skb); | 1187 | vring = wil_find_tx_vring_sta(wil, skb); |
1155 | } else { /* direct communication, find matching VRING */ | 1188 | } else { /* direct communication, find matching VRING */ |
1156 | if (is_unicast_ether_addr(eth->h_dest)) | 1189 | vring = bcast ? wil_find_tx_bcast(wil, skb) : |
1157 | vring = wil_find_tx_vring(wil, skb); | 1190 | wil_find_tx_ucast(wil, skb); |
1158 | else | ||
1159 | vring = wil_tx_bcast(wil, skb); | ||
1160 | } | 1191 | } |
1161 | if (unlikely(!vring)) { | 1192 | if (unlikely(!vring)) { |
1162 | wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest); | 1193 | wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest); |
@@ -1219,7 +1250,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) | |||
1219 | struct vring_tx_data *txdata = &wil->vring_tx_data[ringid]; | 1250 | struct vring_tx_data *txdata = &wil->vring_tx_data[ringid]; |
1220 | int done = 0; | 1251 | int done = 0; |
1221 | int cid = wil->vring2cid_tid[ringid][0]; | 1252 | int cid = wil->vring2cid_tid[ringid][0]; |
1222 | struct wil_net_stats *stats = &wil->sta[cid].stats; | 1253 | struct wil_net_stats *stats = NULL; |
1223 | volatile struct vring_tx_desc *_d; | 1254 | volatile struct vring_tx_desc *_d; |
1224 | int used_before_complete; | 1255 | int used_before_complete; |
1225 | int used_new; | 1256 | int used_new; |
@@ -1238,6 +1269,9 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) | |||
1238 | 1269 | ||
1239 | used_before_complete = wil_vring_used_tx(vring); | 1270 | used_before_complete = wil_vring_used_tx(vring); |
1240 | 1271 | ||
1272 | if (cid < WIL6210_MAX_CID) | ||
1273 | stats = &wil->sta[cid].stats; | ||
1274 | |||
1241 | while (!wil_vring_is_empty(vring)) { | 1275 | while (!wil_vring_is_empty(vring)) { |
1242 | int new_swtail; | 1276 | int new_swtail; |
1243 | struct wil_ctx *ctx = &vring->ctx[vring->swtail]; | 1277 | struct wil_ctx *ctx = &vring->ctx[vring->swtail]; |
@@ -1279,12 +1313,15 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) | |||
1279 | if (skb) { | 1313 | if (skb) { |
1280 | if (likely(d->dma.error == 0)) { | 1314 | if (likely(d->dma.error == 0)) { |
1281 | ndev->stats.tx_packets++; | 1315 | ndev->stats.tx_packets++; |
1282 | stats->tx_packets++; | ||
1283 | ndev->stats.tx_bytes += skb->len; | 1316 | ndev->stats.tx_bytes += skb->len; |
1284 | stats->tx_bytes += skb->len; | 1317 | if (stats) { |
1318 | stats->tx_packets++; | ||
1319 | stats->tx_bytes += skb->len; | ||
1320 | } | ||
1285 | } else { | 1321 | } else { |
1286 | ndev->stats.tx_errors++; | 1322 | ndev->stats.tx_errors++; |
1287 | stats->tx_errors++; | 1323 | if (stats) |
1324 | stats->tx_errors++; | ||
1288 | } | 1325 | } |
1289 | wil_consume_skb(skb, d->dma.error == 0); | 1326 | wil_consume_skb(skb, d->dma.error == 0); |
1290 | } | 1327 | } |
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index a6b096eb7dee..4310972c9e16 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h | |||
@@ -50,6 +50,8 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) | |||
50 | #define WIL_TX_Q_LEN_DEFAULT (4000) | 50 | #define WIL_TX_Q_LEN_DEFAULT (4000) |
51 | #define WIL_RX_RING_SIZE_ORDER_DEFAULT (10) | 51 | #define WIL_RX_RING_SIZE_ORDER_DEFAULT (10) |
52 | #define WIL_TX_RING_SIZE_ORDER_DEFAULT (10) | 52 | #define WIL_TX_RING_SIZE_ORDER_DEFAULT (10) |
53 | #define WIL_BCAST_RING_SIZE_ORDER_DEFAULT (7) | ||
54 | #define WIL_BCAST_MCS0_LIMIT (1024) /* limit for MCS0 frame size */ | ||
53 | /* limit ring size in range [32..32k] */ | 55 | /* limit ring size in range [32..32k] */ |
54 | #define WIL_RING_SIZE_ORDER_MIN (5) | 56 | #define WIL_RING_SIZE_ORDER_MIN (5) |
55 | #define WIL_RING_SIZE_ORDER_MAX (15) | 57 | #define WIL_RING_SIZE_ORDER_MAX (15) |
@@ -595,6 +597,7 @@ struct wil6210_priv { | |||
595 | struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS]; | 597 | struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS]; |
596 | u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ | 598 | u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ |
597 | struct wil_sta_info sta[WIL6210_MAX_CID]; | 599 | struct wil_sta_info sta[WIL6210_MAX_CID]; |
600 | int bcast_vring; | ||
598 | /* scan */ | 601 | /* scan */ |
599 | struct cfg80211_scan_request *scan_request; | 602 | struct cfg80211_scan_request *scan_request; |
600 | 603 | ||
@@ -757,6 +760,9 @@ void wil_rx_fini(struct wil6210_priv *wil); | |||
757 | int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, | 760 | int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, |
758 | int cid, int tid); | 761 | int cid, int tid); |
759 | void wil_vring_fini_tx(struct wil6210_priv *wil, int id); | 762 | void wil_vring_fini_tx(struct wil6210_priv *wil, int id); |
763 | int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size); | ||
764 | int wil_bcast_init(struct wil6210_priv *wil); | ||
765 | void wil_bcast_fini(struct wil6210_priv *wil); | ||
760 | 766 | ||
761 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); | 767 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); |
762 | int wil_tx_complete(struct wil6210_priv *wil, int ringid); | 768 | int wil_tx_complete(struct wil6210_priv *wil, int ringid); |