diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 7207a879e45d..bbffa989e554 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -99,6 +99,22 @@ static void wil_print_ring(struct seq_file *s, struct wil6210_priv *wil, v = (ring_id % 2 ? (v >> 16) : (v & 0xffff)); seq_printf(s, " hwhead = %u\n", v); + if (!ring->is_rx) { + struct wil_ring_tx_data *txdata = + &wil->ring_tx_data[ring_id]; + + seq_printf(s, " available = %d\n", + wil_ring_avail_tx(ring) - + txdata->tx_reserved_count); + seq_printf(s, " used = %d\n", + wil_ring_used_tx(ring)); + seq_printf(s, "\n tx_res_count = %d\n", + txdata->tx_reserved_count); + seq_printf(s, " tx_res_count_used = %d\n", + txdata->tx_reserved_count_used); + seq_printf(s, " tx_res_count_unavail = %d\n", + txdata->tx_reserved_count_not_avail); + } } seq_printf(s, " hwtail = [0x%08x] -> ", ring->hwtail); x = wmi_addr(wil, ring->hwtail); @@ -2461,6 +2477,7 @@ static const struct dbg_off dbg_wil_off[] = { WIL_FIELD(amsdu_en, 0644, doff_u8), WIL_FIELD(force_edmg_channel, 0644, doff_u8), WIL_FIELD(ap_ps, 0644, doff_u8), + WIL_FIELD(tx_reserved_entries, 0644, doff_u32), {}, }; diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index c5120d8c8455..ff95b1a02777 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1896,6 +1896,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ftm->rx_offset); } + wil->tx_reserved_entries = ((drop_if_ring_full || ac_queues) ? + WIL_DEFAULT_TX_RESERVED_ENTRIES : + 0); + if (wil->platform_ops.notify) { rc = wil->platform_ops.notify(wil->platform_handle, WIL_PLATFORM_EVT_FW_RDY); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 531e9a7403ba..406beb73cec4 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1161,7 +1161,8 @@ static int wil_tx_desc_map(union wil_tx_desc *desc, dma_addr_t pa, return 0; } -void wil_tx_data_init(struct wil_ring_tx_data *txdata) +void wil_tx_data_init(const struct wil6210_priv *wil, + struct wil_ring_tx_data *txdata) { spin_lock_bh(&txdata->lock); txdata->dot1x_open = 0; @@ -1174,6 +1175,9 @@ void wil_tx_data_init(struct wil_ring_tx_data *txdata) txdata->agg_amsdu = 0; txdata->addba_in_progress = false; txdata->mid = U8_MAX; + txdata->tx_reserved_count = wil->tx_reserved_entries; + txdata->tx_reserved_count_used = 0; + txdata->tx_reserved_count_not_avail = 0; spin_unlock_bh(&txdata->lock); } @@ -1228,7 +1232,7 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size, goto out; } - wil_tx_data_init(txdata); + wil_tx_data_init(wil, txdata); vring->is_rx = false; vring->size = size; rc = wil_vring_alloc(wil, vring); @@ -1397,7 +1401,7 @@ int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size) goto out; } - wil_tx_data_init(txdata); + wil_tx_data_init(wil, txdata); vring->is_rx = false; vring->size = size; rc = wil_vring_alloc(wil, vring); @@ -2038,6 +2042,20 @@ err_exit: return rc; } +static inline bool is_special_packet(const struct sk_buff *skb) +{ + if (skb->protocol == cpu_to_be16(ETH_P_ARP) || + skb->protocol == cpu_to_be16(ETH_P_RARP) || + (skb->protocol == cpu_to_be16(ETH_P_IP) && + ip_hdr(skb)->protocol == IPPROTO_ICMP) || + (skb->protocol == cpu_to_be16(ETH_P_IPV6) && + ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) || + skb->protocol == cpu_to_be16(ETH_P_PAE)) + return true; + + return false; +} + static int __wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif, struct wil_ring *ring, struct sk_buff *skb) { @@ -2045,7 +2063,6 @@ static int __wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif, struct vring_tx_desc dd, *d = ⅆ volatile struct vring_tx_desc *_d; u32 swhead = ring->swhead; - int avail = wil_ring_avail_tx(ring); int nr_frags = skb_shinfo(skb)->nr_frags; uint f = 0; int ring_index = ring - wil->ring_tx; @@ -2055,6 +2072,11 @@ static int __wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif, int used; bool mcast = (ring_index == vif->bcast_ring); uint len = skb_headlen(skb); + bool special_packet = (wil->tx_reserved_entries != 0 && + is_special_packet(skb)); + int avail = wil_ring_avail_tx(ring) - + (special_packet ? 0 : txdata->tx_reserved_count); + u8 ctx_flags = special_packet ? WIL_CTX_FLAG_RESERVED_USED : 0; wil_dbg_txrx(wil, "tx_ring: %d bytes to ring %d, nr_frags %d\n", skb->len, ring_index, nr_frags); @@ -2063,9 +2085,17 @@ static int __wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif, return -EINVAL; if (unlikely(avail < 1 + nr_frags)) { - wil_err_ratelimited(wil, - "Tx ring[%2d] full. No space for %d fragments\n", - ring_index, 1 + nr_frags); + if (special_packet) { + txdata->tx_reserved_count_not_avail++; + wil_err_ratelimited(wil, + "TX ring[%2d] full. No space for %d fragments for special packet. Tx-reserved-count is %d\n", + ring_index, 1 + nr_frags, + txdata->tx_reserved_count); + } else { + wil_err_ratelimited(wil, + "Tx ring[%2d] full. No space for %d fragments\n", + ring_index, 1 + nr_frags); + } return -ENOMEM; } _d = &ring->va[i].tx.legacy; @@ -2080,6 +2110,7 @@ static int __wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif, if (unlikely(dma_mapping_error(dev, pa))) return -EINVAL; ring->ctx[i].mapped_as = wil_mapped_as_single; + ring->ctx[i].flags = ctx_flags; /* 1-st segment */ wil->txrx_ops.tx_desc_map((union wil_tx_desc *)d, pa, len, ring_index); @@ -2117,6 +2148,8 @@ static int __wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif, goto dma_error; } ring->ctx[i].mapped_as = wil_mapped_as_page; + ring->ctx[i].flags = ctx_flags; + wil->txrx_ops.tx_desc_map((union wil_tx_desc *)d, pa, len, ring_index); /* no need to check return code - @@ -2149,6 +2182,14 @@ static int __wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif, ring_index, used, used + nr_frags + 1); } + if (special_packet) { + txdata->tx_reserved_count -= (f + 1); + txdata->tx_reserved_count_used += (f + 1); + wil_dbg_txrx(wil, + "Ring[%2d] tx_reserved_count: %d, reduced by %d\n", + ring_index, txdata->tx_reserved_count, f + 1); + } + /* Make sure to advance the head only after descriptor update is done. * This will prevent a race condition where the completion thread * will see the DU bit set from previous run and will handle the diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index d6e69926caa9..7aa1afe902d5 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -690,7 +690,8 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, int size, u16 ssn); void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, struct wil_tid_ampdu_rx *r); -void wil_tx_data_init(struct wil_ring_tx_data *txdata); +void wil_tx_data_init(const struct wil6210_priv *wil, + struct wil_ring_tx_data *txdata); void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil); void wil_tx_latency_calc(struct wil6210_priv *wil, struct sk_buff *skb, struct wil_sta_info *sta); diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index ec767b950215..ff6a740f3aab 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -750,7 +750,7 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id, "init TX ring: ring_id=%u, cid=%u, tid=%u, sring_id=%u\n", ring_id, cid, tid, wil->tx_sring_idx); - wil_tx_data_init(txdata); + wil_tx_data_init(wil, txdata); ring->size = size; rc = wil_ring_alloc_desc_ring(wil, ring, true); if (rc) @@ -1294,6 +1294,9 @@ int wil_tx_sring_handler(struct wil6210_priv *wil, (const void *)&msg, sizeof(msg), false); + if (ctx->flags & WIL_CTX_FLAG_RESERVED_USED) + txdata->tx_reserved_count++; + wil_tx_desc_unmap_edma(dev, (union wil_tx_desc *)d, ctx); @@ -1460,7 +1463,7 @@ static int __wil_tx_ring_tso_edma(struct wil6210_priv *wil, struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_index]; int nr_frags = skb_shinfo(skb)->nr_frags; int min_desc_required = nr_frags + 2; /* Headers, Head, Fragments */ - int used, avail = wil_ring_avail_tx(ring); + int used, avail = wil_ring_avail_tx(ring) - txdata->tx_reserved_count; int f, hdrlen, headlen; int gso_type; bool is_ipv4; @@ -1622,7 +1625,7 @@ static int wil_ring_init_bcast_edma(struct wil6210_vif *vif, int ring_id, wil_ipa_set_bcast_sring_id(wil, sring_id); } - wil_tx_data_init(txdata); + wil_tx_data_init(wil, txdata); ring->size = size; ring->is_rx = false; rc = wil_ring_alloc_desc_ring(wil, ring, true); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index e656890d4d77..8454c662f861 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -106,6 +106,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL6210_MAX_STATUS_RINGS (8) #define WIL6210_MAX_HEADROOM_SIZE (256) #define WIL_WMI_CALL_GENERAL_TO_MS 100 +#define WIL_DEFAULT_TX_RESERVED_ENTRIES (16) /* Hardware offload block adds the following: * 26 bytes - 3-address QoS data header @@ -515,13 +516,17 @@ enum { /* for wil_ctx.mapped_as */ wil_mapped_as_page = 2, }; +/* for wil_ctx.flags */ +#define WIL_CTX_FLAG_RESERVED_USED 0x01 + /** * struct wil_ctx - software context for ring descriptor */ struct wil_ctx { struct sk_buff *skb; u8 nr_frags; - u8 mapped_as; + u8 mapped_as:4; + u8 flags:4; }; struct wil_desc_ring_rx_swtail { /* relevant for enhanced DMA only */ @@ -655,6 +660,9 @@ struct wil_ring_tx_data { bool addba_in_progress; /* if set, agg_xxx is for request in progress */ u8 mid; spinlock_t lock; + u32 tx_reserved_count; /* available reserved tx entries */ + u32 tx_reserved_count_used; + u32 tx_reserved_count_not_avail; }; enum { /* for wil6210_priv.status */ @@ -1111,6 +1119,8 @@ struct wil6210_priv { struct work_struct pci_linkdown_recovery_worker; void *ipa_handle; + + u32 tx_reserved_entries; /* Used only in Talyn code-path */ }; #define wil_to_wiphy(i) (i->wiphy)