ralink: reduce access to uncached tx/rx dma ring buffer
[openwrt/svn-archive/archive.git] / target / linux / ramips / files / drivers / net / ethernet / ralink / ralink_soc_eth.c
index 925cc4cc6b6aae65b9696408b1939ceb791a99d2..ca78d715971c378489b972e2ade0f77b2e235213 100644 (file)
@@ -161,6 +161,31 @@ static inline int fe_max_buf_size(int frag_size)
                SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
 }
 
+static inline void fe_get_rxd(struct fe_rx_dma *rxd, struct fe_rx_dma *dma_rxd)
+{
+       rxd->rxd1 = dma_rxd->rxd1;
+       rxd->rxd2 = dma_rxd->rxd2;
+       rxd->rxd3 = dma_rxd->rxd3;
+       rxd->rxd4 = dma_rxd->rxd4;
+}
+
+static inline void fe_get_txd(struct fe_tx_dma *txd, struct fe_tx_dma *dma_txd)
+{
+       txd->txd1 = dma_txd->txd1;
+       txd->txd2 = dma_txd->txd2;
+       txd->txd3 = dma_txd->txd3;
+       txd->txd4 = dma_txd->txd4;
+}
+
+static inline void fe_set_txd(struct fe_tx_dma *txd, struct fe_tx_dma *dma_txd)
+{
+       dma_txd->txd1 = txd->txd1;
+       dma_txd->txd3 = txd->txd3;
+       dma_txd->txd4 = txd->txd4;
+       /* clean dma done flag last */
+       dma_txd->txd2 = txd->txd2;
+}
+
 static void fe_clean_rx(struct fe_priv *priv)
 {
        int i;
@@ -222,7 +247,7 @@ static int fe_alloc_rx(struct fe_priv *priv)
                priv->rx_dma[i].rxd1 = (unsigned int) dma_addr;
 
                if (priv->soc->rx_dma)
-                       priv->soc->rx_dma(priv, i, priv->rx_buf_size);
+                       priv->soc->rx_dma(&priv->rx_dma[i], priv->rx_buf_size);
                else
                        priv->rx_dma[i].rxd2 = RX_DMA_LSO;
        }
@@ -281,7 +306,7 @@ static int fe_alloc_tx(struct fe_priv *priv)
 
        for (i = 0; i < NUM_DMA_DESC; i++) {
                if (priv->soc->tx_dma) {
-                       priv->soc->tx_dma(priv, i, NULL);
+                       priv->soc->tx_dma(&priv->tx_dma[i]);
                        continue;
                }
                priv->tx_dma[i].txd2 = TX_DMA_DESP2_DEF;
@@ -479,36 +504,36 @@ static int fe_tx_map_dma(struct sk_buff *skb, struct net_device *dev,
 {
        struct fe_priv *priv = netdev_priv(dev);
        struct skb_frag_struct *frag;
-       struct fe_tx_dma *txd;
+       struct fe_tx_dma txd, *ptxd;
        dma_addr_t mapped_addr;
        unsigned int nr_frags;
-       u32 def_txd4, txd2;
+       u32 def_txd4;
        int i, j, unmap_idx, tx_num;
 
-       txd = &priv->tx_dma[idx];
+       memset(&txd, 0, sizeof(txd));
        nr_frags = skb_shinfo(skb)->nr_frags;
        tx_num = 1 + (nr_frags >> 1);
 
        /* init tx descriptor */
        if (priv->soc->tx_dma)
-               priv->soc->tx_dma(priv, idx, skb);
+               priv->soc->tx_dma(&txd);
        else
-               txd->txd4 = TX_DMA_DESP4_DEF;
-       def_txd4 = txd->txd4;
+               txd.txd4 = TX_DMA_DESP4_DEF;
+       def_txd4 = txd.txd4;
 
        /* use dma_unmap_single to free it */
-       txd->txd4 |= priv->soc->tx_udf_bit;
+       txd.txd4 |= priv->soc->tx_udf_bit;
 
        /* TX Checksum offload */
        if (skb->ip_summed == CHECKSUM_PARTIAL)
-               txd->txd4 |= TX_DMA_CHKSUM;
+               txd.txd4 |= TX_DMA_CHKSUM;
 
        /* VLAN header offload */
        if (vlan_tx_tag_present(skb)) {
                if (IS_ENABLED(CONFIG_SOC_MT7621))
-                       txd->txd4 |= TX_DMA_INS_VLAN_MT7621 | vlan_tx_tag_get(skb);
+                       txd.txd4 |= TX_DMA_INS_VLAN_MT7621 | vlan_tx_tag_get(skb);
                else
-                       txd->txd4 |= TX_DMA_INS_VLAN |
+                       txd.txd4 |= TX_DMA_INS_VLAN |
                                ((vlan_tx_tag_get(skb) >> VLAN_PRIO_SHIFT) << 4) |
                                (vlan_tx_tag_get(skb) & 0xF);
        }
@@ -522,7 +547,7 @@ static int fe_tx_map_dma(struct sk_buff *skb, struct net_device *dev,
                }
                if (skb_shinfo(skb)->gso_type &
                                (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
-                       txd->txd4 |= TX_DMA_TSO;
+                       txd.txd4 |= TX_DMA_TSO;
                        tcp_hdr(skb)->check = htons(skb_shinfo(skb)->gso_size);
                }
        }
@@ -531,8 +556,8 @@ static int fe_tx_map_dma(struct sk_buff *skb, struct net_device *dev,
                        skb_headlen(skb), DMA_TO_DEVICE);
        if (unlikely(dma_mapping_error(&dev->dev, mapped_addr)))
                goto err_out;
-       txd->txd1 = mapped_addr;
-       txd2 = TX_DMA_PLEN0(skb_headlen(skb));
+       txd.txd1 = mapped_addr;
+       txd.txd2 = TX_DMA_PLEN0(skb_headlen(skb));
 
        /* TX SG offload */
        j = idx;
@@ -546,24 +571,26 @@ static int fe_tx_map_dma(struct sk_buff *skb, struct net_device *dev,
 
                if (i & 0x1) {
                        j = NEXT_TX_DESP_IDX(j);
-                       txd = &priv->tx_dma[j];
-                       txd->txd1 = mapped_addr;
-                       txd2 = TX_DMA_PLEN0(frag->size);
-                       txd->txd4 = def_txd4;
+                       txd.txd1 = mapped_addr;
+                       txd.txd2 = TX_DMA_PLEN0(frag->size);
+                       txd.txd4 = def_txd4;
                } else {
-                       txd->txd3 = mapped_addr;
-                       txd2 |= TX_DMA_PLEN1(frag->size);
-                       if (i != (nr_frags -1))
-                               txd->txd2 = txd2;
+                       txd.txd3 = mapped_addr;
+                       txd.txd2 |= TX_DMA_PLEN1(frag->size);
+                       if (i != (nr_frags -1)) {
+                               fe_set_txd(&txd, &priv->tx_dma[j]);
+                               memset(&txd, 0, sizeof(txd));
+                       }
                        priv->tx_skb[j] = (struct sk_buff *) DMA_DUMMY_DESC;
                }
        }
 
        /* set last segment */
        if (nr_frags & 0x1)
-               txd->txd2 = (txd2 | TX_DMA_LS1);
+               txd.txd2 |= TX_DMA_LS1;
        else
-               txd->txd2 = (txd2 | TX_DMA_LS0);
+               txd.txd2 |= TX_DMA_LS0;
+       fe_set_txd(&txd, &priv->tx_dma[j]);
 
        /* store skb to cleanup */
        priv->tx_skb[j] = skb;
@@ -579,18 +606,18 @@ static int fe_tx_map_dma(struct sk_buff *skb, struct net_device *dev,
 
 err_dma:
        /* unmap dma */
-       txd = &priv->tx_dma[idx];
-       txd_unmap_single(&dev->dev, txd);
+       ptxd = &priv->tx_dma[idx];
+       txd_unmap_single(&dev->dev, ptxd);
 
        j = idx;
        unmap_idx = i;
        for (i = 0; i < unmap_idx; i++) {
                if (i & 0x1) {
                        j = NEXT_TX_DESP_IDX(j);
-                       txd = &priv->tx_dma[j];
-                       txd_unmap_page0(&dev->dev, txd);
+                       ptxd = &priv->tx_dma[j];
+                       txd_unmap_page0(&dev->dev, ptxd);
                } else {
-                       txd_unmap_page1(&dev->dev, txd);
+                       txd_unmap_page1(&dev->dev, ptxd);
                }
        }
 
@@ -706,7 +733,7 @@ static int fe_poll_rx(struct napi_struct *napi, int budget,
        int idx = fe_reg_r32(FE_REG_RX_CALC_IDX0);
        struct sk_buff *skb;
        u8 *data, *new_data;
-       struct fe_rx_dma *rxd;
+       struct fe_rx_dma *rxd, trxd;
        int done = 0;
        bool rx_vlan = netdev->features & NETIF_F_HW_VLAN_CTAG_RX;
 
@@ -722,7 +749,8 @@ static int fe_poll_rx(struct napi_struct *napi, int budget,
                rxd = &priv->rx_dma[idx];
                data = priv->rx_data[idx];
 
-               if (!(rxd->rxd2 & RX_DMA_DONE))
+               fe_get_rxd(&trxd, rxd);
+               if (!(trxd.rxd2 & RX_DMA_DONE))
                        break;
 
                /* alloc new buffer */
@@ -748,12 +776,12 @@ static int fe_poll_rx(struct napi_struct *napi, int budget,
                }
                skb_reserve(skb, FE_RX_OFFSET);
 
-               dma_unmap_single(&netdev->dev, rxd->rxd1,
+               dma_unmap_single(&netdev->dev, trxd.rxd1,
                                priv->rx_buf_size, DMA_FROM_DEVICE);
-               pktlen = RX_DMA_PLEN0(rxd->rxd2);
+               pktlen = RX_DMA_PLEN0(trxd.rxd2);
                skb_put(skb, pktlen);
                skb->dev = netdev;
-               if (rxd->rxd4 & checksum_bit) {
+               if (trxd.rxd4 & checksum_bit) {
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                } else {
                        skb_checksum_none_assert(skb);
@@ -775,7 +803,7 @@ static int fe_poll_rx(struct napi_struct *napi, int budget,
 
 release_desc:
                if (soc->rx_dma)
-                       soc->rx_dma(priv, idx, priv->rx_buf_size);
+                       soc->rx_dma(rxd, priv->rx_buf_size);
                else
                        rxd->rxd2 = RX_DMA_LSO;
 
@@ -793,24 +821,24 @@ static int fe_poll_tx(struct fe_priv *priv, int budget)
        struct device *dev = &netdev->dev;
        unsigned int bytes_compl = 0;
        struct sk_buff *skb;
-       struct fe_tx_dma *txd;
+       struct fe_tx_dma txd;
        int done = 0, idx;
        u32 udf_bit = priv->soc->tx_udf_bit;
 
        idx = priv->tx_free_idx;
        while (done < budget) {
-               txd = &priv->tx_dma[idx];
+               fe_get_txd(&txd, &priv->tx_dma[idx]);
                skb = priv->tx_skb[idx];
 
-               if (!(txd->txd2 & TX_DMA_DONE) || !skb)
+               if (!(txd.txd2 & TX_DMA_DONE) || !skb)
                        break;
 
-               txd_unmap_page1(dev, txd);
+               txd_unmap_page1(dev, &txd);
 
-               if (txd->txd4 & udf_bit)
-                       txd_unmap_single(dev, txd);
+               if (txd.txd4 & udf_bit)
+                       txd_unmap_single(dev, &txd);
                else
-                       txd_unmap_page0(dev, txd);
+                       txd_unmap_page0(dev, &txd);
 
                if (skb != (struct sk_buff *) DMA_DUMMY_DESC) {
                        bytes_compl += skb->len;