Netdev List
 help / color / mirror / Atom feed
* [PATCH v5 3/7] fs/splice: support compiling out splice-family syscalls
From: Pieter Smith @ 2014-11-25  7:19 UTC (permalink / raw)
  To: pieter-qeJ+1H9vRZbz+pZb47iToQ
  Cc: Michael S. Tsirkin, Trond Myklebust, Bertrand Jacquin,
	Oleg Nesterov, J. Bruce Fields, Eric Dumazet, Willem de Bruijn,
	蔡正龙, Jeff Layton, Tom Herbert,
	Alexei Starovoitov, Miklos Szeredi, Peter Foley, Hugh Dickins,
	Xiao Guangrong, Geert Uytterhoeven, Mel Gorman, Matt Turner,
	Paul E. McKenney, Alexander Duyck, open list:FUSE: FILESYSTEM...
In-Reply-To: <1416899996-21315-1-git-send-email-pieter-qeJ+1H9vRZbz+pZb47iToQ@public.gmane.org>

Many embedded systems will not need the splice-family syscalls (splice,
vmsplice, tee and sendfile). Omitting them saves space.  This adds a new EXPERT
config option CONFIG_SYSCALL_SPLICE (default y) to support compiling them out.

The goal is to completely compile out fs/splice along with the syscalls. To
achieve this, the remaining patch-set will deal with fs/splice exports. As far
as possible, the impact on other device drivers will be minimized so as to
reduce the overal maintenance burden of CONFIG_SYSCALL_SPLICE.

The use of exported functions will be solved by transparently mocking them out
with static inlines. Uses of the exported pipe_buf_operations struct however
require direct modification in fs/fuse and net/core. The next two patches will
deal with this.

The last change required before fs/splice can be comipled out is making fs/nfsd
aware of the lacking splice support in file-systems when CONFIG_SYSCALL_SPLICE
is undefined.

The bloat benefit of this patch given a tinyconfig is:

add/remove: 0/16 grow/shrink: 2/5 up/down: 114/-3693 (-3579)
function                                     old     new   delta
splice_direct_to_actor                       348     416     +68
splice_to_pipe                               371     417     +46
splice_from_pipe_next                        107     106      -1
fdput                                         11       -     -11
signal_pending                                39      26     -13
fdget                                         56      42     -14
user_page_pipe_buf_ops                        20       -     -20
user_page_pipe_buf_steal                      25       -     -25
file_end_write                                58      29     -29
file_start_write                              68      34     -34
pipe_to_user                                  43       -     -43
wakeup_pipe_readers                           54       -     -54
do_splice_to                                  87       -     -87
ipipe_prep.part                               92       -     -92
opipe_prep.part                              119       -    -119
sys_sendfile                                 122       -    -122
sys_sendfile64                               126       -    -126
sys_vmsplice                                 137       -    -137
vmsplice_to_user                             205       -    -205
sys_tee                                      491       -    -491
do_sendfile                                  492       -    -492
vmsplice_to_pipe                             558       -    -558
sys_splice                                  1020       -   -1020

Signed-off-by: Pieter Smith <pieter-qeJ+1H9vRZbz+pZb47iToQ@public.gmane.org>
---
 fs/splice.c     |  2 ++
 init/Kconfig    | 10 ++++++++++
 kernel/sys_ni.c |  8 ++++++++
 3 files changed, 20 insertions(+)

diff --git a/fs/splice.c b/fs/splice.c
index 44b201b..7c4c695 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -1316,6 +1316,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
 	return ret;
 }
 
+#ifdef CONFIG_SYSCALL_SPLICE
 static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
 			       struct pipe_inode_info *opipe,
 			       size_t len, unsigned int flags);
@@ -2200,4 +2201,5 @@ COMPAT_SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd,
 	return do_sendfile(out_fd, in_fd, NULL, count, 0);
 }
 #endif
+#endif
 
diff --git a/init/Kconfig b/init/Kconfig
index d811d5f..dec9819 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1571,6 +1571,16 @@ config NTP
 	  system clock to an NTP server, you can disable this option to save
 	  space.
 
+config SYSCALL_SPLICE
+	bool "Enable splice/vmsplice/tee/sendfile syscalls" if EXPERT
+	default y
+	help
+	  This option enables the splice, vmsplice, tee and sendfile syscalls. These
+	  are used by applications to: move data between buffers and arbitrary file
+	  descriptors; "copy" data between buffers; or copy data from userspace into
+	  buffers. If building an embedded system where no applications use these
+	  syscalls, you can disable this option to save space.
+
 config PCI_QUIRKS
 	default y
 	bool "Enable PCI quirk workarounds" if EXPERT
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index d2f5b00..25d5551 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -170,6 +170,14 @@ cond_syscall(sys_fstat);
 cond_syscall(sys_stat);
 cond_syscall(sys_uname);
 cond_syscall(sys_olduname);
+cond_syscall(sys_vmsplice);
+cond_syscall(sys_splice);
+cond_syscall(sys_tee);
+cond_syscall(sys_sendfile);
+cond_syscall(sys_sendfile64);
+cond_syscall(compat_sys_vmsplice);
+cond_syscall(compat_sys_sendfile);
+cond_syscall(compat_sys_sendfile64);
 
 /* arch-specific weak syscall entries */
 cond_syscall(sys_pciconfig_read);
-- 
2.1.0


------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=157005751&iu=/4140/ostg.clktrk

^ permalink raw reply related

* [PATCH v5 4/7] fs/fuse: support compiling out splice
From: Pieter Smith @ 2014-11-25  7:19 UTC (permalink / raw)
  To: pieter
  Cc: Josh Triplett, Alexander Duyck, Alexander Viro,
	Alexei Starovoitov, Andrew Morton, Bertrand Jacquin,
	Catalina Mocanu, Daniel Borkmann, David S. Miller, Eric Dumazet,
	Eric W. Biederman, Fabian Frederick,
	open list:FUSE: FILESYSTEM..., Geert Uytterhoeven, Hugh Dickins,
	Iulia Manda, Jan Beulich, J. Bruce Fields, Jeff Layton,
	open list:ABI/API, linux-fsdevel, linux-kernel
In-Reply-To: <1416899996-21315-1-git-send-email-pieter@boesman.nl>

To implement splice support, fs/fuse makes use of nosteal_pipe_buf_ops. This
struct is exported by fs/splice. The goal of the larger patch set is to
completely compile out fs/splice, so uses of the exported struct need to be
compiled out along with fs/splice.

This patch therefore compiles out splice support in fs/fuse when
CONFIG_SYSCALL_SPLICE is undefined.

Signed-off-by: Pieter Smith <pieter@boesman.nl>
---
 fs/fuse/dev.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index ca88731..e984302 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1191,8 +1191,9 @@ __releases(fc->lock)
  * request_end().  Otherwise add it to the processing list, and set
  * the 'sent' flag.
  */
-static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file,
-				struct fuse_copy_state *cs, size_t nbytes)
+static ssize_t __maybe_unused
+fuse_dev_do_read(struct fuse_conn *fc, struct file *file,
+		 struct fuse_copy_state *cs, size_t nbytes)
 {
 	int err;
 	struct fuse_req *req;
@@ -1291,6 +1292,7 @@ static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
 	return fuse_dev_do_read(fc, file, &cs, iov_length(iov, nr_segs));
 }
 
+#ifdef CONFIG_SYSCALL_SPLICE
 static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
 				    struct pipe_inode_info *pipe,
 				    size_t len, unsigned int flags)
@@ -1368,6 +1370,9 @@ out:
 	kfree(bufs);
 	return ret;
 }
+#else /* CONFIG_SYSCALL_SPLICE */
+#define fuse_dev_splice_read NULL
+#endif
 
 static int fuse_notify_poll(struct fuse_conn *fc, unsigned int size,
 			    struct fuse_copy_state *cs)
-- 
2.1.0

^ permalink raw reply related

* [PATCH v5 5/7] net/core: support compiling out splice
From: Pieter Smith @ 2014-11-25  7:19 UTC (permalink / raw)
  To: pieter-qeJ+1H9vRZbz+pZb47iToQ
  Cc: Michael S. Tsirkin, Trond Myklebust, Bertrand Jacquin,
	Oleg Nesterov, J. Bruce Fields, Eric Dumazet, Willem de Bruijn,
	蔡正龙, Jeff Layton, Tom Herbert,
	Alexei Starovoitov, Miklos Szeredi, Peter Foley, Hugh Dickins,
	Xiao Guangrong, Geert Uytterhoeven, Mel Gorman, Matt Turner,
	Paul E. McKenney, Alexander Duyck, open list:FUSE: FILESYSTEM...
In-Reply-To: <1416899996-21315-1-git-send-email-pieter-qeJ+1H9vRZbz+pZb47iToQ@public.gmane.org>

To implement splice support, net/core makes use of nosteal_pipe_buf_ops. This
struct is exported by fs/splice. The goal of the larger patch set is to
completely compile out fs/splice, so uses of the exported struct need to be
compiled out along with fs/splice.

This patch therefore compiles out splice support in net/core when
CONFIG_SYSCALL_SPLICE is undefined. The compiled out function skb_splice_bits
is transparently mocked out with a static inline. The greater patch set removes
userspace splice support so it cannot be called anyway.

Signed-off-by: Pieter Smith <pieter-qeJ+1H9vRZbz+pZb47iToQ@public.gmane.org>
---
 include/linux/skbuff.h | 10 ++++++++++
 net/core/skbuff.c      | 11 +++++++----
 2 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index a59d934..5cd636b 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2640,9 +2640,19 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
 int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);
 __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,
 			      int len, __wsum csum);
+#ifdef CONFIG_SYSCALL_SPLICE
 int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
 		    struct pipe_inode_info *pipe, unsigned int len,
 		    unsigned int flags);
+#else
+static inline int
+skb_splice_bits(struct sk_buff *skb, unsigned int offset,
+		struct pipe_inode_info *pipe, unsigned int len,
+		unsigned int flags)
+{
+	return -EPERM;
+}
+#endif
 void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
 unsigned int skb_zerocopy_headlen(const struct sk_buff *from);
 int skb_zerocopy(struct sk_buff *to, struct sk_buff *from,
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 61059a0..bb426d9 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1678,7 +1678,8 @@ EXPORT_SYMBOL(skb_copy_bits);
  * Callback from splice_to_pipe(), if we need to release some pages
  * at the end of the spd in case we error'ed out in filling the pipe.
  */
-static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i)
+static void __maybe_unused sock_spd_release(struct splice_pipe_desc *spd,
+					    unsigned int i)
 {
 	put_page(spd->pages[i]);
 }
@@ -1781,9 +1782,9 @@ static bool __splice_segment(struct page *page, unsigned int poff,
  * Map linear and fragment data from the skb to spd. It reports true if the
  * pipe is full or if we already spliced the requested length.
  */
-static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
-			      unsigned int *offset, unsigned int *len,
-			      struct splice_pipe_desc *spd, struct sock *sk)
+static bool __maybe_unused __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
+					     unsigned int *offset, unsigned int *len,
+					     struct splice_pipe_desc *spd, struct sock *sk)
 {
 	int seg;
 
@@ -1821,6 +1822,7 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
  * the frag list, if such a thing exists. We'd probably need to recurse to
  * handle that cleanly.
  */
+#ifdef CONFIG_SYSCALL_SPLICE
 int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
 		    struct pipe_inode_info *pipe, unsigned int tlen,
 		    unsigned int flags)
@@ -1876,6 +1878,7 @@ done:
 
 	return ret;
 }
+#endif /* CONFIG_SYSCALL_SPLICE */
 
 /**
  *	skb_store_bits - store bits from kernel buffer to skb
-- 
2.1.0


------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=157005751&iu=/4140/ostg.clktrk

^ permalink raw reply related

* [PATCH v5 6/7] fs/nfsd: support compiling out splice
From: Pieter Smith @ 2014-11-25  7:19 UTC (permalink / raw)
  To: pieter
  Cc: Josh Triplett, Alexander Duyck, Alexander Viro,
	Alexei Starovoitov, Andrew Morton, Bertrand Jacquin,
	Catalina Mocanu, Daniel Borkmann, David S. Miller, Eric Dumazet,
	Eric W. Biederman, Fabian Frederick,
	open list:FUSE: FILESYSTEM..., Geert Uytterhoeven, Hugh Dickins,
	Iulia Manda, Jan Beulich, J. Bruce Fields, Jeff Layton,
	open list:ABI/API, linux-fsdevel, linux-kernel
In-Reply-To: <1416899996-21315-1-git-send-email-pieter@boesman.nl>

The goal of the larger patch set is to completely compile out fs/splice, and
as a result, splice support for all file-systems. This patch ensures that
fs/nfsd falls back to non-splice fs support when CONFIG_SYSCALL_SPLICE is
undefined.

Signed-off-by: Pieter Smith <pieter@boesman.nl>
---
 net/sunrpc/svc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index ca8a795..6cacc37 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -1084,7 +1084,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
 		goto err_short_len;
 
 	/* Will be turned off only in gss privacy case: */
-	rqstp->rq_splice_ok = true;
+	rqstp->rq_splice_ok = IS_ENABLED(CONFIG_SPLICE_SYSCALL);
 	/* Will be turned off only when NFSv4 Sessions are used */
 	rqstp->rq_usedeferral = true;
 	rqstp->rq_dropme = false;
-- 
2.1.0

^ permalink raw reply related

* [PATCH v5 7/7] fs/splice: full support for compiling out splice
From: Pieter Smith @ 2014-11-25  7:19 UTC (permalink / raw)
  To: pieter-qeJ+1H9vRZbz+pZb47iToQ
  Cc: Michael S. Tsirkin, Trond Myklebust, Bertrand Jacquin,
	Oleg Nesterov, J. Bruce Fields, Eric Dumazet, Willem de Bruijn,
	蔡正龙, Jeff Layton, Tom Herbert,
	Alexei Starovoitov, Miklos Szeredi, Peter Foley, Hugh Dickins,
	Xiao Guangrong, Geert Uytterhoeven, Mel Gorman, Matt Turner,
	Paul E. McKenney, Alexander Duyck, open list:FUSE: FILESYSTEM...
In-Reply-To: <1416899996-21315-1-git-send-email-pieter-qeJ+1H9vRZbz+pZb47iToQ@public.gmane.org>

Entirely compile out splice translation unit when the system is configured
without splice family of syscalls (i.e. CONFIG_SYSCALL_SPLICE is undefined).

Exported fs/splice functions are transparently mocked out with static inlines.
Because userspace support for splice has already been removed by this
patch-set, the exported functions cannot be called anyway. Mocking them out
prevents a maintenance burden on file system drivers.

The bloat score resulting from this patch given a tinyconfig is:
add/remove: 0/25 grow/shrink: 0/5 up/down: 0/-4845 (-4845)
function                                     old     new   delta
pipe_to_null                                   4       -      -4
generic_pipe_buf_nosteal                       6       -      -6
spd_release_page                              10       -     -10
PageUptodate                                  22      11     -11
lock_page                                     36      24     -12
page_cache_pipe_buf_release                   16       -     -16
splice_write_null                             24       4     -20
page_cache_pipe_buf_ops                       20       -     -20
nosteal_pipe_buf_ops                          20       -     -20
default_pipe_buf_ops                          20       -     -20
generic_splice_sendpage                       24       -     -24
splice_shrink_spd                             27       -     -27
direct_splice_actor                           47       -     -47
default_file_splice_write                     49       -     -49
wakeup_pipe_writers                           54       -     -54
write_pipe_buf                                71       -     -71
page_cache_pipe_buf_confirm                   80       -     -80
splice_grow_spd                               87       -     -87
splice_from_pipe                              93       -     -93
splice_from_pipe_next                        106       -    -106
pipe_to_sendpage                             109       -    -109
page_cache_pipe_buf_steal                    114       -    -114
generic_file_splice_read                     131       8    -123
do_splice_direct                             148       -    -148
__splice_from_pipe                           246       -    -246
splice_direct_to_actor                       416       -    -416
splice_to_pipe                               417       -    -417
default_file_splice_read                     688       -    -688
iter_file_splice_write                       702       4    -698
__generic_file_splice_read                  1109       -   -1109

The bloat score for the entire CONFIG_SYSCALL_SPLICE patch-set is:
add/remove: 0/41 grow/shrink: 5/7 up/down: 23/-8422 (-8399)
function                                     old     new   delta
sys_pwritev                                  115     122      +7
sys_preadv                                   115     122      +7
fdput_pos                                     29      36      +7
sys_pwrite64                                 115     116      +1
sys_pread64                                  115     116      +1
pipe_to_null                                   4       -      -4
generic_pipe_buf_nosteal                       6       -      -6
spd_release_page                              10       -     -10
fdput                                         11       -     -11
PageUptodate                                  22      11     -11
lock_page                                     36      24     -12
signal_pending                                39      26     -13
fdget                                         56      42     -14
page_cache_pipe_buf_release                   16       -     -16
user_page_pipe_buf_ops                        20       -     -20
splice_write_null                             24       4     -20
page_cache_pipe_buf_ops                       20       -     -20
nosteal_pipe_buf_ops                          20       -     -20
default_pipe_buf_ops                          20       -     -20
generic_splice_sendpage                       24       -     -24
user_page_pipe_buf_steal                      25       -     -25
splice_shrink_spd                             27       -     -27
pipe_to_user                                  43       -     -43
direct_splice_actor                           47       -     -47
default_file_splice_write                     49       -     -49
wakeup_pipe_writers                           54       -     -54
wakeup_pipe_readers                           54       -     -54
write_pipe_buf                                71       -     -71
page_cache_pipe_buf_confirm                   80       -     -80
splice_grow_spd                               87       -     -87
do_splice_to                                  87       -     -87
ipipe_prep.part                               92       -     -92
splice_from_pipe                              93       -     -93
splice_from_pipe_next                        107       -    -107
pipe_to_sendpage                             109       -    -109
page_cache_pipe_buf_steal                    114       -    -114
opipe_prep.part                              119       -    -119
sys_sendfile                                 122       -    -122
generic_file_splice_read                     131       8    -123
sys_sendfile64                               126       -    -126
sys_vmsplice                                 137       -    -137
do_splice_direct                             148       -    -148
vmsplice_to_user                             205       -    -205
__splice_from_pipe                           246       -    -246
splice_direct_to_actor                       348       -    -348
splice_to_pipe                               371       -    -371
do_sendfile                                  492       -    -492
sys_tee                                      497       -    -497
vmsplice_to_pipe                             558       -    -558
default_file_splice_read                     688       -    -688
iter_file_splice_write                       702       4    -698
sys_splice                                  1075       -   -1075
__generic_file_splice_read                  1109       -   -1109

Signed-off-by: Pieter Smith <pieter-qeJ+1H9vRZbz+pZb47iToQ@public.gmane.org>
---
 fs/Makefile            |  3 ++-
 fs/splice.c            |  2 --
 include/linux/fs.h     | 26 ++++++++++++++++++++++++++
 include/linux/splice.h | 42 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 70 insertions(+), 3 deletions(-)

diff --git a/fs/Makefile b/fs/Makefile
index fb7646e..9395622 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -10,7 +10,7 @@ obj-y :=	open.o read_write.o file_table.o super.o \
 		ioctl.o readdir.o select.o dcache.o inode.o \
 		attr.o bad_inode.o file.o filesystems.o namespace.o \
 		seq_file.o xattr.o libfs.o fs-writeback.o \
-		pnode.o splice.o sync.o utimes.o \
+		pnode.o sync.o utimes.o \
 		stack.o fs_struct.o statfs.o fs_pin.o
 
 ifeq ($(CONFIG_BLOCK),y)
@@ -22,6 +22,7 @@ endif
 obj-$(CONFIG_PROC_FS) += proc_namespace.o
 
 obj-$(CONFIG_FSNOTIFY)		+= notify/
+obj-$(CONFIG_SYSCALL_SPLICE)	+= splice.o
 obj-$(CONFIG_EPOLL)		+= eventpoll.o
 obj-$(CONFIG_ANON_INODES)	+= anon_inodes.o
 obj-$(CONFIG_SIGNALFD)		+= signalfd.o
diff --git a/fs/splice.c b/fs/splice.c
index 7c4c695..44b201b 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -1316,7 +1316,6 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
 	return ret;
 }
 
-#ifdef CONFIG_SYSCALL_SPLICE
 static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
 			       struct pipe_inode_info *opipe,
 			       size_t len, unsigned int flags);
@@ -2201,5 +2200,4 @@ COMPAT_SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd,
 	return do_sendfile(out_fd, in_fd, NULL, count, 0);
 }
 #endif
-#endif
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a957d43..138107e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2444,6 +2444,7 @@ extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end,
 extern void block_sync_page(struct page *page);
 
 /* fs/splice.c */
+#ifdef CONFIG_SYSCALL_SPLICE
 extern ssize_t generic_file_splice_read(struct file *, loff_t *,
 		struct pipe_inode_info *, size_t, unsigned int);
 extern ssize_t default_file_splice_read(struct file *, loff_t *,
@@ -2452,6 +2453,31 @@ extern ssize_t iter_file_splice_write(struct pipe_inode_info *,
 		struct file *, loff_t *, size_t, unsigned int);
 extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
 		struct file *out, loff_t *, size_t len, unsigned int flags);
+#else
+static inline ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
+		struct pipe_inode_info *pipe, size_t len, unsigned int flags)
+{
+	return -EPERM;
+}
+
+static inline ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
+		struct pipe_inode_info *pipe, size_t len, unsigned int flags)
+{
+	return -EPERM;
+}
+
+static inline ssize_t iter_file_splice_write(struct pipe_inode_info *pipe,
+		struct file *out, loff_t *ppos, size_t len, unsigned int flags)
+{
+	return -EPERM;
+}
+
+static inline ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
+		struct file *out, loff_t *ppos, size_t len, unsigned int flags)
+{
+	return -EPERM;
+}
+#endif
 
 extern void
 file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
diff --git a/include/linux/splice.h b/include/linux/splice.h
index da2751d..34570d8 100644
--- a/include/linux/splice.h
+++ b/include/linux/splice.h
@@ -65,6 +65,7 @@ typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *,
 typedef int (splice_direct_actor)(struct pipe_inode_info *,
 				  struct splice_desc *);
 
+#ifdef CONFIG_SYSCALL_SPLICE
 extern ssize_t splice_from_pipe(struct pipe_inode_info *, struct file *,
 				loff_t *, size_t, unsigned int,
 				splice_actor *);
@@ -74,13 +75,54 @@ extern ssize_t splice_to_pipe(struct pipe_inode_info *,
 			      struct splice_pipe_desc *);
 extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
 				      splice_direct_actor *);
+#else
+static inline ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
+			 loff_t *ppos, size_t len, unsigned int flags,
+			 splice_actor *actor)
+{
+	return -EPERM;
+}
+
+static inline ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd,
+			   splice_actor *actor)
+{
+	return -EPERM;
+}
+
+static inline ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
+		       struct splice_pipe_desc *spd)
+{
+	return -EPERM;
+}
+
+static inline ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
+			       splice_direct_actor *actor)
+{
+	return -EPERM;
+}
+#endif
 
 /*
  * for dynamic pipe sizing
  */
+#ifdef CONFIG_SYSCALL_SPLICE
 extern int splice_grow_spd(const struct pipe_inode_info *, struct splice_pipe_desc *);
 extern void splice_shrink_spd(struct splice_pipe_desc *);
 extern void spd_release_page(struct splice_pipe_desc *, unsigned int);
+#else
+static inline int splice_grow_spd(const struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
+{
+	return -EPERM;
+}
+
+static inline void splice_shrink_spd(struct splice_pipe_desc *spd)
+{
+}
+
+static inline void spd_release_page(struct splice_pipe_desc *spd, unsigned int i)
+{
+}
+#endif
 
 extern const struct pipe_buf_operations page_cache_pipe_buf_ops;
 #endif
-- 
2.1.0


------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=157005751&iu=/4140/ostg.clktrk

^ permalink raw reply related

* Goedemorgen
From: Loan Engine® @ 2014-11-25  6:39 UTC (permalink / raw)




Goedemorgen
Ik wil u kennismaken met de Britse regering dit privé
Leningen bedrijf lening motor, geven wij
Leningen aan particulieren en bedrijven, wij bieden alle soorten van
Lening tegen een lage rente van 3%. Wij bieden leningen van
€10,000 en verder. Moet in een financiële
Moeilijkheden en noodzaak een lening, gelieve ons te contacteren
telefonisch of per email: loan.engine@outlook.com of Tel:
+ 447042069238
U kunt ook de volgende informatie invullen:
Volledige naam:
Geslacht:
Land en adres:
Benodigde hoeveelheid:
Duur:
Tel:
Wachten voor uw snelle reactie, als u een lening nodig.
Bedankt
Ana White

-- 
Esta mensagem foi verificada pelo sistema de antivirus e
 acredita-se estar livre de perigo.

^ permalink raw reply

* Re: [PATCH] mdio-mux-gpio: Use GPIO descriptor interface and new gpiod_set_array function
From: Rojhalat Ibrahim @ 2014-11-25  8:13 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Florian Fainelli, netdev, David Daney, linux-gpio@vger.kernel.org,
	Linus Walleij, Alexandre Courbot
In-Reply-To: <CAAVeFuKTmQi3vK5vALbT=hseRm9mn=-cb-7hiHwg7Zbczmz_WA@mail.gmail.com>

On Tuesday 25 November 2014 12:39:13 Alexandre Courbot wrote:
> On Thu, Nov 20, 2014 at 9:24 PM, Rojhalat Ibrahim <imr@rtschenk.de> wrote:
> > @@ -70,20 +64,17 @@ static int mdio_mux_gpio_probe(struct platform_device *pdev)
> >         s->num_gpios = num_gpios;
> >
> >         for (n = 0; n < num_gpios; ) {
> > -               int gpio = of_get_gpio_flags(pdev->dev.of_node, n, &f);
> > -               if (gpio < 0) {
> > -                       r = (gpio == -ENODEV) ? -EPROBE_DEFER : gpio;
> > +               struct gpio_desc *gpio = gpiod_get_index(&pdev->dev,
> > +                                                        "mdio-mux-gpio", n);
> 
> Doesn't this change introduce some incompatibility against the current
> DT bindings? of_get_gpio_flags() looks for a "gpios" property, while
> your call to gpiod_get_index() will look for "mdio-mux-gpio-gpios". It
> should probably be changed to gpiod_get_index(&pdev->dev, NULL, n).
> 

You are right, of course. I'll fix it and post a new patch version.

> ... or even be changed to gpiod_get_index(&pdev->dev, NULL, n,
> GPIOD_OUT_LOW) as the calls to gpiod_get() functions are being updated
> to take an initial state (both variants are currently usable but the
> former one will disappear in the future). This will also allow you to
> get rid of your call to gpiod_direction_output().
> 

Will do that.

> Side-note: it would be nice to have a gpiod_get_array() call that does
> exactly what this loop does, and returns an array of gpios directly
> usable by gpiod_set_array*(). And a matching gpiod_put_array() of
> course.
> 

I'll add that to my to-do-list.


Thanks
   Rojhalat


^ permalink raw reply

* Re: [PATCH] net-timestamp: Fix a documentation typo
From: Richard Cochran @ 2014-11-25  8:33 UTC (permalink / raw)
  To: Willem de Bruijn; +Cc: Andy Lutomirski, Network Development, David S. Miller
In-Reply-To: <CA+FuTSe8pjpUUpStfEHsuZ2Row9=MHVPH0S-MjUxiauBSNMOsg@mail.gmail.com>

On Mon, Nov 24, 2014 at 05:38:21PM -0500, Willem de Bruijn wrote:
> The datagram feature existed before I added the counter and stream
> support, so returning the entire packet in that case is legacy
> behavior, I suppose. I did not intend to expose network headers for
> the new stream socket interface, though.

I suppose that idea (not mine) behind returning the entire frame was
to allow the user to send multiple frames, and then figure out which
time stamp goes with which sent frame. The whole thing is weak for two
reasons, firstly you aren't able to send two identical frames, and
secondly there are quite a few time stamping cards out there which
only handle one transmit time stamp at a time. Thus the ptp4l
application always waits for the hardware time stamp before sending
another frame and never looks at the returned frame data.

Thanks,
Richard

^ permalink raw reply

* [PATCH 0/4] support GMAC driver for RK3288
From: Roger Chen @ 2014-11-25  9:06 UTC (permalink / raw)
  To: heiko
  Cc: peppe.cavallaro, netdev, linux-kernel, linux-rockchip, kever.yang,
	mark.yao, eddie.cai, Roger Chen

Roger Chen (4):
  patch1: add driver for Rockchip RK3288 SoCs integrated GMAC
  patch2: modify CRU config for Rockchip RK3288 SoCs integrated GMAC
  patch3: dts: add gmac info for rk3288
  patch4: dts: enable gmac on RK3288 evb board

tested on rk3288 SDK board:
busybox ifconfig eth0 up
busybox ifconfig eth0 192.168.1.111
ping 192.168.1.1

-- 
1.7.9.5

^ permalink raw reply

* [PATCH 1/4] GMAC: add driver for Rockchip RK3288 SoCs integrated GMAC
From: Roger Chen @ 2014-11-25  9:06 UTC (permalink / raw)
  To: heiko
  Cc: peppe.cavallaro, netdev, linux-kernel, linux-rockchip, kever.yang,
	mark.yao, eddie.cai, Roger Chen
In-Reply-To: <1416906418-26034-1-git-send-email-roger.chen@rock-chips.com>

This driver is based on stmmac driver.

Signed-off-by: Roger Chen <roger.chen@rock-chips.com>
---
 drivers/net/ethernet/stmicro/stmmac/Makefile       |    2 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c     |  629 ++++++++++++++++++++
 .../net/ethernet/stmicro/stmmac/stmmac_platform.c  |    3 +
 .../net/ethernet/stmicro/stmmac/stmmac_platform.h  |    1 +
 4 files changed, 634 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c

diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index ac4d562..73c2715 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o	\
 
 obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
 stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.o	\
-		       dwmac-sti.o dwmac-socfpga.o
+		       dwmac-sti.o dwmac-socfpga.o dwmac-rk.o
 
 obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
 stmmac-pci-objs:= stmmac_pci.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
new file mode 100644
index 0000000..9e50b37
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -0,0 +1,629 @@
+/**
+ * dwmac-rk.c - Rockchip RK3288 DWMAC specific glue layer
+ *
+ * Copyright (C) 2014 Chen-Zhi (Roger Chen)
+ *
+ * Chen-Zhi (Roger Chen)  <roger.chen@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/stmmac.h>
+#include <linux/clk.h>
+#include <linux/phy.h>
+#include <linux/of_net.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+struct rk_priv_data {
+	struct platform_device *pdev;
+	int phy_iface;
+	bool power_ctrl_by_pmu;
+	char pmu_regulator[32];
+	int pmu_enable_level;
+
+	int power_io;
+	int power_io_level;
+	int reset_io;
+	int reset_io_level;
+	int phyirq_io;
+	int phyirq_io_level;
+
+	bool clk_enabled;
+	bool clock_input;
+
+	struct clk *clk_mac;
+	struct clk *clk_mac_pll;
+	struct clk *gmac_clkin;
+	struct clk *mac_clk_rx;
+	struct clk *mac_clk_tx;
+	struct clk *clk_mac_ref;
+	struct clk *clk_mac_refout;
+	struct clk *aclk_mac;
+	struct clk *pclk_mac;
+
+	int tx_delay;
+	int rx_delay;
+
+	struct regmap *grf;
+};
+
+#define RK3288_GRF_SOC_CON1 0x0248
+#define RK3288_GRF_SOC_CON3 0x0250
+#define RK3288_GRF_GPIO3D_E 0x01ec
+#define RK3288_GRF_GPIO4A_E 0x01f0
+#define RK3288_GRF_GPIO4B_E 0x01f4
+
+/*RK3288_GRF_SOC_CON1*/
+#define GMAC_PHY_INTF_SEL_RGMII ((0x01C0 << 16) | (0x0040))
+#define GMAC_PHY_INTF_SEL_RMII  ((0x01C0 << 16) | (0x0100))
+#define GMAC_FLOW_CTRL          ((0x0200 << 16) | (0x0200))
+#define GMAC_FLOW_CTRL_CLR      ((0x0200 << 16) | (0x0000))
+#define GMAC_SPEED_10M          ((0x0400 << 16) | (0x0000))
+#define GMAC_SPEED_100M         ((0x0400 << 16) | (0x0400))
+#define GMAC_RMII_CLK_25M       ((0x0800 << 16) | (0x0800))
+#define GMAC_RMII_CLK_2_5M      ((0x0800 << 16) | (0x0000))
+#define GMAC_CLK_125M           ((0x3000 << 16) | (0x0000))
+#define GMAC_CLK_25M            ((0x3000 << 16) | (0x3000))
+#define GMAC_CLK_2_5M           ((0x3000 << 16) | (0x2000))
+#define GMAC_RMII_MODE          ((0x4000 << 16) | (0x4000))
+#define GMAC_RMII_MODE_CLR      ((0x4000 << 16) | (0x0000))
+
+/*RK3288_GRF_SOC_CON3*/
+#define GMAC_TXCLK_DLY_ENABLE   ((0x4000 << 16) | (0x4000))
+#define GMAC_TXCLK_DLY_DISABLE  ((0x4000 << 16) | (0x0000))
+#define GMAC_RXCLK_DLY_ENABLE   ((0x8000 << 16) | (0x8000))
+#define GMAC_RXCLK_DLY_DISABLE  ((0x8000 << 16) | (0x0000))
+#define GMAC_CLK_RX_DL_CFG(val) ((0x3F80 << 16) | (val<<7))
+#define GMAC_CLK_TX_DL_CFG(val) ((0x007F << 16) | (val))
+
+static void set_to_rgmii(struct rk_priv_data *bsp_priv,
+			 int tx_delay, int rx_delay)
+{
+	if (IS_ERR(bsp_priv->grf)) {
+		pr_err("%s: Missing rockchip,grf property\n", __func__);
+		return;
+	}
+
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+		     GMAC_PHY_INTF_SEL_RGMII);
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+		     GMAC_RMII_MODE_CLR);
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
+		     GMAC_RXCLK_DLY_ENABLE);
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
+		     GMAC_TXCLK_DLY_ENABLE);
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
+		     GMAC_CLK_RX_DL_CFG(rx_delay));
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
+		     GMAC_CLK_TX_DL_CFG(tx_delay));
+
+	regmap_write(bsp_priv->grf, RK3288_GRF_GPIO3D_E, 0xFFFFFFFF);
+	regmap_write(bsp_priv->grf, RK3288_GRF_GPIO4B_E,
+		     0x3<<2<<16 | 0x3<<2);
+	regmap_write(bsp_priv->grf, RK3288_GRF_GPIO4A_E, 0xFFFFFFFF);
+
+	pr_info("%s: tx delay=0x%x; rx delay=0x%x;\n",
+		__func__, tx_delay, rx_delay);
+}
+
+static void set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+	if (IS_ERR(bsp_priv->grf)) {
+		pr_err("%s: Missing rockchip,grf property\n", __func__);
+		return;
+	}
+
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+		     GMAC_PHY_INTF_SEL_RMII);
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+		     GMAC_RMII_MODE);
+}
+
+static void set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+	if (IS_ERR(bsp_priv->grf)) {
+		pr_err("%s: Missing rockchip,grf property\n", __func__);
+		return;
+	}
+
+	if (speed == 10)
+		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_2_5M);
+	else if (speed == 100)
+		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_25M);
+	else if (speed == 1000)
+		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_125M);
+	else
+		pr_err("unknown speed value for RGMII! speed=%d", speed);
+}
+
+static void set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+	if (IS_ERR(bsp_priv->grf)) {
+		pr_err("%s: Missing rockchip,grf property\n", __func__);
+		return;
+	}
+
+	if (speed == 10) {
+		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+			     GMAC_RMII_CLK_2_5M);
+		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+			     GMAC_SPEED_10M);
+	} else if (speed == 100) {
+		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+			     GMAC_RMII_CLK_25M);
+		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+			     GMAC_SPEED_100M);
+	} else {
+		pr_err("unknown speed value for RMII! speed=%d", speed);
+	}
+}
+
+#define MAC_CLK_RX	"mac_clk_rx"
+#define MAC_CLK_TX	"mac_clk_tx"
+#define CLK_MAC_REF	"clk_mac_ref"
+#define CLK_MAC_REF_OUT	"clk_mac_refout"
+#define CLK_MAC_PLL	"clk_mac_pll"
+#define ACLK_MAC	"aclk_mac"
+#define PCLK_MAC	"pclk_mac"
+#define MAC_CLKIN	"ext_gmac"
+#define CLK_MAC		"stmmaceth"
+
+int gmac_clk_init(struct rk_priv_data *bsp_priv)
+{
+	struct device *dev = &bsp_priv->pdev->dev;
+
+	bsp_priv->clk_enabled = false;
+
+	bsp_priv->mac_clk_rx = clk_get(dev, MAC_CLK_RX);
+	if (IS_ERR(bsp_priv->mac_clk_rx))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, MAC_CLK_RX);
+
+	bsp_priv->mac_clk_tx = clk_get(dev, MAC_CLK_TX);
+	if (IS_ERR(bsp_priv->mac_clk_tx))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, MAC_CLK_TX);
+
+	bsp_priv->clk_mac_ref = clk_get(dev, CLK_MAC_REF);
+	if (IS_ERR(bsp_priv->clk_mac_ref))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, CLK_MAC_REF);
+
+	bsp_priv->clk_mac_refout = clk_get(dev, CLK_MAC_REF_OUT);
+	if (IS_ERR(bsp_priv->clk_mac_refout))
+		pr_warn("%s: warning:cannot get clock %s\n",
+			__func__, CLK_MAC_REF_OUT);
+
+	bsp_priv->aclk_mac = clk_get(dev, ACLK_MAC);
+	if (IS_ERR(bsp_priv->aclk_mac))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, ACLK_MAC);
+
+	bsp_priv->pclk_mac = clk_get(dev, PCLK_MAC);
+	if (IS_ERR(bsp_priv->pclk_mac))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, PCLK_MAC);
+
+	bsp_priv->clk_mac_pll = clk_get(dev, CLK_MAC_PLL);
+	if (IS_ERR(bsp_priv->clk_mac_pll))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, CLK_MAC_PLL);
+
+	bsp_priv->gmac_clkin = clk_get(dev, MAC_CLKIN);
+	if (IS_ERR(bsp_priv->gmac_clkin))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, MAC_CLKIN);
+
+	bsp_priv->clk_mac = clk_get(dev, CLK_MAC);
+	if (IS_ERR(bsp_priv->clk_mac))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, CLK_MAC);
+
+	if (bsp_priv->clock_input) {
+		pr_info("%s: clock input from PHY\n", __func__);
+	} else {
+		if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
+			clk_set_rate(bsp_priv->clk_mac_pll, 50000000);
+
+		clk_set_parent(bsp_priv->clk_mac, bsp_priv->clk_mac_pll);
+	}
+
+	return 0;
+}
+
+static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable)
+{
+	int phy_iface = phy_iface = bsp_priv->phy_iface;
+
+	if (enable) {
+		if (!bsp_priv->clk_enabled) {
+			if (phy_iface == PHY_INTERFACE_MODE_RMII) {
+				if (!IS_ERR(bsp_priv->mac_clk_rx))
+					clk_prepare_enable(
+						bsp_priv->mac_clk_rx);
+
+				if (!IS_ERR(bsp_priv->clk_mac_ref))
+					clk_prepare_enable(
+						bsp_priv->clk_mac_ref);
+
+				if (!IS_ERR(bsp_priv->clk_mac_refout))
+					clk_prepare_enable(
+						bsp_priv->clk_mac_refout);
+			}
+
+			if (!IS_ERR(bsp_priv->aclk_mac))
+				clk_prepare_enable(bsp_priv->aclk_mac);
+
+			if (!IS_ERR(bsp_priv->pclk_mac))
+				clk_prepare_enable(bsp_priv->pclk_mac);
+
+			if (!IS_ERR(bsp_priv->mac_clk_tx))
+				clk_prepare_enable(bsp_priv->mac_clk_tx);
+
+			/**
+			 * if (!IS_ERR(bsp_priv->clk_mac))
+			 *	clk_prepare_enable(bsp_priv->clk_mac);
+			 */
+			mdelay(5);
+			bsp_priv->clk_enabled = true;
+		}
+	} else {
+		if (bsp_priv->clk_enabled) {
+			if (phy_iface == PHY_INTERFACE_MODE_RMII) {
+				if (!IS_ERR(bsp_priv->mac_clk_rx))
+					clk_disable_unprepare(
+						bsp_priv->mac_clk_rx);
+
+				if (!IS_ERR(bsp_priv->clk_mac_ref))
+					clk_disable_unprepare(
+						bsp_priv->clk_mac_ref);
+
+				if (!IS_ERR(bsp_priv->clk_mac_refout))
+					clk_disable_unprepare(
+						bsp_priv->clk_mac_refout);
+			}
+
+			if (!IS_ERR(bsp_priv->aclk_mac))
+				clk_disable_unprepare(bsp_priv->aclk_mac);
+
+			if (!IS_ERR(bsp_priv->pclk_mac))
+				clk_disable_unprepare(bsp_priv->pclk_mac);
+
+			if (!IS_ERR(bsp_priv->mac_clk_tx))
+				clk_disable_unprepare(bsp_priv->mac_clk_tx);
+			/**
+			 * if (!IS_ERR(bsp_priv->clk_mac))
+			 *	clk_disable_unprepare(bsp_priv->clk_mac);
+			 */
+			bsp_priv->clk_enabled = false;
+		}
+	}
+
+	return 0;
+}
+
+static int power_on_by_pmu(struct rk_priv_data *bsp_priv, bool enable)
+{
+	struct regulator *ldo;
+	char *ldostr = bsp_priv->pmu_regulator;
+	int ret;
+
+	if (!ldostr) {
+		pr_err("%s: no ldo found\n", __func__);
+		return -1;
+	}
+
+	ldo = regulator_get(NULL, ldostr);
+	if (!ldo) {
+		pr_err("\n%s get ldo %s failed\n", __func__, ldostr);
+	} else {
+		if (enable) {
+			if (!regulator_is_enabled(ldo)) {
+				regulator_set_voltage(ldo, 3300000, 3300000);
+				ret = regulator_enable(ldo);
+				if (ret != 0)
+					pr_err("%s: fail to enable %s\n",
+					       __func__, ldostr);
+				else
+					pr_info("turn on ldo done.\n");
+			} else {
+				pr_warn("%s is enabled before enable", ldostr);
+			}
+		} else {
+			if (regulator_is_enabled(ldo)) {
+				ret = regulator_disable(ldo);
+				if (ret != 0)
+					pr_err("%s: fail to disable %s\n",
+					       __func__, ldostr);
+				else
+					pr_info("turn off ldo done.\n");
+			} else {
+				pr_warn("%s is disabled before disable",
+					ldostr);
+			}
+		}
+		regulator_put(ldo);
+	}
+
+	return 0;
+}
+
+static int power_on_by_gpio(struct rk_priv_data *bsp_priv, bool enable)
+{
+	if (enable) {
+		/*power on*/
+		if (gpio_is_valid(bsp_priv->power_io))
+			gpio_direction_output(bsp_priv->power_io,
+					      bsp_priv->power_io_level);
+	} else {
+		/*power off*/
+		if (gpio_is_valid(bsp_priv->power_io))
+			gpio_direction_output(bsp_priv->power_io,
+					      !bsp_priv->power_io_level);
+	}
+
+	return 0;
+}
+
+static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable)
+{
+	int ret = -1;
+
+	pr_info("Ethernet PHY power %s\n", enable == 1 ? "on" : "off");
+
+	if (bsp_priv->power_ctrl_by_pmu)
+		ret = power_on_by_pmu(bsp_priv, enable);
+	else
+		ret =  power_on_by_gpio(bsp_priv, enable);
+
+	if (enable) {
+		/*reset*/
+		if (gpio_is_valid(bsp_priv->reset_io)) {
+			gpio_direction_output(bsp_priv->reset_io,
+					      bsp_priv->reset_io_level);
+			mdelay(5);
+			gpio_direction_output(bsp_priv->reset_io,
+					      !bsp_priv->reset_io_level);
+		}
+		mdelay(30);
+
+	} else {
+		/*pull down reset*/
+		if (gpio_is_valid(bsp_priv->reset_io)) {
+			gpio_direction_output(bsp_priv->reset_io,
+					      bsp_priv->reset_io_level);
+		}
+	}
+
+	return ret;
+}
+
+#define GPIO_PHY_POWER	"gmac_phy_power"
+#define GPIO_PHY_RESET	"gmac_phy_reset"
+#define GPIO_PHY_IRQ	"gmac_phy_irq"
+
+static void *rk_gmac_setup(struct platform_device *pdev)
+{
+	struct rk_priv_data *bsp_priv;
+	struct device *dev = &pdev->dev;
+	enum of_gpio_flags flags;
+	int ret;
+	const char *strings = NULL;
+	int value;
+	int irq;
+
+	bsp_priv = devm_kzalloc(dev, sizeof(*bsp_priv), GFP_KERNEL);
+	if (!bsp_priv)
+		return ERR_PTR(-ENOMEM);
+
+	bsp_priv->phy_iface = of_get_phy_mode(dev->of_node);
+
+	ret = of_property_read_string(dev->of_node, "pmu_regulator", &strings);
+	if (ret) {
+		pr_err("%s: Can not read property: pmu_regulator.\n", __func__);
+		bsp_priv->power_ctrl_by_pmu = false;
+	} else {
+		pr_info("%s: ethernet phy power controlled by pmu(%s).\n",
+			__func__, strings);
+		bsp_priv->power_ctrl_by_pmu = true;
+		strcpy(bsp_priv->pmu_regulator, strings);
+	}
+
+	ret = of_property_read_u32(dev->of_node, "pmu_enable_level", &value);
+	if (ret) {
+		pr_err("%s: Can not read property: pmu_enable_level.\n",
+		       __func__);
+		bsp_priv->power_ctrl_by_pmu = false;
+	} else {
+		pr_info("%s: PHY power controlled by pmu(level = %s).\n",
+			__func__, (value == 1) ? "HIGH" : "LOW");
+		bsp_priv->power_ctrl_by_pmu = true;
+		bsp_priv->pmu_enable_level = value;
+	}
+
+	ret = of_property_read_string(dev->of_node, "clock_in_out", &strings);
+	if (ret) {
+		pr_err("%s: Can not read property: clock_in_out.\n", __func__);
+		bsp_priv->clock_input = true;
+	} else {
+		pr_info("%s: clock input or output? (%s).\n",
+			__func__, strings);
+		if (!strcmp(strings, "input"))
+			bsp_priv->clock_input = true;
+		else
+			bsp_priv->clock_input = false;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "tx_delay", &value);
+	if (ret) {
+		bsp_priv->tx_delay = 0x30;
+		pr_err("%s: Can not read property: tx_delay.", __func__);
+		pr_err("%s: set tx_delay to 0x%x\n",
+		       __func__, bsp_priv->tx_delay);
+	} else {
+		pr_info("%s: TX delay(0x%x).\n", __func__, value);
+		bsp_priv->tx_delay = value;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "rx_delay", &value);
+	if (ret) {
+		bsp_priv->rx_delay = 0x10;
+		pr_err("%s: Can not read property: rx_delay.", __func__);
+		pr_err("%s: set rx_delay to 0x%x\n",
+		       __func__, bsp_priv->rx_delay);
+	} else {
+		pr_info("%s: RX delay(0x%x).\n", __func__, value);
+		bsp_priv->rx_delay = value;
+	}
+
+	bsp_priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
+							"rockchip,grf");
+	if (IS_ERR(bsp_priv->grf))
+		dev_err(&pdev->dev, "Missing rockchip,grf property\n");
+
+	bsp_priv->phyirq_io =
+		of_get_named_gpio_flags(dev->of_node,
+					"phyirq-gpio", 0, &flags);
+	bsp_priv->phyirq_io_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
+
+	bsp_priv->reset_io =
+		of_get_named_gpio_flags(dev->of_node,
+					"reset-gpio", 0, &flags);
+	bsp_priv->reset_io_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
+
+	bsp_priv->power_io =
+		of_get_named_gpio_flags(dev->of_node, "power-gpio", 0, &flags);
+	bsp_priv->power_io_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
+
+	/*power*/
+	if (!gpio_is_valid(bsp_priv->power_io)) {
+		pr_err("%s: Failed to get GPIO %s.\n",
+		       __func__, "power-gpio");
+	} else {
+		ret = gpio_request(bsp_priv->power_io, GPIO_PHY_POWER);
+		if (ret)
+			pr_err("%s: ERROR: Failed to request GPIO %s.\n",
+			       __func__, GPIO_PHY_POWER);
+	}
+
+	if (!gpio_is_valid(bsp_priv->reset_io)) {
+		pr_err("%s: ERROR: Get reset-gpio failed.\n", __func__);
+	} else {
+		ret = gpio_request(bsp_priv->reset_io, GPIO_PHY_RESET);
+		if (ret)
+			pr_err("%s: ERROR: Failed to request GPIO %s.\n",
+			       __func__, GPIO_PHY_RESET);
+	}
+
+	if (bsp_priv->phyirq_io > 0) {
+		struct plat_stmmacenet_data *plat_dat;
+
+		pr_info("PHY irq in use\n");
+		ret = gpio_request(bsp_priv->phyirq_io, GPIO_PHY_IRQ);
+		if (ret < 0) {
+			pr_warn("%s: Failed to request GPIO %s\n",
+				__func__, GPIO_PHY_IRQ);
+			goto goon;
+		}
+
+		ret = gpio_direction_input(bsp_priv->phyirq_io);
+		if (ret < 0) {
+			pr_err("%s, Failed to set input for GPIO %s\n",
+			       __func__, GPIO_PHY_IRQ);
+			gpio_free(bsp_priv->phyirq_io);
+			goto goon;
+		}
+
+		irq = gpio_to_irq(bsp_priv->phyirq_io);
+		if (irq < 0) {
+			ret = irq;
+			pr_err("Failed to set irq for %s\n",
+			       GPIO_PHY_IRQ);
+			gpio_free(bsp_priv->phyirq_io);
+			goto goon;
+		}
+
+		plat_dat = dev_get_platdata(&pdev->dev);
+		if (plat_dat)
+			plat_dat->mdio_bus_data->probed_phy_irq = irq;
+		else
+			pr_err("%s: plat_data is NULL\n", __func__);
+	}
+
+goon:
+	/*rmii or rgmii*/
+	if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) {
+		pr_info("%s: init for RGMII\n", __func__);
+		set_to_rgmii(bsp_priv, bsp_priv->tx_delay, bsp_priv->rx_delay);
+	} else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) {
+		pr_info("%s: init for RMII\n", __func__);
+		set_to_rmii(bsp_priv);
+	} else {
+		pr_err("%s: ERROR: NO interface defined!\n", __func__);
+	}
+
+	bsp_priv->pdev = pdev;
+
+	gmac_clk_init(bsp_priv);
+
+	return bsp_priv;
+}
+
+static int rk_gmac_init(struct platform_device *pdev, void *priv)
+{
+	struct rk_priv_data *bsp_priv = priv;
+	int ret;
+
+	ret = phy_power_on(bsp_priv, true);
+	if (ret)
+		return ret;
+
+	ret = gmac_clk_enable(bsp_priv, true);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void rk_gmac_exit(struct platform_device *pdev, void *priv)
+{
+	struct rk_priv_data *gmac = priv;
+
+	phy_power_on(gmac, false);
+	gmac_clk_enable(gmac, false);
+}
+
+static void rk_fix_speed(void *priv, unsigned int speed)
+{
+	struct rk_priv_data *bsp_priv = priv;
+
+	if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII)
+		set_rgmii_speed(bsp_priv, speed);
+	else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
+		set_rmii_speed(bsp_priv, speed);
+	else
+		pr_err("unsupported interface %d", bsp_priv->phy_iface);
+}
+
+const struct stmmac_of_data rk_gmac_data = {
+	.has_gmac = 1,
+	.tx_coe = 1,
+	.fix_mac_speed = rk_fix_speed,
+	.setup = rk_gmac_setup,
+	.init = rk_gmac_init,
+	.exit = rk_gmac_exit,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 15814b7..b4dee96 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -33,6 +33,7 @@
 
 static const struct of_device_id stmmac_dt_ids[] = {
 	/* SoC specific glue layers should come before generic bindings */
+	{ .compatible = "rockchip,rk3288-gmac", .data = &rk_gmac_data},
 	{ .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data},
 	{ .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
 	{ .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data},
@@ -291,6 +292,8 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
 			return  -ENOMEM;
 		}
 
+		pdev->dev.platform_data = plat_dat;
+
 		ret = stmmac_probe_config_dt(pdev, plat_dat, &mac);
 		if (ret) {
 			pr_err("%s: main dt probe failed", __func__);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
index 25dd1f7..32a0516 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
@@ -24,5 +24,6 @@ extern const struct stmmac_of_data sun7i_gmac_data;
 extern const struct stmmac_of_data stih4xx_dwmac_data;
 extern const struct stmmac_of_data stid127_dwmac_data;
 extern const struct stmmac_of_data socfpga_gmac_data;
+extern const struct stmmac_of_data rk_gmac_data;
 
 #endif /* __STMMAC_PLATFORM_H__ */
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 0/4] support GMAC driver for RK3288
From: Roger Chen @ 2014-11-25  9:07 UTC (permalink / raw)
  To: heiko
  Cc: peppe.cavallaro, netdev, linux-kernel, linux-rockchip, kever.yang,
	mark.yao, eddie.cai, roger.chen

Roger Chen (4):
  patch1: add driver for Rockchip RK3288 SoCs integrated GMAC
  patch2: modify CRU config for Rockchip RK3288 SoCs integrated GMAC
  patch3: dts: add gmac info for rk3288
  patch4: dts: enable gmac on RK3288 evb board

tested on rk3288 SDK board:
busybox ifconfig eth0 up
busybox ifconfig eth0 192.168.1.111
ping 192.168.1.1

-- 
1.7.9.5

^ permalink raw reply

* [PATCH 1/4] GMAC: add driver for Rockchip RK3288 SoCs integrated GMAC
From: Roger Chen @ 2014-11-25  9:07 UTC (permalink / raw)
  To: heiko
  Cc: peppe.cavallaro, netdev, linux-kernel, linux-rockchip, kever.yang,
	mark.yao, eddie.cai, roger.chen
In-Reply-To: <1416906460-26078-1-git-send-email-roger.chen@rock-chips.com>

This driver is based on stmmac driver.

Signed-off-by: Roger Chen <roger.chen@rock-chips.com>
---
 drivers/net/ethernet/stmicro/stmmac/Makefile       |    2 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c     |  629 ++++++++++++++++++++
 .../net/ethernet/stmicro/stmmac/stmmac_platform.c  |    3 +
 .../net/ethernet/stmicro/stmmac/stmmac_platform.h  |    1 +
 4 files changed, 634 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c

diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index ac4d562..73c2715 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o	\
 
 obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
 stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.o	\
-		       dwmac-sti.o dwmac-socfpga.o
+		       dwmac-sti.o dwmac-socfpga.o dwmac-rk.o
 
 obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
 stmmac-pci-objs:= stmmac_pci.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
new file mode 100644
index 0000000..9e50b37
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -0,0 +1,629 @@
+/**
+ * dwmac-rk.c - Rockchip RK3288 DWMAC specific glue layer
+ *
+ * Copyright (C) 2014 Chen-Zhi (Roger Chen)
+ *
+ * Chen-Zhi (Roger Chen)  <roger.chen@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/stmmac.h>
+#include <linux/clk.h>
+#include <linux/phy.h>
+#include <linux/of_net.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+struct rk_priv_data {
+	struct platform_device *pdev;
+	int phy_iface;
+	bool power_ctrl_by_pmu;
+	char pmu_regulator[32];
+	int pmu_enable_level;
+
+	int power_io;
+	int power_io_level;
+	int reset_io;
+	int reset_io_level;
+	int phyirq_io;
+	int phyirq_io_level;
+
+	bool clk_enabled;
+	bool clock_input;
+
+	struct clk *clk_mac;
+	struct clk *clk_mac_pll;
+	struct clk *gmac_clkin;
+	struct clk *mac_clk_rx;
+	struct clk *mac_clk_tx;
+	struct clk *clk_mac_ref;
+	struct clk *clk_mac_refout;
+	struct clk *aclk_mac;
+	struct clk *pclk_mac;
+
+	int tx_delay;
+	int rx_delay;
+
+	struct regmap *grf;
+};
+
+#define RK3288_GRF_SOC_CON1 0x0248
+#define RK3288_GRF_SOC_CON3 0x0250
+#define RK3288_GRF_GPIO3D_E 0x01ec
+#define RK3288_GRF_GPIO4A_E 0x01f0
+#define RK3288_GRF_GPIO4B_E 0x01f4
+
+/*RK3288_GRF_SOC_CON1*/
+#define GMAC_PHY_INTF_SEL_RGMII ((0x01C0 << 16) | (0x0040))
+#define GMAC_PHY_INTF_SEL_RMII  ((0x01C0 << 16) | (0x0100))
+#define GMAC_FLOW_CTRL          ((0x0200 << 16) | (0x0200))
+#define GMAC_FLOW_CTRL_CLR      ((0x0200 << 16) | (0x0000))
+#define GMAC_SPEED_10M          ((0x0400 << 16) | (0x0000))
+#define GMAC_SPEED_100M         ((0x0400 << 16) | (0x0400))
+#define GMAC_RMII_CLK_25M       ((0x0800 << 16) | (0x0800))
+#define GMAC_RMII_CLK_2_5M      ((0x0800 << 16) | (0x0000))
+#define GMAC_CLK_125M           ((0x3000 << 16) | (0x0000))
+#define GMAC_CLK_25M            ((0x3000 << 16) | (0x3000))
+#define GMAC_CLK_2_5M           ((0x3000 << 16) | (0x2000))
+#define GMAC_RMII_MODE          ((0x4000 << 16) | (0x4000))
+#define GMAC_RMII_MODE_CLR      ((0x4000 << 16) | (0x0000))
+
+/*RK3288_GRF_SOC_CON3*/
+#define GMAC_TXCLK_DLY_ENABLE   ((0x4000 << 16) | (0x4000))
+#define GMAC_TXCLK_DLY_DISABLE  ((0x4000 << 16) | (0x0000))
+#define GMAC_RXCLK_DLY_ENABLE   ((0x8000 << 16) | (0x8000))
+#define GMAC_RXCLK_DLY_DISABLE  ((0x8000 << 16) | (0x0000))
+#define GMAC_CLK_RX_DL_CFG(val) ((0x3F80 << 16) | (val<<7))
+#define GMAC_CLK_TX_DL_CFG(val) ((0x007F << 16) | (val))
+
+static void set_to_rgmii(struct rk_priv_data *bsp_priv,
+			 int tx_delay, int rx_delay)
+{
+	if (IS_ERR(bsp_priv->grf)) {
+		pr_err("%s: Missing rockchip,grf property\n", __func__);
+		return;
+	}
+
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+		     GMAC_PHY_INTF_SEL_RGMII);
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+		     GMAC_RMII_MODE_CLR);
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
+		     GMAC_RXCLK_DLY_ENABLE);
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
+		     GMAC_TXCLK_DLY_ENABLE);
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
+		     GMAC_CLK_RX_DL_CFG(rx_delay));
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
+		     GMAC_CLK_TX_DL_CFG(tx_delay));
+
+	regmap_write(bsp_priv->grf, RK3288_GRF_GPIO3D_E, 0xFFFFFFFF);
+	regmap_write(bsp_priv->grf, RK3288_GRF_GPIO4B_E,
+		     0x3<<2<<16 | 0x3<<2);
+	regmap_write(bsp_priv->grf, RK3288_GRF_GPIO4A_E, 0xFFFFFFFF);
+
+	pr_info("%s: tx delay=0x%x; rx delay=0x%x;\n",
+		__func__, tx_delay, rx_delay);
+}
+
+static void set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+	if (IS_ERR(bsp_priv->grf)) {
+		pr_err("%s: Missing rockchip,grf property\n", __func__);
+		return;
+	}
+
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+		     GMAC_PHY_INTF_SEL_RMII);
+	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+		     GMAC_RMII_MODE);
+}
+
+static void set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+	if (IS_ERR(bsp_priv->grf)) {
+		pr_err("%s: Missing rockchip,grf property\n", __func__);
+		return;
+	}
+
+	if (speed == 10)
+		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_2_5M);
+	else if (speed == 100)
+		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_25M);
+	else if (speed == 1000)
+		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_125M);
+	else
+		pr_err("unknown speed value for RGMII! speed=%d", speed);
+}
+
+static void set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+	if (IS_ERR(bsp_priv->grf)) {
+		pr_err("%s: Missing rockchip,grf property\n", __func__);
+		return;
+	}
+
+	if (speed == 10) {
+		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+			     GMAC_RMII_CLK_2_5M);
+		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+			     GMAC_SPEED_10M);
+	} else if (speed == 100) {
+		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+			     GMAC_RMII_CLK_25M);
+		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+			     GMAC_SPEED_100M);
+	} else {
+		pr_err("unknown speed value for RMII! speed=%d", speed);
+	}
+}
+
+#define MAC_CLK_RX	"mac_clk_rx"
+#define MAC_CLK_TX	"mac_clk_tx"
+#define CLK_MAC_REF	"clk_mac_ref"
+#define CLK_MAC_REF_OUT	"clk_mac_refout"
+#define CLK_MAC_PLL	"clk_mac_pll"
+#define ACLK_MAC	"aclk_mac"
+#define PCLK_MAC	"pclk_mac"
+#define MAC_CLKIN	"ext_gmac"
+#define CLK_MAC		"stmmaceth"
+
+int gmac_clk_init(struct rk_priv_data *bsp_priv)
+{
+	struct device *dev = &bsp_priv->pdev->dev;
+
+	bsp_priv->clk_enabled = false;
+
+	bsp_priv->mac_clk_rx = clk_get(dev, MAC_CLK_RX);
+	if (IS_ERR(bsp_priv->mac_clk_rx))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, MAC_CLK_RX);
+
+	bsp_priv->mac_clk_tx = clk_get(dev, MAC_CLK_TX);
+	if (IS_ERR(bsp_priv->mac_clk_tx))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, MAC_CLK_TX);
+
+	bsp_priv->clk_mac_ref = clk_get(dev, CLK_MAC_REF);
+	if (IS_ERR(bsp_priv->clk_mac_ref))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, CLK_MAC_REF);
+
+	bsp_priv->clk_mac_refout = clk_get(dev, CLK_MAC_REF_OUT);
+	if (IS_ERR(bsp_priv->clk_mac_refout))
+		pr_warn("%s: warning:cannot get clock %s\n",
+			__func__, CLK_MAC_REF_OUT);
+
+	bsp_priv->aclk_mac = clk_get(dev, ACLK_MAC);
+	if (IS_ERR(bsp_priv->aclk_mac))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, ACLK_MAC);
+
+	bsp_priv->pclk_mac = clk_get(dev, PCLK_MAC);
+	if (IS_ERR(bsp_priv->pclk_mac))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, PCLK_MAC);
+
+	bsp_priv->clk_mac_pll = clk_get(dev, CLK_MAC_PLL);
+	if (IS_ERR(bsp_priv->clk_mac_pll))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, CLK_MAC_PLL);
+
+	bsp_priv->gmac_clkin = clk_get(dev, MAC_CLKIN);
+	if (IS_ERR(bsp_priv->gmac_clkin))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, MAC_CLKIN);
+
+	bsp_priv->clk_mac = clk_get(dev, CLK_MAC);
+	if (IS_ERR(bsp_priv->clk_mac))
+		pr_warn("%s: warning: cannot get clock %s\n",
+			__func__, CLK_MAC);
+
+	if (bsp_priv->clock_input) {
+		pr_info("%s: clock input from PHY\n", __func__);
+	} else {
+		if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
+			clk_set_rate(bsp_priv->clk_mac_pll, 50000000);
+
+		clk_set_parent(bsp_priv->clk_mac, bsp_priv->clk_mac_pll);
+	}
+
+	return 0;
+}
+
+static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable)
+{
+	int phy_iface = phy_iface = bsp_priv->phy_iface;
+
+	if (enable) {
+		if (!bsp_priv->clk_enabled) {
+			if (phy_iface == PHY_INTERFACE_MODE_RMII) {
+				if (!IS_ERR(bsp_priv->mac_clk_rx))
+					clk_prepare_enable(
+						bsp_priv->mac_clk_rx);
+
+				if (!IS_ERR(bsp_priv->clk_mac_ref))
+					clk_prepare_enable(
+						bsp_priv->clk_mac_ref);
+
+				if (!IS_ERR(bsp_priv->clk_mac_refout))
+					clk_prepare_enable(
+						bsp_priv->clk_mac_refout);
+			}
+
+			if (!IS_ERR(bsp_priv->aclk_mac))
+				clk_prepare_enable(bsp_priv->aclk_mac);
+
+			if (!IS_ERR(bsp_priv->pclk_mac))
+				clk_prepare_enable(bsp_priv->pclk_mac);
+
+			if (!IS_ERR(bsp_priv->mac_clk_tx))
+				clk_prepare_enable(bsp_priv->mac_clk_tx);
+
+			/**
+			 * if (!IS_ERR(bsp_priv->clk_mac))
+			 *	clk_prepare_enable(bsp_priv->clk_mac);
+			 */
+			mdelay(5);
+			bsp_priv->clk_enabled = true;
+		}
+	} else {
+		if (bsp_priv->clk_enabled) {
+			if (phy_iface == PHY_INTERFACE_MODE_RMII) {
+				if (!IS_ERR(bsp_priv->mac_clk_rx))
+					clk_disable_unprepare(
+						bsp_priv->mac_clk_rx);
+
+				if (!IS_ERR(bsp_priv->clk_mac_ref))
+					clk_disable_unprepare(
+						bsp_priv->clk_mac_ref);
+
+				if (!IS_ERR(bsp_priv->clk_mac_refout))
+					clk_disable_unprepare(
+						bsp_priv->clk_mac_refout);
+			}
+
+			if (!IS_ERR(bsp_priv->aclk_mac))
+				clk_disable_unprepare(bsp_priv->aclk_mac);
+
+			if (!IS_ERR(bsp_priv->pclk_mac))
+				clk_disable_unprepare(bsp_priv->pclk_mac);
+
+			if (!IS_ERR(bsp_priv->mac_clk_tx))
+				clk_disable_unprepare(bsp_priv->mac_clk_tx);
+			/**
+			 * if (!IS_ERR(bsp_priv->clk_mac))
+			 *	clk_disable_unprepare(bsp_priv->clk_mac);
+			 */
+			bsp_priv->clk_enabled = false;
+		}
+	}
+
+	return 0;
+}
+
+static int power_on_by_pmu(struct rk_priv_data *bsp_priv, bool enable)
+{
+	struct regulator *ldo;
+	char *ldostr = bsp_priv->pmu_regulator;
+	int ret;
+
+	if (!ldostr) {
+		pr_err("%s: no ldo found\n", __func__);
+		return -1;
+	}
+
+	ldo = regulator_get(NULL, ldostr);
+	if (!ldo) {
+		pr_err("\n%s get ldo %s failed\n", __func__, ldostr);
+	} else {
+		if (enable) {
+			if (!regulator_is_enabled(ldo)) {
+				regulator_set_voltage(ldo, 3300000, 3300000);
+				ret = regulator_enable(ldo);
+				if (ret != 0)
+					pr_err("%s: fail to enable %s\n",
+					       __func__, ldostr);
+				else
+					pr_info("turn on ldo done.\n");
+			} else {
+				pr_warn("%s is enabled before enable", ldostr);
+			}
+		} else {
+			if (regulator_is_enabled(ldo)) {
+				ret = regulator_disable(ldo);
+				if (ret != 0)
+					pr_err("%s: fail to disable %s\n",
+					       __func__, ldostr);
+				else
+					pr_info("turn off ldo done.\n");
+			} else {
+				pr_warn("%s is disabled before disable",
+					ldostr);
+			}
+		}
+		regulator_put(ldo);
+	}
+
+	return 0;
+}
+
+static int power_on_by_gpio(struct rk_priv_data *bsp_priv, bool enable)
+{
+	if (enable) {
+		/*power on*/
+		if (gpio_is_valid(bsp_priv->power_io))
+			gpio_direction_output(bsp_priv->power_io,
+					      bsp_priv->power_io_level);
+	} else {
+		/*power off*/
+		if (gpio_is_valid(bsp_priv->power_io))
+			gpio_direction_output(bsp_priv->power_io,
+					      !bsp_priv->power_io_level);
+	}
+
+	return 0;
+}
+
+static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable)
+{
+	int ret = -1;
+
+	pr_info("Ethernet PHY power %s\n", enable == 1 ? "on" : "off");
+
+	if (bsp_priv->power_ctrl_by_pmu)
+		ret = power_on_by_pmu(bsp_priv, enable);
+	else
+		ret =  power_on_by_gpio(bsp_priv, enable);
+
+	if (enable) {
+		/*reset*/
+		if (gpio_is_valid(bsp_priv->reset_io)) {
+			gpio_direction_output(bsp_priv->reset_io,
+					      bsp_priv->reset_io_level);
+			mdelay(5);
+			gpio_direction_output(bsp_priv->reset_io,
+					      !bsp_priv->reset_io_level);
+		}
+		mdelay(30);
+
+	} else {
+		/*pull down reset*/
+		if (gpio_is_valid(bsp_priv->reset_io)) {
+			gpio_direction_output(bsp_priv->reset_io,
+					      bsp_priv->reset_io_level);
+		}
+	}
+
+	return ret;
+}
+
+#define GPIO_PHY_POWER	"gmac_phy_power"
+#define GPIO_PHY_RESET	"gmac_phy_reset"
+#define GPIO_PHY_IRQ	"gmac_phy_irq"
+
+static void *rk_gmac_setup(struct platform_device *pdev)
+{
+	struct rk_priv_data *bsp_priv;
+	struct device *dev = &pdev->dev;
+	enum of_gpio_flags flags;
+	int ret;
+	const char *strings = NULL;
+	int value;
+	int irq;
+
+	bsp_priv = devm_kzalloc(dev, sizeof(*bsp_priv), GFP_KERNEL);
+	if (!bsp_priv)
+		return ERR_PTR(-ENOMEM);
+
+	bsp_priv->phy_iface = of_get_phy_mode(dev->of_node);
+
+	ret = of_property_read_string(dev->of_node, "pmu_regulator", &strings);
+	if (ret) {
+		pr_err("%s: Can not read property: pmu_regulator.\n", __func__);
+		bsp_priv->power_ctrl_by_pmu = false;
+	} else {
+		pr_info("%s: ethernet phy power controlled by pmu(%s).\n",
+			__func__, strings);
+		bsp_priv->power_ctrl_by_pmu = true;
+		strcpy(bsp_priv->pmu_regulator, strings);
+	}
+
+	ret = of_property_read_u32(dev->of_node, "pmu_enable_level", &value);
+	if (ret) {
+		pr_err("%s: Can not read property: pmu_enable_level.\n",
+		       __func__);
+		bsp_priv->power_ctrl_by_pmu = false;
+	} else {
+		pr_info("%s: PHY power controlled by pmu(level = %s).\n",
+			__func__, (value == 1) ? "HIGH" : "LOW");
+		bsp_priv->power_ctrl_by_pmu = true;
+		bsp_priv->pmu_enable_level = value;
+	}
+
+	ret = of_property_read_string(dev->of_node, "clock_in_out", &strings);
+	if (ret) {
+		pr_err("%s: Can not read property: clock_in_out.\n", __func__);
+		bsp_priv->clock_input = true;
+	} else {
+		pr_info("%s: clock input or output? (%s).\n",
+			__func__, strings);
+		if (!strcmp(strings, "input"))
+			bsp_priv->clock_input = true;
+		else
+			bsp_priv->clock_input = false;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "tx_delay", &value);
+	if (ret) {
+		bsp_priv->tx_delay = 0x30;
+		pr_err("%s: Can not read property: tx_delay.", __func__);
+		pr_err("%s: set tx_delay to 0x%x\n",
+		       __func__, bsp_priv->tx_delay);
+	} else {
+		pr_info("%s: TX delay(0x%x).\n", __func__, value);
+		bsp_priv->tx_delay = value;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "rx_delay", &value);
+	if (ret) {
+		bsp_priv->rx_delay = 0x10;
+		pr_err("%s: Can not read property: rx_delay.", __func__);
+		pr_err("%s: set rx_delay to 0x%x\n",
+		       __func__, bsp_priv->rx_delay);
+	} else {
+		pr_info("%s: RX delay(0x%x).\n", __func__, value);
+		bsp_priv->rx_delay = value;
+	}
+
+	bsp_priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
+							"rockchip,grf");
+	if (IS_ERR(bsp_priv->grf))
+		dev_err(&pdev->dev, "Missing rockchip,grf property\n");
+
+	bsp_priv->phyirq_io =
+		of_get_named_gpio_flags(dev->of_node,
+					"phyirq-gpio", 0, &flags);
+	bsp_priv->phyirq_io_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
+
+	bsp_priv->reset_io =
+		of_get_named_gpio_flags(dev->of_node,
+					"reset-gpio", 0, &flags);
+	bsp_priv->reset_io_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
+
+	bsp_priv->power_io =
+		of_get_named_gpio_flags(dev->of_node, "power-gpio", 0, &flags);
+	bsp_priv->power_io_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
+
+	/*power*/
+	if (!gpio_is_valid(bsp_priv->power_io)) {
+		pr_err("%s: Failed to get GPIO %s.\n",
+		       __func__, "power-gpio");
+	} else {
+		ret = gpio_request(bsp_priv->power_io, GPIO_PHY_POWER);
+		if (ret)
+			pr_err("%s: ERROR: Failed to request GPIO %s.\n",
+			       __func__, GPIO_PHY_POWER);
+	}
+
+	if (!gpio_is_valid(bsp_priv->reset_io)) {
+		pr_err("%s: ERROR: Get reset-gpio failed.\n", __func__);
+	} else {
+		ret = gpio_request(bsp_priv->reset_io, GPIO_PHY_RESET);
+		if (ret)
+			pr_err("%s: ERROR: Failed to request GPIO %s.\n",
+			       __func__, GPIO_PHY_RESET);
+	}
+
+	if (bsp_priv->phyirq_io > 0) {
+		struct plat_stmmacenet_data *plat_dat;
+
+		pr_info("PHY irq in use\n");
+		ret = gpio_request(bsp_priv->phyirq_io, GPIO_PHY_IRQ);
+		if (ret < 0) {
+			pr_warn("%s: Failed to request GPIO %s\n",
+				__func__, GPIO_PHY_IRQ);
+			goto goon;
+		}
+
+		ret = gpio_direction_input(bsp_priv->phyirq_io);
+		if (ret < 0) {
+			pr_err("%s, Failed to set input for GPIO %s\n",
+			       __func__, GPIO_PHY_IRQ);
+			gpio_free(bsp_priv->phyirq_io);
+			goto goon;
+		}
+
+		irq = gpio_to_irq(bsp_priv->phyirq_io);
+		if (irq < 0) {
+			ret = irq;
+			pr_err("Failed to set irq for %s\n",
+			       GPIO_PHY_IRQ);
+			gpio_free(bsp_priv->phyirq_io);
+			goto goon;
+		}
+
+		plat_dat = dev_get_platdata(&pdev->dev);
+		if (plat_dat)
+			plat_dat->mdio_bus_data->probed_phy_irq = irq;
+		else
+			pr_err("%s: plat_data is NULL\n", __func__);
+	}
+
+goon:
+	/*rmii or rgmii*/
+	if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) {
+		pr_info("%s: init for RGMII\n", __func__);
+		set_to_rgmii(bsp_priv, bsp_priv->tx_delay, bsp_priv->rx_delay);
+	} else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) {
+		pr_info("%s: init for RMII\n", __func__);
+		set_to_rmii(bsp_priv);
+	} else {
+		pr_err("%s: ERROR: NO interface defined!\n", __func__);
+	}
+
+	bsp_priv->pdev = pdev;
+
+	gmac_clk_init(bsp_priv);
+
+	return bsp_priv;
+}
+
+static int rk_gmac_init(struct platform_device *pdev, void *priv)
+{
+	struct rk_priv_data *bsp_priv = priv;
+	int ret;
+
+	ret = phy_power_on(bsp_priv, true);
+	if (ret)
+		return ret;
+
+	ret = gmac_clk_enable(bsp_priv, true);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void rk_gmac_exit(struct platform_device *pdev, void *priv)
+{
+	struct rk_priv_data *gmac = priv;
+
+	phy_power_on(gmac, false);
+	gmac_clk_enable(gmac, false);
+}
+
+static void rk_fix_speed(void *priv, unsigned int speed)
+{
+	struct rk_priv_data *bsp_priv = priv;
+
+	if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII)
+		set_rgmii_speed(bsp_priv, speed);
+	else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
+		set_rmii_speed(bsp_priv, speed);
+	else
+		pr_err("unsupported interface %d", bsp_priv->phy_iface);
+}
+
+const struct stmmac_of_data rk_gmac_data = {
+	.has_gmac = 1,
+	.tx_coe = 1,
+	.fix_mac_speed = rk_fix_speed,
+	.setup = rk_gmac_setup,
+	.init = rk_gmac_init,
+	.exit = rk_gmac_exit,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 15814b7..b4dee96 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -33,6 +33,7 @@
 
 static const struct of_device_id stmmac_dt_ids[] = {
 	/* SoC specific glue layers should come before generic bindings */
+	{ .compatible = "rockchip,rk3288-gmac", .data = &rk_gmac_data},
 	{ .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data},
 	{ .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
 	{ .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data},
@@ -291,6 +292,8 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
 			return  -ENOMEM;
 		}
 
+		pdev->dev.platform_data = plat_dat;
+
 		ret = stmmac_probe_config_dt(pdev, plat_dat, &mac);
 		if (ret) {
 			pr_err("%s: main dt probe failed", __func__);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
index 25dd1f7..32a0516 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
@@ -24,5 +24,6 @@ extern const struct stmmac_of_data sun7i_gmac_data;
 extern const struct stmmac_of_data stih4xx_dwmac_data;
 extern const struct stmmac_of_data stid127_dwmac_data;
 extern const struct stmmac_of_data socfpga_gmac_data;
+extern const struct stmmac_of_data rk_gmac_data;
 
 #endif /* __STMMAC_PLATFORM_H__ */
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 2/4] GMAC: modify CRU config for Rockchip RK3288 SoCs integrated GMAC
From: Roger Chen @ 2014-11-25  9:08 UTC (permalink / raw)
  To: heiko
  Cc: peppe.cavallaro, netdev, linux-kernel, linux-rockchip, kever.yang,
	mark.yao, eddie.cai, roger.chen

modify CRU config for GMAC driver

Signed-off-by: Roger Chen <roger.chen@rock-chips.com>
---
 drivers/clk/rockchip/clk-rk3288.c      |   14 +++++++-------
 include/dt-bindings/clock/rk3288-cru.h |    4 ++++
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 2327829..60237dc 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -187,7 +187,7 @@ PNAME(mux_uart2_p)	= { "uart2_src", "uart2_frac", "xin24m" };
 PNAME(mux_uart3_p)	= { "uart3_src", "uart3_frac", "xin24m" };
 PNAME(mux_uart4_p)	= { "uart4_src", "uart4_frac", "xin24m" };
 PNAME(mux_cif_out_p)	= { "cif_src", "xin24m" };
-PNAME(mux_macref_p)	= { "mac_src", "ext_gmac" };
+PNAME(mux_mac_p)	= { "mac_pll_src", "ext_gmac" };
 PNAME(mux_hsadcout_p)	= { "hsadc_src", "ext_hsadc" };
 PNAME(mux_edp_24m_p)	= { "ext_edp_24m", "xin24m" };
 PNAME(mux_tspout_p)	= { "cpll", "gpll", "npll", "xin27m" };
@@ -560,18 +560,18 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
 	MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, 0,
 			RK3288_CLKSEL_CON(3), 8, 2, MFLAGS),
 
-	COMPOSITE(0, "mac_src", mux_pll_src_npll_cpll_gpll_p, 0,
+	COMPOSITE(SCLK_MAC_PLL, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
 			RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS,
 			RK3288_CLKGATE_CON(2), 5, GFLAGS),
-	MUX(0, "macref", mux_macref_p, 0,
+	MUX(SCLK_MAC, "mac_clk", mux_mac_p, 0,
 			RK3288_CLKSEL_CON(21), 4, 1, MFLAGS),
-	GATE(0, "sclk_macref_out", "macref", 0,
+	GATE(SCLK_MACREF_OUT, "sclk_macref_out", "mac_clk", 0,
 			RK3288_CLKGATE_CON(5), 3, GFLAGS),
-	GATE(SCLK_MACREF, "sclk_macref", "macref", 0,
+	GATE(SCLK_MACREF, "sclk_macref", "mac_clk", 0,
 			RK3288_CLKGATE_CON(5), 2, GFLAGS),
-	GATE(SCLK_MAC_RX, "sclk_mac_rx", "macref", 0,
+	GATE(SCLK_MAC_RX, "sclk_mac_rx", "mac_clk", 0,
 			RK3288_CLKGATE_CON(5), 0, GFLAGS),
-	GATE(SCLK_MAC_TX, "sclk_mac_tx", "macref", 0,
+	GATE(SCLK_MAC_TX, "sclk_mac_tx", "mac_clk", 0,
 			RK3288_CLKGATE_CON(5), 1, GFLAGS),
 
 	COMPOSITE(0, "hsadc_src", mux_pll_src_cpll_gpll_p, 0,
diff --git a/include/dt-bindings/clock/rk3288-cru.h b/include/dt-bindings/clock/rk3288-cru.h
index 100a08c..f9496f5 100644
--- a/include/dt-bindings/clock/rk3288-cru.h
+++ b/include/dt-bindings/clock/rk3288-cru.h
@@ -72,6 +72,10 @@
 #define SCLK_HEVC_CABAC		111
 #define SCLK_HEVC_CORE		112
 
+#define SCLK_MAC_PLL		150
+#define SCLK_MAC		151
+#define SCLK_MACREF_OUT		152
+
 #define DCLK_VOP0		190
 #define DCLK_VOP1		191
 
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 3/4] GMAC: dts: add gmac info for rk3288
From: Roger Chen @ 2014-11-25  9:08 UTC (permalink / raw)
  To: heiko
  Cc: peppe.cavallaro, netdev, linux-kernel, linux-rockchip, kever.yang,
	mark.yao, eddie.cai, roger.chen

add gmac info in rk3288.dtsi for GMAC driver

Signed-off-by: Roger Chen <roger.chen@rock-chips.com>
---
 arch/arm/boot/dts/rk3288.dtsi |   59 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 0f50d5d..949675d 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -137,6 +137,13 @@
 		#clock-cells = <0>;
 	};
 
+	ext_gmac: external-gmac-clock {
+		compatible = "fixed-clock";
+		clock-frequency = <125000000>;
+		clock-output-names = "ext_gmac";
+		#clock-cells = <0>;
+	};
+
 	timer {
 		compatible = "arm,armv7-timer";
 		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
@@ -490,6 +497,25 @@
 		reg = <0xff740000 0x1000>;
 	};
 
+	gmac: eth@ff290000 {
+		compatible = "rockchip,rk3288-gmac";
+		reg = <0xff290000 0x10000>;
+		interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;  /*irq=59*/
+		interrupt-names = "macirq";
+		rockchip,grf = <&grf>;
+		clocks = <&cru SCLK_MAC>, <&cru SCLK_MAC_PLL>,
+			<&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>,
+			<&cru SCLK_MACREF>, <&cru SCLK_MACREF_OUT>,
+			<&cru ACLK_GMAC>, <&cru PCLK_GMAC>;
+		clock-names = "stmmaceth", "clk_mac_pll",
+			"mac_clk_rx", "mac_clk_tx",
+			"clk_mac_ref", "clk_mac_refout",
+			"aclk_mac", "pclk_mac";
+		phy-mode = "rgmii";
+		pinctrl-names = "default";
+		pinctrl-0 = <&rgmii_pin /*&rmii_pin*/>;
+	};
+
 	cru: clock-controller@ff760000 {
 		compatible = "rockchip,rk3288-cru";
 		reg = <0xff760000 0x1000>;
@@ -1040,5 +1066,38 @@
 				rockchip,pins = <7 23 3 &pcfg_pull_none>;
 			};
 		};
+
+		gmac {
+			rgmii_pin: rgmii-pins {
+				rockchip,pins = <3 30 3 &pcfg_pull_none>,
+						<3 31 3 &pcfg_pull_none>,
+						<3 26 3 &pcfg_pull_none>,
+						<3 27 3 &pcfg_pull_none>,
+						<3 28 3 &pcfg_pull_none>,
+						<3 29 3 &pcfg_pull_none>,
+						<3 24 3 &pcfg_pull_none>,
+						<3 25 3 &pcfg_pull_none>,
+						<4 0 3 &pcfg_pull_none>,
+						<4 5 3 &pcfg_pull_none>,
+						<4 6 3 &pcfg_pull_none>,
+						<4 9 3 &pcfg_pull_none>,
+						<4 4 3 &pcfg_pull_none>,
+						<4 1 3 &pcfg_pull_none>,
+						<4 3 3 &pcfg_pull_none>;
+			};
+
+			rmii_pin: rmii-pins {
+				rockchip,pins = <3 30 3 &pcfg_pull_none>,
+						<3 31 3 &pcfg_pull_none>,
+						<3 28 3 &pcfg_pull_none>,
+						<3 29 3 &pcfg_pull_none>,
+						<4 0 3 &pcfg_pull_none>,
+						<4 5 3 &pcfg_pull_none>,
+						<4 4 3 &pcfg_pull_none>,
+						<4 1 3 &pcfg_pull_none>,
+						<4 2 3 &pcfg_pull_none>,
+						<4 3 3 &pcfg_pull_none>;
+			};
+		};
 	};
 };
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 4/4] GMAC: dts: enable gmac on RK3288 evb board
From: Roger Chen @ 2014-11-25  9:09 UTC (permalink / raw)
  To: heiko
  Cc: peppe.cavallaro, netdev, linux-kernel, linux-rockchip, kever.yang,
	mark.yao, eddie.cai, roger.chen

enable gmac in rk3288-evb-rk808.dts

Signed-off-by: Roger Chen <roger.chen@rock-chips.com>
---
 arch/arm/boot/dts/rk3288-evb-rk808.dts |   22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288-evb-rk808.dts b/arch/arm/boot/dts/rk3288-evb-rk808.dts
index d8c775e6..168b4fa 100644
--- a/arch/arm/boot/dts/rk3288-evb-rk808.dts
+++ b/arch/arm/boot/dts/rk3288-evb-rk808.dts
@@ -152,3 +152,25 @@
 		};
 	};
 };
+
+&ext_gmac {
+	clock-frequency = <125000000>;
+	clock-output-names = "ext_gmac";
+};
+
+&gmac {
+	//pmu_regulator = "act_ldo5";
+	//pmu_enable_level = <1>; //1->HIGH, 0->LOW
+	power-gpio = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+	reset-gpio = <&gpio4 7 GPIO_ACTIVE_LOW>;
+	//phyirq-gpio = <&gpio4 2 GPIO_ACTIVE_LOW>;
+	phy-mode = "rgmii";
+	clock_in_out = "input";
+	assigned-clocks = <&cru SCLK_MAC>;
+	assigned-clock-parents = <&ext_gmac>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pin>; /*&rmii_pin*/
+	tx_delay = <0x30>;
+	rx_delay = <0x10>;
+	status = "ok";
+};
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH][v2] mdio-mux-gpio: Use GPIO descriptor interface and new gpiod_set_array function
From: Rojhalat Ibrahim @ 2014-11-25  9:31 UTC (permalink / raw)
  To: linux-gpio@vger.kernel.org, netdev
  Cc: Linus Walleij, Alexandre Courbot, David Miller, Florian Fainelli,
	David Daney

Convert mdio-mux-gpio to the GPIO descriptor interface and use the new
gpiod_set_array function to set all output signals simultaneously.

Signed-off-by: Rojhalat Ibrahim <imr@rtschenk.de>
Acked-by: David S. Miller <davem@davemloft.net>
--
This patch depends on the gpiod_set_array function, which is available in
the linux-gpio devel tree.

v2: fix gpiod_get_index usage

 drivers/net/phy/mdio-mux-gpio.c |   38 ++++++++++++++------------------------
 1 file changed, 14 insertions(+), 24 deletions(-)

diff --git a/drivers/net/phy/mdio-mux-gpio.c b/drivers/net/phy/mdio-mux-gpio.c
index 0966951..1167c5b 100644
--- a/drivers/net/phy/mdio-mux-gpio.c
+++ b/drivers/net/phy/mdio-mux-gpio.c
@@ -14,13 +14,13 @@
 #include <linux/mdio-mux.h>
 #include <linux/of_gpio.h>
 
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.1"
 #define DRV_DESCRIPTION "GPIO controlled MDIO bus multiplexer driver"
 
 #define MDIO_MUX_GPIO_MAX_BITS 8
 
 struct mdio_mux_gpio_state {
-	int gpio[MDIO_MUX_GPIO_MAX_BITS];
+	struct gpio_desc *gpio[MDIO_MUX_GPIO_MAX_BITS];
 	unsigned int num_gpios;
 	void *mux_handle;
 };
@@ -28,29 +28,23 @@ struct mdio_mux_gpio_state {
 static int mdio_mux_gpio_switch_fn(int current_child, int desired_child,
 				   void *data)
 {
-	int change;
+	int values[MDIO_MUX_GPIO_MAX_BITS];
 	unsigned int n;
 	struct mdio_mux_gpio_state *s = data;
 
 	if (current_child == desired_child)
 		return 0;
 
-	change = current_child == -1 ? -1 : current_child ^ desired_child;
-
 	for (n = 0; n < s->num_gpios; n++) {
-		if (change & 1)
-			gpio_set_value_cansleep(s->gpio[n],
-						(desired_child & 1) != 0);
-		change >>= 1;
-		desired_child >>= 1;
+		values[n] = (desired_child >> n) & 1;
 	}
+	gpiod_set_array_cansleep(s->num_gpios, s->gpio, values);
 
 	return 0;
 }
 
 static int mdio_mux_gpio_probe(struct platform_device *pdev)
 {
-	enum of_gpio_flags f;
 	struct mdio_mux_gpio_state *s;
 	int num_gpios;
 	unsigned int n;
@@ -70,22 +64,14 @@ static int mdio_mux_gpio_probe(struct platform_device *pdev)
 	s->num_gpios = num_gpios;
 
 	for (n = 0; n < num_gpios; ) {
-		int gpio = of_get_gpio_flags(pdev->dev.of_node, n, &f);
-		if (gpio < 0) {
-			r = (gpio == -ENODEV) ? -EPROBE_DEFER : gpio;
+		struct gpio_desc *gpio = gpiod_get_index(&pdev->dev, NULL, n,
+							 GPIOD_OUT_LOW);
+		if (IS_ERR(gpio)) {
+			r = PTR_ERR(gpio);
 			goto err;
 		}
 		s->gpio[n] = gpio;
-
 		n++;
-
-		r = gpio_request(gpio, "mdio_mux_gpio");
-		if (r)
-			goto err;
-
-		r = gpio_direction_output(gpio, 0);
-		if (r)
-			goto err;
 	}
 
 	r = mdio_mux_init(&pdev->dev,
@@ -98,15 +84,19 @@ static int mdio_mux_gpio_probe(struct platform_device *pdev)
 err:
 	while (n) {
 		n--;
-		gpio_free(s->gpio[n]);
+		gpiod_put(s->gpio[n]);
 	}
 	return r;
 }
 
 static int mdio_mux_gpio_remove(struct platform_device *pdev)
 {
+	unsigned int n;
 	struct mdio_mux_gpio_state *s = dev_get_platdata(&pdev->dev);
 	mdio_mux_uninit(s->mux_handle);
+	for (n = 0; n < s->num_gpios; n++) {
+		gpiod_put(s->gpio[n]);
+	}
 	return 0;
 }
 
--
2.0.4


^ permalink raw reply related

* Re: [PATCH 2/4] GMAC: modify CRU config for Rockchip RK3288 SoCs integrated GMAC
From: Kever Yang @ 2014-11-25  9:39 UTC (permalink / raw)
  To: Roger Chen, heiko
  Cc: peppe.cavallaro, netdev, linux-kernel, linux-rockchip, mark.yao,
	eddie.cai
In-Reply-To: <1416906512-26120-1-git-send-email-roger.chen@rock-chips.com>

Hi  Roger,

This  patch should be split into two patch, one for clock ID definition,
one for mac related clocks update.

The Subject for clk-rk3288.c should use below prefix:
clk: rockchip: modify clock for mac ...

On 11/25/2014 05:08 PM, Roger Chen wrote:
> modify CRU config for GMAC driver
Could you detail the reason for this patch in commit message?
> Signed-off-by: Roger Chen <roger.chen@rock-chips.com>
> ---
>   drivers/clk/rockchip/clk-rk3288.c      |   14 +++++++-------
>   include/dt-bindings/clock/rk3288-cru.h |    4 ++++
>   2 files changed, 11 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
> index 2327829..60237dc 100644
> --- a/drivers/clk/rockchip/clk-rk3288.c
> +++ b/drivers/clk/rockchip/clk-rk3288.c
> @@ -187,7 +187,7 @@ PNAME(mux_uart2_p)	= { "uart2_src", "uart2_frac", "xin24m" };
>   PNAME(mux_uart3_p)	= { "uart3_src", "uart3_frac", "xin24m" };
>   PNAME(mux_uart4_p)	= { "uart4_src", "uart4_frac", "xin24m" };
>   PNAME(mux_cif_out_p)	= { "cif_src", "xin24m" };
> -PNAME(mux_macref_p)	= { "mac_src", "ext_gmac" };
> +PNAME(mux_mac_p)	= { "mac_pll_src", "ext_gmac" };
>   PNAME(mux_hsadcout_p)	= { "hsadc_src", "ext_hsadc" };
>   PNAME(mux_edp_24m_p)	= { "ext_edp_24m", "xin24m" };
>   PNAME(mux_tspout_p)	= { "cpll", "gpll", "npll", "xin27m" };
> @@ -560,18 +560,18 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
>   	MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, 0,
>   			RK3288_CLKSEL_CON(3), 8, 2, MFLAGS),
>   
> -	COMPOSITE(0, "mac_src", mux_pll_src_npll_cpll_gpll_p, 0,
> +	COMPOSITE(SCLK_MAC_PLL, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
>   			RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS,
>   			RK3288_CLKGATE_CON(2), 5, GFLAGS),
> -	MUX(0, "macref", mux_macref_p, 0,
> +	MUX(SCLK_MAC, "mac_clk", mux_mac_p, 0,
>   			RK3288_CLKSEL_CON(21), 4, 1, MFLAGS),
> -	GATE(0, "sclk_macref_out", "macref", 0,
> +	GATE(SCLK_MACREF_OUT, "sclk_macref_out", "mac_clk", 0,
>   			RK3288_CLKGATE_CON(5), 3, GFLAGS),
> -	GATE(SCLK_MACREF, "sclk_macref", "macref", 0,
> +	GATE(SCLK_MACREF, "sclk_macref", "mac_clk", 0,
>   			RK3288_CLKGATE_CON(5), 2, GFLAGS),
> -	GATE(SCLK_MAC_RX, "sclk_mac_rx", "macref", 0,
> +	GATE(SCLK_MAC_RX, "sclk_mac_rx", "mac_clk", 0,
>   			RK3288_CLKGATE_CON(5), 0, GFLAGS),
> -	GATE(SCLK_MAC_TX, "sclk_mac_tx", "macref", 0,
> +	GATE(SCLK_MAC_TX, "sclk_mac_tx", "mac_clk", 0,
>   			RK3288_CLKGATE_CON(5), 1, GFLAGS),
>   
>   	COMPOSITE(0, "hsadc_src", mux_pll_src_cpll_gpll_p, 0,
> diff --git a/include/dt-bindings/clock/rk3288-cru.h b/include/dt-bindings/clock/rk3288-cru.h
> index 100a08c..f9496f5 100644
> --- a/include/dt-bindings/clock/rk3288-cru.h
> +++ b/include/dt-bindings/clock/rk3288-cru.h
> @@ -72,6 +72,10 @@
>   #define SCLK_HEVC_CABAC		111
>   #define SCLK_HEVC_CORE		112
>   
> +#define SCLK_MAC_PLL		150
> +#define SCLK_MAC		151
> +#define SCLK_MACREF_OUT		152
> +
>   #define DCLK_VOP0		190
>   #define DCLK_VOP1		191
>   

^ permalink raw reply

* [PATCH net] net/mlx4_core: Limit count field to 24 bits in qp_alloc_res
From: Or Gerlitz @ 2014-11-25  9:54 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, Matan Barak, Amir Vadai, Jack Morgenstein, Or Gerlitz

From: Jack Morgenstein <jackm@dev.mellanox.co.il>

Some VF drivers use the upper byte of "param1" (the qp count field)
in mlx4_qp_reserve_range() to pass flags which are used to optimize
the range allocation.

Under the current code, if any of these flags are set, the 32-bit
count field yields a count greater than 2^24, which is out of range,
and this VF fails.

As these flags represent a "best-effort" allocation hint anyway, they may
safely be ignored. Therefore, the PF driver may simply mask out the bits.

Fixes: c82e9aa0a8 "mlx4_core: resource tracking for HCA resources used by guests"
Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
---

Hi Dave, 

This fix goes way backi down to kernel 3.3... I think we will be good 
if it pushed to -stable of >= 3.10

 .../net/ethernet/mellanox/mlx4/resource_tracker.c  |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 5d2498d..cd5cf6d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -1546,7 +1546,7 @@ static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
 
 	switch (op) {
 	case RES_OP_RESERVE:
-		count = get_param_l(&in_param);
+		count = get_param_l(&in_param) & 0xffffff;
 		align = get_param_h(&in_param);
 		err = mlx4_grant_resource(dev, slave, RES_QP, count, 0);
 		if (err)
-- 
1.7.1

^ permalink raw reply related

* Re: [PATCH 3/4] GMAC: dts: add gmac info for rk3288
From: Kever Yang @ 2014-11-25  9:55 UTC (permalink / raw)
  To: Roger Chen, heiko
  Cc: peppe.cavallaro, netdev, linux-kernel, linux-rockchip, mark.yao,
	eddie.cai
In-Reply-To: <1416906536-26158-1-git-send-email-roger.chen@rock-chips.com>

Hi Roger,

The Subject should use below prefix:
ARM: dts: rockchip: add gmac info for rk3288

On 11/25/2014 05:08 PM, Roger Chen wrote:
> add gmac info in rk3288.dtsi for GMAC driver
>
> Signed-off-by: Roger Chen <roger.chen@rock-chips.com>
> ---
>   arch/arm/boot/dts/rk3288.dtsi |   59 +++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 59 insertions(+)
>
> diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
> index 0f50d5d..949675d 100644
> --- a/arch/arm/boot/dts/rk3288.dtsi
> +++ b/arch/arm/boot/dts/rk3288.dtsi
> @@ -137,6 +137,13 @@
>   		#clock-cells = <0>;
>   	};
>   
> +	ext_gmac: external-gmac-clock {
> +		compatible = "fixed-clock";
> +		clock-frequency = <125000000>;
> +		clock-output-names = "ext_gmac";
> +		#clock-cells = <0>;
> +	};
> +
I'm not sure Heiko will happy with both add the new clock source and
gmac node in these patch.

>   	timer {
>   		compatible = "arm,armv7-timer";
>   		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
> @@ -490,6 +497,25 @@
>   		reg = <0xff740000 0x1000>;
>   	};
>   
> +	gmac: eth@ff290000 {
> +		compatible = "rockchip,rk3288-gmac";
> +		reg = <0xff290000 0x10000>;
> +		interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;  /*irq=59*/
> +		interrupt-names = "macirq";
> +		rockchip,grf = <&grf>;
> +		clocks = <&cru SCLK_MAC>, <&cru SCLK_MAC_PLL>,
> +			<&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>,
> +			<&cru SCLK_MACREF>, <&cru SCLK_MACREF_OUT>,
> +			<&cru ACLK_GMAC>, <&cru PCLK_GMAC>;
> +		clock-names = "stmmaceth", "clk_mac_pll",
> +			"mac_clk_rx", "mac_clk_tx",
> +			"clk_mac_ref", "clk_mac_refout",
> +			"aclk_mac", "pclk_mac";
> +		phy-mode = "rgmii";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&rgmii_pin /*&rmii_pin*/>;
> +	};
> +
The controller dts node should be sort by the base address, I'm sure 
this is in a
wrong place.

- Kever
>   	cru: clock-controller@ff760000 {
>   		compatible = "rockchip,rk3288-cru";
>   		reg = <0xff760000 0x1000>;
> @@ -1040,5 +1066,38 @@
>   				rockchip,pins = <7 23 3 &pcfg_pull_none>;
>   			};
>   		};
> +
> +		gmac {
> +			rgmii_pin: rgmii-pins {
> +				rockchip,pins = <3 30 3 &pcfg_pull_none>,
> +						<3 31 3 &pcfg_pull_none>,
> +						<3 26 3 &pcfg_pull_none>,
> +						<3 27 3 &pcfg_pull_none>,
> +						<3 28 3 &pcfg_pull_none>,
> +						<3 29 3 &pcfg_pull_none>,
> +						<3 24 3 &pcfg_pull_none>,
> +						<3 25 3 &pcfg_pull_none>,
> +						<4 0 3 &pcfg_pull_none>,
> +						<4 5 3 &pcfg_pull_none>,
> +						<4 6 3 &pcfg_pull_none>,
> +						<4 9 3 &pcfg_pull_none>,
> +						<4 4 3 &pcfg_pull_none>,
> +						<4 1 3 &pcfg_pull_none>,
> +						<4 3 3 &pcfg_pull_none>;
> +			};
> +
> +			rmii_pin: rmii-pins {
> +				rockchip,pins = <3 30 3 &pcfg_pull_none>,
> +						<3 31 3 &pcfg_pull_none>,
> +						<3 28 3 &pcfg_pull_none>,
> +						<3 29 3 &pcfg_pull_none>,
> +						<4 0 3 &pcfg_pull_none>,
> +						<4 5 3 &pcfg_pull_none>,
> +						<4 4 3 &pcfg_pull_none>,
> +						<4 1 3 &pcfg_pull_none>,
> +						<4 2 3 &pcfg_pull_none>,
> +						<4 3 3 &pcfg_pull_none>;
> +			};
> +		};
>   	};
>   };

^ permalink raw reply

* Re: [PATCH 4/4] GMAC: dts: enable gmac on RK3288 evb board
From: Kever Yang @ 2014-11-25  9:59 UTC (permalink / raw)
  To: Roger Chen, heiko
  Cc: peppe.cavallaro, netdev, linux-kernel, linux-rockchip, mark.yao,
	eddie.cai
In-Reply-To: <1416906549-26196-1-git-send-email-roger.chen@rock-chips.com>

Hi Roger,

The subject should prefix:
Arm: dts: rockchip: enable ...

On 11/25/2014 05:09 PM, Roger Chen wrote:
> enable gmac in rk3288-evb-rk808.dts
>
> Signed-off-by: Roger Chen <roger.chen@rock-chips.com>
> ---
>   arch/arm/boot/dts/rk3288-evb-rk808.dts |   22 ++++++++++++++++++++++
>   1 file changed, 22 insertions(+)
>
> diff --git a/arch/arm/boot/dts/rk3288-evb-rk808.dts b/arch/arm/boot/dts/rk3288-evb-rk808.dts
> index d8c775e6..168b4fa 100644
> --- a/arch/arm/boot/dts/rk3288-evb-rk808.dts
> +++ b/arch/arm/boot/dts/rk3288-evb-rk808.dts
> @@ -152,3 +152,25 @@
>   		};
>   	};
>   };
> +
> +&ext_gmac {
> +	clock-frequency = <125000000>;
> +	clock-output-names = "ext_gmac";
> +};
> +
> +&gmac {
> +	//pmu_regulator = "act_ldo5";
> +	//pmu_enable_level = <1>; //1->HIGH, 0->LOW
remove these unused code.
> +	power-gpio = <&gpio0 6 GPIO_ACTIVE_HIGH>;
> +	reset-gpio = <&gpio4 7 GPIO_ACTIVE_LOW>;
> +	//phyirq-gpio = <&gpio4 2 GPIO_ACTIVE_LOW>;
same.
> +	phy-mode = "rgmii";
> +	clock_in_out = "input";
> +	assigned-clocks = <&cru SCLK_MAC>;
> +	assigned-clock-parents = <&ext_gmac>;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&rgmii_pin>; /*&rmii_pin*/
same.

- Kever
> +	tx_delay = <0x30>;
> +	rx_delay = <0x10>;
> +	status = "ok";
> +};

^ permalink raw reply

* Re: [PATCH 1/4] GMAC: add driver for Rockchip RK3288 SoCs integrated GMAC
From: Giuseppe CAVALLARO @ 2014-11-25 10:05 UTC (permalink / raw)
  To: Roger Chen, heiko
  Cc: netdev, linux-kernel, linux-rockchip, kever.yang, mark.yao,
	eddie.cai
In-Reply-To: <1416906460-26078-2-git-send-email-roger.chen@rock-chips.com>

Hello Roger

thx for these patches, my comments inline below

On 11/25/2014 10:07 AM, Roger Chen wrote:
> This driver is based on stmmac driver.
>
> Signed-off-by: Roger Chen <roger.chen@rock-chips.com>
> ---
>   drivers/net/ethernet/stmicro/stmmac/Makefile       |    2 +-
>   drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c     |  629 ++++++++++++++++++++
>   .../net/ethernet/stmicro/stmmac/stmmac_platform.c  |    3 +
>   .../net/ethernet/stmicro/stmmac/stmmac_platform.h  |    1 +
>   4 files changed, 634 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
> index ac4d562..73c2715 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/Makefile
> +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
> @@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o	\
>
>   obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
>   stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.o	\
> -		       dwmac-sti.o dwmac-socfpga.o
> +		       dwmac-sti.o dwmac-socfpga.o dwmac-rk.o
>
>   obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
>   stmmac-pci-objs:= stmmac_pci.o
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
> new file mode 100644
> index 0000000..9e50b37
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
> @@ -0,0 +1,629 @@
> +/**
> + * dwmac-rk.c - Rockchip RK3288 DWMAC specific glue layer
> + *
> + * Copyright (C) 2014 Chen-Zhi (Roger Chen)
> + *
> + * Chen-Zhi (Roger Chen)  <roger.chen@rock-chips.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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/stmmac.h>
> +#include <linux/clk.h>
> +#include <linux/phy.h>
> +#include <linux/of_net.h>
> +#include <linux/gpio.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of_device.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/delay.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
> +
> +struct rk_priv_data {
> +	struct platform_device *pdev;
> +	int phy_iface;
> +	bool power_ctrl_by_pmu;
> +	char pmu_regulator[32];
> +	int pmu_enable_level;
> +
> +	int power_io;
> +	int power_io_level;
> +	int reset_io;
> +	int reset_io_level;
> +	int phyirq_io;
> +	int phyirq_io_level;
> +
> +	bool clk_enabled;
> +	bool clock_input;
> +
> +	struct clk *clk_mac;
> +	struct clk *clk_mac_pll;
> +	struct clk *gmac_clkin;
> +	struct clk *mac_clk_rx;
> +	struct clk *mac_clk_tx;
> +	struct clk *clk_mac_ref;
> +	struct clk *clk_mac_refout;
> +	struct clk *aclk_mac;
> +	struct clk *pclk_mac;
> +
> +	int tx_delay;
> +	int rx_delay;
> +
> +	struct regmap *grf;
> +};
> +
> +#define RK3288_GRF_SOC_CON1 0x0248
> +#define RK3288_GRF_SOC_CON3 0x0250
> +#define RK3288_GRF_GPIO3D_E 0x01ec
> +#define RK3288_GRF_GPIO4A_E 0x01f0
> +#define RK3288_GRF_GPIO4B_E 0x01f4
> +
> +/*RK3288_GRF_SOC_CON1*/
> +#define GMAC_PHY_INTF_SEL_RGMII ((0x01C0 << 16) | (0x0040))
> +#define GMAC_PHY_INTF_SEL_RMII  ((0x01C0 << 16) | (0x0100))
> +#define GMAC_FLOW_CTRL          ((0x0200 << 16) | (0x0200))
> +#define GMAC_FLOW_CTRL_CLR      ((0x0200 << 16) | (0x0000))
> +#define GMAC_SPEED_10M          ((0x0400 << 16) | (0x0000))
> +#define GMAC_SPEED_100M         ((0x0400 << 16) | (0x0400))
> +#define GMAC_RMII_CLK_25M       ((0x0800 << 16) | (0x0800))
> +#define GMAC_RMII_CLK_2_5M      ((0x0800 << 16) | (0x0000))
> +#define GMAC_CLK_125M           ((0x3000 << 16) | (0x0000))
> +#define GMAC_CLK_25M            ((0x3000 << 16) | (0x3000))
> +#define GMAC_CLK_2_5M           ((0x3000 << 16) | (0x2000))
> +#define GMAC_RMII_MODE          ((0x4000 << 16) | (0x4000))
> +#define GMAC_RMII_MODE_CLR      ((0x4000 << 16) | (0x0000))
> +
> +/*RK3288_GRF_SOC_CON3*/
> +#define GMAC_TXCLK_DLY_ENABLE   ((0x4000 << 16) | (0x4000))
> +#define GMAC_TXCLK_DLY_DISABLE  ((0x4000 << 16) | (0x0000))
> +#define GMAC_RXCLK_DLY_ENABLE   ((0x8000 << 16) | (0x8000))
> +#define GMAC_RXCLK_DLY_DISABLE  ((0x8000 << 16) | (0x0000))
> +#define GMAC_CLK_RX_DL_CFG(val) ((0x3F80 << 16) | (val<<7))
> +#define GMAC_CLK_TX_DL_CFG(val) ((0x007F << 16) | (val))

why do not use BIT and BIT_MASK where possible?

> +static void set_to_rgmii(struct rk_priv_data *bsp_priv,
> +			 int tx_delay, int rx_delay)
> +{
> +	if (IS_ERR(bsp_priv->grf)) {
> +		pr_err("%s: Missing rockchip,grf property\n", __func__);
> +		return;
> +	}
> +
> +	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
> +		     GMAC_PHY_INTF_SEL_RGMII);
> +	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
> +		     GMAC_RMII_MODE_CLR);

maybe you could perform just one write unless there is some HW
constraint.

> +	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
> +		     GMAC_RXCLK_DLY_ENABLE);
> +	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
> +		     GMAC_TXCLK_DLY_ENABLE);
> +	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
> +		     GMAC_CLK_RX_DL_CFG(rx_delay));
> +	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
> +		     GMAC_CLK_TX_DL_CFG(tx_delay));

ditto

> +
> +	regmap_write(bsp_priv->grf, RK3288_GRF_GPIO3D_E, 0xFFFFFFFF);
> +	regmap_write(bsp_priv->grf, RK3288_GRF_GPIO4B_E,
> +		     0x3<<2<<16 | 0x3<<2);

pls use macros, these shift sequence is really help to decode

> +	regmap_write(bsp_priv->grf, RK3288_GRF_GPIO4A_E, 0xFFFFFFFF);
> +
> +	pr_info("%s: tx delay=0x%x; rx delay=0x%x;\n",
> +		__func__, tx_delay, rx_delay);

may I suggest pr_debug?

> +}
> +
> +static void set_to_rmii(struct rk_priv_data *bsp_priv)
> +{
> +	if (IS_ERR(bsp_priv->grf)) {
> +		pr_err("%s: Missing rockchip,grf property\n", __func__);
> +		return;
> +	}
> +
> +	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
> +		     GMAC_PHY_INTF_SEL_RMII);
> +	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
> +		     GMAC_RMII_MODE);
> +}
> +
> +static void set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
> +{
> +	if (IS_ERR(bsp_priv->grf)) {
> +		pr_err("%s: Missing rockchip,grf property\n", __func__);
> +		return;
> +	}
> +
> +	if (speed == 10)
> +		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_2_5M);
> +	else if (speed == 100)
> +		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_25M);
> +	else if (speed == 1000)
> +		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_125M);
> +	else
> +		pr_err("unknown speed value for RGMII! speed=%d", speed);
> +}
> +
> +static void set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
> +{
> +	if (IS_ERR(bsp_priv->grf)) {
> +		pr_err("%s: Missing rockchip,grf property\n", __func__);
> +		return;
> +	}
> +
> +	if (speed == 10) {
> +		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
> +			     GMAC_RMII_CLK_2_5M);
> +		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
> +			     GMAC_SPEED_10M);
> +	} else if (speed == 100) {
> +		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
> +			     GMAC_RMII_CLK_25M);
> +		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
> +			     GMAC_SPEED_100M);
> +	} else {
> +		pr_err("unknown speed value for RMII! speed=%d", speed);
> +	}
> +}
> +
> +#define MAC_CLK_RX	"mac_clk_rx"
> +#define MAC_CLK_TX	"mac_clk_tx"
> +#define CLK_MAC_REF	"clk_mac_ref"
> +#define CLK_MAC_REF_OUT	"clk_mac_refout"
> +#define CLK_MAC_PLL	"clk_mac_pll"
> +#define ACLK_MAC	"aclk_mac"
> +#define PCLK_MAC	"pclk_mac"
> +#define MAC_CLKIN	"ext_gmac"
> +#define CLK_MAC		"stmmaceth"

Concerning the clocks, the "stmmaceth" is actually used for the main
clock so maybe you should use another name.

See: Documentation/devicetree/bindings/net/stmmac.txt

For St platforms, it has been used: sti-ethclk but we could
used a common and better name: stmmac-phyclk
And I could also propose this change on STi glue-logic.

Then, I think that all the clock macros above should be documented
and maybe managed at DT level, what do you think?

> +
> +int gmac_clk_init(struct rk_priv_data *bsp_priv)
> +{
> +	struct device *dev = &bsp_priv->pdev->dev;
> +
> +	bsp_priv->clk_enabled = false;
> +
> +	bsp_priv->mac_clk_rx = clk_get(dev, MAC_CLK_RX);
> +	if (IS_ERR(bsp_priv->mac_clk_rx))
> +		pr_warn("%s: warning: cannot get clock %s\n",
> +			__func__, MAC_CLK_RX);
> +
> +	bsp_priv->mac_clk_tx = clk_get(dev, MAC_CLK_TX);
> +	if (IS_ERR(bsp_priv->mac_clk_tx))
> +		pr_warn("%s: warning: cannot get clock %s\n",
> +			__func__, MAC_CLK_TX);
> +
> +	bsp_priv->clk_mac_ref = clk_get(dev, CLK_MAC_REF);
> +	if (IS_ERR(bsp_priv->clk_mac_ref))
> +		pr_warn("%s: warning: cannot get clock %s\n",
> +			__func__, CLK_MAC_REF);
> +
> +	bsp_priv->clk_mac_refout = clk_get(dev, CLK_MAC_REF_OUT);
> +	if (IS_ERR(bsp_priv->clk_mac_refout))
> +		pr_warn("%s: warning:cannot get clock %s\n",
> +			__func__, CLK_MAC_REF_OUT);
> +
> +	bsp_priv->aclk_mac = clk_get(dev, ACLK_MAC);
> +	if (IS_ERR(bsp_priv->aclk_mac))
> +		pr_warn("%s: warning: cannot get clock %s\n",
> +			__func__, ACLK_MAC);
> +
> +	bsp_priv->pclk_mac = clk_get(dev, PCLK_MAC);
> +	if (IS_ERR(bsp_priv->pclk_mac))
> +		pr_warn("%s: warning: cannot get clock %s\n",
> +			__func__, PCLK_MAC);
> +
> +	bsp_priv->clk_mac_pll = clk_get(dev, CLK_MAC_PLL);
> +	if (IS_ERR(bsp_priv->clk_mac_pll))
> +		pr_warn("%s: warning: cannot get clock %s\n",
> +			__func__, CLK_MAC_PLL);
> +
> +	bsp_priv->gmac_clkin = clk_get(dev, MAC_CLKIN);
> +	if (IS_ERR(bsp_priv->gmac_clkin))
> +		pr_warn("%s: warning: cannot get clock %s\n",
> +			__func__, MAC_CLKIN);
> +
> +	bsp_priv->clk_mac = clk_get(dev, CLK_MAC);
> +	if (IS_ERR(bsp_priv->clk_mac))
> +		pr_warn("%s: warning: cannot get clock %s\n",
> +			__func__, CLK_MAC);
> +
> +	if (bsp_priv->clock_input) {
> +		pr_info("%s: clock input from PHY\n", __func__);
> +	} else {
> +		if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
> +			clk_set_rate(bsp_priv->clk_mac_pll, 50000000);
> +
> +		clk_set_parent(bsp_priv->clk_mac, bsp_priv->clk_mac_pll);
> +	}
> +
> +	return 0;
> +}
> +
> +static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable)
> +{
> +	int phy_iface = phy_iface = bsp_priv->phy_iface;
> +
> +	if (enable) {
> +		if (!bsp_priv->clk_enabled) {
> +			if (phy_iface == PHY_INTERFACE_MODE_RMII) {
> +				if (!IS_ERR(bsp_priv->mac_clk_rx))
> +					clk_prepare_enable(
> +						bsp_priv->mac_clk_rx);
> +
> +				if (!IS_ERR(bsp_priv->clk_mac_ref))
> +					clk_prepare_enable(
> +						bsp_priv->clk_mac_ref);
> +
> +				if (!IS_ERR(bsp_priv->clk_mac_refout))
> +					clk_prepare_enable(
> +						bsp_priv->clk_mac_refout);
> +			}
> +
> +			if (!IS_ERR(bsp_priv->aclk_mac))
> +				clk_prepare_enable(bsp_priv->aclk_mac);
> +
> +			if (!IS_ERR(bsp_priv->pclk_mac))
> +				clk_prepare_enable(bsp_priv->pclk_mac);
> +
> +			if (!IS_ERR(bsp_priv->mac_clk_tx))
> +				clk_prepare_enable(bsp_priv->mac_clk_tx);
> +
> +			/**
> +			 * if (!IS_ERR(bsp_priv->clk_mac))
> +			 *	clk_prepare_enable(bsp_priv->clk_mac);
> +			 */

why do you need to comment this? could it be related to the stmmaceth
clk that is used by the main?

> +			mdelay(5);

hmm, do you actually need this mdelay? Is it to stabilize PLL sources?

> +			bsp_priv->clk_enabled = true;
> +		}
> +	} else {
> +		if (bsp_priv->clk_enabled) {
> +			if (phy_iface == PHY_INTERFACE_MODE_RMII) {
> +				if (!IS_ERR(bsp_priv->mac_clk_rx))
> +					clk_disable_unprepare(
> +						bsp_priv->mac_clk_rx);
> +
> +				if (!IS_ERR(bsp_priv->clk_mac_ref))
> +					clk_disable_unprepare(
> +						bsp_priv->clk_mac_ref);
> +
> +				if (!IS_ERR(bsp_priv->clk_mac_refout))
> +					clk_disable_unprepare(
> +						bsp_priv->clk_mac_refout);
> +			}
> +
> +			if (!IS_ERR(bsp_priv->aclk_mac))
> +				clk_disable_unprepare(bsp_priv->aclk_mac);
> +
> +			if (!IS_ERR(bsp_priv->pclk_mac))
> +				clk_disable_unprepare(bsp_priv->pclk_mac);
> +
> +			if (!IS_ERR(bsp_priv->mac_clk_tx))
> +				clk_disable_unprepare(bsp_priv->mac_clk_tx);
> +			/**
> +			 * if (!IS_ERR(bsp_priv->clk_mac))
> +			 *	clk_disable_unprepare(bsp_priv->clk_mac);
> +			 */
> +			bsp_priv->clk_enabled = false;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int power_on_by_pmu(struct rk_priv_data *bsp_priv, bool enable)
> +{
> +	struct regulator *ldo;
> +	char *ldostr = bsp_priv->pmu_regulator;
> +	int ret;
> +
> +	if (!ldostr) {
> +		pr_err("%s: no ldo found\n", __func__);
> +		return -1;
> +	}
> +
> +	ldo = regulator_get(NULL, ldostr);
> +	if (!ldo) {
> +		pr_err("\n%s get ldo %s failed\n", __func__, ldostr);
> +	} else {
> +		if (enable) {
> +			if (!regulator_is_enabled(ldo)) {
> +				regulator_set_voltage(ldo, 3300000, 3300000);
> +				ret = regulator_enable(ldo);
> +				if (ret != 0)
> +					pr_err("%s: fail to enable %s\n",
> +					       __func__, ldostr);
> +				else
> +					pr_info("turn on ldo done.\n");
> +			} else {
> +				pr_warn("%s is enabled before enable", ldostr);
> +			}
> +		} else {
> +			if (regulator_is_enabled(ldo)) {
> +				ret = regulator_disable(ldo);
> +				if (ret != 0)
> +					pr_err("%s: fail to disable %s\n",
> +					       __func__, ldostr);
> +				else
> +					pr_info("turn off ldo done.\n");
> +			} else {
> +				pr_warn("%s is disabled before disable",
> +					ldostr);
> +			}
> +		}
> +		regulator_put(ldo);
> +	}
> +
> +	return 0;
> +}
> +
> +static int power_on_by_gpio(struct rk_priv_data *bsp_priv, bool enable)
> +{
> +	if (enable) {
> +		/*power on*/
> +		if (gpio_is_valid(bsp_priv->power_io))
> +			gpio_direction_output(bsp_priv->power_io,
> +					      bsp_priv->power_io_level);
> +	} else {
> +		/*power off*/
> +		if (gpio_is_valid(bsp_priv->power_io))
> +			gpio_direction_output(bsp_priv->power_io,
> +					      !bsp_priv->power_io_level);
> +	}
> +
> +	return 0;
> +}
> +
> +static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable)
> +{
> +	int ret = -1;
> +
> +	pr_info("Ethernet PHY power %s\n", enable == 1 ? "on" : "off");
> +
> +	if (bsp_priv->power_ctrl_by_pmu)
> +		ret = power_on_by_pmu(bsp_priv, enable);
> +	else
> +		ret =  power_on_by_gpio(bsp_priv, enable);
> +
> +	if (enable) {
> +		/*reset*/
> +		if (gpio_is_valid(bsp_priv->reset_io)) {
> +			gpio_direction_output(bsp_priv->reset_io,
> +					      bsp_priv->reset_io_level);
> +			mdelay(5);
> +			gpio_direction_output(bsp_priv->reset_io,
> +					      !bsp_priv->reset_io_level);
> +		}
> +		mdelay(30);
> +
> +	} else {
> +		/*pull down reset*/
> +		if (gpio_is_valid(bsp_priv->reset_io)) {
> +			gpio_direction_output(bsp_priv->reset_io,
> +					      bsp_priv->reset_io_level);
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +#define GPIO_PHY_POWER	"gmac_phy_power"
> +#define GPIO_PHY_RESET	"gmac_phy_reset"
> +#define GPIO_PHY_IRQ	"gmac_phy_irq"
> +
> +static void *rk_gmac_setup(struct platform_device *pdev)
> +{
> +	struct rk_priv_data *bsp_priv;
> +	struct device *dev = &pdev->dev;
> +	enum of_gpio_flags flags;
> +	int ret;
> +	const char *strings = NULL;
> +	int value;
> +	int irq;
> +
> +	bsp_priv = devm_kzalloc(dev, sizeof(*bsp_priv), GFP_KERNEL);
> +	if (!bsp_priv)
> +		return ERR_PTR(-ENOMEM);
> +
> +	bsp_priv->phy_iface = of_get_phy_mode(dev->of_node);
> +
> +	ret = of_property_read_string(dev->of_node, "pmu_regulator", &strings);
> +	if (ret) {
> +		pr_err("%s: Can not read property: pmu_regulator.\n", __func__);
> +		bsp_priv->power_ctrl_by_pmu = false;
> +	} else {
> +		pr_info("%s: ethernet phy power controlled by pmu(%s).\n",
> +			__func__, strings);
> +		bsp_priv->power_ctrl_by_pmu = true;
> +		strcpy(bsp_priv->pmu_regulator, strings);
> +	}
> +
> +	ret = of_property_read_u32(dev->of_node, "pmu_enable_level", &value);
> +	if (ret) {
> +		pr_err("%s: Can not read property: pmu_enable_level.\n",
> +		       __func__);
> +		bsp_priv->power_ctrl_by_pmu = false;
> +	} else {
> +		pr_info("%s: PHY power controlled by pmu(level = %s).\n",
> +			__func__, (value == 1) ? "HIGH" : "LOW");
> +		bsp_priv->power_ctrl_by_pmu = true;
> +		bsp_priv->pmu_enable_level = value;
> +	}
> +
> +	ret = of_property_read_string(dev->of_node, "clock_in_out", &strings);
> +	if (ret) {
> +		pr_err("%s: Can not read property: clock_in_out.\n", __func__);
> +		bsp_priv->clock_input = true;
> +	} else {
> +		pr_info("%s: clock input or output? (%s).\n",
> +			__func__, strings);
> +		if (!strcmp(strings, "input"))
> +			bsp_priv->clock_input = true;
> +		else
> +			bsp_priv->clock_input = false;
> +	}
> +
> +	ret = of_property_read_u32(dev->of_node, "tx_delay", &value);
> +	if (ret) {
> +		bsp_priv->tx_delay = 0x30;
> +		pr_err("%s: Can not read property: tx_delay.", __func__);
> +		pr_err("%s: set tx_delay to 0x%x\n",
> +		       __func__, bsp_priv->tx_delay);
> +	} else {
> +		pr_info("%s: TX delay(0x%x).\n", __func__, value);
> +		bsp_priv->tx_delay = value;
> +	}
> +
> +	ret = of_property_read_u32(dev->of_node, "rx_delay", &value);
> +	if (ret) {
> +		bsp_priv->rx_delay = 0x10;
> +		pr_err("%s: Can not read property: rx_delay.", __func__);
> +		pr_err("%s: set rx_delay to 0x%x\n",
> +		       __func__, bsp_priv->rx_delay);
> +	} else {
> +		pr_info("%s: RX delay(0x%x).\n", __func__, value);
> +		bsp_priv->rx_delay = value;
> +	}
> +
> +	bsp_priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
> +							"rockchip,grf");
> +	if (IS_ERR(bsp_priv->grf))
> +		dev_err(&pdev->dev, "Missing rockchip,grf property\n");

I wonder if you can fail on here and save all the check in
set_rgmii_speed etc.
Maybe this can be considered a mandatory property for the glue-logic.

> +
> +	bsp_priv->phyirq_io =
> +		of_get_named_gpio_flags(dev->of_node,
> +					"phyirq-gpio", 0, &flags);
> +	bsp_priv->phyirq_io_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;


Sorry, did you document all in Documentation/devicetree/bindings/net/ ?

> +
> +	bsp_priv->reset_io =
> +		of_get_named_gpio_flags(dev->of_node,
> +					"reset-gpio", 0, &flags);
> +	bsp_priv->reset_io_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
> +
> +	bsp_priv->power_io =
> +		of_get_named_gpio_flags(dev->of_node, "power-gpio", 0, &flags);
> +	bsp_priv->power_io_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
> +
> +	/*power*/
> +	if (!gpio_is_valid(bsp_priv->power_io)) {
> +		pr_err("%s: Failed to get GPIO %s.\n",
> +		       __func__, "power-gpio");
> +	} else {
> +		ret = gpio_request(bsp_priv->power_io, GPIO_PHY_POWER);
> +		if (ret)
> +			pr_err("%s: ERROR: Failed to request GPIO %s.\n",
> +			       __func__, GPIO_PHY_POWER);
> +	}
> +
> +	if (!gpio_is_valid(bsp_priv->reset_io)) {
> +		pr_err("%s: ERROR: Get reset-gpio failed.\n", __func__);
> +	} else {
> +		ret = gpio_request(bsp_priv->reset_io, GPIO_PHY_RESET);
> +		if (ret)
> +			pr_err("%s: ERROR: Failed to request GPIO %s.\n",
> +			       __func__, GPIO_PHY_RESET);
> +	}
> +
> +	if (bsp_priv->phyirq_io > 0) {
> +		struct plat_stmmacenet_data *plat_dat;
> +
> +		pr_info("PHY irq in use\n");
> +		ret = gpio_request(bsp_priv->phyirq_io, GPIO_PHY_IRQ);
> +		if (ret < 0) {
> +			pr_warn("%s: Failed to request GPIO %s\n",
> +				__func__, GPIO_PHY_IRQ);
> +			goto goon;
> +		}
> +
> +		ret = gpio_direction_input(bsp_priv->phyirq_io);
> +		if (ret < 0) {
> +			pr_err("%s, Failed to set input for GPIO %s\n",
> +			       __func__, GPIO_PHY_IRQ);
> +			gpio_free(bsp_priv->phyirq_io);
> +			goto goon;
> +		}
> +
> +		irq = gpio_to_irq(bsp_priv->phyirq_io);
> +		if (irq < 0) {
> +			ret = irq;
> +			pr_err("Failed to set irq for %s\n",
> +			       GPIO_PHY_IRQ);
> +			gpio_free(bsp_priv->phyirq_io);
> +			goto goon;
> +		}
> +
> +		plat_dat = dev_get_platdata(&pdev->dev);
> +		if (plat_dat)
> +			plat_dat->mdio_bus_data->probed_phy_irq = irq;
> +		else
> +			pr_err("%s: plat_data is NULL\n", __func__);
> +	}
> +
> +goon:
> +	/*rmii or rgmii*/
> +	if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) {
> +		pr_info("%s: init for RGMII\n", __func__);
> +		set_to_rgmii(bsp_priv, bsp_priv->tx_delay, bsp_priv->rx_delay);
> +	} else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) {
> +		pr_info("%s: init for RMII\n", __func__);
> +		set_to_rmii(bsp_priv);
> +	} else {
> +		pr_err("%s: ERROR: NO interface defined!\n", __func__);
> +	}
> +
> +	bsp_priv->pdev = pdev;
> +
> +	gmac_clk_init(bsp_priv);
> +
> +	return bsp_priv;
> +}
> +
> +static int rk_gmac_init(struct platform_device *pdev, void *priv)
> +{
> +	struct rk_priv_data *bsp_priv = priv;
> +	int ret;
> +
> +	ret = phy_power_on(bsp_priv, true);
> +	if (ret)
> +		return ret;
> +
> +	ret = gmac_clk_enable(bsp_priv, true);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static void rk_gmac_exit(struct platform_device *pdev, void *priv)
> +{
> +	struct rk_priv_data *gmac = priv;
> +
> +	phy_power_on(gmac, false);
> +	gmac_clk_enable(gmac, false);
> +}
> +
> +static void rk_fix_speed(void *priv, unsigned int speed)
> +{
> +	struct rk_priv_data *bsp_priv = priv;
> +
> +	if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII)
> +		set_rgmii_speed(bsp_priv, speed);
> +	else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
> +		set_rmii_speed(bsp_priv, speed);
> +	else
> +		pr_err("unsupported interface %d", bsp_priv->phy_iface);
> +}
> +
> +const struct stmmac_of_data rk_gmac_data = {
> +	.has_gmac = 1,
> +	.tx_coe = 1,

FYI, on new gmac there is the HW capability register to dinamically
provide you if coe is supported.

IMO you should add the OF "compatible" string and in case of mac
newer than the 3.50a you can remove coe.


BR
Peppe

> +	.fix_mac_speed = rk_fix_speed,
> +	.setup = rk_gmac_setup,
> +	.init = rk_gmac_init,
> +	.exit = rk_gmac_exit,
> +};
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> index 15814b7..b4dee96 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> @@ -33,6 +33,7 @@
>
>   static const struct of_device_id stmmac_dt_ids[] = {
>   	/* SoC specific glue layers should come before generic bindings */
> +	{ .compatible = "rockchip,rk3288-gmac", .data = &rk_gmac_data},
>   	{ .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data},
>   	{ .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
>   	{ .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data},
> @@ -291,6 +292,8 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
>   			return  -ENOMEM;
>   		}
>
> +		pdev->dev.platform_data = plat_dat;
> +
>   		ret = stmmac_probe_config_dt(pdev, plat_dat, &mac);
>   		if (ret) {
>   			pr_err("%s: main dt probe failed", __func__);
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
> index 25dd1f7..32a0516 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
> @@ -24,5 +24,6 @@ extern const struct stmmac_of_data sun7i_gmac_data;
>   extern const struct stmmac_of_data stih4xx_dwmac_data;
>   extern const struct stmmac_of_data stid127_dwmac_data;
>   extern const struct stmmac_of_data socfpga_gmac_data;
> +extern const struct stmmac_of_data rk_gmac_data;
>
>   #endif /* __STMMAC_PLATFORM_H__ */
>

^ permalink raw reply

* Re: [PATCH 3/4] GMAC: dts: add gmac info for rk3288
From: Heiko Stübner @ 2014-11-25 10:12 UTC (permalink / raw)
  To: Kever Yang
  Cc: Roger Chen, peppe.cavallaro, netdev, linux-kernel, linux-rockchip,
	mark.yao, eddie.cai
In-Reply-To: <54745229.2040503@rock-chips.com>

Hi Roger, Kever,

Am Dienstag, 25. November 2014, 17:55:53 schrieb Kever Yang:
> The Subject should use below prefix:
> ARM: dts: rockchip: add gmac info for rk3288
> 
> On 11/25/2014 05:08 PM, Roger Chen wrote:
> > add gmac info in rk3288.dtsi for GMAC driver
> > 
> > Signed-off-by: Roger Chen <roger.chen@rock-chips.com>
> > ---
> > 
> >   arch/arm/boot/dts/rk3288.dtsi |   59
> >   +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59
> >   insertions(+)
> > 
> > diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
> > index 0f50d5d..949675d 100644
> > --- a/arch/arm/boot/dts/rk3288.dtsi
> > +++ b/arch/arm/boot/dts/rk3288.dtsi
> > @@ -137,6 +137,13 @@
> > 
> >   		#clock-cells = <0>;
> >   	
> >   	};
> > 
> > +	ext_gmac: external-gmac-clock {
> > +		compatible = "fixed-clock";
> > +		clock-frequency = <125000000>;
> > +		clock-output-names = "ext_gmac";
> > +		#clock-cells = <0>;
> > +	};
> > +
> 
> I'm not sure Heiko will happy with both add the new clock source and
> gmac node in these patch.

correct. The ext_gmac is an external clock input providing a special clock to 
the gmac. This makes it a board-specific property, which should also only be 
added on boards having this external source - and of course in the board-
specific dts.


> 
> >   	timer {
> >   	
> >   		compatible = "arm,armv7-timer";
> >   		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
> >   		IRQ_TYPE_LEVEL_HIGH)>,
> > 
> > @@ -490,6 +497,25 @@
> > 
> >   		reg = <0xff740000 0x1000>;
> >   	
> >   	};
> > 
> > +	gmac: eth@ff290000 {
> > +		compatible = "rockchip,rk3288-gmac";
> > +		reg = <0xff290000 0x10000>;
> > +		interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;  /*irq=59*/

please remote the "irq=59" comment, as it is not necessary


> > +		interrupt-names = "macirq";
> > +		rockchip,grf = <&grf>;
> > +		clocks = <&cru SCLK_MAC>, <&cru SCLK_MAC_PLL>,
> > +			<&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>,
> > +			<&cru SCLK_MACREF>, <&cru SCLK_MACREF_OUT>,
> > +			<&cru ACLK_GMAC>, <&cru PCLK_GMAC>;
> > +		clock-names = "stmmaceth", "clk_mac_pll",
> > +			"mac_clk_rx", "mac_clk_tx",
> > +			"clk_mac_ref", "clk_mac_refout",
> > +			"aclk_mac", "pclk_mac";
> > +		phy-mode = "rgmii";
> > +		pinctrl-names = "default";
> > +		pinctrl-0 = <&rgmii_pin /*&rmii_pin*/>;
> > +	};
> > +
> 
> The controller dts node should be sort by the base address, I'm sure
> this is in a
> wrong place.

correct, it is on the wrong place


Heiko

^ permalink raw reply

* [patch net-next v3 00/17] introduce rocker switch driver with hardware accelerated datapath api - phase 1: bridge fdb offload
From: Jiri Pirko @ 2014-11-25 10:28 UTC (permalink / raw)
  To: netdev
  Cc: davem, nhorman, andy, tgraf, dborkman, ogerlitz, jesse, pshelar,
	azhou, ben, stephen, jeffrey.t.kirsher, vyasevic, xiyou.wangcong,
	john.r.fastabend, edumazet, jhs, sfeldma, f.fainelli, roopa,
	linville, jasowang, ebiederm, nicolas.dichtel, ryazanov.s.a,
	buytenh, aviadr, nbd, alexei.starovoitov, Neil.Jerram, ronye,
	simon.horman, alexander.h.duyck, john.ronciak, mleitner, shrijeet,
	gospo, bcrl

Hi all.

This patchset is just the first phase of switch and switch-ish device
support api in kernel. Note that the api will extend.

So what this patchset includes:
- introduce switchdev api skeleton for implementing switch drivers 
- introduce rocker switch driver which implements switchdev api fdb and
  bridge set/get link ndos

As to the discussion if there is need to have specific class of device
representing the switch itself, so far we found no need to introduce that.
But we are generally ok with the idea and when the time comes and it will
be needed, it can be easily introduced without any disturbance.

This patchset introduces switch id export through rtnetlink and sysfs,
which is similar to what we have for port id in SR-IOV. I will send iproute2
patchset for showing the switch id for port netdevs once this is applied.
This applies also for the PF_BRIDGE and fdb iproute2 patches.

iproute2 patches are now available here:
https://github.com/jpirko/iproute2-rocker

For detailed description and version history, please see individual patches.

Jiri Pirko (8):
  bridge: rename fdb_*_hw to fdb_*_hw_addr to avoid confusion
  net: make vid as a parameter for ndo_fdb_add/ndo_fdb_del
  net: rename netdev_phys_port_id to more generic name
  net: introduce generic switch devices support
  rtnl: expose physical switch id for particular device
  net-sysfs: expose physical switch id for particular device
  rocker: introduce rocker switch driver
  rocker: implement ndo_fdb_dump

Scott Feldman (9):
  bridge: call netdev_sw_port_stp_update when bridge port STP status
    changes
  bridge: add API to notify bridge driver of learned FBD on offloaded
    device
  rocker: implement rocker ofdpa flow table manipulation
  rocker: implement L2 bridge offloading
  bridge: move private brport flags to if_bridge.h so port drivers can
    use flags
  bridge: add new brport flag LEARNING_SYNC
  bridge: add new hwmode swdev
  bridge: add brport flags to dflt bridge_getlink
  rocker: add ndo_bridge_setlnk/getlink support for learning policy

 Documentation/networking/switchdev.txt           |   59 +
 MAINTAINERS                                      |   14 +
 drivers/net/ethernet/Kconfig                     |    1 +
 drivers/net/ethernet/Makefile                    |    1 +
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c |    2 +-
 drivers/net/ethernet/emulex/benet/be_main.c      |    3 +-
 drivers/net/ethernet/intel/i40e/i40e_main.c      |    4 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c    |    6 +-
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c   |    2 +-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c |   11 +-
 drivers/net/ethernet/rocker/Kconfig              |   27 +
 drivers/net/ethernet/rocker/Makefile             |    5 +
 drivers/net/ethernet/rocker/rocker.c             | 4363 ++++++++++++++++++++++
 drivers/net/ethernet/rocker/rocker.h             |  428 +++
 drivers/net/macvlan.c                            |    4 +-
 drivers/net/vxlan.c                              |    4 +-
 include/linux/if_bridge.h                        |   30 +
 include/linux/netdevice.h                        |   39 +-
 include/linux/rtnetlink.h                        |    9 +-
 include/net/switchdev.h                          |   37 +
 include/uapi/linux/if_bridge.h                   |    1 +
 include/uapi/linux/if_link.h                     |    2 +
 include/uapi/linux/neighbour.h                   |    1 +
 net/Kconfig                                      |    1 +
 net/Makefile                                     |    3 +
 net/bridge/br_fdb.c                              |  144 +-
 net/bridge/br_private.h                          |   15 +-
 net/bridge/br_stp.c                              |    2 +
 net/core/dev.c                                   |    2 +-
 net/core/net-sysfs.c                             |   26 +-
 net/core/rtnetlink.c                             |  119 +-
 net/switchdev/Kconfig                            |   13 +
 net/switchdev/Makefile                           |    5 +
 net/switchdev/switchdev.c                        |   52 +
 34 files changed, 5336 insertions(+), 99 deletions(-)
 create mode 100644 Documentation/networking/switchdev.txt
 create mode 100644 drivers/net/ethernet/rocker/Kconfig
 create mode 100644 drivers/net/ethernet/rocker/Makefile
 create mode 100644 drivers/net/ethernet/rocker/rocker.c
 create mode 100644 drivers/net/ethernet/rocker/rocker.h
 create mode 100644 include/net/switchdev.h
 create mode 100644 net/switchdev/Kconfig
 create mode 100644 net/switchdev/Makefile
 create mode 100644 net/switchdev/switchdev.c

-- 
1.9.3

^ permalink raw reply

* [patch net-next v3 01/17] bridge: rename fdb_*_hw to fdb_*_hw_addr to avoid confusion
From: Jiri Pirko @ 2014-11-25 10:28 UTC (permalink / raw)
  To: netdev
  Cc: davem, nhorman, andy, tgraf, dborkman, ogerlitz, jesse, pshelar,
	azhou, ben, stephen, jeffrey.t.kirsher, vyasevic, xiyou.wangcong,
	john.r.fastabend, edumazet, jhs, sfeldma, f.fainelli, roopa,
	linville, jasowang, ebiederm, nicolas.dichtel, ryazanov.s.a,
	buytenh, aviadr, nbd, alexei.starovoitov, Neil.Jerram, ronye,
	simon.horman, alexander.h.duyck, john.ronciak, mleitner, shrijeet,
	gospo, bcrl
In-Reply-To: <1416911328-10979-1-git-send-email-jiri@resnulli.us>

The current name might seem that this actually offloads the fdb entry to
hw. So rename it to clearly present that this for hardware address
addition/removal.

Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
new in v2 as suggested by DaveM
v2->v3:
-moved the patch to the patchset head
---
 net/bridge/br_fdb.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 6f6c95c..08ef4e7 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -90,7 +90,7 @@ static void fdb_rcu_free(struct rcu_head *head)
  * are then updated with the new information.
  * Called under RTNL.
  */
-static void fdb_add_hw(struct net_bridge *br, const unsigned char *addr)
+static void fdb_add_hw_addr(struct net_bridge *br, const unsigned char *addr)
 {
 	int err;
 	struct net_bridge_port *p;
@@ -118,7 +118,7 @@ undo:
  * the ports with needed information.
  * Called under RTNL.
  */
-static void fdb_del_hw(struct net_bridge *br, const unsigned char *addr)
+static void fdb_del_hw_addr(struct net_bridge *br, const unsigned char *addr)
 {
 	struct net_bridge_port *p;
 
@@ -133,7 +133,7 @@ static void fdb_del_hw(struct net_bridge *br, const unsigned char *addr)
 static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f)
 {
 	if (f->is_static)
-		fdb_del_hw(br, f->addr.addr);
+		fdb_del_hw_addr(br, f->addr.addr);
 
 	hlist_del_rcu(&f->hlist);
 	fdb_notify(br, f, RTM_DELNEIGH);
@@ -514,7 +514,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
 		return -ENOMEM;
 
 	fdb->is_local = fdb->is_static = 1;
-	fdb_add_hw(br, addr);
+	fdb_add_hw_addr(br, addr);
 	fdb_notify(br, fdb, RTM_NEWNEIGH);
 	return 0;
 }
@@ -754,19 +754,19 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
 			fdb->is_local = 1;
 			if (!fdb->is_static) {
 				fdb->is_static = 1;
-				fdb_add_hw(br, addr);
+				fdb_add_hw_addr(br, addr);
 			}
 		} else if (state & NUD_NOARP) {
 			fdb->is_local = 0;
 			if (!fdb->is_static) {
 				fdb->is_static = 1;
-				fdb_add_hw(br, addr);
+				fdb_add_hw_addr(br, addr);
 			}
 		} else {
 			fdb->is_local = 0;
 			if (fdb->is_static) {
 				fdb->is_static = 0;
-				fdb_del_hw(br, addr);
+				fdb_del_hw_addr(br, addr);
 			}
 		}
 
-- 
1.9.3

^ permalink raw reply related

* [patch net-next v3 02/17] net: make vid as a parameter for ndo_fdb_add/ndo_fdb_del
From: Jiri Pirko @ 2014-11-25 10:28 UTC (permalink / raw)
  To: netdev
  Cc: davem, nhorman, andy, tgraf, dborkman, ogerlitz, jesse, pshelar,
	azhou, ben, stephen, jeffrey.t.kirsher, vyasevic, xiyou.wangcong,
	john.r.fastabend, edumazet, jhs, sfeldma, f.fainelli, roopa,
	linville, jasowang, ebiederm, nicolas.dichtel, ryazanov.s.a,
	buytenh, aviadr, nbd, alexei.starovoitov, Neil.Jerram, ronye,
	simon.horman, alexander.h.duyck, john.ronciak, mleitner, shrijeet,
	gospo, bcrl
In-Reply-To: <1416911328-10979-1-git-send-email-jiri@resnulli.us>

Do the work of parsing NDA_VLAN directly in rtnetlink code, pass simple
u16 vid to drivers from there.

Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
new in v3
---
 drivers/net/ethernet/intel/i40e/i40e_main.c      |  2 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c    |  4 +-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c |  9 +++--
 drivers/net/macvlan.c                            |  4 +-
 drivers/net/vxlan.c                              |  4 +-
 include/linux/netdevice.h                        |  8 ++--
 include/linux/rtnetlink.h                        |  6 ++-
 net/bridge/br_fdb.c                              | 39 ++----------------
 net/bridge/br_private.h                          |  4 +-
 net/core/rtnetlink.c                             | 50 ++++++++++++++++++++----
 10 files changed, 70 insertions(+), 60 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 7262077..5ed5e40 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -7536,7 +7536,7 @@ static int i40e_get_phys_port_id(struct net_device *netdev,
  */
 static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 			    struct net_device *dev,
-			    const unsigned char *addr,
+			    const unsigned char *addr, u16 vid,
 			    u16 flags)
 {
 	struct i40e_netdev_priv *np = netdev_priv(dev);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 932f779..1bad9f4 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7708,7 +7708,7 @@ static int ixgbe_set_features(struct net_device *netdev,
 
 static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 			     struct net_device *dev,
-			     const unsigned char *addr,
+			     const unsigned char *addr, u16 vid,
 			     u16 flags)
 {
 	/* guarantee we can provide a unique filter for the unicast address */
@@ -7717,7 +7717,7 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 			return -ENOMEM;
 	}
 
-	return ndo_dflt_fdb_add(ndm, tb, dev, addr, flags);
+	return ndo_dflt_fdb_add(ndm, tb, dev, addr, vid, flags);
 }
 
 static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index a913b3a..3227c80 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -376,13 +376,14 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
 }
 
 static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
-			struct net_device *netdev, const unsigned char *addr)
+			struct net_device *netdev,
+			const unsigned char *addr, u16 vid)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 	int err = -EOPNOTSUPP;
 
 	if (!adapter->fdb_mac_learn)
-		return ndo_dflt_fdb_del(ndm, tb, netdev, addr);
+		return ndo_dflt_fdb_del(ndm, tb, netdev, addr, vid);
 
 	if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
 	    qlcnic_sriov_check(adapter)) {
@@ -401,13 +402,13 @@ static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
 
 static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 			struct net_device *netdev,
-			const unsigned char *addr, u16 flags)
+			const unsigned char *addr, u16 vid, u16 flags)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 	int err = 0;
 
 	if (!adapter->fdb_mac_learn)
-		return ndo_dflt_fdb_add(ndm, tb, netdev, addr, flags);
+		return ndo_dflt_fdb_add(ndm, tb, netdev, addr, vid, flags);
 
 	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) &&
 	    !qlcnic_sriov_check(adapter)) {
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index bfb0b6e..a1a3e3e 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -872,7 +872,7 @@ static int macvlan_vlan_rx_kill_vid(struct net_device *dev,
 
 static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 			   struct net_device *dev,
-			   const unsigned char *addr,
+			   const unsigned char *addr, u16 vid,
 			   u16 flags)
 {
 	struct macvlan_dev *vlan = netdev_priv(dev);
@@ -897,7 +897,7 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 
 static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
 			   struct net_device *dev,
-			   const unsigned char *addr)
+			   const unsigned char *addr, u16 vid)
 {
 	struct macvlan_dev *vlan = netdev_priv(dev);
 	int err = -EINVAL;
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index e9f81d4..7d8013d 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -849,7 +849,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan,
 /* Add static entry (via netlink) */
 static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 			 struct net_device *dev,
-			 const unsigned char *addr, u16 flags)
+			 const unsigned char *addr, u16 vid, u16 flags)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	/* struct net *net = dev_net(vxlan->dev); */
@@ -885,7 +885,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 /* Delete entry (via netlink) */
 static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
 			    struct net_device *dev,
-			    const unsigned char *addr)
+			    const unsigned char *addr, u16 vid)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	struct vxlan_fdb *f;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 5cd5087..fab074e 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -951,11 +951,11 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
  *
  * int (*ndo_fdb_add)(struct ndmsg *ndm, struct nlattr *tb[],
  *		      struct net_device *dev,
- *		      const unsigned char *addr, u16 flags)
+ *		      const unsigned char *addr, u16 vid, u16 flags)
  *	Adds an FDB entry to dev for addr.
  * int (*ndo_fdb_del)(struct ndmsg *ndm, struct nlattr *tb[],
  *		      struct net_device *dev,
- *		      const unsigned char *addr)
+ *		      const unsigned char *addr, u16 vid)
  *	Deletes the FDB entry from dev coresponding to addr.
  * int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb,
  *		       struct net_device *dev, struct net_device *filter_dev,
@@ -1128,11 +1128,13 @@ struct net_device_ops {
 					       struct nlattr *tb[],
 					       struct net_device *dev,
 					       const unsigned char *addr,
+					       u16 vid,
 					       u16 flags);
 	int			(*ndo_fdb_del)(struct ndmsg *ndm,
 					       struct nlattr *tb[],
 					       struct net_device *dev,
-					       const unsigned char *addr);
+					       const unsigned char *addr,
+					       u16 vid);
 	int			(*ndo_fdb_dump)(struct sk_buff *skb,
 						struct netlink_callback *cb,
 						struct net_device *dev,
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 6cacbce..063f0f5 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -94,11 +94,13 @@ extern int ndo_dflt_fdb_add(struct ndmsg *ndm,
 			    struct nlattr *tb[],
 			    struct net_device *dev,
 			    const unsigned char *addr,
-			     u16 flags);
+			    u16 vid,
+			    u16 flags);
 extern int ndo_dflt_fdb_del(struct ndmsg *ndm,
 			    struct nlattr *tb[],
 			    struct net_device *dev,
-			    const unsigned char *addr);
+			    const unsigned char *addr,
+			    u16 vid);
 
 extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
 				   struct net_device *dev, u16 mode);
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 08ef4e7..b1be971 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -805,33 +805,17 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge_port *p,
 /* Add new permanent fdb entry with RTM_NEWNEIGH */
 int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 	       struct net_device *dev,
-	       const unsigned char *addr, u16 nlh_flags)
+	       const unsigned char *addr, u16 vid, u16 nlh_flags)
 {
 	struct net_bridge_port *p;
 	int err = 0;
 	struct net_port_vlans *pv;
-	unsigned short vid = VLAN_N_VID;
 
 	if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) {
 		pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state);
 		return -EINVAL;
 	}
 
-	if (tb[NDA_VLAN]) {
-		if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) {
-			pr_info("bridge: RTM_NEWNEIGH with invalid vlan\n");
-			return -EINVAL;
-		}
-
-		vid = nla_get_u16(tb[NDA_VLAN]);
-
-		if (!vid || vid >= VLAN_VID_MASK) {
-			pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n",
-				vid);
-			return -EINVAL;
-		}
-	}
-
 	if (is_zero_ether_addr(addr)) {
 		pr_info("bridge: RTM_NEWNEIGH with invalid ether address\n");
 		return -EINVAL;
@@ -845,7 +829,7 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 	}
 
 	pv = nbp_get_vlan_info(p);
-	if (vid != VLAN_N_VID) {
+	if (vid) {
 		if (!pv || !test_bit(vid, pv->vlan_bitmap)) {
 			pr_info("bridge: RTM_NEWNEIGH with unconfigured "
 				"vlan %d on port %s\n", vid, dev->name);
@@ -903,27 +887,12 @@ static int __br_fdb_delete(struct net_bridge_port *p,
 /* Remove neighbor entry with RTM_DELNEIGH */
 int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
 		  struct net_device *dev,
-		  const unsigned char *addr)
+		  const unsigned char *addr, u16 vid)
 {
 	struct net_bridge_port *p;
 	int err;
 	struct net_port_vlans *pv;
-	unsigned short vid = VLAN_N_VID;
-
-	if (tb[NDA_VLAN]) {
-		if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) {
-			pr_info("bridge: RTM_NEWNEIGH with invalid vlan\n");
-			return -EINVAL;
-		}
 
-		vid = nla_get_u16(tb[NDA_VLAN]);
-
-		if (!vid || vid >= VLAN_VID_MASK) {
-			pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n",
-				vid);
-			return -EINVAL;
-		}
-	}
 	p = br_port_get_rtnl(dev);
 	if (p == NULL) {
 		pr_info("bridge: RTM_DELNEIGH %s not a bridge port\n",
@@ -932,7 +901,7 @@ int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
 	}
 
 	pv = nbp_get_vlan_info(p);
-	if (vid != VLAN_N_VID) {
+	if (vid) {
 		if (!pv || !test_bit(vid, pv->vlan_bitmap)) {
 			pr_info("bridge: RTM_DELNEIGH with unconfigured "
 				"vlan %d on port %s\n", vid, dev->name);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 8f3f081..4f577c4 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -404,9 +404,9 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
 		   const unsigned char *addr, u16 vid, bool added_by_user);
 
 int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
-		  struct net_device *dev, const unsigned char *addr);
+		  struct net_device *dev, const unsigned char *addr, u16 vid);
 int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev,
-	       const unsigned char *addr, u16 nlh_flags);
+	       const unsigned char *addr, u16 vid, u16 nlh_flags);
 int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
 		struct net_device *dev, struct net_device *fdev, int idx);
 int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index a688268..f2a4b38 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -36,6 +36,7 @@
 #include <linux/mutex.h>
 #include <linux/if_addr.h>
 #include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
 #include <linux/pci.h>
 #include <linux/etherdevice.h>
 
@@ -2312,7 +2313,7 @@ errout:
 int ndo_dflt_fdb_add(struct ndmsg *ndm,
 		     struct nlattr *tb[],
 		     struct net_device *dev,
-		     const unsigned char *addr,
+		     const unsigned char *addr, u16 vid,
 		     u16 flags)
 {
 	int err = -EINVAL;
@@ -2338,6 +2339,28 @@ int ndo_dflt_fdb_add(struct ndmsg *ndm,
 }
 EXPORT_SYMBOL(ndo_dflt_fdb_add);
 
+static int fbd_vid_parse(struct nlattr *vlan_attr, u16 *p_vid)
+{
+	u16 vid = 0;
+
+	if (vlan_attr) {
+		if (nla_len(vlan_attr) != sizeof(u16)) {
+			pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid vlan\n");
+			return -EINVAL;
+		}
+
+		vid = nla_get_u16(vlan_attr);
+
+		if (!vid || vid >= VLAN_VID_MASK) {
+			pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid vlan id %d\n",
+				vid);
+			return -EINVAL;
+		}
+	}
+	*p_vid = vid;
+	return 0;
+}
+
 static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
 	struct net *net = sock_net(skb->sk);
@@ -2345,6 +2368,7 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
 	struct nlattr *tb[NDA_MAX+1];
 	struct net_device *dev;
 	u8 *addr;
+	u16 vid;
 	int err;
 
 	err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
@@ -2370,6 +2394,10 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
 
 	addr = nla_data(tb[NDA_LLADDR]);
 
+	err = fbd_vid_parse(tb[NDA_VLAN], &vid);
+	if (err)
+		return err;
+
 	err = -EOPNOTSUPP;
 
 	/* Support fdb on master device the net/bridge default case */
@@ -2378,7 +2406,8 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
 		struct net_device *br_dev = netdev_master_upper_dev_get(dev);
 		const struct net_device_ops *ops = br_dev->netdev_ops;
 
-		err = ops->ndo_fdb_add(ndm, tb, dev, addr, nlh->nlmsg_flags);
+		err = ops->ndo_fdb_add(ndm, tb, dev, addr, vid,
+				       nlh->nlmsg_flags);
 		if (err)
 			goto out;
 		else
@@ -2389,9 +2418,10 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
 	if ((ndm->ndm_flags & NTF_SELF)) {
 		if (dev->netdev_ops->ndo_fdb_add)
 			err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr,
+							   vid,
 							   nlh->nlmsg_flags);
 		else
-			err = ndo_dflt_fdb_add(ndm, tb, dev, addr,
+			err = ndo_dflt_fdb_add(ndm, tb, dev, addr, vid,
 					       nlh->nlmsg_flags);
 
 		if (!err) {
@@ -2409,7 +2439,7 @@ out:
 int ndo_dflt_fdb_del(struct ndmsg *ndm,
 		     struct nlattr *tb[],
 		     struct net_device *dev,
-		     const unsigned char *addr)
+		     const unsigned char *addr, u16 vid)
 {
 	int err = -EINVAL;
 
@@ -2438,6 +2468,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
 	struct net_device *dev;
 	int err = -EINVAL;
 	__u8 *addr;
+	u16 vid;
 
 	if (!netlink_capable(skb, CAP_NET_ADMIN))
 		return -EPERM;
@@ -2465,6 +2496,10 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
 
 	addr = nla_data(tb[NDA_LLADDR]);
 
+	err = fbd_vid_parse(tb[NDA_VLAN], &vid);
+	if (err)
+		return err;
+
 	err = -EOPNOTSUPP;
 
 	/* Support fdb on master device the net/bridge default case */
@@ -2474,7 +2509,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
 		const struct net_device_ops *ops = br_dev->netdev_ops;
 
 		if (ops->ndo_fdb_del)
-			err = ops->ndo_fdb_del(ndm, tb, dev, addr);
+			err = ops->ndo_fdb_del(ndm, tb, dev, addr, vid);
 
 		if (err)
 			goto out;
@@ -2485,9 +2520,10 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
 	/* Embedded bridge, macvlan, and any other device support */
 	if (ndm->ndm_flags & NTF_SELF) {
 		if (dev->netdev_ops->ndo_fdb_del)
-			err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr);
+			err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr,
+							   vid);
 		else
-			err = ndo_dflt_fdb_del(ndm, tb, dev, addr);
+			err = ndo_dflt_fdb_del(ndm, tb, dev, addr, vid);
 
 		if (!err) {
 			rtnl_fdb_notify(dev, addr, RTM_DELNEIGH);
-- 
1.9.3

^ permalink raw reply related


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