From: Mark Salter msalter@redhat.com
--- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 77 ++++++++++++++++++++---- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 68 ++++++++++++++++++--- drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 1 + 3 files changed, 126 insertions(+), 20 deletions(-)
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 63ea194..bb059b4 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -579,9 +579,11 @@ static void xgene_enet_reset(struct xgene_enet_pdata *pdata) { u32 val;
- clk_prepare_enable(pdata->clk); - clk_disable_unprepare(pdata->clk); - clk_prepare_enable(pdata->clk); + if (pdata->clk) { + clk_prepare_enable(pdata->clk); + clk_disable_unprepare(pdata->clk); + clk_prepare_enable(pdata->clk); + } xgene_enet_ecc_init(pdata); xgene_enet_config_ring_if_assoc(pdata);
@@ -647,15 +649,20 @@ static int xgene_enet_phy_connect(struct net_device *ndev) struct phy_device *phy_dev; struct device *dev = &pdata->pdev->dev;
- phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0); - if (!phy_np) { - netdev_dbg(ndev, "No phy-handle found\n"); - return -ENODEV; + if (dev->of_node) { + phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0); + if (!phy_np) { + netdev_dbg(ndev, "No phy-handle found in DT\n"); + return -ENODEV; + } + pdata->phy_dev = of_phy_find_device(phy_np); }
- phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link, - 0, pdata->phy_mode); - if (!phy_dev) { + phy_dev = pdata->phy_dev; + + if (phy_dev == NULL || + phy_connect_direct(ndev, phy_dev, &xgene_enet_adjust_link, + pdata->phy_mode)) { netdev_err(ndev, "Could not connect to PHY\n"); return -ENODEV; } @@ -665,11 +672,52 @@ static int xgene_enet_phy_connect(struct net_device *ndev) ~SUPPORTED_100baseT_Half & ~SUPPORTED_1000baseT_Half; phy_dev->advertising = phy_dev->supported; - pdata->phy_dev = phy_dev;
return 0; }
+#ifdef CONFIG_ACPI +static int xgene_acpi_mdiobus_register(struct xgene_enet_pdata *pdata, + struct mii_bus *mdio) +{ + struct device *dev = &pdata->pdev->dev; + struct phy_device *phy; + int i, ret; + u32 phy_id; + + /* Mask out all PHYs from auto probing. */ + mdio->phy_mask = ~0; + + /* Clear all the IRQ properties */ + if (mdio->irq) + for (i = 0; i < PHY_MAX_ADDR; i++) + mdio->irq[i] = PHY_POLL; + + /* Register the MDIO bus */ + ret = mdiobus_register(mdio); + if (ret) + return ret; + + ret = device_property_read_u32(dev, "phy-channel", &phy_id); + if (ret) + return -EINVAL; + + phy = get_phy_device(mdio, phy_id, true); + if (!phy || IS_ERR(phy)) + return -EIO; + + ret = phy_device_register(phy); + if (ret) + phy_device_free(phy); + else + pdata->phy_dev = phy; + + return ret; +} +#else +#define xgene_acpi_mdiobus_register(a, b) -1 +#endif + int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) { struct net_device *ndev = pdata->ndev; @@ -686,7 +734,7 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) } }
- if (!mdio_np) { + if (dev->of_node && !mdio_np) { netdev_dbg(ndev, "No mdio node in the dts\n"); return -ENXIO; } @@ -704,7 +752,10 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) mdio_bus->priv = pdata; mdio_bus->parent = &ndev->dev;
- ret = of_mdiobus_register(mdio_bus, mdio_np); + if (dev->of_node) + ret = of_mdiobus_register(mdio_bus, mdio_np); + else + ret = xgene_acpi_mdiobus_register(pdata, mdio_bus); if (ret) { netdev_err(ndev, "Failed to register MDIO bus\n"); mdiobus_free(mdio_bus); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 3c208cc..6370ff4 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -746,6 +746,42 @@ static const struct net_device_ops xgene_ndev_ops = { .ndo_set_mac_address = xgene_enet_set_mac_address, };
+#ifdef CONFIG_ACPI +static int acpi_get_mac_address(struct device *dev, + unsigned char *addr) +{ + int ret; + + ret = device_property_read_u8_array(dev, "mac-address", addr, 6); + if (ret) + return 0; + + return 6; +} + +static int acpi_get_phy_mode(struct device *dev) +{ + int i, ret, phy_mode; + char *modestr; + + ret = device_property_read_string(dev, "phy-mode", &modestr); + if (ret) + return -1; + + phy_mode = -1; + for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) { + if (!strcasecmp(modestr, phy_modes(i))) { + phy_mode = i; + break; + } + } + return phy_mode; +} +#else +#define acpi_get_mac_address(a, b, c) 0 +#define acpi_get_phy_mode(a) -1 +#endif + static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) { struct platform_device *pdev; @@ -761,6 +797,8 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) ndev = pdata->ndev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "enet_csr"); + if (!res) + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "Resource enet_csr not defined\n"); return -ENODEV; @@ -772,6 +810,8 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) }
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_csr"); + if (!res) + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!res) { dev_err(dev, "Resource ring_csr not defined\n"); return -ENODEV; @@ -783,6 +823,8 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) }
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_cmd"); + if (!res) + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); if (!res) { dev_err(dev, "Resource ring_cmd not defined\n"); return -ENODEV; @@ -804,11 +846,13 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) mac = of_get_mac_address(dev->of_node); if (mac) memcpy(ndev->dev_addr, mac, ndev->addr_len); - else + else if (!acpi_get_mac_address(dev, ndev->dev_addr)) eth_hw_addr_random(ndev); memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
pdata->phy_mode = of_get_phy_mode(pdev->dev.of_node); + if (pdata->phy_mode < 0) + pdata->phy_mode = acpi_get_phy_mode(dev); if (pdata->phy_mode < 0) { dev_err(dev, "Unable to get phy-connection-type\n"); return pdata->phy_mode; @@ -821,11 +865,12 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) }
pdata->clk = devm_clk_get(&pdev->dev, NULL); - ret = IS_ERR(pdata->clk); if (IS_ERR(pdata->clk)) { - dev_err(&pdev->dev, "can't get clock\n"); - ret = PTR_ERR(pdata->clk); - return ret; + /* + * Not necessarily an error. Firmware may have + * set up the clock already. + */ + pdata->clk = NULL; }
base_addr = pdata->base_addr; @@ -873,7 +918,7 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id); pdata->mac_ops->init(pdata);
- return ret; + return 0; }
static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata) @@ -934,7 +979,7 @@ static int xgene_enet_probe(struct platform_device *pdev) goto err; }
- ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); if (ret) { netdev_err(ndev, "No usable DMA configuration\n"); goto err; @@ -981,6 +1026,14 @@ static int xgene_enet_remove(struct platform_device *pdev) return 0; }
+#ifdef CONFIG_ACPI +static const struct acpi_device_id xgene_enet_acpi_match[] = { + { "APMC0D05", }, + { } +}; +MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match); +#endif + static struct of_device_id xgene_enet_match[] = { {.compatible = "apm,xgene-enet",}, {}, @@ -992,6 +1045,7 @@ static struct platform_driver xgene_enet_driver = { .driver = { .name = "xgene-enet", .of_match_table = xgene_enet_match, + .acpi_match_table = ACPI_PTR(xgene_enet_acpi_match), }, .probe = xgene_enet_probe, .remove = xgene_enet_remove, diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 874e5a0..8b7e2cf 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -31,6 +31,7 @@ #include <linux/prefetch.h> #include <linux/if_vlan.h> #include <linux/phy.h> +#include <linux/acpi.h> #include "xgene_enet_hw.h"
#define XGENE_DRV_VERSION "v1.0"