diff options
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/txrx.c')
-rw-r--r-- | drivers/net/wireless/ath/wil6210/txrx.c | 81 |
1 files changed, 57 insertions, 24 deletions
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index b58ee52e1860..8439f65db259 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c | |||
@@ -671,6 +671,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, | |||
671 | } | 671 | } |
672 | 672 | ||
673 | memset(txdata, 0, sizeof(*txdata)); | 673 | memset(txdata, 0, sizeof(*txdata)); |
674 | spin_lock_init(&txdata->lock); | ||
674 | vring->size = size; | 675 | vring->size = size; |
675 | rc = wil_vring_alloc(wil, vring); | 676 | rc = wil_vring_alloc(wil, vring); |
676 | if (rc) | 677 | if (rc) |
@@ -718,8 +719,10 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) | |||
718 | 719 | ||
719 | wil_dbg_misc(wil, "%s() id=%d\n", __func__, id); | 720 | wil_dbg_misc(wil, "%s() id=%d\n", __func__, id); |
720 | 721 | ||
722 | spin_lock_bh(&txdata->lock); | ||
723 | txdata->enabled = 0; /* no Tx can be in progress or start anew */ | ||
724 | spin_unlock_bh(&txdata->lock); | ||
721 | /* make sure NAPI won't touch this vring */ | 725 | /* make sure NAPI won't touch this vring */ |
722 | wil->vring_tx_data[id].enabled = 0; | ||
723 | if (test_bit(wil_status_napi_en, wil->status)) | 726 | if (test_bit(wil_status_napi_en, wil->status)) |
724 | napi_synchronize(&wil->napi_tx); | 727 | napi_synchronize(&wil->napi_tx); |
725 | 728 | ||
@@ -873,9 +876,6 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, | |||
873 | d->mac.d[1] = 0; | 876 | d->mac.d[1] = 0; |
874 | d->mac.d[2] = 0; | 877 | d->mac.d[2] = 0; |
875 | d->mac.ucode_cmd = 0; | 878 | d->mac.ucode_cmd = 0; |
876 | /* use dst index 0 */ | ||
877 | d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS) | | ||
878 | (0 << MAC_CFG_DESC_TX_1_DST_INDEX_POS); | ||
879 | /* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */ | 879 | /* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */ |
880 | d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) | | 880 | d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) | |
881 | (1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS); | 881 | (1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS); |
@@ -938,8 +938,8 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, | |||
938 | return 0; | 938 | return 0; |
939 | } | 939 | } |
940 | 940 | ||
941 | static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | 941 | static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, |
942 | struct sk_buff *skb) | 942 | struct sk_buff *skb) |
943 | { | 943 | { |
944 | struct device *dev = wil_to_dev(wil); | 944 | struct device *dev = wil_to_dev(wil); |
945 | struct vring_tx_desc dd, *d = ⅆ | 945 | struct vring_tx_desc dd, *d = ⅆ |
@@ -955,18 +955,21 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
955 | 955 | ||
956 | wil_dbg_txrx(wil, "%s()\n", __func__); | 956 | wil_dbg_txrx(wil, "%s()\n", __func__); |
957 | 957 | ||
958 | if (unlikely(!txdata->enabled)) | ||
959 | return -EINVAL; | ||
960 | |||
958 | if (avail < 1 + nr_frags) { | 961 | if (avail < 1 + nr_frags) { |
959 | wil_err_ratelimited(wil, | 962 | wil_err_ratelimited(wil, |
960 | "Tx ring full. No space for %d fragments\n", | 963 | "Tx ring[%2d] full. No space for %d fragments\n", |
961 | 1 + nr_frags); | 964 | vring_index, 1 + nr_frags); |
962 | return -ENOMEM; | 965 | return -ENOMEM; |
963 | } | 966 | } |
964 | _d = &vring->va[i].tx; | 967 | _d = &vring->va[i].tx; |
965 | 968 | ||
966 | pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); | 969 | pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); |
967 | 970 | ||
968 | wil_dbg_txrx(wil, "Tx skb %d bytes 0x%p -> %pad\n", skb_headlen(skb), | 971 | wil_dbg_txrx(wil, "Tx[%2d] skb %d bytes 0x%p -> %pad\n", vring_index, |
969 | skb->data, &pa); | 972 | skb_headlen(skb), skb->data, &pa); |
970 | wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1, | 973 | wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1, |
971 | skb->data, skb_headlen(skb), false); | 974 | skb->data, skb_headlen(skb), false); |
972 | 975 | ||
@@ -977,15 +980,13 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
977 | wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index); | 980 | wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index); |
978 | /* Process TCP/UDP checksum offloading */ | 981 | /* Process TCP/UDP checksum offloading */ |
979 | if (wil_tx_desc_offload_cksum_set(wil, d, skb)) { | 982 | if (wil_tx_desc_offload_cksum_set(wil, d, skb)) { |
980 | wil_err(wil, "VRING #%d Failed to set cksum, drop packet\n", | 983 | wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n", |
981 | vring_index); | 984 | vring_index); |
982 | goto dma_error; | 985 | goto dma_error; |
983 | } | 986 | } |
984 | 987 | ||
985 | vring->ctx[i].nr_frags = nr_frags; | 988 | vring->ctx[i].nr_frags = nr_frags; |
986 | wil_tx_desc_set_nr_frags(d, nr_frags); | 989 | wil_tx_desc_set_nr_frags(d, nr_frags); |
987 | if (nr_frags) | ||
988 | *_d = *d; | ||
989 | 990 | ||
990 | /* middle segments */ | 991 | /* middle segments */ |
991 | for (; f < nr_frags; f++) { | 992 | for (; f < nr_frags; f++) { |
@@ -993,6 +994,10 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
993 | &skb_shinfo(skb)->frags[f]; | 994 | &skb_shinfo(skb)->frags[f]; |
994 | int len = skb_frag_size(frag); | 995 | int len = skb_frag_size(frag); |
995 | 996 | ||
997 | *_d = *d; | ||
998 | wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i); | ||
999 | wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4, | ||
1000 | (const void *)d, sizeof(*d), false); | ||
996 | i = (swhead + f + 1) % vring->size; | 1001 | i = (swhead + f + 1) % vring->size; |
997 | _d = &vring->va[i].tx; | 1002 | _d = &vring->va[i].tx; |
998 | pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), | 1003 | pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), |
@@ -1006,13 +1011,15 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
1006 | * it will succeed here too | 1011 | * it will succeed here too |
1007 | */ | 1012 | */ |
1008 | wil_tx_desc_offload_cksum_set(wil, d, skb); | 1013 | wil_tx_desc_offload_cksum_set(wil, d, skb); |
1009 | *_d = *d; | ||
1010 | } | 1014 | } |
1011 | /* for the last seg only */ | 1015 | /* for the last seg only */ |
1012 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); | 1016 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); |
1013 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_MARK_WB_POS); | 1017 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_MARK_WB_POS); |
1014 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); | 1018 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); |
1015 | *_d = *d; | 1019 | *_d = *d; |
1020 | wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i); | ||
1021 | wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4, | ||
1022 | (const void *)d, sizeof(*d), false); | ||
1016 | 1023 | ||
1017 | /* hold reference to skb | 1024 | /* hold reference to skb |
1018 | * to prevent skb release before accounting | 1025 | * to prevent skb release before accounting |
@@ -1020,15 +1027,13 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
1020 | */ | 1027 | */ |
1021 | vring->ctx[i].skb = skb_get(skb); | 1028 | vring->ctx[i].skb = skb_get(skb); |
1022 | 1029 | ||
1023 | wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, | ||
1024 | (const void *)d, sizeof(*d), false); | ||
1025 | |||
1026 | if (wil_vring_is_empty(vring)) /* performance monitoring */ | 1030 | if (wil_vring_is_empty(vring)) /* performance monitoring */ |
1027 | txdata->idle += get_cycles() - txdata->last_idle; | 1031 | txdata->idle += get_cycles() - txdata->last_idle; |
1028 | 1032 | ||
1029 | /* advance swhead */ | 1033 | /* advance swhead */ |
1030 | wil_vring_advance_head(vring, nr_frags + 1); | 1034 | wil_vring_advance_head(vring, nr_frags + 1); |
1031 | wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); | 1035 | wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", vring_index, swhead, |
1036 | vring->swhead); | ||
1032 | trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags); | 1037 | trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags); |
1033 | iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); | 1038 | iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); |
1034 | 1039 | ||
@@ -1055,6 +1060,19 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
1055 | return -EINVAL; | 1060 | return -EINVAL; |
1056 | } | 1061 | } |
1057 | 1062 | ||
1063 | static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | ||
1064 | struct sk_buff *skb) | ||
1065 | { | ||
1066 | int vring_index = vring - wil->vring_tx; | ||
1067 | struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; | ||
1068 | int rc; | ||
1069 | |||
1070 | spin_lock(&txdata->lock); | ||
1071 | rc = __wil_tx_vring(wil, vring, skb); | ||
1072 | spin_unlock(&txdata->lock); | ||
1073 | return rc; | ||
1074 | } | ||
1075 | |||
1058 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | 1076 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) |
1059 | { | 1077 | { |
1060 | struct wil6210_priv *wil = ndev_to_wil(ndev); | 1078 | struct wil6210_priv *wil = ndev_to_wil(ndev); |
@@ -1121,6 +1139,22 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
1121 | return NET_XMIT_DROP; | 1139 | return NET_XMIT_DROP; |
1122 | } | 1140 | } |
1123 | 1141 | ||
1142 | static inline bool wil_need_txstat(struct sk_buff *skb) | ||
1143 | { | ||
1144 | struct ethhdr *eth = (void *)skb->data; | ||
1145 | |||
1146 | return is_unicast_ether_addr(eth->h_dest) && skb->sk && | ||
1147 | (skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS); | ||
1148 | } | ||
1149 | |||
1150 | static inline void wil_consume_skb(struct sk_buff *skb, bool acked) | ||
1151 | { | ||
1152 | if (unlikely(wil_need_txstat(skb))) | ||
1153 | skb_complete_wifi_ack(skb, acked); | ||
1154 | else | ||
1155 | acked ? dev_consume_skb_any(skb) : dev_kfree_skb_any(skb); | ||
1156 | } | ||
1157 | |||
1124 | /** | 1158 | /** |
1125 | * Clean up transmitted skb's from the Tx VRING | 1159 | * Clean up transmitted skb's from the Tx VRING |
1126 | * | 1160 | * |
@@ -1181,10 +1215,10 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) | |||
1181 | trace_wil6210_tx_done(ringid, vring->swtail, dmalen, | 1215 | trace_wil6210_tx_done(ringid, vring->swtail, dmalen, |
1182 | d->dma.error); | 1216 | d->dma.error); |
1183 | wil_dbg_txrx(wil, | 1217 | wil_dbg_txrx(wil, |
1184 | "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", | 1218 | "TxC[%2d][%3d] : %d bytes, status 0x%02x err 0x%02x\n", |
1185 | vring->swtail, dmalen, d->dma.status, | 1219 | ringid, vring->swtail, dmalen, |
1186 | d->dma.error); | 1220 | d->dma.status, d->dma.error); |
1187 | wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, | 1221 | wil_hex_dump_txrx("TxCD ", DUMP_PREFIX_NONE, 32, 4, |
1188 | (const void *)d, sizeof(*d), false); | 1222 | (const void *)d, sizeof(*d), false); |
1189 | 1223 | ||
1190 | wil_txdesc_unmap(dev, d, ctx); | 1224 | wil_txdesc_unmap(dev, d, ctx); |
@@ -1199,8 +1233,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) | |||
1199 | ndev->stats.tx_errors++; | 1233 | ndev->stats.tx_errors++; |
1200 | stats->tx_errors++; | 1234 | stats->tx_errors++; |
1201 | } | 1235 | } |
1202 | 1236 | wil_consume_skb(skb, d->dma.error == 0); | |
1203 | dev_kfree_skb_any(skb); | ||
1204 | } | 1237 | } |
1205 | memset(ctx, 0, sizeof(*ctx)); | 1238 | memset(ctx, 0, sizeof(*ctx)); |
1206 | /* There is no need to touch HW descriptor: | 1239 | /* There is no need to touch HW descriptor: |