Skip to content

Commit

Permalink
amd-xgbe: Add ACPI support
Browse files Browse the repository at this point in the history
Add support for ACPI to the amd-xgbe and amd-xgbe-phy drivers. This
support converts many of the device tree APIs to the new device_property
APIs.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Lendacky, Thomas authored and David S. Miller committed Jan 17, 2015
1 parent 0d40b61 commit 82a1903
Show file tree
Hide file tree
Showing 8 changed files with 273 additions and 106 deletions.
2 changes: 1 addition & 1 deletion drivers/net/ethernet/amd/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ config SUNLANCE

config AMD_XGBE
tristate "AMD 10GbE Ethernet driver"
depends on OF_NET && HAS_IOMEM
depends on (OF_NET || ACPI) && HAS_IOMEM
select PHYLIB
select AMD_XGBE_PHY
select BITREVERSE
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/ethernet/amd/xgbe/xgbe-dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,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
Expand All @@ -154,7 +154,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
Expand Down
202 changes: 158 additions & 44 deletions drivers/net/ethernet/amd/xgbe/xgbe-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/of_address.h>
#include <linux/clk.h>
#include <linux/property.h>
#include <linux/acpi.h>

#include "xgbe.h"
#include "xgbe-common.h"
Expand Down Expand Up @@ -162,6 +165,96 @@ static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata)
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 */
ret = device_property_read_u32(dev, XGBE_ACPI_DMA_FREQ, &property);
if (ret) {
dev_err(dev, "unable to obtain %s property\n",
XGBE_ACPI_DMA_FREQ);
return ret;
}
pdata->sysclk_rate = property;

/* Obtain the PTP clock setting */
ret = device_property_read_u32(dev, XGBE_ACPI_PTP_FREQ, &property);
if (ret) {
dev_err(dev, "unable to obtain %s property\n",
XGBE_ACPI_PTP_FREQ);
return ret;
}
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 */
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;

/* 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 device cache coherency value */
pdata->coherent = of_dma_is_coherent(dev->of_node);

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;
Expand All @@ -170,7 +263,7 @@ static int xgbe_probe(struct platform_device *pdev)
struct net_device *netdev;
struct device *dev = &pdev->dev;
struct resource *res;
const u8 *mac_addr;
const char *phy_mode;
unsigned int i;
int ret;

Expand All @@ -187,6 +280,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);

Expand All @@ -195,6 +289,9 @@ static int xgbe_probe(struct platform_device *pdev)
mutex_init(&pdata->rss_mutex);
spin_lock_init(&pdata->tstamp_lock);

/* Check if we should use ACPI or DT */
pdata->use_acpi = (!pdata->adev || acpi_disabled) ? 0 : 1;

/* Set and validate the number of descriptors for a ring */
BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT);
pdata->tx_desc_count = XGBE_TX_DESC_CNT;
Expand All @@ -213,22 +310,6 @@ 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);
Expand All @@ -248,16 +329,42 @@ static int xgbe_probe(struct platform_device *pdev)
}
DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs);

/* 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(40));
if (ret) {
dev_err(dev, "dma_set_mask_and_coherent failed\n");
/* Retrieve the MAC address */
ret = device_property_read_u8_array(dev, XGBE_MAC_ADDR_PROPERTY,
pdata->mac_addr,
sizeof(pdata->mac_addr));
if (ret || !is_valid_ether_addr(pdata->mac_addr)) {
dev_err(dev, "invalid %s property\n", XGBE_MAC_ADDR_PROPERTY);
if (!ret)
ret = -EINVAL;
goto err_io;
}

if (of_property_read_bool(dev->of_node, "dma-coherent")) {
/* Retrieve the PHY mode - it must be "xgmii" */
ret = device_property_read_string(dev, XGBE_PHY_MODE_PROPERTY,
&phy_mode);
if (ret || strcmp(phy_mode, phy_modes(PHY_INTERFACE_MODE_XGMII))) {
dev_err(dev, "invalid %s property\n", XGBE_PHY_MODE_PROPERTY);
if (!ret)
ret = -EINVAL;
goto err_io;
}
pdata->phy_mode = PHY_INTERFACE_MODE_XGMII;

/* Check for per channel interrupt support */
if (device_property_present(dev, XGBE_DMA_IRQS_PROPERTY))
pdata->per_channel_irq = 1;

/* Obtain device settings unique to ACPI/OF */
if (pdata->use_acpi)
ret = xgbe_acpi_support(pdata);
else
ret = xgbe_of_support(pdata);
if (ret)
goto err_io;

/* Set the DMA coherency values */
if (pdata->coherent) {
pdata->axdomain = XGBE_DMA_OS_AXDOMAIN;
pdata->arcache = XGBE_DMA_OS_ARCACHE;
pdata->awcache = XGBE_DMA_OS_AWCACHE;
Expand All @@ -267,10 +374,16 @@ static int xgbe_probe(struct platform_device *pdev)
pdata->awcache = XGBE_DMA_SYS_AWCACHE;
}

/* Check for per channel interrupt support */
if (of_property_read_bool(dev->of_node, XGBE_DMA_IRQS))
pdata->per_channel_irq = 1;
/* 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(40));
if (ret) {
dev_err(dev, "dma_set_mask_and_coherent failed\n");
goto err_io;
}

/* Get the device interrupt */
ret = platform_get_irq(pdev, 0);
if (ret < 0) {
dev_err(dev, "platform_get_irq 0 failed\n");
Expand All @@ -280,6 +393,7 @@ static int xgbe_probe(struct platform_device *pdev)

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);
Expand All @@ -292,23 +406,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);

Expand Down Expand Up @@ -492,18 +589,35 @@ static int xgbe_resume(struct device *dev)
}
#endif /* CONFIG_PM */

#ifdef CONFIG_ACPI
static const struct acpi_device_id xgbe_acpi_match[] = {
{ "AMDI8001", 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-v1a", },
{},
};

MODULE_DEVICE_TABLE(of, xgbe_of_match);
#endif

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,
Expand Down
19 changes: 1 addition & 18 deletions drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,25 +205,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) {
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) */
Expand Down Expand Up @@ -252,12 +243,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;
}
if (!phydev->dev.driver) {
Expand Down Expand Up @@ -287,8 +275,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");
Expand All @@ -304,9 +290,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata)
err_mdiobus_alloc:
mdiobus_free(mii);

err_node_get:
of_node_put(phy_node);

return ret;
}

Expand Down
4 changes: 2 additions & 2 deletions drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,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;
Expand All @@ -254,7 +254,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;
Expand Down
Loading

0 comments on commit 82a1903

Please sign in to comment.