Netdev List
 help / color / mirror / Atom feed
* [PATCH bpf] bpf: run bpf programs with preemption disabled
From: Alexei Starovoitov @ 2019-01-29  2:43 UTC (permalink / raw)
  To: davem
  Cc: daniel, peterz, jannh, paulmck, will.deacon, mingo, netdev,
	kernel-team

Disabled preemption is necessary for proper access to per-cpu maps
from BPF programs.

But the sender side of socket filters didn't have preemption disabled:
unix_dgram_sendmsg->sk_filter->sk_filter_trim_cap->bpf_prog_run_save_cb->BPF_PROG_RUN

and a combination of af_packet with tun device didn't disable either:
tpacket_snd->packet_direct_xmit->packet_pick_tx_queue->ndo_select_queue->
  tun_select_queue->tun_ebpf_select_queue->bpf_prog_run_clear_cb->BPF_PROG_RUN

Disable preemption before executing BPF programs (both classic and extended).

Reported-by: Jann Horn <jannh@google.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
---
 include/linux/filter.h | 21 ++++++++++++++++++---
 kernel/bpf/cgroup.c    |  2 +-
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/include/linux/filter.h b/include/linux/filter.h
index ad106d845b22..e532fcc6e4b5 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -591,8 +591,8 @@ static inline u8 *bpf_skb_cb(struct sk_buff *skb)
 	return qdisc_skb_cb(skb)->data;
 }
 
-static inline u32 bpf_prog_run_save_cb(const struct bpf_prog *prog,
-				       struct sk_buff *skb)
+static inline u32 __bpf_prog_run_save_cb(const struct bpf_prog *prog,
+					 struct sk_buff *skb)
 {
 	u8 *cb_data = bpf_skb_cb(skb);
 	u8 cb_saved[BPF_SKB_CB_LEN];
@@ -611,15 +611,30 @@ static inline u32 bpf_prog_run_save_cb(const struct bpf_prog *prog,
 	return res;
 }
 
+static inline u32 bpf_prog_run_save_cb(const struct bpf_prog *prog,
+				       struct sk_buff *skb)
+{
+	u32 res;
+
+	preempt_disable();
+	res = __bpf_prog_run_save_cb(prog, skb);
+	preempt_enable();
+	return res;
+}
+
 static inline u32 bpf_prog_run_clear_cb(const struct bpf_prog *prog,
 					struct sk_buff *skb)
 {
 	u8 *cb_data = bpf_skb_cb(skb);
+	u32 res;
 
 	if (unlikely(prog->cb_access))
 		memset(cb_data, 0, BPF_SKB_CB_LEN);
 
-	return BPF_PROG_RUN(prog, skb);
+	preempt_disable();
+	res = BPF_PROG_RUN(prog, skb);
+	preempt_enable();
+	return res;
 }
 
 static __always_inline u32 bpf_prog_run_xdp(const struct bpf_prog *prog,
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index ab612fe9862f..d17d05570a3f 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -572,7 +572,7 @@ int __cgroup_bpf_run_filter_skb(struct sock *sk,
 	bpf_compute_and_save_data_end(skb, &saved_data_end);
 
 	ret = BPF_PROG_RUN_ARRAY(cgrp->bpf.effective[type], skb,
-				 bpf_prog_run_save_cb);
+				 __bpf_prog_run_save_cb);
 	bpf_restore_data_end(skb, saved_data_end);
 	__skb_pull(skb, offset);
 	skb->sk = save_sk;
-- 
2.20.0


^ permalink raw reply related

* Re: [PATCH v2 net 7/7] virtio_net: Differentiate sk_buff and xdp_frame on freeing
From: Jason Wang @ 2019-01-29  2:49 UTC (permalink / raw)
  To: Toshiaki Makita, David S. Miller, Michael S. Tsirkin
  Cc: netdev, virtualization
In-Reply-To: <5f114c25-1f42-996b-134c-962b64597e74@lab.ntt.co.jp>


On 2019/1/29 上午10:35, Toshiaki Makita wrote:
> On 2019/01/29 11:23, Jason Wang wrote:
>> On 2019/1/29 上午8:45, Toshiaki Makita wrote:
> ...
>>> @@ -2666,10 +2696,10 @@ static void free_unused_bufs(struct
>>> virtnet_info *vi)
>>>        for (i = 0; i < vi->max_queue_pairs; i++) {
>>>            struct virtqueue *vq = vi->sq[i].vq;
>>>            while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) {
>>> -            if (!is_xdp_raw_buffer_queue(vi, i))
>>> +            if (!is_xdp_frame(buf))
>>
>> I believe this is the last user of is_xdp_raw_buffer_queue(), maybe you
>> can sent a patch on top to remove it.
> Actually patch2 added new users of it ;)


Right, I missed that.

Thanks


>
>>
>>>                    dev_kfree_skb(buf);
>>>                else
>>> -                xdp_return_frame(buf);
>>> +                xdp_return_frame(ptr_to_xdp(buf));
>>>            }
>>>        }
>>>    
>>
>> Acked-by: Jason Wang <jasowang@redhat.com>
>>
> Thanks!
>

^ permalink raw reply

* Re: [PATCH net-next] net: udp Allow CHECKSUM_UNNECESSARY packets to do GRO.
From: maowenan @ 2019-01-29  3:00 UTC (permalink / raw)
  To: netdev, davem, edumazet
In-Reply-To: <1548214428-114642-1-git-send-email-maowenan@huawei.com>

Hi all,
Do you have any comments about this change?


On 2019/1/23 11:33, Mao Wenan wrote:
> When udp4_gro_receive() get one packet that uh->check=0,
> skb_gro_checksum_validate_zero_check() will set the
> skb->ip_summed = CHECKSUM_UNNECESSARY;
> skb->csum_level = 0;
> Then udp_gro_receive() will flush the packet which is not CHECKSUM_PARTIAL,
> It is not our expect,  because check=0 in udp header indicates this
> packet is no need to caculate checksum, we should go further to do GRO.
> 
> This patch changes the value of csum_cnt according to skb->csum_level.
> ---
>  include/linux/netdevice.h | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 1377d08..9c819f1 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -2764,6 +2764,7 @@ static inline void skb_gro_incr_csum_unnecessary(struct sk_buff *skb)
>  		 * during GRO. This saves work if we fallback to normal path.
>  		 */
>  		__skb_incr_checksum_unnecessary(skb);
> +		NAPI_GRO_CB(skb)->csum_cnt = skb->csum_level + 1;
>  	}
>  }
>  
> 


^ permalink raw reply

* Re: [PATCH bpf] bpf, doc: add reviewers to maintainers entry
From: Yonghong Song @ 2019-01-29  3:05 UTC (permalink / raw)
  To: Daniel Borkmann, ast@kernel.org
  Cc: netdev@vger.kernel.org, Martin Lau, Song Liu
In-Reply-To: <20190128225526.5340-1-daniel@iogearbox.net>



On 1/28/19 2:55 PM, Daniel Borkmann wrote:
> In order to better scale BPF development on netdev, we've adopted a
> reviewer rotation for all BPF patches among the five of us for some
> time now. Lets give credit where credit is due, and add Martin, Song
> and Yonghong as official BPF reviewers to MAINTAINERS file. Also
> while at it, add regex matching for BPF such that we get properly
> Cc'ed for files not listed here.
> 
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>

Thanks!
Acked-by: Yonghong Song <yhs@fb.com>


> ---
>   MAINTAINERS | 5 +++++
>   1 file changed, 5 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 51029a4..6e13378 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2848,6 +2848,9 @@ F:	include/uapi/linux/if_bonding.h
>   BPF (Safe dynamic programs and tools)
>   M:	Alexei Starovoitov <ast@kernel.org>
>   M:	Daniel Borkmann <daniel@iogearbox.net>
> +R:	Martin KaFai Lau <kafai@fb.com>
> +R:	Song Liu <songliubraving@fb.com>
> +R:	Yonghong Song <yhs@fb.com>
>   L:	netdev@vger.kernel.org
>   L:	linux-kernel@vger.kernel.org
>   T:	git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git
> @@ -2873,6 +2876,8 @@ F:	samples/bpf/
>   F:	tools/bpf/
>   F:	tools/lib/bpf/
>   F:	tools/testing/selftests/bpf/
> +K:	bpf
> +N:	bpf
>   
>   BPF JIT for ARM
>   M:	Shubham Bansal <illusionist.neo@gmail.com>
> 

^ permalink raw reply

* Re: [PATCH bpf] bpf, doc: add reviewers to maintainers entry
From: Song Liu @ 2019-01-29  3:08 UTC (permalink / raw)
  To: Daniel Borkmann
  Cc: Alexei Starovoitov, netdev@vger.kernel.org, Martin Lau,
	Yonghong Song
In-Reply-To: <20190128225526.5340-1-daniel@iogearbox.net>



> On Jan 28, 2019, at 2:55 PM, Daniel Borkmann <daniel@iogearbox.net> wrote:
> 
> In order to better scale BPF development on netdev, we've adopted a
> reviewer rotation for all BPF patches among the five of us for some
> time now. Lets give credit where credit is due, and add Martin, Song
> and Yonghong as official BPF reviewers to MAINTAINERS file. Also
> while at it, add regex matching for BPF such that we get properly
> Cc'ed for files not listed here.
> 
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>

Thanks!

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


> ---
> MAINTAINERS | 5 +++++
> 1 file changed, 5 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 51029a4..6e13378 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2848,6 +2848,9 @@ F:	include/uapi/linux/if_bonding.h
> BPF (Safe dynamic programs and tools)
> M:	Alexei Starovoitov <ast@kernel.org>
> M:	Daniel Borkmann <daniel@iogearbox.net>
> +R:	Martin KaFai Lau <kafai@fb.com>
> +R:	Song Liu <songliubraving@fb.com>
> +R:	Yonghong Song <yhs@fb.com>
> L:	netdev@vger.kernel.org
> L:	linux-kernel@vger.kernel.org
> T:	git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git
> @@ -2873,6 +2876,8 @@ F:	samples/bpf/
> F:	tools/bpf/
> F:	tools/lib/bpf/
> F:	tools/testing/selftests/bpf/
> +K:	bpf
> +N:	bpf
> 
> BPF JIT for ARM
> M:	Shubham Bansal <illusionist.neo@gmail.com>
> -- 
> 2.9.5
> 


^ permalink raw reply

* Re: [PATCH] bpf/core.c - silence warning messages
From: Song Liu @ 2019-01-29  3:12 UTC (permalink / raw)
  To: Valdis Kletnieks
  Cc: Alexei Starovoitov, Daniel Borkmann, Networking, open list
In-Reply-To: <9865.1548718516@turing-police.cc.vt.edu>

On Mon, Jan 28, 2019 at 3:35 PM <valdis.kletnieks@vt.edu> wrote:
>
> On Mon, 28 Jan 2019 09:18:45 -0800, Song Liu said:
> > On Sun, Jan 27, 2019 at 8:43 PM <valdis.kletnieks@vt.edu> wrote:
>
> > > The attached patch silences the warnings, because we *know* we're overwriting
> > > the default initializer. That leaves bpf/core.c with only 6 other warnings,
> > > which become more visible in comparison.
> >
> > My concern is that this will also mute the warning for other parts of
> > bpf/core.c.
>
> I checked and there weren't any warnings for other parts of the file.  Also, this message
> doesn't even happen unless you build with W=1, which apparently happens so rarely
> that nobody else has submitted a patch.
>
> Is there a high likelihood that another overwrite of an initializer is going to
> be included in the source?
>
> > Maybe we should move bpf_opcode_in_insntable() to a separate file, and mute
> > warning for that file?
>
> Seems to be overkill - the intent of this patch was mostly to make the *other*
> warnings issued with W=1 more noticable.

Yeah, I also felt this might be overkill while asking initially.

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

^ permalink raw reply

* Re: [PATCH 2/2] iwlwifi: Use struct_size() in kzalloc
From: YueHaibing @ 2019-01-29  3:13 UTC (permalink / raw)
  To: Joe Perches, johannes.berg, emmanuel.grumbach, luciano.coelho,
	linuxwifi, kvalo
  Cc: linux-kernel, netdev, linux-wireless
In-Reply-To: <9a66aa07870c729ad0e65ac26a2404fac879f290.camel@perches.com>


On 2019/1/29 5:57, Joe Perches wrote:
> On Mon, 2019-01-28 at 14:44 +0800, YueHaibing wrote:
>> Use struct_size() in kzalloc instead of the 'regd_to_copy'
> 
> There is also the use above that in the same function
> that could also be converted.
> 
> 	/* build a regdomain rule for every valid channel */
> 	size_of_regd =
> 		sizeof(struct ieee80211_regdomain) +
> 		num_of_ch * sizeof(struct ieee80211_reg_rule);
> 
> 	regd = kzalloc(size_of_regd, GFP_KERNEL);
> 	if (!regd)
> 		return ERR_PTR(-ENOMEM);

Thank you, will post v2.

> 
>> diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
> []
>> @@ -1093,7 +1093,7 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
>>  	const u8 *nvm_chan = cfg->nvm_type == IWL_NVM_EXT ?
>>  			     iwl_ext_nvm_channels : iwl_nvm_channels;
>>  	struct ieee80211_regdomain *regd, *copy_rd;
>> -	int size_of_regd, regd_to_copy;
>> +	int size_of_regd;
>>  	struct ieee80211_reg_rule *rule;
>>  	struct regdb_ptrs *regdb_ptrs;
>>  	enum nl80211_band band;
>> @@ -1193,10 +1193,8 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
>>  	 * Narrow down regdom for unused regulatory rules to prevent hole
>>  	 * between reg rules to wmm rules.
>>  	 */
>> -	regd_to_copy = sizeof(struct ieee80211_regdomain) +
>> -		valid_rules * sizeof(struct ieee80211_reg_rule);
>> -
>> -	copy_rd = kmemdup(regd, regd_to_copy, GFP_KERNEL);
>> +	copy_rd = kmemdup(regd, struct_size(regd, reg_rules, valid_rules),
>> +			  GFP_KERNEL);
>>  	if (!copy_rd)
>>  		copy_rd = ERR_PTR(-ENOMEM);
>>  
> 
> 
> .
> 


^ permalink raw reply

* [PATCH v2 0/2] cleanup for iwlwifi
From: YueHaibing @ 2019-01-29  3:21 UTC (permalink / raw)
  To: johannes.berg, emmanuel.grumbach, luciano.coelho, linuxwifi,
	kvalo
  Cc: linux-kernel, netdev, linux-wireless, YueHaibing

v2: Use struct_size in regd allocation

YueHaibing (2):
  iwlwifi: Use kmemdup instead of duplicating its function
  iwlwifi: Use struct_size() in kzalloc

 drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 19 ++++---------------
 1 file changed, 4 insertions(+), 15 deletions(-)

-- 
2.7.4



^ permalink raw reply

* [PATCH v2 1/2] iwlwifi: Use kmemdup instead of duplicating its function
From: YueHaibing @ 2019-01-29  3:21 UTC (permalink / raw)
  To: johannes.berg, emmanuel.grumbach, luciano.coelho, linuxwifi,
	kvalo
  Cc: linux-kernel, netdev, linux-wireless, YueHaibing
In-Reply-To: <20190129032144.18120-1-yuehaibing@huawei.com>

Use kmemdup rather than duplicating its implementation

Signed-off-by: YueHaibing <yuehaibing@huawei.com>
---
 drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index d9afedc..569cc50 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -1196,13 +1196,9 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
 	regd_to_copy = sizeof(struct ieee80211_regdomain) +
 		valid_rules * sizeof(struct ieee80211_reg_rule);
 
-	copy_rd = kzalloc(regd_to_copy, GFP_KERNEL);
-	if (!copy_rd) {
+	copy_rd = kmemdup(regd, regd_to_copy, GFP_KERNEL);
+	if (!copy_rd)
 		copy_rd = ERR_PTR(-ENOMEM);
-		goto out;
-	}
-
-	memcpy(copy_rd, regd, regd_to_copy);
 
 out:
 	kfree(regdb_ptrs);
-- 
2.7.4



^ permalink raw reply related

* [PATCH v2 2/2] iwlwifi: Use struct_size() in kzalloc
From: YueHaibing @ 2019-01-29  3:21 UTC (permalink / raw)
  To: johannes.berg, emmanuel.grumbach, luciano.coelho, linuxwifi,
	kvalo
  Cc: linux-kernel, netdev, linux-wireless, YueHaibing
In-Reply-To: <20190129032144.18120-1-yuehaibing@huawei.com>

Use struct_size() in kzalloc instead of the 'regd_to_copy'

Signed-off-by: YueHaibing <yuehaibing@huawei.com>
---
 drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 569cc50..2b87c7c 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -1093,7 +1093,6 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
 	const u8 *nvm_chan = cfg->nvm_type == IWL_NVM_EXT ?
 			     iwl_ext_nvm_channels : iwl_nvm_channels;
 	struct ieee80211_regdomain *regd, *copy_rd;
-	int size_of_regd, regd_to_copy;
 	struct ieee80211_reg_rule *rule;
 	struct regdb_ptrs *regdb_ptrs;
 	enum nl80211_band band;
@@ -1113,11 +1112,7 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
 		      num_of_ch);
 
 	/* build a regdomain rule for every valid channel */
-	size_of_regd =
-		sizeof(struct ieee80211_regdomain) +
-		num_of_ch * sizeof(struct ieee80211_reg_rule);
-
-	regd = kzalloc(size_of_regd, GFP_KERNEL);
+	regd = kzalloc(struct_size(regd, reg_rules, num_of_ch), GFP_KERNEL);
 	if (!regd)
 		return ERR_PTR(-ENOMEM);
 
@@ -1193,10 +1188,8 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
 	 * Narrow down regdom for unused regulatory rules to prevent hole
 	 * between reg rules to wmm rules.
 	 */
-	regd_to_copy = sizeof(struct ieee80211_regdomain) +
-		valid_rules * sizeof(struct ieee80211_reg_rule);
-
-	copy_rd = kmemdup(regd, regd_to_copy, GFP_KERNEL);
+	copy_rd = kmemdup(regd, struct_size(regd, reg_rules, valid_rules),
+			  GFP_KERNEL);
 	if (!copy_rd)
 		copy_rd = ERR_PTR(-ENOMEM);
 
-- 
2.7.4



^ permalink raw reply related

* Re: [PATCH net-next] mdio_bus: Fix PTR_ERR() usage after initialization to constant
From: YueHaibing @ 2019-01-29  3:30 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: davem, f.fainelli, hkallweit1, linux-kernel, netdev
In-Reply-To: <20190128143634.GF4765@lunn.ch>


On 2019/1/28 22:36, Andrew Lunn wrote:
> On Mon, Jan 28, 2019 at 09:24:09PM +0800, YueHaibing wrote:
>> Fix coccinelle warning:
>>
>> ./drivers/net/phy/mdio_bus.c:51:5-12: ERROR: PTR_ERR applied after initialization to constant on line 44
>> ./drivers/net/phy/mdio_bus.c:52:5-12: ERROR: PTR_ERR applied after initialization to constant on line 44
>>
>> fix this by using IS_ERR before PTR_ERR
>>
>> Fixes: bafbdd527d56 ("phylib: Add device reset GPIO support")
>> Signed-off-by: YueHaibing <yuehaibing@huawei.com>
>> ---
>>  drivers/net/phy/mdio_bus.c | 13 ++++++++-----
>>  1 file changed, 8 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
>> index 3d31358..802716a 100644
>> --- a/drivers/net/phy/mdio_bus.c
>> +++ b/drivers/net/phy/mdio_bus.c
>> @@ -42,17 +42,20 @@
>>  static int mdiobus_register_gpiod(struct mdio_device *mdiodev)
>>  {
>>  	struct gpio_desc *gpiod = NULL;
>> +	int ret;
>>  
> 
> Hi YueHaibing
> 
> I think i prefer the simpler fix:
> 
>  static int mdiobus_register_gpiod(struct mdio_device *mdiodev)
>  {
> -  	struct gpio_desc *gpiod = NULL;
> +       struct gpio_desc *gpiod = ERR_PTR(-ENOENT);
> 

But a56c69803f5a ("net: phy: Handle not having GPIO enabled in the kernel")
add a new check:

@@ -56,7 +56,8 @@ static int mdiobus_register_gpiod(struct mdio_device *mdiodev)
                gpiod = fwnode_get_named_gpiod(&mdiodev->dev.of_node->fwnode,
                                               "reset-gpios", 0, GPIOD_OUT_LOW,
                                               "PHY reset");
-       if (PTR_ERR(gpiod) == -ENOENT)
+       if (PTR_ERR(gpiod) == -ENOENT ||
+           PTR_ERR(gpiod) == -ENOSYS)
                gpiod = NULL;
        else if (IS_ERR(gpiod))
                return PTR_ERR(gpiod);


> Totally untested...
> 
> 	Andrew
> 
>>  	/* Deassert the optional reset signal */
>>  	if (mdiodev->dev.of_node)
>>  		gpiod = fwnode_get_named_gpiod(&mdiodev->dev.of_node->fwnode,
>>  					       "reset-gpios", 0, GPIOD_OUT_LOW,
>>  					       "PHY reset");
>> -	if (PTR_ERR(gpiod) == -ENOENT ||
>> -	    PTR_ERR(gpiod) == -ENOSYS)
>> -		gpiod = NULL;
>> -	else if (IS_ERR(gpiod))
>> -		return PTR_ERR(gpiod);
>> +	if (IS_ERR(gpiod)) {
>> +		ret = PTR_ERR(gpiod);
>> +		if (ret == -ENOENT || ret == -ENOSYS)
>> +			gpiod = NULL;
>> +		else
>> +			return ret;
>> +	}
>>  
>>  	mdiodev->reset = gpiod;
>>  
>> -- 
>> 2.7.4
>>
>>
> 
> .
> 


^ permalink raw reply

* [PATCH net-next 0/7] devlink: add device (driver) information API
From: Jakub Kicinski @ 2019-01-29  3:34 UTC (permalink / raw)
  To: davem
  Cc: netdev, oss-drivers, jiri, andrew, f.fainelli, mkubecek, eugenem,
	jonathan.lemon, Jakub Kicinski

Hi!

fw_version field in ethtool -i does not suit modern needs with 31
characters being quite limiting on more complex systems.  There is
also no distinction between the running and flashed versions of
the firmware.

Since the driver information pertains to the entire device, rather
than a particular netdev, it seems wise to move it do devlink, at
the same time fixing the aforementioned issues.

The new API allows exposing the device serial number and versions
of the components of the card - both hardware, firmware (running
and flashed).  Driver authors can choose descriptive identifiers
for the version fields.  A few version identifiers which seemed
relevant for most devices have been added to the global devlink
header.

Example:
$ devlink dev info pci/0000:05:00.0
pci/0000:05:00.0:
  driver nfp
  serial_number 16240145
  versions:
    fixed:
      board.id AMDA0099-0001
      board.rev 07
      board.vendor SMA
      board.model carbon
    running:
      fw.mgmt: 010156.010156.010156
      fw.cpld: 0x44
      fw.app: sriov-2.1.16
    stored:
      fw.mgmt: 010158.010158.010158
      fw.cpld: 0x44
      fw.app: sriov-2.1.20

Last patch also includes a compat code for ethtool.  If driver
reports no fw_version via the traditional ethtool API, ethtool
can call into devlink and try to cram as many versions as possible
into the 31 characters.

this non-RFC, v3 some would say:
 - add three more versions in the NFP patches;
 - add last patch (ethool compat) - Andrew & Michal.

RFCv2:
 - use one driver op;
 - allow longer serial number;
 - wrap the skb into an opaque request struct;
 - add some common identifier into the devlink header.

Jakub Kicinski (7):
  devlink: add device information API
  devlink: add version reporting to devlink info API
  nfp: devlink: report driver name and serial number
  nfp: devlink: report fixed versions
  nfp: nsp: add support for versions command
  nfp: devlink: report the running and flashed versions
  ethtool: add compat for devlink info

 .../net/ethernet/netronome/nfp/nfp_devlink.c  | 145 +++++++++++++
 .../ethernet/netronome/nfp/nfpcore/nfp_nsp.c  |  61 ++++++
 .../ethernet/netronome/nfp/nfpcore/nfp_nsp.h  |  20 ++
 include/net/devlink.h                         |  59 +++++
 include/uapi/linux/devlink.h                  |  10 +
 net/core/devlink.c                            | 204 ++++++++++++++++++
 net/core/ethtool.c                            |   7 +
 7 files changed, 506 insertions(+)

-- 
2.19.2


^ permalink raw reply

* [PATCH net-next 1/7] devlink: add device information API
From: Jakub Kicinski @ 2019-01-29  3:34 UTC (permalink / raw)
  To: davem
  Cc: netdev, oss-drivers, jiri, andrew, f.fainelli, mkubecek, eugenem,
	jonathan.lemon, Jakub Kicinski
In-Reply-To: <20190129033420.27235-1-jakub.kicinski@netronome.com>

ethtool -i has served us well for a long time, but its showing
its limitations more and more.  The device information should
also be reported per device not per-netdev.

Lay foundation for a simple devlink-based way of reading device
info.  Add driver name and device serial number as initial pieces
of information exposed via this new API.

RFC v2:
 - wrap the skb into an opaque structure (Jiri);
 - allow the serial number of be any length (Jiri & Andrew);
 - add driver name (Jonathan).

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 include/net/devlink.h        |  18 ++++++
 include/uapi/linux/devlink.h |   5 ++
 net/core/devlink.c           | 114 +++++++++++++++++++++++++++++++++++
 3 files changed, 137 insertions(+)

diff --git a/include/net/devlink.h b/include/net/devlink.h
index 67f4293bc970..d8d425028d55 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -420,6 +420,7 @@ enum devlink_param_generic_id {
 }
 
 struct devlink_region;
+struct devlink_info_req;
 
 typedef void devlink_snapshot_data_dest_t(const void *data);
 
@@ -475,6 +476,8 @@ struct devlink_ops {
 	int (*eswitch_encap_mode_get)(struct devlink *devlink, u8 *p_encap_mode);
 	int (*eswitch_encap_mode_set)(struct devlink *devlink, u8 encap_mode,
 				      struct netlink_ext_ack *extack);
+	int (*info_get)(struct devlink *devlink, struct devlink_info_req *req,
+			struct netlink_ext_ack *extack);
 };
 
 static inline void *devlink_priv(struct devlink *devlink)
@@ -583,6 +586,10 @@ u32 devlink_region_shapshot_id_get(struct devlink *devlink);
 int devlink_region_snapshot_create(struct devlink_region *region, u64 data_len,
 				   u8 *data, u32 snapshot_id,
 				   devlink_snapshot_data_dest_t *data_destructor);
+int devlink_info_report_serial_number(struct devlink_info_req *req,
+				      const char *sn);
+int devlink_info_report_driver_name(struct devlink_info_req *req,
+				    const char *name);
 
 #else
 
@@ -844,6 +851,17 @@ devlink_region_snapshot_create(struct devlink_region *region, u64 data_len,
 	return 0;
 }
 
+static inline int
+devlink_info_report_driver_name(struct devlink_info_req *req, const char *name)
+{
+	return 0;
+}
+
+static inline int
+devlink_info_report_serial_number(struct devlink_info_req *req, const char *sn)
+{
+	return 0;
+}
 #endif
 
 #endif /* _NET_DEVLINK_H_ */
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 6e52d3660654..c4b5d923f59f 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -89,6 +89,8 @@ enum devlink_command {
 	DEVLINK_CMD_REGION_DEL,
 	DEVLINK_CMD_REGION_READ,
 
+	DEVLINK_CMD_INFO_GET,
+
 	/* add new commands above here */
 	__DEVLINK_CMD_MAX,
 	DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
@@ -285,6 +287,9 @@ enum devlink_attr {
 	DEVLINK_ATTR_REGION_CHUNK_ADDR,         /* u64 */
 	DEVLINK_ATTR_REGION_CHUNK_LEN,          /* u64 */
 
+	DEVLINK_ATTR_INFO_DRV_NAME,		/* string */
+	DEVLINK_ATTR_INFO_SERIAL_NUMBER,	/* string */
+
 	/* add new attributes above here, update the policy in devlink.c */
 
 	__DEVLINK_ATTR_MAX,
diff --git a/net/core/devlink.c b/net/core/devlink.c
index abb0da9d7b4b..844e086ff038 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -3597,6 +3597,112 @@ static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
 	return 0;
 }
 
+struct devlink_info_req {
+	struct sk_buff *msg;
+};
+
+int devlink_info_report_driver_name(struct devlink_info_req *req,
+				    const char *name)
+{
+	return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRV_NAME, name);
+}
+EXPORT_SYMBOL_GPL(devlink_info_report_driver_name);
+
+int devlink_info_report_serial_number(struct devlink_info_req *req,
+				      const char *sn)
+{
+	return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
+}
+EXPORT_SYMBOL_GPL(devlink_info_report_serial_number);
+
+static int
+devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
+		     enum devlink_command cmd, u32 portid,
+		     u32 seq, int flags, struct netlink_ext_ack *extack)
+{
+	struct devlink_info_req req;
+	void *hdr;
+	int err;
+
+	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	err = -EMSGSIZE;
+	if (devlink_nl_put_handle(msg, devlink))
+		goto err_cancel_msg;
+
+	req.msg = msg;
+	err = devlink->ops->info_get(devlink, &req, extack);
+	if (err)
+		goto err_cancel_msg;
+
+	genlmsg_end(msg, hdr);
+	return 0;
+
+err_cancel_msg:
+	genlmsg_cancel(msg, hdr);
+	return err;
+}
+
+static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
+					struct genl_info *info)
+{
+	struct devlink *devlink = info->user_ptr[0];
+	struct sk_buff *msg;
+	int err;
+
+	if (!devlink->ops || !devlink->ops->info_get)
+		return -EOPNOTSUPP;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
+				   info->snd_portid, info->snd_seq, 0,
+				   info->extack);
+	if (err) {
+		nlmsg_free(msg);
+		return err;
+	}
+
+	return genlmsg_reply(msg, info);
+}
+
+static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
+					  struct netlink_callback *cb)
+{
+	struct devlink *devlink;
+	int start = cb->args[0];
+	int idx = 0;
+	int err;
+
+	mutex_lock(&devlink_mutex);
+	list_for_each_entry(devlink, &devlink_list, list) {
+		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
+			continue;
+		if (idx < start) {
+			idx++;
+			continue;
+		}
+
+		mutex_lock(&devlink->lock);
+		err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
+					   NETLINK_CB(cb->skb).portid,
+					   cb->nlh->nlmsg_seq, NLM_F_MULTI,
+					   cb->extack);
+		mutex_unlock(&devlink->lock);
+		if (err)
+			break;
+		idx++;
+	}
+	mutex_unlock(&devlink_mutex);
+
+	cb->args[0] = idx;
+	return msg->len;
+}
+
 static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
 	[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
 	[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
@@ -3842,6 +3948,14 @@ static const struct genl_ops devlink_nl_ops[] = {
 		.flags = GENL_ADMIN_PERM,
 		.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
 	},
+	{
+		.cmd = DEVLINK_CMD_INFO_GET,
+		.doit = devlink_nl_cmd_info_get_doit,
+		.dumpit = devlink_nl_cmd_info_get_dumpit,
+		.policy = devlink_nl_policy,
+		.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
+		/* can be retrieved by unprivileged users */
+	},
 };
 
 static struct genl_family devlink_nl_family __ro_after_init = {
-- 
2.19.2


^ permalink raw reply related

* [PATCH net-next 2/7] devlink: add version reporting to devlink info API
From: Jakub Kicinski @ 2019-01-29  3:34 UTC (permalink / raw)
  To: davem
  Cc: netdev, oss-drivers, jiri, andrew, f.fainelli, mkubecek, eugenem,
	jonathan.lemon, Jakub Kicinski
In-Reply-To: <20190129033420.27235-1-jakub.kicinski@netronome.com>

ethtool -i has a few fixed-size fields which can be used to report
firmware version and expansion ROM version.  Unfortunately, modern
hardware has more firmware components.  There is usually some
datapath microcode, management controller, PXE drivers, and a
CPLD load.  Running ethtool -i on modern controllers reveals the
fact that vendors cram multiple values into firmware version field.

Here are some examples from systems I could lay my hands on quickly:

tg3:  "FFV20.2.17 bc 5720-v1.39"
i40e: "6.01 0x800034a4 1.1747.0"
nfp:  "0.0.3.5 0.25 sriov-2.1.16 nic"

Add a new devlink API to allow retrieving multiple versions, and
provide user-readable name for those versions.

While at it break down the versions into three categories:
 - fixed - this is the board/fixed component version, usually vendors
           report information like the board version in the PCI VPD,
           but it will benefit from naming and common API as well;
 - running - this is the running firmware version;
 - stored - this is firmware in the flash, after firmware update
            this value will reflect the flashed version, while the
            running version may only be updated after reboot.

RFCv2:
 - remove the nesting in attr DEVLINK_ATTR_INFO_VERSIONS (now
   versions are mixed with other info attrs)l
 - have the driver report versions from the same callback as
   other info.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 include/net/devlink.h        | 18 ++++++++++++++++
 include/uapi/linux/devlink.h |  5 +++++
 net/core/devlink.c           | 40 ++++++++++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+)

diff --git a/include/net/devlink.h b/include/net/devlink.h
index d8d425028d55..f53ace3ac4b3 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -419,6 +419,12 @@ enum devlink_param_generic_id {
 	.validate = _validate,						\
 }
 
+enum devlink_version_type {
+	DEVLINK_VERSION_FIXED,
+	DEVLINK_VERSION_STORED,
+	DEVLINK_VERSION_RUNNING,
+};
+
 struct devlink_region;
 struct devlink_info_req;
 
@@ -590,6 +596,10 @@ int devlink_info_report_serial_number(struct devlink_info_req *req,
 				      const char *sn);
 int devlink_info_report_driver_name(struct devlink_info_req *req,
 				    const char *name);
+int devlink_info_report_version(struct devlink_info_req *req,
+				enum devlink_version_type type,
+				const char *version_name,
+				const char *version_value);
 
 #else
 
@@ -862,6 +872,14 @@ devlink_info_report_serial_number(struct devlink_info_req *req, const char *sn)
 {
 	return 0;
 }
+
+static inline int
+devlink_info_report_version(struct devlink_info_req *req,
+			    enum devlink_version_type type,
+			    const char *version_name, const char *version_value)
+{
+	return 0;
+}
 #endif
 
 #endif /* _NET_DEVLINK_H_ */
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index c4b5d923f59f..e8d449a203ec 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -289,6 +289,11 @@ enum devlink_attr {
 
 	DEVLINK_ATTR_INFO_DRV_NAME,		/* string */
 	DEVLINK_ATTR_INFO_SERIAL_NUMBER,	/* string */
+	DEVLINK_ATTR_INFO_VERSION_FIXED,	/* nested */
+	DEVLINK_ATTR_INFO_VERSION_RUNNING,	/* nested */
+	DEVLINK_ATTR_INFO_VERSION_STORED,	/* nested */
+	DEVLINK_ATTR_INFO_VERSION_NAME,		/* string */
+	DEVLINK_ATTR_INFO_VERSION_VALUE,	/* string */
 
 	/* add new attributes above here, update the policy in devlink.c */
 
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 844e086ff038..f0c5f9bd96b7 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -3615,6 +3615,46 @@ int devlink_info_report_serial_number(struct devlink_info_req *req,
 }
 EXPORT_SYMBOL_GPL(devlink_info_report_serial_number);
 
+int devlink_info_report_version(struct devlink_info_req *req,
+				enum devlink_version_type type,
+				const char *version_name,
+				const char *version_value)
+{
+	static const enum devlink_attr type2attr[] = {
+		[DEVLINK_VERSION_FIXED] = DEVLINK_ATTR_INFO_VERSION_FIXED,
+		[DEVLINK_VERSION_STORED] = DEVLINK_ATTR_INFO_VERSION_STORED,
+		[DEVLINK_VERSION_RUNNING] = DEVLINK_ATTR_INFO_VERSION_RUNNING,
+	};
+	struct nlattr *nest;
+	int err;
+
+	if (type >= ARRAY_SIZE(type2attr) || !type2attr[type])
+		return -EINVAL;
+
+	nest = nla_nest_start(req->msg, type2attr[type]);
+	if (!nest)
+		return -EMSGSIZE;
+
+	err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
+			     version_name);
+	if (err)
+		goto nla_put_failure;
+
+	err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
+			     version_value);
+	if (err)
+		goto nla_put_failure;
+
+	nla_nest_end(req->msg, nest);
+
+	return 0;
+
+nla_put_failure:
+	nla_nest_cancel(req->msg, nest);
+	return err;
+}
+EXPORT_SYMBOL_GPL(devlink_info_report_version);
+
 static int
 devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
 		     enum devlink_command cmd, u32 portid,
-- 
2.19.2


^ permalink raw reply related

* [PATCH net-next 3/7] nfp: devlink: report driver name and serial number
From: Jakub Kicinski @ 2019-01-29  3:34 UTC (permalink / raw)
  To: davem
  Cc: netdev, oss-drivers, jiri, andrew, f.fainelli, mkubecek, eugenem,
	jonathan.lemon, Jakub Kicinski
In-Reply-To: <20190129033420.27235-1-jakub.kicinski@netronome.com>

Report the basic info through new devlink info API.

RFCv2:
 - add driver name;
 - align serial to core changes.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 .../net/ethernet/netronome/nfp/nfp_devlink.c  | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
index 808647ec3573..cb3ef7e46614 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
@@ -4,6 +4,7 @@
 #include <linux/rtnetlink.h>
 #include <net/devlink.h>
 
+#include "nfpcore/nfp.h"
 #include "nfpcore/nfp_nsp.h"
 #include "nfp_app.h"
 #include "nfp_main.h"
@@ -171,6 +172,28 @@ static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
 	return ret;
 }
 
+static int
+nfp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
+		     struct netlink_ext_ack *extack)
+{
+	struct nfp_pf *pf = devlink_priv(devlink);
+	const char *sn;
+	int err;
+
+	err = devlink_info_report_driver_name(req, "nfp");
+	if (err)
+		return err;
+
+	sn = nfp_hwinfo_lookup(pf->hwinfo, "assembly.serial");
+	if (sn) {
+		err = devlink_info_report_serial_number(req, sn);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 const struct devlink_ops nfp_devlink_ops = {
 	.port_split		= nfp_devlink_port_split,
 	.port_unsplit		= nfp_devlink_port_unsplit,
@@ -178,6 +201,7 @@ const struct devlink_ops nfp_devlink_ops = {
 	.sb_pool_set		= nfp_devlink_sb_pool_set,
 	.eswitch_mode_get	= nfp_devlink_eswitch_mode_get,
 	.eswitch_mode_set	= nfp_devlink_eswitch_mode_set,
+	.info_get		= nfp_devlink_info_get,
 };
 
 int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)
-- 
2.19.2


^ permalink raw reply related

* [PATCH net-next 4/7] nfp: devlink: report fixed versions
From: Jakub Kicinski @ 2019-01-29  3:34 UTC (permalink / raw)
  To: davem
  Cc: netdev, oss-drivers, jiri, andrew, f.fainelli, mkubecek, eugenem,
	jonathan.lemon, Jakub Kicinski
In-Reply-To: <20190129033420.27235-1-jakub.kicinski@netronome.com>

Report information about the hardware.

RFCv2:
 - add defines for board IDs which are likely to be reusable for
   other drivers (Jiri).

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 .../net/ethernet/netronome/nfp/nfp_devlink.c  | 37 ++++++++++++++++++-
 include/net/devlink.h                         |  5 +++
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
index cb3ef7e46614..9857fa663adf 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
@@ -172,6 +172,41 @@ static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
 	return ret;
 }
 
+static const struct nfp_devlink_versions_simple {
+	const char *key;
+	const char *hwinfo;
+} nfp_devlink_versions_hwinfo[] = {
+	{ DEVLINK_VERSION_GENERIC_BOARD_ID,	"assembly.partno", },
+	{ DEVLINK_VERSION_GENERIC_BOARD_REV,	"assembly.revision", },
+	{ "board.vendor", /* fab */		"assembly.vendor", },
+	{ "board.model", /* code name */	"assembly.model", },
+};
+
+static int
+nfp_devlink_versions_get_hwinfo(struct nfp_pf *pf, struct devlink_info_req *req)
+{
+	unsigned int i;
+	int err;
+
+	for (i = 0; i < ARRAY_SIZE(nfp_devlink_versions_hwinfo); i++) {
+		const struct nfp_devlink_versions_simple *info;
+		const char *val;
+
+		info = &nfp_devlink_versions_hwinfo[i];
+
+		val = nfp_hwinfo_lookup(pf->hwinfo, info->hwinfo);
+		if (!val)
+			continue;
+
+		err = devlink_info_report_version(req, DEVLINK_VERSION_FIXED,
+						  info->key, val);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 static int
 nfp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
 		     struct netlink_ext_ack *extack)
@@ -191,7 +226,7 @@ nfp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
 			return err;
 	}
 
-	return 0;
+	return nfp_devlink_versions_get_hwinfo(pf, req);
 }
 
 const struct devlink_ops nfp_devlink_ops = {
diff --git a/include/net/devlink.h b/include/net/devlink.h
index f53ace3ac4b3..dc08301028a9 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -419,6 +419,11 @@ enum devlink_param_generic_id {
 	.validate = _validate,						\
 }
 
+/* Part number, identifier of board design */
+#define DEVLINK_VERSION_GENERIC_BOARD_ID	"board.id"
+/* Revision of board design */
+#define DEVLINK_VERSION_GENERIC_BOARD_REV	"board.rev"
+
 enum devlink_version_type {
 	DEVLINK_VERSION_FIXED,
 	DEVLINK_VERSION_STORED,
-- 
2.19.2


^ permalink raw reply related

* [PATCH net-next 5/7] nfp: nsp: add support for versions command
From: Jakub Kicinski @ 2019-01-29  3:34 UTC (permalink / raw)
  To: davem
  Cc: netdev, oss-drivers, jiri, andrew, f.fainelli, mkubecek, eugenem,
	jonathan.lemon, Jakub Kicinski
In-Reply-To: <20190129033420.27235-1-jakub.kicinski@netronome.com>

Retrieve the FW versions with the new command.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 .../ethernet/netronome/nfp/nfpcore/nfp_nsp.c  | 61 +++++++++++++++++++
 .../ethernet/netronome/nfp/nfpcore/nfp_nsp.h  | 20 ++++++
 2 files changed, 81 insertions(+)

diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
index ce1577bbbd2a..a9d53df0070c 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
@@ -7,6 +7,7 @@
  *         Jason McMullan <jason.mcmullan@netronome.com>
  */
 
+#include <asm/unaligned.h>
 #include <linux/bitfield.h>
 #include <linux/delay.h>
 #include <linux/firmware.h>
@@ -62,6 +63,16 @@
 
 #define NFP_HWINFO_LOOKUP_SIZE	GENMASK(11, 0)
 
+#define NFP_VERSIONS_SIZE	GENMASK(11, 0)
+#define NFP_VERSIONS_CNT_OFF	0
+#define NFP_VERSIONS_BSP_OFF	2
+#define NFP_VERSIONS_CPLD_OFF	6
+#define NFP_VERSIONS_APP_OFF	10
+#define NFP_VERSIONS_BUNDLE_OFF	14
+#define NFP_VERSIONS_UNDI_OFF	18
+#define NFP_VERSIONS_NCSI_OFF	22
+#define NFP_VERSIONS_CFGR_OFF	26
+
 enum nfp_nsp_cmd {
 	SPCODE_NOOP		= 0, /* No operation */
 	SPCODE_SOFT_RESET	= 1, /* Soft reset the NFP */
@@ -77,6 +88,7 @@ enum nfp_nsp_cmd {
 	SPCODE_NSP_IDENTIFY	= 13, /* Read NSP version */
 	SPCODE_FW_STORED	= 16, /* If no FW loaded, load flash app FW */
 	SPCODE_HWINFO_LOOKUP	= 17, /* Lookup HWinfo with overwrites etc. */
+	SPCODE_VERSIONS		= 21, /* Report FW versions */
 };
 
 static const struct {
@@ -711,3 +723,52 @@ int nfp_nsp_hwinfo_lookup(struct nfp_nsp *state, void *buf, unsigned int size)
 
 	return 0;
 }
+
+int nfp_nsp_versions(struct nfp_nsp *state, void *buf, unsigned int size)
+{
+	struct nfp_nsp_command_buf_arg versions = {
+		{
+			.code		= SPCODE_VERSIONS,
+			.option		= min_t(u32, size, NFP_VERSIONS_SIZE),
+		},
+		.out_buf	= buf,
+		.out_size	= min_t(u32, size, NFP_VERSIONS_SIZE),
+	};
+
+	return nfp_nsp_command_buf(state, &versions);
+}
+
+const char *nfp_nsp_versions_get(enum nfp_nsp_versions id, bool flash,
+				 const u8 *buf, unsigned int size)
+{
+	static const u32 id2off[] = {
+		[NFP_VERSIONS_BSP] =	NFP_VERSIONS_BSP_OFF,
+		[NFP_VERSIONS_CPLD] =	NFP_VERSIONS_CPLD_OFF,
+		[NFP_VERSIONS_APP] =	NFP_VERSIONS_APP_OFF,
+		[NFP_VERSIONS_BUNDLE] =	NFP_VERSIONS_BUNDLE_OFF,
+		[NFP_VERSIONS_UNDI] =	NFP_VERSIONS_UNDI_OFF,
+		[NFP_VERSIONS_NCSI] =	NFP_VERSIONS_NCSI_OFF,
+		[NFP_VERSIONS_CFGR] =	NFP_VERSIONS_CFGR_OFF,
+	};
+	unsigned int field, buf_field_cnt, buf_off;
+
+	if (id >= ARRAY_SIZE(id2off) || !id2off[id])
+		return ERR_PTR(-EINVAL);
+
+	field = id * 2 + flash;
+
+	buf_field_cnt = get_unaligned_le16(buf);
+	if (buf_field_cnt <= field)
+		return ERR_PTR(-ENOENT);
+
+	buf_off = get_unaligned_le16(buf + id2off[id] + flash * 2);
+	if (!buf_off)
+		return ERR_PTR(-ENOENT);
+
+	if (buf_off >= size)
+		return ERR_PTR(-EINVAL);
+	if (strnlen(&buf[buf_off], size - buf_off) == size - buf_off)
+		return ERR_PTR(-EINVAL);
+
+	return (const char *)&buf[buf_off];
+}
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
index ff33ac54097a..246e213f1514 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
@@ -38,6 +38,11 @@ static inline bool nfp_nsp_has_hwinfo_lookup(struct nfp_nsp *state)
 	return nfp_nsp_get_abi_ver_minor(state) > 24;
 }
 
+static inline bool nfp_nsp_has_versions(struct nfp_nsp *state)
+{
+	return nfp_nsp_get_abi_ver_minor(state) > 27;
+}
+
 enum nfp_eth_interface {
 	NFP_INTERFACE_NONE	= 0,
 	NFP_INTERFACE_SFP	= 1,
@@ -208,4 +213,19 @@ enum nfp_nsp_sensor_id {
 int nfp_hwmon_read_sensor(struct nfp_cpp *cpp, enum nfp_nsp_sensor_id id,
 			  long *val);
 
+#define NFP_NSP_VERSION_BUFSZ	1024 /* reasonable size, not in the ABI */
+
+enum nfp_nsp_versions {
+	NFP_VERSIONS_BSP,
+	NFP_VERSIONS_CPLD,
+	NFP_VERSIONS_APP,
+	NFP_VERSIONS_BUNDLE,
+	NFP_VERSIONS_UNDI,
+	NFP_VERSIONS_NCSI,
+	NFP_VERSIONS_CFGR,
+};
+
+int nfp_nsp_versions(struct nfp_nsp *state, void *buf, unsigned int size);
+const char *nfp_nsp_versions_get(enum nfp_nsp_versions id, bool flash,
+				 const u8 *buf, unsigned int size);
 #endif
-- 
2.19.2


^ permalink raw reply related

* [PATCH net-next 6/7] nfp: devlink: report the running and flashed versions
From: Jakub Kicinski @ 2019-01-29  3:34 UTC (permalink / raw)
  To: davem
  Cc: netdev, oss-drivers, jiri, andrew, f.fainelli, mkubecek, eugenem,
	jonathan.lemon, Jakub Kicinski
In-Reply-To: <20190129033420.27235-1-jakub.kicinski@netronome.com>

Report versions of firmware components using the new NSP command.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 .../net/ethernet/netronome/nfp/nfp_devlink.c  | 86 +++++++++++++++++++
 include/net/devlink.h                         | 11 +++
 2 files changed, 97 insertions(+)

diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
index 9857fa663adf..fade37d2b796 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
@@ -207,11 +207,59 @@ nfp_devlink_versions_get_hwinfo(struct nfp_pf *pf, struct devlink_info_req *req)
 	return 0;
 }
 
+static const struct nfp_devlink_versions {
+	enum nfp_nsp_versions id;
+	const char *key;
+} nfp_devlink_versions_nsp[] = {
+	{ NFP_VERSIONS_BUNDLE,	"fw.bundle_id", },
+	{ NFP_VERSIONS_BSP,	DEVLINK_VERSION_GENERIC_FW_MGMT, },
+	{ NFP_VERSIONS_CPLD,	"fw.cpld", },
+	{ NFP_VERSIONS_APP,	DEVLINK_VERSION_GENERIC_FW_APP, },
+	{ NFP_VERSIONS_UNDI,	DEVLINK_VERSION_GENERIC_FW_UNDI, },
+	{ NFP_VERSIONS_NCSI,	DEVLINK_VERSION_GENERIC_FW_NCSI, },
+	{ NFP_VERSIONS_CFGR,	"chip.init", },
+};
+
+static int
+nfp_devlink_versions_get_nsp(struct devlink_info_req *req, bool flash,
+			     const u8 *buf, unsigned int size)
+{
+	enum devlink_version_type type;
+	unsigned int i;
+	int err;
+
+	type = flash ? DEVLINK_VERSION_STORED : DEVLINK_VERSION_RUNNING;
+
+	for (i = 0; i < ARRAY_SIZE(nfp_devlink_versions_nsp); i++) {
+		const struct nfp_devlink_versions *info;
+		const char *version;
+
+		info = &nfp_devlink_versions_nsp[i];
+
+		version = nfp_nsp_versions_get(info->id, flash, buf, size);
+		if (IS_ERR(version)) {
+			if (PTR_ERR(version) == -ENOENT)
+				continue;
+			else
+				return PTR_ERR(version);
+		}
+
+		err = devlink_info_report_version(req, type,
+						  info->key, version);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 static int
 nfp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
 		     struct netlink_ext_ack *extack)
 {
 	struct nfp_pf *pf = devlink_priv(devlink);
+	struct nfp_nsp *nsp;
+	char *buf = NULL;
 	const char *sn;
 	int err;
 
@@ -226,7 +274,45 @@ nfp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
 			return err;
 	}
 
+	nsp = nfp_nsp_open(pf->cpp);
+	if (IS_ERR(nsp)) {
+		NL_SET_ERR_MSG_MOD(extack, "can't access NSP");
+		return PTR_ERR(nsp);
+	}
+
+	if (nfp_nsp_has_versions(nsp)) {
+		buf = kzalloc(NFP_NSP_VERSION_BUFSZ, GFP_KERNEL);
+		if (!buf) {
+			err = -ENOMEM;
+			goto err_close_nsp;
+		}
+
+		err = nfp_nsp_versions(nsp, buf, NFP_NSP_VERSION_BUFSZ);
+		if (err)
+			goto err_free_buf;
+
+		err = nfp_devlink_versions_get_nsp(req, false,
+						   buf, NFP_NSP_VERSION_BUFSZ);
+		if (err)
+			goto err_free_buf;
+
+		err = nfp_devlink_versions_get_nsp(req, true,
+						   buf, NFP_NSP_VERSION_BUFSZ);
+		if (err)
+			goto err_free_buf;
+
+		kfree(buf);
+	}
+
+	nfp_nsp_close(nsp);
+
 	return nfp_devlink_versions_get_hwinfo(pf, req);
+
+err_free_buf:
+	kfree(buf);
+err_close_nsp:
+	nfp_nsp_close(nsp);
+	return err;
 }
 
 const struct devlink_ops nfp_devlink_ops = {
diff --git a/include/net/devlink.h b/include/net/devlink.h
index dc08301028a9..14da3632e8fc 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -424,6 +424,17 @@ enum devlink_param_generic_id {
 /* Revision of board design */
 #define DEVLINK_VERSION_GENERIC_BOARD_REV	"board.rev"
 
+/* Control processor FW version, FW is responsible for house keeping tasks,
+ * PHY control etc.
+ */
+#define DEVLINK_VERSION_GENERIC_FW_MGMT		"fw.mgmt"
+/* Data path microcode controlling high-speed packet processing */
+#define DEVLINK_VERSION_GENERIC_FW_APP		"fw.app"
+/* UNDI software version */
+#define DEVLINK_VERSION_GENERIC_FW_UNDI		"fw.undi"
+/* NCSI support/handler version */
+#define DEVLINK_VERSION_GENERIC_FW_NCSI		"fw.ncsi"
+
 enum devlink_version_type {
 	DEVLINK_VERSION_FIXED,
 	DEVLINK_VERSION_STORED,
-- 
2.19.2


^ permalink raw reply related

* [PATCH net-next 7/7] ethtool: add compat for devlink info
From: Jakub Kicinski @ 2019-01-29  3:34 UTC (permalink / raw)
  To: davem
  Cc: netdev, oss-drivers, jiri, andrew, f.fainelli, mkubecek, eugenem,
	jonathan.lemon, Jakub Kicinski
In-Reply-To: <20190129033420.27235-1-jakub.kicinski@netronome.com>

If driver did not fill the fw_version field, try to call into
the new devlink get_info op and collect the versions that way.
We assume ethtool was always reporting running versions.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 include/net/devlink.h |  7 ++++++
 net/core/devlink.c    | 52 ++++++++++++++++++++++++++++++++++++++++++-
 net/core/ethtool.c    |  7 ++++++
 3 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/include/net/devlink.h b/include/net/devlink.h
index 14da3632e8fc..b047360b88a9 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -616,6 +616,8 @@ int devlink_info_report_version(struct devlink_info_req *req,
 				enum devlink_version_type type,
 				const char *version_name,
 				const char *version_value);
+void devlink_compat_running_versions(struct net_device *dev,
+				     char *buf, size_t len);
 
 #else
 
@@ -896,6 +898,11 @@ devlink_info_report_version(struct devlink_info_req *req,
 {
 	return 0;
 }
+
+static inline void
+devlink_compat_running_versions(struct net_device *dev, char *buf, size_t len)
+{
+}
 #endif
 
 #endif /* _NET_DEVLINK_H_ */
diff --git a/net/core/devlink.c b/net/core/devlink.c
index f0c5f9bd96b7..99037bf15fb8 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -3598,12 +3598,18 @@ static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
 }
 
 struct devlink_info_req {
+	bool compat;
 	struct sk_buff *msg;
+	/* For compat call */
+	char *buf;
+	size_t len;
 };
 
 int devlink_info_report_driver_name(struct devlink_info_req *req,
 				    const char *name)
 {
+	if (req->compat)
+		return 0;
 	return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRV_NAME, name);
 }
 EXPORT_SYMBOL_GPL(devlink_info_report_driver_name);
@@ -3611,6 +3617,8 @@ EXPORT_SYMBOL_GPL(devlink_info_report_driver_name);
 int devlink_info_report_serial_number(struct devlink_info_req *req,
 				      const char *sn)
 {
+	if (req->compat)
+		return 0;
 	return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
 }
 EXPORT_SYMBOL_GPL(devlink_info_report_serial_number);
@@ -3626,7 +3634,15 @@ int devlink_info_report_version(struct devlink_info_req *req,
 		[DEVLINK_VERSION_RUNNING] = DEVLINK_ATTR_INFO_VERSION_RUNNING,
 	};
 	struct nlattr *nest;
-	int err;
+	int len, err;
+
+	if (req->compat) {
+		if (type == DEVLINK_VERSION_RUNNING) {
+			len = strlcpy(req->buf, version_value, req->len);
+			req->len = max_t(size_t, 0, req->len - len);
+		}
+		return 0;
+	}
 
 	if (type >= ARRAY_SIZE(type2attr) || !type2attr[type])
 		return -EINVAL;
@@ -3672,6 +3688,7 @@ devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
 	if (devlink_nl_put_handle(msg, devlink))
 		goto err_cancel_msg;
 
+	memset(&req, 0, sizeof(req));
 	req.msg = msg;
 	err = devlink->ops->info_get(devlink, &req, extack);
 	if (err)
@@ -4962,6 +4979,39 @@ int devlink_region_snapshot_create(struct devlink_region *region, u64 data_len,
 }
 EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
 
+void devlink_compat_running_versions(struct net_device *dev,
+				     char *buf, size_t len)
+{
+	struct devlink_port *devlink_port;
+	struct devlink_info_req req;
+	struct devlink *devlink;
+	bool found = false;
+
+	mutex_lock(&devlink_mutex);
+	list_for_each_entry(devlink, &devlink_list, list) {
+		mutex_lock(&devlink->lock);
+		list_for_each_entry(devlink_port, &devlink->port_list, list) {
+			if (devlink_port->type == DEVLINK_PORT_TYPE_ETH ||
+			    devlink_port->type_dev == dev) {
+				mutex_unlock(&devlink->lock);
+				found = true;
+				goto out;
+			}
+		}
+		mutex_unlock(&devlink->lock);
+	}
+out:
+	if (found && devlink->ops->info_get) {
+		memset(&req, 0, sizeof(req));
+		req.compat = true;
+		req.buf = buf;
+		req.len = len;
+
+		devlink->ops->info_get(devlink, &req, NULL);
+	}
+	mutex_unlock(&devlink_mutex);
+}
+
 static int __init devlink_module_init(void)
 {
 	return genl_register_family(&devlink_nl_family);
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 158264f7cfaf..176b17d11f08 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -27,6 +27,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/sched/signal.h>
 #include <linux/net.h>
+#include <net/devlink.h>
 #include <net/xdp_sock.h>
 
 /*
@@ -803,6 +804,12 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
 	if (ops->get_eeprom_len)
 		info.eedump_len = ops->get_eeprom_len(dev);
 
+	rtnl_unlock();
+	if (!info.fw_version[0])
+		devlink_compat_running_versions(dev, info.fw_version,
+						ARRAY_SIZE(info.fw_version));
+	rtnl_lock();
+
 	if (copy_to_user(useraddr, &info, sizeof(info)))
 		return -EFAULT;
 	return 0;
-- 
2.19.2


^ permalink raw reply related

* Re: pull-request: bpf-next 2019-01-29
From: David Miller @ 2019-01-29  3:38 UTC (permalink / raw)
  To: daniel; +Cc: ast, netdev
In-Reply-To: <20190129014627.22132-1-daniel@iogearbox.net>

From: Daniel Borkmann <daniel@iogearbox.net>
Date: Tue, 29 Jan 2019 02:46:27 +0100

> The following pull-request contains BPF updates for your *net-next* tree.
> 
> The main changes are:
 ...
> Please consider pulling these changes from:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git

Pulled, thanks Daniel!

^ permalink raw reply

* Re: [PATCH net-next] net: udp Allow CHECKSUM_UNNECESSARY packets to do GRO.
From: Tom Herbert @ 2019-01-29  4:01 UTC (permalink / raw)
  To: maowenan; +Cc: Linux Kernel Network Developers, David S. Miller, Eric Dumazet
In-Reply-To: <b3bdb7c7-17dd-ac52-ff8e-4e312ccaaaa8@huawei.com>

On Mon, Jan 28, 2019 at 7:00 PM maowenan <maowenan@huawei.com> wrote:
>
> Hi all,
> Do you have any comments about this change?
>
>
> On 2019/1/23 11:33, Mao Wenan wrote:
> > When udp4_gro_receive() get one packet that uh->check=0,
> > skb_gro_checksum_validate_zero_check() will set the
> > skb->ip_summed = CHECKSUM_UNNECESSARY;
> > skb->csum_level = 0;
> > Then udp_gro_receive() will flush the packet which is not CHECKSUM_PARTIAL,
> > It is not our expect,  because check=0 in udp header indicates this
> > packet is no need to caculate checksum, we should go further to do GRO.
> >
> > This patch changes the value of csum_cnt according to skb->csum_level.
> > ---
> >  include/linux/netdevice.h | 1 +
> >  1 file changed, 1 insertion(+)
> >
> > diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> > index 1377d08..9c819f1 100644
> > --- a/include/linux/netdevice.h
> > +++ b/include/linux/netdevice.h
> > @@ -2764,6 +2764,7 @@ static inline void skb_gro_incr_csum_unnecessary(struct sk_buff *skb)
> >                * during GRO. This saves work if we fallback to normal path.
> >                */
> >               __skb_incr_checksum_unnecessary(skb);
> > +             NAPI_GRO_CB(skb)->csum_cnt = skb->csum_level + 1;

That doesn't look right. This would be reinitializing the GRO
checksums from the beginning.

> >       }
> >  }
> >
> >
>
I assume the code is bailing on this conditional:

if (NAPI_GRO_CB(skb)->encap_mark ||
            (skb->ip_summed != CHECKSUM_PARTIAL &&
             NAPI_GRO_CB(skb)->csum_cnt == 0 &&
             !NAPI_GRO_CB(skb)->csum_valid) ||
            !udp_sk(sk)->gro_receive)
                goto out_unlock;

I am trying to remember why this needs to check csum_cnt. If there was
a csum_cnt for the UDP csum being zero from checksum-unnecessary, it
was consumed by skb_gro_checksum_validate_zero_check in UDP4 GRO
received.

^ permalink raw reply

* Re: [PATCH bpf] bpf, doc: add reviewers to maintainers entry
From: Alexei Starovoitov @ 2019-01-29  4:04 UTC (permalink / raw)
  To: Song Liu
  Cc: Daniel Borkmann, Alexei Starovoitov, netdev@vger.kernel.org,
	Martin Lau, Yonghong Song
In-Reply-To: <4D178736-570A-4D43-B8AF-4846D525EA63@fb.com>

On Tue, Jan 29, 2019 at 03:08:54AM +0000, Song Liu wrote:
> 
> 
> > On Jan 28, 2019, at 2:55 PM, Daniel Borkmann <daniel@iogearbox.net> wrote:
> > 
> > In order to better scale BPF development on netdev, we've adopted a
> > reviewer rotation for all BPF patches among the five of us for some
> > time now. Lets give credit where credit is due, and add Martin, Song
> > and Yonghong as official BPF reviewers to MAINTAINERS file. Also
> > while at it, add regex matching for BPF such that we get properly
> > Cc'ed for files not listed here.
> > 
> > Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> 
> Thanks!
> 
> Acked-by: Song Liu <songliubraving@fb.com>

Applied to bpf tree. Thanks!


^ permalink raw reply

* [PATCH] kernel/bpf/core.c - fix bitrotted kerneldoc.
From: valdis.kletnieks @ 2019-01-29  4:04 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann; +Cc: netdev, linux-kernel

Over the years, the function signature has changed, the kerneldoc block hasn't.

Signed-off-by: Valdis Kletnieks <valdis.kletnieks@vt.edu>

diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 2a81b8af3748..2728b6247091 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1216,8 +1216,9 @@ bool bpf_opcode_in_insntable(u8 code)
 #ifndef CONFIG_BPF_JIT_ALWAYS_ON
 /**
  *	__bpf_prog_run - run eBPF program on a given context
- *	@ctx: is the data we are operating on
+ *	@regs: is the array of MAX_BPF_EXT_REG eBPF pseudo-registers
  *	@insn: is the array of eBPF instructions
+ *	@stack: is the eBPF storage stack
  *
  * Decode and execute eBPF instructions.
  */


^ permalink raw reply related

* [RFC net-next 2/4] net: Prepare EnOcean device drivers
From: Andreas Färber @ 2019-01-29  5:01 UTC (permalink / raw)
  To: linux-lpwan, linux-wpan
  Cc: Alexander Aring, Stefan Schmidt, netdev, linux-kernel, support,
	Andreas Färber
In-Reply-To: <20190129050130.10932-1-afaerber@suse.de>

Add net_device helpers for EnOcean.

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 drivers/net/enocean/Makefile  |   2 +
 drivers/net/enocean/enocean.c | 124 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/enocean/dev.h   |  23 ++++++++
 3 files changed, 149 insertions(+)
 create mode 100644 drivers/net/enocean/Makefile
 create mode 100644 drivers/net/enocean/enocean.c
 create mode 100644 include/linux/enocean/dev.h

diff --git a/drivers/net/enocean/Makefile b/drivers/net/enocean/Makefile
new file mode 100644
index 000000000000..efb3cd16c7f2
--- /dev/null
+++ b/drivers/net/enocean/Makefile
@@ -0,0 +1,2 @@
+obj-m += enocean-dev.o
+enocean-dev-y := enocean.o
diff --git a/drivers/net/enocean/enocean.c b/drivers/net/enocean/enocean.c
new file mode 100644
index 000000000000..087a4de274c8
--- /dev/null
+++ b/drivers/net/enocean/enocean.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * EnOcean net device
+ *
+ * Copyright (c) 2019 Andreas Färber
+ */
+
+#include <linux/enocean/dev.h>
+#include <linux/if_arp.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <net/rtnetlink.h>
+
+int open_enocean_dev(struct net_device *dev)
+{
+	if (!netif_carrier_ok(dev))
+		netif_carrier_on(dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(open_enocean_dev);
+
+void close_enocean_dev(struct net_device *dev)
+{
+}
+EXPORT_SYMBOL_GPL(close_enocean_dev);
+
+static void enocean_setup(struct net_device *dev)
+{
+	dev->type = ARPHRD_ENOCEAN;
+	dev->mtu = 255; /* XXX */
+	dev->hard_header_len = 0;
+	dev->addr_len = 0; /* XXX 4 */
+	dev->tx_queue_len = 10;
+
+	dev->flags = IFF_NOARP;
+	dev->features = 0;
+}
+
+struct net_device *alloc_enocean_dev(size_t priv_size)
+{
+	struct enocean_dev_priv *priv;
+	struct net_device *netdev;
+
+	netdev = alloc_netdev(priv_size, "enocean%d", NET_NAME_UNKNOWN, enocean_setup);
+	if (!netdev)
+		return NULL;
+
+	priv = netdev_priv(netdev);
+	priv->dev = netdev;
+
+	return netdev;
+}
+EXPORT_SYMBOL_GPL(alloc_enocean_dev);
+
+void free_enocean_dev(struct net_device *netdev)
+{
+	free_netdev(netdev);
+}
+EXPORT_SYMBOL_GPL(free_enocean_dev);
+
+static void devm_free_enocean_dev(struct device *dev, void *res)
+{
+	struct net_device **net = res;
+
+	free_enocean_dev(*net);
+}
+
+struct net_device *devm_alloc_enocean_dev(struct device *dev, size_t priv)
+{
+	struct net_device **ptr;
+	struct net_device *net;
+
+	net = alloc_enocean_dev(priv);
+	if (!net)
+		return NULL;
+
+	ptr = devres_alloc(devm_free_enocean_dev, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr) {
+		free_enocean_dev(net);
+		return NULL;
+	}
+
+	*ptr = net;
+	devres_add(dev, ptr);
+
+	return net;
+}
+EXPORT_SYMBOL_GPL(devm_alloc_enocean_dev);
+
+static struct rtnl_link_ops enocean_link_ops __read_mostly = {
+	.kind = "enocean",
+	.setup = enocean_setup,
+};
+
+int register_enocean_dev(struct net_device *dev)
+{
+	dev->rtnl_link_ops = &enocean_link_ops;
+	return register_netdev(dev);
+}
+EXPORT_SYMBOL_GPL(register_enocean_dev);
+
+void unregister_enocean_dev(struct net_device *dev)
+{
+	unregister_netdev(dev);
+}
+EXPORT_SYMBOL_GPL(unregister_enocean_dev);
+
+static int __init enocean_dev_init(void)
+{
+	return rtnl_link_register(&enocean_link_ops);
+}
+module_init(enocean_dev_init);
+
+static void __exit enocean_dev_exit(void)
+{
+	rtnl_link_unregister(&enocean_link_ops);
+}
+module_exit(enocean_dev_exit);
+
+MODULE_DESCRIPTION("EnOcean device driver interface");
+MODULE_ALIAS_RTNL_LINK("enocean");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andreas Färber");
diff --git a/include/linux/enocean/dev.h b/include/linux/enocean/dev.h
new file mode 100644
index 000000000000..be9d37cdde37
--- /dev/null
+++ b/include/linux/enocean/dev.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * linux/enocean/dev.h
+ *
+ * Copyright (c) 2019 Andreas Färber
+ */
+#ifndef _ENOCEAN_DEV_H
+#define _ENOCEAN_DEV_H
+
+#include <linux/netdevice.h>
+
+struct net_device *alloc_enocean_dev(size_t priv_size);
+struct net_device *devm_alloc_enocean_dev(struct device *dev, size_t priv_size);
+int register_enocean_dev(struct net_device *netdev);
+void unregister_enocean_dev(struct net_device *netdev);
+int open_enocean_dev(struct net_device *netdev);
+void close_enocean_dev(struct net_device *netdev);
+
+struct enocean_dev_priv {
+	struct net_device *dev;
+};
+
+#endif
-- 
2.16.4


^ permalink raw reply related

* [RFC net-next 4/4] net: enocean: Prepare ESP2 support
From: Andreas Färber @ 2019-01-29  5:01 UTC (permalink / raw)
  To: linux-lpwan, linux-wpan
  Cc: Alexander Aring, Stefan Schmidt, netdev, linux-kernel, support,
	Andreas Färber
In-Reply-To: <20190129050130.10932-1-afaerber@suse.de>

The EnOcean Serial Protocol 2 used subtelegram frames different from ESP3.
It also uses ORG identifiers differing from RORG identifiers in ERP.

Only checksumming has been tested.

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 drivers/net/enocean/Makefile       |   1 +
 drivers/net/enocean/enocean_esp.c  |  10 ++
 drivers/net/enocean/enocean_esp.h  |   8 ++
 drivers/net/enocean/enocean_esp2.c | 276 +++++++++++++++++++++++++++++++++++++
 4 files changed, 295 insertions(+)
 create mode 100644 drivers/net/enocean/enocean_esp2.c

diff --git a/drivers/net/enocean/Makefile b/drivers/net/enocean/Makefile
index 4492e3d48c0a..f34b098997e4 100644
--- a/drivers/net/enocean/Makefile
+++ b/drivers/net/enocean/Makefile
@@ -3,4 +3,5 @@ enocean-dev-y := enocean.o
 
 obj-m += enocean-esp.o
 enocean-esp-y := enocean_esp.o
+enocean-esp-y += enocean_esp2.o
 enocean-esp-y += enocean_esp3.o
diff --git a/drivers/net/enocean/enocean_esp.c b/drivers/net/enocean/enocean_esp.c
index 61bddb77762d..74720da49369 100644
--- a/drivers/net/enocean/enocean_esp.c
+++ b/drivers/net/enocean/enocean_esp.c
@@ -150,6 +150,15 @@ static void enocean_esp_cleanup(struct enocean_device *edev)
 		edev->version->cleanup(edev);
 }
 
+static const struct enocean_esp_version enocean_esp2 = {
+	.version = 2,
+	.baudrate = 9600,
+	.serdev_client_ops = &enocean_esp2_serdev_client_ops,
+	.init = enocean_esp2_init,
+	.send = enocean_esp2_send,
+	.cleanup = enocean_esp2_cleanup,
+};
+
 static const struct enocean_esp_version enocean_esp3 = {
 	.version = 3,
 	.baudrate = 57600,
@@ -160,6 +169,7 @@ static const struct enocean_esp_version enocean_esp3 = {
 };
 
 static const struct of_device_id enocean_of_match[] = {
+	{ .compatible = "enocean,esp2", .data = &enocean_esp2 },
 	{ .compatible = "enocean,esp3", .data = &enocean_esp3 },
 	{}
 };
diff --git a/drivers/net/enocean/enocean_esp.h b/drivers/net/enocean/enocean_esp.h
index e02bf5352d61..44660238043a 100644
--- a/drivers/net/enocean/enocean_esp.h
+++ b/drivers/net/enocean/enocean_esp.h
@@ -24,15 +24,23 @@ struct enocean_device {
 	void *priv;
 };
 
+extern const struct serdev_device_ops enocean_esp2_serdev_client_ops;
 extern const struct serdev_device_ops enocean_esp3_serdev_client_ops;
 
 void enocean_esp3_crc8_populate(void);
 
+int enocean_esp2_init(struct enocean_device *edev);
 int enocean_esp3_init(struct enocean_device *edev);
 
+int enocean_esp2_send(struct enocean_device *edev, u32 dest, const void *data, int data_len);
 int enocean_esp3_send(struct enocean_device *edev, u32 dest, const void *data, int data_len);
 void enocean_esp_tx_done(struct enocean_device *edev);
 
+void enocean_esp2_cleanup(struct enocean_device *edev);
 void enocean_esp3_cleanup(struct enocean_device *edev);
 
+#define ENOCEAN_RORG_RPS	0xF6
+#define ENOCEAN_RORG_1BS	0xD5
+#define ENOCEAN_RORG_4BS	0xA5
+
 #endif
diff --git a/drivers/net/enocean/enocean_esp2.c b/drivers/net/enocean/enocean_esp2.c
new file mode 100644
index 000000000000..d4cb787de22e
--- /dev/null
+++ b/drivers/net/enocean/enocean_esp2.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * EnOcean Serial Protocol 2
+ *
+ * Copyright (c) 2019 Andreas Färber
+ */
+
+#include <linux/serdev.h>
+
+#include "enocean_esp.h"
+
+#define ESP2_SYNC_BYTE1 0xA5
+#define ESP2_SYNC_BYTE0 0x5A
+
+struct enocean_esp2_packet {
+	u8 sync[2];
+#ifdef CONFIG_CPU_BIG_ENDIAN
+	u8 h_seq:3;
+	u8 length:5;
+#else
+	u8 length:5;
+	u8 h_seq:3;
+#endif
+	u8 org;
+	u8 data[4];
+	u8 id[4];
+	u8 status;
+	u8 checksum;
+} __packed;
+
+#define ESP2_H_SEQ_TRT	0x3
+#define ESP2_H_SEQ_RCT	0x4
+#define ESP2_H_SEQ_TCT	0x5
+
+#define ESP2_TELEGRAM_RESET	0x0A
+
+#define ENOCEAN_ORG_RPS		0x05
+#define ENOCEAN_ORG_1BS		0x06
+#define ENOCEAN_ORG_4BS		0x07
+
+/* Cf. EnOcean Equipment Profiles, Telegram Types (RORG) */
+static inline u8 enocean_org_to_rorg(u8 org)
+{
+	switch (org) {
+	case ENOCEAN_ORG_RPS:
+		return ENOCEAN_RORG_RPS;
+	case ENOCEAN_ORG_1BS:
+		return ENOCEAN_RORG_1BS;
+	case ENOCEAN_ORG_4BS:
+		return ENOCEAN_RORG_4BS;
+	default:
+		return org;
+	}
+}
+
+static u8 enocean_rorg_to_org(u8 rorg)
+{
+	switch (rorg) {
+	case ENOCEAN_RORG_RPS:
+		return ENOCEAN_ORG_RPS;
+	case ENOCEAN_RORG_1BS:
+		return ENOCEAN_ORG_1BS;
+	case ENOCEAN_RORG_4BS:
+		return ENOCEAN_ORG_4BS;
+	default:
+		return rorg;
+	}
+}
+
+struct enocean_esp2_dispatcher {
+	struct list_head list;
+	u8 h_seq;
+	void (*dispatch)(const u8 *data, u8 data_len, struct enocean_esp2_dispatcher *d);
+};
+
+static void enocean_add_esp2_dispatcher(struct enocean_device *edev,
+	struct enocean_esp2_dispatcher *entry)
+{
+	list_add_tail_rcu(&entry->list, &edev->esp_dispatchers);
+}
+
+static void enocean_remove_esp2_dispatcher(struct enocean_device *edev,
+	struct enocean_esp2_dispatcher *entry)
+{
+	list_del_rcu(&entry->list);
+}
+
+#define ESP2_RESPONSE_ERR_SYNTAX_H_SEQ	0x08
+#define ESP2_RESPONSE_ERR_SYNTAX_LENGTH	0x09
+#define ESP2_RESPONSE_ERR_SYNTAX_CHKSUM	0x0A
+#define ESP2_RESPONSE_ERR_SYNTAX_ORG	0x0B
+#define ESP2_RESPONSE_ERR		0x19
+#define ESP2_RESPONSE_ERR_IDRANGE	0x1A
+#define ESP2_RESPONSE_ERR_TX_IDRANGE	0x22
+#define ESP2_RESPONSE_OK		0x58
+
+struct enocean_esp2_priv {
+	struct enocean_device *edev;
+	struct enocean_esp2_dispatcher tx_telegram_response;
+};
+
+static u8 enocean_esp2_checksum(const u8 *data, int len)
+{
+	u8 chksum = 0;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		chksum += data[i];
+	}
+	return chksum;
+}
+
+static int enocean_esp2_send_telegram(struct enocean_device *edev, u8 h_seq, u8 org,
+	const u8 *data, int data_len, unsigned long timeout)
+{
+	struct enocean_esp2_packet pkt;
+	int ret;
+
+	memset(&pkt, 0, sizeof(pkt));
+	pkt.sync[0] = ESP2_SYNC_BYTE1;
+	pkt.sync[1] = ESP2_SYNC_BYTE0;
+	pkt.h_seq = h_seq;
+	pkt.length = 11;
+	dev_dbg(&edev->serdev->dev, "H_SEQ | LENGTH = %02x\n", (unsigned int)(((u8*)&pkt)[2]));
+	pkt.org = org;
+	if (data_len > 0)
+		memcpy(pkt.data, data, min(data_len, 9));
+	pkt.checksum = enocean_esp2_checksum(((u8 *)&pkt) + 2, sizeof(pkt) - 2 - 1);
+	dev_dbg(&edev->serdev->dev, "checksum = %02x\n", (unsigned int)pkt.checksum);
+
+	ret = serdev_device_write(edev->serdev, (const u8 *)&pkt, sizeof(pkt), timeout);
+	if (ret < 0)
+		return ret;
+	if (ret > 0 && ret < sizeof(pkt))
+		return -EIO;
+	return 0;
+}
+
+static void enocean_esp2_tx_telegram_response_dispatch(const u8 *data, u8 data_len,
+	struct enocean_esp2_dispatcher *d)
+{
+	struct enocean_esp2_priv *priv = container_of(d, struct enocean_esp2_priv, tx_telegram_response);
+	struct enocean_device *edev = priv->edev;
+
+	enocean_remove_esp2_dispatcher(edev, d);
+
+	if (data_len < 1)
+		return;
+
+	switch (data[0]) {
+	case ESP2_RESPONSE_OK:
+		enocean_esp_tx_done(edev);
+		break;
+	case ESP2_RESPONSE_ERR:
+	case ESP2_RESPONSE_ERR_TX_IDRANGE:
+	default:
+		break;
+	}
+}
+
+static int enocean_esp2_tx_telegram(struct enocean_device *edev, u8 org,
+	const u8 *data, int data_len, unsigned long timeout)
+{
+	struct enocean_esp2_priv *priv = edev->priv;
+	int ret;
+
+	enocean_add_esp2_dispatcher(edev, &priv->tx_telegram_response);
+
+	ret = enocean_esp2_send_telegram(edev, ESP2_H_SEQ_TRT,
+		org, data, data_len, timeout);
+	if (ret) {
+		enocean_remove_esp2_dispatcher(edev, &priv->tx_telegram_response);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int enocean_esp2_reset(struct enocean_device *edev, unsigned long timeout)
+{
+	return enocean_esp2_send_telegram(edev, ESP2_H_SEQ_TCT, ESP2_TELEGRAM_RESET, NULL, 0, timeout);
+	/* no RCT */
+}
+
+static int enocean_esp2_receive_buf(struct serdev_device *sdev, const u8 *data, size_t count)
+{
+	struct enocean_device *edev = serdev_device_get_drvdata(sdev);
+	struct enocean_esp2_dispatcher *e;
+	u8 h_seq, length, chksum;
+
+	dev_dbg(&sdev->dev, "Receive (%zu)\n", count);
+
+	if (data[0] != ESP2_SYNC_BYTE1) {
+		dev_warn(&sdev->dev, "not first Sync Byte (found 0x%02x), skipping\n",
+			(unsigned int)data[0]);
+		return 1;
+	}
+
+	if (count < 2)
+		return 0;
+
+	if (data[1] != ESP2_SYNC_BYTE0) {
+		dev_warn(&sdev->dev, "not second Sync Byte (found 0x%02x 0x%02x), skipping\n",
+			ESP2_SYNC_BYTE1, (unsigned int)data[1]);
+		return 1;
+	}
+
+	if (count < 3)
+		return 0;
+
+	h_seq = data[2] >> 5;
+	length = data[2] & 0x1f;
+
+	if (count < 3 + length)
+		return 0;
+
+	chksum = enocean_esp2_checksum(data + 2, 1 + length - 1);
+	if (data[3 + length - 1] != chksum) {
+		dev_warn(&sdev->dev, "invalid checksum (expected 0x%02x, found %02x), skipping\n",
+			(unsigned int)chksum, (unsigned int)data[3 + length - 1]);
+		return 2; /* valid second Sync Byte is not a valid first Sync Byte */
+	}
+
+	print_hex_dump_bytes("received: ", DUMP_PREFIX_OFFSET, data, 3 + length);
+
+	list_for_each_entry_rcu(e, &edev->esp_dispatchers, list) {
+		if (e->h_seq == h_seq)
+			e->dispatch(data + 3, length, e);
+	}
+
+	return 3 + length;
+}
+
+const struct serdev_device_ops enocean_esp2_serdev_client_ops = {
+	.receive_buf = enocean_esp2_receive_buf,
+	.write_wakeup = serdev_device_write_wakeup,
+};
+
+int enocean_esp2_send(struct enocean_device *edev, u32 dest, const void *data, int data_len)
+{
+	const u8 *buf = data;
+
+	return enocean_esp2_tx_telegram(edev,
+		enocean_rorg_to_org(buf[0]), buf + 1, data_len - 1, HZ);
+}
+
+int enocean_esp2_init(struct enocean_device *edev)
+{
+	struct enocean_esp2_priv *priv;
+	int ret;
+
+	ret = enocean_esp2_reset(edev, HZ);
+	if (ret)
+		return ret;
+
+	msleep(100); /* XXX */
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->edev = edev;
+	edev->priv = priv;
+
+	priv->tx_telegram_response.h_seq = ESP2_H_SEQ_RCT;
+	priv->tx_telegram_response.dispatch = enocean_esp2_tx_telegram_response_dispatch;
+
+	return 0;
+}
+
+void enocean_esp2_cleanup(struct enocean_device *edev)
+{
+	struct enocean_esp2_priv *priv = edev->priv;
+
+	kfree(priv);
+}
-- 
2.16.4


^ permalink raw reply related


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