amd-xgbe: Add BQL support
[firefly-linux-kernel-4.4.55.git] / drivers / net / ethernet / amd / xgbe / xgbe-dev.c
index 551794c29d09e05e33ff5e2b505d9dbf7f7bb541..78db5a6576997f4e7f75d7e5658835022a44249e 100644 (file)
@@ -419,6 +419,24 @@ static int xgbe_write_rss_lookup_table(struct xgbe_prv_data *pdata)
        return 0;
 }
 
+static int xgbe_set_rss_hash_key(struct xgbe_prv_data *pdata, const u8 *key)
+{
+       memcpy(pdata->rss_key, key, sizeof(pdata->rss_key));
+
+       return xgbe_write_rss_hash_key(pdata);
+}
+
+static int xgbe_set_rss_lookup_table(struct xgbe_prv_data *pdata,
+                                    const u32 *table)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(pdata->rss_table); i++)
+               XGMAC_SET_BITS(pdata->rss_table[i], MAC_RSSDR, DMCH, table[i]);
+
+       return xgbe_write_rss_lookup_table(pdata);
+}
+
 static int xgbe_enable_rss(struct xgbe_prv_data *pdata)
 {
        int ret;
@@ -1067,10 +1085,10 @@ static void xgbe_rx_desc_reset(struct xgbe_ring_data *rdata)
         *   Set buffer 2 (hi) address to buffer dma address (hi) and
         *     set control bits OWN and INTE
         */
-       rdesc->desc0 = cpu_to_le32(lower_32_bits(rdata->rx_hdr.dma));
-       rdesc->desc1 = cpu_to_le32(upper_32_bits(rdata->rx_hdr.dma));
-       rdesc->desc2 = cpu_to_le32(lower_32_bits(rdata->rx_buf.dma));
-       rdesc->desc3 = cpu_to_le32(upper_32_bits(rdata->rx_buf.dma));
+       rdesc->desc0 = cpu_to_le32(lower_32_bits(rdata->rx.hdr.dma));
+       rdesc->desc1 = cpu_to_le32(upper_32_bits(rdata->rx.hdr.dma));
+       rdesc->desc2 = cpu_to_le32(lower_32_bits(rdata->rx.buf.dma));
+       rdesc->desc3 = cpu_to_le32(upper_32_bits(rdata->rx.buf.dma));
 
        XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE,
                          rdata->interrupt ? 1 : 0);
@@ -1482,6 +1500,10 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
        /* Set LAST bit for the last descriptor */
        XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, LD, 1);
 
+       /* Save the Tx info to report back during cleanup */
+       rdata->tx.packets = packet->tx_packets;
+       rdata->tx.bytes = packet->tx_bytes;
+
        /* In case the Tx DMA engine is running, make sure everything
         * is written to the descriptor(s) before setting the OWN bit
         * for the first descriptor
@@ -1540,6 +1562,9 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
        if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, OWN))
                return 1;
 
+       /* Make sure descriptor fields are read after reading the OWN bit */
+       rmb();
+
 #ifdef XGMAC_ENABLE_RX_DESC_DUMP
        xgbe_dump_rx_desc(ring, rdesc, ring->cur);
 #endif
@@ -1565,8 +1590,8 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
 
        /* Get the header length */
        if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, FD))
-               rdata->hdr_len = XGMAC_GET_BITS_LE(rdesc->desc2,
-                                                  RX_NORMAL_DESC2, HL);
+               rdata->rx.hdr_len = XGMAC_GET_BITS_LE(rdesc->desc2,
+                                                     RX_NORMAL_DESC2, HL);
 
        /* Get the RSS hash */
        if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, RSV)) {
@@ -1582,14 +1607,14 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
                case RX_DESC3_L34T_IPV6_TCP:
                case RX_DESC3_L34T_IPV6_UDP:
                        packet->rss_hash_type = PKT_HASH_TYPE_L4;
-
+                       break;
                default:
                        packet->rss_hash_type = PKT_HASH_TYPE_L3;
                }
        }
 
        /* Get the packet length */
-       rdata->len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
+       rdata->rx.len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
 
        if (!XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, LD)) {
                /* Not all the data has been transferred for this packet */
@@ -1612,7 +1637,8 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
        etlt = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, ETLT);
        DBGPR("  err=%u, etlt=%#x\n", err, etlt);
 
-       if (!err || (err && !etlt)) {
+       if (!err || !etlt) {
+               /* No error if err is 0 or etlt is 0 */
                if ((etlt == 0x09) &&
                    (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
                        XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
@@ -2432,6 +2458,47 @@ static void xgbe_config_mmc(struct xgbe_prv_data *pdata)
        XGMAC_IOWRITE_BITS(pdata, MMC_CR, CR, 1);
 }
 
+static void xgbe_prepare_tx_stop(struct xgbe_prv_data *pdata,
+                                struct xgbe_channel *channel)
+{
+       unsigned int tx_dsr, tx_pos, tx_qidx;
+       unsigned int tx_status;
+       unsigned long tx_timeout;
+
+       /* Calculate the status register to read and the position within */
+       if (channel->queue_index < DMA_DSRX_FIRST_QUEUE) {
+               tx_dsr = DMA_DSR0;
+               tx_pos = (channel->queue_index * DMA_DSR_Q_WIDTH) +
+                        DMA_DSR0_TPS_START;
+       } else {
+               tx_qidx = channel->queue_index - DMA_DSRX_FIRST_QUEUE;
+
+               tx_dsr = DMA_DSR1 + ((tx_qidx / DMA_DSRX_QPR) * DMA_DSRX_INC);
+               tx_pos = ((tx_qidx % DMA_DSRX_QPR) * DMA_DSR_Q_WIDTH) +
+                        DMA_DSRX_TPS_START;
+       }
+
+       /* The Tx engine cannot be stopped if it is actively processing
+        * descriptors. Wait for the Tx engine to enter the stopped or
+        * suspended state.  Don't wait forever though...
+        */
+       tx_timeout = jiffies + (XGBE_DMA_STOP_TIMEOUT * HZ);
+       while (time_before(jiffies, tx_timeout)) {
+               tx_status = XGMAC_IOREAD(pdata, tx_dsr);
+               tx_status = GET_BITS(tx_status, tx_pos, DMA_DSR_TPS_WIDTH);
+               if ((tx_status == DMA_TPS_STOPPED) ||
+                   (tx_status == DMA_TPS_SUSPENDED))
+                       break;
+
+               usleep_range(500, 1000);
+       }
+
+       if (!time_before(jiffies, tx_timeout))
+               netdev_info(pdata->netdev,
+                           "timed out waiting for Tx DMA channel %u to stop\n",
+                           channel->queue_index);
+}
+
 static void xgbe_enable_tx(struct xgbe_prv_data *pdata)
 {
        struct xgbe_channel *channel;
@@ -2460,6 +2527,15 @@ static void xgbe_disable_tx(struct xgbe_prv_data *pdata)
        struct xgbe_channel *channel;
        unsigned int i;
 
+       /* Prepare for Tx DMA channel stop */
+       channel = pdata->channel;
+       for (i = 0; i < pdata->channel_count; i++, channel++) {
+               if (!channel->tx_ring)
+                       break;
+
+               xgbe_prepare_tx_stop(pdata, channel);
+       }
+
        /* Disable MAC Tx */
        XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 0);
 
@@ -2551,6 +2627,15 @@ static void xgbe_powerdown_tx(struct xgbe_prv_data *pdata)
        struct xgbe_channel *channel;
        unsigned int i;
 
+       /* Prepare for Tx DMA channel stop */
+       channel = pdata->channel;
+       for (i = 0; i < pdata->channel_count; i++, channel++) {
+               if (!channel->tx_ring)
+                       break;
+
+               xgbe_prepare_tx_stop(pdata, channel);
+       }
+
        /* Disable MAC Tx */
        XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 0);
 
@@ -2759,6 +2844,8 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if)
        /* For Receive Side Scaling */
        hw_if->enable_rss = xgbe_enable_rss;
        hw_if->disable_rss = xgbe_disable_rss;
+       hw_if->set_rss_hash_key = xgbe_set_rss_hash_key;
+       hw_if->set_rss_lookup_table = xgbe_set_rss_lookup_table;
 
        DBGPR("<--xgbe_init_function_ptrs\n");
 }