lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 25 Apr 2019 07:06:43 +0000
From:   "Voon, Weifeng" <weifeng.voon@...el.com>
To:     "David S. Miller" <davem@...emloft.net>
CC:     "netdev@...r.kernel.org" <netdev@...r.kernel.org>,
        "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
        "Ong, Boon Leong" <boon.leong.ong@...el.com>,
        "Kweh, Hock Leong" <hock.leong.kweh@...el.com>,
        Florian Fainelli <f.fainelli@...il.com>,
        "Andrew Lunn" <andrew@...n.ch>,
        Maxime Coquelin <mcoquelin.stm32@...il.com>,
        "Giuseppe Cavallaro" <peppe.cavallaro@...com>,
        Jose Abreu <joabreu@...opsys.com>,
        "Voon, Weifeng" <weifeng.voon@...el.com>
Subject: RE: [PATCH 4/7] net: stmmac: introducing support for DWC xPCS logics

> From: Ong Boon Leong <boon.leong.ong@...el.com>
> 
> xPCS is DWC Ethernet Physical Coding Sublayer that may be integrated into a
> GbE controller that uses DWC EQoS MAC controller. An example of HW
> configuration is shown below:-
> 
>   <-----------------GBE Controller---------->|<--External PHY chip-->
> 
>   +----------+         +----+    +---+               +--------------+
>   |   EQoS   | <-GMII->|xPCS|<-->|L1 | <-- SGMII --> | External GbE |
>   |   MAC    |         |    |    |PHY|               | PHY Chip     |
>   +----------+         +----+    +---+               +--------------+
>          ^               ^                                  ^
>          |               |                                  |
>          +---------------------MDIO-------------------------+
> 
> xPCS is a Clause-45 MDIO Manageable Device (MMD) and we need a way to
> differentiate it from external PHY chip that is discovered over MDIO.
> Therefore, xpcs_phy_addr is introduced in stmmac platform data
> (plat_stmmacenet_data) for differentiating xPCS from 'phy_addr' that
> belongs to external PHY.
> 
> Basic functionalities for initializing xPCS and configuring auto negotiation (AN),
> loopback, link status, AN advertisement and Link Partner ability are
> implemented.
> 
> xPCS interrupt handling for C37 AN complete is also implemented.
> 
> Tested-by: Kweh Hock Leong <hock.leong.kweh@...el.com>
> Reviewed-by: Chuah Kim Tatt <kim.tatt.chuah@...el.com>
> Reviewed-by: Voon Weifeng <weifeng.voon@...el.com>
> Reviewed-by: Kweh Hock Leong <hock.leong.kweh@...el.com>
> Reviewed-by: Baoli Zhang <baoli.zhang@...el.com>
> Signed-off-by: Ong Boon Leong <boon.leong.ong@...el.com>
> ---
>  drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h | 288
> ++++++++++++++++++++++++++
>  drivers/net/ethernet/stmicro/stmmac/hwif.h    |  17 ++
>  include/linux/stmmac.h                        |   1 +
>  3 files changed, 306 insertions(+)
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
> b/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
> new file mode 100644
> index 0000000..446b714
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
> @@ -0,0 +1,288 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* dw_xpcs.h: DWC Ethernet Physical Coding Sublayer Header
> + *
> + * Copyright (c) 2019, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> +it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but
> +WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY
> +or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> +License for
> + * more details.
> + */
> +#ifndef __DW_XPCS_H__
> +#define __DW_XPCS_H__
> +
> +#include <linux/mdio.h>
> +#include <linux/bitops.h>
> +#include "stmmac.h"
> +
> +/* XPCS Control & MII MMD Device Addresses */
> +#define XPCS_MDIO_CONTROL_MMD	MDIO_MMD_VEND1
> +#define XPCS_MDIO_MII_MMD	MDIO_MMD_VEND2
> +
> +/* Control MMD register offsets */
> +#define MDIO_CONTROL_MMD_CTRL		0x9	/* Control */
> +
> +/* Control MMD Control defines */
> +#define MDIO_CONTROL_MMD_CTRL_MII_MMD_EN	1 /* MII MMD
> Enable */
> +
> +/* MII MMD registers offsets */
> +#define MDIO_MII_MMD_CTRL		0x0	/* Control */
> +#define MDIO_MII_MMD_ADV		0x4	/* AN Advertisement
> */
> +#define MDIO_MII_MMD_LPA		0x5	/* Link Partner Ability
> */
> +#define MDIO_MII_MMD_DIGITAL_CTRL_1	0x8000	/* Digital Control 1 */
> +#define MDIO_MII_MMD_AN_CTRL		0x8001	/* AN Control */
> +#define MDIO_MII_MMD_AN_STAT		0x8002	/* AN Status */
> +
> +/* MII MMD Control defines */
> +#define MDIO_MII_MMD_CTRL_ANE		BIT(12)	/* AN Enable */
> +#define MDIO_MII_MMD_CTRL_LBE		BIT(14)	/* Loopback Enable
> */
> +#define MDIO_MII_MMD_CTRL_RANE		BIT(9)	/* Restart AN
> */
> +
> +/* MII MMD AN Advertisement & Link Partner Ability */
> +#define MDIO_MII_MMD_HD			BIT(6)	/* Half duplex
> */
> +#define MDIO_MII_MMD_FD			BIT(5)	/* Full duplex
> */
> +#define MDIO_MII_MMD_PSE_SHIFT		7	/* Pause
> Ability shift */
> +#define MDIO_MII_MMD_PSE	GENMASK(8, 7)	/* Pause
> Ability */
> +
> +/* MII MMD Digital Control 1 defines */
> +#define MDIO_MII_MMD_DIGI_CTRL_1_SGMII_PHY_MD	BIT(0) /*
> SGMII PHY mode */
> +
> +/* MII MMD AN Control defines */
> +#define MDIO_MII_MMD_AN_CTRL_TX_CONFIG_SHIFT	3 /* TX Config
> shift */
> +#define AN_CTRL_TX_CONF_PHY_SIDE_SGMII		0x1 /* PHY
> side SGMII mode */
> +#define AN_CTRL_TX_CONF_MAC_SIDE_SGMII		0x0 /* MAC
> side SGMII mode */
> +#define MDIO_MII_MMD_AN_CTRL_PCS_MD_SHIFT	1  /* PCS Mode shift
> */
> +#define MDIO_MII_MMD_AN_CTRL_PCS_MD	GENMASK(2, 1) /*
> PCS Mode */
> +#define AN_CTRL_PCS_MD_C37_1000BASEX	0x0	/* C37 AN for
> 1000BASE-X */
> +#define AN_CTRL_PCS_MD_C37_SGMII	0x2	/* C37 AN for SGMII
> */
> +#define MDIO_MII_MMD_AN_CTRL_AN_INTR_EN	BIT(0)	/* AN
> Complete Intr Enable */
> +
> +/* MII MMD AN Status defines for C37 AN SGMII Status */
> +#define AN_STAT_C37_AN_CMPLT		BIT(0)	/* AN Complete Intr
> */
> +#define AN_STAT_C37_AN_FD		BIT(1)	/* Full Duplex */
> +#define AN_STAT_C37_AN_SPEED_SHIFT	2	/* AN Speed shift */
> +#define AN_STAT_C37_AN_SPEED		GENMASK(3, 2)	/* AN
> Speed */
> +#define AN_STAT_C37_AN_10MBPS		0x0	/* 10 Mbps */
> +#define AN_STAT_C37_AN_100MBPS		0x1	/* 100 Mbps */
> +#define AN_STAT_C37_AN_1000MBPS		0x2	/* 1000 Mbps
> */
> +#define AN_STAT_C37_AN_LNKSTS		BIT(4)	/* Link Status */
> +
> +/**
> + * dw_xpcs_init - To initialize xPCS
> + * @ndev: network device pointer
> + * @mode: PCS mode
> + * Description: this is to initialize xPCS  */ static inline void
> +dw_xpcs_init(struct net_device *ndev, int pcs_mode) {
> +	struct stmmac_priv *priv = netdev_priv(ndev);
> +	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
> +
> +	/* Set SGMII PHY mode control */
> +	u16 phydata = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +				    (MII_ADDR_C45 |
> +				     (XPCS_MDIO_MII_MMD <<
> +				      MII_DEVADDR_C45_SHIFT) |
> +				     MDIO_MII_MMD_DIGITAL_CTRL_1));
> +
> +	phydata |= MDIO_MII_MMD_DIGI_CTRL_1_SGMII_PHY_MD;
> +
> +	mdiobus_write(priv->mii, xpcs_phy_addr,
> +		      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
> +		       MII_DEVADDR_C45_SHIFT) |
> MDIO_MII_MMD_DIGITAL_CTRL_1),
> +		      (int)phydata);
> +
> +	/* Set PHY side SGMII, PCS Mode & Enable C37 AN complete
> interrupt */
> +	phydata = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +				    (MII_ADDR_C45 |
> +				     (XPCS_MDIO_MII_MMD <<
> +				      MII_DEVADDR_C45_SHIFT) |
> +				     MDIO_MII_MMD_AN_CTRL));
> +
> +	phydata &= ~MDIO_MII_MMD_AN_CTRL_PCS_MD;
> +	phydata |= (((pcs_mode <<
> MDIO_MII_MMD_AN_CTRL_PCS_MD_SHIFT) &
> +		    MDIO_MII_MMD_AN_CTRL_PCS_MD) |
> +		    (AN_CTRL_TX_CONF_PHY_SIDE_SGMII <<
> +		    MDIO_MII_MMD_AN_CTRL_TX_CONFIG_SHIFT) |
> +		    MDIO_MII_MMD_AN_CTRL_AN_INTR_EN);
> +
> +	mdiobus_write(priv->mii, xpcs_phy_addr,
> +		      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
> +		       MII_DEVADDR_C45_SHIFT) |
> MDIO_MII_MMD_AN_CTRL),
> +		      (int)phydata);
> +}
> +
> +/**
> + * dw_xpcs_rane - To restart Auto Negotiation (AN)
> + * @ndev: network device pointer
> + * @restart: to restart AN
> + * Description: this is to restart AN.
> + */
> +static inline void dw_xpcs_rane(struct net_device *ndev, bool restart)
> +{
> +	struct stmmac_priv *priv = netdev_priv(ndev);
> +	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
> +
> +	u16 phydata = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +				(MII_ADDR_C45 | (XPCS_MDIO_MII_MMD
> <<
> +				 MII_DEVADDR_C45_SHIFT) |
> +				 MDIO_MII_MMD_CTRL));
> +
> +	if (restart)
> +		phydata |= MDIO_MII_MMD_CTRL_RANE;
> +
> +	mdiobus_write(priv->mii, xpcs_phy_addr,
> +		      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
> +		       MII_DEVADDR_C45_SHIFT) | MDIO_MII_MMD_CTRL),
> +		      (int)phydata);
> +}
> +
> +/**
> + * dw_xpcs_ctrl_ane - To program the MII MMD Control Register.
> + * @ndev: network device pointer
> + * @ane: to enable the Auto Negotiation
> + * @loopback: to cause the PHY to loopback Tx data into Rx path.
> + * Description: this is the main function to configure the MII MMD
> + * control register and init the AN Enable and select loopback.
> + */
> +static inline void dw_xpcs_ctrl_ane(struct net_device *ndev, bool ane,
> +				    bool loopback)
> +{
> +	struct stmmac_priv *priv = netdev_priv(ndev);
> +	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
> +
> +	u16 phydata = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +				(MII_ADDR_C45 | (XPCS_MDIO_MII_MMD
> <<
> +				 MII_DEVADDR_C45_SHIFT) |
> +				 MDIO_MII_MMD_CTRL));
> +
> +	if (ane)
> +		phydata |= (MDIO_MII_MMD_CTRL_ANE |
> MDIO_MII_MMD_CTRL_RANE);
> +
> +	if (loopback)
> +		phydata |= MDIO_MII_MMD_CTRL_LBE;
> +
> +	mdiobus_write(priv->mii, xpcs_phy_addr,
> +		      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
> +		       MII_DEVADDR_C45_SHIFT) | MDIO_MII_MMD_CTRL),
> +		      (int)phydata);
> +}
> +
> +/**
> + * dw_xpcs_get_adv_lp - Get AN Advertisement and Link Partner Ability
> + * @ndev: network device pointer
> + * @adv_lp: structure to store the adv, lp status
> + * Description: this is to expose the Auto Negotiation Advertisement
> +and
> + * Link partner ability status to ethtool support.
> + */
> +static inline void dw_xpcs_get_adv_lp(struct net_device *ndev,
> +				      struct rgmii_adv *adv_lp)
> +{
> +	struct stmmac_priv *priv = netdev_priv(ndev);
> +	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
> +
> +	/* AN Advertisement Ability */
> +	u16 value = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +				(MII_ADDR_C45 | (XPCS_MDIO_MII_MMD
> <<
> +				 MII_DEVADDR_C45_SHIFT) |
> +				 MDIO_MII_MMD_ADV));
> +
> +	if (value & MDIO_MII_MMD_FD)
> +		adv_lp->duplex = DUPLEX_FULL;
> +	if (value & MDIO_MII_MMD_HD)
> +		adv_lp->duplex = DUPLEX_HALF;
> +	adv_lp->pause = (u32)((value & MDIO_MII_MMD_PSE) >>
> +			      MDIO_MII_MMD_PSE_SHIFT);
> +
> +	/* Link Partner Ability */
> +	value = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +				  (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD
> <<
> +				   MII_DEVADDR_C45_SHIFT) |
> +				   MDIO_MII_MMD_LPA));
> +
> +	if (value & MDIO_MII_MMD_FD)
> +		adv_lp->lp_duplex = DUPLEX_FULL;
> +	if (value & MDIO_MII_MMD_HD)
> +		adv_lp->lp_duplex = DUPLEX_HALF;
> +	adv_lp->lp_pause = (u32)((value & MDIO_MII_MMD_PSE) >>
> +				 MDIO_MII_MMD_PSE_SHIFT);
> +}
> +
> +/**
> + * dw_xpcs_get_linkstatus - Get Link Status
> + * @an_stat: C37 AN status value
> + * @x: stmmac extra status
> + * Description: this is to read the link extra status from <C37 AN
> +SGMII
> + * status> field of MII MMD AN Status register.
> + */
> +static inline void dw_xpcs_get_linkstatus(u16 an_stat,
> +					  struct stmmac_extra_stats *x)
> +{
> +	/* Check the link status */
> +	if (an_stat & AN_STAT_C37_AN_LNKSTS) {
> +		int speed_value;
> +
> +		x->pcs_link = 1;
> +
> +		speed_value = ((an_stat & AN_STAT_C37_AN_SPEED) >>
> +				AN_STAT_C37_AN_SPEED_SHIFT);
> +		if (speed_value == AN_STAT_C37_AN_1000MBPS)
> +			x->pcs_speed = SPEED_1000;
> +		else if (speed_value == AN_STAT_C37_AN_100MBPS)
> +			x->pcs_speed = SPEED_100;
> +		else
> +			x->pcs_speed = SPEED_10;
> +
> +		if (an_stat & AN_STAT_C37_AN_FD)
> +			x->pcs_duplex = 1;
> +		else
> +			x->pcs_duplex = 0;
> +
> +		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");
> +	}
> +}
> +
> +/**
> + * dw_xpcs_irq_status - Get xPCS IRQ Status
> + * @ndev: network device pointer
> + * @x: stmmac extra status
> + * Description: this is to read the xPCS IRQ status.
> + */
> +static inline int dw_xpcs_irq_status(struct net_device *ndev,
> +				     struct stmmac_extra_stats *x)
> +{
> +	struct stmmac_priv *priv = netdev_priv(ndev);
> +	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
> +	int ret = IRQ_NONE;
> +
> +	/* C37 AN status */
> +	u16 an_stat = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +					(MII_ADDR_C45 |
> +					 (XPCS_MDIO_MII_MMD <<
> +					  MII_DEVADDR_C45_SHIFT) |
> +					 MDIO_MII_MMD_AN_STAT));
> +
> +	if (an_stat & AN_STAT_C37_AN_CMPLT) {
> +		x->irq_pcs_ane_n++;
> +		dw_xpcs_get_linkstatus(an_stat, x);
> +
> +		/* Clear C37 AN complete status by writing zero */
> +		mdiobus_write(priv->mii, xpcs_phy_addr,
> +			      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
> +			       MII_DEVADDR_C45_SHIFT) |
> +			       MDIO_MII_MMD_AN_STAT),
> +			      0);
> +		ret = IRQ_HANDLED;
> +	}
> +
> +	return ret;
> +}
> +#endif /* __DW_XPCS_H__ */
> diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h
> b/drivers/net/ethernet/stmicro/stmmac/hwif.h
> index 5bb0023..cb7eb48 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
> @@ -310,6 +310,13 @@ struct stmmac_ops {
>  			     bool loopback);
>  	void (*pcs_rane)(void __iomem *ioaddr, bool restart);
>  	void (*pcs_get_adv_lp)(void __iomem *ioaddr, struct rgmii_adv
> *adv);
> +	/* xPCS calls */
> +	void (*xpcs_init)(struct net_device *ndev, int pcs_mode);
> +	void (*xpcs_ctrl_ane)(struct net_device *ndev, bool ane, bool
> loopback);
> +	void (*xpcs_rane)(struct net_device *ndev, bool restart);
> +	void (*xpcs_get_adv_lp)(struct net_device *ndev, struct rgmii_adv
> *adv);
> +	int (*xpcs_irq_status)(struct net_device *ndev,
> +			       struct stmmac_extra_stats *x);
>  	/* Safety Features */
>  	int (*safety_feat_config)(void __iomem *ioaddr, unsigned int asp);
>  	int (*safety_feat_irq_status)(struct net_device *ndev, @@ -382,6
> +389,16 @@ struct stmmac_ops {
>  	stmmac_do_void_callback(__priv, mac, pcs_rane, __args)  #define
> stmmac_pcs_get_adv_lp(__priv, __args...) \
>  	stmmac_do_void_callback(__priv, mac, pcs_get_adv_lp, __args)
> +#define stmmac_xpcs_init(__priv, __args...) \
> +	stmmac_do_void_callback(__priv, mac, xpcs_init, __args) #define
> +stmmac_xpcs_ctrl_ane(__priv, __args...) \
> +	stmmac_do_void_callback(__priv, mac, xpcs_ctrl_ane, __args)
> #define
> +stmmac_xpcs_rane(__priv, __args...) \
> +	stmmac_do_void_callback(__priv, mac, xpcs_rane, __args) #define
> +stmmac_xpcs_get_adv_lp(__priv, __args...) \
> +	stmmac_do_void_callback(__priv, mac, xpcs_get_adv_lp, __args)
> #define
> +stmmac_xpcs_irq_status(__priv, __args...) \
> +	stmmac_do_callback(__priv, mac, xpcs_irq_status, __args)
>  #define stmmac_safety_feat_config(__priv, __args...) \
>  	stmmac_do_callback(__priv, mac, safety_feat_config, __args)
> #define stmmac_safety_feat_irq_status(__priv, __args...) \ diff --git
> a/include/linux/stmmac.h b/include/linux/stmmac.h index 4335bd7..b00e795
> 100644
> --- a/include/linux/stmmac.h
> +++ b/include/linux/stmmac.h
> @@ -148,6 +148,7 @@ struct stmmac_txq_cfg {  struct
> plat_stmmacenet_data {
>  	int bus_id;
>  	int phy_addr;
> +	int xpcs_phy_addr;
>  	int interface;
>  	struct stmmac_mdio_bus_data *mdio_bus_data;
>  	struct device_node *phy_node;
> --
> 1.9.1

++ stmmac maintainers and c45 experts

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ