Commit 9202d7b6 authored by Maya Erez's avatar Maya Erez Committed by Kalle Valo

wil6210: add support for enhanced DMA TX data flows

The enhanced DMA TX data path is handled using a descriptor
ring per connection and a single status ring.

The driver gets TX completions via the TX status ring. Each
status message points to the completed descriptor ring and
includes the number of completed descriptors in this ring.

Non TSO enhanced DMA TX descriptors are similar to legacy DMA
TX descriptors, hence the same transmit function can be used.

However, enhanced DMA TSO frames division is performed by the
HW, hence a new function is added to handle enhanced DMA TSO.
Signed-off-by: default avatarGidon Studinski <gidons@codeaurora.org>
Signed-off-by: default avatarMaya Erez <merez@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 96c93589
......@@ -44,6 +44,7 @@
(~(BIT_DMA_EP_RX_ICR_RX_HTRSH)))
#define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \
BIT_DMA_EP_TX_ICR_TX_DONE_N(0))
#define WIL6210_IMC_TX_EDMA BIT_TX_STATUS_IRQ
#define WIL6210_IMC_MISC_NO_HALP (ISR_MISC_FW_READY | \
ISR_MISC_MBOX_EVT | \
ISR_MISC_FW_ERROR)
......@@ -87,6 +88,12 @@ static void wil6210_mask_irq_tx(struct wil6210_priv *wil)
WIL6210_IRQ_DISABLE);
}
static void wil6210_mask_irq_tx_edma(struct wil6210_priv *wil)
{
wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, IMS),
WIL6210_IRQ_DISABLE);
}
static void wil6210_mask_irq_rx(struct wil6210_priv *wil)
{
wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMS),
......@@ -125,6 +132,12 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
WIL6210_IMC_TX);
}
void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil)
{
wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, IMC),
WIL6210_IMC_TX_EDMA);
}
void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
{
bool unmask_rx_htrsh = atomic_read(&wil->connected_vifs) > 0;
......@@ -164,6 +177,7 @@ void wil_mask_irq(struct wil6210_priv *wil)
wil_dbg_irq(wil, "mask_irq\n");
wil6210_mask_irq_tx(wil);
wil6210_mask_irq_tx_edma(wil);
wil6210_mask_irq_rx(wil);
wil6210_mask_irq_misc(wil, true);
wil6210_mask_irq_pseudo(wil);
......@@ -179,10 +193,16 @@ void wil_unmask_irq(struct wil6210_priv *wil)
WIL_ICR_ICC_VALUE);
wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICC),
WIL_ICR_ICC_MISC_VALUE);
wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, ICC),
WIL_ICR_ICC_VALUE);
wil6210_unmask_irq_pseudo(wil);
wil6210_unmask_irq_tx(wil);
wil6210_unmask_irq_rx(wil);
if (wil->use_enhanced_dma_hw) {
wil6210_unmask_irq_tx_edma(wil);
} else {
wil6210_unmask_irq_tx(wil);
wil6210_unmask_irq_rx(wil);
}
wil6210_unmask_irq_misc(wil, true);
}
......@@ -315,6 +335,49 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
return IRQ_HANDLED;
}
static irqreturn_t wil6210_irq_tx_edma(int irq, void *cookie)
{
struct wil6210_priv *wil = cookie;
u32 isr = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_INT_GEN_TX_ICR) +
offsetof(struct RGF_ICR, ICR));
bool need_unmask = true;
trace_wil6210_irq_tx(isr);
wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
if (unlikely(!isr)) {
wil_err(wil, "spurious IRQ: TX\n");
return IRQ_NONE;
}
wil6210_mask_irq_tx_edma(wil);
if (likely(isr & BIT_TX_STATUS_IRQ)) {
wil_dbg_irq(wil, "TX status ring\n");
isr &= ~BIT_TX_STATUS_IRQ;
if (likely(test_bit(wil_status_fwready, wil->status))) {
wil_dbg_txrx(wil, "NAPI(Tx) schedule\n");
need_unmask = false;
napi_schedule(&wil->napi_tx);
} else {
wil_err(wil, "Got Tx status ring IRQ while in reset\n");
}
}
if (unlikely(isr))
wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr);
/* Tx IRQ will be enabled when NAPI processing finished */
atomic_inc(&wil->isr_count_tx);
if (unlikely(need_unmask))
wil6210_unmask_irq_tx_edma(wil);
return IRQ_HANDLED;
}
static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
{
struct wil6210_priv *wil = cookie;
......@@ -531,30 +594,45 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie)
*/
static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause)
{
u32 icm_rx = 0, icr_rx = 0, imv_rx = 0;
u32 icm_tx, icr_tx, imv_tx;
u32 icm_misc, icr_misc, imv_misc;
if (!test_bit(wil_status_irqen, wil->status)) {
u32 icm_rx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_RX_ICR) +
offsetof(struct RGF_ICR, ICM));
u32 icr_rx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_RX_ICR) +
offsetof(struct RGF_ICR, ICR));
u32 imv_rx = wil_r(wil, RGF_DMA_EP_RX_ICR +
offsetof(struct RGF_ICR, IMV));
u32 icm_tx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_TX_ICR) +
offsetof(struct RGF_ICR, ICM));
u32 icr_tx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_TX_ICR) +
offsetof(struct RGF_ICR, ICR));
u32 imv_tx = wil_r(wil, RGF_DMA_EP_TX_ICR +
if (wil->use_enhanced_dma_hw) {
icm_tx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_INT_GEN_TX_ICR) +
offsetof(struct RGF_ICR, ICM));
icr_tx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_INT_GEN_TX_ICR) +
offsetof(struct RGF_ICR, ICR));
imv_tx = wil_r(wil, RGF_INT_GEN_TX_ICR +
offsetof(struct RGF_ICR, IMV));
} else {
icm_rx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_RX_ICR) +
offsetof(struct RGF_ICR, ICM));
icr_rx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_RX_ICR) +
offsetof(struct RGF_ICR, ICR));
imv_rx = wil_r(wil, RGF_DMA_EP_RX_ICR +
offsetof(struct RGF_ICR, IMV));
u32 icm_misc = wil_ioread32_and_clear(wil->csr +
icm_tx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_TX_ICR) +
offsetof(struct RGF_ICR, ICM));
icr_tx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_TX_ICR) +
offsetof(struct RGF_ICR, ICR));
imv_tx = wil_r(wil, RGF_DMA_EP_TX_ICR +
offsetof(struct RGF_ICR, IMV));
}
icm_misc = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_MISC_ICR) +
offsetof(struct RGF_ICR, ICM));
u32 icr_misc = wil_ioread32_and_clear(wil->csr +
icr_misc = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_MISC_ICR) +
offsetof(struct RGF_ICR, ICR));
u32 imv_misc = wil_r(wil, RGF_DMA_EP_MISC_ICR +
imv_misc = wil_r(wil, RGF_DMA_EP_MISC_ICR +
offsetof(struct RGF_ICR, IMV));
/* HALP interrupt can be unmasked when misc interrupts are
......@@ -617,7 +695,7 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie)
rc = IRQ_WAKE_THREAD;
if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) &&
(wil6210_irq_tx(irq, cookie) == IRQ_WAKE_THREAD))
(wil->txrx_ops.irq_tx(irq, cookie) == IRQ_WAKE_THREAD))
rc = IRQ_WAKE_THREAD;
if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) &&
......@@ -645,6 +723,8 @@ void wil6210_clear_irq(struct wil6210_priv *wil)
offsetof(struct RGF_ICR, ICR));
wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) +
offsetof(struct RGF_ICR, ICR));
wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_TX_ICR) +
offsetof(struct RGF_ICR, ICR));
wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
offsetof(struct RGF_ICR, ICR));
wmb(); /* make sure write completed */
......@@ -673,6 +753,10 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi)
wil_dbg_misc(wil, "init_irq: %s\n", use_msi ? "MSI" : "INTx");
if (wil->use_enhanced_dma_hw)
wil->txrx_ops.irq_tx = wil6210_irq_tx_edma;
else
wil->txrx_ops.irq_tx = wil6210_irq_tx;
rc = request_threaded_irq(irq, wil6210_hardirq,
wil6210_thread_irq,
use_msi ? 0 : IRQF_SHARED,
......
......@@ -157,6 +157,30 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
return min(tx_done, budget);
}
static int wil6210_netdev_poll_tx_edma(struct napi_struct *napi, int budget)
{
struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
napi_tx);
int tx_done;
/* There is only one status TX ring */
struct wil_status_ring *sring = &wil->srings[wil->tx_sring_idx];
if (!sring->va)
return 0;
tx_done = wil_tx_sring_handler(wil, sring);
if (tx_done < budget) {
napi_complete(napi);
wil6210_unmask_irq_tx_edma(wil);
wil_dbg_txrx(wil, "NAPI TX complete\n");
}
wil_dbg_txrx(wil, "NAPI TX poll(%d) done %d\n", budget, tx_done);
return min(tx_done, budget);
}
static void wil_dev_setup(struct net_device *dev)
{
ether_setup(dev);
......@@ -420,9 +444,15 @@ int wil_if_add(struct wil6210_priv *wil)
init_dummy_netdev(&wil->napi_ndev);
netif_napi_add(&wil->napi_ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
WIL6210_NAPI_BUDGET);
netif_tx_napi_add(&wil->napi_ndev,
&wil->napi_tx, wil6210_netdev_poll_tx,
WIL6210_NAPI_BUDGET);
if (wil->use_enhanced_dma_hw)
netif_tx_napi_add(&wil->napi_ndev,
&wil->napi_tx, wil6210_netdev_poll_tx_edma,
WIL6210_NAPI_BUDGET);
else
netif_tx_napi_add(&wil->napi_ndev,
&wil->napi_tx, wil6210_netdev_poll_tx,
WIL6210_NAPI_BUDGET);
wil_update_net_queues_bh(wil, vif, NULL, true);
......
......@@ -226,6 +226,31 @@ TRACE_EVENT(wil6210_tx_done,
__entry->err)
);
TRACE_EVENT(wil6210_tx_status,
TP_PROTO(struct wil_ring_tx_status *msg, u16 index,
unsigned int len),
TP_ARGS(msg, index, len),
TP_STRUCT__entry(__field(u16, index)
__field(unsigned int, len)
__field(u8, num_descs)
__field(u8, ring_id)
__field(u8, status)
__field(u8, mcs)
),
TP_fast_assign(__entry->index = index;
__entry->len = len;
__entry->num_descs = msg->num_descriptors;
__entry->ring_id = msg->ring_id;
__entry->status = msg->status;
__entry->mcs = wil_tx_status_get_mcs(msg);
),
TP_printk(
"ring_id %d swtail 0x%x len %d num_descs %d status 0x%x mcs %d",
__entry->ring_id, __entry->index, __entry->len,
__entry->num_descs, __entry->status, __entry->mcs)
);
#endif /* WIL6210_TRACE_H || TRACE_HEADER_MULTI_READ*/
#if defined(CONFIG_WIL6210_TRACING) && !defined(__CHECKER__)
......
This diff is collapsed.
......@@ -555,6 +555,22 @@ static inline int wil_ring_is_full(struct wil_ring *ring)
return wil_ring_next_tail(ring) == ring->swhead;
}
static inline bool wil_need_txstat(struct sk_buff *skb)
{
struct ethhdr *eth = (void *)skb->data;
return is_unicast_ether_addr(eth->h_dest) && skb->sk &&
(skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS);
}
static inline void wil_consume_skb(struct sk_buff *skb, bool acked)
{
if (unlikely(wil_need_txstat(skb)))
skb_complete_wifi_ack(skb, acked);
else
acked ? dev_consume_skb_any(skb) : dev_kfree_skb_any(skb);
}
/* Used space in Tx ring */
static inline int wil_ring_used_tx(struct wil_ring *ring)
{
......@@ -576,6 +592,12 @@ static inline int wil_get_min_tx_ring_id(struct wil6210_priv *wil)
return wil->use_enhanced_dma_hw ? 1 : 0;
}
/* wil_val_in_range - check if value in [min,max) */
static inline bool wil_val_in_range(int val, int min, int max)
{
return val >= min && val < max;
}
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev);
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb);
void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif,
......
......@@ -38,6 +38,30 @@
#define WIL_EDMA_IDLE_TIME_LIMIT_USEC (50)
#define WIL_EDMA_TIME_UNIT_CLK_CYCLES (330) /* fits 1 usec */
#define WIL_EDMA_DESC_TX_MAC_CFG_0_QID_POS 16
#define WIL_EDMA_DESC_TX_MAC_CFG_0_QID_LEN 6
#define WIL_EDMA_DESC_TX_CFG_EOP_POS 0
#define WIL_EDMA_DESC_TX_CFG_EOP_LEN 1
#define WIL_EDMA_DESC_TX_CFG_TSO_DESC_TYPE_POS 3
#define WIL_EDMA_DESC_TX_CFG_TSO_DESC_TYPE_LEN 2
#define WIL_EDMA_DESC_TX_CFG_SEG_EN_POS 5
#define WIL_EDMA_DESC_TX_CFG_SEG_EN_LEN 1
#define WIL_EDMA_DESC_TX_CFG_INSERT_IP_CHKSUM_POS 6
#define WIL_EDMA_DESC_TX_CFG_INSERT_IP_CHKSUM_LEN 1
#define WIL_EDMA_DESC_TX_CFG_INSERT_TCP_CHKSUM_POS 7
#define WIL_EDMA_DESC_TX_CFG_INSERT_TCP_CHKSUM_LEN 1
#define WIL_EDMA_DESC_TX_CFG_L4_TYPE_POS 15
#define WIL_EDMA_DESC_TX_CFG_L4_TYPE_LEN 1
#define WIL_EDMA_DESC_TX_CFG_PSEUDO_HEADER_CALC_EN_POS 5
#define WIL_EDMA_DESC_TX_CFG_PSEUDO_HEADER_CALC_EN_LEN 1
/* Enhanced Rx descriptor - MAC part
* [dword 0] : Reserved
* [dword 1] : Reserved
......@@ -303,7 +327,12 @@ struct wil_rx_status_extension {
struct wil_rx_status_extended {
struct wil_rx_status_compressed comp;
struct wil_rx_status_extension ext;
};
} __packed;
static inline u8 wil_tx_status_get_mcs(struct wil_ring_tx_status *msg)
{
return WIL_GET_BITS(msg->d2, 0, 4);
}
static inline u32 wil_ring_next_head(struct wil_ring *ring)
{
......@@ -336,6 +365,8 @@ dma_addr_t wil_rx_desc_get_addr_edma(struct wil_ring_rx_enhanced_dma *dma)
}
void wil_configure_interrupt_moderation_edma(struct wil6210_priv *wil);
int wil_tx_sring_handler(struct wil6210_priv *wil,
struct wil_status_ring *sring);
void wil_init_txrx_ops_edma(struct wil6210_priv *wil);
#endif /* WIL6210_TXRX_EDMA_H */
......
......@@ -24,6 +24,7 @@
#include <net/cfg80211.h>
#include <linux/timex.h>
#include <linux/types.h>
#include <linux/irqreturn.h>
#include "wmi.h"
#include "wil_platform.h"
#include "fw.h"
......@@ -39,6 +40,7 @@ extern bool disable_ap_sme;
struct wil6210_priv;
struct wil6210_vif;
union wil_tx_desc;
#define WIL_NAME "wil6210"
......@@ -320,6 +322,10 @@ struct RGF_ICR {
#define RGF_INT_GEN_CTRL (0x8bc0ec)
#define BIT_CONTROL_0 BIT(0)
/* eDMA status interrupts */
#define RGF_INT_GEN_TX_ICR (0x8bc110)
#define BIT_TX_STATUS_IRQ BIT(WIL_TX_STATUS_IRQ_IDX)
#define RGF_INT_CTRL_TX_INT_MASK (0x8bc130)
#define RGF_INT_GEN_IDLE_TIME_LIMIT (0x8bc134)
#define USER_EXT_USER_PMU_3 (0x88d00c)
......@@ -540,6 +546,14 @@ struct wil_txrx_ops {
int (*ring_init_bcast)(struct wil6210_vif *vif, int id, int size);
int (*tx_init)(struct wil6210_priv *wil);
void (*tx_fini)(struct wil6210_priv *wil);
int (*tx_desc_map)(union wil_tx_desc *desc, dma_addr_t pa,
u32 len, int ring_index);
void (*tx_desc_unmap)(struct device *dev,
union wil_tx_desc *desc,
struct wil_ctx *ctx);
int (*tx_ring_tso)(struct wil6210_priv *wil, struct wil6210_vif *vif,
struct wil_ring *ring, struct sk_buff *skb);
irqreturn_t (*irq_tx)(int irq, void *cookie);
/* RX ops */
int (*rx_init)(struct wil6210_priv *wil, u16 ring_size);
void (*rx_fini)(struct wil6210_priv *wil);
......@@ -1226,6 +1240,7 @@ void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif,
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
int wil_tx_complete(struct wil6210_vif *vif, int ringid);
void wil6210_unmask_irq_tx(struct wil6210_priv *wil);
void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil);
/* RX API */
void wil_rx_handle(struct wil6210_priv *wil, int *quota);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment