提交 10590c6a 编写于 作者: G Gidon Studinski 提交者: Kalle Valo

wil6210: add support for enhanced DMA structures

In enhanced DMA the vrings are handled internally by the FW
and are not exposed to the driver.
Instead, the driver handles descriptor rings, which are mapped
by the FW to vrings.
The completions of the TX and RX descriptors are notified to
the driver using status rings. Each status ring descriptor
includes information of the completed descriptors and the ring id
of their descriptor ring.

This patch changes struct vring to generic wil_ring to allow
its reuse for enhanced DMA descriptor rings and adds the descriptor
and status rings specific descriptors.

The vring debugfs entries have changed as follows:
- dbg_vring_index has changed to dbg_ring_index
- vrings has changed to rings
- vring_idle_trsh has changed to ring_idle_trsh
- vring_index has changed to ring_index
Signed-off-by: NGidon Studinski <gidons@codeaurora.org>
Signed-off-by: NMaya Erez <merez@codeaurora.org>
Signed-off-by: NKalle Valo <kvalo@codeaurora.org>
上级 485790d0
......@@ -1726,7 +1726,7 @@ static int wil_cfg80211_change_station(struct wiphy *wiphy,
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
int authorize;
int cid, i;
struct vring_tx_data *txdata = NULL;
struct wil_ring_tx_data *txdata = NULL;
wil_dbg_misc(wil, "change station %pM mask 0x%x set 0x%x mid %d\n",
mac, params->sta_flags_mask, params->sta_flags_set,
......@@ -1746,20 +1746,20 @@ static int wil_cfg80211_change_station(struct wiphy *wiphy,
return -ENOLINK;
}
for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++)
if (wil->vring2cid_tid[i][0] == cid) {
txdata = &wil->vring_tx_data[i];
for (i = 0; i < ARRAY_SIZE(wil->ring2cid_tid); i++)
if (wil->ring2cid_tid[i][0] == cid) {
txdata = &wil->ring_tx_data[i];
break;
}
if (!txdata) {
wil_err(wil, "vring data not found\n");
wil_err(wil, "ring data not found\n");
return -ENOLINK;
}
authorize = params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED);
txdata->dot1x_open = authorize ? 1 : 0;
wil_dbg_misc(wil, "cid %d vring %d authorize %d\n", cid, i,
wil_dbg_misc(wil, "cid %d ring %d authorize %d\n", cid, i,
txdata->dot1x_open);
return 0;
......
......@@ -29,7 +29,7 @@
/* Nasty hack. Better have per device instances */
static u32 mem_addr;
static u32 dbg_txdesc_index;
static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
static u32 dbg_ring_index; /* 24+ for Rx, 0..23 for Tx */
enum dbg_off_type {
doff_u32 = 0,
......@@ -47,20 +47,20 @@ struct dbg_off {
enum dbg_off_type type;
};
static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
const char *name, struct vring *vring,
char _s, char _h)
static void wil_print_ring(struct seq_file *s, struct wil6210_priv *wil,
const char *name, struct wil_ring *ring,
char _s, char _h)
{
void __iomem *x = wmi_addr(wil, vring->hwtail);
void __iomem *x = wmi_addr(wil, ring->hwtail);
u32 v;
seq_printf(s, "VRING %s = {\n", name);
seq_printf(s, " pa = %pad\n", &vring->pa);
seq_printf(s, " va = 0x%p\n", vring->va);
seq_printf(s, " size = %d\n", vring->size);
seq_printf(s, " swtail = %d\n", vring->swtail);
seq_printf(s, " swhead = %d\n", vring->swhead);
seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail);
seq_printf(s, "RING %s = {\n", name);
seq_printf(s, " pa = %pad\n", &ring->pa);
seq_printf(s, " va = 0x%p\n", ring->va);
seq_printf(s, " size = %d\n", ring->size);
seq_printf(s, " swtail = %d\n", ring->swtail);
seq_printf(s, " swhead = %d\n", ring->swhead);
seq_printf(s, " hwtail = [0x%08x] -> ", ring->hwtail);
if (x) {
v = readl(x);
seq_printf(s, "0x%08x = %d\n", v, v);
......@@ -68,41 +68,42 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
seq_puts(s, "???\n");
}
if (vring->va && (vring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) {
if (ring->va && (ring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) {
uint i;
for (i = 0; i < vring->size; i++) {
volatile struct vring_tx_desc *d = &vring->va[i].tx;
for (i = 0; i < ring->size; i++) {
volatile struct vring_tx_desc *d =
&ring->va[i].tx.legacy;
if ((i % 128) == 0 && (i != 0))
seq_puts(s, "\n");
seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
_s : (vring->ctx[i].skb ? _h : 'h'));
_s : (ring->ctx[i].skb ? _h : 'h'));
}
seq_puts(s, "\n");
}
seq_puts(s, "}\n");
}
static int wil_vring_debugfs_show(struct seq_file *s, void *data)
static int wil_ring_debugfs_show(struct seq_file *s, void *data)
{
uint i;
struct wil6210_priv *wil = s->private;
wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_');
wil_print_ring(s, wil, "rx", &wil->ring_rx, 'S', '_');
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
struct vring *vring = &wil->vring_tx[i];
struct vring_tx_data *txdata = &wil->vring_tx_data[i];
for (i = 0; i < ARRAY_SIZE(wil->ring_tx); i++) {
struct wil_ring *ring = &wil->ring_tx[i];
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[i];
if (vring->va) {
int cid = wil->vring2cid_tid[i][0];
int tid = wil->vring2cid_tid[i][1];
u32 swhead = vring->swhead;
u32 swtail = vring->swtail;
int used = (vring->size + swhead - swtail)
% vring->size;
int avail = vring->size - used - 1;
if (ring->va) {
int cid = wil->ring2cid_tid[i][0];
int tid = wil->ring2cid_tid[i][1];
u32 swhead = ring->swhead;
u32 swtail = ring->swtail;
int used = (ring->size + swhead - swtail)
% ring->size;
int avail = ring->size - used - 1;
char name[10];
char sidle[10];
/* performance monitoring */
......@@ -137,20 +138,20 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
txdata->dot1x_open ? "+" : "-",
used, avail, sidle);
wil_print_vring(s, wil, name, vring, '_', 'H');
wil_print_ring(s, wil, name, ring, '_', 'H');
}
}
return 0;
}
static int wil_vring_seq_open(struct inode *inode, struct file *file)
static int wil_ring_seq_open(struct inode *inode, struct file *file)
{
return single_open(file, wil_vring_debugfs_show, inode->i_private);
return single_open(file, wil_ring_debugfs_show, inode->i_private);
}
static const struct file_operations fops_vring = {
.open = wil_vring_seq_open,
static const struct file_operations fops_ring = {
.open = wil_ring_seq_open,
.release = single_release,
.read = seq_read,
.llseek = seq_lseek,
......@@ -162,8 +163,8 @@ static void wil_seq_hexdump(struct seq_file *s, void *p, int len,
seq_hex_dump(s, prefix, DUMP_PREFIX_NONE, 16, 1, p, len, false);
}
static void wil_print_ring(struct seq_file *s, const char *prefix,
void __iomem *off)
static void wil_print_mbox_ring(struct seq_file *s, const char *prefix,
void __iomem *off)
{
struct wil6210_priv *wil = s->private;
struct wil6210_mbox_ring r;
......@@ -249,9 +250,9 @@ static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
if (ret < 0)
return ret;
wil_print_ring(s, "tx", wil->csr + HOST_MBOX +
wil_print_mbox_ring(s, "tx", wil->csr + HOST_MBOX +
offsetof(struct wil6210_mbox_ctl, tx));
wil_print_ring(s, "rx", wil->csr + HOST_MBOX +
wil_print_mbox_ring(s, "rx", wil->csr + HOST_MBOX +
offsetof(struct wil6210_mbox_ctl, rx));
wil_pm_runtime_put(wil);
......@@ -719,13 +720,13 @@ static ssize_t wil_write_back(struct file *file, const char __user *buf,
if ((strcmp(cmd, "add") == 0) ||
(strcmp(cmd, "del_tx") == 0)) {
struct vring_tx_data *txdata;
struct wil_ring_tx_data *txdata;
if (p1 < 0 || p1 >= WIL6210_MAX_TX_RINGS) {
wil_err(wil, "BACK: invalid ring id %d\n", p1);
return -EINVAL;
}
txdata = &wil->vring_tx_data[p1];
txdata = &wil->ring_tx_data[p1];
if (strcmp(cmd, "add") == 0) {
if (rc < 3) {
wil_err(wil, "BACK: add require at least 2 params\n");
......@@ -972,30 +973,30 @@ static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb)
static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
struct vring *vring;
bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS);
struct wil_ring *ring;
bool tx = (dbg_ring_index < WIL6210_MAX_TX_RINGS);
vring = tx ? &wil->vring_tx[dbg_vring_index] : &wil->vring_rx;
ring = tx ? &wil->ring_tx[dbg_ring_index] : &wil->ring_rx;
if (!vring->va) {
if (!ring->va) {
if (tx)
seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index);
seq_printf(s, "No Tx[%2d] VRING\n", dbg_ring_index);
else
seq_puts(s, "No Rx VRING\n");
return 0;
}
if (dbg_txdesc_index < vring->size) {
if (dbg_txdesc_index < ring->size) {
/* use struct vring_tx_desc for Rx as well,
* only field used, .dma.length, is the same
*/
volatile struct vring_tx_desc *d =
&vring->va[dbg_txdesc_index].tx;
&ring->va[dbg_txdesc_index].tx.legacy;
volatile u32 *u = (volatile u32 *)d;
struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
struct sk_buff *skb = ring->ctx[dbg_txdesc_index].skb;
if (tx)
seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index,
seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_ring_index,
dbg_txdesc_index);
else
seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index);
......@@ -1014,11 +1015,11 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
} else {
if (tx)
seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
dbg_vring_index, dbg_txdesc_index,
vring->size);
dbg_ring_index, dbg_txdesc_index,
ring->size);
else
seq_printf(s, "RxDesc index (%d) >= size (%d)\n",
dbg_txdesc_index, vring->size);
dbg_txdesc_index, ring->size);
}
return 0;
......@@ -1790,7 +1791,7 @@ static const struct {
const struct file_operations *fops;
} dbg_files[] = {
{"mbox", 0444, &fops_mbox},
{"vrings", 0444, &fops_vring},
{"rings", 0444, &fops_ring},
{"stations", 0444, &fops_sta},
{"mids", 0444, &fops_mids},
{"desc", 0444, &fops_txdesc},
......@@ -1858,7 +1859,7 @@ static const struct dbg_off dbg_wil_off[] = {
WIL_FIELD(chip_revision, 0444, doff_u8),
WIL_FIELD(abft_len, 0644, doff_u8),
WIL_FIELD(wakeup_trigger, 0644, doff_u8),
WIL_FIELD(vring_idle_trsh, 0644, doff_u32),
WIL_FIELD(ring_idle_trsh, 0644, doff_u32),
{},
};
......@@ -1872,7 +1873,7 @@ static const struct dbg_off dbg_wil_regs[] = {
/* static parameters */
static const struct dbg_off dbg_statics[] = {
{"desc_index", 0644, (ulong)&dbg_txdesc_index, doff_u32},
{"vring_index", 0644, (ulong)&dbg_vring_index, doff_u32},
{"ring_index", 0644, (ulong)&dbg_ring_index, doff_u32},
{"mem_addr", 0644, (ulong)&mem_addr, doff_u32},
{"led_polarity", 0644, (ulong)&led_polarity, doff_u8},
{},
......
......@@ -219,9 +219,9 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
memset(sta->tid_crypto_rx, 0, sizeof(sta->tid_crypto_rx));
memset(&sta->group_crypto_rx, 0, sizeof(sta->group_crypto_rx));
/* release vrings */
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
if (wil->vring2cid_tid[i][0] == cid)
wil_vring_fini_tx(wil, i);
for (i = 0; i < ARRAY_SIZE(wil->ring_tx); i++) {
if (wil->ring2cid_tid[i][0] == cid)
wil_ring_fini_tx(wil, i);
}
/* statistics */
memset(&sta->stats, 0, sizeof(sta->stats));
......@@ -453,12 +453,12 @@ static void wil_fw_error_worker(struct work_struct *work)
mutex_unlock(&wil->mutex);
}
static int wil_find_free_vring(struct wil6210_priv *wil)
static int wil_find_free_ring(struct wil6210_priv *wil)
{
int i;
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
if (!wil->vring_tx[i].va)
if (!wil->ring_tx[i].va)
return i;
}
return -EINVAL;
......@@ -473,13 +473,13 @@ int wil_tx_init(struct wil6210_vif *vif, int cid)
wil_err(wil, "No connection pending\n");
goto out;
}
ringid = wil_find_free_vring(wil);
ringid = wil_find_free_ring(wil);
if (ringid < 0) {
wil_err(wil, "No free vring found\n");
goto out;
}
wil_dbg_wmi(wil, "Configure for connection CID %d MID %d vring %d\n",
wil_dbg_wmi(wil, "Configure for connection CID %d MID %d ring %d\n",
cid, vif->mid, ringid);
rc = wil_vring_init_tx(vif, ringid, 1 << tx_ring_order, cid, 0);
......@@ -494,19 +494,19 @@ int wil_tx_init(struct wil6210_vif *vif, int cid)
int wil_bcast_init(struct wil6210_vif *vif)
{
struct wil6210_priv *wil = vif_to_wil(vif);
int ri = vif->bcast_vring, rc;
int ri = vif->bcast_ring, rc;
if ((ri >= 0) && wil->vring_tx[ri].va)
if (ri >= 0 && wil->ring_tx[ri].va)
return 0;
ri = wil_find_free_vring(wil);
ri = wil_find_free_ring(wil);
if (ri < 0)
return ri;
vif->bcast_vring = ri;
vif->bcast_ring = ri;
rc = wil_vring_init_bcast(vif, ri, 1 << bcast_ring_order);
if (rc)
vif->bcast_vring = -1;
vif->bcast_ring = -1;
return rc;
}
......@@ -514,13 +514,13 @@ int wil_bcast_init(struct wil6210_vif *vif)
void wil_bcast_fini(struct wil6210_vif *vif)
{
struct wil6210_priv *wil = vif_to_wil(vif);
int ri = vif->bcast_vring;
int ri = vif->bcast_ring;
if (ri < 0)
return;
vif->bcast_vring = -1;
wil_vring_fini_tx(wil, ri);
vif->bcast_ring = -1;
wil_ring_fini_tx(wil, ri);
}
void wil_bcast_fini_all(struct wil6210_priv *wil)
......@@ -548,7 +548,7 @@ int wil_priv_init(struct wil6210_priv *wil)
}
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++)
spin_lock_init(&wil->vring_tx_data[i].lock);
spin_lock_init(&wil->ring_tx_data[i].lock);
mutex_init(&wil->mutex);
mutex_init(&wil->vif_mutex);
......@@ -589,7 +589,7 @@ int wil_priv_init(struct wil6210_priv *wil)
wil->wakeup_trigger = WMI_WAKEUP_TRIGGER_UCAST |
WMI_WAKEUP_TRIGGER_BCAST;
memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
wil->vring_idle_trsh = 16;
wil->ring_idle_trsh = 16;
wil->reply_mid = U8_MAX;
wil->max_vifs = 1;
......
......@@ -129,11 +129,11 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
/* always process ALL Tx complete, regardless budget - it is fast */
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
struct vring *vring = &wil->vring_tx[i];
struct vring_tx_data *txdata = &wil->vring_tx_data[i];
struct wil_ring *ring = &wil->ring_tx[i];
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[i];
struct wil6210_vif *vif;
if (!vring->va || !txdata->enabled ||
if (!ring->va || !txdata->enabled ||
txdata->mid >= wil->max_vifs)
continue;
......@@ -228,7 +228,7 @@ static void wil_p2p_discovery_timer_fn(struct timer_list *t)
static void wil_vif_init(struct wil6210_vif *vif)
{
vif->bcast_vring = -1;
vif->bcast_ring = -1;
mutex_init(&vif->probe_client_mutex);
......
......@@ -384,7 +384,7 @@ int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize)
{
u8 agg_wsize = wil_agg_size(wil, wsize);
u16 agg_timeout = 0;
struct vring_tx_data *txdata = &wil->vring_tx_data[ringid];
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ringid];
int rc = 0;
if (txdata->addba_in_progress) {
......
......@@ -18,6 +18,9 @@
#ifndef WIL6210_TXRX_H
#define WIL6210_TXRX_H
#include "wil6210.h"
#include "txrx_edma.h"
#define BUF_SW_OWNED (1)
#define BUF_HW_OWNED (0)
......@@ -29,19 +32,13 @@
/* Tx/Rx path */
/* Common representation of physical address in Vring */
struct vring_dma_addr {
__le32 addr_low;
__le16 addr_high;
} __packed;
static inline dma_addr_t wil_desc_addr(struct vring_dma_addr *addr)
static inline dma_addr_t wil_desc_addr(struct wil_ring_dma_addr *addr)
{
return le32_to_cpu(addr->addr_low) |
((u64)le16_to_cpu(addr->addr_high) << 32);
}
static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
static inline void wil_desc_addr_set(struct wil_ring_dma_addr *addr,
dma_addr_t pa)
{
addr->addr_low = cpu_to_le32(lower_32_bits(pa));
......@@ -294,7 +291,7 @@ struct vring_tx_mac {
*/
struct vring_tx_dma {
u32 d0;
struct vring_dma_addr addr;
struct wil_ring_dma_addr addr;
u8 ip_length;
u8 b11; /* 0..6: mac_length; 7:ip_version */
u8 error; /* 0..2: err; 3..7: reserved; */
......@@ -428,7 +425,7 @@ struct vring_rx_mac {
struct vring_rx_dma {
u32 d0;
struct vring_dma_addr addr;
struct wil_ring_dma_addr addr;
u8 ip_length;
u8 b11;
u8 error;
......@@ -441,14 +438,24 @@ struct vring_tx_desc {
struct vring_tx_dma dma;
} __packed;
union wil_tx_desc {
struct vring_tx_desc legacy;
struct wil_tx_enhanced_desc enhanced;
} __packed;
struct vring_rx_desc {
struct vring_rx_mac mac;
struct vring_rx_dma dma;
} __packed;
union vring_desc {
struct vring_tx_desc tx;
struct vring_rx_desc rx;
union wil_rx_desc {
struct vring_rx_desc legacy;
struct wil_rx_enhanced_desc enhanced;
} __packed;
union wil_ring_desc {
union wil_tx_desc tx;
union wil_rx_desc rx;
} __packed;
static inline int wil_rxdesc_tid(struct vring_rx_desc *d)
......@@ -528,6 +535,41 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb)
return (void *)skb->cb;
}
static inline int wil_ring_is_empty(struct wil_ring *ring)
{
return ring->swhead == ring->swtail;
}
static inline u32 wil_ring_next_tail(struct wil_ring *ring)
{
return (ring->swtail + 1) % ring->size;
}
static inline void wil_ring_advance_head(struct wil_ring *ring, int n)
{
ring->swhead = (ring->swhead + n) % ring->size;
}
static inline int wil_ring_is_full(struct wil_ring *ring)
{
return wil_ring_next_tail(ring) == ring->swhead;
}
/* Used space in Tx ring */
static inline int wil_ring_used_tx(struct wil_ring *ring)
{
u32 swhead = ring->swhead;
u32 swtail = ring->swtail;
return (ring->size + swhead - swtail) % ring->size;
}
/* Available space in Tx ring */
static inline int wil_ring_avail_tx(struct wil_ring *ring)
{
return ring->size - wil_ring_used_tx(ring) - 1;
}
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,
......
/*
* Copyright (c) 2012-2016,2018, 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
#define WIL6210_TXRX_EDMA_H
#include "wil6210.h"
/* Enhanced Rx descriptor - MAC part
* [dword 0] : Reserved
* [dword 1] : Reserved
* [dword 2] : Reserved
* [dword 3]
* bit 0..15 : Buffer ID
* bit 16..31 : Reserved
*/
struct wil_ring_rx_enhanced_mac {
u32 d[3];
__le16 buff_id;
u16 reserved;
} __packed;
/* Enhanced Rx descriptor - DMA part
* [dword 0] - Reserved
* [dword 1]
* bit 0..31 : addr_low:32 The payload buffer address, bits 0-31
* [dword 2]
* bit 0..15 : addr_high_low:16 The payload buffer address, bits 32-47
* bit 16..31 : Reserved
* [dword 3]
* bit 0..15 : addr_high_high:16 The payload buffer address, bits 48-63
* bit 16..31 : length
*/
struct wil_ring_rx_enhanced_dma {
u32 d0;
struct wil_ring_dma_addr addr;
u16 w5;
__le16 addr_high_high;
__le16 length;
} __packed;
struct wil_rx_enhanced_desc {
struct wil_ring_rx_enhanced_mac mac;
struct wil_ring_rx_enhanced_dma dma;
} __packed;
/* Enhanced Tx descriptor - DMA part
* [dword 0]
* Same as legacy
* [dword 1]
* bit 0..31 : addr_low:32 The payload buffer address, bits 0-31
* [dword 2]
* bit 0..15 : addr_high_low:16 The payload buffer address, bits 32-47
* bit 16..23 : ip_length:8 The IP header length for the TX IP checksum
* offload feature
* bit 24..30 : mac_length:7
* bit 31 : ip_version:1 1 - IPv4, 0 - IPv6
* [dword 3]
* bit 0..15 : addr_high_high:16 The payload buffer address, bits 48-63
* bit 16..31 : length
*/
struct wil_ring_tx_enhanced_dma {
u8 l4_hdr_len;
u8 cmd;
u16 w1;
struct wil_ring_dma_addr addr;
u8 ip_length;
u8 b11; /* 0..6: mac_length; 7:ip_version */
__le16 addr_high_high;
__le16 length;
} __packed;
/* Enhanced Tx descriptor - MAC part
* [dword 0]
* bit 0.. 9 : lifetime_expiry_value:10
* bit 10 : interrupt_en:1
* bit 11 : status_en:1
* bit 12..13 : txss_override:2
* bit 14 : timestamp_insertion:1
* bit 15 : duration_preserve:1
* bit 16..21 : reserved0:6
* bit 22..26 : mcs_index:5
* bit 27 : mcs_en:1
* bit 28..30 : reserved1:3
* bit 31 : sn_preserved:1
* [dword 1]
* bit 0.. 3 : pkt_mode:4
* bit 4 : pkt_mode_en:1
* bit 5..14 : reserved0:10
* bit 15 : ack_policy_en:1
* bit 16..19 : dst_index:4
* bit 20 : dst_index_en:1
* bit 21..22 : ack_policy:2
* bit 23 : lifetime_en:1
* bit 24..30 : max_retry:7
* bit 31 : max_retry_en:1
* [dword 2]
* bit 0.. 7 : num_of_descriptors:8
* bit 8..17 : reserved:10
* bit 18..19 : l2_translation_type:2 00 - bypass, 01 - 802.3, 10 - 802.11
* bit 20 : snap_hdr_insertion_en:1
* bit 21 : vlan_removal_en:1
* bit 22..23 : reserved0:2
* bit 24 : Dest ID extension:1
* bit 25..31 : reserved0:7
* [dword 3]
* bit 0..15 : tso_mss:16
* bit 16..31 : descriptor_scratchpad:16 - mailbox between driver and ucode
*/
struct wil_ring_tx_enhanced_mac {
u32 d[3];
__le16 tso_mss;
u16 scratchpad;
} __packed;
struct wil_tx_enhanced_desc {
struct wil_ring_tx_enhanced_mac mac;
struct wil_ring_tx_enhanced_dma dma;
} __packed;
#define TX_STATUS_DESC_READY_POS 7
/* Enhanced TX status message
* [dword 0]
* bit 0.. 7 : Number of Descriptor:8 - The number of descriptors that
* are used to form the packets. It is needed for WB when
* releasing the packet
* bit 8..15 : tx_ring_id:8 The transmission ring ID that is related to
* the message
* bit 16..23 : Status:8 - The TX status Code
* 0x0 - A successful transmission
* 0x1 - Retry expired
* 0x2 - Lifetime Expired
* 0x3 - Released
* 0x4-0xFF - Reserved
* bit 24..30 : Reserved:7
* bit 31 : Descriptor Ready bit:1 - It is initiated to
* zero by the driver when the ring is created. It is set by the HW
* to one for each completed status message. Each wrap around,
* the DR bit value is flipped.
* [dword 1]
* bit 0..31 : timestamp:32 - Set when MPDU is transmitted.
* [dword 2]
* bit 0.. 4 : MCS:5 - The transmitted MCS value
* bit 5 : Reserved:1
* bit 6.. 7 : CB mode:2 - 0-DMG 1-EDMG 2-Wide
* bit 8..12 : QID:5 - The QID that was used for the transmission
* bit 13..15 : Reserved:3
* bit 16..20 : Num of MSDUs:5 - Number of MSDUs in the aggregation
* bit 21..22 : Reserved:2
* bit 23 : Retry:1 - An indication that the transmission was retried
* bit 24..31 : TX-Sector:8 - the antenna sector that was used for
* transmission
* [dword 3]
* bit 0..11 : Sequence number:12 - The Sequence Number that was used
* for the MPDU transmission
* bit 12..31 : Reserved:20
*/
struct wil_ring_tx_status {
u8 num_descriptors;
u8 ring_id;
u8 status;
u8 desc_ready; /* Only the last bit should be set */
u32 timestamp;
u32 d2;
u16 seq_number; /* Only the first 12 bits */
u16 w7;
} __packed;
/* Enhanced Rx status message - compressed part
* [dword 0]
* bit 0.. 2 : L2 Rx Status:3 - The L2 packet reception Status
* 0-Success, 1-MIC Error, 2-Key Error, 3-Replay Error,
* 4-A-MSDU Error, 5-Reserved, 6-Reserved, 7-FCS Error
* bit 3.. 4 : L3 Rx Status:2 - Bit0 - L3I - L3 identified and checksum
* calculated, Bit1- L3Err - IPv4 Checksum Error
* bit 5.. 6 : L4 Rx Status:2 - Bit0 - L4I - L4 identified and checksum
* calculated, Bit1- L4Err - TCP/UDP Checksum Error
* bit 7 : Reserved:1
* bit 8..19 : Flow ID:12 - MSDU flow ID
* bit 20..21 : MID:2 - The MAC ID
* bit 22 : MID_V:1 - The MAC ID field is valid
* bit 23 : L3T:1 - IP types: 0-IPv6, 1-IPv4
* bit 24 : L4T:1 - Layer 4 Type: 0-UDP, 1-TCP
* bit 25 : BC:1 - The received MPDU is broadcast
* bit 26 : MC:1 - The received MPDU is multicast
* bit 27 : Raw:1 - The MPDU received with no translation
* bit 28 : Sec:1 - The FC control (b14) - Frame Protected
* bit 29 : Error:1 - An error is set when (L2 status != 0) ||
* (L3 status == 3) || (L4 status == 3)
* bit 30 : EOP:1 - End of MSDU signaling. It is set to mark the end
* of the transfer, otherwise the status indicates buffer
* only completion.
* bit 31 : Descriptor Ready bit:1 - It is initiated to
* zero by the driver when the ring is created. It is set
* by the HW to one for each completed status message.
* Each wrap around, the DR bit value is flipped.
* [dword 1]
* bit 0.. 5 : MAC Len:6 - The number of bytes that are used for L2 header
* bit 6..11 : IPLEN:6 - The number of DW that are used for L3 header
* bit 12..15 : I4Len:4 - The number of DW that are used for L4 header
* bit 16..21 : MCS:6 - The received MCS field from the PLCP Header
* bit 22..23 : CB mode:2 - The CB Mode: 0-DMG, 1-EDMG, 2-Wide
* bit 24..27 : Data Offset:4 - The data offset, a code that describe the
* payload shift from the beginning of the buffer:
* 0 - 0 Bytes, 1 - 2 Bytes, 2 - 6 Bytes
* bit 28 : A-MSDU Present:1 - The QoS (b7) A-MSDU present field
* bit 29 : A-MSDU Type:1 The QoS (b8) A-MSDU Type field
* bit 30 : A-MPDU:1 - Packet is part of aggregated MPDU
* bit 31 : Key ID:1 - The extracted Key ID from the encryption header
* [dword 2]
* bit 0..15 : Buffer ID:16 - The Buffer Identifier
* bit 16..31 : Length:16 - It indicates the valid bytes that are stored
* in the current descriptor buffer. For multiple buffer
* descriptor, SW need to sum the total descriptor length
* in all buffers to produce the packet length
* [dword 3]
* bit 0..31 : timestamp:32 - The MPDU Timestamp.
*/
struct wil_rx_status_compressed {
u32 d0;
u32 d1;
__le16 buff_id;
__le16 length;
u32 timestamp;
} __packed;
/* Enhanced Rx status message - extension part
* [dword 0]
* bit 0.. 4 : QID:5 - The Queue Identifier that the packet is received
* from
* bit 5.. 7 : Reserved:3
* bit 8..11 : TID:4 - The QoS (b3-0) TID Field
* bit 12..15 Source index:4 - The Source index that was found
during Parsing the TA. This field is used to define the
source of the packet
* bit 16..18 : Destination index:3 - The Destination index that
was found during Parsing the RA.
* bit 19..20 : DS Type:2 - The FC Control (b9-8) - From / To DS
* bit 21..22 : MIC ICR:2 - this signal tells the DMA to assert an
interrupt after it writes the packet
* bit 23 : ESOP:1 - The QoS (b4) ESOP field
* bit 24 : RDG:1
* bit 25..31 : Reserved:7
* [dword 1]
* bit 0.. 1 : Frame Type:2 - The FC Control (b3-2) - MPDU Type
(management, data, control and extension)
* bit 2.. 5 : Syb type:4 - The FC Control (b7-4) - Frame Subtype
* bit 6..11 : Ext sub type:6 - The FC Control (b11-8) - Frame Extended
* Subtype
* bit 12..13 : ACK Policy:2 - The QoS (b6-5) ACK Policy fields
* bit 14 : DECRYPT_BYP:1 - The MPDU is bypass by the decryption unit
* bit 15..23 : Reserved:9
* bit 24..31 : RSSI/SNR:8 - The RSSI / SNR measurement for the received
* MPDU
* [dword 2]
* bit 0..11 : SN:12 - The received Sequence number field
* bit 12..15 : Reserved:4
* bit 16..31 : PN bits [15:0]:16
* [dword 3]
* bit 0..31 : PN bits [47:16]:32
*/
struct wil_rx_status_extension {
u32 d0;
u32 d1;
__le16 seq_num; /* only lower 12 bits */
u16 pn_15_0;
u32 pn_47_16;
} __packed;
struct wil_rx_status_extended {
struct wil_rx_status_compressed comp;
struct wil_rx_status_extension ext;
};
#endif /* WIL6210_TXRX_EDMA_H */
......@@ -80,6 +80,8 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
#define WIL6210_NAPI_BUDGET (16) /* arbitrary */
#define WIL_MAX_AMPDU_SIZE (64 * 1024) /* FW/HW limit */
#define WIL_MAX_AGG_WSIZE (32) /* FW/HW limit */
#define WIL6210_MAX_STATUS_RINGS (8)
/* Hardware offload block adds the following:
* 26 bytes - 3-address QoS data header
* 8 bytes - IV + EIV (for GCMP)
......@@ -359,6 +361,12 @@ enum {
#define TALYN_MB_FW_MAPPING_TABLE_SIZE 19
#define MAX_FW_MAPPING_TABLE_SIZE 19
/* Common representation of physical address in wil ring */
struct wil_ring_dma_addr {
__le32 addr_low;
__le16 addr_high;
} __packed;
struct fw_map {
u32 from; /* linker address - from, inclusive */
u32 to; /* linker address - to, exclusive */
......@@ -447,7 +455,7 @@ enum { /* for wil_ctx.mapped_as */
};
/**
* struct wil_ctx - software context for Vring descriptor
* struct wil_ctx - software context for ring descriptor
*/
struct wil_ctx {
struct sk_buff *skb;
......@@ -455,22 +463,59 @@ struct wil_ctx {
u8 mapped_as;
};
union vring_desc;
struct wil_desc_ring_rx_swtail { /* relevant for enhanced DMA only */
u32 *va;
dma_addr_t pa;
};
struct vring {
/**
* A general ring structure, used for RX and TX.
* In legacy DMA it represents the vring,
* In enahnced DMA it represents the descriptor ring (vrings are handled by FW)
*/
struct wil_ring {
dma_addr_t pa;
volatile union vring_desc *va; /* vring_desc[size], WriteBack by DMA */
u16 size; /* number of vring_desc elements */
volatile union wil_ring_desc *va;
u16 size; /* number of wil_ring_desc elements */
u32 swtail;
u32 swhead;
u32 hwtail; /* write here to inform hw */
struct wil_ctx *ctx; /* ctx[size] - software context */
struct wil_desc_ring_rx_swtail edma_rx_swtail;
bool is_rx;
};
/**
* Additional data for Tx Vring
* Additional data for Rx ring.
* Used for enhanced DMA RX chaining.
*/
struct vring_tx_data {
struct wil_ring_rx_data {
/* the skb being assembled */
struct sk_buff *skb;
/* true if we are skipping a bad fragmented packet */
bool skipping;
u16 buff_size;
};
/**
* Status ring structure, used for enhanced DMA completions for RX and TX.
*/
struct wil_status_ring {
dma_addr_t pa;
void *va; /* pointer to ring_[tr]x_status elements */
u16 size; /* number of status elements */
size_t elem_size; /* status element size in bytes */
u32 swhead;
u32 hwtail; /* write here to inform hw */
bool is_rx;
u8 desc_rdy_pol; /* Expected descriptor ready bit polarity */
struct wil_ring_rx_data rx_data;
};
/**
* Additional data for Tx ring
*/
struct wil_ring_tx_data {
bool dot1x_open;
int enabled;
cycles_t idle, last_idle, begin;
......@@ -573,6 +618,9 @@ struct wil_net_stats {
unsigned long rx_short_frame;
unsigned long rx_large_frame;
unsigned long rx_replay;
unsigned long rx_mic_error; /* eDMA specific */
unsigned long rx_key_error; /* eDMA specific */
unsigned long rx_amsdu_error; /* eDMA specific */
u16 last_mcs_rx;
u64 rx_per_mcs[WIL_MCS_MAX + 1];
};
......@@ -690,7 +738,7 @@ struct wil6210_vif {
u8 hidden_ssid; /* relevant in AP mode */
u32 ap_isolate; /* no intra-BSS communication */
bool pbss;
int bcast_vring;
int bcast_ring;
struct cfg80211_bss *bss; /* connected bss, relevant in STA mode */
int locally_generated_disc; /* relevant in STA mode */
struct timer_list connect_timer;
......@@ -706,6 +754,31 @@ struct wil6210_vif {
int net_queue_stopped; /* netif_tx_stop_all_queues invoked */
};
/**
* RX buffer allocated for enhanced DMA RX descriptors
*/
struct wil_rx_buff {
struct sk_buff *skb;
struct list_head list;
int id;
};
/**
* During Rx completion processing, the driver extracts a buffer ID which
* is used as an index to the rx_buff_mgmt.buff_arr array and then the SKB
* is given to the network stack and the buffer is moved from the 'active'
* list to the 'free' list.
* During Rx refill, SKBs are attached to free buffers and moved to the
* 'active' list.
*/
struct wil_rx_buff_mgmt {
struct wil_rx_buff *buff_arr;
size_t size; /* number of items in buff_arr */
struct list_head active;
struct list_head free;
unsigned long free_list_empty_cnt; /* statistics */
};
struct wil6210_priv {
struct pci_dev *pdev;
u32 bar_size;
......@@ -770,14 +843,17 @@ struct wil6210_priv {
struct net_device napi_ndev; /* dummy net_device serving all VIFs */
/* DMA related */
struct vring vring_rx;
struct wil_ring ring_rx;
unsigned int rx_buf_len;
struct vring vring_tx[WIL6210_MAX_TX_RINGS];
struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS];
u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
struct wil_ring ring_tx[WIL6210_MAX_TX_RINGS];
struct wil_ring_tx_data ring_tx_data[WIL6210_MAX_TX_RINGS];
struct wil_status_ring srings[WIL6210_MAX_STATUS_RINGS];
int num_rx_status_rings;
u8 ring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
struct wil_sta_info sta[WIL6210_MAX_CID];
u32 vring_idle_trsh; /* HW fetches up to 16 descriptors at once */
u32 ring_idle_trsh; /* HW fetches up to 16 descriptors at once */
u32 dma_addr_size; /* indicates dma addr size */
struct wil_rx_buff_mgmt rx_buff_mgmt;
struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
/* statistics */
......@@ -999,7 +1075,7 @@ int wmi_add_cipher_key(struct wil6210_vif *vif, u8 key_index,
int key_usage);
int wmi_echo(struct wil6210_priv *wil);
int wmi_set_ie(struct wil6210_vif *vif, u8 type, u16 ie_len, const void *ie);
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
int wmi_rx_chain_add(struct wil6210_priv *wil, struct wil_ring *vring);
int wmi_rxon(struct wil6210_priv *wil, bool on);
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac,
......@@ -1098,7 +1174,7 @@ void wil_rx_fini(struct wil6210_priv *wil);
/* TX API */
int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
int cid, int tid);
void wil_vring_fini_tx(struct wil6210_priv *wil, int id);
void wil_ring_fini_tx(struct wil6210_priv *wil, int id);
int wil_tx_init(struct wil6210_vif *vif, int cid);
int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size);
int wil_bcast_init(struct wil6210_vif *vif);
......@@ -1106,9 +1182,9 @@ void wil_bcast_fini(struct wil6210_vif *vif);
void wil_bcast_fini_all(struct wil6210_priv *wil);
void wil_update_net_queues(struct wil6210_priv *wil, struct wil6210_vif *vif,
struct vring *vring, bool should_stop);
struct wil_ring *ring, bool should_stop);
void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif,
struct vring *vring, bool check_stop);
struct wil_ring *ring, bool check_stop);
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);
......
......@@ -1127,7 +1127,7 @@ static void wmi_evt_vring_en(struct wil6210_vif *vif, int id, void *d, int len)
wil_dbg_wmi(wil, "Enable vring %d MID %d\n", vri, vif->mid);
if (vri >= ARRAY_SIZE(wil->vring_tx)) {
if (vri >= ARRAY_SIZE(wil->ring_tx)) {
wil_err(wil, "Enable for invalid vring %d\n", vri);
return;
}
......@@ -1136,8 +1136,8 @@ static void wmi_evt_vring_en(struct wil6210_vif *vif, int id, void *d, int len)
/* in AP mode with disable_ap_sme, this is done by
* wil_cfg80211_change_station()
*/
wil->vring_tx_data[vri].dot1x_open = true;
if (vri == vif->bcast_vring) /* no BA for bcast */
wil->ring_tx_data[vri].dot1x_open = true;
if (vri == vif->bcast_ring) /* no BA for bcast */
return;
if (agg_wsize >= 0)
wil_addba_tx_request(wil, vri, agg_wsize);
......@@ -1148,7 +1148,7 @@ static void wmi_evt_ba_status(struct wil6210_vif *vif, int id,
{
struct wil6210_priv *wil = vif_to_wil(vif);
struct wmi_ba_status_event *evt = d;
struct vring_tx_data *txdata;
struct wil_ring_tx_data *txdata;
wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d AMSDU%s\n",
evt->ringid,
......@@ -1167,7 +1167,7 @@ static void wmi_evt_ba_status(struct wil6210_vif *vif, int id,
evt->amsdu = 0;
}
txdata = &wil->vring_tx_data[evt->ringid];
txdata = &wil->ring_tx_data[evt->ringid];
txdata->agg_timeout = le16_to_cpu(evt->ba_timeout);
txdata->agg_wsize = evt->agg_wsize;
......@@ -1205,11 +1205,11 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
if (!evt->from_initiator) {
int i;
/* find Tx vring it belongs to */
for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
if ((wil->vring2cid_tid[i][0] == cid) &&
(wil->vring2cid_tid[i][1] == tid)) {
struct vring_tx_data *txdata =
&wil->vring_tx_data[i];
for (i = 0; i < ARRAY_SIZE(wil->ring2cid_tid); i++) {
if (wil->ring2cid_tid[i][0] == cid &&
wil->ring2cid_tid[i][1] == tid) {
struct wil_ring_tx_data *txdata =
&wil->ring_tx_data[i];
wil_dbg_wmi(wil, "DELBA Tx vring %d\n", i);
txdata->agg_timeout = 0;
......@@ -1219,7 +1219,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
break; /* max. 1 matching ring */
}
}
if (i >= ARRAY_SIZE(wil->vring2cid_tid))
if (i >= ARRAY_SIZE(wil->ring2cid_tid))
wil_err(wil, "DELBA: unable to find Tx vring\n");
return;
}
......@@ -1964,7 +1964,7 @@ int wmi_rxon(struct wil6210_priv *wil, bool on)
return rc;
}
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
int wmi_rx_chain_add(struct wil6210_priv *wil, struct wil_ring *vring)
{
struct net_device *ndev = wil->main_ndev;
struct wireless_dev *wdev = ndev->ieee80211_ptr;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册