Commit 68ada71e authored by Vladimir Kondratiev's avatar Vladimir Kondratiev Committed by John W. Linville

wil6210: fix remaining use of non-cached copy of tx/rx descriptors

- Introduce common code for Tx/Rx descriptor physical address set/parse
- Fix endianness for address fields
- consistent descriptor naming: '_d' for non-cached memory, 'd' for cached copy
- wil_tx_desc_map now modify cached copy, no need for 'volatile'
Signed-off-by: default avatarVladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e0287c4a
......@@ -90,8 +90,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
* we can use any
*/
for (i = 0; i < vring->size; i++) {
volatile struct vring_tx_desc *d = &(vring->va[i].tx);
d->dma.status = TX_DMA_STATUS_DU;
volatile struct vring_tx_desc *_d = &(vring->va[i].tx);
_d->dma.status = TX_DMA_STATUS_DU;
}
wil_dbg_misc(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size,
......@@ -107,14 +107,19 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
size_t sz = vring->size * sizeof(vring->va[0]);
while (!wil_vring_is_empty(vring)) {
dma_addr_t pa;
struct sk_buff *skb;
u16 dmalen;
if (tx) {
volatile struct vring_tx_desc *d =
struct vring_tx_desc dd, *d = &dd;
volatile struct vring_tx_desc *_d =
&vring->va[vring->swtail].tx;
dma_addr_t pa = d->dma.addr_low |
((u64)d->dma.addr_high << 32);
struct sk_buff *skb = vring->ctx[vring->swtail];
*d = *_d;
pa = wil_desc_addr(&d->dma.addr);
dmalen = le16_to_cpu(d->dma.length);
skb = vring->ctx[vring->swtail];
if (skb) {
dma_unmap_single(dev, pa, dmalen,
DMA_TO_DEVICE);
......@@ -126,12 +131,14 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
}
vring->swtail = wil_vring_next_tail(vring);
} else { /* rx */
volatile struct vring_rx_desc *d =
struct vring_rx_desc dd, *d = &dd;
volatile struct vring_rx_desc *_d =
&vring->va[vring->swtail].rx;
dma_addr_t pa = d->dma.addr_low |
((u64)d->dma.addr_high << 32);
struct sk_buff *skb = vring->ctx[vring->swhead];
*d = *_d;
pa = wil_desc_addr(&d->dma.addr);
dmalen = le16_to_cpu(d->dma.length);
skb = vring->ctx[vring->swhead];
dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE);
kfree_skb(skb);
wil_vring_advance_head(vring, 1);
......@@ -154,7 +161,8 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
{
struct device *dev = wil_to_dev(wil);
unsigned int sz = RX_BUF_LEN;
volatile struct vring_rx_desc *d = &(vring->va[i].rx);
struct vring_rx_desc dd, *d = &dd;
volatile struct vring_rx_desc *_d = &(vring->va[i].rx);
dma_addr_t pa;
/* TODO align */
......@@ -172,13 +180,13 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
}
d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT;
d->dma.addr_low = lower_32_bits(pa);
d->dma.addr_high = (u16)upper_32_bits(pa);
wil_desc_addr_set(&d->dma.addr, pa);
/* ip_length don't care */
/* b11 don't care */
/* error don't care */
d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */
d->dma.length = cpu_to_le16(sz);
*_d = *d;
vring->ctx[i] = skb;
return 0;
......@@ -324,8 +332,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
{
struct device *dev = wil_to_dev(wil);
struct net_device *ndev = wil_to_ndev(wil);
volatile struct vring_rx_desc *d;
struct vring_rx_desc *d1;
volatile struct vring_rx_desc *_d;
struct vring_rx_desc *d;
struct sk_buff *skb;
dma_addr_t pa;
unsigned int sz = RX_BUF_LEN;
......@@ -338,20 +346,27 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
if (wil_vring_is_empty(vring))
return NULL;
d = &(vring->va[vring->swhead].rx);
if (!(d->dma.status & RX_DMA_STATUS_DU)) {
_d = &(vring->va[vring->swhead].rx);
if (!(_d->dma.status & RX_DMA_STATUS_DU)) {
/* it is not error, we just reached end of Rx done area */
return NULL;
}
pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
skb = vring->ctx[vring->swhead];
d = wil_skb_rxdesc(skb);
*d = *_d;
pa = wil_desc_addr(&d->dma.addr);
vring->ctx[vring->swhead] = NULL;
wil_vring_advance_head(vring, 1);
dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE);
dmalen = le16_to_cpu(d->dma.length);
trace_wil6210_rx(vring->swhead, d);
wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead, dmalen);
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d, sizeof(*d), false);
d1 = wil_skb_rxdesc(skb);
*d1 = *d;
wil_vring_advance_head(vring, 1);
dmalen = le16_to_cpu(d1->dma.length);
if (dmalen > sz) {
wil_err(wil, "Rx size too large: %d bytes!\n", dmalen);
kfree(skb);
......@@ -363,18 +378,12 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
skb->data, skb_headlen(skb), false);
wil->stats.last_mcs_rx = wil_rxdesc_mcs(d1);
wil->stats.last_mcs_rx = wil_rxdesc_mcs(d);
/* use radiotap header only if required */
if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
wil_rx_add_radiotap_header(wil, skb);
trace_wil6210_rx(vring->swhead, d1);
wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead,
d1->dma.length);
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d1, sizeof(*d1), false);
/* no extra checks if in sniffer mode */
if (ndev->type != ARPHRD_ETHER)
return skb;
......@@ -383,7 +392,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
* Driver should recognize it by frame type, that is found
* in Rx descriptor. If type is not data, it is 802.11 frame as is
*/
ftype = wil_rxdesc_ftype(d1) << 2;
ftype = wil_rxdesc_ftype(d) << 2;
if (ftype != IEEE80211_FTYPE_DATA) {
wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype);
/* TODO: process it */
......@@ -398,7 +407,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
return NULL;
}
ds_bits = wil_rxdesc_ds_bits(d1);
ds_bits = wil_rxdesc_ds_bits(d);
if (ds_bits == 1) {
/*
* HW bug - in ToDS mode, i.e. Rx on AP side,
......@@ -612,11 +621,9 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
return NULL;
}
static int wil_tx_desc_map(volatile struct vring_tx_desc *d,
dma_addr_t pa, u32 len)
static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len)
{
d->dma.addr_low = lower_32_bits(pa);
d->dma.addr_high = (u16)upper_32_bits(pa);
wil_desc_addr_set(&d->dma.addr, pa);
d->dma.ip_length = 0;
/* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/
d->dma.b11 = 0/*14 | BIT(7)*/;
......@@ -642,7 +649,8 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
struct sk_buff *skb)
{
struct device *dev = wil_to_dev(wil);
volatile struct vring_tx_desc *d;
struct vring_tx_desc dd, *d = &dd;
volatile struct vring_tx_desc *_d;
u32 swhead = vring->swhead;
int avail = wil_vring_avail_tx(vring);
int nr_frags = skb_shinfo(skb)->nr_frags;
......@@ -660,7 +668,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
1 + nr_frags);
return -ENOMEM;
}
d = &(vring->va[i].tx);
_d = &(vring->va[i].tx);
/* FIXME FW can accept only unicast frames for the peer */
memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN);
......@@ -679,25 +687,30 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
wil_tx_desc_map(d, pa, skb_headlen(skb));
d->mac.d[2] |= ((nr_frags + 1) <<
MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS);
if (nr_frags)
*_d = *d;
/* middle segments */
for (f = 0; f < nr_frags; f++) {
const struct skb_frag_struct *frag =
&skb_shinfo(skb)->frags[f];
int len = skb_frag_size(frag);
i = (swhead + f + 1) % vring->size;
d = &(vring->va[i].tx);
_d = &(vring->va[i].tx);
pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag),
DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(dev, pa)))
goto dma_error;
wil_tx_desc_map(d, pa, len);
vring->ctx[i] = NULL;
*_d = *d;
}
/* for the last seg only */
d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS);
d->dma.d0 |= BIT(9); /* BUG: undocumented bit */
d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS);
d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS);
*_d = *d;
wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d, sizeof(*d), false);
......@@ -721,9 +734,10 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
u16 dmalen;
i = (swhead + f) % vring->size;
d = &(vring->va[i].tx);
d->dma.status = TX_DMA_STATUS_DU;
pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
_d = &(vring->va[i].tx);
*d = *_d;
_d->dma.status = TX_DMA_STATUS_DU;
pa = wil_desc_addr(&d->dma.addr);
dmalen = le16_to_cpu(d->dma.length);
if (vring->ctx[i])
dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
......@@ -806,14 +820,14 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid);
while (!wil_vring_is_empty(vring)) {
volatile struct vring_tx_desc *d1 =
volatile struct vring_tx_desc *_d =
&vring->va[vring->swtail].tx;
struct vring_tx_desc dd, *d = &dd;
dma_addr_t pa;
struct sk_buff *skb;
u16 dmalen;
dd = *d1;
*d = *_d;
if (!(d->dma.status & TX_DMA_STATUS_DU))
break;
......@@ -828,7 +842,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d, sizeof(*d), false);
pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
pa = wil_desc_addr(&d->dma.addr);
skb = vring->ctx[vring->swtail];
if (skb) {
if (d->dma.error == 0) {
......@@ -844,8 +858,8 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
} else {
dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE);
}
d->dma.addr_low = 0;
d->dma.addr_high = 0;
d->dma.addr.addr_low = 0;
d->dma.addr.addr_high = 0;
d->dma.length = 0;
d->dma.status = TX_DMA_STATUS_DU;
vring->swtail = wil_vring_next_tail(vring);
......
......@@ -27,6 +27,28 @@
#define WIL6210_RTAP_SIZE (128)
/* 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)
{
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,
dma_addr_t pa)
{
addr->addr_low = cpu_to_le32(lower_32_bits(pa));
addr->addr_high = cpu_to_le16((u16)upper_32_bits(pa));
}
/*
* Tx descriptor - MAC part
* [dword 0]
......@@ -216,8 +238,7 @@ struct vring_tx_mac {
struct vring_tx_dma {
u32 d0;
u32 addr_low;
u16 addr_high;
struct vring_dma_addr addr;
u8 ip_length;
u8 b11; /* 0..6: mac_length; 7:ip_version */
u8 error; /* 0..2: err; 3..7: reserved; */
......@@ -315,8 +336,7 @@ struct vring_rx_mac {
struct vring_rx_dma {
u32 d0;
u32 addr_low;
u16 addr_high;
struct vring_dma_addr addr;
u8 ip_length;
u8 b11;
u8 error;
......
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