Netdev List
 help / color / mirror / Atom feed
* [PATCH V4 net-next 00/14] TLS offload, netdev & MLX5 support
From: Saeed Mahameed @ 2018-03-27 21:51 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Dave Watson, Boris Pismenny, Saeed Mahameed

Hi Dave,

The following series from Ilya and Boris provides TLS TX inline crypto
offload.

v1->v2:
   - Added IS_ENABLED(CONFIG_TLS_DEVICE) and a STATIC_KEY for icsk_clean_acked
   - File license fix
   - Fix spelling, comment by DaveW
   - Move memory allocations out of tls_set_device_offload and other misc fixes,
	comments by Kiril.

v2->v3:
   - Reversed xmas tree where needed and style fixes
   - Removed the need for skb_page_frag_refill, per Eric's comment
   - IPv6 dependency fixes

v3->v4:
   - Remove “inline” from functions in C files
   - Make clean_acked_data_enabled a static variable and add enable/disable functions to control it.
   - Remove unnecessary variable initialization mentioned by ShannonN
   - Rebase over TLS RX
   - Refactor the tls_software_fallback to reduce the number of variables mentioned by KirilT

Boris says:
===================
This series adds a generic infrastructure to offload TLS crypto to a
network devices. It enables the kernel TLS socket to skip encryption and
authentication operations on the transmit side of the data path. Leaving
those computationally expensive operations to the NIC.

The NIC offload infrastructure builds TLS records and pushes them to the
TCP layer just like the SW KTLS implementation and using the same API.
TCP segmentation is mostly unaffected. Currently the only exception is
that we prevent mixed SKBs where only part of the payload requires
offload. In the future we are likely to add a similar restriction
following a change cipher spec record.

The notable differences between SW KTLS and NIC offloaded TLS
implementations are as follows:
1. The offloaded implementation builds "plaintext TLS record", those
records contain plaintext instead of ciphertext and place holder bytes
instead of authentication tags.
2. The offloaded implementation maintains a mapping from TCP sequence
number to TLS records. Thus given a TCP SKB sent from a NIC offloaded
  TLS socket, we can use the tls NIC offload infrastructure to obtain
enough context to encrypt the payload of the SKB.
A TLS record is released when the last byte of the record is ack'ed,
this is done through the new icsk_clean_acked callback.

The infrastructure should be extendable to support various NIC offload
implementations.  However it is currently written with the
implementation below in mind:
The NIC assumes that packets from each offloaded stream are sent as
plaintext and in-order. It keeps track of the TLS records in the TCP
stream. When a packet marked for offload is transmitted, the NIC
encrypts the payload in-place and puts authentication tags in the
relevant place holders.

The responsibility for handling out-of-order packets (i.e. TCP
retransmission, qdisc drops) falls on the netdev driver.

The netdev driver keeps track of the expected TCP SN from the NIC's
perspective.  If the next packet to transmit matches the expected TCP
SN, the driver advances the expected TCP SN, and transmits the packet
with TLS offload indication.

If the next packet to transmit does not match the expected TCP SN. The
driver calls the TLS layer to obtain the TLS record that includes the
TCP of the packet for transmission. Using this TLS record, the driver
posts a work entry on the transmit queue to reconstruct the NIC TLS
state required for the offload of the out-of-order packet. It updates
the expected TCP SN accordingly and transmit the now in-order packet.
The same queue is used for packet transmission and TLS context
reconstruction to avoid the need for flushing the transmit queue before
issuing the context reconstruction request.

Expected TCP SN is accessed without a lock, under the assumption that
TCP doesn't transmit SKBs from different TX queue concurrently.

We assume that packets are not rerouted to a different network device.

Paper: https://www.netdevconf.org/1.2/papers/netdevconf-TLS.pdf

===================

Thanks,
Saeed.

---

Boris Pismenny (2):
  MAINTAINERS: Update mlx5 innova driver maintainers
  MAINTAINERS: Update TLS maintainers

Ilya Lesokhin (12):
  tcp: Add clean acked data hook
  net: Rename and export copy_skb_header
  net: Add Software fallback infrastructure for socket dependent
    offloads
  net: Add TLS offload netdev ops
  net: Add TLS TX offload features
  net/tls: Add generic NIC offload infrastructure
  net/tls: Support TLS device offload with IPv6
  net/mlx5e: Move defines out of ipsec code
  net/mlx5: Accel, Add TLS tx offload interface
  net/mlx5e: TLS, Add Innova TLS TX support
  net/mlx5e: TLS, Add Innova TLS TX offload data path
  net/mlx5e: TLS, Add error statistics

 MAINTAINERS                                        |  19 +-
 drivers/net/ethernet/mellanox/mlx5/core/Kconfig    |  11 +
 drivers/net/ethernet/mellanox/mlx5/core/Makefile   |   6 +-
 .../net/ethernet/mellanox/mlx5/core/accel/tls.c    |  71 ++
 .../net/ethernet/mellanox/mlx5/core/accel/tls.h    |  86 +++
 drivers/net/ethernet/mellanox/mlx5/core/en.h       |  21 +
 .../mellanox/mlx5/core/en_accel/en_accel.h         |  72 ++
 .../ethernet/mellanox/mlx5/core/en_accel/ipsec.h   |   3 -
 .../net/ethernet/mellanox/mlx5/core/en_accel/tls.c | 197 +++++
 .../net/ethernet/mellanox/mlx5/core/en_accel/tls.h |  87 +++
 .../mellanox/mlx5/core/en_accel/tls_rxtx.c         | 278 +++++++
 .../mellanox/mlx5/core/en_accel/tls_rxtx.h         |  50 ++
 .../mellanox/mlx5/core/en_accel/tls_stats.c        |  89 +++
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c  |   9 +
 drivers/net/ethernet/mellanox/mlx5/core/en_stats.c |  32 +
 drivers/net/ethernet/mellanox/mlx5/core/en_stats.h |   9 +
 drivers/net/ethernet/mellanox/mlx5/core/en_tx.c    |  37 +-
 .../net/ethernet/mellanox/mlx5/core/fpga/core.h    |   1 +
 .../net/ethernet/mellanox/mlx5/core/fpga/ipsec.c   |   5 +-
 drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.h |   2 +
 drivers/net/ethernet/mellanox/mlx5/core/fpga/tls.c | 563 ++++++++++++++
 drivers/net/ethernet/mellanox/mlx5/core/fpga/tls.h |  68 ++
 drivers/net/ethernet/mellanox/mlx5/core/main.c     |  11 +
 include/linux/mlx5/mlx5_ifc.h                      |  16 -
 include/linux/mlx5/mlx5_ifc_fpga.h                 |  77 ++
 include/linux/netdev_features.h                    |   2 +
 include/linux/netdevice.h                          |  24 +
 include/linux/skbuff.h                             |   1 +
 include/net/inet_connection_sock.h                 |   2 +
 include/net/sock.h                                 |  21 +
 include/net/tcp.h                                  |   8 +
 include/net/tls.h                                  | 120 ++-
 net/Kconfig                                        |   4 +
 net/core/dev.c                                     |   4 +
 net/core/ethtool.c                                 |   1 +
 net/core/skbuff.c                                  |   9 +-
 net/ipv4/tcp_input.c                               |  23 +
 net/tls/Kconfig                                    |  10 +
 net/tls/Makefile                                   |   2 +
 net/tls/tls_device.c                               | 808 +++++++++++++++++++++
 net/tls/tls_device_fallback.c                      | 454 ++++++++++++
 net/tls/tls_main.c                                 | 118 +--
 net/tls/tls_sw.c                                   | 132 ++--
 43 files changed, 3384 insertions(+), 179 deletions(-)
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/accel/tls.c
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.c
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.h
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.c
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.h
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_stats.c
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/tls.c
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/tls.h
 create mode 100644 net/tls/tls_device.c
 create mode 100644 net/tls/tls_device_fallback.c

-- 
2.14.3

^ permalink raw reply

* [PATCH V4 net-next 01/14] tcp: Add clean acked data hook
From: Saeed Mahameed @ 2018-03-27 21:51 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, Dave Watson, Boris Pismenny, Ilya Lesokhin,
	Aviad Yehezkel, Saeed Mahameed
In-Reply-To: <20180327215201.18859-1-saeedm@mellanox.com>

From: Ilya Lesokhin <ilyal@mellanox.com>

Called when a TCP segment is acknowledged.
Could be used by application protocols who hold additional
metadata associated with the stream data.

This is required by TLS device offload to release
metadata associated with acknowledged TLS records.

Signed-off-by: Ilya Lesokhin <ilyal@mellanox.com>
Signed-off-by: Boris Pismenny <borisp@mellanox.com>
Signed-off-by: Aviad Yehezkel <aviadye@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 include/net/inet_connection_sock.h |  2 ++
 include/net/tcp.h                  |  8 ++++++++
 net/ipv4/tcp_input.c               | 23 +++++++++++++++++++++++
 3 files changed, 33 insertions(+)

diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
index b68fea022a82..2ab6667275df 100644
--- a/include/net/inet_connection_sock.h
+++ b/include/net/inet_connection_sock.h
@@ -77,6 +77,7 @@ struct inet_connection_sock_af_ops {
  * @icsk_af_ops		   Operations which are AF_INET{4,6} specific
  * @icsk_ulp_ops	   Pluggable ULP control hook
  * @icsk_ulp_data	   ULP private data
+ * @icsk_clean_acked	   Clean acked data hook
  * @icsk_listen_portaddr_node	hash to the portaddr listener hashtable
  * @icsk_ca_state:	   Congestion control state
  * @icsk_retransmits:	   Number of unrecovered [RTO] timeouts
@@ -102,6 +103,7 @@ struct inet_connection_sock {
 	const struct inet_connection_sock_af_ops *icsk_af_ops;
 	const struct tcp_ulp_ops  *icsk_ulp_ops;
 	void			  *icsk_ulp_data;
+	void (*icsk_clean_acked)(struct sock *sk, u32 acked_seq);
 	struct hlist_node         icsk_listen_portaddr_node;
 	unsigned int		  (*icsk_sync_mss)(struct sock *sk, u32 pmtu);
 	__u8			  icsk_ca_state:6,
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 9c9b3768b350..a15e294ced66 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -2101,4 +2101,12 @@ static inline bool tcp_bpf_ca_needs_ecn(struct sock *sk)
 #if IS_ENABLED(CONFIG_SMC)
 extern struct static_key_false tcp_have_smc;
 #endif
+
+#if IS_ENABLED(CONFIG_TLS_DEVICE)
+void clean_acked_data_enable(struct inet_connection_sock *icsk,
+			     void (*cad)(struct sock *sk, u32 ack_seq));
+void clean_acked_data_disable(struct inet_connection_sock *icsk);
+
+#endif
+
 #endif	/* _TCP_H */
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 451ef3012636..8cfc6d1ac804 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -111,6 +111,23 @@ int sysctl_tcp_max_orphans __read_mostly = NR_FILE;
 #define REXMIT_LOST	1 /* retransmit packets marked lost */
 #define REXMIT_NEW	2 /* FRTO-style transmit of unsent/new packets */
 
+#if IS_ENABLED(CONFIG_TLS_DEVICE)
+static DEFINE_STATIC_KEY_FALSE(clean_acked_data_enabled);
+
+void clean_acked_data_enable(struct inet_connection_sock *icsk,
+			     void (*cad)(struct sock *sk, u32 ack_seq))
+{
+	icsk->icsk_clean_acked = cad;
+	static_branch_inc(&clean_acked_data_enabled);
+}
+
+void clean_acked_data_disable(struct inet_connection_sock *icsk)
+{
+	static_branch_dec(&clean_acked_data_enabled);
+	icsk->icsk_clean_acked = NULL;
+}
+#endif
+
 static void tcp_gro_dev_warn(struct sock *sk, const struct sk_buff *skb,
 			     unsigned int len)
 {
@@ -3542,6 +3559,12 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 	if (after(ack, prior_snd_una)) {
 		flag |= FLAG_SND_UNA_ADVANCED;
 		icsk->icsk_retransmits = 0;
+
+#if IS_ENABLED(CONFIG_TLS_DEVICE)
+		if (static_branch_unlikely(&clean_acked_data_enabled))
+			if (icsk->icsk_clean_acked)
+				icsk->icsk_clean_acked(sk, ack);
+#endif
 	}
 
 	prior_fack = tcp_is_sack(tp) ? tcp_highest_sack_seq(tp) : tp->snd_una;
-- 
2.14.3

^ permalink raw reply related

* Re: [PATCH 4/6] rhashtable: allow a walk of the hash table without missing objects.
From: NeilBrown @ 2018-03-27 21:50 UTC (permalink / raw)
  To: David Miller; +Cc: tgraf, herbert, netdev, linux-kernel
In-Reply-To: <20180327.114941.997071660018188736.davem@davemloft.net>

[-- Attachment #1: Type: text/plain, Size: 954 bytes --]

On Tue, Mar 27 2018, David Miller wrote:

> From: NeilBrown <neilb@suse.com>
> Date: Tue, 27 Mar 2018 10:33:04 +1100
>
>> In many cases where the walker needs to drop out of RCU protection,
>> it will take a reference to the object and this can prevent it from
>> being removed from the hash table.  In those cases, the last-returned
>> object can still be used as a cursor.  rhashtable cannot detect
>> these cases itself.
>
> Merely having an elevated reference count does not explicitly prevent
> the object from being removed from the hash table.
>
> This invariant might hold for the particular user of the rhashtable
> instance, but it is not always the case.

Agreed.  Hence "In many case ... this *can* be prevented" and "In those
cases".

The doc comment for rhashtable_walk_start_continue() makes it clear
that:

 *   The
 * previously returned object must still be in the hash table, and must be
 * provided as an argument.

Thanks,
NeilBrown

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply

* [PATCH v6 1/2] dt-bindings: net: Add bindings for National Instruments XGE netdev
From: Moritz Fischer @ 2018-03-27 21:43 UTC (permalink / raw)
  To: davem
  Cc: linux-kernel, devicetree, netdev, robh+dt, andrew, f.fainelli,
	Moritz Fischer

This adds bindings for the NI XGE 1G/10G network device.

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Moritz Fischer <mdf@kernel.org>
---
Changes from v5:
- None

Changes from v4:
- None

Changes from v3:
- Added Rob's Reviewed-by

Changes from v2:
- Addressed Rob's comments w.r.t to IRQ names and typo

Changes from v1:
- Corrected from nixge -> nixge.txt

---

 Documentation/devicetree/bindings/net/nixge.txt | 32 +++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/nixge.txt

diff --git a/Documentation/devicetree/bindings/net/nixge.txt b/Documentation/devicetree/bindings/net/nixge.txt
new file mode 100644
index 000000000000..e55af7f0881a
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/nixge.txt
@@ -0,0 +1,32 @@
+* NI XGE Ethernet controller
+
+Required properties:
+- compatible: Should be "ni,xge-enet-2.00"
+- reg: Address and length of the register set for the device
+- interrupts: Should contain tx and rx interrupt
+- interrupt-names: Should be "rx" and "tx"
+- phy-mode: See ethernet.txt file in the same directory.
+- phy-handle: See ethernet.txt file in the same directory.
+- nvmem-cells: Phandle of nvmem cell containing the MAC address
+- nvmem-cell-names: Should be "address"
+
+Examples (10G generic PHY):
+	nixge0: ethernet@40000000 {
+		compatible = "ni,xge-enet-2.00";
+		reg = <0x40000000 0x6000>;
+
+		nvmem-cells = <&eth1_addr>;
+		nvmem-cell-names = "address";
+
+		interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>, <0 30 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "rx", "tx";
+		interrupt-parent = <&intc>;
+
+		phy-mode = "xgmii";
+		phy-handle = <&ethernet_phy1>;
+
+		ethernet_phy1: ethernet-phy@4 {
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reg = <4>;
+		};
+	};
-- 
2.16.2

^ permalink raw reply related

* [PATCH 1/6 v2] rhashtable: improve documentation for rhashtable_walk_peek()
From: NeilBrown @ 2018-03-27 21:45 UTC (permalink / raw)
  To: Thomas Graf, Herbert Xu
  Cc: netdev, linux-kernel, Tom Herbert, Andreas Gruenbacher
In-Reply-To: <152210718418.11435.11573013181393548255.stgit@noble>

[-- Attachment #1: Type: text/plain, Size: 3154 bytes --]


In this version I:
 - fixed brace-after-else coding style, thanks Sergei Shtylyov,
 - explained where the one user is, thanks David Miller
 - added CC for author of rhashtable_walk_peek (Tom Herbert) and
   of the one usage (Andreas Gruenbacher) - thanks Herbert Xu

NeilBrown

-----------------8<-------------------------
Subject: [PATCH] rhashtable: improve documentation for rhashtable_walk_peek()

The documentation for rhashtable_walk_peek() wrong.  It claims to
return the *next* entry, whereas it in fact returns the *previous*
entry.
However if no entries have yet been returned - or if the iterator
was reset due to a resize event, then rhashtable_walk_peek()
*does* return the next entry, but also advances the iterator.

I suspect that this interface should be discarded and the one user
should be changed to not require it.  The only current user is
gfs2_glock_iter_next in fs/gfs2/glock.c, which is part of the
implementation of a seq_file which reports all the content of the
hash table.
Possibly this patch should be seen as a first step in that
conversation.

This patch mostly corrects the documentation, but does make a
small code change so that the documentation can be correct without
listing too many special cases.  I don't think gfs2_glock_iter_next
will be affected by the code change.

Cc: Tom Herbert <tom@quantonium.net>
Cc: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: NeilBrown <neilb@suse.com>
---
 lib/rhashtable.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/lib/rhashtable.c b/lib/rhashtable.c
index 3825c30aaa36..9367816820ea 100644
--- a/lib/rhashtable.c
+++ b/lib/rhashtable.c
@@ -853,13 +853,17 @@ void *rhashtable_walk_next(struct rhashtable_iter *iter)
 EXPORT_SYMBOL_GPL(rhashtable_walk_next);
 
 /**
- * rhashtable_walk_peek - Return the next object but don't advance the iterator
+ * rhashtable_walk_peek - Return the previously returned object without advancing the iterator
  * @iter:	Hash table iterator
  *
- * Returns the next object or NULL when the end of the table is reached.
+ * Returns the last object returned, or NULL if no object has yet been returned.
+ * If the previously returned object has since been removed, then some other arbitrary
+ * object maybe returned, or possibly NULL will be returned.  In that case, the
+ * iterator might be advanced.
  *
  * Returns -EAGAIN if resize event occurred.  Note that the iterator
- * will rewind back to the beginning and you may continue to use it.
+ * will rewind back to the beginning and rhashtable_walk_next() should be
+ * used to get the next object.
  */
 void *rhashtable_walk_peek(struct rhashtable_iter *iter)
 {
@@ -880,6 +884,12 @@ void *rhashtable_walk_peek(struct rhashtable_iter *iter)
 		 * the table hasn't changed.
 		 */
 		iter->skip--;
+	} else {
+		/* ->skip is only zero after rhashtable_walk_start()
+		 * or when the iterator is reset.  In this case there
+		 * is no previous object to return.
+		 */
+		return NULL;
 	}
 
 	return __rhashtable_walk_find_next(iter);
-- 
2.14.0.rc0.dirty


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply related

* [PATCH v6 2/2] net: ethernet: nixge: Add support for National Instruments XGE netdev
From: Moritz Fischer @ 2018-03-27 21:43 UTC (permalink / raw)
  To: davem
  Cc: linux-kernel, devicetree, netdev, robh+dt, andrew, f.fainelli,
	Moritz Fischer
In-Reply-To: <20180327214315.3224-1-mdf@kernel.org>

Add support for the National Instruments XGE 1/10G network device.

It uses the EEPROM on the board via NVMEM.

Signed-off-by: Moritz Fischer <mdf@kernel.org>
---

Changes from v5:
- Fixed up indents according to David's feedback
- Fixed KConfig ---help--- -> help

Changes from v4:
- Worked on consistency for constants
- Removed unused constants
- Removed unused includes

Changes from v3:
- Added NIXGE prefix to MDIO constants
- Removed NIXGE_MAX_PHY_ADDR (unused)
- Consistency for NIXGE_MDIO_CXX_READ constants
- Use devm_mdiobus_alloc()
- Fixed order of netdev_unregister() and mdio_bus_unregister()
- Addressed feedback w.r.t. disconnecting the PHY
- Removed now superfluous max_frm_size member
- Fix SPDX vs module license to be 'GPL v2' 
  SPDX-License-Identifier: GPL-2.0

Changes from v2:
- Implement recv side NAPI
- Improved error handling
- Implemented C45 writes
- Added ethtool callbacks & blink functionality
- Improved nixge_ctrl_poll_timeout() macro
- Removed dev_dbg() for mdio accesses
- Added businfo to ethtool drvinfo

Changes from v1:
- Added dependency on ARCH_ZYNQ (Kbuild)
- Removed unused variables
- Use of_phy_connect as suggested
- Removed masking of (un)supported modes
- Added #define for some constants
- Removed empty pm functions
- Reworked mac_address handling
- Made nixge_mdio_*() static (sparse)
- Removed driver version
- Addressed timeout loop
- Adressed return values on timeout

---
 drivers/net/ethernet/Kconfig     |    1 +
 drivers/net/ethernet/Makefile    |    1 +
 drivers/net/ethernet/ni/Kconfig  |   27 +
 drivers/net/ethernet/ni/Makefile |    1 +
 drivers/net/ethernet/ni/nixge.c  | 1310 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 1340 insertions(+)
 create mode 100644 drivers/net/ethernet/ni/Kconfig
 create mode 100644 drivers/net/ethernet/ni/Makefile
 create mode 100644 drivers/net/ethernet/ni/nixge.c

diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 074d760a568b..603a5704dab8 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -128,6 +128,7 @@ config FEALNX
 
 source "drivers/net/ethernet/natsemi/Kconfig"
 source "drivers/net/ethernet/netronome/Kconfig"
+source "drivers/net/ethernet/ni/Kconfig"
 source "drivers/net/ethernet/8390/Kconfig"
 
 config NET_NETX
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 135dae67d671..2bfd2eea50bf 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_NET_VENDOR_MYRI) += myricom/
 obj-$(CONFIG_FEALNX) += fealnx.o
 obj-$(CONFIG_NET_VENDOR_NATSEMI) += natsemi/
 obj-$(CONFIG_NET_VENDOR_NETRONOME) += netronome/
+obj-$(CONFIG_NET_VENDOR_NI) += ni/
 obj-$(CONFIG_NET_NETX) += netx-eth.o
 obj-$(CONFIG_NET_VENDOR_NUVOTON) += nuvoton/
 obj-$(CONFIG_NET_VENDOR_NVIDIA) += nvidia/
diff --git a/drivers/net/ethernet/ni/Kconfig b/drivers/net/ethernet/ni/Kconfig
new file mode 100644
index 000000000000..cd30f7de16de
--- /dev/null
+++ b/drivers/net/ethernet/ni/Kconfig
@@ -0,0 +1,27 @@
+#
+# National Instuments network device configuration
+#
+
+config NET_VENDOR_NI
+	bool "National Instruments Devices"
+	default y
+	help
+	  If you have a network (Ethernet) device belonging to this class, say Y.
+
+	  Note that the answer to this question doesn't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about National Instrument devices.
+	  If you say Y, you will be asked for your specific device in the
+	  following questions.
+
+if NET_VENDOR_NI
+
+config NI_XGE_MANAGEMENT_ENET
+	tristate "National Instruments XGE management enet support"
+	depends on ARCH_ZYNQ
+	select PHYLIB
+	help
+	  Simple LAN device for debug or management purposes. Can
+	  support either 10G or 1G PHYs via SFP+ ports.
+
+endif
diff --git a/drivers/net/ethernet/ni/Makefile b/drivers/net/ethernet/ni/Makefile
new file mode 100644
index 000000000000..99c664651c51
--- /dev/null
+++ b/drivers/net/ethernet/ni/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_NI_XGE_MANAGEMENT_ENET) += nixge.o
diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c
new file mode 100644
index 000000000000..27364b7572fc
--- /dev/null
+++ b/drivers/net/ethernet/ni/nixge.c
@@ -0,0 +1,1310 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2016-2017, National Instruments Corp.
+ *
+ * Author: Moritz Fischer <mdf@kernel.org>
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of_address.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/skbuff.h>
+#include <linux/phy.h>
+#include <linux/mii.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/ethtool.h>
+#include <linux/iopoll.h>
+
+#define TX_BD_NUM		64
+#define RX_BD_NUM		128
+
+/* Axi DMA Register definitions */
+#define XAXIDMA_TX_CR_OFFSET	0x00 /* Channel control */
+#define XAXIDMA_TX_SR_OFFSET	0x04 /* Status */
+#define XAXIDMA_TX_CDESC_OFFSET	0x08 /* Current descriptor pointer */
+#define XAXIDMA_TX_TDESC_OFFSET	0x10 /* Tail descriptor pointer */
+
+#define XAXIDMA_RX_CR_OFFSET	0x30 /* Channel control */
+#define XAXIDMA_RX_SR_OFFSET	0x34 /* Status */
+#define XAXIDMA_RX_CDESC_OFFSET	0x38 /* Current descriptor pointer */
+#define XAXIDMA_RX_TDESC_OFFSET	0x40 /* Tail descriptor pointer */
+
+#define XAXIDMA_CR_RUNSTOP_MASK	0x1 /* Start/stop DMA channel */
+#define XAXIDMA_CR_RESET_MASK	0x4 /* Reset DMA engine */
+
+#define XAXIDMA_BD_CTRL_LENGTH_MASK	0x007FFFFF /* Requested len */
+#define XAXIDMA_BD_CTRL_TXSOF_MASK	0x08000000 /* First tx packet */
+#define XAXIDMA_BD_CTRL_TXEOF_MASK	0x04000000 /* Last tx packet */
+#define XAXIDMA_BD_CTRL_ALL_MASK	0x0C000000 /* All control bits */
+
+#define XAXIDMA_DELAY_MASK		0xFF000000 /* Delay timeout counter */
+#define XAXIDMA_COALESCE_MASK		0x00FF0000 /* Coalesce counter */
+
+#define XAXIDMA_DELAY_SHIFT		24
+#define XAXIDMA_COALESCE_SHIFT		16
+
+#define XAXIDMA_IRQ_IOC_MASK		0x00001000 /* Completion intr */
+#define XAXIDMA_IRQ_DELAY_MASK		0x00002000 /* Delay interrupt */
+#define XAXIDMA_IRQ_ERROR_MASK		0x00004000 /* Error interrupt */
+#define XAXIDMA_IRQ_ALL_MASK		0x00007000 /* All interrupts */
+
+/* Default TX/RX Threshold and waitbound values for SGDMA mode */
+#define XAXIDMA_DFT_TX_THRESHOLD	24
+#define XAXIDMA_DFT_TX_WAITBOUND	254
+#define XAXIDMA_DFT_RX_THRESHOLD	24
+#define XAXIDMA_DFT_RX_WAITBOUND	254
+
+#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK	0x007FFFFF /* Actual len */
+#define XAXIDMA_BD_STS_COMPLETE_MASK	0x80000000 /* Completed */
+#define XAXIDMA_BD_STS_DEC_ERR_MASK	0x40000000 /* Decode error */
+#define XAXIDMA_BD_STS_SLV_ERR_MASK	0x20000000 /* Slave error */
+#define XAXIDMA_BD_STS_INT_ERR_MASK	0x10000000 /* Internal err */
+#define XAXIDMA_BD_STS_ALL_ERR_MASK	0x70000000 /* All errors */
+#define XAXIDMA_BD_STS_RXSOF_MASK	0x08000000 /* First rx pkt */
+#define XAXIDMA_BD_STS_RXEOF_MASK	0x04000000 /* Last rx pkt */
+#define XAXIDMA_BD_STS_ALL_MASK		0xFC000000 /* All status bits */
+
+#define NIXGE_REG_CTRL_OFFSET	0x4000
+#define NIXGE_REG_INFO		0x00
+#define NIXGE_REG_MAC_CTL	0x04
+#define NIXGE_REG_PHY_CTL	0x08
+#define NIXGE_REG_LED_CTL	0x0c
+#define NIXGE_REG_MDIO_DATA	0x10
+#define NIXGE_REG_MDIO_ADDR	0x14
+#define NIXGE_REG_MDIO_OP	0x18
+#define NIXGE_REG_MDIO_CTRL	0x1c
+
+#define NIXGE_ID_LED_CTL_EN	BIT(0)
+#define NIXGE_ID_LED_CTL_VAL	BIT(1)
+
+#define NIXGE_MDIO_CLAUSE45	BIT(12)
+#define NIXGE_MDIO_CLAUSE22	0
+#define NIXGE_MDIO_OP(n)     (((n) & 0x3) << 10)
+#define NIXGE_MDIO_OP_ADDRESS	0
+#define NIXGE_MDIO_C45_WRITE	BIT(0)
+#define NIXGE_MDIO_C45_READ	(BIT(1) | BIT(0))
+#define NIXGE_MDIO_C22_WRITE	BIT(0)
+#define NIXGE_MDIO_C22_READ	BIT(1)
+#define NIXGE_MDIO_ADDR(n)   (((n) & 0x1f) << 5)
+#define NIXGE_MDIO_MMD(n)    (((n) & 0x1f) << 0)
+
+#define NIXGE_REG_MAC_LSB	0x1000
+#define NIXGE_REG_MAC_MSB	0x1004
+
+/* Packet size info */
+#define NIXGE_HDR_SIZE		14 /* Size of Ethernet header */
+#define NIXGE_TRL_SIZE		4 /* Size of Ethernet trailer (FCS) */
+#define NIXGE_MTU		1500 /* Max MTU of an Ethernet frame */
+#define NIXGE_JUMBO_MTU		9000 /* Max MTU of a jumbo Eth. frame */
+
+#define NIXGE_MAX_FRAME_SIZE	 (NIXGE_MTU + NIXGE_HDR_SIZE + NIXGE_TRL_SIZE)
+#define NIXGE_MAX_JUMBO_FRAME_SIZE \
+	(NIXGE_JUMBO_MTU + NIXGE_HDR_SIZE + NIXGE_TRL_SIZE)
+
+struct nixge_hw_dma_bd {
+	u32 next;
+	u32 reserved1;
+	u32 phys;
+	u32 reserved2;
+	u32 reserved3;
+	u32 reserved4;
+	u32 cntrl;
+	u32 status;
+	u32 app0;
+	u32 app1;
+	u32 app2;
+	u32 app3;
+	u32 app4;
+	u32 sw_id_offset;
+	u32 reserved5;
+	u32 reserved6;
+};
+
+struct nixge_tx_skb {
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+	size_t size;
+	bool mapped_as_page;
+};
+
+struct nixge_priv {
+	struct net_device *ndev;
+	struct napi_struct napi;
+	struct device *dev;
+
+	/* Connection to PHY device */
+	struct device_node *phy_node;
+	phy_interface_t		phy_mode;
+
+	int link;
+	unsigned int speed;
+	unsigned int duplex;
+
+	/* MDIO bus data */
+	struct mii_bus *mii_bus;	/* MII bus reference */
+
+	/* IO registers, dma functions and IRQs */
+	void __iomem *ctrl_regs;
+	void __iomem *dma_regs;
+
+	struct tasklet_struct dma_err_tasklet;
+
+	int tx_irq;
+	int rx_irq;
+	u32 last_link;
+
+	/* Buffer descriptors */
+	struct nixge_hw_dma_bd *tx_bd_v;
+	struct nixge_tx_skb *tx_skb;
+	dma_addr_t tx_bd_p;
+
+	struct nixge_hw_dma_bd *rx_bd_v;
+	dma_addr_t rx_bd_p;
+	u32 tx_bd_ci;
+	u32 tx_bd_tail;
+	u32 rx_bd_ci;
+
+	u32 coalesce_count_rx;
+	u32 coalesce_count_tx;
+};
+
+static void nixge_dma_write_reg(struct nixge_priv *priv, off_t offset, u32 val)
+{
+	writel(val, priv->dma_regs + offset);
+}
+
+static u32 nixge_dma_read_reg(const struct nixge_priv *priv, off_t offset)
+{
+	return readl(priv->dma_regs + offset);
+}
+
+static void nixge_ctrl_write_reg(struct nixge_priv *priv, off_t offset, u32 val)
+{
+	writel(val, priv->ctrl_regs + offset);
+}
+
+static u32 nixge_ctrl_read_reg(struct nixge_priv *priv, off_t offset)
+{
+	return readl(priv->ctrl_regs + offset);
+}
+
+#define nixge_ctrl_poll_timeout(priv, addr, val, cond, sleep_us, timeout_us) \
+	readl_poll_timeout((priv)->ctrl_regs + (addr), (val), (cond), \
+			   (sleep_us), (timeout_us))
+
+#define nixge_dma_poll_timeout(priv, addr, val, cond, sleep_us, timeout_us) \
+	readl_poll_timeout((priv)->dma_regs + (addr), (val), (cond), \
+			   (sleep_us), (timeout_us))
+
+static void nixge_hw_dma_bd_release(struct net_device *ndev)
+{
+	struct nixge_priv *priv = netdev_priv(ndev);
+	int i;
+
+	for (i = 0; i < RX_BD_NUM; i++) {
+		dma_unmap_single(ndev->dev.parent, priv->rx_bd_v[i].phys,
+				 NIXGE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE);
+		dev_kfree_skb((struct sk_buff *)
+			      (priv->rx_bd_v[i].sw_id_offset));
+	}
+
+	if (priv->rx_bd_v)
+		dma_free_coherent(ndev->dev.parent,
+				  sizeof(*priv->rx_bd_v) * RX_BD_NUM,
+				  priv->rx_bd_v,
+				  priv->rx_bd_p);
+
+	if (priv->tx_skb)
+		devm_kfree(ndev->dev.parent, priv->tx_skb);
+
+	if (priv->tx_bd_v)
+		dma_free_coherent(ndev->dev.parent,
+				  sizeof(*priv->tx_bd_v) * TX_BD_NUM,
+				  priv->tx_bd_v,
+				  priv->tx_bd_p);
+}
+
+static int nixge_hw_dma_bd_init(struct net_device *ndev)
+{
+	struct nixge_priv *priv = netdev_priv(ndev);
+	struct sk_buff *skb;
+	u32 cr;
+	int i;
+
+	/* Reset the indexes which are used for accessing the BDs */
+	priv->tx_bd_ci = 0;
+	priv->tx_bd_tail = 0;
+	priv->rx_bd_ci = 0;
+
+	/* Allocate the Tx and Rx buffer descriptors. */
+	priv->tx_bd_v = dma_zalloc_coherent(ndev->dev.parent,
+					    sizeof(*priv->tx_bd_v) * TX_BD_NUM,
+					    &priv->tx_bd_p, GFP_KERNEL);
+	if (!priv->tx_bd_v)
+		goto out;
+
+	priv->tx_skb = devm_kzalloc(ndev->dev.parent,
+				    sizeof(*priv->tx_skb) *
+				    TX_BD_NUM,
+				    GFP_KERNEL);
+	if (!priv->tx_skb)
+		goto out;
+
+	priv->rx_bd_v = dma_zalloc_coherent(ndev->dev.parent,
+					    sizeof(*priv->rx_bd_v) * RX_BD_NUM,
+					    &priv->rx_bd_p, GFP_KERNEL);
+	if (!priv->rx_bd_v)
+		goto out;
+
+	for (i = 0; i < TX_BD_NUM; i++) {
+		priv->tx_bd_v[i].next = priv->tx_bd_p +
+				      sizeof(*priv->tx_bd_v) *
+				      ((i + 1) % TX_BD_NUM);
+	}
+
+	for (i = 0; i < RX_BD_NUM; i++) {
+		priv->rx_bd_v[i].next = priv->rx_bd_p +
+				      sizeof(*priv->rx_bd_v) *
+				      ((i + 1) % RX_BD_NUM);
+
+		skb = netdev_alloc_skb_ip_align(ndev,
+						NIXGE_MAX_JUMBO_FRAME_SIZE);
+		if (!skb)
+			goto out;
+
+		priv->rx_bd_v[i].sw_id_offset = (u32)skb;
+		priv->rx_bd_v[i].phys =
+			dma_map_single(ndev->dev.parent,
+				       skb->data,
+				       NIXGE_MAX_JUMBO_FRAME_SIZE,
+				       DMA_FROM_DEVICE);
+		priv->rx_bd_v[i].cntrl = NIXGE_MAX_JUMBO_FRAME_SIZE;
+	}
+
+	/* Start updating the Rx channel control register */
+	cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET);
+	/* Update the interrupt coalesce count */
+	cr = ((cr & ~XAXIDMA_COALESCE_MASK) |
+	      ((priv->coalesce_count_rx) << XAXIDMA_COALESCE_SHIFT));
+	/* Update the delay timer count */
+	cr = ((cr & ~XAXIDMA_DELAY_MASK) |
+	      (XAXIDMA_DFT_RX_WAITBOUND << XAXIDMA_DELAY_SHIFT));
+	/* Enable coalesce, delay timer and error interrupts */
+	cr |= XAXIDMA_IRQ_ALL_MASK;
+	/* Write to the Rx channel control register */
+	nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET, cr);
+
+	/* Start updating the Tx channel control register */
+	cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET);
+	/* Update the interrupt coalesce count */
+	cr = (((cr & ~XAXIDMA_COALESCE_MASK)) |
+	      ((priv->coalesce_count_tx) << XAXIDMA_COALESCE_SHIFT));
+	/* Update the delay timer count */
+	cr = (((cr & ~XAXIDMA_DELAY_MASK)) |
+	      (XAXIDMA_DFT_TX_WAITBOUND << XAXIDMA_DELAY_SHIFT));
+	/* Enable coalesce, delay timer and error interrupts */
+	cr |= XAXIDMA_IRQ_ALL_MASK;
+	/* Write to the Tx channel control register */
+	nixge_dma_write_reg(priv, XAXIDMA_TX_CR_OFFSET, cr);
+
+	/* Populate the tail pointer and bring the Rx Axi DMA engine out of
+	 * halted state. This will make the Rx side ready for reception.
+	 */
+	nixge_dma_write_reg(priv, XAXIDMA_RX_CDESC_OFFSET, priv->rx_bd_p);
+	cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET);
+	nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET,
+			    cr | XAXIDMA_CR_RUNSTOP_MASK);
+	nixge_dma_write_reg(priv, XAXIDMA_RX_TDESC_OFFSET, priv->rx_bd_p +
+			    (sizeof(*priv->rx_bd_v) * (RX_BD_NUM - 1)));
+
+	/* Write to the RS (Run-stop) bit in the Tx channel control register.
+	 * Tx channel is now ready to run. But only after we write to the
+	 * tail pointer register that the Tx channel will start transmitting.
+	 */
+	nixge_dma_write_reg(priv, XAXIDMA_TX_CDESC_OFFSET, priv->tx_bd_p);
+	cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET);
+	nixge_dma_write_reg(priv, XAXIDMA_TX_CR_OFFSET,
+			    cr | XAXIDMA_CR_RUNSTOP_MASK);
+
+	return 0;
+out:
+	nixge_hw_dma_bd_release(ndev);
+	return -ENOMEM;
+}
+
+static void __nixge_device_reset(struct nixge_priv *priv, off_t offset)
+{
+	u32 status;
+	int err;
+
+	/* Reset Axi DMA. This would reset NIXGE Ethernet core as well.
+	 * The reset process of Axi DMA takes a while to complete as all
+	 * pending commands/transfers will be flushed or completed during
+	 * this reset process.
+	 */
+	nixge_dma_write_reg(priv, offset, XAXIDMA_CR_RESET_MASK);
+	err = nixge_dma_poll_timeout(priv, offset, status,
+				     !(status & XAXIDMA_CR_RESET_MASK), 10,
+				     1000);
+	if (err)
+		netdev_err(priv->ndev, "%s: DMA reset timeout!\n", __func__);
+}
+
+static void nixge_device_reset(struct net_device *ndev)
+{
+	struct nixge_priv *priv = netdev_priv(ndev);
+
+	__nixge_device_reset(priv, XAXIDMA_TX_CR_OFFSET);
+	__nixge_device_reset(priv, XAXIDMA_RX_CR_OFFSET);
+
+	if (nixge_hw_dma_bd_init(ndev))
+		netdev_err(ndev, "%s: descriptor allocation failed\n",
+			   __func__);
+
+	netif_trans_update(ndev);
+}
+
+static void nixge_handle_link_change(struct net_device *ndev)
+{
+	struct nixge_priv *priv = netdev_priv(ndev);
+	struct phy_device *phydev = ndev->phydev;
+
+	if (phydev->link != priv->link || phydev->speed != priv->speed ||
+	    phydev->duplex != priv->duplex) {
+		priv->link = phydev->link;
+		priv->speed = phydev->speed;
+		priv->duplex = phydev->duplex;
+		phy_print_status(phydev);
+	}
+}
+
+static void nixge_tx_skb_unmap(struct nixge_priv *priv,
+			       struct nixge_tx_skb *tx_skb)
+{
+	if (tx_skb->mapping) {
+		if (tx_skb->mapped_as_page)
+			dma_unmap_page(priv->ndev->dev.parent, tx_skb->mapping,
+				       tx_skb->size, DMA_TO_DEVICE);
+		else
+			dma_unmap_single(priv->ndev->dev.parent,
+					 tx_skb->mapping,
+					 tx_skb->size, DMA_TO_DEVICE);
+		tx_skb->mapping = 0;
+	}
+
+	if (tx_skb->skb) {
+		dev_kfree_skb_any(tx_skb->skb);
+		tx_skb->skb = NULL;
+	}
+}
+
+static void nixge_start_xmit_done(struct net_device *ndev)
+{
+	struct nixge_priv *priv = netdev_priv(ndev);
+	struct nixge_hw_dma_bd *cur_p;
+	struct nixge_tx_skb *tx_skb;
+	unsigned int status = 0;
+	u32 packets = 0;
+	u32 size = 0;
+
+	cur_p = &priv->tx_bd_v[priv->tx_bd_ci];
+	tx_skb = &priv->tx_skb[priv->tx_bd_ci];
+
+	status = cur_p->status;
+
+	while (status & XAXIDMA_BD_STS_COMPLETE_MASK) {
+		nixge_tx_skb_unmap(priv, tx_skb);
+		cur_p->status = 0;
+
+		size += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
+		packets++;
+
+		++priv->tx_bd_ci;
+		priv->tx_bd_ci %= TX_BD_NUM;
+		cur_p = &priv->tx_bd_v[priv->tx_bd_ci];
+		tx_skb = &priv->tx_skb[priv->tx_bd_ci];
+		status = cur_p->status;
+	}
+
+	ndev->stats.tx_packets += packets;
+	ndev->stats.tx_bytes += size;
+
+	if (packets)
+		netif_wake_queue(ndev);
+}
+
+static int nixge_check_tx_bd_space(struct nixge_priv *priv,
+				   int num_frag)
+{
+	struct nixge_hw_dma_bd *cur_p;
+
+	cur_p = &priv->tx_bd_v[(priv->tx_bd_tail + num_frag) % TX_BD_NUM];
+	if (cur_p->status & XAXIDMA_BD_STS_ALL_MASK)
+		return NETDEV_TX_BUSY;
+	return 0;
+}
+
+static int nixge_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	struct nixge_priv *priv = netdev_priv(ndev);
+	struct nixge_hw_dma_bd *cur_p;
+	struct nixge_tx_skb *tx_skb;
+	dma_addr_t tail_p;
+	skb_frag_t *frag;
+	u32 num_frag;
+	u32 ii;
+
+	num_frag = skb_shinfo(skb)->nr_frags;
+	cur_p = &priv->tx_bd_v[priv->tx_bd_tail];
+	tx_skb = &priv->tx_skb[priv->tx_bd_tail];
+
+	if (nixge_check_tx_bd_space(priv, num_frag)) {
+		if (!netif_queue_stopped(ndev))
+			netif_stop_queue(ndev);
+		return NETDEV_TX_OK;
+	}
+
+	cur_p->phys = dma_map_single(ndev->dev.parent, skb->data,
+				     skb_headlen(skb), DMA_TO_DEVICE);
+	if (dma_mapping_error(ndev->dev.parent, cur_p->phys))
+		goto drop;
+
+	cur_p->cntrl = skb_headlen(skb) | XAXIDMA_BD_CTRL_TXSOF_MASK;
+
+	tx_skb->skb = NULL;
+	tx_skb->mapping = cur_p->phys;
+	tx_skb->size = skb_headlen(skb);
+	tx_skb->mapped_as_page = false;
+
+	for (ii = 0; ii < num_frag; ii++) {
+		++priv->tx_bd_tail;
+		priv->tx_bd_tail %= TX_BD_NUM;
+		cur_p = &priv->tx_bd_v[priv->tx_bd_tail];
+		tx_skb = &priv->tx_skb[priv->tx_bd_tail];
+		frag = &skb_shinfo(skb)->frags[ii];
+
+		cur_p->phys = skb_frag_dma_map(ndev->dev.parent, frag, 0,
+					       skb_frag_size(frag),
+					       DMA_TO_DEVICE);
+		if (dma_mapping_error(ndev->dev.parent, cur_p->phys))
+			goto frag_err;
+
+		cur_p->cntrl = skb_frag_size(frag);
+
+		tx_skb->skb = NULL;
+		tx_skb->mapping = cur_p->phys;
+		tx_skb->size = skb_frag_size(frag);
+		tx_skb->mapped_as_page = true;
+	}
+
+	/* last buffer of the frame */
+	tx_skb->skb = skb;
+
+	cur_p->cntrl |= XAXIDMA_BD_CTRL_TXEOF_MASK;
+	cur_p->app4 = (unsigned long)skb;
+
+	tail_p = priv->tx_bd_p + sizeof(*priv->tx_bd_v) * priv->tx_bd_tail;
+	/* Start the transfer */
+	nixge_dma_write_reg(priv, XAXIDMA_TX_TDESC_OFFSET, tail_p);
+	++priv->tx_bd_tail;
+	priv->tx_bd_tail %= TX_BD_NUM;
+
+	return NETDEV_TX_OK;
+frag_err:
+	for (; ii > 0; ii--) {
+		if (priv->tx_bd_tail)
+			priv->tx_bd_tail--;
+		else
+			priv->tx_bd_tail = TX_BD_NUM - 1;
+
+		tx_skb = &priv->tx_skb[priv->tx_bd_tail];
+		nixge_tx_skb_unmap(priv, tx_skb);
+
+		cur_p = &priv->tx_bd_v[priv->tx_bd_tail];
+		cur_p->status = 0;
+	}
+	dma_unmap_single(priv->ndev->dev.parent,
+			 tx_skb->mapping,
+			 tx_skb->size, DMA_TO_DEVICE);
+drop:
+	ndev->stats.tx_dropped++;
+	return NETDEV_TX_OK;
+}
+
+static int nixge_recv(struct net_device *ndev, int budget)
+{
+	struct nixge_priv *priv = netdev_priv(ndev);
+	struct sk_buff *skb, *new_skb;
+	struct nixge_hw_dma_bd *cur_p;
+	dma_addr_t tail_p = 0;
+	u32 packets = 0;
+	u32 length = 0;
+	u32 size = 0;
+
+	cur_p = &priv->rx_bd_v[priv->rx_bd_ci];
+
+	while ((cur_p->status & XAXIDMA_BD_STS_COMPLETE_MASK &&
+		budget > packets)) {
+		tail_p = priv->rx_bd_p + sizeof(*priv->rx_bd_v) *
+			 priv->rx_bd_ci;
+
+		skb = (struct sk_buff *)(cur_p->sw_id_offset);
+
+		length = cur_p->status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
+		if (length > NIXGE_MAX_JUMBO_FRAME_SIZE)
+			length = NIXGE_MAX_JUMBO_FRAME_SIZE;
+
+		dma_unmap_single(ndev->dev.parent, cur_p->phys,
+				 NIXGE_MAX_JUMBO_FRAME_SIZE,
+				 DMA_FROM_DEVICE);
+
+		skb_put(skb, length);
+
+		skb->protocol = eth_type_trans(skb, ndev);
+		skb_checksum_none_assert(skb);
+
+		/* For now mark them as CHECKSUM_NONE since
+		 * we don't have offload capabilities
+		 */
+		skb->ip_summed = CHECKSUM_NONE;
+
+		napi_gro_receive(&priv->napi, skb);
+
+		size += length;
+		packets++;
+
+		new_skb = netdev_alloc_skb_ip_align(ndev,
+						    NIXGE_MAX_JUMBO_FRAME_SIZE);
+		if (!new_skb)
+			return packets;
+
+		cur_p->phys = dma_map_single(ndev->dev.parent, new_skb->data,
+					     NIXGE_MAX_JUMBO_FRAME_SIZE,
+					     DMA_FROM_DEVICE);
+		if (dma_mapping_error(ndev->dev.parent, cur_p->phys)) {
+			/* FIXME: bail out and clean up */
+			netdev_err(ndev, "Failed to map ...\n");
+		}
+		cur_p->cntrl = NIXGE_MAX_JUMBO_FRAME_SIZE;
+		cur_p->status = 0;
+		cur_p->sw_id_offset = (u32)new_skb;
+
+		++priv->rx_bd_ci;
+		priv->rx_bd_ci %= RX_BD_NUM;
+		cur_p = &priv->rx_bd_v[priv->rx_bd_ci];
+	}
+
+	ndev->stats.rx_packets += packets;
+	ndev->stats.rx_bytes += size;
+
+	if (tail_p)
+		nixge_dma_write_reg(priv, XAXIDMA_RX_TDESC_OFFSET, tail_p);
+
+	return packets;
+}
+
+static int nixge_poll(struct napi_struct *napi, int budget)
+{
+	struct nixge_priv *priv = container_of(napi, struct nixge_priv, napi);
+	int work_done;
+	u32 status, cr;
+
+	work_done = 0;
+
+	work_done = nixge_recv(priv->ndev, budget);
+	if (work_done < budget) {
+		napi_complete_done(napi, work_done);
+		status = nixge_dma_read_reg(priv, XAXIDMA_RX_SR_OFFSET);
+
+		if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) {
+			/* If there's more, reschedule, but clear */
+			nixge_dma_write_reg(priv, XAXIDMA_RX_SR_OFFSET, status);
+			napi_reschedule(napi);
+		} else {
+			/* if not, turn on RX IRQs again ... */
+			cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET);
+			cr |= (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK);
+			nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET, cr);
+		}
+	}
+
+	return work_done;
+}
+
+static irqreturn_t nixge_tx_irq(int irq, void *_ndev)
+{
+	struct nixge_priv *priv = netdev_priv(_ndev);
+	struct net_device *ndev = _ndev;
+	unsigned int status;
+	u32 cr;
+
+	status = nixge_dma_read_reg(priv, XAXIDMA_TX_SR_OFFSET);
+	if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) {
+		nixge_dma_write_reg(priv, XAXIDMA_TX_SR_OFFSET, status);
+		nixge_start_xmit_done(priv->ndev);
+		goto out;
+	}
+	if (!(status & XAXIDMA_IRQ_ALL_MASK)) {
+		netdev_err(ndev, "No interrupts asserted in Tx path\n");
+		return IRQ_NONE;
+	}
+	if (status & XAXIDMA_IRQ_ERROR_MASK) {
+		netdev_err(ndev, "DMA Tx error 0x%x\n", status);
+		netdev_err(ndev, "Current BD is at: 0x%x\n",
+			   (priv->tx_bd_v[priv->tx_bd_ci]).phys);
+
+		cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET);
+		/* Disable coalesce, delay timer and error interrupts */
+		cr &= (~XAXIDMA_IRQ_ALL_MASK);
+		/* Write to the Tx channel control register */
+		nixge_dma_write_reg(priv, XAXIDMA_TX_CR_OFFSET, cr);
+
+		cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET);
+		/* Disable coalesce, delay timer and error interrupts */
+		cr &= (~XAXIDMA_IRQ_ALL_MASK);
+		/* Write to the Rx channel control register */
+		nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET, cr);
+
+		tasklet_schedule(&priv->dma_err_tasklet);
+		nixge_dma_write_reg(priv, XAXIDMA_TX_SR_OFFSET, status);
+	}
+out:
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t nixge_rx_irq(int irq, void *_ndev)
+{
+	struct nixge_priv *priv = netdev_priv(_ndev);
+	struct net_device *ndev = _ndev;
+	unsigned int status;
+	u32 cr;
+
+	status = nixge_dma_read_reg(priv, XAXIDMA_RX_SR_OFFSET);
+	if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) {
+		/* Turn of IRQs because NAPI */
+		nixge_dma_write_reg(priv, XAXIDMA_RX_SR_OFFSET, status);
+		cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET);
+		cr &= ~(XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK);
+		nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET, cr);
+
+		if (napi_schedule_prep(&priv->napi))
+			__napi_schedule(&priv->napi);
+		goto out;
+	}
+	if (!(status & XAXIDMA_IRQ_ALL_MASK)) {
+		netdev_err(ndev, "No interrupts asserted in Rx path\n");
+		return IRQ_NONE;
+	}
+	if (status & XAXIDMA_IRQ_ERROR_MASK) {
+		netdev_err(ndev, "DMA Rx error 0x%x\n", status);
+		netdev_err(ndev, "Current BD is at: 0x%x\n",
+			   (priv->rx_bd_v[priv->rx_bd_ci]).phys);
+
+		cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET);
+		/* Disable coalesce, delay timer and error interrupts */
+		cr &= (~XAXIDMA_IRQ_ALL_MASK);
+		/* Finally write to the Tx channel control register */
+		nixge_dma_write_reg(priv, XAXIDMA_TX_CR_OFFSET, cr);
+
+		cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET);
+		/* Disable coalesce, delay timer and error interrupts */
+		cr &= (~XAXIDMA_IRQ_ALL_MASK);
+		/* write to the Rx channel control register */
+		nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET, cr);
+
+		tasklet_schedule(&priv->dma_err_tasklet);
+		nixge_dma_write_reg(priv, XAXIDMA_RX_SR_OFFSET, status);
+	}
+out:
+	return IRQ_HANDLED;
+}
+
+static void nixge_dma_err_handler(unsigned long data)
+{
+	struct nixge_priv *lp = (struct nixge_priv *)data;
+	struct nixge_hw_dma_bd *cur_p;
+	struct nixge_tx_skb *tx_skb;
+	u32 cr, i;
+
+	__nixge_device_reset(lp, XAXIDMA_TX_CR_OFFSET);
+	__nixge_device_reset(lp, XAXIDMA_RX_CR_OFFSET);
+
+	for (i = 0; i < TX_BD_NUM; i++) {
+		cur_p = &lp->tx_bd_v[i];
+		tx_skb = &lp->tx_skb[i];
+		nixge_tx_skb_unmap(lp, tx_skb);
+
+		cur_p->phys = 0;
+		cur_p->cntrl = 0;
+		cur_p->status = 0;
+		cur_p->app0 = 0;
+		cur_p->app1 = 0;
+		cur_p->app2 = 0;
+		cur_p->app3 = 0;
+		cur_p->app4 = 0;
+		cur_p->sw_id_offset = 0;
+	}
+
+	for (i = 0; i < RX_BD_NUM; i++) {
+		cur_p = &lp->rx_bd_v[i];
+		cur_p->status = 0;
+		cur_p->app0 = 0;
+		cur_p->app1 = 0;
+		cur_p->app2 = 0;
+		cur_p->app3 = 0;
+		cur_p->app4 = 0;
+	}
+
+	lp->tx_bd_ci = 0;
+	lp->tx_bd_tail = 0;
+	lp->rx_bd_ci = 0;
+
+	/* Start updating the Rx channel control register */
+	cr = nixge_dma_read_reg(lp, XAXIDMA_RX_CR_OFFSET);
+	/* Update the interrupt coalesce count */
+	cr = ((cr & ~XAXIDMA_COALESCE_MASK) |
+	      (XAXIDMA_DFT_RX_THRESHOLD << XAXIDMA_COALESCE_SHIFT));
+	/* Update the delay timer count */
+	cr = ((cr & ~XAXIDMA_DELAY_MASK) |
+	      (XAXIDMA_DFT_RX_WAITBOUND << XAXIDMA_DELAY_SHIFT));
+	/* Enable coalesce, delay timer and error interrupts */
+	cr |= XAXIDMA_IRQ_ALL_MASK;
+	/* Finally write to the Rx channel control register */
+	nixge_dma_write_reg(lp, XAXIDMA_RX_CR_OFFSET, cr);
+
+	/* Start updating the Tx channel control register */
+	cr = nixge_dma_read_reg(lp, XAXIDMA_TX_CR_OFFSET);
+	/* Update the interrupt coalesce count */
+	cr = (((cr & ~XAXIDMA_COALESCE_MASK)) |
+	      (XAXIDMA_DFT_TX_THRESHOLD << XAXIDMA_COALESCE_SHIFT));
+	/* Update the delay timer count */
+	cr = (((cr & ~XAXIDMA_DELAY_MASK)) |
+	      (XAXIDMA_DFT_TX_WAITBOUND << XAXIDMA_DELAY_SHIFT));
+	/* Enable coalesce, delay timer and error interrupts */
+	cr |= XAXIDMA_IRQ_ALL_MASK;
+	/* Finally write to the Tx channel control register */
+	nixge_dma_write_reg(lp, XAXIDMA_TX_CR_OFFSET, cr);
+
+	/* Populate the tail pointer and bring the Rx Axi DMA engine out of
+	 * halted state. This will make the Rx side ready for reception.
+	 */
+	nixge_dma_write_reg(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p);
+	cr = nixge_dma_read_reg(lp, XAXIDMA_RX_CR_OFFSET);
+	nixge_dma_write_reg(lp, XAXIDMA_RX_CR_OFFSET,
+			    cr | XAXIDMA_CR_RUNSTOP_MASK);
+	nixge_dma_write_reg(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p +
+			    (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
+
+	/* Write to the RS (Run-stop) bit in the Tx channel control register.
+	 * Tx channel is now ready to run. But only after we write to the
+	 * tail pointer register that the Tx channel will start transmitting
+	 */
+	nixge_dma_write_reg(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p);
+	cr = nixge_dma_read_reg(lp, XAXIDMA_TX_CR_OFFSET);
+	nixge_dma_write_reg(lp, XAXIDMA_TX_CR_OFFSET,
+			    cr | XAXIDMA_CR_RUNSTOP_MASK);
+}
+
+static int nixge_open(struct net_device *ndev)
+{
+	struct nixge_priv *priv = netdev_priv(ndev);
+	struct phy_device *phy;
+	int ret;
+
+	nixge_device_reset(ndev);
+
+	phy = of_phy_connect(ndev, priv->phy_node,
+			     &nixge_handle_link_change, 0, priv->phy_mode);
+	if (!phy)
+		return -ENODEV;
+
+	phy_start(phy);
+
+	/* Enable tasklets for Axi DMA error handling */
+	tasklet_init(&priv->dma_err_tasklet, nixge_dma_err_handler,
+		     (unsigned long)priv);
+
+	napi_enable(&priv->napi);
+
+	/* Enable interrupts for Axi DMA Tx */
+	ret = request_irq(priv->tx_irq, nixge_tx_irq, 0, ndev->name, ndev);
+	if (ret)
+		goto err_tx_irq;
+	/* Enable interrupts for Axi DMA Rx */
+	ret = request_irq(priv->rx_irq, nixge_rx_irq, 0, ndev->name, ndev);
+	if (ret)
+		goto err_rx_irq;
+
+	netif_start_queue(ndev);
+
+	return 0;
+
+err_rx_irq:
+	free_irq(priv->tx_irq, ndev);
+err_tx_irq:
+	phy_stop(phy);
+	phy_disconnect(phy);
+	tasklet_kill(&priv->dma_err_tasklet);
+	netdev_err(ndev, "request_irq() failed\n");
+	return ret;
+}
+
+static int nixge_stop(struct net_device *ndev)
+{
+	struct nixge_priv *priv = netdev_priv(ndev);
+	u32 cr;
+
+	netif_stop_queue(ndev);
+	napi_disable(&priv->napi);
+
+	if (ndev->phydev) {
+		phy_stop(ndev->phydev);
+		phy_disconnect(ndev->phydev);
+	}
+
+	cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET);
+	nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET,
+			    cr & (~XAXIDMA_CR_RUNSTOP_MASK));
+	cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET);
+	nixge_dma_write_reg(priv, XAXIDMA_TX_CR_OFFSET,
+			    cr & (~XAXIDMA_CR_RUNSTOP_MASK));
+
+	tasklet_kill(&priv->dma_err_tasklet);
+
+	free_irq(priv->tx_irq, ndev);
+	free_irq(priv->rx_irq, ndev);
+
+	nixge_hw_dma_bd_release(ndev);
+
+	return 0;
+}
+
+static int nixge_change_mtu(struct net_device *ndev, int new_mtu)
+{
+	if (netif_running(ndev))
+		return -EBUSY;
+
+	if ((new_mtu + NIXGE_HDR_SIZE + NIXGE_TRL_SIZE) >
+	     NIXGE_MAX_JUMBO_FRAME_SIZE)
+		return -EINVAL;
+
+	ndev->mtu = new_mtu;
+
+	return 0;
+}
+
+static s32 __nixge_hw_set_mac_address(struct net_device *ndev)
+{
+	struct nixge_priv *priv = netdev_priv(ndev);
+
+	nixge_ctrl_write_reg(priv, NIXGE_REG_MAC_LSB,
+			     (ndev->dev_addr[2]) << 24 |
+			     (ndev->dev_addr[3] << 16) |
+			     (ndev->dev_addr[4] << 8) |
+			     (ndev->dev_addr[5] << 0));
+
+	nixge_ctrl_write_reg(priv, NIXGE_REG_MAC_MSB,
+			     (ndev->dev_addr[1] | (ndev->dev_addr[0] << 8)));
+
+	return 0;
+}
+
+static int nixge_net_set_mac_address(struct net_device *ndev, void *p)
+{
+	int err;
+
+	err = eth_mac_addr(ndev, p);
+	if (!err)
+		__nixge_hw_set_mac_address(ndev);
+
+	return err;
+}
+
+static const struct net_device_ops nixge_netdev_ops = {
+	.ndo_open = nixge_open,
+	.ndo_stop = nixge_stop,
+	.ndo_start_xmit = nixge_start_xmit,
+	.ndo_change_mtu	= nixge_change_mtu,
+	.ndo_set_mac_address = nixge_net_set_mac_address,
+	.ndo_validate_addr = eth_validate_addr,
+};
+
+static void nixge_ethtools_get_drvinfo(struct net_device *ndev,
+				       struct ethtool_drvinfo *ed)
+{
+	strlcpy(ed->driver, "nixge", sizeof(ed->driver));
+	strlcpy(ed->bus_info, "platform", sizeof(ed->driver));
+}
+
+static int nixge_ethtools_get_coalesce(struct net_device *ndev,
+				       struct ethtool_coalesce *ecoalesce)
+{
+	struct nixge_priv *priv = netdev_priv(ndev);
+	u32 regval = 0;
+
+	regval = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET);
+	ecoalesce->rx_max_coalesced_frames = (regval & XAXIDMA_COALESCE_MASK)
+					     >> XAXIDMA_COALESCE_SHIFT;
+	regval = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET);
+	ecoalesce->tx_max_coalesced_frames = (regval & XAXIDMA_COALESCE_MASK)
+					     >> XAXIDMA_COALESCE_SHIFT;
+	return 0;
+}
+
+static int nixge_ethtools_set_coalesce(struct net_device *ndev,
+				       struct ethtool_coalesce *ecoalesce)
+{
+	struct nixge_priv *priv = netdev_priv(ndev);
+
+	if (netif_running(ndev)) {
+		netdev_err(ndev,
+			   "Please stop netif before applying configuration\n");
+		return -EBUSY;
+	}
+
+	if (ecoalesce->rx_coalesce_usecs ||
+	    ecoalesce->rx_coalesce_usecs_irq ||
+	    ecoalesce->rx_max_coalesced_frames_irq ||
+	    ecoalesce->tx_coalesce_usecs ||
+	    ecoalesce->tx_coalesce_usecs_irq ||
+	    ecoalesce->tx_max_coalesced_frames_irq ||
+	    ecoalesce->stats_block_coalesce_usecs ||
+	    ecoalesce->use_adaptive_rx_coalesce ||
+	    ecoalesce->use_adaptive_tx_coalesce ||
+	    ecoalesce->pkt_rate_low ||
+	    ecoalesce->rx_coalesce_usecs_low ||
+	    ecoalesce->rx_max_coalesced_frames_low ||
+	    ecoalesce->tx_coalesce_usecs_low ||
+	    ecoalesce->tx_max_coalesced_frames_low ||
+	    ecoalesce->pkt_rate_high ||
+	    ecoalesce->rx_coalesce_usecs_high ||
+	    ecoalesce->rx_max_coalesced_frames_high ||
+	    ecoalesce->tx_coalesce_usecs_high ||
+	    ecoalesce->tx_max_coalesced_frames_high ||
+	    ecoalesce->rate_sample_interval)
+		return -EOPNOTSUPP;
+	if (ecoalesce->rx_max_coalesced_frames)
+		priv->coalesce_count_rx = ecoalesce->rx_max_coalesced_frames;
+	if (ecoalesce->tx_max_coalesced_frames)
+		priv->coalesce_count_tx = ecoalesce->tx_max_coalesced_frames;
+
+	return 0;
+}
+
+static int nixge_ethtools_set_phys_id(struct net_device *ndev,
+				      enum ethtool_phys_id_state state)
+{
+	struct nixge_priv *priv = netdev_priv(ndev);
+	u32 ctrl;
+
+	ctrl = nixge_ctrl_read_reg(priv, NIXGE_REG_LED_CTL);
+	switch (state) {
+	case ETHTOOL_ID_ACTIVE:
+		ctrl |= NIXGE_ID_LED_CTL_EN;
+		/* Enable identification LED override*/
+		nixge_ctrl_write_reg(priv, NIXGE_REG_LED_CTL, ctrl);
+		return 2;
+
+	case ETHTOOL_ID_ON:
+		ctrl |= NIXGE_ID_LED_CTL_VAL;
+		nixge_ctrl_write_reg(priv, NIXGE_REG_LED_CTL, ctrl);
+		break;
+
+	case ETHTOOL_ID_OFF:
+		ctrl &= ~NIXGE_ID_LED_CTL_VAL;
+		nixge_ctrl_write_reg(priv, NIXGE_REG_LED_CTL, ctrl);
+		break;
+
+	case ETHTOOL_ID_INACTIVE:
+		/* Restore LED settings */
+		ctrl &= ~NIXGE_ID_LED_CTL_EN;
+		nixge_ctrl_write_reg(priv, NIXGE_REG_LED_CTL, ctrl);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct ethtool_ops nixge_ethtool_ops = {
+	.get_drvinfo    = nixge_ethtools_get_drvinfo,
+	.get_coalesce   = nixge_ethtools_get_coalesce,
+	.set_coalesce   = nixge_ethtools_set_coalesce,
+	.set_phys_id    = nixge_ethtools_set_phys_id,
+	.get_link_ksettings     = phy_ethtool_get_link_ksettings,
+	.set_link_ksettings     = phy_ethtool_set_link_ksettings,
+	.get_link		= ethtool_op_get_link,
+};
+
+static int nixge_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+	struct nixge_priv *priv = bus->priv;
+	u32 status, tmp;
+	int err;
+	u16 device;
+
+	if (reg & MII_ADDR_C45) {
+		device = (reg >> 16) & 0x1f;
+
+		nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_ADDR, reg & 0xffff);
+
+		tmp = NIXGE_MDIO_CLAUSE45 | NIXGE_MDIO_OP(NIXGE_MDIO_OP_ADDRESS)
+			| NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device);
+
+		nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_OP, tmp);
+		nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_CTRL, 1);
+
+		err = nixge_ctrl_poll_timeout(priv, NIXGE_REG_MDIO_CTRL, status,
+					      !status, 10, 1000);
+		if (err) {
+			dev_err(priv->dev, "timeout setting address");
+			return err;
+		}
+
+		tmp = NIXGE_MDIO_CLAUSE45 | NIXGE_MDIO_OP(NIXGE_MDIO_C45_READ) |
+			NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device);
+	} else {
+		device = reg & 0x1f;
+
+		tmp = NIXGE_MDIO_CLAUSE22 | NIXGE_MDIO_OP(NIXGE_MDIO_C22_READ) |
+			NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device);
+	}
+
+	nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_OP, tmp);
+	nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_CTRL, 1);
+
+	err = nixge_ctrl_poll_timeout(priv, NIXGE_REG_MDIO_CTRL, status,
+				      !status, 10, 1000);
+	if (err) {
+		dev_err(priv->dev, "timeout setting read command");
+		return err;
+	}
+
+	status = nixge_ctrl_read_reg(priv, NIXGE_REG_MDIO_DATA);
+
+	return status;
+}
+
+static int nixge_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
+{
+	struct nixge_priv *priv = bus->priv;
+	u32 status, tmp;
+	u16 device;
+	int err;
+
+	if (reg & MII_ADDR_C45) {
+		device = (reg >> 16) & 0x1f;
+
+		nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_ADDR, reg & 0xffff);
+
+		tmp = NIXGE_MDIO_CLAUSE45 | NIXGE_MDIO_OP(NIXGE_MDIO_OP_ADDRESS)
+			| NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device);
+
+		nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_OP, tmp);
+		nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_CTRL, 1);
+
+		err = nixge_ctrl_poll_timeout(priv, NIXGE_REG_MDIO_CTRL, status,
+					      !status, 10, 1000);
+		if (err) {
+			dev_err(priv->dev, "timeout setting address");
+			return err;
+		}
+
+		tmp = NIXGE_MDIO_CLAUSE45 | NIXGE_MDIO_OP(NIXGE_MDIO_C45_WRITE)
+			| NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device);
+
+		nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_DATA, val);
+		nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_OP, tmp);
+		err = nixge_ctrl_poll_timeout(priv, NIXGE_REG_MDIO_CTRL, status,
+					      !status, 10, 1000);
+		if (err)
+			dev_err(priv->dev, "timeout setting write command");
+	} else {
+		device = reg & 0x1f;
+
+		tmp = NIXGE_MDIO_CLAUSE22 |
+			NIXGE_MDIO_OP(NIXGE_MDIO_C22_WRITE) |
+			NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device);
+
+		nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_DATA, val);
+		nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_OP, tmp);
+		nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_CTRL, 1);
+
+		err = nixge_ctrl_poll_timeout(priv, NIXGE_REG_MDIO_CTRL, status,
+					      !status, 10, 1000);
+		if (err)
+			dev_err(priv->dev, "timeout setting write command");
+	}
+
+	return err;
+}
+
+static int nixge_mdio_setup(struct nixge_priv *priv, struct device_node *np)
+{
+	struct mii_bus *bus;
+
+	bus = devm_mdiobus_alloc(priv->dev);
+	if (!bus)
+		return -ENOMEM;
+
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(priv->dev));
+	bus->priv = priv;
+	bus->name = "nixge_mii_bus";
+	bus->read = nixge_mdio_read;
+	bus->write = nixge_mdio_write;
+	bus->parent = priv->dev;
+
+	priv->mii_bus = bus;
+
+	return of_mdiobus_register(bus, np);
+}
+
+static void *nixge_get_nvmem_address(struct device *dev)
+{
+	struct nvmem_cell *cell;
+	size_t cell_size;
+	char *mac;
+
+	cell = nvmem_cell_get(dev, "address");
+	if (IS_ERR(cell))
+		return cell;
+
+	mac = nvmem_cell_read(cell, &cell_size);
+	nvmem_cell_put(cell);
+
+	return mac;
+}
+
+static int nixge_probe(struct platform_device *pdev)
+{
+	struct nixge_priv *priv;
+	struct net_device *ndev;
+	struct resource *dmares;
+	const char *mac_addr;
+	int err;
+
+	ndev = alloc_etherdev(sizeof(*priv));
+	if (!ndev)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, ndev);
+	SET_NETDEV_DEV(ndev, &pdev->dev);
+
+	ndev->features = NETIF_F_SG;
+	ndev->netdev_ops = &nixge_netdev_ops;
+	ndev->ethtool_ops = &nixge_ethtool_ops;
+
+	/* MTU range: 64 - 9000 */
+	ndev->min_mtu = 64;
+	ndev->max_mtu = NIXGE_JUMBO_MTU;
+
+	mac_addr = nixge_get_nvmem_address(&pdev->dev);
+	if (mac_addr && is_valid_ether_addr(mac_addr))
+		ether_addr_copy(ndev->dev_addr, mac_addr);
+	else
+		eth_hw_addr_random(ndev);
+
+	priv = netdev_priv(ndev);
+	priv->ndev = ndev;
+	priv->dev = &pdev->dev;
+
+	netif_napi_add(ndev, &priv->napi, nixge_poll, NAPI_POLL_WEIGHT);
+
+	dmares = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->dma_regs = devm_ioremap_resource(&pdev->dev, dmares);
+	if (IS_ERR(priv->dma_regs)) {
+		netdev_err(ndev, "failed to map dma regs\n");
+		return PTR_ERR(priv->dma_regs);
+	}
+	priv->ctrl_regs = priv->dma_regs + NIXGE_REG_CTRL_OFFSET;
+	__nixge_hw_set_mac_address(ndev);
+
+	priv->tx_irq = platform_get_irq_byname(pdev, "tx");
+	if (priv->tx_irq < 0) {
+		netdev_err(ndev, "could not find 'tx' irq");
+		return priv->tx_irq;
+	}
+
+	priv->rx_irq = platform_get_irq_byname(pdev, "rx");
+	if (priv->rx_irq < 0) {
+		netdev_err(ndev, "could not find 'rx' irq");
+		return priv->rx_irq;
+	}
+
+	priv->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD;
+	priv->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD;
+
+	err = nixge_mdio_setup(priv, pdev->dev.of_node);
+	if (err) {
+		netdev_err(ndev, "error registering mdio bus");
+		goto free_netdev;
+	}
+
+	priv->phy_mode = of_get_phy_mode(pdev->dev.of_node);
+	if (priv->phy_mode < 0) {
+		netdev_err(ndev, "not find \"phy-mode\" property\n");
+		err = -EINVAL;
+		goto unregister_mdio;
+	}
+
+	priv->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
+	if (!priv->phy_node) {
+		netdev_err(ndev, "not find \"phy-handle\" property\n");
+		err = -EINVAL;
+		goto unregister_mdio;
+	}
+
+	err = register_netdev(priv->ndev);
+	if (err) {
+		netdev_err(ndev, "register_netdev() error (%i)\n", err);
+		goto unregister_mdio;
+	}
+
+	return 0;
+
+unregister_mdio:
+	mdiobus_unregister(priv->mii_bus);
+
+free_netdev:
+	free_netdev(ndev);
+
+	return err;
+}
+
+static int nixge_remove(struct platform_device *pdev)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct nixge_priv *priv = netdev_priv(ndev);
+
+	unregister_netdev(ndev);
+
+	mdiobus_unregister(priv->mii_bus);
+
+	free_netdev(ndev);
+
+	return 0;
+}
+
+/* Match table for of_platform binding */
+static const struct of_device_id nixge_dt_ids[] = {
+	{ .compatible = "ni,xge-enet-2.00", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, nixge_dt_ids);
+
+static struct platform_driver nixge_driver = {
+	.probe		= nixge_probe,
+	.remove		= nixge_remove,
+	.driver		= {
+		.name		= "nixge",
+		.of_match_table	= of_match_ptr(nixge_dt_ids),
+	},
+};
+module_platform_driver(nixge_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("National Instruments XGE Management MAC");
+MODULE_AUTHOR("Moritz Fischer <mdf@kernel.org>");
-- 
2.16.2

^ permalink raw reply related

* Re: RFC on writel and writel_relaxed
From: Benjamin Herrenschmidt @ 2018-03-27 21:35 UTC (permalink / raw)
  To: Sinan Kaya, Arnd Bergmann, Jason Gunthorpe
  Cc: David Laight, Oliver,
	open list:LINUX FOR POWERPC (32-BIT AND 64-BIT),
	linux-rdma@vger.kernel.org, Alexander Duyck, Will Deacon,
	Paul E. McKenney, netdev@vger.kernel.org, Alexander Duyck
In-Reply-To: <1e077f6a-90b6-cce9-6f0f-a8c003fec850@codeaurora.org>

On Tue, 2018-03-27 at 10:46 -0400, Sinan Kaya wrote:
>  combined buffers.
> 
> Alex:
> "Don't bother. I can tell you right now that for x86 you have to have a
> wmb() before the writel().

No, this isn't the semantics of writel. You shouldn't need it unless
something changed and we need to revisit our complete understanding of
*all* MMIO accessor semantics.

At least for UC space, it has always been accepted (and enforced) that
writel would not require any other barrier to order vs. previous stores
to memory.

> Based on the comment in
> (https://www.spinics.net/lists/linux-rdma/msg62666.html):
>     Replacing wmb() + writel() with wmb() + writel_relaxed() will work on
>     PPC, it will just not give you a benefit today.
> 
> I say the patch set stays. This gives benefit on ARM, and has no
> effect on x86 and PowerPC. If you want to look at trying to optimize
> things further on PowerPC and such then go for it in terms of trying
> to implement the writel_relaxed(). Otherwise I say we call the ARM
> goodness a win and don't get ourselves too wrapped up in trying to fix
> this for all architectures."

^ permalink raw reply

* Re: [PATCH 5/6] rhashtable: support guaranteed successful insertion.
From: NeilBrown @ 2018-03-27 21:34 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Thomas Graf, netdev, linux-kernel
In-Reply-To: <20180327155610.GD14001@gondor.apana.org.au>

[-- Attachment #1: Type: text/plain, Size: 1890 bytes --]

On Tue, Mar 27 2018, Herbert Xu wrote:

> On Tue, Mar 27, 2018 at 10:33:04AM +1100, NeilBrown wrote:
>> The current rhashtable will fail an insertion if the hashtable
>> it "too full", one of:
>>  - table already has 2^31 elements (-E2BIG)
>>  - a max_size was specified and table already has that
>>    many elements (rounded up to power of 2) (-E2BIG)
>>  - a single chain has more than 16 elements (-EBUSY)
>>  - table has more elements than the current table size,
>>    and allocating a new table fails (-ENOMEM)
>>  - a new page needed to be allocated for a nested table,
>>    and the memory allocation failed (-ENOMEM).
>> 
>> A traditional hash table does not have a concept of "too full", and
>> insertion only fails if the key already exists.  Many users of hash
>> tables have separate means of limiting the total number of entries,
>> and are not susceptible to an attack which could cause unusually large
>> hash chains.  For those users, the need to check for errors when
>> inserting objects to an rhashtable is an unnecessary burden and hence
>> a potential source of bugs (as these failures are likely to be rare).
>
> Did you actually encounter an insertion failure? The current code
> should never fail an insertion until you actually run ouf memory.
> That is unless you're using rhashtable when you should be using
> rhlist instead.

It is easy to get an -EBUSY insertion failure when .disable_count is
enabled, and I did get that.  Blindly propagating that up caused lustre
to get terribly confused - not too surprising really.

Even if I didn't seem errors in practive, if the interface can return an
error, then I need to check for the error and really should test that
handling each error works correctly.  It is much easier to write
reliable code when errors cannot happen, so I'd rather have that option.

Thanks,
NeilBrown

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply

* Re: RFC on writel and writel_relaxed
From: Benjamin Herrenschmidt @ 2018-03-27 21:33 UTC (permalink / raw)
  To: Alexander Duyck, Will Deacon
  Cc: Sinan Kaya, Arnd Bergmann, Jason Gunthorpe, David Laight, Oliver,
	open list:LINUX FOR POWERPC (32-BIT AND 64-BIT),
	linux-rdma@vger.kernel.org, Alexander Duyck, Paul E. McKenney,
	netdev@vger.kernel.org, Linus Torvalds
In-Reply-To: <CAKgT0Uem6HT-Z=HBnSVcC4rnDL0yFyXEbr+FN3YYkJ=ExZpUPQ@mail.gmail.com>

On Tue, 2018-03-27 at 11:54 -0700, Alexander Duyck wrote:
> As far as I know the code has been this way for a while, something
> like 2002, when the barrier was already present in e1000. However
> there it was calling out weakly ordered models "such as IA-64". Since
> then pretty much all the hardware based network drivers at this point
> have similar code floating around with wmb() in place to prevent
> issues on weak ordered memory systems.
> 
> So in any case we still need to be careful as there are architectures
> that are depending on this even if they might not be x86. :-/

Well, we need to clarify that once and for all, because as I wrote
earlier, it was decreed by Linus more than a decade ago that writel
would be fully ordered by itself vs. previous memory stores (at least
on UC memory).

This is why we added sync's to writel on powerpc and later ARM added
similar barriers to theirs.

This is also why writel_relaxed was added (though much later), since
what writel_relaxed does is to life that specific requirement.

IE. If what you say is true and wmb() is needed on x86, then
writel_relaxed is now completely useless...

Ben.

^ permalink raw reply

* Re: [PATCH v3 iproute2 1/1] tc: fix conversion types when printing actions unsigned values
From: Roman Mashak @ 2018-03-27 21:33 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, jhs, xiyou.wangcong, jiri
In-Reply-To: <20180327090234.5d457806@xeon-e3>

Stephen Hemminger <stephen@networkplumber.org> writes:

> On Mon, 19 Mar 2018 17:05:41 -0400
> Roman Mashak <mrv@mojatatu.com> wrote:
>
>> diff --git a/tc/m_gact.c b/tc/m_gact.c
>> index 16c4413f4217..52022415db48 100644
>> --- a/tc/m_gact.c
>> +++ b/tc/m_gact.c
>> @@ -194,7 +194,7 @@ print_gact(struct action_util *au, FILE *f, struct rtattr *arg)
>>  	print_string(PRINT_ANY, "random_type", "\n\t random type %s",
>>  		     prob_n2a(pp->ptype));
>>  	print_action_control(f, " ", pp->paction, " ");
>> -	print_int(PRINT_ANY, "val", "val %d", pp->pval);
>> +	print_int(PRINT_ANY, "val", "val %u", pp->pval);
>>  	close_json_object();
>
> This needs to be print_uint in order to work correctly with json output.
>
> Also, please consider doing json on all the match types in a later patch
> for net-next.

Did you mean iproute2-next?

^ permalink raw reply

* Re: [PATCH iproute2 1/1] tc: print index, refcnt & bindcnt for nat action
From: Roman Mashak @ 2018-03-27 21:32 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, jhs, xiyou.wangcong, jiri
In-Reply-To: <20180327090554.44e7c9e2@xeon-e3>

Stephen Hemminger <stephen@networkplumber.org> writes:

> On Tue, 20 Mar 2018 14:21:47 -0400
> Roman Mashak <mrv@mojatatu.com> wrote:
>
>> Signed-off-by: Roman Mashak <mrv@mojatatu.com>
>> ---
>>  tc/m_nat.c | 5 +++++
>>  1 file changed, 5 insertions(+)
>> 
>> diff --git a/tc/m_nat.c b/tc/m_nat.c
>> index 1e4ff51fe75a..f6e373957c1b 100644
>> --- a/tc/m_nat.c
>> +++ b/tc/m_nat.c
>> @@ -169,6 +169,9 @@ print_nat(struct action_util *au, FILE * f, struct rtattr *arg)
>>  		format_host_r(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)));
>>  	print_action_control(f, " ", sel->action, "");
>>  
>> +	fprintf(f, "\n\t index %u ref %d bind %d",
>> +		sel->index, sel->refcnt, sel->bindcnt);
>> +
>>  	if (show_stats) {
>>  		if (tb[TCA_NAT_TM]) {
>>  			struct tcf_t *tm = RTA_DATA(tb[TCA_NAT_TM]);
>> @@ -177,6 +180,8 @@ print_nat(struct action_util *au, FILE * f, struct rtattr *arg)
>>  		}
>>  	}
>>  
>> +	fprintf(f, "\n");
>> +
>>  	return 0;
>>  }
>
> Rather than printing newline all the time, you need to use _SL_ to keep the optional
> oneline output format.
>
> I.e
> 	fprintf(f, "%s\t index %u ref %d bind %d",
> 		_SL_, sel->index, sel->refcnt, sel->bindcnt);

tc currently doesn't support oneline mode, so I'll have to add it first,
then update all actions to use the oneliner.

^ permalink raw reply

* [PATCH net-next] net/mlx4_en: CHECKSUM_COMPLETE support for fragments
From: Eric Dumazet @ 2018-03-27 21:21 UTC (permalink / raw)
  To: David S . Miller
  Cc: netdev, Eric Dumazet, Eric Dumazet, Willem de Bruijn,
	Tariq Toukan

Refine the RX check summing handling to propagate the
hardware provided checksum so that we do not have to
compute it later in software.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Willem de Bruijn <willemb@google.com>
Cc: Tariq Toukan <tariqt@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/en_rx.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 05787efef492b1c0c6ce540ef73647fad91ce282..5c613c6663da51a4ae792eeb4d8956b54655786b 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -821,14 +821,12 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
 		skb_record_rx_queue(skb, cq_ring);
 
 		if (likely(dev->features & NETIF_F_RXCSUM)) {
-			if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_TCP |
-						      MLX4_CQE_STATUS_UDP)) {
+			if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_TCP |
+						       MLX4_CQE_STATUS_UDP)) &&
+			    (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
+			    cqe->checksum == cpu_to_be16(0xffff)) {
 				bool l2_tunnel;
 
-				if (!((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
-				      cqe->checksum == cpu_to_be16(0xffff)))
-					goto csum_none;
-
 				l2_tunnel = (dev->hw_enc_features & NETIF_F_RXCSUM) &&
 					(cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_L2_TUNNEL));
 				ip_summed = CHECKSUM_UNNECESSARY;
-- 
2.17.0.rc1.321.gba9d0f2565-goog

^ permalink raw reply related

* Re: [net-next PATCH v2 05/10] net: netcp: ethss: use rgmii link status for 2u cpsw hardware
From: Murali Karicheri @ 2018-03-27 21:07 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: mark.rutland, devicetree, malat, netdev, linux-kernel, w-kwok2,
	robh+dt, ssantosh, davem, linux-arm-kernel
In-Reply-To: <20180327172953.GP5862@lunn.ch>

On 03/27/2018 01:29 PM, Andrew Lunn wrote:
> On Tue, Mar 27, 2018 at 12:31:44PM -0400, Murali Karicheri wrote:
>> Introduce rgmii link status to handle link state events for 2u
>> cpsw hardware on K2G.
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>> ---
>>  drivers/net/ethernet/ti/netcp_ethss.c | 27 +++++++++++++++++++++++----
>>  1 file changed, 23 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c
>> index ab9d369..078a1b8 100644
>> --- a/drivers/net/ethernet/ti/netcp_ethss.c
>> +++ b/drivers/net/ethernet/ti/netcp_ethss.c
>> @@ -552,6 +552,7 @@ struct gbe_ss_regs {
>>  struct gbe_ss_regs_ofs {
>>  	u16	id_ver;
>>  	u16	control;
>> +	u16	rgmii_status; /* 2U */
>>  };
>>  
>>  struct gbe_switch_regs {
>> @@ -2120,23 +2121,39 @@ static bool gbe_phy_link_status(struct gbe_slave *slave)
>>  	 return !slave->phy || slave->phy->link;
>>  }
>>  
>> +#define RGMII_REG_STATUS_LINK	BIT(0)
>> +
>> +static void netcp_2u_rgmii_get_port_link(struct gbe_priv *gbe_dev, bool *status)
>> +{
>> +	u32 val = 0;
>> +
>> +	val = readl(GBE_REG_ADDR(gbe_dev, ss_regs, rgmii_status));
>> +	*status = false;
>> +	if ((val & RGMII_REG_STATUS_LINK) != 0)
>> +		*status = true;
> 
>   *status = !!(val & RGMII_REG_STATUS_LINK);
> 
> 
>> +}
>> +
>>  static void netcp_ethss_update_link_state(struct gbe_priv *gbe_dev,
>>  					  struct gbe_slave *slave,
>>  					  struct net_device *ndev)
>>  {
>> -	int sp = slave->slave_num;
>> -	int phy_link_state, sgmii_link_state = 1, link_state;
>> +	bool sw_link_state = true, phy_link_state;
>> +	int sp = slave->slave_num, link_state;
>>  
>>  	if (!slave->open)
>>  		return;
>>  
>>  	if (!SLAVE_LINK_IS_XGMII(slave)) {
>> -		sgmii_link_state =
>> +		if (SLAVE_LINK_IS_RGMII(slave))
>> +			netcp_2u_rgmii_get_port_link(gbe_dev,
>> +						     &sw_link_state);
>> +		else
>> +			sw_link_state =
>>  			netcp_sgmii_get_port_link(SGMII_BASE(gbe_dev, sp), sp);
> 
> This would be more readable as
> 
>      if (SLAVE_LINK_IS_RGMII(slave))
> 		netcp_2u_rgmii_get_port_link(gbe_dev,
> 					     &sw_link_state);
>      if (SLAVE_LINK_IS_SGMII(slave))
> 	sw_link_state = netcp_sgmii_get_port_link(
> 	   SGMII_BASE(gbe_dev, sp), sp);
> 
Probably better to use a switch statement in this case for better readability?
handle only SGMII and RGMII cases in the switch statement.

Murali

>    Andrew
> 


-- 
Murali Karicheri
Linux Kernel, Keystone

^ permalink raw reply

* Re: [PATCH v6 bpf-next 08/11] bpf: introduce BPF_RAW_TRACEPOINT
From: Steven Rostedt @ 2018-03-27 21:04 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: davem, daniel, torvalds, peterz, netdev, kernel-team, linux-api,
	Mathieu Desnoyers, Kees Cook
In-Reply-To: <20180327145824.602dfdec@gandalf.local.home>

On Tue, 27 Mar 2018 14:58:24 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> +extern struct bpf_raw_event_map *__start__bpf_raw_tp[];
> +extern struct bpf_raw_event_map *__stop__bpf_raw_tp[];
> +
> +struct bpf_raw_event_map *bpf_find_raw_tracepoint(const char *name)
> +{
> +	struct bpf_raw_event_map* const *btp = __start__bpf_raw_tp;
> +
> +	for (; btp < __stop__bpf_raw_tp; btp++)
> +		if (!strcmp((*btp)->tp->name, name))
> +			return *btp;
> +	return NULL;
> +}
> +

OK, this part is broken, and for some reason it didn't include my
changes to bpf_probe.h. I also tested this without setting BPF_EVENTS,
so I wasn't actually testing it.

I added a test in event_trace_init() to make sure that it worked:
(Not included in the patch below)

{
	struct bpf_raw_event_map *btp;
	btp = bpf_find_raw_tracepoint("sched_switch");
	if (btp)
		printk("found BPF_RAW_TRACEPOINT: %s %pS\n",
		       btp->tp->name, btp->bpf_func);
	else
		printk("COULD NOT FIND BPF_RAW_TRACEPOINT\n");
}

And it found the tracepoint.

Here's take two....

You can add my: Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>

-- Steve

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 1ab0e520d6fc..4fab7392e237 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -178,6 +178,15 @@
 #define TRACE_SYSCALLS()
 #endif
 
+#ifdef CONFIG_BPF_EVENTS
+#define BPF_RAW_TP() . = ALIGN(8);		\
+			 VMLINUX_SYMBOL(__start__bpf_raw_tp) = .;	\
+			 KEEP(*(__bpf_raw_tp_map))			\
+			 VMLINUX_SYMBOL(__stop__bpf_raw_tp) = .;
+#else
+#define BPF_RAW_TP()
+#endif
+
 #ifdef CONFIG_SERIAL_EARLYCON
 #define EARLYCON_TABLE() STRUCT_ALIGN();			\
 			 VMLINUX_SYMBOL(__earlycon_table) = .;	\
@@ -576,6 +585,7 @@
 	*(.init.rodata)							\
 	FTRACE_EVENTS()							\
 	TRACE_SYSCALLS()						\
+	BPF_RAW_TP()							\
 	KPROBE_BLACKLIST()						\
 	ERROR_INJECT_WHITELIST()					\
 	MEM_DISCARD(init.rodata)					\
diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index 399ebe6f90cf..fb4778c0a248 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -470,8 +470,9 @@ unsigned int trace_call_bpf(struct trace_event_call *call, void *ctx);
 int perf_event_attach_bpf_prog(struct perf_event *event, struct bpf_prog *prog);
 void perf_event_detach_bpf_prog(struct perf_event *event);
 int perf_event_query_prog_array(struct perf_event *event, void __user *info);
-int bpf_probe_register(struct tracepoint *tp, struct bpf_prog *prog);
-int bpf_probe_unregister(struct tracepoint *tp, struct bpf_prog *prog);
+int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog);
+int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *prog);
+struct bpf_raw_event_map *bpf_find_raw_tracepoint(const char *name);
 #else
 static inline unsigned int trace_call_bpf(struct trace_event_call *call, void *ctx)
 {
@@ -491,14 +492,18 @@ perf_event_query_prog_array(struct perf_event *event, void __user *info)
 {
 	return -EOPNOTSUPP;
 }
-static inline int bpf_probe_register(struct tracepoint *tp, struct bpf_prog *p)
+static inline int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *p)
 {
 	return -EOPNOTSUPP;
 }
-static inline int bpf_probe_unregister(struct tracepoint *tp, struct bpf_prog *p)
+static inline int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *p)
 {
 	return -EOPNOTSUPP;
 }
+static inline struct bpf_raw_event_map *bpf_find_raw_tracepoint(const char *name)
+{
+	return NULL;
+}
 #endif
 
 enum {
diff --git a/include/linux/tracepoint-defs.h b/include/linux/tracepoint-defs.h
index 39a283c61c51..35db8dd48c4c 100644
--- a/include/linux/tracepoint-defs.h
+++ b/include/linux/tracepoint-defs.h
@@ -36,4 +36,9 @@ struct tracepoint {
 	u32 num_args;
 };
 
+struct bpf_raw_event_map {
+	struct tracepoint	*tp;
+	void			*bpf_func;
+};
+
 #endif
diff --git a/include/trace/bpf_probe.h b/include/trace/bpf_probe.h
index d2cc0663e618..bb8ed2f530ad 100644
--- a/include/trace/bpf_probe.h
+++ b/include/trace/bpf_probe.h
@@ -76,7 +76,13 @@ __bpf_trace_##call(void *__data, proto)					\
 static inline void bpf_test_probe_##call(void)				\
 {									\
 	check_trace_callback_type_##call(__bpf_trace_##template);	\
-}
+}									\
+static struct bpf_raw_event_map	__used					\
+   __attribute__((section("__bpf_raw_tp_map")))				\
+__bpf_trace_tp_map_##call= {						\
+	.tp		= &__tracepoint_##call,				\
+	.bpf_func	= (void *)__bpf_trace_##template,		\
+};
 
 
 #undef DEFINE_EVENT_PRINT
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index f100c63ff19e..6037a2f0108a 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -1312,7 +1312,7 @@ static int bpf_obj_get(const union bpf_attr *attr)
 }
 
 struct bpf_raw_tracepoint {
-	struct tracepoint *tp;
+	struct bpf_raw_event_map *btp;
 	struct bpf_prog *prog;
 };
 
@@ -1321,7 +1321,7 @@ static int bpf_raw_tracepoint_release(struct inode *inode, struct file *filp)
 	struct bpf_raw_tracepoint *raw_tp = filp->private_data;
 
 	if (raw_tp->prog) {
-		bpf_probe_unregister(raw_tp->tp, raw_tp->prog);
+		bpf_probe_unregister(raw_tp->btp, raw_tp->prog);
 		bpf_prog_put(raw_tp->prog);
 	}
 	kfree(raw_tp);
@@ -1339,7 +1339,7 @@ static const struct file_operations bpf_raw_tp_fops = {
 static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
 {
 	struct bpf_raw_tracepoint *raw_tp;
-	struct tracepoint *tp;
+	struct bpf_raw_event_map *btp;
 	struct bpf_prog *prog;
 	char tp_name[128];
 	int tp_fd, err;
@@ -1349,14 +1349,14 @@ static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
 		return -EFAULT;
 	tp_name[sizeof(tp_name) - 1] = 0;
 
-	tp = kernel_tracepoint_find_by_name(tp_name);
-	if (!tp)
+	btp = bpf_find_raw_tracepoint(tp_name);
+	if (!btp)
 		return -ENOENT;
 
 	raw_tp = kmalloc(sizeof(*raw_tp), GFP_USER | __GFP_ZERO);
 	if (!raw_tp)
 		return -ENOMEM;
-	raw_tp->tp = tp;
+	raw_tp->btp = btp;
 
 	prog = bpf_prog_get_type(attr->raw_tracepoint.prog_fd,
 				 BPF_PROG_TYPE_RAW_TRACEPOINT);
@@ -1365,7 +1365,7 @@ static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
 		goto out_free_tp;
 	}
 
-	err = bpf_probe_register(raw_tp->tp, prog);
+	err = bpf_probe_register(raw_tp->btp, prog);
 	if (err)
 		goto out_put_prog;
 
@@ -1373,7 +1373,7 @@ static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
 	tp_fd = anon_inode_getfd("bpf-raw-tracepoint", &bpf_raw_tp_fops, raw_tp,
 				 O_CLOEXEC);
 	if (tp_fd < 0) {
-		bpf_probe_unregister(raw_tp->tp, prog);
+		bpf_probe_unregister(raw_tp->btp, prog);
 		err = tp_fd;
 		goto out_put_prog;
 	}
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index eb58ef156d36..d0975094cff7 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -965,6 +965,22 @@ int perf_event_query_prog_array(struct perf_event *event, void __user *info)
 	return ret;
 }
 
+extern struct bpf_raw_event_map __start__bpf_raw_tp;
+extern struct bpf_raw_event_map __stop__bpf_raw_tp;
+
+struct bpf_raw_event_map *bpf_find_raw_tracepoint(const char *name)
+{
+	const struct bpf_raw_event_map *btp = &__start__bpf_raw_tp;
+	int i = 0;
+
+	for (; btp < &__stop__bpf_raw_tp; btp++) {
+		i++;
+		if (!strcmp(btp->tp->name, name))
+			return btp;
+	}
+	return NULL;
+}
+
 static __always_inline
 void __bpf_trace_run(struct bpf_prog *prog, u64 *args)
 {
@@ -1020,10 +1036,9 @@ BPF_TRACE_DEFN_x(10);
 BPF_TRACE_DEFN_x(11);
 BPF_TRACE_DEFN_x(12);
 
-static int __bpf_probe_register(struct tracepoint *tp, struct bpf_prog *prog)
+static int __bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog)
 {
-	unsigned long addr;
-	char buf[128];
+	struct tracepoint *tp = btp->tp;
 
 	/*
 	 * check that program doesn't access arguments beyond what's
@@ -1032,43 +1047,25 @@ static int __bpf_probe_register(struct tracepoint *tp, struct bpf_prog *prog)
 	if (prog->aux->max_ctx_offset > tp->num_args * sizeof(u64))
 		return -EINVAL;
 
-	snprintf(buf, sizeof(buf), "__bpf_trace_%s", tp->name);
-	addr = kallsyms_lookup_name(buf);
-	if (!addr)
-		return -ENOENT;
-
-	return tracepoint_probe_register(tp, (void *)addr, prog);
+	return tracepoint_probe_register(tp, (void *)btp->bpf_func, prog);
 }
 
-int bpf_probe_register(struct tracepoint *tp, struct bpf_prog *prog)
+int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog)
 {
 	int err;
 
 	mutex_lock(&bpf_event_mutex);
-	err = __bpf_probe_register(tp, prog);
+	err = __bpf_probe_register(btp, prog);
 	mutex_unlock(&bpf_event_mutex);
 	return err;
 }
 
-static int __bpf_probe_unregister(struct tracepoint *tp, struct bpf_prog *prog)
-{
-	unsigned long addr;
-	char buf[128];
-
-	snprintf(buf, sizeof(buf), "__bpf_trace_%s", tp->name);
-	addr = kallsyms_lookup_name(buf);
-	if (!addr)
-		return -ENOENT;
-
-	return tracepoint_probe_unregister(tp, (void *)addr, prog);
-}
-
-int bpf_probe_unregister(struct tracepoint *tp, struct bpf_prog *prog)
+int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *prog)
 {
 	int err;
 
 	mutex_lock(&bpf_event_mutex);
-	err = __bpf_probe_unregister(tp, prog);
+	err = tracepoint_probe_unregister(btp->tp, (void *)btp->bpf_func, prog);
 	mutex_unlock(&bpf_event_mutex);
 	return err;
 }

^ permalink raw reply related

* Re: [PATCH] bpf: follow idr code convention
From: Daniel Borkmann @ 2018-03-27 20:58 UTC (permalink / raw)
  To: Shaohua Li, netdev @ vger . kernel . org
  Cc: Kernel Team, Shaohua Li, Alexei Starovoitov
In-Reply-To: <90243b64dad0d1de21f1a57994d2c43e5facbb33.1522175003.git.shli@fb.com>

On 03/27/2018 08:53 PM, Shaohua Li wrote:
> From: Shaohua Li <shli@fb.com>
> 
> Generally we do a preload before doing idr allocation. This also help
> improve the allocation success rate in memory pressure.
> 
> Cc: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Alexei Starovoitov <ast@kernel.org>
> Signed-off-by: Shaohua Li <shli@fb.com>

Looks good, applied to bpf-next, thanks Shaohua!

^ permalink raw reply

* Re: RFC on writel and writel_relaxed
From: Arnd Bergmann @ 2018-03-27 20:46 UTC (permalink / raw)
  To: Alexander Duyck
  Cc: Will Deacon, Sinan Kaya, Benjamin Herrenschmidt, Jason Gunthorpe,
	David Laight, Oliver,
	open list:LINUX FOR POWERPC (32-BIT AND 64-BIT),
	linux-rdma@vger.kernel.org, Alexander Duyck, Paul E. McKenney,
	netdev@vger.kernel.org, Linus Torvalds
In-Reply-To: <CAK8P3a0MuGs4ifvJefyuSAxgJum-5dvWTOQNLjHCwo9oe3qwuA@mail.gmail.com>

On Tue, Mar 27, 2018 at 9:54 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Tue, Mar 27, 2018 at 8:54 PM, Alexander Duyck
> <alexander.duyck@gmail.com> wrote:
>> On Tue, Mar 27, 2018 at 8:10 AM, Will Deacon <will.deacon@arm.com> wrote:
>
> 11.10 STORE BUFFER
> Intel 64 and IA-32 processors temporarily store each write (store) to
> memory in a store buffer. The store buffer
> improves processor performance by allowing the processor to continue
> executing instructions without having to
> wait until a write to memory and/or to a cache is complete. It also
> allows writes to be delayed for more efficient use
> of memory-access bus cycles.
> In general, the existence of the store buffer is transparent to
> software, even in systems that use multiple processors.
> The processor ensures that write operations are always carried out in
> program order. It also insures that the
> contents of the store buffer are always drained to memory in the
> following situations:
> • When an exception or interrupt is generated.
> • (P6 and more recent processor families only) When a serializing
> instruction is executed.
> • When an I/O instruction is executed.

I guess I/O instruction is still ambiguous on x86, it may just refer
to 'inb'/'outb' style instructions rather than 'mov' on a device MMIO
area.

Here's a link to a reply from Linus that I found on this topic:

http://yarchive.net/comp/linux/write_combining.html

      Arnd

^ permalink raw reply

* Re: [PATCH v13 net-next 02/12] ethtool: enable Inline TLS in HW
From: Sabrina Dubroca @ 2018-03-27 20:44 UTC (permalink / raw)
  To: Atul Gupta
  Cc: davem, herbert, davejwatson, sbrivio, linux-crypto, netdev,
	werner, leedom, swise, indranil, ganeshgr
In-Reply-To: <1522172201-7629-3-git-send-email-atul.gupta@chelsio.com>

2018-03-27, 23:06:31 +0530, Atul Gupta wrote:
> Ethtool option enables TLS record offload on HW, user
> configures the feature for netdev capable of Inline TLS.
> This allows user to define custom sk_prot for Inline TLS sock
> 
> Signed-off-by: Atul Gupta <atul.gupta@chelsio.com>
> Reviewed-by: Sabrina Dubroca <sdubroca@redhat.com>

uh, what? I definitely didn't give my "Reviewed-by" for any of these
patches. Please never do that again.

-- 
Sabrina

^ permalink raw reply

* HI
From: Lucy Boston @ 2018-03-27 20:39 UTC (permalink / raw)


-- 
Greeting, once again is me Lucy Boston this is twice am contacting you
please is very urgent respond to me for more details through my.
Email:

dr.lucyboston@gmail.com

^ permalink raw reply

* Re: RFC on writel and writel_relaxed
From: Arnd Bergmann @ 2018-03-27 19:54 UTC (permalink / raw)
  To: Alexander Duyck
  Cc: Will Deacon, Sinan Kaya, Benjamin Herrenschmidt, Jason Gunthorpe,
	David Laight, Oliver,
	open list:LINUX FOR POWERPC (32-BIT AND 64-BIT),
	linux-rdma@vger.kernel.org, Alexander Duyck, Paul E. McKenney,
	netdev@vger.kernel.org, Linus Torvalds
In-Reply-To: <CAKgT0Uem6HT-Z=HBnSVcC4rnDL0yFyXEbr+FN3YYkJ=ExZpUPQ@mail.gmail.com>

On Tue, Mar 27, 2018 at 8:54 PM, Alexander Duyck
<alexander.duyck@gmail.com> wrote:
> On Tue, Mar 27, 2018 at 8:10 AM, Will Deacon <will.deacon@arm.com> wrote:

>>>
>>> Sinan
>>> "We are being told that if you use writel(), then you don't need a wmb() on
>>> all architectures."
>>>
>>> Alex:
>>> "I'm not sure who told you that but that is incorrect, at least for
>>> x86. If you attempt to use writel() without the wmb() we will have to
>>> NAK the patches. We will accept the wmb() with writel_releaxed() since
>>> that solves things for ARM."
>>>
>>> > Jason is seeking behavior clarification for write combined buffers.
>>>
>>> Alex:
>>> "Don't bother. I can tell you right now that for x86 you have to have a
>>> wmb() before the writel().
>>
>> To clarify: are you saying that on x86 you need a wmb() prior to a writel
>> if you want that writel to be ordered after prior writes to memory? Is this
>> specific to WC memory or some other non-standard attribute?
>
> Note, I am not a CPU guy so this is just my interpretation. It is my
> understanding that the wmb(), aka sfence, is needed on x86 to sort out
> writes between Write-back(WB) system memory and Strong Uncacheable
> (UC) MMIO accesses.
>
> I was hoping to be able to cite something in the software developers
> manual (https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf),
> but that tends to be pretty vague. I have re-read section 22.34
> (volume 3B) several times and I am still not clear on if it says we
> need the sfence or not. It is a matter of figuring out what the impact
> of store buffers and caching are for WB versus UC memory.

Here is what I found regarding the store buffer in that document:

11.10 STORE BUFFER
Intel 64 and IA-32 processors temporarily store each write (store) to
memory in a store buffer. The store buffer
improves processor performance by allowing the processor to continue
executing instructions without having to
wait until a write to memory and/or to a cache is complete. It also
allows writes to be delayed for more efficient use
of memory-access bus cycles.
In general, the existence of the store buffer is transparent to
software, even in systems that use multiple processors.
The processor ensures that write operations are always carried out in
program order. It also insures that the
contents of the store buffer are always drained to memory in the
following situations:
• When an exception or interrupt is generated.
• (P6 and more recent processor families only) When a serializing
instruction is executed.
• When an I/O instruction is executed.
• When a LOCK operation is performed.
• (P6 and more recent processor families only) When a BINIT operation
is performed.
• (Pentium III, and more recent processor families only) When using an
SFENCE instruction to order stores.
• (Pentium 4 and more recent processor families only) When using an
MFENCE instruction to order stores.
The discussion of write ordering in Section 8.2, “Memory Ordering,”
gives a detailed description of the operation of
the store buffer.

       Arnd

^ permalink raw reply

* Re: possible deadlock in rtnl_lock (5)
From: Julian Anastasov @ 2018-03-27 19:52 UTC (permalink / raw)
  To: Florian Westphal; +Cc: syzbot, netdev, lvs-devel, syzkaller-bugs
In-Reply-To: <20180327115001.GC26275@breakpoint.cc>


	Hello,

On Tue, 27 Mar 2018, Florian Westphal wrote:

> syzbot <syzbot+a46d6abf9d56b1365a72@syzkaller.appspotmail.com> wrote:
> [ cc Julian and trimming cc list ]
> 
> > syzkaller688027/4497 is trying to acquire lock:
> >  (rtnl_mutex){+.+.}, at: [<00000000bb14d7fb>] rtnl_lock+0x17/0x20
> > net/core/rtnetlink.c:74
> 
> > but task is already holding lock:
> > IPVS: stopping backup sync thread 4495 ...
> >  (rtnl_mutex){+.+.}, at: [<00000000bb14d7fb>] rtnl_lock+0x17/0x20
> > net/core/rtnetlink.c:74
> > 
> > other info that might help us debug this:
> >  Possible unsafe locking scenario:
> > 
> >        CPU0
> >        ----
> >   lock(rtnl_mutex);
> >   lock(rtnl_mutex);
> > 
> >  *** DEADLOCK ***
> > 
> >  May be due to missing lock nesting notation
> 
> Looks like this is real, commit e0b26cc997d57305b4097711e12e13992580ae34
> ("ipvs: call rtnl_lock early") added rtnl_lock when starting sync thread
> but socket close invokes rtnl_lock too:

	I see, thanks! I'll have to move the locks into
start_sync_thread and to split make_{send,receive}_sock
to {make,setup}_{send,receive}_sock ...

> > stack backtrace:
> >  rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74
> >  ip_mc_drop_socket+0x88/0x230 net/ipv4/igmp.c:2643
> >  inet_release+0x4e/0x1c0 net/ipv4/af_inet.c:413
> >  sock_release+0x8d/0x1e0 net/socket.c:595
> >  start_sync_thread+0x2213/0x2b70 net/netfilter/ipvs/ip_vs_sync.c:1924
> >  do_ip_vs_set_ctl+0x1139/0x1cc0 net/netfilter/ipvs/ip_vs_ctl.c:2389

Regards

^ permalink raw reply

* [PATCH net-next 3/3] net: bcmgenet: Fix coalescing settings handling
From: Florian Fainelli @ 2018-03-27 19:47 UTC (permalink / raw)
  To: netdev
  Cc: Florian Fainelli, davem, jaedon.shin, pgynther, opendmb,
	Michael Chan, gospo, talgi, saeedm
In-Reply-To: <20180327194707.31857-1-f.fainelli@gmail.com>

There were a number of issues with setting the RX coalescing parameters:

- we would not be preserving values that would have been configured
  across close/open calls, instead we would always reset to no timeout
  and 1 interrupt per packet, this would also prevent DIM from setting its
  default usec/pkts values

- when adaptive RX would be turned on, we woud not be fetching the
  default parameters, we would stay with no timeout/1 packet per interrupt
  until the estimator kicks in and changes that

- finally disabling adaptive RX coalescing while providing parameters
  would not be honored, and we would stay with whatever DIM had previously
  determined instead of the user requested parameters

Fixes: 9f4ca05827a2 ("net: bcmgenet: Add support for adaptive RX coalescing")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 78 ++++++++++++++++++--------
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  4 +-
 2 files changed, 57 insertions(+), 25 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 7db8edc643ec..76409debb796 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -625,18 +625,18 @@ static int bcmgenet_get_coalesce(struct net_device *dev,
 	return 0;
 }
 
-static void bcmgenet_set_rx_coalesce(struct bcmgenet_rx_ring *ring)
+static void bcmgenet_set_rx_coalesce(struct bcmgenet_rx_ring *ring,
+				     u32 usecs, u32 pkts)
 {
 	struct bcmgenet_priv *priv = ring->priv;
 	unsigned int i = ring->index;
 	u32 reg;
 
-	bcmgenet_rdma_ring_writel(priv, i, ring->dim.coal_pkts,
-				  DMA_MBUF_DONE_THRESH);
+	bcmgenet_rdma_ring_writel(priv, i, pkts, DMA_MBUF_DONE_THRESH);
 
 	reg = bcmgenet_rdma_readl(priv, DMA_RING0_TIMEOUT + i);
 	reg &= ~DMA_TIMEOUT_MASK;
-	reg |= DIV_ROUND_UP(ring->dim.coal_usecs * 1000, 8192);
+	reg |= DIV_ROUND_UP(usecs * 1000, 8192);
 	bcmgenet_rdma_writel(priv, reg, DMA_RING0_TIMEOUT + i);
 }
 
@@ -645,6 +645,8 @@ static int bcmgenet_set_coalesce(struct net_device *dev,
 {
 	struct bcmgenet_priv *priv = netdev_priv(dev);
 	struct bcmgenet_rx_ring *ring;
+	struct net_dim_cq_moder moder;
+	u32 usecs, pkts;
 	unsigned int i;
 
 	/* Base system clock is 125Mhz, DMA timeout is this reference clock
@@ -682,25 +684,37 @@ static int bcmgenet_set_coalesce(struct net_device *dev,
 
 	for (i = 0; i < priv->hw_params->rx_queues; i++) {
 		ring = &priv->rx_rings[i];
-		ring->dim.coal_usecs = ec->rx_coalesce_usecs;
-		ring->dim.coal_pkts = ec->rx_max_coalesced_frames;
-		if (!ec->use_adaptive_rx_coalesce && ring->dim.use_dim) {
-			ring->dim.coal_pkts = 1;
-			ring->dim.coal_usecs = 0;
+
+		ring->rx_coalesce_usecs = ec->rx_coalesce_usecs;
+		ring->rx_max_coalesced_frames = ec->rx_max_coalesced_frames;
+		usecs = ring->rx_coalesce_usecs;
+		pkts = ring->rx_max_coalesced_frames;
+
+		if (ec->use_adaptive_rx_coalesce) {
+			moder = net_dim_get_def_profile(ring->dim.dim.mode);
+			usecs = moder.usec;
+			pkts = moder.pkts;
 		}
+
 		ring->dim.use_dim = ec->use_adaptive_rx_coalesce;
-		bcmgenet_set_rx_coalesce(ring);
+		bcmgenet_set_rx_coalesce(ring, usecs, pkts);
 	}
 
 	ring = &priv->rx_rings[DESC_INDEX];
-	ring->dim.coal_usecs = ec->rx_coalesce_usecs;
-	ring->dim.coal_pkts = ec->rx_max_coalesced_frames;
-	if (!ec->use_adaptive_rx_coalesce && ring->dim.use_dim) {
-		ring->dim.coal_pkts = 1;
-		ring->dim.coal_usecs = 0;
+
+	ring->rx_coalesce_usecs = ec->rx_coalesce_usecs;
+	ring->rx_max_coalesced_frames = ec->rx_max_coalesced_frames;
+	usecs = ring->rx_coalesce_usecs;
+	pkts = ring->rx_max_coalesced_frames;
+
+	if (ec->use_adaptive_rx_coalesce) {
+		moder = net_dim_get_def_profile(ring->dim.dim.mode);
+		usecs = moder.usec;
+		pkts = moder.pkts;
 	}
+
 	ring->dim.use_dim = ec->use_adaptive_rx_coalesce;
-	bcmgenet_set_rx_coalesce(ring);
+	bcmgenet_set_rx_coalesce(ring, usecs, pkts);
 
 	return 0;
 }
@@ -1924,10 +1938,7 @@ static void bcmgenet_dim_work(struct work_struct *work)
 	struct net_dim_cq_moder cur_profile =
 			net_dim_get_profile(dim->mode, dim->profile_ix);
 
-	ring->dim.coal_usecs = cur_profile.usec;
-	ring->dim.coal_pkts = cur_profile.pkts;
-
-	bcmgenet_set_rx_coalesce(ring);
+	bcmgenet_set_rx_coalesce(ring, cur_profile.usec, cur_profile.pkts);
 	dim->state = NET_DIM_START_MEASURE;
 }
 
@@ -2079,14 +2090,30 @@ static void init_umac(struct bcmgenet_priv *priv)
 	dev_dbg(kdev, "done init umac\n");
 }
 
-static void bcmgenet_init_dim(struct bcmgenet_net_dim *dim,
+static void bcmgenet_init_dim(struct bcmgenet_rx_ring *ring,
 			      void (*cb)(struct work_struct *work))
 {
+	struct bcmgenet_net_dim *dim = &ring->dim;
+	struct net_dim_cq_moder moder;
+	u32 usecs, pkts;
+
 	INIT_WORK(&dim->dim.work, cb);
 	dim->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
 	dim->event_ctr = 0;
 	dim->packets = 0;
 	dim->bytes = 0;
+
+	usecs = ring->rx_coalesce_usecs;
+	pkts = ring->rx_max_coalesced_frames;
+
+	/* If DIM was enabled, re-apply default parameters */
+	if (dim->use_dim) {
+		moder = net_dim_get_def_profile(dim->dim.mode);
+		usecs = moder.usec;
+		pkts = moder.pkts;
+	}
+
+	bcmgenet_set_rx_coalesce(ring, usecs, pkts);
 }
 
 /* Initialize a Tx ring along with corresponding hardware registers */
@@ -2178,7 +2205,7 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv,
 	if (ret)
 		return ret;
 
-	bcmgenet_init_dim(&ring->dim, bcmgenet_dim_work);
+	bcmgenet_init_dim(ring, bcmgenet_dim_work);
 
 	/* Initialize Rx NAPI */
 	netif_napi_add(priv->dev, &ring->napi, bcmgenet_rx_poll,
@@ -2186,7 +2213,6 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv,
 
 	bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_PROD_INDEX);
 	bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_CONS_INDEX);
-	bcmgenet_rdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH);
 	bcmgenet_rdma_ring_writel(priv, index,
 				  ((size << DMA_RING_SIZE_SHIFT) |
 				   RX_BUF_LENGTH), DMA_RING_BUF_SIZE);
@@ -3424,6 +3450,7 @@ static int bcmgenet_probe(struct platform_device *pdev)
 	struct net_device *dev;
 	const void *macaddr;
 	struct resource *r;
+	unsigned int i;
 	int err = -EIO;
 	const char *phy_mode_str;
 
@@ -3552,6 +3579,11 @@ static int bcmgenet_probe(struct platform_device *pdev)
 	netif_set_real_num_tx_queues(priv->dev, priv->hw_params->tx_queues + 1);
 	netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1);
 
+	/* Set default coalescing parameters */
+	for (i = 0; i < priv->hw_params->rx_queues; i++)
+		priv->rx_rings[i].rx_max_coalesced_frames = 1;
+	priv->rx_rings[DESC_INDEX].rx_max_coalesced_frames = 1;
+
 	/* libphy will determine the link state */
 	netif_carrier_off(dev);
 
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index 22c41e0430fb..b773bc07edf7 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -578,8 +578,6 @@ struct bcmgenet_net_dim {
 	u16		event_ctr;
 	unsigned long	packets;
 	unsigned long	bytes;
-	u32		coal_usecs;
-	u32		coal_pkts;
 	struct net_dim	dim;
 };
 
@@ -598,6 +596,8 @@ struct bcmgenet_rx_ring {
 	unsigned int	end_ptr;	/* Rx ring end CB ptr */
 	unsigned int	old_discards;
 	struct bcmgenet_net_dim dim;
+	u32		rx_max_coalesced_frames;
+	u32		rx_coalesce_usecs;
 	void (*int_enable)(struct bcmgenet_rx_ring *);
 	void (*int_disable)(struct bcmgenet_rx_ring *);
 	struct bcmgenet_priv *priv;
-- 
2.14.1

^ permalink raw reply related

* [PATCH net-next 2/3] net: systemport: Fix coalescing settings handling
From: Florian Fainelli @ 2018-03-27 19:47 UTC (permalink / raw)
  To: netdev
  Cc: Florian Fainelli, davem, jaedon.shin, pgynther, opendmb,
	Michael Chan, gospo, talgi, saeedm
In-Reply-To: <20180327194707.31857-1-f.fainelli@gmail.com>

There were a number of issues with setting the RX coalescing parameters:

- we would not be preserving values that would have been configured
  across close/open calls, instead we would always reset to no timeout
  and 1 interrupt per packet, this would also prevent DIM from setting its
  default usec/pkts values

- when adaptive RX would be turned on, we woud not be fetching the
  default parameters, we would stay with no timeout/1 packet per
  interrupt until the estimator kicks in and changes that

- finally disabling adaptive RX coalescing while providing parameters
  would not be honored, and we would stay with whatever DIM had
  previously determined instead of the user requested parameters

Fixes: b6e0e875421e ("net: systemport: Implement adaptive interrupt coalescing")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/net/ethernet/broadcom/bcmsysport.c | 57 ++++++++++++++++++++----------
 drivers/net/ethernet/broadcom/bcmsysport.h |  4 +--
 2 files changed, 41 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 1e52bb7d822e..43ad6300c351 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -574,16 +574,16 @@ static int bcm_sysport_set_wol(struct net_device *dev,
 	return 0;
 }
 
-static void bcm_sysport_set_rx_coalesce(struct bcm_sysport_priv *priv)
+static void bcm_sysport_set_rx_coalesce(struct bcm_sysport_priv *priv,
+					u32 usecs, u32 pkts)
 {
 	u32 reg;
 
 	reg = rdma_readl(priv, RDMA_MBDONE_INTR);
 	reg &= ~(RDMA_INTR_THRESH_MASK |
 		 RDMA_TIMEOUT_MASK << RDMA_TIMEOUT_SHIFT);
-	reg |= priv->dim.coal_pkts;
-	reg |= DIV_ROUND_UP(priv->dim.coal_usecs * 1000, 8192) <<
-			    RDMA_TIMEOUT_SHIFT;
+	reg |= pkts;
+	reg |= DIV_ROUND_UP(usecs * 1000, 8192) << RDMA_TIMEOUT_SHIFT;
 	rdma_writel(priv, reg, RDMA_MBDONE_INTR);
 }
 
@@ -626,6 +626,8 @@ static int bcm_sysport_set_coalesce(struct net_device *dev,
 				    struct ethtool_coalesce *ec)
 {
 	struct bcm_sysport_priv *priv = netdev_priv(dev);
+	struct net_dim_cq_moder moder;
+	u32 usecs, pkts;
 	unsigned int i;
 
 	/* Base system clock is 125Mhz, DMA timeout is this reference clock
@@ -646,15 +648,22 @@ static int bcm_sysport_set_coalesce(struct net_device *dev,
 	for (i = 0; i < dev->num_tx_queues; i++)
 		bcm_sysport_set_tx_coalesce(&priv->tx_rings[i], ec);
 
-	priv->dim.coal_usecs = ec->rx_coalesce_usecs;
-	priv->dim.coal_pkts = ec->rx_max_coalesced_frames;
+	priv->rx_coalesce_usecs = ec->rx_coalesce_usecs;
+	priv->rx_max_coalesced_frames = ec->rx_max_coalesced_frames;
+	usecs = priv->rx_coalesce_usecs;
+	pkts = priv->rx_max_coalesced_frames;
 
-	if (!ec->use_adaptive_rx_coalesce && priv->dim.use_dim) {
-		priv->dim.coal_pkts = 1;
-		priv->dim.coal_usecs = 0;
+	/* If DIM is enabled, immediately obtain default parameters */
+	if (ec->use_adaptive_rx_coalesce) {
+		moder = net_dim_get_def_profile(priv->dim.dim.mode);
+		usecs = moder.usec;
+		pkts = moder.pkts;
 	}
+
 	priv->dim.use_dim = ec->use_adaptive_rx_coalesce;
-	bcm_sysport_set_rx_coalesce(priv);
+
+	/* Apply desired coalescing parameters */
+	bcm_sysport_set_rx_coalesce(priv, usecs, pkts);
 
 	return 0;
 }
@@ -1058,10 +1067,7 @@ static void bcm_sysport_dim_work(struct work_struct *work)
 	struct net_dim_cq_moder cur_profile =
 				net_dim_get_profile(dim->mode, dim->profile_ix);
 
-	priv->dim.coal_usecs = cur_profile.usec;
-	priv->dim.coal_pkts = cur_profile.pkts;
-
-	bcm_sysport_set_rx_coalesce(priv);
+	bcm_sysport_set_rx_coalesce(priv, cur_profile.usec, cur_profile.pkts);
 	dim->state = NET_DIM_START_MEASURE;
 }
 
@@ -1408,14 +1414,30 @@ static void bcm_sysport_adj_link(struct net_device *dev)
 		phy_print_status(phydev);
 }
 
-static void bcm_sysport_init_dim(struct bcm_sysport_net_dim *dim,
+static void bcm_sysport_init_dim(struct bcm_sysport_priv *priv,
 				 void (*cb)(struct work_struct *work))
 {
+	struct bcm_sysport_net_dim *dim = &priv->dim;
+	struct net_dim_cq_moder moder;
+	u32 usecs, pkts;
+
 	INIT_WORK(&dim->dim.work, cb);
 	dim->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
 	dim->event_ctr = 0;
 	dim->packets = 0;
 	dim->bytes = 0;
+
+	usecs = priv->rx_coalesce_usecs;
+	pkts = priv->rx_max_coalesced_frames;
+
+	/* If DIM was enabled, re-apply default parameters */
+	if (dim->use_dim) {
+		moder = net_dim_get_def_profile(dim->dim.mode);
+		usecs = moder.usec;
+		pkts = moder.pkts;
+	}
+
+	bcm_sysport_set_rx_coalesce(priv, usecs, pkts);
 }
 
 static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
@@ -1658,8 +1680,6 @@ static int bcm_sysport_init_rx_ring(struct bcm_sysport_priv *priv)
 	rdma_writel(priv, 0, RDMA_END_ADDR_HI);
 	rdma_writel(priv, priv->num_rx_desc_words - 1, RDMA_END_ADDR_LO);
 
-	rdma_writel(priv, 1, RDMA_MBDONE_INTR);
-
 	netif_dbg(priv, hw, priv->netdev,
 		  "RDMA cfg, num_rx_bds=%d, rx_bds=%p\n",
 		  priv->num_rx_bds, priv->rx_bds);
@@ -1827,7 +1847,7 @@ static void bcm_sysport_netif_start(struct net_device *dev)
 	struct bcm_sysport_priv *priv = netdev_priv(dev);
 
 	/* Enable NAPI */
-	bcm_sysport_init_dim(&priv->dim, bcm_sysport_dim_work);
+	bcm_sysport_init_dim(priv, bcm_sysport_dim_work);
 	napi_enable(&priv->napi);
 
 	/* Enable RX interrupt and TX ring full interrupt */
@@ -2333,6 +2353,7 @@ static int bcm_sysport_probe(struct platform_device *pdev)
 	/* libphy will adjust the link state accordingly */
 	netif_carrier_off(dev);
 
+	priv->rx_max_coalesced_frames = 1;
 	u64_stats_init(&priv->syncp);
 
 	priv->dsa_notifier.notifier_call = bcm_sysport_dsa_notifier;
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h
index 57e18ef8f206..d6e5d0cbf3a3 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.h
+++ b/drivers/net/ethernet/broadcom/bcmsysport.h
@@ -701,8 +701,6 @@ struct bcm_sysport_net_dim {
 	u16			event_ctr;
 	unsigned long		packets;
 	unsigned long		bytes;
-	u32			coal_usecs;
-	u32			coal_pkts;
 	struct net_dim		dim;
 };
 
@@ -755,6 +753,8 @@ struct bcm_sysport_priv {
 	unsigned int		rx_c_index;
 
 	struct bcm_sysport_net_dim	dim;
+	u32			rx_max_coalesced_frames;
+	u32			rx_coalesce_usecs;
 
 	/* PHY device */
 	struct device_node	*phy_dn;
-- 
2.14.1

^ permalink raw reply related

* [PATCH net-next 1/3] net: systemport: Remove adaptive TX coalescing
From: Florian Fainelli @ 2018-03-27 19:47 UTC (permalink / raw)
  To: netdev
  Cc: Florian Fainelli, davem, jaedon.shin, pgynther, opendmb,
	Michael Chan, gospo, talgi, saeedm
In-Reply-To: <20180327194707.31857-1-f.fainelli@gmail.com>

Adaptive TX coalescing is not currently giving us any advantages and
ends up making the CPU spin more frequently until TX completion. Deny
and disable adaptive TX coalescing for now and rely on static
configuration, we can always add it back later.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/net/ethernet/broadcom/bcmsysport.c | 61 ++++--------------------------
 drivers/net/ethernet/broadcom/bcmsysport.h |  1 -
 2 files changed, 8 insertions(+), 54 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 4e26f606a7f2..1e52bb7d822e 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -15,7 +15,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
-#include <linux/net_dim.h>
 #include <linux/etherdevice.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
@@ -588,7 +587,8 @@ static void bcm_sysport_set_rx_coalesce(struct bcm_sysport_priv *priv)
 	rdma_writel(priv, reg, RDMA_MBDONE_INTR);
 }
 
-static void bcm_sysport_set_tx_coalesce(struct bcm_sysport_tx_ring *ring)
+static void bcm_sysport_set_tx_coalesce(struct bcm_sysport_tx_ring *ring,
+					struct ethtool_coalesce *ec)
 {
 	struct bcm_sysport_priv *priv = ring->priv;
 	u32 reg;
@@ -596,8 +596,8 @@ static void bcm_sysport_set_tx_coalesce(struct bcm_sysport_tx_ring *ring)
 	reg = tdma_readl(priv, TDMA_DESC_RING_INTR_CONTROL(ring->index));
 	reg &= ~(RING_INTR_THRESH_MASK |
 		 RING_TIMEOUT_MASK << RING_TIMEOUT_SHIFT);
-	reg |= ring->dim.coal_pkts;
-	reg |= DIV_ROUND_UP(ring->dim.coal_usecs * 1000, 8192) <<
+	reg |= ec->tx_max_coalesced_frames;
+	reg |= DIV_ROUND_UP(ec->tx_coalesce_usecs * 1000, 8192) <<
 			    RING_TIMEOUT_SHIFT;
 	tdma_writel(priv, reg, TDMA_DESC_RING_INTR_CONTROL(ring->index));
 }
@@ -606,18 +606,12 @@ static int bcm_sysport_get_coalesce(struct net_device *dev,
 				    struct ethtool_coalesce *ec)
 {
 	struct bcm_sysport_priv *priv = netdev_priv(dev);
-	struct bcm_sysport_tx_ring *ring;
-	unsigned int i;
 	u32 reg;
 
 	reg = tdma_readl(priv, TDMA_DESC_RING_INTR_CONTROL(0));
 
 	ec->tx_coalesce_usecs = (reg >> RING_TIMEOUT_SHIFT) * 8192 / 1000;
 	ec->tx_max_coalesced_frames = reg & RING_INTR_THRESH_MASK;
-	for (i = 0; i < dev->num_tx_queues; i++) {
-		ring = &priv->tx_rings[i];
-		ec->use_adaptive_tx_coalesce |= ring->dim.use_dim;
-	}
 
 	reg = rdma_readl(priv, RDMA_MBDONE_INTR);
 
@@ -632,7 +626,6 @@ static int bcm_sysport_set_coalesce(struct net_device *dev,
 				    struct ethtool_coalesce *ec)
 {
 	struct bcm_sysport_priv *priv = netdev_priv(dev);
-	struct bcm_sysport_tx_ring *ring;
 	unsigned int i;
 
 	/* Base system clock is 125Mhz, DMA timeout is this reference clock
@@ -646,20 +639,12 @@ static int bcm_sysport_set_coalesce(struct net_device *dev,
 		return -EINVAL;
 
 	if ((ec->tx_coalesce_usecs == 0 && ec->tx_max_coalesced_frames == 0) ||
-	    (ec->rx_coalesce_usecs == 0 && ec->rx_max_coalesced_frames == 0))
+	    (ec->rx_coalesce_usecs == 0 && ec->rx_max_coalesced_frames == 0) ||
+	    ec->use_adaptive_tx_coalesce)
 		return -EINVAL;
 
-	for (i = 0; i < dev->num_tx_queues; i++) {
-		ring = &priv->tx_rings[i];
-		ring->dim.coal_pkts = ec->tx_max_coalesced_frames;
-		ring->dim.coal_usecs = ec->tx_coalesce_usecs;
-		if (!ec->use_adaptive_tx_coalesce && ring->dim.use_dim) {
-			ring->dim.coal_pkts = 1;
-			ring->dim.coal_usecs = 0;
-		}
-		ring->dim.use_dim = ec->use_adaptive_tx_coalesce;
-		bcm_sysport_set_tx_coalesce(ring);
-	}
+	for (i = 0; i < dev->num_tx_queues; i++)
+		bcm_sysport_set_tx_coalesce(&priv->tx_rings[i], ec);
 
 	priv->dim.coal_usecs = ec->rx_coalesce_usecs;
 	priv->dim.coal_pkts = ec->rx_max_coalesced_frames;
@@ -940,8 +925,6 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
 	ring->packets += pkts_compl;
 	ring->bytes += bytes_compl;
 	u64_stats_update_end(&priv->syncp);
-	ring->dim.packets = pkts_compl;
-	ring->dim.bytes = bytes_compl;
 
 	ring->c_index = c_index;
 
@@ -987,7 +970,6 @@ static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget)
 {
 	struct bcm_sysport_tx_ring *ring =
 		container_of(napi, struct bcm_sysport_tx_ring, napi);
-	struct net_dim_sample dim_sample;
 	unsigned int work_done = 0;
 
 	work_done = bcm_sysport_tx_reclaim(ring->priv, ring);
@@ -1004,12 +986,6 @@ static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget)
 		return 0;
 	}
 
-	if (ring->dim.use_dim) {
-		net_dim_sample(ring->dim.event_ctr, ring->dim.packets,
-			       ring->dim.bytes, &dim_sample);
-		net_dim(&ring->dim.dim, dim_sample);
-	}
-
 	return budget;
 }
 
@@ -1089,23 +1065,6 @@ static void bcm_sysport_dim_work(struct work_struct *work)
 	dim->state = NET_DIM_START_MEASURE;
 }
 
-static void bcm_sysport_dim_tx_work(struct work_struct *work)
-{
-	struct net_dim *dim = container_of(work, struct net_dim, work);
-	struct bcm_sysport_net_dim *ndim =
-			container_of(dim, struct bcm_sysport_net_dim, dim);
-	struct bcm_sysport_tx_ring *ring =
-			container_of(ndim, struct bcm_sysport_tx_ring, dim);
-	struct net_dim_cq_moder cur_profile =
-				net_dim_get_profile(dim->mode, dim->profile_ix);
-
-	ring->dim.coal_usecs = cur_profile.usec;
-	ring->dim.coal_pkts = cur_profile.pkts;
-
-	bcm_sysport_set_tx_coalesce(ring);
-	dim->state = NET_DIM_START_MEASURE;
-}
-
 /* RX and misc interrupt routine */
 static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
 {
@@ -1152,7 +1111,6 @@ static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
 			continue;
 
 		txr = &priv->tx_rings[ring];
-		txr->dim.event_ctr++;
 
 		if (likely(napi_schedule_prep(&txr->napi))) {
 			intrl2_0_mask_set(priv, ring_bit);
@@ -1185,7 +1143,6 @@ static irqreturn_t bcm_sysport_tx_isr(int irq, void *dev_id)
 			continue;
 
 		txr = &priv->tx_rings[ring];
-		txr->dim.event_ctr++;
 
 		if (likely(napi_schedule_prep(&txr->napi))) {
 			intrl2_1_mask_set(priv, BIT(ring));
@@ -1551,7 +1508,6 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
 	reg |= (1 << index);
 	tdma_writel(priv, reg, TDMA_TIER1_ARB_0_QUEUE_EN);
 
-	bcm_sysport_init_dim(&ring->dim, bcm_sysport_dim_tx_work);
 	napi_enable(&ring->napi);
 
 	netif_dbg(priv, hw, priv->netdev,
@@ -1582,7 +1538,6 @@ static void bcm_sysport_fini_tx_ring(struct bcm_sysport_priv *priv,
 		return;
 
 	napi_disable(&ring->napi);
-	cancel_work_sync(&ring->dim.dim.work);
 	netif_napi_del(&ring->napi);
 
 	bcm_sysport_tx_clean(priv, ring);
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h
index e1c97d4a82b4..57e18ef8f206 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.h
+++ b/drivers/net/ethernet/broadcom/bcmsysport.h
@@ -723,7 +723,6 @@ struct bcm_sysport_tx_ring {
 	struct bcm_sysport_priv *priv;	/* private context backpointer */
 	unsigned long	packets;	/* packets statistics */
 	unsigned long	bytes;		/* bytes statistics */
-	struct bcm_sysport_net_dim dim;	/* Net DIM context */
 	unsigned int	switch_queue;	/* switch port queue number */
 	unsigned int	switch_port;	/* switch port queue number */
 	bool		inspect;	/* inspect switch port and queue */
-- 
2.14.1

^ permalink raw reply related

* [PATCH net-next 0/3] net: Broadcom drivers coalescing fixes
From: Florian Fainelli @ 2018-03-27 19:47 UTC (permalink / raw)
  To: netdev
  Cc: Florian Fainelli, davem, jaedon.shin, pgynther, opendmb,
	Michael Chan, gospo, talgi, saeedm

Hi all,

Following Tal's review of the adaptive RX/TX coalescing feature added to the
SYSTEMPORT and GENET driver a number of things showed up:

- adaptive TX coalescing is not actually a good idea with the current way
  the estimator will program the ring, this results in a higher CPU load, NAPI
  on TX already does a reasonably good job at maintaining the interrupt count low

- both SYSTEMPORT and GENET would suffer from the same issues while configuring
  coalescing parameters where the values would just not be applied correctly
  based on user settings, so we fix that too

Tal, thanks again for your feedback, I would appreciate if you could review that
the new behavior appears to be implemented correctly.

Thanks!

Florian Fainelli (3):
  net: systemport: Remove adaptive TX coalescing
  net: systemport: Fix coalescing settings handling
  net: bcmgenet: Fix coalescing settings handling

 drivers/net/ethernet/broadcom/bcmsysport.c     | 118 ++++++++++---------------
 drivers/net/ethernet/broadcom/bcmsysport.h     |   5 +-
 drivers/net/ethernet/broadcom/genet/bcmgenet.c |  78 +++++++++++-----
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |   4 +-
 4 files changed, 106 insertions(+), 99 deletions(-)

-- 
2.14.1

^ permalink raw reply

* Re: [net-next PATCH v2 03/10] net: netcp: ethss: make call to gbe_sgmii_config() conditional
From: Murali Karicheri @ 2018-03-27 19:39 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: mark.rutland, devicetree, malat, netdev, linux-kernel, w-kwok2,
	robh+dt, ssantosh, davem, linux-arm-kernel
In-Reply-To: <20180327171817.GO5862@lunn.ch>

On 03/27/2018 01:18 PM, Andrew Lunn wrote:
> On Tue, Mar 27, 2018 at 12:31:42PM -0400, Murali Karicheri wrote:
>> As a preparatory patch to add support for 2u cpsw hardware found on
>> K2G SoC, make call to gbe_sgmii_config() conditional. This is required
>> since 2u uses RGMII interface instead of SGMII and to allow for driver
>> re-use.
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>> ---
>>  drivers/net/ethernet/ti/netcp_ethss.c | 7 +++++--
>>  1 file changed, 5 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c
>> index 56dbc0b..1dea891 100644
>> --- a/drivers/net/ethernet/ti/netcp_ethss.c
>> +++ b/drivers/net/ethernet/ti/netcp_ethss.c
>> @@ -2271,7 +2271,8 @@ static int gbe_slave_open(struct gbe_intf *gbe_intf)
>>  
>>  	void (*hndlr)(struct net_device *) = gbe_adjust_link;
>>  
>> -	gbe_sgmii_config(priv, slave);
>> +	if ((priv->ss_version == GBE_SS_VERSION_14) || IS_SS_ID_NU(priv))
>> +		gbe_sgmii_config(priv, slave);
> 
> Or maybe:
> 
>    if (slave->phy_node == PHY_INTERFACE_MODE_SGMII)
>    	gbe_sgmii_config(priv, slave);

Yeah. Based on my response to your other comment, this would become

if ((slave->link_interface == SGMII_LINK_MAC_PHY) &&
    (IS_SS_ID_VER_14(priv) || IS_SS_ID_NU(priv)))
	gbe_sgmii_config(priv, slave);

We can't solely depends on phy_mode here. Phy interface is one of several
interface possible. There is MAC_TO_MAC_FORCED, NO_MDIO etc. So we check the
link_interface above.

If we can agree, here is what will appear in v3

1) Add another patch to do conversion of priv->ss_version == GBE_SS_VERSION_14 check 
with a macro, IS_SS_ID_VER_14
2) modify this patch as above.

Murali
> 
> 	Andrew
> 


-- 
Murali Karicheri
Linux Kernel, Keystone

^ 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