Johnny Hughes
2019-02-04 c1f36c28393a7bb126cbf436cd6a4077a5b5c313
added extra source files
61 files added
6837 ■■■■■ changed files
SOURCES/0001-BACKPORT-arm64-cmpwait-Clear-event-register-before-a.patch 44 ●●●●● patch | view | raw | blame | history
SOURCES/0001-net-mvpp2-remove-useless-goto.patch 31 ●●●●● patch | view | raw | blame | history
SOURCES/0002-BACKPORT-arm64-barrier-Implement-smp_cond_load_relax.patch 48 ●●●●● patch | view | raw | blame | history
SOURCES/0002-net-mvpp2-set-the-Rx-FIFO-size-depending-on-the-port.patch 99 ●●●●● patch | view | raw | blame | history
SOURCES/0003-BACKPORT-arm64-locking-Replace-ticket-lock-implement.patch 217 ●●●●● patch | view | raw | blame | history
SOURCES/0003-net-mvpp2-initialize-the-Tx-FIFO-size.patch 83 ●●●●● patch | view | raw | blame | history
SOURCES/0004-BACKPORT-arm64-kconfig-Ensure-spinlock-fastpaths-are.patch 47 ●●●●● patch | view | raw | blame | history
SOURCES/0004-net-mvpp2-initialize-the-RSS-tables.patch 103 ●●●●● patch | view | raw | blame | history
SOURCES/0005-BACKPORT-ahci-Disable-LPM-on-Lenovo-50-series-laptop.patch 160 ●●●●● patch | view | raw | blame | history
SOURCES/0005-net-mvpp2-limit-TSO-segments-and-use-stop-wake-thres.patch 88 ●●●●● patch | view | raw | blame | history
SOURCES/0006-BACKPORT-ACPI-bus-Introduce-acpi_get_match_data-func.patch 80 ●●●●● patch | view | raw | blame | history
SOURCES/0006-net-mvpp2-use-the-aggr-txq-size-define-everywhere.patch 51 ●●●●● patch | view | raw | blame | history
SOURCES/0007-BACKPORT-ACPI-bus-Remove-checks-in-acpi_get_match_da.patch 53 ●●●●● patch | view | raw | blame | history
SOURCES/0007-net-mvpp2-simplify-the-Tx-desc-set-DMA-logic.patch 116 ●●●●● patch | view | raw | blame | history
SOURCES/0008-BACKPORT-ACPI-bus-Rename-acpi_get_match_data-to-acpi.patch 73 ●●●●● patch | view | raw | blame | history
SOURCES/0008-net-mvpp2-add-ethtool-GOP-statistics.patch 375 ●●●●● patch | view | raw | blame | history
SOURCES/0009-BACKPORT-ata-Disable-AHCI-ALPM-feature-for-Ampere-Co.patch 72 ●●●●● patch | view | raw | blame | history
SOURCES/0009-net-mvpp2-fix-GOP-statistics-loop-start-and-stop-con.patch 180 ●●●●● patch | view | raw | blame | history
SOURCES/0010-BACKPORT-perf-xgene-Fix-IOB-SLOW-PMU-parser-error.patch 39 ●●●●● patch | view | raw | blame | history
SOURCES/0010-net-mvpp2-fix-the-txq_init-error-path.patch 70 ●●●●● patch | view | raw | blame | history
SOURCES/0011-BACKPORT-iommu-enable-bypass-transaction-caching-for.patch 49 ●●●●● patch | view | raw | blame | history
SOURCES/0011-net-mvpp2-cleanup-probed-ports-in-the-probe-error-pa.patch 55 ●●●●● patch | view | raw | blame | history
SOURCES/0012-net-mvpp2-do-not-disable-GMAC-padding.patch 51 ●●●●● patch | view | raw | blame | history
SOURCES/0013-net-mvpp2-check-ethtool-sets-the-Tx-ring-size-is-to-.patch 41 ●●●●● patch | view | raw | blame | history
SOURCES/0014-net-mvpp2-allocate-zeroed-tx-descriptors.patch 39 ●●●●● patch | view | raw | blame | history
SOURCES/0015-net-mvpp2-fix-the-RSS-table-entry-offset.patch 34 ●●●●● patch | view | raw | blame | history
SOURCES/0016-net-mvpp2-only-free-the-TSO-header-buffers-when-it-w.patch 50 ●●●●● patch | view | raw | blame | history
SOURCES/0017-net-mvpp2-split-the-max-ring-size-from-the-default-o.patch 92 ●●●●● patch | view | raw | blame | history
SOURCES/0018-net-mvpp2-align-values-in-ethtool-get_coalesce.patch 36 ●●●●● patch | view | raw | blame | history
SOURCES/0019-net-mvpp2-report-the-tx-usec-coalescing-information-.patch 33 ●●●●● patch | view | raw | blame | history
SOURCES/0020-net-mvpp2-adjust-the-coalescing-parameters.patch 38 ●●●●● patch | view | raw | blame | history
SOURCES/0021-device-property-Introduce-fwnode_get_mac_address.patch 110 ●●●●● patch | view | raw | blame | history
SOURCES/0022-device-property-Introduce-fwnode_get_phy_mode.patch 96 ●●●●● patch | view | raw | blame | history
SOURCES/0023-device-property-Introduce-fwnode_irq_get.patch 114 ●●●●● patch | view | raw | blame | history
SOURCES/0024-device-property-Allow-iterating-over-available-child.patch 85 ●●●●● patch | view | raw | blame | history
SOURCES/0025-net-mvpp2-simplify-maintaining-enabled-ports-list.patch 94 ●●●●● patch | view | raw | blame | history
SOURCES/0026-net-mvpp2-use-device_-fwnode_-APIs-instead-of-of_.patch 173 ●●●●● patch | view | raw | blame | history
SOURCES/0027-net-mvpp2-enable-ACPI-support-in-the-driver.patch 305 ●●●●● patch | view | raw | blame | history
SOURCES/0028-mvpp2-fix-multicast-address-filter.patch 58 ●●●●● patch | view | raw | blame | history
SOURCES/0029-net-mvpp2-Add-hardware-offloading-for-VLAN-filtering.patch 597 ●●●●● patch | view | raw | blame | history
SOURCES/0030-net-mvpp2-use-the-same-buffer-pool-for-all-ports.patch 228 ●●●●● patch | view | raw | blame | history
SOURCES/0031-net-mvpp2-update-the-BM-buffer-free-destroy-logic.patch 118 ●●●●● patch | view | raw | blame | history
SOURCES/0032-net-mvpp2-use-a-data-size-of-10kB-for-Tx-FIFO-on-por.patch 80 ●●●●● patch | view | raw | blame | history
SOURCES/0033-net-mvpp2-enable-UDP-TCP-checksum-over-IPv6.patch 35 ●●●●● patch | view | raw | blame | history
SOURCES/0034-net-mvpp2-jumbo-frames-support.patch 206 ●●●●● patch | view | raw | blame | history
SOURCES/0035-net-mvpp2-mvpp2_check_hw_buf_num-can-be-static.patch 30 ●●●●● patch | view | raw | blame | history
SOURCES/0036-net-mvpp2-Simplify-MAC-filtering-function-parameters.patch 115 ●●●●● patch | view | raw | blame | history
SOURCES/0037-net-mvpp2-Add-support-for-unicast-filtering.patch 465 ●●●●● patch | view | raw | blame | history
SOURCES/0038-net-mvpp2-use-correct-index-on-array-mvpp2_pools.patch 36 ●●●●● patch | view | raw | blame | history
SOURCES/0039-net-mvpp2-Make-mvpp2_prs_hw_read-a-parser-entry-init.patch 184 ●●●●● patch | view | raw | blame | history
SOURCES/0040-net-mvpp2-Don-t-use-dynamic-allocs-for-local-variabl.patch 624 ●●●●● patch | view | raw | blame | history
SOURCES/0041-net-mvpp2-Use-relaxed-I-O-in-data-path.patch 127 ●●●●● patch | view | raw | blame | history
SOURCES/0042-net-mvpp2-Fix-parser-entry-init-boundary-check.patch 34 ●●●●● patch | view | raw | blame | history
SOURCES/0043-net-mvpp2-Fix-TCAM-filter-reserved-range.patch 43 ●●●●● patch | view | raw | blame | history
SOURCES/0044-net-mvpp2-Fix-DMA-address-mask-size.patch 80 ●●●●● patch | view | raw | blame | history
SOURCES/0045-net-mvpp2-Fix-clk-error-path-in-mvpp2_probe.patch 87 ●●●●● patch | view | raw | blame | history
SOURCES/0046-net-mvpp2-Fix-clock-resource-by-adding-missing-mg_co.patch 85 ●●●●● patch | view | raw | blame | history
SOURCES/centos-ca-secureboot.der patch | view | raw | blame | history
SOURCES/centos-kpatch.x509 patch | view | raw | blame | history
SOURCES/centos-ldup.x509 patch | view | raw | blame | history
SOURCES/centossecureboot001.crt 81 ●●●●● patch | view | raw | blame | history
SOURCES/0001-BACKPORT-arm64-cmpwait-Clear-event-register-before-a.patch
New file
@@ -0,0 +1,44 @@
From 3c9a17d64f5fb028a937b135ba4cfaa7e17fcce1 Mon Sep 17 00:00:00 2001
From: Khuong Dinh <khuong.dinh@amperecomputing.com>
Date: Mon, 30 Apr 2018 13:56:32 +0100
Subject: [PATCH 01/11] BACKPORT: arm64: cmpwait: Clear event register before
 arming exclusive monitor
When waiting for a cacheline to change state in cmpwait, we may immediately
wake-up the first time around the outer loop if the event register was
already set (for example, because of the event stream).
Avoid these spurious wakeups by explicitly clearing the event register
before loading the cacheline and setting the exclusive monitor.
This patch is required to fix kernel lock up due to new implementation of
queued read write locking from kernel 4.14.
This patch is backported from:
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?h=next-20180913&id=1cfc63b5ae60fe7e01773f38132f98d8b13a99a0
Change-Id: I1151172c53f0049a54dfae892ff423ab14b067e7
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Khuong Dinh <khuong.dinh@amperecomputing.com>
---
 arch/arm64/include/asm/cmpxchg.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h
index ae852ad..0f2e1ab 100644
--- a/arch/arm64/include/asm/cmpxchg.h
+++ b/arch/arm64/include/asm/cmpxchg.h
@@ -229,7 +229,9 @@
     unsigned long tmp;                        \
                                     \
     asm volatile(                            \
-    "    ldxr" #sz "\t%" #w "[tmp], %[v]\n"        \
+    "    sevl\n"                            \
+    "    wfe\n"                            \
+    "    ldxr" #sz "\t%" #w "[tmp], %[v]\n"            \
     "    eor    %" #w "[tmp], %" #w "[tmp], %" #w "[val]\n"    \
     "    cbnz    %" #w "[tmp], 1f\n"                \
     "    wfe\n"                            \
--
1.8.3.1
SOURCES/0001-net-mvpp2-remove-useless-goto.patch
New file
@@ -0,0 +1,31 @@
From df729afff345873ba01a0572e2042e68115ab305 Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Mon, 18 Sep 2017 15:36:51 +0200
Subject: [PATCH 01/46] net: mvpp2: remove useless goto
Remove a goto in the PPv2 tx function which jumps to the next line
anyway. This is a cosmetic commit.
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 38c5eb93aca9dc1b21a2c96d583ce7f9886a44e6)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 1 -
 1 file changed, 1 deletion(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index fcf9ba5..c0f7a41 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -6469,7 +6469,6 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev)
         if (mvpp2_tx_frag_process(port, skb, aggr_txq, txq)) {
             tx_desc_unmap_put(port, txq, tx_desc);
             frags = 0;
-            goto out;
         }
     }
--
2.7.4
SOURCES/0002-BACKPORT-arm64-barrier-Implement-smp_cond_load_relax.patch
New file
@@ -0,0 +1,48 @@
From 999d3c8c40286fc57dfcd194a1b7548b975ec875 Mon Sep 17 00:00:00 2001
From: Khuong Dinh <khuong.dinh@amperecomputing.com>
Date: Wed, 31 Jan 2018 15:55:24 +0000
Subject: [PATCH 02/11] BACKPORT: arm64: barrier: Implement
 smp_cond_load_relaxed
We can provide an implementation of smp_cond_load_relaxed using READ_ONCE
and __cmpwait_relaxed.
This patch is required to fix kernel lock up due to new implementation of
queued read write locking from kernel 4.14.
This patch is backported from:
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?h=next-20180913&id=598865c5f32d6e11e99f2aac07348e5fd17cdc03
Change-Id: I69a663a3c84301479f5b077f1dd7a342938b92cf
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Khuong Dinh <khuong.dinh@amperecomputing.com>
---
 arch/arm64/include/asm/barrier.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 6133f3e..bc814e8 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -182,6 +182,19 @@ static inline unsigned long array_index_mask_nospec(unsigned long idx,
     __u.__val;                            \
 })
+#define smp_cond_load_relaxed(ptr, cond_expr)                \
+({                                    \
+    typeof(ptr) __PTR = (ptr);                    \
+    typeof(*ptr) VAL;                        \
+    for (;;) {                            \
+        VAL = READ_ONCE(*__PTR);                \
+        if (cond_expr)                        \
+            break;                        \
+        __cmpwait_relaxed(__PTR, VAL);                \
+    }                                \
+    VAL;                                \
+})
+
 #define smp_cond_load_acquire(ptr, cond_expr)                \
 ({                                    \
     typeof(ptr) __PTR = (ptr);                    \
--
1.8.3.1
SOURCES/0002-net-mvpp2-set-the-Rx-FIFO-size-depending-on-the-port.patch
New file
@@ -0,0 +1,99 @@
From d6bbef303a701b0bfb0cd293de227436cc084f2e Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Mon, 30 Oct 2017 11:23:28 +0100
Subject: [PATCH 02/46] net: mvpp2: set the Rx FIFO size depending on the port
 speeds for PPv2.2
The Rx FIFO size was set to the same value for all ports. This patch
sets it depending on the maximum speed a given port can handle. This is
only working for PPv2.2.
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 2d1d7df8a3652697da7f7929791d555e6c5981c2)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 52 +++++++++++++++++++++++++++++++-----
 1 file changed, 46 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index c0f7a41..80aa7f7 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -504,9 +504,13 @@
 #define MVPP2_TX_DESC_ALIGN        (MVPP2_DESC_ALIGNED_SIZE - 1)
 /* RX FIFO constants */
-#define MVPP2_RX_FIFO_PORT_DATA_SIZE    0x2000
-#define MVPP2_RX_FIFO_PORT_ATTR_SIZE    0x80
-#define MVPP2_RX_FIFO_PORT_MIN_PKT    0x80
+#define MVPP2_RX_FIFO_PORT_DATA_SIZE_32KB    0x8000
+#define MVPP2_RX_FIFO_PORT_DATA_SIZE_8KB    0x2000
+#define MVPP2_RX_FIFO_PORT_DATA_SIZE_4KB    0x1000
+#define MVPP2_RX_FIFO_PORT_ATTR_SIZE_32KB    0x200
+#define MVPP2_RX_FIFO_PORT_ATTR_SIZE_8KB    0x80
+#define MVPP2_RX_FIFO_PORT_ATTR_SIZE_4KB    0x40
+#define MVPP2_RX_FIFO_PORT_MIN_PKT        0x80
 /* RX buffer constants */
 #define MVPP2_SKB_SHINFO_SIZE \
@@ -7768,9 +7772,42 @@ static void mvpp2_rx_fifo_init(struct mvpp2 *priv)
     for (port = 0; port < MVPP2_MAX_PORTS; port++) {
         mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(port),
-                MVPP2_RX_FIFO_PORT_DATA_SIZE);
+                MVPP2_RX_FIFO_PORT_DATA_SIZE_4KB);
         mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(port),
-                MVPP2_RX_FIFO_PORT_ATTR_SIZE);
+                MVPP2_RX_FIFO_PORT_ATTR_SIZE_4KB);
+    }
+
+    mvpp2_write(priv, MVPP2_RX_MIN_PKT_SIZE_REG,
+            MVPP2_RX_FIFO_PORT_MIN_PKT);
+    mvpp2_write(priv, MVPP2_RX_FIFO_INIT_REG, 0x1);
+}
+
+static void mvpp22_rx_fifo_init(struct mvpp2 *priv)
+{
+    int port;
+
+    /* The FIFO size parameters are set depending on the maximum speed a
+     * given port can handle:
+     * - Port 0: 10Gbps
+     * - Port 1: 2.5Gbps
+     * - Ports 2 and 3: 1Gbps
+     */
+
+    mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(0),
+            MVPP2_RX_FIFO_PORT_DATA_SIZE_32KB);
+    mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(0),
+            MVPP2_RX_FIFO_PORT_ATTR_SIZE_32KB);
+
+    mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(1),
+            MVPP2_RX_FIFO_PORT_DATA_SIZE_8KB);
+    mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(1),
+            MVPP2_RX_FIFO_PORT_ATTR_SIZE_8KB);
+
+    for (port = 2; port < MVPP2_MAX_PORTS; port++) {
+        mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(port),
+                MVPP2_RX_FIFO_PORT_DATA_SIZE_4KB);
+        mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(port),
+                MVPP2_RX_FIFO_PORT_ATTR_SIZE_4KB);
     }
     mvpp2_write(priv, MVPP2_RX_MIN_PKT_SIZE_REG,
@@ -7874,7 +7911,10 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
     }
     /* Rx Fifo Init */
-    mvpp2_rx_fifo_init(priv);
+    if (priv->hw_version == MVPP21)
+        mvpp2_rx_fifo_init(priv);
+    else
+        mvpp22_rx_fifo_init(priv);
     if (priv->hw_version == MVPP21)
         writel(MVPP2_EXT_GLOBAL_CTRL_DEFAULT,
--
2.7.4
SOURCES/0003-BACKPORT-arm64-locking-Replace-ticket-lock-implement.patch
New file
@@ -0,0 +1,217 @@
From 66af385bfaf97865f0e6d9032db896656b58920d Mon Sep 17 00:00:00 2001
From: Khuong Dinh <khuong.dinh@amperecomputing.com>
Date: Tue, 13 Mar 2018 20:45:45 +0000
Subject: [PATCH 03/11] BACKPORT: arm64: locking: Replace ticket lock
 implementation with qspinlock
It's fair to say that our ticket lock has served us well over time, but
it's time to bite the bullet and start using the generic qspinlock code
so we can make use of explicit MCS queuing and potentially better PV
performance in future.
This patch is required to fix kernel lock up due to new implementation of
queued read write locking from kernel 4.14.
This patch is backported from:
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?h=next-20180913&id=c11090474d70590170cf5fa6afe85864ab494b37
Change-Id: I1b019176c2b7ae1b25e609a54d7fa35bd380bd0a
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Khuong Dinh <khuong.dinh@amperecomputing.com>
---
 arch/arm64/Kconfig                      |   1 +
 arch/arm64/include/asm/Kbuild           |   1 +
 arch/arm64/include/asm/spinlock.h       | 124 +-------------------------------
 arch/arm64/include/asm/spinlock_types.h |  17 +----
 4 files changed, 4 insertions(+), 139 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 651d8d9..fba4bd7 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -41,6 +41,7 @@ config ARM64
     select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE if !PREEMPT
     select ARCH_USE_CMPXCHG_LOCKREF
     select ARCH_USE_QUEUED_RWLOCKS
+    select ARCH_USE_QUEUED_SPINLOCKS
     select ARCH_SUPPORTS_MEMORY_FAILURE
     select ARCH_SUPPORTS_ATOMIC_RMW
     select ARCH_SUPPORTS_NUMA_BALANCING
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
index e63d0a8..ae621cb 100644
--- a/arch/arm64/include/asm/Kbuild
+++ b/arch/arm64/include/asm/Kbuild
@@ -17,6 +17,7 @@ generic-y += mm-arch-hooks.h
 generic-y += msi.h
 generic-y += preempt.h
 generic-y += qrwlock.h
+generic-y += qspinlock.h
 generic-y += rwsem.h
 generic-y += segment.h
 generic-y += serial.h
diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h
index fa1d966..8871cdd 100644
--- a/arch/arm64/include/asm/spinlock.h
+++ b/arch/arm64/include/asm/spinlock.h
@@ -16,130 +16,8 @@
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
-#include <asm/lse.h>
-#include <asm/spinlock_types.h>
-#include <asm/processor.h>
-
-/*
- * Spinlock implementation.
- *
- * The memory barriers are implicit with the load-acquire and store-release
- * instructions.
- */
-
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
-
-static inline void arch_spin_lock(arch_spinlock_t *lock)
-{
-    unsigned int tmp;
-    arch_spinlock_t lockval, newval;
-
-    asm volatile(
-    /* Atomically increment the next ticket. */
-    ARM64_LSE_ATOMIC_INSN(
-    /* LL/SC */
-"    prfm    pstl1strm, %3\n"
-"1:    ldaxr    %w0, %3\n"
-"    add    %w1, %w0, %w5\n"
-"    stxr    %w2, %w1, %3\n"
-"    cbnz    %w2, 1b\n",
-    /* LSE atomics */
-"    mov    %w2, %w5\n"
-"    ldadda    %w2, %w0, %3\n"
-    __nops(3)
-    )
-
-    /* Did we get the lock? */
-"    eor    %w1, %w0, %w0, ror #16\n"
-"    cbz    %w1, 3f\n"
-    /*
-     * No: spin on the owner. Send a local event to avoid missing an
-     * unlock before the exclusive load.
-     */
-"    sevl\n"
-"2:    wfe\n"
-"    ldaxrh    %w2, %4\n"
-"    eor    %w1, %w2, %w0, lsr #16\n"
-"    cbnz    %w1, 2b\n"
-    /* We got the lock. Critical section starts here. */
-"3:"
-    : "=&r" (lockval), "=&r" (newval), "=&r" (tmp), "+Q" (*lock)
-    : "Q" (lock->owner), "I" (1 << TICKET_SHIFT)
-    : "memory");
-}
-
-static inline int arch_spin_trylock(arch_spinlock_t *lock)
-{
-    unsigned int tmp;
-    arch_spinlock_t lockval;
-
-    asm volatile(ARM64_LSE_ATOMIC_INSN(
-    /* LL/SC */
-    "    prfm    pstl1strm, %2\n"
-    "1:    ldaxr    %w0, %2\n"
-    "    eor    %w1, %w0, %w0, ror #16\n"
-    "    cbnz    %w1, 2f\n"
-    "    add    %w0, %w0, %3\n"
-    "    stxr    %w1, %w0, %2\n"
-    "    cbnz    %w1, 1b\n"
-    "2:",
-    /* LSE atomics */
-    "    ldr    %w0, %2\n"
-    "    eor    %w1, %w0, %w0, ror #16\n"
-    "    cbnz    %w1, 1f\n"
-    "    add    %w1, %w0, %3\n"
-    "    casa    %w0, %w1, %2\n"
-    "    and    %w1, %w1, #0xffff\n"
-    "    eor    %w1, %w1, %w0, lsr #16\n"
-    "1:")
-    : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
-    : "I" (1 << TICKET_SHIFT)
-    : "memory");
-
-    return !tmp;
-}
-
-static inline void arch_spin_unlock(arch_spinlock_t *lock)
-{
-    unsigned long tmp;
-
-    asm volatile(ARM64_LSE_ATOMIC_INSN(
-    /* LL/SC */
-    "    ldrh    %w1, %0\n"
-    "    add    %w1, %w1, #1\n"
-    "    stlrh    %w1, %0",
-    /* LSE atomics */
-    "    mov    %w1, #1\n"
-    "    staddlh    %w1, %0\n"
-    __nops(1))
-    : "=Q" (lock->owner), "=&r" (tmp)
-    :
-    : "memory");
-}
-
-static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
-{
-    return lock.owner == lock.next;
-}
-
-static inline int arch_spin_is_locked(arch_spinlock_t *lock)
-{
-    /*
-     * Ensure prior spin_lock operations to other locks have completed
-     * on this CPU before we test whether "lock" is locked.
-     */
-    smp_mb(); /* ^^^ */
-    return !arch_spin_value_unlocked(READ_ONCE(*lock));
-}
-
-static inline int arch_spin_is_contended(arch_spinlock_t *lock)
-{
-    arch_spinlock_t lockval = READ_ONCE(*lock);
-    return (lockval.next - lockval.owner) > 1;
-}
-#define arch_spin_is_contended    arch_spin_is_contended
-
 #include <asm/qrwlock.h>
+#include <asm/qspinlock.h>
 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
 #define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
diff --git a/arch/arm64/include/asm/spinlock_types.h b/arch/arm64/include/asm/spinlock_types.h
index 6b85601..a157ff4 100644
--- a/arch/arm64/include/asm/spinlock_types.h
+++ b/arch/arm64/include/asm/spinlock_types.h
@@ -20,22 +20,7 @@
 # error "please don't include this file directly"
 #endif
-#include <linux/types.h>
-
-#define TICKET_SHIFT    16
-
-typedef struct {
-#ifdef __AARCH64EB__
-    u16 next;
-    u16 owner;
-#else
-    u16 owner;
-    u16 next;
-#endif
-} __aligned(4) arch_spinlock_t;
-
-#define __ARCH_SPIN_LOCK_UNLOCKED    { 0 , 0 }
-
+#include <asm-generic/qspinlock_types.h>
 #include <asm-generic/qrwlock_types.h>
 #endif
--
1.8.3.1
SOURCES/0003-net-mvpp2-initialize-the-Tx-FIFO-size.patch
New file
@@ -0,0 +1,83 @@
From c265d5613317c689df3f54ea80332af675e6ea84 Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Mon, 30 Oct 2017 11:23:29 +0100
Subject: [PATCH 03/46] net: mvpp2: initialize the Tx FIFO size
So far only the Rx FIFO size was initialized. For PPv2.2 the Tx FIFO
size can be set as well. This patch initializes the Tx FIFO size for
PPv2.2 controllers to 3K.
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 7c10f9742d76ec18bed5de14f5f4ed08859f7b7a)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 80aa7f7..042afd7 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -38,11 +38,12 @@
 #include <net/ipv6.h>
 #include <net/tso.h>
-/* RX Fifo Registers */
+/* Fifo Registers */
 #define MVPP2_RX_DATA_FIFO_SIZE_REG(port)    (0x00 + 4 * (port))
 #define MVPP2_RX_ATTR_FIFO_SIZE_REG(port)    (0x20 + 4 * (port))
 #define MVPP2_RX_MIN_PKT_SIZE_REG        0x60
 #define MVPP2_RX_FIFO_INIT_REG            0x64
+#define MVPP22_TX_FIFO_SIZE_REG(port)        (0x8860 + 4 * (port))
 /* RX DMA Top Registers */
 #define MVPP2_RX_CTRL_REG(port)            (0x140 + 4 * (port))
@@ -512,6 +513,10 @@
 #define MVPP2_RX_FIFO_PORT_ATTR_SIZE_4KB    0x40
 #define MVPP2_RX_FIFO_PORT_MIN_PKT        0x80
+/* TX FIFO constants */
+#define MVPP22_TX_FIFO_DATA_SIZE_10KB        0xa
+#define MVPP22_TX_FIFO_DATA_SIZE_3KB        0x3
+
 /* RX buffer constants */
 #define MVPP2_SKB_SHINFO_SIZE \
     SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
@@ -7815,6 +7820,16 @@ static void mvpp22_rx_fifo_init(struct mvpp2 *priv)
     mvpp2_write(priv, MVPP2_RX_FIFO_INIT_REG, 0x1);
 }
+/* Initialize Tx FIFO's */
+static void mvpp22_tx_fifo_init(struct mvpp2 *priv)
+{
+    int port;
+
+    for (port = 0; port < MVPP2_MAX_PORTS; port++)
+        mvpp2_write(priv, MVPP22_TX_FIFO_SIZE_REG(port),
+                MVPP22_TX_FIFO_DATA_SIZE_3KB);
+}
+
 static void mvpp2_axi_init(struct mvpp2 *priv)
 {
     u32 val, rdval, wrval;
@@ -7910,11 +7925,13 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
             return err;
     }
-    /* Rx Fifo Init */
-    if (priv->hw_version == MVPP21)
+    /* Fifo Init */
+    if (priv->hw_version == MVPP21) {
         mvpp2_rx_fifo_init(priv);
-    else
+    } else {
         mvpp22_rx_fifo_init(priv);
+        mvpp22_tx_fifo_init(priv);
+    }
     if (priv->hw_version == MVPP21)
         writel(MVPP2_EXT_GLOBAL_CTRL_DEFAULT,
--
2.7.4
SOURCES/0004-BACKPORT-arm64-kconfig-Ensure-spinlock-fastpaths-are.patch
New file
@@ -0,0 +1,47 @@
From 89bbb4b308e53d30daca20199b6039b64cd90fc1 Mon Sep 17 00:00:00 2001
From: Khuong Dinh <khuong.dinh@amperecomputing.com>
Date: Tue, 13 Mar 2018 21:17:01 +0000
Subject: [PATCH 04/11] BACKPORT: arm64: kconfig: Ensure spinlock fastpaths are
 inlined if !PREEMPT
When running with CONFIG_PREEMPT=n, the spinlock fastpaths fit inside
64 bytes, which typically coincides with the L1 I-cache line size.
Inline the spinlock fastpaths, like we do already for rwlocks.
This patch is required to fix kernel lock up due to new implementation of
queued read write locking from kernel 4.14.
This patch is backported from:
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?h=next-20180913&id=5d168964aece0b4a41269839c613683c5d7e0fb2
Change-Id: I1d450877a4d589dcd78c080533e71d046c621562
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Khuong Dinh <khuong.dinh@amperecomputing.com>
---
 arch/arm64/Kconfig | 10 ++++++++++
 1 file changed, 10 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index fba4bd7..db83519 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -39,6 +39,16 @@ config ARM64
     select ARCH_INLINE_WRITE_UNLOCK_BH if !PREEMPT
     select ARCH_INLINE_WRITE_UNLOCK_IRQ if !PREEMPT
     select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE if !PREEMPT
+    select ARCH_INLINE_SPIN_TRYLOCK if !PREEMPT
+    select ARCH_INLINE_SPIN_TRYLOCK_BH if !PREEMPT
+    select ARCH_INLINE_SPIN_LOCK if !PREEMPT
+    select ARCH_INLINE_SPIN_LOCK_BH if !PREEMPT
+    select ARCH_INLINE_SPIN_LOCK_IRQ if !PREEMPT
+    select ARCH_INLINE_SPIN_LOCK_IRQSAVE if !PREEMPT
+    select ARCH_INLINE_SPIN_UNLOCK if !PREEMPT
+    select ARCH_INLINE_SPIN_UNLOCK_BH if !PREEMPT
+    select ARCH_INLINE_SPIN_UNLOCK_IRQ if !PREEMPT
+    select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE if !PREEMPT
     select ARCH_USE_CMPXCHG_LOCKREF
     select ARCH_USE_QUEUED_RWLOCKS
     select ARCH_USE_QUEUED_SPINLOCKS
--
1.8.3.1
SOURCES/0004-net-mvpp2-initialize-the-RSS-tables.patch
New file
@@ -0,0 +1,103 @@
From 114b7c5b1ee39740e6faafdc82debdd4b0e4d9c4 Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Mon, 30 Oct 2017 11:23:30 +0100
Subject: [PATCH 04/46] net: mvpp2: initialize the RSS tables
This patch initialize the RSS tables to evenly (depending on the packets
RSS hashes) distribute the packets across port Rx queues. This helps to
handle packets on different CPUs to improve performances, as more queues
will be used in parallel.
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 1d7d15d79fb4660bec3a86e748c50aac7c5d2121)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 50 ++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 042afd7..6eb61a9 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -83,6 +83,16 @@
 #define MVPP2_PRS_TCAM_CTRL_REG            0x1230
 #define     MVPP2_PRS_TCAM_EN_MASK        BIT(0)
+/* RSS Registers */
+#define MVPP22_RSS_INDEX            0x1500
+#define     MVPP22_RSS_INDEX_TABLE_ENTRY(idx)    ((idx) << 8)
+#define     MVPP22_RSS_INDEX_TABLE(idx)        ((idx) << 8)
+#define     MVPP22_RSS_INDEX_QUEUE(idx)        ((idx) << 16)
+#define MVPP22_RSS_TABLE_ENTRY            0x1508
+#define MVPP22_RSS_TABLE            0x1510
+#define     MVPP22_RSS_TABLE_POINTER(p)        (p)
+#define MVPP22_RSS_WIDTH            0x150c
+
 /* Classifier Registers */
 #define MVPP2_CLS_MODE_REG            0x1800
 #define     MVPP2_CLS_MODE_ACTIVE_MASK        BIT(0)
@@ -746,6 +756,10 @@ enum mvpp2_prs_l3_cast {
 #define MVPP2_CLS_FLOWS_TBL_SIZE    512
 #define MVPP2_CLS_FLOWS_TBL_DATA_WORDS    3
 #define MVPP2_CLS_LKP_TBL_SIZE        64
+#define MVPP2_CLS_RX_QUEUES        256
+
+/* RSS constants */
+#define MVPP22_RSS_TABLE_ENTRIES    32
 /* BM constants */
 #define MVPP2_BM_POOLS_NUM        8
@@ -6792,6 +6806,39 @@ static void mvpp2_irqs_deinit(struct mvpp2_port *port)
     }
 }
+static void mvpp22_init_rss(struct mvpp2_port *port)
+{
+    struct mvpp2 *priv = port->priv;
+    int i;
+
+    /* Set the table width: replace the whole classifier Rx queue number
+     * with the ones configured in RSS table entries.
+     */
+    mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_TABLE(0));
+    mvpp2_write(priv, MVPP22_RSS_WIDTH, 8);
+
+    /* Loop through the classifier Rx Queues and map them to a RSS table.
+     * Map them all to the first table (0) by default.
+     */
+    for (i = 0; i < MVPP2_CLS_RX_QUEUES; i++) {
+        mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_QUEUE(i));
+        mvpp2_write(priv, MVPP22_RSS_TABLE,
+                MVPP22_RSS_TABLE_POINTER(0));
+    }
+
+    /* Configure the first table to evenly distribute the packets across
+     * real Rx Queues. The table entries map a hash to an port Rx Queue.
+     */
+    for (i = 0; i < MVPP22_RSS_TABLE_ENTRIES; i++) {
+        u32 sel = MVPP22_RSS_INDEX_TABLE(0) |
+              MVPP22_RSS_INDEX_TABLE_ENTRY(i);
+        mvpp2_write(priv, MVPP22_RSS_INDEX, sel);
+
+        mvpp2_write(priv, MVPP22_RSS_TABLE_ENTRY, i % port->nrxqs);
+    }
+
+}
+
 static int mvpp2_open(struct net_device *dev)
 {
     struct mvpp2_port *port = netdev_priv(dev);
@@ -6866,6 +6913,9 @@ static int mvpp2_open(struct net_device *dev)
     mvpp2_start_dev(port);
+    if (priv->hw_version == MVPP22)
+        mvpp22_init_rss(port);
+
     return 0;
 err_free_link_irq:
--
2.7.4
SOURCES/0005-BACKPORT-ahci-Disable-LPM-on-Lenovo-50-series-laptop.patch
New file
@@ -0,0 +1,160 @@
From c75c91833dd0998ece4c2fbc6bf97a87e19551e3 Mon Sep 17 00:00:00 2001
From: Khuong Dinh <khuong.dinh@amperecomputing.com>
Date: Sun, 1 Jul 2018 12:15:46 +0200
Subject: [PATCH 05/11] BACKPORT: ahci: Disable LPM on Lenovo 50 series laptops
 with a too old BIOS
There have been several reports of LPM related hard freezes about once
a day on multiple Lenovo 50 series models. Strange enough these reports
where not disk model specific as LPM issues usually are and some users
with the exact same disk + laptop where seeing them while other users
where not seeing these issues.
It turns out that enabling LPM triggers a firmware bug somewhere, which
has been fixed in later BIOS versions.
This commit adds a new ahci_broken_lpm() function and a new ATA_FLAG_NO_LPM
for dealing with this.
The ahci_broken_lpm() function contains DMI match info for the 4 models
which are known to be affected by this and the DMI BIOS date field for
known good BIOS versions. If the BIOS date is older then the one in the
table LPM will be disabled and a warning will be printed.
Note the BIOS dates are for known good versions, some older versions may
work too, but we don't know for sure, the table is using dates from BIOS
versions for which users have confirmed that upgrading to that version
makes the problem go away.
Unfortunately I've been unable to get hold of the reporter who reported
that BIOS version 2.35 fixed the problems on the W541 for him. I've been
able to verify the DMI_SYS_VENDOR and DMI_PRODUCT_VERSION from an older
dmidecode, but I don't know the exact BIOS date as reported in the DMI.
Lenovo keeps a changelog with dates in their release notes, but the
dates there are the release dates not the build dates which are in DMI.
So I've chosen to set the date to which we compare to one day past the
release date of the 2.34 BIOS. I plan to fix this with a follow up
commit once I've the necessary info.
This patch is required to support AHCI ALPM de-feature for Ampere Computing
eMAG SATA.
This patch is backported from:
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?h=next-20180913&id=240630e61870e62e39a97225048f9945848fa5f5
Change-Id: I077e886a4faff18e2cb884c361065d9bd0a22e50
Cc: stable@vger.kernel.org
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Khuong Dinh <khuong.dinh@amperecomputing.com>
---
 drivers/ata/ahci.c        | 59 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/ata/libata-core.c |  3 +++
 include/linux/libata.h    |  1 +
 3 files changed, 63 insertions(+)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 9f78bb0..e0c2de6 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1260,6 +1260,59 @@ static bool ahci_broken_suspend(struct pci_dev *pdev)
     return strcmp(buf, dmi->driver_data) < 0;
 }
+static bool ahci_broken_lpm(struct pci_dev *pdev)
+{
+    static const struct dmi_system_id sysids[] = {
+        /* Various Lenovo 50 series have LPM issues with older BIOSen */
+        {
+            .matches = {
+                DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X250"),
+            },
+            .driver_data = "20180406", /* 1.31 */
+        },
+        {
+            .matches = {
+                DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L450"),
+            },
+            .driver_data = "20180420", /* 1.28 */
+        },
+        {
+            .matches = {
+                DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T450s"),
+            },
+            .driver_data = "20180315", /* 1.33 */
+        },
+        {
+            .matches = {
+                DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W541"),
+            },
+            /*
+             * Note date based on release notes, 2.35 has been
+             * reported to be good, but I've been unable to get
+             * a hold of the reporter to get the DMI BIOS date.
+             * TODO: fix this.
+             */
+            .driver_data = "20180310", /* 2.35 */
+        },
+        { }    /* terminate list */
+    };
+    const struct dmi_system_id *dmi = dmi_first_match(sysids);
+    int year, month, date;
+    char buf[9];
+
+    if (!dmi)
+        return false;
+
+    dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
+    snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
+
+    return strcmp(buf, dmi->driver_data) < 0;
+}
+
 static bool ahci_broken_online(struct pci_dev *pdev)
 {
 #define ENCODE_BUSDEVFN(bus, slot, func)            \
@@ -1670,6 +1723,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
             "quirky BIOS, skipping spindown on poweroff\n");
     }
+    if (ahci_broken_lpm(pdev)) {
+        pi.flags |= ATA_FLAG_NO_LPM;
+        dev_warn(&pdev->dev,
+             "BIOS update required for Link Power Management support\n");
+    }
+
     if (ahci_broken_suspend(pdev)) {
         hpriv->flags |= AHCI_HFLAG_NO_SUSPEND;
         dev_warn(&pdev->dev,
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index ee4c1ec..35346c1 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2501,6 +2501,9 @@ int ata_dev_configure(struct ata_device *dev)
         (id[ATA_ID_SATA_CAPABILITY] & 0xe) == 0x2)
         dev->horkage |= ATA_HORKAGE_NOLPM;
+    if (ap->flags & ATA_FLAG_NO_LPM)
+        dev->horkage |= ATA_HORKAGE_NOLPM;
+
     if (dev->horkage & ATA_HORKAGE_NOLPM) {
         ata_dev_warn(dev, "LPM support broken, forcing max_power\n");
         dev->link->ap->target_lpm_policy = ATA_LPM_MAX_POWER;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 6b7a196..a4a7e0f 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -211,6 +211,7 @@ enum {
     ATA_FLAG_SLAVE_POSS    = (1 << 0), /* host supports slave dev */
                         /* (doesn't imply presence) */
     ATA_FLAG_SATA        = (1 << 1),
+    ATA_FLAG_NO_LPM        = (1 << 2), /* host not happy with LPM */
     ATA_FLAG_NO_LOG_PAGE    = (1 << 5), /* do not issue log page read */
     ATA_FLAG_NO_ATAPI    = (1 << 6), /* No ATAPI support */
     ATA_FLAG_PIO_DMA    = (1 << 7), /* PIO cmds via DMA */
--
1.8.3.1
SOURCES/0005-net-mvpp2-limit-TSO-segments-and-use-stop-wake-thres.patch
New file
@@ -0,0 +1,88 @@
From 0ae78841cd368b829178f14c810012297a597222 Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Mon, 30 Oct 2017 11:23:31 +0100
Subject: [PATCH 05/46] net: mvpp2: limit TSO segments and use stop/wake
 thresholds
Too many TSO descriptors can be required for the default queue size,
when using small MSS values for example. Prevent this by adding a
maximum number of allowed TSO segments (300). In addition set a stop and
a wake thresholds to stop the queue when there's no room for a 1 "worst
case scenario skb". Wake up the queue when the number of descriptors is
low enough.
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 1d17db08c056c1f7f4abbff6aff8711b7c3a3b7f)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 6eb61a9..79e6958 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -493,6 +493,13 @@
 /* Maximum number of TXQs used by single port */
 #define MVPP2_MAX_TXQ            8
+/* MVPP2_MAX_TSO_SEGS is the maximum number of fragments to allow in the GSO
+ * skb. As we need a maxium of two descriptors per fragments (1 header, 1 data),
+ * multiply this value by two to count the maximum number of skb descs needed.
+ */
+#define MVPP2_MAX_TSO_SEGS        300
+#define MVPP2_MAX_SKB_DESCS        (MVPP2_MAX_TSO_SEGS * 2 + MAX_SKB_FRAGS)
+
 /* Dfault number of RXQs in use */
 #define MVPP2_DEFAULT_RXQ        4
@@ -1045,6 +1052,9 @@ struct mvpp2_txq_pcpu {
      */
     int count;
+    int wake_threshold;
+    int stop_threshold;
+
     /* Number of Tx DMA descriptors reserved for each CPU */
     int reserved_num;
@@ -5393,7 +5403,7 @@ static void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq,
     txq_pcpu->count -= tx_done;
     if (netif_tx_queue_stopped(nq))
-        if (txq_pcpu->size - txq_pcpu->count >= MAX_SKB_FRAGS + 1)
+        if (txq_pcpu->count <= txq_pcpu->wake_threshold)
             netif_tx_wake_queue(nq);
 }
@@ -5636,6 +5646,9 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
         txq_pcpu->txq_put_index = 0;
         txq_pcpu->txq_get_index = 0;
+        txq_pcpu->stop_threshold = txq->size - MVPP2_MAX_SKB_DESCS;
+        txq_pcpu->wake_threshold = txq_pcpu->stop_threshold / 2;
+
         txq_pcpu->tso_headers =
             dma_alloc_coherent(port->dev->dev.parent,
                        txq_pcpu->size * TSO_HEADER_SIZE,
@@ -6508,7 +6521,7 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev)
         wmb();
         mvpp2_aggr_txq_pend_desc_add(port, frags);
-        if (txq_pcpu->size - txq_pcpu->count < MAX_SKB_FRAGS + 1)
+        if (txq_pcpu->count >= txq_pcpu->stop_threshold)
             netif_tx_stop_queue(nq);
         u64_stats_update_begin(&stats->syncp);
@@ -7736,6 +7749,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
     dev->features = features | NETIF_F_RXCSUM;
     dev->hw_features |= features | NETIF_F_RXCSUM | NETIF_F_GRO;
     dev->vlan_features |= features;
+    dev->gso_max_segs = MVPP2_MAX_TSO_SEGS;
     /* MTU range: 68 - 9676 */
     dev->min_mtu = ETH_MIN_MTU;
--
2.7.4
SOURCES/0006-BACKPORT-ACPI-bus-Introduce-acpi_get_match_data-func.patch
New file
@@ -0,0 +1,80 @@
From 62b61856762a48709e29bbfc5f804b6185b79d93 Mon Sep 17 00:00:00 2001
From: Khuong Dinh <khuong.dinh@amperecomputing.com>
Date: Wed, 13 Dec 2017 02:20:48 -0500
Subject: [PATCH 06/11] BACKPORT: ACPI / bus: Introduce acpi_get_match_data()
 function
OF has of_device_get_match_data() function to extract driver specific data
structure. Add a similar function for ACPI.
This patch is required to support AHCI ALPM de-feature for Ampere Computing
eMAG SATA.
This patch is backported from:
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?h=next-20180913&id=80212a162329e590fde02d8457af16ea0ab0a55f
Change-Id: I764d8e7ef1e9375561dc895bba74f8edb5888d06
Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Khuong Dinh <khuong.dinh@amperecomputing.com>
---
 drivers/acpi/bus.c   | 18 ++++++++++++++++++
 include/linux/acpi.h |  6 ++++++
 2 files changed, 24 insertions(+)
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 4d0979e..f87ed3b 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -785,6 +785,24 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
 }
 EXPORT_SYMBOL_GPL(acpi_match_device);
+void *acpi_get_match_data(const struct device *dev)
+{
+    const struct acpi_device_id *match;
+
+    if (!dev->driver)
+        return NULL;
+
+    if (!dev->driver->acpi_match_table)
+        return NULL;
+
+    match = acpi_match_device(dev->driver->acpi_match_table, dev);
+    if (!match)
+        return NULL;
+
+    return (void *)match->driver_data;
+}
+EXPORT_SYMBOL_GPL(acpi_get_match_data);
+
 int acpi_match_device_ids(struct acpi_device *device,
               const struct acpi_device_id *ids)
 {
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 8bcfe3d..42e1565 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -584,6 +584,7 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
 const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
                            const struct device *dev);
+void *acpi_get_match_data(const struct device *dev);
 extern bool acpi_driver_match_device(struct device *dev,
                      const struct device_driver *drv);
 int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
@@ -755,6 +756,11 @@ static inline const struct acpi_device_id *acpi_match_device(
     return NULL;
 }
+static inline void *acpi_get_match_data(const struct device *dev)
+{
+    return NULL;
+}
+
 static inline bool acpi_driver_match_device(struct device *dev,
                         const struct device_driver *drv)
 {
--
1.8.3.1
SOURCES/0006-net-mvpp2-use-the-aggr-txq-size-define-everywhere.patch
New file
@@ -0,0 +1,51 @@
From 5b24b458fb1934cc91d9cbf31841bd067cf74737 Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Mon, 30 Oct 2017 11:23:32 +0100
Subject: [PATCH 06/46] net: mvpp2: use the aggr txq size define everywhere
Cosmetic patch using the MVPP2_AGGR_TXQ_SIZE everywhere instead of the
size field of aggr_txq, as the size never change and is always equal to
the MVPP2_AGGR_TXQ_SIZE define.
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 02856a3ba6333c536f13d27cc847fcb442a23d9b)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 79e6958..9a9decb 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -5055,7 +5055,7 @@ static void mvpp2_aggr_txq_pend_desc_add(struct mvpp2_port *port, int pending)
 static int mvpp2_aggr_desc_num_check(struct mvpp2 *priv,
                      struct mvpp2_tx_queue *aggr_txq, int num)
 {
-    if ((aggr_txq->count + num) > aggr_txq->size) {
+    if ((aggr_txq->count + num) > MVPP2_AGGR_TXQ_SIZE) {
         /* Update number of occupied aggregated Tx descriptors */
         int cpu = smp_processor_id();
         u32 val = mvpp2_read(priv, MVPP2_AGGR_TXQ_STATUS_REG(cpu));
@@ -5063,7 +5063,7 @@ static int mvpp2_aggr_desc_num_check(struct mvpp2 *priv,
         aggr_txq->count = val & MVPP2_AGGR_TXQ_PENDING_MASK;
     }
-    if ((aggr_txq->count + num) > aggr_txq->size)
+    if ((aggr_txq->count + num) > MVPP2_AGGR_TXQ_SIZE)
         return -ENOMEM;
     return 0;
@@ -5447,7 +5447,7 @@ static int mvpp2_aggr_txq_init(struct platform_device *pdev,
     if (!aggr_txq->descs)
         return -ENOMEM;
-    aggr_txq->last_desc = aggr_txq->size - 1;
+    aggr_txq->last_desc = MVPP2_AGGR_TXQ_SIZE - 1;
     /* Aggr TXQ no reset WA */
     aggr_txq->next_desc_to_proc = mvpp2_read(priv,
--
2.7.4
SOURCES/0007-BACKPORT-ACPI-bus-Remove-checks-in-acpi_get_match_da.patch
New file
@@ -0,0 +1,53 @@
From 4b8a8385da13bd51d7403c5b08bbeab02e05c393 Mon Sep 17 00:00:00 2001
From: Khuong Dinh <khuong.dinh@amperecomputing.com>
Date: Fri, 9 Feb 2018 17:38:34 +0200
Subject: [PATCH 07/11] BACKPORT: ACPI / bus: Remove checks in
 acpi_get_match_data()
As well as its sibling of_device_get_match_data() has no such checks,
no need to do it in acpi_get_match_data().
First of all, we are not supposed to call fwnode API like this without
driver attached.
Second, since __acpi_match_device() does check input parameter there is
no need to duplicate it outside.
And last but not least one, the API should still serve the cases when
ACPI device is enumerated via PRP0001. In such case driver has neither
ACPI table nor driver data there.
This patch is required to support AHCI ALPM de-feature for Ampere Computing
eMAG SATA.
This patch is backported from:
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?h=next-20180913&id=8ff277c5bf87d750a44a656d4f113462493acbfc
Change-Id: Id2f1d591f59af93e21741cd62c8ced0ff6a747b8
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Khuong Dinh <khuong.dinh@amperecomputing.com>
---
 drivers/acpi/bus.c | 6 ------
 1 file changed, 6 deletions(-)
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index f87ed3b..b271eb1 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -789,12 +789,6 @@ void *acpi_get_match_data(const struct device *dev)
 {
     const struct acpi_device_id *match;
-    if (!dev->driver)
-        return NULL;
-
-    if (!dev->driver->acpi_match_table)
-        return NULL;
-
     match = acpi_match_device(dev->driver->acpi_match_table, dev);
     if (!match)
         return NULL;
--
1.8.3.1
SOURCES/0007-net-mvpp2-simplify-the-Tx-desc-set-DMA-logic.patch
New file
@@ -0,0 +1,116 @@
From ed377c192631a3b01501f6332156328efa11babf Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Mon, 30 Oct 2017 11:23:33 +0100
Subject: [PATCH 07/46] net: mvpp2: simplify the Tx desc set DMA logic
Two functions were always used to set the DMA addresses in Tx
descriptors, because this address is split into a base+offset in the
descriptors. A mask was used to come up with the base and offset
addresses and two functions were called, mvpp2_txdesc_dma_addr_set() and
mvpp2_txdesc_offset_set().
This patch moves the base+offset calculation logic to
mvpp2_txdesc_dma_addr_set(), and removes mvpp2_txdesc_offset_set() to
simplify things.
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 6eb5d375cefcbd60ebb4251b150ea95d47140fe0)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 39 ++++++++++++------------------------
 1 file changed, 13 insertions(+), 26 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 9a9decb..fb0d9c0 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -1290,13 +1290,20 @@ static void mvpp2_txdesc_dma_addr_set(struct mvpp2_port *port,
                       struct mvpp2_tx_desc *tx_desc,
                       dma_addr_t dma_addr)
 {
+    dma_addr_t addr, offset;
+
+    addr = dma_addr & ~MVPP2_TX_DESC_ALIGN;
+    offset = dma_addr & MVPP2_TX_DESC_ALIGN;
+
     if (port->priv->hw_version == MVPP21) {
-        tx_desc->pp21.buf_dma_addr = dma_addr;
+        tx_desc->pp21.buf_dma_addr = addr;
+        tx_desc->pp21.packet_offset = offset;
     } else {
-        u64 val = (u64)dma_addr;
+        u64 val = (u64)addr;
         tx_desc->pp22.buf_dma_addr_ptp &= ~GENMASK_ULL(40, 0);
         tx_desc->pp22.buf_dma_addr_ptp |= val;
+        tx_desc->pp22.packet_offset = offset;
     }
 }
@@ -1339,16 +1346,6 @@ static void mvpp2_txdesc_cmd_set(struct mvpp2_port *port,
         tx_desc->pp22.command = command;
 }
-static void mvpp2_txdesc_offset_set(struct mvpp2_port *port,
-                    struct mvpp2_tx_desc *tx_desc,
-                    unsigned int offset)
-{
-    if (port->priv->hw_version == MVPP21)
-        tx_desc->pp21.packet_offset = offset;
-    else
-        tx_desc->pp22.packet_offset = offset;
-}
-
 static unsigned int mvpp2_txdesc_offset_get(struct mvpp2_port *port,
                         struct mvpp2_tx_desc *tx_desc)
 {
@@ -6292,10 +6289,7 @@ static int mvpp2_tx_frag_process(struct mvpp2_port *port, struct sk_buff *skb,
             goto cleanup;
         }
-        mvpp2_txdesc_offset_set(port, tx_desc,
-                    buf_dma_addr & MVPP2_TX_DESC_ALIGN);
-        mvpp2_txdesc_dma_addr_set(port, tx_desc,
-                      buf_dma_addr & ~MVPP2_TX_DESC_ALIGN);
+        mvpp2_txdesc_dma_addr_set(port, tx_desc, buf_dma_addr);
         if (i == (skb_shinfo(skb)->nr_frags - 1)) {
             /* Last descriptor */
@@ -6338,8 +6332,7 @@ static inline void mvpp2_tso_put_hdr(struct sk_buff *skb,
     addr = txq_pcpu->tso_headers_dma +
            txq_pcpu->txq_put_index * TSO_HEADER_SIZE;
-    mvpp2_txdesc_offset_set(port, tx_desc, addr & MVPP2_TX_DESC_ALIGN);
-    mvpp2_txdesc_dma_addr_set(port, tx_desc, addr & ~MVPP2_TX_DESC_ALIGN);
+    mvpp2_txdesc_dma_addr_set(port, tx_desc, addr);
     mvpp2_txdesc_cmd_set(port, tx_desc, mvpp2_skb_tx_csum(port, skb) |
                         MVPP2_TXD_F_DESC |
@@ -6368,10 +6361,7 @@ static inline int mvpp2_tso_put_data(struct sk_buff *skb,
         return -ENOMEM;
     }
-    mvpp2_txdesc_offset_set(port, tx_desc,
-                buf_dma_addr & MVPP2_TX_DESC_ALIGN);
-    mvpp2_txdesc_dma_addr_set(port, tx_desc,
-                  buf_dma_addr & ~MVPP2_TX_DESC_ALIGN);
+    mvpp2_txdesc_dma_addr_set(port, tx_desc, buf_dma_addr);
     if (!left) {
         mvpp2_txdesc_cmd_set(port, tx_desc, MVPP2_TXD_L_DESC);
@@ -6483,10 +6473,7 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev)
         goto out;
     }
-    mvpp2_txdesc_offset_set(port, tx_desc,
-                buf_dma_addr & MVPP2_TX_DESC_ALIGN);
-    mvpp2_txdesc_dma_addr_set(port, tx_desc,
-                  buf_dma_addr & ~MVPP2_TX_DESC_ALIGN);
+    mvpp2_txdesc_dma_addr_set(port, tx_desc, buf_dma_addr);
     tx_cmd = mvpp2_skb_tx_csum(port, skb);
--
2.7.4
SOURCES/0008-BACKPORT-ACPI-bus-Rename-acpi_get_match_data-to-acpi.patch
New file
@@ -0,0 +1,73 @@
From 0fe2601c5f132408da07b3e674d5932549375616 Mon Sep 17 00:00:00 2001
From: Khuong Dinh <khuong.dinh@amperecomputing.com>
Date: Fri, 9 Feb 2018 17:38:35 +0200
Subject: [PATCH 08/11] BACKPORT: ACPI / bus: Rename acpi_get_match_data() to
 acpi_device_get_match_data()
Do the renaming to be consistent with its sibling, i.e.
of_device_get_match_data().
No functional change.
This patch is required to support AHCI ALPM de-feature for Ampere Computing
eMAG SATA.
This patch is backported from:
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?h=next-20180913&id=29d5325a14ab49375476e3a6442ff40a008a8c9a
Change-Id: I1e4becb2b3aced73f30b77ec99b2882983639f50
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Khuong Dinh <khuong.dinh@amperecomputing.com>
---
 drivers/acpi/bus.c   | 4 ++--
 include/linux/acpi.h | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index b271eb1..da29c10 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -785,7 +785,7 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
 }
 EXPORT_SYMBOL_GPL(acpi_match_device);
-void *acpi_get_match_data(const struct device *dev)
+void *acpi_device_get_match_data(const struct device *dev)
 {
     const struct acpi_device_id *match;
@@ -795,7 +795,7 @@ void *acpi_get_match_data(const struct device *dev)
     return (void *)match->driver_data;
 }
-EXPORT_SYMBOL_GPL(acpi_get_match_data);
+EXPORT_SYMBOL_GPL(acpi_device_get_match_data);
 int acpi_match_device_ids(struct acpi_device *device,
               const struct acpi_device_id *ids)
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 42e1565..379619e 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -584,7 +584,7 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
 const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
                            const struct device *dev);
-void *acpi_get_match_data(const struct device *dev);
+void *acpi_device_get_match_data(const struct device *dev);
 extern bool acpi_driver_match_device(struct device *dev,
                      const struct device_driver *drv);
 int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
@@ -756,7 +756,7 @@ static inline const struct acpi_device_id *acpi_match_device(
     return NULL;
 }
-static inline void *acpi_get_match_data(const struct device *dev)
+static inline void *acpi_device_get_match_data(const struct device *dev)
 {
     return NULL;
 }
--
1.8.3.1
SOURCES/0008-net-mvpp2-add-ethtool-GOP-statistics.patch
New file
@@ -0,0 +1,375 @@
From 274098c872141c923ee78936e9bf1e9c2597c82b Mon Sep 17 00:00:00 2001
From: Miquel Raynal <miquel.raynal@free-electrons.com>
Date: Mon, 6 Nov 2017 22:56:53 +0100
Subject: [PATCH 08/46] net: mvpp2: add ethtool GOP statistics
Add ethtool statistics support by reading the GOP statistics from the
hardware counters. Also implement a workqueue to gather the statistics
every second or some 32-bit counters could overflow.
Suggested-by: Stefan Chulski <stefanc@marvell.com>
Signed-off-by: Miquel Raynal <miquel.raynal@free-electrons.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 118d6298f6f0556e54331a6e86de2313d134fdbb)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 228 ++++++++++++++++++++++++++++++++++-
 1 file changed, 223 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index fb0d9c0..a79d2ff 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -799,6 +799,42 @@ enum mvpp2_bm_type {
     MVPP2_BM_SWF_SHORT
 };
+/* GMAC MIB Counters register definitions */
+#define MVPP21_MIB_COUNTERS_OFFSET        0x1000
+#define MVPP21_MIB_COUNTERS_PORT_SZ        0x400
+#define MVPP22_MIB_COUNTERS_OFFSET        0x0
+#define MVPP22_MIB_COUNTERS_PORT_SZ        0x100
+
+#define MVPP2_MIB_GOOD_OCTETS_RCVD        0x0
+#define MVPP2_MIB_BAD_OCTETS_RCVD        0x8
+#define MVPP2_MIB_CRC_ERRORS_SENT        0xc
+#define MVPP2_MIB_UNICAST_FRAMES_RCVD        0x10
+#define MVPP2_MIB_BROADCAST_FRAMES_RCVD        0x18
+#define MVPP2_MIB_MULTICAST_FRAMES_RCVD        0x1c
+#define MVPP2_MIB_FRAMES_64_OCTETS        0x20
+#define MVPP2_MIB_FRAMES_65_TO_127_OCTETS    0x24
+#define MVPP2_MIB_FRAMES_128_TO_255_OCTETS    0x28
+#define MVPP2_MIB_FRAMES_256_TO_511_OCTETS    0x2c
+#define MVPP2_MIB_FRAMES_512_TO_1023_OCTETS    0x30
+#define MVPP2_MIB_FRAMES_1024_TO_MAX_OCTETS    0x34
+#define MVPP2_MIB_GOOD_OCTETS_SENT        0x38
+#define MVPP2_MIB_UNICAST_FRAMES_SENT        0x40
+#define MVPP2_MIB_MULTICAST_FRAMES_SENT        0x48
+#define MVPP2_MIB_BROADCAST_FRAMES_SENT        0x4c
+#define MVPP2_MIB_FC_SENT            0x54
+#define MVPP2_MIB_FC_RCVD            0x58
+#define MVPP2_MIB_RX_FIFO_OVERRUN        0x5c
+#define MVPP2_MIB_UNDERSIZE_RCVD        0x60
+#define MVPP2_MIB_FRAGMENTS_RCVD        0x64
+#define MVPP2_MIB_OVERSIZE_RCVD            0x68
+#define MVPP2_MIB_JABBER_RCVD            0x6c
+#define MVPP2_MIB_MAC_RCV_ERROR            0x70
+#define MVPP2_MIB_BAD_CRC_EVENT            0x74
+#define MVPP2_MIB_COLLISION            0x78
+#define MVPP2_MIB_LATE_COLLISION        0x7c
+
+#define MVPP2_MIB_COUNTERS_STATS_DELAY        (1 * HZ)
+
 /* Definitions */
 /* Shared Packet Processor resources */
@@ -826,6 +862,7 @@ struct mvpp2 {
     struct clk *axi_clk;
     /* List of pointers to port structures */
+    int port_count;
     struct mvpp2_port **port_list;
     /* Aggregated TXQs */
@@ -847,6 +884,12 @@ struct mvpp2 {
     /* Maximum number of RXQs per port */
     unsigned int max_port_rxqs;
+
+    /* Workqueue to gather hardware statistics with its lock */
+    struct mutex gather_stats_lock;
+    struct delayed_work stats_work;
+    char queue_name[30];
+    struct workqueue_struct *stats_queue;
 };
 struct mvpp2_pcpu_stats {
@@ -891,6 +934,7 @@ struct mvpp2_port {
     /* Per-port registers' base address */
     void __iomem *base;
+    void __iomem *stats_base;
     struct mvpp2_rx_queue **rxqs;
     unsigned int nrxqs;
@@ -909,6 +953,7 @@ struct mvpp2_port {
     u16 tx_ring_size;
     u16 rx_ring_size;
     struct mvpp2_pcpu_stats __percpu *stats;
+    u64 *ethtool_stats;
     phy_interface_t phy_interface;
     struct device_node *phy_node;
@@ -4778,9 +4823,136 @@ static void mvpp2_port_loopback_set(struct mvpp2_port *port)
     writel(val, port->base + MVPP2_GMAC_CTRL_1_REG);
 }
+struct mvpp2_ethtool_counter {
+    unsigned int offset;
+    const char string[ETH_GSTRING_LEN];
+    bool reg_is_64b;
+};
+
+static u64 mvpp2_read_count(struct mvpp2_port *port,
+                const struct mvpp2_ethtool_counter *counter)
+{
+    u64 val;
+
+    val = readl(port->stats_base + counter->offset);
+    if (counter->reg_is_64b)
+        val += (u64)readl(port->stats_base + counter->offset + 4) << 32;
+
+    return val;
+}
+
+/* Due to the fact that software statistics and hardware statistics are, by
+ * design, incremented at different moments in the chain of packet processing,
+ * it is very likely that incoming packets could have been dropped after being
+ * counted by hardware but before reaching software statistics (most probably
+ * multicast packets), and in the oppposite way, during transmission, FCS bytes
+ * are added in between as well as TSO skb will be split and header bytes added.
+ * Hence, statistics gathered from userspace with ifconfig (software) and
+ * ethtool (hardware) cannot be compared.
+ */
+static const struct mvpp2_ethtool_counter mvpp2_ethtool_regs[] = {
+    { MVPP2_MIB_GOOD_OCTETS_RCVD, "good_octets_received", true },
+    { MVPP2_MIB_BAD_OCTETS_RCVD, "bad_octets_received" },
+    { MVPP2_MIB_CRC_ERRORS_SENT, "crc_errors_sent" },
+    { MVPP2_MIB_UNICAST_FRAMES_RCVD, "unicast_frames_received" },
+    { MVPP2_MIB_BROADCAST_FRAMES_RCVD, "broadcast_frames_received" },
+    { MVPP2_MIB_MULTICAST_FRAMES_RCVD, "multicast_frames_received" },
+    { MVPP2_MIB_FRAMES_64_OCTETS, "frames_64_octets" },
+    { MVPP2_MIB_FRAMES_65_TO_127_OCTETS, "frames_65_to_127_octet" },
+    { MVPP2_MIB_FRAMES_128_TO_255_OCTETS, "frames_128_to_255_octet" },
+    { MVPP2_MIB_FRAMES_256_TO_511_OCTETS, "frames_256_to_511_octet" },
+    { MVPP2_MIB_FRAMES_512_TO_1023_OCTETS, "frames_512_to_1023_octet" },
+    { MVPP2_MIB_FRAMES_1024_TO_MAX_OCTETS, "frames_1024_to_max_octet" },
+    { MVPP2_MIB_GOOD_OCTETS_SENT, "good_octets_sent", true },
+    { MVPP2_MIB_UNICAST_FRAMES_SENT, "unicast_frames_sent" },
+    { MVPP2_MIB_MULTICAST_FRAMES_SENT, "multicast_frames_sent" },
+    { MVPP2_MIB_BROADCAST_FRAMES_SENT, "broadcast_frames_sent" },
+    { MVPP2_MIB_FC_SENT, "fc_sent" },
+    { MVPP2_MIB_FC_RCVD, "fc_received" },
+    { MVPP2_MIB_RX_FIFO_OVERRUN, "rx_fifo_overrun" },
+    { MVPP2_MIB_UNDERSIZE_RCVD, "undersize_received" },
+    { MVPP2_MIB_FRAGMENTS_RCVD, "fragments_received" },
+    { MVPP2_MIB_OVERSIZE_RCVD, "oversize_received" },
+    { MVPP2_MIB_JABBER_RCVD, "jabber_received" },
+    { MVPP2_MIB_MAC_RCV_ERROR, "mac_receive_error" },
+    { MVPP2_MIB_BAD_CRC_EVENT, "bad_crc_event" },
+    { MVPP2_MIB_COLLISION, "collision" },
+    { MVPP2_MIB_LATE_COLLISION, "late_collision" },
+};
+
+static void mvpp2_ethtool_get_strings(struct net_device *netdev, u32 sset,
+                      u8 *data)
+{
+    if (sset == ETH_SS_STATS) {
+        int i;
+
+        for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_regs); i++)
+            memcpy(data + i * ETH_GSTRING_LEN,
+                   &mvpp2_ethtool_regs[i].string, ETH_GSTRING_LEN);
+    }
+}
+
+static void mvpp2_gather_hw_statistics(struct work_struct *work)
+{
+    struct delayed_work *del_work = to_delayed_work(work);
+    struct mvpp2 *priv = container_of(del_work, struct mvpp2, stats_work);
+    struct mvpp2_port *port;
+    u64 *pstats;
+    int i, j;
+
+    mutex_lock(&priv->gather_stats_lock);
+
+    for (i = 0; i < priv->port_count; i++) {
+        if (!priv->port_list[i])
+            continue;
+
+        port = priv->port_list[i];
+        pstats = port->ethtool_stats;
+        for (j = 0; j < ARRAY_SIZE(mvpp2_ethtool_regs); j++)
+            *pstats++ += mvpp2_read_count(port,
+                              &mvpp2_ethtool_regs[j]);
+    }
+
+    /* No need to read again the counters right after this function if it
+     * was called asynchronously by the user (ie. use of ethtool).
+     */
+    cancel_delayed_work(&priv->stats_work);
+    queue_delayed_work(priv->stats_queue, &priv->stats_work,
+               MVPP2_MIB_COUNTERS_STATS_DELAY);
+
+    mutex_unlock(&priv->gather_stats_lock);
+}
+
+static void mvpp2_ethtool_get_stats(struct net_device *dev,
+                    struct ethtool_stats *stats, u64 *data)
+{
+    struct mvpp2_port *port = netdev_priv(dev);
+
+    /* Update statistics for all ports, copy only those actually needed */
+    mvpp2_gather_hw_statistics(&port->priv->stats_work.work);
+
+    mutex_lock(&port->priv->gather_stats_lock);
+    memcpy(data, port->ethtool_stats,
+           sizeof(u64) * ARRAY_SIZE(mvpp2_ethtool_regs));
+    mutex_unlock(&port->priv->gather_stats_lock);
+}
+
+static int mvpp2_ethtool_get_sset_count(struct net_device *dev, int sset)
+{
+    if (sset == ETH_SS_STATS)
+        return ARRAY_SIZE(mvpp2_ethtool_regs);
+
+    return -EOPNOTSUPP;
+}
+
 static void mvpp2_port_reset(struct mvpp2_port *port)
 {
     u32 val;
+    unsigned int i;
+
+    /* Read the GOP statistics to reset the hardware counters */
+    for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_regs); i++)
+        mvpp2_read_count(port, &mvpp2_ethtool_regs[i]);
     val = readl(port->base + MVPP2_GMAC_CTRL_2_REG) &
             ~MVPP2_GMAC_PORT_RESET_MASK;
@@ -6916,6 +7088,10 @@ static int mvpp2_open(struct net_device *dev)
     if (priv->hw_version == MVPP22)
         mvpp22_init_rss(port);
+    /* Start hardware statistics gathering */
+    queue_delayed_work(priv->stats_queue, &priv->stats_work,
+               MVPP2_MIB_COUNTERS_STATS_DELAY);
+
     return 0;
 err_free_link_irq:
@@ -6960,6 +7136,9 @@ static int mvpp2_stop(struct net_device *dev)
     mvpp2_cleanup_rxqs(port);
     mvpp2_cleanup_txqs(port);
+    cancel_delayed_work_sync(&priv->stats_work);
+    flush_workqueue(priv->stats_queue);
+
     return 0;
 }
@@ -7271,6 +7450,9 @@ static const struct ethtool_ops mvpp2_eth_tool_ops = {
     .get_drvinfo    = mvpp2_ethtool_get_drvinfo,
     .get_ringparam    = mvpp2_ethtool_get_ringparam,
     .set_ringparam    = mvpp2_ethtool_set_ringparam,
+    .get_strings    = mvpp2_ethtool_get_strings,
+    .get_ethtool_stats = mvpp2_ethtool_get_stats,
+    .get_sset_count    = mvpp2_ethtool_get_sset_count,
     .get_link_ksettings = phy_ethtool_get_link_ksettings,
     .set_link_ksettings = phy_ethtool_set_link_ksettings,
 };
@@ -7674,6 +7856,10 @@ static int mvpp2_port_probe(struct platform_device *pdev,
             err = PTR_ERR(port->base);
             goto err_free_irq;
         }
+
+        port->stats_base = port->priv->lms_base +
+                   MVPP21_MIB_COUNTERS_OFFSET +
+                   port->gop_id * MVPP21_MIB_COUNTERS_PORT_SZ;
     } else {
         if (of_property_read_u32(port_node, "gop-port-id",
                      &port->gop_id)) {
@@ -7683,15 +7869,26 @@ static int mvpp2_port_probe(struct platform_device *pdev,
         }
         port->base = priv->iface_base + MVPP22_GMAC_BASE(port->gop_id);
+        port->stats_base = port->priv->iface_base +
+                   MVPP22_MIB_COUNTERS_OFFSET +
+                   port->gop_id * MVPP22_MIB_COUNTERS_PORT_SZ;
     }
-    /* Alloc per-cpu stats */
+    /* Alloc per-cpu and ethtool stats */
     port->stats = netdev_alloc_pcpu_stats(struct mvpp2_pcpu_stats);
     if (!port->stats) {
         err = -ENOMEM;
         goto err_free_irq;
     }
+    port->ethtool_stats = devm_kcalloc(&pdev->dev,
+                       ARRAY_SIZE(mvpp2_ethtool_regs),
+                       sizeof(u64), GFP_KERNEL);
+    if (!port->ethtool_stats) {
+        err = -ENOMEM;
+        goto err_free_stats;
+    }
+
     mvpp2_port_copy_mac_addr(dev, priv, port_node, &mac_from);
     port->tx_ring_size = MVPP2_MAX_TXD;
@@ -8014,7 +8211,7 @@ static int mvpp2_probe(struct platform_device *pdev)
     struct mvpp2 *priv;
     struct resource *res;
     void __iomem *base;
-    int port_count, i;
+    int i;
     int err;
     priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@@ -8129,14 +8326,14 @@ static int mvpp2_probe(struct platform_device *pdev)
         goto err_mg_clk;
     }
-    port_count = of_get_available_child_count(dn);
-    if (port_count == 0) {
+    priv->port_count = of_get_available_child_count(dn);
+    if (priv->port_count == 0) {
         dev_err(&pdev->dev, "no ports enabled\n");
         err = -ENODEV;
         goto err_mg_clk;
     }
-    priv->port_list = devm_kcalloc(&pdev->dev, port_count,
+    priv->port_list = devm_kcalloc(&pdev->dev, priv->port_count,
                        sizeof(*priv->port_list),
                        GFP_KERNEL);
     if (!priv->port_list) {
@@ -8153,6 +8350,24 @@ static int mvpp2_probe(struct platform_device *pdev)
         i++;
     }
+    /* Statistics must be gathered regularly because some of them (like
+     * packets counters) are 32-bit registers and could overflow quite
+     * quickly. For instance, a 10Gb link used at full bandwidth with the
+     * smallest packets (64B) will overflow a 32-bit counter in less than
+     * 30 seconds. Then, use a workqueue to fill 64-bit counters.
+     */
+    mutex_init(&priv->gather_stats_lock);
+    snprintf(priv->queue_name, sizeof(priv->queue_name),
+         "stats-wq-%s%s", netdev_name(priv->port_list[0]->dev),
+         priv->port_count > 1 ? "+" : "");
+    priv->stats_queue = create_singlethread_workqueue(priv->queue_name);
+    if (!priv->stats_queue) {
+        err = -ENOMEM;
+        goto err_mg_clk;
+    }
+
+    INIT_DELAYED_WORK(&priv->stats_work, mvpp2_gather_hw_statistics);
+
     platform_set_drvdata(pdev, priv);
     return 0;
@@ -8174,6 +8389,9 @@ static int mvpp2_remove(struct platform_device *pdev)
     struct device_node *port_node;
     int i = 0;
+    destroy_workqueue(priv->stats_queue);
+    mutex_destroy(&priv->gather_stats_lock);
+
     for_each_available_child_of_node(dn, port_node) {
         if (priv->port_list[i])
             mvpp2_port_remove(priv->port_list[i]);
--
2.7.4
SOURCES/0009-BACKPORT-ata-Disable-AHCI-ALPM-feature-for-Ampere-Co.patch
New file
@@ -0,0 +1,72 @@
From 38b559f8ab1a556cab575c907202dcc7027bc4d2 Mon Sep 17 00:00:00 2001
From: Khuong Dinh <khuong.dinh@amperecomputing.com>
Date: Fri, 7 Sep 2018 08:32:17 -0600
Subject: [PATCH 09/11] BACKPORT ata: Disable AHCI ALPM feature for Ampere
 Computing eMAG SATA
Due to hardware errata, Ampere Computing eMAG SATA can't support
AHCI ALPM feature. This patch disables the AHCI ALPM feature for
eMAG SATA.
This patch is backported from:
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?h=next-20180913&id=20bdc376b427cb420836f39ee8f281ea85dbaeef
Change-Id: I21d4a6ed7bd1f103f696b3865248c562288e2886
Signed-off-by: Suman Trpathi <stripathi@amperecomputing.com>
Signed-off-by: Rameshwar Prasad Sahu <rameshwar.sahu@amperecomputing.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Khuong Dinh <khuong.dinh@amperecomputing.com>
---
 drivers/ata/ahci_platform.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 99f9a89..9ba283f 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -33,6 +33,13 @@
     .port_ops    = &ahci_platform_ops,
 };
+static const struct ata_port_info ahci_port_info_nolpm = {
+    .flags        = AHCI_FLAG_COMMON | ATA_FLAG_NO_LPM,
+    .pio_mask    = ATA_PIO4,
+    .udma_mask    = ATA_UDMA6,
+    .port_ops    = &ahci_platform_ops,
+};
+
 static struct scsi_host_template ahci_platform_sht = {
     AHCI_SHT(DRV_NAME),
 };
@@ -41,6 +48,7 @@ static int ahci_probe(struct platform_device *pdev)
 {
     struct device *dev = &pdev->dev;
     struct ahci_host_priv *hpriv;
+    const struct ata_port_info *port;
     int rc;
     hpriv = ahci_platform_get_resources(pdev);
@@ -57,7 +65,11 @@ static int ahci_probe(struct platform_device *pdev)
     if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci"))
         hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
-    rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info,
+    port = acpi_device_get_match_data(dev);
+    if (!port)
+        port = &ahci_port_info;
+
+    rc = ahci_platform_init_host(pdev, hpriv, port,
                      &ahci_platform_sht);
     if (rc)
         goto disable_resources;
@@ -85,6 +97,7 @@ static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
 MODULE_DEVICE_TABLE(of, ahci_of_match);
 static const struct acpi_device_id ahci_acpi_match[] = {
+    { "APMC0D33", (unsigned long)&ahci_port_info_nolpm },
     { ACPI_DEVICE_CLASS(PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff) },
     {},
 };
--
1.8.3.1
SOURCES/0009-net-mvpp2-fix-GOP-statistics-loop-start-and-stop-con.patch
New file
@@ -0,0 +1,180 @@
From 7dc5b326b4430a292de27c404b2f36fcdb5ec67f Mon Sep 17 00:00:00 2001
From: Miquel Raynal <miquel.raynal@free-electrons.com>
Date: Wed, 8 Nov 2017 08:59:40 +0100
Subject: [PATCH 09/46] net: mvpp2: fix GOP statistics loop start and stop
 conditions
GOP statistics from all ports of one instance of the driver are gathered
with one work recalled in loop in a workqueue. The loop is started when
a port is up, and stopped when a port is down. This last condition is
obviously wrong.
Fix this by having a work per port. This way, starting and stoping it
when the port is up or down will be fine, while minimizing unnecessary
CPU usage.
Fixes: 118d6298f6f0 ("net: mvpp2: add ethtool GOP statistics")
Reported-by: Stefan Chulski <stefanc@marvell.com>
Signed-off-by: Miquel Raynal <miquel.raynal@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit e5c500eb298a9f5ef9b80d16fcea9662c89467b7)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 62 +++++++++++++++++-------------------
 1 file changed, 30 insertions(+), 32 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index a79d2ff..6c20e81 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -885,9 +885,7 @@ struct mvpp2 {
     /* Maximum number of RXQs per port */
     unsigned int max_port_rxqs;
-    /* Workqueue to gather hardware statistics with its lock */
-    struct mutex gather_stats_lock;
-    struct delayed_work stats_work;
+    /* Workqueue to gather hardware statistics */
     char queue_name[30];
     struct workqueue_struct *stats_queue;
 };
@@ -955,6 +953,10 @@ struct mvpp2_port {
     struct mvpp2_pcpu_stats __percpu *stats;
     u64 *ethtool_stats;
+    /* Per-port work and its lock to gather hardware statistics */
+    struct mutex gather_stats_lock;
+    struct delayed_work stats_work;
+
     phy_interface_t phy_interface;
     struct device_node *phy_node;
     struct phy *comphy;
@@ -4895,32 +4897,25 @@ static void mvpp2_ethtool_get_strings(struct net_device *netdev, u32 sset,
 static void mvpp2_gather_hw_statistics(struct work_struct *work)
 {
     struct delayed_work *del_work = to_delayed_work(work);
-    struct mvpp2 *priv = container_of(del_work, struct mvpp2, stats_work);
-    struct mvpp2_port *port;
+    struct mvpp2_port *port = container_of(del_work, struct mvpp2_port,
+                           stats_work);
     u64 *pstats;
-    int i, j;
-
-    mutex_lock(&priv->gather_stats_lock);
+    int i;
-    for (i = 0; i < priv->port_count; i++) {
-        if (!priv->port_list[i])
-            continue;
+    mutex_lock(&port->gather_stats_lock);
-        port = priv->port_list[i];
-        pstats = port->ethtool_stats;
-        for (j = 0; j < ARRAY_SIZE(mvpp2_ethtool_regs); j++)
-            *pstats++ += mvpp2_read_count(port,
-                              &mvpp2_ethtool_regs[j]);
-    }
+    pstats = port->ethtool_stats;
+    for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_regs); i++)
+        *pstats++ += mvpp2_read_count(port, &mvpp2_ethtool_regs[i]);
     /* No need to read again the counters right after this function if it
      * was called asynchronously by the user (ie. use of ethtool).
      */
-    cancel_delayed_work(&priv->stats_work);
-    queue_delayed_work(priv->stats_queue, &priv->stats_work,
+    cancel_delayed_work(&port->stats_work);
+    queue_delayed_work(port->priv->stats_queue, &port->stats_work,
                MVPP2_MIB_COUNTERS_STATS_DELAY);
-    mutex_unlock(&priv->gather_stats_lock);
+    mutex_unlock(&port->gather_stats_lock);
 }
 static void mvpp2_ethtool_get_stats(struct net_device *dev,
@@ -4928,13 +4923,15 @@ static void mvpp2_ethtool_get_stats(struct net_device *dev,
 {
     struct mvpp2_port *port = netdev_priv(dev);
-    /* Update statistics for all ports, copy only those actually needed */
-    mvpp2_gather_hw_statistics(&port->priv->stats_work.work);
+    /* Update statistics for the given port, then take the lock to avoid
+     * concurrent accesses on the ethtool_stats structure during its copy.
+     */
+    mvpp2_gather_hw_statistics(&port->stats_work.work);
-    mutex_lock(&port->priv->gather_stats_lock);
+    mutex_lock(&port->gather_stats_lock);
     memcpy(data, port->ethtool_stats,
            sizeof(u64) * ARRAY_SIZE(mvpp2_ethtool_regs));
-    mutex_unlock(&port->priv->gather_stats_lock);
+    mutex_unlock(&port->gather_stats_lock);
 }
 static int mvpp2_ethtool_get_sset_count(struct net_device *dev, int sset)
@@ -7089,7 +7086,7 @@ static int mvpp2_open(struct net_device *dev)
         mvpp22_init_rss(port);
     /* Start hardware statistics gathering */
-    queue_delayed_work(priv->stats_queue, &priv->stats_work,
+    queue_delayed_work(priv->stats_queue, &port->stats_work,
                MVPP2_MIB_COUNTERS_STATS_DELAY);
     return 0;
@@ -7136,8 +7133,7 @@ static int mvpp2_stop(struct net_device *dev)
     mvpp2_cleanup_rxqs(port);
     mvpp2_cleanup_txqs(port);
-    cancel_delayed_work_sync(&priv->stats_work);
-    flush_workqueue(priv->stats_queue);
+    cancel_delayed_work_sync(&port->stats_work);
     return 0;
 }
@@ -7889,6 +7885,9 @@ static int mvpp2_port_probe(struct platform_device *pdev,
         goto err_free_stats;
     }
+    mutex_init(&port->gather_stats_lock);
+    INIT_DELAYED_WORK(&port->stats_work, mvpp2_gather_hw_statistics);
+
     mvpp2_port_copy_mac_addr(dev, priv, port_node, &mac_from);
     port->tx_ring_size = MVPP2_MAX_TXD;
@@ -8356,7 +8355,6 @@ static int mvpp2_probe(struct platform_device *pdev)
      * smallest packets (64B) will overflow a 32-bit counter in less than
      * 30 seconds. Then, use a workqueue to fill 64-bit counters.
      */
-    mutex_init(&priv->gather_stats_lock);
     snprintf(priv->queue_name, sizeof(priv->queue_name),
          "stats-wq-%s%s", netdev_name(priv->port_list[0]->dev),
          priv->port_count > 1 ? "+" : "");
@@ -8366,8 +8364,6 @@ static int mvpp2_probe(struct platform_device *pdev)
         goto err_mg_clk;
     }
-    INIT_DELAYED_WORK(&priv->stats_work, mvpp2_gather_hw_statistics);
-
     platform_set_drvdata(pdev, priv);
     return 0;
@@ -8389,12 +8385,14 @@ static int mvpp2_remove(struct platform_device *pdev)
     struct device_node *port_node;
     int i = 0;
+    flush_workqueue(priv->stats_queue);
     destroy_workqueue(priv->stats_queue);
-    mutex_destroy(&priv->gather_stats_lock);
     for_each_available_child_of_node(dn, port_node) {
-        if (priv->port_list[i])
+        if (priv->port_list[i]) {
+            mutex_destroy(&priv->port_list[i]->gather_stats_lock);
             mvpp2_port_remove(priv->port_list[i]);
+        }
         i++;
     }
--
2.7.4
SOURCES/0010-BACKPORT-perf-xgene-Fix-IOB-SLOW-PMU-parser-error.patch
New file
@@ -0,0 +1,39 @@
From 55f37c369d9f564cdb7b738fd2a47b7b8975ac52 Mon Sep 17 00:00:00 2001
From: Hoan Tran <hoan.tran@amperecomputing.com>
Date: Tue, 5 Jun 2018 14:48:44 -0700
Subject: [PATCH 10/11] BACKPORT: perf: xgene: Fix IOB SLOW PMU parser error
This patch fixes the below parser error of the IOB SLOW PMU.
    # perf stat -a -e iob-slow0/cycle-count/ sleep 1
    evenf syntax error: 'iob-slow0/cycle-count/'
                             \___ parser error
It replaces the "-" character by "_" character inside the PMU name.
Without this patch, perf for "iob-slow0" PMU does not work.
This patch is backported from https://lkml.org/lkml/2018/6/6/754
Change-Id: Ia5085c305e32f5651e8deedee2958a8b2a987c15
Signed-off-by: Hoan Tran <hoan.tran@amperecomputing.com>
---
 drivers/perf/xgene_pmu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/perf/xgene_pmu.c b/drivers/perf/xgene_pmu.c
index eb23311..8b79c2f 100644
--- a/drivers/perf/xgene_pmu.c
+++ b/drivers/perf/xgene_pmu.c
@@ -1463,7 +1463,7 @@ static char *xgene_pmu_dev_name(struct device *dev, u32 type, int id)
     case PMU_TYPE_IOB:
         return devm_kasprintf(dev, GFP_KERNEL, "iob%d", id);
     case PMU_TYPE_IOB_SLOW:
-        return devm_kasprintf(dev, GFP_KERNEL, "iob-slow%d", id);
+        return devm_kasprintf(dev, GFP_KERNEL, "iob_slow%d", id);
     case PMU_TYPE_MCB:
         return devm_kasprintf(dev, GFP_KERNEL, "mcb%d", id);
     case PMU_TYPE_MC:
--
1.8.3.1
SOURCES/0010-net-mvpp2-fix-the-txq_init-error-path.patch
New file
@@ -0,0 +1,70 @@
From 7be8a46cfb0d162f7733ccd6dd57810285a0ce9e Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Tue, 28 Nov 2017 14:19:48 +0100
Subject: [PATCH 10/46] net: mvpp2: fix the txq_init error path
When an allocation in the txq_init path fails, the allocated buffers
end-up being freed twice: in the txq_init error path, and in txq_deinit.
This lead to issues as txq_deinit would work on already freed memory
regions:
    kernel BUG at mm/slub.c:3915!
    Internal error: Oops - BUG: 0 [#1] PREEMPT SMP
This patch fixes this by removing the txq_init own error path, as the
txq_deinit function is always called on errors. This was introduced by
TSO as way more buffers are allocated.
Fixes: 186cd4d4e414 ("net: mvpp2: software tso support")
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit ba2d8d887d962c2f790e6dc01b2fd25b4608720b)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 20 ++------------------
 1 file changed, 2 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 6c20e81..79f01cd 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -5805,7 +5805,7 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
                         sizeof(*txq_pcpu->buffs),
                         GFP_KERNEL);
         if (!txq_pcpu->buffs)
-            goto cleanup;
+            return -ENOMEM;
         txq_pcpu->count = 0;
         txq_pcpu->reserved_num = 0;
@@ -5821,26 +5821,10 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
                        &txq_pcpu->tso_headers_dma,
                        GFP_KERNEL);
         if (!txq_pcpu->tso_headers)
-            goto cleanup;
+            return -ENOMEM;
     }
     return 0;
-cleanup:
-    for_each_present_cpu(cpu) {
-        txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
-        kfree(txq_pcpu->buffs);
-
-        dma_free_coherent(port->dev->dev.parent,
-                  txq_pcpu->size * TSO_HEADER_SIZE,
-                  txq_pcpu->tso_headers,
-                  txq_pcpu->tso_headers_dma);
-    }
-
-    dma_free_coherent(port->dev->dev.parent,
-              txq->size * MVPP2_DESC_ALIGNED_SIZE,
-              txq->descs, txq->descs_dma);
-
-    return -ENOMEM;
 }
 /* Free allocated TXQ resources */
--
2.7.4
SOURCES/0011-BACKPORT-iommu-enable-bypass-transaction-caching-for.patch
New file
@@ -0,0 +1,49 @@
From ecf036e63e2a910a7ed1de6b89fe3d8ccf4c4d78 Mon Sep 17 00:00:00 2001
From: Khuong Dinh <kdinh@apm.com>
Date: Fri, 13 Oct 2017 16:07:46 -0600
Subject: [PATCH 11/11] BACKPORT: iommu: enable bypass transaction caching for
 ARM SMMU 500
The ARM SMMU identity mapping performance was poor compared with the
DMA mode. It was found that enable caching would restore the performance
back to normal. The S2CRB_TLBEN bit in the ACR register would allow for
caching of the stream to context register bypass transaction information.
This patch is required to properly support PCIe in virtual environment
for Ampere eMag SoC's.
This patch is backported from:
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?h=next-20180504&id=74f55d34414c866dbf3a69e28a2f963abe61ca58
and was accepted from kernel v4.15.
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Feng Kan <fkan@apm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 drivers/iommu/arm-smmu.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 91ff442..d40f154 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -61,6 +61,7 @@
 #define ARM_MMU500_ACTLR_CPRE        (1 << 1)
 #define ARM_MMU500_ACR_CACHE_LOCK    (1 << 26)
+#define ARM_MMU500_ACR_S2CRB_TLBEN    (1 << 10)
 #define ARM_MMU500_ACR_SMTNMB_TLBEN    (1 << 8)
 #define TLB_LOOP_TIMEOUT        1000000    /* 1s! */
@@ -1608,7 +1609,7 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
          * Allow unmatched Stream IDs to allocate bypass
          * TLB entries for reduced latency.
          */
-        reg |= ARM_MMU500_ACR_SMTNMB_TLBEN;
+        reg |= ARM_MMU500_ACR_SMTNMB_TLBEN | ARM_MMU500_ACR_S2CRB_TLBEN;
         writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_sACR);
     }
--
1.8.3.1
SOURCES/0011-net-mvpp2-cleanup-probed-ports-in-the-probe-error-pa.patch
New file
@@ -0,0 +1,55 @@
From 0691379d3ed50fa89cf16d9b443553a4eb7c9d79 Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Tue, 28 Nov 2017 14:19:49 +0100
Subject: [PATCH 11/46] net: mvpp2: cleanup probed ports in the probe error
 path
This patches fixes the probe error path by cleaning up probed ports, to
avoid leaving registered net devices when the driver failed to probe.
Fixes: 3f518509dedc ("ethernet: Add new driver for Marvell Armada 375 network unit")
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 26146b0e6b6869c6cd8a45ab3a4a5562e7a91b23)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 79f01cd..afae4fe 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -8329,7 +8329,7 @@ static int mvpp2_probe(struct platform_device *pdev)
     for_each_available_child_of_node(dn, port_node) {
         err = mvpp2_port_probe(pdev, port_node, priv, i);
         if (err < 0)
-            goto err_mg_clk;
+            goto err_port_probe;
         i++;
     }
@@ -8345,12 +8345,19 @@ static int mvpp2_probe(struct platform_device *pdev)
     priv->stats_queue = create_singlethread_workqueue(priv->queue_name);
     if (!priv->stats_queue) {
         err = -ENOMEM;
-        goto err_mg_clk;
+        goto err_port_probe;
     }
     platform_set_drvdata(pdev, priv);
     return 0;
+err_port_probe:
+    i = 0;
+    for_each_available_child_of_node(dn, port_node) {
+        if (priv->port_list[i])
+            mvpp2_port_remove(priv->port_list[i]);
+        i++;
+    }
 err_mg_clk:
     clk_disable_unprepare(priv->axi_clk);
     if (priv->hw_version == MVPP22)
--
2.7.4
SOURCES/0012-net-mvpp2-do-not-disable-GMAC-padding.patch
New file
@@ -0,0 +1,51 @@
From 5eae17c1e83b13aaa843f45eca112221eb634c78 Mon Sep 17 00:00:00 2001
From: Yan Markman <ymarkman@marvell.com>
Date: Tue, 28 Nov 2017 14:19:50 +0100
Subject: [PATCH 12/46] net: mvpp2: do not disable GMAC padding
Short fragmented packets may never be sent by the hardware when padding
is disabled. This patch stop modifying the GMAC padding bits, to leave
them to their reset value (disabled).
Fixes: 3919357fb0bb ("net: mvpp2: initialize the GMAC when using a port")
Signed-off-by: Yan Markman <ymarkman@marvell.com>
[Antoine: commit message]
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit e749aca84b10f3987b2ee1f76e0c7d8aacc5653c)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 9 ---------
 1 file changed, 9 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index afae4fe..5be58b0 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -4629,11 +4629,6 @@ static void mvpp2_port_mii_gmac_configure_mode(struct mvpp2_port *port)
                MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE;
         val &= ~MVPP22_CTRL4_EXT_PIN_GMII_SEL;
         writel(val, port->base + MVPP22_GMAC_CTRL_4_REG);
-
-        val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
-        val |= MVPP2_GMAC_DISABLE_PADDING;
-        val &= ~MVPP2_GMAC_FLOW_CTRL_MASK;
-        writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
     } else if (phy_interface_mode_is_rgmii(port->phy_interface)) {
         val = readl(port->base + MVPP22_GMAC_CTRL_4_REG);
         val |= MVPP22_CTRL4_EXT_PIN_GMII_SEL |
@@ -4641,10 +4636,6 @@ static void mvpp2_port_mii_gmac_configure_mode(struct mvpp2_port *port)
                MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE;
         val &= ~MVPP22_CTRL4_DP_CLK_SEL;
         writel(val, port->base + MVPP22_GMAC_CTRL_4_REG);
-
-        val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
-        val &= ~MVPP2_GMAC_DISABLE_PADDING;
-        writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
     }
     /* The port is connected to a copper PHY */
--
2.7.4
SOURCES/0013-net-mvpp2-check-ethtool-sets-the-Tx-ring-size-is-to-.patch
New file
@@ -0,0 +1,41 @@
From d624fd6fd3b32311a6060d43e5af4e9328611805 Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Tue, 28 Nov 2017 14:19:51 +0100
Subject: [PATCH 13/46] net: mvpp2: check ethtool sets the Tx ring size is to a
 valid min value
This patch fixes the Tx ring size checks when using ethtool, by adding
an extra check in the PPv2 check_ringparam_valid helper. The Tx ring
size cannot be set to a value smaller than the minimum number of
descriptors needed for TSO.
Fixes: 1d17db08c056 ("net: mvpp2: limit TSO segments and use stop/wake thresholds")
Suggested-by: Yan Markman <ymarkman@marvell.com>
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 76e583c5f50ef539caea6935d37af3595034befb)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 6 ++++++
 1 file changed, 6 insertions(+)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 5be58b0..d83a78b 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -6842,6 +6842,12 @@ static int mvpp2_check_ringparam_valid(struct net_device *dev,
     else if (!IS_ALIGNED(ring->tx_pending, 32))
         new_tx_pending = ALIGN(ring->tx_pending, 32);
+    /* The Tx ring size cannot be smaller than the minimum number of
+     * descriptors needed for TSO.
+     */
+    if (new_tx_pending < MVPP2_MAX_SKB_DESCS)
+        new_tx_pending = ALIGN(MVPP2_MAX_SKB_DESCS, 32);
+
     if (ring->rx_pending != new_rx_pending) {
         netdev_info(dev, "illegal Rx ring size value %d, round to %d\n",
                 ring->rx_pending, new_rx_pending);
--
2.7.4
SOURCES/0014-net-mvpp2-allocate-zeroed-tx-descriptors.patch
New file
@@ -0,0 +1,39 @@
From 8002403d50a1be9857e01ed14c3d78473352eef6 Mon Sep 17 00:00:00 2001
From: Yan Markman <ymarkman@marvell.com>
Date: Thu, 30 Nov 2017 10:49:46 +0100
Subject: [PATCH 14/46] net: mvpp2: allocate zeroed tx descriptors
Reserved and unused fields in the Tx descriptors should be 0. The PPv2
driver doesn't clear them at run-time (for performance reasons) but
these descriptors aren't zeroed when allocated, which can lead to
unpredictable behaviors. This patch fixes this by using
dma_zalloc_coherent instead of dma_alloc_coherent.
Fixes: 3f518509dedc ("ethernet: Add new driver for Marvell Armada 375 network unit")
Signed-off-by: Yan Markman <ymarkman@marvell.com>
[Antoine: commit message]
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit a154f8e399a063137fc42b961f437248d55ece29)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index d83a78b..fed2b2f 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -5598,7 +5598,7 @@ static int mvpp2_aggr_txq_init(struct platform_device *pdev,
     u32 txq_dma;
     /* Allocate memory for TX descriptors */
-    aggr_txq->descs = dma_alloc_coherent(&pdev->dev,
+    aggr_txq->descs = dma_zalloc_coherent(&pdev->dev,
                 MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE,
                 &aggr_txq->descs_dma, GFP_KERNEL);
     if (!aggr_txq->descs)
--
2.7.4
SOURCES/0015-net-mvpp2-fix-the-RSS-table-entry-offset.patch
New file
@@ -0,0 +1,34 @@
From 80baeade5961a9692c9dd313fb9aacd951dde1e8 Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Fri, 8 Dec 2017 10:24:20 +0100
Subject: [PATCH 15/46] net: mvpp2: fix the RSS table entry offset
The macro used to access or set an RSS table entry was using an offset
of 8, while it should use an offset of 0. This lead to wrongly configure
the RSS table, not accessing the right entries.
Fixes: 1d7d15d79fb4 ("net: mvpp2: initialize the RSS tables")
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 8a7b741e76cd31b6000636f0391e67ba6793ad1c)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index fed2b2f..634b2f4 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -85,7 +85,7 @@
 /* RSS Registers */
 #define MVPP22_RSS_INDEX            0x1500
-#define     MVPP22_RSS_INDEX_TABLE_ENTRY(idx)    ((idx) << 8)
+#define     MVPP22_RSS_INDEX_TABLE_ENTRY(idx)    (idx)
 #define     MVPP22_RSS_INDEX_TABLE(idx)        ((idx) << 8)
 #define     MVPP22_RSS_INDEX_QUEUE(idx)        ((idx) << 16)
 #define MVPP22_RSS_TABLE_ENTRY            0x1508
--
2.7.4
SOURCES/0016-net-mvpp2-only-free-the-TSO-header-buffers-when-it-w.patch
New file
@@ -0,0 +1,50 @@
From ee5e257740c16b87408633288ee4247835ec2782 Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Mon, 11 Dec 2017 09:13:25 +0100
Subject: [PATCH 16/46] net: mvpp2: only free the TSO header buffers when it
 was allocated
This patch adds a check to only free the TSO header buffer when its
allocation previously succeeded.
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit b70d4a5195c7193d1d55af791d9811477522e25a)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 634b2f4..f203f08 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -5802,6 +5802,7 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
         txq_pcpu->reserved_num = 0;
         txq_pcpu->txq_put_index = 0;
         txq_pcpu->txq_get_index = 0;
+        txq_pcpu->tso_headers = NULL;
         txq_pcpu->stop_threshold = txq->size - MVPP2_MAX_SKB_DESCS;
         txq_pcpu->wake_threshold = txq_pcpu->stop_threshold / 2;
@@ -5829,10 +5830,13 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port,
         txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
         kfree(txq_pcpu->buffs);
-        dma_free_coherent(port->dev->dev.parent,
-                  txq_pcpu->size * TSO_HEADER_SIZE,
-                  txq_pcpu->tso_headers,
-                  txq_pcpu->tso_headers_dma);
+        if (txq_pcpu->tso_headers)
+            dma_free_coherent(port->dev->dev.parent,
+                      txq_pcpu->size * TSO_HEADER_SIZE,
+                      txq_pcpu->tso_headers,
+                      txq_pcpu->tso_headers_dma);
+
+        txq_pcpu->tso_headers = NULL;
     }
     if (txq->descs)
--
2.7.4
SOURCES/0017-net-mvpp2-split-the-max-ring-size-from-the-default-o.patch
New file
@@ -0,0 +1,92 @@
From cd2a3c67f9810ec7f6f873985655ebbba820c9ce Mon Sep 17 00:00:00 2001
From: Yan Markman <ymarkman@marvell.com>
Date: Mon, 11 Dec 2017 09:13:26 +0100
Subject: [PATCH 17/46] net: mvpp2: split the max ring size from the default
 one
The Rx/Tx ring sizes can be adjusted thanks to ethtool given specific
network needs. This commit splits the default ring size from its max
value to allow ethtool to vary the parameters in both ways.
Signed-off-by: Yan Markman <ymarkman@marvell.com>
[Antoine: commit message]
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 7cf87e4a5c2b120967b3fa3a1beb7123eb704d85)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index f203f08..5e88403 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -504,10 +504,12 @@
 #define MVPP2_DEFAULT_RXQ        4
 /* Max number of Rx descriptors */
-#define MVPP2_MAX_RXD            128
+#define MVPP2_MAX_RXD_MAX        1024
+#define MVPP2_MAX_RXD_DFLT        128
 /* Max number of Tx descriptors */
-#define MVPP2_MAX_TXD            1024
+#define MVPP2_MAX_TXD_MAX        2048
+#define MVPP2_MAX_TXD_DFLT        1024
 /* Amount of Tx descriptors that can be reserved at once by CPU */
 #define MVPP2_CPU_DESC_CHUNK        64
@@ -6836,13 +6838,13 @@ static int mvpp2_check_ringparam_valid(struct net_device *dev,
     if (ring->rx_pending == 0 || ring->tx_pending == 0)
         return -EINVAL;
-    if (ring->rx_pending > MVPP2_MAX_RXD)
-        new_rx_pending = MVPP2_MAX_RXD;
+    if (ring->rx_pending > MVPP2_MAX_RXD_MAX)
+        new_rx_pending = MVPP2_MAX_RXD_MAX;
     else if (!IS_ALIGNED(ring->rx_pending, 16))
         new_rx_pending = ALIGN(ring->rx_pending, 16);
-    if (ring->tx_pending > MVPP2_MAX_TXD)
-        new_tx_pending = MVPP2_MAX_TXD;
+    if (ring->tx_pending > MVPP2_MAX_TXD_MAX)
+        new_tx_pending = MVPP2_MAX_TXD_MAX;
     else if (!IS_ALIGNED(ring->tx_pending, 32))
         new_tx_pending = ALIGN(ring->tx_pending, 32);
@@ -7344,8 +7346,8 @@ static void mvpp2_ethtool_get_ringparam(struct net_device *dev,
 {
     struct mvpp2_port *port = netdev_priv(dev);
-    ring->rx_max_pending = MVPP2_MAX_RXD;
-    ring->tx_max_pending = MVPP2_MAX_TXD;
+    ring->rx_max_pending = MVPP2_MAX_RXD_MAX;
+    ring->tx_max_pending = MVPP2_MAX_TXD_MAX;
     ring->rx_pending = port->rx_ring_size;
     ring->tx_pending = port->tx_ring_size;
 }
@@ -7792,7 +7794,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
         goto err_free_netdev;
     }
-    dev->tx_queue_len = MVPP2_MAX_TXD;
+    dev->tx_queue_len = MVPP2_MAX_TXD_MAX;
     dev->watchdog_timeo = 5 * HZ;
     dev->netdev_ops = &mvpp2_netdev_ops;
     dev->ethtool_ops = &mvpp2_eth_tool_ops;
@@ -7875,8 +7877,8 @@ static int mvpp2_port_probe(struct platform_device *pdev,
     mvpp2_port_copy_mac_addr(dev, priv, port_node, &mac_from);
-    port->tx_ring_size = MVPP2_MAX_TXD;
-    port->rx_ring_size = MVPP2_MAX_RXD;
+    port->tx_ring_size = MVPP2_MAX_TXD_DFLT;
+    port->rx_ring_size = MVPP2_MAX_RXD_DFLT;
     SET_NETDEV_DEV(dev, &pdev->dev);
     err = mvpp2_port_init(port);
--
2.7.4
SOURCES/0018-net-mvpp2-align-values-in-ethtool-get_coalesce.patch
New file
@@ -0,0 +1,36 @@
From 4e8b835b21bdbf54edefc37e9db8976b831e2b51 Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Mon, 11 Dec 2017 09:13:27 +0100
Subject: [PATCH 18/46] net: mvpp2: align values in ethtool get_coalesce
Cosmetic patch aligning values in the ethtool get_coalesce function.
This patch do not modify in anyway the driver's behaviour.
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 385c284fee84d2ad1da3b67111f199cd5641a867)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 5e88403..5c16731 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -7324,9 +7324,9 @@ static int mvpp2_ethtool_get_coalesce(struct net_device *dev,
 {
     struct mvpp2_port *port = netdev_priv(dev);
-    c->rx_coalesce_usecs        = port->rxqs[0]->time_coal;
-    c->rx_max_coalesced_frames  = port->rxqs[0]->pkts_coal;
-    c->tx_max_coalesced_frames =  port->txqs[0]->done_pkts_coal;
+    c->rx_coalesce_usecs       = port->rxqs[0]->time_coal;
+    c->rx_max_coalesced_frames = port->rxqs[0]->pkts_coal;
+    c->tx_max_coalesced_frames = port->txqs[0]->done_pkts_coal;
     return 0;
 }
--
2.7.4
SOURCES/0019-net-mvpp2-report-the-tx-usec-coalescing-information-.patch
New file
@@ -0,0 +1,33 @@
From 0e17bb46c36869108f65cb5e7fca0b60d6b0556e Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Mon, 11 Dec 2017 09:13:28 +0100
Subject: [PATCH 19/46] net: mvpp2: report the tx-usec coalescing information
 to ethtool
This patch adds the tx-usec value to the informations reported to
ethtool by the get_coalesce function.
Suggested-by: Yan Markman <ymarkman@marvell.com>
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 24b28ccb8575481672a9f037c423f7ebcea119b9)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 1 +
 1 file changed, 1 insertion(+)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 5c16731..aa72109 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -7327,6 +7327,7 @@ static int mvpp2_ethtool_get_coalesce(struct net_device *dev,
     c->rx_coalesce_usecs       = port->rxqs[0]->time_coal;
     c->rx_max_coalesced_frames = port->rxqs[0]->pkts_coal;
     c->tx_max_coalesced_frames = port->txqs[0]->done_pkts_coal;
+    c->tx_coalesce_usecs       = port->tx_time_coal;
     return 0;
 }
--
2.7.4
SOURCES/0020-net-mvpp2-adjust-the-coalescing-parameters.patch
New file
@@ -0,0 +1,38 @@
From cf0b1f85ed5e488d830cba267e96dd1dda5e2a2c Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@free-electrons.com>
Date: Mon, 11 Dec 2017 09:13:29 +0100
Subject: [PATCH 20/46] net: mvpp2: adjust the coalescing parameters
This patch adjust the coalescing parameters to the vendor
recommendations for the PPv2 network controller.
Suggested-by: Yan Markman <ymarkman@marvell.com>
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 86162281c25fd76e604978ffa0b2838e86ad4287)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index aa72109..a197607 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -454,11 +454,11 @@
 /* Various constants */
 /* Coalescing */
-#define MVPP2_TXDONE_COAL_PKTS_THRESH    15
+#define MVPP2_TXDONE_COAL_PKTS_THRESH    64
 #define MVPP2_TXDONE_HRTIMER_PERIOD_NS    1000000UL
 #define MVPP2_TXDONE_COAL_USEC        1000
 #define MVPP2_RX_COAL_PKTS        32
-#define MVPP2_RX_COAL_USEC        100
+#define MVPP2_RX_COAL_USEC        64
 /* The two bytes Marvell header. Either contains a special value used
  * by Marvell switches when a specific hardware mode is enabled (not
--
2.7.4
SOURCES/0021-device-property-Introduce-fwnode_get_mac_address.patch
New file
@@ -0,0 +1,110 @@
From b81c9307109512d284a07d864fe886c29df61778 Mon Sep 17 00:00:00 2001
From: Marcin Wojtas <mw@semihalf.com>
Date: Thu, 18 Jan 2018 13:31:38 +0100
Subject: [PATCH 21/46] device property: Introduce fwnode_get_mac_address()
Until now there were two almost identical functions for
obtaining MAC address - of_get_mac_address() and, more generic,
device_get_mac_address(). However it is not uncommon,
that the network interface is represented as a child
of the actual controller, hence it is not associated
directly to any struct device, required by the latter
routine.
This commit allows for getting the MAC address for
children nodes in the ACPI world by introducing a new function -
fwnode_get_mac_address(). This commit also changes
device_get_mac_address() routine to be its wrapper, in order
to prevent unnecessary duplication.
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit babe2dbb28e780177ae2fba6a5640be1712f4af0)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/base/property.c  | 28 ++++++++++++++++++++--------
 include/linux/property.h |  2 ++
 2 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 7ed99c1..fa488e5 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -1148,11 +1148,11 @@ int device_get_phy_mode(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(device_get_phy_mode);
-static void *device_get_mac_addr(struct device *dev,
+static void *fwnode_get_mac_addr(struct fwnode_handle *fwnode,
                  const char *name, char *addr,
                  int alen)
 {
-    int ret = device_property_read_u8_array(dev, name, addr, alen);
+    int ret = fwnode_property_read_u8_array(fwnode, name, addr, alen);
     if (ret == 0 && alen == ETH_ALEN && is_valid_ether_addr(addr))
         return addr;
@@ -1160,8 +1160,8 @@ static void *device_get_mac_addr(struct device *dev,
 }
 /**
- * device_get_mac_address - Get the MAC for a given device
- * @dev:    Pointer to the device
+ * fwnode_get_mac_address - Get the MAC from the firmware node
+ * @fwnode:    Pointer to the firmware node
  * @addr:    Address of buffer to store the MAC in
  * @alen:    Length of the buffer pointed to by addr, should be ETH_ALEN
  *
@@ -1182,19 +1182,31 @@ static void *device_get_mac_addr(struct device *dev,
  * In this case, the real MAC is in 'local-mac-address', and 'mac-address'
  * exists but is all zeros.
 */
-void *device_get_mac_address(struct device *dev, char *addr, int alen)
+void *fwnode_get_mac_address(struct fwnode_handle *fwnode, char *addr, int alen)
 {
     char *res;
-    res = device_get_mac_addr(dev, "mac-address", addr, alen);
+    res = fwnode_get_mac_addr(fwnode, "mac-address", addr, alen);
     if (res)
         return res;
-    res = device_get_mac_addr(dev, "local-mac-address", addr, alen);
+    res = fwnode_get_mac_addr(fwnode, "local-mac-address", addr, alen);
     if (res)
         return res;
-    return device_get_mac_addr(dev, "address", addr, alen);
+    return fwnode_get_mac_addr(fwnode, "address", addr, alen);
+}
+EXPORT_SYMBOL(fwnode_get_mac_address);
+
+/**
+ * device_get_mac_address - Get the MAC for a given device
+ * @dev:    Pointer to the device
+ * @addr:    Address of buffer to store the MAC in
+ * @alen:    Length of the buffer pointed to by addr, should be ETH_ALEN
+ */
+void *device_get_mac_address(struct device *dev, char *addr, int alen)
+{
+    return fwnode_get_mac_address(dev_fwnode(dev), addr, alen);
 }
 EXPORT_SYMBOL(device_get_mac_address);
diff --git a/include/linux/property.h b/include/linux/property.h
index 6bebee1..04d8552 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -279,6 +279,8 @@ int device_get_phy_mode(struct device *dev);
 void *device_get_mac_address(struct device *dev, char *addr, int alen);
+void *fwnode_get_mac_address(struct fwnode_handle *fwnode,
+                 char *addr, int alen);
 struct fwnode_handle *fwnode_graph_get_next_endpoint(
     const struct fwnode_handle *fwnode, struct fwnode_handle *prev);
 struct fwnode_handle *
--
2.7.4
SOURCES/0022-device-property-Introduce-fwnode_get_phy_mode.patch
New file
@@ -0,0 +1,96 @@
From 9cb42aa8f9f9e9fdf56e6a232fb65ecb881e30c9 Mon Sep 17 00:00:00 2001
From: Marcin Wojtas <mw@semihalf.com>
Date: Thu, 18 Jan 2018 13:31:39 +0100
Subject: [PATCH 22/46] device property: Introduce fwnode_get_phy_mode()
Until now there were two almost identical functions for
obtaining network PHY mode - of_get_phy_mode() and,
more generic, device_get_phy_mode(). However it is not uncommon,
that the network interface is represented as a child
of the actual controller, hence it is not associated
directly to any struct device, required by the latter
routine.
This commit allows for getting the PHY mode for
children nodes in the ACPI world by introducing a new function -
fwnode_get_phy_mode(). This commit also changes
device_get_phy_mode() routine to be its wrapper, in order
to prevent unnecessary duplication.
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit b28f263b86709a1e26d7207112030e970abf4aab)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/base/property.c  | 24 +++++++++++++++++++-----
 include/linux/property.h |  1 +
 2 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index fa488e5..9f69d18 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -1121,21 +1121,21 @@ enum dev_dma_attr device_get_dma_attr(struct device *dev)
 EXPORT_SYMBOL_GPL(device_get_dma_attr);
 /**
- * device_get_phy_mode - Get phy mode for given device
- * @dev:    Pointer to the given device
+ * fwnode_get_phy_mode - Get phy mode for given firmware node
+ * @fwnode:    Pointer to the given node
  *
  * The function gets phy interface string from property 'phy-mode' or
  * 'phy-connection-type', and return its index in phy_modes table, or errno in
  * error case.
  */
-int device_get_phy_mode(struct device *dev)
+int fwnode_get_phy_mode(struct fwnode_handle *fwnode)
 {
     const char *pm;
     int err, i;
-    err = device_property_read_string(dev, "phy-mode", &pm);
+    err = fwnode_property_read_string(fwnode, "phy-mode", &pm);
     if (err < 0)
-        err = device_property_read_string(dev,
+        err = fwnode_property_read_string(fwnode,
                           "phy-connection-type", &pm);
     if (err < 0)
         return err;
@@ -1146,6 +1146,20 @@ int device_get_phy_mode(struct device *dev)
     return -ENODEV;
 }
+EXPORT_SYMBOL_GPL(fwnode_get_phy_mode);
+
+/**
+ * device_get_phy_mode - Get phy mode for given device
+ * @dev:    Pointer to the given device
+ *
+ * The function gets phy interface string from property 'phy-mode' or
+ * 'phy-connection-type', and return its index in phy_modes table, or errno in
+ * error case.
+ */
+int device_get_phy_mode(struct device *dev)
+{
+    return fwnode_get_phy_mode(dev_fwnode(dev));
+}
 EXPORT_SYMBOL_GPL(device_get_phy_mode);
 static void *fwnode_get_mac_addr(struct fwnode_handle *fwnode,
diff --git a/include/linux/property.h b/include/linux/property.h
index 04d8552..d29eef4 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -279,6 +279,7 @@ int device_get_phy_mode(struct device *dev);
 void *device_get_mac_address(struct device *dev, char *addr, int alen);
+int fwnode_get_phy_mode(struct fwnode_handle *fwnode);
 void *fwnode_get_mac_address(struct fwnode_handle *fwnode,
                  char *addr, int alen);
 struct fwnode_handle *fwnode_graph_get_next_endpoint(
--
2.7.4
SOURCES/0023-device-property-Introduce-fwnode_irq_get.patch
New file
@@ -0,0 +1,114 @@
From b3db52952272989cfa614893148b4939cc51e982 Mon Sep 17 00:00:00 2001
From: Marcin Wojtas <mw@semihalf.com>
Date: Thu, 18 Jan 2018 13:31:40 +0100
Subject: [PATCH 23/46] device property: Introduce fwnode_irq_get()
Until now there were two very similar functions allowing
to get Linux IRQ number from ACPI handle (acpi_irq_get())
and OF node (of_irq_get()). The first one appeared to be used
only as a subroutine of platform_irq_get(), which (in the generic
code) limited IRQ obtaining from _CRS method only to nodes
associated to kernel's struct platform_device.
This patch introduces a new helper routine - fwnode_irq_get(),
which allows to get the IRQ number directly from the fwnode
to be used as common for OF/ACPI worlds. It is usable not
only for the parents fwnodes, but also for the child nodes
comprising their own _CRS methods with interrupts description.
In order to be able o satisfy compilation with !CONFIG_ACPI
and also simplify the new code, introduce a helper macro
(ACPI_HANDLE_FWNODE), with which it is possible to reach
an ACPI handle directly from its fwnode.
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 7c6c57f2ab2c5113844fe187a7c45c4bd76dc671)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/base/property.c  | 26 ++++++++++++++++++++++++++
 include/linux/acpi.h     |  3 +++
 include/linux/property.h |  2 ++
 3 files changed, 31 insertions(+)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 9f69d18..3a20e2c 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -16,6 +16,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_graph.h>
+#include <linux/of_irq.h>
 #include <linux/property.h>
 #include <linux/etherdevice.h>
 #include <linux/phy.h>
@@ -1225,6 +1226,31 @@ void *device_get_mac_address(struct device *dev, char *addr, int alen)
 EXPORT_SYMBOL(device_get_mac_address);
 /**
+ * fwnode_irq_get - Get IRQ directly from a fwnode
+ * @fwnode:    Pointer to the firmware node
+ * @index:    Zero-based index of the IRQ
+ *
+ * Returns Linux IRQ number on success. Other values are determined
+ * accordingly to acpi_/of_ irq_get() operation.
+ */
+int fwnode_irq_get(struct fwnode_handle *fwnode, unsigned int index)
+{
+    struct device_node *of_node = to_of_node(fwnode);
+    struct resource res;
+    int ret;
+
+    if (IS_ENABLED(CONFIG_OF) && of_node)
+        return of_irq_get(of_node, index);
+
+    ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), index, &res);
+    if (ret)
+        return ret;
+
+    return res.start;
+}
+EXPORT_SYMBOL(fwnode_irq_get);
+
+/**
  * device_graph_get_next_endpoint - Get next endpoint firmware node
  * @fwnode: Pointer to the parent firmware node
  * @prev: Previous endpoint node or %NULL to get the first
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 502af53..0c9ee53 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -56,6 +56,8 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev)
 #define ACPI_COMPANION_SET(dev, adev)    set_primary_fwnode(dev, (adev) ? \
     acpi_fwnode_handle(adev) : NULL)
 #define ACPI_HANDLE(dev)        acpi_device_handle(ACPI_COMPANION(dev))
+#define ACPI_HANDLE_FWNODE(fwnode)    \
+                acpi_device_handle(to_acpi_device_node(fwnode))
 static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
 {
@@ -626,6 +628,7 @@ int acpi_arch_timer_mem_init(struct arch_timer_mem *timer_mem, int *timer_count)
 #define ACPI_COMPANION(dev)        (NULL)
 #define ACPI_COMPANION_SET(dev, adev)    do { } while (0)
 #define ACPI_HANDLE(dev)        (NULL)
+#define ACPI_HANDLE_FWNODE(fwnode)    (NULL)
 #define ACPI_DEVICE_CLASS(_cls, _msk)    .cls = (0), .cls_msk = (0),
 struct fwnode_handle;
diff --git a/include/linux/property.h b/include/linux/property.h
index d29eef4..cd70998 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -103,6 +103,8 @@ struct fwnode_handle *device_get_named_child_node(struct device *dev,
 void fwnode_handle_get(struct fwnode_handle *fwnode);
 void fwnode_handle_put(struct fwnode_handle *fwnode);
+int fwnode_irq_get(struct fwnode_handle *fwnode, unsigned int index);
+
 unsigned int device_get_child_node_count(struct device *dev);
 static inline bool device_property_read_bool(struct device *dev,
--
2.7.4
SOURCES/0024-device-property-Allow-iterating-over-available-child.patch
New file
@@ -0,0 +1,85 @@
From 154dfb69cffd35f4bbbc5a82d823579119491dcd Mon Sep 17 00:00:00 2001
From: Marcin Wojtas <mw@semihalf.com>
Date: Thu, 18 Jan 2018 13:31:41 +0100
Subject: [PATCH 24/46] device property: Allow iterating over available child
 fwnodes
Implement a new helper function fwnode_get_next_available_child_node(),
which enables obtaining next enabled child fwnode, which
works on a similar basis to OF's of_get_next_available_child().
This commit also introduces a macro, thanks to which it is
possible to iterate over the available fwnodes, using the
new function described above.
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 3395de96ae5998692bd86024d0d5e4dd55cd6cc3)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/base/property.c  | 26 ++++++++++++++++++++++++++
 include/linux/property.h |  6 ++++++
 2 files changed, 32 insertions(+)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 3a20e2c..75aec5b 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -998,6 +998,32 @@ fwnode_get_next_child_node(const struct fwnode_handle *fwnode,
 EXPORT_SYMBOL_GPL(fwnode_get_next_child_node);
 /**
+ * fwnode_get_next_available_child_node - Return the next
+ * available child node handle for a node
+ * @fwnode: Firmware node to find the next child node for.
+ * @child: Handle to one of the node's child nodes or a %NULL handle.
+ */
+struct fwnode_handle *
+fwnode_get_next_available_child_node(const struct fwnode_handle *fwnode,
+                     struct fwnode_handle *child)
+{
+    struct fwnode_handle *next_child = child;
+
+    if (!fwnode)
+        return NULL;
+
+    do {
+        next_child = fwnode_get_next_child_node(fwnode, next_child);
+
+        if (!next_child || fwnode_device_is_available(next_child))
+            break;
+    } while (next_child);
+
+    return next_child;
+}
+EXPORT_SYMBOL_GPL(fwnode_get_next_available_child_node);
+
+/**
  * device_get_next_child_node - Return the next child node handle for a device
  * @dev: Device to find the next child node for.
  * @child: Handle to one of the device's child nodes or a null handle.
diff --git a/include/linux/property.h b/include/linux/property.h
index cd70998..f8ba672 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -83,11 +83,17 @@ struct fwnode_handle *fwnode_get_next_parent(
     struct fwnode_handle *fwnode);
 struct fwnode_handle *fwnode_get_next_child_node(
     const struct fwnode_handle *fwnode, struct fwnode_handle *child);
+struct fwnode_handle *fwnode_get_next_available_child_node(
+    const struct fwnode_handle *fwnode, struct fwnode_handle *child);
 #define fwnode_for_each_child_node(fwnode, child)            \
     for (child = fwnode_get_next_child_node(fwnode, NULL); child;    \
          child = fwnode_get_next_child_node(fwnode, child))
+#define fwnode_for_each_available_child_node(fwnode, child)               \
+    for (child = fwnode_get_next_available_child_node(fwnode, NULL); child;\
+         child = fwnode_get_next_available_child_node(fwnode, child))
+
 struct fwnode_handle *device_get_next_child_node(
     struct device *dev, struct fwnode_handle *child);
--
2.7.4
SOURCES/0025-net-mvpp2-simplify-maintaining-enabled-ports-list.patch
New file
@@ -0,0 +1,94 @@
From 8c444fab46352985bc5e9a9e0796f5fe7fe19e5c Mon Sep 17 00:00:00 2001
From: Marcin Wojtas <mw@semihalf.com>
Date: Thu, 18 Jan 2018 13:31:42 +0100
Subject: [PATCH 25/46] net: mvpp2: simplify maintaining enabled ports' list
'port_count' field of the mvpp2 structure holds an overall amount
of available ports, based on DT nodes status. In order to be prepared
to support other HW description, obtain the value by incrementing it
upon each successful port initialization. This allowed for simplifying
port indexing in the controller's private array, whose size is now not
dynamically allocated, but fixed to MVPP2_MAX_PORTS.
This patch simplifies creating and filling list of enabled ports and
is a part of the preparation for adding ACPI support in the mvpp2 driver.
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit bf147153d7f4b0d7337b28040837d9272c1a99fe)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 32 +++++++++++---------------------
 1 file changed, 11 insertions(+), 21 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index a197607..7f42d90 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -865,7 +865,7 @@ struct mvpp2 {
     /* List of pointers to port structures */
     int port_count;
-    struct mvpp2_port **port_list;
+    struct mvpp2_port *port_list[MVPP2_MAX_PORTS];
     /* Aggregated TXQs */
     struct mvpp2_tx_queue *aggr_txqs;
@@ -7741,7 +7741,7 @@ static void mvpp2_port_copy_mac_addr(struct net_device *dev, struct mvpp2 *priv,
 /* Ports initialization */
 static int mvpp2_port_probe(struct platform_device *pdev,
                 struct device_node *port_node,
-                struct mvpp2 *priv, int index)
+                struct mvpp2 *priv)
 {
     struct device_node *phy_node;
     struct phy *comphy;
@@ -7934,7 +7934,8 @@ static int mvpp2_port_probe(struct platform_device *pdev,
     }
     netdev_info(dev, "Using %s mac address %pM\n", mac_from, dev->dev_addr);
-    priv->port_list[index] = port;
+    priv->port_list[priv->port_count++] = port;
+
     return 0;
 err_free_port_pcpu:
@@ -8313,28 +8314,17 @@ static int mvpp2_probe(struct platform_device *pdev)
         goto err_mg_clk;
     }
-    priv->port_count = of_get_available_child_count(dn);
-    if (priv->port_count == 0) {
-        dev_err(&pdev->dev, "no ports enabled\n");
-        err = -ENODEV;
-        goto err_mg_clk;
-    }
-
-    priv->port_list = devm_kcalloc(&pdev->dev, priv->port_count,
-                       sizeof(*priv->port_list),
-                       GFP_KERNEL);
-    if (!priv->port_list) {
-        err = -ENOMEM;
-        goto err_mg_clk;
-    }
-
     /* Initialize ports */
-    i = 0;
     for_each_available_child_of_node(dn, port_node) {
-        err = mvpp2_port_probe(pdev, port_node, priv, i);
+        err = mvpp2_port_probe(pdev, port_node, priv);
         if (err < 0)
             goto err_port_probe;
-        i++;
+    }
+
+    if (priv->port_count == 0) {
+        dev_err(&pdev->dev, "no ports enabled\n");
+        err = -ENODEV;
+        goto err_mg_clk;
     }
     /* Statistics must be gathered regularly because some of them (like
--
2.7.4
SOURCES/0026-net-mvpp2-use-device_-fwnode_-APIs-instead-of-of_.patch
New file
@@ -0,0 +1,173 @@
From b1d7cdef19d9ba1eba6a89b582d36de59ce1363c Mon Sep 17 00:00:00 2001
From: Marcin Wojtas <mw@semihalf.com>
Date: Thu, 18 Jan 2018 13:31:43 +0100
Subject: [PATCH 26/46] net: mvpp2: use device_*/fwnode_* APIs instead of of_*
OF functions can be used only for the driver using DT.
As a preparation for introducing ACPI support in mvpp2
driver, use struct fwnode_handle in order to obtain
properties from the hardware description.
This patch replaces of_* function with device_*/fwnode_*
where possible in the mvpp2.
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 248122212f68dcf13433ec56bb03ddc799259026)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 45 +++++++++++++++++++-----------------
 1 file changed, 24 insertions(+), 21 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 7f42d90..f16448e 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -932,6 +932,9 @@ struct mvpp2_port {
     struct mvpp2 *priv;
+    /* Firmware node associated to the port */
+    struct fwnode_handle *fwnode;
+
     /* Per-port registers' base address */
     void __iomem *base;
     void __iomem *stats_base;
@@ -7711,17 +7714,16 @@ static bool mvpp2_port_has_tx_irqs(struct mvpp2 *priv,
 }
 static void mvpp2_port_copy_mac_addr(struct net_device *dev, struct mvpp2 *priv,
-                     struct device_node *port_node,
+                     struct fwnode_handle *fwnode,
                      char **mac_from)
 {
     struct mvpp2_port *port = netdev_priv(dev);
     char hw_mac_addr[ETH_ALEN] = {0};
-    const char *dt_mac_addr;
+    char fw_mac_addr[ETH_ALEN];
-    dt_mac_addr = of_get_mac_address(port_node);
-    if (dt_mac_addr && is_valid_ether_addr(dt_mac_addr)) {
-        *mac_from = "device tree";
-        ether_addr_copy(dev->dev_addr, dt_mac_addr);
+    if (fwnode_get_mac_address(fwnode, fw_mac_addr, ETH_ALEN)) {
+        *mac_from = "firmware node";
+        ether_addr_copy(dev->dev_addr, fw_mac_addr);
         return;
     }
@@ -7740,13 +7742,14 @@ static void mvpp2_port_copy_mac_addr(struct net_device *dev, struct mvpp2 *priv,
 /* Ports initialization */
 static int mvpp2_port_probe(struct platform_device *pdev,
-                struct device_node *port_node,
+                struct fwnode_handle *port_fwnode,
                 struct mvpp2 *priv)
 {
     struct device_node *phy_node;
     struct phy *comphy;
     struct mvpp2_port *port;
     struct mvpp2_port_pcpu *port_pcpu;
+    struct device_node *port_node = to_of_node(port_fwnode);
     struct net_device *dev;
     struct resource *res;
     char *mac_from = "";
@@ -7773,7 +7776,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
         return -ENOMEM;
     phy_node = of_parse_phandle(port_node, "phy", 0);
-    phy_mode = of_get_phy_mode(port_node);
+    phy_mode = fwnode_get_phy_mode(port_fwnode);
     if (phy_mode < 0) {
         dev_err(&pdev->dev, "incorrect phy mode\n");
         err = phy_mode;
@@ -7789,7 +7792,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
         comphy = NULL;
     }
-    if (of_property_read_u32(port_node, "port-id", &id)) {
+    if (fwnode_property_read_u32(port_fwnode, "port-id", &id)) {
         err = -EINVAL;
         dev_err(&pdev->dev, "missing port-id value\n");
         goto err_free_netdev;
@@ -7820,7 +7823,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
         /* the link irq is optional */
         port->link_irq = 0;
-    if (of_property_read_bool(port_node, "marvell,loopback"))
+    if (fwnode_property_read_bool(port_fwnode, "marvell,loopback"))
         port->flags |= MVPP2_F_LOOPBACK;
     port->id = id;
@@ -7845,8 +7848,8 @@ static int mvpp2_port_probe(struct platform_device *pdev,
                    MVPP21_MIB_COUNTERS_OFFSET +
                    port->gop_id * MVPP21_MIB_COUNTERS_PORT_SZ;
     } else {
-        if (of_property_read_u32(port_node, "gop-port-id",
-                     &port->gop_id)) {
+        if (fwnode_property_read_u32(port_fwnode, "gop-port-id",
+                         &port->gop_id)) {
             err = -EINVAL;
             dev_err(&pdev->dev, "missing gop-port-id value\n");
             goto err_deinit_qvecs;
@@ -7876,7 +7879,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
     mutex_init(&port->gather_stats_lock);
     INIT_DELAYED_WORK(&port->stats_work, mvpp2_gather_hw_statistics);
-    mvpp2_port_copy_mac_addr(dev, priv, port_node, &mac_from);
+    mvpp2_port_copy_mac_addr(dev, priv, port_fwnode, &mac_from);
     port->tx_ring_size = MVPP2_MAX_TXD_DFLT;
     port->rx_ring_size = MVPP2_MAX_RXD_DFLT;
@@ -8194,8 +8197,8 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
 static int mvpp2_probe(struct platform_device *pdev)
 {
-    struct device_node *dn = pdev->dev.of_node;
-    struct device_node *port_node;
+    struct fwnode_handle *fwnode = pdev->dev.fwnode;
+    struct fwnode_handle *port_fwnode;
     struct mvpp2 *priv;
     struct resource *res;
     void __iomem *base;
@@ -8315,8 +8318,8 @@ static int mvpp2_probe(struct platform_device *pdev)
     }
     /* Initialize ports */
-    for_each_available_child_of_node(dn, port_node) {
-        err = mvpp2_port_probe(pdev, port_node, priv);
+    fwnode_for_each_available_child_node(fwnode, port_fwnode) {
+        err = mvpp2_port_probe(pdev, port_fwnode, priv);
         if (err < 0)
             goto err_port_probe;
     }
@@ -8347,7 +8350,7 @@ static int mvpp2_probe(struct platform_device *pdev)
 err_port_probe:
     i = 0;
-    for_each_available_child_of_node(dn, port_node) {
+    fwnode_for_each_available_child_node(fwnode, port_fwnode) {
         if (priv->port_list[i])
             mvpp2_port_remove(priv->port_list[i]);
         i++;
@@ -8366,14 +8369,14 @@ static int mvpp2_probe(struct platform_device *pdev)
 static int mvpp2_remove(struct platform_device *pdev)
 {
     struct mvpp2 *priv = platform_get_drvdata(pdev);
-    struct device_node *dn = pdev->dev.of_node;
-    struct device_node *port_node;
+    struct fwnode_handle *fwnode = pdev->dev.fwnode;
+    struct fwnode_handle *port_fwnode;
     int i = 0;
     flush_workqueue(priv->stats_queue);
     destroy_workqueue(priv->stats_queue);
-    for_each_available_child_of_node(dn, port_node) {
+    fwnode_for_each_available_child_node(fwnode, port_fwnode) {
         if (priv->port_list[i]) {
             mutex_destroy(&priv->port_list[i]->gather_stats_lock);
             mvpp2_port_remove(priv->port_list[i]);
--
2.7.4
SOURCES/0027-net-mvpp2-enable-ACPI-support-in-the-driver.patch
New file
@@ -0,0 +1,305 @@
From 2626faa285fac645ade962a29001558fd0f567a5 Mon Sep 17 00:00:00 2001
From: Marcin Wojtas <mw@semihalf.com>
Date: Thu, 18 Jan 2018 13:31:44 +0100
Subject: [PATCH 27/46] net: mvpp2: enable ACPI support in the driver
This patch introduces an alternative way of obtaining resources - via
ACPI tables provided by firmware. Enabling coexistence with the DT
support, in addition to the OF_*->device_*/fwnode_* API replacement,
required following steps to be taken:
* Add mvpp2_acpi_match table
* Omit clock configuration and obtain tclk from the property - in ACPI
  world, the firmware is responsible for clock maintenance.
* Disable comphy and syscon handling as they are not available for ACPI.
* Modify way of obtaining interrupts - use newly introduced
  fwnode_irq_get() routine
* Until proper MDIO bus and PHY handling with ACPI is established in the
  kernel, use only link interrupts feature in the driver. For the RGMII
  port it results in depending on GMAC settings done during firmware
  stage.
* When booting with ACPI MVPP2_QDIST_MULTI_MODE is picked by
  default, as there is no need to keep any kind of the backward
  compatibility.
Moreover, a memory region used by mvmdio driver is usually placed in
the middle of the address space of the PP2 network controller.
The MDIO base address is obtained without requesting memory region
(by devm_ioremap() call) in mvmdio.c, later overlapping resources are
requested by the network driver, which is responsible for avoiding
a concurrent access.
In case the MDIO memory region is declared in the ACPI, it can
already appear as 'in-use' in the OS. Because it is overlapped by second
region of the network controller, make sure it is released, before
requesting it again. The care is taken by mvpp2 driver to avoid
concurrent access to this memory region.
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit a75edc7c2eab329d20a4ffbbfb15f2aa4a95454f)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 133 +++++++++++++++++++++++++----------
 1 file changed, 94 insertions(+), 39 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index f16448e..a1d7b88 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -10,6 +10,7 @@
  * warranty of any kind, whether express or implied.
  */
+#include <linux/acpi.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -7502,7 +7503,10 @@ static int mvpp2_multi_queue_vectors_init(struct mvpp2_port *port,
             strncpy(irqname, "rx-shared", sizeof(irqname));
         }
-        v->irq = of_irq_get_byname(port_node, irqname);
+        if (port_node)
+            v->irq = of_irq_get_byname(port_node, irqname);
+        else
+            v->irq = fwnode_irq_get(port->fwnode, i);
         if (v->irq <= 0) {
             ret = -EINVAL;
             goto err;
@@ -7746,7 +7750,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
                 struct mvpp2 *priv)
 {
     struct device_node *phy_node;
-    struct phy *comphy;
+    struct phy *comphy = NULL;
     struct mvpp2_port *port;
     struct mvpp2_port_pcpu *port_pcpu;
     struct device_node *port_node = to_of_node(port_fwnode);
@@ -7760,7 +7764,12 @@ static int mvpp2_port_probe(struct platform_device *pdev,
     int phy_mode;
     int err, i, cpu;
-    has_tx_irqs = mvpp2_port_has_tx_irqs(priv, port_node);
+    if (port_node) {
+        has_tx_irqs = mvpp2_port_has_tx_irqs(priv, port_node);
+    } else {
+        has_tx_irqs = true;
+        queue_mode = MVPP2_QDIST_MULTI_MODE;
+    }
     if (!has_tx_irqs)
         queue_mode = MVPP2_QDIST_SINGLE_MODE;
@@ -7775,7 +7784,11 @@ static int mvpp2_port_probe(struct platform_device *pdev,
     if (!dev)
         return -ENOMEM;
-    phy_node = of_parse_phandle(port_node, "phy", 0);
+    if (port_node)
+        phy_node = of_parse_phandle(port_node, "phy", 0);
+    else
+        phy_node = NULL;
+
     phy_mode = fwnode_get_phy_mode(port_fwnode);
     if (phy_mode < 0) {
         dev_err(&pdev->dev, "incorrect phy mode\n");
@@ -7783,13 +7796,15 @@ static int mvpp2_port_probe(struct platform_device *pdev,
         goto err_free_netdev;
     }
-    comphy = devm_of_phy_get(&pdev->dev, port_node, NULL);
-    if (IS_ERR(comphy)) {
-        if (PTR_ERR(comphy) == -EPROBE_DEFER) {
-            err = -EPROBE_DEFER;
-            goto err_free_netdev;
+    if (port_node) {
+        comphy = devm_of_phy_get(&pdev->dev, port_node, NULL);
+        if (IS_ERR(comphy)) {
+            if (PTR_ERR(comphy) == -EPROBE_DEFER) {
+                err = -EPROBE_DEFER;
+                goto err_free_netdev;
+            }
+            comphy = NULL;
         }
-        comphy = NULL;
     }
     if (fwnode_property_read_u32(port_fwnode, "port-id", &id)) {
@@ -7805,6 +7820,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
     port = netdev_priv(dev);
     port->dev = dev;
+    port->fwnode = port_fwnode;
     port->ntxqs = ntxqs;
     port->nrxqs = nrxqs;
     port->priv = priv;
@@ -7814,7 +7830,10 @@ static int mvpp2_port_probe(struct platform_device *pdev,
     if (err)
         goto err_free_netdev;
-    port->link_irq = of_irq_get_byname(port_node, "link");
+    if (port_node)
+        port->link_irq = of_irq_get_byname(port_node, "link");
+    else
+        port->link_irq = fwnode_irq_get(port_fwnode, port->nqvecs + 1);
     if (port->link_irq == -EPROBE_DEFER) {
         err = -EPROBE_DEFER;
         goto err_deinit_qvecs;
@@ -8197,6 +8216,7 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
 static int mvpp2_probe(struct platform_device *pdev)
 {
+    const struct acpi_device_id *acpi_id;
     struct fwnode_handle *fwnode = pdev->dev.fwnode;
     struct fwnode_handle *port_fwnode;
     struct mvpp2 *priv;
@@ -8209,8 +8229,14 @@ static int mvpp2_probe(struct platform_device *pdev)
     if (!priv)
         return -ENOMEM;
-    priv->hw_version =
-        (unsigned long)of_device_get_match_data(&pdev->dev);
+    if (has_acpi_companion(&pdev->dev)) {
+        acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
+                        &pdev->dev);
+        priv->hw_version = (unsigned long)acpi_id->driver_data;
+    } else {
+        priv->hw_version =
+            (unsigned long)of_device_get_match_data(&pdev->dev);
+    }
     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
     base = devm_ioremap_resource(&pdev->dev, res);
@@ -8224,10 +8250,23 @@ static int mvpp2_probe(struct platform_device *pdev)
             return PTR_ERR(priv->lms_base);
     } else {
         res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+        if (has_acpi_companion(&pdev->dev)) {
+            /* In case the MDIO memory region is declared in
+             * the ACPI, it can already appear as 'in-use'
+             * in the OS. Because it is overlapped by second
+             * region of the network controller, make
+             * sure it is released, before requesting it again.
+             * The care is taken by mvpp2 driver to avoid
+             * concurrent access to this memory region.
+             */
+            release_resource(res);
+        }
         priv->iface_base = devm_ioremap_resource(&pdev->dev, res);
         if (IS_ERR(priv->iface_base))
             return PTR_ERR(priv->iface_base);
+    }
+    if (priv->hw_version == MVPP22 && dev_of_node(&pdev->dev)) {
         priv->sysctrl_base =
             syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
                             "marvell,system-controller");
@@ -8253,32 +8292,34 @@ static int mvpp2_probe(struct platform_device *pdev)
     else
         priv->max_port_rxqs = 32;
-    priv->pp_clk = devm_clk_get(&pdev->dev, "pp_clk");
-    if (IS_ERR(priv->pp_clk))
-        return PTR_ERR(priv->pp_clk);
-    err = clk_prepare_enable(priv->pp_clk);
-    if (err < 0)
-        return err;
-
-    priv->gop_clk = devm_clk_get(&pdev->dev, "gop_clk");
-    if (IS_ERR(priv->gop_clk)) {
-        err = PTR_ERR(priv->gop_clk);
-        goto err_pp_clk;
-    }
-    err = clk_prepare_enable(priv->gop_clk);
-    if (err < 0)
-        goto err_pp_clk;
+    if (dev_of_node(&pdev->dev)) {
+        priv->pp_clk = devm_clk_get(&pdev->dev, "pp_clk");
+        if (IS_ERR(priv->pp_clk))
+            return PTR_ERR(priv->pp_clk);
+        err = clk_prepare_enable(priv->pp_clk);
+        if (err < 0)
+            return err;
-    if (priv->hw_version == MVPP22) {
-        priv->mg_clk = devm_clk_get(&pdev->dev, "mg_clk");
-        if (IS_ERR(priv->mg_clk)) {
-            err = PTR_ERR(priv->mg_clk);
-            goto err_gop_clk;
+        priv->gop_clk = devm_clk_get(&pdev->dev, "gop_clk");
+        if (IS_ERR(priv->gop_clk)) {
+            err = PTR_ERR(priv->gop_clk);
+            goto err_pp_clk;
         }
-
-        err = clk_prepare_enable(priv->mg_clk);
+        err = clk_prepare_enable(priv->gop_clk);
         if (err < 0)
-            goto err_gop_clk;
+            goto err_pp_clk;
+
+        if (priv->hw_version == MVPP22) {
+            priv->mg_clk = devm_clk_get(&pdev->dev, "mg_clk");
+            if (IS_ERR(priv->mg_clk)) {
+                err = PTR_ERR(priv->mg_clk);
+                goto err_gop_clk;
+            }
+
+            err = clk_prepare_enable(priv->mg_clk);
+            if (err < 0)
+                goto err_gop_clk;
+        }
         priv->axi_clk = devm_clk_get(&pdev->dev, "axi_clk");
         if (IS_ERR(priv->axi_clk)) {
@@ -8291,10 +8332,14 @@ static int mvpp2_probe(struct platform_device *pdev)
             if (err < 0)
                 goto err_gop_clk;
         }
-    }
-    /* Get system's tclk rate */
-    priv->tclk = clk_get_rate(priv->pp_clk);
+        /* Get system's tclk rate */
+        priv->tclk = clk_get_rate(priv->pp_clk);
+    } else if (device_property_read_u32(&pdev->dev, "clock-frequency",
+                        &priv->tclk)) {
+        dev_err(&pdev->dev, "missing clock-frequency value\n");
+        return -EINVAL;
+    }
     if (priv->hw_version == MVPP22) {
         err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(40));
@@ -8399,6 +8444,9 @@ static int mvpp2_remove(struct platform_device *pdev)
                   aggr_txq->descs_dma);
     }
+    if (is_acpi_node(port_fwnode))
+        return 0;
+
     clk_disable_unprepare(priv->axi_clk);
     clk_disable_unprepare(priv->mg_clk);
     clk_disable_unprepare(priv->pp_clk);
@@ -8420,12 +8468,19 @@ static const struct of_device_id mvpp2_match[] = {
 };
 MODULE_DEVICE_TABLE(of, mvpp2_match);
+static const struct acpi_device_id mvpp2_acpi_match[] = {
+    { "MRVL0110", MVPP22 },
+    { },
+};
+MODULE_DEVICE_TABLE(acpi, mvpp2_acpi_match);
+
 static struct platform_driver mvpp2_driver = {
     .probe = mvpp2_probe,
     .remove = mvpp2_remove,
     .driver = {
         .name = MVPP2_DRIVER_NAME,
         .of_match_table = mvpp2_match,
+        .acpi_match_table = ACPI_PTR(mvpp2_acpi_match),
     },
 };
--
2.7.4
SOURCES/0028-mvpp2-fix-multicast-address-filter.patch
New file
@@ -0,0 +1,58 @@
From 251852630ac787021e7088933187948f27bae241 Mon Sep 17 00:00:00 2001
From: Mikulas Patocka <mpatocka@redhat.com>
Date: Sun, 11 Feb 2018 18:10:28 -0500
Subject: [PATCH 28/46] mvpp2: fix multicast address filter
IPv6 doesn't work on the MacchiatoBIN board. It is caused by broken
multicast address filter in the mvpp2 driver.
The driver loads doesn't load any multicast entries if "allmulti" is not
set. This condition should be reversed.
The condition !netdev_mc_empty(dev) is useless (because
netdev_for_each_mc_addr is nop if the list is empty).
This patch also fixes a possible overflow of the multicast list - if
mvpp2_prs_mac_da_accept fails, we set the allmulti flag and retry.
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Cc: stable@vger.kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 7ac8ff95f48cbfa609a060fd6a1e361dd62feeb3)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index a1d7b88..5a1668c 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -7137,6 +7137,7 @@ static void mvpp2_set_rx_mode(struct net_device *dev)
     int id = port->id;
     bool allmulti = dev->flags & IFF_ALLMULTI;
+retry:
     mvpp2_prs_mac_promisc_set(priv, id, dev->flags & IFF_PROMISC);
     mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_ALL, allmulti);
     mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_IP6, allmulti);
@@ -7144,9 +7145,13 @@ static void mvpp2_set_rx_mode(struct net_device *dev)
     /* Remove all port->id's mcast enries */
     mvpp2_prs_mcast_del_all(priv, id);
-    if (allmulti && !netdev_mc_empty(dev)) {
-        netdev_for_each_mc_addr(ha, dev)
-            mvpp2_prs_mac_da_accept(priv, id, ha->addr, true);
+    if (!allmulti) {
+        netdev_for_each_mc_addr(ha, dev) {
+            if (mvpp2_prs_mac_da_accept(priv, id, ha->addr, true)) {
+                allmulti = true;
+                goto retry;
+            }
+        }
     }
 }
--
2.7.4
SOURCES/0029-net-mvpp2-Add-hardware-offloading-for-VLAN-filtering.patch
New file
@@ -0,0 +1,597 @@
From 1f9adeb81aaa5d359b357aa771c9aaaf1a1cc80f Mon Sep 17 00:00:00 2001
From: Maxime Chevallier <maxime.chevallier@bootlin.com>
Date: Wed, 28 Feb 2018 10:14:13 +0100
Subject: [PATCH 29/46] net: mvpp2: Add hardware offloading for VLAN filtering
Marvell PPv2 controller allows for generic packet filtering. This commit
adds entries to implement VLAN filtering. The approach taken is :
 - Filter entries that would match on the presence of the VLAN tag
   (existing VLAN detection, DSA / EDSA detection) will set the next
   lookup ID to be for the VID.
 - For each VLAN existing on a given port, we add an entry that matches
   this specific VID. If the incoming packet matches the VID entry, it is
   set for the next lookup in the chain (LU_L2).
 - A Guard entry is added for each port, that will match if the incoming
   packet didn't match any of the above VID entries. This entry tags the
   packet to be dropped.
Due to this design, and the fact that the total 256 filter entries are
also used for other purposes, we have a limit of 10 VLANs per port. To
accommodate the case where we would need more VLANS on one port, this
patch implements the ndo_set_features to allow for disabling of VLAN
filtering using ethtool.
The default config has VLAN filtering disabled.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 56beda3db6020428885f0589a0ac16768ea94543)
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 drivers/net/ethernet/marvell/mvpp2.c | 414 ++++++++++++++++++++++++++++++++---
 1 file changed, 380 insertions(+), 34 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 5a1668c..9418f6ee 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -65,6 +65,10 @@
 #define     MVPP2_RXQ_PACKET_OFFSET_MASK    0x70000000
 #define     MVPP2_RXQ_DISABLE_MASK        BIT(31)
+/* Top Registers */
+#define MVPP2_MH_REG(port)            (0x5040 + 4 * (port))
+#define MVPP2_DSA_EXTENDED            BIT(5)
+
 /* Parser Registers */
 #define MVPP2_PRS_INIT_LOOKUP_REG        0x1000
 #define     MVPP2_PRS_PORT_LU_MAX        0xf
@@ -473,6 +477,7 @@
 #define MVPP2_ETH_TYPE_LEN        2
 #define MVPP2_PPPOE_HDR_SIZE        8
 #define MVPP2_VLAN_TAG_LEN        4
+#define MVPP2_VLAN_TAG_EDSA_LEN        8
 /* Lbtd 802.3 type */
 #define MVPP2_IP_LBDT_TYPE        0xfffa
@@ -609,35 +614,64 @@ enum mvpp2_tag_type {
 #define MVPP2_PRS_TCAM_LU_BYTE            20
 #define MVPP2_PRS_TCAM_EN_OFFS(offs)        ((offs) + 2)
 #define MVPP2_PRS_TCAM_INV_WORD            5
+
+#define MVPP2_PRS_VID_TCAM_BYTE         2
+
+/* There is a TCAM range reserved for VLAN filtering entries, range size is 33
+ * 10 VLAN ID filter entries per port
+ * 1 default VLAN filter entry per port
+ * It is assumed that there are 3 ports for filter, not including loopback port
+ */
+#define MVPP2_PRS_VLAN_FILT_MAX        11
+#define MVPP2_PRS_VLAN_FILT_RANGE_SIZE    33
+
+#define MVPP2_PRS_VLAN_FILT_MAX_ENTRY   (MVPP2_PRS_VLAN_FILT_MAX - 2)
+#define MVPP2_PRS_VLAN_FILT_DFLT_ENTRY  (MVPP2_PRS_VLAN_FILT_MAX - 1)
+
 /* Tcam entries ID */
 #define MVPP2_PE_DROP_ALL        0
 #define MVPP2_PE_FIRST_FREE_TID        1
-#define MVPP2_PE_LAST_FREE_TID        (MVPP2_PRS_TCAM_SRAM_SIZE - 31)
+
+/* VLAN filtering range */
+#define MVPP2_PE_VID_FILT_RANGE_END     (MVPP2_PRS_TCAM_SRAM_SIZE - 31)
+#define MVPP2_PE_VID_FILT_RANGE_START   (MVPP2_PE_VID_FILT_RANGE_END - \
+                     MVPP2_PRS_VLAN_FILT_RANGE_SIZE + 1)
+#define MVPP2_PE_LAST_FREE_TID          (MVPP2_PE_VID_FILT_RANGE_START - 1)
 #define MVPP2_PE_IP6_EXT_PROTO_UN    (MVPP2_PRS_TCAM_SRAM_SIZE - 30)
 #define MVPP2_PE_MAC_MC_IP6        (MVPP2_PRS_TCAM_SRAM_SIZE - 29)
 #define MVPP2_PE_IP6_ADDR_UN        (MVPP2_PRS_TCAM_SRAM_SIZE - 28)
 #define MVPP2_PE_IP4_ADDR_UN        (MVPP2_PRS_TCAM_SRAM_SIZE - 27)
 #define MVPP2_PE_LAST_DEFAULT_FLOW    (MVPP2_PRS_TCAM_SRAM_SIZE - 26)
-#define MVPP2_PE_FIRST_DEFAULT_FLOW    (MVPP2_PRS_TCAM_SRAM_SIZE - 19)
-#define MVPP2_PE_EDSA_TAGGED        (MVPP2_PRS_TCAM_SRAM_SIZE - 18)
-#define MVPP2_PE_EDSA_UNTAGGED        (MVPP2_PRS_TCAM_SRAM_SIZE - 17)
-#define MVPP2_PE_DSA_TAGGED        (MVPP2_PRS_TCAM_SRAM_SIZE - 16)
-#define MVPP2_PE_DSA_UNTAGGED        (MVPP2_PRS_TCAM_SRAM_SIZE - 15)
-#define MVPP2_PE_ETYPE_EDSA_TAGGED    (MVPP2_PRS_TCAM_SRAM_SIZE - 14)
-#define MVPP2_PE_ETYPE_EDSA_UNTAGGED    (MVPP2_PRS_TCAM_SRAM_SIZE - 13)
-#define MVPP2_PE_ETYPE_DSA_TAGGED    (MVPP2_PRS_TCAM_SRAM_SIZE - 12)
-#define MVPP2_PE_ETYPE_DSA_UNTAGGED    (MVPP2_PRS_TCAM_SRAM_SIZE - 11)
-#define MVPP2_PE_MH_DEFAULT        (MVPP2_PRS_TCAM_SRAM_SIZE - 10)
-#define MVPP2_PE_DSA_DEFAULT        (MVPP2_PRS_TCAM_SRAM_SIZE - 9)
-#define MVPP2_PE_IP6_PROTO_UN        (MVPP2_PRS_TCAM_SRAM_SIZE - 8)
-#define MVPP2_PE_IP4_PROTO_UN        (MVPP2_PRS_TCAM_SRAM_SIZE - 7)
-#define MVPP2_PE_ETH_TYPE_UN        (MVPP2_PRS_TCAM_SRAM_SIZE - 6)
+#define MVPP2_PE_FIRST_DEFAULT_FLOW    (MVPP2_PRS_TCAM_SRAM_SIZE - 21)
+#define MVPP2_PE_EDSA_TAGGED        (MVPP2_PRS_TCAM_SRAM_SIZE - 20)
+#define MVPP2_PE_EDSA_UNTAGGED        (MVPP2_PRS_TCAM_SRAM_SIZE - 19)
+#define MVPP2_PE_DSA_TAGGED        (MVPP2_PRS_TCAM_SRAM_SIZE - 18)
+#define MVPP2_PE_DSA_UNTAGGED        (MVPP2_PRS_TCAM_SRAM_SIZE - 17)
+#define MVPP2_PE_ETYPE_EDSA_TAGGED    (MVPP2_PRS_TCAM_SRAM_SIZE - 16)
+#define MVPP2_PE_ETYPE_EDSA_UNTAGGED    (MVPP2_PRS_TCAM_SRAM_SIZE - 15)
+#define MVPP2_PE_ETYPE_DSA_TAGGED    (MVPP2_PRS_TCAM_SRAM_SIZE - 14)
+#define MVPP2_PE_ETYPE_DSA_UNTAGGED    (MVPP2_PRS_TCAM_SRAM_SIZE - 13)
+#define MVPP2_PE_MH_DEFAULT        (MVPP2_PRS_TCAM_SRAM_SIZE - 12)
+#define MVPP2_PE_DSA_DEFAULT        (MVPP2_PRS_TCAM_SRAM_SIZE - 11)
+#define MVPP2_PE_IP6_PROTO_UN        (MVPP2_PRS_TCAM_SRAM_SIZE - 10)
+#define MVPP2_PE_IP4_PROTO_UN        (MVPP2_PRS_TCAM_SRAM_SIZE - 9)
+#define MVPP2_PE_ETH_TYPE_UN        (MVPP2_PRS_TCAM_SRAM_SIZE - 8)
+#define MVPP2_PE_VID_FLTR_DEFAULT    (MVPP2_PRS_TCAM_SRAM_SIZE - 7)
+#define MVPP2_PE_VID_EDSA_FLTR_DEFAULT    (MVPP2_PRS_TCAM_SRAM_SIZE - 6)
 #define MVPP2_PE_VLAN_DBL        (MVPP2_PRS_TCAM_SRAM_SIZE - 5)
 #define MVPP2_PE_VLAN_NONE        (MVPP2_PRS_TCAM_SRAM_SIZE - 4)
 #define MVPP2_PE_MAC_MC_ALL        (MVPP2_PRS_TCAM_SRAM_SIZE - 3)
 #define MVPP2_PE_MAC_PROMISCUOUS    (MVPP2_PRS_TCAM_SRAM_SIZE - 2)
 #define MVPP2_PE_MAC_NON_PROMISCUOUS    (MVPP2_PRS_TCAM_SRAM_SIZE - 1)
+#define MVPP2_PRS_VID_PORT_FIRST(port)    (MVPP2_PE_VID_FILT_RANGE_START + \
+                     ((port) * MVPP2_PRS_VLAN_FILT_MAX))
+#define MVPP2_PRS_VID_PORT_LAST(port)    (MVPP2_PRS_VID_PORT_FIRST(port) \
+                     + MVPP2_PRS_VLAN_FILT_MAX_ENTRY)
+/* Index of default vid filter for given port */
+#define MVPP2_PRS_VID_PORT_DFLT(port)    (MVPP2_PRS_VID_PORT_FIRST(port) \
+                     + MVPP2_PRS_VLAN_FILT_DFLT_ENTRY)
+
 /* Sram structure
  * The fields are represented by MVPP2_PRS_TCAM_DATA_REG(3)->(0).
  */
@@ -725,6 +759,7 @@ enum mvpp2_tag_type {
 #define MVPP2_PRS_IPV6_EXT_AH_L4_AI_BIT        BIT(4)
 #define MVPP2_PRS_SINGLE_VLAN_AI        0
 #define MVPP2_PRS_DBL_VLAN_AI_BIT        BIT(7)
+#define MVPP2_PRS_EDSA_VID_AI_BIT        BIT(0)
 /* DSA/EDSA type */
 #define MVPP2_PRS_TAGGED        true
@@ -747,6 +782,7 @@ enum mvpp2_prs_lookup {
     MVPP2_PRS_LU_MAC,
     MVPP2_PRS_LU_DSA,
     MVPP2_PRS_LU_VLAN,
+    MVPP2_PRS_LU_VID,
     MVPP2_PRS_LU_L2,
     MVPP2_PRS_LU_PPPOE,
     MVPP2_PRS_LU_IP4,
@@ -1662,6 +1698,14 @@ static void mvpp2_prs_match_etype(struct mvpp2_prs_entry *pe, int offset,
     mvpp2_prs_tcam_data_byte_set(pe, offset + 1, ethertype & 0xff, 0xff);
 }
+/* Set vid in tcam sw entry */
+static void mvpp2_prs_match_vid(struct mvpp2_prs_entry *pe, int offset,
+                unsigned short vid)
+{
+    mvpp2_prs_tcam_data_byte_set(pe, offset + 0, (vid & 0xf00) >> 8, 0xf);
+    mvpp2_prs_tcam_data_byte_set(pe, offset + 1, vid & 0xff, 0xff);
+}
+
 /* Set bits in sram sw entry */
 static void mvpp2_prs_sram_bits_set(struct mvpp2_prs_entry *pe, int bit_num,
                     int val)
@@ -2029,24 +2073,30 @@ static void mvpp2_prs_dsa_tag_set(struct mvpp2 *priv, int port, bool add,
         mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
         pe.index = tid;
-        /* Shift 4 bytes if DSA tag or 8 bytes in case of EDSA tag*/
-        mvpp2_prs_sram_shift_set(&pe, shift,
-                     MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
-
         /* Update shadow table */
         mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_DSA);
         if (tagged) {
             /* Set tagged bit in DSA tag */
             mvpp2_prs_tcam_data_byte_set(&pe, 0,
-                             MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
-                             MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
-            /* Clear all ai bits for next iteration */
-            mvpp2_prs_sram_ai_update(&pe, 0,
-                         MVPP2_PRS_SRAM_AI_MASK);
-            /* If packet is tagged continue check vlans */
-            mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
+                         MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
+                         MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
+
+            /* Set ai bits for next iteration */
+            if (extend)
+                mvpp2_prs_sram_ai_update(&pe, 1,
+                            MVPP2_PRS_SRAM_AI_MASK);
+            else
+                mvpp2_prs_sram_ai_update(&pe, 0,
+                            MVPP2_PRS_SRAM_AI_MASK);
+
+            /* If packet is tagged continue check vid filtering */
+            mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
         } else {
+            /* Shift 4 bytes for DSA tag or 8 bytes for EDSA tag*/
+            mvpp2_prs_sram_shift_set(&pe, shift,
+                    MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
             /* Set result info bits to 'no vlans' */
             mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
                          MVPP2_PRS_RI_VLAN_MASK);
@@ -2231,10 +2281,9 @@ static int mvpp2_prs_vlan_add(struct mvpp2 *priv, unsigned short tpid, int ai,
         mvpp2_prs_match_etype(pe, 0, tpid);
-        mvpp2_prs_sram_next_lu_set(pe, MVPP2_PRS_LU_L2);
-        /* Shift 4 bytes - skip 1 vlan tag */
-        mvpp2_prs_sram_shift_set(pe, MVPP2_VLAN_TAG_LEN,
-                     MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+        /* VLAN tag detected, proceed with VID filtering */
+        mvpp2_prs_sram_next_lu_set(pe, MVPP2_PRS_LU_VID);
+
         /* Clear all ai bits for next iteration */
         mvpp2_prs_sram_ai_update(pe, 0, MVPP2_PRS_SRAM_AI_MASK);
@@ -2375,8 +2424,8 @@ static int mvpp2_prs_double_vlan_add(struct mvpp2 *priv, unsigned short tpid1,
         mvpp2_prs_match_etype(pe, 4, tpid2);
         mvpp2_prs_sram_next_lu_set(pe, MVPP2_PRS_LU_VLAN);
-        /* Shift 8 bytes - skip 2 vlan tags */
-        mvpp2_prs_sram_shift_set(pe, 2 * MVPP2_VLAN_TAG_LEN,
+        /* Shift 4 bytes - skip outer vlan tag */
+        mvpp2_prs_sram_shift_set(pe, MVPP2_VLAN_TAG_LEN,
                      MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
         mvpp2_prs_sram_ri_update(pe, MVPP2_PRS_RI_VLAN_DOUBLE,
                      MVPP2_PRS_RI_VLAN_MASK);
@@ -2755,6 +2804,62 @@ static void mvpp2_prs_dsa_init(struct mvpp2 *priv)
     mvpp2_prs_hw_write(priv, &pe);
 }
+/* Initialize parser entries for VID filtering */
+static void mvpp2_prs_vid_init(struct mvpp2 *priv)
+{
+    struct mvpp2_prs_entry pe;
+
+    memset(&pe, 0, sizeof(pe));
+
+    /* Set default vid entry */
+    pe.index = MVPP2_PE_VID_FLTR_DEFAULT;
+    mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
+
+    mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_EDSA_VID_AI_BIT);
+
+    /* Skip VLAN header - Set offset to 4 bytes */
+    mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_LEN,
+                 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+    /* Clear all ai bits for next iteration */
+    mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
+
+    mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
+
+    /* Unmask all ports */
+    mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
+
+    /* Update shadow table and hw entry */
+    mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
+    mvpp2_prs_hw_write(priv, &pe);
+
+    /* Set default vid entry for extended DSA*/
+    memset(&pe, 0, sizeof(pe));
+
+    /* Set default vid entry */
+    pe.index = MVPP2_PE_VID_EDSA_FLTR_DEFAULT;
+    mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
+
+    mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_EDSA_VID_AI_BIT,
+                 MVPP2_PRS_EDSA_VID_AI_BIT);
+
+    /* Skip VLAN header - Set offset to 8 bytes */
+    mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_EDSA_LEN,
+                 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+    /* Clear all ai bits for next iteration */
+    mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
+
+    mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
+
+    /* Unmask all ports */
+    mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
+
+    /* Update shadow table and hw entry */
+    mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
+    mvpp2_prs_hw_write(priv, &pe);
+}
+
 /* Match basic ethertypes */
 static int mvpp2_prs_etype_init(struct mvpp2 *priv)
 {
@@ -3023,7 +3128,8 @@ static int mvpp2_prs_vlan_init(struct platform_device *pdev, struct mvpp2 *priv)
     mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
     pe.index = MVPP2_PE_VLAN_DBL;
-    mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
+    mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
+
     /* Clear ai for next iterations */
     mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
     mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_DOUBLE,
@@ -3386,6 +3492,192 @@ static int mvpp2_prs_ip6_init(struct mvpp2 *priv)
     return 0;
 }
+/* Find tcam entry with matched pair <vid,port> */
+static int mvpp2_prs_vid_range_find(struct mvpp2 *priv, int pmap, u16 vid,
+                    u16 mask)
+{
+    unsigned char byte[2], enable[2];
+    struct mvpp2_prs_entry pe;
+    u16 rvid, rmask;
+    int tid;
+
+    /* Go through the all entries with MVPP2_PRS_LU_VID */
+    for (tid = MVPP2_PE_VID_FILT_RANGE_START;
+         tid <= MVPP2_PE_VID_FILT_RANGE_END; tid++) {
+        if (!priv->prs_shadow[tid].valid ||
+            priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VID)
+            continue;
+
+        pe.index = tid;
+
+        mvpp2_prs_hw_read(priv, &pe);
+        mvpp2_prs_tcam_data_byte_get(&pe, 2, &byte[0], &enable[0]);
+        mvpp2_prs_tcam_data_byte_get(&pe, 3, &byte[1], &enable[1]);
+
+        rvid = ((byte[0] & 0xf) << 8) + byte[1];
+        rmask = ((enable[0] & 0xf) << 8) + enable[1];
+
+        if (rvid != vid || rmask != mask)
+            continue;
+
+        return tid;
+    }
+
+    return 0;
+}
+
+/* Write parser entry for VID filtering */
+static int mvpp2_prs_vid_entry_add(struct mvpp2_port *port, u16 vid)
+{
+    unsigned int vid_start = MVPP2_PE_VID_FILT_RANGE_START +
+                 port->id * MVPP2_PRS_VLAN_FILT_MAX;
+    unsigned int mask = 0xfff, reg_val, shift;
+    struct mvpp2 *priv = port->priv;
+    struct mvpp2_prs_entry pe;
+    int tid;
+
+    /* Scan TCAM and see if entry with this <vid,port> already exist */
+    tid = mvpp2_prs_vid_range_find(priv, (1 << port->id), vid, mask);
+
+    reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id));
+    if (reg_val & MVPP2_DSA_EXTENDED)
+        shift = MVPP2_VLAN_TAG_EDSA_LEN;
+    else
+        shift = MVPP2_VLAN_TAG_LEN;
+
+    /* No such entry */
+    if (!tid) {
+        memset(&pe, 0, sizeof(pe));
+
+        /* Go through all entries from first to last in vlan range */
+        tid = mvpp2_prs_tcam_first_free(priv, vid_start,
+                        vid_start +
+                        MVPP2_PRS_VLAN_FILT_MAX_ENTRY);
+
+        /* There isn't room for a new VID filter */
+        if (tid < 0)
+            return tid;
+
+        mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
+        pe.index = tid;
+
+        /* Mask all ports */
+        mvpp2_prs_tcam_port_map_set(&pe, 0);
+    } else {
+        mvpp2_prs_hw_read(priv, &pe);
+    }
+
+    /* Enable the current port */
+    mvpp2_prs_tcam_port_set(&pe, port->id, true);
+
+    /* Continue - set next lookup */
+    mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
+
+    /* Skip VLAN header - Set offset to 4 or 8 bytes */
+    mvpp2_prs_sram_shift_set(&pe, shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+    /* Set match on VID */
+    mvpp2_prs_match_vid(&pe, MVPP2_PRS_VID_TCAM_BYTE, vid);
+
+    /* Clear all ai bits for next iteration */
+    mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
+
+    /* Update shadow table */
+    mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
+    mvpp2_prs_hw_write(priv, &pe);
+
+    return 0;
+}
+
+/* Write parser entry for VID filtering */
+static void mvpp2_prs_vid_entry_remove(struct mvpp2_port *port, u16 vid)
+{
+    struct mvpp2 *priv = port->priv;
+    int tid;
+
+    /* Scan TCAM and see if entry with this <vid,port> already exist */
+    tid = mvpp2_prs_vid_range_find(priv, (1 << port->id), vid, 0xfff);
+
+    /* No such entry */
+    if (tid)
+        return;
+
+    mvpp2_prs_hw_inv(priv, tid);
+    priv->prs_shadow[tid].valid = false;
+}
+
+/* Remove all existing VID filters on this port */
+static void mvpp2_prs_vid_remove_all(struct mvpp2_port *port)
+{
+    struct mvpp2 *priv = port->priv;
+    int tid;
+
+    for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
+         tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
+        if (priv->prs_shadow[tid].valid)
+            mvpp2_prs_vid_entry_remove(port, tid);
+    }
+}
+
+/* Remove VID filering entry for this port */
+static void mvpp2_prs_vid_disable_filtering(struct mvpp2_port *port)
+{
+    unsigned int tid = MVPP2_PRS_VID_PORT_DFLT(port->id);
+    struct mvpp2 *priv = port->priv;
+
+    /* Invalidate the guard entry */
+    mvpp2_prs_hw_inv(priv, tid);
+
+    priv->prs_shadow[tid].valid = false;
+}
+
+/* Add guard entry that drops packets when no VID is matched on this port */
+static void mvpp2_prs_vid_enable_filtering(struct mvpp2_port *port)
+{
+    unsigned int tid = MVPP2_PRS_VID_PORT_DFLT(port->id);
+    struct mvpp2 *priv = port->priv;
+    unsigned int reg_val, shift;
+    struct mvpp2_prs_entry pe;
+
+    if (priv->prs_shadow[tid].valid)
+        return;
+
+    memset(&pe, 0, sizeof(pe));
+
+    pe.index = tid;
+
+    reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id));
+    if (reg_val & MVPP2_DSA_EXTENDED)
+        shift = MVPP2_VLAN_TAG_EDSA_LEN;
+    else
+        shift = MVPP2_VLAN_TAG_LEN;
+
+    mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
+
+    /* Mask all ports */
+    mvpp2_prs_tcam_port_map_set(&pe, 0);
+
+    /* Update port mask */
+    mvpp2_prs_tcam_port_set(&pe, port->id, true);
+
+    /* Continue - set next lookup */
+    mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
+
+    /* Skip VLAN header - Set offset to 4 or 8 bytes */
+    mvpp2_prs_sram_shift_set(&pe, shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+    /* Drop VLAN packets that don't belong to any VIDs on this port */
+    mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
+                 MVPP2_PRS_RI_DROP_MASK);
+
+    /* Clear all ai bits for next iteration */
+    mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
+
+    /* Update shadow table */
+    mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
+    mvpp2_prs_hw_write(priv, &pe);
+}
+
 /* Parser default initialization */
 static int mvpp2_prs_default_init(struct platform_device *pdev,
                   struct mvpp2 *priv)
@@ -3429,6 +3721,8 @@ static int mvpp2_prs_default_init(struct platform_device *pdev,
     mvpp2_prs_dsa_init(priv);
+    mvpp2_prs_vid_init(priv);
+
     err = mvpp2_prs_etype_init(priv);
     if (err)
         return err;
@@ -7153,6 +7447,12 @@ static void mvpp2_set_rx_mode(struct net_device *dev)
             }
         }
     }
+
+    /* Disable VLAN filtering in promiscuous mode */
+    if (dev->flags & IFF_PROMISC)
+        mvpp2_prs_vid_disable_filtering(port);
+    else
+        mvpp2_prs_vid_enable_filtering(port);
 }
 static int mvpp2_set_mac_address(struct net_device *dev, void *p)
@@ -7292,6 +7592,48 @@ static int mvpp2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
     return ret;
 }
+static int mvpp2_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
+{
+    struct mvpp2_port *port = netdev_priv(dev);
+    int ret;
+
+    ret = mvpp2_prs_vid_entry_add(port, vid);
+    if (ret)
+        netdev_err(dev, "rx-vlan-filter offloading cannot accept more than %d VIDs per port\n",
+               MVPP2_PRS_VLAN_FILT_MAX - 1);
+    return ret;
+}
+
+static int mvpp2_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
+{
+    struct mvpp2_port *port = netdev_priv(dev);
+
+    mvpp2_prs_vid_entry_remove(port, vid);
+    return 0;
+}
+
+static int mvpp2_set_features(struct net_device *dev,
+                  netdev_features_t features)
+{
+    netdev_features_t changed = dev->features ^ features;
+    struct mvpp2_port *port = netdev_priv(dev);
+
+    if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) {
+        if (features & NETIF_F_HW_VLAN_CTAG_FILTER) {
+            mvpp2_prs_vid_enable_filtering(port);
+        } else {
+            /* Invalidate all registered VID filters for this
+             * port
+             */
+            mvpp2_prs_vid_remove_all(port);
+
+            mvpp2_prs_vid_disable_filtering(port);
+        }
+    }
+
+    return 0;
+}
+
 /* Ethtool methods */
 /* Set interrupt coalescing for ethtools */
@@ -7433,6 +7775,9 @@ static const struct net_device_ops mvpp2_netdev_ops = {
     .ndo_change_mtu        = mvpp2_change_mtu,
     .ndo_get_stats64    = mvpp2_get_stats64,
     .ndo_do_ioctl        = mvpp2_ioctl,
+    .ndo_vlan_rx_add_vid    = mvpp2_vlan_rx_add_vid,
+    .ndo_vlan_rx_kill_vid    = mvpp2_vlan_rx_kill_vid,
+    .ndo_set_features    = mvpp2_set_features,
 };