Netdev List
 help / color / mirror / Atom feed
* [PATCH v3 net-next 4/4] udp: udp_rmem_release() should touch sk_rmem_alloc later
From: Eric Dumazet @ 2016-12-08 19:41 UTC (permalink / raw)
  To: David S . Miller; +Cc: netdev, Eric Dumazet, Paolo Abeni, Eric Dumazet
In-Reply-To: <1481226117-31288-1-git-send-email-edumazet@google.com>

In flood situations, keeping sk_rmem_alloc at a high value
prevents producers from touching the socket.

It makes sense to lower sk_rmem_alloc only at the end
of udp_rmem_release() after the thread draining receive
queue in udp_recvmsg() finished the writes to sk_forward_alloc.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/ipv4/udp.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 5a38faa12cde7fdcd5b6d86cdc0f4bc33de4..9ca279b130d51f6feaa97785b1c906775810 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1191,13 +1191,14 @@ static void udp_rmem_release(struct sock *sk, int size, int partial)
 	}
 	up->forward_deficit = 0;
 
-	atomic_sub(size, &sk->sk_rmem_alloc);
 	sk->sk_forward_alloc += size;
 	amt = (sk->sk_forward_alloc - partial) & ~(SK_MEM_QUANTUM - 1);
 	sk->sk_forward_alloc -= amt;
 
 	if (amt)
 		__sk_mem_reduce_allocated(sk, amt >> SK_MEM_QUANTUM_SHIFT);
+
+	atomic_sub(size, &sk->sk_rmem_alloc);
 }
 
 /* Note: called with sk_receive_queue.lock held.
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related

* [PATCH v3 net-next 3/4] udp: add batching to udp_rmem_release()
From: Eric Dumazet @ 2016-12-08 19:41 UTC (permalink / raw)
  To: David S . Miller; +Cc: netdev, Eric Dumazet, Paolo Abeni, Eric Dumazet
In-Reply-To: <1481226117-31288-1-git-send-email-edumazet@google.com>

If udp_recvmsg() constantly releases sk_rmem_alloc
for every read packet, it gives opportunity for
producers to immediately grab spinlocks and desperatly
try adding another packet, causing false sharing.

We can add a simple heuristic to give the signal
by batches of ~25 % of the queue capacity.

This patch considerably increases performance under
flood by about 50 %, since the thread draining the queue
is no longer slowed by false sharing.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 include/linux/udp.h |  3 +++
 net/ipv4/udp.c      | 12 ++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/include/linux/udp.h b/include/linux/udp.h
index d1fd8cd39478b635ef5396b5ae1c63f8c965..c0f530809d1f3db7323e51a52224eb49d8f9 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -79,6 +79,9 @@ struct udp_sock {
 	int			(*gro_complete)(struct sock *sk,
 						struct sk_buff *skb,
 						int nhoff);
+
+	/* This field is dirtied by udp_recvmsg() */
+	int		forward_deficit;
 };
 
 static inline struct udp_sock *udp_sk(const struct sock *sk)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index c608334d99aa5620858d9cceec500b2be944..5a38faa12cde7fdcd5b6d86cdc0f4bc33de4 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1177,8 +1177,20 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset,
 /* fully reclaim rmem/fwd memory allocated for skb */
 static void udp_rmem_release(struct sock *sk, int size, int partial)
 {
+	struct udp_sock *up = udp_sk(sk);
 	int amt;
 
+	if (likely(partial)) {
+		up->forward_deficit += size;
+		size = up->forward_deficit;
+		if (size < (sk->sk_rcvbuf >> 2) &&
+		    !skb_queue_empty(&sk->sk_receive_queue))
+			return;
+	} else {
+		size += up->forward_deficit;
+	}
+	up->forward_deficit = 0;
+
 	atomic_sub(size, &sk->sk_rmem_alloc);
 	sk->sk_forward_alloc += size;
 	amt = (sk->sk_forward_alloc - partial) & ~(SK_MEM_QUANTUM - 1);
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related

* [PATCH v3 net-next 2/4] udp: copy skb->truesize in the first cache line
From: Eric Dumazet @ 2016-12-08 19:41 UTC (permalink / raw)
  To: David S . Miller; +Cc: netdev, Eric Dumazet, Paolo Abeni, Eric Dumazet
In-Reply-To: <1481226117-31288-1-git-send-email-edumazet@google.com>

In UDP RX handler, we currently clear skb->dev before skb
is added to receive queue, because device pointer is no longer
available once we exit from RCU section.

Since this first cache line is always hot, lets reuse this space
to store skb->truesize and thus avoid a cache line miss at
udp_recvmsg()/udp_skb_destructor time while receive queue
spinlock is held.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 include/linux/skbuff.h |  9 ++++++++-
 net/ipv4/udp.c         | 13 ++++++++++---
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 0cd92b0f2af5fe5a7c153435b8dc75833818..332e76756f54bee3b625ed8872c024a2bf53 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -645,8 +645,15 @@ struct sk_buff {
 		struct rb_node	rbnode; /* used in netem & tcp stack */
 	};
 	struct sock		*sk;
-	struct net_device	*dev;
 
+	union {
+		struct net_device	*dev;
+		/* Some protocols might use this space to store information,
+		 * while device pointer would be NULL.
+		 * UDP receive path is one user.
+		 */
+		unsigned long		dev_scratch;
+	};
 	/*
 	 * This is the control buffer. It is free to use for every
 	 * layer. Please put your private variables there. If you
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index e6a68d66f3b218998d409527301d2a994e95..c608334d99aa5620858d9cceec500b2be944 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1188,10 +1188,14 @@ static void udp_rmem_release(struct sock *sk, int size, int partial)
 		__sk_mem_reduce_allocated(sk, amt >> SK_MEM_QUANTUM_SHIFT);
 }
 
-/* Note: called with sk_receive_queue.lock held */
+/* Note: called with sk_receive_queue.lock held.
+ * Instead of using skb->truesize here, find a copy of it in skb->dev_scratch
+ * This avoids a cache line miss while receive_queue lock is held.
+ * Look at __udp_enqueue_schedule_skb() to find where this copy is done.
+ */
 void udp_skb_destructor(struct sock *sk, struct sk_buff *skb)
 {
-	udp_rmem_release(sk, skb->truesize, 1);
+	udp_rmem_release(sk, skb->dev_scratch, 1);
 }
 EXPORT_SYMBOL(udp_skb_destructor);
 
@@ -1246,6 +1250,10 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
 		busy = busylock_acquire(sk);
 	}
 	size = skb->truesize;
+	/* Copy skb->truesize into skb->dev_scratch to avoid a cache line miss
+	 * in udp_skb_destructor()
+	 */
+	skb->dev_scratch = size;
 
 	/* we drop only if the receive buf is full and the receive
 	 * queue contains some other skb
@@ -1272,7 +1280,6 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
 	/* no need to setup a destructor, we will explicitly release the
 	 * forward allocated memory on dequeue
 	 */
-	skb->dev = NULL;
 	sock_skb_set_dropcount(sk, skb);
 
 	__skb_queue_tail(list, skb);
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related

* [PATCH v3 net-next 1/4] udp: add busylocks in RX path
From: Eric Dumazet @ 2016-12-08 19:41 UTC (permalink / raw)
  To: David S . Miller; +Cc: netdev, Eric Dumazet, Paolo Abeni, Eric Dumazet
In-Reply-To: <1481226117-31288-1-git-send-email-edumazet@google.com>

Idea of busylocks is to let producers grab an extra spinlock
to relieve pressure on the receive_queue spinlock shared by consumer.

This behavior is requested only once socket receive queue is above
half occupancy.

Under flood, this means that only one producer can be in line
trying to acquire the receive_queue spinlock.

These busylock can be allocated on a per cpu manner, instead of a
per socket one (that would consume a cache line per socket)

This patch considerably improves UDP behavior under stress,
depending on number of NIC RX queues and/or RPS spread.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/ipv4/udp.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index f5628ada47b53f0d92d08210e5d7e4132a10..e6a68d66f3b218998d409527301d2a994e95 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1195,10 +1195,36 @@ void udp_skb_destructor(struct sock *sk, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(udp_skb_destructor);
 
+/* Idea of busylocks is to let producers grab an extra spinlock
+ * to relieve pressure on the receive_queue spinlock shared by consumer.
+ * Under flood, this means that only one producer can be in line
+ * trying to acquire the receive_queue spinlock.
+ * These busylock can be allocated on a per cpu manner, instead of a
+ * per socket one (that would consume a cache line per socket)
+ */
+static int udp_busylocks_log __read_mostly;
+static spinlock_t *udp_busylocks __read_mostly;
+
+static spinlock_t *busylock_acquire(void *ptr)
+{
+	spinlock_t *busy;
+
+	busy = udp_busylocks + hash_ptr(ptr, udp_busylocks_log);
+	spin_lock(busy);
+	return busy;
+}
+
+static void busylock_release(spinlock_t *busy)
+{
+	if (busy)
+		spin_unlock(busy);
+}
+
 int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
 {
 	struct sk_buff_head *list = &sk->sk_receive_queue;
 	int rmem, delta, amt, err = -ENOMEM;
+	spinlock_t *busy = NULL;
 	int size;
 
 	/* try to avoid the costly atomic add/sub pair when the receive
@@ -1214,8 +1240,11 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
 	 * - Less cache line misses at copyout() time
 	 * - Less work at consume_skb() (less alien page frag freeing)
 	 */
-	if (rmem > (sk->sk_rcvbuf >> 1))
+	if (rmem > (sk->sk_rcvbuf >> 1)) {
 		skb_condense(skb);
+
+		busy = busylock_acquire(sk);
+	}
 	size = skb->truesize;
 
 	/* we drop only if the receive buf is full and the receive
@@ -1252,6 +1281,7 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
 	if (!sock_flag(sk, SOCK_DEAD))
 		sk->sk_data_ready(sk);
 
+	busylock_release(busy);
 	return 0;
 
 uncharge_drop:
@@ -1259,6 +1289,7 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
 
 drop:
 	atomic_inc(&sk->sk_drops);
+	busylock_release(busy);
 	return err;
 }
 EXPORT_SYMBOL_GPL(__udp_enqueue_schedule_skb);
@@ -2613,6 +2644,7 @@ EXPORT_SYMBOL(udp_flow_hashrnd);
 void __init udp_init(void)
 {
 	unsigned long limit;
+	unsigned int i;
 
 	udp_table_init(&udp_table, "UDP");
 	limit = nr_free_buffer_pages() / 8;
@@ -2623,4 +2655,13 @@ void __init udp_init(void)
 
 	sysctl_udp_rmem_min = SK_MEM_QUANTUM;
 	sysctl_udp_wmem_min = SK_MEM_QUANTUM;
+
+	/* 16 spinlocks per cpu */
+	udp_busylocks_log = ilog2(nr_cpu_ids) + 4;
+	udp_busylocks = kmalloc(sizeof(spinlock_t) << udp_busylocks_log,
+				GFP_KERNEL);
+	if (!udp_busylocks)
+		panic("UDP: failed to alloc udp_busylocks\n");
+	for (i = 0; i < (1U << udp_busylocks_log); i++)
+		spin_lock_init(udp_busylocks + i);
 }
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related

* [PATCH v3 net-next 0/4] udp: receive path optimizations
From: Eric Dumazet @ 2016-12-08 19:41 UTC (permalink / raw)
  To: David S . Miller; +Cc: netdev, Eric Dumazet, Paolo Abeni, Eric Dumazet

This patch series provides about 100 % performance increase under flood. 

v2: added Paolo feedback on udp_rmem_release() for tiny sk_rcvbuf
    added the last patch touching sk_rmem_alloc later

Eric Dumazet (4):
  udp: add busylocks in RX path
  udp: copy skb->truesize in the first cache line
  udp: add batching to udp_rmem_release()
  udp: udp_rmem_release() should touch sk_rmem_alloc later

 include/linux/skbuff.h |  9 ++++++-
 include/linux/udp.h    |  3 +++
 net/ipv4/udp.c         | 71 ++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 77 insertions(+), 6 deletions(-)

-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply

* Re: [PATCH net-next] openvswitch: fix VxLAN-gpe port can't be created in ovs compat mode
From: Pravin Shelar @ 2016-12-08 19:41 UTC (permalink / raw)
  To: Yi Yang; +Cc: ovs dev, Linux Kernel Network Developers, Jiri Benc
In-Reply-To: <1481185210-13056-1-git-send-email-yi.y.yang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>

On Thu, Dec 8, 2016 at 12:20 AM, Yi Yang <yi.y.yang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> wrote:
> In ovs compat mode, ovs won't use LWT in current kernel, this is to
> make sure ovs can work on the old kernels, Linux kernel v4.7 includes
> VxLAN-gpe support but many Linux distributions' kernels are odler than
> v4.7, this fix will ensure that ovs can create VxLAN-gpe port correctly
> on old kernels, it has been verified on Ubuntu 16.04 x86_64 with Linux
> kernel 4.4.0-53-generic.
>
> This does touch compat code, but it is necessary as Pravin commented.
>
> Without this fix, ovs can't create VxLAN-gpe port, it is still a VxLAN
> port.
>
> vxlan_sys_4790 Link encap:Ethernet  HWaddr 72:23:60:c2:8b:8d
>           inet6 addr: fe80::7023:60ff:fec2:8b8d/64 Scope:Link
>           UP BROADCAST RUNNING MULTICAST  MTU:65485  Metric:1
>           RX packets:0 errors:0 dropped:0 overruns:0 frame:0
>           TX packets:0 errors:0 dropped:8 overruns:0 carrier:0
>           collisions:0 txqueuelen:1000
>           RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
>
> But with this fix applied, a real L3 port is created
>
> vxlan_sys_4790 Link encap:UNSPEC  HWaddr
> 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
>           UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:65485  Metric:1
>           RX packets:0 errors:0 dropped:0 overruns:0 frame:0
>           TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
>           collisions:0 txqueuelen:1000
>           RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
>
> Signed-off-by: Yi Yang <yi.y.yang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> ---
>  include/uapi/linux/openvswitch.h |  1 +
>  net/openvswitch/vport-vxlan.c    | 15 +++++++++++++++
>  2 files changed, 16 insertions(+)
>
There is no need for this patch in upstream kernel module. I am open
to having such a patch in out of tree kernel if it simplifies feature
compatibility code.

^ permalink raw reply

* [PATCH net 2/2] net: ethernet: cpmac: Call SET_NETDEV_DEV()
From: Florian Fainelli @ 2016-12-08 19:41 UTC (permalink / raw)
  To: netdev; +Cc: davem, madalin.bucur, johan, Florian Fainelli
In-Reply-To: <20161208194125.13264-1-f.fainelli@gmail.com>

The TI CPMAC driver calls into PHYLIB which now checks for
net_device->dev.parent, so make sure we do set it before calling into
any MDIO/PHYLIB related function.

Fixes: ec988ad78ed6 ("phy: Don't increment MDIO bus refcount unless it's a different owner")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/net/ethernet/ti/cpmac.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c
index fa0cfda24fd9..28097be2ff28 100644
--- a/drivers/net/ethernet/ti/cpmac.c
+++ b/drivers/net/ethernet/ti/cpmac.c
@@ -1113,6 +1113,7 @@ static int cpmac_probe(struct platform_device *pdev)
 	if (!dev)
 		return -ENOMEM;
 
+	SET_NETDEV_DEV(dev, &pdev->dev);
 	platform_set_drvdata(pdev, dev);
 	priv = netdev_priv(dev);
 
-- 
2.9.3

^ permalink raw reply related

* [PATCH net 1/2] net: ethernet: lantiq_etop: Call SET_NETDEV_DEV()
From: Florian Fainelli @ 2016-12-08 19:41 UTC (permalink / raw)
  To: netdev; +Cc: davem, madalin.bucur, johan, Florian Fainelli
In-Reply-To: <20161208194125.13264-1-f.fainelli@gmail.com>

The Lantiq Etop driver calls into PHYLIB which now checks for
net_device->dev.parent, so make sure we do set it before calling into
any MDIO/PHYLIB related function.

Fixes: ec988ad78ed6 ("phy: Don't increment MDIO bus refcount unless it's a different owner")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/net/ethernet/lantiq_etop.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c
index 91e09d68b7e2..a167fd7ee13e 100644
--- a/drivers/net/ethernet/lantiq_etop.c
+++ b/drivers/net/ethernet/lantiq_etop.c
@@ -704,6 +704,7 @@ ltq_etop_probe(struct platform_device *pdev)
 	priv->pldata = dev_get_platdata(&pdev->dev);
 	priv->netdev = dev;
 	spin_lock_init(&priv->lock);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	for (i = 0; i < MAX_DMA_CHAN; i++) {
 		if (IS_TX(i))
-- 
2.9.3

^ permalink raw reply related

* [PATCH net 0/2] net: ethernet: Make sure we set dev->dev.parent
From: Florian Fainelli @ 2016-12-08 19:41 UTC (permalink / raw)
  To: netdev; +Cc: davem, madalin.bucur, johan, Florian Fainelli

Hi David,

This patch series builds atop:

ec988ad78ed6d184a7f4ca6b8e962b0e8f1de461 ("phy: Don't increment MDIO bus
refcount unless it's a different owner")

FMAN is the one that potentially needs patching as well (call SET_NETDEV_DEV),
but there appears to be no way that init_phy is called right now, or there is
not such an in-tree user. Madalin, can you comment on that?

Florian Fainelli (2):
  net: ethernet: lantiq_etop: Call SET_NETDEV_DEV()
  net: ethernet: cpmac: Call SET_NETDEV_DEV()

 drivers/net/ethernet/lantiq_etop.c | 1 +
 drivers/net/ethernet/ti/cpmac.c    | 1 +
 2 files changed, 2 insertions(+)

-- 
2.9.3

^ permalink raw reply

* Re: [net-next PATCH v5 0/6] XDP for virtio_net
From: Alexei Starovoitov @ 2016-12-08 19:38 UTC (permalink / raw)
  To: David Miller
  Cc: john.fastabend, daniel, mst, shm, tgraf, john.r.fastabend, netdev,
	brouer
In-Reply-To: <20161208.141702.1346950420275854265.davem@davemloft.net>

On Thu, Dec 08, 2016 at 02:17:02PM -0500, David Miller wrote:
> From: John Fastabend <john.fastabend@gmail.com>
> Date: Wed, 07 Dec 2016 12:10:47 -0800
> 
> > This implements virtio_net for the mergeable buffers and big_packet
> > modes. I tested this with vhost_net running on qemu and did not see
> > any issues. For testing num_buf > 1 I added a hack to vhost driver
> > to only but 100 bytes per buffer.
>  ...
> 
> So where are we with this?
> 
> I'm not too thrilled with the idea of making XDP_TX optional or
> something like that.  If someone enables XDP, there is a tradeoff.
> 
> I also have reservations about the idea to make jumbo frames work
> without giving XDP access to the whole packet.  If it wants to push or
> pop a header, it might need to know the whole packet length.  How will
> you pass that to the XDP program?
> 
> Some kinds of encapsulation require trailers, thus preclusing access
> to the entire packet precludes those kinds of transformations.

+1

> This is why we want simple, linear, buffer access for XDP.
> 
> Even the most seemingly minor exception turns into a huge complicated
> mess.

+1

and from the other thread:
> > Can't we disable XDP_TX somehow? Many people might only want RX drop,
> > and extra queues are not always there.
> >
> 
> Alexei, Daniel, any thoughts on this?

I don't like it.

> I know we were trying to claim some base level of feature support for
> all XDP drivers. I am sympathetic to this argument though for DDOS we
> do not need XDP_TX support. And virtio can become queue constrained
> in some cases.

especially for ddos case doing lro/gro is not helpful.
I frankly don't see a use case where you'd want to steer a packet
all the way into VM just to drop them there?
Without XDP_TX it's too crippled. adjust_head() won't be possible,
packet mangling would have to be disabled and so on.
If xdp program doesn't see raw packet it can only parse the headers of
this jumbo meta-packet and drop it, but for virtio it's really too late.
ddos protection needs to be done at the earliest hw nic receive.
I think if driver claims xdp support it needs to support
drop/pass/tx and adjust_head. For metadata passing up into stack from xdp
we need adjust_head, for encap/decap we need it too. And lro is in the way
of such transformations.
We struggled a lot with cls_bpf due to all metadata inside skb that needs
to be kept correct. Feeding non-raw packets into xdp is a rat hole.

^ permalink raw reply

* Re: pull request: bluetooth-next 2016-12-08
From: David Miller @ 2016-12-08 19:33 UTC (permalink / raw)
  To: johan.hedberg; +Cc: linux-bluetooth, netdev
In-Reply-To: <20161208075222.GA5772@x1c.lan>

From: Johan Hedberg <johan.hedberg@gmail.com>
Date: Thu, 8 Dec 2016 09:52:22 +0200

>   git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git for-upstream

Pulled.

^ permalink raw reply

* Re: [PATCH net-next] net: sock_rps_record_flow() is for connected sockets
From: Eric Dumazet @ 2016-12-08 19:32 UTC (permalink / raw)
  To: Paolo Abeni; +Cc: David Miller, netdev, Willem de Bruijn, Tom Herbert
In-Reply-To: <1481223008.8408.6.camel@redhat.com>

On Thu, 2016-12-08 at 19:50 +0100, Paolo Abeni wrote:

> UDP GRO will require connected socket - very likely no DNS server. The
> use-case is an application using long lived UDP sockets doing a lot of
> traffic, like fix protocol feeds over UDP. 

You mean, the kind of traffic that should use TCP in the first place,
right ? ;)

NFS switched to TCP a long time ago.

^ permalink raw reply

* Re: [PATCH] cxgb4/cxgb4vf: Remove deprecated module parameters
From: David Miller @ 2016-12-08 19:31 UTC (permalink / raw)
  To: ganeshgr; +Cc: netdev, nirranjan, hariprasad
In-Reply-To: <1481183185-14636-1-git-send-email-ganeshgr@chelsio.com>

From: Ganesh Goudar <ganeshgr@chelsio.com>
Date: Thu,  8 Dec 2016 13:16:25 +0530

> Remove deprecated module parameters num_vf, dflt_msg_enable and
> force_init.
> 
> Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>

Applied.

^ permalink raw reply

* Re: [PATCH net v2 1/1] driver: ipvlan: Unlink the upper dev when ipvlan_link_new failed
From: David Miller @ 2016-12-08 19:30 UTC (permalink / raw)
  To: fgao; +Cc: maheshb, edumazet, netdev, gfree.wind
In-Reply-To: <1481167018-559-1-git-send-email-fgao@ikuai8.com>

From: fgao@ikuai8.com
Date: Thu,  8 Dec 2016 11:16:58 +0800

> From: Gao Feng <fgao@ikuai8.com>
> 
> When netdev_upper_dev_unlink failed in ipvlan_link_new, need to
> unlink the ipvlan dev with upper dev.
> 
> Signed-off-by: Gao Feng <fgao@ikuai8.com>

Applied.

^ permalink raw reply

* Re: [PATCH v4 net-next 0/4]: Allow head adjustment in XDP prog
From: David Miller @ 2016-12-08 19:25 UTC (permalink / raw)
  To: kafai
  Cc: netdev, ast, bblanco, daniel, kubakici, brouer, john.fastabend,
	saeedm, tariqt, kernel-team
In-Reply-To: <1481154794-2311034-1-git-send-email-kafai@fb.com>

From: Martin KaFai Lau <kafai@fb.com>
Date: Wed, 7 Dec 2016 15:53:10 -0800

> This series adds a helper to allow head adjusting in XDP prog.  mlx4
> driver has been modified to support this feature.  An example is written
> to encapsulate a packet with an IPv4/v6 header and then XDP_TX it
> out.

Series applied.

^ permalink raw reply

* [PATCH 1/2] [v2] net: qcom/emac: move phy init code to separate files
From: Timur Tabi @ 2016-12-08 19:24 UTC (permalink / raw)
  To: David Miller, netdev, alokc
In-Reply-To: <1481225061-30962-1-git-send-email-timur@codeaurora.org>

The internal PHY of the EMAC differs on each SOC, and the list will
only continue to grow.  By separating the code into individual files,
we can add support for more SOCs more cleanly.

Note: The internal PHY is also sometimes called the SGMII device.

We also stop referring to the various PHY variations by version number,
so no more "v2", "v3", etc.  Instead, the devices are named after the
SOC they are, which is in sync with the device tree property names.

Future patches will probably rearrange more code among the files.

Signed-off-by: Timur Tabi <timur@codeaurora.org>
---

Notes:
    v2: remove extraneous _v1

 drivers/net/ethernet/qualcomm/emac/Makefile        |   3 +-
 .../ethernet/qualcomm/emac/emac-sgmii-fsm9900.c    | 245 ++++++++++
 .../ethernet/qualcomm/emac/emac-sgmii-qdf2432.c    | 210 ++++++++
 drivers/net/ethernet/qualcomm/emac/emac-sgmii.c    | 538 +--------------------
 drivers/net/ethernet/qualcomm/emac/emac-sgmii.h    |   5 +-
 5 files changed, 478 insertions(+), 523 deletions(-)
 create mode 100644 drivers/net/ethernet/qualcomm/emac/emac-sgmii-fsm9900.c
 create mode 100644 drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c

diff --git a/drivers/net/ethernet/qualcomm/emac/Makefile b/drivers/net/ethernet/qualcomm/emac/Makefile
index 01ee144..204b787 100644
--- a/drivers/net/ethernet/qualcomm/emac/Makefile
+++ b/drivers/net/ethernet/qualcomm/emac/Makefile
@@ -4,4 +4,5 @@
 
 obj-$(CONFIG_QCOM_EMAC) += qcom-emac.o
 
-qcom-emac-objs := emac.o emac-mac.o emac-phy.o emac-sgmii.o
+qcom-emac-objs := emac.o emac-mac.o emac-phy.o emac-sgmii.o \
+		  emac-sgmii-fsm9900.o emac-sgmii-qdf2432.o
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii-fsm9900.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-fsm9900.c
new file mode 100644
index 0000000..af690e1
--- /dev/null
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-fsm9900.c
@@ -0,0 +1,245 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* Qualcomm Technologies, Inc. FSM9900 EMAC SGMII Controller driver.
+ */
+
+#include <linux/iopoll.h>
+#include "emac.h"
+
+/* EMAC_QSERDES register offsets */
+#define EMAC_QSERDES_COM_SYS_CLK_CTRL		0x0000
+#define EMAC_QSERDES_COM_PLL_CNTRL		0x0014
+#define EMAC_QSERDES_COM_PLL_IP_SETI		0x0018
+#define EMAC_QSERDES_COM_PLL_CP_SETI		0x0024
+#define EMAC_QSERDES_COM_PLL_IP_SETP		0x0028
+#define EMAC_QSERDES_COM_PLL_CP_SETP		0x002c
+#define EMAC_QSERDES_COM_SYSCLK_EN_SEL		0x0038
+#define EMAC_QSERDES_COM_RESETSM_CNTRL		0x0040
+#define EMAC_QSERDES_COM_PLLLOCK_CMP1		0x0044
+#define EMAC_QSERDES_COM_PLLLOCK_CMP2		0x0048
+#define EMAC_QSERDES_COM_PLLLOCK_CMP3		0x004c
+#define EMAC_QSERDES_COM_PLLLOCK_CMP_EN		0x0050
+#define EMAC_QSERDES_COM_DEC_START1		0x0064
+#define EMAC_QSERDES_COM_DIV_FRAC_START1	0x0098
+#define EMAC_QSERDES_COM_DIV_FRAC_START2	0x009c
+#define EMAC_QSERDES_COM_DIV_FRAC_START3	0x00a0
+#define EMAC_QSERDES_COM_DEC_START2		0x00a4
+#define EMAC_QSERDES_COM_PLL_CRCTRL		0x00ac
+#define EMAC_QSERDES_COM_RESET_SM		0x00bc
+#define EMAC_QSERDES_TX_BIST_MODE_LANENO	0x0100
+#define EMAC_QSERDES_TX_TX_EMP_POST1_LVL	0x0108
+#define EMAC_QSERDES_TX_TX_DRV_LVL		0x010c
+#define EMAC_QSERDES_TX_LANE_MODE		0x0150
+#define EMAC_QSERDES_TX_TRAN_DRVR_EMP_EN	0x0170
+#define EMAC_QSERDES_RX_CDR_CONTROL		0x0200
+#define EMAC_QSERDES_RX_CDR_CONTROL2		0x0210
+#define EMAC_QSERDES_RX_RX_EQ_GAIN12		0x0230
+
+/* EMAC_SGMII register offsets */
+#define EMAC_SGMII_PHY_SERDES_START		0x0000
+#define EMAC_SGMII_PHY_CMN_PWR_CTRL		0x0004
+#define EMAC_SGMII_PHY_RX_PWR_CTRL		0x0008
+#define EMAC_SGMII_PHY_TX_PWR_CTRL		0x000C
+#define EMAC_SGMII_PHY_LANE_CTRL1		0x0018
+#define EMAC_SGMII_PHY_CDR_CTRL0		0x0058
+#define EMAC_SGMII_PHY_POW_DWN_CTRL0		0x0080
+#define EMAC_SGMII_PHY_INTERRUPT_MASK		0x00b4
+
+#define PLL_IPSETI(x)				((x) & 0x3f)
+
+#define PLL_CPSETI(x)				((x) & 0xff)
+
+#define PLL_IPSETP(x)				((x) & 0x3f)
+
+#define PLL_CPSETP(x)				((x) & 0x1f)
+
+#define PLL_RCTRL(x)				(((x) & 0xf) << 4)
+#define PLL_CCTRL(x)				((x) & 0xf)
+
+#define LANE_MODE(x)				((x) & 0x1f)
+
+#define SYSCLK_CM				BIT(4)
+#define SYSCLK_AC_COUPLE			BIT(3)
+
+#define OCP_EN					BIT(5)
+#define PLL_DIV_FFEN				BIT(2)
+#define PLL_DIV_ORD				BIT(1)
+
+#define SYSCLK_SEL_CMOS				BIT(3)
+
+#define FRQ_TUNE_MODE				BIT(4)
+
+#define PLLLOCK_CMP_EN				BIT(0)
+
+#define DEC_START1_MUX				BIT(7)
+#define DEC_START1(x)				((x) & 0x7f)
+
+#define DIV_FRAC_START_MUX			BIT(7)
+#define DIV_FRAC_START(x)			((x) & 0x7f)
+
+#define DIV_FRAC_START3_MUX			BIT(4)
+#define DIV_FRAC_START3(x)			((x) & 0xf)
+
+#define DEC_START2_MUX				BIT(1)
+#define DEC_START2				BIT(0)
+
+#define READY					BIT(5)
+
+#define TX_EMP_POST1_LVL_MUX			BIT(5)
+#define TX_EMP_POST1_LVL(x)			((x) & 0x1f)
+
+#define TX_DRV_LVL_MUX				BIT(4)
+#define TX_DRV_LVL(x)				((x) & 0xf)
+
+#define EMP_EN_MUX				BIT(1)
+#define EMP_EN					BIT(0)
+
+#define SECONDORDERENABLE			BIT(6)
+#define FIRSTORDER_THRESH(x)			(((x) & 0x7) << 3)
+#define SECONDORDERGAIN(x)			((x) & 0x7)
+
+#define RX_EQ_GAIN2(x)				(((x) & 0xf) << 4)
+#define RX_EQ_GAIN1(x)				((x) & 0xf)
+
+#define SERDES_START				BIT(0)
+
+#define BIAS_EN					BIT(6)
+#define PLL_EN					BIT(5)
+#define SYSCLK_EN				BIT(4)
+#define CLKBUF_L_EN				BIT(3)
+#define PLL_TXCLK_EN				BIT(1)
+#define PLL_RXCLK_EN				BIT(0)
+
+#define L0_RX_SIGDET_EN				BIT(7)
+#define L0_RX_TERM_MODE(x)			(((x) & 3) << 4)
+#define L0_RX_I_EN				BIT(1)
+
+#define L0_TX_EN				BIT(5)
+#define L0_CLKBUF_EN				BIT(4)
+#define L0_TRAN_BIAS_EN				BIT(1)
+
+#define L0_RX_EQUALIZE_ENABLE			BIT(6)
+#define L0_RESET_TSYNC_EN			BIT(4)
+#define L0_DRV_LVL(x)				((x) & 0xf)
+
+#define PWRDN_B					BIT(0)
+#define CDR_MAX_CNT(x)				((x) & 0xff)
+
+#define PLLLOCK_CMP(x)				((x) & 0xff)
+
+#define SERDES_START_WAIT_TIMES			100
+
+struct emac_reg_write {
+	unsigned int offset;
+	u32 val;
+};
+
+static void emac_reg_write_all(void __iomem *base,
+			       const struct emac_reg_write *itr, size_t size)
+{
+	size_t i;
+
+	for (i = 0; i < size; ++itr, ++i)
+		writel(itr->val, base + itr->offset);
+}
+
+static const struct emac_reg_write physical_coding_sublayer_programming[] = {
+	{EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)},
+	{EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B},
+	{EMAC_SGMII_PHY_CMN_PWR_CTRL,
+		BIAS_EN | SYSCLK_EN | CLKBUF_L_EN | PLL_TXCLK_EN | PLL_RXCLK_EN},
+	{EMAC_SGMII_PHY_TX_PWR_CTRL, L0_TX_EN | L0_CLKBUF_EN | L0_TRAN_BIAS_EN},
+	{EMAC_SGMII_PHY_RX_PWR_CTRL,
+		L0_RX_SIGDET_EN | L0_RX_TERM_MODE(1) | L0_RX_I_EN},
+	{EMAC_SGMII_PHY_CMN_PWR_CTRL,
+		BIAS_EN | PLL_EN | SYSCLK_EN | CLKBUF_L_EN | PLL_TXCLK_EN |
+		PLL_RXCLK_EN},
+	{EMAC_SGMII_PHY_LANE_CTRL1,
+		L0_RX_EQUALIZE_ENABLE | L0_RESET_TSYNC_EN | L0_DRV_LVL(15)},
+};
+
+static const struct emac_reg_write sysclk_refclk_setting[] = {
+	{EMAC_QSERDES_COM_SYSCLK_EN_SEL, SYSCLK_SEL_CMOS},
+	{EMAC_QSERDES_COM_SYS_CLK_CTRL,	SYSCLK_CM | SYSCLK_AC_COUPLE},
+};
+
+static const struct emac_reg_write pll_setting[] = {
+	{EMAC_QSERDES_COM_PLL_IP_SETI, PLL_IPSETI(1)},
+	{EMAC_QSERDES_COM_PLL_CP_SETI, PLL_CPSETI(59)},
+	{EMAC_QSERDES_COM_PLL_IP_SETP, PLL_IPSETP(10)},
+	{EMAC_QSERDES_COM_PLL_CP_SETP, PLL_CPSETP(9)},
+	{EMAC_QSERDES_COM_PLL_CRCTRL, PLL_RCTRL(15) | PLL_CCTRL(11)},
+	{EMAC_QSERDES_COM_PLL_CNTRL, OCP_EN | PLL_DIV_FFEN | PLL_DIV_ORD},
+	{EMAC_QSERDES_COM_DEC_START1, DEC_START1_MUX | DEC_START1(2)},
+	{EMAC_QSERDES_COM_DEC_START2, DEC_START2_MUX | DEC_START2},
+	{EMAC_QSERDES_COM_DIV_FRAC_START1,
+		DIV_FRAC_START_MUX | DIV_FRAC_START(85)},
+	{EMAC_QSERDES_COM_DIV_FRAC_START2,
+		DIV_FRAC_START_MUX | DIV_FRAC_START(42)},
+	{EMAC_QSERDES_COM_DIV_FRAC_START3,
+		DIV_FRAC_START3_MUX | DIV_FRAC_START3(3)},
+	{EMAC_QSERDES_COM_PLLLOCK_CMP1, PLLLOCK_CMP(43)},
+	{EMAC_QSERDES_COM_PLLLOCK_CMP2, PLLLOCK_CMP(104)},
+	{EMAC_QSERDES_COM_PLLLOCK_CMP3, PLLLOCK_CMP(0)},
+	{EMAC_QSERDES_COM_PLLLOCK_CMP_EN, PLLLOCK_CMP_EN},
+	{EMAC_QSERDES_COM_RESETSM_CNTRL, FRQ_TUNE_MODE},
+};
+
+static const struct emac_reg_write cdr_setting[] = {
+	{EMAC_QSERDES_RX_CDR_CONTROL,
+		SECONDORDERENABLE | FIRSTORDER_THRESH(3) | SECONDORDERGAIN(2)},
+	{EMAC_QSERDES_RX_CDR_CONTROL2,
+		SECONDORDERENABLE | FIRSTORDER_THRESH(3) | SECONDORDERGAIN(4)},
+};
+
+static const struct emac_reg_write tx_rx_setting[] = {
+	{EMAC_QSERDES_TX_BIST_MODE_LANENO, 0},
+	{EMAC_QSERDES_TX_TX_DRV_LVL, TX_DRV_LVL_MUX | TX_DRV_LVL(15)},
+	{EMAC_QSERDES_TX_TRAN_DRVR_EMP_EN, EMP_EN_MUX | EMP_EN},
+	{EMAC_QSERDES_TX_TX_EMP_POST1_LVL,
+		TX_EMP_POST1_LVL_MUX | TX_EMP_POST1_LVL(1)},
+	{EMAC_QSERDES_RX_RX_EQ_GAIN12, RX_EQ_GAIN2(15) | RX_EQ_GAIN1(15)},
+	{EMAC_QSERDES_TX_LANE_MODE, LANE_MODE(8)},
+};
+
+int emac_sgmii_init_fsm9900(struct emac_adapter *adpt)
+{
+	struct emac_phy *phy = &adpt->phy;
+	unsigned int i;
+
+	emac_reg_write_all(phy->base, physical_coding_sublayer_programming,
+			   ARRAY_SIZE(physical_coding_sublayer_programming));
+	emac_reg_write_all(phy->base, sysclk_refclk_setting,
+			   ARRAY_SIZE(sysclk_refclk_setting));
+	emac_reg_write_all(phy->base, pll_setting, ARRAY_SIZE(pll_setting));
+	emac_reg_write_all(phy->base, cdr_setting, ARRAY_SIZE(cdr_setting));
+	emac_reg_write_all(phy->base, tx_rx_setting, ARRAY_SIZE(tx_rx_setting));
+
+	/* Power up the Ser/Des engine */
+	writel(SERDES_START, phy->base + EMAC_SGMII_PHY_SERDES_START);
+
+	for (i = 0; i < SERDES_START_WAIT_TIMES; i++) {
+		if (readl(phy->base + EMAC_QSERDES_COM_RESET_SM) & READY)
+			break;
+		usleep_range(100, 200);
+	}
+
+	if (i == SERDES_START_WAIT_TIMES) {
+		netdev_err(adpt->netdev, "error: ser/des failed to start\n");
+		return -EIO;
+	}
+	/* Mask out all the SGMII Interrupt */
+	writel(0, phy->base + EMAC_SGMII_PHY_INTERRUPT_MASK);
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c
new file mode 100644
index 0000000..6170200
--- /dev/null
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c
@@ -0,0 +1,210 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* Qualcomm Technologies, Inc. QDF2432 EMAC SGMII Controller driver.
+ */
+
+#include <linux/iopoll.h>
+#include "emac.h"
+
+/* EMAC_SGMII register offsets */
+#define EMAC_SGMII_PHY_TX_PWR_CTRL		0x000C
+#define EMAC_SGMII_PHY_LANE_CTRL1		0x0018
+#define EMAC_SGMII_PHY_CDR_CTRL0		0x0058
+#define EMAC_SGMII_PHY_POW_DWN_CTRL0		0x0080
+#define EMAC_SGMII_PHY_RESET_CTRL		0x00a8
+#define EMAC_SGMII_PHY_INTERRUPT_MASK		0x00b4
+
+/* SGMII digital lane registers */
+#define EMAC_SGMII_LN_DRVR_CTRL0		0x000C
+#define EMAC_SGMII_LN_DRVR_TAP_EN		0x0018
+#define EMAC_SGMII_LN_TX_MARGINING		0x001C
+#define EMAC_SGMII_LN_TX_PRE			0x0020
+#define EMAC_SGMII_LN_TX_POST			0x0024
+#define EMAC_SGMII_LN_TX_BAND_MODE		0x0060
+#define EMAC_SGMII_LN_LANE_MODE			0x0064
+#define EMAC_SGMII_LN_PARALLEL_RATE		0x0078
+#define EMAC_SGMII_LN_CML_CTRL_MODE0		0x00B8
+#define EMAC_SGMII_LN_MIXER_CTRL_MODE0		0x00D0
+#define EMAC_SGMII_LN_VGA_INITVAL		0x0134
+#define EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0	0x017C
+#define EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0	0x0188
+#define EMAC_SGMII_LN_UCDR_SO_CONFIG		0x0194
+#define EMAC_SGMII_LN_RX_BAND			0x019C
+#define EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0	0x01B8
+#define EMAC_SGMII_LN_RSM_CONFIG		0x01F0
+#define EMAC_SGMII_LN_SIGDET_ENABLES		0x0224
+#define EMAC_SGMII_LN_SIGDET_CNTRL		0x0228
+#define EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL	0x022C
+#define EMAC_SGMII_LN_RX_EN_SIGNAL		0x02A0
+#define EMAC_SGMII_LN_RX_MISC_CNTRL0		0x02AC
+#define EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV		0x02BC
+
+/* SGMII digital lane register values */
+#define UCDR_STEP_BY_TWO_MODE0			BIT(7)
+#define UCDR_xO_GAIN_MODE(x)			((x) & 0x7f)
+#define UCDR_ENABLE				BIT(6)
+#define UCDR_SO_SATURATION(x)			((x) & 0x3f)
+
+#define SIGDET_LP_BYP_PS4			BIT(7)
+#define SIGDET_EN_PS0_TO_PS2			BIT(6)
+
+#define TXVAL_VALID_INIT			BIT(4)
+#define KR_PCIGEN3_MODE				BIT(0)
+
+#define MAIN_EN					BIT(0)
+
+#define TX_MARGINING_MUX			BIT(6)
+#define TX_MARGINING(x)				((x) & 0x3f)
+
+#define TX_PRE_MUX				BIT(6)
+
+#define TX_POST_MUX				BIT(6)
+
+#define CML_GEAR_MODE(x)			(((x) & 7) << 3)
+#define CML2CMOS_IBOOST_MODE(x)			((x) & 7)
+
+#define MIXER_LOADB_MODE(x)			(((x) & 0xf) << 2)
+#define MIXER_DATARATE_MODE(x)			((x) & 3)
+
+#define VGA_THRESH_DFE(x)			((x) & 0x3f)
+
+#define SIGDET_LP_BYP_PS0_TO_PS2		BIT(5)
+#define SIGDET_FLT_BYP				BIT(0)
+
+#define SIGDET_LVL(x)				(((x) & 0xf) << 4)
+
+#define SIGDET_DEGLITCH_CTRL(x)			(((x) & 0xf) << 1)
+
+#define DRVR_LOGIC_CLK_EN			BIT(4)
+#define DRVR_LOGIC_CLK_DIV(x)			((x) & 0xf)
+
+#define PARALLEL_RATE_MODE0(x)			((x) & 0x3)
+
+#define BAND_MODE0(x)				((x) & 0x3)
+
+#define LANE_MODE(x)				((x) & 0x1f)
+
+#define CDR_PD_SEL_MODE0(x)			(((x) & 0x3) << 5)
+#define BYPASS_RSM_SAMP_CAL			BIT(1)
+#define BYPASS_RSM_DLL_CAL			BIT(0)
+
+#define L0_RX_EQUALIZE_ENABLE			BIT(6)
+
+#define PWRDN_B					BIT(0)
+
+#define CDR_MAX_CNT(x)				((x) & 0xff)
+
+#define SERDES_START_WAIT_TIMES			100
+
+struct emac_reg_write {
+	unsigned int offset;
+	u32 val;
+};
+
+static void emac_reg_write_all(void __iomem *base,
+			       const struct emac_reg_write *itr, size_t size)
+{
+	size_t i;
+
+	for (i = 0; i < size; ++itr, ++i)
+		writel(itr->val, base + itr->offset);
+}
+
+static const struct emac_reg_write sgmii_laned[] = {
+	/* CDR Settings */
+	{EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0,
+		UCDR_STEP_BY_TWO_MODE0 | UCDR_xO_GAIN_MODE(10)},
+	{EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(0)},
+	{EMAC_SGMII_LN_UCDR_SO_CONFIG, UCDR_ENABLE | UCDR_SO_SATURATION(12)},
+
+	/* TX/RX Settings */
+	{EMAC_SGMII_LN_RX_EN_SIGNAL, SIGDET_LP_BYP_PS4 | SIGDET_EN_PS0_TO_PS2},
+
+	{EMAC_SGMII_LN_DRVR_CTRL0, TXVAL_VALID_INIT | KR_PCIGEN3_MODE},
+	{EMAC_SGMII_LN_DRVR_TAP_EN, MAIN_EN},
+	{EMAC_SGMII_LN_TX_MARGINING, TX_MARGINING_MUX | TX_MARGINING(25)},
+	{EMAC_SGMII_LN_TX_PRE, TX_PRE_MUX},
+	{EMAC_SGMII_LN_TX_POST, TX_POST_MUX},
+
+	{EMAC_SGMII_LN_CML_CTRL_MODE0,
+		CML_GEAR_MODE(1) | CML2CMOS_IBOOST_MODE(1)},
+	{EMAC_SGMII_LN_MIXER_CTRL_MODE0,
+		MIXER_LOADB_MODE(12) | MIXER_DATARATE_MODE(1)},
+	{EMAC_SGMII_LN_VGA_INITVAL, VGA_THRESH_DFE(31)},
+	{EMAC_SGMII_LN_SIGDET_ENABLES,
+		SIGDET_LP_BYP_PS0_TO_PS2 | SIGDET_FLT_BYP},
+	{EMAC_SGMII_LN_SIGDET_CNTRL, SIGDET_LVL(8)},
+
+	{EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL, SIGDET_DEGLITCH_CTRL(4)},
+	{EMAC_SGMII_LN_RX_MISC_CNTRL0, 0},
+	{EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV,
+		DRVR_LOGIC_CLK_EN | DRVR_LOGIC_CLK_DIV(4)},
+
+	{EMAC_SGMII_LN_PARALLEL_RATE, PARALLEL_RATE_MODE0(1)},
+	{EMAC_SGMII_LN_TX_BAND_MODE, BAND_MODE0(2)},
+	{EMAC_SGMII_LN_RX_BAND, BAND_MODE0(3)},
+	{EMAC_SGMII_LN_LANE_MODE, LANE_MODE(26)},
+	{EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0, CDR_PD_SEL_MODE0(3)},
+	{EMAC_SGMII_LN_RSM_CONFIG, BYPASS_RSM_SAMP_CAL | BYPASS_RSM_DLL_CAL},
+};
+
+static const struct emac_reg_write physical_coding_sublayer_programming[] = {
+	{EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B},
+	{EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)},
+	{EMAC_SGMII_PHY_TX_PWR_CTRL, 0},
+	{EMAC_SGMII_PHY_LANE_CTRL1, L0_RX_EQUALIZE_ENABLE},
+};
+
+int emac_sgmii_init_qdf2432(struct emac_adapter *adpt)
+{
+	struct emac_phy *phy = &adpt->phy;
+	void __iomem *phy_regs = phy->base;
+	void __iomem *laned = phy->digital;
+	unsigned int i;
+	u32 lnstatus;
+
+	/* PCS lane-x init */
+	emac_reg_write_all(phy->base, physical_coding_sublayer_programming,
+			   ARRAY_SIZE(physical_coding_sublayer_programming));
+
+	/* SGMII lane-x init */
+	emac_reg_write_all(phy->digital, sgmii_laned, ARRAY_SIZE(sgmii_laned));
+
+	/* Power up PCS and start reset lane state machine */
+
+	writel(0, phy_regs + EMAC_SGMII_PHY_RESET_CTRL);
+	writel(1, laned + SGMII_LN_RSM_START);
+
+	/* Wait for c_ready assertion */
+	for (i = 0; i < SERDES_START_WAIT_TIMES; i++) {
+		lnstatus = readl(phy_regs + SGMII_PHY_LN_LANE_STATUS);
+		if (lnstatus & BIT(1))
+			break;
+		usleep_range(100, 200);
+	}
+
+	if (i == SERDES_START_WAIT_TIMES) {
+		netdev_err(adpt->netdev, "SGMII failed to start\n");
+		return -EIO;
+	}
+
+	/* Disable digital and SERDES loopback */
+	writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN0);
+	writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN2);
+	writel(0, phy_regs + SGMII_PHY_LN_CDR_CTRL1);
+
+	/* Mask out all the SGMII Interrupt */
+	writel(0, phy_regs + EMAC_SGMII_PHY_INTERRUPT_MASK);
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
index 3edb5a5..07c872a 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
@@ -20,448 +20,33 @@
 #include "emac-mac.h"
 #include "emac-sgmii.h"
 
-/* EMAC_QSERDES register offsets */
-#define EMAC_QSERDES_COM_SYS_CLK_CTRL		0x000000
-#define EMAC_QSERDES_COM_PLL_CNTRL		0x000014
-#define EMAC_QSERDES_COM_PLL_IP_SETI		0x000018
-#define EMAC_QSERDES_COM_PLL_CP_SETI		0x000024
-#define EMAC_QSERDES_COM_PLL_IP_SETP		0x000028
-#define EMAC_QSERDES_COM_PLL_CP_SETP		0x00002c
-#define EMAC_QSERDES_COM_SYSCLK_EN_SEL		0x000038
-#define EMAC_QSERDES_COM_RESETSM_CNTRL		0x000040
-#define EMAC_QSERDES_COM_PLLLOCK_CMP1		0x000044
-#define EMAC_QSERDES_COM_PLLLOCK_CMP2		0x000048
-#define EMAC_QSERDES_COM_PLLLOCK_CMP3		0x00004c
-#define EMAC_QSERDES_COM_PLLLOCK_CMP_EN		0x000050
-#define EMAC_QSERDES_COM_DEC_START1		0x000064
-#define EMAC_QSERDES_COM_DIV_FRAC_START1	0x000098
-#define EMAC_QSERDES_COM_DIV_FRAC_START2	0x00009c
-#define EMAC_QSERDES_COM_DIV_FRAC_START3	0x0000a0
-#define EMAC_QSERDES_COM_DEC_START2		0x0000a4
-#define EMAC_QSERDES_COM_PLL_CRCTRL		0x0000ac
-#define EMAC_QSERDES_COM_RESET_SM		0x0000bc
-#define EMAC_QSERDES_TX_BIST_MODE_LANENO	0x000100
-#define EMAC_QSERDES_TX_TX_EMP_POST1_LVL	0x000108
-#define EMAC_QSERDES_TX_TX_DRV_LVL		0x00010c
-#define EMAC_QSERDES_TX_LANE_MODE		0x000150
-#define EMAC_QSERDES_TX_TRAN_DRVR_EMP_EN	0x000170
-#define EMAC_QSERDES_RX_CDR_CONTROL		0x000200
-#define EMAC_QSERDES_RX_CDR_CONTROL2		0x000210
-#define EMAC_QSERDES_RX_RX_EQ_GAIN12		0x000230
-
 /* EMAC_SGMII register offsets */
-#define EMAC_SGMII_PHY_SERDES_START		0x000000
-#define EMAC_SGMII_PHY_CMN_PWR_CTRL		0x000004
-#define EMAC_SGMII_PHY_RX_PWR_CTRL		0x000008
-#define EMAC_SGMII_PHY_TX_PWR_CTRL		0x00000C
-#define EMAC_SGMII_PHY_LANE_CTRL1		0x000018
-#define EMAC_SGMII_PHY_AUTONEG_CFG2		0x000048
-#define EMAC_SGMII_PHY_CDR_CTRL0		0x000058
-#define EMAC_SGMII_PHY_SPEED_CFG1		0x000074
-#define EMAC_SGMII_PHY_POW_DWN_CTRL0		0x000080
-#define EMAC_SGMII_PHY_RESET_CTRL		0x0000a8
-#define EMAC_SGMII_PHY_IRQ_CMD			0x0000ac
-#define EMAC_SGMII_PHY_INTERRUPT_CLEAR		0x0000b0
-#define EMAC_SGMII_PHY_INTERRUPT_MASK		0x0000b4
-#define EMAC_SGMII_PHY_INTERRUPT_STATUS		0x0000b8
-#define EMAC_SGMII_PHY_RX_CHK_STATUS		0x0000d4
-#define EMAC_SGMII_PHY_AUTONEG0_STATUS		0x0000e0
-#define EMAC_SGMII_PHY_AUTONEG1_STATUS		0x0000e4
-
-/* EMAC_QSERDES_COM_PLL_IP_SETI */
-#define PLL_IPSETI(x)				((x) & 0x3f)
-
-/* EMAC_QSERDES_COM_PLL_CP_SETI */
-#define PLL_CPSETI(x)				((x) & 0xff)
-
-/* EMAC_QSERDES_COM_PLL_IP_SETP */
-#define PLL_IPSETP(x)				((x) & 0x3f)
-
-/* EMAC_QSERDES_COM_PLL_CP_SETP */
-#define PLL_CPSETP(x)				((x) & 0x1f)
-
-/* EMAC_QSERDES_COM_PLL_CRCTRL */
-#define PLL_RCTRL(x)				(((x) & 0xf) << 4)
-#define PLL_CCTRL(x)				((x) & 0xf)
-
-/* SGMII v2 PHY registers per lane */
-#define EMAC_SGMII_PHY_LN_OFFSET		0x0400
-
-/* SGMII v2 digital lane registers */
-#define EMAC_SGMII_LN_DRVR_CTRL0		0x00C
-#define EMAC_SGMII_LN_DRVR_TAP_EN		0x018
-#define EMAC_SGMII_LN_TX_MARGINING		0x01C
-#define EMAC_SGMII_LN_TX_PRE			0x020
-#define EMAC_SGMII_LN_TX_POST			0x024
-#define EMAC_SGMII_LN_TX_BAND_MODE		0x060
-#define EMAC_SGMII_LN_LANE_MODE			0x064
-#define EMAC_SGMII_LN_PARALLEL_RATE		0x078
-#define EMAC_SGMII_LN_CML_CTRL_MODE0		0x0B8
-#define EMAC_SGMII_LN_MIXER_CTRL_MODE0		0x0D0
-#define EMAC_SGMII_LN_VGA_INITVAL		0x134
-#define EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0	0x17C
-#define EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0	0x188
-#define EMAC_SGMII_LN_UCDR_SO_CONFIG		0x194
-#define EMAC_SGMII_LN_RX_BAND			0x19C
-#define EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0	0x1B8
-#define EMAC_SGMII_LN_RSM_CONFIG		0x1F0
-#define EMAC_SGMII_LN_SIGDET_ENABLES		0x224
-#define EMAC_SGMII_LN_SIGDET_CNTRL		0x228
-#define EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL	0x22C
-#define EMAC_SGMII_LN_RX_EN_SIGNAL		0x2A0
-#define EMAC_SGMII_LN_RX_MISC_CNTRL0		0x2AC
-#define EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV		0x2BC
-
-/* SGMII v2 digital lane register values */
-#define UCDR_STEP_BY_TWO_MODE0			BIT(7)
-#define UCDR_xO_GAIN_MODE(x)			((x) & 0x7f)
-#define UCDR_ENABLE				BIT(6)
-#define UCDR_SO_SATURATION(x)			((x) & 0x3f)
-#define SIGDET_LP_BYP_PS4			BIT(7)
-#define SIGDET_EN_PS0_TO_PS2			BIT(6)
-#define EN_ACCOUPLEVCM_SW_MUX			BIT(5)
-#define EN_ACCOUPLEVCM_SW			BIT(4)
-#define RX_SYNC_EN				BIT(3)
-#define RXTERM_HIGHZ_PS5			BIT(2)
-#define SIGDET_EN_PS3				BIT(1)
-#define EN_ACCOUPLE_VCM_PS3			BIT(0)
-#define UFS_MODE				BIT(5)
-#define TXVAL_VALID_INIT			BIT(4)
-#define TXVAL_VALID_MUX				BIT(3)
-#define TXVAL_VALID				BIT(2)
-#define USB3P1_MODE				BIT(1)
-#define KR_PCIGEN3_MODE				BIT(0)
-#define PRE_EN					BIT(3)
-#define POST_EN					BIT(2)
-#define MAIN_EN_MUX				BIT(1)
-#define MAIN_EN					BIT(0)
-#define TX_MARGINING_MUX			BIT(6)
-#define TX_MARGINING(x)				((x) & 0x3f)
-#define TX_PRE_MUX				BIT(6)
-#define TX_PRE(x)				((x) & 0x3f)
-#define TX_POST_MUX				BIT(6)
-#define TX_POST(x)				((x) & 0x3f)
-#define CML_GEAR_MODE(x)			(((x) & 7) << 3)
-#define CML2CMOS_IBOOST_MODE(x)			((x) & 7)
-#define MIXER_LOADB_MODE(x)			(((x) & 0xf) << 2)
-#define MIXER_DATARATE_MODE(x)			((x) & 3)
-#define VGA_THRESH_DFE(x)			((x) & 0x3f)
-#define SIGDET_LP_BYP_PS0_TO_PS2		BIT(5)
-#define SIGDET_LP_BYP_MUX			BIT(4)
-#define SIGDET_LP_BYP				BIT(3)
-#define SIGDET_EN_MUX				BIT(2)
-#define SIGDET_EN				BIT(1)
-#define SIGDET_FLT_BYP				BIT(0)
-#define SIGDET_LVL(x)				(((x) & 0xf) << 4)
-#define SIGDET_BW_CTRL(x)			((x) & 0xf)
-#define SIGDET_DEGLITCH_CTRL(x)			(((x) & 0xf) << 1)
-#define SIGDET_DEGLITCH_BYP			BIT(0)
-#define INVERT_PCS_RX_CLK			BIT(7)
-#define PWM_EN					BIT(6)
-#define RXBIAS_SEL(x)				(((x) & 0x3) << 4)
-#define EBDAC_SIGN				BIT(3)
-#define EDAC_SIGN				BIT(2)
-#define EN_AUXTAP1SIGN_INVERT			BIT(1)
-#define EN_DAC_CHOPPING				BIT(0)
-#define DRVR_LOGIC_CLK_EN			BIT(4)
-#define DRVR_LOGIC_CLK_DIV(x)			((x) & 0xf)
-#define PARALLEL_RATE_MODE2(x)			(((x) & 0x3) << 4)
-#define PARALLEL_RATE_MODE1(x)			(((x) & 0x3) << 2)
-#define PARALLEL_RATE_MODE0(x)			((x) & 0x3)
-#define BAND_MODE2(x)				(((x) & 0x3) << 4)
-#define BAND_MODE1(x)				(((x) & 0x3) << 2)
-#define BAND_MODE0(x)				((x) & 0x3)
-#define LANE_SYNC_MODE				BIT(5)
-#define LANE_MODE(x)				((x) & 0x1f)
-#define CDR_PD_SEL_MODE0(x)			(((x) & 0x3) << 5)
-#define EN_DLL_MODE0				BIT(4)
-#define EN_IQ_DCC_MODE0				BIT(3)
-#define EN_IQCAL_MODE0				BIT(2)
-#define EN_QPATH_MODE0				BIT(1)
-#define EN_EPATH_MODE0				BIT(0)
-#define FORCE_TSYNC_ACK				BIT(7)
-#define FORCE_CMN_ACK				BIT(6)
-#define FORCE_CMN_READY				BIT(5)
-#define EN_RCLK_DEGLITCH			BIT(4)
-#define BYPASS_RSM_CDR_RESET			BIT(3)
-#define BYPASS_RSM_TSYNC			BIT(2)
-#define BYPASS_RSM_SAMP_CAL			BIT(1)
-#define BYPASS_RSM_DLL_CAL			BIT(0)
-
-/* EMAC_QSERDES_COM_SYS_CLK_CTRL */
-#define SYSCLK_CM				BIT(4)
-#define SYSCLK_AC_COUPLE			BIT(3)
-
-/* EMAC_QSERDES_COM_PLL_CNTRL */
-#define OCP_EN					BIT(5)
-#define PLL_DIV_FFEN				BIT(2)
-#define PLL_DIV_ORD				BIT(1)
-
-/* EMAC_QSERDES_COM_SYSCLK_EN_SEL */
-#define SYSCLK_SEL_CMOS				BIT(3)
-
-/* EMAC_QSERDES_COM_RESETSM_CNTRL */
-#define FRQ_TUNE_MODE				BIT(4)
-
-/* EMAC_QSERDES_COM_PLLLOCK_CMP_EN */
-#define PLLLOCK_CMP_EN				BIT(0)
-
-/* EMAC_QSERDES_COM_DEC_START1 */
-#define DEC_START1_MUX				BIT(7)
-#define DEC_START1(x)				((x) & 0x7f)
-
-/* EMAC_QSERDES_COM_DIV_FRAC_START1 * EMAC_QSERDES_COM_DIV_FRAC_START2 */
-#define DIV_FRAC_START_MUX			BIT(7)
-#define DIV_FRAC_START(x)			((x) & 0x7f)
-
-/* EMAC_QSERDES_COM_DIV_FRAC_START3 */
-#define DIV_FRAC_START3_MUX			BIT(4)
-#define DIV_FRAC_START3(x)			((x) & 0xf)
-
-/* EMAC_QSERDES_COM_DEC_START2 */
-#define DEC_START2_MUX				BIT(1)
-#define DEC_START2				BIT(0)
-
-/* EMAC_QSERDES_COM_RESET_SM */
-#define READY					BIT(5)
-
-/* EMAC_QSERDES_TX_TX_EMP_POST1_LVL */
-#define TX_EMP_POST1_LVL_MUX			BIT(5)
-#define TX_EMP_POST1_LVL(x)			((x) & 0x1f)
-#define TX_EMP_POST1_LVL_BMSK			0x1f
-#define TX_EMP_POST1_LVL_SHFT			0
-
-/* EMAC_QSERDES_TX_TX_DRV_LVL */
-#define TX_DRV_LVL_MUX				BIT(4)
-#define TX_DRV_LVL(x)				((x) & 0xf)
-
-/* EMAC_QSERDES_TX_TRAN_DRVR_EMP_EN */
-#define EMP_EN_MUX				BIT(1)
-#define EMP_EN					BIT(0)
-
-/* EMAC_QSERDES_RX_CDR_CONTROL & EMAC_QSERDES_RX_CDR_CONTROL2 */
-#define HBW_PD_EN				BIT(7)
-#define SECONDORDERENABLE			BIT(6)
-#define FIRSTORDER_THRESH(x)			(((x) & 0x7) << 3)
-#define SECONDORDERGAIN(x)			((x) & 0x7)
-
-/* EMAC_QSERDES_RX_RX_EQ_GAIN12 */
-#define RX_EQ_GAIN2(x)				(((x) & 0xf) << 4)
-#define RX_EQ_GAIN1(x)				((x) & 0xf)
-
-/* EMAC_SGMII_PHY_SERDES_START */
-#define SERDES_START				BIT(0)
-
-/* EMAC_SGMII_PHY_CMN_PWR_CTRL */
-#define BIAS_EN					BIT(6)
-#define PLL_EN					BIT(5)
-#define SYSCLK_EN				BIT(4)
-#define CLKBUF_L_EN				BIT(3)
-#define PLL_TXCLK_EN				BIT(1)
-#define PLL_RXCLK_EN				BIT(0)
-
-/* EMAC_SGMII_PHY_RX_PWR_CTRL */
-#define L0_RX_SIGDET_EN				BIT(7)
-#define L0_RX_TERM_MODE(x)			(((x) & 3) << 4)
-#define L0_RX_I_EN				BIT(1)
-
-/* EMAC_SGMII_PHY_TX_PWR_CTRL */
-#define L0_TX_EN				BIT(5)
-#define L0_CLKBUF_EN				BIT(4)
-#define L0_TRAN_BIAS_EN				BIT(1)
-
-/* EMAC_SGMII_PHY_LANE_CTRL1 */
-#define L0_RX_EQUALIZE_ENABLE			BIT(6)
-#define L0_RESET_TSYNC_EN			BIT(4)
-#define L0_DRV_LVL(x)				((x) & 0xf)
-
-/* EMAC_SGMII_PHY_AUTONEG_CFG2 */
+#define EMAC_SGMII_PHY_AUTONEG_CFG2		0x0048
+#define EMAC_SGMII_PHY_SPEED_CFG1		0x0074
+#define EMAC_SGMII_PHY_IRQ_CMD			0x00ac
+#define EMAC_SGMII_PHY_INTERRUPT_CLEAR		0x00b0
+#define EMAC_SGMII_PHY_INTERRUPT_STATUS		0x00b8
+
 #define FORCE_AN_TX_CFG				BIT(5)
 #define FORCE_AN_RX_CFG				BIT(4)
 #define AN_ENABLE				BIT(0)
 
-/* EMAC_SGMII_PHY_SPEED_CFG1 */
 #define DUPLEX_MODE				BIT(4)
 #define SPDMODE_1000				BIT(1)
 #define SPDMODE_100				BIT(0)
 #define SPDMODE_10				0
-#define SPDMODE_BMSK				3
-#define SPDMODE_SHFT				0
-
-/* EMAC_SGMII_PHY_POW_DWN_CTRL0 */
-#define PWRDN_B					BIT(0)
-#define CDR_MAX_CNT(x)				((x) & 0xff)
-
-/* EMAC_QSERDES_TX_BIST_MODE_LANENO */
-#define BIST_LANE_NUMBER(x)			(((x) & 3) << 5)
-#define BISTMODE(x)				((x) & 0x1f)
-
-/* EMAC_QSERDES_COM_PLLLOCK_CMPx */
-#define PLLLOCK_CMP(x)				((x) & 0xff)
 
-/* EMAC_SGMII_PHY_RESET_CTRL */
-#define PHY_SW_RESET				BIT(0)
-
-/* EMAC_SGMII_PHY_IRQ_CMD */
 #define IRQ_GLOBAL_CLEAR			BIT(0)
 
-/* EMAC_SGMII_PHY_INTERRUPT_MASK */
 #define DECODE_CODE_ERR				BIT(7)
 #define DECODE_DISP_ERR				BIT(6)
-#define PLL_UNLOCK				BIT(5)
-#define AN_ILLEGAL_TERM				BIT(4)
-#define SYNC_FAIL				BIT(3)
-#define AN_START				BIT(2)
-#define AN_END					BIT(1)
-#define AN_REQUEST				BIT(0)
 
 #define SGMII_PHY_IRQ_CLR_WAIT_TIME		10
 
-#define SGMII_PHY_INTERRUPT_ERR (\
-	DECODE_CODE_ERR         |\
-	DECODE_DISP_ERR)
-
-#define SGMII_ISR_AN_MASK       (\
-	AN_REQUEST              |\
-	AN_START                |\
-	AN_END                  |\
-	AN_ILLEGAL_TERM         |\
-	PLL_UNLOCK              |\
-	SYNC_FAIL)
-
-#define SGMII_ISR_MASK          (\
-	SGMII_PHY_INTERRUPT_ERR |\
-	SGMII_ISR_AN_MASK)
-
-/* SGMII TX_CONFIG */
-#define TXCFG_LINK				0x8000
-#define TXCFG_MODE_BMSK				0x1c00
-#define TXCFG_1000_FULL				0x1800
-#define TXCFG_100_FULL				0x1400
-#define TXCFG_100_HALF				0x0400
-#define TXCFG_10_FULL				0x1000
-#define TXCFG_10_HALF				0x0000
+#define SGMII_PHY_INTERRUPT_ERR		(DECODE_CODE_ERR | DECODE_DISP_ERR)
 
 #define SERDES_START_WAIT_TIMES			100
 
-struct emac_reg_write {
-	unsigned int offset;
-	u32 val;
-};
-
-static void emac_reg_write_all(void __iomem *base,
-			       const struct emac_reg_write *itr, size_t size)
-{
-	size_t i;
-
-	for (i = 0; i < size; ++itr, ++i)
-		writel(itr->val, base + itr->offset);
-}
-
-static const struct emac_reg_write physical_coding_sublayer_programming_v1[] = {
-	{EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)},
-	{EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B},
-	{EMAC_SGMII_PHY_CMN_PWR_CTRL,
-		BIAS_EN | SYSCLK_EN | CLKBUF_L_EN | PLL_TXCLK_EN | PLL_RXCLK_EN},
-	{EMAC_SGMII_PHY_TX_PWR_CTRL, L0_TX_EN | L0_CLKBUF_EN | L0_TRAN_BIAS_EN},
-	{EMAC_SGMII_PHY_RX_PWR_CTRL,
-		L0_RX_SIGDET_EN | L0_RX_TERM_MODE(1) | L0_RX_I_EN},
-	{EMAC_SGMII_PHY_CMN_PWR_CTRL,
-		BIAS_EN | PLL_EN | SYSCLK_EN | CLKBUF_L_EN | PLL_TXCLK_EN |
-		PLL_RXCLK_EN},
-	{EMAC_SGMII_PHY_LANE_CTRL1,
-		L0_RX_EQUALIZE_ENABLE | L0_RESET_TSYNC_EN | L0_DRV_LVL(15)},
-};
-
-static const struct emac_reg_write sysclk_refclk_setting[] = {
-	{EMAC_QSERDES_COM_SYSCLK_EN_SEL, SYSCLK_SEL_CMOS},
-	{EMAC_QSERDES_COM_SYS_CLK_CTRL,	SYSCLK_CM | SYSCLK_AC_COUPLE},
-};
-
-static const struct emac_reg_write pll_setting[] = {
-	{EMAC_QSERDES_COM_PLL_IP_SETI, PLL_IPSETI(1)},
-	{EMAC_QSERDES_COM_PLL_CP_SETI, PLL_CPSETI(59)},
-	{EMAC_QSERDES_COM_PLL_IP_SETP, PLL_IPSETP(10)},
-	{EMAC_QSERDES_COM_PLL_CP_SETP, PLL_CPSETP(9)},
-	{EMAC_QSERDES_COM_PLL_CRCTRL, PLL_RCTRL(15) | PLL_CCTRL(11)},
-	{EMAC_QSERDES_COM_PLL_CNTRL, OCP_EN | PLL_DIV_FFEN | PLL_DIV_ORD},
-	{EMAC_QSERDES_COM_DEC_START1, DEC_START1_MUX | DEC_START1(2)},
-	{EMAC_QSERDES_COM_DEC_START2, DEC_START2_MUX | DEC_START2},
-	{EMAC_QSERDES_COM_DIV_FRAC_START1,
-		DIV_FRAC_START_MUX | DIV_FRAC_START(85)},
-	{EMAC_QSERDES_COM_DIV_FRAC_START2,
-		DIV_FRAC_START_MUX | DIV_FRAC_START(42)},
-	{EMAC_QSERDES_COM_DIV_FRAC_START3,
-		DIV_FRAC_START3_MUX | DIV_FRAC_START3(3)},
-	{EMAC_QSERDES_COM_PLLLOCK_CMP1, PLLLOCK_CMP(43)},
-	{EMAC_QSERDES_COM_PLLLOCK_CMP2, PLLLOCK_CMP(104)},
-	{EMAC_QSERDES_COM_PLLLOCK_CMP3, PLLLOCK_CMP(0)},
-	{EMAC_QSERDES_COM_PLLLOCK_CMP_EN, PLLLOCK_CMP_EN},
-	{EMAC_QSERDES_COM_RESETSM_CNTRL, FRQ_TUNE_MODE},
-};
-
-static const struct emac_reg_write cdr_setting[] = {
-	{EMAC_QSERDES_RX_CDR_CONTROL,
-		SECONDORDERENABLE | FIRSTORDER_THRESH(3) | SECONDORDERGAIN(2)},
-	{EMAC_QSERDES_RX_CDR_CONTROL2,
-		SECONDORDERENABLE | FIRSTORDER_THRESH(3) | SECONDORDERGAIN(4)},
-};
-
-static const struct emac_reg_write tx_rx_setting[] = {
-	{EMAC_QSERDES_TX_BIST_MODE_LANENO, 0},
-	{EMAC_QSERDES_TX_TX_DRV_LVL, TX_DRV_LVL_MUX | TX_DRV_LVL(15)},
-	{EMAC_QSERDES_TX_TRAN_DRVR_EMP_EN, EMP_EN_MUX | EMP_EN},
-	{EMAC_QSERDES_TX_TX_EMP_POST1_LVL,
-		TX_EMP_POST1_LVL_MUX | TX_EMP_POST1_LVL(1)},
-	{EMAC_QSERDES_RX_RX_EQ_GAIN12, RX_EQ_GAIN2(15) | RX_EQ_GAIN1(15)},
-	{EMAC_QSERDES_TX_LANE_MODE, LANE_MODE(8)},
-};
-
-static const struct emac_reg_write sgmii_v2_laned[] = {
-	/* CDR Settings */
-	{EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0,
-		UCDR_STEP_BY_TWO_MODE0 | UCDR_xO_GAIN_MODE(10)},
-	{EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(0)},
-	{EMAC_SGMII_LN_UCDR_SO_CONFIG, UCDR_ENABLE | UCDR_SO_SATURATION(12)},
-
-	/* TX/RX Settings */
-	{EMAC_SGMII_LN_RX_EN_SIGNAL, SIGDET_LP_BYP_PS4 | SIGDET_EN_PS0_TO_PS2},
-
-	{EMAC_SGMII_LN_DRVR_CTRL0, TXVAL_VALID_INIT | KR_PCIGEN3_MODE},
-	{EMAC_SGMII_LN_DRVR_TAP_EN, MAIN_EN},
-	{EMAC_SGMII_LN_TX_MARGINING, TX_MARGINING_MUX | TX_MARGINING(25)},
-	{EMAC_SGMII_LN_TX_PRE, TX_PRE_MUX},
-	{EMAC_SGMII_LN_TX_POST, TX_POST_MUX},
-
-	{EMAC_SGMII_LN_CML_CTRL_MODE0,
-		CML_GEAR_MODE(1) | CML2CMOS_IBOOST_MODE(1)},
-	{EMAC_SGMII_LN_MIXER_CTRL_MODE0,
-		MIXER_LOADB_MODE(12) | MIXER_DATARATE_MODE(1)},
-	{EMAC_SGMII_LN_VGA_INITVAL, VGA_THRESH_DFE(31)},
-	{EMAC_SGMII_LN_SIGDET_ENABLES,
-		SIGDET_LP_BYP_PS0_TO_PS2 | SIGDET_FLT_BYP},
-	{EMAC_SGMII_LN_SIGDET_CNTRL, SIGDET_LVL(8)},
-
-	{EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL, SIGDET_DEGLITCH_CTRL(4)},
-	{EMAC_SGMII_LN_RX_MISC_CNTRL0, 0},
-	{EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV,
-		DRVR_LOGIC_CLK_EN | DRVR_LOGIC_CLK_DIV(4)},
-
-	{EMAC_SGMII_LN_PARALLEL_RATE, PARALLEL_RATE_MODE0(1)},
-	{EMAC_SGMII_LN_TX_BAND_MODE, BAND_MODE0(2)},
-	{EMAC_SGMII_LN_RX_BAND, BAND_MODE0(3)},
-	{EMAC_SGMII_LN_LANE_MODE, LANE_MODE(26)},
-	{EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0, CDR_PD_SEL_MODE0(3)},
-	{EMAC_SGMII_LN_RSM_CONFIG, BYPASS_RSM_SAMP_CAL | BYPASS_RSM_DLL_CAL},
-};
-
-static const struct emac_reg_write physical_coding_sublayer_programming_v2[] = {
-	{EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B},
-	{EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)},
-	{EMAC_SGMII_PHY_TX_PWR_CTRL, 0},
-	{EMAC_SGMII_PHY_LANE_CTRL1, L0_RX_EQUALIZE_ENABLE},
-};
-
 static int emac_sgmii_link_init(struct emac_adapter *adpt)
 {
 	struct phy_device *phydev = adpt->phydev;
@@ -536,98 +121,6 @@ static int emac_sgmii_irq_clear(struct emac_adapter *adpt, u32 irq_bits)
 	return 0;
 }
 
-int emac_sgmii_init_v1(struct emac_adapter *adpt)
-{
-	struct emac_phy *phy = &adpt->phy;
-	unsigned int i;
-	int ret;
-
-	ret = emac_sgmii_link_init(adpt);
-	if (ret)
-		return ret;
-
-	emac_reg_write_all(phy->base, physical_coding_sublayer_programming_v1,
-			   ARRAY_SIZE(physical_coding_sublayer_programming_v1));
-	emac_reg_write_all(phy->base, sysclk_refclk_setting,
-			   ARRAY_SIZE(sysclk_refclk_setting));
-	emac_reg_write_all(phy->base, pll_setting, ARRAY_SIZE(pll_setting));
-	emac_reg_write_all(phy->base, cdr_setting, ARRAY_SIZE(cdr_setting));
-	emac_reg_write_all(phy->base, tx_rx_setting,
-			   ARRAY_SIZE(tx_rx_setting));
-
-	/* Power up the Ser/Des engine */
-	writel(SERDES_START, phy->base + EMAC_SGMII_PHY_SERDES_START);
-
-	for (i = 0; i < SERDES_START_WAIT_TIMES; i++) {
-		if (readl(phy->base + EMAC_QSERDES_COM_RESET_SM) & READY)
-			break;
-		usleep_range(100, 200);
-	}
-
-	if (i == SERDES_START_WAIT_TIMES) {
-		netdev_err(adpt->netdev, "error: ser/des failed to start\n");
-		return -EIO;
-	}
-	/* Mask out all the SGMII Interrupt */
-	writel(0, phy->base + EMAC_SGMII_PHY_INTERRUPT_MASK);
-
-	emac_sgmii_irq_clear(adpt, SGMII_PHY_INTERRUPT_ERR);
-
-	return 0;
-}
-
-int emac_sgmii_init_v2(struct emac_adapter *adpt)
-{
-	struct emac_phy *phy = &adpt->phy;
-	void __iomem *phy_regs = phy->base;
-	void __iomem *laned = phy->digital;
-	unsigned int i;
-	u32 lnstatus;
-	int ret;
-
-	ret = emac_sgmii_link_init(adpt);
-	if (ret)
-		return ret;
-
-	/* PCS lane-x init */
-	emac_reg_write_all(phy->base, physical_coding_sublayer_programming_v2,
-			   ARRAY_SIZE(physical_coding_sublayer_programming_v2));
-
-	/* SGMII lane-x init */
-	emac_reg_write_all(phy->digital,
-			   sgmii_v2_laned, ARRAY_SIZE(sgmii_v2_laned));
-
-	/* Power up PCS and start reset lane state machine */
-
-	writel(0, phy_regs + EMAC_SGMII_PHY_RESET_CTRL);
-	writel(1, laned + SGMII_LN_RSM_START);
-
-	/* Wait for c_ready assertion */
-	for (i = 0; i < SERDES_START_WAIT_TIMES; i++) {
-		lnstatus = readl(phy_regs + SGMII_PHY_LN_LANE_STATUS);
-		if (lnstatus & BIT(1))
-			break;
-		usleep_range(100, 200);
-	}
-
-	if (i == SERDES_START_WAIT_TIMES) {
-		netdev_err(adpt->netdev, "SGMII failed to start\n");
-		return -EIO;
-	}
-
-	/* Disable digital and SERDES loopback */
-	writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN0);
-	writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN2);
-	writel(0, phy_regs + SGMII_PHY_LN_CDR_CTRL1);
-
-	/* Mask out all the SGMII Interrupt */
-	writel(0, phy_regs + EMAC_SGMII_PHY_INTERRUPT_MASK);
-
-	emac_sgmii_irq_clear(adpt, SGMII_PHY_INTERRUPT_ERR);
-
-	return 0;
-}
-
 static void emac_sgmii_reset_prepare(struct emac_adapter *adpt)
 {
 	struct emac_phy *phy = &adpt->phy;
@@ -651,16 +144,19 @@ void emac_sgmii_reset(struct emac_adapter *adpt)
 {
 	int ret;
 
-	clk_set_rate(adpt->clk[EMAC_CLK_HIGH_SPEED], 19200000);
 	emac_sgmii_reset_prepare(adpt);
 
+	ret = emac_sgmii_link_init(adpt);
+	if (ret) {
+		netdev_err(adpt->netdev, "unsupported link speed\n");
+		return;
+	}
+
 	ret = adpt->phy.initialize(adpt);
 	if (ret)
 		netdev_err(adpt->netdev,
 			   "could not reinitialize internal PHY (error=%i)\n",
 			   ret);
-
-	clk_set_rate(adpt->clk[EMAC_CLK_HIGH_SPEED], 125000000);
 }
 
 static int emac_sgmii_acpi_match(struct device *dev, void *data)
@@ -668,7 +164,7 @@ static int emac_sgmii_acpi_match(struct device *dev, void *data)
 	static const struct acpi_device_id match_table[] = {
 		{
 			.id = "QCOM8071",
-			.driver_data = (kernel_ulong_t)emac_sgmii_init_v2,
+			.driver_data = (kernel_ulong_t)emac_sgmii_init_qdf2432,
 		},
 		{}
 	};
@@ -684,11 +180,11 @@ static int emac_sgmii_acpi_match(struct device *dev, void *data)
 static const struct of_device_id emac_sgmii_dt_match[] = {
 	{
 		.compatible = "qcom,fsm9900-emac-sgmii",
-		.data = emac_sgmii_init_v1,
+		.data = emac_sgmii_init_fsm9900,
 	},
 	{
 		.compatible = "qcom,qdf2432-emac-sgmii",
-		.data = emac_sgmii_init_v2,
+		.data = emac_sgmii_init_qdf2432,
 	},
 	{}
 };
@@ -760,6 +256,8 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt)
 	if (ret)
 		goto error;
 
+	emac_sgmii_irq_clear(adpt, SGMII_PHY_INTERRUPT_ERR);
+
 	/* We've remapped the addresses, so we don't need the device any
 	 * more.  of_find_device_by_node() says we should release it.
 	 */
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h
index ce79212..e2bef14 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h
@@ -16,9 +16,10 @@
 struct emac_adapter;
 struct platform_device;
 
-int emac_sgmii_init_v1(struct emac_adapter *adpt);
-int emac_sgmii_init_v2(struct emac_adapter *adpt);
 int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt);
 void emac_sgmii_reset(struct emac_adapter *adpt);
 
+int emac_sgmii_init_fsm9900(struct emac_adapter *adpt);
+int emac_sgmii_init_qdf2432(struct emac_adapter *adpt);
+
 #endif
-- 
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc.  Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

^ permalink raw reply related

* [PATCH 2/2] [v3] net: qcom/emac: add support for the Qualcomm Technologies QDF2400
From: Timur Tabi @ 2016-12-08 19:24 UTC (permalink / raw)
  To: David Miller, netdev, alokc
In-Reply-To: <1481225061-30962-1-git-send-email-timur@codeaurora.org>

The QDF2432 and the QDF2400 have slightly different internal PHYs,
so there are some programming differences.  Some of the registers in
the QDF2400 have moved, and some registers require different values
during initialization.

Because of the differences, and because HIDs are a scare resource,
the ACPI tables specify the hardware version in an _HRV property.
Version 1 is the QDF2432, and version 2 is the QDF2400.  Any future
SOC that has the same internal PHY but different programming
requirements will be assigned the next available version number.

Signed-off-by: Timur Tabi <timur@codeaurora.org>
---

Notes:
    v3: fix kbuild compilation error with !CONFIG_ACPI

 drivers/net/ethernet/qualcomm/emac/Makefile        |   3 +-
 .../ethernet/qualcomm/emac/emac-sgmii-qdf2400.c    | 217 +++++++++++++++++++++
 drivers/net/ethernet/qualcomm/emac/emac-sgmii.c    |  33 +++-
 drivers/net/ethernet/qualcomm/emac/emac-sgmii.h    |   1 +
 4 files changed, 249 insertions(+), 5 deletions(-)
 create mode 100644 drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c

diff --git a/drivers/net/ethernet/qualcomm/emac/Makefile b/drivers/net/ethernet/qualcomm/emac/Makefile
index 204b787..7a66879 100644
--- a/drivers/net/ethernet/qualcomm/emac/Makefile
+++ b/drivers/net/ethernet/qualcomm/emac/Makefile
@@ -5,4 +5,5 @@
 obj-$(CONFIG_QCOM_EMAC) += qcom-emac.o
 
 qcom-emac-objs := emac.o emac-mac.o emac-phy.o emac-sgmii.o \
-		  emac-sgmii-fsm9900.o emac-sgmii-qdf2432.o
+		  emac-sgmii-fsm9900.o emac-sgmii-qdf2432.o \
+		  emac-sgmii-qdf2400.o
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c
new file mode 100644
index 0000000..5b84194
--- /dev/null
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c
@@ -0,0 +1,217 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* Qualcomm Technologies, Inc. QDF2400 EMAC SGMII Controller driver.
+ */
+
+#include <linux/iopoll.h>
+#include "emac.h"
+
+/* EMAC_SGMII register offsets */
+#define EMAC_SGMII_PHY_TX_PWR_CTRL		0x000C
+#define EMAC_SGMII_PHY_LANE_CTRL1		0x0018
+#define EMAC_SGMII_PHY_CDR_CTRL0		0x0058
+#define EMAC_SGMII_PHY_POW_DWN_CTRL0		0x0080
+#define EMAC_SGMII_PHY_RESET_CTRL		0x00a8
+#define EMAC_SGMII_PHY_INTERRUPT_MASK		0x00b4
+
+/* SGMII digital lane registers */
+#define EMAC_SGMII_LN_DRVR_CTRL0		0x000C
+#define EMAC_SGMII_LN_DRVR_TAP_EN		0x0018
+#define EMAC_SGMII_LN_TX_MARGINING		0x001C
+#define EMAC_SGMII_LN_TX_PRE			0x0020
+#define EMAC_SGMII_LN_TX_POST			0x0024
+#define EMAC_SGMII_LN_TX_BAND_MODE		0x0060
+#define EMAC_SGMII_LN_LANE_MODE			0x0064
+#define EMAC_SGMII_LN_PARALLEL_RATE		0x007C
+#define EMAC_SGMII_LN_CML_CTRL_MODE0		0x00C0
+#define EMAC_SGMII_LN_MIXER_CTRL_MODE0		0x00D8
+#define EMAC_SGMII_LN_VGA_INITVAL		0x013C
+#define EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0	0x0184
+#define EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0	0x0190
+#define EMAC_SGMII_LN_UCDR_SO_CONFIG		0x019C
+#define EMAC_SGMII_LN_RX_BAND			0x01A4
+#define EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0	0x01C0
+#define EMAC_SGMII_LN_RSM_CONFIG		0x01F8
+#define EMAC_SGMII_LN_SIGDET_ENABLES		0x0230
+#define EMAC_SGMII_LN_SIGDET_CNTRL		0x0234
+#define EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL	0x0238
+#define EMAC_SGMII_LN_RX_EN_SIGNAL		0x02AC
+#define EMAC_SGMII_LN_RX_MISC_CNTRL0		0x02B8
+#define EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV		0x02C8
+
+/* SGMII digital lane register values */
+#define UCDR_STEP_BY_TWO_MODE0			BIT(7)
+#define UCDR_xO_GAIN_MODE(x)			((x) & 0x7f)
+#define UCDR_ENABLE				BIT(6)
+#define UCDR_SO_SATURATION(x)			((x) & 0x3f)
+
+#define SIGDET_LP_BYP_PS4			BIT(7)
+#define SIGDET_EN_PS0_TO_PS2			BIT(6)
+
+#define TXVAL_VALID_INIT			BIT(4)
+#define KR_PCIGEN3_MODE				BIT(0)
+
+#define MAIN_EN					BIT(0)
+
+#define TX_MARGINING_MUX			BIT(6)
+#define TX_MARGINING(x)				((x) & 0x3f)
+
+#define TX_PRE_MUX				BIT(6)
+
+#define TX_POST_MUX				BIT(6)
+
+#define CML_GEAR_MODE(x)			(((x) & 7) << 3)
+#define CML2CMOS_IBOOST_MODE(x)			((x) & 7)
+
+#define MIXER_LOADB_MODE(x)			(((x) & 0xf) << 2)
+#define MIXER_DATARATE_MODE(x)			((x) & 3)
+
+#define VGA_THRESH_DFE(x)			((x) & 0x3f)
+
+#define SIGDET_LP_BYP_PS0_TO_PS2		BIT(5)
+#define SIGDET_FLT_BYP				BIT(0)
+
+#define SIGDET_LVL(x)				(((x) & 0xf) << 4)
+
+#define SIGDET_DEGLITCH_CTRL(x)			(((x) & 0xf) << 1)
+
+#define INVERT_PCS_RX_CLK			BIT(7)
+
+#define DRVR_LOGIC_CLK_EN			BIT(4)
+#define DRVR_LOGIC_CLK_DIV(x)			((x) & 0xf)
+
+#define PARALLEL_RATE_MODE0(x)			((x) & 0x3)
+
+#define BAND_MODE0(x)				((x) & 0x3)
+
+#define LANE_MODE(x)				((x) & 0x1f)
+
+#define CDR_PD_SEL_MODE0(x)			(((x) & 0x3) << 5)
+#define EN_DLL_MODE0				BIT(4)
+#define EN_IQ_DCC_MODE0				BIT(3)
+#define EN_IQCAL_MODE0				BIT(2)
+
+#define BYPASS_RSM_SAMP_CAL			BIT(1)
+#define BYPASS_RSM_DLL_CAL			BIT(0)
+
+#define L0_RX_EQUALIZE_ENABLE			BIT(6)
+
+#define PWRDN_B					BIT(0)
+
+#define CDR_MAX_CNT(x)				((x) & 0xff)
+
+#define SERDES_START_WAIT_TIMES			100
+
+struct emac_reg_write {
+	unsigned int offset;
+	u32 val;
+};
+
+static void emac_reg_write_all(void __iomem *base,
+			       const struct emac_reg_write *itr, size_t size)
+{
+	size_t i;
+
+	for (i = 0; i < size; ++itr, ++i)
+		writel(itr->val, base + itr->offset);
+}
+
+static const struct emac_reg_write sgmii_laned[] = {
+	/* CDR Settings */
+	{EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0,
+		UCDR_STEP_BY_TWO_MODE0 | UCDR_xO_GAIN_MODE(10)},
+	{EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(0)},
+	{EMAC_SGMII_LN_UCDR_SO_CONFIG, UCDR_ENABLE | UCDR_SO_SATURATION(12)},
+
+	/* TX/RX Settings */
+	{EMAC_SGMII_LN_RX_EN_SIGNAL, SIGDET_LP_BYP_PS4 | SIGDET_EN_PS0_TO_PS2},
+
+	{EMAC_SGMII_LN_DRVR_CTRL0, TXVAL_VALID_INIT | KR_PCIGEN3_MODE},
+	{EMAC_SGMII_LN_DRVR_TAP_EN, MAIN_EN},
+	{EMAC_SGMII_LN_TX_MARGINING, TX_MARGINING_MUX | TX_MARGINING(25)},
+	{EMAC_SGMII_LN_TX_PRE, TX_PRE_MUX},
+	{EMAC_SGMII_LN_TX_POST, TX_POST_MUX},
+
+	{EMAC_SGMII_LN_CML_CTRL_MODE0,
+		CML_GEAR_MODE(1) | CML2CMOS_IBOOST_MODE(1)},
+	{EMAC_SGMII_LN_MIXER_CTRL_MODE0,
+		MIXER_LOADB_MODE(12) | MIXER_DATARATE_MODE(1)},
+	{EMAC_SGMII_LN_VGA_INITVAL, VGA_THRESH_DFE(31)},
+	{EMAC_SGMII_LN_SIGDET_ENABLES,
+		SIGDET_LP_BYP_PS0_TO_PS2 | SIGDET_FLT_BYP},
+	{EMAC_SGMII_LN_SIGDET_CNTRL, SIGDET_LVL(8)},
+
+	{EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL, SIGDET_DEGLITCH_CTRL(4)},
+	{EMAC_SGMII_LN_RX_MISC_CNTRL0, INVERT_PCS_RX_CLK},
+	{EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV,
+		DRVR_LOGIC_CLK_EN | DRVR_LOGIC_CLK_DIV(4)},
+
+	{EMAC_SGMII_LN_PARALLEL_RATE, PARALLEL_RATE_MODE0(1)},
+	{EMAC_SGMII_LN_TX_BAND_MODE, BAND_MODE0(1)},
+	{EMAC_SGMII_LN_RX_BAND, BAND_MODE0(2)},
+	{EMAC_SGMII_LN_LANE_MODE, LANE_MODE(26)},
+	{EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0, CDR_PD_SEL_MODE0(2) |
+		EN_DLL_MODE0 | EN_IQ_DCC_MODE0 | EN_IQCAL_MODE0},
+	{EMAC_SGMII_LN_RSM_CONFIG, BYPASS_RSM_SAMP_CAL | BYPASS_RSM_DLL_CAL},
+};
+
+static const struct emac_reg_write physical_coding_sublayer_programming[] = {
+	{EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B},
+	{EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)},
+	{EMAC_SGMII_PHY_TX_PWR_CTRL, 0},
+	{EMAC_SGMII_PHY_LANE_CTRL1, L0_RX_EQUALIZE_ENABLE},
+};
+
+int emac_sgmii_init_qdf2400(struct emac_adapter *adpt)
+{
+	struct emac_phy *phy = &adpt->phy;
+	void __iomem *phy_regs = phy->base;
+	void __iomem *laned = phy->digital;
+	unsigned int i;
+	u32 lnstatus;
+
+	/* PCS lane-x init */
+	emac_reg_write_all(phy->base, physical_coding_sublayer_programming,
+			   ARRAY_SIZE(physical_coding_sublayer_programming));
+
+	/* SGMII lane-x init */
+	emac_reg_write_all(phy->digital, sgmii_laned, ARRAY_SIZE(sgmii_laned));
+
+	/* Power up PCS and start reset lane state machine */
+
+	writel(0, phy_regs + EMAC_SGMII_PHY_RESET_CTRL);
+	writel(1, laned + SGMII_LN_RSM_START);
+
+	/* Wait for c_ready assertion */
+	for (i = 0; i < SERDES_START_WAIT_TIMES; i++) {
+		lnstatus = readl(phy_regs + SGMII_PHY_LN_LANE_STATUS);
+		if (lnstatus & BIT(1))
+			break;
+		usleep_range(100, 200);
+	}
+
+	if (i == SERDES_START_WAIT_TIMES) {
+		netdev_err(adpt->netdev, "SGMII failed to start\n");
+		return -EIO;
+	}
+
+	/* Disable digital and SERDES loopback */
+	writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN0);
+	writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN2);
+	writel(0, phy_regs + SGMII_PHY_LN_CDR_CTRL1);
+
+	/* Mask out all the SGMII Interrupt */
+	writel(0, phy_regs + EMAC_SGMII_PHY_INTERRUPT_MASK);
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
index 07c872a..d999d5d 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
@@ -161,20 +161,45 @@ void emac_sgmii_reset(struct emac_adapter *adpt)
 
 static int emac_sgmii_acpi_match(struct device *dev, void *data)
 {
+#ifdef CONFIG_ACPI
 	static const struct acpi_device_id match_table[] = {
 		{
 			.id = "QCOM8071",
-			.driver_data = (kernel_ulong_t)emac_sgmii_init_qdf2432,
 		},
 		{}
 	};
 	const struct acpi_device_id *id = acpi_match_device(match_table, dev);
 	emac_sgmii_initialize *initialize = data;
 
-	if (id)
-		*initialize = (emac_sgmii_initialize)id->driver_data;
+	if (id) {
+		acpi_handle handle = ACPI_HANDLE(dev);
+		unsigned long long hrv;
+		acpi_status status;
+
+		status = acpi_evaluate_integer(handle, "_HRV", NULL, &hrv);
+		if (status) {
+			if (status == AE_NOT_FOUND)
+				/* Older versions of the QDF2432 ACPI tables do
+				 * not have an _HRV property.
+				 */
+				hrv = 1;
+			else
+				/* Something is wrong with the tables */
+				return 0;
+		}
 
-	return !!id;
+		switch (hrv) {
+		case 1:
+			*initialize = emac_sgmii_init_qdf2432;
+			return 1;
+		case 2:
+			*initialize = emac_sgmii_init_qdf2400;
+			return 1;
+		}
+	}
+#endif
+
+	return 0;
 }
 
 static const struct of_device_id emac_sgmii_dt_match[] = {
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h
index e2bef14..80ed3dc 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h
@@ -21,5 +21,6 @@ void emac_sgmii_reset(struct emac_adapter *adpt);
 
 int emac_sgmii_init_fsm9900(struct emac_adapter *adpt);
 int emac_sgmii_init_qdf2432(struct emac_adapter *adpt);
+int emac_sgmii_init_qdf2400(struct emac_adapter *adpt);
 
 #endif
-- 
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc.  Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

^ permalink raw reply related

* [PATCH 0/2 v3] net: qcom/emac: simplify support for different SOCs
From: Timur Tabi @ 2016-12-08 19:24 UTC (permalink / raw)
  To: David Miller, netdev, alokc

On SOCs that have the Qualcomm EMAC network controller, the internal
PHY block is always different.  Sometimes the differences are small, 
sometimes it might be a completely different IP.  Either way, using version
numbers to differentiate them and putting all of the init code in one
file does not scale.

This patchset does two things:  The first breaks up the current code into
different files, and the second patch adds support for a third SOC, the
Qualcomm Technologies QDF2400 ARM Server SOC.

Timur Tabi (2):
  [v2] net: qcom/emac: move phy init code to separate files
  [v3] net: qcom/emac: add support for the Qualcomm Technologies QDF2400

 drivers/net/ethernet/qualcomm/emac/Makefile        |   4 +-
 .../ethernet/qualcomm/emac/emac-sgmii-fsm9900.c    | 245 +++++++++
 .../ethernet/qualcomm/emac/emac-sgmii-qdf2400.c    | 217 ++++++++
 .../ethernet/qualcomm/emac/emac-sgmii-qdf2432.c    | 210 ++++++++
 drivers/net/ethernet/qualcomm/emac/emac-sgmii.c    | 569 ++-------------------
 drivers/net/ethernet/qualcomm/emac/emac-sgmii.h    |   6 +-
 6 files changed, 725 insertions(+), 526 deletions(-)
 create mode 100644 drivers/net/ethernet/qualcomm/emac/emac-sgmii-fsm9900.c
 create mode 100644 drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c
 create mode 100644 drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c

-- 
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc.  Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

^ permalink raw reply

* Re: [PATCH v2 net-next 0/2] phy: lan78xx: add phy fixup unregister functions & LAN7801 update
From: David Miller @ 2016-12-08 19:22 UTC (permalink / raw)
  To: Woojung.Huh; +Cc: f.fainelli, andrew, netdev, UNGLinuxDriver
In-Reply-To: <9235D6609DB808459E95D78E17F2E43D4097998F@CHN-SV-EXMX02.mchp-main.com>

From: <Woojung.Huh@microchip.com>
Date: Wed, 7 Dec 2016 20:25:50 +0000

> V2 patch of adding phy fixup unregister function with use in LAN7801
> update.

Series applied, thanks.

^ permalink raw reply

* Re: [PATCH net-next] net: sock_rps_record_flow() is for connected sockets
From: Edward Cree @ 2016-12-08 19:20 UTC (permalink / raw)
  To: Paolo Abeni, Eric Dumazet
  Cc: David Miller, netdev, Willem de Bruijn, Tom Herbert,
	Jesper Dangaard Brouer
In-Reply-To: <1481097428.5535.12.camel@redhat.com>

On 07/12/16 07:57, Paolo Abeni wrote:
> We have some experimental patches to implement GRO for plain UDP
> connected sockets, using frag_list to preserve the individual skb len,
> and deliver the packet to user space individually. With that I got
> ~3mpps with a single queue/user space sink - before the recent udp
> improvements.
You might want to benchmark these against my batched receive patches
from a while ago[1], both seem to have broadly the same objective.
In my benchmarking (obviously with different hardware) I was using
multiple sink processes, but all (processes and irqs) on a single
core; the unpatched kernel was getting ~5Mpps.  Then with my patches
I was getting ~6.4Mpps.  (Limitations of my test scripts meant that
having a single sink process meant also having a single source
process, in which case I was TX limited to ~3Mpps, and using about
60% CPU on the RX side.)

Let me know if you're interested in doing this comparison; if so I'll
post updated patches against net-next.  My own attempts to benchmark
them more have been held up by lack of time and not really knowing
what constitutes a realistic netfilter setup.
Of course if you're using a device other than sfc you'll need to add
your own equivalent of patch #2 to call the netif_receive_skb_list()
entry point from the driver.

-Ed

[1] https://www.spinics.net/lists/netdev/msg373769.html

^ permalink raw reply

* Re: [PATCH 2/3] i40e: Add XDP_TX support
From: kbuild test robot @ 2016-12-08 19:20 UTC (permalink / raw)
  To: Björn Töpel
  Cc: kbuild-all, jeffrey.t.kirsher, intel-wired-lan,
	Björn Töpel, john.r.fastabend, magnus.karlsson, netdev
In-Reply-To: <20161208170022.11555-3-bjorn.topel@gmail.com>

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

Hi Björn,

[auto build test ERROR on next-20161208]
[cannot apply to jkirsher-next-queue/dev-queue v4.9-rc8 v4.9-rc7 v4.9-rc6 v4.9-rc8]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Bj-rn-T-pel/i40e-Support-for-XDP/20161209-013138
config: sparc64-allmodconfig (attached as .config)
compiler: sparc64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=sparc64 

All error/warnings (new ones prefixed by >>):

   In file included from include/linux/cache.h:4:0,
                    from include/linux/printk.h:8,
                    from include/linux/kernel.h:13,
                    from include/linux/list.h:8,
                    from include/linux/timer.h:4,
                    from include/linux/workqueue.h:8,
                    from include/linux/bpf.h:11,
                    from drivers/net/ethernet/intel/i40e/i40e_txrx.c:27:
   drivers/net/ethernet/intel/i40e/i40e_txrx.c: In function 'i40e_try_flip_rx_page':
>> drivers/net/ethernet/intel/i40e/i40e_txrx.c:1613:32: error: 'size' undeclared (first use in this function)
     unsigned int truesize = ALIGN(size, L1_CACHE_BYTES);
                                   ^
   include/uapi/linux/kernel.h:10:41: note: in definition of macro '__ALIGN_KERNEL_MASK'
    #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
                                            ^
   include/linux/kernel.h:49:22: note: in expansion of macro '__ALIGN_KERNEL'
    #define ALIGN(x, a)  __ALIGN_KERNEL((x), (a))
                         ^~~~~~~~~~~~~~
>> drivers/net/ethernet/intel/i40e/i40e_txrx.c:1613:26: note: in expansion of macro 'ALIGN'
     unsigned int truesize = ALIGN(size, L1_CACHE_BYTES);
                             ^~~~~
   drivers/net/ethernet/intel/i40e/i40e_txrx.c:1613:32: note: each undeclared identifier is reported only once for each function it appears in
     unsigned int truesize = ALIGN(size, L1_CACHE_BYTES);
                                   ^
   include/uapi/linux/kernel.h:10:41: note: in definition of macro '__ALIGN_KERNEL_MASK'
    #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
                                            ^
   include/linux/kernel.h:49:22: note: in expansion of macro '__ALIGN_KERNEL'
    #define ALIGN(x, a)  __ALIGN_KERNEL((x), (a))
                         ^~~~~~~~~~~~~~
>> drivers/net/ethernet/intel/i40e/i40e_txrx.c:1613:26: note: in expansion of macro 'ALIGN'
     unsigned int truesize = ALIGN(size, L1_CACHE_BYTES);
                             ^~~~~

vim +/size +1613 drivers/net/ethernet/intel/i40e/i40e_txrx.c

  1607	 */
  1608	static bool i40e_try_flip_rx_page(struct i40e_rx_buffer *rx_buffer)
  1609	{
  1610	#if (PAGE_SIZE < 8192)
  1611		unsigned int truesize = I40E_RXBUFFER_2048;
  1612	#else
> 1613		unsigned int truesize = ALIGN(size, L1_CACHE_BYTES);
  1614		unsigned int last_offset = PAGE_SIZE - I40E_RXBUFFER_2048;
  1615	#endif
  1616	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 48617 bytes --]

^ permalink raw reply

* Re: [patch] ser_gigaset: return -ENOMEM on error instead of success
From: David Miller @ 2016-12-08 19:19 UTC (permalink / raw)
  To: dan.carpenter
  Cc: pebolle, tilman, isdn, gigaset307x-common, netdev,
	kernel-janitors
In-Reply-To: <20161207112203.GC5507@elgon.mountain>

From: Dan Carpenter <dan.carpenter@oracle.com>
Date: Wed, 7 Dec 2016 14:22:03 +0300

> If we can't allocate the resources in gigaset_initdriver() then we
> should return -ENOMEM instead of zero.
> 
> Fixes: 2869b23e4b95 ("[PATCH] drivers/isdn/gigaset: new M101 driver (v2)")
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>

Applied and queued up for -stable, thanks.

^ permalink raw reply

* Re: [net-next PATCH v5 0/6] XDP for virtio_net
From: David Miller @ 2016-12-08 19:17 UTC (permalink / raw)
  To: john.fastabend
  Cc: daniel, mst, shm, tgraf, alexei.starovoitov, john.r.fastabend,
	netdev, brouer
In-Reply-To: <20161207200139.28121.4811.stgit@john-Precision-Tower-5810>

From: John Fastabend <john.fastabend@gmail.com>
Date: Wed, 07 Dec 2016 12:10:47 -0800

> This implements virtio_net for the mergeable buffers and big_packet
> modes. I tested this with vhost_net running on qemu and did not see
> any issues. For testing num_buf > 1 I added a hack to vhost driver
> to only but 100 bytes per buffer.
 ...

So where are we with this?

I'm not too thrilled with the idea of making XDP_TX optional or
something like that.  If someone enables XDP, there is a tradeoff.

I also have reservations about the idea to make jumbo frames work
without giving XDP access to the whole packet.  If it wants to push or
pop a header, it might need to know the whole packet length.  How will
you pass that to the XDP program?

Some kinds of encapsulation require trailers, thus preclusing access
to the entire packet precludes those kinds of transformations.

This is why we want simple, linear, buffer access for XDP.

Even the most seemingly minor exception turns into a huge complicated
mess.

^ permalink raw reply

* Re: [PATCH net-next] net: sock_rps_record_flow() is for connected sockets
From: Tom Herbert @ 2016-12-08 19:15 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Paolo Abeni, David Miller, netdev, Willem de Bruijn
In-Reply-To: <1481220136.4930.110.camel@edumazet-glaptop3.roam.corp.google.com>

On Thu, Dec 8, 2016 at 10:02 AM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> On Thu, 2016-12-08 at 09:49 -0800, Tom Herbert wrote:
>
>> Of course that would only help on systems where no one enable encaps,
>> ie. looks good in the the simple benchmarks but in real life if just
>> one socket enables encap everyone else takes the hit. Alternatively,
>> maybe we could do early demux when we do the lookup in GRO to
>> eliminate the extra lookup?
>
> Well, if you do the lookup in GRO, wont it be done for every incoming
> MSS, instead of once per GRO packet ?

We should be able to avoid that. We already do the lookup for every
UDP packet going into GRO, would only need to take the refcnt once for
the whole GRO packet.

>
> Anyway, the flooded UDP sockets out there are not normally connected

We still should be able to use early demux in that case, just can't
avoid the route lookup. I wonder if we might be able to cache a soft
route maybe for the last local destination received to help the
unconnected sockets case...

In any case, I can take a look at of doing early demux from with UDP GRO.

Tom

> ones.
>
>
>

^ permalink raw reply

* Re: [PATCH 3/6] net: ethernet: ti: cpts: add support of cpts HW_TS_PUSH
From: Grygorii Strashko @ 2016-12-08 19:04 UTC (permalink / raw)
  To: Richard Cochran
  Cc: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
	Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok
In-Reply-To: <20161203232130.GA17944@netboy>



On 12/03/2016 05:21 PM, Richard Cochran wrote:
> On Mon, Nov 28, 2016 at 05:04:25PM -0600, Grygorii Strashko wrote:
>> This also change overflow polling period when HW_TS_PUSH feature is
>> enabled - overflow check work will be scheduled more often (every
>> 200ms) for proper HW_TS_PUSH events reporting.
> 
> For proper reporting, you should make use of the interrupt.  The small
> fifo (16 iirc) could very well overflow in 200 ms.  The interrupt
> handler should read out the entire fifo at each interrupt.
> 

huh. Seems this is not really good idea, because MISC Irq will be 
triggered for *any* CPTS event and there is no way to enable it just for
HW_TS_PUSH. So, this doesn't work will with current code for RX/TX timestamping
(which uses polling mode). + runtime overhead in net RX/TX caused by 
triggering more interrupts. 

May be, overflow check/polling timeout can be made configurable (module parameter). 

-- 
regards,
-grygorii
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ 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