Merge branch 'ftgmac100-ast2500-support'
authorDavid S. Miller <davem@davemloft.net>
Thu, 22 Sep 2016 07:31:22 +0000 (03:31 -0400)
committerDavid S. Miller <davem@davemloft.net>
Thu, 22 Sep 2016 07:31:22 +0000 (03:31 -0400)
Joel Stanley says:

====================
ftgmac100 support for ast2500

This series adds support to the ftgmac100 driver for the Aspeed ast2400 and
ast2500 SoCs. In particular, they ensure the driver works correctly on the
ast2500 where the MAC block has seen some changes in register layout.

They have been tested on ast2400 and ast2500 systems with the NCSI stack and
with a directly attached PHY.

V2 reworks the two patches relating to PHYSTS_CHG into the one patch that
disables the interrupt instead of playing with interrupt sensitivity. I kept
patch 4 'net/faraday: Clear stale interrupts' which was first introduced to
clear the stale PHYSTS_CHG interrupt, as it helps keep us safe from unhygienic
(vendor) bootloaders.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/faraday/ftgmac100.c
drivers/net/ethernet/faraday/ftgmac100.h

index 36361f8..90f9c54 100644 (file)
@@ -60,6 +60,8 @@ struct ftgmac100 {
        struct ftgmac100_descs *descs;
        dma_addr_t descs_dma_addr;
 
+       struct page *rx_pages[RX_QUEUE_ENTRIES];
+
        unsigned int rx_pointer;
        unsigned int tx_clean_pointer;
        unsigned int tx_pointer;
@@ -77,6 +79,9 @@ struct ftgmac100 {
        int int_mask_all;
        bool use_ncsi;
        bool enabled;
+
+       u32 rxdes0_edorr_mask;
+       u32 txdes0_edotr_mask;
 };
 
 static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv,
@@ -257,10 +262,11 @@ static bool ftgmac100_rxdes_packet_ready(struct ftgmac100_rxdes *rxdes)
        return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RXPKT_RDY);
 }
 
-static void ftgmac100_rxdes_set_dma_own(struct ftgmac100_rxdes *rxdes)
+static void ftgmac100_rxdes_set_dma_own(const struct ftgmac100 *priv,
+                                       struct ftgmac100_rxdes *rxdes)
 {
        /* clear status bits */
-       rxdes->rxdes0 &= cpu_to_le32(FTGMAC100_RXDES0_EDORR);
+       rxdes->rxdes0 &= cpu_to_le32(priv->rxdes0_edorr_mask);
 }
 
 static bool ftgmac100_rxdes_rx_error(struct ftgmac100_rxdes *rxdes)
@@ -298,9 +304,10 @@ static bool ftgmac100_rxdes_multicast(struct ftgmac100_rxdes *rxdes)
        return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_MULTICAST);
 }
 
-static void ftgmac100_rxdes_set_end_of_ring(struct ftgmac100_rxdes *rxdes)
+static void ftgmac100_rxdes_set_end_of_ring(const struct ftgmac100 *priv,
+                                           struct ftgmac100_rxdes *rxdes)
 {
-       rxdes->rxdes0 |= cpu_to_le32(FTGMAC100_RXDES0_EDORR);
+       rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask);
 }
 
 static void ftgmac100_rxdes_set_dma_addr(struct ftgmac100_rxdes *rxdes,
@@ -341,18 +348,27 @@ static bool ftgmac100_rxdes_ipcs_err(struct ftgmac100_rxdes *rxdes)
        return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_IP_CHKSUM_ERR);
 }
 
+static inline struct page **ftgmac100_rxdes_page_slot(struct ftgmac100 *priv,
+                                                     struct ftgmac100_rxdes *rxdes)
+{
+       return &priv->rx_pages[rxdes - priv->descs->rxdes];
+}
+
 /*
  * rxdes2 is not used by hardware. We use it to keep track of page.
  * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
  */
-static void ftgmac100_rxdes_set_page(struct ftgmac100_rxdes *rxdes, struct page *page)
+static void ftgmac100_rxdes_set_page(struct ftgmac100 *priv,
+                                    struct ftgmac100_rxdes *rxdes,
+                                    struct page *page)
 {
-       rxdes->rxdes2 = (unsigned int)page;
+       *ftgmac100_rxdes_page_slot(priv, rxdes) = page;
 }
 
-static struct page *ftgmac100_rxdes_get_page(struct ftgmac100_rxdes *rxdes)
+static struct page *ftgmac100_rxdes_get_page(struct ftgmac100 *priv,
+                                            struct ftgmac100_rxdes *rxdes)
 {
-       return (struct page *)rxdes->rxdes2;
+       return *ftgmac100_rxdes_page_slot(priv, rxdes);
 }
 
 /******************************************************************************
@@ -382,7 +398,7 @@ ftgmac100_rx_locate_first_segment(struct ftgmac100 *priv)
                if (ftgmac100_rxdes_first_segment(rxdes))
                        return rxdes;
 
-               ftgmac100_rxdes_set_dma_own(rxdes);
+               ftgmac100_rxdes_set_dma_own(priv, rxdes);
                ftgmac100_rx_pointer_advance(priv);
                rxdes = ftgmac100_current_rxdes(priv);
        }
@@ -453,7 +469,7 @@ static void ftgmac100_rx_drop_packet(struct ftgmac100 *priv)
                if (ftgmac100_rxdes_last_segment(rxdes))
                        done = true;
 
-               ftgmac100_rxdes_set_dma_own(rxdes);
+               ftgmac100_rxdes_set_dma_own(priv, rxdes);
                ftgmac100_rx_pointer_advance(priv);
                rxdes = ftgmac100_current_rxdes(priv);
        } while (!done && ftgmac100_rxdes_packet_ready(rxdes));
@@ -501,7 +517,7 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
 
        do {
                dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes);
-               struct page *page = ftgmac100_rxdes_get_page(rxdes);
+               struct page *page = ftgmac100_rxdes_get_page(priv, rxdes);
                unsigned int size;
 
                dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
@@ -545,10 +561,11 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
 /******************************************************************************
  * internal functions (transmit descriptor)
  *****************************************************************************/
-static void ftgmac100_txdes_reset(struct ftgmac100_txdes *txdes)
+static void ftgmac100_txdes_reset(const struct ftgmac100 *priv,
+                                 struct ftgmac100_txdes *txdes)
 {
        /* clear all except end of ring bit */
-       txdes->txdes0 &= cpu_to_le32(FTGMAC100_TXDES0_EDOTR);
+       txdes->txdes0 &= cpu_to_le32(priv->txdes0_edotr_mask);
        txdes->txdes1 = 0;
        txdes->txdes2 = 0;
        txdes->txdes3 = 0;
@@ -569,9 +586,10 @@ static void ftgmac100_txdes_set_dma_own(struct ftgmac100_txdes *txdes)
        txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN);
 }
 
-static void ftgmac100_txdes_set_end_of_ring(struct ftgmac100_txdes *txdes)
+static void ftgmac100_txdes_set_end_of_ring(const struct ftgmac100 *priv,
+                                           struct ftgmac100_txdes *txdes)
 {
-       txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_EDOTR);
+       txdes->txdes0 |= cpu_to_le32(priv->txdes0_edotr_mask);
 }
 
 static void ftgmac100_txdes_set_first_segment(struct ftgmac100_txdes *txdes)
@@ -690,7 +708,7 @@ static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv)
 
        dev_kfree_skb(skb);
 
-       ftgmac100_txdes_reset(txdes);
+       ftgmac100_txdes_reset(priv, txdes);
 
        ftgmac100_tx_clean_pointer_advance(priv);
 
@@ -779,9 +797,9 @@ static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv,
                return -ENOMEM;
        }
 
-       ftgmac100_rxdes_set_page(rxdes, page);
+       ftgmac100_rxdes_set_page(priv, rxdes, page);
        ftgmac100_rxdes_set_dma_addr(rxdes, map);
-       ftgmac100_rxdes_set_dma_own(rxdes);
+       ftgmac100_rxdes_set_dma_own(priv, rxdes);
        return 0;
 }
 
@@ -791,7 +809,7 @@ static void ftgmac100_free_buffers(struct ftgmac100 *priv)
 
        for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
                struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
-               struct page *page = ftgmac100_rxdes_get_page(rxdes);
+               struct page *page = ftgmac100_rxdes_get_page(priv, rxdes);
                dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes);
 
                if (!page)
@@ -828,7 +846,8 @@ static int ftgmac100_alloc_buffers(struct ftgmac100 *priv)
                return -ENOMEM;
 
        /* initialize RX ring */
-       ftgmac100_rxdes_set_end_of_ring(&priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
+       ftgmac100_rxdes_set_end_of_ring(priv,
+                                       &priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
 
        for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
                struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
@@ -838,7 +857,8 @@ static int ftgmac100_alloc_buffers(struct ftgmac100 *priv)
        }
 
        /* initialize TX ring */
-       ftgmac100_txdes_set_end_of_ring(&priv->descs->txdes[TX_QUEUE_ENTRIES - 1]);
+       ftgmac100_txdes_set_end_of_ring(priv,
+                                       &priv->descs->txdes[TX_QUEUE_ENTRIES - 1]);
        return 0;
 
 err:
@@ -1055,14 +1075,12 @@ static int ftgmac100_poll(struct napi_struct *napi, int budget)
        }
 
        if (status & priv->int_mask_all & (FTGMAC100_INT_NO_RXBUF |
-                       FTGMAC100_INT_RPKT_LOST | FTGMAC100_INT_AHB_ERR |
-                       FTGMAC100_INT_PHYSTS_CHG)) {
+                       FTGMAC100_INT_RPKT_LOST | FTGMAC100_INT_AHB_ERR)) {
                if (net_ratelimit())
-                       netdev_info(netdev, "[ISR] = 0x%x: %s%s%s%s\n", status,
+                       netdev_info(netdev, "[ISR] = 0x%x: %s%s%s\n", status,
                                    status & FTGMAC100_INT_NO_RXBUF ? "NO_RXBUF " : "",
                                    status & FTGMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "",
-                                   status & FTGMAC100_INT_AHB_ERR ? "AHB_ERR " : "",
-                                   status & FTGMAC100_INT_PHYSTS_CHG ? "PHYSTS_CHG" : "");
+                                   status & FTGMAC100_INT_AHB_ERR ? "AHB_ERR " : "");
 
                if (status & FTGMAC100_INT_NO_RXBUF) {
                        /* RX buffer unavailable */
@@ -1092,6 +1110,7 @@ static int ftgmac100_poll(struct napi_struct *napi, int budget)
 static int ftgmac100_open(struct net_device *netdev)
 {
        struct ftgmac100 *priv = netdev_priv(netdev);
+       unsigned int status;
        int err;
 
        err = ftgmac100_alloc_buffers(priv);
@@ -1117,6 +1136,11 @@ static int ftgmac100_open(struct net_device *netdev)
 
        ftgmac100_init_hw(priv);
        ftgmac100_start_hw(priv, priv->use_ncsi ? 100 : 10);
+
+       /* Clear stale interrupts */
+       status = ioread32(priv->base + FTGMAC100_OFFSET_ISR);
+       iowrite32(status, priv->base + FTGMAC100_OFFSET_ISR);
+
        if (netdev->phydev)
                phy_start(netdev->phydev);
        else if (priv->use_ncsi)
@@ -1226,12 +1250,21 @@ static int ftgmac100_setup_mdio(struct net_device *netdev)
        struct ftgmac100 *priv = netdev_priv(netdev);
        struct platform_device *pdev = to_platform_device(priv->dev);
        int i, err = 0;
+       u32 reg;
 
        /* initialize mdio bus */
        priv->mii_bus = mdiobus_alloc();
        if (!priv->mii_bus)
                return -EIO;
 
+       if (of_machine_is_compatible("aspeed,ast2400") ||
+           of_machine_is_compatible("aspeed,ast2500")) {
+               /* This driver supports the old MDIO interface */
+               reg = ioread32(priv->base + FTGMAC100_OFFSET_REVR);
+               reg &= ~FTGMAC100_REVR_NEW_MDIO_INTERFACE;
+               iowrite32(reg, priv->base + FTGMAC100_OFFSET_REVR);
+       };
+
        priv->mii_bus->name = "ftgmac100_mdio";
        snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%d",
                 pdev->name, pdev->id);
@@ -1355,9 +1388,18 @@ static int ftgmac100_probe(struct platform_device *pdev)
                              FTGMAC100_INT_XPKT_ETH |
                              FTGMAC100_INT_XPKT_LOST |
                              FTGMAC100_INT_AHB_ERR |
-                             FTGMAC100_INT_PHYSTS_CHG |
                              FTGMAC100_INT_RPKT_BUF |
                              FTGMAC100_INT_NO_RXBUF);
+
+       if (of_machine_is_compatible("aspeed,ast2400") ||
+           of_machine_is_compatible("aspeed,ast2500")) {
+               priv->rxdes0_edorr_mask = BIT(30);
+               priv->txdes0_edotr_mask = BIT(30);
+       } else {
+               priv->rxdes0_edorr_mask = BIT(15);
+               priv->txdes0_edotr_mask = BIT(15);
+       }
+
        if (pdev->dev.of_node &&
            of_get_property(pdev->dev.of_node, "use-ncsi", NULL)) {
                if (!IS_ENABLED(CONFIG_NET_NCSI)) {
@@ -1367,7 +1409,6 @@ static int ftgmac100_probe(struct platform_device *pdev)
 
                dev_info(&pdev->dev, "Using NCSI interface\n");
                priv->use_ncsi = true;
-               priv->int_mask_all &= ~FTGMAC100_INT_PHYSTS_CHG;
                priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler);
                if (!priv->ndev)
                        goto err_ncsi_dev;
index 13408d4..a7ce0ac 100644 (file)
 #define FTGMAC100_DMAFIFOS_RXDMA_REQ           (1 << 30)
 #define FTGMAC100_DMAFIFOS_TXDMA_REQ           (1 << 31)
 
+/*
+ * Feature Register
+ */
+#define FTGMAC100_REVR_NEW_MDIO_INTERFACE      BIT(31)
+
 /*
  * Receive buffer size register
  */
 #define FTGMAC100_MACCR_FULLDUP                (1 << 8)
 #define FTGMAC100_MACCR_GIGA_MODE      (1 << 9)
 #define FTGMAC100_MACCR_CRC_APD                (1 << 10)
+#define FTGMAC100_MACCR_PHY_LINK_LEVEL (1 << 11)
 #define FTGMAC100_MACCR_RX_RUNT                (1 << 12)
 #define FTGMAC100_MACCR_JUMBO_LF       (1 << 13)
 #define FTGMAC100_MACCR_RX_ALL         (1 << 14)
@@ -189,7 +195,6 @@ struct ftgmac100_txdes {
 } __attribute__ ((aligned(16)));
 
 #define FTGMAC100_TXDES0_TXBUF_SIZE(x) ((x) & 0x3fff)
-#define FTGMAC100_TXDES0_EDOTR         (1 << 15)
 #define FTGMAC100_TXDES0_CRC_ERR       (1 << 19)
 #define FTGMAC100_TXDES0_LTS           (1 << 28)
 #define FTGMAC100_TXDES0_FTS           (1 << 29)
@@ -215,7 +220,6 @@ struct ftgmac100_rxdes {
 } __attribute__ ((aligned(16)));
 
 #define FTGMAC100_RXDES0_VDBC          0x3fff
-#define FTGMAC100_RXDES0_EDORR         (1 << 15)
 #define FTGMAC100_RXDES0_MULTICAST     (1 << 16)
 #define FTGMAC100_RXDES0_BROADCAST     (1 << 17)
 #define FTGMAC100_RXDES0_RX_ERR                (1 << 18)