Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next] tuntap: fix possible deadlock when fail to register netdev
From: Jason Wang @ 2017-12-08  2:54 UTC (permalink / raw)
  To: netdev, linux-kernel; +Cc: mst, Jason Wang, Eric Dumazet, Willem de Bruijn

Private destructor could be called when register_netdev() fail with
rtnl lock held. This will lead deadlock in tun_free_netdev() who tries
to hold rtnl_lock. Fixing this by switching to use spinlock to
synchronize.

Fixes: 96f84061620c ("tun: add eBPF based queue selection method")
Reported-by: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Willem de Bruijn <willemb@google.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
 drivers/net/tun.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 787cc35..f7ccd79 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -2050,8 +2050,11 @@ static int __tun_set_steering_ebpf(struct tun_struct *tun,
 		new->prog = prog;
 	}
 
-	old = rtnl_dereference(tun->steering_prog);
+	spin_lock(&tun->lock);
+	old = rcu_dereference_protected(tun->steering_prog,
+					lock_is_held(&tun->lock));
 	rcu_assign_pointer(tun->steering_prog, new);
+	spin_unlock(&tun->lock);
 
 	if (old)
 		call_rcu(&old->rcu, tun_steering_prog_free);
@@ -2067,9 +2070,7 @@ static void tun_free_netdev(struct net_device *dev)
 	free_percpu(tun->pcpu_stats);
 	tun_flow_uninit(tun);
 	security_tun_dev_free_security(tun->security);
-	rtnl_lock();
 	__tun_set_steering_ebpf(tun, NULL);
-	rtnl_unlock();
 }
 
 static void tun_setup(struct net_device *dev)
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 0/3] Bluetooth: hci_ll: Get BD address from NVMEM (was "bluetooth: hci_ll: Get MAC address from NVMEM")
From: David Lechner @ 2017-12-08  2:57 UTC (permalink / raw)
  To: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-bluetooth-u79uwXL29TY76Z2rM5mHXA
  Cc: David Lechner, Rob Herring, Mark Rutland, Marcel Holtmann,
	Gustavo Padovan, Johan Hedberg, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

This series adds supporting getting the BD address from a NVMEM provider
for "LL" HCI controllers (Texas Instruments).

v2 changes:
* Fixed typos in dt-bindings
* Use "bd-address" instead of "mac-address"
* Updated dt-bindings to specify the byte order of "bd-address"
* New patch "Bluetooth: hci_ll: add support for setting public address"
* Dropped patch "Bluetooth: hci_ll: add constant for vendor-specific command"
  that is already in bluetooth-next
* Rework error handling
* Use bdaddr_t, bacmp and other bluetooth utils

David Lechner (3):
  Bluetooth: hci_ll: add support for setting public address
  dt-bindings: Add optional nvmem BD address bindings to ti,wlink-st
  Bluetooth: hci_ll: Add optional nvmem BD address source

 .../devicetree/bindings/net/ti,wilink-st.txt       |  5 ++
 drivers/bluetooth/hci_ll.c                         | 71 ++++++++++++++++++++++
 2 files changed, 76 insertions(+)

-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v2 1/3] Bluetooth: hci_ll: add support for setting public address
From: David Lechner @ 2017-12-08  2:57 UTC (permalink / raw)
  To: devicetree, linux-bluetooth
  Cc: David Lechner, Rob Herring, Mark Rutland, Marcel Holtmann,
	Gustavo Padovan, Johan Hedberg, netdev, linux-kernel
In-Reply-To: <1512701860-8321-1-git-send-email-david@lechnology.com>

This adds support for setting the public address on Texas Instruments
Bluetooth chips using a vendor-specific command.

This has been tested on a CC2560A. The TI wiki also indicates that this
command should work on TI WL17xx/WL18xx Bluetooth chips.

Signed-off-by: David Lechner <david@lechnology.com>
---

v2 changes:
* This is a new patch in v2

 drivers/bluetooth/hci_ll.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index 974a788..b732004 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -57,6 +57,7 @@
 #include "hci_uart.h"
 
 /* Vendor-specific HCI commands */
+#define HCI_VS_WRITE_BD_ADDR			0xfc06
 #define HCI_VS_UPDATE_UART_HCI_BAUDRATE		0xff36
 
 /* HCILL commands */
@@ -662,6 +663,20 @@ static int download_firmware(struct ll_device *lldev)
 	return err;
 }
 
+static int ll_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
+{
+	bdaddr_t bdaddr_swapped;
+	struct sk_buff *skb;
+
+	baswap(&bdaddr_swapped, bdaddr);
+	skb = __hci_cmd_sync(hdev, HCI_VS_WRITE_BD_ADDR, sizeof(bdaddr_t),
+			     &bdaddr_swapped, HCI_INIT_TIMEOUT);
+	if (!IS_ERR(skb))
+		kfree_skb(skb);
+	
+	return PTR_ERR_OR_ZERO(skb);
+}
+
 static int ll_setup(struct hci_uart *hu)
 {
 	int err, retry = 3;
@@ -674,6 +689,8 @@ static int ll_setup(struct hci_uart *hu)
 
 	lldev = serdev_device_get_drvdata(serdev);
 
+	hu->hdev->set_bdaddr = ll_set_bdaddr;
+
 	serdev_device_set_flow_control(serdev, true);
 
 	do {
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 2/3] dt-bindings: Add optional nvmem BD address bindings to ti,wlink-st
From: David Lechner @ 2017-12-08  2:57 UTC (permalink / raw)
  To: devicetree, linux-bluetooth
  Cc: David Lechner, Rob Herring, Mark Rutland, Marcel Holtmann,
	Gustavo Padovan, Johan Hedberg, netdev, linux-kernel
In-Reply-To: <1512701860-8321-1-git-send-email-david@lechnology.com>

This adds optional nvmem consumer properties to the ti,wlink-st device tree
bindings to allow specifying the BD address.

Signed-off-by: David Lechner <david@lechnology.com>
---

v2 changes:
* Renamed "mac-address" to "bd-address"
* Fixed typos in example
* Specify byte order of "bd-address"

 Documentation/devicetree/bindings/net/ti,wilink-st.txt | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/ti,wilink-st.txt b/Documentation/devicetree/bindings/net/ti,wilink-st.txt
index 1649c1f..a45a508 100644
--- a/Documentation/devicetree/bindings/net/ti,wilink-st.txt
+++ b/Documentation/devicetree/bindings/net/ti,wilink-st.txt
@@ -32,6 +32,9 @@ Optional properties:
    See ../clocks/clock-bindings.txt for details.
  - clock-names : Must include the following entry:
    "ext_clock" (External clock provided to the TI combo chip).
+ - nvmem-cells: phandle to nvmem data cell that contains a 6 byte BD address
+   with the most significant byte first (big-endian).
+ - nvmem-cell-names: "bd-address" (required when nvmem-cells is specified)
 
 Example:
 
@@ -43,5 +46,7 @@ Example:
 		enable-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
 		clocks = <&clk32k_wl18xx>;
 		clock-names = "ext_clock";
+		nvmem-cells = <&bd_address>;
+		nvmem-cell-names = "bd-address";
 	};
 };
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 3/3] Bluetooth: hci_ll: Add optional nvmem BD address source
From: David Lechner @ 2017-12-08  2:57 UTC (permalink / raw)
  To: devicetree, linux-bluetooth
  Cc: David Lechner, Rob Herring, Mark Rutland, Marcel Holtmann,
	Gustavo Padovan, Johan Hedberg, netdev, linux-kernel
In-Reply-To: <1512701860-8321-1-git-send-email-david@lechnology.com>

This adds an optional nvmem consumer to get a BD address from an external
source. The BD address is then set in the Bluetooth chip after the
firmware has been loaded.

This has been tested working with a TI CC2560A chip (in a LEGO MINDSTORMS
EV3).

Signed-off-by: David Lechner <david@lechnology.com>
---

v2 changes:
* Add support for HCI_QUIRK_INVALID_BDADDR when there is an error getting the
  BD address from nvmem
* Rework error handling
* rename "mac-address" to "bd-address"
* use bdaddr_t, bacmp and other bluetooth helper functions
* use ll_set_bdaddr() from new, separate patch

 drivers/bluetooth/hci_ll.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index b732004..f5fef2d 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -53,6 +53,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <linux/gpio/consumer.h>
+#include <linux/nvmem-consumer.h>
 
 #include "hci_uart.h"
 
@@ -90,6 +91,7 @@ struct ll_device {
 	struct serdev_device *serdev;
 	struct gpio_desc *enable_gpio;
 	struct clk *ext_clk;
+	bdaddr_t bdaddr;
 };
 
 struct ll_struct {
@@ -715,6 +717,19 @@ static int ll_setup(struct hci_uart *hu)
 	if (err)
 		return err;
 
+	/* Set BD address if one was specified at probe */
+	if (!bacmp(&lldev->bdaddr, BDADDR_NONE)) {
+		/*
+		 * This means that there was an error getting the BD address
+		 * during probe, so mark the device as having a bad address.
+		 */
+		set_bit(HCI_QUIRK_INVALID_BDADDR, &hu->hdev->quirks);
+	} else if (bacmp(&lldev->bdaddr, BDADDR_ANY)) {
+		err = ll_set_bdaddr(hu->hdev, &lldev->bdaddr);
+		if (err)
+			set_bit(HCI_QUIRK_INVALID_BDADDR, &hu->hdev->quirks);
+	}
+
 	/* Operational speed if any */
 	if (hu->oper_speed)
 		speed = hu->oper_speed;
@@ -743,6 +758,7 @@ static int hci_ti_probe(struct serdev_device *serdev)
 {
 	struct hci_uart *hu;
 	struct ll_device *lldev;
+	struct nvmem_cell *bdaddr_cell;
 	u32 max_speed = 3000000;
 
 	lldev = devm_kzalloc(&serdev->dev, sizeof(struct ll_device), GFP_KERNEL);
@@ -764,6 +780,45 @@ static int hci_ti_probe(struct serdev_device *serdev)
 	of_property_read_u32(serdev->dev.of_node, "max-speed", &max_speed);
 	hci_uart_set_speeds(hu, 115200, max_speed);
 
+	/* optional BD address from nvram */
+	bdaddr_cell = nvmem_cell_get(&serdev->dev, "bd-address");
+	if (IS_ERR(bdaddr_cell)) {
+		int err = PTR_ERR(bdaddr_cell);
+
+		if (err == -EPROBE_DEFER)
+			return err;
+
+		/*
+		 * ENOENT means there is no matching nvmem cell and ENOSYS
+		 * means that nvmem is not enabled in the kernel configuration.
+		 */
+		if (err != -ENOENT && err != -ENOSYS) {
+			/*
+			 * If there was some other error, give userspace a
+			 * chance to fix the problem instead of failing to load
+			 * the driver. Using BDADDR_NONE as a flag that is
+			 * tested later in the setup function.
+			 */
+			dev_warn(&serdev->dev,
+				 "Failed to get \"bd-address\" nvmem cell (%d)\n",
+				 err);
+			bacpy(&lldev->bdaddr, BDADDR_NONE);
+		}
+	} else {
+		bdaddr_t *bdaddr;
+		int len;
+
+		bdaddr = nvmem_cell_read(bdaddr_cell, &len);
+		if (len != sizeof(bdaddr_t)) {
+			dev_err(&serdev->dev, "Invalid nvmem bd-address length\n");
+			nvmem_cell_put(bdaddr_cell);
+			return -EINVAL;
+		}
+
+		baswap(&lldev->bdaddr, bdaddr);
+		nvmem_cell_put(bdaddr_cell);
+	}
+
 	return hci_uart_register_device(hu, &llp);
 }
 
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH net-next] tuntap: fix possible deadlock when fail to register netdev
From: Eric Dumazet @ 2017-12-08  3:11 UTC (permalink / raw)
  To: Jason Wang, netdev, linux-kernel; +Cc: mst, Willem de Bruijn
In-Reply-To: <1512701655-18751-1-git-send-email-jasowang@redhat.com>

On Fri, 2017-12-08 at 10:54 +0800, Jason Wang wrote:
> Private destructor could be called when register_netdev() fail with
> rtnl lock held. This will lead deadlock in tun_free_netdev() who
> tries
> to hold rtnl_lock. Fixing this by switching to use spinlock to
> synchronize.
> 
> Fixes: 96f84061620c ("tun: add eBPF based queue selection method")
> Reported-by: Eric Dumazet <eric.dumazet@gmail.com>
> Cc: Eric Dumazet <eric.dumazet@gmail.com>
> Cc: Willem de Bruijn <willemb@google.com>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
>  drivers/net/tun.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index 787cc35..f7ccd79 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -2050,8 +2050,11 @@ static int __tun_set_steering_ebpf(struct
> tun_struct *tun,
>  		new->prog = prog;
>  	}
>  
> -	old = rtnl_dereference(tun->steering_prog);
> +	spin_lock(&tun->lock);
> +	old = rcu_dereference_protected(tun->steering_prog,
> +					lock_is_held(&tun->lock));
>  	rcu_assign_pointer(tun->steering_prog, new);
> +	spin_unlock(&tun->lock);
> 

Hi Jason, thank you for the following up.

Have you tested this code path with lockdep enabled ?

My gut feeling is that you need spin_lock_bh() here.

Thanks

^ permalink raw reply

* Re: [PATCH net-next] tuntap: fix possible deadlock when fail to register netdev
From: Jason Wang @ 2017-12-08  3:27 UTC (permalink / raw)
  To: Eric Dumazet, netdev, linux-kernel; +Cc: mst, Willem de Bruijn
In-Reply-To: <1512702678.25033.20.camel@gmail.com>



On 2017年12月08日 11:11, Eric Dumazet wrote:
> On Fri, 2017-12-08 at 10:54 +0800, Jason Wang wrote:
>> Private destructor could be called when register_netdev() fail with
>> rtnl lock held. This will lead deadlock in tun_free_netdev() who
>> tries
>> to hold rtnl_lock. Fixing this by switching to use spinlock to
>> synchronize.
>>
>> Fixes: 96f84061620c ("tun: add eBPF based queue selection method")
>> Reported-by: Eric Dumazet <eric.dumazet@gmail.com>
>> Cc: Eric Dumazet <eric.dumazet@gmail.com>
>> Cc: Willem de Bruijn <willemb@google.com>
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>> ---
>>   drivers/net/tun.c | 7 ++++---
>>   1 file changed, 4 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
>> index 787cc35..f7ccd79 100644
>> --- a/drivers/net/tun.c
>> +++ b/drivers/net/tun.c
>> @@ -2050,8 +2050,11 @@ static int __tun_set_steering_ebpf(struct
>> tun_struct *tun,
>>   		new->prog = prog;
>>   	}
>>   
>> -	old = rtnl_dereference(tun->steering_prog);
>> +	spin_lock(&tun->lock);
>> +	old = rcu_dereference_protected(tun->steering_prog,
>> +					lock_is_held(&tun->lock));
>>   	rcu_assign_pointer(tun->steering_prog, new);
>> +	spin_unlock(&tun->lock);
>>
> Hi Jason, thank you for the following up.
>
> Have you tested this code path with lockdep enabled ?

No I test without it.

>
> My gut feeling is that you need spin_lock_bh() here.
>
> Thanks
>

Yes, I miss the fact this the lock is used by e.g flow caches too. Will 
post V2.

Thanks

^ permalink raw reply

* Re: [PATCH net-next 09/12] sctp: implement renege_events for sctp_stream_interleave
From: kbuild test robot @ 2017-12-08  3:45 UTC (permalink / raw)
  To: Xin Long
  Cc: kbuild-all, network dev, linux-sctp, Marcelo Ricardo Leitner,
	Neil Horman, davem
In-Reply-To: <167166ed3ee953dbcee3aef43496d8c7b44c6b95.1512486606.git.lucien.xin@gmail.com>

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

Hi Xin,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Xin-Long/sctp-Implement-Stream-Interleave-The-I-DATA-Chunk-Supporting-User-Message-Interleaving/20171208-031625
config: x86_64-randconfig-g0-12080821 (attached as .config)
compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   Cyclomatic Complexity 1 include/linux/spinlock.h:spinlock_check
   Cyclomatic Complexity 1 include/linux/skbuff.h:skb_queue_empty
   Cyclomatic Complexity 2 include/linux/skbuff.h:skb_peek_tail
   Cyclomatic Complexity 1 include/linux/skbuff.h:__skb_queue_head_init
   Cyclomatic Complexity 1 include/linux/skbuff.h:__skb_insert
   Cyclomatic Complexity 1 include/linux/skbuff.h:__skb_queue_splice
   Cyclomatic Complexity 2 include/linux/skbuff.h:skb_queue_splice_tail_init
   Cyclomatic Complexity 1 include/linux/skbuff.h:__skb_queue_before
   Cyclomatic Complexity 1 include/linux/skbuff.h:__skb_queue_tail
   Cyclomatic Complexity 1 include/linux/skbuff.h:__skb_unlink
   Cyclomatic Complexity 1 include/net/net_namespace.h:read_pnet
   Cyclomatic Complexity 1 include/net/sock.h:sk_has_account
   Cyclomatic Complexity 1 include/net/sock.h:sock_net
   Cyclomatic Complexity 1 include/net/busy_poll.h:sk_mark_napi_id
   Cyclomatic Complexity 1 include/net/sctp/ulpevent.h:sctp_skb2event
   Cyclomatic Complexity 2 include/net/sctp/ulpevent.h:sctp_ulpevent_type_enabled
   Cyclomatic Complexity 1 include/net/sctp/structs.h:sctp_sk
   Cyclomatic Complexity 1 include/net/sctp/structs.h:sctp_chunk_stream_no
   Cyclomatic Complexity 6 net//sctp/stream_interleave.c:sctp_validate_data
   Cyclomatic Complexity 15 net//sctp/stream_interleave.c:sctp_intl_retrieve_first
   Cyclomatic Complexity 16 net//sctp/stream_interleave.c:sctp_intl_retrieve_partial
   Cyclomatic Complexity 25 net//sctp/stream_interleave.c:sctp_intl_retrieve_reassembled
   Cyclomatic Complexity 3 include/net/sock.h:sk_mem_reclaim
   Cyclomatic Complexity 2 include/net/sctp/ulpevent.h:sctp_event2skb
   Cyclomatic Complexity 23 net//sctp/stream_interleave.c:sctp_intl_store_reasm
   Cyclomatic Complexity 6 net//sctp/stream_interleave.c:sctp_intl_reasm
   Cyclomatic Complexity 13 net//sctp/stream_interleave.c:sctp_intl_store_ordered
   Cyclomatic Complexity 5 net//sctp/stream_interleave.c:sctp_intl_retrieve_ordered
   Cyclomatic Complexity 3 net//sctp/stream_interleave.c:sctp_intl_order
   Cyclomatic Complexity 2 include/net/sock.h:sk_incoming_cpu_update
   Cyclomatic Complexity 2 include/net/sctp/ulpevent.h:sctp_ulpevent_is_enabled
   Cyclomatic Complexity 9 net//sctp/stream_interleave.c:sctp_enqueue_event
   Cyclomatic Complexity 4 net//sctp/stream_interleave.c:sctp_intl_start_pd
   Cyclomatic Complexity 6 net//sctp/stream_interleave.c:sctp_validate_idata
   Cyclomatic Complexity 8 net//sctp/stream_interleave.c:sctp_chunk_assign_mid
   Cyclomatic Complexity 1 include/linux/skbuff.h:skb_queue_head_init
   Cyclomatic Complexity 6 net//sctp/stream_interleave.c:sctp_ulpevent_idata
   Cyclomatic Complexity 7 net//sctp/stream_interleave.c:sctp_renege_events
   Cyclomatic Complexity 3 net//sctp/stream_interleave.c:sctp_make_idatafrag_empty
   Cyclomatic Complexity 3 net//sctp/stream_interleave.c:sctp_stream_interleave_init
   net//sctp/stream_interleave.c: In function 'sctp_renege_events':
>> net//sctp/stream_interleave.c:581:26: warning: 'sin' may be used uninitialized in this function [-Wmaybe-uninitialized]
           cevent->mid == sin->mid &&
                             ^
   net//sctp/stream_interleave.c:550:32: note: 'sin' was declared here
     struct sctp_stream_in *csin, *sin;
                                   ^

vim +/sin +581 net//sctp/stream_interleave.c

   547	
   548	static struct sctp_ulpevent *sctp_intl_retrieve_first(struct sctp_ulpq *ulpq)
   549	{
   550		struct sctp_stream_in *csin, *sin;
   551		struct sk_buff *first_frag = NULL;
   552		struct sk_buff *last_frag = NULL;
   553		struct sctp_ulpevent *retval;
   554		struct sk_buff *pos;
   555		__u32 next_fsn = 0;
   556		__u16 sid = 0;
   557	
   558		skb_queue_walk(&ulpq->reasm, pos) {
   559			struct sctp_ulpevent *cevent = sctp_skb2event(pos);
   560	
   561			csin = sctp_stream_in(ulpq->asoc, cevent->stream);
   562			if (csin->pd_mode)
   563				continue;
   564	
   565			switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
   566			case SCTP_DATA_FIRST_FRAG:
   567				if (first_frag)
   568					goto out;
   569				if (cevent->mid == csin->mid) {
   570					first_frag = pos;
   571					last_frag = pos;
   572					next_fsn = 0;
   573					sin = csin;
   574					sid = cevent->stream;
   575				}
   576				break;
   577			case SCTP_DATA_MIDDLE_FRAG:
   578				if (!first_frag)
   579					break;
   580				if (cevent->stream == sid &&
 > 581				    cevent->mid == sin->mid &&
   582				    cevent->fsn == next_fsn) {
   583					next_fsn++;
   584					last_frag = pos;
   585				} else {
   586					goto out;
   587				}
   588				break;
   589			case SCTP_DATA_LAST_FRAG:
   590				if (first_frag)
   591					goto out;
   592				break;
   593			default:
   594				break;
   595			}
   596		}
   597	
   598		if (!first_frag)
   599			return NULL;
   600	
   601	out:
   602		retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk),
   603						     &ulpq->reasm, first_frag,
   604						     last_frag);
   605		if (retval) {
   606			sin->fsn = next_fsn;
   607			sin->pd_mode = 1;
   608		}
   609	
   610		return retval;
   611	}
   612	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 35797 bytes --]

^ permalink raw reply

* Re: [PATCH v5 net-next] net/tcp: trace all TCP/IP state transition with tcp_set_state tracepoint
From: Yafang Shao @ 2017-12-08  3:40 UTC (permalink / raw)
  To: Marcelo Ricardo Leitner
  Cc: David Miller, Song Liu, Alexey Kuznetsov, yoshfuji,
	Steven Rostedt, Brendan Gregg, netdev, LKML
In-Reply-To: <CALOAHbAixEmBFTuTD42GtC6sbqdguGVSEX8w6+GTw6rLRwRuUQ@mail.gmail.com>

2017-12-08 9:41 GMT+08:00 Yafang Shao <laoar.shao@gmail.com>:
> 2017-12-08 4:02 GMT+08:00 Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>:
>> On Thu, Dec 07, 2017 at 02:10:42PM +0000, Yafang Shao wrote:
>>> The TCP/IP transition from TCP_LISTEN to TCP_SYN_RECV and some other
>>> transitions are not traced with tcp_set_state tracepoint.
>>>
>>> In order to trace the whole tcp lifespans, two helpers are introduced,
>>> void sk_set_state(struct sock *sk, int state);
>>> void sk_state_store(struct sock *sk, int newstate);
>>>
>>> When do TCP/IP state transition, we should use these two helpers or use
>>> tcp_set_state() other than assigning a value to sk_state directly.
>>>
>>> Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
>>> Acked-by: Song Liu <songliubraving@fb.com>
>>> Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
>>> Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
>>> ---
>>> v4->v5: Trace only TCP sockets, whatever it is stream socket or raw socket.
>>> v3->v4: Do not trace DCCP socket
>>> v2->v3: Per suggestion from Marcelo Ricardo Leitner, inverting  __
>>>                to sk_state_store.
>>> ---
>>>  include/net/sock.h              |  8 ++++++--
>>>  net/core/sock.c                 | 15 +++++++++++++++
>>>  net/ipv4/inet_connection_sock.c |  5 +++--
>>>  net/ipv4/inet_hashtables.c      |  2 +-
>>>  net/ipv4/tcp.c                  |  2 +-
>>>  5 files changed, 26 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/include/net/sock.h b/include/net/sock.h
>>> index 79e1a2c..1cf7685 100644
>>> --- a/include/net/sock.h
>>> +++ b/include/net/sock.h
>>> @@ -2349,18 +2349,22 @@ static inline int sk_state_load(const struct sock *sk)
>>>  }
>>>
>>>  /**
>>> - * sk_state_store - update sk->sk_state
>>> + * __sk_state_store - update sk->sk_state
>>>   * @sk: socket pointer
>>>   * @newstate: new state
>>>   *
>>>   * Paired with sk_state_load(). Should be used in contexts where
>>>   * state change might impact lockless readers.
>>>   */
>>> -static inline void sk_state_store(struct sock *sk, int newstate)
>>> +static inline void __sk_state_store(struct sock *sk, int newstate)
>>>  {
>>>       smp_store_release(&sk->sk_state, newstate);
>>>  }
>>>
>>> +/* For tcp_set_state tracepoint */
>>> +void sk_state_store(struct sock *sk, int newstate);
>>> +void sk_set_state(struct sock *sk, int state);
>>> +
>>>  void sock_enable_timestamp(struct sock *sk, int flag);
>>>  int sock_get_timestamp(struct sock *, struct timeval __user *);
>>>  int sock_get_timestampns(struct sock *, struct timespec __user *);
>>> diff --git a/net/core/sock.c b/net/core/sock.c
>>> index c0b5b2f..61841a2 100644
>>> --- a/net/core/sock.c
>>> +++ b/net/core/sock.c
>>> @@ -138,6 +138,7 @@
>>>  #include <net/sock_reuseport.h>
>>>
>>>  #include <trace/events/sock.h>
>>> +#include <trace/events/tcp.h>
>>>
>>>  #include <net/tcp.h>
>>>  #include <net/busy_poll.h>
>>> @@ -2859,6 +2860,20 @@ int sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
>>>  }
>>>  EXPORT_SYMBOL(sock_get_timestampns);
>>>
>>> +void sk_state_store(struct sock *sk, int newstate)
>>> +{
>>> +     if (sk->sk_protocol == IPPROTO_TCP)
>>> +             trace_tcp_set_state(sk, sk->sk_state, newstate);
>>
>> I think this is going in the wrong way. When Dave said to not define a
>> sock generic function in tcp code on v3, you moved it all from tcp.h
>> to sock.h. But now sock.h gets to deal with more tcp code, which also
>> isn't nice.
>>
>> Instead, if you move it back to tcp.h but rename the function to
>> tcp_state_store (instead of the original sk_state_store), it won't be
>> a generic sock code and will fit nicely into tcp.h.
>>
>> You may then even keep sk_state_store() as it is now, and just define
>> tcp_state_store():
>>
>> tcp_state_store()
>> {
>>         trace_tcp_...();
>>         sk_state_store();
>> }
>>
>> Making it very clear that this code is only to be used by tcp stack.
>>
>
> Then we have to do bellow 'if' test in inet_connection_sock.c and
> /inet_hashtables.
>
> if (sk->sk_protocol == IPPROTO_TCP)
>     tcp_state_store(sk, TCP_CLOSE)
> else
>     sk->sk_state = TCP_CLOSE;
>
> And same code about other changes.
>
> Is that proper ?
>
>

It will looks like these,

    if (sk->sk_protocol == IPPROTO_TCP)
        __tcp_set_state(newsk, TCP_SYN_RECV);
    else
        newsk->sk_state = TCP_SYN_RECV;


    if (sk->sk_protocol == IPPROTO_TCP)
          __tcp_set_state(sk, TCP_CLOSE);
    else
          sk->sk_state = TCP_CLOSE;

    if (sk->sk_protocol == IPPROTO_TCP)
          tcp_state_store(sk,  state);
    else
          sk_state_store(sk, state);


Some redundant code.

IMO, put these similar code into a wrapper is more nice.

Thanks
Yafang

^ permalink raw reply

* Re: [PATCH net-next 09/12] sctp: implement renege_events for sctp_stream_interleave
From: Xin Long @ 2017-12-08  3:44 UTC (permalink / raw)
  To: kbuild test robot
  Cc: kbuild-all, network dev, linux-sctp, Marcelo Ricardo Leitner,
	Neil Horman, davem
In-Reply-To: <201712081042.25vrMdbv%fengguang.wu@intel.com>

On Fri, Dec 8, 2017 at 11:45 AM, kbuild test robot <lkp@intel.com> wrote:
> Hi Xin,
>
> Thank you for the patch! Perhaps something to improve:
>
> [auto build test WARNING on net-next/master]
>
> url:    https://github.com/0day-ci/linux/commits/Xin-Long/sctp-Implement-Stream-Interleave-The-I-DATA-Chunk-Supporting-User-Message-Interleaving/20171208-031625
> config: x86_64-randconfig-g0-12080821 (attached as .config)
> compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
> reproduce:
>         # save the attached .config to linux build tree
>         make ARCH=x86_64
>
> Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
> http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings
>
> All warnings (new ones prefixed by >>):
>
>    Cyclomatic Complexity 1 include/linux/spinlock.h:spinlock_check
>    Cyclomatic Complexity 1 include/linux/skbuff.h:skb_queue_empty
>    Cyclomatic Complexity 2 include/linux/skbuff.h:skb_peek_tail
>    Cyclomatic Complexity 1 include/linux/skbuff.h:__skb_queue_head_init
>    Cyclomatic Complexity 1 include/linux/skbuff.h:__skb_insert
>    Cyclomatic Complexity 1 include/linux/skbuff.h:__skb_queue_splice
>    Cyclomatic Complexity 2 include/linux/skbuff.h:skb_queue_splice_tail_init
>    Cyclomatic Complexity 1 include/linux/skbuff.h:__skb_queue_before
>    Cyclomatic Complexity 1 include/linux/skbuff.h:__skb_queue_tail
>    Cyclomatic Complexity 1 include/linux/skbuff.h:__skb_unlink
>    Cyclomatic Complexity 1 include/net/net_namespace.h:read_pnet
>    Cyclomatic Complexity 1 include/net/sock.h:sk_has_account
>    Cyclomatic Complexity 1 include/net/sock.h:sock_net
>    Cyclomatic Complexity 1 include/net/busy_poll.h:sk_mark_napi_id
>    Cyclomatic Complexity 1 include/net/sctp/ulpevent.h:sctp_skb2event
>    Cyclomatic Complexity 2 include/net/sctp/ulpevent.h:sctp_ulpevent_type_enabled
>    Cyclomatic Complexity 1 include/net/sctp/structs.h:sctp_sk
>    Cyclomatic Complexity 1 include/net/sctp/structs.h:sctp_chunk_stream_no
>    Cyclomatic Complexity 6 net//sctp/stream_interleave.c:sctp_validate_data
>    Cyclomatic Complexity 15 net//sctp/stream_interleave.c:sctp_intl_retrieve_first
>    Cyclomatic Complexity 16 net//sctp/stream_interleave.c:sctp_intl_retrieve_partial
>    Cyclomatic Complexity 25 net//sctp/stream_interleave.c:sctp_intl_retrieve_reassembled
>    Cyclomatic Complexity 3 include/net/sock.h:sk_mem_reclaim
>    Cyclomatic Complexity 2 include/net/sctp/ulpevent.h:sctp_event2skb
>    Cyclomatic Complexity 23 net//sctp/stream_interleave.c:sctp_intl_store_reasm
>    Cyclomatic Complexity 6 net//sctp/stream_interleave.c:sctp_intl_reasm
>    Cyclomatic Complexity 13 net//sctp/stream_interleave.c:sctp_intl_store_ordered
>    Cyclomatic Complexity 5 net//sctp/stream_interleave.c:sctp_intl_retrieve_ordered
>    Cyclomatic Complexity 3 net//sctp/stream_interleave.c:sctp_intl_order
>    Cyclomatic Complexity 2 include/net/sock.h:sk_incoming_cpu_update
>    Cyclomatic Complexity 2 include/net/sctp/ulpevent.h:sctp_ulpevent_is_enabled
>    Cyclomatic Complexity 9 net//sctp/stream_interleave.c:sctp_enqueue_event
>    Cyclomatic Complexity 4 net//sctp/stream_interleave.c:sctp_intl_start_pd
>    Cyclomatic Complexity 6 net//sctp/stream_interleave.c:sctp_validate_idata
>    Cyclomatic Complexity 8 net//sctp/stream_interleave.c:sctp_chunk_assign_mid
>    Cyclomatic Complexity 1 include/linux/skbuff.h:skb_queue_head_init
>    Cyclomatic Complexity 6 net//sctp/stream_interleave.c:sctp_ulpevent_idata
>    Cyclomatic Complexity 7 net//sctp/stream_interleave.c:sctp_renege_events
>    Cyclomatic Complexity 3 net//sctp/stream_interleave.c:sctp_make_idatafrag_empty
>    Cyclomatic Complexity 3 net//sctp/stream_interleave.c:sctp_stream_interleave_init
>    net//sctp/stream_interleave.c: In function 'sctp_renege_events':
>>> net//sctp/stream_interleave.c:581:26: warning: 'sin' may be used uninitialized in this function [-Wmaybe-uninitialized]
>            cevent->mid == sin->mid &&
>                              ^
>    net//sctp/stream_interleave.c:550:32: note: 'sin' was declared here
>      struct sctp_stream_in *csin, *sin;
>                                    ^
>
> vim +/sin +581 net//sctp/stream_interleave.c
>
>    547
>    548  static struct sctp_ulpevent *sctp_intl_retrieve_first(struct sctp_ulpq *ulpq)
>    549  {
>    550          struct sctp_stream_in *csin, *sin;
>    551          struct sk_buff *first_frag = NULL;
>    552          struct sk_buff *last_frag = NULL;
>    553          struct sctp_ulpevent *retval;
>    554          struct sk_buff *pos;
>    555          __u32 next_fsn = 0;
>    556          __u16 sid = 0;
>    557
>    558          skb_queue_walk(&ulpq->reasm, pos) {
>    559                  struct sctp_ulpevent *cevent = sctp_skb2event(pos);
>    560
>    561                  csin = sctp_stream_in(ulpq->asoc, cevent->stream);
>    562                  if (csin->pd_mode)
>    563                          continue;
>    564
>    565                  switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
>    566                  case SCTP_DATA_FIRST_FRAG:
>    567                          if (first_frag)
>    568                                  goto out;
>    569                          if (cevent->mid == csin->mid) {
>    570                                  first_frag = pos;
>    571                                  last_frag = pos;
>    572                                  next_fsn = 0;
>    573                                  sin = csin;
>    574                                  sid = cevent->stream;
>    575                          }
>    576                          break;
>    577                  case SCTP_DATA_MIDDLE_FRAG:
>    578                          if (!first_frag)
>    579                                  break;
>    580                          if (cevent->stream == sid &&
>  > 581                              cevent->mid == sin->mid &&
>    582                              cevent->fsn == next_fsn) {
>    583                                  next_fsn++;
>    584                                  last_frag = pos;
>    585                          } else {
>    586                                  goto out;
>    587                          }
>    588                          break;
>    589                  case SCTP_DATA_LAST_FRAG:
>    590                          if (first_frag)
>    591                                  goto out;
>    592                          break;
>    593                  default:
>    594                          break;
>    595                  }
>    596          }
>    597
>    598          if (!first_frag)
>    599                  return NULL;
>    600
>    601  out:
>    602          retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk),
>    603                                               &ulpq->reasm, first_frag,
>    604                                               last_frag);
>    605          if (retval) {
>    606                  sin->fsn = next_fsn;
>    607                  sin->pd_mode = 1;
This is safe,  it comes here only when sin already gets initialized.

>    608          }
>    609
>    610          return retval;
>    611  }
>    612
>
> ---
> 0-DAY kernel test infrastructure                Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply

* Re: [PATCH net-next v2 1/5] net: Introduce NETIF_F_GRO_HW.
From: Michael Chan @ 2017-12-08  4:02 UTC (permalink / raw)
  To: Alexander Duyck
  Cc: David Miller, Netdev, Andrew Gospodarek, Ariel Elior,
	everest-linux-l2
In-Reply-To: <CAKgT0UfsUfVm0YBOrZKnqdqKpRZnt5KSeDs_rJ7Z=7kwS0rh7w@mail.gmail.com>

On Thu, Dec 7, 2017 at 6:36 PM, Alexander Duyck
<alexander.duyck@gmail.com> wrote:
> On Thu, Dec 7, 2017 at 4:05 PM, Michael Chan <michael.chan@broadcom.com> wrote:
>> I see.  But this won't happen.  Because the bonding driver is not
>> advertising NETIF_F_GRO_HW in its hw_features.  It is not advertising
>> NETIF_F_GRO either but I think it gets added automatically since it is
>> a software feature.  So LRO won't get disabled on the bond when a
>> unrelated feature is changed.
>>
>> But I think I see your point.  I can make it so that it is up to
>> individual driver's .ndo_fix_features() to drop LRO/GRO_HW as it sees
>> fit, instead of doing it in the common netdev_fix_features().  That
>> way, it is more flexible at least.
>
> Thank you.

OK.  I will make this change for V3.

>>
>> I don't think that things are necessarily broken today.  LRO truly
>> needs to be propagated.  It's debatable whether other features like
>> GRO/RXCSUM/NTUPLE should be centrally set by the upper device or not.
>
> So I can agree with the NTUPLE not being propagated since it doesn't
> actually effect upper devices. Really the functionality only really
> has effects locally since the functionality consists of route to a
> specific queue/device or drop the packet.
>
> I'm not sure why RXCSUM isn't being propagated. It seems like that is
> something that would make sense to have passed all the way down to the
> lower devices since a single device that is doing bad Rx checksum
> offloads could potentially corrupt all traffic in a bond. Seems like
> that one should definitely be included.

This is a separate discussion that goes beyond GRO.  There are pros
and cons for the upper device to propagate every single feature flag.

>>
>> GRO kicks in at the lower device before it gets to the bond if the
>> lower device calls napi_gro_receive() and GRO is enabled.
>
> I get that. I assume the reason why the bond doesn't have it enabled
> is because we don't want it to kick in at every given netdev, there
> isn't any point to do GRO more than once. The problem is GRO_HW isn't
> a pure software offload like GRO is. Call me a pessimist, but when we
> end up encountering a buggy implementation that has to be disabled we
> will want the right infrastructure in place to handle it. It becomes
> another argument for why we might want to split GRO_HW and GRO without
> tying them together. It would make sense to expose GRO_HW in a bond,
> but not GRO. It might be something where we want to do any close tying
> together of the GRO flag and GRO_HW at the driver as well. Basically
> the legacy devices that transition over to GRO_HW from using just the
> GRO flag could do that to maintain existing functionality, and new
> drivers that implement it could opt in to the same behavior or just
> handle GRO_HW as a separate flag.

To me, making GRO_HW dependent on GRO makes the most intuitive sense.
Separating them is just confusing.  The possibility of GRO_HW being
enabled without GRO enabled makes no sense to me.

>
> Actually I just had a thought. What if we consider this a separate GRO
> stage instead of just a hardware offload? Our standard GRO is a post
> receive from the driver perspective, basically the packet is assembled
> after we have handed it to the stack. What you are doing with GRO_HW
> is essentially providing an early reassembly before it is handed to
> the stack. What if we were to rename GRO_HW to something like
> GRO_LOWER, GRO_EARLY, GRO_PRE, or pick your name (I'm lousy at
> naming), and used it as a way to indicate that we want to perform GRO
> before we begin receive processing on the frame in our driver? Then
> for stacked devices you could use this new flag to indicate you don't
> want to perform GRO on the lower levels below this device, and could
> then use the regular GRO flag to control if we do it ourselves. Doing
> that should provide stacked devices with a good way to control GRO on
> the lower devices and would resolve what you need to indicate as well.
> The only real changes needed might be a rename and to add the
> necessary bit shifting for the upper and lower dev sync code. If you
> aren't interested in the idea I can probably spend a couple of hours
> getting to it tomorrow since I think this might be a much better way
> to go as it solves multiple issues.

I really don't see what a different name will buy us.  If you want to
propagate GRO/GRO_HW, we can do that if others agree.  I only feel
strongly that GRO/GRO_HW should be tied.  I don't feel strongly
whether GRO/GRO_HW should be propagated or not propagated.  Again, LRO
needs to be propagated out of necessity (e.g. when a bond is added to
a bridge).

^ permalink raw reply

* [PATCH net-next V2] tuntap: fix possible deadlock when fail to register netdev
From: Jason Wang @ 2017-12-08  4:02 UTC (permalink / raw)
  To: netdev; +Cc: linux-kernel, mst, Jason Wang, Eric Dumazet, Willem de Bruijn

Private destructor could be called when register_netdev() fail with
rtnl lock held. This will lead deadlock in tun_free_netdev() who tries
to hold rtnl_lock. Fixing this by switching to use spinlock to
synchronize.

Fixes: 96f84061620c ("tun: add eBPF based queue selection method")
Reported-by: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Willem de Bruijn <willemb@google.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
 drivers/net/tun.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 787cc35..8d85163 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -2050,8 +2050,11 @@ static int __tun_set_steering_ebpf(struct tun_struct *tun,
 		new->prog = prog;
 	}
 
-	old = rtnl_dereference(tun->steering_prog);
+	spin_lock_bh(&tun->lock);
+	old = rcu_dereference_protected(tun->steering_prog,
+					lockdep_is_held(&tun->lock));
 	rcu_assign_pointer(tun->steering_prog, new);
+	spin_unlock_bh(&tun->lock);
 
 	if (old)
 		call_rcu(&old->rcu, tun_steering_prog_free);
@@ -2067,9 +2070,7 @@ static void tun_free_netdev(struct net_device *dev)
 	free_percpu(tun->pcpu_stats);
 	tun_flow_uninit(tun);
 	security_tun_dev_free_security(tun->security);
-	rtnl_lock();
 	__tun_set_steering_ebpf(tun, NULL);
-	rtnl_unlock();
 }
 
 static void tun_setup(struct net_device *dev)
-- 
2.7.4

^ permalink raw reply related

* [PATCH net-next v2 0/6] cxgb4: collect hardware logs via ethtool
From: Rahul Lakkireddy @ 2017-12-08  4:18 UTC (permalink / raw)
  To: netdev; +Cc: davem, ganeshgr, nirranjan, indranil, Rahul Lakkireddy

Collect more hardware logs via ethtool --get-dump facility.

Patch 1 collects on-chip memory layout information.

Patch 2 collects on-chip MC memory dumps.

Patch 3 collects HMA memory dump.

Patch 4 evaluates and skips TX and RX payload regions in memory dumps.

Patch 5 collects egress and ingress SGE queue contexts.

Patch 6 collects PCIe configuration logs

Thanks,
Rahul

---
v2:
- Fix uninitialized variable "size" build warning in Patch 1.

Rahul Lakkireddy (6):
  cxgb4: collect on-chip memory information
  cxgb4: collect MC memory dump
  cxgb4: collect HMA memory dump
  cxgb4: skip TX and RX payload regions in memory dumps
  cxgb4: collect egress and ingress SGE queue contexts
  cxgb4: collect PCIe configuration logs

 drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h  |  76 +-
 drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h      |   5 +
 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c     | 822 +++++++++++++++++++--
 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h     |  18 +-
 drivers/net/ethernet/chelsio/cxgb4/cxgb4.h         |   5 +-
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c   |  39 +-
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h   |   1 +
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 278 +------
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c    |   2 +-
 drivers/net/ethernet/chelsio/cxgb4/t4_hw.c         |  14 +-
 drivers/net/ethernet/chelsio/cxgb4/t4_hw.h         |   4 +-
 drivers/net/ethernet/chelsio/cxgb4/t4_regs.h       |   4 +
 12 files changed, 944 insertions(+), 324 deletions(-)

-- 
2.14.1

^ permalink raw reply

* [PATCH net-next v2 1/6] cxgb4: collect on-chip memory information
From: Rahul Lakkireddy @ 2017-12-08  4:18 UTC (permalink / raw)
  To: netdev; +Cc: davem, ganeshgr, nirranjan, indranil, Rahul Lakkireddy
In-Reply-To: <cover.1512705841.git.rahul.lakkireddy@chelsio.com>

Collect memory layout of various on-chip memory regions.  Move code
for collecting on-chip memory information to cudbg_lib.c and update
cxgb4_debugfs.c to use the common function.  Also include
cudbg_entity.h before cudbg_lib.h to avoid adding cudbg entity
structure forward declarations in cudbg_lib.h.

Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
---
v2:
- Fix uninitialized variable "size" build warning in Patch 1.

 drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h  |  35 +++
 drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h      |   1 +
 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c     | 289 ++++++++++++++++++++-
 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h     |   6 +-
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c   |   5 +-
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h   |   1 +
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 278 +++-----------------
 7 files changed, 374 insertions(+), 241 deletions(-)

diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
index 605689957496..348d7e1eb78a 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
@@ -87,6 +87,41 @@ struct cudbg_tp_la {
 	u8 data[0];
 };
 
+static const char * const cudbg_region[] = {
+	"DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:",
+	"Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:",
+	"Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:",
+	"TDDP region:", "TPT region:", "STAG region:", "RQ region:",
+	"RQUDP region:", "PBL region:", "TXPBL region:",
+	"DBVFIFO region:", "ULPRX state:", "ULPTX state:",
+	"On-chip queues:"
+};
+
+struct cudbg_mem_desc {
+	u32 base;
+	u32 limit;
+	u32 idx;
+};
+
+struct cudbg_meminfo {
+	struct cudbg_mem_desc avail[4];
+	struct cudbg_mem_desc mem[ARRAY_SIZE(cudbg_region) + 3];
+	u32 avail_c;
+	u32 mem_c;
+	u32 up_ram_lo;
+	u32 up_ram_hi;
+	u32 up_extmem2_lo;
+	u32 up_extmem2_hi;
+	u32 rx_pages_data[3];
+	u32 tx_pages_data[4];
+	u32 p_structs;
+	u32 reserved[12];
+	u32 port_used[4];
+	u32 port_alloc[4];
+	u32 loopback_used[NCHAN];
+	u32 loopback_alloc[NCHAN];
+};
+
 struct cudbg_cim_pif_la {
 	int size;
 	u8 data[0];
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
index e10ff1ee62c5..5a5cea2fda69 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
@@ -56,6 +56,7 @@ enum cudbg_dbg_entity_type {
 	CUDBG_SGE_INDIRECT = 37,
 	CUDBG_ULPRX_LA = 41,
 	CUDBG_TP_LA = 43,
+	CUDBG_MEMINFO = 44,
 	CUDBG_CIM_PIF_LA = 45,
 	CUDBG_CLK = 46,
 	CUDBG_CIM_OBQ_RXQ0 = 47,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
index d699bf88d18f..21dfd70ad08a 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
@@ -15,12 +15,14 @@
  *
  */
 
+#include <linux/sort.h>
+
 #include "t4_regs.h"
 #include "cxgb4.h"
 #include "cudbg_if.h"
 #include "cudbg_lib_common.h"
-#include "cudbg_lib.h"
 #include "cudbg_entity.h"
+#include "cudbg_lib.h"
 
 static void cudbg_write_and_release_buff(struct cudbg_buffer *pin_buff,
 					 struct cudbg_buffer *dbg_buff)
@@ -84,6 +86,266 @@ static int cudbg_read_vpd_reg(struct adapter *padap, u32 addr, u32 len,
 	return 0;
 }
 
+static int cudbg_mem_desc_cmp(const void *a, const void *b)
+{
+	return ((const struct cudbg_mem_desc *)a)->base -
+	       ((const struct cudbg_mem_desc *)b)->base;
+}
+
+int cudbg_fill_meminfo(struct adapter *padap,
+		       struct cudbg_meminfo *meminfo_buff)
+{
+	struct cudbg_mem_desc *md;
+	u32 lo, hi, used, alloc;
+	int n, i;
+
+	memset(meminfo_buff->avail, 0,
+	       ARRAY_SIZE(meminfo_buff->avail) *
+	       sizeof(struct cudbg_mem_desc));
+	memset(meminfo_buff->mem, 0,
+	       (ARRAY_SIZE(cudbg_region) + 3) * sizeof(struct cudbg_mem_desc));
+	md  = meminfo_buff->mem;
+
+	for (i = 0; i < ARRAY_SIZE(meminfo_buff->mem); i++) {
+		meminfo_buff->mem[i].limit = 0;
+		meminfo_buff->mem[i].idx = i;
+	}
+
+	/* Find and sort the populated memory ranges */
+	i = 0;
+	lo = t4_read_reg(padap, MA_TARGET_MEM_ENABLE_A);
+	if (lo & EDRAM0_ENABLE_F) {
+		hi = t4_read_reg(padap, MA_EDRAM0_BAR_A);
+		meminfo_buff->avail[i].base =
+			cudbg_mbytes_to_bytes(EDRAM0_BASE_G(hi));
+		meminfo_buff->avail[i].limit =
+			meminfo_buff->avail[i].base +
+			cudbg_mbytes_to_bytes(EDRAM0_SIZE_G(hi));
+		meminfo_buff->avail[i].idx = 0;
+		i++;
+	}
+
+	if (lo & EDRAM1_ENABLE_F) {
+		hi =  t4_read_reg(padap, MA_EDRAM1_BAR_A);
+		meminfo_buff->avail[i].base =
+			cudbg_mbytes_to_bytes(EDRAM1_BASE_G(hi));
+		meminfo_buff->avail[i].limit =
+			meminfo_buff->avail[i].base +
+			cudbg_mbytes_to_bytes(EDRAM1_SIZE_G(hi));
+		meminfo_buff->avail[i].idx = 1;
+		i++;
+	}
+
+	if (is_t5(padap->params.chip)) {
+		if (lo & EXT_MEM0_ENABLE_F) {
+			hi = t4_read_reg(padap, MA_EXT_MEMORY0_BAR_A);
+			meminfo_buff->avail[i].base =
+				cudbg_mbytes_to_bytes(EXT_MEM_BASE_G(hi));
+			meminfo_buff->avail[i].limit =
+				meminfo_buff->avail[i].base +
+				cudbg_mbytes_to_bytes(EXT_MEM_SIZE_G(hi));
+			meminfo_buff->avail[i].idx = 3;
+			i++;
+		}
+
+		if (lo & EXT_MEM1_ENABLE_F) {
+			hi = t4_read_reg(padap, MA_EXT_MEMORY1_BAR_A);
+			meminfo_buff->avail[i].base =
+				cudbg_mbytes_to_bytes(EXT_MEM1_BASE_G(hi));
+			meminfo_buff->avail[i].limit =
+				meminfo_buff->avail[i].base +
+				cudbg_mbytes_to_bytes(EXT_MEM1_SIZE_G(hi));
+			meminfo_buff->avail[i].idx = 4;
+			i++;
+		}
+	} else {
+		if (lo & EXT_MEM_ENABLE_F) {
+			hi = t4_read_reg(padap, MA_EXT_MEMORY_BAR_A);
+			meminfo_buff->avail[i].base =
+				cudbg_mbytes_to_bytes(EXT_MEM_BASE_G(hi));
+			meminfo_buff->avail[i].limit =
+				meminfo_buff->avail[i].base +
+				cudbg_mbytes_to_bytes(EXT_MEM_SIZE_G(hi));
+			meminfo_buff->avail[i].idx = 2;
+			i++;
+		}
+	}
+
+	if (!i) /* no memory available */
+		return CUDBG_STATUS_ENTITY_NOT_FOUND;
+
+	meminfo_buff->avail_c = i;
+	sort(meminfo_buff->avail, i, sizeof(struct cudbg_mem_desc),
+	     cudbg_mem_desc_cmp, NULL);
+	(md++)->base = t4_read_reg(padap, SGE_DBQ_CTXT_BADDR_A);
+	(md++)->base = t4_read_reg(padap, SGE_IMSG_CTXT_BADDR_A);
+	(md++)->base = t4_read_reg(padap, SGE_FLM_CACHE_BADDR_A);
+	(md++)->base = t4_read_reg(padap, TP_CMM_TCB_BASE_A);
+	(md++)->base = t4_read_reg(padap, TP_CMM_MM_BASE_A);
+	(md++)->base = t4_read_reg(padap, TP_CMM_TIMER_BASE_A);
+	(md++)->base = t4_read_reg(padap, TP_CMM_MM_RX_FLST_BASE_A);
+	(md++)->base = t4_read_reg(padap, TP_CMM_MM_TX_FLST_BASE_A);
+	(md++)->base = t4_read_reg(padap, TP_CMM_MM_PS_FLST_BASE_A);
+
+	/* the next few have explicit upper bounds */
+	md->base = t4_read_reg(padap, TP_PMM_TX_BASE_A);
+	md->limit = md->base - 1 +
+		    t4_read_reg(padap, TP_PMM_TX_PAGE_SIZE_A) *
+		    PMTXMAXPAGE_G(t4_read_reg(padap, TP_PMM_TX_MAX_PAGE_A));
+	md++;
+
+	md->base = t4_read_reg(padap, TP_PMM_RX_BASE_A);
+	md->limit = md->base - 1 +
+		    t4_read_reg(padap, TP_PMM_RX_PAGE_SIZE_A) *
+		    PMRXMAXPAGE_G(t4_read_reg(padap, TP_PMM_RX_MAX_PAGE_A));
+	md++;
+
+	if (t4_read_reg(padap, LE_DB_CONFIG_A) & HASHEN_F) {
+		if (CHELSIO_CHIP_VERSION(padap->params.chip) <= CHELSIO_T5) {
+			hi = t4_read_reg(padap, LE_DB_TID_HASHBASE_A) / 4;
+			md->base = t4_read_reg(padap, LE_DB_HASH_TID_BASE_A);
+		} else {
+			hi = t4_read_reg(padap, LE_DB_HASH_TID_BASE_A);
+			md->base = t4_read_reg(padap,
+					       LE_DB_HASH_TBL_BASE_ADDR_A);
+		}
+		md->limit = 0;
+	} else {
+		md->base = 0;
+		md->idx = ARRAY_SIZE(cudbg_region);  /* hide it */
+	}
+	md++;
+
+#define ulp_region(reg) do { \
+	md->base = t4_read_reg(padap, ULP_ ## reg ## _LLIMIT_A);\
+	(md++)->limit = t4_read_reg(padap, ULP_ ## reg ## _ULIMIT_A);\
+} while (0)
+
+	ulp_region(RX_ISCSI);
+	ulp_region(RX_TDDP);
+	ulp_region(TX_TPT);
+	ulp_region(RX_STAG);
+	ulp_region(RX_RQ);
+	ulp_region(RX_RQUDP);
+	ulp_region(RX_PBL);
+	ulp_region(TX_PBL);
+#undef ulp_region
+	md->base = 0;
+	md->idx = ARRAY_SIZE(cudbg_region);
+	if (!is_t4(padap->params.chip)) {
+		u32 fifo_size = t4_read_reg(padap, SGE_DBVFIFO_SIZE_A);
+		u32 sge_ctrl = t4_read_reg(padap, SGE_CONTROL2_A);
+		u32 size = 0;
+
+		if (is_t5(padap->params.chip)) {
+			if (sge_ctrl & VFIFO_ENABLE_F)
+				size = DBVFIFO_SIZE_G(fifo_size);
+		} else {
+			size = T6_DBVFIFO_SIZE_G(fifo_size);
+		}
+
+		if (size) {
+			md->base = BASEADDR_G(t4_read_reg(padap,
+							  SGE_DBVFIFO_BADDR_A));
+			md->limit = md->base + (size << 2) - 1;
+		}
+	}
+
+	md++;
+
+	md->base = t4_read_reg(padap, ULP_RX_CTX_BASE_A);
+	md->limit = 0;
+	md++;
+	md->base = t4_read_reg(padap, ULP_TX_ERR_TABLE_BASE_A);
+	md->limit = 0;
+	md++;
+
+	md->base = padap->vres.ocq.start;
+	if (padap->vres.ocq.size)
+		md->limit = md->base + padap->vres.ocq.size - 1;
+	else
+		md->idx = ARRAY_SIZE(cudbg_region);  /* hide it */
+	md++;
+
+	/* add any address-space holes, there can be up to 3 */
+	for (n = 0; n < i - 1; n++)
+		if (meminfo_buff->avail[n].limit <
+		    meminfo_buff->avail[n + 1].base)
+			(md++)->base = meminfo_buff->avail[n].limit;
+
+	if (meminfo_buff->avail[n].limit)
+		(md++)->base = meminfo_buff->avail[n].limit;
+
+	n = md - meminfo_buff->mem;
+	meminfo_buff->mem_c = n;
+
+	sort(meminfo_buff->mem, n, sizeof(struct cudbg_mem_desc),
+	     cudbg_mem_desc_cmp, NULL);
+
+	lo = t4_read_reg(padap, CIM_SDRAM_BASE_ADDR_A);
+	hi = t4_read_reg(padap, CIM_SDRAM_ADDR_SIZE_A) + lo - 1;
+	meminfo_buff->up_ram_lo = lo;
+	meminfo_buff->up_ram_hi = hi;
+
+	lo = t4_read_reg(padap, CIM_EXTMEM2_BASE_ADDR_A);
+	hi = t4_read_reg(padap, CIM_EXTMEM2_ADDR_SIZE_A) + lo - 1;
+	meminfo_buff->up_extmem2_lo = lo;
+	meminfo_buff->up_extmem2_hi = hi;
+
+	lo = t4_read_reg(padap, TP_PMM_RX_MAX_PAGE_A);
+	meminfo_buff->rx_pages_data[0] =  PMRXMAXPAGE_G(lo);
+	meminfo_buff->rx_pages_data[1] =
+		t4_read_reg(padap, TP_PMM_RX_PAGE_SIZE_A) >> 10;
+	meminfo_buff->rx_pages_data[2] = (lo & PMRXNUMCHN_F) ? 2 : 1;
+
+	lo = t4_read_reg(padap, TP_PMM_TX_MAX_PAGE_A);
+	hi = t4_read_reg(padap, TP_PMM_TX_PAGE_SIZE_A);
+	meminfo_buff->tx_pages_data[0] = PMTXMAXPAGE_G(lo);
+	meminfo_buff->tx_pages_data[1] =
+		hi >= (1 << 20) ? (hi >> 20) : (hi >> 10);
+	meminfo_buff->tx_pages_data[2] =
+		hi >= (1 << 20) ? 'M' : 'K';
+	meminfo_buff->tx_pages_data[3] = 1 << PMTXNUMCHN_G(lo);
+
+	meminfo_buff->p_structs = t4_read_reg(padap, TP_CMM_MM_MAX_PSTRUCT_A);
+
+	for (i = 0; i < 4; i++) {
+		if (CHELSIO_CHIP_VERSION(padap->params.chip) > CHELSIO_T5)
+			lo = t4_read_reg(padap,
+					 MPS_RX_MAC_BG_PG_CNT0_A + i * 4);
+		else
+			lo = t4_read_reg(padap, MPS_RX_PG_RSV0_A + i * 4);
+		if (is_t5(padap->params.chip)) {
+			used = T5_USED_G(lo);
+			alloc = T5_ALLOC_G(lo);
+		} else {
+			used = USED_G(lo);
+			alloc = ALLOC_G(lo);
+		}
+		meminfo_buff->port_used[i] = used;
+		meminfo_buff->port_alloc[i] = alloc;
+	}
+
+	for (i = 0; i < padap->params.arch.nchan; i++) {
+		if (CHELSIO_CHIP_VERSION(padap->params.chip) > CHELSIO_T5)
+			lo = t4_read_reg(padap,
+					 MPS_RX_LPBK_BG_PG_CNT0_A + i * 4);
+		else
+			lo = t4_read_reg(padap, MPS_RX_PG_RSV4_A + i * 4);
+		if (is_t5(padap->params.chip)) {
+			used = T5_USED_G(lo);
+			alloc = T5_ALLOC_G(lo);
+		} else {
+			used = USED_G(lo);
+			alloc = ALLOC_G(lo);
+		}
+		meminfo_buff->loopback_used[i] = used;
+		meminfo_buff->loopback_alloc[i] = alloc;
+	}
+
+	return 0;
+}
+
 int cudbg_collect_reg_dump(struct cudbg_init *pdbg_init,
 			   struct cudbg_buffer *dbg_buff,
 			   struct cudbg_error *cudbg_err)
@@ -843,6 +1105,31 @@ int cudbg_collect_tp_la(struct cudbg_init *pdbg_init,
 	return rc;
 }
 
+int cudbg_collect_meminfo(struct cudbg_init *pdbg_init,
+			  struct cudbg_buffer *dbg_buff,
+			  struct cudbg_error *cudbg_err)
+{
+	struct adapter *padap = pdbg_init->adap;
+	struct cudbg_buffer temp_buff = { 0 };
+	struct cudbg_meminfo *meminfo_buff;
+	int rc;
+
+	rc = cudbg_get_buff(dbg_buff, sizeof(struct cudbg_meminfo), &temp_buff);
+	if (rc)
+		return rc;
+
+	meminfo_buff = (struct cudbg_meminfo *)temp_buff.data;
+	rc = cudbg_fill_meminfo(padap, meminfo_buff);
+	if (rc) {
+		cudbg_err->sys_err = rc;
+		cudbg_put_buff(&temp_buff, dbg_buff);
+		return rc;
+	}
+
+	cudbg_write_and_release_buff(&temp_buff, dbg_buff);
+	return rc;
+}
+
 int cudbg_collect_cim_pif_la(struct cudbg_init *pdbg_init,
 			     struct cudbg_buffer *dbg_buff,
 			     struct cudbg_error *cudbg_err)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
index caeee8e33e86..eb4460c8583e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
@@ -102,6 +102,9 @@ int cudbg_collect_ulprx_la(struct cudbg_init *pdbg_init,
 int cudbg_collect_tp_la(struct cudbg_init *pdbg_init,
 			struct cudbg_buffer *dbg_buff,
 			struct cudbg_error *cudbg_err);
+int cudbg_collect_meminfo(struct cudbg_init *pdbg_init,
+			  struct cudbg_buffer *dbg_buff,
+			  struct cudbg_error *cudbg_err);
 int cudbg_collect_cim_pif_la(struct cudbg_init *pdbg_init,
 			     struct cudbg_buffer *dbg_buff,
 			     struct cudbg_error *cudbg_err);
@@ -163,7 +166,8 @@ void cudbg_align_debug_buffer(struct cudbg_buffer *dbg_buff,
 u32 cudbg_cim_obq_size(struct adapter *padap, int qid);
 int cudbg_dump_context_size(struct adapter *padap);
 
-struct cudbg_tcam;
+int cudbg_fill_meminfo(struct adapter *padap,
+		       struct cudbg_meminfo *meminfo_buff);
 void cudbg_fill_le_tcam_info(struct adapter *padap,
 			     struct cudbg_tcam *tcam_region);
 #endif /* __CUDBG_LIB_H__ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
index 29cc625e9833..faa84a5f0878 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
@@ -18,7 +18,6 @@
 #include "t4_regs.h"
 #include "cxgb4.h"
 #include "cxgb4_cudbg.h"
-#include "cudbg_entity.h"
 
 static const struct cxgb4_collect_entity cxgb4_collect_mem_dump[] = {
 	{ CUDBG_EDC0, cudbg_collect_edc0_meminfo },
@@ -53,6 +52,7 @@ static const struct cxgb4_collect_entity cxgb4_collect_hw_dump[] = {
 	{ CUDBG_SGE_INDIRECT, cudbg_collect_sge_indirect },
 	{ CUDBG_ULPRX_LA, cudbg_collect_ulprx_la },
 	{ CUDBG_TP_LA, cudbg_collect_tp_la },
+	{ CUDBG_MEMINFO, cudbg_collect_meminfo },
 	{ CUDBG_CIM_PIF_LA, cudbg_collect_cim_pif_la },
 	{ CUDBG_CLK, cudbg_collect_clk_info },
 	{ CUDBG_CIM_OBQ_RXQ0, cudbg_collect_obq_sge_rx_q0 },
@@ -201,6 +201,9 @@ static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
 	case CUDBG_TP_LA:
 		len = sizeof(struct cudbg_tp_la) + TPLA_SIZE * sizeof(u64);
 		break;
+	case CUDBG_MEMINFO:
+		len = sizeof(struct cudbg_meminfo);
+		break;
 	case CUDBG_CIM_PIF_LA:
 		len = sizeof(struct cudbg_cim_pif_la);
 		len += 2 * CIM_PIFLA_SIZE * 6 * sizeof(u32);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
index c099b5aa2214..7ceeb0bc9fa8 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
@@ -20,6 +20,7 @@
 
 #include "cudbg_if.h"
 #include "cudbg_lib_common.h"
+#include "cudbg_entity.h"
 #include "cudbg_lib.h"
 
 typedef int (*cudbg_collect_callback_t)(struct cudbg_init *pdbg_init,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
index 917663b35603..c6732683cb8c 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
@@ -45,6 +45,10 @@
 #include "cxgb4_debugfs.h"
 #include "clip_tbl.h"
 #include "l2t.h"
+#include "cudbg_if.h"
+#include "cudbg_lib_common.h"
+#include "cudbg_entity.h"
+#include "cudbg_lib.h"
 
 /* generic seq_file support for showing a table of size rows x width. */
 static void *seq_tab_get_idx(struct seq_tab *tb, loff_t pos)
@@ -2794,18 +2798,6 @@ static const struct file_operations blocked_fl_fops = {
 	.llseek  = generic_file_llseek,
 };
 
-struct mem_desc {
-	unsigned int base;
-	unsigned int limit;
-	unsigned int idx;
-};
-
-static int mem_desc_cmp(const void *a, const void *b)
-{
-	return ((const struct mem_desc *)a)->base -
-	       ((const struct mem_desc *)b)->base;
-}
-
 static void mem_region_show(struct seq_file *seq, const char *name,
 			    unsigned int from, unsigned int to)
 {
@@ -2819,250 +2811,60 @@ static void mem_region_show(struct seq_file *seq, const char *name,
 static int meminfo_show(struct seq_file *seq, void *v)
 {
 	static const char * const memory[] = { "EDC0:", "EDC1:", "MC:",
-					"MC0:", "MC1:"};
-	static const char * const region[] = {
-		"DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:",
-		"Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:",
-		"Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:",
-		"TDDP region:", "TPT region:", "STAG region:", "RQ region:",
-		"RQUDP region:", "PBL region:", "TXPBL region:",
-		"DBVFIFO region:", "ULPRX state:", "ULPTX state:",
-		"On-chip queues:"
-	};
-
-	int i, n;
-	u32 lo, hi, used, alloc;
-	struct mem_desc avail[4];
-	struct mem_desc mem[ARRAY_SIZE(region) + 3];      /* up to 3 holes */
-	struct mem_desc *md = mem;
+					       "MC0:", "MC1:"};
 	struct adapter *adap = seq->private;
+	struct cudbg_meminfo meminfo;
+	int i, rc;
 
-	for (i = 0; i < ARRAY_SIZE(mem); i++) {
-		mem[i].limit = 0;
-		mem[i].idx = i;
-	}
-
-	/* Find and sort the populated memory ranges */
-	i = 0;
-	lo = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A);
-	if (lo & EDRAM0_ENABLE_F) {
-		hi = t4_read_reg(adap, MA_EDRAM0_BAR_A);
-		avail[i].base = EDRAM0_BASE_G(hi) << 20;
-		avail[i].limit = avail[i].base + (EDRAM0_SIZE_G(hi) << 20);
-		avail[i].idx = 0;
-		i++;
-	}
-	if (lo & EDRAM1_ENABLE_F) {
-		hi = t4_read_reg(adap, MA_EDRAM1_BAR_A);
-		avail[i].base = EDRAM1_BASE_G(hi) << 20;
-		avail[i].limit = avail[i].base + (EDRAM1_SIZE_G(hi) << 20);
-		avail[i].idx = 1;
-		i++;
-	}
-
-	if (is_t5(adap->params.chip)) {
-		if (lo & EXT_MEM0_ENABLE_F) {
-			hi = t4_read_reg(adap, MA_EXT_MEMORY0_BAR_A);
-			avail[i].base = EXT_MEM0_BASE_G(hi) << 20;
-			avail[i].limit =
-				avail[i].base + (EXT_MEM0_SIZE_G(hi) << 20);
-			avail[i].idx = 3;
-			i++;
-		}
-		if (lo & EXT_MEM1_ENABLE_F) {
-			hi = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A);
-			avail[i].base = EXT_MEM1_BASE_G(hi) << 20;
-			avail[i].limit =
-				avail[i].base + (EXT_MEM1_SIZE_G(hi) << 20);
-			avail[i].idx = 4;
-			i++;
-		}
-	} else {
-		if (lo & EXT_MEM_ENABLE_F) {
-			hi = t4_read_reg(adap, MA_EXT_MEMORY_BAR_A);
-			avail[i].base = EXT_MEM_BASE_G(hi) << 20;
-			avail[i].limit =
-				avail[i].base + (EXT_MEM_SIZE_G(hi) << 20);
-			avail[i].idx = 2;
-			i++;
-		}
-	}
-	if (!i)                                    /* no memory available */
-		return 0;
-	sort(avail, i, sizeof(struct mem_desc), mem_desc_cmp, NULL);
-
-	(md++)->base = t4_read_reg(adap, SGE_DBQ_CTXT_BADDR_A);
-	(md++)->base = t4_read_reg(adap, SGE_IMSG_CTXT_BADDR_A);
-	(md++)->base = t4_read_reg(adap, SGE_FLM_CACHE_BADDR_A);
-	(md++)->base = t4_read_reg(adap, TP_CMM_TCB_BASE_A);
-	(md++)->base = t4_read_reg(adap, TP_CMM_MM_BASE_A);
-	(md++)->base = t4_read_reg(adap, TP_CMM_TIMER_BASE_A);
-	(md++)->base = t4_read_reg(adap, TP_CMM_MM_RX_FLST_BASE_A);
-	(md++)->base = t4_read_reg(adap, TP_CMM_MM_TX_FLST_BASE_A);
-	(md++)->base = t4_read_reg(adap, TP_CMM_MM_PS_FLST_BASE_A);
-
-	/* the next few have explicit upper bounds */
-	md->base = t4_read_reg(adap, TP_PMM_TX_BASE_A);
-	md->limit = md->base - 1 +
-		    t4_read_reg(adap, TP_PMM_TX_PAGE_SIZE_A) *
-		    PMTXMAXPAGE_G(t4_read_reg(adap, TP_PMM_TX_MAX_PAGE_A));
-	md++;
-
-	md->base = t4_read_reg(adap, TP_PMM_RX_BASE_A);
-	md->limit = md->base - 1 +
-		    t4_read_reg(adap, TP_PMM_RX_PAGE_SIZE_A) *
-		    PMRXMAXPAGE_G(t4_read_reg(adap, TP_PMM_RX_MAX_PAGE_A));
-	md++;
-
-	if (t4_read_reg(adap, LE_DB_CONFIG_A) & HASHEN_F) {
-		if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5) {
-			hi = t4_read_reg(adap, LE_DB_TID_HASHBASE_A) / 4;
-			md->base = t4_read_reg(adap, LE_DB_HASH_TID_BASE_A);
-		 } else {
-			hi = t4_read_reg(adap, LE_DB_HASH_TID_BASE_A);
-			md->base = t4_read_reg(adap,
-					       LE_DB_HASH_TBL_BASE_ADDR_A);
-		}
-		md->limit = 0;
-	} else {
-		md->base = 0;
-		md->idx = ARRAY_SIZE(region);  /* hide it */
-	}
-	md++;
-
-#define ulp_region(reg) do { \
-	md->base = t4_read_reg(adap, ULP_ ## reg ## _LLIMIT_A);\
-	(md++)->limit = t4_read_reg(adap, ULP_ ## reg ## _ULIMIT_A); \
-} while (0)
-
-	ulp_region(RX_ISCSI);
-	ulp_region(RX_TDDP);
-	ulp_region(TX_TPT);
-	ulp_region(RX_STAG);
-	ulp_region(RX_RQ);
-	ulp_region(RX_RQUDP);
-	ulp_region(RX_PBL);
-	ulp_region(TX_PBL);
-#undef ulp_region
-	md->base = 0;
-	md->idx = ARRAY_SIZE(region);
-	if (!is_t4(adap->params.chip)) {
-		u32 size = 0;
-		u32 sge_ctrl = t4_read_reg(adap, SGE_CONTROL2_A);
-		u32 fifo_size = t4_read_reg(adap, SGE_DBVFIFO_SIZE_A);
-
-		if (is_t5(adap->params.chip)) {
-			if (sge_ctrl & VFIFO_ENABLE_F)
-				size = DBVFIFO_SIZE_G(fifo_size);
-		} else {
-			size = T6_DBVFIFO_SIZE_G(fifo_size);
-		}
-
-		if (size) {
-			md->base = BASEADDR_G(t4_read_reg(adap,
-					SGE_DBVFIFO_BADDR_A));
-			md->limit = md->base + (size << 2) - 1;
-		}
-	}
-
-	md++;
-
-	md->base = t4_read_reg(adap, ULP_RX_CTX_BASE_A);
-	md->limit = 0;
-	md++;
-	md->base = t4_read_reg(adap, ULP_TX_ERR_TABLE_BASE_A);
-	md->limit = 0;
-	md++;
-
-	md->base = adap->vres.ocq.start;
-	if (adap->vres.ocq.size)
-		md->limit = md->base + adap->vres.ocq.size - 1;
-	else
-		md->idx = ARRAY_SIZE(region);  /* hide it */
-	md++;
-
-	/* add any address-space holes, there can be up to 3 */
-	for (n = 0; n < i - 1; n++)
-		if (avail[n].limit < avail[n + 1].base)
-			(md++)->base = avail[n].limit;
-	if (avail[n].limit)
-		(md++)->base = avail[n].limit;
-
-	n = md - mem;
-	sort(mem, n, sizeof(struct mem_desc), mem_desc_cmp, NULL);
+	memset(&meminfo, 0, sizeof(struct cudbg_meminfo));
+	rc = cudbg_fill_meminfo(adap, &meminfo);
+	if (rc)
+		return -ENXIO;
 
-	for (lo = 0; lo < i; lo++)
-		mem_region_show(seq, memory[avail[lo].idx], avail[lo].base,
-				avail[lo].limit - 1);
+	for (i = 0; i < meminfo.avail_c; i++)
+		mem_region_show(seq, memory[meminfo.avail[i].idx],
+				meminfo.avail[i].base,
+				meminfo.avail[i].limit - 1);
 
 	seq_putc(seq, '\n');
-	for (i = 0; i < n; i++) {
-		if (mem[i].idx >= ARRAY_SIZE(region))
+	for (i = 0; i < meminfo.mem_c; i++) {
+		if (meminfo.mem[i].idx >= ARRAY_SIZE(cudbg_region))
 			continue;                        /* skip holes */
-		if (!mem[i].limit)
-			mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0;
-		mem_region_show(seq, region[mem[i].idx], mem[i].base,
-				mem[i].limit);
+		if (!meminfo.mem[i].limit)
+			meminfo.mem[i].limit =
+				i < meminfo.mem_c - 1 ?
+				meminfo.mem[i + 1].base - 1 : ~0;
+		mem_region_show(seq, cudbg_region[meminfo.mem[i].idx],
+				meminfo.mem[i].base, meminfo.mem[i].limit);
 	}
 
 	seq_putc(seq, '\n');
-	lo = t4_read_reg(adap, CIM_SDRAM_BASE_ADDR_A);
-	hi = t4_read_reg(adap, CIM_SDRAM_ADDR_SIZE_A) + lo - 1;
-	mem_region_show(seq, "uP RAM:", lo, hi);
+	mem_region_show(seq, "uP RAM:", meminfo.up_ram_lo, meminfo.up_ram_hi);
+	mem_region_show(seq, "uP Extmem2:", meminfo.up_extmem2_lo,
+			meminfo.up_extmem2_hi);
 
-	lo = t4_read_reg(adap, CIM_EXTMEM2_BASE_ADDR_A);
-	hi = t4_read_reg(adap, CIM_EXTMEM2_ADDR_SIZE_A) + lo - 1;
-	mem_region_show(seq, "uP Extmem2:", lo, hi);
-
-	lo = t4_read_reg(adap, TP_PMM_RX_MAX_PAGE_A);
 	seq_printf(seq, "\n%u Rx pages of size %uKiB for %u channels\n",
-		   PMRXMAXPAGE_G(lo),
-		   t4_read_reg(adap, TP_PMM_RX_PAGE_SIZE_A) >> 10,
-		   (lo & PMRXNUMCHN_F) ? 2 : 1);
+		   meminfo.rx_pages_data[0], meminfo.rx_pages_data[1],
+		   meminfo.rx_pages_data[2]);
 
-	lo = t4_read_reg(adap, TP_PMM_TX_MAX_PAGE_A);
-	hi = t4_read_reg(adap, TP_PMM_TX_PAGE_SIZE_A);
 	seq_printf(seq, "%u Tx pages of size %u%ciB for %u channels\n",
-		   PMTXMAXPAGE_G(lo),
-		   hi >= (1 << 20) ? (hi >> 20) : (hi >> 10),
-		   hi >= (1 << 20) ? 'M' : 'K', 1 << PMTXNUMCHN_G(lo));
-	seq_printf(seq, "%u p-structs\n\n",
-		   t4_read_reg(adap, TP_CMM_MM_MAX_PSTRUCT_A));
-
-	for (i = 0; i < 4; i++) {
-		if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5)
-			lo = t4_read_reg(adap, MPS_RX_MAC_BG_PG_CNT0_A + i * 4);
-		else
-			lo = t4_read_reg(adap, MPS_RX_PG_RSV0_A + i * 4);
-		if (is_t5(adap->params.chip)) {
-			used = T5_USED_G(lo);
-			alloc = T5_ALLOC_G(lo);
-		} else {
-			used = USED_G(lo);
-			alloc = ALLOC_G(lo);
-		}
+		   meminfo.tx_pages_data[0], meminfo.tx_pages_data[1],
+		   meminfo.tx_pages_data[2], meminfo.tx_pages_data[3]);
+
+	seq_printf(seq, "%u p-structs\n\n", meminfo.p_structs);
+
+	for (i = 0; i < 4; i++)
 		/* For T6 these are MAC buffer groups */
 		seq_printf(seq, "Port %d using %u pages out of %u allocated\n",
-			   i, used, alloc);
-	}
-	for (i = 0; i < adap->params.arch.nchan; i++) {
-		if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5)
-			lo = t4_read_reg(adap,
-					 MPS_RX_LPBK_BG_PG_CNT0_A + i * 4);
-		else
-			lo = t4_read_reg(adap, MPS_RX_PG_RSV4_A + i * 4);
-		if (is_t5(adap->params.chip)) {
-			used = T5_USED_G(lo);
-			alloc = T5_ALLOC_G(lo);
-		} else {
-			used = USED_G(lo);
-			alloc = ALLOC_G(lo);
-		}
+			   i, meminfo.port_used[i], meminfo.port_alloc[i]);
+
+	for (i = 0; i < adap->params.arch.nchan; i++)
 		/* For T6 these are MAC buffer groups */
 		seq_printf(seq,
 			   "Loopback %d using %u pages out of %u allocated\n",
-			   i, used, alloc);
-	}
+			   i, meminfo.loopback_used[i],
+			   meminfo.loopback_alloc[i]);
+
 	return 0;
 }
 
-- 
2.14.1

^ permalink raw reply related

* [PATCH net-next v2 2/6] cxgb4: collect MC memory dump
From: Rahul Lakkireddy @ 2017-12-08  4:18 UTC (permalink / raw)
  To: netdev; +Cc: davem, ganeshgr, nirranjan, indranil, Rahul Lakkireddy
In-Reply-To: <cover.1512705841.git.rahul.lakkireddy@chelsio.com>

Use meminfo to get base address and size of MC memory.  Also use same
meminfo for EDC memory dumps.

Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
---
v2:
- No changes.

 drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h |  13 +--
 drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h     |   2 +
 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c    | 125 +++++++++++++---------
 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h    |   6 ++
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c  |  18 ++++
 5 files changed, 108 insertions(+), 56 deletions(-)

diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
index 348d7e1eb78a..57417f76d4a8 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
@@ -18,17 +18,14 @@
 #ifndef __CUDBG_ENTITY_H__
 #define __CUDBG_ENTITY_H__
 
-#define EDC0_FLAG 3
-#define EDC1_FLAG 4
+#define EDC0_FLAG 0
+#define EDC1_FLAG 1
+#define MC_FLAG 2
+#define MC0_FLAG 3
+#define MC1_FLAG 4
 
 #define CUDBG_ENTITY_SIGNATURE 0xCCEDB001
 
-struct card_mem {
-	u16 size_edc0;
-	u16 size_edc1;
-	u16 mem_flag;
-};
-
 struct cudbg_mbox_log {
 	struct mbox_cmd entry;
 	u32 hi[MBOX_LEN / 8];
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
index 5a5cea2fda69..200ff82a213c 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
@@ -47,6 +47,8 @@ enum cudbg_dbg_entity_type {
 	CUDBG_CIM_OBQ_NCSI = 17,
 	CUDBG_EDC0 = 18,
 	CUDBG_EDC1 = 19,
+	CUDBG_MC0 = 20,
+	CUDBG_MC1 = 21,
 	CUDBG_RSS = 22,
 	CUDBG_RSS_VF_CONF = 25,
 	CUDBG_PATH_MTU = 27,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
index 21dfd70ad08a..2fb27e9f0bce 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
@@ -682,6 +682,42 @@ int cudbg_collect_obq_sge_rx_q1(struct cudbg_init *pdbg_init,
 	return cudbg_read_cim_obq(pdbg_init, dbg_buff, cudbg_err, 7);
 }
 
+static int cudbg_meminfo_get_mem_index(struct adapter *padap,
+				       struct cudbg_meminfo *mem_info,
+				       u8 mem_type, u8 *idx)
+{
+	u8 i, flag;
+
+	switch (mem_type) {
+	case MEM_EDC0:
+		flag = EDC0_FLAG;
+		break;
+	case MEM_EDC1:
+		flag = EDC1_FLAG;
+		break;
+	case MEM_MC0:
+		/* Some T5 cards have both MC0 and MC1. */
+		flag = is_t5(padap->params.chip) ? MC0_FLAG : MC_FLAG;
+		break;
+	case MEM_MC1:
+		flag = MC1_FLAG;
+		break;
+	default:
+		return CUDBG_STATUS_ENTITY_NOT_FOUND;
+	}
+
+	for (i = 0; i < mem_info->avail_c; i++) {
+		if (mem_info->avail[i].idx == flag) {
+			*idx = i;
+			return 0;
+		}
+	}
+
+	return CUDBG_STATUS_ENTITY_NOT_FOUND;
+}
+
+#define CUDBG_YIELD_ITERATION 256
+
 static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
 			     struct cudbg_buffer *dbg_buff, u8 mem_type,
 			     unsigned long tot_len,
@@ -690,10 +726,20 @@ static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
 	unsigned long bytes, bytes_left, bytes_read = 0;
 	struct adapter *padap = pdbg_init->adap;
 	struct cudbg_buffer temp_buff = { 0 };
+	u32 yield_count = 0;
 	int rc = 0;
 
 	bytes_left = tot_len;
 	while (bytes_left > 0) {
+		/* As MC size is huge and read through PIO access, this
+		 * loop will hold cpu for a longer time. OS may think that
+		 * the process is hanged and will generate CPU stall traces.
+		 * So yield the cpu regularly.
+		 */
+		yield_count++;
+		if (!(yield_count % CUDBG_YIELD_ITERATION))
+			schedule();
+
 		bytes = min_t(unsigned long, bytes_left,
 			      (unsigned long)CUDBG_CHUNK_SIZE);
 		rc = cudbg_get_buff(dbg_buff, bytes, &temp_buff);
@@ -717,27 +763,6 @@ static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
 	return rc;
 }
 
-static void cudbg_collect_mem_info(struct cudbg_init *pdbg_init,
-				   struct card_mem *mem_info)
-{
-	struct adapter *padap = pdbg_init->adap;
-	u32 value;
-
-	value = t4_read_reg(padap, MA_EDRAM0_BAR_A);
-	value = EDRAM0_SIZE_G(value);
-	mem_info->size_edc0 = (u16)value;
-
-	value = t4_read_reg(padap, MA_EDRAM1_BAR_A);
-	value = EDRAM1_SIZE_G(value);
-	mem_info->size_edc1 = (u16)value;
-
-	value = t4_read_reg(padap, MA_TARGET_MEM_ENABLE_A);
-	if (value & EDRAM0_ENABLE_F)
-		mem_info->mem_flag |= (1 << EDC0_FLAG);
-	if (value & EDRAM1_ENABLE_F)
-		mem_info->mem_flag |= (1 << EDC1_FLAG);
-}
-
 static void cudbg_t4_fwcache(struct cudbg_init *pdbg_init,
 			     struct cudbg_error *cudbg_err)
 {
@@ -757,37 +782,25 @@ static int cudbg_collect_mem_region(struct cudbg_init *pdbg_init,
 				    struct cudbg_error *cudbg_err,
 				    u8 mem_type)
 {
-	struct card_mem mem_info = {0};
-	unsigned long flag, size;
+	struct adapter *padap = pdbg_init->adap;
+	struct cudbg_meminfo mem_info;
+	unsigned long size;
+	u8 mc_idx;
 	int rc;
 
+	memset(&mem_info, 0, sizeof(struct cudbg_meminfo));
+	rc = cudbg_fill_meminfo(padap, &mem_info);
+	if (rc)
+		return rc;
+
 	cudbg_t4_fwcache(pdbg_init, cudbg_err);
-	cudbg_collect_mem_info(pdbg_init, &mem_info);
-	switch (mem_type) {
-	case MEM_EDC0:
-		flag = (1 << EDC0_FLAG);
-		size = cudbg_mbytes_to_bytes(mem_info.size_edc0);
-		break;
-	case MEM_EDC1:
-		flag = (1 << EDC1_FLAG);
-		size = cudbg_mbytes_to_bytes(mem_info.size_edc1);
-		break;
-	default:
-		rc = CUDBG_STATUS_ENTITY_NOT_FOUND;
-		goto err;
-	}
+	rc = cudbg_meminfo_get_mem_index(padap, &mem_info, mem_type, &mc_idx);
+	if (rc)
+		return rc;
 
-	if (mem_info.mem_flag & flag) {
-		rc = cudbg_read_fw_mem(pdbg_init, dbg_buff, mem_type,
-				       size, cudbg_err);
-		if (rc)
-			goto err;
-	} else {
-		rc = CUDBG_STATUS_ENTITY_NOT_FOUND;
-		goto err;
-	}
-err:
-	return rc;
+	size = mem_info.avail[mc_idx].limit - mem_info.avail[mc_idx].base;
+	return cudbg_read_fw_mem(pdbg_init, dbg_buff, mem_type, size,
+				 cudbg_err);
 }
 
 int cudbg_collect_edc0_meminfo(struct cudbg_init *pdbg_init,
@@ -806,6 +819,22 @@ int cudbg_collect_edc1_meminfo(struct cudbg_init *pdbg_init,
 					MEM_EDC1);
 }
 
+int cudbg_collect_mc0_meminfo(struct cudbg_init *pdbg_init,
+			      struct cudbg_buffer *dbg_buff,
+			      struct cudbg_error *cudbg_err)
+{
+	return cudbg_collect_mem_region(pdbg_init, dbg_buff, cudbg_err,
+					MEM_MC0);
+}
+
+int cudbg_collect_mc1_meminfo(struct cudbg_init *pdbg_init,
+			      struct cudbg_buffer *dbg_buff,
+			      struct cudbg_error *cudbg_err)
+{
+	return cudbg_collect_mem_region(pdbg_init, dbg_buff, cudbg_err,
+					MEM_MC1);
+}
+
 int cudbg_collect_rss(struct cudbg_init *pdbg_init,
 		      struct cudbg_buffer *dbg_buff,
 		      struct cudbg_error *cudbg_err)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
index eb4460c8583e..8bd3d49e712e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
@@ -75,6 +75,12 @@ int cudbg_collect_edc0_meminfo(struct cudbg_init *pdbg_init,
 int cudbg_collect_edc1_meminfo(struct cudbg_init *pdbg_init,
 			       struct cudbg_buffer *dbg_buff,
 			       struct cudbg_error *cudbg_err);
+int cudbg_collect_mc0_meminfo(struct cudbg_init *pdbg_init,
+			      struct cudbg_buffer *dbg_buff,
+			      struct cudbg_error *cudbg_err);
+int cudbg_collect_mc1_meminfo(struct cudbg_init *pdbg_init,
+			      struct cudbg_buffer *dbg_buff,
+			      struct cudbg_error *cudbg_err);
 int cudbg_collect_rss(struct cudbg_init *pdbg_init,
 		      struct cudbg_buffer *dbg_buff,
 		      struct cudbg_error *cudbg_err);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
index faa84a5f0878..389458cb69a8 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
@@ -22,6 +22,8 @@
 static const struct cxgb4_collect_entity cxgb4_collect_mem_dump[] = {
 	{ CUDBG_EDC0, cudbg_collect_edc0_meminfo },
 	{ CUDBG_EDC1, cudbg_collect_edc1_meminfo },
+	{ CUDBG_MC0, cudbg_collect_mc0_meminfo },
+	{ CUDBG_MC1, cudbg_collect_mc1_meminfo },
 };
 
 static const struct cxgb4_collect_entity cxgb4_collect_hw_dump[] = {
@@ -158,6 +160,22 @@ static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
 		}
 		len = cudbg_mbytes_to_bytes(len);
 		break;
+	case CUDBG_MC0:
+		value = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A);
+		if (value & EXT_MEM0_ENABLE_F) {
+			value = t4_read_reg(adap, MA_EXT_MEMORY0_BAR_A);
+			len = EXT_MEM0_SIZE_G(value);
+		}
+		len = cudbg_mbytes_to_bytes(len);
+		break;
+	case CUDBG_MC1:
+		value = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A);
+		if (value & EXT_MEM1_ENABLE_F) {
+			value = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A);
+			len = EXT_MEM1_SIZE_G(value);
+		}
+		len = cudbg_mbytes_to_bytes(len);
+		break;
 	case CUDBG_RSS:
 		len = RSS_NENTRIES * sizeof(u16);
 		break;
-- 
2.14.1

^ permalink raw reply related

* [PATCH net-next v2 3/6] cxgb4: collect HMA memory dump
From: Rahul Lakkireddy @ 2017-12-08  4:18 UTC (permalink / raw)
  To: netdev; +Cc: davem, ganeshgr, nirranjan, indranil, Rahul Lakkireddy
In-Reply-To: <cover.1512705841.git.rahul.lakkireddy@chelsio.com>

Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
---
v2:
- No changes.

 drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h  |  1 +
 drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h      |  1 +
 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c     | 22 ++++++++++++++++++++++
 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h     |  3 +++
 drivers/net/ethernet/chelsio/cxgb4/cxgb4.h         |  3 ++-
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c   | 12 ++++++++++++
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c |  2 +-
 drivers/net/ethernet/chelsio/cxgb4/t4_hw.c         |  7 +++++--
 drivers/net/ethernet/chelsio/cxgb4/t4_regs.h       |  4 ++++
 9 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
index 57417f76d4a8..880b1cb5b463 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
@@ -23,6 +23,7 @@
 #define MC_FLAG 2
 #define MC0_FLAG 3
 #define MC1_FLAG 4
+#define HMA_FLAG 5
 
 #define CUDBG_ENTITY_SIGNATURE 0xCCEDB001
 
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
index 200ff82a213c..69e2c1578b64 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
@@ -77,6 +77,7 @@ enum cudbg_dbg_entity_type {
 	CUDBG_PBT_TABLE = 65,
 	CUDBG_MBOX_LOG = 66,
 	CUDBG_HMA_INDIRECT = 67,
+	CUDBG_HMA = 68,
 	CUDBG_MAX_ENTITY = 70,
 };
 
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
index 2fb27e9f0bce..4e87218d4476 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
@@ -169,6 +169,17 @@ int cudbg_fill_meminfo(struct adapter *padap,
 			meminfo_buff->avail[i].idx = 2;
 			i++;
 		}
+
+		if (lo & HMA_MUX_F) {
+			hi = t4_read_reg(padap, MA_EXT_MEMORY1_BAR_A);
+			meminfo_buff->avail[i].base =
+				cudbg_mbytes_to_bytes(EXT_MEM1_BASE_G(hi));
+			meminfo_buff->avail[i].limit =
+				meminfo_buff->avail[i].base +
+				cudbg_mbytes_to_bytes(EXT_MEM1_SIZE_G(hi));
+			meminfo_buff->avail[i].idx = 5;
+			i++;
+		}
 	}
 
 	if (!i) /* no memory available */
@@ -702,6 +713,9 @@ static int cudbg_meminfo_get_mem_index(struct adapter *padap,
 	case MEM_MC1:
 		flag = MC1_FLAG;
 		break;
+	case MEM_HMA:
+		flag = HMA_FLAG;
+		break;
 	default:
 		return CUDBG_STATUS_ENTITY_NOT_FOUND;
 	}
@@ -835,6 +849,14 @@ int cudbg_collect_mc1_meminfo(struct cudbg_init *pdbg_init,
 					MEM_MC1);
 }
 
+int cudbg_collect_hma_meminfo(struct cudbg_init *pdbg_init,
+			      struct cudbg_buffer *dbg_buff,
+			      struct cudbg_error *cudbg_err)
+{
+	return cudbg_collect_mem_region(pdbg_init, dbg_buff, cudbg_err,
+					MEM_HMA);
+}
+
 int cudbg_collect_rss(struct cudbg_init *pdbg_init,
 		      struct cudbg_buffer *dbg_buff,
 		      struct cudbg_error *cudbg_err)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
index 8bd3d49e712e..18742e5a4399 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
@@ -165,6 +165,9 @@ int cudbg_collect_mbox_log(struct cudbg_init *pdbg_init,
 int cudbg_collect_hma_indirect(struct cudbg_init *pdbg_init,
 			       struct cudbg_buffer *dbg_buff,
 			       struct cudbg_error *cudbg_err);
+int cudbg_collect_hma_meminfo(struct cudbg_init *pdbg_init,
+			      struct cudbg_buffer *dbg_buff,
+			      struct cudbg_error *cudbg_err);
 
 struct cudbg_entity_hdr *cudbg_get_entity_hdr(void *outbuf, int i);
 void cudbg_align_debug_buffer(struct cudbg_buffer *dbg_buff,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 6f9fa6e3c42a..e680beed9030 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -77,7 +77,8 @@ enum {
 	MEM_EDC1,
 	MEM_MC,
 	MEM_MC0 = MEM_MC,
-	MEM_MC1
+	MEM_MC1,
+	MEM_HMA,
 };
 
 enum {
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
index 389458cb69a8..273316f4a20d 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
@@ -24,6 +24,7 @@ static const struct cxgb4_collect_entity cxgb4_collect_mem_dump[] = {
 	{ CUDBG_EDC1, cudbg_collect_edc1_meminfo },
 	{ CUDBG_MC0, cudbg_collect_mc0_meminfo },
 	{ CUDBG_MC1, cudbg_collect_mc1_meminfo },
+	{ CUDBG_HMA, cudbg_collect_hma_meminfo },
 };
 
 static const struct cxgb4_collect_entity cxgb4_collect_hw_dump[] = {
@@ -285,6 +286,17 @@ static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
 			len = sizeof(struct ireg_buf) * n;
 		}
 		break;
+	case CUDBG_HMA:
+		value = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A);
+		if (value & HMA_MUX_F) {
+			/* In T6, there's no MC1.  So, HMA shares MC1
+			 * address space.
+			 */
+			value = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A);
+			len = EXT_MEM1_SIZE_G(value);
+		}
+		len = cudbg_mbytes_to_bytes(len);
+		break;
 	default:
 		break;
 	}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
index c6732683cb8c..4956e429ae1d 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
@@ -2811,7 +2811,7 @@ static void mem_region_show(struct seq_file *seq, const char *name,
 static int meminfo_show(struct seq_file *seq, void *v)
 {
 	static const char * const memory[] = { "EDC0:", "EDC1:", "MC:",
-					       "MC0:", "MC1:"};
+					       "MC0:", "MC1:", "HMA:"};
 	struct adapter *adap = seq->private;
 	struct cudbg_meminfo meminfo;
 	int i, rc;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index f63210f15579..ccb2798c34d1 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -524,11 +524,14 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
 	 * MEM_EDC1 = 1
 	 * MEM_MC   = 2 -- MEM_MC for chips with only 1 memory controller
 	 * MEM_MC1  = 3 -- for chips with 2 memory controllers (e.g. T5)
+	 * MEM_HMA  = 4
 	 */
 	edc_size  = EDRAM0_SIZE_G(t4_read_reg(adap, MA_EDRAM0_BAR_A));
-	if (mtype != MEM_MC1)
+	if (mtype == MEM_HMA) {
+		memoffset = 2 * (edc_size * 1024 * 1024);
+	} else if (mtype != MEM_MC1) {
 		memoffset = (mtype * (edc_size * 1024 * 1024));
-	else {
+	} else {
 		mc_size = EXT_MEM0_SIZE_G(t4_read_reg(adap,
 						      MA_EXT_MEMORY0_BAR_A));
 		memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
index a7cfece72828..f6701e0a6701 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
@@ -961,6 +961,10 @@
 
 #define MA_EXT_MEMORY1_BAR_A 0x7808
 
+#define HMA_MUX_S    5
+#define HMA_MUX_V(x) ((x) << HMA_MUX_S)
+#define HMA_MUX_F    HMA_MUX_V(1U)
+
 #define EXT_MEM1_BASE_S    16
 #define EXT_MEM1_BASE_M    0xfffU
 #define EXT_MEM1_BASE_G(x) (((x) >> EXT_MEM1_BASE_S) & EXT_MEM1_BASE_M)
-- 
2.14.1

^ permalink raw reply related

* [PATCH net-next v2 4/6] cxgb4: skip TX and RX payload regions in memory dumps
From: Rahul Lakkireddy @ 2017-12-08  4:18 UTC (permalink / raw)
  To: netdev; +Cc: davem, ganeshgr, nirranjan, indranil, Rahul Lakkireddy
In-Reply-To: <cover.1512705841.git.rahul.lakkireddy@chelsio.com>

Use meminfo to identify TX and RX payload regions and skip them in
collection of EDC, MC, and HMA.

Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
---
v2:
- No changes.

 drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h |   7 ++
 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c    | 141 ++++++++++++++++++++++
 2 files changed, 148 insertions(+)

diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
index 880b1cb5b463..1e1719526e76 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
@@ -95,6 +95,13 @@ static const char * const cudbg_region[] = {
 	"On-chip queues:"
 };
 
+/* Memory region info relative to current memory (i.e. wrt 0). */
+struct cudbg_region_info {
+	bool exist; /* Does region exists in current memory? */
+	u32 start;  /* Start wrt 0 */
+	u32 end;    /* End wrt 0 */
+};
+
 struct cudbg_mem_desc {
 	u32 base;
 	u32 limit;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
index 4e87218d4476..2e3cf36347a2 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
@@ -730,6 +730,116 @@ static int cudbg_meminfo_get_mem_index(struct adapter *padap,
 	return CUDBG_STATUS_ENTITY_NOT_FOUND;
 }
 
+/* Fetch the @region_name's start and end from @meminfo. */
+static int cudbg_get_mem_region(struct adapter *padap,
+				struct cudbg_meminfo *meminfo,
+				u8 mem_type, const char *region_name,
+				struct cudbg_mem_desc *mem_desc)
+{
+	u8 mc, found = 0;
+	u32 i, idx = 0;
+	int rc;
+
+	rc = cudbg_meminfo_get_mem_index(padap, meminfo, mem_type, &mc);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < ARRAY_SIZE(cudbg_region); i++) {
+		if (!strcmp(cudbg_region[i], region_name)) {
+			found = 1;
+			idx = i;
+			break;
+		}
+	}
+	if (!found)
+		return -EINVAL;
+
+	found = 0;
+	for (i = 0; i < meminfo->mem_c; i++) {
+		if (meminfo->mem[i].idx >= ARRAY_SIZE(cudbg_region))
+			continue; /* Skip holes */
+
+		if (!(meminfo->mem[i].limit))
+			meminfo->mem[i].limit =
+				i < meminfo->mem_c - 1 ?
+				meminfo->mem[i + 1].base - 1 : ~0;
+
+		if (meminfo->mem[i].idx == idx) {
+			/* Check if the region exists in @mem_type memory */
+			if (meminfo->mem[i].base < meminfo->avail[mc].base &&
+			    meminfo->mem[i].limit < meminfo->avail[mc].base)
+				return -EINVAL;
+
+			if (meminfo->mem[i].base > meminfo->avail[mc].limit)
+				return -EINVAL;
+
+			memcpy(mem_desc, &meminfo->mem[i],
+			       sizeof(struct cudbg_mem_desc));
+			found = 1;
+			break;
+		}
+	}
+	if (!found)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* Fetch and update the start and end of the requested memory region w.r.t 0
+ * in the corresponding EDC/MC/HMA.
+ */
+static int cudbg_get_mem_relative(struct adapter *padap,
+				  struct cudbg_meminfo *meminfo,
+				  u8 mem_type, u32 *out_base, u32 *out_end)
+{
+	u8 mc_idx;
+	int rc;
+
+	rc = cudbg_meminfo_get_mem_index(padap, meminfo, mem_type, &mc_idx);
+	if (rc)
+		return rc;
+
+	if (*out_base < meminfo->avail[mc_idx].base)
+		*out_base = 0;
+	else
+		*out_base -= meminfo->avail[mc_idx].base;
+
+	if (*out_end > meminfo->avail[mc_idx].limit)
+		*out_end = meminfo->avail[mc_idx].limit;
+	else
+		*out_end -= meminfo->avail[mc_idx].base;
+
+	return 0;
+}
+
+/* Get TX and RX Payload region */
+static int cudbg_get_payload_range(struct adapter *padap, u8 mem_type,
+				   const char *region_name,
+				   struct cudbg_region_info *payload)
+{
+	struct cudbg_mem_desc mem_desc = { 0 };
+	struct cudbg_meminfo meminfo;
+	int rc;
+
+	rc = cudbg_fill_meminfo(padap, &meminfo);
+	if (rc)
+		return rc;
+
+	rc = cudbg_get_mem_region(padap, &meminfo, mem_type, region_name,
+				  &mem_desc);
+	if (rc) {
+		payload->exist = false;
+		return 0;
+	}
+
+	payload->exist = true;
+	payload->start = mem_desc.base;
+	payload->end = mem_desc.limit;
+
+	return cudbg_get_mem_relative(padap, &meminfo, mem_type,
+				      &payload->start, &payload->end);
+}
+
 #define CUDBG_YIELD_ITERATION 256
 
 static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
@@ -737,11 +847,32 @@ static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
 			     unsigned long tot_len,
 			     struct cudbg_error *cudbg_err)
 {
+	static const char * const region_name[] = { "Tx payload:",
+						    "Rx payload:" };
 	unsigned long bytes, bytes_left, bytes_read = 0;
 	struct adapter *padap = pdbg_init->adap;
 	struct cudbg_buffer temp_buff = { 0 };
+	struct cudbg_region_info payload[2];
 	u32 yield_count = 0;
 	int rc = 0;
+	u8 i;
+
+	/* Get TX/RX Payload region range if they exist */
+	memset(payload, 0, sizeof(payload));
+	for (i = 0; i < ARRAY_SIZE(region_name); i++) {
+		rc = cudbg_get_payload_range(padap, mem_type, region_name[i],
+					     &payload[i]);
+		if (rc)
+			return rc;
+
+		if (payload[i].exist) {
+			/* Align start and end to avoid wrap around */
+			payload[i].start = roundup(payload[i].start,
+						   CUDBG_CHUNK_SIZE);
+			payload[i].end = rounddown(payload[i].end,
+						   CUDBG_CHUNK_SIZE);
+		}
+	}
 
 	bytes_left = tot_len;
 	while (bytes_left > 0) {
@@ -759,6 +890,14 @@ static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
 		rc = cudbg_get_buff(dbg_buff, bytes, &temp_buff);
 		if (rc)
 			return rc;
+
+		for (i = 0; i < ARRAY_SIZE(payload); i++)
+			if (payload[i].exist &&
+			    bytes_read >= payload[i].start &&
+			    bytes_read + bytes <= payload[i].end)
+				/* TX and RX Payload regions can't overlap */
+				goto skip_read;
+
 		spin_lock(&padap->win0_lock);
 		rc = t4_memory_rw(padap, MEMWIN_NIC, mem_type,
 				  bytes_read, bytes,
@@ -770,6 +909,8 @@ static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
 			cudbg_put_buff(&temp_buff, dbg_buff);
 			return rc;
 		}
+
+skip_read:
 		bytes_left -= bytes;
 		bytes_read += bytes;
 		cudbg_write_and_release_buff(&temp_buff, dbg_buff);
-- 
2.14.1

^ permalink raw reply related

* [PATCH net-next v2 5/6] cxgb4: collect egress and ingress SGE queue contexts
From: Rahul Lakkireddy @ 2017-12-08  4:18 UTC (permalink / raw)
  To: netdev; +Cc: davem, ganeshgr, nirranjan, indranil, Rahul Lakkireddy
In-Reply-To: <cover.1512705841.git.rahul.lakkireddy@chelsio.com>

Use meminfo to identify the egress and ingress context regions and
fetch all valid contexts from those regions. Also flush all contexts
before attempting collection to prevent stale information.

Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
---
v2:
- No changes.

 drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h |   1 +
 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c    | 218 ++++++++++++++++++++--
 drivers/net/ethernet/chelsio/cxgb4/cxgb4.h        |   2 +-
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c   |   2 +-
 drivers/net/ethernet/chelsio/cxgb4/t4_hw.c        |   7 +-
 drivers/net/ethernet/chelsio/cxgb4/t4_hw.h        |   4 +-
 6 files changed, 210 insertions(+), 24 deletions(-)

diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
index 1e1719526e76..075916044980 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
@@ -185,6 +185,7 @@ struct cudbg_tid_info_region_rev1 {
 	u32 reserved[16];
 };
 
+#define CUDBG_LOWMEM_MAX_CTXT_QIDS 256
 #define CUDBG_MAX_FL_QIDS 1024
 
 struct cudbg_ch_cntxt {
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
index 2e3cf36347a2..38866f3f45ac 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
@@ -1594,22 +1594,108 @@ int cudbg_collect_tid(struct cudbg_init *pdbg_init,
 	return rc;
 }
 
-int cudbg_dump_context_size(struct adapter *padap)
+static int cudbg_sge_ctxt_check_valid(u32 *buf, int type)
+{
+	int index, bit, bit_pos = 0;
+
+	switch (type) {
+	case CTXT_EGRESS:
+		bit_pos = 176;
+		break;
+	case CTXT_INGRESS:
+		bit_pos = 141;
+		break;
+	case CTXT_FLM:
+		bit_pos = 89;
+		break;
+	}
+	index = bit_pos / 32;
+	bit =  bit_pos % 32;
+	return buf[index] & (1U << bit);
+}
+
+static int cudbg_get_ctxt_region_info(struct adapter *padap,
+				      struct cudbg_region_info *ctx_info,
+				      u8 *mem_type)
 {
-	u32 value, size;
+	struct cudbg_mem_desc mem_desc;
+	struct cudbg_meminfo meminfo;
+	u32 i, j, value, found;
 	u8 flq;
+	int rc;
+
+	rc = cudbg_fill_meminfo(padap, &meminfo);
+	if (rc)
+		return rc;
+
+	/* Get EGRESS and INGRESS context region size */
+	for (i = CTXT_EGRESS; i <= CTXT_INGRESS; i++) {
+		found = 0;
+		memset(&mem_desc, 0, sizeof(struct cudbg_mem_desc));
+		for (j = 0; j < ARRAY_SIZE(meminfo.avail); j++) {
+			rc = cudbg_get_mem_region(padap, &meminfo, j,
+						  cudbg_region[i],
+						  &mem_desc);
+			if (!rc) {
+				found = 1;
+				rc = cudbg_get_mem_relative(padap, &meminfo, j,
+							    &mem_desc.base,
+							    &mem_desc.limit);
+				if (rc) {
+					ctx_info[i].exist = false;
+					break;
+				}
+				ctx_info[i].exist = true;
+				ctx_info[i].start = mem_desc.base;
+				ctx_info[i].end = mem_desc.limit;
+				mem_type[i] = j;
+				break;
+			}
+		}
+		if (!found)
+			ctx_info[i].exist = false;
+	}
 
+	/* Get FLM and CNM max qid. */
 	value = t4_read_reg(padap, SGE_FLM_CFG_A);
 
 	/* Get number of data freelist queues */
 	flq = HDRSTARTFLQ_G(value);
-	size = CUDBG_MAX_FL_QIDS >> flq;
+	ctx_info[CTXT_FLM].exist = true;
+	ctx_info[CTXT_FLM].end = (CUDBG_MAX_FL_QIDS >> flq) * SGE_CTXT_SIZE;
 
-	/* Add extra space for congestion manager contexts.
-	 * The number of CONM contexts are same as number of freelist
+	/* The number of CONM contexts are same as number of freelist
 	 * queues.
 	 */
-	size += size;
+	ctx_info[CTXT_CNM].exist = true;
+	ctx_info[CTXT_CNM].end = ctx_info[CTXT_FLM].end;
+
+	return 0;
+}
+
+int cudbg_dump_context_size(struct adapter *padap)
+{
+	struct cudbg_region_info region_info[CTXT_CNM + 1] = { {0} };
+	u8 mem_type[CTXT_INGRESS + 1] = { 0 };
+	u32 i, size = 0;
+	int rc;
+
+	/* Get max valid qid for each type of queue */
+	rc = cudbg_get_ctxt_region_info(padap, region_info, mem_type);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < CTXT_CNM; i++) {
+		if (!region_info[i].exist) {
+			if (i == CTXT_EGRESS || i == CTXT_INGRESS)
+				size += CUDBG_LOWMEM_MAX_CTXT_QIDS *
+					SGE_CTXT_SIZE;
+			continue;
+		}
+
+		size += (region_info[i].end - region_info[i].start + 1) /
+			SGE_CTXT_SIZE;
+	}
 	return size * sizeof(struct cudbg_ch_cntxt);
 }
 
@@ -1632,16 +1718,54 @@ static void cudbg_read_sge_ctxt(struct cudbg_init *pdbg_init, u32 cid,
 		t4_sge_ctxt_rd_bd(padap, cid, ctype, data);
 }
 
+static void cudbg_get_sge_ctxt_fw(struct cudbg_init *pdbg_init, u32 max_qid,
+				  u8 ctxt_type,
+				  struct cudbg_ch_cntxt **out_buff)
+{
+	struct cudbg_ch_cntxt *buff = *out_buff;
+	int rc;
+	u32 j;
+
+	for (j = 0; j < max_qid; j++) {
+		cudbg_read_sge_ctxt(pdbg_init, j, ctxt_type, buff->data);
+		rc = cudbg_sge_ctxt_check_valid(buff->data, ctxt_type);
+		if (!rc)
+			continue;
+
+		buff->cntxt_type = ctxt_type;
+		buff->cntxt_id = j;
+		buff++;
+		if (ctxt_type == CTXT_FLM) {
+			cudbg_read_sge_ctxt(pdbg_init, j, CTXT_CNM, buff->data);
+			buff->cntxt_type = CTXT_CNM;
+			buff->cntxt_id = j;
+			buff++;
+		}
+	}
+
+	*out_buff = buff;
+}
+
 int cudbg_collect_dump_context(struct cudbg_init *pdbg_init,
 			       struct cudbg_buffer *dbg_buff,
 			       struct cudbg_error *cudbg_err)
 {
+	struct cudbg_region_info region_info[CTXT_CNM + 1] = { {0} };
 	struct adapter *padap = pdbg_init->adap;
+	u32 j, size, max_ctx_size, max_ctx_qid;
+	u8 mem_type[CTXT_INGRESS + 1] = { 0 };
 	struct cudbg_buffer temp_buff = { 0 };
 	struct cudbg_ch_cntxt *buff;
-	u32 size, i = 0;
+	u64 *dst_off, *src_off;
+	u8 *ctx_buf;
+	u8 i, k;
 	int rc;
 
+	/* Get max valid qid for each type of queue */
+	rc = cudbg_get_ctxt_region_info(padap, region_info, mem_type);
+	if (rc)
+		return rc;
+
 	rc = cudbg_dump_context_size(padap);
 	if (rc <= 0)
 		return CUDBG_STATUS_ENTITY_NOT_FOUND;
@@ -1651,23 +1775,79 @@ int cudbg_collect_dump_context(struct cudbg_init *pdbg_init,
 	if (rc)
 		return rc;
 
+	/* Get buffer with enough space to read the biggest context
+	 * region in memory.
+	 */
+	max_ctx_size = max(region_info[CTXT_EGRESS].end -
+			   region_info[CTXT_EGRESS].start + 1,
+			   region_info[CTXT_INGRESS].end -
+			   region_info[CTXT_INGRESS].start + 1);
+
+	ctx_buf = kvzalloc(max_ctx_size, GFP_KERNEL);
+	if (!ctx_buf) {
+		cudbg_put_buff(&temp_buff, dbg_buff);
+		return -ENOMEM;
+	}
+
 	buff = (struct cudbg_ch_cntxt *)temp_buff.data;
-	while (size > 0) {
-		buff->cntxt_type = CTXT_FLM;
-		buff->cntxt_id = i;
-		cudbg_read_sge_ctxt(pdbg_init, i, CTXT_FLM, buff->data);
-		buff++;
-		size -= sizeof(struct cudbg_ch_cntxt);
 
-		buff->cntxt_type = CTXT_CNM;
-		buff->cntxt_id = i;
-		cudbg_read_sge_ctxt(pdbg_init, i, CTXT_CNM, buff->data);
-		buff++;
-		size -= sizeof(struct cudbg_ch_cntxt);
+	/* Collect EGRESS and INGRESS context data.
+	 * In case of failures, fallback to collecting via FW or
+	 * backdoor access.
+	 */
+	for (i = CTXT_EGRESS; i <= CTXT_INGRESS; i++) {
+		if (!region_info[i].exist) {
+			max_ctx_qid = CUDBG_LOWMEM_MAX_CTXT_QIDS;
+			cudbg_get_sge_ctxt_fw(pdbg_init, max_ctx_qid, i,
+					      &buff);
+			continue;
+		}
 
-		i++;
+		max_ctx_size = region_info[i].end - region_info[i].start + 1;
+		max_ctx_qid = max_ctx_size / SGE_CTXT_SIZE;
+
+		t4_sge_ctxt_flush(padap, padap->mbox, i);
+		rc = t4_memory_rw(padap, MEMWIN_NIC, mem_type[i],
+				  region_info[i].start, max_ctx_size,
+				  (__be32 *)ctx_buf, 1);
+		if (rc) {
+			max_ctx_qid = CUDBG_LOWMEM_MAX_CTXT_QIDS;
+			cudbg_get_sge_ctxt_fw(pdbg_init, max_ctx_qid, i,
+					      &buff);
+			continue;
+		}
+
+		for (j = 0; j < max_ctx_qid; j++) {
+			src_off = (u64 *)(ctx_buf + j * SGE_CTXT_SIZE);
+			dst_off = (u64 *)buff->data;
+
+			/* The data is stored in 64-bit cpu order.  Convert it
+			 * to big endian before parsing.
+			 */
+			for (k = 0; k < SGE_CTXT_SIZE / sizeof(u64); k++)
+				dst_off[k] = cpu_to_be64(src_off[k]);
+
+			rc = cudbg_sge_ctxt_check_valid(buff->data, i);
+			if (!rc)
+				continue;
+
+			buff->cntxt_type = i;
+			buff->cntxt_id = j;
+			buff++;
+		}
 	}
 
+	kvfree(ctx_buf);
+
+	/* Collect FREELIST and CONGESTION MANAGER contexts */
+	max_ctx_size = region_info[CTXT_FLM].end -
+		       region_info[CTXT_FLM].start + 1;
+	max_ctx_qid = max_ctx_size / SGE_CTXT_SIZE;
+	/* Since FLM and CONM are 1-to-1 mapped, the below function
+	 * will fetch both FLM and CONM contexts.
+	 */
+	cudbg_get_sge_ctxt_fw(pdbg_init, max_ctx_qid, CTXT_FLM, &buff);
+
 	cudbg_write_and_release_buff(&temp_buff, dbg_buff);
 	return rc;
 }
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index e680beed9030..97dc3efeb234 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -1654,7 +1654,7 @@ int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
 		    unsigned int vf, unsigned int eqid);
 int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
 		    unsigned int vf, unsigned int eqid);
-int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox);
+int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox, int ctxt_type);
 void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl);
 int t4_update_port_info(struct port_info *pi);
 int t4_get_link_params(struct port_info *pi, unsigned int *link_okp,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 6f900ffe25cc..87ac1e4dafc1 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -1673,7 +1673,7 @@ int cxgb4_flush_eq_cache(struct net_device *dev)
 {
 	struct adapter *adap = netdev2adap(dev);
 
-	return t4_sge_ctxt_flush(adap, adap->mbox);
+	return t4_sge_ctxt_flush(adap, adap->mbox, CTXT_EGRESS);
 }
 EXPORT_SYMBOL(cxgb4_flush_eq_cache);
 
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index ccb2798c34d1..112963defd0b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -6530,18 +6530,21 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state)
  *      t4_sge_ctxt_flush - flush the SGE context cache
  *      @adap: the adapter
  *      @mbox: mailbox to use for the FW command
+ *      @ctx_type: Egress or Ingress
  *
  *      Issues a FW command through the given mailbox to flush the
  *      SGE context cache.
  */
-int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox)
+int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox, int ctxt_type)
 {
 	int ret;
 	u32 ldst_addrspace;
 	struct fw_ldst_cmd c;
 
 	memset(&c, 0, sizeof(c));
-	ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_SGE_EGRC);
+	ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(ctxt_type == CTXT_EGRESS ?
+						 FW_LDST_ADDRSPC_SGE_EGRC :
+						 FW_LDST_ADDRSPC_SGE_INGC);
 	c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) |
 					FW_CMD_REQUEST_F | FW_CMD_READ_F |
 					ldst_addrspace);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
index a964ed184356..83afb32c8491 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
@@ -70,7 +70,9 @@ enum {
 
 /* SGE context types */
 enum ctxt_type {
-	CTXT_FLM = 2,
+	CTXT_EGRESS,
+	CTXT_INGRESS,
+	CTXT_FLM,
 	CTXT_CNM,
 };
 
-- 
2.14.1

^ permalink raw reply related

* [PATCH net-next v2 6/6] cxgb4: collect PCIe configuration logs
From: Rahul Lakkireddy @ 2017-12-08  4:18 UTC (permalink / raw)
  To: netdev; +Cc: davem, ganeshgr, nirranjan, indranil, Rahul Lakkireddy
In-Reply-To: <cover.1512705841.git.rahul.lakkireddy@chelsio.com>

Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
---
v2:
- No changes.

 drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 19 ++++++++++++++++
 drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h     |  1 +
 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c    | 27 +++++++++++++++++++++++
 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h    |  3 +++
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c  |  4 ++++
 5 files changed, 54 insertions(+)

diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
index 075916044980..2e71e334d819 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
@@ -375,6 +375,25 @@ static const u32 t5_pm_tx_array[][IREG_NUM_ELEM] = {
 	{0x8FF0, 0x8FF4, 0x10021, 0x1D}, /* t5_pm_tx_regs_10021_to_1003c */
 };
 
+#define CUDBG_NUM_PCIE_CONFIG_REGS 0x61
+
+static const u32 t5_pcie_config_array[][2] = {
+	{0x0, 0x34},
+	{0x3c, 0x40},
+	{0x50, 0x64},
+	{0x70, 0x80},
+	{0x94, 0xa0},
+	{0xb0, 0xb8},
+	{0xd0, 0xd4},
+	{0x100, 0x128},
+	{0x140, 0x148},
+	{0x150, 0x164},
+	{0x170, 0x178},
+	{0x180, 0x194},
+	{0x1a0, 0x1b8},
+	{0x1c0, 0x208},
+};
+
 static const u32 t6_ma_ireg_array[][IREG_NUM_ELEM] = {
 	{0x78f8, 0x78fc, 0xa000, 23}, /* t6_ma_regs_a000_to_a016 */
 	{0x78f8, 0x78fc, 0xa400, 30}, /* t6_ma_regs_a400_to_a41e */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
index 69e2c1578b64..e8173ae32158 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
@@ -66,6 +66,7 @@ enum cudbg_dbg_entity_type {
 	CUDBG_PCIE_INDIRECT = 50,
 	CUDBG_PM_INDIRECT = 51,
 	CUDBG_TID_INFO = 54,
+	CUDBG_PCIE_CONFIG = 55,
 	CUDBG_DUMP_CONTEXT = 56,
 	CUDBG_MPS_TCAM = 57,
 	CUDBG_VPD_DATA = 58,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
index 38866f3f45ac..d73fb6a85f8e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
@@ -1594,6 +1594,33 @@ int cudbg_collect_tid(struct cudbg_init *pdbg_init,
 	return rc;
 }
 
+int cudbg_collect_pcie_config(struct cudbg_init *pdbg_init,
+			      struct cudbg_buffer *dbg_buff,
+			      struct cudbg_error *cudbg_err)
+{
+	struct adapter *padap = pdbg_init->adap;
+	struct cudbg_buffer temp_buff = { 0 };
+	u32 size, *value, j;
+	int i, rc, n;
+
+	size = sizeof(u32) * CUDBG_NUM_PCIE_CONFIG_REGS;
+	n = sizeof(t5_pcie_config_array) / (2 * sizeof(u32));
+	rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
+	if (rc)
+		return rc;
+
+	value = (u32 *)temp_buff.data;
+	for (i = 0; i < n; i++) {
+		for (j = t5_pcie_config_array[i][0];
+		     j <= t5_pcie_config_array[i][1]; j += 4) {
+			t4_hw_pci_read_cfg4(padap, j, value);
+			value++;
+		}
+	}
+	cudbg_write_and_release_buff(&temp_buff, dbg_buff);
+	return rc;
+}
+
 static int cudbg_sge_ctxt_check_valid(u32 *buf, int type)
 {
 	int index, bit, bit_pos = 0;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
index 18742e5a4399..eebefe7cd18e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
@@ -132,6 +132,9 @@ int cudbg_collect_pm_indirect(struct cudbg_init *pdbg_init,
 int cudbg_collect_tid(struct cudbg_init *pdbg_init,
 		      struct cudbg_buffer *dbg_buff,
 		      struct cudbg_error *cudbg_err);
+int cudbg_collect_pcie_config(struct cudbg_init *pdbg_init,
+			      struct cudbg_buffer *dbg_buff,
+			      struct cudbg_error *cudbg_err);
 int cudbg_collect_dump_context(struct cudbg_init *pdbg_init,
 			       struct cudbg_buffer *dbg_buff,
 			       struct cudbg_error *cudbg_err);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
index 273316f4a20d..41c8736314f8 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
@@ -63,6 +63,7 @@ static const struct cxgb4_collect_entity cxgb4_collect_hw_dump[] = {
 	{ CUDBG_PCIE_INDIRECT, cudbg_collect_pcie_indirect },
 	{ CUDBG_PM_INDIRECT, cudbg_collect_pm_indirect },
 	{ CUDBG_TID_INFO, cudbg_collect_tid },
+	{ CUDBG_PCIE_CONFIG, cudbg_collect_pcie_config },
 	{ CUDBG_DUMP_CONTEXT, cudbg_collect_dump_context },
 	{ CUDBG_MPS_TCAM, cudbg_collect_mps_tcam },
 	{ CUDBG_VPD_DATA, cudbg_collect_vpd_data },
@@ -241,6 +242,9 @@ static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
 	case CUDBG_TID_INFO:
 		len = sizeof(struct cudbg_tid_info_region_rev1);
 		break;
+	case CUDBG_PCIE_CONFIG:
+		len = sizeof(u32) * CUDBG_NUM_PCIE_CONFIG_REGS;
+		break;
 	case CUDBG_DUMP_CONTEXT:
 		len = cudbg_dump_context_size(adap);
 		break;
-- 
2.14.1

^ permalink raw reply related

* Re: [PATCH net-next V2] tuntap: fix possible deadlock when fail to register netdev
From: Michael S. Tsirkin @ 2017-12-08  4:43 UTC (permalink / raw)
  To: Jason Wang; +Cc: netdev, linux-kernel, Eric Dumazet, Willem de Bruijn
In-Reply-To: <1512705750-14799-1-git-send-email-jasowang@redhat.com>

On Fri, Dec 08, 2017 at 12:02:30PM +0800, Jason Wang wrote:
> Private destructor could be called when register_netdev() fail with
> rtnl lock held. This will lead deadlock in tun_free_netdev() who tries
> to hold rtnl_lock. Fixing this by switching to use spinlock to
> synchronize.
> 
> Fixes: 96f84061620c ("tun: add eBPF based queue selection method")
> Reported-by: Eric Dumazet <eric.dumazet@gmail.com>
> Cc: Eric Dumazet <eric.dumazet@gmail.com>
> Cc: Willem de Bruijn <willemb@google.com>
> Signed-off-by: Jason Wang <jasowang@redhat.com>

Acked-by: Michael S. Tsirkin <mst@redhat.com>

> ---
>  drivers/net/tun.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index 787cc35..8d85163 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -2050,8 +2050,11 @@ static int __tun_set_steering_ebpf(struct tun_struct *tun,
>  		new->prog = prog;
>  	}
>  
> -	old = rtnl_dereference(tun->steering_prog);
> +	spin_lock_bh(&tun->lock);
> +	old = rcu_dereference_protected(tun->steering_prog,
> +					lockdep_is_held(&tun->lock));
>  	rcu_assign_pointer(tun->steering_prog, new);
> +	spin_unlock_bh(&tun->lock);
>  
>  	if (old)
>  		call_rcu(&old->rcu, tun_steering_prog_free);
> @@ -2067,9 +2070,7 @@ static void tun_free_netdev(struct net_device *dev)
>  	free_percpu(tun->pcpu_stats);
>  	tun_flow_uninit(tun);
>  	security_tun_dev_free_security(tun->security);
> -	rtnl_lock();
>  	__tun_set_steering_ebpf(tun, NULL);
> -	rtnl_unlock();
>  }
>  
>  static void tun_setup(struct net_device *dev)
> -- 
> 2.7.4

^ permalink raw reply

* BUG: KASAN: use-after-free in tcf_block_put_ext+0x5cf/0x5e0
From: Jakub Kicinski @ 2017-12-08  4:51 UTC (permalink / raw)
  To: Cong Wang; +Cc: Roman Kapl, netdev@vger.kernel.org, Jiri Pirko

Running the netdevsim test after a week and a bit of not trying it:

$ make -C tools/testing/selftests/bpf/ CLANG=clang LLC=llc
# ./tools/testing/selftests/bpf/test_offload.py

[  284.174418] ==================================================================
[  284.182655] BUG: KASAN: use-after-free in tcf_block_put_ext+0x5cf/0x5e0
[  284.190160] Read of size 8 at addr ffff8803152f4d08 by task tc/1652

[  284.199033] CPU: 13 PID: 1652 Comm: tc Not tainted 4.15.0-rc2-debug-00310-g227cf4846533 #386
[  284.199043] Hardware name: Dell Inc. PowerEdge R730/072T6D, BIOS 2.3.4 11/08/2016
[  284.199053] Call Trace:
[  284.199068]  dump_stack+0xb3/0x140
[  284.199081]  ? _atomic_dec_and_lock+0x2b0/0x2b0
[  284.199094]  ? show_regs_print_info+0x6d/0x6d
[  284.199109]  ? tcf_chain_destroy+0x29b/0x3d0
[  284.199125]  print_address_description+0x7a/0x440
[  284.199140]  ? tcf_block_put_ext+0x5cf/0x5e0
[  284.199153]  kasan_report+0x1b8/0x430
[  284.199170]  ? tcf_block_put_ext+0x5cf/0x5e0
[  284.199186]  tcf_block_put_ext+0x5cf/0x5e0
[  284.199198]  ? tcf_chain_flush+0x370/0x370
[  284.199226]  ingress_destroy+0x47/0x80 [sch_ingress]
[  284.199242]  qdisc_destroy+0x141/0x430
[  284.199256]  qdisc_graft+0x315/0xcd0
[  284.199280]  tc_get_qdisc+0x3d5/0xad0
[  284.199298]  ? tc_ctl_tclass+0xcb0/0xcb0
[  284.199310]  ? rtnl_dump_all+0x4e0/0x4e0
[  284.199342]  rtnetlink_rcv_msg+0x555/0xb80
[  284.199359]  ? validate_linkmsg+0xb00/0xb00
[  284.199369]  ? netlink_deliver_tap+0x163/0xd30
[  284.199384]  ? lock_acquire+0x169/0x590
[  284.199396]  ? netlink_lookup+0x5/0x170
[  284.199418]  netlink_rcv_skb+0x210/0x4a0
[  284.199428]  ? validate_linkmsg+0xb00/0xb00
[  284.199443]  ? rcu_is_watching+0x59/0x1f0
[  284.199456]  ? netlink_ack+0xd00/0xd00
[  284.199466]  ? rcu_gpnum_ovf+0x310/0x310
[  284.199495]  netlink_unicast+0x435/0x660
[  284.199513]  ? netlink_attachskb+0xa90/0xa90
[  284.199528]  ? push_pipe+0xf10/0xf10
[  284.199549]  netlink_sendmsg+0x9b4/0x1060
[  284.199567]  ? netlink_unicast+0x660/0x660
[  284.199578]  ? SYSC_sendto+0x5f0/0x5f0
[  284.199600]  ? netlink_unicast+0x660/0x660
[  284.199612]  sock_sendmsg+0xd9/0x160
[  284.199627]  ___sys_sendmsg+0x72d/0xcc0
[  284.199646]  ? copy_msghdr_from_user+0x460/0x460
[  284.199659]  ? ___sys_sendmsg+0xcc0/0xcc0
[  284.199692]  ? handle_mm_fault+0x348/0xa70
[  284.199707]  ? downgrade_write+0x180/0x180
[  284.199721]  ? fget_raw+0x10/0x10
[  284.199743]  ? __do_page_fault+0x554/0xd30
[  284.199764]  ? bad_area_access_error+0x280/0x280
[  284.199786]  ? __sys_sendmsg+0xb8/0x210
[  284.199797]  __sys_sendmsg+0xb8/0x210
[  284.199811]  ? SyS_shutdown+0x290/0x290
[  284.199824]  ? rcu_read_lock_sched_held+0x114/0x130
[  284.199835]  ? kmem_cache_free+0x3e9/0x5a0
[  284.199855]  ? do_sys_open+0x24d/0x660
[  284.199878]  ? trace_hardirqs_on_thunk+0x1a/0x1c
[  284.199900]  entry_SYSCALL_64_fastpath+0x1c/0x89
[  284.199912] RIP: 0033:0x7fd870caa450
[  284.199921] RSP: 002b:00007ffdf1bec428 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
[  284.199941] RAX: ffffffffffffffda RBX: 00007fd870f66b20 RCX: 00007fd870caa450
[  284.199950] RDX: 0000000000000000 RSI: 00007ffdf1bec480 RDI: 0000000000000003
[  284.199960] RBP: 0000000000000a11 R08: 0000000000000000 R09: 000000000000000f
[  284.199969] R10: 00000000000005e7 R11: 0000000000000246 R12: 00007fd870f66b78
[  284.199979] R13: 00007fd870f66b78 R14: 000000000000270f R15: 00007fd870f66b78

[  284.201768] Allocated by task 1640:
[  284.205766]  kasan_kmalloc+0xa0/0xd0
[  284.205777]  kmem_cache_alloc_trace+0x1ad/0x5b0
[  284.205786]  tcf_block_get_ext+0xb0/0x790
[  284.205797]  ingress_init+0x122/0x200 [sch_ingress]
[  284.205807]  qdisc_create+0x2c1/0xff0
[  284.205817]  tc_modify_qdisc+0x49f/0x1870
[  284.205827]  rtnetlink_rcv_msg+0x555/0xb80
[  284.205837]  netlink_rcv_skb+0x210/0x4a0
[  284.205847]  netlink_unicast+0x435/0x660
[  284.205857]  netlink_sendmsg+0x9b4/0x1060
[  284.205868]  sock_sendmsg+0xd9/0x160
[  284.205878]  ___sys_sendmsg+0x72d/0xcc0
[  284.205887]  __sys_sendmsg+0xb8/0x210
[  284.205898]  entry_SYSCALL_64_fastpath+0x1c/0x89

[  284.207664] Freed by task 1652:
[  284.211272]  kasan_slab_free+0x71/0xc0
[  284.211282]  kfree+0x120/0x580
[  284.211292]  tcf_chain_destroy+0x29b/0x3d0
[  284.211302]  tcf_block_put_ext+0x3ef/0x5e0
[  284.211312]  ingress_destroy+0x47/0x80 [sch_ingress]
[  284.211322]  qdisc_destroy+0x141/0x430
[  284.211332]  qdisc_graft+0x315/0xcd0
[  284.211342]  tc_get_qdisc+0x3d5/0xad0
[  284.211352]  rtnetlink_rcv_msg+0x555/0xb80
[  284.211362]  netlink_rcv_skb+0x210/0x4a0
[  284.211372]  netlink_unicast+0x435/0x660
[  284.211382]  netlink_sendmsg+0x9b4/0x1060
[  284.211392]  sock_sendmsg+0xd9/0x160
[  284.211403]  ___sys_sendmsg+0x72d/0xcc0
[  284.211412]  __sys_sendmsg+0xb8/0x210
[  284.211423]  entry_SYSCALL_64_fastpath+0x1c/0x89

[  284.213190] The buggy address belongs to the object at ffff8803152f4d08
                which belongs to the cache kmalloc-64 of size 64
[  284.227124] The buggy address is located 0 bytes inside of
                64-byte region [ffff8803152f4d08, ffff8803152f4d48)
[  284.240083] The buggy address belongs to the page:
[  284.245542] page:000000001aa42e32 count:1 mapcount:0 mapping:          (null) index:0x0 compound_mapcount: 0
[  284.256662] flags: 0x2ffff0000008100(slab|head)
[  284.261830] raw: 02ffff0000008100 0000000000000000 0000000000000000 0000000100270027
[  284.270600] raw: ffffea000d7a7020 ffff88036e400778 ffff88036e4173c0 0000000000000000
[  284.279410] page dumped because: kasan: bad access detected

[  284.287543] Memory state around the buggy address:
[  284.293022]  ffff8803152f4c00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[  284.301247]  ffff8803152f4c80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[  284.309473] >ffff8803152f4d00: fc fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc
[  284.317697]                       ^
[  284.321714]  ffff8803152f4d80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[  284.329941]  ffff8803152f4e00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[  284.338166] ==================================================================

^ permalink raw reply

* Re: BUG: KASAN: use-after-free in tcf_block_put_ext+0x5cf/0x5e0
From: Jakub Kicinski @ 2017-12-08  4:59 UTC (permalink / raw)
  To: Cong Wang; +Cc: Roman Kapl, netdev@vger.kernel.org, Jiri Pirko
In-Reply-To: <20171207205127.0eec5947@cakuba.netronome.com>

On Thu, 7 Dec 2017 20:51:27 -0800, Jakub Kicinski wrote:
> Running the netdevsim test after a week and a bit of not trying it:
> 
> $ make -C tools/testing/selftests/bpf/ CLANG=clang LLC=llc
> # ./tools/testing/selftests/bpf/test_offload.py

Ah, I didn't clarify - this is net-next at 66c5c5b56682 ("Merge branch
'smc-fixes-next'") plus some BPF-related commits.

^ permalink raw reply

* Re: [PATCH v2 06/35] nds32: MMU fault handling and page table management
From: Greentime Hu @ 2017-12-08  5:26 UTC (permalink / raw)
  To: Al Viro
  Cc: Greentime, Linux Kernel Mailing List, Arnd Bergmann, linux-arch,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Rob Herring, netdev,
	Vincent Chen, DTML, David Howells, Will Deacon, Daniel Lezcano,
	linux-serial-u79uwXL29TY76Z2rM5mHXA, Vincent Chen
In-Reply-To: <20171207164040.GD21978-3bDd1+5oDREiFSDQTTA3OLVCufUGDwFn@public.gmane.org>

2017-12-08 0:40 GMT+08:00 Al Viro <viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn@public.gmane.org>:
> On Mon, Nov 27, 2017 at 08:27:53PM +0800, Greentime Hu wrote:
>> +void do_page_fault(unsigned long entry, unsigned long addr,
>> +                unsigned int error_code, struct pt_regs *regs)
> [snip]
>> +     /*
>> +      * If we're in an interrupt or have no user
>> +      * context, we must not take the fault..
>> +      */
>> +     if (unlikely(in_atomic() || !mm))
>
> Broken.  in_atomic() is wrong here - it should be faulthandler_disabled().

Thanks.
I will include <linux/uaccess.h> and replace in_atomic() with
faulthandler_disabled()
I will fix it in the next version patch.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2 08/35] nds32: Process management
From: Greentime Hu @ 2017-12-08  5:27 UTC (permalink / raw)
  To: Al Viro
  Cc: Greentime, Linux Kernel Mailing List, Arnd Bergmann, linux-arch,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Rob Herring, netdev,
	Vincent Chen, DTML, David Howells, Will Deacon, Daniel Lezcano,
	linux-serial, Vincent Chen
In-Reply-To: <20171207164506.GE21978@ZenIV.linux.org.uk>

2017-12-08 0:45 GMT+08:00 Al Viro <viro@zeniv.linux.org.uk>:
> On Mon, Nov 27, 2017 at 08:27:55PM +0800, Greentime Hu wrote:
>
>> +#define start_thread(regs,pc,stack)                  \
>> +({                                                   \
>> +     set_fs(USER_DS);                                \
>
> Not the job of start_thread() - its users (->load_binary() methods of
> assorted binfmt) must (and do) call flush_old_exec() first.  And
> that will switch to USER_DS just fine.

Thanks. I will remove this setting in the next version patch.

^ permalink raw reply

* Re: [PATCH v5 2/2] sock: Move the socket inuse to namespace.
From: Tonghao Zhang @ 2017-12-08  5:28 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David Miller, Cong Wang, Eric Dumazet, Willem de Bruijn,
	Linux Kernel Network Developers
In-Reply-To: <1512667208.25033.13.camel@gmail.com>

On Fri, Dec 8, 2017 at 1:20 AM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> On Thu, 2017-12-07 at 08:45 -0800, Tonghao Zhang wrote:
>> In some case, we want to know how many sockets are in use in
>> different _net_ namespaces. It's a key resource metric.
>>
>
> ...
>
>> +static void sock_inuse_add(struct net *net, int val)
>> +{
>> +     if (net->core.prot_inuse)
>> +             this_cpu_add(*net->core.sock_inuse, val);
>> +}
>
> This is very confusing.
>
> Why testing net->core.prot_inuse for NULL is needed at all ?
>
> Why not testing net->core.sock_inuse instead ?
>
Hi Eric and Cong, oh it's a typo. it's net->core.sock_inuse there. Why
we should check the net->core.sock_inuse
Now show you the code:

cleanup_net will call all of the network namespace exit methods,
rcu_barrier, and then remove the _net_ namespace.

cleanup_net:
    list_for_each_entry_reverse(ops, &pernet_list, list)
         ops_exit_list(ops, &net_exit_list);

    rcu_barrier(); /* for netlink sock, the ‘deferred_put_nlk_sk’ will
be called. But sock_inuse has been released. */


    /* Finally it is safe to free my network namespace structure */
    list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {}



Release the netlink sock created in kernel(not hold the _net_ namespace):

netlink_release
       call_rcu(&nlk->rcu, deferred_put_nlk_sk);

deferred_put_nlk_sk
       sk_free(sk);


I may add a comment for sock_inuse_add in v6.

^ permalink raw reply


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