diff options
47 files changed, 1300 insertions, 638 deletions
diff --git a/Documentation/devicetree/bindings/net/davinci-mdio.txt b/Documentation/devicetree/bindings/net/davinci-mdio.txt index 0369e25aabd2..621156ca4ffd 100644 --- a/Documentation/devicetree/bindings/net/davinci-mdio.txt +++ b/Documentation/devicetree/bindings/net/davinci-mdio.txt @@ -2,7 +2,10 @@ TI SoC Davinci/Keystone2 MDIO Controller Device Tree Bindings --------------------------------------------------- Required properties: -- compatible : Should be "ti,davinci_mdio" or "ti,keystone_mdio" +- compatible : Should be "ti,davinci_mdio" + and "ti,keystone_mdio" for Keystone 2 SoCs + and "ti,cpsw-mdio" for am335x, am472x, am57xx/dra7, dm814x SoCs + and "ti,am4372-mdio" for am472x SoC - reg : physical base address and size of the davinci mdio registers map - bus_freq : Mdio Bus frequency diff --git a/Documentation/devicetree/bindings/net/stmmac.txt b/Documentation/devicetree/bindings/net/stmmac.txt index 95816c5fc589..41b49e6075f5 100644 --- a/Documentation/devicetree/bindings/net/stmmac.txt +++ b/Documentation/devicetree/bindings/net/stmmac.txt @@ -47,6 +47,9 @@ Optional properties: supported by this device instance - snps,perfect-filter-entries: Number of perfect filter entries supported by this device instance +- snps,ps-speed: port selection speed that can be passed to the core when + PCS is supported. For example, this is used in case of SGMII + and MAC2MAC connection. - AXI BUS Mode parameters: below the list of all the parameters to program the AXI register inside the DMA module: - snps,lpi_en: enable Low Power Interface diff --git a/Documentation/networking/stmmac.txt b/Documentation/networking/stmmac.txt index 671fe3dd56d3..e226f8925c9e 100644 --- a/Documentation/networking/stmmac.txt +++ b/Documentation/networking/stmmac.txt @@ -285,6 +285,7 @@ Please see the following document: o mmc_core.c/mmc.h: Management MAC Counters; o stmmac_hwtstamp.c: HW timestamp support for PTP; o stmmac_ptp.c: PTP 1588 clock; + o stmmac_pcs.h: Physical Coding Sublayer common implementation; o dwmac-<XXX>.c: these are for the platform glue-logic file; e.g. dwmac-sti.c for STMicroelectronics SoCs. diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index 702126ff4a56..7fa295155543 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -788,7 +788,7 @@ status = "disabled"; davinci_mdio: mdio@4a101000 { - compatible = "ti,davinci_mdio"; + compatible = "ti,cpsw-mdio","ti,davinci_mdio"; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "davinci_mdio"; diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index a10fa7f95442..cd81ecf12731 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -635,7 +635,7 @@ syscon = <&scm_conf>; davinci_mdio: mdio@4a101000 { - compatible = "ti,am4372-mdio","ti,davinci_mdio"; + compatible = "ti,am4372-mdio","ti,cpsw-mdio","ti,davinci_mdio"; reg = <0x4a101000 0x100>; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index b7ddc645dd52..f8b39a5a487a 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1660,7 +1660,7 @@ status = "disabled"; davinci_mdio: mdio@48485000 { - compatible = "ti,davinci_mdio"; + compatible = "ti,cpsw-mdio","ti,davinci_mdio"; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "davinci_mdio"; diff --git a/drivers/net/dsa/b53/b53_mmap.c b/drivers/net/dsa/b53/b53_mmap.c index b70daf9174d4..21f1068b0804 100644 --- a/drivers/net/dsa/b53/b53_mmap.c +++ b/drivers/net/dsa/b53/b53_mmap.c @@ -70,6 +70,8 @@ static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) { + u8 __iomem *regs = dev->priv; + if (WARN_ON(reg % 2)) return -EINVAL; @@ -77,16 +79,26 @@ static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) u16 lo; u32 hi; - b53_mmap_read16(dev, page, reg, &lo); - b53_mmap_read32(dev, page, reg + 2, &hi); + if (dev->pdata && dev->pdata->big_endian) { + lo = ioread16be(regs + (page << 8) + reg); + hi = ioread32be(regs + (page << 8) + reg + 2); + } else { + lo = readw(regs + (page << 8) + reg); + hi = readl(regs + (page << 8) + reg + 2); + } *val = ((u64)hi << 16) | lo; } else { u32 lo; u16 hi; - b53_mmap_read32(dev, page, reg, &lo); - b53_mmap_read16(dev, page, reg + 4, &hi); + if (dev->pdata && dev->pdata->big_endian) { + lo = ioread32be(regs + (page << 8) + reg); + hi = ioread16be(regs + (page << 8) + reg + 4); + } else { + lo = readl(regs + (page << 8) + reg); + hi = readw(regs + (page << 8) + reg + 4); + } *val = ((u64)hi << 32) | lo; } @@ -96,13 +108,19 @@ static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) { + u8 __iomem *regs = dev->priv; u32 hi, lo; if (WARN_ON(reg % 4)) return -EINVAL; - b53_mmap_read32(dev, page, reg, &lo); - b53_mmap_read32(dev, page, reg + 4, &hi); + if (dev->pdata && dev->pdata->big_endian) { + lo = ioread32be(regs + (page << 8) + reg); + hi = ioread32be(regs + (page << 8) + reg + 4); + } else { + lo = readl(regs + (page << 8) + reg); + hi = readl(regs + (page << 8) + reg + 4); + } *val = ((u64)hi << 32) | lo; diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c index b69a9eacc531..c3b64cdd0dec 100644 --- a/drivers/net/ethernet/dnet.c +++ b/drivers/net/ethernet/dnet.c @@ -173,7 +173,7 @@ static int dnet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, static void dnet_handle_link_change(struct net_device *dev) { struct dnet *bp = netdev_priv(dev); - struct phy_device *phydev = bp->phy_dev; + struct phy_device *phydev = dev->phydev; unsigned long flags; u32 mode_reg, ctl_reg; @@ -295,7 +295,6 @@ static int dnet_mii_probe(struct net_device *dev) bp->link = 0; bp->speed = 0; bp->duplex = -1; - bp->phy_dev = phydev; return 0; } @@ -629,16 +628,16 @@ static int dnet_open(struct net_device *dev) struct dnet *bp = netdev_priv(dev); /* if the phy is not yet register, retry later */ - if (!bp->phy_dev) + if (!dev->phydev) return -EAGAIN; napi_enable(&bp->napi); dnet_init_hw(bp); - phy_start_aneg(bp->phy_dev); + phy_start_aneg(dev->phydev); /* schedule a link state check */ - phy_start(bp->phy_dev); + phy_start(dev->phydev); netif_start_queue(dev); @@ -652,8 +651,8 @@ static int dnet_close(struct net_device *dev) netif_stop_queue(dev); napi_disable(&bp->napi); - if (bp->phy_dev) - phy_stop(bp->phy_dev); + if (dev->phydev) + phy_stop(dev->phydev); dnet_reset_hw(bp); netif_carrier_off(dev); @@ -731,32 +730,9 @@ static struct net_device_stats *dnet_get_stats(struct net_device *dev) return nstat; } -static int dnet_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct dnet *bp = netdev_priv(dev); - struct phy_device *phydev = bp->phy_dev; - - if (!phydev) - return -ENODEV; - - return phy_ethtool_gset(phydev, cmd); -} - -static int dnet_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct dnet *bp = netdev_priv(dev); - struct phy_device *phydev = bp->phy_dev; - - if (!phydev) - return -ENODEV; - - return phy_ethtool_sset(phydev, cmd); -} - static int dnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct dnet *bp = netdev_priv(dev); - struct phy_device *phydev = bp->phy_dev; + struct phy_device *phydev = dev->phydev; if (!netif_running(dev)) return -EINVAL; @@ -776,11 +752,11 @@ static void dnet_get_drvinfo(struct net_device *dev, } static const struct ethtool_ops dnet_ethtool_ops = { - .get_settings = dnet_get_settings, - .set_settings = dnet_set_settings, .get_drvinfo = dnet_get_drvinfo, .get_link = ethtool_op_get_link, .get_ts_info = ethtool_op_get_ts_info, + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, }; static const struct net_device_ops dnet_netdev_ops = { @@ -875,7 +851,7 @@ static int dnet_probe(struct platform_device *pdev) (bp->capabilities & DNET_HAS_IRQ) ? "" : "no ", (bp->capabilities & DNET_HAS_GIGABIT) ? "" : "no ", (bp->capabilities & DNET_HAS_DMA) ? "" : "no "); - phydev = bp->phy_dev; + phydev = dev->phydev; phy_attached_info(phydev); return 0; @@ -899,8 +875,8 @@ static int dnet_remove(struct platform_device *pdev) if (dev) { bp = netdev_priv(dev); - if (bp->phy_dev) - phy_disconnect(bp->phy_dev); + if (dev->phydev) + phy_disconnect(dev->phydev); mdiobus_unregister(bp->mii_bus); mdiobus_free(bp->mii_bus); unregister_netdev(dev); diff --git a/drivers/net/ethernet/dnet.h b/drivers/net/ethernet/dnet.h index 37f5b30fa78b..d985080bbd5d 100644 --- a/drivers/net/ethernet/dnet.h +++ b/drivers/net/ethernet/dnet.h @@ -216,7 +216,6 @@ struct dnet { /* PHY stuff */ struct mii_bus *mii_bus; - struct phy_device *phy_dev; unsigned int link; unsigned int speed; unsigned int duplex; diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c index b9f2ea59308a..275618bb4646 100644 --- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c +++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c @@ -218,7 +218,6 @@ struct hix5hd2_priv { struct device *dev; struct net_device *netdev; - struct phy_device *phy; struct device_node *phy_node; phy_interface_t phy_mode; @@ -402,7 +401,7 @@ static int hix5hd2_net_set_mac_address(struct net_device *dev, void *p) static void hix5hd2_adjust_link(struct net_device *dev) { struct hix5hd2_priv *priv = netdev_priv(dev); - struct phy_device *phy = priv->phy; + struct phy_device *phy = dev->phydev; if ((priv->speed != phy->speed) || (priv->duplex != phy->duplex)) { hix5hd2_config_port(dev, phy->speed, phy->duplex); @@ -679,6 +678,7 @@ static void hix5hd2_free_dma_desc_rings(struct hix5hd2_priv *priv) static int hix5hd2_net_open(struct net_device *dev) { struct hix5hd2_priv *priv = netdev_priv(dev); + struct phy_device *phy; int ret; ret = clk_prepare_enable(priv->clk); @@ -687,12 +687,12 @@ static int hix5hd2_net_open(struct net_device *dev) return ret; } - priv->phy = of_phy_connect(dev, priv->phy_node, - &hix5hd2_adjust_link, 0, priv->phy_mode); - if (!priv->phy) + phy = of_phy_connect(dev, priv->phy_node, + &hix5hd2_adjust_link, 0, priv->phy_mode); + if (!phy) return -ENODEV; - phy_start(priv->phy); + phy_start(phy); hix5hd2_hw_init(priv); hix5hd2_rx_refill(priv); @@ -716,9 +716,9 @@ static int hix5hd2_net_close(struct net_device *dev) netif_stop_queue(dev); hix5hd2_free_dma_desc_rings(priv); - if (priv->phy) { - phy_stop(priv->phy); - phy_disconnect(priv->phy); + if (dev->phydev) { + phy_stop(dev->phydev); + phy_disconnect(dev->phydev); } clk_disable_unprepare(priv->clk); @@ -750,32 +750,10 @@ static const struct net_device_ops hix5hd2_netdev_ops = { .ndo_set_mac_address = hix5hd2_net_set_mac_address, }; -static int hix5hd2_get_settings(struct net_device *net_dev, - struct ethtool_cmd *cmd) -{ - struct hix5hd2_priv *priv = netdev_priv(net_dev); - - if (!priv->phy) - return -ENODEV; - - return phy_ethtool_gset(priv->phy, cmd); -} - -static int hix5hd2_set_settings(struct net_device *net_dev, - struct ethtool_cmd *cmd) -{ - struct hix5hd2_priv *priv = netdev_priv(net_dev); - - if (!priv->phy) - return -ENODEV; - - return phy_ethtool_sset(priv->phy, cmd); -} - static struct ethtool_ops hix5hd2_ethtools_ops = { .get_link = ethtool_op_get_link, - .get_settings = hix5hd2_get_settings, - .set_settings = hix5hd2_set_settings, + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, }; static int hix5hd2_mdio_wait_ready(struct mii_bus *bus) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 868a957f24bb..0b047178cda1 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -699,7 +699,6 @@ struct mvpp2_port { u16 rx_ring_size; struct mvpp2_pcpu_stats __percpu *stats; - struct phy_device *phy_dev; phy_interface_t phy_interface; struct device_node *phy_node; unsigned int link; @@ -4850,7 +4849,7 @@ static irqreturn_t mvpp2_isr(int irq, void *dev_id) static void mvpp2_link_event(struct net_device *dev) { struct mvpp2_port *port = netdev_priv(dev); - struct phy_device *phydev = port->phy_dev; + struct phy_device *phydev = dev->phydev; int status_change = 0; u32 val; @@ -5416,6 +5415,8 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) /* Set hw internals when starting port */ static void mvpp2_start_dev(struct mvpp2_port *port) { + struct net_device *ndev = port->dev; + mvpp2_gmac_max_rx_size_set(port); mvpp2_txp_max_tx_size_set(port); @@ -5425,13 +5426,15 @@ static void mvpp2_start_dev(struct mvpp2_port *port) mvpp2_interrupts_enable(port); mvpp2_port_enable(port); - phy_start(port->phy_dev); + phy_start(ndev->phydev); netif_tx_start_all_queues(port->dev); } /* Set hw internals when stopping port */ static void mvpp2_stop_dev(struct mvpp2_port *port) { + struct net_device *ndev = port->dev; + /* Stop new packets from arriving to RXQs */ mvpp2_ingress_disable(port); @@ -5447,7 +5450,7 @@ static void mvpp2_stop_dev(struct mvpp2_port *port) mvpp2_egress_disable(port); mvpp2_port_disable(port); - phy_stop(port->phy_dev); + phy_stop(ndev->phydev); } /* Return positive if MTU is valid */ @@ -5535,7 +5538,6 @@ static int mvpp2_phy_connect(struct mvpp2_port *port) phy_dev->supported &= PHY_GBIT_FEATURES; phy_dev->advertising = phy_dev->supported; - port->phy_dev = phy_dev; port->link = 0; port->duplex = 0; port->speed = 0; @@ -5545,8 +5547,9 @@ static int mvpp2_phy_connect(struct mvpp2_port *port) static void mvpp2_phy_disconnect(struct mvpp2_port *port) { - phy_disconnect(port->phy_dev); - port->phy_dev = NULL; + struct net_device *ndev = port->dev; + + phy_disconnect(ndev->phydev); } static int mvpp2_open(struct net_device *dev) @@ -5796,13 +5799,12 @@ mvpp2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) static int mvpp2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct mvpp2_port *port = netdev_priv(dev); int ret; - if (!port->phy_dev) + if (!dev->phydev) return -ENOTSUPP; - ret = phy_mii_ioctl(port->phy_dev, ifr, cmd); + ret = phy_mii_ioctl(dev->phydev, ifr, cmd); if (!ret) mvpp2_link_event(dev); @@ -5811,28 +5813,6 @@ static int mvpp2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* Ethtool methods */ -/* Get settings (phy address, speed) for ethtools */ -static int mvpp2_ethtool_get_settings(struct net_device *dev, - struct ethtool_cmd *cmd) -{ - struct mvpp2_port *port = netdev_priv(dev); - - if (!port->phy_dev) - return -ENODEV; - return phy_ethtool_gset(port->phy_dev, cmd); -} - -/* Set settings (phy address, speed) for ethtools */ -static int mvpp2_ethtool_set_settings(struct net_device *dev, - struct ethtool_cmd *cmd) -{ - struct mvpp2_port *port = netdev_priv(dev); - - if (!port->phy_dev) - return -ENODEV; - return phy_ethtool_sset(port->phy_dev, cmd); -} - /* Set interrupt coalescing for ethtools */ static int mvpp2_ethtool_set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) @@ -5967,13 +5947,13 @@ static const struct net_device_ops mvpp2_netdev_ops = { static const struct ethtool_ops mvpp2_eth_tool_ops = { .get_link = ethtool_op_get_link, - .get_settings = mvpp2_ethtool_get_settings, - .set_settings = mvpp2_ethtool_set_settings, .set_coalesce = mvpp2_ethtool_set_coalesce, .get_coalesce = mvpp2_ethtool_get_coalesce, .get_drvinfo = mvpp2_ethtool_get_drvinfo, .get_ringparam = mvpp2_ethtool_get_ringparam, .set_ringparam = mvpp2_ethtool_set_ringparam, + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, }; /* Driver initialization */ diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index b1ce7aaa8f8b..01b50ff7c708 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -425,7 +425,6 @@ struct netdata_local { unsigned int last_tx_idx; unsigned int num_used_tx_buffs; struct mii_bus *mii_bus; - struct phy_device *phy_dev; struct clk *clk; dma_addr_t dma_buff_base_p; void *dma_buff_base_v; @@ -750,7 +749,7 @@ static int lpc_mdio_reset(struct mii_bus *bus) static void lpc_handle_link_change(struct net_device *ndev) { struct netdata_local *pldat = netdev_priv(ndev); - struct phy_device *phydev = pldat->phy_dev; + struct phy_device *phydev = ndev->phydev; unsigned long flags; bool status_change = false; @@ -814,7 +813,6 @@ static int lpc_mii_probe(struct net_device *ndev) pldat->link = 0; pldat->speed = 0; pldat->duplex = -1; - pldat->phy_dev = phydev; phy_attached_info(phydev); @@ -1048,8 +1046,8 @@ static int lpc_eth_close(struct net_device *ndev) napi_disable(&pldat->napi); netif_stop_queue(ndev); - if (pldat->phy_dev) - phy_stop(pldat->phy_dev); + if (ndev->phydev) + phy_stop(ndev->phydev); spin_lock_irqsave(&pldat->lock, flags); __lpc_eth_reset(pldat); @@ -1186,7 +1184,7 @@ static void lpc_eth_set_multicast_list(struct net_device *ndev) static int lpc_eth_ioctl(struct net_device *ndev, struct ifreq *req, int cmd) { struct netdata_local *pldat = netdev_priv(ndev); - struct phy_device *phydev = pldat->phy_dev; + struct phy_device *phydev = ndev->phydev; if (!netif_running(ndev)) return -EINVAL; @@ -1207,14 +1205,14 @@ static int lpc_eth_open(struct net_device *ndev) __lpc_eth_clock_enable(pldat, true); /* Suspended PHY makes LPC ethernet core block, so resume now */ - phy_resume(pldat->phy_dev); + phy_resume(ndev->phydev); /* Reset and initialize */ __lpc_eth_reset(pldat); __lpc_eth_init(pldat); /* schedule a link state check */ - phy_start(pldat->phy_dev); + phy_start(ndev->phydev); netif_start_queue(ndev); napi_enable(&pldat->napi); @@ -1247,37 +1245,13 @@ static void lpc_eth_ethtool_setmsglevel(struct net_device *ndev, u32 level) pldat->msg_enable = level; } -static int lpc_eth_ethtool_getsettings(struct net_device *ndev, - struct ethtool_cmd *cmd) -{ - struct netdata_local *pldat = netdev_priv(ndev); - struct phy_device *phydev = pldat->phy_dev; - - if (!phydev) - return -EOPNOTSUPP; - - return phy_ethtool_gset(phydev, cmd); -} - -static int lpc_eth_ethtool_setsettings(struct net_device *ndev, - struct ethtool_cmd *cmd) -{ - struct netdata_local *pldat = netdev_priv(ndev); - struct phy_device *phydev = pldat->phy_dev; - - if (!phydev) - return -EOPNOTSUPP; - - return phy_ethtool_sset(phydev, cmd); -} - static const struct ethtool_ops lpc_eth_ethtool_ops = { .get_drvinfo = lpc_eth_ethtool_getdrvinfo, - .get_settings = lpc_eth_ethtool_getsettings, - .set_settings = lpc_eth_ethtool_setsettings, .get_msglevel = lpc_eth_ethtool_getmsglevel, .set_msglevel = lpc_eth_ethtool_setmsglevel, .get_link = ethtool_op_get_link, + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, }; static const struct net_device_ops lpc_netdev_ops = { @@ -1460,7 +1434,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) netdev_info(ndev, "LPC mac at 0x%08x irq %d\n", res->start, ndev->irq); - phydev = pldat->phy_dev; + phydev = ndev->phydev; device_init_wakeup(&pdev->dev, 1); device_set_wakeup_enable(&pdev->dev, 0); diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index 9a63df1184f1..35e53771533f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -489,8 +489,8 @@ struct qed_dev { u32 int_mode; enum qed_coalescing_mode int_coalescing_mode; - u8 rx_coalesce_usecs; - u8 tx_coalesce_usecs; + u16 rx_coalesce_usecs; + u16 tx_coalesce_usecs; /* Start Bar offset of first hwfn */ void __iomem *regview; diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 6228482bf7f0..c5c658ab0724 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -430,11 +430,13 @@ static int qede_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal) { struct qede_dev *edev = netdev_priv(dev); + u16 rxc, txc; memset(coal, 0, sizeof(struct ethtool_coalesce)); - edev->ops->common->get_coalesce(edev->cdev, - (u16 *)&coal->rx_coalesce_usecs, - (u16 *)&coal->tx_coalesce_usecs); + edev->ops->common->get_coalesce(edev->cdev, &rxc, &txc); + + coal->rx_coalesce_usecs = rxc; + coal->tx_coalesce_usecs = txc; return 0; } diff --git a/drivers/net/ethernet/rdc/r6040.c b/drivers/net/ethernet/rdc/r6040.c index 6b541e57c96a..7a7a395d0512 100644 --- a/drivers/net/ethernet/rdc/r6040.c +++ b/drivers/net/ethernet/rdc/r6040.c @@ -200,7 +200,6 @@ struct r6040_private { struct mii_bus *mii_bus; struct napi_struct napi; void __iomem *base; - struct phy_device *phydev; int old_link; int old_duplex; }; @@ -474,7 +473,7 @@ static void r6040_down(struct net_device *dev) iowrite16(adrp[1], ioaddr + MID_0M); iowrite16(adrp[2], ioaddr + MID_0H); - phy_stop(lp->phydev); + phy_stop(dev->phydev); } static int r6040_close(struct net_device *dev) @@ -515,12 +514,10 @@ static int r6040_close(struct net_device *dev) static int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct r6040_private *lp = netdev_priv(dev); - - if (!lp->phydev) + if (!dev->phydev) return -EINVAL; - return phy_mii_ioctl(lp->phydev, rq, cmd); + return phy_mii_ioctl(dev->phydev, rq, cmd); } static int r6040_rx(struct net_device *dev, int limit) @@ -732,7 +729,7 @@ static int r6040_up(struct net_device *dev) /* Initialize all MAC registers */ r6040_init_mac_regs(dev); - phy_start(lp->phydev); + phy_start(dev->phydev); return 0; } @@ -957,26 +954,12 @@ static void netdev_get_drvinfo(struct net_device *dev, strlcpy(info->bus_info, pci_name(rp->pdev), sizeof(info->bus_info)); } -static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct r6040_private *rp = netdev_priv(dev); - - return phy_ethtool_gset(rp->phydev, cmd); -} - -static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct r6040_private *rp = netdev_priv(dev); - - return phy_ethtool_sset(rp->phydev, cmd); -} - static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, - .get_settings = netdev_get_settings, - .set_settings = netdev_set_settings, .get_link = ethtool_op_get_link, .get_ts_info = ethtool_op_get_ts_info, + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, }; static const struct net_device_ops r6040_netdev_ops = { @@ -998,7 +981,7 @@ static const struct net_device_ops r6040_netdev_ops = { static void r6040_adjust_link(struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); - struct phy_device *phydev = lp->phydev; + struct phy_device *phydev = dev->phydev; int status_changed = 0; void __iomem *ioaddr = lp->base; @@ -1057,7 +1040,6 @@ static int r6040_mii_probe(struct net_device *dev) | SUPPORTED_TP); phydev->advertising = phydev->supported; - lp->phydev = phydev; lp->old_link = 0; lp->old_duplex = -1; diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h index 45019649bbbd..5cb51b609f02 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h @@ -475,7 +475,6 @@ struct sxgbe_priv_data { int rxcsum_insertion; spinlock_t stats_lock; /* lock for tx/rx statatics */ - struct phy_device *phydev; int oldlink; int speed; int oldduplex; diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c index c0981ae45874..542b67d436df 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c @@ -147,7 +147,7 @@ static int sxgbe_get_eee(struct net_device *dev, edata->eee_active = priv->eee_active; edata->tx_lpi_timer = priv->tx_lpi_timer; - return phy_ethtool_get_eee(priv->phydev, edata); + return phy_ethtool_get_eee(dev->phydev, edata); } static int sxgbe_set_eee(struct net_device *dev, @@ -172,7 +172,7 @@ static int sxgbe_set_eee(struct net_device *dev, priv->tx_lpi_timer = edata->tx_lpi_timer; } - return phy_ethtool_set_eee(priv->phydev, edata); + return phy_ethtool_set_eee(dev->phydev, edata); } static void sxgbe_getdrvinfo(struct net_device *dev, @@ -182,27 +182,6 @@ static void sxgbe_getdrvinfo(struct net_device *dev, strlcpy(info->version, DRV_VERSION, sizeof(info->version)); } -static int sxgbe_getsettings(struct net_device *dev, - struct ethtool_cmd *cmd) -{ - struct sxgbe_priv_data *priv = netdev_priv(dev); - - if (priv->phydev) - return phy_ethtool_gset(priv->phydev, cmd); - - return -EOPNOTSUPP; -} - -static int sxgbe_setsettings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct sxgbe_priv_data *priv = netdev_priv(dev); - - if (priv->phydev) - return phy_ethtool_sset(priv->phydev, cmd); - - return -EOPNOTSUPP; -} - static u32 sxgbe_getmsglevel(struct net_device *dev) { struct sxgbe_priv_data *priv = netdev_priv(dev); @@ -255,7 +234,7 @@ static void sxgbe_get_ethtool_stats(struct net_device *dev, char *p; if (priv->eee_enabled) { - int val = phy_get_eee_err(priv->phydev); + int val = phy_get_eee_err(dev->phydev); if (val) priv->xstats.eee_wakeup_error_n = val; @@ -499,8 +478,6 @@ static int sxgbe_get_regs_len(struct net_device *dev) static const struct ethtool_ops sxgbe_ethtool_ops = { .get_drvinfo = sxgbe_getdrvinfo, - .get_settings = sxgbe_getsettings, - .set_settings = sxgbe_setsettings, .get_msglevel = sxgbe_getmsglevel, .set_msglevel = sxgbe_setmsglevel, .get_link = ethtool_op_get_link, @@ -516,6 +493,8 @@ static const struct ethtool_ops sxgbe_ethtool_ops = { .get_regs_len = sxgbe_get_regs_len, .get_eee = sxgbe_get_eee, .set_eee = sxgbe_set_eee, + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, }; void sxgbe_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index 413ea14ab91f..ea44a2456ce1 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -124,12 +124,13 @@ static void sxgbe_eee_ctrl_timer(unsigned long arg) */ bool sxgbe_eee_init(struct sxgbe_priv_data * const priv) { + struct net_device *ndev = priv->dev; bool ret = false; /* MAC core supports the EEE feature. */ if (priv->hw_cap.eee) { /* Check if the PHY supports EEE */ - if (phy_init_eee(priv->phydev, 1)) + if (phy_init_eee(ndev->phydev, 1)) return false; priv->eee_active = 1; @@ -152,12 +153,14 @@ bool sxgbe_eee_init(struct sxgbe_priv_data * const priv) static void sxgbe_eee_adjust(const struct sxgbe_priv_data *priv) { + struct net_device *ndev = priv->dev; + /* When the EEE has been already initialised we have to * modify the PLS bit in the LPI ctrl & status reg according * to the PHY link status. For this reason. */ if (priv->eee_enabled) - priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link); + priv->hw->mac->set_eee_pls(priv->ioaddr, ndev->phydev->link); } /** @@ -203,7 +206,7 @@ static inline u32 sxgbe_tx_avail(struct sxgbe_tx_queue *queue, int tx_qsize) static void sxgbe_adjust_link(struct net_device *dev) { struct sxgbe_priv_data *priv = netdev_priv(dev); - struct phy_device *phydev = priv->phydev; + struct phy_device *phydev = dev->phydev; u8 new_state = 0; u8 speed = 0xff; @@ -306,9 +309,6 @@ static int sxgbe_init_phy(struct net_device *ndev) netdev_dbg(ndev, "%s: attached to PHY (UID 0x%x) Link = %d\n", __func__, phydev->phy_id, phydev->link); - /* save phy device in private structure */ - priv->phydev = phydev; - return 0; } @@ -1173,8 +1173,8 @@ static int sxgbe_open(struct net_device *dev) priv->hw->dma->start_tx(priv->ioaddr, SXGBE_TX_QUEUES); priv->hw->dma->start_rx(priv->ioaddr, SXGBE_RX_QUEUES); - if (priv->phydev) - phy_start(priv->phydev); + if (dev->phydev) + phy_start(dev->phydev); /* initialise TX coalesce parameters */ sxgbe_tx_init_coalesce(priv); @@ -1194,8 +1194,8 @@ static int sxgbe_open(struct net_device *dev) init_error: free_dma_desc_resources(priv); - if (priv->phydev) - phy_disconnect(priv->phydev); + if (dev->phydev) + phy_disconnect(dev->phydev); phy_error: clk_disable_unprepare(priv->sxgbe_clk); @@ -1216,10 +1216,9 @@ static int sxgbe_release(struct net_device *dev) del_timer_sync(&priv->eee_ctrl_timer); /* Stop and disconnect the PHY */ - if (priv->phydev) { - phy_stop(priv->phydev); - phy_disconnect(priv->phydev); - priv->phydev = NULL; + if (dev->phydev) { + phy_stop(dev->phydev); + phy_disconnect(dev->phydev); } netif_tx_stop_all_queues(dev); @@ -1969,7 +1968,6 @@ static void sxgbe_poll_controller(struct net_device *dev) */ static int sxgbe_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct sxgbe_priv_data *priv = netdev_priv(dev); int ret = -EOPNOTSUPP; if (!netif_running(dev)) @@ -1979,9 +1977,9 @@ static int sxgbe_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case SIOCGMIIPHY: case SIOCGMIIREG: case SIOCSMIIREG: - if (!priv->phydev) + if (!dev->phydev) return -EINVAL; - ret = phy_mii_ioctl(priv->phydev, rq, cmd); + ret = phy_mii_ioctl(dev->phydev, rq, cmd); break; default: break; diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index fc60368df2e7..2533b91f1421 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -232,6 +232,11 @@ struct stmmac_extra_stats { #define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY iface */ #define DEFAULT_DMA_PBL 8 +/* PCS status and mask defines */ +#define PCS_ANE_IRQ BIT(2) /* PCS Auto-Negotiation */ +#define PCS_LINK_IRQ BIT(1) /* PCS Link */ +#define PCS_RGSMIIIS_IRQ BIT(0) /* RGMII or SMII Interrupt */ + /* Max/Min RI Watchdog Timer count value */ #define MAX_DMA_RIWT 0xff #define MIN_DMA_RIWT 0x20 @@ -272,9 +277,6 @@ enum dma_irq_status { #define CORE_IRQ_RX_PATH_IN_LPI_MODE (1 << 2) #define CORE_IRQ_RX_PATH_EXIT_LPI_MODE (1 << 3) -#define CORE_PCS_ANE_COMPLETE (1 << 5) -#define CORE_PCS_LINK_STATUS (1 << 6) -#define CORE_RGMII_IRQ (1 << 7) #define CORE_IRQ_MTL_RX_OVERFLOW BIT(8) /* Physical Coding Sublayer */ @@ -469,9 +471,12 @@ struct stmmac_ops { void (*reset_eee_mode)(struct mac_device_info *hw); void (*set_eee_timer)(struct mac_device_info *hw, int ls, int tw); void (*set_eee_pls)(struct mac_device_info *hw, int link); - void (*ctrl_ane)(struct mac_device_info *hw, bool restart); - void (*get_adv)(struct mac_device_info *hw, struct rgmii_adv *adv); void (*debug)(void __iomem *ioaddr, struct stmmac_extra_stats *x); + /* PCS calls */ + void (*pcs_ctrl_ane)(void __iomem *ioaddr, bool ane, bool srgmi_ral, + bool loopback); + void (*pcs_rane)(void __iomem *ioaddr, bool restart); + void (*pcs_get_adv_lp)(void __iomem *ioaddr, struct rgmii_adv *adv); }; /* PTP and HW Timer helpers */ @@ -524,6 +529,9 @@ struct mac_device_info { int unicast_filter_entries; int mcast_bits_log2; unsigned int rx_csum; + unsigned int pcs; + unsigned int pmt; + unsigned int ps; }; struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins, @@ -546,6 +554,7 @@ void stmmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, void stmmac_dwmac4_set_mac(void __iomem *ioaddr, bool enable); void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr); + extern const struct stmmac_mode_ops ring_mode_ops; extern const struct stmmac_mode_ops chain_mode_ops; extern const struct stmmac_desc_ops dwmac4_desc_ops; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h index b0593a4268ee..ff3e5ab39bd0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h @@ -38,19 +38,26 @@ #define GMAC_WAKEUP_FILTER 0x00000028 /* Wake-up Frame Filter */ #define GMAC_INT_STATUS 0x00000038 /* interrupt status register */ -enum dwmac1000_irq_status { - lpiis_irq = 0x400, - time_stamp_irq = 0x0200, - mmc_rx_csum_offload_irq = 0x0080, - mmc_tx_irq = 0x0040, - mmc_rx_irq = 0x0020, - mmc_irq = 0x0010, - pmt_irq = 0x0008, - pcs_ane_irq = 0x0004, - pcs_link_irq = 0x0002, - rgmii_irq = 0x0001, -}; -#define GMAC_INT_MASK 0x0000003c /* interrupt mask register */ +#define GMAC_INT_STATUS_PMT BIT(3) +#define GMAC_INT_STATUS_MMCIS BIT(4) +#define GMAC_INT_STATUS_MMCRIS BIT(5) +#define GMAC_INT_STATUS_MMCTIS BIT(6) +#define GMAC_INT_STATUS_MMCCSUM BIT(7) +#define GMAC_INT_STATUS_TSTAMP BIT(9) +#define GMAC_INT_STATUS_LPIIS BIT(10) + +/* interrupt mask register */ +#define GMAC_INT_MASK 0x0000003c +#define GMAC_INT_DISABLE_RGMII BIT(0) +#define GMAC_INT_DISABLE_PCSLINK BIT(1) +#define GMAC_INT_DISABLE_PCSAN BIT(2) +#define GMAC_INT_DISABLE_PMT BIT(3) +#define GMAC_INT_DISABLE_TIMESTAMP BIT(9) +#define GMAC_INT_DISABLE_PCS (GMAC_INT_DISABLE_RGMII | \ + GMAC_INT_DISABLE_PCSLINK | \ + GMAC_INT_DISABLE_PCSAN) +#define GMAC_INT_DEFAULT_MASK (GMAC_INT_DISABLE_TIMESTAMP | \ + GMAC_INT_DISABLE_PCS) /* PMT Control and Status */ #define GMAC_PMT 0x0000002c @@ -90,42 +97,23 @@ enum power_event { (reg * 8)) #define GMAC_MAX_PERFECT_ADDRESSES 1 -/* PCS registers (AN/TBI/SGMII/RGMII) offset */ -#define GMAC_AN_CTRL 0x000000c0 /* AN control */ -#define GMAC_AN_STATUS 0x000000c4 /* AN status */ -#define GMAC_ANE_ADV 0x000000c8 /* Auto-Neg. Advertisement */ -#define GMAC_ANE_LPA 0x000000cc /* Auto-Neg. link partener ability */ -#define GMAC_ANE_EXP 0x000000d0 /* ANE expansion */ -#define GMAC_TBI 0x000000d4 /* TBI extend status */ -#define GMAC_S_R_GMII 0x000000d8 /* SGMII RGMII status */ - -/* AN Configuration defines */ -#define GMAC_AN_CTRL_RAN 0x00000200 /* Restart Auto-Negotiation */ -#define GMAC_AN_CTRL_ANE 0x00001000 /* Auto-Negotiation Enable */ -#define GMAC_AN_CTRL_ELE 0x00004000 /* External Loopback Enable */ -#define GMAC_AN_CTRL_ECD 0x00010000 /* Enable Comma Detect */ -#define GMAC_AN_CTRL_LR 0x00020000 /* Lock to Reference */ -#define GMAC_AN_CTRL_SGMRAL 0x00040000 /* SGMII RAL Control */ - -/* AN Status defines */ -#define GMAC_AN_STATUS_LS 0x00000004 /* Link Status 0:down 1:up */ -#define GMAC_AN_STATUS_ANA 0x00000008 /* Auto-Negotiation Ability */ -#define GMAC_AN_STATUS_ANC 0x00000020 /* Auto-Negotiation Complete */ -#define GMAC_AN_STATUS_ES 0x00000100 /* Extended Status */ - -/* Register 54 (SGMII/RGMII status register) */ -#define GMAC_S_R_GMII_LINK 0x8 -#define GMAC_S_R_GMII_SPEED 0x5 -#define GMAC_S_R_GMII_SPEED_SHIFT 0x1 -#define GMAC_S_R_GMII_MODE 0x1 -#define GMAC_S_R_GMII_SPEED_125 2 -#define GMAC_S_R_GMII_SPEED_25 1 - -/* Common ADV and LPA defines */ -#define GMAC_ANE_FD (1 << 5) -#define GMAC_ANE_HD (1 << 6) -#define GMAC_ANE_PSE (3 << 7) -#define GMAC_ANE_PSE_SHIFT 7 +#define GMAC_PCS_BASE 0x000000c0 /* PCS register base */ +#define GMAC_RGSMIIIS 0x000000d8 /* RGMII/SMII status */ + +/* SGMII/RGMII status register */ +#define GMAC_RGSMIIIS_LNKMODE BIT(0) +#define GMAC_RGSMIIIS_SPEED GENMASK(2, 1) +#define GMAC_RGSMIIIS_SPEED_SHIFT 1 +#define GMAC_RGSMIIIS_LNKSTS BIT(3) +#define GMAC_RGSMIIIS_JABTO BIT(4) +#define GMAC_RGSMIIIS_FALSECARDET BIT(5) +#define GMAC_RGSMIIIS_SMIDRXS BIT(16) +/* LNKMOD */ +#define GMAC_RGSMIIIS_LNKMOD_MASK 0x1 +/* LNKSPEED */ +#define GMAC_RGSMIIIS_SPEED_125 0x2 +#define GMAC_RGSMIIIS_SPEED_25 0x1 +#define GMAC_RGSMIIIS_SPEED_2_5 0x0 /* GMAC Configuration defines */ #define GMAC_CONTROL_2K 0x08000000 /* IEEE 802.3as 2K packets */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index fb1eb578e34e..cbefe9e2207c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -30,22 +30,48 @@ #include <linux/slab.h> #include <linux/ethtool.h> #include <asm/io.h> +#include "stmmac_pcs.h" #include "dwmac1000.h" static void dwmac1000_core_init(struct mac_device_info *hw, int mtu) { void __iomem *ioaddr = hw->pcsr; u32 value = readl(ioaddr + GMAC_CONTROL); + + /* Configure GMAC core */ value |= GMAC_CORE_INIT; + if (mtu > 1500) value |= GMAC_CONTROL_2K; if (mtu > 2000) value |= GMAC_CONTROL_JE; + if (hw->ps) { + value |= GMAC_CONTROL_TE; + + if (hw->ps == SPEED_1000) { + value &= ~GMAC_CONTROL_PS; + } else { + value |= GMAC_CONTROL_PS; + + if (hw->ps == SPEED_10) + value &= ~GMAC_CONTROL_FES; + else + value |= GMAC_CONTROL_FES; + } + } + writel(value, ioaddr + GMAC_CONTROL); /* Mask GMAC interrupts */ - writel(0x207, ioaddr + GMAC_INT_MASK); + value = GMAC_INT_DEFAULT_MASK; + + if (hw->pmt) + value &= ~GMAC_INT_DISABLE_PMT; + if (hw->pcs) + value &= ~GMAC_INT_DISABLE_PCS; + + writel(value, ioaddr + GMAC_INT_MASK); #ifdef STMMAC_VLAN_TAG_USED /* Tag detection without filtering */ @@ -241,6 +267,39 @@ static void dwmac1000_pmt(struct mac_device_info *hw, unsigned long mode) writel(pmt, ioaddr + GMAC_PMT); } +/* RGMII or SMII interface */ +static void dwmac1000_rgsmii(void __iomem *ioaddr, struct stmmac_extra_stats *x) +{ + u32 status; + + status = readl(ioaddr + GMAC_RGSMIIIS); + x->irq_rgmii_n++; + + /* Check the link status */ + if (status & GMAC_RGSMIIIS_LNKSTS) { + int speed_value; + + x->pcs_link = 1; + + speed_value = ((status & GMAC_RGSMIIIS_SPEED) >> + GMAC_RGSMIIIS_SPEED_SHIFT); + if (speed_value == GMAC_RGSMIIIS_SPEED_125) + x->pcs_speed = SPEED_1000; + else if (speed_value == GMAC_RGSMIIIS_SPEED_25) + x->pcs_speed = SPEED_100; + else + x->pcs_speed = SPEED_10; + + x->pcs_duplex = (status & GMAC_RGSMIIIS_LNKMOD_MASK); + + pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed, + x->pcs_duplex ? "Full" : "Half"); + } else { + x->pcs_link = 0; + pr_info("Link is Down\n"); + } +} + static int dwmac1000_irq_status(struct mac_device_info *hw, struct stmmac_extra_stats *x) { @@ -249,19 +308,20 @@ static int dwmac1000_irq_status(struct mac_device_info *hw, int ret = 0; /* Not used events (e.g. MMC interrupts) are not handled. */ - if ((intr_status & mmc_tx_irq)) + if ((intr_status & GMAC_INT_STATUS_MMCTIS)) x->mmc_tx_irq_n++; - if (unlikely(intr_status & mmc_rx_irq)) + if (unlikely(intr_status & GMAC_INT_STATUS_MMCRIS)) x->mmc_rx_irq_n++; - if (unlikely(intr_status & mmc_rx_csum_offload_irq)) + if (unlikely(intr_status & GMAC_INT_STATUS_MMCCSUM)) x->mmc_rx_csum_offload_irq_n++; - if (unlikely(intr_status & pmt_irq)) { + if (unlikely(intr_status & GMAC_INT_DISABLE_PMT)) { /* clear the PMT bits 5 and 6 by reading the PMT status reg */ readl(ioaddr + GMAC_PMT); x->irq_receive_pmt_irq_n++; } - /* MAC trx/rx EEE LPI entry/exit interrupts */ - if (intr_status & lpiis_irq) { + + /* MAC tx/rx EEE LPI entry/exit interrupts */ + if (intr_status & GMAC_INT_STATUS_LPIIS) { /* Clean LPI interrupt by reading the Reg 12 */ ret = readl(ioaddr + LPI_CTRL_STATUS); @@ -275,36 +335,10 @@ static int dwmac1000_irq_status(struct mac_device_info *hw, x->irq_rx_path_exit_lpi_mode_n++; } - if ((intr_status & pcs_ane_irq) || (intr_status & pcs_link_irq)) { - readl(ioaddr + GMAC_AN_STATUS); - x->irq_pcs_ane_n++; - } - if (intr_status & rgmii_irq) { - u32 status = readl(ioaddr + GMAC_S_R_GMII); - x->irq_rgmii_n++; - - /* Save and dump the link status. */ - if (status & GMAC_S_R_GMII_LINK) { - int speed_value = (status & GMAC_S_R_GMII_SPEED) >> - GMAC_S_R_GMII_SPEED_SHIFT; - x->pcs_duplex = (status & GMAC_S_R_GMII_MODE); - - if (speed_value == GMAC_S_R_GMII_SPEED_125) - x->pcs_speed = SPEED_1000; - else if (speed_value == GMAC_S_R_GMII_SPEED_25) - x->pcs_speed = SPEED_100; - else - x->pcs_speed = SPEED_10; + dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x); - x->pcs_link = 1; - pr_debug("%s: Link is Up - %d/%s\n", __func__, - (int)x->pcs_speed, - x->pcs_duplex ? "Full" : "Half"); - } else { - x->pcs_link = 0; - pr_debug("%s: Link is Down\n", __func__); - } - } + if (intr_status & PCS_RGSMIIIS_IRQ) + dwmac1000_rgsmii(ioaddr, x); return ret; } @@ -363,38 +397,20 @@ static void dwmac1000_set_eee_timer(struct mac_device_info *hw, int ls, int tw) writel(value, ioaddr + LPI_TIMER_CTRL); } -static void dwmac1000_ctrl_ane(struct mac_device_info *hw, bool restart) +static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool ane, bool srgmi_ral, + bool loopback) { - void __iomem *ioaddr = hw->pcsr; - /* auto negotiation enable and External Loopback enable */ - u32 value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE; - - if (restart) - value |= GMAC_AN_CTRL_RAN; - - writel(value, ioaddr + GMAC_AN_CTRL); + dwmac_ctrl_ane(ioaddr, GMAC_PCS_BASE, ane, srgmi_ral, loopback); } -static void dwmac1000_get_adv(struct mac_device_info *hw, struct rgmii_adv *adv) +static void dwmac1000_rane(void __iomem *ioaddr, bool restart) { - void __iomem *ioaddr = hw->pcsr; - u32 value = readl(ioaddr + GMAC_ANE_ADV); - - if (value & GMAC_ANE_FD) - adv->duplex = DUPLEX_FULL; - if (value & GMAC_ANE_HD) - adv->duplex |= DUPLEX_HALF; - - adv->pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT; - - value = readl(ioaddr + GMAC_ANE_LPA); - - if (value & GMAC_ANE_FD) - adv->lp_duplex = DUPLEX_FULL; - if (value & GMAC_ANE_HD) - adv->lp_duplex = DUPLEX_HALF; + dwmac_rane(ioaddr, GMAC_PCS_BASE, restart); +} - adv->lp_pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT; +static void dwmac1000_get_adv_lp(void __iomem *ioaddr, struct rgmii_adv *adv) +{ + dwmac_get_adv_lp(ioaddr, GMAC_PCS_BASE, adv); } static void dwmac1000_debug(void __iomem *ioaddr, struct stmmac_extra_stats *x) @@ -485,9 +501,10 @@ static const struct stmmac_ops dwmac1000_ops = { .reset_eee_mode = dwmac1000_reset_eee_mode, .set_eee_timer = dwmac1000_set_eee_timer, .set_eee_pls = dwmac1000_set_eee_pls, - .ctrl_ane = dwmac1000_ctrl_ane, - .get_adv = dwmac1000_get_adv, .debug = dwmac1000_debug, + .pcs_ctrl_ane = dwmac1000_ctrl_ane, + .pcs_rane = dwmac1000_rane, + .pcs_get_adv_lp = dwmac1000_get_adv_lp, }; struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h index bc50952a18e7..6f4f5ce25114 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h @@ -24,10 +24,8 @@ #define GMAC_QX_TX_FLOW_CTRL(x) (0x70 + x * 4) #define GMAC_INT_STATUS 0x000000b0 #define GMAC_INT_EN 0x000000b4 -#define GMAC_AN_CTRL 0x000000e0 -#define GMAC_AN_STATUS 0x000000e4 -#define GMAC_AN_ADV 0x000000e8 -#define GMAC_AN_LPA 0x000000ec +#define GMAC_PCS_BASE 0x000000e0 +#define GMAC_PHYIF_CONTROL_STATUS 0x000000f8 #define GMAC_PMT 0x000000c0 #define GMAC_VERSION 0x00000110 #define GMAC_DEBUG 0x00000114 @@ -54,9 +52,18 @@ #define GMAC_TX_FLOW_CTRL_PT_SHIFT 16 /* MAC Interrupt bitmap*/ +#define GMAC_INT_RGSMIIS BIT(0) +#define GMAC_INT_PCS_LINK BIT(1) +#define GMAC_INT_PCS_ANE BIT(2) +#define GMAC_INT_PCS_PHYIS BIT(3) #define GMAC_INT_PMT_EN BIT(4) #define GMAC_INT_LPI_EN BIT(5) +#define GMAC_PCS_IRQ_DEFAULT (GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK | \ + GMAC_INT_PCS_ANE) + +#define GMAC_INT_DEFAULT_MASK GMAC_INT_PMT_EN + enum dwmac4_irq_status { time_stamp_irq = 0x00001000, mmc_rx_csum_offload_irq = 0x00000800, @@ -64,19 +71,8 @@ enum dwmac4_irq_status { mmc_rx_irq = 0x00000200, mmc_irq = 0x00000100, pmt_irq = 0x00000010, - pcs_ane_irq = 0x00000004, - pcs_link_irq = 0x00000002, }; -/* MAC Auto-Neg bitmap*/ -#define GMAC_AN_CTRL_RAN BIT(9) -#define GMAC_AN_CTRL_ANE BIT(12) -#define GMAC_AN_CTRL_ELE BIT(14) -#define GMAC_AN_FD BIT(5) -#define GMAC_AN_HD BIT(6) -#define GMAC_AN_PSE_MASK GENMASK(8, 7) -#define GMAC_AN_PSE_SHIFT 7 - /* MAC PMT bitmap */ enum power_event { pointer_reset = 0x80000000, @@ -250,6 +246,23 @@ enum power_event { #define MTL_DEBUG_RRCSTS_FLUSH 3 #define MTL_DEBUG_RWCSTS BIT(0) +/* SGMII/RGMII status register */ +#define GMAC_PHYIF_CTRLSTATUS_TC BIT(0) +#define GMAC_PHYIF_CTRLSTATUS_LUD BIT(1) +#define GMAC_PHYIF_CTRLSTATUS_SMIDRXS BIT(4) +#define GMAC_PHYIF_CTRLSTATUS_LNKMOD BIT(16) +#define GMAC_PHYIF_CTRLSTATUS_SPEED GENMASK(18, 17) +#define GMAC_PHYIF_CTRLSTATUS_SPEED_SHIFT 17 +#define GMAC_PHYIF_CTRLSTATUS_LNKSTS BIT(19) +#define GMAC_PHYIF_CTRLSTATUS_JABTO BIT(20) +#define GMAC_PHYIF_CTRLSTATUS_FALSECARDET BIT(21) +/* LNKMOD */ +#define GMAC_PHYIF_CTRLSTATUS_LNKMOD_MASK 0x1 +/* LNKSPEED */ +#define GMAC_PHYIF_CTRLSTATUS_SPEED_125 0x2 +#define GMAC_PHYIF_CTRLSTATUS_SPEED_25 0x1 +#define GMAC_PHYIF_CTRLSTATUS_SPEED_2_5 0x0 + extern const struct stmmac_dma_ops dwmac4_dma_ops; extern const struct stmmac_dma_ops dwmac410_dma_ops; #endif /* __DWMAC4_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 44da877d2483..df5580dcdfed 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/ethtool.h> #include <linux/io.h> +#include "stmmac_pcs.h" #include "dwmac4.h" static void dwmac4_core_init(struct mac_device_info *hw, int mtu) @@ -31,10 +32,31 @@ static void dwmac4_core_init(struct mac_device_info *hw, int mtu) if (mtu > 2000) value |= GMAC_CONFIG_JE; + if (hw->ps) { + value |= GMAC_CONFIG_TE; + + if (hw->ps == SPEED_1000) { + value &= ~GMAC_CONFIG_PS; + } else { + value |= GMAC_CONFIG_PS; + + if (hw->ps == SPEED_10) + value &= ~GMAC_CONFIG_FES; + else + value |= GMAC_CONFIG_FES; + } + } + writel(value, ioaddr + GMAC_CONFIG); /* Mask GMAC interrupts */ - writel(GMAC_INT_PMT_EN, ioaddr + GMAC_INT_EN); + value = GMAC_INT_DEFAULT_MASK; + if (hw->pmt) + value |= GMAC_INT_PMT_EN; + if (hw->pcs) + value |= GMAC_PCS_IRQ_DEFAULT; + + writel(value, ioaddr + GMAC_INT_EN); } static void dwmac4_dump_regs(struct mac_device_info *hw) @@ -190,39 +212,53 @@ static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex, } } -static void dwmac4_ctrl_ane(struct mac_device_info *hw, bool restart) +static void dwmac4_ctrl_ane(void __iomem *ioaddr, bool ane, bool srgmi_ral, + bool loopback) { - void __iomem *ioaddr = hw->pcsr; - - /* auto negotiation enable and External Loopback enable */ - u32 value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE; + dwmac_ctrl_ane(ioaddr, GMAC_PCS_BASE, ane, srgmi_ral, loopback); +} - if (restart) - value |= GMAC_AN_CTRL_RAN; +static void dwmac4_rane(void __iomem *ioaddr, bool restart) +{ + dwmac_rane(ioaddr, GMAC_PCS_BASE, restart); +} - writel(value, ioaddr + GMAC_AN_CTRL); +static void dwmac4_get_adv_lp(void __iomem *ioaddr, struct rgmii_adv *adv) +{ + dwmac_get_adv_lp(ioaddr, GMAC_PCS_BASE, adv); } -static void dwmac4_get_adv(struct mac_device_info *hw, struct rgmii_adv *adv) +/* RGMII or SMII interface */ +static void dwmac4_phystatus(void __iomem *ioaddr, struct stmmac_extra_stats *x) { - void __iomem *ioaddr = hw->pcsr; - u32 value = readl(ioaddr + GMAC_AN_ADV); + u32 status; - if (value & GMAC_AN_FD) - adv->duplex = DUPLEX_FULL; - if (value & GMAC_AN_HD) - adv->duplex |= DUPLEX_HALF; + status = readl(ioaddr + GMAC_PHYIF_CONTROL_STATUS); + x->irq_rgmii_n++; - adv->pause = (value & GMAC_AN_PSE_MASK) >> GMAC_AN_PSE_SHIFT; + /* Check the link status */ + if (status & GMAC_PHYIF_CTRLSTATUS_LNKSTS) { + int speed_value; - value = readl(ioaddr + GMAC_AN_LPA); + x->pcs_link = 1; + + speed_value = ((status & GMAC_PHYIF_CTRLSTATUS_SPEED) >> + GMAC_PHYIF_CTRLSTATUS_SPEED_SHIFT); + if (speed_value == GMAC_PHYIF_CTRLSTATUS_SPEED_125) + x->pcs_speed = SPEED_1000; + else if (speed_value == GMAC_PHYIF_CTRLSTATUS_SPEED_25) + x->pcs_speed = SPEED_100; + else + x->pcs_speed = SPEED_10; - if (value & GMAC_AN_FD) - adv->lp_duplex = DUPLEX_FULL; - if (value & GMAC_AN_HD) - adv->lp_duplex = DUPLEX_HALF; + x->pcs_duplex = (status & GMAC_PHYIF_CTRLSTATUS_LNKMOD_MASK); - adv->lp_pause = (value & GMAC_AN_PSE_MASK) >> GMAC_AN_PSE_SHIFT; + pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed, + x->pcs_duplex ? "Full" : "Half"); + } else { + x->pcs_link = 0; + pr_info("Link is Down\n"); + } } static int dwmac4_irq_status(struct mac_device_info *hw, @@ -248,11 +284,6 @@ static int dwmac4_irq_status(struct mac_device_info *hw, x->irq_receive_pmt_irq_n++; } - if ((intr_status & pcs_ane_irq) || (intr_status & pcs_link_irq)) { - readl(ioaddr + GMAC_AN_STATUS); - x->irq_pcs_ane_n++; - } - mtl_int_qx_status = readl(ioaddr + MTL_INT_STATUS); /* Check MTL Interrupt: Currently only one queue is used: Q0. */ if (mtl_int_qx_status & MTL_INT_Q0) { @@ -267,6 +298,10 @@ static int dwmac4_irq_status(struct mac_device_info *hw, } } + dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x); + if (intr_status & PCS_RGSMIIIS_IRQ) + dwmac4_phystatus(ioaddr, x); + return ret; } @@ -363,8 +398,9 @@ static const struct stmmac_ops dwmac4_ops = { .pmt = dwmac4_pmt, .set_umac_addr = dwmac4_set_umac_addr, .get_umac_addr = dwmac4_get_umac_addr, - .ctrl_ane = dwmac4_ctrl_ane, - .get_adv = dwmac4_get_adv, + .pcs_ctrl_ane = dwmac4_ctrl_ane, + .pcs_rane = dwmac4_rane, + .pcs_get_adv_lp = dwmac4_get_adv_lp, .debug = dwmac4_debug, .set_filter = dwmac4_set_filter, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 59ae6088cd22..8dc9056c1001 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -117,7 +117,6 @@ struct stmmac_priv { int eee_enabled; int eee_active; int tx_lpi_timer; - int pcs; unsigned int mode; int extend_desc; struct ptp_clock *ptp_clock; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index e2b98b01647e..1e06173fc9d7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -276,7 +276,8 @@ static int stmmac_ethtool_getsettings(struct net_device *dev, struct phy_device *phy = priv->phydev; int rc; - if ((priv->pcs & STMMAC_PCS_RGMII) || (priv->pcs & STMMAC_PCS_SGMII)) { + if (priv->hw->pcs & STMMAC_PCS_RGMII || + priv->hw->pcs & STMMAC_PCS_SGMII) { struct rgmii_adv adv; if (!priv->xstats.pcs_link) { @@ -289,10 +290,10 @@ static int stmmac_ethtool_getsettings(struct net_device *dev, ethtool_cmd_speed_set(cmd, priv->xstats.pcs_speed); /* Get and convert ADV/LP_ADV from the HW AN registers */ - if (!priv->hw->mac->get_adv) + if (!priv->hw->mac->pcs_get_adv_lp) return -EOPNOTSUPP; /* should never happen indeed */ - priv->hw->mac->get_adv(priv->hw, &adv); + priv->hw->mac->pcs_get_adv_lp(priv->ioaddr, &adv); /* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */ @@ -361,7 +362,8 @@ static int stmmac_ethtool_setsettings(struct net_device *dev, struct phy_device *phy = priv->phydev; int rc; - if ((priv->pcs & STMMAC_PCS_RGMII) || (priv->pcs & STMMAC_PCS_SGMII)) { + if (priv->hw->pcs & STMMAC_PCS_RGMII || + priv->hw->pcs & STMMAC_PCS_SGMII) { u32 mask = ADVERTISED_Autoneg | ADVERTISED_Pause; /* Only support ANE */ @@ -376,8 +378,11 @@ static int stmmac_ethtool_setsettings(struct net_device *dev, ADVERTISED_10baseT_Full); spin_lock(&priv->lock); - if (priv->hw->mac->ctrl_ane) - priv->hw->mac->ctrl_ane(priv->hw, 1); + + if (priv->hw->mac->pcs_ctrl_ane) + priv->hw->mac->pcs_ctrl_ane(priv->ioaddr, 1, + priv->hw->ps, 0); + spin_unlock(&priv->lock); return 0; @@ -452,11 +457,22 @@ stmmac_get_pauseparam(struct net_device *netdev, { struct stmmac_priv *priv = netdev_priv(netdev); - if (priv->pcs) /* FIXME */ - return; - pause->rx_pause = 0; pause->tx_pause = 0; + + if (priv->hw->pcs && priv->hw->mac->pcs_get_adv_lp) { + struct rgmii_adv adv_lp; + + pause->autoneg = 1; + priv->hw->mac->pcs_get_adv_lp(priv->ioaddr, &adv_lp); + if (!adv_lp.pause) + return; + } else { + if (!(priv->phydev->supported & SUPPORTED_Pause) || + !(priv->phydev->supported & SUPPORTED_Asym_Pause)) + return; + } + pause->autoneg = priv->phydev->autoneg; if (priv->flow_ctrl & FLOW_RX) @@ -473,10 +489,19 @@ stmmac_set_pauseparam(struct net_device *netdev, struct stmmac_priv *priv = netdev_priv(netdev); struct phy_device *phy = priv->phydev; int new_pause = FLOW_OFF; - int ret = 0; - if (priv->pcs) /* FIXME */ - return -EOPNOTSUPP; + if (priv->hw->pcs && priv->hw->mac->pcs_get_adv_lp) { + struct rgmii_adv adv_lp; + + pause->autoneg = 1; + priv->hw->mac->pcs_get_adv_lp(priv->ioaddr, &adv_lp); + if (!adv_lp.pause) + return -EOPNOTSUPP; + } else { + if (!(phy->supported & SUPPORTED_Pause) || + !(phy->supported & SUPPORTED_Asym_Pause)) + return -EOPNOTSUPP; + } if (pause->rx_pause) new_pause |= FLOW_RX; @@ -488,11 +513,12 @@ stmmac_set_pauseparam(struct net_device *netdev, if (phy->autoneg) { if (netif_running(netdev)) - ret = phy_start_aneg(phy); - } else - priv->hw->mac->flow_ctrl(priv->hw, phy->duplex, - priv->flow_ctrl, priv->pause); - return ret; + return phy_start_aneg(phy); + } + + priv->hw->mac->flow_ctrl(priv->hw, phy->duplex, priv->flow_ctrl, + priv->pause); + return 0; } static void stmmac_get_ethtool_stats(struct net_device *dev, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index a473c182c91d..aab777c1ba33 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -285,8 +285,9 @@ bool stmmac_eee_init(struct stmmac_priv *priv) /* Using PCS we cannot dial with the phy registers at this stage * so we do not support extra feature like EEE. */ - if ((priv->pcs == STMMAC_PCS_RGMII) || (priv->pcs == STMMAC_PCS_TBI) || - (priv->pcs == STMMAC_PCS_RTBI)) + if ((priv->hw->pcs == STMMAC_PCS_RGMII) || + (priv->hw->pcs == STMMAC_PCS_TBI) || + (priv->hw->pcs == STMMAC_PCS_RTBI)) goto out; /* MAC core supports the EEE feature. */ @@ -799,10 +800,10 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv) (interface == PHY_INTERFACE_MODE_RGMII_RXID) || (interface == PHY_INTERFACE_MODE_RGMII_TXID)) { pr_debug("STMMAC: PCS RGMII support enable\n"); - priv->pcs = STMMAC_PCS_RGMII; + priv->hw->pcs = STMMAC_PCS_RGMII; } else if (interface == PHY_INTERFACE_MODE_SGMII) { pr_debug("STMMAC: PCS SGMII support enable\n"); - priv->pcs = STMMAC_PCS_SGMII; + priv->hw->pcs = STMMAC_PCS_SGMII; } } } @@ -1665,6 +1666,19 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) if (priv->plat->bus_setup) priv->plat->bus_setup(priv->ioaddr); + /* PS and related bits will be programmed according to the speed */ + if (priv->hw->pcs) { + int speed = priv->plat->mac_port_sel_speed; + + if ((speed == SPEED_10) || (speed == SPEED_100) || + (speed == SPEED_1000)) { + priv->hw->ps = speed; + } else { + dev_warn(priv->device, "invalid port speed\n"); + priv->hw->ps = 0; + } + } + /* Initialize the MAC Core */ priv->hw->mac->core_init(priv->hw, dev->mtu); @@ -1714,8 +1728,8 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) priv->hw->dma->rx_watchdog(priv->ioaddr, MAX_DMA_RIWT); } - if (priv->pcs && priv->hw->mac->ctrl_ane) - priv->hw->mac->ctrl_ane(priv->hw, 0); + if (priv->hw->pcs && priv->hw->mac->pcs_ctrl_ane) + priv->hw->mac->pcs_ctrl_ane(priv->hw, 1, priv->hw->ps, 0); /* set TX ring length */ if (priv->hw->dma->set_tx_ring_len) @@ -1748,8 +1762,9 @@ static int stmmac_open(struct net_device *dev) stmmac_check_ether_addr(priv); - if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI && - priv->pcs != STMMAC_PCS_RTBI) { + if (priv->hw->pcs != STMMAC_PCS_RGMII && + priv->hw->pcs != STMMAC_PCS_TBI && + priv->hw->pcs != STMMAC_PCS_RTBI) { ret = stmmac_init_phy(dev); if (ret) { pr_err("%s: Cannot attach to PHY (error: %d)\n", @@ -2809,6 +2824,14 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) priv->rx_tail_addr, STMMAC_CHAN0); } + + /* PCS link status */ + if (priv->hw->pcs) { + if (priv->xstats.pcs_link) + netif_carrier_on(dev); + else + netif_carrier_off(dev); + } } /* To handle DMA interrupts */ @@ -3130,6 +3153,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv) */ priv->plat->enh_desc = priv->dma_cap.enh_desc; priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up; + priv->hw->pmt = priv->plat->pmt; /* TXCOE doesn't work in thresh DMA mode */ if (priv->plat->force_thresh_dma_mode) @@ -3325,8 +3349,9 @@ int stmmac_dvr_probe(struct device *device, stmmac_check_pcs_mode(priv); - if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI && - priv->pcs != STMMAC_PCS_RTBI) { + if (priv->hw->pcs != STMMAC_PCS_RGMII && + priv->hw->pcs != STMMAC_PCS_TBI && + priv->hw->pcs != STMMAC_PCS_RTBI) { /* MDIO bus Registration */ ret = stmmac_mdio_register(ndev); if (ret < 0) { @@ -3376,8 +3401,9 @@ int stmmac_dvr_remove(struct device *dev) reset_control_assert(priv->stmmac_rst); clk_disable_unprepare(priv->pclk); clk_disable_unprepare(priv->stmmac_clk); - if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI && - priv->pcs != STMMAC_PCS_RTBI) + if (priv->hw->pcs != STMMAC_PCS_RGMII && + priv->hw->pcs != STMMAC_PCS_TBI && + priv->hw->pcs != STMMAC_PCS_RTBI) stmmac_mdio_unregister(ndev); free_netdev(ndev); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h new file mode 100644 index 000000000000..eba41c24b7a7 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h @@ -0,0 +1,159 @@ +/* + * stmmac_pcs.h: Physical Coding Sublayer Header File + * + * Copyright (C) 2016 STMicroelectronics (R&D) Limited + * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __STMMAC_PCS_H__ +#define __STMMAC_PCS_H__ + +#include <linux/slab.h> +#include <linux/io.h> +#include "common.h" + +/* PCS registers (AN/TBI/SGMII/RGMII) offsets */ +#define GMAC_AN_CTRL(x) (x) /* AN control */ +#define GMAC_AN_STATUS(x) (x + 0x4) /* AN status */ +#define GMAC_ANE_ADV(x) (x + 0x8) /* ANE Advertisement */ +#define GMAC_ANE_LPA(x) (x + 0xc) /* ANE link partener ability */ +#define GMAC_ANE_EXP(x) (x + 0x10) /* ANE expansion */ +#define GMAC_TBI(x) (x + 0x14) /* TBI extend status */ + +/* AN Configuration defines */ +#define GMAC_AN_CTRL_RAN BIT(9) /* Restart Auto-Negotiation */ +#define GMAC_AN_CTRL_ANE BIT(12) /* Auto-Negotiation Enable */ +#define GMAC_AN_CTRL_ELE BIT(14) /* External Loopback Enable */ +#define GMAC_AN_CTRL_ECD BIT(16) /* Enable Comma Detect */ +#define GMAC_AN_CTRL_LR BIT(17) /* Lock to Reference */ +#define GMAC_AN_CTRL_SGMRAL BIT(18) /* SGMII RAL Control */ + +/* AN Status defines */ +#define GMAC_AN_STATUS_LS BIT(2) /* Link Status 0:down 1:up */ +#define GMAC_AN_STATUS_ANA BIT(3) /* Auto-Negotiation Ability */ +#define GMAC_AN_STATUS_ANC BIT(5) /* Auto-Negotiation Complete */ +#define GMAC_AN_STATUS_ES BIT(8) /* Extended Status */ + +/* ADV and LPA defines */ +#define GMAC_ANE_FD BIT(5) +#define GMAC_ANE_HD BIT(6) +#define GMAC_ANE_PSE GENMASK(8, 7) +#define GMAC_ANE_PSE_SHIFT 7 +#define GMAC_ANE_RFE GENMASK(13, 12) +#define GMAC_ANE_RFE_SHIFT 12 +#define GMAC_ANE_ACK BIT(14) + +/** + * dwmac_pcs_isr - TBI, RTBI, or SGMII PHY ISR + * @ioaddr: IO registers pointer + * @reg: Base address of the AN Control Register. + * @intr_status: GMAC core interrupt status + * @x: pointer to log these events as stats + * Description: it is the ISR for PCS events: Auto-Negotiation Completed and + * Link status. + */ +static inline void dwmac_pcs_isr(void __iomem *ioaddr, u32 reg, + unsigned int intr_status, + struct stmmac_extra_stats *x) +{ + u32 val = readl(ioaddr + GMAC_AN_STATUS(reg)); + + if (intr_status & PCS_ANE_IRQ) { + x->irq_pcs_ane_n++; + if (val & GMAC_AN_STATUS_ANC) + pr_info("stmmac_pcs: ANE process completed\n"); + } + + if (intr_status & PCS_LINK_IRQ) { + x->irq_pcs_link_n++; + if (val & GMAC_AN_STATUS_LS) + pr_info("stmmac_pcs: Link Up\n"); + else + pr_info("stmmac_pcs: Link Down\n"); + } +} + +/** + * dwmac_rane - To restart ANE + * @ioaddr: IO registers pointer + * @reg: Base address of the AN Control Register. + * @restart: to restart ANE + * Description: this is to just restart the Auto-Negotiation. + */ +static inline void dwmac_rane(void __iomem *ioaddr, u32 reg, bool restart) +{ + u32 value = readl(ioaddr + GMAC_AN_CTRL(reg)); + + if (restart) + value |= GMAC_AN_CTRL_RAN; + + writel(value, ioaddr + GMAC_AN_CTRL(reg)); +} + +/** + * dwmac_ctrl_ane - To program the AN Control Register. + * @ioaddr: IO registers pointer + * @reg: Base address of the AN Control Register. + * @ane: to enable the auto-negotiation + * @srgmi_ral: to manage MAC-2-MAC SGMII connections. + * @loopback: to cause the PHY to loopback tx data into rx path. + * Description: this is the main function to configure the AN control register + * and init the ANE, select loopback (usually for debugging purpose) and + * configure SGMII RAL. + */ +static inline void dwmac_ctrl_ane(void __iomem *ioaddr, u32 reg, bool ane, + bool srgmi_ral, bool loopback) +{ + u32 value = readl(ioaddr + GMAC_AN_CTRL(reg)); + + /* Enable and restart the Auto-Negotiation */ + if (ane) + value |= GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_RAN; + + /* In case of MAC-2-MAC connection, block is configured to operate + * according to MAC conf register. + */ + if (srgmi_ral) + value |= GMAC_AN_CTRL_SGMRAL; + + if (loopback) + value |= GMAC_AN_CTRL_ELE; + + writel(value, ioaddr + GMAC_AN_CTRL(reg)); +} + +/** + * dwmac_get_adv_lp - Get ADV and LP cap + * @ioaddr: IO registers pointer + * @reg: Base address of the AN Control Register. + * @adv_lp: structure to store the adv,lp status + * Description: this is to expose the ANE advertisement and Link partner ability + * status to ethtool support. + */ +static inline void dwmac_get_adv_lp(void __iomem *ioaddr, u32 reg, + struct rgmii_adv *adv_lp) +{ + u32 value = readl(ioaddr + GMAC_ANE_ADV(reg)); + + if (value & GMAC_ANE_FD) + adv_lp->duplex = DUPLEX_FULL; + if (value & GMAC_ANE_HD) + adv_lp->duplex |= DUPLEX_HALF; + + adv_lp->pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT; + + value = readl(ioaddr + GMAC_ANE_LPA(reg)); + + if (value & GMAC_ANE_FD) + adv_lp->lp_duplex = DUPLEX_FULL; + if (value & GMAC_ANE_HD) + adv_lp->lp_duplex = DUPLEX_HALF; + + adv_lp->lp_pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT; +} +#endif /* __STMMAC_PCS_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index a96714d34560..f7dfc0ae8e9c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -319,6 +319,8 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set."); } + of_property_read_u32(np, "snps,ps-speed", &plat->mac_port_sel_speed); + plat->axi = stmmac_axi_setup(pdev); return plat; diff --git a/drivers/net/ethernet/synopsys/dwc_eth_qos.c b/drivers/net/ethernet/synopsys/dwc_eth_qos.c index 158213cd6cdd..c14fa91c825f 100644 --- a/drivers/net/ethernet/synopsys/dwc_eth_qos.c +++ b/drivers/net/ethernet/synopsys/dwc_eth_qos.c @@ -598,7 +598,6 @@ struct net_local { struct work_struct txtimeout_reinit; phy_interface_t phy_interface; - struct phy_device *phy_dev; struct mii_bus *mii_bus; unsigned int link; @@ -816,7 +815,7 @@ static int dwceqos_mdio_write(struct mii_bus *bus, int mii_id, int phyreg, static int dwceqos_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) { struct net_local *lp = netdev_priv(ndev); - struct phy_device *phydev = lp->phy_dev; + struct phy_device *phydev = ndev->phydev; if (!netif_running(ndev)) return -EINVAL; @@ -850,6 +849,7 @@ static void dwceqos_link_down(struct net_local *lp) static void dwceqos_link_up(struct net_local *lp) { + struct net_device *ndev = lp->ndev; u32 regval; unsigned long flags; @@ -860,7 +860,7 @@ static void dwceqos_link_up(struct net_local *lp) dwceqos_write(lp, REG_DWCEQOS_MAC_LPI_CTRL_STATUS, regval); spin_unlock_irqrestore(&lp->hw_lock, flags); - lp->eee_active = !phy_init_eee(lp->phy_dev, 0); + lp->eee_active = !phy_init_eee(ndev->phydev, 0); /* Check for changed EEE capability */ if (!lp->eee_active && lp->eee_enabled) { @@ -876,7 +876,8 @@ static void dwceqos_link_up(struct net_local *lp) static void dwceqos_set_speed(struct net_local *lp) { - struct phy_device *phydev = lp->phy_dev; + struct net_device *ndev = lp->ndev; + struct phy_device *phydev = ndev->phydev; u32 regval; regval = dwceqos_read(lp, REG_DWCEQOS_MAC_CFG); @@ -903,7 +904,7 @@ static void dwceqos_set_speed(struct net_local *lp) static void dwceqos_adjust_link(struct net_device *ndev) { struct net_local *lp = netdev_priv(ndev); - struct phy_device *phydev = lp->phy_dev; + struct phy_device *phydev = ndev->phydev; int status_change = 0; if (lp->phy_defer) @@ -987,7 +988,6 @@ static int dwceqos_mii_probe(struct net_device *ndev) lp->link = 0; lp->speed = 0; lp->duplex = DUPLEX_UNKNOWN; - lp->phy_dev = phydev; return 0; } @@ -1531,6 +1531,7 @@ static void dwceqos_configure_bus(struct net_local *lp) static void dwceqos_init_hw(struct net_local *lp) { + struct net_device *ndev = lp->ndev; u32 regval; u32 buswidth; u32 dma_skip; @@ -1645,10 +1646,10 @@ static void dwceqos_init_hw(struct net_local *lp) regval | DWCEQOS_MAC_CFG_TE | DWCEQOS_MAC_CFG_RE); lp->phy_defer = false; - mutex_lock(&lp->phy_dev->lock); - phy_read_status(lp->phy_dev); + mutex_lock(&ndev->phydev->lock); + phy_read_status(ndev->phydev); dwceqos_adjust_link(lp->ndev); - mutex_unlock(&lp->phy_dev->lock); + mutex_unlock(&ndev->phydev->lock); } static void dwceqos_tx_reclaim(unsigned long data) @@ -1898,7 +1899,7 @@ static int dwceqos_open(struct net_device *ndev) * hence the unusual init order with phy_start first. */ lp->phy_defer = true; - phy_start(lp->phy_dev); + phy_start(ndev->phydev); dwceqos_init_hw(lp); napi_enable(&lp->napi); @@ -1943,7 +1944,7 @@ static int dwceqos_stop(struct net_device *ndev) dwceqos_drain_dma(lp); dwceqos_reset_hw(lp); - phy_stop(lp->phy_dev); + phy_stop(ndev->phydev); dwceqos_descriptor_free(lp); @@ -2523,30 +2524,6 @@ dwceqos_get_stats64(struct net_device *ndev, struct rtnl_link_stats64 *s) return s; } -static int -dwceqos_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd) -{ - struct net_local *lp = netdev_priv(ndev); - struct phy_device *phydev = lp->phy_dev; - - if (!phydev) - return -ENODEV; - - return phy_ethtool_gset(phydev, ecmd); -} - -static int -dwceqos_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd) -{ - struct net_local *lp = netdev_priv(ndev); - struct phy_device *phydev = lp->phy_dev; - - if (!phydev) - return -ENODEV; - - return phy_ethtool_sset(phydev, ecmd); -} - static void dwceqos_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *ed) { @@ -2574,17 +2551,17 @@ static int dwceqos_set_pauseparam(struct net_device *ndev, lp->flowcontrol.autoneg = pp->autoneg; if (pp->autoneg) { - lp->phy_dev->advertising |= ADVERTISED_Pause; - lp->phy_dev->advertising |= ADVERTISED_Asym_Pause; + ndev->phydev->advertising |= ADVERTISED_Pause; + ndev->phydev->advertising |= ADVERTISED_Asym_Pause; } else { - lp->phy_dev->advertising &= ~ADVERTISED_Pause; - lp->phy_dev->advertising &= ~ADVERTISED_Asym_Pause; + ndev->phydev->advertising &= ~ADVERTISED_Pause; + ndev->phydev->advertising &= ~ADVERTISED_Asym_Pause; lp->flowcontrol.rx = pp->rx_pause; lp->flowcontrol.tx = pp->tx_pause; } if (netif_running(ndev)) - ret = phy_start_aneg(lp->phy_dev); + ret = phy_start_aneg(ndev->phydev); return ret; } @@ -2705,7 +2682,7 @@ static int dwceqos_get_eee(struct net_device *ndev, struct ethtool_eee *edata) dwceqos_get_tx_lpi_state(regval)); } - return phy_ethtool_get_eee(lp->phy_dev, edata); + return phy_ethtool_get_eee(ndev->phydev, edata); } static int dwceqos_set_eee(struct net_device *ndev, struct ethtool_eee *edata) @@ -2747,7 +2724,7 @@ static int dwceqos_set_eee(struct net_device *ndev, struct ethtool_eee *edata) spin_unlock_irqrestore(&lp->hw_lock, flags); } - return phy_ethtool_set_eee(lp->phy_dev, edata); + return phy_ethtool_set_eee(ndev->phydev, edata); } static u32 dwceqos_get_msglevel(struct net_device *ndev) @@ -2765,8 +2742,6 @@ static void dwceqos_set_msglevel(struct net_device *ndev, u32 msglevel) } static struct ethtool_ops dwceqos_ethtool_ops = { - .get_settings = dwceqos_get_settings, - .set_settings = dwceqos_set_settings, .get_drvinfo = dwceqos_get_drvinfo, .get_link = ethtool_op_get_link, .get_pauseparam = dwceqos_get_pauseparam, @@ -2780,6 +2755,8 @@ static struct ethtool_ops dwceqos_ethtool_ops = { .set_eee = dwceqos_set_eee, .get_msglevel = dwceqos_get_msglevel, .set_msglevel = dwceqos_set_msglevel, + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, }; static struct net_device_ops netdev_ops = { @@ -2981,8 +2958,8 @@ static int dwceqos_remove(struct platform_device *pdev) if (ndev) { lp = netdev_priv(ndev); - if (lp->phy_dev) - phy_disconnect(lp->phy_dev); + if (ndev->phydev) + phy_disconnect(ndev->phydev); mdiobus_unregister(lp->mii_bus); mdiobus_free(lp->mii_bus); diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 9c924f15cd03..6d0c5a0c34c6 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1243,6 +1243,7 @@ static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv) slave->phy = NULL; cpsw_ale_control_set(priv->ale, slave_port, ALE_PORT_STATE, ALE_PORT_STATE_DISABLE); + soft_reset_slave(slave); } static int cpsw_ndo_open(struct net_device *ndev) @@ -1251,7 +1252,11 @@ static int cpsw_ndo_open(struct net_device *ndev) int i, ret; u32 reg; - pm_runtime_get_sync(&priv->pdev->dev); + ret = pm_runtime_get_sync(&priv->pdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(&priv->pdev->dev); + return ret; + } if (!cpsw_common_res_usage_state(priv)) cpsw_intr_disable(priv); @@ -1609,10 +1614,17 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) struct sockaddr *addr = (struct sockaddr *)p; int flags = 0; u16 vid = 0; + int ret; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; + ret = pm_runtime_get_sync(&priv->pdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(&priv->pdev->dev); + return ret; + } + if (priv->data.dual_emac) { vid = priv->slaves[priv->emac_port].port_vlan; flags = ALE_VLAN; @@ -1627,6 +1639,8 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) memcpy(ndev->dev_addr, priv->mac_addr, ETH_ALEN); for_each_slave(priv, cpsw_set_slave_mac, priv); + pm_runtime_put(&priv->pdev->dev); + return 0; } @@ -1691,10 +1705,17 @@ static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid) { struct cpsw_priv *priv = netdev_priv(ndev); + int ret; if (vid == priv->data.default_vlan) return 0; + ret = pm_runtime_get_sync(&priv->pdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(&priv->pdev->dev); + return ret; + } + if (priv->data.dual_emac) { /* In dual EMAC, reserved VLAN id should not be used for * creating VLAN interfaces as this can break the dual @@ -1709,7 +1730,10 @@ static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev, } dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid); - return cpsw_add_vlan_ale_entry(priv, vid); + ret = cpsw_add_vlan_ale_entry(priv, vid); + + pm_runtime_put(&priv->pdev->dev); + return ret; } static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, @@ -1721,6 +1745,12 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, if (vid == priv->data.default_vlan) return 0; + ret = pm_runtime_get_sync(&priv->pdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(&priv->pdev->dev); + return ret; + } + if (priv->data.dual_emac) { int i; @@ -1740,8 +1770,10 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, if (ret != 0) return ret; - return cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast, - 0, ALE_VLAN, vid); + ret = cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast, + 0, ALE_VLAN, vid); + pm_runtime_put(&priv->pdev->dev); + return ret; } static const struct net_device_ops cpsw_netdev_ops = { @@ -1900,10 +1932,33 @@ static int cpsw_set_pauseparam(struct net_device *ndev, priv->tx_pause = pause->tx_pause ? true : false; for_each_slave(priv, _cpsw_adjust_link, priv, &link); - return 0; } +static int cpsw_ethtool_op_begin(struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + int ret; + + ret = pm_runtime_get_sync(&priv->pdev->dev); + if (ret < 0) { + cpsw_err(priv, drv, "ethtool begin failed %d\n", ret); + pm_runtime_put_noidle(&priv->pdev->dev); + } + + return ret; +} + +static void cpsw_ethtool_op_complete(struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + int ret; + + ret = pm_runtime_put(&priv->pdev->dev); + if (ret < 0) + cpsw_err(priv, drv, "ethtool complete failed %d\n", ret); +} + static const struct ethtool_ops cpsw_ethtool_ops = { .get_drvinfo = cpsw_get_drvinfo, .get_msglevel = cpsw_get_msglevel, @@ -1923,6 +1978,8 @@ static const struct ethtool_ops cpsw_ethtool_ops = { .set_wol = cpsw_set_wol, .get_regs_len = cpsw_get_regs_len, .get_regs = cpsw_get_regs, + .begin = cpsw_ethtool_op_begin, + .complete = cpsw_ethtool_op_complete, }; static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv, @@ -2311,7 +2368,11 @@ static int cpsw_probe(struct platform_device *pdev) /* Need to enable clocks with runtime PM api to access module * registers */ - pm_runtime_get_sync(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(&pdev->dev); + goto clean_runtime_disable_ret; + } priv->version = readl(&priv->regs->id_ver); pm_runtime_put_sync(&pdev->dev); @@ -2548,16 +2609,12 @@ static int cpsw_suspend(struct device *dev) for (i = 0; i < priv->data.slaves; i++) { if (netif_running(priv->slaves[i].ndev)) cpsw_ndo_stop(priv->slaves[i].ndev); - soft_reset_slave(priv->slaves + i); } } else { if (netif_running(ndev)) cpsw_ndo_stop(ndev); - for_each_slave(priv, soft_reset_slave); } - pm_runtime_put_sync(&pdev->dev); - /* Select sleep pin state */ pinctrl_pm_select_sleep_state(&pdev->dev); @@ -2570,8 +2627,6 @@ static int cpsw_resume(struct device *dev) struct net_device *ndev = platform_get_drvdata(pdev); struct cpsw_priv *priv = netdev_priv(ndev); - pm_runtime_get_sync(&pdev->dev); - /* Select default pin state */ pinctrl_pm_select_default_state(&pdev->dev); diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c index bcd9e455457e..1c653ca7c316 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/drivers/net/ethernet/ti/davinci_cpdma.c @@ -21,7 +21,7 @@ #include <linux/dma-mapping.h> #include <linux/io.h> #include <linux/delay.h> - +#include <linux/genalloc.h> #include "davinci_cpdma.h" /* DMA Registers */ @@ -87,9 +87,8 @@ struct cpdma_desc_pool { void *cpumap; /* dma_alloc map */ int desc_size, mem_size; int num_desc, used_desc; - unsigned long *bitmap; struct device *dev; - spinlock_t lock; + struct gen_pool *gen_pool; }; enum cpdma_state { @@ -117,6 +116,7 @@ struct cpdma_chan { int chan_num; spinlock_t lock; int count; + u32 desc_num; u32 mask; cpdma_handler_fn handler; enum dma_data_direction dir; @@ -145,6 +145,19 @@ struct cpdma_chan { (directed << CPDMA_TO_PORT_SHIFT)); \ } while (0) +static void cpdma_desc_pool_destroy(struct cpdma_desc_pool *pool) +{ + if (!pool) + return; + + WARN_ON(pool->used_desc); + if (pool->cpumap) + dma_free_coherent(pool->dev, pool->mem_size, pool->cpumap, + pool->phys); + else + iounmap(pool->iomap); +} + /* * Utility constructs for a cpdma descriptor pool. Some devices (e.g. davinci * emac) have dedicated on-chip memory for these descriptors. Some other @@ -155,24 +168,25 @@ static struct cpdma_desc_pool * cpdma_desc_pool_create(struct device *dev, u32 phys, dma_addr_t hw_addr, int size, int align) { - int bitmap_size; struct cpdma_desc_pool *pool; + int ret; pool = devm_kzalloc(dev, sizeof(*pool), GFP_KERNEL); if (!pool) - goto fail; - - spin_lock_init(&pool->lock); + goto gen_pool_create_fail; pool->dev = dev; pool->mem_size = size; pool->desc_size = ALIGN(sizeof(struct cpdma_desc), align); pool->num_desc = size / pool->desc_size; - bitmap_size = (pool->num_desc / BITS_PER_LONG) * sizeof(long); - pool->bitmap = devm_kzalloc(dev, bitmap_size, GFP_KERNEL); - if (!pool->bitmap) - goto fail; + pool->gen_pool = devm_gen_pool_create(dev, ilog2(pool->desc_size), -1, + "cpdma"); + if (IS_ERR(pool->gen_pool)) { + dev_err(dev, "pool create failed %ld\n", + PTR_ERR(pool->gen_pool)); + goto gen_pool_create_fail; + } if (phys) { pool->phys = phys; @@ -185,24 +199,22 @@ cpdma_desc_pool_create(struct device *dev, u32 phys, dma_addr_t hw_addr, pool->phys = pool->hw_addr; /* assumes no IOMMU, don't use this value */ } - if (pool->iomap) - return pool; -fail: - return NULL; -} + if (!pool->iomap) + goto gen_pool_create_fail; -static void cpdma_desc_pool_destroy(struct cpdma_desc_pool *pool) -{ - if (!pool) - return; - - WARN_ON(pool->used_desc); - if (pool->cpumap) { - dma_free_coherent(pool->dev, pool->mem_size, pool->cpumap, - pool->phys); - } else { - iounmap(pool->iomap); + ret = gen_pool_add_virt(pool->gen_pool, (unsigned long)pool->iomap, + pool->phys, pool->mem_size, -1); + if (ret < 0) { + dev_err(dev, "pool add failed %d\n", ret); + goto gen_pool_add_virt_fail; } + + return pool; + +gen_pool_add_virt_fail: + cpdma_desc_pool_destroy(pool); +gen_pool_create_fail: + return NULL; } static inline dma_addr_t desc_phys(struct cpdma_desc_pool *pool, @@ -220,47 +232,23 @@ desc_from_phys(struct cpdma_desc_pool *pool, dma_addr_t dma) } static struct cpdma_desc __iomem * -cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc, bool is_rx) +cpdma_desc_alloc(struct cpdma_desc_pool *pool) { - unsigned long flags; - int index; - int desc_start; - int desc_end; struct cpdma_desc __iomem *desc = NULL; - spin_lock_irqsave(&pool->lock, flags); - - if (is_rx) { - desc_start = 0; - desc_end = pool->num_desc/2; - } else { - desc_start = pool->num_desc/2; - desc_end = pool->num_desc; - } - - index = bitmap_find_next_zero_area(pool->bitmap, - desc_end, desc_start, num_desc, 0); - if (index < desc_end) { - bitmap_set(pool->bitmap, index, num_desc); - desc = pool->iomap + pool->desc_size * index; + desc = (struct cpdma_desc __iomem *)gen_pool_alloc(pool->gen_pool, + pool->desc_size); + if (desc) pool->used_desc++; - } - spin_unlock_irqrestore(&pool->lock, flags); return desc; } static void cpdma_desc_free(struct cpdma_desc_pool *pool, struct cpdma_desc __iomem *desc, int num_desc) { - unsigned long flags, index; - - index = ((unsigned long)desc - (unsigned long)pool->iomap) / - pool->desc_size; - spin_lock_irqsave(&pool->lock, flags); - bitmap_clear(pool->bitmap, index, num_desc); + gen_pool_free(pool->gen_pool, (unsigned long)desc, pool->desc_size); pool->used_desc--; - spin_unlock_irqrestore(&pool->lock, flags); } struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params) @@ -516,6 +504,7 @@ struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num, chan->state = CPDMA_STATE_IDLE; chan->chan_num = chan_num; chan->handler = handler; + chan->desc_num = ctlr->pool->num_desc / 2; if (is_rx_chan(chan)) { chan->hdp = ctlr->params.rxhdp + offset; @@ -681,7 +670,13 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, goto unlock_ret; } - desc = cpdma_desc_alloc(ctlr->pool, 1, is_rx_chan(chan)); + if (chan->count >= chan->desc_num) { + chan->stats.desc_alloc_fail++; + ret = -ENOMEM; + goto unlock_ret; + } + + desc = cpdma_desc_alloc(ctlr->pool); if (!desc) { chan->stats.desc_alloc_fail++; ret = -ENOMEM; @@ -727,24 +722,16 @@ EXPORT_SYMBOL_GPL(cpdma_chan_submit); bool cpdma_check_free_tx_desc(struct cpdma_chan *chan) { - unsigned long flags; - int index; - bool ret; struct cpdma_ctlr *ctlr = chan->ctlr; struct cpdma_desc_pool *pool = ctlr->pool; + bool free_tx_desc; + unsigned long flags; - spin_lock_irqsave(&pool->lock, flags); - - index = bitmap_find_next_zero_area(pool->bitmap, - pool->num_desc, pool->num_desc/2, 1, 0); - - if (index < pool->num_desc) - ret = true; - else - ret = false; - - spin_unlock_irqrestore(&pool->lock, flags); - return ret; + spin_lock_irqsave(&chan->lock, flags); + free_tx_desc = (chan->count < chan->desc_num) && + gen_pool_avail(pool->gen_pool); + spin_unlock_irqrestore(&chan->lock, flags); + return free_tx_desc; } EXPORT_SYMBOL_GPL(cpdma_check_free_tx_desc); diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c index 4e7c9b9b042a..33df340db1f1 100644 --- a/drivers/net/ethernet/ti/davinci_mdio.c +++ b/drivers/net/ethernet/ti/davinci_mdio.c @@ -53,6 +53,10 @@ #define DEF_OUT_FREQ 2200000 /* 2.2 MHz */ +struct davinci_mdio_of_param { + int autosuspend_delay_ms; +}; + struct davinci_mdio_regs { u32 version; u32 control; @@ -90,19 +94,19 @@ static const struct mdio_platform_data default_pdata = { struct davinci_mdio_data { struct mdio_platform_data pdata; struct davinci_mdio_regs __iomem *regs; - spinlock_t lock; struct clk *clk; struct device *dev; struct mii_bus *bus; - bool suspended; + bool active_in_suspend; unsigned long access_time; /* jiffies */ /* Indicates that driver shouldn't modify phy_mask in case * if MDIO bus is registered from DT. */ bool skip_scan; + u32 clk_div; }; -static void __davinci_mdio_reset(struct davinci_mdio_data *data) +static void davinci_mdio_init_clk(struct davinci_mdio_data *data) { u32 mdio_in, div, mdio_out_khz, access_time; @@ -111,9 +115,7 @@ static void __davinci_mdio_reset(struct davinci_mdio_data *data) if (div > CONTROL_MAX_DIV) div = CONTROL_MAX_DIV; - /* set enable and clock divider */ - __raw_writel(div | CONTROL_ENABLE, &data->regs->control); - + data->clk_div = div; /* * One mdio transaction consists of: * 32 bits of preamble @@ -134,12 +136,23 @@ static void __davinci_mdio_reset(struct davinci_mdio_data *data) data->access_time = 1; } +static void davinci_mdio_enable(struct davinci_mdio_data *data) +{ + /* set enable and clock divider */ + __raw_writel(data->clk_div | CONTROL_ENABLE, &data->regs->control); +} + static int davinci_mdio_reset(struct mii_bus *bus) { struct davinci_mdio_data *data = bus->priv; u32 phy_mask, ver; + int ret; - __davinci_mdio_reset(data); + ret = pm_runtime_get_sync(data->dev); + if (ret < 0) { + pm_runtime_put_noidle(data->dev); + return ret; + } /* wait for scan logic to settle */ msleep(PHY_MAX_ADDR * data->access_time); @@ -150,7 +163,7 @@ static int davinci_mdio_reset(struct mii_bus *bus) (ver >> 8) & 0xff, ver & 0xff); if (data->skip_scan) - return 0; + goto done; /* get phy mask from the alive register */ phy_mask = __raw_readl(&data->regs->alive); @@ -165,6 +178,10 @@ static int davinci_mdio_reset(struct mii_bus *bus) } data->bus->phy_mask = phy_mask; +done: + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + return 0; } @@ -190,7 +207,7 @@ static inline int wait_for_user_access(struct davinci_mdio_data *data) * operation */ dev_warn(data->dev, "resetting idled controller\n"); - __davinci_mdio_reset(data); + davinci_mdio_enable(data); return -EAGAIN; } @@ -225,11 +242,10 @@ static int davinci_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg) if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK) return -EINVAL; - spin_lock(&data->lock); - - if (data->suspended) { - spin_unlock(&data->lock); - return -ENODEV; + ret = pm_runtime_get_sync(data->dev); + if (ret < 0) { + pm_runtime_put_noidle(data->dev); + return ret; } reg = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) | @@ -255,8 +271,8 @@ static int davinci_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg) break; } - spin_unlock(&data->lock); - + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); return ret; } @@ -270,11 +286,10 @@ static int davinci_mdio_write(struct mii_bus *bus, int phy_id, if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK) return -EINVAL; - spin_lock(&data->lock); - - if (data->suspended) { - spin_unlock(&data->lock); - return -ENODEV; + ret = pm_runtime_get_sync(data->dev); + if (ret < 0) { + pm_runtime_put_noidle(data->dev); + return ret; } reg = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) | @@ -295,9 +310,10 @@ static int davinci_mdio_write(struct mii_bus *bus, int phy_id, break; } - spin_unlock(&data->lock); + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); - return 0; + return ret; } #if IS_ENABLED(CONFIG_OF) @@ -320,6 +336,19 @@ static int davinci_mdio_probe_dt(struct mdio_platform_data *data, } #endif +#if IS_ENABLED(CONFIG_OF) +static const struct davinci_mdio_of_param of_cpsw_mdio_data = { + .autosuspend_delay_ms = 100, +}; + +static const struct of_device_id davinci_mdio_of_mtable[] = { + { .compatible = "ti,davinci_mdio", }, + { .compatible = "ti,cpsw-mdio", .data = &of_cpsw_mdio_data}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, davinci_mdio_of_mtable); +#endif + static int davinci_mdio_probe(struct platform_device *pdev) { struct mdio_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -328,6 +357,7 @@ static int davinci_mdio_probe(struct platform_device *pdev) struct resource *res; struct phy_device *phy; int ret, addr; + int autosuspend_delay_ms = -1; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -340,9 +370,22 @@ static int davinci_mdio_probe(struct platform_device *pdev) } if (dev->of_node) { - if (davinci_mdio_probe_dt(&data->pdata, pdev)) - data->pdata = default_pdata; + const struct of_device_id *of_id; + + ret = davinci_mdio_probe_dt(&data->pdata, pdev); + if (ret) + return ret; snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s", pdev->name); + + of_id = of_match_device(davinci_mdio_of_mtable, &pdev->dev); + if (of_id) { + const struct davinci_mdio_of_param *of_mdio_data; + + of_mdio_data = of_id->data; + if (of_mdio_data) + autosuspend_delay_ms = + of_mdio_data->autosuspend_delay_ms; + } } else { data->pdata = pdata ? (*pdata) : default_pdata; snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s-%x", @@ -356,26 +399,25 @@ static int davinci_mdio_probe(struct platform_device *pdev) data->bus->parent = dev; data->bus->priv = data; - pm_runtime_enable(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); data->clk = devm_clk_get(dev, "fck"); if (IS_ERR(data->clk)) { dev_err(dev, "failed to get device clock\n"); - ret = PTR_ERR(data->clk); - data->clk = NULL; - goto bail_out; + return PTR_ERR(data->clk); } dev_set_drvdata(dev, data); data->dev = dev; - spin_lock_init(&data->lock); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); data->regs = devm_ioremap_resource(dev, res); - if (IS_ERR(data->regs)) { - ret = PTR_ERR(data->regs); - goto bail_out; - } + if (IS_ERR(data->regs)) + return PTR_ERR(data->regs); + + davinci_mdio_init_clk(data); + + pm_runtime_set_autosuspend_delay(&pdev->dev, autosuspend_delay_ms); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); /* register the mii bus * Create PHYs from DT only in case if PHY child nodes are explicitly @@ -404,9 +446,8 @@ static int davinci_mdio_probe(struct platform_device *pdev) return 0; bail_out: - pm_runtime_put_sync(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); - return ret; } @@ -417,29 +458,47 @@ static int davinci_mdio_remove(struct platform_device *pdev) if (data->bus) mdiobus_unregister(data->bus); - pm_runtime_put_sync(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; } -#ifdef CONFIG_PM_SLEEP -static int davinci_mdio_suspend(struct device *dev) +#ifdef CONFIG_PM +static int davinci_mdio_runtime_suspend(struct device *dev) { struct davinci_mdio_data *data = dev_get_drvdata(dev); u32 ctrl; - spin_lock(&data->lock); - /* shutdown the scan state machine */ ctrl = __raw_readl(&data->regs->control); ctrl &= ~CONTROL_ENABLE; __raw_writel(ctrl, &data->regs->control); wait_for_idle(data); - data->suspended = true; - spin_unlock(&data->lock); - pm_runtime_put_sync(data->dev); + return 0; +} + +static int davinci_mdio_runtime_resume(struct device *dev) +{ + struct davinci_mdio_data *data = dev_get_drvdata(dev); + + davinci_mdio_enable(data); + return 0; +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int davinci_mdio_suspend(struct device *dev) +{ + struct davinci_mdio_data *data = dev_get_drvdata(dev); + int ret = 0; + + data->active_in_suspend = !pm_runtime_status_suspended(dev); + if (data->active_in_suspend) + ret = pm_runtime_force_suspend(dev); + if (ret < 0) + return ret; /* Select sleep pin state */ pinctrl_pm_select_sleep_state(dev); @@ -454,31 +513,19 @@ static int davinci_mdio_resume(struct device *dev) /* Select default pin state */ pinctrl_pm_select_default_state(dev); - pm_runtime_get_sync(data->dev); - - spin_lock(&data->lock); - /* restart the scan state machine */ - __davinci_mdio_reset(data); - - data->suspended = false; - spin_unlock(&data->lock); + if (data->active_in_suspend) + pm_runtime_force_resume(dev); return 0; } #endif static const struct dev_pm_ops davinci_mdio_pm_ops = { + SET_RUNTIME_PM_OPS(davinci_mdio_runtime_suspend, + davinci_mdio_runtime_resume, NULL) SET_LATE_SYSTEM_SLEEP_PM_OPS(davinci_mdio_suspend, davinci_mdio_resume) }; -#if IS_ENABLED(CONFIG_OF) -static const struct of_device_id davinci_mdio_of_mtable[] = { - { .compatible = "ti,davinci_mdio", }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, davinci_mdio_of_mtable); -#endif - static struct platform_driver davinci_mdio_driver = { .driver = { .name = "davinci_mdio", diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 9e314b791150..33ab3345d333 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -291,6 +291,17 @@ config FSL_UCC_HDLC To compile this driver as a module, choose M here: the module will be called fsl_ucc_hdlc. +config SLIC_DS26522 + tristate "Slic Maxim ds26522 card support" + depends on SPI + depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE + help + This module initializes and configures the slic maxim card + in T1 or E1 mode. + + To compile this driver as a module, choose M here: the + module will be called slic_ds26522. + config DSCC4_PCISYNC bool "Etinc PCISYNC features" depends on DSCC4 diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index 25fec40d4353..73c2326603fc 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_PCI200SYN) += pci200syn.o obj-$(CONFIG_PC300TOO) += pc300too.o obj-$(CONFIG_IXP4XX_HSS) += ixp4xx_hss.o obj-$(CONFIG_FSL_UCC_HDLC) += fsl_ucc_hdlc.o +obj-$(CONFIG_SLIC_DS26522) += slic_ds26522.o clean-files := wanxlfw.inc $(obj)/wanxl.o: $(obj)/wanxlfw.inc diff --git a/drivers/net/wan/slic_ds26522.c b/drivers/net/wan/slic_ds26522.c new file mode 100644 index 000000000000..d06a887a2352 --- /dev/null +++ b/drivers/net/wan/slic_ds26522.c @@ -0,0 +1,255 @@ +/* + * drivers/net/wan/slic_ds26522.c + * + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * + * Author:Zhao Qiang<qiang.zhao@nxp.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/bitrev.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/kthread.h> +#include <linux/spi/spi.h> +#include <linux/wait.h> +#include <linux/param.h> +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/io.h> +#include "slic_ds26522.h" + +#define DRV_NAME "ds26522" + +#define SLIC_TRANS_LEN 1 +#define SLIC_TWO_LEN 2 +#define SLIC_THREE_LEN 3 + +static struct spi_device *g_spi; + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Zhao Qiang<B45475@freescale.com>"); + +/* the read/write format of address is + * w/r|A13|A12|A11|A10|A9|A8|A7|A6|A5|A4|A3|A2|A1|A0|x + */ +static void slic_write(struct spi_device *spi, u16 addr, + u8 data) +{ + u8 temp[3]; + + addr = bitrev16(addr) >> 1; + data = bitrev8(data); + temp[0] = (u8)((addr >> 8) & 0x7f); + temp[1] = (u8)(addr & 0xfe); + temp[2] = data; + + /* write spi addr and value */ + spi_write(spi, &temp[0], SLIC_THREE_LEN); +} + +static u8 slic_read(struct spi_device *spi, u16 addr) +{ + u8 temp[2]; + u8 data; + + addr = bitrev16(addr) >> 1; + temp[0] = (u8)(((addr >> 8) & 0x7f) | 0x80); + temp[1] = (u8)(addr & 0xfe); + + spi_write_then_read(spi, &temp[0], SLIC_TWO_LEN, &data, + SLIC_TRANS_LEN); + + data = bitrev8(data); + return data; +} + +static bool get_slic_product_code(struct spi_device *spi) +{ + u8 device_id; + + device_id = slic_read(spi, DS26522_IDR_ADDR); + if ((device_id & 0xf8) == 0x68) + return true; + else + return false; +} + +static void ds26522_e1_spec_config(struct spi_device *spi) +{ + /* Receive E1 Mode, Framer Disabled */ + slic_write(spi, DS26522_RMMR_ADDR, DS26522_RMMR_E1); + + /* Transmit E1 Mode, Framer Disable */ + slic_write(spi, DS26522_TMMR_ADDR, DS26522_TMMR_E1); + + /* Receive E1 Mode Framer Enable */ + slic_write(spi, DS26522_RMMR_ADDR, + slic_read(spi, DS26522_RMMR_ADDR) | DS26522_RMMR_FRM_EN); + + /* Transmit E1 Mode Framer Enable */ + slic_write(spi, DS26522_TMMR_ADDR, + slic_read(spi, DS26522_TMMR_ADDR) | DS26522_TMMR_FRM_EN); + + /* RCR1, receive E1 B8zs & ESF */ + slic_write(spi, DS26522_RCR1_ADDR, + DS26522_RCR1_E1_HDB3 | DS26522_RCR1_E1_CCS); + + /* RSYSCLK=2.048MHz, RSYNC-Output */ + slic_write(spi, DS26522_RIOCR_ADDR, + DS26522_RIOCR_2048KHZ | DS26522_RIOCR_RSIO_OUT); + + /* TCR1 Transmit E1 b8zs */ + slic_write(spi, DS26522_TCR1_ADDR, DS26522_TCR1_TB8ZS); + + /* TSYSCLK=2.048MHz, TSYNC-Output */ + slic_write(spi, DS26522_TIOCR_ADDR, + DS26522_TIOCR_2048KHZ | DS26522_TIOCR_TSIO_OUT); + + /* Set E1TAF */ + slic_write(spi, DS26522_E1TAF_ADDR, DS26522_E1TAF_DEFAULT); + + /* Set E1TNAF register */ + slic_write(spi, DS26522_E1TNAF_ADDR, DS26522_E1TNAF_DEFAULT); + + /* Receive E1 Mode Framer Enable & init Done */ + slic_write(spi, DS26522_RMMR_ADDR, slic_read(spi, DS26522_RMMR_ADDR) | + DS26522_RMMR_INIT_DONE); + + /* Transmit E1 Mode Framer Enable & init Done */ + slic_write(spi, DS26522_TMMR_ADDR, slic_read(spi, DS26522_TMMR_ADDR) | + DS26522_TMMR_INIT_DONE); + + /* Configure LIU E1 mode */ + slic_write(spi, DS26522_LTRCR_ADDR, DS26522_LTRCR_E1); + + /* E1 Mode default 75 ohm w/Transmit Impedance Matlinking */ + slic_write(spi, DS26522_LTITSR_ADDR, + DS26522_LTITSR_TLIS_75OHM | DS26522_LTITSR_LBOS_75OHM); + + /* E1 Mode default 75 ohm Long Haul w/Receive Impedance Matlinking */ + slic_write(spi, DS26522_LRISMR_ADDR, + DS26522_LRISMR_75OHM | DS26522_LRISMR_MAX); + + /* Enable Transmit output */ + slic_write(spi, DS26522_LMCR_ADDR, DS26522_LMCR_TE); +} + +static int slic_ds26522_init_configure(struct spi_device *spi) +{ + u16 addr; + + /* set clock */ + slic_write(spi, DS26522_GTCCR_ADDR, DS26522_GTCCR_BPREFSEL_REFCLKIN | + DS26522_GTCCR_BFREQSEL_2048KHZ | + DS26522_GTCCR_FREQSEL_2048KHZ); + slic_write(spi, DS26522_GTCR2_ADDR, DS26522_GTCR2_TSSYNCOUT); + slic_write(spi, DS26522_GFCR_ADDR, DS26522_GFCR_BPCLK_2048KHZ); + + /* set gtcr */ + slic_write(spi, DS26522_GTCR1_ADDR, DS26522_GTCR1); + + /* Global LIU Software Reset Register */ + slic_write(spi, DS26522_GLSRR_ADDR, DS26522_GLSRR_RESET); + + /* Global Framer and BERT Software Reset Register */ + slic_write(spi, DS26522_GFSRR_ADDR, DS26522_GFSRR_RESET); + + usleep_range(100, 120); + + slic_write(spi, DS26522_GLSRR_ADDR, DS26522_GLSRR_NORMAL); + slic_write(spi, DS26522_GFSRR_ADDR, DS26522_GFSRR_NORMAL); + + /* Perform RX/TX SRESET,Reset receiver */ + slic_write(spi, DS26522_RMMR_ADDR, DS26522_RMMR_SFTRST); + + /* Reset tranceiver */ + slic_write(spi, DS26522_TMMR_ADDR, DS26522_TMMR_SFTRST); + + usleep_range(100, 120); + + /* Zero all Framer Registers */ + for (addr = DS26522_RF_ADDR_START; addr <= DS26522_RF_ADDR_END; + addr++) + slic_write(spi, addr, 0); + + for (addr = DS26522_TF_ADDR_START; addr <= DS26522_TF_ADDR_END; + addr++) + slic_write(spi, addr, 0); + + for (addr = DS26522_LIU_ADDR_START; addr <= DS26522_LIU_ADDR_END; + addr++) + slic_write(spi, addr, 0); + + for (addr = DS26522_BERT_ADDR_START; addr <= DS26522_BERT_ADDR_END; + addr++) + slic_write(spi, addr, 0); + + /* setup ds26522 for E1 specification */ + ds26522_e1_spec_config(spi); + + slic_write(spi, DS26522_GTCR1_ADDR, 0x00); + + return 0; +} + +static int slic_ds26522_remove(struct spi_device *spi) +{ + pr_info("DS26522 module uninstalled\n"); + return 0; +} + +static int slic_ds26522_probe(struct spi_device *spi) +{ + int ret = 0; + + g_spi = spi; + spi->bits_per_word = 8; + + if (!get_slic_product_code(spi)) + return ret; + + ret = slic_ds26522_init_configure(spi); + if (ret == 0) + pr_info("DS26522 cs%d configurated\n", spi->chip_select); + + return ret; +} + +static const struct of_device_id slic_ds26522_match[] = { + { + .compatible = "maxim,ds26522", + }, + {}, +}; + +static struct spi_driver slic_ds26522_driver = { + .driver = { + .name = "ds26522", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + .of_match_table = slic_ds26522_match, + }, + .probe = slic_ds26522_probe, + .remove = slic_ds26522_remove, +}; + +static int __init slic_ds26522_init(void) +{ + return spi_register_driver(&slic_ds26522_driver); +} + +static void __exit slic_ds26522_exit(void) +{ + spi_unregister_driver(&slic_ds26522_driver); +} + +module_init(slic_ds26522_init); +module_exit(slic_ds26522_exit); diff --git a/drivers/net/wan/slic_ds26522.h b/drivers/net/wan/slic_ds26522.h new file mode 100644 index 000000000000..22aa0ecbd9fd --- /dev/null +++ b/drivers/net/wan/slic_ds26522.h @@ -0,0 +1,134 @@ +/* + * drivers/tdm/line_ctrl/slic_ds26522.h + * + * Copyright 2016 Freescale Semiconductor, Inc. + * + * Author: Zhao Qiang <B45475@freescale.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#define DS26522_RF_ADDR_START 0x00 +#define DS26522_RF_ADDR_END 0xef +#define DS26522_GLB_ADDR_START 0xf0 +#define DS26522_GLB_ADDR_END 0xff +#define DS26522_TF_ADDR_START 0x100 +#define DS26522_TF_ADDR_END 0x1ef +#define DS26522_LIU_ADDR_START 0x1000 +#define DS26522_LIU_ADDR_END 0x101f +#define DS26522_TEST_ADDR_START 0x1008 +#define DS26522_TEST_ADDR_END 0x101f +#define DS26522_BERT_ADDR_START 0x1100 +#define DS26522_BERT_ADDR_END 0x110f + +#define DS26522_RMMR_ADDR 0x80 +#define DS26522_RCR1_ADDR 0x81 +#define DS26522_RCR3_ADDR 0x83 +#define DS26522_RIOCR_ADDR 0x84 + +#define DS26522_GTCR1_ADDR 0xf0 +#define DS26522_GFCR_ADDR 0xf1 +#define DS26522_GTCR2_ADDR 0xf2 +#define DS26522_GTCCR_ADDR 0xf3 +#define DS26522_GLSRR_ADDR 0xf5 +#define DS26522_GFSRR_ADDR 0xf6 +#define DS26522_IDR_ADDR 0xf8 + +#define DS26522_E1TAF_ADDR 0x164 +#define DS26522_E1TNAF_ADDR 0x165 +#define DS26522_TMMR_ADDR 0x180 +#define DS26522_TCR1_ADDR 0x181 +#define DS26522_TIOCR_ADDR 0x184 + +#define DS26522_LTRCR_ADDR 0x1000 +#define DS26522_LTITSR_ADDR 0x1001 +#define DS26522_LMCR_ADDR 0x1002 +#define DS26522_LRISMR_ADDR 0x1007 + +#define MAX_NUM_OF_CHANNELS 8 +#define PQ_MDS_8E1T1_BRD_REV 0x00 +#define PQ_MDS_8E1T1_PLD_REV 0x00 + +#define DS26522_GTCCR_BPREFSEL_REFCLKIN 0xa0 +#define DS26522_GTCCR_BFREQSEL_1544KHZ 0x08 +#define DS26522_GTCCR_FREQSEL_1544KHZ 0x04 +#define DS26522_GTCCR_BFREQSEL_2048KHZ 0x00 +#define DS26522_GTCCR_FREQSEL_2048KHZ 0x00 + +#define DS26522_GFCR_BPCLK_2048KHZ 0x00 + +#define DS26522_GTCR2_TSSYNCOUT 0x02 +#define DS26522_GTCR1 0x00 + +#define DS26522_GFSRR_RESET 0x01 +#define DS26522_GFSRR_NORMAL 0x00 + +#define DS26522_GLSRR_RESET 0x01 +#define DS26522_GLSRR_NORMAL 0x00 + +#define DS26522_RMMR_SFTRST 0x02 +#define DS26522_RMMR_FRM_EN 0x80 +#define DS26522_RMMR_INIT_DONE 0x40 +#define DS26522_RMMR_T1 0x00 +#define DS26522_RMMR_E1 0x01 + +#define DS26522_E1TAF_DEFAULT 0x1b +#define DS26522_E1TNAF_DEFAULT 0x40 + +#define DS26522_TMMR_SFTRST 0x02 +#define DS26522_TMMR_FRM_EN 0x80 +#define DS26522_TMMR_INIT_DONE 0x40 +#define DS26522_TMMR_T1 0x00 +#define DS26522_TMMR_E1 0x01 + +#define DS26522_RCR1_T1_SYNCT 0x80 +#define DS26522_RCR1_T1_RB8ZS 0x40 +#define DS26522_RCR1_T1_SYNCC 0x08 + +#define DS26522_RCR1_E1_HDB3 0x40 +#define DS26522_RCR1_E1_CCS 0x20 + +#define DS26522_RIOCR_1544KHZ 0x00 +#define DS26522_RIOCR_2048KHZ 0x10 +#define DS26522_RIOCR_RSIO_OUT 0x00 + +#define DS26522_RCR3_FLB 0x01 + +#define DS26522_TIOCR_1544KHZ 0x00 +#define DS26522_TIOCR_2048KHZ 0x10 +#define DS26522_TIOCR_TSIO_OUT 0x04 + +#define DS26522_TCR1_TB8ZS 0x04 + +#define DS26522_LTRCR_T1 0x02 +#define DS26522_LTRCR_E1 0x00 + +#define DS26522_LTITSR_TLIS_75OHM 0x00 +#define DS26522_LTITSR_LBOS_75OHM 0x00 +#define DS26522_LTITSR_TLIS_100OHM 0x10 +#define DS26522_LTITSR_TLIS_0DB_CSU 0x00 + +#define DS26522_LRISMR_75OHM 0x00 +#define DS26522_LRISMR_100OHM 0x10 +#define DS26522_LRISMR_MAX 0x03 + +#define DS26522_LMCR_TE 0x01 + +enum line_rate { + LINE_RATE_T1, /* T1 line rate (1.544 Mbps) */ + LINE_RATE_E1 /* E1 line rate (2.048 Mbps) */ +}; + +enum tdm_trans_mode { + NORMAL = 0, + FRAMER_LB +}; + +enum card_support_type { + LM_CARD = 0, + DS26522_CARD, + NO_CARD +}; diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index b3bec3aaa45d..bc07ad30c9bf 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -74,6 +74,7 @@ config OF_NET config OF_MDIO def_tristate PHYLIB depends on PHYLIB + select FIXED_PHY help OpenFirmware MDIO bus (Ethernet PHY) accessors diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index de68707a99c7..e2b50bc12f23 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -361,7 +361,6 @@ struct phy_device *of_phy_attach(struct net_device *dev, } EXPORT_SYMBOL(of_phy_attach); -#if IS_ENABLED(CONFIG_FIXED_PHY) /* * of_phy_is_fixed_link() and of_phy_register_fixed_link() must * support two DT bindings: @@ -451,4 +450,3 @@ int of_phy_register_fixed_link(struct device_node *np) return -ENODEV; } EXPORT_SYMBOL(of_phy_register_fixed_link); -#endif diff --git a/include/linux/of_mdio.h b/include/linux/of_mdio.h index 6c8cb9aa4c00..4b04587d0441 100644 --- a/include/linux/of_mdio.h +++ b/include/linux/of_mdio.h @@ -25,6 +25,8 @@ struct phy_device *of_phy_attach(struct net_device *dev, extern struct mii_bus *of_mdio_find_bus(struct device_node *mdio_np); extern int of_mdio_parse_addr(struct device *dev, const struct device_node *np); +extern int of_phy_register_fixed_link(struct device_node *np); +extern bool of_phy_is_fixed_link(struct device_node *np); #else /* CONFIG_OF */ static inline int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) @@ -67,12 +69,6 @@ static inline int of_mdio_parse_addr(struct device *dev, { return -ENOSYS; } -#endif /* CONFIG_OF */ - -#if defined(CONFIG_OF) && IS_ENABLED(CONFIG_FIXED_PHY) -extern int of_phy_register_fixed_link(struct device_node *np); -extern bool of_phy_is_fixed_link(struct device_node *np); -#else static inline int of_phy_register_fixed_link(struct device_node *np) { return -ENOSYS; diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index 0507dbfbf63c..705840e0438f 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -141,5 +141,6 @@ struct plat_stmmacenet_data { struct stmmac_axi *axi; int has_gmac4; bool tso_en; + int mac_port_sel_speed; }; #endif diff --git a/include/uapi/linux/inet_diag.h b/include/uapi/linux/inet_diag.h index a16643705669..abbd1dc5d683 100644 --- a/include/uapi/linux/inet_diag.h +++ b/include/uapi/linux/inet_diag.h @@ -72,6 +72,7 @@ enum { INET_DIAG_BC_AUTO, INET_DIAG_BC_S_COND, INET_DIAG_BC_D_COND, + INET_DIAG_BC_DEV_COND, /* u32 ifindex */ }; struct inet_diag_hostcond { diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c index 67a4a36febd1..3408ed51b611 100644 --- a/net/caif/chnl_net.c +++ b/net/caif/chnl_net.c @@ -13,7 +13,6 @@ #include <linux/module.h> #include <linux/netdevice.h> #include <linux/if_ether.h> -#include <linux/moduleparam.h> #include <linux/ip.h> #include <linux/sched.h> #include <linux/sockios.h> diff --git a/net/core/utils.c b/net/core/utils.c index 3d17ca8b4744..cf5622b9ccc4 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -133,7 +133,7 @@ int in4_pton(const char *src, int srclen, s = src; d = dbuf; i = 0; - while(1) { + while (1) { int c; c = xdigit2bin(srclen > 0 ? *s : '\0', delim); if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) { @@ -283,11 +283,11 @@ cont: i = 15; d--; if (dc) { - while(d >= dc) + while (d >= dc) dst[i--] = *d--; - while(i >= dc - dbuf) + while (i >= dc - dbuf) dst[i--] = 0; - while(i >= 0) + while (i >= 0) dst[i--] = *d--; } else memcpy(dst, dbuf, sizeof(dbuf)); diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 25af1243649b..38c2c47fe0e8 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -44,6 +44,7 @@ struct inet_diag_entry { u16 dport; u16 family; u16 userlocks; + u32 ifindex; }; static DEFINE_MUTEX(inet_diag_table_mutex); @@ -571,6 +572,14 @@ static int inet_diag_bc_run(const struct nlattr *_bc, yes = 0; break; } + case INET_DIAG_BC_DEV_COND: { + u32 ifindex; + + ifindex = *((const u32 *)(op + 1)); + if (ifindex != entry->ifindex) + yes = 0; + break; + } } if (yes) { @@ -613,6 +622,7 @@ int inet_diag_bc_sk(const struct nlattr *bc, struct sock *sk) entry_fill_addrs(&entry, sk); entry.sport = inet->inet_num; entry.dport = ntohs(inet->inet_dport); + entry.ifindex = sk->sk_bound_dev_if; entry.userlocks = sk_fullsock(sk) ? sk->sk_userlocks : 0; return inet_diag_bc_run(bc, &entry); @@ -636,6 +646,17 @@ static int valid_cc(const void *bc, int len, int cc) return 0; } +/* data is u32 ifindex */ +static bool valid_devcond(const struct inet_diag_bc_op *op, int len, + int *min_len) +{ + /* Check ifindex space. */ + *min_len += sizeof(u32); + if (len < *min_len) + return false; + + return true; +} /* Validate an inet_diag_hostcond. */ static bool valid_hostcond(const struct inet_diag_bc_op *op, int len, int *min_len) @@ -700,6 +721,10 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) if (!valid_hostcond(bc, len, &min_len)) return -EINVAL; break; + case INET_DIAG_BC_DEV_COND: + if (!valid_devcond(bc, len, &min_len)) + return -EINVAL; + break; case INET_DIAG_BC_S_GE: case INET_DIAG_BC_S_LE: case INET_DIAG_BC_D_GE: diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index ccca8ca4c722..6eac3d880048 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -487,10 +487,14 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, skb = segs; segs = segs->next; - if (!(skb = skb_unshare(skb, GFP_ATOMIC)) || - (skb->ip_summed == CHECKSUM_PARTIAL && - skb_checksum_help(skb))) { - rc = qdisc_drop(skb, sch, to_free); + skb = skb_unshare(skb, GFP_ATOMIC); + if (unlikely(!skb)) { + qdisc_qstats_drop(sch); + goto finish_segs; + } + if (skb->ip_summed == CHECKSUM_PARTIAL && + skb_checksum_help(skb)) { + qdisc_drop(skb, sch, to_free); goto finish_segs; } diff --git a/net/tipc/discover.c b/net/tipc/discover.c index ad9d477cc242..6b109a808d4c 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -135,9 +135,12 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb, u16 caps = msg_node_capabilities(hdr); bool respond = false; bool dupl_addr = false; + int err; - bearer->media->msg2addr(bearer, &maddr, msg_media_addr(hdr)); + err = bearer->media->msg2addr(bearer, &maddr, msg_media_addr(hdr)); kfree_skb(skb); + if (err) + return; /* Ensure message from node is valid and communication is permitted */ if (net_id != tn->net_id) diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index c9cf2be3674a..b016c011970b 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -63,7 +63,7 @@ */ struct udp_media_addr { __be16 proto; - __be16 udp_port; + __be16 port; union { struct in_addr ipv4; struct in6_addr ipv6; @@ -108,9 +108,9 @@ static int tipc_udp_addr2str(struct tipc_media_addr *a, char *buf, int size) struct udp_media_addr *ua = (struct udp_media_addr *)&a->value; if (ntohs(ua->proto) == ETH_P_IP) - snprintf(buf, size, "%pI4:%u", &ua->ipv4, ntohs(ua->udp_port)); + snprintf(buf, size, "%pI4:%u", &ua->ipv4, ntohs(ua->port)); else if (ntohs(ua->proto) == ETH_P_IPV6) - snprintf(buf, size, "%pI6:%u", &ua->ipv6, ntohs(ua->udp_port)); + snprintf(buf, size, "%pI6:%u", &ua->ipv6, ntohs(ua->port)); else pr_err("Invalid UDP media address\n"); return 0; @@ -178,8 +178,8 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb, skb->dev = rt->dst.dev; ttl = ip4_dst_hoplimit(&rt->dst); udp_tunnel_xmit_skb(rt, ub->ubsock->sk, skb, src->ipv4.s_addr, - dst->ipv4.s_addr, 0, ttl, 0, src->udp_port, - dst->udp_port, false, true); + dst->ipv4.s_addr, 0, ttl, 0, src->port, + dst->port, false, true); #if IS_ENABLED(CONFIG_IPV6) } else { struct dst_entry *ndst; @@ -196,8 +196,8 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb, ttl = ip6_dst_hoplimit(ndst); err = udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb, ndst->dev, &src->ipv6, - &dst->ipv6, 0, ttl, 0, src->udp_port, - dst->udp_port, false); + &dst->ipv6, 0, ttl, 0, src->port, + dst->port, false); #endif } return err; @@ -292,12 +292,12 @@ err: ip4 = (struct sockaddr_in *)&sa_local; local->proto = htons(ETH_P_IP); - local->udp_port = ip4->sin_port; + local->port = ip4->sin_port; local->ipv4.s_addr = ip4->sin_addr.s_addr; ip4 = (struct sockaddr_in *)&sa_remote; remote->proto = htons(ETH_P_IP); - remote->udp_port = ip4->sin_port; + remote->port = ip4->sin_port; remote->ipv4.s_addr = ip4->sin_addr.s_addr; return 0; @@ -312,13 +312,13 @@ err: return -EINVAL; local->proto = htons(ETH_P_IPV6); - local->udp_port = ip6->sin6_port; + local->port = ip6->sin6_port; memcpy(&local->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr)); ub->ifindex = ip6->sin6_scope_id; ip6 = (struct sockaddr_in6 *)&sa_remote; remote->proto = htons(ETH_P_IPV6); - remote->udp_port = ip6->sin6_port; + remote->port = ip6->sin6_port; memcpy(&remote->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr)); return 0; #endif @@ -386,7 +386,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, err = -EAFNOSUPPORT; goto err; } - udp_conf.local_udp_port = local.udp_port; + udp_conf.local_udp_port = local.port; err = udp_sock_create(net, &udp_conf, &ub->ubsock); if (err) goto err; |