diff --git a/drivers/net/wireless/ath/wil6210/config.c b/drivers/net/wireless/ath/wil6210/config.c index 67ed36bec23c..6e47f458758b 100644 --- a/drivers/net/wireless/ath/wil6210/config.c +++ b/drivers/net/wireless/ath/wil6210/config.c @@ -209,6 +209,10 @@ static struct wil_config_entry config_table[] = { wil_ini_param_type_signed, &agg_wsize, 0, sizeof(agg_wsize), WIL_CONFIG_AGG_WSIZE_MIN, WIL_CONFIG_AGG_WSIZE_MAX), + WIL_CONFIG_INI_PARAM(WIL_CONFIG_AC_QUEUES_NAME, + wil_ini_param_type_unsigned, &ac_queues, 0, + WIL_CONFIG_BOOL_SIZE, WIL_CONFIG_BOOL_MIN, + WIL_CONFIG_BOOL_MAX), WIL_CONFIG_INI_PARAM(WIL_CONFIG_DROP_IF_FULL_NAME, wil_ini_param_type_unsigned, &drop_if_ring_full, 0, WIL_CONFIG_BOOL_SIZE, WIL_CONFIG_BOOL_MIN, 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/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 65ee11c44232..97b787cedcdb 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -12,10 +12,17 @@ #include "ipa.h" #include "config.h" +#define WIL6210_TX_QUEUES (4) + static bool alt_ifname; /* = false; */ module_param(alt_ifname, bool, 0444); MODULE_PARM_DESC(alt_ifname, " use an alternate interface name wigigN instead of wlanN"); +/* enable access category for transmit packets, this parameter may be controlled + * via wigig.ini config file, default enabled + */ +bool ac_queues = true; + bool wil_has_other_active_ifaces(struct wil6210_priv *wil, struct net_device *ndev, bool up, bool ok) { @@ -87,10 +94,44 @@ static int wil_stop(struct net_device *ndev) return rc; } +/** + * AC to queue mapping + * + * AC_VO -> queue 3 + * AC_VI -> queue 2 + * AC_BE -> queue 1 + * AC_BK -> queue 0 + */ +static u16 wil_select_queue(struct net_device *ndev, + struct sk_buff *skb, + struct net_device *sb_dev) +{ + static const u16 wil_1d_to_queue[8] = {1, 0, 0, 1, 2, 2, 3, 3}; + struct wil6210_priv *wil = ndev_to_wil(ndev); + u16 qid; + + if (!ac_queues) + return 0; + + /* determine the priority */ + if (wil_is_special_packet(skb)) + skb->priority = 7; + else if (skb->priority == 0 || skb->priority > 7) + skb->priority = cfg80211_classify8021d(skb, NULL); + + qid = wil_1d_to_queue[skb->priority]; + + wil_dbg_txrx(wil, "select queue for priority %d -> queue %d\n", + skb->priority, qid); + + return qid; +} + static const struct net_device_ops wil_netdev_ops = { .ndo_open = wil_open, .ndo_stop = wil_stop, .ndo_start_xmit = wil_start_xmit, + .ndo_select_queue = wil_select_queue, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, }; @@ -330,8 +371,12 @@ wil_vif_alloc(struct wil6210_priv *wil, const char *name, return ERR_PTR(-EINVAL); } - ndev = alloc_netdev(sizeof(*vif), name, name_assign_type, - wil_dev_setup); + if (ac_queues) + ndev = alloc_netdev_mqs(sizeof(*vif), name, name_assign_type, + wil_dev_setup, WIL6210_TX_QUEUES, 1); + else + ndev = alloc_netdev(sizeof(*vif), name, name_assign_type, + wil_dev_setup); if (!ndev) { dev_err(wil_to_dev(wil), "alloc_netdev failed\n"); return ERR_PTR(-ENOMEM); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 531e9a7403ba..ced6751f2def 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; } +bool wil_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 && + wil_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..d9e116ba8dce 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -690,10 +690,12 @@ 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); int wil_get_cid_by_ring(struct wil6210_priv *wil, struct wil_ring *ring); +bool wil_is_special_packet(const struct sk_buff *skb); #endif /* WIL6210_TXRX_H */ 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 f04887033199..8454c662f861 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -37,6 +37,7 @@ extern bool drop_if_ring_full; extern int n_msi; extern uint max_assoc_sta; extern bool drop_if_ring_full; +extern bool ac_queues; extern uint rx_ring_order; extern uint tx_ring_order; extern uint bcast_ring_order; @@ -105,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 @@ -514,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 */ @@ -654,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 */ @@ -1110,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) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 4b820bf65329..1aed102c2734 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -199,8 +199,8 @@ const struct fw_map talyn_mb_fw_mapping[] = { {0x8c0000, 0x8c0210, 0x8c0000, "dum_user_rgf", true, true}, /* DMA OFU 296b */ {0x8c2000, 0x8c2128, 0x8c2000, "dma_ofu", true, true}, - /* ucode debug 4k */ - {0x8c3000, 0x8c4000, 0x8c3000, "ucode_debug", true, true}, + /* ucode debug 256b */ + {0x8c3000, 0x8c3100, 0x8c3000, "ucode_debug", true, true}, /* upper area 1536k */ {0x900000, 0xa80000, 0x900000, "upper", true, true}, /* UCODE areas - accessible by debugfs blobs but not by