Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Thumshirn <jthumshirn@suse.de>2018-08-03 11:50:19 +0200
committerJohannes Thumshirn <jthumshirn@suse.de>2018-08-03 11:50:19 +0200
commit0ec97c1596083c59ba4ffca5355540f7836933cb (patch)
tree43e5e0d903b5a2092c87ddeec6feb39ebce7efc5
parentbe407613d34d14f84c3b18f3bd5dbbd741b33ea0 (diff)
parent2813d45bcb18b1d3819198e3c04fe60bfdbf6642 (diff)
Merge remote-tracking branch 'origin/SLE15' into SLE12-SP4
Conflicts: rpm/config.sh series.conf
-rw-r--r--blacklist.conf1
-rw-r--r--patches.arch/s390-add-assembler-macros-for-cpu-alternatives.patch145
-rw-r--r--patches.arch/s390-correct-module-section-names-for-expoline-code.patch44
-rw-r--r--patches.arch/s390-correct-register-corruption-in-critical-section-cleanup.patch51
-rw-r--r--patches.arch/s390-crc32-vx-use-expoline-for-indirect-branches.patch79
-rw-r--r--patches.arch/s390-extend-expoline-to-bc-instructions.patch180
-rw-r--r--patches.arch/s390-ftrace-use-expoline-for-indirect-branches.patch141
-rw-r--r--patches.arch/s390-gs-add-compat-regset-for-the-guarded-storage-broadcast-control-block.patch39
-rw-r--r--patches.arch/s390-kernel-use-expoline-for-indirect-branches.patch169
-rw-r--r--patches.arch/s390-lib-use-expoline-for-indirect-branches.patch80
-rw-r--r--patches.arch/s390-move-expoline-assembler-macros-to-a-header.patch404
-rw-r--r--patches.arch/s390-optimize-memset-implementation.patch63
-rw-r--r--patches.arch/s390-remove-indirect-branch-from-do_softirq_own_stack.patch38
-rw-r--r--patches.arch/s390-use-expoline-thunks-in-the-bpf-jit.patch193
-rw-r--r--patches.drivers/IB-core-Honor-port_num-while-resolving-GID-for-IB-li.patch58
-rw-r--r--patches.drivers/IB-core-Make-ib_mad_client_id-atomic.patch51
-rw-r--r--patches.drivers/IB-hfi1-Fix-user-context-tail-allocation-for-DMA_RTA.patch120
-rw-r--r--patches.drivers/IB-isert-Fix-for-lib-dma_debug-check_sync-warning.patch111
-rw-r--r--patches.drivers/IB-rxe-Fix-for-oops-in-rxe_register_device-on-ppc64l.patch78
-rw-r--r--patches.drivers/IB-rxe-add-RXE_START_MASK-for-rxe_opcode-IB_OPCODE_R.patch36
-rw-r--r--patches.drivers/IB-rxe-avoid-double-kfree_skb.patch94
-rw-r--r--patches.drivers/IB-uverbs-Fix-possible-oops-with-duplicate-ioctl-att.patch39
-rw-r--r--patches.drivers/RDMA-cma-Do-not-query-GID-during-QP-state-transition.patch52
-rw-r--r--patches.drivers/RDMA-mlx5-Fix-NULL-dereference-while-accessing-XRC_T.patch74
-rw-r--r--patches.drivers/RDMA-ucma-Don-t-allow-setting-RDMA_OPTION_IB_PATH-wi.patch33
-rw-r--r--patches.drivers/RDMA-uverbs-Use-an-unambiguous-errno-for-method-not-.patch73
-rw-r--r--patches.drivers/acpi-nfit-Fix-scrub-idle-detection.patch118
-rw-r--r--patches.drivers/device-property-Allow-iterating-over-available-child.patch78
-rw-r--r--patches.drivers/device-property-Introduce-fwnode_call_bool_op-for-op.patch63
-rw-r--r--patches.drivers/device-property-Introduce-fwnode_device_is_available.patch109
-rw-r--r--patches.drivers/device-property-Introduce-fwnode_get_mac_address.patch104
-rw-r--r--patches.drivers/device-property-Introduce-fwnode_get_phy_mode.patch90
-rw-r--r--patches.drivers/device-property-Introduce-fwnode_irq_get.patch106
-rw-r--r--patches.drivers/device-property-Move-FW-type-specific-functionality-.patch651
-rw-r--r--patches.drivers/device-property-Move-fwnode-graph-ops-to-firmware-sp.patch303
-rw-r--r--patches.drivers/device-property-Track-owner-device-of-device-propert.patch15
-rw-r--r--patches.drivers/device-property-preserve-usecount-for-node-passed-to.patch37
-rw-r--r--patches.drivers/enic-do-not-overwrite-error-code.patch44
-rw-r--r--patches.drivers/enic-enable-rq-before-updating-rq-descriptors.patch51
-rw-r--r--patches.drivers/libnvdimm-add-an-api-to-cast-a-struct-nd_region-to-i.patch60
-rw-r--r--patches.drivers/mvpp2-fix-multicast-address-filter.patch54
-rw-r--r--patches.drivers/net-cxgb3_main-fix-potential-Spectre-v1.patch50
-rw-r--r--patches.drivers/net-define-the-TSO-header-size-in-net-tso.h.patch75
-rw-r--r--patches.drivers/net-mlx5-Protect-from-command-bit-overflow.patch57
-rw-r--r--patches.drivers/net-mvmdio-add-xmdio-xsmi-support.patch210
-rw-r--r--patches.drivers/net-mvmdio-check-the-MII_ADDR_C45-bit-is-not-set-for.patch41
-rw-r--r--patches.drivers/net-mvmdio-introduce-an-ops-structure.patch102
-rw-r--r--patches.drivers/net-mvmdio-put-the-poll-intervals-in-the-ops-structu.patch49
-rw-r--r--patches.drivers/net-mvmdio-remove-duplicate-locking.patch79
-rw-r--r--patches.drivers/net-mvmdio-reorder-headers-alphabetically.patch41
-rw-r--r--patches.drivers/net-mvmdio-simplify-the-smi-read-and-write-error-pat.patch70
-rw-r--r--patches.drivers/net-mvmdio-use-GENMASK-for-masks.patch28
-rw-r--r--patches.drivers/net-mvmdio-use-tabs-for-defines.patch58
-rw-r--r--patches.drivers/net-mvpp2-Add-hardware-offloading-for-VLAN-filtering.patch593
-rw-r--r--patches.drivers/net-mvpp2-Add-support-for-unicast-filtering.patch460
-rw-r--r--patches.drivers/net-mvpp2-Don-t-use-dynamic-allocs-for-local-variabl.patch619
-rw-r--r--patches.drivers/net-mvpp2-Fix-DMA-address-mask-size.patch76
-rw-r--r--patches.drivers/net-mvpp2-Fix-TCAM-filter-reserved-range.patch39
-rw-r--r--patches.drivers/net-mvpp2-Fix-clk-error-path-in-mvpp2_probe.patch83
-rw-r--r--patches.drivers/net-mvpp2-Fix-clock-resource-by-adding-an-optional-b.patch92
-rw-r--r--patches.drivers/net-mvpp2-Fix-clock-resource-by-adding-missing-mg_co.patch80
-rw-r--r--patches.drivers/net-mvpp2-Fix-parser-entry-init-boundary-check.patch30
-rw-r--r--patches.drivers/net-mvpp2-Make-mvpp2_prs_hw_read-a-parser-entry-init.patch179
-rw-r--r--patches.drivers/net-mvpp2-Prevent-userspace-from-changing-TX-affinit.patch52
-rw-r--r--patches.drivers/net-mvpp2-Simplify-MAC-filtering-function-parameters.patch111
-rw-r--r--patches.drivers/net-mvpp2-Use-relaxed-I-O-in-data-path.patch122
-rw-r--r--patches.drivers/net-mvpp2-add-comments-about-smp_processor_id-usage.patch103
-rw-r--r--patches.drivers/net-mvpp2-add-ethtool-GOP-statistics.patch371
-rw-r--r--patches.drivers/net-mvpp2-add-support-for-TX-interrupts-and-RX-queue.patch546
-rw-r--r--patches.drivers/net-mvpp2-adjust-the-coalescing-parameters.patch34
-rw-r--r--patches.drivers/net-mvpp2-align-values-in-ethtool-get_coalesce.patch32
-rw-r--r--patches.drivers/net-mvpp2-allocate-zeroed-tx-descriptors.patch34
-rw-r--r--patches.drivers/net-mvpp2-check-ethtool-sets-the-Tx-ring-size-is-to-.patch37
-rw-r--r--patches.drivers/net-mvpp2-cleanup-probed-ports-in-the-probe-error-pa.patch50
-rw-r--r--patches.drivers/net-mvpp2-do-not-call-txq_done-from-the-Tx-path-when.patch35
-rw-r--r--patches.drivers/net-mvpp2-do-not-disable-GMAC-padding.patch46
-rw-r--r--patches.drivers/net-mvpp2-do-not-select-the-internal-source-clock.patch39
-rw-r--r--patches.drivers/net-mvpp2-do-not-set-GMAC-autoneg-when-using-XLG-MAC.patch105
-rw-r--r--patches.drivers/net-mvpp2-do-not-sleep-in-set_rx_mode.patch38
-rw-r--r--patches.drivers/net-mvpp2-do-not-unmap-TSO-headers-buffers.patch65
-rw-r--r--patches.drivers/net-mvpp2-dynamic-reconfiguration-of-the-comphy-GoP-.patch60
-rw-r--r--patches.drivers/net-mvpp2-enable-ACPI-support-in-the-driver.patch301
-rw-r--r--patches.drivers/net-mvpp2-enable-UDP-TCP-checksum-over-IPv6.patch31
-rw-r--r--patches.drivers/net-mvpp2-enable-basic-10G-support.patch101
-rw-r--r--patches.drivers/net-mvpp2-fallback-using-h-w-and-random-mac-if-the-d.patch54
-rw-r--r--patches.drivers/net-mvpp2-fix-GOP-statistics-loop-start-and-stop-con.patch175
-rw-r--r--patches.drivers/net-mvpp2-fix-MVPP21_ISR_RXQ_GROUP_REG-definition.patch29
-rw-r--r--patches.drivers/net-mvpp2-fix-TSO-headers-allocation-and-management.patch49
-rw-r--r--patches.drivers/net-mvpp2-fix-invalid-parameters-order-when-calling-.patch32
-rw-r--r--patches.drivers/net-mvpp2-fix-parsing-fragmentation-detection.patch79
-rw-r--r--patches.drivers/net-mvpp2-fix-port-list-indexing.patch60
-rw-r--r--patches.drivers/net-mvpp2-fix-the-RSS-table-entry-offset.patch30
-rw-r--r--patches.drivers/net-mvpp2-fix-the-packet-size-configuration-for-10G.patch40
-rw-r--r--patches.drivers/net-mvpp2-fix-the-synchronization-module-bypass-macr.patch39
-rw-r--r--patches.drivers/net-mvpp2-fix-the-txq_init-error-path.patch66
-rw-r--r--patches.drivers/net-mvpp2-fix-typo-in-the-tcam-setup.patch29
-rw-r--r--patches.drivers/net-mvpp2-fix-use-of-the-random-mac-address-for-PPv2.patch49
-rw-r--r--patches.drivers/net-mvpp2-improve-the-link-management-function.patch49
-rw-r--r--patches.drivers/net-mvpp2-initialize-the-GMAC-when-using-a-port.patch191
-rw-r--r--patches.drivers/net-mvpp2-initialize-the-GoP.patch240
-rw-r--r--patches.drivers/net-mvpp2-initialize-the-RSS-tables.patch99
-rw-r--r--patches.drivers/net-mvpp2-initialize-the-Tx-FIFO-size.patch79
-rw-r--r--patches.drivers/net-mvpp2-initialize-the-XLG-MAC-when-using-a-port.patch76
-rw-r--r--patches.drivers/net-mvpp2-initialize-the-comphy.patch123
-rw-r--r--patches.drivers/net-mvpp2-introduce-per-port-nrxqs-ntxqs-variables.patch346
-rw-r--r--patches.drivers/net-mvpp2-introduce-queue_vector-concept.patch479
-rw-r--r--patches.drivers/net-mvpp2-jumbo-frames-support.patch202
-rw-r--r--patches.drivers/net-mvpp2-limit-TSO-segments-and-use-stop-wake-thres.patch83
-rw-r--r--patches.drivers/net-mvpp2-make-the-phy-optional.patch83
-rw-r--r--patches.drivers/net-mvpp2-move-from-cpu-centric-naming-to-software-t.patch112
-rw-r--r--patches.drivers/net-mvpp2-move-the-mac-retrieval-copy-logic-into-its.patch86
-rw-r--r--patches.drivers/net-mvpp2-move-the-mii-configuration-in-the-ndo_open.patch37
-rw-r--r--patches.drivers/net-mvpp2-mvpp2_check_hw_buf_num-can-be-static.patch26
-rw-r--r--patches.drivers/net-mvpp2-only-free-the-TSO-header-buffers-when-it-w.patch45
-rw-r--r--patches.drivers/net-mvpp2-remove-RX-queue-group-reset-code.patch45
-rw-r--r--patches.drivers/net-mvpp2-remove-mvpp2_pool_refill.patch62
-rw-r--r--patches.drivers/net-mvpp2-remove-unused-mvpp2_bm_cookie_pool_set-fun.patch36
-rw-r--r--patches.drivers/net-mvpp2-remove-useless-goto.patch27
-rw-r--r--patches.drivers/net-mvpp2-report-the-tx-usec-coalescing-information-.patch28
-rw-r--r--patches.drivers/net-mvpp2-set-maximum-packet-size-for-10G-ports.patch66
-rw-r--r--patches.drivers/net-mvpp2-set-the-Rx-FIFO-size-depending-on-the-port.patch95
-rw-r--r--patches.drivers/net-mvpp2-simplify-maintaining-enabled-ports-list.patch90
-rw-r--r--patches.drivers/net-mvpp2-simplify-the-Tx-desc-set-DMA-logic.patch112
-rw-r--r--patches.drivers/net-mvpp2-simplify-the-link_event-function.patch58
-rw-r--r--patches.drivers/net-mvpp2-software-tso-support.patch260
-rw-r--r--patches.drivers/net-mvpp2-split-the-max-ring-size-from-the-default-o.patch86
-rw-r--r--patches.drivers/net-mvpp2-take-advantage-of-the-is_rgmii-helper.patch56
-rw-r--r--patches.drivers/net-mvpp2-unify-register-definitions-coding-style.patch149
-rw-r--r--patches.drivers/net-mvpp2-unify-the-txq-size-define-use.patch58
-rw-r--r--patches.drivers/net-mvpp2-update-the-BM-buffer-free-destroy-logic.patch113
-rw-r--r--patches.drivers/net-mvpp2-use-a-data-size-of-10kB-for-Tx-FIFO-on-por.patch74
-rw-r--r--patches.drivers/net-mvpp2-use-correct-index-on-array-mvpp2_pools.patch32
-rw-r--r--patches.drivers/net-mvpp2-use-device_-fwnode_-APIs-instead-of-of_.patch169
-rw-r--r--patches.drivers/net-mvpp2-use-the-GoP-interrupt-for-link-status-chan.patch331
-rw-r--r--patches.drivers/net-mvpp2-use-the-aggr-txq-size-define-everywhere.patch47
-rw-r--r--patches.drivers/net-mvpp2-use-the-same-buffer-pool-for-all-ports.patch223
-rw-r--r--patches.drivers/net-phy-add-XAUI-and-10GBASE-KR-PHY-connection-types.patch62
-rw-r--r--patches.drivers/nfit-address-range-scrub-add-module-option-to-skip-i.patch44
-rw-r--r--patches.drivers/nfit-address-range-scrub-determine-one-platform-max_.patch189
-rw-r--r--patches.drivers/nfit-address-range-scrub-introduce-nfit_spa-ars_stat.patch105
-rw-r--r--patches.drivers/nfit-address-range-scrub-rework-and-simplify-ARS-sta.patch694
-rw-r--r--patches.drivers/nvme-add-ANA-support.patch724
-rw-r--r--patches.drivers/nvme-move-init-of-keep_alive-work-item-to-controller.patch2
-rw-r--r--patches.drivers/nvme-remove-nvme_req_needs_failover.patch82
-rw-r--r--patches.drivers/nvme-simplify-the-API-for-getting-log-pages.patch118
-rw-r--r--patches.drivers/nvme.h-add-ANA-definitions.patch131
-rw-r--r--patches.drivers/nvme.h-add-support-for-the-log-specific-field.patch37
-rw-r--r--patches.drivers/nvmet-add-minimal-ANA-support.patch327
-rw-r--r--patches.drivers/nvmet-keep-a-port-pointer-in-nvmet_ctrl.patch49
-rw-r--r--patches.drivers/nvmet-support-configuring-ANA-groups.patch396
-rw-r--r--patches.drivers/nvmet-track-and-limit-the-number-of-namespaces-per-s.patch101
-rw-r--r--patches.drivers/nvmet-use-Retain-Async-Event-bit-to-clear-AEN.patch71
-rw-r--r--patches.drivers/of-Make-of_fwnode_handle-safer.patch36
-rw-r--r--patches.drivers/phy-add-sgmii-and-10gkr-modes-to-the-phy_mode-enum.patch30
-rw-r--r--patches.fixes/4.4.129-041-powerpc-64-Fix-smp_wmb-barrier-definition-use.patch54
-rw-r--r--patches.fixes/4.4.136-002-powerpc-64s-Clear-PCR-on-boot.patch61
-rw-r--r--patches.fixes/nvmet-fixup-crash-on-NULL-device-path.patch56
-rw-r--r--patches.kernel.org/4.4.129-040-powerpc-powernv-Handle-unknown-OPAL-errors-in.patch44
-rw-r--r--patches.kernel.org/4.4.129-042-powerpc-powernv-define-a-standard-delay-for-O.patch54
-rw-r--r--patches.kernel.org/4.4.129-043-powerpc-powernv-Fix-OPAL-NVRAM-driver-OPAL_BU.patch57
-rw-r--r--patches.kernel.org/4.4.129-086-powerpc-eeh-Fix-enabling-bridge-MMIO-windows.patch61
-rw-r--r--patches.kernel.org/4.4.133-056-powerpc-powernv-Fix-NVRAM-sleep-in-invalid-co.patch61
-rw-r--r--patches.kernel.org/4.4.134-183-powerpc-mpic-Check-if-cpu_possible-in-mpic_ph.patch53
-rw-r--r--patches.kernel.org/4.4.134-214-powerpc-Add-missing-prototype-for-arch_irq_wo.patch42
-rw-r--r--patches.kernel.org/4.4.139-043-powerpc-mm-hash-Add-missing-isync-prior-to-ke.patch69
-rw-r--r--patches.kernel.org/4.4.139-044-powerpc-ptrace-Fix-setting-512B-aligned-break.patch48
-rw-r--r--patches.kernel.org/4.4.139-047-powerpc-fadump-Unregister-fadump-on-kexec-dow.patch44
-rw-r--r--patches.suse/net-mvmdio-disable-unprepare-clocks-in-EPROBE_DEFER-.patch4
-rw-r--r--patches.suse/powerpc-64s-Fix-section-mismatch-warnings-from-setup.patch60
-rw-r--r--patches.suse/qed-use-specical-suse-engineering-version.patch34
-rw-r--r--series.conf174
171 files changed, 19182 insertions, 49 deletions
diff --git a/blacklist.conf b/blacklist.conf
index 4255995e5f..2716842e5d 100644
--- a/blacklist.conf
+++ b/blacklist.conf
@@ -420,3 +420,4 @@ ffd2c0d12752a69e480366031ec7a7d723dd2510 # dup of 6291c608a908
490068deaef0c76e47bf89c457de899b7d3995c7 # dup of fc16f56b7bfd
974f6c046ad90d071f96c76ff8ab29355a798c41 # dup of f9bcd60274a5
2bf698671205bb6f898db348b788d16f6976e086 # usb: device_set_of_node_from_dev() missing
+5f3ba878e7a2ffef82fb0882c0dd2c3507d734bc # changes user-space intf
diff --git a/patches.arch/s390-add-assembler-macros-for-cpu-alternatives.patch b/patches.arch/s390-add-assembler-macros-for-cpu-alternatives.patch
new file mode 100644
index 0000000000..66aeed72ef
--- /dev/null
+++ b/patches.arch/s390-add-assembler-macros-for-cpu-alternatives.patch
@@ -0,0 +1,145 @@
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Mon, 19 Mar 2018 18:07:31 +0100
+Subject: s390: add assembler macros for CPU alternatives
+Git-commit: fba9eb7946251d6e420df3bdf7bc45195be7be9a
+Patch-mainline: v4.17-rc1
+References: git-fixes f19fbd5ed6
+
+Add a header with macros usable in assembler files to emit alternative
+code sequences. It works analog to the alternatives for inline assmeblies
+in C files, with the same restrictions and capabilities.
+The syntax is
+
+ ALTERNATIVE "<default instructions sequence>", \
+ "<alternative instructions sequence>", \
+ "<features-bit>"
+and
+
+ ALTERNATIVE_2 "<default instructions sequence>", \
+ "<alternative instructions sqeuence #1>", \
+ "<feature-bit #1>",
+ "<alternative instructions sqeuence #2>", \
+ "<feature-bit #2>"
+
+Reviewed-by: Vasily Gorbik <gor@linux.vnet.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/include/asm/alternative-asm.h | 108 ++++++++++++++++++++++++++++++++
+ 1 file changed, 108 insertions(+)
+
+diff --git a/arch/s390/include/asm/alternative-asm.h b/arch/s390/include/asm/alternative-asm.h
+new file mode 100644
+index 000000000000..955d620db23e
+--- /dev/null
++++ b/arch/s390/include/asm/alternative-asm.h
+@@ -0,0 +1,108 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef _ASM_S390_ALTERNATIVE_ASM_H
++#define _ASM_S390_ALTERNATIVE_ASM_H
++
++#ifdef __ASSEMBLY__
++
++/*
++ * Check the length of an instruction sequence. The length may not be larger
++ * than 254 bytes and it has to be divisible by 2.
++ */
++.macro alt_len_check start,end
++ .if ( \end - \start ) > 254
++ .error "cpu alternatives does not support instructions blocks > 254 bytes\n"
++ .endif
++ .if ( \end - \start ) % 2
++ .error "cpu alternatives instructions length is odd\n"
++ .endif
++.endm
++
++/*
++ * Issue one struct alt_instr descriptor entry (need to put it into
++ * the section .altinstructions, see below). This entry contains
++ * enough information for the alternatives patching code to patch an
++ * instruction. See apply_alternatives().
++ */
++.macro alt_entry orig_start, orig_end, alt_start, alt_end, feature
++ .long \orig_start - .
++ .long \alt_start - .
++ .word \feature
++ .byte \orig_end - \orig_start
++ .byte \alt_end - \alt_start
++.endm
++
++/*
++ * Fill up @bytes with nops. The macro emits 6-byte nop instructions
++ * for the bulk of the area, possibly followed by a 4-byte and/or
++ * a 2-byte nop if the size of the area is not divisible by 6.
++ */
++.macro alt_pad_fill bytes
++ .fill ( \bytes ) / 6, 6, 0xc0040000
++ .fill ( \bytes ) % 6 / 4, 4, 0x47000000
++ .fill ( \bytes ) % 6 % 4 / 2, 2, 0x0700
++.endm
++
++/*
++ * Fill up @bytes with nops. If the number of bytes is larger
++ * than 6, emit a jg instruction to branch over all nops, then
++ * fill an area of size (@bytes - 6) with nop instructions.
++ */
++.macro alt_pad bytes
++ .if ( \bytes > 0 )
++ .if ( \bytes > 6 )
++ jg . + \bytes
++ alt_pad_fill \bytes - 6
++ .else
++ alt_pad_fill \bytes
++ .endif
++ .endif
++.endm
++
++/*
++ * Define an alternative between two instructions. If @feature is
++ * present, early code in apply_alternatives() replaces @oldinstr with
++ * @newinstr. ".skip" directive takes care of proper instruction padding
++ * in case @newinstr is longer than @oldinstr.
++ */
++.macro ALTERNATIVE oldinstr, newinstr, feature
++ .pushsection .altinstr_replacement,"ax"
++770: \newinstr
++771: .popsection
++772: \oldinstr
++773: alt_len_check 770b, 771b
++ alt_len_check 772b, 773b
++ alt_pad ( ( 771b - 770b ) - ( 773b - 772b ) )
++774: .pushsection .altinstructions,"a"
++ alt_entry 772b, 774b, 770b, 771b, \feature
++ .popsection
++.endm
++
++/*
++ * Define an alternative between two instructions. If @feature is
++ * present, early code in apply_alternatives() replaces @oldinstr with
++ * @newinstr. ".skip" directive takes care of proper instruction padding
++ * in case @newinstr is longer than @oldinstr.
++ */
++.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2
++ .pushsection .altinstr_replacement,"ax"
++770: \newinstr1
++771: \newinstr2
++772: .popsection
++773: \oldinstr
++774: alt_len_check 770b, 771b
++ alt_len_check 771b, 772b
++ alt_len_check 773b, 774b
++ .if ( 771b - 770b > 772b - 771b )
++ alt_pad ( ( 771b - 770b ) - ( 774b - 773b ) )
++ .else
++ alt_pad ( ( 772b - 771b ) - ( 774b - 773b ) )
++ .endif
++775: .pushsection .altinstructions,"a"
++ alt_entry 773b, 775b, 770b, 771b,\feature1
++ alt_entry 773b, 775b, 771b, 772b,\feature2
++ .popsection
++.endm
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* _ASM_S390_ALTERNATIVE_ASM_H */
+
diff --git a/patches.arch/s390-correct-module-section-names-for-expoline-code.patch b/patches.arch/s390-correct-module-section-names-for-expoline-code.patch
new file mode 100644
index 0000000000..4841e463b5
--- /dev/null
+++ b/patches.arch/s390-correct-module-section-names-for-expoline-code.patch
@@ -0,0 +1,44 @@
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Fri, 20 Apr 2018 12:48:52 +0200
+Subject: s390: correct module section names for expoline code revert
+Git-commit: 6cf09958f32b9667bb3ebadf74367c791112771b
+Patch-mainline: v4.17-rc3
+References: git-fixes f19fbd5ed6
+
+The main linker script vmlinux.lds.S for the kernel image merges
+the expoline code patch tables into two section ".nospec_call_table"
+and ".nospec_return_table". This is *not* done for the modules,
+there the sections retain their original names as generated by gcc:
+".s390_indirect_call", ".s390_return_mem" and ".s390_return_reg".
+
+The module_finalize code has to check for the compiler generated
+section names, otherwise no code patching is done. This slows down
+the module code in case of "spectre_v2=off".
+
+Cc: stable@vger.kernel.org # 4.16
+Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches")
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/kernel/module.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
+index 5a83be955c70..0dc8ac8548ee 100644
+--- a/arch/s390/kernel/module.c
++++ b/arch/s390/kernel/module.c
+@@ -465,11 +465,11 @@ int module_finalize(const Elf_Ehdr *hdr,
+ apply_alternatives(aseg, aseg + s->sh_size);
+
+ if (IS_ENABLED(CONFIG_EXPOLINE) &&
+- (!strcmp(".nospec_call_table", secname)))
++ (!strncmp(".s390_indirect", secname, 14)))
+ nospec_revert(aseg, aseg + s->sh_size);
+
+ if (IS_ENABLED(CONFIG_EXPOLINE) &&
+- (!strcmp(".nospec_return_table", secname)))
++ (!strncmp(".s390_return", secname, 12)))
+ nospec_revert(aseg, aseg + s->sh_size);
+ }
+
+
diff --git a/patches.arch/s390-correct-register-corruption-in-critical-section-cleanup.patch b/patches.arch/s390-correct-register-corruption-in-critical-section-cleanup.patch
new file mode 100644
index 0000000000..ea1e9826bf
--- /dev/null
+++ b/patches.arch/s390-correct-register-corruption-in-critical-section-cleanup.patch
@@ -0,0 +1,51 @@
+From: Christian Borntraeger <borntraeger@de.ibm.com>
+Date: Thu, 21 Jun 2018 14:49:38 +0200
+Subject: s390: Correct register corruption in critical section cleanup
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+Git-commit: 891f6a726cacbb87e5b06076693ffab53bd378d7
+Patch-mainline: v4.18-rc4
+References: git-fixes 6dd85fbb87
+
+In the critical section cleanup we must not mess with r1. For march=z9
+or older, larl + ex (instead of exrl) are used with r1 as a temporary
+register. This can clobber r1 in several interrupt handlers. Fix this by
+using r11 as a temp register. r11 is being saved by all callers of
+cleanup_critical.
+
+Fixes: 6dd85fbb87 ("s390: move expoline assembler macros to a header")
+Cc: stable@vger.kernel.org #v4.16
+Reported-by: Oliver Kurz <okurz@suse.com>
+Reported-by: Petr Tesařík <ptesarik@suse.com>
+Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
+Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/kernel/entry.S | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
+index f03402efab4b..3891805bfcdd 100644
+--- a/arch/s390/kernel/entry.S
++++ b/arch/s390/kernel/entry.S
+@@ -1265,7 +1265,7 @@ cleanup_critical:
+ jl 0f
+ clg %r9,BASED(.Lcleanup_table+104) # .Lload_fpu_regs_end
+ jl .Lcleanup_load_fpu_regs
+-0: BR_EX %r14
++0: BR_EX %r14,%r11
+
+ .align 8
+ .Lcleanup_table:
+@@ -1301,7 +1301,7 @@ cleanup_critical:
+ ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE
+ lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
+ larl %r9,sie_exit # skip forward to sie_exit
+- BR_EX %r14
++ BR_EX %r14,%r11
+ #endif
+
+ .Lcleanup_system_call:
+
diff --git a/patches.arch/s390-crc32-vx-use-expoline-for-indirect-branches.patch b/patches.arch/s390-crc32-vx-use-expoline-for-indirect-branches.patch
new file mode 100644
index 0000000000..174189bb09
--- /dev/null
+++ b/patches.arch/s390-crc32-vx-use-expoline-for-indirect-branches.patch
@@ -0,0 +1,79 @@
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Mon, 23 Apr 2018 14:31:36 +0200
+Subject: s390/crc32-vx: use expoline for indirect branches
+Git-commit: 467a3bf219cee12259182c5cb4821f88fd518a51
+Patch-mainline: v4.17-rc6
+References: git-fixes f19fbd5ed6
+
+The return from the crc32_le_vgfm_16/crc32c_le_vgfm_16 and the
+crc32_be_vgfm_16 functions are done with "br %r14". These are indirect
+branches as well and need to use execute trampolines for CONFIG_EXPOLINE=y.
+
+Cc: stable@vger.kernel.org # 4.16
+Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches")
+Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/crypto/crc32be-vx.S | 5 ++++-
+ arch/s390/crypto/crc32le-vx.S | 4 +++-
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/arch/s390/crypto/crc32be-vx.S b/arch/s390/crypto/crc32be-vx.S
+index e8077f0971f8..2bf01ba44107 100644
+--- a/arch/s390/crypto/crc32be-vx.S
++++ b/arch/s390/crypto/crc32be-vx.S
+@@ -13,6 +13,7 @@
+ */
+
+ #include <linux/linkage.h>
++#include <asm/nospec-insn.h>
+ #include <asm/vx-insn.h>
+
+ /* Vector register range containing CRC-32 constants */
+@@ -67,6 +68,8 @@
+
+ .previous
+
++ GEN_BR_THUNK %r14
++
+ .text
+ /*
+ * The CRC-32 function(s) use these calling conventions:
+@@ -203,6 +206,6 @@ ENTRY(crc32_be_vgfm_16)
+
+ .Ldone:
+ VLGVF %r2,%v2,3
+- br %r14
++ BR_EX %r14
+
+ .previous
+diff --git a/arch/s390/crypto/crc32le-vx.S b/arch/s390/crypto/crc32le-vx.S
+index d8c67a58c0c5..7d6f568bd3ad 100644
+--- a/arch/s390/crypto/crc32le-vx.S
++++ b/arch/s390/crypto/crc32le-vx.S
+@@ -14,6 +14,7 @@
+ */
+
+ #include <linux/linkage.h>
++#include <asm/nospec-insn.h>
+ #include <asm/vx-insn.h>
+
+ /* Vector register range containing CRC-32 constants */
+@@ -76,6 +77,7 @@
+
+ .previous
+
++ GEN_BR_THUNK %r14
+
+ .text
+
+@@ -264,6 +266,6 @@ crc32_le_vgfm_generic:
+
+ .Ldone:
+ VLGVF %r2,%v2,2
+- br %r14
++ BR_EX %r14
+
+ .previous
+
diff --git a/patches.arch/s390-extend-expoline-to-bc-instructions.patch b/patches.arch/s390-extend-expoline-to-bc-instructions.patch
new file mode 100644
index 0000000000..f80778d387
--- /dev/null
+++ b/patches.arch/s390-extend-expoline-to-bc-instructions.patch
@@ -0,0 +1,180 @@
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Tue, 24 Apr 2018 15:32:08 +0200
+Subject: s390: extend expoline to BC instructions
+Git-commit: 6deaa3bbca804b2a3627fd685f75de64da7be535
+Patch-mainline: v4.17-rc6
+References: git-fixes, bsc#1103421
+
+The BPF JIT uses a 'b <disp>(%r<x>)' instruction in the definition
+of the sk_load_word and sk_load_half functions.
+
+Add support for branch-on-condition instructions contained in the
+thunk code of an expoline.
+
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/include/asm/nospec-insn.h | 57 +++++++++++++++++++++++++++++++++++++
+ arch/s390/kernel/nospec-branch.c | 25 ++++++++++++----
+ 2 files changed, 77 insertions(+), 5 deletions(-)
+
+diff --git a/arch/s390/include/asm/nospec-insn.h b/arch/s390/include/asm/nospec-insn.h
+index 7d7640e1cf90..a01f81186e86 100644
+--- a/arch/s390/include/asm/nospec-insn.h
++++ b/arch/s390/include/asm/nospec-insn.h
+@@ -35,10 +35,18 @@ _LC_BR_R1 = __LC_BR_R1
+ __THUNK_PROLOG_NAME __s390x_indirect_jump_r\r2\()use_r\r1
+ .endm
+
++ .macro __THUNK_PROLOG_BC d0,r1,r2
++ __THUNK_PROLOG_NAME __s390x_indirect_branch_\d0\()_\r2\()use_\r1
++ .endm
++
+ .macro __THUNK_BR r1,r2
+ jg __s390x_indirect_jump_r\r2\()use_r\r1
+ .endm
+
++ .macro __THUNK_BC d0,r1,r2
++ jg __s390x_indirect_branch_\d0\()_\r2\()use_\r1
++ .endm
++
+ .macro __THUNK_BRASL r1,r2,r3
+ brasl \r1,__s390x_indirect_jump_r\r3\()use_r\r2
+ .endm
+@@ -81,6 +89,23 @@ _LC_BR_R1 = __LC_BR_R1
+ .endif
+ .endm
+
++ .macro __DECODE_DRR expand,disp,reg,ruse
++ .set __decode_fail,1
++ .irp r1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
++ .ifc \reg,%r\r1
++ .irp r2,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
++ .ifc \ruse,%r\r2
++ \expand \disp,\r1,\r2
++ .set __decode_fail,0
++ .endif
++ .endr
++ .endif
++ .endr
++ .if __decode_fail == 1
++ .error "__DECODE_DRR failed"
++ .endif
++ .endm
++
+ .macro __THUNK_EX_BR reg,ruse
+ # Be very careful when adding instructions to this macro!
+ # The ALTERNATIVE replacement code has a .+10 which targets
+@@ -101,17 +126,42 @@ _LC_BR_R1 = __LC_BR_R1
+ 555: br \reg
+ .endm
+
++ .macro __THUNK_EX_BC disp,reg,ruse
++#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
++ exrl 0,556f
++ j .
++#else
++ larl \ruse,556f
++ ex 0,0(\ruse)
++ j .
++#endif
++556: b \disp(\reg)
++ .endm
++
+ .macro GEN_BR_THUNK reg,ruse=%r1
+ __DECODE_RR __THUNK_PROLOG_BR,\reg,\ruse
+ __THUNK_EX_BR \reg,\ruse
+ __THUNK_EPILOG
+ .endm
+
++ .macro GEN_B_THUNK disp,reg,ruse=%r1
++ __DECODE_DRR __THUNK_PROLOG_BC,\disp,\reg,\ruse
++ __THUNK_EX_BC \disp,\reg,\ruse
++ __THUNK_EPILOG
++ .endm
++
+ .macro BR_EX reg,ruse=%r1
+ 557: __DECODE_RR __THUNK_BR,\reg,\ruse
+ .pushsection .s390_indirect_branches,"a",@progbits
+ .long 557b-.
+ .popsection
++ .endm
++
++ .macro B_EX disp,reg,ruse=%r1
++558: __DECODE_DRR __THUNK_BC,\disp,\reg,\ruse
++ .pushsection .s390_indirect_branches,"a",@progbits
++ .long 558b-.
++ .popsection
+ .endm
+
+ .macro BASR_EX rsave,rtarget,ruse=%r1
+@@ -123,10 +173,17 @@ _LC_BR_R1 = __LC_BR_R1
+
+ #else
+ .macro GEN_BR_THUNK reg,ruse=%r1
++ .endm
++
++ .macro GEN_B_THUNK disp,reg,ruse=%r1
+ .endm
+
+ .macro BR_EX reg,ruse=%r1
+ br \reg
++ .endm
++
++ .macro B_EX disp,reg,ruse=%r1
++ b \disp(\reg)
+ .endm
+
+ .macro BASR_EX rsave,rtarget,ruse=%r1
+diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c
+index 834cf29f2599..8ad6a7128b3a 100644
+--- a/arch/s390/kernel/nospec-branch.c
++++ b/arch/s390/kernel/nospec-branch.c
+@@ -93,7 +93,6 @@ static void __init_or_module __nospec_revert(s32 *start, s32 *end)
+ s32 *epo;
+
+ /* Second part of the instruction replace is always a nop */
+- memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x00, 0x00 }, 4);
+ for (epo = start; epo < end; epo++) {
+ instr = (u8 *) epo + *epo;
+ if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x04)
+@@ -114,18 +113,34 @@ static void __init_or_module __nospec_revert(s32 *start, s32 *end)
+ br = thunk + (*(int *)(thunk + 2)) * 2;
+ else
+ continue;
+- if (br[0] != 0x07 || (br[1] & 0xf0) != 0xf0)
++ /* Check for unconditional branch 0x07f? or 0x47f???? */
++ if ((br[0] & 0xbf) != 0x07 || (br[1] & 0xf0) != 0xf0)
+ continue;
++
++ memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x07, 0x00 }, 4);
+ switch (type) {
+ case BRCL_EXPOLINE:
+- /* brcl to thunk, replace with br + nop */
+ insnbuf[0] = br[0];
+ insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f);
++ if (br[0] == 0x47) {
++ /* brcl to b, replace with bc + nopr */
++ insnbuf[2] = br[2];
++ insnbuf[3] = br[3];
++ } else {
++ /* brcl to br, replace with bcr + nop */
++ }
+ break;
+ case BRASL_EXPOLINE:
+- /* brasl to thunk, replace with basr + nop */
+- insnbuf[0] = 0x0d;
+ insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f);
++ if (br[0] == 0x47) {
++ /* brasl to b, replace with bas + nopr */
++ insnbuf[0] = 0x4d;
++ insnbuf[2] = br[2];
++ insnbuf[3] = br[3];
++ } else {
++ /* brasl to br, replace with basr + nop */
++ insnbuf[0] = 0x0d;
++ }
+ break;
+ }
+
+
diff --git a/patches.arch/s390-ftrace-use-expoline-for-indirect-branches.patch b/patches.arch/s390-ftrace-use-expoline-for-indirect-branches.patch
new file mode 100644
index 0000000000..1137089152
--- /dev/null
+++ b/patches.arch/s390-ftrace-use-expoline-for-indirect-branches.patch
@@ -0,0 +1,141 @@
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Wed, 25 Apr 2018 18:35:26 +0200
+Subject: s390/ftrace: use expoline for indirect branches
+Git-commit: 23a4d7fd34856da8218c4cfc23dba7a6ec0a423a
+Patch-mainline: v4.17-rc6
+References: git-fixes f19fbd5ed6
+
+The return from the ftrace_stub, _mcount, ftrace_caller and
+return_to_handler functions is done with "br %r14" and "br %r1".
+These are indirect branches as well and need to use execute
+trampolines for CONFIG_EXPOLINE=y.
+
+The ftrace_caller function is a special case as it returns to the
+start of a function and may only use %r0 and %r1. For a pre z10
+machine the standard execute trampoline uses a LARL + EX to do
+this, but this requires *two* registers in the range %r1..%r15.
+To get around this the 'br %r1' located in the lowcore is used,
+then the EX instruction does not need an address register.
+But the lowcore trick may only be used for pre z14 machines,
+with noexec=on the mapping for the first page may not contain
+instructions. The solution for that is an ALTERNATIVE in the
+expoline THUNK generated by 'GEN_BR_THUNK %r1' to switch to
+EXRL, this relies on the fact that a machine that supports
+noexec=on has EXRL as well.
+
+Cc: stable@vger.kernel.org # 4.16
+Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches")
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/include/asm/nospec-insn.h | 12 ++++++++++++
+ arch/s390/kernel/asm-offsets.c | 1 +
+ arch/s390/kernel/mcount.S | 14 +++++++++-----
+ 3 files changed, 22 insertions(+), 5 deletions(-)
+
+--- a/arch/s390/include/asm/nospec-insn.h
++++ b/arch/s390/include/asm/nospec-insn.h
+@@ -2,10 +2,15 @@
+ #ifndef _ASM_S390_NOSPEC_ASM_H
+ #define _ASM_S390_NOSPEC_ASM_H
+
++#include <asm/alternative-asm.h>
++#include <asm/asm-offsets.h>
++
+ #ifdef __ASSEMBLY__
+
+ #ifdef CONFIG_EXPOLINE
+
++_LC_BR_R1 = __LC_BR_R1
++
+ /*
+ * The expoline macros are used to create thunks in the same format
+ * as gcc generates them. The 'comdat' section flag makes sure that
+@@ -78,13 +82,21 @@
+ .endm
+
+ .macro __THUNK_EX_BR reg,ruse
++ # Be very careful when adding instructions to this macro!
++ # The ALTERNATIVE replacement code has a .+10 which targets
++ # the "br \reg" after the code has been patched.
+ #ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
+ exrl 0,555f
+ j .
+ #else
++ .ifc \reg,%r1
++ ALTERNATIVE "ex %r0,_LC_BR_R1", ".insn ril,0xc60000000000,0,.+10", 35
++ j .
++ .else
+ larl \ruse,555f
+ ex 0,0(\ruse)
+ j .
++ .endif
+ #endif
+ 555: br \reg
+ .endm
+--- a/arch/s390/kernel/asm-offsets.c
++++ b/arch/s390/kernel/asm-offsets.c
+@@ -175,6 +175,7 @@ int main(void)
+ OFFSET(__LC_PREEMPT_COUNT, lowcore, preempt_count);
+ OFFSET(__LC_GMAP, lowcore, gmap);
+ OFFSET(__LC_PASTE, lowcore, paste);
++ OFFSET(__LC_BR_R1, lowcore, br_r1_trampoline);
+ /* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */
+ OFFSET(__LC_DUMP_REIPL, lowcore, ipib);
+ /* hardware defined lowcore locations 0x1000 - 0x18ff */
+--- a/arch/s390/kernel/mcount.S
++++ b/arch/s390/kernel/mcount.S
+@@ -8,13 +8,17 @@
+ #include <linux/linkage.h>
+ #include <asm/asm-offsets.h>
+ #include <asm/ftrace.h>
++#include <asm/nospec-insn.h>
+ #include <asm/ptrace.h>
+ #include <asm/export.h>
+
++ GEN_BR_THUNK %r1
++ GEN_BR_THUNK %r14
++
+ .section .kprobes.text, "ax"
+
+ ENTRY(ftrace_stub)
+- br %r14
++ BR_EX %r14
+
+ #define STACK_FRAME_SIZE (STACK_FRAME_OVERHEAD + __PT_SIZE)
+ #define STACK_PTREGS (STACK_FRAME_OVERHEAD)
+@@ -22,7 +26,7 @@ ENTRY(ftrace_stub)
+ #define STACK_PTREGS_PSW (STACK_PTREGS + __PT_PSW)
+
+ ENTRY(_mcount)
+- br %r14
++ BR_EX %r14
+
+ EXPORT_SYMBOL(_mcount)
+
+@@ -52,7 +56,7 @@ ENTRY(ftrace_caller)
+ #endif
+ lgr %r3,%r14
+ la %r5,STACK_PTREGS(%r15)
+- basr %r14,%r1
++ BASR_EX %r14,%r1
+ #ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ # The j instruction gets runtime patched to a nop instruction.
+ # See ftrace_enable_ftrace_graph_caller.
+@@ -67,7 +71,7 @@ ftrace_graph_caller_end:
+ #endif
+ lg %r1,(STACK_PTREGS_PSW+8)(%r15)
+ lmg %r2,%r15,(STACK_PTREGS_GPRS+2*8)(%r15)
+- br %r1
++ BR_EX %r1
+
+ #ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+@@ -80,6 +84,6 @@ ENTRY(return_to_handler)
+ aghi %r15,STACK_FRAME_OVERHEAD
+ lgr %r14,%r2
+ lmg %r2,%r5,32(%r15)
+- br %r14
++ BR_EX %r14
+
+ #endif
diff --git a/patches.arch/s390-gs-add-compat-regset-for-the-guarded-storage-broadcast-control-block.patch b/patches.arch/s390-gs-add-compat-regset-for-the-guarded-storage-broadcast-control-block.patch
new file mode 100644
index 0000000000..b568657369
--- /dev/null
+++ b/patches.arch/s390-gs-add-compat-regset-for-the-guarded-storage-broadcast-control-block.patch
@@ -0,0 +1,39 @@
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Tue, 28 Nov 2017 17:20:53 +0100
+Subject: s390/gs: add compat regset for the guarded storage broadcast control
+ block
+Git-commit: 9d0ca444d0b317d31acf6f8fc18ac6f478518924
+Patch-mainline: v4.15-rc2
+References: git-fixes e525f8a6e696
+
+git commit e525f8a6e696210d15f8b8277d4da12fc4add299
+"s390/gs: add regset for the guarded storage broadcast control block"
+added the missing regset to the s390_regsets array but failed to add it
+to the s390_compat_regsets array.
+
+Fixes: e525f8a6e696 ("add compat regset for the guarded storage broadcast control block")
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/kernel/ptrace.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
+index 26c0523c1488..cd3df5514552 100644
+--- a/arch/s390/kernel/ptrace.c
++++ b/arch/s390/kernel/ptrace.c
+@@ -1650,6 +1650,14 @@ static const struct user_regset s390_compat_regsets[] = {
+ .get = s390_gs_cb_get,
+ .set = s390_gs_cb_set,
+ },
++ {
++ .core_note_type = NT_S390_GS_BC,
++ .n = sizeof(struct gs_cb) / sizeof(__u64),
++ .size = sizeof(__u64),
++ .align = sizeof(__u64),
++ .get = s390_gs_bc_get,
++ .set = s390_gs_bc_set,
++ },
+ };
+
+ static const struct user_regset_view user_s390_compat_view = {
diff --git a/patches.arch/s390-kernel-use-expoline-for-indirect-branches.patch b/patches.arch/s390-kernel-use-expoline-for-indirect-branches.patch
new file mode 100644
index 0000000000..29eea38e03
--- /dev/null
+++ b/patches.arch/s390-kernel-use-expoline-for-indirect-branches.patch
@@ -0,0 +1,169 @@
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Wed, 25 Apr 2018 18:41:30 +0200
+Subject: s390/kernel: use expoline for indirect branches
+Git-commit: c50c84c3ac4d5db683904bdb3257798b6ef980ae
+Patch-mainline: v4.17-rc6
+References: git-fixes f19fbd5ed6
+
+The assember code in arch/s390/kernel uses a few more indirect branches
+which need to be done with execute trampolines for CONFIG_EXPOLINE=y.
+
+Cc: stable@vger.kernel.org # 4.16
+Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches")
+Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/kernel/base.S | 24 ++++++++++++++----------
+ arch/s390/kernel/reipl.S | 7 +++++--
+ arch/s390/kernel/swsusp.S | 10 ++++++----
+ 3 files changed, 25 insertions(+), 16 deletions(-)
+
+diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S
+index f6c56009e822..b65874b0b412 100644
+--- a/arch/s390/kernel/base.S
++++ b/arch/s390/kernel/base.S
+@@ -9,18 +9,22 @@
+
+ #include <linux/linkage.h>
+ #include <asm/asm-offsets.h>
++#include <asm/nospec-insn.h>
+ #include <asm/ptrace.h>
+ #include <asm/sigp.h>
+
++ GEN_BR_THUNK %r9
++ GEN_BR_THUNK %r14
++
+ ENTRY(s390_base_mcck_handler)
+ basr %r13,0
+ 0: lg %r15,__LC_PANIC_STACK # load panic stack
+ aghi %r15,-STACK_FRAME_OVERHEAD
+ larl %r1,s390_base_mcck_handler_fn
+- lg %r1,0(%r1)
+- ltgr %r1,%r1
++ lg %r9,0(%r1)
++ ltgr %r9,%r9
+ jz 1f
+- basr %r14,%r1
++ BASR_EX %r14,%r9
+ 1: la %r1,4095
+ lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
+ lpswe __LC_MCK_OLD_PSW
+@@ -37,10 +41,10 @@ ENTRY(s390_base_ext_handler)
+ basr %r13,0
+ 0: aghi %r15,-STACK_FRAME_OVERHEAD
+ larl %r1,s390_base_ext_handler_fn
+- lg %r1,0(%r1)
+- ltgr %r1,%r1
++ lg %r9,0(%r1)
++ ltgr %r9,%r9
+ jz 1f
+- basr %r14,%r1
++ BASR_EX %r14,%r9
+ 1: lmg %r0,%r15,__LC_SAVE_AREA_ASYNC
+ ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit
+ lpswe __LC_EXT_OLD_PSW
+@@ -57,10 +61,10 @@ ENTRY(s390_base_pgm_handler)
+ basr %r13,0
+ 0: aghi %r15,-STACK_FRAME_OVERHEAD
+ larl %r1,s390_base_pgm_handler_fn
+- lg %r1,0(%r1)
+- ltgr %r1,%r1
++ lg %r9,0(%r1)
++ ltgr %r9,%r9
+ jz 1f
+- basr %r14,%r1
++ BASR_EX %r14,%r9
+ lmg %r0,%r15,__LC_SAVE_AREA_SYNC
+ lpswe __LC_PGM_OLD_PSW
+ 1: lpswe disabled_wait_psw-0b(%r13)
+@@ -117,7 +121,7 @@ ENTRY(diag308_reset)
+ larl %r4,.Lcontinue_psw # Restore PSW flags
+ lpswe 0(%r4)
+ .Lcontinue:
+- br %r14
++ BR_EX %r14
+ .align 16
+ .Lrestart_psw:
+ .long 0x00080000,0x80000000 + .Lrestart_part2
+diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S
+index 73cc3750f0d3..7f14adf512c6 100644
+--- a/arch/s390/kernel/reipl.S
++++ b/arch/s390/kernel/reipl.S
+@@ -7,8 +7,11 @@
+
+ #include <linux/linkage.h>
+ #include <asm/asm-offsets.h>
++#include <asm/nospec-insn.h>
+ #include <asm/sigp.h>
+
++ GEN_BR_THUNK %r9
++
+ #
+ # Issue "store status" for the current CPU to its prefix page
+ # and call passed function afterwards
+@@ -67,9 +70,9 @@ ENTRY(store_status)
+ st %r4,0(%r1)
+ st %r5,4(%r1)
+ stg %r2,8(%r1)
+- lgr %r1,%r2
++ lgr %r9,%r2
+ lgr %r2,%r3
+- br %r1
++ BR_EX %r9
+
+ .section .bss
+ .align 8
+diff --git a/arch/s390/kernel/swsusp.S b/arch/s390/kernel/swsusp.S
+index e99187149f17..a049a7b9d6e8 100644
+--- a/arch/s390/kernel/swsusp.S
++++ b/arch/s390/kernel/swsusp.S
+@@ -13,6 +13,7 @@
+ #include <asm/ptrace.h>
+ #include <asm/thread_info.h>
+ #include <asm/asm-offsets.h>
++#include <asm/nospec-insn.h>
+ #include <asm/sigp.h>
+
+ /*
+@@ -24,6 +25,8 @@
+ * (see below) in the resume process.
+ * This function runs with disabled interrupts.
+ */
++ GEN_BR_THUNK %r14
++
+ .section .text
+ ENTRY(swsusp_arch_suspend)
+ stmg %r6,%r15,__SF_GPRS(%r15)
+@@ -103,7 +106,7 @@ ENTRY(swsusp_arch_suspend)
+ spx 0x318(%r1)
+ lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15)
+ lghi %r2,0
+- br %r14
++ BR_EX %r14
+
+ /*
+ * Restore saved memory image to correct place and restore register context.
+@@ -197,11 +200,10 @@ pgm_check_entry:
+ larl %r15,init_thread_union
+ ahi %r15,1<<(PAGE_SHIFT+THREAD_SIZE_ORDER)
+ larl %r2,.Lpanic_string
+- larl %r3,sclp_early_printk
+ lghi %r1,0
+ sam31
+ sigp %r1,%r0,SIGP_SET_ARCHITECTURE
+- basr %r14,%r3
++ brasl %r14,sclp_early_printk
+ larl %r3,.Ldisabled_wait_31
+ lpsw 0(%r3)
+ 4:
+@@ -267,7 +269,7 @@ restore_registers:
+ /* Return 0 */
+ lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15)
+ lghi %r2,0
+- br %r14
++ BR_EX %r14
+
+ .section .data..nosave,"aw",@progbits
+ .align 8
+
diff --git a/patches.arch/s390-lib-use-expoline-for-indirect-branches.patch b/patches.arch/s390-lib-use-expoline-for-indirect-branches.patch
new file mode 100644
index 0000000000..654f00e3f5
--- /dev/null
+++ b/patches.arch/s390-lib-use-expoline-for-indirect-branches.patch
@@ -0,0 +1,80 @@
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Mon, 23 Apr 2018 14:31:36 +0200
+Subject: s390/lib: use expoline for indirect branches
+Git-commit: 97489e0663fa700d6e7febddc43b58df98d7bcda
+Patch-mainline: v4.17-rc6
+References: git-fixes f19fbd5ed6
+
+The return from the memmove, memset, memcpy, __memset16, __memset32 and
+__memset64 functions are done with "br %r14". These are indirect branches
+as well and need to use execute trampolines for CONFIG_EXPOLINE=y.
+
+Cc: stable@vger.kernel.org # 4.16
+Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches")
+Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Signed-off-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/lib/mem.S | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+--- a/arch/s390/lib/mem.S
++++ b/arch/s390/lib/mem.S
+@@ -6,6 +6,9 @@
+
+ #include <linux/linkage.h>
+ #include <asm/export.h>
++#include <asm/nospec-insn.h>
++
++ GEN_BR_THUNK %r14
+
+ /*
+ * void *memmove(void *dest, const void *src, size_t n)
+@@ -32,14 +35,14 @@ ENTRY(memmove)
+ .Lmemmove_forward_remainder:
+ larl %r5,.Lmemmove_mvc
+ ex %r4,0(%r5)
+- br %r14
++ BR_EX %r14
+ .Lmemmove_reverse:
+ ic %r0,0(%r4,%r3)
+ stc %r0,0(%r4,%r1)
+ brctg %r4,.Lmemmove_reverse
+ ic %r0,0(%r4,%r3)
+ stc %r0,0(%r4,%r1)
+- br %r14
++ BR_EX %r14
+ .Lmemmove_mvc:
+ mvc 0(1,%r1),0(%r3)
+ EXPORT_SYMBOL(memmove)
+@@ -76,7 +79,7 @@ ENTRY(memset)
+ .Lmemset_clear_remainder:
+ larl %r3,.Lmemset_xc
+ ex %r4,0(%r3)
+- br %r14
++ BR_EX %r14
+ .Lmemset_fill:
+ cghi %r4,1
+ lgr %r1,%r2
+@@ -94,10 +97,10 @@ ENTRY(memset)
+ stc %r3,0(%r1)
+ larl %r5,.Lmemset_mvc
+ ex %r4,0(%r5)
+- br %r14
++ BR_EX %r14
+ .Lmemset_fill_exit:
+ stc %r3,0(%r1)
+- br %r14
++ BR_EX %r14
+ .Lmemset_xc:
+ xc 0(1,%r1),0(%r1)
+ .Lmemset_mvc:
+@@ -120,7 +123,7 @@ ENTRY(memcpy)
+ .Lmemcpy_remainder:
+ larl %r5,.Lmemcpy_mvc
+ ex %r4,0(%r5)
+- br %r14
++ BR_EX %r14
+ .Lmemcpy_loop:
+ mvc 0(256,%r1),0(%r3)
+ la %r1,256(%r1)
diff --git a/patches.arch/s390-move-expoline-assembler-macros-to-a-header.patch b/patches.arch/s390-move-expoline-assembler-macros-to-a-header.patch
new file mode 100644
index 0000000000..00ed1e0ef5
--- /dev/null
+++ b/patches.arch/s390-move-expoline-assembler-macros-to-a-header.patch
@@ -0,0 +1,404 @@
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Fri, 20 Apr 2018 16:49:46 +0200
+Subject: s390: move expoline assembler macros to a header
+Git-commit: 6dd85fbb87d1d6b87a3b1f02ca28d7b2abd2e7ba
+Patch-mainline: v4.17-rc6
+References: git-fixes f19fbd5ed6
+
+To be able to use the expoline branches in different assembler
+files move the associated macros from entry.S to a new header
+nospec-insn.h.
+
+While we are at it make the macros a bit nicer to use.
+
+Cc: stable@vger.kernel.org # 4.16
+Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches")
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Signed-off-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/include/asm/nospec-insn.h | 127 ++++++++++++++++++++++++++++++++++++
+ arch/s390/kernel/entry.S | 105 ++++++-----------------------
+ 2 files changed, 151 insertions(+), 81 deletions(-)
+
+--- /dev/null
++++ b/arch/s390/include/asm/nospec-insn.h
+@@ -0,0 +1,125 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef _ASM_S390_NOSPEC_ASM_H
++#define _ASM_S390_NOSPEC_ASM_H
++
++#ifdef __ASSEMBLY__
++
++#ifdef CONFIG_EXPOLINE
++
++/*
++ * The expoline macros are used to create thunks in the same format
++ * as gcc generates them. The 'comdat' section flag makes sure that
++ * the various thunks are merged into a single copy.
++ */
++ .macro __THUNK_PROLOG_NAME name
++ .pushsection .text.\name,"axG",@progbits,\name,comdat
++ .globl \name
++ .hidden \name
++ .type \name,@function
++\name:
++ .cfi_startproc
++ .endm
++
++ .macro __THUNK_EPILOG
++ .cfi_endproc
++ .popsection
++ .endm
++
++ .macro __THUNK_PROLOG_BR r1,r2
++ __THUNK_PROLOG_NAME __s390x_indirect_jump_r\r2\()use_r\r1
++ .endm
++
++ .macro __THUNK_BR r1,r2
++ jg __s390x_indirect_jump_r\r2\()use_r\r1
++ .endm
++
++ .macro __THUNK_BRASL r1,r2,r3
++ brasl \r1,__s390x_indirect_jump_r\r3\()use_r\r2
++ .endm
++
++ .macro __DECODE_RR expand,reg,ruse
++ .set __decode_fail,1
++ .irp r1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
++ .ifc \reg,%r\r1
++ .irp r2,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
++ .ifc \ruse,%r\r2
++ \expand \r1,\r2
++ .set __decode_fail,0
++ .endif
++ .endr
++ .endif
++ .endr
++ .if __decode_fail == 1
++ .error "__DECODE_RR failed"
++ .endif
++ .endm
++
++ .macro __DECODE_RRR expand,rsave,rtarget,ruse
++ .set __decode_fail,1
++ .irp r1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
++ .ifc \rsave,%r\r1
++ .irp r2,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
++ .ifc \rtarget,%r\r2
++ .irp r3,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
++ .ifc \ruse,%r\r3
++ \expand \r1,\r2,\r3
++ .set __decode_fail,0
++ .endif
++ .endr
++ .endif
++ .endr
++ .endif
++ .endr
++ .if __decode_fail == 1
++ .error "__DECODE_RRR failed"
++ .endif
++ .endm
++
++ .macro __THUNK_EX_BR reg,ruse
++#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
++ exrl 0,555f
++ j .
++#else
++ larl \ruse,555f
++ ex 0,0(\ruse)
++ j .
++#endif
++555: br \reg
++ .endm
++
++ .macro GEN_BR_THUNK reg,ruse=%r1
++ __DECODE_RR __THUNK_PROLOG_BR,\reg,\ruse
++ __THUNK_EX_BR \reg,\ruse
++ __THUNK_EPILOG
++ .endm
++
++ .macro BR_EX reg,ruse=%r1
++557: __DECODE_RR __THUNK_BR,\reg,\ruse
++ .pushsection .s390_indirect_branches,"a",@progbits
++ .long 557b-.
++ .popsection
++ .endm
++
++ .macro BASR_EX rsave,rtarget,ruse=%r1
++559: __DECODE_RRR __THUNK_BRASL,\rsave,\rtarget,\ruse
++ .pushsection .s390_indirect_branches,"a",@progbits
++ .long 559b-.
++ .popsection
++ .endm
++
++#else
++ .macro GEN_BR_THUNK reg,ruse=%r1
++ .endm
++
++ .macro BR_EX reg,ruse=%r1
++ br \reg
++ .endm
++
++ .macro BASR_EX rsave,rtarget,ruse=%r1
++ basr \rsave,\rtarget
++ .endm
++#endif
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* _ASM_S390_NOSPEC_ASM_H */
+--- a/arch/s390/kernel/entry.S
++++ b/arch/s390/kernel/entry.S
+@@ -24,6 +24,7 @@
+ #include <asm/setup.h>
+ #include <asm/nmi.h>
+ #include <asm/export.h>
++#include <asm/nospec-insn.h>
+
+ __PT_R0 = __PT_GPRS
+ __PT_R1 = __PT_GPRS + 8
+@@ -220,67 +221,9 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCAL
+ .popsection
+ .endm
+
+-#ifdef CONFIG_EXPOLINE
+-
+- .macro GEN_BR_THUNK name,reg,tmp
+- .section .text.\name,"axG",@progbits,\name,comdat
+- .globl \name
+- .hidden \name
+- .type \name,@function
+-\name:
+- .cfi_startproc
+-#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
+- exrl 0,0f
+-#else
+- larl \tmp,0f
+- ex 0,0(\tmp)
+-#endif
+- j .
+-0: br \reg
+- .cfi_endproc
+- .endm
+-
+- GEN_BR_THUNK __s390x_indirect_jump_r1use_r9,%r9,%r1
+- GEN_BR_THUNK __s390x_indirect_jump_r1use_r14,%r14,%r1
+- GEN_BR_THUNK __s390x_indirect_jump_r11use_r14,%r14,%r11
+-
+- .macro BASR_R14_R9
+-0: brasl %r14,__s390x_indirect_jump_r1use_r9
+- .pushsection .s390_indirect_branches,"a",@progbits
+- .long 0b-.
+- .popsection
+- .endm
+-
+- .macro BR_R1USE_R14
+-0: jg __s390x_indirect_jump_r1use_r14
+- .pushsection .s390_indirect_branches,"a",@progbits
+- .long 0b-.
+- .popsection
+- .endm
+-
+- .macro BR_R11USE_R14
+-0: jg __s390x_indirect_jump_r11use_r14
+- .pushsection .s390_indirect_branches,"a",@progbits
+- .long 0b-.
+- .popsection
+- .endm
+-
+-#else /* CONFIG_EXPOLINE */
+-
+- .macro BASR_R14_R9
+- basr %r14,%r9
+- .endm
+-
+- .macro BR_R1USE_R14
+- br %r14
+- .endm
+-
+- .macro BR_R11USE_R14
+- br %r14
+- .endm
+-
+-#endif /* CONFIG_EXPOLINE */
+-
++ GEN_BR_THUNK %r9
++ GEN_BR_THUNK %r14
++ GEN_BR_THUNK %r14,%r11
+
+ .section .kprobes.text, "ax"
+ .Ldummy:
+@@ -297,7 +240,7 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCAL
+ ENTRY(__bpon)
+ .globl __bpon
+ BPON
+- BR_R1USE_R14
++ BR_EX %r14
+
+ /*
+ * Scheduler resume function, called by switch_to
+@@ -324,7 +267,7 @@ ENTRY(__switch_to)
+ TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_LPP
+ jz 0f
+ .insn s,0xb2800000,__LC_LPP # set program parameter
+-0: BR_R1USE_R14
++0: BR_EX %r14
+
+ .L__critical_start:
+
+@@ -391,7 +334,7 @@ sie_exit:
+ xgr %r5,%r5
+ lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers
+ lg %r2,__SF_EMPTY+16(%r15) # return exit reason code
+- BR_R1USE_R14
++ BR_EX %r14
+ .Lsie_fault:
+ lghi %r14,-EFAULT
+ stg %r14,__SF_EMPTY+16(%r15) # set exit reason code
+@@ -450,7 +393,7 @@ ENTRY(system_call)
+ lgf %r9,0(%r8,%r10) # get system call add.
+ TSTMSK __TI_flags(%r12),_TIF_TRACE
+ jnz .Lsysc_tracesys
+- BASR_R14_R9 # call sys_xxxx
++ BASR_EX %r14,%r9 # call sys_xxxx
+ stg %r2,__PT_R2(%r11) # store return value
+
+ .Lsysc_return:
+@@ -627,7 +570,7 @@ ENTRY(system_call)
+ lmg %r3,%r7,__PT_R3(%r11)
+ stg %r7,STACK_FRAME_OVERHEAD(%r15)
+ lg %r2,__PT_ORIG_GPR2(%r11)
+- BASR_R14_R9 # call sys_xxx
++ BASR_EX %r14,%r9 # call sys_xxx
+ stg %r2,__PT_R2(%r11) # store return value
+ .Lsysc_tracenogo:
+ TSTMSK __TI_flags(%r12),_TIF_TRACE
+@@ -651,7 +594,7 @@ ENTRY(ret_from_fork)
+ lmg %r9,%r10,__PT_R9(%r11) # load gprs
+ ENTRY(kernel_thread_starter)
+ la %r2,0(%r10)
+- BASR_R14_R9
++ BASR_EX %r14,%r9
+ j .Lsysc_tracenogo
+
+ /*
+@@ -730,7 +673,7 @@ ENTRY(pgm_check_handler)
+ je .Lpgm_return
+ lgf %r9,0(%r10,%r1) # load address of handler routine
+ lgr %r2,%r11 # pass pointer to pt_regs
+- BASR_R14_R9 # branch to interrupt-handler
++ BASR_EX %r14,%r9 # branch to interrupt-handler
+ .Lpgm_return:
+ LOCKDEP_SYS_EXIT
+ tm __PT_PSW+1(%r11),0x01 # returning to user ?
+@@ -1040,7 +983,7 @@ ENTRY(psw_idle)
+ stpt __TIMER_IDLE_ENTER(%r2)
+ .Lpsw_idle_lpsw:
+ lpswe __SF_EMPTY(%r15)
+- BR_R1USE_R14
++ BR_EX %r14
+ .Lpsw_idle_end:
+
+ /*
+@@ -1082,7 +1025,7 @@ ENTRY(save_fpu_regs)
+ .Lsave_fpu_regs_done:
+ oi __LC_CPU_FLAGS+7,_CIF_FPU
+ .Lsave_fpu_regs_exit:
+- BR_R1USE_R14
++ BR_EX %r14
+ .Lsave_fpu_regs_end:
+ #if IS_ENABLED(CONFIG_KVM)
+ EXPORT_SYMBOL(save_fpu_regs)
+@@ -1130,7 +1073,7 @@ load_fpu_regs:
+ .Lload_fpu_regs_done:
+ ni __LC_CPU_FLAGS+7,255-_CIF_FPU
+ .Lload_fpu_regs_exit:
+- BR_R1USE_R14
++ BR_EX %r14
+ .Lload_fpu_regs_end:
+
+ .L__critical_end:
+@@ -1302,7 +1245,7 @@ cleanup_critical:
+ jl 0f
+ clg %r9,BASED(.Lcleanup_table+104) # .Lload_fpu_regs_end
+ jl .Lcleanup_load_fpu_regs
+-0: BR_R11USE_R14
++0: BR_EX %r14
+
+ .align 8
+ .Lcleanup_table:
+@@ -1338,7 +1281,7 @@ cleanup_critical:
+ ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE
+ lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
+ larl %r9,sie_exit # skip forward to sie_exit
+- BR_R11USE_R14
++ BR_EX %r14
+ #endif
+
+ .Lcleanup_system_call:
+@@ -1392,7 +1335,7 @@ cleanup_critical:
+ stg %r15,56(%r11) # r15 stack pointer
+ # set new psw address and exit
+ larl %r9,.Lsysc_do_svc
+- BR_R11USE_R14
++ BR_EX %r14,%r11
+ .Lcleanup_system_call_insn:
+ .quad system_call
+ .quad .Lsysc_stmg
+@@ -1404,7 +1347,7 @@ cleanup_critical:
+
+ .Lcleanup_sysc_tif:
+ larl %r9,.Lsysc_tif
+- BR_R11USE_R14
++ BR_EX %r14,%r11
+
+ .Lcleanup_sysc_restore:
+ # check if stpt has been executed
+@@ -1421,14 +1364,14 @@ cleanup_critical:
+ mvc 0(64,%r11),__PT_R8(%r9)
+ lmg %r0,%r7,__PT_R0(%r9)
+ 1: lmg %r8,%r9,__LC_RETURN_PSW
+- BR_R11USE_R14
++ BR_EX %r14,%r11
+ .Lcleanup_sysc_restore_insn:
+ .quad .Lsysc_exit_timer
+ .quad .Lsysc_done - 4
+
+ .Lcleanup_io_tif:
+ larl %r9,.Lio_tif
+- BR_R11USE_R14
++ BR_EX %r14,%r11
+
+ .Lcleanup_io_restore:
+ # check if stpt has been executed
+@@ -1442,7 +1385,7 @@ cleanup_critical:
+ mvc 0(64,%r11),__PT_R8(%r9)
+ lmg %r0,%r7,__PT_R0(%r9)
+ 1: lmg %r8,%r9,__LC_RETURN_PSW
+- BR_R11USE_R14
++ BR_EX %r14,%r11
+ .Lcleanup_io_restore_insn:
+ .quad .Lio_exit_timer
+ .quad .Lio_done - 4
+@@ -1495,17 +1438,17 @@ cleanup_critical:
+ # prepare return psw
+ nihh %r8,0xfcfd # clear irq & wait state bits
+ lg %r9,48(%r11) # return from psw_idle
+- BR_R11USE_R14
++ BR_EX %r14,%r11
+ .Lcleanup_idle_insn:
+ .quad .Lpsw_idle_lpsw
+
+ .Lcleanup_save_fpu_regs:
+ larl %r9,save_fpu_regs
+- BR_R11USE_R14
++ BR_EX %r14,%r11
+
+ .Lcleanup_load_fpu_regs:
+ larl %r9,load_fpu_regs
+- BR_R11USE_R14
++ BR_EX %r14,%r11
+
+ /*
+ * Integer constants
diff --git a/patches.arch/s390-optimize-memset-implementation.patch b/patches.arch/s390-optimize-memset-implementation.patch
new file mode 100644
index 0000000000..e930da91ab
--- /dev/null
+++ b/patches.arch/s390-optimize-memset-implementation.patch
@@ -0,0 +1,63 @@
+From: Heiko Carstens <heiko.carstens@de.ibm.com>
+Date: Wed, 4 Oct 2017 19:27:08 +0200
+Subject: s390: optimize memset implementation
+Git-commit: 993fef95b9c1858894d14b221e04f1161e4f4ed9
+Patch-mainline: v4.15-rc1
+References: git-fixes f19fbd5ed6
+
+Like for the memset16/32/64 variants avoid that subsequent mvc
+instructions depend on each other since that might have negative
+performance impacts.
+
+This patch is currently hardly relevant since at least gcc 7.1
+generates only inline memset code and not a single memset call.
+However there is no reason to not provide an optimized version
+just in case gcc generates memset calls again, like it did in
+the past.
+
+Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/lib/mem.S | 20 ++++++++++++--------
+ 1 file changed, 12 insertions(+), 8 deletions(-)
+
+diff --git a/arch/s390/lib/mem.S b/arch/s390/lib/mem.S
+index f88cf6983849..9255a087fa96 100644
+--- a/arch/s390/lib/mem.S
++++ b/arch/s390/lib/mem.S
+@@ -78,21 +78,25 @@ ENTRY(memset)
+ ex %r4,0(%r3)
+ br %r14
+ .Lmemset_fill:
+- stc %r3,0(%r2)
+ cghi %r4,1
+ lgr %r1,%r2
+- ber %r14
++ je .Lmemset_fill_exit
+ aghi %r4,-2
+- srlg %r3,%r4,8
+- ltgr %r3,%r3
++ srlg %r5,%r4,8
++ ltgr %r5,%r5
+ jz .Lmemset_fill_remainder
+ .Lmemset_fill_loop:
+- mvc 1(256,%r1),0(%r1)
++ stc %r3,0(%r1)
++ mvc 1(255,%r1),0(%r1)
+ la %r1,256(%r1)
+- brctg %r3,.Lmemset_fill_loop
++ brctg %r5,.Lmemset_fill_loop
+ .Lmemset_fill_remainder:
+- larl %r3,.Lmemset_mvc
+- ex %r4,0(%r3)
++ stc %r3,0(%r1)
++ larl %r5,.Lmemset_mvc
++ ex %r4,0(%r5)
++ br %r14
++.Lmemset_fill_exit:
++ stc %r3,0(%r1)
+ br %r14
+ .Lmemset_xc:
+ xc 0(1,%r1),0(%r1)
+
diff --git a/patches.arch/s390-remove-indirect-branch-from-do_softirq_own_stack.patch b/patches.arch/s390-remove-indirect-branch-from-do_softirq_own_stack.patch
new file mode 100644
index 0000000000..667854d468
--- /dev/null
+++ b/patches.arch/s390-remove-indirect-branch-from-do_softirq_own_stack.patch
@@ -0,0 +1,38 @@
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Tue, 24 Apr 2018 11:18:49 +0200
+Subject: s390: remove indirect branch from do_softirq_own_stack
+Git-commit: 9f18fff63cfd6f559daa1eaae60640372c65f84b
+Patch-mainline: v4.17-rc6
+References: git-fixes f19fbd5ed6
+
+The inline assembly to call __do_softirq on the irq stack uses
+an indirect branch. This can be replaced with a normal relative
+branch.
+
+Cc: stable@vger.kernel.org # 4.16
+Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches")
+Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/kernel/irq.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
+index 94f2099bceb0..3d17c41074ca 100644
+--- a/arch/s390/kernel/irq.c
++++ b/arch/s390/kernel/irq.c
+@@ -176,10 +176,9 @@ void do_softirq_own_stack(void)
+ new -= STACK_FRAME_OVERHEAD;
+ ((struct stack_frame *) new)->back_chain = old;
+ asm volatile(" la 15,0(%0)\n"
+- " basr 14,%2\n"
++ " brasl 14,__do_softirq\n"
+ " la 15,0(%1)\n"
+- : : "a" (new), "a" (old),
+- "a" (__do_softirq)
++ : : "a" (new), "a" (old)
+ : "0", "1", "2", "3", "4", "5", "14",
+ "cc", "memory" );
+ } else {
+
diff --git a/patches.arch/s390-use-expoline-thunks-in-the-bpf-jit.patch b/patches.arch/s390-use-expoline-thunks-in-the-bpf-jit.patch
new file mode 100644
index 0000000000..03ded5d489
--- /dev/null
+++ b/patches.arch/s390-use-expoline-thunks-in-the-bpf-jit.patch
@@ -0,0 +1,193 @@
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Mon, 23 Apr 2018 14:31:36 +0200
+Subject: s390: use expoline thunks in the BPF JIT
+Git-commit: de5cb6eb514ebe241e3edeb290cb41deb380b81d
+Patch-mainline: v4.17-rc6
+References: git-fixes, bsc#1103421
+
+The BPF JIT need safe guarding against spectre v2 in the sk_load_xxx
+assembler stubs and the indirect branches generated by the JIT itself
+need to be converted to expolines.
+
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/net/bpf_jit.S | 16 ++++++-----
+ arch/s390/net/bpf_jit_comp.c | 63 ++++++++++++++++++++++++++++++++++++++++++--
+ 2 files changed, 71 insertions(+), 8 deletions(-)
+
+diff --git a/arch/s390/net/bpf_jit.S b/arch/s390/net/bpf_jit.S
+index 25bb4643c4f4..9f794869c1b0 100644
+--- a/arch/s390/net/bpf_jit.S
++++ b/arch/s390/net/bpf_jit.S
+@@ -9,6 +9,7 @@
+ */
+
+ #include <linux/linkage.h>
++#include <asm/nospec-insn.h>
+ #include "bpf_jit.h"
+
+ /*
+@@ -54,7 +55,7 @@ ENTRY(sk_load_##NAME##_pos); \
+ clg %r3,STK_OFF_HLEN(%r15); /* Offset + SIZE > hlen? */ \
+ jh sk_load_##NAME##_slow; \
+ LOAD %r14,-SIZE(%r3,%r12); /* Get data from skb */ \
+- b OFF_OK(%r6); /* Return */ \
++ B_EX OFF_OK,%r6; /* Return */ \
+ \
+ sk_load_##NAME##_slow:; \
+ lgr %r2,%r7; /* Arg1 = skb pointer */ \
+@@ -64,11 +65,14 @@ sk_load_##NAME##_slow:; \
+ brasl %r14,skb_copy_bits; /* Get data from skb */ \
+ LOAD %r14,STK_OFF_TMP(%r15); /* Load from temp bufffer */ \
+ ltgr %r2,%r2; /* Set cc to (%r2 != 0) */ \
+- br %r6; /* Return */
++ BR_EX %r6; /* Return */
+
+ sk_load_common(word, 4, llgf) /* r14 = *(u32 *) (skb->data+offset) */
+ sk_load_common(half, 2, llgh) /* r14 = *(u16 *) (skb->data+offset) */
+
++ GEN_BR_THUNK %r6
++ GEN_B_THUNK OFF_OK,%r6
++
+ /*
+ * Load 1 byte from SKB (optimized version)
+ */
+@@ -80,7 +84,7 @@ ENTRY(sk_load_byte_pos)
+ clg %r3,STK_OFF_HLEN(%r15) # Offset >= hlen?
+ jnl sk_load_byte_slow
+ llgc %r14,0(%r3,%r12) # Get byte from skb
+- b OFF_OK(%r6) # Return OK
++ B_EX OFF_OK,%r6 # Return OK
+
+ sk_load_byte_slow:
+ lgr %r2,%r7 # Arg1 = skb pointer
+@@ -90,7 +94,7 @@ sk_load_byte_slow:
+ brasl %r14,skb_copy_bits # Get data from skb
+ llgc %r14,STK_OFF_TMP(%r15) # Load result from temp buffer
+ ltgr %r2,%r2 # Set cc to (%r2 != 0)
+- br %r6 # Return cc
++ BR_EX %r6 # Return cc
+
+ #define sk_negative_common(NAME, SIZE, LOAD) \
+ sk_load_##NAME##_slow_neg:; \
+@@ -104,7 +108,7 @@ sk_load_##NAME##_slow_neg:; \
+ jz bpf_error; \
+ LOAD %r14,0(%r2); /* Get data from pointer */ \
+ xr %r3,%r3; /* Set cc to zero */ \
+- br %r6; /* Return cc */
++ BR_EX %r6; /* Return cc */
+
+ sk_negative_common(word, 4, llgf)
+ sk_negative_common(half, 2, llgh)
+@@ -113,4 +117,4 @@ sk_negative_common(byte, 1, llgc)
+ bpf_error:
+ # force a return 0 from jit handler
+ ltgr %r15,%r15 # Set condition code
+- br %r6
++ BR_EX %r6
+diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
+index 78a19c93b380..dd2bcf0e7d00 100644
+--- a/arch/s390/net/bpf_jit_comp.c
++++ b/arch/s390/net/bpf_jit_comp.c
+@@ -25,6 +25,8 @@
+ #include <linux/bpf.h>
+ #include <asm/cacheflush.h>
+ #include <asm/dis.h>
++#include <asm/facility.h>
++#include <asm/nospec-branch.h>
+ #include <asm/set_memory.h>
+ #include "bpf_jit.h"
+
+@@ -41,6 +43,8 @@ struct bpf_jit {
+ int base_ip; /* Base address for literal pool */
+ int ret0_ip; /* Address of return 0 */
+ int exit_ip; /* Address of exit */
++ int r1_thunk_ip; /* Address of expoline thunk for 'br %r1' */
++ int r14_thunk_ip; /* Address of expoline thunk for 'br %r14' */
+ int tail_call_start; /* Tail call start offset */
+ int labels[1]; /* Labels for local jumps */
+ };
+@@ -250,6 +254,19 @@ static inline void reg_set_seen(struct bpf_jit *jit, u32 b1)
+ REG_SET_SEEN(b2); \
+ })
+
++#define EMIT6_PCREL_RILB(op, b, target) \
++({ \
++ int rel = (target - jit->prg) / 2; \
++ _EMIT6(op | reg_high(b) << 16 | rel >> 16, rel & 0xffff); \
++ REG_SET_SEEN(b); \
++})
++
++#define EMIT6_PCREL_RIL(op, target) \
++({ \
++ int rel = (target - jit->prg) / 2; \
++ _EMIT6(op | rel >> 16, rel & 0xffff); \
++})
++
+ #define _EMIT6_IMM(op, imm) \
+ ({ \
+ unsigned int __imm = (imm); \
+@@ -469,8 +486,45 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)
+ EMIT4(0xb9040000, REG_2, BPF_REG_0);
+ /* Restore registers */
+ save_restore_regs(jit, REGS_RESTORE, stack_depth);
++ if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) {
++ jit->r14_thunk_ip = jit->prg;
++ /* Generate __s390_indirect_jump_r14 thunk */
++ if (test_facility(35)) {
++ /* exrl %r0,.+10 */
++ EMIT6_PCREL_RIL(0xc6000000, jit->prg + 10);
++ } else {
++ /* larl %r1,.+14 */
++ EMIT6_PCREL_RILB(0xc0000000, REG_1, jit->prg + 14);
++ /* ex 0,0(%r1) */
++ EMIT4_DISP(0x44000000, REG_0, REG_1, 0);
++ }
++ /* j . */
++ EMIT4_PCREL(0xa7f40000, 0);
++ }
+ /* br %r14 */
+ _EMIT2(0x07fe);
++
++ if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable &&
++ (jit->seen & SEEN_FUNC)) {
++ jit->r1_thunk_ip = jit->prg;
++ /* Generate __s390_indirect_jump_r1 thunk */
++ if (test_facility(35)) {
++ /* exrl %r0,.+10 */
++ EMIT6_PCREL_RIL(0xc6000000, jit->prg + 10);
++ /* j . */
++ EMIT4_PCREL(0xa7f40000, 0);
++ /* br %r1 */
++ _EMIT2(0x07f1);
++ } else {
++ /* larl %r1,.+14 */
++ EMIT6_PCREL_RILB(0xc0000000, REG_1, jit->prg + 14);
++ /* ex 0,S390_lowcore.br_r1_tampoline */
++ EMIT4_DISP(0x44000000, REG_0, REG_0,
++ offsetof(struct lowcore, br_r1_trampoline));
++ /* j . */
++ EMIT4_PCREL(0xa7f40000, 0);
++ }
++ }
+ }
+
+ /*
+@@ -966,8 +1020,13 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i
+ /* lg %w1,<d(imm)>(%l) */
+ EMIT6_DISP_LH(0xe3000000, 0x0004, REG_W1, REG_0, REG_L,
+ EMIT_CONST_U64(func));
+- /* basr %r14,%w1 */
+- EMIT2(0x0d00, REG_14, REG_W1);
++ if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) {
++ /* brasl %r14,__s390_indirect_jump_r1 */
++ EMIT6_PCREL_RILB(0xc0050000, REG_14, jit->r1_thunk_ip);
++ } else {
++ /* basr %r14,%w1 */
++ EMIT2(0x0d00, REG_14, REG_W1);
++ }
+ /* lgr %b0,%r2: load return value into %b0 */
+ EMIT4(0xb9040000, BPF_REG_0, REG_2);
+ if ((jit->seen & SEEN_SKB) &&
+
diff --git a/patches.drivers/IB-core-Honor-port_num-while-resolving-GID-for-IB-li.patch b/patches.drivers/IB-core-Honor-port_num-while-resolving-GID-for-IB-li.patch
new file mode 100644
index 0000000000..1cd8ae8bbf
--- /dev/null
+++ b/patches.drivers/IB-core-Honor-port_num-while-resolving-GID-for-IB-li.patch
@@ -0,0 +1,58 @@
+From: Parav Pandit <parav@mellanox.com>
+Date: Tue, 13 Mar 2018 16:06:14 +0200
+Subject: IB/core: Honor port_num while resolving GID for IB link layer
+Patch-mainline: v4.17-rc1
+Git-commit: 563c4ba3bd2b8b0b21c65669ec2226b1cfa1138b
+References: bsc#1046306 FATE#322942
+
+ah_attr contains the port number to which cm_id is bound. However, while
+searching for GID table for matching GID entry, the port number is
+ignored.
+
+This could cause the wrong GID to be used when the ah_attr is converted to
+an AH.
+
+Reviewed-by: Daniel Jurgens <danielj@mellanox.com>
+Signed-off-by: Parav Pandit <parav@mellanox.com>
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/core/multicast.c | 24 +++++++++++-------------
+ 1 file changed, 11 insertions(+), 13 deletions(-)
+
+--- a/drivers/infiniband/core/multicast.c
++++ b/drivers/infiniband/core/multicast.c
+@@ -724,21 +724,19 @@ int ib_init_ah_from_mcmember(struct ib_d
+ {
+ int ret;
+ u16 gid_index;
+- u8 p;
+
+- if (rdma_protocol_roce(device, port_num)) {
+- ret = ib_find_cached_gid_by_port(device, &rec->port_gid,
+- gid_type, port_num,
+- ndev,
+- &gid_index);
+- } else if (rdma_protocol_ib(device, port_num)) {
+- ret = ib_find_cached_gid(device, &rec->port_gid,
+- IB_GID_TYPE_IB, NULL, &p,
+- &gid_index);
+- } else {
+- ret = -EINVAL;
+- }
++ /* GID table is not based on the netdevice for IB link layer,
++ * so ignore ndev during search.
++ */
++ if (rdma_protocol_ib(device, port_num))
++ ndev = NULL;
++ else if (!rdma_protocol_roce(device, port_num))
++ return -EINVAL;
+
++ ret = ib_find_cached_gid_by_port(device, &rec->port_gid,
++ gid_type, port_num,
++ ndev,
++ &gid_index);
+ if (ret)
+ return ret;
+
diff --git a/patches.drivers/IB-core-Make-ib_mad_client_id-atomic.patch b/patches.drivers/IB-core-Make-ib_mad_client_id-atomic.patch
new file mode 100644
index 0000000000..c810342302
--- /dev/null
+++ b/patches.drivers/IB-core-Make-ib_mad_client_id-atomic.patch
@@ -0,0 +1,51 @@
+From: =?UTF-8?q?H=C3=A5kon=20Bugge?= <haakon.bugge@oracle.com>
+Date: Wed, 18 Apr 2018 16:24:50 +0200
+Subject: IB/core: Make ib_mad_client_id atomic
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+Patch-mainline: v4.17-rc4
+Git-commit: db82476f37413eaeff5f836a9d8b022d6544accf
+References: bsc#1046306 FATE#322942
+
+Currently, the kernel protects access to the agent ID allocator on a per
+port basis using a spinlock, so it is impossible for two apps/threads on
+the same port to get the same TID, but it is entirely possible for two
+threads on different ports to end up with the same TID.
+
+As this can be confusing (regardless of it being legal according to the
+IB Spec 1.3, C13-18.1.1, in section 13.4.6.4 - TransactionID usage),
+and as the rdma-core user space API for /dev/umad devices implies unique
+TIDs even across ports, make the TID an atomic type so that no two
+allocations, regardless of port number, will be the same.
+
+Signed-off-by: Håkon Bugge <haakon.bugge@oracle.com>
+Reviewed-by: Jack Morgenstein <jackm@dev.mellanox.co.il>
+Reviewed-by: Ira Weiny <ira.weiny@intel.com>
+Reviewed-by: Zhu Yanjun <yanjun.zhu@oracle.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/core/mad.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/infiniband/core/mad.c
++++ b/drivers/infiniband/core/mad.c
+@@ -60,7 +60,7 @@ module_param_named(recv_queue_size, mad_
+ MODULE_PARM_DESC(recv_queue_size, "Size of receive queue in number of work requests");
+
+ static struct list_head ib_mad_port_list;
+-static u32 ib_mad_client_id = 0;
++static atomic_t ib_mad_client_id = ATOMIC_INIT(0);
+
+ /* Port list lock */
+ static DEFINE_SPINLOCK(ib_mad_port_list_lock);
+@@ -378,7 +378,7 @@ struct ib_mad_agent *ib_register_mad_age
+ }
+
+ spin_lock_irqsave(&port_priv->reg_lock, flags);
+- mad_agent_priv->agent.hi_tid = ++ib_mad_client_id;
++ mad_agent_priv->agent.hi_tid = atomic_inc_return(&ib_mad_client_id);
+
+ /*
+ * Make sure MAD registration (if supplied)
diff --git a/patches.drivers/IB-hfi1-Fix-user-context-tail-allocation-for-DMA_RTA.patch b/patches.drivers/IB-hfi1-Fix-user-context-tail-allocation-for-DMA_RTA.patch
new file mode 100644
index 0000000000..5972e922a5
--- /dev/null
+++ b/patches.drivers/IB-hfi1-Fix-user-context-tail-allocation-for-DMA_RTA.patch
@@ -0,0 +1,120 @@
+From: Mike Marciniszyn <mike.marciniszyn@intel.com>
+Date: Thu, 31 May 2018 11:30:09 -0700
+Subject: IB/hfi1: Fix user context tail allocation for DMA_RTAIL
+Patch-mainline: v4.18-rc1
+Git-commit: 1bc0299d976e000ececc6acd76e33b4582646cb7
+References: bsc#1060463 FATE#323043
+
+The following code fails to allocate a buffer for the
+tail address that the hardware DMAs into when the user
+context DMA_RTAIL is set.
+
+if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL)) {
+ rcd->rcvhdrtail_kvaddr = dma_zalloc_coherent(
+ &dd->pcidev->dev, PAGE_SIZE, &dma_hdrqtail,
+ gfp_flags);
+ if (!rcd->rcvhdrtail_kvaddr)
+ goto bail_free;
+ rcd->rcvhdrqtailaddr_dma = dma_hdrqtail;
+}
+
+So the rcvhdrtail_kvaddr would then be NULL.
+
+The mmap logic fails to check for a NULL rcvhdrtail_kvaddr.
+
+The fix is to test for both user and kernel DMA_TAIL options
+during the allocation as well as testing for a NULL
+rcvhdrtail_kvaddr during the mmap processing.
+
+Additionally, all downstream testing of the capmask for DMA_RTAIL
+have been eliminated in favor of testing rcvhdrtail_kvaddr.
+
+Cc: <stable@vger.kernel.org> # 4.9.x
+Reviewed-by: Michael J. Ruhl <michael.j.ruhl@intel.com>
+Signed-off-by: Mike Marciniszyn <mike.marciniszyn@intel.com>
+Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/hfi1/chip.c | 8 ++++----
+ drivers/infiniband/hw/hfi1/file_ops.c | 2 +-
+ drivers/infiniband/hw/hfi1/init.c | 9 ++++-----
+ 3 files changed, 9 insertions(+), 10 deletions(-)
+
+--- a/drivers/infiniband/hw/hfi1/chip.c
++++ b/drivers/infiniband/hw/hfi1/chip.c
+@@ -6841,7 +6841,7 @@ static void rxe_kernel_unfreeze(struct h
+ }
+ rcvmask = HFI1_RCVCTRL_CTXT_ENB;
+ /* HFI1_RCVCTRL_TAILUPD_[ENB|DIS] needs to be set explicitly */
+- rcvmask |= HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL) ?
++ rcvmask |= rcd->rcvhdrtail_kvaddr ?
+ HFI1_RCVCTRL_TAILUPD_ENB : HFI1_RCVCTRL_TAILUPD_DIS;
+ hfi1_rcvctrl(dd, rcvmask, rcd);
+ hfi1_rcd_put(rcd);
+@@ -8367,7 +8367,7 @@ static inline int check_packet_present(s
+ u32 tail;
+ int present;
+
+- if (!HFI1_CAP_IS_KSET(DMA_RTAIL))
++ if (!rcd->rcvhdrtail_kvaddr)
+ present = (rcd->seq_cnt ==
+ rhf_rcv_seq(rhf_to_cpu(get_rhf_addr(rcd))));
+ else /* is RDMA rtail */
+@@ -11839,7 +11839,7 @@ void hfi1_rcvctrl(struct hfi1_devdata *d
+ /* reset the tail and hdr addresses, and sequence count */
+ write_kctxt_csr(dd, ctxt, RCV_HDR_ADDR,
+ rcd->rcvhdrq_dma);
+- if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL))
++ if (rcd->rcvhdrtail_kvaddr)
+ write_kctxt_csr(dd, ctxt, RCV_HDR_TAIL_ADDR,
+ rcd->rcvhdrqtailaddr_dma);
+ rcd->seq_cnt = 1;
+@@ -11919,7 +11919,7 @@ void hfi1_rcvctrl(struct hfi1_devdata *d
+ rcvctrl |= RCV_CTXT_CTRL_INTR_AVAIL_SMASK;
+ if (op & HFI1_RCVCTRL_INTRAVAIL_DIS)
+ rcvctrl &= ~RCV_CTXT_CTRL_INTR_AVAIL_SMASK;
+- if (op & HFI1_RCVCTRL_TAILUPD_ENB && rcd->rcvhdrqtailaddr_dma)
++ if ((op & HFI1_RCVCTRL_TAILUPD_ENB) && rcd->rcvhdrtail_kvaddr)
+ rcvctrl |= RCV_CTXT_CTRL_TAIL_UPD_SMASK;
+ if (op & HFI1_RCVCTRL_TAILUPD_DIS) {
+ /* See comment on RcvCtxtCtrl.TailUpd above */
+--- a/drivers/infiniband/hw/hfi1/file_ops.c
++++ b/drivers/infiniband/hw/hfi1/file_ops.c
+@@ -558,7 +558,7 @@ static int hfi1_file_mmap(struct file *f
+ ret = -EINVAL;
+ goto done;
+ }
+- if (flags & VM_WRITE) {
++ if ((flags & VM_WRITE) || !uctxt->rcvhdrtail_kvaddr) {
+ ret = -EPERM;
+ goto done;
+ }
+--- a/drivers/infiniband/hw/hfi1/init.c
++++ b/drivers/infiniband/hw/hfi1/init.c
+@@ -1847,7 +1847,6 @@ int hfi1_create_rcvhdrq(struct hfi1_devd
+ u64 reg;
+
+ if (!rcd->rcvhdrq) {
+- dma_addr_t dma_hdrqtail;
+ gfp_t gfp_flags;
+
+ /*
+@@ -1872,13 +1871,13 @@ int hfi1_create_rcvhdrq(struct hfi1_devd
+ goto bail;
+ }
+
+- if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL)) {
++ if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL) ||
++ HFI1_CAP_UGET_MASK(rcd->flags, DMA_RTAIL)) {
+ rcd->rcvhdrtail_kvaddr = dma_zalloc_coherent(
+- &dd->pcidev->dev, PAGE_SIZE, &dma_hdrqtail,
+- gfp_flags);
++ &dd->pcidev->dev, PAGE_SIZE,
++ &rcd->rcvhdrqtailaddr_dma, gfp_flags);
+ if (!rcd->rcvhdrtail_kvaddr)
+ goto bail_free;
+- rcd->rcvhdrqtailaddr_dma = dma_hdrqtail;
+ }
+
+ rcd->rcvhdrq_size = amt;
diff --git a/patches.drivers/IB-isert-Fix-for-lib-dma_debug-check_sync-warning.patch b/patches.drivers/IB-isert-Fix-for-lib-dma_debug-check_sync-warning.patch
new file mode 100644
index 0000000000..e2cb3c27f6
--- /dev/null
+++ b/patches.drivers/IB-isert-Fix-for-lib-dma_debug-check_sync-warning.patch
@@ -0,0 +1,111 @@
+From: Alex Estrin <alex.estrin@intel.com>
+Date: Tue, 15 May 2018 18:31:39 -0700
+Subject: IB/isert: Fix for lib/dma_debug check_sync warning
+Patch-mainline: v4.18-rc1
+Git-commit: 763b69654bfb88ea3230d015e7d755ee8339f8ee
+References: bsc#1046306 FATE#322942
+
+The following error message occurs on a target host in a debug build
+during session login:
+
+[ 3524.411874] WARNING: CPU: 5 PID: 12063 at lib/dma-debug.c:1207 check_sync+0x4ec/0x5b0
+[ 3524.421057] infiniband hfi1_0: DMA-API: device driver tries to sync DMA memory it has not allocated [device address=0x0000000000000000] [size=76 bytes]
+......snip .....
+
+[ 3524.535846] CPU: 5 PID: 12063 Comm: iscsi_np Kdump: loaded Not tainted 3.10.0-862.el7.x86_64.debug #1
+[ 3524.546764] Hardware name: Dell Inc. PowerEdge R430/03XKDV, BIOS 1.2.6 06/08/2015
+[ 3524.555740] Call Trace:
+[ 3524.559102] [<ffffffffa5fe915b>] dump_stack+0x19/0x1b
+[ 3524.565477] [<ffffffffa58a2f58>] __warn+0xd8/0x100
+[ 3524.571557] [<ffffffffa58a2fdf>] warn_slowpath_fmt+0x5f/0x80
+[ 3524.578610] [<ffffffffa5bf5b8c>] check_sync+0x4ec/0x5b0
+[ 3524.585177] [<ffffffffa58efc3f>] ? set_cpus_allowed_ptr+0x5f/0x1c0
+[ 3524.592812] [<ffffffffa5bf5cd0>] debug_dma_sync_single_for_cpu+0x80/0x90
+[ 3524.601029] [<ffffffffa586add3>] ? x2apic_send_IPI_mask+0x13/0x20
+[ 3524.608574] [<ffffffffa585ee1b>] ? native_smp_send_reschedule+0x5b/0x80
+[ 3524.616699] [<ffffffffa58e9b76>] ? resched_curr+0xf6/0x140
+[ 3524.623567] [<ffffffffc0879af0>] isert_create_send_desc.isra.26+0xe0/0x110 [ib_isert]
+[ 3524.633060] [<ffffffffc087af95>] isert_put_login_tx+0x55/0x8b0 [ib_isert]
+[ 3524.641383] [<ffffffffa58ef114>] ? try_to_wake_up+0x1a4/0x430
+[ 3524.648561] [<ffffffffc098cfed>] iscsi_target_do_tx_login_io+0xdd/0x230 [iscsi_target_mod]
+[ 3524.658557] [<ffffffffc098d827>] iscsi_target_do_login+0x1a7/0x600 [iscsi_target_mod]
+[ 3524.668084] [<ffffffffa59f9bc9>] ? kstrdup+0x49/0x60
+[ 3524.674420] [<ffffffffc098e976>] iscsi_target_start_negotiation+0x56/0xc0 [iscsi_target_mod]
+[ 3524.684656] [<ffffffffc098c2ee>] __iscsi_target_login_thread+0x90e/0x1070 [iscsi_target_mod]
+[ 3524.694901] [<ffffffffc098ca50>] ? __iscsi_target_login_thread+0x1070/0x1070 [iscsi_target_mod]
+[ 3524.705446] [<ffffffffc098ca50>] ? __iscsi_target_login_thread+0x1070/0x1070 [iscsi_target_mod]
+[ 3524.715976] [<ffffffffc098ca78>] iscsi_target_login_thread+0x28/0x60 [iscsi_target_mod]
+[ 3524.725739] [<ffffffffa58d60ff>] kthread+0xef/0x100
+[ 3524.732007] [<ffffffffa58d6010>] ? insert_kthread_work+0x80/0x80
+[ 3524.739540] [<ffffffffa5fff1b7>] ret_from_fork_nospec_begin+0x21/0x21
+[ 3524.747558] [<ffffffffa58d6010>] ? insert_kthread_work+0x80/0x80
+[ 3524.755088] ---[ end trace 23f8bf9238bd1ed8 ]---
+[ 3595.510822] iSCSI/iqn.1994-05.com.redhat:537fa56299: Unsupported SCSI Opcode 0xa3, sending CHECK_CONDITION.
+
+The code calls dma_sync on login_tx_desc->dma_addr prior to initializing it
+with dma-mapped address.
+login_tx_desc is a part of iser_conn structure and is used only once
+during login negotiation, so the issue is fixed by eliminating
+dma_sync call for this buffer using a special case routine.
+
+Cc: <stable@vger.kernel.org>
+Reviewed-by: Mike Marciniszyn <mike.marciniszyn@intel.com>
+Reviewed-by: Don Dutile <ddutile@redhat.com>
+Signed-off-by: Alex Estrin <alex.estrin@intel.com>
+Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/ulp/isert/ib_isert.c | 26 +++++++++++++++++---------
+ 1 file changed, 17 insertions(+), 9 deletions(-)
+
+--- a/drivers/infiniband/ulp/isert/ib_isert.c
++++ b/drivers/infiniband/ulp/isert/ib_isert.c
+@@ -885,15 +885,9 @@ isert_login_post_send(struct isert_conn
+ }
+
+ static void
+-isert_create_send_desc(struct isert_conn *isert_conn,
+- struct isert_cmd *isert_cmd,
+- struct iser_tx_desc *tx_desc)
++__isert_create_send_desc(struct isert_device *device,
++ struct iser_tx_desc *tx_desc)
+ {
+- struct isert_device *device = isert_conn->device;
+- struct ib_device *ib_dev = device->ib_device;
+-
+- ib_dma_sync_single_for_cpu(ib_dev, tx_desc->dma_addr,
+- ISER_HEADERS_LEN, DMA_TO_DEVICE);
+
+ memset(&tx_desc->iser_header, 0, sizeof(struct iser_ctrl));
+ tx_desc->iser_header.flags = ISCSI_CTRL;
+@@ -906,6 +900,20 @@ isert_create_send_desc(struct isert_conn
+ }
+ }
+
++static void
++isert_create_send_desc(struct isert_conn *isert_conn,
++ struct isert_cmd *isert_cmd,
++ struct iser_tx_desc *tx_desc)
++{
++ struct isert_device *device = isert_conn->device;
++ struct ib_device *ib_dev = device->ib_device;
++
++ ib_dma_sync_single_for_cpu(ib_dev, tx_desc->dma_addr,
++ ISER_HEADERS_LEN, DMA_TO_DEVICE);
++
++ __isert_create_send_desc(device, tx_desc);
++}
++
+ static int
+ isert_init_tx_hdrs(struct isert_conn *isert_conn,
+ struct iser_tx_desc *tx_desc)
+@@ -993,7 +1001,7 @@ isert_put_login_tx(struct iscsi_conn *co
+ struct iser_tx_desc *tx_desc = &isert_conn->login_tx_desc;
+ int ret;
+
+- isert_create_send_desc(isert_conn, NULL, tx_desc);
++ __isert_create_send_desc(device, tx_desc);
+
+ memcpy(&tx_desc->iscsi_header, &login->rsp[0],
+ sizeof(struct iscsi_hdr));
diff --git a/patches.drivers/IB-rxe-Fix-for-oops-in-rxe_register_device-on-ppc64l.patch b/patches.drivers/IB-rxe-Fix-for-oops-in-rxe_register_device-on-ppc64l.patch
new file mode 100644
index 0000000000..d6b5d3513b
--- /dev/null
+++ b/patches.drivers/IB-rxe-Fix-for-oops-in-rxe_register_device-on-ppc64l.patch
@@ -0,0 +1,78 @@
+From: Mikhail Malygin <mikhail@malygin.me>
+Date: Mon, 2 Apr 2018 12:26:59 +0300
+Subject: IB/rxe: Fix for oops in rxe_register_device on ppc64le arch
+Patch-mainline: v4.17-rc1
+Git-commit: efc365e7290d040fbd43f60b0e97653489a739d4
+References: bsc#1046306 FATE#322942
+
+On ppc64le arch rxe_add command causes oops in kernel log:
+
+[ 92.495140] Oops: Kernel access of bad area, sig: 11 [#1]
+[ 92.499710] SMP NR_CPUS=2048 NUMA pSeries
+[ 92.499792] Modules linked in: ipt_MASQUERADE(E) nf_nat_masquerade_ipv4(E) nf_conntrack_netlink(E) nfnetlink(E) xfrm_user(E) iptable
+_nat(E) nf_conntrack_ipv4(E) nf_defrag_ipv4(E) nf_nat_ipv4(E) xt_addrtype(E) iptable_filter(E) ip_tables(E) xt_conntrack(E) x_tables(E)
+ nf_nat(E) nf_conntrack(E) br_netfilter(E) bridge(E) stp(E) llc(E) overlay(E) af_packet(E) rpcrdma(E) ib_isert(E) iscsi_target_mod(E) i
+b_iser(E) libiscsi(E) ib_srpt(E) target_core_mod(E) ib_srp(E) ib_ipoib(E) rdma_ucm(E) ib_ucm(E) ib_uverbs(E) ib_umad(E) bochs_drm(E) tt
+m(E) drm_kms_helper(E) syscopyarea(E) sysfillrect(E) sysimgblt(E) fb_sys_fops(E) drm(E) agpgart(E) virtio_rng(E) virtio_console(E) rtc_
+generic(E) dm_ec(OEN) ttln_rdma(OEN) rdma_cm(E) configfs(E) iw_cm(E) ib_cm(E) rdma_rxe(E) ip6_udp_tunnel(E) udp_tunnel(E) ib_core(E) ql
+a2xxx(E)
+[ 92.499832] scsi_transport_fc(E) nvme_fc(E) nvme_fabrics(E) nvme_core(E) ipmi_watchdog(E) ipmi_ssif(E) ipmi_poweroff(E) ipmi_powernv(EX) ipmi_devintf(E) ipmi_msghandler(E) dummy(E) ext4(E) crc16(E) jbd2(E) mbcache(E) dm_service_time(E) scsi_transport_iscsi(E) sd_mod(E) sr_mod(E) cdrom(E) hid_generic(E) usbhid(E) virtio_blk(E) virtio_scsi(E) virtio_net(E) ibmvscsi(EX) scsi_transport_srp(E) xhci_pci(E) xhci_hcd(E) usbcore(E) usb_common(E) virtio_pci(E) virtio_ring(E) virtio(E) sunrpc(E) dm_mirror(E) dm_region_hash(E) dm_log(E) sg(E) dm_multipath(E) dm_mod(E) scsi_dh_rdac(E) scsi_dh_emc(E) scsi_dh_alua(E) scsi_mod(E) autofs4(E)
+[ 92.499834] Supported: No, Unsupported modules are loaded
+[ 92.499839] CPU: 3 PID: 5576 Comm: sh Tainted: G OE NX 4.4.120-ttln.17-default #1
+[ 92.499841] task: c0000000afe8a490 ti: c0000000beba8000 task.ti: c0000000beba8000
+[ 92.499842] NIP: c00000000008ba3c LR: c000000000027644 CTR: c00000000008ba10
+[ 92.499844] REGS: c0000000bebab750 TRAP: 0300 Tainted: G OE NX (4.4.120-ttln.17-default)
+[ 92.499850] MSR: 8000000000009033 <SF,EE,ME,IR,DR,RI,LE> CR: 28424428 XER: 20000000
+[ 92.499871] CFAR: 0000000000002424 DAR: 0000000000000208 DSISR: 40000000 SOFTE: 1
+ GPR00: c000000000027644 c0000000bebab9d0 c000000000f09700 0000000000000000
+ GPR04: d0000000043d7192 0000000000000002 000000000000001a fffffffffffffffe
+ GPR08: 000000000000009c c00000000008ba10 d0000000043e5848 d0000000043d3828
+ GPR12: c00000000008ba10 c000000007a02400 0000000010062e38 0000010020388860
+ GPR16: 0000000000000000 0000000000000000 00000100203885f0 00000000100f6c98
+ GPR20: c0000000b3f1fcc0 c0000000b3f1fc48 c0000000b3f1fbd0 c0000000b3f1fb58
+ GPR24: c0000000b3f1fae0 c0000000b3f1fa68 00000000000005dc c0000000b3f1f9f0
+ GPR28: d0000000043e5848 c0000000b3f1f900 c0000000b3f1f320 c0000000b3f1f000
+[ 92.499881] NIP [c00000000008ba3c] dma_get_required_mask_pSeriesLP+0x2c/0x1a0
+[ 92.499885] LR [c000000000027644] dma_get_required_mask+0x44/0xac
+[ 92.499886] Call Trace:
+[ 92.499891] [c0000000bebab9d0] [c0000000bebaba30] 0xc0000000bebaba30 (unreliable)
+[ 92.499894] [c0000000bebaba10] [c000000000027644] dma_get_required_mask+0x44/0xac
+[ 92.499904] [c0000000bebaba30] [d0000000043cb4b4] rxe_register_device+0xc4/0x430 [rdma_rxe]
+[ 92.499910] [c0000000bebabab0] [d0000000043c06c8] rxe_add+0x448/0x4e0 [rdma_rxe]
+[ 92.499915] [c0000000bebabb30] [d0000000043d28dc] rxe_net_add+0x4c/0xf0 [rdma_rxe]
+[ 92.499921] [c0000000bebabb60] [d0000000043d305c] rxe_param_set_add+0x6c/0x1ac [rdma_rxe]
+[ 92.499924] [c0000000bebabbf0] [c0000000000e78c0] param_attr_store+0xa0/0x180
+[ 92.499927] [c0000000bebabc70] [c0000000000e6448] module_attr_store+0x48/0x70
+[ 92.499932] [c0000000bebabc90] [c000000000391f60] sysfs_kf_write+0x70/0xb0
+[ 92.499935] [c0000000bebabcb0] [c000000000390f1c] kernfs_fop_write+0x18c/0x1e0
+[ 92.499939] [c0000000bebabd00] [c0000000002e22ac] __vfs_write+0x4c/0x1d0
+[ 92.499942] [c0000000bebabd90] [c0000000002e2f94] vfs_write+0xc4/0x200
+[ 92.499945] [c0000000bebabde0] [c0000000002e488c] SyS_write+0x6c/0x110
+[ 92.499948] [c0000000bebabe30] [c000000000009384] system_call+0x38/0xe4
+[ 92.499949] Instruction dump:
+[ 92.499954] 4e800020 3c4c00e8 3842dcf0 7c0802a6 f8010010 60000000 7c0802a6 fba1ffe8
+[ 92.499958] fbc1fff0 fbe1fff8 f8010010 f821ffc1 <e9230208> 7c7e1b78 2fa90000 419e0078
+[ 92.499962] ---[ end trace bed077e15eb420cf ]---
+
+It fails in dma_get_required_mask, that has ppc-specific implementation,
+and fail if provided device argument is NULL
+
+Signed-off-by: Mikhail Malygin <mikhail@malygin.me>
+Reviewed-by: Yonatan Cohen <yonatanc@mellanox.com>
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/sw/rxe/rxe_verbs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
++++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
+@@ -1207,7 +1207,7 @@ int rxe_register_device(struct rxe_dev *
+ rxe->ndev->dev_addr);
+ dev->dev.dma_ops = &dma_virt_ops;
+ dma_coerce_mask_and_coherent(&dev->dev,
+- dma_get_required_mask(dev->dev.parent));
++ dma_get_required_mask(&dev->dev));
+
+ dev->uverbs_abi_ver = RXE_UVERBS_ABI_VERSION;
+ dev->uverbs_cmd_mask = BIT_ULL(IB_USER_VERBS_CMD_GET_CONTEXT)
diff --git a/patches.drivers/IB-rxe-add-RXE_START_MASK-for-rxe_opcode-IB_OPCODE_R.patch b/patches.drivers/IB-rxe-add-RXE_START_MASK-for-rxe_opcode-IB_OPCODE_R.patch
new file mode 100644
index 0000000000..815f1138bb
--- /dev/null
+++ b/patches.drivers/IB-rxe-add-RXE_START_MASK-for-rxe_opcode-IB_OPCODE_R.patch
@@ -0,0 +1,36 @@
+From: Jianchao Wang <jianchao.w.wang@oracle.com>
+Date: Thu, 26 Apr 2018 11:52:39 +0800
+Subject: IB/rxe: add RXE_START_MASK for rxe_opcode IB_OPCODE_RC_SEND_ONLY_INV
+Patch-mainline: v4.17-rc4
+Git-commit: 2da36d44a9d54a2c6e1f8da1f7ccc26b0bc6cfec
+References: bsc#1046306 FATE#322942
+
+w/o RXE_START_MASK, the last_psn of IB_OPCODE_RC_SEND_ONLY_INV
+will not be updated in update_wqe_psn, and the corresponding
+wqe will not be acked in rxe_completer due to its last_psn is
+zero. Finally, the other wqe will also not be able to be acked,
+because the wqe of IB_OPCODE_RC_SEND_ONLY_INV with last_psn 0
+is still there. This causes large amount of io timeout when
+nvmeof is over rxe.
+
+Add RXE_START_MASK for IB_OPCODE_RC_SEND_ONLY_INV to fix this.
+
+Signed-off-by: Jianchao Wang <jianchao.w.wang@oracle.com>
+Reviewed-by: Zhu Yanjun <yanjun.zhu@oracle.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/sw/rxe/rxe_opcode.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/infiniband/sw/rxe/rxe_opcode.c
++++ b/drivers/infiniband/sw/rxe/rxe_opcode.c
+@@ -390,7 +390,7 @@ struct rxe_opcode_info rxe_opcode[RXE_NU
+ .name = "IB_OPCODE_RC_SEND_ONLY_INV",
+ .mask = RXE_IETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+ | RXE_COMP_MASK | RXE_RWR_MASK | RXE_SEND_MASK
+- | RXE_END_MASK,
++ | RXE_END_MASK | RXE_START_MASK,
+ .length = RXE_BTH_BYTES + RXE_IETH_BYTES,
+ .offset = {
+ [RXE_BTH] = 0,
diff --git a/patches.drivers/IB-rxe-avoid-double-kfree_skb.patch b/patches.drivers/IB-rxe-avoid-double-kfree_skb.patch
new file mode 100644
index 0000000000..8a31bbc175
--- /dev/null
+++ b/patches.drivers/IB-rxe-avoid-double-kfree_skb.patch
@@ -0,0 +1,94 @@
+From: Zhu Yanjun <yanjun.zhu@oracle.com>
+Date: Thu, 26 Apr 2018 00:41:10 -0400
+Subject: IB/rxe: avoid double kfree_skb
+Patch-mainline: v4.17-rc4
+Git-commit: 9fd4350ba8953804f05215999e11a6cfb7b41f2b
+References: bsc#1046306 FATE#322942
+
+When skb is sent, it will pass the following functions in soft roce.
+
+rxe_send [rdma_rxe]
+ ip_local_out
+ __ip_local_out
+ ip_output
+ ip_finish_output
+ ip_finish_output2
+ dev_queue_xmit
+ __dev_queue_xmit
+ dev_hard_start_xmit
+
+In the above functions, if error occurs in the above functions or
+iptables rules drop skb after ip_local_out, kfree_skb will be called.
+So it is not necessary to call kfree_skb in soft roce module again.
+Or else crash will occur.
+
+The steps to reproduce:
+
+ server client
+ --------- ---------
+ |1.1.1.1|<----rxe-channel--->|1.1.1.2|
+ --------- ---------
+
+On server: rping -s -a 1.1.1.1 -v -C 10000 -S 512
+On client: rping -c -a 1.1.1.1 -v -C 10000 -S 512
+
+The kernel configs CONFIG_DEBUG_KMEMLEAK and
+CONFIG_DEBUG_OBJECTS are enabled on both server and client.
+
+When rping runs, run the following command in server:
+
+iptables -I OUTPUT -p udp --dport 4791 -j DROP
+
+Without this patch, crash will occur.
+
+CC: Srinivas Eeda <srinivas.eeda@oracle.com>
+CC: Junxiao Bi <junxiao.bi@oracle.com>
+Signed-off-by: Zhu Yanjun <yanjun.zhu@oracle.com>
+Reviewed-by: Yuval Shaia <yuval.shaia@oracle.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/sw/rxe/rxe_req.c | 1 -
+ drivers/infiniband/sw/rxe/rxe_resp.c | 6 +-----
+ 2 files changed, 1 insertion(+), 6 deletions(-)
+
+--- a/drivers/infiniband/sw/rxe/rxe_req.c
++++ b/drivers/infiniband/sw/rxe/rxe_req.c
+@@ -728,7 +728,6 @@ next_wqe:
+ rollback_state(wqe, qp, &rollback_wqe, rollback_psn);
+
+ if (ret == -EAGAIN) {
+- kfree_skb(skb);
+ rxe_run_task(&qp->req.task, 1);
+ goto exit;
+ }
+--- a/drivers/infiniband/sw/rxe/rxe_resp.c
++++ b/drivers/infiniband/sw/rxe/rxe_resp.c
+@@ -742,7 +742,6 @@ static enum resp_states read_reply(struc
+ err = rxe_xmit_packet(rxe, qp, &ack_pkt, skb);
+ if (err) {
+ pr_err("Failed sending RDMA reply.\n");
+- kfree_skb(skb);
+ return RESPST_ERR_RNR;
+ }
+
+@@ -955,10 +954,8 @@ static int send_ack(struct rxe_qp *qp, s
+ }
+
+ err = rxe_xmit_packet(rxe, qp, &ack_pkt, skb);
+- if (err) {
++ if (err)
+ pr_err_ratelimited("Failed sending ack\n");
+- kfree_skb(skb);
+- }
+
+ err1:
+ return err;
+@@ -1151,7 +1148,6 @@ static enum resp_states duplicate_reques
+ if (rc) {
+ pr_err("Failed resending result. This flow is not handled - skb ignored\n");
+ rxe_drop_ref(qp);
+- kfree_skb(skb_copy);
+ rc = RESPST_CLEANUP;
+ goto out;
+ }
diff --git a/patches.drivers/IB-uverbs-Fix-possible-oops-with-duplicate-ioctl-att.patch b/patches.drivers/IB-uverbs-Fix-possible-oops-with-duplicate-ioctl-att.patch
new file mode 100644
index 0000000000..3ae4c0f618
--- /dev/null
+++ b/patches.drivers/IB-uverbs-Fix-possible-oops-with-duplicate-ioctl-att.patch
@@ -0,0 +1,39 @@
+From: Matan Barak <matanb@mellanox.com>
+Date: Tue, 13 Feb 2018 12:18:35 +0200
+Subject: IB/uverbs: Fix possible oops with duplicate ioctl attributes
+Patch-mainline: v4.16-rc3
+Git-commit: 4d39a959bc1f3d164b5a54147fdeb19f84b1ed58
+References: bsc#1046306 FATE#322942
+
+If the same attribute is listed twice by the user in the ioctl attribute
+list then error unwind can cause the kernel to deref garbage.
+
+This happens when an object with WRITE access is sent twice. The second
+parse properly fails but corrupts the state required for the error unwind
+it triggers.
+
+Fixing this by making duplicates in the attribute list invalid. This is
+not something we need to support.
+
+The ioctl interface is currently recommended to be disabled in kConfig.
+
+Signed-off-by: Matan Barak <matanb@mellanox.com>
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/core/uverbs_ioctl.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/infiniband/core/uverbs_ioctl.c
++++ b/drivers/infiniband/core/uverbs_ioctl.c
+@@ -59,6 +59,9 @@ static int uverbs_process_attr(struct ib
+ return 0;
+ }
+
++ if (test_bit(attr_id, attr_bundle_h->valid_bitmap))
++ return -EINVAL;
++
+ spec = &attr_spec_bucket->attrs[attr_id];
+ e = &elements[attr_id];
+ e->uattr = uattr_ptr;
diff --git a/patches.drivers/RDMA-cma-Do-not-query-GID-during-QP-state-transition.patch b/patches.drivers/RDMA-cma-Do-not-query-GID-during-QP-state-transition.patch
new file mode 100644
index 0000000000..fb931ac9c1
--- /dev/null
+++ b/patches.drivers/RDMA-cma-Do-not-query-GID-during-QP-state-transition.patch
@@ -0,0 +1,52 @@
+From: Parav Pandit <parav@mellanox.com>
+Date: Wed, 2 May 2018 13:18:59 +0300
+Subject: RDMA/cma: Do not query GID during QP state transition to RTR
+Patch-mainline: v4.17-rc4
+Git-commit: 9aa169213d1166d30ae357a44abbeae93459339d
+References: bsc#1046306 FATE#322942
+
+When commit [1] was added, SGID was queried to derive the SMAC address.
+Then, later on during a refactor [2], SMAC was no longer needed. However,
+the now useless GID query remained. Then during additional code changes
+later on, the GID query was being done in such a way that it caused iWARP
+queries to start breaking. Remove the useless GID query and resolve the
+iWARP breakage at the same time.
+
+This is discussed in [3].
+
+[1] commit dd5f03beb4f7 ("IB/core: Ethernet L2 attributes in verbs/cm structures")
+[2] commit 5c266b2304fb ("IB/cm: Remove the usage of smac and vid of qp_attr and cm_av")
+[3] https://www.spinics.net/lists/linux-rdma/msg63951.html
+
+Suggested-by: Shiraz Saleem <shiraz.saleem@intel.com>
+Signed-off-by: Parav Pandit <parav@mellanox.com>
+Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/core/cma.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+--- a/drivers/infiniband/core/cma.c
++++ b/drivers/infiniband/core/cma.c
+@@ -900,7 +900,6 @@ static int cma_modify_qp_rtr(struct rdma
+ {
+ struct ib_qp_attr qp_attr;
+ int qp_attr_mask, ret;
+- union ib_gid sgid;
+
+ mutex_lock(&id_priv->qp_mutex);
+ if (!id_priv->id.qp) {
+@@ -923,12 +922,6 @@ static int cma_modify_qp_rtr(struct rdma
+ if (ret)
+ goto out;
+
+- ret = ib_query_gid(id_priv->id.device, id_priv->id.port_num,
+- rdma_ah_read_grh(&qp_attr.ah_attr)->sgid_index,
+- &sgid, NULL);
+- if (ret)
+- goto out;
+-
+ BUG_ON(id_priv->cma_dev->device != id_priv->id.device);
+
+ if (conn_param)
diff --git a/patches.drivers/RDMA-mlx5-Fix-NULL-dereference-while-accessing-XRC_T.patch b/patches.drivers/RDMA-mlx5-Fix-NULL-dereference-while-accessing-XRC_T.patch
new file mode 100644
index 0000000000..ace27e6fcf
--- /dev/null
+++ b/patches.drivers/RDMA-mlx5-Fix-NULL-dereference-while-accessing-XRC_T.patch
@@ -0,0 +1,74 @@
+From: Leon Romanovsky <leonro@mellanox.com>
+Date: Sun, 11 Mar 2018 13:51:32 +0200
+Subject: RDMA/mlx5: Fix NULL dereference while accessing XRC_TGT QPs
+Patch-mainline: v4.17-rc1
+Git-commit: 75a4598209cbe45540baa316c3b51d9db222e96e
+References: bsc#1046305 FATE#322943
+
+mlx5 modify_qp() relies on FW that the error will be thrown if wrong
+state is supplied. The missing check in FW causes the following crash
+while using XRC_TGT QPs.
+
+[ 14.769632] BUG: unable to handle kernel NULL pointer dereference at (null)
+[ 14.771085] IP: mlx5_ib_modify_qp+0xf60/0x13f0
+[ 14.771894] PGD 800000001472e067 P4D 800000001472e067 PUD 14529067 PMD 0
+[ 14.773126] Oops: 0002 [#1] SMP PTI
+[ 14.773763] CPU: 0 PID: 365 Comm: ubsan Not tainted 4.16.0-rc1-00038-g8151138c0793 #119
+[ 14.775192] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014
+[ 14.777522] RIP: 0010:mlx5_ib_modify_qp+0xf60/0x13f0
+[ 14.778417] RSP: 0018:ffffbf48001c7bd8 EFLAGS: 00010246
+[ 14.779346] RAX: 0000000000000000 RBX: ffff9a8f9447d400 RCX: 0000000000000000
+[ 14.780643] RDX: 0000000000000000 RSI: 000000000000000a RDI: 0000000000000000
+[ 14.781930] RBP: 0000000000000000 R08: 00000000000217b0 R09: ffffffffbc9c1504
+[ 14.783214] R10: fffff4a180519480 R11: ffff9a8f94523600 R12: ffff9a8f9493e240
+[ 14.784507] R13: ffff9a8f9447d738 R14: 000000000000050a R15: 0000000000000000
+[ 14.785800] FS: 00007f545b466700(0000) GS:ffff9a8f9fc00000(0000) knlGS:0000000000000000
+[ 14.787073] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 14.787792] CR2: 0000000000000000 CR3: 00000000144be000 CR4: 00000000000006b0
+[ 14.788689] Call Trace:
+[ 14.789007] _ib_modify_qp+0x71/0x120
+[ 14.789475] modify_qp.isra.20+0x207/0x2f0
+[ 14.790010] ib_uverbs_modify_qp+0x90/0xe0
+[ 14.790532] ib_uverbs_write+0x1d2/0x3c0
+[ 14.791049] ? __handle_mm_fault+0x93c/0xe40
+[ 14.791644] __vfs_write+0x36/0x180
+[ 14.792096] ? handle_mm_fault+0xc1/0x210
+[ 14.792601] vfs_write+0xad/0x1e0
+[ 14.793018] SyS_write+0x52/0xc0
+[ 14.793422] do_syscall_64+0x75/0x180
+[ 14.793888] entry_SYSCALL_64_after_hwframe+0x21/0x86
+[ 14.794527] RIP: 0033:0x7f545ad76099
+[ 14.794975] RSP: 002b:00007ffd78787468 EFLAGS: 00000287 ORIG_RAX: 0000000000000001
+[ 14.795958] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f545ad76099
+[ 14.797075] RDX: 0000000000000078 RSI: 0000000020009000 RDI: 0000000000000003
+[ 14.798140] RBP: 00007ffd78787470 R08: 00007ffd78787480 R09: 00007ffd78787480
+[ 14.799207] R10: 00007ffd78787480 R11: 0000000000000287 R12: 00005599ada98760
+[ 14.800277] R13: 00007ffd78787560 R14: 0000000000000000 R15: 0000000000000000
+[ 14.801341] Code: 4c 8b 1c 24 48 8b 83 70 02 00 00 48 c7 83 cc 02 00
+00 00 00 00 00 48 c7 83 24 03 00 00 00 00 00 00 c7 83 2c 03 00 00 00 00
+00 00 <c7> 00 00 00 00 00 48 8b 83 70 02 00 00 c7 40 04 00 00 00 00 4c
+[ 14.804012] RIP: mlx5_ib_modify_qp+0xf60/0x13f0 RSP: ffffbf48001c7bd8
+[ 14.804838] CR2: 0000000000000000
+[ 14.805288] ---[ end trace 3f1da0df5c8b7c37 ]---
+
+Cc: syzkaller <syzkaller@googlegroups.com>
+Reported-by: Maor Gottlieb <maorg@mellanox.com>
+Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/hw/mlx5/qp.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/infiniband/hw/mlx5/qp.c
++++ b/drivers/infiniband/hw/mlx5/qp.c
+@@ -2934,7 +2934,8 @@ static int __mlx5_ib_modify_qp(struct ib
+ * If we moved a kernel QP to RESET, clean up all old CQ
+ * entries and reinitialize the QP.
+ */
+- if (new_state == IB_QPS_RESET && !ibqp->uobject) {
++ if (new_state == IB_QPS_RESET &&
++ !ibqp->uobject && ibqp->qp_type != IB_QPT_XRC_TGT) {
+ mlx5_ib_cq_clean(recv_cq, base->mqp.qpn,
+ ibqp->srq ? to_msrq(ibqp->srq) : NULL);
+ if (send_cq != recv_cq)
diff --git a/patches.drivers/RDMA-ucma-Don-t-allow-setting-RDMA_OPTION_IB_PATH-wi.patch b/patches.drivers/RDMA-ucma-Don-t-allow-setting-RDMA_OPTION_IB_PATH-wi.patch
new file mode 100644
index 0000000000..0082056bbe
--- /dev/null
+++ b/patches.drivers/RDMA-ucma-Don-t-allow-setting-RDMA_OPTION_IB_PATH-wi.patch
@@ -0,0 +1,33 @@
+From: Roland Dreier <roland@purestorage.com>
+Date: Tue, 3 Apr 2018 15:33:01 -0700
+Subject: RDMA/ucma: Don't allow setting RDMA_OPTION_IB_PATH without an RDMA
+ device
+Patch-mainline: v4.17-rc1
+Git-commit: 8435168d50e66fa5eae01852769d20a36f9e5e83
+References: bsc#1046306 FATE#322942
+
+Check to make sure that ctx->cm_id->device is set before we use it.
+Otherwise userspace can trigger a NULL dereference by doing
+RDMA_USER_CM_CMD_SET_OPTION on an ID that is not bound to a device.
+
+Cc: <stable@vger.kernel.org>
+Reported-by: <syzbot+a67bc93e14682d92fc2f@syzkaller.appspotmail.com>
+Signed-off-by: Roland Dreier <roland@purestorage.com>
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/core/ucma.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/infiniband/core/ucma.c
++++ b/drivers/infiniband/core/ucma.c
+@@ -1241,6 +1241,9 @@ static int ucma_set_ib_path(struct ucma_
+ if (!optlen)
+ return -EINVAL;
+
++ if (!ctx->cm_id->device)
++ return -EINVAL;
++
+ memset(&sa_path, 0, sizeof(sa_path));
+
+ sa_path.rec_type = SA_PATH_REC_TYPE_IB;
diff --git a/patches.drivers/RDMA-uverbs-Use-an-unambiguous-errno-for-method-not-.patch b/patches.drivers/RDMA-uverbs-Use-an-unambiguous-errno-for-method-not-.patch
new file mode 100644
index 0000000000..1d39111d6c
--- /dev/null
+++ b/patches.drivers/RDMA-uverbs-Use-an-unambiguous-errno-for-method-not-.patch
@@ -0,0 +1,73 @@
+From: Jason Gunthorpe <jgg@mellanox.com>
+Date: Wed, 24 Jan 2018 19:58:34 -0700
+Subject: RDMA/uverbs: Use an unambiguous errno for method not supported
+Patch-mainline: v4.16-rc1
+Git-commit: 3624a8f02568f08aef299d3b117f2226f621177d
+References: bsc#1046306 FATE#322942
+
+Returning EOPNOTSUPP is problematic because it can also be
+returned by the method function, and we use it in quite a few
+places in drivers these days.
+
+Instead, dedicate EPROTONOSUPPORT to indicate that the ioctl framework
+is enabled but the requested object and method are not supported by
+the kernel. No other case will return this code, and it lets userspace
+know to fall back to write().
+
+grep says we do not use it today in drivers/infiniband subsystem.
+
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Reviewed-by: Matan Barak <matanb@mellanox.com>
+Signed-off-by: Doug Ledford <dledford@redhat.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/infiniband/core/uverbs_ioctl.c | 19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+--- a/drivers/infiniband/core/uverbs_ioctl.c
++++ b/drivers/infiniband/core/uverbs_ioctl.c
+@@ -245,16 +245,13 @@ static long ib_uverbs_cmd_verbs(struct i
+ uintptr_t data[UVERBS_OPTIMIZE_USING_STACK_SZ / sizeof(uintptr_t)];
+ #endif
+
+- if (hdr->reserved)
+- return -EINVAL;
+-
+ object_spec = uverbs_get_object(ib_dev, hdr->object_id);
+ if (!object_spec)
+- return -EOPNOTSUPP;
++ return -EPROTONOSUPPORT;
+
+ method_spec = uverbs_get_method(object_spec, hdr->method_id);
+ if (!method_spec)
+- return -EOPNOTSUPP;
++ return -EPROTONOSUPPORT;
+
+ if ((method_spec->flags & UVERBS_ACTION_FLAG_CREATE_ROOT) ^ !file->ucontext)
+ return -EINVAL;
+@@ -310,6 +307,16 @@ static long ib_uverbs_cmd_verbs(struct i
+
+ err = uverbs_handle_method(buf, ctx->uattrs, hdr->num_attrs, ib_dev,
+ file, method_spec, ctx->uverbs_attr_bundle);
++
++ /*
++ * EPROTONOSUPPORT is ONLY to be returned if the ioctl framework can
++ * not invoke the method because the request is not supported. No
++ * other cases should return this code.
++ */
++ if (unlikely(err == -EPROTONOSUPPORT)) {
++ WARN_ON_ONCE(err == -EPROTONOSUPPORT);
++ err = -EINVAL;
++ }
+ out:
+ #ifdef UVERBS_OPTIMIZE_USING_STACK_SZ
+ if (ctx_size > UVERBS_OPTIMIZE_USING_STACK_SZ)
+@@ -348,7 +355,7 @@ long ib_uverbs_ioctl(struct file *filp,
+ }
+
+ if (hdr.reserved) {
+- err = -EOPNOTSUPP;
++ err = -EPROTONOSUPPORT;
+ goto out;
+ }
+
diff --git a/patches.drivers/acpi-nfit-Fix-scrub-idle-detection.patch b/patches.drivers/acpi-nfit-Fix-scrub-idle-detection.patch
new file mode 100644
index 0000000000..a2251209e7
--- /dev/null
+++ b/patches.drivers/acpi-nfit-Fix-scrub-idle-detection.patch
@@ -0,0 +1,118 @@
+From: Dan Williams <dan.j.williams@intel.com>
+Date: Thu, 5 Jul 2018 14:58:49 -0700
+Subject: acpi, nfit: Fix scrub idle detection
+Patch-mainline: v4.18-rc5
+Git-commit: 33cc2c9667561b224215e6dfb5bf98e8fa17914e
+References: bsc#1094119
+
+The notification of scrub completion happens within the scrub workqueue.
+That can clearly race someone running scrub_show() and work_busy()
+before the workqueue has a chance to flush the recently completed work.
+Add a flag to reliably indicate the idle vs busy state. Without this
+change applications using poll(2) to wait for scrub-completion may
+falsely wakeup and read ARS as being busy even though the thread is
+going idle and then hang indefinitely.
+
+Fixes: bc6ba8085842 ("nfit, address-range-scrub: rework and simplify ARS...")
+Cc: <stable@vger.kernel.org>
+Reported-by: Vishal Verma <vishal.l.verma@intel.com>
+Tested-by: Vishal Verma <vishal.l.verma@intel.com>
+Reported-by: Lukasz Dorau <lukasz.dorau@intel.com>
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+Acked-by: Johannes Thumshirn <jthumshirn@suse.de>
+---
+ drivers/acpi/nfit/core.c | 44 +++++++++++++++++++++++++++++++++-----------
+ drivers/acpi/nfit/nfit.h | 1 +
+ 2 files changed, 34 insertions(+), 11 deletions(-)
+
+--- a/drivers/acpi/nfit/core.c
++++ b/drivers/acpi/nfit/core.c
+@@ -1245,7 +1245,7 @@ static ssize_t scrub_show(struct device
+
+ mutex_lock(&acpi_desc->init_mutex);
+ rc = sprintf(buf, "%d%s", acpi_desc->scrub_count,
+- work_busy(&acpi_desc->dwork.work)
++ acpi_desc->scrub_busy
+ && !acpi_desc->cancel ? "+\n" : "\n");
+ mutex_unlock(&acpi_desc->init_mutex);
+ }
+@@ -2893,6 +2893,32 @@ static unsigned int __acpi_nfit_scrub(st
+ return 0;
+ }
+
++static void __sched_ars(struct acpi_nfit_desc *acpi_desc, unsigned int tmo)
++{
++ lockdep_assert_held(&acpi_desc->init_mutex);
++
++ acpi_desc->scrub_busy = 1;
++ /* note this should only be set from within the workqueue */
++ if (tmo)
++ acpi_desc->scrub_tmo = tmo;
++ queue_delayed_work(nfit_wq, &acpi_desc->dwork, tmo * HZ);
++}
++
++static void sched_ars(struct acpi_nfit_desc *acpi_desc)
++{
++ __sched_ars(acpi_desc, 0);
++}
++
++static void notify_ars_done(struct acpi_nfit_desc *acpi_desc)
++{
++ lockdep_assert_held(&acpi_desc->init_mutex);
++
++ acpi_desc->scrub_busy = 0;
++ acpi_desc->scrub_count++;
++ if (acpi_desc->scrub_count_state)
++ sysfs_notify_dirent(acpi_desc->scrub_count_state);
++}
++
+ static void acpi_nfit_scrub(struct work_struct *work)
+ {
+ struct acpi_nfit_desc *acpi_desc;
+@@ -2903,14 +2929,10 @@ static void acpi_nfit_scrub(struct work_
+ mutex_lock(&acpi_desc->init_mutex);
+ query_rc = acpi_nfit_query_poison(acpi_desc);
+ tmo = __acpi_nfit_scrub(acpi_desc, query_rc);
+- if (tmo) {
+- queue_delayed_work(nfit_wq, &acpi_desc->dwork, tmo * HZ);
+- acpi_desc->scrub_tmo = tmo;
+- } else {
+- acpi_desc->scrub_count++;
+- if (acpi_desc->scrub_count_state)
+- sysfs_notify_dirent(acpi_desc->scrub_count_state);
+- }
++ if (tmo)
++ __sched_ars(acpi_desc, tmo);
++ else
++ notify_ars_done(acpi_desc);
+ memset(acpi_desc->ars_status, 0, acpi_desc->max_ars);
+ mutex_unlock(&acpi_desc->init_mutex);
+ }
+@@ -2991,7 +3013,7 @@ static int acpi_nfit_register_regions(st
+ break;
+ }
+
+- queue_delayed_work(nfit_wq, &acpi_desc->dwork, 0);
++ sched_ars(acpi_desc);
+ return 0;
+ }
+
+@@ -3194,7 +3216,7 @@ int acpi_nfit_ars_rescan(struct acpi_nfi
+ }
+ }
+ if (scheduled) {
+- queue_delayed_work(nfit_wq, &acpi_desc->dwork, 0);
++ sched_ars(acpi_desc);
+ dev_dbg(dev, "ars_scan triggered\n");
+
+ }
+--- a/drivers/acpi/nfit/nfit.h
++++ b/drivers/acpi/nfit/nfit.h
+@@ -203,6 +203,7 @@ struct acpi_nfit_desc {
+ unsigned int max_ars;
+ unsigned int scrub_count;
+ unsigned int scrub_mode;
++ unsigned int scrub_busy:1;
+ unsigned int cancel:1;
+ unsigned long dimm_cmd_force_en;
+ unsigned long bus_cmd_force_en;
diff --git a/patches.drivers/device-property-Allow-iterating-over-available-child.patch b/patches.drivers/device-property-Allow-iterating-over-available-child.patch
new file mode 100644
index 0000000000..23f16e74d6
--- /dev/null
+++ b/patches.drivers/device-property-Allow-iterating-over-available-child.patch
@@ -0,0 +1,78 @@
+From: Marcin Wojtas <mw@semihalf.com>
+Date: Thu, 18 Jan 2018 13:31:41 +0100
+Subject: device property: Allow iterating over available child fwnodes
+Patch-mainline: v4.16-rc1
+Git-commit: 3395de96ae5998692bd86024d0d5e4dd55cd6cc3
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/base/property.c | 26 ++++++++++++++++++++++++++
+ include/linux/property.h | 6 ++++++
+ 2 files changed, 32 insertions(+)
+
+--- a/drivers/base/property.c
++++ b/drivers/base/property.c
+@@ -958,6 +958,32 @@ struct fwnode_handle *fwnode_get_next_ch
+ 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((struct fwnode_handle *)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.
+--- a/include/linux/property.h
++++ b/include/linux/property.h
+@@ -77,11 +77,17 @@ struct fwnode_handle *fwnode_get_parent(
+ struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode);
+ struct fwnode_handle *fwnode_get_next_child_node(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);
+
diff --git a/patches.drivers/device-property-Introduce-fwnode_call_bool_op-for-op.patch b/patches.drivers/device-property-Introduce-fwnode_call_bool_op-for-op.patch
new file mode 100644
index 0000000000..bf6bacbf34
--- /dev/null
+++ b/patches.drivers/device-property-Introduce-fwnode_call_bool_op-for-op.patch
@@ -0,0 +1,63 @@
+From: Sakari Ailus <sakari.ailus@linux.intel.com>
+Date: Tue, 11 Jul 2017 18:20:20 +0300
+Subject: device property: Introduce fwnode_call_bool_op() for ops that return
+ bool
+Patch-mainline: v4.13-rc1
+Git-commit: e8158b486d5f3f55cf372c5a32b42f263bf7f123
+References: bsc#1098633
+
+fwnode_call_int_op() isn't suitable for calling ops that return bool
+since it effectively causes the result returned to the user to be
+true when an op hasn't been defined or the fwnode is NULL.
+
+Address this by introducing fwnode_call_bool_op() for calling ops
+that return bool.
+
+Fixes: 3708184afc77 "device property: Move FW type specific functionality to FW specific files"
+Fixes: 2294b3af05e9 "device property: Introduce fwnode_device_is_available()"
+Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/base/property.c | 6 +++---
+ include/linux/fwnode.h | 4 ++++
+ 2 files changed, 7 insertions(+), 3 deletions(-)
+
+--- a/drivers/base/property.c
++++ b/drivers/base/property.c
+@@ -253,10 +253,10 @@ bool fwnode_property_present(struct fwno
+ {
+ bool ret;
+
+- ret = fwnode_call_int_op(fwnode, property_present, propname);
++ ret = fwnode_call_bool_op(fwnode, property_present, propname);
+ if (ret == false && !IS_ERR_OR_NULL(fwnode) &&
+ !IS_ERR_OR_NULL(fwnode->secondary))
+- ret = fwnode_call_int_op(fwnode->secondary, property_present,
++ ret = fwnode_call_bool_op(fwnode->secondary, property_present,
+ propname);
+ return ret;
+ }
+@@ -1027,7 +1027,7 @@ EXPORT_SYMBOL_GPL(fwnode_handle_put);
+ */
+ bool fwnode_device_is_available(struct fwnode_handle *fwnode)
+ {
+- return fwnode_call_int_op(fwnode, device_is_available);
++ return fwnode_call_bool_op(fwnode, device_is_available);
+ }
+ EXPORT_SYMBOL_GPL(fwnode_device_is_available);
+
+--- a/include/linux/fwnode.h
++++ b/include/linux/fwnode.h
+@@ -99,6 +99,10 @@ struct fwnode_operations {
+ (fwnode ? (fwnode_has_op(fwnode, op) ? \
+ (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : -ENXIO) : \
+ -EINVAL)
++#define fwnode_call_bool_op(fwnode, op, ...) \
++ (fwnode ? (fwnode_has_op(fwnode, op) ? \
++ (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : false) : \
++ false)
+ #define fwnode_call_ptr_op(fwnode, op, ...) \
+ (fwnode_has_op(fwnode, op) ? \
+ (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : NULL)
diff --git a/patches.drivers/device-property-Introduce-fwnode_device_is_available.patch b/patches.drivers/device-property-Introduce-fwnode_device_is_available.patch
new file mode 100644
index 0000000000..384c0e645b
--- /dev/null
+++ b/patches.drivers/device-property-Introduce-fwnode_device_is_available.patch
@@ -0,0 +1,109 @@
+From: Sakari Ailus <sakari.ailus@linux.intel.com>
+Date: Tue, 6 Jun 2017 12:37:39 +0300
+Subject: device property: Introduce fwnode_device_is_available()
+Patch-mainline: v4.13-rc1
+Git-commit: 2294b3af05e9b3fe0b84a78971e709037bd7593c
+References: bsc#1098633
+
+Add fwnode_device_is_available() to tell whether the device corresponding
+to a certain fwnode_handle is available for use.
+
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/acpi/property.c | 9 +++++++++
+ drivers/base/property.c | 10 ++++++++++
+ drivers/of/base.c | 6 ++++++
+ include/linux/fwnode.h | 1 +
+ include/linux/property.h | 1 +
+ 5 files changed, 27 insertions(+)
+
+--- a/drivers/acpi/property.c
++++ b/drivers/acpi/property.c
+@@ -1121,6 +1121,14 @@ int acpi_graph_get_remote_endpoint(struc
+ return 0;
+ }
+
++static bool acpi_fwnode_device_is_available(struct fwnode_handle *fwnode)
++{
++ if (!is_acpi_device_node(fwnode))
++ return false;
++
++ return acpi_device_is_present(to_acpi_device_node(fwnode));
++}
++
+ static bool acpi_fwnode_property_present(struct fwnode_handle *fwnode,
+ const char *propname)
+ {
+@@ -1216,6 +1224,7 @@ static int acpi_fwnode_graph_parse_endpo
+ }
+
+ const struct fwnode_operations acpi_fwnode_ops = {
++ .device_is_available = acpi_fwnode_device_is_available,
+ .property_present = acpi_fwnode_property_present,
+ .property_read_int_array = acpi_fwnode_property_read_int_array,
+ .property_read_string_array = acpi_fwnode_property_read_string_array,
+--- a/drivers/base/property.c
++++ b/drivers/base/property.c
+@@ -1022,6 +1022,16 @@ void fwnode_handle_put(struct fwnode_han
+ EXPORT_SYMBOL_GPL(fwnode_handle_put);
+
+ /**
++ * fwnode_device_is_available - check if a device is available for use
++ * @fwnode: Pointer to the fwnode of the device.
++ */
++bool fwnode_device_is_available(struct fwnode_handle *fwnode)
++{
++ return fwnode_call_int_op(fwnode, device_is_available);
++}
++EXPORT_SYMBOL_GPL(fwnode_device_is_available);
++
++/**
+ * device_get_child_node_count - return the number of child nodes for device
+ * @dev: Device to cound the child nodes for
+ */
+--- a/drivers/of/base.c
++++ b/drivers/of/base.c
+@@ -2576,6 +2576,11 @@ static void of_fwnode_put(struct fwnode_
+ of_node_put(to_of_node(fwnode));
+ }
+
++static bool of_fwnode_device_is_available(struct fwnode_handle *fwnode)
++{
++ return of_device_is_available(to_of_node(fwnode));
++}
++
+ static bool of_fwnode_property_present(struct fwnode_handle *fwnode,
+ const char *propname)
+ {
+@@ -2696,6 +2701,7 @@ static int of_fwnode_graph_parse_endpoin
+ const struct fwnode_operations of_fwnode_ops = {
+ .get = of_fwnode_get,
+ .put = of_fwnode_put,
++ .device_is_available = of_fwnode_device_is_available,
+ .property_present = of_fwnode_property_present,
+ .property_read_int_array = of_fwnode_property_read_int_array,
+ .property_read_string_array = of_fwnode_property_read_string_array,
+--- a/include/linux/fwnode.h
++++ b/include/linux/fwnode.h
+@@ -66,6 +66,7 @@ struct fwnode_endpoint {
+ struct fwnode_operations {
+ void (*get)(struct fwnode_handle *fwnode);
+ void (*put)(struct fwnode_handle *fwnode);
++ bool (*device_is_available)(struct fwnode_handle *fwnode);
+ bool (*property_present)(struct fwnode_handle *fwnode,
+ const char *propname);
+ int (*property_read_int_array)(struct fwnode_handle *fwnode,
+--- a/include/linux/property.h
++++ b/include/linux/property.h
+@@ -51,6 +51,7 @@ int device_property_read_string(struct d
+ int device_property_match_string(struct device *dev,
+ const char *propname, const char *string);
+
++bool fwnode_device_is_available(struct fwnode_handle *fwnode);
+ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
+ int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
+ const char *propname, u8 *val,
diff --git a/patches.drivers/device-property-Introduce-fwnode_get_mac_address.patch b/patches.drivers/device-property-Introduce-fwnode_get_mac_address.patch
new file mode 100644
index 0000000000..66df81a471
--- /dev/null
+++ b/patches.drivers/device-property-Introduce-fwnode_get_mac_address.patch
@@ -0,0 +1,104 @@
+From: Marcin Wojtas <mw@semihalf.com>
+Date: Thu, 18 Jan 2018 13:31:38 +0100
+Subject: device property: Introduce fwnode_get_mac_address()
+Patch-mainline: v4.16-rc1
+Git-commit: babe2dbb28e780177ae2fba6a5640be1712f4af0
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/base/property.c | 28 ++++++++++++++++++++--------
+ include/linux/property.h | 2 ++
+ 2 files changed, 22 insertions(+), 8 deletions(-)
+
+--- a/drivers/base/property.c
++++ b/drivers/base/property.c
+@@ -1139,11 +1139,11 @@ int device_get_phy_mode(struct device *d
+ }
+ 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;
+@@ -1151,8 +1151,8 @@ static void *device_get_mac_addr(struct
+ }
+
+ /**
+- * 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
+ *
+@@ -1173,19 +1173,31 @@ static void *device_get_mac_addr(struct
+ * 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);
+
+--- a/include/linux/property.h
++++ b/include/linux/property.h
+@@ -272,6 +272,8 @@ int device_get_phy_mode(struct device *d
+
+ 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(
+ struct fwnode_handle *fwnode, struct fwnode_handle *prev);
+ struct fwnode_handle *fwnode_graph_get_remote_port_parent(
diff --git a/patches.drivers/device-property-Introduce-fwnode_get_phy_mode.patch b/patches.drivers/device-property-Introduce-fwnode_get_phy_mode.patch
new file mode 100644
index 0000000000..d449d538bd
--- /dev/null
+++ b/patches.drivers/device-property-Introduce-fwnode_get_phy_mode.patch
@@ -0,0 +1,90 @@
+From: Marcin Wojtas <mw@semihalf.com>
+Date: Thu, 18 Jan 2018 13:31:39 +0100
+Subject: device property: Introduce fwnode_get_phy_mode()
+Patch-mainline: v4.16-rc1
+Git-commit: b28f263b86709a1e26d7207112030e970abf4aab
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/base/property.c | 24 +++++++++++++++++++-----
+ include/linux/property.h | 1 +
+ 2 files changed, 20 insertions(+), 5 deletions(-)
+
+--- a/drivers/base/property.c
++++ b/drivers/base/property.c
+@@ -1112,21 +1112,21 @@ enum dev_dma_attr device_get_dma_attr(st
+ 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;
+@@ -1137,6 +1137,20 @@ int device_get_phy_mode(struct device *d
+
+ 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,
+--- a/include/linux/property.h
++++ b/include/linux/property.h
+@@ -272,6 +272,7 @@ int device_get_phy_mode(struct device *d
+
+ 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(
diff --git a/patches.drivers/device-property-Introduce-fwnode_irq_get.patch b/patches.drivers/device-property-Introduce-fwnode_irq_get.patch
new file mode 100644
index 0000000000..8d6f853e49
--- /dev/null
+++ b/patches.drivers/device-property-Introduce-fwnode_irq_get.patch
@@ -0,0 +1,106 @@
+From: Marcin Wojtas <mw@semihalf.com>
+Date: Thu, 18 Jan 2018 13:31:40 +0100
+Subject: device property: Introduce fwnode_irq_get()
+Patch-mainline: v4.16-rc1
+Git-commit: 7c6c57f2ab2c5113844fe187a7c45c4bd76dc671
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/base/property.c | 26 ++++++++++++++++++++++++++
+ include/linux/acpi.h | 3 +++
+ include/linux/property.h | 2 ++
+ 3 files changed, 31 insertions(+)
+
+--- 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>
+@@ -1184,6 +1185,31 @@ void *device_get_mac_address(struct devi
+ 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
+--- a/include/linux/acpi.h
++++ b/include/linux/acpi.h
+@@ -56,6 +56,8 @@ static inline acpi_handle acpi_device_ha
+ #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))
+
+
+ extern const struct fwnode_operations acpi_fwnode_ops;
+@@ -628,6 +630,7 @@ int acpi_arch_timer_mem_init(struct arch
+ #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;
+--- a/include/linux/property.h
++++ b/include/linux/property.h
+@@ -97,6 +97,8 @@ struct fwnode_handle *device_get_named_c
+ 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,
diff --git a/patches.drivers/device-property-Move-FW-type-specific-functionality-.patch b/patches.drivers/device-property-Move-FW-type-specific-functionality-.patch
new file mode 100644
index 0000000000..25ce213852
--- /dev/null
+++ b/patches.drivers/device-property-Move-FW-type-specific-functionality-.patch
@@ -0,0 +1,651 @@
+From: Sakari Ailus <sakari.ailus@linux.intel.com>
+Date: Tue, 6 Jun 2017 12:37:37 +0300
+Subject: device property: Move FW type specific functionality to FW specific
+ files
+Patch-mainline: v4.13-rc1
+Git-commit: 3708184afc77bb67709a67a35d9f367ebd32cbc4
+References: bsc#1098633
+
+The device and fwnode property API supports Devicetree, ACPI and pset
+properties. The implementation of this functionality for each firmware
+type was embedded in the fwnode property core. Move it out to firmware
+type specific locations, making it easier to maintain.
+
+Depends-on: ("of: Move OF property and graph API from base.c to property.c")
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/acpi/property.c | 68 +++++++++++++++
+ drivers/acpi/scan.c | 1
+ drivers/base/property.c | 208 +++++++++++++++++++-----------------------------
+ drivers/of/base.c | 90 ++++++++++++++++++++
+ include/linux/acpi.h | 4
+ include/linux/fwnode.h | 54 ++++++++++++
+ include/linux/of.h | 2
+ 7 files changed, 302 insertions(+), 125 deletions(-)
+
+--- a/drivers/acpi/property.c
++++ b/drivers/acpi/property.c
+@@ -57,6 +57,7 @@ static bool acpi_nondev_subnode_extract(
+
+ dn->name = link->package.elements[0].string.pointer;
+ dn->fwnode.type = FWNODE_ACPI_DATA;
++ dn->fwnode.ops = &acpi_fwnode_ops;
+ dn->parent = parent;
+ INIT_LIST_HEAD(&dn->data.subnodes);
+
+@@ -1119,3 +1120,70 @@ int acpi_graph_get_remote_endpoint(struc
+
+ return 0;
+ }
++
++static bool acpi_fwnode_property_present(struct fwnode_handle *fwnode,
++ const char *propname)
++{
++ return !acpi_node_prop_get(fwnode, propname, NULL);
++}
++
++static int acpi_fwnode_property_read_int_array(struct fwnode_handle *fwnode,
++ const char *propname,
++ unsigned int elem_size,
++ void *val, size_t nval)
++{
++ enum dev_prop_type type;
++
++ switch (elem_size) {
++ case sizeof(u8):
++ type = DEV_PROP_U8;
++ break;
++ case sizeof(u16):
++ type = DEV_PROP_U16;
++ break;
++ case sizeof(u32):
++ type = DEV_PROP_U32;
++ break;
++ case sizeof(u64):
++ type = DEV_PROP_U64;
++ break;
++ default:
++ return -ENXIO;
++ }
++
++ return acpi_node_prop_read(fwnode, propname, type, val, nval);
++}
++
++static int acpi_fwnode_property_read_string_array(struct fwnode_handle *fwnode,
++ const char *propname,
++ const char **val, size_t nval)
++{
++ return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
++ val, nval);
++}
++
++static struct fwnode_handle *
++acpi_fwnode_get_named_child_node(struct fwnode_handle *fwnode,
++ const char *childname)
++{
++ struct fwnode_handle *child;
++
++ /*
++ * Find first matching named child node of this fwnode.
++ * For ACPI this will be a data only sub-node.
++ */
++ fwnode_for_each_child_node(fwnode, child)
++ if (acpi_data_node_match(child, childname))
++ return child;
++
++ return NULL;
++}
++
++const struct fwnode_operations acpi_fwnode_ops = {
++ .property_present = acpi_fwnode_property_present,
++ .property_read_int_array = acpi_fwnode_property_read_int_array,
++ .property_read_string_array = acpi_fwnode_property_read_string_array,
++ .get_parent = acpi_node_get_parent,
++ .get_next_child_node = acpi_get_next_subnode,
++ .get_named_child_node = acpi_fwnode_get_named_child_node,
++};
+--- a/drivers/acpi/scan.c
++++ b/drivers/acpi/scan.c
+@@ -1467,6 +1467,7 @@ void acpi_init_device_object(struct acpi
+ device->handle = handle;
+ device->parent = acpi_bus_get_parent(handle);
+ device->fwnode.type = FWNODE_ACPI;
++ device->fwnode.ops = &acpi_fwnode_ops;
+ acpi_set_device_status(device, sta);
+ acpi_device_get_busid(device);
+ acpi_set_pnp_ids(handle, &device->pnp, type);
+--- a/drivers/base/property.c
++++ b/drivers/base/property.c
+@@ -187,6 +187,50 @@ struct fwnode_handle *dev_fwnode(struct
+ }
+ EXPORT_SYMBOL_GPL(dev_fwnode);
+
++static bool pset_fwnode_property_present(struct fwnode_handle *fwnode,
++ const char *propname)
++{
++ return !!pset_prop_get(to_pset_node(fwnode), propname);
++}
++
++static int pset_fwnode_read_int_array(struct fwnode_handle *fwnode,
++ const char *propname,
++ unsigned int elem_size, void *val,
++ size_t nval)
++{
++ struct property_set *node = to_pset_node(fwnode);
++
++ if (!val)
++ return pset_prop_count_elems_of_size(node, propname, elem_size);
++
++ switch (elem_size) {
++ case sizeof(u8):
++ return pset_prop_read_u8_array(node, propname, val, nval);
++ case sizeof(u16):
++ return pset_prop_read_u16_array(node, propname, val, nval);
++ case sizeof(u32):
++ return pset_prop_read_u32_array(node, propname, val, nval);
++ case sizeof(u64):
++ return pset_prop_read_u64_array(node, propname, val, nval);
++ }
++
++ return -ENXIO;
++}
++
++static int pset_fwnode_property_read_string_array(struct fwnode_handle *fwnode,
++ const char *propname,
++ const char **val, size_t nval)
++{
++ return pset_prop_read_string_array(to_pset_node(fwnode), propname,
++ val, nval);
++}
++
++static const struct fwnode_operations pset_fwnode_ops = {
++ .property_present = pset_fwnode_property_present,
++ .property_read_int_array = pset_fwnode_read_int_array,
++ .property_read_string_array = pset_fwnode_property_read_string_array,
++};
++
+ /**
+ * device_property_present - check if a property of a device is present
+ * @dev: Device whose property is being checked
+@@ -200,18 +244,6 @@ bool device_property_present(struct devi
+ }
+ EXPORT_SYMBOL_GPL(device_property_present);
+
+-static bool __fwnode_property_present(struct fwnode_handle *fwnode,
+- const char *propname)
+-{
+- if (is_of_node(fwnode))
+- return of_property_read_bool(to_of_node(fwnode), propname);
+- else if (is_acpi_node(fwnode))
+- return !acpi_node_prop_get(fwnode, propname, NULL);
+- else if (is_pset_node(fwnode))
+- return !!pset_prop_get(to_pset_node(fwnode), propname);
+- return false;
+-}
+-
+ /**
+ * fwnode_property_present - check if a property of a firmware node is present
+ * @fwnode: Firmware node whose property to check
+@@ -221,10 +253,11 @@ bool fwnode_property_present(struct fwno
+ {
+ bool ret;
+
+- ret = __fwnode_property_present(fwnode, propname);
++ ret = fwnode_call_int_op(fwnode, property_present, propname);
+ if (ret == false && !IS_ERR_OR_NULL(fwnode) &&
+ !IS_ERR_OR_NULL(fwnode->secondary))
+- ret = __fwnode_property_present(fwnode->secondary, propname);
++ ret = fwnode_call_int_op(fwnode->secondary, property_present,
++ propname);
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(fwnode_property_present);
+@@ -398,42 +431,23 @@ int device_property_match_string(struct
+ }
+ EXPORT_SYMBOL_GPL(device_property_match_string);
+
+-#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \
+- (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
+- : of_property_count_elems_of_size((node), (propname), sizeof(type))
+-
+-#define PSET_PROP_READ_ARRAY(node, propname, type, val, nval) \
+- (val) ? pset_prop_read_##type##_array((node), (propname), (val), (nval)) \
+- : pset_prop_count_elems_of_size((node), (propname), sizeof(type))
+-
+-#define FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \
+-({ \
+- int _ret_; \
+- if (is_of_node(_fwnode_)) \
+- _ret_ = OF_DEV_PROP_READ_ARRAY(to_of_node(_fwnode_), _propname_, \
+- _type_, _val_, _nval_); \
+- else if (is_acpi_node(_fwnode_)) \
+- _ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_, \
+- _val_, _nval_); \
+- else if (is_pset_node(_fwnode_)) \
+- _ret_ = PSET_PROP_READ_ARRAY(to_pset_node(_fwnode_), _propname_, \
+- _type_, _val_, _nval_); \
+- else \
+- _ret_ = -ENXIO; \
+- _ret_; \
+-})
+-
+-#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \
+-({ \
+- int _ret_; \
+- _ret_ = FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, \
+- _val_, _nval_); \
+- if (_ret_ == -EINVAL && !IS_ERR_OR_NULL(_fwnode_) && \
+- !IS_ERR_OR_NULL(_fwnode_->secondary)) \
+- _ret_ = FWNODE_PROP_READ(_fwnode_->secondary, _propname_, _type_, \
+- _proptype_, _val_, _nval_); \
+- _ret_; \
+-})
++static int fwnode_property_read_int_array(struct fwnode_handle *fwnode,
++ const char *propname,
++ unsigned int elem_size, void *val,
++ size_t nval)
++{
++ int ret;
++
++ ret = fwnode_call_int_op(fwnode, property_read_int_array, propname,
++ elem_size, val, nval);
++ if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
++ !IS_ERR_OR_NULL(fwnode->secondary))
++ ret = fwnode_call_int_op(
++ fwnode->secondary, property_read_int_array, propname,
++ elem_size, val, nval);
++
++ return ret;
++}
+
+ /**
+ * fwnode_property_read_u8_array - return a u8 array property of firmware node
+@@ -456,8 +470,8 @@ EXPORT_SYMBOL_GPL(device_property_match_
+ int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
+ const char *propname, u8 *val, size_t nval)
+ {
+- return FWNODE_PROP_READ_ARRAY(fwnode, propname, u8, DEV_PROP_U8,
+- val, nval);
++ return fwnode_property_read_int_array(fwnode, propname, sizeof(u8),
++ val, nval);
+ }
+ EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
+
+@@ -482,8 +496,8 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u
+ int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
+ const char *propname, u16 *val, size_t nval)
+ {
+- return FWNODE_PROP_READ_ARRAY(fwnode, propname, u16, DEV_PROP_U16,
+- val, nval);
++ return fwnode_property_read_int_array(fwnode, propname, sizeof(u16),
++ val, nval);
+ }
+ EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
+
+@@ -508,8 +522,8 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u
+ int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
+ const char *propname, u32 *val, size_t nval)
+ {
+- return FWNODE_PROP_READ_ARRAY(fwnode, propname, u32, DEV_PROP_U32,
+- val, nval);
++ return fwnode_property_read_int_array(fwnode, propname, sizeof(u32),
++ val, nval);
+ }
+ EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
+
+@@ -534,29 +548,11 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u
+ int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
+ const char *propname, u64 *val, size_t nval)
+ {
+- return FWNODE_PROP_READ_ARRAY(fwnode, propname, u64, DEV_PROP_U64,
+- val, nval);
++ return fwnode_property_read_int_array(fwnode, propname, sizeof(u64),
++ val, nval);
+ }
+ EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
+
+-static int __fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+- const char *propname,
+- const char **val, size_t nval)
+-{
+- if (is_of_node(fwnode))
+- return val ?
+- of_property_read_string_array(to_of_node(fwnode),
+- propname, val, nval) :
+- of_property_count_strings(to_of_node(fwnode), propname);
+- else if (is_acpi_node(fwnode))
+- return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
+- val, nval);
+- else if (is_pset_node(fwnode))
+- return pset_prop_read_string_array(to_pset_node(fwnode),
+- propname, val, nval);
+- return -ENXIO;
+-}
+-
+ /**
+ * fwnode_property_read_string_array - return string array property of a node
+ * @fwnode: Firmware node to get the property of
+@@ -581,11 +577,13 @@ int fwnode_property_read_string_array(st
+ {
+ int ret;
+
+- ret = __fwnode_property_read_string_array(fwnode, propname, val, nval);
++ ret = fwnode_call_int_op(fwnode, property_read_string_array, propname,
++ val, nval);
+ if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
+ !IS_ERR_OR_NULL(fwnode->secondary))
+- ret = __fwnode_property_read_string_array(fwnode->secondary,
+- propname, val, nval);
++ ret = fwnode_call_int_op(fwnode->secondary,
++ property_read_string_array, propname,
++ val, nval);
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
+@@ -903,6 +901,7 @@ int device_add_properties(struct device
+ return PTR_ERR(p);
+
+ p->fwnode.type = FWNODE_PDATA;
++ p->fwnode.ops = &pset_fwnode_ops;
+ set_secondary_fwnode(dev, &p->fwnode);
+ return 0;
+ }
+@@ -938,19 +937,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_parent
+ */
+ struct fwnode_handle *fwnode_get_parent(struct fwnode_handle *fwnode)
+ {
+- struct fwnode_handle *parent = NULL;
+-
+- if (is_of_node(fwnode)) {
+- struct device_node *node;
+-
+- node = of_get_parent(to_of_node(fwnode));
+- if (node)
+- parent = &node->fwnode;
+- } else if (is_acpi_node(fwnode)) {
+- parent = acpi_node_get_parent(fwnode);
+- }
+-
+- return parent;
++ return fwnode_call_ptr_op(fwnode, get_parent);
+ }
+ EXPORT_SYMBOL_GPL(fwnode_get_parent);
+
+@@ -962,18 +949,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_parent);
+ struct fwnode_handle *fwnode_get_next_child_node(struct fwnode_handle *fwnode,
+ struct fwnode_handle *child)
+ {
+- if (is_of_node(fwnode)) {
+- struct device_node *node;
+-
+- node = of_get_next_available_child(to_of_node(fwnode),
+- to_of_node(child));
+- if (node)
+- return &node->fwnode;
+- } else if (is_acpi_node(fwnode)) {
+- return acpi_get_next_subnode(fwnode, child);
+- }
+-
+- return NULL;
++ return fwnode_call_ptr_op(fwnode, get_next_child_node, child);
+ }
+ EXPORT_SYMBOL_GPL(fwnode_get_next_child_node);
+
+@@ -1005,23 +981,7 @@ EXPORT_SYMBOL_GPL(device_get_next_child_
+ struct fwnode_handle *fwnode_get_named_child_node(struct fwnode_handle *fwnode,
+ const char *childname)
+ {
+- struct fwnode_handle *child;
+-
+- /*
+- * Find first matching named child node of this fwnode.
+- * For ACPI this will be a data only sub-node.
+- */
+- fwnode_for_each_child_node(fwnode, child) {
+- if (is_of_node(child)) {
+- if (!of_node_cmp(to_of_node(child)->name, childname))
+- return child;
+- } else if (is_acpi_data_node(child)) {
+- if (acpi_data_node_match(child, childname))
+- return child;
+- }
+- }
+-
+- return NULL;
++ return fwnode_call_ptr_op(fwnode, get_named_child_node, childname);
+ }
+ EXPORT_SYMBOL_GPL(fwnode_get_named_child_node);
+
+@@ -1043,8 +1003,7 @@ EXPORT_SYMBOL_GPL(device_get_named_child
+ */
+ void fwnode_handle_get(struct fwnode_handle *fwnode)
+ {
+- if (is_of_node(fwnode))
+- of_node_get(to_of_node(fwnode));
++ fwnode_call_void_op(fwnode, get);
+ }
+ EXPORT_SYMBOL_GPL(fwnode_handle_get);
+
+@@ -1058,8 +1017,7 @@ EXPORT_SYMBOL_GPL(fwnode_handle_get);
+ */
+ void fwnode_handle_put(struct fwnode_handle *fwnode)
+ {
+- if (is_of_node(fwnode))
+- of_node_put(to_of_node(fwnode));
++ fwnode_call_void_op(fwnode, put);
+ }
+ EXPORT_SYMBOL_GPL(fwnode_handle_put);
+
+--- a/drivers/of/base.c
++++ b/drivers/of/base.c
+@@ -2565,3 +2565,93 @@ struct device_node *of_graph_get_remote_
+ return remote;
+ }
+ EXPORT_SYMBOL(of_graph_get_remote_node);
++
++static void of_fwnode_get(struct fwnode_handle *fwnode)
++{
++ of_node_get(to_of_node(fwnode));
++}
++
++static void of_fwnode_put(struct fwnode_handle *fwnode)
++{
++ of_node_put(to_of_node(fwnode));
++}
++
++static bool of_fwnode_property_present(struct fwnode_handle *fwnode,
++ const char *propname)
++{
++ return of_property_read_bool(to_of_node(fwnode), propname);
++}
++
++static int of_fwnode_property_read_int_array(struct fwnode_handle *fwnode,
++ const char *propname,
++ unsigned int elem_size, void *val,
++ size_t nval)
++{
++ struct device_node *node = to_of_node(fwnode);
++
++ if (!val)
++ return of_property_count_elems_of_size(node, propname,
++ elem_size);
++
++ switch (elem_size) {
++ case sizeof(u8):
++ return of_property_read_u8_array(node, propname, val, nval);
++ case sizeof(u16):
++ return of_property_read_u16_array(node, propname, val, nval);
++ case sizeof(u32):
++ return of_property_read_u32_array(node, propname, val, nval);
++ case sizeof(u64):
++ return of_property_read_u64_array(node, propname, val, nval);
++ }
++
++ return -ENXIO;
++}
++
++static int of_fwnode_property_read_string_array(struct fwnode_handle *fwnode,
++ const char *propname,
++ const char **val, size_t nval)
++{
++ struct device_node *node = to_of_node(fwnode);
++
++ return val ?
++ of_property_read_string_array(node, propname, val, nval) :
++ of_property_count_strings(node, propname);
++}
++
++static struct fwnode_handle *of_fwnode_get_parent(struct fwnode_handle *fwnode)
++{
++ return of_fwnode_handle(of_get_parent(to_of_node(fwnode)));
++}
++
++static struct fwnode_handle *
++of_fwnode_get_next_child_node(struct fwnode_handle *fwnode,
++ struct fwnode_handle *child)
++{
++ return of_fwnode_handle(of_get_next_available_child(to_of_node(fwnode),
++ to_of_node(child)));
++}
++
++static struct fwnode_handle *
++of_fwnode_get_named_child_node(struct fwnode_handle *fwnode,
++ const char *childname)
++{
++ struct device_node *node = to_of_node(fwnode);
++ struct device_node *child;
++
++ for_each_available_child_of_node(node, child)
++ if (!of_node_cmp(child->name, childname))
++ return of_fwnode_handle(child);
++
++ return NULL;
++}
++
++const struct fwnode_operations of_fwnode_ops = {
++ .get = of_fwnode_get,
++ .put = of_fwnode_put,
++ .property_present = of_fwnode_property_present,
++ .property_read_int_array = of_fwnode_property_read_int_array,
++ .property_read_string_array = of_fwnode_property_read_string_array,
++ .get_parent = of_fwnode_get_parent,
++ .get_next_child_node = of_fwnode_get_next_child_node,
++ .get_named_child_node = of_fwnode_get_named_child_node,
++};
+--- a/include/linux/acpi.h
++++ b/include/linux/acpi.h
+@@ -57,6 +57,9 @@ static inline acpi_handle acpi_device_ha
+ acpi_fwnode_handle(adev) : NULL)
+ #define ACPI_HANDLE(dev) acpi_device_handle(ACPI_COMPANION(dev))
+
++
++extern const struct fwnode_operations acpi_fwnode_ops;
++
+ static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
+ {
+ struct fwnode_handle *fwnode;
+@@ -66,6 +69,7 @@ static inline struct fwnode_handle *acpi
+ return NULL;
+
+ fwnode->type = FWNODE_ACPI_STATIC;
++ fwnode->ops = &acpi_fwnode_ops;
+
+ return fwnode;
+ }
+--- a/include/linux/fwnode.h
++++ b/include/linux/fwnode.h
+@@ -12,6 +12,8 @@
+ #ifndef _LINUX_FWNODE_H_
+ #define _LINUX_FWNODE_H_
+
++#include <linux/types.h>
++
+ enum fwnode_type {
+ FWNODE_INVALID = 0,
+ FWNODE_OF,
+@@ -22,9 +24,12 @@ enum fwnode_type {
+ FWNODE_IRQCHIP
+ };
+
++struct fwnode_operations;
++
+ struct fwnode_handle {
+ enum fwnode_type type;
+ struct fwnode_handle *secondary;
++ const struct fwnode_operations *ops;
+ };
+
+ /**
+@@ -39,4 +44,53 @@ struct fwnode_endpoint {
+ const struct fwnode_handle *local_fwnode;
+ };
+
++/**
++ * struct fwnode_operations - Operations for fwnode interface
++ * @get: Get a reference to an fwnode.
++ * @put: Put a reference to an fwnode.
++ * @property_present: Return true if a property is present.
++ * @property_read_integer_array: Read an array of integer properties. Return
++ * zero on success, a negative error code
++ * otherwise.
++ * @property_read_string_array: Read an array of string properties. Return zero
++ * on success, a negative error code otherwise.
++ * @get_parent: Return the parent of an fwnode.
++ * @get_next_child_node: Return the next child node in an iteration.
++ * @get_named_child_node: Return a child node with a given name.
++ */
++struct fwnode_operations {
++ void (*get)(struct fwnode_handle *fwnode);
++ void (*put)(struct fwnode_handle *fwnode);
++ bool (*property_present)(struct fwnode_handle *fwnode,
++ const char *propname);
++ int (*property_read_int_array)(struct fwnode_handle *fwnode,
++ const char *propname,
++ unsigned int elem_size, void *val,
++ size_t nval);
++ int (*property_read_string_array)(struct fwnode_handle *fwnode_handle,
++ const char *propname,
++ const char **val, size_t nval);
++ struct fwnode_handle *(*get_parent)(struct fwnode_handle *fwnode);
++ struct fwnode_handle *
++ (*get_next_child_node)(struct fwnode_handle *fwnode,
++ struct fwnode_handle *child);
++ struct fwnode_handle *
++ (*get_named_child_node)(struct fwnode_handle *fwnode, const char *name);
++};
++
++#define fwnode_has_op(fwnode, op) \
++ ((fwnode) && (fwnode)->ops && (fwnode)->ops->op)
++#define fwnode_call_int_op(fwnode, op, ...) \
++ (fwnode ? (fwnode_has_op(fwnode, op) ? \
++ (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : -ENXIO) : \
++ -EINVAL)
++#define fwnode_call_ptr_op(fwnode, op, ...) \
++ (fwnode_has_op(fwnode, op) ? \
++ (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : NULL)
++#define fwnode_call_void_op(fwnode, op, ...) \
++ do { \
++ if (fwnode_has_op(fwnode, op)) \
++ (fwnode)->ops->op(fwnode, ## __VA_ARGS__); \
++ } while (false)
++
+ #endif
+--- a/include/linux/of.h
++++ b/include/linux/of.h
+@@ -100,10 +100,12 @@ struct of_reconfig_data {
+
+ /* initialize a node */
+ extern struct kobj_type of_node_ktype;
++extern const struct fwnode_operations of_fwnode_ops;
+ static inline void of_node_init(struct device_node *node)
+ {
+ kobject_init(&node->kobj, &of_node_ktype);
+ node->fwnode.type = FWNODE_OF;
++ node->fwnode.ops = &of_fwnode_ops;
+ }
+
+ /* true when node is initialized */
diff --git a/patches.drivers/device-property-Move-fwnode-graph-ops-to-firmware-sp.patch b/patches.drivers/device-property-Move-fwnode-graph-ops-to-firmware-sp.patch
new file mode 100644
index 0000000000..d74bc3c877
--- /dev/null
+++ b/patches.drivers/device-property-Move-fwnode-graph-ops-to-firmware-sp.patch
@@ -0,0 +1,303 @@
+From: Sakari Ailus <sakari.ailus@linux.intel.com>
+Date: Tue, 6 Jun 2017 12:37:38 +0300
+Subject: device property: Move fwnode graph ops to firmware specific locations
+Patch-mainline: v4.13-rc1
+Git-commit: 3b27d00e7b6d7c889d87fd00df600c495b968e30
+References: bsc#1098633
+
+Move firmware specific implementations of the fwnode graph operations to
+firmware specific locations.
+
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/acpi/property.c | 40 +++++++++++++++++++++
+ drivers/base/property.c | 91 ++++--------------------------------------------
+ drivers/of/base.c | 52 +++++++++++++++++++++++++++
+ include/linux/fwnode.h | 14 +++++++
+ 4 files changed, 114 insertions(+), 83 deletions(-)
+
+--- a/drivers/acpi/property.c
++++ b/drivers/acpi/property.c
+@@ -1179,6 +1179,42 @@ acpi_fwnode_get_named_child_node(struct
+ return NULL;
+ }
+
++static struct fwnode_handle *
++acpi_fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode,
++ struct fwnode_handle *prev)
++{
++ struct fwnode_handle *endpoint;
++
++ endpoint = acpi_graph_get_next_endpoint(fwnode, prev);
++ if (IS_ERR(endpoint))
++ return NULL;
++
++ return endpoint;
++}
++
++static struct fwnode_handle *
++acpi_fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode)
++{
++ struct fwnode_handle *endpoint = NULL;
++
++ acpi_graph_get_remote_endpoint(fwnode, NULL, NULL, &endpoint);
++
++ return endpoint;
++}
++
++static int acpi_fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
++ struct fwnode_endpoint *endpoint)
++{
++ struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode);
++
++ endpoint->local_fwnode = fwnode;
++
++ fwnode_property_read_u32(port_fwnode, "port", &endpoint->port);
++ fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id);
++
++ return 0;
++}
++
+ const struct fwnode_operations acpi_fwnode_ops = {
+ .property_present = acpi_fwnode_property_present,
+ .property_read_int_array = acpi_fwnode_property_read_int_array,
+@@ -1186,4 +1222,8 @@ const struct fwnode_operations acpi_fwno
+ .get_parent = acpi_node_get_parent,
+ .get_next_child_node = acpi_get_next_subnode,
+ .get_named_child_node = acpi_fwnode_get_named_child_node,
++ .graph_get_next_endpoint = acpi_fwnode_graph_get_next_endpoint,
++ .graph_get_remote_endpoint = acpi_fwnode_graph_get_remote_endpoint,
++ .graph_get_port_parent = acpi_node_get_parent,
++ .graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint,
+ };
+--- a/drivers/base/property.c
++++ b/drivers/base/property.c
+@@ -1156,24 +1156,7 @@ struct fwnode_handle *
+ fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode,
+ struct fwnode_handle *prev)
+ {
+- struct fwnode_handle *endpoint = NULL;
+-
+- if (is_of_node(fwnode)) {
+- struct device_node *node;
+-
+- node = of_graph_get_next_endpoint(to_of_node(fwnode),
+- to_of_node(prev));
+-
+- if (node)
+- endpoint = &node->fwnode;
+- } else if (is_acpi_node(fwnode)) {
+- endpoint = acpi_graph_get_next_endpoint(fwnode, prev);
+- if (IS_ERR(endpoint))
+- endpoint = NULL;
+- }
+-
+- return endpoint;
+-
++ return fwnode_call_ptr_op(fwnode, graph_get_next_endpoint, prev);
+ }
+ EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
+
+@@ -1186,22 +1169,12 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_next_
+ struct fwnode_handle *
+ fwnode_graph_get_remote_port_parent(struct fwnode_handle *fwnode)
+ {
+- struct fwnode_handle *parent = NULL;
++ struct fwnode_handle *port, *parent;
+
+- if (is_of_node(fwnode)) {
+- struct device_node *node;
++ port = fwnode_graph_get_remote_port(fwnode);
++ parent = fwnode_call_ptr_op(port, graph_get_port_parent);
+
+- node = of_graph_get_remote_port_parent(to_of_node(fwnode));
+- if (node)
+- parent = &node->fwnode;
+- } else if (is_acpi_node(fwnode)) {
+- int ret;
+-
+- ret = acpi_graph_get_remote_endpoint(fwnode, &parent, NULL,
+- NULL);
+- if (ret)
+- return NULL;
+- }
++ fwnode_handle_put(port);
+
+ return parent;
+ }
+@@ -1215,23 +1188,7 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remot
+ */
+ struct fwnode_handle *fwnode_graph_get_remote_port(struct fwnode_handle *fwnode)
+ {
+- struct fwnode_handle *port = NULL;
+-
+- if (is_of_node(fwnode)) {
+- struct device_node *node;
+-
+- node = of_graph_get_remote_port(to_of_node(fwnode));
+- if (node)
+- port = &node->fwnode;
+- } else if (is_acpi_node(fwnode)) {
+- int ret;
+-
+- ret = acpi_graph_get_remote_endpoint(fwnode, NULL, &port, NULL);
+- if (ret)
+- return NULL;
+- }
+-
+- return port;
++ return fwnode_get_next_parent(fwnode_graph_get_remote_endpoint(fwnode));
+ }
+ EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port);
+
+@@ -1244,25 +1201,7 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remot
+ struct fwnode_handle *
+ fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode)
+ {
+- struct fwnode_handle *endpoint = NULL;
+-
+- if (is_of_node(fwnode)) {
+- struct device_node *node;
+-
+- node = of_parse_phandle(to_of_node(fwnode), "remote-endpoint",
+- 0);
+- if (node)
+- endpoint = &node->fwnode;
+- } else if (is_acpi_node(fwnode)) {
+- int ret;
+-
+- ret = acpi_graph_get_remote_endpoint(fwnode, NULL, NULL,
+- &endpoint);
+- if (ret)
+- return NULL;
+- }
+-
+- return endpoint;
++ return fwnode_call_ptr_op(fwnode, graph_get_remote_endpoint);
+ }
+ EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint);
+
+@@ -1278,22 +1217,8 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remot
+ int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
+ struct fwnode_endpoint *endpoint)
+ {
+- struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode);
+-
+ memset(endpoint, 0, sizeof(*endpoint));
+
+- endpoint->local_fwnode = fwnode;
+-
+- if (is_acpi_node(port_fwnode)) {
+- fwnode_property_read_u32(port_fwnode, "port", &endpoint->port);
+- fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id);
+- } else {
+- fwnode_property_read_u32(port_fwnode, "reg", &endpoint->port);
+- fwnode_property_read_u32(fwnode, "reg", &endpoint->id);
+- }
+-
+- fwnode_handle_put(port_fwnode);
+-
+- return 0;
++ return fwnode_call_int_op(fwnode, graph_parse_endpoint, endpoint);
+ }
+ EXPORT_SYMBOL(fwnode_graph_parse_endpoint);
+--- a/drivers/of/base.c
++++ b/drivers/of/base.c
+@@ -2645,6 +2645,54 @@ of_fwnode_get_named_child_node(struct fw
+ return NULL;
+ }
+
++static struct fwnode_handle *
++of_fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode,
++ struct fwnode_handle *prev)
++{
++ return of_fwnode_handle(of_graph_get_next_endpoint(to_of_node(fwnode),
++ to_of_node(prev)));
++}
++
++static struct fwnode_handle *
++of_fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode)
++{
++ return of_fwnode_handle(of_parse_phandle(to_of_node(fwnode),
++ "remote-endpoint", 0));
++}
++
++static struct fwnode_handle *
++of_fwnode_graph_get_port_parent(struct fwnode_handle *fwnode)
++{
++ struct device_node *np;
++
++ /* Get the parent of the port */
++ np = of_get_next_parent(to_of_node(fwnode));
++ if (!np)
++ return NULL;
++
++ /* Is this the "ports" node? If not, it's the port parent. */
++ if (of_node_cmp(np->name, "ports"))
++ return of_fwnode_handle(np);
++
++ return of_fwnode_handle(of_get_next_parent(np));
++}
++
++static int of_fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
++ struct fwnode_endpoint *endpoint)
++{
++ struct device_node *node = to_of_node(fwnode);
++ struct device_node *port_node = of_get_parent(node);
++
++ endpoint->local_fwnode = fwnode;
++
++ of_property_read_u32(port_node, "reg", &endpoint->port);
++ of_property_read_u32(node, "reg", &endpoint->id);
++
++ of_node_put(port_node);
++
++ return 0;
++}
++
+ const struct fwnode_operations of_fwnode_ops = {
+ .get = of_fwnode_get,
+ .put = of_fwnode_put,
+@@ -2654,4 +2702,8 @@ const struct fwnode_operations of_fwnode
+ .get_parent = of_fwnode_get_parent,
+ .get_next_child_node = of_fwnode_get_next_child_node,
+ .get_named_child_node = of_fwnode_get_named_child_node,
++ .graph_get_next_endpoint = of_fwnode_graph_get_next_endpoint,
++ .graph_get_remote_endpoint = of_fwnode_graph_get_remote_endpoint,
++ .graph_get_port_parent = of_fwnode_graph_get_port_parent,
++ .graph_parse_endpoint = of_fwnode_graph_parse_endpoint,
+ };
+--- a/include/linux/fwnode.h
++++ b/include/linux/fwnode.h
+@@ -57,6 +57,11 @@ struct fwnode_endpoint {
+ * @get_parent: Return the parent of an fwnode.
+ * @get_next_child_node: Return the next child node in an iteration.
+ * @get_named_child_node: Return a child node with a given name.
++ * @graph_get_next_endpoint: Return an endpoint node in an iteration.
++ * @graph_get_remote_endpoint: Return the remote endpoint node of a local
++ * endpoint node.
++ * @graph_get_port_parent: Return the parent node of a port node.
++ * @graph_parse_endpoint: Parse endpoint for port and endpoint id.
+ */
+ struct fwnode_operations {
+ void (*get)(struct fwnode_handle *fwnode);
+@@ -76,6 +81,15 @@ struct fwnode_operations {
+ struct fwnode_handle *child);
+ struct fwnode_handle *
+ (*get_named_child_node)(struct fwnode_handle *fwnode, const char *name);
++ struct fwnode_handle *
++ (*graph_get_next_endpoint)(struct fwnode_handle *fwnode,
++ struct fwnode_handle *prev);
++ struct fwnode_handle *
++ (*graph_get_remote_endpoint)(struct fwnode_handle *fwnode);
++ struct fwnode_handle *
++ (*graph_get_port_parent)(struct fwnode_handle *fwnode);
++ int (*graph_parse_endpoint)(struct fwnode_handle *fwnode,
++ struct fwnode_endpoint *endpoint);
+ };
+
+ #define fwnode_has_op(fwnode, op) \
diff --git a/patches.drivers/device-property-Track-owner-device-of-device-propert.patch b/patches.drivers/device-property-Track-owner-device-of-device-propert.patch
index 14c6999d26..25a6f42d0d 100644
--- a/patches.drivers/device-property-Track-owner-device-of-device-propert.patch
+++ b/patches.drivers/device-property-Track-owner-device-of-device-propert.patch
@@ -54,11 +54,9 @@ Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Michal Suchanek <msuchanek@suse.de>
---
- drivers/base/property.c | 15 +++++++++------
+ drivers/base/property.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
-diff --git a/drivers/base/property.c b/drivers/base/property.c
-index 149de311a10e..80973a6d4757 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -21,6 +21,7 @@
@@ -69,7 +67,7 @@ index 149de311a10e..80973a6d4757 100644
struct fwnode_handle fwnode;
const struct property_entry *properties;
};
-@@ -857,6 +858,7 @@ static struct property_set *pset_copy_set(const struct property_set *pset)
+@@ -855,6 +856,7 @@ static struct property_set *pset_copy_se
void device_remove_properties(struct device *dev)
{
struct fwnode_handle *fwnode;
@@ -77,7 +75,7 @@ index 149de311a10e..80973a6d4757 100644
fwnode = dev_fwnode(dev);
if (!fwnode)
-@@ -866,16 +868,16 @@ void device_remove_properties(struct device *dev)
+@@ -864,16 +866,16 @@ void device_remove_properties(struct dev
* the pset. If there is no real firmware node (ACPI/DT) primary
* will hold the pset.
*/
@@ -100,14 +98,11 @@ index 149de311a10e..80973a6d4757 100644
}
EXPORT_SYMBOL_GPL(device_remove_properties);
-@@ -904,6 +906,7 @@ int device_add_properties(struct device *dev,
-
+@@ -903,6 +905,7 @@ int device_add_properties(struct device
p->fwnode.type = FWNODE_PDATA;
+ p->fwnode.ops = &pset_fwnode_ops;
set_secondary_fwnode(dev, &p->fwnode);
+ p->dev = dev;
return 0;
}
EXPORT_SYMBOL_GPL(device_add_properties);
---
-2.13.6
-
diff --git a/patches.drivers/device-property-preserve-usecount-for-node-passed-to.patch b/patches.drivers/device-property-preserve-usecount-for-node-passed-to.patch
new file mode 100644
index 0000000000..db1c5a77d5
--- /dev/null
+++ b/patches.drivers/device-property-preserve-usecount-for-node-passed-to.patch
@@ -0,0 +1,37 @@
+From: =?UTF-8?q?Niklas=20S=C3=B6derlund?=
+Date: Tue, 22 Aug 2017 02:19:12 +0200
+ <niklas.soderlund+renesas@ragnatech.se>
+Subject: device property: preserve usecount for node passed to
+ of_fwnode_graph_get_port_parent()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+Patch-mainline: v4.14-rc5
+Git-commit: 3314c6bdd26880e0dfbcb0cb85a1b36d185ce47c
+References: bsc#1098633
+
+Using CONFIG_OF_DYNAMIC=y uncovered an imbalance in the usecount of the
+node being passed to of_fwnode_graph_get_port_parent(). Preserve the
+usecount by using of_get_parent() instead of of_get_next_parent() which
+don't decrement the usecount of the node passed to it.
+
+Fixes: 3b27d00e7b6d7c88 ("device property: Move fwnode graph ops to firmware specific locations")
+Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/of/base.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/of/base.c
++++ b/drivers/of/base.c
+@@ -2671,7 +2671,7 @@ of_fwnode_graph_get_port_parent(struct f
+ struct device_node *np;
+
+ /* Get the parent of the port */
+- np = of_get_next_parent(to_of_node(fwnode));
++ np = of_get_parent(to_of_node(fwnode));
+ if (!np)
+ return NULL;
+
diff --git a/patches.drivers/enic-do-not-overwrite-error-code.patch b/patches.drivers/enic-do-not-overwrite-error-code.patch
new file mode 100644
index 0000000000..b7571bf966
--- /dev/null
+++ b/patches.drivers/enic-do-not-overwrite-error-code.patch
@@ -0,0 +1,44 @@
+From: Govindarajulu Varadarajan <gvaradar@cisco.com>
+Date: Mon, 18 Jun 2018 10:01:05 -0700
+Subject: enic: do not overwrite error code
+Patch-mainline: v4.18-rc2
+Git-commit: 56f772279a762984f6e9ebbf24a7c829faba5712
+References: bsc#1037697
+
+In failure path, we overwrite err to what vnic_rq_disable() returns. In
+case it returns 0, enic_open() returns success in case of error.
+
+Reported-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Fixes: e8588e268509 ("enic: enable rq before updating rq descriptors")
+Signed-off-by: Govindarajulu Varadarajan <gvaradar@cisco.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/cisco/enic/enic_main.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/cisco/enic/enic_main.c
++++ b/drivers/net/ethernet/cisco/enic/enic_main.c
+@@ -1879,7 +1879,7 @@ static int enic_open(struct net_device *
+ {
+ struct enic *enic = netdev_priv(netdev);
+ unsigned int i;
+- int err;
++ int err, ret;
+
+ err = enic_request_intr(enic);
+ if (err) {
+@@ -1936,10 +1936,9 @@ static int enic_open(struct net_device *
+
+ err_out_free_rq:
+ for (i = 0; i < enic->rq_count; i++) {
+- err = vnic_rq_disable(&enic->rq[i]);
+- if (err)
+- return err;
+- vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
++ ret = vnic_rq_disable(&enic->rq[i]);
++ if (!ret)
++ vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
+ }
+ enic_dev_notify_unset(enic);
+ err_out_free_intr:
diff --git a/patches.drivers/enic-enable-rq-before-updating-rq-descriptors.patch b/patches.drivers/enic-enable-rq-before-updating-rq-descriptors.patch
new file mode 100644
index 0000000000..ce9bd75905
--- /dev/null
+++ b/patches.drivers/enic-enable-rq-before-updating-rq-descriptors.patch
@@ -0,0 +1,51 @@
+From: Govindarajulu Varadarajan <gvaradar@cisco.com>
+Date: Thu, 1 Mar 2018 11:07:23 -0800
+Subject: enic: enable rq before updating rq descriptors
+Patch-mainline: v4.17-rc1
+Git-commit: e8588e268509292550634d9a35f2723a207683b2
+References: bsc#1037697
+
+rq should be enabled before posting the buffers to rq desc. If not hw sees
+stale value and casuses DMAR errors.
+
+Signed-off-by: Govindarajulu Varadarajan <gvaradar@cisco.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/cisco/enic/enic_main.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/cisco/enic/enic_main.c
++++ b/drivers/net/ethernet/cisco/enic/enic_main.c
+@@ -1897,6 +1897,8 @@ static int enic_open(struct net_device *
+ }
+
+ for (i = 0; i < enic->rq_count; i++) {
++ /* enable rq before updating rq desc */
++ vnic_rq_enable(&enic->rq[i]);
+ vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf);
+ /* Need at least one buffer on ring to get going */
+ if (vnic_rq_desc_used(&enic->rq[i]) == 0) {
+@@ -1908,8 +1910,6 @@ static int enic_open(struct net_device *
+
+ for (i = 0; i < enic->wq_count; i++)
+ vnic_wq_enable(&enic->wq[i]);
+- for (i = 0; i < enic->rq_count; i++)
+- vnic_rq_enable(&enic->rq[i]);
+
+ if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic))
+ enic_dev_add_station_addr(enic);
+@@ -1935,8 +1935,12 @@ static int enic_open(struct net_device *
+ return 0;
+
+ err_out_free_rq:
+- for (i = 0; i < enic->rq_count; i++)
++ for (i = 0; i < enic->rq_count; i++) {
++ err = vnic_rq_disable(&enic->rq[i]);
++ if (err)
++ return err;
+ vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
++ }
+ enic_dev_notify_unset(enic);
+ err_out_free_intr:
+ enic_unset_affinity_hint(enic);
diff --git a/patches.drivers/libnvdimm-add-an-api-to-cast-a-struct-nd_region-to-i.patch b/patches.drivers/libnvdimm-add-an-api-to-cast-a-struct-nd_region-to-i.patch
new file mode 100644
index 0000000000..22e6b7eab1
--- /dev/null
+++ b/patches.drivers/libnvdimm-add-an-api-to-cast-a-struct-nd_region-to-i.patch
@@ -0,0 +1,60 @@
+From: Dan Williams <dan.j.williams@intel.com>
+Date: Mon, 2 Apr 2018 13:14:25 -0700
+Subject: libnvdimm: add an api to cast a 'struct nd_region' to its 'struct
+ device'
+Patch-mainline: v4.17-rc1
+Git-commit: 243f29fe449bbead69076ad861dbe8f51b42c4d7
+References: bsc#1094119
+
+For debug, it is useful for bus providers to be able to retrieve the
+'struct device' associated with an nd_region instance that it
+registered. We already have to_nd_region() to perform the reverse cast
+operation, in fact its duplicate declaration can be removed from the
+private drivers/nvdimm/nd.h header.
+
+Reviewed-by: Dave Jiang <dave.jiang@intel.com>
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+Acked-by: Johannes Thumshirn <jthumshirn@suse.de>
+---
+ drivers/nvdimm/nd.h | 1 -
+ drivers/nvdimm/region_devs.c | 8 ++++++++
+ include/linux/libnvdimm.h | 1 +
+ 3 files changed, 9 insertions(+), 1 deletion(-)
+
+--- a/drivers/nvdimm/nd.h
++++ b/drivers/nvdimm/nd.h
+@@ -339,7 +339,6 @@ static inline struct device *nd_dax_crea
+ }
+ #endif
+
+-struct nd_region *to_nd_region(struct device *dev);
+ int nd_region_to_nstype(struct nd_region *nd_region);
+ int nd_region_register_namespaces(struct nd_region *nd_region, int *err);
+ u64 nd_region_interleave_set_cookie(struct nd_region *nd_region,
+--- a/drivers/nvdimm/region_devs.c
++++ b/drivers/nvdimm/region_devs.c
+@@ -178,6 +178,14 @@ struct nd_region *to_nd_region(struct de
+ }
+ EXPORT_SYMBOL_GPL(to_nd_region);
+
++struct device *nd_region_dev(struct nd_region *nd_region)
++{
++ if (!nd_region)
++ return NULL;
++ return &nd_region->dev;
++}
++EXPORT_SYMBOL_GPL(nd_region_dev);
++
+ struct nd_blk_region *to_nd_blk_region(struct device *dev)
+ {
+ struct nd_region *nd_region = to_nd_region(dev);
+--- a/include/linux/libnvdimm.h
++++ b/include/linux/libnvdimm.h
+@@ -148,6 +148,7 @@ void nvdimm_bus_unregister(struct nvdimm
+ struct nvdimm_bus *to_nvdimm_bus(struct device *dev);
+ struct nvdimm *to_nvdimm(struct device *dev);
+ struct nd_region *to_nd_region(struct device *dev);
++struct device *nd_region_dev(struct nd_region *nd_region);
+ struct nd_blk_region *to_nd_blk_region(struct device *dev);
+ struct nvdimm_bus_descriptor *to_nd_desc(struct nvdimm_bus *nvdimm_bus);
+ struct device *to_nvdimm_bus_dev(struct nvdimm_bus *nvdimm_bus);
diff --git a/patches.drivers/mvpp2-fix-multicast-address-filter.patch b/patches.drivers/mvpp2-fix-multicast-address-filter.patch
new file mode 100644
index 0000000000..90ceada825
--- /dev/null
+++ b/patches.drivers/mvpp2-fix-multicast-address-filter.patch
@@ -0,0 +1,54 @@
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Sun, 11 Feb 2018 18:10:28 -0500
+Subject: mvpp2: fix multicast address filter
+Patch-mainline: v4.16-rc3
+Git-commit: 7ac8ff95f48cbfa609a060fd6a1e361dd62feeb3
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- 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
+ 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
+ /* 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;
++ }
++ }
+ }
+ }
+
diff --git a/patches.drivers/net-cxgb3_main-fix-potential-Spectre-v1.patch b/patches.drivers/net-cxgb3_main-fix-potential-Spectre-v1.patch
new file mode 100644
index 0000000000..dafc8fcd3b
--- /dev/null
+++ b/patches.drivers/net-cxgb3_main-fix-potential-Spectre-v1.patch
@@ -0,0 +1,50 @@
+From: "Gustavo A. R. Silva" <gustavo@embeddedor.com>
+Date: Mon, 16 Jul 2018 20:59:58 -0500
+Subject: net: cxgb3_main: fix potential Spectre v1
+Patch-mainline: v4.18-rc6
+Git-commit: 676bcfece19f83621e905aa55b5ed2d45cc4f2d3
+References: bsc#1046533 FATE#322936
+
+t.qset_idx can be indirectly controlled by user-space, hence leading to
+a potential exploitation of the Spectre variant 1 vulnerability.
+
+This issue was detected with the help of Smatch:
+
+drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c:2286 cxgb_extension_ioctl()
+warn: potential spectre issue 'adapter->msix_info'
+
+Fix this by sanitizing t.qset_idx before using it to index
+adapter->msix_info
+
+Notice that given that speculation windows are large, the policy is
+to kill the speculation on the first load and not worry if it can be
+completed with a dependent load/store [1].
+
+[1] https://marc.info/?l=linux-kernel&m=152449131114778&w=2
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+@@ -51,6 +51,7 @@
+ #include <linux/sched.h>
+ #include <linux/slab.h>
+ #include <linux/uaccess.h>
++#include <linux/nospec.h>
+
+ #include "common.h"
+ #include "cxgb3_ioctl.h"
+@@ -2264,6 +2265,7 @@ static int cxgb_extension_ioctl(struct n
+
+ if (t.qset_idx >= nqsets)
+ return -EINVAL;
++ t.qset_idx = array_index_nospec(t.qset_idx, nqsets);
+
+ q = &adapter->params.sge.qset[q1 + t.qset_idx];
+ t.rspq_size = q->rspq_size;
diff --git a/patches.drivers/net-define-the-TSO-header-size-in-net-tso.h.patch b/patches.drivers/net-define-the-TSO-header-size-in-net-tso.h.patch
new file mode 100644
index 0000000000..dbb61421c1
--- /dev/null
+++ b/patches.drivers/net-define-the-TSO-header-size-in-net-tso.h.patch
@@ -0,0 +1,75 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Wed, 23 Aug 2017 09:46:54 +0200
+Subject: net: define the TSO header size in net/tso.h
+Patch-mainline: v4.14-rc1
+Git-commit: f9cbe9a556afca9e82df9aebe4412d93769566b5
+References: bsc#1098633
+
+The TSO header size was defined in many drivers. Factorize the code and
+define its size in net/tso.h.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/cavium/thunder/nicvf_queues.h | 1 -
+ drivers/net/ethernet/freescale/fec_main.c | 1 -
+ drivers/net/ethernet/marvell/mv643xx_eth.c | 2 --
+ drivers/net/ethernet/marvell/mvneta.c | 3 ---
+ include/net/tso.h | 2 ++
+ 5 files changed, 2 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
+@@ -277,7 +277,6 @@ struct snd_queue {
+ u16 xdp_free_cnt;
+ bool is_xdp;
+
+-#define TSO_HEADER_SIZE 128
+ /* For TSO segment's header */
+ char *tso_hdrs;
+ dma_addr_t tso_hdrs_phys;
+--- a/drivers/net/ethernet/freescale/fec_main.c
++++ b/drivers/net/ethernet/freescale/fec_main.c
+@@ -223,7 +223,6 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet
+
+ #define COPYBREAK_DEFAULT 256
+
+-#define TSO_HEADER_SIZE 128
+ /* Max number of allowed TCP segments for software TSO */
+ #define FEC_MAX_TSO_SEGS 100
+ #define FEC_MAX_SKB_DESCS (FEC_MAX_TSO_SEGS * 2 + MAX_SKB_FRAGS)
+--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
++++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
+@@ -183,8 +183,6 @@ static char mv643xx_eth_driver_version[]
+ #define DEFAULT_TX_QUEUE_SIZE 512
+ #define SKB_DMA_REALIGN ((PAGE_SIZE - NET_SKB_PAD) % SMP_CACHE_BYTES)
+
+-#define TSO_HEADER_SIZE 128
+-
+ /* Max number of allowed TCP segments for software TSO */
+ #define MV643XX_MAX_TSO_SEGS 100
+ #define MV643XX_MAX_SKB_DESCS (MV643XX_MAX_TSO_SEGS * 2 + MAX_SKB_FRAGS)
+--- a/drivers/net/ethernet/marvell/mvneta.c
++++ b/drivers/net/ethernet/marvell/mvneta.c
+@@ -281,9 +281,6 @@
+ */
+ #define MVNETA_RSS_LU_TABLE_SIZE 1
+
+-/* TSO header size */
+-#define TSO_HEADER_SIZE 128
+-
+ /* Max number of Rx descriptors */
+ #define MVNETA_MAX_RXD 128
+
+--- a/include/net/tso.h
++++ b/include/net/tso.h
+@@ -3,6 +3,8 @@
+
+ #include <net/ip.h>
+
++#define TSO_HEADER_SIZE 128
++
+ struct tso_t {
+ int next_frag_idx;
+ void *data;
diff --git a/patches.drivers/net-mlx5-Protect-from-command-bit-overflow.patch b/patches.drivers/net-mlx5-Protect-from-command-bit-overflow.patch
new file mode 100644
index 0000000000..236659c6fd
--- /dev/null
+++ b/patches.drivers/net-mlx5-Protect-from-command-bit-overflow.patch
@@ -0,0 +1,57 @@
+From: Leon Romanovsky <leonro@mellanox.com>
+Date: Tue, 2 Jan 2018 16:49:56 +0200
+Subject: net/mlx5: Protect from command bit overflow
+Patch-mainline: v4.17-rc1
+Git-commit: 957f6ba8adc7be401a74ccff427e4cfd88d3bfcb
+References: bsc#1046303 FATE#322944
+
+The system with CONFIG_UBSAN enabled on produces the following error
+during driver initialization. The reason to it that max_reg_cmds can be
+larger enough to cause to "1 << max_reg_cmds" overflow the unsigned long.
+
+================================================================================
+UBSAN: Undefined behaviour in drivers/net/ethernet/mellanox/mlx5/core/cmd.c:1805:42
+signed integer overflow:
+-2147483648 - 1 cannot be represented in type 'int'
+CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.15.0-rc2-00032-g06cda2358d9b-dirty #724
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014
+Call Trace:
+ dump_stack+0xe9/0x18f
+ ? dma_virt_alloc+0x81/0x81
+ ubsan_epilogue+0xe/0x4e
+ handle_overflow+0x187/0x20c
+ mlx5_cmd_init+0x73a/0x12b0
+ mlx5_load_one+0x1c3d/0x1d30
+ init_one+0xd02/0xf10
+ pci_device_probe+0x26c/0x3b0
+ driver_probe_device+0x622/0xb40
+ __driver_attach+0x175/0x1b0
+ bus_for_each_dev+0xef/0x190
+ bus_add_driver+0x2db/0x490
+ driver_register+0x16b/0x1e0
+ __pci_register_driver+0x177/0x1b0
+ init+0x6d/0x92
+ do_one_initcall+0x15b/0x270
+ kernel_init_freeable+0x2d8/0x3d0
+ kernel_init+0x14/0x190
+ ret_from_fork+0x24/0x30
+================================================================================
+
+Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
+Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+@@ -1802,7 +1802,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *
+
+ cmd->checksum_disabled = 1;
+ cmd->max_reg_cmds = (1 << cmd->log_sz) - 1;
+- cmd->bitmask = (1 << cmd->max_reg_cmds) - 1;
++ cmd->bitmask = (1UL << cmd->max_reg_cmds) - 1;
+
+ cmd->cmdif_rev = ioread32be(&dev->iseg->cmdif_rev_fw_sub) >> 16;
+ if (cmd->cmdif_rev > CMD_IF_REV) {
diff --git a/patches.drivers/net-mvmdio-add-xmdio-xsmi-support.patch b/patches.drivers/net-mvmdio-add-xmdio-xsmi-support.patch
new file mode 100644
index 0000000000..52718ba249
--- /dev/null
+++ b/patches.drivers/net-mvmdio-add-xmdio-xsmi-support.patch
@@ -0,0 +1,210 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Thu, 15 Jun 2017 16:43:23 +0200
+Subject: net: mvmdio: add xmdio xsmi support
+Patch-mainline: v4.13-rc1
+Git-commit: c0ac08f533e6995e1bc14e67cd3c21ad07dd9214
+References: bsc#1098633
+
+This patch adds the xmdio xsmi interface support in the mvmdio driver.
+This interface is used in Ethernet controllers on Marvell 370, 7k and 8k
+(as of now). The xsmi interface supported by this driver complies with
+the IEEE 802.3 clause 45. The xSMI interface is used by 10GbE devices.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvmdio.c | 112 +++++++++++++++++++++++++++++++---
+ 1 file changed, 105 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvmdio.c
++++ b/drivers/net/ethernet/marvell/mvmdio.c
+@@ -23,6 +23,7 @@
+ #include <linux/io.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
++#include <linux/of_device.h>
+ #include <linux/of_mdio.h>
+ #include <linux/phy.h>
+ #include <linux/platform_device.h>
+@@ -40,6 +41,15 @@
+ #define MVMDIO_ERR_INT_SMI_DONE 0x00000010
+ #define MVMDIO_ERR_INT_MASK 0x0080
+
++#define MVMDIO_XSMI_MGNT_REG 0x0
++#define MVMDIO_XSMI_PHYADDR_SHIFT 16
++#define MVMDIO_XSMI_DEVADDR_SHIFT 21
++#define MVMDIO_XSMI_WRITE_OPERATION (0x5 << 26)
++#define MVMDIO_XSMI_READ_OPERATION (0x7 << 26)
++#define MVMDIO_XSMI_READ_VALID BIT(29)
++#define MVMDIO_XSMI_BUSY BIT(30)
++#define MVMDIO_XSMI_ADDR_REG 0x8
++
+ /*
+ * SMI Timeout measurements:
+ * - Kirkwood 88F6281 (Globalscale Dreamplug): 45us to 95us (Interrupt)
+@@ -49,6 +59,9 @@
+ #define MVMDIO_SMI_POLL_INTERVAL_MIN 45
+ #define MVMDIO_SMI_POLL_INTERVAL_MAX 55
+
++#define MVMDIO_XSMI_POLL_INTERVAL_MIN 150
++#define MVMDIO_XSMI_POLL_INTERVAL_MAX 160
++
+ struct orion_mdio_dev {
+ void __iomem *regs;
+ struct clk *clk[3];
+@@ -62,6 +75,11 @@ struct orion_mdio_dev {
+ wait_queue_head_t smi_busy_wait;
+ };
+
++enum orion_mdio_bus_type {
++ BUS_TYPE_SMI,
++ BUS_TYPE_XSMI
++};
++
+ struct orion_mdio_ops {
+ int (*is_done)(struct orion_mdio_dev *);
+ unsigned int poll_interval_min;
+@@ -119,8 +137,8 @@ static const struct orion_mdio_ops orion
+ .poll_interval_max = MVMDIO_SMI_POLL_INTERVAL_MAX,
+ };
+
+-static int orion_mdio_read(struct mii_bus *bus, int mii_id,
+- int regnum)
++static int orion_mdio_smi_read(struct mii_bus *bus, int mii_id,
++ int regnum)
+ {
+ struct orion_mdio_dev *dev = bus->priv;
+ u32 val;
+@@ -154,8 +172,8 @@ out:
+ return ret;
+ }
+
+-static int orion_mdio_write(struct mii_bus *bus, int mii_id,
+- int regnum, u16 value)
++static int orion_mdio_smi_write(struct mii_bus *bus, int mii_id,
++ int regnum, u16 value)
+ {
+ struct orion_mdio_dev *dev = bus->priv;
+ int ret;
+@@ -177,6 +195,73 @@ out:
+ return ret;
+ }
+
++static int orion_mdio_xsmi_is_done(struct orion_mdio_dev *dev)
++{
++ return !(readl(dev->regs + MVMDIO_XSMI_MGNT_REG) & MVMDIO_XSMI_BUSY);
++}
++
++static const struct orion_mdio_ops orion_mdio_xsmi_ops = {
++ .is_done = orion_mdio_xsmi_is_done,
++ .poll_interval_min = MVMDIO_XSMI_POLL_INTERVAL_MIN,
++ .poll_interval_max = MVMDIO_XSMI_POLL_INTERVAL_MAX,
++};
++
++static int orion_mdio_xsmi_read(struct mii_bus *bus, int mii_id,
++ int regnum)
++{
++ struct orion_mdio_dev *dev = bus->priv;
++ u16 dev_addr = (regnum >> 16) & GENMASK(4, 0);
++ int ret;
++
++ if (!(regnum & MII_ADDR_C45))
++ return -EOPNOTSUPP;
++
++ ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
++ if (ret < 0)
++ return ret;
++
++ writel(regnum & GENMASK(15, 0), dev->regs + MVMDIO_XSMI_ADDR_REG);
++ writel((mii_id << MVMDIO_XSMI_PHYADDR_SHIFT) |
++ (dev_addr << MVMDIO_XSMI_DEVADDR_SHIFT) |
++ MVMDIO_XSMI_READ_OPERATION,
++ dev->regs + MVMDIO_XSMI_MGNT_REG);
++
++ ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
++ if (ret < 0)
++ return ret;
++
++ if (!(readl(dev->regs + MVMDIO_XSMI_MGNT_REG) &
++ MVMDIO_XSMI_READ_VALID)) {
++ dev_err(bus->parent, "XSMI bus read not valid\n");
++ return -ENODEV;
++ }
++
++ return readl(dev->regs + MVMDIO_XSMI_MGNT_REG) & GENMASK(15, 0);
++}
++
++static int orion_mdio_xsmi_write(struct mii_bus *bus, int mii_id,
++ int regnum, u16 value)
++{
++ struct orion_mdio_dev *dev = bus->priv;
++ u16 dev_addr = (regnum >> 16) & GENMASK(4, 0);
++ int ret;
++
++ if (!(regnum & MII_ADDR_C45))
++ return -EOPNOTSUPP;
++
++ ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
++ if (ret < 0)
++ return ret;
++
++ writel(regnum & GENMASK(15, 0), dev->regs + MVMDIO_XSMI_ADDR_REG);
++ writel((mii_id << MVMDIO_XSMI_PHYADDR_SHIFT) |
++ (dev_addr << MVMDIO_XSMI_DEVADDR_SHIFT) |
++ MVMDIO_XSMI_WRITE_OPERATION | value,
++ dev->regs + MVMDIO_XSMI_MGNT_REG);
++
++ return 0;
++}
++
+ static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id)
+ {
+ struct orion_mdio_dev *dev = dev_id;
+@@ -194,11 +279,14 @@ static irqreturn_t orion_mdio_err_irq(in
+
+ static int orion_mdio_probe(struct platform_device *pdev)
+ {
++ enum orion_mdio_bus_type type;
+ struct resource *r;
+ struct mii_bus *bus;
+ struct orion_mdio_dev *dev;
+ int i, ret;
+
++ type = (enum orion_mdio_bus_type)of_device_get_match_data(&pdev->dev);
++
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "No SMI register address given\n");
+@@ -210,9 +298,18 @@ static int orion_mdio_probe(struct platf
+ if (!bus)
+ return -ENOMEM;
+
++ switch (type) {
++ case BUS_TYPE_SMI:
++ bus->read = orion_mdio_smi_read;
++ bus->write = orion_mdio_smi_write;
++ break;
++ case BUS_TYPE_XSMI:
++ bus->read = orion_mdio_xsmi_read;
++ bus->write = orion_mdio_xsmi_write;
++ break;
++ }
++
+ bus->name = "orion_mdio_bus";
+- bus->read = orion_mdio_read;
+- bus->write = orion_mdio_write;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii",
+ dev_name(&pdev->dev));
+ bus->parent = &pdev->dev;
+@@ -302,7 +399,8 @@ static int orion_mdio_remove(struct plat
+ }
+
+ static const struct of_device_id orion_mdio_match[] = {
+- { .compatible = "marvell,orion-mdio" },
++ { .compatible = "marvell,orion-mdio", .data = (void *)BUS_TYPE_SMI },
++ { .compatible = "marvell,xmdio", .data = (void *)BUS_TYPE_XSMI },
+ { }
+ };
+ MODULE_DEVICE_TABLE(of, orion_mdio_match);
diff --git a/patches.drivers/net-mvmdio-check-the-MII_ADDR_C45-bit-is-not-set-for.patch b/patches.drivers/net-mvmdio-check-the-MII_ADDR_C45-bit-is-not-set-for.patch
new file mode 100644
index 0000000000..e242e06eae
--- /dev/null
+++ b/patches.drivers/net-mvmdio-check-the-MII_ADDR_C45-bit-is-not-set-for.patch
@@ -0,0 +1,41 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Thu, 15 Jun 2017 16:43:22 +0200
+Subject: net: mvmdio: check the MII_ADDR_C45 bit is not set for smi operations
+Patch-mainline: v4.13-rc1
+Git-commit: 440ea77654d0fbb6e144dc90f6fa1d4429d83280
+References: bsc#1098633
+
+Add a check for the read and write smi operations, to ensure the
+MII_ADDR_C45 bit isn't set. This will be needed as soon as the xSMI
+support is added to the mvmdio driver.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvmdio.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/net/ethernet/marvell/mvmdio.c
++++ b/drivers/net/ethernet/marvell/mvmdio.c
+@@ -126,6 +126,9 @@ static int orion_mdio_read(struct mii_bu
+ u32 val;
+ int ret;
+
++ if (regnum & MII_ADDR_C45)
++ return -EOPNOTSUPP;
++
+ ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
+ if (ret < 0)
+ goto out;
+@@ -157,6 +160,9 @@ static int orion_mdio_write(struct mii_b
+ struct orion_mdio_dev *dev = bus->priv;
+ int ret;
+
++ if (regnum & MII_ADDR_C45)
++ return -EOPNOTSUPP;
++
+ ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
+ if (ret < 0)
+ goto out;
diff --git a/patches.drivers/net-mvmdio-introduce-an-ops-structure.patch b/patches.drivers/net-mvmdio-introduce-an-ops-structure.patch
new file mode 100644
index 0000000000..e2d40a0678
--- /dev/null
+++ b/patches.drivers/net-mvmdio-introduce-an-ops-structure.patch
@@ -0,0 +1,102 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Thu, 15 Jun 2017 16:43:20 +0200
+Subject: net: mvmdio: introduce an ops structure
+Patch-mainline: v4.13-rc1
+Git-commit: b0b7fa4f7cd016087f22a4c173318b16c796ff11
+References: bsc#1098633
+
+Introduce an ops structure to add an indirection on the is_done
+function, as this is needed to add the xMDIO support later.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvmdio.c | 30 +++++++++++++++++++-----------
+ 1 file changed, 19 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvmdio.c
++++ b/drivers/net/ethernet/marvell/mvmdio.c
+@@ -62,14 +62,14 @@ struct orion_mdio_dev {
+ wait_queue_head_t smi_busy_wait;
+ };
+
+-static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev)
+-{
+- return !(readl(dev->regs) & MVMDIO_SMI_BUSY);
+-}
++struct orion_mdio_ops {
++ int (*is_done)(struct orion_mdio_dev *);
++};
+
+ /* Wait for the SMI unit to be ready for another operation
+ */
+-static int orion_mdio_wait_ready(struct mii_bus *bus)
++static int orion_mdio_wait_ready(const struct orion_mdio_ops *ops,
++ struct mii_bus *bus)
+ {
+ struct orion_mdio_dev *dev = bus->priv;
+ unsigned long timeout = usecs_to_jiffies(MVMDIO_SMI_TIMEOUT);
+@@ -77,7 +77,7 @@ static int orion_mdio_wait_ready(struct
+ int timedout = 0;
+
+ while (1) {
+- if (orion_mdio_smi_is_done(dev))
++ if (ops->is_done(dev))
+ return 0;
+ else if (timedout)
+ break;
+@@ -96,8 +96,7 @@ static int orion_mdio_wait_ready(struct
+ if (timeout < 2)
+ timeout = 2;
+ wait_event_timeout(dev->smi_busy_wait,
+- orion_mdio_smi_is_done(dev),
+- timeout);
++ ops->is_done(dev), timeout);
+
+ ++timedout;
+ }
+@@ -107,6 +106,15 @@ static int orion_mdio_wait_ready(struct
+ return -ETIMEDOUT;
+ }
+
++static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev)
++{
++ return !(readl(dev->regs) & MVMDIO_SMI_BUSY);
++}
++
++static const struct orion_mdio_ops orion_mdio_smi_ops = {
++ .is_done = orion_mdio_smi_is_done,
++};
++
+ static int orion_mdio_read(struct mii_bus *bus, int mii_id,
+ int regnum)
+ {
+@@ -114,7 +122,7 @@ static int orion_mdio_read(struct mii_bu
+ u32 val;
+ int ret;
+
+- ret = orion_mdio_wait_ready(bus);
++ ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
+ if (ret < 0)
+ goto out;
+
+@@ -123,7 +131,7 @@ static int orion_mdio_read(struct mii_bu
+ MVMDIO_SMI_READ_OPERATION),
+ dev->regs);
+
+- ret = orion_mdio_wait_ready(bus);
++ ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
+ if (ret < 0)
+ goto out;
+
+@@ -145,7 +153,7 @@ static int orion_mdio_write(struct mii_b
+ struct orion_mdio_dev *dev = bus->priv;
+ int ret;
+
+- ret = orion_mdio_wait_ready(bus);
++ ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
+ if (ret < 0)
+ goto out;
+
diff --git a/patches.drivers/net-mvmdio-put-the-poll-intervals-in-the-ops-structu.patch b/patches.drivers/net-mvmdio-put-the-poll-intervals-in-the-ops-structu.patch
new file mode 100644
index 0000000000..8fa623bbe9
--- /dev/null
+++ b/patches.drivers/net-mvmdio-put-the-poll-intervals-in-the-ops-structu.patch
@@ -0,0 +1,49 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Thu, 15 Jun 2017 16:43:21 +0200
+Subject: net: mvmdio: put the poll intervals in the ops structure
+Patch-mainline: v4.13-rc1
+Git-commit: 1955796640a6736583b59c581d3ccddfca66cb33
+References: bsc#1098633
+
+Put the two poll intervals (min and max) in the driver's ops
+structure. This is needed to add the xmdio support later.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvmdio.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvmdio.c
++++ b/drivers/net/ethernet/marvell/mvmdio.c
+@@ -64,6 +64,8 @@ struct orion_mdio_dev {
+
+ struct orion_mdio_ops {
+ int (*is_done)(struct orion_mdio_dev *);
++ unsigned int poll_interval_min;
++ unsigned int poll_interval_max;
+ };
+
+ /* Wait for the SMI unit to be ready for another operation
+@@ -83,8 +85,8 @@ static int orion_mdio_wait_ready(const s
+ break;
+
+ if (dev->err_interrupt <= 0) {
+- usleep_range(MVMDIO_SMI_POLL_INTERVAL_MIN,
+- MVMDIO_SMI_POLL_INTERVAL_MAX);
++ usleep_range(ops->poll_interval_min,
++ ops->poll_interval_max);
+
+ if (time_is_before_jiffies(end))
+ ++timedout;
+@@ -113,6 +115,8 @@ static int orion_mdio_smi_is_done(struct
+
+ static const struct orion_mdio_ops orion_mdio_smi_ops = {
+ .is_done = orion_mdio_smi_is_done,
++ .poll_interval_min = MVMDIO_SMI_POLL_INTERVAL_MIN,
++ .poll_interval_max = MVMDIO_SMI_POLL_INTERVAL_MAX,
+ };
+
+ static int orion_mdio_read(struct mii_bus *bus, int mii_id,
diff --git a/patches.drivers/net-mvmdio-remove-duplicate-locking.patch b/patches.drivers/net-mvmdio-remove-duplicate-locking.patch
new file mode 100644
index 0000000000..5dcb39e30b
--- /dev/null
+++ b/patches.drivers/net-mvmdio-remove-duplicate-locking.patch
@@ -0,0 +1,79 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 15 Jun 2017 16:43:19 +0200
+Subject: net: mvmdio: remove duplicate locking
+Patch-mainline: v4.13-rc1
+Git-commit: 0caf0305a39e62d5cb33cfd1e98aa77a25768232
+References: bsc#1098633
+
+The MDIO layer already provides per-bus locking, so there's no need for
+MDIO bus drivers to do their own internal locking. Remove this.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvmdio.c | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvmdio.c
++++ b/drivers/net/ethernet/marvell/mvmdio.c
+@@ -23,7 +23,6 @@
+ #include <linux/io.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+-#include <linux/mutex.h>
+ #include <linux/of_mdio.h>
+ #include <linux/phy.h>
+ #include <linux/platform_device.h>
+@@ -51,7 +50,6 @@
+ #define MVMDIO_SMI_POLL_INTERVAL_MAX 55
+
+ struct orion_mdio_dev {
+- struct mutex lock;
+ void __iomem *regs;
+ struct clk *clk[3];
+ /*
+@@ -116,8 +114,6 @@ static int orion_mdio_read(struct mii_bu
+ u32 val;
+ int ret;
+
+- mutex_lock(&dev->lock);
+-
+ ret = orion_mdio_wait_ready(bus);
+ if (ret < 0)
+ goto out;
+@@ -140,7 +136,6 @@ static int orion_mdio_read(struct mii_bu
+
+ ret = val & GENMASK(15, 0);
+ out:
+- mutex_unlock(&dev->lock);
+ return ret;
+ }
+
+@@ -150,8 +145,6 @@ static int orion_mdio_write(struct mii_b
+ struct orion_mdio_dev *dev = bus->priv;
+ int ret;
+
+- mutex_lock(&dev->lock);
+-
+ ret = orion_mdio_wait_ready(bus);
+ if (ret < 0)
+ goto out;
+@@ -163,7 +156,6 @@ static int orion_mdio_write(struct mii_b
+ dev->regs);
+
+ out:
+- mutex_unlock(&dev->lock);
+ return ret;
+ }
+
+@@ -244,8 +236,6 @@ static int orion_mdio_probe(struct platf
+ return -EPROBE_DEFER;
+ }
+
+- mutex_init(&dev->lock);
+-
+ if (pdev->dev.of_node)
+ ret = of_mdiobus_register(bus, pdev->dev.of_node);
+ else
diff --git a/patches.drivers/net-mvmdio-reorder-headers-alphabetically.patch b/patches.drivers/net-mvmdio-reorder-headers-alphabetically.patch
new file mode 100644
index 0000000000..7272dc811b
--- /dev/null
+++ b/patches.drivers/net-mvmdio-reorder-headers-alphabetically.patch
@@ -0,0 +1,41 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Thu, 15 Jun 2017 16:43:16 +0200
+Subject: net: mvmdio: reorder headers alphabetically
+Patch-mainline: v4.13-rc1
+Git-commit: 14ef8b367165f88d708efbac60034e47986b23b7
+References: bsc#1098633
+
+Cosmetic fix reordering headers alphabetically.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvmdio.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvmdio.c
++++ b/drivers/net/ethernet/marvell/mvmdio.c
+@@ -17,16 +17,16 @@
+ * warranty of any kind, whether express or implied.
+ */
+
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/mutex.h>
++#include <linux/of_mdio.h>
+ #include <linux/phy.h>
+-#include <linux/interrupt.h>
+ #include <linux/platform_device.h>
+-#include <linux/delay.h>
+-#include <linux/io.h>
+-#include <linux/clk.h>
+-#include <linux/of_mdio.h>
+ #include <linux/sched.h>
+ #include <linux/wait.h>
+
diff --git a/patches.drivers/net-mvmdio-simplify-the-smi-read-and-write-error-pat.patch b/patches.drivers/net-mvmdio-simplify-the-smi-read-and-write-error-pat.patch
new file mode 100644
index 0000000000..294d947312
--- /dev/null
+++ b/patches.drivers/net-mvmdio-simplify-the-smi-read-and-write-error-pat.patch
@@ -0,0 +1,70 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Thu, 15 Jun 2017 16:43:24 +0200
+Subject: net: mvmdio: simplify the smi read and write error paths
+Patch-mainline: v4.13-rc1
+Git-commit: 0268b51e3043d96c4133154b20a5b8338857cb5b
+References: bsc#1098633
+
+Cosmetic patch simplifying the smi read and write error paths. It also
+align their error paths with the ones of the xsmi functions.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvmdio.c | 16 ++++++----------
+ 1 file changed, 6 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvmdio.c
++++ b/drivers/net/ethernet/marvell/mvmdio.c
+@@ -149,7 +149,7 @@ static int orion_mdio_smi_read(struct mi
+
+ ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
+ if (ret < 0)
+- goto out;
++ return ret;
+
+ writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) |
+ (regnum << MVMDIO_SMI_PHY_REG_SHIFT) |
+@@ -158,18 +158,15 @@ static int orion_mdio_smi_read(struct mi
+
+ ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
+ if (ret < 0)
+- goto out;
++ return ret;
+
+ val = readl(dev->regs);
+ if (!(val & MVMDIO_SMI_READ_VALID)) {
+ dev_err(bus->parent, "SMI bus read not valid\n");
+- ret = -ENODEV;
+- goto out;
++ return -ENODEV;
+ }
+
+- ret = val & GENMASK(15, 0);
+-out:
+- return ret;
++ return val & GENMASK(15, 0);
+ }
+
+ static int orion_mdio_smi_write(struct mii_bus *bus, int mii_id,
+@@ -183,7 +180,7 @@ static int orion_mdio_smi_write(struct m
+
+ ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
+ if (ret < 0)
+- goto out;
++ return ret;
+
+ writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) |
+ (regnum << MVMDIO_SMI_PHY_REG_SHIFT) |
+@@ -191,8 +188,7 @@ static int orion_mdio_smi_write(struct m
+ (value << MVMDIO_SMI_DATA_SHIFT)),
+ dev->regs);
+
+-out:
+- return ret;
++ return 0;
+ }
+
+ static int orion_mdio_xsmi_is_done(struct orion_mdio_dev *dev)
diff --git a/patches.drivers/net-mvmdio-use-GENMASK-for-masks.patch b/patches.drivers/net-mvmdio-use-GENMASK-for-masks.patch
new file mode 100644
index 0000000000..cd4a32b8cc
--- /dev/null
+++ b/patches.drivers/net-mvmdio-use-GENMASK-for-masks.patch
@@ -0,0 +1,28 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Thu, 15 Jun 2017 16:43:18 +0200
+Subject: net: mvmdio: use GENMASK for masks
+Patch-mainline: v4.13-rc1
+Git-commit: fd3ebd857895884c2567a7f4dfbf50ba49bd2eab
+References: bsc#1098633
+
+Cosmetic patch to use the GENMASK helper for masks.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvmdio.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/marvell/mvmdio.c
++++ b/drivers/net/ethernet/marvell/mvmdio.c
+@@ -138,7 +138,7 @@ static int orion_mdio_read(struct mii_bu
+ goto out;
+ }
+
+- ret = val & 0xFFFF;
++ ret = val & GENMASK(15, 0);
+ out:
+ mutex_unlock(&dev->lock);
+ return ret;
diff --git a/patches.drivers/net-mvmdio-use-tabs-for-defines.patch b/patches.drivers/net-mvmdio-use-tabs-for-defines.patch
new file mode 100644
index 0000000000..3b4284586c
--- /dev/null
+++ b/patches.drivers/net-mvmdio-use-tabs-for-defines.patch
@@ -0,0 +1,58 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Thu, 15 Jun 2017 16:43:17 +0200
+Subject: net: mvmdio: use tabs for defines
+Patch-mainline: v4.13-rc1
+Git-commit: 2040ef2f74a42a56da424aea28249a7f188aa637
+References: bsc#1098633
+
+Cosmetic patch replacing spaces by tabs for defined values.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvmdio.c | 26 +++++++++++++-------------
+ 1 file changed, 13 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvmdio.c
++++ b/drivers/net/ethernet/marvell/mvmdio.c
+@@ -30,25 +30,25 @@
+ #include <linux/sched.h>
+ #include <linux/wait.h>
+
+-#define MVMDIO_SMI_DATA_SHIFT 0
+-#define MVMDIO_SMI_PHY_ADDR_SHIFT 16
+-#define MVMDIO_SMI_PHY_REG_SHIFT 21
+-#define MVMDIO_SMI_READ_OPERATION BIT(26)
+-#define MVMDIO_SMI_WRITE_OPERATION 0
+-#define MVMDIO_SMI_READ_VALID BIT(27)
+-#define MVMDIO_SMI_BUSY BIT(28)
+-#define MVMDIO_ERR_INT_CAUSE 0x007C
+-#define MVMDIO_ERR_INT_SMI_DONE 0x00000010
+-#define MVMDIO_ERR_INT_MASK 0x0080
++#define MVMDIO_SMI_DATA_SHIFT 0
++#define MVMDIO_SMI_PHY_ADDR_SHIFT 16
++#define MVMDIO_SMI_PHY_REG_SHIFT 21
++#define MVMDIO_SMI_READ_OPERATION BIT(26)
++#define MVMDIO_SMI_WRITE_OPERATION 0
++#define MVMDIO_SMI_READ_VALID BIT(27)
++#define MVMDIO_SMI_BUSY BIT(28)
++#define MVMDIO_ERR_INT_CAUSE 0x007C
++#define MVMDIO_ERR_INT_SMI_DONE 0x00000010
++#define MVMDIO_ERR_INT_MASK 0x0080
+
+ /*
+ * SMI Timeout measurements:
+ * - Kirkwood 88F6281 (Globalscale Dreamplug): 45us to 95us (Interrupt)
+ * - Armada 370 (Globalscale Mirabox): 41us to 43us (Polled)
+ */
+-#define MVMDIO_SMI_TIMEOUT 1000 /* 1000us = 1ms */
+-#define MVMDIO_SMI_POLL_INTERVAL_MIN 45
+-#define MVMDIO_SMI_POLL_INTERVAL_MAX 55
++#define MVMDIO_SMI_TIMEOUT 1000 /* 1000us = 1ms */
++#define MVMDIO_SMI_POLL_INTERVAL_MIN 45
++#define MVMDIO_SMI_POLL_INTERVAL_MAX 55
+
+ struct orion_mdio_dev {
+ struct mutex lock;
diff --git a/patches.drivers/net-mvpp2-Add-hardware-offloading-for-VLAN-filtering.patch b/patches.drivers/net-mvpp2-Add-hardware-offloading-for-VLAN-filtering.patch
new file mode 100644
index 0000000000..e55d662a08
--- /dev/null
+++ b/patches.drivers/net-mvpp2-Add-hardware-offloading-for-VLAN-filtering.patch
@@ -0,0 +1,593 @@
+From: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Date: Wed, 28 Feb 2018 10:14:13 +0100
+Subject: net: mvpp2: Add hardware offloading for VLAN filtering
+Patch-mainline: v4.17-rc1
+Git-commit: 56beda3db6020428885f0589a0ac16768ea94543
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 414 ++++++++++++++++++++++++++++++++---
+ 1 file changed, 380 insertions(+), 34 deletions(-)
+
+--- 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_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_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 mvp
+
+ 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(str
+ 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 mv
+ 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 pl
+ 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 mvp
+ 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
+
+ mvpp2_prs_dsa_init(priv);
+
++ mvpp2_prs_vid_init(priv);
++
+ err = mvpp2_prs_etype_init(priv);
+ if (err)
+ return err;
+@@ -7153,6 +7447,12 @@ retry:
+ }
+ }
+ }
++
++ /* 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
+ 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
+ .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,
+ };
+
+ static const struct ethtool_ops mvpp2_eth_tool_ops = {
+@@ -7945,7 +8290,8 @@ static int mvpp2_port_probe(struct platf
+
+ features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
+ dev->features = features | NETIF_F_RXCSUM;
+- dev->hw_features |= features | NETIF_F_RXCSUM | NETIF_F_GRO;
++ dev->hw_features |= features | NETIF_F_RXCSUM | NETIF_F_GRO |
++ NETIF_F_HW_VLAN_CTAG_FILTER;
+ dev->vlan_features |= features;
+ dev->gso_max_segs = MVPP2_MAX_TSO_SEGS;
+
diff --git a/patches.drivers/net-mvpp2-Add-support-for-unicast-filtering.patch b/patches.drivers/net-mvpp2-Add-support-for-unicast-filtering.patch
new file mode 100644
index 0000000000..c7eb73e261
--- /dev/null
+++ b/patches.drivers/net-mvpp2-Add-support-for-unicast-filtering.patch
@@ -0,0 +1,460 @@
+From: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Date: Wed, 7 Mar 2018 15:18:04 +0100
+Subject: net: mvpp2: Add support for unicast filtering
+Patch-mainline: v4.17-rc1
+Git-commit: 10fea26ce2aaf46c4da834664fb5f8476108a783
+References: bsc#1098633
+
+Marvell PPv2 controller can be used to implement packet filtering based
+on the destination MAC address. This is already used to implement
+multicast filtering. This patch adds support for Unicast filtering.
+
+Filtering is based on so-called "TCAM entries" to implement filtering.
+Due to their limited number and the fact that these are also used for
+other purposes, we reserve 80 entries for both unicast and multicast
+filters. On top of the broadcast address, and each interface's own MAC
+address, we reserve 25 entries per port, 4 for unicast filters, 21 for
+multicast.
+
+Whenever unicast or multicast range for one port is full, the filtering
+is disabled and port goes into promiscuous mode for the given type of
+addresses.
+
+Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 294 +++++++++++++++++++----------------
+ 1 file changed, 160 insertions(+), 134 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -601,6 +601,9 @@ enum mvpp2_tag_type {
+ #define MVPP2_PRS_TCAM_PROTO_MASK 0xff
+ #define MVPP2_PRS_TCAM_PROTO_MASK_L 0x3f
+ #define MVPP2_PRS_DBL_VLANS_MAX 100
++#define MVPP2_PRS_CAST_MASK BIT(0)
++#define MVPP2_PRS_MCAST_VAL BIT(0)
++#define MVPP2_PRS_UCAST_VAL 0x0
+
+ /* Tcam structure:
+ * - lookup ID - 4 bits
+@@ -624,6 +627,19 @@ enum mvpp2_tag_type {
+
+ #define MVPP2_PRS_VID_TCAM_BYTE 2
+
++/* TCAM range for unicast and multicast filtering. We have 25 entries per port,
++ * with 4 dedicated to UC filtering and the rest to multicast filtering.
++ * Additionnally we reserve one entry for the broadcast address, and one for
++ * each port's own address.
++ */
++#define MVPP2_PRS_MAC_UC_MC_FILT_MAX 25
++#define MVPP2_PRS_MAC_RANGE_SIZE 80
++
++/* Number of entries per port dedicated to UC and MC filtering */
++#define MVPP2_PRS_MAC_UC_FILT_MAX 4
++#define MVPP2_PRS_MAC_MC_FILT_MAX (MVPP2_PRS_MAC_UC_MC_FILT_MAX - \
++ MVPP2_PRS_MAC_UC_FILT_MAX)
++
+ /* 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
+@@ -639,36 +655,40 @@ enum mvpp2_tag_type {
+ #define MVPP2_PE_DROP_ALL 0
+ #define MVPP2_PE_FIRST_FREE_TID 1
+
++/* MAC filtering range */
++#define MVPP2_PE_MAC_RANGE_END (MVPP2_PE_VID_FILT_RANGE_START - 1)
++#define MVPP2_PE_MAC_RANGE_START (MVPP2_PE_MAC_RANGE_END - \
++ MVPP2_PRS_MAC_RANGE_SIZE + 1)
+ /* 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 - 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_IP6_ADDR_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 29)
++#define MVPP2_PE_IP4_ADDR_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 28)
++#define MVPP2_PE_LAST_DEFAULT_FLOW (MVPP2_PRS_TCAM_SRAM_SIZE - 27)
++#define MVPP2_PE_FIRST_DEFAULT_FLOW (MVPP2_PRS_TCAM_SRAM_SIZE - 22)
++#define MVPP2_PE_EDSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 21)
++#define MVPP2_PE_EDSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 20)
++#define MVPP2_PE_DSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 19)
++#define MVPP2_PE_DSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 18)
++#define MVPP2_PE_ETYPE_EDSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 17)
++#define MVPP2_PE_ETYPE_EDSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 16)
++#define MVPP2_PE_ETYPE_DSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 15)
++#define MVPP2_PE_ETYPE_DSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 14)
++#define MVPP2_PE_MH_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 13)
++#define MVPP2_PE_DSA_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 12)
++#define MVPP2_PE_IP6_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 11)
++#define MVPP2_PE_IP4_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 10)
++#define MVPP2_PE_ETH_TYPE_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 9)
++#define MVPP2_PE_VID_FLTR_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 8)
++#define MVPP2_PE_VID_EDSA_FLTR_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 7)
++#define MVPP2_PE_VLAN_DBL (MVPP2_PRS_TCAM_SRAM_SIZE - 6)
++#define MVPP2_PE_VLAN_NONE (MVPP2_PRS_TCAM_SRAM_SIZE - 5)
++/* reserved */
++#define MVPP2_PE_MAC_MC_PROMISCUOUS (MVPP2_PRS_TCAM_SRAM_SIZE - 3)
++#define MVPP2_PE_MAC_UC_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 + \
+@@ -798,6 +818,12 @@ enum mvpp2_prs_lookup {
+ MVPP2_PRS_LU_LAST,
+ };
+
++/* L2 cast enum */
++enum mvpp2_prs_l2_cast {
++ MVPP2_PRS_L2_UNI_CAST,
++ MVPP2_PRS_L2_MULTI_CAST,
++};
++
+ /* L3 cast enum */
+ enum mvpp2_prs_l3_cast {
+ MVPP2_PRS_L3_UNI_CAST,
+@@ -1973,78 +1999,43 @@ static void mvpp2_prs_mac_drop_all_set(s
+ mvpp2_prs_hw_write(priv, &pe);
+ }
+
+-/* Set port to promiscuous mode */
+-static void mvpp2_prs_mac_promisc_set(struct mvpp2 *priv, int port, bool add)
++/* Set port to unicast or multicast promiscuous mode */
++static void mvpp2_prs_mac_promisc_set(struct mvpp2 *priv, int port,
++ enum mvpp2_prs_l2_cast l2_cast, bool add)
+ {
+ struct mvpp2_prs_entry pe;
++ unsigned char cast_match;
++ unsigned int ri;
++ int tid;
+
+- /* Promiscuous mode - Accept unknown packets */
+-
+- if (priv->prs_shadow[MVPP2_PE_MAC_PROMISCUOUS].valid) {
+- /* Entry exist - update port only */
+- pe.index = MVPP2_PE_MAC_PROMISCUOUS;
+- mvpp2_prs_hw_read(priv, &pe);
++ if (l2_cast == MVPP2_PRS_L2_UNI_CAST) {
++ cast_match = MVPP2_PRS_UCAST_VAL;
++ tid = MVPP2_PE_MAC_UC_PROMISCUOUS;
++ ri = MVPP2_PRS_RI_L2_UCAST;
+ } else {
+- /* Entry doesn't exist - create new */
+- memset(&pe, 0, sizeof(pe));
+- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
+- pe.index = MVPP2_PE_MAC_PROMISCUOUS;
+-
+- /* Continue - set next lookup */
+- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA);
+-
+- /* Set result info bits */
+- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L2_UCAST,
+- MVPP2_PRS_RI_L2_CAST_MASK);
+-
+- /* Shift to ethertype */
+- mvpp2_prs_sram_shift_set(&pe, 2 * ETH_ALEN,
+- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+-
+- /* Mask all ports */
+- mvpp2_prs_tcam_port_map_set(&pe, 0);
+-
+- /* Update shadow table */
+- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
++ cast_match = MVPP2_PRS_MCAST_VAL;
++ tid = MVPP2_PE_MAC_MC_PROMISCUOUS;
++ ri = MVPP2_PRS_RI_L2_MCAST;
+ }
+
+- /* Update port mask */
+- mvpp2_prs_tcam_port_set(&pe, port, add);
+-
+- mvpp2_prs_hw_write(priv, &pe);
+-}
+-
+-/* Accept multicast */
+-static void mvpp2_prs_mac_multi_set(struct mvpp2 *priv, int port, int index,
+- bool add)
+-{
+- struct mvpp2_prs_entry pe;
+- unsigned char da_mc;
+-
+- /* Ethernet multicast address first byte is
+- * 0x01 for IPv4 and 0x33 for IPv6
+- */
+- da_mc = (index == MVPP2_PE_MAC_MC_ALL) ? 0x01 : 0x33;
+-
+- if (priv->prs_shadow[index].valid) {
+- /* Entry exist - update port only */
+- pe.index = index;
++ /* promiscuous mode - Accept unknown unicast or multicast packets */
++ if (priv->prs_shadow[tid].valid) {
++ pe.index = tid;
+ mvpp2_prs_hw_read(priv, &pe);
+ } else {
+- /* Entry doesn't exist - create new */
+ memset(&pe, 0, sizeof(pe));
+ mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
+- pe.index = index;
++ pe.index = tid;
+
+ /* Continue - set next lookup */
+ mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA);
+
+ /* Set result info bits */
+- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L2_MCAST,
+- MVPP2_PRS_RI_L2_CAST_MASK);
++ mvpp2_prs_sram_ri_update(&pe, ri, MVPP2_PRS_RI_L2_CAST_MASK);
+
+- /* Update tcam entry data first byte */
+- mvpp2_prs_tcam_data_byte_set(&pe, 0, da_mc, 0xff);
++ /* Match UC or MC addresses */
++ mvpp2_prs_tcam_data_byte_set(&pe, 0, cast_match,
++ MVPP2_PRS_CAST_MASK);
+
+ /* Shift to ethertype */
+ mvpp2_prs_sram_shift_set(&pe, 2 * ETH_ALEN,
+@@ -2758,11 +2749,10 @@ static void mvpp2_prs_mac_init(struct mv
+ mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
+ mvpp2_prs_hw_write(priv, &pe);
+
+- /* place holders only - no ports */
++ /* Create dummy entries for drop all and promiscuous modes */
+ mvpp2_prs_mac_drop_all_set(priv, 0, false);
+- mvpp2_prs_mac_promisc_set(priv, 0, false);
+- mvpp2_prs_mac_multi_set(priv, 0, MVPP2_PE_MAC_MC_ALL, false);
+- mvpp2_prs_mac_multi_set(priv, 0, MVPP2_PE_MAC_MC_IP6, false);
++ mvpp2_prs_mac_promisc_set(priv, 0, MVPP2_PRS_L2_UNI_CAST, false);
++ mvpp2_prs_mac_promisc_set(priv, 0, MVPP2_PRS_L2_MULTI_CAST, false);
+ }
+
+ /* Set default entries for various types of dsa packets */
+@@ -3794,8 +3784,8 @@ mvpp2_prs_mac_da_range_find(struct mvpp2
+ mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_MAC);
+
+ /* Go through the all entires with MVPP2_PRS_LU_MAC */
+- for (tid = MVPP2_PE_FIRST_FREE_TID;
+- tid <= MVPP2_PE_LAST_FREE_TID; tid++) {
++ for (tid = MVPP2_PE_MAC_RANGE_START;
++ tid <= MVPP2_PE_MAC_RANGE_END; tid++) {
+ unsigned int entry_pmap;
+
+ if (!priv->prs_shadow[tid].valid ||
+@@ -3836,18 +3826,10 @@ static int mvpp2_prs_mac_da_accept(struc
+ return 0;
+
+ /* Create new TCAM entry */
+- /* Find first range mac entry*/
+- for (tid = MVPP2_PE_FIRST_FREE_TID;
+- tid <= MVPP2_PE_LAST_FREE_TID; tid++)
+- if (priv->prs_shadow[tid].valid &&
+- (priv->prs_shadow[tid].lu == MVPP2_PRS_LU_MAC) &&
+- (priv->prs_shadow[tid].udf ==
+- MVPP2_PRS_UDF_MAC_RANGE))
+- break;
+-
+ /* Go through the all entries from first to last */
+- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
+- tid - 1);
++ tid = mvpp2_prs_tcam_first_free(priv,
++ MVPP2_PE_MAC_RANGE_START,
++ MVPP2_PE_MAC_RANGE_END);
+ if (tid < 0)
+ return tid;
+
+@@ -3886,12 +3868,16 @@ static int mvpp2_prs_mac_da_accept(struc
+ mvpp2_prs_tcam_data_byte_set(pe, len, da[len], 0xff);
+
+ /* Set result info bits */
+- if (is_broadcast_ether_addr(da))
++ if (is_broadcast_ether_addr(da)) {
+ ri = MVPP2_PRS_RI_L2_BCAST;
+- else if (is_multicast_ether_addr(da))
++ } else if (is_multicast_ether_addr(da)) {
+ ri = MVPP2_PRS_RI_L2_MCAST;
+- else
+- ri = MVPP2_PRS_RI_L2_UCAST | MVPP2_PRS_RI_MAC_ME_MASK;
++ } else {
++ ri = MVPP2_PRS_RI_L2_UCAST;
++
++ if (ether_addr_equal(da, port->dev->dev_addr))
++ ri |= MVPP2_PRS_RI_MAC_ME_MASK;
++ }
+
+ mvpp2_prs_sram_ri_update(pe, ri, MVPP2_PRS_RI_L2_CAST_MASK |
+ MVPP2_PRS_RI_MAC_ME_MASK);
+@@ -3933,14 +3919,15 @@ static int mvpp2_prs_update_mac_da(struc
+ return 0;
+ }
+
+-/* Delete all port's multicast simple (not range) entries */
+-static void mvpp2_prs_mcast_del_all(struct mvpp2 *priv, int port)
++static void mvpp2_prs_mac_del_all(struct mvpp2_port *port)
+ {
++ struct mvpp2 *priv = port->priv;
+ struct mvpp2_prs_entry pe;
++ unsigned long pmap;
+ int index, tid;
+
+- for (tid = MVPP2_PE_FIRST_FREE_TID;
+- tid <= MVPP2_PE_LAST_FREE_TID; tid++) {
++ for (tid = MVPP2_PE_MAC_RANGE_START;
++ tid <= MVPP2_PE_MAC_RANGE_END; tid++) {
+ unsigned char da[ETH_ALEN], da_mask[ETH_ALEN];
+
+ if (!priv->prs_shadow[tid].valid ||
+@@ -3948,19 +3935,29 @@ static void mvpp2_prs_mcast_del_all(stru
+ (priv->prs_shadow[tid].udf != MVPP2_PRS_UDF_MAC_DEF))
+ continue;
+
+- /* Only simple mac entries */
+ pe.index = tid;
+ mvpp2_prs_hw_read(priv, &pe);
+
++ pmap = mvpp2_prs_tcam_port_map_get(&pe);
++
++ /* We only want entries active on this port */
++ if (!test_bit(port->id, &pmap))
++ continue;
++
+ /* Read mac addr from entry */
+ for (index = 0; index < ETH_ALEN; index++)
+ mvpp2_prs_tcam_data_byte_get(&pe, index, &da[index],
+ &da_mask[index]);
+
+- if (is_multicast_ether_addr(da) && !is_broadcast_ether_addr(da))
+- /* Delete this entry */
+- mvpp2_prs_mac_da_accept(priv->port_list[port], da,
+- false);
++ /* Special cases : Don't remove broadcast and port's own
++ * address
++ */
++ if (is_broadcast_ether_addr(da) ||
++ ether_addr_equal(da, port->dev->dev_addr))
++ continue;
++
++ /* Remove entry from TCAM */
++ mvpp2_prs_mac_da_accept(port, da, false);
+ }
+ }
+
+@@ -7502,36 +7499,64 @@ static int mvpp2_stop(struct net_device
+ return 0;
+ }
+
+-static void mvpp2_set_rx_mode(struct net_device *dev)
++static int mvpp2_prs_mac_da_accept_list(struct mvpp2_port *port,
++ struct netdev_hw_addr_list *list)
+ {
+- struct mvpp2_port *port = netdev_priv(dev);
+- struct mvpp2 *priv = port->priv;
+ struct netdev_hw_addr *ha;
+- int id = port->id;
+- bool allmulti = dev->flags & IFF_ALLMULTI;
++ int ret;
+
+-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);
+-
+- /* Remove all port->id's mcast enries */
+- mvpp2_prs_mcast_del_all(priv, id);
+-
+- if (!allmulti) {
+- netdev_for_each_mc_addr(ha, dev) {
+- if (mvpp2_prs_mac_da_accept(port, ha->addr, true)) {
+- allmulti = true;
+- goto retry;
+- }
+- }
++ netdev_hw_addr_list_for_each(ha, list) {
++ ret = mvpp2_prs_mac_da_accept(port, ha->addr, true);
++ if (ret)
++ return ret;
+ }
+
+- /* Disable VLAN filtering in promiscuous mode */
+- if (dev->flags & IFF_PROMISC)
+- mvpp2_prs_vid_disable_filtering(port);
+- else
++ return 0;
++}
++
++static void mvpp2_set_rx_promisc(struct mvpp2_port *port, bool enable)
++{
++ if (!enable && (port->dev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
+ mvpp2_prs_vid_enable_filtering(port);
++ else
++ mvpp2_prs_vid_disable_filtering(port);
++
++ mvpp2_prs_mac_promisc_set(port->priv, port->id,
++ MVPP2_PRS_L2_UNI_CAST, enable);
++
++ mvpp2_prs_mac_promisc_set(port->priv, port->id,
++ MVPP2_PRS_L2_MULTI_CAST, enable);
++}
++
++static void mvpp2_set_rx_mode(struct net_device *dev)
++{
++ struct mvpp2_port *port = netdev_priv(dev);
++
++ /* Clear the whole UC and MC list */
++ mvpp2_prs_mac_del_all(port);
++
++ if (dev->flags & IFF_PROMISC) {
++ mvpp2_set_rx_promisc(port, true);
++ return;
++ }
++
++ mvpp2_set_rx_promisc(port, false);
++
++ if (netdev_uc_count(dev) > MVPP2_PRS_MAC_UC_FILT_MAX ||
++ mvpp2_prs_mac_da_accept_list(port, &dev->uc))
++ mvpp2_prs_mac_promisc_set(port->priv, port->id,
++ MVPP2_PRS_L2_UNI_CAST, true);
++
++ if (dev->flags & IFF_ALLMULTI) {
++ mvpp2_prs_mac_promisc_set(port->priv, port->id,
++ MVPP2_PRS_L2_MULTI_CAST, true);
++ return;
++ }
++
++ if (netdev_mc_count(dev) > MVPP2_PRS_MAC_MC_FILT_MAX ||
++ mvpp2_prs_mac_da_accept_list(port, &dev->mc))
++ mvpp2_prs_mac_promisc_set(port->priv, port->id,
++ MVPP2_PRS_L2_MULTI_CAST, true);
+ }
+
+ static int mvpp2_set_mac_address(struct net_device *dev, void *p)
+@@ -8380,6 +8405,7 @@ static int mvpp2_port_probe(struct platf
+
+ dev->vlan_features |= features;
+ dev->gso_max_segs = MVPP2_MAX_TSO_SEGS;
++ dev->priv_flags |= IFF_UNICAST_FLT;
+
+ /* MTU range: 68 - 9704 */
+ dev->min_mtu = ETH_MIN_MTU;
diff --git a/patches.drivers/net-mvpp2-Don-t-use-dynamic-allocs-for-local-variabl.patch b/patches.drivers/net-mvpp2-Don-t-use-dynamic-allocs-for-local-variabl.patch
new file mode 100644
index 0000000000..84f8dbdc76
--- /dev/null
+++ b/patches.drivers/net-mvpp2-Don-t-use-dynamic-allocs-for-local-variabl.patch
@@ -0,0 +1,619 @@
+From: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Date: Mon, 26 Mar 2018 15:34:23 +0200
+Subject: net: mvpp2: Don't use dynamic allocs for local variables
+Patch-mainline: v4.17-rc1
+Git-commit: 0c6d9b44145d8134ebe4e9ebfa02e0dd23744723
+References: bsc#1098633
+
+Some helper functions that search for given entries in the TCAM filter
+on PPv2 controller make use of dynamically alloced temporary variables,
+allocated with GFP_KERNEL. These functions can be called in atomic
+context, and dynamic alloc is not really needed in these cases anyways.
+
+This commit gets rid of dynamic allocs and use stack allocation in the
+following functions, and where they're used :
+ - mvpp2_prs_flow_find
+ - mvpp2_prs_vlan_find
+ - mvpp2_prs_double_vlan_find
+ - mvpp2_prs_mac_da_range_find
+
+For all these functions, instead of returning an temporary object
+representing the TCAM entry, we simply return the TCAM id that matches
+the requested entry.
+
+Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 286 +++++++++++++++--------------------
+ 1 file changed, 125 insertions(+), 161 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -1917,16 +1917,11 @@ static void mvpp2_prs_sram_offset_set(st
+ }
+
+ /* Find parser flow entry */
+-static struct mvpp2_prs_entry *mvpp2_prs_flow_find(struct mvpp2 *priv, int flow)
++static int mvpp2_prs_flow_find(struct mvpp2 *priv, int flow)
+ {
+- struct mvpp2_prs_entry *pe;
++ struct mvpp2_prs_entry pe;
+ int tid;
+
+- pe = kzalloc(sizeof(*pe), GFP_KERNEL);
+- if (!pe)
+- return NULL;
+- mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_FLOWS);
+-
+ /* Go through the all entires with MVPP2_PRS_LU_FLOWS */
+ for (tid = MVPP2_PRS_TCAM_SRAM_SIZE - 1; tid >= 0; tid--) {
+ u8 bits;
+@@ -1935,16 +1930,15 @@ static struct mvpp2_prs_entry *mvpp2_prs
+ priv->prs_shadow[tid].lu != MVPP2_PRS_LU_FLOWS)
+ continue;
+
+- mvpp2_prs_init_from_hw(priv, pe, tid);
+- bits = mvpp2_prs_sram_ai_get(pe);
++ mvpp2_prs_init_from_hw(priv, &pe, tid);
++ bits = mvpp2_prs_sram_ai_get(&pe);
+
+ /* Sram store classification lookup ID in AI bits [5:0] */
+ if ((bits & MVPP2_PRS_FLOW_ID_MASK) == flow)
+- return pe;
++ return tid;
+ }
+- kfree(pe);
+
+- return NULL;
++ return -ENOENT;
+ }
+
+ /* Return first free tcam index, seeking from start to end */
+@@ -2188,17 +2182,11 @@ static void mvpp2_prs_dsa_tag_ethertype_
+ }
+
+ /* Search for existing single/triple vlan entry */
+-static struct mvpp2_prs_entry *mvpp2_prs_vlan_find(struct mvpp2 *priv,
+- unsigned short tpid, int ai)
++static int mvpp2_prs_vlan_find(struct mvpp2 *priv, unsigned short tpid, int ai)
+ {
+- struct mvpp2_prs_entry *pe;
++ struct mvpp2_prs_entry pe;
+ int tid;
+
+- pe = kzalloc(sizeof(*pe), GFP_KERNEL);
+- if (!pe)
+- return NULL;
+- mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_VLAN);
+-
+ /* Go through the all entries with MVPP2_PRS_LU_VLAN */
+ for (tid = MVPP2_PE_FIRST_FREE_TID;
+ tid <= MVPP2_PE_LAST_FREE_TID; tid++) {
+@@ -2209,17 +2197,17 @@ static struct mvpp2_prs_entry *mvpp2_prs
+ priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN)
+ continue;
+
+- mvpp2_prs_init_from_hw(priv, pe, tid);
+- match = mvpp2_prs_tcam_data_cmp(pe, 0, swab16(tpid));
++ mvpp2_prs_init_from_hw(priv, &pe, tid);
++ match = mvpp2_prs_tcam_data_cmp(&pe, 0, swab16(tpid));
+ if (!match)
+ continue;
+
+ /* Get vlan type */
+- ri_bits = mvpp2_prs_sram_ri_get(pe);
++ ri_bits = mvpp2_prs_sram_ri_get(&pe);
+ ri_bits &= MVPP2_PRS_RI_VLAN_MASK;
+
+ /* Get current ai value from tcam */
+- ai_bits = mvpp2_prs_tcam_ai_get(pe);
++ ai_bits = mvpp2_prs_tcam_ai_get(&pe);
+ /* Clear double vlan bit */
+ ai_bits &= ~MVPP2_PRS_DBL_VLAN_AI_BIT;
+
+@@ -2228,34 +2216,31 @@ static struct mvpp2_prs_entry *mvpp2_prs
+
+ if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE ||
+ ri_bits == MVPP2_PRS_RI_VLAN_TRIPLE)
+- return pe;
++ return tid;
+ }
+- kfree(pe);
+
+- return NULL;
++ return -ENOENT;
+ }
+
+ /* Add/update single/triple vlan entry */
+ static int mvpp2_prs_vlan_add(struct mvpp2 *priv, unsigned short tpid, int ai,
+ unsigned int port_map)
+ {
+- struct mvpp2_prs_entry *pe;
++ struct mvpp2_prs_entry pe;
+ int tid_aux, tid;
+ int ret = 0;
+
+- pe = mvpp2_prs_vlan_find(priv, tpid, ai);
++ memset(&pe, 0, sizeof(pe));
++
++ tid = mvpp2_prs_vlan_find(priv, tpid, ai);
+
+- if (!pe) {
++ if (tid < 0) {
+ /* Create new tcam entry */
+ tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_LAST_FREE_TID,
+ MVPP2_PE_FIRST_FREE_TID);
+ if (tid < 0)
+ return tid;
+
+- pe = kzalloc(sizeof(*pe), GFP_KERNEL);
+- if (!pe)
+- return -ENOMEM;
+-
+ /* Get last double vlan tid */
+ for (tid_aux = MVPP2_PE_LAST_FREE_TID;
+ tid_aux >= MVPP2_PE_FIRST_FREE_TID; tid_aux--) {
+@@ -2265,48 +2250,46 @@ static int mvpp2_prs_vlan_add(struct mvp
+ priv->prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN)
+ continue;
+
+- mvpp2_prs_init_from_hw(priv, pe, tid_aux);
+- ri_bits = mvpp2_prs_sram_ri_get(pe);
++ mvpp2_prs_init_from_hw(priv, &pe, tid_aux);
++ ri_bits = mvpp2_prs_sram_ri_get(&pe);
+ if ((ri_bits & MVPP2_PRS_RI_VLAN_MASK) ==
+ MVPP2_PRS_RI_VLAN_DOUBLE)
+ break;
+ }
+
+- if (tid <= tid_aux) {
+- ret = -EINVAL;
+- goto free_pe;
+- }
++ if (tid <= tid_aux)
++ return -EINVAL;
+
+- memset(pe, 0, sizeof(*pe));
+- mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_VLAN);
+- pe->index = tid;
++ memset(&pe, 0, sizeof(pe));
++ pe.index = tid;
++ mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
+
+- mvpp2_prs_match_etype(pe, 0, tpid);
++ mvpp2_prs_match_etype(&pe, 0, tpid);
+
+ /* VLAN tag detected, proceed with VID filtering */
+- mvpp2_prs_sram_next_lu_set(pe, MVPP2_PRS_LU_VID);
++ 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);
++ mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
+
+ if (ai == MVPP2_PRS_SINGLE_VLAN_AI) {
+- mvpp2_prs_sram_ri_update(pe, MVPP2_PRS_RI_VLAN_SINGLE,
++ mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_SINGLE,
+ MVPP2_PRS_RI_VLAN_MASK);
+ } else {
+ ai |= MVPP2_PRS_DBL_VLAN_AI_BIT;
+- mvpp2_prs_sram_ri_update(pe, MVPP2_PRS_RI_VLAN_TRIPLE,
++ mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_TRIPLE,
+ MVPP2_PRS_RI_VLAN_MASK);
+ }
+- mvpp2_prs_tcam_ai_update(pe, ai, MVPP2_PRS_SRAM_AI_MASK);
++ mvpp2_prs_tcam_ai_update(&pe, ai, MVPP2_PRS_SRAM_AI_MASK);
+
+- mvpp2_prs_shadow_set(priv, pe->index, MVPP2_PRS_LU_VLAN);
++ mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
++ } else {
++ mvpp2_prs_init_from_hw(priv, &pe, tid);
+ }
+ /* Update ports' mask */
+- mvpp2_prs_tcam_port_map_set(pe, port_map);
++ mvpp2_prs_tcam_port_map_set(&pe, port_map);
+
+- mvpp2_prs_hw_write(priv, pe);
+-free_pe:
+- kfree(pe);
++ mvpp2_prs_hw_write(priv, &pe);
+
+ return ret;
+ }
+@@ -2325,18 +2308,12 @@ static int mvpp2_prs_double_vlan_ai_free
+ }
+
+ /* Search for existing double vlan entry */
+-static struct mvpp2_prs_entry *mvpp2_prs_double_vlan_find(struct mvpp2 *priv,
+- unsigned short tpid1,
+- unsigned short tpid2)
++static int mvpp2_prs_double_vlan_find(struct mvpp2 *priv, unsigned short tpid1,
++ unsigned short tpid2)
+ {
+- struct mvpp2_prs_entry *pe;
++ struct mvpp2_prs_entry pe;
+ int tid;
+
+- pe = kzalloc(sizeof(*pe), GFP_KERNEL);
+- if (!pe)
+- return NULL;
+- mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_VLAN);
+-
+ /* Go through the all entries with MVPP2_PRS_LU_VLAN */
+ for (tid = MVPP2_PE_FIRST_FREE_TID;
+ tid <= MVPP2_PE_LAST_FREE_TID; tid++) {
+@@ -2347,21 +2324,20 @@ static struct mvpp2_prs_entry *mvpp2_prs
+ priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN)
+ continue;
+
+- mvpp2_prs_init_from_hw(priv, pe, tid);
++ mvpp2_prs_init_from_hw(priv, &pe, tid);
+
+- match = mvpp2_prs_tcam_data_cmp(pe, 0, swab16(tpid1))
+- && mvpp2_prs_tcam_data_cmp(pe, 4, swab16(tpid2));
++ match = mvpp2_prs_tcam_data_cmp(&pe, 0, swab16(tpid1)) &&
++ mvpp2_prs_tcam_data_cmp(&pe, 4, swab16(tpid2));
+
+ if (!match)
+ continue;
+
+- ri_mask = mvpp2_prs_sram_ri_get(pe) & MVPP2_PRS_RI_VLAN_MASK;
++ ri_mask = mvpp2_prs_sram_ri_get(&pe) & MVPP2_PRS_RI_VLAN_MASK;
+ if (ri_mask == MVPP2_PRS_RI_VLAN_DOUBLE)
+- return pe;
++ return tid;
+ }
+- kfree(pe);
+
+- return NULL;
++ return -ENOENT;
+ }
+
+ /* Add or update double vlan entry */
+@@ -2369,28 +2345,24 @@ static int mvpp2_prs_double_vlan_add(str
+ unsigned short tpid2,
+ unsigned int port_map)
+ {
+- struct mvpp2_prs_entry *pe;
+ int tid_aux, tid, ai, ret = 0;
++ struct mvpp2_prs_entry pe;
++
++ memset(&pe, 0, sizeof(pe));
+
+- pe = mvpp2_prs_double_vlan_find(priv, tpid1, tpid2);
++ tid = mvpp2_prs_double_vlan_find(priv, tpid1, tpid2);
+
+- if (!pe) {
++ if (tid < 0) {
+ /* Create new tcam entry */
+ tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
+ MVPP2_PE_LAST_FREE_TID);
+ if (tid < 0)
+ return tid;
+
+- pe = kzalloc(sizeof(*pe), GFP_KERNEL);
+- if (!pe)
+- return -ENOMEM;
+-
+ /* Set ai value for new double vlan entry */
+ ai = mvpp2_prs_double_vlan_ai_free_get(priv);
+- if (ai < 0) {
+- ret = ai;
+- goto free_pe;
+- }
++ if (ai < 0)
++ return ai;
+
+ /* Get first single/triple vlan tid */
+ for (tid_aux = MVPP2_PE_FIRST_FREE_TID;
+@@ -2401,45 +2373,44 @@ static int mvpp2_prs_double_vlan_add(str
+ priv->prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN)
+ continue;
+
+- mvpp2_prs_init_from_hw(priv, pe, tid_aux);
+- ri_bits = mvpp2_prs_sram_ri_get(pe);
++ mvpp2_prs_init_from_hw(priv, &pe, tid_aux);
++ ri_bits = mvpp2_prs_sram_ri_get(&pe);
+ ri_bits &= MVPP2_PRS_RI_VLAN_MASK;
+ if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE ||
+ ri_bits == MVPP2_PRS_RI_VLAN_TRIPLE)
+ break;
+ }
+
+- if (tid >= tid_aux) {
+- ret = -ERANGE;
+- goto free_pe;
+- }
++ if (tid >= tid_aux)
++ return -ERANGE;
+
+- memset(pe, 0, sizeof(*pe));
+- mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_VLAN);
+- pe->index = tid;
++ memset(&pe, 0, sizeof(pe));
++ mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
++ pe.index = tid;
+
+ priv->prs_double_vlans[ai] = true;
+
+- mvpp2_prs_match_etype(pe, 0, tpid1);
+- mvpp2_prs_match_etype(pe, 4, tpid2);
++ mvpp2_prs_match_etype(&pe, 0, tpid1);
++ mvpp2_prs_match_etype(&pe, 4, tpid2);
+
+- mvpp2_prs_sram_next_lu_set(pe, MVPP2_PRS_LU_VLAN);
++ mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
+ /* Shift 4 bytes - skip outer vlan tag */
+- mvpp2_prs_sram_shift_set(pe, MVPP2_VLAN_TAG_LEN,
++ 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_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_DOUBLE,
+ MVPP2_PRS_RI_VLAN_MASK);
+- mvpp2_prs_sram_ai_update(pe, ai | MVPP2_PRS_DBL_VLAN_AI_BIT,
++ mvpp2_prs_sram_ai_update(&pe, ai | MVPP2_PRS_DBL_VLAN_AI_BIT,
+ MVPP2_PRS_SRAM_AI_MASK);
+
+- mvpp2_prs_shadow_set(priv, pe->index, MVPP2_PRS_LU_VLAN);
++ mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
++ } else {
++ mvpp2_prs_init_from_hw(priv, &pe, tid);
+ }
+
+ /* Update ports' mask */
+- mvpp2_prs_tcam_port_map_set(pe, port_map);
+- mvpp2_prs_hw_write(priv, pe);
+-free_pe:
+- kfree(pe);
++ mvpp2_prs_tcam_port_map_set(&pe, port_map);
++ mvpp2_prs_hw_write(priv, &pe);
++
+ return ret;
+ }
+
+@@ -3508,6 +3479,7 @@ static int mvpp2_prs_vid_range_find(stru
+ continue;
+
+ mvpp2_prs_init_from_hw(priv, &pe, tid);
++
+ mvpp2_prs_tcam_data_byte_get(&pe, 2, &byte[0], &enable[0]);
+ mvpp2_prs_tcam_data_byte_get(&pe, 3, &byte[1], &enable[1]);
+
+@@ -3520,7 +3492,7 @@ static int mvpp2_prs_vid_range_find(stru
+ return tid;
+ }
+
+- return 0;
++ return -ENOENT;
+ }
+
+ /* Write parser entry for VID filtering */
+@@ -3533,6 +3505,8 @@ static int mvpp2_prs_vid_entry_add(struc
+ struct mvpp2_prs_entry pe;
+ int tid;
+
++ memset(&pe, 0, sizeof(pe));
++
+ /* Scan TCAM and see if entry with this <vid,port> already exist */
+ tid = mvpp2_prs_vid_range_find(priv, (1 << port->id), vid, mask);
+
+@@ -3543,8 +3517,7 @@ static int mvpp2_prs_vid_entry_add(struc
+ shift = MVPP2_VLAN_TAG_LEN;
+
+ /* No such entry */
+- if (!tid) {
+- memset(&pe, 0, sizeof(pe));
++ if (tid < 0) {
+
+ /* Go through all entries from first to last in vlan range */
+ tid = mvpp2_prs_tcam_first_free(priv, vid_start,
+@@ -3596,7 +3569,7 @@ static void mvpp2_prs_vid_entry_remove(s
+ tid = mvpp2_prs_vid_range_find(priv, (1 << port->id), vid, 0xfff);
+
+ /* No such entry */
+- if (tid)
++ if (tid < 0)
+ return;
+
+ mvpp2_prs_hw_inv(priv, tid);
+@@ -3763,18 +3736,13 @@ static bool mvpp2_prs_mac_range_equals(s
+ }
+
+ /* Find tcam entry with matched pair <MAC DA, port> */
+-static struct mvpp2_prs_entry *
++static int
+ mvpp2_prs_mac_da_range_find(struct mvpp2 *priv, int pmap, const u8 *da,
+ unsigned char *mask, int udf_type)
+ {
+- struct mvpp2_prs_entry *pe;
++ struct mvpp2_prs_entry pe;
+ int tid;
+
+- pe = kzalloc(sizeof(*pe), GFP_ATOMIC);
+- if (!pe)
+- return NULL;
+- mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_MAC);
+-
+ /* Go through the all entires with MVPP2_PRS_LU_MAC */
+ for (tid = MVPP2_PE_MAC_RANGE_START;
+ tid <= MVPP2_PE_MAC_RANGE_END; tid++) {
+@@ -3785,16 +3753,15 @@ mvpp2_prs_mac_da_range_find(struct mvpp2
+ (priv->prs_shadow[tid].udf != udf_type))
+ continue;
+
+- mvpp2_prs_init_from_hw(priv, pe, tid);
+- entry_pmap = mvpp2_prs_tcam_port_map_get(pe);
++ mvpp2_prs_init_from_hw(priv, &pe, tid);
++ entry_pmap = mvpp2_prs_tcam_port_map_get(&pe);
+
+- if (mvpp2_prs_mac_range_equals(pe, da, mask) &&
++ if (mvpp2_prs_mac_range_equals(&pe, da, mask) &&
+ entry_pmap == pmap)
+- return pe;
++ return tid;
+ }
+- kfree(pe);
+
+- return NULL;
++ return -ENOENT;
+ }
+
+ /* Update parser's mac da entry */
+@@ -3804,15 +3771,17 @@ static int mvpp2_prs_mac_da_accept(struc
+ unsigned char mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ struct mvpp2 *priv = port->priv;
+ unsigned int pmap, len, ri;
+- struct mvpp2_prs_entry *pe;
++ struct mvpp2_prs_entry pe;
+ int tid;
+
++ memset(&pe, 0, sizeof(pe));
++
+ /* Scan TCAM and see if entry with this <MAC DA, port> already exist */
+- pe = mvpp2_prs_mac_da_range_find(priv, BIT(port->id), da, mask,
+- MVPP2_PRS_UDF_MAC_DEF);
++ tid = mvpp2_prs_mac_da_range_find(priv, BIT(port->id), da, mask,
++ MVPP2_PRS_UDF_MAC_DEF);
+
+ /* No such entry */
+- if (!pe) {
++ if (tid < 0) {
+ if (!add)
+ return 0;
+
+@@ -3824,39 +3793,37 @@ static int mvpp2_prs_mac_da_accept(struc
+ if (tid < 0)
+ return tid;
+
+- pe = kzalloc(sizeof(*pe), GFP_ATOMIC);
+- if (!pe)
+- return -ENOMEM;
+- mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_MAC);
+- pe->index = tid;
++ pe.index = tid;
+
+ /* Mask all ports */
+- mvpp2_prs_tcam_port_map_set(pe, 0);
++ mvpp2_prs_tcam_port_map_set(&pe, 0);
++ } else {
++ mvpp2_prs_init_from_hw(priv, &pe, tid);
+ }
+
++ mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
++
+ /* Update port mask */
+- mvpp2_prs_tcam_port_set(pe, port->id, add);
++ mvpp2_prs_tcam_port_set(&pe, port->id, add);
+
+ /* Invalidate the entry if no ports are left enabled */
+- pmap = mvpp2_prs_tcam_port_map_get(pe);
++ pmap = mvpp2_prs_tcam_port_map_get(&pe);
+ if (pmap == 0) {
+- if (add) {
+- kfree(pe);
++ if (add)
+ return -EINVAL;
+- }
+- mvpp2_prs_hw_inv(priv, pe->index);
+- priv->prs_shadow[pe->index].valid = false;
+- kfree(pe);
++
++ mvpp2_prs_hw_inv(priv, pe.index);
++ priv->prs_shadow[pe.index].valid = false;
+ return 0;
+ }
+
+ /* Continue - set next lookup */
+- mvpp2_prs_sram_next_lu_set(pe, MVPP2_PRS_LU_DSA);
++ mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA);
+
+ /* Set match on DA */
+ len = ETH_ALEN;
+ while (len--)
+- mvpp2_prs_tcam_data_byte_set(pe, len, da[len], 0xff);
++ mvpp2_prs_tcam_data_byte_set(&pe, len, da[len], 0xff);
+
+ /* Set result info bits */
+ if (is_broadcast_ether_addr(da)) {
+@@ -3870,21 +3837,19 @@ static int mvpp2_prs_mac_da_accept(struc
+ ri |= MVPP2_PRS_RI_MAC_ME_MASK;
+ }
+
+- mvpp2_prs_sram_ri_update(pe, ri, MVPP2_PRS_RI_L2_CAST_MASK |
++ mvpp2_prs_sram_ri_update(&pe, ri, MVPP2_PRS_RI_L2_CAST_MASK |
+ MVPP2_PRS_RI_MAC_ME_MASK);
+- mvpp2_prs_shadow_ri_set(priv, pe->index, ri, MVPP2_PRS_RI_L2_CAST_MASK |
++ mvpp2_prs_shadow_ri_set(priv, pe.index, ri, MVPP2_PRS_RI_L2_CAST_MASK |
+ MVPP2_PRS_RI_MAC_ME_MASK);
+
+ /* Shift to ethertype */
+- mvpp2_prs_sram_shift_set(pe, 2 * ETH_ALEN,
++ mvpp2_prs_sram_shift_set(&pe, 2 * ETH_ALEN,
+ MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+ /* Update shadow table and hw entry */
+- priv->prs_shadow[pe->index].udf = MVPP2_PRS_UDF_MAC_DEF;
+- mvpp2_prs_shadow_set(priv, pe->index, MVPP2_PRS_LU_MAC);
+- mvpp2_prs_hw_write(priv, pe);
+-
+- kfree(pe);
++ priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_MAC_DEF;
++ mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
++ mvpp2_prs_hw_write(priv, &pe);
+
+ return 0;
+ }
+@@ -4004,13 +3969,15 @@ static int mvpp2_prs_tag_mode_set(struct
+ /* Set prs flow for the port */
+ static int mvpp2_prs_def_flow(struct mvpp2_port *port)
+ {
+- struct mvpp2_prs_entry *pe;
++ struct mvpp2_prs_entry pe;
+ int tid;
+
+- pe = mvpp2_prs_flow_find(port->priv, port->id);
++ memset(&pe, 0, sizeof(pe));
++
++ tid = mvpp2_prs_flow_find(port->priv, port->id);
+
+ /* Such entry not exist */
+- if (!pe) {
++ if (tid < 0) {
+ /* Go through the all entires from last to first */
+ tid = mvpp2_prs_tcam_first_free(port->priv,
+ MVPP2_PE_LAST_FREE_TID,
+@@ -4018,24 +3985,21 @@ static int mvpp2_prs_def_flow(struct mvp
+ if (tid < 0)
+ return tid;
+
+- pe = kzalloc(sizeof(*pe), GFP_KERNEL);
+- if (!pe)
+- return -ENOMEM;
+-
+- mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_FLOWS);
+- pe->index = tid;
++ pe.index = tid;
+
+ /* Set flow ID*/
+- mvpp2_prs_sram_ai_update(pe, port->id, MVPP2_PRS_FLOW_ID_MASK);
+- mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
++ mvpp2_prs_sram_ai_update(&pe, port->id, MVPP2_PRS_FLOW_ID_MASK);
++ mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
+
+ /* Update shadow table */
+- mvpp2_prs_shadow_set(port->priv, pe->index, MVPP2_PRS_LU_FLOWS);
++ mvpp2_prs_shadow_set(port->priv, pe.index, MVPP2_PRS_LU_FLOWS);
++ } else {
++ mvpp2_prs_init_from_hw(port->priv, &pe, tid);
+ }
+
+- mvpp2_prs_tcam_port_map_set(pe, (1 << port->id));
+- mvpp2_prs_hw_write(port->priv, pe);
+- kfree(pe);
++ mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
++ mvpp2_prs_tcam_port_map_set(&pe, (1 << port->id));
++ mvpp2_prs_hw_write(port->priv, &pe);
+
+ return 0;
+ }
diff --git a/patches.drivers/net-mvpp2-Fix-DMA-address-mask-size.patch b/patches.drivers/net-mvpp2-Fix-DMA-address-mask-size.patch
new file mode 100644
index 0000000000..0b8771f158
--- /dev/null
+++ b/patches.drivers/net-mvpp2-Fix-DMA-address-mask-size.patch
@@ -0,0 +1,76 @@
+From: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Date: Wed, 18 Apr 2018 11:14:44 +0200
+Subject: net: mvpp2: Fix DMA address mask size
+Patch-mainline: v4.17-rc2
+Git-commit: da42bb271305d68df6cbf99eed90542f1f1ee1c9
+References: bsc#1098633
+
+PPv2 TX/RX descriptors uses 40bits DMA addresses, but 41 bits masks were
+used (GENMASK_ULL(40, 0)).
+
+This commit fixes that by using the correct mask.
+
+Fixes: e7c5359f2eed ("net: mvpp2: introduce PPv2.2 HW descriptors and adapt accessors")
+Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -916,6 +916,8 @@ static struct {
+
+ #define MVPP2_MIB_COUNTERS_STATS_DELAY (1 * HZ)
+
++#define MVPP2_DESC_DMA_MASK DMA_BIT_MASK(40)
++
+ /* Definitions */
+
+ /* Shared Packet Processor resources */
+@@ -1429,7 +1431,7 @@ static dma_addr_t mvpp2_txdesc_dma_addr_
+ if (port->priv->hw_version == MVPP21)
+ return tx_desc->pp21.buf_dma_addr;
+ else
+- return tx_desc->pp22.buf_dma_addr_ptp & GENMASK_ULL(40, 0);
++ return tx_desc->pp22.buf_dma_addr_ptp & MVPP2_DESC_DMA_MASK;
+ }
+
+ static void mvpp2_txdesc_dma_addr_set(struct mvpp2_port *port,
+@@ -1447,7 +1449,7 @@ static void mvpp2_txdesc_dma_addr_set(st
+ } else {
+ u64 val = (u64)addr;
+
+- tx_desc->pp22.buf_dma_addr_ptp &= ~GENMASK_ULL(40, 0);
++ tx_desc->pp22.buf_dma_addr_ptp &= ~MVPP2_DESC_DMA_MASK;
+ tx_desc->pp22.buf_dma_addr_ptp |= val;
+ tx_desc->pp22.packet_offset = offset;
+ }
+@@ -1507,7 +1509,7 @@ static dma_addr_t mvpp2_rxdesc_dma_addr_
+ if (port->priv->hw_version == MVPP21)
+ return rx_desc->pp21.buf_dma_addr;
+ else
+- return rx_desc->pp22.buf_dma_addr_key_hash & GENMASK_ULL(40, 0);
++ return rx_desc->pp22.buf_dma_addr_key_hash & MVPP2_DESC_DMA_MASK;
+ }
+
+ static unsigned long mvpp2_rxdesc_cookie_get(struct mvpp2_port *port,
+@@ -1516,7 +1518,7 @@ static unsigned long mvpp2_rxdesc_cookie
+ if (port->priv->hw_version == MVPP21)
+ return rx_desc->pp21.buf_cookie;
+ else
+- return rx_desc->pp22.buf_cookie_misc & GENMASK_ULL(40, 0);
++ return rx_desc->pp22.buf_cookie_misc & MVPP2_DESC_DMA_MASK;
+ }
+
+ static size_t mvpp2_rxdesc_size_get(struct mvpp2_port *port,
+@@ -8789,7 +8791,7 @@ static int mvpp2_probe(struct platform_d
+ }
+
+ if (priv->hw_version == MVPP22) {
+- err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(40));
++ err = dma_set_mask(&pdev->dev, MVPP2_DESC_DMA_MASK);
+ if (err)
+ goto err_mg_clk;
+ /* Sadly, the BM pools all share the same register to
diff --git a/patches.drivers/net-mvpp2-Fix-TCAM-filter-reserved-range.patch b/patches.drivers/net-mvpp2-Fix-TCAM-filter-reserved-range.patch
new file mode 100644
index 0000000000..512a8eb0a9
--- /dev/null
+++ b/patches.drivers/net-mvpp2-Fix-TCAM-filter-reserved-range.patch
@@ -0,0 +1,39 @@
+From: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Date: Mon, 16 Apr 2018 10:07:23 +0200
+Subject: net: mvpp2: Fix TCAM filter reserved range
+Patch-mainline: v4.17-rc2
+Git-commit: 982e05001c472066ab288e4269ad6cab48889f0d
+References: bsc#1098633
+
+Marvell's PPv2 controller has a Packet Header parser, which uses a
+fixed-size TCAM array of filter entries.
+
+The mvpp2 driver reserves some ranges among the 256 TCAM entries to
+perform MAC and VID filtering. The rest of the TCAM ids are freely usable
+for other features, such as IPv4 proto matching.
+
+This commit fixes the MVPP2_PE_LAST_FREE_TID define that sets the end of
+the "free range", which included the MAC range. This could therefore allow
+some other features to use entries dedicated to MAC filtering,
+lowering the number of unicast/multicast addresses that could be allowed
+before switching to promiscuous mode.
+
+Fixes: 10fea26ce2aa ("net: mvpp2: Add support for unicast filtering")
+Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -663,7 +663,7 @@ enum mvpp2_tag_type {
+ #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_LAST_FREE_TID (MVPP2_PE_MAC_RANGE_START - 1)
+ #define MVPP2_PE_IP6_EXT_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 30)
+ #define MVPP2_PE_IP6_ADDR_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 29)
+ #define MVPP2_PE_IP4_ADDR_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 28)
diff --git a/patches.drivers/net-mvpp2-Fix-clk-error-path-in-mvpp2_probe.patch b/patches.drivers/net-mvpp2-Fix-clk-error-path-in-mvpp2_probe.patch
new file mode 100644
index 0000000000..73718af984
--- /dev/null
+++ b/patches.drivers/net-mvpp2-Fix-clk-error-path-in-mvpp2_probe.patch
@@ -0,0 +1,83 @@
+From: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Date: Wed, 25 Apr 2018 20:21:16 +0200
+Subject: net: mvpp2: Fix clk error path in mvpp2_probe
+Patch-mainline: v4.17-rc4
+Git-commit: 45f972adb7f4db2d7f02af728ccd104113336074
+References: bsc#1098633
+
+When clk_prepare_enable fails for the axi_clk, the mg_clk isn't properly
+cleaned up. Add another jump label to handle that case, and make sure we
+jump to it in the later error cases.
+
+Fixes: 4792ea04bcd0 ("net: mvpp2: Fix clock resource by adding an optional bus clock")
+Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Acked-by: Gregory CLEMENT <gregory.clement@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -8774,12 +8774,12 @@ static int mvpp2_probe(struct platform_d
+ if (IS_ERR(priv->axi_clk)) {
+ err = PTR_ERR(priv->axi_clk);
+ if (err == -EPROBE_DEFER)
+- goto err_gop_clk;
++ goto err_mg_clk;
+ priv->axi_clk = NULL;
+ } else {
+ err = clk_prepare_enable(priv->axi_clk);
+ if (err < 0)
+- goto err_gop_clk;
++ goto err_mg_clk;
+ }
+
+ /* Get system's tclk rate */
+@@ -8793,7 +8793,7 @@ static int mvpp2_probe(struct platform_d
+ if (priv->hw_version == MVPP22) {
+ err = dma_set_mask(&pdev->dev, MVPP2_DESC_DMA_MASK);
+ if (err)
+- goto err_mg_clk;
++ goto err_axi_clk;
+ /* Sadly, the BM pools all share the same register to
+ * store the high 32 bits of their address. So they
+ * must all have the same high 32 bits, which forces
+@@ -8801,14 +8801,14 @@ static int mvpp2_probe(struct platform_d
+ */
+ err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (err)
+- goto err_mg_clk;
++ goto err_axi_clk;
+ }
+
+ /* Initialize network controller */
+ err = mvpp2_init(pdev, priv);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to initialize controller\n");
+- goto err_mg_clk;
++ goto err_axi_clk;
+ }
+
+ /* Initialize ports */
+@@ -8821,7 +8821,7 @@ static int mvpp2_probe(struct platform_d
+ if (priv->port_count == 0) {
+ dev_err(&pdev->dev, "no ports enabled\n");
+ err = -ENODEV;
+- goto err_mg_clk;
++ goto err_axi_clk;
+ }
+
+ /* Statistics must be gathered regularly because some of them (like
+@@ -8849,8 +8849,9 @@ err_port_probe:
+ mvpp2_port_remove(priv->port_list[i]);
+ i++;
+ }
+-err_mg_clk:
++err_axi_clk:
+ clk_disable_unprepare(priv->axi_clk);
++err_mg_clk:
+ if (priv->hw_version == MVPP22)
+ clk_disable_unprepare(priv->mg_clk);
+ err_gop_clk:
diff --git a/patches.drivers/net-mvpp2-Fix-clock-resource-by-adding-an-optional-b.patch b/patches.drivers/net-mvpp2-Fix-clock-resource-by-adding-an-optional-b.patch
new file mode 100644
index 0000000000..074cd76995
--- /dev/null
+++ b/patches.drivers/net-mvpp2-Fix-clock-resource-by-adding-an-optional-b.patch
@@ -0,0 +1,92 @@
+From: Gregory CLEMENT <gregory.clement@free-electrons.com>
+Date: Fri, 29 Sep 2017 14:27:39 +0200
+Subject: net: mvpp2: Fix clock resource by adding an optional bus clock
+Patch-mainline: v4.14-rc4
+Git-commit: 4792ea04bcd03b8ccfd1ae336c5deba52dd9edc9
+References: bsc#1098633
+
+On Armada 7K/8K we need to explicitly enable the bus clock. The bus clock
+is optional because not all the SoCs need them but at least for Armada
+7K/8K it is actually mandatory.
+
+The binding documentation is updating accordingly.
+
+Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ Documentation/devicetree/bindings/net/marvell-pp2.txt | 10 ++++++----
+ drivers/net/ethernet/marvell/mvpp2.c | 15 +++++++++++++++
+ 2 files changed, 21 insertions(+), 4 deletions(-)
+
+--- a/Documentation/devicetree/bindings/net/marvell-pp2.txt
++++ b/Documentation/devicetree/bindings/net/marvell-pp2.txt
+@@ -21,8 +21,9 @@ Required properties:
+ - main controller clock (for both armada-375-pp2 and armada-7k-pp2)
+ - GOP clock (for both armada-375-pp2 and armada-7k-pp2)
+ - MG clock (only for armada-7k-pp2)
+-- clock-names: names of used clocks, must be "pp_clk", "gop_clk" and
+- "mg_clk" (the latter only for armada-7k-pp2).
++ - AXI clock (only for armada-7k-pp2)
++- clock-names: names of used clocks, must be "pp_clk", "gop_clk", "mg_clk"
++ and "axi_clk" (the 2 latter only for armada-7k-pp2).
+
+ The ethernet ports are represented by subnodes. At least one port is
+ required.
+@@ -76,8 +77,9 @@ Example for marvell,armada-7k-pp2:
+ cpm_ethernet: ethernet@0 {
+ compatible = "marvell,armada-7k-pp22";
+ reg = <0x0 0x100000>, <0x129000 0xb000>;
+- clocks = <&cpm_syscon0 1 3>, <&cpm_syscon0 1 9>, <&cpm_syscon0 1 5>;
+- clock-names = "pp_clk", "gop_clk", "gp_clk";
++ clocks = <&cpm_syscon0 1 3>, <&cpm_syscon0 1 9>,
++ <&cpm_syscon0 1 5>, <&cpm_syscon0 1 18>;
++ clock-names = "pp_clk", "gop_clk", "gp_clk", "axi_clk";
+
+ eth0: eth0 {
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -793,6 +793,7 @@ struct mvpp2 {
+ struct clk *pp_clk;
+ struct clk *gop_clk;
+ struct clk *mg_clk;
++ struct clk *axi_clk;
+
+ /* List of pointers to port structures */
+ struct mvpp2_port **port_list;
+@@ -7970,6 +7971,18 @@ static int mvpp2_probe(struct platform_d
+ 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)) {
++ err = PTR_ERR(priv->axi_clk);
++ if (err == -EPROBE_DEFER)
++ goto err_gop_clk;
++ priv->axi_clk = NULL;
++ } else {
++ err = clk_prepare_enable(priv->axi_clk);
++ if (err < 0)
++ goto err_gop_clk;
++ }
+ }
+
+ /* Get system's tclk rate */
+@@ -8024,6 +8037,7 @@ static int mvpp2_probe(struct platform_d
+ return 0;
+
+ err_mg_clk:
++ clk_disable_unprepare(priv->axi_clk);
+ if (priv->hw_version == MVPP22)
+ clk_disable_unprepare(priv->mg_clk);
+ err_gop_clk:
+@@ -8061,6 +8075,7 @@ static int mvpp2_remove(struct platform_
+ aggr_txq->descs_dma);
+ }
+
++ clk_disable_unprepare(priv->axi_clk);
+ clk_disable_unprepare(priv->mg_clk);
+ clk_disable_unprepare(priv->pp_clk);
+ clk_disable_unprepare(priv->gop_clk);
diff --git a/patches.drivers/net-mvpp2-Fix-clock-resource-by-adding-missing-mg_co.patch b/patches.drivers/net-mvpp2-Fix-clock-resource-by-adding-missing-mg_co.patch
new file mode 100644
index 0000000000..4f23fc19b5
--- /dev/null
+++ b/patches.drivers/net-mvpp2-Fix-clock-resource-by-adding-missing-mg_co.patch
@@ -0,0 +1,80 @@
+From: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Date: Wed, 25 Apr 2018 20:21:17 +0200
+Subject: net: mvpp2: Fix clock resource by adding missing mg_core_clk
+Patch-mainline: v4.17-rc4
+Git-commit: 9af771ced473f92b5e57d086a0c2453fc0cb149c
+References: bsc#1098633
+
+Marvell's PPv2.2 IP needs an additional clock named "MG Core clock".
+This is required on Armada 7K and 8K.
+
+This commit adds the required clock in mvpp2, making sure it's only
+used on PPv2.2.
+
+Fixes: c7e92def1ef4 ("clk: mvebu: cp110: Fix clock tree representation")
+Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 19 +++++++++++++++++--
+ 1 file changed, 17 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -942,6 +942,7 @@ struct mvpp2 {
+ struct clk *pp_clk;
+ struct clk *gop_clk;
+ struct clk *mg_clk;
++ struct clk *mg_core_clk;
+ struct clk *axi_clk;
+
+ /* List of pointers to port structures */
+@@ -8768,18 +8769,27 @@ static int mvpp2_probe(struct platform_d
+ err = clk_prepare_enable(priv->mg_clk);
+ if (err < 0)
+ goto err_gop_clk;
++
++ priv->mg_core_clk = devm_clk_get(&pdev->dev, "mg_core_clk");
++ if (IS_ERR(priv->mg_core_clk)) {
++ priv->mg_core_clk = NULL;
++ } else {
++ err = clk_prepare_enable(priv->mg_core_clk);
++ if (err < 0)
++ goto err_mg_clk;
++ }
+ }
+
+ priv->axi_clk = devm_clk_get(&pdev->dev, "axi_clk");
+ if (IS_ERR(priv->axi_clk)) {
+ err = PTR_ERR(priv->axi_clk);
+ if (err == -EPROBE_DEFER)
+- goto err_mg_clk;
++ goto err_mg_core_clk;
+ priv->axi_clk = NULL;
+ } else {
+ err = clk_prepare_enable(priv->axi_clk);
+ if (err < 0)
+- goto err_mg_clk;
++ goto err_mg_core_clk;
+ }
+
+ /* Get system's tclk rate */
+@@ -8851,6 +8861,10 @@ err_port_probe:
+ }
+ err_axi_clk:
+ clk_disable_unprepare(priv->axi_clk);
++
++err_mg_core_clk:
++ if (priv->hw_version == MVPP22)
++ clk_disable_unprepare(priv->mg_core_clk);
+ err_mg_clk:
+ if (priv->hw_version == MVPP22)
+ clk_disable_unprepare(priv->mg_clk);
+@@ -8898,6 +8912,7 @@ static int mvpp2_remove(struct platform_
+ return 0;
+
+ clk_disable_unprepare(priv->axi_clk);
++ clk_disable_unprepare(priv->mg_core_clk);
+ clk_disable_unprepare(priv->mg_clk);
+ clk_disable_unprepare(priv->pp_clk);
+ clk_disable_unprepare(priv->gop_clk);
diff --git a/patches.drivers/net-mvpp2-Fix-parser-entry-init-boundary-check.patch b/patches.drivers/net-mvpp2-Fix-parser-entry-init-boundary-check.patch
new file mode 100644
index 0000000000..5817621188
--- /dev/null
+++ b/patches.drivers/net-mvpp2-Fix-parser-entry-init-boundary-check.patch
@@ -0,0 +1,30 @@
+From: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Date: Thu, 5 Apr 2018 11:55:48 +0200
+Subject: net: mvpp2: Fix parser entry init boundary check
+Patch-mainline: v4.17-rc1
+Git-commit: 3d92f0b582062127026af1fb5e86eda4a3b01783
+References: bsc#1098633
+
+Boundary check in mvpp2_prs_init_from_hw must be done according to the
+passed "tid" parameter, not the mvpp2_prs_entry index, which is not yet
+initialized at the time of the check.
+
+Fixes: 47e0e14eb1a6 ("net: mvpp2: Make mvpp2_prs_hw_read a parser entry init function")
+Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -1604,7 +1604,7 @@ static int mvpp2_prs_init_from_hw(struct
+ {
+ int i;
+
+- if (pe->index > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
++ if (tid > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
+ return -EINVAL;
+
+ memset(pe, 0, sizeof(*pe));
diff --git a/patches.drivers/net-mvpp2-Make-mvpp2_prs_hw_read-a-parser-entry-init.patch b/patches.drivers/net-mvpp2-Make-mvpp2_prs_hw_read-a-parser-entry-init.patch
new file mode 100644
index 0000000000..a13c30c92a
--- /dev/null
+++ b/patches.drivers/net-mvpp2-Make-mvpp2_prs_hw_read-a-parser-entry-init.patch
@@ -0,0 +1,179 @@
+From: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Date: Mon, 26 Mar 2018 15:34:22 +0200
+Subject: net: mvpp2: Make mvpp2_prs_hw_read a parser entry init function
+Patch-mainline: v4.17-rc1
+Git-commit: 47e0e14eb1a688c0868385e02db263093d2df6db
+References: bsc#1098633
+
+The mvpp2_prs_hw_read function uses the 'index' field of the struct
+mvpp2_prs_entry to initialize the rest of the fields. This makes it
+unclear from a caller's perspective, who needs to manipulate a struct
+that is not entirely initialized.
+
+This commit makes it an init function for prs_entry, by passing it the
+index as a parameter. The function now zeroes the entry, and sets the
+index field before doing all other init from HW.
+
+The function is renamed 'mvpp2_prs_init_from_hw' to make that clear.
+
+Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 48 +++++++++++++----------------------
+ 1 file changed, 19 insertions(+), 29 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -1582,14 +1582,18 @@ static int mvpp2_prs_hw_write(struct mvp
+ return 0;
+ }
+
+-/* Read tcam entry from hw */
+-static int mvpp2_prs_hw_read(struct mvpp2 *priv, struct mvpp2_prs_entry *pe)
++/* Initialize tcam entry from hw */
++static int mvpp2_prs_init_from_hw(struct mvpp2 *priv,
++ struct mvpp2_prs_entry *pe, int tid)
+ {
+ int i;
+
+ if (pe->index > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
+ return -EINVAL;
+
++ memset(pe, 0, sizeof(*pe));
++ pe->index = tid;
++
+ /* Write tcam index - indirect access */
+ mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
+
+@@ -1931,8 +1935,7 @@ static struct mvpp2_prs_entry *mvpp2_prs
+ priv->prs_shadow[tid].lu != MVPP2_PRS_LU_FLOWS)
+ continue;
+
+- pe->index = tid;
+- mvpp2_prs_hw_read(priv, pe);
++ mvpp2_prs_init_from_hw(priv, pe, tid);
+ bits = mvpp2_prs_sram_ai_get(pe);
+
+ /* Sram store classification lookup ID in AI bits [5:0] */
+@@ -1971,8 +1974,7 @@ static void mvpp2_prs_mac_drop_all_set(s
+
+ if (priv->prs_shadow[MVPP2_PE_DROP_ALL].valid) {
+ /* Entry exist - update port only */
+- pe.index = MVPP2_PE_DROP_ALL;
+- mvpp2_prs_hw_read(priv, &pe);
++ mvpp2_prs_init_from_hw(priv, &pe, MVPP2_PE_DROP_ALL);
+ } else {
+ /* Entry doesn't exist - create new */
+ memset(&pe, 0, sizeof(pe));
+@@ -2020,8 +2022,7 @@ static void mvpp2_prs_mac_promisc_set(st
+
+ /* promiscuous mode - Accept unknown unicast or multicast packets */
+ if (priv->prs_shadow[tid].valid) {
+- pe.index = tid;
+- mvpp2_prs_hw_read(priv, &pe);
++ mvpp2_prs_init_from_hw(priv, &pe, tid);
+ } else {
+ memset(&pe, 0, sizeof(pe));
+ mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
+@@ -2071,8 +2072,7 @@ static void mvpp2_prs_dsa_tag_set(struct
+
+ if (priv->prs_shadow[tid].valid) {
+ /* Entry exist - update port only */
+- pe.index = tid;
+- mvpp2_prs_hw_read(priv, &pe);
++ mvpp2_prs_init_from_hw(priv, &pe, tid);
+ } else {
+ /* Entry doesn't exist - create new */
+ memset(&pe, 0, sizeof(pe));
+@@ -2140,8 +2140,7 @@ static void mvpp2_prs_dsa_tag_ethertype_
+
+ if (priv->prs_shadow[tid].valid) {
+ /* Entry exist - update port only */
+- pe.index = tid;
+- mvpp2_prs_hw_read(priv, &pe);
++ mvpp2_prs_init_from_hw(priv, &pe, tid);
+ } else {
+ /* Entry doesn't exist - create new */
+ memset(&pe, 0, sizeof(pe));
+@@ -2210,9 +2209,7 @@ static struct mvpp2_prs_entry *mvpp2_prs
+ priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN)
+ continue;
+
+- pe->index = tid;
+-
+- mvpp2_prs_hw_read(priv, pe);
++ mvpp2_prs_init_from_hw(priv, pe, tid);
+ match = mvpp2_prs_tcam_data_cmp(pe, 0, swab16(tpid));
+ if (!match)
+ continue;
+@@ -2268,8 +2265,7 @@ static int mvpp2_prs_vlan_add(struct mvp
+ priv->prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN)
+ continue;
+
+- pe->index = tid_aux;
+- mvpp2_prs_hw_read(priv, pe);
++ mvpp2_prs_init_from_hw(priv, pe, tid_aux);
+ ri_bits = mvpp2_prs_sram_ri_get(pe);
+ if ((ri_bits & MVPP2_PRS_RI_VLAN_MASK) ==
+ MVPP2_PRS_RI_VLAN_DOUBLE)
+@@ -2351,8 +2347,7 @@ static struct mvpp2_prs_entry *mvpp2_prs
+ priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN)
+ continue;
+
+- pe->index = tid;
+- mvpp2_prs_hw_read(priv, pe);
++ mvpp2_prs_init_from_hw(priv, pe, tid);
+
+ match = mvpp2_prs_tcam_data_cmp(pe, 0, swab16(tpid1))
+ && mvpp2_prs_tcam_data_cmp(pe, 4, swab16(tpid2));
+@@ -2406,8 +2401,7 @@ static int mvpp2_prs_double_vlan_add(str
+ priv->prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN)
+ continue;
+
+- pe->index = tid_aux;
+- mvpp2_prs_hw_read(priv, pe);
++ mvpp2_prs_init_from_hw(priv, pe, tid_aux);
+ ri_bits = mvpp2_prs_sram_ri_get(pe);
+ ri_bits &= MVPP2_PRS_RI_VLAN_MASK;
+ if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE ||
+@@ -3513,9 +3507,7 @@ static int mvpp2_prs_vid_range_find(stru
+ priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VID)
+ continue;
+
+- pe.index = tid;
+-
+- mvpp2_prs_hw_read(priv, &pe);
++ mvpp2_prs_init_from_hw(priv, &pe, tid);
+ mvpp2_prs_tcam_data_byte_get(&pe, 2, &byte[0], &enable[0]);
+ mvpp2_prs_tcam_data_byte_get(&pe, 3, &byte[1], &enable[1]);
+
+@@ -3569,7 +3561,7 @@ static int mvpp2_prs_vid_entry_add(struc
+ /* Mask all ports */
+ mvpp2_prs_tcam_port_map_set(&pe, 0);
+ } else {
+- mvpp2_prs_hw_read(priv, &pe);
++ mvpp2_prs_init_from_hw(priv, &pe, tid);
+ }
+
+ /* Enable the current port */
+@@ -3793,8 +3785,7 @@ mvpp2_prs_mac_da_range_find(struct mvpp2
+ (priv->prs_shadow[tid].udf != udf_type))
+ continue;
+
+- pe->index = tid;
+- mvpp2_prs_hw_read(priv, pe);
++ mvpp2_prs_init_from_hw(priv, pe, tid);
+ entry_pmap = mvpp2_prs_tcam_port_map_get(pe);
+
+ if (mvpp2_prs_mac_range_equals(pe, da, mask) &&
+@@ -3935,8 +3926,7 @@ static void mvpp2_prs_mac_del_all(struct
+ (priv->prs_shadow[tid].udf != MVPP2_PRS_UDF_MAC_DEF))
+ continue;
+
+- pe.index = tid;
+- mvpp2_prs_hw_read(priv, &pe);
++ mvpp2_prs_init_from_hw(priv, &pe, tid);
+
+ pmap = mvpp2_prs_tcam_port_map_get(&pe);
+
diff --git a/patches.drivers/net-mvpp2-Prevent-userspace-from-changing-TX-affinit.patch b/patches.drivers/net-mvpp2-Prevent-userspace-from-changing-TX-affinit.patch
new file mode 100644
index 0000000000..23524bcbb9
--- /dev/null
+++ b/patches.drivers/net-mvpp2-Prevent-userspace-from-changing-TX-affinit.patch
@@ -0,0 +1,52 @@
+From: Marc Zyngier <marc.zyngier@arm.com>
+Date: Sat, 4 Nov 2017 12:33:47 +0000
+Subject: net: mvpp2: Prevent userspace from changing TX affinities
+Patch-mainline: v4.14
+Git-commit: 13c249a94f525fe4c757d28854049780b25605c4
+References: bsc#1098633
+
+The mvpp2 driver can't cope at all with the TX affinities being
+changed from userspace, and spit an endless stream of
+
+[ 91.779920] mvpp2 f4000000.ethernet eth2: wrong cpu on the end of Tx processing
+[ 91.779930] mvpp2 f4000000.ethernet eth2: wrong cpu on the end of Tx processing
+[ 91.780402] mvpp2 f4000000.ethernet eth2: wrong cpu on the end of Tx processing
+[ 91.780406] mvpp2 f4000000.ethernet eth2: wrong cpu on the end of Tx processing
+[ 91.780415] mvpp2 f4000000.ethernet eth2: wrong cpu on the end of Tx processing
+[ 91.780418] mvpp2 f4000000.ethernet eth2: wrong cpu on the end of Tx processing
+
+rendering the box completely useless (I've measured around 600k
+interrupts/s on a 8040 box) once irqbalance kicks in and start
+doing its job.
+
+Obviously, the driver was never designed with this in mind. So let's
+work around the problem by preventing userspace from interacting
+with these interrupts altogether.
+
+Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -6747,6 +6747,9 @@ static int mvpp2_irqs_init(struct mvpp2_
+ for (i = 0; i < port->nqvecs; i++) {
+ struct mvpp2_queue_vector *qv = port->qvecs + i;
+
++ if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE)
++ irq_set_status_flags(qv->irq, IRQ_NO_BALANCING);
++
+ err = request_irq(qv->irq, mvpp2_isr, 0, port->dev->name, qv);
+ if (err)
+ goto err;
+@@ -6776,6 +6779,7 @@ static void mvpp2_irqs_deinit(struct mvp
+ struct mvpp2_queue_vector *qv = port->qvecs + i;
+
+ irq_set_affinity_hint(qv->irq, NULL);
++ irq_clear_status_flags(qv->irq, IRQ_NO_BALANCING);
+ free_irq(qv->irq, qv);
+ }
+ }
diff --git a/patches.drivers/net-mvpp2-Simplify-MAC-filtering-function-parameters.patch b/patches.drivers/net-mvpp2-Simplify-MAC-filtering-function-parameters.patch
new file mode 100644
index 0000000000..1a5bbc2896
--- /dev/null
+++ b/patches.drivers/net-mvpp2-Simplify-MAC-filtering-function-parameters.patch
@@ -0,0 +1,111 @@
+From: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Date: Wed, 7 Mar 2018 15:18:03 +0100
+Subject: net: mvpp2: Simplify MAC filtering function parameters
+Patch-mainline: v4.17-rc1
+Git-commit: ce2a27c761acaba032f61f8322ff9447fd084671
+References: bsc#1098633
+
+The mvpp2_prs_mac_da_accept function takes into parameter both the
+struct representing the controller and the port id. This is meaningful
+when we want to create TCAM entries for non-initialized ports, but in
+this case we expect the port to be initialized before starting adding or
+removing MAC addresses to the per-port filter.
+
+This commit changes the function so that it takes struct mvpp2_port as
+a parameter instead.
+
+Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 30 +++++++++++++++---------------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -3817,16 +3817,17 @@ mvpp2_prs_mac_da_range_find(struct mvpp2
+ }
+
+ /* Update parser's mac da entry */
+-static int mvpp2_prs_mac_da_accept(struct mvpp2 *priv, int port,
+- const u8 *da, bool add)
++static int mvpp2_prs_mac_da_accept(struct mvpp2_port *port, const u8 *da,
++ bool add)
+ {
+- struct mvpp2_prs_entry *pe;
+- unsigned int pmap, len, ri;
+ unsigned char mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
++ struct mvpp2 *priv = port->priv;
++ unsigned int pmap, len, ri;
++ struct mvpp2_prs_entry *pe;
+ int tid;
+
+ /* Scan TCAM and see if entry with this <MAC DA, port> already exist */
+- pe = mvpp2_prs_mac_da_range_find(priv, (1 << port), da, mask,
++ pe = mvpp2_prs_mac_da_range_find(priv, BIT(port->id), da, mask,
+ MVPP2_PRS_UDF_MAC_DEF);
+
+ /* No such entry */
+@@ -3861,7 +3862,7 @@ static int mvpp2_prs_mac_da_accept(struc
+ }
+
+ /* Update port mask */
+- mvpp2_prs_tcam_port_set(pe, port, add);
++ mvpp2_prs_tcam_port_set(pe, port->id, add);
+
+ /* Invalidate the entry if no ports are left enabled */
+ pmap = mvpp2_prs_tcam_port_map_get(pe);
+@@ -3917,13 +3918,12 @@ static int mvpp2_prs_update_mac_da(struc
+ int err;
+
+ /* Remove old parser entry */
+- err = mvpp2_prs_mac_da_accept(port->priv, port->id, dev->dev_addr,
+- false);
++ err = mvpp2_prs_mac_da_accept(port, dev->dev_addr, false);
+ if (err)
+ return err;
+
+ /* Add new parser entry */
+- err = mvpp2_prs_mac_da_accept(port->priv, port->id, da, true);
++ err = mvpp2_prs_mac_da_accept(port, da, true);
+ if (err)
+ return err;
+
+@@ -3959,7 +3959,8 @@ static void mvpp2_prs_mcast_del_all(stru
+
+ if (is_multicast_ether_addr(da) && !is_broadcast_ether_addr(da))
+ /* Delete this entry */
+- mvpp2_prs_mac_da_accept(priv, port, da, false);
++ mvpp2_prs_mac_da_accept(priv->port_list[port], da,
++ false);
+ }
+ }
+
+@@ -7380,15 +7381,14 @@ static int mvpp2_open(struct net_device
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ int err;
+
+- err = mvpp2_prs_mac_da_accept(port->priv, port->id, mac_bcast, true);
++ err = mvpp2_prs_mac_da_accept(port, mac_bcast, true);
+ if (err) {
+ netdev_err(dev, "mvpp2_prs_mac_da_accept BC failed\n");
+ return err;
+ }
+- err = mvpp2_prs_mac_da_accept(port->priv, port->id,
+- dev->dev_addr, true);
++ err = mvpp2_prs_mac_da_accept(port, dev->dev_addr, true);
+ if (err) {
+- netdev_err(dev, "mvpp2_prs_mac_da_accept MC failed\n");
++ netdev_err(dev, "mvpp2_prs_mac_da_accept own addr failed\n");
+ return err;
+ }
+ err = mvpp2_prs_tag_mode_set(port->priv, port->id, MVPP2_TAG_TYPE_MH);
+@@ -7520,7 +7520,7 @@ retry:
+
+ if (!allmulti) {
+ netdev_for_each_mc_addr(ha, dev) {
+- if (mvpp2_prs_mac_da_accept(priv, id, ha->addr, true)) {
++ if (mvpp2_prs_mac_da_accept(port, ha->addr, true)) {
+ allmulti = true;
+ goto retry;
+ }
diff --git a/patches.drivers/net-mvpp2-Use-relaxed-I-O-in-data-path.patch b/patches.drivers/net-mvpp2-Use-relaxed-I-O-in-data-path.patch
new file mode 100644
index 0000000000..8e7b910a50
--- /dev/null
+++ b/patches.drivers/net-mvpp2-Use-relaxed-I-O-in-data-path.patch
@@ -0,0 +1,122 @@
+From: Yan Markman <ymarkman@marvell.com>
+Date: Tue, 27 Mar 2018 16:49:05 +0200
+Subject: net: mvpp2: Use relaxed I/O in data path
+Patch-mainline: v4.17-rc1
+Git-commit: cdcfeb0fb473e34e012b9a78b5cb377a6ad1434d
+References: bsc#1098633
+
+Use relaxed I/O on the hot path. This achieves significant performance
+improvements. On a 10G link, this makes a basic iperf TCP test go from
+an average of 4.5 Gbits/sec to about 9.40 Gbits/sec.
+
+Signed-off-by: Yan Markman <ymarkman@marvell.com>
+[Maxime: Commit message, cosmetic changes]
+Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 43 ++++++++++++++++++++++++-----------
+ 1 file changed, 30 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -1359,6 +1359,10 @@ static u32 mvpp2_read(struct mvpp2 *priv
+ return readl(priv->swth_base[0] + offset);
+ }
+
++static u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset)
++{
++ return readl_relaxed(priv->swth_base[0] + offset);
++}
+ /* These accessors should be used to access:
+ *
+ * - per-CPU registers, where each CPU has its own copy of the
+@@ -1407,6 +1411,18 @@ static u32 mvpp2_percpu_read(struct mvpp
+ return readl(priv->swth_base[cpu] + offset);
+ }
+
++static void mvpp2_percpu_write_relaxed(struct mvpp2 *priv, int cpu,
++ u32 offset, u32 data)
++{
++ writel_relaxed(data, priv->swth_base[cpu] + offset);
++}
++
++static u32 mvpp2_percpu_read_relaxed(struct mvpp2 *priv, int cpu,
++ u32 offset)
++{
++ return readl_relaxed(priv->swth_base[cpu] + offset);
++}
++
+ static dma_addr_t mvpp2_txdesc_dma_addr_get(struct mvpp2_port *port,
+ struct mvpp2_tx_desc *tx_desc)
+ {
+@@ -4442,8 +4458,8 @@ static inline void mvpp2_bm_pool_put(str
+ << MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT) &
+ MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK;
+
+- mvpp2_percpu_write(port->priv, cpu,
+- MVPP22_BM_ADDR_HIGH_RLS_REG, val);
++ mvpp2_percpu_write_relaxed(port->priv, cpu,
++ MVPP22_BM_ADDR_HIGH_RLS_REG, val);
+ }
+
+ /* MVPP2_BM_VIRT_RLS_REG is not interpreted by HW, and simply
+@@ -4451,10 +4467,10 @@ static inline void mvpp2_bm_pool_put(str
+ * descriptor. Instead of storing the virtual address, we
+ * store the physical address
+ */
+- mvpp2_percpu_write(port->priv, cpu,
+- MVPP2_BM_VIRT_RLS_REG, buf_phys_addr);
+- mvpp2_percpu_write(port->priv, cpu,
+- MVPP2_BM_PHY_RLS_REG(pool), buf_dma_addr);
++ mvpp2_percpu_write_relaxed(port->priv, cpu,
++ MVPP2_BM_VIRT_RLS_REG, buf_phys_addr);
++ mvpp2_percpu_write_relaxed(port->priv, cpu,
++ MVPP2_BM_PHY_RLS_REG(pool), buf_dma_addr);
+
+ put_cpu();
+ }
+@@ -5546,7 +5562,8 @@ static int mvpp2_aggr_desc_num_check(str
+ 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));
++ u32 val = mvpp2_read_relaxed(priv,
++ MVPP2_AGGR_TXQ_STATUS_REG(cpu));
+
+ aggr_txq->count = val & MVPP2_AGGR_TXQ_PENDING_MASK;
+ }
+@@ -5570,9 +5587,9 @@ static int mvpp2_txq_alloc_reserved_desc
+ int cpu = smp_processor_id();
+
+ val = (txq->id << MVPP2_TXQ_RSVD_REQ_Q_OFFSET) | num;
+- mvpp2_percpu_write(priv, cpu, MVPP2_TXQ_RSVD_REQ_REG, val);
++ mvpp2_percpu_write_relaxed(priv, cpu, MVPP2_TXQ_RSVD_REQ_REG, val);
+
+- val = mvpp2_percpu_read(priv, cpu, MVPP2_TXQ_RSVD_RSLT_REG);
++ val = mvpp2_percpu_read_relaxed(priv, cpu, MVPP2_TXQ_RSVD_RSLT_REG);
+
+ return val & MVPP2_TXQ_RSVD_RSLT_MASK;
+ }
+@@ -5677,8 +5694,8 @@ static inline int mvpp2_txq_sent_desc_pr
+ u32 val;
+
+ /* Reading status reg resets transmitted descriptor counter */
+- val = mvpp2_percpu_read(port->priv, smp_processor_id(),
+- MVPP2_TXQ_SENT_REG(txq->id));
++ val = mvpp2_percpu_read_relaxed(port->priv, smp_processor_id(),
++ MVPP2_TXQ_SENT_REG(txq->id));
+
+ return (val & MVPP2_TRANSMITTED_COUNT_MASK) >>
+ MVPP2_TRANSMITTED_COUNT_OFFSET;
+@@ -7044,8 +7061,8 @@ static int mvpp2_poll(struct napi_struct
+ *
+ * Each CPU has its own Rx/Tx cause register
+ */
+- cause_rx_tx = mvpp2_percpu_read(port->priv, qv->sw_thread_id,
+- MVPP2_ISR_RX_TX_CAUSE_REG(port->id));
++ cause_rx_tx = mvpp2_percpu_read_relaxed(port->priv, qv->sw_thread_id,
++ MVPP2_ISR_RX_TX_CAUSE_REG(port->id));
+
+ cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK;
+ if (cause_misc) {
diff --git a/patches.drivers/net-mvpp2-add-comments-about-smp_processor_id-usage.patch b/patches.drivers/net-mvpp2-add-comments-about-smp_processor_id-usage.patch
new file mode 100644
index 0000000000..15fef601c2
--- /dev/null
+++ b/patches.drivers/net-mvpp2-add-comments-about-smp_processor_id-usage.patch
@@ -0,0 +1,103 @@
+From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Date: Thu, 22 Jun 2017 14:23:18 +0200
+Subject: net: mvpp2: add comments about smp_processor_id() usage
+Patch-mainline: v4.13-rc1
+Git-commit: e0af22d9fd16d1cc2910a68d204e1767be2f8f14
+References: bsc#1098633
+
+A previous commit modified a number of smp_processor_id() used in
+migration-enabled contexts into get_cpu/put_cpu sections. However, a few
+smp_processor_id() calls remain in the driver, and this commit adds
+comments explaining why they can be kept.
+
+Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 33 +++++++++++++++++++++++++++++----
+ 1 file changed, 29 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -4162,7 +4162,10 @@ static inline void mvpp2_interrupts_disa
+ MVPP2_ISR_DISABLE_INTERRUPT(cpu_mask));
+ }
+
+-/* Mask the current CPU's Rx/Tx interrupts */
++/* Mask the current CPU's Rx/Tx interrupts
++ * Called by on_each_cpu(), guaranteed to run with migration disabled,
++ * using smp_processor_id() is OK.
++ */
+ static void mvpp2_interrupts_mask(void *arg)
+ {
+ struct mvpp2_port *port = arg;
+@@ -4171,7 +4174,10 @@ static void mvpp2_interrupts_mask(void *
+ MVPP2_ISR_RX_TX_MASK_REG(port->id), 0);
+ }
+
+-/* Unmask the current CPU's Rx/Tx interrupts */
++/* Unmask the current CPU's Rx/Tx interrupts.
++ * Called by on_each_cpu(), guaranteed to run with migration disabled,
++ * using smp_processor_id() is OK.
++ */
+ static void mvpp2_interrupts_unmask(void *arg)
+ {
+ struct mvpp2_port *port = arg;
+@@ -4554,7 +4560,11 @@ mvpp2_txq_next_desc_get(struct mvpp2_tx_
+ return txq->descs + tx_desc;
+ }
+
+-/* Update HW with number of aggregated Tx descriptors to be sent */
++/* Update HW with number of aggregated Tx descriptors to be sent
++ *
++ * Called only from mvpp2_tx(), so migration is disabled, using
++ * smp_processor_id() is OK.
++ */
+ static void mvpp2_aggr_txq_pend_desc_add(struct mvpp2_port *port, int pending)
+ {
+ /* aggregated access - relevant TXQ number is written in TX desc */
+@@ -4565,6 +4575,9 @@ static void mvpp2_aggr_txq_pend_desc_add
+
+ /* Check if there are enough free descriptors in aggregated txq.
+ * If not, update the number of occupied descriptors and repeat the check.
++ *
++ * Called only from mvpp2_tx(), so migration is disabled, using
++ * smp_processor_id() is OK.
+ */
+ static int mvpp2_aggr_desc_num_check(struct mvpp2 *priv,
+ struct mvpp2_tx_queue *aggr_txq, int num)
+@@ -4583,7 +4596,12 @@ static int mvpp2_aggr_desc_num_check(str
+ return 0;
+ }
+
+-/* Reserved Tx descriptors allocation request */
++/* Reserved Tx descriptors allocation request
++ *
++ * Called only from mvpp2_txq_reserved_desc_num_proc(), itself called
++ * only by mvpp2_tx(), so migration is disabled, using
++ * smp_processor_id() is OK.
++ */
+ static int mvpp2_txq_alloc_reserved_desc(struct mvpp2 *priv,
+ struct mvpp2_tx_queue *txq, int num)
+ {
+@@ -4687,6 +4705,10 @@ static u32 mvpp2_txq_desc_csum(int l3_of
+ /* Get number of sent descriptors and decrement counter.
+ * The number of sent descriptors is returned.
+ * Per-CPU access
++ *
++ * Called only from mvpp2_txq_done(), called from mvpp2_tx()
++ * (migration disabled) and from the TX completion tasklet (migration
++ * disabled) so using smp_processor_id() is OK.
+ */
+ static inline int mvpp2_txq_sent_desc_proc(struct mvpp2_port *port,
+ struct mvpp2_tx_queue *txq)
+@@ -4701,6 +4723,9 @@ static inline int mvpp2_txq_sent_desc_pr
+ MVPP2_TRANSMITTED_COUNT_OFFSET;
+ }
+
++/* Called through on_each_cpu(), so runs on all CPUs, with migration
++ * disabled, therefore using smp_processor_id() is OK.
++ */
+ static void mvpp2_txq_sent_counter_clear(void *arg)
+ {
+ struct mvpp2_port *port = arg;
diff --git a/patches.drivers/net-mvpp2-add-ethtool-GOP-statistics.patch b/patches.drivers/net-mvpp2-add-ethtool-GOP-statistics.patch
new file mode 100644
index 0000000000..93295715ec
--- /dev/null
+++ b/patches.drivers/net-mvpp2-add-ethtool-GOP-statistics.patch
@@ -0,0 +1,371 @@
+From: Miquel Raynal <miquel.raynal@free-electrons.com>
+Date: Mon, 6 Nov 2017 22:56:53 +0100
+Subject: net: mvpp2: add ethtool GOP statistics
+Patch-mainline: v4.15-rc1
+Git-commit: 118d6298f6f0556e54331a6e86de2313d134fdbb
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 228 ++++++++++++++++++++++++++++++++++-
+ 1 file changed, 223 insertions(+), 5 deletions(-)
+
+--- 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(stru
+ 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
+ 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
+ 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_et
+ .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 platf
+ 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 platf
+ }
+
+ 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_d
+ 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_d
+ 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_d
+ 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_
+ 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]);
diff --git a/patches.drivers/net-mvpp2-add-support-for-TX-interrupts-and-RX-queue.patch b/patches.drivers/net-mvpp2-add-support-for-TX-interrupts-and-RX-queue.patch
new file mode 100644
index 0000000000..7ddd424a07
--- /dev/null
+++ b/patches.drivers/net-mvpp2-add-support-for-TX-interrupts-and-RX-queue.patch
@@ -0,0 +1,546 @@
+From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Date: Thu, 3 Aug 2017 10:42:00 +0200
+Subject: net: mvpp2: add support for TX interrupts and RX queue distribution
+ modes
+Patch-mainline: v4.14-rc1
+Git-commit: 213f428f5056affa627056a5953eec58e3adf5a3
+References: bsc#1098633
+
+This commit adds the support for two related features:
+
+ - Support for TX interrupts, with one interrupt for each CPU
+
+ - Support for different RX queue distribution modes
+ MVPP2_QDIST_SINGLE_MODE where a single interrupt, shared by all
+ CPUs, receives the RX events, and MVPP2_QDIST_MULTI_MODE, where the
+ per-CPU interrupts used for TX events are also used for RX events.
+
+Since additional interrupts are needed, an update to the Device Tree
+binding is needed. However, backward compatibility is preserved with
+the old Device Tree binding, by gracefully degrading to the original
+behavior, with only one RX interrupt, and TX completion being handled
+by an hrtimer.
+
+Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 277 +++++++++++++++++++++++++++++++----
+ 1 file changed, 247 insertions(+), 30 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -120,6 +120,9 @@
+ #define MVPP2_TXQ_DESC_ADDR_REG 0x2084
+ #define MVPP2_TXQ_DESC_SIZE_REG 0x2088
+ #define MVPP2_TXQ_DESC_SIZE_MASK 0x3ff0
++#define MVPP2_TXQ_THRESH_REG 0x2094
++#define MVPP2_TXQ_THRESH_OFFSET 16
++#define MVPP2_TXQ_THRESH_MASK 0x3fff
+ #define MVPP2_AGGR_TXQ_UPDATE_REG 0x2090
+ #define MVPP2_TXQ_INDEX_REG 0x2098
+ #define MVPP2_TXQ_PREF_BUF_REG 0x209c
+@@ -183,6 +186,9 @@
+ #define MVPP22_AXI_CODE_DOMAIN_SYSTEM 3
+
+ /* Interrupt Cause and Mask registers */
++#define MVPP2_ISR_TX_THRESHOLD_REG(port) (0x5140 + 4 * (port))
++#define MVPP2_MAX_ISR_TX_THRESHOLD 0xfffff0
++
+ #define MVPP2_ISR_RX_THRESHOLD_REG(rxq) (0x5200 + 4 * (rxq))
+ #define MVPP2_MAX_ISR_RX_THRESHOLD 0xfffff0
+ #define MVPP21_ISR_RXQ_GROUP_REG(port) (0x5400 + 4 * (port))
+@@ -206,6 +212,7 @@
+ #define MVPP2_ISR_RX_TX_CAUSE_REG(port) (0x5480 + 4 * (port))
+ #define MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK 0xffff
+ #define MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK 0xff0000
++#define MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_OFFSET 16
+ #define MVPP2_CAUSE_RX_FIFO_OVERRUN_MASK BIT(24)
+ #define MVPP2_CAUSE_FCS_ERR_MASK BIT(25)
+ #define MVPP2_CAUSE_TX_FIFO_UNDERRUN_MASK BIT(26)
+@@ -372,6 +379,7 @@
+ /* Coalescing */
+ #define MVPP2_TXDONE_COAL_PKTS_THRESH 15
+ #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
+
+@@ -811,6 +819,9 @@ struct mvpp2_port {
+
+ struct mvpp2_queue_vector qvecs[MVPP2_MAX_QVECS];
+ unsigned int nqvecs;
++ bool has_tx_irqs;
++
++ u32 tx_time_coal;
+ };
+
+ /* The mvpp2_tx_desc and mvpp2_rx_desc structures describe the
+@@ -1076,6 +1087,15 @@ struct mvpp2_bm_pool {
+ u32 port_map;
+ };
+
++/* Queue modes */
++#define MVPP2_QDIST_SINGLE_MODE 0
++#define MVPP2_QDIST_MULTI_MODE 1
++
++static int queue_mode = MVPP2_QDIST_SINGLE_MODE;
++
++module_param(queue_mode, int, 0444);
++MODULE_PARM_DESC(queue_mode, "Set queue_mode (single=0, multi=1)");
++
+ #define MVPP2_DRIVER_NAME "mvpp2"
+ #define MVPP2_DRIVER_VERSION "1.0"
+
+@@ -4187,11 +4207,40 @@ static void mvpp2_interrupts_mask(void *
+ static void mvpp2_interrupts_unmask(void *arg)
+ {
+ struct mvpp2_port *port = arg;
++ u32 val;
++
++ val = MVPP2_CAUSE_MISC_SUM_MASK |
++ MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK;
++ if (port->has_tx_irqs)
++ val |= MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK;
+
+ mvpp2_percpu_write(port->priv, smp_processor_id(),
+- MVPP2_ISR_RX_TX_MASK_REG(port->id),
+- (MVPP2_CAUSE_MISC_SUM_MASK |
+- MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK));
++ MVPP2_ISR_RX_TX_MASK_REG(port->id), val);
++}
++
++static void
++mvpp2_shared_interrupt_mask_unmask(struct mvpp2_port *port, bool mask)
++{
++ u32 val;
++ int i;
++
++ if (port->priv->hw_version != MVPP22)
++ return;
++
++ if (mask)
++ val = 0;
++ else
++ val = MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK;
++
++ for (i = 0; i < port->nqvecs; i++) {
++ struct mvpp2_queue_vector *v = port->qvecs + i;
++
++ if (v->type != MVPP2_QUEUE_VECTOR_SHARED)
++ continue;
++
++ mvpp2_percpu_write(port->priv, v->sw_thread_id,
++ MVPP2_ISR_RX_TX_MASK_REG(port->id), val);
++ }
+ }
+
+ /* Port configuration routines */
+@@ -4812,6 +4861,23 @@ static void mvpp2_rx_pkts_coal_set(struc
+ put_cpu();
+ }
+
++/* For some reason in the LSP this is done on each CPU. Why ? */
++static void mvpp2_tx_pkts_coal_set(struct mvpp2_port *port,
++ struct mvpp2_tx_queue *txq)
++{
++ int cpu = get_cpu();
++ u32 val;
++
++ if (txq->done_pkts_coal > MVPP2_TXQ_THRESH_MASK)
++ txq->done_pkts_coal = MVPP2_TXQ_THRESH_MASK;
++
++ val = (txq->done_pkts_coal << MVPP2_TXQ_THRESH_OFFSET);
++ mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_NUM_REG, txq->id);
++ mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_THRESH_REG, val);
++
++ put_cpu();
++}
++
+ static u32 mvpp2_usec_to_cycles(u32 usec, unsigned long clk_hz)
+ {
+ u64 tmp = (u64)clk_hz * usec;
+@@ -4848,6 +4914,22 @@ static void mvpp2_rx_time_coal_set(struc
+ mvpp2_write(port->priv, MVPP2_ISR_RX_THRESHOLD_REG(rxq->id), val);
+ }
+
++static void mvpp2_tx_time_coal_set(struct mvpp2_port *port)
++{
++ unsigned long freq = port->priv->tclk;
++ u32 val = mvpp2_usec_to_cycles(port->tx_time_coal, freq);
++
++ if (val > MVPP2_MAX_ISR_TX_THRESHOLD) {
++ port->tx_time_coal =
++ mvpp2_cycles_to_usec(MVPP2_MAX_ISR_TX_THRESHOLD, freq);
++
++ /* re-evaluate to get actual register value */
++ val = mvpp2_usec_to_cycles(port->tx_time_coal, freq);
++ }
++
++ mvpp2_write(port->priv, MVPP2_ISR_TX_THRESHOLD_REG(port->id), val);
++}
++
+ /* Free Tx queue skbuffs */
+ static void mvpp2_txq_bufs_free(struct mvpp2_port *port,
+ struct mvpp2_tx_queue *txq,
+@@ -4906,7 +4988,8 @@ static void mvpp2_txq_done(struct mvpp2_
+ netif_tx_wake_queue(nq);
+ }
+
+-static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause)
++static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause,
++ int cpu)
+ {
+ struct mvpp2_tx_queue *txq;
+ struct mvpp2_txq_pcpu *txq_pcpu;
+@@ -4917,7 +5000,7 @@ static unsigned int mvpp2_tx_done(struct
+ if (!txq)
+ break;
+
+- txq_pcpu = this_cpu_ptr(txq->pcpu);
++ txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
+
+ if (txq_pcpu->count) {
+ mvpp2_txq_done(port, txq, txq_pcpu);
+@@ -5305,6 +5388,14 @@ static int mvpp2_setup_txqs(struct mvpp2
+ goto err_cleanup;
+ }
+
++ if (port->has_tx_irqs) {
++ mvpp2_tx_time_coal_set(port);
++ for (queue = 0; queue < port->ntxqs; queue++) {
++ txq = port->txqs[queue];
++ mvpp2_tx_pkts_coal_set(port, txq);
++ }
++ }
++
+ on_each_cpu(mvpp2_txq_sent_counter_clear, port, 1);
+ return 0;
+
+@@ -5411,7 +5502,7 @@ static void mvpp2_tx_proc_cb(unsigned lo
+
+ /* Process all the Tx queues */
+ cause = (1 << port->ntxqs) - 1;
+- tx_todo = mvpp2_tx_done(port, cause);
++ tx_todo = mvpp2_tx_done(port, cause, smp_processor_id());
+
+ /* Set the timer in case not all the packets were processed */
+ if (tx_todo)
+@@ -5787,7 +5878,8 @@ out:
+ mvpp2_txq_done(port, txq, txq_pcpu);
+
+ /* Set the timer in case not all frags were processed */
+- if (txq_pcpu->count <= frags && txq_pcpu->count > 0) {
++ if (!port->has_tx_irqs && txq_pcpu->count <= frags &&
++ txq_pcpu->count > 0) {
+ struct mvpp2_port_pcpu *port_pcpu = this_cpu_ptr(port->pcpu);
+
+ mvpp2_timer_set(port_pcpu);
+@@ -5808,7 +5900,7 @@ static inline void mvpp2_cause_error(str
+
+ static int mvpp2_poll(struct napi_struct *napi, int budget)
+ {
+- u32 cause_rx_tx, cause_rx, cause_misc;
++ u32 cause_rx_tx, cause_rx, cause_tx, cause_misc;
+ int rx_done = 0;
+ struct mvpp2_port *port = netdev_priv(napi->dev);
+ struct mvpp2_queue_vector *qv;
+@@ -5826,11 +5918,10 @@ static int mvpp2_poll(struct napi_struct
+ *
+ * Each CPU has its own Rx/Tx cause register
+ */
+- cause_rx_tx = mvpp2_percpu_read(port->priv, cpu,
++ cause_rx_tx = mvpp2_percpu_read(port->priv, qv->sw_thread_id,
+ MVPP2_ISR_RX_TX_CAUSE_REG(port->id));
+- cause_rx_tx &= ~MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK;
+- cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK;
+
++ cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK;
+ if (cause_misc) {
+ mvpp2_cause_error(port->dev, cause_misc);
+
+@@ -5841,9 +5932,15 @@ static int mvpp2_poll(struct napi_struct
+ cause_rx_tx & ~MVPP2_CAUSE_MISC_SUM_MASK);
+ }
+
+- cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK;
++ cause_tx = cause_rx_tx & MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK;
++ if (cause_tx) {
++ cause_tx >>= MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_OFFSET;
++ mvpp2_tx_done(port, cause_tx, qv->sw_thread_id);
++ }
+
+ /* Process RX packets */
++ cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK;
++ cause_rx <<= qv->first_rxq;
+ cause_rx |= qv->pending_cause_rx;
+ while (cause_rx && budget > 0) {
+ int count;
+@@ -6006,6 +6103,10 @@ static int mvpp2_irqs_init(struct mvpp2_
+ err = request_irq(qv->irq, mvpp2_isr, 0, port->dev->name, qv);
+ if (err)
+ goto err;
++
++ if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE)
++ irq_set_affinity_hint(qv->irq,
++ cpumask_of(qv->sw_thread_id));
+ }
+
+ return 0;
+@@ -6013,6 +6114,7 @@ err:
+ for (i = 0; i < port->nqvecs; i++) {
+ struct mvpp2_queue_vector *qv = port->qvecs + i;
+
++ irq_set_affinity_hint(qv->irq, NULL);
+ free_irq(qv->irq, qv);
+ }
+
+@@ -6026,6 +6128,7 @@ static void mvpp2_irqs_deinit(struct mvp
+ for (i = 0; i < port->nqvecs; i++) {
+ struct mvpp2_queue_vector *qv = port->qvecs + i;
+
++ irq_set_affinity_hint(qv->irq, NULL);
+ free_irq(qv->irq, qv);
+ }
+ }
+@@ -6087,6 +6190,7 @@ static int mvpp2_open(struct net_device
+
+ /* Unmask interrupts on all CPUs */
+ on_each_cpu(mvpp2_interrupts_unmask, port, 1);
++ mvpp2_shared_interrupt_mask_unmask(port, false);
+
+ mvpp2_start_dev(port);
+
+@@ -6112,14 +6216,17 @@ static int mvpp2_stop(struct net_device
+
+ /* Mask interrupts on all CPUs */
+ on_each_cpu(mvpp2_interrupts_mask, port, 1);
++ mvpp2_shared_interrupt_mask_unmask(port, true);
+
+ mvpp2_irqs_deinit(port);
+- for_each_present_cpu(cpu) {
+- port_pcpu = per_cpu_ptr(port->pcpu, cpu);
++ if (!port->has_tx_irqs) {
++ for_each_present_cpu(cpu) {
++ port_pcpu = per_cpu_ptr(port->pcpu, cpu);
+
+- hrtimer_cancel(&port_pcpu->tx_done_timer);
+- port_pcpu->timer_scheduled = false;
+- tasklet_kill(&port_pcpu->tx_done_tasklet);
++ hrtimer_cancel(&port_pcpu->tx_done_timer);
++ port_pcpu->timer_scheduled = false;
++ tasklet_kill(&port_pcpu->tx_done_tasklet);
++ }
+ }
+ mvpp2_cleanup_rxqs(port);
+ mvpp2_cleanup_txqs(port);
+@@ -6303,10 +6410,18 @@ static int mvpp2_ethtool_set_coalesce(st
+ mvpp2_rx_time_coal_set(port, rxq);
+ }
+
++ if (port->has_tx_irqs) {
++ port->tx_time_coal = c->tx_coalesce_usecs;
++ mvpp2_tx_time_coal_set(port);
++ }
++
+ for (queue = 0; queue < port->ntxqs; queue++) {
+ struct mvpp2_tx_queue *txq = port->txqs[queue];
+
+ txq->done_pkts_coal = c->tx_max_coalesced_frames;
++
++ if (port->has_tx_irqs)
++ mvpp2_tx_pkts_coal_set(port, txq);
+ }
+
+ return 0;
+@@ -6431,8 +6546,11 @@ static const struct ethtool_ops mvpp2_et
+ .set_link_ksettings = phy_ethtool_set_link_ksettings,
+ };
+
+-static int mvpp2_queue_vectors_init(struct mvpp2_port *port,
+- struct device_node *port_node)
++/* Used for PPv2.1, or PPv2.2 with the old Device Tree binding that
++ * had a single IRQ defined per-port.
++ */
++static int mvpp2_simple_queue_vectors_init(struct mvpp2_port *port,
++ struct device_node *port_node)
+ {
+ struct mvpp2_queue_vector *v = &port->qvecs[0];
+
+@@ -6453,6 +6571,66 @@ static int mvpp2_queue_vectors_init(stru
+ return 0;
+ }
+
++static int mvpp2_multi_queue_vectors_init(struct mvpp2_port *port,
++ struct device_node *port_node)
++{
++ struct mvpp2_queue_vector *v;
++ int i, ret;
++
++ port->nqvecs = num_possible_cpus();
++ if (queue_mode == MVPP2_QDIST_SINGLE_MODE)
++ port->nqvecs += 1;
++
++ for (i = 0; i < port->nqvecs; i++) {
++ char irqname[16];
++
++ v = port->qvecs + i;
++
++ v->port = port;
++ v->type = MVPP2_QUEUE_VECTOR_PRIVATE;
++ v->sw_thread_id = i;
++ v->sw_thread_mask = BIT(i);
++
++ snprintf(irqname, sizeof(irqname), "tx-cpu%d", i);
++
++ if (queue_mode == MVPP2_QDIST_MULTI_MODE) {
++ v->first_rxq = i * MVPP2_DEFAULT_RXQ;
++ v->nrxqs = MVPP2_DEFAULT_RXQ;
++ } else if (queue_mode == MVPP2_QDIST_SINGLE_MODE &&
++ i == (port->nqvecs - 1)) {
++ v->first_rxq = 0;
++ v->nrxqs = port->nrxqs;
++ v->type = MVPP2_QUEUE_VECTOR_SHARED;
++ strncpy(irqname, "rx-shared", sizeof(irqname));
++ }
++
++ v->irq = of_irq_get_byname(port_node, irqname);
++ if (v->irq <= 0) {
++ ret = -EINVAL;
++ goto err;
++ }
++
++ netif_napi_add(port->dev, &v->napi, mvpp2_poll,
++ NAPI_POLL_WEIGHT);
++ }
++
++ return 0;
++
++err:
++ for (i = 0; i < port->nqvecs; i++)
++ irq_dispose_mapping(port->qvecs[i].irq);
++ return ret;
++}
++
++static int mvpp2_queue_vectors_init(struct mvpp2_port *port,
++ struct device_node *port_node)
++{
++ if (port->has_tx_irqs)
++ return mvpp2_multi_queue_vectors_init(port, port_node);
++ else
++ return mvpp2_simple_queue_vectors_init(port, port_node);
++}
++
+ static void mvpp2_queue_vectors_deinit(struct mvpp2_port *port)
+ {
+ int i;
+@@ -6512,6 +6690,8 @@ static int mvpp2_port_init(struct mvpp2_
+ mvpp2_egress_disable(port);
+ mvpp2_port_disable(port);
+
++ port->tx_time_coal = MVPP2_TXDONE_COAL_USEC;
++
+ port->txqs = devm_kcalloc(dev, port->ntxqs, sizeof(*port->txqs),
+ GFP_KERNEL);
+ if (!port->txqs)
+@@ -6611,6 +6791,30 @@ err_free_percpu:
+ return err;
+ }
+
++/* Checks if the port DT description has the TX interrupts
++ * described. On PPv2.1, there are no such interrupts. On PPv2.2,
++ * there are available, but we need to keep support for old DTs.
++ */
++static bool mvpp2_port_has_tx_irqs(struct mvpp2 *priv,
++ struct device_node *port_node)
++{
++ char *irqs[5] = { "rx-shared", "tx-cpu0", "tx-cpu1",
++ "tx-cpu2", "tx-cpu3" };
++ int ret, i;
++
++ if (priv->hw_version == MVPP21)
++ return false;
++
++ for (i = 0; i < 5; i++) {
++ ret = of_property_match_string(port_node, "interrupt-names",
++ irqs[i]);
++ if (ret < 0)
++ return false;
++ }
++
++ return true;
++}
++
+ /* Ports initialization */
+ static int mvpp2_port_probe(struct platform_device *pdev,
+ struct device_node *port_node,
+@@ -6625,13 +6829,22 @@ static int mvpp2_port_probe(struct platf
+ const char *mac_from;
+ char hw_mac_addr[ETH_ALEN] = {0};
+ unsigned int ntxqs, nrxqs;
++ bool has_tx_irqs;
+ u32 id;
+ int features;
+ int phy_mode;
+ int err, i, cpu;
+
++ has_tx_irqs = mvpp2_port_has_tx_irqs(priv, port_node);
++
++ if (!has_tx_irqs)
++ queue_mode = MVPP2_QDIST_SINGLE_MODE;
++
+ ntxqs = MVPP2_MAX_TXQ;
+- nrxqs = MVPP2_DEFAULT_RXQ;
++ if (priv->hw_version == MVPP22 && queue_mode == MVPP2_QDIST_MULTI_MODE)
++ nrxqs = MVPP2_DEFAULT_RXQ * num_possible_cpus();
++ else
++ nrxqs = MVPP2_DEFAULT_RXQ;
+
+ dev = alloc_etherdev_mqs(sizeof(*port), ntxqs, nrxqs);
+ if (!dev)
+@@ -6666,6 +6879,8 @@ static int mvpp2_port_probe(struct platf
+ port->dev = dev;
+ port->ntxqs = ntxqs;
+ port->nrxqs = nrxqs;
++ port->priv = priv;
++ port->has_tx_irqs = has_tx_irqs;
+
+ err = mvpp2_queue_vectors_init(port, port_node);
+ if (err)
+@@ -6674,7 +6889,6 @@ static int mvpp2_port_probe(struct platf
+ if (of_property_read_bool(port_node, "marvell,loopback"))
+ port->flags |= MVPP2_F_LOOPBACK;
+
+- port->priv = priv;
+ port->id = id;
+ if (priv->hw_version == MVPP21)
+ port->first_rxq = port->id * port->nrxqs;
+@@ -6749,16 +6963,19 @@ static int mvpp2_port_probe(struct platf
+ goto err_free_txq_pcpu;
+ }
+
+- for_each_present_cpu(cpu) {
+- port_pcpu = per_cpu_ptr(port->pcpu, cpu);
+-
+- hrtimer_init(&port_pcpu->tx_done_timer, CLOCK_MONOTONIC,
+- HRTIMER_MODE_REL_PINNED);
+- port_pcpu->tx_done_timer.function = mvpp2_hr_timer_cb;
+- port_pcpu->timer_scheduled = false;
++ if (!port->has_tx_irqs) {
++ for_each_present_cpu(cpu) {
++ port_pcpu = per_cpu_ptr(port->pcpu, cpu);
+
+- tasklet_init(&port_pcpu->tx_done_tasklet, mvpp2_tx_proc_cb,
+- (unsigned long)dev);
++ hrtimer_init(&port_pcpu->tx_done_timer, CLOCK_MONOTONIC,
++ HRTIMER_MODE_REL_PINNED);
++ port_pcpu->tx_done_timer.function = mvpp2_hr_timer_cb;
++ port_pcpu->timer_scheduled = false;
++
++ tasklet_init(&port_pcpu->tx_done_tasklet,
++ mvpp2_tx_proc_cb,
++ (unsigned long)dev);
++ }
+ }
+
+ features = NETIF_F_SG | NETIF_F_IP_CSUM;
diff --git a/patches.drivers/net-mvpp2-adjust-the-coalescing-parameters.patch b/patches.drivers/net-mvpp2-adjust-the-coalescing-parameters.patch
new file mode 100644
index 0000000000..fe330d3e63
--- /dev/null
+++ b/patches.drivers/net-mvpp2-adjust-the-coalescing-parameters.patch
@@ -0,0 +1,34 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Mon, 11 Dec 2017 09:13:29 +0100
+Subject: net: mvpp2: adjust the coalescing parameters
+Patch-mainline: v4.16-rc1
+Git-commit: 86162281c25fd76e604978ffa0b2838e86ad4287
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- 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
diff --git a/patches.drivers/net-mvpp2-align-values-in-ethtool-get_coalesce.patch b/patches.drivers/net-mvpp2-align-values-in-ethtool-get_coalesce.patch
new file mode 100644
index 0000000000..0cb608fc52
--- /dev/null
+++ b/patches.drivers/net-mvpp2-align-values-in-ethtool-get_coalesce.patch
@@ -0,0 +1,32 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Mon, 11 Dec 2017 09:13:27 +0100
+Subject: net: mvpp2: align values in ethtool get_coalesce
+Patch-mainline: v4.16-rc1
+Git-commit: 385c284fee84d2ad1da3b67111f199cd5641a867
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -7324,9 +7324,9 @@ static int mvpp2_ethtool_get_coalesce(st
+ {
+ 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;
+ }
+
diff --git a/patches.drivers/net-mvpp2-allocate-zeroed-tx-descriptors.patch b/patches.drivers/net-mvpp2-allocate-zeroed-tx-descriptors.patch
new file mode 100644
index 0000000000..f3262d4384
--- /dev/null
+++ b/patches.drivers/net-mvpp2-allocate-zeroed-tx-descriptors.patch
@@ -0,0 +1,34 @@
+From: Yan Markman <ymarkman@marvell.com>
+Date: Thu, 30 Nov 2017 10:49:46 +0100
+Subject: net: mvpp2: allocate zeroed tx descriptors
+Patch-mainline: v4.15-rc3
+Git-commit: a154f8e399a063137fc42b961f437248d55ece29
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- 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 pl
+ 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)
diff --git a/patches.drivers/net-mvpp2-check-ethtool-sets-the-Tx-ring-size-is-to-.patch b/patches.drivers/net-mvpp2-check-ethtool-sets-the-Tx-ring-size-is-to-.patch
new file mode 100644
index 0000000000..887cdc0d1f
--- /dev/null
+++ b/patches.drivers/net-mvpp2-check-ethtool-sets-the-Tx-ring-size-is-to-.patch
@@ -0,0 +1,37 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Tue, 28 Nov 2017 14:19:51 +0100
+Subject: net: mvpp2: check ethtool sets the Tx ring size is to a valid min
+ value
+Patch-mainline: v4.15-rc2
+Git-commit: 76e583c5f50ef539caea6935d37af3595034befb
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -6842,6 +6842,12 @@ static int mvpp2_check_ringparam_valid(s
+ 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);
diff --git a/patches.drivers/net-mvpp2-cleanup-probed-ports-in-the-probe-error-pa.patch b/patches.drivers/net-mvpp2-cleanup-probed-ports-in-the-probe-error-pa.patch
new file mode 100644
index 0000000000..45d543b054
--- /dev/null
+++ b/patches.drivers/net-mvpp2-cleanup-probed-ports-in-the-probe-error-pa.patch
@@ -0,0 +1,50 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Tue, 28 Nov 2017 14:19:49 +0100
+Subject: net: mvpp2: cleanup probed ports in the probe error path
+Patch-mainline: v4.15-rc2
+Git-commit: 26146b0e6b6869c6cd8a45ab3a4a5562e7a91b23
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -8329,7 +8329,7 @@ static int mvpp2_probe(struct platform_d
+ 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_d
+ 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)
diff --git a/patches.drivers/net-mvpp2-do-not-call-txq_done-from-the-Tx-path-when.patch b/patches.drivers/net-mvpp2-do-not-call-txq_done-from-the-Tx-path-when.patch
new file mode 100644
index 0000000000..ea4e5792cf
--- /dev/null
+++ b/patches.drivers/net-mvpp2-do-not-call-txq_done-from-the-Tx-path-when.patch
@@ -0,0 +1,35 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Mon, 23 Oct 2017 15:24:31 +0200
+Subject: net: mvpp2: do not call txq_done from the Tx path when Tx irqs are
+ used
+Patch-mainline: v4.14-rc7
+Git-commit: 082297e61480c4d72ed75b31077e74aca0e7c799
+References: bsc#1098633
+
+When Tx IRQs are used, txq_bufs_free() can be called from both the Tx
+path and from NAPI poll(). This led to CPU stalls as if these two tasks
+(Tx and Poll) are scheduled on two CPUs at the same time, DMA unmapping
+operations are done on the same txq buffers.
+
+This patch adds a check not to call txq_done() from the Tx path if Tx
+interrupts are used as it does not make sense to do so.
+
+Fixes: edc660fa09e2 ("net: mvpp2: replace TX coalescing interrupts with hrtimer")
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -6499,7 +6499,7 @@ out:
+ }
+
+ /* Finalize TX processing */
+- if (txq_pcpu->count >= txq->done_pkts_coal)
++ if (!port->has_tx_irqs && txq_pcpu->count >= txq->done_pkts_coal)
+ mvpp2_txq_done(port, txq, txq_pcpu);
+
+ /* Set the timer in case not all frags were processed */
diff --git a/patches.drivers/net-mvpp2-do-not-disable-GMAC-padding.patch b/patches.drivers/net-mvpp2-do-not-disable-GMAC-padding.patch
new file mode 100644
index 0000000000..b4ff856caa
--- /dev/null
+++ b/patches.drivers/net-mvpp2-do-not-disable-GMAC-padding.patch
@@ -0,0 +1,46 @@
+From: Yan Markman <ymarkman@marvell.com>
+Date: Tue, 28 Nov 2017 14:19:50 +0100
+Subject: net: mvpp2: do not disable GMAC padding
+Patch-mainline: v4.15-rc2
+Git-commit: e749aca84b10f3987b2ee1f76e0c7d8aacc5653c
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 9 ---------
+ 1 file changed, 9 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -4629,11 +4629,6 @@ static void mvpp2_port_mii_gmac_configur
+ 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_configur
+ 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 */
diff --git a/patches.drivers/net-mvpp2-do-not-select-the-internal-source-clock.patch b/patches.drivers/net-mvpp2-do-not-select-the-internal-source-clock.patch
new file mode 100644
index 0000000000..db56978610
--- /dev/null
+++ b/patches.drivers/net-mvpp2-do-not-select-the-internal-source-clock.patch
@@ -0,0 +1,39 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Mon, 25 Sep 2017 14:59:48 +0200
+Subject: net: mvpp2: do not select the internal source clock
+Patch-mainline: v4.14-rc4
+Git-commit: c7dfc8c848a48f176096f66a14879fb3333a460f
+References: bsc#1098633
+
+This patch stops the internal MAC Tx clock from being enabled as the
+internal clock isn't used. The definition used for the bit controlling
+this behaviour is renamed as well as it was wrongly named (bit 4 of
+GMAC_CTRL_2_REG).
+
+Fixes: 3919357fb0bb ("net: mvpp2: initialize the GMAC when using a port")
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -333,7 +333,7 @@
+ #define MVPP2_GMAC_INBAND_AN_MASK BIT(0)
+ #define MVPP2_GMAC_FLOW_CTRL_MASK GENMASK(2, 1)
+ #define MVPP2_GMAC_PCS_ENABLE_MASK BIT(3)
+-#define MVPP2_GMAC_PORT_RGMII_MASK BIT(4)
++#define MVPP2_GMAC_INTERNAL_CLK_MASK BIT(4)
+ #define MVPP2_GMAC_DISABLE_PADDING BIT(5)
+ #define MVPP2_GMAC_PORT_RESET_MASK BIT(6)
+ #define MVPP2_GMAC_AUTONEG_CONFIG 0xc
+@@ -4599,7 +4599,6 @@ static void mvpp2_port_mii_gmac_configur
+ val |= MVPP2_GMAC_INBAND_AN_MASK | MVPP2_GMAC_PCS_ENABLE_MASK;
+ } else if (phy_interface_mode_is_rgmii(port->phy_interface)) {
+ val &= ~MVPP2_GMAC_PCS_ENABLE_MASK;
+- val |= MVPP2_GMAC_PORT_RGMII_MASK;
+ }
+ writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
+
diff --git a/patches.drivers/net-mvpp2-do-not-set-GMAC-autoneg-when-using-XLG-MAC.patch b/patches.drivers/net-mvpp2-do-not-set-GMAC-autoneg-when-using-XLG-MAC.patch
new file mode 100644
index 0000000000..75f4721af6
--- /dev/null
+++ b/patches.drivers/net-mvpp2-do-not-set-GMAC-autoneg-when-using-XLG-MAC.patch
@@ -0,0 +1,105 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Wed, 30 Aug 2017 10:29:18 +0200
+Subject: net: mvpp2: do not set GMAC autoneg when using XLG MAC
+Patch-mainline: v4.14-rc1
+Git-commit: 65a2c09aea8b9b620bbb3e59f68090a2b7151865
+References: bsc#1098633
+
+When using the XLG MAC, it does not make sense to force the GMAC autoneg
+parameters. This patch adds checks to only set the GMAC autoneg
+parameters when needed (i.e. when not using the XLG MAC).
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 64 ++++++++++++++++++++++-------------
+ 1 file changed, 42 insertions(+), 22 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -5735,6 +5735,37 @@ static irqreturn_t mvpp2_isr(int irq, vo
+ return IRQ_HANDLED;
+ }
+
++static void mvpp2_gmac_set_autoneg(struct mvpp2_port *port,
++ struct phy_device *phydev)
++{
++ u32 val;
++
++ if (port->phy_interface != PHY_INTERFACE_MODE_RGMII &&
++ port->phy_interface != PHY_INTERFACE_MODE_RGMII_ID &&
++ port->phy_interface != PHY_INTERFACE_MODE_RGMII_RXID &&
++ port->phy_interface != PHY_INTERFACE_MODE_RGMII_TXID &&
++ port->phy_interface != PHY_INTERFACE_MODE_SGMII)
++ return;
++
++ val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
++ val &= ~(MVPP2_GMAC_CONFIG_MII_SPEED |
++ MVPP2_GMAC_CONFIG_GMII_SPEED |
++ MVPP2_GMAC_CONFIG_FULL_DUPLEX |
++ MVPP2_GMAC_AN_SPEED_EN |
++ MVPP2_GMAC_AN_DUPLEX_EN);
++
++ if (phydev->duplex)
++ val |= MVPP2_GMAC_CONFIG_FULL_DUPLEX;
++
++ if (phydev->speed == SPEED_1000)
++ val |= MVPP2_GMAC_CONFIG_GMII_SPEED;
++ else if (phydev->speed == SPEED_100)
++ val |= MVPP2_GMAC_CONFIG_MII_SPEED;
++
++ writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
++
++}
++
+ /* Adjust link */
+ static void mvpp2_link_event(struct net_device *dev)
+ {
+@@ -5745,24 +5776,7 @@ static void mvpp2_link_event(struct net_
+ if (phydev->link) {
+ if ((port->speed != phydev->speed) ||
+ (port->duplex != phydev->duplex)) {
+- u32 val;
+-
+- val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
+- val &= ~(MVPP2_GMAC_CONFIG_MII_SPEED |
+- MVPP2_GMAC_CONFIG_GMII_SPEED |
+- MVPP2_GMAC_CONFIG_FULL_DUPLEX |
+- MVPP2_GMAC_AN_SPEED_EN |
+- MVPP2_GMAC_AN_DUPLEX_EN);
+-
+- if (phydev->duplex)
+- val |= MVPP2_GMAC_CONFIG_FULL_DUPLEX;
+-
+- if (phydev->speed == SPEED_1000)
+- val |= MVPP2_GMAC_CONFIG_GMII_SPEED;
+- else if (phydev->speed == SPEED_100)
+- val |= MVPP2_GMAC_CONFIG_MII_SPEED;
+-
+- writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
++ mvpp2_gmac_set_autoneg(port, phydev);
+
+ port->duplex = phydev->duplex;
+ port->speed = phydev->speed;
+@@ -5773,10 +5787,16 @@ static void mvpp2_link_event(struct net_
+ port->link = phydev->link;
+
+ if (phydev->link) {
+- val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
+- val |= (MVPP2_GMAC_FORCE_LINK_PASS |
+- MVPP2_GMAC_FORCE_LINK_DOWN);
+- writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
++ if (port->phy_interface == PHY_INTERFACE_MODE_RGMII ||
++ port->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
++ port->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID ||
++ port->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID ||
++ port->phy_interface == PHY_INTERFACE_MODE_SGMII) {
++ val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
++ val |= (MVPP2_GMAC_FORCE_LINK_PASS |
++ MVPP2_GMAC_FORCE_LINK_DOWN);
++ writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
++ }
+
+ mvpp2_interrupts_enable(port);
+ mvpp2_port_enable(port);
diff --git a/patches.drivers/net-mvpp2-do-not-sleep-in-set_rx_mode.patch b/patches.drivers/net-mvpp2-do-not-sleep-in-set_rx_mode.patch
new file mode 100644
index 0000000000..cf1307f4fb
--- /dev/null
+++ b/patches.drivers/net-mvpp2-do-not-sleep-in-set_rx_mode.patch
@@ -0,0 +1,38 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Tue, 24 Oct 2017 11:41:28 +0200
+Subject: net: mvpp2: do not sleep in set_rx_mode
+Patch-mainline: v4.14-rc7
+Git-commit: 239dd4ee4838523419ad16e05b16a2003b71d317
+References: bsc#1098633
+
+This patch replaces GFP_KERNEL by GFP_ATOMIC to avoid sleeping in the
+ndo_set_rx_mode() call which is called with BH disabled.
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -3396,7 +3396,7 @@ mvpp2_prs_mac_da_range_find(struct mvpp2
+ struct mvpp2_prs_entry *pe;
+ int tid;
+
+- pe = kzalloc(sizeof(*pe), GFP_KERNEL);
++ pe = kzalloc(sizeof(*pe), GFP_ATOMIC);
+ if (!pe)
+ return NULL;
+ mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_MAC);
+@@ -3458,7 +3458,7 @@ static int mvpp2_prs_mac_da_accept(struc
+ if (tid < 0)
+ return tid;
+
+- pe = kzalloc(sizeof(*pe), GFP_KERNEL);
++ pe = kzalloc(sizeof(*pe), GFP_ATOMIC);
+ if (!pe)
+ return -ENOMEM;
+ mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_MAC);
diff --git a/patches.drivers/net-mvpp2-do-not-unmap-TSO-headers-buffers.patch b/patches.drivers/net-mvpp2-do-not-unmap-TSO-headers-buffers.patch
new file mode 100644
index 0000000000..5045258e88
--- /dev/null
+++ b/patches.drivers/net-mvpp2-do-not-unmap-TSO-headers-buffers.patch
@@ -0,0 +1,65 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Mon, 23 Oct 2017 15:24:30 +0200
+Subject: net: mvpp2: do not unmap TSO headers buffers
+Patch-mainline: v4.14-rc7
+Git-commit: 20920267885218fda08dc12c7d3814938ab15b54
+References: bsc#1098633
+
+The TSO header buffers are coming from a per cpu pool and should not
+be unmapped as they are reused. The PPv2 driver was unmapping all
+descriptors buffers unconditionally. This patch fixes this by checking
+the buffers dma addresses before unmapping them, and by not unmapping
+those who are located in the TSO header pool.
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -1167,6 +1167,11 @@ struct mvpp2_bm_pool {
+ u32 port_map;
+ };
+
++#define IS_TSO_HEADER(txq_pcpu, addr) \
++ ((addr) >= (txq_pcpu)->tso_headers_dma && \
++ (addr) < (txq_pcpu)->tso_headers_dma + \
++ (txq_pcpu)->size * TSO_HEADER_SIZE)
++
+ /* Queue modes */
+ #define MVPP2_QDIST_SINGLE_MODE 0
+ #define MVPP2_QDIST_MULTI_MODE 1
+@@ -5321,8 +5326,9 @@ static void mvpp2_txq_bufs_free(struct m
+ struct mvpp2_txq_pcpu_buf *tx_buf =
+ txq_pcpu->buffs + txq_pcpu->txq_get_index;
+
+- dma_unmap_single(port->dev->dev.parent, tx_buf->dma,
+- tx_buf->size, DMA_TO_DEVICE);
++ if (!IS_TSO_HEADER(txq_pcpu, tx_buf->dma))
++ dma_unmap_single(port->dev->dev.parent, tx_buf->dma,
++ tx_buf->size, DMA_TO_DEVICE);
+ if (tx_buf->skb)
+ dev_kfree_skb_any(tx_buf->skb);
+
+@@ -6212,12 +6218,15 @@ static inline void
+ tx_desc_unmap_put(struct mvpp2_port *port, struct mvpp2_tx_queue *txq,
+ struct mvpp2_tx_desc *desc)
+ {
++ struct mvpp2_txq_pcpu *txq_pcpu = this_cpu_ptr(txq->pcpu);
++
+ dma_addr_t buf_dma_addr =
+ mvpp2_txdesc_dma_addr_get(port, desc);
+ size_t buf_sz =
+ mvpp2_txdesc_size_get(port, desc);
+- dma_unmap_single(port->dev->dev.parent, buf_dma_addr,
+- buf_sz, DMA_TO_DEVICE);
++ if (!IS_TSO_HEADER(txq_pcpu, buf_dma_addr))
++ dma_unmap_single(port->dev->dev.parent, buf_dma_addr,
++ buf_sz, DMA_TO_DEVICE);
+ mvpp2_txq_desc_put(txq);
+ }
+
diff --git a/patches.drivers/net-mvpp2-dynamic-reconfiguration-of-the-comphy-GoP-.patch b/patches.drivers/net-mvpp2-dynamic-reconfiguration-of-the-comphy-GoP-.patch
new file mode 100644
index 0000000000..aee07bb9c7
--- /dev/null
+++ b/patches.drivers/net-mvpp2-dynamic-reconfiguration-of-the-comphy-GoP-.patch
@@ -0,0 +1,60 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Wed, 30 Aug 2017 10:29:19 +0200
+Subject: net: mvpp2: dynamic reconfiguration of the comphy/GoP/MAC
+Patch-mainline: v4.14-rc1
+Git-commit: 89273bc060d8c7a70999736fe15b2fb3326d0da8
+References: bsc#1098633
+
+This patch adds logic to reconfigure the comphy/GoP/MAC when the link
+state is updated at runtime. This is very useful on boards where many
+link speed are supported: depending on what is negotiated the PPv2
+driver will automatically reconfigures the link between the PHY and the
+MAC.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -5771,9 +5771,28 @@ static void mvpp2_link_event(struct net_
+ {
+ struct mvpp2_port *port = netdev_priv(dev);
+ struct phy_device *phydev = dev->phydev;
++ bool link_reconfigured = false;
+ u32 val;
+
+ if (phydev->link) {
++ if (port->phy_interface != phydev->interface && port->comphy) {
++ /* disable current port for reconfiguration */
++ mvpp2_interrupts_disable(port);
++ netif_carrier_off(port->dev);
++ mvpp2_port_disable(port);
++ phy_power_off(port->comphy);
++
++ /* comphy reconfiguration */
++ port->phy_interface = phydev->interface;
++ mvpp22_comphy_init(port);
++
++ /* gop/mac reconfiguration */
++ mvpp22_gop_init(port);
++ mvpp2_port_mii_set(port);
++
++ link_reconfigured = true;
++ }
++
+ if ((port->speed != phydev->speed) ||
+ (port->duplex != phydev->duplex)) {
+ mvpp2_gmac_set_autoneg(port, phydev);
+@@ -5783,7 +5802,7 @@ static void mvpp2_link_event(struct net_
+ }
+ }
+
+- if (phydev->link != port->link) {
++ if (phydev->link != port->link || link_reconfigured) {
+ port->link = phydev->link;
+
+ if (phydev->link) {
diff --git a/patches.drivers/net-mvpp2-enable-ACPI-support-in-the-driver.patch b/patches.drivers/net-mvpp2-enable-ACPI-support-in-the-driver.patch
new file mode 100644
index 0000000000..731fe8d794
--- /dev/null
+++ b/patches.drivers/net-mvpp2-enable-ACPI-support-in-the-driver.patch
@@ -0,0 +1,301 @@
+From: Marcin Wojtas <mw@semihalf.com>
+Date: Thu, 18 Jan 2018 13:31:44 +0100
+Subject: net: mvpp2: enable ACPI support in the driver
+Patch-mainline: v4.16-rc1
+Git-commit: a75edc7c2eab329d20a4ffbbfb15f2aa4a95454f
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 133 ++++++++++++++++++++++++-----------
+ 1 file changed, 94 insertions(+), 39 deletions(-)
+
+--- 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_ini
+ 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 platf
+ 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 platf
+ 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 platf
+ 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 platf
+ 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 platf
+
+ 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 platf
+ 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_de
+
+ 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_d
+ 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_d
+ 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_d
+ 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_d
+ 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_
+ 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_m
+ };
+ 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),
+ },
+ };
+
diff --git a/patches.drivers/net-mvpp2-enable-UDP-TCP-checksum-over-IPv6.patch b/patches.drivers/net-mvpp2-enable-UDP-TCP-checksum-over-IPv6.patch
new file mode 100644
index 0000000000..d84862c454
--- /dev/null
+++ b/patches.drivers/net-mvpp2-enable-UDP-TCP-checksum-over-IPv6.patch
@@ -0,0 +1,31 @@
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Mon, 5 Mar 2018 15:16:53 +0100
+Subject: net: mvpp2: enable UDP/TCP checksum over IPv6
+Patch-mainline: v4.17-rc1
+Git-commit: 381c56712db43af1112a21cce6bdc37281890cdb
+References: bsc#1098633
+
+This patch adds the NETIF_F_IPV6_CSUM to the driver's features to enable
+UDP/TCP checksum over IPv6. No extra configuration of the engine is
+needed on top of the IPv4 counterpart, which already is in the features
+list (NETIF_F_IP_CSUM).
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -8321,7 +8321,8 @@ static int mvpp2_port_probe(struct platf
+ }
+ }
+
+- features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
++ features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
++ NETIF_F_TSO;
+ dev->features = features | NETIF_F_RXCSUM;
+ dev->hw_features |= features | NETIF_F_RXCSUM | NETIF_F_GRO |
+ NETIF_F_HW_VLAN_CTAG_FILTER;
diff --git a/patches.drivers/net-mvpp2-enable-basic-10G-support.patch b/patches.drivers/net-mvpp2-enable-basic-10G-support.patch
new file mode 100644
index 0000000000..cba4a072d7
--- /dev/null
+++ b/patches.drivers/net-mvpp2-enable-basic-10G-support.patch
@@ -0,0 +1,101 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Mon, 12 Jun 2017 16:01:39 +0200
+Subject: net: mvpp2: enable basic 10G support
+Patch-mainline: v4.13-rc1
+Git-commit: 725757aee05e51914b72f25ba2a89c43c3779574
+References: bsc#1098633
+
+On GOP port 0 two MAC modes are available: GMAC and XLG. The XLG MAC is
+used for 10G connectivity. This patch adds a basic 10G support by
+allowing to use the XLG MAC on port 0 and by reworking the
+port_enable/disable functions so that the XLG MAC is configured when
+using 10G.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 49 +++++++++++++++++++++++++++++------
+ 1 file changed, 41 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -345,9 +345,15 @@
+ /* Per-port XGMAC registers. PPv2.2 only, only for GOP port 0,
+ * relative to port->base.
+ */
++#define MVPP22_XLG_CTRL0_REG 0x100
++#define MVPP22_XLG_CTRL0_PORT_EN BIT(0)
++#define MVPP22_XLG_CTRL0_MAC_RESET_DIS BIT(1)
++#define MVPP22_XLG_CTRL0_MIB_CNT_DIS BIT(14)
++
+ #define MVPP22_XLG_CTRL3_REG 0x11c
+ #define MVPP22_XLG_CTRL3_MACMODESELECT_MASK (7 << 13)
+ #define MVPP22_XLG_CTRL3_MACMODESELECT_GMAC (0 << 13)
++#define MVPP22_XLG_CTRL3_MACMODESELECT_10G (1 << 13)
+
+ /* SMI registers. PPv2.2 only, relative to priv->iface_base. */
+ #define MVPP22_SMI_MISC_CFG_REG 0x1204
+@@ -4186,7 +4192,13 @@ static void mvpp22_port_mii_set(struct m
+ if (port->gop_id == 0) {
+ val = readl(port->base + MVPP22_XLG_CTRL3_REG);
+ val &= ~MVPP22_XLG_CTRL3_MACMODESELECT_MASK;
+- val |= MVPP22_XLG_CTRL3_MACMODESELECT_GMAC;
++
++ if (port->phy_interface == PHY_INTERFACE_MODE_XAUI ||
++ port->phy_interface == PHY_INTERFACE_MODE_10GKR)
++ val |= MVPP22_XLG_CTRL3_MACMODESELECT_10G;
++ else
++ val |= MVPP22_XLG_CTRL3_MACMODESELECT_GMAC;
++
+ writel(val, port->base + MVPP22_XLG_CTRL3_REG);
+ }
+
+@@ -4236,19 +4248,40 @@ static void mvpp2_port_enable(struct mvp
+ {
+ u32 val;
+
+- val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
+- val |= MVPP2_GMAC_PORT_EN_MASK;
+- val |= MVPP2_GMAC_MIB_CNTR_EN_MASK;
+- writel(val, port->base + MVPP2_GMAC_CTRL_0_REG);
++ /* Only GOP port 0 has an XLG MAC */
++ if (port->gop_id == 0 &&
++ (port->phy_interface == PHY_INTERFACE_MODE_XAUI ||
++ port->phy_interface == PHY_INTERFACE_MODE_10GKR)) {
++ val = readl(port->base + MVPP22_XLG_CTRL0_REG);
++ val |= MVPP22_XLG_CTRL0_PORT_EN |
++ MVPP22_XLG_CTRL0_MAC_RESET_DIS;
++ val &= ~MVPP22_XLG_CTRL0_MIB_CNT_DIS;
++ writel(val, port->base + MVPP22_XLG_CTRL0_REG);
++ } else {
++ val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
++ val |= MVPP2_GMAC_PORT_EN_MASK;
++ val |= MVPP2_GMAC_MIB_CNTR_EN_MASK;
++ writel(val, port->base + MVPP2_GMAC_CTRL_0_REG);
++ }
+ }
+
+ static void mvpp2_port_disable(struct mvpp2_port *port)
+ {
+ u32 val;
+
+- val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
+- val &= ~(MVPP2_GMAC_PORT_EN_MASK);
+- writel(val, port->base + MVPP2_GMAC_CTRL_0_REG);
++ /* Only GOP port 0 has an XLG MAC */
++ if (port->gop_id == 0 &&
++ (port->phy_interface == PHY_INTERFACE_MODE_XAUI ||
++ port->phy_interface == PHY_INTERFACE_MODE_10GKR)) {
++ val = readl(port->base + MVPP22_XLG_CTRL0_REG);
++ val &= ~(MVPP22_XLG_CTRL0_PORT_EN |
++ MVPP22_XLG_CTRL0_MAC_RESET_DIS);
++ writel(val, port->base + MVPP22_XLG_CTRL0_REG);
++ } else {
++ val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
++ val &= ~(MVPP2_GMAC_PORT_EN_MASK);
++ writel(val, port->base + MVPP2_GMAC_CTRL_0_REG);
++ }
+ }
+
+ /* Set IEEE 802.3x Flow Control Xon Packet Transmission Mode */
diff --git a/patches.drivers/net-mvpp2-fallback-using-h-w-and-random-mac-if-the-d.patch b/patches.drivers/net-mvpp2-fallback-using-h-w-and-random-mac-if-the-d.patch
new file mode 100644
index 0000000000..27231757a0
--- /dev/null
+++ b/patches.drivers/net-mvpp2-fallback-using-h-w-and-random-mac-if-the-d.patch
@@ -0,0 +1,54 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Sat, 2 Sep 2017 11:06:49 +0200
+Subject: net: mvpp2: fallback using h/w and random mac if the dt one isn't
+ valid
+Patch-mainline: v4.14-rc1
+Git-commit: 688cbaf202df8b4a69f5ccd39e0027f179852d44
+References: bsc#1098633
+
+When using a mac address described in the device tree, a check is made
+to see if it is valid. When it's not, no fallback is defined. This
+patches tries to get the mac address from h/w (or use a random one if
+the h/w one isn't valid) when the dt mac address isn't valid.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 23 ++++++++++++-----------
+ 1 file changed, 12 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -7477,19 +7477,20 @@ static void mvpp2_port_copy_mac_addr(str
+ if (dt_mac_addr && is_valid_ether_addr(dt_mac_addr)) {
+ *mac_from = "device tree";
+ ether_addr_copy(dev->dev_addr, dt_mac_addr);
+- } else {
+- if (priv->hw_version == MVPP21) {
+- mvpp21_get_mac_address(port, hw_mac_addr);
+- if (is_valid_ether_addr(hw_mac_addr)) {
+- *mac_from = "hardware";
+- ether_addr_copy(dev->dev_addr, hw_mac_addr);
+- return;
+- }
+- }
++ return;
++ }
+
+- *mac_from = "random";
+- eth_hw_addr_random(dev);
++ if (priv->hw_version == MVPP21) {
++ mvpp21_get_mac_address(port, hw_mac_addr);
++ if (is_valid_ether_addr(hw_mac_addr)) {
++ *mac_from = "hardware";
++ ether_addr_copy(dev->dev_addr, hw_mac_addr);
++ return;
++ }
+ }
++
++ *mac_from = "random";
++ eth_hw_addr_random(dev);
+ }
+
+ /* Ports initialization */
diff --git a/patches.drivers/net-mvpp2-fix-GOP-statistics-loop-start-and-stop-con.patch b/patches.drivers/net-mvpp2-fix-GOP-statistics-loop-start-and-stop-con.patch
new file mode 100644
index 0000000000..40d16267fd
--- /dev/null
+++ b/patches.drivers/net-mvpp2-fix-GOP-statistics-loop-start-and-stop-con.patch
@@ -0,0 +1,175 @@
+From: Miquel Raynal <miquel.raynal@free-electrons.com>
+Date: Wed, 8 Nov 2017 08:59:40 +0100
+Subject: net: mvpp2: fix GOP statistics loop start and stop conditions
+Patch-mainline: v4.15-rc1
+Git-commit: e5c500eb298a9f5ef9b80d16fcea9662c89467b7
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 62 ++++++++++++++++-------------------
+ 1 file changed, 30 insertions(+), 32 deletions(-)
+
+--- 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(st
+ 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(stru
+ {
+ 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
+ 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
+ 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 platf
+ 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_d
+ * 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_d
+ 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_
+ 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++;
+ }
+
diff --git a/patches.drivers/net-mvpp2-fix-MVPP21_ISR_RXQ_GROUP_REG-definition.patch b/patches.drivers/net-mvpp2-fix-MVPP21_ISR_RXQ_GROUP_REG-definition.patch
new file mode 100644
index 0000000000..0af4cfc54b
--- /dev/null
+++ b/patches.drivers/net-mvpp2-fix-MVPP21_ISR_RXQ_GROUP_REG-definition.patch
@@ -0,0 +1,29 @@
+From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Date: Thu, 3 Aug 2017 10:41:55 +0200
+Subject: net: mvpp2: fix MVPP21_ISR_RXQ_GROUP_REG definition
+Patch-mainline: v4.14-rc1
+Git-commit: eb1e93a10ef5bedfc15d1404dc6a2c46d843cde9
+References: bsc#1098633
+
+The MVPP21_ISR_RXQ_GROUP_REG register is not indexed by rxq, but by
+port, so we fix the parameter name accordingly. There are no
+functional changes.
+
+Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -185,7 +185,7 @@
+ /* Interrupt Cause and Mask registers */
+ #define MVPP2_ISR_RX_THRESHOLD_REG(rxq) (0x5200 + 4 * (rxq))
+ #define MVPP2_MAX_ISR_RX_THRESHOLD 0xfffff0
+-#define MVPP21_ISR_RXQ_GROUP_REG(rxq) (0x5400 + 4 * (rxq))
++#define MVPP21_ISR_RXQ_GROUP_REG(port) (0x5400 + 4 * (port))
+
+ #define MVPP22_ISR_RXQ_GROUP_INDEX_REG 0x5400
+ #define MVPP22_ISR_RXQ_GROUP_INDEX_SUBGROUP_MASK 0xf
diff --git a/patches.drivers/net-mvpp2-fix-TSO-headers-allocation-and-management.patch b/patches.drivers/net-mvpp2-fix-TSO-headers-allocation-and-management.patch
new file mode 100644
index 0000000000..1bcc937257
--- /dev/null
+++ b/patches.drivers/net-mvpp2-fix-TSO-headers-allocation-and-management.patch
@@ -0,0 +1,49 @@
+From: Yan Markman <ymarkman@marvell.com>
+Date: Mon, 23 Oct 2017 15:24:29 +0200
+Subject: net: mvpp2: fix TSO headers allocation and management
+Patch-mainline: v4.14-rc7
+Git-commit: 822eaf7cfb7c4783375bceadbc7651137346ac00
+References: bsc#1098633
+
+TSO headers are managed with txq index and therefore should be aligned
+with the txq size, not with the aggregated txq size.
+
+Fixes: 186cd4d4e414 ("net: mvpp2: software tso support")
+Reported-by: Marc Zyngier <marc.zyngier@arm.com>
+Signed-off-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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -5609,7 +5609,7 @@ static int mvpp2_txq_init(struct mvpp2_p
+
+ txq_pcpu->tso_headers =
+ dma_alloc_coherent(port->dev->dev.parent,
+- MVPP2_AGGR_TXQ_SIZE * TSO_HEADER_SIZE,
++ txq_pcpu->size * TSO_HEADER_SIZE,
+ &txq_pcpu->tso_headers_dma,
+ GFP_KERNEL);
+ if (!txq_pcpu->tso_headers)
+@@ -5623,7 +5623,7 @@ cleanup:
+ kfree(txq_pcpu->buffs);
+
+ dma_free_coherent(port->dev->dev.parent,
+- MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE,
++ txq_pcpu->size * TSO_HEADER_SIZE,
+ txq_pcpu->tso_headers,
+ txq_pcpu->tso_headers_dma);
+ }
+@@ -5647,7 +5647,7 @@ static void mvpp2_txq_deinit(struct mvpp
+ kfree(txq_pcpu->buffs);
+
+ dma_free_coherent(port->dev->dev.parent,
+- MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE,
++ txq_pcpu->size * TSO_HEADER_SIZE,
+ txq_pcpu->tso_headers,
+ txq_pcpu->tso_headers_dma);
+ }
diff --git a/patches.drivers/net-mvpp2-fix-invalid-parameters-order-when-calling-.patch b/patches.drivers/net-mvpp2-fix-invalid-parameters-order-when-calling-.patch
new file mode 100644
index 0000000000..10576caa7c
--- /dev/null
+++ b/patches.drivers/net-mvpp2-fix-invalid-parameters-order-when-calling-.patch
@@ -0,0 +1,32 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Tue, 24 Oct 2017 11:41:27 +0200
+Subject: net: mvpp2: fix invalid parameters order when calling the tcam init
+Patch-mainline: v4.14-rc7
+Git-commit: 20746d717ea390ac6ac3aa531f27ac156bf2e747
+References: bsc#1098633
+
+When calling mvpp2_prs_mac_multi_set() from mvpp2_prs_mac_init(), two
+parameters (the port index and the table index) are inverted. Fixes
+this.
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -2614,8 +2614,8 @@ static void mvpp2_prs_mac_init(struct mv
+ /* place holders only - no ports */
+ mvpp2_prs_mac_drop_all_set(priv, 0, false);
+ mvpp2_prs_mac_promisc_set(priv, 0, false);
+- mvpp2_prs_mac_multi_set(priv, MVPP2_PE_MAC_MC_ALL, 0, false);
+- mvpp2_prs_mac_multi_set(priv, MVPP2_PE_MAC_MC_IP6, 0, false);
++ mvpp2_prs_mac_multi_set(priv, 0, MVPP2_PE_MAC_MC_ALL, false);
++ mvpp2_prs_mac_multi_set(priv, 0, MVPP2_PE_MAC_MC_IP6, false);
+ }
+
+ /* Set default entries for various types of dsa packets */
diff --git a/patches.drivers/net-mvpp2-fix-parsing-fragmentation-detection.patch b/patches.drivers/net-mvpp2-fix-parsing-fragmentation-detection.patch
new file mode 100644
index 0000000000..c052c893b3
--- /dev/null
+++ b/patches.drivers/net-mvpp2-fix-parsing-fragmentation-detection.patch
@@ -0,0 +1,79 @@
+From: Stefan Chulski <stefanc@marvell.com>
+Date: Mon, 25 Sep 2017 14:59:46 +0200
+Subject: net: mvpp2: fix parsing fragmentation detection
+Patch-mainline: v4.14-rc4
+Git-commit: aff3da39211105a42b2108b8af79bf8e16f670fd
+References: bsc#1098633
+
+Parsing fragmentation detection failed due to wrong configured
+parser TCAM entry's. Some traffic was marked as fragmented in RX
+descriptor, even it wasn't IP fragmented. The hardware also failed to
+calculate checksums which lead to use software checksum and caused
+performance degradation.
+
+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: Stefan Chulski <stefanc@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 20 ++++++++++++++------
+ 1 file changed, 14 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -676,6 +676,7 @@ enum mvpp2_tag_type {
+ #define MVPP2_PRS_RI_L3_MCAST BIT(15)
+ #define MVPP2_PRS_RI_L3_BCAST (BIT(15) | BIT(16))
+ #define MVPP2_PRS_RI_IP_FRAG_MASK 0x20000
++#define MVPP2_PRS_RI_IP_FRAG_TRUE BIT(17)
+ #define MVPP2_PRS_RI_UDF3_MASK 0x300000
+ #define MVPP2_PRS_RI_UDF3_RX_SPECIAL BIT(21)
+ #define MVPP2_PRS_RI_L4_PROTO_MASK 0x1c00000
+@@ -2315,7 +2316,7 @@ static int mvpp2_prs_ip4_proto(struct mv
+ (proto != IPPROTO_IGMP))
+ return -EINVAL;
+
+- /* Fragmented packet */
++ /* Not fragmented packet */
+ tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
+ MVPP2_PE_LAST_FREE_TID);
+ if (tid < 0)
+@@ -2334,8 +2335,12 @@ static int mvpp2_prs_ip4_proto(struct mv
+ MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
+ mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
+ MVPP2_PRS_IPV4_DIP_AI_BIT);
+- mvpp2_prs_sram_ri_update(&pe, ri | MVPP2_PRS_RI_IP_FRAG_MASK,
+- ri_mask | MVPP2_PRS_RI_IP_FRAG_MASK);
++ mvpp2_prs_sram_ri_update(&pe, ri, ri_mask | MVPP2_PRS_RI_IP_FRAG_MASK);
++
++ mvpp2_prs_tcam_data_byte_set(&pe, 2, 0x00,
++ MVPP2_PRS_TCAM_PROTO_MASK_L);
++ mvpp2_prs_tcam_data_byte_set(&pe, 3, 0x00,
++ MVPP2_PRS_TCAM_PROTO_MASK);
+
+ mvpp2_prs_tcam_data_byte_set(&pe, 5, proto, MVPP2_PRS_TCAM_PROTO_MASK);
+ mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
+@@ -2346,7 +2351,7 @@ static int mvpp2_prs_ip4_proto(struct mv
+ mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
+ mvpp2_prs_hw_write(priv, &pe);
+
+- /* Not fragmented packet */
++ /* Fragmented packet */
+ tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
+ MVPP2_PE_LAST_FREE_TID);
+ if (tid < 0)
+@@ -2358,8 +2363,11 @@ static int mvpp2_prs_ip4_proto(struct mv
+ pe.sram.word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
+ mvpp2_prs_sram_ri_update(&pe, ri, ri_mask);
+
+- mvpp2_prs_tcam_data_byte_set(&pe, 2, 0x00, MVPP2_PRS_TCAM_PROTO_MASK_L);
+- mvpp2_prs_tcam_data_byte_set(&pe, 3, 0x00, MVPP2_PRS_TCAM_PROTO_MASK);
++ mvpp2_prs_sram_ri_update(&pe, ri | MVPP2_PRS_RI_IP_FRAG_TRUE,
++ ri_mask | MVPP2_PRS_RI_IP_FRAG_MASK);
++
++ mvpp2_prs_tcam_data_byte_set(&pe, 2, 0x00, 0x0);
++ mvpp2_prs_tcam_data_byte_set(&pe, 3, 0x00, 0x0);
+
+ /* Update shadow table and hw entry */
+ mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
diff --git a/patches.drivers/net-mvpp2-fix-port-list-indexing.patch b/patches.drivers/net-mvpp2-fix-port-list-indexing.patch
new file mode 100644
index 0000000000..65f36903af
--- /dev/null
+++ b/patches.drivers/net-mvpp2-fix-port-list-indexing.patch
@@ -0,0 +1,60 @@
+From: Yan Markman <ymarkman@marvell.com>
+Date: Mon, 25 Sep 2017 14:59:47 +0200
+Subject: net: mvpp2: fix port list indexing
+Patch-mainline: v4.14-rc4
+Git-commit: 6bf69a1d6334bed776875c5ca852594ab4e5b209
+References: bsc#1098633
+
+The private port_list array has a list of pointers to mvpp2_port
+instances. This list is allocated given the number of ports enabled in
+the device tree, but the pointers are set using the port-id property. If
+on a single port is enabled, the port_list array will be of size 1, but
+when registering the port, if its id is not 0 the driver will crash.
+Other crashes were encountered in various situations.
+
+This fixes the issue by using an index not equal to the value of the
+port-id property.
+
+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: Yan Markman <ymarkman@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -7504,7 +7504,7 @@ static void mvpp2_port_copy_mac_addr(str
+ /* Ports initialization */
+ static int mvpp2_port_probe(struct platform_device *pdev,
+ struct device_node *port_node,
+- struct mvpp2 *priv)
++ struct mvpp2 *priv, int index)
+ {
+ struct device_node *phy_node;
+ struct phy *comphy;
+@@ -7678,7 +7678,7 @@ static int mvpp2_port_probe(struct platf
+ }
+ netdev_info(dev, "Using %s mac address %pM\n", mac_from, dev->dev_addr);
+
+- priv->port_list[id] = port;
++ priv->port_list[index] = port;
+ return 0;
+
+ err_free_port_pcpu:
+@@ -8013,10 +8013,12 @@ static int mvpp2_probe(struct platform_d
+ }
+
+ /* Initialize ports */
++ i = 0;
+ for_each_available_child_of_node(dn, port_node) {
+- err = mvpp2_port_probe(pdev, port_node, priv);
++ err = mvpp2_port_probe(pdev, port_node, priv, i);
+ if (err < 0)
+ goto err_mg_clk;
++ i++;
+ }
+
+ platform_set_drvdata(pdev, priv);
diff --git a/patches.drivers/net-mvpp2-fix-the-RSS-table-entry-offset.patch b/patches.drivers/net-mvpp2-fix-the-RSS-table-entry-offset.patch
new file mode 100644
index 0000000000..b855e92650
--- /dev/null
+++ b/patches.drivers/net-mvpp2-fix-the-RSS-table-entry-offset.patch
@@ -0,0 +1,30 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Fri, 8 Dec 2017 10:24:20 +0100
+Subject: net: mvpp2: fix the RSS table entry offset
+Patch-mainline: v4.15-rc3
+Git-commit: 8a7b741e76cd31b6000636f0391e67ba6793ad1c
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- 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
diff --git a/patches.drivers/net-mvpp2-fix-the-packet-size-configuration-for-10G.patch b/patches.drivers/net-mvpp2-fix-the-packet-size-configuration-for-10G.patch
new file mode 100644
index 0000000000..2cb7832778
--- /dev/null
+++ b/patches.drivers/net-mvpp2-fix-the-packet-size-configuration-for-10G.patch
@@ -0,0 +1,40 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Fri, 25 Aug 2017 15:24:46 +0200
+Subject: net: mvpp2: fix the packet size configuration for 10G
+Patch-mainline: v4.14-rc1
+Git-commit: ec15ecdee5eb9e33a565e1e8eaef39fd4de565cb
+References: bsc#1098633
+
+The MVPP22_XLG_CTRL1_FRAMESIZELIMIT define is used as an offset, but is
+defined as BIT(0). Updated its name to contains "OFFS" as in offset and
+fix its value using the offset value, 0.
+
+Reported-by: Stefan Chulski <stefanc@marvell.com>
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Fixes: 76eb1b1de5b6 ("net: mvpp2: set maximum packet size for 10G ports")
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -367,7 +367,7 @@
+ #define MVPP22_XLG_CTRL0_RX_FLOW_CTRL_EN BIT(7)
+ #define MVPP22_XLG_CTRL0_MIB_CNT_DIS BIT(14)
+ #define MVPP22_XLG_CTRL1_REG 0x104
+-#define MVPP22_XLG_CTRL1_FRAMESIZELIMIT BIT(0)
++#define MVPP22_XLG_CTRL1_FRAMESIZELIMIT_OFFS 0
+ #define MVPP22_XLG_CTRL1_FRAMESIZELIMIT_MASK 0x1fff
+ #define MVPP22_XLG_CTRL3_REG 0x11c
+ #define MVPP22_XLG_CTRL3_MACMODESELECT_MASK (7 << 13)
+@@ -4669,7 +4669,7 @@ static inline void mvpp2_xlg_max_rx_size
+ val = readl(port->base + MVPP22_XLG_CTRL1_REG);
+ val &= ~MVPP22_XLG_CTRL1_FRAMESIZELIMIT_MASK;
+ val |= ((port->pkt_size - MVPP2_MH_SIZE) / 2) <<
+- MVPP22_XLG_CTRL1_FRAMESIZELIMIT;
++ MVPP22_XLG_CTRL1_FRAMESIZELIMIT_OFFS;
+ writel(val, port->base + MVPP22_XLG_CTRL1_REG);
+ }
+
diff --git a/patches.drivers/net-mvpp2-fix-the-synchronization-module-bypass-macr.patch b/patches.drivers/net-mvpp2-fix-the-synchronization-module-bypass-macr.patch
new file mode 100644
index 0000000000..6af5dcbeec
--- /dev/null
+++ b/patches.drivers/net-mvpp2-fix-the-synchronization-module-bypass-macr.patch
@@ -0,0 +1,39 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Tue, 22 Aug 2017 19:08:22 +0200
+Subject: net: mvpp2: fix the synchronization module bypass macro name
+Patch-mainline: v4.14-rc1
+Git-commit: 1068ec79d9cb5481ccfa6ffacdcf174636227b5d
+References: bsc#1098633
+
+The macro defining the bit to toggle to bypass or not the
+synchronization module is wrongly named. Writing 1 will disable bypass.
+This patch s/MVPP22_CTRL4_SYNC_BYPASS/MVPP22_CTRL4_SYNC_BYPASS_DIS/.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Tested-by: Marcin Wojtas <mw@semihalf.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -346,7 +346,7 @@
+ #define MVPP22_GMAC_CTRL_4_REG 0x90
+ #define MVPP22_CTRL4_EXT_PIN_GMII_SEL BIT(0)
+ #define MVPP22_CTRL4_DP_CLK_SEL BIT(5)
+-#define MVPP22_CTRL4_SYNC_BYPASS BIT(6)
++#define MVPP22_CTRL4_SYNC_BYPASS_DIS BIT(6)
+ #define MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE BIT(7)
+
+ /* Per-port XGMAC registers. PPv2.2 only, only for GOP port 0,
+@@ -4269,7 +4269,7 @@ static void mvpp22_port_mii_set(struct m
+ else
+ val &= ~MVPP22_CTRL4_EXT_PIN_GMII_SEL;
+ val &= ~MVPP22_CTRL4_DP_CLK_SEL;
+- val |= MVPP22_CTRL4_SYNC_BYPASS;
++ val |= MVPP22_CTRL4_SYNC_BYPASS_DIS;
+ val |= MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE;
+ writel(val, port->base + MVPP22_GMAC_CTRL_4_REG);
+ }
diff --git a/patches.drivers/net-mvpp2-fix-the-txq_init-error-path.patch b/patches.drivers/net-mvpp2-fix-the-txq_init-error-path.patch
new file mode 100644
index 0000000000..c194544c0b
--- /dev/null
+++ b/patches.drivers/net-mvpp2-fix-the-txq_init-error-path.patch
@@ -0,0 +1,66 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Tue, 28 Nov 2017 14:19:48 +0100
+Subject: net: mvpp2: fix the txq_init error path
+Patch-mainline: v4.15-rc2
+Git-commit: ba2d8d887d962c2f790e6dc01b2fd25b4608720b
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 20 ++------------------
+ 1 file changed, 2 insertions(+), 18 deletions(-)
+
+--- 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_p
+ 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_p
+ &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 */
diff --git a/patches.drivers/net-mvpp2-fix-typo-in-the-tcam-setup.patch b/patches.drivers/net-mvpp2-fix-typo-in-the-tcam-setup.patch
new file mode 100644
index 0000000000..7a2509bec5
--- /dev/null
+++ b/patches.drivers/net-mvpp2-fix-typo-in-the-tcam-setup.patch
@@ -0,0 +1,29 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Tue, 24 Oct 2017 11:41:26 +0200
+Subject: net: mvpp2: fix typo in the tcam setup
+Patch-mainline: v4.14-rc7
+Git-commit: ef4816f0ee576d4a27ed35cd1090904121391cb9
+References: bsc#1098633
+
+This patch fixes a typo in the mvpp2_prs_tcam_data_cmp() function, as
+the shift value is inverted with the data.
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -1539,7 +1539,7 @@ static bool mvpp2_prs_tcam_data_cmp(stru
+ int off = MVPP2_PRS_TCAM_DATA_BYTE(offs);
+ u16 tcam_data;
+
+- tcam_data = (8 << pe->tcam.byte[off + 1]) | pe->tcam.byte[off];
++ tcam_data = (pe->tcam.byte[off + 1] << 8) | pe->tcam.byte[off];
+ if (tcam_data != data)
+ return false;
+ return true;
diff --git a/patches.drivers/net-mvpp2-fix-use-of-the-random-mac-address-for-PPv2.patch b/patches.drivers/net-mvpp2-fix-use-of-the-random-mac-address-for-PPv2.patch
new file mode 100644
index 0000000000..735cc94da0
--- /dev/null
+++ b/patches.drivers/net-mvpp2-fix-use-of-the-random-mac-address-for-PPv2.patch
@@ -0,0 +1,49 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Sat, 2 Sep 2017 11:06:48 +0200
+Subject: net: mvpp2: fix use of the random mac address for PPv2.2
+Patch-mainline: v4.14-rc1
+Git-commit: d2a6e48e5254f653decc1612f3cbee3e5c8592c7
+References: bsc#1098633
+
+The MAC retrieval logic is using a variable to store an h/w stored mac
+address and checks this mac against invalid ones before using it. But
+the mac address is only read from h/w when using PPv2.1. So when using
+PPv2.2 it defaults to its init state.
+
+This patches fixes the logic to only check if the h/w mac is valid when
+actually retrieving a mac from h/w.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -7478,15 +7478,17 @@ static void mvpp2_port_copy_mac_addr(str
+ *mac_from = "device tree";
+ ether_addr_copy(dev->dev_addr, dt_mac_addr);
+ } else {
+- if (priv->hw_version == MVPP21)
++ if (priv->hw_version == MVPP21) {
+ mvpp21_get_mac_address(port, hw_mac_addr);
+- if (is_valid_ether_addr(hw_mac_addr)) {
+- *mac_from = "hardware";
+- ether_addr_copy(dev->dev_addr, hw_mac_addr);
+- } else {
+- *mac_from = "random";
+- eth_hw_addr_random(dev);
++ if (is_valid_ether_addr(hw_mac_addr)) {
++ *mac_from = "hardware";
++ ether_addr_copy(dev->dev_addr, hw_mac_addr);
++ return;
++ }
+ }
++
++ *mac_from = "random";
++ eth_hw_addr_random(dev);
+ }
+ }
+
diff --git a/patches.drivers/net-mvpp2-improve-the-link-management-function.patch b/patches.drivers/net-mvpp2-improve-the-link-management-function.patch
new file mode 100644
index 0000000000..60c6e1f1be
--- /dev/null
+++ b/patches.drivers/net-mvpp2-improve-the-link-management-function.patch
@@ -0,0 +1,49 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Wed, 30 Aug 2017 10:29:17 +0200
+Subject: net: mvpp2: improve the link management function
+Patch-mainline: v4.14-rc1
+Git-commit: f55744adeee8598a05f0714b8fe9d131865ef060
+References: bsc#1098633
+
+When the link status changes, the phylib calls the link_event function
+in the mvpp2 driver. Before this patch only the egress/ingress transmit
+was enabled/disabled. This patch adds more functionality to the link
+status management code by enabling/disabling the port per-cpu
+interrupts, and the port itself. The queues are now stopped as well, and
+the netif carrier helpers are called.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -5777,14 +5777,25 @@ static void mvpp2_link_event(struct net_
+ val |= (MVPP2_GMAC_FORCE_LINK_PASS |
+ MVPP2_GMAC_FORCE_LINK_DOWN);
+ writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
++
++ mvpp2_interrupts_enable(port);
++ mvpp2_port_enable(port);
++
+ mvpp2_egress_enable(port);
+ mvpp2_ingress_enable(port);
++ netif_carrier_on(dev);
++ netif_tx_wake_all_queues(dev);
+ } else {
+ port->duplex = -1;
+ port->speed = 0;
+
++ netif_tx_stop_all_queues(dev);
++ netif_carrier_off(dev);
+ mvpp2_ingress_disable(port);
+ mvpp2_egress_disable(port);
++
++ mvpp2_port_disable(port);
++ mvpp2_interrupts_disable(port);
+ }
+
+ phy_print_status(phydev);
diff --git a/patches.drivers/net-mvpp2-initialize-the-GMAC-when-using-a-port.patch b/patches.drivers/net-mvpp2-initialize-the-GMAC-when-using-a-port.patch
new file mode 100644
index 0000000000..4067308748
--- /dev/null
+++ b/patches.drivers/net-mvpp2-initialize-the-GMAC-when-using-a-port.patch
@@ -0,0 +1,191 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Tue, 22 Aug 2017 19:08:24 +0200
+Subject: net: mvpp2: initialize the GMAC when using a port
+Patch-mainline: v4.14-rc1
+Git-commit: 3919357fb0bbdbc18366cf59cbf0f16c608f81fe
+References: bsc#1098633
+
+This adds a routine to initialize the GMAC at the port level when using
+a port. This wasn't done until this commit, and the mvpp2 driver was
+relying on the bootloader/firmware initialization. This doesn't mean
+everything is configured in the mvpp2 driver now, but it helps reducing
+the gap.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Tested-by: Marcin Wojtas <mw@semihalf.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 123 +++++++++++++++++++++++++++--------
+ 1 file changed, 98 insertions(+), 25 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -315,6 +315,7 @@
+ /* Per-port registers */
+ #define MVPP2_GMAC_CTRL_0_REG 0x0
+ #define MVPP2_GMAC_PORT_EN_MASK BIT(0)
++#define MVPP2_GMAC_PORT_TYPE_MASK BIT(1)
+ #define MVPP2_GMAC_MAX_RX_SIZE_OFFS 2
+ #define MVPP2_GMAC_MAX_RX_SIZE_MASK 0x7ffc
+ #define MVPP2_GMAC_MIB_CNTR_EN_MASK BIT(15)
+@@ -326,16 +327,21 @@
+ #define MVPP2_GMAC_SA_LOW_OFFS 7
+ #define MVPP2_GMAC_CTRL_2_REG 0x8
+ #define MVPP2_GMAC_INBAND_AN_MASK BIT(0)
++#define MVPP2_GMAC_FLOW_CTRL_MASK GENMASK(2, 1)
+ #define MVPP2_GMAC_PCS_ENABLE_MASK BIT(3)
+ #define MVPP2_GMAC_PORT_RGMII_MASK BIT(4)
++#define MVPP2_GMAC_DISABLE_PADDING BIT(5)
+ #define MVPP2_GMAC_PORT_RESET_MASK BIT(6)
+ #define MVPP2_GMAC_AUTONEG_CONFIG 0xc
+ #define MVPP2_GMAC_FORCE_LINK_DOWN BIT(0)
+ #define MVPP2_GMAC_FORCE_LINK_PASS BIT(1)
++#define MVPP2_GMAC_IN_BAND_AUTONEG BIT(2)
++#define MVPP2_GMAC_IN_BAND_AUTONEG_BYPASS BIT(3)
+ #define MVPP2_GMAC_CONFIG_MII_SPEED BIT(5)
+ #define MVPP2_GMAC_CONFIG_GMII_SPEED BIT(6)
+ #define MVPP2_GMAC_AN_SPEED_EN BIT(7)
+ #define MVPP2_GMAC_FC_ADV_EN BIT(9)
++#define MVPP2_GMAC_FLOW_CTRL_AUTONEG BIT(11)
+ #define MVPP2_GMAC_CONFIG_FULL_DUPLEX BIT(12)
+ #define MVPP2_GMAC_AN_DUPLEX_EN BIT(13)
+ #define MVPP2_GMAC_PORT_FIFO_CFG_1_REG 0x1c
+@@ -4245,6 +4251,92 @@ mvpp2_shared_interrupt_mask_unmask(struc
+
+ /* Port configuration routines */
+
++static void mvpp2_port_mii_gmac_configure_mode(struct mvpp2_port *port)
++{
++ u32 val;
++
++ if (port->phy_interface == PHY_INTERFACE_MODE_SGMII) {
++ val = readl(port->base + MVPP22_GMAC_CTRL_4_REG);
++ val |= MVPP22_CTRL4_SYNC_BYPASS_DIS | MVPP22_CTRL4_DP_CLK_SEL |
++ 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 (port->phy_interface == PHY_INTERFACE_MODE_RGMII ||
++ port->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
++ port->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID ||
++ port->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) {
++ val = readl(port->base + MVPP22_GMAC_CTRL_4_REG);
++ val |= MVPP22_CTRL4_EXT_PIN_GMII_SEL |
++ MVPP22_CTRL4_SYNC_BYPASS_DIS |
++ 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 */
++ val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
++ val &= ~MVPP2_GMAC_PORT_TYPE_MASK;
++ writel(val, port->base + MVPP2_GMAC_CTRL_0_REG);
++
++ val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
++ val |= MVPP2_GMAC_IN_BAND_AUTONEG_BYPASS |
++ MVPP2_GMAC_AN_SPEED_EN | MVPP2_GMAC_FLOW_CTRL_AUTONEG |
++ MVPP2_GMAC_AN_DUPLEX_EN;
++ if (port->phy_interface == PHY_INTERFACE_MODE_SGMII)
++ val |= MVPP2_GMAC_IN_BAND_AUTONEG;
++ writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
++}
++
++static void mvpp2_port_mii_gmac_configure(struct mvpp2_port *port)
++{
++ u32 val;
++
++ /* Force link down */
++ val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
++ val &= ~MVPP2_GMAC_FORCE_LINK_PASS;
++ val |= MVPP2_GMAC_FORCE_LINK_DOWN;
++ writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
++
++ /* Set the GMAC in a reset state */
++ val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
++ val |= MVPP2_GMAC_PORT_RESET_MASK;
++ writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
++
++ /* Configure the PCS and in-band AN */
++ val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
++ if (port->phy_interface == PHY_INTERFACE_MODE_SGMII) {
++ val |= MVPP2_GMAC_INBAND_AN_MASK | MVPP2_GMAC_PCS_ENABLE_MASK;
++ } else if (port->phy_interface == PHY_INTERFACE_MODE_RGMII ||
++ port->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
++ port->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID ||
++ port->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) {
++ val &= ~MVPP2_GMAC_PCS_ENABLE_MASK;
++ val |= MVPP2_GMAC_PORT_RGMII_MASK;
++ }
++ writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
++
++ mvpp2_port_mii_gmac_configure_mode(port);
++
++ /* Unset the GMAC reset state */
++ val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
++ val &= ~MVPP2_GMAC_PORT_RESET_MASK;
++ writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
++
++ /* Stop forcing link down */
++ val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
++ val &= ~MVPP2_GMAC_FORCE_LINK_DOWN;
++ writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
++}
++
+ static void mvpp22_port_mii_set(struct mvpp2_port *port)
+ {
+ u32 val;
+@@ -4262,38 +4354,19 @@ static void mvpp22_port_mii_set(struct m
+
+ writel(val, port->base + MVPP22_XLG_CTRL3_REG);
+ }
+-
+- val = readl(port->base + MVPP22_GMAC_CTRL_4_REG);
+- if (port->phy_interface == PHY_INTERFACE_MODE_RGMII)
+- val |= MVPP22_CTRL4_EXT_PIN_GMII_SEL;
+- else
+- val &= ~MVPP22_CTRL4_EXT_PIN_GMII_SEL;
+- val &= ~MVPP22_CTRL4_DP_CLK_SEL;
+- val |= MVPP22_CTRL4_SYNC_BYPASS_DIS;
+- val |= MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE;
+- writel(val, port->base + MVPP22_GMAC_CTRL_4_REG);
+ }
+
+ static void mvpp2_port_mii_set(struct mvpp2_port *port)
+ {
+- u32 val;
+-
+ if (port->priv->hw_version == MVPP22)
+ mvpp22_port_mii_set(port);
+
+- val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
+-
+- switch (port->phy_interface) {
+- case PHY_INTERFACE_MODE_SGMII:
+- val |= MVPP2_GMAC_INBAND_AN_MASK;
+- break;
+- case PHY_INTERFACE_MODE_RGMII:
+- val |= MVPP2_GMAC_PORT_RGMII_MASK;
+- default:
+- val &= ~MVPP2_GMAC_PCS_ENABLE_MASK;
+- }
+-
+- writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
++ if (port->phy_interface == PHY_INTERFACE_MODE_RGMII ||
++ port->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
++ port->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID ||
++ port->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID ||
++ port->phy_interface == PHY_INTERFACE_MODE_SGMII)
++ mvpp2_port_mii_gmac_configure(port);
+ }
+
+ static void mvpp2_port_fc_adv_enable(struct mvpp2_port *port)
diff --git a/patches.drivers/net-mvpp2-initialize-the-GoP.patch b/patches.drivers/net-mvpp2-initialize-the-GoP.patch
new file mode 100644
index 0000000000..c095b313fd
--- /dev/null
+++ b/patches.drivers/net-mvpp2-initialize-the-GoP.patch
@@ -0,0 +1,240 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Tue, 22 Aug 2017 19:08:27 +0200
+Subject: net: mvpp2: initialize the GoP
+Patch-mainline: v4.14-rc1
+Git-commit: f84bf386f3956c4a02c773a59c9c61033c00a5b5
+References: bsc#1098633
+
+The patch adds GoP (group of ports) initialization functions. The mvpp2
+driver was relying on the firmware/bootloader initialization; this patch
+moves this setup to the mvpp2 driver.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Tested-by: Marcin Wojtas <mw@semihalf.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 170 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 170 insertions(+)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -18,6 +18,7 @@
+ #include <linux/inetdevice.h>
+ #include <linux/mbus.h>
+ #include <linux/module.h>
++#include <linux/mfd/syscon.h>
+ #include <linux/interrupt.h>
+ #include <linux/cpumask.h>
+ #include <linux/of.h>
+@@ -30,6 +31,7 @@
+ #include <linux/clk.h>
+ #include <linux/hrtimer.h>
+ #include <linux/ktime.h>
++#include <linux/regmap.h>
+ #include <uapi/linux/ppp_defs.h>
+ #include <net/ip.h>
+ #include <net/ipv6.h>
+@@ -388,6 +390,38 @@
+ #define MVPP2_QUEUE_NEXT_DESC(q, index) \
+ (((index) < (q)->last_desc) ? ((index) + 1) : 0)
+
++/* XPCS registers. PPv2.2 only */
++#define MVPP22_MPCS_BASE(port) (0x7000 + (port) * 0x1000)
++#define MVPP22_MPCS_CTRL 0x14
++#define MVPP22_MPCS_CTRL_FWD_ERR_CONN BIT(10)
++#define MVPP22_MPCS_CLK_RESET 0x14c
++#define MAC_CLK_RESET_SD_TX BIT(0)
++#define MAC_CLK_RESET_SD_RX BIT(1)
++#define MAC_CLK_RESET_MAC BIT(2)
++#define MVPP22_MPCS_CLK_RESET_DIV_RATIO(n) ((n) << 4)
++#define MVPP22_MPCS_CLK_RESET_DIV_SET BIT(11)
++
++/* XPCS registers. PPv2.2 only */
++#define MVPP22_XPCS_BASE(port) (0x7400 + (port) * 0x1000)
++#define MVPP22_XPCS_CFG0 0x0
++#define MVPP22_XPCS_CFG0_PCS_MODE(n) ((n) << 3)
++#define MVPP22_XPCS_CFG0_ACTIVE_LANE(n) ((n) << 5)
++
++/* System controller registers. Accessed through a regmap. */
++#define GENCONF_SOFT_RESET1 0x1108
++#define GENCONF_SOFT_RESET1_GOP BIT(6)
++#define GENCONF_PORT_CTRL0 0x1110
++#define GENCONF_PORT_CTRL0_BUS_WIDTH_SELECT BIT(1)
++#define GENCONF_PORT_CTRL0_RX_DATA_SAMPLE BIT(29)
++#define GENCONF_PORT_CTRL0_CLK_DIV_PHASE_CLR BIT(31)
++#define GENCONF_PORT_CTRL1 0x1114
++#define GENCONF_PORT_CTRL1_EN(p) BIT(p)
++#define GENCONF_PORT_CTRL1_RESET(p) (BIT(p) << 28)
++#define GENCONF_CTRL0 0x1120
++#define GENCONF_CTRL0_PORT0_RGMII BIT(0)
++#define GENCONF_CTRL0_PORT1_RGMII_MII BIT(1)
++#define GENCONF_CTRL0_PORT1_RGMII BIT(2)
++
+ /* Various constants */
+
+ /* Coalescing */
+@@ -731,6 +765,11 @@ struct mvpp2 {
+ */
+ void __iomem *swth_base[MVPP2_MAX_THREADS];
+
++ /* On PPv2.2, some port control registers are located into the system
++ * controller space. These registers are accessible through a regmap.
++ */
++ struct regmap *sysctrl_base;
++
+ /* Common clocks */
+ struct clk *pp_clk;
+ struct clk *gop_clk;
+@@ -4259,6 +4298,123 @@ mvpp2_shared_interrupt_mask_unmask(struc
+
+ /* Port configuration routines */
+
++static void mvpp22_gop_init_rgmii(struct mvpp2_port *port)
++{
++ struct mvpp2 *priv = port->priv;
++ u32 val;
++
++ regmap_read(priv->sysctrl_base, GENCONF_PORT_CTRL0, &val);
++ val |= GENCONF_PORT_CTRL0_BUS_WIDTH_SELECT;
++ regmap_write(priv->sysctrl_base, GENCONF_PORT_CTRL0, val);
++
++ regmap_read(priv->sysctrl_base, GENCONF_CTRL0, &val);
++ if (port->gop_id == 2)
++ val |= GENCONF_CTRL0_PORT0_RGMII | GENCONF_CTRL0_PORT1_RGMII;
++ else if (port->gop_id == 3)
++ val |= GENCONF_CTRL0_PORT1_RGMII_MII;
++ regmap_write(priv->sysctrl_base, GENCONF_CTRL0, val);
++}
++
++static void mvpp22_gop_init_sgmii(struct mvpp2_port *port)
++{
++ struct mvpp2 *priv = port->priv;
++ u32 val;
++
++ regmap_read(priv->sysctrl_base, GENCONF_PORT_CTRL0, &val);
++ val |= GENCONF_PORT_CTRL0_BUS_WIDTH_SELECT |
++ GENCONF_PORT_CTRL0_RX_DATA_SAMPLE;
++ regmap_write(priv->sysctrl_base, GENCONF_PORT_CTRL0, val);
++
++ if (port->gop_id > 1) {
++ regmap_read(priv->sysctrl_base, GENCONF_CTRL0, &val);
++ if (port->gop_id == 2)
++ val &= ~GENCONF_CTRL0_PORT0_RGMII;
++ else if (port->gop_id == 3)
++ val &= ~GENCONF_CTRL0_PORT1_RGMII_MII;
++ regmap_write(priv->sysctrl_base, GENCONF_CTRL0, val);
++ }
++}
++
++static void mvpp22_gop_init_10gkr(struct mvpp2_port *port)
++{
++ struct mvpp2 *priv = port->priv;
++ void __iomem *mpcs = priv->iface_base + MVPP22_MPCS_BASE(port->gop_id);
++ void __iomem *xpcs = priv->iface_base + MVPP22_XPCS_BASE(port->gop_id);
++ u32 val;
++
++ /* XPCS */
++ val = readl(xpcs + MVPP22_XPCS_CFG0);
++ val &= ~(MVPP22_XPCS_CFG0_PCS_MODE(0x3) |
++ MVPP22_XPCS_CFG0_ACTIVE_LANE(0x3));
++ val |= MVPP22_XPCS_CFG0_ACTIVE_LANE(2);
++ writel(val, xpcs + MVPP22_XPCS_CFG0);
++
++ /* MPCS */
++ val = readl(mpcs + MVPP22_MPCS_CTRL);
++ val &= ~MVPP22_MPCS_CTRL_FWD_ERR_CONN;
++ writel(val, mpcs + MVPP22_MPCS_CTRL);
++
++ val = readl(mpcs + MVPP22_MPCS_CLK_RESET);
++ val &= ~(MVPP22_MPCS_CLK_RESET_DIV_RATIO(0x7) | MAC_CLK_RESET_MAC |
++ MAC_CLK_RESET_SD_RX | MAC_CLK_RESET_SD_TX);
++ val |= MVPP22_MPCS_CLK_RESET_DIV_RATIO(1);
++ writel(val, mpcs + MVPP22_MPCS_CLK_RESET);
++
++ val &= ~MVPP22_MPCS_CLK_RESET_DIV_SET;
++ val |= MAC_CLK_RESET_MAC | MAC_CLK_RESET_SD_RX | MAC_CLK_RESET_SD_TX;
++ writel(val, mpcs + MVPP22_MPCS_CLK_RESET);
++}
++
++static int mvpp22_gop_init(struct mvpp2_port *port)
++{
++ struct mvpp2 *priv = port->priv;
++ u32 val;
++
++ if (!priv->sysctrl_base)
++ return 0;
++
++ switch (port->phy_interface) {
++ case PHY_INTERFACE_MODE_RGMII:
++ case PHY_INTERFACE_MODE_RGMII_ID:
++ case PHY_INTERFACE_MODE_RGMII_RXID:
++ case PHY_INTERFACE_MODE_RGMII_TXID:
++ if (port->gop_id == 0)
++ goto invalid_conf;
++ mvpp22_gop_init_rgmii(port);
++ break;
++ case PHY_INTERFACE_MODE_SGMII:
++ mvpp22_gop_init_sgmii(port);
++ break;
++ case PHY_INTERFACE_MODE_10GKR:
++ if (port->gop_id != 0)
++ goto invalid_conf;
++ mvpp22_gop_init_10gkr(port);
++ break;
++ default:
++ goto unsupported_conf;
++ }
++
++ regmap_read(priv->sysctrl_base, GENCONF_PORT_CTRL1, &val);
++ val |= GENCONF_PORT_CTRL1_RESET(port->gop_id) |
++ GENCONF_PORT_CTRL1_EN(port->gop_id);
++ regmap_write(priv->sysctrl_base, GENCONF_PORT_CTRL1, val);
++
++ regmap_read(priv->sysctrl_base, GENCONF_PORT_CTRL0, &val);
++ val |= GENCONF_PORT_CTRL0_CLK_DIV_PHASE_CLR;
++ regmap_write(priv->sysctrl_base, GENCONF_PORT_CTRL0, val);
++
++ regmap_read(priv->sysctrl_base, GENCONF_SOFT_RESET1, &val);
++ val |= GENCONF_SOFT_RESET1_GOP;
++ regmap_write(priv->sysctrl_base, GENCONF_SOFT_RESET1, val);
++
++unsupported_conf:
++ return 0;
++
++invalid_conf:
++ netdev_err(port->dev, "Invalid port configuration\n");
++ return -EINVAL;
++}
++
+ static void mvpp2_port_mii_gmac_configure_mode(struct mvpp2_port *port)
+ {
+ u32 val;
+@@ -6105,6 +6261,9 @@ static void mvpp2_start_dev(struct mvpp2
+ /* Enable interrupts on all CPUs */
+ mvpp2_interrupts_enable(port);
+
++ if (port->priv->hw_version == MVPP22)
++ mvpp22_gop_init(port);
++
+ mvpp2_port_mii_set(port);
+ mvpp2_port_enable(port);
+ phy_start(ndev->phydev);
+@@ -7350,6 +7509,17 @@ static int mvpp2_probe(struct platform_d
+ priv->iface_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->iface_base))
+ return PTR_ERR(priv->iface_base);
++
++ priv->sysctrl_base =
++ syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
++ "marvell,system-controller");
++ if (IS_ERR(priv->sysctrl_base))
++ /* The system controller regmap is optional for dt
++ * compatibility reasons. When not provided, the
++ * configuration of the GoP relies on the
++ * firmware/bootloader.
++ */
++ priv->sysctrl_base = NULL;
+ }
+
+ for (i = 0; i < MVPP2_MAX_THREADS; i++) {
diff --git a/patches.drivers/net-mvpp2-initialize-the-RSS-tables.patch b/patches.drivers/net-mvpp2-initialize-the-RSS-tables.patch
new file mode 100644
index 0000000000..031c236004
--- /dev/null
+++ b/patches.drivers/net-mvpp2-initialize-the-RSS-tables.patch
@@ -0,0 +1,99 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Mon, 30 Oct 2017 11:23:30 +0100
+Subject: net: mvpp2: initialize the RSS tables
+Patch-mainline: v4.15-rc1
+Git-commit: 1d7d15d79fb4660bec3a86e748c50aac7c5d2121
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 50 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 50 insertions(+)
+
+--- 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 mvp
+ }
+ }
+
++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
+
+ mvpp2_start_dev(port);
+
++ if (priv->hw_version == MVPP22)
++ mvpp22_init_rss(port);
++
+ return 0;
+
+ err_free_link_irq:
diff --git a/patches.drivers/net-mvpp2-initialize-the-Tx-FIFO-size.patch b/patches.drivers/net-mvpp2-initialize-the-Tx-FIFO-size.patch
new file mode 100644
index 0000000000..30c888c83c
--- /dev/null
+++ b/patches.drivers/net-mvpp2-initialize-the-Tx-FIFO-size.patch
@@ -0,0 +1,79 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Mon, 30 Oct 2017 11:23:29 +0100
+Subject: net: mvpp2: initialize the Tx FIFO size
+Patch-mainline: v4.15-rc1
+Git-commit: 7c10f9742d76ec18bed5de14f5f4ed08859f7b7a
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 25 +++++++++++++++++++++----
+ 1 file changed, 21 insertions(+), 4 deletions(-)
+
+--- 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 m
+ 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_de
+ 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,
diff --git a/patches.drivers/net-mvpp2-initialize-the-XLG-MAC-when-using-a-port.patch b/patches.drivers/net-mvpp2-initialize-the-XLG-MAC-when-using-a-port.patch
new file mode 100644
index 0000000000..15e832651a
--- /dev/null
+++ b/patches.drivers/net-mvpp2-initialize-the-XLG-MAC-when-using-a-port.patch
@@ -0,0 +1,76 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Tue, 22 Aug 2017 19:08:25 +0200
+Subject: net: mvpp2: initialize the XLG MAC when using a port
+Patch-mainline: v4.14-rc1
+Git-commit: 77321959feb9bdcfeeb2a2154d6fb831fb1991c2
+References: bsc#1098633
+
+This adds a routine to initialize the XLG MAC at the port level when
+using a port and the XAUI/10GKR interface mode. This wasn't done until
+this commit, and the mvpp2 driver was relying on the bootloader/firmware
+initialization. This doesn't mean everything is configured in the mvpp2
+driver now, but it helps reducing the gap.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Tested-by: Marcin Wojtas <mw@semihalf.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -361,6 +361,7 @@
+ #define MVPP22_XLG_CTRL0_REG 0x100
+ #define MVPP22_XLG_CTRL0_PORT_EN BIT(0)
+ #define MVPP22_XLG_CTRL0_MAC_RESET_DIS BIT(1)
++#define MVPP22_XLG_CTRL0_RX_FLOW_CTRL_EN BIT(7)
+ #define MVPP22_XLG_CTRL0_MIB_CNT_DIS BIT(14)
+
+ #define MVPP22_XLG_CTRL3_REG 0x11c
+@@ -368,6 +369,11 @@
+ #define MVPP22_XLG_CTRL3_MACMODESELECT_GMAC (0 << 13)
+ #define MVPP22_XLG_CTRL3_MACMODESELECT_10G (1 << 13)
+
++#define MVPP22_XLG_CTRL4_REG 0x184
++#define MVPP22_XLG_CTRL4_FWD_FC BIT(5)
++#define MVPP22_XLG_CTRL4_FWD_PFC BIT(6)
++#define MVPP22_XLG_CTRL4_MACMODSELECT_GMAC BIT(12)
++
+ /* SMI registers. PPv2.2 only, relative to priv->iface_base. */
+ #define MVPP22_SMI_MISC_CFG_REG 0x1204
+ #define MVPP22_SMI_POLLING_EN BIT(10)
+@@ -4337,6 +4343,23 @@ static void mvpp2_port_mii_gmac_configur
+ writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
+ }
+
++static void mvpp2_port_mii_xlg_configure(struct mvpp2_port *port)
++{
++ u32 val;
++
++ if (port->gop_id != 0)
++ return;
++
++ val = readl(port->base + MVPP22_XLG_CTRL0_REG);
++ val |= MVPP22_XLG_CTRL0_RX_FLOW_CTRL_EN;
++ writel(val, port->base + MVPP22_XLG_CTRL0_REG);
++
++ val = readl(port->base + MVPP22_XLG_CTRL4_REG);
++ val &= ~MVPP22_XLG_CTRL4_MACMODSELECT_GMAC;
++ val |= MVPP22_XLG_CTRL4_FWD_FC | MVPP22_XLG_CTRL4_FWD_PFC;
++ writel(val, port->base + MVPP22_XLG_CTRL4_REG);
++}
++
+ static void mvpp22_port_mii_set(struct mvpp2_port *port)
+ {
+ u32 val;
+@@ -4367,6 +4390,8 @@ static void mvpp2_port_mii_set(struct mv
+ port->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID ||
+ port->phy_interface == PHY_INTERFACE_MODE_SGMII)
+ mvpp2_port_mii_gmac_configure(port);
++ else if (port->phy_interface == PHY_INTERFACE_MODE_10GKR)
++ mvpp2_port_mii_xlg_configure(port);
+ }
+
+ static void mvpp2_port_fc_adv_enable(struct mvpp2_port *port)
diff --git a/patches.drivers/net-mvpp2-initialize-the-comphy.patch b/patches.drivers/net-mvpp2-initialize-the-comphy.patch
new file mode 100644
index 0000000000..e657890d6f
--- /dev/null
+++ b/patches.drivers/net-mvpp2-initialize-the-comphy.patch
@@ -0,0 +1,123 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Wed, 30 Aug 2017 10:29:15 +0200
+Subject: net: mvpp2: initialize the comphy
+Patch-mainline: v4.14-rc1
+Git-commit: 542897d987b0d16c4346952f116acb80a8e82a38
+References: bsc#1098633
+
+On some platforms, the comphy is between the MAC GoP and the PHYs. The
+mvpp2 driver currently relies on the firmware/bootloader to configure
+the comphy. As a comphy driver was added to the generic PHY framework,
+this patch uses it in the mvpp2 driver to configure the comphy at boot
+time to avoid relying on the bootloader.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 44 ++++++++++++++++++++++++++++++++++-
+ 1 file changed, 43 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -28,6 +28,7 @@
+ #include <linux/of_address.h>
+ #include <linux/of_device.h>
+ #include <linux/phy.h>
++#include <linux/phy/phy.h>
+ #include <linux/clk.h>
+ #include <linux/hrtimer.h>
+ #include <linux/ktime.h>
+@@ -861,6 +862,7 @@ struct mvpp2_port {
+
+ phy_interface_t phy_interface;
+ struct device_node *phy_node;
++ struct phy *comphy;
+ unsigned int link;
+ unsigned int duplex;
+ unsigned int speed;
+@@ -4420,6 +4422,32 @@ invalid_conf:
+ return -EINVAL;
+ }
+
++static int mvpp22_comphy_init(struct mvpp2_port *port)
++{
++ enum phy_mode mode;
++ int ret;
++
++ if (!port->comphy)
++ return 0;
++
++ switch (port->phy_interface) {
++ case PHY_INTERFACE_MODE_SGMII:
++ mode = PHY_MODE_SGMII;
++ break;
++ case PHY_INTERFACE_MODE_10GKR:
++ mode = PHY_MODE_10GKR;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ ret = phy_set_mode(port->comphy, mode);
++ if (ret)
++ return ret;
++
++ return phy_power_on(port->comphy);
++}
++
+ static void mvpp2_port_mii_gmac_configure_mode(struct mvpp2_port *port)
+ {
+ u32 val;
+@@ -6404,8 +6432,10 @@ static void mvpp2_start_dev(struct mvpp2
+ /* Enable interrupts on all CPUs */
+ mvpp2_interrupts_enable(port);
+
+- if (port->priv->hw_version == MVPP22)
++ if (port->priv->hw_version == MVPP22) {
++ mvpp22_comphy_init(port);
+ mvpp22_gop_init(port);
++ }
+
+ mvpp2_port_mii_set(port);
+ mvpp2_port_enable(port);
+@@ -6436,6 +6466,7 @@ static void mvpp2_stop_dev(struct mvpp2_
+ mvpp2_egress_disable(port);
+ mvpp2_port_disable(port);
+ phy_stop(ndev->phydev);
++ phy_power_off(port->comphy);
+ }
+
+ static int mvpp2_check_ringparam_valid(struct net_device *dev,
+@@ -7242,6 +7273,7 @@ static int mvpp2_port_probe(struct platf
+ struct mvpp2 *priv)
+ {
+ struct device_node *phy_node;
++ struct phy *comphy;
+ struct mvpp2_port *port;
+ struct mvpp2_port_pcpu *port_pcpu;
+ struct net_device *dev;
+@@ -7285,6 +7317,15 @@ static int mvpp2_port_probe(struct platf
+ 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;
++ }
++ comphy = NULL;
++ }
++
+ if (of_property_read_u32(port_node, "port-id", &id)) {
+ err = -EINVAL;
+ dev_err(&pdev->dev, "missing port-id value\n");
+@@ -7318,6 +7359,7 @@ static int mvpp2_port_probe(struct platf
+
+ port->phy_node = phy_node;
+ port->phy_interface = phy_mode;
++ port->comphy = comphy;
+
+ if (priv->hw_version == MVPP21) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2 + id);
diff --git a/patches.drivers/net-mvpp2-introduce-per-port-nrxqs-ntxqs-variables.patch b/patches.drivers/net-mvpp2-introduce-per-port-nrxqs-ntxqs-variables.patch
new file mode 100644
index 0000000000..fab09b5122
--- /dev/null
+++ b/patches.drivers/net-mvpp2-introduce-per-port-nrxqs-ntxqs-variables.patch
@@ -0,0 +1,346 @@
+From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Date: Thu, 3 Aug 2017 10:41:57 +0200
+Subject: net: mvpp2: introduce per-port nrxqs/ntxqs variables
+Patch-mainline: v4.14-rc1
+Git-commit: 09f8397553a24c66e0141ec57f2c1801acd4e4a0
+References: bsc#1098633
+
+Currently, the global variables rxq_number and txq_number hold the
+number of per-port TXQs and RXQs. Until now, such numbers were
+constant regardless of the driver configuration. As we are going to
+introduce different modes for TX and RX queues, these numbers will
+depend on the configuration (PPv2.1 vs. PPv2.2, exact queue
+distribution logic).
+
+Therefore, as a preparation, we move the number of RXQs and TXQs in
+the 'struct mvpp2_port' structure, next to the RXQs and TXQs
+descriptor arrays.
+
+For now, they remain initialized to the same default values as
+rxq_number/txq_number used to be initialized, but this will change in
+future commits.
+
+The only non-mechanical change in this patch is that the check to
+verify hardware constraints on the number of RXQs and TXQs is moved
+from mvpp2_probe() to mvpp2_port_probe(), since it's now in
+mvpp2_port_probe() that we initialize the per-port count of RXQ and
+TXQ.
+
+Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 83 +++++++++++++++++------------------
+ 1 file changed, 41 insertions(+), 42 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -768,7 +768,9 @@ struct mvpp2_port {
+ void __iomem *base;
+
+ struct mvpp2_rx_queue **rxqs;
++ unsigned int nrxqs;
+ struct mvpp2_tx_queue **txqs;
++ unsigned int ntxqs;
+ struct net_device *dev;
+
+ int pkt_size;
+@@ -1062,13 +1064,6 @@ struct mvpp2_bm_pool {
+ u32 port_map;
+ };
+
+-/* Static declaractions */
+-
+-/* Number of RXQs used by single port */
+-static int rxq_number = MVPP2_DEFAULT_RXQ;
+-/* Number of TXQs used by single port */
+-static int txq_number = MVPP2_MAX_TXQ;
+-
+ #define MVPP2_DRIVER_NAME "mvpp2"
+ #define MVPP2_DRIVER_VERSION "1.0"
+
+@@ -4070,7 +4065,7 @@ static int mvpp2_swf_bm_pool_init(struct
+
+ port->pool_long->port_map |= (1 << port->id);
+
+- for (rxq = 0; rxq < rxq_number; rxq++)
++ for (rxq = 0; rxq < port->nrxqs; rxq++)
+ mvpp2_rxq_long_pool_set(port, rxq, port->pool_long->id);
+ }
+
+@@ -4084,7 +4079,7 @@ static int mvpp2_swf_bm_pool_init(struct
+
+ port->pool_short->port_map |= (1 << port->id);
+
+- for (rxq = 0; rxq < rxq_number; rxq++)
++ for (rxq = 0; rxq < port->nrxqs; rxq++)
+ mvpp2_rxq_short_pool_set(port, rxq,
+ port->pool_short->id);
+ }
+@@ -4376,7 +4371,7 @@ static void mvpp2_defaults_set(struct mv
+ MVPP2_RX_LOW_LATENCY_PKT_SIZE(256));
+
+ /* Enable Rx cache snoop */
+- for (lrxq = 0; lrxq < rxq_number; lrxq++) {
++ for (lrxq = 0; lrxq < port->nrxqs; lrxq++) {
+ queue = port->rxqs[lrxq]->id;
+ val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue));
+ val |= MVPP2_SNOOP_PKT_SIZE_MASK |
+@@ -4394,7 +4389,7 @@ static void mvpp2_ingress_enable(struct
+ u32 val;
+ int lrxq, queue;
+
+- for (lrxq = 0; lrxq < rxq_number; lrxq++) {
++ for (lrxq = 0; lrxq < port->nrxqs; lrxq++) {
+ queue = port->rxqs[lrxq]->id;
+ val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue));
+ val &= ~MVPP2_RXQ_DISABLE_MASK;
+@@ -4407,7 +4402,7 @@ static void mvpp2_ingress_disable(struct
+ u32 val;
+ int lrxq, queue;
+
+- for (lrxq = 0; lrxq < rxq_number; lrxq++) {
++ for (lrxq = 0; lrxq < port->nrxqs; lrxq++) {
+ queue = port->rxqs[lrxq]->id;
+ val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue));
+ val |= MVPP2_RXQ_DISABLE_MASK;
+@@ -4426,7 +4421,7 @@ static void mvpp2_egress_enable(struct m
+
+ /* Enable all initialized TXs. */
+ qmap = 0;
+- for (queue = 0; queue < txq_number; queue++) {
++ for (queue = 0; queue < port->ntxqs; queue++) {
+ struct mvpp2_tx_queue *txq = port->txqs[queue];
+
+ if (txq->descs)
+@@ -4712,7 +4707,7 @@ static void mvpp2_txq_sent_counter_clear
+ struct mvpp2_port *port = arg;
+ int queue;
+
+- for (queue = 0; queue < txq_number; queue++) {
++ for (queue = 0; queue < port->ntxqs; queue++) {
+ int id = port->txqs[queue]->id;
+
+ mvpp2_percpu_read(port->priv, smp_processor_id(),
+@@ -4753,7 +4748,7 @@ static void mvpp2_txp_max_tx_size_set(st
+ mvpp2_write(port->priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, val);
+ }
+
+- for (txq = 0; txq < txq_number; txq++) {
++ for (txq = 0; txq < port->ntxqs; txq++) {
+ val = mvpp2_read(port->priv,
+ MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(txq));
+ size = val & MVPP2_TXQ_TOKEN_SIZE_MAX;
+@@ -5229,7 +5224,7 @@ static void mvpp2_cleanup_txqs(struct mv
+ val |= MVPP2_TX_PORT_FLUSH_MASK(port->id);
+ mvpp2_write(port->priv, MVPP2_TX_PORT_FLUSH_REG, val);
+
+- for (queue = 0; queue < txq_number; queue++) {
++ for (queue = 0; queue < port->ntxqs; queue++) {
+ txq = port->txqs[queue];
+ mvpp2_txq_clean(port, txq);
+ mvpp2_txq_deinit(port, txq);
+@@ -5246,7 +5241,7 @@ static void mvpp2_cleanup_rxqs(struct mv
+ {
+ int queue;
+
+- for (queue = 0; queue < rxq_number; queue++)
++ for (queue = 0; queue < port->nrxqs; queue++)
+ mvpp2_rxq_deinit(port, port->rxqs[queue]);
+ }
+
+@@ -5255,7 +5250,7 @@ static int mvpp2_setup_rxqs(struct mvpp2
+ {
+ int queue, err;
+
+- for (queue = 0; queue < rxq_number; queue++) {
++ for (queue = 0; queue < port->nrxqs; queue++) {
+ err = mvpp2_rxq_init(port, port->rxqs[queue]);
+ if (err)
+ goto err_cleanup;
+@@ -5273,7 +5268,7 @@ static int mvpp2_setup_txqs(struct mvpp2
+ struct mvpp2_tx_queue *txq;
+ int queue, err;
+
+- for (queue = 0; queue < txq_number; queue++) {
++ for (queue = 0; queue < port->ntxqs; queue++) {
+ txq = port->txqs[queue];
+ err = mvpp2_txq_init(port, txq);
+ if (err)
+@@ -5385,7 +5380,7 @@ static void mvpp2_tx_proc_cb(unsigned lo
+ port_pcpu->timer_scheduled = false;
+
+ /* Process all the Tx queues */
+- cause = (1 << txq_number) - 1;
++ cause = (1 << port->ntxqs) - 1;
+ tx_todo = mvpp2_tx_done(port, cause);
+
+ /* Set the timer in case not all the packets were processed */
+@@ -6228,7 +6223,7 @@ static int mvpp2_ethtool_set_coalesce(st
+ struct mvpp2_port *port = netdev_priv(dev);
+ int queue;
+
+- for (queue = 0; queue < rxq_number; queue++) {
++ for (queue = 0; queue < port->nrxqs; queue++) {
+ struct mvpp2_rx_queue *rxq = port->rxqs[queue];
+
+ rxq->time_coal = c->rx_coalesce_usecs;
+@@ -6237,7 +6232,7 @@ static int mvpp2_ethtool_set_coalesce(st
+ mvpp2_rx_time_coal_set(port, rxq);
+ }
+
+- for (queue = 0; queue < txq_number; queue++) {
++ for (queue = 0; queue < port->ntxqs; queue++) {
+ struct mvpp2_tx_queue *txq = port->txqs[queue];
+
+ txq->done_pkts_coal = c->tx_max_coalesced_frames;
+@@ -6373,15 +6368,20 @@ static int mvpp2_port_init(struct mvpp2_
+ struct mvpp2_txq_pcpu *txq_pcpu;
+ int queue, cpu, err;
+
+- if (port->first_rxq + rxq_number >
++ /* Checks for hardware constraints */
++ if (port->first_rxq + port->nrxqs >
+ MVPP2_MAX_PORTS * priv->max_port_rxqs)
+ return -EINVAL;
+
++ if (port->nrxqs % 4 || (port->nrxqs > priv->max_port_rxqs) ||
++ (port->ntxqs > MVPP2_MAX_TXQ))
++ return -EINVAL;
++
+ /* Disable port */
+ mvpp2_egress_disable(port);
+ mvpp2_port_disable(port);
+
+- port->txqs = devm_kcalloc(dev, txq_number, sizeof(*port->txqs),
++ port->txqs = devm_kcalloc(dev, port->ntxqs, sizeof(*port->txqs),
+ GFP_KERNEL);
+ if (!port->txqs)
+ return -ENOMEM;
+@@ -6389,7 +6389,7 @@ static int mvpp2_port_init(struct mvpp2_
+ /* Associate physical Tx queues to this port and initialize.
+ * The mapping is predefined.
+ */
+- for (queue = 0; queue < txq_number; queue++) {
++ for (queue = 0; queue < port->ntxqs; queue++) {
+ int queue_phy_id = mvpp2_txq_phys(port->id, queue);
+ struct mvpp2_tx_queue *txq;
+
+@@ -6416,7 +6416,7 @@ static int mvpp2_port_init(struct mvpp2_
+ port->txqs[queue] = txq;
+ }
+
+- port->rxqs = devm_kcalloc(dev, rxq_number, sizeof(*port->rxqs),
++ port->rxqs = devm_kcalloc(dev, port->nrxqs, sizeof(*port->rxqs),
+ GFP_KERNEL);
+ if (!port->rxqs) {
+ err = -ENOMEM;
+@@ -6424,7 +6424,7 @@ static int mvpp2_port_init(struct mvpp2_
+ }
+
+ /* Allocate and initialize Rx queue for this port */
+- for (queue = 0; queue < rxq_number; queue++) {
++ for (queue = 0; queue < port->nrxqs; queue++) {
+ struct mvpp2_rx_queue *rxq;
+
+ /* Map physical Rx queue to port's logical Rx queue */
+@@ -6444,19 +6444,19 @@ static int mvpp2_port_init(struct mvpp2_
+ /* Configure Rx queue group interrupt for this port */
+ if (priv->hw_version == MVPP21) {
+ mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(port->id),
+- rxq_number);
++ port->nrxqs);
+ } else {
+ u32 val;
+
+ val = (port->id << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET);
+ mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val);
+
+- val = (rxq_number << MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET);
++ val = (port->nrxqs << MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET);
+ mvpp2_write(priv, MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val);
+ }
+
+ /* Create Rx descriptor rings */
+- for (queue = 0; queue < rxq_number; queue++) {
++ for (queue = 0; queue < port->nrxqs; queue++) {
+ struct mvpp2_rx_queue *rxq = port->rxqs[queue];
+
+ rxq->size = port->rx_ring_size;
+@@ -6484,7 +6484,7 @@ static int mvpp2_port_init(struct mvpp2_
+ return 0;
+
+ err_free_percpu:
+- for (queue = 0; queue < txq_number; queue++) {
++ for (queue = 0; queue < port->ntxqs; queue++) {
+ if (!port->txqs[queue])
+ continue;
+ free_percpu(port->txqs[queue]->pcpu);
+@@ -6505,12 +6505,16 @@ static int mvpp2_port_probe(struct platf
+ const char *dt_mac_addr;
+ const char *mac_from;
+ char hw_mac_addr[ETH_ALEN] = {0};
++ unsigned int ntxqs, nrxqs;
+ u32 id;
+ int features;
+ int phy_mode;
+ int err, i, cpu;
+
+- dev = alloc_etherdev_mqs(sizeof(*port), txq_number, rxq_number);
++ ntxqs = MVPP2_MAX_TXQ;
++ nrxqs = MVPP2_DEFAULT_RXQ;
++
++ dev = alloc_etherdev_mqs(sizeof(*port), ntxqs, nrxqs);
+ if (!dev)
+ return -ENOMEM;
+
+@@ -6540,6 +6544,8 @@ static int mvpp2_port_probe(struct platf
+ dev->ethtool_ops = &mvpp2_eth_tool_ops;
+
+ port = netdev_priv(dev);
++ port->ntxqs = ntxqs;
++ port->nrxqs = nrxqs;
+
+ port->irq = irq_of_parse_and_map(port_node, 0);
+ if (port->irq <= 0) {
+@@ -6553,7 +6559,7 @@ static int mvpp2_port_probe(struct platf
+ port->priv = priv;
+ port->id = id;
+ if (priv->hw_version == MVPP21)
+- port->first_rxq = port->id * rxq_number;
++ port->first_rxq = port->id * port->nrxqs;
+ else
+ port->first_rxq = port->id * priv->max_port_rxqs;
+
+@@ -6662,7 +6668,7 @@ static int mvpp2_port_probe(struct platf
+ err_free_port_pcpu:
+ free_percpu(port->pcpu);
+ err_free_txq_pcpu:
+- for (i = 0; i < txq_number; i++)
++ for (i = 0; i < port->ntxqs; i++)
+ free_percpu(port->txqs[i]->pcpu);
+ err_free_stats:
+ free_percpu(port->stats);
+@@ -6683,7 +6689,7 @@ static void mvpp2_port_remove(struct mvp
+ of_node_put(port->phy_node);
+ free_percpu(port->pcpu);
+ free_percpu(port->stats);
+- for (i = 0; i < txq_number; i++)
++ for (i = 0; i < port->ntxqs; i++)
+ free_percpu(port->txqs[i]->pcpu);
+ irq_dispose_mapping(port->irq);
+ free_netdev(port->dev);
+@@ -6800,13 +6806,6 @@ static int mvpp2_init(struct platform_de
+ int err, i;
+ u32 val;
+
+- /* Checks for hardware constraints */
+- if (rxq_number % 4 || (rxq_number > priv->max_port_rxqs) ||
+- (txq_number > MVPP2_MAX_TXQ)) {
+- dev_err(&pdev->dev, "invalid queue size parameter\n");
+- return -EINVAL;
+- }
+-
+ /* MBUS windows configuration */
+ dram_target_info = mv_mbus_dram_info();
+ if (dram_target_info)
diff --git a/patches.drivers/net-mvpp2-introduce-queue_vector-concept.patch b/patches.drivers/net-mvpp2-introduce-queue_vector-concept.patch
new file mode 100644
index 0000000000..8bd306cb86
--- /dev/null
+++ b/patches.drivers/net-mvpp2-introduce-queue_vector-concept.patch
@@ -0,0 +1,479 @@
+From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Date: Thu, 3 Aug 2017 10:41:59 +0200
+Subject: net: mvpp2: introduce queue_vector concept
+Patch-mainline: v4.14-rc1
+Git-commit: 591f4cfab38a6e69573210b21c0554e1acbbd532
+References: bsc#1098633
+
+In preparation to the introduction of TX interrupts and improved RX
+queue distribution, this commit introduces the concept of "queue
+vector". A queue vector represents a number of RX and/or TX queues,
+and an associated NAPI instance and interrupt.
+
+This commit currently only creates a single queue_vector, so there are
+no changes in behavior, but it paves the way for additional
+queue_vector in the next commits.
+
+Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 223 ++++++++++++++++++++++++++---------
+ 1 file changed, 169 insertions(+), 54 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -686,6 +686,7 @@ enum mvpp2_prs_l3_cast {
+ #define MVPP22_ADDR_SPACE_SZ SZ_64K
+
+ #define MVPP2_MAX_THREADS 8
++#define MVPP2_MAX_QVECS MVPP2_MAX_THREADS
+
+ enum mvpp2_bm_type {
+ MVPP2_BM_FREE,
+@@ -753,6 +754,18 @@ struct mvpp2_port_pcpu {
+ struct tasklet_struct tx_done_tasklet;
+ };
+
++struct mvpp2_queue_vector {
++ int irq;
++ struct napi_struct napi;
++ enum { MVPP2_QUEUE_VECTOR_SHARED, MVPP2_QUEUE_VECTOR_PRIVATE } type;
++ int sw_thread_id;
++ u16 sw_thread_mask;
++ int first_rxq;
++ int nrxqs;
++ u32 pending_cause_rx;
++ struct mvpp2_port *port;
++};
++
+ struct mvpp2_port {
+ u8 id;
+
+@@ -761,8 +774,6 @@ struct mvpp2_port {
+ */
+ int gop_id;
+
+- int irq;
+-
+ struct mvpp2 *priv;
+
+ /* Per-port registers' base address */
+@@ -776,9 +787,6 @@ struct mvpp2_port {
+
+ int pkt_size;
+
+- u32 pending_cause_rx;
+- struct napi_struct napi;
+-
+ /* Per-CPU port control */
+ struct mvpp2_port_pcpu __percpu *pcpu;
+
+@@ -800,6 +808,9 @@ struct mvpp2_port {
+
+ /* Index of first port's physical RXQ */
+ u8 first_rxq;
++
++ struct mvpp2_queue_vector qvecs[MVPP2_MAX_QVECS];
++ unsigned int nqvecs;
+ };
+
+ /* The mvpp2_tx_desc and mvpp2_rx_desc structures describe the
+@@ -4121,22 +4132,40 @@ static int mvpp2_bm_update_mtu(struct ne
+
+ static inline void mvpp2_interrupts_enable(struct mvpp2_port *port)
+ {
+- int cpu, cpu_mask = 0;
++ int i, sw_thread_mask = 0;
++
++ for (i = 0; i < port->nqvecs; i++)
++ sw_thread_mask |= port->qvecs[i].sw_thread_mask;
+
+- for_each_present_cpu(cpu)
+- cpu_mask |= 1 << cpu;
+ mvpp2_write(port->priv, MVPP2_ISR_ENABLE_REG(port->id),
+- MVPP2_ISR_ENABLE_INTERRUPT(cpu_mask));
++ MVPP2_ISR_ENABLE_INTERRUPT(sw_thread_mask));
+ }
+
+ static inline void mvpp2_interrupts_disable(struct mvpp2_port *port)
+ {
+- int cpu, cpu_mask = 0;
++ int i, sw_thread_mask = 0;
++
++ for (i = 0; i < port->nqvecs; i++)
++ sw_thread_mask |= port->qvecs[i].sw_thread_mask;
++
++ mvpp2_write(port->priv, MVPP2_ISR_ENABLE_REG(port->id),
++ MVPP2_ISR_DISABLE_INTERRUPT(sw_thread_mask));
++}
++
++static inline void mvpp2_qvec_interrupt_enable(struct mvpp2_queue_vector *qvec)
++{
++ struct mvpp2_port *port = qvec->port;
+
+- for_each_present_cpu(cpu)
+- cpu_mask |= 1 << cpu;
+ mvpp2_write(port->priv, MVPP2_ISR_ENABLE_REG(port->id),
+- MVPP2_ISR_DISABLE_INTERRUPT(cpu_mask));
++ MVPP2_ISR_ENABLE_INTERRUPT(qvec->sw_thread_mask));
++}
++
++static inline void mvpp2_qvec_interrupt_disable(struct mvpp2_queue_vector *qvec)
++{
++ struct mvpp2_port *port = qvec->port;
++
++ mvpp2_write(port->priv, MVPP2_ISR_ENABLE_REG(port->id),
++ MVPP2_ISR_DISABLE_INTERRUPT(qvec->sw_thread_mask));
+ }
+
+ /* Mask the current CPU's Rx/Tx interrupts
+@@ -5287,11 +5316,11 @@ err_cleanup:
+ /* The callback for per-port interrupt */
+ static irqreturn_t mvpp2_isr(int irq, void *dev_id)
+ {
+- struct mvpp2_port *port = (struct mvpp2_port *)dev_id;
++ struct mvpp2_queue_vector *qv = dev_id;
+
+- mvpp2_interrupts_disable(port);
++ mvpp2_qvec_interrupt_disable(qv);
+
+- napi_schedule(&port->napi);
++ napi_schedule(&qv->napi);
+
+ return IRQ_HANDLED;
+ }
+@@ -5494,8 +5523,8 @@ static u32 mvpp2_skb_tx_csum(struct mvpp
+ }
+
+ /* Main rx processing */
+-static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
+- struct mvpp2_rx_queue *rxq)
++static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
++ int rx_todo, struct mvpp2_rx_queue *rxq)
+ {
+ struct net_device *dev = port->dev;
+ int rx_received;
+@@ -5573,7 +5602,7 @@ err_drop_frame:
+ skb->protocol = eth_type_trans(skb, dev);
+ mvpp2_rx_csum(port, rx_status, skb);
+
+- napi_gro_receive(&port->napi, skb);
++ napi_gro_receive(napi, skb);
+ }
+
+ if (rcvd_pkts) {
+@@ -5782,8 +5811,11 @@ static int mvpp2_poll(struct napi_struct
+ u32 cause_rx_tx, cause_rx, cause_misc;
+ int rx_done = 0;
+ struct mvpp2_port *port = netdev_priv(napi->dev);
++ struct mvpp2_queue_vector *qv;
+ int cpu = smp_processor_id();
+
++ qv = container_of(napi, struct mvpp2_queue_vector, napi);
++
+ /* Rx/Tx cause register
+ *
+ * Bits 0-15: each bit indicates received packets on the Rx queue
+@@ -5812,7 +5844,7 @@ static int mvpp2_poll(struct napi_struct
+ cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK;
+
+ /* Process RX packets */
+- cause_rx |= port->pending_cause_rx;
++ cause_rx |= qv->pending_cause_rx;
+ while (cause_rx && budget > 0) {
+ int count;
+ struct mvpp2_rx_queue *rxq;
+@@ -5821,7 +5853,7 @@ static int mvpp2_poll(struct napi_struct
+ if (!rxq)
+ break;
+
+- count = mvpp2_rx(port, budget, rxq);
++ count = mvpp2_rx(port, napi, budget, rxq);
+ rx_done += count;
+ budget -= count;
+ if (budget > 0) {
+@@ -5837,9 +5869,9 @@ static int mvpp2_poll(struct napi_struct
+ cause_rx = 0;
+ napi_complete_done(napi, rx_done);
+
+- mvpp2_interrupts_enable(port);
++ mvpp2_qvec_interrupt_enable(qv);
+ }
+- port->pending_cause_rx = cause_rx;
++ qv->pending_cause_rx = cause_rx;
+ return rx_done;
+ }
+
+@@ -5847,11 +5879,13 @@ static int mvpp2_poll(struct napi_struct
+ static void mvpp2_start_dev(struct mvpp2_port *port)
+ {
+ struct net_device *ndev = port->dev;
++ int i;
+
+ mvpp2_gmac_max_rx_size_set(port);
+ mvpp2_txp_max_tx_size_set(port);
+
+- napi_enable(&port->napi);
++ for (i = 0; i < port->nqvecs; i++)
++ napi_enable(&port->qvecs[i].napi);
+
+ /* Enable interrupts on all CPUs */
+ mvpp2_interrupts_enable(port);
+@@ -5865,6 +5899,7 @@ static void mvpp2_start_dev(struct mvpp2
+ static void mvpp2_stop_dev(struct mvpp2_port *port)
+ {
+ struct net_device *ndev = port->dev;
++ int i;
+
+ /* Stop new packets from arriving to RXQs */
+ mvpp2_ingress_disable(port);
+@@ -5874,7 +5909,8 @@ static void mvpp2_stop_dev(struct mvpp2_
+ /* Disable interrupts on all CPUs */
+ mvpp2_interrupts_disable(port);
+
+- napi_disable(&port->napi);
++ for (i = 0; i < port->nqvecs; i++)
++ napi_disable(&port->qvecs[i].napi);
+
+ netif_carrier_off(port->dev);
+ netif_tx_stop_all_queues(port->dev);
+@@ -5960,6 +5996,40 @@ static void mvpp2_phy_disconnect(struct
+ phy_disconnect(ndev->phydev);
+ }
+
++static int mvpp2_irqs_init(struct mvpp2_port *port)
++{
++ int err, i;
++
++ for (i = 0; i < port->nqvecs; i++) {
++ struct mvpp2_queue_vector *qv = port->qvecs + i;
++
++ err = request_irq(qv->irq, mvpp2_isr, 0, port->dev->name, qv);
++ if (err)
++ goto err;
++ }
++
++ return 0;
++err:
++ for (i = 0; i < port->nqvecs; i++) {
++ struct mvpp2_queue_vector *qv = port->qvecs + i;
++
++ free_irq(qv->irq, qv);
++ }
++
++ return err;
++}
++
++static void mvpp2_irqs_deinit(struct mvpp2_port *port)
++{
++ int i;
++
++ for (i = 0; i < port->nqvecs; i++) {
++ struct mvpp2_queue_vector *qv = port->qvecs + i;
++
++ free_irq(qv->irq, qv);
++ }
++}
++
+ static int mvpp2_open(struct net_device *dev)
+ {
+ struct mvpp2_port *port = netdev_priv(dev);
+@@ -6002,9 +6072,9 @@ static int mvpp2_open(struct net_device
+ goto err_cleanup_rxqs;
+ }
+
+- err = request_irq(port->irq, mvpp2_isr, 0, dev->name, port);
++ err = mvpp2_irqs_init(port);
+ if (err) {
+- netdev_err(port->dev, "cannot request IRQ %d\n", port->irq);
++ netdev_err(port->dev, "cannot init IRQs\n");
+ goto err_cleanup_txqs;
+ }
+
+@@ -6023,7 +6093,7 @@ static int mvpp2_open(struct net_device
+ return 0;
+
+ err_free_irq:
+- free_irq(port->irq, port);
++ mvpp2_irqs_deinit(port);
+ err_cleanup_txqs:
+ mvpp2_cleanup_txqs(port);
+ err_cleanup_rxqs:
+@@ -6043,7 +6113,7 @@ static int mvpp2_stop(struct net_device
+ /* Mask interrupts on all CPUs */
+ on_each_cpu(mvpp2_interrupts_mask, port, 1);
+
+- free_irq(port->irq, port);
++ mvpp2_irqs_deinit(port);
+ for_each_present_cpu(cpu) {
+ port_pcpu = per_cpu_ptr(port->pcpu, cpu);
+
+@@ -6361,6 +6431,66 @@ static const struct ethtool_ops mvpp2_et
+ .set_link_ksettings = phy_ethtool_set_link_ksettings,
+ };
+
++static int mvpp2_queue_vectors_init(struct mvpp2_port *port,
++ struct device_node *port_node)
++{
++ struct mvpp2_queue_vector *v = &port->qvecs[0];
++
++ v->first_rxq = 0;
++ v->nrxqs = port->nrxqs;
++ v->type = MVPP2_QUEUE_VECTOR_SHARED;
++ v->sw_thread_id = 0;
++ v->sw_thread_mask = *cpumask_bits(cpu_online_mask);
++ v->port = port;
++ v->irq = irq_of_parse_and_map(port_node, 0);
++ if (v->irq <= 0)
++ return -EINVAL;
++ netif_napi_add(port->dev, &v->napi, mvpp2_poll,
++ NAPI_POLL_WEIGHT);
++
++ port->nqvecs = 1;
++
++ return 0;
++}
++
++static void mvpp2_queue_vectors_deinit(struct mvpp2_port *port)
++{
++ int i;
++
++ for (i = 0; i < port->nqvecs; i++)
++ irq_dispose_mapping(port->qvecs[i].irq);
++}
++
++/* Configure Rx queue group interrupt for this port */
++static void mvpp2_rx_irqs_setup(struct mvpp2_port *port)
++{
++ struct mvpp2 *priv = port->priv;
++ u32 val;
++ int i;
++
++ if (priv->hw_version == MVPP21) {
++ mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(port->id),
++ port->nrxqs);
++ return;
++ }
++
++ /* Handle the more complicated PPv2.2 case */
++ for (i = 0; i < port->nqvecs; i++) {
++ struct mvpp2_queue_vector *qv = port->qvecs + i;
++
++ if (!qv->nrxqs)
++ continue;
++
++ val = qv->sw_thread_id;
++ val |= port->id << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET;
++ mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val);
++
++ val = qv->first_rxq;
++ val |= qv->nrxqs << MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET;
++ mvpp2_write(priv, MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val);
++ }
++}
++
+ /* Initialize port HW */
+ static int mvpp2_port_init(struct mvpp2_port *port)
+ {
+@@ -6442,19 +6572,7 @@ static int mvpp2_port_init(struct mvpp2_
+ port->rxqs[queue] = rxq;
+ }
+
+- /* Configure Rx queue group interrupt for this port */
+- if (priv->hw_version == MVPP21) {
+- mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(port->id),
+- port->nrxqs);
+- } else {
+- u32 val;
+-
+- val = (port->id << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET);
+- mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val);
+-
+- val = (port->nrxqs << MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET);
+- mvpp2_write(priv, MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val);
+- }
++ mvpp2_rx_irqs_setup(port);
+
+ /* Create Rx descriptor rings */
+ for (queue = 0; queue < port->nrxqs; queue++) {
+@@ -6545,14 +6663,13 @@ static int mvpp2_port_probe(struct platf
+ dev->ethtool_ops = &mvpp2_eth_tool_ops;
+
+ port = netdev_priv(dev);
++ port->dev = dev;
+ port->ntxqs = ntxqs;
+ port->nrxqs = nrxqs;
+
+- port->irq = irq_of_parse_and_map(port_node, 0);
+- if (port->irq <= 0) {
+- err = -EINVAL;
++ err = mvpp2_queue_vectors_init(port, port_node);
++ if (err)
+ goto err_free_netdev;
+- }
+
+ if (of_property_read_bool(port_node, "marvell,loopback"))
+ port->flags |= MVPP2_F_LOOPBACK;
+@@ -6572,14 +6689,14 @@ static int mvpp2_port_probe(struct platf
+ port->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(port->base)) {
+ err = PTR_ERR(port->base);
+- goto err_free_irq;
++ goto err_deinit_qvecs;
+ }
+ } else {
+ if (of_property_read_u32(port_node, "gop-port-id",
+ &port->gop_id)) {
+ err = -EINVAL;
+ dev_err(&pdev->dev, "missing gop-port-id value\n");
+- goto err_free_irq;
++ goto err_deinit_qvecs;
+ }
+
+ port->base = priv->iface_base + MVPP22_GMAC_BASE(port->gop_id);
+@@ -6589,7 +6706,7 @@ static int mvpp2_port_probe(struct platf
+ port->stats = netdev_alloc_pcpu_stats(struct mvpp2_pcpu_stats);
+ if (!port->stats) {
+ err = -ENOMEM;
+- goto err_free_irq;
++ goto err_deinit_qvecs;
+ }
+
+ dt_mac_addr = of_get_mac_address(port_node);
+@@ -6610,7 +6727,6 @@ static int mvpp2_port_probe(struct platf
+
+ port->tx_ring_size = MVPP2_MAX_TXD;
+ port->rx_ring_size = MVPP2_MAX_RXD;
+- port->dev = dev;
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ err = mvpp2_port_init(port);
+@@ -6645,7 +6761,6 @@ static int mvpp2_port_probe(struct platf
+ (unsigned long)dev);
+ }
+
+- netif_napi_add(dev, &port->napi, mvpp2_poll, NAPI_POLL_WEIGHT);
+ features = NETIF_F_SG | NETIF_F_IP_CSUM;
+ dev->features = features | NETIF_F_RXCSUM;
+ dev->hw_features |= features | NETIF_F_RXCSUM | NETIF_F_GRO;
+@@ -6673,8 +6788,8 @@ err_free_txq_pcpu:
+ free_percpu(port->txqs[i]->pcpu);
+ err_free_stats:
+ free_percpu(port->stats);
+-err_free_irq:
+- irq_dispose_mapping(port->irq);
++err_deinit_qvecs:
++ mvpp2_queue_vectors_deinit(port);
+ err_free_netdev:
+ of_node_put(phy_node);
+ free_netdev(dev);
+@@ -6692,7 +6807,7 @@ static void mvpp2_port_remove(struct mvp
+ free_percpu(port->stats);
+ for (i = 0; i < port->ntxqs; i++)
+ free_percpu(port->txqs[i]->pcpu);
+- irq_dispose_mapping(port->irq);
++ mvpp2_queue_vectors_deinit(port);
+ free_netdev(port->dev);
+ }
+
diff --git a/patches.drivers/net-mvpp2-jumbo-frames-support.patch b/patches.drivers/net-mvpp2-jumbo-frames-support.patch
new file mode 100644
index 0000000000..bea88b06f3
--- /dev/null
+++ b/patches.drivers/net-mvpp2-jumbo-frames-support.patch
@@ -0,0 +1,202 @@
+From: Stefan Chulski <stefanc@marvell.com>
+Date: Mon, 5 Mar 2018 15:16:54 +0100
+Subject: net: mvpp2: jumbo frames support
+Patch-mainline: v4.17-rc1
+Git-commit: 576193f2d57904cb78454d7b73eecfcac74fdf22
+References: bsc#1098633
+
+This patch adds the support for jumbo frames in the Marvell PPv2 driver.
+A third buffer pool is added with 10KB buffers, which is used if the MTU
+is higher than 1518B for packets larger than 1518B. Please note only the
+port 0 supports hardware checksum offload due to the Tx FIFO size
+limitation.
+
+Signed-off-by: Stefan Chulski <stefanc@marvell.com>
+[Antoine: cosmetic cleanup, commit message]
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 100 ++++++++++++++++++++++++++---------
+ 1 file changed, 76 insertions(+), 24 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -815,6 +815,7 @@ enum mvpp2_prs_l3_cast {
+ #define MVPP22_RSS_TABLE_ENTRIES 32
+
+ /* BM constants */
++#define MVPP2_BM_JUMBO_BUF_NUM 512
+ #define MVPP2_BM_LONG_BUF_NUM 1024
+ #define MVPP2_BM_SHORT_BUF_NUM 2048
+ #define MVPP2_BM_POOL_SIZE_MAX (16*1024 - MVPP2_BM_POOL_PTR_ALIGN/4)
+@@ -826,12 +827,14 @@ enum mvpp2_prs_l3_cast {
+
+ #define MVPP2_BM_SHORT_FRAME_SIZE 512
+ #define MVPP2_BM_LONG_FRAME_SIZE 2048
++#define MVPP2_BM_JUMBO_FRAME_SIZE 10240
+ /* BM short pool packet size
+ * These value assure that for SWF the total number
+ * of bytes allocated for each buffer will be 512
+ */
+ #define MVPP2_BM_SHORT_PKT_SIZE MVPP2_RX_MAX_PKT_SIZE(MVPP2_BM_SHORT_FRAME_SIZE)
+ #define MVPP2_BM_LONG_PKT_SIZE MVPP2_RX_MAX_PKT_SIZE(MVPP2_BM_LONG_FRAME_SIZE)
++#define MVPP2_BM_JUMBO_PKT_SIZE MVPP2_RX_MAX_PKT_SIZE(MVPP2_BM_JUMBO_FRAME_SIZE)
+
+ #define MVPP21_ADDR_SPACE_SZ 0
+ #define MVPP22_ADDR_SPACE_SZ SZ_64K
+@@ -842,6 +845,7 @@ enum mvpp2_prs_l3_cast {
+ enum mvpp2_bm_pool_log_num {
+ MVPP2_BM_SHORT,
+ MVPP2_BM_LONG,
++ MVPP2_BM_JUMBO,
+ MVPP2_BM_POOLS_NUM
+ };
+
+@@ -4393,6 +4397,10 @@ static void mvpp2_setup_bm_pool(void)
+ /* Long pool */
+ mvpp2_pools[MVPP2_BM_LONG].buf_num = MVPP2_BM_LONG_BUF_NUM;
+ mvpp2_pools[MVPP2_BM_LONG].pkt_size = MVPP2_BM_LONG_PKT_SIZE;
++
++ /* Jumbo pool */
++ mvpp2_pools[MVPP2_BM_JUMBO].buf_num = MVPP2_BM_JUMBO_BUF_NUM;
++ mvpp2_pools[MVPP2_BM_JUMBO].pkt_size = MVPP2_BM_JUMBO_PKT_SIZE;
+ }
+
+ /* Attach long pool to rxq */
+@@ -4596,15 +4604,28 @@ mvpp2_bm_pool_use(struct mvpp2_port *por
+ static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port)
+ {
+ int rxq;
++ enum mvpp2_bm_pool_log_num long_log_pool, short_log_pool;
++
++ /* If port pkt_size is higher than 1518B:
++ * HW Long pool - SW Jumbo pool, HW Short pool - SW Long pool
++ * else: HW Long pool - SW Long pool, HW Short pool - SW Short pool
++ */
++ if (port->pkt_size > MVPP2_BM_LONG_PKT_SIZE) {
++ long_log_pool = MVPP2_BM_JUMBO;
++ short_log_pool = MVPP2_BM_LONG;
++ } else {
++ long_log_pool = MVPP2_BM_LONG;
++ short_log_pool = MVPP2_BM_SHORT;
++ }
+
+ if (!port->pool_long) {
+ port->pool_long =
+- mvpp2_bm_pool_use(port, MVPP2_BM_LONG,
+- mvpp2_pools[MVPP2_BM_LONG].pkt_size);
++ mvpp2_bm_pool_use(port, long_log_pool,
++ mvpp2_pools[long_log_pool].pkt_size);
+ if (!port->pool_long)
+ return -ENOMEM;
+
+- port->pool_long->port_map |= (1 << port->id);
++ port->pool_long->port_map |= BIT(port->id);
+
+ for (rxq = 0; rxq < port->nrxqs; rxq++)
+ mvpp2_rxq_long_pool_set(port, rxq, port->pool_long->id);
+@@ -4612,12 +4633,12 @@ static int mvpp2_swf_bm_pool_init(struct
+
+ if (!port->pool_short) {
+ port->pool_short =
+- mvpp2_bm_pool_use(port, MVPP2_BM_SHORT,
+- mvpp2_pools[MVPP2_BM_SHORT].pkt_size);
++ mvpp2_bm_pool_use(port, short_log_pool,
++ mvpp2_pools[long_log_pool].pkt_size);
+ if (!port->pool_short)
+ return -ENOMEM;
+
+- port->pool_short->port_map |= (1 << port->id);
++ port->pool_short->port_map |= BIT(port->id);
+
+ for (rxq = 0; rxq < port->nrxqs; rxq++)
+ mvpp2_rxq_short_pool_set(port, rxq,
+@@ -4630,24 +4651,49 @@ static int mvpp2_swf_bm_pool_init(struct
+ static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu)
+ {
+ struct mvpp2_port *port = netdev_priv(dev);
+- struct mvpp2_bm_pool *port_pool = port->pool_long;
+- int num, pkts_num = port_pool->buf_num;
++ enum mvpp2_bm_pool_log_num new_long_pool;
++ int pkt_size = MVPP2_RX_PKT_SIZE(mtu);
++
++ /* If port MTU is higher than 1518B:
++ * HW Long pool - SW Jumbo pool, HW Short pool - SW Long pool
++ * else: HW Long pool - SW Long pool, HW Short pool - SW Short pool
++ */
++ if (pkt_size > MVPP2_BM_LONG_PKT_SIZE)
++ new_long_pool = MVPP2_BM_JUMBO;
++ else
++ new_long_pool = MVPP2_BM_LONG;
+
+- /* Update BM pool with new buffer size */
+- mvpp2_bm_bufs_free(dev->dev.parent, port->priv, port_pool,
+- port_pool->buf_num);
+- if (port_pool->buf_num) {
+- WARN(1, "cannot free all buffers in pool %d\n", port_pool->id);
+- return -EIO;
+- }
+-
+- num = mvpp2_bm_bufs_add(port, port_pool, pkts_num);
+- if (num != pkts_num) {
+- WARN(1, "pool %d: %d of %d allocated\n",
+- port_pool->id, num, pkts_num);
+- return -EIO;
++ if (new_long_pool != port->pool_long->id) {
++ /* Remove port from old short & long pool */
++ port->pool_long = mvpp2_bm_pool_use(port, port->pool_long->id,
++ port->pool_long->pkt_size);
++ port->pool_long->port_map &= ~BIT(port->id);
++ port->pool_long = NULL;
++
++ port->pool_short = mvpp2_bm_pool_use(port, port->pool_short->id,
++ port->pool_short->pkt_size);
++ port->pool_short->port_map &= ~BIT(port->id);
++ port->pool_short = NULL;
++
++ port->pkt_size = pkt_size;
++
++ /* Add port to new short & long pool */
++ mvpp2_swf_bm_pool_init(port);
++
++ /* Update L4 checksum when jumbo enable/disable on port */
++ if (new_long_pool == MVPP2_BM_JUMBO && port->id != 0) {
++ dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
++ dev->hw_features &= ~(NETIF_F_IP_CSUM |
++ NETIF_F_IPV6_CSUM);
++ } else {
++ dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
++ dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
++ }
+ }
++
+ dev->mtu = mtu;
++ dev->wanted_features = dev->features;
++
+ netdev_update_features(dev);
+ return 0;
+ }
+@@ -8326,13 +8372,19 @@ static int mvpp2_port_probe(struct platf
+ dev->features = features | NETIF_F_RXCSUM;
+ dev->hw_features |= features | NETIF_F_RXCSUM | NETIF_F_GRO |
+ NETIF_F_HW_VLAN_CTAG_FILTER;
++
++ if (port->pool_long->id == MVPP2_BM_JUMBO && port->id != 0) {
++ dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
++ dev->hw_features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
++ }
++
+ dev->vlan_features |= features;
+ dev->gso_max_segs = MVPP2_MAX_TSO_SEGS;
+
+- /* MTU range: 68 - 9676 */
++ /* MTU range: 68 - 9704 */
+ dev->min_mtu = ETH_MIN_MTU;
+- /* 9676 == 9700 - 20 and rounding to 8 */
+- dev->max_mtu = 9676;
++ /* 9704 == 9728 - 20 and rounding to 8 */
++ dev->max_mtu = MVPP2_BM_JUMBO_PKT_SIZE;
+
+ err = register_netdev(dev);
+ if (err < 0) {
diff --git a/patches.drivers/net-mvpp2-limit-TSO-segments-and-use-stop-wake-thres.patch b/patches.drivers/net-mvpp2-limit-TSO-segments-and-use-stop-wake-thres.patch
new file mode 100644
index 0000000000..3764c023aa
--- /dev/null
+++ b/patches.drivers/net-mvpp2-limit-TSO-segments-and-use-stop-wake-thres.patch
@@ -0,0 +1,83 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Mon, 30 Oct 2017 11:23:31 +0100
+Subject: net: mvpp2: limit TSO segments and use stop/wake thresholds
+Patch-mainline: v4.15-rc1
+Git-commit: 1d17db08c056c1f7f4abbff6aff8711b7c3a3b7f
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 18 ++++++++++++++++--
+ 1 file changed, 16 insertions(+), 2 deletions(-)
+
+--- 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_
+ 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_p
+ 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 @@ out:
+ 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 platf
+ 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;
diff --git a/patches.drivers/net-mvpp2-make-the-phy-optional.patch b/patches.drivers/net-mvpp2-make-the-phy-optional.patch
new file mode 100644
index 0000000000..c0c761c695
--- /dev/null
+++ b/patches.drivers/net-mvpp2-make-the-phy-optional.patch
@@ -0,0 +1,83 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Fri, 1 Sep 2017 11:04:53 +0200
+Subject: net: mvpp2: make the phy optional
+Patch-mainline: v4.14-rc1
+Git-commit: 5997c86bf0e94f0b29f9ab416b1db62a8fa4e4eb
+References: bsc#1098633
+
+There is not necessarily a PHY between the GoP and the physical port.
+However, the driver currently makes the "phy" property mandatory,
+contrary to what is stated in the device tree bindings. This patch makes
+the PHY optional, and aligns the PPv2 driver on its device tree
+documentation. However if a PHY is provided, the GoP link interrupt
+won't be used.
+
+With this patch switches directly connected to the serdes lanes and SFP
+ports on the Armada 8040-db and Armada 7040-db can be used if the link
+interrupt is described in the device tree.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Tested-by: Marcin Wojtas <mw@semihalf.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -6475,7 +6475,8 @@ static void mvpp2_start_dev(struct mvpp2
+
+ mvpp2_port_mii_set(port);
+ mvpp2_port_enable(port);
+- phy_start(ndev->phydev);
++ if (ndev->phydev)
++ phy_start(ndev->phydev);
+ netif_tx_start_all_queues(port->dev);
+ }
+
+@@ -6501,7 +6502,8 @@ static void mvpp2_stop_dev(struct mvpp2_
+
+ mvpp2_egress_disable(port);
+ mvpp2_port_disable(port);
+- phy_stop(ndev->phydev);
++ if (ndev->phydev)
++ phy_stop(ndev->phydev);
+ phy_power_off(port->comphy);
+ }
+
+@@ -6558,6 +6560,10 @@ static int mvpp2_phy_connect(struct mvpp
+ {
+ struct phy_device *phy_dev;
+
++ /* No PHY is attached */
++ if (!port->phy_node)
++ return 0;
++
+ phy_dev = of_phy_connect(port->dev, port->phy_node, mvpp2_link_event, 0,
+ port->phy_interface);
+ if (!phy_dev) {
+@@ -6578,6 +6584,9 @@ static void mvpp2_phy_disconnect(struct
+ {
+ struct net_device *ndev = port->dev;
+
++ if (!ndev->phydev)
++ return;
++
+ phy_disconnect(ndev->phydev);
+ }
+
+@@ -7340,12 +7349,6 @@ static int mvpp2_port_probe(struct platf
+ return -ENOMEM;
+
+ phy_node = of_parse_phandle(port_node, "phy", 0);
+- if (!phy_node) {
+- dev_err(&pdev->dev, "missing phy\n");
+- err = -ENODEV;
+- goto err_free_netdev;
+- }
+-
+ phy_mode = of_get_phy_mode(port_node);
+ if (phy_mode < 0) {
+ dev_err(&pdev->dev, "incorrect phy mode\n");
diff --git a/patches.drivers/net-mvpp2-move-from-cpu-centric-naming-to-software-t.patch b/patches.drivers/net-mvpp2-move-from-cpu-centric-naming-to-software-t.patch
new file mode 100644
index 0000000000..811222fecb
--- /dev/null
+++ b/patches.drivers/net-mvpp2-move-from-cpu-centric-naming-to-software-t.patch
@@ -0,0 +1,112 @@
+From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Date: Thu, 3 Aug 2017 10:41:58 +0200
+Subject: net: mvpp2: move from cpu-centric naming to "software thread" naming
+Patch-mainline: v4.14-rc1
+Git-commit: df089aa0acd75bb605e4cce72982942173e742ad
+References: bsc#1098633
+
+The PPv2.2 IP has a concept of "software thread", with all registers
+of the PPv2.2 mapped 8 times, for concurrent accesses by 8 "software
+threads". In addition, interrupts on RX queues are associated to such
+"software thread".
+
+For most cases, we map a "software thread" to the more conventional
+concept of CPU, but we will soon have one exception: we will have a
+model where we have one TX interrupt per CPU (each using one software
+thread), and all RX events mapped to another software thread
+(associated to another interrupt).
+
+In preparation for this change, it makes sense to change the naming
+from MVPP2_MAX_CPUS to MVPP2_MAX_THREADS, and plan for 8 software
+threads instead of 4 currently.
+
+Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 25 +++++++++++++------------
+ 1 file changed, 13 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -685,7 +685,7 @@ enum mvpp2_prs_l3_cast {
+ #define MVPP21_ADDR_SPACE_SZ 0
+ #define MVPP22_ADDR_SPACE_SZ SZ_64K
+
+-#define MVPP2_MAX_CPUS 4
++#define MVPP2_MAX_THREADS 8
+
+ enum mvpp2_bm_type {
+ MVPP2_BM_FREE,
+@@ -701,11 +701,12 @@ struct mvpp2 {
+ void __iomem *lms_base;
+ void __iomem *iface_base;
+
+- /* On PPv2.2, each CPU can access the base register through a
+- * separate address space, each 64 KB apart from each
+- * other.
++ /* On PPv2.2, each "software thread" can access the base
++ * register through a separate address space, each 64 KB apart
++ * from each other. Typically, such address spaces will be
++ * used per CPU.
+ */
+- void __iomem *cpu_base[MVPP2_MAX_CPUS];
++ void __iomem *swth_base[MVPP2_MAX_THREADS];
+
+ /* Common clocks */
+ struct clk *pp_clk;
+@@ -1071,12 +1072,12 @@ struct mvpp2_bm_pool {
+
+ static void mvpp2_write(struct mvpp2 *priv, u32 offset, u32 data)
+ {
+- writel(data, priv->cpu_base[0] + offset);
++ writel(data, priv->swth_base[0] + offset);
+ }
+
+ static u32 mvpp2_read(struct mvpp2 *priv, u32 offset)
+ {
+- return readl(priv->cpu_base[0] + offset);
++ return readl(priv->swth_base[0] + offset);
+ }
+
+ /* These accessors should be used to access:
+@@ -1118,13 +1119,13 @@ static u32 mvpp2_read(struct mvpp2 *priv
+ static void mvpp2_percpu_write(struct mvpp2 *priv, int cpu,
+ u32 offset, u32 data)
+ {
+- writel(data, priv->cpu_base[cpu] + offset);
++ writel(data, priv->swth_base[cpu] + offset);
+ }
+
+ static u32 mvpp2_percpu_read(struct mvpp2 *priv, int cpu,
+ u32 offset)
+ {
+- return readl(priv->cpu_base[cpu] + offset);
++ return readl(priv->swth_base[cpu] + offset);
+ }
+
+ static dma_addr_t mvpp2_txdesc_dma_addr_get(struct mvpp2_port *port,
+@@ -6874,7 +6875,7 @@ static int mvpp2_probe(struct platform_d
+ struct mvpp2 *priv;
+ struct resource *res;
+ void __iomem *base;
+- int port_count, cpu;
++ int port_count, i;
+ int err;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+@@ -6901,12 +6902,12 @@ static int mvpp2_probe(struct platform_d
+ return PTR_ERR(priv->iface_base);
+ }
+
+- for_each_present_cpu(cpu) {
++ for (i = 0; i < MVPP2_MAX_THREADS; i++) {
+ u32 addr_space_sz;
+
+ addr_space_sz = (priv->hw_version == MVPP21 ?
+ MVPP21_ADDR_SPACE_SZ : MVPP22_ADDR_SPACE_SZ);
+- priv->cpu_base[cpu] = base + cpu * addr_space_sz;
++ priv->swth_base[i] = base + i * addr_space_sz;
+ }
+
+ if (priv->hw_version == MVPP21)
diff --git a/patches.drivers/net-mvpp2-move-the-mac-retrieval-copy-logic-into-its.patch b/patches.drivers/net-mvpp2-move-the-mac-retrieval-copy-logic-into-its.patch
new file mode 100644
index 0000000000..99ef724162
--- /dev/null
+++ b/patches.drivers/net-mvpp2-move-the-mac-retrieval-copy-logic-into-its.patch
@@ -0,0 +1,86 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Sat, 2 Sep 2017 11:06:47 +0200
+Subject: net: mvpp2: move the mac retrieval/copy logic into its own function
+Patch-mainline: v4.14-rc1
+Git-commit: 3ba8c81e15c11fc396d0b5d11adaf9db6ed39533
+References: bsc#1098633
+
+The MAC retrieval has a quite complicated logic (which is broken). Moves
+it to its own function to prepare for patches fixing its logic, so that
+reviews are easier.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 45 +++++++++++++++++++++--------------
+ 1 file changed, 27 insertions(+), 18 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -7465,6 +7465,31 @@ static bool mvpp2_port_has_tx_irqs(struc
+ return true;
+ }
+
++static void mvpp2_port_copy_mac_addr(struct net_device *dev, struct mvpp2 *priv,
++ struct device_node *port_node,
++ char **mac_from)
++{
++ struct mvpp2_port *port = netdev_priv(dev);
++ char hw_mac_addr[ETH_ALEN] = {0};
++ const char *dt_mac_addr;
++
++ 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);
++ } else {
++ if (priv->hw_version == MVPP21)
++ mvpp21_get_mac_address(port, hw_mac_addr);
++ if (is_valid_ether_addr(hw_mac_addr)) {
++ *mac_from = "hardware";
++ ether_addr_copy(dev->dev_addr, hw_mac_addr);
++ } else {
++ *mac_from = "random";
++ eth_hw_addr_random(dev);
++ }
++ }
++}
++
+ /* Ports initialization */
+ static int mvpp2_port_probe(struct platform_device *pdev,
+ struct device_node *port_node,
+@@ -7476,9 +7501,7 @@ static int mvpp2_port_probe(struct platf
+ struct mvpp2_port_pcpu *port_pcpu;
+ struct net_device *dev;
+ struct resource *res;
+- const char *dt_mac_addr;
+- const char *mac_from;
+- char hw_mac_addr[ETH_ALEN] = {0};
++ char *mac_from = "";
+ unsigned int ntxqs, nrxqs;
+ bool has_tx_irqs;
+ u32 id;
+@@ -7587,21 +7610,7 @@ static int mvpp2_port_probe(struct platf
+ goto err_free_irq;
+ }
+
+- 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);
+- } else {
+- if (priv->hw_version == MVPP21)
+- mvpp21_get_mac_address(port, hw_mac_addr);
+- if (is_valid_ether_addr(hw_mac_addr)) {
+- mac_from = "hardware";
+- ether_addr_copy(dev->dev_addr, hw_mac_addr);
+- } else {
+- mac_from = "random";
+- eth_hw_addr_random(dev);
+- }
+- }
++ 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;
diff --git a/patches.drivers/net-mvpp2-move-the-mii-configuration-in-the-ndo_open.patch b/patches.drivers/net-mvpp2-move-the-mii-configuration-in-the-ndo_open.patch
new file mode 100644
index 0000000000..6d58d8ad4a
--- /dev/null
+++ b/patches.drivers/net-mvpp2-move-the-mii-configuration-in-the-ndo_open.patch
@@ -0,0 +1,37 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Tue, 22 Aug 2017 19:08:23 +0200
+Subject: net: mvpp2: move the mii configuration in the ndo_open path
+Patch-mainline: v4.14-rc1
+Git-commit: 2055d6268d755fdc3f96f1d0bbf22c6164dacfbf
+References: bsc#1098633
+
+This moves the mii configuration in the ndo_open path, to allow handling
+different mii configurations later and to switch between these
+configurations at runtime.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Tested-by: Marcin Wojtas <mw@semihalf.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -5987,6 +5987,7 @@ static void mvpp2_start_dev(struct mvpp2
+ /* Enable interrupts on all CPUs */
+ mvpp2_interrupts_enable(port);
+
++ mvpp2_port_mii_set(port);
+ mvpp2_port_enable(port);
+ phy_start(ndev->phydev);
+ netif_tx_start_all_queues(port->dev);
+@@ -6949,7 +6950,6 @@ static int mvpp2_port_probe(struct platf
+ goto err_free_stats;
+ }
+
+- mvpp2_port_mii_set(port);
+ mvpp2_port_periodic_xon_disable(port);
+
+ if (priv->hw_version == MVPP21)
diff --git a/patches.drivers/net-mvpp2-mvpp2_check_hw_buf_num-can-be-static.patch b/patches.drivers/net-mvpp2-mvpp2_check_hw_buf_num-can-be-static.patch
new file mode 100644
index 0000000000..45172e39a8
--- /dev/null
+++ b/patches.drivers/net-mvpp2-mvpp2_check_hw_buf_num-can-be-static.patch
@@ -0,0 +1,26 @@
+From: kbuild test robot <fengguang.wu@intel.com>
+Date: Tue, 6 Mar 2018 13:05:06 +0800
+Subject: net: mvpp2: mvpp2_check_hw_buf_num() can be static
+Patch-mainline: v4.17-rc1
+Git-commit: 6e61e10a8a9655424cf03c0fb44d282b40f402a2
+References: bsc#1098633
+
+Fixes: effbf5f58d64 ("net: mvpp2: update the BM buffer free/destroy logic")
+Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -4295,7 +4295,7 @@ static void mvpp2_bm_bufs_free(struct de
+ }
+
+ /* Check number of buffers in BM pool */
+-int mvpp2_check_hw_buf_num(struct mvpp2 *priv, struct mvpp2_bm_pool *bm_pool)
++static int mvpp2_check_hw_buf_num(struct mvpp2 *priv, struct mvpp2_bm_pool *bm_pool)
+ {
+ int buf_num = 0;
+
diff --git a/patches.drivers/net-mvpp2-only-free-the-TSO-header-buffers-when-it-w.patch b/patches.drivers/net-mvpp2-only-free-the-TSO-header-buffers-when-it-w.patch
new file mode 100644
index 0000000000..54ed0c6dce
--- /dev/null
+++ b/patches.drivers/net-mvpp2-only-free-the-TSO-header-buffers-when-it-w.patch
@@ -0,0 +1,45 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Mon, 11 Dec 2017 09:13:25 +0100
+Subject: net: mvpp2: only free the TSO header buffers when it was allocated
+Patch-mainline: v4.16-rc1
+Git-commit: b70d4a5195c7193d1d55af791d9811477522e25a
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+--- 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_p
+ 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 mvpp
+ 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)
diff --git a/patches.drivers/net-mvpp2-remove-RX-queue-group-reset-code.patch b/patches.drivers/net-mvpp2-remove-RX-queue-group-reset-code.patch
new file mode 100644
index 0000000000..96add387ba
--- /dev/null
+++ b/patches.drivers/net-mvpp2-remove-RX-queue-group-reset-code.patch
@@ -0,0 +1,45 @@
+From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Date: Thu, 3 Aug 2017 10:41:56 +0200
+Subject: net: mvpp2: remove RX queue group reset code
+Patch-mainline: v4.14-rc1
+Git-commit: b5635ad2e4906e8f8bd3ab145059ce413c03a7ad
+References: bsc#1098633
+
+The RX queue group allocation is anyway re-done later in
+mvpp2_port_init(), so resetting it in mvpp2_init() is not very useful,
+and will be annoying as we are going to rework the RX queue group
+allocation logic.
+
+Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 17 -----------------
+ 1 file changed, 17 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -6845,23 +6845,6 @@ static int mvpp2_init(struct platform_de
+ /* Rx Fifo Init */
+ mvpp2_rx_fifo_init(priv);
+
+- /* Reset Rx queue group interrupt configuration */
+- for (i = 0; i < MVPP2_MAX_PORTS; i++) {
+- if (priv->hw_version == MVPP21) {
+- mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(i),
+- rxq_number);
+- continue;
+- } else {
+- u32 val;
+-
+- val = (i << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET);
+- mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val);
+-
+- val = (rxq_number << MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET);
+- mvpp2_write(priv, MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val);
+- }
+- }
+-
+ if (priv->hw_version == MVPP21)
+ writel(MVPP2_EXT_GLOBAL_CTRL_DEFAULT,
+ priv->lms_base + MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG);
diff --git a/patches.drivers/net-mvpp2-remove-mvpp2_pool_refill.patch b/patches.drivers/net-mvpp2-remove-mvpp2_pool_refill.patch
new file mode 100644
index 0000000000..f5860c72d9
--- /dev/null
+++ b/patches.drivers/net-mvpp2-remove-mvpp2_pool_refill.patch
@@ -0,0 +1,62 @@
+From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Date: Thu, 22 Jun 2017 14:23:20 +0200
+Subject: net: mvpp2: remove mvpp2_pool_refill()
+Patch-mainline: v4.13-rc1
+Git-commit: 7d7627ba1cb4d1e364e7ba9c3f57947b411424e3
+References: bsc#1098633
+
+When all a function does is calling another function with the exact same
+arguments, in the exact same order, you know it's time to remove said
+function. Which is exactly what this commit does.
+
+Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 14 +++-----------
+ 1 file changed, 3 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -3953,14 +3953,6 @@ static inline void mvpp2_bm_pool_put(str
+ put_cpu();
+ }
+
+-/* Refill BM pool */
+-static void mvpp2_pool_refill(struct mvpp2_port *port, int pool,
+- dma_addr_t dma_addr,
+- phys_addr_t phys_addr)
+-{
+- mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr);
+-}
+-
+ /* Allocate buffers for the pool */
+ static int mvpp2_bm_bufs_add(struct mvpp2_port *port,
+ struct mvpp2_bm_pool *bm_pool, int buf_num)
+@@ -5015,7 +5007,7 @@ static void mvpp2_rxq_drop_pkts(struct m
+ pool = (status & MVPP2_RXD_BM_POOL_ID_MASK) >>
+ MVPP2_RXD_BM_POOL_ID_OFFS;
+
+- mvpp2_pool_refill(port, pool,
++ mvpp2_bm_pool_put(port, pool,
+ mvpp2_rxdesc_dma_addr_get(port, rx_desc),
+ mvpp2_rxdesc_cookie_get(port, rx_desc));
+ }
+@@ -5469,7 +5461,7 @@ static int mvpp2_rx_refill(struct mvpp2_
+ if (!buf)
+ return -ENOMEM;
+
+- mvpp2_pool_refill(port, pool, dma_addr, phys_addr);
++ mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr);
+
+ return 0;
+ }
+@@ -5553,7 +5545,7 @@ err_drop_frame:
+ dev->stats.rx_errors++;
+ mvpp2_rx_error(port, rx_desc);
+ /* Return the buffer to the pool */
+- mvpp2_pool_refill(port, pool, dma_addr, phys_addr);
++ mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr);
+ continue;
+ }
+
diff --git a/patches.drivers/net-mvpp2-remove-unused-mvpp2_bm_cookie_pool_set-fun.patch b/patches.drivers/net-mvpp2-remove-unused-mvpp2_bm_cookie_pool_set-fun.patch
new file mode 100644
index 0000000000..870aaa9479
--- /dev/null
+++ b/patches.drivers/net-mvpp2-remove-unused-mvpp2_bm_cookie_pool_set-fun.patch
@@ -0,0 +1,36 @@
+From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Date: Thu, 22 Jun 2017 14:23:19 +0200
+Subject: net: mvpp2: remove unused mvpp2_bm_cookie_pool_set() function
+Patch-mainline: v4.13-rc1
+Git-commit: 8f3f6e5fd19fab5708d56601e360b92076b1eb82
+References: bsc#1098633
+
+This function is not used in the driver, remove it.
+
+Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 11 -----------
+ 1 file changed, 11 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -3917,17 +3917,6 @@ static void *mvpp2_buf_alloc(struct mvpp
+ return data;
+ }
+
+-/* Set pool number in a BM cookie */
+-static inline u32 mvpp2_bm_cookie_pool_set(u32 cookie, int pool)
+-{
+- u32 bm;
+-
+- bm = cookie & ~(0xFF << MVPP2_BM_COOKIE_POOL_OFFS);
+- bm |= ((pool & 0xFF) << MVPP2_BM_COOKIE_POOL_OFFS);
+-
+- return bm;
+-}
+-
+ /* Release buffer to BM */
+ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool,
+ dma_addr_t buf_dma_addr,
diff --git a/patches.drivers/net-mvpp2-remove-useless-goto.patch b/patches.drivers/net-mvpp2-remove-useless-goto.patch
new file mode 100644
index 0000000000..d492771a7f
--- /dev/null
+++ b/patches.drivers/net-mvpp2-remove-useless-goto.patch
@@ -0,0 +1,27 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Mon, 18 Sep 2017 15:36:51 +0200
+Subject: net: mvpp2: remove useless goto
+Patch-mainline: v4.15-rc1
+Git-commit: 38c5eb93aca9dc1b21a2c96d583ce7f9886a44e6
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- 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,
+ if (mvpp2_tx_frag_process(port, skb, aggr_txq, txq)) {
+ tx_desc_unmap_put(port, txq, tx_desc);
+ frags = 0;
+- goto out;
+ }
+ }
+
diff --git a/patches.drivers/net-mvpp2-report-the-tx-usec-coalescing-information-.patch b/patches.drivers/net-mvpp2-report-the-tx-usec-coalescing-information-.patch
new file mode 100644
index 0000000000..3574e45038
--- /dev/null
+++ b/patches.drivers/net-mvpp2-report-the-tx-usec-coalescing-information-.patch
@@ -0,0 +1,28 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Mon, 11 Dec 2017 09:13:28 +0100
+Subject: net: mvpp2: report the tx-usec coalescing information to ethtool
+Patch-mainline: v4.16-rc1
+Git-commit: 24b28ccb8575481672a9f037c423f7ebcea119b9
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -7327,6 +7327,7 @@ static int mvpp2_ethtool_get_coalesce(st
+ 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;
+ }
+
diff --git a/patches.drivers/net-mvpp2-set-maximum-packet-size-for-10G-ports.patch b/patches.drivers/net-mvpp2-set-maximum-packet-size-for-10G-ports.patch
new file mode 100644
index 0000000000..2fd65b4837
--- /dev/null
+++ b/patches.drivers/net-mvpp2-set-maximum-packet-size-for-10G-ports.patch
@@ -0,0 +1,66 @@
+From: Stefan Chulski <stefanc@marvell.com>
+Date: Tue, 22 Aug 2017 19:08:26 +0200
+Subject: net: mvpp2: set maximum packet size for 10G ports
+Patch-mainline: v4.14-rc1
+Git-commit: 76eb1b1de5b6467c78bb72311dbf29eea1f10a3a
+References: bsc#1098633
+
+Set maximum packet size for XLG 10G ports. Missing maximum packet size
+for XLG configuration will cause kernel panic if oversized packet is
+received by port.
+
+Signed-off-by: Stefan Chulski <stefanc@marvell.com>
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 24 ++++++++++++++++++++++--
+ 1 file changed, 22 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -363,7 +363,9 @@
+ #define MVPP22_XLG_CTRL0_MAC_RESET_DIS BIT(1)
+ #define MVPP22_XLG_CTRL0_RX_FLOW_CTRL_EN BIT(7)
+ #define MVPP22_XLG_CTRL0_MIB_CNT_DIS BIT(14)
+-
++#define MVPP22_XLG_CTRL1_REG 0x104
++#define MVPP22_XLG_CTRL1_FRAMESIZELIMIT BIT(0)
++#define MVPP22_XLG_CTRL1_FRAMESIZELIMIT_MASK 0x1fff
+ #define MVPP22_XLG_CTRL3_REG 0x11c
+ #define MVPP22_XLG_CTRL3_MACMODESELECT_MASK (7 << 13)
+ #define MVPP22_XLG_CTRL3_MACMODESELECT_GMAC (0 << 13)
+@@ -4498,6 +4500,18 @@ static inline void mvpp2_gmac_max_rx_siz
+ writel(val, port->base + MVPP2_GMAC_CTRL_0_REG);
+ }
+
++/* Change maximum receive size of the port */
++static inline void mvpp2_xlg_max_rx_size_set(struct mvpp2_port *port)
++{
++ u32 val;
++
++ val = readl(port->base + MVPP22_XLG_CTRL1_REG);
++ val &= ~MVPP22_XLG_CTRL1_FRAMESIZELIMIT_MASK;
++ val |= ((port->pkt_size - MVPP2_MH_SIZE) / 2) <<
++ MVPP22_XLG_CTRL1_FRAMESIZELIMIT;
++ writel(val, port->base + MVPP22_XLG_CTRL1_REG);
++}
++
+ /* Set defaults to the MVPP2 port */
+ static void mvpp2_defaults_set(struct mvpp2_port *port)
+ {
+@@ -6076,7 +6090,13 @@ static void mvpp2_start_dev(struct mvpp2
+ struct net_device *ndev = port->dev;
+ int i;
+
+- mvpp2_gmac_max_rx_size_set(port);
++ if (port->gop_id == 0 &&
++ (port->phy_interface == PHY_INTERFACE_MODE_XAUI ||
++ port->phy_interface == PHY_INTERFACE_MODE_10GKR))
++ mvpp2_xlg_max_rx_size_set(port);
++ else
++ mvpp2_gmac_max_rx_size_set(port);
++
+ mvpp2_txp_max_tx_size_set(port);
+
+ for (i = 0; i < port->nqvecs; i++)
diff --git a/patches.drivers/net-mvpp2-set-the-Rx-FIFO-size-depending-on-the-port.patch b/patches.drivers/net-mvpp2-set-the-Rx-FIFO-size-depending-on-the-port.patch
new file mode 100644
index 0000000000..52b90d3b9b
--- /dev/null
+++ b/patches.drivers/net-mvpp2-set-the-Rx-FIFO-size-depending-on-the-port.patch
@@ -0,0 +1,95 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Mon, 30 Oct 2017 11:23:28 +0100
+Subject: net: mvpp2: set the Rx FIFO size depending on the port speeds for
+ PPv2.2
+Patch-mainline: v4.15-rc1
+Git-commit: 2d1d7df8a3652697da7f7929791d555e6c5981c2
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 52 ++++++++++++++++++++++++++++++-----
+ 1 file changed, 46 insertions(+), 6 deletions(-)
+
+--- 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 mv
+
+ 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_de
+ }
+
+ /* 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,
diff --git a/patches.drivers/net-mvpp2-simplify-maintaining-enabled-ports-list.patch b/patches.drivers/net-mvpp2-simplify-maintaining-enabled-ports-list.patch
new file mode 100644
index 0000000000..50a5ad3cfd
--- /dev/null
+++ b/patches.drivers/net-mvpp2-simplify-maintaining-enabled-ports-list.patch
@@ -0,0 +1,90 @@
+From: Marcin Wojtas <mw@semihalf.com>
+Date: Thu, 18 Jan 2018 13:31:42 +0100
+Subject: net: mvpp2: simplify maintaining enabled ports' list
+Patch-mainline: v4.16-rc1
+Git-commit: bf147153d7f4b0d7337b28040837d9272c1a99fe
+References: bsc#1098633
+
+'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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 32 +++++++++++---------------------
+ 1 file changed, 11 insertions(+), 21 deletions(-)
+
+--- 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(str
+ /* 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 platf
+ }
+ 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_d
+ 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
diff --git a/patches.drivers/net-mvpp2-simplify-the-Tx-desc-set-DMA-logic.patch b/patches.drivers/net-mvpp2-simplify-the-Tx-desc-set-DMA-logic.patch
new file mode 100644
index 0000000000..c56468403d
--- /dev/null
+++ b/patches.drivers/net-mvpp2-simplify-the-Tx-desc-set-DMA-logic.patch
@@ -0,0 +1,112 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Mon, 30 Oct 2017 11:23:33 +0100
+Subject: net: mvpp2: simplify the Tx desc set DMA logic
+Patch-mainline: v4.15-rc1
+Git-commit: 6eb5d375cefcbd60ebb4251b150ea95d47140fe0
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 39 +++++++++++------------------------
+ 1 file changed, 13 insertions(+), 26 deletions(-)
+
+--- 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(st
+ 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
+ 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
+ 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(str
+
+ 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(str
+ 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,
+ 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);
+
diff --git a/patches.drivers/net-mvpp2-simplify-the-link_event-function.patch b/patches.drivers/net-mvpp2-simplify-the-link_event-function.patch
new file mode 100644
index 0000000000..bc43cf680a
--- /dev/null
+++ b/patches.drivers/net-mvpp2-simplify-the-link_event-function.patch
@@ -0,0 +1,58 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Wed, 30 Aug 2017 10:29:16 +0200
+Subject: net: mvpp2: simplify the link_event function
+Patch-mainline: v4.14-rc1
+Git-commit: 968b211c620b567a4d2183beb0516cbd2c73560a
+References: bsc#1098633
+
+The link_event function is somewhat complicated. This cosmetic patch
+simplifies it.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 13 ++++---------
+ 1 file changed, 4 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -5740,7 +5740,6 @@ static void mvpp2_link_event(struct net_
+ {
+ struct mvpp2_port *port = netdev_priv(dev);
+ struct phy_device *phydev = dev->phydev;
+- int status_change = 0;
+ u32 val;
+
+ if (phydev->link) {
+@@ -5771,16 +5770,8 @@ static void mvpp2_link_event(struct net_
+ }
+
+ if (phydev->link != port->link) {
+- if (!phydev->link) {
+- port->duplex = -1;
+- port->speed = 0;
+- }
+-
+ port->link = phydev->link;
+- status_change = 1;
+- }
+
+- if (status_change) {
+ if (phydev->link) {
+ val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
+ val |= (MVPP2_GMAC_FORCE_LINK_PASS |
+@@ -5789,9 +5780,13 @@ static void mvpp2_link_event(struct net_
+ mvpp2_egress_enable(port);
+ mvpp2_ingress_enable(port);
+ } else {
++ port->duplex = -1;
++ port->speed = 0;
++
+ mvpp2_ingress_disable(port);
+ mvpp2_egress_disable(port);
+ }
++
+ phy_print_status(phydev);
+ }
+ }
diff --git a/patches.drivers/net-mvpp2-software-tso-support.patch b/patches.drivers/net-mvpp2-software-tso-support.patch
new file mode 100644
index 0000000000..68a5767dfd
--- /dev/null
+++ b/patches.drivers/net-mvpp2-software-tso-support.patch
@@ -0,0 +1,260 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Wed, 23 Aug 2017 09:46:56 +0200
+Subject: net: mvpp2: software tso support
+Patch-mainline: v4.14-rc1
+Git-commit: 186cd4d4e4144803652212eb0b7413141469feee
+References: bsc#1098633
+
+The patch uses the tso API to implement the tso functionality in Marvell
+PPv2 driver.
+
+Using iperf and 10G ports, using TSO shows a significant performance
+improvement by a factor 2 to reach around 9.5Gbps in TX; as well as a
+significant CPU usage drop (from 25% to 15%).
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 171 ++++++++++++++++++++++++++++++++---
+ 1 file changed, 157 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -35,6 +35,7 @@
+ #include <uapi/linux/ppp_defs.h>
+ #include <net/ip.h>
+ #include <net/ipv6.h>
++#include <net/tso.h>
+
+ /* RX Fifo Registers */
+ #define MVPP2_RX_DATA_FIFO_SIZE_REG(port) (0x00 + 4 * (port))
+@@ -1010,6 +1011,10 @@ struct mvpp2_txq_pcpu {
+
+ /* Index of the TX DMA descriptor to be cleaned up */
+ int txq_get_index;
++
++ /* DMA buffer for TSO headers */
++ char *tso_headers;
++ dma_addr_t tso_headers_dma;
+ };
+
+ struct mvpp2_tx_queue {
+@@ -5494,6 +5499,14 @@ static int mvpp2_txq_init(struct mvpp2_p
+ txq_pcpu->reserved_num = 0;
+ txq_pcpu->txq_put_index = 0;
+ txq_pcpu->txq_get_index = 0;
++
++ txq_pcpu->tso_headers =
++ dma_alloc_coherent(port->dev->dev.parent,
++ MVPP2_AGGR_TXQ_SIZE * TSO_HEADER_SIZE,
++ &txq_pcpu->tso_headers_dma,
++ GFP_KERNEL);
++ if (!txq_pcpu->tso_headers)
++ goto cleanup;
+ }
+
+ return 0;
+@@ -5501,6 +5514,11 @@ 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,
++ MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE,
++ txq_pcpu->tso_headers,
++ txq_pcpu->tso_headers_dma);
+ }
+
+ dma_free_coherent(port->dev->dev.parent,
+@@ -5520,6 +5538,11 @@ static void mvpp2_txq_deinit(struct mvpp
+ for_each_present_cpu(cpu) {
+ txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
+ kfree(txq_pcpu->buffs);
++
++ dma_free_coherent(port->dev->dev.parent,
++ MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE,
++ txq_pcpu->tso_headers,
++ txq_pcpu->tso_headers_dma);
+ }
+
+ if (txq->descs)
+@@ -6049,6 +6072,123 @@ cleanup:
+ return -ENOMEM;
+ }
+
++static inline void mvpp2_tso_put_hdr(struct sk_buff *skb,
++ struct net_device *dev,
++ struct mvpp2_tx_queue *txq,
++ struct mvpp2_tx_queue *aggr_txq,
++ struct mvpp2_txq_pcpu *txq_pcpu,
++ int hdr_sz)
++{
++ struct mvpp2_port *port = netdev_priv(dev);
++ struct mvpp2_tx_desc *tx_desc = mvpp2_txq_next_desc_get(aggr_txq);
++ dma_addr_t addr;
++
++ mvpp2_txdesc_txq_set(port, tx_desc, txq->id);
++ mvpp2_txdesc_size_set(port, tx_desc, hdr_sz);
++
++ 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_cmd_set(port, tx_desc, mvpp2_skb_tx_csum(port, skb) |
++ MVPP2_TXD_F_DESC |
++ MVPP2_TXD_PADDING_DISABLE);
++ mvpp2_txq_inc_put(port, txq_pcpu, NULL, tx_desc);
++}
++
++static inline int mvpp2_tso_put_data(struct sk_buff *skb,
++ struct net_device *dev, struct tso_t *tso,
++ struct mvpp2_tx_queue *txq,
++ struct mvpp2_tx_queue *aggr_txq,
++ struct mvpp2_txq_pcpu *txq_pcpu,
++ int sz, bool left, bool last)
++{
++ struct mvpp2_port *port = netdev_priv(dev);
++ struct mvpp2_tx_desc *tx_desc = mvpp2_txq_next_desc_get(aggr_txq);
++ dma_addr_t buf_dma_addr;
++
++ mvpp2_txdesc_txq_set(port, tx_desc, txq->id);
++ mvpp2_txdesc_size_set(port, tx_desc, sz);
++
++ buf_dma_addr = dma_map_single(dev->dev.parent, tso->data, sz,
++ DMA_TO_DEVICE);
++ if (unlikely(dma_mapping_error(dev->dev.parent, buf_dma_addr))) {
++ mvpp2_txq_desc_put(txq);
++ 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);
++
++ if (!left) {
++ mvpp2_txdesc_cmd_set(port, tx_desc, MVPP2_TXD_L_DESC);
++ if (last) {
++ mvpp2_txq_inc_put(port, txq_pcpu, skb, tx_desc);
++ return 0;
++ }
++ } else {
++ mvpp2_txdesc_cmd_set(port, tx_desc, 0);
++ }
++
++ mvpp2_txq_inc_put(port, txq_pcpu, NULL, tx_desc);
++ return 0;
++}
++
++static int mvpp2_tx_tso(struct sk_buff *skb, struct net_device *dev,
++ struct mvpp2_tx_queue *txq,
++ struct mvpp2_tx_queue *aggr_txq,
++ struct mvpp2_txq_pcpu *txq_pcpu)
++{
++ struct mvpp2_port *port = netdev_priv(dev);
++ struct tso_t tso;
++ int hdr_sz = skb_transport_offset(skb) + tcp_hdrlen(skb);
++ int i, len, descs = 0;
++
++ /* Check number of available descriptors */
++ if (mvpp2_aggr_desc_num_check(port->priv, aggr_txq,
++ tso_count_descs(skb)) ||
++ mvpp2_txq_reserved_desc_num_proc(port->priv, txq, txq_pcpu,
++ tso_count_descs(skb)))
++ return 0;
++
++ tso_start(skb, &tso);
++ len = skb->len - hdr_sz;
++ while (len > 0) {
++ int left = min_t(int, skb_shinfo(skb)->gso_size, len);
++ char *hdr = txq_pcpu->tso_headers +
++ txq_pcpu->txq_put_index * TSO_HEADER_SIZE;
++
++ len -= left;
++ descs++;
++
++ tso_build_hdr(skb, hdr, &tso, left, len == 0);
++ mvpp2_tso_put_hdr(skb, dev, txq, aggr_txq, txq_pcpu, hdr_sz);
++
++ while (left > 0) {
++ int sz = min_t(int, tso.size, left);
++ left -= sz;
++ descs++;
++
++ if (mvpp2_tso_put_data(skb, dev, &tso, txq, aggr_txq,
++ txq_pcpu, sz, left, len == 0))
++ goto release;
++ tso_build_data(skb, &tso, sz);
++ }
++ }
++
++ return descs;
++
++release:
++ for (i = descs - 1; i >= 0; i--) {
++ struct mvpp2_tx_desc *tx_desc = txq->descs + i;
++ tx_desc_unmap_put(port, txq, tx_desc);
++ }
++ return 0;
++}
++
+ /* Main tx processing */
+ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev)
+ {
+@@ -6066,6 +6206,10 @@ static int mvpp2_tx(struct sk_buff *skb,
+ txq_pcpu = this_cpu_ptr(txq->pcpu);
+ aggr_txq = &port->priv->aggr_txqs[smp_processor_id()];
+
++ if (skb_is_gso(skb)) {
++ frags = mvpp2_tx_tso(skb, dev, txq, aggr_txq, txq_pcpu);
++ goto out;
++ }
+ frags = skb_shinfo(skb)->nr_frags + 1;
+
+ /* Check number of available descriptors */
+@@ -6115,22 +6259,21 @@ static int mvpp2_tx(struct sk_buff *skb,
+ }
+ }
+
+- txq_pcpu->reserved_num -= frags;
+- txq_pcpu->count += frags;
+- aggr_txq->count += frags;
+-
+- /* Enable transmit */
+- wmb();
+- mvpp2_aggr_txq_pend_desc_add(port, frags);
+-
+- if (txq_pcpu->size - txq_pcpu->count < MAX_SKB_FRAGS + 1) {
+- struct netdev_queue *nq = netdev_get_tx_queue(dev, txq_id);
+-
+- netif_tx_stop_queue(nq);
+- }
+ out:
+ if (frags > 0) {
+ struct mvpp2_pcpu_stats *stats = this_cpu_ptr(port->stats);
++ struct netdev_queue *nq = netdev_get_tx_queue(dev, txq_id);
++
++ txq_pcpu->reserved_num -= frags;
++ txq_pcpu->count += frags;
++ aggr_txq->count += frags;
++
++ /* Enable transmit */
++ wmb();
++ mvpp2_aggr_txq_pend_desc_add(port, frags);
++
++ if (txq_pcpu->size - txq_pcpu->count < MAX_SKB_FRAGS + 1)
++ netif_tx_stop_queue(nq);
+
+ u64_stats_update_begin(&stats->syncp);
+ stats->tx_packets++;
+@@ -7255,7 +7398,7 @@ static int mvpp2_port_probe(struct platf
+ }
+ }
+
+- features = NETIF_F_SG | NETIF_F_IP_CSUM;
++ features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
+ dev->features = features | NETIF_F_RXCSUM;
+ dev->hw_features |= features | NETIF_F_RXCSUM | NETIF_F_GRO;
+ dev->vlan_features |= features;
diff --git a/patches.drivers/net-mvpp2-split-the-max-ring-size-from-the-default-o.patch b/patches.drivers/net-mvpp2-split-the-max-ring-size-from-the-default-o.patch
new file mode 100644
index 0000000000..c52c3869eb
--- /dev/null
+++ b/patches.drivers/net-mvpp2-split-the-max-ring-size-from-the-default-o.patch
@@ -0,0 +1,86 @@
+From: Yan Markman <ymarkman@marvell.com>
+Date: Mon, 11 Dec 2017 09:13:26 +0100
+Subject: net: mvpp2: split the max ring size from the default one
+Patch-mainline: v4.16-rc1
+Git-commit: 7cf87e4a5c2b120967b3fa3a1beb7123eb704d85
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 24 +++++++++++++-----------
+ 1 file changed, 13 insertions(+), 11 deletions(-)
+
+--- 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(s
+ 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 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 platf
+ 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 platf
+
+ 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);
diff --git a/patches.drivers/net-mvpp2-take-advantage-of-the-is_rgmii-helper.patch b/patches.drivers/net-mvpp2-take-advantage-of-the-is_rgmii-helper.patch
new file mode 100644
index 0000000000..c656ba45b9
--- /dev/null
+++ b/patches.drivers/net-mvpp2-take-advantage-of-the-is_rgmii-helper.patch
@@ -0,0 +1,56 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Fri, 1 Sep 2017 11:04:52 +0200
+Subject: net: mvpp2: take advantage of the is_rgmii helper
+Patch-mainline: v4.14-rc1
+Git-commit: 1df2270d06fa65c3479e713eb00eca25896db653
+References: bsc#1098633
+
+Convert all RGMII checks to use the phy_interface_mode_is_rgmii()
+helper. This is a cosmetic patch.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 15 +++------------
+ 1 file changed, 3 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -4463,10 +4463,7 @@ static void mvpp2_port_mii_gmac_configur
+ val |= MVPP2_GMAC_DISABLE_PADDING;
+ val &= ~MVPP2_GMAC_FLOW_CTRL_MASK;
+ writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
+- } else if (port->phy_interface == PHY_INTERFACE_MODE_RGMII ||
+- port->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
+- port->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID ||
+- port->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) {
++ } 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 |
+ MVPP22_CTRL4_SYNC_BYPASS_DIS |
+@@ -4512,10 +4509,7 @@ static void mvpp2_port_mii_gmac_configur
+ val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
+ if (port->phy_interface == PHY_INTERFACE_MODE_SGMII) {
+ val |= MVPP2_GMAC_INBAND_AN_MASK | MVPP2_GMAC_PCS_ENABLE_MASK;
+- } else if (port->phy_interface == PHY_INTERFACE_MODE_RGMII ||
+- port->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
+- port->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID ||
+- port->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) {
++ } else if (phy_interface_mode_is_rgmii(port->phy_interface)) {
+ val &= ~MVPP2_GMAC_PCS_ENABLE_MASK;
+ val |= MVPP2_GMAC_PORT_RGMII_MASK;
+ }
+@@ -4575,10 +4569,7 @@ static void mvpp2_port_mii_set(struct mv
+ if (port->priv->hw_version == MVPP22)
+ mvpp22_port_mii_set(port);
+
+- if (port->phy_interface == PHY_INTERFACE_MODE_RGMII ||
+- port->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
+- port->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID ||
+- port->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID ||
++ if (phy_interface_mode_is_rgmii(port->phy_interface) ||
+ port->phy_interface == PHY_INTERFACE_MODE_SGMII)
+ mvpp2_port_mii_gmac_configure(port);
+ else if (port->phy_interface == PHY_INTERFACE_MODE_10GKR)
diff --git a/patches.drivers/net-mvpp2-unify-register-definitions-coding-style.patch b/patches.drivers/net-mvpp2-unify-register-definitions-coding-style.patch
new file mode 100644
index 0000000000..38be03f647
--- /dev/null
+++ b/patches.drivers/net-mvpp2-unify-register-definitions-coding-style.patch
@@ -0,0 +1,149 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Tue, 22 Aug 2017 19:08:21 +0200
+Subject: net: mvpp2: unify register definitions coding style
+Patch-mainline: v4.14-rc1
+Git-commit: 81b6630ff7210356fe1843572543c76674e90450
+References: bsc#1098633
+
+Cosmetic patch to use the same formatting rules on all register
+definitions.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Tested-by: Marcin Wojtas <mw@semihalf.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 88 +++++++++++++++++------------------
+ 1 file changed, 44 insertions(+), 44 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -193,18 +193,18 @@
+ #define MVPP2_MAX_ISR_RX_THRESHOLD 0xfffff0
+ #define MVPP21_ISR_RXQ_GROUP_REG(port) (0x5400 + 4 * (port))
+
+-#define MVPP22_ISR_RXQ_GROUP_INDEX_REG 0x5400
++#define MVPP22_ISR_RXQ_GROUP_INDEX_REG 0x5400
+ #define MVPP22_ISR_RXQ_GROUP_INDEX_SUBGROUP_MASK 0xf
+-#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_MASK 0x380
+-#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET 7
++#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_MASK 0x380
++#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET 7
+
+ #define MVPP22_ISR_RXQ_GROUP_INDEX_SUBGROUP_MASK 0xf
+-#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_MASK 0x380
++#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_MASK 0x380
+
+-#define MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG 0x5404
+-#define MVPP22_ISR_RXQ_SUB_GROUP_STARTQ_MASK 0x1f
+-#define MVPP22_ISR_RXQ_SUB_GROUP_SIZE_MASK 0xf00
+-#define MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET 8
++#define MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG 0x5404
++#define MVPP22_ISR_RXQ_SUB_GROUP_STARTQ_MASK 0x1f
++#define MVPP22_ISR_RXQ_SUB_GROUP_SIZE_MASK 0xf00
++#define MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET 8
+
+ #define MVPP2_ISR_ENABLE_REG(port) (0x5420 + 4 * (port))
+ #define MVPP2_ISR_ENABLE_INTERRUPT(mask) ((mask) & 0xffff)
+@@ -272,7 +272,7 @@
+ #define MVPP2_BM_VIRT_RLS_REG 0x64c0
+ #define MVPP22_BM_ADDR_HIGH_RLS_REG 0x64c4
+ #define MVPP22_BM_ADDR_HIGH_PHYS_RLS_MASK 0xff
+-#define MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK 0xff00
++#define MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK 0xff00
+ #define MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT 8
+
+ /* TX Scheduler registers */
+@@ -314,57 +314,57 @@
+
+ /* Per-port registers */
+ #define MVPP2_GMAC_CTRL_0_REG 0x0
+-#define MVPP2_GMAC_PORT_EN_MASK BIT(0)
+-#define MVPP2_GMAC_MAX_RX_SIZE_OFFS 2
+-#define MVPP2_GMAC_MAX_RX_SIZE_MASK 0x7ffc
+-#define MVPP2_GMAC_MIB_CNTR_EN_MASK BIT(15)
++#define MVPP2_GMAC_PORT_EN_MASK BIT(0)
++#define MVPP2_GMAC_MAX_RX_SIZE_OFFS 2
++#define MVPP2_GMAC_MAX_RX_SIZE_MASK 0x7ffc
++#define MVPP2_GMAC_MIB_CNTR_EN_MASK BIT(15)
+ #define MVPP2_GMAC_CTRL_1_REG 0x4
+-#define MVPP2_GMAC_PERIODIC_XON_EN_MASK BIT(1)
+-#define MVPP2_GMAC_GMII_LB_EN_MASK BIT(5)
+-#define MVPP2_GMAC_PCS_LB_EN_BIT 6
+-#define MVPP2_GMAC_PCS_LB_EN_MASK BIT(6)
+-#define MVPP2_GMAC_SA_LOW_OFFS 7
++#define MVPP2_GMAC_PERIODIC_XON_EN_MASK BIT(1)
++#define MVPP2_GMAC_GMII_LB_EN_MASK BIT(5)
++#define MVPP2_GMAC_PCS_LB_EN_BIT 6
++#define MVPP2_GMAC_PCS_LB_EN_MASK BIT(6)
++#define MVPP2_GMAC_SA_LOW_OFFS 7
+ #define MVPP2_GMAC_CTRL_2_REG 0x8
+-#define MVPP2_GMAC_INBAND_AN_MASK BIT(0)
+-#define MVPP2_GMAC_PCS_ENABLE_MASK BIT(3)
+-#define MVPP2_GMAC_PORT_RGMII_MASK BIT(4)
+-#define MVPP2_GMAC_PORT_RESET_MASK BIT(6)
++#define MVPP2_GMAC_INBAND_AN_MASK BIT(0)
++#define MVPP2_GMAC_PCS_ENABLE_MASK BIT(3)
++#define MVPP2_GMAC_PORT_RGMII_MASK BIT(4)
++#define MVPP2_GMAC_PORT_RESET_MASK BIT(6)
+ #define MVPP2_GMAC_AUTONEG_CONFIG 0xc
+-#define MVPP2_GMAC_FORCE_LINK_DOWN BIT(0)
+-#define MVPP2_GMAC_FORCE_LINK_PASS BIT(1)
+-#define MVPP2_GMAC_CONFIG_MII_SPEED BIT(5)
+-#define MVPP2_GMAC_CONFIG_GMII_SPEED BIT(6)
+-#define MVPP2_GMAC_AN_SPEED_EN BIT(7)
+-#define MVPP2_GMAC_FC_ADV_EN BIT(9)
+-#define MVPP2_GMAC_CONFIG_FULL_DUPLEX BIT(12)
+-#define MVPP2_GMAC_AN_DUPLEX_EN BIT(13)
++#define MVPP2_GMAC_FORCE_LINK_DOWN BIT(0)
++#define MVPP2_GMAC_FORCE_LINK_PASS BIT(1)
++#define MVPP2_GMAC_CONFIG_MII_SPEED BIT(5)
++#define MVPP2_GMAC_CONFIG_GMII_SPEED BIT(6)
++#define MVPP2_GMAC_AN_SPEED_EN BIT(7)
++#define MVPP2_GMAC_FC_ADV_EN BIT(9)
++#define MVPP2_GMAC_CONFIG_FULL_DUPLEX BIT(12)
++#define MVPP2_GMAC_AN_DUPLEX_EN BIT(13)
+ #define MVPP2_GMAC_PORT_FIFO_CFG_1_REG 0x1c
+-#define MVPP2_GMAC_TX_FIFO_MIN_TH_OFFS 6
+-#define MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK 0x1fc0
+-#define MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(v) (((v) << 6) & \
++#define MVPP2_GMAC_TX_FIFO_MIN_TH_OFFS 6
++#define MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK 0x1fc0
++#define MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(v) (((v) << 6) & \
+ MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK)
+ #define MVPP22_GMAC_CTRL_4_REG 0x90
+-#define MVPP22_CTRL4_EXT_PIN_GMII_SEL BIT(0)
+-#define MVPP22_CTRL4_DP_CLK_SEL BIT(5)
+-#define MVPP22_CTRL4_SYNC_BYPASS BIT(6)
+-#define MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE BIT(7)
++#define MVPP22_CTRL4_EXT_PIN_GMII_SEL BIT(0)
++#define MVPP22_CTRL4_DP_CLK_SEL BIT(5)
++#define MVPP22_CTRL4_SYNC_BYPASS BIT(6)
++#define MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE BIT(7)
+
+ /* Per-port XGMAC registers. PPv2.2 only, only for GOP port 0,
+ * relative to port->base.
+ */
+ #define MVPP22_XLG_CTRL0_REG 0x100
+-#define MVPP22_XLG_CTRL0_PORT_EN BIT(0)
+-#define MVPP22_XLG_CTRL0_MAC_RESET_DIS BIT(1)
+-#define MVPP22_XLG_CTRL0_MIB_CNT_DIS BIT(14)
++#define MVPP22_XLG_CTRL0_PORT_EN BIT(0)
++#define MVPP22_XLG_CTRL0_MAC_RESET_DIS BIT(1)
++#define MVPP22_XLG_CTRL0_MIB_CNT_DIS BIT(14)
+
+ #define MVPP22_XLG_CTRL3_REG 0x11c
+-#define MVPP22_XLG_CTRL3_MACMODESELECT_MASK (7 << 13)
+-#define MVPP22_XLG_CTRL3_MACMODESELECT_GMAC (0 << 13)
+-#define MVPP22_XLG_CTRL3_MACMODESELECT_10G (1 << 13)
++#define MVPP22_XLG_CTRL3_MACMODESELECT_MASK (7 << 13)
++#define MVPP22_XLG_CTRL3_MACMODESELECT_GMAC (0 << 13)
++#define MVPP22_XLG_CTRL3_MACMODESELECT_10G (1 << 13)
+
+ /* SMI registers. PPv2.2 only, relative to priv->iface_base. */
+ #define MVPP22_SMI_MISC_CFG_REG 0x1204
+-#define MVPP22_SMI_POLLING_EN BIT(10)
++#define MVPP22_SMI_POLLING_EN BIT(10)
+
+ #define MVPP22_GMAC_BASE(port) (0x7000 + (port) * 0x1000 + 0xe00)
+
diff --git a/patches.drivers/net-mvpp2-unify-the-txq-size-define-use.patch b/patches.drivers/net-mvpp2-unify-the-txq-size-define-use.patch
new file mode 100644
index 0000000000..c60372ec9b
--- /dev/null
+++ b/patches.drivers/net-mvpp2-unify-the-txq-size-define-use.patch
@@ -0,0 +1,58 @@
+From: =?UTF-8?q?Antoine=20T=C3=A9nart?= <antoine.tenart@free-electrons.com>
+Date: Wed, 23 Aug 2017 09:46:55 +0200
+Subject: net: mvpp2: unify the txq size define use
+Patch-mainline: v4.14-rc1
+Git-commit: 85affd7e29e78dbf39f6b1e3a3ddf8432168e231
+References: bsc#1098633
+
+The txq size is defined by MVPP2_AGGR_TXQ_SIZE, which is sometime not
+used directly but through variables. As it is a fixed value use the
+define everywhere in the driver.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -5284,15 +5284,14 @@ static unsigned int mvpp2_tx_done(struct
+
+ /* Allocate and initialize descriptors for aggr TXQ */
+ static int mvpp2_aggr_txq_init(struct platform_device *pdev,
+- struct mvpp2_tx_queue *aggr_txq,
+- int desc_num, int cpu,
++ struct mvpp2_tx_queue *aggr_txq, int cpu,
+ struct mvpp2 *priv)
+ {
+ u32 txq_dma;
+
+ /* Allocate memory for TX descriptors */
+ aggr_txq->descs = dma_alloc_coherent(&pdev->dev,
+- desc_num * MVPP2_DESC_ALIGNED_SIZE,
++ MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE,
+ &aggr_txq->descs_dma, GFP_KERNEL);
+ if (!aggr_txq->descs)
+ return -ENOMEM;
+@@ -5313,7 +5312,8 @@ static int mvpp2_aggr_txq_init(struct pl
+ MVPP22_AGGR_TXQ_DESC_ADDR_OFFS;
+
+ mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu), txq_dma);
+- mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_SIZE_REG(cpu), desc_num);
++ mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_SIZE_REG(cpu),
++ MVPP2_AGGR_TXQ_SIZE);
+
+ return 0;
+ }
+@@ -7445,8 +7445,7 @@ static int mvpp2_init(struct platform_de
+ for_each_present_cpu(i) {
+ priv->aggr_txqs[i].id = i;
+ priv->aggr_txqs[i].size = MVPP2_AGGR_TXQ_SIZE;
+- err = mvpp2_aggr_txq_init(pdev, &priv->aggr_txqs[i],
+- MVPP2_AGGR_TXQ_SIZE, i, priv);
++ err = mvpp2_aggr_txq_init(pdev, &priv->aggr_txqs[i], i, priv);
+ if (err < 0)
+ return err;
+ }
diff --git a/patches.drivers/net-mvpp2-update-the-BM-buffer-free-destroy-logic.patch b/patches.drivers/net-mvpp2-update-the-BM-buffer-free-destroy-logic.patch
new file mode 100644
index 0000000000..9d34ea6cb0
--- /dev/null
+++ b/patches.drivers/net-mvpp2-update-the-BM-buffer-free-destroy-logic.patch
@@ -0,0 +1,113 @@
+From: Stefan Chulski <stefanc@marvell.com>
+Date: Mon, 5 Mar 2018 15:16:51 +0100
+Subject: net: mvpp2: update the BM buffer free/destroy logic
+Patch-mainline: v4.17-rc1
+Git-commit: effbf5f58d64b1d1f93cb687d9797b42f291d5fd
+References: bsc#1098633
+
+The buffer free routine is updated to release only given a number of
+buffers, and the destroy routine now checks the actual number of buffers
+in the (BPPI and BPPE) HW counters before draining the pools. This
+change helps getting jumbo frames support.
+
+Signed-off-by: Stefan Chulski <stefanc@marvell.com>
+[Antoine: cosmetic cleanup, commit message]
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 45 +++++++++++++++++++++++++++++------
+ 1 file changed, 38 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -258,6 +258,7 @@
+ #define MVPP2_BM_BPPI_READ_PTR_REG(pool) (0x6100 + ((pool) * 4))
+ #define MVPP2_BM_BPPI_PTRS_NUM_REG(pool) (0x6140 + ((pool) * 4))
+ #define MVPP2_BM_BPPI_PTR_NUM_MASK 0x7ff
++#define MVPP22_BM_POOL_PTRS_NUM_MASK 0xfff8
+ #define MVPP2_BM_BPPI_PREFETCH_FULL_MASK BIT(16)
+ #define MVPP2_BM_POOL_CTRL_REG(pool) (0x6200 + ((pool) * 4))
+ #define MVPP2_BM_START_MASK BIT(0)
+@@ -4251,11 +4252,17 @@ static void mvpp2_bm_bufs_get_addrs(stru
+
+ /* Free all buffers from the pool */
+ static void mvpp2_bm_bufs_free(struct device *dev, struct mvpp2 *priv,
+- struct mvpp2_bm_pool *bm_pool)
++ struct mvpp2_bm_pool *bm_pool, int buf_num)
+ {
+ int i;
+
+- for (i = 0; i < bm_pool->buf_num; i++) {
++ if (buf_num > bm_pool->buf_num) {
++ WARN(1, "Pool does not have so many bufs pool(%d) bufs(%d)\n",
++ bm_pool->id, buf_num);
++ buf_num = bm_pool->buf_num;
++ }
++
++ for (i = 0; i < buf_num; i++) {
+ dma_addr_t buf_dma_addr;
+ phys_addr_t buf_phys_addr;
+ void *data;
+@@ -4277,16 +4284,39 @@ static void mvpp2_bm_bufs_free(struct de
+ bm_pool->buf_num -= i;
+ }
+
++/* Check number of buffers in BM pool */
++int mvpp2_check_hw_buf_num(struct mvpp2 *priv, struct mvpp2_bm_pool *bm_pool)
++{
++ int buf_num = 0;
++
++ buf_num += mvpp2_read(priv, MVPP2_BM_POOL_PTRS_NUM_REG(bm_pool->id)) &
++ MVPP22_BM_POOL_PTRS_NUM_MASK;
++ buf_num += mvpp2_read(priv, MVPP2_BM_BPPI_PTRS_NUM_REG(bm_pool->id)) &
++ MVPP2_BM_BPPI_PTR_NUM_MASK;
++
++ /* HW has one buffer ready which is not reflected in the counters */
++ if (buf_num)
++ buf_num += 1;
++
++ return buf_num;
++}
++
+ /* Cleanup pool */
+ static int mvpp2_bm_pool_destroy(struct platform_device *pdev,
+ struct mvpp2 *priv,
+ struct mvpp2_bm_pool *bm_pool)
+ {
++ int buf_num;
+ u32 val;
+
+- mvpp2_bm_bufs_free(&pdev->dev, priv, bm_pool);
+- if (bm_pool->buf_num) {
+- WARN(1, "cannot free all buffers in pool %d\n", bm_pool->id);
++ buf_num = mvpp2_check_hw_buf_num(priv, bm_pool);
++ mvpp2_bm_bufs_free(&pdev->dev, priv, bm_pool, buf_num);
++
++ /* Check buffer counters after free */
++ buf_num = mvpp2_check_hw_buf_num(priv, bm_pool);
++ if (buf_num) {
++ WARN(1, "cannot free all buffers in pool %d, buf_num left %d\n",
++ bm_pool->id, bm_pool->buf_num);
+ return 0;
+ }
+
+@@ -4534,7 +4564,7 @@ mvpp2_bm_pool_use(struct mvpp2_port *por
+ pkts_num = mvpp2_pools[pool].buf_num;
+ else
+ mvpp2_bm_bufs_free(port->dev->dev.parent,
+- port->priv, new_pool);
++ port->priv, new_pool, pkts_num);
+
+ new_pool->pkt_size = pkt_size;
+ new_pool->frag_size =
+@@ -4598,7 +4628,8 @@ static int mvpp2_bm_update_mtu(struct ne
+ int num, pkts_num = port_pool->buf_num;
+
+ /* Update BM pool with new buffer size */
+- mvpp2_bm_bufs_free(dev->dev.parent, port->priv, port_pool);
++ mvpp2_bm_bufs_free(dev->dev.parent, port->priv, port_pool,
++ port_pool->buf_num);
+ if (port_pool->buf_num) {
+ WARN(1, "cannot free all buffers in pool %d\n", port_pool->id);
+ return -EIO;
diff --git a/patches.drivers/net-mvpp2-use-a-data-size-of-10kB-for-Tx-FIFO-on-por.patch b/patches.drivers/net-mvpp2-use-a-data-size-of-10kB-for-Tx-FIFO-on-por.patch
new file mode 100644
index 0000000000..a6a77750cd
--- /dev/null
+++ b/patches.drivers/net-mvpp2-use-a-data-size-of-10kB-for-Tx-FIFO-on-por.patch
@@ -0,0 +1,74 @@
+From: Yan Markman <ymarkman@marvell.com>
+Date: Mon, 5 Mar 2018 15:16:52 +0100
+Subject: net: mvpp2: use a data size of 10kB for Tx FIFO on port 0
+Patch-mainline: v4.17-rc1
+Git-commit: 93ff130f1c2bae00c0378f065e441e988b0cd1e7
+References: bsc#1098633
+
+This patch sets the Tx FIFO data size on port 0 to 10kB. This prepares
+the PPv2 driver for the Jumbo frame support addition as the hardware
+will need big enough Tx FIFO buffers when dealing with frames going
+through an interface with an MTU of 9000.
+
+Signed-off-by: Yan Markman <ymarkman@marvell.com>
+[Antoine: commit message, small reworks.]
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 27 ++++++++++++++++++++++-----
+ 1 file changed, 22 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -44,6 +44,7 @@
+ #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_THRESH_REG(port) (0x8840 + 4 * (port))
+ #define MVPP22_TX_FIFO_SIZE_REG(port) (0x8860 + 4 * (port))
+
+ /* RX DMA Top Registers */
+@@ -542,6 +543,11 @@
+ /* TX FIFO constants */
+ #define MVPP22_TX_FIFO_DATA_SIZE_10KB 0xa
+ #define MVPP22_TX_FIFO_DATA_SIZE_3KB 0x3
++#define MVPP2_TX_FIFO_THRESHOLD_MIN 256
++#define MVPP2_TX_FIFO_THRESHOLD_10KB \
++ (MVPP22_TX_FIFO_DATA_SIZE_10KB * 1024 - MVPP2_TX_FIFO_THRESHOLD_MIN)
++#define MVPP2_TX_FIFO_THRESHOLD_3KB \
++ (MVPP22_TX_FIFO_DATA_SIZE_3KB * 1024 - MVPP2_TX_FIFO_THRESHOLD_MIN)
+
+ /* RX buffer constants */
+ #define MVPP2_SKB_SHINFO_SIZE \
+@@ -8456,14 +8462,25 @@ static void mvpp22_rx_fifo_init(struct m
+ mvpp2_write(priv, MVPP2_RX_FIFO_INIT_REG, 0x1);
+ }
+
+-/* Initialize Tx FIFO's */
++/* Initialize Tx FIFO's: the total FIFO size is 19kB on PPv2.2 and 10G
++ * interfaces must have a Tx FIFO size of 10kB. As only port 0 can do 10G,
++ * configure its Tx FIFO size to 10kB and the others ports Tx FIFO size to 3kB.
++ */
+ static void mvpp22_tx_fifo_init(struct mvpp2 *priv)
+ {
+- int port;
++ int port, size, thrs;
+
+- for (port = 0; port < MVPP2_MAX_PORTS; port++)
+- mvpp2_write(priv, MVPP22_TX_FIFO_SIZE_REG(port),
+- MVPP22_TX_FIFO_DATA_SIZE_3KB);
++ for (port = 0; port < MVPP2_MAX_PORTS; port++) {
++ if (port == 0) {
++ size = MVPP22_TX_FIFO_DATA_SIZE_10KB;
++ thrs = MVPP2_TX_FIFO_THRESHOLD_10KB;
++ } else {
++ size = MVPP22_TX_FIFO_DATA_SIZE_3KB;
++ thrs = MVPP2_TX_FIFO_THRESHOLD_3KB;
++ }
++ mvpp2_write(priv, MVPP22_TX_FIFO_SIZE_REG(port), size);
++ mvpp2_write(priv, MVPP22_TX_FIFO_THRESH_REG(port), thrs);
++ }
+ }
+
+ static void mvpp2_axi_init(struct mvpp2 *priv)
diff --git a/patches.drivers/net-mvpp2-use-correct-index-on-array-mvpp2_pools.patch b/patches.drivers/net-mvpp2-use-correct-index-on-array-mvpp2_pools.patch
new file mode 100644
index 0000000000..ee41d1060e
--- /dev/null
+++ b/patches.drivers/net-mvpp2-use-correct-index-on-array-mvpp2_pools.patch
@@ -0,0 +1,32 @@
+From: Colin Ian King <colin.king@canonical.com>
+Date: Wed, 21 Mar 2018 17:31:15 +0000
+Subject: net: mvpp2: use correct index on array mvpp2_pools
+Patch-mainline: v4.17-rc1
+Git-commit: e2e031640b3a9482b137b68193b7d59b8308185c
+References: bsc#1098633
+
+Array mvpp2_pools is being indexed by long_log_pool, however this
+looks like a cut-n-paste bug and in fact should be short_log_pool.
+
+Detected by CoverityScan, CID#1466113 ("Copy-paste error")
+
+Fixes: 576193f2d579 ("net: mvpp2: jumbo frames support")
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+Acked-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -4632,7 +4632,7 @@ static int mvpp2_swf_bm_pool_init(struct
+ if (!port->pool_short) {
+ port->pool_short =
+ mvpp2_bm_pool_use(port, short_log_pool,
+- mvpp2_pools[long_log_pool].pkt_size);
++ mvpp2_pools[short_log_pool].pkt_size);
+ if (!port->pool_short)
+ return -ENOMEM;
+
diff --git a/patches.drivers/net-mvpp2-use-device_-fwnode_-APIs-instead-of-of_.patch b/patches.drivers/net-mvpp2-use-device_-fwnode_-APIs-instead-of-of_.patch
new file mode 100644
index 0000000000..d72e625922
--- /dev/null
+++ b/patches.drivers/net-mvpp2-use-device_-fwnode_-APIs-instead-of-of_.patch
@@ -0,0 +1,169 @@
+From: Marcin Wojtas <mw@semihalf.com>
+Date: Thu, 18 Jan 2018 13:31:43 +0100
+Subject: net: mvpp2: use device_*/fwnode_* APIs instead of of_*
+Patch-mainline: v4.16-rc1
+Git-commit: 248122212f68dcf13433ec56bb03ddc799259026
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 45 ++++++++++++++++++-----------------
+ 1 file changed, 24 insertions(+), 21 deletions(-)
+
+--- 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(struc
+ }
+
+ 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(str
+
+ /* 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 platf
+ 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 platf
+ 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 platf
+ /* 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 platf
+ 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 platf
+ 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_de
+
+ 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_d
+ }
+
+ /* 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_d
+
+ 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 @@ err_pp_clk:
+ 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]);
diff --git a/patches.drivers/net-mvpp2-use-the-GoP-interrupt-for-link-status-chan.patch b/patches.drivers/net-mvpp2-use-the-GoP-interrupt-for-link-status-chan.patch
new file mode 100644
index 0000000000..ac94b5e873
--- /dev/null
+++ b/patches.drivers/net-mvpp2-use-the-GoP-interrupt-for-link-status-chan.patch
@@ -0,0 +1,331 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Fri, 1 Sep 2017 11:04:54 +0200
+Subject: net: mvpp2: use the GoP interrupt for link status changes
+Patch-mainline: v4.14-rc1
+Git-commit: fd3651b2ab66de177ad0d51c239af260a764b9f1
+References: bsc#1098633
+
+This patch adds the GoP link interrupt support for when a port isn't
+connected to a PHY. Because of this the phylib callback is never called
+and the link status management isn't done. This patch use the GoP link
+interrupt in such cases to still have a minimal link management. Without
+this patch ports not connected to a PHY cannot work.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
+Tested-by: Marcin Wojtas <mw@semihalf.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 177 ++++++++++++++++++++++++++++++++++-
+ 1 file changed, 172 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -348,16 +348,24 @@
+ #define MVPP2_GMAC_FLOW_CTRL_AUTONEG BIT(11)
+ #define MVPP2_GMAC_CONFIG_FULL_DUPLEX BIT(12)
+ #define MVPP2_GMAC_AN_DUPLEX_EN BIT(13)
++#define MVPP2_GMAC_STATUS0 0x10
++#define MVPP2_GMAC_STATUS0_LINK_UP BIT(0)
+ #define MVPP2_GMAC_PORT_FIFO_CFG_1_REG 0x1c
+ #define MVPP2_GMAC_TX_FIFO_MIN_TH_OFFS 6
+ #define MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK 0x1fc0
+ #define MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(v) (((v) << 6) & \
+ MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK)
++#define MVPP22_GMAC_INT_STAT 0x20
++#define MVPP22_GMAC_INT_STAT_LINK BIT(1)
++#define MVPP22_GMAC_INT_MASK 0x24
++#define MVPP22_GMAC_INT_MASK_LINK_STAT BIT(1)
+ #define MVPP22_GMAC_CTRL_4_REG 0x90
+ #define MVPP22_CTRL4_EXT_PIN_GMII_SEL BIT(0)
+ #define MVPP22_CTRL4_DP_CLK_SEL BIT(5)
+ #define MVPP22_CTRL4_SYNC_BYPASS_DIS BIT(6)
+ #define MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE BIT(7)
++#define MVPP22_GMAC_INT_SUM_MASK 0xa4
++#define MVPP22_GMAC_INT_SUM_MASK_LINK_STAT BIT(1)
+
+ /* Per-port XGMAC registers. PPv2.2 only, only for GOP port 0,
+ * relative to port->base.
+@@ -370,11 +378,19 @@
+ #define MVPP22_XLG_CTRL1_REG 0x104
+ #define MVPP22_XLG_CTRL1_FRAMESIZELIMIT_OFFS 0
+ #define MVPP22_XLG_CTRL1_FRAMESIZELIMIT_MASK 0x1fff
++#define MVPP22_XLG_STATUS 0x10c
++#define MVPP22_XLG_STATUS_LINK_UP BIT(0)
++#define MVPP22_XLG_INT_STAT 0x114
++#define MVPP22_XLG_INT_STAT_LINK BIT(1)
++#define MVPP22_XLG_INT_MASK 0x118
++#define MVPP22_XLG_INT_MASK_LINK BIT(1)
+ #define MVPP22_XLG_CTRL3_REG 0x11c
+ #define MVPP22_XLG_CTRL3_MACMODESELECT_MASK (7 << 13)
+ #define MVPP22_XLG_CTRL3_MACMODESELECT_GMAC (0 << 13)
+ #define MVPP22_XLG_CTRL3_MACMODESELECT_10G (1 << 13)
+-
++#define MVPP22_XLG_EXT_INT_MASK 0x15c
++#define MVPP22_XLG_EXT_INT_MASK_XLG BIT(1)
++#define MVPP22_XLG_EXT_INT_MASK_GIG BIT(2)
+ #define MVPP22_XLG_CTRL4_REG 0x184
+ #define MVPP22_XLG_CTRL4_FWD_FC BIT(5)
+ #define MVPP22_XLG_CTRL4_FWD_PFC BIT(6)
+@@ -837,6 +853,8 @@ struct mvpp2_port {
+ */
+ int gop_id;
+
++ int link_irq;
++
+ struct mvpp2 *priv;
+
+ /* Per-port registers' base address */
+@@ -4422,6 +4440,68 @@ invalid_conf:
+ return -EINVAL;
+ }
+
++static void mvpp22_gop_unmask_irq(struct mvpp2_port *port)
++{
++ u32 val;
++
++ if (phy_interface_mode_is_rgmii(port->phy_interface) ||
++ port->phy_interface == PHY_INTERFACE_MODE_SGMII) {
++ /* Enable the GMAC link status irq for this port */
++ val = readl(port->base + MVPP22_GMAC_INT_SUM_MASK);
++ val |= MVPP22_GMAC_INT_SUM_MASK_LINK_STAT;
++ writel(val, port->base + MVPP22_GMAC_INT_SUM_MASK);
++ }
++
++ if (port->gop_id == 0) {
++ /* Enable the XLG/GIG irqs for this port */
++ val = readl(port->base + MVPP22_XLG_EXT_INT_MASK);
++ if (port->phy_interface == PHY_INTERFACE_MODE_10GKR)
++ val |= MVPP22_XLG_EXT_INT_MASK_XLG;
++ else
++ val |= MVPP22_XLG_EXT_INT_MASK_GIG;
++ writel(val, port->base + MVPP22_XLG_EXT_INT_MASK);
++ }
++}
++
++static void mvpp22_gop_mask_irq(struct mvpp2_port *port)
++{
++ u32 val;
++
++ if (port->gop_id == 0) {
++ val = readl(port->base + MVPP22_XLG_EXT_INT_MASK);
++ val &= ~(MVPP22_XLG_EXT_INT_MASK_XLG |
++ MVPP22_XLG_EXT_INT_MASK_GIG);
++ writel(val, port->base + MVPP22_XLG_EXT_INT_MASK);
++ }
++
++ if (phy_interface_mode_is_rgmii(port->phy_interface) ||
++ port->phy_interface == PHY_INTERFACE_MODE_SGMII) {
++ val = readl(port->base + MVPP22_GMAC_INT_SUM_MASK);
++ val &= ~MVPP22_GMAC_INT_SUM_MASK_LINK_STAT;
++ writel(val, port->base + MVPP22_GMAC_INT_SUM_MASK);
++ }
++}
++
++static void mvpp22_gop_setup_irq(struct mvpp2_port *port)
++{
++ u32 val;
++
++ if (phy_interface_mode_is_rgmii(port->phy_interface) ||
++ port->phy_interface == PHY_INTERFACE_MODE_SGMII) {
++ val = readl(port->base + MVPP22_GMAC_INT_MASK);
++ val |= MVPP22_GMAC_INT_MASK_LINK_STAT;
++ writel(val, port->base + MVPP22_GMAC_INT_MASK);
++ }
++
++ if (port->gop_id == 0) {
++ val = readl(port->base + MVPP22_XLG_INT_MASK);
++ val |= MVPP22_XLG_INT_MASK_LINK;
++ writel(val, port->base + MVPP22_XLG_INT_MASK);
++ }
++
++ mvpp22_gop_unmask_irq(port);
++}
++
+ static int mvpp22_comphy_init(struct mvpp2_port *port)
+ {
+ enum phy_mode mode;
+@@ -5726,6 +5806,60 @@ static irqreturn_t mvpp2_isr(int irq, vo
+ return IRQ_HANDLED;
+ }
+
++/* Per-port interrupt for link status changes */
++static irqreturn_t mvpp2_link_status_isr(int irq, void *dev_id)
++{
++ struct mvpp2_port *port = (struct mvpp2_port *)dev_id;
++ struct net_device *dev = port->dev;
++ bool event = false, link = false;
++ u32 val;
++
++ mvpp22_gop_mask_irq(port);
++
++ if (port->gop_id == 0 &&
++ port->phy_interface == PHY_INTERFACE_MODE_10GKR) {
++ val = readl(port->base + MVPP22_XLG_INT_STAT);
++ if (val & MVPP22_XLG_INT_STAT_LINK) {
++ event = true;
++ val = readl(port->base + MVPP22_XLG_STATUS);
++ if (val & MVPP22_XLG_STATUS_LINK_UP)
++ link = true;
++ }
++ } else if (phy_interface_mode_is_rgmii(port->phy_interface) ||
++ port->phy_interface == PHY_INTERFACE_MODE_SGMII) {
++ val = readl(port->base + MVPP22_GMAC_INT_STAT);
++ if (val & MVPP22_GMAC_INT_STAT_LINK) {
++ event = true;
++ val = readl(port->base + MVPP2_GMAC_STATUS0);
++ if (val & MVPP2_GMAC_STATUS0_LINK_UP)
++ link = true;
++ }
++ }
++
++ if (!netif_running(dev) || !event)
++ goto handled;
++
++ if (link) {
++ mvpp2_interrupts_enable(port);
++
++ mvpp2_egress_enable(port);
++ mvpp2_ingress_enable(port);
++ netif_carrier_on(dev);
++ netif_tx_wake_all_queues(dev);
++ } else {
++ netif_tx_stop_all_queues(dev);
++ netif_carrier_off(dev);
++ mvpp2_ingress_disable(port);
++ mvpp2_egress_disable(port);
++
++ mvpp2_interrupts_disable(port);
++ }
++
++handled:
++ mvpp22_gop_unmask_irq(port);
++ return IRQ_HANDLED;
++}
++
+ static void mvpp2_gmac_set_autoneg(struct mvpp2_port *port,
+ struct phy_device *phydev)
+ {
+@@ -5754,7 +5888,6 @@ static void mvpp2_gmac_set_autoneg(struc
+ val |= MVPP2_GMAC_CONFIG_MII_SPEED;
+
+ writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
+-
+ }
+
+ /* Adjust link */
+@@ -6633,6 +6766,7 @@ static void mvpp2_irqs_deinit(struct mvp
+ static int mvpp2_open(struct net_device *dev)
+ {
+ struct mvpp2_port *port = netdev_priv(dev);
++ struct mvpp2 *priv = port->priv;
+ unsigned char mac_bcast[ETH_ALEN] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ int err;
+@@ -6678,12 +6812,24 @@ static int mvpp2_open(struct net_device
+ goto err_cleanup_txqs;
+ }
+
++ if (priv->hw_version == MVPP22 && !port->phy_node && port->link_irq) {
++ err = request_irq(port->link_irq, mvpp2_link_status_isr, 0,
++ dev->name, port);
++ if (err) {
++ netdev_err(port->dev, "cannot request link IRQ %d\n",
++ port->link_irq);
++ goto err_free_irq;
++ }
++
++ mvpp22_gop_setup_irq(port);
++ }
++
+ /* In default link is down */
+ netif_carrier_off(port->dev);
+
+ err = mvpp2_phy_connect(port);
+ if (err < 0)
+- goto err_free_irq;
++ goto err_free_link_irq;
+
+ /* Unmask interrupts on all CPUs */
+ on_each_cpu(mvpp2_interrupts_unmask, port, 1);
+@@ -6693,6 +6839,9 @@ static int mvpp2_open(struct net_device
+
+ return 0;
+
++err_free_link_irq:
++ if (priv->hw_version == MVPP22 && !port->phy_node && port->link_irq)
++ free_irq(port->link_irq, port);
+ err_free_irq:
+ mvpp2_irqs_deinit(port);
+ err_cleanup_txqs:
+@@ -6706,6 +6855,7 @@ static int mvpp2_stop(struct net_device
+ {
+ struct mvpp2_port *port = netdev_priv(dev);
+ struct mvpp2_port_pcpu *port_pcpu;
++ struct mvpp2 *priv = port->priv;
+ int cpu;
+
+ mvpp2_stop_dev(port);
+@@ -6715,6 +6865,9 @@ static int mvpp2_stop(struct net_device
+ on_each_cpu(mvpp2_interrupts_mask, port, 1);
+ mvpp2_shared_interrupt_mask_unmask(port, true);
+
++ if (priv->hw_version == MVPP22 && !port->phy_node && port->link_irq)
++ free_irq(port->link_irq, port);
++
+ mvpp2_irqs_deinit(port);
+ if (!port->has_tx_irqs) {
+ for_each_present_cpu(cpu) {
+@@ -7387,6 +7540,15 @@ static int mvpp2_port_probe(struct platf
+ if (err)
+ goto err_free_netdev;
+
++ port->link_irq = of_irq_get_byname(port_node, "link");
++ if (port->link_irq == -EPROBE_DEFER) {
++ err = -EPROBE_DEFER;
++ goto err_deinit_qvecs;
++ }
++ if (port->link_irq <= 0)
++ /* the link irq is optional */
++ port->link_irq = 0;
++
+ if (of_property_read_bool(port_node, "marvell,loopback"))
+ port->flags |= MVPP2_F_LOOPBACK;
+
+@@ -7405,7 +7567,7 @@ static int mvpp2_port_probe(struct platf
+ port->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(port->base)) {
+ err = PTR_ERR(port->base);
+- goto err_deinit_qvecs;
++ goto err_free_irq;
+ }
+ } else {
+ if (of_property_read_u32(port_node, "gop-port-id",
+@@ -7422,7 +7584,7 @@ static int mvpp2_port_probe(struct platf
+ port->stats = netdev_alloc_pcpu_stats(struct mvpp2_pcpu_stats);
+ if (!port->stats) {
+ err = -ENOMEM;
+- goto err_deinit_qvecs;
++ goto err_free_irq;
+ }
+
+ dt_mac_addr = of_get_mac_address(port_node);
+@@ -7506,6 +7668,9 @@ err_free_txq_pcpu:
+ free_percpu(port->txqs[i]->pcpu);
+ err_free_stats:
+ free_percpu(port->stats);
++err_free_irq:
++ if (port->link_irq)
++ irq_dispose_mapping(port->link_irq);
+ err_deinit_qvecs:
+ mvpp2_queue_vectors_deinit(port);
+ err_free_netdev:
+@@ -7526,6 +7691,8 @@ static void mvpp2_port_remove(struct mvp
+ for (i = 0; i < port->ntxqs; i++)
+ free_percpu(port->txqs[i]->pcpu);
+ mvpp2_queue_vectors_deinit(port);
++ if (port->link_irq)
++ irq_dispose_mapping(port->link_irq);
+ free_netdev(port->dev);
+ }
+
diff --git a/patches.drivers/net-mvpp2-use-the-aggr-txq-size-define-everywhere.patch b/patches.drivers/net-mvpp2-use-the-aggr-txq-size-define-everywhere.patch
new file mode 100644
index 0000000000..8a603fd076
--- /dev/null
+++ b/patches.drivers/net-mvpp2-use-the-aggr-txq-size-define-everywhere.patch
@@ -0,0 +1,47 @@
+From: Antoine Tenart <antoine.tenart@free-electrons.com>
+Date: Mon, 30 Oct 2017 11:23:32 +0100
+Subject: net: mvpp2: use the aggr txq size define everywhere
+Patch-mainline: v4.15-rc1
+Git-commit: 02856a3ba6333c536f13d27cc847fcb442a23d9b
+References: bsc#1098633
+
+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>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- 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
+ 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(str
+ 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 pl
+ 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,
diff --git a/patches.drivers/net-mvpp2-use-the-same-buffer-pool-for-all-ports.patch b/patches.drivers/net-mvpp2-use-the-same-buffer-pool-for-all-ports.patch
new file mode 100644
index 0000000000..284d56ad6f
--- /dev/null
+++ b/patches.drivers/net-mvpp2-use-the-same-buffer-pool-for-all-ports.patch
@@ -0,0 +1,223 @@
+From: Stefan Chulski <stefanc@marvell.com>
+Date: Mon, 5 Mar 2018 15:16:50 +0100
+Subject: net: mvpp2: use the same buffer pool for all ports
+Patch-mainline: v4.17-rc1
+Git-commit: 01d049366529544f1df44139f5ca225d4c36ec31
+References: bsc#1098633
+
+This patch configures the buffer manager long pool for all ports part of
+the same CP. Long pool separation between ports is redundant since there
+are no performance improvement when different pools are used.
+
+Signed-off-by: Stefan Chulski <stefanc@marvell.com>
+[Antoine: cosmetic cleanup, commit message]
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/net/ethernet/marvell/mvpp2.c | 76 +++++++++++++++++------------------
+ 1 file changed, 37 insertions(+), 39 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2.c
++++ b/drivers/net/ethernet/marvell/mvpp2.c
+@@ -808,23 +808,23 @@ enum mvpp2_prs_l3_cast {
+ #define MVPP22_RSS_TABLE_ENTRIES 32
+
+ /* BM constants */
+-#define MVPP2_BM_POOLS_NUM 8
+ #define MVPP2_BM_LONG_BUF_NUM 1024
+ #define MVPP2_BM_SHORT_BUF_NUM 2048
+ #define MVPP2_BM_POOL_SIZE_MAX (16*1024 - MVPP2_BM_POOL_PTR_ALIGN/4)
+ #define MVPP2_BM_POOL_PTR_ALIGN 128
+-#define MVPP2_BM_SWF_LONG_POOL(port) ((port > 2) ? 2 : port)
+-#define MVPP2_BM_SWF_SHORT_POOL 3
+
+ /* BM cookie (32 bits) definition */
+ #define MVPP2_BM_COOKIE_POOL_OFFS 8
+ #define MVPP2_BM_COOKIE_CPU_OFFS 24
+
++#define MVPP2_BM_SHORT_FRAME_SIZE 512
++#define MVPP2_BM_LONG_FRAME_SIZE 2048
+ /* BM short pool packet size
+ * These value assure that for SWF the total number
+ * of bytes allocated for each buffer will be 512
+ */
+-#define MVPP2_BM_SHORT_PKT_SIZE MVPP2_RX_MAX_PKT_SIZE(512)
++#define MVPP2_BM_SHORT_PKT_SIZE MVPP2_RX_MAX_PKT_SIZE(MVPP2_BM_SHORT_FRAME_SIZE)
++#define MVPP2_BM_LONG_PKT_SIZE MVPP2_RX_MAX_PKT_SIZE(MVPP2_BM_LONG_FRAME_SIZE)
+
+ #define MVPP21_ADDR_SPACE_SZ 0
+ #define MVPP22_ADDR_SPACE_SZ SZ_64K
+@@ -832,12 +832,17 @@ enum mvpp2_prs_l3_cast {
+ #define MVPP2_MAX_THREADS 8
+ #define MVPP2_MAX_QVECS MVPP2_MAX_THREADS
+
+-enum mvpp2_bm_type {
+- MVPP2_BM_FREE,
+- MVPP2_BM_SWF_LONG,
+- MVPP2_BM_SWF_SHORT
++enum mvpp2_bm_pool_log_num {
++ MVPP2_BM_SHORT,
++ MVPP2_BM_LONG,
++ MVPP2_BM_POOLS_NUM
+ };
+
++static struct {
++ int pkt_size;
++ int buf_num;
++} mvpp2_pools[MVPP2_BM_POOLS_NUM];
++
+ /* GMAC MIB Counters register definitions */
+ #define MVPP21_MIB_COUNTERS_OFFSET 0x1000
+ #define MVPP21_MIB_COUNTERS_PORT_SZ 0x400
+@@ -1266,7 +1271,6 @@ struct mvpp2_cls_lookup_entry {
+ struct mvpp2_bm_pool {
+ /* Pool number in the range 0-7 */
+ int id;
+- enum mvpp2_bm_type type;
+
+ /* Buffer Pointers Pool External (BPPE) size */
+ int size;
+@@ -4195,7 +4199,6 @@ static int mvpp2_bm_pool_create(struct p
+ val |= MVPP2_BM_START_MASK;
+ mvpp2_write(priv, MVPP2_BM_POOL_CTRL_REG(bm_pool->id), val);
+
+- bm_pool->type = MVPP2_BM_FREE;
+ bm_pool->size = size;
+ bm_pool->pkt_size = 0;
+ bm_pool->buf_num = 0;
+@@ -4345,6 +4348,17 @@ static int mvpp2_bm_init(struct platform
+ return 0;
+ }
+
++static void mvpp2_setup_bm_pool(void)
++{
++ /* Short pool */
++ mvpp2_pools[MVPP2_BM_SHORT].buf_num = MVPP2_BM_SHORT_BUF_NUM;
++ mvpp2_pools[MVPP2_BM_SHORT].pkt_size = MVPP2_BM_SHORT_PKT_SIZE;
++
++ /* Long pool */
++ mvpp2_pools[MVPP2_BM_LONG].buf_num = MVPP2_BM_LONG_BUF_NUM;
++ mvpp2_pools[MVPP2_BM_LONG].pkt_size = MVPP2_BM_LONG_PKT_SIZE;
++}
++
+ /* Attach long pool to rxq */
+ static void mvpp2_rxq_long_pool_set(struct mvpp2_port *port,
+ int lrxq, int long_pool)
+@@ -4483,13 +4497,11 @@ static int mvpp2_bm_bufs_add(struct mvpp
+ bm_pool->buf_num += i;
+
+ netdev_dbg(port->dev,
+- "%s pool %d: pkt_size=%4d, buf_size=%4d, total_size=%4d\n",
+- bm_pool->type == MVPP2_BM_SWF_SHORT ? "short" : " long",
++ "pool %d: pkt_size=%4d, buf_size=%4d, total_size=%4d\n",
+ bm_pool->id, bm_pool->pkt_size, buf_size, total_size);
+
+ netdev_dbg(port->dev,
+- "%s pool %d: %d of %d buffers added\n",
+- bm_pool->type == MVPP2_BM_SWF_SHORT ? "short" : " long",
++ "pool %d: %d of %d buffers added\n",
+ bm_pool->id, i, buf_num);
+ return i;
+ }
+@@ -4498,25 +4510,20 @@ static int mvpp2_bm_bufs_add(struct mvpp
+ * pool pointer on success
+ */
+ static struct mvpp2_bm_pool *
+-mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
+- int pkt_size)
++mvpp2_bm_pool_use(struct mvpp2_port *port, unsigned pool, int pkt_size)
+ {
+ struct mvpp2_bm_pool *new_pool = &port->priv->bm_pools[pool];
+ int num;
+
+- if (new_pool->type != MVPP2_BM_FREE && new_pool->type != type) {
+- netdev_err(port->dev, "mixing pool types is forbidden\n");
++ if (pool >= MVPP2_BM_POOLS_NUM) {
++ netdev_err(port->dev, "Invalid pool %d\n", pool);
+ return NULL;
+ }
+
+- if (new_pool->type == MVPP2_BM_FREE)
+- new_pool->type = type;
+-
+ /* Allocate buffers in case BM pool is used as long pool, but packet
+ * size doesn't match MTU or BM pool hasn't being used yet
+ */
+- if (((type == MVPP2_BM_SWF_LONG) && (pkt_size > new_pool->pkt_size)) ||
+- (new_pool->pkt_size == 0)) {
++ if (new_pool->pkt_size == 0) {
+ int pkts_num;
+
+ /* Set default buffer number or free all the buffers in case
+@@ -4524,9 +4531,7 @@ mvpp2_bm_pool_use(struct mvpp2_port *por
+ */
+ pkts_num = new_pool->buf_num;
+ if (pkts_num == 0)
+- pkts_num = type == MVPP2_BM_SWF_LONG ?
+- MVPP2_BM_LONG_BUF_NUM :
+- MVPP2_BM_SHORT_BUF_NUM;
++ pkts_num = mvpp2_pools[pool].buf_num;
+ else
+ mvpp2_bm_bufs_free(port->dev->dev.parent,
+ port->priv, new_pool);
+@@ -4558,9 +4563,8 @@ static int mvpp2_swf_bm_pool_init(struct
+
+ if (!port->pool_long) {
+ port->pool_long =
+- mvpp2_bm_pool_use(port, MVPP2_BM_SWF_LONG_POOL(port->id),
+- MVPP2_BM_SWF_LONG,
+- port->pkt_size);
++ mvpp2_bm_pool_use(port, MVPP2_BM_LONG,
++ mvpp2_pools[MVPP2_BM_LONG].pkt_size);
+ if (!port->pool_long)
+ return -ENOMEM;
+
+@@ -4572,9 +4576,8 @@ static int mvpp2_swf_bm_pool_init(struct
+
+ if (!port->pool_short) {
+ port->pool_short =
+- mvpp2_bm_pool_use(port, MVPP2_BM_SWF_SHORT_POOL,
+- MVPP2_BM_SWF_SHORT,
+- MVPP2_BM_SHORT_PKT_SIZE);
++ mvpp2_bm_pool_use(port, MVPP2_BM_SHORT,
++ mvpp2_pools[MVPP2_BM_SHORT].pkt_size);
+ if (!port->pool_short)
+ return -ENOMEM;
+
+@@ -4593,7 +4596,6 @@ static int mvpp2_bm_update_mtu(struct ne
+ struct mvpp2_port *port = netdev_priv(dev);
+ struct mvpp2_bm_pool *port_pool = port->pool_long;
+ int num, pkts_num = port_pool->buf_num;
+- int pkt_size = MVPP2_RX_PKT_SIZE(mtu);
+
+ /* Update BM pool with new buffer size */
+ mvpp2_bm_bufs_free(dev->dev.parent, port->priv, port_pool);
+@@ -4602,18 +4604,12 @@ static int mvpp2_bm_update_mtu(struct ne
+ return -EIO;
+ }
+
+- port_pool->pkt_size = pkt_size;
+- port_pool->frag_size = SKB_DATA_ALIGN(MVPP2_RX_BUF_SIZE(pkt_size)) +
+- MVPP2_SKB_SHINFO_SIZE;
+ num = mvpp2_bm_bufs_add(port, port_pool, pkts_num);
+ if (num != pkts_num) {
+ WARN(1, "pool %d: %d of %d allocated\n",
+ port_pool->id, num, pkts_num);
+ return -EIO;
+ }
+-
+- mvpp2_bm_pool_bufsize_set(port->priv, port_pool,
+- MVPP2_RX_BUF_SIZE(port_pool->pkt_size));
+ dev->mtu = mtu;
+ netdev_update_features(dev);
+ return 0;
+@@ -8630,6 +8626,8 @@ static int mvpp2_probe(struct platform_d
+ priv->sysctrl_base = NULL;
+ }
+
++ mvpp2_setup_bm_pool();
++
+ for (i = 0; i < MVPP2_MAX_THREADS; i++) {
+ u32 addr_space_sz;
+
diff --git a/patches.drivers/net-phy-add-XAUI-and-10GBASE-KR-PHY-connection-types.patch b/patches.drivers/net-phy-add-XAUI-and-10GBASE-KR-PHY-connection-types.patch
new file mode 100644
index 0000000000..7145495a58
--- /dev/null
+++ b/patches.drivers/net-phy-add-XAUI-and-10GBASE-KR-PHY-connection-types.patch
@@ -0,0 +1,62 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Mon, 5 Jun 2017 12:23:10 +0100
+Subject: net: phy: add XAUI and 10GBASE-KR PHY connection types
+Patch-mainline: v4.13-rc1
+Git-commit: c125ca091873f2e848cc31c2371a3a66c2fd4dd8
+References: bsc#1098633
+
+XAUI allows XGMII to reach an extended distance by using a XGXS layer at
+each end of the MAC to PHY link, operating over four Serdes lanes.
+
+10GBASE-KR is a single lane Serdes backplane ethernet connection method
+with autonegotiation on the link. Some PHYs use this to connect to the
+ethernet interface at 10G speeds, switching to other connection types
+when utilising slower speeds.
+
+10GBASE-KR is also used for XFI and SFI to connect to XFP and SFP fiber
+modules.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ Documentation/devicetree/bindings/net/ethernet.txt | 2 ++
+ include/linux/phy.h | 7 +++++++
+ 2 files changed, 9 insertions(+)
+
+--- a/Documentation/devicetree/bindings/net/ethernet.txt
++++ b/Documentation/devicetree/bindings/net/ethernet.txt
+@@ -32,6 +32,8 @@ The following properties are common to t
+ * "2000base-x",
+ * "2500base-x",
+ * "rxaui"
++ * "xaui"
++ * "10gbase-kr" (10GBASE-KR, XFI, SFI)
+ - phy-connection-type: the same as "phy-mode" property but described in ePAPR;
+ - phy-handle: phandle, specifies a reference to a node representing a PHY
+ device; this property is described in ePAPR and so preferred;
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -84,6 +84,9 @@ typedef enum {
+ PHY_INTERFACE_MODE_1000BASEX,
+ PHY_INTERFACE_MODE_2500BASEX,
+ PHY_INTERFACE_MODE_RXAUI,
++ PHY_INTERFACE_MODE_XAUI,
++ /* 10GBASE-KR, XFI, SFI - single lane 10G Serdes */
++ PHY_INTERFACE_MODE_10GKR,
+ PHY_INTERFACE_MODE_MAX,
+ } phy_interface_t;
+
+@@ -150,6 +153,10 @@ static inline const char *phy_modes(phy_
+ return "2500base-x";
+ case PHY_INTERFACE_MODE_RXAUI:
+ return "rxaui";
++ case PHY_INTERFACE_MODE_XAUI:
++ return "xaui";
++ case PHY_INTERFACE_MODE_10GKR:
++ return "10gbase-kr";
+ default:
+ return "unknown";
+ }
diff --git a/patches.drivers/nfit-address-range-scrub-add-module-option-to-skip-i.patch b/patches.drivers/nfit-address-range-scrub-add-module-option-to-skip-i.patch
new file mode 100644
index 0000000000..537867ad4a
--- /dev/null
+++ b/patches.drivers/nfit-address-range-scrub-add-module-option-to-skip-i.patch
@@ -0,0 +1,44 @@
+From: Dan Williams <dan.j.williams@intel.com>
+Date: Mon, 2 Apr 2018 15:28:03 -0700
+Subject: nfit, address-range-scrub: add module option to skip initial ars
+Patch-mainline: v4.17-rc1
+Git-commit: bca811a7fd5a5c1c0644926161c2843322ab74b3
+References: bsc#1094119
+
+After attempting to quickly retrieve known errors the kernel proceeds to
+kick off a long running ARS. Add a module option to disable this
+behavior at initialization time, or at new region discovery time.
+Otherwise, ARS can be started manually regardless of the state of this
+setting.
+
+Co-developed-by: Dave Jiang <dave.jiang@intel.com>
+Signed-off-by: Dave Jiang <dave.jiang@intel.com>
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+Acked-by: Johannes Thumshirn <jthumshirn@suse.de>
+---
+ drivers/acpi/nfit/core.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/acpi/nfit/core.c
++++ b/drivers/acpi/nfit/core.c
+@@ -50,6 +50,10 @@ module_param(default_dsm_family, int, S_
+ MODULE_PARM_DESC(default_dsm_family,
+ "Try this DSM type first when identifying NVDIMM family");
+
++static bool no_init_ars;
++module_param(no_init_ars, bool, 0644);
++MODULE_PARM_DESC(no_init_ars, "Skip ARS run at nfit init time");
++
+ LIST_HEAD(acpi_descs);
+ DEFINE_MUTEX(acpi_desc_lock);
+
+@@ -2789,6 +2793,9 @@ static int ars_register(struct acpi_nfit
+ {
+ int rc = *query_rc;
+
++ if (no_init_ars)
++ return acpi_nfit_register_region(acpi_desc, nfit_spa);
++
+ set_bit(ARS_REQ, &nfit_spa->ars_state);
+ set_bit(ARS_SHORT, &nfit_spa->ars_state);
+
diff --git a/patches.drivers/nfit-address-range-scrub-determine-one-platform-max_.patch b/patches.drivers/nfit-address-range-scrub-determine-one-platform-max_.patch
new file mode 100644
index 0000000000..a52ca4f647
--- /dev/null
+++ b/patches.drivers/nfit-address-range-scrub-determine-one-platform-max_.patch
@@ -0,0 +1,189 @@
+From: Dan Williams <dan.j.williams@intel.com>
+Date: Thu, 5 Apr 2018 01:25:02 -0700
+Subject: nfit, address-range-scrub: determine one platform max_ars value
+Patch-mainline: v4.17-rc1
+Git-commit: 459d0ddb079c869c986e1bb871c91564a4b8ccfe
+References: bsc#1094119
+
+acpi_nfit_query_poison() is awkward in that it requires an nfit_spa
+argument in order to determine what max_ars value to use. Instead probe
+for the minimum max_ars across all scrub-capable ranges in the system
+and drop the nfit_spa argument.
+
+This enables a larger rework / simplification of the ARS state machine
+whereby the status can be retrieved once and then iterated over all
+address ranges to reap completions.
+
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+Acked-by: Johannes Thumshirn <jthumshirn@suse.de>
+---
+ drivers/acpi/nfit/core.c | 78 ++++++++++++++++++++++++-----------------------
+ drivers/acpi/nfit/nfit.h | 2 -
+ 2 files changed, 41 insertions(+), 39 deletions(-)
+
+--- a/drivers/acpi/nfit/core.c
++++ b/drivers/acpi/nfit/core.c
+@@ -2469,16 +2469,16 @@ static int ars_get_status(struct acpi_nf
+ int rc, cmd_rc;
+
+ rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_STATUS, ars_status,
+- acpi_desc->ars_status_size, &cmd_rc);
++ acpi_desc->max_ars, &cmd_rc);
+ if (rc < 0)
+ return rc;
+ return cmd_rc;
+ }
+
+-static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc,
+- struct nd_cmd_ars_status *ars_status)
++static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc)
+ {
+ struct nvdimm_bus *nvdimm_bus = acpi_desc->nvdimm_bus;
++ struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
+ int rc;
+ u32 i;
+
+@@ -2712,60 +2712,35 @@ static int acpi_nfit_register_region(str
+ return rc;
+ }
+
+-static int ars_status_alloc(struct acpi_nfit_desc *acpi_desc,
+- u32 max_ars)
++static int ars_status_alloc(struct acpi_nfit_desc *acpi_desc)
+ {
+ struct device *dev = acpi_desc->dev;
+ struct nd_cmd_ars_status *ars_status;
+
+- if (acpi_desc->ars_status && acpi_desc->ars_status_size >= max_ars) {
+- memset(acpi_desc->ars_status, 0, acpi_desc->ars_status_size);
++ if (acpi_desc->ars_status) {
++ memset(acpi_desc->ars_status, 0, acpi_desc->max_ars);
+ return 0;
+ }
+
+- if (acpi_desc->ars_status)
+- devm_kfree(dev, acpi_desc->ars_status);
+- acpi_desc->ars_status = NULL;
+- ars_status = devm_kzalloc(dev, max_ars, GFP_KERNEL);
++ ars_status = devm_kzalloc(dev, acpi_desc->max_ars, GFP_KERNEL);
+ if (!ars_status)
+ return -ENOMEM;
+ acpi_desc->ars_status = ars_status;
+- acpi_desc->ars_status_size = max_ars;
+ return 0;
+ }
+
+-static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc,
+- struct nfit_spa *nfit_spa)
++static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc)
+ {
+- struct acpi_nfit_system_address *spa = nfit_spa->spa;
+ int rc;
+