Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH RFC] Update documentation for KSZ DSA drivers so that new drivers can be added
From: Pavel Machek @ 2017-09-08 21:53 UTC (permalink / raw)
  To: Tristram.Ha
  Cc: andrew, muvarov, nathan.leigh.conrad, vivien.didelot, f.fainelli,
	netdev, linux-kernel, Woojung.Huh
In-Reply-To: <93AF473E2DA327428DE3D46B72B1E9FD41121E68@CHN-SV-EXMX02.mchp-main.com>

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

Hi!

> There will be 5 drivers to support these devices:
> 
> ksz9477.c - KSZ9893/KSZ9897/KSZ9567/KSZ9566/KSZ9477
> ksz8795.c - KSZ8795/KSZ8795/KSZ8765
> ksz8895.c - KSZ8895/KSZ8864

Could we see the 8895 driver, please?

> Out of topic I have a question to ask the community regarding the DSA
> port creation:
> 
> Port 1 can be specified using the reg parameter specifying 0; port 2, 1;
> and so on.  The KSZ8794 is a variant of KSZ8795 with port 4 disabled.
> So
> lan1 = 0, lan2 = 1, lan3 = 2, cpu = 4.
> But our company Marketing does not want to promote that fact but treat
> KSZ8794 as a distinct product.
> So
> lan1 = 0, lan2 = 1, lan3 = 2, cpu = 3.
> Is this okay to hide this information inside the driver?  This is manageable
> for KSZ8794 but for KSZ8864 the first port is disabled:
> lan1 = 1, lan2 = 2, lan3 = 3, cpu = 4.
> 
> I am not sure whether DSA has or will have a way to display the port
> mapping to regular users.

Kernel is not a place to play marketing games, and people reading the
kernel sources are not targets of your marketing department.

Please let us just see the underlying hardware, as is.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply

* [PATCH iproute2 3/3] bridge: request vlans along with link information
From: Roman Mashak @ 2017-09-08 21:52 UTC (permalink / raw)
  To: stephen; +Cc: netdev, jhs, Roman Mashak
In-Reply-To: <1504907543-14394-1-git-send-email-mrv@mojatatu.com>

Signed-off-by: Roman Mashak <mrv@mojatatu.com>
---
 bridge/link.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/bridge/link.c b/bridge/link.c
index 60200f1..9e4206f 100644
--- a/bridge/link.c
+++ b/bridge/link.c
@@ -461,9 +461,19 @@ static int brlink_show(int argc, char **argv)
 		}
 	}
 
-	if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) {
-		perror("Cannon send dump request");
-		exit(1);
+	if (show_details) {
+		if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
+					     (compress_vlans ?
+					      RTEXT_FILTER_BRVLAN_COMPRESSED :
+					      RTEXT_FILTER_BRVLAN)) < 0) {
+			perror("Cannon send dump request");
+			exit(1);
+		}
+	} else {
+		if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) {
+			perror("Cannon send dump request");
+			exit(1);
+		}
 	}
 
 	if (rtnl_dump_filter(&rth, print_linkinfo, stdout) < 0) {
-- 
1.9.1

^ permalink raw reply related

* [PATCH iproute2 2/3] bridge: dump vlan table information for link
From: Roman Mashak @ 2017-09-08 21:52 UTC (permalink / raw)
  To: stephen; +Cc: netdev, jhs, Roman Mashak
In-Reply-To: <1504907543-14394-1-git-send-email-mrv@mojatatu.com>

Kernel also reports vlans a port is member of, so print it. Since vlan
table can be quite large, dump it only when detailed information is
requested.

Signed-off-by: Roman Mashak <mrv@mojatatu.com>
---
 bridge/link.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/bridge/link.c b/bridge/link.c
index 93472ad..60200f1 100644
--- a/bridge/link.c
+++ b/bridge/link.c
@@ -213,6 +213,13 @@ int print_linkinfo(const struct sockaddr_nl *who,
 
 		if (aftb[IFLA_BRIDGE_MODE])
 			print_hwmode(fp, rta_getattr_u16(aftb[IFLA_BRIDGE_MODE]));
+		if (show_details) {
+			if (aftb[IFLA_BRIDGE_VLAN_INFO]) {
+				fprintf(fp, "\n");
+				print_vlan_info(fp, tb[IFLA_AF_SPEC],
+						ifi->ifi_index);
+			}
+		}
 	}
 
 	fprintf(fp, "\n");
-- 
1.9.1

^ permalink raw reply related

* [PATCH iproute2 1/3] bridge: isolate vlans  parsing code in a separate API
From: Roman Mashak @ 2017-09-08 21:52 UTC (permalink / raw)
  To: stephen; +Cc: netdev, jhs, Roman Mashak
In-Reply-To: <1504907543-14394-1-git-send-email-mrv@mojatatu.com>

IFLA_BRIDGE_VLAN_INFO parsing logic will be used in link and vlan
processing code, so it makes sense to move it in the separate function.

Signed-off-by: Roman Mashak <mrv@mojatatu.com>
---
 bridge/br_common.h |   1 +
 bridge/vlan.c      | 145 +++++++++++++++++++++++++++--------------------------
 2 files changed, 76 insertions(+), 70 deletions(-)

diff --git a/bridge/br_common.h b/bridge/br_common.h
index c649e7d..01447dd 100644
--- a/bridge/br_common.h
+++ b/bridge/br_common.h
@@ -4,6 +4,7 @@
 #define MDB_RTR_RTA(r) \
 		((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(__u32))))
 
+extern void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex);
 extern int print_linkinfo(const struct sockaddr_nl *who,
 			  struct nlmsghdr *n,
 			  void *arg);
diff --git a/bridge/vlan.c b/bridge/vlan.c
index ebcdace..fc361ae 100644
--- a/bridge/vlan.c
+++ b/bridge/vlan.c
@@ -189,7 +189,6 @@ static int print_vlan(const struct sockaddr_nl *who,
 	struct ifinfomsg *ifm = NLMSG_DATA(n);
 	int len = n->nlmsg_len;
 	struct rtattr *tb[IFLA_MAX+1];
-	bool vlan_flags = false;
 
 	if (n->nlmsg_type != RTM_NEWLINK) {
 		fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n",
@@ -218,75 +217,7 @@ static int print_vlan(const struct sockaddr_nl *who,
 				ll_index_to_name(ifm->ifi_index));
 		return 0;
 	} else {
-		struct rtattr *i, *list = tb[IFLA_AF_SPEC];
-		int rem = RTA_PAYLOAD(list);
-		__u16 last_vid_start = 0;
-
-		if (!filter_vlan)
-			print_vlan_port(fp, ifm->ifi_index);
-
-		for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
-			struct bridge_vlan_info *vinfo;
-			int vcheck_ret;
-
-			if (i->rta_type != IFLA_BRIDGE_VLAN_INFO)
-				continue;
-
-			vinfo = RTA_DATA(i);
-
-			if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
-				last_vid_start = vinfo->vid;
-			vcheck_ret = filter_vlan_check(vinfo);
-			if (vcheck_ret == -1)
-				break;
-			else if (vcheck_ret == 0)
-				continue;
-
-			if (filter_vlan)
-				print_vlan_port(fp, ifm->ifi_index);
-			if (jw_global) {
-				jsonw_start_object(jw_global);
-				jsonw_uint_field(jw_global, "vlan",
-						 last_vid_start);
-				if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
-					continue;
-			} else {
-				fprintf(fp, "\t %hu", last_vid_start);
-			}
-			if (last_vid_start != vinfo->vid) {
-				if (jw_global)
-					jsonw_uint_field(jw_global, "vlanEnd",
-							 vinfo->vid);
-				else
-					fprintf(fp, "-%hu", vinfo->vid);
-			}
-			if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) {
-				if (jw_global) {
-					start_json_vlan_flags_array(&vlan_flags);
-					jsonw_string(jw_global, "PVID");
-				} else {
-					fprintf(fp, " PVID");
-				}
-			}
-			if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) {
-				if (jw_global) {
-					start_json_vlan_flags_array(&vlan_flags);
-					jsonw_string(jw_global,
-						     "Egress Untagged");
-				} else {
-					fprintf(fp, " Egress Untagged");
-				}
-			}
-			if (jw_global && vlan_flags) {
-				jsonw_end_array(jw_global);
-				vlan_flags = false;
-			}
-
-			if (jw_global)
-				jsonw_end_object(jw_global);
-			else
-				fprintf(fp, "\n");
-		}
+		print_vlan_info(fp, tb[IFLA_AF_SPEC], ifm->ifi_index);
 	}
 	if (!filter_vlan) {
 		if (jw_global)
@@ -470,6 +401,80 @@ static int vlan_show(int argc, char **argv)
 	return 0;
 }
 
+void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex)
+{
+	struct rtattr *i, *list = tb;
+	int rem = RTA_PAYLOAD(list);
+	__u16 last_vid_start = 0;
+	bool vlan_flags = false;
+
+	if (!filter_vlan)
+		print_vlan_port(fp, ifindex);
+
+	for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+		struct bridge_vlan_info *vinfo;
+		int vcheck_ret;
+
+		if (i->rta_type != IFLA_BRIDGE_VLAN_INFO)
+			continue;
+
+		vinfo = RTA_DATA(i);
+
+		if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
+			last_vid_start = vinfo->vid;
+		vcheck_ret = filter_vlan_check(vinfo);
+		if (vcheck_ret == -1)
+			break;
+		else if (vcheck_ret == 0)
+			continue;
+
+		if (filter_vlan)
+			print_vlan_port(fp, ifindex);
+		if (jw_global) {
+			jsonw_start_object(jw_global);
+			jsonw_uint_field(jw_global, "vlan",
+					 last_vid_start);
+			if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
+				continue;
+		} else {
+			fprintf(fp, "\t %hu", last_vid_start);
+		}
+		if (last_vid_start != vinfo->vid) {
+			if (jw_global)
+				jsonw_uint_field(jw_global, "vlanEnd",
+						 vinfo->vid);
+			else
+				fprintf(fp, "-%hu", vinfo->vid);
+		}
+		if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) {
+			if (jw_global) {
+				start_json_vlan_flags_array(&vlan_flags);
+				jsonw_string(jw_global, "PVID");
+			} else {
+				fprintf(fp, " PVID");
+			}
+		}
+		if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) {
+			if (jw_global) {
+				start_json_vlan_flags_array(&vlan_flags);
+				jsonw_string(jw_global,
+					     "Egress Untagged");
+			} else {
+				fprintf(fp, " Egress Untagged");
+			}
+		}
+		if (jw_global && vlan_flags) {
+			jsonw_end_array(jw_global);
+			vlan_flags = false;
+		}
+
+		if (jw_global)
+			jsonw_end_object(jw_global);
+		else
+			fprintf(fp, "\n");
+	}
+}
+
 int do_vlan(int argc, char **argv)
 {
 	ll_init_map(&rth);
-- 
1.9.1

^ permalink raw reply related

* [PATCH iproute2 0/3] Process IFLA_BRIDGE_VLAN_INFO tlv
From: Roman Mashak @ 2017-09-08 21:52 UTC (permalink / raw)
  To: stephen; +Cc: netdev, jhs, Roman Mashak

Process IFLA_BRIDGE_VLAN_INFO attribute nested in IFLA_AF_SPEC, which
contains bridge vlan table per port passed in link events.

Roman Mashak (3):
  bridge: isolate vlans  parsing code in a separate API
  bridge: dump vlan table information for link
  bridge: request vlans along with link information

 bridge/br_common.h |   1 +
 bridge/link.c      |  23 +++++++--
 bridge/vlan.c      | 145 +++++++++++++++++++++++++++--------------------------
 3 files changed, 96 insertions(+), 73 deletions(-)

-- 
1.9.1

^ permalink raw reply

* Re: [PATCH RFC] Update documentation for KSZ DSA drivers so that new drivers can be added
From: Pavel Machek @ 2017-09-08 21:50 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Tristram.Ha, muvarov, nathan.leigh.conrad, vivien.didelot,
	f.fainelli, netdev, linux-kernel, Woojung.Huh
In-Reply-To: <20170908190122.GM25219@lunn.ch>

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

On Fri 2017-09-08 21:01:22, Andrew Lunn wrote:
> > > So i would suggest one driver supporting all the different devices.
> > 
> > There will be 5 drivers to support these devices:
> > 
> > ksz9477.c - KSZ9893/KSZ9897/KSZ9567/KSZ9566/KSZ9477
> > ksz8795.c - KSZ8795/KSZ8795/KSZ8765
> > ksz8895.c - KSZ8895/KSZ8864
> > ksz8863.c - KSZ8863/KSZ8873
> > ksz8463.c - KSZ8463
> > 
> > These chips have different SPI access mechanisms, MIB counter reading,
> > and register set.  These can be combined into one single driver using
> > function pointers, at least for ksz8795/ksz8895/ksz8863/ksz8463.  My
> > only concern is the memory footprint.  The customer may not want a
> > big driver to cover all the switches while only one is used.
> 
> If memory footprint is your problem, make it a compile time choice
> which devices are supported within the one driver. In practice, you
> will find most distributions just enable them all.

I have to side with Tristram here. The register layouts are so
different that single driver does not make sense.

What could make sense is single function, compiled 5 times, based on
different includes; same source code but 5 different binaries.

									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply

* Re: [PATCH v2 0/2] enable hires timer to timeout datagram socket
From: David Miller @ 2017-09-08 21:44 UTC (permalink / raw)
  To: eduval
  Cc: dwmw2, vallish, shuah, richardcochran, xiyou.wangcong, netdev,
	linux-kernel, anchalag, dwmw
In-Reply-To: <20170908185521.GA12340@u40b0340c692b58f6553c.ant.amazon.com>

From: Eduardo Valentin <eduval@amazon.com>
Date: Fri, 8 Sep 2017 11:55:21 -0700

> I agree. I would prefer to understand here what is the technical
> reason not to accept these patches other than "use other system
> calls".

I explained this, let me reiterate:

====================
And most importantly, letting the kernel have flexibility in this area
is absolutely essential for various forms of optimizations and power
savings.
====================

^ permalink raw reply

* Re: [PATCH iproute2] tc: fq: support low_rate_threshold attribute
From: Soheil Hassas Yeganeh @ 2017-09-08 21:16 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Stephen Hemminger, netdev, Neal Cardwell, Soheil Hassas Yeganeh
In-Reply-To: <1504905179.15310.101.camel@edumazet-glaptop3.roam.corp.google.com>

On Fri, Sep 8, 2017 at 5:12 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> TCA_FQ_LOW_RATE_THRESHOLD sch_fq attribute was added in linux-4.9
>
> Tested:
>
> lpaa5:/tmp# tc -qd add dev eth1 root fq
> lpaa5:/tmp# tc -s qd sh dev eth1
> qdisc fq 8003: root refcnt 5 limit 10000p flow_limit 1000p buckets 4096 \
>  orphan_mask 4095 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 quantum 3648 \
>  initial_quantum 18240 low_rate_threshold 550Kbit refill_delay 40.0ms
>  Sent 62139 bytes 395 pkt (dropped 0, overlimits 0 requeues 0)
>  backlog 0b 0p requeues 0
>   116 flows (114 inactive, 0 throttled)
>   1 gc, 0 highprio, 0 throttled
>
> lpaa5:/tmp# ./netperf -H lpaa6 -t TCP_RR -l10 -- -q 500000 -r 300,300 -o P99_LATENCY
> 99th Percentile Latency Microseconds
> 7081
>
> lpaa5:/tmp# tc qd replace dev eth1 root fq low_rate_threshold 10Mbit
> lpaa5:/tmp# ./netperf -H lpaa6 -t TCP_RR -l10 -- -q 500000 -r 300,300 -o P99_LATENCY
> 99th Percentile Latency Microseconds
> 858
>
>
> Signed-off-by: Eric Dumazet <edumazet@google.com>

Acked-by: Soheil Hassas Yeganeh <soheil@google.com>

Thank you, Eric!

^ permalink raw reply

* [PATCH iproute2] tc: fq: support low_rate_threshold attribute
From: Eric Dumazet @ 2017-09-08 21:12 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, Neal Cardwell, Soheil Hassas Yeganeh

From: Eric Dumazet <edumazet@google.com>

TCA_FQ_LOW_RATE_THRESHOLD sch_fq attribute was added in linux-4.9

Tested:

lpaa5:/tmp# tc -qd add dev eth1 root fq
lpaa5:/tmp# tc -s qd sh dev eth1
qdisc fq 8003: root refcnt 5 limit 10000p flow_limit 1000p buckets 4096 \
 orphan_mask 4095 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 quantum 3648 \
 initial_quantum 18240 low_rate_threshold 550Kbit refill_delay 40.0ms
 Sent 62139 bytes 395 pkt (dropped 0, overlimits 0 requeues 0)
 backlog 0b 0p requeues 0
  116 flows (114 inactive, 0 throttled)
  1 gc, 0 highprio, 0 throttled
    
lpaa5:/tmp# ./netperf -H lpaa6 -t TCP_RR -l10 -- -q 500000 -r 300,300 -o P99_LATENCY
99th Percentile Latency Microseconds
7081
    
lpaa5:/tmp# tc qd replace dev eth1 root fq low_rate_threshold 10Mbit
lpaa5:/tmp# ./netperf -H lpaa6 -t TCP_RR -l10 -- -q 500000 -r 300,300 -o P99_LATENCY
99th Percentile Latency Microseconds
858


Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 tc/q_fq.c |   20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/tc/q_fq.c b/tc/q_fq.c
index c9efbfc4..45b2ffd9 100644
--- a/tc/q_fq.c
+++ b/tc/q_fq.c
@@ -55,6 +55,7 @@ static void explain(void)
 	fprintf(stderr, "              [ quantum BYTES ] [ initial_quantum BYTES ]\n");
 	fprintf(stderr, "              [ maxrate RATE  ] [ buckets NUMBER ]\n");
 	fprintf(stderr, "              [ [no]pacing ] [ refill_delay TIME ]\n");
+	fprintf(stderr, "              [ low_rate_threshold RATE ]\n");
 	fprintf(stderr, "              [ orphan_mask MASK]\n");
 }
 
@@ -79,6 +80,7 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
 	unsigned int initial_quantum;
 	unsigned int buckets = 0;
 	unsigned int maxrate;
+	unsigned int low_rate_threshold;
 	unsigned int defrate;
 	unsigned int refill_delay;
 	unsigned int orphan_mask;
@@ -90,6 +92,7 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
 	bool set_defrate = false;
 	bool set_refill_delay = false;
 	bool set_orphan_mask = false;
+	bool set_low_rate_threshold = false;
 	int pacing = -1;
 	struct rtattr *tail;
 
@@ -121,6 +124,13 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
 				return -1;
 			}
 			set_maxrate = true;
+		} else if (strcmp(*argv, "low_rate_threshold") == 0) {
+			NEXT_ARG();
+			if (get_rate(&low_rate_threshold, *argv)) {
+				fprintf(stderr, "Illegal \"low_rate_threshold\"\n");
+				return -1;
+			}
+			set_low_rate_threshold = true;
 		} else if (strcmp(*argv, "defrate") == 0) {
 			NEXT_ARG();
 			if (get_rate(&defrate, *argv)) {
@@ -196,6 +206,9 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
 	if (set_maxrate)
 		addattr_l(n, 1024, TCA_FQ_FLOW_MAX_RATE,
 			  &maxrate, sizeof(maxrate));
+	if (set_low_rate_threshold)
+		addattr_l(n, 1024, TCA_FQ_LOW_RATE_THRESHOLD,
+			  &low_rate_threshold, sizeof(low_rate_threshold));
 	if (set_defrate)
 		addattr_l(n, 1024, TCA_FQ_FLOW_DEFAULT_RATE,
 			  &defrate, sizeof(defrate));
@@ -276,6 +289,13 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 		if (rate != 0)
 			fprintf(f, "defrate %s ", sprint_rate(rate, b1));
 	}
+	if (tb[TCA_FQ_LOW_RATE_THRESHOLD] &&
+	    RTA_PAYLOAD(tb[TCA_FQ_LOW_RATE_THRESHOLD]) >= sizeof(__u32)) {
+		rate = rta_getattr_u32(tb[TCA_FQ_LOW_RATE_THRESHOLD]);
+
+		if (rate != 0)
+			fprintf(f, "low_rate_threshold %s ", sprint_rate(rate, b1));
+	}
 	if (tb[TCA_FQ_FLOW_REFILL_DELAY] &&
 	    RTA_PAYLOAD(tb[TCA_FQ_FLOW_REFILL_DELAY]) >= sizeof(__u32)) {
 		refill_delay = rta_getattr_u32(tb[TCA_FQ_FLOW_REFILL_DELAY]);

^ permalink raw reply related

* [net PATCH 3/3] bpf: devmap, use cond_resched instead of cpu_relax
From: John Fastabend @ 2017-09-08 21:01 UTC (permalink / raw)
  To: davem; +Cc: netdev, john.fastabend, daniel, ast
In-Reply-To: <150490397545.11590.1409723973253492363.stgit@john-XPS-13-9360>

Be a bit more friendly about waiting for flush bits to complete.
Replace the cpu_relax() with a cond_resched().

Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
 kernel/bpf/devmap.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index ecf9f99..959c9a0 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -159,7 +159,7 @@ static void dev_map_free(struct bpf_map *map)
 		unsigned long *bitmap = per_cpu_ptr(dtab->flush_needed, cpu);
 
 		while (!bitmap_empty(bitmap, dtab->map.max_entries))
-			cpu_relax();
+			cond_resched();
 	}
 
 	for (i = 0; i < dtab->map.max_entries; i++) {

^ permalink raw reply related

* [net PATCH 2/3] bpf: add support for sockmap detach programs
From: John Fastabend @ 2017-09-08 21:00 UTC (permalink / raw)
  To: davem; +Cc: netdev, john.fastabend, daniel, ast
In-Reply-To: <150490397545.11590.1409723973253492363.stgit@john-XPS-13-9360>

The bpf map sockmap supports adding programs via attach commands. This
patch adds the detach command to keep the API symmetric and allow
users to remove previously added programs. Otherwise the user would
have to delete the map and re-add it to get in this state.

This also adds a series of additional tests to capture detach operation
and also attaching/detaching invalid prog types.

API note: socks will run (or not run) programs depending on the state
of the map at the time the sock is added. We do not for example walk
the map and remove programs from previously attached socks.

Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
 include/linux/bpf.h                     |    8 ++---
 kernel/bpf/sockmap.c                    |    2 +
 kernel/bpf/syscall.c                    |   27 ++++++++++------
 tools/testing/selftests/bpf/test_maps.c |   51 ++++++++++++++++++++++++++++++-
 4 files changed, 72 insertions(+), 16 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index c2cb1b5..8390859 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -385,16 +385,16 @@ static inline void __dev_map_flush(struct bpf_map *map)
 
 #if defined(CONFIG_STREAM_PARSER) && defined(CONFIG_BPF_SYSCALL)
 struct sock  *__sock_map_lookup_elem(struct bpf_map *map, u32 key);
-int sock_map_attach_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type);
+int sock_map_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type);
 #else
 static inline struct sock  *__sock_map_lookup_elem(struct bpf_map *map, u32 key)
 {
 	return NULL;
 }
 
-static inline int sock_map_attach_prog(struct bpf_map *map,
-				       struct bpf_prog *prog,
-				       u32 type)
+static inline int sock_map_prog(struct bpf_map *map,
+				struct bpf_prog *prog,
+				u32 type)
 {
 	return -EOPNOTSUPP;
 }
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c
index f6ffde9..6424ce0 100644
--- a/kernel/bpf/sockmap.c
+++ b/kernel/bpf/sockmap.c
@@ -792,7 +792,7 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
 	return err;
 }
 
-int sock_map_attach_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type)
+int sock_map_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type)
 {
 	struct bpf_stab *stab = container_of(map, struct bpf_stab, map);
 	struct bpf_prog *orig;
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 70ad8e2..cb17e1c 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -1096,10 +1096,10 @@ static int bpf_obj_get(const union bpf_attr *attr)
 
 #define BPF_PROG_ATTACH_LAST_FIELD attach_flags
 
-static int sockmap_get_from_fd(const union bpf_attr *attr)
+static int sockmap_get_from_fd(const union bpf_attr *attr, bool attach)
 {
+	struct bpf_prog *prog = NULL;
 	int ufd = attr->target_fd;
-	struct bpf_prog *prog;
 	struct bpf_map *map;
 	struct fd f;
 	int err;
@@ -1109,16 +1109,20 @@ static int sockmap_get_from_fd(const union bpf_attr *attr)
 	if (IS_ERR(map))
 		return PTR_ERR(map);
 
-	prog = bpf_prog_get_type(attr->attach_bpf_fd, BPF_PROG_TYPE_SK_SKB);
-	if (IS_ERR(prog)) {
-		fdput(f);
-		return PTR_ERR(prog);
+	if (attach) {
+		prog = bpf_prog_get_type(attr->attach_bpf_fd,
+					 BPF_PROG_TYPE_SK_SKB);
+		if (IS_ERR(prog)) {
+			fdput(f);
+			return PTR_ERR(prog);
+		}
 	}
 
-	err = sock_map_attach_prog(map, prog, attr->attach_type);
+	err = sock_map_prog(map, prog, attr->attach_type);
 	if (err) {
 		fdput(f);
-		bpf_prog_put(prog);
+		if (prog)
+			bpf_prog_put(prog);
 		return err;
 	}
 
@@ -1155,7 +1159,7 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 		break;
 	case BPF_SK_SKB_STREAM_PARSER:
 	case BPF_SK_SKB_STREAM_VERDICT:
-		return sockmap_get_from_fd(attr);
+		return sockmap_get_from_fd(attr, true);
 	default:
 		return -EINVAL;
 	}
@@ -1204,7 +1208,10 @@ static int bpf_prog_detach(const union bpf_attr *attr)
 		ret = cgroup_bpf_update(cgrp, NULL, attr->attach_type, false);
 		cgroup_put(cgrp);
 		break;
-
+	case BPF_SK_SKB_STREAM_PARSER:
+	case BPF_SK_SKB_STREAM_VERDICT:
+		ret = sockmap_get_from_fd(attr, false);
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c
index 4acc772..fe3a443 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -558,7 +558,7 @@ static void test_sockmap(int tasks, void *data)
 		}
 	}
 
-	/* Test attaching bad fds */
+	/* Test attaching/detaching bad fds */
 	err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_PARSER, 0);
 	if (!err) {
 		printf("Failed invalid parser prog attach\n");
@@ -571,6 +571,30 @@ static void test_sockmap(int tasks, void *data)
 		goto out_sockmap;
 	}
 
+	err = bpf_prog_attach(-1, fd, __MAX_BPF_ATTACH_TYPE, 0);
+	if (!err) {
+		printf("Failed unknown prog attach\n");
+		goto out_sockmap;
+	}
+
+	err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_PARSER);
+	if (err) {
+		printf("Failed empty parser prog detach\n");
+		goto out_sockmap;
+	}
+
+	err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_VERDICT);
+	if (err) {
+		printf("Failed empty verdict prog detach\n");
+		goto out_sockmap;
+	}
+
+	err = bpf_prog_detach(fd, __MAX_BPF_ATTACH_TYPE);
+	if (!err) {
+		printf("Detach invalid prog successful\n");
+		goto out_sockmap;
+	}
+
 	/* Load SK_SKB program and Attach */
 	err = bpf_prog_load(SOCKMAP_PARSE_PROG,
 			    BPF_PROG_TYPE_SK_SKB, &obj, &parse_prog);
@@ -643,6 +667,13 @@ static void test_sockmap(int tasks, void *data)
 		goto out_sockmap;
 	}
 
+	err = bpf_prog_attach(verdict_prog, map_fd_rx,
+			      __MAX_BPF_ATTACH_TYPE, 0);
+	if (!err) {
+		printf("Attached unknown bpf prog\n");
+		goto out_sockmap;
+	}
+
 	/* Test map update elem afterwards fd lives in fd and map_fd */
 	for (i = 0; i < 6; i++) {
 		err = bpf_map_update_elem(map_fd_rx, &i, &sfd[i], BPF_ANY);
@@ -809,6 +840,24 @@ static void test_sockmap(int tasks, void *data)
 		assert(status == 0);
 	}
 
+	err = bpf_prog_detach(map_fd_rx, __MAX_BPF_ATTACH_TYPE);
+	if (!err) {
+		printf("Detached an invalid prog type.\n");
+		goto out_sockmap;
+	}
+
+	err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_PARSER);
+	if (err) {
+		printf("Failed parser prog detach\n");
+		goto out_sockmap;
+	}
+
+	err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_VERDICT);
+	if (err) {
+		printf("Failed parser prog detach\n");
+		goto out_sockmap;
+	}
+
 	/* Test map close sockets */
 	for (i = 0; i < 6; i++)
 		close(sfd[i]);

^ permalink raw reply related

* [net PATCH 1/3] net: rcu lock and preempt disable missing around generic xdp
From: John Fastabend @ 2017-09-08 21:00 UTC (permalink / raw)
  To: davem; +Cc: netdev, john.fastabend, daniel, ast
In-Reply-To: <150490397545.11590.1409723973253492363.stgit@john-XPS-13-9360>

do_xdp_generic must be called inside rcu critical section with preempt
disabled to ensure BPF programs are valid and per-cpu variables used
for redirect operations are consistent. This patch ensures this is true
and fixes the splat below.

The netif_receive_skb_internal() code path is now broken into two rcu
critical sections. I decided it was better to limit the preempt_enable/disable
block to just the xdp static key portion and the fallout is more
rcu_read_lock/unlock calls. Seems like the best option to me.

[  607.596901] =============================
[  607.596906] WARNING: suspicious RCU usage
[  607.596912] 4.13.0-rc4+ #570 Not tainted
[  607.596917] -----------------------------
[  607.596923] net/core/dev.c:3948 suspicious rcu_dereference_check() usage!
[  607.596927]
[  607.596927] other info that might help us debug this:
[  607.596927]
[  607.596933]
[  607.596933] rcu_scheduler_active = 2, debug_locks = 1
[  607.596938] 2 locks held by pool/14624:
[  607.596943]  #0:  (rcu_read_lock_bh){......}, at: [<ffffffff95445ffd>] ip_finish_output2+0x14d/0x890
[  607.596973]  #1:  (rcu_read_lock_bh){......}, at: [<ffffffff953c8e3a>] __dev_queue_xmit+0x14a/0xfd0
[  607.597000]
[  607.597000] stack backtrace:
[  607.597006] CPU: 5 PID: 14624 Comm: pool Not tainted 4.13.0-rc4+ #570
[  607.597011] Hardware name: Dell Inc. Precision Tower 5810/0HHV7N, BIOS A17 03/01/2017
[  607.597016] Call Trace:
[  607.597027]  dump_stack+0x67/0x92
[  607.597040]  lockdep_rcu_suspicious+0xdd/0x110
[  607.597054]  do_xdp_generic+0x313/0xa50
[  607.597068]  ? time_hardirqs_on+0x5b/0x150
[  607.597076]  ? mark_held_locks+0x6b/0xc0
[  607.597088]  ? netdev_pick_tx+0x150/0x150
[  607.597117]  netif_rx_internal+0x205/0x3f0
[  607.597127]  ? do_xdp_generic+0xa50/0xa50
[  607.597144]  ? lock_downgrade+0x2b0/0x2b0
[  607.597158]  ? __lock_is_held+0x93/0x100
[  607.597187]  netif_rx+0x119/0x190
[  607.597202]  loopback_xmit+0xfd/0x1b0
[  607.597214]  dev_hard_start_xmit+0x127/0x4e0

Fixes: d445516966dc ("net: xdp: support xdp generic on virtual devices")
Fixes: b5cdae3291f7 ("net: Generic XDP")
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
 net/core/dev.c |   25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index 6f845e4..fb766d9 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3981,8 +3981,13 @@ static int netif_rx_internal(struct sk_buff *skb)
 	trace_netif_rx(skb);
 
 	if (static_key_false(&generic_xdp_needed)) {
-		int ret = do_xdp_generic(rcu_dereference(skb->dev->xdp_prog),
-					 skb);
+		int ret;
+
+		preempt_disable();
+		rcu_read_lock();
+		ret = do_xdp_generic(rcu_dereference(skb->dev->xdp_prog), skb);
+		rcu_read_unlock();
+		preempt_enable();
 
 		/* Consider XDP consuming the packet a success from
 		 * the netdev point of view we do not want to count
@@ -4500,18 +4505,20 @@ static int netif_receive_skb_internal(struct sk_buff *skb)
 	if (skb_defer_rx_timestamp(skb))
 		return NET_RX_SUCCESS;
 
-	rcu_read_lock();
-
 	if (static_key_false(&generic_xdp_needed)) {
-		int ret = do_xdp_generic(rcu_dereference(skb->dev->xdp_prog),
-					 skb);
+		int ret;
 
-		if (ret != XDP_PASS) {
-			rcu_read_unlock();
+		preempt_disable();
+		rcu_read_lock();
+		ret = do_xdp_generic(rcu_dereference(skb->dev->xdp_prog), skb);
+		rcu_read_unlock();
+		preempt_enable();
+
+		if (ret != XDP_PASS)
 			return NET_RX_DROP;
-		}
 	}
 
+	rcu_read_lock();
 #ifdef CONFIG_RPS
 	if (static_key_false(&rps_needed)) {
 		struct rps_dev_flow voidflow, *rflow = &voidflow;

^ permalink raw reply related

* [net PATCH 0/3] Fixes for XDP/BPF
From: John Fastabend @ 2017-09-08 21:00 UTC (permalink / raw)
  To: davem; +Cc: netdev, john.fastabend, daniel, ast

The following fixes, UAPI updates, and small improvement,

i. XDP needs to be called inside RCU with preempt disabled.

ii. Not strictly a bug fix but we have an attach command in the
sockmap UAPI already to avoid having a single kernel released with
only the attach and not the detach I'm pushing this into net branch.
Its early in the RC cycle so I think this is OK (not ideal but better
than supporting a UAPI with a missing detach forever).

iii. Final patch replace cpu_relax with cond_resched in devmap.

---

John Fastabend (3):
      net: rcu lock and preempt disable missing around generic xdp
      bpf: add support for sockmap detach programs
      bpf: devmap, use cond_resched instead of cpu_relax


 include/linux/bpf.h                     |    8 ++---
 kernel/bpf/devmap.c                     |    2 +
 kernel/bpf/sockmap.c                    |    2 +
 kernel/bpf/syscall.c                    |   27 ++++++++++------
 net/core/dev.c                          |   25 ++++++++++-----
 tools/testing/selftests/bpf/test_maps.c |   51 ++++++++++++++++++++++++++++++-
 6 files changed, 89 insertions(+), 26 deletions(-)

^ permalink raw reply

* Re: [PATCH RFC] Update documentation for KSZ DSA drivers so that new drivers can be added
From: Florian Fainelli @ 2017-09-08 20:58 UTC (permalink / raw)
  To: Tristram.Ha
  Cc: andrew, pavel, nathan.leigh.conrad, vivien.didelot, netdev,
	linux-kernel, Woojung.Huh, muvarov
In-Reply-To: <93AF473E2DA327428DE3D46B72B1E9FD41121F35@CHN-SV-EXMX02.mchp-main.com>

On 09/08/2017 01:07 PM, Tristram.Ha@microchip.com wrote:
>> -----Original Message-----
>> From: Florian Fainelli [mailto:f.fainelli@gmail.com]
>> Sent: Friday, September 08, 2017 12:54 PM
>> To: Tristram Ha - C24268; muvarov@gmail.com
>> Cc: andrew@lunn.ch; pavel@ucw.cz; nathan.leigh.conrad@gmail.com;
>> vivien.didelot@savoirfairelinux.com; netdev@vger.kernel.org; linux-
>> kernel@vger.kernel.org; Woojung Huh - C21699
>> Subject: Re: [PATCH RFC] Update documentation for KSZ DSA drivers so that new
>> drivers can be added
>>
>> On 09/08/2017 12:48 PM, Tristram.Ha@microchip.com wrote:
>>>> -----Original Message-----
>>>> From: Maxim Uvarov [mailto:muvarov@gmail.com]
>>>> Sent: Friday, September 08, 2017 12:00 PM
>>>> To: Florian Fainelli
>>>> Cc: Tristram Ha - C24268; Andrew Lunn; Pavel Machek; Nathan Conrad; Vivien
>>>> Didelot; netdev; linux-kernel@vger.kernel.org; Woojung Huh - C21699
>>>> Subject: Re: [PATCH RFC] Update documentation for KSZ DSA drivers so that
>> new
>>>> drivers can be added
>>>>
>>>> 2017-09-08 21:48 GMT+03:00 Florian Fainelli <f.fainelli@gmail.com>:
>>>>> On 09/07/2017 02:11 PM, Tristram.Ha@microchip.com wrote:
>>>>>> From: Tristram Ha <Tristram.Ha@microchip.com>
>>>>>>
>>>>>> Add other KSZ switches support so that patch check does not complain.
>>>>>>
>>>>>> Signed-off-by: Tristram Ha <Tristram.Ha@microchip.com>
>>>>>> ---
>>>>>>  Documentation/devicetree/bindings/net/dsa/ksz.txt | 117
>>>>>> ++++++++++++----------
>>>>>>  1 file changed, 62 insertions(+), 55 deletions(-)
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/net/dsa/ksz.txt
>>>>>> b/Documentation/devicetree/bindings/net/dsa/ksz.txt
>>>>>> index 0ab8b39..34af0e0 100644
>>>>>> --- a/Documentation/devicetree/bindings/net/dsa/ksz.txt
>>>>>> +++ b/Documentation/devicetree/bindings/net/dsa/ksz.txt
>>>>>> @@ -3,8 +3,15 @@ Microchip KSZ Series Ethernet switches
>>>>>>
>>>>>>  Required properties:
>>>>>>
>>>>>> -- compatible: For external switch chips, compatible string must be
>>>>>> exactly one
>>>>>> -  of: "microchip,ksz9477"
>>>>>> +- compatible: Should be "microchip,ksz9477" for KSZ9477 chip,
>>>>>> +           "microchip,ksz8795" for KSZ8795 chip,
>>>>>> +           "microchip,ksz8794" for KSZ8794 chip,
>>>>>> +           "microchip,ksz8765" for KSZ8765 chip,
>>>>>> +           "microchip,ksz8895" for KSZ8895 chip,
>>>>>> +           "microchip,ksz8864" for KSZ8864 chip,
>>>>>> +           "microchip,ksz8873" for KSZ8873 chip,
>>>>>> +           "microchip,ksz8863" for KSZ8863 chip,
>>>>>> +           "microchip,ksz8463" for KSZ8463 chip
>>>>>
>>>>
>>>>
>>>> Tristram, does any of this devices support chaining?
>>>>
>>>> Maxim.
>>>
>>> They do not if you mean daisy-chaining the switches together.
>>
>> Marvell tags allow you to specify both a port and switch index
>> destination after setting up an appropriate routing table, I am assuming
>> this is not supported.
>>
>> What happens though if I connect two KSZ switches ones to another say:
>>
>> eth0
>> 	-> KSZ8463
>> 		-> KSZ8463
>>
>> Will the first switch terminates KSZ tag if it sees two tags
>> encapsulated in another, something like this:
>>
>> | MAC DA | MAC SA | .... payload | Inner KSZ tag | Inner KSZ tag | FCS |
>>
> 
> In theory it is doable by adding more tags and remember which port
> is connected to the cpu port of another switch, but there is no switch
> forwarding and everything is handled by software.

Fair enough.

> 
>>>
>>> There is always a problem that once tail tagging mode is enabled
>>> sending a frame through the MAC without going through the DSA
>>> layer will cause the frame to be dropped.
>>
>> Yes, once the master network device is used for DSA, it is still usable
>> directly by e.g: applications, but it won't do anything if the switch is
>> configured such that it drops ingressing frames not having the proper
>> tag. We documented that here:
>>
>> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Docume
>> ntation/networking/dsa/dsa.txt#n275
>> --
> 
> As the DSA was developed for the Marvell switches I assumed they can
> forward frame without a tag.

Once you use tags with your switch, eth0/master netdev/conduit interface
no longer has a purpose as a normal interface because we create per-port
network devices. That means if you want to send packets towards Port 0
you use the proper network interface. If you create a bridge, you will
use brX as the network device to send/receive packets from, in all
cases, the packets originate from the CPU and the frame ingresses the
switch with the proper information within the tag to target the vector
of ports.

If you have tags enabled and you use eth0 to send packets towards the
switch, there are not that many options, either you have the proper tag,
and the switch will forward to the right port which can be the CPU port
itself if you want, but why do that?

When tags are not enabled (e.g: b53) that is slightly different,
eth0/master/conduit remains usable as a normal interface would, but
unless you start adding VLAN tags, you cannot quite differentiate where
the traffic from LAN to CPU is coming from, so this has limited usefulness.

Hope this clears things.
-- 
Florian

^ permalink raw reply

* RE: [PATCH RFC] Update documentation for KSZ DSA drivers so that new drivers can be added
From: Tristram.Ha @ 2017-09-08 20:07 UTC (permalink / raw)
  To: f.fainelli
  Cc: andrew, pavel, nathan.leigh.conrad, vivien.didelot, netdev,
	linux-kernel, Woojung.Huh, muvarov
In-Reply-To: <508d7ef0-e351-5369-b477-b027bae3dda4@gmail.com>

> -----Original Message-----
> From: Florian Fainelli [mailto:f.fainelli@gmail.com]
> Sent: Friday, September 08, 2017 12:54 PM
> To: Tristram Ha - C24268; muvarov@gmail.com
> Cc: andrew@lunn.ch; pavel@ucw.cz; nathan.leigh.conrad@gmail.com;
> vivien.didelot@savoirfairelinux.com; netdev@vger.kernel.org; linux-
> kernel@vger.kernel.org; Woojung Huh - C21699
> Subject: Re: [PATCH RFC] Update documentation for KSZ DSA drivers so that new
> drivers can be added
> 
> On 09/08/2017 12:48 PM, Tristram.Ha@microchip.com wrote:
> >> -----Original Message-----
> >> From: Maxim Uvarov [mailto:muvarov@gmail.com]
> >> Sent: Friday, September 08, 2017 12:00 PM
> >> To: Florian Fainelli
> >> Cc: Tristram Ha - C24268; Andrew Lunn; Pavel Machek; Nathan Conrad; Vivien
> >> Didelot; netdev; linux-kernel@vger.kernel.org; Woojung Huh - C21699
> >> Subject: Re: [PATCH RFC] Update documentation for KSZ DSA drivers so that
> new
> >> drivers can be added
> >>
> >> 2017-09-08 21:48 GMT+03:00 Florian Fainelli <f.fainelli@gmail.com>:
> >>> On 09/07/2017 02:11 PM, Tristram.Ha@microchip.com wrote:
> >>>> From: Tristram Ha <Tristram.Ha@microchip.com>
> >>>>
> >>>> Add other KSZ switches support so that patch check does not complain.
> >>>>
> >>>> Signed-off-by: Tristram Ha <Tristram.Ha@microchip.com>
> >>>> ---
> >>>>  Documentation/devicetree/bindings/net/dsa/ksz.txt | 117
> >>>> ++++++++++++----------
> >>>>  1 file changed, 62 insertions(+), 55 deletions(-)
> >>>>
> >>>> diff --git a/Documentation/devicetree/bindings/net/dsa/ksz.txt
> >>>> b/Documentation/devicetree/bindings/net/dsa/ksz.txt
> >>>> index 0ab8b39..34af0e0 100644
> >>>> --- a/Documentation/devicetree/bindings/net/dsa/ksz.txt
> >>>> +++ b/Documentation/devicetree/bindings/net/dsa/ksz.txt
> >>>> @@ -3,8 +3,15 @@ Microchip KSZ Series Ethernet switches
> >>>>
> >>>>  Required properties:
> >>>>
> >>>> -- compatible: For external switch chips, compatible string must be
> >>>> exactly one
> >>>> -  of: "microchip,ksz9477"
> >>>> +- compatible: Should be "microchip,ksz9477" for KSZ9477 chip,
> >>>> +           "microchip,ksz8795" for KSZ8795 chip,
> >>>> +           "microchip,ksz8794" for KSZ8794 chip,
> >>>> +           "microchip,ksz8765" for KSZ8765 chip,
> >>>> +           "microchip,ksz8895" for KSZ8895 chip,
> >>>> +           "microchip,ksz8864" for KSZ8864 chip,
> >>>> +           "microchip,ksz8873" for KSZ8873 chip,
> >>>> +           "microchip,ksz8863" for KSZ8863 chip,
> >>>> +           "microchip,ksz8463" for KSZ8463 chip
> >>>
> >>
> >>
> >> Tristram, does any of this devices support chaining?
> >>
> >> Maxim.
> >
> > They do not if you mean daisy-chaining the switches together.
> 
> Marvell tags allow you to specify both a port and switch index
> destination after setting up an appropriate routing table, I am assuming
> this is not supported.
> 
> What happens though if I connect two KSZ switches ones to another say:
> 
> eth0
> 	-> KSZ8463
> 		-> KSZ8463
> 
> Will the first switch terminates KSZ tag if it sees two tags
> encapsulated in another, something like this:
> 
> | MAC DA | MAC SA | .... payload | Inner KSZ tag | Inner KSZ tag | FCS |
> 

In theory it is doable by adding more tags and remember which port
is connected to the cpu port of another switch, but there is no switch
forwarding and everything is handled by software.

> >
> > There is always a problem that once tail tagging mode is enabled
> > sending a frame through the MAC without going through the DSA
> > layer will cause the frame to be dropped.
> 
> Yes, once the master network device is used for DSA, it is still usable
> directly by e.g: applications, but it won't do anything if the switch is
> configured such that it drops ingressing frames not having the proper
> tag. We documented that here:
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Docume
> ntation/networking/dsa/dsa.txt#n275
> --

As the DSA was developed for the Marvell switches I assumed they can
forward frame without a tag.


^ permalink raw reply

* RE: [PATCH net-next] mdio_bus: Remove unneeded gpiod NULL check
From: Woojung.Huh @ 2017-09-08 20:03 UTC (permalink / raw)
  To: f.fainelli, linus.walleij
  Cc: andrew, festevam, sergei.shtylyov, davem, netdev, fabio.estevam,
	Bryan.Whitehead
In-Reply-To: <c960202c-02e3-3f54-7d0b-b5ece46c6a9e@gmail.com>

> >> I think it means CONFIG_GPIOLIB=n in the kernel because it's not needed,
> >> yet you run code (like drivers/net/phy/mdio_bus.c) that unconditionally
> >> calls into GPIOLIB and attempts to configure a given GPIO if available.
> > Yes. I'm facing issue on PC which won't need GPIOLIB as default.
> > Warning message goes away when GPIOLIB is enabled, and fortunately,
> > Ubuntu default config has it.
> > So, it may not be seen by many users when with full/default configuration.
> 
> Woojung, I suppose you are also getting a warning from
> gpiod_set_value_cansleep() done in mdiobus_unregister() right? With
> CONFIG_GPIOLIB=n devm_gpiod_get_optional() returns NULL, which we
> don't
> check as an error, on purpose however we still call
> gpiod_set_value_cansleep() on a NULL GPIO descriptor, so the following
> should do:
> 
> diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
> index b6f9fa670168..67dbb7c26840 100644
> --- a/drivers/net/phy/mdio_bus.c
> +++ b/drivers/net/phy/mdio_bus.c
> @@ -424,7 +424,8 @@ void mdiobus_unregister(struct mii_bus *bus)
>         }
> 
>         /* Put PHYs in RESET to save power */
> -       gpiod_set_value_cansleep(bus->reset_gpiod, 1);
> +       if (!IS_ERR_OR_NULL(bus->reset_gpiod))
> +               gpiod_set_value_cansleep(bus->reset_gpiod, 1);
> 
>         device_del(&bus->dev);
>  }
Hi Florian,

Thanks for the patch. I'm avoiding warning with CONFIG_GPIOLIB=y for now.
I'm curious that there is a final conclusion to resolve this issue,
either with CONFIG_GPIOLIB=y or something else.

- Woojung

^ permalink raw reply

* Re: [PATCH net-next] mdio_bus: Remove unneeded gpiod NULL check
From: Florian Fainelli @ 2017-09-08 19:56 UTC (permalink / raw)
  To: Woojung.Huh, linus.walleij
  Cc: andrew, festevam, sergei.shtylyov, davem, netdev, fabio.estevam
In-Reply-To: <9235D6609DB808459E95D78E17F2E43D40B1B47F@CHN-SV-EXMX02.mchp-main.com>

On 09/07/2017 02:51 PM, Woojung.Huh@microchip.com wrote:
>>>>> If someone is using GPIO descriptors with GPIO disabled, i.e. calling
>>>>> gpiod_get() and friends, this is very likely to be a bug, and what
>>>>> the driver wants to do is:
>>>>>
>>>>>  depends on GPIOLIB
>>>>>
>>>>> or
>>>>>
>>>>>  select GPIOLIB
>>>>>
>>>>> in Kconfig. The whole optional thing is mainly a leftover from when it
>>>>> was possible to have a local implementation of the GPIOLIB API in
>>>>> some custom header file, noone sane should be doing that anymore,
>>>>> and if they do, they can very well face the warnings.
>>>>>
>>>>> If someone is facing a lot of WARN_ON() messages to this, it is a clear
>>>>> indication that they need to fix their Kconfig and in that case it is proper.
>>>> Linus & Andrew,
>>>>
>>>> I knew that it is already in David's pulling request.
>>>> Configuring GPIOLIB is the right solution  even if platform doesn't use it?
>>>
>>> I guess?
>>>
>>> "Platform doesn't use it" what does that mean?
>>>
>>> Does it mean it does not call the
>>> APIs of the GPIOLIB, does it mean it doesn't have a GPIO driver
>>> at probe (but may have one by having it probed from a module)
>>> or does it mean the platform can never have it?
>>
>> I think it means CONFIG_GPIOLIB=n in the kernel because it's not needed,
>> yet you run code (like drivers/net/phy/mdio_bus.c) that unconditionally
>> calls into GPIOLIB and attempts to configure a given GPIO if available.
> Yes. I'm facing issue on PC which won't need GPIOLIB as default.
> Warning message goes away when GPIOLIB is enabled, and fortunately,
> Ubuntu default config has it.
> So, it may not be seen by many users when with full/default configuration.

Woojung, I suppose you are also getting a warning from
gpiod_set_value_cansleep() done in mdiobus_unregister() right? With
CONFIG_GPIOLIB=n devm_gpiod_get_optional() returns NULL, which we don't
check as an error, on purpose however we still call
gpiod_set_value_cansleep() on a NULL GPIO descriptor, so the following
should do:

diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index b6f9fa670168..67dbb7c26840 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -424,7 +424,8 @@ void mdiobus_unregister(struct mii_bus *bus)
        }

        /* Put PHYs in RESET to save power */
-       gpiod_set_value_cansleep(bus->reset_gpiod, 1);
+       if (!IS_ERR_OR_NULL(bus->reset_gpiod))
+               gpiod_set_value_cansleep(bus->reset_gpiod, 1);

        device_del(&bus->dev);
 }


> 
>> This thread is actually what prompted me to write this email:
>>
>> https://lkml.org/lkml/2017/9/2/3
> Thanks for the link.
> 
> 


-- 
Florian

^ permalink raw reply related

* Re: [PATCH RFC] Update documentation for KSZ DSA drivers so that new drivers can be added
From: Florian Fainelli @ 2017-09-08 19:54 UTC (permalink / raw)
  To: Tristram.Ha, muvarov
  Cc: andrew, pavel, nathan.leigh.conrad, vivien.didelot, netdev,
	linux-kernel, Woojung.Huh
In-Reply-To: <93AF473E2DA327428DE3D46B72B1E9FD41121EF7@CHN-SV-EXMX02.mchp-main.com>

On 09/08/2017 12:48 PM, Tristram.Ha@microchip.com wrote:
>> -----Original Message-----
>> From: Maxim Uvarov [mailto:muvarov@gmail.com]
>> Sent: Friday, September 08, 2017 12:00 PM
>> To: Florian Fainelli
>> Cc: Tristram Ha - C24268; Andrew Lunn; Pavel Machek; Nathan Conrad; Vivien
>> Didelot; netdev; linux-kernel@vger.kernel.org; Woojung Huh - C21699
>> Subject: Re: [PATCH RFC] Update documentation for KSZ DSA drivers so that new
>> drivers can be added
>>
>> 2017-09-08 21:48 GMT+03:00 Florian Fainelli <f.fainelli@gmail.com>:
>>> On 09/07/2017 02:11 PM, Tristram.Ha@microchip.com wrote:
>>>> From: Tristram Ha <Tristram.Ha@microchip.com>
>>>>
>>>> Add other KSZ switches support so that patch check does not complain.
>>>>
>>>> Signed-off-by: Tristram Ha <Tristram.Ha@microchip.com>
>>>> ---
>>>>  Documentation/devicetree/bindings/net/dsa/ksz.txt | 117
>>>> ++++++++++++----------
>>>>  1 file changed, 62 insertions(+), 55 deletions(-)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/net/dsa/ksz.txt
>>>> b/Documentation/devicetree/bindings/net/dsa/ksz.txt
>>>> index 0ab8b39..34af0e0 100644
>>>> --- a/Documentation/devicetree/bindings/net/dsa/ksz.txt
>>>> +++ b/Documentation/devicetree/bindings/net/dsa/ksz.txt
>>>> @@ -3,8 +3,15 @@ Microchip KSZ Series Ethernet switches
>>>>
>>>>  Required properties:
>>>>
>>>> -- compatible: For external switch chips, compatible string must be
>>>> exactly one
>>>> -  of: "microchip,ksz9477"
>>>> +- compatible: Should be "microchip,ksz9477" for KSZ9477 chip,
>>>> +           "microchip,ksz8795" for KSZ8795 chip,
>>>> +           "microchip,ksz8794" for KSZ8794 chip,
>>>> +           "microchip,ksz8765" for KSZ8765 chip,
>>>> +           "microchip,ksz8895" for KSZ8895 chip,
>>>> +           "microchip,ksz8864" for KSZ8864 chip,
>>>> +           "microchip,ksz8873" for KSZ8873 chip,
>>>> +           "microchip,ksz8863" for KSZ8863 chip,
>>>> +           "microchip,ksz8463" for KSZ8463 chip
>>>
>>
>>
>> Tristram, does any of this devices support chaining?
>>
>> Maxim.
> 
> They do not if you mean daisy-chaining the switches together.

Marvell tags allow you to specify both a port and switch index
destination after setting up an appropriate routing table, I am assuming
this is not supported.

What happens though if I connect two KSZ switches ones to another say:

eth0
	-> KSZ8463
		-> KSZ8463

Will the first switch terminates KSZ tag if it sees two tags
encapsulated in another, something like this:

| MAC DA | MAC SA | .... payload | Inner KSZ tag | Inner KSZ tag | FCS |

> 
> There is always a problem that once tail tagging mode is enabled
> sending a frame through the MAC without going through the DSA
> layer will cause the frame to be dropped.

Yes, once the master network device is used for DSA, it is still usable
directly by e.g: applications, but it won't do anything if the switch is
configured such that it drops ingressing frames not having the proper
tag. We documented that here:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/networking/dsa/dsa.txt#n275
-- 
Florian

^ permalink raw reply

* Re: Use after free in __dst_destroy_metrics_generic
From: Subash Abhinov Kasiviswanathan @ 2017-09-08 19:50 UTC (permalink / raw)
  To: Cong Wang; +Cc: Linux Kernel Network Developers, Eric Dumazet, Lorenzo Colitti
In-Reply-To: <CAM_iQpXKfUkbyuuZEZXyPrVVCoPaxnCmCARz=Jf0VtU1m9NsZg@mail.gmail.com>

On 2017-09-08 10:10, Cong Wang wrote:
> On Thu, Sep 7, 2017 at 5:52 PM, Subash Abhinov Kasiviswanathan
> <subashab@codeaurora.org> wrote:
>> We are seeing a possible use after free in ip6_dst_destroy.
>> 
>> It appears as if memory of the __DST_METRICS_PTR(old) was freed in 
>> some path
>> and allocated
>> to ion driver. ion driver has also freed it. Finally the memory is 
>> freed by
>> the
>> fib gc and crashes since it is already deallocated.
> 
> Does the attach (compile-only) patch help anything?
> 
> From my _quick_ glance, it seems we miss the refcnt'ing
> right in __dst_destroy_metrics_generic().
> 
> Thanks!

Hi Cong

Thanks for patch. I'll try this out.

-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a 
Linux Foundation Collaborative Project

^ permalink raw reply

* RE: [PATCH RFC] Update documentation for KSZ DSA drivers so that new drivers can be added
From: Tristram.Ha @ 2017-09-08 19:48 UTC (permalink / raw)
  To: muvarov
  Cc: andrew, pavel, nathan.leigh.conrad, vivien.didelot, netdev,
	linux-kernel, Woojung.Huh, f.fainelli
In-Reply-To: <CAJGZr0Kp5ZKmFJT+KX9jxMVyZT9=VO0_dpZqE+y1TNaYvURcoQ@mail.gmail.com>

> -----Original Message-----
> From: Maxim Uvarov [mailto:muvarov@gmail.com]
> Sent: Friday, September 08, 2017 12:00 PM
> To: Florian Fainelli
> Cc: Tristram Ha - C24268; Andrew Lunn; Pavel Machek; Nathan Conrad; Vivien
> Didelot; netdev; linux-kernel@vger.kernel.org; Woojung Huh - C21699
> Subject: Re: [PATCH RFC] Update documentation for KSZ DSA drivers so that new
> drivers can be added
> 
> 2017-09-08 21:48 GMT+03:00 Florian Fainelli <f.fainelli@gmail.com>:
> > On 09/07/2017 02:11 PM, Tristram.Ha@microchip.com wrote:
> >> From: Tristram Ha <Tristram.Ha@microchip.com>
> >>
> >> Add other KSZ switches support so that patch check does not complain.
> >>
> >> Signed-off-by: Tristram Ha <Tristram.Ha@microchip.com>
> >> ---
> >>  Documentation/devicetree/bindings/net/dsa/ksz.txt | 117
> >> ++++++++++++----------
> >>  1 file changed, 62 insertions(+), 55 deletions(-)
> >>
> >> diff --git a/Documentation/devicetree/bindings/net/dsa/ksz.txt
> >> b/Documentation/devicetree/bindings/net/dsa/ksz.txt
> >> index 0ab8b39..34af0e0 100644
> >> --- a/Documentation/devicetree/bindings/net/dsa/ksz.txt
> >> +++ b/Documentation/devicetree/bindings/net/dsa/ksz.txt
> >> @@ -3,8 +3,15 @@ Microchip KSZ Series Ethernet switches
> >>
> >>  Required properties:
> >>
> >> -- compatible: For external switch chips, compatible string must be
> >> exactly one
> >> -  of: "microchip,ksz9477"
> >> +- compatible: Should be "microchip,ksz9477" for KSZ9477 chip,
> >> +           "microchip,ksz8795" for KSZ8795 chip,
> >> +           "microchip,ksz8794" for KSZ8794 chip,
> >> +           "microchip,ksz8765" for KSZ8765 chip,
> >> +           "microchip,ksz8895" for KSZ8895 chip,
> >> +           "microchip,ksz8864" for KSZ8864 chip,
> >> +           "microchip,ksz8873" for KSZ8873 chip,
> >> +           "microchip,ksz8863" for KSZ8863 chip,
> >> +           "microchip,ksz8463" for KSZ8463 chip
> >
> 
> 
> Tristram, does any of this devices support chaining?
> 
> Maxim.

They do not if you mean daisy-chaining the switches together.

There is always a problem that once tail tagging mode is enabled
sending a frame through the MAC without going through the DSA
layer will cause the frame to be dropped.


^ permalink raw reply

* Re: [PATCH net] net: qualcomm: rmnet: Fix a double free
From: Subash Abhinov Kasiviswanathan @ 2017-09-08 19:44 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: David S. Miller, netdev, kernel-janitors
In-Reply-To: <20170908102356.tzysh6qaiesd2umz@mwanda>

> diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
> b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
> index 557c9bf1a469..0335fce54201 100644
> --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
> +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
> @@ -95,10 +95,8 @@ struct sk_buff *rmnet_map_deaggregate(struct sk_buff 
> *skb)
>  	skb_pull(skb, packet_len);
> 
>  	/* Some hardware can send us empty frames. Catch them */
> -	if (ntohs(maph->pkt_len) == 0) {
> -		kfree_skb(skb);
> +	if (ntohs(maph->pkt_len) == 0)
>  		return NULL;
> -	}
> 
>  	return skbn;
>  }

Thanks for the patch. This is fixing the double free, but is leaking the 
new skb skbn
created. Perhaps we should add the check earlier -

diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c 
b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
index 557c9bf..86b8c75 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
@@ -84,6 +84,10 @@ struct sk_buff *rmnet_map_deaggregate(struct sk_buff 
*skb)
         if (((int)skb->len - (int)packet_len) < 0)
                 return NULL;

+       /* Some hardware can send us empty frames. Catch them */
+       if (ntohs(maph->pkt_len) == 0)
+               return NULL;
+
         skbn = alloc_skb(packet_len + RMNET_MAP_DEAGGR_SPACING, 
GFP_ATOMIC);
         if (!skbn)
                 return NULL;
@@ -94,11 +98,5 @@ struct sk_buff *rmnet_map_deaggregate(struct sk_buff 
*skb)
         memcpy(skbn->data, skb->data, packet_len);
         skb_pull(skb, packet_len);

-       /* Some hardware can send us empty frames. Catch them */
-       if (ntohs(maph->pkt_len) == 0) {
-               kfree_skb(skb);
-               return NULL;
-       }
-
         return skbn;
  }


-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a 
Linux Foundation Collaborative Project

^ permalink raw reply related

* [PATCH net] tcp: fix a request socket leak
From: Eric Dumazet @ 2017-09-08 19:44 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

From: Eric Dumazet <edumazet@google.com>

While the cited commit fixed a possible deadlock, it added a leak
of the request socket, since reqsk_put() must be called if the BPF
filter decided the ACK packet must be dropped.

Fixes: d624d276d1dd ("tcp: fix possible deadlock in TCP stack vs BPF filter")
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
David, this is a stable candidate (linux-4.13 has this bug)

 net/ipv4/tcp_ipv4.c |    6 +++---
 net/ipv6/tcp_ipv6.c |    6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index a63486afa7a7e7b4dce88b65bc27cfa872a3ba2f..d9416b5162bc1bdd1acd34fcb4da21cb6b62d0ae 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1669,9 +1669,9 @@ int tcp_v4_rcv(struct sk_buff *skb)
 		 */
 		sock_hold(sk);
 		refcounted = true;
-		if (tcp_filter(sk, skb))
-			goto discard_and_relse;
-		nsk = tcp_check_req(sk, skb, req, false);
+		nsk = NULL;
+		if (!tcp_filter(sk, skb))
+			nsk = tcp_check_req(sk, skb, req, false);
 		if (!nsk) {
 			reqsk_put(req);
 			goto discard_and_relse;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 38f76d8b231e3e5923ad72d05b8d320b6aeb850f..64d94afa427f81fd7a505b1cfd1c0be66c273810 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1460,9 +1460,9 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 		}
 		sock_hold(sk);
 		refcounted = true;
-		if (tcp_filter(sk, skb))
-			goto discard_and_relse;
-		nsk = tcp_check_req(sk, skb, req, false);
+		nsk = NULL;
+		if (!tcp_filter(sk, skb))
+			nsk = tcp_check_req(sk, skb, req, false);
 		if (!nsk) {
 			reqsk_put(req);
 			goto discard_and_relse;

^ permalink raw reply related

* Re: [PATCH net] netlink: access nlk groups safely in netlink bind and getname
From: Cong Wang @ 2017-09-08 19:35 UTC (permalink / raw)
  To: Xin Long; +Cc: network dev, David Miller, Florian Westphal
In-Reply-To: <cfb5c05d158b278beb2f1441c67a068a8bb27d44.1504670009.git.lucien.xin@gmail.com>

On Tue, Sep 5, 2017 at 8:53 PM, Xin Long <lucien.xin@gmail.com> wrote:
> Now there is no lock protecting nlk ngroups/groups' accessing in
> netlink bind and getname. It's safe from nlk groups' setting in
> netlink_release, but not from netlink_realloc_groups called by
> netlink_setsockopt.
>
> netlink_lock_table is needed in both netlink bind and getname when
> accessing nlk groups.

This looks very odd.

netlink_lock_table() should be protecting nl_table, why
it also protects nlk->groups?? For me it looks like you
need lock_sock() instead.

^ permalink raw reply

* Re: [PATCH net-next 2/3] net: ethernet: socionext: add AVE ethernet driver
From: Florian Fainelli @ 2017-09-08 19:31 UTC (permalink / raw)
  To: Kunihiko Hayashi, netdev-u79uwXL29TY76Z2rM5mHXA, David S. Miller,
	Andrew Lunn
  Cc: Rob Herring, Mark Rutland,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Masahiro Yamada,
	Masami Hiramatsu, Jassi Brar
In-Reply-To: <1504875731-3680-3-git-send-email-hayashi.kunihiko-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org>

On 09/08/2017 06:02 AM, Kunihiko Hayashi wrote:
> The UniPhier platform from Socionext provides the AVE ethernet
> controller that includes MAC and MDIO bus supporting RGMII/RMII
> modes. The controller is named AVE.
> 
> Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org>
> Signed-off-by: Jassi Brar <jaswinder.singh-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
>  drivers/net/ethernet/Kconfig             |    1 +
>  drivers/net/ethernet/Makefile            |    1 +
>  drivers/net/ethernet/socionext/Kconfig   |   22 +
>  drivers/net/ethernet/socionext/Makefile  |    4 +
>  drivers/net/ethernet/socionext/sni_ave.c | 1618 ++++++++++++++++++++++++++++++
>  5 files changed, 1646 insertions(+)
>  create mode 100644 drivers/net/ethernet/socionext/Kconfig
>  create mode 100644 drivers/net/ethernet/socionext/Makefile
>  create mode 100644 drivers/net/ethernet/socionext/sni_ave.c
> 
> diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
> index c604213..d50519e 100644
> --- a/drivers/net/ethernet/Kconfig
> +++ b/drivers/net/ethernet/Kconfig
> @@ -170,6 +170,7 @@ source "drivers/net/ethernet/sis/Kconfig"
>  source "drivers/net/ethernet/sfc/Kconfig"
>  source "drivers/net/ethernet/sgi/Kconfig"
>  source "drivers/net/ethernet/smsc/Kconfig"
> +source "drivers/net/ethernet/socionext/Kconfig"
>  source "drivers/net/ethernet/stmicro/Kconfig"
>  source "drivers/net/ethernet/sun/Kconfig"
>  source "drivers/net/ethernet/tehuti/Kconfig"
> diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
> index a0a03d4..9f55b36 100644
> --- a/drivers/net/ethernet/Makefile
> +++ b/drivers/net/ethernet/Makefile
> @@ -81,6 +81,7 @@ obj-$(CONFIG_SFC) += sfc/
>  obj-$(CONFIG_SFC_FALCON) += sfc/falcon/
>  obj-$(CONFIG_NET_VENDOR_SGI) += sgi/
>  obj-$(CONFIG_NET_VENDOR_SMSC) += smsc/
> +obj-$(CONFIG_NET_VENDOR_SOCIONEXT) += socionext/
>  obj-$(CONFIG_NET_VENDOR_STMICRO) += stmicro/
>  obj-$(CONFIG_NET_VENDOR_SUN) += sun/
>  obj-$(CONFIG_NET_VENDOR_TEHUTI) += tehuti/
> diff --git a/drivers/net/ethernet/socionext/Kconfig b/drivers/net/ethernet/socionext/Kconfig
> new file mode 100644
> index 0000000..788f26f
> --- /dev/null
> +++ b/drivers/net/ethernet/socionext/Kconfig
> @@ -0,0 +1,22 @@
> +config NET_VENDOR_SOCIONEXT
> +	bool "Socionext ethernet drivers"
> +	default y
> +	---help---
> +	  Option to select ethernet drivers for Socionext platforms.
> +
> +	  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 Agere devices. If you say Y, you will be asked
> +	  for your specific card in the following questions.
> +
> +if NET_VENDOR_SOCIONEXT
> +
> +config SNI_AVE
> +	tristate "Socionext AVE ethernet support"
> +	depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF
> +	select PHYLIB
> +	---help---
> +	  Driver for gigabit ethernet MACs, called AVE, in the
> +	  Socionext UniPhier family.
> +
> +endif #NET_VENDOR_SOCIONEXT
> diff --git a/drivers/net/ethernet/socionext/Makefile b/drivers/net/ethernet/socionext/Makefile
> new file mode 100644
> index 0000000..0356341
> --- /dev/null
> +++ b/drivers/net/ethernet/socionext/Makefile
> @@ -0,0 +1,4 @@
> +#
> +# Makefile for all ethernet ip drivers on Socionext platforms
> +#
> +obj-$(CONFIG_SNI_AVE) += sni_ave.o
> diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c
> new file mode 100644
> index 0000000..c870777
> --- /dev/null
> +++ b/drivers/net/ethernet/socionext/sni_ave.c
> @@ -0,0 +1,1618 @@
> +/**
> + * sni_ave.c - Socionext UniPhier AVE ethernet driver
> + *
> + * Copyright 2014 Panasonic Corporation
> + * Copyright 2015-2017 Socionext Inc.
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2  of
> + * the License 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.
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/clk.h>
> +#include <linux/etherdevice.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/mii.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/of_net.h>
> +#include <linux/of_mdio.h>
> +#include <linux/of_platform.h>
> +#include <linux/phy.h>
> +#include <linux/reset.h>
> +#include <linux/types.h>
> +
> +/* General Register Group */
> +#define AVE_IDR		0x0	/* ID */
> +#define AVE_VR		0x4	/* Version */
> +#define AVE_GRR		0x8	/* Global Reset */
> +#define AVE_CFGR	0xc	/* Configuration */
> +
> +/* Interrupt Register Group */
> +#define AVE_GIMR	0x100	/* Global Interrupt Mask */
> +#define AVE_GISR	0x104	/* Global Interrupt Status */
> +
> +/* MAC Register Group */
> +#define AVE_TXCR	0x200	/* TX Setup */
> +#define AVE_RXCR	0x204	/* RX Setup */
> +#define AVE_RXMAC1R	0x208	/* MAC address (lower) */
> +#define AVE_RXMAC2R	0x20c	/* MAC address (upper) */
> +#define AVE_MDIOCTR	0x214	/* MDIO Control */
> +#define AVE_MDIOAR	0x218	/* MDIO Address */
> +#define AVE_MDIOWDR	0x21c	/* MDIO Data */
> +#define AVE_MDIOSR	0x220	/* MDIO Status */
> +#define AVE_MDIORDR	0x224	/* MDIO Rd Data */
> +
> +/* Descriptor Control Register Group */
> +#define AVE_DESCC	0x300	/* Descriptor Control */
> +#define AVE_TXDC	0x304	/* TX Descriptor Configuration */
> +#define AVE_RXDC0	0x308	/* RX Descriptor Ring0 Configuration */
> +#define AVE_IIRQC	0x34c	/* Interval IRQ Control */
> +
> +/* Frame Counter Register Group */
> +#define AVE_BFCR	0x400	/* Bad Frame Counter */
> +#define AVE_RX0OVFFC	0x414	/* OVF Frame Counter (Ring0) */
> +#define AVE_SN5FC	0x438	/* Frame Counter No5 */
> +#define AVE_SN6FC	0x43c	/* Frame Counter No6 */
> +#define AVE_SN7FC	0x440	/* Frame Counter No7 */
> +
> +/* Packet Filter Register Group */
> +#define AVE_PKTF_BASE		0x800	/* PF Base Address */
> +#define AVE_PFMBYTE_BASE	0xd00	/* PF Mask Byte Base Address */
> +#define AVE_PFMBIT_BASE		0xe00	/* PF Mask Bit Base Address */
> +#define AVE_PFSEL_BASE		0xf00	/* PF Selector Base Address */
> +#define AVE_PFEN		0xffc	/* Packet Filter Enable */
> +#define AVE_PKTF(ent)		(AVE_PKTF_BASE + (ent) * 0x40)
> +#define AVE_PFMBYTE(ent)	(AVE_PFMBYTE_BASE + (ent) * 8)
> +#define AVE_PFMBIT(ent)		(AVE_PFMBIT_BASE + (ent) * 4)
> +#define AVE_PFSEL(ent)		(AVE_PFSEL_BASE + (ent) * 4)
> +
> +/* 64bit descriptor memory */
> +#define AVE_DESC_SIZE_64	12	/* Descriptor Size */
> +
> +#define AVE_TXDM_64		0x1000	/* Tx Descriptor Memory */
> +#define AVE_RXDM_64		0x1c00	/* Rx Descriptor Memory */
> +
> +#define AVE_TXDM_SIZE_64	0x0ba0	/* Tx Descriptor Memory Size 3KB */
> +#define AVE_RXDM_SIZE_64	0x6000	/* Rx Descriptor Memory Size 24KB */
> +
> +/* 32bit descriptor memory */
> +#define AVE_DESC_SIZE_32	8	/* Descriptor Size */
> +
> +#define AVE_TXDM_32		0x1000	/* Tx Descriptor Memory */
> +#define AVE_RXDM_32		0x1800	/* Rx Descriptor Memory */
> +
> +#define AVE_TXDM_SIZE_32	0x07c0	/* Tx Descriptor Memory Size 2KB */
> +#define AVE_RXDM_SIZE_32	0x4000	/* Rx Descriptor Memory Size 16KB */
> +
> +/* RMII Bridge Register Group */
> +#define AVE_RSTCTRL		0x8028	/* Reset control */
> +#define AVE_RSTCTRL_RMIIRST	BIT(16)
> +#define AVE_LINKSEL		0x8034	/* Link speed setting */
> +#define AVE_LINKSEL_100M	BIT(0)
> +
> +/* AVE_GRR */
> +#define AVE_GRR_RXFFR		BIT(5)	/* Reset RxFIFO */
> +#define AVE_GRR_PHYRST		BIT(4)	/* Reset external PHY */
> +#define AVE_GRR_GRST		BIT(0)	/* Reset all MAC */
> +
> +/* AVE_GISR (common with GIMR) */
> +#define AVE_GI_PHY		BIT(24)	/* PHY interrupt */
> +#define AVE_GI_TX		BIT(16)	/* Tx complete */
> +#define AVE_GI_RXERR		BIT(8)	/* Receive frame more than max size */
> +#define AVE_GI_RXOVF		BIT(7)	/* Overflow at the RxFIFO */
> +#define AVE_GI_RXDROP		BIT(6)	/* Drop packet */
> +#define AVE_GI_RXIINT		BIT(5)	/* Interval interrupt */
> +
> +/* AVE_TXCR */
> +#define AVE_TXCR_FLOCTR		BIT(18)	/* Flow control */
> +#define AVE_TXCR_TXSPD_1G	BIT(17)
> +#define AVE_TXCR_TXSPD_100	BIT(16)
> +
> +/* AVE_RXCR */
> +#define AVE_RXCR_RXEN		BIT(30)	/* Rx enable */
> +#define AVE_RXCR_FDUPEN		BIT(22)	/* Interface mode */
> +#define AVE_RXCR_FLOCTR		BIT(21)	/* Flow control */
> +#define AVE_RXCR_AFEN		BIT(19)	/* MAC address filter */
> +#define AVE_RXCR_DRPEN		BIT(18)	/* Drop pause frame */
> +#define AVE_RXCR_MPSIZ_MASK	GENMASK(10, 0)
> +
> +/* AVE_MDIOCTR */
> +#define AVE_MDIOCTR_RREQ	BIT(3)	/* Read request */
> +#define AVE_MDIOCTR_WREQ	BIT(2)	/* Write request */
> +
> +/* AVE_MDIOSR */
> +#define AVE_MDIOSR_STS		BIT(0)	/* access status */
> +
> +/* AVE_DESCC */
> +#define AVE_DESCC_TD		BIT(0)	/* Enable Tx descriptor */
> +#define AVE_DESCC_RDSTP		BIT(4)	/* Pause Rx descriptor */
> +#define AVE_DESCC_RD0		BIT(8)	/* Enable Rx descriptor Ring0 */
> +
> +#define AVE_DESCC_CTRL_MASK	GENMASK(15, 0)
> +
> +/* AVE_TXDC */
> +#define AVE_TXDC_SIZE		GENMASK(27, 16)	/* Size of Tx descriptor */
> +#define AVE_TXDC_ADDR		GENMASK(11, 0)	/* Start address */
> +#define AVE_TXDC_ADDR_START	0
> +
> +/* AVE_RXDC0 */
> +#define AVE_RXDC0_SIZE		GENMASK(30, 16)	/* Size of Rx descriptor */
> +#define AVE_RXDC0_ADDR		GENMASK(14, 0)	/* Start address */
> +#define AVE_RXDC0_ADDR_START	0
> +
> +/* AVE_IIRQC */
> +#define AVE_IIRQC_EN0		BIT(27)	/* Enable interval interrupt Ring0 */
> +#define AVE_IIRQC_BSCK		GENMASK(15, 0)	/* Interval count unit */
> +
> +/* Command status for Descriptor */
> +#define AVE_STS_OWN		BIT(31)	/* Descriptor ownership */
> +#define AVE_STS_INTR		BIT(29)	/* Request for interrupt */
> +#define AVE_STS_OK		BIT(27)	/* Normal transmit */
> +/* TX */
> +#define AVE_STS_NOCSUM		BIT(28)	/* No use HW checksum */
> +#define AVE_STS_1ST		BIT(26)	/* Head of buffer chain */
> +#define AVE_STS_LAST		BIT(25)	/* Tail of buffer chain */
> +#define AVE_STS_OWC		BIT(21)	/* Out of window,Late Collision */
> +#define AVE_STS_EC		BIT(20)	/* Excess collision occurred */
> +#define AVE_STS_PKTLEN_TX	GENMASK(15, 0)
> +/* RX */
> +#define AVE_STS_CSSV		BIT(21)	/* Checksum check performed */
> +#define AVE_STS_CSER		BIT(20)	/* Checksum error detected */
> +#define AVE_STS_PKTLEN_RX	GENMASK(10, 0)
> +
> +/* AVE_CFGR */
> +#define AVE_CFGR_FLE		BIT(31)	/* Filter Function */
> +#define AVE_CFGR_CHE		BIT(30)	/* Checksum Function */
> +#define AVE_CFGR_MII		BIT(27)	/* Func mode (1:MII/RMII, 0:RGMII) */
> +#define AVE_CFGR_IPFCEN		BIT(24)	/* IP fragment sum Enable */
> +
> +#define AVE_MAX_ETHFRAME	1518
> +
> +/* Packet filter size */
> +#define AVE_PF_SIZE		17	/* Number of all packet filter */
> +#define AVE_PF_MULTICAST_SIZE	7	/* Number of multicast filter */
> +
> +/* Packet filter definition */
> +#define AVE_PFNUM_FILTER	0	/* No.0 */
> +#define AVE_PFNUM_UNICAST	1	/* No.1 */
> +#define AVE_PFNUM_BROADCAST	2	/* No.2 */
> +#define AVE_PFNUM_MULTICAST	11	/* No.11-17 */
> +
> +/* NETIF Message control */
> +#define AVE_DEFAULT_MSG_ENABLE	(NETIF_MSG_DRV    |	\
> +				 NETIF_MSG_PROBE  |	\
> +				 NETIF_MSG_LINK   |	\
> +				 NETIF_MSG_TIMER  |	\
> +				 NETIF_MSG_IFDOWN |	\
> +				 NETIF_MSG_IFUP   |	\
> +				 NETIF_MSG_RX_ERR |	\
> +				 NETIF_MSG_TX_ERR)
> +
> +/* Parameter for descriptor */
> +#define AVE_NR_TXDESC		32	/* Tx descriptor */
> +#define AVE_NR_RXDESC		64	/* Rx descriptor */
> +
> +/* Parameter for interrupt */
> +#define AVE_INTM_COUNT		20
> +#define AVE_FORCE_TXINTCNT	1
> +
> +#define IS_DESC_64BIT(p)	((p)->desc_size == AVE_DESC_SIZE_64)
> +
> +enum desc_id {
> +	AVE_DESCID_TX = 0,
> +	AVE_DESCID_RX,
> +};
> +
> +enum desc_state {
> +	AVE_DESC_STOP = 0,
> +	AVE_DESC_START,
> +	AVE_DESC_RX_SUSPEND,
> +	AVE_DESC_RX_PERMIT,
> +};
> +
> +struct ave_desc {
> +	struct sk_buff	*skbs;
> +	dma_addr_t	skbs_dma;
> +	size_t		skbs_dmalen;
> +};
> +
> +struct ave_desc_info {
> +	u32	ndesc;		/* number of descriptor */
> +	u32	daddr;		/* start address of descriptor */
> +	u32	proc_idx;	/* index of processing packet */
> +	u32	done_idx;	/* index of processed packet */
> +	struct ave_desc *desc;	/* skb info related descriptor */
> +};
> +
> +struct ave_private {
> +	int			phy_id;
> +	unsigned int		desc_size;
> +	u32			msg_enable;
> +	struct clk		*clk;
> +	phy_interface_t		phy_mode;
> +	struct phy_device	*phydev;
> +	struct mii_bus		*mdio;
> +	struct net_device_stats	stats;
> +	bool			internal_phy_interrupt;
> +
> +	/* NAPI support */
> +	struct net_device	*ndev;
> +	struct napi_struct	napi_rx;
> +	struct napi_struct	napi_tx;
> +
> +	/* descriptor */
> +	struct ave_desc_info	rx;
> +	struct ave_desc_info	tx;
> +};
> +
> +static inline u32 ave_r32(struct net_device *ndev, u32 offset)
> +{
> +	void __iomem *addr = (void __iomem *)ndev->base_addr;
> +
> +	return readl_relaxed(addr + offset);
> +}

Don't do this, ndev->base_addr is convenient, but is now deprecated
(unlike ISA cards, you can't change this anymore) instead, just pass a
reference to an ave_private structure and store the base register
pointer there.

> +
> +static inline void ave_w32(struct net_device *ndev, u32 offset, u32 value)
> +{
> +	void __iomem *addr = (void __iomem *)ndev->base_addr;
> +
> +	writel_relaxed(value, addr + offset);
> +}

Same here.

> +
> +static inline u32 ave_rdesc(struct net_device *ndev, enum desc_id id,
> +			    int entry, int offset)
> +{
> +	struct ave_private *priv = netdev_priv(ndev);
> +	u32 addr = (id == AVE_DESCID_TX) ? priv->tx.daddr : priv->rx.daddr;
> +
> +	addr += entry * priv->desc_size + offset;
> +
> +	return ave_r32(ndev, addr);
> +}
> +
> +static inline void ave_wdesc(struct net_device *ndev, enum desc_id id,
> +			     int entry, int offset, u32 val)
> +{
> +	struct ave_private *priv = netdev_priv(ndev);
> +	u32 addr = (id == AVE_DESCID_TX) ? priv->tx.daddr : priv->rx.daddr;
> +
> +	addr += entry * priv->desc_size + offset;
> +
> +	ave_w32(ndev, addr, val);
> +}
> +
> +static void ave_wdesc_addr(struct net_device *ndev, enum desc_id id,
> +			   int entry, int offset, dma_addr_t paddr)
> +{
> +	struct ave_private *priv = netdev_priv(ndev);
> +
> +	ave_wdesc(ndev, id, entry, offset, (u32)((u64)paddr & 0xFFFFFFFFULL));

lower_32_bits()

> +	if (IS_DESC_64BIT(priv))
> +		ave_wdesc(ndev, id,
> +			  entry, offset + 4, (u32)((u64)paddr >> 32));

upper_32_bits()

> +	else if ((u64)paddr > (u64)U32_MAX)
> +		netdev_warn(ndev, "DMA address exceeds the address space\n");
> +}
> +
> +static void ave_get_fwversion(struct net_device *ndev, char *buf, int len)
> +{
> +	u32 major, minor;
> +
> +	major = (ave_r32(ndev, AVE_VR) & GENMASK(15, 8)) >> 8;
> +	minor = (ave_r32(ndev, AVE_VR) & GENMASK(7, 0));
> +	snprintf(buf, len, "v%u.%u", major, minor);
> +}
> +
> +static void ave_get_drvinfo(struct net_device *ndev,
> +			    struct ethtool_drvinfo *info)
> +{
> +	struct device *dev = ndev->dev.parent;
> +
> +	strlcpy(info->driver, dev->driver->name, sizeof(info->driver));
> +	strlcpy(info->bus_info, dev_name(dev), sizeof(info->bus_info));

bus_info would likely be platform, since this is a memory mapped
peripheral, right?

> +	ave_get_fwversion(ndev, info->fw_version, sizeof(info->fw_version));
> +}
> +
> +static int ave_nway_reset(struct net_device *ndev)
> +{
> +	return genphy_restart_aneg(ndev->phydev);
> +}

You can just set your ethtool_ops::nway_reset to be
phy_ethtool_nway_reset() which does additional checks.

> +
> +static u32 ave_get_link(struct net_device *ndev)
> +{
> +	int err;
> +
> +	err = genphy_update_link(ndev->phydev);
> +	if (err)
> +		return ethtool_op_get_link(ndev);

No, calling genphy_update_link() is bogus see:

e69e46261063a25c3907bed16a2e9d18b115d1fd ("net: dsa: Do not clobber PHY
link outside of state machine")

> +
> +	return ndev->phydev->link;

This can just be ethtool_op_get_link()

> +}
> +
> +static u32 ave_get_msglevel(struct net_device *ndev)
> +{
> +	struct ave_private *priv = netdev_priv(ndev);
> +
> +	return priv->msg_enable;
> +}
> +
> +static void ave_set_msglevel(struct net_device *ndev, u32 val)
> +{
> +	struct ave_private *priv = netdev_priv(ndev);
> +
> +	priv->msg_enable = val;
> +}
> +
> +static void ave_get_wol(struct net_device *ndev,
> +			struct ethtool_wolinfo *wol)
> +{
> +	wol->supported = 0;
> +	wol->wolopts   = 0;
> +	phy_ethtool_get_wol(ndev->phydev, wol);

This can be called before you successfully connected to a PHY so you
need to check that ndev->phydev is not NULL at the very least.

> +}
> +
> +static int ave_set_wol(struct net_device *ndev,
> +		       struct ethtool_wolinfo *wol)
> +{
> +	if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE))
> +		return -EOPNOTSUPP;
> +
> +	return phy_ethtool_set_wol(ndev->phydev, wol);

Same here.


> +
> +static int ave_mdio_busywait(struct net_device *ndev)
> +{
> +	int ret = 1, loop = 100;
> +	u32 mdiosr;
> +
> +	/* wait until completion */
> +	while (1) {

Since you are already bound by the number of times you allow this look,
just make that a clear condition for the while() loop to exit.

> +		mdiosr = ave_r32(ndev, AVE_MDIOSR);
> +		if (!(mdiosr & AVE_MDIOSR_STS))
> +			break;
> +
> +		usleep_range(10, 20);
> +		if (!loop--) {
> +			netdev_err(ndev,
> +				   "failed to read from MDIO (status:0x%08x)\n",
> +				   mdiosr);
> +			ret = 0;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int ave_mdiobus_read(struct mii_bus *bus, int phyid, int regnum)
> +{
> +	struct net_device *ndev = bus->priv;
> +	u32 mdioctl;
> +
> +	/* write address */
> +	ave_w32(ndev, AVE_MDIOAR, (phyid << 8) | regnum);
> +
> +	/* read request */
> +	mdioctl = ave_r32(ndev, AVE_MDIOCTR);
> +	ave_w32(ndev, AVE_MDIOCTR, mdioctl | AVE_MDIOCTR_RREQ);
> +
> +	if (!ave_mdio_busywait(ndev)) {
> +		netdev_err(ndev, "phy-%d reg-%x read failed\n",
> +			   phyid, regnum);
> +		return 0xffff;
> +	}
> +
> +	return ave_r32(ndev, AVE_MDIORDR) & GENMASK(15, 0);
> +}
> +
> +static int ave_mdiobus_write(struct mii_bus *bus,
> +			     int phyid, int regnum, u16 val)
> +{
> +	struct net_device *ndev = bus->priv;
> +	u32 mdioctl;
> +
> +	/* write address */
> +	ave_w32(ndev, AVE_MDIOAR, (phyid << 8) | regnum);
> +
> +	/* write data */
> +	ave_w32(ndev, AVE_MDIOWDR, val);
> +
> +	/* write request */
> +	mdioctl = ave_r32(ndev, AVE_MDIOCTR);
> +	ave_w32(ndev, AVE_MDIOCTR, mdioctl | AVE_MDIOCTR_WREQ);
> +
> +	if (!ave_mdio_busywait(ndev)) {
> +		netdev_err(ndev, "phy-%d reg-%x write failed\n",
> +			   phyid, regnum);
> +		return -1;
> +	}

Just propagate the return value of ave_mdio_busywait().

> +
> +	return 0;
> +}
> +
> +static dma_addr_t ave_dma_map(struct net_device *ndev, struct ave_desc *desc,
> +			      void *ptr, size_t len,
> +			      enum dma_data_direction dir)
> +{
> +	dma_addr_t paddr;
> +
> +	paddr = dma_map_single(ndev->dev.parent, ptr, len, dir);
> +	if (dma_mapping_error(ndev->dev.parent, paddr)) {
> +		desc->skbs_dma = 0;
> +		paddr = (dma_addr_t)virt_to_phys(ptr);

Why do you do that? If dma_map_single() failed, that's it, game over,
you need to discad the packet, not assume that it is in the kernel's
linear mapping!

> +	} else {
> +		desc->skbs_dma = paddr;
> +		desc->skbs_dmalen = len;
> +	}
> +
> +	return paddr;
> +}
> +
> +static void ave_dma_unmap(struct net_device *ndev, struct ave_desc *desc,
> +			  enum dma_data_direction dir)
> +{
> +	if (!desc->skbs_dma)
> +		return;
> +
> +	dma_unmap_single(ndev->dev.parent,
> +			 desc->skbs_dma, desc->skbs_dmalen, dir);
> +	desc->skbs_dma = 0;
> +}
> +
> +/* Set Rx descriptor and memory */
> +static int ave_set_rxdesc(struct net_device *ndev, int entry)
> +{
> +	struct ave_private *priv = netdev_priv(ndev);
> +	struct sk_buff *skb;
> +	unsigned long align;
> +	dma_addr_t paddr;
> +	void *buffptr;
> +	int ret = 0;
> +
> +	skb = priv->rx.desc[entry].skbs;
> +	if (!skb) {
> +		skb = netdev_alloc_skb_ip_align(ndev,
> +						AVE_MAX_ETHFRAME + NET_SKB_PAD);
> +		if (!skb) {
> +			netdev_err(ndev, "can't allocate skb for Rx\n");
> +			return -ENOMEM;
> +		}
> +	}
> +
> +	/* set disable to cmdsts */
> +	ave_wdesc(ndev, AVE_DESCID_RX, entry, 0, AVE_STS_INTR | AVE_STS_OWN);
> +
> +	/* align skb data for cache size */
> +	align = (unsigned long)skb_tail_pointer(skb) & (NET_SKB_PAD - 1);
> +	align = NET_SKB_PAD - align;
> +	skb_reserve(skb, align);
> +	buffptr = (void *)skb_tail_pointer(skb);

Are you positive you need this? Because by default, the networking stack
will align to the maximum between your L1 cache line size and 64 bytes,
which should be a pretty good alignment guarantee.

> +
> +	paddr = ave_dma_map(ndev, &priv->rx.desc[entry], buffptr,
> +			    AVE_MAX_ETHFRAME + NET_IP_ALIGN, DMA_FROM_DEVICE);

This needs to be checked, as mentioned before, you can't just assume the
linear virtual map is going to be satisfactory.

> +	priv->rx.desc[entry].skbs = skb;
> +
> +	/* set buffer pointer */
> +	ave_wdesc_addr(ndev, AVE_DESCID_RX, entry, 4, paddr);

OK, so 4 is an offset, can you add a define for that so it's clear it is
not an address size instead?

> +
> +	/* set enable to cmdsts */
> +	ave_wdesc(ndev, AVE_DESCID_RX,
> +		  entry, 0, AVE_STS_INTR | AVE_MAX_ETHFRAME);
> +
> +	return ret;
> +}
> +
> +/* Switch state of descriptor */
> +static int ave_desc_switch(struct net_device *ndev, enum desc_state state)
> +{
> +	int counter;
> +	u32 val;
> +
> +	switch (state) {
> +	case AVE_DESC_START:
> +		ave_w32(ndev, AVE_DESCC, AVE_DESCC_TD | AVE_DESCC_RD0);
> +		break;
> +
> +	case AVE_DESC_STOP:
> +		ave_w32(ndev, AVE_DESCC, 0);
> +		counter = 0;
> +		while (1) {
> +			usleep_range(100, 150);
> +			if (!ave_r32(ndev, AVE_DESCC))
> +				break;
> +
> +			counter++;
> +			if (counter > 100) {
> +				netdev_err(ndev, "can't stop descriptor\n");
> +				return -EBUSY;
> +			}
> +		}

Same here, pleas rewrite the loop so the exit condition is clear.

> +		break;
> +
> +	case AVE_DESC_RX_SUSPEND:
> +		val = ave_r32(ndev, AVE_DESCC);
> +		val |= AVE_DESCC_RDSTP;
> +		val &= AVE_DESCC_CTRL_MASK;

Should not this be a &= ~AVE_DESCC_CTRL_MASK? OK maybe not.

> +		ave_w32(ndev, AVE_DESCC, val);
> +
> +		counter = 0;
> +		while (1) {
> +			usleep_range(100, 150);
> +			val = ave_r32(ndev, AVE_DESCC);
> +			if (val & (AVE_DESCC_RDSTP << 16))
> +				break;
> +
> +			counter++;
> +			if (counter > 1000) {
> +				netdev_err(ndev, "can't suspend descriptor\n");
> +				return -EBUSY;
> +			}
> +		}
> +		break;

Same here, please rewrite with the counter as an exit condition.

> +
> +	case AVE_DESC_RX_PERMIT:
> +		val = ave_r32(ndev, AVE_DESCC);
> +		val &= ~AVE_DESCC_RDSTP;
> +		val &= AVE_DESCC_CTRL_MASK;
> +		ave_w32(ndev, AVE_DESCC, val);
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ave_tx_completion(struct net_device *ndev)
> +{
> +	struct ave_private *priv = netdev_priv(ndev);
> +	u32 proc_idx, done_idx, ndesc, val;
> +	int freebuf_flag = 0;
> +
> +	proc_idx = priv->tx.proc_idx;
> +	done_idx = priv->tx.done_idx;
> +	ndesc    = priv->tx.ndesc;
> +
> +	/* free pre stored skb from done to proc */
> +	while (proc_idx != done_idx) {
> +		/* get cmdsts */
> +		val = ave_rdesc(ndev, AVE_DESCID_TX, done_idx, 0);
> +
> +		/* do nothing if owner is HW */
> +		if (val & AVE_STS_OWN)
> +			break;
> +
> +		/* check Tx status and updates statistics */
> +		if (val & AVE_STS_OK) {
> +			priv->stats.tx_bytes += val & AVE_STS_PKTLEN_TX;

AVE_STS_PKTLEN_TX should be suffixed with _MASK to make it clear this is
a bitmask.

> +
> +			/* success */
> +			if (val & AVE_STS_LAST)
> +				priv->stats.tx_packets++;
> +		} else {
> +			/* error */
> +			if (val & AVE_STS_LAST) {
> +				priv->stats.tx_errors++;
> +				if (val & (AVE_STS_OWC | AVE_STS_EC))
> +					priv->stats.collisions++;
> +			}
> +		}
> +
> +		/* release skb */
> +		if (priv->tx.desc[done_idx].skbs) {
> +			ave_dma_unmap(ndev, &priv->tx.desc[done_idx],
> +				      DMA_TO_DEVICE);
> +			dev_consume_skb_any(priv->tx.desc[done_idx].skbs);

Kudos for using dev_consume_skb_any()!

> +			priv->tx.desc[done_idx].skbs = NULL;
> +			freebuf_flag++;
> +		}
> +		done_idx = (done_idx + 1) % ndesc;
> +	}
> +
> +	priv->tx.done_idx = done_idx;
> +
> +	/* wake queue for freeing buffer */
> +	if (netif_queue_stopped(ndev))
> +			if (freebuf_flag)
> +				netif_wake_queue(ndev);

This can be simplified to:

	if (netif_queue_stopped(ndev) && freebuf_flag)
		netif_wake_queue(ndev)

because checking for netif_running() is implicit by actually getting
called here, this would not happen if the network interface was not
operational.

> +static irqreturn_t ave_interrupt(int irq, void *netdev)
> +{
> +	struct net_device *ndev = (struct net_device *)netdev;
> +	struct ave_private *priv = netdev_priv(ndev);
> +	u32 gimr_val, gisr_val;
> +
> +	gimr_val = ave_irq_disable_all(ndev);
> +
> +	/* get interrupt status */
> +	gisr_val = ave_r32(ndev, AVE_GISR);
> +
> +	/* PHY */
> +	if (gisr_val & AVE_GI_PHY) {
> +		ave_w32(ndev, AVE_GISR, AVE_GI_PHY);
> +		if (priv->internal_phy_interrupt)
> +			phy_mac_interrupt(ndev->phydev, ndev->phydev->link);

This is not correct you should be telling the PHY the new link state. If
you cannot, because what happens here is really that the PHY interrupt
is routed to your MAC controller, then what I would suggest doing is the
following: create an interrupt controller domain which allows the PHY
driver to manage the interrupt line using normal request_irq().


> +static int ave_poll_tx(struct napi_struct *napi, int budget)
> +{
> +	struct ave_private *priv;
> +	struct net_device *ndev;
> +	int num;
> +
> +	priv = container_of(napi, struct ave_private, napi_tx);
> +	ndev = priv->ndev;
> +
> +	num = ave_tx_completion(ndev);
> +	if (num < budget) {

TX reclamation should not be bound against the budget, always process
all packets that have been successfully submitted.

> +		napi_complete(napi);
> +
> +		/* enable Tx interrupt when NAPI finishes */
> +		ave_irq_enable(ndev, AVE_GI_TX);
> +	}
> +
> +	return num;
> +}
> +

> +static void ave_adjust_link(struct net_device *ndev)
> +{
> +	struct ave_private *priv = netdev_priv(ndev);
> +	struct phy_device *phydev = ndev->phydev;
> +	u32 val, txcr, rxcr, rxcr_org;
> +
> +	/* set RGMII speed */
> +	val = ave_r32(ndev, AVE_TXCR);
> +	val &= ~(AVE_TXCR_TXSPD_100 | AVE_TXCR_TXSPD_1G);
> +
> +	if (priv->phy_mode == PHY_INTERFACE_MODE_RGMII &&
> +	    phydev->speed == SPEED_1000)
> +		val |= AVE_TXCR_TXSPD_1G;

Using phy_interface_is_rgmii() would be more robust here.

> +	else if (phydev->speed == SPEED_100)
> +		val |= AVE_TXCR_TXSPD_100;
> +
> +	ave_w32(ndev, AVE_TXCR, val);
> +
> +	/* set RMII speed (100M/10M only) */
> +	if (priv->phy_mode != PHY_INTERFACE_MODE_RGMII) {

PHY_INTERFACE_MODE_MII, PHY_INTERFACE_MODE_REVMII,
PHY_INTERFACE_MODE_RMII would all qualify here presumably so you need
this check to be more restrictive to just the modes that you support.

> +		val = ave_r32(ndev, AVE_LINKSEL);
> +		if (phydev->speed == SPEED_10)
> +			val &= ~AVE_LINKSEL_100M;
> +		else
> +			val |= AVE_LINKSEL_100M;
> +		ave_w32(ndev, AVE_LINKSEL, val);
> +	}
> +
> +	/* check current RXCR/TXCR */
> +	rxcr = ave_r32(ndev, AVE_RXCR);
> +	txcr = ave_r32(ndev, AVE_TXCR);
> +	rxcr_org = rxcr;
> +
> +	if (phydev->duplex)
> +		rxcr |= AVE_RXCR_FDUPEN;
> +	else
> +		rxcr &= ~AVE_RXCR_FDUPEN;
> +
> +	if (phydev->pause) {
> +		rxcr |= AVE_RXCR_FLOCTR;
> +		txcr |= AVE_TXCR_FLOCTR;

You must also check for phydev->asym_pause and keep in mind that
phydev->pause and phydev->asym_pause reflect what the link partner
reflects, you need to implement .get_pauseparam and .set_pauseparam or
default to flow control ON (which is what you are doing here).

> +	} else {
> +		rxcr &= ~AVE_RXCR_FLOCTR;
> +		txcr &= ~AVE_TXCR_FLOCTR;
> +	}
> +
> +	if (rxcr_org != rxcr) {
> +		/* disable Rx mac */
> +		ave_w32(ndev, AVE_RXCR, rxcr & ~AVE_RXCR_RXEN);
> +		/* change and enable TX/Rx mac */
> +		ave_w32(ndev, AVE_TXCR, txcr);
> +		ave_w32(ndev, AVE_RXCR, rxcr);
> +	}
> +
> +	if (phydev->link)
> +		netif_carrier_on(ndev);
> +	else
> +		netif_carrier_off(ndev);

This is not necessary, PHYLIB is specifically taking care of that.

> +
> +	phy_print_status(phydev);
> +}
> +
> +static int ave_init(struct net_device *ndev)
> +{
> +	struct ave_private *priv = netdev_priv(ndev);
> +	struct device *dev = ndev->dev.parent;
> +	struct device_node *phy_node, *np = dev->of_node;
> +	struct phy_device *phydev;
> +	const void *mac_addr;
> +	u32 supported;
> +
> +	/* get mac address */
> +	mac_addr = of_get_mac_address(np);
> +	if (mac_addr)
> +		ether_addr_copy(ndev->dev_addr, mac_addr);
> +
> +	/* if the mac address is invalid, use random mac address */
> +	if (!is_valid_ether_addr(ndev->dev_addr)) {
> +		eth_hw_addr_random(ndev);
> +		dev_warn(dev, "Using random MAC address: %pM\n",
> +			 ndev->dev_addr);
> +	}
> +
> +	/* attach PHY with MAC */
> +	phy_node =  of_get_next_available_child(np, NULL);

You should be using a "phy-handle" property to connect to a designated
PHY, not the next child DT node.

> +	phydev = of_phy_connect(ndev, phy_node,
> +				ave_adjust_link, 0, priv->phy_mode);
> +	if (!phydev) {
> +		dev_err(dev, "could not attach to PHY\n");
> +		return -ENODEV;
> +	}
> +	of_node_put(phy_node);
> +
> +	priv->phydev = phydev;
> +	phydev->autoneg = AUTONEG_ENABLE;
> +	phydev->speed = 0;
> +	phydev->duplex = 0;

This is not necessary.

> +
> +	dev_info(dev, "connected to %s phy with id 0x%x\n",
> +		 phydev->drv->name, phydev->phy_id);
> +
> +	if (priv->phy_mode != PHY_INTERFACE_MODE_RGMII) {
> +		supported = phydev->supported;
> +		phydev->supported &= ~PHY_GBIT_FEATURES;
> +		phydev->supported |= supported & PHY_BASIC_FEATURES;

One of these two statements is redundant here.

> +	}
> +
> +	/* PHY interrupt stop instruction is needed because the interrupt
> +	 * continues to assert.
> +	 */
> +	phy_stop_interrupts(phydev);

Wait, what?

> +
> +	/* When PHY driver can't handle its interrupt directly,
> +	 * interrupt request always fails and polling method is used
> +	 * alternatively. In this case, the libphy says
> +	 * "libphy: uniphier-mdio: Can't get IRQ -1 (PHY)".
> +	 */
> +	phy_start_interrupts(phydev);
> +
> +	phy_start_aneg(phydev);

No, no, phy_start() would take care of all of that correctly for you,
you don't have have to do it just there because ave_open() eventually
calls phy_start() for you, so just drop these two calls.

> +
> +	return 0;
> +}
> +
> +static void ave_uninit(struct net_device *ndev)
> +{
> +	struct ave_private *priv = netdev_priv(ndev);
> +
> +	phy_stop_interrupts(priv->phydev);

You are missing a call to phy_stop() here, calling phy_stop_interrupts()
directly should not happen.

> +	phy_disconnect(priv->phydev);
> +}
> +
> +static int ave_open(struct net_device *ndev)
> +{
> +	struct ave_private *priv = netdev_priv(ndev);
> +	int entry;
> +	u32 val;
> +
> +	/* initialize Tx work */
> +	priv->tx.proc_idx = 0;
> +	priv->tx.done_idx = 0;
> +	memset(priv->tx.desc, 0, sizeof(struct ave_desc) * priv->tx.ndesc);
> +
> +	/* initialize Tx descriptor */
> +	for (entry = 0; entry < priv->tx.ndesc; entry++) {
> +		ave_wdesc(ndev, AVE_DESCID_TX, entry, 0, 0);
> +		ave_wdesc_addr(ndev, AVE_DESCID_TX, entry, 4, 0);
> +	}
> +	ave_w32(ndev, AVE_TXDC, AVE_TXDC_ADDR_START
> +		| (((priv->tx.ndesc * priv->desc_size) << 16) & AVE_TXDC_SIZE));
> +
> +	/* initialize Rx work */
> +	priv->rx.proc_idx = 0;
> +	priv->rx.done_idx = 0;
> +	memset(priv->rx.desc, 0, sizeof(struct ave_desc) * priv->rx.ndesc);
> +
> +	/* initialize Rx descriptor and buffer */
> +	for (entry = 0; entry < priv->rx.ndesc; entry++) {
> +		if (ave_set_rxdesc(ndev, entry))
> +			break;
> +	}
> +	ave_w32(ndev, AVE_RXDC0, AVE_RXDC0_ADDR_START
> +	    | (((priv->rx.ndesc * priv->desc_size) << 16) & AVE_RXDC0_SIZE));
> +
> +	/* enable descriptor */
> +	ave_desc_switch(ndev, AVE_DESC_START);
> +
> +	/* initialize filter */
> +	ave_pfsel_init(ndev);
> +
> +	/* set macaddr */
> +	val = le32_to_cpu(((u32 *)ndev->dev_addr)[0]);
> +	ave_w32(ndev, AVE_RXMAC1R, val);
> +	val = (u32)le16_to_cpu(((u16 *)ndev->dev_addr)[2]);
> +	ave_w32(ndev, AVE_RXMAC2R, val);
> +
> +	/* set Rx configuration */
> +	/* full duplex, enable pause drop, enalbe flow control */
> +	val = AVE_RXCR_RXEN | AVE_RXCR_FDUPEN | AVE_RXCR_DRPEN |
> +		AVE_RXCR_FLOCTR | (AVE_MAX_ETHFRAME & AVE_RXCR_MPSIZ_MASK);
> +	ave_w32(ndev, AVE_RXCR, val);
> +
> +	/* set Tx configuration */
> +	/* enable flow control, disable loopback */
> +	ave_w32(ndev, AVE_TXCR, AVE_TXCR_FLOCTR);
> +
> +	/* enable timer, clear EN,INTM, and mask interval unit(BSCK) */
> +	val = ave_r32(ndev, AVE_IIRQC) & AVE_IIRQC_BSCK;
> +	val |= AVE_IIRQC_EN0 | (AVE_INTM_COUNT << 16);
> +	ave_w32(ndev, AVE_IIRQC, val);
> +
> +	/* set interrupt mask */
> +	val = AVE_GI_RXIINT | AVE_GI_RXOVF | AVE_GI_TX;
> +	val |= (priv->internal_phy_interrupt) ? AVE_GI_PHY : 0;
> +	ave_irq_restore(ndev, val);
> +
> +	napi_enable(&priv->napi_rx);
> +	napi_enable(&priv->napi_tx);
> +
> +	phy_start(ndev->phydev);
> +	netif_start_queue(ndev);
> +
> +	return 0;
> +}
> +
> +static int ave_stop(struct net_device *ndev)
> +{
> +	struct ave_private *priv = netdev_priv(ndev);
> +	int entry;
> +
> +	/* disable all interrupt */
> +	ave_irq_disable_all(ndev);
> +	disable_irq(ndev->irq);
> +
> +	netif_tx_disable(ndev);
> +	phy_stop(ndev->phydev);
> +	napi_disable(&priv->napi_tx);
> +	napi_disable(&priv->napi_rx);
> +
> +	/* free Tx buffer */
> +	for (entry = 0; entry < priv->tx.ndesc; entry++) {
> +		if (!priv->tx.desc[entry].skbs)
> +			continue;
> +
> +		ave_dma_unmap(ndev, &priv->tx.desc[entry], DMA_TO_DEVICE);
> +		dev_kfree_skb_any(priv->tx.desc[entry].skbs);
> +		priv->tx.desc[entry].skbs = NULL;
> +	}
> +	priv->tx.proc_idx = 0;
> +	priv->tx.done_idx = 0;
> +
> +	/* free Rx buffer */
> +	for (entry = 0; entry < priv->rx.ndesc; entry++) {
> +		if (!priv->rx.desc[entry].skbs)
> +			continue;
> +
> +		ave_dma_unmap(ndev, &priv->rx.desc[entry], DMA_FROM_DEVICE);
> +		dev_kfree_skb_any(priv->rx.desc[entry].skbs);
> +		priv->rx.desc[entry].skbs = NULL;
> +	}
> +	priv->rx.proc_idx = 0;
> +	priv->rx.done_idx = 0;
> +
> +	return 0;
> +}
> +
> +static int ave_start_xmit(struct sk_buff *skb, struct net_device *ndev)
> +{
> +	struct ave_private *priv = netdev_priv(ndev);
> +	u32 proc_idx, done_idx, ndesc, cmdsts;
> +	int freepkt;
> +	unsigned char *buffptr = NULL; /* buffptr for descriptor */
> +	unsigned int len;
> +	dma_addr_t paddr;
> +
> +	proc_idx = priv->tx.proc_idx;
> +	done_idx = priv->tx.done_idx;
> +	ndesc = priv->tx.ndesc;
> +	freepkt = ((done_idx + ndesc - 1) - proc_idx) % ndesc;
> +
> +	/* not enough entry, then we stop queue */
> +	if (unlikely(freepkt < 2)) {
> +		netif_stop_queue(ndev);
> +		if (unlikely(freepkt < 1))
> +			return NETDEV_TX_BUSY;
> +	}
> +
> +	priv->tx.desc[proc_idx].skbs = skb;
> +
> +	/* add padding for short packet */
> +	if (skb_padto(skb, ETH_ZLEN)) {
> +		dev_kfree_skb_any(skb);
> +		return NETDEV_TX_OK;
> +	}
> +
> +	buffptr = skb->data - NET_IP_ALIGN;
> +	len = max_t(unsigned int, ETH_ZLEN, skb->len);
> +
> +	paddr = ave_dma_map(ndev, &priv->tx.desc[proc_idx], buffptr,
> +			    len + NET_IP_ALIGN, DMA_TO_DEVICE);
> +	paddr += NET_IP_ALIGN;
> +
> +	/* set buffer address to descriptor */
> +	ave_wdesc_addr(ndev, AVE_DESCID_TX, proc_idx, 4, paddr);
> +
> +	/* set flag and length to send */
> +	cmdsts = AVE_STS_OWN | AVE_STS_1ST | AVE_STS_LAST
> +		| (len & AVE_STS_PKTLEN_TX);
> +
> +	/* set interrupt per AVE_FORCE_TXINTCNT or when queue is stopped */
> +	if (!(proc_idx % AVE_FORCE_TXINTCNT) || netif_queue_stopped(ndev))
> +		cmdsts |= AVE_STS_INTR;
> +
> +	/* disable checksum calculation when skb doesn't calurate checksum */
> +	if (skb->ip_summed == CHECKSUM_NONE ||
> +	    skb->ip_summed == CHECKSUM_UNNECESSARY)
> +		cmdsts |= AVE_STS_NOCSUM;
> +
> +	/* set cmdsts */
> +	ave_wdesc(ndev, AVE_DESCID_TX, proc_idx, 0, cmdsts);
> +
> +	priv->tx.proc_idx = (proc_idx + 1) % ndesc;
> +
> +	return NETDEV_TX_OK;
> +}
> +
> +static int ave_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
> +{
> +	return phy_mii_ioctl(ndev->phydev, ifr, cmd);
> +}
> +
> +static void ave_set_rx_mode(struct net_device *ndev)
> +{
> +	int count, mc_cnt = netdev_mc_count(ndev);
> +	struct netdev_hw_addr *hw_adr;
> +	u32 val;
> +	u8 v4multi_macadr[6] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
> +	u8 v6multi_macadr[6] = { 0x33, 0x00, 0x00, 0x00, 0x00, 0x00 };
> +
> +	/* MAC addr filter enable for promiscious mode */
> +	val = ave_r32(ndev, AVE_RXCR);
> +	if (ndev->flags & IFF_PROMISC || !mc_cnt)
> +		val &= ~AVE_RXCR_AFEN;
> +	else
> +		val |= AVE_RXCR_AFEN;
> +	ave_w32(ndev, AVE_RXCR, val);
> +
> +	/* set all multicast address */
> +	if ((ndev->flags & IFF_ALLMULTI) || (mc_cnt > AVE_PF_MULTICAST_SIZE)) {
> +		ave_pfsel_macaddr_set(ndev, AVE_PFNUM_MULTICAST,
> +				      v4multi_macadr, 1);
> +		ave_pfsel_macaddr_set(ndev, AVE_PFNUM_MULTICAST + 1,
> +				      v6multi_macadr, 1);
> +	} else {
> +		/* stop all multicast filter */
> +		for (count = 0; count < AVE_PF_MULTICAST_SIZE; count++)
> +			ave_pfsel_stop(ndev, AVE_PFNUM_MULTICAST + count);
> +
> +		/* set multicast addresses */
> +		count = 0;
> +		netdev_for_each_mc_addr(hw_adr, ndev) {
> +			if (count == mc_cnt)
> +				break;
> +			ave_pfsel_macaddr_set(ndev, AVE_PFNUM_MULTICAST + count,
> +					      hw_adr->addr, 6);
> +			count++;
> +		}
> +	}
> +}
> +
> +static struct net_device_stats *ave_stats(struct net_device *ndev)
> +{
> +	struct ave_private *priv = netdev_priv(ndev);
> +	u32 drop_num = 0;
> +
> +	priv->stats.rx_errors = ave_r32(ndev, AVE_BFCR);
> +
> +	drop_num += ave_r32(ndev, AVE_RX0OVFFC);
> +	drop_num += ave_r32(ndev, AVE_SN5FC);
> +	drop_num += ave_r32(ndev, AVE_SN6FC);
> +	drop_num += ave_r32(ndev, AVE_SN7FC);
> +	priv->stats.rx_dropped = drop_num;
> +
> +	return &priv->stats;
> +}
> +
> +static int ave_set_mac_address(struct net_device *ndev, void *p)
> +{
> +	int ret = eth_mac_addr(ndev, p);
> +	u32 val;
> +
> +	if (ret)
> +		return ret;
> +
> +	/* set macaddr */
> +	val = le32_to_cpu(((u32 *)ndev->dev_addr)[0]);
> +	ave_w32(ndev, AVE_RXMAC1R, val);
> +	val = (u32)le16_to_cpu(((u16 *)ndev->dev_addr)[2]);
> +	ave_w32(ndev, AVE_RXMAC2R, val);
> +
> +	/* pfsel unicast entry */
> +	ave_pfsel_macaddr_set(ndev, AVE_PFNUM_UNICAST, ndev->dev_addr, 6);
> +
> +	return 0;
> +}
> +
> +static const struct net_device_ops ave_netdev_ops = {
> +	.ndo_init		= ave_init,
> +	.ndo_uninit		= ave_uninit,
> +	.ndo_open		= ave_open,
> +	.ndo_stop		= ave_stop,
> +	.ndo_start_xmit		= ave_start_xmit,
> +	.ndo_do_ioctl		= ave_ioctl,
> +	.ndo_set_rx_mode	= ave_set_rx_mode,
> +	.ndo_get_stats		= ave_stats,
> +	.ndo_set_mac_address	= ave_set_mac_address,
> +};
> +
> +static int ave_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	u32 desc_bits, ave_id;
> +	struct reset_control *rst;
> +	struct ave_private *priv;
> +	phy_interface_t phy_mode;
> +	struct net_device *ndev;
> +	struct resource	*res;
> +	void __iomem *base;
> +	int irq, ret = 0;
> +	char buf[ETHTOOL_FWVERS_LEN];
> +
> +	/* get phy mode */
> +	phy_mode = of_get_phy_mode(np);
> +	if (phy_mode < 0) {
> +		dev_err(dev, "phy-mode not found\n");
> +		return -EINVAL;
> +	}
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0) {
> +		dev_err(dev, "IRQ not found\n");
> +		return irq;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(base))
> +		return PTR_ERR(base);
> +
> +	/* alloc netdevice */
> +	ndev = alloc_etherdev(sizeof(struct ave_private));
> +	if (!ndev) {
> +		dev_err(dev, "can't allocate ethernet device\n");
> +		return -ENOMEM;
> +	}
> +
> +	ndev->base_addr = (unsigned long)base;

This is deprecated as mentioned earlier, just store this in
priv->base_adr or something.

> +	ndev->irq = irq;

Same here.

> +	ndev->netdev_ops = &ave_netdev_ops;
> +	ndev->ethtool_ops = &ave_ethtool_ops;
> +	SET_NETDEV_DEV(ndev, dev);
> +
> +	/* support hardware checksum */
> +	ndev->features    |= (NETIF_F_IP_CSUM | NETIF_F_RXCSUM);
> +	ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_RXCSUM);
> +
> +	ndev->max_mtu = AVE_MAX_ETHFRAME - (ETH_HLEN + ETH_FCS_LEN);
> +
> +	priv = netdev_priv(ndev);
> +	priv->ndev = ndev;
> +	priv->msg_enable = netif_msg_init(-1, AVE_DEFAULT_MSG_ENABLE);
> +	priv->phy_mode = phy_mode;
> +
> +	/* get bits of descriptor from devicetree */
> +	of_property_read_u32(np, "socionext,desc-bits", &desc_bits);
> +	priv->desc_size = AVE_DESC_SIZE_32;
> +	if (desc_bits == 64)
> +		priv->desc_size = AVE_DESC_SIZE_64;
> +	else if (desc_bits != 32)
> +		dev_warn(dev, "Defaulting to 32bit descriptor\n");

This should really be determined by the compatible string.

> +
> +	/* use internal phy interrupt */
> +	priv->internal_phy_interrupt =
> +		of_property_read_bool(np, "socionext,internal-phy-interrupt");

Same here.

> +
> +	/* setting private data for descriptor */
> +	priv->tx.daddr = IS_DESC_64BIT(priv) ? AVE_TXDM_64 : AVE_TXDM_32;
> +	priv->tx.ndesc = AVE_NR_TXDESC;
> +	priv->tx.desc = devm_kzalloc(dev,
> +				     sizeof(struct ave_desc) * priv->tx.ndesc,
> +				     GFP_KERNEL);
> +	if (!priv->tx.desc)
> +		return -ENOMEM;
> +
> +	priv->rx.daddr = IS_DESC_64BIT(priv) ? AVE_RXDM_64 : AVE_RXDM_32;
> +	priv->rx.ndesc = AVE_NR_RXDESC;
> +	priv->rx.desc = devm_kzalloc(dev,
> +				     sizeof(struct ave_desc) * priv->rx.ndesc,
> +				     GFP_KERNEL);
> +	if (!priv->rx.desc)
> +		return -ENOMEM;

If your network device driver is probed, but never used after that, that
is the network device is not open, you just this memory sitting for
nothing, you should consider moving that to ndo_open() time.

> +
> +	/* enable clock */
> +	priv->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(priv->clk))
> +		priv->clk = NULL;
> +	clk_prepare_enable(priv->clk);

Same here with the clock, the block is clocked, so it can consume some
amount of power, just do the necessary HW initialization with the clock
enabled, then defer until ndo_open() before turning it back on.

> +
> +	/* reset block */
> +	rst = devm_reset_control_get(dev, NULL);
> +	if (!IS_ERR_OR_NULL(rst)) {
> +		reset_control_deassert(rst);
> +		reset_control_put(rst);
> +	}

Ah so that's interesting, you need it clocked first, then reset, I guess
that works :)

> +
> +	/* reset mac and phy */
> +	ave_global_reset(ndev);
> +
> +	/* request interrupt */
> +	ret = devm_request_irq(dev, irq, ave_interrupt,
> +			       IRQF_SHARED, ndev->name, ndev);
> +	if (ret)
> +		goto err_req_irq;

Same here, this is usually moved to ndo_open() for network drivers, but
then remember not to use devm_, just normal request_irq() because it
need to be balanced in ndo_close().

This looks like a pretty good first submission, and there does not
appear to be any obvious functional problems!
-- 
Florian
--
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

* Re: ipset losing entries on its own
From: Akshat Kakkar @ 2017-09-08 19:24 UTC (permalink / raw)
  To: Denys Fedoryshchenko; +Cc: netdev, netdev-owner
In-Reply-To: <CAA5aLPgM9=VU4Cysy-LtN-uXPqvG00X2v8MP9EM5RtPVB6tGvw@mail.gmail.com>

Any more information needed?

^ 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