Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH v3 bpf-next 03/10] bpf: introduce per-cpu cgroup local storage
From: Song Liu @ 2018-09-26 16:13 UTC (permalink / raw)
  To: Roman Gushchin
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Kernel Team,
	Daniel Borkmann, Alexei Starovoitov
In-Reply-To: <20180926113326.29069-4-guro@fb.com>



> On Sep 26, 2018, at 4:33 AM, Roman Gushchin <guro@fb.com> wrote:
> 
> This commit introduced per-cpu cgroup local storage.
> 
> Per-cpu cgroup local storage is very similar to simple cgroup storage
> (let's call it shared), except all the data is per-cpu.
> 
> The main goal of per-cpu variant is to implement super fast
> counters (e.g. packet counters), which don't require neither
> lookups, neither atomic operations.
> 
> From userspace's point of view, accessing a per-cpu cgroup storage
> is similar to other per-cpu map types (e.g. per-cpu hashmaps and
> arrays).
> 
> Writing to a per-cpu cgroup storage is not atomic, but is performed
> by copying longs, so some minimal atomicity is here, exactly
> as with other per-cpu maps.
> 
> Signed-off-by: Roman Gushchin <guro@fb.com>
> Cc: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Alexei Starovoitov <ast@kernel.org>

Acked-by: Song Liu <songliubraving@fb.com>

> ---
> include/linux/bpf-cgroup.h |  20 ++++-
> include/linux/bpf.h        |   1 +
> include/linux/bpf_types.h  |   1 +
> include/uapi/linux/bpf.h   |   1 +
> kernel/bpf/helpers.c       |   8 +-
> kernel/bpf/local_storage.c | 148 ++++++++++++++++++++++++++++++++-----
> kernel/bpf/syscall.c       |  11 ++-
> kernel/bpf/verifier.c      |  15 +++-
> 8 files changed, 177 insertions(+), 28 deletions(-)
> 
> diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h
> index 7e0c9a1d48b7..588dd5f0bd85 100644
> --- a/include/linux/bpf-cgroup.h
> +++ b/include/linux/bpf-cgroup.h
> @@ -37,7 +37,10 @@ struct bpf_storage_buffer {
> };
> 
> struct bpf_cgroup_storage {
> -	struct bpf_storage_buffer *buf;
> +	union {
> +		struct bpf_storage_buffer *buf;
> +		void __percpu *percpu_buf;
> +	};
> 	struct bpf_cgroup_storage_map *map;
> 	struct bpf_cgroup_storage_key key;
> 	struct list_head list;
> @@ -109,6 +112,9 @@ int __cgroup_bpf_check_dev_permission(short dev_type, u32 major, u32 minor,
> static inline enum bpf_cgroup_storage_type cgroup_storage_type(
> 	struct bpf_map *map)
> {
> +	if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE)
> +		return BPF_CGROUP_STORAGE_PERCPU;
> +
> 	return BPF_CGROUP_STORAGE_SHARED;
> }
> 
> @@ -131,6 +137,10 @@ void bpf_cgroup_storage_unlink(struct bpf_cgroup_storage *storage);
> int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *map);
> void bpf_cgroup_storage_release(struct bpf_prog *prog, struct bpf_map *map);
> 
> +int bpf_percpu_cgroup_storage_copy(struct bpf_map *map, void *key, void *value);
> +int bpf_percpu_cgroup_storage_update(struct bpf_map *map, void *key,
> +				     void *value, u64 flags);
> +
> /* Wrappers for __cgroup_bpf_run_filter_skb() guarded by cgroup_bpf_enabled. */
> #define BPF_CGROUP_RUN_PROG_INET_INGRESS(sk, skb)			      \
> ({									      \
> @@ -285,6 +295,14 @@ static inline struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(
> 	struct bpf_prog *prog, enum bpf_cgroup_storage_type stype) { return 0; }
> static inline void bpf_cgroup_storage_free(
> 	struct bpf_cgroup_storage *storage) {}
> +static inline int bpf_percpu_cgroup_storage_copy(struct bpf_map *map, void *key,
> +						 void *value) {
> +	return 0;
> +}
> +static inline int bpf_percpu_cgroup_storage_update(struct bpf_map *map,
> +					void *key, void *value, u64 flags) {
> +	return 0;
> +}
> 
> #define cgroup_bpf_enabled (0)
> #define BPF_CGROUP_PRE_CONNECT_ENABLED(sk) (0)
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index b457fbe7b70b..018299a595c8 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -274,6 +274,7 @@ struct bpf_prog_offload {
> 
> enum bpf_cgroup_storage_type {
> 	BPF_CGROUP_STORAGE_SHARED,
> +	BPF_CGROUP_STORAGE_PERCPU,
> 	__BPF_CGROUP_STORAGE_MAX
> };
> 
> diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h
> index c9bd6fb765b0..5432f4c9f50e 100644
> --- a/include/linux/bpf_types.h
> +++ b/include/linux/bpf_types.h
> @@ -43,6 +43,7 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_CGROUP_ARRAY, cgroup_array_map_ops)
> #endif
> #ifdef CONFIG_CGROUP_BPF
> BPF_MAP_TYPE(BPF_MAP_TYPE_CGROUP_STORAGE, cgroup_storage_map_ops)
> +BPF_MAP_TYPE(BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, cgroup_storage_map_ops)
> #endif
> BPF_MAP_TYPE(BPF_MAP_TYPE_HASH, htab_map_ops)
> BPF_MAP_TYPE(BPF_MAP_TYPE_PERCPU_HASH, htab_percpu_map_ops)
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index aa5ccd2385ed..e2070d819e04 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -127,6 +127,7 @@ enum bpf_map_type {
> 	BPF_MAP_TYPE_SOCKHASH,
> 	BPF_MAP_TYPE_CGROUP_STORAGE,
> 	BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
> +	BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
> };
> 
> enum bpf_prog_type {
> diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
> index e42f8789b7ea..6502115e8f55 100644
> --- a/kernel/bpf/helpers.c
> +++ b/kernel/bpf/helpers.c
> @@ -206,10 +206,16 @@ BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags)
> 	 */
> 	enum bpf_cgroup_storage_type stype = cgroup_storage_type(map);
> 	struct bpf_cgroup_storage *storage;
> +	void *ptr;
> 
> 	storage = this_cpu_read(bpf_cgroup_storage[stype]);
> 
> -	return (unsigned long)&READ_ONCE(storage->buf)->data[0];
> +	if (stype == BPF_CGROUP_STORAGE_SHARED)
> +		ptr = &READ_ONCE(storage->buf)->data[0];
> +	else
> +		ptr = this_cpu_ptr(storage->percpu_buf);
> +
> +	return (unsigned long)ptr;
> }
> 
> const struct bpf_func_proto bpf_get_local_storage_proto = {
> diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c
> index 6742292fb39e..c739f6dcc3c2 100644
> --- a/kernel/bpf/local_storage.c
> +++ b/kernel/bpf/local_storage.c
> @@ -152,6 +152,71 @@ static int cgroup_storage_update_elem(struct bpf_map *map, void *_key,
> 	return 0;
> }
> 
> +int bpf_percpu_cgroup_storage_copy(struct bpf_map *_map, void *_key,
> +				   void *value)
> +{
> +	struct bpf_cgroup_storage_map *map = map_to_storage(_map);
> +	struct bpf_cgroup_storage_key *key = _key;
> +	struct bpf_cgroup_storage *storage;
> +	int cpu, off = 0;
> +	u32 size;
> +
> +	rcu_read_lock();
> +	storage = cgroup_storage_lookup(map, key, false);
> +	if (!storage) {
> +		rcu_read_unlock();
> +		return -ENOENT;
> +	}
> +
> +	/* per_cpu areas are zero-filled and bpf programs can only
> +	 * access 'value_size' of them, so copying rounded areas
> +	 * will not leak any kernel data
> +	 */
> +	size = round_up(_map->value_size, 8);
> +	for_each_possible_cpu(cpu) {
> +		bpf_long_memcpy(value + off,
> +				per_cpu_ptr(storage->percpu_buf, cpu), size);
> +		off += size;
> +	}
> +	rcu_read_unlock();
> +	return 0;
> +}
> +
> +int bpf_percpu_cgroup_storage_update(struct bpf_map *_map, void *_key,
> +				     void *value, u64 map_flags)
> +{
> +	struct bpf_cgroup_storage_map *map = map_to_storage(_map);
> +	struct bpf_cgroup_storage_key *key = _key;
> +	struct bpf_cgroup_storage *storage;
> +	int cpu, off = 0;
> +	u32 size;
> +
> +	if (unlikely(map_flags & BPF_EXIST))
> +		return -EINVAL;
> +
> +	rcu_read_lock();
> +	storage = cgroup_storage_lookup(map, key, false);
> +	if (!storage) {
> +		rcu_read_unlock();
> +		return -ENOENT;
> +	}
> +
> +	/* the user space will provide round_up(value_size, 8) bytes that
> +	 * will be copied into per-cpu area. bpf programs can only access
> +	 * value_size of it. During lookup the same extra bytes will be
> +	 * returned or zeros which were zero-filled by percpu_alloc,
> +	 * so no kernel data leaks possible
> +	 */
> +	size = round_up(_map->value_size, 8);
> +	for_each_possible_cpu(cpu) {
> +		bpf_long_memcpy(per_cpu_ptr(storage->percpu_buf, cpu),
> +				value + off, size);
> +		off += size;
> +	}
> +	rcu_read_unlock();
> +	return 0;
> +}
> +
> static int cgroup_storage_get_next_key(struct bpf_map *_map, void *_key,
> 				       void *_next_key)
> {
> @@ -292,55 +357,98 @@ struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog,
> {
> 	struct bpf_cgroup_storage *storage;
> 	struct bpf_map *map;
> +	gfp_t flags;
> +	size_t size;
> 	u32 pages;
> 
> 	map = prog->aux->cgroup_storage[stype];
> 	if (!map)
> 		return NULL;
> 
> -	pages = round_up(sizeof(struct bpf_cgroup_storage) +
> -			 sizeof(struct bpf_storage_buffer) +
> -			 map->value_size, PAGE_SIZE) >> PAGE_SHIFT;
> +	if (stype == BPF_CGROUP_STORAGE_SHARED) {
> +		size = sizeof(struct bpf_storage_buffer) + map->value_size;
> +		pages = round_up(sizeof(struct bpf_cgroup_storage) + size,
> +				 PAGE_SIZE) >> PAGE_SHIFT;
> +	} else {
> +		size = map->value_size;
> +		pages = round_up(round_up(size, 8) * num_possible_cpus(),
> +				 PAGE_SIZE) >> PAGE_SHIFT;
> +	}
> +
> 	if (bpf_map_charge_memlock(map, pages))
> 		return ERR_PTR(-EPERM);
> 
> 	storage = kmalloc_node(sizeof(struct bpf_cgroup_storage),
> 			       __GFP_ZERO | GFP_USER, map->numa_node);
> -	if (!storage) {
> -		bpf_map_uncharge_memlock(map, pages);
> -		return ERR_PTR(-ENOMEM);
> -	}
> +	if (!storage)
> +		goto enomem;
> 
> -	storage->buf = kmalloc_node(sizeof(struct bpf_storage_buffer) +
> -				    map->value_size, __GFP_ZERO | GFP_USER,
> -				    map->numa_node);
> -	if (!storage->buf) {
> -		bpf_map_uncharge_memlock(map, pages);
> -		kfree(storage);
> -		return ERR_PTR(-ENOMEM);
> +	flags = __GFP_ZERO | GFP_USER;
> +
> +	if (stype == BPF_CGROUP_STORAGE_SHARED) {
> +		storage->buf = kmalloc_node(size, flags, map->numa_node);
> +		if (!storage->buf)
> +			goto enomem;
> +	} else {
> +		storage->percpu_buf = __alloc_percpu_gfp(size, 8, flags);
> +		if (!storage->percpu_buf)
> +			goto enomem;
> 	}
> 
> 	storage->map = (struct bpf_cgroup_storage_map *)map;
> 
> 	return storage;
> +
> +enomem:
> +	bpf_map_uncharge_memlock(map, pages);
> +	kfree(storage);
> +	return ERR_PTR(-ENOMEM);
> +}
> +
> +static void free_shared_cgroup_storage_rcu(struct rcu_head *rcu)
> +{
> +	struct bpf_cgroup_storage *storage =
> +		container_of(rcu, struct bpf_cgroup_storage, rcu);
> +
> +	kfree(storage->buf);
> +	kfree(storage);
> +}
> +
> +static void free_percpu_cgroup_storage_rcu(struct rcu_head *rcu)
> +{
> +	struct bpf_cgroup_storage *storage =
> +		container_of(rcu, struct bpf_cgroup_storage, rcu);
> +
> +	free_percpu(storage->percpu_buf);
> +	kfree(storage);
> }
> 
> void bpf_cgroup_storage_free(struct bpf_cgroup_storage *storage)
> {
> -	u32 pages;
> +	enum bpf_cgroup_storage_type stype;
> 	struct bpf_map *map;
> +	u32 pages;
> 
> 	if (!storage)
> 		return;
> 
> 	map = &storage->map->map;
> -	pages = round_up(sizeof(struct bpf_cgroup_storage) +
> -			 sizeof(struct bpf_storage_buffer) +
> -			 map->value_size, PAGE_SIZE) >> PAGE_SHIFT;
> +	stype = cgroup_storage_type(map);
> +	if (stype == BPF_CGROUP_STORAGE_SHARED)
> +		pages = round_up(sizeof(struct bpf_cgroup_storage) +
> +				 sizeof(struct bpf_storage_buffer) +
> +				 map->value_size, PAGE_SIZE) >> PAGE_SHIFT;
> +	else
> +		pages = round_up(round_up(map->value_size, 8) *
> +				 num_possible_cpus(),
> +				 PAGE_SIZE) >> PAGE_SHIFT;
> +
> 	bpf_map_uncharge_memlock(map, pages);
> 
> -	kfree_rcu(storage->buf, rcu);
> -	kfree_rcu(storage, rcu);
> +	if (stype == BPF_CGROUP_STORAGE_SHARED)
> +		call_rcu(&storage->rcu, free_shared_cgroup_storage_rcu);
> +	else
> +		call_rcu(&storage->rcu, free_percpu_cgroup_storage_rcu);
> }
> 
> void bpf_cgroup_storage_link(struct bpf_cgroup_storage *storage,
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 8c91d2b41b1e..5742df21598c 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -686,7 +686,8 @@ static int map_lookup_elem(union bpf_attr *attr)
> 
> 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
> 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
> -	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
> +	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY ||
> +	    map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE)
> 		value_size = round_up(map->value_size, 8) * num_possible_cpus();
> 	else if (IS_FD_MAP(map))
> 		value_size = sizeof(u32);
> @@ -705,6 +706,8 @@ static int map_lookup_elem(union bpf_attr *attr)
> 		err = bpf_percpu_hash_copy(map, key, value);
> 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
> 		err = bpf_percpu_array_copy(map, key, value);
> +	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
> +		err = bpf_percpu_cgroup_storage_copy(map, key, value);
> 	} else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) {
> 		err = bpf_stackmap_copy(map, key, value);
> 	} else if (IS_FD_ARRAY(map)) {
> @@ -774,7 +777,8 @@ static int map_update_elem(union bpf_attr *attr)
> 
> 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
> 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
> -	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
> +	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY ||
> +	    map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE)
> 		value_size = round_up(map->value_size, 8) * num_possible_cpus();
> 	else
> 		value_size = map->value_size;
> @@ -809,6 +813,9 @@ static int map_update_elem(union bpf_attr *attr)
> 		err = bpf_percpu_hash_update(map, key, value, attr->flags);
> 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
> 		err = bpf_percpu_array_update(map, key, value, attr->flags);
> +	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
> +		err = bpf_percpu_cgroup_storage_update(map, key, value,
> +						       attr->flags);
> 	} else if (IS_FD_ARRAY(map)) {
> 		rcu_read_lock();
> 		err = bpf_fd_array_map_update_elem(map, f.file, key, value,
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index e90899df585d..a8cc83a970d1 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -2074,6 +2074,7 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env,
> 			goto error;
> 		break;
> 	case BPF_MAP_TYPE_CGROUP_STORAGE:
> +	case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE:
> 		if (func_id != BPF_FUNC_get_local_storage)
> 			goto error;
> 		break;
> @@ -2164,7 +2165,8 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env,
> 			goto error;
> 		break;
> 	case BPF_FUNC_get_local_storage:
> -		if (map->map_type != BPF_MAP_TYPE_CGROUP_STORAGE)
> +		if (map->map_type != BPF_MAP_TYPE_CGROUP_STORAGE &&
> +		    map->map_type != BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE)
> 			goto error;
> 		break;
> 	case BPF_FUNC_sk_select_reuseport:
> @@ -5049,6 +5051,12 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env,
> 	return 0;
> }
> 
> +static bool bpf_map_is_cgroup_storage(struct bpf_map *map)
> +{
> +	return (map->map_type == BPF_MAP_TYPE_CGROUP_STORAGE ||
> +		map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE);
> +}
> +
> /* look for pseudo eBPF instructions that access map FDs and
>  * replace them with actual map pointers
>  */
> @@ -5139,10 +5147,9 @@ static int replace_map_fd_with_map_ptr(struct bpf_verifier_env *env)
> 			}
> 			env->used_maps[env->used_map_cnt++] = map;
> 
> -			if (map->map_type == BPF_MAP_TYPE_CGROUP_STORAGE &&
> +			if (bpf_map_is_cgroup_storage(map) &&
> 			    bpf_cgroup_storage_assign(env->prog, map)) {
> -				verbose(env,
> -					"only one cgroup storage is allowed\n");
> +				verbose(env, "only one cgroup storage of each type is allowed\n");
> 				fdput(f);
> 				return -EBUSY;
> 			}
> -- 
> 2.17.1
> 

^ permalink raw reply

* Re: pull-request: bpf-next 2018-09-25
From: Daniel Borkmann @ 2018-09-26 10:03 UTC (permalink / raw)
  To: David Miller; +Cc: ast, netdev
In-Reply-To: <20180925.204049.402375716601309433.davem@davemloft.net>

On 09/26/2018 05:40 AM, David Miller wrote:
> From: Daniel Borkmann <daniel@iogearbox.net>
> Date: Tue, 25 Sep 2018 22:43:43 +0200
> 
>> The following pull-request contains BPF updates for your *net-next*
>> tree.
> 
> Pulled, there was a minor merge conflict.  Please double check my work.

The resolution in tools/lib/bpf/Build looks good to me, thanks!

^ permalink raw reply

* KASAN: use-after-free Read in rtnl_fill_ifinfo
From: syzbot @ 2018-09-26 16:16 UTC (permalink / raw)
  To: christian, davem, dsahern, fw, jakub.kicinski, jbenc, ktkhai,
	linux-kernel, lucien.xin, netdev, syzkaller-bugs

Hello,

syzbot found the following crash on:

HEAD commit:    4b1bd6976945 net: phy: marvell: Fix build.
git tree:       net-next
console output: https://syzkaller.appspot.com/x/log.txt?x=1477df9e400000
kernel config:  https://syzkaller.appspot.com/x/.config?x=443816db871edd66
dashboard link: https://syzkaller.appspot.com/bug?extid=1e0c7db78acf0d004daf
compiler:       gcc (GCC) 8.0.1 20180413 (experimental)

Unfortunately, I don't have any reproducer for this crash yet.

IMPORTANT: if you fix the bug, please add the following tag to the commit:
Reported-by: syzbot+1e0c7db78acf0d004daf@syzkaller.appspotmail.com

llcp: llcp_sock_recvmsg: Recv datagram failed state 5 -107 0
==================================================================
BUG: KASAN: use-after-free in rtnl_fill_ifinfo+0x420e/0x4670  
net/core/rtnetlink.c:1630
Read of size 8 at addr ffff8801c2e7a4d8 by task syz-executor2/9379

CPU: 1 PID: 9379 Comm: syz-executor2 Not tainted 4.19.0-rc5+ #232
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS  
Google 01/01/2011
Call Trace:
  __dump_stack lib/dump_stack.c:77 [inline]
  dump_stack+0x1c4/0x2b4 lib/dump_stack.c:113
  print_address_description.cold.8+0x9/0x1ff mm/kasan/report.c:256
  kasan_report_error mm/kasan/report.c:354 [inline]
  kasan_report.cold.9+0x242/0x309 mm/kasan/report.c:412
  __asan_report_load8_noabort+0x14/0x20 mm/kasan/report.c:433
  rtnl_fill_ifinfo+0x420e/0x4670 net/core/rtnetlink.c:1630
  rtnl_dump_ifinfo+0x90a/0x1130 net/core/rtnetlink.c:1943
  netlink_dump+0x519/0xd50 net/netlink/af_netlink.c:2226
  netlink_recvmsg+0xf6f/0x1480 net/netlink/af_netlink.c:1984
  sock_recvmsg_nosec+0x8c/0xb0 net/socket.c:794
  ___sys_recvmsg+0x2b6/0x680 net/socket.c:2278
  __sys_recvmmsg+0x303/0xb90 net/socket.c:2390
  do_sys_recvmmsg+0xec/0x1a0 net/socket.c:2471
  __do_sys_recvmmsg net/socket.c:2484 [inline]
  __se_sys_recvmmsg net/socket.c:2480 [inline]
  __x64_sys_recvmmsg+0xbe/0x150 net/socket.c:2480
  do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290
  entry_SYSCALL_64_after_hwframe+0x49/0xbe
RIP: 0033:0x457579
Code: 1d b4 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7  
48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff  
ff 0f 83 eb b3 fb ff c3 66 2e 0f 1f 84 00 00 00 00
RSP: 002b:00007f3e5c58cc78 EFLAGS: 00000246
  ORIG_RAX: 000000000000012b
RAX: ffffffffffffffda RBX: 0000000000000005 RCX: 0000000000457579
RDX: 04000000000000f6 RSI: 00000000200037c0 RDI: 0000000000000003
RBP: 000000000072bfa0 R08: 0000000020003700 R09: 0000000000000000
R10: 0000000000000006 R11: 0000000000000246 R12: 00007f3e5c58d6d4
R13: 00000000004c3258 R14: 00000000004d4de8 R15: 00000000ffffffff

Allocated by task 5629:
  save_stack+0x43/0xd0 mm/kasan/kasan.c:448
  set_track mm/kasan/kasan.c:460 [inline]
  kasan_kmalloc+0xc7/0xe0 mm/kasan/kasan.c:553
  __do_kmalloc_node mm/slab.c:3682 [inline]
  __kmalloc_node+0x47/0x70 mm/slab.c:3689
  kmalloc_node include/linux/slab.h:555 [inline]
  kzalloc_node include/linux/slab.h:718 [inline]
  qdisc_alloc+0x10f/0xb50 net/sched/sch_generic.c:820
  qdisc_create_dflt+0x7a/0x1e0 net/sched/sch_generic.c:894
  attach_one_default_qdisc net/sched/sch_generic.c:1041 [inline]
  netdev_for_each_tx_queue include/linux/netdevice.h:2114 [inline]
  attach_default_qdiscs net/sched/sch_generic.c:1060 [inline]
  dev_activate+0x82f/0xcb0 net/sched/sch_generic.c:1103
  __dev_open+0x2cb/0x410 net/core/dev.c:1400
  dev_open+0xf2/0x1b0 net/core/dev.c:1426
  bond_enslave+0xfca/0x5f90 drivers/net/bonding/bond_main.c:1531
  do_set_master+0x1c9/0x220 net/core/rtnetlink.c:2313
  do_setlink+0xbe6/0x3f20 net/core/rtnetlink.c:2447
  rtnl_newlink+0x136f/0x1d40 net/core/rtnetlink.c:3054
  rtnetlink_rcv_msg+0x46a/0xc20 net/core/rtnetlink.c:4730
  netlink_rcv_skb+0x172/0x440 net/netlink/af_netlink.c:2447
  rtnetlink_rcv+0x1c/0x20 net/core/rtnetlink.c:4748
  netlink_unicast_kernel net/netlink/af_netlink.c:1310 [inline]
  netlink_unicast+0x5a5/0x760 net/netlink/af_netlink.c:1336
  netlink_sendmsg+0xa18/0xfc0 net/netlink/af_netlink.c:1901
  sock_sendmsg_nosec net/socket.c:621 [inline]
  sock_sendmsg+0xd5/0x120 net/socket.c:631
  ___sys_sendmsg+0x7fd/0x930 net/socket.c:2116
  __sys_sendmsg+0x11d/0x280 net/socket.c:2154
  __do_sys_sendmsg net/socket.c:2163 [inline]
  __se_sys_sendmsg net/socket.c:2161 [inline]
  __x64_sys_sendmsg+0x78/0xb0 net/socket.c:2161
  do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290
  entry_SYSCALL_64_after_hwframe+0x49/0xbe

Freed by task 5520:
  save_stack+0x43/0xd0 mm/kasan/kasan.c:448
  set_track mm/kasan/kasan.c:460 [inline]
  __kasan_slab_free+0x102/0x150 mm/kasan/kasan.c:521
  kasan_slab_free+0xe/0x10 mm/kasan/kasan.c:528
  __cache_free mm/slab.c:3498 [inline]
  kfree+0xcf/0x230 mm/slab.c:3813
  qdisc_free+0x89/0x100 net/sched/sch_generic.c:941
  qdisc_free_cb+0x19/0x20 net/sched/sch_generic.c:948
  __rcu_reclaim kernel/rcu/rcu.h:236 [inline]
  rcu_do_batch kernel/rcu/tree.c:2576 [inline]
  invoke_rcu_callbacks kernel/rcu/tree.c:2880 [inline]
  __rcu_process_callbacks kernel/rcu/tree.c:2847 [inline]
  rcu_process_callbacks+0xf23/0x2670 kernel/rcu/tree.c:2864
  __do_softirq+0x30b/0xad8 kernel/softirq.c:292

The buggy address belongs to the object at ffff8801c2e7a4c0
  which belongs to the cache kmalloc-1024 of size 1024
The buggy address is located 24 bytes inside of
  1024-byte region [ffff8801c2e7a4c0, ffff8801c2e7a8c0)
The buggy address belongs to the page:
page:ffffea00070b9e80 count:1 mapcount:0 mapping:ffff8801da800ac0 index:0x0  
compound_mapcount: 0
flags: 0x2fffc0000008100(slab|head)
raw: 02fffc0000008100 ffffea0007081708 ffffea00071f2688 ffff8801da800ac0
raw: 0000000000000000 ffff8801c2e7a040 0000000100000007 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
  ffff8801c2e7a380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
  ffff8801c2e7a400: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
> ffff8801c2e7a480: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
                                                     ^
  ffff8801c2e7a500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
  ffff8801c2e7a580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================


---
This bug is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this bug report. See:
https://goo.gl/tpsmEJ#bug-status-tracking for how to communicate with  
syzbot.

^ permalink raw reply

* Re: [PATCH bpf-next] bpftool: Fix bpftool net output
From: Daniel Borkmann @ 2018-09-26 10:19 UTC (permalink / raw)
  To: Andrey Ignatov, netdev; +Cc: ast, yhs
In-Reply-To: <20180925222037.1858472-1-rdna@fb.com>

On 09/26/2018 12:20 AM, Andrey Ignatov wrote:
> Print `bpftool net` output to stdout instead of stderr. Only errors
> should be printed to stderr. Regular output should go to stdout and this
> is what all other subcommands of bpftool do, including --json and
> --pretty formats of `bpftool net` itself.
> 
> Fixes: commit f6f3bac08ff9 ("tools/bpf: bpftool: add net support")
> Signed-off-by: Andrey Ignatov <rdna@fb.com>
> Acked-by: Yonghong Song <yhs@fb.com>

Applied to bpf-next, thanks Andrey!

^ permalink raw reply

* [PATCH] hv_netvsc: Make sure out channel is fully opened on send
From: Mohammed Gamal @ 2018-09-26 16:34 UTC (permalink / raw)
  To: sthemmin, netdev
  Cc: kys, haiyangz, vkuznets, otubo, cavery, linux-kernel, devel,
	Mohammed Gamal

Dring high network traffic changes to network interface parameters
such as number of channels or MTU can cause a kernel panic with a NULL
pointer dereference. This is due to netvsc_device_remove() being
called and deallocating the channel ring buffers, which can then be
accessed by netvsc_send_pkt() before they're allocated on calling
netvsc_device_add()

The patch fixes this problem by checking the channel state and returning
ENODEV if not yet opened. We also move the call to hv_ringbuf_avail_percent()
which may access the uninitialized ring buffer.

Signed-off-by: Mohammed Gamal <mgamal@redhat.com>
---
 drivers/net/hyperv/netvsc.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index fe01e14..75f1b31 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -825,7 +825,12 @@ static inline int netvsc_send_pkt(
 	struct netdev_queue *txq = netdev_get_tx_queue(ndev, packet->q_idx);
 	u64 req_id;
 	int ret;
-	u32 ring_avail = hv_get_avail_to_write_percent(&out_channel->outbound);
+	u32 ring_avail;
+
+	if (out_channel->state != CHANNEL_OPENED_STATE)
+		return -ENODEV;
+
+	ring_avail = hv_get_avail_to_write_percent(&out_channel->outbound);
 
 	nvmsg.hdr.msg_type = NVSP_MSG1_TYPE_SEND_RNDIS_PKT;
 	if (skb)
-- 
1.8.3.1

^ permalink raw reply related

* Re: kernel 4.18.5 Realtek 8111G network adapter stops responding under high system load
From: David Arendt @ 2018-09-26 16:44 UTC (permalink / raw)
  To: Heiner Kallweit, Maciej S. Szmigiero, Gabriel C,
	Ortwin Glück
  Cc: linux-kernel, nic_swsd, netdev
In-Reply-To: <968f03ee-a271-242b-d90a-5c70ea72ce3b@gmail.com>

Hi,

Thanks.

I have just applied Heiner Kallweit's patch on top of kernel 4.18.10 and
the TxConfig register contains 0x4f000f80.

I will give it 24 hours under high load and report back if the patch
really solves the problem.

Bye,
David Arendt

On 9/25/18 11:03 PM, Heiner Kallweit wrote:
> On 19.09.2018 06:12, David Arendt wrote:
>> Hi,
>>
>> Thanks for the patch.
>>
>> I just applied it and the TxConfig register now contains 0x4f000f80.
>> The next day will show if it really solves the problem.
>>
>> Thanks in advance,
>> David Arendt
>>
>> On 9/19/18 12:30 AM, Maciej S. Szmigiero wrote:
>>> Hi,
>>>
>>> On 18.09.2018 12:23, David Arendt wrote:
>>>> Hi,
>>>>
>>>> Today I had the network adapter problems again.
>>>> So the patch doesn't seem to change anything regarding this problem.
>>>> This week my time is unfortunately very limited, but I will try to
>>>> find some time next weekend to look a bit more into the issue.
>>> If the problem is caused by missing TXCFG_AUTO_FIFO bit in TxConfig,
>>> as the register difference would suggest, then you can try applying
>>> the following patch (hack) on top of 4.18.8 that is already patched
>>> with commit f74dd480cf4e:
>>> --- a/drivers/net/ethernet/realtek/r8169.c
>>> +++ b/drivers/net/ethernet/realtek/r8169.c
>>> @@ -5043,7 +5043,8 @@
>>>  {
>>>  	/* Set DMA burst size and Interframe Gap Time */
>>>  	RTL_W32(tp, TxConfig, (TX_DMA_BURST << TxDMAShift) |
>>> -		(InterFrameGap << TxInterFrameGapShift));
>>> +		(InterFrameGap << TxInterFrameGapShift)
>>> +		| TXCFG_AUTO_FIFO);
>>>  }
>>>  
>>>  static void rtl_set_rx_max_size(struct rtl8169_private *tp)
>>>
>>> This hack will probably only work properly on RTL_GIGA_MAC_VER_40 or
>>> later NICs.
>>>
>>> Before running any tests please verify with "ethtool -d enp3s0" that
>>> TxConfig register now contains 0x4f000f80, as it did in the old,
>>> working driver version.
>>>
>>> If this does not help then a bisection will most likely be needed.
>>>
>>>> Thanks in advance,
>>>> David Arendt
>>> Maciej
>>
>>
> @Gabriel:
> Thanks for the hint, I wasn't fully aware of this thread.
> @Maciej:
> Thanks for the analysis.
>
> It seems that all chip versions from 34 (= RTL8168E-VL) with the
> exception of version 39 (= RTL8106E, first sub-version) need
> bit TXCFG_AUTO_FIFO.
>
> And indeed, due to reordering of calls this bit is overwritten.
> Following patch moves setting the bit from the chip-specific
> hw_start function to rtl_set_tx_config_registers().
>
> Whoever is hit by the issue and has the option to build a kernel,
> could you please test whether the patch fixes the issue for you?
>
> Thanks, Heiner
>
> ---
>  drivers/net/ethernet/realtek/r8169.c | 20 ++++++++------------
>  1 file changed, 8 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
> index f882be49f..ae8abe900 100644
> --- a/drivers/net/ethernet/realtek/r8169.c
> +++ b/drivers/net/ethernet/realtek/r8169.c
> @@ -4514,9 +4514,14 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
>  
>  static void rtl_set_tx_config_registers(struct rtl8169_private *tp)
>  {
> -	/* Set DMA burst size and Interframe Gap Time */
> -	RTL_W32(tp, TxConfig, (TX_DMA_BURST << TxDMAShift) |
> -		(InterFrameGap << TxInterFrameGapShift));
> +	u32 val = TX_DMA_BURST << TxDMAShift |
> +		  InterFrameGap << TxInterFrameGapShift;
> +
> +	if (tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
> +	    tp->mac_version != RTL_GIGA_MAC_VER_39)
> +		val |= TXCFG_AUTO_FIFO;
> +
> +	RTL_W32(tp, TxConfig, val);
>  }
>  
>  static void rtl_set_rx_max_size(struct rtl8169_private *tp)
> @@ -5011,7 +5016,6 @@ static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
>  
>  	rtl_disable_clock_request(tp);
>  
> -	RTL_W32(tp, TxConfig, RTL_R32(tp, TxConfig) | TXCFG_AUTO_FIFO);
>  	RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB);
>  
>  	/* Adjust EEE LED frequency */
> @@ -5045,7 +5049,6 @@ static void rtl_hw_start_8168f(struct rtl8169_private *tp)
>  
>  	rtl_disable_clock_request(tp);
>  
> -	RTL_W32(tp, TxConfig, RTL_R32(tp, TxConfig) | TXCFG_AUTO_FIFO);
>  	RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB);
>  	RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) | PFM_EN);
>  	RTL_W32(tp, MISC, RTL_R32(tp, MISC) | PWM_EN);
> @@ -5090,8 +5093,6 @@ static void rtl_hw_start_8411(struct rtl8169_private *tp)
>  
>  static void rtl_hw_start_8168g(struct rtl8169_private *tp)
>  {
> -	RTL_W32(tp, TxConfig, RTL_R32(tp, TxConfig) | TXCFG_AUTO_FIFO);
> -
>  	rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x080002, ERIAR_EXGMAC);
>  	rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
>  	rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
> @@ -5189,8 +5190,6 @@ static void rtl_hw_start_8168h_1(struct rtl8169_private *tp)
>  	rtl_hw_aspm_clkreq_enable(tp, false);
>  	rtl_ephy_init(tp, e_info_8168h_1, ARRAY_SIZE(e_info_8168h_1));
>  
> -	RTL_W32(tp, TxConfig, RTL_R32(tp, TxConfig) | TXCFG_AUTO_FIFO);
> -
>  	rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x00080002, ERIAR_EXGMAC);
>  	rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
>  	rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
> @@ -5273,8 +5272,6 @@ static void rtl_hw_start_8168ep(struct rtl8169_private *tp)
>  {
>  	rtl8168ep_stop_cmac(tp);
>  
> -	RTL_W32(tp, TxConfig, RTL_R32(tp, TxConfig) | TXCFG_AUTO_FIFO);
> -
>  	rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x00080002, ERIAR_EXGMAC);
>  	rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x2f, ERIAR_EXGMAC);
>  	rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x5f, ERIAR_EXGMAC);
> @@ -5596,7 +5593,6 @@ static void rtl_hw_start_8402(struct rtl8169_private *tp)
>  	/* Force LAN exit from ASPM if Rx/Tx are not idle */
>  	RTL_W32(tp, FuncEvent, RTL_R32(tp, FuncEvent) | 0x002800);
>  
> -	RTL_W32(tp, TxConfig, RTL_R32(tp, TxConfig) | TXCFG_AUTO_FIFO);
>  	RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB);
>  
>  	rtl_ephy_init(tp, e_info_8402, ARRAY_SIZE(e_info_8402));

^ permalink raw reply

* [PATCH] 9p: potential NULL dereference
From: Dan Carpenter @ 2018-09-26 10:39 UTC (permalink / raw)
  To: Eric Van Hensbergen, Matthew Wilcox
  Cc: Latchesar Ionkov, Dominique Martinet, David S. Miller,
	v9fs-developer, netdev, kernel-janitors

p9_tag_alloc() is supposed to return error pointers, but we accidentally
return a NULL here.  It would cause a NULL dereference in the caller.

Fixes: 996d5b4db4b1 ("9p: Use a slab for allocating requests")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>

diff --git a/net/9p/client.c b/net/9p/client.c
index 47fa6158a75a..5f23e18eecc0 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -281,7 +281,7 @@ p9_tag_alloc(struct p9_client *c, int8_t type, unsigned int max_size)
 	int tag;
 
 	if (!req)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	if (p9_fcall_init(c, &req->tc, alloc_msize))
 		goto free_req;

^ permalink raw reply related

* Re: netlink: 16 bytes leftover after parsing attributes in process `ip'.
From: Christian Brauner @ 2018-09-26 10:45 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: David Ahern, netdev@vger.kernel.org, David Miller
In-Reply-To: <20180925141612.13084179@shemminger-XPS-13-9360>

On Tue, Sep 25, 2018 at 02:16:12PM +0100, Stephen Hemminger wrote:
> On Tue, 25 Sep 2018 14:34:08 +0200
> Christian Brauner <christian@brauner.io> wrote:
> 
> > On Tue, Sep 25, 2018, 14:07 Stephen Hemminger <stephen@networkplumber.org>
> > wrote:
> > 
> > > On Tue, 25 Sep 2018 11:49:10 +0200
> > > Christian Brauner <christian@brauner.io> wrote:
> > >  
> > > > On Mon, Sep 24, 2018 at 09:19:06PM -0600, David Ahern wrote:  
> > > > > On top of net-next I am see a dmesg error:
> > > > >
> > > > > netlink: 16 bytes leftover after parsing attributes in process `ip'.
> > > > >
> > > > > I traced it to address lists and commit:
> > > > >
> > > > > commit 6ecf4c37eb3e89b0832c9616089a5cdca3747da7
> > > > > Author: Christian Brauner <christian@brauner.io>
> > > > > Date:   Tue Sep 4 21:53:50 2018 +0200
> > > > >
> > > > >     ipv6: enable IFA_TARGET_NETNSID for RTM_GETADDR
> > > > >
> > > > > Per the commit you are trying to guess whether the ancillary header is
> > > > > an ifinfomsg or a ifaddrmsg. I am guessing you are guessing wrong.  
> > > :-)  
> > > >
> > > > Well, I currently don't guess at all. :) I'm parsing with struct
> > > > ifaddrmsg as assumed header size but ignore parsing errors when that
> > > > fails. You don't get the niceties of the new property if you don't pack  
> > >
> > > There are legacy parts of netlink interface with kernel.
> > > The ABI has evolved over time but some old parts are stuck in the past.
> > >
> > >  
> > > > > I don't have time to take this to ground, but address listing is not  
> > > the  
> > > > > only area subject to iproute2's SNAFU of infomsg everywhere on dumps. I
> > > > > have thought about this for route dumps, but its solution does not work
> > > > > here. You'll need to find something because the current warning on  
> > > every  
> > > > > address dump is not acceptable.  
> > > >
> > > > Two points before I propose a migitation:
> > > >
> > > > 1. The burded of seeing pr_warn_ratelimited() messages in dmesg when
> > > >    userspace is doing something wrong is imho justifiable.
> > > >    Actually, I would argue that we should not hide the problem from
> > > >    userspace at all. The rate-limited (so no logging DOS afaict) warning
> > > >    messages are a perfect indicator that a tool is doing something wrong
> > > >    *without* introducing any regressions.
> > > >    The rtnetlink manpage clearly indicates that ifaddrmsg is supposed to
> > > >    be used too. Additionally, userspace stuffs an ifinfomsg in there but
> > > >    expects to receive ifaddrmsg. They should be warned loudly. :) So I
> > > >    actually like the warning messages.
> > > > 2. Userspace should be fixed. Especially such an important standard tool
> > > >    as iproute2 that is maintained on git.kernel.org (glibc is already
> > > >    doing the right.).
> > > >
> > > > So if people really want to hide this issue as much as we can then we
> > > > can play the guessing game. I could send a patch that roughly does the
> > > > following:
> > > >
> > > > if (nlmsg_len(cb->nlh) < sizeof(struct ifinfomsg))
> > > >         guessed_header_len = sizeof(struct ifaddrmsg);
> > > > else
> > > >         guessed_header_len = sizeof(struct ifinfomsg);
> > > >
> > > > This will work since sizeof(ifaddrmsg) == 8 and sizeof(ifinfomsg) == 16.
> > > > The only valid property for RTM_GETADDR requests is IFA_TARGET_NETNSID.
> > > > This propert is a __s32 which should bring the message up to 12 bytes
> > > > (not sure about alignment requiremnts and where we might wend up ten)
> > > > which is still less than the 16 bytes without that property from
> > > > ifinfomsg. That's a hacky hacky hack-hack and will likely work but will
> > > > break when ifaddrmsg grows a new member or we introduce another property
> > > > that is valid in RTM_GETADDR requests. It also will not work cleanly
> > > > when users stuff additional properties in there that are valid for the
> > > > address family but are not used int RTM_GETADDR requests.
> > > >
> > > > I would like to hear what other people and davem think we should do.
> > > > Patch it away or print the warning.
> > > >
> > > > Christian  
> > >
> > > You can't break old programs. That is one of the rules of kernel.
> > > Therefore, please either revert the kernel change or put the new attribute
> > > in a place where old versions do not cause problem.
> > >  
> > 
> > Sorry, there's a misunderstanding here. The code doesn't regress anything.
> > The patch  was  written  in a backward compatible way. The only thing it
> > causes are rate-limited logging messages when the wrong struct is passed.
> > But the request still succeeds. The issue is with the logging afaict.
> > 
> > Christian
> 
> 
> That still means enterprise distributions that use the current kernel will
> get customer complaints. You need to remove the warning.

First, you're the senior developer and I totally accept your decision so
we'll make the warning go away!

Rate-limited messages in dmesg on an edge kernel in response to wrong
userspace behavior *without any functional regressions* is something
that I find justifiable and to some extent necessary.
The promise about not regressing userspace is about identical results
from the kernel on unchanged userspace behavior. The contract doesn't
and shouldn't include "We're also not going to tell you that you're
doing something wrong.".
The log messages are an indicator to userspace that "Hey, you're passing
me something wrong in this request. I still will fulfill your request
just as before but please, think about changing this.". That's basically
the only way we have to get userspace to correct false prior behavior
without introducing regressions. Considering warnings in log messages to
be regressions leaves us with nothing visible to do.

Christian

^ permalink raw reply

* [PATCH net-next] tls: Remove redundant vars from tls record structure
From: Vakul Garg @ 2018-09-26 10:52 UTC (permalink / raw)
  To: netdev; +Cc: borisp, aviadye, davejwatson, davem, doronrk, Vakul Garg

Structure 'tls_rec' contains sg_aead_in and sg_aead_out which point
to a aad_space and then chain scatterlists sg_plaintext_data,
sg_encrypted_data respectively. Rather than using chained scatterlists
for plaintext and encrypted data in aead_req, it is efficient to store
aad_space in sg_encrypted_data and sg_plaintext_data itself in the
first index and get rid of sg_aead_in, sg_aead_in and further chaining.

This requires increasing size of sg_encrypted_data & sg_plaintext_data
arrarys by 1 to accommodate entry for aad_space. The code which uses
sg_encrypted_data and sg_plaintext_data has been modified to skip first
index as it points to aad_space.

Signed-off-by: Vakul Garg <vakul.garg@nxp.com>
---
 include/net/tls.h |  6 ++--
 net/tls/tls_sw.c  | 92 ++++++++++++++++++++++++++-----------------------------
 2 files changed, 45 insertions(+), 53 deletions(-)

diff --git a/include/net/tls.h b/include/net/tls.h
index 1615fb5ea114..262420cdad10 100644
--- a/include/net/tls.h
+++ b/include/net/tls.h
@@ -101,13 +101,11 @@ struct tls_rec {
 	struct list_head list;
 	int tx_ready;
 	int tx_flags;
-	struct scatterlist sg_plaintext_data[MAX_SKB_FRAGS];
-	struct scatterlist sg_encrypted_data[MAX_SKB_FRAGS];
 
 	/* AAD | sg_plaintext_data | sg_tag */
-	struct scatterlist sg_aead_in[2];
+	struct scatterlist sg_plaintext_data[MAX_SKB_FRAGS + 1];
 	/* AAD | sg_encrypted_data (data contain overhead for hdr&iv&tag) */
-	struct scatterlist sg_aead_out[2];
+	struct scatterlist sg_encrypted_data[MAX_SKB_FRAGS + 1];
 
 	unsigned int sg_plaintext_size;
 	unsigned int sg_encrypted_size;
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index 4c18b4dba284..8cf7bef7c5a2 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -248,7 +248,7 @@ static void trim_both_sgl(struct sock *sk, int target_size)
 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx);
 	struct tls_rec *rec = ctx->open_rec;
 
-	trim_sg(sk, rec->sg_plaintext_data,
+	trim_sg(sk, &rec->sg_plaintext_data[1],
 		&rec->sg_plaintext_num_elem,
 		&rec->sg_plaintext_size,
 		target_size);
@@ -256,7 +256,7 @@ static void trim_both_sgl(struct sock *sk, int target_size)
 	if (target_size > 0)
 		target_size += tls_ctx->tx.overhead_size;
 
-	trim_sg(sk, rec->sg_encrypted_data,
+	trim_sg(sk, &rec->sg_encrypted_data[1],
 		&rec->sg_encrypted_num_elem,
 		&rec->sg_encrypted_size,
 		target_size);
@@ -270,12 +270,13 @@ static int alloc_encrypted_sg(struct sock *sk, int len)
 	int rc = 0;
 
 	rc = sk_alloc_sg(sk, len,
-			 rec->sg_encrypted_data, 0,
+			 &rec->sg_encrypted_data[1], 0,
 			 &rec->sg_encrypted_num_elem,
 			 &rec->sg_encrypted_size, 0);
 
 	if (rc == -ENOSPC)
-		rec->sg_encrypted_num_elem = ARRAY_SIZE(rec->sg_encrypted_data);
+		rec->sg_encrypted_num_elem =
+			ARRAY_SIZE(rec->sg_encrypted_data) - 1;
 
 	return rc;
 }
@@ -287,12 +288,15 @@ static int alloc_plaintext_sg(struct sock *sk, int len)
 	struct tls_rec *rec = ctx->open_rec;
 	int rc = 0;
 
-	rc = sk_alloc_sg(sk, len, rec->sg_plaintext_data, 0,
-			 &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size,
+	rc = sk_alloc_sg(sk, len,
+			 &rec->sg_plaintext_data[1], 0,
+			 &rec->sg_plaintext_num_elem,
+			 &rec->sg_plaintext_size,
 			 tls_ctx->pending_open_record_frags);
 
 	if (rc == -ENOSPC)
-		rec->sg_plaintext_num_elem = ARRAY_SIZE(rec->sg_plaintext_data);
+		rec->sg_plaintext_num_elem =
+			ARRAY_SIZE(rec->sg_plaintext_data) - 1;
 
 	return rc;
 }
@@ -320,11 +324,11 @@ static void tls_free_open_rec(struct sock *sk)
 	if (!rec)
 		return;
 
-	free_sg(sk, rec->sg_encrypted_data,
+	free_sg(sk, &rec->sg_encrypted_data[1],
 		&rec->sg_encrypted_num_elem,
 		&rec->sg_encrypted_size);
 
-	free_sg(sk, rec->sg_plaintext_data,
+	free_sg(sk, &rec->sg_plaintext_data[1],
 		&rec->sg_plaintext_num_elem,
 		&rec->sg_plaintext_size);
 
@@ -355,7 +359,7 @@ int tls_tx_records(struct sock *sk, int flags)
 		 * Remove the head of tx_list
 		 */
 		list_del(&rec->list);
-		free_sg(sk, rec->sg_plaintext_data,
+		free_sg(sk, &rec->sg_plaintext_data[1],
 			&rec->sg_plaintext_num_elem, &rec->sg_plaintext_size);
 
 		kfree(rec);
@@ -370,13 +374,13 @@ int tls_tx_records(struct sock *sk, int flags)
 				tx_flags = flags;
 
 			rc = tls_push_sg(sk, tls_ctx,
-					 &rec->sg_encrypted_data[0],
+					 &rec->sg_encrypted_data[1],
 					 0, tx_flags);
 			if (rc)
 				goto tx_err;
 
 			list_del(&rec->list);
-			free_sg(sk, rec->sg_plaintext_data,
+			free_sg(sk, &rec->sg_plaintext_data[1],
 				&rec->sg_plaintext_num_elem,
 				&rec->sg_plaintext_size);
 
@@ -405,16 +409,12 @@ static void tls_encrypt_done(struct crypto_async_request *req, int err)
 
 	rec = container_of(aead_req, struct tls_rec, aead_req);
 
-	rec->sg_encrypted_data[0].offset -= tls_ctx->tx.prepend_size;
-	rec->sg_encrypted_data[0].length += tls_ctx->tx.prepend_size;
+	rec->sg_encrypted_data[1].offset -= tls_ctx->tx.prepend_size;
+	rec->sg_encrypted_data[1].length += tls_ctx->tx.prepend_size;
 
 
-	/* Free the record if error is previously set on socket */
+	/* Check if error is previously set on socket */
 	if (err || sk->sk_err) {
-		free_sg(sk, rec->sg_encrypted_data,
-			&rec->sg_encrypted_num_elem, &rec->sg_encrypted_size);
-
-		kfree(rec);
 		rec = NULL;
 
 		/* If err is already set on socket, return the same code */
@@ -449,7 +449,7 @@ static void tls_encrypt_done(struct crypto_async_request *req, int err)
 
 	/* Schedule the transmission */
 	if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask))
-		schedule_delayed_work(&ctx->tx_work.work, 1);
+		schedule_delayed_work(&ctx->tx_work.work, 2);
 }
 
 static int tls_do_encryption(struct sock *sk,
@@ -461,13 +461,14 @@ static int tls_do_encryption(struct sock *sk,
 	struct tls_rec *rec = ctx->open_rec;
 	int rc;
 
-	rec->sg_encrypted_data[0].offset += tls_ctx->tx.prepend_size;
-	rec->sg_encrypted_data[0].length -= tls_ctx->tx.prepend_size;
+	/* Skip the first index as it contains AAD data */
+	rec->sg_encrypted_data[1].offset += tls_ctx->tx.prepend_size;
+	rec->sg_encrypted_data[1].length -= tls_ctx->tx.prepend_size;
 
 	aead_request_set_tfm(aead_req, ctx->aead_send);
 	aead_request_set_ad(aead_req, TLS_AAD_SPACE_SIZE);
-	aead_request_set_crypt(aead_req, rec->sg_aead_in,
-			       rec->sg_aead_out,
+	aead_request_set_crypt(aead_req, rec->sg_plaintext_data,
+			       rec->sg_encrypted_data,
 			       data_len, tls_ctx->tx.iv);
 
 	aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG,
@@ -480,8 +481,8 @@ static int tls_do_encryption(struct sock *sk,
 	rc = crypto_aead_encrypt(aead_req);
 	if (!rc || rc != -EINPROGRESS) {
 		atomic_dec(&ctx->encrypt_pending);
-		rec->sg_encrypted_data[0].offset -= tls_ctx->tx.prepend_size;
-		rec->sg_encrypted_data[0].length += tls_ctx->tx.prepend_size;
+		rec->sg_encrypted_data[1].offset -= tls_ctx->tx.prepend_size;
+		rec->sg_encrypted_data[1].length += tls_ctx->tx.prepend_size;
 	}
 
 	if (!rc) {
@@ -512,16 +513,16 @@ static int tls_push_record(struct sock *sk, int flags,
 	rec->tx_flags = flags;
 	req = &rec->aead_req;
 
-	sg_mark_end(rec->sg_plaintext_data + rec->sg_plaintext_num_elem - 1);
-	sg_mark_end(rec->sg_encrypted_data + rec->sg_encrypted_num_elem - 1);
+	sg_mark_end(rec->sg_plaintext_data + rec->sg_plaintext_num_elem);
+	sg_mark_end(rec->sg_encrypted_data + rec->sg_encrypted_num_elem);
 
 	tls_make_aad(rec->aad_space, rec->sg_plaintext_size,
 		     tls_ctx->tx.rec_seq, tls_ctx->tx.rec_seq_size,
 		     record_type);
 
 	tls_fill_prepend(tls_ctx,
-			 page_address(sg_page(&rec->sg_encrypted_data[0])) +
-			 rec->sg_encrypted_data[0].offset,
+			 page_address(sg_page(&rec->sg_encrypted_data[1])) +
+			 rec->sg_encrypted_data[1].offset,
 			 rec->sg_plaintext_size, record_type);
 
 	tls_ctx->pending_open_record_frags = 0;
@@ -613,7 +614,7 @@ static int memcopy_from_iter(struct sock *sk, struct iov_iter *from,
 	struct tls_context *tls_ctx = tls_get_ctx(sk);
 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx);
 	struct tls_rec *rec = ctx->open_rec;
-	struct scatterlist *sg = rec->sg_plaintext_data;
+	struct scatterlist *sg = &rec->sg_plaintext_data[1];
 	int copy, i, rc = 0;
 
 	for (i = tls_ctx->pending_open_record_frags;
@@ -659,17 +660,10 @@ struct tls_rec *get_rec(struct sock *sk)
 	sg_init_table(&rec->sg_encrypted_data[0],
 		      ARRAY_SIZE(rec->sg_encrypted_data));
 
-	sg_init_table(rec->sg_aead_in, 2);
-	sg_set_buf(&rec->sg_aead_in[0], rec->aad_space,
+	sg_set_buf(&rec->sg_plaintext_data[0], rec->aad_space,
 		   sizeof(rec->aad_space));
-	sg_unmark_end(&rec->sg_aead_in[1]);
-	sg_chain(rec->sg_aead_in, 2, rec->sg_plaintext_data);
-
-	sg_init_table(rec->sg_aead_out, 2);
-	sg_set_buf(&rec->sg_aead_out[0], rec->aad_space,
+	sg_set_buf(&rec->sg_encrypted_data[0], rec->aad_space,
 		   sizeof(rec->aad_space));
-	sg_unmark_end(&rec->sg_aead_out[1]);
-	sg_chain(rec->sg_aead_out, 2, rec->sg_encrypted_data);
 
 	ctx->open_rec = rec;
 
@@ -763,8 +757,8 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
 			ret = zerocopy_from_iter(sk, &msg->msg_iter,
 				try_to_copy, &rec->sg_plaintext_num_elem,
 				&rec->sg_plaintext_size,
-				rec->sg_plaintext_data,
-				ARRAY_SIZE(rec->sg_plaintext_data),
+				&rec->sg_plaintext_data[1],
+				ARRAY_SIZE(rec->sg_plaintext_data) - 1,
 				true);
 			if (ret)
 				goto fallback_to_reg_send;
@@ -781,7 +775,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
 			continue;
 
 fallback_to_reg_send:
-			trim_sg(sk, rec->sg_plaintext_data,
+			trim_sg(sk, &rec->sg_plaintext_data[1],
 				&rec->sg_plaintext_num_elem,
 				&rec->sg_plaintext_size,
 				orig_size);
@@ -801,7 +795,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
 			try_to_copy -= required_size - rec->sg_plaintext_size;
 			full_record = true;
 
-			trim_sg(sk, rec->sg_encrypted_data,
+			trim_sg(sk, &rec->sg_encrypted_data[1],
 				&rec->sg_encrypted_num_elem,
 				&rec->sg_encrypted_size,
 				rec->sg_plaintext_size +
@@ -949,7 +943,7 @@ int tls_sw_sendpage(struct sock *sk, struct page *page,
 		}
 
 		get_page(page);
-		sg = rec->sg_plaintext_data + rec->sg_plaintext_num_elem;
+		sg = &rec->sg_plaintext_data[1] + rec->sg_plaintext_num_elem;
 		sg_set_page(sg, page, copy, offset);
 		sg_unmark_end(sg);
 
@@ -963,7 +957,7 @@ int tls_sw_sendpage(struct sock *sk, struct page *page,
 
 		if (full_record || eor ||
 		    rec->sg_plaintext_num_elem ==
-		    ARRAY_SIZE(rec->sg_plaintext_data)) {
+		    ARRAY_SIZE(rec->sg_plaintext_data) - 1) {
 			ret = tls_push_record(sk, flags, record_type);
 			if (ret) {
 				if (ret == -EINPROGRESS)
@@ -1571,7 +1565,7 @@ void tls_sw_free_resources_tx(struct sock *sk)
 		rec = list_first_entry(&ctx->tx_list,
 				       struct tls_rec, list);
 
-		free_sg(sk, rec->sg_plaintext_data,
+		free_sg(sk, &rec->sg_plaintext_data[1],
 			&rec->sg_plaintext_num_elem,
 			&rec->sg_plaintext_size);
 
@@ -1580,11 +1574,11 @@ void tls_sw_free_resources_tx(struct sock *sk)
 	}
 
 	list_for_each_entry_safe(rec, tmp, &ctx->tx_list, list) {
-		free_sg(sk, rec->sg_encrypted_data,
+		free_sg(sk, &rec->sg_encrypted_data[1],
 			&rec->sg_encrypted_num_elem,
 			&rec->sg_encrypted_size);
 
-		free_sg(sk, rec->sg_plaintext_data,
+		free_sg(sk, &rec->sg_plaintext_data[1],
 			&rec->sg_plaintext_num_elem,
 			&rec->sg_plaintext_size);
 
-- 
2.13.6

^ permalink raw reply related

* Re: [PATCH net-next v6 07/23] zinc: ChaCha20 ARM and ARM64 implementations
From: Jason A. Donenfeld @ 2018-09-26 17:07 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Herbert Xu, Thomas Gleixner, LKML, Netdev,
	Linux Crypto Mailing List, David Miller, Greg Kroah-Hartman,
	Samuel Neves, Andrew Lutomirski, Jean-Philippe Aumasson,
	Russell King - ARM Linux, linux-arm-kernel
In-Reply-To: <CAKv+Gu9hOW0pOjDjrvg1q-v85aiwSZRnjivnvRTCwxMdph4j7g@mail.gmail.com>

On Wed, Sep 26, 2018 at 6:55 PM Ard Biesheuvel
<ard.biesheuvel@linaro.org> wrote:
> Framing it as /needless/ complexity does not help at all. The changes
> you are proposing are very useful, but nobody wants two crypto
> subsystems with two different maintainers in the kernel, so I would
> like to understand where this is going in the future. I am not saying
> it should block these patches though.

Thanks for clarifying. I understood you to be intending to block the
patches until they were converted to an async interface, which is not
what Zinc's about. Seeing as you're just curious about future
directions, that seems much more tenable.

> Also, I have spent a *lot* of time looking at your code, and trying to
> make it better, especially for use cases that weren't on your radar to
> begin with

I am extremely grateful for a good portion of your reviews indeed. As
I mentioned earlier, much is very useful. But in other places, I fear
you're steering this in a direction I really am hesitant to go.

> (e.g., 'pet projects' [your words]

Taken out of context.

> consideration for other aspects of kernel programming, e.g.,
> preemption under -rt, stack size constraints, coding style, importing
> code from other projects etc.

And indeed all of these concerns I've been pretty amenable to, and
continue to do so. What I'm commenting on are things outside of these.


> - please try to be less dismissive of
> feedback first time around, but try to understand why people are
> raising these issues

Apologies, and duly noted. I'll give you the benefit of the doubt.

Jason

^ permalink raw reply

* Re: [PATCH net-next v6 07/23] zinc: ChaCha20 ARM and ARM64 implementations
From: Ard Biesheuvel @ 2018-09-26 17:08 UTC (permalink / raw)
  To: Jason A. Donenfeld
  Cc: Andy Lutomirski, Herbert Xu, Thomas Gleixner,
	Linux Kernel Mailing List, <netdev@vger.kernel.org>,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE, David S. Miller,
	Greg Kroah-Hartman, Samuel Neves, Andy Lutomirski,
	Jean-Philippe Aumasson, Russell King, linux-arm-kernel
In-Reply-To: <CAHmME9pZKUMnnSZ0670rUH4H61g0x88c-B-DZYw_X-8+xgH-=g@mail.gmail.com>

On Wed, 26 Sep 2018 at 19:03, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
>
> On Wed, Sep 26, 2018 at 6:21 PM Andy Lutomirski <luto@amacapital.net> wrote:
> > Are, is what you’re saying that the Zinc chacha20 functions should call simd_relax() every n bytes automatically for some reasonable value of n?  If so, seems sensible, except that some care might be needed to make sure they interact with preemption correctly.
> >
> > What I mean is: the public Zinc entry points should either be callable in an atomic context or they should not be.  I think this should be checked at runtime in an appropriate place with an __might_sleep or similar.  Or simd_relax should learn to *not* schedule if the result of preempt_enable() leaves it atomic. (And the latter needs to be done in a way that works even on non-preempt kernels, and I don’t remember whether that’s possible.). And this should happen regardless of how many bytes are processed. IOW, calling into Zinc should be equally not atomic-safe for 100 bytes and for 10 MB.
>
> I'm not sure this is actually a problem. Namely:
>
> preempt_disable();
> kernel_fpu_begin();
> kernel_fpu_end();
> schedule(); <--- bug!
>
> Calling kernel_fpu_end() disables preemption, but AFAIK, preemption
> enabling/disabling is recursive, so kernel_fpu_end's use of
> preempt_disable won't actually do anything until the outer preempt
> enable is called:
>
> preempt_disable();
> kernel_fpu_begin();
> kernel_fpu_end();
> preempt_enable();
> schedule(); <--- works!
>
> Or am I missing some more subtle point?
>

No that seems accurate to me.

^ permalink raw reply

* Re: [PATCH] net: qed: list usage cleanup
From: David Miller @ 2018-09-26 17:14 UTC (permalink / raw)
  To: zhongjiang; +Cc: Ariel.Elior, everest-linux-l2, netdev, linux-kernel
In-Reply-To: <1537951981-6464-1-git-send-email-zhongjiang@huawei.com>

From: zhong jiang <zhongjiang@huawei.com>
Date: Wed, 26 Sep 2018 16:53:00 +0800

> Trival cleanup, list_move_tail will implement the same function that
> list_del() + list_add_tail() will do. hence just replace them.
> 
> Signed-off-by: zhong jiang <zhongjiang@huawei.com>

Applied.

^ permalink raw reply

* Re: [PATCH] net: liquidio: list usage cleanup
From: David Miller @ 2018-09-26 17:14 UTC (permalink / raw)
  To: zhongjiang
  Cc: derek.chickles, satananda.burla, felix.manlunas, netdev,
	linux-kernel
In-Reply-To: <1537952210-6687-1-git-send-email-zhongjiang@huawei.com>

From: zhong jiang <zhongjiang@huawei.com>
Date: Wed, 26 Sep 2018 16:56:50 +0800

> Trival cleanup, list_move_tail will implement the same function that
> list_del() + list_add_tail() will do. hence just replace them.
> 
> Signed-off-by: zhong jiang <zhongjiang@huawei.com>

Applied.

^ permalink raw reply

* Re: [PATCH net-next] net: smsc: fix return type of ndo_start_xmit function
From: David Miller @ 2018-09-26 17:15 UTC (permalink / raw)
  To: yuehaibing; +Cc: nico, steve.glendinning, robert.jarzmik, linux-kernel, netdev
In-Reply-To: <20180926090629.26400-1-yuehaibing@huawei.com>

From: YueHaibing <yuehaibing@huawei.com>
Date: Wed, 26 Sep 2018 17:06:29 +0800

> The method ndo_start_xmit() is defined as returning an 'netdev_tx_t',
> which is a typedef for an enum type, so make sure the implementation in
> this driver has returns 'netdev_tx_t' value, and change the function
> return type to netdev_tx_t.
> 
> Found by coccinelle.
> 
> Signed-off-by: YueHaibing <yuehaibing@huawei.com>

Applied.

^ permalink raw reply

* Re: [PATCH net-next] net: ti: fix return type of ndo_start_xmit function
From: David Miller @ 2018-09-26 17:17 UTC (permalink / raw)
  To: yuehaibing
  Cc: f.fainelli, grygorii.strashko, w-kwok2, m-karicheri2, lukas,
	bgolaszewski, ivan.khoronzhuk, dan.carpenter, linux-kernel,
	netdev, linux-omap
In-Reply-To: <20180926090951.25544-1-yuehaibing@huawei.com>

From: YueHaibing <yuehaibing@huawei.com>
Date: Wed, 26 Sep 2018 17:09:51 +0800

> @@ -1290,7 +1291,7 @@ static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev)
>  			dev_warn(netcp->ndev_dev, "padding failed (%d), packet dropped\n",
>  				 ret);
>  			tx_stats->tx_dropped++;
> -			return ret;
> +			return NETDEV_TX_BUSY;
>  		}
>  		skb->len = NETCP_MIN_PACKET_SIZE;
>  	}
> @@ -1298,7 +1299,6 @@ static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev)
>  	desc = netcp_tx_map_skb(skb, netcp);
>  	if (unlikely(!desc)) {
>  		netif_stop_subqueue(ndev, subqueue);
> -		ret = -ENOBUFS;
>  		goto drop;
>  	}
>  
> @@ -1319,7 +1319,7 @@ static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev)
>  	if (desc)
>  		netcp_free_tx_desc_chain(netcp, desc, sizeof(*desc));
>  	dev_kfree_skb(skb);
> -	return ret;
> +	return NETDEV_TX_BUSY;
>  }

These conversions are not correct.

If the driver frees the SKB you must not return NETDEV_TX_BUSY.

NETDEV_TX_BUSY tells the caller that the driver could not process the
packet and that it should reqeueu up the SKB and try again later when
there is more TX queue room.

^ permalink raw reply

* Re: [PATCH net-next] net: faraday: fix return type of ndo_start_xmit function
From: David Miller @ 2018-09-26 17:18 UTC (permalink / raw)
  To: yuehaibing; +Cc: andrew, f.fainelli, joel, sam, garsilva, linux-kernel, netdev
In-Reply-To: <20180926091305.24556-1-yuehaibing@huawei.com>

From: YueHaibing <yuehaibing@huawei.com>
Date: Wed, 26 Sep 2018 17:13:05 +0800

> The method ndo_start_xmit() is defined as returning an 'netdev_tx_t',
> which is a typedef for an enum type, so make sure the implementation in
> this driver has returns 'netdev_tx_t' value, and change the function
> return type to netdev_tx_t.
> 
> Found by coccinelle.
> 
> Signed-off-by: YueHaibing <yuehaibing@huawei.com>

Applied.

^ permalink raw reply

* Re: [PATCH net-next] net: ovs: fix return type of ndo_start_xmit function
From: David Miller @ 2018-09-26 17:23 UTC (permalink / raw)
  To: yuehaibing; +Cc: pshelar, linux-kernel, netdev, dev
In-Reply-To: <20180926091538.17876-1-yuehaibing@huawei.com>

From: YueHaibing <yuehaibing@huawei.com>
Date: Wed, 26 Sep 2018 17:15:38 +0800

> The method ndo_start_xmit() is defined as returning an 'netdev_tx_t',
> which is a typedef for an enum type, so make sure the implementation in
> this driver has returns 'netdev_tx_t' value, and change the function
> return type to netdev_tx_t.
> 
> Found by coccinelle.
> 
> Signed-off-by: YueHaibing <yuehaibing@huawei.com>

Applied.

^ permalink raw reply

* Re: [PATCH net-next] net: xen-netback: fix return type of ndo_start_xmit function
From: David Miller @ 2018-09-26 17:23 UTC (permalink / raw)
  To: yuehaibing; +Cc: wei.liu2, paul.durrant, linux-kernel, netdev, xen-devel
In-Reply-To: <20180926091814.11104-1-yuehaibing@huawei.com>

From: YueHaibing <yuehaibing@huawei.com>
Date: Wed, 26 Sep 2018 17:18:14 +0800

> The method ndo_start_xmit() is defined as returning an 'netdev_tx_t',
> which is a typedef for an enum type, so make sure the implementation in
> this driver has returns 'netdev_tx_t' value, and change the function
> return type to netdev_tx_t.
> 
> Found by coccinelle.
> 
> Signed-off-by: YueHaibing <yuehaibing@huawei.com>
> Acked-by: Wei Liu <wei.liu2@citrix.com>

Applied.

^ permalink raw reply

* Re: [PATCH net-next] net: ethernet: dpaa: remove unused variables
From: David Miller @ 2018-09-26 17:35 UTC (permalink / raw)
  To: arnd
  Cc: madalin.bucur, andrew, f.fainelli, yangbo.lu, mail, gustavo,
	netdev, linux-kernel
In-Reply-To: <20180926131225.2661703-1-arnd@arndb.de>

From: Arnd Bergmann <arnd@arndb.de>
Date: Wed, 26 Sep 2018 15:12:13 +0200

> The patch that removed the only users of the oldadv/newadv variables
> accidentally left the now-unused declarations behind:
> 
> drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c: In function 'dpaa_set_pauseparam':
> drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c:185:14: error: unused variable 'oldadv' [-Werror=unused-variable]
> drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c:185:6: error: unused variable 'newadv' [-Werror=unused-variable]
> 
> Fixes: 70814e819c11 ("net: ethernet: Add helper for set_pauseparam for Asym Pause")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Applied.

^ permalink raw reply

* Re: [PATCH net-next] net: phy: mdio-bcm-unimac: mark PM functions as __maybe_unused
From: David Miller @ 2018-09-26 17:36 UTC (permalink / raw)
  To: arnd; +Cc: andrew, f.fainelli, weiyongjun1, netdev, linux-kernel
In-Reply-To: <20180926131418.2729391-1-arnd@arndb.de>

From: Arnd Bergmann <arnd@arndb.de>
Date: Wed, 26 Sep 2018 15:14:10 +0200

> The newly added runtime-pm support causes a harmless warning
> when CONFIG_PM is disabled:
> 
> drivers/net/phy/mdio-bcm-unimac.c:330:12: error: 'unimac_mdio_resume' defined but not used [-Werror=unused-function]
>  static int unimac_mdio_resume(struct device *d)
> drivers/net/phy/mdio-bcm-unimac.c:321:12: error: 'unimac_mdio_suspend' defined but not used [-Werror=unused-function]
>  static int unimac_mdio_suspend(struct device *d)
> 
> Marking the functions as __maybe_unused is the easiest workaround
> and avoids adding #ifdef checks.
> 
> Fixes: b78ac6ecd1b6 ("net: phy: mdio-bcm-unimac: Allow configuring MDIO clock divider")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Applied.

^ permalink raw reply

* Re: [PATCH net-next] phy: mscc: fix printf format
From: David Miller @ 2018-09-26 17:37 UTC (permalink / raw)
  To: arnd
  Cc: andrew, f.fainelli, quentin.schulz, alexandre.belloni, netdev,
	linux-kernel
In-Reply-To: <20180926132021.2933754-1-arnd@arndb.de>

From: Arnd Bergmann <arnd@arndb.de>
Date: Wed, 26 Sep 2018 15:20:11 +0200

> gcc points out that the length of the temporary buffer may not be sufficient for
> large numbers of leds:
> 
> drivers/net/phy/mscc.c: In function 'vsc85xx_probe':
> drivers/net/phy/mscc.c:460:45: error: '-mode' directive writing 5 bytes into a region of size between 0 and 9 [-Werror=format-overflow=]
>    ret = sprintf(led_dt_prop, "vsc8531,led-%d-mode", i);
>                                              ^~~~~
> drivers/net/phy/mscc.c:460:9: note: 'sprintf' output between 19 and 28 bytes into a destination of size 22
>    ret = sprintf(led_dt_prop, "vsc8531,led-%d-mode", i);
>          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 
> While we can make a reasonable assumption that the number of LEDs is small,
> the cost of making the buffer a little bigger is insignificant as well.
> 
> Fixes: 11bfdabb7ff5 ("net: phy: mscc: factorize code for LEDs mode")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Applied.

^ permalink raw reply

* Re: [PATCH net-next v6 07/23] zinc: ChaCha20 ARM and ARM64 implementations
From: Eric Biggers @ 2018-09-26 17:37 UTC (permalink / raw)
  To: Jason A. Donenfeld
  Cc: Ard Biesheuvel, Herbert Xu, Thomas Gleixner, LKML, Netdev,
	Linux Crypto Mailing List, David Miller, Greg Kroah-Hartman,
	Samuel Neves, Andrew Lutomirski, Jean-Philippe Aumasson,
	Russell King - ARM Linux, linux-arm-kernel
In-Reply-To: <CAHmME9p5b=L0FSL72gCszhvut-kr=aD4ZniY9qsJxiBnZk8qNQ@mail.gmail.com>

On Wed, Sep 26, 2018 at 05:41:12PM +0200, Jason A. Donenfeld wrote:
> On Wed, Sep 26, 2018 at 4:02 PM Ard Biesheuvel
> <ard.biesheuvel@linaro.org> wrote:
> > I don't think it makes sense to keep
> > it simple now and add the complexity later (and the same concern
> > applies to async support btw).
> 
> Ugh, no. I don't want to add needless complexity, period. Zinc is
> synchronous, not asynchronous. It provides software implementations.
> That's what it does. While many of your reviews have been useful, many
> of your comments indicate some desire to change and mold the purpose
> and focus of Zinc away from Zinc's intents. Stop that. It's not going
> to become a bloated mess of "things Ard wanted and quipped about on
> LKML." Things like these only serve to filibuster the patchset
> indefinitely. But maybe that's what you'd like all along? Hard to
> tell, honestly. So, no, sorry, Zinc isn't gaining an async interface
> right now.

Can you please stop accusing Ard of "filibustering" your patchset?  Spending too
long in non-preemptible code is a real problem even on non-RT systems.
syzkaller has been reporting bugs where the kernel spins too long without any
preemption points, both in crypto-related code and elsewhere in the kernel.  So
we've had to add explicit preemption points to address those, as otherwise users
can lock up all CPUs for tens of seconds.  The issue being discussed here is
basically the same except here preemption is being explicitly disabled via
kernel_neon_begin(), so it becomes a problem even on non-CONFIG_PREEMPT kernels.

It's much better to address this problem (which is a regression from the current
skcipher API which only maps a page at a time) up front rather than have to rush
to patch it after the fact once the syzbot reports start coming in.

- Eric

^ permalink raw reply

* Greeting
From: Kim Leang @ 2018-09-26 11:25 UTC (permalink / raw)


Hello 

I'm a Board member (C.P.A) of the Foreign Trade Bank of Cambodia. (FTB) 

So i can provide you the details.

Regard

Kim Leang
Member Of Board

^ permalink raw reply

* Re: [PATCH 1/2] dt-bindings: can: tcan4x5x: Add DT bindings for TCAN4x5X driver
From: Dan Murphy @ 2018-09-26 17:40 UTC (permalink / raw)
  To: wg, mkl, davem; +Cc: linux-can, netdev, linux-kernel
In-Reply-To: <20180910201241.24092-1-dmurphy@ti.com>

bump

On 09/10/2018 03:12 PM, Dan Murphy wrote:
> DT binding documentation for TI TCAN4x5x driver.
> 
> Signed-off-by: Dan Murphy <dmurphy@ti.com>
> ---
>  .../devicetree/bindings/net/can/tcan4x5x.txt  | 33 +++++++++++++++++++
>  1 file changed, 33 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/net/can/tcan4x5x.txt
> 
> diff --git a/Documentation/devicetree/bindings/net/can/tcan4x5x.txt b/Documentation/devicetree/bindings/net/can/tcan4x5x.txt
> new file mode 100644
> index 000000000000..3eea2f2bb8a7
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/can/tcan4x5x.txt
> @@ -0,0 +1,33 @@
> +Texas Instruments TCAN4x5x CAN Controller
> +================================================
> +
> +This file provides device node information for the TCAN4x5x interface contains.
> +
> +Required properties:
> +	- compatible: "ti,tcan4x5x"
> +	- reg: 0
> +	- #address-cells : 1
> +	- #size-cells : 0
> +	- spi-max-frequency: Maximum frequency of the SPI bus the chip can
> +			     operate at should be less than or equal to 18 MHz.
> +	- data-ready-gpios: Interrupt GPIO for data and error reporting. 
> +	- wake-up-gpios: Wake up GPIO to wake up the TCAN device
> +
> +Optional properties:
> +	- clocks: Processor clock phandles (see clock bindings for details)
> +		  If no clock is defined then the default 40MHz freq is set.
> +	- reset-gpios: Hardwired output GPIO. If not defined then software
> +		       reset.
> +
> +Example:
> +tcan4x5x: tcan4x5x@0 {
> +		compatible = "ti,tcan4x5x";
> +		reg = <0>;
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		clocks = <&tclkin_ck>;
> +		spi-max-frequency = <10000000>;
> +		data-ready-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;
> +		wake-up-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
> +		reset-gpios = <&gpio1 27 GPIO_ACTIVE_LOW>;
> +	};
> 


-- 
------------------
Dan Murphy

^ permalink raw reply

* Re: [PATCH 2/2] can: tcan4x5x: Add tcan4x5x driver to the kernel
From: Dan Murphy @ 2018-09-26 17:40 UTC (permalink / raw)
  To: wg, mkl, davem; +Cc: linux-can, netdev, linux-kernel
In-Reply-To: <20180910201241.24092-2-dmurphy@ti.com>

bump

On 09/10/2018 03:12 PM, Dan Murphy wrote:
> Add the TCAN4x5x SPI CAN driver.  This device
> uses the Bosch MCAN IP core along with a SPI
> interface map.  The register and data are
> 32 bits wide.
> 
> Signed-off-by: Dan Murphy <dmurphy@ti.com>
> ---
>  drivers/net/can/spi/Kconfig    |    5 +
>  drivers/net/can/spi/Makefile   |    1 +
>  drivers/net/can/spi/tcan4x5x.c | 1206 ++++++++++++++++++++++++++++++++
>  drivers/net/can/spi/tcan4x5x.h |  109 +++
>  4 files changed, 1321 insertions(+)
>  create mode 100644 drivers/net/can/spi/tcan4x5x.c
>  create mode 100644 drivers/net/can/spi/tcan4x5x.h
> 
> diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig
> index 8f2e0dd7b756..8cac6ce37506 100644
> --- a/drivers/net/can/spi/Kconfig
> +++ b/drivers/net/can/spi/Kconfig
> @@ -13,4 +13,9 @@ config CAN_MCP251X
>  	---help---
>  	  Driver for the Microchip MCP251x SPI CAN controllers.
>  
> +config CAN_TCAN4X5X
> +	tristate "Texas Instruments TCAN4X5X SPI CAN controllers"
> +	depends on HAS_DMA
> +	---help---
> +	  Driver for the Texas Instruments TCAN4X5X SPI CAN controllers.
>  endmenu
> diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile
> index f59fa3731073..8ecaace7a920 100644
> --- a/drivers/net/can/spi/Makefile
> +++ b/drivers/net/can/spi/Makefile
> @@ -5,3 +5,4 @@
>  
>  obj-$(CONFIG_CAN_HI311X)	+= hi311x.o
>  obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
> +obj-$(CONFIG_CAN_TCAN4X5X)	+= tcan4x5x.o
> diff --git a/drivers/net/can/spi/tcan4x5x.c b/drivers/net/can/spi/tcan4x5x.c
> new file mode 100644
> index 000000000000..ca3753efe35a
> --- /dev/null
> +++ b/drivers/net/can/spi/tcan4x5x.c
> @@ -0,0 +1,1206 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// SPI to CAN driver for the Texas Instruments TCAN4x5x
> +// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
> +
> +#include <linux/can/core.h>
> +#include <linux/can/dev.h>
> +#include <linux/can/led.h>
> +#include <linux/clk.h>
> +#include <linux/completion.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/freezer.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/spi/spi.h>
> +#include <linux/uaccess.h>
> +
> +#include <linux/regulator/consumer.h>
> +#include <linux/gpio/consumer.h>
> +
> +#include "tcan4x5x.h"
> +
> +#define DEVICE_NAME "tcan4x5x"
> +#define TCAN4X5X_EXT_CLK_DEF	40000000
> +
> +#define TCAN4X5X_CLEAR_ALL_INT	0xffffffff
> +#define TCAN4X5X_SET_ALL_INT	0xffffffff
> +
> +#define TCAN4X5X_TX_ECHO_SKB_MAX 1
> +#define TCAN4X5X_DATA_PKT_OFF	2
> +#define TCAN4X5X_WRITE_CMD	(0x61 << 24)
> +#define TCAN4X5X_READ_CMD	(0x41 << 24)
> +
> +#define TCAN4X5X_SID_SHIFT	18
> +#define TCAN4X5X_DLC_SHIFT	16
> +
> +#define TCAN4X5X_ESI_SHIFT	31
> +#define TCAN4X5X_XTD_SHIFT	30
> +#define TCAN4X5X_RTR_SHIFT	29
> +#define TCAN4X5X_FDF_SHIFT	21
> +#define TCAN4X5X_BRS_SHIFT	20
> +#define TCAN4X5X_DLC_SHIFT	16
> +
> +#define TCAN4X5X_ESI_MASK	BIT(31)
> +#define TCAN4X5X_XTD_MASK	BIT(30)
> +#define TCAN4X5X_RTR_MASK	BIT(29)
> +
> +#define TCAN4X5X_DLC_MASK	0xf0000
> +#define TCAN4X5X_SW_RESET	BIT(2)
> +
> +#define TCAN4X5X_MODE_SEL_MASK		(BIT(7) | BIT(6))
> +#define TCAN4X5X_MODE_SLEEP		0x00
> +#define TCAN4X5X_MODE_STANDBY		BIT(6)
> +#define TCAN4X5X_MODE_NORMAL		BIT(7)
> +#define TCAN4X5X_MCAN_CONFIGURED	BIT(5)
> +#define TCAN4X5X_WATCHDOG_EN		BIT(3)
> +#define TCAN4X5X_WD_60_MS_TIMER		0
> +#define TCAN4X5X_WD_600_MS_TIMER	BIT(28)
> +#define TCAN4X5X_WD_3_S_TIMER		BIT(29)
> +#define TCAN4X5X_WD_6_S_TIMER		(BIT(28) | BIT(29))
> +
> +/* Nominal Bit Timing & Prescaler Register */
> +#define TCAN4X5X_NSJW_SHIFT	25
> +#define TCAN4X5X_NBRP_SHIFT	16
> +#define TCAN4X5X_NTSEG1_SHIFT	8
> +
> +#define TCAN4X5X_TDCR_TDCO_SHIFT	8
> +
> +/* Data Bit Timing & Prescaler Register (DBTP) */
> +#define DBTP_TDC		BIT(23)
> +#define DBTP_DBRP_SHIFT		16
> +#define DBTP_DBRP_MASK		(0x1f << DBTP_DBRP_SHIFT)
> +#define DBTP_DTSEG1_SHIFT	8
> +#define DBTP_DTSEG1_MASK	(0x1f << DBTP_DTSEG1_SHIFT)
> +#define DBTP_DTSEG2_SHIFT	4
> +#define DBTP_DTSEG2_MASK	(0xf << DBTP_DTSEG2_SHIFT)
> +#define DBTP_DSJW_SHIFT		0
> +#define DBTP_DSJW_MASK		(0xf << DBTP_DSJW_SHIFT)
> +
> +#define TCAN4x5x_QUEUE_LVL_MASK		0x1f
> +#define TCAN4x5x_QUEUE_IDX_SHIFT	16
> +#define TCAN4x5x_QUEUE_IDX_MASK		0x1f00
> +
> +#define TCAN4X5X_CANBUSNOM_INT_EN	BIT(14)
> +
> +#define TCAN4X5X_NUM_TX_BUF	5
> +#define TCAN4X5X_TX_QUEUE_SHIFT	24
> +#define TCAN4X5X_TX_NDTB_SHIFT	16
> +#define TCAN4X5X_TX_BUF_START	0x324
> +
> +#define TCAN4X5X_NUM_RX_BUF		3
> +#define TCAN4X5X_RX_WATER_MARK		2
> +#define TCAN4X5X_RX_WATER_MARK_SHIFT	24
> +#define TCAN4X5X_RX_FIFO_SZ_SHIFT	16
> +#define TCAN4X5X_RX_BUF_START		0x4
> +
> +#define TCAN4X5X_RX_F1DS_SHIFT	4
> +#define TCAN4X5X_RX_RBDS_SHIFT	8
> +
> +#define TCAN4X5X_RX_FIFO0_MESSAGE	BIT(0)
> +#define TCAN4X5X_RX_FIFO1_MESSAGE	BIT(4)
> +#define TCAN4X5X_RX_BUFFER_MESSAGE	BIT(19)
> +#define TCAN4X5X_RX_INDEX_MASK		0x3f00
> +#define TCAN4X5X_RX_INDEX_SHIFT		8
> +
> +#define TCAN4X5X_RX_ADDR_OFFSET		0x8000
> +#define TCAN4X5X_RX_BUF_ADDR_OFFSET	0x8100
> +#define TCAN4X5X_RX_ADDR_MASK		0xffff
> +
> +#define TCAN4X5X_ERR_PROTOCOL_MASK	0x7
> +#define TCAN4X5X_ERR_STUFERR		0x1
> +#define TCAN4X5X_ERR_FRMERR		0x2
> +#define TCAN4X5X_ERR_ACKERR		0x3
> +#define TCAN4X5X_ERR_BIT1ERR		0x4
> +#define TCAN4X5X_ERR_BIT0ERR		0x5
> +#define TCAN4X5X_ERR_CRCERR		0x6
> +
> +/* Interrupt bits */
> +#define TCAN4X5X_CANBUSTERMOPEN_INT_EN	BIT(30)
> +#define TCAN4X5X_CANHCANL_INT_EN	BIT(29)
> +#define TCAN4X5X_CANHBAT_INT_EN		BIT(28)
> +#define TCAN4X5X_CANLGND_INT_EN		BIT(27)
> +#define TCAN4X5X_CANBUSOPEN_INT_EN	BIT(26)
> +#define TCAN4X5X_CANBUSGND_INT_EN	BIT(25)
> +#define TCAN4X5X_CANBUSBAT_INT_EN	BIT(24)
> +#define TCAN4X5X_UVSUP_INT_EN		BIT(22)
> +#define TCAN4X5X_UVIO_INT_EN		BIT(21)
> +#define TCAN4X5X_TSD_INT_EN		BIT(19)
> +#define TCAN4X5X_ECCERR_INT_EN		BIT(16)
> +#define TCAN4X5X_CANINT_INT_EN		BIT(15)
> +#define TCAN4X5X_LWU_INT_EN		BIT(14)
> +#define TCAN4X5X_CANSLNT_INT_EN		BIT(10)
> +#define TCAN4X5X_CANDOM_INT_EN		BIT(8)
> +#define TCAN4X5X_CANBUS_ERR_INT_EN	BIT(5)
> +#define TCAN4X5X_BUS_FAULT		BIT(4)
> +#define TCAN4X5X_MCAN_INT		BIT(1)
> +#define TCAN4X5X_ENABLE_ALL_INT		(TCAN4X5X_MCAN_INT | \
> +					TCAN4X5X_BUS_FAULT | \
> +					TCAN4X5X_CANBUS_ERR_INT_EN | \
> +					TCAN4X5X_CANINT_INT_EN)
> +
> +/* MCAN Interrupt bits */
> +#define TCAN4X5X_MCAN_IR_ARA		BIT(29)
> +#define TCAN4X5X_MCAN_IR_PED		BIT(28)
> +#define TCAN4X5X_MCAN_IR_PEA		BIT(27)
> +#define TCAN4X5X_MCAN_IR_WD		BIT(26)
> +#define TCAN4X5X_MCAN_IR_BO		BIT(25)
> +#define TCAN4X5X_MCAN_IR_EW		BIT(24)
> +#define TCAN4X5X_MCAN_IR_EP		BIT(23)
> +#define TCAN4X5X_MCAN_IR_ELO		BIT(22)
> +#define TCAN4X5X_MCAN_IR_BEU		BIT(21)
> +#define TCAN4X5X_MCAN_IR_BEC		BIT(20)
> +#define TCAN4X5X_MCAN_IR_DRX		BIT(19)
> +#define TCAN4X5X_MCAN_IR_TOO		BIT(18)
> +#define TCAN4X5X_MCAN_IR_MRAF		BIT(17)
> +#define TCAN4X5X_MCAN_IR_TSW		BIT(16)
> +#define TCAN4X5X_MCAN_IR_TEFL		BIT(15)
> +#define TCAN4X5X_MCAN_IR_TEFF		BIT(14)
> +#define TCAN4X5X_MCAN_IR_TEFW		BIT(13)
> +#define TCAN4X5X_MCAN_IR_TEFN		BIT(12)
> +#define TCAN4X5X_MCAN_IR_TFE		BIT(11)
> +#define TCAN4X5X_MCAN_IR_TCF		BIT(10)
> +#define TCAN4X5X_MCAN_IR_TC		BIT(9)
> +#define TCAN4X5X_MCAN_IR_HPM		BIT(8)
> +#define TCAN4X5X_MCAN_IR_RF1L		BIT(7)
> +#define TCAN4X5X_MCAN_IR_RF1F		BIT(6)
> +#define TCAN4X5X_MCAN_IR_RF1W		BIT(5)
> +#define TCAN4X5X_MCAN_IR_RF1N		BIT(4)
> +#define TCAN4X5X_MCAN_IR_RF0L		BIT(3)
> +#define TCAN4X5X_MCAN_IR_RF0F		BIT(2)
> +#define TCAN4X5X_MCAN_IR_RF0W		BIT(1)
> +#define TCAN4X5X_MCAN_IR_RF0N		BIT(0)
> +#define TCAN4X5X_ENABLE_MCAN_INT	(TCAN4X5X_MCAN_IR_TC | \
> +					TCAN4X5X_MCAN_IR_RF0N | \
> +					TCAN4X5X_MCAN_IR_RF1N | \
> +					TCAN4X5X_MCAN_IR_RF0F | \
> +					TCAN4X5X_MCAN_IR_RF1F)
> +
> +/* CCR bits */
> +#define TCAN4X5X_CCCR_NISO_BOSCH	BIT(15)
> +#define TCAN4X5X_CCCR_TXP		BIT(15)
> +#define TCAN4X5X_CCCR_EFBI		BIT(13)
> +#define TCAN4X5X_CCCR_PXHD_DIS		BIT(12)
> +#define TCAN4X5X_CCCR_BRSE		BIT(9)
> +#define TCAN4X5X_CCCR_FDOE		BIT(8)
> +#define TCAN4X5X_CCCR_TEST		BIT(7)
> +#define TCAN4X5X_CCCR_DAR_DIS		BIT(6)
> +#define TCAN4X5X_CCCR_MON		BIT(5)
> +#define TCAN4X5X_CCCR_CSR		BIT(4)
> +#define TCAN4X5X_CCCR_CSA		BIT(3)
> +#define TCAN4X5X_CCCR_ASM		BIT(2)
> +#define TCAN4X5X_CCCR_CCE		BIT(1)
> +#define TCAN4X5X_CCCR_INIT		BIT(0)
> +
> +#define TCAN4X5X_EINT0			BIT(0)
> +#define TCAN4X5X_EINT1			BIT(1)
> +
> +struct tcan4x5x_rx_regs {
> +	u32 fifo_status_reg;
> +	u32 fifo_config_reg;
> +	u32 fifo_ack_reg;
> +	u32 rx_buf_shift;
> +};
> +
> +struct tcan4x5x_rx_regs tcan4x5x_fifo_regs[] = {
> +	{ TCAN4X5X_MCAN_RXF0S, TCAN4X5X_MCAN_RXF0C, TCAN4X5X_MCAN_RXF0A, 0},
> +	{ TCAN4X5X_MCAN_RXF1S, TCAN4X5X_MCAN_RXF1C, TCAN4X5X_MCAN_RXF1A, 4},
> +	{ TCAN4X5X_MCAN_NDAT1, TCAN4X5X_MCAN_RXBC, TCAN4X5X_MCAN_NDAT1, 8},
> +};
> +
> +enum tcan4x5x_data_size {
> +	TCAN4X5X_8_BYTE = 0,
> +	TCAN4X5X_12_BYTE,
> +	TCAN4X5X_16_BYTE,
> +	TCAN4X5X_20_BYTE,
> +	TCAN4X5X_24_BYTE,
> +	TCAN4X5X_32_BYTE,
> +	TCAN4X5X_48_BYTE,
> +	TCAN4X5X_64_BYTE,
> +};
> +
> +static const struct can_bittiming_const tcan4x5x_bittiming_const = {
> +	.name = DEVICE_NAME,
> +	.tseg1_min = 2,
> +	.tseg1_max = 31,
> +	.tseg2_min = 2,
> +	.tseg2_max = 16,
> +	.sjw_max = 16,
> +	.brp_min = 1,
> +	.brp_max = 32,
> +	.brp_inc = 1,
> +};
> +
> +static const struct can_bittiming_const tcan4x5x_data_bittiming_const = {
> +	.name = DEVICE_NAME,
> +	.tseg1_min = 1,
> +	.tseg1_max = 32,
> +	.tseg2_min = 1,
> +	.tseg2_max = 16,
> +	.sjw_max = 16,
> +	.brp_min = 1,
> +	.brp_max = 32,
> +	.brp_inc = 1,
> +};
> +
> +static void tcan4x5x_clean(struct net_device *net)
> +{
> +	struct tcan4x5x_priv *priv = netdev_priv(net);
> +
> +	if (priv->tx_skb || priv->tx_len)
> +		net->stats.tx_errors++;
> +	if (priv->tx_skb)
> +		dev_kfree_skb(priv->tx_skb);
> +	if (priv->tx_len)
> +		can_free_echo_skb(priv->net, 0);
> +
> +	priv->tx_skb = NULL;
> +	priv->tx_len = 0;
> +}
> +
> +static int regmap_spi_gather_write(void *context, const void *reg,
> +				   size_t reg_len, const void *val,
> +				   size_t val_len)
> +{
> +	struct device *dev = context;
> +	struct spi_device *spi = to_spi_device(dev);
> +	u32 addr;
> +	struct spi_message m;
> +	struct spi_transfer t[2] = {{ .tx_buf = &addr, .len = 4, .cs_change = 0,},
> +				   { .tx_buf = val, .len = val_len, },};
> +
> +	addr = TCAN4X5X_WRITE_CMD | (*((u16 *)reg) << 8) | val_len >> 2;
> +
> +	spi_message_init(&m);
> +	spi_message_add_tail(&t[0], &m);
> +	spi_message_add_tail(&t[1], &m);
> +
> +	return spi_sync(spi, &m);
> +}
> +
> +static int tcan4x5x_regmap_write(void *context, const void *data, size_t count)
> +{
> +	u16 *reg = (u16 *)(data);
> +	const u32 *val = data + 2;
> +
> +	return regmap_spi_gather_write(context, reg, 2, val, count - 2);
> +}
> +
> +static int regmap_spi_async_write(void *context,
> +				  const void *reg, size_t reg_len,
> +				  const void *val, size_t val_len,
> +				  struct regmap_async *a)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static struct regmap_async *regmap_spi_async_alloc(void)
> +{
> +	return NULL;
> +}
> +
> +static int tcan4x5x_regmap_read(void *context,
> +				const void *reg, size_t reg_size,
> +				void *val, size_t val_size)
> +{
> +	struct device *dev = context;
> +	struct spi_device *spi = to_spi_device(dev);
> +
> +	u32 addr = TCAN4X5X_READ_CMD | (*((u16 *)reg) << 8) | val_size >> 2;
> +
> +	return spi_write_then_read(spi, &addr, 4, val, val_size);
> +}
> +
> +static struct regmap_bus tcan4x5x_bus = {
> +	.write = tcan4x5x_regmap_write,
> +	.gather_write = regmap_spi_gather_write,
> +	.async_write = regmap_spi_async_write,
> +	.async_alloc = regmap_spi_async_alloc,
> +	.read = tcan4x5x_regmap_read,
> +	.read_flag_mask = 0x00,
> +	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
> +	.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
> +};
> +
> +static uint8_t tcan4x5x_dlc_conv(uint8_t input)
> +{
> +	const static u8 lookup[7] = {12, 16, 20, 24, 32, 48, 64};
> +
> +	if (input < 9)
> +		return input;
> +
> +	if (input < 16)
> +		return lookup[(unsigned int)(input - 9)];
> +
> +	return 0;
> +}
> +
> +static uint8_t tcan4x5x_txrxesc_value(uint8_t input)
> +{
> +	const u8 lookup[8] = {8, 12, 16, 20, 24, 32, 48, 64};
> +	return lookup[(unsigned int)(input & 0x07)];
> +}
> +
> +static void tcan4x5x_hw_tx(struct tcan4x5x_priv *tcan4x5x)
> +{
> +	u32 sid, eid, exide, rtr, brs, esi, fdf, xtd, data_len;
> +	u32 mcan_address, mcan_tx_element_sz;
> +	int queue_stat, queue_lvl, queue_idx;
> +	struct canfd_frame *fd_frame;
> +	struct can_frame *frame;
> +	int tx_element_sz, i, temp;
> +	canid_t frame_id;
> +	u8 dlc_len;
> +
> +	regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_TXFQS, &queue_stat);
> +	queue_lvl = queue_stat & TCAN4x5x_QUEUE_LVL_MASK;
> +	queue_idx = (queue_stat & TCAN4x5x_QUEUE_IDX_MASK) >> TCAN4x5x_QUEUE_IDX_SHIFT;
> +
> +	if (tcan4x5x->tx_skb->len == CAN_MTU) {
> +		fd_frame = NULL;
> +		frame = (struct can_frame *)tcan4x5x->tx_skb->data;
> +		frame_id = frame->can_id;
> +		dlc_len = frame->can_dlc;
> +		data_len = ((dlc_len % 4) + dlc_len) / 4;
> +		brs = 0;
> +	} else if (tcan4x5x->tx_skb->len == CANFD_MTU) {
> +		frame = NULL;
> +		fd_frame = (struct canfd_frame *)tcan4x5x->tx_skb->data;
> +		frame_id = fd_frame->can_id;
> +		dlc_len = fd_frame->len;
> +		data_len = ((dlc_len % 4) + dlc_len) / 4;
> +		brs = fd_frame->flags & CANFD_BRS;
> +		esi = fd_frame->flags & CANFD_ESI;
> +		fdf = 1;
> +	} else {
> +		return;
> +	}
> +
> +	eid = frame_id & CAN_EFF_MASK;
> +	rtr = (frame_id & CAN_RTR_FLAG) ? 1 : 0;
> +
> +	exide = (frame_id & CAN_EFF_FLAG) ? 1 : 0;
> +	if (exide) {
> +		sid = frame_id & CAN_EFF_MASK;
> +		xtd = 1;
> +	} else {
> +		sid = (frame_id & CAN_SFF_MASK) << TCAN4X5X_SID_SHIFT;
> +		xtd = 0;
> +	}
> +
> +	regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_TXBC, &mcan_address);
> +
> +	mcan_address = (mcan_address & 0xffff) + TCAN4X5X_MRAM_START;
> +	temp = (uint8_t)((mcan_address >> 24) & 0x3F);
> +
> +	tx_element_sz = temp > 32 ? 32 : temp;
> +	temp = (uint8_t)((mcan_address >> 16) & 0x3F);
> +
> +	tx_element_sz += temp > 32 ? 32 : temp;
> +	mcan_address += ((uint32_t)tx_element_sz * queue_idx);
> +	regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_TXESC, &mcan_tx_element_sz);
> +	tx_element_sz = tcan4x5x_txrxesc_value(mcan_tx_element_sz & 0x07) + 8;
> +	mcan_address += ((uint32_t)tx_element_sz * 0);
> +
> +	tx_element_sz = (tcan4x5x_dlc_conv(dlc_len & 0x0F) + 8) >> 2;
> +	if (tcan4x5x_dlc_conv(dlc_len & 0x0F) % 4)
> +		tx_element_sz += 1;
> +
> +	tcan4x5x->spi_tx_buf[0] = esi << TCAN4X5X_ESI_SHIFT |
> +				  xtd << TCAN4X5X_XTD_SHIFT |
> +				  rtr << TCAN4X5X_RTR_SHIFT | sid;
> +
> +	tcan4x5x->spi_tx_buf[1] = fdf << TCAN4X5X_FDF_SHIFT |
> +		 brs << TCAN4X5X_BRS_SHIFT | dlc_len << TCAN4X5X_DLC_SHIFT;
> +
> +	if (tcan4x5x->tx_skb->len == CAN_MTU)
> +		memcpy(tcan4x5x->spi_tx_buf + TCAN4X5X_DATA_PKT_OFF,
> +		       frame->data, dlc_len);
> +	else
> +		memcpy(tcan4x5x->spi_tx_buf + TCAN4X5X_DATA_PKT_OFF,
> +		       fd_frame->data, dlc_len);
> +
> +	for (i = dlc_len + 1; i < TCAN4X5X_BUF_LEN / 4; i++)
> +		tcan4x5x->spi_tx_buf[i] = 0;
> +
> +	regmap_bulk_write(tcan4x5x->regmap, mcan_address, tcan4x5x->spi_tx_buf,
> +			  TCAN4X5X_BUF_LEN);
> +
> +	regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_TXBAR, (1 << (queue_idx)));
> +}
> +
> +int tcan4x5x_hw_rx(struct tcan4x5x_priv *tcan4x5x)
> +{
> +	u32 queue_idx, fifo_idx, fifo_start_addr, rx_buf_size, msg_type;
> +	u32 data_buffer[TCAN4X5X_BUF_LEN] = {0x0};
> +	u32 rx_header[2] = {0x0};
> +	struct tcan4x5x_rx_regs *buffer_regs;
> +	struct canfd_frame *fd_frame;
> +	int dlc_len, data_len;
> +	struct sk_buff *skb;
> +
> +	skb = alloc_canfd_skb(tcan4x5x->net, &fd_frame);
> +	if (!skb) {
> +		dev_err(&tcan4x5x->spi->dev, "cannot allocate RX skb\n");
> +		tcan4x5x->net->stats.rx_dropped++;
> +		return -ENOMEM;
> +	}
> +
> +	regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_INT_FLAG, &msg_type);
> +	if (msg_type & TCAN4X5X_RX_FIFO0_MESSAGE) {
> +		buffer_regs = &tcan4x5x_fifo_regs[0];
> +	} else if (msg_type & TCAN4X5X_RX_FIFO1_MESSAGE) {
> +		buffer_regs = &tcan4x5x_fifo_regs[1];
> +	} else if (msg_type & TCAN4X5X_RX_BUFFER_MESSAGE) {
> +		buffer_regs = &tcan4x5x_fifo_regs[2];
> +	} else {
> +		buffer_regs = NULL;
> +		return -EINVAL;
> +	}
> +
> +	rx_buf_size = TCAN4X5X_BUF_LEN;
> +
> +	/* Determine which FIFO needs service */
> +	regmap_read(tcan4x5x->regmap, buffer_regs->fifo_status_reg, &fifo_idx);
> +	if (msg_type & TCAN4X5X_RX_BUFFER_MESSAGE)
> +		queue_idx = fifo_idx - 1;
> +	else
> +		queue_idx = (TCAN4X5X_RX_INDEX_MASK & fifo_idx) >> TCAN4X5X_RX_INDEX_SHIFT;
> +
> +	/* Calculate the FIFO start address to service */
> +	regmap_read(tcan4x5x->regmap, buffer_regs->fifo_config_reg, &fifo_start_addr);
> +	fifo_start_addr = (TCAN4X5X_RX_ADDR_MASK & fifo_start_addr);
> +	if (msg_type & TCAN4X5X_RX_BUFFER_MESSAGE)
> +		fifo_start_addr = fifo_start_addr + TCAN4X5X_RX_BUF_ADDR_OFFSET +
> +				  (rx_buf_size * queue_idx);
> +	else
> +		fifo_start_addr = fifo_start_addr + TCAN4X5X_RX_ADDR_OFFSET +
> +				  (rx_buf_size * queue_idx);
> +
> +	regmap_bulk_read(tcan4x5x->regmap, fifo_start_addr, rx_header, 2);
> +
> +	dlc_len = (rx_header[1] & TCAN4X5X_DLC_MASK) >> TCAN4X5X_DLC_SHIFT;
> +	if (dlc_len <= 8)
> +		data_len = dlc_len;
> +	else
> +		data_len = tcan4x5x_txrxesc_value(dlc_len);
> +
> +	regmap_bulk_read(tcan4x5x->regmap, fifo_start_addr + 8,
> +			 data_buffer, data_len / 4);
> +
> +	/* Acknowledge receipt of the data */
> +	regmap_write(tcan4x5x->regmap, buffer_regs->fifo_ack_reg, queue_idx);
> +
> +	if (rx_header[0] &  TCAN4X5X_XTD_MASK) {
> +		fd_frame->can_id = CAN_EFF_FLAG;
> +		fd_frame->can_id |= (rx_header[0] & CAN_EFF_MASK);
> +	} else {
> +		fd_frame->can_id |= ((rx_header[0] >> TCAN4X5X_SID_SHIFT) &
> +				    CAN_SFF_MASK);
> +	}
> +
> +	if (rx_header[0] & TCAN4X5X_RTR_MASK)
> +		fd_frame->can_id |= CAN_RTR_FLAG;
> +
> +	if (rx_header[0] & TCAN4X5X_ESI_MASK) {
> +		fd_frame->can_id |= CAN_ERR_FLAG;
> +		fd_frame->flags |= CANFD_ESI;
> +		netdev_dbg(tcan4x5x->net, "ESI Error\n");
> +	}
> +
> +	fd_frame->len = data_len;
> +	memcpy(fd_frame->data, data_buffer, fd_frame->len);
> +
> +	tcan4x5x->net->stats.rx_packets++;
> +	tcan4x5x->net->stats.rx_bytes += fd_frame->len;
> +
> +	can_led_event(tcan4x5x->net, CAN_LED_EVENT_RX);
> +	netif_rx_ni(skb);
> +
> +	return 0;
> +}
> +
> +static void tcan4x5x_sleep(struct spi_device *spi)
> +{
> +	struct tcan4x5x_priv *tcan4x5x = spi_get_drvdata(spi);
> +
> +	regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
> +			   TCAN4X5X_MODE_SEL_MASK, TCAN4X5X_MODE_STANDBY);
> +}
> +
> +static int tcan4x5x_reset(struct net_device *net)
> +{
> +	struct tcan4x5x_priv *tcan4x5x = netdev_priv(net);
> +
> +	if (tcan4x5x->reset_gpio) {
> +		gpiod_set_value_cansleep(tcan4x5x->reset_gpio, 1);
> +		udelay(10);
> +		gpiod_set_value_cansleep(tcan4x5x->reset_gpio, 0);
> +	} else {
> +		regmap_write(tcan4x5x->regmap, TCAN4X5X_CONFIG,
> +			     TCAN4X5X_SW_RESET);
> +	}
> +
> +	return 0;
> +}
> +
> +static int tcan4x5x_power_enable(struct regulator *reg, int enable)
> +{
> +	if (IS_ERR_OR_NULL(reg))
> +		return 0;
> +
> +	if (enable)
> +		return regulator_enable(reg);
> +	else
> +		return regulator_disable(reg);
> +}
> +
> +static irqreturn_t tcan4x5x_can_ist(int irq, void *dev_id)
> +{
> +	struct tcan4x5x_priv *tcan4x5x = dev_id;
> +	struct spi_device *spi = tcan4x5x->spi;
> +	struct net_device *net = tcan4x5x->net;
> +	enum can_state new_state;
> +	int intf, eflag, mcan_intf;
> +
> +	mutex_lock(&tcan4x5x->tcan4x5x_lock);
> +
> +	regmap_read(tcan4x5x->regmap, TCAN4X5X_INT_FLAGS, &intf);
> +	if (intf & TCAN4X5X_MCAN_INT)
> +		tcan4x5x_hw_rx(tcan4x5x);
> +
> +	regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_INT_FLAG, &mcan_intf);
> +
> +	regmap_read(tcan4x5x->regmap, TCAN4X5X_STATUS, &eflag);
> +	/* Update can state */
> +	if (eflag & TCAN4X5X_MCAN_IR_BO)
> +		new_state = CAN_STATE_BUS_OFF;
> +	else if (eflag & TCAN4X5X_MCAN_IR_EP)
> +		new_state = CAN_STATE_ERROR_PASSIVE;
> +	else if (eflag & TCAN4X5X_MCAN_IR_EW)
> +		new_state = CAN_STATE_ERROR_WARNING;
> +	else
> +		new_state = CAN_STATE_ERROR_ACTIVE;
> +
> +	if (new_state != tcan4x5x->can.state) {
> +		struct can_frame *cf;
> +		struct sk_buff *skb;
> +		enum can_state rx_state, tx_state;
> +		u32 error_count;
> +
> +		skb = alloc_can_err_skb(net, &cf);
> +		if (!skb)
> +			goto ist_out;
> +
> +		regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_ECR, &error_count);
> +		cf->data[6] = error_count & 0xff;
> +		cf->data[7] = error_count & 0x7f00 >> 8;
> +		tx_state = cf->data[6] >= cf->data[7] ? new_state : 0;
> +		rx_state = cf->data[6] <= cf->data[7] ? new_state : 0;
> +		can_change_state(net, cf, tx_state, rx_state);
> +		netif_rx_ni(skb);
> +
> +		if (new_state == CAN_STATE_BUS_OFF) {
> +			can_bus_off(net);
> +			if (tcan4x5x->can.restart_ms == 0) {
> +				tcan4x5x->force_quit = 1;
> +				tcan4x5x_sleep(spi);
> +				goto ist_out;
> +			}
> +		}
> +	}
> +
> +	/* Update bus errors */
> +	if ((intf & TCAN4X5X_BUS_FAULT) &&
> +	    (tcan4x5x->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) {
> +		struct can_frame *cf;
> +		struct sk_buff *skb;
> +		u32 psr_err, error_count;
> +
> +		/* Check for protocol errors */
> +		regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_PSR, &psr_err);
> +		if (psr_err & TCAN4X5X_ERR_PROTOCOL_MASK) {
> +			skb = alloc_can_err_skb(net, &cf);
> +			if (!skb)
> +				goto ist_out;
> +
> +			cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
> +			tcan4x5x->can.can_stats.bus_error++;
> +			tcan4x5x->net->stats.rx_errors++;
> +			if (psr_err & TCAN4X5X_ERR_BIT0ERR)
> +				cf->data[2] |= CAN_ERR_PROT_BIT0;
> +			else if (psr_err & TCAN4X5X_ERR_BIT1ERR)
> +				cf->data[2] |= CAN_ERR_PROT_BIT1;
> +			else if (psr_err & TCAN4X5X_ERR_FRMERR)
> +				cf->data[2] |= CAN_ERR_PROT_FORM;
> +			else if (psr_err & TCAN4X5X_ERR_STUFERR)
> +				cf->data[2] |= CAN_ERR_PROT_STUFF;
> +			else if (psr_err & TCAN4X5X_ERR_CRCERR)
> +				cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
> +			else if (psr_err & TCAN4X5X_ERR_ACKERR)
> +				cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
> +
> +			regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_ECR,
> +				    &error_count);
> +			cf->data[6] = error_count & 0xff;
> +			cf->data[7] = error_count & 0x7f00 >> 8;
> +			netdev_dbg(tcan4x5x->net, "Bus Error\n");
> +			netif_rx_ni(skb);
> +		}
> +	}
> +
> +	if (mcan_intf & TCAN4X5X_MCAN_IR_TC) {
> +		net->stats.tx_packets++;
> +		net->stats.tx_bytes += tcan4x5x->tx_len - 1;
> +		can_led_event(net, CAN_LED_EVENT_TX);
> +		if (tcan4x5x->tx_len) {
> +			can_get_echo_skb(net, 0);
> +			tcan4x5x->tx_len = 0;
> +		}
> +		netif_wake_queue(net);
> +	}
> +
> +ist_out:
> +	regmap_write(tcan4x5x->regmap, TCAN4X5X_INT_FLAGS, TCAN4X5X_CLEAR_ALL_INT);
> +	regmap_write(tcan4x5x->regmap, TCAN4X5X_STATUS, TCAN4X5X_CLEAR_ALL_INT);
> +	regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_INT_FLAG,
> +		     TCAN4X5X_CLEAR_ALL_INT);
> +
> +	mutex_unlock(&tcan4x5x->tcan4x5x_lock);
> +	return IRQ_HANDLED;
> +}
> +
> +static int tcan4x5x_do_set_bittiming(struct net_device *net)
> +{
> +	struct tcan4x5x_priv *priv = netdev_priv(net);
> +	struct can_bittiming *bt = &priv->can.bittiming;
> +	struct can_bittiming *dbt = &priv->can.data_bittiming;
> +	u16 brp, sjw, tseg1, tseg2;
> +	int ret;
> +	u32 val;
> +
> +	brp = bt->brp - 1;
> +	sjw = bt->sjw - 1;
> +	tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
> +	tseg2 = bt->phase_seg2 - 1;
> +	val = (brp << TCAN4X5X_NBRP_SHIFT) | (sjw << TCAN4X5X_NSJW_SHIFT) |
> +		(tseg1 << TCAN4X5X_NTSEG1_SHIFT) | tseg2;
> +
> +	ret = regmap_write(priv->regmap, TCAN4X5X_MCAN_NBTP, val);
> +	if (ret)
> +		return -EIO;
> +
> +	if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
> +		val = 0;
> +		brp = dbt->brp - 1;
> +		sjw = dbt->sjw - 1;
> +		tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
> +		tseg2 = dbt->phase_seg2 - 1;
> +
> +		/* TDC is only needed for bitrates beyond 2.5 MBit/s.
> +		 * This is mentioned in the "Bit Time Requirements for CAN FD"
> +		 * paper presented at the International CAN Conference 2013
> +		 */
> +		if (dbt->bitrate > 2500000) {
> +			u32 tdco, ssp;
> +
> +			/* Use the same value of secondary sampling point
> +			 * as the data sampling point
> +			 */
> +			ssp = dbt->sample_point;
> +
> +			/* Equation based on Bosch's M_CAN User Manual's
> +			 * Transmitter Delay Compensation Section
> +			 */
> +			tdco = (priv->can.clock.freq / 1000) *
> +			       ssp / dbt->bitrate;
> +
> +			/* Max valid TDCO value is 127 */
> +			if (tdco > 127) {
> +				netdev_warn(net, "TDCO value of %u is beyond maximum. Using maximum possible value\n",
> +					    tdco);
> +				tdco = 127;
> +			}
> +
> +			val |= DBTP_TDC;
> +			ret = regmap_write(priv->regmap, TCAN4X5X_MCAN_TDCR,
> +					   tdco << TCAN4X5X_TDCR_TDCO_SHIFT);
> +			if (ret)
> +				return -EIO;
> +		}
> +
> +		val |= (brp << DBTP_DBRP_SHIFT) |
> +			   (sjw << DBTP_DSJW_SHIFT) |
> +			   (tseg1 << DBTP_DTSEG1_SHIFT) |
> +			   (tseg2 << DBTP_DTSEG2_SHIFT);
> +
> +		ret = regmap_write(priv->regmap, TCAN4X5X_MCAN_DBTP, val);
> +	}
> +
> +	return ret;
> +}
> +
> +static int tcan4x5x_setup(struct spi_device *spi)
> +{
> +	struct tcan4x5x_priv *tcan4x5x = spi_get_drvdata(spi);
> +	int start_reg = TCAN4X5X_MRAM_START;
> +	int end_reg = start_reg + TCAN4X5X_MRAM_SIZE;
> +	int ret;
> +
> +	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_INT_REG,
> +			   TCAN4X5X_CLEAR_ALL_INT);
> +	if (ret)
> +		return -EIO;
> +
> +	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_INT_EN,
> +			   TCAN4X5X_ENABLE_MCAN_INT);
> +	if (ret)
> +		return -EIO;
> +
> +	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_CCCR,
> +			   TCAN4X5X_CCCR_INIT | TCAN4X5X_CCCR_CCE);
> +	if (ret)
> +		return -EIO;
> +
> +	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_CCCR,
> +			   TCAN4X5X_CCCR_INIT | TCAN4X5X_CCCR_CCE |
> +			   TCAN4X5X_CCCR_FDOE | TCAN4X5X_CCCR_BRSE);
> +	if (ret)
> +		return -EIO;
> +
> +	ret = tcan4x5x_do_set_bittiming(tcan4x5x->net);
> +	if (ret)
> +		return -EIO;
> +
> +	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_TXESC,
> +			   TCAN4X5X_64_BYTE);
> +	if (ret)
> +		return -EIO;
> +
> +	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_TXBC,
> +			   (TCAN4X5X_NUM_TX_BUF << TCAN4X5X_TX_QUEUE_SHIFT |
> +			   TCAN4X5X_TX_BUF_START));
> +	if (ret)
> +		return -EIO;
> +
> +	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_RXF0C,
> +			   (TCAN4X5X_RX_WATER_MARK << TCAN4X5X_RX_WATER_MARK_SHIFT |
> +			   TCAN4X5X_NUM_RX_BUF << TCAN4X5X_RX_FIFO_SZ_SHIFT |
> +			   TCAN4X5X_RX_BUF_START));
> +	if (ret)
> +		return -EIO;
> +
> +	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_RXESC,
> +			   (TCAN4X5X_64_BYTE << TCAN4X5X_RX_RBDS_SHIFT |
> +			   TCAN4X5X_64_BYTE << TCAN4X5X_RX_F1DS_SHIFT |
> +			   TCAN4X5X_64_BYTE));
> +	if (ret)
> +		return -EIO;
> +
> +	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_TXBTIE,
> +			   TCAN4X5X_SET_ALL_INT);
> +	if (ret)
> +		return -EIO;
> +
> +
> +	ret = regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
> +				 TCAN4X5X_MODE_SEL_MASK, TCAN4X5X_MODE_NORMAL);
> +	if (ret)
> +		return -EIO;
> +
> +	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_ILE, TCAN4X5X_EINT0);
> +	if (ret)
> +		return -EIO;
> +
> +	/* Zero out the MCAN buffers */
> +	while (start_reg < end_reg) {
> +		regmap_write(tcan4x5x->regmap, start_reg, 0);
> +		start_reg += 4;
> +	}
> +
> +	return ret;
> +}
> +
> +static void tcan4x5x_tx_work_handler(struct work_struct *ws)
> +{
> +	struct tcan4x5x_priv *tcan4x5x = container_of(ws, struct tcan4x5x_priv,
> +						tx_work);
> +	struct net_device *net = tcan4x5x->net;
> +	struct can_frame *frame;
> +
> +	mutex_lock(&tcan4x5x->tcan4x5x_lock);
> +	if (tcan4x5x->tx_skb) {
> +		if (tcan4x5x->can.state == CAN_STATE_BUS_OFF) {
> +			tcan4x5x_clean(net);
> +		} else {
> +			frame = (struct can_frame *)tcan4x5x->tx_skb->data;
> +			tcan4x5x_hw_tx(tcan4x5x);
> +			tcan4x5x->tx_len = 1 + frame->can_dlc;
> +			can_put_echo_skb(tcan4x5x->tx_skb, net, 0);
> +			tcan4x5x->tx_skb = NULL;
> +		}
> +	}
> +	mutex_unlock(&tcan4x5x->tcan4x5x_lock);
> +}
> +
> +static void tcan4x5x_restart_work_handler(struct work_struct *ws)
> +{
> +	struct tcan4x5x_priv *tcan4x5x = container_of(ws, struct tcan4x5x_priv,
> +						restart_work);
> +	struct spi_device *spi = tcan4x5x->spi;
> +	struct net_device *net = tcan4x5x->net;
> +
> +	mutex_lock(&tcan4x5x->tcan4x5x_lock);
> +	if (tcan4x5x->after_suspend) {
> +		tcan4x5x_reset(net);
> +		tcan4x5x_setup(spi);
> +		if (tcan4x5x->after_suspend & AFTER_SUSPEND_RESTART) {
> +			tcan4x5x_setup(spi);
> +		} else if (tcan4x5x->after_suspend & AFTER_SUSPEND_UP) {
> +			netif_device_attach(net);
> +			tcan4x5x_clean(net);
> +			tcan4x5x_setup(spi);
> +			netif_wake_queue(net);
> +		} else {
> +			tcan4x5x_sleep(spi);
> +		}
> +		tcan4x5x->after_suspend = 0;
> +		tcan4x5x->force_quit = 0;
> +	}
> +
> +	if (tcan4x5x->restart_tx) {
> +		tcan4x5x->restart_tx = 0;
> +		tcan4x5x_reset(net);
> +		tcan4x5x_clean(net);
> +		tcan4x5x_setup(spi);
> +		netif_wake_queue(net);
> +	}
> +	mutex_unlock(&tcan4x5x->tcan4x5x_lock);
> +}
> +
> +static int tcan4x5x_open(struct net_device *net)
> +{
> +	struct tcan4x5x_priv *priv = netdev_priv(net);
> +	struct spi_device *spi = priv->spi;
> +	unsigned long flags = IRQF_ONESHOT | IRQF_TRIGGER_LOW;
> +	int ret;
> +
> +	ret = open_candev(net);
> +	if (ret)
> +		return ret;
> +
> +	mutex_lock(&priv->tcan4x5x_lock);
> +	tcan4x5x_power_enable(priv->power, 1);
> +
> +	priv->force_quit = 0;
> +	priv->tx_skb = NULL;
> +	priv->tx_len = 0;
> +
> +	ret = request_threaded_irq(priv->irq, NULL, tcan4x5x_can_ist,
> +				   flags, DEVICE_NAME, priv);
> +	if (ret) {
> +		dev_err(&spi->dev, "failed to acquire irq %d %i\n",
> +			priv->irq, ret);
> +		goto out_close;
> +	}
> +
> +	priv->wq = alloc_workqueue("tcan4x5x_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM,
> +				   0);
> +	if (!priv->wq) {
> +		ret = -ENOMEM;
> +		goto out_free_irq;
> +	}
> +
> +	INIT_WORK(&priv->tx_work, tcan4x5x_tx_work_handler);
> +	INIT_WORK(&priv->restart_work, tcan4x5x_restart_work_handler);
> +
> +	priv->spi_tx_buf = devm_kzalloc(&spi->dev, TCAN4X5X_BUF_LEN,
> +					GFP_KERNEL);
> +	if (!priv->spi_tx_buf) {
> +		ret = -ENOMEM;
> +		goto  out_free_wq;
> +	}
> +
> +	priv->spi_rx_buf = devm_kzalloc(&spi->dev, TCAN4X5X_BUF_LEN,
> +					GFP_KERNEL);
> +	if (!priv->spi_rx_buf) {
> +		ret = -ENOMEM;
> +		goto  out_free_wq;
> +	}
> +
> +	if (priv->wake_gpio)
> +		gpiod_set_value_cansleep(priv->wake_gpio, 1);
> +
> +	ret = tcan4x5x_reset(net);
> +	if (ret)
> +		goto out_free_wq;
> +
> +	ret = tcan4x5x_setup(spi);
> +	if (ret)
> +		goto out_free_wq;
> +
> +	can_led_event(net, CAN_LED_EVENT_OPEN);
> +	netif_wake_queue(net);
> +	mutex_unlock(&priv->tcan4x5x_lock);
> +
> +	return 0;
> +
> + out_free_wq:
> +	destroy_workqueue(priv->wq);
> + out_free_irq:
> +	free_irq(priv->irq, priv);
> +	tcan4x5x_sleep(spi);
> + out_close:
> +	tcan4x5x_power_enable(priv->power, 0);
> +	close_candev(net);
> +	mutex_unlock(&priv->tcan4x5x_lock);
> +	return ret;
> +}
> +
> +static int tcan4x5x_stop(struct net_device *net)
> +{
> +	struct tcan4x5x_priv *priv = netdev_priv(net);
> +	struct spi_device *spi = priv->spi;
> +
> +	close_candev(net);
> +
> +	priv->force_quit = 1;
> +	free_irq(priv->irq, priv);
> +	destroy_workqueue(priv->wq);
> +	priv->wq = NULL;
> +
> +	mutex_lock(&priv->tcan4x5x_lock);
> +
> +	priv->can.state = CAN_STATE_STOPPED;
> +	tcan4x5x_sleep(spi);
> +	tcan4x5x_power_enable(priv->power, 0);
> +
> +	mutex_unlock(&priv->tcan4x5x_lock);
> +
> +	can_led_event(net, CAN_LED_EVENT_STOP);
> +
> +	return 0;
> +}
> +
> +static netdev_tx_t tcan4x5x_hard_start_xmit(struct sk_buff *skb,
> +					    struct net_device *net)
> +{
> +	struct tcan4x5x_priv *priv = netdev_priv(net);
> +	struct spi_device *spi = priv->spi;
> +
> +	if (priv->tx_skb || priv->tx_len) {
> +		dev_warn(&spi->dev, "hard_xmit called while tx busy\n");
> +		return NETDEV_TX_BUSY;
> +	}
> +
> +	if (can_dropped_invalid_skb(net, skb))
> +		return NETDEV_TX_OK;
> +
> +	netif_stop_queue(net);
> +	priv->tx_skb = skb;
> +	queue_work(priv->wq, &priv->tx_work);
> +
> +	return NETDEV_TX_OK;
> +}
> +
> +static int tcan4x5x_do_set_mode(struct net_device *net, enum can_mode mode)
> +{
> +	struct tcan4x5x_priv *priv = netdev_priv(net);
> +
> +	switch (mode) {
> +	case CAN_MODE_START:
> +		tcan4x5x_clean(net);
> +		priv->can.state = CAN_STATE_ERROR_ACTIVE;
> +		priv->restart_tx = 1;
> +		queue_work(priv->wq, &priv->restart_work);
> +		break;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct net_device_ops tcan4x5x_netdev_ops = {
> +	.ndo_open = tcan4x5x_open,
> +	.ndo_stop = tcan4x5x_stop,
> +	.ndo_start_xmit = tcan4x5x_hard_start_xmit,
> +	.ndo_change_mtu = can_change_mtu,
> +};
> +
> +static int tcan4x5x_parse_config(struct tcan4x5x_priv *tcan4x5x)
> +{
> +	tcan4x5x->reset_gpio = devm_gpiod_get_optional(&tcan4x5x->spi->dev,
> +						       "reset", GPIOD_OUT_LOW);
> +	if (IS_ERR(tcan4x5x->reset_gpio))
> +		tcan4x5x->reset_gpio = NULL;
> +
> +	tcan4x5x->wake_gpio = devm_gpiod_get_optional(&tcan4x5x->spi->dev,
> +						      "wake-up", GPIOD_OUT_LOW);
> +	if (IS_ERR(tcan4x5x->wake_gpio))
> +		tcan4x5x->wake_gpio = NULL;
> +
> +	tcan4x5x->interrupt_gpio = devm_gpiod_get(&tcan4x5x->spi->dev,
> +						  "data-ready", GPIOD_IN);
> +	if (IS_ERR(tcan4x5x->interrupt_gpio)) {
> +		dev_err(&tcan4x5x->spi->dev, "data-ready gpio not defined\n");
> +		return -EINVAL;
> +	}
> +
> +	tcan4x5x->irq = gpiod_to_irq(tcan4x5x->interrupt_gpio);
> +
> +	tcan4x5x->power = devm_regulator_get_optional(&tcan4x5x->spi->dev,
> +						      "vsup");
> +	if (PTR_ERR(tcan4x5x->power) == -EPROBE_DEFER)
> +		return -EPROBE_DEFER;
> +
> +	return 0;
> +}
> +
> +static const struct regmap_config tcan4x5x_regmap = {
> +	.reg_bits = 16,
> +	.val_bits = 32,
> +	.cache_type = REGCACHE_NONE,
> +	.max_register = TCAN4X5X_MAX_REGISTER,
> +};
> +
> +static int tcan4x5x_can_probe(struct spi_device *spi)
> +{
> +	struct net_device *net;
> +	struct tcan4x5x_priv *priv;
> +	struct clk *clk;
> +	int freq, ret;
> +
> +	clk = devm_clk_get(&spi->dev, NULL);
> +	if (IS_ERR(clk)) {
> +		dev_err(&spi->dev, "no CAN clock source defined\n");
> +		freq = TCAN4X5X_EXT_CLK_DEF;
> +	} else {
> +		freq = clk_get_rate(clk);
> +	}
> +
> +	/* Sanity check */
> +	if (freq < 20000000 || freq > TCAN4X5X_EXT_CLK_DEF)
> +		return -ERANGE;
> +
> +	/* Allocate can/net device */
> +	net = alloc_candev(sizeof(*priv), TCAN4X5X_TX_ECHO_SKB_MAX);
> +	if (!net)
> +		return -ENOMEM;
> +
> +	if (!IS_ERR(clk)) {
> +		ret = clk_prepare_enable(clk);
> +		if (ret)
> +			goto out_free;
> +	}
> +
> +	net->netdev_ops = &tcan4x5x_netdev_ops;
> +	net->flags |= IFF_ECHO;
> +	net->mtu = CANFD_MTU;
> +
> +	priv = netdev_priv(net);
> +	priv->can.bittiming_const = &tcan4x5x_bittiming_const;
> +	priv->can.data_bittiming_const = &tcan4x5x_data_bittiming_const;
> +	priv->can.do_set_mode = tcan4x5x_do_set_mode;
> +	priv->can.clock.freq = freq;
> +	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
> +				       CAN_CTRLMODE_LISTENONLY |
> +				       CAN_CTRLMODE_BERR_REPORTING |
> +				       CAN_CTRLMODE_FD |
> +				       CAN_CTRLMODE_FD_NON_ISO;
> +	priv->net = net;
> +	priv->spi = spi;
> +	priv->clk = clk;
> +	spi_set_drvdata(spi, priv);
> +
> +	ret = tcan4x5x_parse_config(priv);
> +	if (ret)
> +		goto out_clk;
> +
> +	/* Configure the SPI bus */
> +	spi->bits_per_word = 32;
> +	ret = spi_setup(spi);
> +	if (ret)
> +		goto out_clk;
> +
> +	mutex_init(&priv->tcan4x5x_lock);
> +
> +	priv->regmap = devm_regmap_init(&spi->dev, &tcan4x5x_bus,
> +					&spi->dev, &tcan4x5x_regmap);
> +
> +	SET_NETDEV_DEV(net, &spi->dev);
> +	ret = register_candev(net);
> +	if (ret)
> +		goto error_probe;
> +
> +	devm_can_led_init(net);
> +
> +	netdev_info(net, "TCAN4X5X successfully initialized.\n");
> +	return 0;
> +
> +error_probe:
> +	tcan4x5x_power_enable(priv->power, 0);
> +out_clk:
> +	if (!IS_ERR(clk))
> +		clk_disable_unprepare(clk);
> +out_free:
> +	free_candev(net);
> +	dev_err(&spi->dev, "Probe failed, err=%d\n", -ret);
> +	return ret;
> +}
> +
> +static int tcan4x5x_can_remove(struct spi_device *spi)
> +{
> +	struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
> +	struct net_device *net = priv->net;
> +
> +	unregister_candev(net);
> +
> +	tcan4x5x_power_enable(priv->power, 0);
> +
> +	if (!IS_ERR(priv->clk))
> +		clk_disable_unprepare(priv->clk);
> +
> +	free_candev(net);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id tcan4x5x_of_match[] = {
> +	{ .compatible = "ti,tcan4x5x", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, tcan4x5x_of_match);
> +
> +static const struct spi_device_id tcan4x5x_id_table[] = {
> +	{
> +		.name		= "tcan4x5x",
> +		.driver_data	= 0,
> +	},
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(spi, tcan4x5x_id_table);
> +
> +static struct spi_driver tcan4x5x_can_driver = {
> +	.driver = {
> +		.name = DEVICE_NAME,
> +		.of_match_table = tcan4x5x_of_match,
> +		.pm = NULL,
> +	},
> +	.id_table = tcan4x5x_id_table,
> +	.probe = tcan4x5x_can_probe,
> +	.remove = tcan4x5x_can_remove,
> +};
> +module_spi_driver(tcan4x5x_can_driver);
> +
> +MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
> +MODULE_DESCRIPTION("Texas Instruments TCAN4x5x CAN driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/net/can/spi/tcan4x5x.h b/drivers/net/can/spi/tcan4x5x.h
> new file mode 100644
> index 000000000000..5e14ba571d49
> --- /dev/null
> +++ b/drivers/net/can/spi/tcan4x5x.h
> @@ -0,0 +1,109 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// SPI to CAN driver for the Texas Instruments TCA4x5x
> +// Flash driver chip family
> +// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
> +
> +#define TCAN4X5X_DEV_ID0	0x00
> +#define TCAN4X5X_DEV_ID1	0x04
> +#define TCAN4X5X_REV		0x08
> +#define TCAN4X5X_STATUS		0x0C
> +#define TCAN4X5X_ERROR_STATUS	0x10
> +#define TCAN4X5X_CONTROL	0x14
> +
> +#define TCAN4X5X_CONFIG		0x800
> +#define TCAN4X5X_TS_PRESCALE	0x804
> +#define TCAN4X5X_TEST_REG	0x808
> +#define TCAN4X5X_INT_FLAGS	0x820
> +#define TCAN4X5X_MCAN_INT_REG	0x824
> +#define TCAN4X5X_INT_EN		0x830
> +
> +#define TCAN4X5X_MCAN_CREL	0x1000
> +#define TCAN4X5X_MCAN_ENDN	0x1004
> +#define TCAN4X5X_MCAN_CUST	0x1008
> +#define TCAN4X5X_MCAN_DBTP	0x100C
> +#define TCAN4X5X_MCAN_TEST	0x1010
> +#define TCAN4X5X_MCAN_RWD	0x1014
> +#define TCAN4X5X_MCAN_CCCR	0x1018
> +#define TCAN4X5X_MCAN_NBTP	0x101C
> +#define TCAN4X5X_MCAN_TSCC	0x1020
> +#define TCAN4X5X_MCAN_TSCV	0x1024
> +#define TCAN4X5X_MCAN_TOCC	0x1028
> +#define TCAN4X5X_MCAN_TOCV	0x102C
> +#define TCAN4X5X_MCAN_ECR	0x1040
> +#define TCAN4X5X_MCAN_PSR	0x1044
> +#define TCAN4X5X_MCAN_TDCR	0x1048
> +#define TCAN4X5X_MCAN_INT_FLAG	0x1050
> +#define TCAN4X5X_MCAN_INT_EN	0x1054
> +#define TCAN4X5X_MCAN_ILS	0x1058
> +#define TCAN4X5X_MCAN_ILE	0x105C
> +#define TCAN4X5X_MCAN_GFC	0x1080
> +#define TCAN4X5X_MCAN_SIDFC	0x1084
> +#define TCAN4X5X_MCAN_XIDFC	0x1088
> +#define TCAN4X5X_MCAN_XIDAM	0x1090
> +#define TCAN4X5X_MCAN_HPMS	0x1094
> +#define TCAN4X5X_MCAN_NDAT1	0x1098
> +#define TCAN4X5X_MCAN_NDAT2	0x109C
> +#define TCAN4X5X_MCAN_RXF0C	0x10A0
> +#define TCAN4X5X_MCAN_RXF0S	0x10A4
> +#define TCAN4X5X_MCAN_RXF0A	0x10A8
> +#define TCAN4X5X_MCAN_RXBC	0x10AC
> +#define TCAN4X5X_MCAN_RXF1C	0x10B0
> +#define TCAN4X5X_MCAN_RXF1S	0x10B4
> +#define TCAN4X5X_MCAN_RXF1A	0x10B8
> +#define TCAN4X5X_MCAN_RXESC	0x10BC
> +#define TCAN4X5X_MCAN_TXBC	0x10C0
> +#define TCAN4X5X_MCAN_TXFQS	0x10C4
> +#define TCAN4X5X_MCAN_TXESC	0x10C8
> +#define TCAN4X5X_MCAN_TXBRP	0x10CC
> +#define TCAN4X5X_MCAN_TXBAR	0x10D0
> +#define TCAN4X5X_MCAN_TXBCR	0x10D4
> +#define TCAN4X5X_MCAN_TXBTO	0x10D8
> +#define TCAN4X5X_MCAN_TXBCF	0x10DC
> +#define TCAN4X5X_MCAN_TXBTIE	0x10E0
> +#define TCAN4X5X_MCAN_TXBCIE	0x10E4
> +#define TCAN4X5X_MCAN_TXEFC	0x10F0
> +#define TCAN4X5X_MCAN_TXEFS	0x10F4
> +#define TCAN4X5X_MCAN_TXEFA	0x10F8
> +
> +#define TCAN4X5X_MRAM_START	0x8000
> +#define TCAN4X5X_MRAM_SIZE	2048
> +
> +#define TCAN4X5X_MAX_REGISTER	0x8fff
> +
> +/* 64 byte buffer + 8 byte MCAN header */
> +#define TCAN4X5X_BUF_LEN 	72
> +
> +struct tcan4x5x_priv {
> +	struct can_priv can;
> +	struct net_device *net;
> +	struct regmap *regmap;
> +	struct spi_device *spi;
> +
> +	struct mutex tcan4x5x_lock; /* SPI device lock */
> +
> +	struct gpio_desc *reset_gpio;
> +	struct gpio_desc *interrupt_gpio;
> +	struct gpio_desc *wake_gpio;
> +	struct regulator *power;
> +	struct clk *clk;
> +
> +	struct sk_buff *tx_skb;
> +	int tx_len;
> +
> +	struct workqueue_struct *wq;
> +	struct work_struct tx_work;
> +	struct work_struct restart_work;
> +
> +	u32 *spi_tx_buf;
> +	u32 *spi_rx_buf;
> +
> +	int force_quit;
> +	int after_suspend;
> +#define AFTER_SUSPEND_UP 1
> +#define AFTER_SUSPEND_DOWN 2
> +#define AFTER_SUSPEND_POWER 4
> +#define AFTER_SUSPEND_RESTART 8
> +	int restart_tx;
> +
> +	int irq;
> +};
> 


-- 
------------------
Dan Murphy

^ permalink raw reply


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