Skip to content

Commit

Permalink
Merge branch 'bcmgenet-phy-rework'
Browse files Browse the repository at this point in the history
Florian Fainelli says:

====================
net: bcmgenet: PHY initialization rework

This patch series reworks how we perform PHY initialization and resets in the
GENET driver. Although this contains mostly fixes, some of the changes are a
bit too intrusive to be backported to 'net' at the moment.

Some of the motivations behind these changes were to reduce the time spent in how
performing MDIO transactions, since it is better to perform then when we have
interrupts enabled. This reduces the bring-up time of GENET from ~600 msecs down
to ~8 msecs, and about the same time for suspend/resume.

Since I do not currently have a system which is not DT-aware, can you (Petri,
Jaedon) give this a try and confirm things keep working as expected?
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jul 21, 2015
2 parents 2c1bcaf + 28b4591 commit 0e55a42
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 63 deletions.
33 changes: 17 additions & 16 deletions drivers/net/ethernet/broadcom/genet/bcmgenet.c
Original file line number Diff line number Diff line change
Expand Up @@ -907,9 +907,8 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv,
}

bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);

if (mode == GENET_POWER_PASSIVE)
bcmgenet_mii_reset(priv->dev);
bcmgenet_phy_power_set(priv->dev, true);
}

/* ioctl handle special commands that are not present in ethtool. */
Expand Down Expand Up @@ -1725,7 +1724,7 @@ static int init_umac(struct bcmgenet_priv *priv)
int0_enable |= UMAC_IRQ_TXDMA_DONE;

/* Monitor cable plug/unplugged event for internal PHY */
if (phy_is_internal(priv->phydev)) {
if (priv->internal_phy) {
int0_enable |= UMAC_IRQ_LINK_EVENT;
} else if (priv->ext_phy) {
int0_enable |= UMAC_IRQ_LINK_EVENT;
Expand Down Expand Up @@ -2632,7 +2631,7 @@ static int bcmgenet_open(struct net_device *dev)
/* If this is an internal GPHY, power it back on now, before UniMAC is
* brought out of reset as absolutely no UniMAC activity is allowed
*/
if (phy_is_internal(priv->phydev))
if (priv->internal_phy)
bcmgenet_power_up(priv, GENET_POWER_PASSIVE);

/* take MAC out of reset */
Expand All @@ -2651,7 +2650,7 @@ static int bcmgenet_open(struct net_device *dev)

bcmgenet_set_hw_addr(priv, dev->dev_addr);

if (phy_is_internal(priv->phydev)) {
if (priv->internal_phy) {
reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
reg |= EXT_ENERGY_DET_MASK;
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
Expand Down Expand Up @@ -2687,18 +2686,20 @@ static int bcmgenet_open(struct net_device *dev)
goto err_irq0;
}

/* Re-configure the port multiplexer towards the PHY device */
bcmgenet_mii_config(priv->dev, false);

phy_connect_direct(dev, priv->phydev, bcmgenet_mii_setup,
priv->phy_interface);
ret = bcmgenet_mii_probe(dev);
if (ret) {
netdev_err(dev, "failed to connect to PHY\n");
goto err_irq1;
}

bcmgenet_netif_start(dev);

return 0;

err_irq1:
free_irq(priv->irq1, priv);
err_irq0:
free_irq(priv->irq0, dev);
free_irq(priv->irq0, priv);
err_fini_dma:
bcmgenet_fini_dma(priv);
err_clk_disable:
Expand Down Expand Up @@ -2757,7 +2758,7 @@ static int bcmgenet_close(struct net_device *dev)
free_irq(priv->irq0, priv);
free_irq(priv->irq1, priv);

if (phy_is_internal(priv->phydev))
if (priv->internal_phy)
ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE);

if (!IS_ERR(priv->clk))
Expand Down Expand Up @@ -3319,7 +3320,7 @@ static int bcmgenet_suspend(struct device *d)
if (device_may_wakeup(d) && priv->wolopts) {
ret = bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC);
clk_prepare_enable(priv->clk_wol);
} else if (phy_is_internal(priv->phydev)) {
} else if (priv->internal_phy) {
ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
}

Expand Down Expand Up @@ -3348,7 +3349,7 @@ static int bcmgenet_resume(struct device *d)
/* If this is an internal GPHY, power it back on now, before UniMAC is
* brought out of reset as absolutely no UniMAC activity is allowed
*/
if (phy_is_internal(priv->phydev))
if (priv->internal_phy)
bcmgenet_power_up(priv, GENET_POWER_PASSIVE);

bcmgenet_umac_reset(priv);
Expand All @@ -3363,14 +3364,14 @@ static int bcmgenet_resume(struct device *d)

phy_init_hw(priv->phydev);
/* Speed settings must be restored */
bcmgenet_mii_config(priv->dev, false);
bcmgenet_mii_config(priv->dev);

/* disable ethernet MAC while updating its registers */
umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false);

bcmgenet_set_hw_addr(priv, dev->dev_addr);

if (phy_is_internal(priv->phydev)) {
if (priv->internal_phy) {
reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
reg |= EXT_ENERGY_DET_MASK;
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
Expand Down
5 changes: 3 additions & 2 deletions drivers/net/ethernet/broadcom/genet/bcmgenet.h
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ struct bcmgenet_priv {
/* MDIO bus variables */
wait_queue_head_t wq;
struct phy_device *phydev;
bool internal_phy;
struct device_node *phy_dn;
struct device_node *mdio_dn;
struct mii_bus *mii_bus;
Expand Down Expand Up @@ -670,9 +671,9 @@ GENET_IO_MACRO(rbuf, GENET_RBUF_OFF);

/* MDIO routines */
int bcmgenet_mii_init(struct net_device *dev);
int bcmgenet_mii_config(struct net_device *dev, bool init);
int bcmgenet_mii_config(struct net_device *dev);
int bcmgenet_mii_probe(struct net_device *dev);
void bcmgenet_mii_exit(struct net_device *dev);
void bcmgenet_mii_reset(struct net_device *dev);
void bcmgenet_phy_power_set(struct net_device *dev, bool enable);
void bcmgenet_mii_setup(struct net_device *dev);

Expand Down
84 changes: 39 additions & 45 deletions drivers/net/ethernet/broadcom/genet/bcmmii.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,16 +163,6 @@ void bcmgenet_mii_setup(struct net_device *dev)
phy_print_status(phydev);
}

void bcmgenet_mii_reset(struct net_device *dev)
{
struct bcmgenet_priv *priv = netdev_priv(dev);

if (priv->phydev) {
phy_init_hw(priv->phydev);
phy_start_aneg(priv->phydev);
}
}

void bcmgenet_phy_power_set(struct net_device *dev, bool enable)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
Expand Down Expand Up @@ -215,7 +205,6 @@ static void bcmgenet_internal_phy_setup(struct net_device *dev)
reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
reg |= EXT_PWR_DN_EN_LD;
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
bcmgenet_mii_reset(dev);
}

static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
Expand All @@ -228,7 +217,7 @@ static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL);
}

int bcmgenet_mii_config(struct net_device *dev, bool init)
int bcmgenet_mii_config(struct net_device *dev)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
struct phy_device *phydev = priv->phydev;
Expand All @@ -238,10 +227,10 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
u32 port_ctrl;
u32 reg;

priv->ext_phy = !phy_is_internal(priv->phydev) &&
priv->ext_phy = !priv->internal_phy &&
(priv->phy_interface != PHY_INTERFACE_MODE_MOCA);

if (phy_is_internal(priv->phydev))
if (priv->internal_phy)
priv->phy_interface = PHY_INTERFACE_MODE_NA;

switch (priv->phy_interface) {
Expand All @@ -259,7 +248,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)

bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL);

if (phy_is_internal(priv->phydev)) {
if (priv->internal_phy) {
phy_name = "internal PHY";
bcmgenet_internal_phy_setup(dev);
} else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
Expand Down Expand Up @@ -321,13 +310,12 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
}

if (init)
dev_info(kdev, "configuring instance for %s\n", phy_name);
dev_info_once(kdev, "configuring instance for %s\n", phy_name);

return 0;
}

static int bcmgenet_mii_probe(struct net_device *dev)
int bcmgenet_mii_probe(struct net_device *dev)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
struct device_node *dn = priv->pdev->dev.of_node;
Expand All @@ -345,22 +333,6 @@ static int bcmgenet_mii_probe(struct net_device *dev)
priv->old_pause = -1;

if (dn) {
if (priv->phydev) {
pr_info("PHY already attached\n");
return 0;
}

/* In the case of a fixed PHY, the DT node associated
* to the PHY is the Ethernet MAC DT node.
*/
if (!priv->phy_dn && of_phy_is_fixed_link(dn)) {
ret = of_phy_register_fixed_link(dn);
if (ret)
return ret;

priv->phy_dn = of_node_get(dn);
}

phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup,
phy_flags, priv->phy_interface);
if (!phydev) {
Expand All @@ -386,7 +358,7 @@ static int bcmgenet_mii_probe(struct net_device *dev)
* PHY speed which is needed for bcmgenet_mii_config() to configure
* things appropriately.
*/
ret = bcmgenet_mii_config(dev, true);
ret = bcmgenet_mii_config(dev);
if (ret) {
phy_disconnect(priv->phydev);
return ret;
Expand All @@ -397,14 +369,11 @@ static int bcmgenet_mii_probe(struct net_device *dev)
/* The internal PHY has its link interrupts routed to the
* Ethernet MAC ISRs
*/
if (phy_is_internal(priv->phydev))
if (priv->internal_phy)
priv->mii_bus->irq[phydev->addr] = PHY_IGNORE_INTERRUPT;
else
priv->mii_bus->irq[phydev->addr] = PHY_POLL;

pr_info("attached PHY at address %d [%s]\n",
phydev->addr, phydev->drv->name);

return 0;
}

Expand Down Expand Up @@ -490,7 +459,9 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv)
{
struct device_node *dn = priv->pdev->dev.of_node;
struct device *kdev = &priv->pdev->dev;
const char *phy_mode_str = NULL;
char *compat;
int phy_mode;
int ret;

compat = kasprintf(GFP_KERNEL, "brcm,genet-mdio-v%d", priv->version);
Expand All @@ -513,8 +484,36 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv)
/* Fetch the PHY phandle */
priv->phy_dn = of_parse_phandle(dn, "phy-handle", 0);

/* In the case of a fixed PHY, the DT node associated
* to the PHY is the Ethernet MAC DT node.
*/
if (!priv->phy_dn && of_phy_is_fixed_link(dn)) {
ret = of_phy_register_fixed_link(dn);
if (ret)
return ret;

priv->phy_dn = of_node_get(dn);
}

/* Get the link mode */
priv->phy_interface = of_get_phy_mode(dn);
phy_mode = of_get_phy_mode(dn);
priv->phy_interface = phy_mode;

/* We need to specifically look up whether this PHY interface is internal
* or not *before* we even try to probe the PHY driver over MDIO as we
* may have shut down the internal PHY for power saving purposes.
*/
if (phy_mode < 0) {
ret = of_property_read_string(dn, "phy-mode", &phy_mode_str);
if (ret < 0) {
dev_err(kdev, "invalid PHY mode property\n");
return ret;
}

priv->phy_interface = PHY_INTERFACE_MODE_NA;
if (!strcasecmp(phy_mode_str, "internal"))
priv->internal_phy = true;
}

return 0;
}
Expand Down Expand Up @@ -614,10 +613,6 @@ int bcmgenet_mii_init(struct net_device *dev)
return ret;

ret = bcmgenet_mii_bus_init(priv);
if (ret)
goto out_free;

ret = bcmgenet_mii_probe(dev);
if (ret)
goto out;

Expand All @@ -626,7 +621,6 @@ int bcmgenet_mii_init(struct net_device *dev)
out:
of_node_put(priv->phy_dn);
mdiobus_unregister(priv->mii_bus);
out_free:
kfree(priv->mii_bus->irq);
mdiobus_free(priv->mii_bus);
return ret;
Expand Down

0 comments on commit 0e55a42

Please sign in to comment.