Home Home > GIT Browse > SLE15-SP1-AZURE
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKernel Build Daemon <kbuild@suse.de>2019-06-22 07:10:29 +0200
committerKernel Build Daemon <kbuild@suse.de>2019-06-22 07:10:29 +0200
commitd6d41d025ae222f1d26e7ad972df6074f4174d8a (patch)
treebee90bec68165ea84d1ab8599d1919b13f9a9c6a
parent20060318f6db4f5c8371104295a60a1e0042ac29 (diff)
parent52b668b6e852151fea4e101da852c107e00fad4d (diff)
Merge branch 'SLE15-SP1' into SLE15-SP1-AZURE
-rw-r--r--blacklist.conf8
-rw-r--r--config/arm64/default4
-rw-r--r--config/s390x/default1
-rw-r--r--config/s390x/zfcpdump1
-rw-r--r--kabi/severities21
-rw-r--r--patches.arch/PCI-Remove-reset-argument-from-pci_iov_-add-remove-_.patch8
-rw-r--r--patches.arch/kvm-x86-include-cpuid-leaf-0x8000001e-in-kvm-s-supported-cpuid.patch40
-rw-r--r--patches.arch/kvm-x86-include-multiple-indices-with-cpuid-leaf-0x8000001d.patch57
-rw-r--r--patches.arch/powerpc-cacheinfo-add-cacheinfo_teardown-cacheinfo_r.patch72
-rw-r--r--patches.arch/powerpc-pseries-Fix-oops-in-hotplug-memory-notifier.patch44
-rw-r--r--patches.arch/powerpc-pseries-dlpar-Fix-a-missing-check-in-dlpar_p.patch40
-rw-r--r--patches.arch/powerpc-pseries-mobility-prevent-cpu-hotplug-during-.patch61
-rw-r--r--patches.arch/powerpc-pseries-mobility-rebuild-cacheinfo-hierarchy.patch83
-rw-r--r--patches.arch/s390-airq-provide-cacheline-aligned-ivs114
-rw-r--r--patches.arch/s390-airq-recognize-directed-interrupts121
-rw-r--r--patches.arch/s390-enable-processes-for-mio-instructions52
-rw-r--r--patches.arch/s390-ism-move-oddities-of-device-io-to-wrapper-function135
-rw-r--r--patches.arch/s390-jump_label-Use-jdd-constraint-on-gcc9.patch72
-rw-r--r--patches.arch/s390-pci-add-parameter-to-disable-usage-of-mio-instructions58
-rw-r--r--patches.arch/s390-pci-add-parameter-to-force-floating-irqs72
-rw-r--r--patches.arch/s390-pci-clarify-interrupt-vector-usage124
-rw-r--r--patches.arch/s390-pci-fix-assignment-of-bus-resources31
-rw-r--r--patches.arch/s390-pci-fix-struct-definition-for-set-pci-function87
-rw-r--r--patches.arch/s390-pci-gather-statistics-for-floating-vs-directed-irqs70
-rw-r--r--patches.arch/s390-pci-improve-bar-check29
-rw-r--r--patches.arch/s390-pci-map-iov-resources53
-rw-r--r--patches.arch/s390-pci-mark-command-line-parser-data-_initdata27
-rw-r--r--patches.arch/s390-pci-move-everything-irq-related-to-pci_irq-c535
-rw-r--r--patches.arch/s390-pci-move-io-address-mapping-code-to-pci_insn-c294
-rw-r--r--patches.arch/s390-pci-provide-support-for-cpu-directed-interrupts646
-rw-r--r--patches.arch/s390-pci-provide-support-for-mio-instructions583
-rw-r--r--patches.arch/s390-pci-remove-stale-rc26
-rw-r--r--patches.arch/s390-pci-remove-unused-define27
-rw-r--r--patches.arch/s390-pci-skip-vf-scanning30
-rw-r--r--patches.arch/s390-protvirt-add-memory-sharing-for-diag-308-set-store79
-rw-r--r--patches.arch/s390-protvirt-block-kernel-command-line-alteration33
-rw-r--r--patches.arch/s390-sclp-detect-dirq-facility47
-rw-r--r--patches.arch/s390-show-statistics-for-msi-irqs155
-rw-r--r--patches.arch/s390-uv-introduce-guest-side-ultravisor-code257
-rw-r--r--patches.arch/x86-amd_nb-add-pci-device-ids-for-family-17h-model-30h.patch19
-rw-r--r--patches.arch/x86-amd_nb-add-support-for-raven-ridge-cpus.patch56
-rw-r--r--patches.arch/x86-cpu-amd-don-t-force-the-cpb-cap-when-running-under-a-hypervisor.patch65
-rw-r--r--patches.arch/x86-mce-fix-machine_check_poll-tests-for-error-types.patch103
-rw-r--r--patches.arch/x86-microcode-cpuhotplug-add-a-microcode-loader-cpu-hotplug-callback.patch72
-rw-r--r--patches.arch/x86-microcode-fix-the-ancient-deprecated-microcode-loading-method.patch42
-rw-r--r--patches.arch/x86-mm-mem_encrypt-disable-all-instrumentation-for-early-sme-setup.patch94
-rw-r--r--patches.arch/x86-speculation-mds-revert-cpu-buffer-clear-on-double-fault-exit.patch70
-rw-r--r--patches.arch/x86-umip-make-the-umip-activated-message-generic.patch37
-rw-r--r--patches.arch/x86-umip-print-umip-line-only-once.patch34
-rw-r--r--patches.drivers/ALSA-firewire-motu-fix-destruction-of-data-for-isoch.patch36
-rw-r--r--patches.drivers/ALSA-hda-realtek-Update-headset-mode-for-ALC256.patch193
-rw-r--r--patches.drivers/ALSA-oxfw-allow-PCM-capture-for-Stanton-SCS.1m.patch41
-rw-r--r--patches.drivers/ASoC-cs42xx8-Add-regcache-mask-dirty.patch39
-rw-r--r--patches.drivers/ASoC-fsl_asrc-Fix-the-issue-about-unsupported-rate.patch45
-rw-r--r--patches.drivers/HID-Wacom-switch-Dell-canvas-into-highres-mode.patch45
-rw-r--r--patches.drivers/HID-wacom-Add-ability-to-provide-explicit-battery-st.patch253
-rw-r--r--patches.drivers/HID-wacom-Add-support-for-3rd-generation-Intuos-BT.patch228
-rw-r--r--patches.drivers/HID-wacom-Add-support-for-Pro-Pen-slim.patch45
-rw-r--r--patches.drivers/HID-wacom-Correct-button-numbering-2nd-gen-Intuos-Pr.patch73
-rw-r--r--patches.drivers/HID-wacom-Don-t-report-anything-prior-to-the-tool-en.patch77
-rw-r--r--patches.drivers/HID-wacom-Don-t-set-tool-type-until-we-re-in-range.patch75
-rw-r--r--patches.drivers/HID-wacom-Mark-expected-switch-fall-through.patch53
-rw-r--r--patches.drivers/HID-wacom-Move-HID-fix-for-AES-serial-number-into-wa.patch102
-rw-r--r--patches.drivers/HID-wacom-Move-handling-of-HID-quirks-into-a-dedicat.patch147
-rw-r--r--patches.drivers/HID-wacom-Properly-handle-AES-serial-number-and-tool.patch120
-rw-r--r--patches.drivers/HID-wacom-Queue-events-with-missing-type-serial-data.patch223
-rw-r--r--patches.drivers/HID-wacom-Remove-comparison-of-u8-mode-with-zero-and.patch40
-rw-r--r--patches.drivers/HID-wacom-Replace-touch_max-fixup-code-with-static-t.patch121
-rw-r--r--patches.drivers/HID-wacom-Send-BTN_TOUCH-in-response-to-INTUOSP2_BT-.patch42
-rw-r--r--patches.drivers/HID-wacom-Support-in-range-for-Intuos-Bamboo-tablets.patch142
-rw-r--r--patches.drivers/HID-wacom-Sync-INTUOSP2_BT-touch-state-after-each-fr.patch55
-rw-r--r--patches.drivers/HID-wacom-Work-around-HID-descriptor-bug-in-DTK-2451.patch70
-rw-r--r--patches.drivers/HID-wacom-bluetooth-send-exit-report-for-recent-Blue10
-rw-r--r--patches.drivers/HID-wacom-convert-Wacom-custom-usages-to-standard-HI.patch43
-rw-r--r--patches.drivers/HID-wacom-fix-mistake-in-printk.patch59
-rw-r--r--patches.drivers/HID-wacom-generic-Ignore-HID_DG_BATTERYSTRENTH-0.patch38
-rw-r--r--patches.drivers/HID-wacom-generic-Leave-tool-in-prox-until-it-comple.patch73
-rw-r--r--patches.drivers/HID-wacom-generic-Refactor-generic-battery-handling.patch302
-rw-r--r--patches.drivers/HID-wacom-generic-Report-AES-battery-information.patch37
-rw-r--r--patches.drivers/HID-wacom-generic-Reset-events-back-to-zero-when-pen.patch43
-rw-r--r--patches.drivers/HID-wacom-generic-Scale-battery-capacity-measurement.patch46
-rw-r--r--patches.drivers/HID-wacom-generic-Send-BTN_STYLUS3-when-both-barrel-.patch109
-rw-r--r--patches.drivers/HID-wacom-generic-Send-BTN_TOOL_PEN-in-prox-once-the.patch50
-rw-r--r--patches.drivers/HID-wacom-generic-Support-multiple-tools-per-report.patch179
-rw-r--r--patches.drivers/HID-wacom-generic-Use-generic-codepath-terminology-i.patch87
-rw-r--r--patches.drivers/HID-wacom-generic-add-the-Report-Valid-usage.patch104
-rw-r--r--patches.drivers/HID-wacom-wacom_wac_collection-is-local-to-wacom_wac.patch33
-rw-r--r--patches.drivers/PM-core-Propagate-dev-power.wakeup_path-when-no-call.patch50
-rw-r--r--patches.drivers/Revert-ALSA-hda-realtek-Improve-the-headset-mic-for-.patch62
-rw-r--r--patches.drivers/Revert-HID-wacom-generic-Send-BTN_TOOL_PEN-in-prox-o.patch57
-rw-r--r--patches.drivers/cpufreq-amd-ignore-the-check-for-procfeedback-in-st-cz.patch (renamed from patches.arch/cpufreq-amd-ignore-the-check-for-procfeedback-in-st-cz.patch)0
-rw-r--r--patches.drivers/dmaengine-Replace-WARN_TAINT_ONCE-with-pr_warn_once.patch48
-rw-r--r--patches.drivers/dmaengine-ioat-constify-pci_device_id.patch44
-rw-r--r--patches.drivers/dmaengine-ioat-don-t-use-DMA_ERROR_CODE.patch80
-rw-r--r--patches.drivers/dmaengine-ioat-fix-prototype-of-ioat_enumerate_chann.patch58
-rw-r--r--patches.drivers/dmaengine-ioatdma-Add-Snow-Ridge-ioatdma-device-id.patch65
-rw-r--r--patches.drivers/dmaengine-ioatdma-Add-intr_coalesce-sysfs-entry.patch142
-rw-r--r--patches.drivers/dmaengine-ioatdma-add-descriptor-pre-fetch-support-f.patch108
-rw-r--r--patches.drivers/dmaengine-ioatdma-disable-DCA-enabling-on-IOATDMA-v3.patch47
-rw-r--r--patches.drivers/dmaengine-ioatdma-set-the-completion-address-registe.patch40
-rw-r--r--patches.drivers/dmaengine-ioatdma-support-latency-tolerance-report-L.patch93
-rw-r--r--patches.drivers/drivers-depend-on-has_iomem-for-devm_platform_ioremap_resource36
-rw-r--r--patches.drivers/drivers-dma-ioat-Remove-now-redundant-smp_read_barri.patch49
-rw-r--r--patches.drivers/drivers-fix-a-typo-in-the-kernel-doc-for-devm_platfo.patch31
-rw-r--r--patches.drivers/drivers-provide-devm_platform_ioremap_resource.patch64
-rw-r--r--patches.drivers/drivers-rapidio-devices-rio_mport_cdev.c-fix-resourc.patch44
-rw-r--r--patches.drivers/drivers-rapidio-rio_cm.c-fix-potential-oops-in-riocm.patch44
-rw-r--r--patches.drivers/edac-mc-fix-edac_mc_find-in-case-no-device-is-found.patch60
-rw-r--r--patches.drivers/hid-input-fix-a4tech-horizontal-wheel-custom-usage.patch90
-rw-r--r--patches.drivers/hwmon-k10temp-27c-offset-needed-for-threadripper2.patch28
-rw-r--r--patches.drivers/hwmon-k10temp-add-hygon-dhyana-support.patch39
-rw-r--r--patches.drivers/hwmon-k10temp-add-support-for-amd-family-17h-model-30h-cpus.patch4
-rw-r--r--patches.drivers/hwmon-k10temp-add-support-for-amd-ryzen-w-vega-graphics.patch40
-rw-r--r--patches.drivers/hwmon-k10temp-add-support-for-family-17h.patch67
-rw-r--r--patches.drivers/hwmon-k10temp-add-support-for-stoney-ridge-and-bristol.patch38
-rw-r--r--patches.drivers/hwmon-k10temp-add-support-for-temperature-offsets.patch77
-rw-r--r--patches.drivers/hwmon-k10temp-add-temperature-offset-for-ryzen-1900x.patch25
-rw-r--r--patches.drivers/hwmon-k10temp-add-temperature-offset-for-ryzen-2700x.patch62
-rw-r--r--patches.drivers/hwmon-k10temp-correct-model-name-for-ryzen-1600x.patch25
-rw-r--r--patches.drivers/hwmon-k10temp-display-both-tctl-and-tdie.patch138
-rw-r--r--patches.drivers/hwmon-k10temp-fix-reading-critical-temperature-register.patch116
-rw-r--r--patches.drivers/hwmon-k10temp-make-function-get_raw_temp-static.patch31
-rw-r--r--patches.drivers/hwmon-k10temp-move-chip-specific-code-into-probe-function.patch129
-rw-r--r--patches.drivers/hwmon-k10temp-only-apply-temperature-offset-if-result-is.patch38
-rw-r--r--patches.drivers/hwmon-k10temp-support-all-family-15h-model-6xh-and-model.patch36
-rw-r--r--patches.drivers/hwmon-k10temp-support-threadripper-2920x-2970wx-simplify.patch39
-rw-r--r--patches.drivers/hwmon-k10temp-use-api-function-to-access-system-management.patch78
-rw-r--r--patches.drivers/hwmon-k10temp-x86-amd_nb-consolidate-shared-device-ids.patch32
-rw-r--r--patches.drivers/i2c-piix4-add-hygon-dhyana-smbus-support.patch91
-rw-r--r--patches.drivers/ipv6-fib-Don-t-assume-only-nodes-hold-a-reference-on.patch41
-rw-r--r--patches.drivers/mfd-intel-lpss-Set-the-device-in-reset-state-when-in.patch72
-rw-r--r--patches.drivers/mfd-tps65912-spi-Add-missing-of-table-registration.patch44
-rw-r--r--patches.drivers/mfd-twl6040-Fix-device-init-errors-for-ACCCTL-regist.patch64
-rw-r--r--patches.drivers/mmc-core-make-pwrseq_emmc-partially-support-sleepy-G.patch118
-rw-r--r--patches.drivers/mmc-mmci-Prevent-polling-for-busy-detection-in-IRQ-c.patch46
-rw-r--r--patches.drivers/mmc-sdhci-of-esdhc-add-erratum-eSDHC-A001-and-A-0083.patch52
-rw-r--r--patches.drivers/nvmem-Don-t-let-a-NULL-cell_id-for-nvmem_cell_get-cr.patch79
-rw-r--r--patches.drivers/nvmem-allow-to-select-i.MX-nvmem-driver-for-i.MX-7D.patch37
-rw-r--r--patches.drivers/nvmem-core-fix-read-buffer-in-place.patch60
-rw-r--r--patches.drivers/nvmem-correct-Broadcom-OTP-controller-driver-writes.patch48
-rw-r--r--patches.drivers/nvmem-imx-ocotp-Add-i.MX7D-timing-write-clock-setup-.patch132
-rw-r--r--patches.drivers/nvmem-imx-ocotp-Add-support-for-banked-OTP-addressin.patch159
-rw-r--r--patches.drivers/nvmem-imx-ocotp-Enable-i.MX7D-OTP-write-support.patch38
-rw-r--r--patches.drivers/nvmem-imx-ocotp-Move-i.MX6-write-clock-setup-to-dedi.patch99
-rw-r--r--patches.drivers/nvmem-imx-ocotp-Pass-parameters-via-a-struct.patch107
-rw-r--r--patches.drivers/nvmem-imx-ocotp-Restrict-OTP-write-to-IMX6-processor.patch43
-rw-r--r--patches.drivers/nvmem-imx-ocotp-Update-module-description.patch36
-rw-r--r--patches.drivers/nvmem-properly-handle-returned-value-nvmem_reg_read.patch57
-rw-r--r--patches.drivers/platform-chrome-cros_ec_proto-check-for-NULL-transfe.patch53
-rw-r--r--patches.drivers/platform-mellanox-Add-TmFifo-driver-for-Mellanox-Blu.patch1410
-rw-r--r--patches.drivers/platform-mellanox-Add-new-ODM-system-types-to-mlx-pl.patch59
-rw-r--r--patches.drivers/platform-mellanox-mlxreg-hotplug-Add-devm_free_irq-c.patch70
-rw-r--r--patches.drivers/platform-x86-asus-wmi-Only-Tell-EC-the-OS-will-handl.patch102
-rw-r--r--patches.drivers/platform-x86-intel_pmc_core-Add-ICL-platform-support.patch142
-rw-r--r--patches.drivers/platform-x86-intel_pmc_core-Add-Package-cstates-resi.patch162
-rw-r--r--patches.drivers/platform-x86-intel_pmc_core-Avoid-a-u32-overflow.patch43
-rw-r--r--patches.drivers/platform-x86-intel_pmc_core-Include-Reserved-IP-for-.patch74
-rw-r--r--patches.drivers/platform-x86-intel_pmc_core-Mark-local-function-stat.patch41
-rw-r--r--patches.drivers/platform-x86-intel_pmc_core-Quirk-to-ignore-XTAL-shu.patch131
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Add-ASIC-hotplug-device-co.patch196
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Add-LED-platform-driver-ac.patch396
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Add-UID-LED-for-the-next-g.patch36
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Add-definitions-for-new-re.patch54
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Add-extra-CPLD-for-next-ge.patch61
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Add-mlx-wdt-platform-drive.patch376
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Add-mlxreg-fan-platform-dr.patch270
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Add-mlxreg-io-platform-dri.patch350
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Add-support-for-fan-capabi.patch315
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Add-support-for-fan-direct.patch59
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Add-support-for-new-VMOD00.patch46
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Add-support-for-tachometer.patch57
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Allow-mlxreg-io-driver-act-e2883859.patch151
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Allow-mlxreg-io-driver-act.patch138
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Change-mlxreg-io-configura.patch38
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Convert-to-use-SPDX-identi.patch57
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Fix-LED-configuration.patch43
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Fix-access-mode-for-fan_di.patch32
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Fix-copy-paste-error-in-ml.patch32
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Fix-parent-device-in-i2c-m.patch160
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Fix-tachometer-registers.patch47
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Remove-unused-define.patch26
-rw-r--r--patches.drivers/platform-x86-mlx-platform-Rename-new-systems-product.patch49
-rw-r--r--patches.drivers/platform_data-mlxreg-Add-capability-field-to-core-pl.patch36
-rw-r--r--patches.drivers/platform_data-mlxreg-Document-fixes-for-core-platfor.patch31
-rw-r--r--patches.drivers/platform_data-mlxreg-additions-for-Mellanox-watchdog.patch63
-rw-r--r--patches.drivers/power-supply-max14656-fix-potential-use-before-alloc.patch65
-rw-r--r--patches.drivers/power-supply-sysfs-prevent-endless-uevent-loop-with-.patch69
-rw-r--r--patches.drivers/qlcnic-Avoid-potential-NULL-pointer-dereference.patch35
-rw-r--r--patches.drivers/qmi_wwan-Add-quirk-for-Quectel-dynamic-config.patch170
-rw-r--r--patches.drivers/qmi_wwan-add-network-device-usage-statistics-for-qmi.patch156
-rw-r--r--patches.drivers/qmi_wwan-add-support-for-QMAP-padding-in-the-RX-path.patch66
-rw-r--r--patches.drivers/qmi_wwan-avoid-RCU-stalls-on-device-disconnect-when-.patch76
-rw-r--r--patches.drivers/qmi_wwan-extend-permitted-QMAP-mux_id-value-range.patch60
-rw-r--r--patches.drivers/rapidio-fix-a-NULL-pointer-dereference-when-create_w.patch44
-rw-r--r--patches.drivers/ras-cec-convert-the-timer-callback-to-a-workqueue.patch141
-rw-r--r--patches.drivers/ras-cec-fix-binary-search-function.patch90
-rw-r--r--patches.drivers/scsi-mpt3sas_ctl-fix-double-fetch-bug-in-ctl_ioctl_main2
-rw-r--r--patches.drivers/scsi-qla2xxx-Fix-FC-AL-connection-target-discovery.patch44
-rw-r--r--patches.drivers/scsi-qla2xxx-Fix-N2N-target-discovery-with-Local-loo.patch2
-rw-r--r--patches.drivers/serial-sh-sci-disable-DMA-for-uart_console.patch50
-rw-r--r--patches.drivers/soc-mediatek-pwrap-Zero-initialize-rdata-in-pwrap_in.patch46
-rw-r--r--patches.drivers/soc-rockchip-Set-the-proper-PWM-for-rk3288.patch57
-rw-r--r--patches.drivers/spi-Fix-zero-length-xfer-bug.patch45
-rw-r--r--patches.drivers/spi-bitbang-Fix-NULL-pointer-dereference-in-spi_unre.patch88
-rw-r--r--patches.drivers/spi-pxa2xx-fix-SCR-divisor-calculation.patch62
-rw-r--r--patches.drivers/spi-spi-fsl-spi-call-spi_finalize_current_message-at.patch44
-rw-r--r--patches.drivers/spi-spi-topcliff-pch-Fix-to-handle-empty-DMA-buffers.patch67
-rw-r--r--patches.drivers/spi-tegra114-reset-controller-on-probe.patch103
-rw-r--r--patches.drivers/tty-max310x-Fix-external-crystal-register-setup.patch47
-rw-r--r--patches.drivers/usb-dwc2-Fix-DMA-cache-alignment-issues.patch61
-rw-r--r--patches.drivers/video-hgafb-fix-potential-NULL-pointer-dereference.patch38
-rw-r--r--patches.drivers/video-imsttfb-fix-potential-NULL-pointer-dereference.patch43
-rw-r--r--patches.drivers/virtio_console-initialize-vtermno-value-for-ports.patch50
-rw-r--r--patches.drivers/watchdog-imx2_wdt-Fix-set_timeout-for-big-timeout-va.patch43
-rw-r--r--patches.drivers/x86-CPU-Add-Icelake-model-number.patch44
-rw-r--r--patches.drm/drm-add-fallback-override-firmware-EDID-modes-workar.patch152
-rw-r--r--patches.drm/drm-amd-display-Use-plane-color_space-for-dpp-if-spe.patch73
-rw-r--r--patches.drm/drm-edid-abstract-override-firmware-EDID-retrieval.patch70
-rw-r--r--patches.drm/drm-i915-Add-new-AML_ULX-support-list.patch39
-rw-r--r--patches.drm/drm-i915-Add-new-ICL-PCI-ID.patch42
-rw-r--r--patches.drm/drm-i915-Apply-correct-ddi-translation-table-for-AML.patch66
-rw-r--r--patches.drm/drm-i915-Attach-the-pci-match-data-to-the-device-upo.patch141
-rw-r--r--patches.drm/drm-i915-Fix-uninitialized-mask-in-intel_device_info.patch51
-rw-r--r--patches.drm/drm-i915-Introduce-concept-of-a-sub-platform.patch416
-rw-r--r--patches.drm/drm-i915-Mark-AML-0x87CA-as-ULX.patch44
-rw-r--r--patches.drm/drm-i915-Move-final-cleanup-of-drm_i915_private-to-i.patch64
-rw-r--r--patches.drm/drm-i915-Remove-redundant-device-id-from-IS_IRONLAKE.patch61
-rw-r--r--patches.drm/drm-i915-Split-Pineview-device-info-into-desktop-and.patch119
-rw-r--r--patches.drm/drm-i915-Split-some-PCI-ids-into-separate-groups.patch351
-rw-r--r--patches.drm/drm-i915-aml-Add-new-Amber-Lake-PCI-ID.patch93
-rw-r--r--patches.drm/drm-i915-cfl-Adding-another-PCI-Device-ID.patch67
-rw-r--r--patches.drm/drm-i915-cml-Add-CML-PCI-IDS.patch93
-rw-r--r--patches.drm/drm-i915-icl-Adding-few-more-device-IDs-for-Ice-Lake.patch48
-rw-r--r--patches.drm/drm-i915-perf-fix-whitelist-on-Gen10.patch53
-rw-r--r--patches.drm/drm-i915-sdvo-Implement-proper-HDMI-audio-support-fo.patch188
-rw-r--r--patches.drm/drm-i915-start-moving-runtime-device-info-to-a-separ.patch734
-rw-r--r--patches.drm/drm-mediatek-call-drm_atomic_helper_shutdown-when-un.patch34
-rw-r--r--patches.drm/drm-mediatek-call-mtk_dsi_stop-after-mtk_drm_crtc_at.patch71
-rw-r--r--patches.drm/drm-mediatek-clear-num_pipes-when-unbind-driver.patch37
-rw-r--r--patches.drm/drm-mediatek-fix-unbind-functions.patch36
-rw-r--r--patches.drm/drm-mediatek-unbind-components-in-mtk_drm_unbind.patch57
-rw-r--r--patches.drm/drm-nouveau-disp-dp-respect-sink-limits-when-selecti.patch47
-rw-r--r--patches.drm/drm-nouveau-kms-gf119-gp10x-push-HeadSetControlOutpu.patch41
-rw-r--r--patches.drm/drm-nouveau-kms-gv100-fix-spurious-window-immediate-.patch64
-rw-r--r--patches.fixes/0001-USB-serial-pl2303-fix-tranceiver-suspend-mode.patch83
-rw-r--r--patches.fixes/0001-mwifiex-Abort-at-too-short-BSS-descriptor-element.patch3
-rw-r--r--patches.fixes/0001-mwifiex-Fix-heap-overflow-in-mwifiex_uap_parse_tail_.patch3
-rw-r--r--patches.fixes/0001-mwifiex-Fix-possible-buffer-overflows-at-parsing-bss.patch3
-rw-r--r--patches.fixes/0001-usb-xhci-avoid-null-pointer-deref-when-bos-field-is-.patch105
-rw-r--r--patches.fixes/6lowpan-Off-by-one-handling-nexthdr.patch41
-rw-r--r--patches.fixes/PCI-PM-Avoid-possible-suspend-to-idle-issue.patch89
-rw-r--r--patches.fixes/SMB3-Fix-endian-warning.patch40
-rw-r--r--patches.fixes/af_key-unconditionally-clone-on-broadcast.patch132
-rw-r--r--patches.fixes/audit-fix-a-memory-leak-bug.patch68
-rw-r--r--patches.fixes/blk-mq-fix-hang-caused-by-freeze-unfreeze-sequence.patch149
-rw-r--r--patches.fixes/ceph-factor-out-ceph_lookup_inode.patch64
-rw-r--r--patches.fixes/ceph-fix-null-pointer-deref-when-debugging-is-enabled.patch25
-rw-r--r--patches.fixes/ceph-fix-potential-use-after-free-in-ceph_mdsc_build_path.patch57
-rw-r--r--patches.fixes/ceph-flush-dirty-inodes-before-proceeding-with-remount.patch48
-rw-r--r--patches.fixes/ceph-print-inode-number-in-_caps_issued_mask-debugging-messages.patch55
-rw-r--r--patches.fixes/ceph-quota-fix-quota-subdir-mounts.patch347
-rw-r--r--patches.fixes/ceph-remove-duplicated-filelock-ref-increase.patch53
-rw-r--r--patches.fixes/cfg80211-fix-memory-leak-of-wiphy-device-name.patch39
-rw-r--r--patches.fixes/drbd-Avoid-Clang-warning-about-pointless-switch-stat.patch74
-rw-r--r--patches.fixes/drbd-disconnect-if-the-wrong-UUIDs-are-attached-on-a.patch48
-rw-r--r--patches.fixes/drbd-narrow-rcu_read_lock-in-drbd_sync_handshake.patch84
-rw-r--r--patches.fixes/drbd-skip-spurious-timeout-ping-timeo-when-failing-p.patch62
-rw-r--r--patches.fixes/drivers-thermal-tsens-Don-t-print-error-message-on-E.patch38
-rw-r--r--patches.fixes/mdio_bus-Fix-use-after-free-on-device_register-fails.patch2
-rw-r--r--patches.fixes/nfsd-COPY-and-CLONE-operations-require-the-saved-fil.patch2
-rw-r--r--patches.fixes/nl-mac-80211-allow-4addr-AP-operation-on-crypto-cont.patch107
-rw-r--r--patches.fixes/nl80211-fix-station_info-pertid-memory-leak.patch43
-rw-r--r--patches.fixes/pci-disable-vf-decoding-before-pcibios_sriov_disable-updates-resources72
-rw-r--r--patches.fixes/rbd-don-t-assert-on-writes-to-snapshots.patch44
-rw-r--r--patches.fixes/sched-topology-Improve-load-balancing-on-AMD-EPYC.patch144
-rw-r--r--patches.fixes/scsi-vmw_pscsi-Fix-use-after-free-in-pvscsi_queue_lc.patch51
-rw-r--r--patches.fixes/tcp-add-tcp_min_snd_mss-sysctl.patch122
-rw-r--r--patches.fixes/tcp-enforce-tcp_min_snd_mss-in-tcp_mtu_probing.patch36
-rw-r--r--patches.fixes/tcp-limit-payload-size-of-sacked-skbs.patch161
-rw-r--r--patches.fixes/tcp-tcp_fragment-should-apply-sane-memory-limits.patch69
-rw-r--r--patches.fixes/thermal-rcar_gen3_thermal-disable-interrupt-in-.remo.patch42
-rw-r--r--patches.fixes/tmpfs-fix-link-accounting-when-a-tmpfile-is-linked-i.patch64
-rw-r--r--patches.fixes/tmpfs-fix-uninitialized-return-value-in-shmem_link.patch42
-rw-r--r--patches.fixes/vlan-disable-SIOCSHWTSTAMP-in-container.patch44
-rw-r--r--patches.kabi/PCI-skip_bus_pm-kabi-fix.patch31
-rw-r--r--patches.kabi/asus-wmi-kabi-workaround.patch27
-rw-r--r--patches.kabi/kabi-drop-LINUX_MIB_TCPWQUEUETOOBIG-snmp-counter.patch52
-rw-r--r--patches.kabi/kabi-move-sysctl_tcp_min_snd_mss-to-preserve-struct-.patch90
-rw-r--r--patches.kabi/kabi-x86-microcode-hotplug-state-fix.patch40
-rw-r--r--patches.kabi/pci-iov-add-flag-so-platforms-can-skip-vf-scanning25
-rw-r--r--patches.kabi/s390-show-statistics-for-msi-irqs56
-rw-r--r--patches.kabi/x86-topology-Add-CPUID.1F-multi-die-package-support.patch36
-rw-r--r--patches.kabi/x86-topology-Define-topology_logical_die_id.patch34
-rw-r--r--patches.suse/NFS-optional-NFSv4_2-fix.patch30
-rw-r--r--patches.suse/cpu-topology-Export-die_id.patch94
-rw-r--r--patches.suse/hwmon-coretemp-Cosmetic-Rename-internal-variables-to.patch133
-rw-r--r--patches.suse/hwmon-coretemp-Support-multi-die-package.patch65
-rw-r--r--patches.suse/ibmveth-Update-ethtool-settings-to-reflect-virtual-p.patch162
-rw-r--r--patches.suse/module-fix-livepatch-ftrace-module-text-permissions-race.patch170
-rw-r--r--patches.suse/net-nfc-Fix-NULL-dereference-on-nfc_llcp_build_tlv-f.patch2
-rw-r--r--patches.suse/nvme-skip-nvme_update_disk_info-if-the-controller-is.patch34
-rw-r--r--patches.suse/pci-iov-add-flag-so-platforms-can-skip-vf-scanning52
-rw-r--r--patches.suse/pci-iov-factor-out-sriov_add_vfs98
-rw-r--r--patches.suse/perf-x86-intel-cstate-Support-multi-die-package.patch73
-rw-r--r--patches.suse/perf-x86-intel-rapl-Cosmetic-rename-internal-variabl.patch82
-rw-r--r--patches.suse/perf-x86-intel-rapl-Support-multi-die-package.patch78
-rw-r--r--patches.suse/perf-x86-intel-uncore-Cosmetic-renames-in-response-t.patch326
-rw-r--r--patches.suse/perf-x86-intel-uncore-Support-multi-die-package.patch120
-rw-r--r--patches.suse/powercap-intel_rapl-Simplify-rapl_find_package.patch96
-rw-r--r--patches.suse/powercap-intel_rapl-Support-multi-die-package.patch49
-rw-r--r--patches.suse/powercap-intel_rapl-Update-RAPL-domain-name-and-debu.patch199
-rw-r--r--patches.suse/thermal-x86_pkg_temp_thermal-Cosmetic-Rename-interna.patch404
-rw-r--r--patches.suse/thermal-x86_pkg_temp_thermal-Support-multi-die-packa.patch64
-rw-r--r--patches.suse/topology-Create-core_cpus-and-die_cpus-sysfs-attribu.patch240
-rw-r--r--patches.suse/topology-Create-package_cpus-sysfs-attribute.patch81
-rw-r--r--patches.suse/x86-cpufeatures-Carve-out-CQM-features-retrieval.patch105
-rw-r--r--patches.suse/x86-cpufeatures-Combine-word-11-and-12-into-a-new-sc.patch198
-rw-r--r--patches.suse/x86-cpufeatures-Enumerate-the-new-AVX512-BFLOAT16-in.patch109
-rw-r--r--patches.suse/x86-smpboot-Rename-match_die-to-match_pkg.patch54
-rw-r--r--patches.suse/x86-topology-Add-CPUID.1F-multi-die-package-support.patch238
-rw-r--r--patches.suse/x86-topology-Create-topology_max_die_per_package.patch86
-rw-r--r--patches.suse/x86-topology-Define-topology_die_id.patch31
-rw-r--r--patches.suse/x86-topology-Define-topology_logical_die_id.patch147
-rw-r--r--series.conf327
-rw-r--r--supported.conf1
325 files changed, 29761 insertions, 43 deletions
diff --git a/blacklist.conf b/blacklist.conf
index 12a6398a84..d71d7d1d0b 100644
--- a/blacklist.conf
+++ b/blacklist.conf
@@ -1160,3 +1160,11 @@ f627caf55b8e735dcec8fa6538e9668632b55276 # sm712fb driver not enabled: fbdev: sm
406d2b6ae3420f5bb2b3db6986dc6f0b6dbb637b # powerpc/64: Make meltdown reporting Book3S 64 specific - we compile only this arch
ebcd1bfc33c7a90df941df68a6e5d4018c022fba # powerpc/fsl: Add barrier_nospec implementation for NXP PowerPC Book3E
e40542aff909ac34d2c24712c5c0769c8f77f895 # KVM: PPC: Book3S HV: Fix build failure without IOMMU support - we build with IOMMU
+b30a43ac7132cdda833ac4b13dd1ebd35ace14b7 # drm/nouveau: superfluous Kconfig change
+9091d4924476b50f5587f4524504a3748b68a794 # reverting drm/nouveau kconfig change above in stable 4.14.y
+b616b9dbc5f613d64224b2e430211211812eadd0 # reverting drm/nouveau kconfig change above in stable 4.19.y
+4f4fd7c5798bbdd5a03a60f6269cf1177fbd11ef # md/raid5: reverted by the below
+a25d8c327bb41742dbd59f8c545f59f3b9c39983 # md/raid5: reverting the above
+9421e45f5ff3d558cf8b75a8cc0824530caf3453 # uio: reverted by the below
+3d27c4de8d4fb2d4099ff324671792aa2578c6f9 # uio: reverting the above
+9d8d0294e78a164d407133dea05caf4b84247d6a # documentation only
diff --git a/config/arm64/default b/config/arm64/default
index 4229d329d6..41af0f8f76 100644
--- a/config/arm64/default
+++ b/config/arm64/default
@@ -6385,6 +6385,10 @@ CONFIG_CHROME_PLATFORMS=y
CONFIG_CROS_EC_CHARDEV=m
CONFIG_CROS_EC_PROTO=y
CONFIG_CROS_KBD_LED_BACKLIGHT=m
+CONFIG_MELLANOX_PLATFORM=y
+CONFIG_MLXREG_HOTPLUG=m
+CONFIG_MLXREG_IO=m
+CONFIG_MLXBF_TMFIFO=m
CONFIG_CLKDEV_LOOKUP=y
CONFIG_HAVE_CLK_PREPARE=y
CONFIG_COMMON_CLK=y
diff --git a/config/s390x/default b/config/s390x/default
index f22a092411..17b0491cd6 100644
--- a/config/s390x/default
+++ b/config/s390x/default
@@ -3395,6 +3395,7 @@ CONFIG_PARMAN=m
#
# Virtualization
#
+CONFIG_PROTECTED_VIRTUALIZATION_GUEST=y
CONFIG_PFAULT=y
CONFIG_CMM=m
CONFIG_CMM_IUCV=y
diff --git a/config/s390x/zfcpdump b/config/s390x/zfcpdump
index 7ad097bd47..c13ffaa4d7 100644
--- a/config/s390x/zfcpdump
+++ b/config/s390x/zfcpdump
@@ -1243,6 +1243,7 @@ CONFIG_SBITMAP=y
#
# Virtualization
#
+CONFIG_PROTECTED_VIRTUALIZATION_GUEST=y
# CONFIG_PFAULT is not set
# CONFIG_SHARED_KERNEL is not set
# CONFIG_CMM is not set
diff --git a/kabi/severities b/kabi/severities
index ed91247c4c..41c4eba838 100644
--- a/kabi/severities
+++ b/kabi/severities
@@ -19,12 +19,27 @@ arch/x86/kvm/* PASS
arch/powerpc/kvm/* PASS
kvmppc_* PASS
+# IBM Z internal symbols
+# Cf. bsc#894391 / LTC#115441 and bsc#1134730 / LTC#173388
+arch/s390/* PASS
+drivers/s390/* PASS
+net/iucv/* PASS
+airq_iv_* PASS
+ccw_device_* PASS
+ccw_driver_* PASS
+get_ccwdev_* PASS
+zpci_* PASS
+register_adapter_interrupt PASS
+unregister_adapter_interrupt PASS
+enable_cmf PASS
+disable_cmf PASS
+cmf_read PASS
+cmf_readall PASS
+sclp PASS
+
# nobody cares bcache symbols
drivers/md/bcache/* PASS
-# only inter-module local symbols
-drivers/s390/net/qeth* PASS
-
# ceph-related modules
net/ceph/libceph PASS
drivers/block/rbd PASS
diff --git a/patches.arch/PCI-Remove-reset-argument-from-pci_iov_-add-remove-_.patch b/patches.arch/PCI-Remove-reset-argument-from-pci_iov_-add-remove-_.patch
index 659991163c..61508aae86 100644
--- a/patches.arch/PCI-Remove-reset-argument-from-pci_iov_-add-remove-_.patch
+++ b/patches.arch/PCI-Remove-reset-argument-from-pci_iov_-add-remove-_.patch
@@ -68,7 +68,7 @@ index d9dc7363ac77..12c9779e02a0 100644
pci_device_add(virtfn, virtfn->bus);
pci_bus_add_device(virtfn);
-@@ -187,7 +184,7 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id, int reset)
+@@ -187,7 +184,7 @@ failed:
return rc;
}
@@ -105,8 +105,8 @@ index d9dc7363ac77..12c9779e02a0 100644
- pci_iov_remove_virtfn(dev, i, 0);
+ pci_iov_remove_virtfn(dev, i);
- pcibios_sriov_disable(dev);
err_pcibios:
+ iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
@@ -355,7 +347,7 @@ static void sriov_disable(struct pci_dev *dev)
return;
@@ -114,8 +114,8 @@ index d9dc7363ac77..12c9779e02a0 100644
- pci_iov_remove_virtfn(dev, i, 0);
+ pci_iov_remove_virtfn(dev, i);
- pcibios_sriov_disable(dev);
-
+ iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
+ pci_cfg_access_lock(dev);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 3a84c5f7fc94..8ae0fd23cb30 100644
--- a/include/linux/pci.h
diff --git a/patches.arch/kvm-x86-include-cpuid-leaf-0x8000001e-in-kvm-s-supported-cpuid.patch b/patches.arch/kvm-x86-include-cpuid-leaf-0x8000001e-in-kvm-s-supported-cpuid.patch
new file mode 100644
index 0000000000..6b9f1eb7d7
--- /dev/null
+++ b/patches.arch/kvm-x86-include-cpuid-leaf-0x8000001e-in-kvm-s-supported-cpuid.patch
@@ -0,0 +1,40 @@
+From: Jim Mattson <jmattson@google.com>
+Date: Wed, 27 Mar 2019 13:15:37 -0700
+Subject: kvm: x86: Include CPUID leaf 0x8000001e in kvm's supported CPUID
+Git-commit: 382409b4c43e5b44ae4a869ff793d3cf01d12004
+Patch-mainline: v5.2-rc2
+References: bsc#1114279
+
+Kvm now supports extended CPUID functions through 0x8000001f. CPUID
+leaf 0x8000001e is AMD's Processor Topology Information leaf. This
+contains similar information to CPUID leaf 0xb (Intel's Extended
+Topology Enumeration leaf), and should be included in the output of
+KVM_GET_SUPPORTED_CPUID, even though userspace is likely to override
+some of this information based upon the configuration of the
+particular VM.
+
+Cc: Brijesh Singh <brijesh.singh@amd.com>
+Cc: Borislav Petkov <bp@suse.de>
+Fixes: 8765d75329a38 ("KVM: X86: Extend CPUID range to include new leaf")
+Signed-off-by: Jim Mattson <jmattson@google.com>
+Reviewed-by: Marc Orr <marcorr@google.com>
+Reviewed-by: Borislav Petkov <bp@suse.de>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Acked-by: Borislav Petkov <bp@suse.de>
+---
+ arch/x86/kvm/cpuid.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
+index 3c96ce8fbb96..e18a9f9f65b5 100644
+--- a/arch/x86/kvm/cpuid.c
++++ b/arch/x86/kvm/cpuid.c
+@@ -702,6 +702,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
+ entry->ecx = entry->edx = 0;
+ break;
+ case 0x8000001a:
++ case 0x8000001e:
+ break;
+ /*Add support for Centaur's CPUID instruction*/
+ case 0xC0000000:
+
diff --git a/patches.arch/kvm-x86-include-multiple-indices-with-cpuid-leaf-0x8000001d.patch b/patches.arch/kvm-x86-include-multiple-indices-with-cpuid-leaf-0x8000001d.patch
new file mode 100644
index 0000000000..96647bad22
--- /dev/null
+++ b/patches.arch/kvm-x86-include-multiple-indices-with-cpuid-leaf-0x8000001d.patch
@@ -0,0 +1,57 @@
+From: Jim Mattson <jmattson@google.com>
+Date: Wed, 27 Mar 2019 13:15:36 -0700
+Subject: kvm: x86: Include multiple indices with CPUID leaf 0x8000001d
+Git-commit: 32a243df82c8dc04ccba7fc6c6564ae9261cb738
+Patch-mainline: v5.2-rc2
+References: bsc#1114279
+
+Per the APM, "CPUID Fn8000_001D_E[D,C,B,A]X reports cache topology
+information for the cache enumerated by the value passed to the
+instruction in ECX, referred to as Cache n in the following
+description. To gather information for all cache levels, software must
+repeatedly execute CPUID with 8000_001Dh in EAX and ECX set to
+increasing values beginning with 0 until a value of 00h is returned in
+the field CacheType (EAX[4:0]) indicating no more cache descriptions
+are available for this processor."
+
+The termination condition is the same as leaf 4, so we can reuse that
+code block for leaf 0x8000001d.
+
+Fixes: 8765d75329a38 ("KVM: X86: Extend CPUID range to include new leaf")
+Cc: Brijesh Singh <brijesh.singh@amd.com>
+Cc: Borislav Petkov <bp@suse.de>
+Signed-off-by: Jim Mattson <jmattson@google.com>
+Reviewed-by: Marc Orr <marcorr@google.com>
+Reviewed-by: Borislav Petkov <bp@suse.de>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Acked-by: Borislav Petkov <bp@suse.de>
+---
+ arch/x86/kvm/cpuid.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
+index 80a642a0143d..3c96ce8fbb96 100644
+--- a/arch/x86/kvm/cpuid.c
++++ b/arch/x86/kvm/cpuid.c
+@@ -456,8 +456,9 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
+ }
+ break;
+ }
+- /* function 4 has additional index. */
+- case 4: {
++ /* functions 4 and 0x8000001d have additional index. */
++ case 4:
++ case 0x8000001d: {
+ int i, cache_type;
+
+ entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+@@ -702,8 +703,6 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
+ break;
+ case 0x8000001a:
+ break;
+- case 0x8000001d:
+- break;
+ /*Add support for Centaur's CPUID instruction*/
+ case 0xC0000000:
+ /*Just support up to 0xC0000004 now*/
+
diff --git a/patches.arch/powerpc-cacheinfo-add-cacheinfo_teardown-cacheinfo_r.patch b/patches.arch/powerpc-cacheinfo-add-cacheinfo_teardown-cacheinfo_r.patch
new file mode 100644
index 0000000000..05aa8da393
--- /dev/null
+++ b/patches.arch/powerpc-cacheinfo-add-cacheinfo_teardown-cacheinfo_r.patch
@@ -0,0 +1,72 @@
+From d4aa219a074a5abaf95a756b9f0d190b5c03a945 Mon Sep 17 00:00:00 2001
+From: Nathan Lynch <nathanl@linux.ibm.com>
+Date: Tue, 11 Jun 2019 23:45:04 -0500
+Subject: [PATCH] powerpc/cacheinfo: add cacheinfo_teardown, cacheinfo_rebuild
+
+References: bsc#1138374, LTC#178199
+Patch-mainline: queued
+Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git
+Git-commit: d4aa219a074a5abaf95a756b9f0d190b5c03a945
+
+Allow external callers to force the cacheinfo code to release all its
+references to cache nodes, e.g. before processing device tree updates
+post-migration, and to rebuild the hierarchy afterward.
+
+CPU online/offline must be blocked by callers; enforce this.
+
+Fixes: 410bccf97881 ("powerpc/pseries: Partition migration in the kernel")
+Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
+Reviewed-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Acked-by: Michal Suchanek <msuchanek@suse.de>
+---
+ arch/powerpc/kernel/cacheinfo.c | 21 +++++++++++++++++++++
+ arch/powerpc/kernel/cacheinfo.h | 4 ++++
+ 2 files changed, 25 insertions(+)
+
+diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c
+index 862e2890bd3d..42c559efe060 100644
+--- a/arch/powerpc/kernel/cacheinfo.c
++++ b/arch/powerpc/kernel/cacheinfo.c
+@@ -896,4 +896,25 @@ void cacheinfo_cpu_offline(unsigned int cpu_id)
+ if (cache)
+ cache_cpu_clear(cache, cpu_id);
+ }
++
++void cacheinfo_teardown(void)
++{
++ unsigned int cpu;
++
++ lockdep_assert_cpus_held();
++
++ for_each_online_cpu(cpu)
++ cacheinfo_cpu_offline(cpu);
++}
++
++void cacheinfo_rebuild(void)
++{
++ unsigned int cpu;
++
++ lockdep_assert_cpus_held();
++
++ for_each_online_cpu(cpu)
++ cacheinfo_cpu_online(cpu);
++}
++
+ #endif /* (CONFIG_PPC_PSERIES && CONFIG_SUSPEND) || CONFIG_HOTPLUG_CPU */
+diff --git a/arch/powerpc/kernel/cacheinfo.h b/arch/powerpc/kernel/cacheinfo.h
+index 955f5e999f1b..52bd3fc6642d 100644
+--- a/arch/powerpc/kernel/cacheinfo.h
++++ b/arch/powerpc/kernel/cacheinfo.h
+@@ -6,4 +6,8 @@
+ extern void cacheinfo_cpu_online(unsigned int cpu_id);
+ extern void cacheinfo_cpu_offline(unsigned int cpu_id);
+
++/* Allow migration/suspend to tear down and rebuild the hierarchy. */
++extern void cacheinfo_teardown(void);
++extern void cacheinfo_rebuild(void);
++
+ #endif /* _PPC_CACHEINFO_H */
+--
+2.21.0
+
diff --git a/patches.arch/powerpc-pseries-Fix-oops-in-hotplug-memory-notifier.patch b/patches.arch/powerpc-pseries-Fix-oops-in-hotplug-memory-notifier.patch
new file mode 100644
index 0000000000..d546c9e250
--- /dev/null
+++ b/patches.arch/powerpc-pseries-Fix-oops-in-hotplug-memory-notifier.patch
@@ -0,0 +1,44 @@
+From 0aa82c482ab2ece530a6f44897b63b274bb43c8e Mon Sep 17 00:00:00 2001
+From: Nathan Lynch <nathanl@linux.ibm.com>
+Date: Fri, 7 Jun 2019 00:04:07 -0500
+Subject: [PATCH] powerpc/pseries: Fix oops in hotplug memory notifier
+
+References: bsc#1138375, LTC#178204
+Patch-mainline: queued
+Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git
+Git-commit: 0aa82c482ab2ece530a6f44897b63b274bb43c8e
+
+During post-migration device tree updates, we can oops in
+pseries_update_drconf_memory() if the source device tree has an
+ibm,dynamic-memory-v2 property and the destination has a
+ibm,dynamic_memory (v1) property. The notifier processes an "update"
+for the ibm,dynamic-memory property but it's really an add in this
+scenario. So make sure the old property object is there before
+dereferencing it.
+
+Fixes: 2b31e3aec1db ("powerpc/drmem: Add support for ibm, dynamic-memory-v2 property")
+Cc: stable@vger.kernel.org # v4.16+
+Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Acked-by: Michal Suchanek <msuchanek@suse.de>
+---
+ arch/powerpc/platforms/pseries/hotplug-memory.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
+index 47087832f8b2..e6bd172bcf30 100644
+--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
++++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
+@@ -980,6 +980,9 @@ static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
+ if (!memblock_size)
+ return -EINVAL;
+
++ if (!pr->old_prop)
++ return 0;
++
+ p = (__be32 *) pr->old_prop->value;
+ if (!p)
+ return -EINVAL;
+--
+2.21.0
+
diff --git a/patches.arch/powerpc-pseries-dlpar-Fix-a-missing-check-in-dlpar_p.patch b/patches.arch/powerpc-pseries-dlpar-Fix-a-missing-check-in-dlpar_p.patch
new file mode 100644
index 0000000000..412f1cfa75
--- /dev/null
+++ b/patches.arch/powerpc-pseries-dlpar-Fix-a-missing-check-in-dlpar_p.patch
@@ -0,0 +1,40 @@
+From efa9ace68e487ddd29c2b4d6dd23242158f1f607 Mon Sep 17 00:00:00 2001
+From: Gen Zhang <blackgod016574@gmail.com>
+Date: Sun, 26 May 2019 10:42:40 +0800
+Subject: [PATCH] powerpc/pseries/dlpar: Fix a missing check in
+ dlpar_parse_cc_property()
+
+References: bsc#1137194, CVE-2019-12614
+Patch-mainline: queued
+Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git
+Git-commit: efa9ace68e487ddd29c2b4d6dd23242158f1f607
+
+In dlpar_parse_cc_property(), 'prop->name' is allocated by kstrdup().
+kstrdup() may return NULL, so it should be checked and handle error.
+And prop should be freed if 'prop->name' is NULL.
+
+Signed-off-by: Gen Zhang <blackgod016574@gmail.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Acked-by: Michal Suchanek <msuchanek@suse.de>
+---
+ arch/powerpc/platforms/pseries/dlpar.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
+index 17958043e7f7..c852024044bb 100644
+--- a/arch/powerpc/platforms/pseries/dlpar.c
++++ b/arch/powerpc/platforms/pseries/dlpar.c
+@@ -61,6 +61,10 @@ static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa)
+
+ name = (char *)ccwa + be32_to_cpu(ccwa->name_offset);
+ prop->name = kstrdup(name, GFP_KERNEL);
++ if (!prop->name) {
++ dlpar_free_cc_property(prop);
++ return NULL;
++ }
+
+ prop->length = be32_to_cpu(ccwa->prop_length);
+ value = (char *)ccwa + be32_to_cpu(ccwa->prop_offset);
+--
+2.21.0
+
diff --git a/patches.arch/powerpc-pseries-mobility-prevent-cpu-hotplug-during-.patch b/patches.arch/powerpc-pseries-mobility-prevent-cpu-hotplug-during-.patch
new file mode 100644
index 0000000000..b6b768e89a
--- /dev/null
+++ b/patches.arch/powerpc-pseries-mobility-prevent-cpu-hotplug-during-.patch
@@ -0,0 +1,61 @@
+From e59a175faa8df9d674247946f2a5a9c29c835725 Mon Sep 17 00:00:00 2001
+From: Nathan Lynch <nathanl@linux.ibm.com>
+Date: Tue, 11 Jun 2019 23:45:05 -0500
+Subject: [PATCH] powerpc/pseries/mobility: prevent cpu hotplug during DT
+ update
+
+References: bsc#1138374, LTC#178199
+Patch-mainline: queued
+Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git
+Git-commit: e59a175faa8df9d674247946f2a5a9c29c835725
+
+CPU online/offline code paths are sensitive to parts of the device
+tree (various cpu node properties, cache nodes) that can be changed as
+a result of a migration.
+
+Prevent CPU hotplug while the device tree potentially is inconsistent.
+
+Fixes: 410bccf97881 ("powerpc/pseries: Partition migration in the kernel")
+Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
+Reviewed-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Acked-by: Michal Suchanek <msuchanek@suse.de>
+---
+ arch/powerpc/platforms/pseries/mobility.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c
+index 88925f8ca8a0..edc1ec408589 100644
+--- a/arch/powerpc/platforms/pseries/mobility.c
++++ b/arch/powerpc/platforms/pseries/mobility.c
+@@ -9,6 +9,7 @@
+ * 2 as published by the Free Software Foundation.
+ */
+
++#include <linux/cpu.h>
+ #include <linux/kernel.h>
+ #include <linux/kobject.h>
+ #include <linux/smp.h>
+@@ -338,11 +339,19 @@ void post_mobility_fixup(void)
+ if (rc)
+ printk(KERN_ERR "Post-mobility activate-fw failed: %d\n", rc);
+
++ /*
++ * We don't want CPUs to go online/offline while the device
++ * tree is being updated.
++ */
++ cpus_read_lock();
++
+ rc = pseries_devicetree_update(MIGRATION_SCOPE);
+ if (rc)
+ printk(KERN_ERR "Post-mobility device tree update "
+ "failed: %d\n", rc);
+
++ cpus_read_unlock();
++
+ /* Possibly switch to a new RFI flush type */
+ pseries_setup_rfi_flush();
+
+--
+2.21.0
+
diff --git a/patches.arch/powerpc-pseries-mobility-rebuild-cacheinfo-hierarchy.patch b/patches.arch/powerpc-pseries-mobility-rebuild-cacheinfo-hierarchy.patch
new file mode 100644
index 0000000000..5ca26871a7
--- /dev/null
+++ b/patches.arch/powerpc-pseries-mobility-rebuild-cacheinfo-hierarchy.patch
@@ -0,0 +1,83 @@
+From e610a466d16a086e321f0bd421e2fc75cff28605 Mon Sep 17 00:00:00 2001
+From: Nathan Lynch <nathanl@linux.ibm.com>
+Date: Tue, 11 Jun 2019 23:45:06 -0500
+Subject: [PATCH] powerpc/pseries/mobility: rebuild cacheinfo hierarchy
+ post-migration
+
+References: bsc#1138374, LTC#178199
+Patch-mainline: queued
+Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git
+Git-commit: e610a466d16a086e321f0bd421e2fc75cff28605
+
+It's common for the platform to replace the cache device nodes after a
+migration. Since the cacheinfo code is never informed about this, it
+never drops its references to the source system's cache nodes, causing
+it to wind up in an inconsistent state resulting in warnings and oopses
+as soon as CPU online/offline occurs after the migration, e.g.
+
+ cache for /cpus/l3-cache@3113(Unified) refers to cache for /cpus/l2-cache@200d(Unified)
+ WARNING: CPU: 15 PID: 86 at arch/powerpc/kernel/cacheinfo.c:176 release_cache+0x1bc/0x1d0
+ [...]
+ NIP release_cache+0x1bc/0x1d0
+ LR release_cache+0x1b8/0x1d0
+ Call Trace:
+ release_cache+0x1b8/0x1d0 (unreliable)
+ cacheinfo_cpu_offline+0x1c4/0x2c0
+ unregister_cpu_online+0x1b8/0x260
+ cpuhp_invoke_callback+0x114/0xf40
+ cpuhp_thread_fun+0x270/0x310
+ smpboot_thread_fn+0x2c8/0x390
+ kthread+0x1b8/0x1c0
+ ret_from_kernel_thread+0x5c/0x68
+
+Using device tree notifiers won't work since we want to rebuild the
+hierarchy only after all the removals and additions have occurred and
+the device tree is in a consistent state. Call cacheinfo_teardown()
+before processing device tree updates, and rebuild the hierarchy
+afterward.
+
+Fixes: 410bccf97881 ("powerpc/pseries: Partition migration in the kernel")
+Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
+Reviewed-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Acked-by: Michal Suchanek <msuchanek@suse.de>
+---
+ arch/powerpc/platforms/pseries/mobility.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c
+index edc1ec408589..b8c8096907d4 100644
+--- a/arch/powerpc/platforms/pseries/mobility.c
++++ b/arch/powerpc/platforms/pseries/mobility.c
+@@ -23,6 +23,7 @@
+ #include <asm/machdep.h>
+ #include <asm/rtas.h>
+ #include "pseries.h"
++#include "../../kernel/cacheinfo.h"
+
+ static struct kobject *mobility_kobj;
+
+@@ -345,11 +346,20 @@ void post_mobility_fixup(void)
+ */
+ cpus_read_lock();
+
++ /*
++ * It's common for the destination firmware to replace cache
++ * nodes. Release all of the cacheinfo hierarchy's references
++ * before updating the device tree.
++ */
++ cacheinfo_teardown();
++
+ rc = pseries_devicetree_update(MIGRATION_SCOPE);
+ if (rc)
+ printk(KERN_ERR "Post-mobility device tree update "
+ "failed: %d\n", rc);
+
++ cacheinfo_rebuild();
++
+ cpus_read_unlock();
+
+ /* Possibly switch to a new RFI flush type */
+--
+2.21.0
+
diff --git a/patches.arch/s390-airq-provide-cacheline-aligned-ivs b/patches.arch/s390-airq-provide-cacheline-aligned-ivs
new file mode 100644
index 0000000000..cb6090cd53
--- /dev/null
+++ b/patches.arch/s390-airq-provide-cacheline-aligned-ivs
@@ -0,0 +1,114 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Wed, 27 Feb 2019 13:56:08 +0100
+Subject: s390/airq: provide cacheline aligned ivs
+Git-commit: 414cbd1e3d14ec0e60666a0fb9d8ae2d77eb7c63
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5789 FATE#327042 bsc#1134730 LTC#173388
+
+Provide the ability to create cachesize aligned interrupt vectors.
+These will be used for per-CPU interrupt vectors.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/include/asm/airq.h | 10 ++++++----
+ drivers/s390/cio/airq.c | 39 ++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 40 insertions(+), 9 deletions(-)
+
+--- a/arch/s390/include/asm/airq.h
++++ b/arch/s390/include/asm/airq.h
+@@ -34,13 +34,15 @@ struct airq_iv {
+ unsigned int *data; /* 32 bit value associated with each bit */
+ unsigned long bits; /* Number of bits in the vector */
+ unsigned long end; /* Number of highest allocated bit + 1 */
++ unsigned long flags; /* Allocation flags */
+ spinlock_t lock; /* Lock to protect alloc & free */
+ };
+
+-#define AIRQ_IV_ALLOC 1 /* Use an allocation bit mask */
+-#define AIRQ_IV_BITLOCK 2 /* Allocate the lock bit mask */
+-#define AIRQ_IV_PTR 4 /* Allocate the ptr array */
+-#define AIRQ_IV_DATA 8 /* Allocate the data array */
++#define AIRQ_IV_ALLOC 1 /* Use an allocation bit mask */
++#define AIRQ_IV_BITLOCK 2 /* Allocate the lock bit mask */
++#define AIRQ_IV_PTR 4 /* Allocate the ptr array */
++#define AIRQ_IV_DATA 8 /* Allocate the data array */
++#define AIRQ_IV_CACHELINE 16 /* Cacheline alignment for the vector */
+
+ struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags);
+ void airq_iv_release(struct airq_iv *iv);
+--- a/drivers/s390/cio/airq.c
++++ b/drivers/s390/cio/airq.c
+@@ -26,6 +26,8 @@
+ static DEFINE_SPINLOCK(airq_lists_lock);
+ static struct hlist_head airq_lists[MAX_ISC+1];
+
++static struct kmem_cache *airq_iv_cache;
++
+ /**
+ * register_adapter_interrupt() - register adapter interrupt handler
+ * @airq: pointer to adapter interrupt descriptor
+@@ -128,10 +130,21 @@ struct airq_iv *airq_iv_create(unsigned
+ if (!iv)
+ goto out;
+ iv->bits = bits;
++ iv->flags = flags;
+ size = BITS_TO_LONGS(bits) * sizeof(unsigned long);
+- iv->vector = kzalloc(size, GFP_KERNEL);
+- if (!iv->vector)
+- goto out_free;
++
++ if (flags & AIRQ_IV_CACHELINE) {
++ if ((cache_line_size() * BITS_PER_BYTE) < bits)
++ goto out_free;
++
++ iv->vector = kmem_cache_zalloc(airq_iv_cache, GFP_KERNEL);
++ if (!iv->vector)
++ goto out_free;
++ } else {
++ iv->vector = kzalloc(size, GFP_KERNEL);
++ if (!iv->vector)
++ goto out_free;
++ }
+ if (flags & AIRQ_IV_ALLOC) {
+ iv->avail = kmalloc(size, GFP_KERNEL);
+ if (!iv->avail)
+@@ -164,7 +177,10 @@ out_free:
+ kfree(iv->ptr);
+ kfree(iv->bitlock);
+ kfree(iv->avail);
+- kfree(iv->vector);
++ if (iv->flags & AIRQ_IV_CACHELINE)
++ kmem_cache_free(airq_iv_cache, iv->vector);
++ else
++ kfree(iv->vector);
+ kfree(iv);
+ out:
+ return NULL;
+@@ -180,7 +196,10 @@ void airq_iv_release(struct airq_iv *iv)
+ kfree(iv->data);
+ kfree(iv->ptr);
+ kfree(iv->bitlock);
+- kfree(iv->vector);
++ if (iv->flags & AIRQ_IV_CACHELINE)
++ kmem_cache_free(airq_iv_cache, iv->vector);
++ else
++ kfree(iv->vector);
+ kfree(iv->avail);
+ kfree(iv);
+ }
+@@ -274,3 +293,13 @@ unsigned long airq_iv_scan(struct airq_i
+ return bit;
+ }
+ EXPORT_SYMBOL(airq_iv_scan);
++
++static int __init airq_init(void)
++{
++ airq_iv_cache = kmem_cache_create("airq_iv_cache", cache_line_size(),
++ cache_line_size(), 0, NULL);
++ if (!airq_iv_cache)
++ return -ENOMEM;
++ return 0;
++}
++subsys_initcall(airq_init);
diff --git a/patches.arch/s390-airq-recognize-directed-interrupts b/patches.arch/s390-airq-recognize-directed-interrupts
new file mode 100644
index 0000000000..38a819649e
--- /dev/null
+++ b/patches.arch/s390-airq-recognize-directed-interrupts
@@ -0,0 +1,121 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Sun, 28 Oct 2018 11:51:56 +0100
+Subject: s390/airq: recognize directed interrupts
+Git-commit: 30e63ef2ef43f014bf2039bd57cc917780d6a44b
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5789 FATE#327042 bsc#1134730 LTC#173388
+
+Add an extra parameter for airq handlers to recognize
+floating vs. directed interrupts.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+[ ptesarik: Removed the hunk that patches gib_alert_irq_handler in
+ arch/s390/kvm/interrupt.c, because it depends on upstream commit
+ 9f30f62163786a0b80e0886046b5c66e714e7e71. ]
+Signed-off-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/include/asm/airq.h | 2 +-
+ arch/s390/pci/pci_irq.c | 2 +-
+ drivers/s390/cio/airq.c | 2 +-
+ drivers/s390/cio/cio.h | 2 +-
+ drivers/s390/cio/qdio_thinint.c | 4 ++--
+ drivers/s390/crypto/ap_bus.c | 4 ++--
+ drivers/s390/virtio/virtio_ccw.c | 2 +-
+ 7 files changed, 9 insertions(+), 9 deletions(-)
+
+--- a/arch/s390/include/asm/airq.h
++++ b/arch/s390/include/asm/airq.h
+@@ -13,7 +13,7 @@
+
+ struct airq_struct {
+ struct hlist_node list; /* Handler queueing. */
+- void (*handler)(struct airq_struct *); /* Thin-interrupt handler */
++ void (*handler)(struct airq_struct *airq, bool floating);
+ u8 *lsi_ptr; /* Local-Summary-Indicator pointer */
+ u8 lsi_mask; /* Local-Summary-Indicator mask */
+ u8 isc; /* Interrupt-subclass */
+--- a/arch/s390/pci/pci_irq.c
++++ b/arch/s390/pci/pci_irq.c
+@@ -56,7 +56,7 @@ static struct irq_chip zpci_irq_chip = {
+ .irq_mask = pci_msi_mask_irq,
+ };
+
+-static void zpci_irq_handler(struct airq_struct *airq)
++static void zpci_irq_handler(struct airq_struct *airq, bool floating)
+ {
+ unsigned long si, ai;
+ struct airq_iv *aibv;
+--- a/drivers/s390/cio/airq.c
++++ b/drivers/s390/cio/airq.c
+@@ -94,7 +94,7 @@ static irqreturn_t do_airq_interrupt(int
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(airq, head, list)
+ if ((*airq->lsi_ptr & airq->lsi_mask) != 0)
+- airq->handler(airq);
++ airq->handler(airq, !tpi_info->directed_irq);
+ rcu_read_unlock();
+
+ return IRQ_HANDLED;
+--- a/drivers/s390/cio/cio.h
++++ b/drivers/s390/cio/cio.h
+@@ -50,7 +50,7 @@ struct tpi_info {
+ struct subchannel_id schid;
+ u32 intparm;
+ u32 adapter_IO:1;
+- u32 :1;
++ u32 directed_irq:1;
+ u32 isc:3;
+ u32 :27;
+ u32 type:3;
+--- a/drivers/s390/cio/qdio_thinint.c
++++ b/drivers/s390/cio/qdio_thinint.c
+@@ -39,7 +39,7 @@ static LIST_HEAD(tiq_list);
+ static DEFINE_MUTEX(tiq_list_lock);
+
+ /* Adapter interrupt definitions */
+-static void tiqdio_thinint_handler(struct airq_struct *airq);
++static void tiqdio_thinint_handler(struct airq_struct *airq, bool floating);
+
+ static struct airq_struct tiqdio_airq = {
+ .handler = tiqdio_thinint_handler,
+@@ -182,7 +182,7 @@ static inline void tiqdio_call_inq_handl
+ * tiqdio_thinint_handler - thin interrupt handler for qdio
+ * @airq: pointer to adapter interrupt descriptor
+ */
+-static void tiqdio_thinint_handler(struct airq_struct *airq)
++static void tiqdio_thinint_handler(struct airq_struct *airq, bool floating)
+ {
+ u32 si_used = clear_shared_ind();
+ struct qdio_q *q;
+--- a/drivers/s390/crypto/ap_bus.c
++++ b/drivers/s390/crypto/ap_bus.c
+@@ -130,7 +130,7 @@ static int user_set_domain;
+ static struct bus_type ap_bus_type;
+
+ /* Adapter interrupt definitions */
+-static void ap_interrupt_handler(struct airq_struct *airq);
++static void ap_interrupt_handler(struct airq_struct *airq, bool floating);
+
+ static int ap_airq_flag;
+
+@@ -407,7 +407,7 @@ static enum hrtimer_restart ap_poll_time
+ * ap_interrupt_handler() - Schedule ap_tasklet on interrupt
+ * @airq: pointer to adapter interrupt descriptor
+ */
+-static void ap_interrupt_handler(struct airq_struct *airq)
++static void ap_interrupt_handler(struct airq_struct *airq, bool floating)
+ {
+ inc_irq_stat(IRQIO_APB);
+ if (!ap_suspend_flag)
+--- a/drivers/s390/virtio/virtio_ccw.c
++++ b/drivers/s390/virtio/virtio_ccw.c
+@@ -185,7 +185,7 @@ static void drop_airq_indicator(struct v
+ write_unlock_irqrestore(&info->lock, flags);
+ }
+
+-static void virtio_airq_handler(struct airq_struct *airq)
++static void virtio_airq_handler(struct airq_struct *airq, bool floating)
+ {
+ struct airq_info *info = container_of(airq, struct airq_info, airq);
+ unsigned long ai;
diff --git a/patches.arch/s390-enable-processes-for-mio-instructions b/patches.arch/s390-enable-processes-for-mio-instructions
new file mode 100644
index 0000000000..0abcdfefdb
--- /dev/null
+++ b/patches.arch/s390-enable-processes-for-mio-instructions
@@ -0,0 +1,52 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Tue, 23 Apr 2019 13:14:28 +0200
+Subject: s390: enable processes for mio instructions
+Git-commit: 833b441ec0f6f3c57cc2106ef628bb19d8fb0ee2
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5802 FATE#327055 bsc#1134738 LTC#173387
+
+Allow for userspace to use PCI MIO instructions.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/include/asm/pci_insn.h | 10 ++++++++++
+ arch/s390/kernel/early.c | 2 ++
+ 2 files changed, 12 insertions(+)
+
+--- a/arch/s390/include/asm/pci_insn.h
++++ b/arch/s390/include/asm/pci_insn.h
+@@ -142,4 +142,14 @@ static inline int zpci_set_irq_ctrl(u16
+ return __zpci_set_irq_ctrl(ctl, isc, &iib);
+ }
+
++#ifdef CONFIG_PCI
++static inline void enable_mio_ctl(void)
++{
++ if (static_branch_likely(&have_mio))
++ __ctl_set_bit(2, 5);
++}
++#else /* CONFIG_PCI */
++static inline void enable_mio_ctl(void) {}
++#endif /* CONFIG_PCI */
++
+ #endif
+--- a/arch/s390/kernel/early.c
++++ b/arch/s390/kernel/early.c
+@@ -28,6 +28,7 @@
+ #include <asm/sclp.h>
+ #include <asm/facility.h>
+ #include <asm/uv.h>
++#include <asm/pci_insn.h>
+ #include "entry.h"
+
+ /*
+@@ -394,6 +395,7 @@ static __init void detect_machine_facili
+ }
+ if (test_facility(133))
+ S390_lowcore.machine_flags |= MACHINE_FLAG_GS;
++ enable_mio_ctl();
+ }
+
+ static inline void save_vector_registers(void)
diff --git a/patches.arch/s390-ism-move-oddities-of-device-io-to-wrapper-function b/patches.arch/s390-ism-move-oddities-of-device-io-to-wrapper-function
new file mode 100644
index 0000000000..335d615786
--- /dev/null
+++ b/patches.arch/s390-ism-move-oddities-of-device-io-to-wrapper-function
@@ -0,0 +1,135 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Tue, 23 Apr 2019 11:57:46 +0200
+Subject: s390/ism: move oddities of device IO to wrapper function
+Git-commit: c475f1770a5e062652a6a877afcbd4e22b18039f
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5802 FATE#327055 bsc#1134738 LTC#173387
+
+ISM devices are special in how they access PCI memory space. Provide
+wrappers for handling commands to the device. No functional change.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ drivers/s390/net/ism.h | 27 +++++++++++++++++++++++++--
+ drivers/s390/net/ism_drv.c | 20 ++++++--------------
+ 2 files changed, 31 insertions(+), 16 deletions(-)
+
+--- a/drivers/s390/net/ism.h
++++ b/drivers/s390/net/ism.h
+@@ -6,6 +6,7 @@
+ #include <linux/types.h>
+ #include <linux/pci.h>
+ #include <net/smc.h>
++#include <asm/pci_insn.h>
+
+ #define UTIL_STR_LEN 16
+
+@@ -194,8 +195,6 @@ struct ism_dev {
+ struct pci_dev *pdev;
+ struct smcd_dev *smcd;
+
+- void __iomem *ctl;
+-
+ struct ism_sba *sba;
+ dma_addr_t sba_dma_addr;
+ DECLARE_BITMAP(sba_bitmap, ISM_NR_DMBS);
+@@ -209,6 +208,30 @@ struct ism_dev {
+ #define ISM_CREATE_REQ(dmb, idx, sf, offset) \
+ ((dmb) | (idx) << 24 | (sf) << 23 | (offset))
+
++static inline void __ism_read_cmd(struct ism_dev *ism, void *data,
++ unsigned long offset, unsigned long len)
++{
++ struct zpci_dev *zdev = to_zpci(ism->pdev);
++ u64 req = ZPCI_CREATE_REQ(zdev->fh, 2, 8);
++
++ while (len > 0) {
++ __zpci_load(data, req, offset);
++ offset += 8;
++ data += 8;
++ len -= 8;
++ }
++}
++
++static inline void __ism_write_cmd(struct ism_dev *ism, void *data,
++ unsigned long offset, unsigned long len)
++{
++ struct zpci_dev *zdev = to_zpci(ism->pdev);
++ u64 req = ZPCI_CREATE_REQ(zdev->fh, 2, len);
++
++ if (len)
++ __zpci_store_block(data, req, offset);
++}
++
+ static inline int __ism_move(struct ism_dev *ism, u64 dmb_req, void *data,
+ unsigned int size)
+ {
+--- a/drivers/s390/net/ism_drv.c
++++ b/drivers/s390/net/ism_drv.c
+@@ -38,19 +38,18 @@ static int ism_cmd(struct ism_dev *ism,
+ struct ism_req_hdr *req = cmd;
+ struct ism_resp_hdr *resp = cmd;
+
+- memcpy_toio(ism->ctl + sizeof(*req), req + 1, req->len - sizeof(*req));
+- memcpy_toio(ism->ctl, req, sizeof(*req));
++ __ism_write_cmd(ism, req + 1, sizeof(*req), req->len - sizeof(*req));
++ __ism_write_cmd(ism, req, 0, sizeof(*req));
+
+ WRITE_ONCE(resp->ret, ISM_ERROR);
+
+- memcpy_fromio(resp, ism->ctl, sizeof(*resp));
++ __ism_read_cmd(ism, resp, 0, sizeof(*resp));
+ if (resp->ret) {
+ debug_text_event(ism_debug_info, 0, "cmd failure");
+ debug_event(ism_debug_info, 0, resp, sizeof(*resp));
+ goto out;
+ }
+- memcpy_fromio(resp + 1, ism->ctl + sizeof(*resp),
+- resp->len - sizeof(*resp));
++ __ism_read_cmd(ism, resp + 1, sizeof(*resp), resp->len - sizeof(*resp));
+ out:
+ return resp->ret;
+ }
+@@ -513,13 +512,9 @@ static int ism_probe(struct pci_dev *pde
+ if (ret)
+ goto err_disable;
+
+- ism->ctl = pci_iomap(pdev, 2, 0);
+- if (!ism->ctl)
+- goto err_resource;
+-
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (ret)
+- goto err_unmap;
++ goto err_resource;
+
+ pci_set_dma_seg_boundary(pdev, SZ_1M - 1);
+ pci_set_dma_max_seg_size(pdev, SZ_1M);
+@@ -528,7 +523,7 @@ static int ism_probe(struct pci_dev *pde
+ ism->smcd = smcd_alloc_dev(&pdev->dev, dev_name(&pdev->dev), &ism_ops,
+ ISM_NR_DMBS);
+ if (!ism->smcd)
+- goto err_unmap;
++ goto err_resource;
+
+ ism->smcd->priv = ism;
+ ret = ism_dev_init(ism);
+@@ -539,8 +534,6 @@ static int ism_probe(struct pci_dev *pde
+
+ err_free:
+ smcd_free_dev(ism->smcd);
+-err_unmap:
+- pci_iounmap(pdev, ism->ctl);
+ err_resource:
+ pci_release_mem_regions(pdev);
+ err_disable:
+@@ -569,7 +562,6 @@ static void ism_remove(struct pci_dev *p
+ ism_dev_exit(ism);
+
+ smcd_free_dev(ism->smcd);
+- pci_iounmap(pdev, ism->ctl);
+ pci_release_mem_regions(pdev);
+ pci_disable_device(pdev);
+ dev_set_drvdata(&pdev->dev, NULL);
diff --git a/patches.arch/s390-jump_label-Use-jdd-constraint-on-gcc9.patch b/patches.arch/s390-jump_label-Use-jdd-constraint-on-gcc9.patch
new file mode 100644
index 0000000000..d6f09a9478
--- /dev/null
+++ b/patches.arch/s390-jump_label-Use-jdd-constraint-on-gcc9.patch
@@ -0,0 +1,72 @@
+From 146448524bddbf6dfc62de31957e428de001cbda Mon Sep 17 00:00:00 2001
+From: Ilya Leoshkevich <iii@linux.ibm.com>
+Date: Wed, 6 Feb 2019 12:35:58 +0100
+Subject: [PATCH] s390/jump_label: Use "jdd" constraint on gcc9
+
+References: bsc#1138589
+Patch-mainline: v5.1-rc1
+Git-commit: 146448524bddbf6dfc62de31957e428de001cbda
+
+[heiko.carstens@de.ibm.com]:
+-----
+Laura Abbott reported that the kernel doesn't build anymore with gcc 9,
+due to the "X" constraint. Ilya provided the gcc 9 patch "S/390:
+Introduce jdd constraint" which introduces the new "jdd" constraint
+which fixes this.
+-----
+
+The support for section anchors on S/390 introduced in gcc9 has changed
+the behavior of "X" constraint, which can now produce register
+references. Since existing constraints, in particular, "i", do not fit
+the intended use case on S/390, the new machine-specific "jdd"
+constraint was introduced. This patch makes jump labels use "jdd"
+constraint when building with gcc9.
+
+Reported-by: Laura Abbott <labbott@redhat.com>
+Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
+Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Michal Suchanek <msuchanek@suse.de>
+---
+ arch/s390/include/asm/jump_label.h | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+--- a/arch/s390/include/asm/jump_label.h
++++ b/arch/s390/include/asm/jump_label.h
+@@ -9,6 +9,12 @@
+ #define JUMP_LABEL_NOP_SIZE 6
+ #define JUMP_LABEL_NOP_OFFSET 2
+
++#if __GNUC__ < 9
++#define JUMP_LABEL_STATIC_KEY_CONSTRAINT "X"
++#else
++#define JUMP_LABEL_STATIC_KEY_CONSTRAINT "jdd"
++#endif
++
+ /*
+ * We use a brcl 0,2 instruction for jump labels at compile time so it
+ * can be easily distinguished from a hotpatch generated instruction.
+@@ -18,9 +24,9 @@ static __always_inline bool arch_static_
+ asm_volatile_goto("0: brcl 0,"__stringify(JUMP_LABEL_NOP_OFFSET)"\n"
+ ".pushsection __jump_table, \"aw\"\n"
+ ".balign 8\n"
+- ".quad 0b, %l[label], %0\n"
++ ".quad 0b, %l[label], %0+%1\n"
+ ".popsection\n"
+- : : "X" (&((char *)key)[branch]) : : label);
++ : : JUMP_LABEL_STATIC_KEY_CONSTRAINT (key), "i" (branch) : : label);
+
+ return false;
+ label:
+@@ -32,9 +38,9 @@ static __always_inline bool arch_static_
+ asm_volatile_goto("0: brcl 15, %l[label]\n"
+ ".pushsection __jump_table, \"aw\"\n"
+ ".balign 8\n"
+- ".quad 0b, %l[label], %0\n"
++ ".quad 0b, %l[label], %0+%1\n"
+ ".popsection\n"
+- : : "X" (&((char *)key)[branch]) : : label);
++ : : JUMP_LABEL_STATIC_KEY_CONSTRAINT (key), "i" (branch) : : label);
+
+ return false;
+ label:
diff --git a/patches.arch/s390-pci-add-parameter-to-disable-usage-of-mio-instructions b/patches.arch/s390-pci-add-parameter-to-disable-usage-of-mio-instructions
new file mode 100644
index 0000000000..8509068905
--- /dev/null
+++ b/patches.arch/s390-pci-add-parameter-to-disable-usage-of-mio-instructions
@@ -0,0 +1,58 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Thu, 18 Apr 2019 21:39:06 +0200
+Subject: s390/pci: add parameter to disable usage of MIO instructions
+Git-commit: 56271303808fb86375ec33183d56c21fdeb836ea
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5802 FATE#327055 bsc#1134738 LTC#173387
+
+Allow users to disable usage of MIO instructions by specifying pci=nomio
+at the kernel command line.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ Documentation/admin-guide/kernel-parameters.txt | 1 +
+ arch/s390/pci/pci.c | 7 ++++++-
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+--- a/Documentation/admin-guide/kernel-parameters.txt
++++ b/Documentation/admin-guide/kernel-parameters.txt
+@@ -3200,6 +3200,7 @@
+ conflict with unreported devices), so this
+ taints the kernel.
+ force_floating [S390] Force usage of floating interrupts.
++ nomio [S390] Do not use MIO instructions.
+
+ pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power
+ Management.
+--- a/arch/s390/pci/pci.c
++++ b/arch/s390/pci/pci.c
+@@ -824,6 +824,7 @@ static void zpci_mem_exit(void)
+ }
+
+ static unsigned int s390_pci_probe __initdata = 1;
++static unsigned int s390_pci_no_mio __initdata;
+ unsigned int s390_pci_force_floating __initdata;
+ static unsigned int s390_pci_initialized;
+
+@@ -833,6 +834,10 @@ char * __init pcibios_setup(char *str)
+ s390_pci_probe = 0;
+ return NULL;
+ }
++ if (!strcmp(str, "nomio")) {
++ s390_pci_no_mio = 1;
++ return NULL;
++ }
+ if (!strcmp(str, "force_floating")) {
+ s390_pci_force_floating = 1;
+ return NULL;
+@@ -855,7 +860,7 @@ static int __init pci_base_init(void)
+ if (!test_facility(69) || !test_facility(71))
+ return 0;
+
+- if (test_facility(153))
++ if (test_facility(153) && !s390_pci_no_mio)
+ static_branch_enable(&have_mio);
+
+ rc = zpci_debug_init();
diff --git a/patches.arch/s390-pci-add-parameter-to-force-floating-irqs b/patches.arch/s390-pci-add-parameter-to-force-floating-irqs
new file mode 100644
index 0000000000..b84a668910
--- /dev/null
+++ b/patches.arch/s390-pci-add-parameter-to-force-floating-irqs
@@ -0,0 +1,72 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Tue, 26 Feb 2019 16:07:32 +0100
+Subject: s390/pci: add parameter to force floating irqs
+Git-commit: fbfe07d440f2c55070a0358f66560bb4f9fb92e7
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5789 FATE#327042 bsc#1134730 LTC#173388
+
+Provide a kernel parameter to force the usage of floating interrupts.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ Documentation/admin-guide/kernel-parameters.txt | 1 +
+ arch/s390/include/asm/pci.h | 1 +
+ arch/s390/pci/pci.c | 5 +++++
+ arch/s390/pci/pci_irq.c | 3 +++
+ 4 files changed, 10 insertions(+)
+
+--- a/Documentation/admin-guide/kernel-parameters.txt
++++ b/Documentation/admin-guide/kernel-parameters.txt
+@@ -3199,6 +3199,7 @@
+ Adding the window is slightly risky (it may
+ conflict with unreported devices), so this
+ taints the kernel.
++ force_floating [S390] Force usage of floating interrupts.
+
+ pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power
+ Management.
+--- a/arch/s390/include/asm/pci.h
++++ b/arch/s390/include/asm/pci.h
+@@ -157,6 +157,7 @@ static inline bool zdev_enabled(struct z
+ }
+
+ extern const struct attribute_group *zpci_attr_groups[];
++extern unsigned int s390_pci_force_floating __initdata;
+
+ /* -----------------------------------------------------------------------------
+ Prototypes
+--- a/arch/s390/pci/pci.c
++++ b/arch/s390/pci/pci.c
+@@ -714,6 +714,7 @@ static void zpci_mem_exit(void)
+ }
+
+ static unsigned int s390_pci_probe __initdata = 1;
++unsigned int s390_pci_force_floating __initdata;
+ static unsigned int s390_pci_initialized;
+
+ char * __init pcibios_setup(char *str)
+@@ -722,6 +723,10 @@ char * __init pcibios_setup(char *str)
+ s390_pci_probe = 0;
+ return NULL;
+ }
++ if (!strcmp(str, "force_floating")) {
++ s390_pci_force_floating = 1;
++ return NULL;
++ }
+ return str;
+ }
+
+--- a/arch/s390/pci/pci_irq.c
++++ b/arch/s390/pci/pci_irq.c
+@@ -433,6 +433,9 @@ int __init zpci_irq_init(void)
+ int rc;
+
+ irq_delivery = sclp.has_dirq ? DIRECTED : FLOATING;
++ if (s390_pci_force_floating)
++ irq_delivery = FLOATING;
++
+ if (irq_delivery == DIRECTED)
+ zpci_airq.handler = zpci_directed_irq_handler;
+
diff --git a/patches.arch/s390-pci-clarify-interrupt-vector-usage b/patches.arch/s390-pci-clarify-interrupt-vector-usage
new file mode 100644
index 0000000000..5b0c7daae8
--- /dev/null
+++ b/patches.arch/s390-pci-clarify-interrupt-vector-usage
@@ -0,0 +1,124 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Thu, 14 Feb 2019 12:56:50 +0100
+Subject: s390/pci: clarify interrupt vector usage
+Git-commit: b1f548645cb587c14f5e751b9163939d0723885f
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5789 FATE#327042 bsc#1134730 LTC#173388
+
+Rename and clarify the usage of the interrupt bit vectors. Also change
+the array of the per-function bit vectors to be dynamically allocated.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/pci/pci_irq.c | 38 ++++++++++++++++++++++++++------------
+ 1 file changed, 26 insertions(+), 12 deletions(-)
+
+--- a/arch/s390/pci/pci_irq.c
++++ b/arch/s390/pci/pci_irq.c
+@@ -14,8 +14,15 @@
+ #define SIC_IRQ_MODE_ALL 0
+ #define SIC_IRQ_MODE_SINGLE 1
+
+-static struct airq_iv *zpci_aisb_iv;
+-static struct airq_iv *zpci_aibv[ZPCI_NR_DEVICES];
++/*
++ * summary bit vector - one summary bit per function
++ */
++static struct airq_iv *zpci_sbv;
++
++/*
++ * interrupt bit vectors - one vector per function
++ */
++static struct airq_iv **zpci_ibv;
+
+ /* Modify PCI: Register adapter interruptions */
+ static int zpci_set_airq(struct zpci_dev *zdev)
+@@ -29,7 +36,7 @@ static int zpci_set_airq(struct zpci_dev
+ fib.noi = airq_iv_end(zdev->aibv);
+ fib.aibv = (unsigned long) zdev->aibv->vector;
+ fib.aibvo = 0; /* each zdev has its own interrupt vector */
+- fib.aisb = (unsigned long) zpci_aisb_iv->vector + (zdev->aisb/64)*8;
++ fib.aisb = (unsigned long) zpci_sbv->vector + (zdev->aisb/64)*8;
+ fib.aisbo = zdev->aisb & 63;
+
+ return zpci_mod_fc(req, &fib, &status) ? -EIO : 0;
+@@ -65,7 +72,7 @@ static void zpci_irq_handler(struct airq
+ inc_irq_stat(IRQIO_PCI);
+ for (si = 0;;) {
+ /* Scan adapter summary indicator bit vector */
+- si = airq_iv_scan(zpci_aisb_iv, si, airq_iv_end(zpci_aisb_iv));
++ si = airq_iv_scan(zpci_sbv, si, airq_iv_end(zpci_sbv));
+ if (si == -1UL) {
+ if (irqs_on++)
+ /* End of second scan with interrupts on. */
+@@ -78,7 +85,7 @@ static void zpci_irq_handler(struct airq
+ }
+
+ /* Scan the adapter interrupt vector for this device. */
+- aibv = zpci_aibv[si];
++ aibv = zpci_ibv[si];
+ for (ai = 0;;) {
+ ai = airq_iv_scan(aibv, ai, airq_iv_end(aibv));
+ if (ai == -1UL)
+@@ -106,7 +113,7 @@ int arch_setup_msi_irqs(struct pci_dev *
+ msi_vecs = min_t(unsigned int, nvec, zdev->max_msi);
+
+ /* Allocate adapter summary indicator bit */
+- aisb = airq_iv_alloc_bit(zpci_aisb_iv);
++ aisb = airq_iv_alloc_bit(zpci_sbv);
+ if (aisb == -1UL)
+ return -EIO;
+ zdev->aisb = aisb;
+@@ -117,7 +124,7 @@ int arch_setup_msi_irqs(struct pci_dev *
+ return -ENOMEM;
+
+ /* Wire up shortcut pointer */
+- zpci_aibv[aisb] = zdev->aibv;
++ zpci_ibv[aisb] = zdev->aibv;
+
+ /* Request MSI interrupts */
+ hwirq = 0;
+@@ -176,8 +183,8 @@ void arch_teardown_msi_irqs(struct pci_d
+ }
+
+ if (zdev->aisb != -1UL) {
+- zpci_aibv[zdev->aisb] = NULL;
+- airq_iv_free_bit(zpci_aisb_iv, zdev->aisb);
++ zpci_ibv[zdev->aisb] = NULL;
++ airq_iv_free_bit(zpci_sbv, zdev->aisb);
+ zdev->aisb = -1UL;
+ }
+ if (zdev->aibv) {
+@@ -202,13 +209,19 @@ int __init zpci_irq_init(void)
+ *zpci_airq.lsi_ptr = 1;
+
+ rc = -ENOMEM;
+- zpci_aisb_iv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC);
+- if (!zpci_aisb_iv)
++ zpci_ibv = kcalloc(ZPCI_NR_DEVICES, sizeof(*zpci_ibv), GFP_KERNEL);
++ if (!zpci_ibv)
+ goto out_airq;
+
++ zpci_sbv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC);
++ if (!zpci_sbv)
++ goto out_free;
++
+ zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
+ return 0;
+
++out_free:
++ kfree(zpci_ibv);
+ out_airq:
+ unregister_adapter_interrupt(&zpci_airq);
+ out:
+@@ -217,6 +230,7 @@ out:
+
+ void __init zpci_irq_exit(void)
+ {
+- airq_iv_release(zpci_aisb_iv);
++ airq_iv_release(zpci_sbv);
++ kfree(zpci_ibv);
+ unregister_adapter_interrupt(&zpci_airq);
+ }
diff --git a/patches.arch/s390-pci-fix-assignment-of-bus-resources b/patches.arch/s390-pci-fix-assignment-of-bus-resources
new file mode 100644
index 0000000000..815629c2af
--- /dev/null
+++ b/patches.arch/s390-pci-fix-assignment-of-bus-resources
@@ -0,0 +1,31 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Thu, 16 May 2019 14:19:51 +0200
+Subject: s390/pci: fix assignment of bus resources
+Git-commit: dcd33b23c9f322274efb94d6e86370bac2b3c68f
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5802 FATE#327055 bsc#1134738 LTC#173387
+
+Adjust bus resources depending on the usage of MIO instructions.
+
+Fixes: 71ba41c9b1d9 ("s390/pci: provide support for MIO instructions")
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/pci/pci.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/arch/s390/pci/pci.c
++++ b/arch/s390/pci/pci.c
+@@ -730,7 +730,10 @@ static int zpci_setup_bus_resources(stru
+ if (zdev->bars[i].val & 4)
+ flags |= IORESOURCE_MEM_64;
+
+- addr = ZPCI_ADDR(entry);
++ if (static_branch_likely(&have_mio))
++ addr = (unsigned long) zdev->bars[i].mio_wb;
++ else
++ addr = ZPCI_ADDR(entry);
+ size = 1UL << zdev->bars[i].size;
+
+ res = __alloc_res(zdev, addr, size, flags);
diff --git a/patches.arch/s390-pci-fix-struct-definition-for-set-pci-function b/patches.arch/s390-pci-fix-struct-definition-for-set-pci-function
new file mode 100644
index 0000000000..6d24d552cc
--- /dev/null
+++ b/patches.arch/s390-pci-fix-struct-definition-for-set-pci-function
@@ -0,0 +1,87 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Thu, 16 May 2019 13:28:17 +0200
+Subject: s390/pci: fix struct definition for set PCI function
+Git-commit: 1354b38b3ddf47e0612d21f401d2bfeb8acd9b80
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5802 FATE#327055 bsc#1134738 LTC#173387
+
+Recent firmware will store PCI MIO information also when enabling MIO
+instructions via set PCI function. We do not use this information but
+currently calling enable MIO will fail because of insufficient response
+block length. Fix this by putting a struct mio_info at the end of the
+affected response block struct.
+
+Fixes: 71ba41c9b1d9 ("s390/pci: provide support for MIO instructions")
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/include/asm/pci_clp.h | 25 +++++++++++++++----------
+ arch/s390/pci/pci_clp.c | 6 +++---
+ 2 files changed, 18 insertions(+), 13 deletions(-)
+
+--- a/arch/s390/include/asm/pci_clp.h
++++ b/arch/s390/include/asm/pci_clp.h
+@@ -69,6 +69,17 @@ struct clp_rsp_list_pci {
+ struct clp_fh_list_entry fh_list[CLP_FH_LIST_NR_ENTRIES];
+ } __packed;
+
++struct mio_info {
++ u32 valid : 6;
++ u32 : 26;
++ u32 : 32;
++ struct {
++ u64 wb;
++ u64 wt;
++ } addr[PCI_BAR_COUNT];
++ u32 reserved[6];
++} __packed;
++
+ /* Query PCI function request */
+ struct clp_req_query_pci {
+ struct clp_req_hdr hdr;
+@@ -99,14 +110,7 @@ struct clp_rsp_query_pci {
+ u32 uid; /* user defined id */
+ u8 util_str[CLP_UTIL_STR_LEN]; /* utility string */
+ u32 reserved2[16];
+- u32 mio_valid : 6;
+- u32 : 26;
+- u32 : 32;
+- struct {
+- u64 wb;
+- u64 wt;
+- } addr[PCI_BAR_COUNT];
+- u32 reserved3[6];
++ struct mio_info mio;
+ } __packed;
+
+ /* Query PCI function group request */
+@@ -150,8 +154,9 @@ struct clp_req_set_pci {
+ struct clp_rsp_set_pci {
+ struct clp_rsp_hdr hdr;
+ u32 fh; /* function handle */
+- u32 reserved3;
+- u64 reserved4;
++ u32 reserved1;
++ u64 reserved2;
++ struct mio_info mio;
+ } __packed;
+
+ /* Combined request/response block structures used by clp insn */
+--- a/arch/s390/pci/pci_clp.c
++++ b/arch/s390/pci/pci_clp.c
+@@ -157,11 +157,11 @@ static int clp_store_query_pci_fn(struct
+ }
+ zdev->mio_capable = response->mio_addr_avail;
+ for (i = 0; i < PCI_BAR_COUNT; i++) {
+- if (!(response->mio_valid & (1 << (PCI_BAR_COUNT - i - 1))))
++ if (!(response->mio.valid & (1 << (PCI_BAR_COUNT - i - 1))))
+ continue;
+
+- zdev->bars[i].mio_wb = (void __iomem *) response->addr[i].wb;
+- zdev->bars[i].mio_wt = (void __iomem *) response->addr[i].wt;
++ zdev->bars[i].mio_wb = (void __iomem *) response->mio.addr[i].wb;
++ zdev->bars[i].mio_wt = (void __iomem *) response->mio.addr[i].wt;
+ }
+ return 0;
+ }
diff --git a/patches.arch/s390-pci-gather-statistics-for-floating-vs-directed-irqs b/patches.arch/s390-pci-gather-statistics-for-floating-vs-directed-irqs
new file mode 100644
index 0000000000..46d68ec9f3
--- /dev/null
+++ b/patches.arch/s390-pci-gather-statistics-for-floating-vs-directed-irqs
@@ -0,0 +1,70 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Thu, 22 Nov 2018 14:08:33 +0100
+Subject: s390/pci: gather statistics for floating vs directed irqs
+Git-commit: 07e3ec3acb80726f60b7ab924b1b0f1498148b56
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5789 FATE#327042 bsc#1134730 LTC#173388
+
+Gather statistics to distinguish floating and directed interrupts.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/include/asm/irq.h | 3 ++-
+ arch/s390/kernel/irq.c | 3 ++-
+ arch/s390/pci/pci_irq.c | 10 ++++++----
+ 3 files changed, 10 insertions(+), 6 deletions(-)
+
+--- a/arch/s390/include/asm/irq.h
++++ b/arch/s390/include/asm/irq.h
+@@ -58,7 +58,8 @@ enum interruption_class {
+ IRQIO_VIR,
+ IRQIO_QAI,
+ IRQIO_APB,
+- IRQIO_PCI,
++ IRQIO_PCF,
++ IRQIO_PCD,
+ IRQIO_MSI,
+ IRQIO_VAI,
+ NMI_NMI,
+--- a/arch/s390/kernel/irq.c
++++ b/arch/s390/kernel/irq.c
+@@ -84,7 +84,8 @@ static const struct irq_class irqclass_s
+ {.irq = IRQIO_VIR, .name = "VIR", .desc = "[I/O] Virtual I/O Devices"},
+ {.irq = IRQIO_QAI, .name = "QAI", .desc = "[AIO] QDIO Adapter Interrupt"},
+ {.irq = IRQIO_APB, .name = "APB", .desc = "[AIO] AP Bus"},
+- {.irq = IRQIO_PCI, .name = "PCI", .desc = "[AIO] PCI Interrupt"},
++ {.irq = IRQIO_PCF, .name = "PCF", .desc = "[AIO] PCI Floating Interrupt"},
++ {.irq = IRQIO_PCD, .name = "PCD", .desc = "[AIO] PCI Directed Interrupt"},
+ {.irq = IRQIO_MSI, .name = "MSI", .desc = "[AIO] MSI Interrupt"},
+ {.irq = IRQIO_VAI, .name = "VAI", .desc = "[AIO] Virtual I/O Devices AI"},
+ {.irq = NMI_NMI, .name = "NMI", .desc = "[NMI] Machine Check"},
+--- a/arch/s390/pci/pci_irq.c
++++ b/arch/s390/pci/pci_irq.c
+@@ -188,11 +188,13 @@ static void zpci_handle_fallback_irq(voi
+
+ static void zpci_directed_irq_handler(struct airq_struct *airq, bool floating)
+ {
+- inc_irq_stat(IRQIO_PCI);
+- if (floating)
++ if (floating) {
++ inc_irq_stat(IRQIO_PCF);
+ zpci_handle_fallback_irq();
+- else
++ } else {
++ inc_irq_stat(IRQIO_PCD);
+ zpci_handle_cpu_local_irq(true);
++ }
+ }
+
+ static void zpci_floating_irq_handler(struct airq_struct *airq, bool floating)
+@@ -201,7 +203,7 @@ static void zpci_floating_irq_handler(st
+ struct airq_iv *aibv;
+ int irqs_on = 0;
+
+- inc_irq_stat(IRQIO_PCI);
++ inc_irq_stat(IRQIO_PCF);
+ for (si = 0;;) {
+ /* Scan adapter summary indicator bit vector */
+ si = airq_iv_scan(zpci_sbv, si, airq_iv_end(zpci_sbv));
diff --git a/patches.arch/s390-pci-improve-bar-check b/patches.arch/s390-pci-improve-bar-check
new file mode 100644
index 0000000000..0517719633
--- /dev/null
+++ b/patches.arch/s390-pci-improve-bar-check
@@ -0,0 +1,29 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Tue, 31 Jul 2018 09:59:09 -0400
+Subject: s390/pci: improve bar check
+Git-commit: e8e25a7718cf64701ddf7f7b2e31c79815b613f1
+Patch-mainline: v5.1-rc1
+References: jsc#SLE-5803 FATE#327056
+
+Improve the bar check in pci_iomap_range to cover functions
+for which we recognize more bars than what we can access due
+to AR restrictions.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/pci/pci.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/s390/pci/pci.c
++++ b/arch/s390/pci/pci.c
+@@ -288,7 +288,7 @@ void __iomem *pci_iomap_range(struct pci
+ struct zpci_dev *zdev = to_zpci(pdev);
+ int idx;
+
+- if (!pci_resource_len(pdev, bar))
++ if (!pci_resource_len(pdev, bar) || bar >= PCI_BAR_COUNT)
+ return NULL;
+
+ idx = zdev->bars[bar].map_idx;
diff --git a/patches.arch/s390-pci-map-iov-resources b/patches.arch/s390-pci-map-iov-resources
new file mode 100644
index 0000000000..ca0954b319
--- /dev/null
+++ b/patches.arch/s390-pci-map-iov-resources
@@ -0,0 +1,53 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Wed, 12 Sep 2018 12:47:37 +0200
+Subject: s390/pci: map IOV resources
+Git-commit: cfbb4a7ab6bd5df7aca826b92ebb3565efd3d801
+Patch-mainline: v5.1-rc1
+References: jsc#SLE-5803 FATE#327056
+
+Map IOV resources such that pci common code recognizes the IOV
+capability of PFs.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/pci/pci.c | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+--- a/arch/s390/pci/pci.c
++++ b/arch/s390/pci/pci.c
+@@ -487,6 +487,15 @@ void arch_teardown_msi_irqs(struct pci_d
+ }
+ }
+
++#ifdef CONFIG_PCI_IOV
++static struct resource iov_res = {
++ .name = "PCI IOV res",
++ .start = 0,
++ .end = -1,
++ .flags = IORESOURCE_MEM,
++};
++#endif
++
+ static void zpci_map_resources(struct pci_dev *pdev)
+ {
+ resource_size_t len;
+@@ -500,6 +509,17 @@ static void zpci_map_resources(struct pc
+ (resource_size_t __force) pci_iomap(pdev, i, 0);
+ pdev->resource[i].end = pdev->resource[i].start + len - 1;
+ }
++
++#ifdef CONFIG_PCI_IOV
++ i = PCI_IOV_RESOURCES;
++
++ for (; i < PCI_SRIOV_NUM_BARS + PCI_IOV_RESOURCES; i++) {
++ len = pci_resource_len(pdev, i);
++ if (!len)
++ continue;
++ pdev->resource[i].parent = &iov_res;
++ }
++#endif
+ }
+
+ static void zpci_unmap_resources(struct pci_dev *pdev)
diff --git a/patches.arch/s390-pci-mark-command-line-parser-data-_initdata b/patches.arch/s390-pci-mark-command-line-parser-data-_initdata
new file mode 100644
index 0000000000..5c81cf6280
--- /dev/null
+++ b/patches.arch/s390-pci-mark-command-line-parser-data-_initdata
@@ -0,0 +1,27 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Tue, 12 Feb 2019 16:23:13 +0100
+Subject: s390/pci: mark command line parser data __initdata
+Git-commit: 6324b4de6dca40361399d3e9a2f2f1cbe8e7e11e
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5789 FATE#327042 bsc#1134730 LTC#173388
+
+No point to keep that around.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/pci/pci.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/s390/pci/pci.c
++++ b/arch/s390/pci/pci.c
+@@ -932,7 +932,7 @@ static void zpci_mem_exit(void)
+ kmem_cache_destroy(zdev_fmb_cache);
+ }
+
+-static unsigned int s390_pci_probe = 1;
++static unsigned int s390_pci_probe __initdata = 1;
+ static unsigned int s390_pci_initialized;
+
+ char * __init pcibios_setup(char *str)
diff --git a/patches.arch/s390-pci-move-everything-irq-related-to-pci_irq-c b/patches.arch/s390-pci-move-everything-irq-related-to-pci_irq-c
new file mode 100644
index 0000000000..e5d53bd030
--- /dev/null
+++ b/patches.arch/s390-pci-move-everything-irq-related-to-pci_irq-c
@@ -0,0 +1,535 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Tue, 12 Feb 2019 18:39:46 +0100
+Subject: s390/pci: move everything irq related to pci_irq.c
+Git-commit: c840927cf5f24d080236775e4c3a934e778069f5
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5789 FATE#327042 bsc#1134730 LTC#173388
+
+Move everything interrupt related from pci.c to pci_irq.c.
+No functional change.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/include/asm/pci.h | 6 +
+ arch/s390/pci/Makefile | 2
+ arch/s390/pci/pci.c | 216 ------------------------------------------
+ arch/s390/pci/pci_irq.c | 222 ++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 229 insertions(+), 217 deletions(-)
+
+--- a/arch/s390/include/asm/pci.h
++++ b/arch/s390/include/asm/pci.h
+@@ -26,6 +26,9 @@ int pci_proc_domain(struct pci_bus *);
+ #define ZPCI_BUS_NR 0 /* default bus number */
+ #define ZPCI_DEVFN 0 /* default device number */
+
++#define ZPCI_NR_DMA_SPACES 1
++#define ZPCI_NR_DEVICES CONFIG_PCI_NR_FUNCTIONS
++
+ /* PCI Function Controls */
+ #define ZPCI_FC_FN_ENABLED 0x80
+ #define ZPCI_FC_ERROR 0x40
+@@ -209,6 +212,9 @@ struct zpci_dev *get_zdev_by_fid(u32);
+ int zpci_dma_init(void);
+ void zpci_dma_exit(void);
+
++int __init zpci_irq_init(void);
++void __init zpci_irq_exit(void);
++
+ /* FMB */
+ int zpci_fmb_enable_device(struct zpci_dev *);
+ int zpci_fmb_disable_device(struct zpci_dev *);
+--- a/arch/s390/pci/Makefile
++++ b/arch/s390/pci/Makefile
+@@ -2,5 +2,5 @@
+ # Makefile for the s390 PCI subsystem.
+ #
+
+-obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_sysfs.o \
++obj-$(CONFIG_PCI) += pci.o pci_irq.o pci_dma.o pci_clp.o pci_sysfs.o \
+ pci_event.o pci_debug.o pci_insn.o pci_mmio.o
+--- a/arch/s390/pci/pci.c
++++ b/arch/s390/pci/pci.c
+@@ -23,8 +23,6 @@
+ #include <linux/err.h>
+ #include <linux/export.h>
+ #include <linux/delay.h>
+-#include <linux/irq.h>
+-#include <linux/kernel_stat.h>
+ #include <linux/seq_file.h>
+ #include <linux/pci.h>
+ #include <linux/msi.h>
+@@ -36,28 +33,13 @@
+ #include <asm/pci_clp.h>
+ #include <asm/pci_dma.h>
+
+-#define SIC_IRQ_MODE_ALL 0
+-#define SIC_IRQ_MODE_SINGLE 1
+-
+-#define ZPCI_NR_DMA_SPACES 1
+-#define ZPCI_NR_DEVICES CONFIG_PCI_NR_FUNCTIONS
+-
+ /* list of all detected zpci devices */
+ static LIST_HEAD(zpci_list);
+ static DEFINE_SPINLOCK(zpci_list_lock);
+
+-static struct irq_chip zpci_irq_chip = {
+- .name = "zPCI",
+- .irq_unmask = pci_msi_unmask_irq,
+- .irq_mask = pci_msi_mask_irq,
+-};
+-
+ static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES);
+ static DEFINE_SPINLOCK(zpci_domain_lock);
+
+-static struct airq_iv *zpci_aisb_iv;
+-static struct airq_iv *zpci_aibv[ZPCI_NR_DEVICES];
+-
+ #define ZPCI_IOMAP_ENTRIES \
+ min(((unsigned long) ZPCI_NR_DEVICES * PCI_BAR_COUNT / 2), \
+ ZPCI_IOMAP_MAX_ENTRIES)
+@@ -120,39 +102,6 @@ int pci_proc_domain(struct pci_bus *bus)
+ }
+ EXPORT_SYMBOL_GPL(pci_proc_domain);
+
+-/* Modify PCI: Register adapter interruptions */
+-static int zpci_set_airq(struct zpci_dev *zdev)
+-{
+- u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_REG_INT);
+- struct zpci_fib fib = {0};
+- u8 status;
+-
+- fib.isc = PCI_ISC;
+- fib.sum = 1; /* enable summary notifications */
+- fib.noi = airq_iv_end(zdev->aibv);
+- fib.aibv = (unsigned long) zdev->aibv->vector;
+- fib.aibvo = 0; /* each zdev has its own interrupt vector */
+- fib.aisb = (unsigned long) zpci_aisb_iv->vector + (zdev->aisb/64)*8;
+- fib.aisbo = zdev->aisb & 63;
+-
+- return zpci_mod_fc(req, &fib, &status) ? -EIO : 0;
+-}
+-
+-/* Modify PCI: Unregister adapter interruptions */
+-static int zpci_clear_airq(struct zpci_dev *zdev)
+-{
+- u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_DEREG_INT);
+- struct zpci_fib fib = {0};
+- u8 cc, status;
+-
+- cc = zpci_mod_fc(req, &fib, &status);
+- if (cc == 3 || (cc == 1 && status == 24))
+- /* Function already gone or IRQs already deregistered. */
+- cc = 0;
+-
+- return cc ? -EIO : 0;
+-}
+-
+ /* Modify PCI: Register I/O address translation parameters */
+ int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas,
+ u64 base, u64 limit, u64 iota)
+@@ -355,136 +304,6 @@ static struct pci_ops pci_root_ops = {
+ .write = pci_write,
+ };
+
+-static void zpci_irq_handler(struct airq_struct *airq)
+-{
+- unsigned long si, ai;
+- struct airq_iv *aibv;
+- int irqs_on = 0;
+-
+- inc_irq_stat(IRQIO_PCI);
+- for (si = 0;;) {
+- /* Scan adapter summary indicator bit vector */
+- si = airq_iv_scan(zpci_aisb_iv, si, airq_iv_end(zpci_aisb_iv));
+- if (si == -1UL) {
+- if (irqs_on++)
+- /* End of second scan with interrupts on. */
+- break;
+- /* First scan complete, reenable interrupts. */
+- if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC))
+- break;
+- si = 0;
+- continue;
+- }
+-
+- /* Scan the adapter interrupt vector for this device. */
+- aibv = zpci_aibv[si];
+- for (ai = 0;;) {
+- ai = airq_iv_scan(aibv, ai, airq_iv_end(aibv));
+- if (ai == -1UL)
+- break;
+- inc_irq_stat(IRQIO_MSI);
+- airq_iv_lock(aibv, ai);
+- generic_handle_irq(airq_iv_get_data(aibv, ai));
+- airq_iv_unlock(aibv, ai);
+- }
+- }
+-}
+-
+-int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
+-{
+- struct zpci_dev *zdev = to_zpci(pdev);
+- unsigned int hwirq, msi_vecs;
+- unsigned long aisb;
+- struct msi_desc *msi;
+- struct msi_msg msg;
+- int rc, irq;
+-
+- zdev->aisb = -1UL;
+- if (type == PCI_CAP_ID_MSI && nvec > 1)
+- return 1;
+- msi_vecs = min_t(unsigned int, nvec, zdev->max_msi);
+-
+- /* Allocate adapter summary indicator bit */
+- aisb = airq_iv_alloc_bit(zpci_aisb_iv);
+- if (aisb == -1UL)
+- return -EIO;
+- zdev->aisb = aisb;
+-
+- /* Create adapter interrupt vector */
+- zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK);
+- if (!zdev->aibv)
+- return -ENOMEM;
+-
+- /* Wire up shortcut pointer */
+- zpci_aibv[aisb] = zdev->aibv;
+-
+- /* Request MSI interrupts */
+- hwirq = 0;
+- for_each_pci_msi_entry(msi, pdev) {
+- if (hwirq >= msi_vecs)
+- break;
+- irq = irq_alloc_desc(0); /* Alloc irq on node 0 */
+- if (irq < 0)
+- return -ENOMEM;
+- rc = irq_set_msi_desc(irq, msi);
+- if (rc)
+- return rc;
+- irq_set_chip_and_handler(irq, &zpci_irq_chip,
+- handle_simple_irq);
+- msg.data = hwirq;
+- msg.address_lo = zdev->msi_addr & 0xffffffff;
+- msg.address_hi = zdev->msi_addr >> 32;
+- pci_write_msi_msg(irq, &msg);
+- airq_iv_set_data(zdev->aibv, hwirq, irq);
+- hwirq++;
+- }
+-
+- /* Enable adapter interrupts */
+- rc = zpci_set_airq(zdev);
+- if (rc)
+- return rc;
+-
+- return (msi_vecs == nvec) ? 0 : msi_vecs;
+-}
+-
+-void arch_teardown_msi_irqs(struct pci_dev *pdev)
+-{
+- struct zpci_dev *zdev = to_zpci(pdev);
+- struct msi_desc *msi;
+- int rc;
+-
+- /* Disable adapter interrupts */
+- rc = zpci_clear_airq(zdev);
+- if (rc)
+- return;
+-
+- /* Release MSI interrupts */
+- for_each_pci_msi_entry(msi, pdev) {
+- if (!msi->irq)
+- continue;
+- if (msi->msi_attrib.is_msix)
+- __pci_msix_desc_mask_irq(msi, 1);
+- else
+- __pci_msi_desc_mask_irq(msi, 1, 1);
+- irq_set_msi_desc(msi->irq, NULL);
+- irq_free_desc(msi->irq);
+- msi->msg.address_lo = 0;
+- msi->msg.address_hi = 0;
+- msi->msg.data = 0;
+- msi->irq = 0;
+- }
+-
+- if (zdev->aisb != -1UL) {
+- zpci_aibv[zdev->aisb] = NULL;
+- airq_iv_free_bit(zpci_aisb_iv, zdev->aisb);
+- zdev->aisb = -1UL;
+- }
+- if (zdev->aibv) {
+- airq_iv_release(zdev->aibv);
+- zdev->aibv = NULL;
+- }
+-}
+-
+ #ifdef CONFIG_PCI_IOV
+ static struct resource iov_res = {
+ .name = "PCI IOV res",
+@@ -514,41 +333,6 @@ static void zpci_unmap_resources(struct
+ }
+ }
+
+-static struct airq_struct zpci_airq = {
+- .handler = zpci_irq_handler,
+- .isc = PCI_ISC,
+-};
+-
+-static int __init zpci_irq_init(void)
+-{
+- int rc;
+-
+- rc = register_adapter_interrupt(&zpci_airq);
+- if (rc)
+- goto out;
+- /* Set summary to 1 to be called every time for the ISC. */
+- *zpci_airq.lsi_ptr = 1;
+-
+- rc = -ENOMEM;
+- zpci_aisb_iv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC);
+- if (!zpci_aisb_iv)
+- goto out_airq;
+-
+- zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
+- return 0;
+-
+-out_airq:
+- unregister_adapter_interrupt(&zpci_airq);
+-out:
+- return rc;
+-}
+-
+-static void zpci_irq_exit(void)
+-{
+- airq_iv_release(zpci_aisb_iv);
+- unregister_adapter_interrupt(&zpci_airq);
+-}
+-
+ static int zpci_alloc_iomap(struct zpci_dev *zdev)
+ {
+ unsigned long entry;
+--- /dev/null
++++ b/arch/s390/pci/pci_irq.c
+@@ -0,0 +1,222 @@
++// SPDX-License-Identifier: GPL-2.0
++#define KMSG_COMPONENT "zpci"
++#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
++
++#include <linux/kernel.h>
++#include <linux/irq.h>
++#include <linux/kernel_stat.h>
++#include <linux/pci.h>
++#include <linux/msi.h>
++
++#include <asm/isc.h>
++#include <asm/airq.h>
++
++#define SIC_IRQ_MODE_ALL 0
++#define SIC_IRQ_MODE_SINGLE 1
++
++static struct airq_iv *zpci_aisb_iv;
++static struct airq_iv *zpci_aibv[ZPCI_NR_DEVICES];
++
++/* Modify PCI: Register adapter interruptions */
++static int zpci_set_airq(struct zpci_dev *zdev)
++{
++ u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_REG_INT);
++ struct zpci_fib fib = {0};
++ u8 status;
++
++ fib.isc = PCI_ISC;
++ fib.sum = 1; /* enable summary notifications */
++ fib.noi = airq_iv_end(zdev->aibv);
++ fib.aibv = (unsigned long) zdev->aibv->vector;
++ fib.aibvo = 0; /* each zdev has its own interrupt vector */
++ fib.aisb = (unsigned long) zpci_aisb_iv->vector + (zdev->aisb/64)*8;
++ fib.aisbo = zdev->aisb & 63;
++
++ return zpci_mod_fc(req, &fib, &status) ? -EIO : 0;
++}
++
++/* Modify PCI: Unregister adapter interruptions */
++static int zpci_clear_airq(struct zpci_dev *zdev)
++{
++ u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_DEREG_INT);
++ struct zpci_fib fib = {0};
++ u8 cc, status;
++
++ cc = zpci_mod_fc(req, &fib, &status);
++ if (cc == 3 || (cc == 1 && status == 24))
++ /* Function already gone or IRQs already deregistered. */
++ cc = 0;
++
++ return cc ? -EIO : 0;
++}
++
++static struct irq_chip zpci_irq_chip = {
++ .name = "zPCI",
++ .irq_unmask = pci_msi_unmask_irq,
++ .irq_mask = pci_msi_mask_irq,
++};
++
++static void zpci_irq_handler(struct airq_struct *airq)
++{
++ unsigned long si, ai;
++ struct airq_iv *aibv;
++ int irqs_on = 0;
++
++ inc_irq_stat(IRQIO_PCI);
++ for (si = 0;;) {
++ /* Scan adapter summary indicator bit vector */
++ si = airq_iv_scan(zpci_aisb_iv, si, airq_iv_end(zpci_aisb_iv));
++ if (si == -1UL) {
++ if (irqs_on++)
++ /* End of second scan with interrupts on. */
++ break;
++ /* First scan complete, reenable interrupts. */
++ if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC))
++ break;
++ si = 0;
++ continue;
++ }
++
++ /* Scan the adapter interrupt vector for this device. */
++ aibv = zpci_aibv[si];
++ for (ai = 0;;) {
++ ai = airq_iv_scan(aibv, ai, airq_iv_end(aibv));
++ if (ai == -1UL)
++ break;
++ inc_irq_stat(IRQIO_MSI);
++ airq_iv_lock(aibv, ai);
++ generic_handle_irq(airq_iv_get_data(aibv, ai));
++ airq_iv_unlock(aibv, ai);
++ }
++ }
++}
++
++int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
++{
++ struct zpci_dev *zdev = to_zpci(pdev);
++ unsigned int hwirq, msi_vecs;
++ unsigned long aisb;
++ struct msi_desc *msi;
++ struct msi_msg msg;
++ int rc, irq;
++
++ zdev->aisb = -1UL;
++ if (type == PCI_CAP_ID_MSI && nvec > 1)
++ return 1;
++ msi_vecs = min_t(unsigned int, nvec, zdev->max_msi);
++
++ /* Allocate adapter summary indicator bit */
++ aisb = airq_iv_alloc_bit(zpci_aisb_iv);
++ if (aisb == -1UL)
++ return -EIO;
++ zdev->aisb = aisb;
++
++ /* Create adapter interrupt vector */
++ zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK);
++ if (!zdev->aibv)
++ return -ENOMEM;
++
++ /* Wire up shortcut pointer */
++ zpci_aibv[aisb] = zdev->aibv;
++
++ /* Request MSI interrupts */
++ hwirq = 0;
++ for_each_pci_msi_entry(msi, pdev) {
++ if (hwirq >= msi_vecs)
++ break;
++ irq = irq_alloc_desc(0); /* Alloc irq on node 0 */
++ if (irq < 0)
++ return -ENOMEM;
++ rc = irq_set_msi_desc(irq, msi);
++ if (rc)
++ return rc;
++ irq_set_chip_and_handler(irq, &zpci_irq_chip,
++ handle_simple_irq);
++ msg.data = hwirq;
++ msg.address_lo = zdev->msi_addr & 0xffffffff;
++ msg.address_hi = zdev->msi_addr >> 32;
++ pci_write_msi_msg(irq, &msg);
++ airq_iv_set_data(zdev->aibv, hwirq, irq);
++ hwirq++;
++ }
++
++ /* Enable adapter interrupts */
++ rc = zpci_set_airq(zdev);
++ if (rc)
++ return rc;
++
++ return (msi_vecs == nvec) ? 0 : msi_vecs;
++}
++
++void arch_teardown_msi_irqs(struct pci_dev *pdev)
++{
++ struct zpci_dev *zdev = to_zpci(pdev);
++ struct msi_desc *msi;
++ int rc;
++
++ /* Disable adapter interrupts */
++ rc = zpci_clear_airq(zdev);
++ if (rc)
++ return;
++
++ /* Release MSI interrupts */
++ for_each_pci_msi_entry(msi, pdev) {
++ if (!msi->irq)
++ continue;
++ if (msi->msi_attrib.is_msix)
++ __pci_msix_desc_mask_irq(msi, 1);
++ else
++ __pci_msi_desc_mask_irq(msi, 1, 1);
++ irq_set_msi_desc(msi->irq, NULL);
++ irq_free_desc(msi->irq);
++ msi->msg.address_lo = 0;
++ msi->msg.address_hi = 0;
++ msi->msg.data = 0;
++ msi->irq = 0;
++ }
++
++ if (zdev->aisb != -1UL) {
++ zpci_aibv[zdev->aisb] = NULL;
++ airq_iv_free_bit(zpci_aisb_iv, zdev->aisb);
++ zdev->aisb = -1UL;
++ }
++ if (zdev->aibv) {
++ airq_iv_release(zdev->aibv);
++ zdev->aibv = NULL;
++ }
++}
++
++static struct airq_struct zpci_airq = {
++ .handler = zpci_irq_handler,
++ .isc = PCI_ISC,
++};
++
++int __init zpci_irq_init(void)
++{
++ int rc;
++
++ rc = register_adapter_interrupt(&zpci_airq);
++ if (rc)
++ goto out;
++ /* Set summary to 1 to be called every time for the ISC. */
++ *zpci_airq.lsi_ptr = 1;
++
++ rc = -ENOMEM;
++ zpci_aisb_iv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC);
++ if (!zpci_aisb_iv)
++ goto out_airq;
++
++ zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
++ return 0;
++
++out_airq:
++ unregister_adapter_interrupt(&zpci_airq);
++out:
++ return rc;
++}
++
++void __init zpci_irq_exit(void)
++{
++ airq_iv_release(zpci_aisb_iv);
++ unregister_adapter_interrupt(&zpci_airq);
++}
diff --git a/patches.arch/s390-pci-move-io-address-mapping-code-to-pci_insn-c b/patches.arch/s390-pci-move-io-address-mapping-code-to-pci_insn-c
new file mode 100644
index 0000000000..82f0b4b7f9
--- /dev/null
+++ b/patches.arch/s390-pci-move-io-address-mapping-code-to-pci_insn-c
@@ -0,0 +1,294 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Sun, 14 Apr 2019 16:25:54 +0200
+Subject: s390/pci: move io address mapping code to pci_insn.c
+Git-commit: 81deca12c202aa240a28f561a161ac3387a985db
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5802 FATE#327055 bsc#1134738 LTC#173387
+
+This is a preparation patch for usage of new pci instructions.
+No functional change.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/include/asm/pci_insn.h | 8 +++---
+ arch/s390/include/asm/pci_io.h | 49 +++++++++++++++------------------------
+ arch/s390/pci/pci.c | 4 +--
+ arch/s390/pci/pci_insn.c | 38 +++++++++++++++++++++++++++---
+ drivers/s390/net/ism.h | 2 -
+ 5 files changed, 61 insertions(+), 40 deletions(-)
+
+--- a/arch/s390/include/asm/pci_insn.h
++++ b/arch/s390/include/asm/pci_insn.h
+@@ -123,9 +123,11 @@ union zpci_sic_iib {
+
+ u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status);
+ int zpci_refresh_trans(u64 fn, u64 addr, u64 range);
+-int zpci_load(u64 *data, u64 req, u64 offset);
+-int zpci_store(u64 data, u64 req, u64 offset);
+-int zpci_store_block(const u64 *data, u64 req, u64 offset);
++int __zpci_load(u64 *data, u64 req, u64 offset);
++int zpci_load(u64 *data, const volatile void __iomem *addr, unsigned long len);
++int __zpci_store(u64 data, u64 req, u64 offset);
++int zpci_store(const volatile void __iomem *addr, u64 data, unsigned long len);
++int __zpci_store_block(const u64 *data, u64 req, u64 offset);
+ int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib);
+
+ static inline int zpci_set_irq_ctrl(u16 ctl, u8 isc)
+--- a/arch/s390/include/asm/pci_io.h
++++ b/arch/s390/include/asm/pci_io.h
+@@ -36,12 +36,10 @@ extern struct zpci_iomap_entry *zpci_iom
+ #define zpci_read(LENGTH, RETTYPE) \
+ static inline RETTYPE zpci_read_##RETTYPE(const volatile void __iomem *addr) \
+ { \
+- struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)]; \
+- u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, LENGTH); \
+ u64 data; \
+ int rc; \
+ \
+- rc = zpci_load(&data, req, ZPCI_OFFSET(addr)); \
++ rc = zpci_load(&data, addr, LENGTH); \
+ if (rc) \
+ data = -1ULL; \
+ return (RETTYPE) data; \
+@@ -51,11 +49,9 @@ static inline RETTYPE zpci_read_##RETTYP
+ static inline void zpci_write_##VALTYPE(VALTYPE val, \
+ const volatile void __iomem *addr) \
+ { \
+- struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)]; \
+- u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, LENGTH); \
+ u64 data = (VALTYPE) val; \
+ \
+- zpci_store(data, req, ZPCI_OFFSET(addr)); \
++ zpci_store(addr, data, LENGTH); \
+ }
+
+ zpci_read(8, u64)
+@@ -67,36 +63,38 @@ zpci_write(4, u32)
+ zpci_write(2, u16)
+ zpci_write(1, u8)
+
+-static inline int zpci_write_single(u64 req, const u64 *data, u64 offset, u8 len)
++static inline int zpci_write_single(volatile void __iomem *dst, const void *src,
++ unsigned long len)
+ {
+ u64 val;
+
+ switch (len) {
+ case 1:
+- val = (u64) *((u8 *) data);
++ val = (u64) *((u8 *) src);
+ break;
+ case 2:
+- val = (u64) *((u16 *) data);
++ val = (u64) *((u16 *) src);
+ break;
+ case 4:
+- val = (u64) *((u32 *) data);
++ val = (u64) *((u32 *) src);
+ break;
+ case 8:
+- val = (u64) *((u64 *) data);
++ val = (u64) *((u64 *) src);
+ break;
+ default:
+ val = 0; /* let FW report error */
+ break;
+ }
+- return zpci_store(val, req, offset);
++ return zpci_store(dst, val, len);
+ }
+
+-static inline int zpci_read_single(u64 req, u64 *dst, u64 offset, u8 len)
++static inline int zpci_read_single(void *dst, const volatile void __iomem *src,
++ unsigned long len)
+ {
+ u64 data;
+ int cc;
+
+- cc = zpci_load(&data, req, offset);
++ cc = zpci_load(&data, src, len);
+ if (cc)
+ goto out;
+
+@@ -118,10 +116,8 @@ out:
+ return cc;
+ }
+
+-static inline int zpci_write_block(u64 req, const u64 *data, u64 offset)
+-{
+- return zpci_store_block(data, req, offset);
+-}
++int zpci_write_block(volatile void __iomem *dst, const void *src,
++ unsigned long len);
+
+ static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max)
+ {
+@@ -139,18 +135,15 @@ static inline int zpci_memcpy_fromio(voi
+ const volatile void __iomem *src,
+ unsigned long n)
+ {
+- struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(src)];
+- u64 req, offset = ZPCI_OFFSET(src);
+ int size, rc = 0;
+
+ while (n > 0) {
+ size = zpci_get_max_write_size((u64 __force) src,
+ (u64) dst, n, 8);
+- req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size);
+- rc = zpci_read_single(req, dst, offset, size);
++ rc = zpci_read_single(dst, src, size);
+ if (rc)
+ break;
+- offset += size;
++ src += size;
+ dst += size;
+ n -= size;
+ }
+@@ -160,8 +153,6 @@ static inline int zpci_memcpy_fromio(voi
+ static inline int zpci_memcpy_toio(volatile void __iomem *dst,
+ const void *src, unsigned long n)
+ {
+- struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(dst)];
+- u64 req, offset = ZPCI_OFFSET(dst);
+ int size, rc = 0;
+
+ if (!src)
+@@ -170,16 +161,14 @@ static inline int zpci_memcpy_toio(volat
+ while (n > 0) {
+ size = zpci_get_max_write_size((u64 __force) dst,
+ (u64) src, n, 128);
+- req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size);
+-
+ if (size > 8) /* main path */
+- rc = zpci_write_block(req, src, offset);
++ rc = zpci_write_block(dst, src, size);
+ else
+- rc = zpci_write_single(req, src, offset, size);
++ rc = zpci_write_single(dst, src, size);
+ if (rc)
+ break;
+- offset += size;
+ src += size;
++ dst += size;
+ n -= size;
+ }
+ return rc;
+--- a/arch/s390/pci/pci.c
++++ b/arch/s390/pci/pci.c
+@@ -188,7 +188,7 @@ static int zpci_cfg_load(struct zpci_dev
+ u64 data;
+ int rc;
+
+- rc = zpci_load(&data, req, offset);
++ rc = __zpci_load(&data, req, offset);
+ if (!rc) {
+ data = le64_to_cpu((__force __le64) data);
+ data >>= (8 - len) * 8;
+@@ -206,7 +206,7 @@ static int zpci_cfg_store(struct zpci_de
+
+ data <<= (8 - len) * 8;
+ data = (__force u64) cpu_to_le64(data);
+- rc = zpci_store(data, req, offset);
++ rc = __zpci_store(data, req, offset);
+ return rc;
+ }
+
+--- a/arch/s390/pci/pci_insn.c
++++ b/arch/s390/pci/pci_insn.c
+@@ -10,6 +10,7 @@
+ #include <asm/facility.h>
+ #include <asm/pci_insn.h>
+ #include <asm/pci_debug.h>
++#include <asm/pci_io.h>
+ #include <asm/processor.h>
+
+ #define ZPCI_INSN_BUSY_DELAY 1 /* 1 microsecond */
+@@ -141,7 +142,7 @@ static inline int __pcilg(u64 *data, u64
+ return cc;
+ }
+
+-int zpci_load(u64 *data, u64 req, u64 offset)
++int __zpci_load(u64 *data, u64 req, u64 offset)
+ {
+ u8 status;
+ int cc;
+@@ -157,6 +158,15 @@ int zpci_load(u64 *data, u64 req, u64 of
+
+ return (cc > 0) ? -EIO : cc;
+ }
++EXPORT_SYMBOL_GPL(__zpci_load);
++
++int zpci_load(u64 *data, const volatile void __iomem *addr, unsigned long len)
++{
++ struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)];
++ u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len);
++
++ return __zpci_load(data, req, ZPCI_OFFSET(addr));
++}
+ EXPORT_SYMBOL_GPL(zpci_load);
+
+ /* PCI Store */
+@@ -179,7 +189,7 @@ static inline int __pcistg(u64 data, u64
+ return cc;
+ }
+
+-int zpci_store(u64 data, u64 req, u64 offset)
++int __zpci_store(u64 data, u64 req, u64 offset)
+ {
+ u8 status;
+ int cc;
+@@ -195,6 +205,15 @@ int zpci_store(u64 data, u64 req, u64 of
+
+ return (cc > 0) ? -EIO : cc;
+ }
++EXPORT_SYMBOL_GPL(__zpci_store);
++
++int zpci_store(const volatile void __iomem *addr, u64 data, unsigned long len)
++{
++ struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)];
++ u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len);
++
++ return __zpci_store(data, req, ZPCI_OFFSET(addr));
++}
+ EXPORT_SYMBOL_GPL(zpci_store);
+
+ /* PCI Store Block */
+@@ -215,7 +234,7 @@ static inline int __pcistb(const u64 *da
+ return cc;
+ }
+
+-int zpci_store_block(const u64 *data, u64 req, u64 offset)
++int __zpci_store_block(const u64 *data, u64 req, u64 offset)
+ {
+ u8 status;
+ int cc;
+@@ -231,4 +250,15 @@ int zpci_store_block(const u64 *data, u6
+
+ return (cc > 0) ? -EIO : cc;
+ }
+-EXPORT_SYMBOL_GPL(zpci_store_block);
++EXPORT_SYMBOL_GPL(__zpci_store_block);
++
++int zpci_write_block(volatile void __iomem *dst,
++ const void *src, unsigned long len)
++{
++ struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(dst)];
++ u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len);
++ u64 offset = ZPCI_OFFSET(dst);
++
++ return __zpci_store_block(src, req, offset);
++}
++EXPORT_SYMBOL_GPL(zpci_write_block);
+--- a/drivers/s390/net/ism.h
++++ b/drivers/s390/net/ism.h
+@@ -215,7 +215,7 @@ static inline int __ism_move(struct ism_
+ struct zpci_dev *zdev = to_zpci(ism->pdev);
+ u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, size);
+
+- return zpci_write_block(req, data, dmb_req);
++ return __zpci_store_block(data, req, dmb_req);
+ }
+
+ #endif /* S390_ISM_H */
diff --git a/patches.arch/s390-pci-provide-support-for-cpu-directed-interrupts b/patches.arch/s390-pci-provide-support-for-cpu-directed-interrupts
new file mode 100644
index 0000000000..eb64161ff9
--- /dev/null
+++ b/patches.arch/s390-pci-provide-support-for-cpu-directed-interrupts
@@ -0,0 +1,646 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Thu, 27 Sep 2018 13:57:12 +0200
+Subject: s390/pci: provide support for CPU directed interrupts
+Git-commit: e979ce7bced2ee019b5b1a040295484bd7f23680
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5789 FATE#327042 bsc#1134730 LTC#173388
+
+Up until now all interrupts on s390 have been floating. For MSI interrupts
+we've used a global summary bit vector (with a bit for each function) and
+a per-function interrupt bit vector (with a bit per MSI).
+
+This patch introduces a new IRQ delivery mode: CPU directed interrupts.
+In this new mode a per-CPU interrupt bit vector is used (with a bit per
+MSI per function). Further it is now possible to direct an IRQ to a
+specific CPU so we can finally support IRQ affinity.
+
+If an interrupt can't be delivered because the appointed CPU is occupied
+by a hypervisor the interrupt is delivered floating. For this a global
+summary bit vector is used (with a bit per CPU).
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/include/asm/pci.h | 2
+ arch/s390/include/asm/pci_clp.h | 6
+ arch/s390/include/asm/pci_insn.h | 74 +++++++-
+ arch/s390/pci/pci_insn.c | 10 -
+ arch/s390/pci/pci_irq.c | 339 +++++++++++++++++++++++++++++++++------
+ 5 files changed, 368 insertions(+), 63 deletions(-)
+
+--- a/arch/s390/include/asm/pci.h
++++ b/arch/s390/include/asm/pci.h
+@@ -110,6 +110,8 @@ struct zpci_dev {
+ /* IRQ stuff */
+ u64 msi_addr; /* MSI address */
+ unsigned int max_msi; /* maximum number of MSI's */
++ unsigned int msi_first_bit;
++ unsigned int msi_nr_irqs;
+ struct airq_iv *aibv; /* adapter interrupt bit vector */
+ unsigned long aisb; /* number of the summary bit */
+
+--- a/arch/s390/include/asm/pci_clp.h
++++ b/arch/s390/include/asm/pci_clp.h
+@@ -117,7 +117,11 @@ struct clp_rsp_query_pci_grp {
+ u8 refresh : 1; /* TLB refresh mode */
+ u16 reserved2;
+ u16 mui;
+- u64 reserved3;
++ u16 : 16;
++ u16 maxfaal;
++ u16 : 4;
++ u16 dnoi : 12;
++ u16 maxcpu;
+ u64 dasm; /* dma address space mask */
+ u64 msia; /* MSI address */
+ u64 reserved4;
+--- a/arch/s390/include/asm/pci_insn.h
++++ b/arch/s390/include/asm/pci_insn.h
+@@ -37,6 +37,8 @@
+ #define ZPCI_MOD_FC_RESET_ERROR 7
+ #define ZPCI_MOD_FC_RESET_BLOCK 9
+ #define ZPCI_MOD_FC_SET_MEASURE 10
++#define ZPCI_MOD_FC_REG_INT_D 16
++#define ZPCI_MOD_FC_DEREG_INT_D 17
+
+ /* FIB function controls */
+ #define ZPCI_FIB_FC_ENABLED 0x80
+@@ -50,16 +52,7 @@
+ #define ZPCI_FIB_FC_LS_BLOCKED 0x20
+ #define ZPCI_FIB_FC_DMAAS_REG 0x10
+
+-/* Function Information Block */
+-struct zpci_fib {
+- u32 fmt : 8; /* format */
+- u32 : 24;
+- u32 : 32;
+- u8 fc; /* function controls */
+- u64 : 56;
+- u64 pba; /* PCI base address */
+- u64 pal; /* PCI address limit */
+- u64 iota; /* I/O Translation Anchor */
++struct zpci_fib_fmt0 {
+ u32 : 1;
+ u32 isc : 3; /* Interrupt subclass */
+ u32 noi : 12; /* Number of interrupts */
+@@ -71,16 +64,75 @@ struct zpci_fib {
+ u32 : 32;
+ u64 aibv; /* Adapter int bit vector address */
+ u64 aisb; /* Adapter int summary bit address */
++};
++
++struct zpci_fib_fmt1 {
++ u32 : 4;
++ u32 noi : 12;
++ u32 : 16;
++ u32 dibvo : 16;
++ u32 : 16;
++ u64 : 64;
++ u64 : 64;
++};
++
++/* Function Information Block */
++struct zpci_fib {
++ u32 fmt : 8; /* format */
++ u32 : 24;
++ u32 : 32;
++ u8 fc; /* function controls */
++ u64 : 56;
++ u64 pba; /* PCI base address */
++ u64 pal; /* PCI address limit */
++ u64 iota; /* I/O Translation Anchor */
++ union {
++ struct zpci_fib_fmt0 fmt0;
++ struct zpci_fib_fmt1 fmt1;
++ };
+ u64 fmb_addr; /* Function measurement block address and key */
+ u32 : 32;
+ u32 gd;
+ } __packed __aligned(8);
+
++/* directed interruption information block */
++struct zpci_diib {
++ u32 : 1;
++ u32 isc : 3;
++ u32 : 28;
++ u16 : 16;
++ u16 nr_cpus;
++ u64 disb_addr;
++ u64 : 64;
++ u64 : 64;
++} __packed __aligned(8);
++
++/* cpu directed interruption information block */
++struct zpci_cdiib {
++ u64 : 64;
++ u64 dibv_addr;
++ u64 : 64;
++ u64 : 64;
++ u64 : 64;
++} __packed __aligned(8);
++
++union zpci_sic_iib {
++ struct zpci_diib diib;
++ struct zpci_cdiib cdiib;
++};
++
+ u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status);
+ int zpci_refresh_trans(u64 fn, u64 addr, u64 range);
+ int zpci_load(u64 *data, u64 req, u64 offset);
+ int zpci_store(u64 data, u64 req, u64 offset);
+ int zpci_store_block(const u64 *data, u64 req, u64 offset);
+-int zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc);
++int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib);
++
++static inline int zpci_set_irq_ctrl(u16 ctl, u8 isc)
++{
++ union zpci_sic_iib iib = {{0}};
++
++ return __zpci_set_irq_ctrl(ctl, isc, &iib);
++}
+
+ #endif
+--- a/arch/s390/pci/pci_insn.c
++++ b/arch/s390/pci/pci_insn.c
+@@ -95,13 +95,15 @@ int zpci_refresh_trans(u64 fn, u64 addr,
+ }
+
+ /* Set Interruption Controls */
+-int zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc)
++int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib)
+ {
+ if (!test_facility(72))
+ return -EIO;
+- asm volatile (
+- " .insn rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n"
+- : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused));
++
++ asm volatile(
++ ".insn rsy,0xeb00000000d1,%[ctl],%[isc],%[iib]\n"
++ : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [iib] "Q" (*iib));
++
+ return 0;
+ }
+
+--- a/arch/s390/pci/pci_irq.c
++++ b/arch/s390/pci/pci_irq.c
+@@ -7,20 +7,31 @@
+ #include <linux/kernel_stat.h>
+ #include <linux/pci.h>
+ #include <linux/msi.h>
++#include <linux/smp.h>
+
+ #include <asm/isc.h>
+ #include <asm/airq.h>
+
++static enum {FLOATING, DIRECTED} irq_delivery;
++
+ #define SIC_IRQ_MODE_ALL 0
+ #define SIC_IRQ_MODE_SINGLE 1
++#define SIC_IRQ_MODE_DIRECT 4
++#define SIC_IRQ_MODE_D_ALL 16
++#define SIC_IRQ_MODE_D_SINGLE 17
++#define SIC_IRQ_MODE_SET_CPU 18
+
+ /*
+- * summary bit vector - one summary bit per function
++ * summary bit vector
++ * FLOATING - summary bit per function
++ * DIRECTED - summary bit per cpu (only used in fallback path)
+ */
+ static struct airq_iv *zpci_sbv;
+
+ /*
+- * interrupt bit vectors - one vector per function
++ * interrupt bit vectors
++ * FLOATING - interrupt bit vector per function
++ * DIRECTED - interrupt bit vector per cpu
+ */
+ static struct airq_iv **zpci_ibv;
+
+@@ -31,13 +42,13 @@ static int zpci_set_airq(struct zpci_dev
+ struct zpci_fib fib = {0};
+ u8 status;
+
+- fib.isc = PCI_ISC;
+- fib.sum = 1; /* enable summary notifications */
+- fib.noi = airq_iv_end(zdev->aibv);
+- fib.aibv = (unsigned long) zdev->aibv->vector;
+- fib.aibvo = 0; /* each zdev has its own interrupt vector */
+- fib.aisb = (unsigned long) zpci_sbv->vector + (zdev->aisb/64)*8;
+- fib.aisbo = zdev->aisb & 63;
++ fib.fmt0.isc = PCI_ISC;
++ fib.fmt0.sum = 1; /* enable summary notifications */
++ fib.fmt0.noi = airq_iv_end(zdev->aibv);
++ fib.fmt0.aibv = (unsigned long) zdev->aibv->vector;
++ fib.fmt0.aibvo = 0; /* each zdev has its own interrupt vector */
++ fib.fmt0.aisb = (unsigned long) zpci_sbv->vector + (zdev->aisb/64)*8;
++ fib.fmt0.aisbo = zdev->aisb & 63;
+
+ return zpci_mod_fc(req, &fib, &status) ? -EIO : 0;
+ }
+@@ -57,13 +68,134 @@ static int zpci_clear_airq(struct zpci_d
+ return cc ? -EIO : 0;
+ }
+
++/* Modify PCI: Register CPU directed interruptions */
++static int zpci_set_directed_irq(struct zpci_dev *zdev)
++{
++ u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_REG_INT_D);
++ struct zpci_fib fib = {0};
++ u8 status;
++
++ fib.fmt = 1;
++ fib.fmt1.noi = zdev->msi_nr_irqs;
++ fib.fmt1.dibvo = zdev->msi_first_bit;
++
++ return zpci_mod_fc(req, &fib, &status) ? -EIO : 0;
++}
++
++/* Modify PCI: Unregister CPU directed interruptions */
++static int zpci_clear_directed_irq(struct zpci_dev *zdev)
++{
++ u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_DEREG_INT_D);
++ struct zpci_fib fib = {0};
++ u8 cc, status;
++
++ fib.fmt = 1;
++ cc = zpci_mod_fc(req, &fib, &status);
++ if (cc == 3 || (cc == 1 && status == 24))
++ /* Function already gone or IRQs already deregistered. */
++ cc = 0;
++
++ return cc ? -EIO : 0;
++}
++
++static int zpci_set_irq_affinity(struct irq_data *data, const struct cpumask *dest,
++ bool force)
++{
++ struct msi_desc *entry = irq_get_msi_desc(data->irq);
++ struct msi_msg msg = entry->msg;
++
++ msg.address_lo &= 0xff0000ff;
++ msg.address_lo |= (cpumask_first(dest) << 8);
++ pci_write_msi_msg(data->irq, &msg);
++
++ return IRQ_SET_MASK_OK;
++}
++
+ static struct irq_chip zpci_irq_chip = {
+ .name = "zPCI",
+ .irq_unmask = pci_msi_unmask_irq,
+ .irq_mask = pci_msi_mask_irq,
++ .irq_set_affinity = zpci_set_irq_affinity,
++};
++
++static void zpci_handle_cpu_local_irq(bool rescan)
++{
++ struct airq_iv *dibv = zpci_ibv[smp_processor_id()];
++ unsigned long bit;
++ int irqs_on = 0;
++
++ for (bit = 0;;) {
++ /* Scan the directed IRQ bit vector */
++ bit = airq_iv_scan(dibv, bit, airq_iv_end(dibv));
++ if (bit == -1UL) {
++ if (!rescan || irqs_on++)
++ /* End of second scan with interrupts on. */
++ break;
++ /* First scan complete, reenable interrupts. */
++ if (zpci_set_irq_ctrl(SIC_IRQ_MODE_D_SINGLE, PCI_ISC))
++ break;
++ bit = 0;
++ continue;
++ }
++ inc_irq_stat(IRQIO_MSI);
++ generic_handle_irq(airq_iv_get_data(dibv, bit));
++ }
++}
++
++struct cpu_irq_data {
++ call_single_data_t csd;
++ atomic_t scheduled;
+ };
++static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_irq_data, irq_data);
++
++static void zpci_handle_remote_irq(void *data)
++{
++ atomic_t *scheduled = data;
++
++ do {
++ zpci_handle_cpu_local_irq(false);
++ } while (atomic_dec_return(scheduled));
++}
++
++static void zpci_handle_fallback_irq(void)
++{
++ struct cpu_irq_data *cpu_data;
++ unsigned long cpu;
++ int irqs_on = 0;
++
++ for (cpu = 0;;) {
++ cpu = airq_iv_scan(zpci_sbv, cpu, airq_iv_end(zpci_sbv));
++ if (cpu == -1UL) {
++ if (irqs_on++)
++ /* End of second scan with interrupts on. */
++ break;
++ /* First scan complete, reenable interrupts. */
++ if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC))
++ break;
++ cpu = 0;
++ continue;
++ }
++ cpu_data = &per_cpu(irq_data, cpu);
++ if (atomic_inc_return(&cpu_data->scheduled) > 1)
++ continue;
++
++ cpu_data->csd.func = zpci_handle_remote_irq;
++ cpu_data->csd.info = &cpu_data->scheduled;
++ cpu_data->csd.flags = 0;
++ smp_call_function_single_async(cpu, &cpu_data->csd);
++ }
++}
++
++static void zpci_directed_irq_handler(struct airq_struct *airq, bool floating)
++{
++ inc_irq_stat(IRQIO_PCI);
++ if (floating)
++ zpci_handle_fallback_irq();
++ else
++ zpci_handle_cpu_local_irq(true);
++}
+
+-static void zpci_irq_handler(struct airq_struct *airq, bool floating)
++static void zpci_floating_irq_handler(struct airq_struct *airq, bool floating)
+ {
+ unsigned long si, ai;
+ struct airq_iv *aibv;
+@@ -78,7 +210,7 @@ static void zpci_irq_handler(struct airq
+ /* End of second scan with interrupts on. */
+ break;
+ /* First scan complete, reenable interrupts. */
+- if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC))
++ if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC))
+ break;
+ si = 0;
+ continue;
+@@ -101,54 +233,79 @@ static void zpci_irq_handler(struct airq
+ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
+ {
+ struct zpci_dev *zdev = to_zpci(pdev);
+- unsigned int hwirq, msi_vecs;
+- unsigned long aisb;
++ unsigned int hwirq, msi_vecs, cpu;
++ unsigned long bit;
+ struct msi_desc *msi;
+ struct msi_msg msg;
+ int rc, irq;
+
+ zdev->aisb = -1UL;
++ zdev->msi_first_bit = -1U;
+ if (type == PCI_CAP_ID_MSI && nvec > 1)
+ return 1;
+ msi_vecs = min_t(unsigned int, nvec, zdev->max_msi);
+
+- /* Allocate adapter summary indicator bit */
+- aisb = airq_iv_alloc_bit(zpci_sbv);
+- if (aisb == -1UL)
+- return -EIO;
+- zdev->aisb = aisb;
+-
+- /* Create adapter interrupt vector */
+- zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK);
+- if (!zdev->aibv)
+- return -ENOMEM;
++ if (irq_delivery == DIRECTED) {
++ /* Allocate cpu vector bits */
++ bit = airq_iv_alloc(zpci_ibv[0], msi_vecs);
++ if (bit == -1UL)
++ return -EIO;
++ } else {
++ /* Allocate adapter summary indicator bit */
++ bit = airq_iv_alloc_bit(zpci_sbv);
++ if (bit == -1UL)
++ return -EIO;
++ zdev->aisb = bit;
++
++ /* Create adapter interrupt vector */
++ zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK);
++ if (!zdev->aibv)
++ return -ENOMEM;
+
+- /* Wire up shortcut pointer */
+- zpci_ibv[aisb] = zdev->aibv;
++ /* Wire up shortcut pointer */
++ zpci_ibv[bit] = zdev->aibv;
++ /* Each function has its own interrupt vector */
++ bit = 0;
++ }
+
+ /* Request MSI interrupts */
+- hwirq = 0;
++ hwirq = bit;
+ for_each_pci_msi_entry(msi, pdev) {
+- if (hwirq >= msi_vecs)
++ rc = -EIO;
++ if (hwirq - bit >= msi_vecs)
+ break;
+- irq = irq_alloc_desc(0); /* Alloc irq on node 0 */
++ irq = __irq_alloc_descs(-1, 0, 1, 0, THIS_MODULE, msi->affinity);
+ if (irq < 0)
+ return -ENOMEM;
+ rc = irq_set_msi_desc(irq, msi);
+ if (rc)
+ return rc;
+ irq_set_chip_and_handler(irq, &zpci_irq_chip,
+- handle_simple_irq);
++ handle_percpu_irq);
+ msg.data = hwirq;
+- msg.address_lo = zdev->msi_addr & 0xffffffff;
++ if (irq_delivery == DIRECTED) {
++ msg.address_lo = zdev->msi_addr & 0xff0000ff;
++ msg.address_lo |= msi->affinity ?
++ (cpumask_first(msi->affinity) << 8) : 0;
++ for_each_possible_cpu(cpu) {
++ airq_iv_set_data(zpci_ibv[cpu], hwirq, irq);
++ }
++ } else {
++ msg.address_lo = zdev->msi_addr & 0xffffffff;
++ airq_iv_set_data(zdev->aibv, hwirq, irq);
++ }
+ msg.address_hi = zdev->msi_addr >> 32;
+ pci_write_msi_msg(irq, &msg);
+- airq_iv_set_data(zdev->aibv, hwirq, irq);
+ hwirq++;
+ }
+
+- /* Enable adapter interrupts */
+- rc = zpci_set_airq(zdev);
++ zdev->msi_first_bit = bit;
++ zdev->msi_nr_irqs = msi_vecs;
++
++ if (irq_delivery == DIRECTED)
++ rc = zpci_set_directed_irq(zdev);
++ else
++ rc = zpci_set_airq(zdev);
+ if (rc)
+ return rc;
+
+@@ -161,8 +318,11 @@ void arch_teardown_msi_irqs(struct pci_d
+ struct msi_desc *msi;
+ int rc;
+
+- /* Disable adapter interrupts */
+- rc = zpci_clear_airq(zdev);
++ /* Disable interrupts */
++ if (irq_delivery == DIRECTED)
++ rc = zpci_clear_directed_irq(zdev);
++ else
++ rc = zpci_clear_airq(zdev);
+ if (rc)
+ return;
+
+@@ -191,37 +351,114 @@ void arch_teardown_msi_irqs(struct pci_d
+ airq_iv_release(zdev->aibv);
+ zdev->aibv = NULL;
+ }
++
++ if ((irq_delivery == DIRECTED) && zdev->msi_first_bit != -1U)
++ airq_iv_free(zpci_ibv[0], zdev->msi_first_bit, zdev->msi_nr_irqs);
+ }
+
+ static struct airq_struct zpci_airq = {
+- .handler = zpci_irq_handler,
++ .handler = zpci_floating_irq_handler,
+ .isc = PCI_ISC,
+ };
+
+-int __init zpci_irq_init(void)
++static void __init cpu_enable_directed_irq(void *unused)
+ {
+- int rc;
++ union zpci_sic_iib iib = {{0}};
+
+- rc = register_adapter_interrupt(&zpci_airq);
+- if (rc)
+- goto out;
+- /* Set summary to 1 to be called every time for the ISC. */
+- *zpci_airq.lsi_ptr = 1;
++ iib.cdiib.dibv_addr = (u64) zpci_ibv[smp_processor_id()]->vector;
++
++ __zpci_set_irq_ctrl(SIC_IRQ_MODE_SET_CPU, 0, &iib);
++ zpci_set_irq_ctrl(SIC_IRQ_MODE_D_SINGLE, PCI_ISC);
++}
++
++static int __init zpci_directed_irq_init(void)
++{
++ union zpci_sic_iib iib = {{0}};
++ unsigned int cpu;
++
++ zpci_sbv = airq_iv_create(num_possible_cpus(), 0);
++ if (!zpci_sbv)
++ return -ENOMEM;
++
++ iib.diib.isc = PCI_ISC;
++ iib.diib.nr_cpus = num_possible_cpus();
++ iib.diib.disb_addr = (u64) zpci_sbv->vector;
++ __zpci_set_irq_ctrl(SIC_IRQ_MODE_DIRECT, 0, &iib);
++
++ zpci_ibv = kcalloc(num_possible_cpus(), sizeof(*zpci_ibv),
++ GFP_KERNEL);
++ if (!zpci_ibv)
++ return -ENOMEM;
++
++ for_each_possible_cpu(cpu) {
++ /*
++ * Per CPU IRQ vectors look the same but bit-allocation
++ * is only done on the first vector.
++ */
++ zpci_ibv[cpu] = airq_iv_create(cache_line_size() * BITS_PER_BYTE,
++ AIRQ_IV_DATA |
++ AIRQ_IV_CACHELINE |
++ (!cpu ? AIRQ_IV_ALLOC : 0));
++ if (!zpci_ibv[cpu])
++ return -ENOMEM;
++ }
++ on_each_cpu(cpu_enable_directed_irq, NULL, 1);
+
+- rc = -ENOMEM;
++ zpci_irq_chip.irq_set_affinity = zpci_set_irq_affinity;
++
++ return 0;
++}
++
++static int __init zpci_floating_irq_init(void)
++{
+ zpci_ibv = kcalloc(ZPCI_NR_DEVICES, sizeof(*zpci_ibv), GFP_KERNEL);
+ if (!zpci_ibv)
+- goto out_airq;
++ return -ENOMEM;
+
+ zpci_sbv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC);
+ if (!zpci_sbv)
+ goto out_free;
+
+- zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
+ return 0;
+
+ out_free:
+ kfree(zpci_ibv);
++ return -ENOMEM;
++}
++
++int __init zpci_irq_init(void)
++{
++ int rc;
++
++ irq_delivery = sclp.has_dirq ? DIRECTED : FLOATING;
++ if (irq_delivery == DIRECTED)
++ zpci_airq.handler = zpci_directed_irq_handler;
++
++ rc = register_adapter_interrupt(&zpci_airq);
++ if (rc)
++ goto out;
++ /* Set summary to 1 to be called every time for the ISC. */
++ *zpci_airq.lsi_ptr = 1;
++
++ switch (irq_delivery) {
++ case FLOATING:
++ rc = zpci_floating_irq_init();
++ break;
++ case DIRECTED:
++ rc = zpci_directed_irq_init();
++ break;
++ }
++
++ if (rc)
++ goto out_airq;
++
++ /*
++ * Enable floating IRQs (with suppression after one IRQ). When using
++ * directed IRQs this enables the fallback path.
++ */
++ zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC);
++
++ return 0;
+ out_airq:
+ unregister_adapter_interrupt(&zpci_airq);
+ out:
+@@ -230,7 +467,15 @@ out:
+
+ void __init zpci_irq_exit(void)
+ {
+- airq_iv_release(zpci_sbv);
++ unsigned int cpu;
++
++ if (irq_delivery == DIRECTED) {
++ for_each_possible_cpu(cpu) {
++ airq_iv_release(zpci_ibv[cpu]);
++ }
++ }
+ kfree(zpci_ibv);
++ if (zpci_sbv)
++ airq_iv_release(zpci_sbv);
+ unregister_adapter_interrupt(&zpci_airq);
+ }
diff --git a/patches.arch/s390-pci-provide-support-for-mio-instructions b/patches.arch/s390-pci-provide-support-for-mio-instructions
new file mode 100644
index 0000000000..c2bae3c646
--- /dev/null
+++ b/patches.arch/s390-pci-provide-support-for-mio-instructions
@@ -0,0 +1,583 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Sun, 14 Apr 2019 15:38:01 +0200
+Subject: s390/pci: provide support for MIO instructions
+Git-commit: 71ba41c9b1d91042960e9d92a5c8f52dc8531eda
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5802 FATE#327055 bsc#1134738 LTC#173387
+
+Provide support for PCI I/O instructions that work on mapped IO addresses.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/include/asm/io.h | 17 ++---
+ arch/s390/include/asm/pci.h | 3
+ arch/s390/include/asm/pci_clp.h | 14 +++-
+ arch/s390/include/asm/pci_insn.h | 5 +
+ arch/s390/pci/pci.c | 132 ++++++++++++++++++++++++++++++++++++---
+ arch/s390/pci/pci_clp.c | 25 +++++--
+ arch/s390/pci/pci_insn.c | 129 ++++++++++++++++++++++++++++++++++++--
+ 7 files changed, 294 insertions(+), 31 deletions(-)
+
+--- a/arch/s390/include/asm/io.h
++++ b/arch/s390/include/asm/io.h
+@@ -31,14 +31,8 @@ void unxlate_dev_mem_ptr(phys_addr_t phy
+ #define ioremap_wc ioremap_nocache
+ #define ioremap_wt ioremap_nocache
+
+-static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
+-{
+- return (void __iomem *) offset;
+-}
+-
+-static inline void iounmap(volatile void __iomem *addr)
+-{
+-}
++void __iomem *ioremap(unsigned long offset, unsigned long size);
++void iounmap(volatile void __iomem *addr);
+
+ static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
+ {
+@@ -56,14 +50,17 @@ static inline void ioport_unmap(void __i
+ * the corresponding device and create the mapping cookie.
+ */
+ #define pci_iomap pci_iomap
++#define pci_iomap_range pci_iomap_range
+ #define pci_iounmap pci_iounmap
+-#define pci_iomap_wc pci_iomap
+-#define pci_iomap_wc_range pci_iomap_range
++#define pci_iomap_wc pci_iomap_wc
++#define pci_iomap_wc_range pci_iomap_wc_range
+
+ #define memcpy_fromio(dst, src, count) zpci_memcpy_fromio(dst, src, count)
+ #define memcpy_toio(dst, src, count) zpci_memcpy_toio(dst, src, count)
+ #define memset_io(dst, val, count) zpci_memset_io(dst, val, count)
+
++#define mmiowb() zpci_barrier()
++
+ #define __raw_readb zpci_read_u8
+ #define __raw_readw zpci_read_u16
+ #define __raw_readl zpci_read_u32
+--- a/arch/s390/include/asm/pci.h
++++ b/arch/s390/include/asm/pci.h
+@@ -81,6 +81,8 @@ enum zpci_state {
+
+ struct zpci_bar_struct {
+ struct resource *res; /* bus resource */
++ void __iomem *mio_wb;
++ void __iomem *mio_wt;
+ u32 val; /* bar start & 3 flag bits */
+ u16 map_idx; /* index into bar mapping array */
+ u8 size; /* order 2 exponent */
+@@ -128,6 +130,7 @@ struct zpci_dev {
+ unsigned int next_bit;
+
+ char res_name[16];
++ bool mio_capable;
+ struct zpci_bar_struct bars[PCI_BAR_COUNT];
+
+ u64 start_dma; /* Start of available DMA addresses */
+--- a/arch/s390/include/asm/pci_clp.h
++++ b/arch/s390/include/asm/pci_clp.h
+@@ -42,6 +42,8 @@ struct clp_fh_list_entry {
+
+ #define CLP_SET_ENABLE_PCI_FN 0 /* Yes, 0 enables it */
+ #define CLP_SET_DISABLE_PCI_FN 1 /* Yes, 1 disables it */
++#define CLP_SET_ENABLE_MIO 2
++#define CLP_SET_DISABLE_MIO 3
+
+ #define CLP_UTIL_STR_LEN 64
+ #define CLP_PFIP_NR_SEGMENTS 4
+@@ -79,7 +81,8 @@ struct clp_req_query_pci {
+ struct clp_rsp_query_pci {
+ struct clp_rsp_hdr hdr;
+ u16 vfn; /* virtual fn number */
+- u16 : 7;
++ u16 : 6;
++ u16 mio_addr_avail : 1;
+ u16 util_str_avail : 1; /* utility string available? */
+ u16 pfgid : 8; /* pci function group id */
+ u32 fid; /* pci function id */
+@@ -95,6 +98,15 @@ struct clp_rsp_query_pci {
+ u32 reserved[11];
+ u32 uid; /* user defined id */
+ u8 util_str[CLP_UTIL_STR_LEN]; /* utility string */
++ u32 reserved2[16];
++ u32 mio_valid : 6;
++ u32 : 26;
++ u32 : 32;
++ struct {
++ u64 wb;
++ u64 wt;
++ } addr[PCI_BAR_COUNT];
++ u32 reserved3[6];
+ } __packed;
+
+ /* Query PCI function group request */
+--- a/arch/s390/include/asm/pci_insn.h
++++ b/arch/s390/include/asm/pci_insn.h
+@@ -1,6 +1,8 @@
+ #ifndef _ASM_S390_PCI_INSN_H
+ #define _ASM_S390_PCI_INSN_H
+
++#include <linux/jump_label.h>
++
+ /* Load/Store status codes */
+ #define ZPCI_PCI_ST_FUNC_NOT_ENABLED 4
+ #define ZPCI_PCI_ST_FUNC_IN_ERR 8
+@@ -121,6 +123,8 @@ union zpci_sic_iib {
+ struct zpci_cdiib cdiib;
+ };
+
++DECLARE_STATIC_KEY_FALSE(have_mio);
++
+ u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status);
+ int zpci_refresh_trans(u64 fn, u64 addr, u64 range);
+ int __zpci_load(u64 *data, u64 req, u64 offset);
+@@ -128,6 +132,7 @@ int zpci_load(u64 *data, const volatile
+ int __zpci_store(u64 data, u64 req, u64 offset);
+ int zpci_store(const volatile void __iomem *addr, u64 data, unsigned long len);
+ int __zpci_store_block(const u64 *data, u64 req, u64 offset);
++void zpci_barrier(void);
+ int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib);
+
+ static inline int zpci_set_irq_ctrl(u16 ctl, u8 isc)
+--- a/arch/s390/pci/pci.c
++++ b/arch/s390/pci/pci.c
+@@ -24,6 +24,7 @@
+ #include <linux/export.h>
+ #include <linux/delay.h>
+ #include <linux/seq_file.h>
++#include <linux/jump_label.h>
+ #include <linux/pci.h>
+ #include <linux/msi.h>
+
+@@ -50,6 +51,8 @@ static unsigned long *zpci_iomap_bitmap;
+ struct zpci_iomap_entry *zpci_iomap_start;
+ EXPORT_SYMBOL_GPL(zpci_iomap_start);
+
++DEFINE_STATIC_KEY_FALSE(have_mio);
++
+ static struct kmem_cache *zdev_fmb_cache;
+
+ struct zpci_dev *get_zdev_by_fid(u32 fid)
+@@ -227,18 +230,48 @@ void __iowrite64_copy(void __iomem *to,
+ zpci_memcpy_toio(to, from, count);
+ }
+
++void __iomem *ioremap(unsigned long ioaddr, unsigned long size)
++{
++ struct vm_struct *area;
++ unsigned long offset;
++
++ if (!size)
++ return NULL;
++
++ if (!static_branch_unlikely(&have_mio))
++ return (void __iomem *) ioaddr;
++
++ offset = ioaddr & ~PAGE_MASK;
++ ioaddr &= PAGE_MASK;
++ size = PAGE_ALIGN(size + offset);
++ area = get_vm_area(size, VM_IOREMAP);
++ if (!area)
++ return NULL;
++
++ if (ioremap_page_range((unsigned long) area->addr,
++ (unsigned long) area->addr + size,
++ ioaddr, PAGE_KERNEL)) {
++ vunmap(area->addr);
++ return NULL;
++ }
++ return (void __iomem *) ((unsigned long) area->addr + offset);
++}
++EXPORT_SYMBOL(ioremap);
++
++void iounmap(volatile void __iomem *addr)
++{
++ if (static_branch_likely(&have_mio))
++ vunmap((__force void *) ((unsigned long) addr & PAGE_MASK));
++}
++EXPORT_SYMBOL(iounmap);
++
+ /* Create a virtual mapping cookie for a PCI BAR */
+-void __iomem *pci_iomap_range(struct pci_dev *pdev,
+- int bar,
+- unsigned long offset,
+- unsigned long max)
++static void __iomem *pci_iomap_range_fh(struct pci_dev *pdev, int bar,
++ unsigned long offset, unsigned long max)
+ {
+ struct zpci_dev *zdev = to_zpci(pdev);
+ int idx;
+
+- if (!pci_resource_len(pdev, bar) || bar >= PCI_BAR_COUNT)
+- return NULL;
+-
+ idx = zdev->bars[bar].map_idx;
+ spin_lock(&zpci_iomap_lock);
+ /* Detect overrun */
+@@ -249,6 +282,30 @@ void __iomem *pci_iomap_range(struct pci
+
+ return (void __iomem *) ZPCI_ADDR(idx) + offset;
+ }
++
++static void __iomem *pci_iomap_range_mio(struct pci_dev *pdev, int bar,
++ unsigned long offset,
++ unsigned long max)
++{
++ unsigned long barsize = pci_resource_len(pdev, bar);
++ struct zpci_dev *zdev = to_zpci(pdev);
++ void __iomem *iova;
++
++ iova = ioremap((unsigned long) zdev->bars[bar].mio_wt, barsize);
++ return iova ? iova + offset : iova;
++}
++
++void __iomem *pci_iomap_range(struct pci_dev *pdev, int bar,
++ unsigned long offset, unsigned long max)
++{
++ if (!pci_resource_len(pdev, bar) || bar >= PCI_BAR_COUNT)
++ return NULL;
++
++ if (static_branch_likely(&have_mio))
++ return pci_iomap_range_mio(pdev, bar, offset, max);
++ else
++ return pci_iomap_range_fh(pdev, bar, offset, max);
++}
+ EXPORT_SYMBOL(pci_iomap_range);
+
+ void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+@@ -257,7 +314,37 @@ void __iomem *pci_iomap(struct pci_dev *
+ }
+ EXPORT_SYMBOL(pci_iomap);
+
+-void pci_iounmap(struct pci_dev *pdev, void __iomem *addr)
++static void __iomem *pci_iomap_wc_range_mio(struct pci_dev *pdev, int bar,
++ unsigned long offset, unsigned long max)
++{
++ unsigned long barsize = pci_resource_len(pdev, bar);
++ struct zpci_dev *zdev = to_zpci(pdev);
++ void __iomem *iova;
++
++ iova = ioremap((unsigned long) zdev->bars[bar].mio_wb, barsize);
++ return iova ? iova + offset : iova;
++}
++
++void __iomem *pci_iomap_wc_range(struct pci_dev *pdev, int bar,
++ unsigned long offset, unsigned long max)
++{
++ if (!pci_resource_len(pdev, bar) || bar >= PCI_BAR_COUNT)
++ return NULL;
++
++ if (static_branch_likely(&have_mio))
++ return pci_iomap_wc_range_mio(pdev, bar, offset, max);
++ else
++ return pci_iomap_range_fh(pdev, bar, offset, max);
++}
++EXPORT_SYMBOL(pci_iomap_wc_range);
++
++void __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long maxlen)
++{
++ return pci_iomap_wc_range(dev, bar, 0, maxlen);
++}
++EXPORT_SYMBOL(pci_iomap_wc);
++
++static void pci_iounmap_fh(struct pci_dev *pdev, void __iomem *addr)
+ {
+ unsigned int idx = ZPCI_IDX(addr);
+
+@@ -270,6 +357,19 @@ void pci_iounmap(struct pci_dev *pdev, v
+ }
+ spin_unlock(&zpci_iomap_lock);
+ }
++
++static void pci_iounmap_mio(struct pci_dev *pdev, void __iomem *addr)
++{
++ iounmap(addr);
++}
++
++void pci_iounmap(struct pci_dev *pdev, void __iomem *addr)
++{
++ if (static_branch_likely(&have_mio))
++ pci_iounmap_mio(pdev, addr);
++ else
++ pci_iounmap_fh(pdev, addr);
++}
+ EXPORT_SYMBOL(pci_iounmap);
+
+ static int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
+@@ -307,6 +407,7 @@ static struct pci_ops pci_root_ops = {
+
+ static void zpci_map_resources(struct pci_dev *pdev)
+ {
++ struct zpci_dev *zdev = to_zpci(pdev);
+ resource_size_t len;
+ int i;
+
+@@ -314,8 +415,13 @@ static void zpci_map_resources(struct pc
+ len = pci_resource_len(pdev, i);
+ if (!len)
+ continue;
+- pdev->resource[i].start =
+- (resource_size_t __force) pci_iomap(pdev, i, 0);
++
++ if (static_branch_likely(&have_mio))
++ pdev->resource[i].start =
++ (resource_size_t __force) zdev->bars[i].mio_wb;
++ else
++ pdev->resource[i].start =
++ (resource_size_t __force) pci_iomap(pdev, i, 0);
+ pdev->resource[i].end = pdev->resource[i].start + len - 1;
+ }
+
+@@ -325,6 +431,9 @@ static void zpci_unmap_resources(struct
+ resource_size_t len;
+ int i;
+
++ if (static_branch_likely(&have_mio))
++ return;
++
+ for (i = 0; i < PCI_BAR_COUNT; i++) {
+ len = pci_resource_len(pdev, i);
+ if (!len)
+@@ -746,6 +855,9 @@ static int __init pci_base_init(void)
+ if (!test_facility(69) || !test_facility(71))
+ return 0;
+
++ if (test_facility(153))
++ static_branch_enable(&have_mio);
++
+ rc = zpci_debug_init();
+ if (rc)
+ goto out;
+--- a/arch/s390/pci/pci_clp.c
++++ b/arch/s390/pci/pci_clp.c
+@@ -155,7 +155,14 @@ static int clp_store_query_pci_fn(struct
+ memcpy(zdev->util_str, response->util_str,
+ sizeof(zdev->util_str));
+ }
++ zdev->mio_capable = response->mio_addr_avail;
++ for (i = 0; i < PCI_BAR_COUNT; i++) {
++ if (!(response->mio_valid & (1 << (PCI_BAR_COUNT - i - 1))))
++ continue;
+
++ zdev->bars[i].mio_wb = (void __iomem *) response->addr[i].wb;
++ zdev->bars[i].mio_wt = (void __iomem *) response->addr[i].wt;
++ }
+ return 0;
+ }
+
+@@ -271,11 +278,18 @@ int clp_enable_fh(struct zpci_dev *zdev,
+ int rc;
+
+ rc = clp_set_pci_fn(&fh, nr_dma_as, CLP_SET_ENABLE_PCI_FN);
+- if (!rc)
+- /* Success -> store enabled handle in zdev */
+- zdev->fh = fh;
++ zpci_dbg(3, "ena fid:%x, fh:%x, rc:%d\n", zdev->fid, fh, rc);
++ if (rc)
++ goto out;
+
+- zpci_dbg(3, "ena fid:%x, fh:%x, rc:%d\n", zdev->fid, zdev->fh, rc);
++ zdev->fh = fh;
++ if (zdev->mio_capable) {
++ rc = clp_set_pci_fn(&fh, nr_dma_as, CLP_SET_ENABLE_MIO);
++ zpci_dbg(3, "ena mio fid:%x, fh:%x, rc:%d\n", zdev->fid, fh, rc);
++ if (rc)
++ clp_disable_fh(zdev);
++ }
++out:
+ return rc;
+ }
+
+@@ -288,11 +302,10 @@ int clp_disable_fh(struct zpci_dev *zdev
+ return 0;
+
+ rc = clp_set_pci_fn(&fh, 0, CLP_SET_DISABLE_PCI_FN);
++ zpci_dbg(3, "dis fid:%x, fh:%x, rc:%d\n", zdev->fid, fh, rc);
+ if (!rc)
+- /* Success -> store disabled handle in zdev */
+ zdev->fh = fh;
+
+- zpci_dbg(3, "dis fid:%x, fh:%x, rc:%d\n", zdev->fid, zdev->fh, rc);
+ return rc;
+ }
+
+--- a/arch/s390/pci/pci_insn.c
++++ b/arch/s390/pci/pci_insn.c
+@@ -7,6 +7,7 @@
+ #include <linux/export.h>
+ #include <linux/errno.h>
+ #include <linux/delay.h>
++#include <linux/jump_label.h>
+ #include <asm/facility.h>
+ #include <asm/pci_insn.h>
+ #include <asm/pci_debug.h>
+@@ -160,13 +161,50 @@ int __zpci_load(u64 *data, u64 req, u64
+ }
+ EXPORT_SYMBOL_GPL(__zpci_load);
+
+-int zpci_load(u64 *data, const volatile void __iomem *addr, unsigned long len)
++static inline int zpci_load_fh(u64 *data, const volatile void __iomem *addr,
++ unsigned long len)
+ {
+ struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)];
+ u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len);
+
+ return __zpci_load(data, req, ZPCI_OFFSET(addr));
+ }
++
++static inline int __pcilg_mio(u64 *data, u64 ioaddr, u64 len, u8 *status)
++{
++ register u64 addr asm("2") = ioaddr;
++ register u64 r3 asm("3") = len;
++ int cc = -ENXIO;
++ u64 __data;
++
++ asm volatile (
++ " .insn rre,0xb9d60000,%[data],%[ioaddr]\n"
++ "0: ipm %[cc]\n"
++ " srl %[cc],28\n"
++ "1:\n"
++ EX_TABLE(0b, 1b)
++ : [cc] "+d" (cc), [data] "=d" (__data), "+d" (r3)
++ : [ioaddr] "d" (addr)
++ : "cc");
++ *status = r3 >> 24 & 0xff;
++ *data = __data;
++ return cc;
++}
++
++int zpci_load(u64 *data, const volatile void __iomem *addr, unsigned long len)
++{
++ u8 status;
++ int cc;
++
++ if (!static_branch_unlikely(&have_mio))
++ return zpci_load_fh(data, addr, len);
++
++ cc = __pcilg_mio(data, (__force u64) addr, len, &status);
++ if (cc)
++ zpci_err_insn(cc, status, 0, (__force u64) addr);
++
++ return (cc > 0) ? -EIO : cc;
++}
+ EXPORT_SYMBOL_GPL(zpci_load);
+
+ /* PCI Store */
+@@ -207,13 +245,48 @@ int __zpci_store(u64 data, u64 req, u64
+ }
+ EXPORT_SYMBOL_GPL(__zpci_store);
+
+-int zpci_store(const volatile void __iomem *addr, u64 data, unsigned long len)
++static inline int zpci_store_fh(const volatile void __iomem *addr, u64 data,
++ unsigned long len)
+ {
+ struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)];
+ u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len);
+
+ return __zpci_store(data, req, ZPCI_OFFSET(addr));
+ }
++
++static inline int __pcistg_mio(u64 data, u64 ioaddr, u64 len, u8 *status)
++{
++ register u64 addr asm("2") = ioaddr;
++ register u64 r3 asm("3") = len;
++ int cc = -ENXIO;
++
++ asm volatile (
++ " .insn rre,0xb9d40000,%[data],%[ioaddr]\n"
++ "0: ipm %[cc]\n"
++ " srl %[cc],28\n"
++ "1:\n"
++ EX_TABLE(0b, 1b)
++ : [cc] "+d" (cc), "+d" (r3)
++ : [data] "d" (data), [ioaddr] "d" (addr)
++ : "cc");
++ *status = r3 >> 24 & 0xff;
++ return cc;
++}
++
++int zpci_store(const volatile void __iomem *addr, u64 data, unsigned long len)
++{
++ u8 status;
++ int cc;
++
++ if (!static_branch_unlikely(&have_mio))
++ return zpci_store_fh(addr, data, len);
++
++ cc = __pcistg_mio(data, (__force u64) addr, len, &status);
++ if (cc)
++ zpci_err_insn(cc, status, 0, (__force u64) addr);
++
++ return (cc > 0) ? -EIO : cc;
++}
+ EXPORT_SYMBOL_GPL(zpci_store);
+
+ /* PCI Store Block */
+@@ -252,8 +325,8 @@ int __zpci_store_block(const u64 *data,
+ }
+ EXPORT_SYMBOL_GPL(__zpci_store_block);
+
+-int zpci_write_block(volatile void __iomem *dst,
+- const void *src, unsigned long len)
++static inline int zpci_write_block_fh(volatile void __iomem *dst,
++ const void *src, unsigned long len)
+ {
+ struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(dst)];
+ u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len);
+@@ -261,4 +334,52 @@ int zpci_write_block(volatile void __iom
+
+ return __zpci_store_block(src, req, offset);
+ }
++
++static inline int __pcistb_mio(const u64 *data, u64 ioaddr, u64 len, u8 *status)
++{
++ int cc = -ENXIO;
++
++ asm volatile (
++ " .insn rsy,0xeb00000000d4,%[len],%[ioaddr],%[data]\n"
++ "0: ipm %[cc]\n"
++ " srl %[cc],28\n"
++ "1:\n"
++ EX_TABLE(0b, 1b)
++ : [cc] "+d" (cc), [len] "+d" (len)
++ : [ioaddr] "d" (ioaddr), [data] "Q" (*data)
++ : "cc");
++ *status = len >> 24 & 0xff;
++ return cc;
++}
++
++int zpci_write_block(volatile void __iomem *dst,
++ const void *src, unsigned long len)
++{
++ u8 status;
++ int cc;
++
++ if (!static_branch_unlikely(&have_mio))
++ return zpci_write_block_fh(dst, src, len);
++
++ cc = __pcistb_mio(src, (__force u64) dst, len, &status);
++ if (cc)
++ zpci_err_insn(cc, status, 0, (__force u64) dst);
++
++ return (cc > 0) ? -EIO : cc;
++}
+ EXPORT_SYMBOL_GPL(zpci_write_block);
++
++static inline void __pciwb_mio(void)
++{
++ unsigned long unused = 0;
++
++ asm volatile (".insn rre,0xb9d50000,%[op],%[op]\n"
++ : [op] "+d" (unused));
++}
++
++void zpci_barrier(void)
++{
++ if (static_branch_likely(&have_mio))
++ __pciwb_mio();
++}
++EXPORT_SYMBOL_GPL(zpci_barrier);
diff --git a/patches.arch/s390-pci-remove-stale-rc b/patches.arch/s390-pci-remove-stale-rc
new file mode 100644
index 0000000000..fb823e9f10
--- /dev/null
+++ b/patches.arch/s390-pci-remove-stale-rc
@@ -0,0 +1,26 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Mon, 13 Aug 2018 11:27:23 +0200
+Subject: s390/pci: remove stale rc
+Git-commit: 38204071a024bb6b62e669e971799152809f1722
+Patch-mainline: v4.19-rc1
+References: jsc#SLE-5789 FATE#327042 bsc#1134730 LTC#173388
+
+Get rid of a leftover return code in arch_setup_msi_irqs.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/pci/pci.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/arch/s390/pci/pci.c
++++ b/arch/s390/pci/pci.c
+@@ -423,7 +423,6 @@ int arch_setup_msi_irqs(struct pci_dev *
+ /* Request MSI interrupts */
+ hwirq = 0;
+ for_each_pci_msi_entry(msi, pdev) {
+- rc = -EIO;
+ if (hwirq >= msi_vecs)
+ break;
+ irq = irq_alloc_desc(0); /* Alloc irq on node 0 */
diff --git a/patches.arch/s390-pci-remove-unused-define b/patches.arch/s390-pci-remove-unused-define
new file mode 100644
index 0000000000..b6de79386a
--- /dev/null
+++ b/patches.arch/s390-pci-remove-unused-define
@@ -0,0 +1,27 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Tue, 12 Feb 2019 18:41:49 +0100
+Subject: s390/pci: remove unused define
+Git-commit: 066ee72aecdcb8cb2fd5968c852f304d7b88e2be
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5789 FATE#327042 bsc#1134730 LTC#173388
+
+No users of pr_debug in that file.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/pci/pci.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/arch/s390/pci/pci.c
++++ b/arch/s390/pci/pci.c
+@@ -36,8 +36,6 @@
+ #include <asm/pci_clp.h>
+ #include <asm/pci_dma.h>
+
+-#define DEBUG /* enable pr_debug */
+-
+ #define SIC_IRQ_MODE_ALL 0
+ #define SIC_IRQ_MODE_SINGLE 1
+
diff --git a/patches.arch/s390-pci-skip-vf-scanning b/patches.arch/s390-pci-skip-vf-scanning
new file mode 100644
index 0000000000..b01dde5dd5
--- /dev/null
+++ b/patches.arch/s390-pci-skip-vf-scanning
@@ -0,0 +1,30 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Fri, 21 Dec 2018 15:14:20 +0100
+Subject: s390/pci: skip VF scanning
+Git-commit: 7dc20ab1b9c431b792a6fe1e78baf36b63edc5e3
+Patch-mainline: v5.0-rc1
+References: jsc#SLE-5803 FATE#327056
+
+Set the flag to skip scanning for VFs after SR-IOV enablement. VF creation
+will be triggered by the hotplug code.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/pci/pci.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/arch/s390/pci/pci.c
++++ b/arch/s390/pci/pci.c
+@@ -654,6 +654,9 @@ int pcibios_add_device(struct pci_dev *p
+ struct resource *res;
+ int i;
+
++ if (pdev->is_physfn)
++ pdev->no_vf_scan = 1;
++
+ pdev->dev.groups = zpci_attr_groups;
+ pdev->dev.dma_ops = &s390_pci_dma_ops;
+ zpci_map_resources(pdev);
diff --git a/patches.arch/s390-protvirt-add-memory-sharing-for-diag-308-set-store b/patches.arch/s390-protvirt-add-memory-sharing-for-diag-308-set-store
new file mode 100644
index 0000000000..c71ccc93a6
--- /dev/null
+++ b/patches.arch/s390-protvirt-add-memory-sharing-for-diag-308-set-store
@@ -0,0 +1,79 @@
+From: Vasily Gorbik <gor@linux.ibm.com>
+Date: Mon, 1 Apr 2019 19:11:04 +0200
+Subject: s390/protvirt: add memory sharing for diag 308 set/store
+Git-commit: db9492cef45efc347beed7b617dfdfac399f662b
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5759 FATE#327003 bsc#1135153 LTC#173151
+
+Add sharing of ipl parameter block for diag 308 set/store calls to allow
+kvm access in protected virtualization environment.
+
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+
+[ ptesarik: Added SLE modifications by IBM's Vasily Gorbik, because
+ SLE15-SP1 does not contain these upstream commits:
+ 96c0cdbc7c60885d65dc8d11a39bbcfd9cc49d03
+ 49698745e53c417370ac5cfe8b849bb65d62f129 ]
+
+---
+ arch/s390/kernel/ipl.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/arch/s390/kernel/ipl.c
++++ b/arch/s390/kernel/ipl.c
+@@ -30,6 +30,7 @@
+ #include <asm/checksum.h>
+ #include <asm/debug.h>
+ #include <asm/os_info.h>
++#include <asm/uv.h>
+ #include "entry.h"
+
+ #define IPL_PARM_BLOCK_VERSION 0
+@@ -1087,11 +1088,15 @@ static void __reipl_run(void *unused)
+ __cpcmd(buf, NULL, 0, NULL);
+ break;
+ case REIPL_METHOD_CCW_DIAG:
++ uv_set_shared(__pa(reipl_block_ccw));
+ diag308(DIAG308_SET, reipl_block_ccw);
++ uv_remove_shared(__pa(reipl_block_ccw));
+ diag308(DIAG308_LOAD_CLEAR, NULL);
+ break;
+ case REIPL_METHOD_FCP_RW_DIAG:
++ uv_set_shared(__pa(reipl_block_fcp));
+ diag308(DIAG308_SET, reipl_block_fcp);
++ uv_remove_shared(__pa(reipl_block_fcp));
+ diag308(DIAG308_LOAD_CLEAR, NULL);
+ break;
+ case REIPL_METHOD_FCP_RO_DIAG:
+@@ -1101,7 +1106,9 @@ static void __reipl_run(void *unused)
+ __cpcmd("IPL", NULL, 0, NULL);
+ break;
+ case REIPL_METHOD_NSS_DIAG:
++ uv_set_shared(__pa(reipl_block_nss));
+ diag308(DIAG308_SET, reipl_block_nss);
++ uv_remove_shared(__pa(reipl_block_nss));
+ diag308(DIAG308_LOAD_CLEAR, NULL);
+ break;
+ case REIPL_METHOD_NSS:
+@@ -1424,7 +1431,9 @@ static struct kset *dump_kset;
+
+ static void diag308_dump(void *dump_block)
+ {
++ uv_set_shared(__pa(dump_block));
+ diag308(DIAG308_SET, dump_block);
++ uv_remove_shared(__pa(dump_block));
+ while (1) {
+ if (diag308(DIAG308_LOAD_NORMAL_DUMP, NULL) != 0x302)
+ break;
+@@ -1987,7 +1996,9 @@ void __init ipl_update_parameters(void)
+ {
+ int rc;
+
++ uv_set_shared(__pa(&ipl_block));
+ rc = diag308(DIAG308_STORE, &ipl_block);
++ uv_remove_shared(__pa(&ipl_block));
+ if ((rc == DIAG308_RC_OK) || (rc == DIAG308_RC_NOCONFIG))
+ diag308_set_works = 1;
+ }
diff --git a/patches.arch/s390-protvirt-block-kernel-command-line-alteration b/patches.arch/s390-protvirt-block-kernel-command-line-alteration
new file mode 100644
index 0000000000..7e174365ac
--- /dev/null
+++ b/patches.arch/s390-protvirt-block-kernel-command-line-alteration
@@ -0,0 +1,33 @@
+From: Vasily Gorbik <gor@linux.ibm.com>
+Date: Mon, 1 Apr 2019 19:11:08 +0200
+Subject: s390/protvirt: block kernel command line alteration
+Git-commit: 093ddccb55157f909f203f9e50bce0c24431e791
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5759 FATE#327003 bsc#1135153 LTC#173151
+
+Disallow kernel command line alteration via ipl parameter block if
+running in protected virtualization environment.
+
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+[ ptesarik: Added SLE modifications by IBM's Vasily Gorbik, because
+ SLE15-SP1 does not contain these upstream commits:
+ 49698745e53c417370ac5cfe8b849bb65d62f129 ]
+
+---
+ arch/s390/kernel/early.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/arch/s390/kernel/early.c
++++ b/arch/s390/kernel/early.c
+@@ -542,6 +542,9 @@ static void __init setup_boot_command_li
+ strlcpy(boot_command_line, strstrip(COMMAND_LINE),
+ ARCH_COMMAND_LINE_SIZE);
+
++ if (is_prot_virt_guest())
++ return;
++
+ /* append IPL PARM data to the boot command line */
+ if (MACHINE_IS_VM)
+ append_to_cmdline(append_ipl_vmparm);
diff --git a/patches.arch/s390-sclp-detect-dirq-facility b/patches.arch/s390-sclp-detect-dirq-facility
new file mode 100644
index 0000000000..1d546e5c87
--- /dev/null
+++ b/patches.arch/s390-sclp-detect-dirq-facility
@@ -0,0 +1,47 @@
+From: Sebastian Ott <sebott@linux.ibm.com>
+Date: Tue, 12 Feb 2019 12:37:50 +0100
+Subject: s390/sclp: detect DIRQ facility
+Git-commit: 0a9fddfaa8ea0f66564329ce89390c8dd38b2df0
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5789 FATE#327042 bsc#1134730 LTC#173388
+
+Detect the adapter CPU directed interruption facility.
+
+Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ arch/s390/include/asm/sclp.h | 1 +
+ drivers/s390/char/sclp_early.c | 4 +++-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+--- a/arch/s390/include/asm/sclp.h
++++ b/arch/s390/include/asm/sclp.h
+@@ -77,6 +77,7 @@ struct sclp_info {
+ unsigned char has_skey : 1;
+ unsigned char has_kss : 1;
+ unsigned char has_diag318 : 1;
++ unsigned char has_dirq : 1;
+ unsigned int ibc;
+ unsigned int mtid;
+ unsigned int mtid_cp;
+--- a/drivers/s390/char/sclp_early.c
++++ b/drivers/s390/char/sclp_early.c
+@@ -55,7 +55,8 @@ struct read_info_sccb {
+ u32 hmfai; /* 124-127 */
+ u8 _pad_128[134 - 128]; /* 128-133 */
+ u8 byte_134; /* 134 */
+- u8 _pad_135[4096 - 135]; /* 135-4095 */
++ u8 cpudirq; /* 135 */
++ u8 _pad_136[4096 - 136]; /* 136-4095 */
+ } __packed __aligned(PAGE_SIZE);
+
+ static struct sclp_ipl_info sclp_ipl_info;
+@@ -154,6 +155,7 @@ static void __init sclp_early_facilities
+ sclp.mtid_prev = (sccb->fac42 & 0x80) ? (sccb->fac66 & 31) : 0;
+
+ sclp.hmfai = sccb->hmfai;
++ sclp.has_dirq = !!(sccb->cpudirq & 0x80);
+ }
+
+ /*
diff --git a/patches.arch/s390-show-statistics-for-msi-irqs b/patches.arch/s390-show-statistics-for-msi-irqs
new file mode 100644
index 0000000000..4585ba99b3
--- /dev/null
+++ b/patches.arch/s390-show-statistics-for-msi-irqs
@@ -0,0 +1,155 @@
+From: Sebastian Ott <sebott@linux.vnet.ibm.com>
+Date: Tue, 14 Feb 2017 18:13:09 +0100
+Subject: s390: show statistics for MSI IRQs
+Git-commit: 914b7dd07ee8713c69c31ddb3e19a76852a846ac
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5789 FATE#327042 bsc#1134730 LTC#173388
+
+Improve /proc/interrupts on s390 to show statistics for individual
+MSI interrupts.
+
+Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
+Acked-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/include/asm/irq.h | 6 ++---
+ arch/s390/kernel/irq.c | 45 ++++++++++++++++++++++++++++++++++++--------
+ arch/s390/pci/pci_irq.c | 2 -
+ drivers/s390/cio/cio.c | 2 -
+ 4 files changed, 42 insertions(+), 13 deletions(-)
+
+--- a/arch/s390/include/asm/irq.h
++++ b/arch/s390/include/asm/irq.h
+@@ -46,7 +46,6 @@ enum interruption_class {
+ IRQEXT_CMC,
+ IRQEXT_FTP,
+ IRQIO_CIO,
+- IRQIO_QAI,
+ IRQIO_DAS,
+ IRQIO_C15,
+ IRQIO_C70,
+@@ -54,12 +53,13 @@ enum interruption_class {
+ IRQIO_VMR,
+ IRQIO_LCS,
+ IRQIO_CTC,
+- IRQIO_APB,
+ IRQIO_ADM,
+ IRQIO_CSC,
++ IRQIO_VIR,
++ IRQIO_QAI,
++ IRQIO_APB,
+ IRQIO_PCI,
+ IRQIO_MSI,
+- IRQIO_VIR,
+ IRQIO_VAI,
+ NMI_NMI,
+ CPU_RST,
+--- a/arch/s390/kernel/irq.c
++++ b/arch/s390/kernel/irq.c
+@@ -72,7 +72,6 @@ static const struct irq_class irqclass_s
+ {.irq = IRQEXT_CMC, .name = "CMC", .desc = "[EXT] CPU-Measurement: Counter"},
+ {.irq = IRQEXT_FTP, .name = "FTP", .desc = "[EXT] HMC FTP Service"},
+ {.irq = IRQIO_CIO, .name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt"},
+- {.irq = IRQIO_QAI, .name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt"},
+ {.irq = IRQIO_DAS, .name = "DAS", .desc = "[I/O] DASD"},
+ {.irq = IRQIO_C15, .name = "C15", .desc = "[I/O] 3215"},
+ {.irq = IRQIO_C70, .name = "C70", .desc = "[I/O] 3270"},
+@@ -80,13 +79,14 @@ static const struct irq_class irqclass_s
+ {.irq = IRQIO_VMR, .name = "VMR", .desc = "[I/O] Unit Record Devices"},
+ {.irq = IRQIO_LCS, .name = "LCS", .desc = "[I/O] LCS"},
+ {.irq = IRQIO_CTC, .name = "CTC", .desc = "[I/O] CTC"},
+- {.irq = IRQIO_APB, .name = "APB", .desc = "[I/O] AP Bus"},
+ {.irq = IRQIO_ADM, .name = "ADM", .desc = "[I/O] EADM Subchannel"},
+ {.irq = IRQIO_CSC, .name = "CSC", .desc = "[I/O] CHSC Subchannel"},
+- {.irq = IRQIO_PCI, .name = "PCI", .desc = "[I/O] PCI Interrupt" },
+- {.irq = IRQIO_MSI, .name = "MSI", .desc = "[I/O] MSI Interrupt" },
+ {.irq = IRQIO_VIR, .name = "VIR", .desc = "[I/O] Virtual I/O Devices"},
+- {.irq = IRQIO_VAI, .name = "VAI", .desc = "[I/O] Virtual I/O Devices AI"},
++ {.irq = IRQIO_QAI, .name = "QAI", .desc = "[AIO] QDIO Adapter Interrupt"},
++ {.irq = IRQIO_APB, .name = "APB", .desc = "[AIO] AP Bus"},
++ {.irq = IRQIO_PCI, .name = "PCI", .desc = "[AIO] PCI Interrupt"},
++ {.irq = IRQIO_MSI, .name = "MSI", .desc = "[AIO] MSI Interrupt"},
++ {.irq = IRQIO_VAI, .name = "VAI", .desc = "[AIO] Virtual I/O Devices AI"},
+ {.irq = NMI_NMI, .name = "NMI", .desc = "[NMI] Machine Check"},
+ {.irq = CPU_RST, .name = "RST", .desc = "[CPU] CPU Restart"},
+ };
+@@ -113,6 +113,34 @@ void do_IRQ(struct pt_regs *regs, int ir
+ set_irq_regs(old_regs);
+ }
+
++static void show_msi_interrupt(struct seq_file *p, int irq)
++{
++ struct irq_desc *desc;
++ unsigned long flags;
++ int cpu;
++
++ irq_lock_sparse();
++ desc = irq_to_desc(irq);
++ if (!desc)
++ goto out;
++
++ raw_spin_lock_irqsave(&desc->lock, flags);
++ seq_printf(p, "%3d: ", irq);
++ for_each_online_cpu(cpu)
++ seq_printf(p, "%10u ", kstat_irqs_cpu(irq, cpu));
++
++ if (desc->irq_data.chip)
++ seq_printf(p, " %8s", desc->irq_data.chip->name);
++
++ if (desc->action)
++ seq_printf(p, " %s", desc->action->name);
++
++ seq_putc(p, '\n');
++ raw_spin_unlock_irqrestore(&desc->lock, flags);
++out:
++ irq_unlock_sparse();
++}
++
+ /*
+ * show_interrupts is needed by /proc/interrupts.
+ */
+@@ -125,7 +153,7 @@ int show_interrupts(struct seq_file *p,
+ if (index == 0) {
+ seq_puts(p, " ");
+ for_each_online_cpu(cpu)
+- seq_printf(p, "CPU%d ", cpu);
++ seq_printf(p, "CPU%-8d", cpu);
+ seq_putc(p, '\n');
+ }
+ if (index < NR_IRQS_BASE) {
+@@ -136,9 +164,10 @@ int show_interrupts(struct seq_file *p,
+ seq_putc(p, '\n');
+ goto out;
+ }
+- if (index > NR_IRQS_BASE)
++ if (index < nr_irqs) {
++ show_msi_interrupt(p, index);
+ goto out;
+-
++ }
+ for (index = 0; index < NR_ARCH_IRQS; index++) {
+ seq_printf(p, "%s: ", irqclass_sub_desc[index].name);
+ irq = irqclass_sub_desc[index].irq;
+--- a/arch/s390/pci/pci_irq.c
++++ b/arch/s390/pci/pci_irq.c
+@@ -112,7 +112,7 @@ static int zpci_set_irq_affinity(struct
+ }
+
+ static struct irq_chip zpci_irq_chip = {
+- .name = "zPCI",
++ .name = "PCI-MSI",
+ .irq_unmask = pci_msi_unmask_irq,
+ .irq_mask = pci_msi_mask_irq,
+ .irq_set_affinity = zpci_set_irq_affinity,
+--- a/drivers/s390/cio/cio.c
++++ b/drivers/s390/cio/cio.c
+@@ -634,7 +634,7 @@ static irqreturn_t do_cio_interrupt(int
+ }
+
+ static struct irqaction io_interrupt = {
+- .name = "IO",
++ .name = "I/O",
+ .handler = do_cio_interrupt,
+ };
+
diff --git a/patches.arch/s390-uv-introduce-guest-side-ultravisor-code b/patches.arch/s390-uv-introduce-guest-side-ultravisor-code
new file mode 100644
index 0000000000..6d5999a087
--- /dev/null
+++ b/patches.arch/s390-uv-introduce-guest-side-ultravisor-code
@@ -0,0 +1,257 @@
+From: Vasily Gorbik <gor@linux.ibm.com>
+Date: Mon, 1 Apr 2019 19:11:03 +0200
+Subject: s390/uv: introduce guest side ultravisor code
+Git-commit: 5abb9351dfd937d43193f4d09af9c72bfe2c4180
+Patch-mainline: v5.2-rc1
+References: jsc#SLE-5759 FATE#327003 bsc#1135153 LTC#173151
+
+The Ultravisor Call Facility (stfle bit 158) defines an API to the
+Ultravisor (UV calls), a mini hypervisor located at machine
+level. With help of the Ultravisor, KVM will be able to run
+"protected" VMs, special VMs whose memory and management data are
+unavailable to KVM.
+
+The protected VMs can also request services from the Ultravisor.
+The guest api consists of UV calls to share and unshare memory with the
+kvm hypervisor.
+
+To enable this feature support PROTECTED_VIRTUALIZATION_GUEST kconfig
+option has been introduced.
+
+Co-developed-by: Janosch Frank <frankja@de.ibm.com>
+Signed-off-by: Janosch Frank <frankja@de.ibm.com>
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+
+[ ptesarik: Added SLE modifications by IBM's Vasily Gorbik, because
+ SLE15-SP1 does not contain these upstream commits:
+ 49698745e53c417370ac5cfe8b849bb65d62f129
+ bf9921a9c15bad089c08b94c300a6cafa035a612
+ Removed duplicate definition of prot_virt_guest in
+ arch/s390/kernel/setup.c. ]
+
+---
+ arch/s390/Kconfig | 11 +++
+ arch/s390/include/asm/uv.h | 132 +++++++++++++++++++++++++++++++++++++++++++++
+ arch/s390/kernel/Makefile | 1
+ arch/s390/kernel/early.c | 4 +
+ arch/s390/kernel/uv.c | 23 +++++++
+ 5 files changed, 170 insertions(+), 1 deletion(-)
+
+--- a/arch/s390/Kconfig
++++ b/arch/s390/Kconfig
+@@ -856,6 +856,17 @@ source "lib/Kconfig"
+
+ menu "Virtualization"
+
++config PROTECTED_VIRTUALIZATION_GUEST
++ def_bool n
++ prompt "Protected virtualization guest support"
++ help
++ Select this option, if you want to be able to run this
++ kernel as a protected virtualization KVM guest.
++ Protected virtualization capable machines have a mini hypervisor
++ located at machine level (an ultravisor). With help of the
++ Ultravisor, KVM will be able to run "protected" VMs, special
++ VMs whose memory and management data are unavailable to KVM.
++
+ config PFAULT
+ def_bool y
+ prompt "Pseudo page fault support"
+--- /dev/null
++++ b/arch/s390/include/asm/uv.h
+@@ -0,0 +1,132 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Ultravisor Interfaces
++ *
++ * Copyright IBM Corp. 2019
++ *
++ * Author(s):
++ * Vasily Gorbik <gor@linux.ibm.com>
++ * Janosch Frank <frankja@linux.ibm.com>
++ */
++#ifndef _ASM_S390_UV_H
++#define _ASM_S390_UV_H
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/bug.h>
++#include <asm/page.h>
++
++#define UVC_RC_EXECUTED 0x0001
++#define UVC_RC_INV_CMD 0x0002
++#define UVC_RC_INV_STATE 0x0003
++#define UVC_RC_INV_LEN 0x0005
++#define UVC_RC_NO_RESUME 0x0007
++
++#define UVC_CMD_QUI 0x0001
++#define UVC_CMD_SET_SHARED_ACCESS 0x1000
++#define UVC_CMD_REMOVE_SHARED_ACCESS 0x1001
++
++/* Bits in installed uv calls */
++enum uv_cmds_inst {
++ BIT_UVC_CMD_QUI = 0,
++ BIT_UVC_CMD_SET_SHARED_ACCESS = 8,
++ BIT_UVC_CMD_REMOVE_SHARED_ACCESS = 9,
++};
++
++struct uv_cb_header {
++ u16 len;
++ u16 cmd; /* Command Code */
++ u16 rc; /* Response Code */
++ u16 rrc; /* Return Reason Code */
++} __packed __aligned(8);
++
++struct uv_cb_qui {
++ struct uv_cb_header header;
++ u64 reserved08;
++ u64 inst_calls_list[4];
++ u64 reserved30[15];
++} __packed __aligned(8);
++
++struct uv_cb_share {
++ struct uv_cb_header header;
++ u64 reserved08[3];
++ u64 paddr;
++ u64 reserved28;
++} __packed __aligned(8);
++
++static inline int uv_call(unsigned long r1, unsigned long r2)
++{
++ int cc;
++
++ asm volatile(
++ "0: .insn rrf,0xB9A40000,%[r1],%[r2],0,0\n"
++ " brc 3,0b\n"
++ " ipm %[cc]\n"
++ " srl %[cc],28\n"
++ : [cc] "=d" (cc)
++ : [r1] "a" (r1), [r2] "a" (r2)
++ : "memory", "cc");
++ return cc;
++}
++
++#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
++extern int prot_virt_guest;
++
++static inline int is_prot_virt_guest(void)
++{
++ return prot_virt_guest;
++}
++
++static inline int share(unsigned long addr, u16 cmd)
++{
++ struct uv_cb_share uvcb = {
++ .header.cmd = cmd,
++ .header.len = sizeof(uvcb),
++ .paddr = addr
++ };
++
++ if (!is_prot_virt_guest())
++ return -ENOTSUPP;
++ /*
++ * Sharing is page wise, if we encounter addresses that are
++ * not page aligned, we assume something went wrong. If
++ * malloced structs are passed to this function, we could leak
++ * data to the hypervisor.
++ */
++ BUG_ON(addr & ~PAGE_MASK);
++
++ if (!uv_call(0, (u64)&uvcb))
++ return 0;
++ return -EINVAL;
++}
++
++/*
++ * Guest 2 request to the Ultravisor to make a page shared with the
++ * hypervisor for IO.
++ *
++ * @addr: Real or absolute address of the page to be shared
++ */
++static inline int uv_set_shared(unsigned long addr)
++{
++ return share(addr, UVC_CMD_SET_SHARED_ACCESS);
++}
++
++/*
++ * Guest 2 request to the Ultravisor to make a page unshared.
++ *
++ * @addr: Real or absolute address of the page to be unshared
++ */
++static inline int uv_remove_shared(unsigned long addr)
++{
++ return share(addr, UVC_CMD_REMOVE_SHARED_ACCESS);
++}
++
++void uv_query_info(void);
++#else
++#define is_prot_virt_guest() 0
++static inline int uv_set_shared(unsigned long addr) { return 0; }
++static inline int uv_remove_shared(unsigned long addr) { return 0; }
++static inline void uv_query_info(void) {}
++#endif
++
++#endif /* _ASM_S390_UV_H */
+--- a/arch/s390/kernel/Makefile
++++ b/arch/s390/kernel/Makefile
+@@ -84,6 +84,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.
+ obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_events.o
+
+ obj-$(CONFIG_TRACEPOINTS) += trace.o
++obj-$(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) += uv.o
+
+ # vdso
+ obj-y += vdso64/
+--- a/arch/s390/kernel/early.c
++++ b/arch/s390/kernel/early.c
+@@ -28,6 +28,7 @@
+ #include <asm/cpcmd.h>
+ #include <asm/sclp.h>
+ #include <asm/facility.h>
++#include <asm/uv.h>
+ #include "entry.h"
+
+ /*
+@@ -558,12 +559,13 @@ void __init startup_init(void)
+ ipl_save_parameters();
+ rescue_initrd();
+ clear_bss_section();
++ setup_facility_list();
++ uv_query_info();
+ ipl_verify_parameters();
+ time_early_init();
+ init_kernel_storage_key();
+ lockdep_off();
+ setup_lowcore_early();
+- setup_facility_list();
+ detect_machine_type();
+ setup_arch_string();
+ ipl_update_parameters();
+--- /dev/null
++++ b/arch/s390/kernel/uv.c
+@@ -0,0 +1,23 @@
++// SPDX-License-Identifier: GPL-2.0
++#include <asm/uv.h>
++#include <asm/facility.h>
++
++int prot_virt_guest;
++
++void uv_query_info(void)
++{
++ struct uv_cb_qui uvcb = {
++ .header.cmd = UVC_CMD_QUI,
++ .header.len = sizeof(uvcb)
++ };
++
++ if (!test_facility(158))
++ return;
++
++ if (uv_call(0, (uint64_t)&uvcb))
++ return;
++
++ if (test_bit_inv(BIT_UVC_CMD_SET_SHARED_ACCESS, (unsigned long *)uvcb.inst_calls_list) &&
++ test_bit_inv(BIT_UVC_CMD_REMOVE_SHARED_ACCESS, (unsigned long *)uvcb.inst_calls_list))
++ prot_virt_guest = 1;
++}
diff --git a/patches.arch/x86-amd_nb-add-pci-device-ids-for-family-17h-model-30h.patch b/patches.arch/x86-amd_nb-add-pci-device-ids-for-family-17h-model-30h.patch
index 17c39d1ebd..f45d89847a 100644
--- a/patches.arch/x86-amd_nb-add-pci-device-ids-for-family-17h-model-30h.patch
+++ b/patches.arch/x86-amd_nb-add-pci-device-ids-for-family-17h-model-30h.patch
@@ -30,20 +30,21 @@ Link: http://lkml.kernel.org/r/20181106200754.60722-4-brian.woods@amd.com
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
-@@ -15,7 +15,9 @@
- #include <asm/amd_nb.h>
+@@ -16,8 +16,10 @@
#define PCI_DEVICE_ID_AMD_17H_ROOT 0x1450
+ #define PCI_DEVICE_ID_AMD_17H_M10H_ROOT 0x15d0
+#define PCI_DEVICE_ID_AMD_17H_M30H_ROOT 0x1480
#define PCI_DEVICE_ID_AMD_17H_DF_F4 0x1464
+ #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F4 0x15ec
+#define PCI_DEVICE_ID_AMD_17H_M30H_DF_F4 0x1494
/* Protect the PCI config register pairs used for SMN and DF indirect access. */
static DEFINE_MUTEX(smn_mutex);
-@@ -24,9 +26,11 @@ static u32 *flush_words;
-
+@@ -27,9 +29,11 @@ static u32 *flush_words;
static const struct pci_device_id amd_root_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_ROOT) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_ROOT) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_ROOT) },
{}
};
@@ -52,25 +53,25 @@ Link: http://lkml.kernel.org/r/20181106200754.60722-4-brian.woods@amd.com
#define PCI_DEVICE_ID_AMD_CNB17H_F4 0x1704
const struct pci_device_id amd_nb_misc_ids[] = {
-@@ -39,6 +43,7 @@ const struct pci_device_id amd_nb_misc_i
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
+@@ -43,6 +47,7 @@ const struct pci_device_id amd_nb_misc_i
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
{}
};
-@@ -51,6 +56,7 @@ static const struct pci_device_id amd_nb
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
+@@ -56,6 +61,7 @@ static const struct pci_device_id amd_nb
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F4) },
{}
};
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
-@@ -539,6 +539,7 @@
+@@ -542,6 +542,7 @@
#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F4 0x1584
#define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463
#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F3 0x15eb
diff --git a/patches.arch/x86-amd_nb-add-support-for-raven-ridge-cpus.patch b/patches.arch/x86-amd_nb-add-support-for-raven-ridge-cpus.patch
new file mode 100644
index 0000000000..9da914c237
--- /dev/null
+++ b/patches.arch/x86-amd_nb-add-support-for-raven-ridge-cpus.patch
@@ -0,0 +1,56 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Fri, 4 May 2018 13:01:32 -0700
+Subject: x86/amd_nb: Add support for Raven Ridge CPUs
+Git-commit: f9bc6b2dd9cf025f827f471769e1d88b527bfb91
+Patch-mainline: v4.17
+References: FATE#327735
+
+Add Raven Ridge root bridge and data fabric PCI IDs.
+This is required for amd_pci_dev_to_node_id() and amd_smn_read().
+
+Cc: stable@vger.kernel.org # v4.16+
+Tested-by: Gabriel Craciunescu <nix.or.die@gmail.com>
+Acked-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c
+index c88e0b127810..b481b95bd8f6 100644
+--- a/arch/x86/kernel/amd_nb.c
++++ b/arch/x86/kernel/amd_nb.c
+@@ -14,8 +14,11 @@
+ #include <asm/amd_nb.h>
+
+ #define PCI_DEVICE_ID_AMD_17H_ROOT 0x1450
++#define PCI_DEVICE_ID_AMD_17H_M10H_ROOT 0x15d0
+ #define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463
+ #define PCI_DEVICE_ID_AMD_17H_DF_F4 0x1464
++#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F3 0x15eb
++#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F4 0x15ec
+
+ /* Protect the PCI config register pairs used for SMN and DF indirect access. */
+ static DEFINE_MUTEX(smn_mutex);
+@@ -24,6 +27,7 @@ static u32 *flush_words;
+
+ static const struct pci_device_id amd_root_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_ROOT) },
++ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_ROOT) },
+ {}
+ };
+
+@@ -39,6 +43,7 @@ const struct pci_device_id amd_nb_misc_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
++ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
+ {}
+ };
+@@ -51,6 +56,7 @@ static const struct pci_device_id amd_nb_link_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F4) },
++ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F4) },
+ {}
+ };
diff --git a/patches.arch/x86-cpu-amd-don-t-force-the-cpb-cap-when-running-under-a-hypervisor.patch b/patches.arch/x86-cpu-amd-don-t-force-the-cpb-cap-when-running-under-a-hypervisor.patch
new file mode 100644
index 0000000000..41cd328937
--- /dev/null
+++ b/patches.arch/x86-cpu-amd-don-t-force-the-cpb-cap-when-running-under-a-hypervisor.patch
@@ -0,0 +1,65 @@
+From: Frank van der Linden <fllinden@amazon.com>
+Date: Wed, 22 May 2019 22:17:45 +0000
+Subject: x86/CPU/AMD: Don't force the CPB cap when running under a hypervisor
+Git-commit: 2ac44ab608705948564791ce1d15d43ba81a1e38
+Patch-mainline: v5.2-rc3
+References: bsc#1114279
+
+For F17h AMD CPUs, the CPB capability ('Core Performance Boost') is forcibly set,
+because some versions of that chip incorrectly report that they do not have it.
+
+However, a hypervisor may filter out the CPB capability, for good
+reasons. For example, KVM currently does not emulate setting the CPB
+bit in MSR_K7_HWCR, and unchecked MSR access errors will be thrown
+when trying to set it as a guest:
+
+ unchecked MSR access error: WRMSR to 0xc0010015 (tried to write 0x0000000001000011) at rIP: 0xffffffff890638f4 (native_write_msr+0x4/0x20)
+
+ Call Trace:
+ boost_set_msr+0x50/0x80 [acpi_cpufreq]
+ cpuhp_invoke_callback+0x86/0x560
+ sort_range+0x20/0x20
+ cpuhp_thread_fun+0xb0/0x110
+ smpboot_thread_fn+0xef/0x160
+ kthread+0x113/0x130
+ kthread_create_worker_on_cpu+0x70/0x70
+ ret_from_fork+0x35/0x40
+
+To avoid this issue, don't forcibly set the CPB capability for a CPU
+when running under a hypervisor.
+
+Signed-off-by: Frank van der Linden <fllinden@amazon.com>
+Acked-by: Borislav Petkov <bp@suse.de>
+Cc: Andy Lutomirski <luto@kernel.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: bp@alien8.de
+Cc: jiaxun.yang@flygoat.com
+Fixes: 0237199186e7 ("x86/CPU/AMD: Set the CPB bit unconditionally on F17h")
+Link: http://lkml.kernel.org/r/20190522221745.GA15789@dev-dsk-fllinden-2c-c1893d73.us-west-2.amazon.com
+[ Minor edits to the changelog. ]
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+---
+ arch/x86/kernel/cpu/amd.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
+index 80a405c2048a..8d4e50428b68 100644
+--- a/arch/x86/kernel/cpu/amd.c
++++ b/arch/x86/kernel/cpu/amd.c
+@@ -824,8 +824,11 @@ static void init_amd_zn(struct cpuinfo_x86 *c)
+ {
+ set_cpu_cap(c, X86_FEATURE_ZEN);
+
+- /* Fix erratum 1076: CPB feature bit not being set in CPUID. */
+- if (!cpu_has(c, X86_FEATURE_CPB))
++ /*
++ * Fix erratum 1076: CPB feature bit not being set in CPUID.
++ * Always set it, except when running under a hypervisor.
++ */
++ if (!cpu_has(c, X86_FEATURE_HYPERVISOR) && !cpu_has(c, X86_FEATURE_CPB))
+ set_cpu_cap(c, X86_FEATURE_CPB);
+ }
+
+
diff --git a/patches.arch/x86-mce-fix-machine_check_poll-tests-for-error-types.patch b/patches.arch/x86-mce-fix-machine_check_poll-tests-for-error-types.patch
new file mode 100644
index 0000000000..ed550385fe
--- /dev/null
+++ b/patches.arch/x86-mce-fix-machine_check_poll-tests-for-error-types.patch
@@ -0,0 +1,103 @@
+From: Tony Luck <tony.luck@intel.com>
+Date: Tue, 12 Mar 2019 10:09:38 -0700
+Subject: x86/mce: Fix machine_check_poll() tests for error types
+Git-commit: f19501aa07f18268ab14f458b51c1c6b7f72a134
+Patch-mainline: v5.2-rc1
+References: bsc#1114279
+
+There has been a lurking "TBD" in the machine check poll routine ever
+since it was first split out from the machine check handler. The
+potential issue is that the poll routine may have just begun a read from
+the STATUS register in a machine check bank when the hardware logs an
+error in that bank and signals a machine check.
+
+That race used to be pretty small back when machine checks were
+broadcast, but the addition of local machine check means that the poll
+code could continue running and clear the error from the bank before the
+local machine check handler on another CPU gets around to reading it.
+
+Fix the code to be sure to only process errors that need to be processed
+in the poll code, leaving other logged errors alone for the machine
+check handler to find and process.
+
+ [ bp: Massage a bit and flip the "== 0" check to the usual !(..) test. ]
+
+Fixes: b79109c3bbcf ("x86, mce: separate correct machine check poller and fatal exception handler")
+Fixes: ed7290d0ee8f ("x86, mce: implement new status bits")
+Reported-by: Ashok Raj <ashok.raj@intel.com>
+Signed-off-by: Tony Luck <tony.luck@intel.com>
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Cc: Ashok Raj <ashok.raj@intel.com>
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: linux-edac <linux-edac@vger.kernel.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: x86-ml <x86@kernel.org>
+Cc: Yazen Ghannam <Yazen.Ghannam@amd.com>
+Link: https://lkml.kernel.org/r/20190312170938.GA23035@agluck-desk
+---
+ arch/x86/kernel/cpu/mcheck/mce.c | 44 +++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 37 insertions(+), 7 deletions(-)
+
+diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
+index b7fb541a4873..e558ca77cfe8 100644
+--- a/arch/x86/kernel/cpu/mcheck/mce.c
++++ b/arch/x86/kernel/cpu/mcheck/mce.c
+@@ -712,19 +712,49 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
+
+ barrier();
+ m.status = mce_rdmsrl(msr_ops.status(i));
++
++ /* If this entry is not valid, ignore it */
+ if (!(m.status & MCI_STATUS_VAL))
+ continue;
+
+ /*
+- * Uncorrected or signalled events are handled by the exception
+- * handler when it is enabled, so don't process those here.
+- *
+- * TBD do the same check for MCI_STATUS_EN here?
++ * If we are logging everything (at CPU online) or this
++ * is a corrected error, then we must log it.
+ */
+- if (!(flags & MCP_UC) &&
+- (m.status & (mca_cfg.ser ? MCI_STATUS_S : MCI_STATUS_UC)))
+- continue;
++ if ((flags & MCP_UC) || !(m.status & MCI_STATUS_UC))
++ goto log_it;
++
++ /*
++ * Newer Intel systems that support software error
++ * recovery need to make additional checks. Other
++ * CPUs should skip over uncorrected errors, but log
++ * everything else.
++ */
++ if (!mca_cfg.ser) {
++ if (m.status & MCI_STATUS_UC)
++ continue;
++ goto log_it;
++ }
++
++ /* Log "not enabled" (speculative) errors */
++ if (!(m.status & MCI_STATUS_EN))
++ goto log_it;
++
++ /*
++ * Log UCNA (SDM: 15.6.3 "UCR Error Classification")
++ * UC == 1 && PCC == 0 && S == 0
++ */
++ if (!(m.status & MCI_STATUS_PCC) && !(m.status & MCI_STATUS_S))
++ goto log_it;
++
++ /*
++ * Skip anything else. Presumption is that our read of this
++ * bank is racing with a machine check. Leave the log alone
++ * for do_machine_check() to deal with it.
++ */
++ continue;
+
++log_it:
+ error_seen = true;
+
+ mce_read_aux(&m, i);
+
diff --git a/patches.arch/x86-microcode-cpuhotplug-add-a-microcode-loader-cpu-hotplug-callback.patch b/patches.arch/x86-microcode-cpuhotplug-add-a-microcode-loader-cpu-hotplug-callback.patch
new file mode 100644
index 0000000000..feaa22f1ea
--- /dev/null
+++ b/patches.arch/x86-microcode-cpuhotplug-add-a-microcode-loader-cpu-hotplug-callback.patch
@@ -0,0 +1,72 @@
+From: Borislav Petkov <bp@suse.de>
+Date: Thu, 13 Jun 2019 15:49:02 +0200
+Subject: x86/microcode, cpuhotplug: Add a microcode loader CPU hotplug callback
+Git-commit: 78f4e932f7760d965fb1569025d1576ab77557c5
+Patch-mainline: v5.2-rc5
+References: bsc#1114279
+
+Adric Blake reported the following warning during suspend-resume:
+
+ Enabling non-boot CPUs ...
+ x86: Booting SMP configuration:
+ smpboot: Booting Node 0 Processor 1 APIC 0x2
+ unchecked MSR access error: WRMSR to 0x10f (tried to write 0x0000000000000000) \
+ at rIP: 0xffffffff8d267924 (native_write_msr+0x4/0x20)
+ Call Trace:
+ intel_set_tfa
+ intel_pmu_cpu_starting
+ ? x86_pmu_dead_cpu
+ x86_pmu_starting_cpu
+ cpuhp_invoke_callback
+ ? _raw_spin_lock_irqsave
+ notify_cpu_starting
+ start_secondary
+ secondary_startup_64
+ microcode: sig=0x806ea, pf=0x80, revision=0x96
+ microcode: updated to revision 0xb4, date = 2019-04-01
+ CPU1 is up
+
+The MSR in question is MSR_TFA_RTM_FORCE_ABORT and that MSR is emulated
+by microcode. The log above shows that the microcode loader callback
+happens after the PMU restoration, leading to the conjecture that
+because the microcode hasn't been updated yet, that MSR is not present
+yet, leading to the #GP.
+
+Add a microcode loader-specific hotplug vector which comes before
+the PERF vectors and thus executes earlier and makes sure the MSR is
+present.
+
+Fixes: 400816f60c54 ("perf/x86/intel: Implement support for TSX Force Abort")
+Reported-by: Adric Blake <promarbler14@gmail.com>
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: <stable@vger.kernel.org>
+Cc: x86@kernel.org
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=203637
+---
+ arch/x86/kernel/cpu/microcode/core.c | 2 +-
+ include/linux/cpuhotplug.h | 1 +
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/kernel/cpu/microcode/core.c
++++ b/arch/x86/kernel/cpu/microcode/core.c
+@@ -853,7 +853,7 @@ int __init microcode_init(void)
+ goto out_ucode_group;
+
+ register_syscore_ops(&mc_syscore_ops);
+- cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "x86/microcode:online",
++ cpuhp_setup_state_nocalls(CPUHP_AP_MICROCODE_LOADER, "x86/microcode:online",
+ mc_cpu_online, mc_cpu_down_prep);
+
+ pr_info("Microcode Update Driver: v%s.", DRIVER_VERSION);
+--- a/include/linux/cpuhotplug.h
++++ b/include/linux/cpuhotplug.h
+@@ -84,6 +84,7 @@ enum cpuhp_state {
+ CPUHP_AP_IRQ_ARMADA_XP_STARTING,
+ CPUHP_AP_IRQ_BCM2836_STARTING,
+ CPUHP_AP_ARM_MVEBU_COHERENCY,
++ CPUHP_AP_MICROCODE_LOADER,
+ CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING,
+ CPUHP_AP_PERF_X86_STARTING,
+ CPUHP_AP_PERF_X86_AMD_IBS_STARTING,
diff --git a/patches.arch/x86-microcode-fix-the-ancient-deprecated-microcode-loading-method.patch b/patches.arch/x86-microcode-fix-the-ancient-deprecated-microcode-loading-method.patch
new file mode 100644
index 0000000000..09f5dbadd8
--- /dev/null
+++ b/patches.arch/x86-microcode-fix-the-ancient-deprecated-microcode-loading-method.patch
@@ -0,0 +1,42 @@
+From: Borislav Petkov <bp@suse.de>
+Date: Thu, 4 Apr 2019 22:14:07 +0200
+Subject: x86/microcode: Fix the ancient deprecated microcode loading method
+Git-commit: 24613a04ad1c0588c10f4b5403ca60a73d164051
+Patch-mainline: v5.2-rc1
+References: bsc#1114279
+
+Commit
+
+ 2613f36ed965 ("x86/microcode: Attempt late loading only when new microcode is present")
+
+added the new define UCODE_NEW to denote that an update should happen
+only when newer microcode (than installed on the system) has been found.
+
+But it missed adjusting that for the old /dev/cpu/microcode loading
+interface. Fix it.
+
+Fixes: 2613f36ed965 ("x86/microcode: Attempt late loading only when new microcode is present")
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: Jann Horn <jannh@google.com>
+Link: https://lkml.kernel.org/r/20190405133010.24249-3-bp@alien8.de
+---
+ arch/x86/kernel/cpu/microcode/core.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
+index 5260185cbf7b..8a4a7823451a 100644
+--- a/arch/x86/kernel/cpu/microcode/core.c
++++ b/arch/x86/kernel/cpu/microcode/core.c
+@@ -418,8 +418,9 @@ static int do_microcode_update(const void __user *buf, size_t size)
+ if (ustate == UCODE_ERROR) {
+ error = -1;
+ break;
+- } else if (ustate == UCODE_OK)
++ } else if (ustate == UCODE_NEW) {
+ apply_microcode_on_target(cpu);
++ }
+ }
+
+ return error;
+
diff --git a/patches.arch/x86-mm-mem_encrypt-disable-all-instrumentation-for-early-sme-setup.patch b/patches.arch/x86-mm-mem_encrypt-disable-all-instrumentation-for-early-sme-setup.patch
new file mode 100644
index 0000000000..71866ad228
--- /dev/null
+++ b/patches.arch/x86-mm-mem_encrypt-disable-all-instrumentation-for-early-sme-setup.patch
@@ -0,0 +1,94 @@
+From: Gary Hook <Gary.Hook@amd.com>
+Date: Mon, 29 Apr 2019 22:22:58 +0000
+Subject: x86/mm/mem_encrypt: Disable all instrumentation for early SME setup
+Git-commit: b51ce3744f115850166f3d6c292b9c8cb849ad4f
+Patch-mainline: v5.1
+References: bsc#1114279
+
+Enablement of AMD's Secure Memory Encryption feature is determined very
+early after start_kernel() is entered. Part of this procedure involves
+scanning the command line for the parameter 'mem_encrypt'.
+
+To determine intended state, the function sme_enable() uses library
+functions cmdline_find_option() and strncmp(). Their use occurs early
+enough such that it cannot be assumed that any instrumentation subsystem
+is initialized.
+
+For example, making calls to a KASAN-instrumented function before KASAN
+is set up will result in the use of uninitialized memory and a boot
+failure.
+
+When AMD's SME support is enabled, conditionally disable instrumentation
+of these dependent functions in lib/string.c and arch/x86/lib/cmdline.c.
+
+ [ bp: Get rid of intermediary nostackp var and cleanup whitespace. ]
+
+Fixes: aca20d546214 ("x86/mm: Add support to make use of Secure Memory Encryption")
+Reported-by: Li RongQing <lirongqing@baidu.com>
+Signed-off-by: Gary R Hook <gary.hook@amd.com>
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Cc: Boris Brezillon <bbrezillon@kernel.org>
+Cc: Coly Li <colyli@suse.de>
+Cc: "dave.hansen@linux.intel.com" <dave.hansen@linux.intel.com>
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: Kent Overstreet <kent.overstreet@gmail.com>
+Cc: "luto@kernel.org" <luto@kernel.org>
+Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
+Cc: Matthew Wilcox <willy@infradead.org>
+Cc: "mingo@redhat.com" <mingo@redhat.com>
+Cc: "peterz@infradead.org" <peterz@infradead.org>
+Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: x86-ml <x86@kernel.org>
+Link: https://lkml.kernel.org/r/155657657552.7116.18363762932464011367.stgit@sosrh3.amd.com
+---
+ arch/x86/lib/Makefile | 12 ++++++++++++
+ lib/Makefile | 11 +++++++++++
+ 2 files changed, 23 insertions(+)
+
+--- a/arch/x86/lib/Makefile
++++ b/arch/x86/lib/Makefile
+@@ -5,6 +5,18 @@
+ # Produces uninteresting flaky coverage.
+ KCOV_INSTRUMENT_delay.o := n
+
++# Early boot use of cmdline; don't instrument it
++ifdef CONFIG_AMD_MEM_ENCRYPT
++KCOV_INSTRUMENT_cmdline.o := n
++KASAN_SANITIZE_cmdline.o := n
++
++ifdef CONFIG_FUNCTION_TRACER
++CFLAGS_REMOVE_cmdline.o = -pg
++endif
++
++CFLAGS_cmdline.o := $(call cc-option, -fno-stack-protector)
++endif
++
+ inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk
+ inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt
+ quiet_cmd_inat_tables = GEN $@
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -16,6 +16,17 @@ KCOV_INSTRUMENT_list_debug.o := n
+ KCOV_INSTRUMENT_debugobjects.o := n
+ KCOV_INSTRUMENT_dynamic_debug.o := n
+
++# Early boot use of cmdline, don't instrument it
++ifdef CONFIG_AMD_MEM_ENCRYPT
++KASAN_SANITIZE_string.o := n
++
++ifdef CONFIG_FUNCTION_TRACER
++CFLAGS_REMOVE_string.o = -pg
++endif
++
++CFLAGS_string.o := $(call cc-option, -fno-stack-protector)
++endif
++
+ lib-y := ctype.o string.o vsprintf.o cmdline.o \
+ rbtree.o radix-tree.o dump_stack.o timerqueue.o\
+ idr.o int_sqrt.o extable.o \
diff --git a/patches.arch/x86-speculation-mds-revert-cpu-buffer-clear-on-double-fault-exit.patch b/patches.arch/x86-speculation-mds-revert-cpu-buffer-clear-on-double-fault-exit.patch
new file mode 100644
index 0000000000..4e0b16cc72
--- /dev/null
+++ b/patches.arch/x86-speculation-mds-revert-cpu-buffer-clear-on-double-fault-exit.patch
@@ -0,0 +1,70 @@
+From: Andy Lutomirski <luto@kernel.org>
+Date: Tue, 14 May 2019 13:24:39 -0700
+Subject: x86/speculation/mds: Revert CPU buffer clear on double fault exit
+Git-commit: 88640e1dcd089879530a49a8d212d1814678dfe7
+Patch-mainline: v5.2-rc1
+References: bsc#1114279
+
+The double fault ESPFIX path doesn't return to user mode at all --
+it returns back to the kernel by simulating a #GP fault.
+prepare_exit_to_usermode() will run on the way out of
+general_protection before running user code.
+
+Signed-off-by: Andy Lutomirski <luto@kernel.org>
+Cc: Borislav Petkov <bp@suse.de>
+Cc: Frederic Weisbecker <frederic@kernel.org>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Jon Masters <jcm@redhat.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: stable@vger.kernel.org
+Fixes: 04dcbdb80578 ("x86/speculation/mds: Clear CPU buffers on exit to user")
+Link: http://lkml.kernel.org/r/ac97612445c0a44ee10374f6ea79c222fe22a5c4.1557865329.git.luto@kernel.org
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Acked-by: Borislav Petkov <bp@suse.de>
+---
+ Documentation/x86/mds.rst | 7 -------
+ arch/x86/kernel/traps.c | 8 --------
+ 2 files changed, 15 deletions(-)
+
+--- a/arch/x86/kernel/traps.c
++++ b/arch/x86/kernel/traps.c
+@@ -59,7 +59,6 @@
+ #include <asm/alternative.h>
+ #include <asm/fpu/xstate.h>
+ #include <asm/trace/mpx.h>
+-#include <asm/nospec-branch.h>
+ #include <asm/mpx.h>
+ #include <asm/vm86.h>
+ #include <asm/umip.h>
+@@ -394,13 +393,6 @@ dotraplinkage void do_double_fault(struc
+ regs->ip = (unsigned long)general_protection;
+ regs->sp = (unsigned long)&gpregs->orig_ax;
+
+- /*
+- * This situation can be triggered by userspace via
+- * modify_ldt(2) and the return does not take the regular
+- * user space exit, so a CPU buffer clear is required when
+- * MDS mitigation is enabled.
+- */
+- mds_user_clear_cpu_buffers();
+ return;
+ }
+ #endif
+--- a/Documentation/x86/mds.rst
++++ b/Documentation/x86/mds.rst
+@@ -157,13 +157,6 @@ Mitigation points
+ mitigated on the return from do_nmi() to provide almost complete
+ coverage.
+
+- - Double fault (#DF):
+-
+- A double fault is usually fatal, but the ESPFIX workaround, which can
+- be triggered from user space through modify_ldt(2) is a recoverable
+- double fault. #DF uses the paranoid exit path, so explicit mitigation
+- in the double fault handler is required.
+-
+ - Machine Check Exception (#MC):
+
+ Another corner case is a #MC which hits between the CPU buffer clear
diff --git a/patches.arch/x86-umip-make-the-umip-activated-message-generic.patch b/patches.arch/x86-umip-make-the-umip-activated-message-generic.patch
new file mode 100644
index 0000000000..a78cc7b50e
--- /dev/null
+++ b/patches.arch/x86-umip-make-the-umip-activated-message-generic.patch
@@ -0,0 +1,37 @@
+From: "Lendacky, Thomas" <Thomas.Lendacky@amd.com>
+Date: Tue, 4 Dec 2018 22:27:20 +0000
+Subject: x86/umip: Make the UMIP activated message generic
+Git-commit: 438cbf8871246606f2fc1964d301fa02af39e4e4
+Patch-mainline: v5.0-rc1
+References: bsc#1138336
+
+The User Mode Instruction Prevention (UMIP) feature is part of the x86_64
+instruction set architecture and not specific to Intel. Make the message
+generic.
+
+Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: linux-kernel@vger.kernel.org
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Acked-by: Borislav Petkov <bp@suse.de>
+---
+ arch/x86/kernel/cpu/common.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
+index 2c56b8066280..cb28e98a0659 100644
+--- a/arch/x86/kernel/cpu/common.c
++++ b/arch/x86/kernel/cpu/common.c
+@@ -353,7 +353,7 @@ static __always_inline void setup_umip(struct cpuinfo_x86 *c)
+
+ cr4_set_bits(X86_CR4_UMIP);
+
+- pr_info_once("x86/cpu: Intel User Mode Instruction Prevention (UMIP) activated\n");
++ pr_info_once("x86/cpu: User Mode Instruction Prevention (UMIP) activated\n");
+
+ return;
+
+
diff --git a/patches.arch/x86-umip-print-umip-line-only-once.patch b/patches.arch/x86-umip-print-umip-line-only-once.patch
new file mode 100644
index 0000000000..8e13171de6
--- /dev/null
+++ b/patches.arch/x86-umip-print-umip-line-only-once.patch
@@ -0,0 +1,34 @@
+From: Borislav Petkov <bp@suse.de>
+Date: Tue, 27 Nov 2018 21:54:18 +0100
+Subject: x86/umip: Print UMIP line only once
+Git-commit: 0abbbc63d0251a25d3df6c8a56ab3d3c20af082c
+Patch-mainline: v5.0-rc1
+References: bsc#1138336
+
+... instead of issuing it per CPU and flooding dmesg unnecessarily.
+Streamline the formulation, while at it.
+
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lkml.kernel.org/r/20181127205936.30331-1-bp@alien8.de
+---
+ arch/x86/kernel/cpu/common.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
+index ffb181f959d2..2c56b8066280 100644
+--- a/arch/x86/kernel/cpu/common.c
++++ b/arch/x86/kernel/cpu/common.c
+@@ -353,7 +353,7 @@ static __always_inline void setup_umip(struct cpuinfo_x86 *c)
+
+ cr4_set_bits(X86_CR4_UMIP);
+
+- pr_info("x86/cpu: Activated the Intel User Mode Instruction Prevention (UMIP) CPU feature\n");
++ pr_info_once("x86/cpu: Intel User Mode Instruction Prevention (UMIP) activated\n");
+
+ return;
+
+
diff --git a/patches.drivers/ALSA-firewire-motu-fix-destruction-of-data-for-isoch.patch b/patches.drivers/ALSA-firewire-motu-fix-destruction-of-data-for-isoch.patch
new file mode 100644
index 0000000000..a85740577e
--- /dev/null
+++ b/patches.drivers/ALSA-firewire-motu-fix-destruction-of-data-for-isoch.patch
@@ -0,0 +1,36 @@
+From 0e3fb6995bfabb23c172e8b883bf5ac57102678e Mon Sep 17 00:00:00 2001
+From: Takashi Sakamoto <o-takashi@sakamocchi.jp>
+Date: Sat, 1 Jun 2019 12:08:01 +0900
+Subject: [PATCH] ALSA: firewire-motu: fix destruction of data for isochronous resources
+Git-commit: 0e3fb6995bfabb23c172e8b883bf5ac57102678e
+Patch-mainline: v5.2-rc5
+References: bsc#1051510
+
+The data for isochronous resources is not destroyed in expected place.
+This commit fixes the bug.
+
+Cc: <stable@vger.kernel.org> # v4.12+
+Fixes: 9b2bb4f2f4a2 ("ALSA: firewire-motu: add stream management functionality")
+Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ sound/firewire/motu/motu-stream.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c
+index 73e7a5e527fc..483a8771d502 100644
+--- a/sound/firewire/motu/motu-stream.c
++++ b/sound/firewire/motu/motu-stream.c
+@@ -345,7 +345,7 @@ static void destroy_stream(struct snd_motu *motu,
+ }
+
+ amdtp_stream_destroy(stream);
+- fw_iso_resources_free(resources);
++ fw_iso_resources_destroy(resources);
+ }
+
+ int snd_motu_stream_init_duplex(struct snd_motu *motu)
+--
+2.16.4
+
diff --git a/patches.drivers/ALSA-hda-realtek-Update-headset-mode-for-ALC256.patch b/patches.drivers/ALSA-hda-realtek-Update-headset-mode-for-ALC256.patch
new file mode 100644
index 0000000000..1bbfef3fe4
--- /dev/null
+++ b/patches.drivers/ALSA-hda-realtek-Update-headset-mode-for-ALC256.patch
@@ -0,0 +1,193 @@
+From 717f43d81afc1250300479075952a0e36d74ded3 Mon Sep 17 00:00:00 2001
+From: Kailang Yang <kailang@realtek.com>
+Date: Fri, 31 May 2019 17:16:53 +0800
+Subject: [PATCH] ALSA: hda/realtek - Update headset mode for ALC256
+Git-commit: 717f43d81afc1250300479075952a0e36d74ded3
+Patch-mainline: v5.2-rc5
+References: bsc#1051510
+
+ALC255 and ALC256 were some difference for hidden register.
+This update was suitable for ALC256.
+
+Fixes: e69e7e03ed22 ("ALSA: hda/realtek - ALC256 speaker noise issue")
+Signed-off-by: Kailang Yang <kailang@realtek.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ sound/pci/hda/patch_realtek.c | 75 ++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 60 insertions(+), 15 deletions(-)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 18cb48054e54..1afb268f3da0 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -4133,18 +4133,19 @@ static struct coef_fw alc225_pre_hsmode[] = {
+ static void alc_headset_mode_unplugged(struct hda_codec *codec)
+ {
+ static struct coef_fw coef0255[] = {
++ WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */
+ WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
+ UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+ WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
+ WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */
+ {}
+ };
+- static struct coef_fw coef0255_1[] = {
+- WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */
+- {}
+- };
+ static struct coef_fw coef0256[] = {
+ WRITE_COEF(0x1b, 0x0c4b), /* LDO and MISC control */
++ WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
++ WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
++ WRITE_COEFEX(0x57, 0x03, 0x09a3), /* Direct Drive HP Amp control */
++ UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+ {}
+ };
+ static struct coef_fw coef0233[] = {
+@@ -4207,13 +4208,11 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
+
+ switch (codec->core.vendor_id) {
+ case 0x10ec0255:
+- alc_process_coef_fw(codec, coef0255_1);
+ alc_process_coef_fw(codec, coef0255);
+ break;
+ case 0x10ec0236:
+ case 0x10ec0256:
+ alc_process_coef_fw(codec, coef0256);
+- alc_process_coef_fw(codec, coef0255);
+ break;
+ case 0x10ec0234:
+ case 0x10ec0274:
+@@ -4266,6 +4265,12 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
+ WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
+ {}
+ };
++ static struct coef_fw coef0256[] = {
++ UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), /* Direct Drive HP Amp control(Set to verb control)*/
++ WRITE_COEFEX(0x57, 0x03, 0x09a3),
++ WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
++ {}
++ };
+ static struct coef_fw coef0233[] = {
+ UPDATE_COEF(0x35, 0, 1<<14),
+ WRITE_COEF(0x06, 0x2100),
+@@ -4313,14 +4318,19 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
+ };
+
+ switch (codec->core.vendor_id) {
+- case 0x10ec0236:
+ case 0x10ec0255:
+- case 0x10ec0256:
+ alc_write_coef_idx(codec, 0x45, 0xc489);
+ snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+ alc_process_coef_fw(codec, coef0255);
+ snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+ break;
++ case 0x10ec0236:
++ case 0x10ec0256:
++ alc_write_coef_idx(codec, 0x45, 0xc489);
++ snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
++ alc_process_coef_fw(codec, coef0256);
++ snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
++ break;
+ case 0x10ec0234:
+ case 0x10ec0274:
+ case 0x10ec0294:
+@@ -4402,6 +4412,14 @@ static void alc_headset_mode_default(struct hda_codec *codec)
+ WRITE_COEF(0x49, 0x0049),
+ {}
+ };
++ static struct coef_fw coef0256[] = {
++ WRITE_COEF(0x45, 0xc489),
++ WRITE_COEFEX(0x57, 0x03, 0x0da3),
++ WRITE_COEF(0x49, 0x0049),
++ UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
++ WRITE_COEF(0x06, 0x6100),
++ {}
++ };
+ static struct coef_fw coef0233[] = {
+ WRITE_COEF(0x06, 0x2100),
+ WRITE_COEF(0x32, 0x4ea3),
+@@ -4452,11 +4470,16 @@ static void alc_headset_mode_default(struct hda_codec *codec)
+ alc_process_coef_fw(codec, alc225_pre_hsmode);
+ alc_process_coef_fw(codec, coef0225);
+ break;
+- case 0x10ec0236:
+ case 0x10ec0255:
+- case 0x10ec0256:
+ alc_process_coef_fw(codec, coef0255);
+ break;
++ case 0x10ec0236:
++ case 0x10ec0256:
++ alc_write_coef_idx(codec, 0x1b, 0x0e4b);
++ alc_write_coef_idx(codec, 0x45, 0xc089);
++ msleep(50);
++ alc_process_coef_fw(codec, coef0256);
++ break;
+ case 0x10ec0234:
+ case 0x10ec0274:
+ case 0x10ec0294:
+@@ -4500,8 +4523,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
+ };
+ static struct coef_fw coef0256[] = {
+ WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
+- WRITE_COEF(0x1b, 0x0c6b),
+- WRITE_COEFEX(0x57, 0x03, 0x8ea6),
++ WRITE_COEF(0x1b, 0x0e6b),
+ {}
+ };
+ static struct coef_fw coef0233[] = {
+@@ -4619,8 +4641,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
+ };
+ static struct coef_fw coef0256[] = {
+ WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
+- WRITE_COEF(0x1b, 0x0c6b),
+- WRITE_COEFEX(0x57, 0x03, 0x8ea6),
++ WRITE_COEF(0x1b, 0x0e6b),
+ {}
+ };
+ static struct coef_fw coef0233[] = {
+@@ -4752,13 +4773,37 @@ static void alc_determine_headset_type(struct hda_codec *codec)
+ };
+
+ switch (codec->core.vendor_id) {
+- case 0x10ec0236:
+ case 0x10ec0255:
++ alc_process_coef_fw(codec, coef0255);
++ msleep(300);
++ val = alc_read_coef_idx(codec, 0x46);
++ is_ctia = (val & 0x0070) == 0x0070;
++ break;
++ case 0x10ec0236:
+ case 0x10ec0256:
++ alc_write_coef_idx(codec, 0x1b, 0x0e4b);
++ alc_write_coef_idx(codec, 0x06, 0x6104);
++ alc_write_coefex_idx(codec, 0x57, 0x3, 0x09a3);
++
++ snd_hda_codec_write(codec, 0x21, 0,
++ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
++ msleep(80);
++ snd_hda_codec_write(codec, 0x21, 0,
++ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
++
+ alc_process_coef_fw(codec, coef0255);
+ msleep(300);
+ val = alc_read_coef_idx(codec, 0x46);
+ is_ctia = (val & 0x0070) == 0x0070;
++
++ alc_write_coefex_idx(codec, 0x57, 0x3, 0x0da3);
++ alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
++
++ snd_hda_codec_write(codec, 0x21, 0,
++ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
++ msleep(80);
++ snd_hda_codec_write(codec, 0x21, 0,
++ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+ break;
+ case 0x10ec0234:
+ case 0x10ec0274:
+--
+2.16.4
+
diff --git a/patches.drivers/ALSA-oxfw-allow-PCM-capture-for-Stanton-SCS.1m.patch b/patches.drivers/ALSA-oxfw-allow-PCM-capture-for-Stanton-SCS.1m.patch
new file mode 100644
index 0000000000..3407e24b9a
--- /dev/null
+++ b/patches.drivers/ALSA-oxfw-allow-PCM-capture-for-Stanton-SCS.1m.patch
@@ -0,0 +1,41 @@
+From d8fa87c368f5b4096c4746894fdcc195da285df1 Mon Sep 17 00:00:00 2001
+From: Takashi Sakamoto <o-takashi@sakamocchi.jp>
+Date: Sun, 9 Jun 2019 19:29:12 +0900
+Subject: [PATCH] ALSA: oxfw: allow PCM capture for Stanton SCS.1m
+Git-commit: d8fa87c368f5b4096c4746894fdcc195da285df1
+Patch-mainline: v5.2-rc5
+References: bsc#1051510
+
+Stanton SCS.1m can transfer isochronous packet with Multi Bit Linear
+Audio data channels, therefore it allows software to capture PCM
+substream. However, ALSA oxfw driver doesn't.
+
+This commit changes the driver to add one PCM substream for capture
+direction.
+
+Fixes: de5126cc3c0b ("ALSA: oxfw: add stream format quirk for SCS.1 models")
+Cc: <stable@vger.kernel.org> # v4.5+
+Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ sound/firewire/oxfw/oxfw.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
+index 3d27f3378d5d..b4bef574929d 100644
+--- a/sound/firewire/oxfw/oxfw.c
++++ b/sound/firewire/oxfw/oxfw.c
+@@ -148,9 +148,6 @@ static int detect_quirks(struct snd_oxfw *oxfw)
+ oxfw->midi_input_ports = 0;
+ oxfw->midi_output_ports = 0;
+
+- /* Output stream exists but no data channels are useful. */
+- oxfw->has_output = false;
+-
+ return snd_oxfw_scs1x_add(oxfw);
+ }
+
+--
+2.16.4
+
diff --git a/patches.drivers/ASoC-cs42xx8-Add-regcache-mask-dirty.patch b/patches.drivers/ASoC-cs42xx8-Add-regcache-mask-dirty.patch
new file mode 100644
index 0000000000..66fe6a1f6d
--- /dev/null
+++ b/patches.drivers/ASoC-cs42xx8-Add-regcache-mask-dirty.patch
@@ -0,0 +1,39 @@
+From ad6eecbfc01c987e0253371f274c3872042e4350 Mon Sep 17 00:00:00 2001
+From: "S.j. Wang" <shengjiu.wang@nxp.com>
+Date: Thu, 16 May 2019 06:04:29 +0000
+Subject: [PATCH] ASoC: cs42xx8: Add regcache mask dirty
+Git-commit: ad6eecbfc01c987e0253371f274c3872042e4350
+Patch-mainline: v5.2-rc5
+References: bsc#1051510
+
+Add regcache_mark_dirty before regcache_sync for power
+of codec may be lost at suspend, then all the register
+need to be reconfigured.
+
+Fixes: 0c516b4ff85c ("ASoC: cs42xx8: Add codec driver
+support for CS42448/CS42888")
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ sound/soc/codecs/cs42xx8.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
+index ebb9e0cf8364..28a4ac36c4f8 100644
+--- a/sound/soc/codecs/cs42xx8.c
++++ b/sound/soc/codecs/cs42xx8.c
+@@ -558,6 +558,7 @@ static int cs42xx8_runtime_resume(struct device *dev)
+ msleep(5);
+
+ regcache_cache_only(cs42xx8->regmap, false);
++ regcache_mark_dirty(cs42xx8->regmap);
+
+ ret = regcache_sync(cs42xx8->regmap);
+ if (ret) {
+--
+2.16.4
+
diff --git a/patches.drivers/ASoC-fsl_asrc-Fix-the-issue-about-unsupported-rate.patch b/patches.drivers/ASoC-fsl_asrc-Fix-the-issue-about-unsupported-rate.patch
new file mode 100644
index 0000000000..31c316be52
--- /dev/null
+++ b/patches.drivers/ASoC-fsl_asrc-Fix-the-issue-about-unsupported-rate.patch
@@ -0,0 +1,45 @@
+From b06c58c2a1eed571ea2a6640fdb85b7b00196b1e Mon Sep 17 00:00:00 2001
+From: "S.j. Wang" <shengjiu.wang@nxp.com>
+Date: Wed, 15 May 2019 06:42:18 +0000
+Subject: [PATCH] ASoC: fsl_asrc: Fix the issue about unsupported rate
+Git-commit: b06c58c2a1eed571ea2a6640fdb85b7b00196b1e
+Patch-mainline: v5.2-rc5
+References: bsc#1051510
+
+When the output sample rate is [8kHz, 30kHz], the limitation
+of the supported ratio range is [1/24, 8]. In the driver
+we use (8kHz, 30kHz) instead of [8kHz, 30kHz].
+So this patch is to fix this issue and the potential rounding
+issue with divider.
+
+Fixes: fff6e03c7b65 ("ASoC: fsl_asrc: add support for 8-30kHz
+output sample rate")
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+Acked-by: Nicolin Chen <nicoleotsuka@gmail.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ sound/soc/fsl/fsl_asrc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
+index 0b937924d2e4..ea035c12a325 100644
+--- a/sound/soc/fsl/fsl_asrc.c
++++ b/sound/soc/fsl/fsl_asrc.c
+@@ -282,8 +282,8 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair)
+ return -EINVAL;
+ }
+
+- if ((outrate > 8000 && outrate < 30000) &&
+- (outrate/inrate > 24 || inrate/outrate > 8)) {
++ if ((outrate >= 8000 && outrate <= 30000) &&
++ (outrate > 24 * inrate || inrate > 8 * outrate)) {
+ pair_err("exceed supported ratio range [1/24, 8] for \
+ inrate/outrate: %d/%d\n", inrate, outrate);
+ return -EINVAL;
+--
+2.16.4
+
diff --git a/patches.drivers/HID-Wacom-switch-Dell-canvas-into-highres-mode.patch b/patches.drivers/HID-Wacom-switch-Dell-canvas-into-highres-mode.patch
new file mode 100644
index 0000000000..400c83cde0
--- /dev/null
+++ b/patches.drivers/HID-Wacom-switch-Dell-canvas-into-highres-mode.patch
@@ -0,0 +1,45 @@
+From 5b01b3b8b122fde7fbe116803f7863667b4c5beb Mon Sep 17 00:00:00 2001
+From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Date: Fri, 3 Nov 2017 18:29:47 +0100
+Subject: [PATCH] HID: Wacom: switch Dell canvas into highres mode
+Git-commit: 5b01b3b8b122fde7fbe116803f7863667b4c5beb
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+The Dell Canvas exports 2 collections for the Pen part. The only
+difference between the 2 is that the default one has half the resolution
+of the second one.
+
+The Windows driver switches the tablet into the second mode, so we should
+behave the same.
+
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_sys.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
+index 735bfbbcaa82..ab3178bef0b6 100644
+--- a/drivers/hid/wacom_sys.c
++++ b/drivers/hid/wacom_sys.c
+@@ -196,6 +196,13 @@ static void wacom_feature_mapping(struct hid_device *hdev,
+ kfree(data);
+ break;
+ }
++
++ if (hdev->vendor == USB_VENDOR_ID_WACOM &&
++ hdev->product == 0x4200 /* Dell Canvas 27 */ &&
++ field->application == HID_UP_MSVENDOR) {
++ wacom->wacom_wac.mode_report = field->report->id;
++ wacom->wacom_wac.mode_value = 2;
++ }
+ }
+
+ /*
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Add-ability-to-provide-explicit-battery-st.patch b/patches.drivers/HID-wacom-Add-ability-to-provide-explicit-battery-st.patch
new file mode 100644
index 0000000000..2dc4ce670e
--- /dev/null
+++ b/patches.drivers/HID-wacom-Add-ability-to-provide-explicit-battery-st.patch
@@ -0,0 +1,253 @@
+From 16e4598905a9d7793350ffad2f627b3dfdb7b595 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Fri, 28 Apr 2017 09:25:33 -0700
+Subject: [PATCH] HID: wacom: Add ability to provide explicit battery status info
+Git-commit: 16e4598905a9d7793350ffad2f627b3dfdb7b595
+Patch-mainline: v4.13-rc1
+References: bsc#1051510
+
+At the moment, our driver relies on 'wacom_battery_get_property()' to
+determine the most likely battery state (e.g charging, discharging, or
+full) based on the information available. It is not always possible
+for the function to properly determine this, however. For instance,
+whenever an AES pen leaves proximity the battery state becomes
+indeterminite. This commit adds the ability to provide it with explict
+state information if desired. Whenever explicit state is not required
+(the majority of circumstances), WACOM_POWER_SUPPLY_STATUS_AUTO can
+be used in its place.
+
+Three uses of explicit battery status are added: two wireless disconnect
+paths and the AES case mentioned above.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom.h | 1 +
+ drivers/hid/wacom_sys.c | 4 +++-
+ drivers/hid/wacom_wac.c | 62 ++++++++++++++++++++++++++++++-------------------
+ drivers/hid/wacom_wac.h | 3 +++
+ 4 files changed, 45 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h
+index c7b9ab1907d8..3c37c3cbf6f1 100644
+--- a/drivers/hid/wacom.h
++++ b/drivers/hid/wacom.h
+@@ -138,6 +138,7 @@ struct wacom_battery {
+ struct power_supply_desc bat_desc;
+ struct power_supply *battery;
+ char bat_name[WACOM_NAME_MAX];
++ int bat_status;
+ int battery_capacity;
+ int bat_charging;
+ int bat_connected;
+diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
+index 0022c0dac88a..838c1ebfffa9 100644
+--- a/drivers/hid/wacom_sys.c
++++ b/drivers/hid/wacom_sys.c
+@@ -1547,7 +1547,9 @@ static int wacom_battery_get_property(struct power_supply *psy,
+ val->intval = battery->battery_capacity;
+ break;
+ case POWER_SUPPLY_PROP_STATUS:
+- if (battery->bat_charging)
++ if (battery->bat_status != WACOM_POWER_SUPPLY_STATUS_AUTO)
++ val->intval = battery->bat_status;
++ else if (battery->bat_charging)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else if (battery->battery_capacity == 100 &&
+ battery->ps_connected)
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 3e034506778f..08a865f733fa 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -57,15 +57,18 @@ static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
+ static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
+
+ static void __wacom_notify_battery(struct wacom_battery *battery,
+- int bat_capacity, bool bat_charging,
+- bool bat_connected, bool ps_connected)
++ int bat_status, int bat_capacity,
++ bool bat_charging, bool bat_connected,
++ bool ps_connected)
+ {
+- bool changed = battery->battery_capacity != bat_capacity ||
++ bool changed = battery->bat_status != bat_status ||
++ battery->battery_capacity != bat_capacity ||
+ battery->bat_charging != bat_charging ||
+ battery->bat_connected != bat_connected ||
+ battery->ps_connected != ps_connected;
+
+ if (changed) {
++ battery->bat_status = bat_status;
+ battery->battery_capacity = bat_capacity;
+ battery->bat_charging = bat_charging;
+ battery->bat_connected = bat_connected;
+@@ -77,13 +80,13 @@ static void __wacom_notify_battery(struct wacom_battery *battery,
+ }
+
+ static void wacom_notify_battery(struct wacom_wac *wacom_wac,
+- int bat_capacity, bool bat_charging, bool bat_connected,
+- bool ps_connected)
++ int bat_status, int bat_capacity, bool bat_charging,
++ bool bat_connected, bool ps_connected)
+ {
+ struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+
+- __wacom_notify_battery(&wacom->battery, bat_capacity, bat_charging,
+- bat_connected, ps_connected);
++ __wacom_notify_battery(&wacom->battery, bat_status, bat_capacity,
++ bat_charging, bat_connected, ps_connected);
+ }
+
+ static int wacom_penpartner_irq(struct wacom_wac *wacom)
+@@ -448,8 +451,9 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
+ rw = (data[7] >> 2 & 0x07);
+ battery_capacity = batcap_gr[rw];
+ ps_connected = rw == 7;
+- wacom_notify_battery(wacom, battery_capacity, ps_connected,
+- 1, ps_connected);
++ wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
++ battery_capacity, ps_connected, 1,
++ ps_connected);
+ }
+ exit:
+ return retval;
+@@ -1071,7 +1075,8 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
+ wacom->led.groups[i].select = touch_ring_mode;
+ }
+
+- __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
++ __wacom_notify_battery(&remote->remotes[index].battery,
++ WACOM_POWER_SUPPLY_STATUS_AUTO, bat_percent,
+ bat_charging, 1, bat_charging);
+
+ out:
+@@ -1157,7 +1162,8 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
+ bat_charging = (power_raw & 0x08) ? 1 : 0;
+ ps_connected = (power_raw & 0x10) ? 1 : 0;
+ battery_capacity = batcap_i4[power_raw & 0x07];
+- wacom_notify_battery(wacom, battery_capacity, bat_charging,
++ wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
++ battery_capacity, bat_charging,
+ battery_capacity || bat_charging,
+ ps_connected);
+ break;
+@@ -1334,7 +1340,8 @@ static void wacom_intuos_pro2_bt_battery(struct wacom_wac *wacom)
+ bool chg = data[284] & 0x80;
+ int battery_status = data[284] & 0x7F;
+
+- wacom_notify_battery(wacom, battery_status, chg, 1, chg);
++ wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
++ battery_status, chg, 1, chg);
+ }
+
+ static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len)
+@@ -1814,6 +1821,7 @@ static void wacom_wac_pad_battery_event(struct hid_device *hdev, struct hid_fiel
+ value = value * 100 / (field->logical_maximum - field->logical_minimum);
+ wacom_wac->hid_data.battery_capacity = value;
+ wacom_wac->hid_data.bat_connected = 1;
++ wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
+ break;
+
+ case WACOM_HID_WD_BATTERY_CHARGING:
+@@ -1905,13 +1913,14 @@ static void wacom_wac_pad_battery_report(struct hid_device *hdev,
+ struct wacom_features *features = &wacom_wac->features;
+
+ if (features->quirks & WACOM_QUIRK_BATTERY) {
++ int status = wacom_wac->hid_data.bat_status;
+ int capacity = wacom_wac->hid_data.battery_capacity;
+ bool charging = wacom_wac->hid_data.bat_charging;
+ bool connected = wacom_wac->hid_data.bat_connected;
+ bool powered = wacom_wac->hid_data.ps_connected;
+
+- wacom_notify_battery(wacom_wac, capacity, charging,
+- connected, powered);
++ wacom_notify_battery(wacom_wac, status, capacity,
++ charging, connected, powered);
+ }
+ }
+
+@@ -2036,11 +2045,15 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
+ wacom_wac->hid_data.sense_state = value;
+ return;
+ case HID_DG_BATTERYSTRENGTH:
+- if (value == 0) /* "not available" */
+- break;
+- value = value * 100 / (field->logical_maximum - field->logical_minimum);
+- wacom_wac->hid_data.battery_capacity = value;
+- wacom_wac->hid_data.bat_connected = 1;
++ if (value == 0) {
++ wacom_wac->hid_data.bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
++ }
++ else {
++ value = value * 100 / (field->logical_maximum - field->logical_minimum);
++ wacom_wac->hid_data.battery_capacity = value;
++ wacom_wac->hid_data.bat_connected = 1;
++ wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
++ }
+ break;
+ case HID_DG_INVERT:
+ wacom_wac->hid_data.invert_state = value;
+@@ -2818,13 +2831,14 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
+ wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
+ }
+
+- wacom_notify_battery(wacom, battery, charging, 1, 0);
++ wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
++ battery, charging, 1, 0);
+
+ } else if (wacom->pid != 0) {
+ /* disconnected while previously connected */
+ wacom->pid = 0;
+ wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
+- wacom_notify_battery(wacom, 0, 0, 0, 0);
++ wacom_notify_battery(wacom, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0);
+ }
+
+ return 0;
+@@ -2852,8 +2866,8 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
+ int battery = (data[8] & 0x3f) * 100 / 31;
+ bool charging = !!(data[8] & 0x80);
+
+- wacom_notify_battery(wacom_wac, battery, charging,
+- battery || charging, 1);
++ wacom_notify_battery(wacom_wac, WACOM_POWER_SUPPLY_STATUS_AUTO,
++ battery, charging, battery || charging, 1);
+
+ if (!wacom->battery.battery &&
+ !(features->quirks & WACOM_QUIRK_BATTERY)) {
+@@ -2865,7 +2879,7 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
+ wacom->battery.battery) {
+ features->quirks &= ~WACOM_QUIRK_BATTERY;
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
+- wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
++ wacom_notify_battery(wacom_wac, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0);
+ }
+ return 0;
+ }
+diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
+index 570d29582b82..1824b530bcb5 100644
+--- a/drivers/hid/wacom_wac.h
++++ b/drivers/hid/wacom_wac.h
+@@ -96,6 +96,8 @@
+ #define WACOM_DEVICETYPE_WL_MONITOR 0x0008
+ #define WACOM_DEVICETYPE_DIRECT 0x0010
+
++#define WACOM_POWER_SUPPLY_STATUS_AUTO -1
++
+ #define WACOM_HID_UP_WACOMDIGITIZER 0xff0d0000
+ #define WACOM_HID_SP_PAD 0x00040000
+ #define WACOM_HID_SP_BUTTON 0x00090000
+@@ -297,6 +299,7 @@ struct hid_data {
+ int last_slot_field;
+ int num_expected;
+ int num_received;
++ int bat_status;
+ int battery_capacity;
+ int bat_charging;
+ int bat_connected;
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Add-support-for-3rd-generation-Intuos-BT.patch b/patches.drivers/HID-wacom-Add-support-for-3rd-generation-Intuos-BT.patch
new file mode 100644
index 0000000000..6c7938a42a
--- /dev/null
+++ b/patches.drivers/HID-wacom-Add-support-for-3rd-generation-Intuos-BT.patch
@@ -0,0 +1,228 @@
+From 87046b6c995c50c11c8bd4a71877df83f99b3516 Mon Sep 17 00:00:00 2001
+From: Aaron Armstrong Skomra <skomra@gmail.com>
+Date: Tue, 6 Mar 2018 10:48:33 -0800
+Subject: [PATCH] HID: wacom: Add support for 3rd generation Intuos BT
+Git-commit: 87046b6c995c50c11c8bd4a71877df83f99b3516
+Patch-mainline: v4.17-rc1
+References: bsc#1051510
+
+Use the code path that predates generic device support.
+
+Signed-off-by: Aaron Armstrong Skomra <skomra@gmail.com>
+Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
+Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 113 +++++++++++++++++++++++++++++++++++++++---------
+ drivers/hid/wacom_wac.h | 1
+ 2 files changed, 94 insertions(+), 20 deletions(-)
+
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1202,15 +1202,24 @@ static int wacom_wac_finger_count_touche
+
+ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
+ {
+- const int pen_frame_len = 14;
+- const int pen_frames = 7;
++ int pen_frame_len, pen_frames;
+
+ struct input_dev *pen_input = wacom->pen_input;
+ unsigned char *data = wacom->data;
+ int i;
+
+- wacom->serial[0] = get_unaligned_le64(&data[99]);
+- wacom->id[0] = get_unaligned_le16(&data[107]);
++ if (wacom->features.type == INTUOSP2_BT) {
++ wacom->serial[0] = get_unaligned_le64(&data[99]);
++ wacom->id[0] = get_unaligned_le16(&data[107]);
++ pen_frame_len = 14;
++ pen_frames = 7;
++ } else {
++ wacom->serial[0] = get_unaligned_le64(&data[33]);
++ wacom->id[0] = get_unaligned_le16(&data[41]);
++ pen_frame_len = 8;
++ pen_frames = 4;
++ }
++
+ if (wacom->serial[0] >> 52 == 1) {
+ /* Add back in missing bits of ID for non-USI pens */
+ wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF;
+@@ -1227,21 +1236,35 @@ static void wacom_intuos_pro2_bt_pen(str
+ continue;
+
+ if (range) {
+- /* Fix rotation alignment: userspace expects zero at left */
+- int16_t rotation = (int16_t)get_unaligned_le16(&frame[9]);
+- rotation += 1800/4;
+- if (rotation > 899)
+- rotation -= 1800;
+-
+ input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
+ input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
+- input_report_abs(pen_input, ABS_TILT_X, (char)frame[7]);
+- input_report_abs(pen_input, ABS_TILT_Y, (char)frame[8]);
+- input_report_abs(pen_input, ABS_Z, rotation);
+- input_report_abs(pen_input, ABS_WHEEL, get_unaligned_le16(&frame[11]));
++
++ if (wacom->features.type == INTUOSP2_BT) {
++ /* Fix rotation alignment: userspace expects zero at left */
++ int16_t rotation =
++ (int16_t)get_unaligned_le16(&frame[9]);
++ rotation += 1800/4;
++
++ if (rotation > 899)
++ rotation -= 1800;
++
++ input_report_abs(pen_input, ABS_TILT_X,
++ (char)frame[7]);
++ input_report_abs(pen_input, ABS_TILT_Y,
++ (char)frame[8]);
++ input_report_abs(pen_input, ABS_Z, rotation);
++ input_report_abs(pen_input, ABS_WHEEL,
++ get_unaligned_le16(&frame[11]));
++ }
+ }
+ input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
+- input_report_abs(pen_input, ABS_DISTANCE, range ? frame[13] : wacom->features.distance_max);
++ if (wacom->features.type == INTUOSP2_BT) {
++ input_report_abs(pen_input, ABS_DISTANCE,
++ range ? frame[13] : wacom->features.distance_max);
++ } else {
++ input_report_abs(pen_input, ABS_DISTANCE,
++ range ? frame[7] : wacom->features.distance_max);
++ }
+
+ input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x01);
+ input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02);
+@@ -1357,20 +1380,52 @@ static void wacom_intuos_pro2_bt_battery
+ battery_status, chg, 1, chg);
+ }
+
++static void wacom_intuos_gen3_bt_pad(struct wacom_wac *wacom)
++{
++ struct input_dev *pad_input = wacom->pad_input;
++ unsigned char *data = wacom->data;
++
++ int buttons = data[44];
++
++ wacom_report_numbered_buttons(pad_input, 4, buttons);
++
++ input_report_key(pad_input, wacom->tool[1], buttons ? 1 : 0);
++ input_report_abs(pad_input, ABS_MISC, buttons ? PAD_DEVICE_ID : 0);
++ input_event(pad_input, EV_MSC, MSC_SERIAL, 0xffffffff);
++
++ input_sync(pad_input);
++}
++
++static void wacom_intuos_gen3_bt_battery(struct wacom_wac *wacom)
++{
++ unsigned char *data = wacom->data;
++
++ bool chg = data[45] & 0x80;
++ int battery_status = data[45] & 0x7F;
++
++ wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
++ battery_status, chg, 1, chg);
++}
++
+ static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len)
+ {
+ unsigned char *data = wacom->data;
+
+- if (data[0] != 0x80) {
++ if (data[0] != 0x80 && data[0] != 0x81) {
+ dev_dbg(wacom->pen_input->dev.parent,
+ "%s: received unknown report #%d\n", __func__, data[0]);
+ return 0;
+ }
+
+ wacom_intuos_pro2_bt_pen(wacom);
+- wacom_intuos_pro2_bt_touch(wacom);
+- wacom_intuos_pro2_bt_pad(wacom);
+- wacom_intuos_pro2_bt_battery(wacom);
++ if (wacom->features.type == INTUOSP2_BT) {
++ wacom_intuos_pro2_bt_touch(wacom);
++ wacom_intuos_pro2_bt_pad(wacom);
++ wacom_intuos_pro2_bt_battery(wacom);
++ } else {
++ wacom_intuos_gen3_bt_pad(wacom);
++ wacom_intuos_gen3_bt_battery(wacom);
++ }
+ return 0;
+ }
+
+@@ -3093,6 +3148,7 @@ void wacom_wac_irq(struct wacom_wac *wac
+ break;
+
+ case INTUOSP2_BT:
++ case INTUOSHT3_BT:
+ sync = wacom_intuos_pro2_bt_irq(wacom_wac, len);
+ break;
+
+@@ -3272,6 +3328,12 @@ void wacom_setup_device_quirks(struct wa
+ features->quirks |= WACOM_QUIRK_BATTERY;
+ }
+
++ if (features->type == INTUOSHT3_BT) {
++ features->device_type |= WACOM_DEVICETYPE_PEN |
++ WACOM_DEVICETYPE_PAD;
++ features->quirks |= WACOM_QUIRK_BATTERY;
++ }
++
+ switch (features->type) {
+ case PL:
+ case DTU:
+@@ -3466,7 +3528,9 @@ int wacom_setup_pen_input_capabilities(s
+ case BAMBOO_PT:
+ case BAMBOO_PEN:
+ case INTUOSHT2:
+- if (features->type == INTUOSHT2) {
++ case INTUOSHT3_BT:
++ if (features->type == INTUOSHT2 ||
++ features->type == INTUOSHT3_BT) {
+ wacom_setup_basic_pro_pen(wacom_wac);
+ } else {
+ __clear_bit(ABS_MISC, input_dev->absbit);
+@@ -3887,6 +3951,7 @@ int wacom_setup_pad_input_capabilities(s
+ input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
+ break;
+
++ case INTUOSHT3_BT:
+ case HID_GENERIC:
+ break;
+
+@@ -4415,6 +4480,12 @@ static const struct wacom_features wacom
+ static const struct wacom_features wacom_features_0x361 =
+ { "Wacom Intuos Pro L", 62200, 43200, 8191, 63,
+ INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 };
++static const struct wacom_features wacom_features_0x377 =
++ { "Wacom Intuos BT S", 15200, 9500, 4095, 63,
++ INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
++static const struct wacom_features wacom_features_0x379 =
++ { "Wacom Intuos BT M", 21600, 13500, 4095, 63,
++ INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
+ static const struct wacom_features wacom_features_0x37A =
+ { "Wacom One by Wacom S", 15200, 9500, 2047, 63,
+ BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+@@ -4589,6 +4660,8 @@ const struct hid_device_id wacom_ids[] =
+ { USB_DEVICE_WACOM(0x343) },
+ { BT_DEVICE_WACOM(0x360) },
+ { BT_DEVICE_WACOM(0x361) },
++ { BT_DEVICE_WACOM(0x377) },
++ { BT_DEVICE_WACOM(0x379) },
+ { USB_DEVICE_WACOM(0x37A) },
+ { USB_DEVICE_WACOM(0x37B) },
+ { USB_DEVICE_WACOM(0x4001) },
+--- a/drivers/hid/wacom_wac.h
++++ b/drivers/hid/wacom_wac.h
+@@ -213,6 +213,7 @@ enum {
+ INTUOSPM,
+ INTUOSPL,
+ INTUOSP2_BT,
++ INTUOSHT3_BT,
+ WACOM_21UX2,
+ WACOM_22HD,
+ DTK,
diff --git a/patches.drivers/HID-wacom-Add-support-for-Pro-Pen-slim.patch b/patches.drivers/HID-wacom-Add-support-for-Pro-Pen-slim.patch
new file mode 100644
index 0000000000..c52d3057d2
--- /dev/null
+++ b/patches.drivers/HID-wacom-Add-support-for-Pro-Pen-slim.patch
@@ -0,0 +1,45 @@
+From 4e6e7d7252745ff589a5b02834c1b228d2c9140f Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Tue, 19 Feb 2019 17:58:56 +0000
+Subject: [PATCH] HID: wacom: Add support for Pro Pen slim
+Git-commit: 4e6e7d7252745ff589a5b02834c1b228d2c9140f
+Patch-mainline: v5.1-rc1
+References: bsc#1051510
+
+Wacom has introduced a new pen compatible with its MobileStudio Pro and
+other tablets. Although adding it to the tool ID tablet is not strictly
+necessary unrecognized pens are reported as BTN_TOOL_PEN already, unless
+the tablet sends the "eraser" bit, when BTN_TOOL_RUBBER is used instead),
+we'll keep it updated anyway.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 5ecda99bf431..747730d32ab6 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -626,6 +626,7 @@ static int wacom_intuos_get_tool_type(int tool_id)
+ case 0x8e2: /* IntuosHT2 pen */
+ case 0x022:
+ case 0x10804: /* Intuos4/5 13HD/24HD Art Pen */
++ case 0x10842: /* MobileStudio Pro Pro Pen slim */
+ case 0x14802: /* Intuos4/5 13HD/24HD Classic Pen */
+ case 0x16802: /* Cintiq 13HD Pro Pen */
+ case 0x18802: /* DTH2242 Pen */
+@@ -667,6 +668,7 @@ static int wacom_intuos_get_tool_type(int tool_id)
+ case 0x1480a: /* Intuos4/5 13HD/24HD Classic Pen Eraser */
+ case 0x1090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
+ case 0x1080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */
++ case 0x1084a: /* MobileStudio Pro Pro Pen slim Eraser */
+ case 0x1680a: /* Cintiq 13HD Pro Pen Eraser */
+ case 0x1880a: /* DTH2242 Eraser */
+ case 0x1080a: /* Intuos4/5 13HD/24HD General Pen Eraser */
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Correct-button-numbering-2nd-gen-Intuos-Pr.patch b/patches.drivers/HID-wacom-Correct-button-numbering-2nd-gen-Intuos-Pr.patch
new file mode 100644
index 0000000000..fbebaa7dc0
--- /dev/null
+++ b/patches.drivers/HID-wacom-Correct-button-numbering-2nd-gen-Intuos-Pr.patch
@@ -0,0 +1,73 @@
+From 6441fc781c344df61402be1fde582c4491fa35fa Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <jason.gerecke@wacom.com>
+Date: Tue, 7 May 2019 11:53:21 -0700
+Subject: [PATCH] HID: wacom: Correct button numbering 2nd-gen Intuos Pro over Bluetooth
+Git-commit: 6441fc781c344df61402be1fde582c4491fa35fa
+Patch-mainline: v5.2 or v5.2-rc5 (next release)
+References: bsc#1051510
+
+The button numbering of the 2nd-gen Intuos Pro is not consistent between
+the USB and Bluetooth interfaces. Over USB, the HID_GENERIC codepath
+enumerates the eight ExpressKeys first (BTN_0 - BTN_7) followed by the
+center modeswitch button (BTN_8). The Bluetooth codepath, however, has
+the center modeswitch button as BTN_0 and the the eight ExpressKeys as
+BTN_1 - BTN_8. To ensure userspace button mappings do not change
+depending on how the tablet is connected, modify the Bluetooth codepath
+to report buttons in the same order as USB.
+
+To ensure the mode switch LED continues to toggle in response to the
+mode switch button, the `wacom_is_led_toggled` function also requires
+a small update.
+
+Link: https://github.com/linuxwacom/input-wacom/pull/79
+Fixes: 4922cd26f03c ("HID: wacom: Support 2nd-gen Intuos Pro's Bluetooth classic interface")
+Cc: <stable@vger.kernel.org> # 4.11+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Aaron Skomra <aaron.skomra@wacom.com>
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index af62a630fee9..e848445236d8 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1383,7 +1383,7 @@ static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom)
+ struct input_dev *pad_input = wacom->pad_input;
+ unsigned char *data = wacom->data;
+
+- int buttons = (data[282] << 1) | ((data[281] >> 6) & 0x01);
++ int buttons = data[282] | ((data[281] & 0x40) << 2);
+ int ring = data[285] & 0x7F;
+ bool ringstatus = data[285] & 0x80;
+ bool prox = buttons || ringstatus;
+@@ -3832,7 +3832,7 @@ static void wacom_24hd_update_leds(struct wacom *wacom, int mask, int group)
+ static bool wacom_is_led_toggled(struct wacom *wacom, int button_count,
+ int mask, int group)
+ {
+- int button_per_group;
++ int group_button;
+
+ /*
+ * 21UX2 has LED group 1 to the left and LED group 0
+@@ -3842,9 +3842,12 @@ static bool wacom_is_led_toggled(struct wacom *wacom, int button_count,
+ if (wacom->wacom_wac.features.type == WACOM_21UX2)
+ group = 1 - group;
+
+- button_per_group = button_count/wacom->led.count;
++ group_button = group * (button_count/wacom->led.count);
+
+- return mask & (1 << (group * button_per_group));
++ if (wacom->wacom_wac.features.type == INTUOSP2_BT)
++ group_button = 8;
++
++ return mask & (1 << group_button);
+ }
+
+ static void wacom_update_led(struct wacom *wacom, int button_count, int mask,
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Don-t-report-anything-prior-to-the-tool-en.patch b/patches.drivers/HID-wacom-Don-t-report-anything-prior-to-the-tool-en.patch
new file mode 100644
index 0000000000..0cd7f595ac
--- /dev/null
+++ b/patches.drivers/HID-wacom-Don-t-report-anything-prior-to-the-tool-en.patch
@@ -0,0 +1,77 @@
+From e92a7be7fe5b2510fa60965eaf25f9e3dc08b8cc Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <jason.gerecke@wacom.com>
+Date: Wed, 24 Apr 2019 15:12:58 -0700
+Subject: [PATCH] HID: wacom: Don't report anything prior to the tool entering range
+Git-commit: e92a7be7fe5b2510fa60965eaf25f9e3dc08b8cc
+Patch-mainline: v5.2 or v5.2-rc5 (next release)
+References: bsc#1051510
+
+If the tool spends some time in prox before entering range, a series of
+events (e.g. ABS_DISTANCE, MSC_SERIAL) can be sent before we or userspace
+have any clue about the pen whose data is being reported. We need to hold
+off on reporting anything until the pen has entered range. Since we still
+want to report events that occur "in prox" after the pen has *left* range
+we use 'wacom-tool[0]' as the indicator that the pen did at one point
+enter range and provide us/userspace with tool type and serial number
+information.
+
+Fixes: a48324de6d4d ("HID: wacom: Bluetooth IRQ for Intuos Pro should handle prox/range")
+Cc: <stable@vger.kernel.org> # 4.11+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Aaron Armstrong Skomra <aaron.skomra@wacom.com>
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 33 ++++++++++++++++++---------------
+ 1 file changed, 18 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 4c1bc239207e..613342bb9d6b 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1290,23 +1290,26 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
+ get_unaligned_le16(&frame[11]));
+ }
+ }
+- input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
+- if (wacom->features.type == INTUOSP2_BT) {
+- input_report_abs(pen_input, ABS_DISTANCE,
+- range ? frame[13] : wacom->features.distance_max);
+- } else {
+- input_report_abs(pen_input, ABS_DISTANCE,
+- range ? frame[7] : wacom->features.distance_max);
+- }
+
+- input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x01);
+- input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02);
+- input_report_key(pen_input, BTN_STYLUS2, frame[0] & 0x04);
++ if (wacom->tool[0]) {
++ input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
++ if (wacom->features.type == INTUOSP2_BT) {
++ input_report_abs(pen_input, ABS_DISTANCE,
++ range ? frame[13] : wacom->features.distance_max);
++ } else {
++ input_report_abs(pen_input, ABS_DISTANCE,
++ range ? frame[7] : wacom->features.distance_max);
++ }
++
++ input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x01);
++ input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02);
++ input_report_key(pen_input, BTN_STYLUS2, frame[0] & 0x04);
+
+- input_report_key(pen_input, wacom->tool[0], prox);
+- input_event(pen_input, EV_MSC, MSC_SERIAL, wacom->serial[0]);
+- input_report_abs(pen_input, ABS_MISC,
+- wacom_intuos_id_mangle(wacom->id[0])); /* report tool id */
++ input_report_key(pen_input, wacom->tool[0], prox);
++ input_event(pen_input, EV_MSC, MSC_SERIAL, wacom->serial[0]);
++ input_report_abs(pen_input, ABS_MISC,
++ wacom_intuos_id_mangle(wacom->id[0])); /* report tool id */
++ }
+
+ wacom->shared->stylus_in_proximity = prox;
+
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Don-t-set-tool-type-until-we-re-in-range.patch b/patches.drivers/HID-wacom-Don-t-set-tool-type-until-we-re-in-range.patch
new file mode 100644
index 0000000000..7b98372204
--- /dev/null
+++ b/patches.drivers/HID-wacom-Don-t-set-tool-type-until-we-re-in-range.patch
@@ -0,0 +1,75 @@
+From 2cc08800a6b9fcda7c7afbcf2da1a6e8808da725 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <jason.gerecke@wacom.com>
+Date: Wed, 24 Apr 2019 15:12:57 -0700
+Subject: [PATCH] HID: wacom: Don't set tool type until we're in range
+Git-commit: 2cc08800a6b9fcda7c7afbcf2da1a6e8808da725
+Patch-mainline: v5.2 or v5.2-rc5 (next release)
+References: bsc#1051510
+
+The serial number and tool type information that is reported by the tablet
+while a pen is merely "in prox" instead of fully "in range" can be stale
+and cause us to report incorrect tool information. Serial number, tool
+type, and other information is only valid once the pen comes fully in range
+so we should be careful to not use this information until that point.
+
+In particular, this issue may cause the driver to incorectly report
+BTN_TOOL_RUBBER after switching from the eraser tool back to the pen.
+
+Fixes: a48324de6d4d ("HID: wacom: Bluetooth IRQ for Intuos Pro should handle prox/range")
+Cc: <stable@vger.kernel.org> # 4.11+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Aaron Armstrong Skomra <aaron.skomra@wacom.com>
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 747730d32ab6..4c1bc239207e 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1236,13 +1236,13 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
+ /* Add back in missing bits of ID for non-USI pens */
+ wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF;
+ }
+- wacom->tool[0] = wacom_intuos_get_tool_type(wacom_intuos_id_mangle(wacom->id[0]));
+
+ for (i = 0; i < pen_frames; i++) {
+ unsigned char *frame = &data[i*pen_frame_len + 1];
+ bool valid = frame[0] & 0x80;
+ bool prox = frame[0] & 0x40;
+ bool range = frame[0] & 0x20;
++ bool invert = frame[0] & 0x10;
+
+ if (!valid)
+ continue;
+@@ -1251,9 +1251,24 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
+ wacom->shared->stylus_in_proximity = false;
+ wacom_exit_report(wacom);
+ input_sync(pen_input);
++
++ wacom->tool[0] = 0;
++ wacom->id[0] = 0;
++ wacom->serial[0] = 0;
+ return;
+ }
++
+ if (range) {
++ if (!wacom->tool[0]) { /* first in range */
++ /* Going into range select tool */
++ if (invert)
++ wacom->tool[0] = BTN_TOOL_RUBBER;
++ else if (wacom->id[0])
++ wacom->tool[0] = wacom_intuos_get_tool_type(wacom->id[0]);
++ else
++ wacom->tool[0] = BTN_TOOL_PEN;
++ }
++
+ input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
+ input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
+
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Mark-expected-switch-fall-through.patch b/patches.drivers/HID-wacom-Mark-expected-switch-fall-through.patch
new file mode 100644
index 0000000000..8b7bf28c65
--- /dev/null
+++ b/patches.drivers/HID-wacom-Mark-expected-switch-fall-through.patch
@@ -0,0 +1,53 @@
+From 1da92d436c93a6ffc049f60206b684db2d25882f Mon Sep 17 00:00:00 2001
+From: "Gustavo A. R. Silva" <gustavo@embeddedor.com>
+Date: Mon, 11 Feb 2019 16:04:22 -0600
+Subject: [PATCH] HID: wacom: Mark expected switch fall-through
+Mime-version: 1.0
+Content-type: text/plain; charset=UTF-8
+Content-transfer-encoding: 8bit
+Git-commit: 1da92d436c93a6ffc049f60206b684db2d25882f
+Patch-mainline: v5.1-rc1
+References: bsc#1051510
+
+In preparation to enabling -Wimplicit-fallthrough, mark switch
+cases where we are expecting to fall through.
+
+This patch fixes the following warning:
+
+Drivers/hid/wacom_wac.c: In function ‘wacom_setup_pen_input_capabilities’:
+drivers/hid/wacom_wac.c:3506:3: warning: this statement may fall through [-Wimplicit-fallthrough=]
+ __clear_bit(ABS_MISC, input_dev->absbit);
+ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+drivers/hid/wacom_wac.c:3508:2: note: here
+ case WACOM_MO:
+ ^~~~
+
+Warning level 3 was used: -Wimplicit-fallthrough=3
+
+This patch is part of the ongoing efforts to enable
+-Wimplicit-fallthrough.
+
+Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
+Acked-by: Ping Cheng <ping.cheng@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 72477e872324..5ecda99bf431 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -3504,6 +3504,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
+ switch (features->type) {
+ case GRAPHIRE_BT:
+ __clear_bit(ABS_MISC, input_dev->absbit);
++ /* fall through */
+
+ case WACOM_MO:
+ case WACOM_G4:
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Move-HID-fix-for-AES-serial-number-into-wa.patch b/patches.drivers/HID-wacom-Move-HID-fix-for-AES-serial-number-into-wa.patch
new file mode 100644
index 0000000000..0d96f77b0a
--- /dev/null
+++ b/patches.drivers/HID-wacom-Move-HID-fix-for-AES-serial-number-into-wa.patch
@@ -0,0 +1,102 @@
+From e9fe0d4921ee07d934d839d8e418f83dded48aa7 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Thu, 24 Jan 2019 11:09:44 -0800
+Subject: [PATCH] HID: wacom: Move HID fix for AES serial number into wacom_hid_usage_quirk
+Git-commit: e9fe0d4921ee07d934d839d8e418f83dded48aa7
+Patch-mainline: v5.1-rc1
+References: bsc#1051510
+
+The 'wacom_hid_usage_quirk' function is the intended home for fixing
+up descriptors that are buggy or that don't quite fit the mold. Commit
+578325120e was supposed to move all of these quirks but it missed the
+code to handle fixup the serial number usages for AES pens. Lets move
+this code out of 'wacom_wac_pen_usage_mapping' where it was previously
+lurking and put it into the same place as the others.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_sys.c | 32 ++++++++++++++++++++++++++++++++
+ drivers/hid/wacom_wac.c | 21 ---------------------
+ 2 files changed, 32 insertions(+), 21 deletions(-)
+
+diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
+index 0bdd85d486fe..a8633b1437b2 100644
+--- a/drivers/hid/wacom_sys.c
++++ b/drivers/hid/wacom_sys.c
+@@ -252,6 +252,38 @@ static void wacom_hid_usage_quirk(struct hid_device *hdev,
+ }
+ }
+
++ /*
++ * Wacom's AES devices use different vendor-defined usages to
++ * report serial number information compared to their branded
++ * hardware. The usages are also sometimes ill-defined and do
++ * not have the correct logical min/max values set. Lets patch
++ * the descriptor to use the branded usage convention and fix
++ * the errors.
++ */
++ if (usage->hid == WACOM_HID_WT_SERIALNUMBER &&
++ field->report_size == 16 &&
++ field->index + 2 < field->report->maxfield) {
++ struct hid_field *a = field->report->field[field->index + 1];
++ struct hid_field *b = field->report->field[field->index + 2];
++
++ if (a->maxusage > 0 &&
++ a->usage[0].hid == HID_DG_TOOLSERIALNUMBER &&
++ a->report_size == 32 &&
++ b->maxusage > 0 &&
++ b->usage[0].hid == 0xFF000000 &&
++ b->report_size == 8) {
++ features->quirks |= WACOM_QUIRK_AESPEN;
++ usage->hid = WACOM_HID_WD_TOOLTYPE;
++ field->logical_minimum = S16_MIN;
++ field->logical_maximum = S16_MAX;
++ a->logical_minimum = S32_MIN;
++ a->logical_maximum = S32_MAX;
++ b->usage[0].hid = WACOM_HID_WD_SERIALHI;
++ b->logical_minimum = 0;
++ b->logical_maximum = U8_MAX;
++ }
++ }
++
+ /* 2nd-generation Intuos Pro Large has incorrect Y maximum */
+ if (hdev->vendor == USB_VENDOR_ID_WACOM &&
+ hdev->product == 0x0358 &&
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 5dd3a8245f0f..72477e872324 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2159,27 +2159,6 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
+ case HID_DG_TOOLSERIALNUMBER:
+ features->quirks |= WACOM_QUIRK_TOOLSERIAL;
+ wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0);
+-
+- /* Adjust AES usages to match modern convention */
+- if (usage->hid == WACOM_HID_WT_SERIALNUMBER && field->report_size == 16) {
+- if (field->index + 2 < field->report->maxfield) {
+- struct hid_field *a = field->report->field[field->index + 1];
+- struct hid_field *b = field->report->field[field->index + 2];
+-
+- if (a->maxusage > 0 && a->usage[0].hid == HID_DG_TOOLSERIALNUMBER && a->report_size == 32 &&
+- b->maxusage > 0 && b->usage[0].hid == 0xFF000000 && b->report_size == 8) {
+- features->quirks |= WACOM_QUIRK_AESPEN;
+- usage->hid = WACOM_HID_WD_TOOLTYPE;
+- field->logical_minimum = S16_MIN;
+- field->logical_maximum = S16_MAX;
+- a->logical_minimum = S32_MIN;
+- a->logical_maximum = S32_MAX;
+- b->usage[0].hid = WACOM_HID_WD_SERIALHI;
+- b->logical_minimum = 0;
+- b->logical_maximum = U8_MAX;
+- }
+- }
+- }
+ break;
+ case WACOM_HID_WD_SENSE:
+ features->quirks |= WACOM_QUIRK_SENSE;
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Move-handling-of-HID-quirks-into-a-dedicat.patch b/patches.drivers/HID-wacom-Move-handling-of-HID-quirks-into-a-dedicat.patch
new file mode 100644
index 0000000000..a84ed1508e
--- /dev/null
+++ b/patches.drivers/HID-wacom-Move-handling-of-HID-quirks-into-a-dedicat.patch
@@ -0,0 +1,147 @@
+From 578325120ec122db98b3d57e833d16c1bdac6ec6 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Mon, 25 Jun 2018 13:24:35 -0700
+Subject: [PATCH] HID: wacom: Move handling of HID quirks into a dedicated function
+Git-commit: 578325120ec122db98b3d57e833d16c1bdac6ec6
+Patch-mainline: v4.19-rc1
+References: bsc#1051510
+
+We want to keep device-specific quirks as contained as possible so that the
+the code remains maintainable. Our 'wacom_setup_device_quirks' function is
+the usual place for this, but some quirks need to be applied to the HID
+descriptor as it is parsed. This commit introduces a new function which is
+called for each usage so that any HID-specific quirks can be applied. The
+function now houses quirks that were being done in 'wacom_feature_mapping'
+and 'wacom_usage_mapping'.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_sys.c | 92 ++++++++++++++++++++++++++++--------------------
+ 1 file changed, 54 insertions(+), 38 deletions(-)
+
+--- a/drivers/hid/wacom_sys.c
++++ b/drivers/hid/wacom_sys.c
+@@ -210,6 +210,57 @@ static int wacom_calc_hid_res(int logica
+ return hidinput_calc_abs_res(&field, ABS_X);
+ }
+
++static void wacom_hid_usage_quirk(struct hid_device *hdev,
++ struct hid_field *field, struct hid_usage *usage)
++{
++ struct wacom *wacom = hid_get_drvdata(hdev);
++ struct wacom_features *features = &wacom->wacom_wac.features;
++ unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
++
++ /*
++ * The Dell Canvas 27 needs to be switched to its vendor-defined
++ * report to provide the best resolution.
++ */
++ if (hdev->vendor == USB_VENDOR_ID_WACOM &&
++ hdev->product == 0x4200 &&
++ field->application == HID_UP_MSVENDOR) {
++ wacom->wacom_wac.mode_report = field->report->id;
++ wacom->wacom_wac.mode_value = 2;
++ }
++
++ /*
++ * ISDv4 devices which predate HID's adoption of the
++ * HID_DG_BARELSWITCH2 usage use 0x000D0000 in its
++ * position instead. We can accurately detect if a
++ * usage with that value should be HID_DG_BARRELSWITCH2
++ * based on the surrounding usages, which have remained
++ * constant across generations.
++ */
++ if (features->type == HID_GENERIC &&
++ usage->hid == 0x000D0000 &&
++ field->application == HID_DG_PEN &&
++ field->physical == HID_DG_STYLUS) {
++ int i = usage->usage_index;
++
++ if (i-4 >= 0 && i+1 < field->maxusage &&
++ field->usage[i-4].hid == HID_DG_TIPSWITCH &&
++ field->usage[i-3].hid == HID_DG_BARRELSWITCH &&
++ field->usage[i-2].hid == HID_DG_ERASER &&
++ field->usage[i-1].hid == HID_DG_INVERT &&
++ field->usage[i+1].hid == HID_DG_INRANGE) {
++ usage->hid = HID_DG_BARRELSWITCH2;
++ }
++ }
++
++ /* 2nd-generation Intuos Pro Large has incorrect Y maximum */
++ if (hdev->vendor == USB_VENDOR_ID_WACOM &&
++ hdev->product == 0x0358 &&
++ WACOM_PEN_FIELD(field) &&
++ equivalent_usage == HID_GD_Y) {
++ field->logical_maximum = 43200;
++ }
++}
++
+ static void wacom_feature_mapping(struct hid_device *hdev,
+ struct hid_field *field, struct hid_usage *usage)
+ {
+@@ -221,6 +272,8 @@ static void wacom_feature_mapping(struct
+ int ret;
+ int n;
+
++ wacom_hid_usage_quirk(hdev, field, usage);
++
+ switch (equivalent_usage) {
+ case HID_DG_CONTACTMAX:
+ /* leave touch_max as is if predefined */
+@@ -300,13 +353,6 @@ static void wacom_feature_mapping(struct
+ kfree(data);
+ break;
+ }
+-
+- if (hdev->vendor == USB_VENDOR_ID_WACOM &&
+- hdev->product == 0x4200 /* Dell Canvas 27 */ &&
+- field->application == HID_UP_MSVENDOR) {
+- wacom->wacom_wac.mode_report = field->report->id;
+- wacom->wacom_wac.mode_value = 2;
+- }
+ }
+
+ /*
+@@ -361,37 +407,7 @@ static void wacom_usage_mapping(struct h
+ else
+ return;
+
+- /*
+- * ISDv4 devices which predate HID's adoption of the
+- * HID_DG_BARELSWITCH2 usage use 0x000D0000 in its
+- * position instead. We can accurately detect if a
+- * usage with that value should be HID_DG_BARRELSWITCH2
+- * based on the surrounding usages, which have remained
+- * constant across generations.
+- */
+- if (features->type == HID_GENERIC &&
+- usage->hid == 0x000D0000 &&
+- field->application == HID_DG_PEN &&
+- field->physical == HID_DG_STYLUS) {
+- int i = usage->usage_index;
+-
+- if (i-4 >= 0 && i+1 < field->maxusage &&
+- field->usage[i-4].hid == HID_DG_TIPSWITCH &&
+- field->usage[i-3].hid == HID_DG_BARRELSWITCH &&
+- field->usage[i-2].hid == HID_DG_ERASER &&
+- field->usage[i-1].hid == HID_DG_INVERT &&
+- field->usage[i+1].hid == HID_DG_INRANGE) {
+- usage->hid = HID_DG_BARRELSWITCH2;
+- }
+- }
+-
+- /* 2nd-generation Intuos Pro Large has incorrect Y maximum */
+- if (hdev->vendor == USB_VENDOR_ID_WACOM &&
+- hdev->product == 0x0358 &&
+- WACOM_PEN_FIELD(field) &&
+- wacom_equivalent_usage(usage->hid) == HID_GD_Y) {
+- field->logical_maximum = 43200;
+- }
++ wacom_hid_usage_quirk(hdev, field, usage);
+
+ switch (usage->hid) {
+ case HID_GD_X:
diff --git a/patches.drivers/HID-wacom-Properly-handle-AES-serial-number-and-tool.patch b/patches.drivers/HID-wacom-Properly-handle-AES-serial-number-and-tool.patch
new file mode 100644
index 0000000000..1e83e3766f
--- /dev/null
+++ b/patches.drivers/HID-wacom-Properly-handle-AES-serial-number-and-tool.patch
@@ -0,0 +1,120 @@
+From 99acedadde157a02b21761fd406ef7adc7615533 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Fri, 10 Nov 2017 11:50:00 -0800
+Subject: [PATCH] HID: wacom: Properly handle AES serial number and tool type
+Git-commit: 99acedadde157a02b21761fd406ef7adc7615533
+Patch-mainline: v4.16-rc1
+References: bsc#1051510
+
+Current AES sensors relay tool type and serial number information with
+a different set of usages than those prescribed by the modern (i.e.
+MobileStudio Pro and newer) EMR tablet standard. To ensure the driver
+properly understands these usages, we modify them to be compatible.
+The identifying information is split across three consecutive fields:
+a 16-bit WACOM_HID_WT_SERIALNUMBER (which is more accurately described
+as WACOM_HID_WD_TOOLTYPE), a 32-bit HID_DG_TOOLSERIALNUMBER, and an
+8-bit 0xFF000000 (which should be WACOM_HID_WD_SERIALHI). While we're
+at it, we also define proper min/max values since may may be undefined
+on some devices.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 42 +++++++++++++++++++++++++++++++++---------
+ drivers/hid/wacom_wac.h | 3 +++
+ 2 files changed, 36 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 16af6886e828..ff679ee3b358 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2086,6 +2086,27 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
+ break;
+ case HID_DG_TOOLSERIALNUMBER:
+ wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0);
++
++ /* Adjust AES usages to match modern convention */
++ if (usage->hid == WACOM_HID_WT_SERIALNUMBER && field->report_size == 16) {
++ if (field->index + 2 < field->report->maxfield) {
++ struct hid_field *a = field->report->field[field->index + 1];
++ struct hid_field *b = field->report->field[field->index + 2];
++
++ if (a->maxusage > 0 && a->usage[0].hid == HID_DG_TOOLSERIALNUMBER && a->report_size == 32 &&
++ b->maxusage > 0 && b->usage[0].hid == 0xFF000000 && b->report_size == 8) {
++ features->quirks |= WACOM_QUIRK_AESPEN;
++ usage->hid = WACOM_HID_WD_TOOLTYPE;
++ field->logical_minimum = S16_MIN;
++ field->logical_maximum = S16_MAX;
++ a->logical_minimum = S32_MIN;
++ a->logical_maximum = S32_MAX;
++ b->usage[0].hid = WACOM_HID_WD_SERIALHI;
++ b->logical_minimum = 0;
++ b->logical_maximum = U8_MAX;
++ }
++ }
++ }
+ break;
+ case WACOM_HID_WD_SENSE:
+ features->quirks |= WACOM_QUIRK_SENSE;
+@@ -2093,15 +2114,18 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
+ break;
+ case WACOM_HID_WD_SERIALHI:
+ wacom_map_usage(input, usage, field, EV_ABS, ABS_MISC, 0);
+- set_bit(EV_KEY, input->evbit);
+- input_set_capability(input, EV_KEY, BTN_TOOL_PEN);
+- input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER);
+- input_set_capability(input, EV_KEY, BTN_TOOL_BRUSH);
+- input_set_capability(input, EV_KEY, BTN_TOOL_PENCIL);
+- input_set_capability(input, EV_KEY, BTN_TOOL_AIRBRUSH);
+- if (!(features->device_type & WACOM_DEVICETYPE_DIRECT)) {
+- input_set_capability(input, EV_KEY, BTN_TOOL_MOUSE);
+- input_set_capability(input, EV_KEY, BTN_TOOL_LENS);
++
++ if (!(features->quirks & WACOM_QUIRK_AESPEN)) {
++ set_bit(EV_KEY, input->evbit);
++ input_set_capability(input, EV_KEY, BTN_TOOL_PEN);
++ input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER);
++ input_set_capability(input, EV_KEY, BTN_TOOL_BRUSH);
++ input_set_capability(input, EV_KEY, BTN_TOOL_PENCIL);
++ input_set_capability(input, EV_KEY, BTN_TOOL_AIRBRUSH);
++ if (!(features->device_type & WACOM_DEVICETYPE_DIRECT)) {
++ input_set_capability(input, EV_KEY, BTN_TOOL_MOUSE);
++ input_set_capability(input, EV_KEY, BTN_TOOL_LENS);
++ }
+ }
+ break;
+ case WACOM_HID_WD_FINGERWHEEL:
+diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
+index 64d8f014602e..6fe6d60f9ab5 100644
+--- a/drivers/hid/wacom_wac.h
++++ b/drivers/hid/wacom_wac.h
+@@ -86,6 +86,7 @@
+ /* device quirks */
+ #define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001
+ #define WACOM_QUIRK_SENSE 0x0002
++#define WACOM_QUIRK_AESPEN 0x0004
+ #define WACOM_QUIRK_BATTERY 0x0008
+
+ /* device types */
+@@ -107,6 +108,7 @@
+ #define WACOM_HID_WD_PEN (WACOM_HID_UP_WACOMDIGITIZER | 0x02)
+ #define WACOM_HID_WD_SENSE (WACOM_HID_UP_WACOMDIGITIZER | 0x36)
+ #define WACOM_HID_WD_DIGITIZERFNKEYS (WACOM_HID_UP_WACOMDIGITIZER | 0x39)
++#define WACOM_HID_WD_SERIALNUMBER (WACOM_HID_UP_WACOMDIGITIZER | 0x5b)
+ #define WACOM_HID_WD_SERIALHI (WACOM_HID_UP_WACOMDIGITIZER | 0x5c)
+ #define WACOM_HID_WD_TOOLTYPE (WACOM_HID_UP_WACOMDIGITIZER | 0x77)
+ #define WACOM_HID_WD_DISTANCE (WACOM_HID_UP_WACOMDIGITIZER | 0x0132)
+@@ -150,6 +152,7 @@
+ #define WACOM_HID_WT_TOUCHSCREEN (WACOM_HID_UP_WACOMTOUCH | 0x04)
+ #define WACOM_HID_WT_TOUCHPAD (WACOM_HID_UP_WACOMTOUCH | 0x05)
+ #define WACOM_HID_WT_CONTACTMAX (WACOM_HID_UP_WACOMTOUCH | 0x55)
++#define WACOM_HID_WT_SERIALNUMBER (WACOM_HID_UP_WACOMTOUCH | 0x5b)
+ #define WACOM_HID_WT_X (WACOM_HID_UP_WACOMTOUCH | 0x130)
+ #define WACOM_HID_WT_Y (WACOM_HID_UP_WACOMTOUCH | 0x131)
+
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Queue-events-with-missing-type-serial-data.patch b/patches.drivers/HID-wacom-Queue-events-with-missing-type-serial-data.patch
new file mode 100644
index 0000000000..64eeb314fe
--- /dev/null
+++ b/patches.drivers/HID-wacom-Queue-events-with-missing-type-serial-data.patch
@@ -0,0 +1,223 @@
+From 83417206427bdf0fef9fa69957807194f25923c3 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Fri, 10 Nov 2017 11:50:01 -0800
+Subject: [PATCH] HID: wacom: Queue events with missing type/serial data for later processing
+Git-commit: 83417206427bdf0fef9fa69957807194f25923c3
+Patch-mainline: v4.16-rc1
+References: bsc#1051510
+
+Userspace expects to receive tool type and serial number information
+for the active pen in the very first kernel report, if such data is
+supported by the hardware. While this expectation is not an issue for
+EMR devices, AES sensors will often send several packets worth of in-
+range data before relaying type/serial data to the kernel. Sending this
+data "late" can result in proximity-tracking issues by xf86-input-wacom,
+or an inability to distinguish different pens by input-wacom.
+
+Options for dealing with this situation include ignoring reports from
+the tablet until we get the necessary data, or using the information
+from the last-seen pen instead of the (eventual) real data. Neither
+option is particularly attractive: the former results in truncated
+strokes and the latter causes issues with switching between pens.
+
+This commit instead opts to queue up events with missing information
+until we receive a report which contains it. At that point, we can
+update the driver's state variables (id[0] and serial[0]) and replay
+the queued events.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_sys.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/hid/wacom_wac.c | 1 +
+ drivers/hid/wacom_wac.h | 3 ++
+ 3 files changed, 114 insertions(+)
+
+diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
+index ee71ad9b6cc1..c9eadf632564 100644
+--- a/drivers/hid/wacom_sys.c
++++ b/drivers/hid/wacom_sys.c
+@@ -56,6 +56,107 @@ static int wacom_set_report(struct hid_device *hdev, u8 type, u8 *buf,
+ return retval;
+ }
+
++static void wacom_wac_queue_insert(struct hid_device *hdev,
++ struct kfifo_rec_ptr_2 *fifo,
++ u8 *raw_data, int size)
++{
++ bool warned = false;
++
++ while (kfifo_avail(fifo) < size) {
++ if (!warned)
++ hid_warn(hdev, "%s: kfifo has filled, starting to drop events\n", __func__);
++ warned = true;
++
++ kfifo_skip(fifo);
++ }
++
++ kfifo_in(fifo, raw_data, size);
++}
++
++static void wacom_wac_queue_flush(struct hid_device *hdev,
++ struct kfifo_rec_ptr_2 *fifo)
++{
++ while (!kfifo_is_empty(fifo)) {
++ u8 buf[WACOM_PKGLEN_MAX];
++ int size;
++ int err;
++
++ size = kfifo_out(fifo, buf, sizeof(buf));
++ err = hid_report_raw_event(hdev, HID_INPUT_REPORT, buf, size, false);
++ if (err) {
++ hid_warn(hdev, "%s: unable to flush event due to error %d\n",
++ __func__, err);
++ }
++ }
++}
++
++static int wacom_wac_pen_serial_enforce(struct hid_device *hdev,
++ struct hid_report *report, u8 *raw_data, int size)
++{
++ struct wacom *wacom = hid_get_drvdata(hdev);
++ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
++ struct wacom_features *features = &wacom_wac->features;
++ bool flush = false;
++ bool insert = false;
++ int i, j;
++
++ if (wacom_wac->serial[0] || !(features->quirks & WACOM_QUIRK_TOOLSERIAL))
++ return 0;
++
++ /* Queue events which have invalid tool type or serial number */
++ for (i = 0; i < report->maxfield; i++) {
++ for (j = 0; j < report->field[i]->maxusage; j++) {
++ struct hid_field *field = report->field[i];
++ struct hid_usage *usage = &field->usage[j];
++ unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
++ unsigned int offset;
++ unsigned int size;
++ unsigned int value;
++
++ if (equivalent_usage != HID_DG_INRANGE &&
++ equivalent_usage != HID_DG_TOOLSERIALNUMBER &&
++ equivalent_usage != WACOM_HID_WD_SERIALHI &&
++ equivalent_usage != WACOM_HID_WD_TOOLTYPE)
++ continue;
++
++ offset = field->report_offset;
++ size = field->report_size;
++ value = hid_field_extract(hdev, raw_data+1, offset + j * size, size);
++
++ /* If we go out of range, we need to flush the queue ASAP */
++ if (equivalent_usage == HID_DG_INRANGE)
++ value = !value;
++
++ if (value) {
++ flush = true;
++ switch (equivalent_usage) {
++ case HID_DG_TOOLSERIALNUMBER:
++ wacom_wac->serial[0] = value;
++ break;
++
++ case WACOM_HID_WD_SERIALHI:
++ wacom_wac->serial[0] |= ((__u64)value) << 32;
++ break;
++
++ case WACOM_HID_WD_TOOLTYPE:
++ wacom_wac->id[0] = value;
++ break;
++ }
++ }
++ else {
++ insert = true;
++ }
++ }
++ }
++
++ if (flush)
++ wacom_wac_queue_flush(hdev, &wacom_wac->pen_fifo);
++ else if (insert)
++ wacom_wac_queue_insert(hdev, &wacom_wac->pen_fifo, raw_data, size);
++
++ return insert && !flush;
++}
++
+ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *raw_data, int size)
+ {
+@@ -64,6 +165,9 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
+ if (size > WACOM_PKGLEN_MAX)
+ return 1;
+
++ if (wacom_wac_pen_serial_enforce(hdev, report, raw_data, size))
++ return -1;
++
+ memcpy(wacom->wacom_wac.data, raw_data, size);
+
+ wacom_wac_irq(&wacom->wacom_wac, size);
+@@ -2580,6 +2684,10 @@ static int wacom_probe(struct hid_device *hdev,
+ goto fail;
+ }
+
++ error = kfifo_alloc(&wacom_wac->pen_fifo, WACOM_PKGLEN_MAX, GFP_KERNEL);
++ if (error)
++ goto fail;
++
+ wacom_wac->hid_data.inputmode = -1;
+ wacom_wac->mode_report = -1;
+
+@@ -2643,6 +2751,8 @@ static void wacom_remove(struct hid_device *hdev)
+ if (wacom->wacom_wac.features.type != REMOTE)
+ wacom_release_resources(wacom);
+
++ kfifo_free(&wacom_wac->pen_fifo);
++
+ hid_set_drvdata(hdev, NULL);
+ }
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index ff679ee3b358..7fa373225d8a 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2085,6 +2085,7 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
+ wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS2, 0);
+ break;
+ case HID_DG_TOOLSERIALNUMBER:
++ features->quirks |= WACOM_QUIRK_TOOLSERIAL;
+ wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0);
+
+ /* Adjust AES usages to match modern convention */
+diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
+index 6fe6d60f9ab5..15d9c14fbdf7 100644
+--- a/drivers/hid/wacom_wac.h
++++ b/drivers/hid/wacom_wac.h
+@@ -11,6 +11,7 @@
+
+ #include <linux/types.h>
+ #include <linux/hid.h>
++#include <linux/kfifo.h>
+
+ /* maximum packet length for USB/BT devices */
+ #define WACOM_PKGLEN_MAX 361
+@@ -88,6 +89,7 @@
+ #define WACOM_QUIRK_SENSE 0x0002
+ #define WACOM_QUIRK_AESPEN 0x0004
+ #define WACOM_QUIRK_BATTERY 0x0008
++#define WACOM_QUIRK_TOOLSERIAL 0x0010
+
+ /* device types */
+ #define WACOM_DEVICETYPE_NONE 0x0000
+@@ -339,6 +341,7 @@ struct wacom_wac {
+ struct input_dev *pen_input;
+ struct input_dev *touch_input;
+ struct input_dev *pad_input;
++ struct kfifo_rec_ptr_2 pen_fifo;
+ int pid;
+ int num_contacts_left;
+ u8 bt_features;
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Remove-comparison-of-u8-mode-with-zero-and.patch b/patches.drivers/HID-wacom-Remove-comparison-of-u8-mode-with-zero-and.patch
new file mode 100644
index 0000000000..12f505f3a5
--- /dev/null
+++ b/patches.drivers/HID-wacom-Remove-comparison-of-u8-mode-with-zero-and.patch
@@ -0,0 +1,40 @@
+From bc35f73aa62f51b80f769d3a6617f4a4ba11d81e Mon Sep 17 00:00:00 2001
+From: Christos Gkekas <chris.gekas@gmail.com>
+Date: Sat, 8 Jul 2017 20:25:48 +0100
+Subject: [PATCH] HID: wacom: Remove comparison of u8 mode with zero and simplify.
+Git-commit: bc35f73aa62f51b80f769d3a6617f4a4ba11d81e
+Patch-mainline: v4.14-rc1
+References: bsc#1051510
+
+Variable mode in method wacom_show_remote_mode() is defined as u8, thus
+statement (mode >= 0) is always true and should be removed, simplifying
+the logic.
+
+Signed-off-by: Christos Gkekas <chris.gekas@gmail.com>
+Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_sys.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
+index 838c1ebfffa9..ae2408d5e53d 100644
+--- a/drivers/hid/wacom_sys.c
++++ b/drivers/hid/wacom_sys.c
+@@ -1671,10 +1671,7 @@ static ssize_t wacom_show_remote_mode(struct kobject *kobj,
+ u8 mode;
+
+ mode = wacom->led.groups[index].select;
+- if (mode >= 0 && mode < 3)
+- return snprintf(buf, PAGE_SIZE, "%d\n", mode);
+- else
+- return snprintf(buf, PAGE_SIZE, "%d\n", -1);
++ return sprintf(buf, "%d\n", mode < 3 ? mode : -1);
+ }
+
+ #define DEVICE_EKR_ATTR_GROUP(SET_ID) \
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Replace-touch_max-fixup-code-with-static-t.patch b/patches.drivers/HID-wacom-Replace-touch_max-fixup-code-with-static-t.patch
new file mode 100644
index 0000000000..17cbb24128
--- /dev/null
+++ b/patches.drivers/HID-wacom-Replace-touch_max-fixup-code-with-static-t.patch
@@ -0,0 +1,121 @@
+From 29b9e14846f1ff201c4c1ba4fdb868dcdce6c760 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Mon, 25 Jun 2018 13:24:34 -0700
+Subject: [PATCH] HID: wacom: Replace touch_max fixup code with static touch_max definitions
+Git-commit: 29b9e14846f1ff201c4c1ba4fdb868dcdce6c760
+Patch-mainline: v4.19-rc1
+References: bsc#1051510
+
+Detecting the number of supported touches for a particular device used
+to be tricky, both because early forms of the driver didn't have a very
+good HID parser and because early hardware didn't always advertise the
+actual number. At the time, we added a block of code which would ensure
+that touch_max would always be equal to at least 1 on any touch device,
+and relied on setting touch_max to e.g. 2 only for the multitouch-capable
+exceptions.
+
+The common case has since flipped, and the driver and descriptors can
+reliably detect the number of touches supported by modern sensors.
+Because of this, it makes sense to remove the fixup code and instead
+place static declarations of "touch_max = 1" for these old devices. It
+isn't entirely clear if all 2-finger devices actually report a maximum
+number of touches so we leave these declarations still in place.
+
+For the eagle-eyed, the "> BAMBOO_PT" condition was originally equivalent
+to ">= TABLETPC", which is what the intent was. This commit doesn't have
+to consider the types introduced in the interim since they shouldn't be
+affected, hence why only the tablet PC definitions have been modified.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_sys.c | 10 ----------
+ drivers/hid/wacom_wac.c | 20 ++++++++++----------
+ 2 files changed, 10 insertions(+), 20 deletions(-)
+
+diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
+index d6797535fff9..6b67c6907caa 100644
+--- a/drivers/hid/wacom_sys.c
++++ b/drivers/hid/wacom_sys.c
+@@ -361,16 +361,6 @@ static void wacom_usage_mapping(struct hid_device *hdev,
+ else
+ return;
+
+- /*
+- * Bamboo models do not support HID_DG_CONTACTMAX.
+- * And, Bamboo Pen only descriptor contains touch.
+- */
+- if (features->type > BAMBOO_PT) {
+- /* ISDv4 touch devices at least supports one touch point */
+- if (finger && !features->touch_max)
+- features->touch_max = 1;
+- }
+-
+ /*
+ * ISDv4 devices which predate HID's adoption of the
+ * HID_DG_BARELSWITCH2 usage use 0x000D0000 in its
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 0bb44d0088ed..e0842241f692 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -4351,19 +4351,19 @@ static const struct wacom_features wacom_features_0x5E =
+ .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+ static const struct wacom_features wacom_features_0x90 =
+ { "Wacom ISDv4 90", 26202, 16325, 255, 0,
+- TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
++ TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
+ static const struct wacom_features wacom_features_0x93 =
+ { "Wacom ISDv4 93", 26202, 16325, 255, 0,
+- TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
++ TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
+ static const struct wacom_features wacom_features_0x97 =
+ { "Wacom ISDv4 97", 26202, 16325, 511, 0,
+- TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
++ TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
+ static const struct wacom_features wacom_features_0x9A =
+ { "Wacom ISDv4 9A", 26202, 16325, 255, 0,
+- TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
++ TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
+ static const struct wacom_features wacom_features_0x9F =
+ { "Wacom ISDv4 9F", 26202, 16325, 255, 0,
+- TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
++ TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
+ static const struct wacom_features wacom_features_0xE2 =
+ { "Wacom ISDv4 E2", 26202, 16325, 255, 0,
+ TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
+@@ -4378,13 +4378,13 @@ static const struct wacom_features wacom_features_0xE6 =
+ TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
+ static const struct wacom_features wacom_features_0xEC =
+ { "Wacom ISDv4 EC", 25710, 14500, 255, 0,
+- TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
++ TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
+ static const struct wacom_features wacom_features_0xED =
+ { "Wacom ISDv4 ED", 26202, 16325, 255, 0,
+- TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
++ TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
+ static const struct wacom_features wacom_features_0xEF =
+ { "Wacom ISDv4 EF", 26202, 16325, 255, 0,
+- TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
++ TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
+ static const struct wacom_features wacom_features_0x100 =
+ { "Wacom ISDv4 100", 26202, 16325, 255, 0,
+ MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+@@ -4402,10 +4402,10 @@ static const struct wacom_features wacom_features_0x10F =
+ MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ static const struct wacom_features wacom_features_0x116 =
+ { "Wacom ISDv4 116", 26202, 16325, 255, 0,
+- TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
++ TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 };
+ static const struct wacom_features wacom_features_0x12C =
+ { "Wacom ISDv4 12C", 27848, 15752, 2047, 0,
+- TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
++ TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */
+ static const struct wacom_features wacom_features_0x4001 =
+ { "Wacom ISDv4 4001", 26202, 16325, 255, 0,
+ MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Send-BTN_TOUCH-in-response-to-INTUOSP2_BT-.patch b/patches.drivers/HID-wacom-Send-BTN_TOUCH-in-response-to-INTUOSP2_BT-.patch
new file mode 100644
index 0000000000..5165b74ea3
--- /dev/null
+++ b/patches.drivers/HID-wacom-Send-BTN_TOUCH-in-response-to-INTUOSP2_BT-.patch
@@ -0,0 +1,42 @@
+From fe7f8d73d1af19b678171170e4e5384deb57833d Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <jason.gerecke@wacom.com>
+Date: Tue, 7 May 2019 11:53:20 -0700
+Subject: [PATCH] HID: wacom: Send BTN_TOUCH in response to INTUOSP2_BT eraser contact
+Git-commit: fe7f8d73d1af19b678171170e4e5384deb57833d
+Patch-mainline: v5.2 or v5.2-rc5 (next release)
+References: bsc#1051510
+
+The Bluetooth reports from the 2nd-gen Intuos Pro have separate bits for
+indicating if the tip or eraser is in contact with the tablet. At the
+moment, only the tip contact bit controls the state of the BTN_TOUCH
+event. This prevents the eraser from working as expected. This commit
+changes the driver to send BTN_TOUCH whenever either the tip or eraser
+contact bit is set.
+
+Fixes: 4922cd26f03c ("HID: wacom: Support 2nd-gen Intuos Pro's Bluetooth classic interface")
+Cc: <stable@vger.kernel.org> # 4.11+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Aaron Skomra <aaron.skomra@wacom.com>
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 613342bb9d6b..af62a630fee9 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1301,7 +1301,7 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
+ range ? frame[7] : wacom->features.distance_max);
+ }
+
+- input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x01);
++ input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x09);
+ input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02);
+ input_report_key(pen_input, BTN_STYLUS2, frame[0] & 0x04);
+
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Support-in-range-for-Intuos-Bamboo-tablets.patch b/patches.drivers/HID-wacom-Support-in-range-for-Intuos-Bamboo-tablets.patch
new file mode 100644
index 0000000000..ec491fd927
--- /dev/null
+++ b/patches.drivers/HID-wacom-Support-in-range-for-Intuos-Bamboo-tablets.patch
@@ -0,0 +1,142 @@
+From 8947b0cfdcc111722b2293f26debdab8697f4c68 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Fri, 18 May 2018 07:17:18 -0700
+Subject: [PATCH] HID: wacom: Support "in range" for Intuos/Bamboo tablets where possible
+Git-commit: 8947b0cfdcc111722b2293f26debdab8697f4c68
+Patch-mainline: v4.18-rc1
+References: bsc#1051510
+
+The 1st-generation Intuos tablets (CTL-X80) include an "in range" flag
+like some professional tablets. To ensure the pen remains usable at as
+large as distance as possible (and to preemptively disable touch when
+it is nearby) we need to ensure that we handle these "in range" events.
+Handling of tool type identification has been moved to occur only when
+the pen is fully in prox rather than any time the "stylus_in_proximity"
+flag changes (which is controlled by the further-out "in range" flag).
+
+Link: https://sourceforge.net/p/linuxwacom/bugs/358/
+Link: https://github.com/linuxwacom/xf86-input-wacom/issues/14
+Link: https://github.com/linuxwacom/xf86-input-wacom/issues/17
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Tested-by: Ping Cheng <ping.cheng@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 74 ++++++++++++++++++++++++++-----------------------
+ 1 file changed, 39 insertions(+), 35 deletions(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 5f947ec20dcb..0bb44d0088ed 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2894,24 +2894,31 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
+ struct wacom_features *features = &wacom->features;
+ struct input_dev *input = wacom->pen_input;
+ unsigned char *data = wacom->data;
+- int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0;
++ int x = 0, y = 0, p = 0, d = 0;
++ bool pen = false, btn1 = false, btn2 = false;
++ bool range, prox, rdy;
+
+ if (data[0] != WACOM_REPORT_PENABLED)
+ return 0;
+
+- prox = (data[1] & 0x20) == 0x20;
++ range = (data[1] & 0x80) == 0x80;
++ prox = (data[1] & 0x40) == 0x40;
++ rdy = (data[1] & 0x20) == 0x20;
++
++ wacom->shared->stylus_in_proximity = range;
++ if (delay_pen_events(wacom))
++ return 0;
++
++ if (rdy) {
++ p = le16_to_cpup((__le16 *)&data[6]);
++ pen = data[1] & 0x01;
++ btn1 = data[1] & 0x02;
++ btn2 = data[1] & 0x04;
++ }
++ if (prox) {
++ x = le16_to_cpup((__le16 *)&data[2]);
++ y = le16_to_cpup((__le16 *)&data[4]);
+
+- /*
+- * All reports shared between PEN and RUBBER tool must be
+- * forced to a known starting value (zero) when transitioning to
+- * out-of-prox.
+- *
+- * If not reset then, to userspace, it will look like lost events
+- * if new tool comes in-prox with same values as previous tool sent.
+- *
+- * Hardware does report zero in most out-of-prox cases but not all.
+- */
+- if (!wacom->shared->stylus_in_proximity) {
+ if (data[1] & 0x08) {
+ wacom->tool[0] = BTN_TOOL_RUBBER;
+ wacom->id[0] = ERASER_DEVICE_ID;
+@@ -2919,16 +2926,9 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
+ wacom->tool[0] = BTN_TOOL_PEN;
+ wacom->id[0] = STYLUS_DEVICE_ID;
+ }
++ wacom->reporting_data = true;
+ }
+-
+- wacom->shared->stylus_in_proximity = prox;
+- if (delay_pen_events(wacom))
+- return 0;
+-
+- if (prox) {
+- x = le16_to_cpup((__le16 *)&data[2]);
+- y = le16_to_cpup((__le16 *)&data[4]);
+- p = le16_to_cpup((__le16 *)&data[6]);
++ if (range) {
+ /*
+ * Convert distance from out prox to distance from tablet.
+ * distance will be greater than distance_max once
+@@ -2937,25 +2937,29 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
+ */
+ if (data[8] <= features->distance_max)
+ d = features->distance_max - data[8];
+-
+- pen = data[1] & 0x01;
+- btn1 = data[1] & 0x02;
+- btn2 = data[1] & 0x04;
+ } else {
+ wacom->id[0] = 0;
+ }
+
+- input_report_key(input, BTN_TOUCH, pen);
+- input_report_key(input, BTN_STYLUS, btn1);
+- input_report_key(input, BTN_STYLUS2, btn2);
++ if (wacom->reporting_data) {
++ input_report_key(input, BTN_TOUCH, pen);
++ input_report_key(input, BTN_STYLUS, btn1);
++ input_report_key(input, BTN_STYLUS2, btn2);
+
+- input_report_abs(input, ABS_X, x);
+- input_report_abs(input, ABS_Y, y);
+- input_report_abs(input, ABS_PRESSURE, p);
+- input_report_abs(input, ABS_DISTANCE, d);
++ if (prox || !range) {
++ input_report_abs(input, ABS_X, x);
++ input_report_abs(input, ABS_Y, y);
++ }
++ input_report_abs(input, ABS_PRESSURE, p);
++ input_report_abs(input, ABS_DISTANCE, d);
+
+- input_report_key(input, wacom->tool[0], prox); /* PEN or RUBBER */
+- input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */
++ input_report_key(input, wacom->tool[0], range); /* PEN or RUBBER */
++ input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */
++ }
++
++ if (!range) {
++ wacom->reporting_data = false;
++ }
+
+ return 1;
+ }
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Sync-INTUOSP2_BT-touch-state-after-each-fr.patch b/patches.drivers/HID-wacom-Sync-INTUOSP2_BT-touch-state-after-each-fr.patch
new file mode 100644
index 0000000000..e3e0901a0f
--- /dev/null
+++ b/patches.drivers/HID-wacom-Sync-INTUOSP2_BT-touch-state-after-each-fr.patch
@@ -0,0 +1,55 @@
+From 69dbdfffef20c715df9f381b2cee4e9e0a4efd93 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <jason.gerecke@wacom.com>
+Date: Tue, 7 May 2019 11:53:22 -0700
+Subject: [PATCH] HID: wacom: Sync INTUOSP2_BT touch state after each frame if necessary
+Git-commit: 69dbdfffef20c715df9f381b2cee4e9e0a4efd93
+Patch-mainline: v5.2 or v5.2-rc5 (next release)
+References: bsc#1051510
+
+The Bluetooth interface of the 2nd-gen Intuos Pro batches together four
+independent "frames" of finger data into a single report. Each frame
+is essentially equivalent to a single USB report, with the up-to-10
+fingers worth of information being spread across two frames. At the
+moment the driver only calls `input_sync` after processing all four
+frames have been processed, which can result in the driver sending
+multiple updates for a single slot within the same SYN_REPORT. This
+can confuse userspace, so modify the driver to sync more often if
+necessary (i.e., after reporting the state of all fingers).
+
+Fixes: 4922cd26f03c ("HID: wacom: Support 2nd-gen Intuos Pro's Bluetooth classic interface")
+Cc: <stable@vger.kernel.org> # 4.11+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index e848445236d8..09b8e4aac82f 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1371,11 +1371,17 @@ static void wacom_intuos_pro2_bt_touch(struct wacom_wac *wacom)
+ if (wacom->num_contacts_left <= 0) {
+ wacom->num_contacts_left = 0;
+ wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
++ input_sync(touch_input);
+ }
+ }
+
+- input_report_switch(touch_input, SW_MUTE_DEVICE, !(data[281] >> 7));
+- input_sync(touch_input);
++ if (wacom->num_contacts_left == 0) {
++ // Be careful that we don't accidentally call input_sync with
++ // only a partial set of fingers of processed
++ input_report_switch(touch_input, SW_MUTE_DEVICE, !(data[281] >> 7));
++ input_sync(touch_input);
++ }
++
+ }
+
+ static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom)
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-Work-around-HID-descriptor-bug-in-DTK-2451.patch b/patches.drivers/HID-wacom-Work-around-HID-descriptor-bug-in-DTK-2451.patch
new file mode 100644
index 0000000000..bb67013b58
--- /dev/null
+++ b/patches.drivers/HID-wacom-Work-around-HID-descriptor-bug-in-DTK-2451.patch
@@ -0,0 +1,70 @@
+From 11db8173dbab7a94cf5ba5225fcedbfc0f3b7e54 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Wed, 10 Oct 2018 13:40:26 -0700
+Subject: [PATCH] HID: wacom: Work around HID descriptor bug in DTK-2451 and DTH-2452
+Git-commit: 11db8173dbab7a94cf5ba5225fcedbfc0f3b7e54
+Patch-mainline: v4.20-rc1
+References: bsc#1051510
+
+The DTK-2451 and DTH-2452 have a buggy HID descriptor which incorrectly
+contains a Cintiq-like report, complete with pen tilt, rotation, twist, serial
+number, etc. The hardware doesn't actually support this data but our driver
+duitifully sets up the device as though it does. To ensure userspace has a
+correct view of devices without updated firmware, we clean up this incorrect
+data in wacom_setup_device_quirks.
+
+We're also careful to clear the WACOM_QUIRK_TOOLSERIAL flag since its presence
+causes the driver to wait for serial number information (via
+wacom_wac_pen_serial_enforce) that never comes, resulting in
+the pen being non-responsive.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Fixes: 8341720642 ("HID: wacom: Queue events with missing type/serial data for later processing")
+Cc: stable@vger.kernel.org # v4.16+
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index e0a06be5ef5c..5dd3a8245f0f 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -3335,6 +3335,7 @@ static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
+
+ void wacom_setup_device_quirks(struct wacom *wacom)
+ {
++ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_features *features = &wacom->wacom_wac.features;
+
+ /* The pen and pad share the same interface on most devices */
+@@ -3464,6 +3465,24 @@ void wacom_setup_device_quirks(struct wacom *wacom)
+
+ if (features->type == REMOTE)
+ features->device_type |= WACOM_DEVICETYPE_WL_MONITOR;
++
++ /* HID descriptor for DTK-2451 / DTH-2452 claims to report lots
++ * of things it shouldn't. Lets fix up the damage...
++ */
++ if (wacom->hdev->product == 0x382 || wacom->hdev->product == 0x37d) {
++ features->quirks &= ~WACOM_QUIRK_TOOLSERIAL;
++ __clear_bit(BTN_TOOL_BRUSH, wacom_wac->pen_input->keybit);
++ __clear_bit(BTN_TOOL_PENCIL, wacom_wac->pen_input->keybit);
++ __clear_bit(BTN_TOOL_AIRBRUSH, wacom_wac->pen_input->keybit);
++ __clear_bit(ABS_Z, wacom_wac->pen_input->absbit);
++ __clear_bit(ABS_DISTANCE, wacom_wac->pen_input->absbit);
++ __clear_bit(ABS_TILT_X, wacom_wac->pen_input->absbit);
++ __clear_bit(ABS_TILT_Y, wacom_wac->pen_input->absbit);
++ __clear_bit(ABS_WHEEL, wacom_wac->pen_input->absbit);
++ __clear_bit(ABS_MISC, wacom_wac->pen_input->absbit);
++ __clear_bit(MSC_SERIAL, wacom_wac->pen_input->mscbit);
++ __clear_bit(EV_MSC, wacom_wac->pen_input->evbit);
++ }
+ }
+
+ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-bluetooth-send-exit-report-for-recent-Blue b/patches.drivers/HID-wacom-bluetooth-send-exit-report-for-recent-Blue
index 50c8e508e7..486a41e08d 100644
--- a/patches.drivers/HID-wacom-bluetooth-send-exit-report-for-recent-Blue
+++ b/patches.drivers/HID-wacom-bluetooth-send-exit-report-for-recent-Blue
@@ -22,7 +22,7 @@ Acked-by: Takashi Iwai <tiwai@suse.de>
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
-@@ -685,6 +685,45 @@ static int wacom_intuos_get_tool_type(in
+@@ -689,6 +689,45 @@ static int wacom_intuos_get_tool_type(in
return tool_type;
}
@@ -68,7 +68,7 @@ Acked-by: Takashi Iwai <tiwai@suse.de>
static int wacom_intuos_inout(struct wacom_wac *wacom)
{
struct wacom_features *features = &wacom->features;
-@@ -737,36 +776,7 @@ static int wacom_intuos_inout(struct wac
+@@ -741,36 +780,7 @@ static int wacom_intuos_inout(struct wac
if (!wacom->id[idx])
return 1;
@@ -106,7 +106,7 @@ Acked-by: Takashi Iwai <tiwai@suse.de>
return 2;
}
-@@ -1220,6 +1230,12 @@ static void wacom_intuos_pro2_bt_pen(str
+@@ -1235,6 +1245,12 @@ static void wacom_intuos_pro2_bt_pen(str
if (!valid)
continue;
@@ -117,5 +117,5 @@ Acked-by: Takashi Iwai <tiwai@suse.de>
+ return;
+ }
if (range) {
- /* Fix rotation alignment: userspace expects zero at left */
- int16_t rotation = (int16_t)get_unaligned_le16(&frame[9]);
+ input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
+ input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
diff --git a/patches.drivers/HID-wacom-convert-Wacom-custom-usages-to-standard-HI.patch b/patches.drivers/HID-wacom-convert-Wacom-custom-usages-to-standard-HI.patch
new file mode 100644
index 0000000000..b1014761e2
--- /dev/null
+++ b/patches.drivers/HID-wacom-convert-Wacom-custom-usages-to-standard-HI.patch
@@ -0,0 +1,43 @@
+From 418b573b431310306db31e445594317ba62f5508 Mon Sep 17 00:00:00 2001
+From: Ping Cheng <pingc@wacom.com>
+Date: Mon, 25 Jun 2018 13:24:36 -0700
+Subject: [PATCH] HID: wacom: convert Wacom custom usages to standard HID usages
+Git-commit: 418b573b431310306db31e445594317ba62f5508
+Patch-mainline: v4.19-rc1
+References: bsc#1051510
+
+Otherwise the switch would not catch the proper usages.
+
+Signed-off-by: Ping Cheng <ping.cheng@wacom.com>
+Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_sys.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
+index 3a4cf2666a7c..52e85d21e40f 100644
+--- a/drivers/hid/wacom_sys.c
++++ b/drivers/hid/wacom_sys.c
+@@ -394,6 +394,7 @@ static void wacom_usage_mapping(struct hid_device *hdev,
+ struct wacom_features *features = &wacom->wacom_wac.features;
+ bool finger = WACOM_FINGER_FIELD(field);
+ bool pen = WACOM_PEN_FIELD(field);
++ unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
+
+ /*
+ * Requiring Stylus Usage will ignore boot mouse
+@@ -409,7 +410,7 @@ static void wacom_usage_mapping(struct hid_device *hdev,
+
+ wacom_hid_usage_quirk(hdev, field, usage);
+
+- switch (usage->hid) {
++ switch (equivalent_usage) {
+ case HID_GD_X:
+ features->x_max = field->logical_maximum;
+ if (finger) {
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-fix-mistake-in-printk.patch b/patches.drivers/HID-wacom-fix-mistake-in-printk.patch
new file mode 100644
index 0000000000..edeee05353
--- /dev/null
+++ b/patches.drivers/HID-wacom-fix-mistake-in-printk.patch
@@ -0,0 +1,59 @@
+From 75a5f3ac5c861e969e2379816709d55f1cb5e9f4 Mon Sep 17 00:00:00 2001
+From: Colin Ian King <colin.king@canonical.com>
+Date: Mon, 26 Jun 2017 20:35:38 +0100
+Subject: [PATCH] HID: wacom: fix mistake in printk
+Git-commit: 75a5f3ac5c861e969e2379816709d55f1cb5e9f4
+Patch-mainline: v4.13-rc1
+References: bsc#1051510
+
+trivial fix to spelling mistake in hid_warn warning message
+
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index aa0becea865e..149bdff28d32 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2109,28 +2109,28 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
+ return;
+ case WACOM_HID_WD_OFFSETLEFT:
+ if (features->offset_left && value != features->offset_left)
+- hid_warn(hdev, "%s: overriding exising left offset "
++ hid_warn(hdev, "%s: overriding existing left offset "
+ "%d -> %d\n", __func__, value,
+ features->offset_left);
+ features->offset_left = value;
+ return;
+ case WACOM_HID_WD_OFFSETRIGHT:
+ if (features->offset_right && value != features->offset_right)
+- hid_warn(hdev, "%s: overriding exising right offset "
++ hid_warn(hdev, "%s: overriding existing right offset "
+ "%d -> %d\n", __func__, value,
+ features->offset_right);
+ features->offset_right = value;
+ return;
+ case WACOM_HID_WD_OFFSETTOP:
+ if (features->offset_top && value != features->offset_top)
+- hid_warn(hdev, "%s: overriding exising top offset "
++ hid_warn(hdev, "%s: overriding existing top offset "
+ "%d -> %d\n", __func__, value,
+ features->offset_top);
+ features->offset_top = value;
+ return;
+ case WACOM_HID_WD_OFFSETBOTTOM:
+ if (features->offset_bottom && value != features->offset_bottom)
+- hid_warn(hdev, "%s: overriding exising bottom offset "
++ hid_warn(hdev, "%s: overriding existing bottom offset "
+ "%d -> %d\n", __func__, value,
+ features->offset_bottom);
+ features->offset_bottom = value;
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-generic-Ignore-HID_DG_BATTERYSTRENTH-0.patch b/patches.drivers/HID-wacom-generic-Ignore-HID_DG_BATTERYSTRENTH-0.patch
new file mode 100644
index 0000000000..495606822f
--- /dev/null
+++ b/patches.drivers/HID-wacom-generic-Ignore-HID_DG_BATTERYSTRENTH-0.patch
@@ -0,0 +1,38 @@
+From f496c09c0785b60fa6b762ad720ba31f6a9de0ac Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Fri, 28 Apr 2017 09:25:31 -0700
+Subject: [PATCH] HID: wacom: generic: Ignore HID_DG_BATTERYSTRENTH == 0
+Git-commit: f496c09c0785b60fa6b762ad720ba31f6a9de0ac
+Patch-mainline: v4.13-rc1
+References: bsc#1051510
+
+AES sensors use the value 0 to indicate "not available" rather than
+"completely dead". Such values are often sent for dozens of reports
+while the pen is being brought into proximity and can cause userspace
+to get the wrong impression about the actual battery state.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index fd989e09ae2d..70a9e47b215a 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2036,6 +2036,8 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
+ wacom_wac->hid_data.sense_state = value;
+ return;
+ case HID_DG_BATTERYSTRENGTH:
++ if (value == 0) /* "not available" */
++ break;
+ value = value * 100 / (field->logical_maximum - field->logical_minimum);
+ wacom_wac->hid_data.battery_capacity = value;
+ wacom_wac->hid_data.bat_connected = 1;
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-generic-Leave-tool-in-prox-until-it-comple.patch b/patches.drivers/HID-wacom-generic-Leave-tool-in-prox-until-it-comple.patch
new file mode 100644
index 0000000000..d287629ad9
--- /dev/null
+++ b/patches.drivers/HID-wacom-generic-Leave-tool-in-prox-until-it-comple.patch
@@ -0,0 +1,73 @@
+From 4affc2331a70fff3d0d0e8f28ead80aa2b8b589a Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Thu, 7 Sep 2017 17:49:50 -0700
+Subject: [PATCH] HID: wacom: generic: Leave tool in prox until it completely leaves sense
+Git-commit: 4affc2331a70fff3d0d0e8f28ead80aa2b8b589a
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+The legacy Intuos codepath and tablet behavior (e.g. the 1st-gen Intuos
+Pro, Cintiq 27, etc.) would result in a BTN_TOOL_* event not being cleared
+to zero until the tool had completely left the sensing range of the
+tablet. Before the final "out of prox" packet would be sent, zero or
+more "in range" packets could be sent to indicate that a pen was still
+detectable but not within a useful distance. These "in range" packets
+were used by the driver to keep touch input disabled at greater pen
+distances. In addition to keeping the `stylus_in_proximity` flag set,
+the driver would leave the current BTN_TOOL_* marked as being in
+proximity as well.
+
+The new HID codepath also sets `stylus_in_proximity` based on the "sense"
+flag, but does not leave the current BTN_TOOL_* marked as being in prox.
+This information is potentially useful to for a future userspace-based
+palm rejection, so this patch modifies the driver to continue sending it.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index cdf95e1999d1..9b3a247ee552 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2217,8 +2217,8 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
+ if (!usage->type || delay_pen_events(wacom_wac))
+ return;
+
+- /* send pen events only when the pen is in/entering/leaving range */
+- if (!wacom_wac->hid_data.inrange_state && !wacom_wac->tool[0])
++ /* send pen events only when the pen is in range */
++ if (!wacom_wac->hid_data.inrange_state)
+ return;
+
+ input_event(input, usage->type, usage->code, value);
+@@ -2269,10 +2269,10 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
+ */
+ input_report_key(input, BTN_TOUCH,
+ wacom_wac->hid_data.tipswitch);
+- input_report_key(input, wacom_wac->tool[0], range);
++ input_report_key(input, wacom_wac->tool[0], sense);
+ if (wacom_wac->serial[0]) {
+ input_event(input, EV_MSC, MSC_SERIAL, wacom_wac->serial[0]);
+- input_report_abs(input, ABS_MISC, range ? id : 0);
++ input_report_abs(input, ABS_MISC, sense ? id : 0);
+ }
+
+ wacom_wac->hid_data.tipswitch = false;
+@@ -2280,7 +2280,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
+ input_sync(input);
+ }
+
+- if (!range) {
++ if (!sense) {
+ wacom_wac->tool[0] = 0;
+ wacom_wac->id[0] = 0;
+ wacom_wac->serial[0] = 0;
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-generic-Refactor-generic-battery-handling.patch b/patches.drivers/HID-wacom-generic-Refactor-generic-battery-handling.patch
new file mode 100644
index 0000000000..6157a461a4
--- /dev/null
+++ b/patches.drivers/HID-wacom-generic-Refactor-generic-battery-handling.patch
@@ -0,0 +1,302 @@
+From 5ac3d4ae58050f451a4fd868028f25258ea0a628 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Fri, 28 Apr 2017 09:25:34 -0700
+Subject: [PATCH] HID: wacom: generic: Refactor generic battery handling
+Git-commit: 5ac3d4ae58050f451a4fd868028f25258ea0a628
+Patch-mainline: v4.13-rc1
+References: bsc#1051510
+
+Generic battery handling code is spread between the pen and pad codepaths
+since battery usages may appear in reports for either. This makes it
+difficult to concisely see the logic involved. Since battery data is
+not treated like other data (i.e., we report it through the power_supply
+subsystem rather than through the input subsystem), it makes reasonable
+sense to split the functionality out into its own functions.
+
+This commit has the generic battery handling duplicate the same pattern
+that is used by the pen, pad, and touch interfaces. A "mapping" function
+is provided to set up the battery, an "event" function is provided to
+update the battery data, and a "report" function is provided to notify
+the power_supply subsystem after all the data has been read. We look at
+the usage itself rather than its collection to determine if one of the
+battery functions should handle it. Additionally, we unconditionally
+call the "report" function since there is no particularly good way to
+know if a report contained a battery usage; 'wacom_notify_battery()'
+will filter out any duplicate updates, however.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 162 +++++++++++++++++++++++++++---------------------
+ drivers/hid/wacom_wac.h | 4 ++
+ 2 files changed, 95 insertions(+), 71 deletions(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 08a865f733fa..aa0becea865e 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1702,20 +1702,92 @@ static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage,
+ }
+ }
+
+-static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
++static void wacom_wac_battery_usage_mapping(struct hid_device *hdev,
+ struct hid_field *field, struct hid_usage *usage)
+ {
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_features *features = &wacom_wac->features;
+- struct input_dev *input = wacom_wac->pad_input;
+ unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
+
+ switch (equivalent_usage) {
++ case HID_DG_BATTERYSTRENGTH:
+ case WACOM_HID_WD_BATTERY_LEVEL:
+ case WACOM_HID_WD_BATTERY_CHARGING:
+ features->quirks |= WACOM_QUIRK_BATTERY;
+ break;
++ }
++}
++
++static void wacom_wac_battery_event(struct hid_device *hdev, struct hid_field *field,
++ struct hid_usage *usage, __s32 value)
++{
++ struct wacom *wacom = hid_get_drvdata(hdev);
++ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
++ unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
++
++ switch (equivalent_usage) {
++ case HID_DG_BATTERYSTRENGTH:
++ if (value == 0) {
++ wacom_wac->hid_data.bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
++ }
++ else {
++ value = value * 100 / (field->logical_maximum - field->logical_minimum);
++ wacom_wac->hid_data.battery_capacity = value;
++ wacom_wac->hid_data.bat_connected = 1;
++ wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
++ }
++ break;
++ case WACOM_HID_WD_BATTERY_LEVEL:
++ value = value * 100 / (field->logical_maximum - field->logical_minimum);
++ wacom_wac->hid_data.battery_capacity = value;
++ wacom_wac->hid_data.bat_connected = 1;
++ wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
++ break;
++ case WACOM_HID_WD_BATTERY_CHARGING:
++ wacom_wac->hid_data.bat_charging = value;
++ wacom_wac->hid_data.ps_connected = value;
++ wacom_wac->hid_data.bat_connected = 1;
++ wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
++ break;
++ }
++}
++
++static void wacom_wac_battery_pre_report(struct hid_device *hdev,
++ struct hid_report *report)
++{
++ return;
++}
++
++static void wacom_wac_battery_report(struct hid_device *hdev,
++ struct hid_report *report)
++{
++ struct wacom *wacom = hid_get_drvdata(hdev);
++ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
++ struct wacom_features *features = &wacom_wac->features;
++
++ if (features->quirks & WACOM_QUIRK_BATTERY) {
++ int status = wacom_wac->hid_data.bat_status;
++ int capacity = wacom_wac->hid_data.battery_capacity;
++ bool charging = wacom_wac->hid_data.bat_charging;
++ bool connected = wacom_wac->hid_data.bat_connected;
++ bool powered = wacom_wac->hid_data.ps_connected;
++
++ wacom_notify_battery(wacom_wac, status, capacity, charging,
++ connected, powered);
++ }
++}
++
++static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
++ struct hid_field *field, struct hid_usage *usage)
++{
++ struct wacom *wacom = hid_get_drvdata(hdev);
++ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
++ struct wacom_features *features = &wacom_wac->features;
++ struct input_dev *input = wacom_wac->pad_input;
++ unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
++
++ switch (equivalent_usage) {
+ case WACOM_HID_WD_ACCELEROMETER_X:
+ __set_bit(INPUT_PROP_ACCELEROMETER, input->propbit);
+ wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 0);
+@@ -1809,29 +1881,6 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
+ }
+ }
+
+-static void wacom_wac_pad_battery_event(struct hid_device *hdev, struct hid_field *field,
+- struct hid_usage *usage, __s32 value)
+-{
+- struct wacom *wacom = hid_get_drvdata(hdev);
+- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+- unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
+-
+- switch (equivalent_usage) {
+- case WACOM_HID_WD_BATTERY_LEVEL:
+- value = value * 100 / (field->logical_maximum - field->logical_minimum);
+- wacom_wac->hid_data.battery_capacity = value;
+- wacom_wac->hid_data.bat_connected = 1;
+- wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
+- break;
+-
+- case WACOM_HID_WD_BATTERY_CHARGING:
+- wacom_wac->hid_data.bat_charging = value;
+- wacom_wac->hid_data.ps_connected = value;
+- wacom_wac->hid_data.bat_connected = 1;
+- break;
+- }
+-}
+-
+ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+ {
+@@ -1905,25 +1954,6 @@ static void wacom_wac_pad_pre_report(struct hid_device *hdev,
+ wacom_wac->hid_data.inrange_state = 0;
+ }
+
+-static void wacom_wac_pad_battery_report(struct hid_device *hdev,
+- struct hid_report *report)
+-{
+- struct wacom *wacom = hid_get_drvdata(hdev);
+- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+- struct wacom_features *features = &wacom_wac->features;
+-
+- if (features->quirks & WACOM_QUIRK_BATTERY) {
+- int status = wacom_wac->hid_data.bat_status;
+- int capacity = wacom_wac->hid_data.battery_capacity;
+- bool charging = wacom_wac->hid_data.bat_charging;
+- bool connected = wacom_wac->hid_data.bat_connected;
+- bool powered = wacom_wac->hid_data.ps_connected;
+-
+- wacom_notify_battery(wacom_wac, status, capacity,
+- charging, connected, powered);
+- }
+-}
+-
+ static void wacom_wac_pad_report(struct hid_device *hdev,
+ struct hid_report *report)
+ {
+@@ -1969,9 +1999,6 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
+ case HID_DG_INRANGE:
+ wacom_map_usage(input, usage, field, EV_KEY, BTN_TOOL_PEN, 0);
+ break;
+- case HID_DG_BATTERYSTRENGTH:
+- features->quirks |= WACOM_QUIRK_BATTERY;
+- break;
+ case HID_DG_INVERT:
+ wacom_map_usage(input, usage, field, EV_KEY,
+ BTN_TOOL_RUBBER, 0);
+@@ -2044,17 +2071,6 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
+ if (!(features->quirks & WACOM_QUIRK_SENSE))
+ wacom_wac->hid_data.sense_state = value;
+ return;
+- case HID_DG_BATTERYSTRENGTH:
+- if (value == 0) {
+- wacom_wac->hid_data.bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
+- }
+- else {
+- value = value * 100 / (field->logical_maximum - field->logical_minimum);
+- wacom_wac->hid_data.battery_capacity = value;
+- wacom_wac->hid_data.bat_connected = 1;
+- wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
+- }
+- break;
+ case HID_DG_INVERT:
+ wacom_wac->hid_data.invert_state = value;
+ return;
+@@ -2190,8 +2206,6 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
+ input_sync(input);
+ }
+
+- wacom_wac_pad_battery_report(hdev, report);
+-
+ if (!prox) {
+ wacom_wac->tool[0] = 0;
+ wacom_wac->id[0] = 0;
+@@ -2413,7 +2427,10 @@ void wacom_wac_usage_mapping(struct hid_device *hdev,
+ if (WACOM_DIRECT_DEVICE(field))
+ features->device_type |= WACOM_DEVICETYPE_DIRECT;
+
+- if (WACOM_PAD_FIELD(field))
++ /* usage tests must precede field tests */
++ if (WACOM_BATTERY_USAGE(usage))
++ wacom_wac_battery_usage_mapping(hdev, field, usage);
++ else if (WACOM_PAD_FIELD(field))
+ wacom_wac_pad_usage_mapping(hdev, field, usage);
+ else if (WACOM_PEN_FIELD(field))
+ wacom_wac_pen_usage_mapping(hdev, field, usage);
+@@ -2432,11 +2449,12 @@ void wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
+ if (value > field->logical_maximum || value < field->logical_minimum)
+ return;
+
+- if (WACOM_PAD_FIELD(field)) {
+- wacom_wac_pad_battery_event(hdev, field, usage, value);
+- if (wacom->wacom_wac.pad_input)
+- wacom_wac_pad_event(hdev, field, usage, value);
+- } else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
++ /* usage tests must precede field tests */
++ if (WACOM_BATTERY_USAGE(usage))
++ wacom_wac_battery_event(hdev, field, usage, value);
++ else if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
++ wacom_wac_pad_event(hdev, field, usage, value);
++ else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
+ wacom_wac_pen_event(hdev, field, usage, value);
+ else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
+ wacom_wac_finger_event(hdev, field, usage, value);
+@@ -2470,6 +2488,8 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
+ if (wacom_wac->features.type != HID_GENERIC)
+ return;
+
++ wacom_wac_battery_pre_report(hdev, report);
++
+ if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
+ wacom_wac_pad_pre_report(hdev, report);
+ else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
+@@ -2489,11 +2509,11 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
+ if (report->type != HID_INPUT_REPORT)
+ return;
+
+- if (WACOM_PAD_FIELD(field)) {
+- wacom_wac_pad_battery_report(hdev, report);
+- if (wacom->wacom_wac.pad_input)
+- wacom_wac_pad_report(hdev, report);
+- } else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
++ wacom_wac_battery_report(hdev, report);
++
++ if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
++ wacom_wac_pad_report(hdev, report);
++ else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
+ wacom_wac_pen_report(hdev, report);
+ else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
+ wacom_wac_finger_report(hdev, report);
+diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
+index 1824b530bcb5..8a03654048bf 100644
+--- a/drivers/hid/wacom_wac.h
++++ b/drivers/hid/wacom_wac.h
+@@ -153,6 +153,10 @@
+ #define WACOM_HID_WT_X (WACOM_HID_UP_WACOMTOUCH | 0x130)
+ #define WACOM_HID_WT_Y (WACOM_HID_UP_WACOMTOUCH | 0x131)
+
++#define WACOM_BATTERY_USAGE(f) (((f)->hid == HID_DG_BATTERYSTRENGTH) || \
++ ((f)->hid == WACOM_HID_WD_BATTERY_CHARGING) || \
++ ((f)->hid == WACOM_HID_WD_BATTERY_LEVEL))
++
+ #define WACOM_PAD_FIELD(f) (((f)->physical == HID_DG_TABLETFUNCTIONKEY) || \
+ ((f)->physical == WACOM_HID_WD_DIGITIZERFNKEYS) || \
+ ((f)->physical == WACOM_HID_WD_DIGITIZERINFO))
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-generic-Report-AES-battery-information.patch b/patches.drivers/HID-wacom-generic-Report-AES-battery-information.patch
new file mode 100644
index 0000000000..edbf2cf975
--- /dev/null
+++ b/patches.drivers/HID-wacom-generic-Report-AES-battery-information.patch
@@ -0,0 +1,37 @@
+From a7758702879e68d221cf6dd9844bf5b2a070c8cb Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Fri, 28 Apr 2017 09:25:32 -0700
+Subject: [PATCH] HID: wacom: generic: Report AES battery information
+Git-commit: a7758702879e68d221cf6dd9844bf5b2a070c8cb
+Patch-mainline: v4.13-rc1
+References: bsc#1051510
+
+When support for the HID_DG_BATTERYSTRENGTH usage was added for AES devices,
+it appears that the value was read, but never actually forwarded to the
+power_supply subystem for userspace's benefit. Let's correct that.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 70a9e47b215a..3e034506778f 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2177,6 +2177,8 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
+ input_sync(input);
+ }
+
++ wacom_wac_pad_battery_report(hdev, report);
++
+ if (!prox) {
+ wacom_wac->tool[0] = 0;
+ wacom_wac->id[0] = 0;
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-generic-Reset-events-back-to-zero-when-pen.patch b/patches.drivers/HID-wacom-generic-Reset-events-back-to-zero-when-pen.patch
new file mode 100644
index 0000000000..72ff79d2cc
--- /dev/null
+++ b/patches.drivers/HID-wacom-generic-Reset-events-back-to-zero-when-pen.patch
@@ -0,0 +1,43 @@
+From 5b40104edfb003b1e8bae3e546771e6edb59c6b7 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Thu, 7 Sep 2017 17:52:15 -0700
+Subject: [PATCH] HID: wacom: generic: Reset events back to zero when pen leaves
+Git-commit: 5b40104edfb003b1e8bae3e546771e6edb59c6b7
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+As a pen leaves, we need to be sure to reset all events back to zero
+so that userspace is able to get the complete pen state when it enters
+proximity again.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 929a1ceabc21..2926e36cb684 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2218,10 +2218,10 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
+ return;
+
+ /* send pen events only when the pen is in range */
+- if (!wacom_wac->hid_data.inrange_state)
+- return;
+-
+- input_event(input, usage->type, usage->code, value);
++ if (wacom_wac->hid_data.inrange_state)
++ input_event(input, usage->type, usage->code, value);
++ else if (wacom_wac->shared->stylus_in_proximity && !wacom_wac->hid_data.sense_state)
++ input_event(input, usage->type, usage->code, 0);
+ }
+
+ static void wacom_wac_pen_pre_report(struct hid_device *hdev,
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-generic-Scale-battery-capacity-measurement.patch b/patches.drivers/HID-wacom-generic-Scale-battery-capacity-measurement.patch
new file mode 100644
index 0000000000..569a86e005
--- /dev/null
+++ b/patches.drivers/HID-wacom-generic-Scale-battery-capacity-measurement.patch
@@ -0,0 +1,46 @@
+From 37d1601938349e79e9c31a8aba431d5543e09e72 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Fri, 28 Apr 2017 09:25:30 -0700
+Subject: [PATCH] HID: wacom: generic: Scale battery capacity measurements to percentages
+Git-commit: 37d1601938349e79e9c31a8aba431d5543e09e72
+Patch-mainline: v4.13-rc1
+References: bsc#1051510
+
+The power_supply subsystem expects us to provide it with capacity values
+measured in percent. In particular, AES devices (HID_DG_BATTERYSTRENGTH)
+use the range 0-255, which needs to be rescaled. The MobileStudio Pro
+(WACOM_HID_WD_BATTERY_LEVEL) uses the range 0-100, but there's no guarantee
+that future devices will share the same range.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 4b225fb19a16..fd989e09ae2d 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1811,6 +1811,7 @@ static void wacom_wac_pad_battery_event(struct hid_device *hdev, struct hid_fiel
+
+ switch (equivalent_usage) {
+ case WACOM_HID_WD_BATTERY_LEVEL:
++ value = value * 100 / (field->logical_maximum - field->logical_minimum);
+ wacom_wac->hid_data.battery_capacity = value;
+ wacom_wac->hid_data.bat_connected = 1;
+ break;
+@@ -2035,6 +2036,7 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
+ wacom_wac->hid_data.sense_state = value;
+ return;
+ case HID_DG_BATTERYSTRENGTH:
++ value = value * 100 / (field->logical_maximum - field->logical_minimum);
+ wacom_wac->hid_data.battery_capacity = value;
+ wacom_wac->hid_data.bat_connected = 1;
+ break;
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-generic-Send-BTN_STYLUS3-when-both-barrel-.patch b/patches.drivers/HID-wacom-generic-Send-BTN_STYLUS3-when-both-barrel-.patch
new file mode 100644
index 0000000000..db5ddfed4d
--- /dev/null
+++ b/patches.drivers/HID-wacom-generic-Send-BTN_STYLUS3-when-both-barrel-.patch
@@ -0,0 +1,109 @@
+From 9e429d564926d3bca49907fa03031da705ad6f2c Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Tue, 7 Nov 2017 08:25:17 -0800
+Subject: [PATCH] HID: wacom: generic: Send BTN_STYLUS3 when both barrel switches are set
+Git-commit: 9e429d564926d3bca49907fa03031da705ad6f2c
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+The Wacom Pro Pen 3D includes a third barrel switch which is intended to
+be particularly useful in applications where one frequency uses pan, zoom,
+and rotate to navigate around a scene or model. The pen is compatible with
+the MobileStudio Pro, 2nd-gen Intuos Pro, and Cintiq Pro. When the third
+button is pressed, these devices set both the HID_DG_BARRELSWITCH and
+HID_DG_BARRELSWITCH2 usages since their HID descriptors do not include a
+usage specific to the button.
+
+Rather than send both BTN_STYLUS and BTN_STYLUS2 when the third button is
+pressed, userspace (libinput) has requested that we detect this condition
+and report a newly-defined BTN_STYLUS3 event instead. We could define a
+quirk specific to devices compatible with the Pro Pen 3D, but the liklihood
+of seeing both barrel switch bits set with other pens/devices is low enough
+to not worry about (pens mechanically prevent accidental activation of
+multiple switches).
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Acked-by: Peter Hutterer <peter.hutterer@who-t.net>
+Acked-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 18 ++++++++++++++++--
+ drivers/hid/wacom_wac.h | 2 ++
+ include/uapi/linux/input-event-codes.h | 1 +
+ 3 files changed, 19 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index e3223b0c4f90..16af6886e828 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2140,6 +2140,12 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
+ case HID_DG_TIPSWITCH:
+ wacom_wac->hid_data.tipswitch |= value;
+ return;
++ case HID_DG_BARRELSWITCH:
++ wacom_wac->hid_data.barrelswitch = value;
++ return;
++ case HID_DG_BARRELSWITCH2:
++ wacom_wac->hid_data.barrelswitch2 = value;
++ return;
+ case HID_DG_TOOLSERIALNUMBER:
+ if (value) {
+ wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL);
+@@ -2254,6 +2260,12 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
+
+ if (!delay_pen_events(wacom_wac) && wacom_wac->tool[0]) {
+ int id = wacom_wac->id[0];
++ int sw_state = wacom_wac->hid_data.barrelswitch |
++ (wacom_wac->hid_data.barrelswitch2 << 1);
++
++ input_report_key(input, BTN_STYLUS, sw_state == 1);
++ input_report_key(input, BTN_STYLUS2, sw_state == 2);
++ input_report_key(input, BTN_STYLUS3, sw_state == 3);
+
+ /*
+ * Non-USI EMR tools should have their IDs mangled to
+@@ -3300,9 +3312,11 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
+ else
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
+- if (features->type == HID_GENERIC)
+- /* setup has already been done */
++ if (features->type == HID_GENERIC) {
++ /* setup has already been done; apply otherwise-undetectible quirks */
++ input_set_capability(input_dev, EV_KEY, BTN_STYLUS3);
+ return 0;
++ }
+
+ __set_bit(BTN_TOUCH, input_dev->keybit);
+ __set_bit(ABS_MISC, input_dev->absbit);
+diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
+index 8a03654048bf..69dda27e8dde 100644
+--- a/drivers/hid/wacom_wac.h
++++ b/drivers/hid/wacom_wac.h
+@@ -291,6 +291,8 @@ struct hid_data {
+ bool inrange_state;
+ bool invert_state;
+ bool tipswitch;
++ bool barrelswitch;
++ bool barrelswitch2;
+ int x;
+ int y;
+ int pressure;
+diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
+index 179891074b3c..9b3a522f50d1 100644
+--- a/include/uapi/linux/input-event-codes.h
++++ b/include/uapi/linux/input-event-codes.h
+@@ -406,6 +406,7 @@
+ #define BTN_TOOL_MOUSE 0x146
+ #define BTN_TOOL_LENS 0x147
+ #define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */
++#define BTN_STYLUS3 0x149
+ #define BTN_TOUCH 0x14a
+ #define BTN_STYLUS 0x14b
+ #define BTN_STYLUS2 0x14c
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-generic-Send-BTN_TOOL_PEN-in-prox-once-the.patch b/patches.drivers/HID-wacom-generic-Send-BTN_TOOL_PEN-in-prox-once-the.patch
new file mode 100644
index 0000000000..cf4b641b35
--- /dev/null
+++ b/patches.drivers/HID-wacom-generic-Send-BTN_TOOL_PEN-in-prox-once-the.patch
@@ -0,0 +1,50 @@
+From 3e70969e44ee52d72053145dab2cbad74109c685 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Thu, 7 Sep 2017 17:51:06 -0700
+Subject: [PATCH] HID: wacom: generic: Send BTN_TOOL_PEN in prox once the pen enters range
+Git-commit: 3e70969e44ee52d72053145dab2cbad74109c685
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+When a pen is first able to to be sensed by the tablet, we would like
+to inform userspace that a tool is nearby so that it can attempt to
+perform palm rejection. Unfortunately, we don't know any information
+about the tool that is nearby, so the best we can do is send a prox
+event for a generic BTN_TOOL_PEN. If the pen later comes closer and
+enters proximity, we can determine the actual tool type and send
+BTN_TOOL_PEN out of prox if necessary.
+
+Signed-off-by: Ping Cheng <ping.cheng@wacom.com>
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 9b3a247ee552..929a1ceabc21 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2247,6 +2247,17 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
+ wacom_wac->tool[0] = wacom_intuos_get_tool_type(wacom_wac->id[0]);
+ else
+ wacom_wac->tool[0] = BTN_TOOL_PEN;
++
++ if (wacom_wac->shared->stylus_in_proximity &&
++ wacom_wac->tool[0] != BTN_TOOL_PEN) {
++ input_report_key(input, BTN_TOOL_PEN, 0);
++ input_sync(input);
++ }
++ }
++ else if (!wacom_wac->tool[0] && !range) { /* entering in sense */
++ input_report_key(input, BTN_TOOL_PEN, sense);
++ input_report_key(input, BTN_TOUCH, 0);
++ input_sync(input);
+ }
+
+ /* keep pen state for touch events */
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-generic-Support-multiple-tools-per-report.patch b/patches.drivers/HID-wacom-generic-Support-multiple-tools-per-report.patch
new file mode 100644
index 0000000000..870b31b3a4
--- /dev/null
+++ b/patches.drivers/HID-wacom-generic-Support-multiple-tools-per-report.patch
@@ -0,0 +1,179 @@
+From f8b6a74719b5e003e28b2deb7ef91d7158333cbf Mon Sep 17 00:00:00 2001
+From: Aaron Armstrong Skomra <skomra@gmail.com>
+Date: Tue, 6 Mar 2018 10:48:34 -0800
+Subject: [PATCH] HID: wacom: generic: Support multiple tools per report
+Git-commit: f8b6a74719b5e003e28b2deb7ef91d7158333cbf
+Patch-mainline: v4.17-rc1
+References: bsc#1051510
+
+Some Wacom devices contain contain Pen and Pad usages in
+the same report. Future devices of this type may utilize
+HID Descriptors.
+
+The generic code path of the Wacom driver previously
+assumed pen, touch, and pad reports were delivered in
+separate reports. This patch adds support for processing
+each collection of a report separately, in order to support
+reports with multiple tools.
+
+Signed-off-by: Aaron Armstrong Skomra <skomra@gmail.com>
+Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
+Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 94 +++++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 68 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index d532c1ebf2ee..7a0a7f67e7ed 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2072,7 +2072,7 @@ static void wacom_wac_pad_pre_report(struct hid_device *hdev,
+ }
+
+ static void wacom_wac_pad_report(struct hid_device *hdev,
+- struct hid_report *report)
++ struct hid_report *report, struct hid_field *field)
+ {
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+@@ -2080,7 +2080,7 @@ static void wacom_wac_pad_report(struct hid_device *hdev,
+ bool active = wacom_wac->hid_data.inrange_state != 0;
+
+ /* report prox for expresskey events */
+- if ((wacom_equivalent_usage(report->field[0]->physical) == HID_DG_TABLETFUNCTIONKEY) &&
++ if ((wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) &&
+ wacom_wac->hid_data.pad_input_event_flag) {
+ input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
+ input_sync(input);
+@@ -2627,11 +2627,13 @@ void wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
+ wacom_wac_finger_event(hdev, field, usage, value);
+ }
+
+-static void wacom_report_events(struct hid_device *hdev, struct hid_report *report)
++static void wacom_report_events(struct hid_device *hdev,
++ struct hid_report *report, int collection_index,
++ int field_index)
+ {
+ int r;
+
+- for (r = 0; r < report->maxfield; r++) {
++ for (r = field_index; r < report->maxfield; r++) {
+ struct hid_field *field;
+ unsigned count, n;
+
+@@ -2641,30 +2643,23 @@ static void wacom_report_events(struct hid_device *hdev, struct hid_report *repo
+ if (!(HID_MAIN_ITEM_VARIABLE & field->flags))
+ continue;
+
+- for (n = 0; n < count; n++)
+- wacom_wac_event(hdev, field, &field->usage[n], field->value[n]);
++ for (n = 0 ; n < count; n++) {
++ if (field->usage[n].collection_index == collection_index)
++ wacom_wac_event(hdev, field, &field->usage[n],
++ field->value[n]);
++ else
++ return;
++ }
+ }
+ }
+
+-void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
++int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report,
++ int collection_index, struct hid_field *field,
++ int field_index)
+ {
+ struct wacom *wacom = hid_get_drvdata(hdev);
+- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+- struct hid_field *field = report->field[0];
+-
+- if (wacom_wac->features.type != HID_GENERIC)
+- return;
+-
+- wacom_wac_battery_pre_report(hdev, report);
+-
+- if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
+- wacom_wac_pad_pre_report(hdev, report);
+- else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
+- wacom_wac_pen_pre_report(hdev, report);
+- else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
+- wacom_wac_finger_pre_report(hdev, report);
+
+- wacom_report_events(hdev, report);
++ wacom_report_events(hdev, report, collection_index, field_index);
+
+ /*
+ * Non-input reports may be sent prior to the device being
+@@ -2674,16 +2669,63 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
+ * processing functions.
+ */
+ if (report->type != HID_INPUT_REPORT)
+- return;
+-
+- wacom_wac_battery_report(hdev, report);
++ return -1;
+
+ if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
+- wacom_wac_pad_report(hdev, report);
++ wacom_wac_pad_report(hdev, report, field);
+ else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
+ wacom_wac_pen_report(hdev, report);
+ else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
+ wacom_wac_finger_report(hdev, report);
++
++ return 0;
++}
++
++void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
++{
++ struct wacom *wacom = hid_get_drvdata(hdev);
++ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
++ struct hid_field *field;
++ bool pad_in_hid_field = false, pen_in_hid_field = false,
++ finger_in_hid_field = false;
++ int r;
++ int prev_collection = -1;
++
++ if (wacom_wac->features.type != HID_GENERIC)
++ return;
++
++ for (r = 0; r < report->maxfield; r++) {
++ field = report->field[r];
++
++ if (WACOM_PAD_FIELD(field))
++ pad_in_hid_field = true;
++ if (WACOM_PEN_FIELD(field))
++ pen_in_hid_field = true;
++ if (WACOM_FINGER_FIELD(field))
++ finger_in_hid_field = true;
++ }
++
++ wacom_wac_battery_pre_report(hdev, report);
++
++ if (pad_in_hid_field && wacom->wacom_wac.pad_input)
++ wacom_wac_pad_pre_report(hdev, report);
++ if (pen_in_hid_field && wacom->wacom_wac.pen_input)
++ wacom_wac_pen_pre_report(hdev, report);
++ if (finger_in_hid_field && wacom->wacom_wac.touch_input)
++ wacom_wac_finger_pre_report(hdev, report);
++
++ for (r = 0; r < report->maxfield; r++) {
++ field = report->field[r];
++
++ if (field->usage[0].collection_index != prev_collection) {
++ if (wacom_wac_collection(hdev, report,
++ field->usage[0].collection_index, field, r) < 0)
++ return;
++ prev_collection = field->usage[0].collection_index;
++ }
++ }
++
++ wacom_wac_battery_report(hdev, report);
+ }
+
+ static int wacom_bpt_touch(struct wacom_wac *wacom)
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-generic-Use-generic-codepath-terminology-i.patch b/patches.drivers/HID-wacom-generic-Use-generic-codepath-terminology-i.patch
new file mode 100644
index 0000000000..a0821030c0
--- /dev/null
+++ b/patches.drivers/HID-wacom-generic-Use-generic-codepath-terminology-i.patch
@@ -0,0 +1,87 @@
+From 7690dd18ddeda98521f4966e60e1a70b97316d11 Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Thu, 7 Sep 2017 17:48:55 -0700
+Subject: [PATCH] HID: wacom: generic: Use generic codepath terminology in wacom_wac_pen_report
+Git-commit: 7690dd18ddeda98521f4966e60e1a70b97316d11
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+The terminology used to describe the various degrees of pen proximity
+within the wacom_wac_pen_report function does not match that used elsewhere
+in the generic codepath. Specifically, the names of the variables "prox"
+and "range" were inspired by the non-generic codepaths. To make the generic
+codepath internally consistent, replace these terms with "range" and "sense"
+respectively.
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Ping Cheng <ping.cheng@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index aa692e28b2cd..cdf95e1999d1 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2217,7 +2217,7 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
+ if (!usage->type || delay_pen_events(wacom_wac))
+ return;
+
+- /* send pen events only when the pen is in/entering/leaving proximity */
++ /* send pen events only when the pen is in/entering/leaving range */
+ if (!wacom_wac->hid_data.inrange_state && !wacom_wac->tool[0])
+ return;
+
+@@ -2236,11 +2236,11 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct input_dev *input = wacom_wac->pen_input;
+- bool prox = wacom_wac->hid_data.inrange_state;
+- bool range = wacom_wac->hid_data.sense_state;
++ bool range = wacom_wac->hid_data.inrange_state;
++ bool sense = wacom_wac->hid_data.sense_state;
+
+- if (!wacom_wac->tool[0] && prox) { /* first in prox */
+- /* Going into proximity select tool */
++ if (!wacom_wac->tool[0] && range) { /* first in range */
++ /* Going into range select tool */
+ if (wacom_wac->hid_data.invert_state)
+ wacom_wac->tool[0] = BTN_TOOL_RUBBER;
+ else if (wacom_wac->id[0])
+@@ -2250,7 +2250,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
+ }
+
+ /* keep pen state for touch events */
+- wacom_wac->shared->stylus_in_proximity = range;
++ wacom_wac->shared->stylus_in_proximity = sense;
+
+ if (!delay_pen_events(wacom_wac) && wacom_wac->tool[0]) {
+ int id = wacom_wac->id[0];
+@@ -2269,10 +2269,10 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
+ */
+ input_report_key(input, BTN_TOUCH,
+ wacom_wac->hid_data.tipswitch);
+- input_report_key(input, wacom_wac->tool[0], prox);
++ input_report_key(input, wacom_wac->tool[0], range);
+ if (wacom_wac->serial[0]) {
+ input_event(input, EV_MSC, MSC_SERIAL, wacom_wac->serial[0]);
+- input_report_abs(input, ABS_MISC, prox ? id : 0);
++ input_report_abs(input, ABS_MISC, range ? id : 0);
+ }
+
+ wacom_wac->hid_data.tipswitch = false;
+@@ -2280,7 +2280,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
+ input_sync(input);
+ }
+
+- if (!prox) {
++ if (!range) {
+ wacom_wac->tool[0] = 0;
+ wacom_wac->id[0] = 0;
+ wacom_wac->serial[0] = 0;
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-generic-add-the-Report-Valid-usage.patch b/patches.drivers/HID-wacom-generic-add-the-Report-Valid-usage.patch
new file mode 100644
index 0000000000..e2b71ef17d
--- /dev/null
+++ b/patches.drivers/HID-wacom-generic-add-the-Report-Valid-usage.patch
@@ -0,0 +1,104 @@
+From b1f466a90c516d54bd8bea7fb142a807d7800304 Mon Sep 17 00:00:00 2001
+From: Aaron Armstrong Skomra <skomra@gmail.com>
+Date: Tue, 6 Mar 2018 10:48:35 -0800
+Subject: [PATCH] HID: wacom: generic: add the "Report Valid" usage
+Git-commit: b1f466a90c516d54bd8bea7fb142a807d7800304
+Patch-mainline: v4.17-rc1
+References: bsc#1051510
+
+Wacom Bluetooth reports contain multiple pen frames per report.
+Each frame contains a flag indicating if the frame is valid.
+Future Wacom devices with this type of report may contain HID
+descriptors, add support for this usage to the generic codepath
+of the Wacom driver.
+
+Signed-off-by: Aaron Armstrong Skomra <skomra@gmail.com>
+Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
+Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 16 +++++++++++++++-
+ drivers/hid/wacom_wac.h | 3 ++-
+ 2 files changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 7a0a7f67e7ed..afa8c9f24a42 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1715,7 +1715,8 @@ int wacom_equivalent_usage(int usage)
+ usage == WACOM_HID_WD_TOUCHSTRIP ||
+ usage == WACOM_HID_WD_TOUCHSTRIP2 ||
+ usage == WACOM_HID_WD_TOUCHRING ||
+- usage == WACOM_HID_WD_TOUCHRINGSTATUS) {
++ usage == WACOM_HID_WD_TOUCHRINGSTATUS ||
++ usage == WACOM_HID_WD_REPORT_VALID) {
+ return usage;
+ }
+
+@@ -2199,6 +2200,9 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
+ struct input_dev *input = wacom_wac->pen_input;
+ unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
+
++ if (wacom_wac->is_invalid_bt_frame)
++ return;
++
+ switch (equivalent_usage) {
+ case HID_GD_Z:
+ /*
+@@ -2295,6 +2299,9 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
+ features->offset_bottom);
+ features->offset_bottom = value;
+ return;
++ case WACOM_HID_WD_REPORT_VALID:
++ wacom_wac->is_invalid_bt_frame = !value;
++ return;
+ }
+
+ /* send pen events only when touch is up or forced out
+@@ -2313,6 +2320,10 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
+ static void wacom_wac_pen_pre_report(struct hid_device *hdev,
+ struct hid_report *report)
+ {
++ struct wacom *wacom = hid_get_drvdata(hdev);
++ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
++
++ wacom_wac->is_invalid_bt_frame = false;
+ return;
+ }
+
+@@ -2325,6 +2336,9 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
+ bool range = wacom_wac->hid_data.inrange_state;
+ bool sense = wacom_wac->hid_data.sense_state;
+
++ if (wacom_wac->is_invalid_bt_frame)
++ return;
++
+ if (!wacom_wac->tool[0] && range) { /* first in range */
+ /* Going into range select tool */
+ if (wacom_wac->hid_data.invert_state)
+diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
+index 827d8fc4a3f2..295fd3718caa 100644
+--- a/drivers/hid/wacom_wac.h
++++ b/drivers/hid/wacom_wac.h
+@@ -118,6 +118,7 @@
+ #define WACOM_HID_WD_TOUCHSTRIP2 (WACOM_HID_UP_WACOMDIGITIZER | 0x0137)
+ #define WACOM_HID_WD_TOUCHRING (WACOM_HID_UP_WACOMDIGITIZER | 0x0138)
+ #define WACOM_HID_WD_TOUCHRINGSTATUS (WACOM_HID_UP_WACOMDIGITIZER | 0x0139)
++#define WACOM_HID_WD_REPORT_VALID (WACOM_HID_UP_WACOMDIGITIZER | 0x01d0)
+ #define WACOM_HID_WD_ACCELEROMETER_X (WACOM_HID_UP_WACOMDIGITIZER | 0x0401)
+ #define WACOM_HID_WD_ACCELEROMETER_Y (WACOM_HID_UP_WACOMDIGITIZER | 0x0402)
+ #define WACOM_HID_WD_ACCELEROMETER_Z (WACOM_HID_UP_WACOMDIGITIZER | 0x0403)
+@@ -353,7 +354,7 @@ struct wacom_wac {
+ bool has_mute_touch_switch;
+ bool has_mode_change;
+ bool is_direct_mode;
+-
++ bool is_invalid_bt_frame;
+ };
+
+ #endif
+--
+2.16.4
+
diff --git a/patches.drivers/HID-wacom-wacom_wac_collection-is-local-to-wacom_wac.patch b/patches.drivers/HID-wacom-wacom_wac_collection-is-local-to-wacom_wac.patch
new file mode 100644
index 0000000000..8037b2805a
--- /dev/null
+++ b/patches.drivers/HID-wacom-wacom_wac_collection-is-local-to-wacom_wac.patch
@@ -0,0 +1,33 @@
+From 7ba8fc0904e3cdfe5b02aaf6fa8fcdb76ad67b0f Mon Sep 17 00:00:00 2001
+From: Jiri Kosina <jkosina@suse.cz>
+Date: Wed, 7 Mar 2018 15:34:51 +0100
+Subject: [PATCH] HID: wacom: wacom_wac_collection() is local to wacom_wac.c
+Git-commit: 7ba8fc0904e3cdfe5b02aaf6fa8fcdb76ad67b0f
+Patch-mainline: v4.17-rc1
+References: bsc#1051510
+
+... and therefore should be static.
+
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index afa8c9f24a42..6da16a879c9f 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2667,7 +2667,7 @@ static void wacom_report_events(struct hid_device *hdev,
+ }
+ }
+
+-int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report,
++static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report,
+ int collection_index, struct hid_field *field,
+ int field_index)
+ {
+--
+2.16.4
+
diff --git a/patches.drivers/PM-core-Propagate-dev-power.wakeup_path-when-no-call.patch b/patches.drivers/PM-core-Propagate-dev-power.wakeup_path-when-no-call.patch
new file mode 100644
index 0000000000..692d809ad0
--- /dev/null
+++ b/patches.drivers/PM-core-Propagate-dev-power.wakeup_path-when-no-call.patch
@@ -0,0 +1,50 @@
+From dc351d4c5f4fe4d0f274d6d660227be0c3a03317 Mon Sep 17 00:00:00 2001
+From: Ulf Hansson <ulf.hansson@linaro.org>
+Date: Wed, 10 Apr 2019 11:55:16 +0200
+Subject: [PATCH] PM / core: Propagate dev->power.wakeup_path when no callbacks
+Git-commit: dc351d4c5f4fe4d0f274d6d660227be0c3a03317
+Patch-mainline: v5.2-rc1
+References: bsc#1051510
+
+The dev->power.direct_complete flag may become set in device_prepare() in
+case the device don't have any PM callbacks (dev->power.no_pm_callbacks is
+set). This leads to a broken behaviour, when there is child having wakeup
+enabled and relies on its parent to be used in the wakeup path.
+
+More precisely, when the direct complete path becomes selected for the
+child in __device_suspend(), the propagation of the dev->power.wakeup_path
+becomes skipped as well.
+
+Let's address this problem, by checking if the device is a part the wakeup
+path or has wakeup enabled, then prevent the direct complete path from
+being used.
+
+Reported-by: Loic Pallardy <loic.pallardy@st.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+[ rjw: Comment cleanup ]
+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/base/power/main.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
+index 9b8c829798f1..43e863cc0c1b 100644
+--- a/drivers/base/power/main.c
++++ b/drivers/base/power/main.c
+@@ -1736,6 +1736,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
+ if (dev->power.syscore)
+ goto Complete;
+
++ /* Avoid direct_complete to let wakeup_path propagate. */
++ if (device_may_wakeup(dev) || dev->power.wakeup_path)
++ dev->power.direct_complete = false;
++
+ if (dev->power.direct_complete) {
+ if (pm_runtime_status_suspended(dev)) {
+ pm_runtime_disable(dev);
+--
+2.16.4
+
diff --git a/patches.drivers/Revert-ALSA-hda-realtek-Improve-the-headset-mic-for-.patch b/patches.drivers/Revert-ALSA-hda-realtek-Improve-the-headset-mic-for-.patch
new file mode 100644
index 0000000000..c7c226e3ad
--- /dev/null
+++ b/patches.drivers/Revert-ALSA-hda-realtek-Improve-the-headset-mic-for-.patch
@@ -0,0 +1,62 @@
+From 17d304604a88cf20c8dfd2c95d3decb9c4f8bca4 Mon Sep 17 00:00:00 2001
+From: Hui Wang <hui.wang@canonical.com>
+Date: Fri, 14 Jun 2019 16:44:12 +0800
+Subject: [PATCH] Revert "ALSA: hda/realtek - Improve the headset mic for Acer Aspire laptops"
+Git-commit: 17d304604a88cf20c8dfd2c95d3decb9c4f8bca4
+Patch-mainline: v5.2-rc5
+References: bsc#1051510
+
+This reverts commit 9cb40eb184c4220d244a532bd940c6345ad9dbd9.
+
+This patch introduces noise and headphone playback issue after
+rebooting or suspending/resuming. Let us revert it.
+
+Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=203831
+Fixes: 9cb40eb184c4 ("ALSA: hda/realtek - Improve the headset mic for Acer Aspire laptops")
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Hui Wang <hui.wang@canonical.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ sound/pci/hda/patch_realtek.c | 16 +++++-----------
+ 1 file changed, 5 insertions(+), 11 deletions(-)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 1afb268f3da0..179e4be1f747 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -6268,15 +6268,13 @@ static const struct hda_fixup alc269_fixups[] = {
+ .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
+ },
+ [ALC255_FIXUP_ACER_MIC_NO_PRESENCE] = {
+- .type = HDA_FIXUP_VERBS,
+- .v.verbs = (const struct hda_verb[]) {
+- /* Enable the Mic */
+- { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 },
+- { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 },
+- {}
++ .type = HDA_FIXUP_PINS,
++ .v.pins = (const struct hda_pintbl[]) {
++ { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
++ { }
+ },
+ .chained = true,
+- .chain_id = ALC269_FIXUP_LIFEBOOK_EXTMIC
++ .chain_id = ALC255_FIXUP_HEADSET_MODE
+ },
+ [ALC255_FIXUP_ASUS_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+@@ -7320,10 +7318,6 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
+ {0x18, 0x02a11030},
+ {0x19, 0x0181303F},
+ {0x21, 0x0221102f}),
+- SND_HDA_PIN_QUIRK(0x10ec0255, 0x1025, "Acer", ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
+- {0x12, 0x90a60140},
+- {0x14, 0x90170120},
+- {0x21, 0x02211030}),
+ SND_HDA_PIN_QUIRK(0x10ec0255, 0x1025, "Acer", ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
+ {0x12, 0x90a601c0},
+ {0x14, 0x90171120},
+--
+2.16.4
+
diff --git a/patches.drivers/Revert-HID-wacom-generic-Send-BTN_TOOL_PEN-in-prox-o.patch b/patches.drivers/Revert-HID-wacom-generic-Send-BTN_TOOL_PEN-in-prox-o.patch
new file mode 100644
index 0000000000..491bc3b329
--- /dev/null
+++ b/patches.drivers/Revert-HID-wacom-generic-Send-BTN_TOOL_PEN-in-prox-o.patch
@@ -0,0 +1,57 @@
+From 2f84723de7cdd031f293b900fecd68ddbec3feaa Mon Sep 17 00:00:00 2001
+From: Jason Gerecke <killertofu@gmail.com>
+Date: Thu, 5 Oct 2017 11:14:02 -0700
+Subject: [PATCH] Revert "HID: wacom: generic: Send BTN_TOOL_PEN in prox once the pen enters range"
+Git-commit: 2f84723de7cdd031f293b900fecd68ddbec3feaa
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+This reverts commit 3e70969e44ee52d72053145dab2cbad74109c685.
+
+This commit causes a few problems for userspace. The most noteworthy are
+problems related to the distinguishing of different pens and pointer jumps
+when entering proximity. Userspace is written with the expectation that a
+pen will provide its tool ID and serial number (if available) in the very
+first in-prox report. By sending BTN_TOOL_PEN when the tablet starts
+communicating rather than waiting until a tool ID/serial number is
+available, userspace ends up treating all pens as being the same and
+lacking a serial number. Similarly, userspace assumes that the first
+report will contain X/Y data, but by marking the pen as being in-prox
+without an X/Y coordinate, userspace ends up warping the pen to the last-
+known X/Y location. As of commit 5b40104edfb0 ("HID: wacom: generic: Reset
+events back to zero when pen leaves") this means warping to (0,0).
+
+Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
+Acked-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/hid/wacom_wac.c | 11 -----------
+ 1 file changed, 11 deletions(-)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 2926e36cb684..e3223b0c4f90 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2247,17 +2247,6 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
+ wacom_wac->tool[0] = wacom_intuos_get_tool_type(wacom_wac->id[0]);
+ else
+ wacom_wac->tool[0] = BTN_TOOL_PEN;
+-
+- if (wacom_wac->shared->stylus_in_proximity &&
+- wacom_wac->tool[0] != BTN_TOOL_PEN) {
+- input_report_key(input, BTN_TOOL_PEN, 0);
+- input_sync(input);
+- }
+- }
+- else if (!wacom_wac->tool[0] && !range) { /* entering in sense */
+- input_report_key(input, BTN_TOOL_PEN, sense);
+- input_report_key(input, BTN_TOUCH, 0);
+- input_sync(input);
+ }
+
+ /* keep pen state for touch events */
+--
+2.16.4
+
diff --git a/patches.arch/cpufreq-amd-ignore-the-check-for-procfeedback-in-st-cz.patch b/patches.drivers/cpufreq-amd-ignore-the-check-for-procfeedback-in-st-cz.patch
index 57f06dc96c..57f06dc96c 100644
--- a/patches.arch/cpufreq-amd-ignore-the-check-for-procfeedback-in-st-cz.patch
+++ b/patches.drivers/cpufreq-amd-ignore-the-check-for-procfeedback-in-st-cz.patch
diff --git a/patches.drivers/dmaengine-Replace-WARN_TAINT_ONCE-with-pr_warn_once.patch b/patches.drivers/dmaengine-Replace-WARN_TAINT_ONCE-with-pr_warn_once.patch
new file mode 100644
index 0000000000..4e0167c3db
--- /dev/null
+++ b/patches.drivers/dmaengine-Replace-WARN_TAINT_ONCE-with-pr_warn_once.patch
@@ -0,0 +1,48 @@
+From 036e9ef8becde736e693be4f4bef56d5b56fc298 Mon Sep 17 00:00:00 2001
+From: Prarit Bhargava <prarit@redhat.com>
+Date: Tue, 13 Jun 2017 12:56:34 -0400
+Subject: [PATCH] dmaengine: Replace WARN_TAINT_ONCE() with pr_warn_once()
+Git-commit: 036e9ef8becde736e693be4f4bef56d5b56fc298
+Patch-mainline: v4.13-rc1
+References: jsc#SLE-5442
+
+The WARN_TAINT_ONCE() prints out a loud stack trace on broken BIOSes.
+The systems that have this problem are several years out of support and
+no longer have BIOS updates available. The stack trace isn't necessary
+and a pr_warn_once() will do.
+
+Change WARN_TAINT_ONCE() to pr_warn_once() and taint.
+
+Signed-off-by: Prarit Bhargava <prarit@redhat.com>
+Cc: Dan Williams <dan.j.williams@intel.com>
+Cc: Vinod Koul <vinod.koul@intel.com>
+Cc: Duyck, Alexander H <alexander.h.duyck@intel.com>
+Signed-off-by: Vinod Koul <vinod.koul@intel.com>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/dma/ioat/dca.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/dma/ioat/dca.c b/drivers/dma/ioat/dca.c
+index 0b9b6b07db9e..eab2fdda29ec 100644
+--- a/drivers/dma/ioat/dca.c
++++ b/drivers/dma/ioat/dca.c
+@@ -336,10 +336,10 @@ struct dca_provider *ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase)
+ }
+
+ if (dca3_tag_map_invalid(ioatdca->tag_map)) {
+- WARN_TAINT_ONCE(1, TAINT_FIRMWARE_WORKAROUND,
+- "%s %s: APICID_TAG_MAP set incorrectly by BIOS, disabling DCA\n",
+- dev_driver_string(&pdev->dev),
+- dev_name(&pdev->dev));
++ add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
++ pr_warn_once("%s %s: APICID_TAG_MAP set incorrectly by BIOS, disabling DCA\n",
++ dev_driver_string(&pdev->dev),
++ dev_name(&pdev->dev));
+ free_dca_provider(dca);
+ return NULL;
+ }
+--
+2.16.4
+
diff --git a/patches.drivers/dmaengine-ioat-constify-pci_device_id.patch b/patches.drivers/dmaengine-ioat-constify-pci_device_id.patch
new file mode 100644
index 0000000000..930ffe8994
--- /dev/null
+++ b/patches.drivers/dmaengine-ioat-constify-pci_device_id.patch
@@ -0,0 +1,44 @@
+From 01fa2fae5a0b0f1c7c7c4afb336fff0278161432 Mon Sep 17 00:00:00 2001
+From: Arvind Yadav <arvind.yadav.cs@gmail.com>
+Date: Mon, 17 Jul 2017 21:39:00 +0530
+Subject: [PATCH] dmaengine: ioat: constify pci_device_id.
+Git-commit: 01fa2fae5a0b0f1c7c7c4afb336fff0278161432
+Patch-mainline: v4.14-rc1
+References: jsc#SLE-5442
+
+pci_device_id are not supposed to change at runtime. All functions
+working with pci_device_id provided by <linux/pci.h> work with
+const pci_device_id. So mark the non-const structs as const.
+
+File size before:
+ text data bss dec hex filename
+ 12582 3056 16 15654 3d26 drivers/dma/ioat/init.o
+
+File size After adding 'const':
+ text data bss dec hex filename
+ 14773 865 16 15654 3d26 drivers/dma/ioat/init.o
+
+Signed-off-by: Arvind Yadav <arvind.yadav.cs@gmail.com>
+Signed-off-by: Vinod Koul <vinod.koul@intel.com>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/dma/ioat/init.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
+index ed8ed1192775..93e006c3441d 100644
+--- a/drivers/dma/ioat/init.c
++++ b/drivers/dma/ioat/init.c
+@@ -39,7 +39,7 @@ MODULE_VERSION(IOAT_DMA_VERSION);
+ MODULE_LICENSE("Dual BSD/GPL");
+ MODULE_AUTHOR("Intel Corporation");
+
+-static struct pci_device_id ioat_pci_tbl[] = {
++static const struct pci_device_id ioat_pci_tbl[] = {
+ /* I/OAT v3 platforms */
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG0) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG1) },
+--
+2.16.4
+
diff --git a/patches.drivers/dmaengine-ioat-don-t-use-DMA_ERROR_CODE.patch b/patches.drivers/dmaengine-ioat-don-t-use-DMA_ERROR_CODE.patch
new file mode 100644
index 0000000000..49a53296be
--- /dev/null
+++ b/patches.drivers/dmaengine-ioat-don-t-use-DMA_ERROR_CODE.patch
@@ -0,0 +1,80 @@
+From e4734b3f5ffc42d821a316383222d71dce7d5c9e Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@lst.de>
+Date: Sun, 21 May 2017 12:54:31 +0200
+Subject: [PATCH] dmaengine: ioat: don't use DMA_ERROR_CODE
+Git-commit: e4734b3f5ffc42d821a316383222d71dce7d5c9e
+Patch-mainline: v4.13-rc1
+References: jsc#SLE-5442
+
+DMA_ERROR_CODE is not a public API and will go away. Instead properly
+unwind based on the loop counter.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Acked-by: Dave Jiang <dave.jiang@intel.com>
+Acked-by: Vinod Koul <vinod.koul@intel.com>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/dma/ioat/init.c | 24 +++++++-----------------
+ 1 file changed, 7 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
+index 6ad4384b3fa8..ed8ed1192775 100644
+--- a/drivers/dma/ioat/init.c
++++ b/drivers/dma/ioat/init.c
+@@ -839,8 +839,6 @@ static int ioat_xor_val_self_test(struct ioatdma_device *ioat_dma)
+ goto free_resources;
+ }
+
+- for (i = 0; i < IOAT_NUM_SRC_TEST; i++)
+- dma_srcs[i] = DMA_ERROR_CODE;
+ for (i = 0; i < IOAT_NUM_SRC_TEST; i++) {
+ dma_srcs[i] = dma_map_page(dev, xor_srcs[i], 0, PAGE_SIZE,
+ DMA_TO_DEVICE);
+@@ -910,8 +908,6 @@ static int ioat_xor_val_self_test(struct ioatdma_device *ioat_dma)
+
+ xor_val_result = 1;
+
+- for (i = 0; i < IOAT_NUM_SRC_TEST + 1; i++)
+- dma_srcs[i] = DMA_ERROR_CODE;
+ for (i = 0; i < IOAT_NUM_SRC_TEST + 1; i++) {
+ dma_srcs[i] = dma_map_page(dev, xor_val_srcs[i], 0, PAGE_SIZE,
+ DMA_TO_DEVICE);
+@@ -965,8 +961,6 @@ static int ioat_xor_val_self_test(struct ioatdma_device *ioat_dma)
+ op = IOAT_OP_XOR_VAL;
+
+ xor_val_result = 0;
+- for (i = 0; i < IOAT_NUM_SRC_TEST + 1; i++)
+- dma_srcs[i] = DMA_ERROR_CODE;
+ for (i = 0; i < IOAT_NUM_SRC_TEST + 1; i++) {
+ dma_srcs[i] = dma_map_page(dev, xor_val_srcs[i], 0, PAGE_SIZE,
+ DMA_TO_DEVICE);
+@@ -1017,18 +1011,14 @@ static int ioat_xor_val_self_test(struct ioatdma_device *ioat_dma)
+ goto free_resources;
+ dma_unmap:
+ if (op == IOAT_OP_XOR) {
+- if (dest_dma != DMA_ERROR_CODE)
+- dma_unmap_page(dev, dest_dma, PAGE_SIZE,
+- DMA_FROM_DEVICE);
+- for (i = 0; i < IOAT_NUM_SRC_TEST; i++)
+- if (dma_srcs[i] != DMA_ERROR_CODE)
+- dma_unmap_page(dev, dma_srcs[i], PAGE_SIZE,
+- DMA_TO_DEVICE);
++ while (--i >= 0)
++ dma_unmap_page(dev, dma_srcs[i], PAGE_SIZE,
++ DMA_TO_DEVICE);
++ dma_unmap_page(dev, dest_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+ } else if (op == IOAT_OP_XOR_VAL) {
+- for (i = 0; i < IOAT_NUM_SRC_TEST + 1; i++)
+- if (dma_srcs[i] != DMA_ERROR_CODE)
+- dma_unmap_page(dev, dma_srcs[i], PAGE_SIZE,
+- DMA_TO_DEVICE);
++ while (--i >= 0)
++ dma_unmap_page(dev, dma_srcs[i], PAGE_SIZE,
++ DMA_TO_DEVICE);
+ }
+ free_resources:
+ dma->device_free_chan_resources(dma_chan);
+--
+2.16.4
+
diff --git a/patches.drivers/dmaengine-ioat-fix-prototype-of-ioat_enumerate_chann.patch b/patches.drivers/dmaengine-ioat-fix-prototype-of-ioat_enumerate_chann.patch
new file mode 100644
index 0000000000..876c9167d2
--- /dev/null
+++ b/patches.drivers/dmaengine-ioat-fix-prototype-of-ioat_enumerate_chann.patch
@@ -0,0 +1,58 @@
+From f4d34aa8c887a8a2d23ef546da0efa10e3f77241 Mon Sep 17 00:00:00 2001
+From: Rami Rosen <ramirose@gmail.com>
+Date: Fri, 5 Oct 2018 00:03:10 +0300
+Subject: [PATCH] dmaengine: ioat: fix prototype of ioat_enumerate_channels
+Git-commit: f4d34aa8c887a8a2d23ef546da0efa10e3f77241
+Patch-mainline: v4.20-rc1
+References: jsc#SLE-5442
+
+Signed-off-by: Rami Rosen <ramirose@gmail.com>
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/dma/ioat/init.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
+index 21a5708985bc..0fec3c554fe3 100644
+--- a/drivers/dma/ioat/init.c
++++ b/drivers/dma/ioat/init.c
+@@ -129,7 +129,7 @@ static void
+ ioat_init_channel(struct ioatdma_device *ioat_dma,
+ struct ioatdma_chan *ioat_chan, int idx);
+ static void ioat_intr_quirk(struct ioatdma_device *ioat_dma);
+-static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma);
++static void ioat_enumerate_channels(struct ioatdma_device *ioat_dma);
+ static int ioat3_dma_self_test(struct ioatdma_device *ioat_dma);
+
+ static int ioat_dca_enabled = 1;
+@@ -575,7 +575,7 @@ static void ioat_dma_remove(struct ioatdma_device *ioat_dma)
+ * ioat_enumerate_channels - find and initialize the device's channels
+ * @ioat_dma: the ioat dma device to be enumerated
+ */
+-static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma)
++static void ioat_enumerate_channels(struct ioatdma_device *ioat_dma)
+ {
+ struct ioatdma_chan *ioat_chan;
+ struct device *dev = &ioat_dma->pdev->dev;
+@@ -594,7 +594,7 @@ static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma)
+ xfercap_log = readb(ioat_dma->reg_base + IOAT_XFERCAP_OFFSET);
+ xfercap_log &= 0x1f; /* bits [4:0] valid */
+ if (xfercap_log == 0)
+- return 0;
++ return;
+ dev_dbg(dev, "%s: xfercap = %d\n", __func__, 1 << xfercap_log);
+
+ for (i = 0; i < dma->chancnt; i++) {
+@@ -611,7 +611,6 @@ static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma)
+ }
+ }
+ dma->chancnt = i;
+- return i;
+ }
+
+ /**
+--
+2.16.4
+
diff --git a/patches.drivers/dmaengine-ioatdma-Add-Snow-Ridge-ioatdma-device-id.patch b/patches.drivers/dmaengine-ioatdma-Add-Snow-Ridge-ioatdma-device-id.patch
new file mode 100644
index 0000000000..a0377409ca
--- /dev/null
+++ b/patches.drivers/dmaengine-ioatdma-Add-Snow-Ridge-ioatdma-device-id.patch
@@ -0,0 +1,65 @@
+From 4d75873f814055359bb6722c4e35a185d02157a8 Mon Sep 17 00:00:00 2001
+From: Dave Jiang <dave.jiang@intel.com>
+Date: Fri, 22 Feb 2019 09:59:54 -0700
+Subject: [PATCH] dmaengine: ioatdma: Add Snow Ridge ioatdma device id
+Git-commit: 4d75873f814055359bb6722c4e35a185d02157a8
+Patch-mainline: v5.1-rc1
+References: jsc#SLE-5442
+
+Add Snowridge Xeon-D ioatdma PCI device id. Also applies for Icelake
+SP Xeon. This introduces ioatdma v3.4 platform. Also bumping driver version
+to 5.0 since we are adding additional code for 3.4 support.
+
+Signed-off-by: Dave Jiang <dave.jiang@intel.com>
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/dma/ioat/dma.h | 2 +-
+ drivers/dma/ioat/hw.h | 2 ++
+ drivers/dma/ioat/init.c | 3 +++
+ 3 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h
+index 1ab42ec2b7ff..aaafd0e882b5 100644
+--- a/drivers/dma/ioat/dma.h
++++ b/drivers/dma/ioat/dma.h
+@@ -27,7 +27,7 @@
+ #include "registers.h"
+ #include "hw.h"
+
+-#define IOAT_DMA_VERSION "4.00"
++#define IOAT_DMA_VERSION "5.00"
+
+ #define IOAT_DMA_DCA_ANY_CPU ~0
+
+diff --git a/drivers/dma/ioat/hw.h b/drivers/dma/ioat/hw.h
+index abcc51b343ce..3e38877cae6b 100644
+--- a/drivers/dma/ioat/hw.h
++++ b/drivers/dma/ioat/hw.h
+@@ -66,6 +66,8 @@
+
+ #define PCI_DEVICE_ID_INTEL_IOAT_SKX 0x2021
+
++#define PCI_DEVICE_ID_INTEL_IOAT_ICX 0x0b00
++
+ #define IOAT_VER_1_2 0x12 /* Version 1.2 */
+ #define IOAT_VER_2_0 0x20 /* Version 2.0 */
+ #define IOAT_VER_3_0 0x30 /* Version 3.0 */
+diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
+index 2d810dfcdc48..3161dfbca505 100644
+--- a/drivers/dma/ioat/init.c
++++ b/drivers/dma/ioat/init.c
+@@ -119,6 +119,9 @@ static const struct pci_device_id ioat_pci_tbl[] = {
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDXDE2) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDXDE3) },
+
++ /* I/OAT v3.4 platforms */
++ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_ICX) },
++
+ { 0, }
+ };
+ MODULE_DEVICE_TABLE(pci, ioat_pci_tbl);
+--
+2.16.4
+
diff --git a/patches.drivers/dmaengine-ioatdma-Add-intr_coalesce-sysfs-entry.patch b/patches.drivers/dmaengine-ioatdma-Add-intr_coalesce-sysfs-entry.patch
new file mode 100644
index 0000000000..393ea09d5e
--- /dev/null
+++ b/patches.drivers/dmaengine-ioatdma-Add-intr_coalesce-sysfs-entry.patch
@@ -0,0 +1,142 @@
+From 268e2519f5b7101d707a0df32e628e9990bc0da6 Mon Sep 17 00:00:00 2001
+From: Ujjal Singh <ujjal.singh@intel.com>
+Date: Tue, 22 Aug 2017 20:31:18 -0400
+Subject: [PATCH] dmaengine: ioatdma: Add intr_coalesce sysfs entry
+Git-commit: 268e2519f5b7101d707a0df32e628e9990bc0da6
+Patch-mainline: v4.14-rc1
+References: jsc#SLE-5442
+
+We observed performance increase with DMA copy from memory
+to MMIO by changing the interrupt coalescing value to 0.
+The previous set value was projected on the C5xxx Xeon
+platform and no longer holds true. Removing hard coded
+value and providing a tune-able in sysfs in order to allow
+user to tune this on a per channel basis. By default this
+value will be set to 0.
+Example of sysfs variable importing for interrupt coalescing
+value from command line:
+echo 5> /sys/devices/pci0000:00/0000:00:04.0/dma/dma0chan0/
+quickdata/intr_coalesce
+
+Reported-by: Nithin Sujir <nsujir@tintri.com>
+Signed-off-by: Ujjal Singh <ujjal.singh@intel.com>
+Acked-by: Dave Jiang <dave.jiang@intel.com>
+Signed-off-by: Vinod Koul <vinod.koul@intel.com>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/dma/ioat/dma.c | 10 +++++++---
+ drivers/dma/ioat/dma.h | 3 +++
+ drivers/dma/ioat/sysfs.c | 42 ++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 52 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
+index a371b07a0981..f70cc74032ea 100644
+--- a/drivers/dma/ioat/dma.c
++++ b/drivers/dma/ioat/dma.c
+@@ -644,9 +644,13 @@ static void __cleanup(struct ioatdma_chan *ioat_chan, dma_addr_t phys_complete)
+ mod_timer(&ioat_chan->timer, jiffies + IDLE_TIMEOUT);
+ }
+
+- /* 5 microsecond delay per pending descriptor */
+- writew(min((5 * (active - i)), IOAT_INTRDELAY_MASK),
+- ioat_chan->ioat_dma->reg_base + IOAT_INTRDELAY_OFFSET);
++ /* microsecond delay by sysfs variable per pending descriptor */
++ if (ioat_chan->intr_coalesce != ioat_chan->prev_intr_coalesce) {
++ writew(min((ioat_chan->intr_coalesce * (active - i)),
++ IOAT_INTRDELAY_MASK),
++ ioat_chan->ioat_dma->reg_base + IOAT_INTRDELAY_OFFSET);
++ ioat_chan->prev_intr_coalesce = ioat_chan->intr_coalesce;
++ }
+ }
+
+ static void ioat_cleanup(struct ioatdma_chan *ioat_chan)
+diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h
+index a9bc1a15b0d1..56200eefcf5e 100644
+--- a/drivers/dma/ioat/dma.h
++++ b/drivers/dma/ioat/dma.h
+@@ -142,11 +142,14 @@ struct ioatdma_chan {
+ spinlock_t prep_lock;
+ struct ioat_descs descs[2];
+ int desc_chunks;
++ int intr_coalesce;
++ int prev_intr_coalesce;
+ };
+
+ struct ioat_sysfs_entry {
+ struct attribute attr;
+ ssize_t (*show)(struct dma_chan *, char *);
++ ssize_t (*store)(struct dma_chan *, const char *, size_t);
+ };
+
+ /**
+diff --git a/drivers/dma/ioat/sysfs.c b/drivers/dma/ioat/sysfs.c
+index cb4a857ee21b..3ac677f29e8f 100644
+--- a/drivers/dma/ioat/sysfs.c
++++ b/drivers/dma/ioat/sysfs.c
+@@ -64,8 +64,24 @@ ioat_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
+ return entry->show(&ioat_chan->dma_chan, page);
+ }
+
++static ssize_t
++ioat_attr_store(struct kobject *kobj, struct attribute *attr,
++const char *page, size_t count)
++{
++ struct ioat_sysfs_entry *entry;
++ struct ioatdma_chan *ioat_chan;
++
++ entry = container_of(attr, struct ioat_sysfs_entry, attr);
++ ioat_chan = container_of(kobj, struct ioatdma_chan, kobj);
++
++ if (!entry->store)
++ return -EIO;
++ return entry->store(&ioat_chan->dma_chan, page, count);
++}
++
+ const struct sysfs_ops ioat_sysfs_ops = {
+ .show = ioat_attr_show,
++ .store = ioat_attr_store,
+ };
+
+ void ioat_kobject_add(struct ioatdma_device *ioat_dma, struct kobj_type *type)
+@@ -121,11 +137,37 @@ static ssize_t ring_active_show(struct dma_chan *c, char *page)
+ }
+ static struct ioat_sysfs_entry ring_active_attr = __ATTR_RO(ring_active);
+
++static ssize_t intr_coalesce_show(struct dma_chan *c, char *page)
++{
++ struct ioatdma_chan *ioat_chan = to_ioat_chan(c);
++
++ return sprintf(page, "%d\n", ioat_chan->intr_coalesce);
++}
++
++static ssize_t intr_coalesce_store(struct dma_chan *c, const char *page,
++size_t count)
++{
++ int intr_coalesce = 0;
++ struct ioatdma_chan *ioat_chan = to_ioat_chan(c);
++
++ if (sscanf(page, "%du", &intr_coalesce) != -1) {
++ if ((intr_coalesce < 0) ||
++ (intr_coalesce > IOAT_INTRDELAY_MASK))
++ return -EINVAL;
++ ioat_chan->intr_coalesce = intr_coalesce;
++ }
++
++ return count;
++}
++
++static struct ioat_sysfs_entry intr_coalesce_attr = __ATTR_RW(intr_coalesce);
++
+ static struct attribute *ioat_attrs[] = {
+ &ring_size_attr.attr,
+ &ring_active_attr.attr,
+ &ioat_cap_attr.attr,
+ &ioat_version_attr.attr,
++ &intr_coalesce_attr.attr,
+ NULL,
+ };
+
+--
+2.16.4
+
diff --git a/patches.drivers/dmaengine-ioatdma-add-descriptor-pre-fetch-support-f.patch b/patches.drivers/dmaengine-ioatdma-add-descriptor-pre-fetch-support-f.patch
new file mode 100644
index 0000000000..88dc5e6d40
--- /dev/null
+++ b/patches.drivers/dmaengine-ioatdma-add-descriptor-pre-fetch-support-f.patch
@@ -0,0 +1,108 @@
+From e0100d40906d5dbe6d09d31083c1a5aaccc947fa Mon Sep 17 00:00:00 2001
+From: Dave Jiang <dave.jiang@intel.com>
+Date: Fri, 22 Feb 2019 10:00:05 -0700
+Subject: [PATCH] dmaengine: ioatdma: add descriptor pre-fetch support for v3.4
+Git-commit: e0100d40906d5dbe6d09d31083c1a5aaccc947fa
+Patch-mainline: v5.1-rc1
+References: jsc#SLE-5442
+
+Adding support for new feature on ioatdma 3.4 hardware that provides
+descriptor pre-fetching in order to reduce small DMA latencies.
+
+Signed-off-by: Dave Jiang <dave.jiang@intel.com>
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/dma/ioat/dma.c | 12 ++++++++++++
+ drivers/dma/ioat/init.c | 8 ++++++--
+ drivers/dma/ioat/registers.h | 10 ++++++++++
+ 3 files changed, 28 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
+index 23fb2fa04000..f373a139e0c3 100644
+--- a/drivers/dma/ioat/dma.c
++++ b/drivers/dma/ioat/dma.c
+@@ -372,6 +372,7 @@ struct ioat_ring_ent **
+ ioat_alloc_ring(struct dma_chan *c, int order, gfp_t flags)
+ {
+ struct ioatdma_chan *ioat_chan = to_ioat_chan(c);
++ struct ioatdma_device *ioat_dma = ioat_chan->ioat_dma;
+ struct ioat_ring_ent **ring;
+ int total_descs = 1 << order;
+ int i, chunks;
+@@ -437,6 +438,17 @@ ioat_alloc_ring(struct dma_chan *c, int order, gfp_t flags)
+ }
+ ring[i]->hw->next = ring[0]->txd.phys;
+
++ /* setup descriptor pre-fetching for v3.4 */
++ if (ioat_dma->cap & IOAT_CAP_DPS) {
++ u16 drsctl = IOAT_CHAN_DRSZ_2MB | IOAT_CHAN_DRS_EN;
++
++ if (chunks == 1)
++ drsctl |= IOAT_CHAN_DRS_AUTOWRAP;
++
++ writew(drsctl, ioat_chan->reg_base + IOAT_CHAN_DRSCTL_OFFSET);
++
++ }
++
+ return ring;
+ }
+
+diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
+index 58dd1bfd3edd..020bcdecb3fb 100644
+--- a/drivers/dma/ioat/init.c
++++ b/drivers/dma/ioat/init.c
+@@ -138,10 +138,10 @@ static int ioat3_dma_self_test(struct ioatdma_device *ioat_dma);
+ static int ioat_dca_enabled = 1;
+ module_param(ioat_dca_enabled, int, 0644);
+ MODULE_PARM_DESC(ioat_dca_enabled, "control support of dca service (default: 1)");
+-int ioat_pending_level = 4;
++int ioat_pending_level = 7;
+ module_param(ioat_pending_level, int, 0644);
+ MODULE_PARM_DESC(ioat_pending_level,
+- "high-water mark for pushing ioat descriptors (default: 4)");
++ "high-water mark for pushing ioat descriptors (default: 7)");
+ static char ioat_interrupt_style[32] = "msix";
+ module_param_string(ioat_interrupt_style, ioat_interrupt_style,
+ sizeof(ioat_interrupt_style), 0644);
+@@ -1188,6 +1188,10 @@ static int ioat3_dma_probe(struct ioatdma_device *ioat_dma, int dca)
+ if (err)
+ return err;
+
++ if (ioat_dma->cap & IOAT_CAP_DPS)
++ writeb(ioat_pending_level + 1,
++ ioat_dma->reg_base + IOAT_PREFETCH_LIMIT_OFFSET);
++
+ return 0;
+ }
+
+diff --git a/drivers/dma/ioat/registers.h b/drivers/dma/ioat/registers.h
+index 2f3bbc88ff2a..2b517d6db5fd 100644
+--- a/drivers/dma/ioat/registers.h
++++ b/drivers/dma/ioat/registers.h
+@@ -84,6 +84,9 @@
+ #define IOAT_CAP_PQ 0x00000200
+ #define IOAT_CAP_DWBES 0x00002000
+ #define IOAT_CAP_RAID16SS 0x00020000
++#define IOAT_CAP_DPS 0x00800000
++
++#define IOAT_PREFETCH_LIMIT_OFFSET 0x4C /* CHWPREFLMT */
+
+ #define IOAT_CHANNEL_MMIO_SIZE 0x80 /* Each Channel MMIO space is this size */
+
+@@ -243,4 +246,11 @@
+
+ #define IOAT_CHANERR_MASK_OFFSET 0x2C /* 32-bit Channel Error Register */
+
++#define IOAT_CHAN_DRSCTL_OFFSET 0xB6
++#define IOAT_CHAN_DRSZ_4KB 0x0000
++#define IOAT_CHAN_DRSZ_8KB 0x0001
++#define IOAT_CHAN_DRSZ_2MB 0x0009
++#define IOAT_CHAN_DRS_EN 0x0100
++#define IOAT_CHAN_DRS_AUTOWRAP 0x0200
++
+ #endif /* _IOAT_REGISTERS_H_ */
+--
+2.16.4
+
diff --git a/patches.drivers/dmaengine-ioatdma-disable-DCA-enabling-on-IOATDMA-v3.patch b/patches.drivers/dmaengine-ioatdma-disable-DCA-enabling-on-IOATDMA-v3.patch
new file mode 100644
index 0000000000..0c0250ae01
--- /dev/null
+++ b/patches.drivers/dmaengine-ioatdma-disable-DCA-enabling-on-IOATDMA-v3.patch
@@ -0,0 +1,47 @@
+From 11e31e281bd8f482a9277268f7b0d9c213584271 Mon Sep 17 00:00:00 2001
+From: Dave Jiang <dave.jiang@intel.com>
+Date: Fri, 22 Feb 2019 09:59:59 -0700
+Subject: [PATCH] dmaengine: ioatdma: disable DCA enabling on IOATDMA v3.4
+Git-commit: 11e31e281bd8f482a9277268f7b0d9c213584271
+Patch-mainline: v5.1-rc1
+References: jsc#SLE-5442
+
+IOATDMA v3.4 does not support DCA. Disable
+
+Signed-off-by: Dave Jiang <dave.jiang@intel.com>
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/dma/ioat/hw.h | 1 +
+ drivers/dma/ioat/init.c | 2 ++
+ 2 files changed, 3 insertions(+)
+
+diff --git a/drivers/dma/ioat/hw.h b/drivers/dma/ioat/hw.h
+index 3e38877cae6b..781c94de8e81 100644
+--- a/drivers/dma/ioat/hw.h
++++ b/drivers/dma/ioat/hw.h
+@@ -73,6 +73,7 @@
+ #define IOAT_VER_3_0 0x30 /* Version 3.0 */
+ #define IOAT_VER_3_2 0x32 /* Version 3.2 */
+ #define IOAT_VER_3_3 0x33 /* Version 3.3 */
++#define IOAT_VER_3_4 0x34 /* Version 3.4 */
+
+
+ int system_has_dca_enabled(struct pci_dev *pdev);
+diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
+index 3161dfbca505..58dd1bfd3edd 100644
+--- a/drivers/dma/ioat/init.c
++++ b/drivers/dma/ioat/init.c
+@@ -1353,6 +1353,8 @@ static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ pci_set_drvdata(pdev, device);
+
+ device->version = readb(device->reg_base + IOAT_VER_OFFSET);
++ if (device->version >= IOAT_VER_3_4)
++ ioat_dca_enabled = 0;
+ if (device->version >= IOAT_VER_3_0) {
+ if (is_skx_ioat(pdev))
+ device->version = IOAT_VER_3_2;
+--
+2.16.4
+
diff --git a/patches.drivers/dmaengine-ioatdma-set-the-completion-address-registe.patch b/patches.drivers/dmaengine-ioatdma-set-the-completion-address-registe.patch
new file mode 100644
index 0000000000..1c90490519
--- /dev/null
+++ b/patches.drivers/dmaengine-ioatdma-set-the-completion-address-registe.patch
@@ -0,0 +1,40 @@
+From 4cb0e60112168594da2ac8a7752b0250c4387733 Mon Sep 17 00:00:00 2001
+From: Dave Jiang <dave.jiang@intel.com>
+Date: Mon, 11 Jun 2018 12:49:03 -0700
+Subject: [PATCH] dmaengine: ioatdma: set the completion address register after channel reset
+Git-commit: 4cb0e60112168594da2ac8a7752b0250c4387733
+Patch-mainline: v4.19-rc1
+References: jsc#SLE-5442
+
+It seems that starting with Skylake Xeon, channel reset clears the
+completion address register. Make sure the completion address register is
+set again after reset.
+
+Signed-off-by: Dave Jiang <dave.jiang@intel.com>
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/dma/ioat/dma.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
+index 8b5b23a8ace9..23fb2fa04000 100644
+--- a/drivers/dma/ioat/dma.c
++++ b/drivers/dma/ioat/dma.c
+@@ -688,6 +688,12 @@ static void ioat_restart_channel(struct ioatdma_chan *ioat_chan)
+ {
+ u64 phys_complete;
+
++ /* set the completion address register again */
++ writel(lower_32_bits(ioat_chan->completion_dma),
++ ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_LOW);
++ writel(upper_32_bits(ioat_chan->completion_dma),
++ ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
++
+ ioat_quiesce(ioat_chan, 0);
+ if (ioat_cleanup_preamble(ioat_chan, &phys_complete))
+ __cleanup(ioat_chan, phys_complete);
+--
+2.16.4
+
diff --git a/patches.drivers/dmaengine-ioatdma-support-latency-tolerance-report-L.patch b/patches.drivers/dmaengine-ioatdma-support-latency-tolerance-report-L.patch
new file mode 100644
index 0000000000..f4ded1ce78
--- /dev/null
+++ b/patches.drivers/dmaengine-ioatdma-support-latency-tolerance-report-L.patch
@@ -0,0 +1,93 @@
+From 528314b503f855b268ae7861ea4e206fbbfb8356 Mon Sep 17 00:00:00 2001
+From: Dave Jiang <dave.jiang@intel.com>
+Date: Fri, 22 Feb 2019 10:00:10 -0700
+Subject: [PATCH] dmaengine: ioatdma: support latency tolerance report (LTR) for v3.4
+Git-commit: 528314b503f855b268ae7861ea4e206fbbfb8356
+Patch-mainline: v5.1-rc1
+References: jsc#SLE-5442
+
+IOATDMA 3.4 supports PCIe LTR mechanism. The registers are non-standard
+PCIe LTR support. This needs to be setup in order to not suffer performance
+impact and provide proper power management. The channel is set to active
+when it is allocated, and to passive when it's freed.
+
+Signed-off-by: Dave Jiang <dave.jiang@intel.com>
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/dma/ioat/init.c | 27 +++++++++++++++++++++++++++
+ drivers/dma/ioat/registers.h | 14 ++++++++++++++
+ 2 files changed, 41 insertions(+)
+
+diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
+index 020bcdecb3fb..d41dc9a9ff68 100644
+--- a/drivers/dma/ioat/init.c
++++ b/drivers/dma/ioat/init.c
+@@ -638,6 +638,11 @@ static void ioat_free_chan_resources(struct dma_chan *c)
+ ioat_stop(ioat_chan);
+ ioat_reset_hw(ioat_chan);
+
++ /* Put LTR to idle */
++ if (ioat_dma->version >= IOAT_VER_3_4)
++ writeb(IOAT_CHAN_LTR_SWSEL_IDLE,
++ ioat_chan->reg_base + IOAT_CHAN_LTR_SWSEL_OFFSET);
++
+ spin_lock_bh(&ioat_chan->cleanup_lock);
+ spin_lock_bh(&ioat_chan->prep_lock);
+ descs = ioat_ring_space(ioat_chan);
+@@ -727,6 +732,28 @@ static int ioat_alloc_chan_resources(struct dma_chan *c)
+ spin_unlock_bh(&ioat_chan->prep_lock);
+ spin_unlock_bh(&ioat_chan->cleanup_lock);
+
++ /* Setting up LTR values for 3.4 or later */
++ if (ioat_chan->ioat_dma->version >= IOAT_VER_3_4) {
++ u32 lat_val;
++
++ lat_val = IOAT_CHAN_LTR_ACTIVE_SNVAL |
++ IOAT_CHAN_LTR_ACTIVE_SNLATSCALE |
++ IOAT_CHAN_LTR_ACTIVE_SNREQMNT;
++ writel(lat_val, ioat_chan->reg_base +
++ IOAT_CHAN_LTR_ACTIVE_OFFSET);
++
++ lat_val = IOAT_CHAN_LTR_IDLE_SNVAL |
++ IOAT_CHAN_LTR_IDLE_SNLATSCALE |
++ IOAT_CHAN_LTR_IDLE_SNREQMNT;
++ writel(lat_val, ioat_chan->reg_base +
++ IOAT_CHAN_LTR_IDLE_OFFSET);
++
++ /* Select to active */
++ writeb(IOAT_CHAN_LTR_SWSEL_ACTIVE,
++ ioat_chan->reg_base +
++ IOAT_CHAN_LTR_SWSEL_OFFSET);
++ }
++
+ ioat_start_null_desc(ioat_chan);
+
+ /* check that we got off the ground */
+diff --git a/drivers/dma/ioat/registers.h b/drivers/dma/ioat/registers.h
+index 2b517d6db5fd..99c1c24d465d 100644
+--- a/drivers/dma/ioat/registers.h
++++ b/drivers/dma/ioat/registers.h
+@@ -253,4 +253,18 @@
+ #define IOAT_CHAN_DRS_EN 0x0100
+ #define IOAT_CHAN_DRS_AUTOWRAP 0x0200
+
++#define IOAT_CHAN_LTR_SWSEL_OFFSET 0xBC
++#define IOAT_CHAN_LTR_SWSEL_ACTIVE 0x0
++#define IOAT_CHAN_LTR_SWSEL_IDLE 0x1
++
++#define IOAT_CHAN_LTR_ACTIVE_OFFSET 0xC0
++#define IOAT_CHAN_LTR_ACTIVE_SNVAL 0x0000 /* 0 us */
++#define IOAT_CHAN_LTR_ACTIVE_SNLATSCALE 0x0800 /* 1us scale */
++#define IOAT_CHAN_LTR_ACTIVE_SNREQMNT 0x8000 /* snoop req enable */
++
++#define IOAT_CHAN_LTR_IDLE_OFFSET 0xC4
++#define IOAT_CHAN_LTR_IDLE_SNVAL 0x0258 /* 600 us */
++#define IOAT_CHAN_LTR_IDLE_SNLATSCALE 0x0800 /* 1us scale */
++#define IOAT_CHAN_LTR_IDLE_SNREQMNT 0x8000 /* snoop req enable */
++
+ #endif /* _IOAT_REGISTERS_H_ */
+--
+2.16.4
+
diff --git a/patches.drivers/drivers-depend-on-has_iomem-for-devm_platform_ioremap_resource b/patches.drivers/drivers-depend-on-has_iomem-for-devm_platform_ioremap_resource
new file mode 100644
index 0000000000..e17aca8572
--- /dev/null
+++ b/patches.drivers/drivers-depend-on-has_iomem-for-devm_platform_ioremap_resource
@@ -0,0 +1,36 @@
+From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+Date: Thu, 21 Feb 2019 17:26:27 +0100
+Subject: drivers: depend on HAS_IOMEM for devm_platform_ioremap_resource()
+Git-commit: 837ccda3480d2861c09aabc5fa014be18df9dd3c
+Patch-mainline: v5.1-rc1
+References: bsc#1136333 jsc#SLE-4994
+
+We only build devm_ioremap_resource() if HAS_IOMEM is selected, so this
+dependency must cascade down to devm_platform_ioremap_resource().
+
+Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ drivers/base/platform.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/base/platform.c
++++ b/drivers/base/platform.c
+@@ -87,6 +87,7 @@ EXPORT_SYMBOL_GPL(platform_get_resource)
+ * resource managemend
+ * @index: resource index
+ */
++#ifdef CONFIG_HAS_IOMEM
+ void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev,
+ unsigned int index)
+ {
+@@ -96,6 +97,7 @@ void __iomem *devm_platform_ioremap_reso
+ return devm_ioremap_resource(&pdev->dev, res);
+ }
+ EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource);
++#endif /* CONFIG_HAS_IOMEM */
+
+ /**
+ * platform_get_irq - get an IRQ for a device
diff --git a/patches.drivers/drivers-dma-ioat-Remove-now-redundant-smp_read_barri.patch b/patches.drivers/drivers-dma-ioat-Remove-now-redundant-smp_read_barri.patch
new file mode 100644
index 0000000000..d4602bab6a
--- /dev/null
+++ b/patches.drivers/drivers-dma-ioat-Remove-now-redundant-smp_read_barri.patch
@@ -0,0 +1,49 @@
+From 98c1ec7cefaadbf65680d116c3d8612b93a841a0 Mon Sep 17 00:00:00 2001
+From: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
+Date: Fri, 1 Dec 2017 17:04:39 -0800
+Subject: [PATCH] drivers/dma/ioat: Remove now-redundant smp_read_barrier_depends()
+Git-commit: 98c1ec7cefaadbf65680d116c3d8612b93a841a0
+Patch-mainline: v4.16-rc1
+References: jsc#SLE-5442
+
+Now that READ_ONCE() implies smp_read_barrier_depends(), the
+__cleanup() and ioat_abort_descs() functions no longer need their
+smp_read_barrier_depends() calls, which this commit removes.
+It is actually not entirely clear why this driver ever included
+smp_read_barrier_depends() given that it appears to be x86-only and
+given that smp_read_barrier_depends() has no effect whatsoever except
+on DEC Alpha.
+
+Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+Cc: Vinod Koul <vinod.koul@intel.com>
+Cc: Dan Williams <dan.j.williams@intel.com>
+Cc: <dmaengine@vger.kernel.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/dma/ioat/dma.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
+index 58d4ccd33672..8b5b23a8ace9 100644
+--- a/drivers/dma/ioat/dma.c
++++ b/drivers/dma/ioat/dma.c
+@@ -597,7 +597,6 @@ static void __cleanup(struct ioatdma_chan *ioat_chan, dma_addr_t phys_complete)
+ for (i = 0; i < active && !seen_current; i++) {
+ struct dma_async_tx_descriptor *tx;
+
+- smp_read_barrier_depends();
+ prefetch(ioat_get_ring_ent(ioat_chan, idx + i + 1));
+ desc = ioat_get_ring_ent(ioat_chan, idx + i);
+ dump_desc_dbg(ioat_chan, desc);
+@@ -715,7 +714,6 @@ static void ioat_abort_descs(struct ioatdma_chan *ioat_chan)
+ for (i = 1; i < active; i++) {
+ struct dma_async_tx_descriptor *tx;
+
+- smp_read_barrier_depends();
+ prefetch(ioat_get_ring_ent(ioat_chan, idx + i + 1));
+ desc = ioat_get_ring_ent(ioat_chan, idx + i);
+
+--
+2.16.4
+
diff --git a/patches.drivers/drivers-fix-a-typo-in-the-kernel-doc-for-devm_platfo.patch b/patches.drivers/drivers-fix-a-typo-in-the-kernel-doc-for-devm_platfo.patch
new file mode 100644
index 0000000000..e21b00dcd8
--- /dev/null
+++ b/patches.drivers/drivers-fix-a-typo-in-the-kernel-doc-for-devm_platfo.patch
@@ -0,0 +1,31 @@
+From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+Date: Mon, 1 Apr 2019 10:16:35 +0200
+Subject: drivers: fix a typo in the kernel doc for
+ devm_platform_ioremap_resource()
+Patch-mainline: v5.2-rc1
+Git-commit: 7067c96ee8d2d77039aeb49670acfe160f484ef9
+References: bsc#1136333 jsc#SLE-4994
+
+It should have been 'management' not 'managemend'.
+
+Fixes: 7945f929f1a7 ("drivers: provide devm_platform_ioremap_resource()")
+Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+Reviewed-by: Mukesh Ojha <mojha@codeaurora.org>
+Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/base/platform.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/base/platform.c
++++ b/drivers/base/platform.c
+@@ -84,7 +84,7 @@ EXPORT_SYMBOL_GPL(platform_get_resource)
+ * device
+ *
+ * @pdev: platform device to use both for memory resource lookup as well as
+- * resource managemend
++ * resource management
+ * @index: resource index
+ */
+ #ifdef CONFIG_HAS_IOMEM
diff --git a/patches.drivers/drivers-provide-devm_platform_ioremap_resource.patch b/patches.drivers/drivers-provide-devm_platform_ioremap_resource.patch
new file mode 100644
index 0000000000..26051d1bab
--- /dev/null
+++ b/patches.drivers/drivers-provide-devm_platform_ioremap_resource.patch
@@ -0,0 +1,64 @@
+From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+Date: Wed, 20 Feb 2019 11:12:39 +0000
+Subject: drivers: provide devm_platform_ioremap_resource()
+Patch-mainline: v5.1-rc1
+Git-commit: 7945f929f1a77a1c8887a97ca07f87626858ff42
+References: bsc#1136333 jsc#SLE-4994
+
+There are currently 1200+ instances of using platform_get_resource()
+and devm_ioremap_resource() together in the kernel tree.
+
+This patch wraps these two calls in a single helper. Thanks to that
+we don't have to declare a local variable for struct resource * and can
+omit the redundant argument for resource type. We also have one
+function call less.
+
+Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/base/platform.c | 18 ++++++++++++++++++
+ include/linux/platform_device.h | 3 +++
+ 2 files changed, 21 insertions(+)
+
+--- a/drivers/base/platform.c
++++ b/drivers/base/platform.c
+@@ -80,6 +80,24 @@ struct resource *platform_get_resource(s
+ EXPORT_SYMBOL_GPL(platform_get_resource);
+
+ /**
++ * devm_platform_ioremap_resource - call devm_ioremap_resource() for a platform
++ * device
++ *
++ * @pdev: platform device to use both for memory resource lookup as well as
++ * resource managemend
++ * @index: resource index
++ */
++void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev,
++ unsigned int index)
++{
++ struct resource *res;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, index);
++ return devm_ioremap_resource(&pdev->dev, res);
++}
++EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource);
++
++/**
+ * platform_get_irq - get an IRQ for a device
+ * @dev: platform device
+ * @num: IRQ number index
+--- a/include/linux/platform_device.h
++++ b/include/linux/platform_device.h
+@@ -51,6 +51,9 @@ extern struct device platform_bus;
+ extern void arch_setup_pdev_archdata(struct platform_device *);
+ extern struct resource *platform_get_resource(struct platform_device *,
+ unsigned int, unsigned int);
++extern void __iomem *
++devm_platform_ioremap_resource(struct platform_device *pdev,
++ unsigned int index);
+ extern int platform_get_irq(struct platform_device *, unsigned int);
+ extern int platform_irq_count(struct platform_device *);
+ extern struct resource *platform_get_resource_byname(struct platform_device *,
diff --git a/patches.drivers/drivers-rapidio-devices-rio_mport_cdev.c-fix-resourc.patch b/patches.drivers/drivers-rapidio-devices-rio_mport_cdev.c-fix-resourc.patch
new file mode 100644
index 0000000000..5f2be1e44a
--- /dev/null
+++ b/patches.drivers/drivers-rapidio-devices-rio_mport_cdev.c-fix-resourc.patch
@@ -0,0 +1,44 @@
+From b1402dcb5643b7a27d46a05edd7491d49ba0e248 Mon Sep 17 00:00:00 2001
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Date: Fri, 17 Nov 2017 15:37:57 -0800
+Subject: [PATCH] drivers/rapidio/devices/rio_mport_cdev.c: fix resource leak in error handling path in 'rio_dma_transfer()'
+Git-commit: b1402dcb5643b7a27d46a05edd7491d49ba0e248
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+If 'dma_map_sg()', we should branch to the existing error handling path
+to free some resources before returning.
+
+Link: http://lkml.kernel.org/r/61292a4f369229eee03394247385e955027283f8.1505687047.git.christophe.jaillet@wanadoo.fr
+Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
+Cc: Matt Porter <mporter@kernel.crashing.org>
+Cc: Alexandre Bounine <alexandre.bounine@idt.com>
+Cc: Lorenzo Stoakes <lstoakes@gmail.com>
+Cc: Jesper Nilsson <jesper.nilsson@axis.com>
+Cc: Christian K_nig <christian.koenig@amd.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/rapidio/devices/rio_mport_cdev.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c
+index 5c1b6388122a..86805747a422 100644
+--- a/drivers/rapidio/devices/rio_mport_cdev.c
++++ b/drivers/rapidio/devices/rio_mport_cdev.c
+@@ -963,7 +963,8 @@ rio_dma_transfer(struct file *filp, u32 transfer_mode,
+ req->sgt.sgl, req->sgt.nents, dir);
+ if (nents == -EFAULT) {
+ rmcd_error("Failed to map SG list");
+- return -EFAULT;
++ ret = -EFAULT;
++ goto err_pg;
+ }
+
+ ret = do_dma_request(req, xfer, sync, nents);
+--
+2.16.4
+
diff --git a/patches.drivers/drivers-rapidio-rio_cm.c-fix-potential-oops-in-riocm.patch b/patches.drivers/drivers-rapidio-rio_cm.c-fix-potential-oops-in-riocm.patch
new file mode 100644
index 0000000000..41da0a0e02
--- /dev/null
+++ b/patches.drivers/drivers-rapidio-rio_cm.c-fix-potential-oops-in-riocm.patch
@@ -0,0 +1,44 @@
+From 5ac188b12e7cbdd92dee60877d1fac913fc1d074 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Thu, 7 Mar 2019 16:29:33 -0800
+Subject: [PATCH] drivers/rapidio/rio_cm.c: fix potential oops in riocm_ch_listen()
+Git-commit: 5ac188b12e7cbdd92dee60877d1fac913fc1d074
+Patch-mainline: v5.1-rc1
+References: bsc#1051510
+
+If riocm_get_channel() fails, then we should just return -EINVAL.
+Calling riocm_put_channel() will trigger a NULL dereference and
+generally we should call put() if the get() didn't succeed.
+
+Link: http://lkml.kernel.org/r/20190110130230.GB27017@kadam
+Fixes: b6e8d4aa1110 ("rapidio: add RapidIO channelized messaging driver")
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
+Cc: Matt Porter <mporter@kernel.crashing.org>
+Cc: Alexandre Bounine <alexandre.bounine@idt.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/rapidio/rio_cm.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/rapidio/rio_cm.c b/drivers/rapidio/rio_cm.c
+index bad0e0ea4f30..cf45829585cb 100644
+--- a/drivers/rapidio/rio_cm.c
++++ b/drivers/rapidio/rio_cm.c
+@@ -1215,7 +1215,9 @@ static int riocm_ch_listen(u16 ch_id)
+ riocm_debug(CHOP, "(ch_%d)", ch_id);
+
+ ch = riocm_get_channel(ch_id);
+- if (!ch || !riocm_cmp_exch(ch, RIO_CM_CHAN_BOUND, RIO_CM_LISTEN))
++ if (!ch)
++ return -EINVAL;
++ if (!riocm_cmp_exch(ch, RIO_CM_CHAN_BOUND, RIO_CM_LISTEN))
+ ret = -EINVAL;
+ riocm_put_channel(ch);
+ return ret;
+--
+2.16.4
+
diff --git a/patches.drivers/edac-mc-fix-edac_mc_find-in-case-no-device-is-found.patch b/patches.drivers/edac-mc-fix-edac_mc_find-in-case-no-device-is-found.patch
new file mode 100644
index 0000000000..947777dc21
--- /dev/null
+++ b/patches.drivers/edac-mc-fix-edac_mc_find-in-case-no-device-is-found.patch
@@ -0,0 +1,60 @@
+From: Robert Richter <rrichter@marvell.com>
+Date: Tue, 14 May 2019 10:49:09 +0000
+Subject: EDAC/mc: Fix edac_mc_find() in case no device is found
+Git-commit: 29a0c843973bc385918158c6976e4dbe891df969
+Patch-mainline: v5.2-rc1
+References: bsc#1114279
+
+The function should return NULL in case no device is found, but it
+always returns the last checked mc device from the list even if the
+index did not match. Fix that.
+
+I did some analysis why this did not raise any issues for about 3 years
+and the reason is that edac_mc_find() is mostly used to search for
+existing devices. Thus, the bug is not triggered.
+
+ [ bp: Drop the if (mci->mc_idx > idx) test in favor of readability. ]
+
+Fixes: c73e8833bec5 ("EDAC, mc: Fix locking around mc_devices list")
+Signed-off-by: Robert Richter <rrichter@marvell.com>
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Cc: "linux-edac@vger.kernel.org" <linux-edac@vger.kernel.org>
+Cc: James Morse <james.morse@arm.com>
+Cc: Mauro Carvalho Chehab <mchehab@kernel.org>
+Link: https://lkml.kernel.org/r/20190514104838.15065-1-rrichter@marvell.com
+---
+ drivers/edac/edac_mc.c | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
+index 13594ffadcb3..64922c8fa7e3 100644
+--- a/drivers/edac/edac_mc.c
++++ b/drivers/edac/edac_mc.c
+@@ -679,22 +679,18 @@ static int del_mc_from_global_list(struct mem_ctl_info *mci)
+
+ struct mem_ctl_info *edac_mc_find(int idx)
+ {
+- struct mem_ctl_info *mci = NULL;
++ struct mem_ctl_info *mci;
+ struct list_head *item;
+
+ mutex_lock(&mem_ctls_mutex);
+
+ list_for_each(item, &mc_devices) {
+ mci = list_entry(item, struct mem_ctl_info, link);
+-
+- if (mci->mc_idx >= idx) {
+- if (mci->mc_idx == idx) {
+- goto unlock;
+- }
+- break;
+- }
++ if (mci->mc_idx == idx)
++ goto unlock;
+ }
+
++ mci = NULL;
+ unlock:
+ mutex_unlock(&mem_ctls_mutex);
+ return mci;
+
diff --git a/patches.drivers/hid-input-fix-a4tech-horizontal-wheel-custom-usage.patch b/patches.drivers/hid-input-fix-a4tech-horizontal-wheel-custom-usage.patch
new file mode 100644
index 0000000000..5854f9886e
--- /dev/null
+++ b/patches.drivers/hid-input-fix-a4tech-horizontal-wheel-custom-usage.patch
@@ -0,0 +1,90 @@
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Tue, 11 Jun 2019 14:13:20 +0200
+Subject: HID: input: fix a4tech horizontal wheel custom usage
+Patch-mainline: Submitted, https://lkml.kernel.org/lkml/5346893.KeHrH3GHoD@linux-lf90.site/T/
+References: bsc#1137429
+
+Some a4tech mice use the 'GenericDesktop.00b8' usage to inform whether
+the previous wheel report was horizontal or vertical. Before
+c01908a14bf73 ("HID: input: add mapping for "Toggle Display" key") this
+usage was being mapped to 'Relative.Misc'. After the patch it's simply
+ignored (usage->type == 0 & usage->code == 0). Which ultimately makes
+hid-a4tech ignore the WHEEL/HWHEEL selection event, as it has no
+usage->type.
+
+We shouldn't rely on a mapping for that usage as it's nonstandard and
+doesn't really map to an input event. So we bypass the mapping and make
+sure the custom event handling properly handles both reports.
+
+Fixes: c01908a14bf73 ("HID: input: add mapping for "Toggle Display" key")
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+---
+ drivers/hid/hid-a4tech.c | 30 +++++++++++++++++++++++++++---
+ 1 file changed, 27 insertions(+), 3 deletions(-)
+
+--- a/drivers/hid/hid-a4tech.c
++++ b/drivers/hid/hid-a4tech.c
+@@ -26,12 +26,36 @@
+ #define A4_2WHEEL_MOUSE_HACK_7 0x01
+ #define A4_2WHEEL_MOUSE_HACK_B8 0x02
+
++#define A4_WHEEL_ORIENTATION (HID_UP_GENDESK | 0x000000b8)
++
+ struct a4tech_sc {
+ unsigned long quirks;
+ unsigned int hw_wheel;
+ __s32 delayed_value;
+ };
+
++static int a4_input_mapping(struct hid_device *hdev, struct hid_input *hi,
++ struct hid_field *field, struct hid_usage *usage,
++ unsigned long **bit, int *max)
++{
++ struct a4tech_sc *a4 = hid_get_drvdata(hdev);
++
++ if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8 &&
++ usage->hid == A4_WHEEL_ORIENTATION) {
++ /*
++ * We do not want to have this usage mapped to anything as it's
++ * nonstandard and doesn't really behave like an HID report.
++ * It's only selecting the orientation (vertical/horizontal) of
++ * the previous mouse wheel report. The input_events will be
++ * generated once both reports are recorded in a4_event().
++ */
++ return -1;
++ }
++
++ return 0;
++
++}
++
+ static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+@@ -53,8 +77,7 @@ static int a4_event(struct hid_device *h
+ struct a4tech_sc *a4 = hid_get_drvdata(hdev);
+ struct input_dev *input;
+
+- if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+- !usage->type)
++ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput)
+ return 0;
+
+ input = field->hidinput->input;
+@@ -65,7 +88,7 @@ static int a4_event(struct hid_device *h
+ return 1;
+ }
+
+- if (usage->hid == 0x000100b8) {
++ if (usage->hid == A4_WHEEL_ORIENTATION) {
+ input_event(input, EV_REL, value ? REL_HWHEEL :
+ REL_WHEEL, a4->delayed_value);
+ return 1;
+@@ -129,6 +152,7 @@ MODULE_DEVICE_TABLE(hid, a4_devices);
+ static struct hid_driver a4_driver = {
+ .name = "a4tech",
+ .id_table = a4_devices,
++ .input_mapping = a4_input_mapping,
+ .input_mapped = a4_input_mapped,
+ .event = a4_event,
+ .probe = a4_probe,
diff --git a/patches.drivers/hwmon-k10temp-27c-offset-needed-for-threadripper2.patch b/patches.drivers/hwmon-k10temp-27c-offset-needed-for-threadripper2.patch
new file mode 100644
index 0000000000..c3f0ba00b5
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-27c-offset-needed-for-threadripper2.patch
@@ -0,0 +1,28 @@
+From: Michael Larabel <michael@phoronix.com>
+Date: Tue, 7 Aug 2018 09:54:54 -0400
+Subject: hwmon: (k10temp) 27C Offset needed for Threadripper2
+Git-commit: 484a84f25ca7817c3662001316ba7d1e06b74ae2
+Patch-mainline: v4.19
+References: FATE#327735
+
+For at least the Threadripper 2950X and Threadripper 2990WX,
+it's confirmed a 27 degree offset is needed.
+
+Signed-off-by: Michael Larabel <michael@phoronix.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index 17c6460ae351..577e2ede5a1a 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -105,6 +105,8 @@ static const struct tctl_offset tctl_offset_table[] = {
+ { 0x17, "AMD Ryzen Threadripper 1950", 10000 },
+ { 0x17, "AMD Ryzen Threadripper 1920", 10000 },
+ { 0x17, "AMD Ryzen Threadripper 1910", 10000 },
++ { 0x17, "AMD Ryzen Threadripper 2950X", 27000 },
++ { 0x17, "AMD Ryzen Threadripper 2990WX", 27000 },
+ };
+
+ static void read_htcreg_pci(struct pci_dev *pdev, u32 *regval)
diff --git a/patches.drivers/hwmon-k10temp-add-hygon-dhyana-support.patch b/patches.drivers/hwmon-k10temp-add-hygon-dhyana-support.patch
new file mode 100644
index 0000000000..c24a4b3373
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-add-hygon-dhyana-support.patch
@@ -0,0 +1,39 @@
+From: Pu Wen <puwen@hygon.cn>
+Date: Sat, 8 Dec 2018 14:33:28 +0800
+Subject: hwmon: (k10temp) Add Hygon Dhyana support
+Git-commit: d93217d84c6c7ef74bfeb606a1fb1ee28720646b
+Patch-mainline: v5.0
+References: FATE#327735
+
+Add support for Hygon Dhyana family 18h processor for k10temp to get the
+temperature. As Hygon Dhyana shares the same function interface with AMD
+family 17h, so add Hygon PCI Vendor ID and reuse the code path of AMD.
+
+Signed-off-by: Pu Wen <puwen@hygon.cn>
+Acked-by: Borislav Petkov <bp@suse.de>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+---
+ drivers/hwmon/k10temp.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -323,7 +323,7 @@ static int k10temp_probe(struct pci_dev
+ (boot_cpu_data.x86_model & 0xf0) == 0x70)) {
+ data->read_htcreg = read_htcreg_nb_f15;
+ data->read_tempreg = read_tempreg_nb_f15;
+- } else if (boot_cpu_data.x86 == 0x17) {
++ } else if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) {
+ data->temp_adjust_mask = 0x80000;
+ data->read_tempreg = read_tempreg_nb_f17;
+ data->show_tdie = true;
+@@ -360,6 +360,7 @@ static const struct pci_device_id k10tem
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
++ { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) },
+ {}
+ };
+ MODULE_DEVICE_TABLE(pci, k10temp_id_table);
diff --git a/patches.drivers/hwmon-k10temp-add-support-for-amd-family-17h-model-30h-cpus.patch b/patches.drivers/hwmon-k10temp-add-support-for-amd-family-17h-model-30h-cpus.patch
index 529de2ce30..ff0d2050cd 100644
--- a/patches.drivers/hwmon-k10temp-add-support-for-amd-family-17h-model-30h-cpus.patch
+++ b/patches.drivers/hwmon-k10temp-add-support-for-amd-family-17h-model-30h-cpus.patch
@@ -31,9 +31,9 @@ Link: http://lkml.kernel.org/r/20181106200754.60722-5-brian.woods@amd.com
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -215,6 +215,7 @@ static const struct pci_device_id k10tem
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
{}
};
diff --git a/patches.drivers/hwmon-k10temp-add-support-for-amd-ryzen-w-vega-graphics.patch b/patches.drivers/hwmon-k10temp-add-support-for-amd-ryzen-w-vega-graphics.patch
new file mode 100644
index 0000000000..ea4a4ea221
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-add-support-for-amd-ryzen-w-vega-graphics.patch
@@ -0,0 +1,40 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Tue, 24 Apr 2018 08:59:45 -0700
+Subject: hwmon: (k10temp) Add support for AMD Ryzen w/ Vega graphics
+Git-commit: 877d8948d0aa402fbbede138fc73432bb335b65f
+Patch-mainline: v4.17
+References: FATE#327735
+
+Enable k10temp for AMD Ryzen APUs w/ Vega Mobile Gfx.
+
+Based on patch from René Rebe <rene@exactcode.de>. Dropped temperature
+offsets since those are not supposed to apply for the affected CPUs.
+
+Cc: stable@vger.kernel.org # v4.16+
+Cc: René Rebe <rene@exactcode.de>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index d19d08f81c6f..d2cc55e21374 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -40,6 +40,10 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
+ #define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463
+ #endif
+
++#ifndef PCI_DEVICE_ID_AMD_17H_RR_NB
++#define PCI_DEVICE_ID_AMD_17H_RR_NB 0x15d0
++#endif
++
+ /* CPUID function 0x80000001, ebx */
+ #define CPUID_PKGTYPE_MASK 0xf0000000
+ #define CPUID_PKGTYPE_F 0x00000000
+@@ -298,6 +302,7 @@ static const struct pci_device_id k10temp_id_table[] = {
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
++ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_RR_NB) },
+ {}
+ };
+ MODULE_DEVICE_TABLE(pci, k10temp_id_table);
diff --git a/patches.drivers/hwmon-k10temp-add-support-for-family-17h.patch b/patches.drivers/hwmon-k10temp-add-support-for-family-17h.patch
new file mode 100644
index 0000000000..cc7b2e4997
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-add-support-for-family-17h.patch
@@ -0,0 +1,67 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Mon, 4 Sep 2017 18:33:53 -0700
+Subject: hwmon: (k10temp) Add support for family 17h
+Git-commit: 9af0a9aecdb945cd5513941ffdcbcc031009b402
+Patch-mainline: v4.15
+References: FATE#327735
+
+Add support for temperature sensors on Family 17h (Ryzen) processors.
+
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index fc8076c7e1a1..c4dac53206c3 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -36,6 +36,10 @@ MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
+ /* Provide lock for writing to NB_SMU_IND_ADDR */
+ static DEFINE_MUTEX(nb_smu_ind_mutex);
+
++#ifndef PCI_DEVICE_ID_AMD_17H_DF_F3
++#define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463
++#endif
++
+ /* CPUID function 0x80000001, ebx */
+ #define CPUID_PKGTYPE_MASK 0xf0000000
+ #define CPUID_PKGTYPE_F 0x00000000
+@@ -61,6 +65,9 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
+ */
+ #define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET 0xd8200ca4
+
++/* F17h M01h Access througn SMN */
++#define F17H_M01H_REPORTED_TEMP_CTRL_OFFSET 0x00059800
++
+ struct k10temp_data {
+ struct pci_dev *pdev;
+ void (*read_tempreg)(struct pci_dev *pdev, u32 *regval);
+@@ -88,6 +95,12 @@ static void read_tempreg_nb_f15(struct pci_dev *pdev, u32 *regval)
+ F15H_M60H_REPORTED_TEMP_CTRL_OFFSET, regval);
+ }
+
++static void read_tempreg_nb_f17(struct pci_dev *pdev, u32 *regval)
++{
++ amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0x60,
++ F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, regval);
++}
++
+ static ssize_t temp1_input_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+@@ -224,6 +237,8 @@ static int k10temp_probe(struct pci_dev *pdev,
+ if (boot_cpu_data.x86 == 0x15 && (boot_cpu_data.x86_model == 0x60 ||
+ boot_cpu_data.x86_model == 0x70))
+ data->read_tempreg = read_tempreg_nb_f15;
++ else if (boot_cpu_data.x86 == 0x17)
++ data->read_tempreg = read_tempreg_nb_f17;
+ else
+ data->read_tempreg = read_tempreg_pci;
+
+@@ -242,6 +257,7 @@ static const struct pci_device_id k10temp_id_table[] = {
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
++ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
+ {}
+ };
+ MODULE_DEVICE_TABLE(pci, k10temp_id_table);
diff --git a/patches.drivers/hwmon-k10temp-add-support-for-stoney-ridge-and-bristol.patch b/patches.drivers/hwmon-k10temp-add-support-for-stoney-ridge-and-bristol.patch
new file mode 100644
index 0000000000..cb9253540c
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-add-support-for-stoney-ridge-and-bristol.patch
@@ -0,0 +1,38 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Sun, 29 Apr 2018 09:16:45 -0700
+Subject: hwmon: (k10temp) Add support for Stoney Ridge and Bristol Ridge CPUs
+Git-commit: ccaf63b4d6eaf3447037cefbb0b1038fa80c6639
+Patch-mainline: v4.18
+References: FATE#327735
+
+Add support for Stoney Ridge and Bristol Ridge (Family 15h Model 0x70)
+CPUs. Registers match those of Family 15h Model 0x60.
+
+Cc: stable@vger.kernel.org # v4.16+
+Tested-by: Gabriel Craciunescu <nix.or.die@gmail.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index 3b73dee6fdc6..e97105ae4158 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -37,6 +37,10 @@ MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
+ /* Provide lock for writing to NB_SMU_IND_ADDR */
+ static DEFINE_MUTEX(nb_smu_ind_mutex);
+
++#ifndef PCI_DEVICE_ID_AMD_15H_M70H_NB_F3
++#define PCI_DEVICE_ID_AMD_15H_M70H_NB_F3 0x15b3
++#endif
++
+ #ifndef PCI_DEVICE_ID_AMD_17H_DF_F3
+ #define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463
+ #endif
+@@ -320,6 +324,7 @@ static const struct pci_device_id k10temp_id_table[] = {
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
++ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M70H_NB_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
diff --git a/patches.drivers/hwmon-k10temp-add-support-for-temperature-offsets.patch b/patches.drivers/hwmon-k10temp-add-support-for-temperature-offsets.patch
new file mode 100644
index 0000000000..3981e66da0
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-add-support-for-temperature-offsets.patch
@@ -0,0 +1,77 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Mon, 4 Sep 2017 18:33:53 -0700
+Subject: hwmon: (k10temp) Add support for temperature offsets
+Git-commit: 1b50b776355fa6c6d7b3281a63c275d5c18d629d
+Patch-mainline: v4.15
+References: FATE#327735
+
+Add support for handling temperature offset values for various AMD CPUs,
+similar to the code used in the coretemp driver for Intel CPUs. This is
+primarily for Ryzen CPUs (which has documented temperature offsets),
+but the code is kept generic to simplify adding additional CPUs.
+
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index c4dac53206c3..46a54ed23410 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -71,6 +71,24 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
+ struct k10temp_data {
+ struct pci_dev *pdev;
+ void (*read_tempreg)(struct pci_dev *pdev, u32 *regval);
++ int temp_offset;
++};
++
++struct tctl_offset {
++ u8 model;
++ char const *id;
++ int offset;
++};
++
++static const struct tctl_offset tctl_offset_table[] = {
++ { 0x17, "AMD Ryzen 7 1600X", 20000 },
++ { 0x17, "AMD Ryzen 7 1700X", 20000 },
++ { 0x17, "AMD Ryzen 7 1800X", 20000 },
++ { 0x17, "AMD Ryzen Threadripper 1950X", 27000 },
++ { 0x17, "AMD Ryzen Threadripper 1920X", 27000 },
++ { 0x17, "AMD Ryzen Threadripper 1950", 10000 },
++ { 0x17, "AMD Ryzen Threadripper 1920", 10000 },
++ { 0x17, "AMD Ryzen Threadripper 1910", 10000 },
+ };
+
+ static void read_tempreg_pci(struct pci_dev *pdev, u32 *regval)
+@@ -110,6 +128,7 @@ static ssize_t temp1_input_show(struct device *dev,
+
+ data->read_tempreg(data->pdev, &regval);
+ temp = (regval >> 21) * 125;
++ temp -= data->temp_offset;
+
+ return sprintf(buf, "%u\n", temp);
+ }
+@@ -217,6 +236,7 @@ static int k10temp_probe(struct pci_dev *pdev,
+ struct device *dev = &pdev->dev;
+ struct k10temp_data *data;
+ struct device *hwmon_dev;
++ int i;
+
+ if (unreliable) {
+ if (!force) {
+@@ -242,6 +262,16 @@ static int k10temp_probe(struct pci_dev *pdev,
+ else
+ data->read_tempreg = read_tempreg_pci;
+
++ for (i = 0; i < ARRAY_SIZE(tctl_offset_table); i++) {
++ const struct tctl_offset *entry = &tctl_offset_table[i];
++
++ if (boot_cpu_data.x86 == entry->model &&
++ strstr(boot_cpu_data.x86_model_id, entry->id)) {
++ data->temp_offset = entry->offset;
++ break;
++ }
++ }
++
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, "k10temp", data,
+ k10temp_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
diff --git a/patches.drivers/hwmon-k10temp-add-temperature-offset-for-ryzen-1900x.patch b/patches.drivers/hwmon-k10temp-add-temperature-offset-for-ryzen-1900x.patch
new file mode 100644
index 0000000000..32b6594373
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-add-temperature-offset-for-ryzen-1900x.patch
@@ -0,0 +1,25 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Fri, 19 Jan 2018 06:38:03 -0800
+Subject: hwmon: (k10temp) Add temperature offset for Ryzen 1900X
+Git-commit: 6509614fdd2d05c6926d50901a45d5dfb852b715
+Patch-mainline: v4.16
+References: FATE#327735
+
+Like the other CPUs from the same series, the 1900X has a
+temperature offset of 27 degrees C.
+
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index 0721e175664a..06b4e1c78bd8 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -86,6 +86,7 @@ static const struct tctl_offset tctl_offset_table[] = {
+ { 0x17, "AMD Ryzen 7 1800X", 20000 },
+ { 0x17, "AMD Ryzen Threadripper 1950X", 27000 },
+ { 0x17, "AMD Ryzen Threadripper 1920X", 27000 },
++ { 0x17, "AMD Ryzen Threadripper 1900X", 27000 },
+ { 0x17, "AMD Ryzen Threadripper 1950", 10000 },
+ { 0x17, "AMD Ryzen Threadripper 1920", 10000 },
+ { 0x17, "AMD Ryzen Threadripper 1910", 10000 },
diff --git a/patches.drivers/hwmon-k10temp-add-temperature-offset-for-ryzen-2700x.patch b/patches.drivers/hwmon-k10temp-add-temperature-offset-for-ryzen-2700x.patch
new file mode 100644
index 0000000000..d2a177033b
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-add-temperature-offset-for-ryzen-2700x.patch
@@ -0,0 +1,62 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Tue, 24 Apr 2018 06:55:55 -0700
+Subject: hwmon: (k10temp) Add temperature offset for Ryzen 2700X
+Git-commit: 1b59788979acd230b9627276c76f6e6ba2c4709c
+Patch-mainline: v4.17
+References: FATE#327735
+
+Ryzen 2700X has a temperature offset of 10 degrees C. If bit 19 of the
+Temperature Control register is set, there is an additional offset of
+49 degrees C. Take this into account as well.
+
+Cc: stable@vger.kernel.org # v4.16+
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index 051a72eecb24..d19d08f81c6f 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -72,6 +72,7 @@ struct k10temp_data {
+ struct pci_dev *pdev;
+ void (*read_tempreg)(struct pci_dev *pdev, u32 *regval);
+ int temp_offset;
++ u32 temp_adjust_mask;
+ };
+
+ struct tctl_offset {
+@@ -84,6 +85,7 @@ static const struct tctl_offset tctl_offset_table[] = {
+ { 0x17, "AMD Ryzen 5 1600X", 20000 },
+ { 0x17, "AMD Ryzen 7 1700X", 20000 },
+ { 0x17, "AMD Ryzen 7 1800X", 20000 },
++ { 0x17, "AMD Ryzen 7 2700X", 10000 },
+ { 0x17, "AMD Ryzen Threadripper 1950X", 27000 },
+ { 0x17, "AMD Ryzen Threadripper 1920X", 27000 },
+ { 0x17, "AMD Ryzen Threadripper 1900X", 27000 },
+@@ -129,6 +131,8 @@ static ssize_t temp1_input_show(struct device *dev,
+
+ data->read_tempreg(data->pdev, &regval);
+ temp = (regval >> 21) * 125;
++ if (regval & data->temp_adjust_mask)
++ temp -= 49000;
+ if (temp > data->temp_offset)
+ temp -= data->temp_offset;
+ else
+@@ -259,12 +263,14 @@ static int k10temp_probe(struct pci_dev *pdev,
+ data->pdev = pdev;
+
+ if (boot_cpu_data.x86 == 0x15 && (boot_cpu_data.x86_model == 0x60 ||
+- boot_cpu_data.x86_model == 0x70))
++ boot_cpu_data.x86_model == 0x70)) {
+ data->read_tempreg = read_tempreg_nb_f15;
+- else if (boot_cpu_data.x86 == 0x17)
++ } else if (boot_cpu_data.x86 == 0x17) {
++ data->temp_adjust_mask = 0x80000;
+ data->read_tempreg = read_tempreg_nb_f17;
+- else
++ } else {
+ data->read_tempreg = read_tempreg_pci;
++ }
+
+ for (i = 0; i < ARRAY_SIZE(tctl_offset_table); i++) {
+ const struct tctl_offset *entry = &tctl_offset_table[i];
diff --git a/patches.drivers/hwmon-k10temp-correct-model-name-for-ryzen-1600x.patch b/patches.drivers/hwmon-k10temp-correct-model-name-for-ryzen-1600x.patch
new file mode 100644
index 0000000000..a9e79d94a3
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-correct-model-name-for-ryzen-1600x.patch
@@ -0,0 +1,25 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Mon, 13 Nov 2017 12:38:23 -0800
+Subject: hwmon: (k10temp) Correct model name for Ryzen 1600X
+Git-commit: ab5ee24615f9dd8b0cd199403959f8b13309e7b1
+Patch-mainline: v4.15
+References: FATE#327735
+
+Ryzen 1600X is a Ryzen 5 processor.
+
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index 46a54ed23410..0721e175664a 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -81,7 +81,7 @@ struct tctl_offset {
+ };
+
+ static const struct tctl_offset tctl_offset_table[] = {
+- { 0x17, "AMD Ryzen 7 1600X", 20000 },
++ { 0x17, "AMD Ryzen 5 1600X", 20000 },
+ { 0x17, "AMD Ryzen 7 1700X", 20000 },
+ { 0x17, "AMD Ryzen 7 1800X", 20000 },
+ { 0x17, "AMD Ryzen Threadripper 1950X", 27000 },
diff --git a/patches.drivers/hwmon-k10temp-display-both-tctl-and-tdie.patch b/patches.drivers/hwmon-k10temp-display-both-tctl-and-tdie.patch
new file mode 100644
index 0000000000..7bebab0460
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-display-both-tctl-and-tdie.patch
@@ -0,0 +1,138 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Thu, 26 Apr 2018 12:22:29 -0700
+Subject: hwmon: (k10temp) Display both Tctl and Tdie
+Git-commit: f934c0599ecab63ec9cca0000315240c1202d20c
+Patch-mainline: v4.18
+References: FATE#327735
+
+On some AMD CPUs, there is a different between the die temperature
+(Tdie) and the reported temperature (Tctl). Tdie is the real measured
+temperature, and Tctl is used for fan control. Lets report both for
+affected CPUs.
+
+Tested-by: Gabriel Craciunescu <nix.or.die@gmail.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index e97105ae4158..d3fae5a8e508 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -85,6 +85,7 @@ struct k10temp_data {
+ void (*read_tempreg)(struct pci_dev *pdev, u32 *regval);
+ int temp_offset;
+ u32 temp_adjust_mask;
++ bool show_tdie;
+ };
+
+ struct tctl_offset {
+@@ -145,17 +146,24 @@ static void read_tempreg_nb_f17(struct pci_dev *pdev, u32 *regval)
+ F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, regval);
+ }
+
+-static ssize_t temp1_input_show(struct device *dev,
+- struct device_attribute *attr, char *buf)
++unsigned int get_raw_temp(struct k10temp_data *data)
+ {
+- struct k10temp_data *data = dev_get_drvdata(dev);
+- u32 regval;
+ unsigned int temp;
++ u32 regval;
+
+ data->read_tempreg(data->pdev, &regval);
+ temp = (regval >> 21) * 125;
+ if (regval & data->temp_adjust_mask)
+ temp -= 49000;
++ return temp;
++}
++
++static ssize_t temp1_input_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct k10temp_data *data = dev_get_drvdata(dev);
++ unsigned int temp = get_raw_temp(data);
++
+ if (temp > data->temp_offset)
+ temp -= data->temp_offset;
+ else
+@@ -164,6 +172,23 @@ static ssize_t temp1_input_show(struct device *dev,
+ return sprintf(buf, "%u\n", temp);
+ }
+
++static ssize_t temp2_input_show(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct k10temp_data *data = dev_get_drvdata(dev);
++ unsigned int temp = get_raw_temp(data);
++
++ return sprintf(buf, "%u\n", temp);
++}
++
++static ssize_t temp_label_show(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++
++ return sprintf(buf, "%s\n", attr->index ? "Tctl" : "Tdie");
++}
++
+ static ssize_t temp1_max_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+@@ -191,16 +216,23 @@ static DEVICE_ATTR_RO(temp1_max);
+ static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0);
+ static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit, NULL, 1);
+
++static SENSOR_DEVICE_ATTR(temp1_label, 0444, temp_label_show, NULL, 0);
++static DEVICE_ATTR_RO(temp2_input);
++static SENSOR_DEVICE_ATTR(temp2_label, 0444, temp_label_show, NULL, 1);
++
+ static umode_t k10temp_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+ {
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct k10temp_data *data = dev_get_drvdata(dev);
+ struct pci_dev *pdev = data->pdev;
++ u32 reg;
+
+- if (index >= 2) {
+- u32 reg;
+-
++ switch (index) {
++ case 0 ... 1: /* temp1_input, temp1_max */
++ default:
++ break;
++ case 2 ... 3: /* temp1_crit, temp1_crit_hyst */
+ if (!data->read_htcreg)
+ return 0;
+
+@@ -212,6 +244,11 @@ static umode_t k10temp_is_visible(struct kobject *kobj,
+ data->read_htcreg(data->pdev, &reg);
+ if (!(reg & HTC_ENABLE))
+ return 0;
++ break;
++ case 4 ... 6: /* temp1_label, temp2_input, temp2_label */
++ if (!data->show_tdie)
++ return 0;
++ break;
+ }
+ return attr->mode;
+ }
+@@ -221,6 +258,9 @@ static struct attribute *k10temp_attrs[] = {
+ &dev_attr_temp1_max.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
++ &sensor_dev_attr_temp1_label.dev_attr.attr,
++ &dev_attr_temp2_input.attr,
++ &sensor_dev_attr_temp2_label.dev_attr.attr,
+ NULL
+ };
+
+@@ -296,6 +336,7 @@ static int k10temp_probe(struct pci_dev *pdev,
+ } else if (boot_cpu_data.x86 == 0x17) {
+ data->temp_adjust_mask = 0x80000;
+ data->read_tempreg = read_tempreg_nb_f17;
++ data->show_tdie = true;
+ } else {
+ data->read_htcreg = read_htcreg_pci;
+ data->read_tempreg = read_tempreg_pci;
diff --git a/patches.drivers/hwmon-k10temp-fix-reading-critical-temperature-register.patch b/patches.drivers/hwmon-k10temp-fix-reading-critical-temperature-register.patch
new file mode 100644
index 0000000000..f01561de90
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-fix-reading-critical-temperature-register.patch
@@ -0,0 +1,116 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Sun, 29 Apr 2018 08:08:24 -0700
+Subject: hwmon: (k10temp) Fix reading critical temperature register
+Git-commit: 40626a1bf657eef557fcee9e1b8ef5b4f5b56dcd
+Patch-mainline: v4.17
+References: FATE#327735
+
+The HTC (Hardware Temperature Control) register has moved
+for recent chips.
+
+Cc: stable@vger.kernel.org # v4.16+
+Tested-by: Gabriel Craciunescu <nix.or.die@gmail.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index d2cc55e21374..34b5448b00be 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -63,10 +63,12 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
+ #define NB_CAP_HTC 0x00000400
+
+ /*
+- * For F15h M60h, functionality of REG_REPORTED_TEMPERATURE
+- * has been moved to D0F0xBC_xD820_0CA4 [Reported Temperature
+- * Control]
++ * For F15h M60h and M70h, REG_HARDWARE_THERMAL_CONTROL
++ * and REG_REPORTED_TEMPERATURE have been moved to
++ * D0F0xBC_xD820_0C64 [Hardware Temperature Control]
++ * D0F0xBC_xD820_0CA4 [Reported Temperature Control]
+ */
++#define F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET 0xd8200c64
+ #define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET 0xd8200ca4
+
+ /* F17h M01h Access througn SMN */
+@@ -74,6 +76,7 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
+
+ struct k10temp_data {
+ struct pci_dev *pdev;
++ void (*read_htcreg)(struct pci_dev *pdev, u32 *regval);
+ void (*read_tempreg)(struct pci_dev *pdev, u32 *regval);
+ int temp_offset;
+ u32 temp_adjust_mask;
+@@ -98,6 +101,11 @@ static const struct tctl_offset tctl_offset_table[] = {
+ { 0x17, "AMD Ryzen Threadripper 1910", 10000 },
+ };
+
++static void read_htcreg_pci(struct pci_dev *pdev, u32 *regval)
++{
++ pci_read_config_dword(pdev, REG_HARDWARE_THERMAL_CONTROL, regval);
++}
++
+ static void read_tempreg_pci(struct pci_dev *pdev, u32 *regval)
+ {
+ pci_read_config_dword(pdev, REG_REPORTED_TEMPERATURE, regval);
+@@ -114,6 +122,12 @@ static void amd_nb_index_read(struct pci_dev *pdev, unsigned int devfn,
+ mutex_unlock(&nb_smu_ind_mutex);
+ }
+
++static void read_htcreg_nb_f15(struct pci_dev *pdev, u32 *regval)
++{
++ amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0xb8,
++ F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET, regval);
++}
++
+ static void read_tempreg_nb_f15(struct pci_dev *pdev, u32 *regval)
+ {
+ amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0xb8,
+@@ -160,8 +174,7 @@ static ssize_t show_temp_crit(struct device *dev,
+ u32 regval;
+ int value;
+
+- pci_read_config_dword(data->pdev,
+- REG_HARDWARE_THERMAL_CONTROL, &regval);
++ data->read_htcreg(data->pdev, &regval);
+ value = ((regval >> 16) & 0x7f) * 500 + 52000;
+ if (show_hyst)
+ value -= ((regval >> 24) & 0xf) * 500;
+@@ -181,13 +194,18 @@ static umode_t k10temp_is_visible(struct kobject *kobj,
+ struct pci_dev *pdev = data->pdev;
+
+ if (index >= 2) {
+- u32 reg_caps, reg_htc;
++ u32 reg;
++
++ if (!data->read_htcreg)
++ return 0;
+
+ pci_read_config_dword(pdev, REG_NORTHBRIDGE_CAPABILITIES,
+- &reg_caps);
+- pci_read_config_dword(pdev, REG_HARDWARE_THERMAL_CONTROL,
+- &reg_htc);
+- if (!(reg_caps & NB_CAP_HTC) || !(reg_htc & HTC_ENABLE))
++ &reg);
++ if (!(reg & NB_CAP_HTC))
++ return 0;
++
++ data->read_htcreg(data->pdev, &reg);
++ if (!(reg & HTC_ENABLE))
+ return 0;
+ }
+ return attr->mode;
+@@ -268,11 +286,13 @@ static int k10temp_probe(struct pci_dev *pdev,
+
+ if (boot_cpu_data.x86 == 0x15 && (boot_cpu_data.x86_model == 0x60 ||
+ boot_cpu_data.x86_model == 0x70)) {
++ data->read_htcreg = read_htcreg_nb_f15;
+ data->read_tempreg = read_tempreg_nb_f15;
+ } else if (boot_cpu_data.x86 == 0x17) {
+ data->temp_adjust_mask = 0x80000;
+ data->read_tempreg = read_tempreg_nb_f17;
+ } else {
++ data->read_htcreg = read_htcreg_pci;
+ data->read_tempreg = read_tempreg_pci;
+ }
+
diff --git a/patches.drivers/hwmon-k10temp-make-function-get_raw_temp-static.patch b/patches.drivers/hwmon-k10temp-make-function-get_raw_temp-static.patch
new file mode 100644
index 0000000000..a5d943e3b5
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-make-function-get_raw_temp-static.patch
@@ -0,0 +1,31 @@
+From: Colin Ian King <colin.king@canonical.com>
+Date: Fri, 1 Jun 2018 14:37:13 +0100
+Subject: hwmon: (k10temp) Make function get_raw_temp static
+Git-commit: fb8eefd3b4e6f79e0930fffff6640744699c6f1d
+Patch-mainline: v4.18
+References: FATE#327735
+
+The function get_raw_temp is local to the source and does not need to
+be in global scope, so make it static.
+
+Cleans up sparse warning:
+drivers/hwmon/k10temp.c:149:14: warning: symbol 'get_raw_temp' was not
+declared. Should it be static?
+
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index d3fae5a8e508..17c6460ae351 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -146,7 +146,7 @@ static void read_tempreg_nb_f17(struct pci_dev *pdev, u32 *regval)
+ F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, regval);
+ }
+
+-unsigned int get_raw_temp(struct k10temp_data *data)
++static unsigned int get_raw_temp(struct k10temp_data *data)
+ {
+ unsigned int temp;
+ u32 regval;
diff --git a/patches.drivers/hwmon-k10temp-move-chip-specific-code-into-probe-function.patch b/patches.drivers/hwmon-k10temp-move-chip-specific-code-into-probe-function.patch
new file mode 100644
index 0000000000..79c7ec76ca
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-move-chip-specific-code-into-probe-function.patch
@@ -0,0 +1,129 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Mon, 4 Sep 2017 18:33:53 -0700
+Subject: hwmon: (k10temp) Move chip specific code into probe function
+Git-commit: 68546abf7a3a63f199e53d6dcaa7375df37a6aaa
+Patch-mainline: v4.15
+References: FATE#327735
+
+Introduce a local data structure and determine the temperature read
+function at probe time to reduce runtime complexity.
+
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index ce3b91f22e30..fc8076c7e1a1 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -61,31 +61,44 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
+ */
+ #define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET 0xd8200ca4
+
+-static void amd_nb_smu_index_read(struct pci_dev *pdev, unsigned int devfn,
+- int offset, u32 *val)
++struct k10temp_data {
++ struct pci_dev *pdev;
++ void (*read_tempreg)(struct pci_dev *pdev, u32 *regval);
++};
++
++static void read_tempreg_pci(struct pci_dev *pdev, u32 *regval)
++{
++ pci_read_config_dword(pdev, REG_REPORTED_TEMPERATURE, regval);
++}
++
++static void amd_nb_index_read(struct pci_dev *pdev, unsigned int devfn,
++ unsigned int base, int offset, u32 *val)
+ {
+ mutex_lock(&nb_smu_ind_mutex);
+ pci_bus_write_config_dword(pdev->bus, devfn,
+- 0xb8, offset);
++ base, offset);
+ pci_bus_read_config_dword(pdev->bus, devfn,
+- 0xbc, val);
++ base + 4, val);
+ mutex_unlock(&nb_smu_ind_mutex);
+ }
+
++static void read_tempreg_nb_f15(struct pci_dev *pdev, u32 *regval)
++{
++ amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0xb8,
++ F15H_M60H_REPORTED_TEMP_CTRL_OFFSET, regval);
++}
++
+ static ssize_t temp1_input_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
++ struct k10temp_data *data = dev_get_drvdata(dev);
+ u32 regval;
+- struct pci_dev *pdev = dev_get_drvdata(dev);
+-
+- if (boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model == 0x60) {
+- amd_nb_smu_index_read(pdev, PCI_DEVFN(0, 0),
+- F15H_M60H_REPORTED_TEMP_CTRL_OFFSET,
+- &regval);
+- } else {
+- pci_read_config_dword(pdev, REG_REPORTED_TEMPERATURE, &regval);
+- }
+- return sprintf(buf, "%u\n", (regval >> 21) * 125);
++ unsigned int temp;
++
++ data->read_tempreg(data->pdev, &regval);
++ temp = (regval >> 21) * 125;
++
++ return sprintf(buf, "%u\n", temp);
+ }
+
+ static ssize_t temp1_max_show(struct device *dev,
+@@ -98,11 +111,12 @@ static ssize_t show_temp_crit(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+ {
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct k10temp_data *data = dev_get_drvdata(dev);
+ int show_hyst = attr->index;
+ u32 regval;
+ int value;
+
+- pci_read_config_dword(dev_get_drvdata(dev),
++ pci_read_config_dword(data->pdev,
+ REG_HARDWARE_THERMAL_CONTROL, &regval);
+ value = ((regval >> 16) & 0x7f) * 500 + 52000;
+ if (show_hyst)
+@@ -119,7 +133,8 @@ static umode_t k10temp_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+ {
+ struct device *dev = container_of(kobj, struct device, kobj);
+- struct pci_dev *pdev = dev_get_drvdata(dev);
++ struct k10temp_data *data = dev_get_drvdata(dev);
++ struct pci_dev *pdev = data->pdev;
+
+ if (index >= 2) {
+ u32 reg_caps, reg_htc;
+@@ -187,6 +202,7 @@ static int k10temp_probe(struct pci_dev *pdev,
+ {
+ int unreliable = has_erratum_319(pdev);
+ struct device *dev = &pdev->dev;
++ struct k10temp_data *data;
+ struct device *hwmon_dev;
+
+ if (unreliable) {
+@@ -199,7 +215,19 @@ static int k10temp_probe(struct pci_dev *pdev,
+ "unreliable CPU thermal sensor; check erratum 319\n");
+ }
+
+- hwmon_dev = devm_hwmon_device_register_with_groups(dev, "k10temp", pdev,
++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
++ data->pdev = pdev;
++
++ if (boot_cpu_data.x86 == 0x15 && (boot_cpu_data.x86_model == 0x60 ||
++ boot_cpu_data.x86_model == 0x70))
++ data->read_tempreg = read_tempreg_nb_f15;
++ else
++ data->read_tempreg = read_tempreg_pci;
++
++ hwmon_dev = devm_hwmon_device_register_with_groups(dev, "k10temp", data,
+ k10temp_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+ }
diff --git a/patches.drivers/hwmon-k10temp-only-apply-temperature-offset-if-result-is.patch b/patches.drivers/hwmon-k10temp-only-apply-temperature-offset-if-result-is.patch
new file mode 100644
index 0000000000..3fafff4be7
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-only-apply-temperature-offset-if-result-is.patch
@@ -0,0 +1,38 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Wed, 7 Feb 2018 17:49:39 -0800
+Subject: hwmon: (k10temp) Only apply temperature offset if result is positive
+Git-commit: aef17ca1271948ee57cc39b2493d31110cc42625
+Patch-mainline: v4.16
+References: FATE#327735
+
+A user reports a really bad temperature on Ryzen 1950X.
+
+k10temp-pci-00cb
+Adapter: PCI adapter
+temp1: +4294948.3°C (high = +70.0°C)
+
+This will happen if the temperature reported by the chip is lower than
+the offset temperature. This has been seen in the field if "Sense MI Skew"
+and/or "Sense MI Offset" BIOS parameters were set to unexpected values.
+Let's report a temperature of 0 degrees C in that case.
+
+Fixes: 1b50b776355f ("hwmon: (k10temp) Add support for temperature offsets")
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index 06b4e1c78bd8..4c6594a4661d 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -129,7 +129,10 @@ static ssize_t temp1_input_show(struct device *dev,
+
+ data->read_tempreg(data->pdev, &regval);
+ temp = (regval >> 21) * 125;
+- temp -= data->temp_offset;
++ if (temp > data->temp_offset)
++ temp -= data->temp_offset;
++ else
++ temp = 0;
+
+ return sprintf(buf, "%u\n", temp);
+ }
diff --git a/patches.drivers/hwmon-k10temp-support-all-family-15h-model-6xh-and-model.patch b/patches.drivers/hwmon-k10temp-support-all-family-15h-model-6xh-and-model.patch
new file mode 100644
index 0000000000..e0241f3f34
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-support-all-family-15h-model-6xh-and-model.patch
@@ -0,0 +1,36 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Sun, 2 Sep 2018 12:02:53 -0700
+Subject: hwmon: (k10temp) Support all Family 15h Model 6xh and Model 7xh processors
+Git-commit: 53dfa0088edd2e2793afa21488532b12eb2dae48
+Patch-mainline: v4.20
+References: FATE#327735
+
+BIOS developer guides refer to Family 15h Models 60h-6fh and Family 15h
+Models 70h-7fh. So far the driver only checked for Models 60h and 70h.
+However, there are now processors with other model numbers in the same
+families. Example is A10-9620P family 15h model 65h. Follow the developer
+guides and mask the lower 4 bit of the model number to determine the
+registers to use for reading temperatures and temperature limits.
+
+Reported-by: Guglielmo Fanini <g.fanini@gmail.com>
+Cc: Guglielmo Fanini <g.fanini@gmail.com>
+Acked-by: Clemens Ladisch <clemens@ladisch.de>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index bb15d7816a29..2cef0c37ff6f 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -325,8 +325,9 @@ static int k10temp_probe(struct pci_dev *pdev,
+
+ data->pdev = pdev;
+
+- if (boot_cpu_data.x86 == 0x15 && (boot_cpu_data.x86_model == 0x60 ||
+- boot_cpu_data.x86_model == 0x70)) {
++ if (boot_cpu_data.x86 == 0x15 &&
++ ((boot_cpu_data.x86_model & 0xf0) == 0x60 ||
++ (boot_cpu_data.x86_model & 0xf0) == 0x70)) {
+ data->read_htcreg = read_htcreg_nb_f15;
+ data->read_tempreg = read_tempreg_nb_f15;
+ } else if (boot_cpu_data.x86 == 0x17) {
diff --git a/patches.drivers/hwmon-k10temp-support-threadripper-2920x-2970wx-simplify.patch b/patches.drivers/hwmon-k10temp-support-threadripper-2920x-2970wx-simplify.patch
new file mode 100644
index 0000000000..5335679822
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-support-threadripper-2920x-2970wx-simplify.patch
@@ -0,0 +1,39 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Thu, 9 Aug 2018 11:50:46 -0700
+Subject: hwmon: k10temp: Support Threadripper 2920X, 2970WX; simplify offset table
+Git-commit: cd6a2064dbf9e485b80c54687f0ce91cca91a6df
+Patch-mainline: v4.19
+References: FATE#327735
+
+All announced Threadripper 29xx models have a temperature offset of
+27 degrees C. Simplify temperature offset table to match all 29xx
+Threadripper models with a single entry. Also simplify the table to match
+all 19xx Threadripper models with a single entry. This effectively drops
+entries for Threadripper 1910/1920/1950 which never saw the light of day.
+
+Cc: Michael Larabel <Michael@phoronix.com>
+Cc: Clemens Ladisch <clemens@ladisch.de>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index 577e2ede5a1a..bb15d7816a29 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -99,14 +99,8 @@ static const struct tctl_offset tctl_offset_table[] = {
+ { 0x17, "AMD Ryzen 7 1700X", 20000 },
+ { 0x17, "AMD Ryzen 7 1800X", 20000 },
+ { 0x17, "AMD Ryzen 7 2700X", 10000 },
+- { 0x17, "AMD Ryzen Threadripper 1950X", 27000 },
+- { 0x17, "AMD Ryzen Threadripper 1920X", 27000 },
+- { 0x17, "AMD Ryzen Threadripper 1900X", 27000 },
+- { 0x17, "AMD Ryzen Threadripper 1950", 10000 },
+- { 0x17, "AMD Ryzen Threadripper 1920", 10000 },
+- { 0x17, "AMD Ryzen Threadripper 1910", 10000 },
+- { 0x17, "AMD Ryzen Threadripper 2950X", 27000 },
+- { 0x17, "AMD Ryzen Threadripper 2990WX", 27000 },
++ { 0x17, "AMD Ryzen Threadripper 19", 27000 }, /* 19{00,20,50}X */
++ { 0x17, "AMD Ryzen Threadripper 29", 27000 }, /* 29{20,50,70,90}[W]X */
+ };
+
+ static void read_htcreg_pci(struct pci_dev *pdev, u32 *regval)
diff --git a/patches.drivers/hwmon-k10temp-use-api-function-to-access-system-management.patch b/patches.drivers/hwmon-k10temp-use-api-function-to-access-system-management.patch
new file mode 100644
index 0000000000..418b823488
--- /dev/null
+++ b/patches.drivers/hwmon-k10temp-use-api-function-to-access-system-management.patch
@@ -0,0 +1,78 @@
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Fri, 4 May 2018 13:01:33 -0700
+Subject: hwmon: (k10temp) Use API function to access System Management Network
+Git-commit: 3b031622f598481970400519bd5abc2a16708282
+Patch-mainline: v4.17
+References: FATE#327735
+
+The SMN (System Management Network) on Family 17h AMD CPUs is also accessed
+from other drivers, specifically EDAC. Accessing it directly is racy.
+On top of that, accessing the SMN through root bridge 00:00 is wrong on
+multi-die CPUs and may result in reading the temperature from the wrong
+die. Use available API functions to fix the problem.
+
+For this to work, add dependency on AMD_NB. Also change the Raven Ridge
+PCI device ID to point to Data Fabric Function 3, since this ID is used
+by the API functions to find the CPU node.
+
+Cc: stable@vger.kernel.org # v4.16+
+Tested-by: Gabriel Craciunescu <nix.or.die@gmail.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+
+diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
+index f249a4428458..6ec307c93ece 100644
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -272,7 +272,7 @@ config SENSORS_K8TEMP
+
+ config SENSORS_K10TEMP
+ tristate "AMD Family 10h+ temperature sensor"
+- depends on X86 && PCI
++ depends on X86 && PCI && AMD_NB
+ help
+ If you say yes here you get support for the temperature
+ sensor(s) inside your CPU. Supported are later revisions of
+diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
+index 34b5448b00be..3b73dee6fdc6 100644
+--- a/drivers/hwmon/k10temp.c
++++ b/drivers/hwmon/k10temp.c
+@@ -23,6 +23,7 @@
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/pci.h>
++#include <asm/amd_nb.h>
+ #include <asm/processor.h>
+
+ MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor");
+@@ -40,8 +41,8 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
+ #define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463
+ #endif
+
+-#ifndef PCI_DEVICE_ID_AMD_17H_RR_NB
+-#define PCI_DEVICE_ID_AMD_17H_RR_NB 0x15d0
++#ifndef PCI_DEVICE_ID_AMD_17H_M10H_DF_F3
++#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F3 0x15eb
+ #endif
+
+ /* CPUID function 0x80000001, ebx */
+@@ -136,8 +137,8 @@ static void read_tempreg_nb_f15(struct pci_dev *pdev, u32 *regval)
+
+ static void read_tempreg_nb_f17(struct pci_dev *pdev, u32 *regval)
+ {
+- amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0x60,
+- F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, regval);
++ amd_smn_read(amd_pci_dev_to_node_id(pdev),
++ F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, regval);
+ }
+
+ static ssize_t temp1_input_show(struct device *dev,
+@@ -322,7 +323,7 @@ static const struct pci_device_id k10temp_id_table[] = {
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
+- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_RR_NB) },
++ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
+ {}
+ };
+ MODULE_DEVICE_TABLE(pci, k10temp_id_table);
diff --git a/patches.drivers/hwmon-k10temp-x86-amd_nb-consolidate-shared-device-ids.patch b/patches.drivers/hwmon-k10temp-x86-amd_nb-consolidate-shared-device-ids.patch
index 5ea776d679..0a1697b980 100644
--- a/patches.drivers/hwmon-k10temp-x86-amd_nb-consolidate-shared-device-ids.patch
+++ b/patches.drivers/hwmon-k10temp-x86-amd_nb-consolidate-shared-device-ids.patch
@@ -3,7 +3,7 @@ Date: Tue, 6 Nov 2018 20:08:14 +0000
Subject: hwmon/k10temp, x86/amd_nb: Consolidate shared device IDs
Git-commit: dedf7dce4cec5c0abe69f4fa6938d5100398220b
Patch-mainline: v5.0-rc1
-References: fate#326884
+References: FATE#326884 FATE#327735
Consolidate shared PCI_DEVICE_IDs that were scattered through k10temp
and amd_nb, and move them into pci_ids.
@@ -24,14 +24,14 @@ CC: Thomas Gleixner <tglx@linutronix.de>
CC: x86-ml <x86@kernel.org>
Link: http://lkml.kernel.org/r/20181106200754.60722-2-brian.woods@amd.com
---
- arch/x86/kernel/amd_nb.c | 2 +-
- drivers/hwmon/k10temp.c | 1 +
+ arch/x86/kernel/amd_nb.c | 3 +--
+ drivers/hwmon/k10temp.c | 9 +--------
include/linux/pci_ids.h | 2 ++
- 3 files changed, 4 insertions(+), 1 deletion(-)
+ 3 files changed, 4 insertions(+), 10 deletions(-)
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
-@@ -11,10 +11,10 @@
+@@ -11,13 +11,12 @@
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/spinlock.h>
@@ -39,8 +39,11 @@ Link: http://lkml.kernel.org/r/20181106200754.60722-2-brian.woods@amd.com
#include <asm/amd_nb.h>
#define PCI_DEVICE_ID_AMD_17H_ROOT 0x1450
+ #define PCI_DEVICE_ID_AMD_17H_M10H_ROOT 0x15d0
-#define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463
#define PCI_DEVICE_ID_AMD_17H_DF_F4 0x1464
+-#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F3 0x15eb
+ #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F4 0x15ec
/* Protect the PCI config register pairs used for SMN and DF indirect access. */
--- a/drivers/hwmon/k10temp.c
@@ -50,12 +53,27 @@ Link: http://lkml.kernel.org/r/20181106200754.60722-2-brian.woods@amd.com
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/pci_ids.h>
+ #include <asm/amd_nb.h>
#include <asm/processor.h>
- MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor");
+@@ -41,14 +42,6 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
+ #define PCI_DEVICE_ID_AMD_15H_M70H_NB_F3 0x15b3
+ #endif
+
+-#ifndef PCI_DEVICE_ID_AMD_17H_DF_F3
+-#define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463
+-#endif
+-
+-#ifndef PCI_DEVICE_ID_AMD_17H_M10H_DF_F3
+-#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F3 0x15eb
+-#endif
+-
+ /* CPUID function 0x80000001, ebx */
+ #define CPUID_PKGTYPE_MASK 0xf0000000
+ #define CPUID_PKGTYPE_F 0x00000000
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
-@@ -537,6 +537,8 @@
+@@ -540,6 +540,8 @@
#define PCI_DEVICE_ID_AMD_16H_NB_F4 0x1534
#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F3 0x1583
#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F4 0x1584
diff --git a/patches.drivers/i2c-piix4-add-hygon-dhyana-smbus-support.patch b/patches.drivers/i2c-piix4-add-hygon-dhyana-smbus-support.patch
new file mode 100644
index 0000000000..0857566a32
--- /dev/null
+++ b/patches.drivers/i2c-piix4-add-hygon-dhyana-smbus-support.patch
@@ -0,0 +1,91 @@
+From: Pu Wen <puwen@hygon.cn>
+Date: Tue, 30 Apr 2019 00:08:43 +0800
+Subject: i2c-piix4: Add Hygon Dhyana SMBus support
+Git-commit: 24beb83ad289c68bce7c01351cb90465bbb1940a
+Patch-mainline: v5.2
+References: FATE#327735
+
+The Hygon Dhyana CPU has the SMBus device with PCI device ID 0x790b,
+which is the same as AMD CZ SMBus device. So add Hygon Dhyana support
+to the i2c-piix4 driver by using the code path of AMD.
+
+Signed-off-by: Pu Wen <puwen@hygon.cn>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
+Acked-by: Jean Delvare <jdelvare@suse.de>
+---
+ Documentation/i2c/busses/i2c-piix4 | 2 ++
+ drivers/i2c/busses/Kconfig | 1 +
+ drivers/i2c/busses/i2c-piix4.c | 12 +++++++++---
+ 3 files changed, 12 insertions(+), 3 deletions(-)
+
+--- a/Documentation/i2c/busses/i2c-piix4
++++ b/Documentation/i2c/busses/i2c-piix4
+@@ -15,6 +15,8 @@ Supported adapters:
+ http://support.amd.com/us/Embedded_TechDocs/44413.pdf
+ * AMD Hudson-2, ML, CZ
+ Datasheet: Not publicly available
++ * Hygon CZ
++ Datasheet: Not publicly available
+ * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
+ Datasheet: Publicly available at the SMSC website http://www.smsc.com
+
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -176,6 +176,7 @@ config I2C_PIIX4
+ AMD Hudson-2
+ AMD ML
+ AMD CZ
++ Hygon CZ
+ Serverworks OSB4
+ Serverworks CSB5
+ Serverworks CSB6
+--- a/drivers/i2c/busses/i2c-piix4.c
++++ b/drivers/i2c/busses/i2c-piix4.c
+@@ -19,6 +19,7 @@
+ Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
+ ATI IXP200, IXP300, IXP400, SB600, SB700/SP5100, SB800
+ AMD Hudson-2, ML, CZ
++ Hygon CZ
+ SMSC Victory66
+
+ Note: we assume there can only be one device, with one or more
+@@ -289,7 +290,9 @@ static int piix4_setup_sb800(struct pci_
+ PIIX4_dev->revision >= 0x41) ||
+ (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD &&
+ PIIX4_dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS &&
+- PIIX4_dev->revision >= 0x49))
++ PIIX4_dev->revision >= 0x49) ||
++ (PIIX4_dev->vendor == PCI_VENDOR_ID_HYGON &&
++ PIIX4_dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS))
+ smb_en = 0x00;
+ else
+ smb_en = (aux) ? 0x28 : 0x2c;
+@@ -354,7 +357,8 @@ static int piix4_setup_sb800(struct pci_
+ piix4_smba, i2ccfg >> 4);
+
+ /* Find which register is used for port selection */
+- if (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD) {
++ if (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD ||
++ PIIX4_dev->vendor == PCI_VENDOR_ID_HYGON) {
+ switch (PIIX4_dev->device) {
+ case PCI_DEVICE_ID_AMD_KERNCZ_SMBUS:
+ piix4_port_sel_sb800 = SB800_PIIX4_PORT_IDX_KERNCZ;
+@@ -682,6 +686,7 @@ static const struct pci_device_id piix4_
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_KERNCZ_SMBUS) },
++ { PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_KERNCZ_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_OSB4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+@@ -790,7 +795,8 @@ static int piix4_probe(struct pci_dev *d
+ if ((dev->vendor == PCI_VENDOR_ID_ATI &&
+ dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
+ dev->revision >= 0x40) ||
+- dev->vendor == PCI_VENDOR_ID_AMD) {
++ dev->vendor == PCI_VENDOR_ID_AMD ||
++ dev->vendor == PCI_VENDOR_ID_HYGON) {
+ is_sb800 = true;
+
+ if (!request_region(SB800_PIIX4_SMB_IDX, 2, "smba_idx")) {
diff --git a/patches.drivers/ipv6-fib-Don-t-assume-only-nodes-hold-a-reference-on.patch b/patches.drivers/ipv6-fib-Don-t-assume-only-nodes-hold-a-reference-on.patch
new file mode 100644
index 0000000000..0d801ac374
--- /dev/null
+++ b/patches.drivers/ipv6-fib-Don-t-assume-only-nodes-hold-a-reference-on.patch
@@ -0,0 +1,41 @@
+From: Ido Schimmel <idosch@mellanox.com>
+Date: Thu, 3 Aug 2017 13:28:21 +0200
+Subject: ipv6: fib: Don't assume only nodes hold a reference on routes
+Patch-mainline: v4.14-rc1
+Git-commit: c5b12410fa591acb1d48e167b9bd0d2a7a38498d
+References: bsc#1138732
+
+The code currently assumes that only FIB nodes can hold a reference on
+routes. Therefore, after fib6_purge_rt() has run and the route is no
+longer present in any intermediate nodes, it's assumed that its
+reference count would be 1 - taken by the node where it's currently
+stored.
+
+However, we're going to allow users other than the FIB to take a
+reference on a route, so this assumption is no longer valid and the
+BUG_ON() needs to be removed.
+
+Note that purging only takes place if the initial reference count is
+different than 1. I've left that check intact, as in the majority of
+systems (where routes are only referenced by the FIB), it does actually
+mean the route is present in intermediate nodes.
+
+Signed-off-by: Ido Schimmel <idosch@mellanox.com>
+Signed-off-by: Jiri Pirko <jiri@mellanox.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ net/ipv6/ip6_fib.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/net/ipv6/ip6_fib.c
++++ b/net/ipv6/ip6_fib.c
+@@ -763,8 +763,6 @@ static void fib6_purge_rt(struct rt6_inf
+ }
+ fn = fn->parent;
+ }
+- /* No more references are possible at this point. */
+- BUG_ON(atomic_read(&rt->rt6i_ref) != 1);
+ }
+ }
+
diff --git a/patches.drivers/mfd-intel-lpss-Set-the-device-in-reset-state-when-in.patch b/patches.drivers/mfd-intel-lpss-Set-the-device-in-reset-state-when-in.patch
new file mode 100644
index 0000000000..1cf727027f
--- /dev/null
+++ b/patches.drivers/mfd-intel-lpss-Set-the-device-in-reset-state-when-in.patch
@@ -0,0 +1,72 @@
+From dad06532292d77f37fbe831a02948a593500f682 Mon Sep 17 00:00:00 2001
+From: Binbin Wu <binbin.wu@intel.com>
+Date: Mon, 8 Apr 2019 16:09:10 +0800
+Subject: [PATCH] mfd: intel-lpss: Set the device in reset state when init
+Git-commit: dad06532292d77f37fbe831a02948a593500f682
+Patch-mainline: v5.2-rc1
+References: bsc#1051510
+
+In virtualized setup, when system reboots due to warm
+reset interrupt storm is seen.
+
+Call Trace:
+<IRQ>
+dump_stack+0x70/0xa5
+__report_bad_irq+0x2e/0xc0
+note_interrupt+0x248/0x290
+? add_interrupt_randomness+0x30/0x220
+handle_irq_event_percpu+0x54/0x80
+handle_irq_event+0x39/0x60
+handle_fasteoi_irq+0x91/0x150
+handle_irq+0x108/0x180
+do_IRQ+0x52/0xf0
+common_interrupt+0xf/0xf
+</IRQ>
+Rip: 0033:0x76fc2cfabc1d
+Code: 24 28 bf 03 00 00 00 31 c0 48 8d 35 63 77 0e 00 48 8d 15 2e
+94 0e 00 4c 89 f9 49 89 d9 4c 89 d3 e8 b8 e2 01 00 48 8b 54 24 18
+<48> 89 ef 48 89 de 4c 89 e1 e8 d5 97 01 00 84 c0 74 2d 48 8b 04
+24
+Rsp: 002b:00007ffd247c1fc0 EFLAGS: 00000293 ORIG_RAX: ffffffffffffffda
+Rax: 0000000000000000 RBX: 00007ffd247c1ff0 RCX: 000000000003d3ce
+Rdx: 0000000000000000 RSI: 00007ffd247c1ff0 RDI: 000076fc2cbb6010
+Rbp: 000076fc2cded010 R08: 00007ffd247c2210 R09: 00007ffd247c22a0
+R10: 000076fc29465470 R11: 0000000000000000 R12: 00007ffd247c1fc0
+R13: 000076fc2ce8e470 R14: 000076fc27ec9960 R15: 0000000000000414
+Handlers:
+[<000000000d3fa913>] idma64_irq
+Disabling IRQ #27
+
+To avoid interrupt storm, set the device in reset state
+before bringing out the device from reset state.
+
+Changelog v2:
+- correct the subject line by adding "mfd: "
+
+Signed-off-by: Binbin Wu <binbin.wu@intel.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Lee Jones <lee.jones@linaro.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/mfd/intel-lpss.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c
+index 50bffc3382d7..ff3fba16e735 100644
+--- a/drivers/mfd/intel-lpss.c
++++ b/drivers/mfd/intel-lpss.c
+@@ -273,6 +273,9 @@ static void intel_lpss_init_dev(const struct intel_lpss *lpss)
+ {
+ u32 value = LPSS_PRIV_SSP_REG_DIS_DMA_FIN;
+
++ /* Set the device in reset state */
++ writel(0, lpss->priv + LPSS_PRIV_RESETS);
++
+ intel_lpss_deassert_reset(lpss);
+
+ intel_lpss_set_remap_addr(lpss);
+--
+2.16.4
+
diff --git a/patches.drivers/mfd-tps65912-spi-Add-missing-of-table-registration.patch b/patches.drivers/mfd-tps65912-spi-Add-missing-of-table-registration.patch
new file mode 100644
index 0000000000..30d754aacd
--- /dev/null
+++ b/patches.drivers/mfd-tps65912-spi-Add-missing-of-table-registration.patch
@@ -0,0 +1,44 @@
+From 9e364e87ad7f2c636276c773d718cda29d62b741 Mon Sep 17 00:00:00 2001
+From: Daniel Gomez <dagmcr@gmail.com>
+Date: Mon, 22 Apr 2019 21:09:50 +0200
+Subject: [PATCH] mfd: tps65912-spi: Add missing of table registration
+Git-commit: 9e364e87ad7f2c636276c773d718cda29d62b741
+Patch-mainline: v5.2-rc1
+References: bsc#1051510
+
+MODULE_DEVICE_TABLE(of, <of_match_table> should be called to complete DT
+OF mathing mechanism and register it.
+
+Before this patch:
+modinfo drivers/mfd/tps65912-spi.ko | grep alias
+Alias: spi:tps65912
+
+After this patch:
+modinfo drivers/mfd/tps65912-spi.ko | grep alias
+Alias: of:N*T*Cti,tps65912C*
+Alias: of:N*T*Cti,tps65912
+
+Reported-by: Javier Martinez Canillas <javier@dowhile0.org>
+Signed-off-by: Daniel Gomez <dagmcr@gmail.com>
+Signed-off-by: Lee Jones <lee.jones@linaro.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/mfd/tps65912-spi.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c
+index 3bd75061f777..f78be039e463 100644
+--- a/drivers/mfd/tps65912-spi.c
++++ b/drivers/mfd/tps65912-spi.c
+@@ -27,6 +27,7 @@ static const struct of_device_id tps65912_spi_of_match_table[] = {
+ { .compatible = "ti,tps65912", },
+ { /* sentinel */ }
+ };
++MODULE_DEVICE_TABLE(of, tps65912_spi_of_match_table);
+
+ static int tps65912_spi_probe(struct spi_device *spi)
+ {
+--
+2.16.4
+
diff --git a/patches.drivers/mfd-twl6040-Fix-device-init-errors-for-ACCCTL-regist.patch b/patches.drivers/mfd-twl6040-Fix-device-init-errors-for-ACCCTL-regist.patch
new file mode 100644
index 0000000000..9e7971f254
--- /dev/null
+++ b/patches.drivers/mfd-twl6040-Fix-device-init-errors-for-ACCCTL-regist.patch
@@ -0,0 +1,64 @@
+From 48171d0ea7caccf21c9ee3ae75eb370f2a756062 Mon Sep 17 00:00:00 2001
+From: Tony Lindgren <tony@atomide.com>
+Date: Thu, 14 Feb 2019 08:03:45 -0800
+Subject: [PATCH] mfd: twl6040: Fix device init errors for ACCCTL register
+Git-commit: 48171d0ea7caccf21c9ee3ae75eb370f2a756062
+Patch-mainline: v5.2-rc1
+References: bsc#1051510
+
+I noticed that we can get a -EREMOTEIO errors on at least omap4 duovero:
+
+twl6040 0-004b: Failed to write 2d = 19: -121
+
+And then any following register access will produce errors.
+
+There 2d offset above is register ACCCTL that gets written on twl6040
+powerup. With error checking added to the related regcache_sync() call,
+the -EREMOTEIO error is reproducable on twl6040 powerup at least
+duovero.
+
+To fix the error, we need to wait until twl6040 is accessible after the
+powerup. Based on tests on omap4 duovero, we need to wait over 8ms after
+powerup before register write will complete without failures. Let's also
+make sure we warn about possible errors too.
+
+Note that we have twl6040_patch[] reg_sequence with the ACCCTL register
+configuration and regcache_sync() will write the new value to ACCCTL.
+
+Signed-off-by: Tony Lindgren <tony@atomide.com>
+Acked-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
+Signed-off-by: Lee Jones <lee.jones@linaro.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/mfd/twl6040.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c
+index 7c3c5fd5fcd0..86052c5c6069 100644
+--- a/drivers/mfd/twl6040.c
++++ b/drivers/mfd/twl6040.c
+@@ -322,8 +322,19 @@ int twl6040_power(struct twl6040 *twl6040, int on)
+ }
+ }
+
++ /*
++ * Register access can produce errors after power-up unless we
++ * wait at least 8ms based on measurements on duovero.
++ */
++ usleep_range(10000, 12000);
++
+ /* Sync with the HW */
+- regcache_sync(twl6040->regmap);
++ ret = regcache_sync(twl6040->regmap);
++ if (ret) {
++ dev_err(twl6040->dev, "Failed to sync with the HW: %i\n",
++ ret);
++ goto out;
++ }
+
+ /* Default PLL configuration after power up */
+ twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL;
+--
+2.16.4
+
diff --git a/patches.drivers/mmc-core-make-pwrseq_emmc-partially-support-sleepy-G.patch b/patches.drivers/mmc-core-make-pwrseq_emmc-partially-support-sleepy-G.patch
new file mode 100644
index 0000000000..eadb1086d8
--- /dev/null
+++ b/patches.drivers/mmc-core-make-pwrseq_emmc-partially-support-sleepy-G.patch
@@ -0,0 +1,118 @@
+From 002ee28e8b322d4d4b7b83234b5d0f4ebd428eda Mon Sep 17 00:00:00 2001
+From: Andrea Merello <andrea.merello@gmail.com>
+Date: Fri, 5 Apr 2019 10:34:58 +0200
+Subject: [PATCH] mmc: core: make pwrseq_emmc (partially) support sleepy GPIO controllers
+Git-commit: 002ee28e8b322d4d4b7b83234b5d0f4ebd428eda
+Patch-mainline: v5.2-rc1
+References: bsc#1051510
+
+pwrseq_emmc.c implements a HW reset procedure for eMMC chip by driving a
+GPIO line.
+
+It registers the .reset() cb on mmc_pwrseq_ops and it registers a system
+restart notification handler; both of them perform reset by unconditionally
+calling gpiod_set_value().
+
+If the eMMC reset line is tied to a GPIO controller whose driver can sleep
+(i.e. I2C GPIO controller), then the kernel would spit warnings when trying
+to reset the eMMC chip by means of .reset() mmc_pwrseq_ops cb (that is
+exactly what I'm seeing during boot).
+
+Furthermore, on system reset we would gets to the system restart
+notification handler with disabled interrupts - local_irq_disable() is
+called in machine_restart() at least on ARM/ARM64 - and we would be in
+trouble when the GPIO driver tries to sleep (which indeed doesn't happen
+here, likely because in my case the machine specific code doesn't call
+do_kernel_restart(), I guess..).
+
+This patch fixes the .reset() cb to make use of gpiod_set_value_cansleep(),
+so that the eMMC gets reset on boot without complaints, while, since there
+isn't that much we can do, we avoid register the restart handler if the
+GPIO controller has a sleepy driver (and we spit a dev_notice() message to
+let people know)..
+
+This had been tested on a downstream 4.9 kernel with backported
+commit 83f37ee7ba33 ("mmc: pwrseq: Add reset callback to the struct
+mmc_pwrseq_ops") and commit ae60fb031cf2 ("mmc: core: Don't do eMMC HW
+reset when resuming the eMMC card"), because I couldn't boot my board
+otherwise. Maybe worth to RFT.
+
+Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/mmc/core/pwrseq_emmc.c | 38 ++++++++++++++++++++------------------
+ 1 file changed, 20 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c
+index efb8a7965dd4..154f4204d58c 100644
+--- a/drivers/mmc/core/pwrseq_emmc.c
++++ b/drivers/mmc/core/pwrseq_emmc.c
+@@ -30,19 +30,14 @@ struct mmc_pwrseq_emmc {
+
+ #define to_pwrseq_emmc(p) container_of(p, struct mmc_pwrseq_emmc, pwrseq)
+
+-static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq)
+-{
+- gpiod_set_value(pwrseq->reset_gpio, 1);
+- udelay(1);
+- gpiod_set_value(pwrseq->reset_gpio, 0);
+- udelay(200);
+-}
+-
+ static void mmc_pwrseq_emmc_reset(struct mmc_host *host)
+ {
+ struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(host->pwrseq);
+
+- __mmc_pwrseq_emmc_reset(pwrseq);
++ gpiod_set_value_cansleep(pwrseq->reset_gpio, 1);
++ udelay(1);
++ gpiod_set_value_cansleep(pwrseq->reset_gpio, 0);
++ udelay(200);
+ }
+
+ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
+@@ -50,8 +45,11 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
+ {
+ struct mmc_pwrseq_emmc *pwrseq = container_of(this,
+ struct mmc_pwrseq_emmc, reset_nb);
++ gpiod_set_value(pwrseq->reset_gpio, 1);
++ udelay(1);
++ gpiod_set_value(pwrseq->reset_gpio, 0);
++ udelay(200);
+
+- __mmc_pwrseq_emmc_reset(pwrseq);
+ return NOTIFY_DONE;
+ }
+
+@@ -72,14 +70,18 @@ static int mmc_pwrseq_emmc_probe(struct platform_device *pdev)
+ if (IS_ERR(pwrseq->reset_gpio))
+ return PTR_ERR(pwrseq->reset_gpio);
+
+- /*
+- * register reset handler to ensure emmc reset also from
+- * emergency_reboot(), priority 255 is the highest priority
+- * so it will be executed before any system reboot handler.
+- */
+- pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb;
+- pwrseq->reset_nb.priority = 255;
+- register_restart_handler(&pwrseq->reset_nb);
++ if (!gpiod_cansleep(pwrseq->reset_gpio)) {
++ /*
++ * register reset handler to ensure emmc reset also from
++ * emergency_reboot(), priority 255 is the highest priority
++ * so it will be executed before any system reboot handler.
++ */
++ pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb;
++ pwrseq->reset_nb.priority = 255;
++ register_restart_handler(&pwrseq->reset_nb);
++ } else {
++ dev_notice(dev, "EMMC reset pin tied to a sleepy GPIO driver; reset on emergency-reboot disabled\n");
++ }
+
+ pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops;
+ pwrseq->pwrseq.dev = dev;
+--
+2.16.4
+
diff --git a/patches.drivers/mmc-mmci-Prevent-polling-for-busy-detection-in-IRQ-c.patch b/patches.drivers/mmc-mmci-Prevent-polling-for-busy-detection-in-IRQ-c.patch
new file mode 100644
index 0000000000..dae4210656
--- /dev/null
+++ b/patches.drivers/mmc-mmci-Prevent-polling-for-busy-detection-in-IRQ-c.patch
@@ -0,0 +1,46 @@
+From 8520ce1e17799b220ff421d4f39438c9c572ade3 Mon Sep 17 00:00:00 2001
+From: Ludovic Barre <ludovic.barre@st.com>
+Date: Fri, 26 Apr 2019 09:46:35 +0200
+Subject: [PATCH] mmc: mmci: Prevent polling for busy detection in IRQ context
+Git-commit: 8520ce1e17799b220ff421d4f39438c9c572ade3
+Patch-mainline: v5.2-rc1
+References: bsc#1051510
+
+The IRQ handler, mmci_irq(), loops until all status bits have been cleared.
+However, the status bit signaling busy in variant->busy_detect_flag, may be
+set even if busy detection isn't monitored for the current request.
+
+This may be the case for the CMD11 when switching the I/O voltage, which
+leads to that mmci_irq() busy loops in IRQ context. Fix this problem, by
+clearing the status bit for busy, before continuing to validate the
+condition for the loop. This is safe, because the busy status detection has
+already been taken care of by mmci_cmd_irq().
+
+Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/mmc/host/mmci.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
+index 049f8e3676ac..356833a606d5 100644
+--- a/drivers/mmc/host/mmci.c
++++ b/drivers/mmc/host/mmci.c
+@@ -1535,9 +1535,10 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
+ }
+
+ /*
+- * Don't poll for busy completion in irq context.
++ * Busy detection has been handled by mmci_cmd_irq() above.
++ * Clear the status bit to prevent polling in IRQ context.
+ */
+- if (host->variant->busy_detect && host->busy_status)
++ if (host->variant->busy_detect_flag)
+ status &= ~host->variant->busy_detect_flag;
+
+ ret = 1;
+--
+2.16.4
+
diff --git a/patches.drivers/mmc-sdhci-of-esdhc-add-erratum-eSDHC-A001-and-A-0083.patch b/patches.drivers/mmc-sdhci-of-esdhc-add-erratum-eSDHC-A001-and-A-0083.patch
new file mode 100644
index 0000000000..cad25cd742
--- /dev/null
+++ b/patches.drivers/mmc-sdhci-of-esdhc-add-erratum-eSDHC-A001-and-A-0083.patch
@@ -0,0 +1,52 @@
+From 05cb6b2a66fa7837211a060878e91be5eb10cb07 Mon Sep 17 00:00:00 2001
+From: Yinbo Zhu <yinbo.zhu@nxp.com>
+Date: Mon, 11 Mar 2019 02:16:40 +0000
+Subject: [PATCH] mmc: sdhci-of-esdhc: add erratum eSDHC-A001 and A-008358 support
+Mime-version: 1.0
+Content-type: text/plain; charset=UTF-8
+Content-transfer-encoding: 8bit
+Git-commit: 05cb6b2a66fa7837211a060878e91be5eb10cb07
+Patch-mainline: v5.2-rc1
+References: bsc#1051510
+
+Esdhc-a001: The data timeout counter (SYSCTL[DTOCV]) is not
+reliable for DTOCV values 0x4(2^17 SD clock), 0x8(2^21 SD clock),
+and 0xC(2^25 SD clock). The data timeout counter can count from
+2^13–2^27, but for values 2^17, 2^21, and 2^25, the timeout
+counter counts for only 2^13 SD clocks.
+A-008358: The data timeout counter value loaded into the timeout
+counter is less than expected and can result into early timeout
+error in case of eSDHC data transactions. The table below shows
+the expected vs actual timeout period for different values of
+Sysctl[dtocv]:
+these two erratum has the same quirk to control it, and set
+SDHCI_QUIRK_RESET_AFTER_REQUEST to fix above issue.
+
+Signed-off-by: Yinbo Zhu <yinbo.zhu@nxp.com>
+Acked-by: Adrian Hunter <adrian.hunter@intel.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/mmc/host/sdhci-of-esdhc.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
+index b3310ea90231..04d7d95e9bba 100644
+--- a/drivers/mmc/host/sdhci-of-esdhc.c
++++ b/drivers/mmc/host/sdhci-of-esdhc.c
+@@ -1075,8 +1075,10 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
+ if (esdhc->vendor_ver > VENDOR_V_22)
+ host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
+
+- if (of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc"))
++ if (of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc")) {
+ host->quirks2 |= SDHCI_QUIRK_RESET_AFTER_REQUEST;
++ host->quirks2 |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
++ }
+
+ if (of_device_is_compatible(np, "fsl,p5040-esdhc") ||
+ of_device_is_compatible(np, "fsl,p5020-esdhc") ||
+--
+2.16.4
+
diff --git a/patches.drivers/nvmem-Don-t-let-a-NULL-cell_id-for-nvmem_cell_get-cr.patch b/patches.drivers/nvmem-Don-t-let-a-NULL-cell_id-for-nvmem_cell_get-cr.patch
new file mode 100644
index 0000000000..049a2db4ca
--- /dev/null
+++ b/patches.drivers/nvmem-Don-t-let-a-NULL-cell_id-for-nvmem_cell_get-cr.patch
@@ -0,0 +1,79 @@
+From 87ed1405ef09d29a14df43295f7b6a93b63bfe6e Mon Sep 17 00:00:00 2001
+From: Douglas Anderson <dianders@chromium.org>
+Date: Mon, 18 Jun 2018 18:30:43 +0100
+Subject: [PATCH] nvmem: Don't let a NULL cell_id for nvmem_cell_get() crash us
+Git-commit: 87ed1405ef09d29a14df43295f7b6a93b63bfe6e
+Patch-mainline: v4.18-rc5
+References: bsc#1051510
+
+In commit ca04d9d3e1b1 ("phy: qcom-qusb2: New driver for QUSB2 PHY on
+Qcom chips") you can see a call like:
+
+ devm_nvmem_cell_get(dev, NULL);
+
+Note that the cell ID passed to the function is NULL. This is because
+the qcom-qusb2 driver is expected to work only on systems where the
+PHY node is hooked up via device-tree and is nameless.
+
+This works OK for the most part. The first thing nvmem_cell_get()
+does is to call of_nvmem_cell_get() and there it's documented that a
+NULL name is fine. The problem happens when the call to
+of_nvmem_cell_get() returns -EINVAL. In such a case we'll fall back
+to nvmem_cell_get_from_list() and eventually might (if nvmem_cells
+isn't an empty list) crash with something that looks like:
+
+ strcmp
+ nvmem_find_cell
+ __nvmem_device_get
+ nvmem_cell_get_from_list
+ nvmem_cell_get
+ devm_nvmem_cell_get
+ qusb2_phy_probe
+
+There are several different ways we could fix this problem:
+
+One could argue that perhaps the qcom-qusb2 driver should be changed
+to use of_nvmem_cell_get() which is allowed to have a NULL name. In
+that case, we'd need to add a patche to introduce
+devm_of_nvmem_cell_get() since the qcom-qusb2 driver is using devm
+managed resources.
+
+One could also argue that perhaps we could just add a name to
+qcom-qusb2. That would be OK but I believe it effectively changes the
+device tree bindings, so maybe it's a no-go.
+
+In this patch I have chosen to fix the problem by simply not crashing
+when a NULL cell_id is passed to nvmem_cell_get().
+
+Note: that for the qcom-qusb2 driver the "nvmem-cells" property is
+defined to be optional and thus it's expected to be a common case that
+we would hit this crash and this is more than just a theoretical fix.
+
+Fixes: ca04d9d3e1b1 ("phy: qcom-qusb2: New driver for QUSB2 PHY on Qcom chips")
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/nvmem/core.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
+index b5b0cdc21d01..514d1dfc5630 100644
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -936,6 +936,10 @@ struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id)
+ return cell;
+ }
+
++ /* NULL cell_id only allowed for device tree; invalid otherwise */
++ if (!cell_id)
++ return ERR_PTR(-EINVAL);
++
+ return nvmem_cell_get_from_list(cell_id);
+ }
+ EXPORT_SYMBOL_GPL(nvmem_cell_get);
+--
+2.16.4
+
diff --git a/patches.drivers/nvmem-allow-to-select-i.MX-nvmem-driver-for-i.MX-7D.patch b/patches.drivers/nvmem-allow-to-select-i.MX-nvmem-driver-for-i.MX-7D.patch
new file mode 100644
index 0000000000..a08be2a20f
--- /dev/null
+++ b/patches.drivers/nvmem-allow-to-select-i.MX-nvmem-driver-for-i.MX-7D.patch
@@ -0,0 +1,37 @@
+From 9f23379c67fa20b367ea53cfd989da5212316e6f Mon Sep 17 00:00:00 2001
+From: Stefan Agner <stefan@agner.ch>
+Date: Sun, 3 Feb 2019 09:43:37 +0000
+Subject: [PATCH] nvmem: allow to select i.MX nvmem driver for i.MX 7D
+Git-commit: 9f23379c67fa20b367ea53cfd989da5212316e6f
+Patch-mainline: v5.1-rc1
+References: bsc#1051510
+
+The imx-ocotp nvmem driver supports the i.MX 7D SoC too. Allow to select
+the imx-ocotp driver even if only the i.MX 7D SoC has been selected.
+
+Fixes: 711d45477931 ("nvmem: octop: Add i.MX7D support")
+Signed-off-by: Stefan Agner <stefan@agner.ch>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/nvmem/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
+index 0a7a470ee859..9bbe2816400a 100644
+--- a/drivers/nvmem/Kconfig
++++ b/drivers/nvmem/Kconfig
+@@ -26,7 +26,7 @@ config NVMEM_IMX_IIM
+
+ config NVMEM_IMX_OCOTP
+ tristate "i.MX6 On-Chip OTP Controller support"
+- depends on SOC_IMX6 || COMPILE_TEST
++ depends on SOC_IMX6 || SOC_IMX7D || COMPILE_TEST
+ depends on HAS_IOMEM
+ help
+ This is a driver for the On-Chip OTP Controller (OCOTP) available on
+--
+2.16.4
+
diff --git a/patches.drivers/nvmem-core-fix-read-buffer-in-place.patch b/patches.drivers/nvmem-core-fix-read-buffer-in-place.patch
new file mode 100644
index 0000000000..a37a24c0f9
--- /dev/null
+++ b/patches.drivers/nvmem-core-fix-read-buffer-in-place.patch
@@ -0,0 +1,60 @@
+From 2fe518fecb3a4727393be286db9804cd82ee2d91 Mon Sep 17 00:00:00 2001
+From: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+Date: Sat, 13 Apr 2019 11:32:58 +0100
+Subject: [PATCH] nvmem: core: fix read buffer in place
+Git-commit: 2fe518fecb3a4727393be286db9804cd82ee2d91
+Patch-mainline: v5.2-rc1
+References: bsc#1051510
+
+When the bit_offset in the cell is zero, the pointer to the msb will
+not be properly initialized (ie, will still be pointing to the first
+byte in the buffer).
+
+This being the case, if there are bits to clear in the msb, those will
+be left untouched while the mask will incorrectly clear bit positions
+on the first byte.
+
+This commit also makes sure that any byte unused in the cell is
+cleared.
+
+Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/nvmem/core.c | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -946,7 +946,7 @@ static inline void nvmem_shift_read_buff
+ void *buf)
+ {
+ u8 *p, *b;
+- int i, bit_offset = cell->bit_offset;
++ int i, extra, bit_offset = cell->bit_offset;
+
+ p = b = buf;
+ if (bit_offset) {
+@@ -961,11 +961,16 @@ static inline void nvmem_shift_read_buff
+ p = b;
+ *b++ >>= bit_offset;
+ }
+-
+- /* result fits in less bytes */
+- if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE))
+- *p-- = 0;
++ } else {
++ /* point to the msb */
++ p += cell->bytes - 1;
+ }
++
++ /* result fits in less bytes */
++ extra = cell->bytes - DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE);
++ while (--extra >= 0)
++ *p-- = 0;
++
+ /* clear msb bits if any leftover in the last byte */
+ *p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0);
+ }
diff --git a/patches.drivers/nvmem-correct-Broadcom-OTP-controller-driver-writes.patch b/patches.drivers/nvmem-correct-Broadcom-OTP-controller-driver-writes.patch
new file mode 100644
index 0000000000..180a892851
--- /dev/null
+++ b/patches.drivers/nvmem-correct-Broadcom-OTP-controller-driver-writes.patch
@@ -0,0 +1,48 @@
+From e827756d64773515fa7de5e7e942a6d1494bf64e Mon Sep 17 00:00:00 2001
+From: Oza Pawandeep <oza.oza@broadcom.com>
+Date: Fri, 9 Jun 2017 10:59:06 +0100
+Subject: [PATCH] nvmem: correct Broadcom OTP controller driver writes
+Git-commit: e827756d64773515fa7de5e7e942a6d1494bf64e
+Patch-mainline: v4.13-rc1
+References: bsc#1051510
+
+- use data write offset to write otp data instead of read offset
+- use OTP program command 0x8 to write otp with ECC rather than just
+command 0xA without ECC
+
+Fixes: 9d59c6e8ae27 ("nvmem: Add the Broadcom OTP controller driver")
+Signed-off-by: Oza Pawandeep <oza.oza@broadcom.com>
+Signed-off-by: Scott Branden <scott.branden@broadcom.com>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/nvmem/bcm-ocotp.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/nvmem/bcm-ocotp.c b/drivers/nvmem/bcm-ocotp.c
+index 646cadbf1f93..3c56e3b2bd65 100644
+--- a/drivers/nvmem/bcm-ocotp.c
++++ b/drivers/nvmem/bcm-ocotp.c
+@@ -34,7 +34,7 @@
+ #define OTPC_CMD_READ 0x0
+ #define OTPC_CMD_OTP_PROG_ENABLE 0x2
+ #define OTPC_CMD_OTP_PROG_DISABLE 0x3
+-#define OTPC_CMD_PROGRAM 0xA
++#define OTPC_CMD_PROGRAM 0x8
+
+ /* OTPC Status Bits */
+ #define OTPC_STAT_CMD_DONE BIT(1)
+@@ -209,7 +209,7 @@ static int bcm_otpc_write(void *context, unsigned int offset, void *val,
+ set_command(priv->base, OTPC_CMD_PROGRAM);
+ set_cpu_address(priv->base, address++);
+ for (i = 0; i < priv->map->otpc_row_size; i++) {
+- writel(*buf, priv->base + priv->map->data_r_offset[i]);
++ writel(*buf, priv->base + priv->map->data_w_offset[i]);
+ buf++;
+ bytes_written += sizeof(*buf);
+ }
+--
+2.16.4
+
diff --git a/patches.drivers/nvmem-imx-ocotp-Add-i.MX7D-timing-write-clock-setup-.patch b/patches.drivers/nvmem-imx-ocotp-Add-i.MX7D-timing-write-clock-setup-.patch
new file mode 100644
index 0000000000..b6feb3959b
--- /dev/null
+++ b/patches.drivers/nvmem-imx-ocotp-Add-i.MX7D-timing-write-clock-setup-.patch
@@ -0,0 +1,132 @@
+From 828ae7a47caf86570f19b78d0923b3ea89714168 Mon Sep 17 00:00:00 2001
+From: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Date: Tue, 24 Oct 2017 10:54:31 +0100
+Subject: [PATCH] nvmem: imx-ocotp: Add i.MX7D timing write clock setup support
+Git-commit: 828ae7a47caf86570f19b78d0923b3ea89714168
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+This patch adds logic to correctly setup the write timing parameters
+when blowing an OTP fuse for the i.MX7S/D.
+
+Fixes: 0642bac7da42 ("nvmem: imx-ocotp: add write support")
+
+Signed-off-by: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/nvmem/imx-ocotp.c | 43 ++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 36 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
+index 8136ce8e77cd..10fc4a70a6e5 100644
+--- a/drivers/nvmem/imx-ocotp.c
++++ b/drivers/nvmem/imx-ocotp.c
+@@ -50,17 +50,14 @@
+ #define IMX_OCOTP_BM_CTRL_ERROR 0x00000200
+ #define IMX_OCOTP_BM_CTRL_REL_SHADOWS 0x00000400
+
+-#define DEF_RELAX 20 /* > 16.5ns */
++#define DEF_RELAX 20 /* > 16.5ns */
++#define DEF_FSOURCE 1001 /* > 1000 ns */
++#define DEF_STROBE_PROG 10000 /* IPG clocks */
+ #define IMX_OCOTP_WR_UNLOCK 0x3E770000
+ #define IMX_OCOTP_READ_LOCKED_VAL 0xBADABADA
+
+ static DEFINE_MUTEX(ocotp_mutex);
+
+-struct ocotp_params {
+- unsigned int nregs;
+- unsigned int bank_address_words;
+-};
+-
+ struct ocotp_priv {
+ struct device *dev;
+ struct clk *clk;
+@@ -69,6 +66,12 @@ struct ocotp_priv {
+ struct nvmem_config *config;
+ };
+
++struct ocotp_params {
++ unsigned int nregs;
++ unsigned int bank_address_words;
++ void (*set_timing)(struct ocotp_priv *priv);
++};
++
+ static int imx_ocotp_wait_for_busy(void __iomem *base, u32 flags)
+ {
+ int count;
+@@ -193,6 +196,27 @@ static void imx_ocotp_set_imx6_timing(struct ocotp_priv *priv)
+ writel(timing, priv->base + IMX_OCOTP_ADDR_TIMING);
+ }
+
++static void imx_ocotp_set_imx7_timing(struct ocotp_priv *priv)
++{
++ unsigned long clk_rate = 0;
++ u64 fsource, strobe_prog;
++ u32 timing = 0;
++
++ /* i.MX 7Solo Applications Processor Reference Manual, Rev. 0.1
++ * 6.4.3.3
++ */
++ clk_rate = clk_get_rate(priv->clk);
++ fsource = DIV_ROUND_UP_ULL((u64)clk_rate * DEF_FSOURCE,
++ NSEC_PER_SEC) + 1;
++ strobe_prog = DIV_ROUND_CLOSEST_ULL((u64)clk_rate * DEF_STROBE_PROG,
++ NSEC_PER_SEC) + 1;
++
++ timing = strobe_prog & 0x00000FFF;
++ timing |= (fsource << 12) & 0x000FF000;
++
++ writel(timing, priv->base + IMX_OCOTP_ADDR_TIMING);
++}
++
+ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
+ size_t bytes)
+ {
+@@ -219,7 +243,7 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
+ }
+
+ /* Setup the write timing values */
+- imx_ocotp_set_imx6_timing(priv);
++ priv->params->set_timing(priv);
+
+ /* 47.3.1.3.2
+ * Check that HW_OCOTP_CTRL[BUSY] and HW_OCOTP_CTRL[ERROR] are clear.
+@@ -376,26 +400,31 @@ static struct nvmem_config imx_ocotp_nvmem_config = {
+ static const struct ocotp_params imx6q_params = {
+ .nregs = 128,
+ .bank_address_words = 0,
++ .set_timing = imx_ocotp_set_imx6_timing,
+ };
+
+ static const struct ocotp_params imx6sl_params = {
+ .nregs = 64,
+ .bank_address_words = 0,
++ .set_timing = imx_ocotp_set_imx6_timing,
+ };
+
+ static const struct ocotp_params imx6sx_params = {
+ .nregs = 128,
+ .bank_address_words = 0,
++ .set_timing = imx_ocotp_set_imx6_timing,
+ };
+
+ static const struct ocotp_params imx6ul_params = {
+ .nregs = 128,
+ .bank_address_words = 0,
++ .set_timing = imx_ocotp_set_imx6_timing,
+ };
+
+ static const struct ocotp_params imx7d_params = {
+ .nregs = 64,
+ .bank_address_words = 4,
++ .set_timing = imx_ocotp_set_imx7_timing,
+ };
+
+ static const struct of_device_id imx_ocotp_dt_ids[] = {
+--
+2.16.4
+
diff --git a/patches.drivers/nvmem-imx-ocotp-Add-support-for-banked-OTP-addressin.patch b/patches.drivers/nvmem-imx-ocotp-Add-support-for-banked-OTP-addressin.patch
new file mode 100644
index 0000000000..c8d689f1a1
--- /dev/null
+++ b/patches.drivers/nvmem-imx-ocotp-Add-support-for-banked-OTP-addressin.patch
@@ -0,0 +1,159 @@
+From ffd9115f6548c51d347489e76bfb7d10e728f43d Mon Sep 17 00:00:00 2001
+From: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Date: Tue, 24 Oct 2017 10:54:29 +0100
+Subject: [PATCH] nvmem: imx-ocotp: Add support for banked OTP addressing
+Git-commit: ffd9115f6548c51d347489e76bfb7d10e728f43d
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+The i.MX7S/D takes the bank address in the CTRLn.ADDR field and the data
+value in one of the DATAx {0, 1, 2, 3} register fields. The current write
+routine is based on writing the CTRLn.ADDR field and writing a single DATA
+register only.
+
+Fixes: 0642bac7da42 ("nvmem: imx-ocotp: add write support")
+
+Signed-off-by: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/nvmem/imx-ocotp.c | 68 ++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 64 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
+index d94ed2d69a10..bf95a0ecd0dc 100644
+--- a/drivers/nvmem/imx-ocotp.c
++++ b/drivers/nvmem/imx-ocotp.c
+@@ -40,7 +40,10 @@
+ #define IMX_OCOTP_ADDR_CTRL_SET 0x0004
+ #define IMX_OCOTP_ADDR_CTRL_CLR 0x0008
+ #define IMX_OCOTP_ADDR_TIMING 0x0010
+-#define IMX_OCOTP_ADDR_DATA 0x0020
++#define IMX_OCOTP_ADDR_DATA0 0x0020
++#define IMX_OCOTP_ADDR_DATA1 0x0030
++#define IMX_OCOTP_ADDR_DATA2 0x0040
++#define IMX_OCOTP_ADDR_DATA3 0x0050
+
+ #define IMX_OCOTP_BM_CTRL_ADDR 0x0000007F
+ #define IMX_OCOTP_BM_CTRL_BUSY 0x00000100
+@@ -55,6 +58,7 @@ static DEFINE_MUTEX(ocotp_mutex);
+
+ struct ocotp_params {
+ unsigned int nregs;
++ unsigned int bank_address_words;
+ };
+
+ struct ocotp_priv {
+@@ -176,6 +180,7 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
+ u32 timing = 0;
+ u32 ctrl;
+ u8 waddr;
++ u8 word = 0;
+
+ /* allow only writing one complete OTP word at a time */
+ if ((bytes != priv->config->word_size) ||
+@@ -228,8 +233,23 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
+ * description. Both the unlock code and address can be written in the
+ * same operation.
+ */
+- /* OTP write/read address specifies one of 128 word address locations */
+- waddr = offset / 4;
++ if (priv->params->bank_address_words != 0) {
++ /*
++ * In banked/i.MX7 mode the OTP register bank goes into waddr
++ * see i.MX 7Solo Applications Processor Reference Manual, Rev.
++ * 0.1 section 6.4.3.1
++ */
++ offset = offset / priv->config->word_size;
++ waddr = offset / priv->params->bank_address_words;
++ word = offset & (priv->params->bank_address_words - 1);
++ } else {
++ /*
++ * Non-banked i.MX6 mode.
++ * OTP write/read address specifies one of 128 word address
++ * locations
++ */
++ waddr = offset / 4;
++ }
+
+ ctrl = readl(priv->base + IMX_OCOTP_ADDR_CTRL);
+ ctrl &= ~IMX_OCOTP_BM_CTRL_ADDR;
+@@ -255,8 +275,43 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
+ * shift right (with zero fill). This shifting is required to program
+ * the OTP serially. During the write operation, HW_OCOTP_DATA cannot be
+ * modified.
++ * Note: on i.MX7 there are four data fields to write for banked write
++ * with the fuse blowing operation only taking place after data0
++ * has been written. This is why data0 must always be the last
++ * register written.
+ */
+- writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA);
++ if (priv->params->bank_address_words != 0) {
++ /* Banked/i.MX7 mode */
++ switch (word) {
++ case 0:
++ writel(0, priv->base + IMX_OCOTP_ADDR_DATA1);
++ writel(0, priv->base + IMX_OCOTP_ADDR_DATA2);
++ writel(0, priv->base + IMX_OCOTP_ADDR_DATA3);
++ writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA0);
++ break;
++ case 1:
++ writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA1);
++ writel(0, priv->base + IMX_OCOTP_ADDR_DATA2);
++ writel(0, priv->base + IMX_OCOTP_ADDR_DATA3);
++ writel(0, priv->base + IMX_OCOTP_ADDR_DATA0);
++ break;
++ case 2:
++ writel(0, priv->base + IMX_OCOTP_ADDR_DATA1);
++ writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA2);
++ writel(0, priv->base + IMX_OCOTP_ADDR_DATA3);
++ writel(0, priv->base + IMX_OCOTP_ADDR_DATA0);
++ break;
++ case 3:
++ writel(0, priv->base + IMX_OCOTP_ADDR_DATA1);
++ writel(0, priv->base + IMX_OCOTP_ADDR_DATA2);
++ writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA3);
++ writel(0, priv->base + IMX_OCOTP_ADDR_DATA0);
++ break;
++ }
++ } else {
++ /* Non-banked i.MX6 mode */
++ writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA0);
++ }
+
+ /* 47.4.1.4.5
+ * Once complete, the controller will clear BUSY. A write request to a
+@@ -313,22 +368,27 @@ static struct nvmem_config imx_ocotp_nvmem_config = {
+
+ static const struct ocotp_params imx6q_params = {
+ .nregs = 128,
++ .bank_address_words = 0,
+ };
+
+ static const struct ocotp_params imx6sl_params = {
+ .nregs = 64,
++ .bank_address_words = 0,
+ };
+
+ static const struct ocotp_params imx6sx_params = {
+ .nregs = 128,
++ .bank_address_words = 0,
+ };
+
+ static const struct ocotp_params imx6ul_params = {
+ .nregs = 128,
++ .bank_address_words = 0,
+ };
+
+ static const struct ocotp_params imx7d_params = {
+ .nregs = 64,
++ .bank_address_words = 4,
+ };
+
+ static const struct of_device_id imx_ocotp_dt_ids[] = {
+--
+2.16.4
+
diff --git a/patches.drivers/nvmem-imx-ocotp-Enable-i.MX7D-OTP-write-support.patch b/patches.drivers/nvmem-imx-ocotp-Enable-i.MX7D-OTP-write-support.patch
new file mode 100644
index 0000000000..00b55950b7
--- /dev/null
+++ b/patches.drivers/nvmem-imx-ocotp-Enable-i.MX7D-OTP-write-support.patch
@@ -0,0 +1,38 @@
+From a32bab320fe1e9d5c4fd70f1d7ad92be46a9fcd3 Mon Sep 17 00:00:00 2001
+From: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Date: Tue, 24 Oct 2017 10:54:32 +0100
+Subject: [PATCH] nvmem: imx-ocotp: Enable i.MX7D OTP write support
+Git-commit: a32bab320fe1e9d5c4fd70f1d7ad92be46a9fcd3
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+After applying patches for both banked access and write timings we can
+re-enable the OTP write interface on i.MX7D processors.
+
+Fixes: 0642bac7da42 ("nvmem: imx-ocotp: add write support")
+
+Signed-off-by: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/nvmem/imx-ocotp.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
+index 10fc4a70a6e5..d56d481eca57 100644
+--- a/drivers/nvmem/imx-ocotp.c
++++ b/drivers/nvmem/imx-ocotp.c
+@@ -466,8 +466,6 @@ static int imx_ocotp_probe(struct platform_device *pdev)
+ imx_ocotp_nvmem_config.dev = dev;
+ imx_ocotp_nvmem_config.priv = priv;
+ priv->config = &imx_ocotp_nvmem_config;
+- if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx7d-ocotp"))
+- imx_ocotp_nvmem_config.read_only = true;
+ nvmem = nvmem_register(&imx_ocotp_nvmem_config);
+
+ if (IS_ERR(nvmem))
+--
+2.16.4
+
diff --git a/patches.drivers/nvmem-imx-ocotp-Move-i.MX6-write-clock-setup-to-dedi.patch b/patches.drivers/nvmem-imx-ocotp-Move-i.MX6-write-clock-setup-to-dedi.patch
new file mode 100644
index 0000000000..1e5c81bc94
--- /dev/null
+++ b/patches.drivers/nvmem-imx-ocotp-Move-i.MX6-write-clock-setup-to-dedi.patch
@@ -0,0 +1,99 @@
+From b50cb68f16ce393db040f755dcb26b9a246180c4 Mon Sep 17 00:00:00 2001
+From: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Date: Tue, 24 Oct 2017 10:54:30 +0100
+Subject: [PATCH] nvmem: imx-ocotp: Move i.MX6 write clock setup to dedicated function
+Git-commit: b50cb68f16ce393db040f755dcb26b9a246180c4
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+The i.MX7S/D has a different set of timing requirements, as a pre-cursor to
+adding the i.MX7 timing parameters, move the i.MX6 stuff to a dedicated
+function.
+
+Fixes: 0642bac7da42 ("nvmem: imx-ocotp: add write support")
+
+Signed-off-by: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/nvmem/imx-ocotp.c | 47 +++++++++++++++++++++++++++--------------------
+ 1 file changed, 27 insertions(+), 20 deletions(-)
+
+diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
+index bf95a0ecd0dc..8136ce8e77cd 100644
+--- a/drivers/nvmem/imx-ocotp.c
++++ b/drivers/nvmem/imx-ocotp.c
+@@ -168,6 +168,31 @@ static int imx_ocotp_read(void *context, unsigned int offset,
+ return ret;
+ }
+
++static void imx_ocotp_set_imx6_timing(struct ocotp_priv *priv)
++{
++ unsigned long clk_rate = 0;
++ unsigned long strobe_read, relax, strobe_prog;
++ u32 timing = 0;
++
++ /* 47.3.1.3.1
++ * Program HW_OCOTP_TIMING[STROBE_PROG] and HW_OCOTP_TIMING[RELAX]
++ * fields with timing values to match the current frequency of the
++ * ipg_clk. OTP writes will work at maximum bus frequencies as long
++ * as the HW_OCOTP_TIMING parameters are set correctly.
++ */
++ clk_rate = clk_get_rate(priv->clk);
++
++ relax = clk_rate / (1000000000 / DEF_RELAX) - 1;
++ strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1;
++ strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1;
++
++ timing = strobe_prog & 0x00000FFF;
++ timing |= (relax << 12) & 0x0000F000;
++ timing |= (strobe_read << 16) & 0x003F0000;
++
++ writel(timing, priv->base + IMX_OCOTP_ADDR_TIMING);
++}
++
+ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
+ size_t bytes)
+ {
+@@ -175,9 +200,6 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
+ u32 *buf = val;
+ int ret;
+
+- unsigned long clk_rate = 0;
+- unsigned long strobe_read, relax, strobe_prog;
+- u32 timing = 0;
+ u32 ctrl;
+ u8 waddr;
+ u8 word = 0;
+@@ -196,23 +218,8 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
+ return ret;
+ }
+
+- /* 47.3.1.3.1
+- * Program HW_OCOTP_TIMING[STROBE_PROG] and HW_OCOTP_TIMING[RELAX]
+- * fields with timing values to match the current frequency of the
+- * ipg_clk. OTP writes will work at maximum bus frequencies as long
+- * as the HW_OCOTP_TIMING parameters are set correctly.
+- */
+- clk_rate = clk_get_rate(priv->clk);
+-
+- relax = clk_rate / (1000000000 / DEF_RELAX) - 1;
+- strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1;
+- strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1;
+-
+- timing = strobe_prog & 0x00000FFF;
+- timing |= (relax << 12) & 0x0000F000;
+- timing |= (strobe_read << 16) & 0x003F0000;
+-
+- writel(timing, priv->base + IMX_OCOTP_ADDR_TIMING);
++ /* Setup the write timing values */
++ imx_ocotp_set_imx6_timing(priv);
+
+ /* 47.3.1.3.2
+ * Check that HW_OCOTP_CTRL[BUSY] and HW_OCOTP_CTRL[ERROR] are clear.
+--
+2.16.4
+
diff --git a/patches.drivers/nvmem-imx-ocotp-Pass-parameters-via-a-struct.patch b/patches.drivers/nvmem-imx-ocotp-Pass-parameters-via-a-struct.patch
new file mode 100644
index 0000000000..e858a17903
--- /dev/null
+++ b/patches.drivers/nvmem-imx-ocotp-Pass-parameters-via-a-struct.patch
@@ -0,0 +1,107 @@
+From e20d2b291ba2f5441fd4aacd746c21e60d48b559 Mon Sep 17 00:00:00 2001
+From: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Date: Tue, 24 Oct 2017 10:54:28 +0100
+Subject: [PATCH] nvmem: imx-ocotp: Pass parameters via a struct
+Git-commit: e20d2b291ba2f5441fd4aacd746c21e60d48b559
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+It will be useful in later patches to know the register access mode and
+bit-shift to apply to a given input offset.
+
+Fixes: 0642bac7da42 ("nvmem: imx-ocotp: add write support")
+
+Signed-off-by: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/nvmem/imx-ocotp.c | 44 ++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 34 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
+index 653cff9d9927..d94ed2d69a10 100644
+--- a/drivers/nvmem/imx-ocotp.c
++++ b/drivers/nvmem/imx-ocotp.c
+@@ -53,11 +53,15 @@
+
+ static DEFINE_MUTEX(ocotp_mutex);
+
++struct ocotp_params {
++ unsigned int nregs;
++};
++
+ struct ocotp_priv {
+ struct device *dev;
+ struct clk *clk;
+ void __iomem *base;
+- unsigned int nregs;
++ const struct ocotp_params *params;
+ struct nvmem_config *config;
+ };
+
+@@ -121,8 +125,8 @@ static int imx_ocotp_read(void *context, unsigned int offset,
+ index = offset >> 2;
+ count = bytes >> 2;
+
+- if (count > (priv->nregs - index))
+- count = priv->nregs - index;
++ if (count > (priv->params->nregs - index))
++ count = priv->params->nregs - index;
+
+ mutex_lock(&ocotp_mutex);
+
+@@ -307,12 +311,32 @@ static struct nvmem_config imx_ocotp_nvmem_config = {
+ .reg_write = imx_ocotp_write,
+ };
+
++static const struct ocotp_params imx6q_params = {
++ .nregs = 128,
++};
++
++static const struct ocotp_params imx6sl_params = {
++ .nregs = 64,
++};
++
++static const struct ocotp_params imx6sx_params = {
++ .nregs = 128,
++};
++
++static const struct ocotp_params imx6ul_params = {
++ .nregs = 128,
++};
++
++static const struct ocotp_params imx7d_params = {
++ .nregs = 64,
++};
++
+ static const struct of_device_id imx_ocotp_dt_ids[] = {
+- { .compatible = "fsl,imx6q-ocotp", (void *)128 },
+- { .compatible = "fsl,imx6sl-ocotp", (void *)64 },
+- { .compatible = "fsl,imx6sx-ocotp", (void *)128 },
+- { .compatible = "fsl,imx6ul-ocotp", (void *)128 },
+- { .compatible = "fsl,imx7d-ocotp", (void *)64 },
++ { .compatible = "fsl,imx6q-ocotp", .data = &imx6q_params },
++ { .compatible = "fsl,imx6sl-ocotp", .data = &imx6sl_params },
++ { .compatible = "fsl,imx6sx-ocotp", .data = &imx6sx_params },
++ { .compatible = "fsl,imx6ul-ocotp", .data = &imx6ul_params },
++ { .compatible = "fsl,imx7d-ocotp", .data = &imx7d_params },
+ { },
+ };
+ MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids);
+@@ -341,8 +365,8 @@ static int imx_ocotp_probe(struct platform_device *pdev)
+ return PTR_ERR(priv->clk);
+
+ of_id = of_match_device(imx_ocotp_dt_ids, dev);
+- priv->nregs = (unsigned long)of_id->data;
+- imx_ocotp_nvmem_config.size = 4 * priv->nregs;
++ priv->params = of_device_get_match_data(&pdev->dev);
++ imx_ocotp_nvmem_config.size = 4 * priv->params->nregs;
+ imx_ocotp_nvmem_config.dev = dev;
+ imx_ocotp_nvmem_config.priv = priv;
+ priv->config = &imx_ocotp_nvmem_config;
+--
+2.16.4
+
diff --git a/patches.drivers/nvmem-imx-ocotp-Restrict-OTP-write-to-IMX6-processor.patch b/patches.drivers/nvmem-imx-ocotp-Restrict-OTP-write-to-IMX6-processor.patch
new file mode 100644
index 0000000000..7649426048
--- /dev/null
+++ b/patches.drivers/nvmem-imx-ocotp-Restrict-OTP-write-to-IMX6-processor.patch
@@ -0,0 +1,43 @@
+From 9d6a8dab8d8b94975d7d78a7866053bd1c9444ca Mon Sep 17 00:00:00 2001
+From: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Date: Tue, 24 Oct 2017 10:54:27 +0100
+Subject: [PATCH] nvmem: imx-ocotp: Restrict OTP write to IMX6 processors
+Git-commit: 9d6a8dab8d8b94975d7d78a7866053bd1c9444ca
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+i.MX7S/D have a different scheme for addressing the OTP registers inside
+the OCOTP block. Currently it's possible to address the wrong OTP registers
+given the disparity between IMX6 and IMX7 OTP addressing.
+
+Since OTP programming is one-time destructive its important we restrict
+this interface ASAP.
+
+Fixes: 0642bac7da42 ("nvmem: imx-ocotp: add write support")
+
+Signed-off-by: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/nvmem/imx-ocotp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
+index e57e2a57aa3f..653cff9d9927 100644
+--- a/drivers/nvmem/imx-ocotp.c
++++ b/drivers/nvmem/imx-ocotp.c
+@@ -346,6 +346,8 @@ static int imx_ocotp_probe(struct platform_device *pdev)
+ imx_ocotp_nvmem_config.dev = dev;
+ imx_ocotp_nvmem_config.priv = priv;
+ priv->config = &imx_ocotp_nvmem_config;
++ if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx7d-ocotp"))
++ imx_ocotp_nvmem_config.read_only = true;
+ nvmem = nvmem_register(&imx_ocotp_nvmem_config);
+
+ if (IS_ERR(nvmem))
+--
+2.16.4
+
diff --git a/patches.drivers/nvmem-imx-ocotp-Update-module-description.patch b/patches.drivers/nvmem-imx-ocotp-Update-module-description.patch
new file mode 100644
index 0000000000..7d42e7f20a
--- /dev/null
+++ b/patches.drivers/nvmem-imx-ocotp-Update-module-description.patch
@@ -0,0 +1,36 @@
+From aef9a4de2afa25c02b1d112211ce29e6453ad210 Mon Sep 17 00:00:00 2001
+From: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Date: Tue, 24 Oct 2017 10:54:33 +0100
+Subject: [PATCH] nvmem: imx-ocotp: Update module description
+Git-commit: aef9a4de2afa25c02b1d112211ce29e6453ad210
+Patch-mainline: v4.15-rc1
+References: bsc#1051510
+
+This imx-ocotp driver encapsulates support for a subset of both i.MX6 and
+i.MX7 processors. Update the module description to reflect.
+
+Fixes: 711d45477931 ("nvmem: octop: Add i.MX7D support")
+
+Signed-off-by: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/nvmem/imx-ocotp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
+index d56d481eca57..d7ba351a70c9 100644
+--- a/drivers/nvmem/imx-ocotp.c
++++ b/drivers/nvmem/imx-ocotp.c
+@@ -494,5 +494,5 @@ static struct platform_driver imx_ocotp_driver = {
+ module_platform_driver(imx_ocotp_driver);
+
+ MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>");
+-MODULE_DESCRIPTION("i.MX6 OCOTP fuse box driver");
++MODULE_DESCRIPTION("i.MX6/i.MX7 OCOTP fuse box driver");
+ MODULE_LICENSE("GPL v2");
+--
+2.16.4
+
diff --git a/patches.drivers/nvmem-properly-handle-returned-value-nvmem_reg_read.patch b/patches.drivers/nvmem-properly-handle-returned-value-nvmem_reg_read.patch
new file mode 100644
index 0000000000..bc4ac39010
--- /dev/null
+++ b/patches.drivers/nvmem-properly-handle-returned-value-nvmem_reg_read.patch
@@ -0,0 +1,57 @@
+From 50808bfcc14b854775a9f1d0abe3dac2babcf5c3 Mon Sep 17 00:00:00 2001
+From: Mathieu Malaterre <malat@debian.org>
+Date: Fri, 11 May 2018 12:07:03 +0100
+Subject: [PATCH] nvmem: properly handle returned value nvmem_reg_read
+Git-commit: 50808bfcc14b854775a9f1d0abe3dac2babcf5c3
+Patch-mainline: v4.18-rc1
+References: bsc#1051510
+
+Function nvmem_reg_read can return a non zero value indicating an error.
+This returned value must be read and error propagated to
+nvmem_cell_prepare_write_buffer. Silence the following gcc warning (W=1):
+
+drivers/nvmem/core.c:1093:9: warning: variable 'rc' set but
+ not used [-Wunused-but-set-variable]
+
+Signed-off-by: Mathieu Malaterre <malat@debian.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/nvmem/core.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
+index 36361044ddbe..b5b0cdc21d01 100644
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -1119,6 +1119,8 @@ static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell,
+
+ /* setup the first byte with lsb bits from nvmem */
+ rc = nvmem_reg_read(nvmem, cell->offset, &v, 1);
++ if (rc)
++ goto err;
+ *b++ |= GENMASK(bit_offset - 1, 0) & v;
+
+ /* setup rest of the byte if any */
+@@ -1137,11 +1139,16 @@ static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell,
+ /* setup the last byte with msb bits from nvmem */
+ rc = nvmem_reg_read(nvmem,
+ cell->offset + cell->bytes - 1, &v, 1);
++ if (rc)
++ goto err;
+ *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v;
+
+ }
+
+ return buf;
++err:
++ kfree(buf);
++ return ERR_PTR(rc);
+ }
+
+ /**
+--
+2.16.4
+
diff --git a/patches.drivers/platform-chrome-cros_ec_proto-check-for-NULL-transfe.patch b/patches.drivers/platform-chrome-cros_ec_proto-check-for-NULL-transfe.patch
new file mode 100644
index 0000000000..ab94771df5
--- /dev/null
+++ b/patches.drivers/platform-chrome-cros_ec_proto-check-for-NULL-transfe.patch
@@ -0,0 +1,53 @@
+From 94d4e7af14a1170e34cf082d92e4c02de9e9fb88 Mon Sep 17 00:00:00 2001
+From: Enrico Granata <egranata@chromium.org>
+Date: Wed, 3 Apr 2019 15:40:36 -0700
+Subject: [PATCH] platform/chrome: cros_ec_proto: check for NULL transfer function
+Git-commit: 94d4e7af14a1170e34cf082d92e4c02de9e9fb88
+Patch-mainline: v5.2-rc1
+References: bsc#1051510
+
+As new transfer mechanisms are added to the EC codebase, they may
+not support v2 of the EC protocol.
+
+If the v3 initial handshake transfer fails, the kernel will try
+and call cmd_xfer as a fallback. If v2 is not supported, cmd_xfer
+will be NULL, and the code will end up causing a kernel panic.
+
+Add a check for NULL before calling the transfer function, along
+with a helpful comment explaining how one might end up in this
+situation.
+
+Signed-off-by: Enrico Granata <egranata@chromium.org>
+Reviewed-by: Jett Rink <jettrink@chromium.org>
+Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ drivers/platform/chrome/cros_ec_proto.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c
+index 97a068dff192..3bb954997ebc 100644
+--- a/drivers/platform/chrome/cros_ec_proto.c
++++ b/drivers/platform/chrome/cros_ec_proto.c
+@@ -56,6 +56,17 @@ static int send_command(struct cros_ec_device *ec_dev,
+ else
+ xfer_fxn = ec_dev->cmd_xfer;
+
++ if (!xfer_fxn) {
++ /*
++ * This error can happen if a communication error happened and
++ * the EC is trying to use protocol v2, on an underlying
++ * communication mechanism that does not support v2.
++ */
++ dev_err_once(ec_dev->dev,
++ "missing EC transfer API, cannot send command\n");
++ return -EIO;
++ }
++
+ ret = (*xfer_fxn)(ec_dev, msg);
+ if (msg->result == EC_RES_IN_PROGRESS) {
+ int i;
+--
+2.16.4
+
diff --git a/patches.drivers/platform-mellanox-Add-TmFifo-driver-for-Mellanox-Blu.patch b/patches.drivers/platform-mellanox-Add-TmFifo-driver-for-Mellanox-Blu.patch
new file mode 100644
index 0000000000..231a9e17a8
--- /dev/null
+++ b/patches.drivers/platform-mellanox-Add-TmFifo-driver-for-Mellanox-Blu.patch
@@ -0,0 +1,1410 @@
+From: Liming Sun <lsun@mellanox.com>
+Date: Fri, 3 May 2019 09:49:08 -0400
+Subject: platform/mellanox: Add TmFifo driver for Mellanox BlueField Soc
+Patch-mainline: v5.2-rc1
+Git-commit: 1357dfd7261fc2f625bf895f77bb57e8827b8f63
+References: bsc#1136333 jsc#SLE-4994
+
+This commit adds the TmFifo platform driver for Mellanox BlueField
+Soc. TmFifo is a shared FIFO which enables external host machine
+to exchange data with the SoC via USB or PCIe. The driver is based
+on virtio framework and has console and network access enabled.
+
+Reviewed-by: Vadim Pasternak <vadimp@mellanox.com>
+Signed-off-by: Liming Sun <lsun@mellanox.com>
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+---
+ drivers/platform/mellanox/Kconfig | 12
+ drivers/platform/mellanox/Makefile | 1
+ drivers/platform/mellanox/mlxbf-tmfifo-regs.h | 63 +
+ drivers/platform/mellanox/mlxbf-tmfifo.c | 1281 ++++++++++++++++++++++++++
+ 4 files changed, 1356 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/platform/mellanox/mlxbf-tmfifo-regs.h
+ create mode 100644 drivers/platform/mellanox/mlxbf-tmfifo.c
+
+--- a/drivers/platform/mellanox/Kconfig
++++ b/drivers/platform/mellanox/Kconfig
+@@ -5,7 +5,7 @@
+
+ menuconfig MELLANOX_PLATFORM
+ bool "Platform support for Mellanox hardware"
+- depends on X86 || ARM || COMPILE_TEST
++ depends on X86 || ARM || ARM64 || COMPILE_TEST
+ ---help---
+ Say Y here to get to see options for platform support for
+ Mellanox systems. This option alone does not add any kernel code.
+@@ -34,4 +34,14 @@ config MLXREG_IO
+ to system resets operation, system reset causes monitoring and some
+ kinds of mux selection.
+
++config MLXBF_TMFIFO
++ tristate "Mellanox BlueField SoC TmFifo platform driver"
++ depends on ARM64
++ depends on ACPI
++ depends on VIRTIO_CONSOLE && VIRTIO_NET
++ help
++ Say y here to enable TmFifo support. The TmFifo driver provides
++ platform driver support for the TmFifo which supports console
++ and networking based on the virtio framework.
++
+ endif # MELLANOX_PLATFORM
+--- a/drivers/platform/mellanox/Makefile
++++ b/drivers/platform/mellanox/Makefile
+@@ -3,5 +3,6 @@
+ # Makefile for linux/drivers/platform/mellanox
+ # Mellanox Platform-Specific Drivers
+ #
++obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o
+ obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
+ obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o
+--- /dev/null
++++ b/drivers/platform/mellanox/mlxbf-tmfifo-regs.h
+@@ -0,0 +1,63 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (c) 2019, Mellanox Technologies. All rights reserved.
++ */
++
++#ifndef __MLXBF_TMFIFO_REGS_H__
++#define __MLXBF_TMFIFO_REGS_H__
++
++#include <linux/types.h>
++#include <linux/bits.h>
++
++#define MLXBF_TMFIFO_TX_DATA 0x00
++#define MLXBF_TMFIFO_TX_STS 0x08
++#define MLXBF_TMFIFO_TX_STS__LENGTH 0x0001
++#define MLXBF_TMFIFO_TX_STS__COUNT_SHIFT 0
++#define MLXBF_TMFIFO_TX_STS__COUNT_WIDTH 9
++#define MLXBF_TMFIFO_TX_STS__COUNT_RESET_VAL 0
++#define MLXBF_TMFIFO_TX_STS__COUNT_RMASK GENMASK_ULL(8, 0)
++#define MLXBF_TMFIFO_TX_STS__COUNT_MASK GENMASK_ULL(8, 0)
++#define MLXBF_TMFIFO_TX_CTL 0x10
++#define MLXBF_TMFIFO_TX_CTL__LENGTH 0x0001
++#define MLXBF_TMFIFO_TX_CTL__LWM_SHIFT 0
++#define MLXBF_TMFIFO_TX_CTL__LWM_WIDTH 8
++#define MLXBF_TMFIFO_TX_CTL__LWM_RESET_VAL 128
++#define MLXBF_TMFIFO_TX_CTL__LWM_RMASK GENMASK_ULL(7, 0)
++#define MLXBF_TMFIFO_TX_CTL__LWM_MASK GENMASK_ULL(7, 0)
++#define MLXBF_TMFIFO_TX_CTL__HWM_SHIFT 8
++#define MLXBF_TMFIFO_TX_CTL__HWM_WIDTH 8
++#define MLXBF_TMFIFO_TX_CTL__HWM_RESET_VAL 128
++#define MLXBF_TMFIFO_TX_CTL__HWM_RMASK GENMASK_ULL(7, 0)
++#define MLXBF_TMFIFO_TX_CTL__HWM_MASK GENMASK_ULL(15, 8)
++#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_SHIFT 32
++#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_WIDTH 9
++#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_RESET_VAL 256
++#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_RMASK GENMASK_ULL(8, 0)
++#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_MASK GENMASK_ULL(40, 32)
++#define MLXBF_TMFIFO_RX_DATA 0x00
++#define MLXBF_TMFIFO_RX_STS 0x08
++#define MLXBF_TMFIFO_RX_STS__LENGTH 0x0001
++#define MLXBF_TMFIFO_RX_STS__COUNT_SHIFT 0
++#define MLXBF_TMFIFO_RX_STS__COUNT_WIDTH 9
++#define MLXBF_TMFIFO_RX_STS__COUNT_RESET_VAL 0
++#define MLXBF_TMFIFO_RX_STS__COUNT_RMASK GENMASK_ULL(8, 0)
++#define MLXBF_TMFIFO_RX_STS__COUNT_MASK GENMASK_ULL(8, 0)
++#define MLXBF_TMFIFO_RX_CTL 0x10
++#define MLXBF_TMFIFO_RX_CTL__LENGTH 0x0001
++#define MLXBF_TMFIFO_RX_CTL__LWM_SHIFT 0
++#define MLXBF_TMFIFO_RX_CTL__LWM_WIDTH 8
++#define MLXBF_TMFIFO_RX_CTL__LWM_RESET_VAL 128
++#define MLXBF_TMFIFO_RX_CTL__LWM_RMASK GENMASK_ULL(7, 0)
++#define MLXBF_TMFIFO_RX_CTL__LWM_MASK GENMASK_ULL(7, 0)
++#define MLXBF_TMFIFO_RX_CTL__HWM_SHIFT 8
++#define MLXBF_TMFIFO_RX_CTL__HWM_WIDTH 8
++#define MLXBF_TMFIFO_RX_CTL__HWM_RESET_VAL 128
++#define MLXBF_TMFIFO_RX_CTL__HWM_RMASK GENMASK_ULL(7, 0)
++#define MLXBF_TMFIFO_RX_CTL__HWM_MASK GENMASK_ULL(15, 8)
++#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_SHIFT 32
++#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_WIDTH 9
++#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_RESET_VAL 256
++#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_RMASK GENMASK_ULL(8, 0)
++#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK GENMASK_ULL(40, 32)
++
++#endif /* !defined(__MLXBF_TMFIFO_REGS_H__) */
+--- /dev/null
++++ b/drivers/platform/mellanox/mlxbf-tmfifo.c
+@@ -0,0 +1,1281 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Mellanox BlueField SoC TmFifo driver
++ *
++ * Copyright (C) 2019 Mellanox Technologies
++ */
++
++#include <linux/acpi.h>
++#include <linux/bitfield.h>
++#include <linux/circ_buf.h>
++#include <linux/efi.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/platform_device.h>
++#include <linux/types.h>
++
++#include <linux/virtio_config.h>
++#include <linux/virtio_console.h>
++#include <linux/virtio_ids.h>
++#include <linux/virtio_net.h>
++#include <linux/virtio_ring.h>
++
++#include "mlxbf-tmfifo-regs.h"
++
++/* Vring size. */
++#define MLXBF_TMFIFO_VRING_SIZE SZ_1K
++
++/* Console Tx buffer size. */
++#define MLXBF_TMFIFO_CON_TX_BUF_SIZE SZ_32K
++
++/* Console Tx buffer reserved space. */
++#define MLXBF_TMFIFO_CON_TX_BUF_RSV_SIZE 8
++
++/* House-keeping timer interval. */
++#define MLXBF_TMFIFO_TIMER_INTERVAL (HZ / 10)
++
++/* Virtual devices sharing the TM FIFO. */
++#define MLXBF_TMFIFO_VDEV_MAX (VIRTIO_ID_CONSOLE + 1)
++
++/*
++ * Reserve 1/16 of TmFifo space, so console messages are not starved by
++ * the networking traffic.
++ */
++#define MLXBF_TMFIFO_RESERVE_RATIO 16
++
++/* Message with data needs at least two words (for header & data). */
++#define MLXBF_TMFIFO_DATA_MIN_WORDS 2
++
++struct mlxbf_tmfifo;
++
++/**
++ * mlxbf_tmfifo_vring - Structure of the TmFifo virtual ring
++ * @va: virtual address of the ring
++ * @dma: dma address of the ring
++ * @vq: pointer to the virtio virtqueue
++ * @desc: current descriptor of the pending packet
++ * @desc_head: head descriptor of the pending packet
++ * @cur_len: processed length of the current descriptor
++ * @rem_len: remaining length of the pending packet
++ * @pkt_len: total length of the pending packet
++ * @next_avail: next avail descriptor id
++ * @num: vring size (number of descriptors)
++ * @align: vring alignment size
++ * @index: vring index
++ * @vdev_id: vring virtio id (VIRTIO_ID_xxx)
++ * @fifo: pointer to the tmfifo structure
++ */
++struct mlxbf_tmfifo_vring {
++ void *va;
++ dma_addr_t dma;
++ struct virtqueue *vq;
++ struct vring_desc *desc;
++ struct vring_desc *desc_head;
++ int cur_len;
++ int rem_len;
++ u32 pkt_len;
++ u16 next_avail;
++ int num;
++ int align;
++ int index;
++ int vdev_id;
++ struct mlxbf_tmfifo *fifo;
++};
++
++/* Interrupt types. */
++enum {
++ MLXBF_TM_RX_LWM_IRQ,
++ MLXBF_TM_RX_HWM_IRQ,
++ MLXBF_TM_TX_LWM_IRQ,
++ MLXBF_TM_TX_HWM_IRQ,
++ MLXBF_TM_MAX_IRQ
++};
++
++/* Ring types (Rx & Tx). */
++enum {
++ MLXBF_TMFIFO_VRING_RX,
++ MLXBF_TMFIFO_VRING_TX,
++ MLXBF_TMFIFO_VRING_MAX
++};
++
++/**
++ * mlxbf_tmfifo_vdev - Structure of the TmFifo virtual device
++ * @vdev: virtio device, in which the vdev.id.device field has the
++ * VIRTIO_ID_xxx id to distinguish the virtual device.
++ * @status: status of the device
++ * @features: supported features of the device
++ * @vrings: array of tmfifo vrings of this device
++ * @config.cons: virtual console config -
++ * select if vdev.id.device is VIRTIO_ID_CONSOLE
++ * @config.net: virtual network config -
++ * select if vdev.id.device is VIRTIO_ID_NET
++ * @tx_buf: tx buffer used to buffer data before writing into the FIFO
++ */
++struct mlxbf_tmfifo_vdev {
++ struct virtio_device vdev;
++ u8 status;
++ u64 features;
++ struct mlxbf_tmfifo_vring vrings[MLXBF_TMFIFO_VRING_MAX];
++ union {
++ struct virtio_console_config cons;
++ struct virtio_net_config net;
++ } config;
++ struct circ_buf tx_buf;
++};
++
++/**
++ * mlxbf_tmfifo_irq_info - Structure of the interrupt information
++ * @fifo: pointer to the tmfifo structure
++ * @irq: interrupt number
++ * @index: index into the interrupt array
++ */
++struct mlxbf_tmfifo_irq_info {
++ struct mlxbf_tmfifo *fifo;
++ int irq;
++ int index;
++};
++
++/**
++ * mlxbf_tmfifo - Structure of the TmFifo
++ * @vdev: array of the virtual devices running over the TmFifo
++ * @lock: lock to protect the TmFifo access
++ * @rx_base: mapped register base address for the Rx FIFO
++ * @tx_base: mapped register base address for the Tx FIFO
++ * @rx_fifo_size: number of entries of the Rx FIFO
++ * @tx_fifo_size: number of entries of the Tx FIFO
++ * @pend_events: pending bits for deferred events
++ * @irq_info: interrupt information
++ * @work: work struct for deferred process
++ * @timer: background timer
++ * @vring: Tx/Rx ring
++ * @spin_lock: spin lock
++ * @is_ready: ready flag
++ */
++struct mlxbf_tmfifo {
++ struct mlxbf_tmfifo_vdev *vdev[MLXBF_TMFIFO_VDEV_MAX];
++ struct mutex lock; /* TmFifo lock */
++ void __iomem *rx_base;
++ void __iomem *tx_base;
++ int rx_fifo_size;
++ int tx_fifo_size;
++ unsigned long pend_events;
++ struct mlxbf_tmfifo_irq_info irq_info[MLXBF_TM_MAX_IRQ];
++ struct work_struct work;
++ struct timer_list timer;
++ struct mlxbf_tmfifo_vring *vring[2];
++ spinlock_t spin_lock; /* spin lock */
++ bool is_ready;
++};
++
++/**
++ * mlxbf_tmfifo_msg_hdr - Structure of the TmFifo message header
++ * @type: message type
++ * @len: payload length in network byte order. Messages sent into the FIFO
++ * will be read by the other side as data stream in the same byte order.
++ * The length needs to be encoded into network order so both sides
++ * could understand it.
++ */
++struct mlxbf_tmfifo_msg_hdr {
++ u8 type;
++ __be16 len;
++ u8 unused[5];
++} __packed __aligned(sizeof(u64));
++
++/*
++ * Default MAC.
++ * This MAC address will be read from EFI persistent variable if configured.
++ * It can also be reconfigured with standard Linux tools.
++ */
++static u8 mlxbf_tmfifo_net_default_mac[ETH_ALEN] = {
++ 0x00, 0x1A, 0xCA, 0xFF, 0xFF, 0x01
++};
++
++/* EFI variable name of the MAC address. */
++static efi_char16_t mlxbf_tmfifo_efi_name[] = L"RshimMacAddr";
++
++/* Maximum L2 header length. */
++#define MLXBF_TMFIFO_NET_L2_OVERHEAD 36
++
++/* Supported virtio-net features. */
++#define MLXBF_TMFIFO_NET_FEATURES \
++ (BIT_ULL(VIRTIO_NET_F_MTU) | BIT_ULL(VIRTIO_NET_F_STATUS) | \
++ BIT_ULL(VIRTIO_NET_F_MAC))
++
++#define mlxbf_vdev_to_tmfifo(d) container_of(d, struct mlxbf_tmfifo_vdev, vdev)
++
++/* Free vrings of the FIFO device. */
++static void mlxbf_tmfifo_free_vrings(struct mlxbf_tmfifo *fifo,
++ struct mlxbf_tmfifo_vdev *tm_vdev)
++{
++ struct mlxbf_tmfifo_vring *vring;
++ int i, size;
++
++ for (i = 0; i < ARRAY_SIZE(tm_vdev->vrings); i++) {
++ vring = &tm_vdev->vrings[i];
++ if (vring->va) {
++ size = vring_size(vring->num, vring->align);
++ dma_free_coherent(tm_vdev->vdev.dev.parent, size,
++ vring->va, vring->dma);
++ vring->va = NULL;
++ if (vring->vq) {
++ vring_del_virtqueue(vring->vq);
++ vring->vq = NULL;
++ }
++ }
++ }
++}
++
++/* Allocate vrings for the FIFO. */
++static int mlxbf_tmfifo_alloc_vrings(struct mlxbf_tmfifo *fifo,
++ struct mlxbf_tmfifo_vdev *tm_vdev)
++{
++ struct mlxbf_tmfifo_vring *vring;
++ struct device *dev;
++ dma_addr_t dma;
++ int i, size;
++ void *va;
++
++ for (i = 0; i < ARRAY_SIZE(tm_vdev->vrings); i++) {
++ vring = &tm_vdev->vrings[i];
++ vring->fifo = fifo;
++ vring->num = MLXBF_TMFIFO_VRING_SIZE;
++ vring->align = SMP_CACHE_BYTES;
++ vring->index = i;
++ vring->vdev_id = tm_vdev->vdev.id.device;
++ dev = &tm_vdev->vdev.dev;
++
++ size = vring_size(vring->num, vring->align);
++ va = dma_alloc_coherent(dev->parent, size, &dma, GFP_KERNEL);
++ if (!va) {
++ mlxbf_tmfifo_free_vrings(fifo, tm_vdev);
++ dev_err(dev->parent, "dma_alloc_coherent failed\n");
++ return -ENOMEM;
++ }
++
++ vring->va = va;
++ vring->dma = dma;
++ }
++
++ return 0;
++}
++
++/* Disable interrupts of the FIFO device. */
++static void mlxbf_tmfifo_disable_irqs(struct mlxbf_tmfifo *fifo)
++{
++ int i, irq;
++
++ for (i = 0; i < MLXBF_TM_MAX_IRQ; i++) {
++ irq = fifo->irq_info[i].irq;
++ fifo->irq_info[i].irq = 0;
++ disable_irq(irq);
++ }
++}
++
++/* Interrupt handler. */
++static irqreturn_t mlxbf_tmfifo_irq_handler(int irq, void *arg)
++{
++ struct mlxbf_tmfifo_irq_info *irq_info = arg;
++
++ if (!test_and_set_bit(irq_info->index, &irq_info->fifo->pend_events))
++ schedule_work(&irq_info->fifo->work);
++
++ return IRQ_HANDLED;
++}
++
++/* Get the next packet descriptor from the vring. */
++static struct vring_desc *
++mlxbf_tmfifo_get_next_desc(struct mlxbf_tmfifo_vring *vring)
++{
++ const struct vring *vr = virtqueue_get_vring(vring->vq);
++ struct virtio_device *vdev = vring->vq->vdev;
++ unsigned int idx, head;
++
++ if (vring->next_avail == virtio16_to_cpu(vdev, vr->avail->idx))
++ return NULL;
++
++ idx = vring->next_avail % vr->num;
++ head = virtio16_to_cpu(vdev, vr->avail->ring[idx]);
++ if (WARN_ON(head >= vr->num))
++ return NULL;
++
++ vring->next_avail++;
++
++ return &vr->desc[head];
++}
++
++/* Release virtio descriptor. */
++static void mlxbf_tmfifo_release_desc(struct mlxbf_tmfifo_vring *vring,
++ struct vring_desc *desc, u32 len)
++{
++ const struct vring *vr = virtqueue_get_vring(vring->vq);
++ struct virtio_device *vdev = vring->vq->vdev;
++ u16 idx, vr_idx;
++
++ vr_idx = virtio16_to_cpu(vdev, vr->used->idx);
++ idx = vr_idx % vr->num;
++ vr->used->ring[idx].id = cpu_to_virtio32(vdev, desc - vr->desc);
++ vr->used->ring[idx].len = cpu_to_virtio32(vdev, len);
++
++ /*
++ * Virtio could poll and check the 'idx' to decide whether the desc is
++ * done or not. Add a memory barrier here to make sure the update above
++ * completes before updating the idx.
++ */
++ mb();
++ vr->used->idx = cpu_to_virtio16(vdev, vr_idx + 1);
++}
++
++/* Get the total length of the descriptor chain. */
++static u32 mlxbf_tmfifo_get_pkt_len(struct mlxbf_tmfifo_vring *vring,
++ struct vring_desc *desc)
++{
++ const struct vring *vr = virtqueue_get_vring(vring->vq);
++ struct virtio_device *vdev = vring->vq->vdev;
++ u32 len = 0, idx;
++
++ while (desc) {
++ len += virtio32_to_cpu(vdev, desc->len);
++ if (!(virtio16_to_cpu(vdev, desc->flags) & VRING_DESC_F_NEXT))
++ break;
++ idx = virtio16_to_cpu(vdev, desc->next);
++ desc = &vr->desc[idx];
++ }
++
++ return len;
++}
++
++static void mlxbf_tmfifo_release_pending_pkt(struct mlxbf_tmfifo_vring *vring)
++{
++ struct vring_desc *desc_head;
++ u32 len = 0;
++
++ if (vring->desc_head) {
++ desc_head = vring->desc_head;
++ len = vring->pkt_len;
++ } else {
++ desc_head = mlxbf_tmfifo_get_next_desc(vring);
++ len = mlxbf_tmfifo_get_pkt_len(vring, desc_head);
++ }
++
++ if (desc_head)
++ mlxbf_tmfifo_release_desc(vring, desc_head, len);
++
++ vring->pkt_len = 0;
++ vring->desc = NULL;
++ vring->desc_head = NULL;
++}
++
++static void mlxbf_tmfifo_init_net_desc(struct mlxbf_tmfifo_vring *vring,
++ struct vring_desc *desc, bool is_rx)
++{
++ struct virtio_device *vdev = vring->vq->vdev;
++ struct virtio_net_hdr *net_hdr;
++
++ net_hdr = phys_to_virt(virtio64_to_cpu(vdev, desc->addr));
++ memset(net_hdr, 0, sizeof(*net_hdr));
++}
++
++/* Get and initialize the next packet. */
++static struct vring_desc *
++mlxbf_tmfifo_get_next_pkt(struct mlxbf_tmfifo_vring *vring, bool is_rx)
++{
++ struct vring_desc *desc;
++
++ desc = mlxbf_tmfifo_get_next_desc(vring);
++ if (desc && is_rx && vring->vdev_id == VIRTIO_ID_NET)
++ mlxbf_tmfifo_init_net_desc(vring, desc, is_rx);
++
++ vring->desc_head = desc;
++ vring->desc = desc;
++
++ return desc;
++}
++
++/* House-keeping timer. */
++static void mlxbf_tmfifo_timer(struct timer_list *t)
++{
++ struct mlxbf_tmfifo *fifo = container_of(t, struct mlxbf_tmfifo, timer);
++ int rx, tx;
++
++ rx = !test_and_set_bit(MLXBF_TM_RX_HWM_IRQ, &fifo->pend_events);
++ tx = !test_and_set_bit(MLXBF_TM_TX_LWM_IRQ, &fifo->pend_events);
++
++ if (rx || tx)
++ schedule_work(&fifo->work);
++
++ mod_timer(&fifo->timer, jiffies + MLXBF_TMFIFO_TIMER_INTERVAL);
++}
++
++/* Copy one console packet into the output buffer. */
++static void mlxbf_tmfifo_console_output_one(struct mlxbf_tmfifo_vdev *cons,
++ struct mlxbf_tmfifo_vring *vring,
++ struct vring_desc *desc)
++{
++ const struct vring *vr = virtqueue_get_vring(vring->vq);
++ struct virtio_device *vdev = &cons->vdev;
++ u32 len, idx, seg;
++ void *addr;
++
++ while (desc) {
++ addr = phys_to_virt(virtio64_to_cpu(vdev, desc->addr));
++ len = virtio32_to_cpu(vdev, desc->len);
++
++ seg = CIRC_SPACE_TO_END(cons->tx_buf.head, cons->tx_buf.tail,
++ MLXBF_TMFIFO_CON_TX_BUF_SIZE);
++ if (len <= seg) {
++ memcpy(cons->tx_buf.buf + cons->tx_buf.head, addr, len);
++ } else {
++ memcpy(cons->tx_buf.buf + cons->tx_buf.head, addr, seg);
++ addr += seg;
++ memcpy(cons->tx_buf.buf, addr, len - seg);
++ }
++ cons->tx_buf.head = (cons->tx_buf.head + len) %
++ MLXBF_TMFIFO_CON_TX_BUF_SIZE;
++
++ if (!(virtio16_to_cpu(vdev, desc->flags) & VRING_DESC_F_NEXT))
++ break;
++ idx = virtio16_to_cpu(vdev, desc->next);
++ desc = &vr->desc[idx];
++ }
++}
++
++/* Copy console data into the output buffer. */
++static void mlxbf_tmfifo_console_output(struct mlxbf_tmfifo_vdev *cons,
++ struct mlxbf_tmfifo_vring *vring)
++{
++ struct vring_desc *desc;
++ u32 len, avail;
++
++ desc = mlxbf_tmfifo_get_next_desc(vring);
++ while (desc) {
++ /* Release the packet if not enough space. */
++ len = mlxbf_tmfifo_get_pkt_len(vring, desc);
++ avail = CIRC_SPACE(cons->tx_buf.head, cons->tx_buf.tail,
++ MLXBF_TMFIFO_CON_TX_BUF_SIZE);
++ if (len + MLXBF_TMFIFO_CON_TX_BUF_RSV_SIZE > avail) {
++ mlxbf_tmfifo_release_desc(vring, desc, len);
++ break;
++ }
++
++ mlxbf_tmfifo_console_output_one(cons, vring, desc);
++ mlxbf_tmfifo_release_desc(vring, desc, len);
++ desc = mlxbf_tmfifo_get_next_desc(vring);
++ }
++}
++
++/* Get the number of available words in Rx FIFO for receiving. */
++static int mlxbf_tmfifo_get_rx_avail(struct mlxbf_tmfifo *fifo)
++{
++ u64 sts;
++
++ sts = readq(fifo->rx_base + MLXBF_TMFIFO_RX_STS);
++ return FIELD_GET(MLXBF_TMFIFO_RX_STS__COUNT_MASK, sts);
++}
++
++/* Get the number of available words in the TmFifo for sending. */
++static int mlxbf_tmfifo_get_tx_avail(struct mlxbf_tmfifo *fifo, int vdev_id)
++{
++ int tx_reserve;
++ u32 count;
++ u64 sts;
++
++ /* Reserve some room in FIFO for console messages. */
++ if (vdev_id == VIRTIO_ID_NET)
++ tx_reserve = fifo->tx_fifo_size / MLXBF_TMFIFO_RESERVE_RATIO;
++ else
++ tx_reserve = 1;
++
++ sts = readq(fifo->tx_base + MLXBF_TMFIFO_TX_STS);
++ count = FIELD_GET(MLXBF_TMFIFO_TX_STS__COUNT_MASK, sts);
++ return fifo->tx_fifo_size - tx_reserve - count;
++}
++
++/* Console Tx (move data from the output buffer into the TmFifo). */
++static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail)
++{
++ struct mlxbf_tmfifo_msg_hdr hdr;
++ struct mlxbf_tmfifo_vdev *cons;
++ unsigned long flags;
++ int size, seg;
++ void *addr;
++ u64 data;
++
++ /* Return if not enough space available. */
++ if (avail < MLXBF_TMFIFO_DATA_MIN_WORDS)
++ return;
++
++ cons = fifo->vdev[VIRTIO_ID_CONSOLE];
++ if (!cons || !cons->tx_buf.buf)
++ return;
++
++ /* Return if no data to send. */
++ size = CIRC_CNT(cons->tx_buf.head, cons->tx_buf.tail,
++ MLXBF_TMFIFO_CON_TX_BUF_SIZE);
++ if (size == 0)
++ return;
++
++ /* Adjust the size to available space. */
++ if (size + sizeof(hdr) > avail * sizeof(u64))
++ size = avail * sizeof(u64) - sizeof(hdr);
++
++ /* Write header. */
++ hdr.type = VIRTIO_ID_CONSOLE;
++ hdr.len = htons(size);
++ writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
++
++ /* Use spin-lock to protect the 'cons->tx_buf'. */
++ spin_lock_irqsave(&fifo->spin_lock, flags);
++
++ while (size > 0) {
++ addr = cons->tx_buf.buf + cons->tx_buf.tail;
++
++ seg = CIRC_CNT_TO_END(cons->tx_buf.head, cons->tx_buf.tail,
++ MLXBF_TMFIFO_CON_TX_BUF_SIZE);
++ if (seg >= sizeof(u64)) {
++ memcpy(&data, addr, sizeof(u64));
++ } else {
++ memcpy(&data, addr, seg);
++ memcpy((u8 *)&data + seg, cons->tx_buf.buf,
++ sizeof(u64) - seg);
++ }
++ writeq(data, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
++
++ if (size >= sizeof(u64)) {
++ cons->tx_buf.tail = (cons->tx_buf.tail + sizeof(u64)) %
++ MLXBF_TMFIFO_CON_TX_BUF_SIZE;
++ size -= sizeof(u64);
++ } else {
++ cons->tx_buf.tail = (cons->tx_buf.tail + size) %
++ MLXBF_TMFIFO_CON_TX_BUF_SIZE;
++ size = 0;
++ }
++ }
++
++ spin_unlock_irqrestore(&fifo->spin_lock, flags);
++}
++
++/* Rx/Tx one word in the descriptor buffer. */
++static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring,
++ struct vring_desc *desc,
++ bool is_rx, int len)
++{
++ struct virtio_device *vdev = vring->vq->vdev;
++ struct mlxbf_tmfifo *fifo = vring->fifo;
++ void *addr;
++ u64 data;
++
++ /* Get the buffer address of this desc. */
++ addr = phys_to_virt(virtio64_to_cpu(vdev, desc->addr));
++
++ /* Read a word from FIFO for Rx. */
++ if (is_rx)
++ data = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA);
++
++ if (vring->cur_len + sizeof(u64) <= len) {
++ /* The whole word. */
++ if (is_rx)
++ memcpy(addr + vring->cur_len, &data, sizeof(u64));
++ else
++ memcpy(&data, addr + vring->cur_len, sizeof(u64));
++ vring->cur_len += sizeof(u64);
++ } else {
++ /* Leftover bytes. */
++ if (is_rx)
++ memcpy(addr + vring->cur_len, &data,
++ len - vring->cur_len);
++ else
++ memcpy(&data, addr + vring->cur_len,
++ len - vring->cur_len);
++ vring->cur_len = len;
++ }
++
++ /* Write the word into FIFO for Tx. */
++ if (!is_rx)
++ writeq(data, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
++}
++
++/*
++ * Rx/Tx packet header.
++ *
++ * In Rx case, the packet might be found to belong to a different vring since
++ * the TmFifo is shared by different services. In such case, the 'vring_change'
++ * flag is set.
++ */
++static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring,
++ struct vring_desc *desc,
++ bool is_rx, bool *vring_change)
++{
++ struct mlxbf_tmfifo *fifo = vring->fifo;
++ struct virtio_net_config *config;
++ struct mlxbf_tmfifo_msg_hdr hdr;
++ int vdev_id, hdr_len;
++
++ /* Read/Write packet header. */
++ if (is_rx) {
++ /* Drain one word from the FIFO. */
++ *(u64 *)&hdr = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA);
++
++ /* Skip the length 0 packets (keepalive). */
++ if (hdr.len == 0)
++ return;
++
++ /* Check packet type. */
++ if (hdr.type == VIRTIO_ID_NET) {
++ vdev_id = VIRTIO_ID_NET;
++ hdr_len = sizeof(struct virtio_net_hdr);
++ config = &fifo->vdev[vdev_id]->config.net;
++ if (ntohs(hdr.len) > config->mtu +
++ MLXBF_TMFIFO_NET_L2_OVERHEAD)
++ return;
++ } else {
++ vdev_id = VIRTIO_ID_CONSOLE;
++ hdr_len = 0;
++ }
++
++ /*
++ * Check whether the new packet still belongs to this vring.
++ * If not, update the pkt_len of the new vring.
++ */
++ if (vdev_id != vring->vdev_id) {
++ struct mlxbf_tmfifo_vdev *tm_dev2 = fifo->vdev[vdev_id];
++
++ if (!tm_dev2)
++ return;
++ vring->desc = desc;
++ vring = &tm_dev2->vrings[MLXBF_TMFIFO_VRING_RX];
++ *vring_change = true;
++ }
++ vring->pkt_len = ntohs(hdr.len) + hdr_len;
++ } else {
++ /* Network virtio has an extra header. */
++ hdr_len = (vring->vdev_id == VIRTIO_ID_NET) ?
++ sizeof(struct virtio_net_hdr) : 0;
++ vring->pkt_len = mlxbf_tmfifo_get_pkt_len(vring, desc);
++ hdr.type = (vring->vdev_id == VIRTIO_ID_NET) ?
++ VIRTIO_ID_NET : VIRTIO_ID_CONSOLE;
++ hdr.len = htons(vring->pkt_len - hdr_len);
++ writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
++ }
++
++ vring->cur_len = hdr_len;
++ vring->rem_len = vring->pkt_len;
++ fifo->vring[is_rx] = vring;
++}
++
++/*
++ * Rx/Tx one descriptor.
++ *
++ * Return true to indicate more data available.
++ */
++static bool mlxbf_tmfifo_rxtx_one_desc(struct mlxbf_tmfifo_vring *vring,
++ bool is_rx, int *avail)
++{
++ const struct vring *vr = virtqueue_get_vring(vring->vq);
++ struct mlxbf_tmfifo *fifo = vring->fifo;
++ struct virtio_device *vdev;
++ bool vring_change = false;
++ struct vring_desc *desc;
++ unsigned long flags;
++ u32 len, idx;
++
++ vdev = &fifo->vdev[vring->vdev_id]->vdev;
++
++ /* Get the descriptor of the next packet. */
++ if (!vring->desc) {
++ desc = mlxbf_tmfifo_get_next_pkt(vring, is_rx);
++ if (!desc)
++ return false;
++ } else {
++ desc = vring->desc;
++ }
++
++ /* Beginning of a packet. Start to Rx/Tx packet header. */
++ if (vring->pkt_len == 0) {
++ mlxbf_tmfifo_rxtx_header(vring, desc, is_rx, &vring_change);
++ (*avail)--;
++
++ /* Return if new packet is for another ring. */
++ if (vring_change)
++ return false;
++ goto mlxbf_tmfifo_desc_done;
++ }
++
++ /* Get the length of this desc. */
++ len = virtio32_to_cpu(vdev, desc->len);
++ if (len > vring->rem_len)
++ len = vring->rem_len;
++
++ /* Rx/Tx one word (8 bytes) if not done. */
++ if (vring->cur_len < len) {
++ mlxbf_tmfifo_rxtx_word(vring, desc, is_rx, len);
++ (*avail)--;
++ }
++
++ /* Check again whether it's done. */
++ if (vring->cur_len == len) {
++ vring->cur_len = 0;
++ vring->rem_len -= len;
++
++ /* Get the next desc on the chain. */
++ if (vring->rem_len > 0 &&
++ (virtio16_to_cpu(vdev, desc->flags) & VRING_DESC_F_NEXT)) {
++ idx = virtio16_to_cpu(vdev, desc->next);
++ desc = &vr->desc[idx];
++ goto mlxbf_tmfifo_desc_done;
++ }
++
++ /* Done and release the pending packet. */
++ mlxbf_tmfifo_release_pending_pkt(vring);
++ desc = NULL;
++ fifo->vring[is_rx] = NULL;
++
++ /* Notify upper layer that packet is done. */
++ spin_lock_irqsave(&fifo->spin_lock, flags);
++ vring_interrupt(0, vring->vq);
++ spin_unlock_irqrestore(&fifo->spin_lock, flags);
++ }
++
++mlxbf_tmfifo_desc_done:
++ /* Save the current desc. */
++ vring->desc = desc;
++
++ return true;
++}
++
++/* Rx & Tx processing of a queue. */
++static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
++{
++ int avail = 0, devid = vring->vdev_id;
++ struct mlxbf_tmfifo *fifo;
++ bool more;
++
++ fifo = vring->fifo;
++
++ /* Return if vdev is not ready. */
++ if (!fifo->vdev[devid])
++ return;
++
++ /* Return if another vring is running. */
++ if (fifo->vring[is_rx] && fifo->vring[is_rx] != vring)
++ return;
++
++ /* Only handle console and network for now. */
++ if (WARN_ON(devid != VIRTIO_ID_NET && devid != VIRTIO_ID_CONSOLE))
++ return;
++
++ do {
++ /* Get available FIFO space. */
++ if (avail == 0) {
++ if (is_rx)
++ avail = mlxbf_tmfifo_get_rx_avail(fifo);
++ else
++ avail = mlxbf_tmfifo_get_tx_avail(fifo, devid);
++ if (avail <= 0)
++ break;
++ }
++
++ /* Console output always comes from the Tx buffer. */
++ if (!is_rx && devid == VIRTIO_ID_CONSOLE) {
++ mlxbf_tmfifo_console_tx(fifo, avail);
++ break;
++ }
++
++ /* Handle one descriptor. */
++ more = mlxbf_tmfifo_rxtx_one_desc(vring, is_rx, &avail);
++ } while (more);
++}
++
++/* Handle Rx or Tx queues. */
++static void mlxbf_tmfifo_work_rxtx(struct mlxbf_tmfifo *fifo, int queue_id,
++ int irq_id, bool is_rx)
++{
++ struct mlxbf_tmfifo_vdev *tm_vdev;
++ struct mlxbf_tmfifo_vring *vring;
++ int i;
++
++ if (!test_and_clear_bit(irq_id, &fifo->pend_events) ||
++ !fifo->irq_info[irq_id].irq)
++ return;
++
++ for (i = 0; i < MLXBF_TMFIFO_VDEV_MAX; i++) {
++ tm_vdev = fifo->vdev[i];
++ if (tm_vdev) {
++ vring = &tm_vdev->vrings[queue_id];
++ if (vring->vq)
++ mlxbf_tmfifo_rxtx(vring, is_rx);
++ }
++ }
++}
++
++/* Work handler for Rx and Tx case. */
++static void mlxbf_tmfifo_work_handler(struct work_struct *work)
++{
++ struct mlxbf_tmfifo *fifo;
++
++ fifo = container_of(work, struct mlxbf_tmfifo, work);
++ if (!fifo->is_ready)
++ return;
++
++ mutex_lock(&fifo->lock);
++
++ /* Tx (Send data to the TmFifo). */
++ mlxbf_tmfifo_work_rxtx(fifo, MLXBF_TMFIFO_VRING_TX,
++ MLXBF_TM_TX_LWM_IRQ, false);
++
++ /* Rx (Receive data from the TmFifo). */
++ mlxbf_tmfifo_work_rxtx(fifo, MLXBF_TMFIFO_VRING_RX,
++ MLXBF_TM_RX_HWM_IRQ, true);
++
++ mutex_unlock(&fifo->lock);
++}
++
++/* The notify function is called when new buffers are posted. */
++static bool mlxbf_tmfifo_virtio_notify(struct virtqueue *vq)
++{
++ struct mlxbf_tmfifo_vring *vring = vq->priv;
++ struct mlxbf_tmfifo_vdev *tm_vdev;
++ struct mlxbf_tmfifo *fifo;
++ unsigned long flags;
++
++ fifo = vring->fifo;
++
++ /*
++ * Virtio maintains vrings in pairs, even number ring for Rx
++ * and odd number ring for Tx.
++ */
++ if (vring->index & BIT(0)) {
++ /*
++ * Console could make blocking call with interrupts disabled.
++ * In such case, the vring needs to be served right away. For
++ * other cases, just set the TX LWM bit to start Tx in the
++ * worker handler.
++ */
++ if (vring->vdev_id == VIRTIO_ID_CONSOLE) {
++ spin_lock_irqsave(&fifo->spin_lock, flags);
++ tm_vdev = fifo->vdev[VIRTIO_ID_CONSOLE];
++ mlxbf_tmfifo_console_output(tm_vdev, vring);
++ spin_unlock_irqrestore(&fifo->spin_lock, flags);
++ } else if (test_and_set_bit(MLXBF_TM_TX_LWM_IRQ,
++ &fifo->pend_events)) {
++ return true;
++ }
++ } else {
++ if (test_and_set_bit(MLXBF_TM_RX_HWM_IRQ, &fifo->pend_events))
++ return true;
++ }
++
++ schedule_work(&fifo->work);
++
++ return true;
++}
++
++/* Get the array of feature bits for this device. */
++static u64 mlxbf_tmfifo_virtio_get_features(struct virtio_device *vdev)
++{
++ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
++
++ return tm_vdev->features;
++}
++
++/* Confirm device features to use. */
++static int mlxbf_tmfifo_virtio_finalize_features(struct virtio_device *vdev)
++{
++ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
++
++ tm_vdev->features = vdev->features;
++
++ return 0;
++}
++
++/* Free virtqueues found by find_vqs(). */
++static void mlxbf_tmfifo_virtio_del_vqs(struct virtio_device *vdev)
++{
++ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
++ struct mlxbf_tmfifo_vring *vring;
++ struct virtqueue *vq;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(tm_vdev->vrings); i++) {
++ vring = &tm_vdev->vrings[i];
++
++ /* Release the pending packet. */
++ if (vring->desc)
++ mlxbf_tmfifo_release_pending_pkt(vring);
++ vq = vring->vq;
++ if (vq) {
++ vring->vq = NULL;
++ vring_del_virtqueue(vq);
++ }
++ }
++}
++
++/* Create and initialize the virtual queues. */
++static int mlxbf_tmfifo_virtio_find_vqs(struct virtio_device *vdev,
++ unsigned int nvqs,
++ struct virtqueue *vqs[],
++ vq_callback_t *callbacks[],
++ const char * const names[],
++ const bool *ctx,
++ struct irq_affinity *desc)
++{
++ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
++ struct mlxbf_tmfifo_vring *vring;
++ struct virtqueue *vq;
++ int i, ret, size;
++
++ if (nvqs > ARRAY_SIZE(tm_vdev->vrings))
++ return -EINVAL;
++
++ for (i = 0; i < nvqs; ++i) {
++ if (!names[i]) {
++ ret = -EINVAL;
++ goto error;
++ }
++ vring = &tm_vdev->vrings[i];
++
++ /* zero vring */
++ size = vring_size(vring->num, vring->align);
++ memset(vring->va, 0, size);
++ vq = vring_new_virtqueue(i, vring->num, vring->align, vdev,
++ false, false, vring->va,
++ mlxbf_tmfifo_virtio_notify,
++ callbacks[i], names[i]);
++ if (!vq) {
++ dev_err(&vdev->dev, "vring_new_virtqueue failed\n");
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ vqs[i] = vq;
++ vring->vq = vq;
++ vq->priv = vring;
++ }
++
++ return 0;
++
++error:
++ mlxbf_tmfifo_virtio_del_vqs(vdev);
++ return ret;
++}
++
++/* Read the status byte. */
++static u8 mlxbf_tmfifo_virtio_get_status(struct virtio_device *vdev)
++{
++ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
++
++ return tm_vdev->status;
++}
++
++/* Write the status byte. */
++static void mlxbf_tmfifo_virtio_set_status(struct virtio_device *vdev,
++ u8 status)
++{
++ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
++
++ tm_vdev->status = status;
++}
++
++/* Reset the device. Not much here for now. */
++static void mlxbf_tmfifo_virtio_reset(struct virtio_device *vdev)
++{
++ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
++
++ tm_vdev->status = 0;
++}
++
++/* Read the value of a configuration field. */
++static void mlxbf_tmfifo_virtio_get(struct virtio_device *vdev,
++ unsigned int offset,
++ void *buf,
++ unsigned int len)
++{
++ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
++
++ if ((u64)offset + len > sizeof(tm_vdev->config))
++ return;
++
++ memcpy(buf, (u8 *)&tm_vdev->config + offset, len);
++}
++
++/* Write the value of a configuration field. */
++static void mlxbf_tmfifo_virtio_set(struct virtio_device *vdev,
++ unsigned int offset,
++ const void *buf,
++ unsigned int len)
++{
++ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
++
++ if ((u64)offset + len > sizeof(tm_vdev->config))
++ return;
++
++ memcpy((u8 *)&tm_vdev->config + offset, buf, len);
++}
++
++static void tmfifo_virtio_dev_release(struct device *device)
++{
++ struct virtio_device *vdev =
++ container_of(device, struct virtio_device, dev);
++ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
++
++ kfree(tm_vdev);
++}
++
++/* Virtio config operations. */
++static const struct virtio_config_ops mlxbf_tmfifo_virtio_config_ops = {
++ .get_features = mlxbf_tmfifo_virtio_get_features,
++ .finalize_features = mlxbf_tmfifo_virtio_finalize_features,
++ .find_vqs = mlxbf_tmfifo_virtio_find_vqs,
++ .del_vqs = mlxbf_tmfifo_virtio_del_vqs,
++ .reset = mlxbf_tmfifo_virtio_reset,
++ .set_status = mlxbf_tmfifo_virtio_set_status,
++ .get_status = mlxbf_tmfifo_virtio_get_status,
++ .get = mlxbf_tmfifo_virtio_get,
++ .set = mlxbf_tmfifo_virtio_set,
++};
++
++/* Create vdev for the FIFO. */
++static int mlxbf_tmfifo_create_vdev(struct device *dev,
++ struct mlxbf_tmfifo *fifo,
++ int vdev_id, u64 features,
++ void *config, u32 size)
++{
++ struct mlxbf_tmfifo_vdev *tm_vdev, *reg_dev = NULL;
++ int ret;
++
++ mutex_lock(&fifo->lock);
++
++ tm_vdev = fifo->vdev[vdev_id];
++ if (tm_vdev) {
++ dev_err(dev, "vdev %d already exists\n", vdev_id);
++ ret = -EEXIST;
++ goto fail;
++ }
++
++ tm_vdev = kzalloc(sizeof(*tm_vdev), GFP_KERNEL);
++ if (!tm_vdev) {
++ ret = -ENOMEM;
++ goto fail;
++ }
++
++ tm_vdev->vdev.id.device = vdev_id;
++ tm_vdev->vdev.config = &mlxbf_tmfifo_virtio_config_ops;
++ tm_vdev->vdev.dev.parent = dev;
++ tm_vdev->vdev.dev.release = tmfifo_virtio_dev_release;
++ tm_vdev->features = features;
++ if (config)
++ memcpy(&tm_vdev->config, config, size);
++
++ if (mlxbf_tmfifo_alloc_vrings(fifo, tm_vdev)) {
++ dev_err(dev, "unable to allocate vring\n");
++ ret = -ENOMEM;
++ goto vdev_fail;
++ }
++
++ /* Allocate an output buffer for the console device. */
++ if (vdev_id == VIRTIO_ID_CONSOLE)
++ tm_vdev->tx_buf.buf = devm_kmalloc(dev,
++ MLXBF_TMFIFO_CON_TX_BUF_SIZE,
++ GFP_KERNEL);
++ fifo->vdev[vdev_id] = tm_vdev;
++
++ /* Register the virtio device. */
++ ret = register_virtio_device(&tm_vdev->vdev);
++ reg_dev = tm_vdev;
++ if (ret) {
++ dev_err(dev, "register_virtio_device failed\n");
++ goto vdev_fail;
++ }
++
++ mutex_unlock(&fifo->lock);
++ return 0;
++
++vdev_fail:
++ mlxbf_tmfifo_free_vrings(fifo, tm_vdev);
++ fifo->vdev[vdev_id] = NULL;
++ if (reg_dev)
++ put_device(&tm_vdev->vdev.dev);
++ else
++ kfree(tm_vdev);
++fail:
++ mutex_unlock(&fifo->lock);
++ return ret;
++}
++
++/* Delete vdev for the FIFO. */
++static int mlxbf_tmfifo_delete_vdev(struct mlxbf_tmfifo *fifo, int vdev_id)
++{
++ struct mlxbf_tmfifo_vdev *tm_vdev;
++
++ mutex_lock(&fifo->lock);
++
++ /* Unregister vdev. */
++ tm_vdev = fifo->vdev[vdev_id];
++ if (tm_vdev) {
++ unregister_virtio_device(&tm_vdev->vdev);
++ mlxbf_tmfifo_free_vrings(fifo, tm_vdev);
++ fifo->vdev[vdev_id] = NULL;
++ }
++
++ mutex_unlock(&fifo->lock);
++
++ return 0;
++}
++
++/* Read the configured network MAC address from efi variable. */
++static void mlxbf_tmfifo_get_cfg_mac(u8 *mac)
++{
++ efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID;
++ unsigned long size = ETH_ALEN;
++ u8 buf[ETH_ALEN];
++ efi_status_t rc;
++
++ rc = efi.get_variable(mlxbf_tmfifo_efi_name, &guid, NULL, &size, buf);
++ if (rc == EFI_SUCCESS && size == ETH_ALEN)
++ ether_addr_copy(mac, buf);
++ else
++ ether_addr_copy(mac, mlxbf_tmfifo_net_default_mac);
++}
++
++/* Set TmFifo thresolds which is used to trigger interrupts. */
++static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo)
++{
++ u64 ctl;
++
++ /* Get Tx FIFO size and set the low/high watermark. */
++ ctl = readq(fifo->tx_base + MLXBF_TMFIFO_TX_CTL);
++ fifo->tx_fifo_size =
++ FIELD_GET(MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_MASK, ctl);
++ ctl = (ctl & ~MLXBF_TMFIFO_TX_CTL__LWM_MASK) |
++ FIELD_PREP(MLXBF_TMFIFO_TX_CTL__LWM_MASK,
++ fifo->tx_fifo_size / 2);
++ ctl = (ctl & ~MLXBF_TMFIFO_TX_CTL__HWM_MASK) |
++ FIELD_PREP(MLXBF_TMFIFO_TX_CTL__HWM_MASK,
++ fifo->tx_fifo_size - 1);
++ writeq(ctl, fifo->tx_base + MLXBF_TMFIFO_TX_CTL);
++
++ /* Get Rx FIFO size and set the low/high watermark. */
++ ctl = readq(fifo->rx_base + MLXBF_TMFIFO_RX_CTL);
++ fifo->rx_fifo_size =
++ FIELD_GET(MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK, ctl);
++ ctl = (ctl & ~MLXBF_TMFIFO_RX_CTL__LWM_MASK) |
++ FIELD_PREP(MLXBF_TMFIFO_RX_CTL__LWM_MASK, 0);
++ ctl = (ctl & ~MLXBF_TMFIFO_RX_CTL__HWM_MASK) |
++ FIELD_PREP(MLXBF_TMFIFO_RX_CTL__HWM_MASK, 1);
++ writeq(ctl, fifo->rx_base + MLXBF_TMFIFO_RX_CTL);
++}
++
++static void mlxbf_tmfifo_cleanup(struct mlxbf_tmfifo *fifo)
++{
++ int i;
++
++ fifo->is_ready = false;
++ del_timer_sync(&fifo->timer);
++ mlxbf_tmfifo_disable_irqs(fifo);
++ cancel_work_sync(&fifo->work);
++ for (i = 0; i < MLXBF_TMFIFO_VDEV_MAX; i++)
++ mlxbf_tmfifo_delete_vdev(fifo, i);
++}
++
++/* Probe the TMFIFO. */
++static int mlxbf_tmfifo_probe(struct platform_device *pdev)
++{
++ struct virtio_net_config net_config;
++ struct device *dev = &pdev->dev;
++ struct mlxbf_tmfifo *fifo;
++ int i, rc;
++
++ fifo = devm_kzalloc(dev, sizeof(*fifo), GFP_KERNEL);
++ if (!fifo)
++ return -ENOMEM;
++
++ spin_lock_init(&fifo->spin_lock);
++ INIT_WORK(&fifo->work, mlxbf_tmfifo_work_handler);
++ mutex_init(&fifo->lock);
++
++ /* Get the resource of the Rx FIFO. */
++ fifo->rx_base = devm_platform_ioremap_resource(pdev, 0);
++ if (IS_ERR(fifo->rx_base))
++ return PTR_ERR(fifo->rx_base);
++
++ /* Get the resource of the Tx FIFO. */
++ fifo->tx_base = devm_platform_ioremap_resource(pdev, 1);
++ if (IS_ERR(fifo->tx_base))
++ return PTR_ERR(fifo->tx_base);
++
++ platform_set_drvdata(pdev, fifo);
++
++ timer_setup(&fifo->timer, mlxbf_tmfifo_timer, 0);
++
++ for (i = 0; i < MLXBF_TM_MAX_IRQ; i++) {
++ fifo->irq_info[i].index = i;
++ fifo->irq_info[i].fifo = fifo;
++ fifo->irq_info[i].irq = platform_get_irq(pdev, i);
++ rc = devm_request_irq(dev, fifo->irq_info[i].irq,
++ mlxbf_tmfifo_irq_handler, 0,
++ "tmfifo", &fifo->irq_info[i]);
++ if (rc) {
++ dev_err(dev, "devm_request_irq failed\n");
++ fifo->irq_info[i].irq = 0;
++ return rc;
++ }
++ }
++
++ mlxbf_tmfifo_set_threshold(fifo);
++
++ /* Create the console vdev. */
++ rc = mlxbf_tmfifo_create_vdev(dev, fifo, VIRTIO_ID_CONSOLE, 0, NULL, 0);
++ if (rc)
++ goto fail;
++
++ /* Create the network vdev. */
++ memset(&net_config, 0, sizeof(net_config));
++ net_config.mtu = ETH_DATA_LEN;
++ net_config.status = VIRTIO_NET_S_LINK_UP;
++ mlxbf_tmfifo_get_cfg_mac(net_config.mac);
++ rc = mlxbf_tmfifo_create_vdev(dev, fifo, VIRTIO_ID_NET,
++ MLXBF_TMFIFO_NET_FEATURES, &net_config,
++ sizeof(net_config));</