Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net-next v2] net: ipv6: make sure multicast packets are not forwarded beyond the different scopes
From: Donatas Abraitis @ 2017-05-03  7:53 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, stable
In-Reply-To: <20170502.145923.66844914584656456.davem@davemloft.net>

Looks like there is this test already:

                if (IPV6_ADDR_MC_SCOPE(&ipv6_hdr(skb)->daddr) <=
                    IPV6_ADDR_SCOPE_NODELOCAL &&
                    !(dev->flags & IFF_LOOPBACK)) {
                        kfree_skb(skb);
                        return 0;
                }

On Tue, May 2, 2017 at 9:59 PM, David Miller <davem@davemloft.net> wrote:
> From: Donatas Abraitis <donatas.abraitis@gmail.com>
> Date: Thu, 27 Apr 2017 10:12:02 +0300
>
>>           RFC4291 2.7 Routers must not forward any multicast packets
>>           beyond of the scope indicated by the scop field in the
>>           destination multicast address.
>>
>> Signed-off-by: Donatas Abraitis <donatas.abraitis@gmail.com>
>
> I think it's a ">=" test which is needed here, not pure equality.
> Scopes are subsets of other scopes and are therefore allowed within
> eachother.
>
> Did you actually see misbehavior due to this issue, or see a real
> bonafide conformance test fail?
>
> If you're just reading the RFC and sticking tests here and there based
> upon what you read, without any testing or real life verification of
> the issue, this is _strongly_ discouraged.
>
> It would even be ok if you merely showed how another open source
> networking stack makes this test.



-- 
Donatas

^ permalink raw reply

* [PATCH net] tg3: don't clear stats while tg3_close
From: YueHaibing @ 2017-05-03  7:51 UTC (permalink / raw)
  To: davem, netdev; +Cc: weiyongjun1

Now tg3 NIC's stats will be cleared after ifdown/ifup. bond_get_stats traverse
its salves to get statistics,cumulative the increment.If a tg3 NIC is added to
bonding as a slave,ifdown/ifup will cause bonding's stats become tremendous value
(ex.1638.3 PiB) because of negative increment.

Fixes: 92feeabf3f67 ("tg3: Save stats across chip resets")
Signed-off-by: YueHaibing <yuehaibing@huawei.com>
---
 drivers/net/ethernet/broadcom/tg3.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 30d1eb9..29beba1 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -11722,10 +11722,6 @@ static int tg3_close(struct net_device *dev)
 
 	tg3_stop(tp);
 
-	/* Clear stats across close / open calls */
-	memset(&tp->net_stats_prev, 0, sizeof(tp->net_stats_prev));
-	memset(&tp->estats_prev, 0, sizeof(tp->estats_prev));
-
 	if (pci_device_is_present(tp->pdev)) {
 		tg3_power_down_prepare(tp);
 
-- 
2.5.0

^ permalink raw reply related

* [PATCH] brcmfmac: btcoex: replace init_timer with setup_timer
From: Xie Qirong @ 2017-05-03  7:35 UTC (permalink / raw)
  To: Arend van Spriel, Franky Lin, Hante Meuleman, Kalle Valo
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	brcm80211-dev-list.pdl-dY08KVG/lbpWk0Htik3J/w,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Piotr Haber, Xie Qirong

Signed-off-by: Xie Qirong <cheerx1994-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---

 setup_timer.cocci suggested the following improvement:
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c:383:1-11: Use
 setup_timer function for function on line 384.

 Patch was compile checked with: x86_64_defconfig + CONFIG_BRCMFMAC=y +
 CONFIG_BRCMFMAC_USB=y + CONFIG_BRCMFMAC_PCIE=y + CONFIG_BRCM_TRACING=y +
 CONFIG_BRCMDBG=y

 Kernel version: next-20170502 (localversion-next is next-20170502)

 drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
index 14a70d4..3559fb5 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
@@ -380,9 +380,7 @@ int brcmf_btcoex_attach(struct brcmf_cfg80211_info *cfg)
 	/* Set up timer for BT  */
 	btci->timer_on = false;
 	btci->timeout = BRCMF_BTCOEX_OPPR_WIN_TIME;
-	init_timer(&btci->timer);
-	btci->timer.data = (ulong)btci;
-	btci->timer.function = brcmf_btcoex_timerfunc;
+	setup_timer(&btci->timer, brcmf_btcoex_timerfunc, (ulong)btci);
 	btci->cfg = cfg;
 	btci->saved_regs_part1 = false;
 	btci->saved_regs_part2 = false;
-- 
2.9.3

^ permalink raw reply related

* Re: [PATCH 0/9] net: thunderx: Adds XDP support
From: Sunil Kovvuri @ 2017-05-03  7:28 UTC (permalink / raw)
  To: David Miller; +Cc: Linux Netdev List, LKML, LAKML, Sunil Goutham
In-Reply-To: <20170502.154744.1762061314370744901.davem@davemloft.net>

On Wed, May 3, 2017 at 1:17 AM, David Miller <davem@davemloft.net> wrote:
> From: sunil.kovvuri@gmail.com
> Date: Tue,  2 May 2017 18:36:49 +0530
>
>> From: Sunil Goutham <sgoutham@cavium.com>
>>
>> This patch series adds support for XDP to ThunderX NIC driver
>> which is used on CN88xx, CN81xx and CN83xx platforms.
>>
>> Patches 1-4 are performance improvement and cleanup patches
>> which are done keeping XDP performance bottlenecks in view.
>> Rest of the patches adds actual XDP support.
>
> Series applied, thanks for doing this work.

Thanks.

>
> Do you have any performance numbers?

Below are the forwarding numbers on a single core.
with network stack: 0.32 Mpps
with XDP (XDP_TX): 3 Mpps
and XDP_DROP: 3.8 Mpps

Thanks,
Sunil.

^ permalink raw reply

* Miss it//Re: [PATCH v3] iov_iter: don't revert iov buffer if csum error
From: Ding Tianhong @ 2017-05-03  7:15 UTC (permalink / raw)
  To: David Miller, pabeni, edumazet, hannes, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, LinuxArm, weiyongjun (A), Al Viro
In-Reply-To: <12d4d81f-40c7-c83d-11d6-290acc084695@huawei.com>

Miss it, it is already in the kernel tree, sorry for the noisy.

On 2017/5/3 15:02, Ding Tianhong wrote:
> The patch 327868212381 (make skb_copy_datagram_msg() et.al. preserve
> ->msg_iter on error) will revert the iov buffer if copy to iter
> failed, but it didn't copy any datagram if the skb_checksum_complete
> error, so no need to revert any data at this place.
> 
> v2: Sabrina notice that return -EFAULT when checksum error is not correct
>     here, it would confuse the caller about the return value, so fix it.
> 
> v3: According AI's suggestion, directly return -EINVAL when __skb_checksum_complete()
>     return error is a more simple solution.
> 
> Fixes: 327868212381 ("make skb_copy_datagram_msg() et.al. preserve->msg_iter on error")
> Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
> Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
> ---
>  net/core/datagram.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/net/core/datagram.c b/net/core/datagram.c
> index 0306543..726bf8a 100644
> --- a/net/core/datagram.c
> +++ b/net/core/datagram.c
> @@ -719,7 +719,7 @@ int skb_copy_and_csum_datagram_msg(struct sk_buff *skb,
> 
>  	if (msg_data_left(msg) < chunk) {
>  		if (__skb_checksum_complete(skb))
> -			goto csum_error;
> +			return -EINVAL;
>  		if (skb_copy_datagram_msg(skb, hlen, msg, chunk))
>  			goto fault;
>  	} else {
> 

^ permalink raw reply

* Re:
From: H.A @ 2017-05-03  7:00 UTC (permalink / raw)
  To: Recipients

With profound love in my heart, I Kindly Oblige your interest to very important proposal.. It is Truly Divine and require your utmost attention..........

S hlubokou láskou v mém srdci, Laskave jsem prinutit svuj zájem k návrhu .. Je velmi duležité, skutecne Divine a vyžadují vaši nejvyšší pozornost.

  Kontaktujte me prímo pres: helenaroberts99@gmail.com pro úplné podrobnosti.complete.


HELINA .A ROBERTS

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

^ permalink raw reply

* Re: [PATCH v3] iov_iter: don't revert iov buffer if csum error
From: Al Viro @ 2017-05-03  7:07 UTC (permalink / raw)
  To: Ding Tianhong
  Cc: David Miller, pabeni, edumazet, hannes, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, LinuxArm, weiyongjun (A)
In-Reply-To: <12d4d81f-40c7-c83d-11d6-290acc084695@huawei.com>

On Wed, May 03, 2017 at 03:02:32PM +0800, Ding Tianhong wrote:
> The patch 327868212381 (make skb_copy_datagram_msg() et.al. preserve
> ->msg_iter on error) will revert the iov buffer if copy to iter
> failed, but it didn't copy any datagram if the skb_checksum_complete
> error, so no need to revert any data at this place.

See a6a5993243550b09f620941dea741b7421fdf79c in mainline...

^ permalink raw reply

* [PATCH v3] iov_iter: don't revert iov buffer if csum error
From: Ding Tianhong @ 2017-05-03  7:02 UTC (permalink / raw)
  To: David Miller, pabeni, edumazet, hannes, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, LinuxArm, weiyongjun (A), Al Viro

The patch 327868212381 (make skb_copy_datagram_msg() et.al. preserve
->msg_iter on error) will revert the iov buffer if copy to iter
failed, but it didn't copy any datagram if the skb_checksum_complete
error, so no need to revert any data at this place.

v2: Sabrina notice that return -EFAULT when checksum error is not correct
    here, it would confuse the caller about the return value, so fix it.

v3: According AI's suggestion, directly return -EINVAL when __skb_checksum_complete()
    return error is a more simple solution.

Fixes: 327868212381 ("make skb_copy_datagram_msg() et.al. preserve->msg_iter on error")
Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
---
 net/core/datagram.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/core/datagram.c b/net/core/datagram.c
index 0306543..726bf8a 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -719,7 +719,7 @@ int skb_copy_and_csum_datagram_msg(struct sk_buff *skb,

 	if (msg_data_left(msg) < chunk) {
 		if (__skb_checksum_complete(skb))
-			goto csum_error;
+			return -EINVAL;
 		if (skb_copy_datagram_msg(skb, hlen, msg, chunk))
 			goto fault;
 	} else {
-- 
1.8.3.1

^ permalink raw reply related

* Re: [PATCH net-next] net/esp4: Fix invalid esph pointer crash
From: Steffen Klassert @ 2017-05-03  7:02 UTC (permalink / raw)
  To: ilant; +Cc: netdev
In-Reply-To: <20170430133438.31962-1-ilant@mellanox.com>

On Sun, Apr 30, 2017 at 04:34:38PM +0300, ilant@mellanox.com wrote:
> From: Ilan Tayari <ilant@mellanox.com>
> 
> Both esp_output and esp_xmit take a pointer to the ESP header
> and place it in esp_info struct prior to calling esp_output_head.
> 
> Inside esp_output_head, the call to esp_output_udp_encap
> makes sure to update the pointer if it gets invalid.
> However, if esp_output_head itself calls skb_cow_data, the
> pointer is not updated and stays invalid, causing a crash
> after esp_output_head returns.
> 
> Update the pointer if it becomes invalid in esp_output_head
> 
> Fixes: fca11ebde3f0 ("esp4: Reorganize esp_output")
> Signed-off-by: Ilan Tayari <ilant@mellanox.com>
> ---
>  net/ipv4/esp4.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
> index 7f2caf71212b..65cc02bd82bc 100644
> --- a/net/ipv4/esp4.c
> +++ b/net/ipv4/esp4.c
> @@ -317,6 +317,7 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
>  	if (nfrags < 0)
>  		goto out;
>  	tail = skb_tail_pointer(trailer);
> +	esp->esph = ip_esp_hdr(skb);

This is not quite right for udpencap. It fixes the crash,
but introduces a bug that we already have in v4.11.

On udpencap the esp header has an offset to skb_transport_header,
the problem was discussed last week here:

https://lkml.org/lkml/2017/4/25/937

I plan to fix this with the patch below:

Subject: [PATCH RFC] esp4: Fix udpencap for local TCP packets.

Locally generated TCP packets are usually cloned, so we
do skb_cow_data() on this packets. After that we need to
reload the pointer to the esp header. On udpencap this
header has an offset to skb_transport_header, so take this
offset into account.

Fixes: 67d349ed603 ("net/esp4: Fix invalid esph pointer crash")
Fixes: fca11ebde3f0 ("esp4: Reorganize esp_output")
Reported-by: Don Bowman <db@donbowman.ca>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 net/ipv4/esp4.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 65cc02b..93322f8 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -248,6 +248,7 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
 	u8 *tail;
 	u8 *vaddr;
 	int nfrags;
+	int esph_offset;
 	struct page *page;
 	struct sk_buff *trailer;
 	int tailen = esp->tailen;
@@ -313,11 +314,13 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
 	}
 
 cow:
+	esph_offset = (unsigned char *)esp->esph - skb_transport_header(skb);
+
 	nfrags = skb_cow_data(skb, tailen, &trailer);
 	if (nfrags < 0)
 		goto out;
 	tail = skb_tail_pointer(trailer);
-	esp->esph = ip_esp_hdr(skb);
+	esp->esph = (struct ip_esp_hdr *)(skb_transport_header(skb) + esph_offset);
 
 skip_cow:
 	esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto);
-- 
2.7.4

^ permalink raw reply related

* RE: [PATCH net v3] driver: veth: Fix one possbile memleak when fail to register_netdevice
From: Gao Feng @ 2017-05-03  6:37 UTC (permalink / raw)
  To: 'Xin Long'
  Cc: 'Gao Feng', 'davem', jarod,
	'Stephen Hemminger', dsa, 'network dev'
In-Reply-To: <CADvbK_c32g2t-Azgf10da8qke5B+wgG4dw3jLTE2L+R2qR3xPA@mail.gmail.com>

> From: Xin Long [mailto:lucien.xin@gmail.com]
> Sent: Wednesday, May 3, 2017 1:38 PM
> On Wed, May 3, 2017 at 10:07 AM, Gao Feng <gfree.wind@foxmail.com>
> wrote:
> >> From: netdev-owner@vger.kernel.org
> >> [mailto:netdev-owner@vger.kernel.org]
> >> On Behalf Of Xin Long
> >> Sent: Wednesday, May 3, 2017 12:59 AM On Tue, May 2, 2017 at 7:03 PM,
> >> Gao Feng <gfree.wind@vip.163.com> wrote:
> >> >> From: Xin Long [mailto:lucien.xin@gmail.com]
> >> >> Sent: Tuesday, May 2, 2017 3:56 PM On Sat, Apr 29, 2017 at 11:51
> >> >> AM,  <gfree.wind@foxmail.com> wrote:
> >> >> > From: Gao Feng <gfree.wind@foxmail.com>
[...]
> > The fix you mentioned change the original logic.
> > The dev->vstats is freed in advance in the ndo_uninit, not destructor.
> > It may break the backward.
> Sorry, I didn't get your "backward"
> I can't see there will be any problem caused by it.
> can you say this patch also break the 'backward' ?
> https://patchwork.ozlabs.org/patch/748964/
> 
> It's really weird to do dev->reg_state check in ndo_unint ndo_unint is supposed
> to free the memory alloced in ndo_init.
> 

I am not sure if it would break the backward, so I said it MAY break.
I assumed there may be someone would access the dev->vstats after ndo_uninit,
because current veth driver free the mem in the destructor.
I selected this approach because I don't want to bring new bugs during fix bug.

If you're sure it is safe to free dev->vstats in ndo_uninit, I would like to update it.

BTW there are too many drivers which have possible memleak.
You could find the list by https://www.mail-archive.com/netdev@vger.kernel.org/msg166629.html.

Some drivers allocate the resources in ndo_init, free some in ndo_uninit and free left in destructor.
I think there are some reasons. 
We could not move all free in the ndo_uninit from destructor. What's your opinion?

Best Regards
Feng

^ permalink raw reply

* Re: [PATCH iproute2 net 0/8] tc/act_pedit: Support offset relative to conventional header
From: Amir Vadai @ 2017-05-03  6:27 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, Or Gerlitz, Jamal Hadi Salim
In-Reply-To: <20170501092625.30274bee@xeon-e3>

On Mon, May 01, 2017 at 09:26:25AM -0700, Stephen Hemminger wrote:
> On Sun, 23 Apr 2017 15:53:48 +0300
> Amir Vadai <amir@vadai.me> wrote:
> 
> > Hi Stephen,
> > 
> > This patchset extends pedit to support modifying a field in an offset relative
> > to the conventional network headers (kenrel support was added [1] in 4.11 rc1).
> > Without the extended pedit, user could specify fields in TCP and ICMP headers,
> > but the kernel code was using an offset relative to the begining of the IP
> > header. This will break if IP header length is greater than the minimal value
> > of 20, or if L3 is not IPv4.
> > 
> > It also introduces support in manipulating ETH, TCP, UDP and IP.ttl fields and
> > a new command to increase/decrease the value of a field (current use case is IP.ttl).
> > 
> > Since there might be deployments already using pedit, special consideration was
> > taken, not to break those scripts - only by specifying the special keyword
> > 'ex', the extended capabilities are available, thus there should be no impact
> > on existing scripts.
> > Also, the new code can live together with rules added by the old code. It
> > supports both the old netlink and the new one.
> > 
> > This patchset is against the master and not net-next as the functionality was
> > added in 4.11
> > 
> > Thanks,
> > Amir
> > 
> > [1] - 71d0ed7079df ("net/act_pedit: Support using offset relative to the
> >                      conventional network headers")

[...]

> 
> Applied. Then I cleaned up long lines

Thanks. Will make sure to clean up long lines in future patches.

^ permalink raw reply

* Re: [net-next PATCH 0/4] Improve bpf ELF-loader under samples/bpf
From: Jesper Dangaard Brouer @ 2017-05-03  6:16 UTC (permalink / raw)
  To: Daniel Borkmann
  Cc: kafai, netdev, eric, Daniel Borkmann, Alexei Starovoitov, brouer
In-Reply-To: <5908F5AC.6000703@iogearbox.net>

On Tue, 02 May 2017 23:10:04 +0200
Daniel Borkmann <daniel@iogearbox.net> wrote:

> On 05/02/2017 02:31 PM, Jesper Dangaard Brouer wrote:
> > This series improves and fixes bpf ELF loader and programs under
> > samples/bpf.  The bpf_load.c created some hard to debug issues when
> > the struct (bpf_map_def) used in the ELF maps section format changed
> > in commit fb30d4b71214 ("bpf: Add tests for map-in-map").
> >
> > This was hotfixed in commit 409526bea3c3 ("samples/bpf: bpf_load.c
> > detect and abort if ELF maps section size is wrong") by detecting the
> > issue and aborting the program.
> >
> > In most situations the bpf-loader should be able to handle these kind
> > of changes to the struct size.  This patch series aim to do proper
> > backward and forward compabilility handling when loading ELF files.
> >
> > This series also adjust the callback that was introduced in commit
> > 9fd63d05f3e8 ("bpf: Allow bpf sample programs (*_user.c) to change
> > bpf_map_def") to use the new bpf_map_data structure, before more users
> > start to use this callback.
> >
> > Hoping these changes can make the merge window, as above mentioned
> > commits have not been merged yet, and it would be good to avoid users
> > hitting these issues.  
> 
> Overall, set looks good to me. The last patch doesn't have a
> user yet, so probably better to drop it until there is an actual
> user in the tree.

The reason for simply exporting map_data[] was that in patch 3, the
data-struct (bpf_map_data) is already exposed, thus users can already
grab and store those into a separate data structure.  Thus, it seemed
natural to simply export/expose the map_data[] array directly.  Guess,
I could have combined patch 4 and 3.  As patch-3 uses the data struct,
but in an indirect way.

To Daniel, if you still feel we should drop patch 4, then let me know.
It is only the other patches that are time critical, as patch 4 is
trivial to introduce once the first sample program uses this directly
(instead of indirectly through the callback).


> Long term, I'd like to see the samples being migrated to use the
> tools/lib/bpf/ library from the tree, so that we can avoid duplicating
> effort with having two libs in the tree (f.e. elf map validation is
> performed to a certain degree in the other one, but w/o compat
> support last time I looked).

Yes, I agree that we should migrate to use the tools/lib/bpf/ library.
But as you also say, it actually have similar compat loader issues,
although it does more validation.  Once we start this migration, I'll
also fix the compat loader issues in this lib.
 
> Anyway, other than that:
> 
> Acked-by: Daniel Borkmann <daniel@iogearbox.net>

Thanks

-- 
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer

^ permalink raw reply

* Re: [net-next PATCH 2/4] samples/bpf: make bpf_load.c code compatible with ELF maps section changes
From: Jesper Dangaard Brouer @ 2017-05-03  5:48 UTC (permalink / raw)
  To: Alexei Starovoitov; +Cc: kafai, netdev, eric, Daniel Borkmann, brouer
In-Reply-To: <20170503005449.urnux43sril3ganq@ast-mbp>

On Tue, 2 May 2017 17:54:51 -0700
Alexei Starovoitov <alexei.starovoitov@gmail.com> wrote:

> On Tue, May 02, 2017 at 02:31:56PM +0200, Jesper Dangaard Brouer wrote:
> > This patch does proper parsing of the ELF "maps" section, in-order to
> > be both backwards and forwards compatible with changes to the map
> > definition struct bpf_map_def, which gets compiled into the ELF file.
> > 
> > The assumption is that new features with value zero, means that they
> > are not in-use.  For backward compatibility where loading an ELF file
> > with a smaller struct bpf_map_def, only copy objects ELF size, leaving
> > rest of loaders struct zero.  For forward compatibility where ELF file
> > have a larger struct bpf_map_def, only copy loaders own struct size
> > and verify that rest of the larger struct is zero, assuming this means
> > the newer feature was not activated, thus it should be safe for this
> > older loader to load this newer ELF file.
> > 
> > Fixes: fb30d4b71214 ("bpf: Add tests for map-in-map")
> > Fixes: 409526bea3c3 ("samples/bpf: bpf_load.c detect and abort if ELF maps section size is wrong")
> > Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>  
> 
> I would just merge patches 2 and 3 to reduce churn,
> but it looks like great improvement already.

I could have combined them, but I prefer keeping them separate to keep
the ELF changes separated from changing a sample program e.g.
map_perf_test_user.c.  IHMO is is cleaner this way.

> Acked-by: Alexei Starovoitov <ast@kernel.org>
 
Thanks

-- 
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer

^ permalink raw reply

* Re: [PATCH net v3] driver: veth: Fix one possbile memleak when fail to register_netdevice
From: Xin Long @ 2017-05-03  5:37 UTC (permalink / raw)
  To: Gao Feng; +Cc: Gao Feng, davem, jarod, Stephen Hemminger, dsa, network dev
In-Reply-To: <000c01d2c3b2$0925e880$1b71b980$@foxmail.com>

On Wed, May 3, 2017 at 10:07 AM, Gao Feng <gfree.wind@foxmail.com> wrote:
>> From: netdev-owner@vger.kernel.org [mailto:netdev-owner@vger.kernel.org]
>> On Behalf Of Xin Long
>> Sent: Wednesday, May 3, 2017 12:59 AM
>> On Tue, May 2, 2017 at 7:03 PM, Gao Feng <gfree.wind@vip.163.com> wrote:
>> >> From: Xin Long [mailto:lucien.xin@gmail.com]
>> >> Sent: Tuesday, May 2, 2017 3:56 PM
>> >> On Sat, Apr 29, 2017 at 11:51 AM,  <gfree.wind@foxmail.com> wrote:
>> >> > From: Gao Feng <gfree.wind@foxmail.com>
>> > [...]
>> >> > -static void veth_dev_free(struct net_device *dev)
>> >> > +static void veth_destructor_free(struct net_device *dev)
>> >> >  {
>> >> >         free_percpu(dev->vstats);
>> >> > +}
>> >> not sure why you needed to add this function.
>> >> to use free_percpu() directly may be clearer.
>> >
>> > Because both of ndo_uninit and destructor need to perform same free
>> statements.
>> > It is good at maintain the codes with the common function.
>> >>
>> >> > +
>> >> > +static void veth_dev_uninit(struct net_device *dev) {
>> >> call free_percpu() here, no need to check dev->reg_state.
>> >> free_percpu will just return if dev->vstats is NULL.
>> >
>> > It would break the original design if don't check the reg_state.
>> > The original logic is that free the resources in the destructor, not in ndo_init.
>> I got what you're doing now, can you pls try to fix this with:
>>
>> --- a/drivers/net/veth.c
>> +++ b/drivers/net/veth.c
>> @@ -219,10 +219,9 @@ static int veth_dev_init(struct net_device *dev)
>>         return 0;
>>  }
>>
>> -static void veth_dev_free(struct net_device *dev)
>> +static void veth_dev_uninit(struct net_device *dev)
>>  {
>>         free_percpu(dev->vstats);
>> -       free_netdev(dev);
>>  }
>>
>>  #ifdef CONFIG_NET_POLL_CONTROLLER
>> @@ -279,6 +278,7 @@ static void veth_set_rx_headroom(struct net_device
>> *dev, int new_hr)
>>
>>  static const struct net_device_ops veth_netdev_ops = {
>>         .ndo_init            = veth_dev_init,
>> +       .ndo_uninit          = veth_dev_uninit,
>>         .ndo_open            = veth_open,
>>         .ndo_stop            = veth_close,
>>         .ndo_start_xmit      = veth_xmit,
>> @@ -317,7 +317,7 @@ static void veth_setup(struct net_device *dev)
>>                                NETIF_F_HW_VLAN_STAG_TX |
>>                                NETIF_F_HW_VLAN_CTAG_RX |
>>                                NETIF_F_HW_VLAN_STAG_RX);
>> -       dev->destructor = veth_dev_free;
>> +       dev->destructor = free_netdev;
>>         dev->max_mtu = ETH_MAX_MTU;
>>
>>         dev->hw_features = VETH_FEATURES;
>>
>>
>> just as what other virtual nic drivers do (vxlan, geneve, macsec, bridge ....)
>>
>
> The fix you mentioned change the original logic.
> The dev->vstats is freed in advance in the ndo_uninit, not destructor.
> It may break the backward.
Sorry, I didn't get your "backward"
I can't see there will be any problem caused by it.

can you say this patch also break the 'backward' ?
https://patchwork.ozlabs.org/patch/748964/

It's really weird to do dev->reg_state check in ndo_unint
ndo_unint is supposed to free the memory alloced in ndo_init.

>
> Regards
> Feng
>
>

^ permalink raw reply

* Re: [PATCH 1/1] IB/mlx5: Add port_xmit_wait to counter registers read
From: Leon Romanovsky @ 2017-05-03  5:38 UTC (permalink / raw)
  To: Tim Wright
  Cc: matanb-VPRAkNaXOzVWk0Htik3J/w, dledford-H+wXaHxf7aLQT0dZR+AlfA,
	sean.hefty-ral2JQCrhuEAvxtiuMwx3w,
	hal.rosenstock-Re5JQEeQqe8AvxtiuMwx3w,
	saeedm-VPRAkNaXOzVWk0Htik3J/w, linux-rdma-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170501163008.27043-1-tim-r/Uwd3QrhQcqdlJmJB21zg@public.gmane.org>

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

On Mon, May 01, 2017 at 05:30:08PM +0100, Tim Wright wrote:
> Add port_xmit_wait to the error counters read by mlx5_ib_process_mad to
> ensure sysfs port counter provides correct value for PortXmitWait.
> Otherwise the sysfs port_xmit_wait file always contains zero.
>
> The previous MAD_IFC implementation populated this counter, but it was
> removed during the migration to PPCNT for error counters (32-bit only).
>
> Signed-off-by: Tim Wright <tim-r/Uwd3QrhQcqdlJmJB21zg@public.gmane.org>
> ---
>  drivers/infiniband/hw/mlx5/mad.c | 2 ++
>  include/linux/mlx5/mlx5_ifc.h    | 4 +++-
>  2 files changed, 5 insertions(+), 1 deletion(-)
>

Thanks,
Acked-by: Leon Romanovsky <leonro-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [PATCH] xdp: use common helper for netlink extended ack reporting
From: Johannes Berg @ 2017-05-03  5:32 UTC (permalink / raw)
  To: Daniel Borkmann, davem; +Cc: jakub.kicinski, alexei.starovoitov, netdev
In-Reply-To: <9dc20d2c3cca095b42e730655c8fd9f5d59a4568.1493763990.git.daniel@iogearbox.net>

On Wed, 2017-05-03 at 00:39 +0200, Daniel Borkmann wrote:
> Small follow-up to d74a32acd59a ("xdp: use netlink extended ACK
> reporting")
> in order to let drivers all use the same NL_SET_ERR_MSG_MOD() helper
> macro
> for reporting. This also ensures that we consistently add the
> driver's
> prefix for dumping the report in user space to indicate that the
> error
> message is driver specific and not coming from core code.
> Furthermore,
> NL_SET_ERR_MSG_MOD() now reuses NL_SET_ERR_MSG() and thus makes all
> macros
> check the pointer as suggested.
> 
> References: https://www.spinics.net/lists/netdev/msg433267.html
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>

I did wonder about the whole _TRY_ thing. LGTM

Reviewed-by: Johannes Berg <johannes@sipsolutions.net>

johannes

^ permalink raw reply

* Re: [PATCH v4 net-next 00/10] net/ncsi: Add debugging functionality
From: David Miller @ 2017-05-03  5:25 UTC (permalink / raw)
  To: gwshan; +Cc: netdev, joe, kubakici, f.fainelli
In-Reply-To: <1493786681-27468-1-git-send-email-gwshan@linux.vnet.ibm.com>


Sorry, the net-next tree is closed right now as we are in the merge
window.

Please resubmit this when the net-next tree opens back up.

Thank you.

^ permalink raw reply

* [PATCH v4 net-next 05/10] net/ncsi: Ethtool operation to get NCSI channel info
From: Gavin Shan @ 2017-05-03  4:44 UTC (permalink / raw)
  To: netdev; +Cc: joe, kubakici, f.fainelli, davem, Gavin Shan
In-Reply-To: <1493786681-27468-1-git-send-email-gwshan@linux.vnet.ibm.com>

This adds ethtool command (ETHTOOL_GNCSICINFO) to retrieve the
NCSI channel information for the specified one. The simplified
output of this command is shown as follows from the modified
(private) ethtool:

 # ethtool --ncsi eth0 info
 NCSI channel 0:0 version:
   version:        00000000
   alpha2:         00000000
   f/w name:
   f/w version:    00000000
   PCI IDs:        0000 0000 0000 0000
   Manufacture ID: 00000000

   Generic capability:   0000000f (0000000f)
   Multicast capability: 00000007 (00000000)
   Buffer capability:    00004000
   AEN capability:       00000007 (00000000)
   VLAN capability:      00000007 (00000000)
   Filters:              VLAN (2), Mixed (0), MC (2), UC (4)

   Link status:             000ff66b 00000000 00000000
   MAC filter entries:
   00:00:00:00:00:00
   48:c4:b6:f0:a6:d4
   b6:fa:8f:70:00:00
   00:00:00:01:07:34
   VLAN filter entries:
   0004
   bc84

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 include/linux/ethtool.h      |   2 +
 include/uapi/linux/ethtool.h | 151 +++++++++++++++++++++++++++++++++++++++++++
 net/core/ethtool.c           |  22 +++++++
 net/ncsi/ncsi-ethtool.c      | 120 ++++++++++++++++++++++++++++++++++
 4 files changed, 295 insertions(+)

diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 720bb4d..5704b8b 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -376,5 +376,7 @@ struct ethtool_ops {
 				      const struct ethtool_link_ksettings *);
 	int	(*get_ncsi_channels)(struct net_device *,
 				     struct ethtool_ncsi_channels *);
+	int	(*get_ncsi_channel_info)(struct net_device *,
+					 struct ethtool_ncsi_channel_info *);
 };
 #endif /* _LINUX_ETHTOOL_H */
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index e43aacf..81fbd51 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -1332,6 +1332,7 @@ struct ethtool_per_queue_op {
 #define ETHTOOL_PHY_STUNABLE	0x0000004f /* Set PHY tunable configuration */
 
 #define ETHTOOL_GNCSICHANNELS	0x00000050 /* Get NCSI channels */
+#define ETHTOOL_GNCSICINFO	0x00000051 /* Get NCSI channel information */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET		ETHTOOL_GSET
@@ -1780,4 +1781,154 @@ struct ethtool_ncsi_channels {
 #define ETHTOOL_NCSI_CHANNEL_ACTIVE	(1 << 8)
 #define ETHTOOL_NCSI_CHANNEL_FLAGS	0x100
 };
+
+/**
+ * struct ethtool_ncsi_channel_info - NCSI channel information
+ *
+ * @cmd: Command number = %ETHTOOL_GNCSICINFO
+ * @id:  NCSI channel identifier
+ * @version: BCD encoded NCSI version
+ * @alpha2: BCD encoded NCSI version
+ * @fw_name: Firmware name string
+ * @fw_version: Firmware version
+ * @pci_ids: PCI identifier
+ * @mf_id: Manufacture identifier
+ * @cap_generic: Generic capability list
+ * @cap_bc: Broadcast capability list
+ * @setting_bc: Broadcast filtering setting
+ * @cap_mc: Multicast capability list
+ * @setting_mc: Multicast filtering setting
+ * @cap_buf: Length of receive buffer
+ * @cap_aen: AEN capability list
+ * @setting_aen: AEN setting
+ * @cap_vlan: VLAN filtering capability list
+ * @setting_vlan: VLAN filltering setting
+ * @cap_vlan_filter: Number of VLAN filtering entries
+ * @cap_mixed_filter: Number of mixed filtering entries
+ * @cap_mc_filter: Number of multicast filtering entries
+ * @cap_uc_filter: Number of unicast filtering entries
+ * @link_status: Link status
+ * @link_other_ind: Link other indication
+ * @link_oem: Link OEM information
+ * @mac_valid_bits: Bitmap for valid MAC filtering entries
+ * @mac: MAC filtering entries
+ * @vlan_valid_bits: Bitmap for valid VLAN filtering entries
+ * @vlan: VLAN filtering entries
+ */
+struct ethtool_ncsi_channel_info {
+	__u32	cmd;
+	__u32	id;
+	__u32	version;
+	__u32	alpha2;
+	__u8	fw_name[12];
+	__u32	fw_version;
+	__u16	pci_ids[4];
+	__u32	mf_id;
+	__u32	cap_generic;
+#define ETHTOOL_NCSI_G_HWA             (1 << 0) /* HW arbitration           */
+#define ETHTOOL_NCSI_G_HDS             (1 << 1) /* HNC driver status change */
+#define ETHTOOL_NCSI_G_FC              (1 << 2) /* HNC to MC flow control   */
+#define ETHTOOL_NCSI_G_FC1             (1 << 3) /* MC to HNC flow control   */
+#define ETHTOOL_NCSI_G_MC              (1 << 4) /* Global MC filtering      */
+#define ETHTOOL_NCSI_G_HWA_MASK        0x60
+#define ETHTOOL_NCSI_G_HWA_UNKNOWN     0x00     /* Unknown HW arbitration   */
+#define ETHTOOL_NCSI_G_HWA_SUPPORT     0x20     /* Supported HW arbitration */
+#define ETHTOOL_NCSI_G_HWA_NOT_SUPPORT 0x40     /* No HW arbitration        */
+#define ETHTOOL_NCSI_G_HWA_RESERVED    0x60     /* Reserved HW arbitration  */
+#define ETHTOOL_NCSI_G_MASK            0x7f
+	__u32	cap_bc;
+	__u32	setting_bc;
+#define ETHTOOL_NCSI_BC_ARP            (1 << 0) /* ARP packet filtering     */
+#define ETHTOOL_NCSI_BC_DHCPC          (1 << 1) /* DHCP client filtering    */
+#define ETHTOOL_NCSI_BC_DHCPS          (1 << 2) /* DHCP server filtering    */
+#define ETHTOOL_NCSI_BC_NETBIOS        (1 << 3) /* NetBIOS packet filtering */
+#define ETHTOOL_NCSI_BC_MASK           0xf
+	__u32	cap_mc;
+	__u32	setting_mc;
+#define ETHTOOL_NCSI_MC_IPV6_NEIGHBOR     (1 << 0) /* IPv6 neighbor filter  */
+#define ETHTOOL_NCSI_MC_IPV6_ROUTER       (1 << 1) /* IPv6 router filter    */
+#define ETHTOOL_NCSI_MC_DHCPV6_RELAY      (1 << 2) /* DHCPv6 relay/server   */
+#define ETHTOOL_NCSI_MC_DHCPV6_WELL_KNOWN (1 << 3) /* DHCPv6 well-known MC  */
+#define ETHTOOL_NCSI_MC_IPV6_MLD          (1 << 4) /* IPv6 MLD filtering    */
+#define ETHTOOL_NCSI_MC_IPV6_NEIGHBOR_S   (1 << 5) /* IPv6 neighbour filter */
+#define ETHTOOL_NCSI_MC_MASK              0x3f
+	__u32	cap_buf;
+	__u32	cap_aen;
+	__u32	setting_aen;
+#define ETHTOOL_NCSI_AEN_LSC           (1 << 0) /* Link status change       */
+#define ETHTOOL_NCSI_AEN_CR            (1 << 1) /* Configuration required   */
+#define ETHTOOL_NCSI_AEN_HDS           (1 << 2) /* HNC driver status        */
+#define ETHTOOL_NCSI_AEN_MASK          0x07
+	__u32	cap_vlan;
+	__u32	setting_vlan;
+#define ETHTOOL_NCSI_VLAN_ONLY         (1 << 0) /* Filter VLAN packet only  */
+#define ETHTOOL_NCSI_VLAN_NO           (1 << 1) /* Filter VLAN and non-VLAN */
+#define ETHTOOL_NCSI_VLAN_ANY          (1 << 2) /* Filter Any-and-non-VLAN  */
+#define ETHTOOL_NCSI_VLAN_MASK         0x07
+	__u8	cap_vlan_filter;
+	__u8	cap_mixed_filter;
+	__u8	cap_mc_filter;
+	__u8	cap_uc_filter;
+	__u32	link_status;
+#define ETHTOOL_NCSI_LINK_UP               (1 << 0)  /* Link up or down       */
+#define ETHTOOL_NCSI_LINK_SPEED_MASK       0x1e      /* Link speed            */
+#define ETHTOOL_NCSI_LINK_SPEED_INVALID         0x0
+#define ETHTOOL_NCSI_LINK_SPEED_10BASE_T_H      0x2
+#define ETHTOOL_NCSI_LINK_SPEED_10BASE_T_F      0x4
+#define ETHTOOL_NCSI_LINK_SPEED_100BASE_TX_H    0x6
+#define ETHTOOL_NCSI_LINK_SPEED_100BASE_T4      0x8
+#define ETHTOOL_NCSI_LINK_SPEED_100BASE_TX_F    0xa
+#define ETHTOOL_NCSI_LINK_SPEED_1000BASE_T_H    0xc
+#define ETHTOOL_NCSI_LINK_SPEED_1000BASE_T_F    0xe
+#define ETHTOOL_NCSI_LINK_SPEED_10GBASE_T       0x10
+#define ETHTOOL_NCSI_LINK_SPEED_20G             0x12
+#define ETHTOOL_NCSI_LINK_SPEED_25G             0x14
+#define ETHTOOL_NCSI_LINK_SPEED_40G             0x16
+#define ETHTOOL_NCSI_LINK_SPEED_50G             0x18
+#define ETHTOOL_NCSI_LINK_SPEED_100G            0x1a
+#define ETHTOOL_NCSI_LINK_SPEED_2_5G            0x1c
+#define ETHTOOL_NCSI_LINK_SPEED_OPTIONAL        0x1e
+#define ETHTOOL_NCSI_LINK_AUTONEG_ENABLED  (1 << 5)  /* Enabled auto-neg      */
+#define ETHTOOL_NCSI_LINK_AUTONEG_DONE     (1 << 6)  /* Auto-neg is done      */
+#define ETHTOOL_NCSI_LINK_PARALLEL         (1 << 7)  /* Parallel detection    */
+#define ETHTOOL_NCSI_LINK_LPA_1000BASE_T_F (1 << 9)  /* LPA: 1000BASE_T_Full  */
+#define ETHTOOL_NCSI_LINK_LPA_1000BASE_T_H (1 << 10) /* LPA: 1000BASE_T_Half  */
+#define ETHTOOL_NCSI_LINK_LPA_100_T4       (1 << 11) /* LPA: 100T4            */
+#define ETHTOOL_NCSI_LINK_LPA_100BASE_TX_F (1 << 12) /* LPA: 100BASE_TX_Full  */
+#define ETHTOOL_NCSI_LINK_LPA_100BASE_TX_H (1 << 13) /* LPA: 100BASE_TX_Half  */
+#define ETHTOOL_NCSI_LINK_LPA_10BASE_T_F   (1 << 14) /* LPA: 10BASE_T_Full    */
+#define ETHTOOL_NCSI_LINK_LPA_10BASE_T_H   (1 << 15) /* LPA: 10BASE_T_Half    */
+#define ETHTOOL_NCSI_LINK_TX_FC            (1 << 16) /* Tx flow control       */
+#define ETHTOOL_NCSI_LINK_RX_FC            (1 << 17) /* Rx flow control       */
+#define ETHTOOL_NCSI_LINK_LPA_FC_MASK      0xc0000
+#define ETHTOOL_NCSI_LINK_LPA_FC_NONE      0x0
+#define ETHTOOL_NCSI_LINK_LPA_FC_SYNC      0x40000
+#define ETHTOOL_NCSI_LINK_LPA_FC_ASYNC     0x80000
+#define ETHTOOL_NCSI_LINK_SERDES           (1 << 20) /* SerDes used or not    */
+#define ETHTOOL_NCSI_LINK_OEM_VALID        (1 << 21)
+#define ETHTOOL_NCSI_LINK_ESPEED_MASK      0xff000000
+#define ETHTOOL_NCSI_LINK_ESPEED_INVALID          0x0
+#define ETHTOOL_NCSI_LINK_ESPEED_10BASE_T_H       0x01000000
+#define ETHTOOL_NCSI_LINK_ESPEED_10BASE_T_F       0x02000000
+#define ETHTOOL_NCSI_LINK_ESPEED_100BASE_TX_H     0x03000000
+#define ETHTOOL_NCSI_LINK_ESPEED_100BASE_T4       0x04000000
+#define ETHTOOL_NCSI_LINK_ESPEED_100BASE_TX_F     0x05000000
+#define ETHTOOL_NCSI_LINK_ESPEED_1000BASE_T_H     0x06000000
+#define ETHTOOL_NCSI_LINK_ESPEED_1000BASE_T_F     0x07000000
+#define ETHTOOL_NCSI_LINK_ESPEED_10GBASE_T        0x08000000
+#define ETHTOOL_NCSI_LINK_ESPEED_20G              0x09000000
+#define ETHTOOL_NCSI_LINK_ESPEED_25G              0x0a000000
+#define ETHTOOL_NCSI_LINK_ESPEED_40G              0x0b000000
+#define ETHTOOL_NCSI_LINK_ESPEED_50G              0x0c000000
+#define ETHTOOL_NCSI_LINK_ESPEED_100G             0x0d000000
+#define ETHTOOL_NCSI_LINK_ESPEED_2_5G             0x0e000000
+#define ETHTOOL_NCSI_LINK_ESPEED_OPTIONAL         0x0f000000
+	__u32	link_other_ind;
+#define ETHTOOL_NCSI_LINK_HNC_DRV_STATUS   (1 << 0)
+	__u32	link_oem;
+	__u32	mac_valid_bits;
+	__u8	mac[8][6];
+	__u32	vlan_valid_bits;
+	__u16	vlan[16];
+};
 #endif /* _UAPI_LINUX_ETHTOOL_H */
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 7644765..116ef10 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -793,6 +793,25 @@ static int ethtool_get_ncsi_channels(struct net_device *dev,
 	return ret;
 }
 
+static int ethtool_get_ncsi_channel_info(struct net_device *dev,
+					 void __user *useraddr)
+{
+	struct ethtool_ncsi_channel_info enci;
+	int ret;
+
+	if (!dev->ethtool_ops->get_ncsi_channel_info)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&enci, useraddr, sizeof(enci)))
+		return -EFAULT;
+
+	ret = dev->ethtool_ops->get_ncsi_channel_info(dev, &enci);
+	if (!ret && copy_to_user(useraddr, &enci, sizeof(enci)))
+		return -EFAULT;
+
+	return ret;
+}
+
 static void
 warn_incomplete_ethtool_legacy_settings_conversion(const char *details)
 {
@@ -2833,6 +2852,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
 	case ETHTOOL_GNCSICHANNELS:
 		rc = ethtool_get_ncsi_channels(dev, useraddr);
 		break;
+	case ETHTOOL_GNCSICINFO:
+		rc = ethtool_get_ncsi_channel_info(dev, useraddr);
+		break;
 	default:
 		rc = -EOPNOTSUPP;
 	}
diff --git a/net/ncsi/ncsi-ethtool.c b/net/ncsi/ncsi-ethtool.c
index 747aab6..9eee5fb 100644
--- a/net/ncsi/ncsi-ethtool.c
+++ b/net/ncsi/ncsi-ethtool.c
@@ -57,6 +57,124 @@ static int ncsi_get_channels(struct net_device *dev,
 	return 0;
 }
 
+static int ncsi_get_channel_info(struct net_device *dev,
+				 struct ethtool_ncsi_channel_info *enci)
+{
+	struct ncsi_dev *nd;
+	struct ncsi_dev_priv *ndp;
+	struct ncsi_channel *nc;
+	unsigned long flags;
+	int i;
+
+	nd = ncsi_find_dev(dev);
+	if (!nd)
+		return -ENXIO;
+
+	ndp = TO_NCSI_DEV_PRIV(nd);
+	ncsi_find_package_and_channel(ndp, enci->id, NULL, &nc);
+	if (!nc)
+		return -ENXIO;
+
+	spin_lock_irqsave(&nc->lock, flags);
+
+	/* NCSI channel's version */
+	enci->version = nc->version.version;
+	enci->alpha2 = nc->version.alpha2;
+	memcpy(enci->fw_name, nc->version.fw_name, 12);
+	enci->fw_version = nc->version.fw_version;
+	memcpy(enci->pci_ids, nc->version.pci_ids,
+	       4 * sizeof(enci->pci_ids[0]));
+	enci->mf_id = nc->version.mf_id;
+
+	/* NCSI channel's capabilities */
+	enci->cap_generic = (nc->caps[NCSI_CAP_GENERIC].cap &
+			     ETHTOOL_NCSI_G_MASK);
+	enci->cap_bc = (nc->caps[NCSI_CAP_BC].cap &
+			ETHTOOL_NCSI_BC_MASK);
+	enci->cap_mc = (nc->caps[NCSI_CAP_MC].cap &
+			ETHTOOL_NCSI_MC_MASK);
+	enci->cap_buf = nc->caps[NCSI_CAP_BUFFER].cap;
+	enci->cap_aen = (nc->caps[NCSI_CAP_AEN].cap &
+			 ETHTOOL_NCSI_AEN_MASK);
+	enci->cap_vlan = (nc->caps[NCSI_CAP_VLAN].cap &
+			  ETHTOOL_NCSI_VLAN_MASK);
+	for (i = NCSI_FILTER_BASE; i < NCSI_FILTER_MAX; i++) {
+		struct ncsi_channel_filter *ncf;
+		unsigned char *p_cap_filter;
+		unsigned int *p_valid_bits;
+		int entry_size, s_idx, d_idx;
+		void *dest;
+
+		switch (i) {
+		case NCSI_FILTER_VLAN:
+			p_cap_filter = &enci->cap_vlan_filter;
+			entry_size = 2;
+			p_valid_bits = &enci->vlan_valid_bits;
+			dest = enci->vlan;
+			d_idx = 0;
+			break;
+		case NCSI_FILTER_UC:
+			p_cap_filter = &enci->cap_uc_filter;
+			entry_size = 6;
+			p_valid_bits = &enci->mac_valid_bits;
+			dest = enci->mac;
+			d_idx = 0;
+			break;
+		case NCSI_FILTER_MC:
+			p_cap_filter = &enci->cap_mc_filter;
+			entry_size = 6;
+			break;
+		case NCSI_FILTER_MIXED:
+			p_cap_filter = &enci->cap_mixed_filter;
+			entry_size = 6;
+			break;
+		default:
+			continue;
+		}
+
+		*p_cap_filter = 0;
+		ncf = nc->filters[i];
+		if (!ncf)
+			continue;
+
+		*p_cap_filter = ncf->total;
+		s_idx = -1;
+		while ((s_idx = find_next_bit((void *)&ncf->bitmap,
+					      ncf->total, s_idx + 1))
+			< ncf->total) {
+			memcpy(dest + (d_idx * entry_size),
+			       ((void *)(ncf->data)) + (s_idx * entry_size),
+			       entry_size);
+			*p_valid_bits |= (1 << d_idx);
+
+			d_idx++;
+		}
+	}
+
+	/* NCSI channel's settings */
+	enci->setting_bc = nc->modes[NCSI_MODE_BC].enable ?
+			   nc->modes[NCSI_MODE_BC].data[0] : 0;
+	enci->setting_bc &= ETHTOOL_NCSI_BC_MASK;
+	enci->setting_mc = nc->modes[NCSI_MODE_MC].enable ?
+			   nc->modes[NCSI_MODE_MC].data[0] : 0;
+	enci->setting_mc &= ETHTOOL_NCSI_MC_MASK;
+	enci->setting_aen = nc->modes[NCSI_MODE_AEN].enable ?
+			    nc->modes[NCSI_MODE_AEN].data[0] : 0;
+	enci->setting_aen &= ETHTOOL_NCSI_AEN_MASK;
+	enci->setting_vlan = nc->modes[NCSI_MODE_VLAN].enable ?
+			     nc->modes[NCSI_MODE_VLAN].data[0] : 0;
+	enci->setting_vlan &= ETHTOOL_NCSI_VLAN_MASK;
+
+	/* NCSI channel's link status */
+	enci->link_status = nc->modes[NCSI_MODE_LINK].data[2];
+	enci->link_other_ind = nc->modes[NCSI_MODE_LINK].data[3];
+	enci->link_oem = nc->modes[NCSI_MODE_LINK].data[4];
+
+	spin_unlock_irqrestore(&nc->lock, flags);
+
+	return 0;
+}
+
 void ncsi_ethtool_register_dev(struct net_device *dev)
 {
 	struct ethtool_ops *ops;
@@ -66,6 +184,7 @@ void ncsi_ethtool_register_dev(struct net_device *dev)
 		return;
 
 	ops->get_ncsi_channels = ncsi_get_channels;
+	ops->get_ncsi_channel_info = ncsi_get_channel_info;
 }
 
 void ncsi_ethtool_unregister_dev(struct net_device *dev)
@@ -77,4 +196,5 @@ void ncsi_ethtool_unregister_dev(struct net_device *dev)
 		return;
 
 	ops->get_ncsi_channels = NULL;
+	ops->get_ncsi_channel_info = NULL;
 }
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 net-next 06/10] net/ncsi: Ethtool operation to get NCSI hw statistics
From: Gavin Shan @ 2017-05-03  4:44 UTC (permalink / raw)
  To: netdev; +Cc: joe, kubakici, f.fainelli, davem, Gavin Shan
In-Reply-To: <1493786681-27468-1-git-send-email-gwshan@linux.vnet.ibm.com>

This adds ethtool command (ETHTOOL_GNCSISTATS) to retrieve the
NCSI hardware statistics. The simplified output of this command is
shown as follows from the modified (private) ethtool. It's obvious
the HW statistics isn't fetched from hardware yet, which is to be
sorted out later.

 # ethtool --ncsi eth0 stats
 NCSI statistics as below

   hnc_cnt_hi:           0
   hnc_cnt_lo:           0
   hnc_rx_bytes:         0
   hnc_tx_bytes:         0
   hnc_rx_uc_pkts:       0
   hnc_rx_mc_pkts:       0
   hnc_rx_bc_pkts:       0
   hnc_tx_uc_pkts:       0
   hnc_tx_mc_pkts:       0
   hnc_tx_bc_pkts:       0
   hnc_fcs_err:          0
   hnc_align_err:        0
   hnc_false_carrier:    0
   hnc_runt_pkts:        0
   hnc_jabber_pkts:      0
   hnc_rx_pause_xon:     0
   hnc_rx_pause_xoff:    0
   hnc_tx_pause_xon:     0
   hnc_tx_pause_xoff:    0
   hnc_tx_s_collision:   0
   hnc_tx_m_collision:   0
   hnc_l_collision:      0
   hnc_e_collision:      0
   hnc_rx_ctl_frames:    0
   hnc_rx_64_frames:     0
   hnc_rx_127_frames:    0
   hnc_rx_255_frames:    0
   hnc_rx_511_frames:    0
   hnc_rx_1023_frames:   0
   hnc_rx_1522_frames:   0
   hnc_rx_9022_frames:   0
   hnc_tx_64_frames:     0
   hnc_tx_127_frames:    0
   hnc_tx_255_frames:    0
   hnc_tx_511_frames:    0
   hnc_tx_1023_frames:   0
   hnc_tx_1522_frames:   0
   hnc_tx_9022_frames:   0
   hnc_rx_valid_bytes:   0
   hnc_rx_runt_pkts:     0
   hnc_rx_jabber_pkts:   0
   ncsi_rx_cmds:         0
   ncsi_dropped_cmds:    0
   ncsi_cmd_type_errs:   0
   ncsi_cmd_csum_errs:   0
   ncsi_rx_pkts:         0
   ncsi_tx_pkts:         0
   ncsi_tx_aen_pkts:     0
   pt_tx_pkts:           0
   pt_tx_dropped:        0
   pt_tx_channel_err:    0
   pt_tx_us_err:         0
   pt_rx_pkts:           0
   pt_rx_dropped:        0
   pt_rx_channel_err:    0
   pt_rx_us_err:         0
   pt_rx_os_err:         0

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 include/linux/ethtool.h      |   2 +
 include/uapi/linux/ethtool.h | 124 +++++++++++++++++++++++++++++++++++++++++++
 net/core/ethtool.c           |  29 ++++++++++
 net/ncsi/ncsi-ethtool.c      |  87 ++++++++++++++++++++++++++++++
 4 files changed, 242 insertions(+)

diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 5704b8b..6d712ca 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -378,5 +378,7 @@ struct ethtool_ops {
 				     struct ethtool_ncsi_channels *);
 	int	(*get_ncsi_channel_info)(struct net_device *,
 					 struct ethtool_ncsi_channel_info *);
+	int	(*get_ncsi_stats)(struct net_device *,
+				  struct ethtool_ncsi_stats *);
 };
 #endif /* _LINUX_ETHTOOL_H */
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index 81fbd51..472773c 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -1333,6 +1333,7 @@ struct ethtool_per_queue_op {
 
 #define ETHTOOL_GNCSICHANNELS	0x00000050 /* Get NCSI channels */
 #define ETHTOOL_GNCSICINFO	0x00000051 /* Get NCSI channel information */
+#define ETHTOOL_GNCSISTATS	0x00000052 /* Get NCSI HW statistics */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET		ETHTOOL_GSET
@@ -1931,4 +1932,127 @@ struct ethtool_ncsi_channel_info {
 	__u32	vlan_valid_bits;
 	__u16	vlan[16];
 };
+
+/**
+ * struct ethtool_ncsi_stats - NCSI hardware statistics
+ *
+ * @cmd: Command number = %ETHTOOL_GNCSISTATS
+ * @hnc_cnt_hi: Counter cleared
+ * @hnc_cnt_lo: Counter cleared
+ * @hnc_rx_bytes: Rx bytes
+ * @hnc_tx_bytes: Tx bytes
+ * @hnc_rx_uc_pkts: Rx UC packets
+ * @hnc_rx_mc_pkts: Rx MC packets
+ * @hnc_rx_bc_pkts: Rx BC packets
+ * @hnc_tx_uc_pkts: Tx UC packets
+ * @hnc_tx_mc_pkts: Tx MC packets
+ * @hnc_tx_bc_pkts: Tx BC packets
+ * @hnc_fcs_err: FCS errors
+ * @hnc_align_err: Alignment errors
+ * @hnc_false_carrier: False carrier detection
+ * @hnc_runt_pkts: Rx runt packets
+ * @hnc_jabber_pkts: Rx jabber packets
+ * @hnc_rx_pause_xon: Rx pause XON frames
+ * @hnc_rx_pause_xoff: Rx XOFF frames
+ * @hnc_tx_pause_xon: Tx XON frames
+ * @hnc_tx_pause_xoff: Tx XOFF frames
+ * @hnc_tx_s_collision: Single collision frames
+ * @hnc_tx_m_collision: Multiple collision frames
+ * @hnc_l_collision: Late collision frames
+ * @hnc_e_collision: Excessive collision frames
+ * @hnc_rx_ctl_frames: Rx control frames
+ * @hnc_rx_64_frames: Rx 64-bytes frames
+ * @hnc_rx_127_frames: Rx 65-127 bytes frames
+ * @hnc_rx_255_frames: Rx 128-255 bytes frames
+ * @hnc_rx_511_frames: Rx 256-511 bytes frames
+ * @hnc_rx_1023_frames: Rx 512-1023 bytes frames
+ * @hnc_rx_1522_frames: Rx 1024-1522 bytes frames
+ * @hnc_rx_9022_frames: Rx 1523-9022 bytes frames
+ * @hnc_tx_64_frames: Tx 64-bytes frames
+ * @hnc_tx_127_frames: Tx 65-127 bytes frames
+ * @hnc_tx_255_frames: Tx 128-255 bytes frames
+ * @hnc_tx_511_frames: Tx 256-511 bytes frames
+ * @hnc_tx_1023_frames: Tx 512-1023 bytes frames
+ * @hnc_tx_1522_frames: Tx 1024-1522 bytes frames
+ * @hnc_tx_9022_frames: Tx 1523-9022 bytes frames
+ * @hnc_rx_valid_bytes: Rx valid bytes
+ * @hnc_rx_runt_pkts: Rx error runt packets
+ * @hnc_rx_jabber_pkts: Rx error jabber packets
+ * @ncsi_rx_cmds: Rx NCSI commands
+ * @ncsi_dropped_cmds: Dropped commands
+ * @ncsi_cmd_type_errs: Command type errors
+ * @ncsi_cmd_csum_errs: Command checksum errors
+ * @ncsi_rx_pkts: Rx NCSI packets
+ * @ncsi_tx_pkts: Tx NCSI packets
+ * @ncsi_tx_aen_pkts: Tx AEN packets
+ * @pt_tx_pkts: Tx packets
+ * @pt_tx_dropped: Tx dropped packets
+ * @pt_tx_channel_err: Tx channel errors
+ * @pt_tx_us_err: Tx undersize errors
+ * @pt_rx_pkts: Rx packets
+ * @pt_rx_dropped: Rx dropped packets
+ * @pt_rx_channel_err: Rx channel errors
+ * @pt_rx_us_err: Rx undersize errors
+ * @pt_rx_os_err: Rx oversize errors
+ */
+struct ethtool_ncsi_stats {
+	__u32	cmd;
+	__u64	hnc_cnt_hi;
+	__u64	hnc_cnt_lo;
+	__u64	hnc_rx_bytes;
+	__u64	hnc_tx_bytes;
+	__u64	hnc_rx_uc_pkts;
+	__u64	hnc_rx_mc_pkts;
+	__u64	hnc_rx_bc_pkts;
+	__u64	hnc_tx_uc_pkts;
+	__u64	hnc_tx_mc_pkts;
+	__u64	hnc_tx_bc_pkts;
+	__u64	hnc_fcs_err;
+	__u64	hnc_align_err;
+	__u64	hnc_false_carrier;
+	__u64	hnc_runt_pkts;
+	__u64	hnc_jabber_pkts;
+	__u64	hnc_rx_pause_xon;
+	__u64	hnc_rx_pause_xoff;
+	__u64	hnc_tx_pause_xon;
+	__u64	hnc_tx_pause_xoff;
+	__u64	hnc_tx_s_collision;
+	__u64	hnc_tx_m_collision;
+	__u64	hnc_l_collision;
+	__u64	hnc_e_collision;
+	__u64	hnc_rx_ctl_frames;
+	__u64	hnc_rx_64_frames;
+	__u64	hnc_rx_127_frames;
+	__u64	hnc_rx_255_frames;
+	__u64	hnc_rx_511_frames;
+	__u64	hnc_rx_1023_frames;
+	__u64	hnc_rx_1522_frames;
+	__u64	hnc_rx_9022_frames;
+	__u64	hnc_tx_64_frames;
+	__u64	hnc_tx_127_frames;
+	__u64	hnc_tx_255_frames;
+	__u64	hnc_tx_511_frames;
+	__u64	hnc_tx_1023_frames;
+	__u64	hnc_tx_1522_frames;
+	__u64	hnc_tx_9022_frames;
+	__u64	hnc_rx_valid_bytes;
+	__u64	hnc_rx_runt_pkts;
+	__u64	hnc_rx_jabber_pkts;
+	__u64	ncsi_rx_cmds;
+	__u64	ncsi_dropped_cmds;
+	__u64	ncsi_cmd_type_errs;
+	__u64	ncsi_cmd_csum_errs;
+	__u64	ncsi_rx_pkts;
+	__u64	ncsi_tx_pkts;
+	__u64	ncsi_tx_aen_pkts;
+	__u64	pt_tx_pkts;
+	__u64	pt_tx_dropped;
+	__u64	pt_tx_channel_err;
+	__u64	pt_tx_us_err;
+	__u64	pt_rx_pkts;
+	__u64	pt_rx_dropped;
+	__u64	pt_rx_channel_err;
+	__u64	pt_rx_us_err;
+	__u64	pt_rx_os_err;
+};
 #endif /* _UAPI_LINUX_ETHTOOL_H */
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 116ef10..f26aa36 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -812,6 +812,32 @@ static int ethtool_get_ncsi_channel_info(struct net_device *dev,
 	return ret;
 }
 
+static int ethtool_get_ncsi_stats(struct net_device *dev,
+				  void __user *useraddr)
+{
+	struct ethtool_ncsi_stats *ens;
+	int ret;
+
+	if (!dev->ethtool_ops->get_ncsi_stats)
+		return -EOPNOTSUPP;
+
+	ens = kzalloc(sizeof(*ens), GFP_KERNEL);
+	if (!ens)
+		return -ENOMEM;
+
+	if (copy_from_user(ens, useraddr, sizeof(*ens))) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	ret = dev->ethtool_ops->get_ncsi_stats(dev, ens);
+	if (!ret && copy_to_user(useraddr, ens, sizeof(*ens)))
+		ret = -EFAULT;
+out:
+	kfree(ens);
+	return ret;
+}
+
 static void
 warn_incomplete_ethtool_legacy_settings_conversion(const char *details)
 {
@@ -2855,6 +2881,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
 	case ETHTOOL_GNCSICINFO:
 		rc = ethtool_get_ncsi_channel_info(dev, useraddr);
 		break;
+	case ETHTOOL_GNCSISTATS:
+		rc = ethtool_get_ncsi_stats(dev, useraddr);
+		break;
 	default:
 		rc = -EOPNOTSUPP;
 	}
diff --git a/net/ncsi/ncsi-ethtool.c b/net/ncsi/ncsi-ethtool.c
index 9eee5fb..1ccdb50 100644
--- a/net/ncsi/ncsi-ethtool.c
+++ b/net/ncsi/ncsi-ethtool.c
@@ -175,6 +175,91 @@ static int ncsi_get_channel_info(struct net_device *dev,
 	return 0;
 }
 
+static int ncsi_get_stats(struct net_device *dev,
+			  struct ethtool_ncsi_stats *ens)
+{
+	struct ncsi_dev *nd;
+	struct ncsi_dev_priv *ndp;
+	struct ncsi_package *np;
+	struct ncsi_channel *nc;
+	struct ncsi_channel_stats *ncs;
+	unsigned long flags;
+
+	nd = ncsi_find_dev(dev);
+	if (!nd)
+		return -ENXIO;
+
+	ndp = TO_NCSI_DEV_PRIV(nd);
+	NCSI_FOR_EACH_PACKAGE(ndp, np) {
+		NCSI_FOR_EACH_CHANNEL(np, nc) {
+			spin_lock_irqsave(&nc->lock, flags);
+
+			ncs = &nc->stats;
+			ens->hnc_cnt_hi += ncs->hnc_cnt_hi;
+			ens->hnc_cnt_lo += ncs->hnc_cnt_lo;
+			ens->hnc_rx_bytes += ncs->hnc_rx_bytes;
+			ens->hnc_tx_bytes += ncs->hnc_tx_bytes;
+			ens->hnc_rx_uc_pkts += ncs->hnc_rx_uc_pkts;
+			ens->hnc_rx_mc_pkts += ncs->hnc_rx_mc_pkts;
+			ens->hnc_rx_bc_pkts += ncs->hnc_rx_bc_pkts;
+			ens->hnc_tx_uc_pkts += ncs->hnc_tx_uc_pkts;
+			ens->hnc_tx_mc_pkts += ncs->hnc_tx_mc_pkts;
+			ens->hnc_tx_bc_pkts += ncs->hnc_tx_bc_pkts;
+			ens->hnc_fcs_err += ncs->hnc_fcs_err;
+			ens->hnc_align_err += ncs->hnc_align_err;
+			ens->hnc_false_carrier += ncs->hnc_false_carrier;
+			ens->hnc_runt_pkts += ncs->hnc_runt_pkts;
+			ens->hnc_jabber_pkts += ncs->hnc_jabber_pkts;
+			ens->hnc_rx_pause_xon += ncs->hnc_rx_pause_xon;
+			ens->hnc_rx_pause_xoff += ncs->hnc_rx_pause_xoff;
+			ens->hnc_tx_pause_xon += ncs->hnc_tx_pause_xon;
+			ens->hnc_tx_pause_xoff += ncs->hnc_tx_pause_xoff;
+			ens->hnc_tx_s_collision += ncs->hnc_tx_s_collision;
+			ens->hnc_tx_m_collision += ncs->hnc_tx_m_collision;
+			ens->hnc_l_collision += ncs->hnc_l_collision;
+			ens->hnc_e_collision += ncs->hnc_e_collision;
+			ens->hnc_rx_ctl_frames += ncs->hnc_rx_ctl_frames;
+			ens->hnc_rx_64_frames += ncs->hnc_rx_64_frames;
+			ens->hnc_rx_127_frames += ncs->hnc_rx_127_frames;
+			ens->hnc_rx_255_frames += ncs->hnc_rx_255_frames;
+			ens->hnc_rx_511_frames += ncs->hnc_rx_511_frames;
+			ens->hnc_rx_1023_frames += ncs->hnc_rx_1023_frames;
+			ens->hnc_rx_1522_frames += ncs->hnc_rx_1522_frames;
+			ens->hnc_rx_9022_frames += ncs->hnc_rx_9022_frames;
+			ens->hnc_tx_64_frames += ncs->hnc_tx_64_frames;
+			ens->hnc_tx_127_frames += ncs->hnc_tx_127_frames;
+			ens->hnc_tx_255_frames += ncs->hnc_tx_255_frames;
+			ens->hnc_tx_511_frames += ncs->hnc_tx_511_frames;
+			ens->hnc_tx_1023_frames += ncs->hnc_tx_1023_frames;
+			ens->hnc_tx_1522_frames += ncs->hnc_tx_1522_frames;
+			ens->hnc_tx_9022_frames += ncs->hnc_tx_9022_frames;
+			ens->hnc_rx_valid_bytes += ncs->hnc_rx_valid_bytes;
+			ens->hnc_rx_runt_pkts += ncs->hnc_rx_runt_pkts;
+			ens->hnc_rx_jabber_pkts += ncs->hnc_rx_jabber_pkts;
+			ens->ncsi_rx_cmds += ncs->ncsi_rx_cmds;
+			ens->ncsi_dropped_cmds += ncs->ncsi_dropped_cmds;
+			ens->ncsi_cmd_type_errs += ncs->ncsi_cmd_type_errs;
+			ens->ncsi_cmd_csum_errs += ncs->ncsi_cmd_csum_errs;
+			ens->ncsi_rx_pkts += ncs->ncsi_rx_pkts;
+			ens->ncsi_tx_pkts += ncs->ncsi_tx_pkts;
+			ens->ncsi_tx_aen_pkts += ncs->ncsi_tx_aen_pkts;
+			ens->pt_tx_pkts += ncs->pt_tx_pkts;
+			ens->pt_tx_dropped += ncs->pt_tx_dropped;
+			ens->pt_tx_channel_err += ncs->pt_tx_channel_err;
+			ens->pt_tx_us_err += ncs->pt_tx_us_err;
+			ens->pt_rx_pkts += ncs->pt_rx_pkts;
+			ens->pt_rx_dropped += ncs->pt_rx_dropped;
+			ens->pt_rx_channel_err += ncs->pt_rx_channel_err;
+			ens->pt_rx_us_err += ncs->pt_rx_us_err;
+			ens->pt_rx_os_err += ncs->pt_rx_os_err;
+
+			spin_unlock_irqrestore(&nc->lock, flags);
+		}
+	}
+
+	return 0;
+}
+
 void ncsi_ethtool_register_dev(struct net_device *dev)
 {
 	struct ethtool_ops *ops;
@@ -185,6 +270,7 @@ void ncsi_ethtool_register_dev(struct net_device *dev)
 
 	ops->get_ncsi_channels = ncsi_get_channels;
 	ops->get_ncsi_channel_info = ncsi_get_channel_info;
+	ops->get_ncsi_stats = ncsi_get_stats;
 }
 
 void ncsi_ethtool_unregister_dev(struct net_device *dev)
@@ -197,4 +283,5 @@ void ncsi_ethtool_unregister_dev(struct net_device *dev)
 
 	ops->get_ncsi_channels = NULL;
 	ops->get_ncsi_channel_info = NULL;
+	ops->get_ncsi_stats = NULL;
 }
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 net-next 07/10] net/ncsi: Ethtool operation to get NCSI sw statistics
From: Gavin Shan @ 2017-05-03  4:44 UTC (permalink / raw)
  To: netdev; +Cc: joe, kubakici, f.fainelli, davem, Gavin Shan
In-Reply-To: <1493786681-27468-1-git-send-email-gwshan@linux.vnet.ibm.com>

This adds ethtool command (ETHTOOL_GNCSISWSTATS) to retrieve the
NCSI software statistics. The simplified output of this command is
shown as follows from the modified (private) ethtool.

 COMMAND      OK       TIMEOUT  ERROR
 ====================================
 CIS          32       29       0
 SP           10       7        0
 DP           17       14       0
 EC           1        0        0
 ECNT         1        0        0
 AE           1        0        0
 GLS          10       0        0
 SMA          1        0        0
 DBF          1        0        0
 GC           2        0        0
 GP           2        0        0

 RESPONSE     OK       TIMEOUT  ERROR
 ====================================
 CIS          3        0        0
 SP           3        0        0
 DP           2        0        1
 EC           1        0        0
 ECNT         1        0        0
 AE           1        0        0
 GLS          10       0        0
 SMA          1        0        0
 DBF          1        0        0
 GC           0        0        2
 GP           2        0        0

 AEN          OK       TIMEOUT  ERROR
 ====================================

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 include/linux/ethtool.h      |  2 ++
 include/uapi/linux/ethtool.h | 20 ++++++++++++++++++++
 net/core/ethtool.c           | 29 ++++++++++++++++++++++++++++
 net/ncsi/Kconfig             |  9 +++++++++
 net/ncsi/Makefile            |  1 +
 net/ncsi/internal.h          | 13 +++++++++++++
 net/ncsi/ncsi-aen.c          | 14 +++++++++++++-
 net/ncsi/ncsi-cmd.c          | 12 +++++++++++-
 net/ncsi/ncsi-debug.c        | 45 ++++++++++++++++++++++++++++++++++++++++++++
 net/ncsi/ncsi-ethtool.c      | 34 +++++++++++++++++++++++++++++++++
 net/ncsi/ncsi-manage.c       |  4 ++++
 net/ncsi/ncsi-rsp.c          | 19 ++++++++++++++++++-
 12 files changed, 199 insertions(+), 3 deletions(-)
 create mode 100644 net/ncsi/ncsi-debug.c

diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 6d712ca..eb57142 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -380,5 +380,7 @@ struct ethtool_ops {
 					 struct ethtool_ncsi_channel_info *);
 	int	(*get_ncsi_stats)(struct net_device *,
 				  struct ethtool_ncsi_stats *);
+	int	(*get_ncsi_sw_stats)(struct net_device *,
+				     struct ethtool_ncsi_sw_stats *);
 };
 #endif /* _LINUX_ETHTOOL_H */
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index 472773c..bf6fa2b 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -1334,6 +1334,7 @@ struct ethtool_per_queue_op {
 #define ETHTOOL_GNCSICHANNELS	0x00000050 /* Get NCSI channels */
 #define ETHTOOL_GNCSICINFO	0x00000051 /* Get NCSI channel information */
 #define ETHTOOL_GNCSISTATS	0x00000052 /* Get NCSI HW statistics */
+#define ETHTOOL_GNCSISWSTATS	0x00000053 /* Get NCSI software statistics */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET		ETHTOOL_GSET
@@ -2055,4 +2056,23 @@ struct ethtool_ncsi_stats {
 	__u64	pt_rx_us_err;
 	__u64	pt_rx_os_err;
 };
+
+/**
+ * struct ethtool_ncsi_sw_stats - NCSI software statistics
+ *
+ * @cmd: Command number = %ETHTOOL_GNCSISWSTATS
+ * @command: Statistics for sent command packets
+ * @response: Statistics for received response packets
+ * @aen: Statistics for received AEN packets
+ */
+struct ethtool_ncsi_sw_stats {
+	__u32	cmd;
+#define ETHTOOL_NCSI_SW_STAT_OK		0
+#define ETHTOOL_NCSI_SW_STAT_TIMEOUT	1
+#define ETHTOOL_NCSI_SW_STAT_ERROR	2
+#define ETHTOOL_NCSI_SW_STAT_MAX	3
+	__u64	command[128][ETHTOOL_NCSI_SW_STAT_MAX];
+	__u64	response[128][ETHTOOL_NCSI_SW_STAT_MAX];
+	__u64	aen[256][ETHTOOL_NCSI_SW_STAT_MAX];
+};
 #endif /* _UAPI_LINUX_ETHTOOL_H */
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index f26aa36..998d29b 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -838,6 +838,32 @@ static int ethtool_get_ncsi_stats(struct net_device *dev,
 	return ret;
 }
 
+static int ethtool_get_ncsi_sw_stats(struct net_device *dev,
+				     void __user *useraddr)
+{
+	struct ethtool_ncsi_sw_stats *enss;
+	int ret;
+
+	if (!dev->ethtool_ops->get_ncsi_sw_stats)
+		return -EOPNOTSUPP;
+
+	enss = kzalloc(sizeof(*enss), GFP_KERNEL);
+	if (!enss)
+		return -ENOMEM;
+
+	if (copy_from_user(&enss->cmd, useraddr, sizeof(enss->cmd))) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	ret = dev->ethtool_ops->get_ncsi_sw_stats(dev, enss);
+	if (!ret && copy_to_user(useraddr, enss, sizeof(*enss)))
+		ret = -EFAULT;
+out:
+	kfree(enss);
+	return ret;
+}
+
 static void
 warn_incomplete_ethtool_legacy_settings_conversion(const char *details)
 {
@@ -2884,6 +2910,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
 	case ETHTOOL_GNCSISTATS:
 		rc = ethtool_get_ncsi_stats(dev, useraddr);
 		break;
+	case ETHTOOL_GNCSISWSTATS:
+		rc = ethtool_get_ncsi_sw_stats(dev, useraddr);
+		break;
 	default:
 		rc = -EOPNOTSUPP;
 	}
diff --git a/net/ncsi/Kconfig b/net/ncsi/Kconfig
index 08a8a60..9e59145 100644
--- a/net/ncsi/Kconfig
+++ b/net/ncsi/Kconfig
@@ -10,3 +10,12 @@ config NET_NCSI
 	  support. Enable this only if your system connects to a network
 	  device via NCSI and the ethernet driver you're using supports
 	  the protocol explicitly.
+
+config NET_NCSI_DEBUG
+	bool "Enable NCSI debugging"
+	depends on NET_NCSI && DEBUG_FS
+	default n
+	---help---
+	  This enables the interfaces (e.g. debugfs) for NCSI debugging purpose.
+
+	  If unsure, say N.
diff --git a/net/ncsi/Makefile b/net/ncsi/Makefile
index 71a258a..4e0c5d2 100644
--- a/net/ncsi/Makefile
+++ b/net/ncsi/Makefile
@@ -3,3 +3,4 @@
 #
 obj-$(CONFIG_NET_NCSI) += ncsi-cmd.o ncsi-rsp.o ncsi-aen.o ncsi-manage.o \
 			  ncsi-ethtool.o
+obj-$(CONFIG_NET_NCSI_DEBUG) += ncsi-debug.o
diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index 09a7ba7..5a6cd74 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -275,6 +275,9 @@ struct ncsi_dev_priv {
 	struct list_head    channel_queue;   /* Config queue of channels   */
 	struct work_struct  work;            /* For channel management     */
 	struct packet_type  ptype;           /* NCSI packet Rx handler     */
+#ifdef CONFIG_NET_NCSI_DEBUG
+	struct ethtool_ncsi_sw_stats stats;  /* NCSI software statistics   */
+#endif /* CONFIG_NET_NCSI_DEBUG */
 	struct list_head    node;            /* Form NCSI device list      */
 };
 
@@ -341,4 +344,14 @@ int ncsi_aen_handler(struct ncsi_dev_priv *ndp, struct sk_buff *skb);
 void ncsi_ethtool_register_dev(struct net_device *dev);
 void ncsi_ethtool_unregister_dev(struct net_device *dev);
 
+/* Debugging functionality */
+#ifdef CONFIG_NET_NCSI_DEBUG
+void ncsi_dev_update_stats(struct ncsi_dev_priv *ndp,
+			   int type, int subtype, int errno);
+#else
+static inline void ncsi_dev_update_stats(struct ncsi_dev_priv *ndp,
+					 int type, int subtype, int errno)
+{
+}
+#endif /* CONFIG_NET_NCSI_DEBUG */
 #endif /* __NCSI_INTERNAL_H__ */
diff --git a/net/ncsi/ncsi-aen.c b/net/ncsi/ncsi-aen.c
index 6898e72..7a3d181 100644
--- a/net/ncsi/ncsi-aen.c
+++ b/net/ncsi/ncsi-aen.c
@@ -206,16 +206,28 @@ int ncsi_aen_handler(struct ncsi_dev_priv *ndp, struct sk_buff *skb)
 	}
 
 	if (!nah) {
+		ncsi_dev_update_stats(ndp, NCSI_PKT_AEN, h->type,
+				      ETHTOOL_NCSI_SW_STAT_ERROR);
 		netdev_warn(ndp->ndev.dev, "Invalid AEN (0x%x) received\n",
 			    h->type);
 		return -ENOENT;
 	}
 
 	ret = ncsi_validate_aen_pkt(h, nah->payload);
-	if (ret)
+	if (ret) {
+		ncsi_dev_update_stats(ndp, NCSI_PKT_AEN, h->type,
+				      ETHTOOL_NCSI_SW_STAT_ERROR);
 		goto out;
+	}
 
 	ret = nah->handler(ndp, h);
+	if (!ret) {
+		ncsi_dev_update_stats(ndp, NCSI_PKT_AEN, h->type,
+				      ETHTOOL_NCSI_SW_STAT_OK);
+	} else {
+		ncsi_dev_update_stats(ndp, NCSI_PKT_AEN, h->type,
+				      ETHTOOL_NCSI_SW_STAT_ERROR);
+	}
 out:
 	consume_skb(skb);
 	return ret;
diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c
index db7083b..875ff07 100644
--- a/net/ncsi/ncsi-cmd.c
+++ b/net/ncsi/ncsi-cmd.c
@@ -323,6 +323,8 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
 	}
 
 	if (!nch) {
+		ncsi_dev_update_stats(nca->ndp, nca->type, 0,
+				      ETHTOOL_NCSI_SW_STAT_ERROR);
 		netdev_err(nca->ndp->ndev.dev,
 			   "Cannot send packet with type 0x%02x\n", nca->type);
 		return -ENOENT;
@@ -331,13 +333,18 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
 	/* Get packet payload length and allocate the request */
 	nca->payload = nch->payload;
 	nr = ncsi_alloc_command(nca);
-	if (!nr)
+	if (!nr) {
+		ncsi_dev_update_stats(nca->ndp, nca->type, 0,
+				      ETHTOOL_NCSI_SW_STAT_ERROR);
 		return -ENOMEM;
+	}
 
 	/* Prepare the packet */
 	nca->id = nr->id;
 	ret = nch->handler(nr->cmd, nca);
 	if (ret) {
+		ncsi_dev_update_stats(nca->ndp, nca->type, 0,
+				      ETHTOOL_NCSI_SW_STAT_ERROR);
 		ncsi_free_request(nr);
 		return ret;
 	}
@@ -359,9 +366,12 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
 	skb_get(nr->cmd);
 	ret = dev_queue_xmit(nr->cmd);
 	if (ret < 0) {
+		ncsi_dev_update_stats(nca->ndp, nca->type, 0,
+				      ETHTOOL_NCSI_SW_STAT_ERROR);
 		ncsi_free_request(nr);
 		return ret;
 	}
 
+	ncsi_dev_update_stats(nca->ndp, nca->type, 0, ETHTOOL_NCSI_SW_STAT_OK);
 	return 0;
 }
diff --git a/net/ncsi/ncsi-debug.c b/net/ncsi/ncsi-debug.c
new file mode 100644
index 0000000..0e6c038
--- /dev/null
+++ b/net/ncsi/ncsi-debug.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright Gavin Shan, IBM Corporation 2017.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/atomic.h>
+#include <linux/netdevice.h>
+#include <linux/debugfs.h>
+#include <linux/skbuff.h>
+
+#include <net/ncsi.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+
+#include "internal.h"
+#include "ncsi-pkt.h"
+
+void ncsi_dev_update_stats(struct ncsi_dev_priv *ndp,
+			   int type, int subtype, int errno)
+{
+	unsigned long flags;
+
+	if (errno >= ETHTOOL_NCSI_SW_STAT_MAX)
+		return;
+
+	spin_lock_irqsave(&ndp->lock, flags);
+
+	if (type == NCSI_PKT_AEN) {
+		if (subtype < 256)
+			ndp->stats.aen[subtype][errno]++;
+	} else if (type < 128) {
+		ndp->stats.command[type][errno]++;
+	} else if (type < 256) {
+		ndp->stats.response[type - 128][errno]++;
+	}
+
+	spin_unlock_irqrestore(&ndp->lock, flags);
+}
diff --git a/net/ncsi/ncsi-ethtool.c b/net/ncsi/ncsi-ethtool.c
index 1ccdb50..82642ae 100644
--- a/net/ncsi/ncsi-ethtool.c
+++ b/net/ncsi/ncsi-ethtool.c
@@ -260,6 +260,38 @@ static int ncsi_get_stats(struct net_device *dev,
 	return 0;
 }
 
+#ifdef CONFIG_NET_NCSI_DEBUG
+static int ncsi_get_sw_stats(struct net_device *dev,
+			     struct ethtool_ncsi_sw_stats *enss)
+{
+	struct ncsi_dev *nd;
+	struct ncsi_dev_priv *ndp;
+	unsigned long flags;
+
+	nd = ncsi_find_dev(dev);
+	if (!nd)
+		return -ENXIO;
+
+	ndp = TO_NCSI_DEV_PRIV(nd);
+	spin_lock_irqsave(&ndp->lock, flags);
+	memcpy(enss->command, ndp->stats.command,
+	       128 * ETHTOOL_NCSI_SW_STAT_MAX * sizeof(enss->command[0][0]));
+	memcpy(enss->response, ndp->stats.response,
+	       128 * ETHTOOL_NCSI_SW_STAT_MAX * sizeof(enss->response[0][0]));
+	memcpy(enss->aen, ndp->stats.aen,
+	       256 * ETHTOOL_NCSI_SW_STAT_MAX * sizeof(enss->aen[0][0]));
+	spin_unlock_irqrestore(&ndp->lock, flags);
+
+	return 0;
+}
+#else
+static int ncsi_get_sw_stats(struct net_device *dev,
+			     struct ethtool_ncsi_sw_stats *enss)
+{
+	return -EOPNOTSUPP;
+}
+#endif /* CONFIG_NET_NCSI_DEBUG */
+
 void ncsi_ethtool_register_dev(struct net_device *dev)
 {
 	struct ethtool_ops *ops;
@@ -271,6 +303,7 @@ void ncsi_ethtool_register_dev(struct net_device *dev)
 	ops->get_ncsi_channels = ncsi_get_channels;
 	ops->get_ncsi_channel_info = ncsi_get_channel_info;
 	ops->get_ncsi_stats = ncsi_get_stats;
+	ops->get_ncsi_sw_stats = ncsi_get_sw_stats;
 }
 
 void ncsi_ethtool_unregister_dev(struct net_device *dev)
@@ -284,4 +317,5 @@ void ncsi_ethtool_unregister_dev(struct net_device *dev)
 	ops->get_ncsi_channels = NULL;
 	ops->get_ncsi_channel_info = NULL;
 	ops->get_ncsi_stats = NULL;
+	ops->get_ncsi_sw_stats = NULL;
 }
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index f1c10f0..8365a5b 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -521,6 +521,7 @@ static void ncsi_request_timeout(unsigned long data)
 {
 	struct ncsi_request *nr = (struct ncsi_request *)data;
 	struct ncsi_dev_priv *ndp = nr->ndp;
+	struct ncsi_pkt_hdr *hdr;
 	unsigned long flags;
 
 	/* If the request already had associated response,
@@ -534,6 +535,9 @@ static void ncsi_request_timeout(unsigned long data)
 	}
 	spin_unlock_irqrestore(&ndp->lock, flags);
 
+	hdr = (struct ncsi_pkt_hdr *)skb_network_header(nr->cmd);
+	ncsi_dev_update_stats(ndp, hdr->type, 0, ETHTOOL_NCSI_SW_STAT_TIMEOUT);
+
 	/* Release the request */
 	ncsi_free_request(nr);
 }
diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index 087db77..d362d2c 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -998,6 +998,8 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
 	}
 
 	if (!nrh) {
+		ncsi_dev_update_stats(ndp, hdr->type, 0,
+				      ETHTOOL_NCSI_SW_STAT_ERROR);
 		netdev_err(nd->dev, "Received unrecognized packet (0x%x)\n",
 			   hdr->type);
 		return -ENOENT;
@@ -1008,12 +1010,16 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
 	nr = &ndp->requests[hdr->id];
 	if (!nr->used) {
 		spin_unlock_irqrestore(&ndp->lock, flags);
+		ncsi_dev_update_stats(ndp, hdr->type, 0,
+				      ETHTOOL_NCSI_SW_STAT_TIMEOUT);
 		return -ENODEV;
 	}
 
 	nr->rsp = skb;
 	if (!nr->enabled) {
 		spin_unlock_irqrestore(&ndp->lock, flags);
+		ncsi_dev_update_stats(ndp, hdr->type, 0,
+				      ETHTOOL_NCSI_SW_STAT_TIMEOUT);
 		ret = -ENOENT;
 		goto out;
 	}
@@ -1024,11 +1030,22 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
 	if (payload < 0)
 		payload = ntohs(hdr->length);
 	ret = ncsi_validate_rsp_pkt(nr, payload);
-	if (ret)
+	if (ret) {
+		ncsi_dev_update_stats(ndp, hdr->type, 0,
+				      ETHTOOL_NCSI_SW_STAT_ERROR);
 		goto out;
+	}
 
 	/* Process the packet */
 	ret = nrh->handler(nr);
+	if (!ret) {
+		ncsi_dev_update_stats(ndp, hdr->type, 0,
+				      ETHTOOL_NCSI_SW_STAT_OK);
+	} else {
+		ncsi_dev_update_stats(ndp, hdr->type, 0,
+				      ETHTOOL_NCSI_SW_STAT_ERROR);
+	}
+
 out:
 	ncsi_free_request(nr);
 	return ret;
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 net-next 09/10] net/ncsi: No error report on DP response to non-existing package
From: Gavin Shan @ 2017-05-03  4:44 UTC (permalink / raw)
  To: netdev; +Cc: joe, kubakici, f.fainelli, davem, Gavin Shan
In-Reply-To: <1493786681-27468-1-git-send-email-gwshan@linux.vnet.ibm.com>

The issue was found from /sys/kernel/debug/ncsi/eth0/stats. The
first step in NCSI package/channel enumeration is deselect all
packages by sending DP (Deselect Package) commands. The remote
NIC replies with response while the corresponding package isn't
populated yet and it is treated as an error wrongly.

 # ethtool --ncsi eth0 swstats
     :
 RESPONSE     OK       TIMEOUT  ERROR
 =======================================
 DP           2        0        1

This fixes the issue by ignoring the error in DP response handler,
when the corresponding package isn't existing. With this applied,
no error reported from DP response packets.

 # ethtool --ncsi eth0 swstats
     :
 RESPONSE     OK       TIMEOUT  ERROR
 =======================================
 DP           3        0        0

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 net/ncsi/ncsi-rsp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index 41479a4..5097d86 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -118,7 +118,7 @@ static int ncsi_rsp_handler_dp(struct ncsi_request *nr)
 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
 				      &np, NULL);
 	if (!np)
-		return -ENODEV;
+		return 0;
 
 	/* Change state of all channels attached to the package */
 	NCSI_FOR_EACH_CHANNEL(np, nc) {
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 net-next 08/10] net/ncsi: Support NCSI packet generation
From: Gavin Shan @ 2017-05-03  4:44 UTC (permalink / raw)
  To: netdev; +Cc: joe, kubakici, f.fainelli, davem, Gavin Shan
In-Reply-To: <1493786681-27468-1-git-send-email-gwshan@linux.vnet.ibm.com>

This introduces /sys/kernel/debug/ncsi/eth0/pkt. The debugfs entry
can accept parameters to produce NCSI command packet. The received
NCSI response packet is dumped on read. Below is an example to send
CIS command and dump its response.

   # echo CIS,0,0 > /sys/kernel/debug/ncsi/eth0/pkt
   # cat /sys/kernel/debug/ncsi/eth0/pkt
   NCSI response [CIS] packet received

   00 01 dd 80 00 0004 0000 0000

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 net/ncsi/internal.h    |  54 ++++
 net/ncsi/ncsi-cmd.c    |   1 +
 net/ncsi/ncsi-debug.c  | 714 +++++++++++++++++++++++++++++++++++++++++++++++++
 net/ncsi/ncsi-manage.c |  10 +
 net/ncsi/ncsi-rsp.c    |  11 +
 5 files changed, 790 insertions(+)

diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index 5a6cd74..0a9210d 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -215,6 +215,9 @@ struct ncsi_request {
 	bool                 used;    /* Request that has been assigned  */
 	unsigned int         flags;   /* NCSI request property           */
 #define NCSI_REQ_FLAG_EVENT_DRIVEN	1
+#ifdef CONFIG_NET_NCSI_DEBUG
+#define NCSI_REQ_FLAG_DEBUG		2
+#endif
 	struct ncsi_dev_priv *ndp;    /* Associated NCSI device          */
 	struct sk_buff       *cmd;    /* Associated NCSI command packet  */
 	struct sk_buff       *rsp;    /* Associated NCSI response packet */
@@ -277,6 +280,15 @@ struct ncsi_dev_priv {
 	struct packet_type  ptype;           /* NCSI packet Rx handler     */
 #ifdef CONFIG_NET_NCSI_DEBUG
 	struct ethtool_ncsi_sw_stats stats;  /* NCSI software statistics   */
+	struct dentry       *dentry;         /* Debugfs directory           */
+	struct {
+		struct dentry  *dentry;
+		unsigned int   req;
+#define NCSI_PKT_REQ_FREE	0
+#define NCSI_PKT_REQ_BUSY	0xFFFFFFFF
+		int            errno;
+		struct sk_buff *rsp;
+	} pkt;
 #endif /* CONFIG_NET_NCSI_DEBUG */
 	struct list_head    node;            /* Form NCSI device list      */
 };
@@ -348,10 +360,52 @@ void ncsi_ethtool_unregister_dev(struct net_device *dev);
 #ifdef CONFIG_NET_NCSI_DEBUG
 void ncsi_dev_update_stats(struct ncsi_dev_priv *ndp,
 			   int type, int subtype, int errno);
+int ncsi_dev_init_debug(struct ncsi_dev_priv *ndp);
+void ncsi_dev_release_debug(struct ncsi_dev_priv *ndp);
+void ncsi_dev_reset_debug_pkt(struct ncsi_dev_priv *ndp,
+			      struct sk_buff *skb, int errno);
+
+static inline bool ncsi_dev_is_debug_pkt(struct ncsi_dev_priv *ndp,
+					 struct ncsi_request *nr)
+{
+	return ((nr->flags & NCSI_REQ_FLAG_DEBUG) && ndp->pkt.req == nr->id);
+}
+
+static inline void ncsi_dev_set_debug_pkt(struct ncsi_dev_priv *ndp,
+					  struct ncsi_request *nr)
+{
+	if (nr->flags & NCSI_REQ_FLAG_DEBUG)
+		ndp->pkt.req = nr->id;
+}
 #else
 static inline void ncsi_dev_update_stats(struct ncsi_dev_priv *ndp,
 					 int type, int subtype, int errno)
 {
 }
+
+static inline int ncsi_dev_init_debug(struct ncsi_dev_priv *ndp)
+{
+	return -ENOTTY;
+}
+
+static inline void ncsi_dev_release_debug(struct ncsi_dev_priv *ndp)
+{
+}
+
+static inline bool ncsi_dev_is_debug_pkt(struct ncsi_dev_priv *ndp,
+					 struct ncsi_request *nr)
+{
+	return false;
+}
+
+static inline void ncsi_dev_set_debug_pkt(struct ncsi_dev_priv *ndp,
+					  struct ncsi_request *nr)
+{
+}
+
+static inline void ncsi_dev_reset_debug_pkt(struct ncsi_dev_priv *ndp,
+					    struct sk_buff *skb, int errno)
+{
+}
 #endif /* CONFIG_NET_NCSI_DEBUG */
 #endif /* __NCSI_INTERNAL_H__ */
diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c
index 875ff07..cfcda87 100644
--- a/net/ncsi/ncsi-cmd.c
+++ b/net/ncsi/ncsi-cmd.c
@@ -361,6 +361,7 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
 	 */
 	nr->enabled = true;
 	mod_timer(&nr->timer, jiffies + 1 * HZ);
+	ncsi_dev_set_debug_pkt(nca->ndp, nr);
 
 	/* Send NCSI packet */
 	skb_get(nr->cmd);
diff --git a/net/ncsi/ncsi-debug.c b/net/ncsi/ncsi-debug.c
index 0e6c038..5a5f058 100644
--- a/net/ncsi/ncsi-debug.c
+++ b/net/ncsi/ncsi-debug.c
@@ -22,6 +22,9 @@
 #include "internal.h"
 #include "ncsi-pkt.h"
 
+static struct dentry *ncsi_dentry;
+static const char *ncsi_pkt_type_name(unsigned int type);
+
 void ncsi_dev_update_stats(struct ncsi_dev_priv *ndp,
 			   int type, int subtype, int errno)
 {
@@ -43,3 +46,714 @@ void ncsi_dev_update_stats(struct ncsi_dev_priv *ndp,
 
 	spin_unlock_irqrestore(&ndp->lock, flags);
 }
+
+void ncsi_dev_reset_debug_pkt(struct ncsi_dev_priv *ndp,
+			      struct sk_buff *skb, int errno)
+{
+	unsigned long flags;
+	struct sk_buff *old;
+
+	spin_lock_irqsave(&ndp->lock, flags);
+	ndp->pkt.req = NCSI_PKT_REQ_FREE;
+	ndp->pkt.errno = errno;
+
+	old = ndp->pkt.rsp;
+	ndp->pkt.rsp = skb;
+	spin_unlock_irqrestore(&ndp->lock, flags);
+
+	consume_skb(old);
+}
+
+static int ncsi_pkt_input_default(struct ncsi_dev_priv *ndp,
+				  struct ncsi_cmd_arg *nca, char *buf)
+{
+	return 0;
+}
+
+static int ncsi_pkt_input_params(char *buf, int *outval, int count)
+{
+	int num, i;
+
+	for (i = 0; i < count; i++, outval++) {
+		if (sscanf(buf, "%x%n", outval, &num) != 1)
+			return -EINVAL;
+
+		if (buf[num] == ',')
+			buf += (count + 1);
+		else
+			buf += count;
+	}
+
+	return 0;
+}
+
+static int ncsi_pkt_input_sp(struct ncsi_dev_priv *ndp,
+			     struct ncsi_cmd_arg *nca, char *buf)
+{
+	int param, ret;
+
+	/* The hardware arbitration will be configured according
+	 * to the NCSI's capability if it's not specified.
+	 */
+	ret = ncsi_pkt_input_params(buf, &param, 1);
+	if (!ret && param != 0 && param != 1)
+		return -EINVAL;
+	else if (ret)
+		param = (ndp->flags & NCSI_DEV_HWA) ? 1 : 0;
+
+	nca->bytes[0] = param;
+
+	return 0;
+}
+
+static int ncsi_pkt_input_dc(struct ncsi_dev_priv *ndp,
+			     struct ncsi_cmd_arg *nca, char *buf)
+{
+	int param, ret;
+
+	/* Allow link down will be disallowed if it's not specified */
+	ret = ncsi_pkt_input_params(buf, &param, 1);
+	if (!ret && param != 0 && param != 1)
+		return -EINVAL;
+	else if (ret)
+		param = 0;
+
+	nca->bytes[0] = param;
+
+	return 0;
+}
+
+static int ncsi_pkt_input_ae(struct ncsi_dev_priv *ndp,
+			     struct ncsi_cmd_arg *nca, char *buf)
+{
+	int param[2], ret;
+
+	/* MC ID and AE mode are mandatory */
+	ret = ncsi_pkt_input_params(buf, param, 2);
+	if (ret)
+		return -EINVAL;
+
+	nca->bytes[0] = param[0];
+	nca->dwords[1] = param[1];
+
+	return 0;
+}
+
+static int ncsi_pkt_input_sl(struct ncsi_dev_priv *ndp,
+			     struct ncsi_cmd_arg *nca, char *buf)
+{
+	int param[2], ret;
+
+	/* Link mode and OEM mode are mandatory */
+	ret = ncsi_pkt_input_params(buf, param, 2);
+	if (ret)
+		return -EINVAL;
+
+	nca->dwords[0] = param[0];
+	nca->dwords[1] = param[1];
+
+	return 0;
+}
+
+static int ncsi_pkt_input_svf(struct ncsi_dev_priv *ndp,
+			      struct ncsi_cmd_arg *nca, char *buf)
+{
+	int param[3], ret;
+
+	/* VLAN ID, table index and enable */
+	ret = ncsi_pkt_input_params(buf, param, 3);
+	if (ret)
+		return -EINVAL;
+
+	if (param[2] != 0 && param[2] != 1)
+		return -EINVAL;
+
+	nca->words[0] = param[0];
+	nca->bytes[2] = param[1];
+	nca->bytes[3] = param[2];
+
+	return 0;
+}
+
+static int ncsi_pkt_input_ev(struct ncsi_dev_priv *ndp,
+			     struct ncsi_cmd_arg *nca, char *buf)
+{
+	int param, ret;
+
+	/* VLAN filter mode */
+	ret = ncsi_pkt_input_params(buf, &param, 1);
+	if (ret)
+		return -EINVAL;
+
+	nca->bytes[0] = param;
+
+	return 0;
+}
+
+static int ncsi_pkt_input_sma(struct ncsi_dev_priv *ndp,
+			      struct ncsi_cmd_arg *nca, char *buf)
+{
+	int param[8], ret;
+
+	/* MAC address, MAC table index, Address type and operation */
+	ret = ncsi_pkt_input_params(buf, param, 8);
+	if (ret)
+		return -EINVAL;
+
+	if (param[7] & ~0x9)
+		return -EINVAL;
+
+	nca->bytes[0] = param[0];
+	nca->bytes[1] = param[1];
+	nca->bytes[2] = param[2];
+	nca->bytes[3] = param[3];
+	nca->bytes[4] = param[4];
+	nca->bytes[5] = param[5];
+
+	nca->bytes[6] = param[6];
+	nca->bytes[7] = param[7];
+
+	return 0;
+}
+
+static int ncsi_pkt_input_ebf(struct ncsi_dev_priv *ndp,
+			      struct ncsi_cmd_arg *nca, char *buf)
+{
+	int param, ret;
+
+	/* Broadcast filter mode */
+	ret = ncsi_pkt_input_params(buf, &param, 1);
+	if (ret)
+		return -EINVAL;
+
+	nca->dwords[0] = param;
+
+	return 0;
+}
+
+static int ncsi_pkt_input_egmf(struct ncsi_dev_priv *ndp,
+			       struct ncsi_cmd_arg *nca, char *buf)
+{
+	int param, ret;
+
+	/* Global multicast filter mode */
+	ret = ncsi_pkt_input_params(buf, &param, 1);
+	if (ret)
+		return -EINVAL;
+
+	nca->dwords[0] = param;
+
+	return 0;
+}
+
+static int ncsi_pkt_input_snfc(struct ncsi_dev_priv *ndp,
+			       struct ncsi_cmd_arg *nca, char *buf)
+{
+	int param, ret;
+
+	/* NCSI flow control mode */
+	ret = ncsi_pkt_input_params(buf, &param, 1);
+	if (ret)
+		return -EINVAL;
+
+	nca->bytes[0] = param;
+
+	return 0;
+}
+
+static void ncsi_pkt_output_header(struct ncsi_dev_priv *ndp,
+				   struct seq_file *seq,
+				   struct ncsi_rsp_pkt_hdr *h)
+{
+	seq_printf(seq, "NCSI response [%s] packet received\n\n",
+		   ncsi_pkt_type_name(h->common.type - 0x80));
+	seq_printf(seq, "%02x %02x %02x %02x %02x %04x %04x %04x\n",
+		   h->common.mc_id, h->common.revision, h->common.id,
+		   h->common.type, h->common.channel, ntohs(h->common.length),
+		   ntohs(h->code), ntohs(h->reason));
+}
+
+static int ncsi_pkt_output_default(struct ncsi_dev_priv *ndp,
+				   struct seq_file *seq,
+				   struct sk_buff *skb)
+{
+	struct ncsi_rsp_pkt_hdr *hdr;
+
+	hdr = (struct ncsi_rsp_pkt_hdr *)skb_network_header(skb);
+	ncsi_pkt_output_header(ndp, seq, hdr);
+
+	return 0;
+}
+
+static int ncsi_pkt_output_gls(struct ncsi_dev_priv *ndp,
+			       struct seq_file *seq, struct sk_buff *skb)
+{
+	struct ncsi_rsp_gls_pkt *gls;
+
+	ncsi_pkt_output_default(ndp, seq, skb);
+
+	gls = (struct ncsi_rsp_gls_pkt *)skb_network_header(skb);
+	seq_printf(seq, "Status: %08x Other: %08x OEM: %08x\n",
+		   ntohl(gls->status), ntohl(gls->other),
+		   ntohl(gls->oem_status));
+
+	return 0;
+}
+
+static int ncsi_pkt_output_gvi(struct ncsi_dev_priv *ndp,
+			       struct seq_file *seq, struct sk_buff *skb)
+{
+	struct ncsi_rsp_gvi_pkt *gvi;
+
+	ncsi_pkt_output_default(ndp, seq, skb);
+
+	gvi = (struct ncsi_rsp_gvi_pkt *)skb_network_header(skb);
+	seq_printf(seq, "NCSI Version: %08x Alpha2: %02x\n",
+		   ntohl(gvi->ncsi_version), gvi->alpha2);
+	seq_printf(seq, "Firmware: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x Version: %08x\n",
+		   gvi->fw_name[0], gvi->fw_name[1], gvi->fw_name[2],
+		   gvi->fw_name[3], gvi->fw_name[4], gvi->fw_name[5],
+		   gvi->fw_name[6], gvi->fw_name[7], gvi->fw_name[8],
+		   gvi->fw_name[9], gvi->fw_name[10], gvi->fw_name[11],
+		   ntohl(gvi->fw_version));
+	seq_printf(seq, "PCI: %04x %04x %04x %04x Manufacture ID: %08x\n",
+		   ntohs(gvi->pci_ids[0]), ntohs(gvi->pci_ids[1]),
+		   ntohs(gvi->pci_ids[2]), ntohs(gvi->pci_ids[3]),
+		   ntohl(gvi->mf_id));
+
+	return 0;
+}
+
+static int ncsi_pkt_output_gc(struct ncsi_dev_priv *ndp,
+			      struct seq_file *seq, struct sk_buff *skb)
+{
+	struct ncsi_rsp_gc_pkt *gc;
+
+	ncsi_pkt_output_default(ndp, seq, skb);
+
+	gc = (struct ncsi_rsp_gc_pkt *)skb_network_header(skb);
+	seq_printf(seq, "Cap: %08x BC: %08x MC: %08x Buf: %08x AEN: %08x\n",
+		   ntohl(gc->cap), ntohl(gc->bc_cap), ntohl(gc->mc_cap),
+		   ntohl(gc->buf_cap), ntohl(gc->aen_cap));
+	seq_printf(seq, "VLAN: %02x Mixed: %02x MC: %02x UC: %02x\n",
+		   gc->vlan_cnt, gc->mixed_cnt, gc->mc_cnt, gc->uc_cnt);
+	seq_printf(seq, "VLAN Mode: %02x Channels: %02x\n",
+		   gc->vlan_mode, gc->channel_cnt);
+
+	return 0;
+}
+
+static int ncsi_pkt_output_gp(struct ncsi_dev_priv *ndp,
+			      struct seq_file *seq, struct sk_buff *skb)
+{
+	struct ncsi_rsp_gp_pkt *gp;
+
+	ncsi_pkt_output_default(ndp, seq, skb);
+
+	gp = (struct ncsi_rsp_gp_pkt *)skb_network_header(skb);
+	seq_printf(seq, "MAC: %02x %02x VLAN: %02x %04x\n",
+		   gp->mac_cnt, gp->mac_enable, gp->vlan_cnt,
+		   ntohs(gp->vlan_enable));
+	seq_printf(seq, "Link: %08x BC: %08x Valid: %08x\n",
+		   ntohl(gp->link_mode), ntohl(gp->bc_mode),
+		   ntohl(gp->valid_modes));
+	seq_printf(seq, "VLAN: %02x FC: %02x AEN: %08x\n",
+		   gp->vlan_mode, gp->fc_mode, ntohl(gp->aen_mode));
+	seq_printf(seq, "MAC: %02x %02x %02x %02x %02x %02x VLAN: %04x\n",
+		   gp->mac[5], gp->mac[4], gp->mac[3], gp->mac[2],
+		   gp->mac[1], gp->mac[0], ntohs(gp->vlan));
+
+	return 0;
+}
+
+static int ncsi_pkt_output_gcps(struct ncsi_dev_priv *ndp,
+				struct seq_file *seq, struct sk_buff *skb)
+{
+	struct ncsi_rsp_gcps_pkt *gcps;
+
+	ncsi_pkt_output_default(ndp, seq, skb);
+
+	gcps = (struct ncsi_rsp_gcps_pkt *)skb_network_header(skb);
+	seq_printf(seq, "cnt_hi: %08x cnt_lo: %08x rx_bytes: %08x\n",
+		   ntohl(gcps->cnt_hi), ntohl(gcps->cnt_lo),
+		   ntohl(gcps->rx_bytes));
+	seq_printf(seq, "tx_bytes: %08x rx_uc_pkts: %08x rx_mc_pkts: %08x\n",
+		   ntohl(gcps->tx_bytes), ntohl(gcps->rx_uc_pkts),
+		   ntohl(gcps->rx_mc_pkts));
+	seq_printf(seq, "rx_bc_pkts: %08x tx_uc_pkts: %08x tx_mc_pkts: %08x\n",
+		   ntohl(gcps->rx_bc_pkts), ntohl(gcps->tx_uc_pkts),
+		   ntohl(gcps->tx_mc_pkts));
+	seq_printf(seq, "tx_bc_pkts: %08x fcs_err: %08x align_err: %08x\n",
+		   ntohl(gcps->tx_bc_pkts), ntohl(gcps->fcs_err),
+		   ntohl(gcps->align_err));
+	seq_printf(seq, "false_carrier: %08x runt_pkts: %08x jabber_pkts: %08x\n",
+		   ntohl(gcps->false_carrier), ntohl(gcps->runt_pkts),
+		   ntohl(gcps->jabber_pkts));
+	seq_printf(seq, "rx_pause_xon: %08x rx_pause_xoff: %08x tx_pause_xon: %08x",
+		   ntohl(gcps->rx_pause_xon), ntohl(gcps->rx_pause_xoff),
+		   ntohl(gcps->tx_pause_xon));
+	seq_printf(seq, "tx_pause_xoff: %08x tx_s_collision: %08x tx_m_collision: %08x\n",
+		   ntohl(gcps->tx_pause_xoff), ntohl(gcps->tx_s_collision),
+		   ntohl(gcps->tx_m_collision));
+	seq_printf(seq, "l_collision: %08x e_collision: %08x rx_ctl_frames: %08x\n",
+		   ntohl(gcps->l_collision), ntohl(gcps->e_collision),
+		   ntohl(gcps->rx_ctl_frames));
+	seq_printf(seq, "rx_64_frames: %08x rx_127_frames: %08x rx_255_frames: %08x\n",
+		   ntohl(gcps->rx_64_frames), ntohl(gcps->rx_127_frames),
+		   ntohl(gcps->rx_255_frames));
+	seq_printf(seq, "rx_511_frames: %08x rx_1023_frames: %08x rx_1522_frames: %08x\n",
+		   ntohl(gcps->rx_511_frames), ntohl(gcps->rx_1023_frames),
+		   ntohl(gcps->rx_1522_frames));
+	seq_printf(seq, "rx_9022_frames: %08x tx_64_frames: %08x tx_127_frames: %08x\n",
+		   ntohl(gcps->rx_9022_frames), ntohl(gcps->tx_64_frames),
+		   ntohl(gcps->tx_127_frames));
+	seq_printf(seq, "tx_255_frames: %08x tx_511_frames: %08x tx_1023_frames: %08x\n",
+		   ntohl(gcps->tx_255_frames), ntohl(gcps->tx_511_frames),
+		   ntohl(gcps->tx_1023_frames));
+	seq_printf(seq, "tx_1522_frames: %08x tx_9022_frames: %08x rx_valid_bytes: %08x\n",
+		   ntohl(gcps->tx_1522_frames), ntohl(gcps->tx_9022_frames),
+		   ntohl(gcps->rx_valid_bytes));
+	seq_printf(seq, "rx_runt_pkts: %08x rx_jabber_pkts: %08x\n",
+		   ntohl(gcps->rx_runt_pkts), ntohl(gcps->rx_jabber_pkts));
+
+	return 0;
+}
+
+static int ncsi_pkt_output_gns(struct ncsi_dev_priv *ndp,
+			       struct seq_file *seq, struct sk_buff *skb)
+{
+	struct ncsi_rsp_gns_pkt *gns;
+
+	ncsi_pkt_output_default(ndp, seq, skb);
+
+	gns = (struct ncsi_rsp_gns_pkt *)skb_network_header(skb);
+	seq_printf(seq, "rx_cmds: %08x dropped_cmds: %08x cmd_type_errs: %08x\n",
+		   ntohl(gns->rx_cmds), ntohl(gns->dropped_cmds),
+		   ntohl(gns->cmd_type_errs));
+	seq_printf(seq, "cmd_csum_errs: %08x rx_pkts: %08x tx_pkts: %08x\n",
+		   ntohl(gns->cmd_csum_errs), ntohl(gns->rx_pkts),
+		   ntohl(gns->tx_pkts));
+	seq_printf(seq, "tx_aen_pkts: %08x\n",
+		   ntohl(gns->tx_aen_pkts));
+
+	return 0;
+}
+
+static int ncsi_pkt_output_gnpts(struct ncsi_dev_priv *ndp,
+				 struct seq_file *seq, struct sk_buff *skb)
+{
+	struct ncsi_rsp_gnpts_pkt *gnpts;
+
+	ncsi_pkt_output_default(ndp, seq, skb);
+
+	gnpts = (struct ncsi_rsp_gnpts_pkt *)skb_network_header(skb);
+	seq_printf(seq, "tx_pkts: %08x tx_dropped: %08x tx_channel_err: %08x\n",
+		   ntohl(gnpts->tx_pkts), ntohl(gnpts->tx_dropped),
+		   ntohl(gnpts->tx_channel_err));
+	seq_printf(seq, "tx_us_err: %08x rx_pkts: %08x rx_dropped: %08x\n",
+		   ntohl(gnpts->tx_us_err), ntohl(gnpts->rx_pkts),
+		   ntohl(gnpts->rx_dropped));
+	seq_printf(seq, "rx_channel_err: %08x rx_us_err: %08x rx_os_err: %08x\n",
+		   ntohl(gnpts->rx_channel_err), ntohl(gnpts->rx_us_err),
+		   ntohl(gnpts->rx_os_err));
+
+	return 0;
+}
+
+static int ncsi_pkt_output_gps(struct ncsi_dev_priv *ndp,
+			       struct seq_file *seq, struct sk_buff *skb)
+{
+	struct ncsi_rsp_gps_pkt *gps;
+
+	ncsi_pkt_output_default(ndp, seq, skb);
+
+	gps = (struct ncsi_rsp_gps_pkt *)skb_network_header(skb);
+	seq_printf(seq, "Status: %08x\n", ntohl(gps->status));
+
+	return 0;
+}
+
+static int ncsi_pkt_output_gpuuid(struct ncsi_dev_priv *ndp,
+				  struct seq_file *seq, struct sk_buff *skb)
+{
+	struct ncsi_rsp_gpuuid_pkt *gpuuid;
+
+	ncsi_pkt_output_default(ndp, seq, skb);
+
+	gpuuid = (struct ncsi_rsp_gpuuid_pkt *)skb_network_header(skb);
+	seq_printf(seq, "UUID: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		   gpuuid->uuid[15], gpuuid->uuid[14], gpuuid->uuid[13],
+		   gpuuid->uuid[12], gpuuid->uuid[11], gpuuid->uuid[10],
+		   gpuuid->uuid[9],  gpuuid->uuid[8]);
+	seq_printf(seq, "      %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		   gpuuid->uuid[7], gpuuid->uuid[6], gpuuid->uuid[5],
+		   gpuuid->uuid[4], gpuuid->uuid[3], gpuuid->uuid[2],
+		   gpuuid->uuid[1], gpuuid->uuid[0]);
+
+	return 0;
+}
+
+static const struct ncsi_pkt_handler {
+	unsigned char	type;
+	const char	*name;
+	int		(*input)(struct ncsi_dev_priv *ndp,
+				 struct ncsi_cmd_arg *nca, char *buf);
+	int		(*output)(struct ncsi_dev_priv *ndp,
+				  struct seq_file *seq, struct sk_buff *skb);
+} ncsi_pkt_handlers[] = {
+	{ NCSI_PKT_CMD_CIS,    "CIS",
+	  ncsi_pkt_input_default, ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_SP,     "SP",
+	  ncsi_pkt_input_sp,      ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_DP,     "DP",
+	  ncsi_pkt_input_default, ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_EC,     "EC",
+	  ncsi_pkt_input_default, ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_DC,     "DC",
+	  ncsi_pkt_input_dc,      ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_RC,     "RC",
+	  ncsi_pkt_input_default, ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_ECNT,   "ECNT",
+	  ncsi_pkt_input_default, ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_DCNT,   "DCNT",
+	  ncsi_pkt_input_default, ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_AE,     "AE",
+	  ncsi_pkt_input_ae,      ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_SL,     "SL",
+	  ncsi_pkt_input_sl,      ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_GLS,    "GLS",
+	  ncsi_pkt_input_default, ncsi_pkt_output_gls     },
+	{ NCSI_PKT_CMD_SVF,    "SVF",
+	  ncsi_pkt_input_svf,     ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_EV,     "EV",
+	  ncsi_pkt_input_ev,      ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_DV,     "DV",
+	  ncsi_pkt_input_default, ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_SMA,    "SMA",
+	  ncsi_pkt_input_sma,     ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_EBF,    "EBF",
+	  ncsi_pkt_input_ebf,     ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_DBF,    "DBF",
+	  ncsi_pkt_input_default, ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_EGMF,   "EGMF",
+	  ncsi_pkt_input_egmf,    ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_DGMF,   "DGMF",
+	  ncsi_pkt_input_default, ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_SNFC,   "SNFC",
+	  ncsi_pkt_input_snfc,    ncsi_pkt_output_default },
+	{ NCSI_PKT_CMD_GVI,    "GVI",
+	  ncsi_pkt_input_default, ncsi_pkt_output_gvi     },
+	{ NCSI_PKT_CMD_GC,     "GC",
+	  ncsi_pkt_input_default, ncsi_pkt_output_gc      },
+	{ NCSI_PKT_CMD_GP,     "GP",
+	  ncsi_pkt_input_default, ncsi_pkt_output_gp      },
+	{ NCSI_PKT_CMD_GCPS,   "GCPS",
+	  ncsi_pkt_input_default, ncsi_pkt_output_gcps    },
+	{ NCSI_PKT_CMD_GNS,    "GNS",
+	  ncsi_pkt_input_default, ncsi_pkt_output_gns     },
+	{ NCSI_PKT_CMD_GNPTS,  "GNPTS",
+	  ncsi_pkt_input_default, ncsi_pkt_output_gnpts   },
+	{ NCSI_PKT_CMD_GPS,    "GPS",
+	  ncsi_pkt_input_default, ncsi_pkt_output_gps     },
+	{ NCSI_PKT_CMD_OEM,    "OEM",
+	  NULL,                   NULL                    },
+	{ NCSI_PKT_CMD_PLDM,   "PLDM",
+	  NULL,                   NULL                    },
+	{ NCSI_PKT_CMD_GPUUID, "GPUUID",
+	  ncsi_pkt_input_default, ncsi_pkt_output_gpuuid  },
+};
+
+static const char *ncsi_pkt_type_name(unsigned int type)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ncsi_pkt_handlers); i++) {
+		if (ncsi_pkt_handlers[i].type == type)
+			return ncsi_pkt_handlers[i].name;
+	}
+
+	return "N/A";
+}
+
+static int ncsi_dev_pkt_seq_show(struct seq_file *seq, void *v)
+{
+	struct ncsi_dev_priv *ndp = seq->private;
+	const struct ncsi_pkt_handler *h = NULL;
+	struct ncsi_pkt_hdr *hdr;
+	struct sk_buff *skb;
+	int i, errno;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ndp->lock, flags);
+	errno = ndp->pkt.errno;
+	skb = ndp->pkt.rsp;
+	ndp->pkt.rsp = NULL;
+	spin_unlock_irqrestore(&ndp->lock, flags);
+	ncsi_dev_reset_debug_pkt(ndp, NULL, 0);
+
+	if (errno) {
+		WARN_ON(skb);
+		seq_printf(seq, "Error %d receiving response packet\n", errno);
+		return 0;
+	} else if (!skb) {
+		seq_puts(seq, "No available response packet\n");
+		return 0;
+	}
+
+	hdr = (struct ncsi_pkt_hdr *)skb_network_header(skb);
+	for (i = 0; i < ARRAY_SIZE(ncsi_pkt_handlers); i++) {
+		if (ncsi_pkt_handlers[i].type == (hdr->type - 0x80)) {
+			h = &ncsi_pkt_handlers[i];
+			break;
+		}
+	}
+
+	if (!h || !h->output) {
+		consume_skb(skb);
+		return 0;
+	}
+
+	h->output(ndp, seq, skb);
+	return 0;
+}
+
+static int ncsi_dev_pkt_seq_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ncsi_dev_pkt_seq_show, inode->i_private);
+}
+
+static ssize_t ncsi_dev_pkt_seq_write(struct file *file,
+				      const char __user *buffer,
+				      size_t count, loff_t *pos)
+{
+	struct seq_file *seq = file->private_data;
+	struct ncsi_dev_priv *ndp = seq->private;
+	struct ncsi_cmd_arg nca;
+	char buf[64], name[64], *pbuf;
+	const struct ncsi_pkt_handler *h;
+	int num, package, channel, i, ret;
+	unsigned long flags;
+
+	if (count >= sizeof(buf))
+		return -EINVAL;
+
+	/* Copy the buffer from user space. Currently we have 64 bytes as
+	 * the length limitation. It should be enough as there are no bunch
+	 * of parameters to be specified when sending NCSI command packet.
+	 */
+	memset(buf, 0, sizeof(buf));
+	if (copy_from_user(buf, buffer, count))
+		return -EFAULT;
+
+	/* Extract the specified command */
+	memset(name, 0, sizeof(name));
+	pbuf = strchr(buf, ',');
+	if (!pbuf)
+		return -EINVAL;
+	memcpy(name, buf, pbuf - buf);
+	pbuf++;
+
+	/* Extract mandatory parameters: package and channel ID */
+	memset(&nca, 0, sizeof(struct ncsi_cmd_arg));
+	if (sscanf(pbuf, "%x,%x%n", &package, &channel, &num) != 2)
+		return -EINVAL;
+	if (package < 0 || package >= 8 ||
+	    channel < 0 || channel > NCSI_RESERVED_CHANNEL)
+		return -EINVAL;
+
+	nca.package = package;
+	nca.channel = channel;
+	if (pbuf[num] == ',')
+		pbuf += (count + 1);
+	else
+		pbuf += count;
+
+	/* Search for handler */
+	h = NULL;
+	for (i = 0; i < ARRAY_SIZE(ncsi_pkt_handlers); i++) {
+		if (!strcmp(ncsi_pkt_handlers[i].name, name)) {
+			h = &ncsi_pkt_handlers[i];
+			nca.type = h->type;
+			break;
+		}
+	}
+
+	if (!h || !h->input)
+		return -ERANGE;
+
+	/* Sort out additional parameters */
+	nca.ndp = ndp;
+	nca.req_flags = NCSI_REQ_FLAG_DEBUG;
+	ret = h->input(ndp, &nca, pbuf);
+	if (ret)
+		return ret;
+
+	/* This interface works in serialized fashion, meaning new command
+	 * cannot be sent until previous one has been finalized.
+	 */
+	spin_lock_irqsave(&ndp->lock, flags);
+	if (ndp->pkt.req != NCSI_PKT_REQ_FREE) {
+		spin_unlock_irqrestore(&ndp->lock, flags);
+		return -EBUSY;
+	}
+
+	ndp->pkt.req = NCSI_PKT_REQ_BUSY;
+	spin_unlock_irqrestore(&ndp->lock, flags);
+
+	ret = ncsi_xmit_cmd(&nca);
+	if (ret) {
+		spin_lock_irqsave(&ndp->lock, flags);
+		ndp->pkt.req = NCSI_PKT_REQ_FREE;
+		spin_unlock_irqrestore(&ndp->lock, flags);
+		return ret;
+	}
+
+	return count;
+}
+
+static const struct file_operations ncsi_dev_pkt_fops = {
+	.owner   = THIS_MODULE,
+	.open    = ncsi_dev_pkt_seq_open,
+	.read    = seq_read,
+	.write   = ncsi_dev_pkt_seq_write,
+	.llseek  = seq_lseek,
+	.release = seq_release,
+};
+
+int ncsi_dev_init_debug(struct ncsi_dev_priv *ndp)
+{
+	if (WARN_ON_ONCE(ndp->dentry))
+		return 0;
+
+	if (!ncsi_dentry) {
+		ncsi_dentry = debugfs_create_dir("ncsi", NULL);
+		if (!ncsi_dentry) {
+			pr_debug("Failed to create debugfs directory 'ncsi'\n");
+			return -ENOMEM;
+		}
+	}
+
+	ndp->dentry = debugfs_create_dir(netdev_name(ndp->ndev.dev),
+					 ncsi_dentry);
+	if (!ndp->dentry) {
+		pr_debug("Failed to create debugfs directory 'ncsi/%s'\n",
+			 netdev_name(ndp->ndev.dev));
+		return -ENOMEM;
+	}
+
+	ndp->pkt.dentry = debugfs_create_file("pkt", 0600, ndp->dentry,
+					      ndp, &ncsi_dev_pkt_fops);
+	if (!ndp->pkt.dentry) {
+		pr_debug("Failed to create debugfs file 'ncsi/%s/pkt'\n",
+			 netdev_name(ndp->ndev.dev));
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void ncsi_dev_release_debug(struct ncsi_dev_priv *ndp)
+{
+	debugfs_remove(ndp->pkt.dentry);
+	debugfs_remove(ndp->dentry);
+}
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index 8365a5b..ea8ea0e 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -537,6 +537,8 @@ static void ncsi_request_timeout(unsigned long data)
 
 	hdr = (struct ncsi_pkt_hdr *)skb_network_header(nr->cmd);
 	ncsi_dev_update_stats(ndp, hdr->type, 0, ETHTOOL_NCSI_SW_STAT_TIMEOUT);
+	if (ncsi_dev_is_debug_pkt(ndp, nr))
+		ncsi_dev_reset_debug_pkt(ndp, NULL, -ETIMEDOUT);
 
 	/* Release the request */
 	ncsi_free_request(nr);
@@ -1287,6 +1289,13 @@ int ncsi_start_dev(struct ncsi_dev *nd)
 		return -ENOTTY;
 
 	if (!(ndp->flags & NCSI_DEV_PROBED)) {
+		/* The debugging functionality should have been initialized
+		 * when registerring the NCSI device. As the network device
+		 * name isn't available that time, we have to delay the work
+		 * to here.
+		 */
+		ncsi_dev_init_debug(ndp);
+
 		nd->state = ncsi_dev_state_probe;
 		schedule_work(&ndp->work);
 		return 0;
@@ -1336,6 +1345,7 @@ void ncsi_unregister_dev(struct ncsi_dev *nd)
 	struct ncsi_package *np, *tmp;
 	unsigned long flags;
 
+	ncsi_dev_release_debug(ndp);
 	dev_remove_pack(&ndp->ptype);
 
 	/* Restore ethtool operations */
diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index d362d2c..41479a4 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -1033,10 +1033,21 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
 	if (ret) {
 		ncsi_dev_update_stats(ndp, hdr->type, 0,
 				      ETHTOOL_NCSI_SW_STAT_ERROR);
+		if (ncsi_dev_is_debug_pkt(ndp, nr))
+			ncsi_dev_reset_debug_pkt(ndp, NULL, -EINVAL);
+
 		goto out;
 	}
 
 	/* Process the packet */
+	if (ncsi_dev_is_debug_pkt(ndp, nr)) {
+		ncsi_dev_update_stats(ndp, hdr->type, 0,
+				      ETHTOOL_NCSI_SW_STAT_OK);
+		ncsi_dev_reset_debug_pkt(ndp, nr->rsp, 0);
+		nr->rsp = NULL;
+		goto out;
+	}
+
 	ret = nrh->handler(nr);
 	if (!ret) {
 		ncsi_dev_update_stats(ndp, hdr->type, 0,
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 net-next 10/10] net/ncsi: Fix length of GVI response packet
From: Gavin Shan @ 2017-05-03  4:44 UTC (permalink / raw)
  To: netdev; +Cc: joe, kubakici, f.fainelli, davem, Gavin Shan
In-Reply-To: <1493786681-27468-1-git-send-email-gwshan@linux.vnet.ibm.com>

The length of GVI (GetVersionInfo) response packet should be 40 instead
of 36. This issue was found from /sys/kernel/debug/ncsi/eth0/stats.

 # ethtool --ncsi eth0 swstats
     :
 RESPONSE     OK       TIMEOUT  ERROR
 =======================================
 GVI          0        0        2

With this applied, no error reported on GVI response packets:

 # ethtool --ncsi eth0 swstats
     :
 RESPONSE     OK       TIMEOUT  ERROR
 =======================================
 GVI          2        0        0

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 net/ncsi/ncsi-rsp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index 5097d86..a3e0f4f 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -951,7 +951,7 @@ static struct ncsi_rsp_handler {
 	{ NCSI_PKT_RSP_EGMF,    4, ncsi_rsp_handler_egmf    },
 	{ NCSI_PKT_RSP_DGMF,    4, ncsi_rsp_handler_dgmf    },
 	{ NCSI_PKT_RSP_SNFC,    4, ncsi_rsp_handler_snfc    },
-	{ NCSI_PKT_RSP_GVI,    36, ncsi_rsp_handler_gvi     },
+	{ NCSI_PKT_RSP_GVI,    40, ncsi_rsp_handler_gvi     },
 	{ NCSI_PKT_RSP_GC,     32, ncsi_rsp_handler_gc      },
 	{ NCSI_PKT_RSP_GP,     -1, ncsi_rsp_handler_gp      },
 	{ NCSI_PKT_RSP_GCPS,  172, ncsi_rsp_handler_gcps    },
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 net-next 02/10] net/ncsi: Properly track channel monitor timer state
From: Gavin Shan @ 2017-05-03  4:44 UTC (permalink / raw)
  To: netdev; +Cc: joe, kubakici, f.fainelli, davem, Gavin Shan
In-Reply-To: <1493786681-27468-1-git-send-email-gwshan@linux.vnet.ibm.com>

The field @monitor.enabled in the NCSI channel descriptor is used
to track the state of channel monitor timer. It indicates the timer's
state (pending or not). We could not start the timer again in its
handler. In that case, We missed to update @monitor.enabled to false.
It leads to below warning printed by WARN_ON_ONCE() when the monitor
is restarted afterwards.

   ------------[ cut here ]------------
   WARNING: CPU: 0 PID: 411 at /var/lib/jenkins/workspace/openbmc-build \
   /distro/ubuntu/target/palmetto/openbmc/build/tmp/work-shared/palmetto \
   net/ncsi/ncsi-manage.c:240 ncsi_start_channel_monitor+0x44/0x7c
   CPU: 0 PID: 411 Comm: kworker/0:3 Not tainted \
   4.7.10-f26558191540830589fe03932d05577957670b8d #1
   Hardware name: ASpeed SoC
   Workqueue: events ncsi_dev_work
   [<c0106cbc>] (unwind_backtrace) from [<c0104f04>] (show_stack+0x10/0x14)
   [<c0104f04>] (show_stack) from [<c010eef8>] (__warn+0xc4/0xf0)
   [<c010eef8>] (__warn) from [<c010f018>] (warn_slowpath_null+0x1c/0x24)
   [<c010f018>] (warn_slowpath_null) from [<c03e1d10>] (ncsi_start_channel_monitor+0x44/0x7c)
   [<c03e1d10>] (ncsi_start_channel_monitor) from [<c03e29c4>] (ncsi_configure_channel+0x27c/0x2dc)
   [<c03e29c4>] (ncsi_configure_channel) from [<c03e31d0>] (ncsi_dev_work+0x39c/0x3e8)
   [<c03e31d0>] (ncsi_dev_work) from [<c0120288>] (process_one_work+0x1b8/0x2fc)
   [<c0120288>] (process_one_work) from [<c01206bc>] (worker_thread+0x2c0/0x3f8)
   [<c01206bc>] (worker_thread) from [<c0124b10>] (kthread+0xd0/0xe8)
   [<c0124b10>] (kthread) from [<c0102250>] (ret_from_fork+0x14/0x24)
   ---[ end trace 110cccf2b038c44d ]---

This fixes the issue by updating @monitor.enabled to false if needed.

Reported-by: Sridevi Ramesh <sridevra@in.ibm.com>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 net/ncsi/ncsi-manage.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index 5073e15..c71a3a5 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -183,11 +183,16 @@ static void ncsi_channel_monitor(unsigned long data)
 	monitor_state = nc->monitor.state;
 	spin_unlock_irqrestore(&nc->lock, flags);
 
-	if (!enabled || chained)
+	if (!enabled || chained) {
+		ncsi_stop_channel_monitor(nc);
 		return;
+	}
+
 	if (state != NCSI_CHANNEL_INACTIVE &&
-	    state != NCSI_CHANNEL_ACTIVE)
+	    state != NCSI_CHANNEL_ACTIVE) {
+		ncsi_stop_channel_monitor(nc);
 		return;
+	}
 
 	switch (monitor_state) {
 	case NCSI_CHANNEL_MONITOR_START:
@@ -199,6 +204,7 @@ static void ncsi_channel_monitor(unsigned long data)
 		nca.req_flags = 0;
 		ret = ncsi_xmit_cmd(&nca);
 		if (ret) {
+			ncsi_stop_channel_monitor(nc);
 			netdev_err(ndp->ndev.dev, "Error %d sending GLS\n",
 				   ret);
 			return;
@@ -218,6 +224,8 @@ static void ncsi_channel_monitor(unsigned long data)
 		nc->state = NCSI_CHANNEL_INVISIBLE;
 		spin_unlock_irqrestore(&nc->lock, flags);
 
+		ncsi_stop_channel_monitor(nc);
+
 		spin_lock_irqsave(&ndp->lock, flags);
 		nc->state = NCSI_CHANNEL_INACTIVE;
 		list_add_tail_rcu(&nc->link, &ndp->channel_queue);
@@ -257,6 +265,10 @@ void ncsi_stop_channel_monitor(struct ncsi_channel *nc)
 	nc->monitor.enabled = false;
 	spin_unlock_irqrestore(&nc->lock, flags);
 
+	/* The timer isn't in pending state if we're deleting the timer
+	 * in its handler. del_timer_sync() can detect it and just does
+	 * nothing.
+	 */
 	del_timer_sync(&nc->monitor.timer);
 }
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 net-next 03/10] net/ncsi: Enforce failover on link monitor timeout
From: Gavin Shan @ 2017-05-03  4:44 UTC (permalink / raw)
  To: netdev; +Cc: joe, kubakici, f.fainelli, davem, Gavin Shan
In-Reply-To: <1493786681-27468-1-git-send-email-gwshan@linux.vnet.ibm.com>

The NCSI channel has been configured to provide service if its link
monitor timer is enabled, regardless of its state (inactive or active).
So the timeout event on the link monitor indicates the out-of-service
on that channel, for which a failover is needed.

This sets NCSI_DEV_RESHUFFLE flag to enforce failover on link monitor
timeout, regardless the channel's original state (inactive or active).
Also, the link is put into "down" state to give the failing channel
lowest priority when selecting for the active channel. The state of
failing channel should be set to active in order for deinitialization
and failover to be done.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 net/ncsi/ncsi-manage.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index c71a3a5..13ad1f26 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -170,6 +170,7 @@ static void ncsi_channel_monitor(unsigned long data)
 	struct ncsi_channel *nc = (struct ncsi_channel *)data;
 	struct ncsi_package *np = nc->package;
 	struct ncsi_dev_priv *ndp = np->ndp;
+	struct ncsi_channel_mode *ncm;
 	struct ncsi_cmd_arg nca;
 	bool enabled, chained;
 	unsigned int monitor_state;
@@ -214,20 +215,21 @@ static void ncsi_channel_monitor(unsigned long data)
 	case NCSI_CHANNEL_MONITOR_WAIT ... NCSI_CHANNEL_MONITOR_WAIT_MAX:
 		break;
 	default:
-		if (!(ndp->flags & NCSI_DEV_HWA) &&
-		    state == NCSI_CHANNEL_ACTIVE) {
+		if (!(ndp->flags & NCSI_DEV_HWA)) {
 			ncsi_report_link(ndp, true);
 			ndp->flags |= NCSI_DEV_RESHUFFLE;
 		}
 
+		ncm = &nc->modes[NCSI_MODE_LINK];
 		spin_lock_irqsave(&nc->lock, flags);
 		nc->state = NCSI_CHANNEL_INVISIBLE;
+		ncm->data[2] &= ~0x1;
 		spin_unlock_irqrestore(&nc->lock, flags);
 
 		ncsi_stop_channel_monitor(nc);
 
 		spin_lock_irqsave(&ndp->lock, flags);
-		nc->state = NCSI_CHANNEL_INACTIVE;
+		nc->state = NCSI_CHANNEL_ACTIVE;
 		list_add_tail_rcu(&nc->link, &ndp->channel_queue);
 		spin_unlock_irqrestore(&ndp->lock, flags);
 		ncsi_process_next_channel(ndp);
-- 
2.7.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