Commit 7be13fc3 authored by Gidon Studinski's avatar Gidon Studinski Committed by Kalle Valo

wil6210: add support for enhanced DMA RX data flows

Enhanced DMA RX data path is handled using a single
RX descriptor ring for all VIFs.
Multiple RX status rings are supported, to allow RSS
and multi MSI support.
The driver gets the RX completions via the RX status rings.
The RX status message includes the completed RX buffer ID,
which points to the allocated SKB.

The enhanced DMA RX data flow supports RX chaining, where
multiple SKBs are merged into a single packet.

Enhanced DMA HW supports RX HW reorder offload, enabled by
default for Talyn-MB.

amsdu_en debugfs entry was added to allow control MSDU aggregation.
Use the following command to disable AMSDU (enabled by default):
echo 0 > amsdu_en
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 9202d7b6
......@@ -1919,6 +1919,7 @@ static const struct dbg_off dbg_wil_off[] = {
WIL_FIELD(rx_status_ring_order, 0644, doff_u32),
WIL_FIELD(tx_status_ring_order, 0644, doff_u32),
WIL_FIELD(rx_buff_id_count, 0644, doff_u32),
WIL_FIELD(amsdu_en, 0644, doff_u8),
{},
};
......
......@@ -45,6 +45,7 @@
#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_RX_EDMA BIT_RX_STATUS_IRQ
#define WIL6210_IMC_MISC_NO_HALP (ISR_MISC_FW_READY | \
ISR_MISC_MBOX_EVT | \
ISR_MISC_FW_ERROR)
......@@ -100,6 +101,12 @@ static void wil6210_mask_irq_rx(struct wil6210_priv *wil)
WIL6210_IRQ_DISABLE);
}
static void wil6210_mask_irq_rx_edma(struct wil6210_priv *wil)
{
wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, IMS),
WIL6210_IRQ_DISABLE);
}
static void wil6210_mask_irq_misc(struct wil6210_priv *wil, bool mask_halp)
{
wil_dbg_irq(wil, "mask_irq_misc: mask_halp(%s)\n",
......@@ -146,6 +153,12 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH);
}
void wil6210_unmask_irq_rx_edma(struct wil6210_priv *wil)
{
wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, IMC),
WIL6210_IMC_RX_EDMA);
}
static void wil6210_unmask_irq_misc(struct wil6210_priv *wil, bool unmask_halp)
{
wil_dbg_irq(wil, "unmask_irq_misc: unmask_halp(%s)\n",
......@@ -179,6 +192,7 @@ void wil_mask_irq(struct wil6210_priv *wil)
wil6210_mask_irq_tx(wil);
wil6210_mask_irq_tx_edma(wil);
wil6210_mask_irq_rx(wil);
wil6210_mask_irq_rx_edma(wil);
wil6210_mask_irq_misc(wil, true);
wil6210_mask_irq_pseudo(wil);
}
......@@ -195,10 +209,13 @@ void wil_unmask_irq(struct wil6210_priv *wil)
WIL_ICR_ICC_MISC_VALUE);
wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, ICC),
WIL_ICR_ICC_VALUE);
wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, ICC),
WIL_ICR_ICC_VALUE);
wil6210_unmask_irq_pseudo(wil);
if (wil->use_enhanced_dma_hw) {
wil6210_unmask_irq_tx_edma(wil);
wil6210_unmask_irq_rx_edma(wil);
} else {
wil6210_unmask_irq_tx(wil);
wil6210_unmask_irq_rx(wil);
......@@ -335,6 +352,54 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
return IRQ_HANDLED;
}
static irqreturn_t wil6210_irq_rx_edma(int irq, void *cookie)
{
struct wil6210_priv *wil = cookie;
u32 isr = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_INT_GEN_RX_ICR) +
offsetof(struct RGF_ICR, ICR));
bool need_unmask = true;
trace_wil6210_irq_rx(isr);
wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
if (unlikely(!isr)) {
wil_err(wil, "spurious IRQ: RX\n");
return IRQ_NONE;
}
wil6210_mask_irq_rx_edma(wil);
if (likely(isr & BIT_RX_STATUS_IRQ)) {
wil_dbg_irq(wil, "RX status ring\n");
isr &= ~BIT_RX_STATUS_IRQ;
if (likely(test_bit(wil_status_fwready, wil->status))) {
if (likely(test_bit(wil_status_napi_en, wil->status))) {
wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
need_unmask = false;
napi_schedule(&wil->napi_rx);
} else {
wil_err(wil,
"Got Rx interrupt while stopping interface\n");
}
} else {
wil_err(wil, "Got Rx interrupt while in reset\n");
}
}
if (unlikely(isr))
wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr);
/* Rx IRQ will be enabled when NAPI processing finished */
atomic_inc(&wil->isr_count_rx);
if (unlikely(need_unmask))
wil6210_unmask_irq_rx_edma(wil);
return IRQ_HANDLED;
}
static irqreturn_t wil6210_irq_tx_edma(int irq, void *cookie)
{
struct wil6210_priv *wil = cookie;
......@@ -594,12 +659,20 @@ 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_rx, icr_rx, imv_rx;
u32 icm_tx, icr_tx, imv_tx;
u32 icm_misc, icr_misc, imv_misc;
if (!test_bit(wil_status_irqen, wil->status)) {
if (wil->use_enhanced_dma_hw) {
icm_rx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_INT_GEN_RX_ICR) +
offsetof(struct RGF_ICR, ICM));
icr_rx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_INT_GEN_RX_ICR) +
offsetof(struct RGF_ICR, ICR));
imv_rx = wil_r(wil, RGF_INT_GEN_RX_ICR +
offsetof(struct RGF_ICR, IMV));
icm_tx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_INT_GEN_TX_ICR) +
offsetof(struct RGF_ICR, ICM));
......@@ -691,7 +764,7 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie)
* voting for wake thread - need at least 1 vote
*/
if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) &&
(wil6210_irq_rx(irq, cookie) == IRQ_WAKE_THREAD))
(wil->txrx_ops.irq_rx(irq, cookie) == IRQ_WAKE_THREAD))
rc = IRQ_WAKE_THREAD;
if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) &&
......@@ -723,6 +796,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_RX_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) +
......@@ -753,10 +828,13 @@ 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)
if (wil->use_enhanced_dma_hw) {
wil->txrx_ops.irq_tx = wil6210_irq_tx_edma;
else
wil->txrx_ops.irq_rx = wil6210_irq_rx_edma;
} else {
wil->txrx_ops.irq_tx = wil6210_irq_tx;
wil->txrx_ops.irq_rx = wil6210_irq_rx;
}
rc = request_threaded_irq(irq, wil6210_hardirq,
wil6210_thread_irq,
use_msi ? 0 : IRQF_SHARED,
......
......@@ -632,6 +632,7 @@ int wil_priv_init(struct wil6210_priv *wil)
/* edma configuration can be updated via debugfs before allocation */
wil->num_rx_status_rings = WIL_DEFAULT_NUM_RX_STATUS_RINGS;
wil->use_compressed_rx_status = true;
wil->use_rx_hw_reordering = true;
wil->tx_status_ring_order = WIL_TX_SRING_SIZE_ORDER_DEFAULT;
/* Rx status ring size should be bigger than the number of RX buffers
......@@ -645,6 +646,8 @@ int wil_priv_init(struct wil6210_priv *wil)
*/
wil->rx_buff_id_count = WIL_RX_BUFF_ARR_SIZE_DEFAULT;
wil->amsdu_en = 1;
return 0;
out_wmi_wq:
......
......@@ -120,6 +120,27 @@ static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget)
return done;
}
static int wil6210_netdev_poll_rx_edma(struct napi_struct *napi, int budget)
{
struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
napi_rx);
int quota = budget;
int done;
wil_rx_handle_edma(wil, &quota);
done = budget - quota;
if (done < budget) {
napi_complete_done(napi, done);
wil6210_unmask_irq_rx_edma(wil);
wil_dbg_txrx(wil, "NAPI RX complete\n");
}
wil_dbg_txrx(wil, "NAPI RX poll(%d) done %d\n", budget, done);
return done;
}
static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
{
struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
......@@ -442,17 +463,21 @@ 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);
if (wil->use_enhanced_dma_hw)
if (wil->use_enhanced_dma_hw) {
netif_napi_add(&wil->napi_ndev, &wil->napi_rx,
wil6210_netdev_poll_rx_edma,
WIL6210_NAPI_BUDGET);
netif_tx_napi_add(&wil->napi_ndev,
&wil->napi_tx, wil6210_netdev_poll_tx_edma,
WIL6210_NAPI_BUDGET);
else
} else {
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);
}
wil_update_net_queues_bh(wil, vif, NULL, true);
......
......@@ -103,6 +103,7 @@ int wil_set_capabilities(struct wil6210_priv *wil)
wil->rgf_ucode_assert_code_addr = TALYN_RGF_UCODE_ASSERT_CODE;
set_bit(hw_capa_no_flash, wil->hw_capa);
wil->use_enhanced_dma_hw = true;
wil->use_rx_hw_reordering = true;
break;
default:
wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n",
......
......@@ -211,7 +211,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
goto reject_suspend;
}
if (!wil_is_rx_idle(wil)) {
if (!wil->txrx_ops.is_rx_idle(wil)) {
wil_dbg_pm(wil, "Pending RX data, reject suspend\n");
wil->suspend_stats.rejected_by_host++;
goto reject_suspend;
......@@ -235,9 +235,9 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
start = jiffies;
data_comp_to = jiffies + msecs_to_jiffies(WIL_DATA_COMPLETION_TO_MS);
if (test_bit(wil_status_napi_en, wil->status)) {
while (!wil_is_rx_idle(wil)) {
while (!wil->txrx_ops.is_rx_idle(wil)) {
if (time_after(jiffies, data_comp_to)) {
if (wil_is_rx_idle(wil))
if (wil->txrx_ops.is_rx_idle(wil))
break;
wil_err(wil,
"TO waiting for idle RX, suspend failed\n");
......
......@@ -95,17 +95,17 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
{
struct wil6210_vif *vif;
struct net_device *ndev;
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
int tid = wil_rxdesc_tid(d);
int cid = wil_rxdesc_cid(d);
int mid = wil_rxdesc_mid(d);
u16 seq = wil_rxdesc_seq(d);
int mcast = wil_rxdesc_mcast(d);
struct wil_sta_info *sta = &wil->sta[cid];
int tid, cid, mid, mcast;
u16 seq;
struct wil_sta_info *sta;
struct wil_tid_ampdu_rx *r;
u16 hseq;
int index;
wil->txrx_ops.get_reorder_params(wil, skb, &tid, &cid, &mid, &seq,
&mcast);
sta = &wil->sta[cid];
wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n",
mid, cid, tid, seq, mcast);
......@@ -315,7 +315,10 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
* bits 6..15: buffer size
*/
u16 req_agg_wsize = WIL_GET_BITS(param_set, 6, 15);
bool agg_amsdu = !!(param_set & BIT(0));
bool agg_amsdu = wil->use_enhanced_dma_hw &&
wil->use_rx_hw_reordering &&
test_bit(WMI_FW_CAPABILITY_AMSDU, wil->fw_capabilities) &&
wil->amsdu_en && (param_set & BIT(0));
int ba_policy = param_set & BIT(1);
u16 status = WLAN_STATUS_SUCCESS;
u16 ssn = seq_ctrl >> 4;
......@@ -360,8 +363,9 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
}
}
rc = wmi_addba_rx_resp(wil, mid, cid, tid, dialog_token, status,
agg_amsdu, agg_wsize, agg_timeout);
rc = wil->txrx_ops.wmi_addba_rx_resp(wil, mid, cid, tid, dialog_token,
status, agg_amsdu, agg_wsize,
agg_timeout);
if (rc || (status != WLAN_STATUS_SUCCESS)) {
wil_err(wil, "do not apply ba, rc(%d), status(%d)\n", rc,
status);
......
......@@ -187,6 +187,40 @@ TRACE_EVENT(wil6210_rx,
__entry->seq, __entry->type, __entry->subtype)
);
TRACE_EVENT(wil6210_rx_status,
TP_PROTO(struct wil6210_priv *wil, u8 use_compressed, u16 buff_id,
void *msg),
TP_ARGS(wil, use_compressed, buff_id, msg),
TP_STRUCT__entry(__field(u8, use_compressed)
__field(u16, buff_id)
__field(unsigned int, len)
__field(u8, mid)
__field(u8, cid)
__field(u8, tid)
__field(u8, type)
__field(u8, subtype)
__field(u16, seq)
__field(u8, mcs)
),
TP_fast_assign(__entry->use_compressed = use_compressed;
__entry->buff_id = buff_id;
__entry->len = wil_rx_status_get_length(msg);
__entry->mid = wil_rx_status_get_mid(msg);
__entry->cid = wil_rx_status_get_cid(msg);
__entry->tid = wil_rx_status_get_tid(msg);
__entry->type = wil_rx_status_get_frame_type(wil,
msg);
__entry->subtype = wil_rx_status_get_fc1(wil, msg);
__entry->seq = wil_rx_status_get_seq(wil, msg);
__entry->mcs = wil_rx_status_get_mcs(msg);
),
TP_printk(
"compressed %d buff_id %d len %d mid %d cid %d tid %d mcs %d seq 0x%03x type 0x%1x subtype 0x%1x",
__entry->use_compressed, __entry->buff_id, __entry->len,
__entry->mid, __entry->cid, __entry->tid, __entry->mcs,
__entry->seq, __entry->type, __entry->subtype)
);
TRACE_EVENT(wil6210_tx,
TP_PROTO(u8 vring, u16 index, unsigned int len, u8 frags),
TP_ARGS(vring, index, len, frags),
......
......@@ -28,6 +28,7 @@
#include "wmi.h"
#include "txrx.h"
#include "trace.h"
#include "txrx_edma.h"
static bool rtap_include_phy_info;
module_param(rtap_include_phy_info, bool, 0444);
......@@ -407,14 +408,7 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
}
}
/* similar to ieee80211_ version, but FC contain only 1-st byte */
static inline int wil_is_back_req(u8 fc)
{
return (fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) ==
(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK_REQ);
}
bool wil_is_rx_idle(struct wil6210_priv *wil)
static bool wil_is_rx_idle(struct wil6210_priv *wil)
{
struct vring_rx_desc *_d;
struct wil_ring *ring = &wil->ring_rx;
......@@ -639,7 +633,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count)
* Cut'n'paste from original memcmp (see lib/string.c)
* with minimal modifications
*/
static int reverse_memcmp(const void *cs, const void *ct, size_t count)
int reverse_memcmp(const void *cs, const void *ct, size_t count)
{
const unsigned char *su1, *su2;
int res = 0;
......@@ -684,6 +678,15 @@ static int wil_rx_crypto_check(struct wil6210_priv *wil, struct sk_buff *skb)
return 0;
}
static void wil_get_netif_rx_params(struct sk_buff *skb, int *cid,
int *security)
{
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
*cid = wil_rxdesc_cid(d); /* always 0..7, no need to check */
*security = wil_rxdesc_security(d);
}
/*
* Pass Rx packet to the netif. Update statistics.
* Called in softirq context (NAPI poll).
......@@ -695,15 +698,14 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
struct wil6210_priv *wil = ndev_to_wil(ndev);
struct wireless_dev *wdev = vif_to_wdev(vif);
unsigned int len = skb->len;
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
int cid = wil_rxdesc_cid(d); /* always 0..7, no need to check */
int security = wil_rxdesc_security(d);
int cid;
int security;
struct ethhdr *eth = (void *)skb->data;
/* here looking for DA, not A1, thus Rxdesc's 'mcast' indication
* is not suitable, need to look at data
*/
int mcast = is_multicast_ether_addr(eth->h_dest);
struct wil_net_stats *stats = &wil->sta[cid].stats;
struct wil_net_stats *stats;
struct sk_buff *xmit_skb = NULL;
static const char * const gro_res_str[] = {
[GRO_MERGED] = "GRO_MERGED",
......@@ -713,6 +715,10 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
[GRO_DROP] = "GRO_DROP",
};
wil->txrx_ops.get_netif_rx_params(skb, &cid, &security);
stats = &wil->sta[cid].stats;
if (ndev->features & NETIF_F_RXHASH)
/* fake L4 to ensure it won't be re-calculated later
* set hash to any non-zero value to activate rps
......@@ -723,7 +729,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
skb_orphan(skb);
if (security && (wil_rx_crypto_check(wil, skb) != 0)) {
if (security && (wil->txrx_ops.rx_crypto_check(wil, skb) != 0)) {
rc = GRO_DROP;
dev_kfree_skb(skb);
stats->rx_replay++;
......@@ -2172,6 +2178,19 @@ static inline int wil_tx_init(struct wil6210_priv *wil)
static inline void wil_tx_fini(struct wil6210_priv *wil) {}
static void wil_get_reorder_params(struct wil6210_priv *wil,
struct sk_buff *skb, int *tid, int *cid,
int *mid, u16 *seq, int *mcast)
{
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
*tid = wil_rxdesc_tid(d);
*cid = wil_rxdesc_cid(d);
*mid = wil_rxdesc_mid(d);
*seq = wil_rxdesc_seq(d);
*mcast = wil_rxdesc_mcast(d);
}
void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil)
{
wil->txrx_ops.configure_interrupt_moderation =
......@@ -2187,5 +2206,11 @@ void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil)
wil->txrx_ops.tx_fini = wil_tx_fini;
/* RX ops */
wil->txrx_ops.rx_init = wil_rx_init;
wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp;
wil->txrx_ops.get_reorder_params = wil_get_reorder_params;
wil->txrx_ops.get_netif_rx_params =
wil_get_netif_rx_params;
wil->txrx_ops.rx_crypto_check = wil_rx_crypto_check;
wil->txrx_ops.is_rx_idle = wil_is_rx_idle;
wil->txrx_ops.rx_fini = wil_rx_fini;
}
......@@ -592,6 +592,13 @@ static inline int wil_get_min_tx_ring_id(struct wil6210_priv *wil)
return wil->use_enhanced_dma_hw ? 1 : 0;
}
/* similar to ieee80211_ version, but FC contain only 1-st byte */
static inline int wil_is_back_req(u8 fc)
{
return (fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) ==
(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK_REQ);
}
/* wil_val_in_range - check if value in [min,max) */
static inline bool wil_val_in_range(int val, int min, int max)
{
......
......@@ -38,6 +38,27 @@
#define WIL_EDMA_IDLE_TIME_LIMIT_USEC (50)
#define WIL_EDMA_TIME_UNIT_CLK_CYCLES (330) /* fits 1 usec */
/* Error field */
#define WIL_RX_EDMA_ERROR_MIC (1)
#define WIL_RX_EDMA_ERROR_KEY (2) /* Key missing */
#define WIL_RX_EDMA_ERROR_REPLAY (3)
#define WIL_RX_EDMA_ERROR_AMSDU (4)
#define WIL_RX_EDMA_ERROR_FCS (7)
#define WIL_RX_EDMA_ERROR_L3_ERR (BIT(0) | BIT(1))
#define WIL_RX_EDMA_ERROR_L4_ERR (BIT(0) | BIT(1))
#define WIL_RX_EDMA_DLPF_LU_MISS_BIT BIT(11)
#define WIL_RX_EDMA_DLPF_LU_MISS_CID_TID_MASK 0x7
#define WIL_RX_EDMA_DLPF_LU_HIT_CID_TID_MASK 0xf
#define WIL_RX_EDMA_DLPF_LU_MISS_CID_POS 2
#define WIL_RX_EDMA_DLPF_LU_HIT_CID_POS 4
#define WIL_RX_EDMA_DLPF_LU_MISS_TID_POS 5
#define WIL_RX_EDMA_MID_VALID_BIT BIT(22)
#define WIL_EDMA_DESC_TX_MAC_CFG_0_QID_POS 16
#define WIL_EDMA_DESC_TX_MAC_CFG_0_QID_LEN 6
......@@ -329,6 +350,173 @@ struct wil_rx_status_extended {
struct wil_rx_status_extension ext;
} __packed;
static inline void *wil_skb_rxstatus(struct sk_buff *skb)
{
return (void *)skb->cb;
}
static inline __le16 wil_rx_status_get_length(void *msg)
{
return ((struct wil_rx_status_compressed *)msg)->length;
}
static inline u8 wil_rx_status_get_mcs(void *msg)
{
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d1,
16, 21);
}
static inline u16 wil_rx_status_get_flow_id(void *msg)
{
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
8, 19);
}
static inline u8 wil_rx_status_get_mcast(void *msg)
{
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
26, 26);
}
/**
* In case of DLPF miss the parsing of flow Id should be as follows:
* dest_id:2
* src_id :3 - cid
* tid:3
* Otherwise:
* tid:4
* cid:4
*/
static inline u8 wil_rx_status_get_cid(void *msg)
{
u16 val = wil_rx_status_get_flow_id(msg);
if (val & WIL_RX_EDMA_DLPF_LU_MISS_BIT)
/* CID is in bits 2..4 */
return (val >> WIL_RX_EDMA_DLPF_LU_MISS_CID_POS) &
WIL_RX_EDMA_DLPF_LU_MISS_CID_TID_MASK;
else
/* CID is in bits 4..7 */
return (val >> WIL_RX_EDMA_DLPF_LU_HIT_CID_POS) &
WIL_RX_EDMA_DLPF_LU_HIT_CID_TID_MASK;
}
static inline u8 wil_rx_status_get_tid(void *msg)
{
u16 val = wil_rx_status_get_flow_id(msg);
if (val & WIL_RX_EDMA_DLPF_LU_MISS_BIT)
/* TID is in bits 5..7 */
return (val >> WIL_RX_EDMA_DLPF_LU_MISS_TID_POS) &
WIL_RX_EDMA_DLPF_LU_MISS_CID_TID_MASK;
else
/* TID is in bits 0..3 */
return val & WIL_RX_EDMA_DLPF_LU_MISS_CID_TID_MASK;
}
static inline int wil_rx_status_get_desc_rdy_bit(void *msg)
{
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
31, 31);
}
static inline int wil_rx_status_get_eop(void *msg) /* EoP = End of Packet */
{
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
30, 30);
}
static inline __le16 wil_rx_status_get_buff_id(void *msg)
{
return ((struct wil_rx_status_compressed *)msg)->buff_id;
}
static inline u8 wil_rx_status_get_data_offset(void *msg)
{
u8 val = WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d1,
24, 27);
switch (val) {
case 0: return 0;
case 3: return 2;
default: return 0xFF;
}
}
static inline int wil_rx_status_get_frame_type(struct wil6210_priv *wil,
void *msg)
{
if (wil->use_compressed_rx_status)
return IEEE80211_FTYPE_DATA;
return WIL_GET_BITS(((struct wil_rx_status_extended *)msg)->ext.d1,
0, 1) << 2;
}
static inline int wil_rx_status_get_fc1(struct wil6210_priv *wil, void *msg)
{
if (wil->use_compressed_rx_status)
return 0;
return WIL_GET_BITS(((struct wil_rx_status_extended *)msg)->ext.d1,
0, 5) << 2;
}
static inline __le16 wil_rx_status_get_seq(struct wil6210_priv *wil, void *msg)
{
if (wil->use_compressed_rx_status)
return 0;
return ((struct wil_rx_status_extended *)msg)->ext.seq_num;
}
static inline int wil_rx_status_get_mid(void *msg)
{
if (!(((struct wil_rx_status_compressed *)msg)->d0 &
WIL_RX_EDMA_MID_VALID_BIT))
return 0; /* use the default MID */
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
20, 21);
}
static inline int wil_rx_status_get_error(void *msg)
{
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
29, 29);
}
static inline int wil_rx_status_get_l2_rx_status(void *msg)
{
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
0, 2);
}
static inline int wil_rx_status_get_l3_rx_status(void *msg)
{
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
3, 4);
}
static inline int wil_rx_status_get_l4_rx_status(void *msg)
{
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
5, 6);
}
static inline int wil_rx_status_get_security(void *msg)
{
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
28, 28);
}
static inline u8 wil_rx_status_get_key_id(void *msg)
{
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d1,
31, 31);
}
static inline u8 wil_tx_status_get_mcs(struct wil_ring_tx_status *msg)
{
return WIL_GET_BITS(msg->d2, 0, 4);
......@@ -367,6 +555,7 @@ 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_rx_handle_edma(struct wil6210_priv *wil, int *quota);
void wil_init_txrx_ops_edma(struct wil6210_priv *wil);
#endif /* WIL6210_TXRX_EDMA_H */
......
......@@ -323,9 +323,13 @@ struct RGF_ICR {
#define BIT_CONTROL_0 BIT(0)
/* eDMA status interrupts */
#define RGF_INT_GEN_RX_ICR (0x8bc0f4)
#define BIT_RX_STATUS_IRQ BIT(WIL_RX_STATUS_IRQ_IDX)
#define RGF_INT_GEN_TX_ICR (0x8bc110)
#define BIT_TX_STATUS_IRQ BIT(WIL_TX_STATUS_IRQ_IDX)
#define RGF_INT_CTRL_RX_INT_MASK (0x8bc12c)
#define RGF_INT_CTRL_TX_INT_MASK (0x8bc130)
#define RGF_INT_GEN_IDLE_TIME_LIMIT (0x8bc134)
#define USER_EXT_USER_PMU_3 (0x88d00c)
......@@ -557,6 +561,17 @@ struct wil_txrx_ops {
/* RX ops */
int (*rx_init)(struct wil6210_priv *wil, u16 ring_size);
void (*rx_fini)(struct wil6210_priv *wil);
int (*wmi_addba_rx_resp)(struct wil6210_priv *wil, u8 mid, u8 cid,
u8 tid, u8 token, u16 status, bool amsdu,
u16 agg_wsize, u16 timeout);
void (*get_reorder_params)(struct wil6210_priv *wil,
struct sk_buff *skb, int *tid, int *cid,
int *mid, u16 *seq, int *mcast);
void (*get_netif_rx_params)(struct sk_buff *skb,
int *cid, int *security);
int (*rx_crypto_check)(struct wil6210_priv *wil, struct sk_buff *skb);
bool (*is_rx_idle)(struct wil6210_priv *wil);
irqreturn_t (*irq_rx)(int irq, void *cookie);
};
/**
......@@ -952,6 +967,8 @@ struct wil6210_priv {
u32 rx_status_ring_order;
u32 tx_status_ring_order;
u32 rx_buff_id_count;
bool amsdu_en;
bool use_rx_hw_reordering;
};
#define wil_to_wiphy(i) (i->wiphy)
......@@ -1245,6 +1262,7 @@ void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil);
/* RX API */
void wil_rx_handle(struct wil6210_priv *wil, int *quota);
void wil6210_unmask_irq_rx(struct wil6210_priv *wil);
void wil6210_unmask_irq_rx_edma(struct wil6210_priv *wil);
int wil_iftype_nl2wmi(enum nl80211_iftype type);
......@@ -1265,7 +1283,6 @@ bool wil_is_wmi_idle(struct wil6210_priv *wil);
int wmi_resume(struct wil6210_priv *wil);
int wmi_suspend(struct wil6210_priv *wil);
bool wil_is_tx_idle(struct wil6210_priv *wil);
bool wil_is_rx_idle(struct wil6210_priv *wil);
int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size);
void wil_fw_core_dump(struct wil6210_priv *wil);
......@@ -1280,6 +1297,8 @@ int wmi_start_sched_scan(struct wil6210_priv *wil,
int wmi_stop_sched_scan(struct wil6210_priv *wil);
int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len);
int reverse_memcmp(const void *cs, const void *ct, size_t count);
/* WMI for enhanced DMA */
int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id);
int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil,
......@@ -1289,5 +1308,8 @@ int wil_wmi_rx_desc_ring_add(struct wil6210_priv *wil, int status_ring_id);
int wil_wmi_tx_desc_ring_add(struct wil6210_vif *vif, int ring_id, int cid,
int tid);
int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id);
int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid,
u8 tid, u8 token, u16 status, bool amsdu,
u16 agg_wsize, u16 timeout);
#endif /* __WIL6210_H__ */
......@@ -428,6 +428,8 @@ static const char *cmdid2name(u16 cmdid)
return "WMI_RCP_DELBA_CMD";
case WMI_RCP_ADDBA_RESP_CMDID:
return "WMI_RCP_ADDBA_RESP_CMD";
case WMI_RCP_ADDBA_RESP_EDMA_CMDID:
return "WMI_RCP_ADDBA_RESP_EDMA_CMD";
case WMI_PS_DEV_PROFILE_CFG_CMDID:
return "WMI_PS_DEV_PROFILE_CFG_CMD";
case WMI_SET_MGMT_RETRY_LIMIT_CMDID:
......@@ -2140,15 +2142,18 @@ int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac,
int wmi_addba(struct wil6210_priv *wil, u8 mid,
u8 ringid, u8 size, u16 timeout)
{
u8 amsdu = wil->use_enhanced_dma_hw && wil->use_rx_hw_reordering &&
test_bit(WMI_FW_CAPABILITY_AMSDU, wil->fw_capabilities) &&
wil->amsdu_en;
struct wmi_ring_ba_en_cmd cmd = {
.ring_id = ringid,
.agg_max_wsize = size,
.ba_timeout = cpu_to_le16(timeout),
.amsdu = 0,
.amsdu = amsdu,
};
wil_dbg_wmi(wil, "addba: (ring %d size %d timeout %d)\n", ringid, size,
timeout);
wil_dbg_wmi(wil, "addba: (ring %d size %d timeout %d amsdu %d)\n",
ringid, size, timeout, amsdu);
return wmi_send(wil, WMI_RING_BA_EN_CMDID, mid, &cmd, sizeof(cmd));
}
......@@ -2223,6 +2228,54 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil,
return rc;
}
int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid,
u8 token, u16 status, bool amsdu, u16 agg_wsize,
u16 timeout)
{
int rc;
struct wmi_rcp_addba_resp_edma_cmd cmd = {
.cid = cid,
.tid = tid,
.dialog_token = token,
.status_code = cpu_to_le16(status),
/* bit 0: A-MSDU supported
* bit 1: policy (should be 0 for us)
* bits 2..5: TID
* bits 6..15: buffer size
*/
.ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) |
(agg_wsize << 6)),
.ba_timeout = cpu_to_le16(timeout),
/* route all the connections to status ring 0 */
.status_ring_id = WIL_DEFAULT_RX_STATUS_RING_ID,
};
struct {
struct wmi_cmd_hdr wmi;
struct wmi_rcp_addba_resp_sent_event evt;
} __packed reply = {
.evt = {.status = cpu_to_le16(WMI_FW_STATUS_FAILURE)},
};
wil_dbg_wmi(wil,
"ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s, sring_id %d\n",
cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-",
WIL_DEFAULT_RX_STATUS_RING_ID);
rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_EDMA_CMDID, mid, &cmd,
sizeof(cmd), WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply,
sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
return rc;
if (reply.evt.status) {
wil_err(wil, "ADDBA response failed with status %d\n",
le16_to_cpu(reply.evt.status));
rc = -EINVAL;
}
return rc;
}
int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
enum wmi_ps_profile_type ps_profile)
{
......
......@@ -86,6 +86,7 @@ enum wmi_fw_capability {
WMI_FW_CAPABILITY_PNO = 15,
WMI_FW_CAPABILITY_REF_CLOCK_CONTROL = 18,
WMI_FW_CAPABILITY_AP_SME_OFFLOAD_NONE = 19,
WMI_FW_CAPABILITY_AMSDU = 23,
WMI_FW_CAPABILITY_MAX,
};
......
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