RE: [RFC net-next 1/5] net: stmmac: introduce IEEE 802.1Qbv configuration functionalities

2019-06-27 Thread Ong, Boon Leong
>-Original Message-
>From: Jose Abreu [mailto:jose.ab...@synopsys.com]
>>From: Voon Weifeng 
>> diff --git a/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
>b/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
>> new file mode 100644
>> index ..cba27c604cb1
>> --- /dev/null
>> +++ b/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
>
>XGMAC also supports TSN features so I think more abstraction is needed
>on this because the XGMAC implementation is very similar (only reg
>offsets and bitfields changes).
>
>I would rather:
>   - Implement HW specific handling in dwmac4_core.c / dwmac4_dma.c
>and
>add the callbacks in hwif table;
>   - Let TSN logic in this file but call it stmmac_tsn.c.
OK. Thanks for above feedback.
>
>> @@ -3621,6 +3622,8 @@ static int stmmac_set_features(struct net_device
>*netdev,
>>   */
>>  stmmac_rx_ipc(priv, priv->hw);
>>
>> +netdev->features = features;
>
>Isn't this a fix ?
Yup. We will split this out as a patch and send separately.


RE: [RFC net-next 1/5] net: stmmac: introduce IEEE 802.1Qbv configuration functionalities

2019-06-27 Thread Jose Abreu
From: Voon Weifeng 

> diff --git a/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c 
> b/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
> new file mode 100644
> index ..cba27c604cb1
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c

XGMAC also supports TSN features so I think more abstraction is needed 
on this because the XGMAC implementation is very similar (only reg 
offsets and bitfields changes).

I would rather:
- Implement HW specific handling in dwmac4_core.c / dwmac4_dma.c and 
add the callbacks in hwif table;
- Let TSN logic in this file but call it stmmac_tsn.c.

> @@ -3621,6 +3622,8 @@ static int stmmac_set_features(struct net_device 
> *netdev,
>*/
>   stmmac_rx_ipc(priv, priv->hw);
>  
> + netdev->features = features;

Isn't this a fix ?


RE: [RFC net-next 1/5] net: stmmac: introduce IEEE 802.1Qbv configuration functionalities

2019-06-19 Thread Ong, Boon Leong
>-Original Message-
>From: Gomes, Vinicius
>> +++ b/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
>> @@ -0,0 +1,790 @@
>> +
>> +static struct tsn_hw_cap dw_tsn_hwcap;
>> +static bool dw_tsn_feat_en[TSN_FEAT_ID_MAX];
>> +static unsigned int dw_tsn_hwtunable[TSN_HWTUNA_MAX];
>> +static struct est_gc_config dw_est_gc_config;
>
>If it's at all possible to have more than one of these devices in a
>system, this should be moved to a per-device structure. That
>mac_device_info struct perhaps?
I do see value in scaling the code to more than one device there.
Thanks.

>> +void dwmac_tsn_init(void *ioaddr)
>
>Perhaps this should return an error if TSN is not supported. It may help
>simplify the initialization below.
Thanks for the input. It may not be apparent because this code does not
include Qbu detection yet. The thinking here is to avoid caller function
not need to handle and IP configuration difference, i.e. SoC-1 may have only
Qbv and SoC-2 have both. 

>
>> +{
>> +unsigned int hwid = TSN_RD32(ioaddr + GMAC4_VERSION) &
>TSN_VER_MASK;
>> +unsigned int hw_cap2 = TSN_RD32(ioaddr + GMAC_HW_FEATURE2);
>> +unsigned int hw_cap3 = TSN_RD32(ioaddr + GMAC_HW_FEATURE3);
>> +struct tsn_hw_cap *cap = &dw_tsn_hwcap;
>> +unsigned int gcl_depth;
>> +unsigned int tils_max;
>> +unsigned int ti_wid;
>> +
>> +memset(cap, 0, sizeof(*cap));
>> +
>> +if (hwid < TSN_CORE_VER) {
>> +TSN_WARN_NA("IP v5.00 does not support TSN\n");
Perhaps, we just print info here instead of warning because SoC with EQoS v5
can be built without Qbv. 

>> +return;
>> +}
>> +
>> +if (!(hw_cap3 & GMAC_HW_FEAT_ESTSEL)) {
>> +TSN_WARN_NA("EST NOT supported\n");
>> +cap->est_support = 0;
Same here. 

>> +
>> +return;
>> +}
>> +
>> +gcl_depth = est_get_gcl_depth(hw_cap3);
>> +ti_wid = est_get_ti_width(hw_cap3);
>> +
>> +cap->ti_wid = ti_wid;
>> +cap->gcl_depth = gcl_depth;
>> +
>> +tils_max = (hw_cap3 & GMAC_HW_FEAT_ESTSEL ? 3 : 0);
>> +tils_max = (1 << tils_max) - 1;
>> +cap->tils_max = tils_max;
>> +
>> +cap->ext_max = EST_TIWID_TO_EXTMAX(ti_wid);
>> +cap->txqcnt = ((hw_cap2 & GMAC_HW_FEAT_TXQCNT) >> 6) + 1;
>> +cap->est_support = 1;
>> +
>> +TSN_INFO("EST: depth=%u, ti_wid=%u, tils_max=%u tqcnt=%u\n",
>> + gcl_depth, ti_wid, tils_max, cap->txqcnt);
>> +}

>> diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h
>b/drivers/net/ethernet/stmicro/stmmac/hwif.h
>> index 2acfbc70e3c8..518a72805185 100644
>> --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
>> +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
>> @@ -7,6 +7,7 @@
>>
>>  #include 
>>  #include 
>> +#include "dw_tsn_lib.h"
>>
>>  #define stmmac_do_void_callback(__priv, __module, __cname,  __arg0,
>__args...) \
>>  ({ \
>> @@ -311,6 +312,31 @@ 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);
>> +/* TSN functions */
>> +void (*tsn_init)(void __iomem *ioaddr);
>> +void (*get_tsn_hwcap)(struct tsn_hw_cap **tsn_hwcap);
>> +void (*set_est_gcb)(struct est_gc_entry *gcl,
>> +u32 bank);
>> +void (*set_tsn_feat)(enum tsn_feat_id featid, bool enable);
>> +int (*set_tsn_hwtunable)(void __iomem *ioaddr,
>> + enum tsn_hwtunable_id id,
>> + const unsigned int *data);
>> +int (*get_tsn_hwtunable)(enum tsn_hwtunable_id id,
>> + unsigned int *data);
>> +int (*get_est_bank)(void __iomem *ioaddr, u32 own);
>> +int (*set_est_gce)(void __iomem *ioaddr,
>> +   struct est_gc_entry *gce, u32 row,
>> +   u32 dbgb, u32 dbgm);
>> +int (*get_est_gcrr_llr)(void __iomem *ioaddr, u32 *gcl_len,
>> +u32 dbgb, u32 dbgm);
>> +int (*set_est_gcrr_llr)(void __iomem *ioaddr, u32 gcl_len,
>> +u32 dbgb, u32 dbgm);
>> +int (*set_est_gcrr_times)(void __iomem *ioaddr,
>> +  struct est_gcrr *gcrr,
>> +  u32 dbgb, u32 dbgm);
>> +int (*set_est_enable)(void __iomem *ioaddr, bool enable);
>> +int (*get_est_gcc)(void __iomem *ioaddr,
>> +   struct est_gc_config **gcc, bool frmdrv);
>
>These functions do not seem to be consistent with the rest of the
>stmmac_ops: most of the operations already there receive an
>mac_device_info as first argument, which seem much less error prone than
>a void* ioaddr.
Thanks for the input. We will look into this together with mac_device_info
and adjust accordingly. 



RE: [RFC net-next 1/5] net: stmmac: introduce IEEE 802.1Qbv configuration functionalities

2019-06-19 Thread Ong, Boon Leong
>> > It looks like most o the TSN_WARN should actually be netdev_dbg().
>> >
>> >Andrew
>>
>> Hi Andrew,
>> This file is targeted for dual licensing which is GPL-2.0 OR BSD-3-Clause.
>> This is the reason why we are using wrappers around the functions so that
>> all the function call is generic.
>
>I don't see why dual licenses should require wrappers. Please explain.
>
>  Thanks
>   Andrew
Agree with the Andrew. We can change those wrapper functions that have
serve the internal development needs for multiple OS scaling reason. 
We will update the kernel codes as suggsted.  




Re: [RFC net-next 1/5] net: stmmac: introduce IEEE 802.1Qbv configuration functionalities

2019-06-19 Thread Vinicius Costa Gomes
Hi,

Voon Weifeng  writes:

> From: Ong Boon Leong 
>
> IEEE 802.1Qbv Enhancements for Scheduled Traffics (EST) is available in
> EQoS ver5.xx. The change adds basic EST functionalities:
>
> a) EST initialization with hardware capabilities detection.
> b) Setting Gate Control List (GCL), i.e. gate open/close & time intervals,
>and all GC Related Registers (GCRR), e.g., base time (BTR), cycle time
>(CTR), time extension (TER) and GC List Length (LLR).
> c) Setting time interval left shift (TILS), PTP time offset (PTOV) and
>current time offset (CTOV).
> d) Enable/disable EST.
> e) Getting TSN hardware capabilities.
> f) Getting Gate Control configuration either from driver data store or
>hardware.
>
> We extend the main driver logic to include basic TSN capability discovery,
> and setup. We also add EST feature enable/disable control.
>
> Reviewed-by: Chuah Kim Tatt 
> Reviewed-by: Voon Weifeng 
> Reviewed-by: Kweh Hock Leong 
> Signed-off-by: Ong Boon Leong 
> Signed-off-by: Voon Weifeng 
> ---
>  drivers/net/ethernet/stmicro/stmmac/Makefile  |   2 +-
>  drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c  | 790 
> ++
>  drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.h  | 173 +
>  drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c |  13 +
>  drivers/net/ethernet/stmicro/stmmac/hwif.h|  52 ++
>  drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |  46 ++
>  include/linux/stmmac.h|   1 +
>  7 files changed, 1076 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.h
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile 
> b/drivers/net/ethernet/stmicro/stmmac/Makefile
> index c59926d96bcc..76fb36cb4da7 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/Makefile
> +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
> @@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o 
> ring_mode.o\
> mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o  \
> dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
> stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
> -   $(stmmac-y)
> +   dw_tsn_lib.o $(stmmac-y)
>  
>  stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
>  
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c 
> b/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
> new file mode 100644
> index ..cba27c604cb1
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
> @@ -0,0 +1,790 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> +/* Copyright (c) 2019, Intel Corporation.
> + * dw_tsn_lib.c: DW EQoS v5.00 TSN capabilities
> + */
> +
> +#include "dwmac4.h"
> +#include "dwmac5.h"
> +#include "dw_tsn_lib.h"
> +
> +static struct tsn_hw_cap dw_tsn_hwcap;
> +static bool dw_tsn_feat_en[TSN_FEAT_ID_MAX];
> +static unsigned int dw_tsn_hwtunable[TSN_HWTUNA_MAX];
> +static struct est_gc_config dw_est_gc_config;

If it's at all possible to have more than one of these devices in a
system, this should be moved to a per-device structure. That
mac_device_info struct perhaps?

> +
> +static unsigned int est_get_gcl_depth(unsigned int hw_cap)
> +{
> + unsigned int estdep = (hw_cap & GMAC_HW_FEAT_ESTDEP)
> + >> GMAC_HW_FEAT_ESTDEP_SHIFT;
> + unsigned int depth;
> +
> + switch (estdep) {
> + case 1:
> + depth = 64;
> + break;
> + case 2:
> + depth = 128;
> + break;
> + case 3:
> + depth = 256;
> + break;
> + case 4:
> + depth = 512;
> + break;
> + case 5:
> + depth = 1024;
> + break;
> + default:
> + depth = 0;
> + }
> +
> + return depth;
> +}
> +
> +static unsigned int est_get_ti_width(unsigned int hw_cap)
> +{
> + unsigned int estwid = (hw_cap & GMAC_HW_FEAT_ESTWID)
> + >> GMAC_HW_FEAT_ESTWID_SHIFT;
> + unsigned int width;
> +
> + switch (estwid) {
> + case 1:
> + width = 16;
> + break;
> + case 2:
> + width = 20;
> + break;
> + case 3:
> + width = 24;
> + break;
> + default:
> + width = 0;
> + }
> +
> + return width;
> +}
> +
> +static int est_poll_srwo(void *ioaddr)
> +{
> + /* Poll until the EST GCL Control[SRWO] bit clears.
> +  * Total wait = 12 x 50ms ~= 0.6s.
> +  */
> + unsigned int retries = 12;
> + unsigned int value;
> +
> + do {
> + value = TSN_RD32(ioaddr + MTL_EST_GCL_CTRL);
> + if (!(value & MTL_EST_GCL_CTRL_SRWO))
> + return 0;
> + msleep(50);
> + } while (--retries);
> +
> + return -ETIMEDOUT;
> +}
> +
> +static int est_set_gcl_addr(void *ioaddr, un

Re: [RFC net-next 1/5] net: stmmac: introduce IEEE 802.1Qbv configuration functionalities

2019-06-19 Thread Andrew Lunn
> > It looks like most o the TSN_WARN should actually be netdev_dbg().
> > 
> >Andrew
> 
> Hi Andrew,
> This file is targeted for dual licensing which is GPL-2.0 OR BSD-3-Clause.
> This is the reason why we are using wrappers around the functions so that
> all the function call is generic.

I don't see why dual licenses should require wrappers. Please explain.

  Thanks
Andrew


RE: [RFC net-next 1/5] net: stmmac: introduce IEEE 802.1Qbv configuration functionalities

2019-06-19 Thread Voon, Weifeng
> > +static int est_poll_srwo(void *ioaddr) {
> > +   /* Poll until the EST GCL Control[SRWO] bit clears.
> > +* Total wait = 12 x 50ms ~= 0.6s.
> > +*/
> > +   unsigned int retries = 12;
> > +   unsigned int value;
> > +
> > +   do {
> > +   value = TSN_RD32(ioaddr + MTL_EST_GCL_CTRL);
> > +   if (!(value & MTL_EST_GCL_CTRL_SRWO))
> > +   return 0;
> > +   msleep(50);
> > +   } while (--retries);
> > +
> > +   return -ETIMEDOUT;
> 
> Maybe use one of the readx_poll_timeout() macros?
> 
> > +static int est_read_gce(void *ioaddr, unsigned int row,
> > +   unsigned int *gates, unsigned int *ti_nsec,
> > +   unsigned int dbgb, unsigned int dbgm) {
> > +   struct tsn_hw_cap *cap = &dw_tsn_hwcap;
> > +   unsigned int ti_wid = cap->ti_wid;
> > +   unsigned int gates_mask;
> > +   unsigned int ti_mask;
> > +   unsigned int value;
> > +   int ret;
> > +
> > +   gates_mask = (1 << cap->txqcnt) - 1;
> > +   ti_mask = (1 << ti_wid) - 1;
> > +
> > +   ret = est_read_gcl_config(ioaddr, &value, row, 0, dbgb, dbgm);
> > +   if (ret) {
> > +   TSN_ERR("Read GCE failed! row=%u\n", row);
> 
> It is generally not a good idea to put wrappers around the kernel print
> functions. It would be better if all these functions took struct
> stmmac_priv *priv rather than ioaddr, so you could then do
> 
>   netdev_err(priv->dev, "Read GCE failed! row=%u\n", row);
> 
> > +   /* Ensure that HW is not in the midst of GCL transition */
> > +   value = TSN_RD32(ioaddr + MTL_EST_CTRL);
> 
> Also, don't put wrapper around readl()/writel().
> 
> > +   value &= ~MTL_EST_CTRL_SSWL;
> > +
> > +   /* MTL_EST_CTRL value has been read earlier, if TILS value
> > +* differs, we update here.
> > +*/
> > +   if (tils != dw_tsn_hwtunable[TSN_HWTUNA_TX_EST_TILS]) {
> > +   value &= ~MTL_EST_CTRL_TILS;
> > +   value |= (tils << MTL_EST_CTRL_TILS_SHIFT);
> > +
> > +   TSN_WR32(value, ioaddr + MTL_EST_CTRL);
> > +   dw_tsn_hwtunable[TSN_HWTUNA_TX_EST_TILS] = tils;
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static int est_set_ov(void *ioaddr,
> > + const unsigned int *ptov,
> > + const unsigned int *ctov)
> > +{
> > +   unsigned int value;
> > +
> > +   if (!dw_tsn_feat_en[TSN_FEAT_ID_EST])
> > +   return -ENOTSUPP;
> > +
> > +   value = TSN_RD32(ioaddr + MTL_EST_CTRL);
> > +   value &= ~MTL_EST_CTRL_SSWL;
> > +
> > +   if (ptov) {
> > +   if (*ptov > EST_PTOV_MAX) {
> > +   TSN_WARN("EST: invalid PTOV(%u), max=%u\n",
> > +*ptov, EST_PTOV_MAX);
> 
> It looks like most o the TSN_WARN should actually be netdev_dbg().
> 
>Andrew

Hi Andrew,
This file is targeted for dual licensing which is GPL-2.0 OR BSD-3-Clause.
This is the reason why we are using wrappers around the functions so that
all the function call is generic.

Regards,
Weifeng



Re: [RFC net-next 1/5] net: stmmac: introduce IEEE 802.1Qbv configuration functionalities

2019-06-18 Thread Andrew Lunn
On Wed, Jun 19, 2019 at 05:36:14AM +0800, Voon Weifeng wrote:

Hi Voon

> +static int est_poll_srwo(void *ioaddr)
> +{
> + /* Poll until the EST GCL Control[SRWO] bit clears.
> +  * Total wait = 12 x 50ms ~= 0.6s.
> +  */
> + unsigned int retries = 12;
> + unsigned int value;
> +
> + do {
> + value = TSN_RD32(ioaddr + MTL_EST_GCL_CTRL);
> + if (!(value & MTL_EST_GCL_CTRL_SRWO))
> + return 0;
> + msleep(50);
> + } while (--retries);
> +
> + return -ETIMEDOUT;

Maybe use one of the readx_poll_timeout() macros?

> +static int est_read_gce(void *ioaddr, unsigned int row,
> + unsigned int *gates, unsigned int *ti_nsec,
> + unsigned int dbgb, unsigned int dbgm)
> +{
> + struct tsn_hw_cap *cap = &dw_tsn_hwcap;
> + unsigned int ti_wid = cap->ti_wid;
> + unsigned int gates_mask;
> + unsigned int ti_mask;
> + unsigned int value;
> + int ret;
> +
> + gates_mask = (1 << cap->txqcnt) - 1;
> + ti_mask = (1 << ti_wid) - 1;
> +
> + ret = est_read_gcl_config(ioaddr, &value, row, 0, dbgb, dbgm);
> + if (ret) {
> + TSN_ERR("Read GCE failed! row=%u\n", row);

It is generally not a good idea to put wrappers around the kernel
print functions. It would be better if all these functions took struct
stmmac_priv *priv rather than ioaddr, so you could then do

netdev_err(priv->dev, "Read GCE failed! row=%u\n", row);

> + /* Ensure that HW is not in the midst of GCL transition */
> + value = TSN_RD32(ioaddr + MTL_EST_CTRL);

Also, don't put wrapper around readl()/writel().

> + value &= ~MTL_EST_CTRL_SSWL;
> +
> + /* MTL_EST_CTRL value has been read earlier, if TILS value
> +  * differs, we update here.
> +  */
> + if (tils != dw_tsn_hwtunable[TSN_HWTUNA_TX_EST_TILS]) {
> + value &= ~MTL_EST_CTRL_TILS;
> + value |= (tils << MTL_EST_CTRL_TILS_SHIFT);
> +
> + TSN_WR32(value, ioaddr + MTL_EST_CTRL);
> + dw_tsn_hwtunable[TSN_HWTUNA_TX_EST_TILS] = tils;
> + }
> +
> + return 0;
> +}
> +
> +static int est_set_ov(void *ioaddr,
> +   const unsigned int *ptov,
> +   const unsigned int *ctov)
> +{
> + unsigned int value;
> +
> + if (!dw_tsn_feat_en[TSN_FEAT_ID_EST])
> + return -ENOTSUPP;
> +
> + value = TSN_RD32(ioaddr + MTL_EST_CTRL);
> + value &= ~MTL_EST_CTRL_SSWL;
> +
> + if (ptov) {
> + if (*ptov > EST_PTOV_MAX) {
> + TSN_WARN("EST: invalid PTOV(%u), max=%u\n",
> +  *ptov, EST_PTOV_MAX);

It looks like most o the TSN_WARN should actually be netdev_dbg().

   Andrew


[RFC net-next 1/5] net: stmmac: introduce IEEE 802.1Qbv configuration functionalities

2019-06-18 Thread Voon Weifeng
From: Ong Boon Leong 

IEEE 802.1Qbv Enhancements for Scheduled Traffics (EST) is available in
EQoS ver5.xx. The change adds basic EST functionalities:

a) EST initialization with hardware capabilities detection.
b) Setting Gate Control List (GCL), i.e. gate open/close & time intervals,
   and all GC Related Registers (GCRR), e.g., base time (BTR), cycle time
   (CTR), time extension (TER) and GC List Length (LLR).
c) Setting time interval left shift (TILS), PTP time offset (PTOV) and
   current time offset (CTOV).
d) Enable/disable EST.
e) Getting TSN hardware capabilities.
f) Getting Gate Control configuration either from driver data store or
   hardware.

We extend the main driver logic to include basic TSN capability discovery,
and setup. We also add EST feature enable/disable control.

Reviewed-by: Chuah Kim Tatt 
Reviewed-by: Voon Weifeng 
Reviewed-by: Kweh Hock Leong 
Signed-off-by: Ong Boon Leong 
Signed-off-by: Voon Weifeng 
---
 drivers/net/ethernet/stmicro/stmmac/Makefile  |   2 +-
 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c  | 790 ++
 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.h  | 173 +
 drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c |  13 +
 drivers/net/ethernet/stmicro/stmmac/hwif.h|  52 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |  46 ++
 include/linux/stmmac.h|   1 +
 7 files changed, 1076 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.h

diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile 
b/drivers/net/ethernet/stmicro/stmmac/Makefile
index c59926d96bcc..76fb36cb4da7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o 
ring_mode.o  \
  mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o  \
  dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
  stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
- $(stmmac-y)
+ dw_tsn_lib.o $(stmmac-y)
 
 stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c 
b/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
new file mode 100644
index ..cba27c604cb1
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dw_tsn_lib.c
@@ -0,0 +1,790 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright (c) 2019, Intel Corporation.
+ * dw_tsn_lib.c: DW EQoS v5.00 TSN capabilities
+ */
+
+#include "dwmac4.h"
+#include "dwmac5.h"
+#include "dw_tsn_lib.h"
+
+static struct tsn_hw_cap dw_tsn_hwcap;
+static bool dw_tsn_feat_en[TSN_FEAT_ID_MAX];
+static unsigned int dw_tsn_hwtunable[TSN_HWTUNA_MAX];
+static struct est_gc_config dw_est_gc_config;
+
+static unsigned int est_get_gcl_depth(unsigned int hw_cap)
+{
+   unsigned int estdep = (hw_cap & GMAC_HW_FEAT_ESTDEP)
+   >> GMAC_HW_FEAT_ESTDEP_SHIFT;
+   unsigned int depth;
+
+   switch (estdep) {
+   case 1:
+   depth = 64;
+   break;
+   case 2:
+   depth = 128;
+   break;
+   case 3:
+   depth = 256;
+   break;
+   case 4:
+   depth = 512;
+   break;
+   case 5:
+   depth = 1024;
+   break;
+   default:
+   depth = 0;
+   }
+
+   return depth;
+}
+
+static unsigned int est_get_ti_width(unsigned int hw_cap)
+{
+   unsigned int estwid = (hw_cap & GMAC_HW_FEAT_ESTWID)
+   >> GMAC_HW_FEAT_ESTWID_SHIFT;
+   unsigned int width;
+
+   switch (estwid) {
+   case 1:
+   width = 16;
+   break;
+   case 2:
+   width = 20;
+   break;
+   case 3:
+   width = 24;
+   break;
+   default:
+   width = 0;
+   }
+
+   return width;
+}
+
+static int est_poll_srwo(void *ioaddr)
+{
+   /* Poll until the EST GCL Control[SRWO] bit clears.
+* Total wait = 12 x 50ms ~= 0.6s.
+*/
+   unsigned int retries = 12;
+   unsigned int value;
+
+   do {
+   value = TSN_RD32(ioaddr + MTL_EST_GCL_CTRL);
+   if (!(value & MTL_EST_GCL_CTRL_SRWO))
+   return 0;
+   msleep(50);
+   } while (--retries);
+
+   return -ETIMEDOUT;
+}
+
+static int est_set_gcl_addr(void *ioaddr, unsigned int addr,
+   unsigned int gcrr, unsigned int rwops,
+   unsigned int dbgb, unsigned int dbgm)
+{
+   unsigned int value;
+
+   value = MTL_EST_GCL_CTRL_ADDR_VAL(addr) & MTL_EST_GCL_CTRL_ADDR;
+
+   if (dbgm) {
+   if (dbgb)
+   value |= MTL_EST_GCL_CTRL_DBGB1;
+
+