wil6210: support multiple desc and status rings handling

Support multiple status rings:
- Move Tx status ring initialization code to separate function
- Add status ring id argument to relevant functions instead of
  relaying on wil->tx_sring_idx
- Store allocated Rx status ring id in wil->rx_sring_idx and use it
  instead of hard coded WIL_DEFAULT_RX_STATUS_RING_ID
- Configure interrupt moderation for multiple rings
- Allow allocation of descriptor ring without ctx array
- Set irq_mode upon Tx ring allocation

Enhance wil_wmi_cfg_def_rx_offload to enable/disable checksum offload.

Change-Id: If7d346dec2c1ba35cf377235d4c520eca11be166
Signed-off-by: Dedy Lansky <dlansky@codeaurora.org>
Signed-off-by: Alexei Avshalom Lazar <ailizaro@codeaurora.org>
This commit is contained in:
Dedy Lansky 2019-12-04 10:20:40 +02:00 • committed by Alexei Avshalom Lazar
commit ba42954178
8 changed files with 116 additions and 106 deletions

View file

@ -1,18 +1,7 @@
// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/interrupt.h>
@ -44,7 +33,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_TX_EDMA (0xFFFFFFFFUL)
#define WIL6210_IMC_RX_EDMA BIT_RX_STATUS_IRQ
#define WIL6210_IMC_MISC_NO_HALP (ISR_MISC_FW_READY | \
ISR_MISC_MBOX_EVT | \
@ -226,6 +215,7 @@ void wil_unmask_irq(struct wil6210_priv *wil)
void wil_configure_interrupt_moderation_edma(struct wil6210_priv *wil)
{
u32 moderation;
int i, num_int_lines = 2 /* Rx + Tx status */;
wil_s(wil, RGF_INT_GEN_IDLE_TIME_LIMIT, WIL_EDMA_IDLE_TIME_LIMIT_USEC);
@ -234,8 +224,8 @@ void wil_configure_interrupt_moderation_edma(struct wil6210_priv *wil)
/* Update RX and TX moderation */
moderation = wil->rx_max_burst_duration |
(WIL_EDMA_AGG_WATERMARK << WIL_EDMA_AGG_WATERMARK_POS);
wil_w(wil, RGF_INT_CTRL_INT_GEN_CFG_0, moderation);
wil_w(wil, RGF_INT_CTRL_INT_GEN_CFG_1, moderation);
for (i = 0; i < num_int_lines; i++)
wil_w(wil, i * 4 + RGF_INT_CTRL_INT_GEN_CFG, moderation);
/* Treat special events as regular
* (set bit 0 to 0x1 and clear bits 1-8)

View file

@ -178,10 +178,18 @@ static int wil6210_netdev_poll_tx_edma(struct napi_struct *napi, int budget)
napi_tx);
int tx_done;
/* There is only one status TX ring */
struct wil_status_ring *sring = &wil->srings[wil->tx_sring_idx];
struct wil_status_ring *sring;
if (!sring->va)
if (wil->tx_sring_idx >= WIL6210_MAX_STATUS_RINGS) {
napi_complete(napi);
return 0;
}
sring = &wil->srings[wil->tx_sring_idx];
if (!sring->va) {
napi_complete(napi);
return 0;
}
tx_done = wil_tx_sring_handler(wil, sring);

View file

@ -1636,12 +1636,6 @@ found:
return v;
}
static inline
void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags)
{
d->mac.d[2] |= (nr_frags << MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS);
}
/**
* Sets the descriptor @d up for csum and/or TSO offloading. The corresponding
* @skb is used to obtain the protocol and headers length.

View file

@ -1,18 +1,7 @@
/* SPDX-License-Identifier: ISC */
/*
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef WIL6210_TXRX_H
@ -685,6 +674,12 @@ static inline void wil_skb_set_cid(struct sk_buff *skb, u8 cid)
skb_rx_info->rx_info.cid = cid;
}
static inline
void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags)
{
d->mac.d[2] |= (nr_frags << MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS);
}
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev);
void wil_netif_rx(struct sk_buff *skb, struct net_device *ndev, int cid,
struct wil_net_stats *stats, bool gro);

View file

@ -103,47 +103,58 @@ static int wil_sring_alloc(struct wil6210_priv *wil,
return 0;
}
static int wil_init_tx_sring(struct wil6210_priv *wil, u16 status_ring_size,
size_t elem_size, u16 sring_id)
{
struct wil_status_ring *sring = &wil->srings[sring_id];
int rc;
u8 irq_mode = WMI_RING_ADD_IRQ_MODE_ENABLE;
wil_dbg_misc(wil, "init TX sring: size=%u, sring_id=%u\n",
status_ring_size, sring_id);
sring->is_rx = false;
sring->size = status_ring_size;
sring->elem_size = elem_size;
rc = wil_sring_alloc(wil, sring);
if (rc)
return rc;
rc = wil_wmi_tx_sring_cfg(wil, sring_id, irq_mode);
if (rc)
goto out_free;
sring->desc_rdy_pol = 1;
return 0;
out_free:
wil_sring_free(wil, sring);
return rc;
}
static int wil_tx_init_edma(struct wil6210_priv *wil)
{
int ring_id = wil_find_free_sring(wil);
struct wil_status_ring *sring;
int rc;
u16 status_ring_size;
int sring_id = wil_find_free_sring(wil), rc;
u16 sring_size;
if (sring_id < 0)
return sring_id;
if (wil->tx_status_ring_order < WIL_SRING_SIZE_ORDER_MIN ||
wil->tx_status_ring_order > WIL_SRING_SIZE_ORDER_MAX)
wil->tx_status_ring_order = WIL_TX_SRING_SIZE_ORDER_DEFAULT;
status_ring_size = 1 << wil->tx_status_ring_order;
wil_dbg_misc(wil, "init TX sring: size=%u, ring_id=%u\n",
status_ring_size, ring_id);
if (ring_id < 0)
return ring_id;
sring_size = 1 << wil->tx_status_ring_order;
/* Allocate Tx status ring. Tx descriptor rings will be
* allocated on WMI connect event
*/
sring = &wil->srings[ring_id];
rc = wil_init_tx_sring(wil, sring_size,
sizeof(struct wil_ring_tx_status), sring_id);
if (!rc)
wil->tx_sring_idx = sring_id;
sring->is_rx = false;
sring->size = status_ring_size;
sring->elem_size = sizeof(struct wil_ring_tx_status);
rc = wil_sring_alloc(wil, sring);
if (rc)
return rc;
rc = wil_wmi_tx_sring_cfg(wil, ring_id);
if (rc)
goto out_free;
sring->desc_rdy_pol = 1;
wil->tx_sring_idx = ring_id;
return 0;
out_free:
wil_sring_free(wil, sring);
return rc;
}
@ -374,7 +385,8 @@ out_free:
}
static int wil_ring_alloc_desc_ring(struct wil6210_priv *wil,
struct wil_ring *ring)
struct wil_ring *ring,
bool alloc_ctx)
{
struct device *dev = wil_to_dev(wil);
size_t sz = ring->size * sizeof(ring->va[0]);
@ -385,9 +397,15 @@ static int wil_ring_alloc_desc_ring(struct wil6210_priv *wil,
ring->swhead = 0;
ring->swtail = 0;
ring->ctx = kcalloc(ring->size, sizeof(ring->ctx[0]), GFP_KERNEL);
if (!ring->ctx)
goto err;
if (alloc_ctx) {
ring->ctx = kcalloc(ring->size, sizeof(ring->ctx[0]),
GFP_KERNEL);
if (!ring->ctx)
goto err;
} else {
ring->ctx = NULL;
}
ring->va = dma_alloc_coherent(dev, sz, &ring->pa, GFP_KERNEL);
if (!ring->va)
@ -490,7 +508,7 @@ static int wil_init_rx_desc_ring(struct wil6210_priv *wil, u16 desc_ring_size,
ring->size = desc_ring_size;
ring->is_rx = true;
rc = wil_ring_alloc_desc_ring(wil, ring);
rc = wil_ring_alloc_desc_ring(wil, ring, true);
if (rc)
return rc;
@ -642,7 +660,7 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, uint desc_ring_order)
wil_dbg_misc(wil, "rx_init: allocate %d status rings\n",
wil->num_rx_status_rings);
rc = wil_wmi_cfg_def_rx_offload(wil, wil->rx_buf_len);
rc = wil_wmi_cfg_def_rx_offload(wil, wil->rx_buf_len, true);
if (rc)
return rc;
@ -658,11 +676,13 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, uint desc_ring_order)
sring_id);
if (rc)
goto err_free_status;
if (i == 0)
wil->rx_sring_idx = sring_id;
}
/* Allocate descriptor ring */
rc = wil_init_rx_desc_ring(wil, desc_ring_size,
WIL_DEFAULT_RX_STATUS_RING_ID);
rc = wil_init_rx_desc_ring(wil, desc_ring_size, wil->rx_sring_idx);
if (rc)
goto err_free_status;
@ -703,6 +723,7 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id,
int rc;
struct wil_ring *ring = &wil->ring_tx[ring_id];
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id];
u8 irq_mode = WMI_RING_ADD_IRQ_MODE_DISABLE;
lockdep_assert_held(&wil->mutex);
@ -712,7 +733,7 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id,
wil_tx_data_init(txdata);
ring->size = size;
rc = wil_ring_alloc_desc_ring(wil, ring);
rc = wil_ring_alloc_desc_ring(wil, ring, true);
if (rc)
goto out;
@ -721,7 +742,8 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id,
if (!vif->privacy)
txdata->dot1x_open = true;
rc = wil_wmi_tx_desc_ring_add(vif, ring_id, cid, tid);
rc = wil_wmi_tx_desc_ring_add(vif, ring_id, cid, tid, wil->tx_sring_idx,
irq_mode);
if (rc) {
wil_err(wil, "WMI_TX_DESC_RING_ADD_CMD failed\n");
goto out_free;
@ -1540,18 +1562,18 @@ static int wil_ring_init_bcast_edma(struct wil6210_vif *vif, int ring_id,
{
struct wil6210_priv *wil = vif_to_wil(vif);
struct wil_ring *ring = &wil->ring_tx[ring_id];
int rc;
int rc, sring_id = wil->tx_sring_idx;
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id];
wil_dbg_misc(wil, "init bcast: ring_id=%d, sring_id=%d\n",
ring_id, wil->tx_sring_idx);
ring_id, sring_id);
lockdep_assert_held(&wil->mutex);
wil_tx_data_init(txdata);
ring->size = size;
ring->is_rx = false;
rc = wil_ring_alloc_desc_ring(wil, ring);
rc = wil_ring_alloc_desc_ring(wil, ring, true);
if (rc)
goto out;
@ -1560,7 +1582,7 @@ static int wil_ring_init_bcast_edma(struct wil6210_vif *vif, int ring_id,
if (!vif->privacy)
txdata->dot1x_open = true;
rc = wil_wmi_bcast_desc_ring_add(vif, ring_id);
rc = wil_wmi_bcast_desc_ring_add(vif, ring_id, sring_id);
if (rc)
goto out_free;
@ -1579,11 +1601,18 @@ out:
static void wil_tx_fini_edma(struct wil6210_priv *wil)
{
struct wil_status_ring *sring = &wil->srings[wil->tx_sring_idx];
int i;
wil_dbg_misc(wil, "free TX sring\n");
for (i = 0; i < WIL6210_MAX_STATUS_RINGS; i++) {
struct wil_status_ring *sring = &wil->srings[i];
wil_sring_free(wil, sring);
if (!sring->va || sring->is_rx)
continue;
wil_dbg_misc(wil, "free TX sring %d\n", i);
wil_sring_free(wil, sring);
}
}
static void wil_rx_data_free(struct wil_status_ring *sring)

View file

@ -1,17 +1,6 @@
/* SPDX-License-Identifier: ISC */
/*
* Copyright (c) 2012-2016,2018-2019, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef WIL6210_TXRX_EDMA_H
@ -27,7 +16,6 @@
#define WIL_TX_SRING_SIZE_ORDER_DEFAULT (14)
#define WIL_RX_BUFF_ARR_SIZE_DEFAULT (2600)
#define WIL_DEFAULT_RX_STATUS_RING_ID 0
#define WIL_RX_DESC_RING_ID 0
#define WIL_RX_STATUS_IRQ_IDX 0
#define WIL_TX_STATUS_IRQ_IDX 1

View file

@ -336,8 +336,7 @@ struct RGF_ICR {
#define RGF_INT_COUNT_ON_SPECIAL_EVT (0x8b62d8)
#define RGF_INT_CTRL_INT_GEN_CFG_0 (0x8bc000)
#define RGF_INT_CTRL_INT_GEN_CFG_1 (0x8bc004)
#define RGF_INT_CTRL_INT_GEN_CFG (0x8bc000)
#define RGF_INT_GEN_TIME_UNIT_LIMIT (0x8bc0c8)
#define RGF_INT_GEN_CTRL (0x8bc0ec)
@ -1000,6 +999,7 @@ struct wil6210_priv {
struct wil_status_ring srings[WIL6210_MAX_STATUS_RINGS];
u8 num_rx_status_rings;
int tx_sring_idx;
int rx_sring_idx;
u8 ring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
struct wil_sta_info sta[WIL6210_MAX_CID];
u32 ring_idle_trsh; /* HW fetches up to 16 descriptors at once */
@ -1485,14 +1485,15 @@ int wil_spec2wmi_ch(u8 spec_ch, u8 *wmi_ch);
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_tx_sring_cfg(struct wil6210_priv *wil, int ring_id, u8 irq_mode);
int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil,
u16 max_rx_pl_per_desc);
u16 max_rx_pl_per_desc, bool checksum);
int wil_wmi_rx_sring_add(struct wil6210_priv *wil, u16 ring_id);
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 tid, int sring_id, u8 irq_mode);
int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id,
int sring_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);

View file

@ -2943,8 +2943,8 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid,
.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,
/* route all the connections to same Rx status ring */
.status_ring_id = wil->rx_sring_idx,
};
struct {
struct wmi_cmd_hdr wmi;
@ -2956,7 +2956,7 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid,
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);
cmd.status_ring_id);
rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_EDMA_CMDID, mid, &cmd,
sizeof(cmd), WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply,
@ -3908,7 +3908,7 @@ int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len,
return rc;
}
int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id)
int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id, u8 irq_mode)
{
int rc;
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
@ -3917,7 +3917,8 @@ int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id)
.ring_cfg = {
.ring_size = cpu_to_le16(sring->size),
},
.irq_index = WIL_TX_STATUS_IRQ_IDX
.irq_index = WIL_TX_STATUS_IRQ_IDX,
.irq_mode = irq_mode,
};
struct {
struct wmi_cmd_hdr hdr;
@ -3948,7 +3949,8 @@ int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id)
return 0;
}
int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil, u16 max_rx_pl_per_desc)
int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil,
u16 max_rx_pl_per_desc, bool checksum)
{
struct net_device *ndev = wil->main_ndev;
struct wil6210_vif *vif = ndev_to_vif(ndev);
@ -3958,7 +3960,8 @@ int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil, u16 max_rx_pl_per_desc)
.max_rx_pl_per_desc = cpu_to_le16(max_rx_pl_per_desc),
.decap_trans_type = WMI_DECAP_TYPE_802_3,
.l2_802_3_offload_ctrl = 0,
.l3_l4_ctrl = 1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS,
.l3_l4_ctrl =
(checksum ? 1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS : 0),
};
struct {
struct wmi_cmd_hdr hdr;
@ -4070,10 +4073,9 @@ 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 tid, int sring_id, u8 irq_mode)
{
struct wil6210_priv *wil = vif_to_wil(vif);
int sring_id = wil->tx_sring_idx; /* there is only one TX sring */
int rc;
struct wil_ring *ring = &wil->ring_tx[ring_id];
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id];
@ -4090,7 +4092,9 @@ int wil_wmi_tx_desc_ring_add(struct wil6210_vif *vif, int ring_id, int cid,
.schd_params = {
.priority = cpu_to_le16(0),
.timeslot_us = cpu_to_le16(0xfff),
}
},
.irq_index = ring_id,
.irq_mode = irq_mode,
};
struct {
struct wmi_cmd_hdr hdr;
@ -4123,7 +4127,8 @@ int wil_wmi_tx_desc_ring_add(struct wil6210_vif *vif, int ring_id, int cid,
return 0;
}
int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id)
int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id,
int sring_id)
{
struct wil6210_priv *wil = vif_to_wil(vif);
struct wil_ring *ring = &wil->ring_tx[ring_id];
@ -4134,7 +4139,7 @@ int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id)
.ring_id = ring_id,
},
.max_msdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)),
.status_ring_id = wil->tx_sring_idx,
.status_ring_id = sring_id,
.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
};
struct {