wil6210: fix remaining use of non-cached copy of tx/rx descriptors
authorVladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Sun, 12 May 2013 11:43:37 +0000 (14:43 +0300)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 22 May 2013 19:08:37 +0000 (15:08 -0400)
- 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: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/wil6210/txrx.c
drivers/net/wireless/ath/wil6210/txrx.h

index bab5011..5613148 100644 (file)
@@ -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);
index a40aa0b..23c0781 100644 (file)
 #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;