These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / net / ethernet / amd / xgbe / xgbe-main.c
index 7149053..618d952 100644 (file)
 #include <linux/of.h>
 #include <linux/of_net.h>
 #include <linux/of_address.h>
+#include <linux/of_platform.h>
 #include <linux/clk.h>
 #include <linux/property.h>
 #include <linux/acpi.h>
+#include <linux/mdio.h>
 
 #include "xgbe.h"
 #include "xgbe-common.h"
@@ -136,6 +138,49 @@ MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(XGBE_DRV_VERSION);
 MODULE_DESCRIPTION(XGBE_DRV_DESC);
 
+static int debug = -1;
+module_param(debug, int, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(debug, " Network interface message level setting");
+
+static const u32 default_msg_level = (NETIF_MSG_LINK | NETIF_MSG_IFDOWN |
+                                     NETIF_MSG_IFUP);
+
+static const u32 xgbe_serdes_blwc[] = {
+       XGBE_SPEED_1000_BLWC,
+       XGBE_SPEED_2500_BLWC,
+       XGBE_SPEED_10000_BLWC,
+};
+
+static const u32 xgbe_serdes_cdr_rate[] = {
+       XGBE_SPEED_1000_CDR,
+       XGBE_SPEED_2500_CDR,
+       XGBE_SPEED_10000_CDR,
+};
+
+static const u32 xgbe_serdes_pq_skew[] = {
+       XGBE_SPEED_1000_PQ,
+       XGBE_SPEED_2500_PQ,
+       XGBE_SPEED_10000_PQ,
+};
+
+static const u32 xgbe_serdes_tx_amp[] = {
+       XGBE_SPEED_1000_TXAMP,
+       XGBE_SPEED_2500_TXAMP,
+       XGBE_SPEED_10000_TXAMP,
+};
+
+static const u32 xgbe_serdes_dfe_tap_cfg[] = {
+       XGBE_SPEED_1000_DFE_TAP_CONFIG,
+       XGBE_SPEED_2500_DFE_TAP_CONFIG,
+       XGBE_SPEED_10000_DFE_TAP_CONFIG,
+};
+
+static const u32 xgbe_serdes_dfe_tap_ena[] = {
+       XGBE_SPEED_1000_DFE_TAP_ENABLE,
+       XGBE_SPEED_2500_DFE_TAP_ENABLE,
+       XGBE_SPEED_10000_DFE_TAP_ENABLE,
+};
+
 static void xgbe_default_config(struct xgbe_prv_data *pdata)
 {
        DBGPR("-->xgbe_default_config\n");
@@ -153,8 +198,6 @@ static void xgbe_default_config(struct xgbe_prv_data *pdata)
        pdata->rx_pause = 1;
        pdata->phy_speed = SPEED_UNKNOWN;
        pdata->power_down = 0;
-       pdata->default_autoneg = AUTONEG_ENABLE;
-       pdata->default_speed = SPEED_10000;
 
        DBGPR("<--xgbe_default_config\n");
 }
@@ -162,19 +205,15 @@ static void xgbe_default_config(struct xgbe_prv_data *pdata)
 static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata)
 {
        xgbe_init_function_ptrs_dev(&pdata->hw_if);
+       xgbe_init_function_ptrs_phy(&pdata->phy_if);
        xgbe_init_function_ptrs_desc(&pdata->desc_if);
 }
 
 #ifdef CONFIG_ACPI
 static int xgbe_acpi_support(struct xgbe_prv_data *pdata)
 {
-       struct acpi_device *adev = pdata->adev;
        struct device *dev = pdata->dev;
        u32 property;
-       acpi_handle handle;
-       acpi_status status;
-       unsigned long long data;
-       int cca;
        int ret;
 
        /* Obtain the system clock setting */
@@ -195,24 +234,6 @@ static int xgbe_acpi_support(struct xgbe_prv_data *pdata)
        }
        pdata->ptpclk_rate = property;
 
-       /* Retrieve the device cache coherency value */
-       handle = adev->handle;
-       do {
-               status = acpi_evaluate_integer(handle, "_CCA", NULL, &data);
-               if (!ACPI_FAILURE(status)) {
-                       cca = data;
-                       break;
-               }
-
-               status = acpi_get_parent(handle, &handle);
-       } while (!ACPI_FAILURE(status));
-
-       if (ACPI_FAILURE(status)) {
-               dev_err(dev, "error obtaining acpi coherency value\n");
-               return -EINVAL;
-       }
-       pdata->coherent = !!cca;
-
        return 0;
 }
 #else   /* CONFIG_ACPI */
@@ -243,28 +264,85 @@ static int xgbe_of_support(struct xgbe_prv_data *pdata)
        }
        pdata->ptpclk_rate = clk_get_rate(pdata->ptpclk);
 
-       /* Retrieve the device cache coherency value */
-       pdata->coherent = of_dma_is_coherent(dev->of_node);
-
        return 0;
 }
+
+static struct platform_device *xgbe_of_get_phy_pdev(struct xgbe_prv_data *pdata)
+{
+       struct device *dev = pdata->dev;
+       struct device_node *phy_node;
+       struct platform_device *phy_pdev;
+
+       phy_node = of_parse_phandle(dev->of_node, "phy-handle", 0);
+       if (phy_node) {
+               /* Old style device tree:
+                *   The XGBE and PHY resources are separate
+                */
+               phy_pdev = of_find_device_by_node(phy_node);
+               of_node_put(phy_node);
+       } else {
+               /* New style device tree:
+                *   The XGBE and PHY resources are grouped together with
+                *   the PHY resources listed last
+                */
+               get_device(dev);
+               phy_pdev = pdata->pdev;
+       }
+
+       return phy_pdev;
+}
 #else   /* CONFIG_OF */
 static int xgbe_of_support(struct xgbe_prv_data *pdata)
 {
        return -EINVAL;
 }
-#endif  /*CONFIG_OF */
+
+static struct platform_device *xgbe_of_get_phy_pdev(struct xgbe_prv_data *pdata)
+{
+       return NULL;
+}
+#endif  /* CONFIG_OF */
+
+static unsigned int xgbe_resource_count(struct platform_device *pdev,
+                                       unsigned int type)
+{
+       unsigned int count;
+       int i;
+
+       for (i = 0, count = 0; i < pdev->num_resources; i++) {
+               struct resource *res = &pdev->resource[i];
+
+               if (type == resource_type(res))
+                       count++;
+       }
+
+       return count;
+}
+
+static struct platform_device *xgbe_get_phy_pdev(struct xgbe_prv_data *pdata)
+{
+       struct platform_device *phy_pdev;
+
+       if (pdata->use_acpi) {
+               get_device(pdata->dev);
+               phy_pdev = pdata->pdev;
+       } else {
+               phy_pdev = xgbe_of_get_phy_pdev(pdata);
+       }
+
+       return phy_pdev;
+}
 
 static int xgbe_probe(struct platform_device *pdev)
 {
        struct xgbe_prv_data *pdata;
-       struct xgbe_hw_if *hw_if;
-       struct xgbe_desc_if *desc_if;
        struct net_device *netdev;
-       struct device *dev = &pdev->dev;
+       struct device *dev = &pdev->dev, *phy_dev;
+       struct platform_device *phy_pdev;
        struct resource *res;
        const char *phy_mode;
-       unsigned int i;
+       unsigned int i, phy_memnum, phy_irqnum;
+       enum dev_dma_attr attr;
        int ret;
 
        DBGPR("--> xgbe_probe\n");
@@ -289,8 +367,35 @@ static int xgbe_probe(struct platform_device *pdev)
        mutex_init(&pdata->rss_mutex);
        spin_lock_init(&pdata->tstamp_lock);
 
+       pdata->msg_enable = netif_msg_init(debug, default_msg_level);
+
+       set_bit(XGBE_DOWN, &pdata->dev_state);
+
        /* Check if we should use ACPI or DT */
-       pdata->use_acpi = (!pdata->adev || acpi_disabled) ? 0 : 1;
+       pdata->use_acpi = dev->of_node ? 0 : 1;
+
+       phy_pdev = xgbe_get_phy_pdev(pdata);
+       if (!phy_pdev) {
+               dev_err(dev, "unable to obtain phy device\n");
+               ret = -EINVAL;
+               goto err_phydev;
+       }
+       phy_dev = &phy_pdev->dev;
+
+       if (pdev == phy_pdev) {
+               /* New style device tree or ACPI:
+                *   The XGBE and PHY resources are grouped together with
+                *   the PHY resources listed last
+                */
+               phy_memnum = xgbe_resource_count(pdev, IORESOURCE_MEM) - 3;
+               phy_irqnum = xgbe_resource_count(pdev, IORESOURCE_IRQ) - 1;
+       } else {
+               /* Old style device tree:
+                *   The XGBE and PHY resources are separate
+                */
+               phy_memnum = 0;
+               phy_irqnum = 0;
+       }
 
        /* Set and validate the number of descriptors for a ring */
        BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT);
@@ -318,7 +423,8 @@ static int xgbe_probe(struct platform_device *pdev)
                ret = PTR_ERR(pdata->xgmac_regs);
                goto err_io;
        }
-       DBGPR("  xgmac_regs = %p\n", pdata->xgmac_regs);
+       if (netif_msg_probe(pdata))
+               dev_dbg(dev, "xgmac_regs = %p\n", pdata->xgmac_regs);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        pdata->xpcs_regs = devm_ioremap_resource(dev, res);
@@ -327,7 +433,38 @@ static int xgbe_probe(struct platform_device *pdev)
                ret = PTR_ERR(pdata->xpcs_regs);
                goto err_io;
        }
-       DBGPR("  xpcs_regs  = %p\n", pdata->xpcs_regs);
+       if (netif_msg_probe(pdata))
+               dev_dbg(dev, "xpcs_regs  = %p\n", pdata->xpcs_regs);
+
+       res = platform_get_resource(phy_pdev, IORESOURCE_MEM, phy_memnum++);
+       pdata->rxtx_regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(pdata->rxtx_regs)) {
+               dev_err(dev, "rxtx ioremap failed\n");
+               ret = PTR_ERR(pdata->rxtx_regs);
+               goto err_io;
+       }
+       if (netif_msg_probe(pdata))
+               dev_dbg(dev, "rxtx_regs  = %p\n", pdata->rxtx_regs);
+
+       res = platform_get_resource(phy_pdev, IORESOURCE_MEM, phy_memnum++);
+       pdata->sir0_regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(pdata->sir0_regs)) {
+               dev_err(dev, "sir0 ioremap failed\n");
+               ret = PTR_ERR(pdata->sir0_regs);
+               goto err_io;
+       }
+       if (netif_msg_probe(pdata))
+               dev_dbg(dev, "sir0_regs  = %p\n", pdata->sir0_regs);
+
+       res = platform_get_resource(phy_pdev, IORESOURCE_MEM, phy_memnum++);
+       pdata->sir1_regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(pdata->sir1_regs)) {
+               dev_err(dev, "sir1 ioremap failed\n");
+               ret = PTR_ERR(pdata->sir1_regs);
+               goto err_io;
+       }
+       if (netif_msg_probe(pdata))
+               dev_dbg(dev, "sir1_regs  = %p\n", pdata->sir1_regs);
 
        /* Retrieve the MAC address */
        ret = device_property_read_u8_array(dev, XGBE_MAC_ADDR_PROPERTY,
@@ -355,6 +492,115 @@ static int xgbe_probe(struct platform_device *pdev)
        if (device_property_present(dev, XGBE_DMA_IRQS_PROPERTY))
                pdata->per_channel_irq = 1;
 
+       /* Retrieve the PHY speedset */
+       ret = device_property_read_u32(phy_dev, XGBE_SPEEDSET_PROPERTY,
+                                      &pdata->speed_set);
+       if (ret) {
+               dev_err(dev, "invalid %s property\n", XGBE_SPEEDSET_PROPERTY);
+               goto err_io;
+       }
+
+       switch (pdata->speed_set) {
+       case XGBE_SPEEDSET_1000_10000:
+       case XGBE_SPEEDSET_2500_10000:
+               break;
+       default:
+               dev_err(dev, "invalid %s property\n", XGBE_SPEEDSET_PROPERTY);
+               ret = -EINVAL;
+               goto err_io;
+       }
+
+       /* Retrieve the PHY configuration properties */
+       if (device_property_present(phy_dev, XGBE_BLWC_PROPERTY)) {
+               ret = device_property_read_u32_array(phy_dev,
+                                                    XGBE_BLWC_PROPERTY,
+                                                    pdata->serdes_blwc,
+                                                    XGBE_SPEEDS);
+               if (ret) {
+                       dev_err(dev, "invalid %s property\n",
+                               XGBE_BLWC_PROPERTY);
+                       goto err_io;
+               }
+       } else {
+               memcpy(pdata->serdes_blwc, xgbe_serdes_blwc,
+                      sizeof(pdata->serdes_blwc));
+       }
+
+       if (device_property_present(phy_dev, XGBE_CDR_RATE_PROPERTY)) {
+               ret = device_property_read_u32_array(phy_dev,
+                                                    XGBE_CDR_RATE_PROPERTY,
+                                                    pdata->serdes_cdr_rate,
+                                                    XGBE_SPEEDS);
+               if (ret) {
+                       dev_err(dev, "invalid %s property\n",
+                               XGBE_CDR_RATE_PROPERTY);
+                       goto err_io;
+               }
+       } else {
+               memcpy(pdata->serdes_cdr_rate, xgbe_serdes_cdr_rate,
+                      sizeof(pdata->serdes_cdr_rate));
+       }
+
+       if (device_property_present(phy_dev, XGBE_PQ_SKEW_PROPERTY)) {
+               ret = device_property_read_u32_array(phy_dev,
+                                                    XGBE_PQ_SKEW_PROPERTY,
+                                                    pdata->serdes_pq_skew,
+                                                    XGBE_SPEEDS);
+               if (ret) {
+                       dev_err(dev, "invalid %s property\n",
+                               XGBE_PQ_SKEW_PROPERTY);
+                       goto err_io;
+               }
+       } else {
+               memcpy(pdata->serdes_pq_skew, xgbe_serdes_pq_skew,
+                      sizeof(pdata->serdes_pq_skew));
+       }
+
+       if (device_property_present(phy_dev, XGBE_TX_AMP_PROPERTY)) {
+               ret = device_property_read_u32_array(phy_dev,
+                                                    XGBE_TX_AMP_PROPERTY,
+                                                    pdata->serdes_tx_amp,
+                                                    XGBE_SPEEDS);
+               if (ret) {
+                       dev_err(dev, "invalid %s property\n",
+                               XGBE_TX_AMP_PROPERTY);
+                       goto err_io;
+               }
+       } else {
+               memcpy(pdata->serdes_tx_amp, xgbe_serdes_tx_amp,
+                      sizeof(pdata->serdes_tx_amp));
+       }
+
+       if (device_property_present(phy_dev, XGBE_DFE_CFG_PROPERTY)) {
+               ret = device_property_read_u32_array(phy_dev,
+                                                    XGBE_DFE_CFG_PROPERTY,
+                                                    pdata->serdes_dfe_tap_cfg,
+                                                    XGBE_SPEEDS);
+               if (ret) {
+                       dev_err(dev, "invalid %s property\n",
+                               XGBE_DFE_CFG_PROPERTY);
+                       goto err_io;
+               }
+       } else {
+               memcpy(pdata->serdes_dfe_tap_cfg, xgbe_serdes_dfe_tap_cfg,
+                      sizeof(pdata->serdes_dfe_tap_cfg));
+       }
+
+       if (device_property_present(phy_dev, XGBE_DFE_ENA_PROPERTY)) {
+               ret = device_property_read_u32_array(phy_dev,
+                                                    XGBE_DFE_ENA_PROPERTY,
+                                                    pdata->serdes_dfe_tap_ena,
+                                                    XGBE_SPEEDS);
+               if (ret) {
+                       dev_err(dev, "invalid %s property\n",
+                               XGBE_DFE_ENA_PROPERTY);
+                       goto err_io;
+               }
+       } else {
+               memcpy(pdata->serdes_dfe_tap_ena, xgbe_serdes_dfe_tap_ena,
+                      sizeof(pdata->serdes_dfe_tap_ena));
+       }
+
        /* Obtain device settings unique to ACPI/OF */
        if (pdata->use_acpi)
                ret = xgbe_acpi_support(pdata);
@@ -364,6 +610,12 @@ static int xgbe_probe(struct platform_device *pdev)
                goto err_io;
 
        /* Set the DMA coherency values */
+       attr = device_get_dma_attr(dev);
+       if (attr == DEV_DMA_NOT_SUPPORTED) {
+               dev_err(dev, "DMA is not supported");
+               goto err_io;
+       }
+       pdata->coherent = (attr == DEV_DMA_COHERENT);
        if (pdata->coherent) {
                pdata->axdomain = XGBE_DMA_OS_AXDOMAIN;
                pdata->arcache = XGBE_DMA_OS_ARCACHE;
@@ -382,17 +634,23 @@ static int xgbe_probe(struct platform_device *pdev)
        }
        pdata->dev_irq = ret;
 
+       /* Get the auto-negotiation interrupt */
+       ret = platform_get_irq(phy_pdev, phy_irqnum++);
+       if (ret < 0) {
+               dev_err(dev, "platform_get_irq phy 0 failed\n");
+               goto err_io;
+       }
+       pdata->an_irq = ret;
+
        netdev->irq = pdata->dev_irq;
        netdev->base_addr = (unsigned long)pdata->xgmac_regs;
        memcpy(netdev->dev_addr, pdata->mac_addr, netdev->addr_len);
 
        /* Set all the function pointers */
        xgbe_init_all_fptrs(pdata);
-       hw_if = &pdata->hw_if;
-       desc_if = &pdata->desc_if;
 
        /* Issue software reset to device */
-       hw_if->exit(pdata);
+       pdata->hw_if.exit(pdata);
 
        /* Populate the hardware features */
        xgbe_get_all_hw_features(pdata);
@@ -401,8 +659,6 @@ static int xgbe_probe(struct platform_device *pdev)
        xgbe_default_config(pdata);
 
        /* Set the DMA mask */
-       if (!dev->dma_mask)
-               dev->dma_mask = &dev->coherent_dma_mask;
        ret = dma_set_mask_and_coherent(dev,
                                        DMA_BIT_MASK(pdata->hw_feat.dma_width));
        if (ret) {
@@ -447,16 +703,8 @@ static int xgbe_probe(struct platform_device *pdev)
        XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, TCP4TE, 1);
        XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1);
 
-       /* Prepare to regsiter with MDIO */
-       pdata->mii_bus_id = kasprintf(GFP_KERNEL, "%s", pdev->name);
-       if (!pdata->mii_bus_id) {
-               dev_err(dev, "failed to allocate mii bus id\n");
-               ret = -ENOMEM;
-               goto err_io;
-       }
-       ret = xgbe_mdio_register(pdata);
-       if (ret)
-               goto err_bus_id;
+       /* Call MDIO/PHY initialization routine */
+       pdata->phy_if.phy_init(pdata);
 
        /* Set device operations */
        netdev->netdev_ops = xgbe_get_netdev_ops();
@@ -501,26 +749,52 @@ static int xgbe_probe(struct platform_device *pdev)
        ret = register_netdev(netdev);
        if (ret) {
                dev_err(dev, "net device registration failed\n");
-               goto err_reg_netdev;
+               goto err_io;
+       }
+
+       /* Create the PHY/ANEG name based on netdev name */
+       snprintf(pdata->an_name, sizeof(pdata->an_name) - 1, "%s-pcs",
+                netdev_name(netdev));
+
+       /* Create workqueues */
+       pdata->dev_workqueue =
+               create_singlethread_workqueue(netdev_name(netdev));
+       if (!pdata->dev_workqueue) {
+               netdev_err(netdev, "device workqueue creation failed\n");
+               ret = -ENOMEM;
+               goto err_netdev;
+       }
+
+       pdata->an_workqueue =
+               create_singlethread_workqueue(pdata->an_name);
+       if (!pdata->an_workqueue) {
+               netdev_err(netdev, "phy workqueue creation failed\n");
+               ret = -ENOMEM;
+               goto err_wq;
        }
 
        xgbe_ptp_register(pdata);
 
        xgbe_debugfs_init(pdata);
 
+       platform_device_put(phy_pdev);
+
        netdev_notice(netdev, "net device enabled\n");
 
        DBGPR("<-- xgbe_probe\n");
 
        return 0;
 
-err_reg_netdev:
-       xgbe_mdio_unregister(pdata);
+err_wq:
+       destroy_workqueue(pdata->dev_workqueue);
 
-err_bus_id:
-       kfree(pdata->mii_bus_id);
+err_netdev:
+       unregister_netdev(netdev);
 
 err_io:
+       platform_device_put(phy_pdev);
+
+err_phydev:
        free_netdev(netdev);
 
 err_alloc:
@@ -540,11 +814,13 @@ static int xgbe_remove(struct platform_device *pdev)
 
        xgbe_ptp_unregister(pdata);
 
-       unregister_netdev(netdev);
+       flush_workqueue(pdata->an_workqueue);
+       destroy_workqueue(pdata->an_workqueue);
 
-       xgbe_mdio_unregister(pdata);
+       flush_workqueue(pdata->dev_workqueue);
+       destroy_workqueue(pdata->dev_workqueue);
 
-       kfree(pdata->mii_bus_id);
+       unregister_netdev(netdev);
 
        free_netdev(netdev);
 
@@ -557,16 +833,17 @@ static int xgbe_remove(struct platform_device *pdev)
 static int xgbe_suspend(struct device *dev)
 {
        struct net_device *netdev = dev_get_drvdata(dev);
-       int ret;
+       struct xgbe_prv_data *pdata = netdev_priv(netdev);
+       int ret = 0;
 
        DBGPR("-->xgbe_suspend\n");
 
-       if (!netif_running(netdev)) {
-               DBGPR("<--xgbe_dev_suspend\n");
-               return -EINVAL;
-       }
+       if (netif_running(netdev))
+               ret = xgbe_powerdown(netdev, XGMAC_DRIVER_CONTEXT);
 
-       ret = xgbe_powerdown(netdev, XGMAC_DRIVER_CONTEXT);
+       pdata->lpm_ctrl = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
+       pdata->lpm_ctrl |= MDIO_CTRL1_LPOWER;
+       XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl);
 
        DBGPR("<--xgbe_suspend\n");
 
@@ -576,16 +853,16 @@ static int xgbe_suspend(struct device *dev)
 static int xgbe_resume(struct device *dev)
 {
        struct net_device *netdev = dev_get_drvdata(dev);
-       int ret;
+       struct xgbe_prv_data *pdata = netdev_priv(netdev);
+       int ret = 0;
 
        DBGPR("-->xgbe_resume\n");
 
-       if (!netif_running(netdev)) {
-               DBGPR("<--xgbe_dev_resume\n");
-               return -EINVAL;
-       }
+       pdata->lpm_ctrl &= ~MDIO_CTRL1_LPOWER;
+       XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl);
 
-       ret = xgbe_powerup(netdev, XGMAC_DRIVER_CONTEXT);
+       if (netif_running(netdev))
+               ret = xgbe_powerup(netdev, XGMAC_DRIVER_CONTEXT);
 
        DBGPR("<--xgbe_resume\n");