Netdev List
 help / color / mirror / Atom feed
* Re: [patch net-next] net: sched: fix block->refcnt decrement
From: David Miller @ 2018-08-09 21:12 UTC (permalink / raw)
  To: jiri; +Cc: netdev, jhs, xiyou.wangcong, vladbu, mlxsw
In-Reply-To: <20180808120413.7667-1-jiri@resnulli.us>

From: Jiri Pirko <jiri@resnulli.us>
Date: Wed,  8 Aug 2018 14:04:13 +0200

> From: Jiri Pirko <jiri@mellanox.com>
> 
> Currently the refcnt is never decremented in case the value is not 1.
> Fix it by adding decrement in case the refcnt is not 1.
> 
> Reported-by: Vlad Buslov <vladbu@mellanox.com>
> Fixes: f71e0ca4db18 ("net: sched: Avoid implicit chain 0 creation")
> Signed-off-by: Jiri Pirko <jiri@mellanox.com>

Applied.

^ permalink raw reply

* Re: [PATCH lora-next v2 6/8] net: lora: sx1301: replace version and size magic numbers with defines
From: Andreas Färber @ 2018-08-09 21:11 UTC (permalink / raw)
  To: Ben Whitten
  Cc: starnight, hasnain.virk, netdev, liuxuenetmail, shess,
	Ben Whitten
In-Reply-To: <1533818018-29005-6-git-send-email-ben.whitten@lairdtech.com>

Am 09.08.2018 um 14:33 schrieb Ben Whitten:
> We replace the hard coded numbers for size and version with meaningful
> names.
> 
> Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
> ---
>  drivers/net/lora/sx1301.c | 21 +++++++++++++--------
>  drivers/net/lora/sx1301.h | 18 ++++++++++++++++++
>  2 files changed, 31 insertions(+), 8 deletions(-)
>  create mode 100644 drivers/net/lora/sx1301.h
> 
> diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
> index 916ee40..8e81179 100644
> --- a/drivers/net/lora/sx1301.c
> +++ b/drivers/net/lora/sx1301.c
> @@ -21,6 +21,8 @@
>  #include <linux/lora/dev.h>
>  #include <linux/spi/spi.h>
>  
> +#include "sx1301.h"
> +
>  #define REG_PAGE_RESET			0
>  #define REG_VERSION			1
>  #define REG_MCU_PROM_ADDR		9
> @@ -293,7 +295,7 @@ static int sx1301_load_firmware(struct sx1301_priv *priv, int mcu, const struct
>  	u8 val, rst, select_mux;
>  	int ret;
>  
> -	if (fw->size != 8192) {
> +	if (fw->size != SX1301_MCU_FW_BYTE) {

I think that should be BYTES, but we can still rename it later.

>  		dev_err(priv->dev, "Unexpected firmware size\n");
>  		return -EINVAL;
>  	}
[...]
> diff --git a/drivers/net/lora/sx1301.h b/drivers/net/lora/sx1301.h
> new file mode 100644
> index 0000000..b37ac56
> --- /dev/null
> +++ b/drivers/net/lora/sx1301.h
> @@ -0,0 +1,18 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later

Header files must use /* ... */ or checkpatch.pl complains.

> +/*
> + * Semtech SX1301 lora concentrator

LoRa

> + *
> + * Copyright (c) 2018   Ben Whitten

Any reason for the multiple whitespaces?

> + */
> +
> +#ifndef _SX1301_
> +#define _SX1301_
> +
> +#define SX1301_CHIP_VERSION 103
> +
> +#define SX1301_MCU_FW_BYTE 8192
> +#define SX1301_MCU_ARB_FW_VERSION 1
> +#define SX1301_MCU_AGC_FW_VERSION 4
> +#define SX1301_MCU_AGC_CAL_FW_VERSION 2
> +
> +#endif

Applied.

Thanks,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

^ permalink raw reply

* Re: [PATCH net-next] net: ipv6_gre: Fix GRO to work on IPv6 over GRE tap
From: David Miller @ 2018-08-09 21:08 UTC (permalink / raw)
  To: tariqt; +Cc: netdev, eranbe, mariap
In-Reply-To: <1533717990-25365-1-git-send-email-tariqt@mellanox.com>

From: Tariq Toukan <tariqt@mellanox.com>
Date: Wed,  8 Aug 2018 11:46:30 +0300

> IPv6 GRO over GRE tap is not working while GRO is not set
> over the native interface.
 ...
> This patch removes the override of the hard_header_len, and
> assigns the calculated value to needed_headroom.
> This way, the comparison in gro_list_prepare is really of
> the mac headers, and if the packets have the same mac headers
> the same_flow will be set to 1.
> 
> Performance testing: 45% higher bandwidth.
> Measuring bandwidth of single-stream IPv4 TCP traffic over IPv6
> GRE tap while GRO is not set on the native.
> NIC: ConnectX-4LX
> Before (GRO not working) : 7.2 Gbits/sec
> After (GRO working): 10.5 Gbits/sec
> 
> Signed-off-by: Maria Pasechnik <mariap@mellanox.com>
> Signed-off-by: Tariq Toukan <tariqt@mellanox.com>

Applied, thank you.

^ permalink raw reply

* Re: [PATCH lora-next v2 3/8] net: lora: sx1301: convert to passing priv data throughout
From: Ben Whitten @ 2018-08-09 21:06 UTC (permalink / raw)
  To: Andreas Färber
  Cc: 潘建宏, hasnain.virk, netdev, Xue Liu, shess,
	Ben Whitten
In-Reply-To: <3884a134-c916-7b30-1db3-1e2c8f0d9d5b@suse.de>

On Thu, 9 Aug 2018 at 21:43, Andreas Färber <afaerber@suse.de> wrote:
>
> Am 09.08.2018 um 14:33 schrieb Ben Whitten:
> > Instead of passing around the spi device we instead pass around our
> > driver data directly.
> >
> > Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
> > ---
> >  drivers/net/lora/sx1301.c | 305 +++++++++++++++++++++++-----------------------
> >  1 file changed, 155 insertions(+), 150 deletions(-)
> >
> > diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
> > index 3c09f5a..7324001 100644
> > --- a/drivers/net/lora/sx1301.c
> > +++ b/drivers/net/lora/sx1301.c
> > @@ -73,24 +73,26 @@ struct spi_sx1301 {
> >  };
> >
> >  struct sx1301_priv {
> > +     struct device           *dev;
> > +     struct spi_device       *spi;
>
> Obviously this is not a long-term solution, but as interim step it'll
> have to do.
>
> >       struct lora_priv lora;
> >       struct gpio_desc *rst_gpio;
> >       u8 cur_page;
> >       struct spi_controller *radio_a_ctrl, *radio_b_ctrl;
> >  };
> >
> > -static int sx1301_read_burst(struct spi_device *spi, u8 reg, u8 *val, size_t len)
> > +static int sx1301_read_burst(struct sx1301_priv *priv, u8 reg, u8 *val, size_t len)
> >  {
> >       u8 addr = reg & 0x7f;
> > -     return spi_write_then_read(spi, &addr, 1, val, len);
> > +     return spi_write_then_read(priv->spi, &addr, 1, val, len);
> >  }
> >
> > -static int sx1301_read(struct spi_device *spi, u8 reg, u8 *val)
> > +static int sx1301_read(struct sx1301_priv *priv, u8 reg, u8 *val)
> >  {
> > -     return sx1301_read_burst(spi, reg, val, 1);
> > +     return sx1301_read_burst(priv, reg, val, 1);
> >  }
> >
> > -static int sx1301_write_burst(struct spi_device *spi, u8 reg, const u8 *val, size_t len)
> > +static int sx1301_write_burst(struct sx1301_priv *priv, u8 reg, const u8 *val, size_t len)
> >  {
> >       u8 addr = reg | BIT(7);
> >       struct spi_transfer xfr[2] = {
>
> This hunk did not apply for some reason, I've manually re-applied it.
>
> [...]
> > @@ -654,22 +646,35 @@ static int sx1301_probe(struct spi_device *spi)
> >       priv->rst_gpio = rst;
> >       priv->cur_page = 0xff;
> >
> > -     spi_set_drvdata(spi, netdev);
> > +     spi_set_drvdata(spi, priv);
>
> This change seems unnecessary and counter-productive for unregistration.
>
> Otherwise applying.

This is actually pretty critical, as it stands with the two spi masters we use
spi_get_drvdata on the parent device of the controller to recover the priv
struct for regmap.

We may have to include the netdev in the priv data, or do a container_of
dance to recover netdev in unregistration.
That said if we wrap things in devm then really our remove function could
be empty, as we have done with the allocation.

Regards,
Ben

^ permalink raw reply

* Re: [PATCH net-next 0/3] qed*: Enhancements
From: David Miller @ 2018-08-09 21:05 UTC (permalink / raw)
  To: manish.chopra; +Cc: netdev, ariel.elior, michal.kalderon
In-Reply-To: <20180809181351.32394-1-manish.chopra@cavium.com>

From: Manish Chopra <manish.chopra@cavium.com>
Date: Thu, 9 Aug 2018 11:13:48 -0700

> This patch series adds following support in drivers -
> 
> 1. Egress mqprio offload.
> 2. Add destination IP based flow profile.
> 3. Ingress flower offload (for drop action).
> 
> Please consider applying this series to "net-next".

Series applied, thank you.

^ permalink raw reply

* Re: [PATCH net-next 0/7] s390/qeth: updates 2018-08-09
From: David Miller @ 2018-08-09 21:04 UTC (permalink / raw)
  To: jwi; +Cc: netdev, linux-s390, schwidefsky, heiko.carstens, raspl, ubraun
In-Reply-To: <20180809124804.20056-1-jwi@linux.ibm.com>

From: Julian Wiedmann <jwi@linux.ibm.com>
Date: Thu,  9 Aug 2018 14:47:57 +0200

> one more set of patches for net-next. This is all sorts of cleanups
> and more refactoring on the way to using netdev_priv. Please apply.

Looks simple enough, series applied, thanks.

^ permalink raw reply

* Re: [PATCH lora-next v2 5/8] net: lora: sx1301: remove duplicate firmware size checks
From: Andreas Färber @ 2018-08-09 20:58 UTC (permalink / raw)
  To: Ben Whitten
  Cc: starnight, hasnain.virk, netdev, liuxuenetmail, shess,
	Ben Whitten
In-Reply-To: <1533818018-29005-5-git-send-email-ben.whitten@lairdtech.com>

Am 09.08.2018 um 14:33 schrieb Ben Whitten:
> No need to check the size of the firmware multiple times, just do it once
> in the function responsible for loading as the firmwares are the same size.
> 
> Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
> ---
>  drivers/net/lora/sx1301.c | 21 +++------------------
>  1 file changed, 3 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
> index 3f2a532..916ee40 100644
> --- a/drivers/net/lora/sx1301.c
> +++ b/drivers/net/lora/sx1301.c
> @@ -293,8 +293,10 @@ static int sx1301_load_firmware(struct sx1301_priv *priv, int mcu, const struct
>  	u8 val, rst, select_mux;
>  	int ret;
>  
> -	if (fw->size > 8192)
> +	if (fw->size != 8192) {

Note the original intention here was to allow loading firmware smaller
than the maximum size, but we can revisit that later if we ever have
such a firmware.

Applied.

Thanks,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

^ permalink raw reply

* Re: KCM - recvmsg() mangles packets?
From: Tom Herbert @ 2018-08-09 20:58 UTC (permalink / raw)
  To: Dominique Martinet; +Cc: Linux Kernel Network Developers
In-Reply-To: <20180805233921.GA5773@nautica>

On Sun, Aug 5, 2018 at 4:39 PM, Dominique Martinet
<asmadeus@codewreck.org> wrote:
> Dominique Martinet wrote on Sun, Aug 05, 2018:
>> It's getting late but I'll try adding a pskb_pull in there tomorrow, it
>> would be better to make the bpf program start with an offset but I don't
>> think that'll be easy to change...
>
> I can confirm the following patch fixes the issue for me:
> -----8<---------------------
> diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c
> index 625acb27efcc..348ff5945591 100644
> --- a/net/strparser/strparser.c
> +++ b/net/strparser/strparser.c
> @@ -222,6 +222,16 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
>                 if (!stm->strp.full_len) {
>                         ssize_t len;
>
> +                       /* Can only parse if there is no offset */
> +                       if (unlikely(stm->strp.offset)) {
> +                               if (!pskb_pull(skb, stm->strp.offset)) {
> +                                       STRP_STATS_INCR(strp->stats.mem_fail);
> +                                       strp_parser_err(strp, -ENOMEM, desc);
> +                                       break;
> +                               }
> +                               stm->strp.offset = 0;
> +                       }
> +

Seems okay to me for a fix. Looks like strp.offset is only set in one
place and read in one place. With this pull maybe that just can go
away?

Tom


>                         len = (*strp->cb.parse_msg)(strp, head);
>
>                         if (!len) {
> ----------------8<----------------------
>
> Now, I was looking at other users of strparser (I see sockmap, kcm and
> tls) and it looks like sockmap does not handle offsets either but tls
> does by using skb_copy_bits -- they're copying the tls header to a
> buffer on the stack.
>
> kcm cannot do that because we do not know how much data the user expects
> to read, and I'm not comfortable doing pskb_pull in the kcm callback
> either, but the cost of this pull is probably non-negligible if some
> user can make do without it...
>
> On the other hand, I do not see how to make the bpf program handle an
> offset in the skb as that offset is strparser-specific.
>
> Maybe add a flag in the cb that specifies wether the callback allows
> non-zero offset?
>
>
> I'll let you see if you can reproduce this and will wait for advices on
> how to solve this properly so we can work on a proper fix.
>
>
> Thanks,
> --
> Dominique

^ permalink raw reply

* [PATCH net-next] liquidio: copperhead LED identification
From: Felix Manlunas @ 2018-08-09 20:54 UTC (permalink / raw)
  To: davem
  Cc: netdev, raghu.vatsavayi, derek.chickles, satananda.burla,
	felix.manlunas

From: Raghu Vatsavayi <raghu.vatsavayi@cavium.com>

Add LED identification support for liquidio TP copperhead cards.

Signed-off-by: Raghu Vatsavayi <raghu.vatsavayi@cavium.com>
Acked-by: Derek Chickles <derek.chickles@cavium.com>
Signed-off-by: Felix Manlunas <felix.manlunas@cavium.com>
---
 drivers/net/ethernet/cavium/liquidio/lio_ethtool.c | 27 ++++++++++++++++++----
 .../net/ethernet/cavium/liquidio/liquidio_common.h |  1 +
 2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c
index 06f7449..807ea2c 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c
@@ -857,7 +857,14 @@ static int lio_set_phys_id(struct net_device *netdev,
 {
 	struct lio *lio = GET_LIO(netdev);
 	struct octeon_device *oct = lio->oct_dev;
+	struct oct_link_info *linfo;
 	int value, ret;
+	u32 cur_ver;
+
+	linfo = &lio->linfo;
+	cur_ver = OCT_FW_VER(oct->fw_info.ver.maj,
+			     oct->fw_info.ver.min,
+			     oct->fw_info.ver.rev);
 
 	switch (state) {
 	case ETHTOOL_ID_ACTIVE:
@@ -896,16 +903,22 @@ static int lio_set_phys_id(struct net_device *netdev,
 				return ret;
 		} else if (oct->chip_id == OCTEON_CN23XX_PF_VID) {
 			octnet_id_active(netdev, LED_IDENTIFICATION_ON);
-
-			/* returns 0 since updates are asynchronous */
-			return 0;
+			if (linfo->link.s.phy_type == LIO_PHY_PORT_TP &&
+			    cur_ver > OCT_FW_VER(1, 7, 2))
+				return 2;
+			else
+				return 0;
 		} else {
 			return -EINVAL;
 		}
 		break;
 
 	case ETHTOOL_ID_ON:
-		if (oct->chip_id == OCTEON_CN66XX)
+		if (oct->chip_id == OCTEON_CN23XX_PF_VID &&
+		    linfo->link.s.phy_type == LIO_PHY_PORT_TP &&
+		    cur_ver > OCT_FW_VER(1, 7, 2))
+			octnet_id_active(netdev, LED_IDENTIFICATION_ON);
+		else if (oct->chip_id == OCTEON_CN66XX)
 			octnet_gpio_access(netdev, VITESSE_PHY_GPIO_CFG,
 					   VITESSE_PHY_GPIO_HIGH);
 		else
@@ -914,7 +927,11 @@ static int lio_set_phys_id(struct net_device *netdev,
 		break;
 
 	case ETHTOOL_ID_OFF:
-		if (oct->chip_id == OCTEON_CN66XX)
+		if (oct->chip_id == OCTEON_CN23XX_PF_VID &&
+		    linfo->link.s.phy_type == LIO_PHY_PORT_TP &&
+		    cur_ver > OCT_FW_VER(1, 7, 2))
+			octnet_id_active(netdev, LED_IDENTIFICATION_OFF);
+		else if (oct->chip_id == OCTEON_CN66XX)
 			octnet_gpio_access(netdev, VITESSE_PHY_GPIO_CFG,
 					   VITESSE_PHY_GPIO_LOW);
 		else
diff --git a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h
index 690424b..7407fcd 100644
--- a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h
+++ b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h
@@ -907,6 +907,7 @@ static inline int opcode_slow_path(union octeon_rh *rh)
 #define VITESSE_PHY_GPIO_LOW      0x3
 #define LED_IDENTIFICATION_ON     0x1
 #define LED_IDENTIFICATION_OFF    0x0
+#define LIO23XX_COPPERHEAD_LED_GPIO 0x2
 
 struct oct_mdio_cmd {
 	u64 op;

^ permalink raw reply related

* Re: [PATCH bpf-next] bpf: enable btf for use in all maps
From: Yonghong Song @ 2018-08-09 20:50 UTC (permalink / raw)
  To: Daniel Borkmann, ast; +Cc: netdev
In-Reply-To: <20180809194220.17484-1-daniel@iogearbox.net>



On 8/9/18 12:42 PM, Daniel Borkmann wrote:
> Commit a26ca7c982cb ("bpf: btf: Add pretty print support to
> the basic arraymap") enabled support for BTF and dumping via
> BPF fs for arraymap. However, both can be decoupled from each
> other such that all BPF maps can be supported for attaching
> BTF key/value information, while not all maps necessarily
> need to dump via map_seq_show_elem() callback.
> 
> The check in array_map_check_btf() can be generalized as
> ultimatively the key and value size is the only contraint
> that needs to match for the map. The fact that the key needs
> to be of type int is optional; it could be any data type as
> long as it matches the 4 byte key size, just like hash table
> key or others could be of any data type as well.
> 
> Minimal example of a hash table dump which then works out
> of the box for bpftool:
> 
>    # bpftool map dump id 19
>    [{
>            "key": {
>                "": {
>                    "vip": 0,
>                    "vipv6": []
>                },
>                "port": 0,
>                "family": 0,
>                "proto": 0
>            },
>            "value": {
>                "flags": 0,
>                "vip_num": 0
>            }
>        }
>    ]
> 
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Yonghong Song <yhs@fb.com>

LGTM. Thanks!
Acked-by: Yonghong Song <yhs@fb.com>

^ permalink raw reply

* Re: [PATCH lora-next v2 4/8] net: lora: sx1301: convert load_firmware to take firmware directly
From: Andreas Färber @ 2018-08-09 20:48 UTC (permalink / raw)
  To: Ben Whitten
  Cc: starnight, hasnain.virk, netdev, liuxuenetmail, shess,
	Ben Whitten
In-Reply-To: <1533818018-29005-4-git-send-email-ben.whitten@lairdtech.com>

Am 09.08.2018 um 14:33 schrieb Ben Whitten:
> We just pass the pointer to firmware down to the function that loads
> it.
> 
> Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
> ---
>  drivers/net/lora/sx1301.c | 18 +++++++++---------
>  1 file changed, 9 insertions(+), 9 deletions(-)

Applied.

Thanks,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

^ permalink raw reply

* Re: [PATCH lora-next v2 3/8] net: lora: sx1301: convert to passing priv data throughout
From: Andreas Färber @ 2018-08-09 20:43 UTC (permalink / raw)
  To: Ben Whitten
  Cc: starnight, hasnain.virk, netdev, liuxuenetmail, shess,
	Ben Whitten
In-Reply-To: <1533818018-29005-3-git-send-email-ben.whitten@lairdtech.com>

Am 09.08.2018 um 14:33 schrieb Ben Whitten:
> Instead of passing around the spi device we instead pass around our
> driver data directly.
> 
> Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
> ---
>  drivers/net/lora/sx1301.c | 305 +++++++++++++++++++++++-----------------------
>  1 file changed, 155 insertions(+), 150 deletions(-)
> 
> diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
> index 3c09f5a..7324001 100644
> --- a/drivers/net/lora/sx1301.c
> +++ b/drivers/net/lora/sx1301.c
> @@ -73,24 +73,26 @@ struct spi_sx1301 {
>  };
>  
>  struct sx1301_priv {
> +	struct device		*dev;
> +	struct spi_device	*spi;

Obviously this is not a long-term solution, but as interim step it'll
have to do.

>  	struct lora_priv lora;
>  	struct gpio_desc *rst_gpio;
>  	u8 cur_page;
>  	struct spi_controller *radio_a_ctrl, *radio_b_ctrl;
>  };
>  
> -static int sx1301_read_burst(struct spi_device *spi, u8 reg, u8 *val, size_t len)
> +static int sx1301_read_burst(struct sx1301_priv *priv, u8 reg, u8 *val, size_t len)
>  {
>  	u8 addr = reg & 0x7f;
> -	return spi_write_then_read(spi, &addr, 1, val, len);
> +	return spi_write_then_read(priv->spi, &addr, 1, val, len);
>  }
>  
> -static int sx1301_read(struct spi_device *spi, u8 reg, u8 *val)
> +static int sx1301_read(struct sx1301_priv *priv, u8 reg, u8 *val)
>  {
> -	return sx1301_read_burst(spi, reg, val, 1);
> +	return sx1301_read_burst(priv, reg, val, 1);
>  }
>  
> -static int sx1301_write_burst(struct spi_device *spi, u8 reg, const u8 *val, size_t len)
> +static int sx1301_write_burst(struct sx1301_priv *priv, u8 reg, const u8 *val, size_t len)
>  {
>  	u8 addr = reg | BIT(7);
>  	struct spi_transfer xfr[2] = {

This hunk did not apply for some reason, I've manually re-applied it.

[...]
> @@ -654,22 +646,35 @@ static int sx1301_probe(struct spi_device *spi)
>  	priv->rst_gpio = rst;
>  	priv->cur_page = 0xff;
>  
> -	spi_set_drvdata(spi, netdev);
> +	spi_set_drvdata(spi, priv);

This change seems unnecessary and counter-productive for unregistration.

Otherwise applying.

Thanks,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

^ permalink raw reply

* Re: [bpf-next PATCH 2/2] samples/bpf: xdp_redirect_cpu load balance like Suricata
From: Jesper Dangaard Brouer @ 2018-08-09 20:36 UTC (permalink / raw)
  To: Daniel Borkmann
  Cc: netdev, Daniel Borkmann, Alexei Starovoitov, jhsiao, brouer
In-Reply-To: <8e6cdc1c-1f97-7280-58b9-d9db10986338@iogearbox.net>

On Thu, 9 Aug 2018 22:15:22 +0200
Daniel Borkmann <daniel@iogearbox.net> wrote:

> On 08/09/2018 03:26 PM, Jesper Dangaard Brouer wrote:
> > This implement XDP CPU redirection load-balancing across available
> > CPUs, based on the hashing IP-pairs + L4-protocol.  This equivalent to
> > xdp-cpu-redirect feature in Suricata, which is inspired by the
> > Suricata 'ippair' hashing code.
> > 
> > An important property is that the hashing is flow symmetric, meaning
> > that if the source and destination gets swapped then the selected CPU
> > will remain the same.  This is helps locality by placing both directions
> > of a flows on the same CPU, in a forwarding/routing scenario.
> > 
> > The hashing INITVAL (15485863 the 10^6th prime number) was fairly
> > arbitrary choosen, but experiments with kernel tree pktgen scripts
> > (pktgen_sample04_many_flows.sh +pktgen_sample05_flow_per_thread.sh)
> > showed this improved the distribution.
> > 
> > This patch also change the default loaded XDP program to be this
> > load-balancer.  As based on different user feedback, this seems to be
> > the expected behavior of the sample xdp_redirect_cpu.
> > 
> > Link: https://github.com/OISF/suricata/commit/796ec08dd7a63
> > Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
> > ---
> >  samples/bpf/xdp_redirect_cpu_kern.c |  103 +++++++++++++++++++++++++++++++++++
> >  samples/bpf/xdp_redirect_cpu_user.c |    4 +
> >  2 files changed, 105 insertions(+), 2 deletions(-)
> > 
> > diff --git a/samples/bpf/xdp_redirect_cpu_kern.c b/samples/bpf/xdp_redirect_cpu_kern.c
> > index 0cc3d71057f0..a306d1c75622 100644
> > --- a/samples/bpf/xdp_redirect_cpu_kern.c
> > +++ b/samples/bpf/xdp_redirect_cpu_kern.c
> > @@ -13,6 +13,7 @@
> >  
> >  #include <uapi/linux/bpf.h>
> >  #include "bpf_helpers.h"
> > +#include "hash_func01.h"
> >  
> >  #define MAX_CPUS 64 /* WARNING - sync with _user.c */  
> 
> Hmm, this doesn't apply cleanly. I have the following in bpf-next:
> 
> #define MAX_CPUS 12 /* WARNING - sync with _user.c */
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/tree/samples/bpf/xdp_redirect_cpu_kern.c#n17
> 
> Rebase issue? Please respin, thanks.

Ah, this is due to the teardown-fixes patchset for "bpf" git-tree,
which you just applied, which changed MAX_CPUS to 64 (so, QA can use
the reproducer).

-- 
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer

^ permalink raw reply

* Re: [bpf-next PATCH 2/2] samples/bpf: xdp_redirect_cpu load balance like Suricata
From: Daniel Borkmann @ 2018-08-09 20:15 UTC (permalink / raw)
  To: Jesper Dangaard Brouer, netdev
  Cc: Daniel Borkmann, Alexei Starovoitov, jhsiao
In-Reply-To: <153382118685.1066.13384325128020314152.stgit@firesoul>

On 08/09/2018 03:26 PM, Jesper Dangaard Brouer wrote:
> This implement XDP CPU redirection load-balancing across available
> CPUs, based on the hashing IP-pairs + L4-protocol.  This equivalent to
> xdp-cpu-redirect feature in Suricata, which is inspired by the
> Suricata 'ippair' hashing code.
> 
> An important property is that the hashing is flow symmetric, meaning
> that if the source and destination gets swapped then the selected CPU
> will remain the same.  This is helps locality by placing both directions
> of a flows on the same CPU, in a forwarding/routing scenario.
> 
> The hashing INITVAL (15485863 the 10^6th prime number) was fairly
> arbitrary choosen, but experiments with kernel tree pktgen scripts
> (pktgen_sample04_many_flows.sh +pktgen_sample05_flow_per_thread.sh)
> showed this improved the distribution.
> 
> This patch also change the default loaded XDP program to be this
> load-balancer.  As based on different user feedback, this seems to be
> the expected behavior of the sample xdp_redirect_cpu.
> 
> Link: https://github.com/OISF/suricata/commit/796ec08dd7a63
> Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
> ---
>  samples/bpf/xdp_redirect_cpu_kern.c |  103 +++++++++++++++++++++++++++++++++++
>  samples/bpf/xdp_redirect_cpu_user.c |    4 +
>  2 files changed, 105 insertions(+), 2 deletions(-)
> 
> diff --git a/samples/bpf/xdp_redirect_cpu_kern.c b/samples/bpf/xdp_redirect_cpu_kern.c
> index 0cc3d71057f0..a306d1c75622 100644
> --- a/samples/bpf/xdp_redirect_cpu_kern.c
> +++ b/samples/bpf/xdp_redirect_cpu_kern.c
> @@ -13,6 +13,7 @@
>  
>  #include <uapi/linux/bpf.h>
>  #include "bpf_helpers.h"
> +#include "hash_func01.h"
>  
>  #define MAX_CPUS 64 /* WARNING - sync with _user.c */

Hmm, this doesn't apply cleanly. I have the following in bpf-next:

#define MAX_CPUS 12 /* WARNING - sync with _user.c */

https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/tree/samples/bpf/xdp_redirect_cpu_kern.c#n17

Rebase issue? Please respin, thanks.

^ permalink raw reply

* Re: [net PATCH 0/3] Fix two teardown bugs for BPF maps cpumap and devmap
From: Daniel Borkmann @ 2018-08-09 19:54 UTC (permalink / raw)
  To: Jesper Dangaard Brouer, netdev
  Cc: Daniel Borkmann, Alexei Starovoitov, jhsiao
In-Reply-To: <153376197849.14272.8201612461878004477.stgit@firesoul>

On 08/08/2018 11:00 PM, Jesper Dangaard Brouer wrote:
> Removing entries from cpumap and devmap, goes through a number of
> syncronization steps to make sure no new xdp_frames can be enqueued.
> But there is a small chance, that xdp_frames remains which have not
> been flushed/processed yet.  Flushing these during teardown, happens
> from RCU context and not as usual under RX NAPI context.
> 
> The optimization introduced in commt 389ab7f01af9 ("xdp: introduce
> xdp_return_frame_rx_napi"), missed that the flush operation can also
> be called from RCU context.  Thus, we cannot always use the
> xdp_return_frame_rx_napi call, which take advantage of the protection
> provided by XDP RX running under NAPI protection.
> 
> The samples/bpf xdp_redirect_cpu have a --stress-mode, that is
> adjusted to easier reproduce (verified by Red Hat QA).

Applied to bpf, thanks Jesper!

^ permalink raw reply

* Re: [PATCH bpf] bpf: fix bpffs non-array map seq_show issue
From: Daniel Borkmann @ 2018-08-09 19:44 UTC (permalink / raw)
  To: Yonghong Song, Alexei Starovoitov
  Cc: ast, netdev, kernel-team, jakub.kicinski
In-Reply-To: <ad36fdca-5e65-e574-027c-ae363b5f95d4@fb.com>

On 08/09/2018 07:54 PM, Yonghong Song wrote:
> On 8/9/18 10:02 AM, Daniel Borkmann wrote:
>> On 08/09/2018 06:55 PM, Yonghong Song wrote:
>>> On 8/9/18 8:59 AM, Daniel Borkmann wrote:
>>>> On 08/09/2018 05:15 PM, Yonghong Song wrote:
>>>>> On 8/9/18 7:24 AM, Daniel Borkmann wrote:
>>>>>> On 08/09/2018 05:55 AM, Yonghong Song wrote:
>>>>>>> On 8/8/18 7:25 PM, Alexei Starovoitov wrote:
>>>>>>>> On Wed, Aug 08, 2018 at 06:25:19PM -0700, Yonghong Song wrote:
>>>>>>>>> In function map_seq_next() of kernel/bpf/inode.c,
>>>>>>>>> the first key will be the "0" regardless of the map type.
>>>>>>>>> This works for array. But for hash type, if it happens
>>>>>>>>> key "0" is in the map, the bpffs map show will miss
>>>>>>>>> some items if the key "0" is not the first element of
>>>>>>>>> the first bucket.
>>>>>>>>>
>>>>>>>>> This patch fixed the issue by guaranteeing to get
>>>>>>>>> the first element, if the seq_show is just started,
>>>>>>>>> by passing NULL pointer key to map_get_next_key() callback.
>>>>>>>>> This way, no missing elements will occur for
>>>>>>>>> bpffs hash table show even if key "0" is in the map.
>>>>>>>
>>>>>>> Currently, map_seq_show_elem callback is only implemented
>>>>>>> for arraymap. So the problem actually is not exposed.
>>>>>>>
>>>>>>> The issue is discovered when I tried to implement
>>>>>>> map_seq_show_elem for hash maps, and I will have followup
>>>>>>> patches for it.
>>>>
>>>> Btw, on that note, I would also prefer if we could decouple
>>>> BTF from the map_seq_show_elem() as there is really no reason
>>>> to have it on a per-map. I had a patch below which would enable
>>>> it for all map types generically, and bpftool works out of the
>>>> box for it. Also, array doesn't really have to be 'int' type
>>>> enforced as long as it's some data structure with 4 bytes, it's
>>>> all fine, so this can be made fully generic (we only eventually
>>>> care about the match in size).
>>>
>>> I agree with a generic map_check_btf as mostly we only care about size
>>> and this change should enable btftool btf based pretty print for hash/lru_hash tables.
>>
>> Yep, agree, the below output from bpftool is from test_xdp_noinline.o
>> where both work with it.
>>
>>>>   From 0a8be27cbc2ac0c6fc2632865b5afe37222a1fc7 Mon Sep 17 00:00:00 2001
>>>> Message-Id: <0a8be27cbc2ac0c6fc2632865b5afe37222a1fc7.1533830053.git.daniel@iogearbox.net>
>>>> From: Daniel Borkmann <daniel@iogearbox.net>
>>>> Date: Thu, 9 Aug 2018 16:50:21 +0200
>>>> Subject: [PATCH bpf-next] bpf, btf: enable for all maps
>>>>
>>>> # bpftool m dump id 19
>>>> [{
>>>>           "key": {
>>>>               "": {
>>>>                   "vip": 0,
>>>>                   "vipv6": []
>>>>               },
>>>>               "port": 0,
>>>>               "family": 0,
>>>>               "proto": 0
>>>>           },
>>>>           "value": {
>>>>               "flags": 0,
>>>>               "vip_num": 0
>>>>           }
>>>>       }
>>>> ]
>>>>
>>>> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
>>>> ---
>>>>    include/linux/bpf.h   |  4 +---
>>>>    kernel/bpf/arraymap.c | 27 ---------------------------
>>>>    kernel/bpf/inode.c    |  3 ++-
>>>>    kernel/bpf/syscall.c  | 24 ++++++++++++++++++++----
>>>>    4 files changed, 23 insertions(+), 35 deletions(-)
>>>>
>>>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>>>> index cd8790d..91aa4be 100644
>>>> --- a/include/linux/bpf.h
>>>> +++ b/include/linux/bpf.h
>>>> @@ -48,8 +48,6 @@ struct bpf_map_ops {
>>>>        u32 (*map_fd_sys_lookup_elem)(void *ptr);
>>>>        void (*map_seq_show_elem)(struct bpf_map *map, void *key,
>>>>                      struct seq_file *m);
>>>> -    int (*map_check_btf)(const struct bpf_map *map, const struct btf *btf,
>>>> -                 u32 key_type_id, u32 value_type_id);
>>>>    };
>>>>
>>>>    struct bpf_map {
>>>> @@ -118,7 +116,7 @@ static inline bool bpf_map_offload_neutral(const struct bpf_map *map)
>>>>
>>>>    static inline bool bpf_map_support_seq_show(const struct bpf_map *map)
>>>>    {
>>>> -    return map->ops->map_seq_show_elem && map->ops->map_check_btf;
>>>> +    return map->ops->map_seq_show_elem;
>>>>    }
>>>>
>>>>    extern const struct bpf_map_ops bpf_map_offload_ops;
>>>> diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
>>>> index 2aa55d030..67f0bdf 100644
>>>> --- a/kernel/bpf/arraymap.c
>>>> +++ b/kernel/bpf/arraymap.c
>>>> @@ -358,32 +358,6 @@ static void array_map_seq_show_elem(struct bpf_map *map, void *key,
>>>>        rcu_read_unlock();
>>>>    }
>>>>
>>>> -static int array_map_check_btf(const struct bpf_map *map, const struct btf *btf,
>>>> -                   u32 btf_key_id, u32 btf_value_id)
>>>> -{
>>>> -    const struct btf_type *key_type, *value_type;
>>>> -    u32 key_size, value_size;
>>>> -    u32 int_data;
>>>> -
>>>> -    key_type = btf_type_id_size(btf, &btf_key_id, &key_size);
>>>> -    if (!key_type || BTF_INFO_KIND(key_type->info) != BTF_KIND_INT)
>>>> -        return -EINVAL;
>>>> -
>>>> -    int_data = *(u32 *)(key_type + 1);
>>>> -    /* bpf array can only take a u32 key.  This check makes
>>>> -     * sure that the btf matches the attr used during map_create.
>>>> -     */
>>>> -    if (BTF_INT_BITS(int_data) != 32 || key_size != 4 ||
>>>> -        BTF_INT_OFFSET(int_data))
>>>> -        return -EINVAL;
>>>> -
>>>> -    value_type = btf_type_id_size(btf, &btf_value_id, &value_size);
>>>> -    if (!value_type || value_size != map->value_size)
>>>> -        return -EINVAL;
>>>> -
>>>> -    return 0;
>>>> -}
>>>> -
>>>>    const struct bpf_map_ops array_map_ops = {
>>>>        .map_alloc_check = array_map_alloc_check,
>>>>        .map_alloc = array_map_alloc,
>>>> @@ -394,7 +368,6 @@ const struct bpf_map_ops array_map_ops = {
>>>>        .map_delete_elem = array_map_delete_elem,
>>>>        .map_gen_lookup = array_map_gen_lookup,
>>>>        .map_seq_show_elem = array_map_seq_show_elem,
>>>> -    .map_check_btf = array_map_check_btf,
>>>>    };
>>>>
>>>>    const struct bpf_map_ops percpu_array_map_ops = {
>>>> diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
>>>> index 76efe9a..400f27d 100644
>>>> --- a/kernel/bpf/inode.c
>>>> +++ b/kernel/bpf/inode.c
>>>> @@ -332,7 +332,8 @@ static int bpf_mkmap(struct dentry *dentry, umode_t mode, void *arg)
>>>>        struct bpf_map *map = arg;
>>>>
>>>>        return bpf_mkobj_ops(dentry, mode, arg, &bpf_map_iops,
>>>> -                 map->btf ? &bpffs_map_fops : &bpffs_obj_fops);
>>>> +                 bpf_map_support_seq_show(map) ?
>>>> +                 &bpffs_map_fops : &bpffs_obj_fops);
>>>
>>> There are an issue here, the condition bpf_map_support_seq_show(map) may not be enough since the map specific implementation assumes availability of btf and proper map key/value btf_type_id's.
>>> We can either use
>>>      map->btf && bpf_map_support_seq_show(map)
>>> condition here, or check map->btf in each individual implementation
>>> of map_support_seq_show().
>>
>> Good, point, agree. Will fix and cook proper patch later today.
> 
> Sounds good. i will wait until this gets merged and then resubmit.

Ok, just flushed it out. Thanks!

^ permalink raw reply

* [PATCH bpf-next] bpf: enable btf for use in all maps
From: Daniel Borkmann @ 2018-08-09 19:42 UTC (permalink / raw)
  To: ast; +Cc: netdev, yhs, Daniel Borkmann

Commit a26ca7c982cb ("bpf: btf: Add pretty print support to
the basic arraymap") enabled support for BTF and dumping via
BPF fs for arraymap. However, both can be decoupled from each
other such that all BPF maps can be supported for attaching
BTF key/value information, while not all maps necessarily
need to dump via map_seq_show_elem() callback.

The check in array_map_check_btf() can be generalized as
ultimatively the key and value size is the only contraint
that needs to match for the map. The fact that the key needs
to be of type int is optional; it could be any data type as
long as it matches the 4 byte key size, just like hash table
key or others could be of any data type as well.

Minimal example of a hash table dump which then works out
of the box for bpftool:

  # bpftool map dump id 19
  [{
          "key": {
              "": {
                  "vip": 0,
                  "vipv6": []
              },
              "port": 0,
              "family": 0,
              "proto": 0
          },
          "value": {
              "flags": 0,
              "vip_num": 0
          }
      }
  ]

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Cc: Yonghong Song <yhs@fb.com>
---
 include/linux/bpf.h   |  4 +---
 kernel/bpf/arraymap.c | 27 ---------------------------
 kernel/bpf/inode.c    |  3 ++-
 kernel/bpf/syscall.c  | 24 ++++++++++++++++++++----
 4 files changed, 23 insertions(+), 35 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index cd8790d..eb76e8e 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -48,8 +48,6 @@ struct bpf_map_ops {
 	u32 (*map_fd_sys_lookup_elem)(void *ptr);
 	void (*map_seq_show_elem)(struct bpf_map *map, void *key,
 				  struct seq_file *m);
-	int (*map_check_btf)(const struct bpf_map *map, const struct btf *btf,
-			     u32 key_type_id, u32 value_type_id);
 };
 
 struct bpf_map {
@@ -118,7 +116,7 @@ static inline bool bpf_map_offload_neutral(const struct bpf_map *map)
 
 static inline bool bpf_map_support_seq_show(const struct bpf_map *map)
 {
-	return map->ops->map_seq_show_elem && map->ops->map_check_btf;
+	return map->btf && map->ops->map_seq_show_elem;
 }
 
 extern const struct bpf_map_ops bpf_map_offload_ops;
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 2aa55d030..67f0bdf 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -358,32 +358,6 @@ static void array_map_seq_show_elem(struct bpf_map *map, void *key,
 	rcu_read_unlock();
 }
 
-static int array_map_check_btf(const struct bpf_map *map, const struct btf *btf,
-			       u32 btf_key_id, u32 btf_value_id)
-{
-	const struct btf_type *key_type, *value_type;
-	u32 key_size, value_size;
-	u32 int_data;
-
-	key_type = btf_type_id_size(btf, &btf_key_id, &key_size);
-	if (!key_type || BTF_INFO_KIND(key_type->info) != BTF_KIND_INT)
-		return -EINVAL;
-
-	int_data = *(u32 *)(key_type + 1);
-	/* bpf array can only take a u32 key.  This check makes
-	 * sure that the btf matches the attr used during map_create.
-	 */
-	if (BTF_INT_BITS(int_data) != 32 || key_size != 4 ||
-	    BTF_INT_OFFSET(int_data))
-		return -EINVAL;
-
-	value_type = btf_type_id_size(btf, &btf_value_id, &value_size);
-	if (!value_type || value_size != map->value_size)
-		return -EINVAL;
-
-	return 0;
-}
-
 const struct bpf_map_ops array_map_ops = {
 	.map_alloc_check = array_map_alloc_check,
 	.map_alloc = array_map_alloc,
@@ -394,7 +368,6 @@ const struct bpf_map_ops array_map_ops = {
 	.map_delete_elem = array_map_delete_elem,
 	.map_gen_lookup = array_map_gen_lookup,
 	.map_seq_show_elem = array_map_seq_show_elem,
-	.map_check_btf = array_map_check_btf,
 };
 
 const struct bpf_map_ops percpu_array_map_ops = {
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
index 76efe9a..400f27d 100644
--- a/kernel/bpf/inode.c
+++ b/kernel/bpf/inode.c
@@ -332,7 +332,8 @@ static int bpf_mkmap(struct dentry *dentry, umode_t mode, void *arg)
 	struct bpf_map *map = arg;
 
 	return bpf_mkobj_ops(dentry, mode, arg, &bpf_map_iops,
-			     map->btf ? &bpffs_map_fops : &bpffs_obj_fops);
+			     bpf_map_support_seq_show(map) ?
+			     &bpffs_map_fops : &bpffs_obj_fops);
 }
 
 static struct dentry *
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 5af4e9e..0b6f6e8 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -455,6 +455,23 @@ static int bpf_obj_name_cpy(char *dst, const char *src)
 	return 0;
 }
 
+static int map_check_btf(const struct bpf_map *map, const struct btf *btf,
+			 u32 btf_key_id, u32 btf_value_id)
+{
+	const struct btf_type *key_type, *value_type;
+	u32 key_size, value_size;
+
+	key_type = btf_type_id_size(btf, &btf_key_id, &key_size);
+	if (!key_type || key_size != map->key_size)
+		return -EINVAL;
+
+	value_type = btf_type_id_size(btf, &btf_value_id, &value_size);
+	if (!value_type || value_size != map->value_size)
+		return -EINVAL;
+
+	return 0;
+}
+
 #define BPF_MAP_CREATE_LAST_FIELD btf_value_type_id
 /* called via syscall */
 static int map_create(union bpf_attr *attr)
@@ -489,8 +506,7 @@ static int map_create(union bpf_attr *attr)
 	atomic_set(&map->refcnt, 1);
 	atomic_set(&map->usercnt, 1);
 
-	if (bpf_map_support_seq_show(map) &&
-	    (attr->btf_key_type_id || attr->btf_value_type_id)) {
+	if (attr->btf_key_type_id || attr->btf_value_type_id) {
 		struct btf *btf;
 
 		if (!attr->btf_key_type_id || !attr->btf_value_type_id) {
@@ -504,8 +520,8 @@ static int map_create(union bpf_attr *attr)
 			goto free_map_nouncharge;
 		}
 
-		err = map->ops->map_check_btf(map, btf, attr->btf_key_type_id,
-					      attr->btf_value_type_id);
+		err = map_check_btf(map, btf, attr->btf_key_type_id,
+				    attr->btf_value_type_id);
 		if (err) {
 			btf_put(btf);
 			goto free_map_nouncharge;
-- 
2.9.5

^ permalink raw reply related

* [PATCH v1 net-next] lan743x: lan743x: Add PTP support
From: Bryan Whitehead @ 2018-08-09 19:36 UTC (permalink / raw)
  To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran

PTP support includes:
    Ingress, and egress timestamping.
    One step timestamping available.
    PTP clock support.
    Periodic output support.

Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
---
 drivers/net/ethernet/microchip/Makefile          |    2 +-
 drivers/net/ethernet/microchip/lan743x_ethtool.c |   27 +
 drivers/net/ethernet/microchip/lan743x_main.c    |   78 +-
 drivers/net/ethernet/microchip/lan743x_main.h    |  101 +-
 drivers/net/ethernet/microchip/lan743x_ptp.c     | 1164 ++++++++++++++++++++++
 drivers/net/ethernet/microchip/lan743x_ptp.h     |   76 ++
 6 files changed, 1443 insertions(+), 5 deletions(-)
 create mode 100644 drivers/net/ethernet/microchip/lan743x_ptp.c
 create mode 100644 drivers/net/ethernet/microchip/lan743x_ptp.h

diff --git a/drivers/net/ethernet/microchip/Makefile b/drivers/net/ethernet/microchip/Makefile
index 43f47cb..538926d 100644
--- a/drivers/net/ethernet/microchip/Makefile
+++ b/drivers/net/ethernet/microchip/Makefile
@@ -6,4 +6,4 @@ obj-$(CONFIG_ENC28J60) += enc28j60.o
 obj-$(CONFIG_ENCX24J600) += encx24j600.o encx24j600-regmap.o
 obj-$(CONFIG_LAN743X) += lan743x.o
 
-lan743x-objs := lan743x_main.o lan743x_ethtool.o
+lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o
diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
index c25b3e9..07c1eb6 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -4,6 +4,7 @@
 #include <linux/netdevice.h>
 #include "lan743x_main.h"
 #include "lan743x_ethtool.h"
+#include <linux/net_tstamp.h>
 #include <linux/pci.h>
 #include <linux/phy.h>
 
@@ -542,6 +543,31 @@ static int lan743x_ethtool_set_rxfh(struct net_device *netdev,
 	return 0;
 }
 
+static int lan743x_ethtool_get_ts_info(struct net_device *netdev,
+				       struct ethtool_ts_info *ts_info)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+	ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
+				   SOF_TIMESTAMPING_RX_SOFTWARE |
+				   SOF_TIMESTAMPING_SOFTWARE |
+				   SOF_TIMESTAMPING_TX_HARDWARE |
+				   SOF_TIMESTAMPING_RX_HARDWARE |
+				   SOF_TIMESTAMPING_RAW_HARDWARE;
+
+	if (adapter->ptp.ptp_clock)
+		ts_info->phc_index = ptp_clock_index(adapter->ptp.ptp_clock);
+	else
+		ts_info->phc_index = -1;
+
+	ts_info->tx_types = BIT(HWTSTAMP_TX_OFF) |
+			    BIT(HWTSTAMP_TX_ON) |
+			    BIT(HWTSTAMP_TX_ONESTEP_SYNC);
+	ts_info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
+			      BIT(HWTSTAMP_FILTER_ALL);
+	return 0;
+}
+
 static int lan743x_ethtool_get_eee(struct net_device *netdev,
 				   struct ethtool_eee *eee)
 {
@@ -685,6 +711,7 @@ const struct ethtool_ops lan743x_ethtool_ops = {
 	.get_rxfh_indir_size = lan743x_ethtool_get_rxfh_indir_size,
 	.get_rxfh = lan743x_ethtool_get_rxfh,
 	.set_rxfh = lan743x_ethtool_set_rxfh,
+	.get_ts_info = lan743x_ethtool_get_ts_info,
 	.get_eee = lan743x_ethtool_get_eee,
 	.set_eee = lan743x_ethtool_set_eee,
 	.get_link_ksettings = phy_ethtool_get_link_ksettings,
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index cd41911..48da18c 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -267,6 +267,10 @@ static void lan743x_intr_shared_isr(void *context, u32 int_sts, u32 flags)
 			lan743x_intr_software_isr(adapter);
 			int_sts &= ~INT_BIT_SW_GP_;
 		}
+		if (int_sts & INT_BIT_1588_) {
+			lan743x_ptp_isr(adapter);
+			int_sts &= ~INT_BIT_1588_;
+		}
 	}
 	if (int_sts)
 		lan743x_csr_write(adapter, INT_EN_CLR, int_sts);
@@ -976,6 +980,7 @@ static void lan743x_phy_link_status_change(struct net_device *netdev)
 					       ksettings.base.duplex,
 					       local_advertisement,
 					       remote_advertisement);
+		lan743x_ptp_update_latency(adapter, ksettings.base.speed);
 	}
 }
 
@@ -1226,6 +1231,7 @@ static void lan743x_tx_release_desc(struct lan743x_tx *tx,
 	struct lan743x_tx_buffer_info *buffer_info = NULL;
 	struct lan743x_tx_descriptor *descriptor = NULL;
 	u32 descriptor_type = 0;
+	bool ignore_sync;
 
 	descriptor = &tx->ring_cpu_ptr[descriptor_index];
 	buffer_info = &tx->buffer_info[descriptor_index];
@@ -1256,11 +1262,27 @@ static void lan743x_tx_release_desc(struct lan743x_tx *tx,
 		buffer_info->dma_ptr = 0;
 		buffer_info->buffer_length = 0;
 	}
-	if (buffer_info->skb) {
+	if (!buffer_info->skb)
+		goto clear_active;
+
+	if (!(buffer_info->flags & TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED)) {
 		dev_kfree_skb(buffer_info->skb);
-		buffer_info->skb = NULL;
+		goto clear_skb;
+	}
+
+	if (cleanup) {
+		lan743x_ptp_unrequest_tx_timestamp(tx->adapter);
+		dev_kfree_skb(buffer_info->skb);
+	} else {
+		ignore_sync = (buffer_info->flags &
+			       TX_BUFFER_INFO_FLAG_IGNORE_SYNC) != 0;
+		lan743x_ptp_tx_timestamp_skb(tx->adapter,
+					     buffer_info->skb, ignore_sync);
 	}
 
+clear_skb:
+	buffer_info->skb = NULL;
+
 clear_active:
 	buffer_info->flags &= ~TX_BUFFER_INFO_FLAG_ACTIVE;
 
@@ -1321,10 +1343,25 @@ static int lan743x_tx_get_avail_desc(struct lan743x_tx *tx)
 		return last_head - last_tail - 1;
 }
 
+void lan743x_tx_set_timestamping_mode(struct lan743x_tx *tx,
+				      bool enable_timestamping,
+				      bool enable_onestep_sync)
+{
+	if (enable_timestamping)
+		tx->ts_flags |= TX_TS_FLAG_TIMESTAMPING_ENABLED;
+	else
+		tx->ts_flags &= ~TX_TS_FLAG_TIMESTAMPING_ENABLED;
+	if (enable_onestep_sync)
+		tx->ts_flags |= TX_TS_FLAG_ONE_STEP_SYNC;
+	else
+		tx->ts_flags &= ~TX_TS_FLAG_ONE_STEP_SYNC;
+}
+
 static int lan743x_tx_frame_start(struct lan743x_tx *tx,
 				  unsigned char *first_buffer,
 				  unsigned int first_buffer_length,
 				  unsigned int frame_length,
+				  bool time_stamp,
 				  bool check_sum)
 {
 	/* called only from within lan743x_tx_xmit_frame.
@@ -1362,6 +1399,8 @@ static int lan743x_tx_frame_start(struct lan743x_tx *tx,
 		TX_DESC_DATA0_DTYPE_DATA_ |
 		TX_DESC_DATA0_FS_ |
 		TX_DESC_DATA0_FCS_;
+	if (time_stamp)
+		tx->frame_data0 |= TX_DESC_DATA0_TSE_;
 
 	if (check_sum)
 		tx->frame_data0 |= TX_DESC_DATA0_ICE_ |
@@ -1475,6 +1514,7 @@ static int lan743x_tx_frame_add_fragment(struct lan743x_tx *tx,
 
 static void lan743x_tx_frame_end(struct lan743x_tx *tx,
 				 struct sk_buff *skb,
+				 bool time_stamp,
 				 bool ignore_sync)
 {
 	/* called only from within lan743x_tx_xmit_frame
@@ -1492,6 +1532,8 @@ static void lan743x_tx_frame_end(struct lan743x_tx *tx,
 	tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
 	buffer_info = &tx->buffer_info[tx->frame_tail];
 	buffer_info->skb = skb;
+	if (time_stamp)
+		buffer_info->flags |= TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED;
 	if (ignore_sync)
 		buffer_info->flags |= TX_BUFFER_INFO_FLAG_IGNORE_SYNC;
 
@@ -1520,6 +1562,7 @@ static netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx,
 	unsigned int frame_length = 0;
 	unsigned int head_length = 0;
 	unsigned long irq_flags = 0;
+	bool do_timestamp = false;
 	bool ignore_sync = false;
 	int nr_frags = 0;
 	bool gso = false;
@@ -1541,6 +1584,14 @@ static netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx,
 	}
 
 	/* space available, transmit skb  */
+	if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+	    (tx->ts_flags & TX_TS_FLAG_TIMESTAMPING_ENABLED) &&
+	    (lan743x_ptp_request_tx_timestamp(tx->adapter))) {
+		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+		do_timestamp = true;
+		if (tx->ts_flags & TX_TS_FLAG_ONE_STEP_SYNC)
+			ignore_sync = true;
+	}
 	head_length = skb_headlen(skb);
 	frame_length = skb_pagelen(skb);
 	nr_frags = skb_shinfo(skb)->nr_frags;
@@ -1554,6 +1605,7 @@ static netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx,
 	if (lan743x_tx_frame_start(tx,
 				   skb->data, head_length,
 				   start_frame_length,
+				   do_timestamp,
 				   skb->ip_summed == CHECKSUM_PARTIAL)) {
 		dev_kfree_skb(skb);
 		goto unlock;
@@ -1581,7 +1633,7 @@ static netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx,
 	}
 
 finish:
-	lan743x_tx_frame_end(tx, skb, ignore_sync);
+	lan743x_tx_frame_end(tx, skb, do_timestamp, ignore_sync);
 
 unlock:
 	spin_unlock_irqrestore(&tx->ring_lock, irq_flags);
@@ -2410,6 +2462,8 @@ static int lan743x_netdev_close(struct net_device *netdev)
 	for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++)
 		lan743x_rx_close(&adapter->rx[index]);
 
+	lan743x_ptp_close(adapter);
+
 	lan743x_phy_close(adapter);
 
 	lan743x_mac_close(adapter);
@@ -2437,6 +2491,10 @@ static int lan743x_netdev_open(struct net_device *netdev)
 	if (ret)
 		goto close_mac;
 
+	ret = lan743x_ptp_open(adapter);
+	if (ret)
+		goto close_phy;
+
 	lan743x_rfe_open(adapter);
 
 	for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) {
@@ -2456,6 +2514,9 @@ static int lan743x_netdev_open(struct net_device *netdev)
 		if (adapter->rx[index].ring_cpu_ptr)
 			lan743x_rx_close(&adapter->rx[index]);
 	}
+	lan743x_ptp_close(adapter);
+
+close_phy:
 	lan743x_phy_close(adapter);
 
 close_mac:
@@ -2483,6 +2544,8 @@ static int lan743x_netdev_ioctl(struct net_device *netdev,
 {
 	if (!netif_running(netdev))
 		return -EINVAL;
+	if (cmd == SIOCSHWTSTAMP)
+		return lan743x_ptp_ioctl(netdev, ifr, cmd);
 	return phy_mii_ioctl(netdev->phydev, ifr, cmd);
 }
 
@@ -2607,6 +2670,11 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter,
 	adapter->intr.irq = adapter->pdev->irq;
 	lan743x_csr_write(adapter, INT_EN_CLR, 0xFFFFFFFF);
 	mutex_init(&adapter->dp_lock);
+
+	ret = lan743x_gpio_init(adapter);
+	if (ret)
+		return ret;
+
 	ret = lan743x_mac_init(adapter);
 	if (ret)
 		return ret;
@@ -2615,6 +2683,10 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter,
 	if (ret)
 		return ret;
 
+	ret = lan743x_ptp_init(adapter);
+	if (ret)
+		return ret;
+
 	lan743x_rfe_update_mac_address(adapter);
 
 	ret = lan743x_dmac_init(adapter);
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index 4fa7a5e..0e82b63 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -4,12 +4,17 @@
 #ifndef _LAN743X_H
 #define _LAN743X_H
 
+#include "lan743x_ptp.h"
+
 #define DRIVER_AUTHOR   "Bryan Whitehead <Bryan.Whitehead@microchip.com>"
 #define DRIVER_DESC "LAN743x PCIe Gigabit Ethernet Driver"
 #define DRIVER_NAME "lan743x"
 
 /* Register Definitions */
 #define ID_REV				(0x00)
+#define ID_REV_ID_MASK_			(0xFFFF0000)
+#define ID_REV_ID_LAN7430_		(0x74300000)
+#define ID_REV_ID_LAN7431_		(0x74310000)
 #define ID_REV_IS_VALID_CHIP_ID_(id_rev)	\
 	(((id_rev) & 0xFFF00000) == 0x74300000)
 #define ID_REV_CHIP_REV_MASK_		(0x0000FFFF)
@@ -62,6 +67,21 @@
 
 #define E2P_DATA			(0x044)
 
+#define GPIO_CFG0			(0x050)
+#define GPIO_CFG0_GPIO_DIR_BIT_(bit)	BIT(16 + (bit))
+#define GPIO_CFG0_GPIO_DATA_BIT_(bit)	BIT(0 + (bit))
+
+#define GPIO_CFG1			(0x054)
+#define GPIO_CFG1_GPIOEN_BIT_(bit)	BIT(16 + (bit))
+#define GPIO_CFG1_GPIOBUF_BIT_(bit)	BIT(0 + (bit))
+
+#define GPIO_CFG2			(0x058)
+#define GPIO_CFG2_1588_POL_BIT_(bit)	BIT(0 + (bit))
+
+#define GPIO_CFG3			(0x05C)
+#define GPIO_CFG3_1588_CH_SEL_BIT_(bit)	BIT(16 + (bit))
+#define GPIO_CFG3_1588_OE_BIT_(bit)	BIT(0 + (bit))
+
 #define FCT_RX_CTL			(0xAC)
 #define FCT_RX_CTL_EN_(channel)		BIT(28 + (channel))
 #define FCT_RX_CTL_DIS_(channel)	BIT(24 + (channel))
@@ -193,7 +213,8 @@
 #define INT_BIT_DMA_TX_(channel)	BIT(16 + (channel))
 #define INT_BIT_ALL_TX_			(0x000F0000)
 #define INT_BIT_SW_GP_			BIT(9)
-#define INT_BIT_ALL_OTHER_		(0x00000280)
+#define INT_BIT_1588_			BIT(7)
+#define INT_BIT_ALL_OTHER_		(INT_BIT_SW_GP_ | INT_BIT_1588_)
 #define INT_BIT_MAS_			BIT(0)
 
 #define INT_SET				(0x784)
@@ -234,6 +255,71 @@
 #define INT_MOD_CFG6			(0x7D8)
 #define INT_MOD_CFG7			(0x7DC)
 
+#define PTP_CMD_CTL					(0x0A00)
+#define PTP_CMD_CTL_PTP_CLK_STP_NSEC_			BIT(6)
+#define PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_			BIT(5)
+#define PTP_CMD_CTL_PTP_CLOCK_LOAD_			BIT(4)
+#define PTP_CMD_CTL_PTP_CLOCK_READ_			BIT(3)
+#define PTP_CMD_CTL_PTP_ENABLE_				BIT(2)
+#define PTP_CMD_CTL_PTP_DISABLE_			BIT(1)
+#define PTP_CMD_CTL_PTP_RESET_				BIT(0)
+#define PTP_GENERAL_CONFIG				(0x0A04)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_(channel) \
+	(0x7 << (1 + ((channel) << 2)))
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_	(0)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_	(1)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_	(2)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_	(3)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_	(4)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_	(5)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_(channel, value) \
+	(((value) & 0x7) << (1 + ((channel) << 2)))
+#define PTP_GENERAL_CONFIG_RELOAD_ADD_X_(channel)	(BIT((channel) << 2))
+
+#define PTP_INT_STS				(0x0A08)
+#define PTP_INT_EN_SET				(0x0A0C)
+#define PTP_INT_EN_CLR				(0x0A10)
+#define PTP_INT_BIT_TX_SWTS_ERR_		BIT(13)
+#define PTP_INT_BIT_TX_TS_			BIT(12)
+#define PTP_INT_BIT_TIMER_B_			BIT(1)
+#define PTP_INT_BIT_TIMER_A_			BIT(0)
+
+#define PTP_CLOCK_SEC				(0x0A14)
+#define PTP_CLOCK_NS				(0x0A18)
+#define PTP_CLOCK_SUBNS				(0x0A1C)
+#define PTP_CLOCK_RATE_ADJ			(0x0A20)
+#define PTP_CLOCK_RATE_ADJ_DIR_			BIT(31)
+#define PTP_CLOCK_STEP_ADJ			(0x0A2C)
+#define PTP_CLOCK_STEP_ADJ_DIR_			BIT(31)
+#define PTP_CLOCK_STEP_ADJ_VALUE_MASK_		(0x3FFFFFFF)
+#define PTP_CLOCK_TARGET_SEC_X(channel)		(0x0A30 + ((channel) << 4))
+#define PTP_CLOCK_TARGET_NS_X(channel)		(0x0A34 + ((channel) << 4))
+#define PTP_CLOCK_TARGET_RELOAD_SEC_X(channel)	(0x0A38 + ((channel) << 4))
+#define PTP_CLOCK_TARGET_RELOAD_NS_X(channel)	(0x0A3C + ((channel) << 4))
+#define PTP_LATENCY				(0x0A5C)
+#define PTP_LATENCY_TX_SET_(tx_latency)		(((u32)(tx_latency)) << 16)
+#define PTP_LATENCY_RX_SET_(rx_latency)		\
+	(((u32)(rx_latency)) & 0x0000FFFF)
+#define PTP_CAP_INFO				(0x0A60)
+#define PTP_CAP_INFO_TX_TS_CNT_GET_(reg_val)	(((reg_val) & 0x00000070) >> 4)
+
+#define PTP_TX_MOD				(0x0AA4)
+#define PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_	(0x10000000)
+
+#define PTP_TX_MOD2				(0x0AA8)
+#define PTP_TX_MOD2_TX_PTP_CLR_UDPV4_CHKSUM_	(0x00000001)
+
+#define PTP_TX_EGRESS_SEC			(0x0AAC)
+#define PTP_TX_EGRESS_NS			(0x0AB0)
+#define PTP_TX_EGRESS_NS_CAPTURE_CAUSE_MASK_	(0xC0000000)
+#define PTP_TX_EGRESS_NS_CAPTURE_CAUSE_AUTO_	(0x00000000)
+#define PTP_TX_EGRESS_NS_CAPTURE_CAUSE_SW_	(0x40000000)
+#define PTP_TX_EGRESS_NS_TS_NS_MASK_		(0x3FFFFFFF)
+
+#define PTP_TX_MSG_HEADER			(0x0AB4)
+#define PTP_TX_MSG_HEADER_MSG_TYPE_		(0x000F0000)
+#define PTP_TX_MSG_HEADER_MSG_TYPE_SYNC_	(0x00000000)
+
 #define DMAC_CFG				(0xC00)
 #define DMAC_CFG_COAL_EN_			BIT(16)
 #define DMAC_CFG_CH_ARB_SEL_RX_HIGH_		(0x00000000)
@@ -542,8 +628,12 @@ struct lan743x_tx_buffer_info;
 
 #define TX_FRAME_FLAG_IN_PROGRESS	BIT(0)
 
+#define TX_TS_FLAG_TIMESTAMPING_ENABLED	BIT(0)
+#define TX_TS_FLAG_ONE_STEP_SYNC	BIT(1)
+
 struct lan743x_tx {
 	struct lan743x_adapter *adapter;
+	u32	ts_flags;
 	u32	vector_flags;
 	int	channel_number;
 
@@ -570,6 +660,10 @@ struct lan743x_tx {
 	struct sk_buff *overflow_skb;
 };
 
+void lan743x_tx_set_timestamping_mode(struct lan743x_tx *tx,
+				      bool enable_timestamping,
+				      bool enable_onestep_sync);
+
 /* RX */
 struct lan743x_rx_descriptor;
 struct lan743x_rx_buffer_info;
@@ -610,6 +704,9 @@ struct lan743x_adapter {
 	/* lock, used to prevent concurrent access to data port */
 	struct mutex		dp_lock;
 
+	struct lan743x_gpio	gpio;
+	struct lan743x_ptp	ptp;
+
 	u8			mac_address[ETH_ALEN];
 
 	struct lan743x_phy      phy;
@@ -660,6 +757,7 @@ struct lan743x_adapter {
 #define TX_DESC_DATA0_IPE_			(0x00200000)
 #define TX_DESC_DATA0_TPE_			(0x00100000)
 #define TX_DESC_DATA0_FCS_			(0x00020000)
+#define TX_DESC_DATA0_TSE_			(0x00010000)
 #define TX_DESC_DATA0_BUF_LENGTH_MASK_		(0x0000FFFF)
 #define TX_DESC_DATA0_EXT_LSO_			(0x00200000)
 #define TX_DESC_DATA0_EXT_PAY_LENGTH_MASK_	(0x000FFFFF)
@@ -673,6 +771,7 @@ struct lan743x_tx_descriptor {
 } __aligned(DEFAULT_DMA_DESCRIPTOR_SPACING);
 
 #define TX_BUFFER_INFO_FLAG_ACTIVE		BIT(0)
+#define TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED	BIT(1)
 #define TX_BUFFER_INFO_FLAG_IGNORE_SYNC		BIT(2)
 #define TX_BUFFER_INFO_FLAG_SKB_FRAGMENT	BIT(3)
 struct lan743x_tx_buffer_info {
diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.c b/drivers/net/ethernet/microchip/lan743x_ptp.c
new file mode 100644
index 0000000..42064fd
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan743x_ptp.c
@@ -0,0 +1,1164 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (C) 2018 Microchip Technology Inc. */
+
+#include <linux/netdevice.h>
+#include "lan743x_main.h"
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/net_tstamp.h>
+
+#include "lan743x_ptp.h"
+
+#define LAN743X_NUMBER_OF_GPIO			(12)
+#define LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB		(31249999)
+#define LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM	(2047999934)
+
+static bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter);
+static void lan743x_ptp_enable(struct lan743x_adapter *adapter);
+static void lan743x_ptp_disable(struct lan743x_adapter *adapter);
+static void lan743x_ptp_reset(struct lan743x_adapter *adapter);
+static void lan743x_ptp_clock_set(struct lan743x_adapter *adapter,
+				  u32 seconds, u32 nano_seconds,
+				  u32 sub_nano_seconds);
+
+int lan743x_gpio_init(struct lan743x_adapter *adapter)
+{
+	struct lan743x_gpio *gpio = &adapter->gpio;
+
+	spin_lock_init(&gpio->gpio_lock);
+
+	gpio->gpio_cfg0 = 0; /* set all direction to input, data = 0 */
+	gpio->gpio_cfg1 = 0x0FFF0000;/* disable all gpio, set to open drain */
+	gpio->gpio_cfg2 = 0;/* set all to 1588 low polarity level */
+	gpio->gpio_cfg3 = 0;/* disable all 1588 output */
+	lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
+	lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
+	lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2);
+	lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3);
+
+	return 0;
+}
+
+static void lan743x_ptp_wait_till_cmd_done(struct lan743x_adapter *adapter,
+					   u32 bit_mask)
+{
+	int timeout = 1000;
+	u32 data = 0;
+
+	while (timeout &&
+	       (data = (lan743x_csr_read(adapter, PTP_CMD_CTL) &
+	       bit_mask))) {
+		usleep_range(1000, 20000);
+		timeout--;
+	}
+	if (data) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "timeout waiting for cmd to be done, cmd = 0x%08X\n",
+			  bit_mask);
+	}
+}
+
+static void lan743x_ptp_tx_ts_enqueue_ts(struct lan743x_adapter *adapter,
+					 u32 seconds, u32 nano_seconds,
+					 u32 header)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	spin_lock_bh(&ptp->tx_ts_lock);
+	if (ptp->tx_ts_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
+		ptp->tx_ts_seconds_queue[ptp->tx_ts_queue_size] = seconds;
+		ptp->tx_ts_nseconds_queue[ptp->tx_ts_queue_size] = nano_seconds;
+		ptp->tx_ts_header_queue[ptp->tx_ts_queue_size] = header;
+		ptp->tx_ts_queue_size++;
+	} else {
+		netif_err(adapter, drv, adapter->netdev,
+			  "tx ts queue overflow\n");
+	}
+	spin_unlock_bh(&ptp->tx_ts_lock);
+}
+
+static void lan743x_ptp_tx_ts_complete(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	struct skb_shared_hwtstamps tstamps;
+	u32 header, nseconds, seconds;
+	bool ignore_sync = false;
+	struct sk_buff *skb;
+	int c, i;
+
+	spin_lock_bh(&ptp->tx_ts_lock);
+	c = ptp->tx_ts_skb_queue_size;
+
+	if (c > ptp->tx_ts_queue_size)
+		c = ptp->tx_ts_queue_size;
+	if (c <= 0)
+		goto done;
+
+	for (i = 0; i < c; i++) {
+		ignore_sync = ((ptp->tx_ts_ignore_sync_queue &
+				BIT(i)) != 0);
+		skb = ptp->tx_ts_skb_queue[i];
+		nseconds = ptp->tx_ts_nseconds_queue[i];
+		seconds = ptp->tx_ts_seconds_queue[i];
+		header = ptp->tx_ts_header_queue[i];
+
+		memset(&tstamps, 0, sizeof(tstamps));
+		tstamps.hwtstamp = ktime_set(seconds, nseconds);
+		if (!ignore_sync ||
+		    ((header & PTP_TX_MSG_HEADER_MSG_TYPE_) !=
+		    PTP_TX_MSG_HEADER_MSG_TYPE_SYNC_))
+			skb_tstamp_tx(skb, &tstamps);
+
+		dev_kfree_skb(skb);
+
+		ptp->tx_ts_skb_queue[i] = NULL;
+		ptp->tx_ts_seconds_queue[i] = 0;
+		ptp->tx_ts_nseconds_queue[i] = 0;
+		ptp->tx_ts_header_queue[i] = 0;
+	}
+
+	/* shift queue */
+	ptp->tx_ts_ignore_sync_queue >>= c;
+	for (i = c; i < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS; i++) {
+		ptp->tx_ts_skb_queue[i - c] = ptp->tx_ts_skb_queue[i];
+		ptp->tx_ts_seconds_queue[i - c] = ptp->tx_ts_seconds_queue[i];
+		ptp->tx_ts_nseconds_queue[i - c] = ptp->tx_ts_nseconds_queue[i];
+		ptp->tx_ts_header_queue[i - c] = ptp->tx_ts_header_queue[i];
+
+		ptp->tx_ts_skb_queue[i] = NULL;
+		ptp->tx_ts_seconds_queue[i] = 0;
+		ptp->tx_ts_nseconds_queue[i] = 0;
+		ptp->tx_ts_header_queue[i] = 0;
+	}
+	ptp->tx_ts_skb_queue_size -= c;
+	ptp->tx_ts_queue_size -= c;
+done:
+	ptp->pending_tx_timestamps -= c;
+	spin_unlock_bh(&ptp->tx_ts_lock);
+}
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptp_reserve_event_ch(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	int result = -ENODEV;
+	int index = 0;
+
+	mutex_lock(&ptp->command_lock);
+	for (index = 0; index < LAN743X_PTP_NUMBER_OF_EVENT_CHANNELS; index++) {
+		if (!(test_bit(index, &ptp->used_event_ch))) {
+			ptp->used_event_ch |= BIT(index);
+			result = index;
+			break;
+		}
+	}
+	mutex_unlock(&ptp->command_lock);
+	return result;
+}
+
+static void lan743x_ptp_release_event_ch(struct lan743x_adapter *adapter,
+					 int event_channel)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	mutex_lock(&ptp->command_lock);
+	if (test_bit(event_channel, &ptp->used_event_ch)) {
+		ptp->used_event_ch &= ~BIT(event_channel);
+	} else {
+		netif_warn(adapter, drv, adapter->netdev,
+			   "attempted release on a not used event_channel = %d\n",
+			   event_channel);
+	}
+	mutex_unlock(&ptp->command_lock);
+}
+
+static void lan743x_ptp_clock_get(struct lan743x_adapter *adapter,
+				  u32 *seconds, u32 *nano_seconds,
+				  u32 *sub_nano_seconds);
+static void lan743x_ptp_clock_step(struct lan743x_adapter *adapter,
+				   s64 time_step_ns);
+
+static int lan743x_gpio_rsrv_ptp_out(struct lan743x_adapter *adapter,
+				     int bit, int ptp_channel)
+{
+	struct lan743x_gpio *gpio = &adapter->gpio;
+	unsigned long irq_flags = 0;
+	int bit_mask = BIT(bit);
+	int ret = -EBUSY;
+
+	spin_lock_irqsave(&gpio->gpio_lock, irq_flags);
+
+	if (!(gpio->used_bits & bit_mask)) {
+		gpio->used_bits |= bit_mask;
+		gpio->output_bits |= bit_mask;
+		gpio->ptp_bits |= bit_mask;
+
+		/* set as output, and zero initial value */
+		gpio->gpio_cfg0 |= GPIO_CFG0_GPIO_DIR_BIT_(bit);
+		gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(bit);
+		lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
+
+		/* enable gpio, and set buffer type to push pull */
+		gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOEN_BIT_(bit);
+		gpio->gpio_cfg1 |= GPIO_CFG1_GPIOBUF_BIT_(bit);
+		lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
+
+		/* set 1588 polarity to high */
+		gpio->gpio_cfg2 |= GPIO_CFG2_1588_POL_BIT_(bit);
+		lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2);
+
+		if (!ptp_channel) {
+			/* use channel A */
+			gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_CH_SEL_BIT_(bit);
+		} else {
+			/* use channel B */
+			gpio->gpio_cfg3 |= GPIO_CFG3_1588_CH_SEL_BIT_(bit);
+		}
+		gpio->gpio_cfg3 |= GPIO_CFG3_1588_OE_BIT_(bit);
+		lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3);
+
+		ret = bit;
+	}
+	spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags);
+	return ret;
+}
+
+static void lan743x_gpio_release(struct lan743x_adapter *adapter, int bit)
+{
+	struct lan743x_gpio *gpio = &adapter->gpio;
+	unsigned long irq_flags = 0;
+	int bit_mask = BIT(bit);
+
+	spin_lock_irqsave(&gpio->gpio_lock, irq_flags);
+	if (gpio->used_bits & bit_mask) {
+		gpio->used_bits &= ~bit_mask;
+		if (gpio->output_bits & bit_mask) {
+			gpio->output_bits &= ~bit_mask;
+
+			if (gpio->ptp_bits & bit_mask) {
+				gpio->ptp_bits &= ~bit_mask;
+				/* disable ptp output */
+				gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_OE_BIT_(bit);
+				lan743x_csr_write(adapter, GPIO_CFG3,
+						  gpio->gpio_cfg3);
+			}
+			/* release gpio output */
+
+			/* disable gpio */
+			gpio->gpio_cfg1 |= GPIO_CFG1_GPIOEN_BIT_(bit);
+			gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOBUF_BIT_(bit);
+			lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
+
+			/* reset back to input */
+			gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DIR_BIT_(bit);
+			gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(bit);
+			lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
+		}
+	}
+	spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags);
+}
+
+static int lan743x_ptpci_adjfine(struct ptp_clock_info *ptpci, long scaled_ppm)
+{
+	struct lan743x_ptp *ptp =
+		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
+	struct lan743x_adapter *adapter =
+		container_of(ptp, struct lan743x_adapter, ptp);
+	u32 lan743x_rate_adj = 0;
+	bool positive = true;
+	u64 u64_delta = 0;
+
+	if ((scaled_ppm < (-LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM)) ||
+	    scaled_ppm > LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM) {
+		return -EINVAL;
+	}
+	if (scaled_ppm > 0) {
+		u64_delta = (u64)scaled_ppm;
+		positive = true;
+	} else {
+		u64_delta = (u64)(-scaled_ppm);
+		positive = false;
+	}
+	u64_delta = (u64_delta << 19);
+	lan743x_rate_adj = div_u64(u64_delta, 1000000);
+
+	if (positive)
+		lan743x_rate_adj |= PTP_CLOCK_RATE_ADJ_DIR_;
+
+	lan743x_csr_write(adapter, PTP_CLOCK_RATE_ADJ,
+			  lan743x_rate_adj);
+
+	return 0;
+}
+
+static int lan743x_ptpci_adjfreq(struct ptp_clock_info *ptpci, s32 delta_ppb)
+{
+	struct lan743x_ptp *ptp =
+		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
+	struct lan743x_adapter *adapter =
+		container_of(ptp, struct lan743x_adapter, ptp);
+	u32 lan743x_rate_adj = 0;
+	bool positive = true;
+	u32 u32_delta = 0;
+	u64 u64_delta = 0;
+
+	if ((delta_ppb < (-LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB)) ||
+	    delta_ppb > LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB) {
+		return -EINVAL;
+	}
+	if (delta_ppb > 0) {
+		u32_delta = (u32)delta_ppb;
+		positive = true;
+	} else {
+		u32_delta = (u32)(-delta_ppb);
+		positive = false;
+	}
+	u64_delta = (((u64)u32_delta) << 35);
+	lan743x_rate_adj = div_u64(u64_delta, 1000000000);
+
+	if (positive)
+		lan743x_rate_adj |= PTP_CLOCK_RATE_ADJ_DIR_;
+
+	lan743x_csr_write(adapter, PTP_CLOCK_RATE_ADJ,
+			  lan743x_rate_adj);
+
+	return 0;
+}
+
+static int lan743x_ptpci_adjtime(struct ptp_clock_info *ptpci, s64 delta)
+{
+	struct lan743x_ptp *ptp =
+		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
+	struct lan743x_adapter *adapter =
+		container_of(ptp, struct lan743x_adapter, ptp);
+
+	lan743x_ptp_clock_step(adapter, delta);
+
+	return 0;
+}
+
+static int lan743x_ptpci_gettime64(struct ptp_clock_info *ptpci,
+				   struct timespec64 *ts)
+{
+	struct lan743x_ptp *ptp =
+		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
+	struct lan743x_adapter *adapter =
+		container_of(ptp, struct lan743x_adapter, ptp);
+	u32 nano_seconds = 0;
+	u32 seconds = 0;
+
+	lan743x_ptp_clock_get(adapter, &seconds, &nano_seconds, NULL);
+	ts->tv_sec = seconds;
+	ts->tv_nsec = nano_seconds;
+
+	return 0;
+}
+
+static int lan743x_ptpci_settime64(struct ptp_clock_info *ptpci,
+				   const struct timespec64 *ts)
+{
+	struct lan743x_ptp *ptp =
+		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
+	struct lan743x_adapter *adapter =
+		container_of(ptp, struct lan743x_adapter, ptp);
+	u32 nano_seconds = 0;
+	u32 seconds = 0;
+
+	if (ts) {
+		if (ts->tv_sec > 0xFFFFFFFFLL ||
+		    ts->tv_sec < 0) {
+			netif_warn(adapter, drv, adapter->netdev,
+				   "ts->tv_sec out of range, %lld\n",
+				   ts->tv_sec);
+			return -ERANGE;
+		}
+		if (ts->tv_nsec >= 1000000000L ||
+		    ts->tv_nsec < 0) {
+			netif_warn(adapter, drv, adapter->netdev,
+				   "ts->tv_nsec out of range, %ld\n",
+				   ts->tv_nsec);
+			return -ERANGE;
+		}
+		seconds = ts->tv_sec;
+		nano_seconds = ts->tv_nsec;
+		lan743x_ptp_clock_set(adapter, seconds, nano_seconds, 0);
+	} else {
+		netif_warn(adapter, drv, adapter->netdev, "ts == NULL\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void lan743x_ptp_perout_off(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	u32 general_config = 0;
+
+	if (ptp->perout_gpio_bit >= 0) {
+		lan743x_gpio_release(adapter, ptp->perout_gpio_bit);
+		ptp->perout_gpio_bit = -1;
+	}
+
+	if (ptp->perout_event_ch >= 0) {
+		/* set target to far in the future, effectively disabling it */
+		lan743x_csr_write(adapter,
+				  PTP_CLOCK_TARGET_SEC_X(ptp->perout_event_ch),
+				  0xFFFF0000);
+		lan743x_csr_write(adapter,
+				  PTP_CLOCK_TARGET_NS_X(ptp->perout_event_ch),
+				  0);
+
+		general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG);
+		general_config |= PTP_GENERAL_CONFIG_RELOAD_ADD_X_
+				  (ptp->perout_event_ch);
+		lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config);
+		lan743x_ptp_release_event_ch(adapter, ptp->perout_event_ch);
+		ptp->perout_event_ch = -1;
+	}
+}
+
+static int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on,
+			      struct ptp_perout_request *perout)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	u32 period_sec = 0, period_nsec = 0;
+	u32 start_sec = 0, start_nsec = 0;
+	u32 general_config = 0;
+	int pulse_width = 0;
+	int perout_bit = 0;
+
+	if (!on) {
+		lan743x_ptp_perout_off(adapter);
+		return 0;
+	}
+
+	if (ptp->perout_event_ch >= 0 ||
+	    ptp->perout_gpio_bit >= 0) {
+		/* already on, turn off first */
+		lan743x_ptp_perout_off(adapter);
+	}
+
+	ptp->perout_event_ch = lan743x_ptp_reserve_event_ch(adapter);
+	if (ptp->perout_event_ch < 0) {
+		netif_warn(adapter, drv, adapter->netdev,
+			   "Failed to reserve event channel for PEROUT\n");
+		goto failed;
+	}
+
+	switch (adapter->csr.id_rev & ID_REV_ID_MASK_) {
+	case ID_REV_ID_LAN7430_:
+		perout_bit = 2;/* GPIO 2 is preferred on EVB LAN7430 */
+		break;
+	case ID_REV_ID_LAN7431_:
+		perout_bit = 4;/* GPIO 4 is preferred on EVB LAN7431 */
+		break;
+	}
+
+	ptp->perout_gpio_bit = lan743x_gpio_rsrv_ptp_out(adapter,
+							 perout_bit,
+							 ptp->perout_event_ch);
+
+	if (ptp->perout_gpio_bit < 0) {
+		netif_warn(adapter, drv, adapter->netdev,
+			   "Failed to reserve gpio %d for PEROUT\n",
+			   perout_bit);
+		goto failed;
+	}
+
+	start_sec = perout->start.sec;
+	start_sec += perout->start.nsec / 1000000000;
+	start_nsec = perout->start.nsec % 1000000000;
+
+	period_sec = perout->period.sec;
+	period_sec += perout->period.nsec / 1000000000;
+	period_nsec = perout->period.nsec % 1000000000;
+
+	if (period_sec == 0) {
+		if (period_nsec >= 400000000) {
+			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_;
+		} else if (period_nsec >= 20000000) {
+			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_;
+		} else if (period_nsec >= 2000000) {
+			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_;
+		} else if (period_nsec >= 200000) {
+			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_;
+		} else if (period_nsec >= 20000) {
+			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_;
+		} else if (period_nsec >= 200) {
+			pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_;
+		} else {
+			netif_warn(adapter, drv, adapter->netdev,
+				   "perout period too small, minimum is 200nS\n");
+			goto failed;
+		}
+	} else {
+		pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_;
+	}
+
+	/* turn off by setting target far in future */
+	lan743x_csr_write(adapter,
+			  PTP_CLOCK_TARGET_SEC_X(ptp->perout_event_ch),
+			  0xFFFF0000);
+	lan743x_csr_write(adapter,
+			  PTP_CLOCK_TARGET_NS_X(ptp->perout_event_ch), 0);
+
+	/* Configure to pulse every period */
+	general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG);
+	general_config &= ~(PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_
+			  (ptp->perout_event_ch));
+	general_config |= PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_
+			  (ptp->perout_event_ch, pulse_width);
+	general_config &= ~PTP_GENERAL_CONFIG_RELOAD_ADD_X_
+			  (ptp->perout_event_ch);
+	lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config);
+
+	/* set the reload to one toggle cycle */
+	lan743x_csr_write(adapter,
+			  PTP_CLOCK_TARGET_RELOAD_SEC_X(ptp->perout_event_ch),
+			  period_sec);
+	lan743x_csr_write(adapter,
+			  PTP_CLOCK_TARGET_RELOAD_NS_X(ptp->perout_event_ch),
+			  period_nsec);
+
+	/* set the start time */
+	lan743x_csr_write(adapter,
+			  PTP_CLOCK_TARGET_SEC_X(ptp->perout_event_ch),
+			  start_sec);
+	lan743x_csr_write(adapter,
+			  PTP_CLOCK_TARGET_NS_X(ptp->perout_event_ch),
+			  start_nsec);
+
+	return 0;
+
+failed:
+	lan743x_ptp_perout_off(adapter);
+	return -ENODEV;
+}
+
+static int lan743x_ptpci_enable(struct ptp_clock_info *ptpci,
+				struct ptp_clock_request *request, int on)
+{
+	struct lan743x_ptp *ptp =
+		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
+	struct lan743x_adapter *adapter =
+		container_of(ptp, struct lan743x_adapter, ptp);
+
+	if (request) {
+		switch (request->type) {
+		case PTP_CLK_REQ_EXTTS:
+			return -EINVAL;
+		case PTP_CLK_REQ_PEROUT:
+			if (request->perout.index == 0)
+				return lan743x_ptp_perout(adapter, on,
+							  &request->perout);
+			return -EINVAL;
+		case PTP_CLK_REQ_PPS:
+			return -EINVAL;
+		default:
+			netif_err(adapter, drv, adapter->netdev,
+				  "request->type == %d, Unknown\n",
+				  request->type);
+			break;
+		}
+	} else {
+		netif_err(adapter, drv, adapter->netdev, "request == NULL\n");
+	}
+	return 0;
+}
+
+static long lan743x_ptpci_do_aux_work(struct ptp_clock_info *ptpci)
+{
+	struct lan743x_ptp *ptp =
+		container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
+	struct lan743x_adapter *adapter =
+		container_of(ptp, struct lan743x_adapter, ptp);
+	u32 cap_info, cause, header, nsec, seconds;
+	bool new_timestamp_available = false;
+	int count = 0;
+
+	while ((count < 100) &&
+	       (lan743x_csr_read(adapter, PTP_INT_STS) & PTP_INT_BIT_TX_TS_)) {
+		count++;
+		cap_info = lan743x_csr_read(adapter, PTP_CAP_INFO);
+
+		if (PTP_CAP_INFO_TX_TS_CNT_GET_(cap_info) > 0) {
+			seconds = lan743x_csr_read(adapter,
+						   PTP_TX_EGRESS_SEC);
+			nsec = lan743x_csr_read(adapter, PTP_TX_EGRESS_NS);
+			cause = (nsec &
+				 PTP_TX_EGRESS_NS_CAPTURE_CAUSE_MASK_);
+			header = lan743x_csr_read(adapter,
+						  PTP_TX_MSG_HEADER);
+
+			if (cause == PTP_TX_EGRESS_NS_CAPTURE_CAUSE_SW_) {
+				nsec &= PTP_TX_EGRESS_NS_TS_NS_MASK_;
+				lan743x_ptp_tx_ts_enqueue_ts(adapter,
+							     seconds, nsec,
+							     header);
+				new_timestamp_available = true;
+			} else if (cause ==
+				PTP_TX_EGRESS_NS_CAPTURE_CAUSE_AUTO_) {
+				netif_err(adapter, drv, adapter->netdev,
+					  "Auto capture cause not supported\n");
+			} else {
+				netif_warn(adapter, drv, adapter->netdev,
+					   "unknown tx timestamp capture cause\n");
+			}
+		} else {
+			netif_warn(adapter, drv, adapter->netdev,
+				   "TX TS INT but no TX TS CNT\n");
+		}
+		lan743x_csr_write(adapter, PTP_INT_STS, PTP_INT_BIT_TX_TS_);
+	}
+
+	if (new_timestamp_available)
+		lan743x_ptp_tx_ts_complete(adapter);
+
+	lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
+
+	return -1;
+}
+
+static void lan743x_ptp_clock_get(struct lan743x_adapter *adapter,
+				  u32 *seconds, u32 *nano_seconds,
+				  u32 *sub_nano_seconds)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	mutex_lock(&ptp->command_lock);
+
+	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_READ_);
+	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_READ_);
+
+	if (seconds)
+		(*seconds) = lan743x_csr_read(adapter, PTP_CLOCK_SEC);
+
+	if (nano_seconds)
+		(*nano_seconds) = lan743x_csr_read(adapter, PTP_CLOCK_NS);
+
+	if (sub_nano_seconds)
+		(*sub_nano_seconds) =
+		lan743x_csr_read(adapter, PTP_CLOCK_SUBNS);
+
+	mutex_unlock(&ptp->command_lock);
+}
+
+static void lan743x_ptp_clock_step(struct lan743x_adapter *adapter,
+				   s64 time_step_ns)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	u32 nano_seconds_step = 0;
+	u64 abs_time_step_ns = 0;
+	u32 unsigned_seconds = 0;
+	u32 nano_seconds = 0;
+	u32 remainder = 0;
+	s32 seconds = 0;
+
+	if (time_step_ns >  15000000000LL) {
+		/* convert to clock set */
+		lan743x_ptp_clock_get(adapter, &unsigned_seconds,
+				      &nano_seconds, NULL);
+		unsigned_seconds += div_u64_rem(time_step_ns, 1000000000LL,
+						&remainder);
+		nano_seconds += remainder;
+		if (nano_seconds >= 1000000000) {
+			unsigned_seconds++;
+			nano_seconds -= 1000000000;
+		}
+		lan743x_ptp_clock_set(adapter, unsigned_seconds,
+				      nano_seconds, 0);
+		return;
+	} else if (time_step_ns < -15000000000LL) {
+		/* convert to clock set */
+		time_step_ns = -time_step_ns;
+
+		lan743x_ptp_clock_get(adapter, &unsigned_seconds,
+				      &nano_seconds, NULL);
+		unsigned_seconds -= div_u64_rem(time_step_ns, 1000000000LL,
+						&remainder);
+		nano_seconds_step = remainder;
+		if (nano_seconds < nano_seconds_step) {
+			unsigned_seconds--;
+			nano_seconds += 1000000000;
+		}
+		nano_seconds -= nano_seconds_step;
+		lan743x_ptp_clock_set(adapter, unsigned_seconds,
+				      nano_seconds, 0);
+		return;
+	}
+
+	/* do clock step */
+	if (time_step_ns >= 0) {
+		abs_time_step_ns = (u64)(time_step_ns);
+		seconds = (s32)div_u64_rem(abs_time_step_ns, 1000000000,
+					   &remainder);
+		nano_seconds = (u32)remainder;
+	} else {
+		abs_time_step_ns = (u64)(-time_step_ns);
+		seconds = -((s32)div_u64_rem(abs_time_step_ns, 1000000000,
+					     &remainder));
+		nano_seconds = (u32)remainder;
+		if (nano_seconds > 0) {
+			/* subtracting nano seconds is not allowed
+			 * convert to subtracting from seconds,
+			 * and adding to nanoseconds
+			 */
+			seconds--;
+			nano_seconds = (1000000000 - nano_seconds);
+		}
+	}
+
+	if (nano_seconds > 0) {
+		/* add 8 ns to cover the likely normal increment */
+		nano_seconds += 8;
+	}
+
+	if (nano_seconds >= 1000000000) {
+		/* carry into seconds */
+		seconds++;
+		nano_seconds -= 1000000000;
+	}
+
+	while (seconds) {
+		mutex_lock(&ptp->command_lock);
+		if (seconds > 0) {
+			u32 adjustment_value = (u32)seconds;
+
+			if (adjustment_value > 0xF)
+				adjustment_value = 0xF;
+			lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
+					  PTP_CLOCK_STEP_ADJ_DIR_ |
+					  adjustment_value);
+			seconds -= ((s32)adjustment_value);
+		} else {
+			u32 adjustment_value = (u32)(-seconds);
+
+			if (adjustment_value > 0xF)
+				adjustment_value = 0xF;
+			lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
+					  adjustment_value);
+			seconds += ((s32)adjustment_value);
+		}
+		lan743x_csr_write(adapter, PTP_CMD_CTL,
+				  PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_);
+		lan743x_ptp_wait_till_cmd_done(adapter,
+					       PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_);
+		mutex_unlock(&ptp->command_lock);
+	}
+	if (nano_seconds) {
+		mutex_lock(&ptp->command_lock);
+		lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
+				  PTP_CLOCK_STEP_ADJ_DIR_ |
+				  (nano_seconds &
+				  PTP_CLOCK_STEP_ADJ_VALUE_MASK_));
+		lan743x_csr_write(adapter, PTP_CMD_CTL,
+				  PTP_CMD_CTL_PTP_CLK_STP_NSEC_);
+		lan743x_ptp_wait_till_cmd_done(adapter,
+					       PTP_CMD_CTL_PTP_CLK_STP_NSEC_);
+		mutex_unlock(&ptp->command_lock);
+	}
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+void lan743x_ptp_isr(void *context)
+{
+	struct lan743x_adapter *adapter = (struct lan743x_adapter *)context;
+	struct lan743x_ptp *ptp = NULL;
+	int enable_flag = 1;
+	u32 ptp_int_sts = 0;
+
+	ptp = &adapter->ptp;
+
+	lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_);
+
+	ptp_int_sts = lan743x_csr_read(adapter, PTP_INT_STS);
+	ptp_int_sts &= lan743x_csr_read(adapter, PTP_INT_EN_SET);
+
+	if (ptp_int_sts & PTP_INT_BIT_TX_TS_) {
+		ptp_schedule_worker(ptp->ptp_clock, 0);
+		enable_flag = 0;/* tasklet will re-enable later */
+	}
+	if (ptp_int_sts & PTP_INT_BIT_TX_SWTS_ERR_) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "PTP TX Software Timestamp Error\n");
+		/* clear int status bit */
+		lan743x_csr_write(adapter, PTP_INT_STS,
+				  PTP_INT_BIT_TX_SWTS_ERR_);
+	}
+	if (ptp_int_sts & PTP_INT_BIT_TIMER_B_) {
+		/* clear int status bit */
+		lan743x_csr_write(adapter, PTP_INT_STS,
+				  PTP_INT_BIT_TIMER_B_);
+	}
+	if (ptp_int_sts & PTP_INT_BIT_TIMER_A_) {
+		/* clear int status bit */
+		lan743x_csr_write(adapter, PTP_INT_STS,
+				  PTP_INT_BIT_TIMER_A_);
+	}
+
+	if (enable_flag) {
+		/* re-enable isr */
+		lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
+	}
+}
+
+static void lan743x_ptp_tx_ts_enqueue_skb(struct lan743x_adapter *adapter,
+					  struct sk_buff *skb, bool ignore_sync)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	spin_lock_bh(&ptp->tx_ts_lock);
+	if (ptp->tx_ts_skb_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
+		ptp->tx_ts_skb_queue[ptp->tx_ts_skb_queue_size] = skb;
+		if (ignore_sync)
+			ptp->tx_ts_ignore_sync_queue |=
+				BIT(ptp->tx_ts_skb_queue_size);
+		ptp->tx_ts_skb_queue_size++;
+	} else {
+		/* this should never happen, so long as the tx channel
+		 * calls and honors the result from
+		 * lan743x_ptp_request_tx_timestamp
+		 */
+		netif_err(adapter, drv, adapter->netdev,
+			  "tx ts skb queue overflow\n");
+		dev_kfree_skb(skb);
+	}
+	spin_unlock_bh(&ptp->tx_ts_lock);
+}
+
+static void lan743x_ptp_sync_to_system_clock(struct lan743x_adapter *adapter)
+{
+	struct timespec64 ts;
+
+	memset(&ts, 0, sizeof(ts));
+	timekeeping_clocktai64(&ts);
+
+	lan743x_ptp_clock_set(adapter, ts.tv_sec, ts.tv_nsec, 0);
+}
+
+void lan743x_ptp_update_latency(struct lan743x_adapter *adapter,
+				u32 link_speed)
+{
+	switch (link_speed) {
+	case 10:
+		lan743x_csr_write(adapter, PTP_LATENCY,
+				  PTP_LATENCY_TX_SET_(0) |
+				  PTP_LATENCY_RX_SET_(0));
+		break;
+	case 100:
+		lan743x_csr_write(adapter, PTP_LATENCY,
+				  PTP_LATENCY_TX_SET_(181) |
+				  PTP_LATENCY_RX_SET_(594));
+		break;
+	case 1000:
+		lan743x_csr_write(adapter, PTP_LATENCY,
+				  PTP_LATENCY_TX_SET_(30) |
+				  PTP_LATENCY_RX_SET_(525));
+		break;
+	}
+}
+
+int lan743x_ptp_init(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	mutex_init(&ptp->command_lock);
+	spin_lock_init(&ptp->tx_ts_lock);
+	ptp->used_event_ch = 0;
+	ptp->perout_event_ch = -1;
+	ptp->perout_gpio_bit = -1;
+	return 0;
+}
+
+int lan743x_ptp_open(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	int ret = -ENODEV;
+	u32 temp;
+
+	lan743x_ptp_reset(adapter);
+	lan743x_ptp_sync_to_system_clock(adapter);
+	temp = lan743x_csr_read(adapter, PTP_TX_MOD2);
+	temp |= PTP_TX_MOD2_TX_PTP_CLR_UDPV4_CHKSUM_;
+	lan743x_csr_write(adapter, PTP_TX_MOD2, temp);
+	lan743x_ptp_enable(adapter);
+	lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
+	lan743x_csr_write(adapter, PTP_INT_EN_SET,
+			  PTP_INT_BIT_TX_SWTS_ERR_ | PTP_INT_BIT_TX_TS_);
+	ptp->flags |= PTP_FLAG_ISR_ENABLED;
+
+#ifdef CONFIG_PTP_1588_CLOCK
+	snprintf(ptp->pin_config[0].name, 32, "lan743x_ptp_pin_0");
+	ptp->pin_config[0].index = 0;
+	ptp->pin_config[0].func = PTP_PF_PEROUT;
+	ptp->pin_config[0].chan = 0;
+
+	ptp->ptp_clock_info.owner = THIS_MODULE;
+	snprintf(ptp->ptp_clock_info.name, 16, "%pm",
+		 adapter->netdev->dev_addr);
+	ptp->ptp_clock_info.max_adj = LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB;
+	ptp->ptp_clock_info.n_alarm = 0;
+	ptp->ptp_clock_info.n_ext_ts = 0;
+	ptp->ptp_clock_info.n_per_out = 1;
+	ptp->ptp_clock_info.n_pins = 0;
+	ptp->ptp_clock_info.pps = 0;
+	ptp->ptp_clock_info.pin_config = NULL;
+	ptp->ptp_clock_info.adjfine = lan743x_ptpci_adjfine;
+	ptp->ptp_clock_info.adjfreq = lan743x_ptpci_adjfreq;
+	ptp->ptp_clock_info.adjtime = lan743x_ptpci_adjtime;
+	ptp->ptp_clock_info.gettime64 = lan743x_ptpci_gettime64;
+	ptp->ptp_clock_info.getcrosststamp = NULL;
+	ptp->ptp_clock_info.settime64 = lan743x_ptpci_settime64;
+	ptp->ptp_clock_info.enable = lan743x_ptpci_enable;
+	ptp->ptp_clock_info.do_aux_work = lan743x_ptpci_do_aux_work;
+	ptp->ptp_clock_info.verify = NULL;
+
+	ptp->ptp_clock = ptp_clock_register(&ptp->ptp_clock_info,
+					    &adapter->pdev->dev);
+
+	if (IS_ERR(ptp->ptp_clock)) {
+		netif_err(adapter, ifup, adapter->netdev,
+			  "ptp_clock_register failed\n");
+		goto done;
+	}
+	ptp->flags |= PTP_FLAG_PTP_CLOCK_REGISTERED;
+	netif_info(adapter, ifup, adapter->netdev,
+		   "successfully registered ptp clock\n");
+
+	return 0;
+done:
+	lan743x_ptp_close(adapter);
+	return ret;
+#else
+	return 0;
+#endif
+}
+
+void lan743x_ptp_close(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	int index;
+
+#ifdef CONFIG_PTP_1588_CLOCK
+	if (ptp->flags & PTP_FLAG_PTP_CLOCK_REGISTERED) {
+		ptp_clock_unregister(ptp->ptp_clock);
+		ptp->ptp_clock = NULL;
+		ptp->flags &= ~PTP_FLAG_PTP_CLOCK_REGISTERED;
+		netif_info(adapter, drv, adapter->netdev,
+			   "ptp clock unregister\n");
+	}
+#endif
+
+	if (ptp->flags & PTP_FLAG_ISR_ENABLED) {
+		lan743x_csr_write(adapter, PTP_INT_EN_CLR,
+				  PTP_INT_BIT_TX_SWTS_ERR_ |
+				  PTP_INT_BIT_TX_TS_);
+		lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_);
+		ptp->flags &= ~PTP_FLAG_ISR_ENABLED;
+	}
+
+	/* clean up pending timestamp requests */
+	lan743x_ptp_tx_ts_complete(adapter);
+	spin_lock_bh(&ptp->tx_ts_lock);
+	for (index = 0;
+		index < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS;
+		index++) {
+		struct sk_buff *skb = ptp->tx_ts_skb_queue[index];
+
+		if (skb)
+			dev_kfree_skb(skb);
+		ptp->tx_ts_skb_queue[index] = NULL;
+		ptp->tx_ts_seconds_queue[index] = 0;
+		ptp->tx_ts_nseconds_queue[index] = 0;
+	}
+	ptp->tx_ts_skb_queue_size = 0;
+	ptp->tx_ts_queue_size = 0;
+	ptp->pending_tx_timestamps = 0;
+	spin_unlock_bh(&ptp->tx_ts_lock);
+
+	lan743x_ptp_disable(adapter);
+}
+
+void lan743x_ptp_set_sync_ts_insert(struct lan743x_adapter *adapter,
+				    bool ts_insert_enable)
+{
+	u32 ptp_tx_mod = lan743x_csr_read(adapter, PTP_TX_MOD);
+
+	if (ts_insert_enable)
+		ptp_tx_mod |= PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_;
+	else
+		ptp_tx_mod &= ~PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_;
+
+	lan743x_csr_write(adapter, PTP_TX_MOD, ptp_tx_mod);
+}
+
+static bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter)
+{
+	if (lan743x_csr_read(adapter, PTP_CMD_CTL) & PTP_CMD_CTL_PTP_ENABLE_)
+		return true;
+	return false;
+}
+
+static void lan743x_ptp_enable(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	mutex_lock(&ptp->command_lock);
+
+	if (lan743x_ptp_is_enabled(adapter)) {
+		netif_warn(adapter, drv, adapter->netdev,
+			   "PTP already enabled\n");
+		goto done;
+	}
+	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_ENABLE_);
+done:
+	mutex_unlock(&ptp->command_lock);
+}
+
+static void lan743x_ptp_disable(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	mutex_lock(&ptp->command_lock);
+	if (!lan743x_ptp_is_enabled(adapter)) {
+		netif_warn(adapter, drv, adapter->netdev,
+			   "PTP already disabled\n");
+		goto done;
+	}
+	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_DISABLE_);
+	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_ENABLE_);
+done:
+	mutex_unlock(&ptp->command_lock);
+}
+
+static void lan743x_ptp_reset(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	mutex_lock(&ptp->command_lock);
+
+	if (lan743x_ptp_is_enabled(adapter)) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "Attempting reset while enabled\n");
+		goto done;
+	}
+
+	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_RESET_);
+	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_RESET_);
+done:
+	mutex_unlock(&ptp->command_lock);
+}
+
+static void lan743x_ptp_clock_set(struct lan743x_adapter *adapter,
+				  u32 seconds, u32 nano_seconds,
+				  u32 sub_nano_seconds)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	mutex_lock(&ptp->command_lock);
+
+	lan743x_csr_write(adapter, PTP_CLOCK_SEC, seconds);
+	lan743x_csr_write(adapter, PTP_CLOCK_NS, nano_seconds);
+	lan743x_csr_write(adapter, PTP_CLOCK_SUBNS, sub_nano_seconds);
+
+	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_LOAD_);
+	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_LOAD_);
+	mutex_unlock(&ptp->command_lock);
+}
+
+bool lan743x_ptp_request_tx_timestamp(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	bool result = false;
+
+	spin_lock_bh(&ptp->tx_ts_lock);
+	if (ptp->pending_tx_timestamps < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
+		/* request granted */
+		ptp->pending_tx_timestamps++;
+		result = true;
+	}
+	spin_unlock_bh(&ptp->tx_ts_lock);
+	return result;
+}
+
+void lan743x_ptp_unrequest_tx_timestamp(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	spin_lock_bh(&ptp->tx_ts_lock);
+	if (ptp->pending_tx_timestamps > 0)
+		ptp->pending_tx_timestamps--;
+	else
+		netif_err(adapter, drv, adapter->netdev,
+			  "unrequest failed, pending_tx_timestamps==0\n");
+	spin_unlock_bh(&ptp->tx_ts_lock);
+}
+
+void lan743x_ptp_tx_timestamp_skb(struct lan743x_adapter *adapter,
+				  struct sk_buff *skb, bool ignore_sync)
+{
+	lan743x_ptp_tx_ts_enqueue_skb(adapter, skb, ignore_sync);
+
+	lan743x_ptp_tx_ts_complete(adapter);
+}
+
+int lan743x_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+	struct hwtstamp_config config;
+	int ret = 0;
+	int index;
+
+	if (!ifr) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "SIOCSHWTSTAMP, ifr == NULL\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+		return -EFAULT;
+
+	if (config.flags) {
+		netif_warn(adapter, drv, adapter->netdev,
+			   "ignoring hwtstamp_config.flags == 0x%08X, expected 0\n",
+			   config.flags);
+	}
+
+	switch (config.tx_type) {
+	case HWTSTAMP_TX_OFF:
+		for (index = 0; index < LAN743X_MAX_TX_CHANNELS;
+			index++)
+			lan743x_tx_set_timestamping_mode(&adapter->tx[index],
+							 false, false);
+		lan743x_ptp_set_sync_ts_insert(adapter, false);
+		break;
+	case HWTSTAMP_TX_ON:
+		for (index = 0; index < LAN743X_MAX_TX_CHANNELS;
+			index++)
+			lan743x_tx_set_timestamping_mode(&adapter->tx[index],
+							 true, false);
+		lan743x_ptp_set_sync_ts_insert(adapter, false);
+		break;
+	case HWTSTAMP_TX_ONESTEP_SYNC:
+		for (index = 0; index < LAN743X_MAX_TX_CHANNELS;
+			index++)
+			lan743x_tx_set_timestamping_mode(&adapter->tx[index],
+							 true, true);
+
+		lan743x_ptp_set_sync_ts_insert(adapter, true);
+		break;
+	default:
+		netif_warn(adapter, drv, adapter->netdev,
+			   "  tx_type = %d, UNKNOWN\n", config.tx_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	if (!ret)
+		return copy_to_user(ifr->ifr_data, &config,
+			sizeof(config)) ? -EFAULT : 0;
+	return ret;
+}
diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.h b/drivers/net/ethernet/microchip/lan743x_ptp.h
new file mode 100644
index 0000000..20f2223
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan743x_ptp.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (C) 2018 Microchip Technology Inc. */
+
+#ifndef _LAN743X_PTP_H
+#define _LAN743X_PTP_H
+
+#include "linux/ptp_clock_kernel.h"
+#include "linux/netdevice.h"
+
+struct lan743x_adapter;
+
+/* GPIO */
+struct lan743x_gpio {
+	/* gpio_lock: used to prevent concurrent access to gpio settings */
+	spinlock_t gpio_lock;
+
+	int used_bits;
+	int output_bits;
+	int ptp_bits;
+	u32 gpio_cfg0;
+	u32 gpio_cfg1;
+	u32 gpio_cfg2;
+	u32 gpio_cfg3;
+};
+
+int lan743x_gpio_init(struct lan743x_adapter *adapter);
+
+void lan743x_ptp_isr(void *context);
+bool lan743x_ptp_request_tx_timestamp(struct lan743x_adapter *adapter);
+void lan743x_ptp_unrequest_tx_timestamp(struct lan743x_adapter *adapter);
+void lan743x_ptp_tx_timestamp_skb(struct lan743x_adapter *adapter,
+				  struct sk_buff *skb, bool ignore_sync);
+int lan743x_ptp_init(struct lan743x_adapter *adapter);
+int lan743x_ptp_open(struct lan743x_adapter *adapter);
+void lan743x_ptp_close(struct lan743x_adapter *adapter);
+void lan743x_ptp_update_latency(struct lan743x_adapter *adapter,
+				u32 link_speed);
+
+int lan743x_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
+
+#define LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS (4)
+
+#define PTP_FLAG_PTP_CLOCK_REGISTERED	BIT(1)
+#define PTP_FLAG_ISR_ENABLED			BIT(2)
+
+struct lan743x_ptp {
+	int flags;
+
+	/* command_lock: used to prevent concurrent ptp commands */
+	struct mutex	command_lock;
+
+#ifdef CONFIG_PTP_1588_CLOCK
+	struct ptp_clock *ptp_clock;
+	struct ptp_clock_info ptp_clock_info;
+	struct ptp_pin_desc pin_config[1];
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+#define LAN743X_PTP_NUMBER_OF_EVENT_CHANNELS (2)
+	unsigned long used_event_ch;
+
+	int perout_event_ch;
+	int perout_gpio_bit;
+
+	/* tx_ts_lock: used to prevent concurrent access to timestamp arrays */
+	spinlock_t	tx_ts_lock;
+	int pending_tx_timestamps;
+	struct sk_buff *tx_ts_skb_queue[LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS];
+	unsigned int	tx_ts_ignore_sync_queue;
+	int tx_ts_skb_queue_size;
+	u32 tx_ts_seconds_queue[LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS];
+	u32 tx_ts_nseconds_queue[LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS];
+	u32 tx_ts_header_queue[LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS];
+	int tx_ts_queue_size;
+};
+
+#endif /* _LAN743X_PTP_H */
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH net-next v6 06/11] net: sched: add 'delete' function to action ops
From: Cong Wang @ 2018-08-09 19:38 UTC (permalink / raw)
  To: Vlad Buslov
  Cc: Linux Kernel Network Developers, David Miller, Jamal Hadi Salim,
	Jiri Pirko, Alexei Starovoitov, Daniel Borkmann,
	Yevgeny Kliteynik, Jiri Pirko
In-Reply-To: <1530800673-12280-7-git-send-email-vladbu@mellanox.com>

On Thu, Jul 5, 2018 at 7:24 AM Vlad Buslov <vladbu@mellanox.com> wrote:
>
> Extend action ops with 'delete' function. Each action type to implements
> its own delete function that doesn't depend on rtnl lock.
>
> Implement delete function that is required to delete actions without
> holding rtnl lock. Use action API function that atomically deletes action
> only if it is still in action idr. This implementation prevents concurrent
> threads from deleting same action twice.

I fail to understand why you introduce ops->delete(), it seems all
you want is getting the tn->idrinfo, but you already have tc_action
before calling ops->delete(), and tc_action has ->idrinfo...

Each type of action does the same too, that is, just calling
tcf_idr_delete_index()...

This changelog sucks again, it claims for skipping rtnl lock,
but you can skip rtnl lock by just calling tcf_idr_delete_index()
directly too, it is not the reason for adding ops->delete().

^ permalink raw reply

* Re: [PATCH lora-next v2 2/8] net: lora: sx1301: convert to devm registration of netdev
From: Andreas Färber @ 2018-08-09 19:27 UTC (permalink / raw)
  To: Ben Whitten
  Cc: starnight, hasnain.virk, netdev, liuxuenetmail, shess,
	Ben Whitten
In-Reply-To: <1533818018-29005-2-git-send-email-ben.whitten@lairdtech.com>

Am 09.08.2018 um 14:33 schrieb Ben Whitten:
> We allow the devres framework handle the clean removal of resources on
> teardown of the device, in this case the SPI device, saving lengthy
> unwind code and improving clarity.
> 
> Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
> ---
>  drivers/net/lora/sx1301.c | 87 +++++++++++++++--------------------------------
>  1 file changed, 27 insertions(+), 60 deletions(-)
> 
> diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
> index 5342b61..3c09f5a 100644
> --- a/drivers/net/lora/sx1301.c
> +++ b/drivers/net/lora/sx1301.c
[...]
>  static int sx1301_remove(struct spi_device *spi)
>  {
> -	struct net_device *netdev = spi_get_drvdata(spi);
> -
> -	//unregister_loradev(netdev);

Thanks, this part we'll still need later though.

Applying.

Regards,
Andreas

> -	free_loradev(netdev);
> -
>  	dev_info(&spi->dev, "SX1301 module removed\n");
>  
>  	return 0;
[snip]

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

^ permalink raw reply

* Re: [PATCH net-next 5/5] net: aquantia: bump driver version
From: Jakub Kicinski @ 2018-08-09 19:20 UTC (permalink / raw)
  To: Igor Russkikh; +Cc: Andrew Lunn, David S . Miller, netdev
In-Reply-To: <a409e532-035e-3544-a050-e7238f3a45f4@aquantia.com>

On Thu, 9 Aug 2018 13:10:09 +0300, Igor Russkikh wrote:
> Hi Andrew,
> 
> Thanks for the review, agreed on all your findings,
> we'll address these comments in next version.
> 
> > Driver versions are pretty much useless. Say somebody backports this
> > driver into a vendor kernel. Vendor kernels are typically based on an
> > old kernel, plus thousands of patches. Is 2.0.4 on such a kernel the
> > same as 2.0.4 in 4.19?
> > 
> > You probably want to remove this, just the avoid people thinking is
> > means something.  
> 
> We do distribute our driver as a separate source package, customers for older
> kernels use it and install without updating their kernels.
> 
> We also in fact always have a gap in featureset between upstream driver and our
> preview driver releases on github - alot of people tend to tryout 'hot and latest' driver
> instead of waiting for their distro kernel to receive updates.
> 
> All this means we have to understand which version (and featureset)
> users have installed in fields.
> 
> `ethtool -i` and this internal driver version is a huge helper for us.
> 
> You are right that in event of backporting there could be some
> uncertainty whether that bugfix is there or not. But having kernel
> version plus driver version really helps us to understand the exact
> configuration in fields.
> 
> Moreover, inkernel driver version bumps are linked with new features
> added (like in this patchset). Thus the overall concept of internal
> version is still very useful for Aquantia technical and support
> engineers.
> 
> Hope the above are good enough arguments to keep up version bumps.

A reasonably successful strategy is to version your out-of-tree driver
with corresponding kernel release versions.  Flip the equation.

E.g. current net-next will become 4.19, so all the features you're
pushing now would in your GH repo be:

4.19.0.${extra_numbers_if_you_want}-gh

And you still have single versioning scheme, but the "bump to version
XYZ" commits now go into your local tree not the kernel.

As Andrew said backports make driver versions less than useful.  Not
only feature backports to enterprise kernel, but bug fixes which have to
go to stable.

^ permalink raw reply

* Re: [PATCH lora-next v2 1/8] net: lora: add methods for devm registration
From: Andreas Färber @ 2018-08-09 19:18 UTC (permalink / raw)
  To: Ben Whitten
  Cc: starnight, hasnain.virk, netdev, liuxuenetmail, shess,
	Ben Whitten
In-Reply-To: <1533818018-29005-1-git-send-email-ben.whitten@lairdtech.com>

Am 09.08.2018 um 14:33 schrieb Ben Whitten:
> Follow the devm model so that we can avoid lengthy unwind code.
> 
> Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
> ---
>  drivers/net/lora/dev.c   | 28 ++++++++++++++++++++++++++++
>  include/linux/lora/dev.h |  1 +
>  2 files changed, 29 insertions(+)
> 
> diff --git a/drivers/net/lora/dev.c b/drivers/net/lora/dev.c
> index 8c01106..e32a870 100644
> --- a/drivers/net/lora/dev.c
> +++ b/drivers/net/lora/dev.c
> @@ -84,6 +84,34 @@ void free_loradev(struct net_device *dev)
>  }
>  EXPORT_SYMBOL_GPL(free_loradev);
>  
> +static void devm_free_loradev(struct device *dev, void *res)
> +{
> +	struct net_device *net = (*(struct net_device **)res);
> +	free_loradev(net);

This is what I meant with adding a variable:

diff --git a/drivers/net/lora/dev.c b/drivers/net/lora/dev.c
index c1b196cdf835..0d4823de8c06 100644
--- a/drivers/net/lora/dev.c
+++ b/drivers/net/lora/dev.c
@@ -87,8 +87,9 @@ EXPORT_SYMBOL_GPL(free_loradev);

 static void devm_free_loradev(struct device *dev, void *res)
 {
-       struct net_device *net = (*(struct net_device **)res);
-       free_loradev(net);
+       struct net_device **net = res;
+
+       free_loradev(*net);
 }

 struct net_device *devm_alloc_loradev(struct device *dev, size_t priv)

Applying.

Thanks,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

^ permalink raw reply related

* Re: [net-next, PATCH 1/2] net: socionext: Use descriptor info instead of MMIO reads on Rx
From: Ilias Apalodimas @ 2018-08-09 19:05 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: Networking, Jassi Brar
In-Reply-To: <CAK8P3a0xq2i03Ktr2_10pqkn=Oeebh1p+Yjp26K9CpEA2SxNaQ@mail.gmail.com>

On Thu, Aug 09, 2018 at 05:37:15PM +0200, Arnd Bergmann wrote:
> On Thu, Aug 9, 2018 at 10:02 AM Ilias Apalodimas
> <ilias.apalodimas@linaro.org> wrote:
> >
> > MMIO reads for remaining packets in queue occur (at least)twice per
> > invocation of netsec_process_rx(). We can use the packet descriptor to
> > identify if it's owned by the hardware and break out, avoiding the more
> > expensive MMIO read operations. This has a ~2% increase on the pps of the
> > Rx path when tested with 64byte packets
> >
> > Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> > ---
> >  drivers/net/ethernet/socionext/netsec.c | 19 +++++--------------
> >  1 file changed, 5 insertions(+), 14 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c
> > index 01589b6..ae32909 100644
> > --- a/drivers/net/ethernet/socionext/netsec.c
> > +++ b/drivers/net/ethernet/socionext/netsec.c
> > @@ -657,8 +657,6 @@ static struct sk_buff *netsec_get_rx_pkt_data(struct netsec_priv *priv,
> 
> > +               if (de->attr & (1U << NETSEC_RX_PKT_OWN_FIELD))
> > +                       break;
> >                 done++;
> 
> Should this use READ_ONCE() to prevent the compiler from moving the
> access around? I see that netsec_get_rx_pkt_data() has a dma_rmb()
> before reading the data, which prevents the CPU from doing something
> wrong here, but not the compiler.
> 
>         Arnd
As we discussed i'll send a V2 with the dma_rmb() right after the desc status
read

Thnaks
Ilias

^ permalink raw reply

* [PATCH net] l2tp: use sk_dst_check() to avoid race on sk->sk_dst_cache
From: Wei Wang @ 2018-08-09 18:54 UTC (permalink / raw)
  To: David Miller, netdev; +Cc: Martin KaFai Lau, Wei Wang, David Ahern, Cong Wang

From: Wei Wang <weiwan@google.com>

In l2tp code, if it is a L2TP_UDP_ENCAP tunnel, tunnel->sk points to a
UDP socket. User could call sendmsg() on both this tunnel and the UDP
socket itself concurrently. As l2tp_xmit_skb() holds socket lock and call
__sk_dst_check() to refresh sk->sk_dst_cache, while udpv6_sendmsg() is
lockless and call sk_dst_check() to refresh sk->sk_dst_cache, there
could be a race and cause the dst cache to be freed multiple times.
So we fix l2tp side code to always call sk_dst_check() to garantee
xchg() is called when refreshing sk->sk_dst_cache to avoid race
conditions.

Syzkaller reported stack trace:
BUG: KASAN: use-after-free in atomic_read include/asm-generic/atomic-instrumented.h:21 [inline]
BUG: KASAN: use-after-free in atomic_fetch_add_unless include/linux/atomic.h:575 [inline]
BUG: KASAN: use-after-free in atomic_add_unless include/linux/atomic.h:597 [inline]
BUG: KASAN: use-after-free in dst_hold_safe include/net/dst.h:308 [inline]
BUG: KASAN: use-after-free in ip6_hold_safe+0xe6/0x670 net/ipv6/route.c:1029
Read of size 4 at addr ffff8801aea9a880 by task syz-executor129/4829

CPU: 0 PID: 4829 Comm: syz-executor129 Not tainted 4.18.0-rc7-next-20180802+ #30
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Call Trace:
 __dump_stack lib/dump_stack.c:77 [inline]
 dump_stack+0x1c9/0x2b4 lib/dump_stack.c:113
 print_address_description+0x6c/0x20b mm/kasan/report.c:256
 kasan_report_error mm/kasan/report.c:354 [inline]
 kasan_report.cold.7+0x242/0x30d mm/kasan/report.c:412
 check_memory_region_inline mm/kasan/kasan.c:260 [inline]
 check_memory_region+0x13e/0x1b0 mm/kasan/kasan.c:267
 kasan_check_read+0x11/0x20 mm/kasan/kasan.c:272
 atomic_read include/asm-generic/atomic-instrumented.h:21 [inline]
 atomic_fetch_add_unless include/linux/atomic.h:575 [inline]
 atomic_add_unless include/linux/atomic.h:597 [inline]
 dst_hold_safe include/net/dst.h:308 [inline]
 ip6_hold_safe+0xe6/0x670 net/ipv6/route.c:1029
 rt6_get_pcpu_route net/ipv6/route.c:1249 [inline]
 ip6_pol_route+0x354/0xd20 net/ipv6/route.c:1922
 ip6_pol_route_output+0x54/0x70 net/ipv6/route.c:2098
 fib6_rule_lookup+0x283/0x890 net/ipv6/fib6_rules.c:122
 ip6_route_output_flags+0x2c5/0x350 net/ipv6/route.c:2126
 ip6_dst_lookup_tail+0x1278/0x1da0 net/ipv6/ip6_output.c:978
 ip6_dst_lookup_flow+0xc8/0x270 net/ipv6/ip6_output.c:1079
 ip6_sk_dst_lookup_flow+0x5ed/0xc50 net/ipv6/ip6_output.c:1117
 udpv6_sendmsg+0x2163/0x36b0 net/ipv6/udp.c:1354
 inet_sendmsg+0x1a1/0x690 net/ipv4/af_inet.c:798
 sock_sendmsg_nosec net/socket.c:622 [inline]
 sock_sendmsg+0xd5/0x120 net/socket.c:632
 ___sys_sendmsg+0x51d/0x930 net/socket.c:2115
 __sys_sendmmsg+0x240/0x6f0 net/socket.c:2210
 __do_sys_sendmmsg net/socket.c:2239 [inline]
 __se_sys_sendmmsg net/socket.c:2236 [inline]
 __x64_sys_sendmmsg+0x9d/0x100 net/socket.c:2236
 do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290
 entry_SYSCALL_64_after_hwframe+0x49/0xbe
RIP: 0033:0x446a29
Code: e8 ac b8 02 00 48 83 c4 18 c3 0f 1f 80 00 00 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 eb 08 fc ff c3 66 2e 0f 1f 84 00 00 00 00
RSP: 002b:00007f4de5532db8 EFLAGS: 00000246 ORIG_RAX: 0000000000000133
RAX: ffffffffffffffda RBX: 00000000006dcc38 RCX: 0000000000446a29
RDX: 00000000000000b8 RSI: 0000000020001b00 RDI: 0000000000000003
RBP: 00000000006dcc30 R08: 00007f4de5533700 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 00000000006dcc3c
R13: 00007ffe2b830fdf R14: 00007f4de55339c0 R15: 0000000000000001

Fixes: 71b1391a4128 ("l2tp: ensure sk->dst is still valid")
Reported-by: syzbot+05f840f3b04f211bad55@syzkaller.appspotmail.com
Signed-off-by: Wei Wang <weiwan@google.com>
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Cong Wang <xiyou.wangcong@gmail.com>
---
 net/l2tp/l2tp_core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 40261cb68e83..7166b61338d4 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1110,7 +1110,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
 
 	/* Get routing info from the tunnel socket */
 	skb_dst_drop(skb);
-	skb_dst_set(skb, dst_clone(__sk_dst_check(sk, 0)));
+	skb_dst_set(skb, dst_clone(sk_dst_check(sk, 0)));
 
 	inet = inet_sk(sk);
 	fl = &inet->cork.fl;
-- 
2.18.0.597.ga71716f1ad-goog

^ permalink raw reply related

* Re: [PATCH] ethernet/qlogic: remove unused array msi_tgt_status
From: David Miller @ 2018-08-09 21:17 UTC (permalink / raw)
  To: colin.king
  Cc: harish.patil, manish.chopra, Dept-GELinuxNICDev, netdev,
	kernel-janitors, linux-kernel
In-Reply-To: <20180808180427.14864-1-colin.king@canonical.com>

From: Colin King <colin.king@canonical.com>
Date: Wed,  8 Aug 2018 19:04:27 +0100

> From: Colin Ian King <colin.king@canonical.com>
> 
> Array msi_tgt_status is defined but never used, hence it is
> redundant and can be removed.
> 
> Cleans up clang warning:
> warning: 'msi_tgt_status' defined but not used [-Wunused-const-variable=]
> 
> Signed-off-by: Colin Ian King <colin.king@canonical.com>

Applied, thank you.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox