Home Home > GIT Browse > vanilla
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2017-12-01 16:22:36 +0100
committerJiri Kosina <jkosina@suse.cz>2017-12-01 16:22:36 +0100
commit97f8750d5a29e02c7038c1d80426b1b59a1df2be (patch)
treeadf8346d944026d88f71eff07f118505b3bbcf88
parent9915372e67fe38327b2bc03a87f7408d06cedfea (diff)
parent20cef465c6195e02be63a6b3c8eee87396fa064c (diff)
Merge remote-tracking branch 'origin/users/tbogendoerfer/SLE15/for-next' into SLE15
Conflicts: series.conf
-rw-r--r--patches.drivers/IB-cxgb3-cxgb4-Remove-unneeded-config-dependencies.patch38
-rw-r--r--patches.drivers/RDMA-cxgb4-Annotate-r2-and-stag-as-__be32.patch42
-rw-r--r--patches.drivers/RDMA-cxgb4-Declare-stag-as-__be32.patch31
-rw-r--r--patches.drivers/RDMA-cxgb4-Fix-indentation.patch71
-rw-r--r--patches.drivers/RDMA-cxgb4-Protect-from-possible-dereference.patch32
-rw-r--r--patches.drivers/RDMA-cxgb4-Remove-a-set-but-not-used-variable.patch40
-rw-r--r--patches.drivers/RDMA-cxgb4-Remove-the-obsolete-kernel-module-option-.patch32
-rw-r--r--patches.drivers/RDMA-cxgb4-Suppress-gcc-7-fall-through-complaints.patch29
-rw-r--r--patches.drivers/cxgb3-Check-and-handle-the-dma-mapping-errors.patch268
-rw-r--r--patches.drivers/cxgb4-Add-support-for-new-flash-parts.patch195
-rw-r--r--patches.drivers/cxgb4-Update-comment-for-min_mtu.patch30
-rw-r--r--patches.drivers/cxgb4-add-basic-tc-flower-offload-support.patch426
-rw-r--r--patches.drivers/cxgb4-add-support-to-create-hash-filters-via-tc-flow.patch227
-rw-r--r--patches.drivers/cxgb4-add-support-to-create-hash-filters.patch773
-rw-r--r--patches.drivers/cxgb4-add-support-to-delete-hash-filter.patch325
-rw-r--r--patches.drivers/cxgb4-add-support-to-offload-action-vlan.patch84
-rw-r--r--patches.drivers/cxgb4-add-support-to-retrieve-stats-for-hash-filters.patch113
-rw-r--r--patches.drivers/cxgb4-add-tc-flower-match-support-for-TOS.patch95
-rw-r--r--patches.drivers/cxgb4-add-tc-flower-match-support-for-vlan.patch70
-rw-r--r--patches.drivers/cxgb4-add-tc-flower-offload-skeleton.patch190
-rw-r--r--patches.drivers/cxgb4-add-tc-flower-support-for-ETH-DMAC-rewrite.patch214
-rw-r--r--patches.drivers/cxgb4-add-tc-flower-support-for-ETH-SMAC-rewrite.patch71
-rw-r--r--patches.drivers/cxgb4-add-tc-flower-support-for-L3-L4-rewrite.patch396
-rw-r--r--patches.drivers/cxgb4-add-tc-flower-support-for-action-PASS.patch42
-rw-r--r--patches.drivers/cxgb4-avoid-stall-while-shutting-down-the-adapter.patch73
-rw-r--r--patches.drivers/cxgb4-collect-CIM-queue-configuration-dump.patch127
-rw-r--r--patches.drivers/cxgb4-collect-IBQ-and-OBQ-dumps.patch327
-rw-r--r--patches.drivers/cxgb4-collect-LE-TCAM-dump.patch373
-rw-r--r--patches.drivers/cxgb4-collect-MPS-TCAM-dump.patch318
-rw-r--r--patches.drivers/cxgb4-collect-PBT-tables-dump.patch162
-rw-r--r--patches.drivers/cxgb4-collect-RSS-dumps.patch141
-rw-r--r--patches.drivers/cxgb4-collect-SGE-queue-context-dump.patch329
-rw-r--r--patches.drivers/cxgb4-collect-TID-info-dump.patch254
-rw-r--r--patches.drivers/cxgb4-collect-TP-dump.patch345
-rw-r--r--patches.drivers/cxgb4-collect-firmware-mbox-and-device-log-dump.patch206
-rw-r--r--patches.drivers/cxgb4-collect-hardware-LA-dumps.patch400
-rw-r--r--patches.drivers/cxgb4-collect-hardware-misc-dumps.patch365
-rw-r--r--patches.drivers/cxgb4-collect-hardware-module-dumps.patch505
-rw-r--r--patches.drivers/cxgb4-collect-hardware-scheduler-dumps.patch253
-rw-r--r--patches.drivers/cxgb4-collect-on-chip-memory-dump.patch359
-rw-r--r--patches.drivers/cxgb4-collect-register-dump.patch383
-rw-r--r--patches.drivers/cxgb4-collect-vpd-info-directly-from-hardware.patch241
-rw-r--r--patches.drivers/cxgb4-do-DCB-state-reset-in-couple-of-places.patch97
-rw-r--r--patches.drivers/cxgb4-fetch-stats-for-offloaded-tc-flower-flows.patch268
-rw-r--r--patches.drivers/cxgb4-fix-error-return-code-in-cxgb4_set_hash_filter.patch33
-rw-r--r--patches.drivers/cxgb4-fix-missing-break-in-switch-and-indent-return-.patch53
-rw-r--r--patches.drivers/cxgb4-fix-overflow-in-collecting-IBQ-and-OBQ-dump.patch120
-rw-r--r--patches.drivers/cxgb4-implement-ethtool-dump-data-operations.patch366
-rw-r--r--patches.drivers/cxgb4-initialize-hash-filter-configuration.patch152
-rw-r--r--patches.drivers/cxgb4-introduce-SMT-ops-to-prepare-for-SMAC-rewrite-.patch717
-rw-r--r--patches.drivers/cxgb4-introduce-fw_filter2_wr-to-prepare-for-L3-L4-r.patch219
-rw-r--r--patches.drivers/cxgb4-make-function-ch_flower_stats_cb-fixes-warning.patch31
-rw-r--r--patches.drivers/cxgb4-save-additional-filter-tuple-field-shifts-in-t.patch96
-rw-r--r--patches.drivers/cxgb4-update-API-for-TP-indirect-register-access.patch716
-rw-r--r--patches.drivers/cxgb4vf-define-get_fecparam-ethtool-callback.patch92
-rw-r--r--patches.drivers/cxgb4vf-make-a-couple-of-functions-static.patch44
-rw-r--r--patches.drivers/iw_cxgb4-Fix-possible-circular-dependency-locking-wa.patch211
-rw-r--r--patches.drivers/iw_cxgb4-Remove-__func__-parameter-from-pr_debug.patch1673
-rw-r--r--patches.drivers/iw_cxgb4-add-referencing-to-wait-objects.patch544
-rw-r--r--patches.drivers/iw_cxgb4-allocate-wait-object-for-each-cq-object.patch211
-rw-r--r--patches.drivers/iw_cxgb4-allocate-wait-object-for-each-ep-object.patch215
-rw-r--r--patches.drivers/iw_cxgb4-allocate-wait-object-for-each-memory-object.patch583
-rw-r--r--patches.drivers/iw_cxgb4-allocate-wait-object-for-each-qp-object.patch191
-rw-r--r--patches.drivers/iw_cxgb4-atomically-flush-the-qp.patch76
-rw-r--r--patches.drivers/iw_cxgb4-change-pr_debug-to-appropriate-log-level.patch233
-rw-r--r--patches.drivers/iw_cxgb4-only-call-the-cq-comp_handler-when-the-cq-i.patch71
-rw-r--r--patches.drivers/iw_cxgb4-remove-BUG_ON-usage.patch341
-rw-r--r--patches.drivers/net-sched-add-couple-of-goto_chain-helpers.patch64
-rw-r--r--patches.drivers/net-sched-introduce-helper-to-identify-gact-pass-act.patch31
-rw-r--r--patches.drivers/net-sched-introduce-helper-to-identify-gact-trap-act.patch52
-rw-r--r--series.conf70
71 files changed, 16565 insertions, 0 deletions
diff --git a/patches.drivers/IB-cxgb3-cxgb4-Remove-unneeded-config-dependencies.patch b/patches.drivers/IB-cxgb3-cxgb4-Remove-unneeded-config-dependencies.patch
new file mode 100644
index 0000000000..464a205530
--- /dev/null
+++ b/patches.drivers/IB-cxgb3-cxgb4-Remove-unneeded-config-dependencies.patch
@@ -0,0 +1,38 @@
+From: Yuval Shaia <yuval.shaia@oracle.com>
+Date: Wed, 6 Sep 2017 13:52:01 +0300
+Subject: IB/{cxgb3,cxgb4}: Remove unneeded config dependencies
+Patch-mainline: v4.15-rc1
+Git-commit: be92d4891f89cb08f8a7cfc268b211c8e1253497
+References: bsc#1064802 bsc#1066129
+
+CHELSIO_T3 already depend on INET
+CHELSIO_T4 already depend on (IPV6 || IPV6=n)
+
+Signed-off-by: Yuval Shaia <yuval.shaia@oracle.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb3/Kconfig | 2 +-
+ drivers/infiniband/hw/cxgb4/Kconfig | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb3/Kconfig
++++ b/drivers/infiniband/hw/cxgb3/Kconfig
+@@ -1,6 +1,6 @@
+ config INFINIBAND_CXGB3
+ tristate "Chelsio RDMA Driver"
+- depends on CHELSIO_T3 && INET
++ depends on CHELSIO_T3
+ select GENERIC_ALLOCATOR
+ ---help---
+ This is an iWARP/RDMA driver for the Chelsio T3 1GbE and
+--- a/drivers/infiniband/hw/cxgb4/Kconfig
++++ b/drivers/infiniband/hw/cxgb4/Kconfig
+@@ -1,6 +1,6 @@
+ config INFINIBAND_CXGB4
+ tristate "Chelsio T4/T5 RDMA Driver"
+- depends on CHELSIO_T4 && INET && (IPV6 || IPV6=n)
++ depends on CHELSIO_T4 && INET
+ select CHELSIO_LIB
+ select GENERIC_ALLOCATOR
+ ---help---
diff --git a/patches.drivers/RDMA-cxgb4-Annotate-r2-and-stag-as-__be32.patch b/patches.drivers/RDMA-cxgb4-Annotate-r2-and-stag-as-__be32.patch
new file mode 100644
index 0000000000..9172f7e688
--- /dev/null
+++ b/patches.drivers/RDMA-cxgb4-Annotate-r2-and-stag-as-__be32.patch
@@ -0,0 +1,42 @@
+From: Leon Romanovsky <leon@kernel.org>
+Date: Wed, 25 Oct 2017 23:10:19 +0300
+Subject: RDMA/cxgb4: Annotate r2 and stag as __be32
+Patch-mainline: v4.15-rc1
+Git-commit: 7d7d065a5eec7e218174d5c64a9f53f99ffdb119
+References: bsc#1064802 bsc#1066129
+
+Chelsio cxgb4 HW is big-endian, hence there is need to properly
+annotate r2 and stag fields as __be32 and not __u32 to fix the
+following sparse warnings.
+
+ drivers/infiniband/hw/cxgb4/qp.c:614:16:
+ warning: incorrect type in assignment (different base types)
+ expected unsigned int [unsigned] [usertype] r2
+ got restricted __be32 [usertype] <noident>
+ drivers/infiniband/hw/cxgb4/qp.c:615:18:
+ warning: incorrect type in assignment (different base types)
+ expected unsigned int [unsigned] [usertype] stag
+ got restricted __be32 [usertype] <noident>
+
+Cc: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Reviewed-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/t4fw_ri_api.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
++++ b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
+@@ -675,8 +675,8 @@ struct fw_ri_fr_nsmr_tpte_wr {
+ __u16 wrid;
+ __u8 r1[3];
+ __u8 len16;
+- __u32 r2;
+- __u32 stag;
++ __be32 r2;
++ __be32 stag;
+ struct fw_ri_tpte tpte;
+ __u64 pbl[2];
+ };
diff --git a/patches.drivers/RDMA-cxgb4-Declare-stag-as-__be32.patch b/patches.drivers/RDMA-cxgb4-Declare-stag-as-__be32.patch
new file mode 100644
index 0000000000..5ffd3bfbb2
--- /dev/null
+++ b/patches.drivers/RDMA-cxgb4-Declare-stag-as-__be32.patch
@@ -0,0 +1,31 @@
+From: Leon Romanovsky <leon@kernel.org>
+Date: Wed, 25 Oct 2017 07:41:11 +0300
+Subject: RDMA/cxgb4: Declare stag as __be32
+Patch-mainline: v4.15-rc1
+Git-commit: 35fb2a88ed4b77356fa679a8525c869a3594e287
+References: bsc#1064802 bsc#1066129
+
+The scqe.stag is actually __b32, fix it.
+
+ drivers/infiniband/hw/cxgb4/cq.c:754:52: warning: cast to restricted __be32
+
+Cc: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Reviewed-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/t4.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/infiniband/hw/cxgb4/t4.h
++++ b/drivers/infiniband/hw/cxgb4/t4.h
+@@ -171,7 +171,7 @@ struct t4_cqe {
+ __be32 msn;
+ } rcqe;
+ struct {
+- u32 stag;
++ __be32 stag;
+ u16 nada2;
+ u16 cidx;
+ } scqe;
diff --git a/patches.drivers/RDMA-cxgb4-Fix-indentation.patch b/patches.drivers/RDMA-cxgb4-Fix-indentation.patch
new file mode 100644
index 0000000000..92d530a884
--- /dev/null
+++ b/patches.drivers/RDMA-cxgb4-Fix-indentation.patch
@@ -0,0 +1,71 @@
+From: Bart Van Assche <bart.vanassche@wdc.com>
+Date: Wed, 11 Oct 2017 10:48:53 -0700
+Subject: RDMA/cxgb4: Fix indentation
+Patch-mainline: v4.15-rc1
+Git-commit: 70d7256819639e2b0c0425a50bbbb9e9fd9e9286
+References: bsc#1064802 bsc#1066129
+
+This patch avoids that smatch reports the following:
+
+drivers/infiniband/hw/cxgb4/device.c:1105: copy_gl_to_skb_pkt() warn: inconsistent indenting
+drivers/infiniband/hw/cxgb4/cm.c:835: send_connect() warn: inconsistent indenting
+drivers/infiniband/hw/cxgb4/cm.c:841: send_connect() warn: inconsistent indenting
+drivers/infiniband/hw/cxgb4/cm.c:888: send_connect() warn: inconsistent indenting
+drivers/infiniband/hw/cxgb4/cm.c:894: send_connect() warn: inconsistent indenting
+
+Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
+Reviewed-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 8 ++++----
+ drivers/infiniband/hw/cxgb4/device.c | 4 ++--
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -832,13 +832,13 @@ static int send_connect(struct c4iw_ep *
+ t5req->params =
+ cpu_to_be64(FILTER_TUPLE_V(params));
+ t5req->rsvd = cpu_to_be32(isn);
+- pr_debug("snd_isn %u\n", t5req->rsvd);
++ pr_debug("snd_isn %u\n", t5req->rsvd);
+ t5req->opt2 = cpu_to_be32(opt2);
+ } else {
+ t6req->params =
+ cpu_to_be64(FILTER_TUPLE_V(params));
+ t6req->rsvd = cpu_to_be32(isn);
+- pr_debug("snd_isn %u\n", t6req->rsvd);
++ pr_debug("snd_isn %u\n", t6req->rsvd);
+ t6req->opt2 = cpu_to_be32(opt2);
+ }
+ }
+@@ -885,13 +885,13 @@ static int send_connect(struct c4iw_ep *
+ t5req6->params =
+ cpu_to_be64(FILTER_TUPLE_V(params));
+ t5req6->rsvd = cpu_to_be32(isn);
+- pr_debug("snd_isn %u\n", t5req6->rsvd);
++ pr_debug("snd_isn %u\n", t5req6->rsvd);
+ t5req6->opt2 = cpu_to_be32(opt2);
+ } else {
+ t6req6->params =
+ cpu_to_be64(FILTER_TUPLE_V(params));
+ t6req6->rsvd = cpu_to_be32(isn);
+- pr_debug("snd_isn %u\n", t6req6->rsvd);
++ pr_debug("snd_isn %u\n", t6req6->rsvd);
+ t6req6->opt2 = cpu_to_be32(opt2);
+ }
+
+--- a/drivers/infiniband/hw/cxgb4/device.c
++++ b/drivers/infiniband/hw/cxgb4/device.c
+@@ -1102,8 +1102,8 @@ static inline struct sk_buff *copy_gl_to
+ if (unlikely(!skb))
+ return NULL;
+
+- __skb_put(skb, gl->tot_len + sizeof(struct cpl_pass_accept_req) +
+- sizeof(struct rss_header) - pktshift);
++ __skb_put(skb, gl->tot_len + sizeof(struct cpl_pass_accept_req) +
++ sizeof(struct rss_header) - pktshift);
+
+ /*
+ * This skb will contain:
diff --git a/patches.drivers/RDMA-cxgb4-Protect-from-possible-dereference.patch b/patches.drivers/RDMA-cxgb4-Protect-from-possible-dereference.patch
new file mode 100644
index 0000000000..6dcf32d590
--- /dev/null
+++ b/patches.drivers/RDMA-cxgb4-Protect-from-possible-dereference.patch
@@ -0,0 +1,32 @@
+From: Leon Romanovsky <leon@kernel.org>
+Date: Sun, 29 Oct 2017 21:34:35 +0200
+Subject: RDMA/cxgb4: Protect from possible dereference
+Patch-mainline: v4.15-rc1
+Git-commit: 9950acf945f55222385d85489617e1d81e45fe34
+References: bsc#1064802 bsc#1066129
+
+Smatch tool reports the following error:
+ drivers/infiniband/hw/cxgb4/qp.c:1886
+ c4iw_create_qp() error: we previously assumed 'ucontext'
+ could be null (see line 1804)
+
+Cc: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Reviewed-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/qp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/infiniband/hw/cxgb4/qp.c
++++ b/drivers/infiniband/hw/cxgb4/qp.c
+@@ -1843,7 +1843,7 @@ struct ib_qp *c4iw_create_qp(struct ib_p
+ if (ret)
+ goto err_destroy_qp;
+
+- if (udata) {
++ if (udata && ucontext) {
+ sq_key_mm = kmalloc(sizeof(*sq_key_mm), GFP_KERNEL);
+ if (!sq_key_mm) {
+ ret = -ENOMEM;
diff --git a/patches.drivers/RDMA-cxgb4-Remove-a-set-but-not-used-variable.patch b/patches.drivers/RDMA-cxgb4-Remove-a-set-but-not-used-variable.patch
new file mode 100644
index 0000000000..fcde128f31
--- /dev/null
+++ b/patches.drivers/RDMA-cxgb4-Remove-a-set-but-not-used-variable.patch
@@ -0,0 +1,40 @@
+From: Bart Van Assche <bart.vanassche@wdc.com>
+Date: Wed, 11 Oct 2017 10:48:56 -0700
+Subject: RDMA/cxgb4: Remove a set-but-not-used variable
+Patch-mainline: v4.15-rc1
+Git-commit: 81e74ec286135927df6b360b3cea61764da4fdb9
+References: bsc#1064802 bsc#1066129
+
+Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
+Reviewed-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -3877,7 +3877,6 @@ static int rx_pkt(struct c4iw_dev *dev,
+ struct net_device *pdev;
+ u16 rss_qid, eth_hdr_len;
+ int step;
+- u32 tx_chan;
+ struct neighbour *neigh;
+
+ /* Drop all non-SYN packets */
+@@ -3959,14 +3958,12 @@ static int rx_pkt(struct c4iw_dev *dev,
+ e = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh,
+ pdev, 0);
+ pi = (struct port_info *)netdev_priv(pdev);
+- tx_chan = cxgb4_port_chan(pdev);
+ dev_put(pdev);
+ } else {
+ pdev = get_real_dev(neigh->dev);
+ e = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh,
+ pdev, 0);
+ pi = (struct port_info *)netdev_priv(pdev);
+- tx_chan = cxgb4_port_chan(pdev);
+ }
+ neigh_release(neigh);
+ if (!e) {
diff --git a/patches.drivers/RDMA-cxgb4-Remove-the-obsolete-kernel-module-option-.patch b/patches.drivers/RDMA-cxgb4-Remove-the-obsolete-kernel-module-option-.patch
new file mode 100644
index 0000000000..07e97440e7
--- /dev/null
+++ b/patches.drivers/RDMA-cxgb4-Remove-the-obsolete-kernel-module-option-.patch
@@ -0,0 +1,32 @@
+From: Bart Van Assche <bart.vanassche@wdc.com>
+Date: Wed, 11 Oct 2017 10:48:54 -0700
+Subject: RDMA/cxgb4: Remove the obsolete kernel module option 'c4iw_debug'
+Patch-mainline: v4.15-rc1
+Git-commit: 76ca0d1b16233b0d7c03aadaafc56931d095b79c
+References: bsc#1064802 bsc#1066129
+
+This patch avoids that building the cxgb4 module with W=1 triggers
+a complaint about a local variable that has not been declared static.
+
+Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
+Cc: Steve Wise <swise@opengridcomputing.com>
+Acked-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -99,10 +99,6 @@ module_param(enable_tcp_window_scaling,
+ MODULE_PARM_DESC(enable_tcp_window_scaling,
+ "Enable tcp window scaling (default=1)");
+
+-int c4iw_debug;
+-module_param(c4iw_debug, int, 0644);
+-MODULE_PARM_DESC(c4iw_debug, "obsolete");
+-
+ static int peer2peer = 1;
+ module_param(peer2peer, int, 0644);
+ MODULE_PARM_DESC(peer2peer, "Support peer2peer ULPs (default=1)");
diff --git a/patches.drivers/RDMA-cxgb4-Suppress-gcc-7-fall-through-complaints.patch b/patches.drivers/RDMA-cxgb4-Suppress-gcc-7-fall-through-complaints.patch
new file mode 100644
index 0000000000..17dc014141
--- /dev/null
+++ b/patches.drivers/RDMA-cxgb4-Suppress-gcc-7-fall-through-complaints.patch
@@ -0,0 +1,29 @@
+From: Bart Van Assche <bart.vanassche@wdc.com>
+Date: Wed, 11 Oct 2017 10:48:55 -0700
+Subject: RDMA/cxgb4: Suppress gcc 7 fall-through complaints
+Patch-mainline: v4.15-rc1
+Git-commit: 9ae970e27729e976598584a9427e8f8705efa585
+References: bsc#1064802 bsc#1066129
+
+Avoid that gcc 7 reports the following warning when building with W=1:
+
+warning: this statement may fall through [-Wimplicit-fallthrough=]
+
+Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
+Reviewed-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -3638,6 +3638,7 @@ static void active_ofld_conn_reply(struc
+ send_fw_act_open_req(ep, atid);
+ return;
+ }
++ /* fall through */
+ case FW_EADDRINUSE:
+ set_bit(ACT_RETRY_INUSE, &ep->com.history);
+ if (ep->retry_count++ < ACT_OPEN_RETRY_COUNT) {
diff --git a/patches.drivers/cxgb3-Check-and-handle-the-dma-mapping-errors.patch b/patches.drivers/cxgb3-Check-and-handle-the-dma-mapping-errors.patch
new file mode 100644
index 0000000000..388e73f1d3
--- /dev/null
+++ b/patches.drivers/cxgb3-Check-and-handle-the-dma-mapping-errors.patch
@@ -0,0 +1,268 @@
+From: Arjun Vynipadath <arjun@chelsio.com>
+Date: Fri, 27 Oct 2017 18:08:21 +0530
+Subject: cxgb3: Check and handle the dma mapping errors
+Patch-mainline: v4.15-rc1
+Git-commit: c69fe407803d4b554b7397fad9598a04717ac255
+References: bsc#1064802 bsc#1066129
+
+This patch adds checks at approprate places whether *dma_map*() call has
+succeeded or not.
+
+Original Work by: Santosh Rastapur <santosh@chelsio.com>
+Signed-off-by: Arjun Vynipadath <arjun@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb3/sge.c | 118 ++++++++++++++++++++++++-------
+ 1 file changed, 92 insertions(+), 26 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb3/sge.c
++++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c
+@@ -455,6 +455,11 @@ static int alloc_pg_chunk(struct adapter
+ q->pg_chunk.offset = 0;
+ mapping = pci_map_page(adapter->pdev, q->pg_chunk.page,
+ 0, q->alloc_size, PCI_DMA_FROMDEVICE);
++ if (unlikely(pci_dma_mapping_error(adapter->pdev, mapping))) {
++ __free_pages(q->pg_chunk.page, order);
++ q->pg_chunk.page = NULL;
++ return -EIO;
++ }
+ q->pg_chunk.mapping = mapping;
+ }
+ sd->pg_chunk = q->pg_chunk;
+@@ -949,40 +954,78 @@ static inline unsigned int calc_tx_descs
+ return flits_to_desc(flits);
+ }
+
++/* map_skb - map a packet main body and its page fragments
++ * @pdev: the PCI device
++ * @skb: the packet
++ * @addr: placeholder to save the mapped addresses
++ *
++ * map the main body of an sk_buff and its page fragments, if any.
++ */
++static int map_skb(struct pci_dev *pdev, const struct sk_buff *skb,
++ dma_addr_t *addr)
++{
++ const skb_frag_t *fp, *end;
++ const struct skb_shared_info *si;
++
++ if (skb_headlen(skb)) {
++ *addr = pci_map_single(pdev, skb->data, skb_headlen(skb),
++ PCI_DMA_TODEVICE);
++ if (pci_dma_mapping_error(pdev, *addr))
++ goto out_err;
++ addr++;
++ }
++
++ si = skb_shinfo(skb);
++ end = &si->frags[si->nr_frags];
++
++ for (fp = si->frags; fp < end; fp++) {
++ *addr = skb_frag_dma_map(&pdev->dev, fp, 0, skb_frag_size(fp),
++ DMA_TO_DEVICE);
++ if (pci_dma_mapping_error(pdev, *addr))
++ goto unwind;
++ addr++;
++ }
++ return 0;
++
++unwind:
++ while (fp-- > si->frags)
++ dma_unmap_page(&pdev->dev, *--addr, skb_frag_size(fp),
++ DMA_TO_DEVICE);
++
++ pci_unmap_single(pdev, addr[-1], skb_headlen(skb), PCI_DMA_TODEVICE);
++out_err:
++ return -ENOMEM;
++}
++
+ /**
+- * make_sgl - populate a scatter/gather list for a packet
++ * write_sgl - populate a scatter/gather list for a packet
+ * @skb: the packet
+ * @sgp: the SGL to populate
+ * @start: start address of skb main body data to include in the SGL
+ * @len: length of skb main body data to include in the SGL
+- * @pdev: the PCI device
++ * @addr: the list of the mapped addresses
+ *
+- * Generates a scatter/gather list for the buffers that make up a packet
++ * Copies the scatter/gather list for the buffers that make up a packet
+ * and returns the SGL size in 8-byte words. The caller must size the SGL
+ * appropriately.
+ */
+-static inline unsigned int make_sgl(const struct sk_buff *skb,
+- struct sg_ent *sgp, unsigned char *start,
+- unsigned int len, struct pci_dev *pdev)
++static inline unsigned int write_sgl(const struct sk_buff *skb,
++ struct sg_ent *sgp, unsigned char *start,
++ unsigned int len, const dma_addr_t *addr)
+ {
+- dma_addr_t mapping;
+- unsigned int i, j = 0, nfrags;
++ unsigned int i, j = 0, k = 0, nfrags;
+
+ if (len) {
+- mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE);
+ sgp->len[0] = cpu_to_be32(len);
+- sgp->addr[0] = cpu_to_be64(mapping);
+- j = 1;
++ sgp->addr[j++] = cpu_to_be64(addr[k++]);
+ }
+
+ nfrags = skb_shinfo(skb)->nr_frags;
+ for (i = 0; i < nfrags; i++) {
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+- mapping = skb_frag_dma_map(&pdev->dev, frag, 0, skb_frag_size(frag),
+- DMA_TO_DEVICE);
+ sgp->len[j] = cpu_to_be32(skb_frag_size(frag));
+- sgp->addr[j] = cpu_to_be64(mapping);
++ sgp->addr[j] = cpu_to_be64(addr[k++]);
+ j ^= 1;
+ if (j == 0)
+ ++sgp;
+@@ -1138,7 +1181,7 @@ static void write_tx_pkt_wr(struct adapt
+ const struct port_info *pi,
+ unsigned int pidx, unsigned int gen,
+ struct sge_txq *q, unsigned int ndesc,
+- unsigned int compl)
++ unsigned int compl, const dma_addr_t *addr)
+ {
+ unsigned int flits, sgl_flits, cntrl, tso_info;
+ struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1];
+@@ -1196,7 +1239,7 @@ static void write_tx_pkt_wr(struct adapt
+ }
+
+ sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
+- sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev);
++ sgl_flits = write_sgl(skb, sgp, skb->data, skb_headlen(skb), addr);
+
+ write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen,
+ htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl),
+@@ -1227,6 +1270,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *
+ struct netdev_queue *txq;
+ struct sge_qset *qs;
+ struct sge_txq *q;
++ dma_addr_t addr[MAX_SKB_FRAGS + 1];
+
+ /*
+ * The chip min packet length is 9 octets but play safe and reject
+@@ -1255,6 +1299,14 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *
+ return NETDEV_TX_BUSY;
+ }
+
++ /* Check if ethernet packet can't be sent as immediate data */
++ if (skb->len > (WR_LEN - sizeof(struct cpl_tx_pkt))) {
++ if (unlikely(map_skb(adap->pdev, skb, addr) < 0)) {
++ dev_kfree_skb(skb);
++ return NETDEV_TX_OK;
++ }
++ }
++
+ q->in_use += ndesc;
+ if (unlikely(credits - ndesc < q->stop_thres)) {
+ t3_stop_tx_queue(txq, qs, q);
+@@ -1312,7 +1364,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *
+ if (likely(!skb_shared(skb)))
+ skb_orphan(skb);
+
+- write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl);
++ write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl, addr);
+ check_ring_tx_db(adap, q);
+ return NETDEV_TX_OK;
+ }
+@@ -1577,7 +1629,8 @@ static void setup_deferred_unmapping(str
+ */
+ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
+ struct sge_txq *q, unsigned int pidx,
+- unsigned int gen, unsigned int ndesc)
++ unsigned int gen, unsigned int ndesc,
++ const dma_addr_t *addr)
+ {
+ unsigned int sgl_flits, flits;
+ struct work_request_hdr *from;
+@@ -1598,10 +1651,9 @@ static void write_ofld_wr(struct adapter
+
+ flits = skb_transport_offset(skb) / 8;
+ sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
+- sgl_flits = make_sgl(skb, sgp, skb_transport_header(skb),
+- skb_tail_pointer(skb) -
+- skb_transport_header(skb),
+- adap->pdev);
++ sgl_flits = write_sgl(skb, sgp, skb_transport_header(skb),
++ skb_tail_pointer(skb) - skb_transport_header(skb),
++ addr);
+ if (need_skb_unmap()) {
+ setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits);
+ skb->destructor = deferred_unmap_destructor;
+@@ -1659,6 +1711,12 @@ again: reclaim_completed_tx(adap, q, TX_
+ goto again;
+ }
+
++ if (!immediate(skb) &&
++ map_skb(adap->pdev, skb, (dma_addr_t *)skb->head)) {
++ spin_unlock(&q->lock);
++ return NET_XMIT_SUCCESS;
++ }
++
+ gen = q->gen;
+ q->in_use += ndesc;
+ pidx = q->pidx;
+@@ -1669,7 +1727,7 @@ again: reclaim_completed_tx(adap, q, TX_
+ }
+ spin_unlock(&q->lock);
+
+- write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
++ write_ofld_wr(adap, skb, q, pidx, gen, ndesc, (dma_addr_t *)skb->head);
+ check_ring_tx_db(adap, q);
+ return NET_XMIT_SUCCESS;
+ }
+@@ -1687,6 +1745,7 @@ static void restart_offloadq(unsigned lo
+ struct sge_txq *q = &qs->txq[TXQ_OFLD];
+ const struct port_info *pi = netdev_priv(qs->netdev);
+ struct adapter *adap = pi->adapter;
++ unsigned int written = 0;
+
+ spin_lock(&q->lock);
+ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
+@@ -1706,10 +1765,15 @@ again: reclaim_completed_tx(adap, q, TX_
+ break;
+ }
+
++ if (!immediate(skb) &&
++ map_skb(adap->pdev, skb, (dma_addr_t *)skb->head))
++ break;
++
+ gen = q->gen;
+ q->in_use += ndesc;
+ pidx = q->pidx;
+ q->pidx += ndesc;
++ written += ndesc;
+ if (q->pidx >= q->size) {
+ q->pidx -= q->size;
+ q->gen ^= 1;
+@@ -1717,7 +1781,8 @@ again: reclaim_completed_tx(adap, q, TX_
+ __skb_unlink(skb, &q->sendq);
+ spin_unlock(&q->lock);
+
+- write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
++ write_ofld_wr(adap, skb, q, pidx, gen, ndesc,
++ (dma_addr_t *)skb->head);
+ spin_lock(&q->lock);
+ }
+ spin_unlock(&q->lock);
+@@ -1727,8 +1792,9 @@ again: reclaim_completed_tx(adap, q, TX_
+ set_bit(TXQ_LAST_PKT_DB, &q->flags);
+ #endif
+ wmb();
+- t3_write_reg(adap, A_SG_KDOORBELL,
+- F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
++ if (likely(written))
++ t3_write_reg(adap, A_SG_KDOORBELL,
++ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+ }
+
+ /**
diff --git a/patches.drivers/cxgb4-Add-support-for-new-flash-parts.patch b/patches.drivers/cxgb4-Add-support-for-new-flash-parts.patch
new file mode 100644
index 0000000000..5345e8a905
--- /dev/null
+++ b/patches.drivers/cxgb4-Add-support-for-new-flash-parts.patch
@@ -0,0 +1,195 @@
+From: Ganesh Goudar <ganeshgr@chelsio.com>
+Date: Tue, 10 Oct 2017 12:44:13 +0530
+Subject: cxgb4: Add support for new flash parts
+Patch-mainline: v4.15-rc1
+Git-commit: 96ac18f14a5a721dc4233f1c6ebd07e103ae5a63
+References: bsc#1064802 bsc#1066129
+
+Add support for new flash parts identification, and
+also cleanup the flash Part identifying and decoding
+code.
+
+Based on the original work of Casey Leedom <leedom@chelsio.com>
+
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 136 ++++++++++++++++++++++++-----
+ 1 file changed, 116 insertions(+), 20 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+@@ -8205,7 +8205,7 @@ struct flash_desc {
+ u32 size_mb;
+ };
+
+-static int get_flash_params(struct adapter *adap)
++static int t4_get_flash_params(struct adapter *adap)
+ {
+ /* Table for non-Numonix supported flash parts. Numonix parts are left
+ * to the preexisting code. All flash parts have 64KB sectors.
+@@ -8214,40 +8214,136 @@ static int get_flash_params(struct adapt
+ { 0x150201, 4 << 20 }, /* Spansion 4MB S25FL032P */
+ };
+
++ unsigned int part, manufacturer;
++ unsigned int density, size;
++ u32 flashid = 0;
+ int ret;
+- u32 info;
++
++ /* Issue a Read ID Command to the Flash part. We decode supported
++ * Flash parts and their sizes from this. There's a newer Query
++ * Command which can retrieve detailed geometry information but many
++ * Flash parts don't support it.
++ */
+
+ ret = sf1_write(adap, 1, 1, 0, SF_RD_ID);
+ if (!ret)
+- ret = sf1_read(adap, 3, 0, 1, &info);
++ ret = sf1_read(adap, 3, 0, 1, &flashid);
+ t4_write_reg(adap, SF_OP_A, 0); /* unlock SF */
+ if (ret)
+ return ret;
+
+- for (ret = 0; ret < ARRAY_SIZE(supported_flash); ++ret)
+- if (supported_flash[ret].vendor_and_model_id == info) {
+- adap->params.sf_size = supported_flash[ret].size_mb;
++ /* Check to see if it's one of our non-standard supported Flash parts.
++ */
++ for (part = 0; part < ARRAY_SIZE(supported_flash); part++)
++ if (supported_flash[part].vendor_and_model_id == flashid) {
++ adap->params.sf_size = supported_flash[part].size_mb;
+ adap->params.sf_nsec =
+ adap->params.sf_size / SF_SEC_SIZE;
+- return 0;
++ goto found;
+ }
+
+- if ((info & 0xff) != 0x20) /* not a Numonix flash */
++ /* Decode Flash part size. The code below looks repetative with
++ * common encodings, but that's not guaranteed in the JEDEC
++ * specification for the Read JADEC ID command. The only thing that
++ * we're guaranteed by the JADEC specification is where the
++ * Manufacturer ID is in the returned result. After that each
++ * Manufacturer ~could~ encode things completely differently.
++ * Note, all Flash parts must have 64KB sectors.
++ */
++ manufacturer = flashid & 0xff;
++ switch (manufacturer) {
++ case 0x20: { /* Micron/Numonix */
++ /* This Density -> Size decoding table is taken from Micron
++ * Data Sheets.
++ */
++ density = (flashid >> 16) & 0xff;
++ switch (density) {
++ case 0x14: /* 1MB */
++ size = 1 << 20;
++ break;
++ case 0x15: /* 2MB */
++ size = 1 << 21;
++ break;
++ case 0x16: /* 4MB */
++ size = 1 << 22;
++ break;
++ case 0x17: /* 8MB */
++ size = 1 << 23;
++ break;
++ case 0x18: /* 16MB */
++ size = 1 << 24;
++ break;
++ case 0x19: /* 32MB */
++ size = 1 << 25;
++ break;
++ case 0x20: /* 64MB */
++ size = 1 << 26;
++ break;
++ case 0x21: /* 128MB */
++ size = 1 << 27;
++ break;
++ case 0x22: /* 256MB */
++ size = 1 << 28;
++ break;
++
++ default:
++ dev_err(adap->pdev_dev, "Micron Flash Part has bad size, ID = %#x, Density code = %#x\n",
++ flashid, density);
++ return -EINVAL;
++ }
++ break;
++ }
++ case 0xc2: { /* Macronix */
++ /* This Density -> Size decoding table is taken from Macronix
++ * Data Sheets.
++ */
++ density = (flashid >> 16) & 0xff;
++ switch (density) {
++ case 0x17: /* 8MB */
++ size = 1 << 23;
++ break;
++ case 0x18: /* 16MB */
++ size = 1 << 24;
++ break;
++ default:
++ dev_err(adap->pdev_dev, "Macronix Flash Part has bad size, ID = %#x, Density code = %#x\n",
++ flashid, density);
+ return -EINVAL;
+- info >>= 16; /* log2 of size */
+- if (info >= 0x14 && info < 0x18)
+- adap->params.sf_nsec = 1 << (info - 16);
+- else if (info == 0x18)
+- adap->params.sf_nsec = 64;
+- else
++ }
++ }
++ case 0xef: { /* Winbond */
++ /* This Density -> Size decoding table is taken from Winbond
++ * Data Sheets.
++ */
++ density = (flashid >> 16) & 0xff;
++ switch (density) {
++ case 0x17: /* 8MB */
++ size = 1 << 23;
++ break;
++ case 0x18: /* 16MB */
++ size = 1 << 24;
++ break;
++ default:
++ dev_err(adap->pdev_dev, "Winbond Flash Part has bad size, ID = %#x, Density code = %#x\n",
++ flashid, density);
+ return -EINVAL;
+- adap->params.sf_size = 1 << info;
+- adap->params.sf_fw_start =
+- t4_read_reg(adap, CIM_BOOT_CFG_A) & BOOTADDR_M;
++ }
++ break;
++ }
++ default:
++ dev_err(adap->pdev_dev, "Unsupported Flash Part, ID = %#x\n",
++ flashid);
++ return -EINVAL;
++ }
++
++ /* Store decoded Flash size and fall through into vetting code. */
++ adap->params.sf_size = size;
++ adap->params.sf_nsec = size / SF_SEC_SIZE;
+
++found:
+ if (adap->params.sf_size < FLASH_MIN_SIZE)
+- dev_warn(adap->pdev_dev, "WARNING!!! FLASH size %#x < %#x!!!\n",
+- adap->params.sf_size, FLASH_MIN_SIZE);
++ dev_warn(adap->pdev_dev, "WARNING: Flash Part ID %#x, size %#x < %#x\n",
++ flashid, adap->params.sf_size, FLASH_MIN_SIZE);
+ return 0;
+ }
+
+@@ -8285,7 +8381,7 @@ int t4_prep_adapter(struct adapter *adap
+ get_pci_mode(adapter, &adapter->params.pci);
+ pl_rev = REV_G(t4_read_reg(adapter, PL_REV_A));
+
+- ret = get_flash_params(adapter);
++ ret = t4_get_flash_params(adapter);
+ if (ret < 0) {
+ dev_err(adapter->pdev_dev, "error %d identifying flash\n", ret);
+ return ret;
diff --git a/patches.drivers/cxgb4-Update-comment-for-min_mtu.patch b/patches.drivers/cxgb4-Update-comment-for-min_mtu.patch
new file mode 100644
index 0000000000..db39083e15
--- /dev/null
+++ b/patches.drivers/cxgb4-Update-comment-for-min_mtu.patch
@@ -0,0 +1,30 @@
+From: Arjun Vynipadath <arjun@chelsio.com>
+Date: Tue, 3 Oct 2017 11:43:05 +0530
+Subject: cxgb4: Update comment for min_mtu
+Patch-mainline: v4.15-rc1
+Git-commit: a047fbae23e1d94da28f81fb0f86fab4e473a094
+References: bsc#1064802 bsc#1066129
+
+We have lost a comment for minimum mtu value set for netdevice with
+'commit d894be57ca92 ("ethernet: use net core MTU range checking in
+more drivers"). Updating it accordingly.
+
+Signed-off-by: Arjun Vynipadath <arjun@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -5024,7 +5024,7 @@ static int init_one(struct pci_dev *pdev
+ netdev->priv_flags |= IFF_UNICAST_FLT;
+
+ /* MTU range: 81 - 9600 */
+- netdev->min_mtu = 81;
++ netdev->min_mtu = 81; /* accommodate SACK */
+ netdev->max_mtu = MAX_MTU;
+
+ netdev->netdev_ops = &cxgb4_netdev_ops;
diff --git a/patches.drivers/cxgb4-add-basic-tc-flower-offload-support.patch b/patches.drivers/cxgb4-add-basic-tc-flower-offload-support.patch
new file mode 100644
index 0000000000..99a20592ec
--- /dev/null
+++ b/patches.drivers/cxgb4-add-basic-tc-flower-offload-support.patch
@@ -0,0 +1,426 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Thu, 21 Sep 2017 23:41:14 +0530
+Subject: cxgb4: add basic tc flower offload support
+Patch-mainline: v4.15-rc1
+Git-commit: 62488e4b53ae02d82ac000f91ec82b5cfb41d6f2
+References: bsc#1064802 bsc#1066129
+
+Add support to add/remove flows for offload. Following match
+and action are supported for offloading a flow:
+
+Match: ether-protocol, IPv4/IPv6 addresses, L4 ports (TCP/UDP)
+Action: drop, redirect to another port on the device.
+
+The qualifying flows can have accompanying mask information.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 3
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 24 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 280 ++++++++++++++++++-
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h | 17 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 1
+ 6 files changed, 325 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -905,6 +905,9 @@ struct adapter {
+ /* TC u32 offload */
+ struct cxgb4_tc_u32_table *tc_u32;
+ struct chcr_stats_debug chcr_stats;
++
++ /* TC flower offload */
++ DECLARE_HASHTABLE(flower_anymatch_tbl, 9);
+ };
+
+ /* Support for "sched-class" command to allow a TX Scheduling Class to be
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+@@ -148,6 +148,30 @@ static int get_filter_steerq(struct net_
+ return iq;
+ }
+
++int cxgb4_get_free_ftid(struct net_device *dev, int family)
++{
++ struct adapter *adap = netdev2adap(dev);
++ struct tid_info *t = &adap->tids;
++ int ftid;
++
++ spin_lock_bh(&t->ftid_lock);
++ if (family == PF_INET) {
++ ftid = find_first_zero_bit(t->ftid_bmap, t->nftids);
++ if (ftid >= t->nftids)
++ ftid = -1;
++ } else {
++ ftid = bitmap_find_free_region(t->ftid_bmap, t->nftids, 2);
++ if (ftid < 0)
++ goto out_unlock;
++
++ /* this is only a lookup, keep the found region unallocated */
++ bitmap_release_region(t->ftid_bmap, ftid, 2);
++ }
++out_unlock:
++ spin_unlock_bh(&t->ftid_lock);
++ return ftid;
++}
++
+ static int cxgb4_set_ftid(struct tid_info *t, int fidx, int family)
+ {
+ spin_lock_bh(&t->ftid_lock);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -5105,6 +5105,8 @@ static int init_one(struct pci_dev *pdev
+ if (!adapter->tc_u32)
+ dev_warn(&pdev->dev,
+ "could not offload tc u32, continuing\n");
++
++ cxgb4_init_tc_flower(adapter);
+ }
+
+ if (is_offload(adapter)) {
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+@@ -38,16 +38,287 @@
+ #include "cxgb4.h"
+ #include "cxgb4_tc_flower.h"
+
++static struct ch_tc_flower_entry *allocate_flower_entry(void)
++{
++ struct ch_tc_flower_entry *new = kzalloc(sizeof(*new), GFP_KERNEL);
++ return new;
++}
++
++/* Must be called with either RTNL or rcu_read_lock */
++static struct ch_tc_flower_entry *ch_flower_lookup(struct adapter *adap,
++ unsigned long flower_cookie)
++{
++ struct ch_tc_flower_entry *flower_entry;
++
++ hash_for_each_possible_rcu(adap->flower_anymatch_tbl, flower_entry,
++ link, flower_cookie)
++ if (flower_entry->tc_flower_cookie == flower_cookie)
++ return flower_entry;
++ return NULL;
++}
++
++static void cxgb4_process_flow_match(struct net_device *dev,
++ struct tc_cls_flower_offload *cls,
++ struct ch_filter_specification *fs)
++{
++ u16 addr_type = 0;
++
++ if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
++ struct flow_dissector_key_control *key =
++ skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_CONTROL,
++ cls->key);
++
++ addr_type = key->addr_type;
++ }
++
++ if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
++ struct flow_dissector_key_basic *key =
++ skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_BASIC,
++ cls->key);
++ struct flow_dissector_key_basic *mask =
++ skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_BASIC,
++ cls->mask);
++ u16 ethtype_key = ntohs(key->n_proto);
++ u16 ethtype_mask = ntohs(mask->n_proto);
++
++ if (ethtype_key == ETH_P_ALL) {
++ ethtype_key = 0;
++ ethtype_mask = 0;
++ }
++
++ fs->val.ethtype = ethtype_key;
++ fs->mask.ethtype = ethtype_mask;
++ fs->val.proto = key->ip_proto;
++ fs->mask.proto = mask->ip_proto;
++ }
++
++ if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
++ struct flow_dissector_key_ipv4_addrs *key =
++ skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_IPV4_ADDRS,
++ cls->key);
++ struct flow_dissector_key_ipv4_addrs *mask =
++ skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_IPV4_ADDRS,
++ cls->mask);
++ fs->type = 0;
++ memcpy(&fs->val.lip[0], &key->dst, sizeof(key->dst));
++ memcpy(&fs->val.fip[0], &key->src, sizeof(key->src));
++ memcpy(&fs->mask.lip[0], &mask->dst, sizeof(mask->dst));
++ memcpy(&fs->mask.fip[0], &mask->src, sizeof(mask->src));
++ }
++
++ if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
++ struct flow_dissector_key_ipv6_addrs *key =
++ skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_IPV6_ADDRS,
++ cls->key);
++ struct flow_dissector_key_ipv6_addrs *mask =
++ skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_IPV6_ADDRS,
++ cls->mask);
++
++ fs->type = 1;
++ memcpy(&fs->val.lip[0], key->dst.s6_addr, sizeof(key->dst));
++ memcpy(&fs->val.fip[0], key->src.s6_addr, sizeof(key->src));
++ memcpy(&fs->mask.lip[0], mask->dst.s6_addr, sizeof(mask->dst));
++ memcpy(&fs->mask.fip[0], mask->src.s6_addr, sizeof(mask->src));
++ }
++
++ if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
++ struct flow_dissector_key_ports *key, *mask;
++
++ key = skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_PORTS,
++ cls->key);
++ mask = skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_PORTS,
++ cls->mask);
++ fs->val.lport = cpu_to_be16(key->dst);
++ fs->mask.lport = cpu_to_be16(mask->dst);
++ fs->val.fport = cpu_to_be16(key->src);
++ fs->mask.fport = cpu_to_be16(mask->src);
++ }
++
++ /* Match only packets coming from the ingress port where this
++ * filter will be created.
++ */
++ fs->val.iport = netdev2pinfo(dev)->port_id;
++ fs->mask.iport = ~0;
++}
++
++static int cxgb4_validate_flow_match(struct net_device *dev,
++ struct tc_cls_flower_offload *cls)
++{
++ if (cls->dissector->used_keys &
++ ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
++ BIT(FLOW_DISSECTOR_KEY_BASIC) |
++ BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
++ BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
++ BIT(FLOW_DISSECTOR_KEY_PORTS))) {
++ netdev_warn(dev, "Unsupported key used: 0x%x\n",
++ cls->dissector->used_keys);
++ return -EOPNOTSUPP;
++ }
++ return 0;
++}
++
++static void cxgb4_process_flow_actions(struct net_device *in,
++ struct tc_cls_flower_offload *cls,
++ struct ch_filter_specification *fs)
++{
++ const struct tc_action *a;
++ LIST_HEAD(actions);
++
++ tcf_exts_to_list(cls->exts, &actions);
++ list_for_each_entry(a, &actions, list) {
++ if (is_tcf_gact_shot(a)) {
++ fs->action = FILTER_DROP;
++ } else if (is_tcf_mirred_egress_redirect(a)) {
++ int ifindex = tcf_mirred_ifindex(a);
++ struct net_device *out = __dev_get_by_index(dev_net(in),
++ ifindex);
++ struct port_info *pi = netdev_priv(out);
++
++ fs->action = FILTER_SWITCH;
++ fs->eport = pi->port_id;
++ }
++ }
++}
++
++static int cxgb4_validate_flow_actions(struct net_device *dev,
++ struct tc_cls_flower_offload *cls)
++{
++ const struct tc_action *a;
++ LIST_HEAD(actions);
++
++ tcf_exts_to_list(cls->exts, &actions);
++ list_for_each_entry(a, &actions, list) {
++ if (is_tcf_gact_shot(a)) {
++ /* Do nothing */
++ } else if (is_tcf_mirred_egress_redirect(a)) {
++ struct adapter *adap = netdev2adap(dev);
++ struct net_device *n_dev;
++ unsigned int i, ifindex;
++ bool found = false;
++
++ ifindex = tcf_mirred_ifindex(a);
++ for_each_port(adap, i) {
++ n_dev = adap->port[i];
++ if (ifindex == n_dev->ifindex) {
++ found = true;
++ break;
++ }
++ }
++
++ /* If interface doesn't belong to our hw, then
++ * the provided output port is not valid
++ */
++ if (!found) {
++ netdev_err(dev, "%s: Out port invalid\n",
++ __func__);
++ return -EINVAL;
++ }
++ } else {
++ netdev_err(dev, "%s: Unsupported action\n", __func__);
++ return -EOPNOTSUPP;
++ }
++ }
++ return 0;
++}
++
+ int cxgb4_tc_flower_replace(struct net_device *dev,
+ struct tc_cls_flower_offload *cls)
+ {
+- return -EOPNOTSUPP;
++ struct adapter *adap = netdev2adap(dev);
++ struct ch_tc_flower_entry *ch_flower;
++ struct ch_filter_specification *fs;
++ struct filter_ctx ctx;
++ int fidx;
++ int ret;
++
++ if (cxgb4_validate_flow_actions(dev, cls))
++ return -EOPNOTSUPP;
++
++ if (cxgb4_validate_flow_match(dev, cls))
++ return -EOPNOTSUPP;
++
++ ch_flower = allocate_flower_entry();
++ if (!ch_flower) {
++ netdev_err(dev, "%s: ch_flower alloc failed.\n", __func__);
++ return -ENOMEM;
++ }
++
++ fs = &ch_flower->fs;
++ fs->hitcnts = 1;
++ cxgb4_process_flow_actions(dev, cls, fs);
++ cxgb4_process_flow_match(dev, cls, fs);
++
++ fidx = cxgb4_get_free_ftid(dev, fs->type ? PF_INET6 : PF_INET);
++ if (fidx < 0) {
++ netdev_err(dev, "%s: No fidx for offload.\n", __func__);
++ ret = -ENOMEM;
++ goto free_entry;
++ }
++
++ init_completion(&ctx.completion);
++ ret = __cxgb4_set_filter(dev, fidx, fs, &ctx);
++ if (ret) {
++ netdev_err(dev, "%s: filter creation err %d\n",
++ __func__, ret);
++ goto free_entry;
++ }
++
++ /* Wait for reply */
++ ret = wait_for_completion_timeout(&ctx.completion, 10 * HZ);
++ if (!ret) {
++ ret = -ETIMEDOUT;
++ goto free_entry;
++ }
++
++ ret = ctx.result;
++ /* Check if hw returned error for filter creation */
++ if (ret) {
++ netdev_err(dev, "%s: filter creation err %d\n",
++ __func__, ret);
++ goto free_entry;
++ }
++
++ INIT_HLIST_NODE(&ch_flower->link);
++ ch_flower->tc_flower_cookie = cls->cookie;
++ ch_flower->filter_id = ctx.tid;
++ hash_add_rcu(adap->flower_anymatch_tbl, &ch_flower->link, cls->cookie);
++
++ return ret;
++
++free_entry:
++ kfree(ch_flower);
++ return ret;
+ }
+
+ int cxgb4_tc_flower_destroy(struct net_device *dev,
+ struct tc_cls_flower_offload *cls)
+ {
+- return -EOPNOTSUPP;
++ struct adapter *adap = netdev2adap(dev);
++ struct ch_tc_flower_entry *ch_flower;
++ int ret;
++
++ ch_flower = ch_flower_lookup(adap, cls->cookie);
++ if (!ch_flower)
++ return -ENOENT;
++
++ ret = cxgb4_del_filter(dev, ch_flower->filter_id);
++ if (ret)
++ goto err;
++
++ hash_del_rcu(&ch_flower->link);
++ kfree_rcu(ch_flower, rcu);
++
++err:
++ return ret;
+ }
+
+ int cxgb4_tc_flower_stats(struct net_device *dev,
+@@ -55,3 +326,8 @@ int cxgb4_tc_flower_stats(struct net_dev
+ {
+ return -EOPNOTSUPP;
+ }
++
++void cxgb4_init_tc_flower(struct adapter *adap)
++{
++ hash_init(adap->flower_anymatch_tbl);
++}
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
+@@ -37,10 +37,27 @@
+
+ #include <net/pkt_cls.h>
+
++struct ch_tc_flower_stats {
++ u64 packet_count;
++ u64 byte_count;
++ u64 last_used;
++};
++
++struct ch_tc_flower_entry {
++ struct ch_filter_specification fs;
++ struct ch_tc_flower_stats stats;
++ unsigned long tc_flower_cookie;
++ struct hlist_node link;
++ struct rcu_head rcu;
++ u32 filter_id;
++};
++
+ int cxgb4_tc_flower_replace(struct net_device *dev,
+ struct tc_cls_flower_offload *cls);
+ int cxgb4_tc_flower_destroy(struct net_device *dev,
+ struct tc_cls_flower_offload *cls);
+ int cxgb4_tc_flower_stats(struct net_device *dev,
+ struct tc_cls_flower_offload *cls);
++
++void cxgb4_init_tc_flower(struct adapter *adap);
+ #endif /* __CXGB4_TC_FLOWER_H */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+@@ -212,6 +212,7 @@ struct filter_ctx {
+
+ struct ch_filter_specification;
+
++int cxgb4_get_free_ftid(struct net_device *dev, int family);
+ int __cxgb4_set_filter(struct net_device *dev, int filter_id,
+ struct ch_filter_specification *fs,
+ struct filter_ctx *ctx);
diff --git a/patches.drivers/cxgb4-add-support-to-create-hash-filters-via-tc-flow.patch b/patches.drivers/cxgb4-add-support-to-create-hash-filters-via-tc-flow.patch
new file mode 100644
index 0000000000..e72e08fb2e
--- /dev/null
+++ b/patches.drivers/cxgb4-add-support-to-create-hash-filters-via-tc-flow.patch
@@ -0,0 +1,227 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Wed, 1 Nov 2017 08:53:05 +0530
+Subject: cxgb4: add support to create hash-filters via tc-flower offload
+Patch-mainline: v4.15-rc1
+Git-commit: 3eb8b62d5a260fcd9683b0ce89beb3b28b12a304
+References: bsc#1064802 bsc#1066129
+
+Determine whether the flow classifies as exact-match with respect to
+4-tuple and configured tuple mask in hw. If successfully classified
+as exact-match, offload the flow as hash-filter in hw.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 148 +++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h | 2
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 16 +-
+ 3 files changed, 161 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+@@ -31,6 +31,7 @@
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
++#include <net/ipv6.h>
+
+ #include "cxgb4.h"
+ #include "t4_regs.h"
+@@ -765,6 +766,153 @@ static void fill_default_mask(struct ch_
+ fs->mask.fport = ~0;
+ }
+
++static bool is_addr_all_mask(u8 *ipmask, int family)
++{
++ if (family == AF_INET) {
++ struct in_addr *addr;
++
++ addr = (struct in_addr *)ipmask;
++ if (addr->s_addr == 0xffffffff)
++ return true;
++ } else if (family == AF_INET6) {
++ struct in6_addr *addr6;
++
++ addr6 = (struct in6_addr *)ipmask;
++ if (addr6->s6_addr32[0] == 0xffffffff &&
++ addr6->s6_addr32[1] == 0xffffffff &&
++ addr6->s6_addr32[2] == 0xffffffff &&
++ addr6->s6_addr32[3] == 0xffffffff)
++ return true;
++ }
++ return false;
++}
++
++static bool is_inaddr_any(u8 *ip, int family)
++{
++ int addr_type;
++
++ if (family == AF_INET) {
++ struct in_addr *addr;
++
++ addr = (struct in_addr *)ip;
++ if (addr->s_addr == htonl(INADDR_ANY))
++ return true;
++ } else if (family == AF_INET6) {
++ struct in6_addr *addr6;
++
++ addr6 = (struct in6_addr *)ip;
++ addr_type = ipv6_addr_type((const struct in6_addr *)
++ &addr6);
++ if (addr_type == IPV6_ADDR_ANY)
++ return true;
++ }
++ return false;
++}
++
++bool is_filter_exact_match(struct adapter *adap,
++ struct ch_filter_specification *fs)
++{
++ struct tp_params *tp = &adap->params.tp;
++ u64 hash_filter_mask = tp->hash_filter_mask;
++ u32 mask;
++
++ if (!is_hashfilter(adap))
++ return false;
++
++ if (fs->type) {
++ if (is_inaddr_any(fs->val.fip, AF_INET6) ||
++ !is_addr_all_mask(fs->mask.fip, AF_INET6))
++ return false;
++
++ if (is_inaddr_any(fs->val.lip, AF_INET6) ||
++ !is_addr_all_mask(fs->mask.lip, AF_INET6))
++ return false;
++ } else {
++ if (is_inaddr_any(fs->val.fip, AF_INET) ||
++ !is_addr_all_mask(fs->mask.fip, AF_INET))
++ return false;
++
++ if (is_inaddr_any(fs->val.lip, AF_INET) ||
++ !is_addr_all_mask(fs->mask.lip, AF_INET))
++ return false;
++ }
++
++ if (!fs->val.lport || fs->mask.lport != 0xffff)
++ return false;
++
++ if (!fs->val.fport || fs->mask.fport != 0xffff)
++ return false;
++
++ if (tp->fcoe_shift >= 0) {
++ mask = (hash_filter_mask >> tp->fcoe_shift) & FT_FCOE_W;
++ if (mask && !fs->mask.fcoe)
++ return false;
++ }
++
++ if (tp->port_shift >= 0) {
++ mask = (hash_filter_mask >> tp->port_shift) & FT_PORT_W;
++ if (mask && !fs->mask.iport)
++ return false;
++ }
++
++ if (tp->vnic_shift >= 0) {
++ mask = (hash_filter_mask >> tp->vnic_shift) & FT_VNIC_ID_W;
++
++ if ((adap->params.tp.ingress_config & VNIC_F)) {
++ if (mask && !fs->mask.pfvf_vld)
++ return false;
++ } else {
++ if (mask && !fs->mask.ovlan_vld)
++ return false;
++ }
++ }
++
++ if (tp->vlan_shift >= 0) {
++ mask = (hash_filter_mask >> tp->vlan_shift) & FT_VLAN_W;
++ if (mask && !fs->mask.ivlan)
++ return false;
++ }
++
++ if (tp->tos_shift >= 0) {
++ mask = (hash_filter_mask >> tp->tos_shift) & FT_TOS_W;
++ if (mask && !fs->mask.tos)
++ return false;
++ }
++
++ if (tp->protocol_shift >= 0) {
++ mask = (hash_filter_mask >> tp->protocol_shift) & FT_PROTOCOL_W;
++ if (mask && !fs->mask.proto)
++ return false;
++ }
++
++ if (tp->ethertype_shift >= 0) {
++ mask = (hash_filter_mask >> tp->ethertype_shift) &
++ FT_ETHERTYPE_W;
++ if (mask && !fs->mask.ethtype)
++ return false;
++ }
++
++ if (tp->macmatch_shift >= 0) {
++ mask = (hash_filter_mask >> tp->macmatch_shift) & FT_MACMATCH_W;
++ if (mask && !fs->mask.macidx)
++ return false;
++ }
++
++ if (tp->matchtype_shift >= 0) {
++ mask = (hash_filter_mask >> tp->matchtype_shift) &
++ FT_MPSHITTYPE_W;
++ if (mask && !fs->mask.matchtype)
++ return false;
++ }
++ if (tp->frag_shift >= 0) {
++ mask = (hash_filter_mask >> tp->frag_shift) &
++ FT_FRAGMENTATION_W;
++ if (mask && !fs->mask.frag)
++ return false;
++ }
++ return true;
++}
++
+ static u64 hash_filter_ntuple(struct ch_filter_specification *fs,
+ struct net_device *dev)
+ {
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h
+@@ -51,4 +51,6 @@ int delete_filter(struct adapter *adapte
+ int writable_filter(struct filter_entry *f);
+ void clear_all_filters(struct adapter *adapter);
+ int init_hash_filter(struct adapter *adap);
++bool is_filter_exact_match(struct adapter *adap,
++ struct ch_filter_specification *fs);
+ #endif /* __CXGB4_FILTER_H */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+@@ -38,6 +38,7 @@
+ #include <net/tc_act/tc_vlan.h>
+
+ #include "cxgb4.h"
++#include "cxgb4_filter.h"
+ #include "cxgb4_tc_flower.h"
+
+ #define STATS_CHECK_PERIOD (HZ / 2)
+@@ -677,11 +678,16 @@ int cxgb4_tc_flower_replace(struct net_d
+ cxgb4_process_flow_match(dev, cls, fs);
+ cxgb4_process_flow_actions(dev, cls, fs);
+
+- fidx = cxgb4_get_free_ftid(dev, fs->type ? PF_INET6 : PF_INET);
+- if (fidx < 0) {
+- netdev_err(dev, "%s: No fidx for offload.\n", __func__);
+- ret = -ENOMEM;
+- goto free_entry;
++ fs->hash = is_filter_exact_match(adap, fs);
++ if (fs->hash) {
++ fidx = 0;
++ } else {
++ fidx = cxgb4_get_free_ftid(dev, fs->type ? PF_INET6 : PF_INET);
++ if (fidx < 0) {
++ netdev_err(dev, "%s: No fidx for offload.\n", __func__);
++ ret = -ENOMEM;
++ goto free_entry;
++ }
+ }
+
+ init_completion(&ctx.completion);
diff --git a/patches.drivers/cxgb4-add-support-to-create-hash-filters.patch b/patches.drivers/cxgb4-add-support-to-create-hash-filters.patch
new file mode 100644
index 0000000000..d2aa027c5a
--- /dev/null
+++ b/patches.drivers/cxgb4-add-support-to-create-hash-filters.patch
@@ -0,0 +1,773 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Wed, 1 Nov 2017 08:53:01 +0530
+Subject: cxgb4: add support to create hash filters
+Patch-mainline: v4.15-rc1
+Git-commit: 12b276fbf6e092adca08a8125afcc4e7f530a0b6
+References: bsc#1064802 bsc#1066129
+
+Add support to create hash (exact-match) filters based on the value
+of 'hash' field in ch_filter_specification.
+
+Allocate SMT/L2T entries if DMAC-rewrite/SMAC-rewrite is requested.
+
+Allocate CLIP entry in case of IPv6 filter.
+
+Use cpl_act_open_req[6] to send hash filter create request to hw.
+Also, the filter tuple is calculated as part of sending this request.
+
+Hash-filter reply is processed on getting cpl_act_open_rpl.
+In case of success, various bits/fields in filter-tcb are set per
+filter requirement, such as enabling filter hitcnts, and/or various
+header rewrite operations, such as VLAN-rewrite, NAT or
+(L3/L4)-rewrite, and SMAC/DMAC-rewrite. In case of failure, clear the
+filter entry and release any hw resources occupied by it.
+
+The patch also moves the functions set_tcb_field, set_tcb_tflag and
+configure_filter_smac towards beginning of file.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 10
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 573 ++++++++++++++++++++--
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h | 3
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 4
+ drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 5
+ drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h | 17
+ 6 files changed, 562 insertions(+), 50 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -1050,6 +1050,7 @@ struct ch_filter_specification {
+ * matching that doesn't exist as a (value, mask) tuple.
+ */
+ uint32_t type:1; /* 0 => IPv4, 1 => IPv6 */
++ u32 hash:1; /* 0 => wild-card, 1 => exact-match */
+
+ /* Packet dispatch information. Ingress packets which match the
+ * filter rules will be dropped, passed to the host or switched back
+@@ -1107,7 +1108,14 @@ enum {
+ };
+
+ enum {
+- NAT_MODE_ALL = 7, /* NAT on entire 4-tuple */
++ NAT_MODE_NONE = 0, /* No NAT performed */
++ NAT_MODE_DIP, /* NAT on Dst IP */
++ NAT_MODE_DIP_DP, /* NAT on Dst IP, Dst Port */
++ NAT_MODE_DIP_DP_SIP, /* NAT on Dst IP, Dst Port and Src IP */
++ NAT_MODE_DIP_DP_SP, /* NAT on Dst IP, Dst Port and Src Port */
++ NAT_MODE_SIP_SP, /* NAT on Src IP and Src Port */
++ NAT_MODE_DIP_SIP_SP, /* NAT on Dst IP, Src IP and Src Port */
++ NAT_MODE_ALL /* NAT on entire 4-tuple */
+ };
+
+ /* Host shadow copy of ingress filter entry. This is in host native format
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+@@ -35,6 +35,8 @@
+ #include "cxgb4.h"
+ #include "t4_regs.h"
+ #include "t4_tcb.h"
++#include "t4_values.h"
++#include "clip_tbl.h"
+ #include "l2t.h"
+ #include "smt.h"
+ #include "t4fw_api.h"
+@@ -50,6 +52,141 @@ static inline bool unsupported(u32 conf,
+ return !(conf & conf_mask) && is_field_set(val, mask);
+ }
+
++static int set_tcb_field(struct adapter *adap, struct filter_entry *f,
++ unsigned int ftid, u16 word, u64 mask, u64 val,
++ int no_reply)
++{
++ struct cpl_set_tcb_field *req;
++ struct sk_buff *skb;
++
++ skb = alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_ATOMIC);
++ if (!skb)
++ return -ENOMEM;
++
++ req = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*req));
++ memset(req, 0, sizeof(*req));
++ INIT_TP_WR_CPL(req, CPL_SET_TCB_FIELD, ftid);
++ req->reply_ctrl = htons(REPLY_CHAN_V(0) |
++ QUEUENO_V(adap->sge.fw_evtq.abs_id) |
++ NO_REPLY_V(no_reply));
++ req->word_cookie = htons(TCB_WORD_V(word) | TCB_COOKIE_V(ftid));
++ req->mask = cpu_to_be64(mask);
++ req->val = cpu_to_be64(val);
++ set_wr_txq(skb, CPL_PRIORITY_CONTROL, f->fs.val.iport & 0x3);
++ t4_ofld_send(adap, skb);
++ return 0;
++}
++
++/* Set one of the t_flags bits in the TCB.
++ */
++static int set_tcb_tflag(struct adapter *adap, struct filter_entry *f,
++ unsigned int ftid, unsigned int bit_pos,
++ unsigned int val, int no_reply)
++{
++ return set_tcb_field(adap, f, ftid, TCB_T_FLAGS_W, 1ULL << bit_pos,
++ (unsigned long long)val << bit_pos, no_reply);
++}
++
++static int configure_filter_smac(struct adapter *adap, struct filter_entry *f)
++{
++ int err;
++
++ /* do a set-tcb for smac-sel and CWR bit.. */
++ err = set_tcb_tflag(adap, f, f->tid, TF_CCTRL_CWR_S, 1, 1);
++ if (err)
++ goto smac_err;
++
++ err = set_tcb_field(adap, f, f->tid, TCB_SMAC_SEL_W,
++ TCB_SMAC_SEL_V(TCB_SMAC_SEL_M),
++ TCB_SMAC_SEL_V(f->smt->idx), 1);
++ if (!err)
++ return 0;
++
++smac_err:
++ dev_err(adap->pdev_dev, "filter %u smac config failed with error %u\n",
++ f->tid, err);
++ return err;
++}
++
++static void set_nat_params(struct adapter *adap, struct filter_entry *f,
++ unsigned int tid, bool dip, bool sip, bool dp,
++ bool sp)
++{
++ if (dip) {
++ if (f->fs.type) {
++ set_tcb_field(adap, f, tid, TCB_SND_UNA_RAW_W,
++ WORD_MASK, f->fs.nat_lip[15] |
++ f->fs.nat_lip[14] << 8 |
++ f->fs.nat_lip[13] << 16 |
++ f->fs.nat_lip[12] << 24, 1);
++
++ set_tcb_field(adap, f, tid, TCB_SND_UNA_RAW_W + 1,
++ WORD_MASK, f->fs.nat_lip[11] |
++ f->fs.nat_lip[10] << 8 |
++ f->fs.nat_lip[9] << 16 |
++ f->fs.nat_lip[8] << 24, 1);
++
++ set_tcb_field(adap, f, tid, TCB_SND_UNA_RAW_W + 2,
++ WORD_MASK, f->fs.nat_lip[7] |
++ f->fs.nat_lip[6] << 8 |
++ f->fs.nat_lip[5] << 16 |
++ f->fs.nat_lip[4] << 24, 1);
++
++ set_tcb_field(adap, f, tid, TCB_SND_UNA_RAW_W + 3,
++ WORD_MASK, f->fs.nat_lip[3] |
++ f->fs.nat_lip[2] << 8 |
++ f->fs.nat_lip[1] << 16 |
++ f->fs.nat_lip[0] << 24, 1);
++ } else {
++ set_tcb_field(adap, f, tid, TCB_RX_FRAG3_LEN_RAW_W,
++ WORD_MASK, f->fs.nat_lip[3] |
++ f->fs.nat_lip[2] << 8 |
++ f->fs.nat_lip[1] << 16 |
++ f->fs.nat_lip[0] << 24, 1);
++ }
++ }
++
++ if (sip) {
++ if (f->fs.type) {
++ set_tcb_field(adap, f, tid, TCB_RX_FRAG2_PTR_RAW_W,
++ WORD_MASK, f->fs.nat_fip[15] |
++ f->fs.nat_fip[14] << 8 |
++ f->fs.nat_fip[13] << 16 |
++ f->fs.nat_fip[12] << 24, 1);
++
++ set_tcb_field(adap, f, tid, TCB_RX_FRAG2_PTR_RAW_W + 1,
++ WORD_MASK, f->fs.nat_fip[11] |
++ f->fs.nat_fip[10] << 8 |
++ f->fs.nat_fip[9] << 16 |
++ f->fs.nat_fip[8] << 24, 1);
++
++ set_tcb_field(adap, f, tid, TCB_RX_FRAG2_PTR_RAW_W + 2,
++ WORD_MASK, f->fs.nat_fip[7] |
++ f->fs.nat_fip[6] << 8 |
++ f->fs.nat_fip[5] << 16 |
++ f->fs.nat_fip[4] << 24, 1);
++
++ set_tcb_field(adap, f, tid, TCB_RX_FRAG2_PTR_RAW_W + 3,
++ WORD_MASK, f->fs.nat_fip[3] |
++ f->fs.nat_fip[2] << 8 |
++ f->fs.nat_fip[1] << 16 |
++ f->fs.nat_fip[0] << 24, 1);
++
++ } else {
++ set_tcb_field(adap, f, tid,
++ TCB_RX_FRAG3_START_IDX_OFFSET_RAW_W,
++ WORD_MASK, f->fs.nat_fip[3] |
++ f->fs.nat_fip[2] << 8 |
++ f->fs.nat_fip[1] << 16 |
++ f->fs.nat_fip[0] << 24, 1);
++ }
++ }
++
++ set_tcb_field(adap, f, tid, TCB_PDU_HDR_LEN_W, WORD_MASK,
++ (dp ? f->fs.nat_lport : 0) |
++ (sp ? f->fs.nat_fport << 16 : 0), 1);
++}
++
+ /* Validate filter spec against configuration done on the card. */
+ static int validate_filter(struct net_device *dev,
+ struct ch_filter_specification *fs)
+@@ -484,10 +621,8 @@ int delete_filter(struct adapter *adapte
+ void clear_filter(struct adapter *adap, struct filter_entry *f)
+ {
+ /* If the new or old filter have loopback rewriteing rules then we'll
+- * need to free any existing Layer Two Table (L2T) entries of the old
+- * filter rule. The firmware will handle freeing up any Source MAC
+- * Table (SMT) entries used for rewriting Source MAC Addresses in
+- * loopback rules.
++ * need to free any existing L2T, SMT, CLIP entries of filter
++ * rule.
+ */
+ if (f->l2t)
+ cxgb4_l2t_release(f->l2t);
+@@ -495,6 +630,9 @@ void clear_filter(struct adapter *adap,
+ if (f->smt)
+ cxgb4_smt_release(f->smt);
+
++ if (f->fs.hash && f->fs.type)
++ cxgb4_clip_release(f->dev, (const u32 *)&f->fs.val.lip, 1);
++
+ /* The zeroing of the filter rule below clears the filter valid,
+ * pending, locked flags, l2t pointer, etc. so it's all we need for
+ * this operation.
+@@ -564,6 +702,269 @@ static void fill_default_mask(struct ch_
+ fs->mask.fport = ~0;
+ }
+
++static u64 hash_filter_ntuple(struct ch_filter_specification *fs,
++ struct net_device *dev)
++{
++ struct adapter *adap = netdev2adap(dev);
++ struct tp_params *tp = &adap->params.tp;
++ u64 ntuple = 0;
++
++ /* Initialize each of the fields which we care about which are present
++ * in the Compressed Filter Tuple.
++ */
++ if (tp->vlan_shift >= 0 && fs->mask.ivlan)
++ ntuple |= (FT_VLAN_VLD_F | fs->val.ivlan) << tp->vlan_shift;
++
++ if (tp->port_shift >= 0 && fs->mask.iport)
++ ntuple |= (u64)fs->val.iport << tp->port_shift;
++
++ if (tp->protocol_shift >= 0) {
++ if (!fs->val.proto)
++ ntuple |= (u64)IPPROTO_TCP << tp->protocol_shift;
++ else
++ ntuple |= (u64)fs->val.proto << tp->protocol_shift;
++ }
++
++ if (tp->tos_shift >= 0 && fs->mask.tos)
++ ntuple |= (u64)(fs->val.tos) << tp->tos_shift;
++
++ if (tp->vnic_shift >= 0) {
++ if ((adap->params.tp.ingress_config & VNIC_F) &&
++ fs->mask.pfvf_vld)
++ ntuple |= (u64)((fs->val.pfvf_vld << 16) |
++ (fs->val.pf << 13) |
++ (fs->val.vf)) << tp->vnic_shift;
++ else
++ ntuple |= (u64)((fs->val.ovlan_vld << 16) |
++ (fs->val.ovlan)) << tp->vnic_shift;
++ }
++
++ if (tp->macmatch_shift >= 0 && fs->mask.macidx)
++ ntuple |= (u64)(fs->val.macidx) << tp->macmatch_shift;
++
++ if (tp->ethertype_shift >= 0 && fs->mask.ethtype)
++ ntuple |= (u64)(fs->val.ethtype) << tp->ethertype_shift;
++
++ if (tp->matchtype_shift >= 0 && fs->mask.matchtype)
++ ntuple |= (u64)(fs->val.matchtype) << tp->matchtype_shift;
++
++ if (tp->frag_shift >= 0 && fs->mask.frag)
++ ntuple |= (u64)(fs->val.frag) << tp->frag_shift;
++
++ if (tp->fcoe_shift >= 0 && fs->mask.fcoe)
++ ntuple |= (u64)(fs->val.fcoe) << tp->fcoe_shift;
++ return ntuple;
++}
++
++static void mk_act_open_req6(struct filter_entry *f, struct sk_buff *skb,
++ unsigned int qid_filterid, struct adapter *adap)
++{
++ struct cpl_t6_act_open_req6 *t6req = NULL;
++ struct cpl_act_open_req6 *req = NULL;
++
++ t6req = (struct cpl_t6_act_open_req6 *)__skb_put(skb, sizeof(*t6req));
++ INIT_TP_WR(t6req, 0);
++ req = (struct cpl_act_open_req6 *)t6req;
++ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6, qid_filterid));
++ req->local_port = cpu_to_be16(f->fs.val.lport);
++ req->peer_port = cpu_to_be16(f->fs.val.fport);
++ req->local_ip_hi = *(__be64 *)(&f->fs.val.lip);
++ req->local_ip_lo = *(((__be64 *)&f->fs.val.lip) + 1);
++ req->peer_ip_hi = *(__be64 *)(&f->fs.val.fip);
++ req->peer_ip_lo = *(((__be64 *)&f->fs.val.fip) + 1);
++ req->opt0 = cpu_to_be64(NAGLE_V(f->fs.newvlan == VLAN_REMOVE ||
++ f->fs.newvlan == VLAN_REWRITE) |
++ DELACK_V(f->fs.hitcnts) |
++ L2T_IDX_V(f->l2t ? f->l2t->idx : 0) |
++ SMAC_SEL_V((cxgb4_port_viid(f->dev) &
++ 0x7F) << 1) |
++ TX_CHAN_V(f->fs.eport) |
++ NO_CONG_V(f->fs.rpttid) |
++ ULP_MODE_V(f->fs.nat_mode ?
++ ULP_MODE_TCPDDP : ULP_MODE_NONE) |
++ TCAM_BYPASS_F | NON_OFFLOAD_F);
++ t6req->params = cpu_to_be64(FILTER_TUPLE_V(hash_filter_ntuple(&f->fs,
++ f->dev)));
++ t6req->opt2 = htonl(RSS_QUEUE_VALID_F |
++ RSS_QUEUE_V(f->fs.iq) |
++ TX_QUEUE_V(f->fs.nat_mode) |
++ T5_OPT_2_VALID_F |
++ RX_CHANNEL_F |
++ CONG_CNTRL_V((f->fs.action == FILTER_DROP) |
++ (f->fs.dirsteer << 1)) |
++ PACE_V((f->fs.maskhash) |
++ ((f->fs.dirsteerhash) << 1)) |
++ CCTRL_ECN_V(f->fs.action == FILTER_SWITCH));
++}
++
++static void mk_act_open_req(struct filter_entry *f, struct sk_buff *skb,
++ unsigned int qid_filterid, struct adapter *adap)
++{
++ struct cpl_t6_act_open_req *t6req = NULL;
++ struct cpl_act_open_req *req = NULL;
++
++ t6req = (struct cpl_t6_act_open_req *)__skb_put(skb, sizeof(*t6req));
++ INIT_TP_WR(t6req, 0);
++ req = (struct cpl_act_open_req *)t6req;
++ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, qid_filterid));
++ req->local_port = cpu_to_be16(f->fs.val.lport);
++ req->peer_port = cpu_to_be16(f->fs.val.fport);
++ req->local_ip = f->fs.val.lip[0] | f->fs.val.lip[1] << 8 |
++ f->fs.val.lip[2] << 16 | f->fs.val.lip[3] << 24;
++ req->peer_ip = f->fs.val.fip[0] | f->fs.val.fip[1] << 8 |
++ f->fs.val.fip[2] << 16 | f->fs.val.fip[3] << 24;
++ req->opt0 = cpu_to_be64(NAGLE_V(f->fs.newvlan == VLAN_REMOVE ||
++ f->fs.newvlan == VLAN_REWRITE) |
++ DELACK_V(f->fs.hitcnts) |
++ L2T_IDX_V(f->l2t ? f->l2t->idx : 0) |
++ SMAC_SEL_V((cxgb4_port_viid(f->dev) &
++ 0x7F) << 1) |
++ TX_CHAN_V(f->fs.eport) |
++ NO_CONG_V(f->fs.rpttid) |
++ ULP_MODE_V(f->fs.nat_mode ?
++ ULP_MODE_TCPDDP : ULP_MODE_NONE) |
++ TCAM_BYPASS_F | NON_OFFLOAD_F);
++
++ t6req->params = cpu_to_be64(FILTER_TUPLE_V(hash_filter_ntuple(&f->fs,
++ f->dev)));
++ t6req->opt2 = htonl(RSS_QUEUE_VALID_F |
++ RSS_QUEUE_V(f->fs.iq) |
++ TX_QUEUE_V(f->fs.nat_mode) |
++ T5_OPT_2_VALID_F |
++ RX_CHANNEL_F |
++ CONG_CNTRL_V((f->fs.action == FILTER_DROP) |
++ (f->fs.dirsteer << 1)) |
++ PACE_V((f->fs.maskhash) |
++ ((f->fs.dirsteerhash) << 1)) |
++ CCTRL_ECN_V(f->fs.action == FILTER_SWITCH));
++}
++
++static int cxgb4_set_hash_filter(struct net_device *dev,
++ struct ch_filter_specification *fs,
++ struct filter_ctx *ctx)
++{
++ struct adapter *adapter = netdev2adap(dev);
++ struct tid_info *t = &adapter->tids;
++ struct filter_entry *f;
++ struct sk_buff *skb;
++ int iq, atid, size;
++ int ret = 0;
++ u32 iconf;
++
++ fill_default_mask(fs);
++ ret = validate_filter(dev, fs);
++ if (ret)
++ return ret;
++
++ iq = get_filter_steerq(dev, fs);
++ if (iq < 0)
++ return iq;
++
++ f = kzalloc(sizeof(*f), GFP_KERNEL);
++ if (!f)
++ return -ENOMEM;
++
++ f->fs = *fs;
++ f->ctx = ctx;
++ f->dev = dev;
++ f->fs.iq = iq;
++
++ /* If the new filter requires loopback Destination MAC and/or VLAN
++ * rewriting then we need to allocate a Layer 2 Table (L2T) entry for
++ * the filter.
++ */
++ if (f->fs.newdmac || f->fs.newvlan) {
++ /* allocate L2T entry for new filter */
++ f->l2t = t4_l2t_alloc_switching(adapter, f->fs.vlan,
++ f->fs.eport, f->fs.dmac);
++ if (!f->l2t) {
++ ret = -ENOMEM;
++ goto out_err;
++ }
++ }
++
++ /* If the new filter requires loopback Source MAC rewriting then
++ * we need to allocate a SMT entry for the filter.
++ */
++ if (f->fs.newsmac) {
++ f->smt = cxgb4_smt_alloc_switching(f->dev, f->fs.smac);
++ if (!f->smt) {
++ if (f->l2t) {
++ cxgb4_l2t_release(f->l2t);
++ f->l2t = NULL;
++ }
++ ret = -ENOMEM;
++ goto free_l2t;
++ }
++ }
++
++ atid = cxgb4_alloc_atid(t, f);
++ if (atid < 0)
++ goto free_smt;
++
++ iconf = adapter->params.tp.ingress_config;
++ if (iconf & VNIC_F) {
++ f->fs.val.ovlan = (fs->val.pf << 13) | fs->val.vf;
++ f->fs.mask.ovlan = (fs->mask.pf << 13) | fs->mask.vf;
++ f->fs.val.ovlan_vld = fs->val.pfvf_vld;
++ f->fs.mask.ovlan_vld = fs->mask.pfvf_vld;
++ }
++
++ size = sizeof(struct cpl_t6_act_open_req);
++ if (f->fs.type) {
++ ret = cxgb4_clip_get(f->dev, (const u32 *)&f->fs.val.lip, 1);
++ if (ret)
++ goto free_atid;
++
++ skb = alloc_skb(size, GFP_KERNEL);
++ if (!skb) {
++ ret = -ENOMEM;
++ goto free_clip;
++ }
++
++ mk_act_open_req6(f, skb,
++ ((adapter->sge.fw_evtq.abs_id << 14) | atid),
++ adapter);
++ } else {
++ skb = alloc_skb(size, GFP_KERNEL);
++ if (!skb) {
++ ret = -ENOMEM;
++ goto free_atid;
++ }
++
++ mk_act_open_req(f, skb,
++ ((adapter->sge.fw_evtq.abs_id << 14) | atid),
++ adapter);
++ }
++
++ f->pending = 1;
++ set_wr_txq(skb, CPL_PRIORITY_SETUP, f->fs.val.iport & 0x3);
++ t4_ofld_send(adapter, skb);
++ return 0;
++
++free_clip:
++ cxgb4_clip_release(f->dev, (const u32 *)&f->fs.val.lip, 1);
++
++free_atid:
++ cxgb4_free_atid(t, atid);
++
++free_smt:
++ if (f->smt) {
++ cxgb4_smt_release(f->smt);
++ f->smt = NULL;
++ }
++
++free_l2t:
++ if (f->l2t) {
++ cxgb4_l2t_release(f->l2t);
++ f->l2t = NULL;
++ }
++
++out_err:
++ kfree(f);
++ return ret;
++}
++
+ /* Check a Chelsio Filter Request for validity, convert it into our internal
+ * format and send it to the hardware. Return 0 on success, an error number
+ * otherwise. We attach any provided filter operation context to the internal
+@@ -580,6 +981,14 @@ int __cxgb4_set_filter(struct net_device
+ u32 iconf;
+ int iq, ret;
+
++ if (fs->hash) {
++ if (is_hashfilter(adapter))
++ return cxgb4_set_hash_filter(dev, fs, ctx);
++ netdev_err(dev, "%s: Exact-match filters only supported with Hash Filter configuration\n",
++ __func__);
++ return -EINVAL;
++ }
++
+ max_fidx = adapter->tids.nftids;
+ if (filter_id != (max_fidx + adapter->tids.nsftids - 1) &&
+ filter_id >= max_fidx)
+@@ -789,60 +1198,126 @@ out:
+ return ret;
+ }
+
+-static int set_tcb_field(struct adapter *adap, struct filter_entry *f,
+- unsigned int ftid, u16 word, u64 mask, u64 val,
+- int no_reply)
++static int configure_filter_tcb(struct adapter *adap, unsigned int tid,
++ struct filter_entry *f)
+ {
+- struct cpl_set_tcb_field *req;
+- struct sk_buff *skb;
+-
+- skb = alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_ATOMIC);
+- if (!skb)
+- return -ENOMEM;
+-
+- req = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*req));
+- memset(req, 0, sizeof(*req));
+- INIT_TP_WR_CPL(req, CPL_SET_TCB_FIELD, ftid);
+- req->reply_ctrl = htons(REPLY_CHAN_V(0) |
+- QUEUENO_V(adap->sge.fw_evtq.abs_id) |
+- NO_REPLY_V(no_reply));
+- req->word_cookie = htons(TCB_WORD_V(word) | TCB_COOKIE_V(ftid));
+- req->mask = cpu_to_be64(mask);
+- req->val = cpu_to_be64(val);
+- set_wr_txq(skb, CPL_PRIORITY_CONTROL, f->fs.val.iport & 0x3);
+- t4_ofld_send(adap, skb);
++ if (f->fs.hitcnts)
++ set_tcb_field(adap, f, tid, TCB_TIMESTAMP_W,
++ TCB_TIMESTAMP_V(TCB_TIMESTAMP_M) |
++ TCB_RTT_TS_RECENT_AGE_V(TCB_RTT_TS_RECENT_AGE_M),
++ TCB_TIMESTAMP_V(0ULL) |
++ TCB_RTT_TS_RECENT_AGE_V(0ULL),
++ 1);
++
++ if (f->fs.newdmac)
++ set_tcb_tflag(adap, f, tid, TF_CCTRL_ECE_S, 1,
++ 1);
++
++ if (f->fs.newvlan == VLAN_INSERT ||
++ f->fs.newvlan == VLAN_REWRITE)
++ set_tcb_tflag(adap, f, tid, TF_CCTRL_RFR_S, 1,
++ 1);
++ if (f->fs.newsmac)
++ configure_filter_smac(adap, f);
++
++ if (f->fs.nat_mode) {
++ switch (f->fs.nat_mode) {
++ case NAT_MODE_DIP:
++ set_nat_params(adap, f, tid, true, false, false, false);
++ break;
++
++ case NAT_MODE_DIP_DP:
++ set_nat_params(adap, f, tid, true, false, true, false);
++ break;
++
++ case NAT_MODE_DIP_DP_SIP:
++ set_nat_params(adap, f, tid, true, true, true, false);
++ break;
++ case NAT_MODE_DIP_DP_SP:
++ set_nat_params(adap, f, tid, true, false, true, true);
++ break;
++
++ case NAT_MODE_SIP_SP:
++ set_nat_params(adap, f, tid, false, true, false, true);
++ break;
++
++ case NAT_MODE_DIP_SIP_SP:
++ set_nat_params(adap, f, tid, true, true, false, true);
++ break;
++
++ case NAT_MODE_ALL:
++ set_nat_params(adap, f, tid, true, true, true, true);
++ break;
++
++ default:
++ pr_err("%s: Invalid NAT mode: %d\n",
++ __func__, f->fs.nat_mode);
++ return -EINVAL;
++ }
++ }
+ return 0;
+ }
+
+-/* Set one of the t_flags bits in the TCB.
+- */
+-static int set_tcb_tflag(struct adapter *adap, struct filter_entry *f,
+- unsigned int ftid, unsigned int bit_pos,
+- unsigned int val, int no_reply)
++void hash_filter_rpl(struct adapter *adap, const struct cpl_act_open_rpl *rpl)
+ {
+- return set_tcb_field(adap, f, ftid, TCB_T_FLAGS_W, 1ULL << bit_pos,
+- (unsigned long long)val << bit_pos, no_reply);
+-}
++ unsigned int ftid = TID_TID_G(AOPEN_ATID_G(ntohl(rpl->atid_status)));
++ unsigned int status = AOPEN_STATUS_G(ntohl(rpl->atid_status));
++ struct tid_info *t = &adap->tids;
++ unsigned int tid = GET_TID(rpl);
++ struct filter_ctx *ctx = NULL;
++ struct filter_entry *f;
+
+-static int configure_filter_smac(struct adapter *adap, struct filter_entry *f)
+-{
+- int err;
++ dev_dbg(adap->pdev_dev, "%s: tid = %u; atid = %u; status = %u\n",
++ __func__, tid, ftid, status);
+
+- /* do a set-tcb for smac-sel and CWR bit.. */
+- err = set_tcb_tflag(adap, f, f->tid, TF_CCTRL_CWR_S, 1, 1);
+- if (err)
+- goto smac_err;
++ f = lookup_atid(t, ftid);
++ if (!f) {
++ dev_err(adap->pdev_dev, "%s:could not find filter entry",
++ __func__);
++ return;
++ }
++ ctx = f->ctx;
++ f->ctx = NULL;
+
+- err = set_tcb_field(adap, f, f->tid, TCB_SMAC_SEL_W,
+- TCB_SMAC_SEL_V(TCB_SMAC_SEL_M),
+- TCB_SMAC_SEL_V(f->smt->idx), 1);
+- if (!err)
+- return 0;
++ switch (status) {
++ case CPL_ERR_NONE:
++ f->tid = tid;
++ f->pending = 0;
++ f->valid = 1;
++ cxgb4_insert_tid(t, f, f->tid, 0);
++ cxgb4_free_atid(t, ftid);
++ if (ctx) {
++ ctx->tid = f->tid;
++ ctx->result = 0;
++ }
++ if (configure_filter_tcb(adap, tid, f)) {
++ clear_filter(adap, f);
++ cxgb4_remove_tid(t, 0, tid, 0);
++ kfree(f);
++ if (ctx) {
++ ctx->result = -EINVAL;
++ complete(&ctx->completion);
++ }
++ return;
++ }
++ break;
+
+-smac_err:
+- dev_err(adap->pdev_dev, "filter %u smac config failed with error %u\n",
+- f->tid, err);
+- return err;
++ default:
++ dev_err(adap->pdev_dev, "%s: filter creation PROBLEM; status = %u\n",
++ __func__, status);
++
++ if (ctx) {
++ if (status == CPL_ERR_TCAM_FULL)
++ ctx->result = -EAGAIN;
++ else
++ ctx->result = -EINVAL;
++ }
++ clear_filter(adap, f);
++ cxgb4_free_atid(t, ftid);
++ kfree(f);
++ }
++ if (ctx)
++ complete(&ctx->completion);
+ }
+
+ /* Handle a filter write/deletion reply. */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h
+@@ -37,7 +37,10 @@
+
+ #include "t4_msg.h"
+
++#define WORD_MASK 0xffffffff
++
+ void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl);
++void hash_filter_rpl(struct adapter *adap, const struct cpl_act_open_rpl *rpl);
+ void clear_filter(struct adapter *adap, struct filter_entry *f);
+
+ int set_filter_wr(struct adapter *adapter, int fidx);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -572,6 +572,10 @@ static int fwevtq_handler(struct sge_rsp
+ const struct cpl_set_tcb_rpl *p = (void *)rsp;
+
+ filter_rpl(q->adap, p);
++ } else if (opcode == CPL_ACT_OPEN_RPL) {
++ const struct cpl_act_open_rpl *p = (void *)rsp;
++
++ hash_filter_rpl(q->adap, p);
+ } else
+ dev_err(q->adap->pdev_dev,
+ "unexpected CPL %#x on FW event queue\n", opcode);
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+@@ -286,6 +286,7 @@ struct work_request_hdr {
+
+ #define RX_CHANNEL_S 26
+ #define RX_CHANNEL_V(x) ((x) << RX_CHANNEL_S)
++#define RX_CHANNEL_F RX_CHANNEL_V(1U)
+
+ #define WND_SCALE_EN_S 28
+ #define WND_SCALE_EN_V(x) ((x) << WND_SCALE_EN_S)
+@@ -315,6 +316,10 @@ struct cpl_pass_open_req {
+ #define DELACK_V(x) ((x) << DELACK_S)
+ #define DELACK_F DELACK_V(1U)
+
++#define NON_OFFLOAD_S 7
++#define NON_OFFLOAD_V(x) ((x) << NON_OFFLOAD_S)
++#define NON_OFFLOAD_F NON_OFFLOAD_V(1U)
++
+ #define DSCP_S 22
+ #define DSCP_M 0x3F
+ #define DSCP_V(x) ((x) << DSCP_S)
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h
+@@ -42,6 +42,23 @@
+
+ #define TCB_T_FLAGS_W 1
+
++#define TF_CCTRL_ECE_S 60
+ #define TF_CCTRL_CWR_S 61
++#define TF_CCTRL_RFR_S 62
+
++#define TCB_TIMESTAMP_W 5
++#define TCB_TIMESTAMP_S 0
++#define TCB_TIMESTAMP_M 0xffffffffULL
++#define TCB_TIMESTAMP_V(x) ((x) << TCB_TIMESTAMP_S)
++
++#define TCB_RTT_TS_RECENT_AGE_W 6
++#define TCB_RTT_TS_RECENT_AGE_S 0
++#define TCB_RTT_TS_RECENT_AGE_M 0xffffffffULL
++#define TCB_RTT_TS_RECENT_AGE_V(x) ((x) << TCB_RTT_TS_RECENT_AGE_S)
++
++#define TCB_SND_UNA_RAW_W 10
++#define TCB_RX_FRAG2_PTR_RAW_W 27
++#define TCB_RX_FRAG3_LEN_RAW_W 29
++#define TCB_RX_FRAG3_START_IDX_OFFSET_RAW_W 30
++#define TCB_PDU_HDR_LEN_W 31
+ #endif /* __T4_TCB_H */
diff --git a/patches.drivers/cxgb4-add-support-to-delete-hash-filter.patch b/patches.drivers/cxgb4-add-support-to-delete-hash-filter.patch
new file mode 100644
index 0000000000..5e4eade975
--- /dev/null
+++ b/patches.drivers/cxgb4-add-support-to-delete-hash-filter.patch
@@ -0,0 +1,325 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Wed, 1 Nov 2017 08:53:02 +0530
+Subject: cxgb4: add support to delete hash filter
+Patch-mainline: v4.15-rc1
+Git-commit: 3b0b3bee56dd4e5cd1976a046f391a1435d727b2
+References: bsc#1064802 bsc#1066129
+
+Use a combined ulptx work-request to send hash filter deletion
+request to hw. Hash filter deletion reply is processed on
+getting cpl_abort_rpl_rss.
+
+Release any L2T/SMT/CLIP entries on filter deletion.
+Also, free up the corresponding filter entry.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 159 ++++++++++++++++++-
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h | 2
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 4
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 2
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c | 4
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 4
+ drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h | 5
+ 7 files changed, 173 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+@@ -87,6 +87,59 @@ static int set_tcb_tflag(struct adapter
+ (unsigned long long)val << bit_pos, no_reply);
+ }
+
++static void mk_abort_req_ulp(struct cpl_abort_req *abort_req, unsigned int tid)
++{
++ struct ulp_txpkt *txpkt = (struct ulp_txpkt *)abort_req;
++ struct ulptx_idata *sc = (struct ulptx_idata *)(txpkt + 1);
++
++ txpkt->cmd_dest = htonl(ULPTX_CMD_V(ULP_TX_PKT) | ULP_TXPKT_DEST_V(0));
++ txpkt->len = htonl(DIV_ROUND_UP(sizeof(*abort_req), 16));
++ sc->cmd_more = htonl(ULPTX_CMD_V(ULP_TX_SC_IMM));
++ sc->len = htonl(sizeof(*abort_req) - sizeof(struct work_request_hdr));
++ OPCODE_TID(abort_req) = htonl(MK_OPCODE_TID(CPL_ABORT_REQ, tid));
++ abort_req->rsvd0 = htonl(0);
++ abort_req->rsvd1 = 0;
++ abort_req->cmd = CPL_ABORT_NO_RST;
++}
++
++static void mk_abort_rpl_ulp(struct cpl_abort_rpl *abort_rpl, unsigned int tid)
++{
++ struct ulp_txpkt *txpkt = (struct ulp_txpkt *)abort_rpl;
++ struct ulptx_idata *sc = (struct ulptx_idata *)(txpkt + 1);
++
++ txpkt->cmd_dest = htonl(ULPTX_CMD_V(ULP_TX_PKT) | ULP_TXPKT_DEST_V(0));
++ txpkt->len = htonl(DIV_ROUND_UP(sizeof(*abort_rpl), 16));
++ sc->cmd_more = htonl(ULPTX_CMD_V(ULP_TX_SC_IMM));
++ sc->len = htonl(sizeof(*abort_rpl) - sizeof(struct work_request_hdr));
++ OPCODE_TID(abort_rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, tid));
++ abort_rpl->rsvd0 = htonl(0);
++ abort_rpl->rsvd1 = 0;
++ abort_rpl->cmd = CPL_ABORT_NO_RST;
++}
++
++static void mk_set_tcb_ulp(struct filter_entry *f,
++ struct cpl_set_tcb_field *req,
++ unsigned int word, u64 mask, u64 val,
++ u8 cookie, int no_reply)
++{
++ struct ulp_txpkt *txpkt = (struct ulp_txpkt *)req;
++ struct ulptx_idata *sc = (struct ulptx_idata *)(txpkt + 1);
++
++ txpkt->cmd_dest = htonl(ULPTX_CMD_V(ULP_TX_PKT) | ULP_TXPKT_DEST_V(0));
++ txpkt->len = htonl(DIV_ROUND_UP(sizeof(*req), 16));
++ sc->cmd_more = htonl(ULPTX_CMD_V(ULP_TX_SC_IMM));
++ sc->len = htonl(sizeof(*req) - sizeof(struct work_request_hdr));
++ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, f->tid));
++ req->reply_ctrl = htons(NO_REPLY_V(no_reply) | REPLY_CHAN_V(0) |
++ QUEUENO_V(0));
++ req->word_cookie = htons(TCB_WORD_V(word) | TCB_COOKIE_V(cookie));
++ req->mask = cpu_to_be64(mask);
++ req->val = cpu_to_be64(val);
++ sc = (struct ulptx_idata *)(req + 1);
++ sc->cmd_more = htonl(ULPTX_CMD_V(ULP_TX_SC_NOOP));
++ sc->len = htonl(0);
++}
++
+ static int configure_filter_smac(struct adapter *adap, struct filter_entry *f)
+ {
+ int err;
+@@ -1110,12 +1163,74 @@ int __cxgb4_set_filter(struct net_device
+ return ret;
+ }
+
++static int cxgb4_del_hash_filter(struct net_device *dev, int filter_id,
++ struct filter_ctx *ctx)
++{
++ struct adapter *adapter = netdev2adap(dev);
++ struct tid_info *t = &adapter->tids;
++ struct cpl_abort_req *abort_req;
++ struct cpl_abort_rpl *abort_rpl;
++ struct cpl_set_tcb_field *req;
++ struct ulptx_idata *aligner;
++ struct work_request_hdr *wr;
++ struct filter_entry *f;
++ struct sk_buff *skb;
++ unsigned int wrlen;
++ int ret;
++
++ netdev_dbg(dev, "%s: filter_id = %d ; nftids = %d\n",
++ __func__, filter_id, adapter->tids.nftids);
++
++ if (filter_id > adapter->tids.ntids)
++ return -E2BIG;
++
++ f = lookup_tid(t, filter_id);
++ if (!f) {
++ netdev_err(dev, "%s: no filter entry for filter_id = %d",
++ __func__, filter_id);
++ return -EINVAL;
++ }
++
++ ret = writable_filter(f);
++ if (ret)
++ return ret;
++
++ if (!f->valid)
++ return -EINVAL;
++
++ f->ctx = ctx;
++ f->pending = 1;
++ wrlen = roundup(sizeof(*wr) + (sizeof(*req) + sizeof(*aligner))
++ + sizeof(*abort_req) + sizeof(*abort_rpl), 16);
++ skb = alloc_skb(wrlen, GFP_KERNEL);
++ if (!skb) {
++ netdev_err(dev, "%s: could not allocate skb ..\n", __func__);
++ return -ENOMEM;
++ }
++ set_wr_txq(skb, CPL_PRIORITY_CONTROL, f->fs.val.iport & 0x3);
++ req = (struct cpl_set_tcb_field *)__skb_put(skb, wrlen);
++ INIT_ULPTX_WR(req, wrlen, 0, 0);
++ wr = (struct work_request_hdr *)req;
++ wr++;
++ req = (struct cpl_set_tcb_field *)wr;
++ mk_set_tcb_ulp(f, req, TCB_RSS_INFO_W, TCB_RSS_INFO_V(TCB_RSS_INFO_M),
++ TCB_RSS_INFO_V(adapter->sge.fw_evtq.abs_id), 0, 1);
++ aligner = (struct ulptx_idata *)(req + 1);
++ abort_req = (struct cpl_abort_req *)(aligner + 1);
++ mk_abort_req_ulp(abort_req, f->tid);
++ abort_rpl = (struct cpl_abort_rpl *)(abort_req + 1);
++ mk_abort_rpl_ulp(abort_rpl, f->tid);
++ t4_ofld_send(adapter, skb);
++ return 0;
++}
++
+ /* Check a delete filter request for validity and send it to the hardware.
+ * Return 0 on success, an error number otherwise. We attach any provided
+ * filter operation context to the internal filter specification in order to
+ * facilitate signaling completion of the operation.
+ */
+ int __cxgb4_del_filter(struct net_device *dev, int filter_id,
++ struct ch_filter_specification *fs,
+ struct filter_ctx *ctx)
+ {
+ struct adapter *adapter = netdev2adap(dev);
+@@ -1123,6 +1238,14 @@ int __cxgb4_del_filter(struct net_device
+ unsigned int max_fidx;
+ int ret;
+
++ if (fs && fs->hash) {
++ if (is_hashfilter(adapter))
++ return cxgb4_del_hash_filter(dev, filter_id, ctx);
++ netdev_err(dev, "%s: Exact-match filters only supported with Hash Filter configuration\n",
++ __func__);
++ return -EINVAL;
++ }
++
+ max_fidx = adapter->tids.nftids;
+ if (filter_id != (max_fidx + adapter->tids.nsftids - 1) &&
+ filter_id >= max_fidx)
+@@ -1173,18 +1296,19 @@ out:
+ return ret;
+ }
+
+-int cxgb4_del_filter(struct net_device *dev, int filter_id)
++int cxgb4_del_filter(struct net_device *dev, int filter_id,
++ struct ch_filter_specification *fs)
+ {
+ struct filter_ctx ctx;
+ int ret;
+
+ /* If we are shutting down the adapter do not wait for completion */
+ if (netdev2adap(dev)->flags & SHUTTING_DOWN)
+- return __cxgb4_del_filter(dev, filter_id, NULL);
++ return __cxgb4_del_filter(dev, filter_id, fs, NULL);
+
+ init_completion(&ctx.completion);
+
+- ret = __cxgb4_del_filter(dev, filter_id, &ctx);
++ ret = __cxgb4_del_filter(dev, filter_id, fs, &ctx);
+ if (ret)
+ goto out;
+
+@@ -1258,6 +1382,35 @@ static int configure_filter_tcb(struct a
+ return 0;
+ }
+
++void hash_del_filter_rpl(struct adapter *adap,
++ const struct cpl_abort_rpl_rss *rpl)
++{
++ unsigned int status = rpl->status;
++ struct tid_info *t = &adap->tids;
++ unsigned int tid = GET_TID(rpl);
++ struct filter_ctx *ctx = NULL;
++ struct filter_entry *f;
++
++ dev_dbg(adap->pdev_dev, "%s: status = %u; tid = %u\n",
++ __func__, status, tid);
++
++ f = lookup_tid(t, tid);
++ if (!f) {
++ dev_err(adap->pdev_dev, "%s:could not find filter entry",
++ __func__);
++ return;
++ }
++ ctx = f->ctx;
++ f->ctx = NULL;
++ clear_filter(adap, f);
++ cxgb4_remove_tid(t, 0, tid, 0);
++ kfree(f);
++ if (ctx) {
++ ctx->result = 0;
++ complete(&ctx->completion);
++ }
++}
++
+ void hash_filter_rpl(struct adapter *adap, const struct cpl_act_open_rpl *rpl)
+ {
+ unsigned int ftid = TID_TID_G(AOPEN_ATID_G(ntohl(rpl->atid_status)));
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h
+@@ -41,6 +41,8 @@
+
+ void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl);
+ void hash_filter_rpl(struct adapter *adap, const struct cpl_act_open_rpl *rpl);
++void hash_del_filter_rpl(struct adapter *adap,
++ const struct cpl_abort_rpl_rss *rpl);
+ void clear_filter(struct adapter *adap, struct filter_entry *f);
+
+ int set_filter_wr(struct adapter *adapter, int fidx);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -576,6 +576,10 @@ static int fwevtq_handler(struct sge_rsp
+ const struct cpl_act_open_rpl *p = (void *)rsp;
+
+ hash_filter_rpl(q->adap, p);
++ } else if (opcode == CPL_ABORT_RPL_RSS) {
++ const struct cpl_abort_rpl_rss *p = (void *)rsp;
++
++ hash_del_filter_rpl(q->adap, p);
+ } else
+ dev_err(q->adap->pdev_dev,
+ "unexpected CPL %#x on FW event queue\n", opcode);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+@@ -730,7 +730,7 @@ int cxgb4_tc_flower_destroy(struct net_d
+ if (!ch_flower)
+ return -ENOENT;
+
+- ret = cxgb4_del_filter(dev, ch_flower->filter_id);
++ ret = cxgb4_del_filter(dev, ch_flower->filter_id, &ch_flower->fs);
+ if (ret)
+ goto err;
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c
+@@ -380,7 +380,7 @@ int cxgb4_delete_knode(struct net_device
+ return -EINVAL;
+ }
+
+- ret = cxgb4_del_filter(dev, filter_id);
++ ret = cxgb4_del_filter(dev, filter_id, NULL);
+ if (ret)
+ goto out;
+
+@@ -399,7 +399,7 @@ int cxgb4_delete_knode(struct net_device
+ if (!test_bit(j, link->tid_map))
+ continue;
+
+- ret = __cxgb4_del_filter(dev, j, NULL);
++ ret = __cxgb4_del_filter(dev, j, NULL, NULL);
+ if (ret)
+ goto out;
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+@@ -217,10 +217,12 @@ int __cxgb4_set_filter(struct net_device
+ struct ch_filter_specification *fs,
+ struct filter_ctx *ctx);
+ int __cxgb4_del_filter(struct net_device *dev, int filter_id,
++ struct ch_filter_specification *fs,
+ struct filter_ctx *ctx);
+ int cxgb4_set_filter(struct net_device *dev, int filter_id,
+ struct ch_filter_specification *fs);
+-int cxgb4_del_filter(struct net_device *dev, int filter_id);
++int cxgb4_del_filter(struct net_device *dev, int filter_id,
++ struct ch_filter_specification *fs);
+ int cxgb4_get_filter_counters(struct net_device *dev, unsigned int fidx,
+ u64 *hitcnt, u64 *bytecnt);
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h
+@@ -46,6 +46,11 @@
+ #define TF_CCTRL_CWR_S 61
+ #define TF_CCTRL_RFR_S 62
+
++#define TCB_RSS_INFO_W 3
++#define TCB_RSS_INFO_S 0
++#define TCB_RSS_INFO_M 0x3ffULL
++#define TCB_RSS_INFO_V(x) ((x) << TCB_RSS_INFO_S)
++
+ #define TCB_TIMESTAMP_W 5
+ #define TCB_TIMESTAMP_S 0
+ #define TCB_TIMESTAMP_M 0xffffffffULL
diff --git a/patches.drivers/cxgb4-add-support-to-offload-action-vlan.patch b/patches.drivers/cxgb4-add-support-to-offload-action-vlan.patch
new file mode 100644
index 0000000000..5e3c61c95a
--- /dev/null
+++ b/patches.drivers/cxgb4-add-support-to-offload-action-vlan.patch
@@ -0,0 +1,84 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Thu, 21 Sep 2017 23:41:15 +0530
+Subject: cxgb4: add support to offload action vlan
+Patch-mainline: v4.15-rc1
+Git-commit: cf2885a70fc71d5f6b434b86eedfc18ad66ba6f6
+References: bsc#1064802 bsc#1066129
+
+Add support for offloading tc-flower flows having
+vlan actions: pop, push and modify.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 42 +++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+@@ -34,6 +34,7 @@
+
+ #include <net/tc_act/tc_gact.h>
+ #include <net/tc_act/tc_mirred.h>
++#include <net/tc_act/tc_vlan.h>
+
+ #include "cxgb4.h"
+ #include "cxgb4_tc_flower.h"
+@@ -185,6 +186,27 @@ static void cxgb4_process_flow_actions(s
+
+ fs->action = FILTER_SWITCH;
+ fs->eport = pi->port_id;
++ } else if (is_tcf_vlan(a)) {
++ u32 vlan_action = tcf_vlan_action(a);
++ u8 prio = tcf_vlan_push_prio(a);
++ u16 vid = tcf_vlan_push_vid(a);
++ u16 vlan_tci = (prio << VLAN_PRIO_SHIFT) | vid;
++
++ switch (vlan_action) {
++ case TCA_VLAN_ACT_POP:
++ fs->newvlan |= VLAN_REMOVE;
++ break;
++ case TCA_VLAN_ACT_PUSH:
++ fs->newvlan |= VLAN_INSERT;
++ fs->vlan = vlan_tci;
++ break;
++ case TCA_VLAN_ACT_MODIFY:
++ fs->newvlan |= VLAN_REWRITE;
++ fs->vlan = vlan_tci;
++ break;
++ default:
++ break;
++ }
+ }
+ }
+ }
+@@ -222,6 +244,26 @@ static int cxgb4_validate_flow_actions(s
+ __func__);
+ return -EINVAL;
+ }
++ } else if (is_tcf_vlan(a)) {
++ u16 proto = be16_to_cpu(tcf_vlan_push_proto(a));
++ u32 vlan_action = tcf_vlan_action(a);
++
++ switch (vlan_action) {
++ case TCA_VLAN_ACT_POP:
++ break;
++ case TCA_VLAN_ACT_PUSH:
++ case TCA_VLAN_ACT_MODIFY:
++ if (proto != ETH_P_8021Q) {
++ netdev_err(dev, "%s: Unsupported vlan proto\n",
++ __func__);
++ return -EOPNOTSUPP;
++ }
++ break;
++ default:
++ netdev_err(dev, "%s: Unsupported vlan action\n",
++ __func__);
++ return -EOPNOTSUPP;
++ }
+ } else {
+ netdev_err(dev, "%s: Unsupported action\n", __func__);
+ return -EOPNOTSUPP;
diff --git a/patches.drivers/cxgb4-add-support-to-retrieve-stats-for-hash-filters.patch b/patches.drivers/cxgb4-add-support-to-retrieve-stats-for-hash-filters.patch
new file mode 100644
index 0000000000..a03d53d833
--- /dev/null
+++ b/patches.drivers/cxgb4-add-support-to-retrieve-stats-for-hash-filters.patch
@@ -0,0 +1,113 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Wed, 1 Nov 2017 08:53:03 +0530
+Subject: cxgb4: add support to retrieve stats for hash filters
+Patch-mainline: v4.15-rc1
+Git-commit: 9d922d4b016d3d7908dd70112aaf46a38313d866
+References: bsc#1064802 bsc#1066129
+
+Add support to retrieve packet-count and byte-count for hash-filters
+by retrieving filter-entry appropriately based on whether the
+request is for hash-filter or not.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 32 ++++++++++++-------
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 6 ++-
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 2 -
+ 3 files changed, 26 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+@@ -341,7 +341,7 @@ static int get_filter_steerq(struct net_
+ }
+
+ static int get_filter_count(struct adapter *adapter, unsigned int fidx,
+- u64 *pkts, u64 *bytes)
++ u64 *pkts, u64 *bytes, bool hash)
+ {
+ unsigned int tcb_base, tcbaddr;
+ unsigned int word_offset;
+@@ -350,14 +350,24 @@ static int get_filter_count(struct adapt
+ int ret;
+
+ tcb_base = t4_read_reg(adapter, TP_CMM_TCB_BASE_A);
+- if ((fidx != (adapter->tids.nftids + adapter->tids.nsftids - 1)) &&
+- fidx >= adapter->tids.nftids)
+- return -E2BIG;
+-
+- f = &adapter->tids.ftid_tab[fidx];
+- if (!f->valid)
+- return -EINVAL;
+-
++ if (is_hashfilter(adapter) && hash) {
++ if (fidx < adapter->tids.ntids) {
++ f = adapter->tids.tid_tab[fidx];
++ if (!f)
++ return -EINVAL;
++ } else {
++ return -E2BIG;
++ }
++ } else {
++ if ((fidx != (adapter->tids.nftids +
++ adapter->tids.nsftids - 1)) &&
++ fidx >= adapter->tids.nftids)
++ return -E2BIG;
++
++ f = &adapter->tids.ftid_tab[fidx];
++ if (!f->valid)
++ return -EINVAL;
++ }
+ tcbaddr = tcb_base + f->tid * TCB_SIZE;
+
+ spin_lock(&adapter->win0_lock);
+@@ -409,11 +419,11 @@ out:
+ }
+
+ int cxgb4_get_filter_counters(struct net_device *dev, unsigned int fidx,
+- u64 *hitcnt, u64 *bytecnt)
++ u64 *hitcnt, u64 *bytecnt, bool hash)
+ {
+ struct adapter *adapter = netdev2adap(dev);
+
+- return get_filter_count(adapter, fidx, hitcnt, bytecnt);
++ return get_filter_count(adapter, fidx, hitcnt, bytecnt, hash);
+ }
+
+ int cxgb4_get_free_ftid(struct net_device *dev, int family)
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+@@ -755,7 +755,8 @@ static void ch_flower_stats_cb(unsigned
+ hash_for_each_rcu(adap->flower_anymatch_tbl, i, flower_entry, link) {
+ ret = cxgb4_get_filter_counters(adap->port[0],
+ flower_entry->filter_id,
+- &packets, &bytes);
++ &packets, &bytes,
++ flower_entry->fs.hash);
+ if (!ret) {
+ spin_lock(&flower_entry->lock);
+ ofld_stats = &flower_entry->stats;
+@@ -788,7 +789,8 @@ int cxgb4_tc_flower_stats(struct net_dev
+ }
+
+ ret = cxgb4_get_filter_counters(dev, ch_flower->filter_id,
+- &packets, &bytes);
++ &packets, &bytes,
++ ch_flower->fs.hash);
+ if (ret < 0)
+ goto err;
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+@@ -224,7 +224,7 @@ int cxgb4_set_filter(struct net_device *
+ int cxgb4_del_filter(struct net_device *dev, int filter_id,
+ struct ch_filter_specification *fs);
+ int cxgb4_get_filter_counters(struct net_device *dev, unsigned int fidx,
+- u64 *hitcnt, u64 *bytecnt);
++ u64 *hitcnt, u64 *bytecnt, bool hash);
+
+ static inline void set_wr_txq(struct sk_buff *skb, int prio, int queue)
+ {
diff --git a/patches.drivers/cxgb4-add-tc-flower-match-support-for-TOS.patch b/patches.drivers/cxgb4-add-tc-flower-match-support-for-TOS.patch
new file mode 100644
index 0000000000..b43b901312
--- /dev/null
+++ b/patches.drivers/cxgb4-add-tc-flower-match-support-for-TOS.patch
@@ -0,0 +1,95 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Wed, 18 Oct 2017 20:49:07 +0530
+Subject: cxgb4: add tc flower match support for TOS
+Patch-mainline: v4.15-rc1
+Git-commit: bda1e229153fbdd0efd22a14c1c76a28c05d1b27
+References: bsc#1064802 bsc#1066129
+
+Add support for matching on IP TOS. Also check on ethtype value
+to be either IPv4 or IPv6.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 51 ++++++++++++++++++-
+ 1 file changed, 50 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+@@ -147,6 +147,19 @@ static void cxgb4_process_flow_match(str
+ fs->mask.fport = cpu_to_be16(mask->src);
+ }
+
++ if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_IP)) {
++ struct flow_dissector_key_ip *key, *mask;
++
++ key = skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_IP,
++ cls->key);
++ mask = skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_IP,
++ cls->mask);
++ fs->val.tos = key->tos;
++ fs->mask.tos = mask->tos;
++ }
++
+ /* Match only packets coming from the ingress port where this
+ * filter will be created.
+ */
+@@ -157,16 +170,52 @@ static void cxgb4_process_flow_match(str
+ static int cxgb4_validate_flow_match(struct net_device *dev,
+ struct tc_cls_flower_offload *cls)
+ {
++ u16 ethtype_mask = 0;
++ u16 ethtype_key = 0;
++
+ if (cls->dissector->used_keys &
+ ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+- BIT(FLOW_DISSECTOR_KEY_PORTS))) {
++ BIT(FLOW_DISSECTOR_KEY_PORTS) |
++ BIT(FLOW_DISSECTOR_KEY_IP))) {
+ netdev_warn(dev, "Unsupported key used: 0x%x\n",
+ cls->dissector->used_keys);
+ return -EOPNOTSUPP;
+ }
++
++ if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
++ struct flow_dissector_key_basic *key =
++ skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_BASIC,
++ cls->key);
++ struct flow_dissector_key_basic *mask =
++ skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_BASIC,
++ cls->mask);
++ ethtype_key = ntohs(key->n_proto);
++ ethtype_mask = ntohs(mask->n_proto);
++ }
++
++ if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_IP)) {
++ u16 eth_ip_type = ethtype_key & ethtype_mask;
++ struct flow_dissector_key_ip *mask;
++
++ if (eth_ip_type != ETH_P_IP && eth_ip_type != ETH_P_IPV6) {
++ netdev_err(dev, "IP Key supported only with IPv4/v6");
++ return -EINVAL;
++ }
++
++ mask = skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_IP,
++ cls->mask);
++ if (mask->ttl) {
++ netdev_warn(dev, "ttl match unsupported for offload");
++ return -EOPNOTSUPP;
++ }
++ }
++
+ return 0;
+ }
+
diff --git a/patches.drivers/cxgb4-add-tc-flower-match-support-for-vlan.patch b/patches.drivers/cxgb4-add-tc-flower-match-support-for-vlan.patch
new file mode 100644
index 0000000000..86c4b8c024
--- /dev/null
+++ b/patches.drivers/cxgb4-add-tc-flower-match-support-for-vlan.patch
@@ -0,0 +1,70 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Wed, 18 Oct 2017 20:49:08 +0530
+Subject: cxgb4: add tc flower match support for vlan
+Patch-mainline: v4.15-rc1
+Git-commit: ad9af3e09cb6b201db56190d92eb3ffe469a0bc4
+References: bsc#1064802 bsc#1066129
+
+Add support for matching on vlan tci. Construct vlan tci match param
+based on vlan-id and vlan-pcp values supplied by tc.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 35 +++++++++++++++++++
+ 1 file changed, 35 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+@@ -160,6 +160,40 @@ static void cxgb4_process_flow_match(str
+ fs->mask.tos = mask->tos;
+ }
+
++ if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
++ struct flow_dissector_key_vlan *key, *mask;
++ u16 vlan_tci, vlan_tci_mask;
++
++ key = skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_VLAN,
++ cls->key);
++ mask = skb_flow_dissector_target(cls->dissector,
++ FLOW_DISSECTOR_KEY_VLAN,
++ cls->mask);
++ vlan_tci = key->vlan_id | (key->vlan_priority <<
++ VLAN_PRIO_SHIFT);
++ vlan_tci_mask = mask->vlan_id | (mask->vlan_priority <<
++ VLAN_PRIO_SHIFT);
++ fs->val.ivlan = cpu_to_be16(vlan_tci);
++ fs->mask.ivlan = cpu_to_be16(vlan_tci_mask);
++
++ /* Chelsio adapters use ivlan_vld bit to match vlan packets
++ * as 802.1Q. Also, when vlan tag is present in packets,
++ * ethtype match is used then to match on ethtype of inner
++ * header ie. the header following the vlan header.
++ * So, set the ivlan_vld based on ethtype info supplied by
++ * TC for vlan packets if its 802.1Q. And then reset the
++ * ethtype value else, hw will try to match the supplied
++ * ethtype value with ethtype of inner header.
++ */
++ if (fs->val.ethtype == ETH_P_8021Q) {
++ fs->val.ivlan_vld = 1;
++ fs->mask.ivlan_vld = 1;
++ fs->val.ethtype = 0;
++ fs->mask.ethtype = 0;
++ }
++ }
++
+ /* Match only packets coming from the ingress port where this
+ * filter will be created.
+ */
+@@ -179,6 +213,7 @@ static int cxgb4_validate_flow_match(str
+ BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT(FLOW_DISSECTOR_KEY_PORTS) |
++ BIT(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT(FLOW_DISSECTOR_KEY_IP))) {
+ netdev_warn(dev, "Unsupported key used: 0x%x\n",
+ cls->dissector->used_keys);
diff --git a/patches.drivers/cxgb4-add-tc-flower-offload-skeleton.patch b/patches.drivers/cxgb4-add-tc-flower-offload-skeleton.patch
new file mode 100644
index 0000000000..5c07521fed
--- /dev/null
+++ b/patches.drivers/cxgb4-add-tc-flower-offload-skeleton.patch
@@ -0,0 +1,190 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Thu, 21 Sep 2017 23:41:13 +0530
+Subject: cxgb4: add tc flower offload skeleton
+Patch-mainline: v4.15-rc1
+Git-commit: 6a345b3dbd1ed83a7877993c6e23c977a84bb483
+References: bsc#1064802 bsc#1066129
+
+Add basic skeleton to prepare for offloading tc-flower flows.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/Makefile | 4 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 22 +++++++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 57 +++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h | 46 +++++++++++++++
+ 4 files changed, 128 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+ create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/Makefile
++++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile
+@@ -4,7 +4,9 @@
+
+ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o
+
+-cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o cxgb4_uld.o sched.o cxgb4_filter.o cxgb4_tc_u32.o cxgb4_ptp.o
++cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o \
++ cxgb4_uld.o sched.o cxgb4_filter.o cxgb4_tc_u32.o \
++ cxgb4_ptp.o cxgb4_tc_flower.o
+ cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o
+ cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o
+ cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -79,6 +79,7 @@
+ #include "l2t.h"
+ #include "sched.h"
+ #include "cxgb4_tc_u32.h"
++#include "cxgb4_tc_flower.h"
+ #include "cxgb4_ptp.h"
+
+ char cxgb4_driver_name[] = KBUILD_MODNAME;
+@@ -2873,6 +2874,25 @@ static int cxgb_set_tx_maxrate(struct ne
+ return err;
+ }
+
++static int cxgb_setup_tc_flower(struct net_device *dev,
++ struct tc_cls_flower_offload *cls_flower)
++{
++ if (!is_classid_clsact_ingress(cls_flower->common.classid) ||
++ cls_flower->common.chain_index)
++ return -EOPNOTSUPP;
++
++ switch (cls_flower->command) {
++ case TC_CLSFLOWER_REPLACE:
++ return cxgb4_tc_flower_replace(dev, cls_flower);
++ case TC_CLSFLOWER_DESTROY:
++ return cxgb4_tc_flower_destroy(dev, cls_flower);
++ case TC_CLSFLOWER_STATS:
++ return cxgb4_tc_flower_stats(dev, cls_flower);
++ default:
++ return -EOPNOTSUPP;
++ }
++}
++
+ static int cxgb_setup_tc_cls_u32(struct net_device *dev,
+ struct tc_cls_u32_offload *cls_u32)
+ {
+@@ -2907,6 +2927,8 @@ static int cxgb_setup_tc(struct net_devi
+ switch (type) {
+ case TC_SETUP_CLSU32:
+ return cxgb_setup_tc_cls_u32(dev, type_data);
++ case TC_SETUP_CLSFLOWER:
++ return cxgb_setup_tc_flower(dev, type_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+--- /dev/null
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+@@ -0,0 +1,57 @@
++/*
++ * This file is part of the Chelsio T4/T5/T6 Ethernet driver for Linux.
++ *
++ * Copyright (c) 2017 Chelsio Communications, Inc. All rights reserved.
++ *
++ * This software is available to you under a choice of one of two
++ * licenses. You may choose to be licensed under the terms of the GNU
++ * General Public License (GPL) Version 2, available from the file
++ * COPYING in the main directory of this source tree, or the
++ * OpenIB.org BSD license below:
++ *
++ * Redistribution and use in source and binary forms, with or
++ * without modification, are permitted provided that the following
++ * conditions are met:
++ *
++ * - Redistributions of source code must retain the above
++ * copyright notice, this list of conditions and the following
++ * disclaimer.
++ *
++ * - Redistributions in binary form must reproduce the above
++ * copyright notice, this list of conditions and the following
++ * disclaimer in the documentation and/or other materials
++ * provided with the distribution.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++ */
++
++#include <net/tc_act/tc_gact.h>
++#include <net/tc_act/tc_mirred.h>
++
++#include "cxgb4.h"
++#include "cxgb4_tc_flower.h"
++
++int cxgb4_tc_flower_replace(struct net_device *dev,
++ struct tc_cls_flower_offload *cls)
++{
++ return -EOPNOTSUPP;
++}
++
++int cxgb4_tc_flower_destroy(struct net_device *dev,
++ struct tc_cls_flower_offload *cls)
++{
++ return -EOPNOTSUPP;
++}
++
++int cxgb4_tc_flower_stats(struct net_device *dev,
++ struct tc_cls_flower_offload *cls)
++{
++ return -EOPNOTSUPP;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
+@@ -0,0 +1,46 @@
++/*
++ * This file is part of the Chelsio T4/T5/T6 Ethernet driver for Linux.
++ *
++ * Copyright (c) 2017 Chelsio Communications, Inc. All rights reserved.
++ *
++ * This software is available to you under a choice of one of two
++ * licenses. You may choose to be licensed under the terms of the GNU
++ * General Public License (GPL) Version 2, available from the file
++ * COPYING in the main directory of this source tree, or the
++ * OpenIB.org BSD license below:
++ *
++ * Redistribution and use in source and binary forms, with or
++ * without modification, are permitted provided that the following
++ * conditions are met:
++ *
++ * - Redistributions of source code must retain the above
++ * copyright notice, this list of conditions and the following
++ * disclaimer.
++ *
++ * - Redistributions in binary form must reproduce the above
++ * copyright notice, this list of conditions and the following
++ * disclaimer in the documentation and/or other materials
++ * provided with the distribution.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++ */
++
++#ifndef __CXGB4_TC_FLOWER_H
++#define __CXGB4_TC_FLOWER_H
++
++#include <net/pkt_cls.h>
++
++int cxgb4_tc_flower_replace(struct net_device *dev,
++ struct tc_cls_flower_offload *cls);
++int cxgb4_tc_flower_destroy(struct net_device *dev,
++ struct tc_cls_flower_offload *cls);
++int cxgb4_tc_flower_stats(struct net_device *dev,
++ struct tc_cls_flower_offload *cls);
++#endif /* __CXGB4_TC_FLOWER_H */
diff --git a/patches.drivers/cxgb4-add-tc-flower-support-for-ETH-DMAC-rewrite.patch b/patches.drivers/cxgb4-add-tc-flower-support-for-ETH-DMAC-rewrite.patch
new file mode 100644
index 0000000000..e71316ffc2
--- /dev/null
+++ b/patches.drivers/cxgb4-add-tc-flower-support-for-ETH-DMAC-rewrite.patch
@@ -0,0 +1,214 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Wed, 18 Oct 2017 20:49:10 +0530
+Subject: cxgb4: add tc flower support for ETH-DMAC rewrite
+Patch-mainline: v4.15-rc1
+Git-commit: 27ece1f357b71c63e6e35c645b9c344835d4a129
+References: bsc#1064802 bsc#1066129
+
+Add support for ETH-DMAC Rewrite via TC-PEDIT action. Also, add
+check to assert that vlan/eth-dmac rewrite actions are valid only
+in combination with action egress redirect.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 108 ++++++++++++++++++-
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h | 19 +++
+ 2 files changed, 126 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+@@ -32,8 +32,9 @@
+ * SOFTWARE.
+ */
+
+-#include <net/tc_act/tc_gact.h>
+ #include <net/tc_act/tc_mirred.h>
++#include <net/tc_act/tc_pedit.h>
++#include <net/tc_act/tc_gact.h>
+ #include <net/tc_act/tc_vlan.h>
+
+ #include "cxgb4.h"
+@@ -41,6 +42,11 @@
+
+ #define STATS_CHECK_PERIOD (HZ / 2)
+
++struct ch_tc_pedit_fields pedits[] = {
++ PEDIT_FIELDS(ETH_, DMAC_31_0, 4, dmac, 0),
++ PEDIT_FIELDS(ETH_, DMAC_47_32, 2, dmac, 4),
++};
++
+ static struct ch_tc_flower_entry *allocate_flower_entry(void)
+ {
+ struct ch_tc_flower_entry *new = kzalloc(sizeof(*new), GFP_KERNEL);
+@@ -254,6 +260,41 @@ static int cxgb4_validate_flow_match(str
+ return 0;
+ }
+
++static void offload_pedit(struct ch_filter_specification *fs, u32 val, u32 mask,
++ u8 field)
++{
++ u32 set_val = val & ~mask;
++ u32 offset;
++ u8 size;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(pedits); i++) {
++ if (pedits[i].field == field) {
++ offset = pedits[i].offset;
++ size = pedits[i].size;
++ break;
++ }
++ }
++ memcpy((u8 *)fs + offset, &set_val, size);
++}
++
++static void process_pedit_field(struct ch_filter_specification *fs, u32 val,
++ u32 mask, u32 offset, u8 htype)
++{
++ switch (htype) {
++ case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH:
++ switch (offset) {
++ case PEDIT_ETH_DMAC_31_0:
++ fs->newdmac = 1;
++ offload_pedit(fs, val, mask, ETH_DMAC_31_0);
++ break;
++ case PEDIT_ETH_DMAC_47_32_SMAC_15_0:
++ if (~mask & PEDIT_ETH_DMAC_MASK)
++ offload_pedit(fs, val, mask, ETH_DMAC_47_32);
++ }
++ }
++}
++
+ static void cxgb4_process_flow_actions(struct net_device *in,
+ struct tc_cls_flower_offload *cls,
+ struct ch_filter_specification *fs)
+@@ -296,6 +337,21 @@ static void cxgb4_process_flow_actions(s
+ default:
+ break;
+ }
++ } else if (is_tcf_pedit(a)) {
++ u32 mask, val, offset;
++ int nkeys, i;
++ u8 htype;
++
++ nkeys = tcf_pedit_nkeys(a);
++ for (i = 0; i < nkeys; i++) {
++ htype = tcf_pedit_htype(a, i);
++ mask = tcf_pedit_mask(a, i);
++ val = tcf_pedit_val(a, i);
++ offset = tcf_pedit_offset(a, i);
++
++ process_pedit_field(fs, val, mask, offset,
++ htype);
++ }
+ }
+ }
+ }
+@@ -304,6 +360,9 @@ static int cxgb4_validate_flow_actions(s
+ struct tc_cls_flower_offload *cls)
+ {
+ const struct tc_action *a;
++ bool act_redir = false;
++ bool act_pedit = false;
++ bool act_vlan = false;
+ LIST_HEAD(actions);
+
+ tcf_exts_to_list(cls->exts, &actions);
+@@ -335,6 +394,7 @@ static int cxgb4_validate_flow_actions(s
+ __func__);
+ return -EINVAL;
+ }
++ act_redir = true;
+ } else if (is_tcf_vlan(a)) {
+ u16 proto = be16_to_cpu(tcf_vlan_push_proto(a));
+ u32 vlan_action = tcf_vlan_action(a);
+@@ -355,11 +415,57 @@ static int cxgb4_validate_flow_actions(s
+ __func__);
+ return -EOPNOTSUPP;
+ }
++ act_vlan = true;
++ } else if (is_tcf_pedit(a)) {
++ u32 mask, val, offset;
++ u8 cmd, htype;
++ int nkeys, i;
++
++ nkeys = tcf_pedit_nkeys(a);
++ for (i = 0; i < nkeys; i++) {
++ htype = tcf_pedit_htype(a, i);
++ cmd = tcf_pedit_cmd(a, i);
++ mask = tcf_pedit_mask(a, i);
++ val = tcf_pedit_val(a, i);
++ offset = tcf_pedit_offset(a, i);
++
++ if (cmd != TCA_PEDIT_KEY_EX_CMD_SET) {
++ netdev_err(dev, "%s: Unsupported pedit cmd\n",
++ __func__);
++ return -EOPNOTSUPP;
++ }
++
++ switch (htype) {
++ case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH:
++ switch (offset) {
++ case PEDIT_ETH_DMAC_31_0:
++ case PEDIT_ETH_DMAC_47_32_SMAC_15_0:
++ break;
++ default:
++ netdev_err(dev, "%s: Unsupported pedit field\n",
++ __func__);
++ return -EOPNOTSUPP;
++ }
++ break;
++ default:
++ netdev_err(dev, "%s: Unsupported pedit type\n",
++ __func__);
++ return -EOPNOTSUPP;
++ }
++ }
++ act_pedit = true;
+ } else {
+ netdev_err(dev, "%s: Unsupported action\n", __func__);
+ return -EOPNOTSUPP;
+ }
+ }
++
++ if ((act_pedit || act_vlan) && !act_redir) {
++ netdev_err(dev, "%s: pedit/vlan rewrite invalid without egress redirect\n",
++ __func__);
++ return -EINVAL;
++ }
++
+ return 0;
+ }
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
+@@ -54,6 +54,25 @@ struct ch_tc_flower_entry {
+ u32 filter_id;
+ };
+
++enum {
++ ETH_DMAC_31_0, /* dmac bits 0.. 31 */
++ ETH_DMAC_47_32, /* dmac bits 32..47 */
++};
++
++struct ch_tc_pedit_fields {
++ u8 field;
++ u8 size;
++ u32 offset;
++};
++
++#define PEDIT_FIELDS(type, field, size, fs_field, offset) \
++ { type## field, size, \
++ offsetof(struct ch_filter_specification, fs_field) + (offset) }
++
++#define PEDIT_ETH_DMAC_MASK 0xffff
++#define PEDIT_ETH_DMAC_31_0 0x0
++#define PEDIT_ETH_DMAC_47_32_SMAC_15_0 0x4
++
+ int cxgb4_tc_flower_replace(struct net_device *dev,
+ struct tc_cls_flower_offload *cls);
+ int cxgb4_tc_flower_destroy(struct net_device *dev,
diff --git a/patches.drivers/cxgb4-add-tc-flower-support-for-ETH-SMAC-rewrite.patch b/patches.drivers/cxgb4-add-tc-flower-support-for-ETH-SMAC-rewrite.patch
new file mode 100644
index 0000000000..d4096d3eb0
--- /dev/null
+++ b/patches.drivers/cxgb4-add-tc-flower-support-for-ETH-SMAC-rewrite.patch
@@ -0,0 +1,71 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Wed, 18 Oct 2017 20:49:12 +0530
+Subject: cxgb4: add tc flower support for ETH-SMAC rewrite
+Patch-mainline: v4.15-rc1
+Git-commit: 202187c34c7e3efd9662a25977cddef6e7dec572
+References: bsc#1064802 bsc#1066129
+
+Adds support for ETH-SMAC rewrite via TC-PEDIT action.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 10 ++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h | 3 +++
+ 2 files changed, 13 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+@@ -45,6 +45,8 @@
+ struct ch_tc_pedit_fields pedits[] = {
+ PEDIT_FIELDS(ETH_, DMAC_31_0, 4, dmac, 0),
+ PEDIT_FIELDS(ETH_, DMAC_47_32, 2, dmac, 4),
++ PEDIT_FIELDS(ETH_, SMAC_15_0, 2, smac, 0),
++ PEDIT_FIELDS(ETH_, SMAC_47_16, 4, smac, 2),
+ };
+
+ static struct ch_tc_flower_entry *allocate_flower_entry(void)
+@@ -291,6 +293,13 @@ static void process_pedit_field(struct c
+ case PEDIT_ETH_DMAC_47_32_SMAC_15_0:
+ if (~mask & PEDIT_ETH_DMAC_MASK)
+ offload_pedit(fs, val, mask, ETH_DMAC_47_32);
++ else
++ offload_pedit(fs, val >> 16, mask >> 16,
++ ETH_SMAC_15_0);
++ break;
++ case PEDIT_ETH_SMAC_47_16:
++ fs->newsmac = 1;
++ offload_pedit(fs, val, mask, ETH_SMAC_47_16);
+ }
+ }
+ }
+@@ -440,6 +449,7 @@ static int cxgb4_validate_flow_actions(s
+ switch (offset) {
+ case PEDIT_ETH_DMAC_31_0:
+ case PEDIT_ETH_DMAC_47_32_SMAC_15_0:
++ case PEDIT_ETH_SMAC_47_16:
+ break;
+ default:
+ netdev_err(dev, "%s: Unsupported pedit field\n",
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
+@@ -57,6 +57,8 @@ struct ch_tc_flower_entry {
+ enum {
+ ETH_DMAC_31_0, /* dmac bits 0.. 31 */
+ ETH_DMAC_47_32, /* dmac bits 32..47 */
++ ETH_SMAC_15_0, /* smac bits 0.. 15 */
++ ETH_SMAC_47_16, /* smac bits 16..47 */
+ };
+
+ struct ch_tc_pedit_fields {
+@@ -72,6 +74,7 @@ struct ch_tc_pedit_fields {
+ #define PEDIT_ETH_DMAC_MASK 0xffff
+ #define PEDIT_ETH_DMAC_31_0 0x0
+ #define PEDIT_ETH_DMAC_47_32_SMAC_15_0 0x4
++#define PEDIT_ETH_SMAC_47_16 0x8
+
+ int cxgb4_tc_flower_replace(struct net_device *dev,
+ struct tc_cls_flower_offload *cls);
diff --git a/patches.drivers/cxgb4-add-tc-flower-support-for-L3-L4-rewrite.patch b/patches.drivers/cxgb4-add-tc-flower-support-for-L3-L4-rewrite.patch
new file mode 100644
index 0000000000..eb682c8d02
--- /dev/null
+++ b/patches.drivers/cxgb4-add-tc-flower-support-for-L3-L4-rewrite.patch
@@ -0,0 +1,396 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Wed, 18 Oct 2017 20:49:14 +0530
+Subject: cxgb4: add tc flower support for L3/L4 rewrite
+Patch-mainline: v4.15-rc1
+Git-commit: 557ccbf9dfa8de133b9247af42f0c5760bb103f0
+References: bsc#1064802 bsc#1066129
+
+Adds support to rewrite L3/L4 fields via TC-PEDIT action.
+Supported fields for rewrite are:
+IPv4 src/dst address, IPv6 src/dst address, TCP/UDP sport/dport.
+
+Also, process match fields first and then process the action items.
+
+Refactor pedit action validation to separate function to avoid
+excessive code indentation.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 4
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 245 ++++++++++++++++---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h | 32 ++
+ 3 files changed, 244 insertions(+), 37 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -1097,6 +1097,10 @@ enum {
+ VLAN_REWRITE
+ };
+
++enum {
++ NAT_MODE_ALL = 7, /* NAT on entire 4-tuple */
++};
++
+ /* Host shadow copy of ingress filter entry. This is in host native format
+ * and doesn't match the ordering or bit order, etc. of the hardware of the
+ * firmware command. The use of bit-field structure elements is purely to
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+@@ -47,6 +47,20 @@ struct ch_tc_pedit_fields pedits[] = {
+ PEDIT_FIELDS(ETH_, DMAC_47_32, 2, dmac, 4),
+ PEDIT_FIELDS(ETH_, SMAC_15_0, 2, smac, 0),
+ PEDIT_FIELDS(ETH_, SMAC_47_16, 4, smac, 2),
++ PEDIT_FIELDS(IP4_, SRC, 4, nat_fip, 0),
++ PEDIT_FIELDS(IP4_, DST, 4, nat_lip, 0),
++ PEDIT_FIELDS(IP6_, SRC_31_0, 4, nat_fip, 0),
++ PEDIT_FIELDS(IP6_, SRC_63_32, 4, nat_fip, 4),
++ PEDIT_FIELDS(IP6_, SRC_95_64, 4, nat_fip, 8),
++ PEDIT_FIELDS(IP6_, SRC_127_96, 4, nat_fip, 12),
++ PEDIT_FIELDS(IP6_, DST_31_0, 4, nat_lip, 0),
++ PEDIT_FIELDS(IP6_, DST_63_32, 4, nat_lip, 4),
++ PEDIT_FIELDS(IP6_, DST_95_64, 4, nat_lip, 8),
++ PEDIT_FIELDS(IP6_, DST_127_96, 4, nat_lip, 12),
++ PEDIT_FIELDS(TCP_, SPORT, 2, nat_fport, 0),
++ PEDIT_FIELDS(TCP_, DPORT, 2, nat_lport, 0),
++ PEDIT_FIELDS(UDP_, SPORT, 2, nat_fport, 0),
++ PEDIT_FIELDS(UDP_, DPORT, 2, nat_lport, 0),
+ };
+
+ static struct ch_tc_flower_entry *allocate_flower_entry(void)
+@@ -121,6 +135,11 @@ static void cxgb4_process_flow_match(str
+ memcpy(&fs->val.fip[0], &key->src, sizeof(key->src));
+ memcpy(&fs->mask.lip[0], &mask->dst, sizeof(mask->dst));
+ memcpy(&fs->mask.fip[0], &mask->src, sizeof(mask->src));
++
++ /* also initialize nat_lip/fip to same values */
++ memcpy(&fs->nat_lip[0], &key->dst, sizeof(key->dst));
++ memcpy(&fs->nat_fip[0], &key->src, sizeof(key->src));
++
+ }
+
+ if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
+@@ -138,6 +157,10 @@ static void cxgb4_process_flow_match(str
+ memcpy(&fs->val.fip[0], key->src.s6_addr, sizeof(key->src));
+ memcpy(&fs->mask.lip[0], mask->dst.s6_addr, sizeof(mask->dst));
+ memcpy(&fs->mask.fip[0], mask->src.s6_addr, sizeof(mask->src));
++
++ /* also initialize nat_lip/fip to same values */
++ memcpy(&fs->nat_lip[0], key->dst.s6_addr, sizeof(key->dst));
++ memcpy(&fs->nat_fip[0], key->src.s6_addr, sizeof(key->src));
+ }
+
+ if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
+@@ -153,6 +176,10 @@ static void cxgb4_process_flow_match(str
+ fs->mask.lport = cpu_to_be16(mask->dst);
+ fs->val.fport = cpu_to_be16(key->src);
+ fs->mask.fport = cpu_to_be16(mask->src);
++
++ /* also initialize nat_lport/fport to same values */
++ fs->nat_lport = cpu_to_be16(key->dst);
++ fs->nat_fport = cpu_to_be16(key->src);
+ }
+
+ if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_IP)) {
+@@ -301,6 +328,70 @@ static void process_pedit_field(struct c
+ fs->newsmac = 1;
+ offload_pedit(fs, val, mask, ETH_SMAC_47_16);
+ }
++ break;
++ case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4:
++ switch (offset) {
++ case PEDIT_IP4_SRC:
++ offload_pedit(fs, val, mask, IP4_SRC);
++ break;
++ case PEDIT_IP4_DST:
++ offload_pedit(fs, val, mask, IP4_DST);
++ }
++ fs->nat_mode = NAT_MODE_ALL;
++ break;
++ case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6:
++ switch (offset) {
++ case PEDIT_IP6_SRC_31_0:
++ offload_pedit(fs, val, mask, IP6_SRC_31_0);
++ break;
++ case PEDIT_IP6_SRC_63_32:
++ offload_pedit(fs, val, mask, IP6_SRC_63_32);
++ break;
++ case PEDIT_IP6_SRC_95_64:
++ offload_pedit(fs, val, mask, IP6_SRC_95_64);
++ break;
++ case PEDIT_IP6_SRC_127_96:
++ offload_pedit(fs, val, mask, IP6_SRC_127_96);
++ break;
++ case PEDIT_IP6_DST_31_0:
++ offload_pedit(fs, val, mask, IP6_DST_31_0);
++ break;
++ case PEDIT_IP6_DST_63_32:
++ offload_pedit(fs, val, mask, IP6_DST_63_32);
++ break;
++ case PEDIT_IP6_DST_95_64:
++ offload_pedit(fs, val, mask, IP6_DST_95_64);
++ break;
++ case PEDIT_IP6_DST_127_96:
++ offload_pedit(fs, val, mask, IP6_DST_127_96);
++ }
++ fs->nat_mode = NAT_MODE_ALL;
++ break;
++ case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP:
++ switch (offset) {
++ case PEDIT_TCP_SPORT_DPORT:
++ if (~mask & PEDIT_TCP_UDP_SPORT_MASK)
++ offload_pedit(fs, cpu_to_be32(val) >> 16,
++ cpu_to_be32(mask) >> 16,
++ TCP_SPORT);
++ else
++ offload_pedit(fs, cpu_to_be32(val),
++ cpu_to_be32(mask), TCP_DPORT);
++ }
++ fs->nat_mode = NAT_MODE_ALL;
++ break;
++ case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP:
++ switch (offset) {
++ case PEDIT_UDP_SPORT_DPORT:
++ if (~mask & PEDIT_TCP_UDP_SPORT_MASK)
++ offload_pedit(fs, cpu_to_be32(val) >> 16,
++ cpu_to_be32(mask) >> 16,
++ UDP_SPORT);
++ else
++ offload_pedit(fs, cpu_to_be32(val),
++ cpu_to_be32(mask), UDP_DPORT);
++ }
++ fs->nat_mode = NAT_MODE_ALL;
+ }
+ }
+
+@@ -365,6 +456,119 @@ static void cxgb4_process_flow_actions(s
+ }
+ }
+
++static bool valid_l4_mask(u32 mask)
++{
++ u16 hi, lo;
++
++ /* Either the upper 16-bits (SPORT) OR the lower
++ * 16-bits (DPORT) can be set, but NOT BOTH.
++ */
++ hi = (mask >> 16) & 0xFFFF;
++ lo = mask & 0xFFFF;
++
++ return hi && lo ? false : true;
++}
++
++static bool valid_pedit_action(struct net_device *dev,
++ const struct tc_action *a)
++{
++ u32 mask, offset;
++ u8 cmd, htype;
++ int nkeys, i;
++
++ nkeys = tcf_pedit_nkeys(a);
++ for (i = 0; i < nkeys; i++) {
++ htype = tcf_pedit_htype(a, i);
++ cmd = tcf_pedit_cmd(a, i);
++ mask = tcf_pedit_mask(a, i);
++ offset = tcf_pedit_offset(a, i);
++
++ if (cmd != TCA_PEDIT_KEY_EX_CMD_SET) {
++ netdev_err(dev, "%s: Unsupported pedit cmd\n",
++ __func__);
++ return false;
++ }
++
++ switch (htype) {
++ case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH:
++ switch (offset) {
++ case PEDIT_ETH_DMAC_31_0:
++ case PEDIT_ETH_DMAC_47_32_SMAC_15_0:
++ case PEDIT_ETH_SMAC_47_16:
++ break;
++ default:
++ netdev_err(dev, "%s: Unsupported pedit field\n",
++ __func__);
++ return false;
++ }
++ break;
++ case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4:
++ switch (offset) {
++ case PEDIT_IP4_SRC:
++ case PEDIT_IP4_DST:
++ break;
++ default:
++ netdev_err(dev, "%s: Unsupported pedit field\n",
++ __func__);
++ return false;
++ }
++ break;
++ case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6:
++ switch (offset) {
++ case PEDIT_IP6_SRC_31_0:
++ case PEDIT_IP6_SRC_63_32:
++ case PEDIT_IP6_SRC_95_64:
++ case PEDIT_IP6_SRC_127_96:
++ case PEDIT_IP6_DST_31_0:
++ case PEDIT_IP6_DST_63_32:
++ case PEDIT_IP6_DST_95_64:
++ case PEDIT_IP6_DST_127_96:
++ break;
++ default:
++ netdev_err(dev, "%s: Unsupported pedit field\n",
++ __func__);
++ return false;
++ }
++ break;
++ case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP:
++ switch (offset) {
++ case PEDIT_TCP_SPORT_DPORT:
++ if (!valid_l4_mask(~mask)) {
++ netdev_err(dev, "%s: Unsupported mask for TCP L4 ports\n",
++ __func__);
++ return false;
++ }
++ break;
++ default:
++ netdev_err(dev, "%s: Unsupported pedit field\n",
++ __func__);
++ return false;
++ }
++ break;
++ case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP:
++ switch (offset) {
++ case PEDIT_UDP_SPORT_DPORT:
++ if (!valid_l4_mask(~mask)) {
++ netdev_err(dev, "%s: Unsupported mask for UDP L4 ports\n",
++ __func__);
++ return false;
++ }
++ break;
++ default:
++ netdev_err(dev, "%s: Unsupported pedit field\n",
++ __func__);
++ return false;
++ }
++ break;
++ default:
++ netdev_err(dev, "%s: Unsupported pedit type\n",
++ __func__);
++ return false;
++ }
++ }
++ return true;
++}
++
+ static int cxgb4_validate_flow_actions(struct net_device *dev,
+ struct tc_cls_flower_offload *cls)
+ {
+@@ -426,43 +630,10 @@ static int cxgb4_validate_flow_actions(s
+ }
+ act_vlan = true;
+ } else if (is_tcf_pedit(a)) {
+- u32 mask, val, offset;
+- u8 cmd, htype;
+- int nkeys, i;
++ bool pedit_valid = valid_pedit_action(dev, a);
+
+- nkeys = tcf_pedit_nkeys(a);
+- for (i = 0; i < nkeys; i++) {
+- htype = tcf_pedit_htype(a, i);
+- cmd = tcf_pedit_cmd(a, i);
+- mask = tcf_pedit_mask(a, i);
+- val = tcf_pedit_val(a, i);
+- offset = tcf_pedit_offset(a, i);
+-
+- if (cmd != TCA_PEDIT_KEY_EX_CMD_SET) {
+- netdev_err(dev, "%s: Unsupported pedit cmd\n",
+- __func__);
+- return -EOPNOTSUPP;
+- }
+-
+- switch (htype) {
+- case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH:
+- switch (offset) {
+- case PEDIT_ETH_DMAC_31_0:
+- case PEDIT_ETH_DMAC_47_32_SMAC_15_0:
+- case PEDIT_ETH_SMAC_47_16:
+- break;
+- default:
+- netdev_err(dev, "%s: Unsupported pedit field\n",
+- __func__);
+- return -EOPNOTSUPP;
+- }
+- break;
+- default:
+- netdev_err(dev, "%s: Unsupported pedit type\n",
+- __func__);
+- return -EOPNOTSUPP;
+- }
+- }
++ if (!pedit_valid)
++ return -EOPNOTSUPP;
+ act_pedit = true;
+ } else {
+ netdev_err(dev, "%s: Unsupported action\n", __func__);
+@@ -503,8 +674,8 @@ int cxgb4_tc_flower_replace(struct net_d
+
+ fs = &ch_flower->fs;
+ fs->hitcnts = 1;
+- cxgb4_process_flow_actions(dev, cls, fs);
+ cxgb4_process_flow_match(dev, cls, fs);
++ cxgb4_process_flow_actions(dev, cls, fs);
+
+ fidx = cxgb4_get_free_ftid(dev, fs->type ? PF_INET6 : PF_INET);
+ if (fidx < 0) {
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
+@@ -59,6 +59,25 @@ enum {
+ ETH_DMAC_47_32, /* dmac bits 32..47 */
+ ETH_SMAC_15_0, /* smac bits 0.. 15 */
+ ETH_SMAC_47_16, /* smac bits 16..47 */
++
++ IP4_SRC, /* 32-bit IPv4 src */
++ IP4_DST, /* 32-bit IPv4 dst */
++
++ IP6_SRC_31_0, /* src bits 0.. 31 */
++ IP6_SRC_63_32, /* src bits 63.. 32 */
++ IP6_SRC_95_64, /* src bits 95.. 64 */
++ IP6_SRC_127_96, /* src bits 127..96 */
++
++ IP6_DST_31_0, /* dst bits 0.. 31 */
++ IP6_DST_63_32, /* dst bits 63.. 32 */
++ IP6_DST_95_64, /* dst bits 95.. 64 */
++ IP6_DST_127_96, /* dst bits 127..96 */
++
++ TCP_SPORT, /* 16-bit TCP sport */
++ TCP_DPORT, /* 16-bit TCP dport */
++
++ UDP_SPORT, /* 16-bit UDP sport */
++ UDP_DPORT, /* 16-bit UDP dport */
+ };
+
+ struct ch_tc_pedit_fields {
+@@ -72,9 +91,22 @@ struct ch_tc_pedit_fields {
+ offsetof(struct ch_filter_specification, fs_field) + (offset) }
+
+ #define PEDIT_ETH_DMAC_MASK 0xffff
++#define PEDIT_TCP_UDP_SPORT_MASK 0xffff
+ #define PEDIT_ETH_DMAC_31_0 0x0
+ #define PEDIT_ETH_DMAC_47_32_SMAC_15_0 0x4
+ #define PEDIT_ETH_SMAC_47_16 0x8
++#define PEDIT_IP4_SRC 0xC
++#define PEDIT_IP4_DST 0x10
++#define PEDIT_IP6_SRC_31_0 0x8
++#define PEDIT_IP6_SRC_63_32 0xC
++#define PEDIT_IP6_SRC_95_64 0x10
++#define PEDIT_IP6_SRC_127_96 0x14
++#define PEDIT_IP6_DST_31_0 0x18
++#define PEDIT_IP6_DST_63_32 0x1C
++#define PEDIT_IP6_DST_95_64 0x20
++#define PEDIT_IP6_DST_127_96 0x24
++#define PEDIT_TCP_SPORT_DPORT 0x0
++#define PEDIT_UDP_SPORT_DPORT 0x0
+
+ int cxgb4_tc_flower_replace(struct net_device *dev,
+ struct tc_cls_flower_offload *cls);
diff --git a/patches.drivers/cxgb4-add-tc-flower-support-for-action-PASS.patch b/patches.drivers/cxgb4-add-tc-flower-support-for-action-PASS.patch
new file mode 100644
index 0000000000..253e8881df
--- /dev/null
+++ b/patches.drivers/cxgb4-add-tc-flower-support-for-action-PASS.patch
@@ -0,0 +1,42 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Wed, 18 Oct 2017 20:49:09 +0530
+Subject: cxgb4: add tc flower support for action PASS
+Patch-mainline: v4.15-rc1
+Git-commit: c39bff47d735e39fdbf59ad56df5581b0cf88c7c
+References: bsc#1064802 bsc#1066129
+
+Add support for tc flower action PASS.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+@@ -263,7 +263,9 @@ static void cxgb4_process_flow_actions(s
+
+ tcf_exts_to_list(cls->exts, &actions);
+ list_for_each_entry(a, &actions, list) {
+- if (is_tcf_gact_shot(a)) {
++ if (is_tcf_gact_ok(a)) {
++ fs->action = FILTER_PASS;
++ } else if (is_tcf_gact_shot(a)) {
+ fs->action = FILTER_DROP;
+ } else if (is_tcf_mirred_egress_redirect(a)) {
+ int ifindex = tcf_mirred_ifindex(a);
+@@ -306,7 +308,9 @@ static int cxgb4_validate_flow_actions(s
+
+ tcf_exts_to_list(cls->exts, &actions);
+ list_for_each_entry(a, &actions, list) {
+- if (is_tcf_gact_shot(a)) {
++ if (is_tcf_gact_ok(a)) {
++ /* Do nothing */
++ } else if (is_tcf_gact_shot(a)) {
+ /* Do nothing */
+ } else if (is_tcf_mirred_egress_redirect(a)) {
+ struct adapter *adap = netdev2adap(dev);
diff --git a/patches.drivers/cxgb4-avoid-stall-while-shutting-down-the-adapter.patch b/patches.drivers/cxgb4-avoid-stall-while-shutting-down-the-adapter.patch
new file mode 100644
index 0000000000..7830d010ee
--- /dev/null
+++ b/patches.drivers/cxgb4-avoid-stall-while-shutting-down-the-adapter.patch
@@ -0,0 +1,73 @@
+From: Ganesh Goudar <ganeshgr@chelsio.com>
+Date: Thu, 21 Sep 2017 12:50:47 +0530
+Subject: cxgb4: avoid stall while shutting down the adapter
+Patch-mainline: v4.15-rc1
+Git-commit: e1f6198e221f472c03b88e352432a01076ec8647
+References: bsc#1064802 bsc#1066129
+
+do not wait for completion while deleting the filters
+when the adapter is shutting down because we may not get
+the response as interrupts will be disabled.
+
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 7 ++++++-
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 4 ++++
+ 3 files changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -549,6 +549,7 @@ enum { /
+ MASTER_PF = (1 << 7),
+ FW_OFLD_CONN = (1 << 9),
+ ROOT_NO_RELAXED_ORDERING = (1 << 10),
++ SHUTTING_DOWN = (1 << 11),
+ };
+
+ enum {
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+@@ -191,7 +191,8 @@ static int del_filter_wr(struct adapter
+ return -ENOMEM;
+
+ fwr = __skb_put(skb, len);
+- t4_mk_filtdelwr(f->tid, fwr, adapter->sge.fw_evtq.abs_id);
++ t4_mk_filtdelwr(f->tid, fwr, (adapter->flags & SHUTTING_DOWN) ? -1
++ : adapter->sge.fw_evtq.abs_id);
+
+ /* Mark the filter as "pending" and ship off the Filter Work Request.
+ * When we get the Work Request Reply we'll clear the pending status.
+@@ -636,6 +637,10 @@ int cxgb4_del_filter(struct net_device *
+ struct filter_ctx ctx;
+ int ret;
+
++ /* If we are shutting down the adapter do not wait for completion */
++ if (netdev2adap(dev)->flags & SHUTTING_DOWN)
++ return __cxgb4_del_filter(dev, filter_id, NULL);
++
+ init_completion(&ctx.completion);
+
+ ret = __cxgb4_del_filter(dev, filter_id, &ctx);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -5254,6 +5254,8 @@ static void remove_one(struct pci_dev *p
+ return;
+ }
+
++ adapter->flags |= SHUTTING_DOWN;
++
+ if (adapter->pf == 4) {
+ int i;
+
+@@ -5339,6 +5341,8 @@ static void shutdown_one(struct pci_dev
+ return;
+ }
+
++ adapter->flags |= SHUTTING_DOWN;
++
+ if (adapter->pf == 4) {
+ int i;
+
diff --git a/patches.drivers/cxgb4-collect-CIM-queue-configuration-dump.patch b/patches.drivers/cxgb4-collect-CIM-queue-configuration-dump.patch
new file mode 100644
index 0000000000..535af37033
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-CIM-queue-configuration-dump.patch
@@ -0,0 +1,127 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Thu, 26 Oct 2017 17:18:34 +0530
+Subject: cxgb4: collect CIM queue configuration dump
+Patch-mainline: v4.15-rc1
+Git-commit: 3044d0fb016ecd953724c966bede8c8626f32bd5
+References: bsc#1064802 bsc#1066129
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 9 +++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 1
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 39 ++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 3 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 4 ++
+ 5 files changed, 56 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -33,6 +33,15 @@ struct cudbg_mbox_log {
+ u32 lo[MBOX_LEN / 8];
+ };
+
++struct cudbg_cim_qcfg {
++ u8 chip;
++ u16 base[CIM_NUM_IBQ + CIM_NUM_OBQ_T5];
++ u16 size[CIM_NUM_IBQ + CIM_NUM_OBQ_T5];
++ u16 thres[CIM_NUM_IBQ];
++ u32 obq_wr[2 * CIM_NUM_OBQ_T5];
++ u32 stat[4 * (CIM_NUM_IBQ + CIM_NUM_OBQ_T5)];
++};
++
+ struct ireg_field {
+ u32 ireg_addr;
+ u32 ireg_data;
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -31,6 +31,7 @@ enum cudbg_dbg_entity_type {
+ CUDBG_DEV_LOG = 2,
+ CUDBG_CIM_LA = 3,
+ CUDBG_CIM_MA_LA = 4,
++ CUDBG_CIM_QCFG = 5,
+ CUDBG_CIM_IBQ_TP0 = 6,
+ CUDBG_CIM_IBQ_TP1 = 7,
+ CUDBG_CIM_IBQ_ULP = 8,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -192,6 +192,45 @@ int cudbg_collect_cim_ma_la(struct cudbg
+ return rc;
+ }
+
++int cudbg_collect_cim_qcfg(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_cim_qcfg *cim_qcfg_data;
++ int rc;
++
++ rc = cudbg_get_buff(dbg_buff, sizeof(struct cudbg_cim_qcfg),
++ &temp_buff);
++ if (rc)
++ return rc;
++
++ cim_qcfg_data = (struct cudbg_cim_qcfg *)temp_buff.data;
++ cim_qcfg_data->chip = padap->params.chip;
++ rc = t4_cim_read(padap, UP_IBQ_0_RDADDR_A,
++ ARRAY_SIZE(cim_qcfg_data->stat), cim_qcfg_data->stat);
++ if (rc) {
++ cudbg_err->sys_err = rc;
++ cudbg_put_buff(&temp_buff, dbg_buff);
++ return rc;
++ }
++
++ rc = t4_cim_read(padap, UP_OBQ_0_REALADDR_A,
++ ARRAY_SIZE(cim_qcfg_data->obq_wr),
++ cim_qcfg_data->obq_wr);
++ if (rc) {
++ cudbg_err->sys_err = rc;
++ cudbg_put_buff(&temp_buff, dbg_buff);
++ return rc;
++ }
++
++ t4_read_cimq_cfg(padap, cim_qcfg_data->base, cim_qcfg_data->size,
++ cim_qcfg_data->thres);
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
+ static int cudbg_read_cim_ibq(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err, int qid)
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -30,6 +30,9 @@ int cudbg_collect_cim_la(struct cudbg_in
+ int cudbg_collect_cim_ma_la(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_qcfg(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_cim_ibq_tp0(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -31,6 +31,7 @@ static const struct cxgb4_collect_entity
+ { CUDBG_REG_DUMP, cudbg_collect_reg_dump },
+ { CUDBG_CIM_LA, cudbg_collect_cim_la },
+ { CUDBG_CIM_MA_LA, cudbg_collect_cim_ma_la },
++ { CUDBG_CIM_QCFG, cudbg_collect_cim_qcfg },
+ { CUDBG_CIM_IBQ_TP0, cudbg_collect_cim_ibq_tp0 },
+ { CUDBG_CIM_IBQ_TP1, cudbg_collect_cim_ibq_tp1 },
+ { CUDBG_CIM_IBQ_ULP, cudbg_collect_cim_ibq_ulp },
+@@ -92,6 +93,9 @@ static u32 cxgb4_get_entity_length(struc
+ case CUDBG_CIM_MA_LA:
+ len = 2 * CIM_MALA_SIZE * 5 * sizeof(u32);
+ break;
++ case CUDBG_CIM_QCFG:
++ len = sizeof(struct cudbg_cim_qcfg);
++ break;
+ case CUDBG_CIM_IBQ_TP0:
+ case CUDBG_CIM_IBQ_TP1:
+ case CUDBG_CIM_IBQ_ULP:
diff --git a/patches.drivers/cxgb4-collect-IBQ-and-OBQ-dumps.patch b/patches.drivers/cxgb4-collect-IBQ-and-OBQ-dumps.patch
new file mode 100644
index 0000000000..0416d00e78
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-IBQ-and-OBQ-dumps.patch
@@ -0,0 +1,327 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Fri, 13 Oct 2017 18:48:20 +0530
+Subject: cxgb4: collect IBQ and OBQ dumps
+Patch-mainline: v4.15-rc1
+Git-commit: 7c075ce221cf10a7aaef96b002d1d4c5dc715822
+References: bsc#1064802 bsc#1066129
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 14 +
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 165 +++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 42 +++++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 32 ++++
+ 4 files changed, 253 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -29,10 +29,24 @@
+ enum cudbg_dbg_entity_type {
+ CUDBG_REG_DUMP = 1,
+ CUDBG_DEV_LOG = 2,
++ CUDBG_CIM_IBQ_TP0 = 6,
++ CUDBG_CIM_IBQ_TP1 = 7,
++ CUDBG_CIM_IBQ_ULP = 8,
++ CUDBG_CIM_IBQ_SGE0 = 9,
++ CUDBG_CIM_IBQ_SGE1 = 10,
++ CUDBG_CIM_IBQ_NCSI = 11,
++ CUDBG_CIM_OBQ_ULP0 = 12,
++ CUDBG_CIM_OBQ_ULP1 = 13,
++ CUDBG_CIM_OBQ_ULP2 = 14,
++ CUDBG_CIM_OBQ_ULP3 = 15,
++ CUDBG_CIM_OBQ_SGE = 16,
++ CUDBG_CIM_OBQ_NCSI = 17,
+ CUDBG_EDC0 = 18,
+ CUDBG_EDC1 = 19,
+ CUDBG_TP_INDIRECT = 36,
+ CUDBG_SGE_INDIRECT = 37,
++ CUDBG_CIM_OBQ_RXQ0 = 47,
++ CUDBG_CIM_OBQ_RXQ1 = 48,
+ CUDBG_PCIE_INDIRECT = 50,
+ CUDBG_PM_INDIRECT = 51,
+ CUDBG_MA_INDIRECT = 61,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -129,6 +129,171 @@ int cudbg_collect_fw_devlog(struct cudbg
+ return rc;
+ }
+
++static int cudbg_read_cim_ibq(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err, int qid)
++{
++ struct adapter *padap = pdbg_init->adap;
++ struct cudbg_buffer temp_buff = { 0 };
++ int no_of_read_words, rc = 0;
++ u32 qsize;
++
++ /* collect CIM IBQ */
++ qsize = CIM_IBQ_SIZE * 4 * sizeof(u32);
++ rc = cudbg_get_buff(dbg_buff, qsize, &temp_buff);
++ if (rc)
++ return rc;
++
++ /* t4_read_cim_ibq will return no. of read words or error */
++ no_of_read_words = t4_read_cim_ibq(padap, qid,
++ (u32 *)((u32 *)temp_buff.data +
++ temp_buff.offset), qsize);
++ /* no_of_read_words is less than or equal to 0 means error */
++ if (no_of_read_words <= 0) {
++ if (!no_of_read_words)
++ rc = CUDBG_SYSTEM_ERROR;
++ else
++ rc = no_of_read_words;
++ 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_ibq_tp0(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ return cudbg_read_cim_ibq(pdbg_init, dbg_buff, cudbg_err, 0);
++}
++
++int cudbg_collect_cim_ibq_tp1(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ return cudbg_read_cim_ibq(pdbg_init, dbg_buff, cudbg_err, 1);
++}
++
++int cudbg_collect_cim_ibq_ulp(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ return cudbg_read_cim_ibq(pdbg_init, dbg_buff, cudbg_err, 2);
++}
++
++int cudbg_collect_cim_ibq_sge0(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ return cudbg_read_cim_ibq(pdbg_init, dbg_buff, cudbg_err, 3);
++}
++
++int cudbg_collect_cim_ibq_sge1(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ return cudbg_read_cim_ibq(pdbg_init, dbg_buff, cudbg_err, 4);
++}
++
++int cudbg_collect_cim_ibq_ncsi(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ return cudbg_read_cim_ibq(pdbg_init, dbg_buff, cudbg_err, 5);
++}
++
++static int cudbg_read_cim_obq(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err, int qid)
++{
++ struct adapter *padap = pdbg_init->adap;
++ struct cudbg_buffer temp_buff = { 0 };
++ int no_of_read_words, rc = 0;
++ u32 qsize;
++
++ /* collect CIM OBQ */
++ qsize = 6 * CIM_OBQ_SIZE * 4 * sizeof(u32);
++ rc = cudbg_get_buff(dbg_buff, qsize, &temp_buff);
++ if (rc)
++ return rc;
++
++ /* t4_read_cim_obq will return no. of read words or error */
++ no_of_read_words = t4_read_cim_obq(padap, qid,
++ (u32 *)((u32 *)temp_buff.data +
++ temp_buff.offset), qsize);
++ /* no_of_read_words is less than or equal to 0 means error */
++ if (no_of_read_words <= 0) {
++ if (!no_of_read_words)
++ rc = CUDBG_SYSTEM_ERROR;
++ else
++ rc = no_of_read_words;
++ cudbg_err->sys_err = rc;
++ cudbg_put_buff(&temp_buff, dbg_buff);
++ return rc;
++ }
++ temp_buff.size = no_of_read_words * 4;
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
++int cudbg_collect_cim_obq_ulp0(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ return cudbg_read_cim_obq(pdbg_init, dbg_buff, cudbg_err, 0);
++}
++
++int cudbg_collect_cim_obq_ulp1(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ return cudbg_read_cim_obq(pdbg_init, dbg_buff, cudbg_err, 1);
++}
++
++int cudbg_collect_cim_obq_ulp2(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ return cudbg_read_cim_obq(pdbg_init, dbg_buff, cudbg_err, 2);
++}
++
++int cudbg_collect_cim_obq_ulp3(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ return cudbg_read_cim_obq(pdbg_init, dbg_buff, cudbg_err, 3);
++}
++
++int cudbg_collect_cim_obq_sge(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ return cudbg_read_cim_obq(pdbg_init, dbg_buff, cudbg_err, 4);
++}
++
++int cudbg_collect_cim_obq_ncsi(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ return cudbg_read_cim_obq(pdbg_init, dbg_buff, cudbg_err, 5);
++}
++
++int cudbg_collect_obq_sge_rx_q0(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ return cudbg_read_cim_obq(pdbg_init, dbg_buff, cudbg_err, 6);
++}
++
++int cudbg_collect_obq_sge_rx_q1(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ return cudbg_read_cim_obq(pdbg_init, dbg_buff, cudbg_err, 7);
++}
++
+ static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff, u8 mem_type,
+ unsigned long tot_len,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -24,6 +24,42 @@ int cudbg_collect_reg_dump(struct cudbg_
+ int cudbg_collect_fw_devlog(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_ibq_tp0(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_ibq_tp1(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_ibq_ulp(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_ibq_sge0(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_ibq_sge1(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_ibq_ncsi(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_obq_ulp0(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_obq_ulp1(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_obq_ulp2(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_obq_ulp3(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_obq_sge(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_obq_ncsi(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_edc0_meminfo(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+@@ -36,6 +72,12 @@ int cudbg_collect_tp_indirect(struct cud
+ int cudbg_collect_sge_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_obq_sge_rx_q0(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_obq_sge_rx_q1(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_pcie_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -29,8 +29,22 @@ static const struct cxgb4_collect_entity
+ { CUDBG_MBOX_LOG, cudbg_collect_mbox_log },
+ { CUDBG_DEV_LOG, cudbg_collect_fw_devlog },
+ { CUDBG_REG_DUMP, cudbg_collect_reg_dump },
++ { CUDBG_CIM_IBQ_TP0, cudbg_collect_cim_ibq_tp0 },
++ { CUDBG_CIM_IBQ_TP1, cudbg_collect_cim_ibq_tp1 },
++ { CUDBG_CIM_IBQ_ULP, cudbg_collect_cim_ibq_ulp },
++ { CUDBG_CIM_IBQ_SGE0, cudbg_collect_cim_ibq_sge0 },
++ { CUDBG_CIM_IBQ_SGE1, cudbg_collect_cim_ibq_sge1 },
++ { CUDBG_CIM_IBQ_NCSI, cudbg_collect_cim_ibq_ncsi },
++ { CUDBG_CIM_OBQ_ULP0, cudbg_collect_cim_obq_ulp0 },
++ { CUDBG_CIM_OBQ_ULP1, cudbg_collect_cim_obq_ulp1 },
++ { CUDBG_CIM_OBQ_ULP2, cudbg_collect_cim_obq_ulp2 },
++ { CUDBG_CIM_OBQ_ULP3, cudbg_collect_cim_obq_ulp3 },
++ { CUDBG_CIM_OBQ_SGE, cudbg_collect_cim_obq_sge },
++ { CUDBG_CIM_OBQ_NCSI, cudbg_collect_cim_obq_ncsi },
+ { CUDBG_TP_INDIRECT, cudbg_collect_tp_indirect },
+ { CUDBG_SGE_INDIRECT, cudbg_collect_sge_indirect },
++ { CUDBG_CIM_OBQ_RXQ0, cudbg_collect_obq_sge_rx_q0 },
++ { CUDBG_CIM_OBQ_RXQ1, cudbg_collect_obq_sge_rx_q1 },
+ { CUDBG_PCIE_INDIRECT, cudbg_collect_pcie_indirect },
+ { CUDBG_PM_INDIRECT, cudbg_collect_pm_indirect },
+ { CUDBG_MA_INDIRECT, cudbg_collect_ma_indirect },
+@@ -59,6 +73,24 @@ static u32 cxgb4_get_entity_length(struc
+ case CUDBG_DEV_LOG:
+ len = adap->params.devlog.size;
+ break;
++ case CUDBG_CIM_IBQ_TP0:
++ case CUDBG_CIM_IBQ_TP1:
++ case CUDBG_CIM_IBQ_ULP:
++ case CUDBG_CIM_IBQ_SGE0:
++ case CUDBG_CIM_IBQ_SGE1:
++ case CUDBG_CIM_IBQ_NCSI:
++ len = CIM_IBQ_SIZE * 4 * sizeof(u32);
++ break;
++ case CUDBG_CIM_OBQ_ULP0:
++ case CUDBG_CIM_OBQ_ULP1:
++ case CUDBG_CIM_OBQ_ULP2:
++ case CUDBG_CIM_OBQ_ULP3:
++ case CUDBG_CIM_OBQ_SGE:
++ case CUDBG_CIM_OBQ_NCSI:
++ case CUDBG_CIM_OBQ_RXQ0:
++ case CUDBG_CIM_OBQ_RXQ1:
++ len = 6 * CIM_OBQ_SIZE * 4 * sizeof(u32);
++ break;
+ case CUDBG_EDC0:
+ value = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A);
+ if (value & EDRAM0_ENABLE_F) {
diff --git a/patches.drivers/cxgb4-collect-LE-TCAM-dump.patch b/patches.drivers/cxgb4-collect-LE-TCAM-dump.patch
new file mode 100644
index 0000000000..908ade8c7f
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-LE-TCAM-dump.patch
@@ -0,0 +1,373 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Sat, 11 Nov 2017 19:48:15 +0530
+Subject: cxgb4: collect LE-TCAM dump
+Patch-mainline: v4.15-rc1
+Git-commit: 03e98b9118bed1960993466f4d64f9f5a9146b66
+References: bsc#1064802 bsc#1066129
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 30 +++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 1
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 175 ++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 7
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 7
+ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 41 +++++
+ 6 files changed, 261 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -185,6 +185,36 @@ struct cudbg_vpd_data {
+ u32 vpd_vers;
+ };
+
++#define CUDBG_MAX_TCAM_TID 0x800
++
++enum cudbg_le_entry_types {
++ LE_ET_UNKNOWN = 0,
++ LE_ET_TCAM_CON = 1,
++ LE_ET_TCAM_SERVER = 2,
++ LE_ET_TCAM_FILTER = 3,
++ LE_ET_TCAM_CLIP = 4,
++ LE_ET_TCAM_ROUTING = 5,
++ LE_ET_HASH_CON = 6,
++ LE_ET_INVALID_TID = 8,
++};
++
++struct cudbg_tcam {
++ u32 filter_start;
++ u32 server_start;
++ u32 clip_start;
++ u32 routing_start;
++ u32 tid_hash_base;
++ u32 max_tid;
++};
++
++struct cudbg_tid_data {
++ u32 tid;
++ u32 dbig_cmd;
++ u32 dbig_conf;
++ u32 dbig_rsp_stat;
++ u32 data[NUM_LE_DB_DBGI_RSP_DATA_INSTANCES];
++};
++
+ #define CUDBG_NUM_ULPTX 11
+ #define CUDBG_NUM_ULPTX_READ 512
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -65,6 +65,7 @@ enum cudbg_dbg_entity_type {
+ CUDBG_TID_INFO = 54,
+ CUDBG_MPS_TCAM = 57,
+ CUDBG_VPD_DATA = 58,
++ CUDBG_LE_TCAM = 59,
+ CUDBG_CCTRL = 60,
+ CUDBG_MA_INDIRECT = 61,
+ CUDBG_ULPTX_LA = 62,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -1367,6 +1367,181 @@ int cudbg_collect_vpd_data(struct cudbg_
+ return rc;
+ }
+
++static int cudbg_read_tid(struct cudbg_init *pdbg_init, u32 tid,
++ struct cudbg_tid_data *tid_data)
++{
++ struct adapter *padap = pdbg_init->adap;
++ int i, cmd_retry = 8;
++ u32 val;
++
++ /* Fill REQ_DATA regs with 0's */
++ for (i = 0; i < NUM_LE_DB_DBGI_REQ_DATA_INSTANCES; i++)
++ t4_write_reg(padap, LE_DB_DBGI_REQ_DATA_A + (i << 2), 0);
++
++ /* Write DBIG command */
++ val = DBGICMD_V(4) | DBGITID_V(tid);
++ t4_write_reg(padap, LE_DB_DBGI_REQ_TCAM_CMD_A, val);
++ tid_data->dbig_cmd = val;
++
++ val = DBGICMDSTRT_F | DBGICMDMODE_V(1); /* LE mode */
++ t4_write_reg(padap, LE_DB_DBGI_CONFIG_A, val);
++ tid_data->dbig_conf = val;
++
++ /* Poll the DBGICMDBUSY bit */
++ val = 1;
++ while (val) {
++ val = t4_read_reg(padap, LE_DB_DBGI_CONFIG_A);
++ val = val & DBGICMDBUSY_F;
++ cmd_retry--;
++ if (!cmd_retry)
++ return CUDBG_SYSTEM_ERROR;
++ }
++
++ /* Check RESP status */
++ val = t4_read_reg(padap, LE_DB_DBGI_RSP_STATUS_A);
++ tid_data->dbig_rsp_stat = val;
++ if (!(val & 1))
++ return CUDBG_SYSTEM_ERROR;
++
++ /* Read RESP data */
++ for (i = 0; i < NUM_LE_DB_DBGI_RSP_DATA_INSTANCES; i++)
++ tid_data->data[i] = t4_read_reg(padap,
++ LE_DB_DBGI_RSP_DATA_A +
++ (i << 2));
++ tid_data->tid = tid;
++ return 0;
++}
++
++static int cudbg_get_le_type(u32 tid, struct cudbg_tcam tcam_region)
++{
++ int type = LE_ET_UNKNOWN;
++
++ if (tid < tcam_region.server_start)
++ type = LE_ET_TCAM_CON;
++ else if (tid < tcam_region.filter_start)
++ type = LE_ET_TCAM_SERVER;
++ else if (tid < tcam_region.clip_start)
++ type = LE_ET_TCAM_FILTER;
++ else if (tid < tcam_region.routing_start)
++ type = LE_ET_TCAM_CLIP;
++ else if (tid < tcam_region.tid_hash_base)
++ type = LE_ET_TCAM_ROUTING;
++ else if (tid < tcam_region.max_tid)
++ type = LE_ET_HASH_CON;
++ else
++ type = LE_ET_INVALID_TID;
++
++ return type;
++}
++
++static int cudbg_is_ipv6_entry(struct cudbg_tid_data *tid_data,
++ struct cudbg_tcam tcam_region)
++{
++ int ipv6 = 0;
++ int le_type;
++
++ le_type = cudbg_get_le_type(tid_data->tid, tcam_region);
++ if (tid_data->tid & 1)
++ return 0;
++
++ if (le_type == LE_ET_HASH_CON) {
++ ipv6 = tid_data->data[16] & 0x8000;
++ } else if (le_type == LE_ET_TCAM_CON) {
++ ipv6 = tid_data->data[16] & 0x8000;
++ if (ipv6)
++ ipv6 = tid_data->data[9] == 0x00C00000;
++ } else {
++ ipv6 = 0;
++ }
++ return ipv6;
++}
++
++void cudbg_fill_le_tcam_info(struct adapter *padap,
++ struct cudbg_tcam *tcam_region)
++{
++ u32 value;
++
++ /* Get the LE regions */
++ value = t4_read_reg(padap, LE_DB_TID_HASHBASE_A); /* hash base index */
++ tcam_region->tid_hash_base = value;
++
++ /* Get routing table index */
++ value = t4_read_reg(padap, LE_DB_ROUTING_TABLE_INDEX_A);
++ tcam_region->routing_start = value;
++
++ /*Get clip table index */
++ value = t4_read_reg(padap, LE_DB_CLIP_TABLE_INDEX_A);
++ tcam_region->clip_start = value;
++
++ /* Get filter table index */
++ value = t4_read_reg(padap, LE_DB_FILTER_TABLE_INDEX_A);
++ tcam_region->filter_start = value;
++
++ /* Get server table index */
++ value = t4_read_reg(padap, LE_DB_SERVER_INDEX_A);
++ tcam_region->server_start = value;
++
++ /* Check whether hash is enabled and calculate the max tids */
++ value = t4_read_reg(padap, LE_DB_CONFIG_A);
++ if ((value >> HASHEN_S) & 1) {
++ value = t4_read_reg(padap, LE_DB_HASH_CONFIG_A);
++ if (CHELSIO_CHIP_VERSION(padap->params.chip) > CHELSIO_T5) {
++ tcam_region->max_tid = (value & 0xFFFFF) +
++ tcam_region->tid_hash_base;
++ } else {
++ value = HASHTIDSIZE_G(value);
++ value = 1 << value;
++ tcam_region->max_tid = value +
++ tcam_region->tid_hash_base;
++ }
++ } else { /* hash not enabled */
++ tcam_region->max_tid = CUDBG_MAX_TCAM_TID;
++ }
++}
++
++int cudbg_collect_le_tcam(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_tcam tcam_region = { 0 };
++ struct cudbg_tid_data *tid_data;
++ u32 bytes = 0;
++ int rc, size;
++ u32 i;
++
++ cudbg_fill_le_tcam_info(padap, &tcam_region);
++
++ size = sizeof(struct cudbg_tid_data) * tcam_region.max_tid;
++ size += sizeof(struct cudbg_tcam);
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ memcpy(temp_buff.data, &tcam_region, sizeof(struct cudbg_tcam));
++ bytes = sizeof(struct cudbg_tcam);
++ tid_data = (struct cudbg_tid_data *)(temp_buff.data + bytes);
++ /* read all tid */
++ for (i = 0; i < tcam_region.max_tid; ) {
++ rc = cudbg_read_tid(pdbg_init, i, tid_data);
++ if (rc) {
++ cudbg_err->sys_err = rc;
++ cudbg_put_buff(&temp_buff, dbg_buff);
++ return rc;
++ }
++
++ /* ipv6 takes two tids */
++ cudbg_is_ipv6_entry(tid_data, tcam_region) ? i += 2 : i++;
++
++ tid_data++;
++ bytes += sizeof(struct cudbg_tid_data);
++ }
++
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
+ int cudbg_collect_cctrl(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err)
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -129,6 +129,9 @@ int cudbg_collect_mps_tcam(struct cudbg_
+ int cudbg_collect_vpd_data(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_le_tcam(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_cctrl(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+@@ -155,4 +158,8 @@ struct cudbg_entity_hdr *cudbg_get_entit
+ void cudbg_align_debug_buffer(struct cudbg_buffer *dbg_buff,
+ struct cudbg_entity_hdr *entity_hdr);
+ u32 cudbg_cim_obq_size(struct adapter *padap, int qid);
++
++struct cudbg_tcam;
++void cudbg_fill_le_tcam_info(struct adapter *padap,
++ struct cudbg_tcam *tcam_region);
+ #endif /* __CUDBG_LIB_H__ */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -62,6 +62,7 @@ static const struct cxgb4_collect_entity
+ { CUDBG_TID_INFO, cudbg_collect_tid },
+ { CUDBG_MPS_TCAM, cudbg_collect_mps_tcam },
+ { CUDBG_VPD_DATA, cudbg_collect_vpd_data },
++ { CUDBG_LE_TCAM, cudbg_collect_le_tcam },
+ { CUDBG_CCTRL, cudbg_collect_cctrl },
+ { CUDBG_MA_INDIRECT, cudbg_collect_ma_indirect },
+ { CUDBG_ULPTX_LA, cudbg_collect_ulptx_la },
+@@ -72,6 +73,7 @@ static const struct cxgb4_collect_entity
+
+ static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
+ {
++ struct cudbg_tcam tcam_region = { 0 };
+ u32 value, n = 0, len = 0;
+
+ switch (entity) {
+@@ -223,6 +225,11 @@ static u32 cxgb4_get_entity_length(struc
+ case CUDBG_VPD_DATA:
+ len = sizeof(struct cudbg_vpd_data);
+ break;
++ case CUDBG_LE_TCAM:
++ cudbg_fill_le_tcam_info(adap, &tcam_region);
++ len = sizeof(struct cudbg_tcam) +
++ sizeof(struct cudbg_tid_data) * tcam_region.max_tid;
++ break;
+ case CUDBG_CCTRL:
+ len = sizeof(u16) * NMTUS * NCCTRL_WIN;
+ break;
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+@@ -65,6 +65,9 @@
+
+ #define PCIE_FW_REG(reg_addr, idx) ((reg_addr) + (idx) * 4)
+
++#define NUM_LE_DB_DBGI_REQ_DATA_INSTANCES 17
++#define NUM_LE_DB_DBGI_RSP_DATA_INSTANCES 17
++
+ #define SGE_PF_KDOORBELL_A 0x0
+
+ #define QID_S 15
+@@ -2273,6 +2276,35 @@
+ #define CHNENABLE_V(x) ((x) << CHNENABLE_S)
+ #define CHNENABLE_F CHNENABLE_V(1U)
+
++#define LE_DB_DBGI_CONFIG_A 0x19cf0
++
++#define DBGICMDBUSY_S 3
++#define DBGICMDBUSY_V(x) ((x) << DBGICMDBUSY_S)
++#define DBGICMDBUSY_F DBGICMDBUSY_V(1U)
++
++#define DBGICMDSTRT_S 2
++#define DBGICMDSTRT_V(x) ((x) << DBGICMDSTRT_S)
++#define DBGICMDSTRT_F DBGICMDSTRT_V(1U)
++
++#define DBGICMDMODE_S 0
++#define DBGICMDMODE_M 0x3U
++#define DBGICMDMODE_V(x) ((x) << DBGICMDMODE_S)
++
++#define LE_DB_DBGI_REQ_TCAM_CMD_A 0x19cf4
++
++#define DBGICMD_S 20
++#define DBGICMD_M 0xfU
++#define DBGICMD_V(x) ((x) << DBGICMD_S)
++
++#define DBGITID_S 0
++#define DBGITID_M 0xfffffU
++#define DBGITID_V(x) ((x) << DBGITID_S)
++
++#define LE_DB_DBGI_REQ_DATA_A 0x19d00
++#define LE_DB_DBGI_RSP_STATUS_A 0x19d94
++
++#define LE_DB_DBGI_RSP_DATA_A 0x19da0
++
+ #define PRTENABLE_S 29
+ #define PRTENABLE_V(x) ((x) << PRTENABLE_S)
+ #define PRTENABLE_F PRTENABLE_V(1U)
+@@ -2882,11 +2914,20 @@
+ #define T6_LIPMISS_F T6_LIPMISS_V(1U)
+
+ #define LE_DB_CONFIG_A 0x19c04
++#define LE_DB_ROUTING_TABLE_INDEX_A 0x19c10
+ #define LE_DB_ACTIVE_TABLE_START_INDEX_A 0x19c10
++#define LE_DB_FILTER_TABLE_INDEX_A 0x19c14
+ #define LE_DB_SERVER_INDEX_A 0x19c18
+ #define LE_DB_SRVR_START_INDEX_A 0x19c18
++#define LE_DB_CLIP_TABLE_INDEX_A 0x19c1c
+ #define LE_DB_ACT_CNT_IPV4_A 0x19c20
+ #define LE_DB_ACT_CNT_IPV6_A 0x19c24
++#define LE_DB_HASH_CONFIG_A 0x19c28
++
++#define HASHTIDSIZE_S 16
++#define HASHTIDSIZE_M 0x3fU
++#define HASHTIDSIZE_G(x) (((x) >> HASHTIDSIZE_S) & HASHTIDSIZE_M)
++
+ #define LE_DB_HASH_TID_BASE_A 0x19c30
+ #define LE_DB_HASH_TBL_BASE_ADDR_A 0x19c30
+ #define LE_DB_INT_CAUSE_A 0x19c3c
diff --git a/patches.drivers/cxgb4-collect-MPS-TCAM-dump.patch b/patches.drivers/cxgb4-collect-MPS-TCAM-dump.patch
new file mode 100644
index 0000000000..cd4c188923
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-MPS-TCAM-dump.patch
@@ -0,0 +1,318 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Thu, 26 Oct 2017 17:18:37 +0530
+Subject: cxgb4: collect MPS-TCAM dump
+Patch-mainline: v4.15-rc1
+Git-commit: b289593e1398480f5ac1a1df2dae479516a21372
+References: bsc#1064802 bsc#1066129
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 21 ++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 1
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 184 ++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 3
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 5
+ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 16 +
+ 6 files changed, 230 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -114,6 +114,27 @@ struct cudbg_tid_info_region_rev1 {
+ u32 reserved[16];
+ };
+
++#define CUDBG_MAX_RPLC_SIZE 128
++
++struct cudbg_mps_tcam {
++ u64 mask;
++ u32 rplc[8];
++ u32 idx;
++ u32 cls_lo;
++ u32 cls_hi;
++ u32 rplc_size;
++ u32 vniy;
++ u32 vnix;
++ u32 dip_hit;
++ u32 vlan_vld;
++ u32 repli;
++ u16 ivlan;
++ u8 addr[ETH_ALEN];
++ u8 lookup_type;
++ u8 port_num;
++ u8 reserved[2];
++};
++
+ #define CUDBG_NUM_ULPTX 11
+ #define CUDBG_NUM_ULPTX_READ 512
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -58,6 +58,7 @@ enum cudbg_dbg_entity_type {
+ CUDBG_PCIE_INDIRECT = 50,
+ CUDBG_PM_INDIRECT = 51,
+ CUDBG_TID_INFO = 54,
++ CUDBG_MPS_TCAM = 57,
+ CUDBG_MA_INDIRECT = 61,
+ CUDBG_ULPTX_LA = 62,
+ CUDBG_UP_CIM_INDIRECT = 64,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -987,6 +987,190 @@ int cudbg_collect_tid(struct cudbg_init
+ return rc;
+ }
+
++static inline void cudbg_tcamxy2valmask(u64 x, u64 y, u8 *addr, u64 *mask)
++{
++ *mask = x | y;
++ y = (__force u64)cpu_to_be64(y);
++ memcpy(addr, (char *)&y + 2, ETH_ALEN);
++}
++
++static void cudbg_mps_rpl_backdoor(struct adapter *padap,
++ struct fw_ldst_mps_rplc *mps_rplc)
++{
++ if (is_t5(padap->params.chip)) {
++ mps_rplc->rplc255_224 = htonl(t4_read_reg(padap,
++ MPS_VF_RPLCT_MAP3_A));
++ mps_rplc->rplc223_192 = htonl(t4_read_reg(padap,
++ MPS_VF_RPLCT_MAP2_A));
++ mps_rplc->rplc191_160 = htonl(t4_read_reg(padap,
++ MPS_VF_RPLCT_MAP1_A));
++ mps_rplc->rplc159_128 = htonl(t4_read_reg(padap,
++ MPS_VF_RPLCT_MAP0_A));
++ } else {
++ mps_rplc->rplc255_224 = htonl(t4_read_reg(padap,
++ MPS_VF_RPLCT_MAP7_A));
++ mps_rplc->rplc223_192 = htonl(t4_read_reg(padap,
++ MPS_VF_RPLCT_MAP6_A));
++ mps_rplc->rplc191_160 = htonl(t4_read_reg(padap,
++ MPS_VF_RPLCT_MAP5_A));
++ mps_rplc->rplc159_128 = htonl(t4_read_reg(padap,
++ MPS_VF_RPLCT_MAP4_A));
++ }
++ mps_rplc->rplc127_96 = htonl(t4_read_reg(padap, MPS_VF_RPLCT_MAP3_A));
++ mps_rplc->rplc95_64 = htonl(t4_read_reg(padap, MPS_VF_RPLCT_MAP2_A));
++ mps_rplc->rplc63_32 = htonl(t4_read_reg(padap, MPS_VF_RPLCT_MAP1_A));
++ mps_rplc->rplc31_0 = htonl(t4_read_reg(padap, MPS_VF_RPLCT_MAP0_A));
++}
++
++static int cudbg_collect_tcam_index(struct adapter *padap,
++ struct cudbg_mps_tcam *tcam, u32 idx)
++{
++ u64 tcamy, tcamx, val;
++ u32 ctl, data2;
++ int rc = 0;
++
++ if (CHELSIO_CHIP_VERSION(padap->params.chip) >= CHELSIO_T6) {
++ /* CtlReqID - 1: use Host Driver Requester ID
++ * CtlCmdType - 0: Read, 1: Write
++ * CtlTcamSel - 0: TCAM0, 1: TCAM1
++ * CtlXYBitSel- 0: Y bit, 1: X bit
++ */
++
++ /* Read tcamy */
++ ctl = CTLREQID_V(1) | CTLCMDTYPE_V(0) | CTLXYBITSEL_V(0);
++ if (idx < 256)
++ ctl |= CTLTCAMINDEX_V(idx) | CTLTCAMSEL_V(0);
++ else
++ ctl |= CTLTCAMINDEX_V(idx - 256) | CTLTCAMSEL_V(1);
++
++ t4_write_reg(padap, MPS_CLS_TCAM_DATA2_CTL_A, ctl);
++ val = t4_read_reg(padap, MPS_CLS_TCAM_RDATA1_REQ_ID1_A);
++ tcamy = DMACH_G(val) << 32;
++ tcamy |= t4_read_reg(padap, MPS_CLS_TCAM_RDATA0_REQ_ID1_A);
++ data2 = t4_read_reg(padap, MPS_CLS_TCAM_RDATA2_REQ_ID1_A);
++ tcam->lookup_type = DATALKPTYPE_G(data2);
++
++ /* 0 - Outer header, 1 - Inner header
++ * [71:48] bit locations are overloaded for
++ * outer vs. inner lookup types.
++ */
++ if (tcam->lookup_type && tcam->lookup_type != DATALKPTYPE_M) {
++ /* Inner header VNI */
++ tcam->vniy = (data2 & DATAVIDH2_F) | DATAVIDH1_G(data2);
++ tcam->vniy = (tcam->vniy << 16) | VIDL_G(val);
++ tcam->dip_hit = data2 & DATADIPHIT_F;
++ } else {
++ tcam->vlan_vld = data2 & DATAVIDH2_F;
++ tcam->ivlan = VIDL_G(val);
++ }
++
++ tcam->port_num = DATAPORTNUM_G(data2);
++
++ /* Read tcamx. Change the control param */
++ ctl |= CTLXYBITSEL_V(1);
++ t4_write_reg(padap, MPS_CLS_TCAM_DATA2_CTL_A, ctl);
++ val = t4_read_reg(padap, MPS_CLS_TCAM_RDATA1_REQ_ID1_A);
++ tcamx = DMACH_G(val) << 32;
++ tcamx |= t4_read_reg(padap, MPS_CLS_TCAM_RDATA0_REQ_ID1_A);
++ data2 = t4_read_reg(padap, MPS_CLS_TCAM_RDATA2_REQ_ID1_A);
++ if (tcam->lookup_type && tcam->lookup_type != DATALKPTYPE_M) {
++ /* Inner header VNI mask */
++ tcam->vnix = (data2 & DATAVIDH2_F) | DATAVIDH1_G(data2);
++ tcam->vnix = (tcam->vnix << 16) | VIDL_G(val);
++ }
++ } else {
++ tcamy = t4_read_reg64(padap, MPS_CLS_TCAM_Y_L(idx));
++ tcamx = t4_read_reg64(padap, MPS_CLS_TCAM_X_L(idx));
++ }
++
++ /* If no entry, return */
++ if (tcamx & tcamy)
++ return rc;
++
++ tcam->cls_lo = t4_read_reg(padap, MPS_CLS_SRAM_L(idx));
++ tcam->cls_hi = t4_read_reg(padap, MPS_CLS_SRAM_H(idx));
++
++ if (is_t5(padap->params.chip))
++ tcam->repli = (tcam->cls_lo & REPLICATE_F);
++ else if (is_t6(padap->params.chip))
++ tcam->repli = (tcam->cls_lo & T6_REPLICATE_F);
++
++ if (tcam->repli) {
++ struct fw_ldst_cmd ldst_cmd;
++ struct fw_ldst_mps_rplc mps_rplc;
++
++ memset(&ldst_cmd, 0, sizeof(ldst_cmd));
++ ldst_cmd.op_to_addrspace =
++ htonl(FW_CMD_OP_V(FW_LDST_CMD) |
++ FW_CMD_REQUEST_F | FW_CMD_READ_F |
++ FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_MPS));
++ ldst_cmd.cycles_to_len16 = htonl(FW_LEN16(ldst_cmd));
++ ldst_cmd.u.mps.rplc.fid_idx =
++ htons(FW_LDST_CMD_FID_V(FW_LDST_MPS_RPLC) |
++ FW_LDST_CMD_IDX_V(idx));
++
++ rc = t4_wr_mbox(padap, padap->mbox, &ldst_cmd, sizeof(ldst_cmd),
++ &ldst_cmd);
++ if (rc)
++ cudbg_mps_rpl_backdoor(padap, &mps_rplc);
++ else
++ mps_rplc = ldst_cmd.u.mps.rplc;
++
++ tcam->rplc[0] = ntohl(mps_rplc.rplc31_0);
++ tcam->rplc[1] = ntohl(mps_rplc.rplc63_32);
++ tcam->rplc[2] = ntohl(mps_rplc.rplc95_64);
++ tcam->rplc[3] = ntohl(mps_rplc.rplc127_96);
++ if (padap->params.arch.mps_rplc_size > CUDBG_MAX_RPLC_SIZE) {
++ tcam->rplc[4] = ntohl(mps_rplc.rplc159_128);
++ tcam->rplc[5] = ntohl(mps_rplc.rplc191_160);
++ tcam->rplc[6] = ntohl(mps_rplc.rplc223_192);
++ tcam->rplc[7] = ntohl(mps_rplc.rplc255_224);
++ }
++ }
++ cudbg_tcamxy2valmask(tcamx, tcamy, tcam->addr, &tcam->mask);
++ tcam->idx = idx;
++ tcam->rplc_size = padap->params.arch.mps_rplc_size;
++ return rc;
++}
++
++int cudbg_collect_mps_tcam(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 = 0, i, n, total_size = 0;
++ struct cudbg_mps_tcam *tcam;
++ int rc;
++
++ n = padap->params.arch.mps_tcam_size;
++ size = sizeof(struct cudbg_mps_tcam) * n;
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ tcam = (struct cudbg_mps_tcam *)temp_buff.data;
++ for (i = 0; i < n; i++) {
++ rc = cudbg_collect_tcam_index(padap, tcam, i);
++ if (rc) {
++ cudbg_err->sys_err = rc;
++ cudbg_put_buff(&temp_buff, dbg_buff);
++ return rc;
++ }
++ total_size += sizeof(struct cudbg_mps_tcam);
++ tcam++;
++ }
++
++ if (!total_size) {
++ rc = CUDBG_SYSTEM_ERROR;
++ 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_ma_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err)
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -111,6 +111,9 @@ int cudbg_collect_pm_indirect(struct cud
+ int cudbg_collect_tid(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_mps_tcam(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_ma_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -56,6 +56,7 @@ static const struct cxgb4_collect_entity
+ { CUDBG_PCIE_INDIRECT, cudbg_collect_pcie_indirect },
+ { CUDBG_PM_INDIRECT, cudbg_collect_pm_indirect },
+ { CUDBG_TID_INFO, cudbg_collect_tid },
++ { CUDBG_MPS_TCAM, cudbg_collect_mps_tcam },
+ { CUDBG_MA_INDIRECT, cudbg_collect_ma_indirect },
+ { CUDBG_ULPTX_LA, cudbg_collect_ulptx_la },
+ { CUDBG_UP_CIM_INDIRECT, cudbg_collect_up_cim_indirect },
+@@ -196,6 +197,10 @@ static u32 cxgb4_get_entity_length(struc
+ case CUDBG_TID_INFO:
+ len = sizeof(struct cudbg_tid_info_region_rev1);
+ break;
++ case CUDBG_MPS_TCAM:
++ len = sizeof(struct cudbg_mps_tcam) *
++ adap->params.arch.mps_tcam_size;
++ break;
+ case CUDBG_MA_INDIRECT:
+ if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) {
+ n = sizeof(t6_ma_ireg_array) /
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+@@ -2439,6 +2439,18 @@
+ #define MPS_CLS_TCAM_DATA0_A 0xf000
+ #define MPS_CLS_TCAM_DATA1_A 0xf004
+
++#define CTLREQID_S 30
++#define CTLREQID_V(x) ((x) << CTLREQID_S)
++
++#define MPS_VF_RPLCT_MAP0_A 0x1111c
++#define MPS_VF_RPLCT_MAP1_A 0x11120
++#define MPS_VF_RPLCT_MAP2_A 0x11124
++#define MPS_VF_RPLCT_MAP3_A 0x11128
++#define MPS_VF_RPLCT_MAP4_A 0x11300
++#define MPS_VF_RPLCT_MAP5_A 0x11304
++#define MPS_VF_RPLCT_MAP6_A 0x11308
++#define MPS_VF_RPLCT_MAP7_A 0x1130c
++
+ #define VIDL_S 16
+ #define VIDL_M 0xffffU
+ #define VIDL_G(x) (((x) >> VIDL_S) & VIDL_M)
+@@ -2463,6 +2475,10 @@
+ #define DATAVIDH1_M 0x7fU
+ #define DATAVIDH1_G(x) (((x) >> DATAVIDH1_S) & DATAVIDH1_M)
+
++#define MPS_CLS_TCAM_RDATA0_REQ_ID1_A 0xf020
++#define MPS_CLS_TCAM_RDATA1_REQ_ID1_A 0xf024
++#define MPS_CLS_TCAM_RDATA2_REQ_ID1_A 0xf028
++
+ #define USED_S 16
+ #define USED_M 0x7ffU
+ #define USED_G(x) (((x) >> USED_S) & USED_M)
diff --git a/patches.drivers/cxgb4-collect-PBT-tables-dump.patch b/patches.drivers/cxgb4-collect-PBT-tables-dump.patch
new file mode 100644
index 0000000000..e26cd079f8
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-PBT-tables-dump.patch
@@ -0,0 +1,162 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Thu, 26 Oct 2017 17:18:38 +0530
+Subject: cxgb4: collect PBT tables dump
+Patch-mainline: v4.15-rc1
+Git-commit: db8cd7ce208a7e7d440856b5c3e4e96af6dd9917
+References: bsc#1064802 bsc#1066129
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 15 ++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 1
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 68 ++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 3
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 4 +
+ 5 files changed, 91 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -145,6 +145,21 @@ struct cudbg_ulptx_la {
+ u32 rd_data[CUDBG_NUM_ULPTX][CUDBG_NUM_ULPTX_READ];
+ };
+
++#define CUDBG_CHAC_PBT_ADDR 0x2800
++#define CUDBG_CHAC_PBT_LRF 0x3000
++#define CUDBG_CHAC_PBT_DATA 0x3800
++#define CUDBG_PBT_DYNAMIC_ENTRIES 8
++#define CUDBG_PBT_STATIC_ENTRIES 16
++#define CUDBG_LRF_ENTRIES 8
++#define CUDBG_PBT_DATA_ENTRIES 512
++
++struct cudbg_pbt_tables {
++ u32 pbt_dynamic[CUDBG_PBT_DYNAMIC_ENTRIES];
++ u32 pbt_static[CUDBG_PBT_STATIC_ENTRIES];
++ u32 lrf_table[CUDBG_LRF_ENTRIES];
++ u32 pbt_data[CUDBG_PBT_DATA_ENTRIES];
++};
++
+ #define IREG_NUM_ELEM 4
+
+ static const u32 t6_tp_pio_array[][IREG_NUM_ELEM] = {
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -62,6 +62,7 @@ enum cudbg_dbg_entity_type {
+ CUDBG_MA_INDIRECT = 61,
+ CUDBG_ULPTX_LA = 62,
+ CUDBG_UP_CIM_INDIRECT = 64,
++ CUDBG_PBT_TABLE = 65,
+ CUDBG_MBOX_LOG = 66,
+ CUDBG_HMA_INDIRECT = 67,
+ CUDBG_MAX_ENTITY = 70,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -1310,6 +1310,74 @@ int cudbg_collect_up_cim_indirect(struct
+ return rc;
+ }
+
++int cudbg_collect_pbt_tables(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_pbt_tables *pbt;
++ int i, rc;
++ u32 addr;
++
++ rc = cudbg_get_buff(dbg_buff, sizeof(struct cudbg_pbt_tables),
++ &temp_buff);
++ if (rc)
++ return rc;
++
++ pbt = (struct cudbg_pbt_tables *)temp_buff.data;
++ /* PBT dynamic entries */
++ addr = CUDBG_CHAC_PBT_ADDR;
++ for (i = 0; i < CUDBG_PBT_DYNAMIC_ENTRIES; i++) {
++ rc = t4_cim_read(padap, addr + (i * 4), 1,
++ &pbt->pbt_dynamic[i]);
++ if (rc) {
++ cudbg_err->sys_err = rc;
++ cudbg_put_buff(&temp_buff, dbg_buff);
++ return rc;
++ }
++ }
++
++ /* PBT static entries */
++ /* static entries start when bit 6 is set */
++ addr = CUDBG_CHAC_PBT_ADDR + (1 << 6);
++ for (i = 0; i < CUDBG_PBT_STATIC_ENTRIES; i++) {
++ rc = t4_cim_read(padap, addr + (i * 4), 1,
++ &pbt->pbt_static[i]);
++ if (rc) {
++ cudbg_err->sys_err = rc;
++ cudbg_put_buff(&temp_buff, dbg_buff);
++ return rc;
++ }
++ }
++
++ /* LRF entries */
++ addr = CUDBG_CHAC_PBT_LRF;
++ for (i = 0; i < CUDBG_LRF_ENTRIES; i++) {
++ rc = t4_cim_read(padap, addr + (i * 4), 1,
++ &pbt->lrf_table[i]);
++ if (rc) {
++ cudbg_err->sys_err = rc;
++ cudbg_put_buff(&temp_buff, dbg_buff);
++ return rc;
++ }
++ }
++
++ /* PBT data entries */
++ addr = CUDBG_CHAC_PBT_DATA;
++ for (i = 0; i < CUDBG_PBT_DATA_ENTRIES; i++) {
++ rc = t4_cim_read(padap, addr + (i * 4), 1,
++ &pbt->pbt_data[i]);
++ 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_mbox_log(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err)
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -123,6 +123,9 @@ int cudbg_collect_ulptx_la(struct cudbg_
+ int cudbg_collect_up_cim_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_pbt_tables(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_mbox_log(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -60,6 +60,7 @@ static const struct cxgb4_collect_entity
+ { CUDBG_MA_INDIRECT, cudbg_collect_ma_indirect },
+ { CUDBG_ULPTX_LA, cudbg_collect_ulptx_la },
+ { CUDBG_UP_CIM_INDIRECT, cudbg_collect_up_cim_indirect },
++ { CUDBG_PBT_TABLE, cudbg_collect_pbt_tables },
+ { CUDBG_HMA_INDIRECT, cudbg_collect_hma_indirect },
+ };
+
+@@ -215,6 +216,9 @@ static u32 cxgb4_get_entity_length(struc
+ n = sizeof(t5_up_cim_reg_array) / (IREG_NUM_ELEM * sizeof(u32));
+ len = sizeof(struct ireg_buf) * n;
+ break;
++ case CUDBG_PBT_TABLE:
++ len = sizeof(struct cudbg_pbt_tables);
++ break;
+ case CUDBG_MBOX_LOG:
+ len = sizeof(struct cudbg_mbox_log) * adap->mbox_log->size;
+ break;
diff --git a/patches.drivers/cxgb4-collect-RSS-dumps.patch b/patches.drivers/cxgb4-collect-RSS-dumps.patch
new file mode 100644
index 0000000000..81f2d9deb1
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-RSS-dumps.patch
@@ -0,0 +1,141 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Thu, 26 Oct 2017 17:18:35 +0530
+Subject: cxgb4: collect RSS dumps
+Patch-mainline: v4.15-rc1
+Git-commit: 28b445561fbac2e3c9886231b0a414336878e20f
+References: bsc#1064802 bsc#1066129
+
+Collect RSS table and RSS VF configuration dumps.
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 5 ++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 2
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 46 ++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 6 ++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 9 ++++
+ 5 files changed, 68 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -42,6 +42,11 @@ struct cudbg_cim_qcfg {
+ u32 stat[4 * (CIM_NUM_IBQ + CIM_NUM_OBQ_T5)];
+ };
+
++struct cudbg_rss_vf_conf {
++ u32 rss_vf_vfl;
++ u32 rss_vf_vfh;
++};
++
+ struct ireg_field {
+ u32 ireg_addr;
+ u32 ireg_data;
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -46,6 +46,8 @@ enum cudbg_dbg_entity_type {
+ CUDBG_CIM_OBQ_NCSI = 17,
+ CUDBG_EDC0 = 18,
+ CUDBG_EDC1 = 19,
++ CUDBG_RSS = 22,
++ CUDBG_RSS_VF_CONF = 25,
+ CUDBG_TP_INDIRECT = 36,
+ CUDBG_SGE_INDIRECT = 37,
+ CUDBG_ULPRX_LA = 41,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -528,6 +528,52 @@ int cudbg_collect_edc1_meminfo(struct cu
+ MEM_EDC1);
+ }
+
++int cudbg_collect_rss(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 };
++ int rc;
++
++ rc = cudbg_get_buff(dbg_buff, RSS_NENTRIES * sizeof(u16), &temp_buff);
++ if (rc)
++ return rc;
++
++ rc = t4_read_rss(padap, (u16 *)temp_buff.data);
++ 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_rss_vf_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 };
++ struct cudbg_rss_vf_conf *vfconf;
++ int vf, rc, vf_count;
++
++ vf_count = padap->params.arch.vfcount;
++ rc = cudbg_get_buff(dbg_buff,
++ vf_count * sizeof(struct cudbg_rss_vf_conf),
++ &temp_buff);
++ if (rc)
++ return rc;
++
++ vfconf = (struct cudbg_rss_vf_conf *)temp_buff.data;
++ for (vf = 0; vf < vf_count; vf++)
++ t4_read_rss_vf_config(padap, vf, &vfconf[vf].rss_vf_vfl,
++ &vfconf[vf].rss_vf_vfh, true);
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
+ int cudbg_collect_tp_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err)
+--- 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 cu
+ int cudbg_collect_edc1_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);
++int cudbg_collect_rss_vf_config(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_tp_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -44,6 +44,8 @@ static const struct cxgb4_collect_entity
+ { CUDBG_CIM_OBQ_ULP3, cudbg_collect_cim_obq_ulp3 },
+ { CUDBG_CIM_OBQ_SGE, cudbg_collect_cim_obq_sge },
+ { CUDBG_CIM_OBQ_NCSI, cudbg_collect_cim_obq_ncsi },
++ { CUDBG_RSS, cudbg_collect_rss },
++ { CUDBG_RSS_VF_CONF, cudbg_collect_rss_vf_config },
+ { CUDBG_TP_INDIRECT, cudbg_collect_tp_indirect },
+ { CUDBG_SGE_INDIRECT, cudbg_collect_sge_indirect },
+ { CUDBG_ULPRX_LA, cudbg_collect_ulprx_la },
+@@ -144,6 +146,13 @@ static u32 cxgb4_get_entity_length(struc
+ }
+ len = cudbg_mbytes_to_bytes(len);
+ break;
++ case CUDBG_RSS:
++ len = RSS_NENTRIES * sizeof(u16);
++ break;
++ case CUDBG_RSS_VF_CONF:
++ len = adap->params.arch.vfcount *
++ sizeof(struct cudbg_rss_vf_conf);
++ break;
+ case CUDBG_TP_INDIRECT:
+ switch (CHELSIO_CHIP_VERSION(adap->params.chip)) {
+ case CHELSIO_T5:
diff --git a/patches.drivers/cxgb4-collect-SGE-queue-context-dump.patch b/patches.drivers/cxgb4-collect-SGE-queue-context-dump.patch
new file mode 100644
index 0000000000..9f2be131e0
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-SGE-queue-context-dump.patch
@@ -0,0 +1,329 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Sat, 11 Nov 2017 19:48:16 +0530
+Subject: cxgb4: collect SGE queue context dump
+Patch-mainline: v4.15-rc1
+Git-commit: 9e5c598c720792e210f83964441ee1c99451e8d1
+References: bsc#1064802 bsc#1066129
+
+Collect SGE freelist queue and congestion manager contexts.
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 8 ++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 1
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 78 ++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 4 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 4 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 4 +
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 62 +++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 7 +
+ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 27 +++++++
+ 9 files changed, 195 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -145,6 +145,14 @@ struct cudbg_tid_info_region_rev1 {
+ u32 reserved[16];
+ };
+
++#define CUDBG_MAX_FL_QIDS 1024
++
++struct cudbg_ch_cntxt {
++ u32 cntxt_type;
++ u32 cntxt_id;
++ u32 data[SGE_CTXT_SIZE / 4];
++};
++
+ #define CUDBG_MAX_RPLC_SIZE 128
+
+ struct cudbg_mps_tcam {
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -63,6 +63,7 @@ enum cudbg_dbg_entity_type {
+ CUDBG_PCIE_INDIRECT = 50,
+ CUDBG_PM_INDIRECT = 51,
+ CUDBG_TID_INFO = 54,
++ CUDBG_DUMP_CONTEXT = 56,
+ CUDBG_MPS_TCAM = 57,
+ CUDBG_VPD_DATA = 58,
+ CUDBG_LE_TCAM = 59,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -1115,6 +1115,84 @@ int cudbg_collect_tid(struct cudbg_init
+ return rc;
+ }
+
++int cudbg_dump_context_size(struct adapter *padap)
++{
++ u32 value, size;
++ u8 flq;
++
++ 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;
++
++ /* Add extra space for congestion manager contexts.
++ * The number of CONM contexts are same as number of freelist
++ * queues.
++ */
++ size += size;
++ return size * sizeof(struct cudbg_ch_cntxt);
++}
++
++static void cudbg_read_sge_ctxt(struct cudbg_init *pdbg_init, u32 cid,
++ enum ctxt_type ctype, u32 *data)
++{
++ struct adapter *padap = pdbg_init->adap;
++ int rc = -1;
++
++ /* Under heavy traffic, the SGE Queue contexts registers will be
++ * frequently accessed by firmware.
++ *
++ * To avoid conflicts with firmware, always ask firmware to fetch
++ * the SGE Queue contexts via mailbox. On failure, fallback to
++ * accessing hardware registers directly.
++ */
++ if (is_fw_attached(pdbg_init))
++ rc = t4_sge_ctxt_rd(padap, padap->mbox, cid, ctype, data);
++ if (rc)
++ t4_sge_ctxt_rd_bd(padap, cid, ctype, data);
++}
++
++int cudbg_collect_dump_context(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_ch_cntxt *buff;
++ u32 size, i = 0;
++ int rc;
++
++ rc = cudbg_dump_context_size(padap);
++ if (rc <= 0)
++ return CUDBG_STATUS_ENTITY_NOT_FOUND;
++
++ size = rc;
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ 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);
++
++ i++;
++ }
++
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
+ static inline void cudbg_tcamxy2valmask(u64 x, u64 y, u8 *addr, u64 *mask)
+ {
+ *mask = x | y;
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -123,6 +123,9 @@ int cudbg_collect_pm_indirect(struct cud
+ int cudbg_collect_tid(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);
+ int cudbg_collect_mps_tcam(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+@@ -158,6 +161,7 @@ struct cudbg_entity_hdr *cudbg_get_entit
+ void cudbg_align_debug_buffer(struct cudbg_buffer *dbg_buff,
+ struct cudbg_entity_hdr *entity_hdr);
+ u32 cudbg_cim_obq_size(struct adapter *padap, int qid);
++int cudbg_dump_context_size(struct adapter *padap);
+
+ struct cudbg_tcam;
+ void cudbg_fill_le_tcam_info(struct adapter *padap,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -1668,6 +1668,10 @@ int t4_fwaddrspace_write(struct adapter
+ void t4_read_pace_tbl(struct adapter *adap, unsigned int pace_vals[NTX_SCHED]);
+ void t4_get_tx_sched(struct adapter *adap, unsigned int sched,
+ unsigned int *kbps, unsigned int *ipg, bool sleep_ok);
++int t4_sge_ctxt_rd(struct adapter *adap, unsigned int mbox, unsigned int cid,
++ enum ctxt_type ctype, u32 *data);
++int t4_sge_ctxt_rd_bd(struct adapter *adap, unsigned int cid,
++ enum ctxt_type ctype, u32 *data);
+ int t4_sched_params(struct adapter *adapter, int type, int level, int mode,
+ int rateunit, int ratemode, int channel, int class,
+ int minrate, int maxrate, int weight, int pktsize);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -60,6 +60,7 @@ static const struct cxgb4_collect_entity
+ { CUDBG_PCIE_INDIRECT, cudbg_collect_pcie_indirect },
+ { CUDBG_PM_INDIRECT, cudbg_collect_pm_indirect },
+ { CUDBG_TID_INFO, cudbg_collect_tid },
++ { CUDBG_DUMP_CONTEXT, cudbg_collect_dump_context },
+ { CUDBG_MPS_TCAM, cudbg_collect_mps_tcam },
+ { CUDBG_VPD_DATA, cudbg_collect_vpd_data },
+ { CUDBG_LE_TCAM, cudbg_collect_le_tcam },
+@@ -218,6 +219,9 @@ static u32 cxgb4_get_entity_length(struc
+ case CUDBG_TID_INFO:
+ len = sizeof(struct cudbg_tid_info_region_rev1);
+ break;
++ case CUDBG_DUMP_CONTEXT:
++ len = cudbg_dump_context_size(adap);
++ break;
+ case CUDBG_MPS_TCAM:
+ len = sizeof(struct cudbg_mps_tcam) *
+ adap->params.arch.mps_tcam_size;
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+@@ -9647,6 +9647,68 @@ void t4_get_tx_sched(struct adapter *ada
+ }
+ }
+
++/* t4_sge_ctxt_rd - read an SGE context through FW
++ * @adap: the adapter
++ * @mbox: mailbox to use for the FW command
++ * @cid: the context id
++ * @ctype: the context type
++ * @data: where to store the context data
++ *
++ * Issues a FW command through the given mailbox to read an SGE context.
++ */
++int t4_sge_ctxt_rd(struct adapter *adap, unsigned int mbox, unsigned int cid,
++ enum ctxt_type ctype, u32 *data)
++{
++ struct fw_ldst_cmd c;
++ int ret;
++
++ if (ctype == CTXT_FLM)
++ ret = FW_LDST_ADDRSPC_SGE_FLMC;
++ else
++ ret = FW_LDST_ADDRSPC_SGE_CONMC;
++
++ memset(&c, 0, sizeof(c));
++ c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) |
++ FW_CMD_REQUEST_F | FW_CMD_READ_F |
++ FW_LDST_CMD_ADDRSPACE_V(ret));
++ c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c));
++ c.u.idctxt.physid = cpu_to_be32(cid);
++
++ ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
++ if (ret == 0) {
++ data[0] = be32_to_cpu(c.u.idctxt.ctxt_data0);
++ data[1] = be32_to_cpu(c.u.idctxt.ctxt_data1);
++ data[2] = be32_to_cpu(c.u.idctxt.ctxt_data2);
++ data[3] = be32_to_cpu(c.u.idctxt.ctxt_data3);
++ data[4] = be32_to_cpu(c.u.idctxt.ctxt_data4);
++ data[5] = be32_to_cpu(c.u.idctxt.ctxt_data5);
++ }
++ return ret;
++}
++
++/**
++ * t4_sge_ctxt_rd_bd - read an SGE context bypassing FW
++ * @adap: the adapter
++ * @cid: the context id
++ * @ctype: the context type
++ * @data: where to store the context data
++ *
++ * Reads an SGE context directly, bypassing FW. This is only for
++ * debugging when FW is unavailable.
++ */
++int t4_sge_ctxt_rd_bd(struct adapter *adap, unsigned int cid,
++ enum ctxt_type ctype, u32 *data)
++{
++ int i, ret;
++
++ t4_write_reg(adap, SGE_CTXT_CMD_A, CTXTQID_V(cid) | CTXTTYPE_V(ctype));
++ ret = t4_wait_op_done(adap, SGE_CTXT_CMD_A, BUSY_F, 0, 3, 1);
++ if (!ret)
++ for (i = SGE_CTXT_DATA0_A; i <= SGE_CTXT_DATA5_A; i += 4)
++ *data++ = t4_read_reg(adap, i);
++ return ret;
++}
++
+ int t4_sched_params(struct adapter *adapter, int type, int level, int mode,
+ int rateunit, int ratemode, int channel, int class,
+ int minrate, int maxrate, int weight, int pktsize)
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
+@@ -68,6 +68,12 @@ enum {
+ ULPRX_LA_SIZE = 512, /* # of 256-bit words in ULP_RX LA */
+ };
+
++/* SGE context types */
++enum ctxt_type {
++ CTXT_FLM = 2,
++ CTXT_CNM,
++};
++
+ enum {
+ SF_PAGE_SIZE = 256, /* serial flash page size */
+ SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */
+@@ -79,6 +85,7 @@ enum { MBOX_OWNER_NONE, MBOX_OWNER_FW, M
+
+ enum {
+ SGE_MAX_WR_LEN = 512, /* max WR size in bytes */
++ SGE_CTXT_SIZE = 24, /* size of SGE context */
+ SGE_NTIMERS = 6, /* # of interrupt holdoff timer values */
+ SGE_NCOUNTERS = 4, /* # of interrupt packet counter values */
+ SGE_MAX_IQ_SIZE = 65520,
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+@@ -153,6 +153,23 @@
+ #define T6_DBVFIFO_SIZE_M 0x1fffU
+ #define T6_DBVFIFO_SIZE_G(x) (((x) >> T6_DBVFIFO_SIZE_S) & T6_DBVFIFO_SIZE_M)
+
++#define SGE_CTXT_CMD_A 0x11fc
++
++#define BUSY_S 31
++#define BUSY_V(x) ((x) << BUSY_S)
++#define BUSY_F BUSY_V(1U)
++
++#define CTXTTYPE_S 24
++#define CTXTTYPE_M 0x3U
++#define CTXTTYPE_V(x) ((x) << CTXTTYPE_S)
++
++#define CTXTQID_S 0
++#define CTXTQID_M 0x1ffffU
++#define CTXTQID_V(x) ((x) << CTXTQID_S)
++
++#define SGE_CTXT_DATA0_A 0x1200
++#define SGE_CTXT_DATA5_A 0x1214
++
+ #define GLOBALENABLE_S 0
+ #define GLOBALENABLE_V(x) ((x) << GLOBALENABLE_S)
+ #define GLOBALENABLE_F GLOBALENABLE_V(1U)
+@@ -322,6 +339,16 @@
+
+ #define SGE_IMSG_CTXT_BADDR_A 0x1088
+ #define SGE_FLM_CACHE_BADDR_A 0x108c
++#define SGE_FLM_CFG_A 0x1090
++
++#define NOHDR_S 18
++#define NOHDR_V(x) ((x) << NOHDR_S)
++#define NOHDR_F NOHDR_V(1U)
++
++#define HDRSTARTFLQ_S 11
++#define HDRSTARTFLQ_M 0x7U
++#define HDRSTARTFLQ_G(x) (((x) >> HDRSTARTFLQ_S) & HDRSTARTFLQ_M)
++
+ #define SGE_INGRESS_RX_THRESHOLD_A 0x10a0
+
+ #define THRESHOLD_0_S 24
diff --git a/patches.drivers/cxgb4-collect-TID-info-dump.patch b/patches.drivers/cxgb4-collect-TID-info-dump.patch
new file mode 100644
index 0000000000..1bf283ee91
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-TID-info-dump.patch
@@ -0,0 +1,254 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Thu, 26 Oct 2017 17:18:36 +0530
+Subject: cxgb4: collect TID info dump
+Patch-mainline: v4.15-rc1
+Git-commit: 9030e49897f57dea3126e35d97a33588c5307aa1
+References: bsc#1064802 bsc#1066129
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 39 ++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 1
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 85 ++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 3
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h | 6 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 4
+ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 1
+ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 5 -
+ 8 files changed, 143 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -21,6 +21,8 @@
+ #define EDC0_FLAG 3
+ #define EDC1_FLAG 4
+
++#define CUDBG_ENTITY_SIGNATURE 0xCCEDB001
++
+ struct card_mem {
+ u16 size_edc0;
+ u16 size_edc1;
+@@ -75,6 +77,43 @@ struct cudbg_cim_pif_la {
+ u8 data[0];
+ };
+
++struct cudbg_tid_info_region {
++ u32 ntids;
++ u32 nstids;
++ u32 stid_base;
++ u32 hash_base;
++
++ u32 natids;
++ u32 nftids;
++ u32 ftid_base;
++ u32 aftid_base;
++ u32 aftid_end;
++
++ u32 sftid_base;
++ u32 nsftids;
++
++ u32 uotid_base;
++ u32 nuotids;
++
++ u32 sb;
++ u32 flags;
++ u32 le_db_conf;
++ u32 ip_users;
++ u32 ipv6_users;
++
++ u32 hpftid_base;
++ u32 nhpftids;
++};
++
++#define CUDBG_TID_INFO_REV 1
++
++struct cudbg_tid_info_region_rev1 {
++ struct cudbg_ver_hdr ver_hdr;
++ struct cudbg_tid_info_region tid;
++ u32 tid_start;
++ u32 reserved[16];
++};
++
+ #define CUDBG_NUM_ULPTX 11
+ #define CUDBG_NUM_ULPTX_READ 512
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -57,6 +57,7 @@ enum cudbg_dbg_entity_type {
+ CUDBG_CIM_OBQ_RXQ1 = 48,
+ CUDBG_PCIE_INDIRECT = 50,
+ CUDBG_PM_INDIRECT = 51,
++ CUDBG_TID_INFO = 54,
+ CUDBG_MA_INDIRECT = 61,
+ CUDBG_ULPTX_LA = 62,
+ CUDBG_UP_CIM_INDIRECT = 64,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -902,6 +902,91 @@ int cudbg_collect_pm_indirect(struct cud
+ return rc;
+ }
+
++int cudbg_collect_tid(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ struct adapter *padap = pdbg_init->adap;
++ struct cudbg_tid_info_region_rev1 *tid1;
++ struct cudbg_buffer temp_buff = { 0 };
++ struct cudbg_tid_info_region *tid;
++ u32 para[2], val[2];
++ int rc;
++
++ rc = cudbg_get_buff(dbg_buff, sizeof(struct cudbg_tid_info_region_rev1),
++ &temp_buff);
++ if (rc)
++ return rc;
++
++ tid1 = (struct cudbg_tid_info_region_rev1 *)temp_buff.data;
++ tid = &tid1->tid;
++ tid1->ver_hdr.signature = CUDBG_ENTITY_SIGNATURE;
++ tid1->ver_hdr.revision = CUDBG_TID_INFO_REV;
++ tid1->ver_hdr.size = sizeof(struct cudbg_tid_info_region_rev1) -
++ sizeof(struct cudbg_ver_hdr);
++
++#define FW_PARAM_PFVF_A(param) \
++ (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | \
++ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_##param) | \
++ FW_PARAMS_PARAM_Y_V(0) | \
++ FW_PARAMS_PARAM_Z_V(0))
++
++ para[0] = FW_PARAM_PFVF_A(ETHOFLD_START);
++ para[1] = FW_PARAM_PFVF_A(ETHOFLD_END);
++ rc = t4_query_params(padap, padap->mbox, padap->pf, 0, 2, para, val);
++ if (rc < 0) {
++ cudbg_err->sys_err = rc;
++ cudbg_put_buff(&temp_buff, dbg_buff);
++ return rc;
++ }
++ tid->uotid_base = val[0];
++ tid->nuotids = val[1] - val[0] + 1;
++
++ if (is_t5(padap->params.chip)) {
++ tid->sb = t4_read_reg(padap, LE_DB_SERVER_INDEX_A) / 4;
++ } else if (is_t6(padap->params.chip)) {
++ tid1->tid_start =
++ t4_read_reg(padap, LE_DB_ACTIVE_TABLE_START_INDEX_A);
++ tid->sb = t4_read_reg(padap, LE_DB_SRVR_START_INDEX_A);
++
++ para[0] = FW_PARAM_PFVF_A(HPFILTER_START);
++ para[1] = FW_PARAM_PFVF_A(HPFILTER_END);
++ rc = t4_query_params(padap, padap->mbox, padap->pf, 0, 2,
++ para, val);
++ if (rc < 0) {
++ cudbg_err->sys_err = rc;
++ cudbg_put_buff(&temp_buff, dbg_buff);
++ return rc;
++ }
++ tid->hpftid_base = val[0];
++ tid->nhpftids = val[1] - val[0] + 1;
++ }
++
++ tid->ntids = padap->tids.ntids;
++ tid->nstids = padap->tids.nstids;
++ tid->stid_base = padap->tids.stid_base;
++ tid->hash_base = padap->tids.hash_base;
++
++ tid->natids = padap->tids.natids;
++ tid->nftids = padap->tids.nftids;
++ tid->ftid_base = padap->tids.ftid_base;
++ tid->aftid_base = padap->tids.aftid_base;
++ tid->aftid_end = padap->tids.aftid_end;
++
++ tid->sftid_base = padap->tids.sftid_base;
++ tid->nsftids = padap->tids.nsftids;
++
++ tid->flags = padap->flags;
++ tid->le_db_conf = t4_read_reg(padap, LE_DB_CONFIG_A);
++ tid->ip_users = t4_read_reg(padap, LE_DB_ACT_CNT_IPV4_A);
++ tid->ipv6_users = t4_read_reg(padap, LE_DB_ACT_CNT_IPV6_A);
++
++#undef FW_PARAM_PFVF_A
++
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
+ int cudbg_collect_ma_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err)
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -108,6 +108,9 @@ int cudbg_collect_pcie_indirect(struct c
+ int cudbg_collect_pm_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_tid(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_ma_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h
+@@ -57,6 +57,12 @@ struct cudbg_entity_hdr {
+ u32 reserved[5];
+ };
+
++struct cudbg_ver_hdr {
++ u32 signature;
++ u16 revision;
++ u16 size;
++};
++
+ struct cudbg_buffer {
+ u32 size;
+ u32 offset;
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -55,6 +55,7 @@ static const struct cxgb4_collect_entity
+ { CUDBG_CIM_OBQ_RXQ1, cudbg_collect_obq_sge_rx_q1 },
+ { CUDBG_PCIE_INDIRECT, cudbg_collect_pcie_indirect },
+ { CUDBG_PM_INDIRECT, cudbg_collect_pm_indirect },
++ { CUDBG_TID_INFO, cudbg_collect_tid },
+ { CUDBG_MA_INDIRECT, cudbg_collect_ma_indirect },
+ { CUDBG_ULPTX_LA, cudbg_collect_ulptx_la },
+ { CUDBG_UP_CIM_INDIRECT, cudbg_collect_up_cim_indirect },
+@@ -192,6 +193,9 @@ static u32 cxgb4_get_entity_length(struc
+ n = sizeof(t5_pm_rx_array) / (IREG_NUM_ELEM * sizeof(u32));
+ len = sizeof(struct ireg_buf) * n * 2;
+ break;
++ case CUDBG_TID_INFO:
++ len = sizeof(struct cudbg_tid_info_region_rev1);
++ break;
+ case CUDBG_MA_INDIRECT:
+ if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) {
+ n = sizeof(t6_ma_ireg_array) /
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+@@ -2856,6 +2856,7 @@
+ #define T6_LIPMISS_F T6_LIPMISS_V(1U)
+
+ #define LE_DB_CONFIG_A 0x19c04
++#define LE_DB_ACTIVE_TABLE_START_INDEX_A 0x19c10
+ #define LE_DB_SERVER_INDEX_A 0x19c18
+ #define LE_DB_SRVR_START_INDEX_A 0x19c18
+ #define LE_DB_ACT_CNT_IPV4_A 0x19c20
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+@@ -1244,9 +1244,12 @@ enum fw_params_param_pfvf {
+ FW_PARAMS_PARAM_PFVF_EQ_END = 0x2C,
+ FW_PARAMS_PARAM_PFVF_ACTIVE_FILTER_START = 0x2D,
+ FW_PARAMS_PARAM_PFVF_ACTIVE_FILTER_END = 0x2E,
++ FW_PARAMS_PARAM_PFVF_ETHOFLD_START = 0x2F,
+ FW_PARAMS_PARAM_PFVF_ETHOFLD_END = 0x30,
+ FW_PARAMS_PARAM_PFVF_CPLFW4MSG_ENCAP = 0x31,
+- FW_PARAMS_PARAM_PFVF_NCRYPTO_LOOKASIDE = 0x32,
++ FW_PARAMS_PARAM_PFVF_HPFILTER_START = 0x32,
++ FW_PARAMS_PARAM_PFVF_HPFILTER_END = 0x33,
++ FW_PARAMS_PARAM_PFVF_NCRYPTO_LOOKASIDE = 0x39,
+ FW_PARAMS_PARAM_PFVF_PORT_CAPS32 = 0x3A,
+ };
+
diff --git a/patches.drivers/cxgb4-collect-TP-dump.patch b/patches.drivers/cxgb4-collect-TP-dump.patch
new file mode 100644
index 0000000000..eb7bcf0da2
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-TP-dump.patch
@@ -0,0 +1,345 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Fri, 13 Oct 2017 18:48:18 +0530
+Subject: cxgb4: collect TP dump
+Patch-mainline: v4.15-rc1
+Git-commit: 4359cf33680c3f276c6bba11730836c41d3540a2
+References: bsc#1064802 bsc#1066129
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 72 +++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 1
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 114 ++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 3
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 2
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 21 +++-
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 20 +++
+ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 2
+ 8 files changed, 234 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -32,4 +32,76 @@ struct cudbg_mbox_log {
+ u32 hi[MBOX_LEN / 8];
+ u32 lo[MBOX_LEN / 8];
+ };
++
++struct ireg_field {
++ u32 ireg_addr;
++ u32 ireg_data;
++ u32 ireg_local_offset;
++ u32 ireg_offset_range;
++};
++
++struct ireg_buf {
++ struct ireg_field tp_pio;
++ u32 outbuf[32];
++};
++
++#define IREG_NUM_ELEM 4
++
++static const u32 t6_tp_pio_array[][IREG_NUM_ELEM] = {
++ {0x7e40, 0x7e44, 0x020, 28}, /* t6_tp_pio_regs_20_to_3b */
++ {0x7e40, 0x7e44, 0x040, 10}, /* t6_tp_pio_regs_40_to_49 */
++ {0x7e40, 0x7e44, 0x050, 10}, /* t6_tp_pio_regs_50_to_59 */
++ {0x7e40, 0x7e44, 0x060, 14}, /* t6_tp_pio_regs_60_to_6d */
++ {0x7e40, 0x7e44, 0x06F, 1}, /* t6_tp_pio_regs_6f */
++ {0x7e40, 0x7e44, 0x070, 6}, /* t6_tp_pio_regs_70_to_75 */
++ {0x7e40, 0x7e44, 0x130, 18}, /* t6_tp_pio_regs_130_to_141 */
++ {0x7e40, 0x7e44, 0x145, 19}, /* t6_tp_pio_regs_145_to_157 */
++ {0x7e40, 0x7e44, 0x160, 1}, /* t6_tp_pio_regs_160 */
++ {0x7e40, 0x7e44, 0x230, 25}, /* t6_tp_pio_regs_230_to_248 */
++ {0x7e40, 0x7e44, 0x24a, 3}, /* t6_tp_pio_regs_24c */
++ {0x7e40, 0x7e44, 0x8C0, 1} /* t6_tp_pio_regs_8c0 */
++};
++
++static const u32 t5_tp_pio_array[][IREG_NUM_ELEM] = {
++ {0x7e40, 0x7e44, 0x020, 28}, /* t5_tp_pio_regs_20_to_3b */
++ {0x7e40, 0x7e44, 0x040, 19}, /* t5_tp_pio_regs_40_to_52 */
++ {0x7e40, 0x7e44, 0x054, 2}, /* t5_tp_pio_regs_54_to_55 */
++ {0x7e40, 0x7e44, 0x060, 13}, /* t5_tp_pio_regs_60_to_6c */
++ {0x7e40, 0x7e44, 0x06F, 1}, /* t5_tp_pio_regs_6f */
++ {0x7e40, 0x7e44, 0x120, 4}, /* t5_tp_pio_regs_120_to_123 */
++ {0x7e40, 0x7e44, 0x12b, 2}, /* t5_tp_pio_regs_12b_to_12c */
++ {0x7e40, 0x7e44, 0x12f, 21}, /* t5_tp_pio_regs_12f_to_143 */
++ {0x7e40, 0x7e44, 0x145, 19}, /* t5_tp_pio_regs_145_to_157 */
++ {0x7e40, 0x7e44, 0x230, 25}, /* t5_tp_pio_regs_230_to_248 */
++ {0x7e40, 0x7e44, 0x8C0, 1} /* t5_tp_pio_regs_8c0 */
++};
++
++static const u32 t6_tp_tm_pio_array[][IREG_NUM_ELEM] = {
++ {0x7e18, 0x7e1c, 0x0, 12}
++};
++
++static const u32 t5_tp_tm_pio_array[][IREG_NUM_ELEM] = {
++ {0x7e18, 0x7e1c, 0x0, 12}
++};
++
++static const u32 t6_tp_mib_index_array[6][IREG_NUM_ELEM] = {
++ {0x7e50, 0x7e54, 0x0, 13},
++ {0x7e50, 0x7e54, 0x10, 6},
++ {0x7e50, 0x7e54, 0x18, 21},
++ {0x7e50, 0x7e54, 0x30, 32},
++ {0x7e50, 0x7e54, 0x50, 22},
++ {0x7e50, 0x7e54, 0x68, 12}
++};
++
++static const u32 t5_tp_mib_index_array[9][IREG_NUM_ELEM] = {
++ {0x7e50, 0x7e54, 0x0, 13},
++ {0x7e50, 0x7e54, 0x10, 6},
++ {0x7e50, 0x7e54, 0x18, 8},
++ {0x7e50, 0x7e54, 0x20, 13},
++ {0x7e50, 0x7e54, 0x30, 16},
++ {0x7e50, 0x7e54, 0x40, 16},
++ {0x7e50, 0x7e54, 0x50, 16},
++ {0x7e50, 0x7e54, 0x60, 6},
++ {0x7e50, 0x7e54, 0x68, 4}
++};
+ #endif /* __CUDBG_ENTITY_H__ */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -31,6 +31,7 @@ enum cudbg_dbg_entity_type {
+ CUDBG_DEV_LOG = 2,
+ CUDBG_EDC0 = 18,
+ CUDBG_EDC1 = 19,
++ CUDBG_TP_INDIRECT = 36,
+ CUDBG_MBOX_LOG = 66,
+ CUDBG_MAX_ENTITY = 70,
+ };
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -253,6 +253,120 @@ int cudbg_collect_edc1_meminfo(struct cu
+ MEM_EDC1);
+ }
+
++int cudbg_collect_tp_indirect(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 ireg_buf *ch_tp_pio;
++ int i, rc, n = 0;
++ u32 size;
++
++ if (is_t5(padap->params.chip))
++ n = sizeof(t5_tp_pio_array) +
++ sizeof(t5_tp_tm_pio_array) +
++ sizeof(t5_tp_mib_index_array);
++ else
++ n = sizeof(t6_tp_pio_array) +
++ sizeof(t6_tp_tm_pio_array) +
++ sizeof(t6_tp_mib_index_array);
++
++ n = n / (IREG_NUM_ELEM * sizeof(u32));
++ size = sizeof(struct ireg_buf) * n;
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ ch_tp_pio = (struct ireg_buf *)temp_buff.data;
++
++ /* TP_PIO */
++ if (is_t5(padap->params.chip))
++ n = sizeof(t5_tp_pio_array) / (IREG_NUM_ELEM * sizeof(u32));
++ else if (is_t6(padap->params.chip))
++ n = sizeof(t6_tp_pio_array) / (IREG_NUM_ELEM * sizeof(u32));
++
++ for (i = 0; i < n; i++) {
++ struct ireg_field *tp_pio = &ch_tp_pio->tp_pio;
++ u32 *buff = ch_tp_pio->outbuf;
++
++ if (is_t5(padap->params.chip)) {
++ tp_pio->ireg_addr = t5_tp_pio_array[i][0];
++ tp_pio->ireg_data = t5_tp_pio_array[i][1];
++ tp_pio->ireg_local_offset = t5_tp_pio_array[i][2];
++ tp_pio->ireg_offset_range = t5_tp_pio_array[i][3];
++ } else if (is_t6(padap->params.chip)) {
++ tp_pio->ireg_addr = t6_tp_pio_array[i][0];
++ tp_pio->ireg_data = t6_tp_pio_array[i][1];
++ tp_pio->ireg_local_offset = t6_tp_pio_array[i][2];
++ tp_pio->ireg_offset_range = t6_tp_pio_array[i][3];
++ }
++ t4_tp_pio_read(padap, buff, tp_pio->ireg_offset_range,
++ tp_pio->ireg_local_offset, true);
++ ch_tp_pio++;
++ }
++
++ /* TP_TM_PIO */
++ if (is_t5(padap->params.chip))
++ n = sizeof(t5_tp_tm_pio_array) / (IREG_NUM_ELEM * sizeof(u32));
++ else if (is_t6(padap->params.chip))
++ n = sizeof(t6_tp_tm_pio_array) / (IREG_NUM_ELEM * sizeof(u32));
++
++ for (i = 0; i < n; i++) {
++ struct ireg_field *tp_pio = &ch_tp_pio->tp_pio;
++ u32 *buff = ch_tp_pio->outbuf;
++
++ if (is_t5(padap->params.chip)) {
++ tp_pio->ireg_addr = t5_tp_tm_pio_array[i][0];
++ tp_pio->ireg_data = t5_tp_tm_pio_array[i][1];
++ tp_pio->ireg_local_offset = t5_tp_tm_pio_array[i][2];
++ tp_pio->ireg_offset_range = t5_tp_tm_pio_array[i][3];
++ } else if (is_t6(padap->params.chip)) {
++ tp_pio->ireg_addr = t6_tp_tm_pio_array[i][0];
++ tp_pio->ireg_data = t6_tp_tm_pio_array[i][1];
++ tp_pio->ireg_local_offset = t6_tp_tm_pio_array[i][2];
++ tp_pio->ireg_offset_range = t6_tp_tm_pio_array[i][3];
++ }
++ t4_tp_tm_pio_read(padap, buff, tp_pio->ireg_offset_range,
++ tp_pio->ireg_local_offset, true);
++ ch_tp_pio++;
++ }
++
++ /* TP_MIB_INDEX */
++ if (is_t5(padap->params.chip))
++ n = sizeof(t5_tp_mib_index_array) /
++ (IREG_NUM_ELEM * sizeof(u32));
++ else if (is_t6(padap->params.chip))
++ n = sizeof(t6_tp_mib_index_array) /
++ (IREG_NUM_ELEM * sizeof(u32));
++
++ for (i = 0; i < n ; i++) {
++ struct ireg_field *tp_pio = &ch_tp_pio->tp_pio;
++ u32 *buff = ch_tp_pio->outbuf;
++
++ if (is_t5(padap->params.chip)) {
++ tp_pio->ireg_addr = t5_tp_mib_index_array[i][0];
++ tp_pio->ireg_data = t5_tp_mib_index_array[i][1];
++ tp_pio->ireg_local_offset =
++ t5_tp_mib_index_array[i][2];
++ tp_pio->ireg_offset_range =
++ t5_tp_mib_index_array[i][3];
++ } else if (is_t6(padap->params.chip)) {
++ tp_pio->ireg_addr = t6_tp_mib_index_array[i][0];
++ tp_pio->ireg_data = t6_tp_mib_index_array[i][1];
++ tp_pio->ireg_local_offset =
++ t6_tp_mib_index_array[i][2];
++ tp_pio->ireg_offset_range =
++ t6_tp_mib_index_array[i][3];
++ }
++ t4_tp_mib_read(padap, buff, tp_pio->ireg_offset_range,
++ tp_pio->ireg_local_offset, true);
++ ch_tp_pio++;
++ }
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
+ int cudbg_collect_mbox_log(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err)
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -30,6 +30,9 @@ int cudbg_collect_edc0_meminfo(struct cu
+ int cudbg_collect_edc1_meminfo(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_tp_indirect(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_mbox_log(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -1634,6 +1634,8 @@ int t4_set_vf_mac_acl(struct adapter *ad
+ unsigned int naddr, u8 *addr);
+ void t4_tp_pio_read(struct adapter *adap, u32 *buff, u32 nregs,
+ u32 start_index, bool sleep_ok);
++void t4_tp_tm_pio_read(struct adapter *adap, u32 *buff, u32 nregs,
++ u32 start_index, bool sleep_ok);
+ void t4_tp_mib_read(struct adapter *adap, u32 *buff, u32 nregs,
+ u32 start_index, bool sleep_ok);
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -29,11 +29,12 @@ static const struct cxgb4_collect_entity
+ { CUDBG_MBOX_LOG, cudbg_collect_mbox_log },
+ { CUDBG_DEV_LOG, cudbg_collect_fw_devlog },
+ { CUDBG_REG_DUMP, cudbg_collect_reg_dump },
++ { CUDBG_TP_INDIRECT, cudbg_collect_tp_indirect },
+ };
+
+ static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
+ {
+- u32 value, len = 0;
++ u32 value, n = 0, len = 0;
+
+ switch (entity) {
+ case CUDBG_REG_DUMP:
+@@ -68,6 +69,24 @@ static u32 cxgb4_get_entity_length(struc
+ }
+ len = cudbg_mbytes_to_bytes(len);
+ break;
++ case CUDBG_TP_INDIRECT:
++ switch (CHELSIO_CHIP_VERSION(adap->params.chip)) {
++ case CHELSIO_T5:
++ n = sizeof(t5_tp_pio_array) +
++ sizeof(t5_tp_tm_pio_array) +
++ sizeof(t5_tp_mib_index_array);
++ break;
++ case CHELSIO_T6:
++ n = sizeof(t6_tp_pio_array) +
++ sizeof(t6_tp_tm_pio_array) +
++ sizeof(t6_tp_mib_index_array);
++ break;
++ default:
++ break;
++ }
++ n = n / (IREG_NUM_ELEM * sizeof(u32));
++ len = sizeof(struct ireg_buf) * n;
++ break;
+ case CUDBG_MBOX_LOG:
+ len = sizeof(struct cudbg_mbox_log) * adap->mbox_log->size;
+ break;
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+@@ -5118,6 +5118,9 @@ static void t4_tp_indirect_rw(struct ada
+ case TP_PIO_ADDR_A:
+ cmd = FW_LDST_ADDRSPC_TP_PIO;
+ break;
++ case TP_TM_PIO_ADDR_A:
++ cmd = FW_LDST_ADDRSPC_TP_TM_PIO;
++ break;
+ case TP_MIB_INDEX_A:
+ cmd = FW_LDST_ADDRSPC_TP_MIB;
+ break;
+@@ -5176,6 +5179,23 @@ static void t4_tp_pio_write(struct adapt
+ }
+
+ /**
++ * t4_tp_tm_pio_read - Read TP TM PIO registers
++ * @adap: the adapter
++ * @buff: where the indirect register values are written
++ * @nregs: how many indirect registers to read
++ * @start_index: index of first indirect register to read
++ * @sleep_ok: if true we may sleep while awaiting command completion
++ *
++ * Read TP TM PIO Registers
++ **/
++void t4_tp_tm_pio_read(struct adapter *adap, u32 *buff, u32 nregs,
++ u32 start_index, bool sleep_ok)
++{
++ t4_tp_indirect_rw(adap, TP_TM_PIO_ADDR_A, TP_TM_PIO_DATA_A, buff,
++ nregs, start_index, 1, sleep_ok);
++}
++
++/**
+ * t4_tp_mib_read - Read TP MIB registers
+ * @adap: the adapter
+ * @buff: where the indirect register values are written
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+@@ -1447,6 +1447,8 @@
+ #define LKPTBLQUEUE0_M 0x3ffU
+ #define LKPTBLQUEUE0_G(x) (((x) >> LKPTBLQUEUE0_S) & LKPTBLQUEUE0_M)
+
++#define TP_TM_PIO_ADDR_A 0x7e18
++#define TP_TM_PIO_DATA_A 0x7e1c
+ #define TP_PIO_ADDR_A 0x7e40
+ #define TP_PIO_DATA_A 0x7e44
+ #define TP_MIB_INDEX_A 0x7e50
diff --git a/patches.drivers/cxgb4-collect-firmware-mbox-and-device-log-dump.patch b/patches.drivers/cxgb4-collect-firmware-mbox-and-device-log-dump.patch
new file mode 100644
index 0000000000..5c4ebf11bf
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-firmware-mbox-and-device-log-dump.patch
@@ -0,0 +1,206 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Fri, 13 Oct 2017 18:48:16 +0530
+Subject: cxgb4: collect firmware mbox and device log dump
+Patch-mainline: v4.15-rc1
+Git-commit: 844d1b6f0ef8051a1ac0403327ab881dd4d101a3
+References: bsc#1064802 bsc#1066129
+
+Collect firmware mbox and device logs before collecting the rest of
+the hardware dumps to snap the firmware state before the mailbox logs
+are updated by other hardware dumps.
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 6 +
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 2
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 84 ++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 6 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 9 ++
+ 5 files changed, 107 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -26,4 +26,10 @@ struct card_mem {
+ u16 size_edc1;
+ u16 mem_flag;
+ };
++
++struct cudbg_mbox_log {
++ struct mbox_cmd entry;
++ u32 hi[MBOX_LEN / 8];
++ u32 lo[MBOX_LEN / 8];
++};
+ #endif /* __CUDBG_ENTITY_H__ */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -28,8 +28,10 @@
+
+ enum cudbg_dbg_entity_type {
+ CUDBG_REG_DUMP = 1,
++ CUDBG_DEV_LOG = 2,
+ CUDBG_EDC0 = 18,
+ CUDBG_EDC1 = 19,
++ CUDBG_MBOX_LOG = 66,
+ CUDBG_MAX_ENTITY = 70,
+ };
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -90,6 +90,45 @@ int cudbg_collect_reg_dump(struct cudbg_
+ return rc;
+ }
+
++int cudbg_collect_fw_devlog(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 devlog_params *dparams;
++ int rc = 0;
++
++ rc = t4_init_devlog_params(padap);
++ if (rc < 0) {
++ cudbg_err->sys_err = rc;
++ return rc;
++ }
++
++ dparams = &padap->params.devlog;
++ rc = cudbg_get_buff(dbg_buff, dparams->size, &temp_buff);
++ if (rc)
++ return rc;
++
++ /* Collect FW devlog */
++ if (dparams->start != 0) {
++ spin_lock(&padap->win0_lock);
++ rc = t4_memory_rw(padap, padap->params.drv_memwin,
++ dparams->memtype, dparams->start,
++ dparams->size,
++ (__be32 *)(char *)temp_buff.data,
++ 1);
++ spin_unlock(&padap->win0_lock);
++ 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;
++}
++
+ static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff, u8 mem_type,
+ unsigned long tot_len,
+@@ -213,3 +252,48 @@ int cudbg_collect_edc1_meminfo(struct cu
+ return cudbg_collect_mem_region(pdbg_init, dbg_buff, cudbg_err,
+ MEM_EDC1);
+ }
++
++int cudbg_collect_mbox_log(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err)
++{
++ struct adapter *padap = pdbg_init->adap;
++ struct cudbg_mbox_log *mboxlog = NULL;
++ struct cudbg_buffer temp_buff = { 0 };
++ struct mbox_cmd_log *log = NULL;
++ struct mbox_cmd *entry;
++ unsigned int entry_idx;
++ u16 mbox_cmds;
++ int i, k, rc;
++ u64 flit;
++ u32 size;
++
++ log = padap->mbox_log;
++ mbox_cmds = padap->mbox_log->size;
++ size = sizeof(struct cudbg_mbox_log) * mbox_cmds;
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ mboxlog = (struct cudbg_mbox_log *)temp_buff.data;
++ for (k = 0; k < mbox_cmds; k++) {
++ entry_idx = log->cursor + k;
++ if (entry_idx >= log->size)
++ entry_idx -= log->size;
++
++ entry = mbox_cmd_log_entry(log, entry_idx);
++ /* skip over unused entries */
++ if (entry->timestamp == 0)
++ continue;
++
++ memcpy(&mboxlog->entry, entry, sizeof(struct mbox_cmd));
++ for (i = 0; i < MBOX_LEN / 8; i++) {
++ flit = entry->cmd[i];
++ mboxlog->hi[i] = (u32)(flit >> 32);
++ mboxlog->lo[i] = (u32)flit;
++ }
++ mboxlog++;
++ }
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -21,12 +21,18 @@
+ int cudbg_collect_reg_dump(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_fw_devlog(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_edc0_meminfo(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+ int cudbg_collect_edc1_meminfo(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_mbox_log(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,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -18,6 +18,7 @@
+ #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 },
+@@ -25,6 +26,8 @@ static const struct cxgb4_collect_entity
+ };
+
+ static const struct cxgb4_collect_entity cxgb4_collect_hw_dump[] = {
++ { CUDBG_MBOX_LOG, cudbg_collect_mbox_log },
++ { CUDBG_DEV_LOG, cudbg_collect_fw_devlog },
+ { CUDBG_REG_DUMP, cudbg_collect_reg_dump },
+ };
+
+@@ -46,6 +49,9 @@ static u32 cxgb4_get_entity_length(struc
+ break;
+ }
+ break;
++ case CUDBG_DEV_LOG:
++ len = adap->params.devlog.size;
++ break;
+ case CUDBG_EDC0:
+ value = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A);
+ if (value & EDRAM0_ENABLE_F) {
+@@ -62,6 +68,9 @@ static u32 cxgb4_get_entity_length(struc
+ }
+ len = cudbg_mbytes_to_bytes(len);
+ break;
++ case CUDBG_MBOX_LOG:
++ len = sizeof(struct cudbg_mbox_log) * adap->mbox_log->size;
++ break;
+ default:
+ break;
+ }
diff --git a/patches.drivers/cxgb4-collect-hardware-LA-dumps.patch b/patches.drivers/cxgb4-collect-hardware-LA-dumps.patch
new file mode 100644
index 0000000000..e3b327a2bf
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-hardware-LA-dumps.patch
@@ -0,0 +1,400 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Thu, 26 Oct 2017 17:18:33 +0530
+Subject: cxgb4: collect hardware LA dumps
+Patch-mainline: v4.15-rc1
+Git-commit: 27887bc7cb7fc5a0a3b8f4b0f27b332c8121515b
+References: bsc#1064802 bsc#1066129
+
+Collect CIM, CIM_MA, ULP_RX, TP, CIM_PIF, and ULP_TX logic analyzer
+dumps.
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 26 +++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 6
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 164 ++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 18 ++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 32 ++++
+ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 4
+ 6 files changed, 250 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -45,6 +45,32 @@ struct ireg_buf {
+ u32 outbuf[32];
+ };
+
++struct cudbg_ulprx_la {
++ u32 data[ULPRX_LA_SIZE * 8];
++ u32 size;
++};
++
++struct cudbg_tp_la {
++ u32 size;
++ u32 mode;
++ u8 data[0];
++};
++
++struct cudbg_cim_pif_la {
++ int size;
++ u8 data[0];
++};
++
++#define CUDBG_NUM_ULPTX 11
++#define CUDBG_NUM_ULPTX_READ 512
++
++struct cudbg_ulptx_la {
++ u32 rdptr[CUDBG_NUM_ULPTX];
++ u32 wrptr[CUDBG_NUM_ULPTX];
++ u32 rddata[CUDBG_NUM_ULPTX];
++ u32 rd_data[CUDBG_NUM_ULPTX][CUDBG_NUM_ULPTX_READ];
++};
++
+ #define IREG_NUM_ELEM 4
+
+ static const u32 t6_tp_pio_array[][IREG_NUM_ELEM] = {
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -29,6 +29,8 @@
+ enum cudbg_dbg_entity_type {
+ CUDBG_REG_DUMP = 1,
+ CUDBG_DEV_LOG = 2,
++ CUDBG_CIM_LA = 3,
++ CUDBG_CIM_MA_LA = 4,
+ CUDBG_CIM_IBQ_TP0 = 6,
+ CUDBG_CIM_IBQ_TP1 = 7,
+ CUDBG_CIM_IBQ_ULP = 8,
+@@ -45,11 +47,15 @@ enum cudbg_dbg_entity_type {
+ CUDBG_EDC1 = 19,
+ CUDBG_TP_INDIRECT = 36,
+ CUDBG_SGE_INDIRECT = 37,
++ CUDBG_ULPRX_LA = 41,
++ CUDBG_TP_LA = 43,
++ CUDBG_CIM_PIF_LA = 45,
+ CUDBG_CIM_OBQ_RXQ0 = 47,
+ CUDBG_CIM_OBQ_RXQ1 = 48,
+ CUDBG_PCIE_INDIRECT = 50,
+ CUDBG_PM_INDIRECT = 51,
+ CUDBG_MA_INDIRECT = 61,
++ CUDBG_ULPTX_LA = 62,
+ CUDBG_UP_CIM_INDIRECT = 64,
+ CUDBG_MBOX_LOG = 66,
+ CUDBG_HMA_INDIRECT = 67,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -129,6 +129,69 @@ int cudbg_collect_fw_devlog(struct cudbg
+ return rc;
+ }
+
++int cudbg_collect_cim_la(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 };
++ int size, rc;
++ u32 cfg = 0;
++
++ if (is_t6(padap->params.chip)) {
++ size = padap->params.cim_la_size / 10 + 1;
++ size *= 11 * sizeof(u32);
++ } else {
++ size = padap->params.cim_la_size / 8;
++ size *= 8 * sizeof(u32);
++ }
++
++ size += sizeof(cfg);
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ rc = t4_cim_read(padap, UP_UP_DBG_LA_CFG_A, 1, &cfg);
++ if (rc) {
++ cudbg_err->sys_err = rc;
++ cudbg_put_buff(&temp_buff, dbg_buff);
++ return rc;
++ }
++
++ memcpy((char *)temp_buff.data, &cfg, sizeof(cfg));
++ rc = t4_cim_read_la(padap,
++ (u32 *)((char *)temp_buff.data + sizeof(cfg)),
++ NULL);
++ if (rc < 0) {
++ 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_ma_la(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 };
++ int size, rc;
++
++ size = 2 * CIM_MALA_SIZE * 5 * sizeof(u32);
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ t4_cim_read_ma_la(padap,
++ (u32 *)temp_buff.data,
++ (u32 *)((char *)temp_buff.data +
++ 5 * CIM_MALA_SIZE));
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
+ static int cudbg_read_cim_ibq(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err, int qid)
+@@ -574,6 +637,72 @@ int cudbg_collect_sge_indirect(struct cu
+ return rc;
+ }
+
++int cudbg_collect_ulprx_la(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_ulprx_la *ulprx_la_buff;
++ int rc;
++
++ rc = cudbg_get_buff(dbg_buff, sizeof(struct cudbg_ulprx_la),
++ &temp_buff);
++ if (rc)
++ return rc;
++
++ ulprx_la_buff = (struct cudbg_ulprx_la *)temp_buff.data;
++ t4_ulprx_read_la(padap, (u32 *)ulprx_la_buff->data);
++ ulprx_la_buff->size = ULPRX_LA_SIZE;
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
++int cudbg_collect_tp_la(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_tp_la *tp_la_buff;
++ int size, rc;
++
++ size = sizeof(struct cudbg_tp_la) + TPLA_SIZE * sizeof(u64);
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ tp_la_buff = (struct cudbg_tp_la *)temp_buff.data;
++ tp_la_buff->mode = DBGLAMODE_G(t4_read_reg(padap, TP_DBG_LA_CONFIG_A));
++ t4_tp_read_la(padap, (u64 *)tp_la_buff->data, NULL);
++ 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)
++{
++ struct cudbg_cim_pif_la *cim_pif_la_buff;
++ struct adapter *padap = pdbg_init->adap;
++ struct cudbg_buffer temp_buff = { 0 };
++ int size, rc;
++
++ size = sizeof(struct cudbg_cim_pif_la) +
++ 2 * CIM_PIFLA_SIZE * 6 * sizeof(u32);
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ cim_pif_la_buff = (struct cudbg_cim_pif_la *)temp_buff.data;
++ cim_pif_la_buff->size = CIM_PIFLA_SIZE;
++ t4_cim_read_pif_la(padap, (u32 *)cim_pif_la_buff->data,
++ (u32 *)cim_pif_la_buff->data + 6 * CIM_PIFLA_SIZE,
++ NULL, NULL);
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
+ int cudbg_collect_pcie_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err)
+@@ -741,6 +870,41 @@ int cudbg_collect_ma_indirect(struct cud
+ }
+ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
+ return rc;
++}
++
++int cudbg_collect_ulptx_la(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_ulptx_la *ulptx_la_buff;
++ u32 i, j;
++ int rc;
++
++ rc = cudbg_get_buff(dbg_buff, sizeof(struct cudbg_ulptx_la),
++ &temp_buff);
++ if (rc)
++ return rc;
++
++ ulptx_la_buff = (struct cudbg_ulptx_la *)temp_buff.data;
++ for (i = 0; i < CUDBG_NUM_ULPTX; i++) {
++ ulptx_la_buff->rdptr[i] = t4_read_reg(padap,
++ ULP_TX_LA_RDPTR_0_A +
++ 0x10 * i);
++ ulptx_la_buff->wrptr[i] = t4_read_reg(padap,
++ ULP_TX_LA_WRPTR_0_A +
++ 0x10 * i);
++ ulptx_la_buff->rddata[i] = t4_read_reg(padap,
++ ULP_TX_LA_RDDATA_0_A +
++ 0x10 * i);
++ for (j = 0; j < CUDBG_NUM_ULPTX_READ; j++)
++ ulptx_la_buff->rd_data[i][j] =
++ t4_read_reg(padap,
++ ULP_TX_LA_RDDATA_0_A + 0x10 * i);
++ }
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
+ }
+
+ int cudbg_collect_up_cim_indirect(struct cudbg_init *pdbg_init,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -24,6 +24,12 @@ int cudbg_collect_reg_dump(struct cudbg_
+ int cudbg_collect_fw_devlog(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_la(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_cim_ma_la(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_cim_ibq_tp0(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+@@ -72,6 +78,15 @@ int cudbg_collect_tp_indirect(struct cud
+ int cudbg_collect_sge_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_ulprx_la(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_tp_la(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);
+ int cudbg_collect_obq_sge_rx_q0(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+@@ -87,6 +102,9 @@ int cudbg_collect_pm_indirect(struct cud
+ int cudbg_collect_ma_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_ulptx_la(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_up_cim_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -29,6 +29,8 @@ static const struct cxgb4_collect_entity
+ { CUDBG_MBOX_LOG, cudbg_collect_mbox_log },
+ { CUDBG_DEV_LOG, cudbg_collect_fw_devlog },
+ { CUDBG_REG_DUMP, cudbg_collect_reg_dump },
++ { CUDBG_CIM_LA, cudbg_collect_cim_la },
++ { CUDBG_CIM_MA_LA, cudbg_collect_cim_ma_la },
+ { CUDBG_CIM_IBQ_TP0, cudbg_collect_cim_ibq_tp0 },
+ { CUDBG_CIM_IBQ_TP1, cudbg_collect_cim_ibq_tp1 },
+ { CUDBG_CIM_IBQ_ULP, cudbg_collect_cim_ibq_ulp },
+@@ -43,11 +45,15 @@ static const struct cxgb4_collect_entity
+ { CUDBG_CIM_OBQ_NCSI, cudbg_collect_cim_obq_ncsi },
+ { CUDBG_TP_INDIRECT, cudbg_collect_tp_indirect },
+ { CUDBG_SGE_INDIRECT, cudbg_collect_sge_indirect },
++ { CUDBG_ULPRX_LA, cudbg_collect_ulprx_la },
++ { CUDBG_TP_LA, cudbg_collect_tp_la },
++ { CUDBG_CIM_PIF_LA, cudbg_collect_cim_pif_la },
+ { CUDBG_CIM_OBQ_RXQ0, cudbg_collect_obq_sge_rx_q0 },
+ { CUDBG_CIM_OBQ_RXQ1, cudbg_collect_obq_sge_rx_q1 },
+ { CUDBG_PCIE_INDIRECT, cudbg_collect_pcie_indirect },
+ { CUDBG_PM_INDIRECT, cudbg_collect_pm_indirect },
+ { CUDBG_MA_INDIRECT, cudbg_collect_ma_indirect },
++ { CUDBG_ULPTX_LA, cudbg_collect_ulptx_la },
+ { CUDBG_UP_CIM_INDIRECT, cudbg_collect_up_cim_indirect },
+ { CUDBG_HMA_INDIRECT, cudbg_collect_hma_indirect },
+ };
+@@ -73,6 +79,19 @@ static u32 cxgb4_get_entity_length(struc
+ case CUDBG_DEV_LOG:
+ len = adap->params.devlog.size;
+ break;
++ case CUDBG_CIM_LA:
++ if (is_t6(adap->params.chip)) {
++ len = adap->params.cim_la_size / 10 + 1;
++ len *= 11 * sizeof(u32);
++ } else {
++ len = adap->params.cim_la_size / 8;
++ len *= 8 * sizeof(u32);
++ }
++ len += sizeof(u32); /* for reading CIM LA configuration */
++ break;
++ case CUDBG_CIM_MA_LA:
++ len = 2 * CIM_MALA_SIZE * 5 * sizeof(u32);
++ break;
+ case CUDBG_CIM_IBQ_TP0:
+ case CUDBG_CIM_IBQ_TP1:
+ case CUDBG_CIM_IBQ_ULP:
+@@ -142,6 +161,16 @@ static u32 cxgb4_get_entity_length(struc
+ case CUDBG_SGE_INDIRECT:
+ len = sizeof(struct ireg_buf) * 2;
+ break;
++ case CUDBG_ULPRX_LA:
++ len = sizeof(struct cudbg_ulprx_la);
++ break;
++ case CUDBG_TP_LA:
++ len = sizeof(struct cudbg_tp_la) + TPLA_SIZE * sizeof(u64);
++ break;
++ case CUDBG_CIM_PIF_LA:
++ len = sizeof(struct cudbg_cim_pif_la);
++ len += 2 * CIM_PIFLA_SIZE * 6 * sizeof(u32);
++ break;
+ case CUDBG_PCIE_INDIRECT:
+ n = sizeof(t5_pcie_pdbg_array) / (IREG_NUM_ELEM * sizeof(u32));
+ len = sizeof(struct ireg_buf) * n * 2;
+@@ -157,6 +186,9 @@ static u32 cxgb4_get_entity_length(struc
+ len = sizeof(struct ireg_buf) * n * 2;
+ }
+ break;
++ case CUDBG_ULPTX_LA:
++ len = sizeof(struct cudbg_ulptx_la);
++ break;
+ case CUDBG_UP_CIM_INDIRECT:
+ n = sizeof(t5_up_cim_reg_array) / (IREG_NUM_ELEM * sizeof(u32));
+ len = sizeof(struct ireg_buf) * n;
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+@@ -1629,6 +1629,10 @@
+ #define IESPI_PAR_ERROR_V(x) ((x) << IESPI_PAR_ERROR_S)
+ #define IESPI_PAR_ERROR_F IESPI_PAR_ERROR_V(1U)
+
++#define ULP_TX_LA_RDPTR_0_A 0x8ec0
++#define ULP_TX_LA_RDDATA_0_A 0x8ec4
++#define ULP_TX_LA_WRPTR_0_A 0x8ec8
++
+ #define PMRX_E_PCMD_PAR_ERROR_S 0
+ #define PMRX_E_PCMD_PAR_ERROR_V(x) ((x) << PMRX_E_PCMD_PAR_ERROR_S)
+ #define PMRX_E_PCMD_PAR_ERROR_F PMRX_E_PCMD_PAR_ERROR_V(1U)
diff --git a/patches.drivers/cxgb4-collect-hardware-misc-dumps.patch b/patches.drivers/cxgb4-collect-hardware-misc-dumps.patch
new file mode 100644
index 0000000000..3302e18bfd
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-hardware-misc-dumps.patch
@@ -0,0 +1,365 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Thu, 26 Oct 2017 17:18:40 +0530
+Subject: cxgb4: collect hardware misc dumps
+Patch-mainline: v4.15-rc1
+Git-commit: 6f92a6544f1a4ed2d495a937283f01ee7d590fec
+References: bsc#1064802 bsc#1066129
+
+Collect path mtu, PM stats, TP clock info, congestion control, and VPD
+data dumps.
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 36 +++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 5
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 135 ++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 15 ++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 20 +++
+ 5 files changed, 211 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -49,6 +49,13 @@ struct cudbg_rss_vf_conf {
+ u32 rss_vf_vfh;
+ };
+
++struct cudbg_pm_stats {
++ u32 tx_cnt[T6_PM_NSTATS];
++ u32 rx_cnt[T6_PM_NSTATS];
++ u64 tx_cyc[T6_PM_NSTATS];
++ u64 rx_cyc[T6_PM_NSTATS];
++};
++
+ struct cudbg_hw_sched {
+ u32 kbps[NTX_SCHED];
+ u32 ipg[NTX_SCHED];
+@@ -85,6 +92,22 @@ struct cudbg_cim_pif_la {
+ u8 data[0];
+ };
+
++struct cudbg_clk_info {
++ u64 retransmit_min;
++ u64 retransmit_max;
++ u64 persist_timer_min;
++ u64 persist_timer_max;
++ u64 keepalive_idle_timer;
++ u64 keepalive_interval;
++ u64 initial_srtt;
++ u64 finwait2_timer;
++ u32 dack_timer;
++ u32 res;
++ u32 cclk_ps;
++ u32 tre;
++ u32 dack_re;
++};
++
+ struct cudbg_tid_info_region {
+ u32 ntids;
+ u32 nstids;
+@@ -143,6 +166,19 @@ struct cudbg_mps_tcam {
+ u8 reserved[2];
+ };
+
++struct cudbg_vpd_data {
++ u8 sn[SERNUM_LEN + 1];
++ u8 bn[PN_LEN + 1];
++ u8 na[MACADDR_LEN + 1];
++ u8 mn[ID_LEN + 1];
++ u16 fw_major;
++ u16 fw_minor;
++ u16 fw_micro;
++ u16 fw_build;
++ u32 scfg_vers;
++ u32 vpd_vers;
++};
++
+ #define CUDBG_NUM_ULPTX 11
+ #define CUDBG_NUM_ULPTX_READ 512
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -49,18 +49,23 @@ enum cudbg_dbg_entity_type {
+ CUDBG_EDC1 = 19,
+ CUDBG_RSS = 22,
+ CUDBG_RSS_VF_CONF = 25,
++ CUDBG_PATH_MTU = 27,
++ CUDBG_PM_STATS = 30,
+ CUDBG_HW_SCHED = 31,
+ CUDBG_TP_INDIRECT = 36,
+ CUDBG_SGE_INDIRECT = 37,
+ CUDBG_ULPRX_LA = 41,
+ CUDBG_TP_LA = 43,
+ CUDBG_CIM_PIF_LA = 45,
++ CUDBG_CLK = 46,
+ CUDBG_CIM_OBQ_RXQ0 = 47,
+ CUDBG_CIM_OBQ_RXQ1 = 48,
+ CUDBG_PCIE_INDIRECT = 50,
+ CUDBG_PM_INDIRECT = 51,
+ CUDBG_TID_INFO = 54,
+ CUDBG_MPS_TCAM = 57,
++ CUDBG_VPD_DATA = 58,
++ CUDBG_CCTRL = 60,
+ CUDBG_MA_INDIRECT = 61,
+ CUDBG_ULPTX_LA = 62,
+ CUDBG_UP_CIM_INDIRECT = 64,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -574,6 +574,44 @@ int cudbg_collect_rss_vf_config(struct c
+ return rc;
+ }
+
++int cudbg_collect_path_mtu(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 };
++ int rc;
++
++ rc = cudbg_get_buff(dbg_buff, NMTUS * sizeof(u16), &temp_buff);
++ if (rc)
++ return rc;
++
++ t4_read_mtu_tbl(padap, (u16 *)temp_buff.data, NULL);
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
++int cudbg_collect_pm_stats(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_pm_stats *pm_stats_buff;
++ int rc;
++
++ rc = cudbg_get_buff(dbg_buff, sizeof(struct cudbg_pm_stats),
++ &temp_buff);
++ if (rc)
++ return rc;
++
++ pm_stats_buff = (struct cudbg_pm_stats *)temp_buff.data;
++ t4_pmtx_get_stats(padap, pm_stats_buff->tx_cnt, pm_stats_buff->tx_cyc);
++ t4_pmrx_get_stats(padap, pm_stats_buff->rx_cnt, pm_stats_buff->rx_cyc);
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
+ int cudbg_collect_hw_sched(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err)
+@@ -813,6 +851,55 @@ int cudbg_collect_cim_pif_la(struct cudb
+ return rc;
+ }
+
++int cudbg_collect_clk_info(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_clk_info *clk_info_buff;
++ u64 tp_tick_us;
++ int rc;
++
++ if (!padap->params.vpd.cclk)
++ return CUDBG_STATUS_CCLK_NOT_DEFINED;
++
++ rc = cudbg_get_buff(dbg_buff, sizeof(struct cudbg_clk_info),
++ &temp_buff);
++ if (rc)
++ return rc;
++
++ clk_info_buff = (struct cudbg_clk_info *)temp_buff.data;
++ clk_info_buff->cclk_ps = 1000000000 / padap->params.vpd.cclk; /* psec */
++ clk_info_buff->res = t4_read_reg(padap, TP_TIMER_RESOLUTION_A);
++ clk_info_buff->tre = TIMERRESOLUTION_G(clk_info_buff->res);
++ clk_info_buff->dack_re = DELAYEDACKRESOLUTION_G(clk_info_buff->res);
++ tp_tick_us = (clk_info_buff->cclk_ps << clk_info_buff->tre) / 1000000;
++
++ clk_info_buff->dack_timer =
++ (clk_info_buff->cclk_ps << clk_info_buff->dack_re) / 1000000 *
++ t4_read_reg(padap, TP_DACK_TIMER_A);
++ clk_info_buff->retransmit_min =
++ tp_tick_us * t4_read_reg(padap, TP_RXT_MIN_A);
++ clk_info_buff->retransmit_max =
++ tp_tick_us * t4_read_reg(padap, TP_RXT_MAX_A);
++ clk_info_buff->persist_timer_min =
++ tp_tick_us * t4_read_reg(padap, TP_PERS_MIN_A);
++ clk_info_buff->persist_timer_max =
++ tp_tick_us * t4_read_reg(padap, TP_PERS_MAX_A);
++ clk_info_buff->keepalive_idle_timer =
++ tp_tick_us * t4_read_reg(padap, TP_KEEP_IDLE_A);
++ clk_info_buff->keepalive_interval =
++ tp_tick_us * t4_read_reg(padap, TP_KEEP_INTVL_A);
++ clk_info_buff->initial_srtt =
++ tp_tick_us * INITSRTT_G(t4_read_reg(padap, TP_INIT_SRTT_A));
++ clk_info_buff->finwait2_timer =
++ tp_tick_us * t4_read_reg(padap, TP_FINWAIT2_TIMER_A);
++
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
+ int cudbg_collect_pcie_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err)
+@@ -1195,6 +1282,54 @@ int cudbg_collect_mps_tcam(struct cudbg_
+ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
+ return rc;
+ }
++
++int cudbg_collect_vpd_data(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_vpd_data *vpd_data;
++ int rc;
++
++ rc = cudbg_get_buff(dbg_buff, sizeof(struct cudbg_vpd_data),
++ &temp_buff);
++ if (rc)
++ return rc;
++
++ vpd_data = (struct cudbg_vpd_data *)temp_buff.data;
++ memcpy(vpd_data->sn, padap->params.vpd.sn, SERNUM_LEN + 1);
++ memcpy(vpd_data->bn, padap->params.vpd.pn, PN_LEN + 1);
++ memcpy(vpd_data->na, padap->params.vpd.na, MACADDR_LEN + 1);
++ memcpy(vpd_data->mn, padap->params.vpd.id, ID_LEN + 1);
++ vpd_data->scfg_vers = padap->params.scfg_vers;
++ vpd_data->vpd_vers = padap->params.vpd_vers;
++ vpd_data->fw_major = FW_HDR_FW_VER_MAJOR_G(padap->params.fw_vers);
++ vpd_data->fw_minor = FW_HDR_FW_VER_MINOR_G(padap->params.fw_vers);
++ vpd_data->fw_micro = FW_HDR_FW_VER_MICRO_G(padap->params.fw_vers);
++ vpd_data->fw_build = FW_HDR_FW_VER_BUILD_G(padap->params.fw_vers);
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
++int cudbg_collect_cctrl(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;
++ int rc;
++
++ size = sizeof(u16) * NMTUS * NCCTRL_WIN;
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ t4_read_cong_tbl(padap, (void *)temp_buff.data);
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
+
+ int cudbg_collect_ma_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -84,6 +84,12 @@ int cudbg_collect_rss_vf_config(struct c
+ int cudbg_collect_tp_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_path_mtu(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_pm_stats(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_hw_sched(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+@@ -99,6 +105,9 @@ int cudbg_collect_tp_la(struct cudbg_ini
+ int cudbg_collect_cim_pif_la(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_clk_info(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_obq_sge_rx_q0(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+@@ -117,6 +126,12 @@ int cudbg_collect_tid(struct cudbg_init
+ int cudbg_collect_mps_tcam(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_vpd_data(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_cctrl(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_ma_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -46,18 +46,23 @@ static const struct cxgb4_collect_entity
+ { CUDBG_CIM_OBQ_NCSI, cudbg_collect_cim_obq_ncsi },
+ { CUDBG_RSS, cudbg_collect_rss },
+ { CUDBG_RSS_VF_CONF, cudbg_collect_rss_vf_config },
++ { CUDBG_PATH_MTU, cudbg_collect_path_mtu },
++ { CUDBG_PM_STATS, cudbg_collect_pm_stats },
+ { CUDBG_HW_SCHED, cudbg_collect_hw_sched },
+ { CUDBG_TP_INDIRECT, cudbg_collect_tp_indirect },
+ { CUDBG_SGE_INDIRECT, cudbg_collect_sge_indirect },
+ { CUDBG_ULPRX_LA, cudbg_collect_ulprx_la },
+ { CUDBG_TP_LA, cudbg_collect_tp_la },
+ { 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 },
+ { CUDBG_CIM_OBQ_RXQ1, cudbg_collect_obq_sge_rx_q1 },
+ { CUDBG_PCIE_INDIRECT, cudbg_collect_pcie_indirect },
+ { CUDBG_PM_INDIRECT, cudbg_collect_pm_indirect },
+ { CUDBG_TID_INFO, cudbg_collect_tid },
+ { CUDBG_MPS_TCAM, cudbg_collect_mps_tcam },
++ { CUDBG_VPD_DATA, cudbg_collect_vpd_data },
++ { CUDBG_CCTRL, cudbg_collect_cctrl },
+ { CUDBG_MA_INDIRECT, cudbg_collect_ma_indirect },
+ { CUDBG_ULPTX_LA, cudbg_collect_ulptx_la },
+ { CUDBG_UP_CIM_INDIRECT, cudbg_collect_up_cim_indirect },
+@@ -157,6 +162,12 @@ static u32 cxgb4_get_entity_length(struc
+ len = adap->params.arch.vfcount *
+ sizeof(struct cudbg_rss_vf_conf);
+ break;
++ case CUDBG_PATH_MTU:
++ len = NMTUS * sizeof(u16);
++ break;
++ case CUDBG_PM_STATS:
++ len = sizeof(struct cudbg_pm_stats);
++ break;
+ case CUDBG_HW_SCHED:
+ len = sizeof(struct cudbg_hw_sched);
+ break;
+@@ -191,6 +202,9 @@ static u32 cxgb4_get_entity_length(struc
+ len = sizeof(struct cudbg_cim_pif_la);
+ len += 2 * CIM_PIFLA_SIZE * 6 * sizeof(u32);
+ break;
++ case CUDBG_CLK:
++ len = sizeof(struct cudbg_clk_info);
++ break;
+ case CUDBG_PCIE_INDIRECT:
+ n = sizeof(t5_pcie_pdbg_array) / (IREG_NUM_ELEM * sizeof(u32));
+ len = sizeof(struct ireg_buf) * n * 2;
+@@ -206,6 +220,12 @@ static u32 cxgb4_get_entity_length(struc
+ len = sizeof(struct cudbg_mps_tcam) *
+ adap->params.arch.mps_tcam_size;
+ break;
++ case CUDBG_VPD_DATA:
++ len = sizeof(struct cudbg_vpd_data);
++ break;
++ case CUDBG_CCTRL:
++ len = sizeof(u16) * NMTUS * NCCTRL_WIN;
++ break;
+ case CUDBG_MA_INDIRECT:
+ if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) {
+ n = sizeof(t6_ma_ireg_array) /
diff --git a/patches.drivers/cxgb4-collect-hardware-module-dumps.patch b/patches.drivers/cxgb4-collect-hardware-module-dumps.patch
new file mode 100644
index 0000000000..601b8fac44
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-hardware-module-dumps.patch
@@ -0,0 +1,505 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Fri, 13 Oct 2017 18:48:19 +0530
+Subject: cxgb4: collect hardware module dumps
+Patch-mainline: v4.15-rc1
+Git-commit: 270d39bf324ecdb9ab3f9c521e6b7fd9cc6c27b8
+References: bsc#1064802 bsc#1066129
+
+Collect SGE, PCIE, PM, UP CIM, MA and HMA dumps.
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 74 +++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 6
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 289 ++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 18 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 35 ++
+ 5 files changed, 422 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -104,4 +104,78 @@ static const u32 t5_tp_mib_index_array[9
+ {0x7e50, 0x7e54, 0x60, 6},
+ {0x7e50, 0x7e54, 0x68, 4}
+ };
++
++static const u32 t5_sge_dbg_index_array[2][IREG_NUM_ELEM] = {
++ {0x10cc, 0x10d0, 0x0, 16},
++ {0x10cc, 0x10d4, 0x0, 16},
++};
++
++static const u32 t5_pcie_pdbg_array[][IREG_NUM_ELEM] = {
++ {0x5a04, 0x5a0c, 0x00, 0x20}, /* t5_pcie_pdbg_regs_00_to_20 */
++ {0x5a04, 0x5a0c, 0x21, 0x20}, /* t5_pcie_pdbg_regs_21_to_40 */
++ {0x5a04, 0x5a0c, 0x41, 0x10}, /* t5_pcie_pdbg_regs_41_to_50 */
++};
++
++static const u32 t5_pcie_cdbg_array[][IREG_NUM_ELEM] = {
++ {0x5a10, 0x5a18, 0x00, 0x20}, /* t5_pcie_cdbg_regs_00_to_20 */
++ {0x5a10, 0x5a18, 0x21, 0x18}, /* t5_pcie_cdbg_regs_21_to_37 */
++};
++
++static const u32 t5_pm_rx_array[][IREG_NUM_ELEM] = {
++ {0x8FD0, 0x8FD4, 0x10000, 0x20}, /* t5_pm_rx_regs_10000_to_10020 */
++ {0x8FD0, 0x8FD4, 0x10021, 0x0D}, /* t5_pm_rx_regs_10021_to_1002c */
++};
++
++static const u32 t5_pm_tx_array[][IREG_NUM_ELEM] = {
++ {0x8FF0, 0x8FF4, 0x10000, 0x20}, /* t5_pm_tx_regs_10000_to_10020 */
++ {0x8FF0, 0x8FF4, 0x10021, 0x1D}, /* t5_pm_tx_regs_10021_to_1003c */
++};
++
++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 */
++ {0x78f8, 0x78fc, 0xa800, 20} /* t6_ma_regs_a800_to_a813 */
++};
++
++static const u32 t6_ma_ireg_array2[][IREG_NUM_ELEM] = {
++ {0x78f8, 0x78fc, 0xe400, 17}, /* t6_ma_regs_e400_to_e600 */
++ {0x78f8, 0x78fc, 0xe640, 13} /* t6_ma_regs_e640_to_e7c0 */
++};
++
++static const u32 t6_up_cim_reg_array[][IREG_NUM_ELEM] = {
++ {0x7b50, 0x7b54, 0x2000, 0x20}, /* up_cim_2000_to_207c */
++ {0x7b50, 0x7b54, 0x2080, 0x1d}, /* up_cim_2080_to_20fc */
++ {0x7b50, 0x7b54, 0x00, 0x20}, /* up_cim_00_to_7c */
++ {0x7b50, 0x7b54, 0x80, 0x20}, /* up_cim_80_to_fc */
++ {0x7b50, 0x7b54, 0x100, 0x11}, /* up_cim_100_to_14c */
++ {0x7b50, 0x7b54, 0x200, 0x10}, /* up_cim_200_to_23c */
++ {0x7b50, 0x7b54, 0x240, 0x2}, /* up_cim_240_to_244 */
++ {0x7b50, 0x7b54, 0x250, 0x2}, /* up_cim_250_to_254 */
++ {0x7b50, 0x7b54, 0x260, 0x2}, /* up_cim_260_to_264 */
++ {0x7b50, 0x7b54, 0x270, 0x2}, /* up_cim_270_to_274 */
++ {0x7b50, 0x7b54, 0x280, 0x20}, /* up_cim_280_to_2fc */
++ {0x7b50, 0x7b54, 0x300, 0x20}, /* up_cim_300_to_37c */
++ {0x7b50, 0x7b54, 0x380, 0x14}, /* up_cim_380_to_3cc */
++
++};
++
++static const u32 t5_up_cim_reg_array[][IREG_NUM_ELEM] = {
++ {0x7b50, 0x7b54, 0x2000, 0x20}, /* up_cim_2000_to_207c */
++ {0x7b50, 0x7b54, 0x2080, 0x19}, /* up_cim_2080_to_20ec */
++ {0x7b50, 0x7b54, 0x00, 0x20}, /* up_cim_00_to_7c */
++ {0x7b50, 0x7b54, 0x80, 0x20}, /* up_cim_80_to_fc */
++ {0x7b50, 0x7b54, 0x100, 0x11}, /* up_cim_100_to_14c */
++ {0x7b50, 0x7b54, 0x200, 0x10}, /* up_cim_200_to_23c */
++ {0x7b50, 0x7b54, 0x240, 0x2}, /* up_cim_240_to_244 */
++ {0x7b50, 0x7b54, 0x250, 0x2}, /* up_cim_250_to_254 */
++ {0x7b50, 0x7b54, 0x260, 0x2}, /* up_cim_260_to_264 */
++ {0x7b50, 0x7b54, 0x270, 0x2}, /* up_cim_270_to_274 */
++ {0x7b50, 0x7b54, 0x280, 0x20}, /* up_cim_280_to_2fc */
++ {0x7b50, 0x7b54, 0x300, 0x20}, /* up_cim_300_to_37c */
++ {0x7b50, 0x7b54, 0x380, 0x14}, /* up_cim_380_to_3cc */
++};
++
++static const u32 t6_hma_ireg_array[][IREG_NUM_ELEM] = {
++ {0x51320, 0x51324, 0xa000, 32} /* t6_hma_regs_a000_to_a01f */
++};
+ #endif /* __CUDBG_ENTITY_H__ */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -32,7 +32,13 @@ enum cudbg_dbg_entity_type {
+ CUDBG_EDC0 = 18,
+ CUDBG_EDC1 = 19,
+ CUDBG_TP_INDIRECT = 36,
++ CUDBG_SGE_INDIRECT = 37,
++ CUDBG_PCIE_INDIRECT = 50,
++ CUDBG_PM_INDIRECT = 51,
++ CUDBG_MA_INDIRECT = 61,
++ CUDBG_UP_CIM_INDIRECT = 64,
+ CUDBG_MBOX_LOG = 66,
++ CUDBG_HMA_INDIRECT = 67,
+ CUDBG_MAX_ENTITY = 70,
+ };
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -367,6 +367,258 @@ int cudbg_collect_tp_indirect(struct cud
+ return rc;
+ }
+
++int cudbg_collect_sge_indirect(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 ireg_buf *ch_sge_dbg;
++ int i, rc;
++
++ rc = cudbg_get_buff(dbg_buff, sizeof(*ch_sge_dbg) * 2, &temp_buff);
++ if (rc)
++ return rc;
++
++ ch_sge_dbg = (struct ireg_buf *)temp_buff.data;
++ for (i = 0; i < 2; i++) {
++ struct ireg_field *sge_pio = &ch_sge_dbg->tp_pio;
++ u32 *buff = ch_sge_dbg->outbuf;
++
++ sge_pio->ireg_addr = t5_sge_dbg_index_array[i][0];
++ sge_pio->ireg_data = t5_sge_dbg_index_array[i][1];
++ sge_pio->ireg_local_offset = t5_sge_dbg_index_array[i][2];
++ sge_pio->ireg_offset_range = t5_sge_dbg_index_array[i][3];
++ t4_read_indirect(padap,
++ sge_pio->ireg_addr,
++ sge_pio->ireg_data,
++ buff,
++ sge_pio->ireg_offset_range,
++ sge_pio->ireg_local_offset);
++ ch_sge_dbg++;
++ }
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
++int cudbg_collect_pcie_indirect(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 ireg_buf *ch_pcie;
++ int i, rc, n;
++ u32 size;
++
++ n = sizeof(t5_pcie_pdbg_array) / (IREG_NUM_ELEM * sizeof(u32));
++ size = sizeof(struct ireg_buf) * n * 2;
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ ch_pcie = (struct ireg_buf *)temp_buff.data;
++ /* PCIE_PDBG */
++ for (i = 0; i < n; i++) {
++ struct ireg_field *pcie_pio = &ch_pcie->tp_pio;
++ u32 *buff = ch_pcie->outbuf;
++
++ pcie_pio->ireg_addr = t5_pcie_pdbg_array[i][0];
++ pcie_pio->ireg_data = t5_pcie_pdbg_array[i][1];
++ pcie_pio->ireg_local_offset = t5_pcie_pdbg_array[i][2];
++ pcie_pio->ireg_offset_range = t5_pcie_pdbg_array[i][3];
++ t4_read_indirect(padap,
++ pcie_pio->ireg_addr,
++ pcie_pio->ireg_data,
++ buff,
++ pcie_pio->ireg_offset_range,
++ pcie_pio->ireg_local_offset);
++ ch_pcie++;
++ }
++
++ /* PCIE_CDBG */
++ n = sizeof(t5_pcie_cdbg_array) / (IREG_NUM_ELEM * sizeof(u32));
++ for (i = 0; i < n; i++) {
++ struct ireg_field *pcie_pio = &ch_pcie->tp_pio;
++ u32 *buff = ch_pcie->outbuf;
++
++ pcie_pio->ireg_addr = t5_pcie_cdbg_array[i][0];
++ pcie_pio->ireg_data = t5_pcie_cdbg_array[i][1];
++ pcie_pio->ireg_local_offset = t5_pcie_cdbg_array[i][2];
++ pcie_pio->ireg_offset_range = t5_pcie_cdbg_array[i][3];
++ t4_read_indirect(padap,
++ pcie_pio->ireg_addr,
++ pcie_pio->ireg_data,
++ buff,
++ pcie_pio->ireg_offset_range,
++ pcie_pio->ireg_local_offset);
++ ch_pcie++;
++ }
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
++int cudbg_collect_pm_indirect(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 ireg_buf *ch_pm;
++ int i, rc, n;
++ u32 size;
++
++ n = sizeof(t5_pm_rx_array) / (IREG_NUM_ELEM * sizeof(u32));
++ size = sizeof(struct ireg_buf) * n * 2;
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ ch_pm = (struct ireg_buf *)temp_buff.data;
++ /* PM_RX */
++ for (i = 0; i < n; i++) {
++ struct ireg_field *pm_pio = &ch_pm->tp_pio;
++ u32 *buff = ch_pm->outbuf;
++
++ pm_pio->ireg_addr = t5_pm_rx_array[i][0];
++ pm_pio->ireg_data = t5_pm_rx_array[i][1];
++ pm_pio->ireg_local_offset = t5_pm_rx_array[i][2];
++ pm_pio->ireg_offset_range = t5_pm_rx_array[i][3];
++ t4_read_indirect(padap,
++ pm_pio->ireg_addr,
++ pm_pio->ireg_data,
++ buff,
++ pm_pio->ireg_offset_range,
++ pm_pio->ireg_local_offset);
++ ch_pm++;
++ }
++
++ /* PM_TX */
++ n = sizeof(t5_pm_tx_array) / (IREG_NUM_ELEM * sizeof(u32));
++ for (i = 0; i < n; i++) {
++ struct ireg_field *pm_pio = &ch_pm->tp_pio;
++ u32 *buff = ch_pm->outbuf;
++
++ pm_pio->ireg_addr = t5_pm_tx_array[i][0];
++ pm_pio->ireg_data = t5_pm_tx_array[i][1];
++ pm_pio->ireg_local_offset = t5_pm_tx_array[i][2];
++ pm_pio->ireg_offset_range = t5_pm_tx_array[i][3];
++ t4_read_indirect(padap,
++ pm_pio->ireg_addr,
++ pm_pio->ireg_data,
++ buff,
++ pm_pio->ireg_offset_range,
++ pm_pio->ireg_local_offset);
++ ch_pm++;
++ }
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
++int cudbg_collect_ma_indirect(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 ireg_buf *ma_indr;
++ int i, rc, n;
++ u32 size, j;
++
++ if (CHELSIO_CHIP_VERSION(padap->params.chip) < CHELSIO_T6)
++ return CUDBG_STATUS_ENTITY_NOT_FOUND;
++
++ n = sizeof(t6_ma_ireg_array) / (IREG_NUM_ELEM * sizeof(u32));
++ size = sizeof(struct ireg_buf) * n * 2;
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ ma_indr = (struct ireg_buf *)temp_buff.data;
++ for (i = 0; i < n; i++) {
++ struct ireg_field *ma_fli = &ma_indr->tp_pio;
++ u32 *buff = ma_indr->outbuf;
++
++ ma_fli->ireg_addr = t6_ma_ireg_array[i][0];
++ ma_fli->ireg_data = t6_ma_ireg_array[i][1];
++ ma_fli->ireg_local_offset = t6_ma_ireg_array[i][2];
++ ma_fli->ireg_offset_range = t6_ma_ireg_array[i][3];
++ t4_read_indirect(padap, ma_fli->ireg_addr, ma_fli->ireg_data,
++ buff, ma_fli->ireg_offset_range,
++ ma_fli->ireg_local_offset);
++ ma_indr++;
++ }
++
++ n = sizeof(t6_ma_ireg_array2) / (IREG_NUM_ELEM * sizeof(u32));
++ for (i = 0; i < n; i++) {
++ struct ireg_field *ma_fli = &ma_indr->tp_pio;
++ u32 *buff = ma_indr->outbuf;
++
++ ma_fli->ireg_addr = t6_ma_ireg_array2[i][0];
++ ma_fli->ireg_data = t6_ma_ireg_array2[i][1];
++ ma_fli->ireg_local_offset = t6_ma_ireg_array2[i][2];
++ for (j = 0; j < t6_ma_ireg_array2[i][3]; j++) {
++ t4_read_indirect(padap, ma_fli->ireg_addr,
++ ma_fli->ireg_data, buff, 1,
++ ma_fli->ireg_local_offset);
++ buff++;
++ ma_fli->ireg_local_offset += 0x20;
++ }
++ ma_indr++;
++ }
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
++int cudbg_collect_up_cim_indirect(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 ireg_buf *up_cim;
++ int i, rc, n;
++ u32 size;
++
++ n = sizeof(t5_up_cim_reg_array) / (IREG_NUM_ELEM * sizeof(u32));
++ size = sizeof(struct ireg_buf) * n;
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ up_cim = (struct ireg_buf *)temp_buff.data;
++ for (i = 0; i < n; i++) {
++ struct ireg_field *up_cim_reg = &up_cim->tp_pio;
++ u32 *buff = up_cim->outbuf;
++
++ if (is_t5(padap->params.chip)) {
++ up_cim_reg->ireg_addr = t5_up_cim_reg_array[i][0];
++ up_cim_reg->ireg_data = t5_up_cim_reg_array[i][1];
++ up_cim_reg->ireg_local_offset =
++ t5_up_cim_reg_array[i][2];
++ up_cim_reg->ireg_offset_range =
++ t5_up_cim_reg_array[i][3];
++ } else if (is_t6(padap->params.chip)) {
++ up_cim_reg->ireg_addr = t6_up_cim_reg_array[i][0];
++ up_cim_reg->ireg_data = t6_up_cim_reg_array[i][1];
++ up_cim_reg->ireg_local_offset =
++ t6_up_cim_reg_array[i][2];
++ up_cim_reg->ireg_offset_range =
++ t6_up_cim_reg_array[i][3];
++ }
++
++ rc = t4_cim_read(padap, up_cim_reg->ireg_local_offset,
++ up_cim_reg->ireg_offset_range, buff);
++ if (rc) {
++ cudbg_put_buff(&temp_buff, dbg_buff);
++ return rc;
++ }
++ up_cim++;
++ }
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
+ int cudbg_collect_mbox_log(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err)
+@@ -410,4 +662,41 @@ int cudbg_collect_mbox_log(struct cudbg_
+ }
+ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
+ return rc;
++}
++
++int cudbg_collect_hma_indirect(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 ireg_buf *hma_indr;
++ int i, rc, n;
++ u32 size;
++
++ if (CHELSIO_CHIP_VERSION(padap->params.chip) < CHELSIO_T6)
++ return CUDBG_STATUS_ENTITY_NOT_FOUND;
++
++ n = sizeof(t6_hma_ireg_array) / (IREG_NUM_ELEM * sizeof(u32));
++ size = sizeof(struct ireg_buf) * n;
++ rc = cudbg_get_buff(dbg_buff, size, &temp_buff);
++ if (rc)
++ return rc;
++
++ hma_indr = (struct ireg_buf *)temp_buff.data;
++ for (i = 0; i < n; i++) {
++ struct ireg_field *hma_fli = &hma_indr->tp_pio;
++ u32 *buff = hma_indr->outbuf;
++
++ hma_fli->ireg_addr = t6_hma_ireg_array[i][0];
++ hma_fli->ireg_data = t6_hma_ireg_array[i][1];
++ hma_fli->ireg_local_offset = t6_hma_ireg_array[i][2];
++ hma_fli->ireg_offset_range = t6_hma_ireg_array[i][3];
++ t4_read_indirect(padap, hma_fli->ireg_addr, hma_fli->ireg_data,
++ buff, hma_fli->ireg_offset_range,
++ hma_fli->ireg_local_offset);
++ hma_indr++;
++ }
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
+ }
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -33,9 +33,27 @@ int cudbg_collect_edc1_meminfo(struct cu
+ int cudbg_collect_tp_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_sge_indirect(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_pcie_indirect(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_pm_indirect(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_ma_indirect(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_up_cim_indirect(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_mbox_log(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_hma_indirect(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,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -30,6 +30,12 @@ static const struct cxgb4_collect_entity
+ { CUDBG_DEV_LOG, cudbg_collect_fw_devlog },
+ { CUDBG_REG_DUMP, cudbg_collect_reg_dump },
+ { CUDBG_TP_INDIRECT, cudbg_collect_tp_indirect },
++ { CUDBG_SGE_INDIRECT, cudbg_collect_sge_indirect },
++ { CUDBG_PCIE_INDIRECT, cudbg_collect_pcie_indirect },
++ { CUDBG_PM_INDIRECT, cudbg_collect_pm_indirect },
++ { CUDBG_MA_INDIRECT, cudbg_collect_ma_indirect },
++ { CUDBG_UP_CIM_INDIRECT, cudbg_collect_up_cim_indirect },
++ { CUDBG_HMA_INDIRECT, cudbg_collect_hma_indirect },
+ };
+
+ static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
+@@ -87,9 +93,38 @@ static u32 cxgb4_get_entity_length(struc
+ n = n / (IREG_NUM_ELEM * sizeof(u32));
+ len = sizeof(struct ireg_buf) * n;
+ break;
++ case CUDBG_SGE_INDIRECT:
++ len = sizeof(struct ireg_buf) * 2;
++ break;
++ case CUDBG_PCIE_INDIRECT:
++ n = sizeof(t5_pcie_pdbg_array) / (IREG_NUM_ELEM * sizeof(u32));
++ len = sizeof(struct ireg_buf) * n * 2;
++ break;
++ case CUDBG_PM_INDIRECT:
++ n = sizeof(t5_pm_rx_array) / (IREG_NUM_ELEM * sizeof(u32));
++ len = sizeof(struct ireg_buf) * n * 2;
++ break;
++ case CUDBG_MA_INDIRECT:
++ if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) {
++ n = sizeof(t6_ma_ireg_array) /
++ (IREG_NUM_ELEM * sizeof(u32));
++ len = sizeof(struct ireg_buf) * n * 2;
++ }
++ break;
++ case CUDBG_UP_CIM_INDIRECT:
++ n = sizeof(t5_up_cim_reg_array) / (IREG_NUM_ELEM * sizeof(u32));
++ len = sizeof(struct ireg_buf) * n;
++ break;
+ case CUDBG_MBOX_LOG:
+ len = sizeof(struct cudbg_mbox_log) * adap->mbox_log->size;
+ break;
++ case CUDBG_HMA_INDIRECT:
++ if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) {
++ n = sizeof(t6_hma_ireg_array) /
++ (IREG_NUM_ELEM * sizeof(u32));
++ len = sizeof(struct ireg_buf) * n;
++ }
++ break;
+ default:
+ break;
+ }
diff --git a/patches.drivers/cxgb4-collect-hardware-scheduler-dumps.patch b/patches.drivers/cxgb4-collect-hardware-scheduler-dumps.patch
new file mode 100644
index 0000000000..c4b85b9d12
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-hardware-scheduler-dumps.patch
@@ -0,0 +1,253 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Thu, 26 Oct 2017 17:18:39 +0530
+Subject: cxgb4: collect hardware scheduler dumps
+Patch-mainline: v4.15-rc1
+Git-commit: 08c4901bfe0b3beb12e7a5d7749e3522d7b1471e
+References: bsc#1064802 bsc#1066129
+
+Collect hardware TX traffic scheduler and pace tables.
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 8 +++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 2
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 25 +++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 3 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 9 +++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 4 +
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 57 ++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 1
+ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 10 +++
+ 9 files changed, 119 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -49,6 +49,14 @@ struct cudbg_rss_vf_conf {
+ u32 rss_vf_vfh;
+ };
+
++struct cudbg_hw_sched {
++ u32 kbps[NTX_SCHED];
++ u32 ipg[NTX_SCHED];
++ u32 pace_tab[NTX_SCHED];
++ u32 mode;
++ u32 map;
++};
++
+ struct ireg_field {
+ u32 ireg_addr;
+ u32 ireg_data;
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -22,6 +22,7 @@
+ #define CUDBG_STATUS_NO_MEM -19
+ #define CUDBG_STATUS_ENTITY_NOT_FOUND -24
+ #define CUDBG_SYSTEM_ERROR -29
++#define CUDBG_STATUS_CCLK_NOT_DEFINED -32
+
+ #define CUDBG_MAJOR_VERSION 1
+ #define CUDBG_MINOR_VERSION 14
+@@ -48,6 +49,7 @@ enum cudbg_dbg_entity_type {
+ CUDBG_EDC1 = 19,
+ CUDBG_RSS = 22,
+ CUDBG_RSS_VF_CONF = 25,
++ CUDBG_HW_SCHED = 31,
+ CUDBG_TP_INDIRECT = 36,
+ CUDBG_SGE_INDIRECT = 37,
+ CUDBG_ULPRX_LA = 41,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -574,6 +574,31 @@ int cudbg_collect_rss_vf_config(struct c
+ return rc;
+ }
+
++int cudbg_collect_hw_sched(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_hw_sched *hw_sched_buff;
++ int i, rc = 0;
++
++ if (!padap->params.vpd.cclk)
++ return CUDBG_STATUS_CCLK_NOT_DEFINED;
++
++ rc = cudbg_get_buff(dbg_buff, sizeof(struct cudbg_hw_sched),
++ &temp_buff);
++ hw_sched_buff = (struct cudbg_hw_sched *)temp_buff.data;
++ hw_sched_buff->map = t4_read_reg(padap, TP_TX_MOD_QUEUE_REQ_MAP_A);
++ hw_sched_buff->mode = TIMERMODE_G(t4_read_reg(padap, TP_MOD_CONFIG_A));
++ t4_read_pace_tbl(padap, hw_sched_buff->pace_tab);
++ for (i = 0; i < NTX_SCHED; ++i)
++ t4_get_tx_sched(padap, i, &hw_sched_buff->kbps[i],
++ &hw_sched_buff->ipg[i], true);
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
++
+ int cudbg_collect_tp_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err)
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -84,6 +84,9 @@ int cudbg_collect_rss_vf_config(struct c
+ int cudbg_collect_tp_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_hw_sched(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
+ int cudbg_collect_sge_indirect(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -1335,6 +1335,12 @@ static inline unsigned int core_ticks_to
+ adapter->params.vpd.cclk);
+ }
+
++static inline unsigned int dack_ticks_to_usec(const struct adapter *adap,
++ unsigned int ticks)
++{
++ return (ticks << adap->params.tp.dack_re) / core_ticks_per_usec(adap);
++}
++
+ void t4_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask,
+ u32 val);
+
+@@ -1636,6 +1642,9 @@ void t4_get_trace_filter(struct adapter
+ int filter_index, int *enabled);
+ int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
+ u32 addr, u32 val);
++void t4_read_pace_tbl(struct adapter *adap, unsigned int pace_vals[NTX_SCHED]);
++void t4_get_tx_sched(struct adapter *adap, unsigned int sched,
++ unsigned int *kbps, unsigned int *ipg, bool sleep_ok);
+ int t4_sched_params(struct adapter *adapter, int type, int level, int mode,
+ int rateunit, int ratemode, int channel, int class,
+ int minrate, int maxrate, int weight, int pktsize);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -46,6 +46,7 @@ static const struct cxgb4_collect_entity
+ { CUDBG_CIM_OBQ_NCSI, cudbg_collect_cim_obq_ncsi },
+ { CUDBG_RSS, cudbg_collect_rss },
+ { CUDBG_RSS_VF_CONF, cudbg_collect_rss_vf_config },
++ { CUDBG_HW_SCHED, cudbg_collect_hw_sched },
+ { CUDBG_TP_INDIRECT, cudbg_collect_tp_indirect },
+ { CUDBG_SGE_INDIRECT, cudbg_collect_sge_indirect },
+ { CUDBG_ULPRX_LA, cudbg_collect_ulprx_la },
+@@ -156,6 +157,9 @@ static u32 cxgb4_get_entity_length(struc
+ len = adap->params.arch.vfcount *
+ sizeof(struct cudbg_rss_vf_conf);
+ break;
++ case CUDBG_HW_SCHED:
++ len = sizeof(struct cudbg_hw_sched);
++ break;
+ case CUDBG_TP_INDIRECT:
+ switch (CHELSIO_CHIP_VERSION(adap->params.chip)) {
+ case CHELSIO_T5:
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+@@ -9547,6 +9547,63 @@ int t4_set_vf_mac_acl(struct adapter *ad
+ return t4_wr_mbox(adapter, adapter->mbox, &cmd, sizeof(cmd), &cmd);
+ }
+
++/**
++ * t4_read_pace_tbl - read the pace table
++ * @adap: the adapter
++ * @pace_vals: holds the returned values
++ *
++ * Returns the values of TP's pace table in microseconds.
++ */
++void t4_read_pace_tbl(struct adapter *adap, unsigned int pace_vals[NTX_SCHED])
++{
++ unsigned int i, v;
++
++ for (i = 0; i < NTX_SCHED; i++) {
++ t4_write_reg(adap, TP_PACE_TABLE_A, 0xffff0000 + i);
++ v = t4_read_reg(adap, TP_PACE_TABLE_A);
++ pace_vals[i] = dack_ticks_to_usec(adap, v);
++ }
++}
++
++/**
++ * t4_get_tx_sched - get the configuration of a Tx HW traffic scheduler
++ * @adap: the adapter
++ * @sched: the scheduler index
++ * @kbps: the byte rate in Kbps
++ * @ipg: the interpacket delay in tenths of nanoseconds
++ * @sleep_ok: if true we may sleep while awaiting command completion
++ *
++ * Return the current configuration of a HW Tx scheduler.
++ */
++void t4_get_tx_sched(struct adapter *adap, unsigned int sched,
++ unsigned int *kbps, unsigned int *ipg, bool sleep_ok)
++{
++ unsigned int v, addr, bpt, cpt;
++
++ if (kbps) {
++ addr = TP_TX_MOD_Q1_Q0_RATE_LIMIT_A - sched / 2;
++ t4_tp_tm_pio_read(adap, &v, 1, addr, sleep_ok);
++ if (sched & 1)
++ v >>= 16;
++ bpt = (v >> 8) & 0xff;
++ cpt = v & 0xff;
++ if (!cpt) {
++ *kbps = 0; /* scheduler disabled */
++ } else {
++ v = (adap->params.vpd.cclk * 1000) / cpt; /* ticks/s */
++ *kbps = (v * bpt) / 125;
++ }
++ }
++ if (ipg) {
++ addr = TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR_A - sched / 2;
++ t4_tp_tm_pio_read(adap, &v, 1, addr, sleep_ok);
++ if (sched & 1)
++ v >>= 16;
++ v &= 0xffff;
++ *ipg = (10000 * v) / core_ticks_per_usec(adap);
++ }
++}
++
+ int t4_sched_params(struct adapter *adapter, int type, int level, int mode,
+ int rateunit, int ratemode, int channel, int class,
+ int minrate, int maxrate, int weight, int pktsize)
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
+@@ -47,6 +47,7 @@ enum {
+ TCB_SIZE = 128, /* TCB size */
+ NMTUS = 16, /* size of MTU table */
+ NCCTRL_WIN = 32, /* # of congestion control windows */
++ NTX_SCHED = 8, /* # of HW Tx scheduling queues */
+ PM_NSTATS = 5, /* # of PM stats */
+ T6_PM_NSTATS = 7, /* # of PM stats in T6 */
+ MBOX_LEN = 64, /* mailbox size in bytes */
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+@@ -1415,6 +1415,7 @@
+ #define ROWINDEX_V(x) ((x) << ROWINDEX_S)
+
+ #define TP_CCTRL_TABLE_A 0x7ddc
++#define TP_PACE_TABLE_A 0x7dd8
+ #define TP_MTU_TABLE_A 0x7de4
+
+ #define MTUINDEX_S 24
+@@ -1449,6 +1450,15 @@
+
+ #define TP_TM_PIO_ADDR_A 0x7e18
+ #define TP_TM_PIO_DATA_A 0x7e1c
++#define TP_MOD_CONFIG_A 0x7e24
++
++#define TIMERMODE_S 8
++#define TIMERMODE_M 0xffU
++#define TIMERMODE_G(x) (((x) >> TIMERMODE_S) & TIMERMODE_M)
++
++#define TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR_A 0x3
++#define TP_TX_MOD_Q1_Q0_RATE_LIMIT_A 0x8
++
+ #define TP_PIO_ADDR_A 0x7e40
+ #define TP_PIO_DATA_A 0x7e44
+ #define TP_MIB_INDEX_A 0x7e50
diff --git a/patches.drivers/cxgb4-collect-on-chip-memory-dump.patch b/patches.drivers/cxgb4-collect-on-chip-memory-dump.patch
new file mode 100644
index 0000000000..be0d25cce4
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-on-chip-memory-dump.patch
@@ -0,0 +1,359 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Fri, 13 Oct 2017 18:48:15 +0530
+Subject: cxgb4: collect on-chip memory dump
+Patch-mainline: v4.15-rc1
+Git-commit: b33af022e57996dc818ec960cbdf0f07cb5130d8
+References: bsc#1064802 bsc#1066129
+
+Collect EDC0 and EDC1 memory dump.
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 29 +++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 8 +
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 136 ++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 6
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h | 3
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 38 ++++-
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h | 1
+ 7 files changed, 220 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+
+--- /dev/null
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -0,0 +1,29 @@
++/*
++ * Copyright (C) 2017 Chelsio Communications. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * The full GNU General Public License is included in this distribution in
++ * the file called "COPYING".
++ *
++ */
++
++#ifndef __CUDBG_ENTITY_H__
++#define __CUDBG_ENTITY_H__
++
++#define EDC0_FLAG 3
++#define EDC1_FLAG 4
++
++struct card_mem {
++ u16 size_edc0;
++ u16 size_edc1;
++ u16 mem_flag;
++};
++#endif /* __CUDBG_ENTITY_H__ */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -20,6 +20,7 @@
+
+ /* Error codes */
+ #define CUDBG_STATUS_NO_MEM -19
++#define CUDBG_STATUS_ENTITY_NOT_FOUND -24
+ #define CUDBG_SYSTEM_ERROR -29
+
+ #define CUDBG_MAJOR_VERSION 1
+@@ -27,6 +28,8 @@
+
+ enum cudbg_dbg_entity_type {
+ CUDBG_REG_DUMP = 1,
++ CUDBG_EDC0 = 18,
++ CUDBG_EDC1 = 19,
+ CUDBG_MAX_ENTITY = 70,
+ };
+
+@@ -35,4 +38,9 @@ struct cudbg_init {
+ void *outbuf; /* Output buffer */
+ u32 outbuf_size; /* Output buffer size */
+ };
++
++static inline unsigned int cudbg_mbytes_to_bytes(unsigned int size)
++{
++ return size * 1024 * 1024;
++}
+ #endif /* __CUDBG_IF_H__ */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -15,10 +15,12 @@
+ *
+ */
+
++#include "t4_regs.h"
+ #include "cxgb4.h"
+ #include "cudbg_if.h"
+ #include "cudbg_lib_common.h"
+ #include "cudbg_lib.h"
++#include "cudbg_entity.h"
+
+ static void cudbg_write_and_release_buff(struct cudbg_buffer *pin_buff,
+ struct cudbg_buffer *dbg_buff)
+@@ -27,6 +29,16 @@ static void cudbg_write_and_release_buff
+ cudbg_put_buff(pin_buff, dbg_buff);
+ }
+
++static int is_fw_attached(struct cudbg_init *pdbg_init)
++{
++ struct adapter *padap = pdbg_init->adap;
++
++ if (!(padap->flags & FW_OK) || padap->use_bd)
++ return 0;
++
++ return 1;
++}
++
+ /* This function will add additional padding bytes into debug_buffer to make it
+ * 4 byte aligned.
+ */
+@@ -77,3 +89,127 @@ int cudbg_collect_reg_dump(struct cudbg_
+ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
+ return rc;
+ }
++
++static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff, u8 mem_type,
++ unsigned long tot_len,
++ struct cudbg_error *cudbg_err)
++{
++ unsigned long bytes, bytes_left, bytes_read = 0;
++ struct adapter *padap = pdbg_init->adap;
++ struct cudbg_buffer temp_buff = { 0 };
++ int rc = 0;
++
++ bytes_left = tot_len;
++ while (bytes_left > 0) {
++ bytes = min_t(unsigned long, bytes_left,
++ (unsigned long)CUDBG_CHUNK_SIZE);
++ rc = cudbg_get_buff(dbg_buff, bytes, &temp_buff);
++ if (rc)
++ return rc;
++ spin_lock(&padap->win0_lock);
++ rc = t4_memory_rw(padap, MEMWIN_NIC, mem_type,
++ bytes_read, bytes,
++ (__be32 *)temp_buff.data,
++ 1);
++ spin_unlock(&padap->win0_lock);
++ if (rc) {
++ cudbg_err->sys_err = rc;
++ cudbg_put_buff(&temp_buff, dbg_buff);
++ return rc;
++ }
++ bytes_left -= bytes;
++ bytes_read += bytes;
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ }
++ 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)
++{
++ struct adapter *padap = pdbg_init->adap;
++ int rc;
++
++ if (is_fw_attached(pdbg_init)) {
++ /* Flush uP dcache before reading edcX/mcX */
++ rc = t4_fwcache(padap, FW_PARAM_DEV_FWCACHE_FLUSH);
++ if (rc)
++ cudbg_err->sys_warn = rc;
++ }
++}
++
++static int cudbg_collect_mem_region(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err,
++ u8 mem_type)
++{
++ struct card_mem mem_info = {0};
++ unsigned long flag, size;
++ int 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;
++ }
++
++ 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;
++}
++
++int cudbg_collect_edc0_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_EDC0);
++}
++
++int cudbg_collect_edc1_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_EDC1);
++}
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -21,6 +21,12 @@
+ int cudbg_collect_reg_dump(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
++int cudbg_collect_edc0_meminfo(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++int cudbg_collect_edc1_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,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h
+@@ -69,6 +69,9 @@ struct cudbg_error {
+ int app_err;
+ };
+
++#define CDUMP_MAX_COMP_BUF_SIZE ((64 * 1024) - 1)
++#define CUDBG_CHUNK_SIZE ((CDUMP_MAX_COMP_BUF_SIZE / 1024) * 1024)
++
+ int cudbg_get_buff(struct cudbg_buffer *pdbg_buff, u32 size,
+ struct cudbg_buffer *pin_buff);
+ void cudbg_put_buff(struct cudbg_buffer *pin_buff,
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -15,16 +15,22 @@
+ *
+ */
+
++#include "t4_regs.h"
+ #include "cxgb4.h"
+ #include "cxgb4_cudbg.h"
+
++static const struct cxgb4_collect_entity cxgb4_collect_mem_dump[] = {
++ { CUDBG_EDC0, cudbg_collect_edc0_meminfo },
++ { CUDBG_EDC1, cudbg_collect_edc1_meminfo },
++};
++
+ static const struct cxgb4_collect_entity cxgb4_collect_hw_dump[] = {
+ { CUDBG_REG_DUMP, cudbg_collect_reg_dump },
+ };
+
+ static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
+ {
+- u32 len = 0;
++ u32 value, len = 0;
+
+ switch (entity) {
+ case CUDBG_REG_DUMP:
+@@ -40,6 +46,22 @@ static u32 cxgb4_get_entity_length(struc
+ break;
+ }
+ break;
++ case CUDBG_EDC0:
++ value = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A);
++ if (value & EDRAM0_ENABLE_F) {
++ value = t4_read_reg(adap, MA_EDRAM0_BAR_A);
++ len = EDRAM0_SIZE_G(value);
++ }
++ len = cudbg_mbytes_to_bytes(len);
++ break;
++ case CUDBG_EDC1:
++ value = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A);
++ if (value & EDRAM1_ENABLE_F) {
++ value = t4_read_reg(adap, MA_EDRAM1_BAR_A);
++ len = EDRAM1_SIZE_G(value);
++ }
++ len = cudbg_mbytes_to_bytes(len);
++ break;
+ default:
+ break;
+ }
+@@ -59,6 +81,13 @@ u32 cxgb4_get_dump_length(struct adapter
+ }
+ }
+
++ if (flag & CXGB4_ETH_DUMP_MEM) {
++ for (i = 0; i < ARRAY_SIZE(cxgb4_collect_mem_dump); i++) {
++ entity = cxgb4_collect_mem_dump[i].entity;
++ len += cxgb4_get_entity_length(adap, entity);
++ }
++ }
++
+ return len;
+ }
+
+@@ -152,6 +181,13 @@ int cxgb4_cudbg_collect(struct adapter *
+ buf,
+ &total_size);
+
++ if (flag & CXGB4_ETH_DUMP_MEM)
++ cxgb4_cudbg_collect_entity(&cudbg_init, &dbg_buff,
++ cxgb4_collect_mem_dump,
++ ARRAY_SIZE(cxgb4_collect_mem_dump),
++ buf,
++ &total_size);
++
+ cudbg_hdr->data_len = total_size;
+ *buf_size = total_size;
+ return 0;
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
+@@ -33,6 +33,7 @@ struct cxgb4_collect_entity {
+
+ enum CXGB4_ETHTOOL_DUMP_FLAGS {
+ CXGB4_ETH_DUMP_NONE = ETH_FW_DUMP_DISABLE,
++ CXGB4_ETH_DUMP_MEM = (1 << 0), /* On-Chip Memory Dumps */
+ CXGB4_ETH_DUMP_HW = (1 << 1), /* various FW and HW dumps */
+ };
+
diff --git a/patches.drivers/cxgb4-collect-register-dump.patch b/patches.drivers/cxgb4-collect-register-dump.patch
new file mode 100644
index 0000000000..ec34e1f3b2
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-register-dump.patch
@@ -0,0 +1,383 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Fri, 13 Oct 2017 18:48:14 +0530
+Subject: cxgb4: collect register dump
+Patch-mainline: v4.15-rc1
+Git-commit: a7975a2f9a7984de9b9b318da9d1826033db32c7
+References: bsc#1064802 bsc#1066129
+
+Add base to collect dump entities. Collect register dump and
+update template header accordingly.
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/Makefile | 3
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_common.c | 54 ++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 5
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 79 +++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 28 +++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h | 13 ++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 94 +++++++++++++++++-
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h | 11 ++
+ 8 files changed, 285 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cudbg_common.c
+ create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+ create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/Makefile
++++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile
+@@ -6,7 +6,8 @@ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o
+
+ cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o \
+ cxgb4_uld.o sched.o cxgb4_filter.o cxgb4_tc_u32.o \
+- cxgb4_ptp.o cxgb4_tc_flower.o cxgb4_cudbg.o
++ cxgb4_ptp.o cxgb4_tc_flower.o cxgb4_cudbg.o \
++ cudbg_common.o cudbg_lib.o
+ cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o
+ cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o
+ cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o
+--- /dev/null
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_common.c
+@@ -0,0 +1,54 @@
++/*
++ * Copyright (C) 2017 Chelsio Communications. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * The full GNU General Public License is included in this distribution in
++ * the file called "COPYING".
++ *
++ */
++
++#include "cxgb4.h"
++#include "cudbg_if.h"
++#include "cudbg_lib_common.h"
++
++int cudbg_get_buff(struct cudbg_buffer *pdbg_buff, u32 size,
++ struct cudbg_buffer *pin_buff)
++{
++ u32 offset;
++
++ offset = pdbg_buff->offset;
++ if (offset + size > pdbg_buff->size)
++ return CUDBG_STATUS_NO_MEM;
++
++ pin_buff->data = (char *)pdbg_buff->data + offset;
++ pin_buff->offset = offset;
++ pin_buff->size = size;
++ pdbg_buff->size -= size;
++ return 0;
++}
++
++void cudbg_put_buff(struct cudbg_buffer *pin_buff,
++ struct cudbg_buffer *pdbg_buff)
++{
++ pdbg_buff->size += pin_buff->size;
++ pin_buff->data = NULL;
++ pin_buff->offset = 0;
++ pin_buff->size = 0;
++}
++
++void cudbg_update_buff(struct cudbg_buffer *pin_buff,
++ struct cudbg_buffer *pout_buff)
++{
++ /* We already write to buffer provided by ethool, so just
++ * increment offset to next free space.
++ */
++ pout_buff->offset += pin_buff->size;
++}
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -18,10 +18,15 @@
+ #ifndef __CUDBG_IF_H__
+ #define __CUDBG_IF_H__
+
++/* Error codes */
++#define CUDBG_STATUS_NO_MEM -19
++#define CUDBG_SYSTEM_ERROR -29
++
+ #define CUDBG_MAJOR_VERSION 1
+ #define CUDBG_MINOR_VERSION 14
+
+ enum cudbg_dbg_entity_type {
++ CUDBG_REG_DUMP = 1,
+ CUDBG_MAX_ENTITY = 70,
+ };
+
+--- /dev/null
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -0,0 +1,79 @@
++/*
++ * Copyright (C) 2017 Chelsio Communications. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * The full GNU General Public License is included in this distribution in
++ * the file called "COPYING".
++ *
++ */
++
++#include "cxgb4.h"
++#include "cudbg_if.h"
++#include "cudbg_lib_common.h"
++#include "cudbg_lib.h"
++
++static void cudbg_write_and_release_buff(struct cudbg_buffer *pin_buff,
++ struct cudbg_buffer *dbg_buff)
++{
++ cudbg_update_buff(pin_buff, dbg_buff);
++ cudbg_put_buff(pin_buff, dbg_buff);
++}
++
++/* This function will add additional padding bytes into debug_buffer to make it
++ * 4 byte aligned.
++ */
++void cudbg_align_debug_buffer(struct cudbg_buffer *dbg_buff,
++ struct cudbg_entity_hdr *entity_hdr)
++{
++ u8 zero_buf[4] = {0};
++ u8 padding, remain;
++
++ remain = (dbg_buff->offset - entity_hdr->start_offset) % 4;
++ padding = 4 - remain;
++ if (remain) {
++ memcpy(((u8 *)dbg_buff->data) + dbg_buff->offset, &zero_buf,
++ padding);
++ dbg_buff->offset += padding;
++ entity_hdr->num_pad = padding;
++ }
++ entity_hdr->size = dbg_buff->offset - entity_hdr->start_offset;
++}
++
++struct cudbg_entity_hdr *cudbg_get_entity_hdr(void *outbuf, int i)
++{
++ struct cudbg_hdr *cudbg_hdr = (struct cudbg_hdr *)outbuf;
++
++ return (struct cudbg_entity_hdr *)
++ ((char *)outbuf + cudbg_hdr->hdr_len +
++ (sizeof(struct cudbg_entity_hdr) * (i - 1)));
++}
++
++int cudbg_collect_reg_dump(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 buf_size = 0;
++ int rc = 0;
++
++ if (is_t4(padap->params.chip))
++ buf_size = T4_REGMAP_SIZE;
++ else if (is_t5(padap->params.chip) || is_t6(padap->params.chip))
++ buf_size = T5_REGMAP_SIZE;
++
++ rc = cudbg_get_buff(dbg_buff, buf_size, &temp_buff);
++ if (rc)
++ return rc;
++ t4_get_regs(padap, (void *)temp_buff.data, temp_buff.size);
++ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
++ return rc;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -0,0 +1,28 @@
++/*
++ * Copyright (C) 2017 Chelsio Communications. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * The full GNU General Public License is included in this distribution in
++ * the file called "COPYING".
++ *
++ */
++
++#ifndef __CUDBG_LIB_H__
++#define __CUDBG_LIB_H__
++
++int cudbg_collect_reg_dump(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,
++ struct cudbg_entity_hdr *entity_hdr);
++#endif /* __CUDBG_LIB_H__ */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h
+@@ -62,4 +62,17 @@ struct cudbg_buffer {
+ u32 offset;
+ char *data;
+ };
++
++struct cudbg_error {
++ int sys_err;
++ int sys_warn;
++ int app_err;
++};
++
++int cudbg_get_buff(struct cudbg_buffer *pdbg_buff, u32 size,
++ struct cudbg_buffer *pin_buff);
++void cudbg_put_buff(struct cudbg_buffer *pin_buff,
++ struct cudbg_buffer *pdbg_buff);
++void cudbg_update_buff(struct cudbg_buffer *pin_buff,
++ struct cudbg_buffer *pout_buff);
+ #endif /* __CUDBG_LIB_COMMON_H__ */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -18,9 +18,94 @@
+ #include "cxgb4.h"
+ #include "cxgb4_cudbg.h"
+
++static const struct cxgb4_collect_entity cxgb4_collect_hw_dump[] = {
++ { CUDBG_REG_DUMP, cudbg_collect_reg_dump },
++};
++
++static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
++{
++ u32 len = 0;
++
++ switch (entity) {
++ case CUDBG_REG_DUMP:
++ switch (CHELSIO_CHIP_VERSION(adap->params.chip)) {
++ case CHELSIO_T4:
++ len = T4_REGMAP_SIZE;
++ break;
++ case CHELSIO_T5:
++ case CHELSIO_T6:
++ len = T5_REGMAP_SIZE;
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ break;
++ }
++
++ return len;
++}
++
+ u32 cxgb4_get_dump_length(struct adapter *adap, u32 flag)
+ {
+- return 0;
++ u32 i, entity;
++ u32 len = 0;
++
++ if (flag & CXGB4_ETH_DUMP_HW) {
++ for (i = 0; i < ARRAY_SIZE(cxgb4_collect_hw_dump); i++) {
++ entity = cxgb4_collect_hw_dump[i].entity;
++ len += cxgb4_get_entity_length(adap, entity);
++ }
++ }
++
++ return len;
++}
++
++static void cxgb4_cudbg_collect_entity(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ const struct cxgb4_collect_entity *e_arr,
++ u32 arr_size, void *buf, u32 *tot_size)
++{
++ struct adapter *adap = pdbg_init->adap;
++ struct cudbg_error cudbg_err = { 0 };
++ struct cudbg_entity_hdr *entity_hdr;
++ u32 entity_size, i;
++ u32 total_size = 0;
++ int ret;
++
++ for (i = 0; i < arr_size; i++) {
++ const struct cxgb4_collect_entity *e = &e_arr[i];
++
++ /* Skip entities that won't fit in output buffer */
++ entity_size = cxgb4_get_entity_length(adap, e->entity);
++ if (entity_size >
++ pdbg_init->outbuf_size - *tot_size - total_size)
++ continue;
++
++ entity_hdr = cudbg_get_entity_hdr(buf, e->entity);
++ entity_hdr->entity_type = e->entity;
++ entity_hdr->start_offset = dbg_buff->offset;
++ memset(&cudbg_err, 0, sizeof(struct cudbg_error));
++ ret = e->collect_cb(pdbg_init, dbg_buff, &cudbg_err);
++ if (ret) {
++ entity_hdr->size = 0;
++ dbg_buff->offset = entity_hdr->start_offset;
++ } else {
++ cudbg_align_debug_buffer(dbg_buff, entity_hdr);
++ }
++
++ /* Log error and continue with next entity */
++ if (cudbg_err.sys_err)
++ ret = CUDBG_SYSTEM_ERROR;
++
++ entity_hdr->hdr_flags = ret;
++ entity_hdr->sys_err = cudbg_err.sys_err;
++ entity_hdr->sys_warn = cudbg_err.sys_warn;
++ total_size += entity_hdr->size;
++ }
++
++ *tot_size += total_size;
+ }
+
+ int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
+@@ -60,6 +145,13 @@ int cxgb4_cudbg_collect(struct adapter *
+ dbg_buff.offset += min_size;
+ total_size = dbg_buff.offset;
+
++ if (flag & CXGB4_ETH_DUMP_HW)
++ cxgb4_cudbg_collect_entity(&cudbg_init, &dbg_buff,
++ cxgb4_collect_hw_dump,
++ ARRAY_SIZE(cxgb4_collect_hw_dump),
++ buf,
++ &total_size);
++
+ cudbg_hdr->data_len = total_size;
+ *buf_size = total_size;
+ return 0;
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
+@@ -20,9 +20,20 @@
+
+ #include "cudbg_if.h"
+ #include "cudbg_lib_common.h"
++#include "cudbg_lib.h"
++
++typedef int (*cudbg_collect_callback_t)(struct cudbg_init *pdbg_init,
++ struct cudbg_buffer *dbg_buff,
++ struct cudbg_error *cudbg_err);
++
++struct cxgb4_collect_entity {
++ enum cudbg_dbg_entity_type entity;
++ cudbg_collect_callback_t collect_cb;
++};
+
+ enum CXGB4_ETHTOOL_DUMP_FLAGS {
+ CXGB4_ETH_DUMP_NONE = ETH_FW_DUMP_DISABLE,
++ CXGB4_ETH_DUMP_HW = (1 << 1), /* various FW and HW dumps */
+ };
+
+ u32 cxgb4_get_dump_length(struct adapter *adap, u32 flag);
diff --git a/patches.drivers/cxgb4-collect-vpd-info-directly-from-hardware.patch b/patches.drivers/cxgb4-collect-vpd-info-directly-from-hardware.patch
new file mode 100644
index 0000000000..c5ec9cba42
--- /dev/null
+++ b/patches.drivers/cxgb4-collect-vpd-info-directly-from-hardware.patch
@@ -0,0 +1,241 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Fri, 10 Nov 2017 13:03:37 +0530
+Subject: cxgb4: collect vpd info directly from hardware
+Patch-mainline: v4.15-rc1
+Git-commit: 940c9c458866725e0ade96d5c1c7dbe5fcf1cf85
+References: bsc#1064802 bsc#1066129
+
+Collect vpd information directly from hardware instead of software
+adapter context. Move EEPROM physical address to virtual address
+translation logic to t4_hw.c and update relevant files.
+
+Fixes: 6f92a6544f1a ("cxgb4: collect hardware misc dumps")
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 6 +
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 77 ++++++++++++++++++---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c | 33 ---------
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 29 +++++++
+ 5 files changed, 104 insertions(+), 42 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+@@ -166,6 +166,12 @@ struct cudbg_mps_tcam {
+ u8 reserved[2];
+ };
+
++#define CUDBG_VPD_PF_SIZE 0x800
++#define CUDBG_SCFG_VER_ADDR 0x06
++#define CUDBG_SCFG_VER_LEN 4
++#define CUDBG_VPD_VER_ADDR 0x18c7
++#define CUDBG_VPD_VER_LEN 2
++
+ struct cudbg_vpd_data {
+ u8 sn[SERNUM_LEN + 1];
+ u8 bn[PN_LEN + 1];
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -68,6 +68,22 @@ struct cudbg_entity_hdr *cudbg_get_entit
+ (sizeof(struct cudbg_entity_hdr) * (i - 1)));
+ }
+
++static int cudbg_read_vpd_reg(struct adapter *padap, u32 addr, u32 len,
++ void *dest)
++{
++ int vaddr, rc;
++
++ vaddr = t4_eeprom_ptov(addr, padap->pf, EEPROMPFSIZE);
++ if (vaddr < 0)
++ return vaddr;
++
++ rc = pci_read_vpd(padap->pdev, vaddr, len, dest);
++ if (rc < 0)
++ return rc;
++
++ return 0;
++}
++
+ int cudbg_collect_reg_dump(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err)
+@@ -1289,8 +1305,47 @@ int cudbg_collect_vpd_data(struct cudbg_
+ {
+ struct adapter *padap = pdbg_init->adap;
+ struct cudbg_buffer temp_buff = { 0 };
++ char vpd_str[CUDBG_VPD_VER_LEN + 1];
++ u32 scfg_vers, vpd_vers, fw_vers;
+ struct cudbg_vpd_data *vpd_data;
+- int rc;
++ struct vpd_params vpd = { 0 };
++ int rc, ret;
++
++ rc = t4_get_raw_vpd_params(padap, &vpd);
++ if (rc)
++ return rc;
++
++ rc = t4_get_fw_version(padap, &fw_vers);
++ if (rc)
++ return rc;
++
++ /* Serial Configuration Version is located beyond the PF's vpd size.
++ * Temporarily give access to entire EEPROM to get it.
++ */
++ rc = pci_set_vpd_size(padap->pdev, EEPROMVSIZE);
++ if (rc < 0)
++ return rc;
++
++ ret = cudbg_read_vpd_reg(padap, CUDBG_SCFG_VER_ADDR, CUDBG_SCFG_VER_LEN,
++ &scfg_vers);
++
++ /* Restore back to original PF's vpd size */
++ rc = pci_set_vpd_size(padap->pdev, CUDBG_VPD_PF_SIZE);
++ if (rc < 0)
++ return rc;
++
++ if (ret)
++ return ret;
++
++ rc = cudbg_read_vpd_reg(padap, CUDBG_VPD_VER_ADDR, CUDBG_VPD_VER_LEN,
++ vpd_str);
++ if (rc)
++ return rc;
++
++ vpd_str[CUDBG_VPD_VER_LEN] = '\0';
++ rc = kstrtouint(vpd_str, 0, &vpd_vers);
++ if (rc)
++ return rc;
+
+ rc = cudbg_get_buff(dbg_buff, sizeof(struct cudbg_vpd_data),
+ &temp_buff);
+@@ -1298,16 +1353,16 @@ int cudbg_collect_vpd_data(struct cudbg_
+ return rc;
+
+ vpd_data = (struct cudbg_vpd_data *)temp_buff.data;
+- memcpy(vpd_data->sn, padap->params.vpd.sn, SERNUM_LEN + 1);
+- memcpy(vpd_data->bn, padap->params.vpd.pn, PN_LEN + 1);
+- memcpy(vpd_data->na, padap->params.vpd.na, MACADDR_LEN + 1);
+- memcpy(vpd_data->mn, padap->params.vpd.id, ID_LEN + 1);
+- vpd_data->scfg_vers = padap->params.scfg_vers;
+- vpd_data->vpd_vers = padap->params.vpd_vers;
+- vpd_data->fw_major = FW_HDR_FW_VER_MAJOR_G(padap->params.fw_vers);
+- vpd_data->fw_minor = FW_HDR_FW_VER_MINOR_G(padap->params.fw_vers);
+- vpd_data->fw_micro = FW_HDR_FW_VER_MICRO_G(padap->params.fw_vers);
+- vpd_data->fw_build = FW_HDR_FW_VER_BUILD_G(padap->params.fw_vers);
++ memcpy(vpd_data->sn, vpd.sn, SERNUM_LEN + 1);
++ memcpy(vpd_data->bn, vpd.pn, PN_LEN + 1);
++ memcpy(vpd_data->na, vpd.na, MACADDR_LEN + 1);
++ memcpy(vpd_data->mn, vpd.id, ID_LEN + 1);
++ vpd_data->scfg_vers = scfg_vers;
++ vpd_data->vpd_vers = vpd_vers;
++ vpd_data->fw_major = FW_HDR_FW_VER_MAJOR_G(fw_vers);
++ vpd_data->fw_minor = FW_HDR_FW_VER_MINOR_G(fw_vers);
++ vpd_data->fw_micro = FW_HDR_FW_VER_MICRO_G(fw_vers);
++ vpd_data->fw_build = FW_HDR_FW_VER_BUILD_G(fw_vers);
+ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
+ return rc;
+ }
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -1457,6 +1457,7 @@ static inline int t4_memory_write(struct
+ unsigned int t4_get_regs_len(struct adapter *adapter);
+ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size);
+
++int t4_eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz);
+ int t4_seeprom_wp(struct adapter *adapter, bool enable);
+ int t4_get_raw_vpd_params(struct adapter *adapter, struct vpd_params *p);
+ int t4_get_vpd_params(struct adapter *adapter, struct vpd_params *p);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
+@@ -1064,40 +1064,11 @@ static int get_coalesce(struct net_devic
+ return 0;
+ }
+
+-/**
+- * eeprom_ptov - translate a physical EEPROM address to virtual
+- * @phys_addr: the physical EEPROM address
+- * @fn: the PCI function number
+- * @sz: size of function-specific area
+- *
+- * Translate a physical EEPROM address to virtual. The first 1K is
+- * accessed through virtual addresses starting at 31K, the rest is
+- * accessed through virtual addresses starting at 0.
+- *
+- * The mapping is as follows:
+- * [0..1K) -> [31K..32K)
+- * [1K..1K+A) -> [31K-A..31K)
+- * [1K+A..ES) -> [0..ES-A-1K)
+- *
+- * where A = @fn * @sz, and ES = EEPROM size.
+- */
+-static int eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz)
+-{
+- fn *= sz;
+- if (phys_addr < 1024)
+- return phys_addr + (31 << 10);
+- if (phys_addr < 1024 + fn)
+- return 31744 - fn + phys_addr - 1024;
+- if (phys_addr < EEPROMSIZE)
+- return phys_addr - 1024 - fn;
+- return -EINVAL;
+-}
+-
+ /* The next two routines implement eeprom read/write from physical addresses.
+ */
+ static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v)
+ {
+- int vaddr = eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE);
++ int vaddr = t4_eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE);
+
+ if (vaddr >= 0)
+ vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v);
+@@ -1106,7 +1077,7 @@ static int eeprom_rd_phys(struct adapter
+
+ static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v)
+ {
+- int vaddr = eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE);
++ int vaddr = t4_eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE);
+
+ if (vaddr >= 0)
+ vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v);
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+@@ -2639,6 +2639,35 @@ void t4_get_regs(struct adapter *adap, v
+ #define CHELSIO_VPD_UNIQUE_ID 0x82
+
+ /**
++ * t4_eeprom_ptov - translate a physical EEPROM address to virtual
++ * @phys_addr: the physical EEPROM address
++ * @fn: the PCI function number
++ * @sz: size of function-specific area
++ *
++ * Translate a physical EEPROM address to virtual. The first 1K is
++ * accessed through virtual addresses starting at 31K, the rest is
++ * accessed through virtual addresses starting at 0.
++ *
++ * The mapping is as follows:
++ * [0..1K) -> [31K..32K)
++ * [1K..1K+A) -> [31K-A..31K)
++ * [1K+A..ES) -> [0..ES-A-1K)
++ *
++ * where A = @fn * @sz, and ES = EEPROM size.
++ */
++int t4_eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz)
++{
++ fn *= sz;
++ if (phys_addr < 1024)
++ return phys_addr + (31 << 10);
++ if (phys_addr < 1024 + fn)
++ return 31744 - fn + phys_addr - 1024;
++ if (phys_addr < EEPROMSIZE)
++ return phys_addr - 1024 - fn;
++ return -EINVAL;
++}
++
++/**
+ * t4_seeprom_wp - enable/disable EEPROM write protection
+ * @adapter: the adapter
+ * @enable: whether to enable or disable write protection
diff --git a/patches.drivers/cxgb4-do-DCB-state-reset-in-couple-of-places.patch b/patches.drivers/cxgb4-do-DCB-state-reset-in-couple-of-places.patch
new file mode 100644
index 0000000000..2af660e4bf
--- /dev/null
+++ b/patches.drivers/cxgb4-do-DCB-state-reset-in-couple-of-places.patch
@@ -0,0 +1,97 @@
+From: Ganesh Goudar <ganeshgr@chelsio.com>
+Date: Sat, 23 Sep 2017 16:07:28 +0530
+Subject: cxgb4: do DCB state reset in couple of places
+Patch-mainline: v4.15-rc1
+Git-commit: ba581f77df23c8ee70b372966e69cf10bc5453d8
+References: bsc#1064802 bsc#1066129
+
+reset the driver's DCB state in couple of places
+where it was missing.
+
+Signed-off-by: Casey Leedom <leedom@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c | 15 +++++++++++----
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h | 1 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 10 ++++++++--
+ 3 files changed, 20 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c
+@@ -40,8 +40,7 @@ static inline bool cxgb4_dcb_state_synce
+ return false;
+ }
+
+-/* Initialize a port's Data Center Bridging state. Typically used after a
+- * Link Down event.
++/* Initialize a port's Data Center Bridging state.
+ */
+ void cxgb4_dcb_state_init(struct net_device *dev)
+ {
+@@ -106,6 +105,15 @@ static void cxgb4_dcb_cleanup_apps(struc
+ }
+ }
+
++/* Reset a port's Data Center Bridging state. Typically used after a
++ * Link Down event.
++ */
++void cxgb4_dcb_reset(struct net_device *dev)
++{
++ cxgb4_dcb_cleanup_apps(dev);
++ cxgb4_dcb_state_init(dev);
++}
++
+ /* Finite State machine for Data Center Bridging.
+ */
+ void cxgb4_dcb_state_fsm(struct net_device *dev,
+@@ -194,8 +202,7 @@ void cxgb4_dcb_state_fsm(struct net_devi
+ * state. We need to reset back to a ground state
+ * of incomplete.
+ */
+- cxgb4_dcb_cleanup_apps(dev);
+- cxgb4_dcb_state_init(dev);
++ cxgb4_dcb_reset(dev);
+ dcb->state = CXGB4_DCB_STATE_FW_INCOMPLETE;
+ dcb->supported = CXGB4_DCBX_FW_SUPPORT;
+ linkwatch_fire_event(dev);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h
+@@ -131,6 +131,7 @@ struct port_dcb_info {
+
+ void cxgb4_dcb_state_init(struct net_device *);
+ void cxgb4_dcb_version_init(struct net_device *);
++void cxgb4_dcb_reset(struct net_device *dev);
+ void cxgb4_dcb_state_fsm(struct net_device *, enum cxgb4_dcb_state_input);
+ void cxgb4_dcb_handle_fw_update(struct adapter *, const struct fw_port_cmd *);
+ void cxgb4_dcb_set_caps(struct adapter *, const struct fw_port_cmd *);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -281,7 +281,7 @@ void t4_os_link_changed(struct adapter *
+ else {
+ #ifdef CONFIG_CHELSIO_T4_DCB
+ if (cxgb4_dcb_enabled(dev)) {
+- cxgb4_dcb_state_init(dev);
++ cxgb4_dcb_reset(dev);
+ dcb_tx_queue_prio_enable(dev, false);
+ }
+ #endif /* CONFIG_CHELSIO_T4_DCB */
+@@ -2304,10 +2304,16 @@ static int cxgb_close(struct net_device
+ {
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
++ int ret;
+
+ netif_tx_stop_all_queues(dev);
+ netif_carrier_off(dev);
+- return t4_enable_vi(adapter, adapter->pf, pi->viid, false, false);
++ ret = t4_enable_vi(adapter, adapter->pf, pi->viid, false, false);
++#ifdef CONFIG_CHELSIO_T4_DCB
++ cxgb4_dcb_reset(dev);
++ dcb_tx_queue_prio_enable(dev, false);
++#endif
++ return ret;
+ }
+
+ int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid,
diff --git a/patches.drivers/cxgb4-fetch-stats-for-offloaded-tc-flower-flows.patch b/patches.drivers/cxgb4-fetch-stats-for-offloaded-tc-flower-flows.patch
new file mode 100644
index 0000000000..3224aae584
--- /dev/null
+++ b/patches.drivers/cxgb4-fetch-stats-for-offloaded-tc-flower-flows.patch
@@ -0,0 +1,268 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Thu, 21 Sep 2017 23:41:16 +0530
+Subject: cxgb4: fetch stats for offloaded tc flower flows
+Patch-mainline: v4.15-rc1
+Git-commit: e0f911c81e93fc23fe1a4fb0318ff1c3b1c9027f
+References: bsc#1064802 bsc#1066129
+
+Add support to retrieve stats from hardware for offloaded tc flower
+flows. Also, poll for the stats of offloaded flows via timer callback.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 76 ++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 1
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 79 ++++++++++++++++++-
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h | 3
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 2
+ 6 files changed, 161 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -908,6 +908,7 @@ struct adapter {
+
+ /* TC flower offload */
+ DECLARE_HASHTABLE(flower_anymatch_tbl, 9);
++ struct timer_list flower_stats_timer;
+ };
+
+ /* Support for "sched-class" command to allow a TX Scheduling Class to be
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+@@ -148,6 +148,82 @@ static int get_filter_steerq(struct net_
+ return iq;
+ }
+
++static int get_filter_count(struct adapter *adapter, unsigned int fidx,
++ u64 *pkts, u64 *bytes)
++{
++ unsigned int tcb_base, tcbaddr;
++ unsigned int word_offset;
++ struct filter_entry *f;
++ __be64 be64_byte_count;
++ int ret;
++
++ tcb_base = t4_read_reg(adapter, TP_CMM_TCB_BASE_A);
++ if ((fidx != (adapter->tids.nftids + adapter->tids.nsftids - 1)) &&
++ fidx >= adapter->tids.nftids)
++ return -E2BIG;
++
++ f = &adapter->tids.ftid_tab[fidx];
++ if (!f->valid)
++ return -EINVAL;
++
++ tcbaddr = tcb_base + f->tid * TCB_SIZE;
++
++ spin_lock(&adapter->win0_lock);
++ if (is_t4(adapter->params.chip)) {
++ __be64 be64_count;
++
++ /* T4 doesn't maintain byte counts in hw */
++ *bytes = 0;
++
++ /* Get pkts */
++ word_offset = 4;
++ ret = t4_memory_rw(adapter, MEMWIN_NIC, MEM_EDC0,
++ tcbaddr + (word_offset * sizeof(__be32)),
++ sizeof(be64_count),
++ (__be32 *)&be64_count,
++ T4_MEMORY_READ);
++ if (ret < 0)
++ goto out;
++ *pkts = be64_to_cpu(be64_count);
++ } else {
++ __be32 be32_count;
++
++ /* Get bytes */
++ word_offset = 4;
++ ret = t4_memory_rw(adapter, MEMWIN_NIC, MEM_EDC0,
++ tcbaddr + (word_offset * sizeof(__be32)),
++ sizeof(be64_byte_count),
++ &be64_byte_count,
++ T4_MEMORY_READ);
++ if (ret < 0)
++ goto out;
++ *bytes = be64_to_cpu(be64_byte_count);
++
++ /* Get pkts */
++ word_offset = 6;
++ ret = t4_memory_rw(adapter, MEMWIN_NIC, MEM_EDC0,
++ tcbaddr + (word_offset * sizeof(__be32)),
++ sizeof(be32_count),
++ &be32_count,
++ T4_MEMORY_READ);
++ if (ret < 0)
++ goto out;
++ *pkts = (u64)be32_to_cpu(be32_count);
++ }
++
++out:
++ spin_unlock(&adapter->win0_lock);
++ return ret;
++}
++
++int cxgb4_get_filter_counters(struct net_device *dev, unsigned int fidx,
++ u64 *hitcnt, u64 *bytecnt)
++{
++ struct adapter *adapter = netdev2adap(dev);
++
++ return get_filter_count(adapter, fidx, hitcnt, bytecnt);
++}
++
+ int cxgb4_get_free_ftid(struct net_device *dev, int family)
+ {
+ struct adapter *adap = netdev2adap(dev);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -4637,6 +4637,7 @@ static void free_some_resources(struct a
+ kvfree(adapter->l2t);
+ t4_cleanup_sched(adapter);
+ kvfree(adapter->tids.tid_tab);
++ cxgb4_cleanup_tc_flower(adapter);
+ cxgb4_cleanup_tc_u32(adapter);
+ kfree(adapter->sge.egr_map);
+ kfree(adapter->sge.ingr_map);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+@@ -39,9 +39,12 @@
+ #include "cxgb4.h"
+ #include "cxgb4_tc_flower.h"
+
++#define STATS_CHECK_PERIOD (HZ / 2)
++
+ static struct ch_tc_flower_entry *allocate_flower_entry(void)
+ {
+ struct ch_tc_flower_entry *new = kzalloc(sizeof(*new), GFP_KERNEL);
++ spin_lock_init(&new->lock);
+ return new;
+ }
+
+@@ -363,13 +366,87 @@ err:
+ return ret;
+ }
+
++void ch_flower_stats_cb(unsigned long data)
++{
++ struct adapter *adap = (struct adapter *)data;
++ struct ch_tc_flower_entry *flower_entry;
++ struct ch_tc_flower_stats *ofld_stats;
++ unsigned int i;
++ u64 packets;
++ u64 bytes;
++ int ret;
++
++ rcu_read_lock();
++ hash_for_each_rcu(adap->flower_anymatch_tbl, i, flower_entry, link) {
++ ret = cxgb4_get_filter_counters(adap->port[0],
++ flower_entry->filter_id,
++ &packets, &bytes);
++ if (!ret) {
++ spin_lock(&flower_entry->lock);
++ ofld_stats = &flower_entry->stats;
++
++ if (ofld_stats->prev_packet_count != packets) {
++ ofld_stats->prev_packet_count = packets;
++ ofld_stats->last_used = jiffies;
++ }
++ spin_unlock(&flower_entry->lock);
++ }
++ }
++ rcu_read_unlock();
++ mod_timer(&adap->flower_stats_timer, jiffies + STATS_CHECK_PERIOD);
++}
++
+ int cxgb4_tc_flower_stats(struct net_device *dev,
+ struct tc_cls_flower_offload *cls)
+ {
+- return -EOPNOTSUPP;
++ struct adapter *adap = netdev2adap(dev);
++ struct ch_tc_flower_stats *ofld_stats;
++ struct ch_tc_flower_entry *ch_flower;
++ u64 packets;
++ u64 bytes;
++ int ret;
++
++ ch_flower = ch_flower_lookup(adap, cls->cookie);
++ if (!ch_flower) {
++ ret = -ENOENT;
++ goto err;
++ }
++
++ ret = cxgb4_get_filter_counters(dev, ch_flower->filter_id,
++ &packets, &bytes);
++ if (ret < 0)
++ goto err;
++
++ spin_lock_bh(&ch_flower->lock);
++ ofld_stats = &ch_flower->stats;
++ if (ofld_stats->packet_count != packets) {
++ if (ofld_stats->prev_packet_count != packets)
++ ofld_stats->last_used = jiffies;
++ tcf_exts_stats_update(cls->exts, bytes - ofld_stats->byte_count,
++ packets - ofld_stats->packet_count,
++ ofld_stats->last_used);
++
++ ofld_stats->packet_count = packets;
++ ofld_stats->byte_count = bytes;
++ ofld_stats->prev_packet_count = packets;
++ }
++ spin_unlock_bh(&ch_flower->lock);
++ return 0;
++
++err:
++ return ret;
+ }
+
+ void cxgb4_init_tc_flower(struct adapter *adap)
+ {
+ hash_init(adap->flower_anymatch_tbl);
++ setup_timer(&adap->flower_stats_timer, ch_flower_stats_cb,
++ (unsigned long)adap);
++ mod_timer(&adap->flower_stats_timer, jiffies + STATS_CHECK_PERIOD);
++}
++
++void cxgb4_cleanup_tc_flower(struct adapter *adap)
++{
++ if (adap->flower_stats_timer.function)
++ del_timer_sync(&adap->flower_stats_timer);
+ }
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
+@@ -38,6 +38,7 @@
+ #include <net/pkt_cls.h>
+
+ struct ch_tc_flower_stats {
++ u64 prev_packet_count;
+ u64 packet_count;
+ u64 byte_count;
+ u64 last_used;
+@@ -49,6 +50,7 @@ struct ch_tc_flower_entry {
+ unsigned long tc_flower_cookie;
+ struct hlist_node link;
+ struct rcu_head rcu;
++ spinlock_t lock; /* lock for stats */
+ u32 filter_id;
+ };
+
+@@ -60,4 +62,5 @@ int cxgb4_tc_flower_stats(struct net_dev
+ struct tc_cls_flower_offload *cls);
+
+ void cxgb4_init_tc_flower(struct adapter *adap);
++void cxgb4_cleanup_tc_flower(struct adapter *adap);
+ #endif /* __CXGB4_TC_FLOWER_H */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+@@ -221,6 +221,8 @@ int __cxgb4_del_filter(struct net_device
+ int cxgb4_set_filter(struct net_device *dev, int filter_id,
+ struct ch_filter_specification *fs);
+ int cxgb4_del_filter(struct net_device *dev, int filter_id);
++int cxgb4_get_filter_counters(struct net_device *dev, unsigned int fidx,
++ u64 *hitcnt, u64 *bytecnt);
+
+ static inline void set_wr_txq(struct sk_buff *skb, int prio, int queue)
+ {
diff --git a/patches.drivers/cxgb4-fix-error-return-code-in-cxgb4_set_hash_filter.patch b/patches.drivers/cxgb4-fix-error-return-code-in-cxgb4_set_hash_filter.patch
new file mode 100644
index 0000000000..a689e802ec
--- /dev/null
+++ b/patches.drivers/cxgb4-fix-error-return-code-in-cxgb4_set_hash_filter.patch
@@ -0,0 +1,33 @@
+From: Wei Yongjun <weiyongjun1@huawei.com>
+Date: Thu, 2 Nov 2017 11:15:07 +0000
+Subject: cxgb4: fix error return code in cxgb4_set_hash_filter()
+Patch-mainline: v4.15-rc1
+Git-commit: a882d20cdb7775ff8b4aac880255eff6a2c1c85e
+References: bsc#1064802 bsc#1066129
+
+Fix to return a negative error code from thecxgb4_alloc_atid()
+error handling case instead of 0.
+
+Fixes: 12b276fbf6e0 ("cxgb4: add support to create hash filters")
+Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
+Acked-By: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+@@ -1110,8 +1110,10 @@ static int cxgb4_set_hash_filter(struct
+ }
+
+ atid = cxgb4_alloc_atid(t, f);
+- if (atid < 0)
++ if (atid < 0) {
++ ret = atid;
+ goto free_smt;
++ }
+
+ iconf = adapter->params.tp.ingress_config;
+ if (iconf & VNIC_F) {
diff --git a/patches.drivers/cxgb4-fix-missing-break-in-switch-and-indent-return-.patch b/patches.drivers/cxgb4-fix-missing-break-in-switch-and-indent-return-.patch
new file mode 100644
index 0000000000..f74d7fa7ce
--- /dev/null
+++ b/patches.drivers/cxgb4-fix-missing-break-in-switch-and-indent-return-.patch
@@ -0,0 +1,53 @@
+From: Colin Ian King <colin.king@canonical.com>
+Date: Fri, 13 Oct 2017 17:29:00 +0100
+Subject: cxgb4: fix missing break in switch and indent return statements
+Patch-mainline: v4.15-rc1
+Git-commit: 5dc874252faa818426480a7c00fa05738fe05402
+References: bsc#1064802 bsc#1066129
+
+The break statement for the Macronix case is missing and will
+fall through to the Winbond case and re-assign the size setting.
+Fix this by adding the missing break statement. Also correctly
+indent the return statements.
+
+Detected by CoverityScan, CID#1458020 ("Missing break in switch")
+
+Fixes: 96ac18f14a5a ("cxgb4: Add support for new flash parts")
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+@@ -8404,7 +8404,7 @@ static int t4_get_flash_params(struct ad
+ default:
+ dev_err(adap->pdev_dev, "Micron Flash Part has bad size, ID = %#x, Density code = %#x\n",
+ flashid, density);
+- return -EINVAL;
++ return -EINVAL;
+ }
+ break;
+ }
+@@ -8423,8 +8423,9 @@ static int t4_get_flash_params(struct ad
+ default:
+ dev_err(adap->pdev_dev, "Macronix Flash Part has bad size, ID = %#x, Density code = %#x\n",
+ flashid, density);
+- return -EINVAL;
++ return -EINVAL;
+ }
++ break;
+ }
+ case 0xef: { /* Winbond */
+ /* This Density -> Size decoding table is taken from Winbond
+@@ -8441,7 +8442,7 @@ static int t4_get_flash_params(struct ad
+ default:
+ dev_err(adap->pdev_dev, "Winbond Flash Part has bad size, ID = %#x, Density code = %#x\n",
+ flashid, density);
+- return -EINVAL;
++ return -EINVAL;
+ }
+ break;
+ }
diff --git a/patches.drivers/cxgb4-fix-overflow-in-collecting-IBQ-and-OBQ-dump.patch b/patches.drivers/cxgb4-fix-overflow-in-collecting-IBQ-and-OBQ-dump.patch
new file mode 100644
index 0000000000..37fa9cf2c2
--- /dev/null
+++ b/patches.drivers/cxgb4-fix-overflow-in-collecting-IBQ-and-OBQ-dump.patch
@@ -0,0 +1,120 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Tue, 24 Oct 2017 19:28:26 +0530
+Subject: cxgb4: fix overflow in collecting IBQ and OBQ dump
+Patch-mainline: v4.15-rc1
+Git-commit: acfdf7eabea4186a386ba5e656f0c739563cb1a5
+References: bsc#1064802 bsc#1066129
+
+Destination buffer already has offset added. So, don't add offset
+again.
+
+Fetch actual size of configured OBQ from hardware, instead of using
+hardcoded value.
+
+Fixes: 7c075ce221cf ("cxgb4: collect IBQ and OBQ dumps")
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 20 ++++++++++++++------
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h | 1 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 16 +++++++++++++++-
+ 3 files changed, 30 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -146,8 +146,7 @@ static int cudbg_read_cim_ibq(struct cud
+
+ /* t4_read_cim_ibq will return no. of read words or error */
+ no_of_read_words = t4_read_cim_ibq(padap, qid,
+- (u32 *)((u32 *)temp_buff.data +
+- temp_buff.offset), qsize);
++ (u32 *)temp_buff.data, qsize);
+ /* no_of_read_words is less than or equal to 0 means error */
+ if (no_of_read_words <= 0) {
+ if (!no_of_read_words)
+@@ -204,6 +203,17 @@ int cudbg_collect_cim_ibq_ncsi(struct cu
+ return cudbg_read_cim_ibq(pdbg_init, dbg_buff, cudbg_err, 5);
+ }
+
++u32 cudbg_cim_obq_size(struct adapter *padap, int qid)
++{
++ u32 value;
++
++ t4_write_reg(padap, CIM_QUEUE_CONFIG_REF_A, OBQSELECT_F |
++ QUENUMSELECT_V(qid));
++ value = t4_read_reg(padap, CIM_QUEUE_CONFIG_CTRL_A);
++ value = CIMQSIZE_G(value) * 64; /* size in number of words */
++ return value * sizeof(u32);
++}
++
+ static int cudbg_read_cim_obq(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err, int qid)
+@@ -214,15 +224,14 @@ static int cudbg_read_cim_obq(struct cud
+ u32 qsize;
+
+ /* collect CIM OBQ */
+- qsize = 6 * CIM_OBQ_SIZE * 4 * sizeof(u32);
++ qsize = cudbg_cim_obq_size(padap, qid);
+ rc = cudbg_get_buff(dbg_buff, qsize, &temp_buff);
+ if (rc)
+ return rc;
+
+ /* t4_read_cim_obq will return no. of read words or error */
+ no_of_read_words = t4_read_cim_obq(padap, qid,
+- (u32 *)((u32 *)temp_buff.data +
+- temp_buff.offset), qsize);
++ (u32 *)temp_buff.data, qsize);
+ /* no_of_read_words is less than or equal to 0 means error */
+ if (no_of_read_words <= 0) {
+ if (!no_of_read_words)
+@@ -233,7 +242,6 @@ static int cudbg_read_cim_obq(struct cud
+ cudbg_put_buff(&temp_buff, dbg_buff);
+ return rc;
+ }
+- temp_buff.size = no_of_read_words * 4;
+ cudbg_write_and_release_buff(&temp_buff, dbg_buff);
+ return rc;
+ }
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+@@ -100,4 +100,5 @@ int cudbg_collect_hma_indirect(struct cu
+ struct cudbg_entity_hdr *cudbg_get_entity_hdr(void *outbuf, int i);
+ void cudbg_align_debug_buffer(struct cudbg_buffer *dbg_buff,
+ struct cudbg_entity_hdr *entity_hdr);
++u32 cudbg_cim_obq_size(struct adapter *padap, int qid);
+ #endif /* __CUDBG_LIB_H__ */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -82,14 +82,28 @@ static u32 cxgb4_get_entity_length(struc
+ len = CIM_IBQ_SIZE * 4 * sizeof(u32);
+ break;
+ case CUDBG_CIM_OBQ_ULP0:
++ len = cudbg_cim_obq_size(adap, 0);
++ break;
+ case CUDBG_CIM_OBQ_ULP1:
++ len = cudbg_cim_obq_size(adap, 1);
++ break;
+ case CUDBG_CIM_OBQ_ULP2:
++ len = cudbg_cim_obq_size(adap, 2);
++ break;
+ case CUDBG_CIM_OBQ_ULP3:
++ len = cudbg_cim_obq_size(adap, 3);
++ break;
+ case CUDBG_CIM_OBQ_SGE:
++ len = cudbg_cim_obq_size(adap, 4);
++ break;
+ case CUDBG_CIM_OBQ_NCSI:
++ len = cudbg_cim_obq_size(adap, 5);
++ break;
+ case CUDBG_CIM_OBQ_RXQ0:
++ len = cudbg_cim_obq_size(adap, 6);
++ break;
+ case CUDBG_CIM_OBQ_RXQ1:
+- len = 6 * CIM_OBQ_SIZE * 4 * sizeof(u32);
++ len = cudbg_cim_obq_size(adap, 7);
+ break;
+ case CUDBG_EDC0:
+ value = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A);
diff --git a/patches.drivers/cxgb4-implement-ethtool-dump-data-operations.patch b/patches.drivers/cxgb4-implement-ethtool-dump-data-operations.patch
new file mode 100644
index 0000000000..5ac03b89cd
--- /dev/null
+++ b/patches.drivers/cxgb4-implement-ethtool-dump-data-operations.patch
@@ -0,0 +1,366 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Fri, 13 Oct 2017 18:48:13 +0530
+Subject: cxgb4: implement ethtool dump data operations
+Patch-mainline: v4.15-rc1
+Git-commit: ad75b7d32f2517a6cc92a5d70569c33455157453
+References: bsc#1064802 bsc#1066129
+
+Implement operations to set/get dump data via ethtool. Also add
+template header that precedes dump data, which helps in decoding
+and extracting the dump data.
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/Makefile | 2
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 33 ++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h | 65 ++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 3
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 73 ++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h | 32 +++++++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c | 56 +++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 3
+ 8 files changed, 265 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+ create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h
+ create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+ create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/Makefile
++++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile
+@@ -6,7 +6,7 @@ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o
+
+ cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o \
+ cxgb4_uld.o sched.o cxgb4_filter.o cxgb4_tc_u32.o \
+- cxgb4_ptp.o cxgb4_tc_flower.o
++ cxgb4_ptp.o cxgb4_tc_flower.o cxgb4_cudbg.o
+ cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o
+ cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o
+ cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o
+--- /dev/null
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+@@ -0,0 +1,33 @@
++/*
++ * Copyright (C) 2017 Chelsio Communications. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * The full GNU General Public License is included in this distribution in
++ * the file called "COPYING".
++ *
++ */
++
++#ifndef __CUDBG_IF_H__
++#define __CUDBG_IF_H__
++
++#define CUDBG_MAJOR_VERSION 1
++#define CUDBG_MINOR_VERSION 14
++
++enum cudbg_dbg_entity_type {
++ CUDBG_MAX_ENTITY = 70,
++};
++
++struct cudbg_init {
++ struct adapter *adap; /* Pointer to adapter structure */
++ void *outbuf; /* Output buffer */
++ u32 outbuf_size; /* Output buffer size */
++};
++#endif /* __CUDBG_IF_H__ */
+--- /dev/null
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h
+@@ -0,0 +1,65 @@
++/*
++ * Copyright (C) 2017 Chelsio Communications. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * The full GNU General Public License is included in this distribution in
++ * the file called "COPYING".
++ *
++ */
++
++#ifndef __CUDBG_LIB_COMMON_H__
++#define __CUDBG_LIB_COMMON_H__
++
++#define CUDBG_SIGNATURE 67856866 /* CUDB in ascii */
++
++enum cudbg_dump_type {
++ CUDBG_DUMP_TYPE_MINI = 1,
++};
++
++enum cudbg_compression_type {
++ CUDBG_COMPRESSION_NONE = 1,
++};
++
++struct cudbg_hdr {
++ u32 signature;
++ u32 hdr_len;
++ u16 major_ver;
++ u16 minor_ver;
++ u32 data_len;
++ u32 hdr_flags;
++ u16 max_entities;
++ u8 chip_ver;
++ u8 dump_type:3;
++ u8 reserved1:1;
++ u8 compress_type:4;
++ u32 reserved[8];
++};
++
++struct cudbg_entity_hdr {
++ u32 entity_type;
++ u32 start_offset;
++ u32 size;
++ int hdr_flags;
++ u32 sys_warn;
++ u32 sys_err;
++ u8 num_pad;
++ u8 flag; /* bit 0 is used to indicate ext data */
++ u8 reserved1[2];
++ u32 next_ext_offset; /* pointer to next extended entity meta data */
++ u32 reserved[5];
++};
++
++struct cudbg_buffer {
++ u32 size;
++ u32 offset;
++ char *data;
++};
++#endif /* __CUDBG_LIB_COMMON_H__ */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -909,6 +909,9 @@ struct adapter {
+ /* TC flower offload */
+ DECLARE_HASHTABLE(flower_anymatch_tbl, 9);
+ struct timer_list flower_stats_timer;
++
++ /* Ethtool Dump */
++ struct ethtool_dump eth_dump;
+ };
+
+ /* Support for "sched-class" command to allow a TX Scheduling Class to be
+--- /dev/null
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+@@ -0,0 +1,73 @@
++/*
++ * Copyright (C) 2017 Chelsio Communications. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * The full GNU General Public License is included in this distribution in
++ * the file called "COPYING".
++ *
++ */
++
++#include "cxgb4.h"
++#include "cxgb4_cudbg.h"
++
++u32 cxgb4_get_dump_length(struct adapter *adap, u32 flag)
++{
++ return 0;
++}
++
++int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
++ u32 flag)
++{
++ struct cudbg_init cudbg_init = { 0 };
++ struct cudbg_buffer dbg_buff = { 0 };
++ u32 size, min_size, total_size = 0;
++ struct cudbg_hdr *cudbg_hdr;
++
++ size = *buf_size;
++
++ cudbg_init.adap = adap;
++ cudbg_init.outbuf = buf;
++ cudbg_init.outbuf_size = size;
++
++ dbg_buff.data = buf;
++ dbg_buff.size = size;
++ dbg_buff.offset = 0;
++
++ cudbg_hdr = (struct cudbg_hdr *)buf;
++ cudbg_hdr->signature = CUDBG_SIGNATURE;
++ cudbg_hdr->hdr_len = sizeof(struct cudbg_hdr);
++ cudbg_hdr->major_ver = CUDBG_MAJOR_VERSION;
++ cudbg_hdr->minor_ver = CUDBG_MINOR_VERSION;
++ cudbg_hdr->max_entities = CUDBG_MAX_ENTITY;
++ cudbg_hdr->chip_ver = adap->params.chip;
++ cudbg_hdr->dump_type = CUDBG_DUMP_TYPE_MINI;
++ cudbg_hdr->compress_type = CUDBG_COMPRESSION_NONE;
++
++ min_size = sizeof(struct cudbg_hdr) +
++ sizeof(struct cudbg_entity_hdr) *
++ cudbg_hdr->max_entities;
++ if (size < min_size)
++ return -ENOMEM;
++
++ dbg_buff.offset += min_size;
++ total_size = dbg_buff.offset;
++
++ cudbg_hdr->data_len = total_size;
++ *buf_size = total_size;
++ return 0;
++}
++
++void cxgb4_init_ethtool_dump(struct adapter *adapter)
++{
++ adapter->eth_dump.flag = CXGB4_ETH_DUMP_NONE;
++ adapter->eth_dump.version = adapter->params.fw_vers;
++ adapter->eth_dump.len = 0;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
+@@ -0,0 +1,32 @@
++/*
++ * Copyright (C) 2017 Chelsio Communications. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * The full GNU General Public License is included in this distribution in
++ * the file called "COPYING".
++ *
++ */
++
++#ifndef __CXGB4_CUDBG_H__
++#define __CXGB4_CUDBG_H__
++
++#include "cudbg_if.h"
++#include "cudbg_lib_common.h"
++
++enum CXGB4_ETHTOOL_DUMP_FLAGS {
++ CXGB4_ETH_DUMP_NONE = ETH_FW_DUMP_DISABLE,
++};
++
++u32 cxgb4_get_dump_length(struct adapter *adap, u32 flag);
++int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
++ u32 flag);
++void cxgb4_init_ethtool_dump(struct adapter *adapter);
++#endif /* __CXGB4_CUDBG_H__ */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
+@@ -21,6 +21,7 @@
+ #include "cxgb4.h"
+ #include "t4_regs.h"
+ #include "t4fw_api.h"
++#include "cxgb4_cudbg.h"
+
+ #define EEPROM_MAGIC 0x38E2F10C
+
+@@ -1374,6 +1375,56 @@ static int get_rxnfc(struct net_device *
+ return -EOPNOTSUPP;
+ }
+
++static int set_dump(struct net_device *dev, struct ethtool_dump *eth_dump)
++{
++ struct adapter *adapter = netdev2adap(dev);
++ u32 len = 0;
++
++ len = sizeof(struct cudbg_hdr) +
++ sizeof(struct cudbg_entity_hdr) * CUDBG_MAX_ENTITY;
++ len += cxgb4_get_dump_length(adapter, eth_dump->flag);
++
++ adapter->eth_dump.flag = eth_dump->flag;
++ adapter->eth_dump.len = len;
++ return 0;
++}
++
++static int get_dump_flag(struct net_device *dev, struct ethtool_dump *eth_dump)
++{
++ struct adapter *adapter = netdev2adap(dev);
++
++ eth_dump->flag = adapter->eth_dump.flag;
++ eth_dump->len = adapter->eth_dump.len;
++ eth_dump->version = adapter->eth_dump.version;
++ return 0;
++}
++
++static int get_dump_data(struct net_device *dev, struct ethtool_dump *eth_dump,
++ void *buf)
++{
++ struct adapter *adapter = netdev2adap(dev);
++ u32 len = 0;
++ int ret = 0;
++
++ if (adapter->eth_dump.flag == CXGB4_ETH_DUMP_NONE)
++ return -ENOENT;
++
++ len = sizeof(struct cudbg_hdr) +
++ sizeof(struct cudbg_entity_hdr) * CUDBG_MAX_ENTITY;
++ len += cxgb4_get_dump_length(adapter, adapter->eth_dump.flag);
++ if (eth_dump->len < len)
++ return -ENOMEM;
++
++ ret = cxgb4_cudbg_collect(adapter, buf, &len, adapter->eth_dump.flag);
++ if (ret)
++ return ret;
++
++ eth_dump->flag = adapter->eth_dump.flag;
++ eth_dump->len = len;
++ eth_dump->version = adapter->eth_dump.version;
++ return 0;
++}
++
+ static const struct ethtool_ops cxgb_ethtool_ops = {
+ .get_link_ksettings = get_link_ksettings,
+ .set_link_ksettings = set_link_ksettings,
+@@ -1404,7 +1455,10 @@ static const struct ethtool_ops cxgb_eth
+ .get_rxfh = get_rss_table,
+ .set_rxfh = set_rss_table,
+ .flash_device = set_flash,
+- .get_ts_info = get_ts_info
++ .get_ts_info = get_ts_info,
++ .set_dump = set_dump,
++ .get_dump_flag = get_dump_flag,
++ .get_dump_data = get_dump_data,
+ };
+
+ void cxgb4_set_ethtool_ops(struct net_device *netdev)
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -81,6 +81,7 @@
+ #include "cxgb4_tc_u32.h"
+ #include "cxgb4_tc_flower.h"
+ #include "cxgb4_ptp.h"
++#include "cxgb4_cudbg.h"
+
+ char cxgb4_driver_name[] = KBUILD_MODNAME;
+
+@@ -5035,6 +5036,8 @@ static int init_one(struct pci_dev *pdev
+ cxgb4_set_ethtool_ops(netdev);
+ }
+
++ cxgb4_init_ethtool_dump(adapter);
++
+ pci_set_drvdata(pdev, adapter);
+
+ if (adapter->flags & FW_OK) {
diff --git a/patches.drivers/cxgb4-initialize-hash-filter-configuration.patch b/patches.drivers/cxgb4-initialize-hash-filter-configuration.patch
new file mode 100644
index 0000000000..04c54608a0
--- /dev/null
+++ b/patches.drivers/cxgb4-initialize-hash-filter-configuration.patch
@@ -0,0 +1,152 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Wed, 1 Nov 2017 08:53:00 +0530
+Subject: cxgb4: initialize hash-filter configuration
+Patch-mainline: v4.15-rc1
+Git-commit: 5c31254e35a8a5767c3b23377c34018d8bdd0567
+References: bsc#1064802 bsc#1066129
+
+Add support for hash-filter configuration on T6. Also, do basic
+checks for the related initialization.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 6 ++++++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 22 ++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h | 1 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 14 ++++++++++----
+ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 14 ++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 1 +
+ 6 files changed, 54 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -366,6 +366,7 @@ struct adapter_params {
+ unsigned char crypto; /* HW capability for crypto */
+
+ unsigned char bypass;
++ unsigned char hash_filter;
+
+ unsigned int ofldq_wr_cred;
+ bool ulptx_memwrite_dsgl; /* use of T5 DSGL allowed */
+@@ -1140,6 +1141,11 @@ static inline int is_offload(const struc
+ return adap->params.offload;
+ }
+
++static inline int is_hashfilter(const struct adapter *adap)
++{
++ return adap->params.hash_filter;
++}
++
+ static inline int is_pci_uld(const struct adapter *adap)
+ {
+ return adap->params.crypto;
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+@@ -915,3 +915,25 @@ void filter_rpl(struct adapter *adap, co
+ complete(&ctx->completion);
+ }
+ }
++
++int init_hash_filter(struct adapter *adap)
++{
++ /* On T6, verify the necessary register configs and warn the user in
++ * case of improper config
++ */
++ if (is_t6(adap->params.chip)) {
++ if (TCAM_ACTV_HIT_G(t4_read_reg(adap, LE_DB_RSP_CODE_0_A)) != 4)
++ goto err;
++
++ if (HASH_ACTV_HIT_G(t4_read_reg(adap, LE_DB_RSP_CODE_1_A)) != 4)
++ goto err;
++ } else {
++ dev_err(adap->pdev_dev, "Hash filter supported only on T6\n");
++ return -EINVAL;
++ }
++ adap->params.hash_filter = 1;
++ return 0;
++err:
++ dev_warn(adap->pdev_dev, "Invalid hash filter config!\n");
++ return -EINVAL;
++}
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h
+@@ -45,4 +45,5 @@ int delete_filter(struct adapter *adapte
+
+ int writable_filter(struct filter_entry *f);
+ void clear_all_filters(struct adapter *adapter);
++int init_hash_filter(struct adapter *adap);
+ #endif /* __CXGB4_FILTER_H */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -3933,7 +3933,8 @@ static int adap_init0(struct adapter *ad
+ if (ret < 0)
+ goto bye;
+
+- if (caps_cmd.ofldcaps) {
++ if (caps_cmd.ofldcaps ||
++ (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_HASHFILTER))) {
+ /* query offload-related parameters */
+ params[0] = FW_PARAM_DEV(NTID);
+ params[1] = FW_PARAM_PFVF(SERVER_START);
+@@ -3970,8 +3971,13 @@ static int adap_init0(struct adapter *ad
+ adap->vres.ddp.size = val[4] - val[3] + 1;
+ adap->params.ofldq_wr_cred = val[5];
+
+- adap->params.offload = 1;
+- adap->num_ofld_uld += 1;
++ if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_HASHFILTER)) {
++ if (init_hash_filter(adap) < 0)
++ goto bye;
++ } else {
++ adap->params.offload = 1;
++ adap->num_ofld_uld += 1;
++ }
+ }
+ if (caps_cmd.rdmacaps) {
+ params[0] = FW_PARAM_PFVF(STAG_START);
+@@ -5141,7 +5147,7 @@ static int init_one(struct pci_dev *pdev
+ cxgb4_init_tc_flower(adapter);
+ }
+
+- if (is_offload(adapter)) {
++ if (is_offload(adapter) || is_hashfilter(adapter)) {
+ if (t4_read_reg(adapter, LE_DB_CONFIG_A) & HASHEN_F) {
+ u32 hash_base, hash_reg;
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+@@ -2933,6 +2933,20 @@
+ #define SSRAMINTPERR_V(x) ((x) << SSRAMINTPERR_S)
+ #define SSRAMINTPERR_F SSRAMINTPERR_V(1U)
+
++#define LE_DB_RSP_CODE_0_A 0x19c74
++
++#define TCAM_ACTV_HIT_S 0
++#define TCAM_ACTV_HIT_M 0x1fU
++#define TCAM_ACTV_HIT_V(x) ((x) << TCAM_ACTV_HIT_S)
++#define TCAM_ACTV_HIT_G(x) (((x) >> TCAM_ACTV_HIT_S) & TCAM_ACTV_HIT_M)
++
++#define LE_DB_RSP_CODE_1_A 0x19c78
++
++#define HASH_ACTV_HIT_S 25
++#define HASH_ACTV_HIT_M 0x1fU
++#define HASH_ACTV_HIT_V(x) ((x) << HASH_ACTV_HIT_S)
++#define HASH_ACTV_HIT_G(x) (((x) >> HASH_ACTV_HIT_S) & HASH_ACTV_HIT_M)
++
+ #define LE_3_DB_HASH_MASK_GEN_IPV4_T6_A 0x19eac
+ #define LE_4_DB_HASH_MASK_GEN_IPV4_T6_A 0x19eb0
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+@@ -1092,6 +1092,7 @@ enum fw_caps_config_switch {
+ enum fw_caps_config_nic {
+ FW_CAPS_CONFIG_NIC = 0x00000001,
+ FW_CAPS_CONFIG_NIC_VM = 0x00000002,
++ FW_CAPS_CONFIG_NIC_HASHFILTER = 0x00000020,
+ };
+
+ enum fw_caps_config_ofld {
diff --git a/patches.drivers/cxgb4-introduce-SMT-ops-to-prepare-for-SMAC-rewrite-.patch b/patches.drivers/cxgb4-introduce-SMT-ops-to-prepare-for-SMAC-rewrite-.patch
new file mode 100644
index 0000000000..d290da965f
--- /dev/null
+++ b/patches.drivers/cxgb4-introduce-SMT-ops-to-prepare-for-SMAC-rewrite-.patch
@@ -0,0 +1,717 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Wed, 18 Oct 2017 20:49:11 +0530
+Subject: cxgb4: introduce SMT ops to prepare for SMAC rewrite support
+Patch-mainline: v4.15-rc1
+Git-commit: 3bdb376e6944134d0f4d6d65497054a54ef273c9
+References: bsc#1064802 bsc#1066129
+
+Introduce SMT operations for allocating/removing entries from
+SMAC table. Make TCAM filters use the SMT ops whenever SMAC rewrite
+is required.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/Makefile | 2
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 3
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 107 ++++++++-
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 12 +
+ drivers/net/ethernet/chelsio/cxgb4/smt.c | 247 ++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/smt.h | 76 ++++++
+ drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 44 +++
+ drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h | 47 ++++
+ 8 files changed, 519 insertions(+), 19 deletions(-)
+ create mode 100644 drivers/net/ethernet/chelsio/cxgb4/smt.c
+ create mode 100644 drivers/net/ethernet/chelsio/cxgb4/smt.h
+ create mode 100644 drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/Makefile
++++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile
+@@ -4,7 +4,7 @@
+
+ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o
+
+-cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o \
++cxgb4-objs := cxgb4_main.o l2t.o smt.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o \
+ cxgb4_uld.o sched.o cxgb4_filter.o cxgb4_tc_u32.o \
+ cxgb4_ptp.o cxgb4_tc_flower.o cxgb4_cudbg.o \
+ cudbg_common.o cudbg_lib.o
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -858,6 +858,7 @@ struct adapter {
+ unsigned int clipt_start;
+ unsigned int clipt_end;
+ struct clip_tbl *clipt;
++ struct smt_data *smt;
+ struct cxgb4_uld_info *uld;
+ void *uld_handle[CXGB4_ULD_MAX];
+ unsigned int num_uld;
+@@ -1098,9 +1099,9 @@ struct filter_entry {
+ u32 locked:1; /* filter is administratively locked */
+
+ u32 pending:1; /* filter action is pending firmware reply */
+- u32 smtidx:8; /* Source MAC Table index for smac */
+ struct filter_ctx *ctx; /* Caller's completion hook */
+ struct l2t_entry *l2t; /* Layer Two Table entry for dmac */
++ struct smt_entry *smt; /* Source Mac Table entry for smac */
+ struct net_device *dev; /* Associated net device */
+ u32 tid; /* This will store the actual tid */
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+@@ -34,7 +34,9 @@
+
+ #include "cxgb4.h"
+ #include "t4_regs.h"
++#include "t4_tcb.h"
+ #include "l2t.h"
++#include "smt.h"
+ #include "t4fw_api.h"
+ #include "cxgb4_filter.h"
+
+@@ -332,6 +334,21 @@ int set_filter_wr(struct adapter *adapte
+ }
+ }
+
++ /* If the new filter requires loopback Source MAC rewriting then
++ * we need to allocate a SMT entry for the filter.
++ */
++ if (f->fs.newsmac) {
++ f->smt = cxgb4_smt_alloc_switching(f->dev, f->fs.smac);
++ if (!f->smt) {
++ if (f->l2t) {
++ cxgb4_l2t_release(f->l2t);
++ f->l2t = NULL;
++ }
++ kfree_skb(skb);
++ return -ENOMEM;
++ }
++ }
++
+ fwr = __skb_put_zero(skb, sizeof(*fwr));
+
+ /* It would be nice to put most of the following in t4_hw.c but most
+@@ -357,7 +374,6 @@ int set_filter_wr(struct adapter *adapte
+ FW_FILTER_WR_DIRSTEERHASH_V(f->fs.dirsteerhash) |
+ FW_FILTER_WR_LPBK_V(f->fs.action == FILTER_SWITCH) |
+ FW_FILTER_WR_DMAC_V(f->fs.newdmac) |
+- FW_FILTER_WR_SMAC_V(f->fs.newsmac) |
+ FW_FILTER_WR_INSVLAN_V(f->fs.newvlan == VLAN_INSERT ||
+ f->fs.newvlan == VLAN_REWRITE) |
+ FW_FILTER_WR_RMVLAN_V(f->fs.newvlan == VLAN_REMOVE ||
+@@ -404,8 +420,6 @@ int set_filter_wr(struct adapter *adapte
+ fwr->lpm = htons(f->fs.mask.lport);
+ fwr->fp = htons(f->fs.val.fport);
+ fwr->fpm = htons(f->fs.mask.fport);
+- if (f->fs.newsmac)
+- memcpy(fwr->sma, f->fs.smac, sizeof(fwr->sma));
+
+ /* Mark the filter as "pending" and ship off the Filter Work Request.
+ * When we get the Work Request Reply we'll clear the pending status.
+@@ -463,6 +477,9 @@ void clear_filter(struct adapter *adap,
+ if (f->l2t)
+ cxgb4_l2t_release(f->l2t);
+
++ if (f->smt)
++ cxgb4_smt_release(f->smt);
++
+ /* The zeroing of the filter rule below clears the filter valid,
+ * pending, locked flags, l2t pointer, etc. so it's all we need for
+ * this operation.
+@@ -757,6 +774,62 @@ out:
+ return ret;
+ }
+
++static int set_tcb_field(struct adapter *adap, struct filter_entry *f,
++ unsigned int ftid, u16 word, u64 mask, u64 val,
++ int no_reply)
++{
++ struct cpl_set_tcb_field *req;
++ struct sk_buff *skb;
++
++ skb = alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_ATOMIC);
++ if (!skb)
++ return -ENOMEM;
++
++ req = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*req));
++ memset(req, 0, sizeof(*req));
++ INIT_TP_WR_CPL(req, CPL_SET_TCB_FIELD, ftid);
++ req->reply_ctrl = htons(REPLY_CHAN_V(0) |
++ QUEUENO_V(adap->sge.fw_evtq.abs_id) |
++ NO_REPLY_V(no_reply));
++ req->word_cookie = htons(TCB_WORD_V(word) | TCB_COOKIE_V(ftid));
++ req->mask = cpu_to_be64(mask);
++ req->val = cpu_to_be64(val);
++ set_wr_txq(skb, CPL_PRIORITY_CONTROL, f->fs.val.iport & 0x3);
++ t4_ofld_send(adap, skb);
++ return 0;
++}
++
++/* Set one of the t_flags bits in the TCB.
++ */
++static int set_tcb_tflag(struct adapter *adap, struct filter_entry *f,
++ unsigned int ftid, unsigned int bit_pos,
++ unsigned int val, int no_reply)
++{
++ return set_tcb_field(adap, f, ftid, TCB_T_FLAGS_W, 1ULL << bit_pos,
++ (unsigned long long)val << bit_pos, no_reply);
++}
++
++static int configure_filter_smac(struct adapter *adap, struct filter_entry *f)
++{
++ int err;
++
++ /* do a set-tcb for smac-sel and CWR bit.. */
++ err = set_tcb_tflag(adap, f, f->tid, TF_CCTRL_CWR_S, 1, 1);
++ if (err)
++ goto smac_err;
++
++ err = set_tcb_field(adap, f, f->tid, TCB_SMAC_SEL_W,
++ TCB_SMAC_SEL_V(TCB_SMAC_SEL_M),
++ TCB_SMAC_SEL_V(f->smt->idx), 1);
++ if (!err)
++ return 0;
++
++smac_err:
++ dev_err(adap->pdev_dev, "filter %u smac config failed with error %u\n",
++ f->tid, err);
++ return err;
++}
++
+ /* Handle a filter write/deletion reply. */
+ void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl)
+ {
+@@ -795,19 +868,23 @@ void filter_rpl(struct adapter *adap, co
+ clear_filter(adap, f);
+ if (ctx)
+ ctx->result = 0;
+- } else if (ret == FW_FILTER_WR_SMT_TBL_FULL) {
+- dev_err(adap->pdev_dev, "filter %u setup failed due to full SMT\n",
+- idx);
+- clear_filter(adap, f);
+- if (ctx)
+- ctx->result = -ENOMEM;
+ } else if (ret == FW_FILTER_WR_FLT_ADDED) {
+- f->smtidx = (be64_to_cpu(rpl->oldval) >> 24) & 0xff;
+- f->pending = 0; /* asynchronous setup completed */
+- f->valid = 1;
+- if (ctx) {
+- ctx->result = 0;
+- ctx->tid = idx;
++ int err = 0;
++
++ if (f->fs.newsmac)
++ err = configure_filter_smac(adap, f);
++
++ if (!err) {
++ f->pending = 0; /* async setup completed */
++ f->valid = 1;
++ if (ctx) {
++ ctx->result = 0;
++ ctx->tid = idx;
++ }
++ } else {
++ clear_filter(adap, f);
++ if (ctx)
++ ctx->result = err;
+ }
+ } else {
+ /* Something went wrong. Issue a warning about the
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -77,6 +77,7 @@
+ #include "cxgb4_debugfs.h"
+ #include "clip_tbl.h"
+ #include "l2t.h"
++#include "smt.h"
+ #include "sched.h"
+ #include "cxgb4_tc_u32.h"
+ #include "cxgb4_tc_flower.h"
+@@ -563,6 +564,10 @@ static int fwevtq_handler(struct sge_rsp
+ const struct cpl_l2t_write_rpl *p = (void *)rsp;
+
+ do_l2t_write_rpl(q->adap, p);
++ } else if (opcode == CPL_SMT_WRITE_RPL) {
++ const struct cpl_smt_write_rpl *p = (void *)rsp;
++
++ do_smt_write_rpl(q->adap, p);
+ } else if (opcode == CPL_SET_TCB_RPL) {
+ const struct cpl_set_tcb_rpl *p = (void *)rsp;
+
+@@ -4641,6 +4646,7 @@ static void free_some_resources(struct a
+ {
+ unsigned int i;
+
++ kvfree(adapter->smt);
+ kvfree(adapter->l2t);
+ t4_cleanup_sched(adapter);
+ kvfree(adapter->tids.tid_tab);
+@@ -5067,6 +5073,12 @@ static int init_one(struct pci_dev *pdev
+ */
+ cfg_queues(adapter);
+
++ adapter->smt = t4_init_smt();
++ if (!adapter->smt) {
++ /* We tolerate a lack of SMT, giving up some functionality */
++ dev_warn(&pdev->dev, "could not allocate SMT, continuing\n");
++ }
++
+ adapter->l2t = t4_init_l2t(adapter->l2t_start, adapter->l2t_end);
+ if (!adapter->l2t) {
+ /* We tolerate a lack of L2T, giving up some functionality */
+--- /dev/null
++++ b/drivers/net/ethernet/chelsio/cxgb4/smt.c
+@@ -0,0 +1,247 @@
++/*
++ * This file is part of the Chelsio T4/T5/T6 Ethernet driver for Linux.
++ *
++ * Copyright (c) 2017 Chelsio Communications, Inc. All rights reserved.
++ *
++ * This software is available to you under a choice of one of two
++ * licenses. You may choose to be licensed under the terms of the GNU
++ * General Public License (GPL) Version 2, available from the file
++ * COPYING in the main directory of this source tree, or the
++ * OpenIB.org BSD license below:
++ *
++ * Redistribution and use in source and binary forms, with or
++ * without modification, are permitted provided that the following
++ * conditions are met:
++ *
++ * - Redistributions of source code must retain the above
++ * copyright notice, this list of conditions and the following
++ * disclaimer.
++ *
++ * - Redistributions in binary form must reproduce the above
++ * copyright notice, this list of conditions and the following
++ * disclaimer in the documentation and/or other materials
++ * provided with the distribution.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++ */
++
++#include "cxgb4.h"
++#include "smt.h"
++#include "t4_msg.h"
++#include "t4fw_api.h"
++#include "t4_regs.h"
++#include "t4_values.h"
++
++struct smt_data *t4_init_smt(void)
++{
++ unsigned int smt_size;
++ struct smt_data *s;
++ int i;
++
++ smt_size = SMT_SIZE;
++
++ s = kvzalloc(sizeof(*s) + smt_size * sizeof(struct smt_entry),
++ GFP_KERNEL);
++ if (!s)
++ return NULL;
++ s->smt_size = smt_size;
++ rwlock_init(&s->lock);
++ for (i = 0; i < s->smt_size; ++i) {
++ s->smtab[i].idx = i;
++ s->smtab[i].state = SMT_STATE_UNUSED;
++ memset(&s->smtab[i].src_mac, 0, ETH_ALEN);
++ spin_lock_init(&s->smtab[i].lock);
++ atomic_set(&s->smtab[i].refcnt, 0);
++ }
++ return s;
++}
++
++static struct smt_entry *find_or_alloc_smte(struct smt_data *s, u8 *smac)
++{
++ struct smt_entry *first_free = NULL;
++ struct smt_entry *e, *end;
++
++ for (e = &s->smtab[0], end = &s->smtab[s->smt_size]; e != end; ++e) {
++ if (atomic_read(&e->refcnt) == 0) {
++ if (!first_free)
++ first_free = e;
++ } else {
++ if (e->state == SMT_STATE_SWITCHING) {
++ /* This entry is actually in use. See if we can
++ * re-use it ?
++ */
++ if (memcmp(e->src_mac, smac, ETH_ALEN) == 0)
++ goto found_reuse;
++ }
++ }
++ }
++
++ if (first_free) {
++ e = first_free;
++ goto found;
++ }
++ return NULL;
++
++found:
++ e->state = SMT_STATE_UNUSED;
++
++found_reuse:
++ return e;
++}
++
++static void t4_smte_free(struct smt_entry *e)
++{
++ spin_lock_bh(&e->lock);
++ if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */
++ e->state = SMT_STATE_UNUSED;
++ }
++ spin_unlock_bh(&e->lock);
++}
++
++/**
++ * @e: smt entry to release
++ *
++ * Releases ref count and frees up an smt entry from SMT table
++ */
++void cxgb4_smt_release(struct smt_entry *e)
++{
++ if (atomic_dec_and_test(&e->refcnt))
++ t4_smte_free(e);
++}
++EXPORT_SYMBOL(cxgb4_smt_release);
++
++void do_smt_write_rpl(struct adapter *adap, const struct cpl_smt_write_rpl *rpl)
++{
++ unsigned int smtidx = TID_TID_G(GET_TID(rpl));
++ struct smt_data *s = adap->smt;
++
++ if (unlikely(rpl->status != CPL_ERR_NONE)) {
++ struct smt_entry *e = &s->smtab[smtidx];
++
++ dev_err(adap->pdev_dev,
++ "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
++ rpl->status, smtidx);
++ spin_lock(&e->lock);
++ e->state = SMT_STATE_ERROR;
++ spin_unlock(&e->lock);
++ return;
++ }
++}
++
++static int write_smt_entry(struct adapter *adapter, struct smt_entry *e)
++{
++ struct cpl_t6_smt_write_req *t6req;
++ struct smt_data *s = adapter->smt;
++ struct cpl_smt_write_req *req;
++ struct sk_buff *skb;
++ int size;
++ u8 row;
++
++ if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) {
++ size = sizeof(*req);
++ skb = alloc_skb(size, GFP_ATOMIC);
++ if (!skb)
++ return -ENOMEM;
++ /* Source MAC Table (SMT) contains 256 SMAC entries
++ * organized in 128 rows of 2 entries each.
++ */
++ req = (struct cpl_smt_write_req *)__skb_put(skb, size);
++ INIT_TP_WR(req, 0);
++
++ /* Each row contains an SMAC pair.
++ * LSB selects the SMAC entry within a row
++ */
++ row = (e->idx >> 1);
++ if (e->idx & 1) {
++ req->pfvf1 = 0x0;
++ memcpy(req->src_mac1, e->src_mac, ETH_ALEN);
++
++ /* fill pfvf0/src_mac0 with entry
++ * at prev index from smt-tab.
++ */
++ req->pfvf0 = 0x0;
++ memcpy(req->src_mac0, s->smtab[e->idx - 1].src_mac,
++ ETH_ALEN);
++ } else {
++ req->pfvf0 = 0x0;
++ memcpy(req->src_mac0, e->src_mac, ETH_ALEN);
++
++ /* fill pfvf1/src_mac1 with entry
++ * at next index from smt-tab
++ */
++ req->pfvf1 = 0x0;
++ memcpy(req->src_mac1, s->smtab[e->idx + 1].src_mac,
++ ETH_ALEN);
++ }
++ } else {
++ size = sizeof(*t6req);
++ skb = alloc_skb(size, GFP_ATOMIC);
++ if (!skb)
++ return -ENOMEM;
++ /* Source MAC Table (SMT) contains 256 SMAC entries */
++ t6req = (struct cpl_t6_smt_write_req *)__skb_put(skb, size);
++ INIT_TP_WR(t6req, 0);
++ req = (struct cpl_smt_write_req *)t6req;
++
++ /* fill pfvf0/src_mac0 from smt-tab */
++ req->pfvf0 = 0x0;
++ memcpy(req->src_mac0, s->smtab[e->idx].src_mac, ETH_ALEN);
++ row = e->idx;
++ }
++
++ OPCODE_TID(req) =
++ htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, e->idx |
++ TID_QID_V(adapter->sge.fw_evtq.abs_id)));
++ req->params = htonl(SMTW_NORPL_V(0) |
++ SMTW_IDX_V(row) |
++ SMTW_OVLAN_IDX_V(0));
++ t4_mgmt_tx(adapter, skb);
++ return 0;
++}
++
++static struct smt_entry *t4_smt_alloc_switching(struct adapter *adap, u16 pfvf,
++ u8 *smac)
++{
++ struct smt_data *s = adap->smt;
++ struct smt_entry *e;
++
++ write_lock_bh(&s->lock);
++ e = find_or_alloc_smte(s, smac);
++ if (e) {
++ spin_lock(&e->lock);
++ if (!atomic_read(&e->refcnt)) {
++ atomic_set(&e->refcnt, 1);
++ e->state = SMT_STATE_SWITCHING;
++ e->pfvf = pfvf;
++ memcpy(e->src_mac, smac, ETH_ALEN);
++ write_smt_entry(adap, e);
++ } else {
++ atomic_inc(&e->refcnt);
++ }
++ spin_unlock(&e->lock);
++ }
++ write_unlock_bh(&s->lock);
++ return e;
++}
++
++/**
++ * @dev: net_device pointer
++ * @smac: MAC address to add to SMT
++ * Returns pointer to the SMT entry created
++ *
++ * Allocates an SMT entry to be used by switching rule of a filter.
++ */
++struct smt_entry *cxgb4_smt_alloc_switching(struct net_device *dev, u8 *smac)
++{
++ struct adapter *adap = netdev2adap(dev);
++
++ return t4_smt_alloc_switching(adap, 0x0, smac);
++}
++EXPORT_SYMBOL(cxgb4_smt_alloc_switching);
+--- /dev/null
++++ b/drivers/net/ethernet/chelsio/cxgb4/smt.h
+@@ -0,0 +1,76 @@
++/*
++ * This file is part of the Chelsio T4/T5/T6 Ethernet driver for Linux.
++ *
++ * Copyright (c) 2017 Chelsio Communications, Inc. All rights reserved.
++ *
++ * This software is available to you under a choice of one of two
++ * licenses. You may choose to be licensed under the terms of the GNU
++ * General Public License (GPL) Version 2, available from the file
++ * COPYING in the main directory of this source tree, or the
++ * OpenIB.org BSD license below:
++ *
++ * Redistribution and use in source and binary forms, with or
++ * without modification, are permitted provided that the following
++ * conditions are met:
++ *
++ * - Redistributions of source code must retain the above
++ * copyright notice, this list of conditions and the following
++ * disclaimer.
++ *
++ * - Redistributions in binary form must reproduce the above
++ * copyright notice, this list of conditions and the following
++ * disclaimer in the documentation and/or other materials
++ * provided with the distribution.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++ */
++
++#ifndef __CXGB4_SMT_H
++#define __CXGB4_SMT_H
++
++#include <linux/spinlock.h>
++#include <linux/if_ether.h>
++#include <linux/atomic.h>
++
++struct adapter;
++struct cpl_smt_write_rpl;
++
++/* SMT related handling. Heavily adapted based on l2t ops in l2t.h/l2t.c
++ */
++enum {
++ SMT_STATE_SWITCHING,
++ SMT_STATE_UNUSED,
++ SMT_STATE_ERROR
++};
++
++enum {
++ SMT_SIZE = 256
++};
++
++struct smt_entry {
++ u16 state;
++ u16 idx;
++ u16 pfvf;
++ u8 src_mac[ETH_ALEN];
++ atomic_t refcnt;
++ spinlock_t lock; /* protect smt entry add,removal */
++};
++
++struct smt_data {
++ unsigned int smt_size;
++ rwlock_t lock;
++ struct smt_entry smtab[0];
++};
++
++struct smt_data *t4_init_smt(void);
++struct smt_entry *cxgb4_smt_alloc_switching(struct net_device *dev, u8 *smac);
++void cxgb4_smt_release(struct smt_entry *e);
++void do_smt_write_rpl(struct adapter *p, const struct cpl_smt_write_rpl *rpl);
++#endif /* __CXGB4_SMT_H */
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+@@ -50,6 +50,7 @@ enum {
+ CPL_RX_DATA_ACK = 0xD,
+ CPL_TX_PKT = 0xE,
+ CPL_L2T_WRITE_REQ = 0x12,
++ CPL_SMT_WRITE_REQ = 0x14,
+ CPL_TID_RELEASE = 0x1A,
+ CPL_TX_DATA_ISO = 0x1F,
+
+@@ -60,6 +61,7 @@ enum {
+ CPL_PEER_CLOSE = 0x26,
+ CPL_ABORT_REQ_RSS = 0x2B,
+ CPL_ABORT_RPL_RSS = 0x2D,
++ CPL_SMT_WRITE_RPL = 0x2E,
+
+ CPL_RX_PHYS_ADDR = 0x30,
+ CPL_CLOSE_CON_RPL = 0x32,
+@@ -681,8 +683,8 @@ struct cpl_set_tcb_field {
+ };
+
+ /* cpl_set_tcb_field.word_cookie fields */
+-#define TCB_WORD_S 0
+-#define TCB_WORD(x) ((x) << TCB_WORD_S)
++#define TCB_WORD_S 0
++#define TCB_WORD_V(x) ((x) << TCB_WORD_S)
+
+ #define TCB_COOKIE_S 5
+ #define TCB_COOKIE_M 0x7
+@@ -1266,6 +1268,44 @@ struct cpl_l2t_write_rpl {
+ u8 rsvd[3];
+ };
+
++struct cpl_smt_write_req {
++ WR_HDR;
++ union opcode_tid ot;
++ __be32 params;
++ __be16 pfvf1;
++ u8 src_mac1[6];
++ __be16 pfvf0;
++ u8 src_mac0[6];
++};
++
++struct cpl_t6_smt_write_req {
++ WR_HDR;
++ union opcode_tid ot;
++ __be32 params;
++ __be64 tag;
++ __be16 pfvf0;
++ u8 src_mac0[6];
++ __be32 local_ip;
++ __be32 rsvd;
++};
++
++struct cpl_smt_write_rpl {
++ union opcode_tid ot;
++ u8 status;
++ u8 rsvd[3];
++};
++
++/* cpl_smt_{read,write}_req.params fields */
++#define SMTW_OVLAN_IDX_S 16
++#define SMTW_OVLAN_IDX_V(x) ((x) << SMTW_OVLAN_IDX_S)
++
++#define SMTW_IDX_S 20
++#define SMTW_IDX_V(x) ((x) << SMTW_IDX_S)
++
++#define SMTW_NORPL_S 31
++#define SMTW_NORPL_V(x) ((x) << SMTW_NORPL_S)
++#define SMTW_NORPL_F SMTW_NORPL_V(1U)
++
+ struct cpl_rdma_terminate {
+ union opcode_tid ot;
+ __be16 rsvd;
+--- /dev/null
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h
+@@ -0,0 +1,47 @@
++/*
++ * This file is part of the Chelsio T4/T5/T6 Ethernet driver for Linux.
++ *
++ * Copyright (c) 2017 Chelsio Communications, Inc. All rights reserved.
++ *
++ * This software is available to you under a choice of one of two
++ * licenses. You may choose to be licensed under the terms of the GNU
++ * General Public License (GPL) Version 2, available from the file
++ * COPYING in the main directory of this source tree, or the
++ * OpenIB.org BSD license below:
++ *
++ * Redistribution and use in source and binary forms, with or
++ * without modification, are permitted provided that the following
++ * conditions are met:
++ *
++ * - Redistributions of source code must retain the above
++ * copyright notice, this list of conditions and the following
++ * disclaimer.
++ *
++ * - Redistributions in binary form must reproduce the above
++ * copyright notice, this list of conditions and the following
++ * disclaimer in the documentation and/or other materials
++ * provided with the distribution.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++ */
++
++#ifndef __T4_TCB_H
++#define __T4_TCB_H
++
++#define TCB_SMAC_SEL_W 0
++#define TCB_SMAC_SEL_S 24
++#define TCB_SMAC_SEL_M 0xffULL
++#define TCB_SMAC_SEL_V(x) ((x) << TCB_SMAC_SEL_S)
++
++#define TCB_T_FLAGS_W 1
++
++#define TF_CCTRL_CWR_S 61
++
++#endif /* __T4_TCB_H */
diff --git a/patches.drivers/cxgb4-introduce-fw_filter2_wr-to-prepare-for-L3-L4-r.patch b/patches.drivers/cxgb4-introduce-fw_filter2_wr-to-prepare-for-L3-L4-r.patch
new file mode 100644
index 0000000000..ef434a86db
--- /dev/null
+++ b/patches.drivers/cxgb4-introduce-fw_filter2_wr-to-prepare-for-L3-L4-r.patch
@@ -0,0 +1,219 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Wed, 18 Oct 2017 20:49:13 +0530
+Subject: cxgb4: introduce fw_filter2_wr to prepare for L3/L4 rewrite support
+Patch-mainline: v4.15-rc1
+Git-commit: 0ff909946155ed1af2ec8feed3c1bac485201683
+References: bsc#1064802 bsc#1066129
+
+Update driver to use new fw_filter2_wr in order to support rewrite of
+L3/L4 header fields via filters. Query FW_PARAMS_PARAM_DEV_FILTER2_WR
+to check whether FW supports this new wr.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 10 ++
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 19 ++++-
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 10 ++
+ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 75 +++++++++++++++++++++-
+ 4 files changed, 111 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -367,6 +367,7 @@ struct adapter_params {
+ unsigned int max_ird_adapter; /* Max read depth per adapter */
+ bool fr_nsmr_tpte_wr_support; /* FW support for FR_NSMR_TPTE_WR */
+ u8 fw_caps_support; /* 32-bit Port Capabilities */
++ bool filter2_wr_support; /* FW support for FILTER2_WR */
+
+ /* MPS Buffer Group Map[per Port]. Bit i is set if buffer group i is
+ * used by the Port
+@@ -1064,10 +1065,19 @@ struct ch_filter_specification {
+ uint32_t newdmac:1; /* rewrite destination MAC address */
+ uint32_t newsmac:1; /* rewrite source MAC address */
+ uint32_t newvlan:2; /* rewrite VLAN Tag */
++ uint32_t nat_mode:3; /* specify NAT operation mode */
+ uint8_t dmac[ETH_ALEN]; /* new destination MAC address */
+ uint8_t smac[ETH_ALEN]; /* new source MAC address */
+ uint16_t vlan; /* VLAN Tag to insert */
+
++ u8 nat_lip[16]; /* local IP to use after NAT'ing */
++ u8 nat_fip[16]; /* foreign IP to use after NAT'ing */
++ u16 nat_lport; /* local port to use after NAT'ing */
++ u16 nat_fport; /* foreign port to use after NAT'ing */
++
++ /* reservation for future additions */
++ u8 rsvd[24];
++
+ /* Filter rule value/mask pairs.
+ */
+ struct ch_filter_tuple val;
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+@@ -313,7 +313,7 @@ static int del_filter_wr(struct adapter
+ int set_filter_wr(struct adapter *adapter, int fidx)
+ {
+ struct filter_entry *f = &adapter->tids.ftid_tab[fidx];
+- struct fw_filter_wr *fwr;
++ struct fw_filter2_wr *fwr;
+ struct sk_buff *skb;
+
+ skb = alloc_skb(sizeof(*fwr), GFP_KERNEL);
+@@ -359,7 +359,10 @@ int set_filter_wr(struct adapter *adapte
+ * filter specification structure but for now it's easiest to simply
+ * put this fairly direct code in line ...
+ */
+- fwr->op_pkd = htonl(FW_WR_OP_V(FW_FILTER_WR));
++ if (adapter->params.filter2_wr_support)
++ fwr->op_pkd = htonl(FW_WR_OP_V(FW_FILTER2_WR));
++ else
++ fwr->op_pkd = htonl(FW_WR_OP_V(FW_FILTER_WR));
+ fwr->len16_pkd = htonl(FW_WR_LEN16_V(sizeof(*fwr) / 16));
+ fwr->tid_to_iq =
+ htonl(FW_FILTER_WR_TID_V(f->tid) |
+@@ -421,6 +424,18 @@ int set_filter_wr(struct adapter *adapte
+ fwr->fp = htons(f->fs.val.fport);
+ fwr->fpm = htons(f->fs.mask.fport);
+
++ if (adapter->params.filter2_wr_support) {
++ fwr->natmode_to_ulp_type =
++ FW_FILTER2_WR_ULP_TYPE_V(f->fs.nat_mode ?
++ ULP_MODE_TCPDDP :
++ ULP_MODE_NONE) |
++ FW_FILTER2_WR_NATMODE_V(f->fs.nat_mode);
++ memcpy(fwr->newlip, f->fs.nat_lip, sizeof(fwr->newlip));
++ memcpy(fwr->newfip, f->fs.nat_fip, sizeof(fwr->newfip));
++ fwr->newlport = htons(f->fs.nat_lport);
++ fwr->newfport = htons(f->fs.nat_fport);
++ }
++
+ /* Mark the filter as "pending" and ship off the Filter Work Request.
+ * When we get the Work Request Reply we'll clear the pending status.
+ */
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -3910,6 +3910,16 @@ static int adap_init0(struct adapter *ad
+ 1, params, val);
+ adap->params.fr_nsmr_tpte_wr_support = (ret == 0 && val[0] != 0);
+
++ /* See if FW supports FW_FILTER2 work request */
++ if (is_t4(adap->params.chip)) {
++ adap->params.filter2_wr_support = 0;
++ } else {
++ params[0] = FW_PARAM_DEV(FILTER2_WR);
++ ret = t4_query_params(adap, adap->mbox, adap->pf, 0,
++ 1, params, val);
++ adap->params.filter2_wr_support = (ret == 0 && val[0] != 0);
++ }
++
+ /*
+ * Get device capabilities so we can determine what resources we need
+ * to manage.
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+@@ -105,7 +105,8 @@ enum fw_wr_opcodes {
+ FW_ISCSI_TX_DATA_WR = 0x45,
+ FW_PTP_TX_PKT_WR = 0x46,
+ FW_CRYPTO_LOOKASIDE_WR = 0X6d,
+- FW_LASTC2E_WR = 0x70
++ FW_LASTC2E_WR = 0x70,
++ FW_FILTER2_WR = 0x77
+ };
+
+ struct fw_wr_hdr {
+@@ -201,6 +202,51 @@ struct fw_filter_wr {
+ __u8 sma[6];
+ };
+
++struct fw_filter2_wr {
++ __be32 op_pkd;
++ __be32 len16_pkd;
++ __be64 r3;
++ __be32 tid_to_iq;
++ __be32 del_filter_to_l2tix;
++ __be16 ethtype;
++ __be16 ethtypem;
++ __u8 frag_to_ovlan_vldm;
++ __u8 smac_sel;
++ __be16 rx_chan_rx_rpl_iq;
++ __be32 maci_to_matchtypem;
++ __u8 ptcl;
++ __u8 ptclm;
++ __u8 ttyp;
++ __u8 ttypm;
++ __be16 ivlan;
++ __be16 ivlanm;
++ __be16 ovlan;
++ __be16 ovlanm;
++ __u8 lip[16];
++ __u8 lipm[16];
++ __u8 fip[16];
++ __u8 fipm[16];
++ __be16 lp;
++ __be16 lpm;
++ __be16 fp;
++ __be16 fpm;
++ __be16 r7;
++ __u8 sma[6];
++ __be16 r8;
++ __u8 filter_type_swapmac;
++ __u8 natmode_to_ulp_type;
++ __be16 newlport;
++ __be16 newfport;
++ __u8 newlip[16];
++ __u8 newfip[16];
++ __be32 natseqcheck;
++ __be32 r9;
++ __be64 r10;
++ __be64 r11;
++ __be64 r12;
++ __be64 r13;
++};
++
+ #define FW_FILTER_WR_TID_S 12
+ #define FW_FILTER_WR_TID_M 0xfffff
+ #define FW_FILTER_WR_TID_V(x) ((x) << FW_FILTER_WR_TID_S)
+@@ -385,6 +431,32 @@ struct fw_filter_wr {
+ #define FW_FILTER_WR_RX_RPL_IQ_G(x) \
+ (((x) >> FW_FILTER_WR_RX_RPL_IQ_S) & FW_FILTER_WR_RX_RPL_IQ_M)
+
++#define FW_FILTER2_WR_FILTER_TYPE_S 1
++#define FW_FILTER2_WR_FILTER_TYPE_M 0x1
++#define FW_FILTER2_WR_FILTER_TYPE_V(x) ((x) << FW_FILTER2_WR_FILTER_TYPE_S)
++#define FW_FILTER2_WR_FILTER_TYPE_G(x) \
++ (((x) >> FW_FILTER2_WR_FILTER_TYPE_S) & FW_FILTER2_WR_FILTER_TYPE_M)
++#define FW_FILTER2_WR_FILTER_TYPE_F FW_FILTER2_WR_FILTER_TYPE_V(1U)
++
++#define FW_FILTER2_WR_NATMODE_S 5
++#define FW_FILTER2_WR_NATMODE_M 0x7
++#define FW_FILTER2_WR_NATMODE_V(x) ((x) << FW_FILTER2_WR_NATMODE_S)
++#define FW_FILTER2_WR_NATMODE_G(x) \
++ (((x) >> FW_FILTER2_WR_NATMODE_S) & FW_FILTER2_WR_NATMODE_M)
++
++#define FW_FILTER2_WR_NATFLAGCHECK_S 4
++#define FW_FILTER2_WR_NATFLAGCHECK_M 0x1
++#define FW_FILTER2_WR_NATFLAGCHECK_V(x) ((x) << FW_FILTER2_WR_NATFLAGCHECK_S)
++#define FW_FILTER2_WR_NATFLAGCHECK_G(x) \
++ (((x) >> FW_FILTER2_WR_NATFLAGCHECK_S) & FW_FILTER2_WR_NATFLAGCHECK_M)
++#define FW_FILTER2_WR_NATFLAGCHECK_F FW_FILTER2_WR_NATFLAGCHECK_V(1U)
++
++#define FW_FILTER2_WR_ULP_TYPE_S 0
++#define FW_FILTER2_WR_ULP_TYPE_M 0xf
++#define FW_FILTER2_WR_ULP_TYPE_V(x) ((x) << FW_FILTER2_WR_ULP_TYPE_S)
++#define FW_FILTER2_WR_ULP_TYPE_G(x) \
++ (((x) >> FW_FILTER2_WR_ULP_TYPE_S) & FW_FILTER2_WR_ULP_TYPE_M)
++
+ #define FW_FILTER_WR_MACI_S 23
+ #define FW_FILTER_WR_MACI_M 0x1ff
+ #define FW_FILTER_WR_MACI_V(x) ((x) << FW_FILTER_WR_MACI_S)
+@@ -1127,6 +1199,7 @@ enum fw_params_param_dev {
+ FW_PARAMS_PARAM_DEV_SCFGREV = 0x1A,
+ FW_PARAMS_PARAM_DEV_VPDREV = 0x1B,
+ FW_PARAMS_PARAM_DEV_RI_FR_NSMR_TPTE_WR = 0x1C,
++ FW_PARAMS_PARAM_DEV_FILTER2_WR = 0x1D,
+ FW_PARAMS_PARAM_DEV_MPSBGMAP = 0x1E,
+ };
+
diff --git a/patches.drivers/cxgb4-make-function-ch_flower_stats_cb-fixes-warning.patch b/patches.drivers/cxgb4-make-function-ch_flower_stats_cb-fixes-warning.patch
new file mode 100644
index 0000000000..295fa6b495
--- /dev/null
+++ b/patches.drivers/cxgb4-make-function-ch_flower_stats_cb-fixes-warning.patch
@@ -0,0 +1,31 @@
+From: Colin Ian King <colin.king@canonical.com>
+Date: Tue, 26 Sep 2017 16:14:09 +0100
+Subject: cxgb4: make function ch_flower_stats_cb, fixes warning
+Patch-mainline: v4.15-rc1
+Git-commit: 4d8806fd14e1492cd4fb2021f709b163ea3364ad
+References: bsc#1064802 bsc#1066129
+
+The function ch_flower_stats_cb is local to the source and does not need
+to be in global scope, so make it static.
+
+Cleans up sparse warnings:
+symbol 'ch_flower_stats_cb' was not declared. Should it be static?
+
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+@@ -366,7 +366,7 @@ err:
+ return ret;
+ }
+
+-void ch_flower_stats_cb(unsigned long data)
++static void ch_flower_stats_cb(unsigned long data)
+ {
+ struct adapter *adap = (struct adapter *)data;
+ struct ch_tc_flower_entry *flower_entry;
diff --git a/patches.drivers/cxgb4-save-additional-filter-tuple-field-shifts-in-t.patch b/patches.drivers/cxgb4-save-additional-filter-tuple-field-shifts-in-t.patch
new file mode 100644
index 0000000000..959e38bdb9
--- /dev/null
+++ b/patches.drivers/cxgb4-save-additional-filter-tuple-field-shifts-in-t.patch
@@ -0,0 +1,96 @@
+From: Kumar Sanghvi <kumaras@chelsio.com>
+Date: Wed, 1 Nov 2017 08:52:59 +0530
+Subject: cxgb4: save additional filter tuple field shifts in tp_params
+Patch-mainline: v4.15-rc1
+Git-commit: 0ba9a3b65c794982f4dc7fcdc8110c327359916b
+References: bsc#1064802 bsc#1066129
+
+Save additional filter tuple field shifts in tp_params based on
+configured filter tuple fields.
+
+Also, save the combined filter tuple mask based on configured
+filter tuple fields.
+
+Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 12 ++++++++++--
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 18 ++++++++++++++++--
+ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 3 +++
+ 3 files changed, 29 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -287,10 +287,18 @@ struct tp_params {
+ * places we store their offsets here, or a -1 if the field isn't
+ * present.
+ */
+- int vlan_shift;
+- int vnic_shift;
++ int fcoe_shift;
+ int port_shift;
++ int vnic_shift;
++ int vlan_shift;
++ int tos_shift;
+ int protocol_shift;
++ int ethertype_shift;
++ int macmatch_shift;
++ int matchtype_shift;
++ int frag_shift;
++
++ u64 hash_filter_mask;
+ };
+
+ struct vpd_params {
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+@@ -8816,11 +8816,21 @@ int t4_init_tp_params(struct adapter *ad
+ * shift positions of several elements of the Compressed Filter Tuple
+ * for this adapter which we need frequently ...
+ */
+- adap->params.tp.vlan_shift = t4_filter_field_shift(adap, VLAN_F);
+- adap->params.tp.vnic_shift = t4_filter_field_shift(adap, VNIC_ID_F);
++ adap->params.tp.fcoe_shift = t4_filter_field_shift(adap, FCOE_F);
+ adap->params.tp.port_shift = t4_filter_field_shift(adap, PORT_F);
++ adap->params.tp.vnic_shift = t4_filter_field_shift(adap, VNIC_ID_F);
++ adap->params.tp.vlan_shift = t4_filter_field_shift(adap, VLAN_F);
++ adap->params.tp.tos_shift = t4_filter_field_shift(adap, TOS_F);
+ adap->params.tp.protocol_shift = t4_filter_field_shift(adap,
+ PROTOCOL_F);
++ adap->params.tp.ethertype_shift = t4_filter_field_shift(adap,
++ ETHERTYPE_F);
++ adap->params.tp.macmatch_shift = t4_filter_field_shift(adap,
++ MACMATCH_F);
++ adap->params.tp.matchtype_shift = t4_filter_field_shift(adap,
++ MPSHITTYPE_F);
++ adap->params.tp.frag_shift = t4_filter_field_shift(adap,
++ FRAGMENTATION_F);
+
+ /* If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID
+ * represents the presence of an Outer VLAN instead of a VNIC ID.
+@@ -8828,6 +8838,10 @@ int t4_init_tp_params(struct adapter *ad
+ if ((adap->params.tp.ingress_config & VNIC_F) == 0)
+ adap->params.tp.vnic_shift = -1;
+
++ v = t4_read_reg(adap, LE_3_DB_HASH_MASK_GEN_IPV4_T6_A);
++ adap->params.tp.hash_filter_mask = v;
++ v = t4_read_reg(adap, LE_4_DB_HASH_MASK_GEN_IPV4_T6_A);
++ adap->params.tp.hash_filter_mask |= ((u64)v << 32);
+ return 0;
+ }
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+@@ -2933,6 +2933,9 @@
+ #define SSRAMINTPERR_V(x) ((x) << SSRAMINTPERR_S)
+ #define SSRAMINTPERR_F SSRAMINTPERR_V(1U)
+
++#define LE_3_DB_HASH_MASK_GEN_IPV4_T6_A 0x19eac
++#define LE_4_DB_HASH_MASK_GEN_IPV4_T6_A 0x19eb0
++
+ #define NCSI_INT_CAUSE_A 0x1a0d8
+
+ #define CIM_DM_PRTY_ERR_S 8
diff --git a/patches.drivers/cxgb4-update-API-for-TP-indirect-register-access.patch b/patches.drivers/cxgb4-update-API-for-TP-indirect-register-access.patch
new file mode 100644
index 0000000000..8667c075de
--- /dev/null
+++ b/patches.drivers/cxgb4-update-API-for-TP-indirect-register-access.patch
@@ -0,0 +1,716 @@
+From: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Date: Fri, 13 Oct 2017 18:48:17 +0530
+Subject: cxgb4: update API for TP indirect register access
+Patch-mainline: v4.15-rc1
+Git-commit: 5ccf9d049615994349e9b0a1f0d4b9a398b9b0c2
+References: bsc#1064802 bsc#1066129
+
+Try to access TP indirect registers via firmware first. If this fails,
+fallback and access them directly. This ensures that driver and
+firmware do not conflict each other while accessing the TP indirect
+registers.
+
+Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 36 +-
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 13
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c | 14
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 4
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 316 +++++++++++++--------
+ 5 files changed, 241 insertions(+), 142 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -1459,7 +1459,7 @@ unsigned int qtimer_val(const struct ada
+
+ int t4_init_devlog_params(struct adapter *adapter);
+ int t4_init_sge_params(struct adapter *adapter);
+-int t4_init_tp_params(struct adapter *adap);
++int t4_init_tp_params(struct adapter *adap, bool sleep_ok);
+ int t4_filter_field_shift(const struct adapter *adap, int filter_sel);
+ int t4_init_rss_mode(struct adapter *adap, int mbox);
+ int t4_init_portinfo(struct port_info *pi, int mbox,
+@@ -1473,14 +1473,15 @@ int t4_config_glbl_rss(struct adapter *a
+ int t4_config_vi_rss(struct adapter *adapter, int mbox, unsigned int viid,
+ unsigned int flags, unsigned int defq);
+ int t4_read_rss(struct adapter *adapter, u16 *entries);
+-void t4_read_rss_key(struct adapter *adapter, u32 *key);
+-void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx);
++void t4_read_rss_key(struct adapter *adapter, u32 *key, bool sleep_ok);
++void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx,
++ bool sleep_ok);
+ void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index,
+- u32 *valp);
++ u32 *valp, bool sleep_ok);
+ void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index,
+- u32 *vfl, u32 *vfh);
+-u32 t4_read_rss_pf_map(struct adapter *adapter);
+-u32 t4_read_rss_pf_mask(struct adapter *adapter);
++ u32 *vfl, u32 *vfh, bool sleep_ok);
++u32 t4_read_rss_pf_map(struct adapter *adapter, bool sleep_ok);
++u32 t4_read_rss_pf_mask(struct adapter *adapter, bool sleep_ok);
+
+ unsigned int t4_get_mps_bg_map(struct adapter *adapter, int pidx);
+ unsigned int t4_get_tp_ch_map(struct adapter *adapter, int pidx);
+@@ -1511,14 +1512,18 @@ void t4_read_cong_tbl(struct adapter *ad
+ void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
+ unsigned int mask, unsigned int val);
+ void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr);
+-void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st);
+-void t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st);
+-void t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st);
+-void t4_get_usm_stats(struct adapter *adap, struct tp_usm_stats *st);
++void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st,
++ bool sleep_ok);
++void t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st,
++ bool sleep_ok);
++void t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st,
++ bool sleep_ok);
++void t4_get_usm_stats(struct adapter *adap, struct tp_usm_stats *st,
++ bool sleep_ok);
+ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
+- struct tp_tcp_stats *v6);
++ struct tp_tcp_stats *v6, bool sleep_ok);
+ void t4_get_fcoe_stats(struct adapter *adap, unsigned int idx,
+- struct tp_fcoe_stats *st);
++ struct tp_fcoe_stats *st, bool sleep_ok);
+ void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
+ const unsigned short *alpha, const unsigned short *beta);
+
+@@ -1627,6 +1632,11 @@ void t4_idma_monitor(struct adapter *ada
+ int hz, int ticks);
+ int t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf,
+ unsigned int naddr, u8 *addr);
++void t4_tp_pio_read(struct adapter *adap, u32 *buff, u32 nregs,
++ u32 start_index, bool sleep_ok);
++void t4_tp_mib_read(struct adapter *adap, u32 *buff, u32 nregs,
++ u32 start_index, bool sleep_ok);
++
+ void t4_uld_mem_free(struct adapter *adap);
+ int t4_uld_mem_alloc(struct adapter *adap);
+ void t4_uld_clean_up(struct adapter *adap);
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
+@@ -2211,7 +2211,7 @@ static int rss_key_show(struct seq_file
+ {
+ u32 key[10];
+
+- t4_read_rss_key(seq->private, key);
++ t4_read_rss_key(seq->private, key, true);
+ seq_printf(seq, "%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x\n",
+ key[9], key[8], key[7], key[6], key[5], key[4], key[3],
+ key[2], key[1], key[0]);
+@@ -2248,7 +2248,7 @@ static ssize_t rss_key_write(struct file
+ }
+ }
+
+- t4_write_rss_key(adap, key, -1);
++ t4_write_rss_key(adap, key, -1, true);
+ return count;
+ }
+
+@@ -2325,12 +2325,13 @@ static int rss_pf_config_open(struct ino
+ return -ENOMEM;
+
+ pfconf = (struct rss_pf_conf *)p->data;
+- rss_pf_map = t4_read_rss_pf_map(adapter);
+- rss_pf_mask = t4_read_rss_pf_mask(adapter);
++ rss_pf_map = t4_read_rss_pf_map(adapter, true);
++ rss_pf_mask = t4_read_rss_pf_mask(adapter, true);
+ for (pf = 0; pf < 8; pf++) {
+ pfconf[pf].rss_pf_map = rss_pf_map;
+ pfconf[pf].rss_pf_mask = rss_pf_mask;
+- t4_read_rss_pf_config(adapter, pf, &pfconf[pf].rss_pf_config);
++ t4_read_rss_pf_config(adapter, pf, &pfconf[pf].rss_pf_config,
++ true);
+ }
+ return 0;
+ }
+@@ -2393,7 +2394,7 @@ static int rss_vf_config_open(struct ino
+ vfconf = (struct rss_vf_conf *)p->data;
+ for (vf = 0; vf < vfcount; vf++) {
+ t4_read_rss_vf_config(adapter, vf, &vfconf[vf].rss_vf_vfl,
+- &vfconf[vf].rss_vf_vfh);
++ &vfconf[vf].rss_vf_vfh, true);
+ }
+ return 0;
+ }
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
+@@ -336,10 +336,10 @@ static void collect_adapter_stats(struct
+ memset(s, 0, sizeof(*s));
+
+ spin_lock(&adap->stats_lock);
+- t4_tp_get_tcp_stats(adap, &v4, &v6);
+- t4_tp_get_rdma_stats(adap, &rdma_stats);
+- t4_get_usm_stats(adap, &usm_stats);
+- t4_tp_get_err_stats(adap, &err_stats);
++ t4_tp_get_tcp_stats(adap, &v4, &v6, false);
++ t4_tp_get_rdma_stats(adap, &rdma_stats, false);
++ t4_get_usm_stats(adap, &usm_stats, false);
++ t4_tp_get_err_stats(adap, &err_stats, false);
+ spin_unlock(&adap->stats_lock);
+
+ s->db_drop = adap->db_stats.db_drop;
+@@ -389,9 +389,9 @@ static void collect_channel_stats(struct
+ memset(s, 0, sizeof(*s));
+
+ spin_lock(&adap->stats_lock);
+- t4_tp_get_cpl_stats(adap, &cpl_stats);
+- t4_tp_get_err_stats(adap, &err_stats);
+- t4_get_fcoe_stats(adap, i, &fcoe_stats);
++ t4_tp_get_cpl_stats(adap, &cpl_stats, false);
++ t4_tp_get_err_stats(adap, &err_stats, false);
++ t4_get_fcoe_stats(adap, i, &fcoe_stats, false);
+ spin_unlock(&adap->stats_lock);
+
+ s->cpl_req = cpl_stats.req[i];
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -1639,7 +1639,7 @@ void cxgb4_get_tcp_stats(struct pci_dev
+ struct adapter *adap = pci_get_drvdata(pdev);
+
+ spin_lock(&adap->stats_lock);
+- t4_tp_get_tcp_stats(adap, v4, v6);
++ t4_tp_get_tcp_stats(adap, v4, v6, false);
+ spin_unlock(&adap->stats_lock);
+ }
+ EXPORT_SYMBOL(cxgb4_get_tcp_stats);
+@@ -4077,7 +4077,7 @@ static int adap_init0(struct adapter *ad
+ }
+ t4_init_sge_params(adap);
+ adap->flags |= FW_OK;
+- t4_init_tp_params(adap);
++ t4_init_tp_params(adap, true);
+ return 0;
+
+ /*
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+@@ -5052,23 +5052,26 @@ static unsigned int t4_use_ldst(struct a
+ }
+
+ /**
+- * t4_fw_tp_pio_rw - Access TP PIO through LDST
+- * @adap: the adapter
+- * @vals: where the indirect register values are stored/written
+- * @nregs: how many indirect registers to read/write
+- * @start_idx: index of first indirect register to read/write
+- * @rw: Read (1) or Write (0)
+- *
+- * Access TP PIO registers through LDST
+- */
+-static void t4_fw_tp_pio_rw(struct adapter *adap, u32 *vals, unsigned int nregs,
+- unsigned int start_index, unsigned int rw)
++ * t4_tp_fw_ldst_rw - Access TP indirect register through LDST
++ * @adap: the adapter
++ * @cmd: TP fw ldst address space type
++ * @vals: where the indirect register values are stored/written
++ * @nregs: how many indirect registers to read/write
++ * @start_idx: index of first indirect register to read/write
++ * @rw: Read (1) or Write (0)
++ * @sleep_ok: if true we may sleep while awaiting command completion
++ *
++ * Access TP indirect registers through LDST
++ */
++static int t4_tp_fw_ldst_rw(struct adapter *adap, int cmd, u32 *vals,
++ unsigned int nregs, unsigned int start_index,
++ unsigned int rw, bool sleep_ok)
+ {
+- int ret, i;
+- int cmd = FW_LDST_ADDRSPC_TP_PIO;
++ int ret = 0;
++ unsigned int i;
+ struct fw_ldst_cmd c;
+
+- for (i = 0 ; i < nregs; i++) {
++ for (i = 0; i < nregs; i++) {
+ memset(&c, 0, sizeof(c));
+ c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) |
+ FW_CMD_REQUEST_F |
+@@ -5079,26 +5082,127 @@ static void t4_fw_tp_pio_rw(struct adapt
+
+ c.u.addrval.addr = cpu_to_be32(start_index + i);
+ c.u.addrval.val = rw ? 0 : cpu_to_be32(vals[i]);
+- ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c);
+- if (!ret && rw)
++ ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c,
++ sleep_ok);
++ if (ret)
++ return ret;
++
++ if (rw)
+ vals[i] = be32_to_cpu(c.u.addrval.val);
+ }
++ return 0;
++}
++
++/**
++ * t4_tp_indirect_rw - Read/Write TP indirect register through LDST or backdoor
++ * @adap: the adapter
++ * @reg_addr: Address Register
++ * @reg_data: Data register
++ * @buff: where the indirect register values are stored/written
++ * @nregs: how many indirect registers to read/write
++ * @start_index: index of first indirect register to read/write
++ * @rw: READ(1) or WRITE(0)
++ * @sleep_ok: if true we may sleep while awaiting command completion
++ *
++ * Read/Write TP indirect registers through LDST if possible.
++ * Else, use backdoor access
++ **/
++static void t4_tp_indirect_rw(struct adapter *adap, u32 reg_addr, u32 reg_data,
++ u32 *buff, u32 nregs, u32 start_index, int rw,
++ bool sleep_ok)
++{
++ int rc = -EINVAL;
++ int cmd;
++
++ switch (reg_addr) {
++ case TP_PIO_ADDR_A:
++ cmd = FW_LDST_ADDRSPC_TP_PIO;
++ break;
++ case TP_MIB_INDEX_A:
++ cmd = FW_LDST_ADDRSPC_TP_MIB;
++ break;
++ default:
++ goto indirect_access;
++ }
++
++ if (t4_use_ldst(adap))
++ rc = t4_tp_fw_ldst_rw(adap, cmd, buff, nregs, start_index, rw,
++ sleep_ok);
++
++indirect_access:
++
++ if (rc) {
++ if (rw)
++ t4_read_indirect(adap, reg_addr, reg_data, buff, nregs,
++ start_index);
++ else
++ t4_write_indirect(adap, reg_addr, reg_data, buff, nregs,
++ start_index);
++ }
++}
++
++/**
++ * t4_tp_pio_read - Read TP PIO registers
++ * @adap: the adapter
++ * @buff: where the indirect register values are written
++ * @nregs: how many indirect registers to read
++ * @start_index: index of first indirect register to read
++ * @sleep_ok: if true we may sleep while awaiting command completion
++ *
++ * Read TP PIO Registers
++ **/
++void t4_tp_pio_read(struct adapter *adap, u32 *buff, u32 nregs,
++ u32 start_index, bool sleep_ok)
++{
++ t4_tp_indirect_rw(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, buff, nregs,
++ start_index, 1, sleep_ok);
++}
++
++/**
++ * t4_tp_pio_write - Write TP PIO registers
++ * @adap: the adapter
++ * @buff: where the indirect register values are stored
++ * @nregs: how many indirect registers to write
++ * @start_index: index of first indirect register to write
++ * @sleep_ok: if true we may sleep while awaiting command completion
++ *
++ * Write TP PIO Registers
++ **/
++static void t4_tp_pio_write(struct adapter *adap, u32 *buff, u32 nregs,
++ u32 start_index, bool sleep_ok)
++{
++ t4_tp_indirect_rw(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, buff, nregs,
++ start_index, 0, sleep_ok);
++}
++
++/**
++ * t4_tp_mib_read - Read TP MIB registers
++ * @adap: the adapter
++ * @buff: where the indirect register values are written
++ * @nregs: how many indirect registers to read
++ * @start_index: index of first indirect register to read
++ * @sleep_ok: if true we may sleep while awaiting command completion
++ *
++ * Read TP MIB Registers
++ **/
++void t4_tp_mib_read(struct adapter *adap, u32 *buff, u32 nregs, u32 start_index,
++ bool sleep_ok)
++{
++ t4_tp_indirect_rw(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, buff, nregs,
++ start_index, 1, sleep_ok);
+ }
+
+ /**
+ * t4_read_rss_key - read the global RSS key
+ * @adap: the adapter
+ * @key: 10-entry array holding the 320-bit RSS key
++ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Reads the global 320-bit RSS key.
+ */
+-void t4_read_rss_key(struct adapter *adap, u32 *key)
++void t4_read_rss_key(struct adapter *adap, u32 *key, bool sleep_ok)
+ {
+- if (t4_use_ldst(adap))
+- t4_fw_tp_pio_rw(adap, key, 10, TP_RSS_SECRET_KEY0_A, 1);
+- else
+- t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10,
+- TP_RSS_SECRET_KEY0_A);
++ t4_tp_pio_read(adap, key, 10, TP_RSS_SECRET_KEY0_A, sleep_ok);
+ }
+
+ /**
+@@ -5106,12 +5210,14 @@ void t4_read_rss_key(struct adapter *ada
+ * @adap: the adapter
+ * @key: 10-entry array holding the 320-bit RSS key
+ * @idx: which RSS key to write
++ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Writes one of the RSS keys with the given 320-bit value. If @idx is
+ * 0..15 the corresponding entry in the RSS key table is written,
+ * otherwise the global RSS key is written.
+ */
+-void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx)
++void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx,
++ bool sleep_ok)
+ {
+ u8 rss_key_addr_cnt = 16;
+ u32 vrt = t4_read_reg(adap, TP_RSS_CONFIG_VRT_A);
+@@ -5124,11 +5230,7 @@ void t4_write_rss_key(struct adapter *ad
+ (vrt & KEYEXTEND_F) && (KEYMODE_G(vrt) == 3))
+ rss_key_addr_cnt = 32;
+
+- if (t4_use_ldst(adap))
+- t4_fw_tp_pio_rw(adap, (void *)key, 10, TP_RSS_SECRET_KEY0_A, 0);
+- else
+- t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10,
+- TP_RSS_SECRET_KEY0_A);
++ t4_tp_pio_write(adap, (void *)key, 10, TP_RSS_SECRET_KEY0_A, sleep_ok);
+
+ if (idx >= 0 && idx < rss_key_addr_cnt) {
+ if (rss_key_addr_cnt > 16)
+@@ -5146,19 +5248,15 @@ void t4_write_rss_key(struct adapter *ad
+ * @adapter: the adapter
+ * @index: the entry in the PF RSS table to read
+ * @valp: where to store the returned value
++ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Reads the PF RSS Configuration Table at the specified index and returns
+ * the value found there.
+ */
+ void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index,
+- u32 *valp)
++ u32 *valp, bool sleep_ok)
+ {
+- if (t4_use_ldst(adapter))
+- t4_fw_tp_pio_rw(adapter, valp, 1,
+- TP_RSS_PF0_CONFIG_A + index, 1);
+- else
+- t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+- valp, 1, TP_RSS_PF0_CONFIG_A + index);
++ t4_tp_pio_read(adapter, valp, 1, TP_RSS_PF0_CONFIG_A + index, sleep_ok);
+ }
+
+ /**
+@@ -5167,12 +5265,13 @@ void t4_read_rss_pf_config(struct adapte
+ * @index: the entry in the VF RSS table to read
+ * @vfl: where to store the returned VFL
+ * @vfh: where to store the returned VFH
++ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Reads the VF RSS Configuration Table at the specified index and returns
+ * the (VFL, VFH) values found there.
+ */
+ void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index,
+- u32 *vfl, u32 *vfh)
++ u32 *vfl, u32 *vfh, bool sleep_ok)
+ {
+ u32 vrt, mask, data;
+
+@@ -5193,50 +5292,37 @@ void t4_read_rss_vf_config(struct adapte
+
+ /* Grab the VFL/VFH values ...
+ */
+- if (t4_use_ldst(adapter)) {
+- t4_fw_tp_pio_rw(adapter, vfl, 1, TP_RSS_VFL_CONFIG_A, 1);
+- t4_fw_tp_pio_rw(adapter, vfh, 1, TP_RSS_VFH_CONFIG_A, 1);
+- } else {
+- t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+- vfl, 1, TP_RSS_VFL_CONFIG_A);
+- t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+- vfh, 1, TP_RSS_VFH_CONFIG_A);
+- }
++ t4_tp_pio_read(adapter, vfl, 1, TP_RSS_VFL_CONFIG_A, sleep_ok);
++ t4_tp_pio_read(adapter, vfh, 1, TP_RSS_VFH_CONFIG_A, sleep_ok);
+ }
+
+ /**
+ * t4_read_rss_pf_map - read PF RSS Map
+ * @adapter: the adapter
++ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Reads the PF RSS Map register and returns its value.
+ */
+-u32 t4_read_rss_pf_map(struct adapter *adapter)
++u32 t4_read_rss_pf_map(struct adapter *adapter, bool sleep_ok)
+ {
+ u32 pfmap;
+
+- if (t4_use_ldst(adapter))
+- t4_fw_tp_pio_rw(adapter, &pfmap, 1, TP_RSS_PF_MAP_A, 1);
+- else
+- t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+- &pfmap, 1, TP_RSS_PF_MAP_A);
++ t4_tp_pio_read(adapter, &pfmap, 1, TP_RSS_PF_MAP_A, sleep_ok);
+ return pfmap;
+ }
+
+ /**
+ * t4_read_rss_pf_mask - read PF RSS Mask
+ * @adapter: the adapter
++ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Reads the PF RSS Mask register and returns its value.
+ */
+-u32 t4_read_rss_pf_mask(struct adapter *adapter)
++u32 t4_read_rss_pf_mask(struct adapter *adapter, bool sleep_ok)
+ {
+ u32 pfmask;
+
+- if (t4_use_ldst(adapter))
+- t4_fw_tp_pio_rw(adapter, &pfmask, 1, TP_RSS_PF_MSK_A, 1);
+- else
+- t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+- &pfmask, 1, TP_RSS_PF_MSK_A);
++ t4_tp_pio_read(adapter, &pfmask, 1, TP_RSS_PF_MSK_A, sleep_ok);
+ return pfmask;
+ }
+
+@@ -5245,12 +5331,13 @@ u32 t4_read_rss_pf_mask(struct adapter *
+ * @adap: the adapter
+ * @v4: holds the TCP/IP counter values
+ * @v6: holds the TCP/IPv6 counter values
++ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Returns the values of TP's TCP/IP and TCP/IPv6 MIB counters.
+ * Either @v4 or @v6 may be %NULL to skip the corresponding stats.
+ */
+ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
+- struct tp_tcp_stats *v6)
++ struct tp_tcp_stats *v6, bool sleep_ok)
+ {
+ u32 val[TP_MIB_TCP_RXT_SEG_LO_A - TP_MIB_TCP_OUT_RST_A + 1];
+
+@@ -5259,16 +5346,16 @@ void t4_tp_get_tcp_stats(struct adapter
+ #define STAT64(x) (((u64)STAT(x##_HI) << 32) | STAT(x##_LO))
+
+ if (v4) {
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val,
+- ARRAY_SIZE(val), TP_MIB_TCP_OUT_RST_A);
++ t4_tp_mib_read(adap, val, ARRAY_SIZE(val),
++ TP_MIB_TCP_OUT_RST_A, sleep_ok);
+ v4->tcp_out_rsts = STAT(OUT_RST);
+ v4->tcp_in_segs = STAT64(IN_SEG);
+ v4->tcp_out_segs = STAT64(OUT_SEG);
+ v4->tcp_retrans_segs = STAT64(RXT_SEG);
+ }
+ if (v6) {
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val,
+- ARRAY_SIZE(val), TP_MIB_TCP_V6OUT_RST_A);
++ t4_tp_mib_read(adap, val, ARRAY_SIZE(val),
++ TP_MIB_TCP_V6OUT_RST_A, sleep_ok);
+ v6->tcp_out_rsts = STAT(OUT_RST);
+ v6->tcp_in_segs = STAT64(IN_SEG);
+ v6->tcp_out_segs = STAT64(OUT_SEG);
+@@ -5283,63 +5370,66 @@ void t4_tp_get_tcp_stats(struct adapter
+ * t4_tp_get_err_stats - read TP's error MIB counters
+ * @adap: the adapter
+ * @st: holds the counter values
++ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Returns the values of TP's error counters.
+ */
+-void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st)
++void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st,
++ bool sleep_ok)
+ {
+ int nchan = adap->params.arch.nchan;
+
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+- st->mac_in_errs, nchan, TP_MIB_MAC_IN_ERR_0_A);
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+- st->hdr_in_errs, nchan, TP_MIB_HDR_IN_ERR_0_A);
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+- st->tcp_in_errs, nchan, TP_MIB_TCP_IN_ERR_0_A);
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+- st->tnl_cong_drops, nchan, TP_MIB_TNL_CNG_DROP_0_A);
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+- st->ofld_chan_drops, nchan, TP_MIB_OFD_CHN_DROP_0_A);
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+- st->tnl_tx_drops, nchan, TP_MIB_TNL_DROP_0_A);
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+- st->ofld_vlan_drops, nchan, TP_MIB_OFD_VLN_DROP_0_A);
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+- st->tcp6_in_errs, nchan, TP_MIB_TCP_V6IN_ERR_0_A);
+-
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+- &st->ofld_no_neigh, 2, TP_MIB_OFD_ARP_DROP_A);
++ t4_tp_mib_read(adap, st->mac_in_errs, nchan, TP_MIB_MAC_IN_ERR_0_A,
++ sleep_ok);
++ t4_tp_mib_read(adap, st->hdr_in_errs, nchan, TP_MIB_HDR_IN_ERR_0_A,
++ sleep_ok);
++ t4_tp_mib_read(adap, st->tcp_in_errs, nchan, TP_MIB_TCP_IN_ERR_0_A,
++ sleep_ok);
++ t4_tp_mib_read(adap, st->tnl_cong_drops, nchan,
++ TP_MIB_TNL_CNG_DROP_0_A, sleep_ok);
++ t4_tp_mib_read(adap, st->ofld_chan_drops, nchan,
++ TP_MIB_OFD_CHN_DROP_0_A, sleep_ok);
++ t4_tp_mib_read(adap, st->tnl_tx_drops, nchan, TP_MIB_TNL_DROP_0_A,
++ sleep_ok);
++ t4_tp_mib_read(adap, st->ofld_vlan_drops, nchan,
++ TP_MIB_OFD_VLN_DROP_0_A, sleep_ok);
++ t4_tp_mib_read(adap, st->tcp6_in_errs, nchan,
++ TP_MIB_TCP_V6IN_ERR_0_A, sleep_ok);
++ t4_tp_mib_read(adap, &st->ofld_no_neigh, 2, TP_MIB_OFD_ARP_DROP_A,
++ sleep_ok);
+ }
+
+ /**
+ * t4_tp_get_cpl_stats - read TP's CPL MIB counters
+ * @adap: the adapter
+ * @st: holds the counter values
++ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Returns the values of TP's CPL counters.
+ */
+-void t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st)
++void t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st,
++ bool sleep_ok)
+ {
+ int nchan = adap->params.arch.nchan;
+
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->req,
+- nchan, TP_MIB_CPL_IN_REQ_0_A);
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->rsp,
+- nchan, TP_MIB_CPL_OUT_RSP_0_A);
++ t4_tp_mib_read(adap, st->req, nchan, TP_MIB_CPL_IN_REQ_0_A, sleep_ok);
+
++ t4_tp_mib_read(adap, st->rsp, nchan, TP_MIB_CPL_OUT_RSP_0_A, sleep_ok);
+ }
+
+ /**
+ * t4_tp_get_rdma_stats - read TP's RDMA MIB counters
+ * @adap: the adapter
+ * @st: holds the counter values
++ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Returns the values of TP's RDMA counters.
+ */
+-void t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st)
++void t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st,
++ bool sleep_ok)
+ {
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, &st->rqe_dfr_pkt,
+- 2, TP_MIB_RQE_DFR_PKT_A);
++ t4_tp_mib_read(adap, &st->rqe_dfr_pkt, 2, TP_MIB_RQE_DFR_PKT_A,
++ sleep_ok);
+ }
+
+ /**
+@@ -5347,20 +5437,24 @@ void t4_tp_get_rdma_stats(struct adapter
+ * @adap: the adapter
+ * @idx: the port index
+ * @st: holds the counter values
++ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Returns the values of TP's FCoE counters for the selected port.
+ */
+ void t4_get_fcoe_stats(struct adapter *adap, unsigned int idx,
+- struct tp_fcoe_stats *st)
++ struct tp_fcoe_stats *st, bool sleep_ok)
+ {
+ u32 val[2];
+
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, &st->frames_ddp,
+- 1, TP_MIB_FCOE_DDP_0_A + idx);
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, &st->frames_drop,
+- 1, TP_MIB_FCOE_DROP_0_A + idx);
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val,
+- 2, TP_MIB_FCOE_BYTE_0_HI_A + 2 * idx);
++ t4_tp_mib_read(adap, &st->frames_ddp, 1, TP_MIB_FCOE_DDP_0_A + idx,
++ sleep_ok);
++
++ t4_tp_mib_read(adap, &st->frames_drop, 1,
++ TP_MIB_FCOE_DROP_0_A + idx, sleep_ok);
++
++ t4_tp_mib_read(adap, val, 2, TP_MIB_FCOE_BYTE_0_HI_A + 2 * idx,
++ sleep_ok);
++
+ st->octets_ddp = ((u64)val[0] << 32) | val[1];
+ }
+
+@@ -5368,15 +5462,16 @@ void t4_get_fcoe_stats(struct adapter *a
+ * t4_get_usm_stats - read TP's non-TCP DDP MIB counters
+ * @adap: the adapter
+ * @st: holds the counter values
++ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Returns the values of TP's counters for non-TCP directly-placed packets.
+ */
+-void t4_get_usm_stats(struct adapter *adap, struct tp_usm_stats *st)
++void t4_get_usm_stats(struct adapter *adap, struct tp_usm_stats *st,
++ bool sleep_ok)
+ {
+ u32 val[4];
+
+- t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val, 4,
+- TP_MIB_USM_PKTS_A);
++ t4_tp_mib_read(adap, val, 4, TP_MIB_USM_PKTS_A, sleep_ok);
+ st->frames = val[0];
+ st->drops = val[1];
+ st->octets = ((u64)val[2] << 32) | val[3];
+@@ -8663,10 +8758,11 @@ int t4_init_sge_params(struct adapter *a
+ /**
+ * t4_init_tp_params - initialize adap->params.tp
+ * @adap: the adapter
++ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Initialize various fields of the adapter's TP Parameters structure.
+ */
+-int t4_init_tp_params(struct adapter *adap)
++int t4_init_tp_params(struct adapter *adap, bool sleep_ok)
+ {
+ int chan;
+ u32 v;
+@@ -8682,19 +8778,11 @@ int t4_init_tp_params(struct adapter *ad
+ /* Cache the adapter's Compressed Filter Mode and global Incress
+ * Configuration.
+ */
+- if (t4_use_ldst(adap)) {
+- t4_fw_tp_pio_rw(adap, &adap->params.tp.vlan_pri_map, 1,
+- TP_VLAN_PRI_MAP_A, 1);
+- t4_fw_tp_pio_rw(adap, &adap->params.tp.ingress_config, 1,
+- TP_INGRESS_CONFIG_A, 1);
+- } else {
+- t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+- &adap->params.tp.vlan_pri_map, 1,
+- TP_VLAN_PRI_MAP_A);
+- t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+- &adap->params.tp.ingress_config, 1,
+- TP_INGRESS_CONFIG_A);
+- }
++ t4_tp_pio_read(adap, &adap->params.tp.vlan_pri_map, 1,
++ TP_VLAN_PRI_MAP_A, sleep_ok);
++ t4_tp_pio_read(adap, &adap->params.tp.ingress_config, 1,
++ TP_INGRESS_CONFIG_A, sleep_ok);
++
+ /* For T6, cache the adapter's compressed error vector
+ * and passing outer header info for encapsulated packets.
+ */
diff --git a/patches.drivers/cxgb4vf-define-get_fecparam-ethtool-callback.patch b/patches.drivers/cxgb4vf-define-get_fecparam-ethtool-callback.patch
new file mode 100644
index 0000000000..e5fbda9754
--- /dev/null
+++ b/patches.drivers/cxgb4vf-define-get_fecparam-ethtool-callback.patch
@@ -0,0 +1,92 @@
+From: Ganesh Goudar <ganeshgr@chelsio.com>
+Date: Thu, 2 Nov 2017 19:28:20 +0530
+Subject: cxgb4vf: define get_fecparam ethtool callback
+Patch-mainline: v4.15-rc1
+Git-commit: 9a7b96b3462679a2fcf7205d396dbf1f8f28454c
+References: bsc#1064802 bsc#1066129
+
+Add support to new ethtool operation get_fecparam to
+fetch FEC parameters.
+
+Original Work by: Casey Leedom <leedom@chelsio.com>
+Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c | 58 ++++++++++++++++++++
+ 1 file changed, 58 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
+@@ -1401,6 +1401,63 @@ static int cxgb4vf_get_link_ksettings(st
+ return 0;
+ }
+
++/* Translate the Firmware FEC value into the ethtool value. */
++static inline unsigned int fwcap_to_eth_fec(unsigned int fw_fec)
++{
++ unsigned int eth_fec = 0;
++
++ if (fw_fec & FW_PORT_CAP32_FEC_RS)
++ eth_fec |= ETHTOOL_FEC_RS;
++ if (fw_fec & FW_PORT_CAP32_FEC_BASER_RS)
++ eth_fec |= ETHTOOL_FEC_BASER;
++
++ /* if nothing is set, then FEC is off */
++ if (!eth_fec)
++ eth_fec = ETHTOOL_FEC_OFF;
++
++ return eth_fec;
++}
++
++/* Translate Common Code FEC value into ethtool value. */
++static inline unsigned int cc_to_eth_fec(unsigned int cc_fec)
++{
++ unsigned int eth_fec = 0;
++
++ if (cc_fec & FEC_AUTO)
++ eth_fec |= ETHTOOL_FEC_AUTO;
++ if (cc_fec & FEC_RS)
++ eth_fec |= ETHTOOL_FEC_RS;
++ if (cc_fec & FEC_BASER_RS)
++ eth_fec |= ETHTOOL_FEC_BASER;
++
++ /* if nothing is set, then FEC is off */
++ if (!eth_fec)
++ eth_fec = ETHTOOL_FEC_OFF;
++
++ return eth_fec;
++}
++
++static int cxgb4vf_get_fecparam(struct net_device *dev,
++ struct ethtool_fecparam *fec)
++{
++ const struct port_info *pi = netdev_priv(dev);
++ const struct link_config *lc = &pi->link_cfg;
++
++ /* Translate the Firmware FEC Support into the ethtool value. We
++ * always support IEEE 802.3 "automatic" selection of Link FEC type if
++ * any FEC is supported.
++ */
++ fec->fec = fwcap_to_eth_fec(lc->pcaps);
++ if (fec->fec != ETHTOOL_FEC_OFF)
++ fec->fec |= ETHTOOL_FEC_AUTO;
++
++ /* Translate the current internal FEC parameters into the
++ * ethtool values.
++ */
++ fec->active_fec = cc_to_eth_fec(lc->fec);
++ return 0;
++}
++
+ /*
+ * Return our driver information.
+ */
+@@ -1774,6 +1831,7 @@ static void cxgb4vf_get_wol(struct net_d
+
+ static const struct ethtool_ops cxgb4vf_ethtool_ops = {
+ .get_link_ksettings = cxgb4vf_get_link_ksettings,
++ .get_fecparam = cxgb4vf_get_fecparam,
+ .get_drvinfo = cxgb4vf_get_drvinfo,
+ .get_msglevel = cxgb4vf_get_msglevel,
+ .set_msglevel = cxgb4vf_set_msglevel,
diff --git a/patches.drivers/cxgb4vf-make-a-couple-of-functions-static.patch b/patches.drivers/cxgb4vf-make-a-couple-of-functions-static.patch
new file mode 100644
index 0000000000..1525367838
--- /dev/null
+++ b/patches.drivers/cxgb4vf-make-a-couple-of-functions-static.patch
@@ -0,0 +1,44 @@
+From: Colin Ian King <colin.king@canonical.com>
+Date: Wed, 4 Oct 2017 14:20:37 +0100
+Subject: cxgb4vf: make a couple of functions static
+Patch-mainline: v4.15-rc1
+Git-commit: ebf6b13142f947be576b40edce214788dfe1d3e3
+References: bsc#1064802 bsc#1066129
+
+The functions t4vf_link_down_rc_str and t4vf_handle_get_port_info are
+local to the source and do not need to be in global scope, so make
+them static.
+
+Cleans up sparse warnings:
+symbol 't4vf_link_down_rc_str' was not declared. Should it be static?
+symbol 't4vf_handle_get_port_info' was not declared. Should it be static?
+
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
++++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
+@@ -1812,7 +1812,7 @@ int t4vf_eth_eq_free(struct adapter *ada
+ *
+ * Returns a string representation of the Link Down Reason Code.
+ */
+-const char *t4vf_link_down_rc_str(unsigned char link_down_rc)
++static const char *t4vf_link_down_rc_str(unsigned char link_down_rc)
+ {
+ static const char * const reason[] = {
+ "Link Down",
+@@ -1838,8 +1838,8 @@ const char *t4vf_link_down_rc_str(unsign
+ *
+ * Processes a GET_PORT_INFO FW reply message.
+ */
+-void t4vf_handle_get_port_info(struct port_info *pi,
+- const struct fw_port_cmd *cmd)
++static void t4vf_handle_get_port_info(struct port_info *pi,
++ const struct fw_port_cmd *cmd)
+ {
+ int action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16));
+ struct adapter *adapter = pi->adapter;
diff --git a/patches.drivers/iw_cxgb4-Fix-possible-circular-dependency-locking-wa.patch b/patches.drivers/iw_cxgb4-Fix-possible-circular-dependency-locking-wa.patch
new file mode 100644
index 0000000000..fdac1a4b2a
--- /dev/null
+++ b/patches.drivers/iw_cxgb4-Fix-possible-circular-dependency-locking-wa.patch
@@ -0,0 +1,211 @@
+From: Bharat Potnuri <bharat@chelsio.com>
+Date: Thu, 9 Nov 2017 17:47:33 +0530
+Subject: iw_cxgb4: Fix possible circular dependency locking warning
+Patch-mainline: v4.15-rc1
+Git-commit: 1c8f1da5d851b92aeb81dbbb9ebd516f6e2588f5
+References: bsc#1064802 bsc#1066129
+
+Locking sequence of iw_cxgb4 and RoCE drivers in ib_register_device() is
+slightly different and this leads to possible circular dependency locking
+warning when both the devices are brought up.
+
+Here is the locking sequence upto ib_register_device():
+iw_cxgb4: rtnl_mutex(net stack) --> uld_mutex --> device_mutex
+RoCE drivers: device_mutex --> rtnl_mutex
+
+Here is the possibility of cross locking:
+
+ CPU #0 (iw_cxgb4) CPU #1 (RoCE drivers)
+
+-> on interface up cxgb4_up()
+executed with rtnl_mutex held
+-> hold uld_mutex and try
+registering ib device
+ -> In ib_register_device() hold
+ device_mutex
+-> hold device mutex in
+ib_register_device
+ -> try acquiring rtnl_mutex in
+ ib_enum_roce_netdev()
+
+Current patch schedules the ib_register_device() functionality of
+iw_cxgb4 to a workqueue to prevent the possible cross-locking.
+Also rename the labels in c4iw_reister_device().
+
+Signed-off-by: Potnuri Bharat Teja <bharat@chelsio.com>
+Reviewed-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/device.c | 28 +++++++++++++---------------
+ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 10 +++++++++-
+ drivers/infiniband/hw/cxgb4/provider.c | 26 +++++++++++++++++---------
+ 3 files changed, 39 insertions(+), 25 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/device.c
++++ b/drivers/infiniband/hw/cxgb4/device.c
+@@ -64,14 +64,9 @@ module_param(c4iw_wr_log_size_order, int
+ MODULE_PARM_DESC(c4iw_wr_log_size_order,
+ "Number of entries (log2) in the work request timing log.");
+
+-struct uld_ctx {
+- struct list_head entry;
+- struct cxgb4_lld_info lldi;
+- struct c4iw_dev *dev;
+-};
+-
+ static LIST_HEAD(uld_ctx_list);
+ static DEFINE_MUTEX(dev_mutex);
++struct workqueue_struct *reg_workq;
+
+ #define DB_FC_RESUME_SIZE 64
+ #define DB_FC_RESUME_DELAY 1
+@@ -912,7 +907,7 @@ static void c4iw_rdev_close(struct c4iw_
+ c4iw_destroy_resource(&rdev->resource);
+ }
+
+-static void c4iw_dealloc(struct uld_ctx *ctx)
++void c4iw_dealloc(struct uld_ctx *ctx)
+ {
+ c4iw_rdev_close(&ctx->dev->rdev);
+ WARN_ON_ONCE(!idr_is_empty(&ctx->dev->cqidr));
+@@ -1208,8 +1203,6 @@ static int c4iw_uld_state_change(void *h
+ case CXGB4_STATE_UP:
+ pr_info("%s: Up\n", pci_name(ctx->lldi.pdev));
+ if (!ctx->dev) {
+- int ret;
+-
+ ctx->dev = c4iw_alloc(&ctx->lldi);
+ if (IS_ERR(ctx->dev)) {
+ pr_err("%s: initialization failed: %ld\n",
+@@ -1218,12 +1211,9 @@ static int c4iw_uld_state_change(void *h
+ ctx->dev = NULL;
+ break;
+ }
+- ret = c4iw_register_device(ctx->dev);
+- if (ret) {
+- pr_err("%s: RDMA registration failed: %d\n",
+- pci_name(ctx->lldi.pdev), ret);
+- c4iw_dealloc(ctx);
+- }
++
++ INIT_WORK(&ctx->reg_work, c4iw_register_device);
++ queue_work(reg_workq, &ctx->reg_work);
+ }
+ break;
+ case CXGB4_STATE_DOWN:
+@@ -1551,6 +1541,12 @@ static int __init c4iw_init_module(void)
+ if (!c4iw_debugfs_root)
+ pr_warn("could not create debugfs entry, continuing\n");
+
++ reg_workq = create_singlethread_workqueue("Register_iWARP_device");
++ if (!reg_workq) {
++ pr_err("Failed creating workqueue to register iwarp device\n");
++ return -ENOMEM;
++ }
++
+ cxgb4_register_uld(CXGB4_ULD_RDMA, &c4iw_uld_info);
+
+ return 0;
+@@ -1567,6 +1563,8 @@ static void __exit c4iw_exit_module(void
+ kfree(ctx);
+ }
+ mutex_unlock(&dev_mutex);
++ flush_workqueue(reg_workq);
++ destroy_workqueue(reg_workq);
+ cxgb4_unregister_uld(CXGB4_ULD_RDMA);
+ c4iw_cm_term();
+ debugfs_remove_recursive(c4iw_debugfs_root);
+--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+@@ -322,6 +322,13 @@ struct c4iw_dev {
+ wait_queue_head_t wait;
+ };
+
++struct uld_ctx {
++ struct list_head entry;
++ struct cxgb4_lld_info lldi;
++ struct c4iw_dev *dev;
++ struct work_struct reg_work;
++};
++
+ static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev)
+ {
+ return container_of(ibdev, struct c4iw_dev, ibdev);
+@@ -989,7 +996,7 @@ void c4iw_rqtpool_destroy(struct c4iw_rd
+ void c4iw_ocqp_pool_destroy(struct c4iw_rdev *rdev);
+ void c4iw_destroy_resource(struct c4iw_resource *rscp);
+ int c4iw_destroy_ctrl_qp(struct c4iw_rdev *rdev);
+-int c4iw_register_device(struct c4iw_dev *dev);
++void c4iw_register_device(struct work_struct *work);
+ void c4iw_unregister_device(struct c4iw_dev *dev);
+ int __init c4iw_cm_init(void);
+ void c4iw_cm_term(void);
+@@ -1015,6 +1022,7 @@ struct ib_mr *c4iw_alloc_mr(struct ib_pd
+ int c4iw_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
+ unsigned int *sg_offset);
+ int c4iw_dealloc_mw(struct ib_mw *mw);
++void c4iw_dealloc(struct uld_ctx *ctx);
+ struct ib_mw *c4iw_alloc_mw(struct ib_pd *pd, enum ib_mw_type type,
+ struct ib_udata *udata);
+ struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start,
+--- a/drivers/infiniband/hw/cxgb4/provider.c
++++ b/drivers/infiniband/hw/cxgb4/provider.c
+@@ -531,10 +531,12 @@ static void get_dev_fw_str(struct ib_dev
+ FW_HDR_FW_VER_BUILD_G(c4iw_dev->rdev.lldi.fw_vers));
+ }
+
+-int c4iw_register_device(struct c4iw_dev *dev)
++void c4iw_register_device(struct work_struct *work)
+ {
+ int ret;
+ int i;
++ struct uld_ctx *ctx = container_of(work, struct uld_ctx, reg_work);
++ struct c4iw_dev *dev = ctx->dev;
+
+ pr_debug("c4iw_dev %p\n", dev);
+ strlcpy(dev->ibdev.name, "cxgb4_%d", IB_DEVICE_NAME_MAX);
+@@ -609,8 +611,10 @@ int c4iw_register_device(struct c4iw_dev
+ dev->ibdev.get_dev_fw_str = get_dev_fw_str;
+
+ dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL);
+- if (!dev->ibdev.iwcm)
+- return -ENOMEM;
++ if (!dev->ibdev.iwcm) {
++ ret = -ENOMEM;
++ goto err_dealloc_ctx;
++ }
+
+ dev->ibdev.iwcm->connect = c4iw_connect;
+ dev->ibdev.iwcm->accept = c4iw_accept_cr;
+@@ -625,20 +629,24 @@ int c4iw_register_device(struct c4iw_dev
+
+ ret = ib_register_device(&dev->ibdev, NULL);
+ if (ret)
+- goto bail1;
++ goto err_kfree_iwcm;
+
+ for (i = 0; i < ARRAY_SIZE(c4iw_class_attributes); ++i) {
+ ret = device_create_file(&dev->ibdev.dev,
+ c4iw_class_attributes[i]);
+ if (ret)
+- goto bail2;
++ goto err_unregister_device;
+ }
+- return 0;
+-bail2:
++ return;
++err_unregister_device:
+ ib_unregister_device(&dev->ibdev);
+-bail1:
++err_kfree_iwcm:
+ kfree(dev->ibdev.iwcm);
+- return ret;
++err_dealloc_ctx:
++ pr_err("%s - Failed registering iwarp device: %d\n",
++ pci_name(ctx->lldi.pdev), ret);
++ c4iw_dealloc(ctx);
++ return;
+ }
+
+ void c4iw_unregister_device(struct c4iw_dev *dev)
diff --git a/patches.drivers/iw_cxgb4-Remove-__func__-parameter-from-pr_debug.patch b/patches.drivers/iw_cxgb4-Remove-__func__-parameter-from-pr_debug.patch
new file mode 100644
index 0000000000..6c70c329b3
--- /dev/null
+++ b/patches.drivers/iw_cxgb4-Remove-__func__-parameter-from-pr_debug.patch
@@ -0,0 +1,1673 @@
+From: Bharat Potnuri <bharat@chelsio.com>
+Date: Wed, 27 Sep 2017 13:05:49 +0530
+Subject: iw_cxgb4: Remove __func__ parameter from pr_debug()
+Patch-mainline: v4.15-rc1
+Git-commit: 548ddb19afbabf8f7af7a900c19d0f0705d6dc90
+References: bsc#1064802 bsc#1066129
+
+pr_debug() can be enabled to print function names, So removing the
+unwanted __func__ parameters from debug logs.
+Realign function parameters.
+
+Signed-off-by: Potnuri Bharat Teja <bharat@chelsio.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 198 ++++++++++++++++-----------------
+ drivers/infiniband/hw/cxgb4/cq.c | 50 ++++----
+ drivers/infiniband/hw/cxgb4/device.c | 16 +-
+ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 13 --
+ drivers/infiniband/hw/cxgb4/mem.c | 26 ++--
+ drivers/infiniband/hw/cxgb4/provider.c | 36 +++---
+ drivers/infiniband/hw/cxgb4/qp.c | 55 ++++-----
+ drivers/infiniband/hw/cxgb4/resource.c | 46 +++----
+ drivers/infiniband/hw/cxgb4/t4.h | 12 --
+ 9 files changed, 217 insertions(+), 235 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -180,7 +180,7 @@ static void ref_qp(struct c4iw_ep *ep)
+
+ static void start_ep_timer(struct c4iw_ep *ep)
+ {
+- pr_debug("%s ep %p\n", __func__, ep);
++ pr_debug("ep %p\n", ep);
+ if (timer_pending(&ep->timer)) {
+ pr_err("%s timer already started! ep %p\n",
+ __func__, ep);
+@@ -196,7 +196,7 @@ static void start_ep_timer(struct c4iw_e
+
+ static int stop_ep_timer(struct c4iw_ep *ep)
+ {
+- pr_debug("%s ep %p stopping\n", __func__, ep);
++ pr_debug("ep %p stopping\n", ep);
+ del_timer_sync(&ep->timer);
+ if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) {
+ c4iw_put_ep(&ep->com);
+@@ -265,8 +265,8 @@ static void set_emss(struct c4iw_ep *ep,
+ if (ep->emss & 7)
+ pr_debug("Warning: misaligned mtu idx %u mss %u emss=%u\n",
+ TCPOPT_MSS_G(opt), ep->mss, ep->emss);
+- pr_debug("%s mss_idx %u mss %u emss=%u\n", __func__, TCPOPT_MSS_G(opt),
+- ep->mss, ep->emss);
++ pr_debug("mss_idx %u mss %u emss=%u\n", TCPOPT_MSS_G(opt), ep->mss,
++ ep->emss);
+ }
+
+ static enum c4iw_ep_state state_read(struct c4iw_ep_common *epc)
+@@ -287,7 +287,7 @@ static void __state_set(struct c4iw_ep_c
+ static void state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state new)
+ {
+ mutex_lock(&epc->mutex);
+- pr_debug("%s - %s -> %s\n", __func__, states[epc->state], states[new]);
++ pr_debug("%s -> %s\n", states[epc->state], states[new]);
+ __state_set(epc, new);
+ mutex_unlock(&epc->mutex);
+ return;
+@@ -322,7 +322,7 @@ static void *alloc_ep(int size, gfp_t gf
+ mutex_init(&epc->mutex);
+ c4iw_init_wr_wait(&epc->wr_wait);
+ }
+- pr_debug("%s alloc ep %p\n", __func__, epc);
++ pr_debug("alloc ep %p\n", epc);
+ return epc;
+ }
+
+@@ -384,7 +384,7 @@ void _c4iw_free_ep(struct kref *kref)
+ struct c4iw_ep *ep;
+
+ ep = container_of(kref, struct c4iw_ep, com.kref);
+- pr_debug("%s ep %p state %s\n", __func__, ep, states[ep->com.state]);
++ pr_debug("ep %p state %s\n", ep, states[ep->com.state]);
+ if (test_bit(QP_REFERENCED, &ep->com.flags))
+ deref_qp(ep);
+ if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) {
+@@ -570,7 +570,7 @@ static void abort_arp_failure(void *hand
+ struct c4iw_rdev *rdev = &ep->com.dev->rdev;
+ struct cpl_abort_req *req = cplhdr(skb);
+
+- pr_debug("%s rdev %p\n", __func__, rdev);
++ pr_debug("rdev %p\n", rdev);
+ req->cmd = CPL_ABORT_NO_RST;
+ skb_get(skb);
+ ret = c4iw_ofld_send(rdev, skb);
+@@ -647,7 +647,7 @@ static int send_halfclose(struct c4iw_ep
+ struct sk_buff *skb = skb_dequeue(&ep->com.ep_skb_list);
+ u32 wrlen = roundup(sizeof(struct cpl_close_con_req), 16);
+
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+ if (WARN_ON(!skb))
+ return -ENOMEM;
+
+@@ -662,7 +662,7 @@ static int send_abort(struct c4iw_ep *ep
+ u32 wrlen = roundup(sizeof(struct cpl_abort_req), 16);
+ struct sk_buff *req_skb = skb_dequeue(&ep->com.ep_skb_list);
+
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+ if (WARN_ON(!req_skb))
+ return -ENOMEM;
+
+@@ -725,7 +725,7 @@ static int send_connect(struct c4iw_ep *
+ roundup(sizev4, 16) :
+ roundup(sizev6, 16);
+
+- pr_debug("%s ep %p atid %u\n", __func__, ep, ep->atid);
++ pr_debug("ep %p atid %u\n", ep, ep->atid);
+
+ skb = get_skb(NULL, wrlen, GFP_KERNEL);
+ if (!skb) {
+@@ -824,13 +824,13 @@ static int send_connect(struct c4iw_ep *
+ t5req->params =
+ cpu_to_be64(FILTER_TUPLE_V(params));
+ t5req->rsvd = cpu_to_be32(isn);
+- pr_debug("%s snd_isn %u\n", __func__, t5req->rsvd);
++ pr_debug("snd_isn %u\n", t5req->rsvd);
+ t5req->opt2 = cpu_to_be32(opt2);
+ } else {
+ t6req->params =
+ cpu_to_be64(FILTER_TUPLE_V(params));
+ t6req->rsvd = cpu_to_be32(isn);
+- pr_debug("%s snd_isn %u\n", __func__, t6req->rsvd);
++ pr_debug("snd_isn %u\n", t6req->rsvd);
+ t6req->opt2 = cpu_to_be32(opt2);
+ }
+ }
+@@ -877,13 +877,13 @@ static int send_connect(struct c4iw_ep *
+ t5req6->params =
+ cpu_to_be64(FILTER_TUPLE_V(params));
+ t5req6->rsvd = cpu_to_be32(isn);
+- pr_debug("%s snd_isn %u\n", __func__, t5req6->rsvd);
++ pr_debug("snd_isn %u\n", t5req6->rsvd);
+ t5req6->opt2 = cpu_to_be32(opt2);
+ } else {
+ t6req6->params =
+ cpu_to_be64(FILTER_TUPLE_V(params));
+ t6req6->rsvd = cpu_to_be32(isn);
+- pr_debug("%s snd_isn %u\n", __func__, t6req6->rsvd);
++ pr_debug("snd_isn %u\n", t6req6->rsvd);
+ t6req6->opt2 = cpu_to_be32(opt2);
+ }
+
+@@ -907,8 +907,8 @@ static int send_mpa_req(struct c4iw_ep *
+ struct mpa_message *mpa;
+ struct mpa_v2_conn_params mpa_v2_params;
+
+- pr_debug("%s ep %p tid %u pd_len %d\n",
+- __func__, ep, ep->hwtid, ep->plen);
++ pr_debug("ep %p tid %u pd_len %d\n",
++ ep, ep->hwtid, ep->plen);
+
+ BUG_ON(skb_cloned(skb));
+
+@@ -961,7 +961,7 @@ static int send_mpa_req(struct c4iw_ep *
+ if (mpa_rev_to_use == 2) {
+ mpa->private_data_size = htons(ntohs(mpa->private_data_size) +
+ sizeof (struct mpa_v2_conn_params));
+- pr_debug("%s initiator ird %u ord %u\n", __func__, ep->ird,
++ pr_debug("initiator ird %u ord %u\n", ep->ird,
+ ep->ord);
+ mpa_v2_params.ird = htons((u16)ep->ird);
+ mpa_v2_params.ord = htons((u16)ep->ord);
+@@ -1014,8 +1014,8 @@ static int send_mpa_reject(struct c4iw_e
+ struct sk_buff *skb;
+ struct mpa_v2_conn_params mpa_v2_params;
+
+- pr_debug("%s ep %p tid %u pd_len %d\n",
+- __func__, ep, ep->hwtid, ep->plen);
++ pr_debug("ep %p tid %u pd_len %d\n",
++ ep, ep->hwtid, ep->plen);
+
+ mpalen = sizeof(*mpa) + plen;
+ if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn)
+@@ -1094,8 +1094,8 @@ static int send_mpa_reply(struct c4iw_ep
+ struct sk_buff *skb;
+ struct mpa_v2_conn_params mpa_v2_params;
+
+- pr_debug("%s ep %p tid %u pd_len %d\n",
+- __func__, ep, ep->hwtid, ep->plen);
++ pr_debug("ep %p tid %u pd_len %d\n",
++ ep, ep->hwtid, ep->plen);
+
+ mpalen = sizeof(*mpa) + plen;
+ if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn)
+@@ -1185,7 +1185,7 @@ static int act_establish(struct c4iw_dev
+
+ ep = lookup_atid(t, atid);
+
+- pr_debug("%s ep %p tid %u snd_isn %u rcv_isn %u\n", __func__, ep, tid,
++ pr_debug("ep %p tid %u snd_isn %u rcv_isn %u\n", ep, tid,
+ be32_to_cpu(req->snd_isn), be32_to_cpu(req->rcv_isn));
+
+ mutex_lock(&ep->com.mutex);
+@@ -1229,7 +1229,7 @@ static void close_complete_upcall(struct
+ {
+ struct iw_cm_event event;
+
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+ memset(&event, 0, sizeof(event));
+ event.event = IW_CM_EVENT_CLOSE;
+ event.status = status;
+@@ -1246,7 +1246,7 @@ static void peer_close_upcall(struct c4i
+ {
+ struct iw_cm_event event;
+
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+ memset(&event, 0, sizeof(event));
+ event.event = IW_CM_EVENT_DISCONNECT;
+ if (ep->com.cm_id) {
+@@ -1261,7 +1261,7 @@ static void peer_abort_upcall(struct c4i
+ {
+ struct iw_cm_event event;
+
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+ memset(&event, 0, sizeof(event));
+ event.event = IW_CM_EVENT_CLOSE;
+ event.status = -ECONNRESET;
+@@ -1278,8 +1278,8 @@ static void connect_reply_upcall(struct
+ {
+ struct iw_cm_event event;
+
+- pr_debug("%s ep %p tid %u status %d\n",
+- __func__, ep, ep->hwtid, status);
++ pr_debug("ep %p tid %u status %d\n",
++ ep, ep->hwtid, status);
+ memset(&event, 0, sizeof(event));
+ event.event = IW_CM_EVENT_CONNECT_REPLY;
+ event.status = status;
+@@ -1308,7 +1308,7 @@ static void connect_reply_upcall(struct
+ }
+ }
+
+- pr_debug("%s ep %p tid %u status %d\n", __func__, ep,
++ pr_debug("ep %p tid %u status %d\n", ep,
+ ep->hwtid, status);
+ set_bit(CONN_RPL_UPCALL, &ep->com.history);
+ ep->com.cm_id->event_handler(ep->com.cm_id, &event);
+@@ -1322,7 +1322,7 @@ static int connect_request_upcall(struct
+ struct iw_cm_event event;
+ int ret;
+
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+ memset(&event, 0, sizeof(event));
+ event.event = IW_CM_EVENT_CONNECT_REQUEST;
+ memcpy(&event.local_addr, &ep->com.local_addr,
+@@ -1359,13 +1359,13 @@ static void established_upcall(struct c4
+ {
+ struct iw_cm_event event;
+
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+ memset(&event, 0, sizeof(event));
+ event.event = IW_CM_EVENT_ESTABLISHED;
+ event.ird = ep->ord;
+ event.ord = ep->ird;
+ if (ep->com.cm_id) {
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+ ep->com.cm_id->event_handler(ep->com.cm_id, &event);
+ set_bit(ESTAB_UPCALL, &ep->com.history);
+ }
+@@ -1377,8 +1377,8 @@ static int update_rx_credits(struct c4iw
+ u32 wrlen = roundup(sizeof(struct cpl_rx_data_ack), 16);
+ u32 credit_dack;
+
+- pr_debug("%s ep %p tid %u credits %u\n",
+- __func__, ep, ep->hwtid, credits);
++ pr_debug("ep %p tid %u credits %u\n",
++ ep, ep->hwtid, credits);
+ skb = get_skb(NULL, wrlen, GFP_KERNEL);
+ if (!skb) {
+ pr_err("update_rx_credits - cannot alloc skb!\n");
+@@ -1429,7 +1429,7 @@ static int process_mpa_reply(struct c4iw
+ int err;
+ int disconnect = 0;
+
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+
+ /*
+ * If we get more than the supported amount of private data
+@@ -1527,8 +1527,7 @@ static int process_mpa_reply(struct c4iw
+ MPA_V2_IRD_ORD_MASK;
+ resp_ord = ntohs(mpa_v2_params->ord) &
+ MPA_V2_IRD_ORD_MASK;
+- pr_debug("%s responder ird %u ord %u ep ird %u ord %u\n",
+- __func__,
++ pr_debug("responder ird %u ord %u ep ird %u ord %u\n",
+ resp_ird, resp_ord, ep->ird, ep->ord);
+
+ /*
+@@ -1573,8 +1572,8 @@ static int process_mpa_reply(struct c4iw
+ if (peer2peer)
+ ep->mpa_attr.p2p_type = p2p_type;
+
+- pr_debug("%s - crc_enabled=%d, recv_marker_enabled=%d, xmit_marker_enabled=%d, version=%d p2p_type=%d local-p2p_type = %d\n",
+- __func__, ep->mpa_attr.crc_enabled,
++ pr_debug("crc_enabled=%d, recv_marker_enabled=%d, xmit_marker_enabled=%d, version=%d p2p_type=%d local-p2p_type = %d\n",
++ ep->mpa_attr.crc_enabled,
+ ep->mpa_attr.recv_marker_enabled,
+ ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version,
+ ep->mpa_attr.p2p_type, p2p_type);
+@@ -1670,7 +1669,7 @@ static int process_mpa_request(struct c4
+ struct mpa_v2_conn_params *mpa_v2_params;
+ u16 plen;
+
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+
+ /*
+ * If we get more than the supported amount of private data
+@@ -1679,7 +1678,7 @@ static int process_mpa_request(struct c4
+ if (ep->mpa_pkt_len + skb->len > sizeof(ep->mpa_pkt))
+ goto err_stop_timer;
+
+- pr_debug("%s enter (%s line %u)\n", __func__, __FILE__, __LINE__);
++ pr_debug("enter (%s line %u)\n", __FILE__, __LINE__);
+
+ /*
+ * Copy the new data into our accumulation buffer.
+@@ -1695,7 +1694,7 @@ static int process_mpa_request(struct c4
+ if (ep->mpa_pkt_len < sizeof(*mpa))
+ return 0;
+
+- pr_debug("%s enter (%s line %u)\n", __func__, __FILE__, __LINE__);
++ pr_debug("enter (%s line %u)\n", __FILE__, __LINE__);
+ mpa = (struct mpa_message *) ep->mpa_pkt;
+
+ /*
+@@ -1758,8 +1757,8 @@ static int process_mpa_request(struct c4
+ MPA_V2_IRD_ORD_MASK;
+ ep->ord = min_t(u32, ep->ord,
+ cur_max_read_depth(ep->com.dev));
+- pr_debug("%s initiator ird %u ord %u\n",
+- __func__, ep->ird, ep->ord);
++ pr_debug("initiator ird %u ord %u\n",
++ ep->ird, ep->ord);
+ if (ntohs(mpa_v2_params->ird) & MPA_V2_PEER2PEER_MODEL)
+ if (peer2peer) {
+ if (ntohs(mpa_v2_params->ord) &
+@@ -1776,8 +1775,7 @@ static int process_mpa_request(struct c4
+ if (peer2peer)
+ ep->mpa_attr.p2p_type = p2p_type;
+
+- pr_debug("%s - crc_enabled=%d, recv_marker_enabled=%d, xmit_marker_enabled=%d, version=%d p2p_type=%d\n",
+- __func__,
++ pr_debug("crc_enabled=%d, recv_marker_enabled=%d, xmit_marker_enabled=%d, version=%d p2p_type=%d\n",
+ ep->mpa_attr.crc_enabled, ep->mpa_attr.recv_marker_enabled,
+ ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version,
+ ep->mpa_attr.p2p_type);
+@@ -1816,7 +1814,7 @@ static int rx_data(struct c4iw_dev *dev,
+ ep = get_ep_from_tid(dev, tid);
+ if (!ep)
+ return 0;
+- pr_debug("%s ep %p tid %u dlen %u\n", __func__, ep, ep->hwtid, dlen);
++ pr_debug("ep %p tid %u dlen %u\n", ep, ep->hwtid, dlen);
+ skb_pull(skb, sizeof(*hdr));
+ skb_trim(skb, dlen);
+ mutex_lock(&ep->com.mutex);
+@@ -1870,7 +1868,7 @@ static int abort_rpl(struct c4iw_dev *de
+ pr_warn("Abort rpl to freed endpoint\n");
+ return 0;
+ }
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+ mutex_lock(&ep->com.mutex);
+ switch (ep->com.state) {
+ case ABORTING:
+@@ -1994,8 +1992,8 @@ static void set_tcp_window(struct c4iw_e
+ {
+ ep->snd_win = snd_win;
+ ep->rcv_win = rcv_win;
+- pr_debug("%s snd_win %d rcv_win %d\n",
+- __func__, ep->snd_win, ep->rcv_win);
++ pr_debug("snd_win %d rcv_win %d\n",
++ ep->snd_win, ep->rcv_win);
+ }
+
+ #define ACT_OPEN_RETRY_COUNT 2
+@@ -2100,7 +2098,7 @@ static int c4iw_reconnect(struct c4iw_ep
+ int iptype;
+ __u8 *ra;
+
+- pr_debug("%s qp %p cm_id %p\n", __func__, ep->com.qp, ep->com.cm_id);
++ pr_debug("qp %p cm_id %p\n", ep->com.qp, ep->com.cm_id);
+ init_timer(&ep->timer);
+ c4iw_init_wr_wait(&ep->com.wr_wait);
+
+@@ -2163,8 +2161,8 @@ static int c4iw_reconnect(struct c4iw_ep
+ goto fail4;
+ }
+
+- pr_debug("%s txq_idx %u tx_chan %u smac_idx %u rss_qid %u l2t_idx %u\n",
+- __func__, ep->txq_idx, ep->tx_chan, ep->smac_idx, ep->rss_qid,
++ pr_debug("txq_idx %u tx_chan %u smac_idx %u rss_qid %u l2t_idx %u\n",
++ ep->txq_idx, ep->tx_chan, ep->smac_idx, ep->rss_qid,
+ ep->l2t->idx);
+
+ state_set(&ep->com, CONNECTING);
+@@ -2215,12 +2213,12 @@ static int act_open_rpl(struct c4iw_dev
+ la6 = (struct sockaddr_in6 *)&ep->com.local_addr;
+ ra6 = (struct sockaddr_in6 *)&ep->com.remote_addr;
+
+- pr_debug("%s ep %p atid %u status %u errno %d\n", __func__, ep, atid,
++ pr_debug("ep %p atid %u status %u errno %d\n", ep, atid,
+ status, status2errno(status));
+
+ if (cxgb_is_neg_adv(status)) {
+- pr_debug("%s Connection problems for atid %u status %u (%s)\n",
+- __func__, atid, status, neg_adv_str(status));
++ pr_debug("Connection problems for atid %u status %u (%s)\n",
++ atid, status, neg_adv_str(status));
+ ep->stats.connect_neg_adv++;
+ mutex_lock(&dev->rdev.stats.lock);
+ dev->rdev.stats.neg_adv++;
+@@ -2319,7 +2317,7 @@ static int pass_open_rpl(struct c4iw_dev
+ pr_debug("%s stid %d lookup failure!\n", __func__, stid);
+ goto out;
+ }
+- pr_debug("%s ep %p status %d error %d\n", __func__, ep,
++ pr_debug("ep %p status %d error %d\n", ep,
+ rpl->status, status2errno(rpl->status));
+ c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
+ c4iw_put_ep(&ep->com);
+@@ -2337,7 +2335,7 @@ static int close_listsrv_rpl(struct c4iw
+ pr_debug("%s stid %d lookup failure!\n", __func__, stid);
+ goto out;
+ }
+- pr_debug("%s ep %p\n", __func__, ep);
++ pr_debug("ep %p\n", ep);
+ c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
+ c4iw_put_ep(&ep->com);
+ out:
+@@ -2356,7 +2354,7 @@ static int accept_cr(struct c4iw_ep *ep,
+ int win;
+ enum chip_type adapter_type = ep->com.dev->rdev.lldi.adapter_type;
+
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+ BUG_ON(skb_cloned(skb));
+
+ skb_get(skb);
+@@ -2427,7 +2425,7 @@ static int accept_cr(struct c4iw_ep *ep,
+ if (peer2peer)
+ isn += 4;
+ rpl5->iss = cpu_to_be32(isn);
+- pr_debug("%s iss %u\n", __func__, be32_to_cpu(rpl5->iss));
++ pr_debug("iss %u\n", be32_to_cpu(rpl5->iss));
+ }
+
+ rpl->opt0 = cpu_to_be64(opt0);
+@@ -2440,7 +2438,7 @@ static int accept_cr(struct c4iw_ep *ep,
+
+ static void reject_cr(struct c4iw_dev *dev, u32 hwtid, struct sk_buff *skb)
+ {
+- pr_debug("%s c4iw_dev %p tid %u\n", __func__, dev, hwtid);
++ pr_debug("c4iw_dev %p tid %u\n", dev, hwtid);
+ BUG_ON(skb_cloned(skb));
+ skb_trim(skb, sizeof(struct cpl_tid_release));
+ release_tid(&dev->rdev, hwtid, skb);
+@@ -2481,16 +2479,16 @@ static int pass_accept_req(struct c4iw_d
+
+ /* Find output route */
+ if (iptype == 4) {
+- pr_debug("%s parent ep %p hwtid %u laddr %pI4 raddr %pI4 lport %d rport %d peer_mss %d\n"
+- , __func__, parent_ep, hwtid,
++ pr_debug("parent ep %p hwtid %u laddr %pI4 raddr %pI4 lport %d rport %d peer_mss %d\n"
++ , parent_ep, hwtid,
+ local_ip, peer_ip, ntohs(local_port),
+ ntohs(peer_port), peer_mss);
+ dst = cxgb_find_route(&dev->rdev.lldi, get_real_dev,
+ *(__be32 *)local_ip, *(__be32 *)peer_ip,
+ local_port, peer_port, tos);
+ } else {
+- pr_debug("%s parent ep %p hwtid %u laddr %pI6 raddr %pI6 lport %d rport %d peer_mss %d\n"
+- , __func__, parent_ep, hwtid,
++ pr_debug("parent ep %p hwtid %u laddr %pI6 raddr %pI6 lport %d rport %d peer_mss %d\n"
++ , parent_ep, hwtid,
+ local_ip, peer_ip, ntohs(local_port),
+ ntohs(peer_port), peer_mss);
+ dst = cxgb_find_route6(&dev->rdev.lldi, get_real_dev,
+@@ -2576,7 +2574,7 @@ static int pass_accept_req(struct c4iw_d
+ child_ep->dst = dst;
+ child_ep->hwtid = hwtid;
+
+- pr_debug("%s tx_chan %u smac_idx %u rss_qid %u\n", __func__,
++ pr_debug("tx_chan %u smac_idx %u rss_qid %u\n",
+ child_ep->tx_chan, child_ep->smac_idx, child_ep->rss_qid);
+
+ init_timer(&child_ep->timer);
+@@ -2613,11 +2611,11 @@ static int pass_establish(struct c4iw_de
+ int ret;
+
+ ep = get_ep_from_tid(dev, tid);
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+ ep->snd_seq = be32_to_cpu(req->snd_isn);
+ ep->rcv_seq = be32_to_cpu(req->rcv_isn);
+
+- pr_debug("%s ep %p hwtid %u tcp_opt 0x%02x\n", __func__, ep, tid,
++ pr_debug("ep %p hwtid %u tcp_opt 0x%02x\n", ep, tid,
+ ntohs(req->tcp_opt));
+
+ set_emss(ep, ntohs(req->tcp_opt));
+@@ -2650,7 +2648,7 @@ static int peer_close(struct c4iw_dev *d
+ if (!ep)
+ return 0;
+
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+ dst_confirm(ep->dst);
+
+ set_bit(PEER_CLOSE, &ep->com.history);
+@@ -2750,7 +2748,7 @@ static int peer_abort(struct c4iw_dev *d
+ mutex_unlock(&dev->rdev.stats.lock);
+ goto deref_ep;
+ }
+- pr_debug("%s ep %p tid %u state %u\n", __func__, ep, ep->hwtid,
++ pr_debug("ep %p tid %u state %u\n", ep, ep->hwtid,
+ ep->com.state);
+ set_bit(PEER_ABORT, &ep->com.history);
+
+@@ -2875,7 +2873,7 @@ static int close_con_rpl(struct c4iw_dev
+ if (!ep)
+ return 0;
+
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+
+ /* The cm_id may be null if we failed to connect */
+ mutex_lock(&ep->com.mutex);
+@@ -2950,19 +2948,19 @@ static int fw4_ack(struct c4iw_dev *dev,
+ ep = get_ep_from_tid(dev, tid);
+ if (!ep)
+ return 0;
+- pr_debug("%s ep %p tid %u credits %u\n",
+- __func__, ep, ep->hwtid, credits);
++ pr_debug("ep %p tid %u credits %u\n",
++ ep, ep->hwtid, credits);
+ if (credits == 0) {
+- pr_debug("%s 0 credit ack ep %p tid %u state %u\n",
+- __func__, ep, ep->hwtid, state_read(&ep->com));
++ pr_debug("0 credit ack ep %p tid %u state %u\n",
++ ep, ep->hwtid, state_read(&ep->com));
+ goto out;
+ }
+
+ dst_confirm(ep->dst);
+ if (ep->mpa_skb) {
+- pr_debug("%s last streaming msg ack ep %p tid %u state %u initiator %u freeing skb\n",
+- __func__, ep, ep->hwtid,
+- state_read(&ep->com), ep->mpa_attr.initiator ? 1 : 0);
++ pr_debug("last streaming msg ack ep %p tid %u state %u initiator %u freeing skb\n",
++ ep, ep->hwtid, state_read(&ep->com),
++ ep->mpa_attr.initiator ? 1 : 0);
+ mutex_lock(&ep->com.mutex);
+ kfree_skb(ep->mpa_skb);
+ ep->mpa_skb = NULL;
+@@ -2980,7 +2978,7 @@ int c4iw_reject_cr(struct iw_cm_id *cm_i
+ int abort;
+ struct c4iw_ep *ep = to_ep(cm_id);
+
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+
+ mutex_lock(&ep->com.mutex);
+ if (ep->com.state != MPA_REQ_RCVD) {
+@@ -3011,7 +3009,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_i
+ struct c4iw_qp *qp = get_qhp(h, conn_param->qpn);
+ int abort = 0;
+
+- pr_debug("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
++ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+
+ mutex_lock(&ep->com.mutex);
+ if (ep->com.state != MPA_REQ_RCVD) {
+@@ -3064,7 +3062,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_i
+ ep->ird = 1;
+ }
+
+- pr_debug("%s %d ird %d ord %d\n", __func__, __LINE__, ep->ird, ep->ord);
++ pr_debug("ird %d ord %d\n", ep->ird, ep->ord);
+
+ ep->com.cm_id = cm_id;
+ ref_cm_id(&ep->com);
+@@ -3225,7 +3223,7 @@ int c4iw_connect(struct iw_cm_id *cm_id,
+ goto fail2;
+ }
+ ref_qp(ep);
+- pr_debug("%s qpn 0x%x qp %p cm_id %p\n", __func__, conn_param->qpn,
++ pr_debug("qpn 0x%x qp %p cm_id %p\n", conn_param->qpn,
+ ep->com.qp, cm_id);
+
+ /*
+@@ -3263,8 +3261,8 @@ int c4iw_connect(struct iw_cm_id *cm_id,
+ }
+
+ /* find a route */
+- pr_debug("%s saddr %pI4 sport 0x%x raddr %pI4 rport 0x%x\n",
+- __func__, &laddr->sin_addr, ntohs(laddr->sin_port),
++ pr_debug("saddr %pI4 sport 0x%x raddr %pI4 rport 0x%x\n",
++ &laddr->sin_addr, ntohs(laddr->sin_port),
+ ra, ntohs(raddr->sin_port));
+ ep->dst = cxgb_find_route(&dev->rdev.lldi, get_real_dev,
+ laddr->sin_addr.s_addr,
+@@ -3285,8 +3283,8 @@ int c4iw_connect(struct iw_cm_id *cm_id,
+ }
+
+ /* find a route */
+- pr_debug("%s saddr %pI6 sport 0x%x raddr %pI6 rport 0x%x\n",
+- __func__, laddr6->sin6_addr.s6_addr,
++ pr_debug("saddr %pI6 sport 0x%x raddr %pI6 rport 0x%x\n",
++ laddr6->sin6_addr.s6_addr,
+ ntohs(laddr6->sin6_port),
+ raddr6->sin6_addr.s6_addr, ntohs(raddr6->sin6_port));
+ ep->dst = cxgb_find_route6(&dev->rdev.lldi, get_real_dev,
+@@ -3309,8 +3307,8 @@ int c4iw_connect(struct iw_cm_id *cm_id,
+ goto fail4;
+ }
+
+- pr_debug("%s txq_idx %u tx_chan %u smac_idx %u rss_qid %u l2t_idx %u\n",
+- __func__, ep->txq_idx, ep->tx_chan, ep->smac_idx, ep->rss_qid,
++ pr_debug("txq_idx %u tx_chan %u smac_idx %u rss_qid %u l2t_idx %u\n",
++ ep->txq_idx, ep->tx_chan, ep->smac_idx, ep->rss_qid,
+ ep->l2t->idx);
+
+ state_set(&ep->com, CONNECTING);
+@@ -3424,7 +3422,7 @@ int c4iw_create_listen(struct iw_cm_id *
+ goto fail1;
+ }
+ skb_queue_head_init(&ep->com.ep_skb_list);
+- pr_debug("%s ep %p\n", __func__, ep);
++ pr_debug("ep %p\n", ep);
+ ep->com.cm_id = cm_id;
+ ref_cm_id(&ep->com);
+ ep->com.dev = dev;
+@@ -3478,7 +3476,7 @@ int c4iw_destroy_listen(struct iw_cm_id
+ int err;
+ struct c4iw_listen_ep *ep = to_listen_ep(cm_id);
+
+- pr_debug("%s ep %p\n", __func__, ep);
++ pr_debug("ep %p\n", ep);
+
+ might_sleep();
+ state_set(&ep->com, DEAD);
+@@ -3519,7 +3517,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *e
+
+ mutex_lock(&ep->com.mutex);
+
+- pr_debug("%s ep %p state %s, abrupt %d\n", __func__, ep,
++ pr_debug("ep %p state %s, abrupt %d\n", ep,
+ states[ep->com.state], abrupt);
+
+ /*
+@@ -3933,7 +3931,7 @@ static int rx_pkt(struct c4iw_dev *dev,
+ skb_set_transport_header(skb, (void *)tcph - (void *)rss);
+ skb_get(skb);
+
+- pr_debug("%s lip 0x%x lport %u pip 0x%x pport %u tos %d\n", __func__,
++ pr_debug("lip 0x%x lport %u pip 0x%x pport %u tos %d\n",
+ ntohl(iph->daddr), ntohs(tcph->dest), ntohl(iph->saddr),
+ ntohs(tcph->source), iph->tos);
+
+@@ -3941,15 +3939,13 @@ static int rx_pkt(struct c4iw_dev *dev,
+ iph->daddr, iph->saddr, tcph->dest,
+ tcph->source, iph->tos);
+ if (!dst) {
+- pr_err("%s - failed to find dst entry!\n",
+- __func__);
++ pr_err("%s - failed to find dst entry!\n", __func__);
+ goto reject;
+ }
+ neigh = dst_neigh_lookup_skb(dst, skb);
+
+ if (!neigh) {
+- pr_err("%s - failed to allocate neigh!\n",
+- __func__);
++ pr_err("%s - failed to allocate neigh!\n", __func__);
+ goto free_dst;
+ }
+
+@@ -4032,8 +4028,7 @@ static void process_timeout(struct c4iw_
+ int abort = 1;
+
+ mutex_lock(&ep->com.mutex);
+- pr_debug("%s ep %p tid %u state %d\n", __func__, ep, ep->hwtid,
+- ep->com.state);
++ pr_debug("ep %p tid %u state %d\n", ep, ep->hwtid, ep->com.state);
+ set_bit(TIMEDOUT, &ep->com.history);
+ switch (ep->com.state) {
+ case MPA_REQ_SENT:
+@@ -4176,13 +4171,13 @@ static int fw6_msg(struct c4iw_dev *dev,
+ struct c4iw_wr_wait *wr_waitp;
+ int ret;
+
+- pr_debug("%s type %u\n", __func__, rpl->type);
++ pr_debug("type %u\n", rpl->type);
+
+ switch (rpl->type) {
+ case FW6_TYPE_WR_RPL:
+ ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff);
+ wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1];
+- pr_debug("%s wr_waitp %p ret %u\n", __func__, wr_waitp, ret);
++ pr_debug("wr_waitp %p ret %u\n", wr_waitp, ret);
+ if (wr_waitp)
+ c4iw_wake_up(wr_waitp, ret ? -ret : 0);
+ kfree_skb(skb);
+@@ -4219,8 +4214,7 @@ static int peer_abort_intr(struct c4iw_d
+ neg_adv_str(req->status));
+ goto out;
+ }
+- pr_debug("%s ep %p tid %u state %u\n", __func__, ep, ep->hwtid,
+- ep->com.state);
++ pr_debug("ep %p tid %u state %u\n", ep, ep->hwtid, ep->com.state);
+
+ c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
+ out:
+--- a/drivers/infiniband/hw/cxgb4/cq.c
++++ b/drivers/infiniband/hw/cxgb4/cq.c
+@@ -144,7 +144,7 @@ static int create_cq(struct c4iw_rdev *r
+ ret = c4iw_ofld_send(rdev, skb);
+ if (ret)
+ goto err4;
+- pr_debug("%s wait_event wr_wait %p\n", __func__, &wr_wait);
++ pr_debug("wait_event wr_wait %p\n", &wr_wait);
+ ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
+ if (ret)
+ goto err4;
+@@ -178,7 +178,7 @@ static void insert_recv_cqe(struct t4_wq
+ {
+ struct t4_cqe cqe;
+
+- pr_debug("%s wq %p cq %p sw_cidx %u sw_pidx %u\n", __func__,
++ pr_debug("wq %p cq %p sw_cidx %u sw_pidx %u\n",
+ wq, cq, cq->sw_cidx, cq->sw_pidx);
+ memset(&cqe, 0, sizeof(cqe));
+ cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) |
+@@ -197,7 +197,7 @@ int c4iw_flush_rq(struct t4_wq *wq, stru
+ int in_use = wq->rq.in_use - count;
+
+ BUG_ON(in_use < 0);
+- pr_debug("%s wq %p cq %p rq.in_use %u skip count %u\n", __func__,
++ pr_debug("wq %p cq %p rq.in_use %u skip count %u\n",
+ wq, cq, wq->rq.in_use, count);
+ while (in_use--) {
+ insert_recv_cqe(wq, cq);
+@@ -211,7 +211,7 @@ static void insert_sq_cqe(struct t4_wq *
+ {
+ struct t4_cqe cqe;
+
+- pr_debug("%s wq %p cq %p sw_cidx %u sw_pidx %u\n", __func__,
++ pr_debug("wq %p cq %p sw_cidx %u sw_pidx %u\n",
+ wq, cq, cq->sw_cidx, cq->sw_pidx);
+ memset(&cqe, 0, sizeof(cqe));
+ cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) |
+@@ -281,8 +281,8 @@ static void flush_completed_wrs(struct t
+ /*
+ * Insert this completed cqe into the swcq.
+ */
+- pr_debug("%s moving cqe into swcq sq idx %u cq idx %u\n",
+- __func__, cidx, cq->sw_pidx);
++ pr_debug("moving cqe into swcq sq idx %u cq idx %u\n",
++ cidx, cq->sw_pidx);
+ swsqe->cqe.header |= htonl(CQE_SWCQE_V(1));
+ cq->sw_queue[cq->sw_pidx] = swsqe->cqe;
+ t4_swcq_produce(cq);
+@@ -337,7 +337,7 @@ void c4iw_flush_hw_cq(struct c4iw_cq *ch
+ struct t4_swsqe *swsqe;
+ int ret;
+
+- pr_debug("%s cqid 0x%x\n", __func__, chp->cq.cqid);
++ pr_debug("cqid 0x%x\n", chp->cq.cqid);
+ ret = t4_next_hw_cqe(&chp->cq, &hw_cqe);
+
+ /*
+@@ -430,7 +430,7 @@ void c4iw_count_rcqes(struct t4_cq *cq,
+ u32 ptr;
+
+ *count = 0;
+- pr_debug("%s count zero %d\n", __func__, *count);
++ pr_debug("count zero %d\n", *count);
+ ptr = cq->sw_cidx;
+ while (ptr != cq->sw_pidx) {
+ cqe = &cq->sw_queue[ptr];
+@@ -440,7 +440,7 @@ void c4iw_count_rcqes(struct t4_cq *cq,
+ if (++ptr == cq->size)
+ ptr = 0;
+ }
+- pr_debug("%s cq %p count %d\n", __func__, cq, *count);
++ pr_debug("cq %p count %d\n", cq, *count);
+ }
+
+ /*
+@@ -471,8 +471,8 @@ static int poll_cq(struct t4_wq *wq, str
+ if (ret)
+ return ret;
+
+- pr_debug("%s CQE OVF %u qpid 0x%0x genbit %u type %u status 0x%0x opcode 0x%0x len 0x%0x wrid_hi_stag 0x%x wrid_low_msn 0x%x\n",
+- __func__, CQE_OVFBIT(hw_cqe), CQE_QPID(hw_cqe),
++ pr_debug("CQE OVF %u qpid 0x%0x genbit %u type %u status 0x%0x opcode 0x%0x len 0x%0x wrid_hi_stag 0x%x wrid_low_msn 0x%x\n",
++ CQE_OVFBIT(hw_cqe), CQE_QPID(hw_cqe),
+ CQE_GENBIT(hw_cqe), CQE_TYPE(hw_cqe), CQE_STATUS(hw_cqe),
+ CQE_OPCODE(hw_cqe), CQE_LEN(hw_cqe), CQE_WRID_HI(hw_cqe),
+ CQE_WRID_LOW(hw_cqe));
+@@ -603,8 +603,8 @@ static int poll_cq(struct t4_wq *wq, str
+ if (!SW_CQE(hw_cqe) && (CQE_WRID_SQ_IDX(hw_cqe) != wq->sq.cidx)) {
+ struct t4_swsqe *swsqe;
+
+- pr_debug("%s out of order completion going in sw_sq at idx %u\n",
+- __func__, CQE_WRID_SQ_IDX(hw_cqe));
++ pr_debug("out of order completion going in sw_sq at idx %u\n",
++ CQE_WRID_SQ_IDX(hw_cqe));
+ swsqe = &wq->sq.sw_sq[CQE_WRID_SQ_IDX(hw_cqe)];
+ swsqe->cqe = *hw_cqe;
+ swsqe->complete = 1;
+@@ -638,13 +638,13 @@ proc_cqe:
+ BUG_ON(wq->sq.in_use <= 0 && wq->sq.in_use >= wq->sq.size);
+
+ wq->sq.cidx = (uint16_t)idx;
+- pr_debug("%s completing sq idx %u\n", __func__, wq->sq.cidx);
++ pr_debug("completing sq idx %u\n", wq->sq.cidx);
+ *cookie = wq->sq.sw_sq[wq->sq.cidx].wr_id;
+ if (c4iw_wr_log)
+ c4iw_log_wr_stats(wq, hw_cqe);
+ t4_sq_consume(wq);
+ } else {
+- pr_debug("%s completing rq idx %u\n", __func__, wq->rq.cidx);
++ pr_debug("completing rq idx %u\n", wq->rq.cidx);
+ *cookie = wq->rq.sw_rq[wq->rq.cidx].wr_id;
+ BUG_ON(t4_rq_empty(wq));
+ if (c4iw_wr_log)
+@@ -661,12 +661,12 @@ flush_wq:
+
+ skip_cqe:
+ if (SW_CQE(hw_cqe)) {
+- pr_debug("%s cq %p cqid 0x%x skip sw cqe cidx %u\n",
+- __func__, cq, cq->cqid, cq->sw_cidx);
++ pr_debug("cq %p cqid 0x%x skip sw cqe cidx %u\n",
++ cq, cq->cqid, cq->sw_cidx);
+ t4_swcq_consume(cq);
+ } else {
+- pr_debug("%s cq %p cqid 0x%x skip hw cqe cidx %u\n",
+- __func__, cq, cq->cqid, cq->cidx);
++ pr_debug("cq %p cqid 0x%x skip hw cqe cidx %u\n",
++ cq, cq->cqid, cq->cidx);
+ t4_hwcq_consume(cq);
+ }
+ return ret;
+@@ -712,8 +712,8 @@ static int c4iw_poll_cq_one(struct c4iw_
+ wc->vendor_err = CQE_STATUS(&cqe);
+ wc->wc_flags = 0;
+
+- pr_debug("%s qpid 0x%x type %d opcode %d status 0x%x len %u wrid hi 0x%x lo 0x%x cookie 0x%llx\n",
+- __func__, CQE_QPID(&cqe),
++ pr_debug("qpid 0x%x type %d opcode %d status 0x%x len %u wrid hi 0x%x lo 0x%x cookie 0x%llx\n",
++ CQE_QPID(&cqe),
+ CQE_TYPE(&cqe), CQE_OPCODE(&cqe),
+ CQE_STATUS(&cqe), CQE_LEN(&cqe),
+ CQE_WRID_HI(&cqe), CQE_WRID_LOW(&cqe),
+@@ -857,7 +857,7 @@ int c4iw_destroy_cq(struct ib_cq *ib_cq)
+ struct c4iw_cq *chp;
+ struct c4iw_ucontext *ucontext;
+
+- pr_debug("%s ib_cq %p\n", __func__, ib_cq);
++ pr_debug("ib_cq %p\n", ib_cq);
+ chp = to_c4iw_cq(ib_cq);
+
+ remove_handle(chp->rhp, &chp->rhp->cqidr, chp->cq.cqid);
+@@ -889,7 +889,7 @@ struct ib_cq *c4iw_create_cq(struct ib_d
+ size_t memsize, hwentries;
+ struct c4iw_mm_entry *mm, *mm2;
+
+- pr_debug("%s ib_dev %p entries %d\n", __func__, ibdev, entries);
++ pr_debug("ib_dev %p entries %d\n", ibdev, entries);
+ if (attr->flags)
+ return ERR_PTR(-EINVAL);
+
+@@ -996,8 +996,8 @@ struct ib_cq *c4iw_create_cq(struct ib_d
+ mm2->len = PAGE_SIZE;
+ insert_mmap(ucontext, mm2);
+ }
+- pr_debug("%s cqid 0x%0x chp %p size %u memsize %zu, dma_addr 0x%0llx\n",
+- __func__, chp->cq.cqid, chp, chp->cq.size,
++ pr_debug("cqid 0x%0x chp %p size %u memsize %zu, dma_addr 0x%0llx\n",
++ chp->cq.cqid, chp, chp->cq.size,
+ chp->cq.memsize, (unsigned long long)chp->cq.dma_addr);
+ return &chp->ibcq;
+ err6:
+--- a/drivers/infiniband/hw/cxgb4/device.c
++++ b/drivers/infiniband/hw/cxgb4/device.c
+@@ -811,8 +811,8 @@ static int c4iw_rdev_open(struct c4iw_rd
+
+ rdev->qpmask = rdev->lldi.udb_density - 1;
+ rdev->cqmask = rdev->lldi.ucq_density - 1;
+- pr_debug("%s dev %s stag start 0x%0x size 0x%0x num stags %d pbl start 0x%0x size 0x%0x rq start 0x%0x size 0x%0x qp qid start %u size %u cq qid start %u size %u\n",
+- __func__, pci_name(rdev->lldi.pdev), rdev->lldi.vr->stag.start,
++ pr_debug("dev %s stag start 0x%0x size 0x%0x num stags %d pbl start 0x%0x size 0x%0x rq start 0x%0x size 0x%0x qp qid start %u size %u cq qid start %u size %u\n",
++ pci_name(rdev->lldi.pdev), rdev->lldi.vr->stag.start,
+ rdev->lldi.vr->stag.size, c4iw_num_stags(rdev),
+ rdev->lldi.vr->pbl.start,
+ rdev->lldi.vr->pbl.size, rdev->lldi.vr->rq.start,
+@@ -935,7 +935,7 @@ static void c4iw_dealloc(struct uld_ctx
+
+ static void c4iw_remove(struct uld_ctx *ctx)
+ {
+- pr_debug("%s c4iw_dev %p\n", __func__, ctx->dev);
++ pr_debug("c4iw_dev %p\n", ctx->dev);
+ c4iw_unregister_device(ctx->dev);
+ c4iw_dealloc(ctx);
+ }
+@@ -969,8 +969,8 @@ static struct c4iw_dev *c4iw_alloc(const
+ devp->rdev.lldi = *infop;
+
+ /* init various hw-queue params based on lld info */
+- pr_debug("%s: Ing. padding boundary is %d, egrsstatuspagesize = %d\n",
+- __func__, devp->rdev.lldi.sge_ingpadboundary,
++ pr_debug("Ing. padding boundary is %d, egrsstatuspagesize = %d\n",
++ devp->rdev.lldi.sge_ingpadboundary,
+ devp->rdev.lldi.sge_egrstatuspagesize);
+
+ devp->rdev.hw_queue.t4_eq_status_entries =
+@@ -1069,8 +1069,8 @@ static void *c4iw_uld_add(const struct c
+ }
+ ctx->lldi = *infop;
+
+- pr_debug("%s found device %s nchan %u nrxq %u ntxq %u nports %u\n",
+- __func__, pci_name(ctx->lldi.pdev),
++ pr_debug("found device %s nchan %u nrxq %u ntxq %u nports %u\n",
++ pci_name(ctx->lldi.pdev),
+ ctx->lldi.nchan, ctx->lldi.nrxq,
+ ctx->lldi.ntxq, ctx->lldi.nports);
+
+@@ -1203,7 +1203,7 @@ static int c4iw_uld_state_change(void *h
+ {
+ struct uld_ctx *ctx = handle;
+
+- pr_debug("%s new_state %u\n", __func__, new_state);
++ pr_debug("new_state %u\n", new_state);
+ switch (new_state) {
+ case CXGB4_STATE_UP:
+ pr_info("%s: Up\n", pci_name(ctx->lldi.pdev));
+--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+@@ -537,8 +537,7 @@ static inline struct c4iw_mm_entry *remo
+ if (mm->key == key && mm->len == len) {
+ list_del_init(&mm->entry);
+ spin_unlock(&ucontext->mmap_lock);
+- pr_debug("%s key 0x%x addr 0x%llx len %d\n",
+- __func__, key,
++ pr_debug("key 0x%x addr 0x%llx len %d\n", key,
+ (unsigned long long)mm->addr, mm->len);
+ return mm;
+ }
+@@ -551,8 +550,8 @@ static inline void insert_mmap(struct c4
+ struct c4iw_mm_entry *mm)
+ {
+ spin_lock(&ucontext->mmap_lock);
+- pr_debug("%s key 0x%x addr 0x%llx len %d\n",
+- __func__, mm->key, (unsigned long long)mm->addr, mm->len);
++ pr_debug("key 0x%x addr 0x%llx len %d\n",
++ mm->key, (unsigned long long)mm->addr, mm->len);
+ list_add_tail(&mm->entry, &ucontext->mmaps);
+ spin_unlock(&ucontext->mmap_lock);
+ }
+@@ -671,16 +670,14 @@ enum c4iw_mmid_state {
+ #define MPA_V2_IRD_ORD_MASK 0x3FFF
+
+ #define c4iw_put_ep(ep) { \
+- pr_debug("put_ep (via %s:%u) ep %p refcnt %d\n", \
+- __func__, __LINE__, \
++ pr_debug("put_ep ep %p refcnt %d\n", \
+ ep, kref_read(&((ep)->kref))); \
+ WARN_ON(kref_read(&((ep)->kref)) < 1); \
+ kref_put(&((ep)->kref), _c4iw_free_ep); \
+ }
+
+ #define c4iw_get_ep(ep) { \
+- pr_debug("get_ep (via %s:%u) ep %p, refcnt %d\n", \
+- __func__, __LINE__, \
++ pr_debug("get_ep ep %p, refcnt %d\n", \
+ ep, kref_read(&((ep)->kref))); \
+ kref_get(&((ep)->kref)); \
+ }
+--- a/drivers/infiniband/hw/cxgb4/mem.c
++++ b/drivers/infiniband/hw/cxgb4/mem.c
+@@ -124,7 +124,7 @@ static int _c4iw_write_mem_inline(struct
+ cmd |= cpu_to_be32(T5_ULP_MEMIO_IMM_F);
+
+ addr &= 0x7FFFFFF;
+- pr_debug("%s addr 0x%x len %u\n", __func__, addr, len);
++ pr_debug("addr 0x%x len %u\n", addr, len);
+ num_wqe = DIV_ROUND_UP(len, C4IW_MAX_INLINE_SIZE);
+ c4iw_init_wr_wait(&wr_wait);
+ for (i = 0; i < num_wqe; i++) {
+@@ -285,8 +285,8 @@ static int write_tpt_entry(struct c4iw_r
+ mutex_unlock(&rdev->stats.lock);
+ *stag = (stag_idx << 8) | (atomic_inc_return(&key) & 0xff);
+ }
+- pr_debug("%s stag_state 0x%0x type 0x%0x pdid 0x%0x, stag_idx 0x%x\n",
+- __func__, stag_state, type, pdid, stag_idx);
++ pr_debug("stag_state 0x%0x type 0x%0x pdid 0x%0x, stag_idx 0x%x\n",
++ stag_state, type, pdid, stag_idx);
+
+ /* write TPT entry */
+ if (reset_tpt_entry)
+@@ -327,8 +327,8 @@ static int write_pbl(struct c4iw_rdev *r
+ {
+ int err;
+
+- pr_debug("%s *pdb_addr 0x%x, pbl_base 0x%x, pbl_size %d\n",
+- __func__, pbl_addr, rdev->lldi.vr->pbl.start,
++ pr_debug("*pdb_addr 0x%x, pbl_base 0x%x, pbl_size %d\n",
++ pbl_addr, rdev->lldi.vr->pbl.start,
+ pbl_size);
+
+ err = write_adapter_mem(rdev, pbl_addr >> 5, pbl_size << 3, pbl, NULL);
+@@ -372,7 +372,7 @@ static int finish_mem_reg(struct c4iw_mr
+ mhp->attr.stag = stag;
+ mmid = stag >> 8;
+ mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
+- pr_debug("%s mmid 0x%x mhp %p\n", __func__, mmid, mhp);
++ pr_debug("mmid 0x%x mhp %p\n", mmid, mhp);
+ return insert_handle(mhp->rhp, &mhp->rhp->mmidr, mhp, mmid);
+ }
+
+@@ -422,7 +422,7 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_
+ int ret;
+ u32 stag = T4_STAG_UNSET;
+
+- pr_debug("%s ib_pd %p\n", __func__, pd);
++ pr_debug("ib_pd %p\n", pd);
+ php = to_c4iw_pd(pd);
+ rhp = php->rhp;
+
+@@ -479,7 +479,7 @@ struct ib_mr *c4iw_reg_user_mr(struct ib
+ struct c4iw_pd *php;
+ struct c4iw_mr *mhp;
+
+- pr_debug("%s ib_pd %p\n", __func__, pd);
++ pr_debug("ib_pd %p\n", pd);
+
+ if (length == ~0ULL)
+ return ERR_PTR(-EINVAL);
+@@ -616,7 +616,7 @@ struct ib_mw *c4iw_alloc_mw(struct ib_pd
+ ret = -ENOMEM;
+ goto dealloc_win;
+ }
+- pr_debug("%s mmid 0x%x mhp %p stag 0x%x\n", __func__, mmid, mhp, stag);
++ pr_debug("mmid 0x%x mhp %p stag 0x%x\n", mmid, mhp, stag);
+ return &(mhp->ibmw);
+
+ dealloc_win:
+@@ -641,7 +641,7 @@ int c4iw_dealloc_mw(struct ib_mw *mw)
+ deallocate_window(&rhp->rdev, mhp->attr.stag, mhp->dereg_skb);
+ kfree_skb(mhp->dereg_skb);
+ kfree(mhp);
+- pr_debug("%s ib_mw %p mmid 0x%x ptr %p\n", __func__, mw, mmid, mhp);
++ pr_debug("ib_mw %p mmid 0x%x ptr %p\n", mw, mmid, mhp);
+ return 0;
+ }
+
+@@ -699,7 +699,7 @@ struct ib_mr *c4iw_alloc_mr(struct ib_pd
+ goto err3;
+ }
+
+- pr_debug("%s mmid 0x%x mhp %p stag 0x%x\n", __func__, mmid, mhp, stag);
++ pr_debug("mmid 0x%x mhp %p stag 0x%x\n", mmid, mhp, stag);
+ return &(mhp->ibmr);
+ err3:
+ dereg_mem(&rhp->rdev, stag, mhp->attr.pbl_size,
+@@ -744,7 +744,7 @@ int c4iw_dereg_mr(struct ib_mr *ib_mr)
+ struct c4iw_mr *mhp;
+ u32 mmid;
+
+- pr_debug("%s ib_mr %p\n", __func__, ib_mr);
++ pr_debug("ib_mr %p\n", ib_mr);
+
+ mhp = to_c4iw_mr(ib_mr);
+ rhp = mhp->rhp;
+@@ -762,7 +762,7 @@ int c4iw_dereg_mr(struct ib_mr *ib_mr)
+ kfree((void *) (unsigned long) mhp->kva);
+ if (mhp->umem)
+ ib_umem_release(mhp->umem);
+- pr_debug("%s mmid 0x%x ptr %p\n", __func__, mmid, mhp);
++ pr_debug("mmid 0x%x ptr %p\n", mmid, mhp);
+ kfree(mhp);
+ return 0;
+ }
+--- a/drivers/infiniband/hw/cxgb4/provider.c
++++ b/drivers/infiniband/hw/cxgb4/provider.c
+@@ -102,7 +102,7 @@ void _c4iw_free_ucontext(struct kref *kr
+ ucontext = container_of(kref, struct c4iw_ucontext, kref);
+ rhp = to_c4iw_dev(ucontext->ibucontext.device);
+
+- pr_debug("%s ucontext %p\n", __func__, ucontext);
++ pr_debug("ucontext %p\n", ucontext);
+ list_for_each_entry_safe(mm, tmp, &ucontext->mmaps, entry)
+ kfree(mm);
+ c4iw_release_dev_ucontext(&rhp->rdev, &ucontext->uctx);
+@@ -113,7 +113,7 @@ static int c4iw_dealloc_ucontext(struct
+ {
+ struct c4iw_ucontext *ucontext = to_c4iw_ucontext(context);
+
+- pr_debug("%s context %p\n", __func__, context);
++ pr_debug("context %p\n", context);
+ c4iw_put_ucontext(ucontext);
+ return 0;
+ }
+@@ -127,7 +127,7 @@ static struct ib_ucontext *c4iw_alloc_uc
+ int ret = 0;
+ struct c4iw_mm_entry *mm = NULL;
+
+- pr_debug("%s ibdev %p\n", __func__, ibdev);
++ pr_debug("ibdev %p\n", ibdev);
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context) {
+ ret = -ENOMEM;
+@@ -185,7 +185,7 @@ static int c4iw_mmap(struct ib_ucontext
+ struct c4iw_ucontext *ucontext;
+ u64 addr;
+
+- pr_debug("%s pgoff 0x%lx key 0x%x len %d\n", __func__, vma->vm_pgoff,
++ pr_debug("pgoff 0x%lx key 0x%x len %d\n", vma->vm_pgoff,
+ key, len);
+
+ if (vma->vm_start & (PAGE_SIZE-1))
+@@ -251,7 +251,7 @@ static int c4iw_deallocate_pd(struct ib_
+
+ php = to_c4iw_pd(pd);
+ rhp = php->rhp;
+- pr_debug("%s ibpd %p pdid 0x%x\n", __func__, pd, php->pdid);
++ pr_debug("ibpd %p pdid 0x%x\n", pd, php->pdid);
+ c4iw_put_resource(&rhp->rdev.resource.pdid_table, php->pdid);
+ mutex_lock(&rhp->rdev.stats.lock);
+ rhp->rdev.stats.pd.cur--;
+@@ -268,7 +268,7 @@ static struct ib_pd *c4iw_allocate_pd(st
+ u32 pdid;
+ struct c4iw_dev *rhp;
+
+- pr_debug("%s ibdev %p\n", __func__, ibdev);
++ pr_debug("ibdev %p\n", ibdev);
+ rhp = (struct c4iw_dev *) ibdev;
+ pdid = c4iw_get_resource(&rhp->rdev.resource.pdid_table);
+ if (!pdid)
+@@ -291,14 +291,14 @@ static struct ib_pd *c4iw_allocate_pd(st
+ if (rhp->rdev.stats.pd.cur > rhp->rdev.stats.pd.max)
+ rhp->rdev.stats.pd.max = rhp->rdev.stats.pd.cur;
+ mutex_unlock(&rhp->rdev.stats.lock);
+- pr_debug("%s pdid 0x%0x ptr 0x%p\n", __func__, pdid, php);
++ pr_debug("pdid 0x%0x ptr 0x%p\n", pdid, php);
+ return &php->ibpd;
+ }
+
+ static int c4iw_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
+ u16 *pkey)
+ {
+- pr_debug("%s ibdev %p\n", __func__, ibdev);
++ pr_debug("ibdev %p\n", ibdev);
+ *pkey = 0;
+ return 0;
+ }
+@@ -308,8 +308,8 @@ static int c4iw_query_gid(struct ib_devi
+ {
+ struct c4iw_dev *dev;
+
+- pr_debug("%s ibdev %p, port %d, index %d, gid %p\n",
+- __func__, ibdev, port, index, gid);
++ pr_debug("ibdev %p, port %d, index %d, gid %p\n",
++ ibdev, port, index, gid);
+ dev = to_c4iw_dev(ibdev);
+ BUG_ON(port == 0);
+ memset(&(gid->raw[0]), 0, sizeof(gid->raw));
+@@ -323,7 +323,7 @@ static int c4iw_query_device(struct ib_d
+
+ struct c4iw_dev *dev;
+
+- pr_debug("%s ibdev %p\n", __func__, ibdev);
++ pr_debug("ibdev %p\n", ibdev);
+
+ if (uhw->inlen || uhw->outlen)
+ return -EINVAL;
+@@ -364,7 +364,7 @@ static int c4iw_query_port(struct ib_dev
+ struct net_device *netdev;
+ struct in_device *inetdev;
+
+- pr_debug("%s ibdev %p\n", __func__, ibdev);
++ pr_debug("ibdev %p\n", ibdev);
+
+ dev = to_c4iw_dev(ibdev);
+ netdev = dev->rdev.lldi.ports[port-1];
+@@ -406,7 +406,7 @@ static ssize_t show_rev(struct device *d
+ {
+ struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev,
+ ibdev.dev);
+- pr_debug("%s dev 0x%p\n", __func__, dev);
++ pr_debug("dev 0x%p\n", dev);
+ return sprintf(buf, "%d\n",
+ CHELSIO_CHIP_RELEASE(c4iw_dev->rdev.lldi.adapter_type));
+ }
+@@ -419,7 +419,7 @@ static ssize_t show_hca(struct device *d
+ struct ethtool_drvinfo info;
+ struct net_device *lldev = c4iw_dev->rdev.lldi.ports[0];
+
+- pr_debug("%s dev 0x%p\n", __func__, dev);
++ pr_debug("dev 0x%p\n", dev);
+ lldev->ethtool_ops->get_drvinfo(lldev, &info);
+ return sprintf(buf, "%s\n", info.driver);
+ }
+@@ -429,7 +429,7 @@ static ssize_t show_board(struct device
+ {
+ struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev,
+ ibdev.dev);
+- pr_debug("%s dev 0x%p\n", __func__, dev);
++ pr_debug("dev 0x%p\n", dev);
+ return sprintf(buf, "%x.%x\n", c4iw_dev->rdev.lldi.pdev->vendor,
+ c4iw_dev->rdev.lldi.pdev->device);
+ }
+@@ -521,7 +521,7 @@ static void get_dev_fw_str(struct ib_dev
+ {
+ struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev,
+ ibdev);
+- pr_debug("%s dev 0x%p\n", __func__, dev);
++ pr_debug("dev 0x%p\n", dev);
+
+ snprintf(str, IB_FW_VERSION_NAME_MAX, "%u.%u.%u.%u",
+ FW_HDR_FW_VER_MAJOR_G(c4iw_dev->rdev.lldi.fw_vers),
+@@ -535,7 +535,7 @@ int c4iw_register_device(struct c4iw_dev
+ int ret;
+ int i;
+
+- pr_debug("%s c4iw_dev %p\n", __func__, dev);
++ pr_debug("c4iw_dev %p\n", dev);
+ BUG_ON(!dev->rdev.lldi.ports[0]);
+ strlcpy(dev->ibdev.name, "cxgb4_%d", IB_DEVICE_NAME_MAX);
+ memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
+@@ -645,7 +645,7 @@ void c4iw_unregister_device(struct c4iw_
+ {
+ int i;
+
+- pr_debug("%s c4iw_dev %p\n", __func__, dev);
++ pr_debug("c4iw_dev %p\n", dev);
+ for (i = 0; i < ARRAY_SIZE(c4iw_class_attributes); ++i)
+ device_remove_file(&dev->ibdev.dev,
+ c4iw_class_attributes[i]);
+--- a/drivers/infiniband/hw/cxgb4/qp.c
++++ b/drivers/infiniband/hw/cxgb4/qp.c
+@@ -254,8 +254,8 @@ static int create_qp(struct c4iw_rdev *r
+ ret = -ENOMEM;
+ goto free_sq;
+ }
+- pr_debug("%s sq base va 0x%p pa 0x%llx rq base va 0x%p pa 0x%llx\n",
+- __func__, wq->sq.queue,
++ pr_debug("sq base va 0x%p pa 0x%llx rq base va 0x%p pa 0x%llx\n",
++ wq->sq.queue,
+ (unsigned long long)virt_to_phys(wq->sq.queue),
+ wq->rq.queue,
+ (unsigned long long)virt_to_phys(wq->rq.queue));
+@@ -361,8 +361,8 @@ static int create_qp(struct c4iw_rdev *r
+ if (ret)
+ goto free_dma;
+
+- pr_debug("%s sqid 0x%x rqid 0x%x kdb 0x%p sq_bar2_addr %p rq_bar2_addr %p\n",
+- __func__, wq->sq.qid, wq->rq.qid, wq->db,
++ pr_debug("sqid 0x%x rqid 0x%x kdb 0x%p sq_bar2_addr %p rq_bar2_addr %p\n",
++ wq->sq.qid, wq->rq.qid, wq->db,
+ wq->sq.bar2_va, wq->rq.bar2_va);
+
+ return 0;
+@@ -724,7 +724,7 @@ static void free_qp_work(struct work_str
+ ucontext = qhp->ucontext;
+ rhp = qhp->rhp;
+
+- pr_debug("%s qhp %p ucontext %p\n", __func__, qhp, ucontext);
++ pr_debug("qhp %p ucontext %p\n", qhp, ucontext);
+ destroy_qp(&rhp->rdev, &qhp->wq,
+ ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
+
+@@ -738,19 +738,19 @@ static void queue_qp_free(struct kref *k
+ struct c4iw_qp *qhp;
+
+ qhp = container_of(kref, struct c4iw_qp, kref);
+- pr_debug("%s qhp %p\n", __func__, qhp);
++ pr_debug("qhp %p\n", qhp);
+ queue_work(qhp->rhp->rdev.free_workq, &qhp->free_work);
+ }
+
+ void c4iw_qp_add_ref(struct ib_qp *qp)
+ {
+- pr_debug("%s ib_qp %p\n", __func__, qp);
++ pr_debug("ib_qp %p\n", qp);
+ kref_get(&to_c4iw_qp(qp)->kref);
+ }
+
+ void c4iw_qp_rem_ref(struct ib_qp *qp)
+ {
+- pr_debug("%s ib_qp %p\n", __func__, qp);
++ pr_debug("ib_qp %p\n", qp);
+ kref_put(&to_c4iw_qp(qp)->kref, queue_qp_free);
+ }
+
+@@ -980,8 +980,7 @@ int c4iw_post_send(struct ib_qp *ibqp, s
+
+ init_wr_hdr(wqe, qhp->wq.sq.pidx, fw_opcode, fw_flags, len16);
+
+- pr_debug("%s cookie 0x%llx pidx 0x%x opcode 0x%x read_len %u\n",
+- __func__,
++ pr_debug("cookie 0x%llx pidx 0x%x opcode 0x%x read_len %u\n",
+ (unsigned long long)wr->wr_id, qhp->wq.sq.pidx,
+ swsqe->opcode, swsqe->read_len);
+ wr = wr->next;
+@@ -1057,8 +1056,7 @@ int c4iw_post_receive(struct ib_qp *ibqp
+ wqe->recv.r2[1] = 0;
+ wqe->recv.r2[2] = 0;
+ wqe->recv.len16 = len16;
+- pr_debug("%s cookie 0x%llx pidx %u\n",
+- __func__,
++ pr_debug("cookie 0x%llx pidx %u\n",
+ (unsigned long long)wr->wr_id, qhp->wq.rq.pidx);
+ t4_rq_produce(&qhp->wq, len16);
+ idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
+@@ -1218,7 +1216,7 @@ static void post_terminate(struct c4iw_q
+ struct sk_buff *skb;
+ struct terminate_message *term;
+
+- pr_debug("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid,
++ pr_debug("qhp %p qid 0x%x tid %u\n", qhp, qhp->wq.sq.qid,
+ qhp->ep->hwtid);
+
+ skb = skb_dequeue(&qhp->ep->com.ep_skb_list);
+@@ -1255,7 +1253,7 @@ static void __flush_qp(struct c4iw_qp *q
+ int rq_flushed, sq_flushed;
+ unsigned long flag;
+
+- pr_debug("%s qhp %p rchp %p schp %p\n", __func__, qhp, rchp, schp);
++ pr_debug("qhp %p rchp %p schp %p\n", qhp, rchp, schp);
+
+ /* locking hierarchy: cq lock first, then qp lock. */
+ spin_lock_irqsave(&rchp->lock, flag);
+@@ -1340,8 +1338,7 @@ static int rdma_fini(struct c4iw_dev *rh
+ int ret;
+ struct sk_buff *skb;
+
+- pr_debug("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid,
+- ep->hwtid);
++ pr_debug("qhp %p qid 0x%x tid %u\n", qhp, qhp->wq.sq.qid, ep->hwtid);
+
+ skb = skb_dequeue(&ep->com.ep_skb_list);
+ if (WARN_ON(!skb))
+@@ -1367,13 +1364,13 @@ static int rdma_fini(struct c4iw_dev *rh
+ ret = c4iw_wait_for_reply(&rhp->rdev, &ep->com.wr_wait, qhp->ep->hwtid,
+ qhp->wq.sq.qid, __func__);
+ out:
+- pr_debug("%s ret %d\n", __func__, ret);
++ pr_debug("ret %d\n", ret);
+ return ret;
+ }
+
+ static void build_rtr_msg(u8 p2p_type, struct fw_ri_init *init)
+ {
+- pr_debug("%s p2p_type = %d\n", __func__, p2p_type);
++ pr_debug("p2p_type = %d\n", p2p_type);
+ memset(&init->u, 0, sizeof init->u);
+ switch (p2p_type) {
+ case FW_RI_INIT_P2PTYPE_RDMA_WRITE:
+@@ -1402,7 +1399,7 @@ static int rdma_init(struct c4iw_dev *rh
+ int ret;
+ struct sk_buff *skb;
+
+- pr_debug("%s qhp %p qid 0x%x tid %u ird %u ord %u\n", __func__, qhp,
++ pr_debug("qhp %p qid 0x%x tid %u ird %u ord %u\n", qhp,
+ qhp->wq.sq.qid, qhp->ep->hwtid, qhp->ep->ird, qhp->ep->ord);
+
+ skb = alloc_skb(sizeof *wqe, GFP_KERNEL);
+@@ -1475,7 +1472,7 @@ static int rdma_init(struct c4iw_dev *rh
+ err1:
+ free_ird(rhp, qhp->attr.max_ird);
+ out:
+- pr_debug("%s ret %d\n", __func__, ret);
++ pr_debug("ret %d\n", ret);
+ return ret;
+ }
+
+@@ -1492,8 +1489,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp,
+ int free = 0;
+ struct c4iw_ep *ep = NULL;
+
+- pr_debug("%s qhp %p sqid 0x%x rqid 0x%x ep %p state %d -> %d\n",
+- __func__,
++ pr_debug("qhp %p sqid 0x%x rqid 0x%x ep %p state %d -> %d\n",
+ qhp, qhp->wq.sq.qid, qhp->wq.rq.qid, qhp->ep, qhp->attr.state,
+ (mask & C4IW_QP_ATTR_NEXT_STATE) ? attrs->next_state : -1);
+
+@@ -1680,7 +1676,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp,
+ }
+ goto out;
+ err:
+- pr_debug("%s disassociating ep %p qpid 0x%x\n", __func__, qhp->ep,
++ pr_debug("disassociating ep %p qpid 0x%x\n", qhp->ep,
+ qhp->wq.sq.qid);
+
+ /* disassociate the LLP connection */
+@@ -1717,7 +1713,7 @@ out:
+ */
+ if (free)
+ c4iw_put_ep(&ep->com);
+- pr_debug("%s exit state %d\n", __func__, qhp->attr.state);
++ pr_debug("exit state %d\n", qhp->attr.state);
+ return ret;
+ }
+
+@@ -1747,7 +1743,7 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
+
+ c4iw_qp_rem_ref(ib_qp);
+
+- pr_debug("%s ib_qp %p qpid 0x%0x\n", __func__, ib_qp, qhp->wq.sq.qid);
++ pr_debug("ib_qp %p qpid 0x%0x\n", ib_qp, qhp->wq.sq.qid);
+ return 0;
+ }
+
+@@ -1766,7 +1762,7 @@ struct ib_qp *c4iw_create_qp(struct ib_p
+ struct c4iw_mm_entry *sq_key_mm, *rq_key_mm = NULL, *sq_db_key_mm;
+ struct c4iw_mm_entry *rq_db_key_mm = NULL, *ma_sync_key_mm = NULL;
+
+- pr_debug("%s ib_pd %p\n", __func__, pd);
++ pr_debug("ib_pd %p\n", pd);
+
+ if (attrs->qp_type != IB_QPT_RC)
+ return ERR_PTR(-EINVAL);
+@@ -1937,8 +1933,7 @@ struct ib_qp *c4iw_create_qp(struct ib_p
+ qhp->ibqp.qp_num = qhp->wq.sq.qid;
+ init_timer(&(qhp->timer));
+ INIT_LIST_HEAD(&qhp->db_fc_entry);
+- pr_debug("%s sq id %u size %u memsize %zu num_entries %u rq id %u size %u memsize %zu num_entries %u\n",
+- __func__,
++ pr_debug("sq id %u size %u memsize %zu num_entries %u rq id %u size %u memsize %zu num_entries %u\n",
+ qhp->wq.sq.qid, qhp->wq.sq.size, qhp->wq.sq.memsize,
+ attrs->cap.max_send_wr, qhp->wq.rq.qid, qhp->wq.rq.size,
+ qhp->wq.rq.memsize, attrs->cap.max_recv_wr);
+@@ -1971,7 +1966,7 @@ int c4iw_ib_modify_qp(struct ib_qp *ibqp
+ enum c4iw_qp_attr_mask mask = 0;
+ struct c4iw_qp_attributes attrs;
+
+- pr_debug("%s ib_qp %p\n", __func__, ibqp);
++ pr_debug("ib_qp %p\n", ibqp);
+
+ /* iwarp does not support the RTR state */
+ if ((attr_mask & IB_QP_STATE) && (attr->qp_state == IB_QPS_RTR))
+@@ -2017,7 +2012,7 @@ int c4iw_ib_modify_qp(struct ib_qp *ibqp
+
+ struct ib_qp *c4iw_get_qp(struct ib_device *dev, int qpn)
+ {
+- pr_debug("%s ib_dev %p qpn 0x%x\n", __func__, dev, qpn);
++ pr_debug("ib_dev %p qpn 0x%x\n", dev, qpn);
+ return (struct ib_qp *)get_qhp(to_c4iw_dev(dev), qpn);
+ }
+
+--- a/drivers/infiniband/hw/cxgb4/resource.c
++++ b/drivers/infiniband/hw/cxgb4/resource.c
+@@ -90,7 +90,7 @@ u32 c4iw_get_resource(struct c4iw_id_tab
+
+ void c4iw_put_resource(struct c4iw_id_table *id_table, u32 entry)
+ {
+- pr_debug("%s entry 0x%x\n", __func__, entry);
++ pr_debug("entry 0x%x\n", entry);
+ c4iw_id_free(id_table, entry);
+ }
+
+@@ -141,7 +141,7 @@ u32 c4iw_get_cqid(struct c4iw_rdev *rdev
+ }
+ out:
+ mutex_unlock(&uctx->lock);
+- pr_debug("%s qid 0x%x\n", __func__, qid);
++ pr_debug("qid 0x%x\n", qid);
+ mutex_lock(&rdev->stats.lock);
+ if (rdev->stats.qid.cur > rdev->stats.qid.max)
+ rdev->stats.qid.max = rdev->stats.qid.cur;
+@@ -157,7 +157,7 @@ void c4iw_put_cqid(struct c4iw_rdev *rde
+ entry = kmalloc(sizeof *entry, GFP_KERNEL);
+ if (!entry)
+ return;
+- pr_debug("%s qid 0x%x\n", __func__, qid);
++ pr_debug("qid 0x%x\n", qid);
+ entry->qid = qid;
+ mutex_lock(&uctx->lock);
+ list_add_tail(&entry->entry, &uctx->cqids);
+@@ -215,7 +215,7 @@ u32 c4iw_get_qpid(struct c4iw_rdev *rdev
+ }
+ out:
+ mutex_unlock(&uctx->lock);
+- pr_debug("%s qid 0x%x\n", __func__, qid);
++ pr_debug("qid 0x%x\n", qid);
+ mutex_lock(&rdev->stats.lock);
+ if (rdev->stats.qid.cur > rdev->stats.qid.max)
+ rdev->stats.qid.max = rdev->stats.qid.cur;
+@@ -231,7 +231,7 @@ void c4iw_put_qpid(struct c4iw_rdev *rde
+ entry = kmalloc(sizeof *entry, GFP_KERNEL);
+ if (!entry)
+ return;
+- pr_debug("%s qid 0x%x\n", __func__, qid);
++ pr_debug("qid 0x%x\n", qid);
+ entry->qid = qid;
+ mutex_lock(&uctx->lock);
+ list_add_tail(&entry->entry, &uctx->qpids);
+@@ -254,7 +254,7 @@ void c4iw_destroy_resource(struct c4iw_r
+ u32 c4iw_pblpool_alloc(struct c4iw_rdev *rdev, int size)
+ {
+ unsigned long addr = gen_pool_alloc(rdev->pbl_pool, size);
+- pr_debug("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
++ pr_debug("addr 0x%x size %d\n", (u32)addr, size);
+ mutex_lock(&rdev->stats.lock);
+ if (addr) {
+ rdev->stats.pbl.cur += roundup(size, 1 << MIN_PBL_SHIFT);
+@@ -268,7 +268,7 @@ u32 c4iw_pblpool_alloc(struct c4iw_rdev
+
+ void c4iw_pblpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
+ {
+- pr_debug("%s addr 0x%x size %d\n", __func__, addr, size);
++ pr_debug("addr 0x%x size %d\n", addr, size);
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.pbl.cur -= roundup(size, 1 << MIN_PBL_SHIFT);
+ mutex_unlock(&rdev->stats.lock);
+@@ -290,8 +290,8 @@ int c4iw_pblpool_create(struct c4iw_rdev
+ while (pbl_start < pbl_top) {
+ pbl_chunk = min(pbl_top - pbl_start + 1, pbl_chunk);
+ if (gen_pool_add(rdev->pbl_pool, pbl_start, pbl_chunk, -1)) {
+- pr_debug("%s failed to add PBL chunk (%x/%x)\n",
+- __func__, pbl_start, pbl_chunk);
++ pr_debug("failed to add PBL chunk (%x/%x)\n",
++ pbl_start, pbl_chunk);
+ if (pbl_chunk <= 1024 << MIN_PBL_SHIFT) {
+ pr_warn("Failed to add all PBL chunks (%x/%x)\n",
+ pbl_start, pbl_top - pbl_start);
+@@ -299,8 +299,8 @@ int c4iw_pblpool_create(struct c4iw_rdev
+ }
+ pbl_chunk >>= 1;
+ } else {
+- pr_debug("%s added PBL chunk (%x/%x)\n",
+- __func__, pbl_start, pbl_chunk);
++ pr_debug("added PBL chunk (%x/%x)\n",
++ pbl_start, pbl_chunk);
+ pbl_start += pbl_chunk;
+ }
+ }
+@@ -322,7 +322,7 @@ void c4iw_pblpool_destroy(struct c4iw_rd
+ u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size)
+ {
+ unsigned long addr = gen_pool_alloc(rdev->rqt_pool, size << 6);
+- pr_debug("%s addr 0x%x size %d\n", __func__, (u32)addr, size << 6);
++ pr_debug("addr 0x%x size %d\n", (u32)addr, size << 6);
+ if (!addr)
+ pr_warn_ratelimited("%s: Out of RQT memory\n",
+ pci_name(rdev->lldi.pdev));
+@@ -339,7 +339,7 @@ u32 c4iw_rqtpool_alloc(struct c4iw_rdev
+
+ void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
+ {
+- pr_debug("%s addr 0x%x size %d\n", __func__, addr, size << 6);
++ pr_debug("addr 0x%x size %d\n", addr, size << 6);
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.rqt.cur -= roundup(size << 6, 1 << MIN_RQT_SHIFT);
+ mutex_unlock(&rdev->stats.lock);
+@@ -361,8 +361,8 @@ int c4iw_rqtpool_create(struct c4iw_rdev
+ while (rqt_start < rqt_top) {
+ rqt_chunk = min(rqt_top - rqt_start + 1, rqt_chunk);
+ if (gen_pool_add(rdev->rqt_pool, rqt_start, rqt_chunk, -1)) {
+- pr_debug("%s failed to add RQT chunk (%x/%x)\n",
+- __func__, rqt_start, rqt_chunk);
++ pr_debug("failed to add RQT chunk (%x/%x)\n",
++ rqt_start, rqt_chunk);
+ if (rqt_chunk <= 1024 << MIN_RQT_SHIFT) {
+ pr_warn("Failed to add all RQT chunks (%x/%x)\n",
+ rqt_start, rqt_top - rqt_start);
+@@ -370,8 +370,8 @@ int c4iw_rqtpool_create(struct c4iw_rdev
+ }
+ rqt_chunk >>= 1;
+ } else {
+- pr_debug("%s added RQT chunk (%x/%x)\n",
+- __func__, rqt_start, rqt_chunk);
++ pr_debug("added RQT chunk (%x/%x)\n",
++ rqt_start, rqt_chunk);
+ rqt_start += rqt_chunk;
+ }
+ }
+@@ -391,7 +391,7 @@ void c4iw_rqtpool_destroy(struct c4iw_rd
+ u32 c4iw_ocqp_pool_alloc(struct c4iw_rdev *rdev, int size)
+ {
+ unsigned long addr = gen_pool_alloc(rdev->ocqp_pool, size);
+- pr_debug("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
++ pr_debug("addr 0x%x size %d\n", (u32)addr, size);
+ if (addr) {
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.ocqp.cur += roundup(size, 1 << MIN_OCQP_SHIFT);
+@@ -404,7 +404,7 @@ u32 c4iw_ocqp_pool_alloc(struct c4iw_rde
+
+ void c4iw_ocqp_pool_free(struct c4iw_rdev *rdev, u32 addr, int size)
+ {
+- pr_debug("%s addr 0x%x size %d\n", __func__, addr, size);
++ pr_debug("addr 0x%x size %d\n", addr, size);
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.ocqp.cur -= roundup(size, 1 << MIN_OCQP_SHIFT);
+ mutex_unlock(&rdev->stats.lock);
+@@ -426,8 +426,8 @@ int c4iw_ocqp_pool_create(struct c4iw_rd
+ while (start < top) {
+ chunk = min(top - start + 1, chunk);
+ if (gen_pool_add(rdev->ocqp_pool, start, chunk, -1)) {
+- pr_debug("%s failed to add OCQP chunk (%x/%x)\n",
+- __func__, start, chunk);
++ pr_debug("failed to add OCQP chunk (%x/%x)\n",
++ start, chunk);
+ if (chunk <= 1024 << MIN_OCQP_SHIFT) {
+ pr_warn("Failed to add all OCQP chunks (%x/%x)\n",
+ start, top - start);
+@@ -435,8 +435,8 @@ int c4iw_ocqp_pool_create(struct c4iw_rd
+ }
+ chunk >>= 1;
+ } else {
+- pr_debug("%s added OCQP chunk (%x/%x)\n",
+- __func__, start, chunk);
++ pr_debug("added OCQP chunk (%x/%x)\n",
++ start, chunk);
+ start += chunk;
+ }
+ }
+--- a/drivers/infiniband/hw/cxgb4/t4.h
++++ b/drivers/infiniband/hw/cxgb4/t4.h
+@@ -466,14 +466,12 @@ static inline void t4_ring_sq_db(struct
+ wmb();
+ if (wq->sq.bar2_va) {
+ if (inc == 1 && wq->sq.bar2_qid == 0 && wqe) {
+- pr_debug("%s: WC wq->sq.pidx = %d\n",
+- __func__, wq->sq.pidx);
++ pr_debug("WC wq->sq.pidx = %d\n", wq->sq.pidx);
+ pio_copy((u64 __iomem *)
+ (wq->sq.bar2_va + SGE_UDB_WCDOORBELL),
+ (u64 *)wqe);
+ } else {
+- pr_debug("%s: DB wq->sq.pidx = %d\n",
+- __func__, wq->sq.pidx);
++ pr_debug("DB wq->sq.pidx = %d\n", wq->sq.pidx);
+ writel(PIDX_T5_V(inc) | QID_V(wq->sq.bar2_qid),
+ wq->sq.bar2_va + SGE_UDB_KDOORBELL);
+ }
+@@ -493,14 +491,12 @@ static inline void t4_ring_rq_db(struct
+ wmb();
+ if (wq->rq.bar2_va) {
+ if (inc == 1 && wq->rq.bar2_qid == 0 && wqe) {
+- pr_debug("%s: WC wq->rq.pidx = %d\n",
+- __func__, wq->rq.pidx);
++ pr_debug("WC wq->rq.pidx = %d\n", wq->rq.pidx);
+ pio_copy((u64 __iomem *)
+ (wq->rq.bar2_va + SGE_UDB_WCDOORBELL),
+ (void *)wqe);
+ } else {
+- pr_debug("%s: DB wq->rq.pidx = %d\n",
+- __func__, wq->rq.pidx);
++ pr_debug("DB wq->rq.pidx = %d\n", wq->rq.pidx);
+ writel(PIDX_T5_V(inc) | QID_V(wq->rq.bar2_qid),
+ wq->rq.bar2_va + SGE_UDB_KDOORBELL);
+ }
diff --git a/patches.drivers/iw_cxgb4-add-referencing-to-wait-objects.patch b/patches.drivers/iw_cxgb4-add-referencing-to-wait-objects.patch
new file mode 100644
index 0000000000..a0af87d717
--- /dev/null
+++ b/patches.drivers/iw_cxgb4-add-referencing-to-wait-objects.patch
@@ -0,0 +1,544 @@
+From: Steve Wise <swise@opengridcomputing.com>
+Date: Tue, 26 Sep 2017 13:13:17 -0700
+Subject: iw_cxgb4: add referencing to wait objects
+Patch-mainline: v4.15-rc1
+Git-commit: 2015f26cfadec126265fabfbb0e6566e2cca94b4
+References: bsc#1064802 bsc#1066129
+
+For messages sent from the host to fw that solicit a reply from fw,
+the c4iw_wr_wait struct pointer is passed in the host->fw message, and
+included in the fw->host fw6_msg reply. This allows the sender to wait
+until the reply is received, and the code processing the ingress reply
+to wake up the sender.
+
+If c4iw_wait_for_reply() times out, however, we need to keep the
+c4iw_wr_wait object around in case the reply eventually does arrive.
+Otherwise we have touch-after-free bugs in the wake_up paths.
+
+This was hit due to a bad kernel driver that blocked ingress processing
+of cxgb4 for a long time, causing iw_cxgb4 timeouts, but eventually
+resuming ingress processing and thus hitting the touch-after-free bug.
+
+So I want to fix iw_cxgb4 such that we'll at least keep the wait object
+around until the reply comes. If it never comes we leak a small amount of
+memory, but if it does come late, we won't potentially crash the system.
+
+So add a kref struct in the c4iw_wr_wait struct, and take a reference
+before sending a message to FW that will generate a FW6 reply. And remove
+the reference (and potentially free the wait object) when the reply
+is processed.
+
+The ep code also uses the wr_wait for non FW6 CPL messages and doesn't
+embed the c4iw_wr_wait object in the message sent to firmware. So for
+those cases we add c4iw_wake_up_noref().
+
+The mr/mw, cq, and qp object create/destroy paths do need this reference
+logic. For these paths, c4iw_ref_send_wait() is introduced to take the
+wr_wait reference, send the msg to fw, and then wait for the reply.
+
+So going forward, iw_cxgb4 either uses c4iw_ofld_send(),
+c4iw_wait_for_reply() and c4iw_wake_up_noref() like is done in the some
+of the endpoint logic, or c4iw_ref_send_wait() and c4iw_wake_up_deref()
+(formerly c4iw_wake_up()) when sending messages with the c4iw_wr_wait
+object pointer embedded in the message and resulting FW6 reply.
+
+Signed-off-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 20 +++++------
+ drivers/infiniband/hw/cxgb4/cq.c | 18 ++-------
+ drivers/infiniband/hw/cxgb4/device.c | 21 +++++++++++
+ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 60 +++++++++++++++++++++++++++++++--
+ drivers/infiniband/hw/cxgb4/mem.c | 38 +++++++++++---------
+ drivers/infiniband/hw/cxgb4/qp.c | 31 +++++------------
+ 6 files changed, 123 insertions(+), 65 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -318,7 +318,7 @@ static void *alloc_ep(int size, gfp_t gf
+
+ epc = kzalloc(size, gfp);
+ if (epc) {
+- epc->wr_waitp = kzalloc(sizeof(*epc->wr_waitp), gfp);
++ epc->wr_waitp = c4iw_alloc_wr_wait(gfp);
+ if (!epc->wr_waitp) {
+ kfree(epc);
+ epc = NULL;
+@@ -414,7 +414,7 @@ void _c4iw_free_ep(struct kref *kref)
+ }
+ if (!skb_queue_empty(&ep->com.ep_skb_list))
+ skb_queue_purge(&ep->com.ep_skb_list);
+- kfree(ep->com.wr_waitp);
++ c4iw_put_wr_wait(ep->com.wr_waitp);
+ kfree(ep);
+ }
+
+@@ -1880,7 +1880,7 @@ static int abort_rpl(struct c4iw_dev *de
+ mutex_lock(&ep->com.mutex);
+ switch (ep->com.state) {
+ case ABORTING:
+- c4iw_wake_up(ep->com.wr_waitp, -ECONNRESET);
++ c4iw_wake_up_noref(ep->com.wr_waitp, -ECONNRESET);
+ __state_set(&ep->com, DEAD);
+ release = 1;
+ break;
+@@ -2327,7 +2327,7 @@ static int pass_open_rpl(struct c4iw_dev
+ }
+ pr_debug("ep %p status %d error %d\n", ep,
+ rpl->status, status2errno(rpl->status));
+- c4iw_wake_up(ep->com.wr_waitp, status2errno(rpl->status));
++ c4iw_wake_up_noref(ep->com.wr_waitp, status2errno(rpl->status));
+ c4iw_put_ep(&ep->com);
+ out:
+ return 0;
+@@ -2344,7 +2344,7 @@ static int close_listsrv_rpl(struct c4iw
+ goto out;
+ }
+ pr_debug("ep %p\n", ep);
+- c4iw_wake_up(ep->com.wr_waitp, status2errno(rpl->status));
++ c4iw_wake_up_noref(ep->com.wr_waitp, status2errno(rpl->status));
+ c4iw_put_ep(&ep->com);
+ out:
+ return 0;
+@@ -2679,12 +2679,12 @@ static int peer_close(struct c4iw_dev *d
+ */
+ __state_set(&ep->com, CLOSING);
+ pr_debug("waking up ep %p tid %u\n", ep, ep->hwtid);
+- c4iw_wake_up(ep->com.wr_waitp, -ECONNRESET);
++ c4iw_wake_up_noref(ep->com.wr_waitp, -ECONNRESET);
+ break;
+ case MPA_REP_SENT:
+ __state_set(&ep->com, CLOSING);
+ pr_debug("waking up ep %p tid %u\n", ep, ep->hwtid);
+- c4iw_wake_up(ep->com.wr_waitp, -ECONNRESET);
++ c4iw_wake_up_noref(ep->com.wr_waitp, -ECONNRESET);
+ break;
+ case FPDU_MODE:
+ start_ep_timer(ep);
+@@ -2766,7 +2766,7 @@ static int peer_abort(struct c4iw_dev *d
+ * MPA_REQ_SENT
+ */
+ if (ep->com.state != MPA_REQ_SENT)
+- c4iw_wake_up(ep->com.wr_waitp, -ECONNRESET);
++ c4iw_wake_up_noref(ep->com.wr_waitp, -ECONNRESET);
+
+ mutex_lock(&ep->com.mutex);
+ switch (ep->com.state) {
+@@ -4187,7 +4187,7 @@ static int fw6_msg(struct c4iw_dev *dev,
+ wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1];
+ pr_debug("wr_waitp %p ret %u\n", wr_waitp, ret);
+ if (wr_waitp)
+- c4iw_wake_up(wr_waitp, ret ? -ret : 0);
++ c4iw_wake_up_deref(wr_waitp, ret ? -ret : 0);
+ kfree_skb(skb);
+ break;
+ case FW6_TYPE_CQE:
+@@ -4224,7 +4224,7 @@ static int peer_abort_intr(struct c4iw_d
+ }
+ pr_debug("ep %p tid %u state %u\n", ep, ep->hwtid, ep->com.state);
+
+- c4iw_wake_up(ep->com.wr_waitp, -ECONNRESET);
++ c4iw_wake_up_noref(ep->com.wr_waitp, -ECONNRESET);
+ out:
+ sched(dev, skb);
+ return 0;
+--- a/drivers/infiniband/hw/cxgb4/cq.c
++++ b/drivers/infiniband/hw/cxgb4/cq.c
+@@ -57,10 +57,7 @@ static int destroy_cq(struct c4iw_rdev *
+ res->u.cq.iqid = cpu_to_be32(cq->cqid);
+
+ c4iw_init_wr_wait(wr_waitp);
+- ret = c4iw_ofld_send(rdev, skb);
+- if (!ret) {
+- ret = c4iw_wait_for_reply(rdev, wr_waitp, 0, 0, __func__);
+- }
++ ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0, __func__);
+
+ kfree(cq->sw_queue);
+ dma_free_coherent(&(rdev->lldi.pdev->dev),
+@@ -140,12 +137,7 @@ static int create_cq(struct c4iw_rdev *r
+ res->u.cq.iqaddr = cpu_to_be64(cq->dma_addr);
+
+ c4iw_init_wr_wait(wr_waitp);
+-
+- ret = c4iw_ofld_send(rdev, skb);
+- if (ret)
+- goto err4;
+- pr_debug("wait_event wr_wait %p\n", wr_waitp);
+- ret = c4iw_wait_for_reply(rdev, wr_waitp, 0, 0, __func__);
++ ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0, __func__);
+ if (ret)
+ goto err4;
+
+@@ -869,7 +861,7 @@ int c4iw_destroy_cq(struct ib_cq *ib_cq)
+ destroy_cq(&chp->rhp->rdev, &chp->cq,
+ ucontext ? &ucontext->uctx : &chp->cq.rdev->uctx,
+ chp->destroy_skb, chp->wr_waitp);
+- kfree(chp->wr_waitp);
++ c4iw_put_wr_wait(chp->wr_waitp);
+ kfree(chp);
+ return 0;
+ }
+@@ -901,7 +893,7 @@ struct ib_cq *c4iw_create_cq(struct ib_d
+ chp = kzalloc(sizeof(*chp), GFP_KERNEL);
+ if (!chp)
+ return ERR_PTR(-ENOMEM);
+- chp->wr_waitp = kzalloc(sizeof(*chp->wr_waitp), GFP_KERNEL);
++ chp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
+ if (!chp->wr_waitp) {
+ ret = -ENOMEM;
+ goto err_free_chp;
+@@ -1020,7 +1012,7 @@ err_destroy_cq:
+ err_free_skb:
+ kfree_skb(chp->destroy_skb);
+ err_free_wr_wait:
+- kfree(chp->wr_waitp);
++ c4iw_put_wr_wait(chp->wr_waitp);
+ err_free_chp:
+ kfree(chp);
+ return ERR_PTR(ret);
+--- a/drivers/infiniband/hw/cxgb4/device.c
++++ b/drivers/infiniband/hw/cxgb4/device.c
+@@ -1518,6 +1518,27 @@ static struct cxgb4_uld_info c4iw_uld_in
+ .control = c4iw_uld_control,
+ };
+
++void _c4iw_free_wr_wait(struct kref *kref)
++{
++ struct c4iw_wr_wait *wr_waitp;
++
++ wr_waitp = container_of(kref, struct c4iw_wr_wait, kref);
++ pr_debug("Free wr_wait %p\n", wr_waitp);
++ kfree(wr_waitp);
++}
++
++struct c4iw_wr_wait *c4iw_alloc_wr_wait(gfp_t gfp)
++{
++ struct c4iw_wr_wait *wr_waitp;
++
++ wr_waitp = kzalloc(sizeof(*wr_waitp), gfp);
++ if (wr_waitp) {
++ kref_init(&wr_waitp->kref);
++ pr_debug("wr_wait %p\n", wr_waitp);
++ }
++ return wr_waitp;
++}
++
+ static int __init c4iw_init_module(void)
+ {
+ int err;
+--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+@@ -202,18 +202,50 @@ static inline int c4iw_num_stags(struct
+ struct c4iw_wr_wait {
+ struct completion completion;
+ int ret;
++ struct kref kref;
+ };
+
++void _c4iw_free_wr_wait(struct kref *kref);
++
++static inline void c4iw_put_wr_wait(struct c4iw_wr_wait *wr_waitp)
++{
++ pr_debug("wr_wait %p ref before put %u\n", wr_waitp,
++ kref_read(&wr_waitp->kref));
++ WARN_ON(kref_read(&wr_waitp->kref) == 0);
++ kref_put(&wr_waitp->kref, _c4iw_free_wr_wait);
++}
++
++static inline void c4iw_get_wr_wait(struct c4iw_wr_wait *wr_waitp)
++{
++ pr_debug("wr_wait %p ref before get %u\n", wr_waitp,
++ kref_read(&wr_waitp->kref));
++ WARN_ON(kref_read(&wr_waitp->kref) == 0);
++ kref_get(&wr_waitp->kref);
++}
++
+ static inline void c4iw_init_wr_wait(struct c4iw_wr_wait *wr_waitp)
+ {
+ wr_waitp->ret = 0;
+ init_completion(&wr_waitp->completion);
+ }
+
+-static inline void c4iw_wake_up(struct c4iw_wr_wait *wr_waitp, int ret)
++static inline void _c4iw_wake_up(struct c4iw_wr_wait *wr_waitp, int ret,
++ bool deref)
+ {
+ wr_waitp->ret = ret;
+ complete(&wr_waitp->completion);
++ if (deref)
++ c4iw_put_wr_wait(wr_waitp);
++}
++
++static inline void c4iw_wake_up_noref(struct c4iw_wr_wait *wr_waitp, int ret)
++{
++ _c4iw_wake_up(wr_waitp, ret, false);
++}
++
++static inline void c4iw_wake_up_deref(struct c4iw_wr_wait *wr_waitp, int ret)
++{
++ _c4iw_wake_up(wr_waitp, ret, true);
+ }
+
+ static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
+@@ -234,14 +266,36 @@ static inline int c4iw_wait_for_reply(st
+ func, pci_name(rdev->lldi.pdev), hwtid, qpid);
+ rdev->flags |= T4_FATAL_ERROR;
+ wr_waitp->ret = -EIO;
++ goto out;
+ }
+-out:
+ if (wr_waitp->ret)
+ pr_debug("%s: FW reply %d tid %u qpid %u\n",
+ pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid);
++out:
+ return wr_waitp->ret;
+ }
+
++int c4iw_ofld_send(struct c4iw_rdev *rdev, struct sk_buff *skb);
++
++static inline int c4iw_ref_send_wait(struct c4iw_rdev *rdev,
++ struct sk_buff *skb,
++ struct c4iw_wr_wait *wr_waitp,
++ u32 hwtid, u32 qpid,
++ const char *func)
++{
++ int ret;
++
++ pr_debug("%s wr_wait %p hwtid %u qpid %u\n", func, wr_waitp, hwtid,
++ qpid);
++ c4iw_get_wr_wait(wr_waitp);
++ ret = c4iw_ofld_send(rdev, skb);
++ if (ret) {
++ c4iw_put_wr_wait(wr_waitp);
++ return ret;
++ }
++ return c4iw_wait_for_reply(rdev, wr_waitp, hwtid, qpid, func);
++}
++
+ enum db_state {
+ NORMAL = 0,
+ FLOW_CONTROL = 1,
+@@ -991,7 +1045,6 @@ u32 c4iw_pblpool_alloc(struct c4iw_rdev
+ void c4iw_pblpool_free(struct c4iw_rdev *rdev, u32 addr, int size);
+ u32 c4iw_ocqp_pool_alloc(struct c4iw_rdev *rdev, int size);
+ void c4iw_ocqp_pool_free(struct c4iw_rdev *rdev, u32 addr, int size);
+-int c4iw_ofld_send(struct c4iw_rdev *rdev, struct sk_buff *skb);
+ void c4iw_flush_hw_cq(struct c4iw_cq *chp);
+ void c4iw_count_rcqes(struct t4_cq *cq, struct t4_wq *wq, int *count);
+ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp);
+@@ -1019,5 +1072,6 @@ extern int db_fc_threshold;
+ extern int db_coalescing_threshold;
+ extern int use_dsgl;
+ void c4iw_invalidate_mr(struct c4iw_dev *rhp, u32 rkey);
++struct c4iw_wr_wait *c4iw_alloc_wr_wait(gfp_t gfp);
+
+ #endif
+--- a/drivers/infiniband/hw/cxgb4/mem.c
++++ b/drivers/infiniband/hw/cxgb4/mem.c
+@@ -100,11 +100,10 @@ static int _c4iw_write_mem_dma_aligned(s
+ sgl->len0 = cpu_to_be32(len);
+ sgl->addr0 = cpu_to_be64(data);
+
+- ret = c4iw_ofld_send(rdev, skb);
+- if (ret)
+- return ret;
+ if (wr_waitp)
+- ret = c4iw_wait_for_reply(rdev, wr_waitp, 0, 0, __func__);
++ ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0, __func__);
++ else
++ ret = c4iw_ofld_send(rdev, skb);
+ return ret;
+ }
+
+@@ -173,14 +172,17 @@ static int _c4iw_write_mem_inline(struct
+ if (copy_len % T4_ULPTX_MIN_IO)
+ memset(to_dp + copy_len, 0, T4_ULPTX_MIN_IO -
+ (copy_len % T4_ULPTX_MIN_IO));
+- ret = c4iw_ofld_send(rdev, skb);
+- skb = NULL;
++ if (i == (num_wqe-1))
++ ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0,
++ __func__);
++ else
++ ret = c4iw_ofld_send(rdev, skb);
+ if (ret)
+- return ret;
++ break;
++ skb = NULL;
+ len -= C4IW_MAX_INLINE_SIZE;
+ }
+
+- ret = c4iw_wait_for_reply(rdev, wr_waitp, 0, 0, __func__);
+ return ret;
+ }
+
+@@ -447,7 +449,7 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_
+ mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
+ if (!mhp)
+ return ERR_PTR(-ENOMEM);
+- mhp->wr_waitp = kzalloc(sizeof(*mhp->wr_waitp), GFP_KERNEL);
++ mhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
+ if (!mhp->wr_waitp) {
+ ret = -ENOMEM;
+ goto err_free_mhp;
+@@ -485,7 +487,7 @@ err_dereg_mem:
+ dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
+ mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
+ err_free_wr_wait:
+- kfree(mhp->wr_waitp);
++ c4iw_put_wr_wait(mhp->wr_waitp);
+ err_free_skb:
+ kfree_skb(mhp->dereg_skb);
+ err_free_mhp:
+@@ -522,7 +524,7 @@ struct ib_mr *c4iw_reg_user_mr(struct ib
+ mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
+ if (!mhp)
+ return ERR_PTR(-ENOMEM);
+- mhp->wr_waitp = kzalloc(sizeof(*mhp->wr_waitp), GFP_KERNEL);
++ mhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
+ if (!mhp->wr_waitp)
+ goto err_free_mhp;
+
+@@ -600,7 +602,7 @@ err_umem_release:
+ err_free_skb:
+ kfree_skb(mhp->dereg_skb);
+ err_free_wr_wait:
+- kfree(mhp->wr_waitp);
++ c4iw_put_wr_wait(mhp->wr_waitp);
+ err_free_mhp:
+ kfree(mhp);
+ return ERR_PTR(err);
+@@ -625,7 +627,7 @@ struct ib_mw *c4iw_alloc_mw(struct ib_pd
+ if (!mhp)
+ return ERR_PTR(-ENOMEM);
+
+- mhp->wr_waitp = kzalloc(sizeof(*mhp->wr_waitp), GFP_KERNEL);
++ mhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
+ if (!mhp->wr_waitp) {
+ ret = -ENOMEM;
+ goto free_mhp;
+@@ -659,7 +661,7 @@ dealloc_win:
+ free_skb:
+ kfree_skb(mhp->dereg_skb);
+ free_wr_wait:
+- kfree(mhp->wr_waitp);
++ c4iw_put_wr_wait(mhp->wr_waitp);
+ free_mhp:
+ kfree(mhp);
+ return ERR_PTR(ret);
+@@ -678,7 +680,7 @@ int c4iw_dealloc_mw(struct ib_mw *mw)
+ deallocate_window(&rhp->rdev, mhp->attr.stag, mhp->dereg_skb,
+ mhp->wr_waitp);
+ kfree_skb(mhp->dereg_skb);
+- kfree(mhp->wr_waitp);
++ c4iw_put_wr_wait(mhp->wr_waitp);
+ kfree(mhp);
+ pr_debug("ib_mw %p mmid 0x%x ptr %p\n", mw, mmid, mhp);
+ return 0;
+@@ -710,7 +712,7 @@ struct ib_mr *c4iw_alloc_mr(struct ib_pd
+ goto err;
+ }
+
+- mhp->wr_waitp = kzalloc(sizeof(*mhp->wr_waitp), GFP_KERNEL);
++ mhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
+ if (!mhp->wr_waitp) {
+ ret = -ENOMEM;
+ goto err_free_mhp;
+@@ -758,7 +760,7 @@ err_free_dma:
+ dma_free_coherent(&mhp->rhp->rdev.lldi.pdev->dev,
+ mhp->max_mpl_len, mhp->mpl, mhp->mpl_addr);
+ err_free_wr_wait:
+- kfree(mhp->wr_waitp);
++ c4iw_put_wr_wait(mhp->wr_waitp);
+ err_free_mhp:
+ kfree(mhp);
+ err:
+@@ -812,7 +814,7 @@ int c4iw_dereg_mr(struct ib_mr *ib_mr)
+ if (mhp->umem)
+ ib_umem_release(mhp->umem);
+ pr_debug("mmid 0x%x ptr %p\n", mmid, mhp);
+- kfree(mhp->wr_waitp);
++ c4iw_put_wr_wait(mhp->wr_waitp);
+ kfree(mhp);
+ return 0;
+ }
+--- a/drivers/infiniband/hw/cxgb4/qp.c
++++ b/drivers/infiniband/hw/cxgb4/qp.c
+@@ -353,11 +353,7 @@ static int create_qp(struct c4iw_rdev *r
+ res->u.sqrq.eqaddr = cpu_to_be64(wq->rq.dma_addr);
+
+ c4iw_init_wr_wait(wr_waitp);
+-
+- ret = c4iw_ofld_send(rdev, skb);
+- if (ret)
+- goto free_dma;
+- ret = c4iw_wait_for_reply(rdev, wr_waitp, 0, wq->sq.qid, __func__);
++ ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, wq->sq.qid, __func__);
+ if (ret)
+ goto free_dma;
+
+@@ -730,7 +726,7 @@ static void free_qp_work(struct work_str
+
+ if (ucontext)
+ c4iw_put_ucontext(ucontext);
+- kfree(qhp->wr_waitp);
++ c4iw_put_wr_wait(qhp->wr_waitp);
+ kfree(qhp);
+ }
+
+@@ -1358,13 +1354,10 @@ static int rdma_fini(struct c4iw_dev *rh
+ wqe->cookie = (uintptr_t)ep->com.wr_waitp;
+
+ wqe->u.fini.type = FW_RI_TYPE_FINI;
+- ret = c4iw_ofld_send(&rhp->rdev, skb);
+- if (ret)
+- goto out;
+
+- ret = c4iw_wait_for_reply(&rhp->rdev, ep->com.wr_waitp, qhp->ep->hwtid,
+- qhp->wq.sq.qid, __func__);
+-out:
++ ret = c4iw_ref_send_wait(&rhp->rdev, skb, ep->com.wr_waitp,
++ qhp->ep->hwtid, qhp->wq.sq.qid, __func__);
++
+ pr_debug("ret %d\n", ret);
+ return ret;
+ }
+@@ -1462,15 +1455,11 @@ static int rdma_init(struct c4iw_dev *rh
+ if (qhp->attr.mpa_attr.initiator)
+ build_rtr_msg(qhp->attr.mpa_attr.p2p_type, &wqe->u.init);
+
+- ret = c4iw_ofld_send(&rhp->rdev, skb);
+- if (ret)
+- goto err1;
+-
+- ret = c4iw_wait_for_reply(&rhp->rdev, qhp->ep->com.wr_waitp,
+- qhp->ep->hwtid, qhp->wq.sq.qid, __func__);
++ ret = c4iw_ref_send_wait(&rhp->rdev, skb, qhp->ep->com.wr_waitp,
++ qhp->ep->hwtid, qhp->wq.sq.qid, __func__);
+ if (!ret)
+ goto out;
+-err1:
++
+ free_ird(rhp, qhp->attr.max_ird);
+ out:
+ pr_debug("ret %d\n", ret);
+@@ -1796,7 +1785,7 @@ struct ib_qp *c4iw_create_qp(struct ib_p
+ if (!qhp)
+ return ERR_PTR(-ENOMEM);
+
+- qhp->wr_waitp = kzalloc(sizeof(*qhp), GFP_KERNEL);
++ qhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
+ if (!qhp->wr_waitp) {
+ ret = -ENOMEM;
+ goto err_free_qhp;
+@@ -1963,7 +1952,7 @@ err_destroy_qp:
+ destroy_qp(&rhp->rdev, &qhp->wq,
+ ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
+ err_free_wr_wait:
+- kfree(qhp->wr_waitp);
++ c4iw_put_wr_wait(qhp->wr_waitp);
+ err_free_qhp:
+ kfree(qhp);
+ return ERR_PTR(ret);
diff --git a/patches.drivers/iw_cxgb4-allocate-wait-object-for-each-cq-object.patch b/patches.drivers/iw_cxgb4-allocate-wait-object-for-each-cq-object.patch
new file mode 100644
index 0000000000..18859dac39
--- /dev/null
+++ b/patches.drivers/iw_cxgb4-allocate-wait-object-for-each-cq-object.patch
@@ -0,0 +1,211 @@
+From: Steve Wise <swise@opengridcomputing.com>
+Date: Tue, 26 Sep 2017 13:08:08 -0700
+Subject: iw_cxgb4: allocate wait object for each cq object
+Patch-mainline: v4.15-rc1
+Git-commit: 13ce83174afaf4ceb4dddd7b7e421778ee4fcf5e
+References: bsc#1064802 bsc#1066129
+
+Remove the local stack allocated c4iw_wr_wait object in preparation for
+correctly handling timeouts.
+
+Also cleaned up some error path unwind logic to make it more readable.
+
+Signed-off-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/cq.c | 63 ++++++++++++++++++---------------
+ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 1
+ 2 files changed, 37 insertions(+), 27 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/cq.c
++++ b/drivers/infiniband/hw/cxgb4/cq.c
+@@ -33,12 +33,12 @@
+ #include "iw_cxgb4.h"
+
+ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
+- struct c4iw_dev_ucontext *uctx, struct sk_buff *skb)
++ struct c4iw_dev_ucontext *uctx, struct sk_buff *skb,
++ struct c4iw_wr_wait *wr_waitp)
+ {
+ struct fw_ri_res_wr *res_wr;
+ struct fw_ri_res *res;
+ int wr_len;
+- struct c4iw_wr_wait wr_wait;
+ int ret;
+
+ wr_len = sizeof *res_wr + sizeof *res;
+@@ -50,16 +50,16 @@ static int destroy_cq(struct c4iw_rdev *
+ FW_RI_RES_WR_NRES_V(1) |
+ FW_WR_COMPL_F);
+ res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
+- res_wr->cookie = (uintptr_t)&wr_wait;
++ res_wr->cookie = (uintptr_t)wr_waitp;
+ res = res_wr->res;
+ res->u.cq.restype = FW_RI_RES_TYPE_CQ;
+ res->u.cq.op = FW_RI_RES_OP_RESET;
+ res->u.cq.iqid = cpu_to_be32(cq->cqid);
+
+- c4iw_init_wr_wait(&wr_wait);
++ c4iw_init_wr_wait(wr_waitp);
+ ret = c4iw_ofld_send(rdev, skb);
+ if (!ret) {
+- ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
++ ret = c4iw_wait_for_reply(rdev, wr_waitp, 0, 0, __func__);
+ }
+
+ kfree(cq->sw_queue);
+@@ -71,13 +71,13 @@ static int destroy_cq(struct c4iw_rdev *
+ }
+
+ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
+- struct c4iw_dev_ucontext *uctx)
++ struct c4iw_dev_ucontext *uctx,
++ struct c4iw_wr_wait *wr_waitp)
+ {
+ struct fw_ri_res_wr *res_wr;
+ struct fw_ri_res *res;
+ int wr_len;
+ int user = (uctx != &rdev->uctx);
+- struct c4iw_wr_wait wr_wait;
+ int ret;
+ struct sk_buff *skb;
+
+@@ -119,7 +119,7 @@ static int create_cq(struct c4iw_rdev *r
+ FW_RI_RES_WR_NRES_V(1) |
+ FW_WR_COMPL_F);
+ res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
+- res_wr->cookie = (uintptr_t)&wr_wait;
++ res_wr->cookie = (uintptr_t)wr_waitp;
+ res = res_wr->res;
+ res->u.cq.restype = FW_RI_RES_TYPE_CQ;
+ res->u.cq.op = FW_RI_RES_OP_WRITE;
+@@ -139,13 +139,13 @@ static int create_cq(struct c4iw_rdev *r
+ res->u.cq.iqsize = cpu_to_be16(cq->size);
+ res->u.cq.iqaddr = cpu_to_be64(cq->dma_addr);
+
+- c4iw_init_wr_wait(&wr_wait);
++ c4iw_init_wr_wait(wr_waitp);
+
+ ret = c4iw_ofld_send(rdev, skb);
+ if (ret)
+ goto err4;
+- pr_debug("wait_event wr_wait %p\n", &wr_wait);
+- ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
++ pr_debug("wait_event wr_wait %p\n", wr_waitp);
++ ret = c4iw_wait_for_reply(rdev, wr_waitp, 0, 0, __func__);
+ if (ret)
+ goto err4;
+
+@@ -868,8 +868,8 @@ int c4iw_destroy_cq(struct ib_cq *ib_cq)
+ : NULL;
+ destroy_cq(&chp->rhp->rdev, &chp->cq,
+ ucontext ? &ucontext->uctx : &chp->cq.rdev->uctx,
+- chp->destroy_skb);
+- chp->destroy_skb = NULL;
++ chp->destroy_skb, chp->wr_waitp);
++ kfree(chp->wr_waitp);
+ kfree(chp);
+ return 0;
+ }
+@@ -901,12 +901,18 @@ struct ib_cq *c4iw_create_cq(struct ib_d
+ chp = kzalloc(sizeof(*chp), GFP_KERNEL);
+ if (!chp)
+ return ERR_PTR(-ENOMEM);
++ chp->wr_waitp = kzalloc(sizeof(*chp->wr_waitp), GFP_KERNEL);
++ if (!chp->wr_waitp) {
++ ret = -ENOMEM;
++ goto err_free_chp;
++ }
++ c4iw_init_wr_wait(chp->wr_waitp);
+
+ wr_len = sizeof(struct fw_ri_res_wr) + sizeof(struct fw_ri_res);
+ chp->destroy_skb = alloc_skb(wr_len, GFP_KERNEL);
+ if (!chp->destroy_skb) {
+ ret = -ENOMEM;
+- goto err1;
++ goto err_free_wr_wait;
+ }
+
+ if (ib_context)
+@@ -947,9 +953,10 @@ struct ib_cq *c4iw_create_cq(struct ib_d
+ chp->cq.vector = vector;
+
+ ret = create_cq(&rhp->rdev, &chp->cq,
+- ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
++ ucontext ? &ucontext->uctx : &rhp->rdev.uctx,
++ chp->wr_waitp);
+ if (ret)
+- goto err2;
++ goto err_free_skb;
+
+ chp->rhp = rhp;
+ chp->cq.size--; /* status page */
+@@ -960,16 +967,16 @@ struct ib_cq *c4iw_create_cq(struct ib_d
+ init_waitqueue_head(&chp->wait);
+ ret = insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid);
+ if (ret)
+- goto err3;
++ goto err_destroy_cq;
+
+ if (ucontext) {
+ ret = -ENOMEM;
+ mm = kmalloc(sizeof *mm, GFP_KERNEL);
+ if (!mm)
+- goto err4;
++ goto err_remove_handle;
+ mm2 = kmalloc(sizeof *mm2, GFP_KERNEL);
+ if (!mm2)
+- goto err5;
++ goto err_free_mm;
+
+ uresp.qid_mask = rhp->rdev.cqmask;
+ uresp.cqid = chp->cq.cqid;
+@@ -984,7 +991,7 @@ struct ib_cq *c4iw_create_cq(struct ib_d
+ ret = ib_copy_to_udata(udata, &uresp,
+ sizeof(uresp) - sizeof(uresp.reserved));
+ if (ret)
+- goto err6;
++ goto err_free_mm2;
+
+ mm->key = uresp.key;
+ mm->addr = virt_to_phys(chp->cq.queue);
+@@ -1000,19 +1007,21 @@ struct ib_cq *c4iw_create_cq(struct ib_d
+ chp->cq.cqid, chp, chp->cq.size,
+ chp->cq.memsize, (unsigned long long)chp->cq.dma_addr);
+ return &chp->ibcq;
+-err6:
++err_free_mm2:
+ kfree(mm2);
+-err5:
++err_free_mm:
+ kfree(mm);
+-err4:
++err_remove_handle:
+ remove_handle(rhp, &rhp->cqidr, chp->cq.cqid);
+-err3:
++err_destroy_cq:
+ destroy_cq(&chp->rhp->rdev, &chp->cq,
+ ucontext ? &ucontext->uctx : &rhp->rdev.uctx,
+- chp->destroy_skb);
+-err2:
++ chp->destroy_skb, chp->wr_waitp);
++err_free_skb:
+ kfree_skb(chp->destroy_skb);
+-err1:
++err_free_wr_wait:
++ kfree(chp->wr_waitp);
++err_free_chp:
+ kfree(chp);
+ return ERR_PTR(ret);
+ }
+--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+@@ -425,6 +425,7 @@ struct c4iw_cq {
+ spinlock_t comp_handler_lock;
+ atomic_t refcnt;
+ wait_queue_head_t wait;
++ struct c4iw_wr_wait *wr_waitp;
+ };
+
+ static inline struct c4iw_cq *to_c4iw_cq(struct ib_cq *ibcq)
diff --git a/patches.drivers/iw_cxgb4-allocate-wait-object-for-each-ep-object.patch b/patches.drivers/iw_cxgb4-allocate-wait-object-for-each-ep-object.patch
new file mode 100644
index 0000000000..e6655d4ae2
--- /dev/null
+++ b/patches.drivers/iw_cxgb4-allocate-wait-object-for-each-ep-object.patch
@@ -0,0 +1,215 @@
+From: Steve Wise <swise@opengridcomputing.com>
+Date: Tue, 26 Sep 2017 13:12:16 -0700
+Subject: iw_cxgb4: allocate wait object for each ep object
+Patch-mainline: v4.15-rc1
+Git-commit: ef885dc66c29dd8e6f6a12f164ed11237323c234
+References: bsc#1064802 bsc#1066129
+
+Remove the embedded c4iw_wr_wait object in preparation for correctly
+handling timeouts.
+
+Signed-off-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 38 +++++++++++++++++++--------------
+ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 2 -
+ drivers/infiniband/hw/cxgb4/qp.c | 8 +++---
+ 3 files changed, 28 insertions(+), 20 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -318,11 +318,18 @@ static void *alloc_ep(int size, gfp_t gf
+
+ epc = kzalloc(size, gfp);
+ if (epc) {
++ epc->wr_waitp = kzalloc(sizeof(*epc->wr_waitp), gfp);
++ if (!epc->wr_waitp) {
++ kfree(epc);
++ epc = NULL;
++ goto out;
++ }
+ kref_init(&epc->kref);
+ mutex_init(&epc->mutex);
+- c4iw_init_wr_wait(&epc->wr_wait);
++ c4iw_init_wr_wait(epc->wr_waitp);
+ }
+ pr_debug("alloc ep %p\n", epc);
++out:
+ return epc;
+ }
+
+@@ -407,6 +414,7 @@ void _c4iw_free_ep(struct kref *kref)
+ }
+ if (!skb_queue_empty(&ep->com.ep_skb_list))
+ skb_queue_purge(&ep->com.ep_skb_list);
++ kfree(ep->com.wr_waitp);
+ kfree(ep);
+ }
+
+@@ -1872,7 +1880,7 @@ static int abort_rpl(struct c4iw_dev *de
+ mutex_lock(&ep->com.mutex);
+ switch (ep->com.state) {
+ case ABORTING:
+- c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
++ c4iw_wake_up(ep->com.wr_waitp, -ECONNRESET);
+ __state_set(&ep->com, DEAD);
+ release = 1;
+ break;
+@@ -2100,7 +2108,7 @@ static int c4iw_reconnect(struct c4iw_ep
+
+ pr_debug("qp %p cm_id %p\n", ep->com.qp, ep->com.cm_id);
+ init_timer(&ep->timer);
+- c4iw_init_wr_wait(&ep->com.wr_wait);
++ c4iw_init_wr_wait(ep->com.wr_waitp);
+
+ /* When MPA revision is different on nodes, the node with MPA_rev=2
+ * tries to reconnect with MPA_rev 1 for the same EP through
+@@ -2319,7 +2327,7 @@ static int pass_open_rpl(struct c4iw_dev
+ }
+ pr_debug("ep %p status %d error %d\n", ep,
+ rpl->status, status2errno(rpl->status));
+- c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
++ c4iw_wake_up(ep->com.wr_waitp, status2errno(rpl->status));
+ c4iw_put_ep(&ep->com);
+ out:
+ return 0;
+@@ -2336,7 +2344,7 @@ static int close_listsrv_rpl(struct c4iw
+ goto out;
+ }
+ pr_debug("ep %p\n", ep);
+- c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
++ c4iw_wake_up(ep->com.wr_waitp, status2errno(rpl->status));
+ c4iw_put_ep(&ep->com);
+ out:
+ return 0;
+@@ -2671,12 +2679,12 @@ static int peer_close(struct c4iw_dev *d
+ */
+ __state_set(&ep->com, CLOSING);
+ pr_debug("waking up ep %p tid %u\n", ep, ep->hwtid);
+- c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
++ c4iw_wake_up(ep->com.wr_waitp, -ECONNRESET);
+ break;
+ case MPA_REP_SENT:
+ __state_set(&ep->com, CLOSING);
+ pr_debug("waking up ep %p tid %u\n", ep, ep->hwtid);
+- c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
++ c4iw_wake_up(ep->com.wr_waitp, -ECONNRESET);
+ break;
+ case FPDU_MODE:
+ start_ep_timer(ep);
+@@ -2758,7 +2766,7 @@ static int peer_abort(struct c4iw_dev *d
+ * MPA_REQ_SENT
+ */
+ if (ep->com.state != MPA_REQ_SENT)
+- c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
++ c4iw_wake_up(ep->com.wr_waitp, -ECONNRESET);
+
+ mutex_lock(&ep->com.mutex);
+ switch (ep->com.state) {
+@@ -3346,14 +3354,14 @@ static int create_server6(struct c4iw_de
+ if (err)
+ return err;
+ }
+- c4iw_init_wr_wait(&ep->com.wr_wait);
++ c4iw_init_wr_wait(ep->com.wr_waitp);
+ err = cxgb4_create_server6(ep->com.dev->rdev.lldi.ports[0],
+ ep->stid, &sin6->sin6_addr,
+ sin6->sin6_port,
+ ep->com.dev->rdev.lldi.rxq_ids[0]);
+ if (!err)
+ err = c4iw_wait_for_reply(&ep->com.dev->rdev,
+- &ep->com.wr_wait,
++ ep->com.wr_waitp,
+ 0, 0, __func__);
+ else if (err > 0)
+ err = net_xmit_errno(err);
+@@ -3389,13 +3397,13 @@ static int create_server4(struct c4iw_de
+ }
+ } while (err == -EBUSY);
+ } else {
+- c4iw_init_wr_wait(&ep->com.wr_wait);
++ c4iw_init_wr_wait(ep->com.wr_waitp);
+ err = cxgb4_create_server(ep->com.dev->rdev.lldi.ports[0],
+ ep->stid, sin->sin_addr.s_addr, sin->sin_port,
+ 0, ep->com.dev->rdev.lldi.rxq_ids[0]);
+ if (!err)
+ err = c4iw_wait_for_reply(&ep->com.dev->rdev,
+- &ep->com.wr_wait,
++ ep->com.wr_waitp,
+ 0, 0, __func__);
+ else if (err > 0)
+ err = net_xmit_errno(err);
+@@ -3487,13 +3495,13 @@ int c4iw_destroy_listen(struct iw_cm_id
+ ep->com.dev->rdev.lldi.rxq_ids[0], 0);
+ } else {
+ struct sockaddr_in6 *sin6;
+- c4iw_init_wr_wait(&ep->com.wr_wait);
++ c4iw_init_wr_wait(ep->com.wr_waitp);
+ err = cxgb4_remove_server(
+ ep->com.dev->rdev.lldi.ports[0], ep->stid,
+ ep->com.dev->rdev.lldi.rxq_ids[0], 0);
+ if (err)
+ goto done;
+- err = c4iw_wait_for_reply(&ep->com.dev->rdev, &ep->com.wr_wait,
++ err = c4iw_wait_for_reply(&ep->com.dev->rdev, ep->com.wr_waitp,
+ 0, 0, __func__);
+ sin6 = (struct sockaddr_in6 *)&ep->com.local_addr;
+ cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0],
+@@ -4216,7 +4224,7 @@ static int peer_abort_intr(struct c4iw_d
+ }
+ pr_debug("ep %p tid %u state %u\n", ep, ep->hwtid, ep->com.state);
+
+- c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
++ c4iw_wake_up(ep->com.wr_waitp, -ECONNRESET);
+ out:
+ sched(dev, skb);
+ return 0;
+--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+@@ -842,7 +842,7 @@ struct c4iw_ep_common {
+ struct mutex mutex;
+ struct sockaddr_storage local_addr;
+ struct sockaddr_storage remote_addr;
+- struct c4iw_wr_wait wr_wait;
++ struct c4iw_wr_wait *wr_waitp;
+ unsigned long flags;
+ unsigned long history;
+ };
+--- a/drivers/infiniband/hw/cxgb4/qp.c
++++ b/drivers/infiniband/hw/cxgb4/qp.c
+@@ -1355,14 +1355,14 @@ static int rdma_fini(struct c4iw_dev *rh
+ wqe->flowid_len16 = cpu_to_be32(
+ FW_WR_FLOWID_V(ep->hwtid) |
+ FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16)));
+- wqe->cookie = (uintptr_t)&ep->com.wr_wait;
++ wqe->cookie = (uintptr_t)ep->com.wr_waitp;
+
+ wqe->u.fini.type = FW_RI_TYPE_FINI;
+ ret = c4iw_ofld_send(&rhp->rdev, skb);
+ if (ret)
+ goto out;
+
+- ret = c4iw_wait_for_reply(&rhp->rdev, &ep->com.wr_wait, qhp->ep->hwtid,
++ ret = c4iw_wait_for_reply(&rhp->rdev, ep->com.wr_waitp, qhp->ep->hwtid,
+ qhp->wq.sq.qid, __func__);
+ out:
+ pr_debug("ret %d\n", ret);
+@@ -1425,7 +1425,7 @@ static int rdma_init(struct c4iw_dev *rh
+ FW_WR_FLOWID_V(qhp->ep->hwtid) |
+ FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16)));
+
+- wqe->cookie = (uintptr_t)&qhp->ep->com.wr_wait;
++ wqe->cookie = (uintptr_t)qhp->ep->com.wr_waitp;
+
+ wqe->u.init.type = FW_RI_TYPE_INIT;
+ wqe->u.init.mpareqbit_p2ptype =
+@@ -1466,7 +1466,7 @@ static int rdma_init(struct c4iw_dev *rh
+ if (ret)
+ goto err1;
+
+- ret = c4iw_wait_for_reply(&rhp->rdev, &qhp->ep->com.wr_wait,
++ ret = c4iw_wait_for_reply(&rhp->rdev, qhp->ep->com.wr_waitp,
+ qhp->ep->hwtid, qhp->wq.sq.qid, __func__);
+ if (!ret)
+ goto out;
diff --git a/patches.drivers/iw_cxgb4-allocate-wait-object-for-each-memory-object.patch b/patches.drivers/iw_cxgb4-allocate-wait-object-for-each-memory-object.patch
new file mode 100644
index 0000000000..5ebbb37271
--- /dev/null
+++ b/patches.drivers/iw_cxgb4-allocate-wait-object-for-each-memory-object.patch
@@ -0,0 +1,583 @@
+From: Steve Wise <swise@opengridcomputing.com>
+Date: Tue, 26 Sep 2017 13:07:26 -0700
+Subject: iw_cxgb4: allocate wait object for each memory object
+Patch-mainline: v4.15-rc1
+Git-commit: a3f12da0e99a8d17118ee9e18a1f760a0d427b26
+References: bsc#1064802 bsc#1066129
+
+Remove the local stack allocated c4iw_wr_wait object in preparation for
+correctly handling timeouts.
+
+Also refactored some code to simplify it and make errpath unwinding
+more readable.
+
+Signed-off-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 2
+ drivers/infiniband/hw/cxgb4/mem.c | 228 ++++++++++++++++++++-------------
+ 2 files changed, 141 insertions(+), 89 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+@@ -394,6 +394,7 @@ struct c4iw_mr {
+ dma_addr_t mpl_addr;
+ u32 max_mpl_len;
+ u32 mpl_len;
++ struct c4iw_wr_wait *wr_waitp;
+ };
+
+ static inline struct c4iw_mr *to_c4iw_mr(struct ib_mr *ibmr)
+@@ -407,6 +408,7 @@ struct c4iw_mw {
+ struct sk_buff *dereg_skb;
+ u64 kva;
+ struct tpt_attributes attr;
++ struct c4iw_wr_wait *wr_waitp;
+ };
+
+ static inline struct c4iw_mw *to_c4iw_mw(struct ib_mw *ibmw)
+--- a/drivers/infiniband/hw/cxgb4/mem.c
++++ b/drivers/infiniband/hw/cxgb4/mem.c
+@@ -60,18 +60,18 @@ static int mr_exceeds_hw_limits(struct c
+
+ static int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr,
+ u32 len, dma_addr_t data,
+- int wait, struct sk_buff *skb)
++ struct sk_buff *skb,
++ struct c4iw_wr_wait *wr_waitp)
+ {
+ struct ulp_mem_io *req;
+ struct ulptx_sgl *sgl;
+ u8 wr_len;
+ int ret = 0;
+- struct c4iw_wr_wait wr_wait;
+
+ addr &= 0x7FFFFFF;
+
+- if (wait)
+- c4iw_init_wr_wait(&wr_wait);
++ if (wr_waitp)
++ c4iw_init_wr_wait(wr_waitp);
+ wr_len = roundup(sizeof(*req) + sizeof(*sgl), 16);
+
+ if (!skb) {
+@@ -84,8 +84,8 @@ static int _c4iw_write_mem_dma_aligned(s
+ req = __skb_put_zero(skb, wr_len);
+ INIT_ULPTX_WR(req, wr_len, 0, 0);
+ req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) |
+- (wait ? FW_WR_COMPL_F : 0));
+- req->wr.wr_lo = wait ? (__force __be64)(unsigned long) &wr_wait : 0L;
++ (wr_waitp ? FW_WR_COMPL_F : 0));
++ req->wr.wr_lo = wr_waitp ? (__force __be64)(unsigned long)wr_waitp : 0L;
+ req->wr.wr_mid = cpu_to_be32(FW_WR_LEN16_V(DIV_ROUND_UP(wr_len, 16)));
+ req->cmd = cpu_to_be32(ULPTX_CMD_V(ULP_TX_MEM_WRITE) |
+ T5_ULP_MEMIO_ORDER_V(1) |
+@@ -103,19 +103,19 @@ static int _c4iw_write_mem_dma_aligned(s
+ ret = c4iw_ofld_send(rdev, skb);
+ if (ret)
+ return ret;
+- if (wait)
+- ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
++ if (wr_waitp)
++ ret = c4iw_wait_for_reply(rdev, wr_waitp, 0, 0, __func__);
+ return ret;
+ }
+
+ static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
+- void *data, struct sk_buff *skb)
++ void *data, struct sk_buff *skb,
++ struct c4iw_wr_wait *wr_waitp)
+ {
+ struct ulp_mem_io *req;
+ struct ulptx_idata *sc;
+ u8 wr_len, *to_dp, *from_dp;
+ int copy_len, num_wqe, i, ret = 0;
+- struct c4iw_wr_wait wr_wait;
+ __be32 cmd = cpu_to_be32(ULPTX_CMD_V(ULP_TX_MEM_WRITE));
+
+ if (is_t4(rdev->lldi.adapter_type))
+@@ -126,7 +126,7 @@ static int _c4iw_write_mem_inline(struct
+ addr &= 0x7FFFFFF;
+ pr_debug("addr 0x%x len %u\n", addr, len);
+ num_wqe = DIV_ROUND_UP(len, C4IW_MAX_INLINE_SIZE);
+- c4iw_init_wr_wait(&wr_wait);
++ c4iw_init_wr_wait(wr_waitp);
+ for (i = 0; i < num_wqe; i++) {
+
+ copy_len = len > C4IW_MAX_INLINE_SIZE ? C4IW_MAX_INLINE_SIZE :
+@@ -147,7 +147,7 @@ static int _c4iw_write_mem_inline(struct
+ if (i == (num_wqe-1)) {
+ req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) |
+ FW_WR_COMPL_F);
+- req->wr.wr_lo = (__force __be64)(unsigned long)&wr_wait;
++ req->wr.wr_lo = (__force __be64)(unsigned long)wr_waitp;
+ } else
+ req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR));
+ req->wr.wr_mid = cpu_to_be32(
+@@ -180,12 +180,13 @@ static int _c4iw_write_mem_inline(struct
+ len -= C4IW_MAX_INLINE_SIZE;
+ }
+
+- ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
++ ret = c4iw_wait_for_reply(rdev, wr_waitp, 0, 0, __func__);
+ return ret;
+ }
+
+ static int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len,
+- void *data, struct sk_buff *skb)
++ void *data, struct sk_buff *skb,
++ struct c4iw_wr_wait *wr_waitp)
+ {
+ u32 remain = len;
+ u32 dmalen;
+@@ -208,7 +209,7 @@ static int _c4iw_write_mem_dma(struct c4
+ dmalen = T4_ULPTX_MAX_DMA;
+ remain -= dmalen;
+ ret = _c4iw_write_mem_dma_aligned(rdev, addr, dmalen, daddr,
+- !remain, skb);
++ skb, remain ? NULL : wr_waitp);
+ if (ret)
+ goto out;
+ addr += dmalen >> 5;
+@@ -216,7 +217,8 @@ static int _c4iw_write_mem_dma(struct c4
+ daddr += dmalen;
+ }
+ if (remain)
+- ret = _c4iw_write_mem_inline(rdev, addr, remain, data, skb);
++ ret = _c4iw_write_mem_inline(rdev, addr, remain, data, skb,
++ wr_waitp);
+ out:
+ dma_unmap_single(&rdev->lldi.pdev->dev, save, len, DMA_TO_DEVICE);
+ return ret;
+@@ -227,23 +229,33 @@ out:
+ * If data is NULL, clear len byte of memory to zero.
+ */
+ static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
+- void *data, struct sk_buff *skb)
++ void *data, struct sk_buff *skb,
++ struct c4iw_wr_wait *wr_waitp)
+ {
+- if (rdev->lldi.ulptx_memwrite_dsgl && use_dsgl) {
+- if (len > inline_threshold) {
+- if (_c4iw_write_mem_dma(rdev, addr, len, data, skb)) {
+- pr_warn_ratelimited("%s: dma map failure (non fatal)\n",
+- pci_name(rdev->lldi.pdev));
+- return _c4iw_write_mem_inline(rdev, addr, len,
+- data, skb);
+- } else {
+- return 0;
+- }
+- } else
+- return _c4iw_write_mem_inline(rdev, addr,
+- len, data, skb);
+- } else
+- return _c4iw_write_mem_inline(rdev, addr, len, data, skb);
++ int ret;
++
++ if (!rdev->lldi.ulptx_memwrite_dsgl || !use_dsgl) {
++ ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
++ wr_waitp);
++ goto out;
++ }
++
++ if (len <= inline_threshold) {
++ ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
++ wr_waitp);
++ goto out;
++ }
++
++ ret = _c4iw_write_mem_dma(rdev, addr, len, data, skb, wr_waitp);
++ if (ret) {
++ pr_warn_ratelimited("%s: dma map failure (non fatal)\n",
++ pci_name(rdev->lldi.pdev));
++ ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
++ wr_waitp);
++ }
++out:
++ return ret;
++
+ }
+
+ /*
+@@ -257,7 +269,7 @@ static int write_tpt_entry(struct c4iw_r
+ enum fw_ri_stag_type type, enum fw_ri_mem_perms perm,
+ int bind_enabled, u32 zbva, u64 to,
+ u64 len, u8 page_size, u32 pbl_size, u32 pbl_addr,
+- struct sk_buff *skb)
++ struct sk_buff *skb, struct c4iw_wr_wait *wr_waitp)
+ {
+ int err;
+ struct fw_ri_tpte tpt;
+@@ -311,7 +323,7 @@ static int write_tpt_entry(struct c4iw_r
+ }
+ err = write_adapter_mem(rdev, stag_idx +
+ (rdev->lldi.vr->stag.start >> 5),
+- sizeof(tpt), &tpt, skb);
++ sizeof(tpt), &tpt, skb, wr_waitp);
+
+ if (reset_tpt_entry) {
+ c4iw_put_resource(&rdev->resource.tpt_table, stag_idx);
+@@ -323,7 +335,7 @@ static int write_tpt_entry(struct c4iw_r
+ }
+
+ static int write_pbl(struct c4iw_rdev *rdev, __be64 *pbl,
+- u32 pbl_addr, u32 pbl_size)
++ u32 pbl_addr, u32 pbl_size, struct c4iw_wr_wait *wr_waitp)
+ {
+ int err;
+
+@@ -331,37 +343,42 @@ static int write_pbl(struct c4iw_rdev *r
+ pbl_addr, rdev->lldi.vr->pbl.start,
+ pbl_size);
+
+- err = write_adapter_mem(rdev, pbl_addr >> 5, pbl_size << 3, pbl, NULL);
++ err = write_adapter_mem(rdev, pbl_addr >> 5, pbl_size << 3, pbl, NULL,
++ wr_waitp);
+ return err;
+ }
+
+ static int dereg_mem(struct c4iw_rdev *rdev, u32 stag, u32 pbl_size,
+- u32 pbl_addr, struct sk_buff *skb)
++ u32 pbl_addr, struct sk_buff *skb,
++ struct c4iw_wr_wait *wr_waitp)
+ {
+ return write_tpt_entry(rdev, 1, &stag, 0, 0, 0, 0, 0, 0, 0UL, 0, 0,
+- pbl_size, pbl_addr, skb);
++ pbl_size, pbl_addr, skb, wr_waitp);
+ }
+
+-static int allocate_window(struct c4iw_rdev *rdev, u32 * stag, u32 pdid)
++static int allocate_window(struct c4iw_rdev *rdev, u32 *stag, u32 pdid,
++ struct c4iw_wr_wait *wr_waitp)
+ {
+ *stag = T4_STAG_UNSET;
+ return write_tpt_entry(rdev, 0, stag, 0, pdid, FW_RI_STAG_MW, 0, 0, 0,
+- 0UL, 0, 0, 0, 0, NULL);
++ 0UL, 0, 0, 0, 0, NULL, wr_waitp);
+ }
+
+ static int deallocate_window(struct c4iw_rdev *rdev, u32 stag,
+- struct sk_buff *skb)
++ struct sk_buff *skb,
++ struct c4iw_wr_wait *wr_waitp)
+ {
+ return write_tpt_entry(rdev, 1, &stag, 0, 0, 0, 0, 0, 0, 0UL, 0, 0, 0,
+- 0, skb);
++ 0, skb, wr_waitp);
+ }
+
+ static int allocate_stag(struct c4iw_rdev *rdev, u32 *stag, u32 pdid,
+- u32 pbl_size, u32 pbl_addr)
++ u32 pbl_size, u32 pbl_addr,
++ struct c4iw_wr_wait *wr_waitp)
+ {
+ *stag = T4_STAG_UNSET;
+ return write_tpt_entry(rdev, 0, stag, 0, pdid, FW_RI_STAG_NSMR, 0, 0, 0,
+- 0UL, 0, 0, pbl_size, pbl_addr, NULL);
++ 0UL, 0, 0, pbl_size, pbl_addr, NULL, wr_waitp);
+ }
+
+ static int finish_mem_reg(struct c4iw_mr *mhp, u32 stag)
+@@ -388,14 +405,15 @@ static int register_mem(struct c4iw_dev
+ mhp->attr.mw_bind_enable, mhp->attr.zbva,
+ mhp->attr.va_fbo, mhp->attr.len ?
+ mhp->attr.len : -1, shift - 12,
+- mhp->attr.pbl_size, mhp->attr.pbl_addr, NULL);
++ mhp->attr.pbl_size, mhp->attr.pbl_addr, NULL,
++ mhp->wr_waitp);
+ if (ret)
+ return ret;
+
+ ret = finish_mem_reg(mhp, stag);
+ if (ret) {
+ dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
+- mhp->attr.pbl_addr, mhp->dereg_skb);
++ mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
+ mhp->dereg_skb = NULL;
+ }
+ return ret;
+@@ -429,11 +447,17 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_
+ mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
+ if (!mhp)
+ return ERR_PTR(-ENOMEM);
++ mhp->wr_waitp = kzalloc(sizeof(*mhp->wr_waitp), GFP_KERNEL);
++ if (!mhp->wr_waitp) {
++ ret = -ENOMEM;
++ goto err_free_mhp;
++ }
++ c4iw_init_wr_wait(mhp->wr_waitp);
+
+ mhp->dereg_skb = alloc_skb(SGE_MAX_WR_LEN, GFP_KERNEL);
+ if (!mhp->dereg_skb) {
+ ret = -ENOMEM;
+- goto err0;
++ goto err_free_wr_wait;
+ }
+
+ mhp->rhp = rhp;
+@@ -449,20 +473,22 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_
+ ret = write_tpt_entry(&rhp->rdev, 0, &stag, 1, php->pdid,
+ FW_RI_STAG_NSMR, mhp->attr.perms,
+ mhp->attr.mw_bind_enable, 0, 0, ~0ULL, 0, 0, 0,
+- NULL);
++ NULL, mhp->wr_waitp);
+ if (ret)
+- goto err1;
++ goto err_free_skb;
+
+ ret = finish_mem_reg(mhp, stag);
+ if (ret)
+- goto err2;
++ goto err_dereg_mem;
+ return &mhp->ibmr;
+-err2:
++err_dereg_mem:
+ dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
+- mhp->attr.pbl_addr, mhp->dereg_skb);
+-err1:
++ mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
++err_free_wr_wait:
++ kfree(mhp->wr_waitp);
++err_free_skb:
+ kfree_skb(mhp->dereg_skb);
+-err0:
++err_free_mhp:
+ kfree(mhp);
+ return ERR_PTR(ret);
+ }
+@@ -473,7 +499,7 @@ struct ib_mr *c4iw_reg_user_mr(struct ib
+ __be64 *pages;
+ int shift, n, len;
+ int i, k, entry;
+- int err = 0;
++ int err = -ENOMEM;
+ struct scatterlist *sg;
+ struct c4iw_dev *rhp;
+ struct c4iw_pd *php;
+@@ -496,34 +522,31 @@ struct ib_mr *c4iw_reg_user_mr(struct ib
+ mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
+ if (!mhp)
+ return ERR_PTR(-ENOMEM);
++ mhp->wr_waitp = kzalloc(sizeof(*mhp->wr_waitp), GFP_KERNEL);
++ if (!mhp->wr_waitp)
++ goto err_free_mhp;
+
+ mhp->dereg_skb = alloc_skb(SGE_MAX_WR_LEN, GFP_KERNEL);
+- if (!mhp->dereg_skb) {
+- kfree(mhp);
+- return ERR_PTR(-ENOMEM);
+- }
++ if (!mhp->dereg_skb)
++ goto err_free_wr_wait;
+
+ mhp->rhp = rhp;
+
+ mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0);
+- if (IS_ERR(mhp->umem)) {
+- err = PTR_ERR(mhp->umem);
+- kfree_skb(mhp->dereg_skb);
+- kfree(mhp);
+- return ERR_PTR(err);
+- }
++ if (IS_ERR(mhp->umem))
++ goto err_free_skb;
+
+ shift = mhp->umem->page_shift;
+
+ n = mhp->umem->nmap;
+ err = alloc_pbl(mhp, n);
+ if (err)
+- goto err;
++ goto err_umem_release;
+
+ pages = (__be64 *) __get_free_page(GFP_KERNEL);
+ if (!pages) {
+ err = -ENOMEM;
+- goto err_pbl;
++ goto err_pbl_free;
+ }
+
+ i = n = 0;
+@@ -536,7 +559,8 @@ struct ib_mr *c4iw_reg_user_mr(struct ib
+ if (i == PAGE_SIZE / sizeof *pages) {
+ err = write_pbl(&mhp->rhp->rdev,
+ pages,
+- mhp->attr.pbl_addr + (n << 3), i);
++ mhp->attr.pbl_addr + (n << 3), i,
++ mhp->wr_waitp);
+ if (err)
+ goto pbl_done;
+ n += i;
+@@ -547,12 +571,13 @@ struct ib_mr *c4iw_reg_user_mr(struct ib
+
+ if (i)
+ err = write_pbl(&mhp->rhp->rdev, pages,
+- mhp->attr.pbl_addr + (n << 3), i);
++ mhp->attr.pbl_addr + (n << 3), i,
++ mhp->wr_waitp);
+
+ pbl_done:
+ free_page((unsigned long) pages);
+ if (err)
+- goto err_pbl;
++ goto err_pbl_free;
+
+ mhp->attr.pdid = php->pdid;
+ mhp->attr.zbva = 0;
+@@ -563,17 +588,20 @@ pbl_done:
+
+ err = register_mem(rhp, php, mhp, shift);
+ if (err)
+- goto err_pbl;
++ goto err_pbl_free;
+
+ return &mhp->ibmr;
+
+-err_pbl:
++err_pbl_free:
+ c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
+ mhp->attr.pbl_size << 3);
+-
+-err:
++err_umem_release:
+ ib_umem_release(mhp->umem);
++err_free_skb:
+ kfree_skb(mhp->dereg_skb);
++err_free_wr_wait:
++ kfree(mhp->wr_waitp);
++err_free_mhp:
+ kfree(mhp);
+ return ERR_PTR(err);
+ }
+@@ -597,13 +625,19 @@ struct ib_mw *c4iw_alloc_mw(struct ib_pd
+ if (!mhp)
+ return ERR_PTR(-ENOMEM);
+
++ mhp->wr_waitp = kzalloc(sizeof(*mhp->wr_waitp), GFP_KERNEL);
++ if (!mhp->wr_waitp) {
++ ret = -ENOMEM;
++ goto free_mhp;
++ }
++
+ mhp->dereg_skb = alloc_skb(SGE_MAX_WR_LEN, GFP_KERNEL);
+ if (!mhp->dereg_skb) {
+ ret = -ENOMEM;
+- goto free_mhp;
++ goto free_wr_wait;
+ }
+
+- ret = allocate_window(&rhp->rdev, &stag, php->pdid);
++ ret = allocate_window(&rhp->rdev, &stag, php->pdid, mhp->wr_waitp);
+ if (ret)
+ goto free_skb;
+ mhp->rhp = rhp;
+@@ -620,9 +654,12 @@ struct ib_mw *c4iw_alloc_mw(struct ib_pd
+ return &(mhp->ibmw);
+
+ dealloc_win:
+- deallocate_window(&rhp->rdev, mhp->attr.stag, mhp->dereg_skb);
++ deallocate_window(&rhp->rdev, mhp->attr.stag, mhp->dereg_skb,
++ mhp->wr_waitp);
+ free_skb:
+ kfree_skb(mhp->dereg_skb);
++free_wr_wait:
++ kfree(mhp->wr_waitp);
+ free_mhp:
+ kfree(mhp);
+ return ERR_PTR(ret);
+@@ -638,8 +675,10 @@ int c4iw_dealloc_mw(struct ib_mw *mw)
+ rhp = mhp->rhp;
+ mmid = (mw->rkey) >> 8;
+ remove_handle(rhp, &rhp->mmidr, mmid);
+- deallocate_window(&rhp->rdev, mhp->attr.stag, mhp->dereg_skb);
++ deallocate_window(&rhp->rdev, mhp->attr.stag, mhp->dereg_skb,
++ mhp->wr_waitp);
+ kfree_skb(mhp->dereg_skb);
++ kfree(mhp->wr_waitp);
+ kfree(mhp);
+ pr_debug("ib_mw %p mmid 0x%x ptr %p\n", mw, mmid, mhp);
+ return 0;
+@@ -671,23 +710,31 @@ struct ib_mr *c4iw_alloc_mr(struct ib_pd
+ goto err;
+ }
+
++ mhp->wr_waitp = kzalloc(sizeof(*mhp->wr_waitp), GFP_KERNEL);
++ if (!mhp->wr_waitp) {
++ ret = -ENOMEM;
++ goto err_free_mhp;
++ }
++ c4iw_init_wr_wait(mhp->wr_waitp);
++
+ mhp->mpl = dma_alloc_coherent(&rhp->rdev.lldi.pdev->dev,
+ length, &mhp->mpl_addr, GFP_KERNEL);
+ if (!mhp->mpl) {
+ ret = -ENOMEM;
+- goto err_mpl;
++ goto err_free_wr_wait;
+ }
+ mhp->max_mpl_len = length;
+
+ mhp->rhp = rhp;
+ ret = alloc_pbl(mhp, max_num_sg);
+ if (ret)
+- goto err1;
++ goto err_free_dma;
+ mhp->attr.pbl_size = max_num_sg;
+ ret = allocate_stag(&rhp->rdev, &stag, php->pdid,
+- mhp->attr.pbl_size, mhp->attr.pbl_addr);
++ mhp->attr.pbl_size, mhp->attr.pbl_addr,
++ mhp->wr_waitp);
+ if (ret)
+- goto err2;
++ goto err_free_pbl;
+ mhp->attr.pdid = php->pdid;
+ mhp->attr.type = FW_RI_STAG_NSMR;
+ mhp->attr.stag = stag;
+@@ -696,21 +743,23 @@ struct ib_mr *c4iw_alloc_mr(struct ib_pd
+ mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
+ if (insert_handle(rhp, &rhp->mmidr, mhp, mmid)) {
+ ret = -ENOMEM;
+- goto err3;
++ goto err_dereg;
+ }
+
+ pr_debug("mmid 0x%x mhp %p stag 0x%x\n", mmid, mhp, stag);
+ return &(mhp->ibmr);
+-err3:
++err_dereg:
+ dereg_mem(&rhp->rdev, stag, mhp->attr.pbl_size,
+- mhp->attr.pbl_addr, mhp->dereg_skb);
+-err2:
++ mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
++err_free_pbl:
+ c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
+ mhp->attr.pbl_size << 3);
+-err1:
++err_free_dma:
+ dma_free_coherent(&mhp->rhp->rdev.lldi.pdev->dev,
+ mhp->max_mpl_len, mhp->mpl, mhp->mpl_addr);
+-err_mpl:
++err_free_wr_wait:
++ kfree(mhp->wr_waitp);
++err_free_mhp:
+ kfree(mhp);
+ err:
+ return ERR_PTR(ret);
+@@ -754,7 +803,7 @@ int c4iw_dereg_mr(struct ib_mr *ib_mr)
+ dma_free_coherent(&mhp->rhp->rdev.lldi.pdev->dev,
+ mhp->max_mpl_len, mhp->mpl, mhp->mpl_addr);
+ dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
+- mhp->attr.pbl_addr, mhp->dereg_skb);
++ mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
+ if (mhp->attr.pbl_size)
+ c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
+ mhp->attr.pbl_size << 3);
+@@ -763,6 +812,7 @@ int c4iw_dereg_mr(struct ib_mr *ib_mr)
+ if (mhp->umem)
+ ib_umem_release(mhp->umem);
+ pr_debug("mmid 0x%x ptr %p\n", mmid, mhp);
++ kfree(mhp->wr_waitp);
+ kfree(mhp);
+ return 0;
+ }
diff --git a/patches.drivers/iw_cxgb4-allocate-wait-object-for-each-qp-object.patch b/patches.drivers/iw_cxgb4-allocate-wait-object-for-each-qp-object.patch
new file mode 100644
index 0000000000..01a7660258
--- /dev/null
+++ b/patches.drivers/iw_cxgb4-allocate-wait-object-for-each-qp-object.patch
@@ -0,0 +1,191 @@
+From: Steve Wise <swise@opengridcomputing.com>
+Date: Tue, 26 Sep 2017 13:11:36 -0700
+Subject: iw_cxgb4: allocate wait object for each qp object
+Patch-mainline: v4.15-rc1
+Git-commit: 7088a9ba624599696f920eac552eac69366c8440
+References: bsc#1064802 bsc#1066129
+
+Remove the local stack allocated c4iw_wr_wait object in preparation for
+correctly handling timeouts.
+
+Also cleaned up some error path unwind logic to make it more readable.
+
+Signed-off-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 1
+ drivers/infiniband/hw/cxgb4/qp.c | 55 +++++++++++++++++++--------------
+ 2 files changed, 34 insertions(+), 22 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+@@ -487,6 +487,7 @@ struct c4iw_qp {
+ int sq_sig_all;
+ struct work_struct free_work;
+ struct c4iw_ucontext *ucontext;
++ struct c4iw_wr_wait *wr_waitp;
+ };
+
+ static inline struct c4iw_qp *to_c4iw_qp(struct ib_qp *ibqp)
+--- a/drivers/infiniband/hw/cxgb4/qp.c
++++ b/drivers/infiniband/hw/cxgb4/qp.c
+@@ -194,13 +194,13 @@ void __iomem *c4iw_bar2_addrs(struct c4i
+
+ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
+ struct t4_cq *rcq, struct t4_cq *scq,
+- struct c4iw_dev_ucontext *uctx)
++ struct c4iw_dev_ucontext *uctx,
++ struct c4iw_wr_wait *wr_waitp)
+ {
+ int user = (uctx != &rdev->uctx);
+ struct fw_ri_res_wr *res_wr;
+ struct fw_ri_res *res;
+ int wr_len;
+- struct c4iw_wr_wait wr_wait;
+ struct sk_buff *skb;
+ int ret = 0;
+ int eqsize;
+@@ -299,7 +299,7 @@ static int create_qp(struct c4iw_rdev *r
+ FW_RI_RES_WR_NRES_V(2) |
+ FW_WR_COMPL_F);
+ res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
+- res_wr->cookie = (uintptr_t)&wr_wait;
++ res_wr->cookie = (uintptr_t)wr_waitp;
+ res = res_wr->res;
+ res->u.sqrq.restype = FW_RI_RES_TYPE_SQ;
+ res->u.sqrq.op = FW_RI_RES_OP_WRITE;
+@@ -352,12 +352,12 @@ static int create_qp(struct c4iw_rdev *r
+ res->u.sqrq.eqid = cpu_to_be32(wq->rq.qid);
+ res->u.sqrq.eqaddr = cpu_to_be64(wq->rq.dma_addr);
+
+- c4iw_init_wr_wait(&wr_wait);
++ c4iw_init_wr_wait(wr_waitp);
+
+ ret = c4iw_ofld_send(rdev, skb);
+ if (ret)
+ goto free_dma;
+- ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, wq->sq.qid, __func__);
++ ret = c4iw_wait_for_reply(rdev, wr_waitp, 0, wq->sq.qid, __func__);
+ if (ret)
+ goto free_dma;
+
+@@ -730,6 +730,7 @@ static void free_qp_work(struct work_str
+
+ if (ucontext)
+ c4iw_put_ucontext(ucontext);
++ kfree(qhp->wr_waitp);
+ kfree(qhp);
+ }
+
+@@ -1794,6 +1795,13 @@ struct ib_qp *c4iw_create_qp(struct ib_p
+ qhp = kzalloc(sizeof(*qhp), GFP_KERNEL);
+ if (!qhp)
+ return ERR_PTR(-ENOMEM);
++
++ qhp->wr_waitp = kzalloc(sizeof(*qhp), GFP_KERNEL);
++ if (!qhp->wr_waitp) {
++ ret = -ENOMEM;
++ goto err_free_qhp;
++ }
++
+ qhp->wq.sq.size = sqsize;
+ qhp->wq.sq.memsize =
+ (sqsize + rhp->rdev.hw_queue.t4_eq_status_entries) *
+@@ -1810,9 +1818,10 @@ struct ib_qp *c4iw_create_qp(struct ib_p
+ }
+
+ ret = create_qp(&rhp->rdev, &qhp->wq, &schp->cq, &rchp->cq,
+- ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
++ ucontext ? &ucontext->uctx : &rhp->rdev.uctx,
++ qhp->wr_waitp);
+ if (ret)
+- goto err1;
++ goto err_free_wr_wait;
+
+ attrs->cap.max_recv_wr = rqsize - 1;
+ attrs->cap.max_send_wr = sqsize - 1;
+@@ -1843,35 +1852,35 @@ struct ib_qp *c4iw_create_qp(struct ib_p
+
+ ret = insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid);
+ if (ret)
+- goto err2;
++ goto err_destroy_qp;
+
+ if (udata) {
+ sq_key_mm = kmalloc(sizeof(*sq_key_mm), GFP_KERNEL);
+ if (!sq_key_mm) {
+ ret = -ENOMEM;
+- goto err3;
++ goto err_remove_handle;
+ }
+ rq_key_mm = kmalloc(sizeof(*rq_key_mm), GFP_KERNEL);
+ if (!rq_key_mm) {
+ ret = -ENOMEM;
+- goto err4;
++ goto err_free_sq_key;
+ }
+ sq_db_key_mm = kmalloc(sizeof(*sq_db_key_mm), GFP_KERNEL);
+ if (!sq_db_key_mm) {
+ ret = -ENOMEM;
+- goto err5;
++ goto err_free_rq_key;
+ }
+ rq_db_key_mm = kmalloc(sizeof(*rq_db_key_mm), GFP_KERNEL);
+ if (!rq_db_key_mm) {
+ ret = -ENOMEM;
+- goto err6;
++ goto err_free_sq_db_key;
+ }
+ if (t4_sq_onchip(&qhp->wq.sq)) {
+ ma_sync_key_mm = kmalloc(sizeof(*ma_sync_key_mm),
+ GFP_KERNEL);
+ if (!ma_sync_key_mm) {
+ ret = -ENOMEM;
+- goto err7;
++ goto err_free_rq_db_key;
+ }
+ uresp.flags = C4IW_QPF_ONCHIP;
+ } else
+@@ -1901,7 +1910,7 @@ struct ib_qp *c4iw_create_qp(struct ib_p
+ spin_unlock(&ucontext->mmap_lock);
+ ret = ib_copy_to_udata(udata, &uresp, sizeof uresp);
+ if (ret)
+- goto err8;
++ goto err_free_ma_sync_key;
+ sq_key_mm->key = uresp.sq_key;
+ sq_key_mm->addr = qhp->wq.sq.phys_addr;
+ sq_key_mm->len = PAGE_ALIGN(qhp->wq.sq.memsize);
+@@ -1938,22 +1947,24 @@ struct ib_qp *c4iw_create_qp(struct ib_p
+ attrs->cap.max_send_wr, qhp->wq.rq.qid, qhp->wq.rq.size,
+ qhp->wq.rq.memsize, attrs->cap.max_recv_wr);
+ return &qhp->ibqp;
+-err8:
++err_free_ma_sync_key:
+ kfree(ma_sync_key_mm);
+-err7:
++err_free_rq_db_key:
+ kfree(rq_db_key_mm);
+-err6:
++err_free_sq_db_key:
+ kfree(sq_db_key_mm);
+-err5:
++err_free_rq_key:
+ kfree(rq_key_mm);
+-err4:
++err_free_sq_key:
+ kfree(sq_key_mm);
+-err3:
++err_remove_handle:
+ remove_handle(rhp, &rhp->qpidr, qhp->wq.sq.qid);
+-err2:
++err_destroy_qp:
+ destroy_qp(&rhp->rdev, &qhp->wq,
+ ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
+-err1:
++err_free_wr_wait:
++ kfree(qhp->wr_waitp);
++err_free_qhp:
+ kfree(qhp);
+ return ERR_PTR(ret);
+ }
diff --git a/patches.drivers/iw_cxgb4-atomically-flush-the-qp.patch b/patches.drivers/iw_cxgb4-atomically-flush-the-qp.patch
new file mode 100644
index 0000000000..e23d43f4a9
--- /dev/null
+++ b/patches.drivers/iw_cxgb4-atomically-flush-the-qp.patch
@@ -0,0 +1,76 @@
+From: Steve Wise <swise@opengridcomputing.com>
+Date: Thu, 9 Nov 2017 07:21:26 -0800
+Subject: iw_cxgb4: atomically flush the qp
+Patch-mainline: v4.15-rc1
+Git-commit: bc52e9ca74b9a395897bb640c6671b2cbf716032
+References: bsc#1064802 bsc#1066129
+
+__flush_qp() has a race condition where during the flush operation,
+the qp lock is released allowing another thread to possibly post a WR,
+which corrupts the queue state, possibly causing crashes. The lock was
+released to preserve the cq/qp locking hierarchy of cq first, then qp.
+However releasing the qp lock is not necessary; both RQ and SQ CQ locks
+can be acquired first, followed by the qp lock, and then the RQ and SQ
+flushing can be done w/o unlocking.
+
+Signed-off-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/qp.c | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/qp.c
++++ b/drivers/infiniband/hw/cxgb4/qp.c
+@@ -1255,31 +1255,34 @@ static void __flush_qp(struct c4iw_qp *q
+
+ pr_debug("qhp %p rchp %p schp %p\n", qhp, rchp, schp);
+
+- /* locking hierarchy: cq lock first, then qp lock. */
++ /* locking hierarchy: cqs lock first, then qp lock. */
+ spin_lock_irqsave(&rchp->lock, flag);
++ if (schp != rchp)
++ spin_lock(&schp->lock);
+ spin_lock(&qhp->lock);
+
+ if (qhp->wq.flushed) {
+ spin_unlock(&qhp->lock);
++ if (schp != rchp)
++ spin_unlock(&schp->lock);
+ spin_unlock_irqrestore(&rchp->lock, flag);
+ return;
+ }
+ qhp->wq.flushed = 1;
++ t4_set_wq_in_error(&qhp->wq);
+
+ c4iw_flush_hw_cq(rchp);
+ c4iw_count_rcqes(&rchp->cq, &qhp->wq, &count);
+ rq_flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count);
+- spin_unlock(&qhp->lock);
+- spin_unlock_irqrestore(&rchp->lock, flag);
+
+- /* locking hierarchy: cq lock first, then qp lock. */
+- spin_lock_irqsave(&schp->lock, flag);
+- spin_lock(&qhp->lock);
+ if (schp != rchp)
+ c4iw_flush_hw_cq(schp);
+ sq_flushed = c4iw_flush_sq(qhp);
++
+ spin_unlock(&qhp->lock);
+- spin_unlock_irqrestore(&schp->lock, flag);
++ if (schp != rchp)
++ spin_unlock(&schp->lock);
++ spin_unlock_irqrestore(&rchp->lock, flag);
+
+ if (schp == rchp) {
+ if (t4_clear_cq_armed(&rchp->cq) &&
+@@ -1313,8 +1316,8 @@ static void flush_qp(struct c4iw_qp *qhp
+ rchp = to_c4iw_cq(qhp->ibqp.recv_cq);
+ schp = to_c4iw_cq(qhp->ibqp.send_cq);
+
+- t4_set_wq_in_error(&qhp->wq);
+ if (qhp->ibqp.uobject) {
++ t4_set_wq_in_error(&qhp->wq);
+ t4_set_cq_in_error(&rchp->cq);
+ spin_lock_irqsave(&rchp->comp_handler_lock, flag);
+ (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
diff --git a/patches.drivers/iw_cxgb4-change-pr_debug-to-appropriate-log-level.patch b/patches.drivers/iw_cxgb4-change-pr_debug-to-appropriate-log-level.patch
new file mode 100644
index 0000000000..43292c927a
--- /dev/null
+++ b/patches.drivers/iw_cxgb4-change-pr_debug-to-appropriate-log-level.patch
@@ -0,0 +1,233 @@
+From: Bharat Potnuri <bharat@chelsio.com>
+Date: Wed, 27 Sep 2017 13:05:50 +0530
+Subject: iw_cxgb4: change pr_debug to appropriate log level
+Patch-mainline: v4.15-rc1
+Git-commit: 4d45b7573ba74a278652b0566d779c2aa7ea3df1
+References: bsc#1064802 bsc#1066129
+
+Error logs of iw_cxgb4 needs to be printed by default. This patch
+changes the necessary pr_debug() to appropriate pr_<log level>.
+
+Signed-off-by: Potnuri Bharat Teja <bharat@chelsio.com>
+Reviewed-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 46 ++++++++++++++++-----------------
+ drivers/infiniband/hw/cxgb4/ev.c | 2 -
+ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 4 +-
+ drivers/infiniband/hw/cxgb4/qp.c | 4 +-
+ drivers/infiniband/hw/cxgb4/t4.h | 8 ++---
+ 5 files changed, 32 insertions(+), 32 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -212,7 +212,7 @@ static int c4iw_l2t_send(struct c4iw_rde
+
+ if (c4iw_fatal_error(rdev)) {
+ kfree_skb(skb);
+- pr_debug("%s - device in error state - dropping\n", __func__);
++ pr_err("%s - device in error state - dropping\n", __func__);
+ return -EIO;
+ }
+ error = cxgb4_l2t_send(rdev->lldi.ports[0], skb, l2e);
+@@ -229,7 +229,7 @@ int c4iw_ofld_send(struct c4iw_rdev *rde
+
+ if (c4iw_fatal_error(rdev)) {
+ kfree_skb(skb);
+- pr_debug("%s - device in error state - dropping\n", __func__);
++ pr_err("%s - device in error state - dropping\n", __func__);
+ return -EIO;
+ }
+ error = cxgb4_ofld_send(rdev->lldi.ports[0], skb);
+@@ -263,8 +263,8 @@ static void set_emss(struct c4iw_ep *ep,
+ if (ep->emss < 128)
+ ep->emss = 128;
+ if (ep->emss & 7)
+- pr_debug("Warning: misaligned mtu idx %u mss %u emss=%u\n",
+- TCPOPT_MSS_G(opt), ep->mss, ep->emss);
++ pr_warn("Warning: misaligned mtu idx %u mss %u emss=%u\n",
++ TCPOPT_MSS_G(opt), ep->mss, ep->emss);
+ pr_debug("mss_idx %u mss %u emss=%u\n", TCPOPT_MSS_G(opt), ep->mss,
+ ep->emss);
+ }
+@@ -2314,7 +2314,7 @@ static int pass_open_rpl(struct c4iw_dev
+ struct c4iw_listen_ep *ep = get_ep_from_stid(dev, stid);
+
+ if (!ep) {
+- pr_debug("%s stid %d lookup failure!\n", __func__, stid);
++ pr_warn("%s stid %d lookup failure!\n", __func__, stid);
+ goto out;
+ }
+ pr_debug("ep %p status %d error %d\n", ep,
+@@ -2332,7 +2332,7 @@ static int close_listsrv_rpl(struct c4iw
+ struct c4iw_listen_ep *ep = get_ep_from_stid(dev, stid);
+
+ if (!ep) {
+- pr_debug("%s stid %d lookup failure!\n", __func__, stid);
++ pr_warn("%s stid %d lookup failure!\n", __func__, stid);
+ goto out;
+ }
+ pr_debug("ep %p\n", ep);
+@@ -2464,13 +2464,13 @@ static int pass_accept_req(struct c4iw_d
+
+ parent_ep = (struct c4iw_ep *)get_ep_from_stid(dev, stid);
+ if (!parent_ep) {
+- pr_debug("%s connect request on invalid stid %d\n",
+- __func__, stid);
++ pr_err("%s connect request on invalid stid %d\n",
++ __func__, stid);
+ goto reject;
+ }
+
+ if (state_read(&parent_ep->com) != LISTEN) {
+- pr_debug("%s - listening ep not in LISTEN\n", __func__);
++ pr_err("%s - listening ep not in LISTEN\n", __func__);
+ goto reject;
+ }
+
+@@ -2739,9 +2739,9 @@ static int peer_abort(struct c4iw_dev *d
+ return 0;
+
+ if (cxgb_is_neg_adv(req->status)) {
+- pr_debug("%s Negative advice on abort- tid %u status %d (%s)\n",
+- __func__, ep->hwtid, req->status,
+- neg_adv_str(req->status));
++ pr_warn("%s Negative advice on abort- tid %u status %d (%s)\n",
++ __func__, ep->hwtid, req->status,
++ neg_adv_str(req->status));
+ ep->stats.abort_neg_adv++;
+ mutex_lock(&dev->rdev.stats.lock);
+ dev->rdev.stats.neg_adv++;
+@@ -2781,8 +2781,8 @@ static int peer_abort(struct c4iw_dev *d
+ * do some housekeeping so as to re-initiate the
+ * connection
+ */
+- pr_debug("%s: mpa_rev=%d. Retrying with mpav1\n",
+- __func__, mpa_rev);
++ pr_info("%s: mpa_rev=%d. Retrying with mpav1\n",
++ __func__, mpa_rev);
+ ep->retry_with_mpa_v1 = 1;
+ }
+ break;
+@@ -2808,7 +2808,7 @@ static int peer_abort(struct c4iw_dev *d
+ case ABORTING:
+ break;
+ case DEAD:
+- pr_debug("%s PEER_ABORT IN DEAD STATE!!!!\n", __func__);
++ pr_warn("%s PEER_ABORT IN DEAD STATE!!!!\n", __func__);
+ mutex_unlock(&ep->com.mutex);
+ goto deref_ep;
+ default:
+@@ -3218,7 +3218,7 @@ int c4iw_connect(struct iw_cm_id *cm_id,
+ ep->com.dev = dev;
+ ep->com.qp = get_qhp(dev, conn_param->qpn);
+ if (!ep->com.qp) {
+- pr_debug("%s qpn 0x%x not found!\n", __func__, conn_param->qpn);
++ pr_warn("%s qpn 0x%x not found!\n", __func__, conn_param->qpn);
+ err = -EINVAL;
+ goto fail2;
+ }
+@@ -3571,8 +3571,8 @@ int c4iw_ep_disconnect(struct c4iw_ep *e
+ case MORIBUND:
+ case ABORTING:
+ case DEAD:
+- pr_debug("%s ignoring disconnect ep %p state %u\n",
+- __func__, ep, ep->com.state);
++ pr_info("%s ignoring disconnect ep %p state %u\n",
++ __func__, ep, ep->com.state);
+ break;
+ default:
+ BUG();
+@@ -3676,7 +3676,7 @@ static void passive_ofld_conn_reply(stru
+ rpl_skb = (struct sk_buff *)(unsigned long)req->cookie;
+ BUG_ON(!rpl_skb);
+ if (req->retval) {
+- pr_debug("%s passive open failure %d\n", __func__, req->retval);
++ pr_err("%s passive open failure %d\n", __func__, req->retval);
+ mutex_lock(&dev->rdev.stats.lock);
+ dev->rdev.stats.pas_ofld_conn_fails++;
+ mutex_unlock(&dev->rdev.stats.lock);
+@@ -3893,8 +3893,8 @@ static int rx_pkt(struct c4iw_dev *dev,
+
+ lep = (struct c4iw_ep *)get_ep_from_stid(dev, stid);
+ if (!lep) {
+- pr_debug("%s connect request on invalid stid %d\n",
+- __func__, stid);
++ pr_warn("%s connect request on invalid stid %d\n",
++ __func__, stid);
+ goto reject;
+ }
+
+@@ -4209,8 +4209,8 @@ static int peer_abort_intr(struct c4iw_d
+ return 0;
+ }
+ if (cxgb_is_neg_adv(req->status)) {
+- pr_debug("%s Negative advice on abort- tid %u status %d (%s)\n",
+- __func__, ep->hwtid, req->status,
++ pr_warn("%s Negative advice on abort- tid %u status %d (%s)\n",
++ __func__, ep->hwtid, req->status,
+ neg_adv_str(req->status));
+ goto out;
+ }
+--- a/drivers/infiniband/hw/cxgb4/ev.c
++++ b/drivers/infiniband/hw/cxgb4/ev.c
+@@ -234,7 +234,7 @@ int c4iw_ev_handler(struct c4iw_dev *dev
+ if (atomic_dec_and_test(&chp->refcnt))
+ wake_up(&chp->wait);
+ } else {
+- pr_debug("%s unknown cqid 0x%x\n", __func__, qid);
++ pr_warn("%s unknown cqid 0x%x\n", __func__, qid);
+ spin_unlock_irqrestore(&dev->lock, flag);
+ }
+ return 0;
+--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+@@ -230,8 +230,8 @@ static inline int c4iw_wait_for_reply(st
+
+ ret = wait_for_completion_timeout(&wr_waitp->completion, C4IW_WR_TO);
+ if (!ret) {
+- pr_debug("%s - Device %s not responding (disabling device) - tid %u qpid %u\n",
+- func, pci_name(rdev->lldi.pdev), hwtid, qpid);
++ pr_err("%s - Device %s not responding (disabling device) - tid %u qpid %u\n",
++ func, pci_name(rdev->lldi.pdev), hwtid, qpid);
+ rdev->flags |= T4_FATAL_ERROR;
+ wr_waitp->ret = -EIO;
+ }
+--- a/drivers/infiniband/hw/cxgb4/qp.c
++++ b/drivers/infiniband/hw/cxgb4/qp.c
+@@ -958,8 +958,8 @@ int c4iw_post_send(struct ib_qp *ibqp, s
+ c4iw_invalidate_mr(qhp->rhp, wr->ex.invalidate_rkey);
+ break;
+ default:
+- pr_debug("%s post of type=%d TBD!\n", __func__,
+- wr->opcode);
++ pr_warn("%s post of type=%d TBD!\n", __func__,
++ wr->opcode);
+ err = -EINVAL;
+ }
+ if (err) {
+--- a/drivers/infiniband/hw/cxgb4/t4.h
++++ b/drivers/infiniband/hw/cxgb4/t4.h
+@@ -597,8 +597,8 @@ static inline void t4_swcq_produce(struc
+ {
+ cq->sw_in_use++;
+ if (cq->sw_in_use == cq->size) {
+- pr_debug("%s cxgb4 sw cq overflow cqid %u\n",
+- __func__, cq->cqid);
++ pr_warn("%s cxgb4 sw cq overflow cqid %u\n",
++ __func__, cq->cqid);
+ cq->error = 1;
+ BUG_ON(1);
+ }
+@@ -669,8 +669,8 @@ static inline int t4_next_hw_cqe(struct
+ static inline struct t4_cqe *t4_next_sw_cqe(struct t4_cq *cq)
+ {
+ if (cq->sw_in_use == cq->size) {
+- pr_debug("%s cxgb4 sw cq overflow cqid %u\n",
+- __func__, cq->cqid);
++ pr_warn("%s cxgb4 sw cq overflow cqid %u\n",
++ __func__, cq->cqid);
+ cq->error = 1;
+ BUG_ON(1);
+ return NULL;
diff --git a/patches.drivers/iw_cxgb4-only-call-the-cq-comp_handler-when-the-cq-i.patch b/patches.drivers/iw_cxgb4-only-call-the-cq-comp_handler-when-the-cq-i.patch
new file mode 100644
index 0000000000..992575461f
--- /dev/null
+++ b/patches.drivers/iw_cxgb4-only-call-the-cq-comp_handler-when-the-cq-i.patch
@@ -0,0 +1,71 @@
+From: Steve Wise <swise@opengridcomputing.com>
+Date: Thu, 9 Nov 2017 07:14:43 -0800
+Subject: iw_cxgb4: only call the cq comp_handler when the cq is armed
+Patch-mainline: v4.15-rc1
+Git-commit: cbb40fadd31c6bbc59104e58ac95c6ef492d038b
+References: bsc#1064802 bsc#1066129
+
+The ULPs completion handler should only be called if the CQ is
+armed for notification.
+
+Signed-off-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/ev.c | 8 +++++---
+ drivers/infiniband/hw/cxgb4/qp.c | 20 ++++++++++++--------
+ 2 files changed, 17 insertions(+), 11 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/ev.c
++++ b/drivers/infiniband/hw/cxgb4/ev.c
+@@ -109,9 +109,11 @@ static void post_qp_event(struct c4iw_de
+ if (qhp->ibqp.event_handler)
+ (*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context);
+
+- spin_lock_irqsave(&chp->comp_handler_lock, flag);
+- (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
+- spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
++ if (t4_clear_cq_armed(&chp->cq)) {
++ spin_lock_irqsave(&chp->comp_handler_lock, flag);
++ (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
++ spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
++ }
+ }
+
+ void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
+--- a/drivers/infiniband/hw/cxgb4/qp.c
++++ b/drivers/infiniband/hw/cxgb4/qp.c
+@@ -813,10 +813,12 @@ static void complete_sq_drain_wr(struct
+ t4_swcq_produce(cq);
+ spin_unlock_irqrestore(&schp->lock, flag);
+
+- spin_lock_irqsave(&schp->comp_handler_lock, flag);
+- (*schp->ibcq.comp_handler)(&schp->ibcq,
+- schp->ibcq.cq_context);
+- spin_unlock_irqrestore(&schp->comp_handler_lock, flag);
++ if (t4_clear_cq_armed(&schp->cq)) {
++ spin_lock_irqsave(&schp->comp_handler_lock, flag);
++ (*schp->ibcq.comp_handler)(&schp->ibcq,
++ schp->ibcq.cq_context);
++ spin_unlock_irqrestore(&schp->comp_handler_lock, flag);
++ }
+ }
+
+ static void complete_rq_drain_wr(struct c4iw_qp *qhp, struct ib_recv_wr *wr)
+@@ -842,10 +844,12 @@ static void complete_rq_drain_wr(struct
+ t4_swcq_produce(cq);
+ spin_unlock_irqrestore(&rchp->lock, flag);
+
+- spin_lock_irqsave(&rchp->comp_handler_lock, flag);
+- (*rchp->ibcq.comp_handler)(&rchp->ibcq,
+- rchp->ibcq.cq_context);
+- spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
++ if (t4_clear_cq_armed(&rchp->cq)) {
++ spin_lock_irqsave(&rchp->comp_handler_lock, flag);
++ (*rchp->ibcq.comp_handler)(&rchp->ibcq,
++ rchp->ibcq.cq_context);
++ spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
++ }
+ }
+
+ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
diff --git a/patches.drivers/iw_cxgb4-remove-BUG_ON-usage.patch b/patches.drivers/iw_cxgb4-remove-BUG_ON-usage.patch
new file mode 100644
index 0000000000..a5ddc8168d
--- /dev/null
+++ b/patches.drivers/iw_cxgb4-remove-BUG_ON-usage.patch
@@ -0,0 +1,341 @@
+From: Steve Wise <swise@opengridcomputing.com>
+Date: Thu, 2 Nov 2017 14:11:03 -0700
+Subject: iw_cxgb4: remove BUG_ON() usage.
+Patch-mainline: v4.15-rc1
+Git-commit: ba97b749979ef0ebb821e58ee8b16a84412922f6
+References: bsc#1064802 bsc#1066129
+
+iw_cxgb4 has many BUG_ON()s that were left over from various enhancemnets
+made over the years. Almost all of them should just be removed. Some,
+however indicate a ULP usage error and can be handled w/o bringing down
+the system.
+
+If the condition cannot happen with correctly implemented cxgb4 sw/fw,
+then remove the BUG_ON.
+
+If the condition indicates a misbehaving ULP (like CQ overflows), add
+proper recovery logic.
+
+Signed-off-by: Steve Wise <swise@opengridcomputing.com>
+Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 25 +++++++++----------------
+ drivers/infiniband/hw/cxgb4/cq.c | 10 ----------
+ drivers/infiniband/hw/cxgb4/id_table.c | 1 -
+ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 1 -
+ drivers/infiniband/hw/cxgb4/provider.c | 4 ++--
+ drivers/infiniband/hw/cxgb4/qp.c | 3 ---
+ drivers/infiniband/hw/cxgb4/t4.h | 7 ++-----
+ 7 files changed, 13 insertions(+), 38 deletions(-)
+
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -914,8 +914,6 @@ static int send_mpa_req(struct c4iw_ep *
+ pr_debug("ep %p tid %u pd_len %d\n",
+ ep, ep->hwtid, ep->plen);
+
+- BUG_ON(skb_cloned(skb));
+-
+ mpalen = sizeof(*mpa) + ep->plen;
+ if (mpa_rev_to_use == 2)
+ mpalen += sizeof(struct mpa_v2_conn_params);
+@@ -998,7 +996,6 @@ static int send_mpa_req(struct c4iw_ep *
+ */
+ skb_get(skb);
+ t4_set_arp_err_handler(skb, NULL, arp_failure_discard);
+- BUG_ON(ep->mpa_skb);
+ ep->mpa_skb = skb;
+ ret = c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
+ if (ret)
+@@ -1084,7 +1081,6 @@ static int send_mpa_reject(struct c4iw_e
+ skb_get(skb);
+ set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx);
+ t4_set_arp_err_handler(skb, NULL, mpa_start_arp_failure);
+- BUG_ON(ep->mpa_skb);
+ ep->mpa_skb = skb;
+ ep->snd_seq += mpalen;
+ return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
+@@ -1838,7 +1834,6 @@ static int rx_data(struct c4iw_dev *dev,
+ struct c4iw_qp_attributes attrs;
+
+ update_rx_credits(ep, dlen);
+- BUG_ON(!ep->com.qp);
+ if (status)
+ pr_err("%s Unexpected streaming data." \
+ " qpid %u ep %p state %d tid %u status %d\n",
+@@ -2112,7 +2107,7 @@ static int c4iw_reconnect(struct c4iw_ep
+ * further connection establishment. As we are using the same EP pointer
+ * for reconnect, few skbs are used during the previous c4iw_connect(),
+ * which leaves the EP with inadequate skbs for further
+- * c4iw_reconnect(), Further causing an assert BUG_ON() due to empty
++ * c4iw_reconnect(), Further causing a crash due to an empty
+ * skb_list() during peer_abort(). Allocate skbs which is already used.
+ */
+ size = (CN_MAX_CON_BUF - skb_queue_len(&ep->com.ep_skb_list));
+@@ -2359,7 +2354,6 @@ static int accept_cr(struct c4iw_ep *ep,
+ enum chip_type adapter_type = ep->com.dev->rdev.lldi.adapter_type;
+
+ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+- BUG_ON(skb_cloned(skb));
+
+ skb_get(skb);
+ rpl = cplhdr(skb);
+@@ -2443,7 +2437,6 @@ static int accept_cr(struct c4iw_ep *ep,
+ static void reject_cr(struct c4iw_dev *dev, u32 hwtid, struct sk_buff *skb)
+ {
+ pr_debug("c4iw_dev %p tid %u\n", dev, hwtid);
+- BUG_ON(skb_cloned(skb));
+ skb_trim(skb, sizeof(struct cpl_tid_release));
+ release_tid(&dev->rdev, hwtid, skb);
+ return;
+@@ -2716,7 +2709,7 @@ static int peer_close(struct c4iw_dev *d
+ disconnect = 0;
+ break;
+ default:
+- BUG_ON(1);
++ WARN_ONCE(1, "Bad endpoint state %u\n", ep->com.state);
+ }
+ mutex_unlock(&ep->com.mutex);
+ if (disconnect)
+@@ -2816,7 +2809,7 @@ static int peer_abort(struct c4iw_dev *d
+ mutex_unlock(&ep->com.mutex);
+ goto deref_ep;
+ default:
+- BUG_ON(1);
++ WARN_ONCE(1, "Bad endpoint state %u\n", ep->com.state);
+ break;
+ }
+ dst_confirm(ep->dst);
+@@ -2903,7 +2896,7 @@ static int close_con_rpl(struct c4iw_dev
+ case DEAD:
+ break;
+ default:
+- BUG_ON(1);
++ WARN_ONCE(1, "Bad endpoint state %u\n", ep->com.state);
+ break;
+ }
+ mutex_unlock(&ep->com.mutex);
+@@ -2921,7 +2914,6 @@ static int terminate(struct c4iw_dev *de
+ struct c4iw_qp_attributes attrs;
+
+ ep = get_ep_from_tid(dev, tid);
+- BUG_ON(!ep);
+
+ if (ep && ep->com.qp) {
+ pr_warn("TERM received tid %u qpid %u\n",
+@@ -3021,7 +3013,10 @@ int c4iw_accept_cr(struct iw_cm_id *cm_i
+ goto err_out;
+ }
+
+- BUG_ON(!qp);
++ if (!qp) {
++ err = -EINVAL;
++ goto err_out;
++ }
+
+ set_bit(ULP_ACCEPT, &ep->com.history);
+ if ((conn_param->ord > cur_max_read_depth(ep->com.dev)) ||
+@@ -3579,7 +3574,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *e
+ __func__, ep, ep->com.state);
+ break;
+ default:
+- BUG();
++ WARN_ONCE(1, "Bad endpoint state %u\n", ep->com.state);
+ break;
+ }
+
+@@ -3679,7 +3674,6 @@ static void passive_ofld_conn_reply(stru
+ int ret;
+
+ rpl_skb = (struct sk_buff *)(unsigned long)req->cookie;
+- BUG_ON(!rpl_skb);
+ if (req->retval) {
+ pr_err("%s passive open failure %d\n", __func__, req->retval);
+ mutex_lock(&dev->rdev.stats.lock);
+@@ -4106,7 +4100,6 @@ static void process_work(struct work_str
+ dev = *((struct c4iw_dev **) (skb->cb + sizeof(void *)));
+ opcode = rpl->ot.opcode;
+
+- BUG_ON(!work_handlers[opcode]);
+ ret = work_handlers[opcode](dev, skb);
+ if (!ret)
+ kfree_skb(skb);
+--- a/drivers/infiniband/hw/cxgb4/cq.c
++++ b/drivers/infiniband/hw/cxgb4/cq.c
+@@ -188,7 +188,6 @@ int c4iw_flush_rq(struct t4_wq *wq, stru
+ int flushed = 0;
+ int in_use = wq->rq.in_use - count;
+
+- BUG_ON(in_use < 0);
+ pr_debug("wq %p cq %p rq.in_use %u skip count %u\n",
+ wq, cq, wq->rq.in_use, count);
+ while (in_use--) {
+@@ -231,14 +230,11 @@ int c4iw_flush_sq(struct c4iw_qp *qhp)
+ if (wq->sq.flush_cidx == -1)
+ wq->sq.flush_cidx = wq->sq.cidx;
+ idx = wq->sq.flush_cidx;
+- BUG_ON(idx >= wq->sq.size);
+ while (idx != wq->sq.pidx) {
+ swsqe = &wq->sq.sw_sq[idx];
+- BUG_ON(swsqe->flushed);
+ swsqe->flushed = 1;
+ insert_sq_cqe(wq, cq, swsqe);
+ if (wq->sq.oldest_read == swsqe) {
+- BUG_ON(swsqe->opcode != FW_RI_READ_REQ);
+ advance_oldest_read(wq);
+ }
+ flushed++;
+@@ -259,7 +255,6 @@ static void flush_completed_wrs(struct t
+ if (wq->sq.flush_cidx == -1)
+ wq->sq.flush_cidx = wq->sq.cidx;
+ cidx = wq->sq.flush_cidx;
+- BUG_ON(cidx > wq->sq.size);
+
+ while (cidx != wq->sq.pidx) {
+ swsqe = &wq->sq.sw_sq[cidx];
+@@ -268,8 +263,6 @@ static void flush_completed_wrs(struct t
+ cidx = 0;
+ } else if (swsqe->complete) {
+
+- BUG_ON(swsqe->flushed);
+-
+ /*
+ * Insert this completed cqe into the swcq.
+ */
+@@ -613,7 +606,6 @@ proc_cqe:
+ */
+ if (SQ_TYPE(hw_cqe)) {
+ int idx = CQE_WRID_SQ_IDX(hw_cqe);
+- BUG_ON(idx >= wq->sq.size);
+
+ /*
+ * Account for any unsignaled completions completed by
+@@ -627,7 +619,6 @@ proc_cqe:
+ wq->sq.in_use -= wq->sq.size + idx - wq->sq.cidx;
+ else
+ wq->sq.in_use -= idx - wq->sq.cidx;
+- BUG_ON(wq->sq.in_use <= 0 && wq->sq.in_use >= wq->sq.size);
+
+ wq->sq.cidx = (uint16_t)idx;
+ pr_debug("completing sq idx %u\n", wq->sq.cidx);
+@@ -638,7 +629,6 @@ proc_cqe:
+ } else {
+ pr_debug("completing rq idx %u\n", wq->rq.cidx);
+ *cookie = wq->rq.sw_rq[wq->rq.cidx].wr_id;
+- BUG_ON(t4_rq_empty(wq));
+ if (c4iw_wr_log)
+ c4iw_log_wr_stats(wq, hw_cqe);
+ t4_rq_consume(wq);
+--- a/drivers/infiniband/hw/cxgb4/id_table.c
++++ b/drivers/infiniband/hw/cxgb4/id_table.c
+@@ -73,7 +73,6 @@ void c4iw_id_free(struct c4iw_id_table *
+ unsigned long flags;
+
+ obj -= alloc->start;
+- BUG_ON((int)obj < 0);
+
+ spin_lock_irqsave(&alloc->lock, flags);
+ clear_bit(obj, alloc->table);
+--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+@@ -364,7 +364,6 @@ static inline int _insert_handle(struct
+ idr_preload_end();
+ }
+
+- BUG_ON(ret == -ENOSPC);
+ return ret < 0 ? ret : 0;
+ }
+
+--- a/drivers/infiniband/hw/cxgb4/provider.c
++++ b/drivers/infiniband/hw/cxgb4/provider.c
+@@ -310,8 +310,9 @@ static int c4iw_query_gid(struct ib_devi
+
+ pr_debug("ibdev %p, port %d, index %d, gid %p\n",
+ ibdev, port, index, gid);
++ if (!port)
++ return -EINVAL;
+ dev = to_c4iw_dev(ibdev);
+- BUG_ON(port == 0);
+ memset(&(gid->raw[0]), 0, sizeof(gid->raw));
+ memcpy(&(gid->raw[0]), dev->rdev.lldi.ports[port-1]->dev_addr, 6);
+ return 0;
+@@ -536,7 +537,6 @@ int c4iw_register_device(struct c4iw_dev
+ int i;
+
+ pr_debug("c4iw_dev %p\n", dev);
+- BUG_ON(!dev->rdev.lldi.ports[0]);
+ strlcpy(dev->ibdev.name, "cxgb4_%d", IB_DEVICE_NAME_MAX);
+ memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
+ memcpy(&dev->ibdev.node_guid, dev->rdev.lldi.ports[0]->dev_addr, 6);
+--- a/drivers/infiniband/hw/cxgb4/qp.c
++++ b/drivers/infiniband/hw/cxgb4/qp.c
+@@ -689,7 +689,6 @@ static int build_memreg(struct t4_sq *sq
+ if (++p == (__be64 *)&sq->queue[sq->size])
+ p = (__be64 *)sq->queue;
+ }
+- BUG_ON(rem < 0);
+ while (rem) {
+ *p = 0;
+ rem -= sizeof(*p);
+@@ -1568,7 +1567,6 @@ int c4iw_modify_qp(struct c4iw_dev *rhp,
+ case C4IW_QP_STATE_RTS:
+ switch (attrs->next_state) {
+ case C4IW_QP_STATE_CLOSING:
+- BUG_ON(kref_read(&qhp->ep->com.kref) < 2);
+ t4_set_wq_in_error(&qhp->wq);
+ set_state(qhp, C4IW_QP_STATE_CLOSING);
+ ep = qhp->ep;
+@@ -1677,7 +1675,6 @@ err:
+ set_state(qhp, C4IW_QP_STATE_ERROR);
+ free = 1;
+ abort = 1;
+- BUG_ON(!ep);
+ flush_qp(qhp);
+ wake_up(&qhp->wait);
+ out:
+--- a/drivers/infiniband/hw/cxgb4/t4.h
++++ b/drivers/infiniband/hw/cxgb4/t4.h
+@@ -425,7 +425,6 @@ static inline void t4_sq_produce(struct
+
+ static inline void t4_sq_consume(struct t4_wq *wq)
+ {
+- BUG_ON(wq->sq.in_use < 1);
+ if (wq->sq.cidx == wq->sq.flush_cidx)
+ wq->sq.flush_cidx = -1;
+ wq->sq.in_use--;
+@@ -600,7 +599,8 @@ static inline void t4_swcq_produce(struc
+ pr_warn("%s cxgb4 sw cq overflow cqid %u\n",
+ __func__, cq->cqid);
+ cq->error = 1;
+- BUG_ON(1);
++ cq->sw_in_use--;
++ return;
+ }
+ if (++cq->sw_pidx == cq->size)
+ cq->sw_pidx = 0;
+@@ -608,7 +608,6 @@ static inline void t4_swcq_produce(struc
+
+ static inline void t4_swcq_consume(struct t4_cq *cq)
+ {
+- BUG_ON(cq->sw_in_use < 1);
+ cq->sw_in_use--;
+ if (++cq->sw_cidx == cq->size)
+ cq->sw_cidx = 0;
+@@ -654,7 +653,6 @@ static inline int t4_next_hw_cqe(struct
+ ret = -EOVERFLOW;
+ cq->error = 1;
+ pr_err("cq overflow cqid %u\n", cq->cqid);
+- BUG_ON(1);
+ } else if (t4_valid_cqe(cq, &cq->queue[cq->cidx])) {
+
+ /* Ensure CQE is flushed to memory */
+@@ -672,7 +670,6 @@ static inline struct t4_cqe *t4_next_sw_
+ pr_warn("%s cxgb4 sw cq overflow cqid %u\n",
+ __func__, cq->cqid);
+ cq->error = 1;
+- BUG_ON(1);
+ return NULL;
+ }
+ if (cq->sw_in_use)
diff --git a/patches.drivers/net-sched-add-couple-of-goto_chain-helpers.patch b/patches.drivers/net-sched-add-couple-of-goto_chain-helpers.patch
new file mode 100644
index 0000000000..324c0083df
--- /dev/null
+++ b/patches.drivers/net-sched-add-couple-of-goto_chain-helpers.patch
@@ -0,0 +1,64 @@
+From: Jiri Pirko <jiri@mellanox.com>
+Date: Wed, 23 Aug 2017 10:08:19 +0200
+Subject: net: sched: add couple of goto_chain helpers
+Patch-mainline: v4.14-rc1
+Git-commit: e457d86ada27cbd2f46ded75d4b4bc06e26d0e2e
+References: bsc#1064802 bsc#1066129
+
+Add helpers to find out if a gact instance is goto_chain termination
+action and to get chain index.
+
+Signed-off-by: Jiri Pirko <jiri@mellanox.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ include/net/tc_act/tc_gact.h | 20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+--- a/include/net/tc_act/tc_gact.h
++++ b/include/net/tc_act/tc_gact.h
+@@ -15,7 +15,8 @@ struct tcf_gact {
+ };
+ #define to_gact(a) ((struct tcf_gact *)a)
+
+-static inline bool __is_tcf_gact_act(const struct tc_action *a, int act)
++static inline bool __is_tcf_gact_act(const struct tc_action *a, int act,
++ bool is_ext)
+ {
+ #ifdef CONFIG_NET_CLS_ACT
+ struct tcf_gact *gact;
+@@ -24,7 +25,8 @@ static inline bool __is_tcf_gact_act(con
+ return false;
+
+ gact = to_gact(a);
+- if (gact->tcf_action == act)
++ if ((!is_ext && gact->tcf_action == act) ||
++ (is_ext && TC_ACT_EXT_CMP(gact->tcf_action, act)))
+ return true;
+
+ #endif
+@@ -33,12 +35,22 @@ static inline bool __is_tcf_gact_act(con
+
+ static inline bool is_tcf_gact_shot(const struct tc_action *a)
+ {
+- return __is_tcf_gact_act(a, TC_ACT_SHOT);
++ return __is_tcf_gact_act(a, TC_ACT_SHOT, false);
+ }
+
+ static inline bool is_tcf_gact_trap(const struct tc_action *a)
+ {
+- return __is_tcf_gact_act(a, TC_ACT_TRAP);
++ return __is_tcf_gact_act(a, TC_ACT_TRAP, false);
++}
++
++static inline bool is_tcf_gact_goto_chain(const struct tc_action *a)
++{
++ return __is_tcf_gact_act(a, TC_ACT_GOTO_CHAIN, true);
++}
++
++static inline u32 tcf_gact_goto_chain_index(const struct tc_action *a)
++{
++ return a->goto_chain->index;
+ }
+
+ #endif /* __NET_TC_GACT_H */
diff --git a/patches.drivers/net-sched-introduce-helper-to-identify-gact-pass-act.patch b/patches.drivers/net-sched-introduce-helper-to-identify-gact-pass-act.patch
new file mode 100644
index 0000000000..d005ffe52c
--- /dev/null
+++ b/patches.drivers/net-sched-introduce-helper-to-identify-gact-pass-act.patch
@@ -0,0 +1,31 @@
+From: Jiri Pirko <jiri@mellanox.com>
+Date: Mon, 25 Sep 2017 10:58:21 +0200
+Subject: net: sched: introduce helper to identify gact pass action
+Patch-mainline: v4.15-rc1
+Git-commit: 3b8e9238a8d194e82f0202a5fb68a63686ebe420
+References: bsc#1064802 bsc#1066129
+
+Introduce a helper called is_tcf_gact_pass which could be used to
+tell if the action is gact pass or not.
+
+Signed-off-by: Jiri Pirko <jiri@mellanox.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ include/net/tc_act/tc_gact.h | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/include/net/tc_act/tc_gact.h
++++ b/include/net/tc_act/tc_gact.h
+@@ -33,6 +33,11 @@ static inline bool __is_tcf_gact_act(con
+ return false;
+ }
+
++static inline bool is_tcf_gact_ok(const struct tc_action *a)
++{
++ return __is_tcf_gact_act(a, TC_ACT_OK, false);
++}
++
+ static inline bool is_tcf_gact_shot(const struct tc_action *a)
+ {
+ return __is_tcf_gact_act(a, TC_ACT_SHOT, false);
diff --git a/patches.drivers/net-sched-introduce-helper-to-identify-gact-trap-act.patch b/patches.drivers/net-sched-introduce-helper-to-identify-gact-trap-act.patch
new file mode 100644
index 0000000000..3cd343c1dc
--- /dev/null
+++ b/patches.drivers/net-sched-introduce-helper-to-identify-gact-trap-act.patch
@@ -0,0 +1,52 @@
+From: Jiri Pirko <jiri@mellanox.com>
+Date: Tue, 6 Jun 2017 14:12:03 +0200
+Subject: net: sched: introduce helper to identify gact trap action
+Patch-mainline: v4.13-rc1
+Git-commit: 5a4d1fee2f844813cb2092b7a06b0e20ed9e2fa4
+References: bsc#1064802 bsc#1066129
+
+Introduce a helper called is_tcf_gact_trap which could be used to
+tell if the action is gact trap or not.
+
+Signed-off-by: Jiri Pirko <jiri@mellanox.com>
+Reviewed-by: Yotam Gigi <yotamg@mellanox.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ include/net/tc_act/tc_gact.h | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+--- a/include/net/tc_act/tc_gact.h
++++ b/include/net/tc_act/tc_gact.h
+@@ -15,7 +15,7 @@ struct tcf_gact {
+ };
+ #define to_gact(a) ((struct tcf_gact *)a)
+
+-static inline bool is_tcf_gact_shot(const struct tc_action *a)
++static inline bool __is_tcf_gact_act(const struct tc_action *a, int act)
+ {
+ #ifdef CONFIG_NET_CLS_ACT
+ struct tcf_gact *gact;
+@@ -24,10 +24,21 @@ static inline bool is_tcf_gact_shot(cons
+ return false;
+
+ gact = to_gact(a);
+- if (gact->tcf_action == TC_ACT_SHOT)
++ if (gact->tcf_action == act)
+ return true;
+
+ #endif
+ return false;
+ }
++
++static inline bool is_tcf_gact_shot(const struct tc_action *a)
++{
++ return __is_tcf_gact_act(a, TC_ACT_SHOT);
++}
++
++static inline bool is_tcf_gact_trap(const struct tc_action *a)
++{
++ return __is_tcf_gact_act(a, TC_ACT_TRAP);
++}
++
+ #endif /* __NET_TC_GACT_H */
diff --git a/series.conf b/series.conf
index fe2bfde49c..0ca4d4cab2 100644
--- a/series.conf
+++ b/series.conf
@@ -3030,6 +3030,7 @@
patches.drivers/e1000e-use-disable_hardirq-also-for-MSIX-vectors-in-.patch
patches.drivers/net-mlxfw-remove-redundant-goto-on-error-check.patch
patches.drivers/net-sched-introduce-a-TRAP-control-action.patch
+ patches.drivers/net-sched-introduce-helper-to-identify-gact-trap-act.patch
patches.drivers/s390-qeth-remove-support-for-IPA_IP_FRAGMENTATION.patch
patches.drivers/s390-qeth-remove-skb_is_nonlinear-check-on-IQD.patch
patches.drivers/s390-qeth-query-IPv6-IPA-support-on-HiperSockets.patch
@@ -4784,6 +4785,7 @@
patches.drivers/liquidio-make-VF-driver-notify-NIC-firmware-of-MTU-c.patch
patches.fixes/udp-remove-unreachable-ufo-branches.patch
patches.drivers/liquidio-change-manner-of-detecting-whether-or-not-N.patch
+ patches.drivers/net-sched-add-couple-of-goto_chain-helpers.patch
patches.drivers/net-sock-allow-the-user-to-set-negative-peek-offset.patch
patches.drivers/bpf-verifier-when-pruning-a-branch-ignore-its-write-.patch
patches.drivers/bpf-verifier-remove-varlen_map_value_access-flag.patch
@@ -5584,12 +5586,22 @@
patches.drivers/s390-qeth-add-VNICC-enable-disable-support.patch
patches.drivers/s390-qeth-add-VNICC-get-set-timeout-support.patch
patches.drivers/cxgb4-add-new-T5-pci-device-id-s-34929cb4.patch
+ patches.drivers/cxgb4-avoid-stall-while-shutting-down-the-adapter.patch
+ patches.drivers/cxgb4-add-tc-flower-offload-skeleton.patch
+ patches.drivers/cxgb4-add-basic-tc-flower-offload-support.patch
+ patches.drivers/cxgb4-add-support-to-offload-action-vlan.patch
+ patches.drivers/cxgb4-fetch-stats-for-offloaded-tc-flower-flows.patch
+ patches.drivers/cxgb4-do-DCB-state-reset-in-couple-of-places.patch
patches.drivers/qed-Add-iWARP-enablement-support.patch
patches.drivers/qed-Add-iWARP-out-of-order-support.patch
patches.drivers/qed-Fix-maximum-number-of-CQs-for-iWARP.patch
patches.drivers/qed-iWARP-Add-check-for-errors-on-a-SYN-packet.patch
+ patches.drivers/net-sched-introduce-helper-to-identify-gact-pass-act.patch
+ patches.drivers/cxgb4-make-function-ch_flower_stats_cb-fixes-warning.patch
patches.drivers/ibmvnic-113-Set-state-UP.patch
+ patches.drivers/cxgb4-Update-comment-for-min_mtu.patch
patches.drivers/cxgb4-add-new-T6-pci-device-id-s-acd669a8.patch
+ patches.drivers/cxgb4vf-make-a-couple-of-functions-static.patch
patches.drivers/i40e-add-private-flag-to-control-source-pruning.patch
patches.drivers/net-mlx5-Avoid-NULL-pointer-dereference-on-steering-.patch
patches.drivers/qed-Delete-redundant-check-on-dcb_app-priority.patch
@@ -5607,20 +5619,59 @@
patches.drivers/qed-Add-iWARP-support-for-fpdu-spanned-over-more-tha.patch
patches.drivers/net-mlx4_en-Use-__force-to-fix-a-sparse-warning-in-T.patch
patches.drivers/i40e-Avoid-some-useless-variables-and-initializers-i.patch
+ patches.drivers/cxgb4-Add-support-for-new-flash-parts.patch
patches.drivers/cxgb4-add-new-T5-pci-device-id-s-652faa98.patch
patches.drivers/net-smc-dev_put-for-netdev-after-usage-of-ib_query_g.patch
+ patches.drivers/cxgb4-implement-ethtool-dump-data-operations.patch
+ patches.drivers/cxgb4-collect-register-dump.patch
+ patches.drivers/cxgb4-collect-on-chip-memory-dump.patch
+ patches.drivers/cxgb4-collect-firmware-mbox-and-device-log-dump.patch
+ patches.drivers/cxgb4-update-API-for-TP-indirect-register-access.patch
+ patches.drivers/cxgb4-collect-TP-dump.patch
+ patches.drivers/cxgb4-collect-hardware-module-dumps.patch
+ patches.drivers/cxgb4-collect-IBQ-and-OBQ-dumps.patch
+ patches.drivers/cxgb4-fix-missing-break-in-switch-and-indent-return-.patch
patches.drivers/qed-Fix-iWARP-out-of-order-flow.patch
patches.drivers/ibmvnic-115-Enable-scatter-gather-support.patch
patches.drivers/ibmvnic-116-Enable-TSO-support.patch
patches.drivers/ibmvnic-117-Let-users-change-net-device-features.patch
+ patches.drivers/cxgb4-add-tc-flower-match-support-for-TOS.patch
+ patches.drivers/cxgb4-add-tc-flower-match-support-for-vlan.patch
+ patches.drivers/cxgb4-add-tc-flower-support-for-action-PASS.patch
+ patches.drivers/cxgb4-add-tc-flower-support-for-ETH-DMAC-rewrite.patch
+ patches.drivers/cxgb4-introduce-SMT-ops-to-prepare-for-SMAC-rewrite-.patch
+ patches.drivers/cxgb4-add-tc-flower-support-for-ETH-SMAC-rewrite.patch
+ patches.drivers/cxgb4-introduce-fw_filter2_wr-to-prepare-for-L3-L4-r.patch
+ patches.drivers/cxgb4-add-tc-flower-support-for-L3-L4-rewrite.patch
patches.drivers/Bluetooth-hci_bcm-Add-support-for-BCM2E7E
+ patches.drivers/cxgb4-fix-overflow-in-collecting-IBQ-and-OBQ-dump.patch
+ patches.drivers/cxgb4-collect-hardware-LA-dumps.patch
+ patches.drivers/cxgb4-collect-CIM-queue-configuration-dump.patch
+ patches.drivers/cxgb4-collect-RSS-dumps.patch
+ patches.drivers/cxgb4-collect-TID-info-dump.patch
+ patches.drivers/cxgb4-collect-MPS-TCAM-dump.patch
+ patches.drivers/cxgb4-collect-PBT-tables-dump.patch
+ patches.drivers/cxgb4-collect-hardware-scheduler-dumps.patch
+ patches.drivers/cxgb4-collect-hardware-misc-dumps.patch
patches.drivers/ibmvnic-118-Update-reset-infrastructure-to-support-tunab.patch
patches.drivers/ibmvnic-119-Fix-failover-error-path-for-non-fatal-resets.patch
+ patches.drivers/cxgb3-Check-and-handle-the-dma-mapping-errors.patch
+ patches.drivers/cxgb4-save-additional-filter-tuple-field-shifts-in-t.patch
+ patches.drivers/cxgb4-initialize-hash-filter-configuration.patch
+ patches.drivers/cxgb4-add-support-to-create-hash-filters.patch
+ patches.drivers/cxgb4-add-support-to-delete-hash-filter.patch
+ patches.drivers/cxgb4-add-support-to-retrieve-stats-for-hash-filters.patch
+ patches.drivers/cxgb4-add-support-to-create-hash-filters-via-tc-flow.patch
+ patches.drivers/cxgb4-fix-error-return-code-in-cxgb4_set_hash_filter.patch
patches.drivers/cxgb4-add-new-T6-pci-device-id-s-36bf994a.patch
+ patches.drivers/cxgb4vf-define-get_fecparam-ethtool-callback.patch
patches.drivers/iwlwifi-mvm-add-missing-lq_color.patch
patches.drivers/ibmvnic-120-Add-vnic-client-data-to-login-buffer.patch
+ patches.drivers/cxgb4-collect-vpd-info-directly-from-hardware.patch
patches.drivers/iwlwifi-mvm-reset-seq-num-after-restart.patch
patches.drivers/iwlwifi-fix-multi-queue-notification-for-a000-device.patch
+ patches.drivers/cxgb4-collect-LE-TCAM-dump.patch
+ patches.drivers/cxgb4-collect-SGE-queue-context-dump.patch
patches.drivers/ibmvnic-121-Feature-implementation-of-Vital-Product-Data.patch
patches.drivers/IB-core-Fix-use-workqueue-without-WQ_MEM_RECLAIM.patch
patches.drivers/IB-core-Fix-calculation-of-maximum-RoCE-MTU.patch
@@ -5634,9 +5685,17 @@
patches.drivers/RDMA-qedr-Missing-error-code-in-qedr_init_user_queue.patch
patches.drivers/RDMA-qedr-fix-build-error-without-ipv6.patch
patches.drivers/IB-Move-PCI-dependency-from-root-KConfig-to-HW-s-KCo.patch
+ patches.drivers/IB-cxgb3-cxgb4-Remove-unneeded-config-dependencies.patch
patches.drivers/IB-uverbs-clean-up-INIT_UDATA_BUF_OR_NULL-usage.patch
+ patches.drivers/iw_cxgb4-Remove-__func__-parameter-from-pr_debug.patch
+ patches.drivers/iw_cxgb4-change-pr_debug-to-appropriate-log-level.patch
patches.drivers/IB-hfi1-Extend-input-hdr-tracing-for-packet-type.patch
patches.drivers/RDMA-qedr-Fix-rdma_type-initialization.patch
+ patches.drivers/iw_cxgb4-allocate-wait-object-for-each-memory-object.patch
+ patches.drivers/iw_cxgb4-allocate-wait-object-for-each-cq-object.patch
+ patches.drivers/iw_cxgb4-allocate-wait-object-for-each-qp-object.patch
+ patches.drivers/iw_cxgb4-allocate-wait-object-for-each-ep-object.patch
+ patches.drivers/iw_cxgb4-add-referencing-to-wait-objects.patch
patches.drivers/i40iw-Do-not-retransmit-MPA-request-after-it-is-ACKe.patch
patches.drivers/i40iw-Do-not-generate-CQE-for-RTR-on-QP-flush.patch
patches.drivers/i40iw-Do-not-allow-posting-WR-after-QP-is-flushed.patch
@@ -5650,6 +5709,10 @@
patches.drivers/IB-rxe-put-the-pool-on-allocation-failure.patch
patches.drivers/infiniband-add-MMU-dependency-for-user_mem.patch
patches.drivers/IB-core-Fix-endianness-annotation-in-rdma_is_multica.patch
+ patches.drivers/RDMA-cxgb4-Fix-indentation.patch
+ patches.drivers/RDMA-cxgb4-Remove-the-obsolete-kernel-module-option-.patch
+ patches.drivers/RDMA-cxgb4-Suppress-gcc-7-fall-through-complaints.patch
+ patches.drivers/RDMA-cxgb4-Remove-a-set-but-not-used-variable.patch
patches.drivers/IB-hfi1-Mask-out-A-bit-from-psn-trace.patch
patches.drivers/IB-hfi1-Eliminate-allocation-while-atomic.patch
patches.drivers/IB-hfi1-Set-hdr_type-when-tx-req-is-allocated.patch
@@ -5664,12 +5727,16 @@
patches.drivers/i40iw-Remove-UDA-QP-from-QoS-list-if-creation-fails.patch
patches.drivers/i40iw-Move-cqp_cmd_head-init-to-CQP-initialization.patch
patches.drivers/IB-cm-Fix-memory-corruption-in-handling-CM-request.patch
+ patches.drivers/RDMA-cxgb4-Declare-stag-as-__be32.patch
patches.drivers/bnxt_re-Implement-the-shutdown-hook-of-the-L2-RoCE-d.patch
patches.drivers/IB-mlx4-Fix-RSS-s-QPC-attributes-assignments.patch
+ patches.drivers/RDMA-cxgb4-Annotate-r2-and-stag-as-__be32.patch
patches.drivers/IB-core-Avoid-crash-on-pkey-enforcement-failed-in-re.patch
patches.drivers/IB-rxe-don-t-crash-if-allocation-of-crc-algorithm-fa.patch
+ patches.drivers/RDMA-cxgb4-Protect-from-possible-dereference.patch
patches.drivers/bnxt_re-fix-a-crash-in-qp-error-event-processing.patch
patches.drivers/bnxt_re-changing-the-ip-address-shouldn-t-affect-new.patch
+ patches.drivers/iw_cxgb4-remove-BUG_ON-usage.patch
patches.drivers/IB-hfi1-Allow-MgmtAllowed-on-B2B-setups.patch
patches.drivers/IB-core-Convert-OPA-AH-to-IB-for-Extended-LIDs-only.patch
patches.drivers/IB-hfi1-Mask-upper-16Bits-of-Extended-LID-prior-to-r.patch
@@ -5679,6 +5746,9 @@
patches.drivers/RDMA-bnxt_re-synchronize-poll_cq-and-req_notify_cq-v.patch
patches.drivers/RDMA-core-avoid-uninitialized-variable-warning-in-cr.patch
patches.drivers/IB-core-Only-maintain-real-QPs-in-the-security-lists.patch
+ patches.drivers/iw_cxgb4-Fix-possible-circular-dependency-locking-wa.patch
+ patches.drivers/iw_cxgb4-only-call-the-cq-comp_handler-when-the-cq-i.patch
+ patches.drivers/iw_cxgb4-atomically-flush-the-qp.patch
patches.suse/mm-Handle-0-flags-in-_calc_vm_trans-macro.patch
patches.suse/mm-introduce-MAP_SHARED_VALIDATE-a-mechanism-to-safe.patch
patches.suse/mm-Remove-VM_FAULT_HWPOISON_LARGE_MASK.patch