From: Tom Lendacky thomas.lendacky@amd.com
This patch provides ACPI support for the AMD 10GbE device driver and AMD 10GbE phy driver.
Signed-off-by: Tom Lendacky thomas.lendacky@amd.com --- drivers/net/ethernet/amd/Kconfig | 2 +- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 4 +- drivers/net/ethernet/amd/xgbe/xgbe-main.c | 288 +++++++++++++++++++++++------- drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 20 +-- drivers/net/ethernet/amd/xgbe/xgbe-ptp.c | 4 +- drivers/net/ethernet/amd/xgbe/xgbe.h | 10 ++ drivers/net/phy/Kconfig | 2 +- drivers/net/phy/amd-xgbe-phy.c | 247 ++++++++++++++++++------- 8 files changed, 422 insertions(+), 155 deletions(-)
diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index 8319c99..6feb6ef3 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -179,7 +179,7 @@ config SUNLANCE
config AMD_XGBE tristate "AMD 10GbE Ethernet driver" - depends on OF_NET + depends on OF_NET || ACPI select PHYLIB select AMD_XGBE_PHY select BITREVERSE diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 1c03abb..a34cad2 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -130,7 +130,7 @@ static unsigned int xgbe_usec_to_riwt(struct xgbe_prv_data *pdata,
DBGPR("-->xgbe_usec_to_riwt\n");
- rate = clk_get_rate(pdata->sysclk); + rate = pdata->sysclk_rate;
/* * Convert the input usec value to the watchdog timer value. Each @@ -153,7 +153,7 @@ static unsigned int xgbe_riwt_to_usec(struct xgbe_prv_data *pdata,
DBGPR("-->xgbe_riwt_to_usec\n");
- rate = clk_get_rate(pdata->sysclk); + rate = pdata->sysclk_rate;
/* * Convert the input watchdog timer value to the usec value. Each diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index 3809d1c..338c0ed 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -124,6 +124,7 @@ #include <linux/of.h> #include <linux/of_net.h> #include <linux/clk.h> +#include <linux/acpi.h>
#include "xgbe.h" #include "xgbe-common.h" @@ -215,6 +216,205 @@ static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata) xgbe_init_function_ptrs_desc(&pdata->desc_if); }
+static int xgbe_map_resources(struct xgbe_prv_data *pdata) +{ + struct platform_device *pdev = pdata->pdev; + struct device *dev = pdata->dev; + struct resource *res; + + /* Obtain the mmio areas for the device */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pdata->xgmac_regs = devm_ioremap_resource(dev, res); + if (IS_ERR(pdata->xgmac_regs)) { + dev_err(dev, "xgmac ioremap failed\n"); + return PTR_ERR(pdata->xgmac_regs); + } + DBGPR(" xgmac_regs = %p\n", pdata->xgmac_regs); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + pdata->xpcs_regs = devm_ioremap_resource(dev, res); + if (IS_ERR(pdata->xpcs_regs)) { + dev_err(dev, "xpcs ioremap failed\n"); + return PTR_ERR(pdata->xpcs_regs); + } + DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs); + + return 0; +} + +#ifdef CONFIG_ACPI +static int xgbe_acpi_support(struct xgbe_prv_data *pdata) +{ + struct acpi_device *adev = pdata->adev; + struct device *dev = pdata->dev; + const union acpi_object *property; + acpi_status status; + u64 cca; + unsigned int i; + int ret; + + /* Map the memory resources */ + ret = xgbe_map_resources(pdata); + if (ret) + return ret; + + /* Obtain the system clock setting */ + ret = acpi_dev_get_property(adev, XGBE_ACPI_DMA_FREQ, ACPI_TYPE_INTEGER, + &property); + if (ret) { + dev_err(dev, "unable to obtain %s acpi property\n", + XGBE_ACPI_DMA_FREQ); + return ret; + } + pdata->sysclk_rate = property->integer.value; + + /* Obtain the PTP clock setting */ + ret = acpi_dev_get_property(adev, XGBE_ACPI_PTP_FREQ, ACPI_TYPE_INTEGER, + &property); + if (ret) { + dev_err(dev, "unable to obtain %s acpi property\n", + XGBE_ACPI_PTP_FREQ); + return ret; + } + pdata->ptpclk_rate = property->integer.value; + + /* Retrieve the MAC address */ + ret = acpi_dev_get_property_array(adev, XGBE_ACPI_MAC_ADDR, + ACPI_TYPE_INTEGER, &property); + if (ret) { + dev_err(dev, "unable to obtain %s acpi property\n", + XGBE_ACPI_MAC_ADDR); + return ret; + } + if (property->package.count != 6) { + dev_err(dev, "invalid %s acpi property\n", + XGBE_ACPI_MAC_ADDR); + return -EINVAL; + } + for (i = 0; i < property->package.count; i++) { + union acpi_object *obj = &property->package.elements[i]; + + pdata->mac_addr[i] = (u8)obj->integer.value; + } + if (!is_valid_ether_addr(pdata->mac_addr)) { + dev_err(dev, "invalid %s acpi property\n", + XGBE_ACPI_MAC_ADDR); + return -EINVAL; + } + + /* Retrieve the PHY mode - it must be "xgmii" */ + ret = acpi_dev_get_property(adev, XGBE_ACPI_PHY_MODE, ACPI_TYPE_STRING, + &property); + if (ret) { + dev_err(dev, "unable to obtain %s acpi property\n", + XGBE_ACPI_PHY_MODE); + return ret; + } + if (strcmp(property->string.pointer, + phy_modes(PHY_INTERFACE_MODE_XGMII))) { + dev_err(dev, "invalid %s acpi property\n", + XGBE_ACPI_PHY_MODE); + return -EINVAL; + } + pdata->phy_mode = PHY_INTERFACE_MODE_XGMII; + +#ifndef METHOD_NAME__CCA +#define METHOD_NAME__CCA "_CCA" +#endif + /* Set the device cache coherency values */ + if (acpi_has_method(adev->handle, METHOD_NAME__CCA)) { + status = acpi_evaluate_integer(adev->handle, METHOD_NAME__CCA, + NULL, &cca); + if (ACPI_FAILURE(status)) { + dev_err(dev, "error obtaining acpi _CCA method\n"); + return -EINVAL; + } + } else { + cca = 0; + } + + if (cca) { + pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; + pdata->arcache = XGBE_DMA_OS_ARCACHE; + pdata->awcache = XGBE_DMA_OS_AWCACHE; + } else { + pdata->axdomain = XGBE_DMA_SYS_AXDOMAIN; + pdata->arcache = XGBE_DMA_SYS_ARCACHE; + pdata->awcache = XGBE_DMA_SYS_AWCACHE; + } + + return 0; +} +#else /* CONFIG_ACPI */ +static int xgbe_acpi_support(struct xgbe_prv_data *pdata) +{ + return -EINVAL; +} +#endif /* CONFIG_ACPI */ + +#ifdef CONFIG_OF +static int xgbe_of_support(struct xgbe_prv_data *pdata) +{ + struct device *dev = pdata->dev; + const u8 *mac_addr; + int ret; + + /* Map the memory resources */ + ret = xgbe_map_resources(pdata); + if (ret) + return ret; + + /* Obtain the system clock setting */ + pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK); + if (IS_ERR(pdata->sysclk)) { + dev_err(dev, "dma devm_clk_get failed\n"); + return PTR_ERR(pdata->sysclk); + } + pdata->sysclk_rate = clk_get_rate(pdata->sysclk); + + /* Obtain the PTP clock setting */ + pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK); + if (IS_ERR(pdata->ptpclk)) { + dev_err(dev, "ptp devm_clk_get failed\n"); + return PTR_ERR(pdata->ptpclk); + } + pdata->ptpclk_rate = clk_get_rate(pdata->ptpclk); + + /* Retrieve the MAC address */ + mac_addr = of_get_mac_address(dev->of_node); + if (!mac_addr) { + dev_err(dev, "invalid mac address for this device\n"); + return -EINVAL; + } + memcpy(pdata->mac_addr, mac_addr, ETH_ALEN); + + /* Retrieve the PHY mode - it must be "xgmii" */ + pdata->phy_mode = of_get_phy_mode(dev->of_node); + if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { + dev_err(dev, "invalid phy-mode specified for this device\n"); + return -EINVAL; + } + + /* Set the device cache coherency values */ + if (of_property_read_bool(dev->of_node, "dma-coherent")) { + pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; + pdata->arcache = XGBE_DMA_OS_ARCACHE; + pdata->awcache = XGBE_DMA_OS_AWCACHE; + } else { + pdata->axdomain = XGBE_DMA_SYS_AXDOMAIN; + pdata->arcache = XGBE_DMA_SYS_ARCACHE; + pdata->awcache = XGBE_DMA_SYS_AWCACHE; + } + + return 0; +} +#else /* CONFIG_OF */ +static int xgbe_of_support(struct xgbe_prv_data *pdata) +{ + return -EINVAL; +} +#endif /*CONFIG_OF */ + static int xgbe_probe(struct platform_device *pdev) { struct xgbe_prv_data *pdata; @@ -222,8 +422,6 @@ static int xgbe_probe(struct platform_device *pdev) struct xgbe_desc_if *desc_if; struct net_device *netdev; struct device *dev = &pdev->dev; - struct resource *res; - const u8 *mac_addr; int ret;
DBGPR("--> xgbe_probe\n"); @@ -239,6 +437,7 @@ static int xgbe_probe(struct platform_device *pdev) pdata = netdev_priv(netdev); pdata->netdev = netdev; pdata->pdev = pdev; + pdata->adev = ACPI_COMPANION(dev); pdata->dev = dev; platform_set_drvdata(pdev, netdev);
@@ -264,40 +463,13 @@ static int xgbe_probe(struct platform_device *pdev) goto err_io; }
- /* Obtain the system clock setting */ - pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK); - if (IS_ERR(pdata->sysclk)) { - dev_err(dev, "dma devm_clk_get failed\n"); - ret = PTR_ERR(pdata->sysclk); - goto err_io; - } - - /* Obtain the PTP clock setting */ - pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK); - if (IS_ERR(pdata->ptpclk)) { - dev_err(dev, "ptp devm_clk_get failed\n"); - ret = PTR_ERR(pdata->ptpclk); - goto err_io; - } - - /* Obtain the mmio areas for the device */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pdata->xgmac_regs = devm_ioremap_resource(dev, res); - if (IS_ERR(pdata->xgmac_regs)) { - dev_err(dev, "xgmac ioremap failed\n"); - ret = PTR_ERR(pdata->xgmac_regs); - goto err_io; - } - DBGPR(" xgmac_regs = %p\n", pdata->xgmac_regs); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - pdata->xpcs_regs = devm_ioremap_resource(dev, res); - if (IS_ERR(pdata->xpcs_regs)) { - dev_err(dev, "xpcs ioremap failed\n"); - ret = PTR_ERR(pdata->xpcs_regs); + /* Obtain device settings */ + if (pdata->adev && !acpi_disabled) + ret = xgbe_acpi_support(pdata); + else + ret = xgbe_of_support(pdata); + if (ret) goto err_io; - } - DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs);
/* Set the DMA mask */ if (!dev->dma_mask) @@ -308,23 +480,16 @@ static int xgbe_probe(struct platform_device *pdev) goto err_io; }
- if (of_property_read_bool(dev->of_node, "dma-coherent")) { - pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; - pdata->arcache = XGBE_DMA_OS_ARCACHE; - pdata->awcache = XGBE_DMA_OS_AWCACHE; - } else { - pdata->axdomain = XGBE_DMA_SYS_AXDOMAIN; - pdata->arcache = XGBE_DMA_SYS_ARCACHE; - pdata->awcache = XGBE_DMA_SYS_AWCACHE; - } - + /* Get the device interrupt */ ret = platform_get_irq(pdev, 0); if (ret < 0) { dev_err(dev, "platform_get_irq failed\n"); goto err_io; } + netdev->irq = ret; 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); @@ -337,23 +502,6 @@ static int xgbe_probe(struct platform_device *pdev) /* Populate the hardware features */ xgbe_get_all_hw_features(pdata);
- /* Retrieve the MAC address */ - mac_addr = of_get_mac_address(dev->of_node); - if (!mac_addr) { - dev_err(dev, "invalid mac address for this device\n"); - ret = -EINVAL; - goto err_io; - } - memcpy(netdev->dev_addr, mac_addr, netdev->addr_len); - - /* Retrieve the PHY mode - it must be "xgmii" */ - pdata->phy_mode = of_get_phy_mode(dev->of_node); - if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { - dev_err(dev, "invalid phy-mode specified for this device\n"); - ret = -EINVAL; - goto err_io; - } - /* Set default configuration data */ xgbe_default_config(pdata);
@@ -531,11 +679,22 @@ static int xgbe_resume(struct device *dev) } #endif /* CONFIG_PM */
+#ifdef CONFIG_ACPI +static const struct acpi_device_id xgbe_acpi_match[] = { + { "AMDI8000", 0 }, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, xgbe_acpi_match); +#endif + +#ifdef CONFIG_OF static const struct of_device_id xgbe_of_match[] = { { .compatible = "amd,xgbe-seattle-v0a", }, { .compatible = "amd,xgbe-seattle-v1a", }, {}, }; +#endif
MODULE_DEVICE_TABLE(of, xgbe_of_match); static SIMPLE_DEV_PM_OPS(xgbe_pm_ops, xgbe_suspend, xgbe_resume); @@ -543,7 +702,12 @@ static SIMPLE_DEV_PM_OPS(xgbe_pm_ops, xgbe_suspend, xgbe_resume); static struct platform_driver xgbe_driver = { .driver = { .name = "amd-xgbe", +#ifdef CONFIG_ACPI + .acpi_match_table = xgbe_acpi_match, +#endif +#ifdef CONFIG_OF .of_match_table = xgbe_of_match, +#endif .pm = &xgbe_pm_ops, }, .probe = xgbe_probe, diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 363b210..5d2c89b 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -119,6 +119,7 @@ #include <linux/mdio.h> #include <linux/phy.h> #include <linux/of.h> +#include <linux/acpi.h>
#include "xgbe.h" #include "xgbe-common.h" @@ -205,25 +206,16 @@ void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
int xgbe_mdio_register(struct xgbe_prv_data *pdata) { - struct device_node *phy_node; struct mii_bus *mii; struct phy_device *phydev; int ret = 0;
DBGPR("-->xgbe_mdio_register\n");
- /* Retrieve the phy-handle */ - phy_node = of_parse_phandle(pdata->dev->of_node, "phy-handle", 0); - if (!phy_node) { - dev_err(pdata->dev, "unable to parse phy-handle\n"); - return -EINVAL; - } - mii = mdiobus_alloc(); if (mii == NULL) { dev_err(pdata->dev, "mdiobus_alloc failed\n"); - ret = -ENOMEM; - goto err_node_get; + return -ENOMEM; }
/* Register on the MDIO bus (don't probe any PHYs) */ @@ -252,12 +244,9 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phydev->c45_ids.device_ids[MDIO_MMD_PCS]));
- of_node_get(phy_node); - phydev->dev.of_node = phy_node; ret = phy_device_register(phydev); if (ret) { dev_err(pdata->dev, "phy_device_register failed\n"); - of_node_put(phy_node); goto err_phy_device; }
@@ -283,8 +272,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata)
pdata->phydev = phydev;
- of_node_put(phy_node); - DBGPHY_REGS(pdata);
DBGPR("<--xgbe_mdio_register\n"); @@ -300,9 +287,6 @@ err_mdiobus_register: err_mdiobus_alloc: mdiobus_free(mii);
-err_node_get: - of_node_put(phy_node); - return ret; }
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c index a1bf9d1c..fa67203 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c @@ -239,7 +239,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) snprintf(info->name, sizeof(info->name), "%s", netdev_name(pdata->netdev)); info->owner = THIS_MODULE; - info->max_adj = clk_get_rate(pdata->ptpclk); + info->max_adj = pdata->ptpclk_rate; info->adjfreq = xgbe_adjfreq; info->adjtime = xgbe_adjtime; info->gettime = xgbe_gettime; @@ -260,7 +260,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) */ dividend = 50000000; dividend <<= 32; - pdata->tstamp_addend = div_u64(dividend, clk_get_rate(pdata->ptpclk)); + pdata->tstamp_addend = div_u64(dividend, pdata->ptpclk_rate);
/* Setup the timecounter */ cc->read = xgbe_cc_read; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 5636db4..59498eb 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -172,6 +172,12 @@ #define XGBE_DMA_CLOCK "dma_clk" #define XGBE_PTP_CLOCK "ptp_clk"
+/* ACPI property names */ +#define XGBE_ACPI_MAC_ADDR "mac-address" +#define XGBE_ACPI_PHY_MODE "phy-mode" +#define XGBE_ACPI_DMA_FREQ "amd,dma-freq" +#define XGBE_ACPI_PTP_FREQ "amd,ptp-freq" + /* Timestamp support - values based on 50MHz PTP clock * 50MHz => 20 nsec */ @@ -572,6 +578,7 @@ struct xgbe_hw_features { struct xgbe_prv_data { struct net_device *netdev; struct platform_device *pdev; + struct acpi_device *adev; struct device *dev;
/* XGMAC/XPCS related mmio registers */ @@ -652,6 +659,7 @@ struct xgbe_prv_data { unsigned int phy_rx_pause;
/* Netdev related settings */ + unsigned char mac_addr[MAX_ADDR_LEN]; netdev_features_t netdev_features; struct napi_struct napi; struct xgbe_mmc_stats mmc_stats; @@ -661,7 +669,9 @@ struct xgbe_prv_data {
/* Device clocks */ struct clk *sysclk; + unsigned long sysclk_rate; struct clk *ptpclk; + unsigned long ptpclk_rate;
/* Timestamp support */ spinlock_t tstamp_lock; diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 75472cf7..bacafe2 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -26,7 +26,7 @@ config AMD_PHY
config AMD_XGBE_PHY tristate "Driver for the AMD 10GbE (amd-xgbe) PHYs" - depends on OF + depends on OF || ACPI ---help--- Currently supports the AMD 10GbE PHY
diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index 90145d9..d852c6e 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -74,6 +74,7 @@ #include <linux/of_platform.h> #include <linux/of_device.h> #include <linux/uaccess.h> +#include <linux/acpi.h>
MODULE_AUTHOR("Tom Lendacky thomas.lendacky@amd.com"); @@ -252,12 +253,13 @@ enum amd_xgbe_phy_mode { };
enum amd_xgbe_phy_speedset { - AMD_XGBE_PHY_SPEEDSET_1000_10000, + AMD_XGBE_PHY_SPEEDSET_1000_10000 = 0, AMD_XGBE_PHY_SPEEDSET_2500_10000, };
struct amd_xgbe_phy_priv { struct platform_device *pdev; + struct acpi_device *adev; struct device *dev;
struct phy_device *phydev; @@ -1238,54 +1240,28 @@ unlock: return ret; }
-static int amd_xgbe_phy_probe(struct phy_device *phydev) +static int amd_xgbe_phy_map_resources(struct amd_xgbe_phy_priv *priv, + struct platform_device *phy_pdev, + unsigned int phy_resnum) { - struct amd_xgbe_phy_priv *priv; - struct platform_device *pdev; - struct device *dev; - char *wq_name; - const __be32 *property; - unsigned int speed_set; + struct device *dev = priv->dev; int ret;
- if (!phydev->dev.of_node) - return -EINVAL; - - pdev = of_find_device_by_node(phydev->dev.of_node); - if (!pdev) - return -EINVAL; - dev = &pdev->dev; - - wq_name = kasprintf(GFP_KERNEL, "%s-amd-xgbe-phy", phydev->bus->name); - if (!wq_name) { - ret = -ENOMEM; - goto err_pdev; - } - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_name; - } - - priv->pdev = pdev; - priv->dev = dev; - priv->phydev = phydev; - /* Get the device mmio areas */ - priv->rxtx_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->rxtx_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, + phy_resnum++); priv->rxtx_regs = devm_ioremap_resource(dev, priv->rxtx_res); if (IS_ERR(priv->rxtx_regs)) { dev_err(dev, "rxtx ioremap failed\n"); - ret = PTR_ERR(priv->rxtx_regs); - goto err_priv; + return PTR_ERR(priv->rxtx_regs); }
/* All xgbe phy devices share the CMU registers so retrieve * the resource and do the ioremap directly rather than * the devm_ioremap_resource call */ - priv->cmu_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + priv->cmu_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, + phy_resnum++); if (!priv->cmu_res) { dev_err(dev, "cmu invalid resource\n"); ret = -EINVAL; @@ -1299,41 +1275,187 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) goto err_rxtx; }
+ return 0; + +err_rxtx: + devm_iounmap(dev, priv->rxtx_regs); + devm_release_mem_region(dev, priv->rxtx_res->start, + resource_size(priv->rxtx_res)); + + return ret; +} + +static void amd_xgbe_phy_unmap_resources(struct amd_xgbe_phy_priv *priv) +{ + struct device *dev = priv->dev; + + devm_iounmap(dev, priv->cmu_regs); + + devm_iounmap(dev, priv->rxtx_regs); + devm_release_mem_region(dev, priv->rxtx_res->start, + resource_size(priv->rxtx_res)); +} + +#ifdef CONFIG_ACPI +static int amd_xgbe_phy_acpi_support(struct amd_xgbe_phy_priv *priv) +{ + struct platform_device *phy_pdev = priv->pdev; + struct acpi_device *adev = priv->adev; + struct device *dev = priv->dev; + const union acpi_object *property; + int ret; + + /* Map the memory resources */ + ret = amd_xgbe_phy_map_resources(priv, phy_pdev, 2); + if (ret) + return ret; + /* Get the device serdes channel property */ - property = of_get_property(dev->of_node, XGBE_PHY_CHANNEL_PROPERTY, - NULL); + ret = acpi_dev_get_property(adev, XGBE_PHY_CHANNEL_PROPERTY, + ACPI_TYPE_INTEGER, &property); + if (ret) { + dev_err(dev, "unable to obtain %s acpi property\n", + XGBE_PHY_CHANNEL_PROPERTY); + goto err_resources; + } + priv->serdes_channel = property->integer.value; + + /* Get the device speed set property */ + ret = acpi_dev_get_property(adev, XGBE_PHY_SPEEDSET_PROPERTY, + ACPI_TYPE_INTEGER, &property); + if (ret) { + dev_err(dev, "unable to obtain %s acpi property\n", + XGBE_PHY_SPEEDSET_PROPERTY); + goto err_resources; + } + priv->speed_set = property->integer.value; + + return 0; + +err_resources: + amd_xgbe_phy_unmap_resources(priv); + + return ret; +} +#else /* CONFIG_ACPI */ +static int amd_xgbe_phy_acpi_support(struct amd_xgbe_phy_priv *priv) +{ + return -EINVAL; +} +#endif /* CONFIG_ACPI */ + +#ifdef CONFIG_OF +static int amd_xgbe_phy_of_support(struct amd_xgbe_phy_priv *priv) +{ + struct platform_device *phy_pdev; + struct device_node *bus_node; + struct device_node *phy_node; + struct device *dev = priv->dev; + const __be32 *property; + int ret; + + bus_node = priv->dev->of_node; + phy_node = of_parse_phandle(bus_node, "phy-handle", 0); + if (!phy_node) { + dev_err(dev, "unable to parse phy-handle\n"); + return -EINVAL; + } + + phy_pdev = of_find_device_by_node(phy_node); + if (!phy_pdev) { + dev_err(dev, "unable to obtain phy device\n"); + ret = -EINVAL; + goto err_put; + } + + /* Map the memory resources */ + ret = amd_xgbe_phy_map_resources(priv, phy_pdev, 0); + if (ret) + goto err_put; + + /* Get the device serdes channel property */ + property = of_get_property(phy_node, XGBE_PHY_CHANNEL_PROPERTY, NULL); if (!property) { - dev_err(dev, "unable to obtain serdes_channel property\n"); + dev_err(dev, "unable to obtain %s property\n", + XGBE_PHY_CHANNEL_PROPERTY); ret = -EINVAL; - goto err_cmu; + goto err_resources; } priv->serdes_channel = be32_to_cpu(*property);
/* Get the device speed set property */ - speed_set = 0; - property = of_get_property(dev->of_node, XGBE_PHY_SPEEDSET_PROPERTY, - NULL); + property = of_get_property(phy_node, XGBE_PHY_SPEEDSET_PROPERTY, NULL); if (property) - speed_set = be32_to_cpu(*property); + priv->speed_set = be32_to_cpu(*property);
- switch (speed_set) { - case 0: - priv->speed_set = AMD_XGBE_PHY_SPEEDSET_1000_10000; - break; - case 1: - priv->speed_set = AMD_XGBE_PHY_SPEEDSET_2500_10000; + of_node_put(phy_node); + + return 0; + +err_resources: + amd_xgbe_phy_unmap_resources(priv); + +err_put: + of_node_put(phy_node); + + return ret; +} +#else /* CONFIG_OF */ +static int amd_xgbe_phy_of_support(struct amd_xgbe_phy_priv *priv) +{ + return -EINVAL; +} +#endif /* CONFIG_OF */ + +static int amd_xgbe_phy_probe(struct phy_device *phydev) +{ + struct amd_xgbe_phy_priv *priv; + struct device *dev; + char *wq_name; + int ret; + + if (!phydev->bus || !phydev->bus->parent) + return -EINVAL; + + dev = phydev->bus->parent; + + wq_name = kasprintf(GFP_KERNEL, "%s-amd-xgbe-phy", phydev->bus->name); + if (!wq_name) + return -ENOMEM; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto err_name; + } + + priv->pdev = to_platform_device(dev); + priv->adev = ACPI_COMPANION(dev); + priv->dev = dev; + priv->phydev = phydev; + + if (priv->adev && !acpi_disabled) + ret = amd_xgbe_phy_acpi_support(priv); + else + ret = amd_xgbe_phy_of_support(priv); + if (ret) + goto err_priv; + + switch (priv->speed_set) { + case AMD_XGBE_PHY_SPEEDSET_1000_10000: + case AMD_XGBE_PHY_SPEEDSET_2500_10000: break; default: dev_err(dev, "invalid amd,speed-set property\n"); ret = -EINVAL; - goto err_cmu; + goto err_resources; }
priv->link = 1;
ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); if (ret < 0) - goto err_cmu; + goto err_resources; if ((ret & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR) priv->mode = AMD_XGBE_MODE_KR; else @@ -1344,23 +1466,17 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) priv->an_workqueue = create_singlethread_workqueue(wq_name); if (!priv->an_workqueue) { ret = -ENOMEM; - goto err_cmu; + goto err_resources; }
phydev->priv = priv;
kfree(wq_name); - of_dev_put(pdev);
return 0;
-err_cmu: - devm_iounmap(dev, priv->cmu_regs); - -err_rxtx: - devm_iounmap(dev, priv->rxtx_regs); - devm_release_mem_region(dev, priv->rxtx_res->start, - resource_size(priv->rxtx_res)); +err_resources: + amd_xgbe_phy_unmap_resources(priv);
err_priv: devm_kfree(dev, priv); @@ -1368,9 +1484,6 @@ err_priv: err_name: kfree(wq_name);
-err_pdev: - of_dev_put(pdev); - return ret; }
@@ -1387,11 +1500,7 @@ static void amd_xgbe_phy_remove(struct phy_device *phydev) flush_workqueue(priv->an_workqueue); destroy_workqueue(priv->an_workqueue);
- devm_iounmap(dev, priv->cmu_regs); - - devm_iounmap(dev, priv->rxtx_regs); - devm_release_mem_region(dev, priv->rxtx_res->start, - resource_size(priv->rxtx_res)); + amd_xgbe_phy_unmap_resources(priv);
devm_kfree(dev, priv); }