diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index e2aa09ce6af7702d6d8a9063e9841f3c4f50c830..0452937227ff188a78a7cee3582cf2a68a296f9a 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -682,70 +682,6 @@ static int bgmac_phy_write(struct bgmac *bgmac, u8 phyaddr, u8 reg, u16 value) return 0; } -/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyforce */ -static void bgmac_phy_force(struct bgmac *bgmac) -{ - u16 ctl; - u16 mask = ~(BGMAC_PHY_CTL_SPEED | BGMAC_PHY_CTL_SPEED_MSB | - BGMAC_PHY_CTL_ANENAB | BGMAC_PHY_CTL_DUPLEX); - - if (bgmac->phyaddr == BGMAC_PHY_NOREGS) - return; - - if (bgmac->autoneg) - return; - - ctl = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL); - ctl &= mask; - if (bgmac->full_duplex) - ctl |= BGMAC_PHY_CTL_DUPLEX; - if (bgmac->speed == BGMAC_SPEED_100) - ctl |= BGMAC_PHY_CTL_SPEED_100; - else if (bgmac->speed == BGMAC_SPEED_1000) - ctl |= BGMAC_PHY_CTL_SPEED_1000; - bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL, ctl); -} - -/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyadvertise */ -static void bgmac_phy_advertise(struct bgmac *bgmac) -{ - u16 adv; - - if (bgmac->phyaddr == BGMAC_PHY_NOREGS) - return; - - if (!bgmac->autoneg) - return; - - /* Adv selected 10/100 speeds */ - adv = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV); - adv &= ~(BGMAC_PHY_ADV_10HALF | BGMAC_PHY_ADV_10FULL | - BGMAC_PHY_ADV_100HALF | BGMAC_PHY_ADV_100FULL); - if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_10) - adv |= BGMAC_PHY_ADV_10HALF; - if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_100) - adv |= BGMAC_PHY_ADV_100HALF; - if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_10) - adv |= BGMAC_PHY_ADV_10FULL; - if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_100) - adv |= BGMAC_PHY_ADV_100FULL; - bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV, adv); - - /* Adv selected 1000 speeds */ - adv = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV2); - adv &= ~(BGMAC_PHY_ADV2_1000HALF | BGMAC_PHY_ADV2_1000FULL); - if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_1000) - adv |= BGMAC_PHY_ADV2_1000HALF; - if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_1000) - adv |= BGMAC_PHY_ADV2_1000FULL; - bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV2, adv); - - /* Restart */ - bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL, - bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL) | - BGMAC_PHY_CTL_RESTART); -} - /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */ static void bgmac_phy_init(struct bgmac *bgmac) { @@ -876,19 +812,28 @@ static void bgmac_clear_mib(struct bgmac *bgmac) } /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_speed */ -static void bgmac_speed(struct bgmac *bgmac, int speed) +static void bgmac_mac_speed(struct bgmac *bgmac) { u32 mask = ~(BGMAC_CMDCFG_ES_MASK | BGMAC_CMDCFG_HD); u32 set = 0; - if (speed & BGMAC_SPEED_10) + switch (bgmac->mac_speed) { + case SPEED_10: set |= BGMAC_CMDCFG_ES_10; - if (speed & BGMAC_SPEED_100) + break; + case SPEED_100: set |= BGMAC_CMDCFG_ES_100; - if (speed & BGMAC_SPEED_1000) + break; + case SPEED_1000: set |= BGMAC_CMDCFG_ES_1000; - if (!bgmac->full_duplex) + break; + default: + bgmac_err(bgmac, "Unsupported speed: %d\n", bgmac->mac_speed); + } + + if (bgmac->mac_duplex == DUPLEX_HALF) set |= BGMAC_CMDCFG_HD; + bgmac_cmdcfg_maskset(bgmac, mask, set, true); } @@ -897,10 +842,9 @@ static void bgmac_miiconfig(struct bgmac *bgmac) u8 imode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >> BGMAC_DS_MM_SHIFT; if (imode == 0 || imode == 1) { - if (bgmac->autoneg) - bgmac_speed(bgmac, BGMAC_SPEED_100); - else - bgmac_speed(bgmac, bgmac->speed); + bgmac->mac_speed = SPEED_100; + bgmac->mac_duplex = DUPLEX_FULL; + bgmac_mac_speed(bgmac); } } @@ -1108,13 +1052,6 @@ static void bgmac_chip_init(struct bgmac *bgmac, bool full_init) bgmac_write(bgmac, BGMAC_RXMAX_LENGTH, 32 + ETHER_MAX_LEN); - if (!bgmac->autoneg) { - bgmac_speed(bgmac, bgmac->speed); - bgmac_phy_force(bgmac); - } else if (bgmac->speed) { /* if there is anything to adv */ - bgmac_phy_advertise(bgmac); - } - if (full_init) { bgmac_dma_init(bgmac); if (1) /* FIXME: is there any case we don't want IRQs? */ @@ -1294,61 +1231,16 @@ static int bgmac_get_settings(struct net_device *net_dev, { struct bgmac *bgmac = netdev_priv(net_dev); - cmd->supported = SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full | - SUPPORTED_Autoneg; - - if (bgmac->autoneg) { - WARN_ON(cmd->advertising); - if (bgmac->full_duplex) { - if (bgmac->speed & BGMAC_SPEED_10) - cmd->advertising |= ADVERTISED_10baseT_Full; - if (bgmac->speed & BGMAC_SPEED_100) - cmd->advertising |= ADVERTISED_100baseT_Full; - if (bgmac->speed & BGMAC_SPEED_1000) - cmd->advertising |= ADVERTISED_1000baseT_Full; - } else { - if (bgmac->speed & BGMAC_SPEED_10) - cmd->advertising |= ADVERTISED_10baseT_Half; - if (bgmac->speed & BGMAC_SPEED_100) - cmd->advertising |= ADVERTISED_100baseT_Half; - if (bgmac->speed & BGMAC_SPEED_1000) - cmd->advertising |= ADVERTISED_1000baseT_Half; - } - } else { - switch (bgmac->speed) { - case BGMAC_SPEED_10: - ethtool_cmd_speed_set(cmd, SPEED_10); - break; - case BGMAC_SPEED_100: - ethtool_cmd_speed_set(cmd, SPEED_100); - break; - case BGMAC_SPEED_1000: - ethtool_cmd_speed_set(cmd, SPEED_1000); - break; - } - } - - cmd->duplex = bgmac->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; - - cmd->autoneg = bgmac->autoneg; - - return 0; + return phy_ethtool_gset(bgmac->phy_dev, cmd); } -#if 0 static int bgmac_set_settings(struct net_device *net_dev, struct ethtool_cmd *cmd) { struct bgmac *bgmac = netdev_priv(net_dev); - return -1; + return phy_ethtool_sset(bgmac->phy_dev, cmd); } -#endif static void bgmac_get_drvinfo(struct net_device *net_dev, struct ethtool_drvinfo *info) @@ -1359,6 +1251,7 @@ static void bgmac_get_drvinfo(struct net_device *net_dev, static const struct ethtool_ops bgmac_ethtool_ops = { .get_settings = bgmac_get_settings, + .set_settings = bgmac_set_settings, .get_drvinfo = bgmac_get_drvinfo, }; @@ -1377,9 +1270,35 @@ static int bgmac_mii_write(struct mii_bus *bus, int mii_id, int regnum, return bgmac_phy_write(bus->priv, mii_id, regnum, value); } +static void bgmac_adjust_link(struct net_device *net_dev) +{ + struct bgmac *bgmac = netdev_priv(net_dev); + struct phy_device *phy_dev = bgmac->phy_dev; + bool update = false; + + if (phy_dev->link) { + if (phy_dev->speed != bgmac->mac_speed) { + bgmac->mac_speed = phy_dev->speed; + update = true; + } + + if (phy_dev->duplex != bgmac->mac_duplex) { + bgmac->mac_duplex = phy_dev->duplex; + update = true; + } + } + + if (update) { + bgmac_mac_speed(bgmac); + phy_print_status(phy_dev); + } +} + static int bgmac_mii_register(struct bgmac *bgmac) { struct mii_bus *mii_bus; + struct phy_device *phy_dev; + char bus_id[MII_BUS_ID_SIZE + 3]; int i, err = 0; mii_bus = mdiobus_alloc(); @@ -1411,8 +1330,22 @@ static int bgmac_mii_register(struct bgmac *bgmac) bgmac->mii_bus = mii_bus; + /* Connect to the PHY */ + snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, mii_bus->id, + bgmac->phyaddr); + phy_dev = phy_connect(bgmac->net_dev, bus_id, &bgmac_adjust_link, + PHY_INTERFACE_MODE_MII); + if (IS_ERR(phy_dev)) { + bgmac_err(bgmac, "PHY connecton failed\n"); + err = PTR_ERR(phy_dev); + goto err_unregister_bus; + } + bgmac->phy_dev = phy_dev; + return err; +err_unregister_bus: + mdiobus_unregister(mii_bus); err_free_irq: kfree(mii_bus->irq); err_free_bus: @@ -1467,9 +1400,6 @@ static int bgmac_probe(struct bcma_device *core) bcma_set_drvdata(core, bgmac); /* Defaults */ - bgmac->autoneg = true; - bgmac->full_duplex = true; - bgmac->speed = BGMAC_SPEED_10 | BGMAC_SPEED_100 | BGMAC_SPEED_1000; memcpy(bgmac->net_dev->dev_addr, mac, ETH_ALEN); /* On BCM4706 we need common core to access PHY */ diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h index 66c8afbdc8c7fd863337da4795df8df9443ae120..550f2a8e85a9758920c8cf2aef7aa8a660f4036f 100644 --- a/drivers/net/ethernet/broadcom/bgmac.h +++ b/drivers/net/ethernet/broadcom/bgmac.h @@ -342,10 +342,6 @@ #define BGMAC_CHIPCTL_1_SW_TYPE_RGMII 0x000000C0 #define BGMAC_CHIPCTL_1_RXC_DLL_BYPASS 0x00010000 -#define BGMAC_SPEED_10 0x0001 -#define BGMAC_SPEED_100 0x0002 -#define BGMAC_SPEED_1000 0x0004 - #define BGMAC_WEIGHT 64 #define ETHER_MAX_LEN 1518 @@ -402,6 +398,7 @@ struct bgmac { struct net_device *net_dev; struct napi_struct napi; struct mii_bus *mii_bus; + struct phy_device *phy_dev; /* DMA */ struct bgmac_dma_ring tx_ring[BGMAC_MAX_TX_RINGS]; @@ -416,10 +413,9 @@ struct bgmac { u32 int_mask; u32 int_status; - /* Speed-related */ - int speed; - bool autoneg; - bool full_duplex; + /* Current MAC state */ + int mac_speed; + int mac_duplex; u8 phyaddr; bool has_robosw;