Merge branches 'pm-opp', 'pm-devfreq' and 'powercap'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 10 Jan 2022 17:00:31 +0000 (18:00 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 10 Jan 2022 17:00:31 +0000 (18:00 +0100)
Merge an operating performance points (OPP) update, devfreq updates
and power capping updates for 5.17-rc1:

 - Update outdated OPP documentation (Tang Yizhou).

 - Reduce log severity for informative message regarding frequency
   transition failures in devfreq (Tzung-Bi Shih).

 - Add DRAM frequency controller devfreq driver for Allwinner sunXi
   SoCs (Samuel Holland).

 - Add missing COMMON_CLK dependency to the sun8i devfreq driver (Arnd
   Bergmann).

 - Add support for new layout of Psys PowerLimit Register on SPR to
   the Intel RAPL power capping driver (Zhang Rui).

 - Fix typo in a comment in idle_inject.c (Jason Wang).

 - Remove unused function definition from the DTPM (Dynamit Thermal
   Power Management) power capping framework (Daniel Lezcano).

 - Reduce DTPM trace verbosity (Daniel Lezcano).

* pm-opp:
  Documentation: power: Update outdated contents in opp.rst

* pm-devfreq:
  PM / devfreq: Reduce log severity for informative message
  PM / devfreq: sun8i: addd COMMON_CLK dependency
  PM / devfreq: Add a driver for the sun8i/sun50i MBUS

* powercap:
  powercap/drivers/dtpm: Reduce trace verbosity
  powercap/drivers/dtpm: Remove unused function definition
  powercap: fix typo in a comment in idle_inject.c
  powercap: intel_rapl: support new layout of Psys PowerLimit Register on SPR

337 files changed:
Documentation/admin-guide/acpi/cppc_sysfs.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/pm/amd-pstate.rst [new file with mode: 0644]
Documentation/admin-guide/pm/working-state.rst
Documentation/devicetree/bindings/regulator/samsung,s5m8767.yaml
Documentation/i2c/summary.rst
Documentation/networking/bonding.rst
Documentation/networking/device_drivers/ethernet/freescale/dpaa2/overview.rst
Documentation/networking/ip-sysctl.rst
Documentation/networking/timestamping.rst
Documentation/power/opp.rst
Documentation/power/runtime_pm.rst
Documentation/sound/hd-audio/models.rst
MAINTAINERS
Makefile
arch/arm/boot/dts/imx6qdl-wandboard.dtsi
arch/arm/include/asm/efi.h
arch/arm/include/asm/topology.h
arch/arm/kernel/entry-armv.S
arch/arm/kernel/head-nommu.S
arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus.dts
arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
arch/arm64/include/asm/efi.h
arch/arm64/include/asm/topology.h
arch/parisc/Kconfig
arch/parisc/include/asm/futex.h
arch/parisc/kernel/syscall.S
arch/parisc/kernel/traps.c
arch/powerpc/mm/ptdump/ptdump.c
arch/riscv/include/asm/efi.h
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/efi.h
arch/x86/include/asm/kvm-x86-ops.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/pkru.h
arch/x86/include/asm/topology.h
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/cpu/intel_epb.c
arch/x86/kernel/setup.c
arch/x86/kvm/mmu/tdp_iter.c
arch/x86/kvm/mmu/tdp_iter.h
arch/x86/kvm/mmu/tdp_mmu.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c
arch/x86/tools/relocs.c
drivers/acpi/cppc_acpi.c
drivers/acpi/sleep.c
drivers/android/binder_alloc.c
drivers/auxdisplay/charlcd.c
drivers/base/arch_topology.c
drivers/base/core.c
drivers/base/power/main.c
drivers/base/power/runtime.c
drivers/block/xen-blkfront.c
drivers/bus/sunxi-rsb.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_ssif.c
drivers/cpufreq/Kconfig.x86
drivers/cpufreq/Makefile
drivers/cpufreq/amd-pstate-trace.c [new file with mode: 0644]
drivers/cpufreq/amd-pstate-trace.h [new file with mode: 0644]
drivers/cpufreq/amd-pstate.c [new file with mode: 0644]
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/mediatek-cpufreq-hw.c
drivers/cpufreq/qcom-cpufreq-hw.c
drivers/cpuidle/governors/menu.c
drivers/cpuidle/sysfs.c
drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c
drivers/devfreq/Kconfig
drivers/devfreq/Makefile
drivers/devfreq/devfreq.c
drivers/devfreq/sun8i-a33-mbus.c [new file with mode: 0644]
drivers/gpio/gpio-dln2.c
drivers/gpio/gpio-virtio.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c
drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c
drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h
drivers/gpu/drm/amd/include/discovery.h
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c
drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
drivers/gpu/drm/i915/gem/i915_gem_context.c
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
drivers/gpu/drm/mediatek/mtk_hdmi.c
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/hid/hid-holtek-mouse.c
drivers/hid/hid-vivaldi.c
drivers/hwmon/lm90.c
drivers/i2c/i2c-dev.c
drivers/infiniband/hw/hns/hns_roce_hw_v2.c
drivers/infiniband/hw/hns/hns_roce_hw_v2.h
drivers/infiniband/hw/hns/hns_roce_srq.c
drivers/infiniband/hw/qib/qib_user_sdma.c
drivers/input/joystick/spaceball.c
drivers/input/misc/iqs626a.c
drivers/input/mouse/appletouch.c
drivers/input/mouse/elantech.c
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/i8042.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/elants_i2c.c
drivers/input/touchscreen/goodix.c
drivers/input/touchscreen/goodix.h
drivers/input/touchscreen/goodix_fwupload.c
drivers/isdn/mISDN/core.c
drivers/isdn/mISDN/core.h
drivers/isdn/mISDN/layer1.c
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/host.c
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/meson-mx-sdhc-mmc.c
drivers/mmc/host/mmci_stm32_sdmmc.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/sdhci-tegra.c
drivers/net/bonding/bond_options.c
drivers/net/ethernet/aquantia/atlantic/aq_ring.c
drivers/net/ethernet/atheros/ag71xx.c
drivers/net/ethernet/freescale/fman/fman_port.c
drivers/net/ethernet/google/gve/gve_adminq.c
drivers/net/ethernet/intel/ice/ice_base.c
drivers/net/ethernet/intel/ice/ice_txrx.c
drivers/net/ethernet/intel/ice/ice_txrx.h
drivers/net/ethernet/intel/ice/ice_xsk.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igc/igc_main.c
drivers/net/ethernet/intel/igc/igc_ptp.c
drivers/net/ethernet/lantiq_xrx200.c
drivers/net/ethernet/marvell/prestera/prestera_main.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en/health.h
drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.h
drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c
drivers/net/ethernet/micrel/ks8851_par.c
drivers/net/ethernet/pensando/ionic/ionic_lif.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/sfc/falcon/rx.c
drivers/net/ethernet/sfc/rx_common.c
drivers/net/ethernet/smsc/smc911x.c
drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
drivers/net/fjes/fjes_main.c
drivers/net/hamradio/mkiss.c
drivers/net/phy/fixed_phy.c
drivers/net/tun.c
drivers/net/usb/asix_common.c
drivers/net/usb/pegasus.c
drivers/net/usb/r8152.c
drivers/net/veth.c
drivers/net/xen-netback/common.h
drivers/net/xen-netback/rx.c
drivers/net/xen-netfront.c
drivers/nfc/st21nfca/i2c.c
drivers/pinctrl/bcm/pinctrl-bcm2835.c
drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
drivers/pinctrl/stm32/pinctrl-stm32.c
drivers/platform/mellanox/mlxbf-pmc.c
drivers/platform/x86/Makefile
drivers/platform/x86/amd-pmc.c
drivers/platform/x86/apple-gmux.c
drivers/platform/x86/intel/Kconfig
drivers/platform/x86/intel/pmc/pltdrv.c
drivers/platform/x86/system76_acpi.c
drivers/scsi/libiscsi.c
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/scsi/vmw_pvscsi.c
drivers/spi/spi-armada-3700.c
drivers/tee/optee/core.c
drivers/tee/optee/smc_abi.c
drivers/tee/tee_shm.c
drivers/thermal/cpufreq_cooling.c
drivers/tty/hvc/hvc_xen.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/host/xhci-pci.c
drivers/usb/mtu3/mtu3_gadget.c
drivers/usb/mtu3/mtu3_qmu.c
drivers/usb/typec/ucsi/ucsi.c
drivers/virt/nitro_enclaves/ne_misc_dev.c
drivers/xen/events/events_base.c
fs/io_uring.c
fs/ksmbd/ndr.c
fs/ksmbd/smb2ops.c
fs/ksmbd/smb2pdu.c
fs/namespace.c
fs/nfsd/nfs3proc.c
fs/nfsd/nfsproc.c
include/acpi/cppc_acpi.h
include/linux/acpi.h
include/linux/arch_topology.h
include/linux/compiler.h
include/linux/efi.h
include/linux/gfp.h
include/linux/instrumentation.h
include/linux/memblock.h
include/linux/mmzone.h
include/linux/netdevice.h
include/linux/pagemap.h
include/linux/pm.h
include/linux/pm_runtime.h
include/linux/sched/topology.h
include/linux/skbuff.h
include/linux/suspend.h
include/linux/tee_drv.h
include/linux/virtio_net.h
include/net/pkt_sched.h
include/net/sch_generic.h
include/net/sctp/sctp.h
include/net/sctp/structs.h
include/net/sock.h
include/trace/events/vmscan.h
include/uapi/linux/byteorder/big_endian.h
include/uapi/linux/byteorder/little_endian.h
include/uapi/linux/nfc.h
include/xen/events.h
init/Kconfig
kernel/crash_core.c
kernel/power/power.h
kernel/power/swap.c
kernel/ucount.c
mm/damon/dbgfs.c
mm/kfence/core.c
mm/memory-failure.c
mm/mempolicy.c
mm/vmscan.c
net/ax25/af_ax25.c
net/bridge/br_ioctl.c
net/bridge/br_multicast.c
net/bridge/br_netlink.c
net/bridge/br_private.h
net/bridge/br_sysfs_br.c
net/bridge/br_vlan_options.c
net/core/dev.c
net/core/flow_dissector.c
net/dsa/tag_ocelot.c
net/ipv4/af_inet.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv6/ip6_vti.c
net/ipv6/raw.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/mac80211/cfg.c
net/ncsi/ncsi-netlink.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink_log.c
net/netfilter/nfnetlink_queue.c
net/openvswitch/flow.c
net/phonet/pep.c
net/sched/act_ct.c
net/sched/cls_api.c
net/sched/cls_flower.c
net/sched/sch_frag.c
net/sctp/diag.c
net/sctp/endpointola.c
net/sctp/socket.c
net/smc/smc.h
net/smc/smc_cdc.c
net/smc/smc_cdc.h
net/smc/smc_core.c
net/smc/smc_core.h
net/smc/smc_ib.c
net/smc/smc_ib.h
net/smc/smc_llc.c
net/smc/smc_wr.c
net/smc/smc_wr.h
net/tipc/crypto.c
net/xdp/xsk_buff_pool.c
scripts/recordmcount.pl
security/selinux/hooks.c
security/tomoyo/util.c
sound/core/jack.c
sound/core/rawmidi.c
sound/drivers/opl3/opl3_midi.c
sound/hda/intel-sdw-acpi.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/soc/codecs/rt5682.c
sound/soc/codecs/tas2770.c
sound/soc/meson/aiu-encoder-i2s.c
sound/soc/meson/aiu-fifo-i2s.c
sound/soc/meson/aiu-fifo.c
sound/soc/sof/intel/pci-tgl.c
sound/soc/tegra/tegra_asoc_machine.c
sound/soc/tegra/tegra_asoc_machine.h
tools/perf/builtin-script.c
tools/perf/scripts/python/intel-pt-events.py
tools/perf/ui/tui/setup.c
tools/perf/util/expr.c
tools/perf/util/intel-pt.c
tools/perf/util/pmu.c
tools/testing/selftests/kvm/.gitignore
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/include/kvm_util.h
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c [new file with mode: 0644]
tools/testing/selftests/net/mptcp/config
tools/testing/selftests/net/udpgro_fwd.sh
tools/testing/selftests/net/udpgso.c
tools/testing/selftests/net/udpgso_bench_tx.c
tools/testing/selftests/vm/userfaultfd.c

index fccf221..e53d763 100644 (file)
@@ -4,6 +4,8 @@
 Collaborative Processor Performance Control (CPPC)
 ==================================================
 
+.. _cppc_sysfs:
+
 CPPC
 ====
 
index 9725c54..a8a80a3 100644 (file)
                        For broken nForce2 BIOS resulting in XT-PIC timer.
 
        acpi_sleep=     [HW,ACPI] Sleep options
-                       Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig,
-                                 old_ordering, nonvs, sci_force_enable, nobl }
+                       Format: { s3_bios, s3_mode, s3_beep, s4_hwsig,
+                                 s4_nohwsig, old_ordering, nonvs,
+                                 sci_force_enable, nobl }
                        See Documentation/power/video.rst for information on
                        s3_bios and s3_mode.
                        s3_beep is for debugging; it makes the PC's speaker beep
                        as soon as the kernel's real-mode entry point is called.
+                       s4_hwsig causes the kernel to check the ACPI hardware
+                       signature during resume from hibernation, and gracefully
+                       refuse to resume if it has changed. This complies with
+                       the ACPI specification but not with reality, since
+                       Windows does not do this and many laptops do change it
+                       on docking. So the default behaviour is to allow resume
+                       and simply warn when the signature changes, unless the
+                       s4_hwsig option is enabled.
                        s4_nohwsig prevents ACPI hardware signature from being
-                       used during resume from hibernation.
+                       used (or even warned about) during resume.
                        old_ordering causes the ACPI 1.0 ordering of the _PTS
                        control method, with respect to putting devices into
                        low power states, to be enforced (the ACPI 2.0 ordering
                        architectures force reset to be always executed
        i8042.unlock    [HW] Unlock (ignore) the keylock
        i8042.kbdreset  [HW] Reset device connected to KBD port
+       i8042.probe_defer
+                       [HW] Allow deferred probing upon i8042 probe errors
 
        i810=           [HW,DRM]
 
                        Default is 1 (enabled)
 
        kvm-intel.emulate_invalid_guest_state=
-                       [KVM,Intel] Enable emulation of invalid guest states
-                       Default is 0 (disabled)
+                       [KVM,Intel] Disable emulation of invalid guest state.
+                       Ignored if kvm-intel.enable_unrestricted_guest=1, as
+                       guest state is never invalid for unrestricted guests.
+                       This param doesn't apply to nested guests (L2), as KVM
+                       never emulates invalid L2 guest state.
+                       Default is 1 (enabled)
 
        kvm-intel.flexpriority=
                        [KVM,Intel] Disable FlexPriority feature (TPR shadow).
diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst
new file mode 100644 (file)
index 0000000..2f066df
--- /dev/null
@@ -0,0 +1,382 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: <isonum.txt>
+
+===============================================
+``amd-pstate`` CPU Performance Scaling Driver
+===============================================
+
+:Copyright: |copy| 2021 Advanced Micro Devices, Inc.
+
+:Author: Huang Rui <ray.huang@amd.com>
+
+
+Introduction
+===================
+
+``amd-pstate`` is the AMD CPU performance scaling driver that introduces a
+new CPU frequency control mechanism on modern AMD APU and CPU series in
+Linux kernel. The new mechanism is based on Collaborative Processor
+Performance Control (CPPC) which provides finer grain frequency management
+than legacy ACPI hardware P-States. Current AMD CPU/APU platforms are using
+the ACPI P-states driver to manage CPU frequency and clocks with switching
+only in 3 P-states. CPPC replaces the ACPI P-states controls, allows a
+flexible, low-latency interface for the Linux kernel to directly
+communicate the performance hints to hardware.
+
+``amd-pstate`` leverages the Linux kernel governors such as ``schedutil``,
+``ondemand``, etc. to manage the performance hints which are provided by
+CPPC hardware functionality that internally follows the hardware
+specification (for details refer to AMD64 Architecture Programmer's Manual
+Volume 2: System Programming [1]_). Currently ``amd-pstate`` supports basic
+frequency control function according to kernel governors on some of the
+Zen2 and Zen3 processors, and we will implement more AMD specific functions
+in future after we verify them on the hardware and SBIOS.
+
+
+AMD CPPC Overview
+=======================
+
+Collaborative Processor Performance Control (CPPC) interface enumerates a
+continuous, abstract, and unit-less performance value in a scale that is
+not tied to a specific performance state / frequency. This is an ACPI
+standard [2]_ which software can specify application performance goals and
+hints as a relative target to the infrastructure limits. AMD processors
+provides the low latency register model (MSR) instead of AML code
+interpreter for performance adjustments. ``amd-pstate`` will initialize a
+``struct cpufreq_driver`` instance ``amd_pstate_driver`` with the callbacks
+to manage each performance update behavior. ::
+
+ Highest Perf ------>+-----------------------+                         +-----------------------+
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+                     |                       |          Max Perf  ---->|                       |
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+ Nominal Perf ------>+-----------------------+                         +-----------------------+
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+                     |                       |      Desired Perf  ---->|                       |
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+  Lowest non-        |                       |                         |                       |
+  linear perf ------>+-----------------------+                         +-----------------------+
+                     |                       |                         |                       |
+                     |                       |       Lowest perf  ---->|                       |
+                     |                       |                         |                       |
+  Lowest perf ------>+-----------------------+                         +-----------------------+
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+                     |                       |                         |                       |
+          0   ------>+-----------------------+                         +-----------------------+
+
+                                     AMD P-States Performance Scale
+
+
+.. _perf_cap:
+
+AMD CPPC Performance Capability
+--------------------------------
+
+Highest Performance (RO)
+.........................
+
+It is the absolute maximum performance an individual processor may reach,
+assuming ideal conditions. This performance level may not be sustainable
+for long durations and may only be achievable if other platform components
+are in a specific state; for example, it may require other processors be in
+an idle state. This would be equivalent to the highest frequencies
+supported by the processor.
+
+Nominal (Guaranteed) Performance (RO)
+......................................
+
+It is the maximum sustained performance level of the processor, assuming
+ideal operating conditions. In absence of an external constraint (power,
+thermal, etc.) this is the performance level the processor is expected to
+be able to maintain continuously. All cores/processors are expected to be
+able to sustain their nominal performance state simultaneously.
+
+Lowest non-linear Performance (RO)
+...................................
+
+It is the lowest performance level at which nonlinear power savings are
+achieved, for example, due to the combined effects of voltage and frequency
+scaling. Above this threshold, lower performance levels should be generally
+more energy efficient than higher performance levels. This register
+effectively conveys the most efficient performance level to ``amd-pstate``.
+
+Lowest Performance (RO)
+........................
+
+It is the absolute lowest performance level of the processor. Selecting a
+performance level lower than the lowest nonlinear performance level may
+cause an efficiency penalty but should reduce the instantaneous power
+consumption of the processor.
+
+AMD CPPC Performance Control
+------------------------------
+
+``amd-pstate`` passes performance goals through these registers. The
+register drives the behavior of the desired performance target.
+
+Minimum requested performance (RW)
+...................................
+
+``amd-pstate`` specifies the minimum allowed performance level.
+
+Maximum requested performance (RW)
+...................................
+
+``amd-pstate`` specifies a limit the maximum performance that is expected
+to be supplied by the hardware.
+
+Desired performance target (RW)
+...................................
+
+``amd-pstate`` specifies a desired target in the CPPC performance scale as
+a relative number. This can be expressed as percentage of nominal
+performance (infrastructure max). Below the nominal sustained performance
+level, desired performance expresses the average performance level of the
+processor subject to hardware. Above the nominal performance level,
+processor must provide at least nominal performance requested and go higher
+if current operating conditions allow.
+
+Energy Performance Preference (EPP) (RW)
+.........................................
+
+Provides a hint to the hardware if software wants to bias toward performance
+(0x0) or energy efficiency (0xff).
+
+
+Key Governors Support
+=======================
+
+``amd-pstate`` can be used with all the (generic) scaling governors listed
+by the ``scaling_available_governors`` policy attribute in ``sysfs``. Then,
+it is responsible for the configuration of policy objects corresponding to
+CPUs and provides the ``CPUFreq`` core (and the scaling governors attached
+to the policy objects) with accurate information on the maximum and minimum
+operating frequencies supported by the hardware. Users can check the
+``scaling_cur_freq`` information comes from the ``CPUFreq`` core.
+
+``amd-pstate`` mainly supports ``schedutil`` and ``ondemand`` for dynamic
+frequency control. It is to fine tune the processor configuration on
+``amd-pstate`` to the ``schedutil`` with CPU CFS scheduler. ``amd-pstate``
+registers adjust_perf callback to implement the CPPC similar performance
+update behavior. It is initialized by ``sugov_start`` and then populate the
+CPU's update_util_data pointer to assign ``sugov_update_single_perf`` as
+the utilization update callback function in CPU scheduler. CPU scheduler
+will call ``cpufreq_update_util`` and assign the target performance
+according to the ``struct sugov_cpu`` that utilization update belongs to.
+Then ``amd-pstate`` updates the desired performance according to the CPU
+scheduler assigned.
+
+
+Processor Support
+=======================
+
+The ``amd-pstate`` initialization will fail if the _CPC in ACPI SBIOS is
+not existed at the detected processor, and it uses ``acpi_cpc_valid`` to
+check the _CPC existence. All Zen based processors support legacy ACPI
+hardware P-States function, so while the ``amd-pstate`` fails to be
+initialized, the kernel will fall back to initialize ``acpi-cpufreq``
+driver.
+
+There are two types of hardware implementations for ``amd-pstate``: one is
+`Full MSR Support <perf_cap_>`_ and another is `Shared Memory Support
+<perf_cap_>`_. It can use :c:macro:`X86_FEATURE_CPPC` feature flag (for
+details refer to Processor Programming Reference (PPR) for AMD Family
+19h Model 51h, Revision A1 Processors [3]_) to indicate the different
+types. ``amd-pstate`` is to register different ``static_call`` instances
+for different hardware implementations.
+
+Currently, some of Zen2 and Zen3 processors support ``amd-pstate``. In the
+future, it will be supported on more and more AMD processors.
+
+Full MSR Support
+-----------------
+
+Some new Zen3 processors such as Cezanne provide the MSR registers directly
+while the :c:macro:`X86_FEATURE_CPPC` CPU feature flag is set.
+``amd-pstate`` can handle the MSR register to implement the fast switch
+function in ``CPUFreq`` that can shrink latency of frequency control on the
+interrupt context. The functions with ``pstate_xxx`` prefix represent the
+operations of MSR registers.
+
+Shared Memory Support
+----------------------
+
+If :c:macro:`X86_FEATURE_CPPC` CPU feature flag is not set, that means the
+processor supports shared memory solution. In this case, ``amd-pstate``
+uses the ``cppc_acpi`` helper methods to implement the callback functions
+that defined on ``static_call``. The functions with ``cppc_xxx`` prefix
+represent the operations of acpi cppc helpers for shared memory solution.
+
+
+AMD P-States and ACPI hardware P-States always can be supported in one
+processor. But AMD P-States has the higher priority and if it is enabled
+with :c:macro:`MSR_AMD_CPPC_ENABLE` or ``cppc_set_enable``, it will respond
+to the request from AMD P-States.
+
+
+User Space Interface in ``sysfs``
+==================================
+
+``amd-pstate`` exposes several global attributes (files) in ``sysfs`` to
+control its functionality at the system level. They located in the
+``/sys/devices/system/cpu/cpufreq/policyX/`` directory and affect all CPUs. ::
+
+ root@hr-test1:/home/ray# ls /sys/devices/system/cpu/cpufreq/policy0/*amd*
+ /sys/devices/system/cpu/cpufreq/policy0/amd_pstate_highest_perf
+ /sys/devices/system/cpu/cpufreq/policy0/amd_pstate_lowest_nonlinear_freq
+ /sys/devices/system/cpu/cpufreq/policy0/amd_pstate_max_freq
+
+
+``amd_pstate_highest_perf / amd_pstate_max_freq``
+
+Maximum CPPC performance and CPU frequency that the driver is allowed to
+set in percent of the maximum supported CPPC performance level (the highest
+performance supported in `AMD CPPC Performance Capability <perf_cap_>`_).
+In some of ASICs, the highest CPPC performance is not the one in the _CPC
+table, so we need to expose it to sysfs. If boost is not active but
+supported, this maximum frequency will be larger than the one in
+``cpuinfo``.
+This attribute is read-only.
+
+``amd_pstate_lowest_nonlinear_freq``
+
+The lowest non-linear CPPC CPU frequency that the driver is allowed to set
+in percent of the maximum supported CPPC performance level (Please see the
+lowest non-linear performance in `AMD CPPC Performance Capability
+<perf_cap_>`_).
+This attribute is read-only.
+
+For other performance and frequency values, we can read them back from
+``/sys/devices/system/cpu/cpuX/acpi_cppc/``, see :ref:`cppc_sysfs`.
+
+
+``amd-pstate`` vs ``acpi-cpufreq``
+======================================
+
+On majority of AMD platforms supported by ``acpi-cpufreq``, the ACPI tables
+provided by the platform firmware used for CPU performance scaling, but
+only provides 3 P-states on AMD processors.
+However, on modern AMD APU and CPU series, it provides the collaborative
+processor performance control according to ACPI protocol and customize this
+for AMD platforms. That is fine-grain and continuous frequency range
+instead of the legacy hardware P-states. ``amd-pstate`` is the kernel
+module which supports the new AMD P-States mechanism on most of future AMD
+platforms. The AMD P-States mechanism will be the more performance and energy
+efficiency frequency management method on AMD processors.
+
+Kernel Module Options for ``amd-pstate``
+=========================================
+
+``shared_mem``
+Use a module param (shared_mem) to enable related processors manually with
+**amd_pstate.shared_mem=1**.
+Due to the performance issue on the processors with `Shared Memory Support
+<perf_cap_>`_, so we disable it for the moment and will enable this by default
+once we address performance issue on this solution.
+
+The way to check whether current processor is `Full MSR Support <perf_cap_>`_
+or `Shared Memory Support <perf_cap_>`_ : ::
+
+  ray@hr-test1:~$ lscpu | grep cppc
+  Flags:                           fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate ssbd mba ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd cppc arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl umip pku ospke vaes vpclmulqdq rdpid overflow_recov succor smca fsrm
+
+If CPU Flags have cppc, then this processor supports `Full MSR Support
+<perf_cap_>`_. Otherwise it supports `Shared Memory Support <perf_cap_>`_.
+
+
+``cpupower`` tool support for ``amd-pstate``
+===============================================
+
+``amd-pstate`` is supported on ``cpupower`` tool that can be used to dump the frequency
+information. And it is in progress to support more and more operations for new
+``amd-pstate`` module with this tool. ::
+
+ root@hr-test1:/home/ray# cpupower frequency-info
+ analyzing CPU 0:
+   driver: amd-pstate
+   CPUs which run at the same hardware frequency: 0
+   CPUs which need to have their frequency coordinated by software: 0
+   maximum transition latency: 131 us
+   hardware limits: 400 MHz - 4.68 GHz
+   available cpufreq governors: ondemand conservative powersave userspace performance schedutil
+   current policy: frequency should be within 400 MHz and 4.68 GHz.
+                   The governor "schedutil" may decide which speed to use
+                   within this range.
+   current CPU frequency: Unable to call hardware
+   current CPU frequency: 4.02 GHz (asserted by call to kernel)
+   boost state support:
+     Supported: yes
+     Active: yes
+     AMD PSTATE Highest Performance: 166. Maximum Frequency: 4.68 GHz.
+     AMD PSTATE Nominal Performance: 117. Nominal Frequency: 3.30 GHz.
+     AMD PSTATE Lowest Non-linear Performance: 39. Lowest Non-linear Frequency: 1.10 GHz.
+     AMD PSTATE Lowest Performance: 15. Lowest Frequency: 400 MHz.
+
+
+Diagnostics and Tuning
+=======================
+
+Trace Events
+--------------
+
+There are two static trace events that can be used for ``amd-pstate``
+diagnostics.  One of them is the cpu_frequency trace event generally used
+by ``CPUFreq``, and the other one is the ``amd_pstate_perf`` trace event
+specific to ``amd-pstate``.  The following sequence of shell commands can
+be used to enable them and see their output (if the kernel is generally
+configured to support event tracing). ::
+
+ root@hr-test1:/home/ray# cd /sys/kernel/tracing/
+ root@hr-test1:/sys/kernel/tracing# echo 1 > events/amd_cpu/enable
+ root@hr-test1:/sys/kernel/tracing# cat trace
+ # tracer: nop
+ #
+ # entries-in-buffer/entries-written: 47827/42233061   #P:2
+ #
+ #                                _-----=> irqs-off
+ #                               / _----=> need-resched
+ #                              | / _---=> hardirq/softirq
+ #                              || / _--=> preempt-depth
+ #                              ||| /     delay
+ #           TASK-PID     CPU#  ||||   TIMESTAMP  FUNCTION
+ #              | |         |   ||||      |         |
+          <idle>-0       [015] dN...  4995.979886: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=15 changed=false fast_switch=true
+          <idle>-0       [007] d.h..  4995.979893: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=7 changed=false fast_switch=true
+             cat-2161    [000] d....  4995.980841: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=0 changed=false fast_switch=true
+            sshd-2125    [004] d.s..  4995.980968: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=4 changed=false fast_switch=true
+          <idle>-0       [007] d.s..  4995.980968: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=7 changed=false fast_switch=true
+          <idle>-0       [003] d.s..  4995.980971: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=3 changed=false fast_switch=true
+          <idle>-0       [011] d.s..  4995.980996: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=11 changed=false fast_switch=true
+
+The cpu_frequency trace event will be triggered either by the ``schedutil`` scaling
+governor (for the policies it is attached to), or by the ``CPUFreq`` core (for the
+policies with other scaling governors).
+
+
+Reference
+===========
+
+.. [1] AMD64 Architecture Programmer's Manual Volume 2: System Programming,
+       https://www.amd.com/system/files/TechDocs/24593.pdf
+
+.. [2] Advanced Configuration and Power Interface Specification,
+       https://uefi.org/sites/default/files/resources/ACPI_Spec_6_4_Jan22.pdf
+
+.. [3] Processor Programming Reference (PPR) for AMD Family 19h Model 51h, Revision A1 Processors
+       https://www.amd.com/system/files/TechDocs/56569-A1-PUB.zip
index f40994c..5d2757e 100644 (file)
@@ -11,6 +11,7 @@ Working-State Power Management
    intel_idle
    cpufreq
    intel_pstate
+   amd-pstate
    cpufreq_drivers
    intel_epb
    intel-speed-select
index 80a63d4..c98929a 100644 (file)
@@ -51,6 +51,19 @@ patternProperties:
     description:
       Properties for single BUCK regulator.
 
+    properties:
+      op_mode:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [0, 1, 2, 3]
+        default: 1
+        description: |
+          Describes the different operating modes of the regulator with power
+          mode change in SOC. The different possible values are:
+            0 - always off mode
+            1 - on in normal mode
+            2 - low power mode
+            3 - suspend mode
+
     required:
       - regulator-name
 
@@ -63,6 +76,18 @@ patternProperties:
       Properties for single BUCK regulator.
 
     properties:
+      op_mode:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [0, 1, 2, 3]
+        default: 1
+        description: |
+          Describes the different operating modes of the regulator with power
+          mode change in SOC. The different possible values are:
+            0 - always off mode
+            1 - on in normal mode
+            2 - low power mode
+            3 - suspend mode
+
       s5m8767,pmic-ext-control-gpios:
         maxItems: 1
         description: |
index 136c4e3..786c618 100644 (file)
@@ -11,9 +11,11 @@ systems.  Some systems use variants that don't meet branding requirements,
 and so are not advertised as being I2C but come under different names,
 e.g. TWI (Two Wire Interface), IIC.
 
-The official I2C specification is the `"I2C-bus specification and user
-manual" (UM10204) <https://www.nxp.com/docs/en/user-guide/UM10204.pdf>`_
-published by NXP Semiconductors.
+The latest official I2C specification is the `"I2C-bus specification and user
+manual" (UM10204) <https://www.nxp.com/webapp/Download?colCode=UM10204>`_
+published by NXP Semiconductors. However, you need to log-in to the site to
+access the PDF. An older version of the specification (revision 6) is archived
+`here <https://web.archive.org/web/20210813122132/https://www.nxp.com/docs/en/user-guide/UM10204.pdf>`_.
 
 SMBus (System Management Bus) is based on the I2C protocol, and is mostly
 a subset of I2C protocols and signaling.  Many I2C devices will work on an
index 31cfd7d..c0a789b 100644 (file)
@@ -196,11 +196,12 @@ ad_actor_sys_prio
 ad_actor_system
 
        In an AD system, this specifies the mac-address for the actor in
-       protocol packet exchanges (LACPDUs). The value cannot be NULL or
-       multicast. It is preferred to have the local-admin bit set for this
-       mac but driver does not enforce it. If the value is not given then
-       system defaults to using the masters' mac address as actors' system
-       address.
+       protocol packet exchanges (LACPDUs). The value cannot be a multicast
+       address. If the all-zeroes MAC is specified, bonding will internally
+       use the MAC of the bond itself. It is preferred to have the
+       local-admin bit set for this mac but driver does not enforce it. If
+       the value is not given then system defaults to using the masters'
+       mac address as actors' system address.
 
        This parameter has effect only in 802.3ad mode and is available through
        SysFs interface.
index d638b5a..1996477 100644 (file)
@@ -183,6 +183,7 @@ PHY and allows physical transmission and reception of Ethernet frames.
   IRQ config, enable, reset
 
 DPNI (Datapath Network Interface)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Contains TX/RX queues, network interface configuration, and RX buffer pool
 configuration mechanisms.  The TX/RX queues are in memory and are identified
 by queue number.
index c044311..2572eec 100644 (file)
@@ -25,7 +25,8 @@ ip_default_ttl - INTEGER
 ip_no_pmtu_disc - INTEGER
        Disable Path MTU Discovery. If enabled in mode 1 and a
        fragmentation-required ICMP is received, the PMTU to this
-       destination will be set to min_pmtu (see below). You will need
+       destination will be set to the smallest of the old MTU to
+       this destination and min_pmtu (see below). You will need
        to raise min_pmtu to the smallest interface MTU on your system
        manually if you want to avoid locally generated fragments.
 
@@ -49,7 +50,8 @@ ip_no_pmtu_disc - INTEGER
        Default: FALSE
 
 min_pmtu - INTEGER
-       default 552 - minimum discovered Path MTU
+       default 552 - minimum Path MTU. Unless this is changed mannually,
+       each cached pmtu will never be lower than this setting.
 
 ip_forward_use_pmtu - BOOLEAN
        By default we don't trust protocol path MTUs while forwarding
index 80b1335..f580920 100644 (file)
@@ -582,8 +582,8 @@ Time stamps for outgoing packets are to be generated as follows:
   and hardware timestamping is not possible (SKBTX_IN_PROGRESS not set).
 - As soon as the driver has sent the packet and/or obtained a
   hardware time stamp for it, it passes the time stamp back by
-  calling skb_hwtstamp_tx() with the original skb, the raw
-  hardware time stamp. skb_hwtstamp_tx() clones the original skb and
+  calling skb_tstamp_tx() with the original skb, the raw
+  hardware time stamp. skb_tstamp_tx() clones the original skb and
   adds the timestamps, therefore the original skb has to be freed now.
   If obtaining the hardware time stamp somehow fails, then the driver
   should not fall back to software time stamping. The rationale is that
index e3cc4f3..a7c03c4 100644 (file)
@@ -48,9 +48,9 @@ We can represent these as three OPPs as the following {Hz, uV} tuples:
 OPP library provides a set of helper functions to organize and query the OPP
 information. The library is located in drivers/opp/ directory and the header
 is located in include/linux/pm_opp.h. OPP library can be enabled by enabling
-CONFIG_PM_OPP from power management menuconfig menu. OPP library depends on
-CONFIG_PM as certain SoCs such as Texas Instrument's OMAP framework allows to
-optionally boot at a certain OPP without needing cpufreq.
+CONFIG_PM_OPP from power management menuconfig menu. Certain SoCs such as Texas
+Instrument's OMAP framework allows to optionally boot at a certain OPP without
+needing cpufreq.
 
 Typical usage of the OPP library is as follows::
 
@@ -75,8 +75,8 @@ operations until that OPP could be re-enabled if possible.
 
 OPP library facilitates this concept in its implementation. The following
 operational functions operate only on available opps:
-opp_find_freq_{ceil, floor}, dev_pm_opp_get_voltage, dev_pm_opp_get_freq,
-dev_pm_opp_get_opp_count
+dev_pm_opp_find_freq_{ceil, floor}, dev_pm_opp_get_voltage, dev_pm_opp_get_freq,
+dev_pm_opp_get_opp_count.
 
 dev_pm_opp_find_freq_exact is meant to be used to find the opp pointer
 which can then be used for dev_pm_opp_enable/disable functions to make an
@@ -103,7 +103,7 @@ dev_pm_opp_add
        The OPP is defined using the frequency and voltage. Once added, the OPP
        is assumed to be available and control of its availability can be done
        with the dev_pm_opp_enable/disable functions. OPP library
-       internally stores and manages this information in the opp struct.
+       internally stores and manages this information in the dev_pm_opp struct.
        This function may be used by SoC framework to define a optimal list
        as per the demands of SoC usage environment.
 
@@ -247,7 +247,7 @@ dev_pm_opp_disable
 5. OPP Data Retrieval Functions
 ===============================
 Since OPP library abstracts away the OPP information, a set of functions to pull
-information from the OPP structure is necessary. Once an OPP pointer is
+information from the dev_pm_opp structure is necessary. Once an OPP pointer is
 retrieved using the search functions, the following functions can be used by SoC
 framework to retrieve the information represented inside the OPP layer.
 
index d6bf84f..65b86e4 100644 (file)
@@ -265,6 +265,10 @@ defined in include/linux/pm.h:
       RPM_SUSPENDED, which means that each device is initially regarded by the
       PM core as 'suspended', regardless of its real hardware status
 
+  `enum rpm_status last_status;`
+    - the last runtime PM status of the device captured before disabling runtime
+      PM for it (invalid initially and when disable_depth is 0)
+
   `unsigned int runtime_auto;`
     - if set, indicates that the user space has allowed the device driver to
       power manage the device at run time via the /sys/devices/.../power/control
@@ -333,10 +337,12 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
 
   `int pm_runtime_resume(struct device *dev);`
     - execute the subsystem-level resume callback for the device; returns 0 on
-      success, 1 if the device's runtime PM status was already 'active' or
-      error code on failure, where -EAGAIN means it may be safe to attempt to
-      resume the device again in future, but 'power.runtime_error' should be
-      checked additionally, and -EACCES means that 'power.disable_depth' is
+      success, 1 if the device's runtime PM status is already 'active' (also if
+      'power.disable_depth' is nonzero, but the status was 'active' when it was
+      changing from 0 to 1) or error code on failure, where -EAGAIN means it may
+      be safe to attempt to resume the device again in future, but
+      'power.runtime_error' should be checked additionally, and -EACCES means
+      that the callback could not be run, because 'power.disable_depth' was
       different from 0
 
   `int pm_runtime_resume_and_get(struct device *dev);`
index 0ea967d..d253359 100644 (file)
@@ -326,6 +326,8 @@ usi-headset
     Headset support on USI machines
 dual-codecs
     Lenovo laptops with dual codecs
+alc285-hp-amp-init
+    HP laptops which require speaker amplifier initialization (ALC285)
 
 ALC680
 ======
index 8912b2c..f452446 100644 (file)
@@ -993,6 +993,13 @@ S: Supported
 T:     git https://gitlab.freedesktop.org/agd5f/linux.git
 F:     drivers/gpu/drm/amd/pm/
 
+AMD PSTATE DRIVER
+M:     Huang Rui <ray.huang@amd.com>
+L:     linux-pm@vger.kernel.org
+S:     Supported
+F:     Documentation/admin-guide/pm/amd-pstate.rst
+F:     drivers/cpufreq/amd-pstate*
+
 AMD PTDMA DRIVER
 M:     Sanjay R Mehta <sanju.mehta@amd.com>
 L:     dmaengine@vger.kernel.org
@@ -14845,7 +14852,7 @@ PCIE DRIVER FOR MEDIATEK
 M:     Ryder Lee <ryder.lee@mediatek.com>
 M:     Jianjun Wang <jianjun.wang@mediatek.com>
 L:     linux-pci@vger.kernel.org
-L:     linux-mediatek@lists.infradead.org
+L:     linux-mediatek@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
 F:     Documentation/devicetree/bindings/pci/mediatek*
 F:     drivers/pci/controller/*mediatek*
@@ -17423,7 +17430,7 @@ F:      drivers/video/fbdev/sm712*
 SILVACO I3C DUAL-ROLE MASTER
 M:     Miquel Raynal <miquel.raynal@bootlin.com>
 M:     Conor Culhane <conor.culhane@silvaco.com>
-L:     linux-i3c@lists.infradead.org
+L:     linux-i3c@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml
 F:     drivers/i3c/master/svc-i3c-master.c
index d85f1ff..16d7f83 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 16
 SUBLEVEL = 0
-EXTRAVERSION = -rc6
+EXTRAVERSION = -rc8
 NAME = Gobble Gobble
 
 # *DOCUMENTATION*
index b62a0db..ec6fba5 100644 (file)
 
                ethphy: ethernet-phy@1 {
                        reg = <1>;
+                       qca,clk-out-frequency = <125000000>;
                };
        };
 };
index a6f3b17..27218ea 100644 (file)
@@ -17,7 +17,6 @@
 
 #ifdef CONFIG_EFI
 void efi_init(void);
-extern void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
 
 int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
 int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
index 470299e..c7d2510 100644 (file)
@@ -23,7 +23,7 @@
 
 /* Replace task scheduler's default thermal pressure API */
 #define arch_scale_thermal_pressure topology_get_thermal_pressure
-#define arch_set_thermal_pressure   topology_set_thermal_pressure
+#define arch_update_thermal_pressure   topology_update_thermal_pressure
 
 #else
 
index deff286..5cd0578 100644 (file)
@@ -596,11 +596,9 @@ call_fpe:
        tstne   r0, #0x04000000                 @ bit 26 set on both ARM and Thumb-2
        reteq   lr
        and     r8, r0, #0x00000f00             @ mask out CP number
- THUMB(        lsr     r8, r8, #8              )
        mov     r7, #1
-       add     r6, r10, #TI_USED_CP
- ARM(  strb    r7, [r6, r8, lsr #8]    )       @ set appropriate used_cp[]
- THUMB(        strb    r7, [r6, r8]            )       @ set appropriate used_cp[]
+       add     r6, r10, r8, lsr #8             @ add used_cp[] array offset first
+       strb    r7, [r6, #TI_USED_CP]           @ set appropriate used_cp[]
 #ifdef CONFIG_IWMMXT
        @ Test if we need to give access to iWMMXt coprocessors
        ldr     r5, [r10, #TI_FLAGS]
@@ -609,7 +607,7 @@ call_fpe:
        bcs     iwmmxt_task_enable
 #endif
  ARM(  add     pc, pc, r8, lsr #6      )
- THUMB(        lsl     r8, r8, #2              )
+ THUMB(        lsr     r8, r8, #6              )
  THUMB(        add     pc, r8                  )
        nop
 
index fadfee9..950bef8 100644 (file)
@@ -114,6 +114,7 @@ ENTRY(secondary_startup)
        add     r12, r12, r10
        ret     r12
 1:     bl      __after_proc_init
+       ldr     r7, __secondary_data            @ reload r7
        ldr     sp, [r7, #12]                   @ set up the stack pointer
        ldr     r0, [r7, #16]                   @ set up task pointer
        mov     fp, #0
index d13980e..7ec5ac8 100644 (file)
@@ -69,7 +69,7 @@
        pinctrl-0 = <&emac_rgmii_pins>;
        phy-supply = <&reg_gmac_3v3>;
        phy-handle = <&ext_rgmii_phy>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        status = "okay";
 };
 
index dc8661e..2433e6f 100644 (file)
                        clock-names = "i2c";
                        clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
                                            QORIQ_CLK_PLL_DIV(16)>;
-                       scl-gpio = <&gpio2 15 GPIO_ACTIVE_HIGH>;
+                       scl-gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>;
                        status = "disabled";
                };
 
                        clock-names = "i2c";
                        clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
                                            QORIQ_CLK_PLL_DIV(16)>;
-                       scl-gpio = <&gpio2 16 GPIO_ACTIVE_HIGH>;
+                       scl-gpios = <&gpio2 16 GPIO_ACTIVE_HIGH>;
                        status = "disabled";
                };
 
index d3e1825..ad55079 100644 (file)
@@ -14,7 +14,6 @@
 
 #ifdef CONFIG_EFI
 extern void efi_init(void);
-extern void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
 #else
 #define efi_init()
 #endif
index ec2db34..f386b90 100644 (file)
@@ -32,7 +32,7 @@ void update_freq_counters_refs(void);
 
 /* Replace task scheduler's default thermal pressure API */
 #define arch_scale_thermal_pressure topology_get_thermal_pressure
-#define arch_set_thermal_pressure   topology_set_thermal_pressure
+#define arch_update_thermal_pressure   topology_update_thermal_pressure
 
 #include <asm-generic/topology.h>
 
index b2188da..011dc32 100644 (file)
@@ -85,11 +85,6 @@ config MMU
 config STACK_GROWSUP
        def_bool y
 
-config ARCH_DEFCONFIG
-       string
-       default "arch/parisc/configs/generic-32bit_defconfig" if !64BIT
-       default "arch/parisc/configs/generic-64bit_defconfig" if 64BIT
-
 config GENERIC_LOCKBREAK
        bool
        default y
index 70cf8f0..9cd4dd6 100644 (file)
@@ -14,7 +14,7 @@ static inline void
 _futex_spin_lock(u32 __user *uaddr)
 {
        extern u32 lws_lock_start[];
-       long index = ((long)uaddr & 0x3f8) >> 1;
+       long index = ((long)uaddr & 0x7f8) >> 1;
        arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
        preempt_disable();
        arch_spin_lock(s);
@@ -24,7 +24,7 @@ static inline void
 _futex_spin_unlock(u32 __user *uaddr)
 {
        extern u32 lws_lock_start[];
-       long index = ((long)uaddr & 0x3f8) >> 1;
+       long index = ((long)uaddr & 0x7f8) >> 1;
        arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
        arch_spin_unlock(s);
        preempt_enable();
index d2497b3..65c88ca 100644 (file)
@@ -472,7 +472,7 @@ lws_start:
        extrd,u %r1,PSW_W_BIT,1,%r1
        /* sp must be aligned on 4, so deposit the W bit setting into
         * the bottom of sp temporarily */
-       or,ev   %r1,%r30,%r30
+       or,od   %r1,%r30,%r30
 
        /* Clip LWS number to a 32-bit value for 32-bit processes */
        depdi   0, 31, 32, %r20
index b11fb26..892b7fc 100644 (file)
@@ -730,6 +730,8 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
                        }
                        mmap_read_unlock(current->mm);
                }
+               /* CPU could not fetch instruction, so clear stale IIR value. */
+               regs->iir = 0xbaadf00d;
                fallthrough;
        case 27: 
                /* Data memory protection ID trap */
index bf25119..32bfb21 100644 (file)
@@ -183,7 +183,7 @@ static void note_prot_wx(struct pg_state *st, unsigned long addr)
 {
        pte_t pte = __pte(st->current_flags);
 
-       if (!IS_ENABLED(CONFIG_PPC_DEBUG_WX) || !st->check_wx)
+       if (!IS_ENABLED(CONFIG_DEBUG_WX) || !st->check_wx)
                return;
 
        if (!pte_write(pte) || !pte_exec(pte))
index 49b398f..cc4f678 100644 (file)
@@ -13,7 +13,6 @@
 
 #ifdef CONFIG_EFI
 extern void efi_init(void);
-extern void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
 #else
 #define efi_init()
 #endif
index d5b5f2a..18de5f7 100644 (file)
 #define X86_FEATURE_AMD_SSBD           (13*32+24) /* "" Speculative Store Bypass Disable */
 #define X86_FEATURE_VIRT_SSBD          (13*32+25) /* Virtualized Speculative Store Bypass Disable */
 #define X86_FEATURE_AMD_SSB_NO         (13*32+26) /* "" Speculative Store Bypass is fixed in hardware. */
+#define X86_FEATURE_CPPC               (13*32+27) /* Collaborative Processor Performance Control */
 
 /* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */
 #define X86_FEATURE_DTHERM             (14*32+ 0) /* Digital Thermal Sensor */
index 4d0b126..63158fd 100644 (file)
@@ -197,8 +197,6 @@ static inline bool efi_runtime_supported(void)
 
 extern void parse_efi_setup(u64 phys_addr, u32 data_len);
 
-extern void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
-
 extern void efi_thunk_runtime_setup(void);
 efi_status_t efi_set_virtual_address_map(unsigned long memory_map_size,
                                         unsigned long descriptor_size,
index cefe1d8..9e50da3 100644 (file)
@@ -47,6 +47,7 @@ KVM_X86_OP(set_dr7)
 KVM_X86_OP(cache_reg)
 KVM_X86_OP(get_rflags)
 KVM_X86_OP(set_rflags)
+KVM_X86_OP(get_if_flag)
 KVM_X86_OP(tlb_flush_all)
 KVM_X86_OP(tlb_flush_current)
 KVM_X86_OP_NULL(tlb_remote_flush)
index 2164b9f..555f4de 100644 (file)
@@ -1349,6 +1349,7 @@ struct kvm_x86_ops {
        void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg);
        unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
        void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
+       bool (*get_if_flag)(struct kvm_vcpu *vcpu);
 
        void (*tlb_flush_all)(struct kvm_vcpu *vcpu);
        void (*tlb_flush_current)(struct kvm_vcpu *vcpu);
index 01e2650..3faf0f9 100644 (file)
 
 #define MSR_AMD64_VIRT_SPEC_CTRL       0xc001011f
 
+/* AMD Collaborative Processor Performance Control MSRs */
+#define MSR_AMD_CPPC_CAP1              0xc00102b0
+#define MSR_AMD_CPPC_ENABLE            0xc00102b1
+#define MSR_AMD_CPPC_CAP2              0xc00102b2
+#define MSR_AMD_CPPC_REQ               0xc00102b3
+#define MSR_AMD_CPPC_STATUS            0xc00102b4
+
+#define AMD_CPPC_LOWEST_PERF(x)                (((x) >> 0) & 0xff)
+#define AMD_CPPC_LOWNONLIN_PERF(x)     (((x) >> 8) & 0xff)
+#define AMD_CPPC_NOMINAL_PERF(x)       (((x) >> 16) & 0xff)
+#define AMD_CPPC_HIGHEST_PERF(x)       (((x) >> 24) & 0xff)
+
+#define AMD_CPPC_MAX_PERF(x)           (((x) & 0xff) << 0)
+#define AMD_CPPC_MIN_PERF(x)           (((x) & 0xff) << 8)
+#define AMD_CPPC_DES_PERF(x)           (((x) & 0xff) << 16)
+#define AMD_CPPC_ENERGY_PERF_PREF(x)   (((x) & 0xff) << 24)
+
 /* Fam 17h MSRs */
 #define MSR_F17H_IRPERF                        0xc00000e9
 
index 4cd49af..74f0a2d 100644 (file)
@@ -4,8 +4,8 @@
 
 #include <asm/cpufeature.h>
 
-#define PKRU_AD_BIT 0x1
-#define PKRU_WD_BIT 0x2
+#define PKRU_AD_BIT 0x1u
+#define PKRU_WD_BIT 0x2u
 #define PKRU_BITS_PER_PKEY 2
 
 #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
index cc16477..2f0b6be 100644 (file)
@@ -221,7 +221,7 @@ static inline void arch_set_max_freq_ratio(bool turbo_disabled)
 }
 #endif
 
-#ifdef CONFIG_ACPI_CPPC_LIB
+#if defined(CONFIG_ACPI_CPPC_LIB) && defined(CONFIG_SMP)
 void init_freq_invariance_cppc(void);
 #define init_freq_invariance_cppc init_freq_invariance_cppc
 #endif
index 3f85fca..1e97f94 100644 (file)
@@ -139,8 +139,10 @@ static int __init acpi_sleep_setup(char *str)
                if (strncmp(str, "s3_beep", 7) == 0)
                        acpi_realmode_flags |= 4;
 #ifdef CONFIG_HIBERNATION
+               if (strncmp(str, "s4_hwsig", 8) == 0)
+                       acpi_check_s4_hw_signature(1);
                if (strncmp(str, "s4_nohwsig", 10) == 0)
-                       acpi_no_s4_hw_signature();
+                       acpi_check_s4_hw_signature(0);
 #endif
                if (strncmp(str, "nonvs", 5) == 0)
                        acpi_nvs_nosave();
index f4dd733..fbaf12e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/syscore_ops.h>
 #include <linux/pm.h>
 
+#include <asm/cpu_device_id.h>
 #include <asm/cpufeature.h>
 #include <asm/msr.h>
 
@@ -58,6 +59,22 @@ static DEFINE_PER_CPU(u8, saved_epb);
 #define EPB_SAVED      0x10ULL
 #define MAX_EPB                EPB_MASK
 
+enum energy_perf_value_index {
+       EPB_INDEX_PERFORMANCE,
+       EPB_INDEX_BALANCE_PERFORMANCE,
+       EPB_INDEX_NORMAL,
+       EPB_INDEX_BALANCE_POWERSAVE,
+       EPB_INDEX_POWERSAVE,
+};
+
+static u8 energ_perf_values[] = {
+       [EPB_INDEX_PERFORMANCE] = ENERGY_PERF_BIAS_PERFORMANCE,
+       [EPB_INDEX_BALANCE_PERFORMANCE] = ENERGY_PERF_BIAS_BALANCE_PERFORMANCE,
+       [EPB_INDEX_NORMAL] = ENERGY_PERF_BIAS_NORMAL,
+       [EPB_INDEX_BALANCE_POWERSAVE] = ENERGY_PERF_BIAS_BALANCE_POWERSAVE,
+       [EPB_INDEX_POWERSAVE] = ENERGY_PERF_BIAS_POWERSAVE,
+};
+
 static int intel_epb_save(void)
 {
        u64 epb;
@@ -90,7 +107,7 @@ static void intel_epb_restore(void)
                 */
                val = epb & EPB_MASK;
                if (val == ENERGY_PERF_BIAS_PERFORMANCE) {
-                       val = ENERGY_PERF_BIAS_NORMAL;
+                       val = energ_perf_values[EPB_INDEX_NORMAL];
                        pr_warn_once("ENERGY_PERF_BIAS: Set to 'normal', was 'performance'\n");
                }
        }
@@ -103,18 +120,11 @@ static struct syscore_ops intel_epb_syscore_ops = {
 };
 
 static const char * const energy_perf_strings[] = {
-       "performance",
-       "balance-performance",
-       "normal",
-       "balance-power",
-       "power"
-};
-static const u8 energ_perf_values[] = {
-       ENERGY_PERF_BIAS_PERFORMANCE,
-       ENERGY_PERF_BIAS_BALANCE_PERFORMANCE,
-       ENERGY_PERF_BIAS_NORMAL,
-       ENERGY_PERF_BIAS_BALANCE_POWERSAVE,
-       ENERGY_PERF_BIAS_POWERSAVE
+       [EPB_INDEX_PERFORMANCE] = "performance",
+       [EPB_INDEX_BALANCE_PERFORMANCE] = "balance-performance",
+       [EPB_INDEX_NORMAL] = "normal",
+       [EPB_INDEX_BALANCE_POWERSAVE] = "balance-power",
+       [EPB_INDEX_POWERSAVE] = "power",
 };
 
 static ssize_t energy_perf_bias_show(struct device *dev,
@@ -193,13 +203,22 @@ static int intel_epb_offline(unsigned int cpu)
        return 0;
 }
 
+static const struct x86_cpu_id intel_epb_normal[] = {
+       X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, 7),
+       {}
+};
+
 static __init int intel_epb_init(void)
 {
+       const struct x86_cpu_id *id = x86_match_cpu(intel_epb_normal);
        int ret;
 
        if (!boot_cpu_has(X86_FEATURE_EPB))
                return -ENODEV;
 
+       if (id)
+               energ_perf_values[EPB_INDEX_NORMAL] = id->driver_data;
+
        ret = cpuhp_setup_state(CPUHP_AP_X86_INTEL_EPB_ONLINE,
                                "x86/intel/epb:online", intel_epb_online,
                                intel_epb_offline);
index 6a190c7..e04f5e6 100644 (file)
@@ -713,9 +713,6 @@ static void __init early_reserve_memory(void)
 
        early_reserve_initrd();
 
-       if (efi_enabled(EFI_BOOT))
-               efi_memblock_x86_reserve_range();
-
        memblock_x86_reserve_range_setup_data();
 
        reserve_ibft_region();
@@ -742,28 +739,6 @@ dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p)
        return 0;
 }
 
-static char * __init prepare_command_line(void)
-{
-#ifdef CONFIG_CMDLINE_BOOL
-#ifdef CONFIG_CMDLINE_OVERRIDE
-       strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
-#else
-       if (builtin_cmdline[0]) {
-               /* append boot loader cmdline to builtin */
-               strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);
-               strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE);
-               strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
-       }
-#endif
-#endif
-
-       strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
-
-       parse_early_param();
-
-       return command_line;
-}
-
 /*
  * Determine if we were loaded by an EFI loader.  If so, then we have also been
  * passed the efi memmap, systab, etc., so we should use these data structures
@@ -852,23 +827,6 @@ void __init setup_arch(char **cmdline_p)
 
        x86_init.oem.arch_setup();
 
-       /*
-        * x86_configure_nx() is called before parse_early_param() (called by
-        * prepare_command_line()) to detect whether hardware doesn't support
-        * NX (so that the early EHCI debug console setup can safely call
-        * set_fixmap()). It may then be called again from within noexec_setup()
-        * during parsing early parameters to honor the respective command line
-        * option.
-        */
-       x86_configure_nx();
-
-       /*
-        * This parses early params and it needs to run before
-        * early_reserve_memory() because latter relies on such settings
-        * supplied as early params.
-        */
-       *cmdline_p = prepare_command_line();
-
        /*
         * Do some memory reservations *before* memory is added to memblock, so
         * memblock allocations won't overwrite it.
@@ -902,6 +860,36 @@ void __init setup_arch(char **cmdline_p)
        bss_resource.start = __pa_symbol(__bss_start);
        bss_resource.end = __pa_symbol(__bss_stop)-1;
 
+#ifdef CONFIG_CMDLINE_BOOL
+#ifdef CONFIG_CMDLINE_OVERRIDE
+       strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+#else
+       if (builtin_cmdline[0]) {
+               /* append boot loader cmdline to builtin */
+               strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);
+               strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE);
+               strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+       }
+#endif
+#endif
+
+       strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
+       *cmdline_p = command_line;
+
+       /*
+        * x86_configure_nx() is called before parse_early_param() to detect
+        * whether hardware doesn't support NX (so that the early EHCI debug
+        * console setup can safely call set_fixmap()). It may then be called
+        * again from within noexec_setup() during parsing early parameters
+        * to honor the respective command line option.
+        */
+       x86_configure_nx();
+
+       parse_early_param();
+
+       if (efi_enabled(EFI_BOOT))
+               efi_memblock_x86_reserve_range();
+
 #ifdef CONFIG_MEMORY_HOTPLUG
        /*
         * Memory used by the kernel cannot be hot-removed because Linux
index b3ed302..caa96c2 100644 (file)
@@ -26,6 +26,7 @@ static gfn_t round_gfn_for_level(gfn_t gfn, int level)
  */
 void tdp_iter_restart(struct tdp_iter *iter)
 {
+       iter->yielded = false;
        iter->yielded_gfn = iter->next_last_level_gfn;
        iter->level = iter->root_level;
 
@@ -160,6 +161,11 @@ static bool try_step_up(struct tdp_iter *iter)
  */
 void tdp_iter_next(struct tdp_iter *iter)
 {
+       if (iter->yielded) {
+               tdp_iter_restart(iter);
+               return;
+       }
+
        if (try_step_down(iter))
                return;
 
index b1748b9..e19cabb 100644 (file)
@@ -45,6 +45,12 @@ struct tdp_iter {
         * iterator walks off the end of the paging structure.
         */
        bool valid;
+       /*
+        * True if KVM dropped mmu_lock and yielded in the middle of a walk, in
+        * which case tdp_iter_next() needs to restart the walk at the root
+        * level instead of advancing to the next entry.
+        */
+       bool yielded;
 };
 
 /*
index 1db8496..1beb4ca 100644 (file)
@@ -502,6 +502,8 @@ static inline bool tdp_mmu_set_spte_atomic(struct kvm *kvm,
                                           struct tdp_iter *iter,
                                           u64 new_spte)
 {
+       WARN_ON_ONCE(iter->yielded);
+
        lockdep_assert_held_read(&kvm->mmu_lock);
 
        /*
@@ -575,6 +577,8 @@ static inline void __tdp_mmu_set_spte(struct kvm *kvm, struct tdp_iter *iter,
                                      u64 new_spte, bool record_acc_track,
                                      bool record_dirty_log)
 {
+       WARN_ON_ONCE(iter->yielded);
+
        lockdep_assert_held_write(&kvm->mmu_lock);
 
        /*
@@ -640,18 +644,19 @@ static inline void tdp_mmu_set_spte_no_dirty_log(struct kvm *kvm,
  * If this function should yield and flush is set, it will perform a remote
  * TLB flush before yielding.
  *
- * If this function yields, it will also reset the tdp_iter's walk over the
- * paging structure and the calling function should skip to the next
- * iteration to allow the iterator to continue its traversal from the
- * paging structure root.
+ * If this function yields, iter->yielded is set and the caller must skip to
+ * the next iteration, where tdp_iter_next() will reset the tdp_iter's walk
+ * over the paging structures to allow the iterator to continue its traversal
+ * from the paging structure root.
  *
- * Return true if this function yielded and the iterator's traversal was reset.
- * Return false if a yield was not needed.
+ * Returns true if this function yielded.
  */
-static inline bool tdp_mmu_iter_cond_resched(struct kvm *kvm,
-                                            struct tdp_iter *iter, bool flush,
-                                            bool shared)
+static inline bool __must_check tdp_mmu_iter_cond_resched(struct kvm *kvm,
+                                                         struct tdp_iter *iter,
+                                                         bool flush, bool shared)
 {
+       WARN_ON(iter->yielded);
+
        /* Ensure forward progress has been made before yielding. */
        if (iter->next_last_level_gfn == iter->yielded_gfn)
                return false;
@@ -671,12 +676,10 @@ static inline bool tdp_mmu_iter_cond_resched(struct kvm *kvm,
 
                WARN_ON(iter->gfn > iter->next_last_level_gfn);
 
-               tdp_iter_restart(iter);
-
-               return true;
+               iter->yielded = true;
        }
 
-       return false;
+       return iter->yielded;
 }
 
 /*
index d0f68d1..5151efa 100644 (file)
@@ -1585,6 +1585,15 @@ static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
        to_svm(vcpu)->vmcb->save.rflags = rflags;
 }
 
+static bool svm_get_if_flag(struct kvm_vcpu *vcpu)
+{
+       struct vmcb *vmcb = to_svm(vcpu)->vmcb;
+
+       return sev_es_guest(vcpu->kvm)
+               ? vmcb->control.int_state & SVM_GUEST_INTERRUPT_MASK
+               : kvm_get_rflags(vcpu) & X86_EFLAGS_IF;
+}
+
 static void svm_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
 {
        switch (reg) {
@@ -3568,14 +3577,7 @@ bool svm_interrupt_blocked(struct kvm_vcpu *vcpu)
        if (!gif_set(svm))
                return true;
 
-       if (sev_es_guest(vcpu->kvm)) {
-               /*
-                * SEV-ES guests to not expose RFLAGS. Use the VMCB interrupt mask
-                * bit to determine the state of the IF flag.
-                */
-               if (!(vmcb->control.int_state & SVM_GUEST_INTERRUPT_MASK))
-                       return true;
-       } else if (is_guest_mode(vcpu)) {
+       if (is_guest_mode(vcpu)) {
                /* As long as interrupts are being delivered...  */
                if ((svm->nested.ctl.int_ctl & V_INTR_MASKING_MASK)
                    ? !(svm->vmcb01.ptr->save.rflags & X86_EFLAGS_IF)
@@ -3586,7 +3588,7 @@ bool svm_interrupt_blocked(struct kvm_vcpu *vcpu)
                if (nested_exit_on_intr(svm))
                        return false;
        } else {
-               if (!(kvm_get_rflags(vcpu) & X86_EFLAGS_IF))
+               if (!svm_get_if_flag(vcpu))
                        return true;
        }
 
@@ -4621,6 +4623,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
        .cache_reg = svm_cache_reg,
        .get_rflags = svm_get_rflags,
        .set_rflags = svm_set_rflags,
+       .get_if_flag = svm_get_if_flag,
 
        .tlb_flush_all = svm_flush_tlb,
        .tlb_flush_current = svm_flush_tlb,
index 5aadad3..0dbf94e 100644 (file)
@@ -1363,6 +1363,11 @@ void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
                vmx->emulation_required = vmx_emulation_required(vcpu);
 }
 
+static bool vmx_get_if_flag(struct kvm_vcpu *vcpu)
+{
+       return vmx_get_rflags(vcpu) & X86_EFLAGS_IF;
+}
+
 u32 vmx_get_interrupt_shadow(struct kvm_vcpu *vcpu)
 {
        u32 interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
@@ -3959,8 +3964,7 @@ static int vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
        if (pi_test_and_set_on(&vmx->pi_desc))
                return 0;
 
-       if (vcpu != kvm_get_running_vcpu() &&
-           !kvm_vcpu_trigger_posted_interrupt(vcpu, false))
+       if (!kvm_vcpu_trigger_posted_interrupt(vcpu, false))
                kvm_vcpu_kick(vcpu);
 
        return 0;
@@ -5877,18 +5881,14 @@ static int __vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
                vmx_flush_pml_buffer(vcpu);
 
        /*
-        * We should never reach this point with a pending nested VM-Enter, and
-        * more specifically emulation of L2 due to invalid guest state (see
-        * below) should never happen as that means we incorrectly allowed a
-        * nested VM-Enter with an invalid vmcs12.
+        * KVM should never reach this point with a pending nested VM-Enter.
+        * More specifically, short-circuiting VM-Entry to emulate L2 due to
+        * invalid guest state should never happen as that means KVM knowingly
+        * allowed a nested VM-Enter with an invalid vmcs12.  More below.
         */
        if (KVM_BUG_ON(vmx->nested.nested_run_pending, vcpu->kvm))
                return -EIO;
 
-       /* If guest state is invalid, start emulating */
-       if (vmx->emulation_required)
-               return handle_invalid_guest_state(vcpu);
-
        if (is_guest_mode(vcpu)) {
                /*
                 * PML is never enabled when running L2, bail immediately if a
@@ -5910,10 +5910,30 @@ static int __vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
                 */
                nested_mark_vmcs12_pages_dirty(vcpu);
 
+               /*
+                * Synthesize a triple fault if L2 state is invalid.  In normal
+                * operation, nested VM-Enter rejects any attempt to enter L2
+                * with invalid state.  However, those checks are skipped if
+                * state is being stuffed via RSM or KVM_SET_NESTED_STATE.  If
+                * L2 state is invalid, it means either L1 modified SMRAM state
+                * or userspace provided bad state.  Synthesize TRIPLE_FAULT as
+                * doing so is architecturally allowed in the RSM case, and is
+                * the least awful solution for the userspace case without
+                * risking false positives.
+                */
+               if (vmx->emulation_required) {
+                       nested_vmx_vmexit(vcpu, EXIT_REASON_TRIPLE_FAULT, 0, 0);
+                       return 1;
+               }
+
                if (nested_vmx_reflect_vmexit(vcpu))
                        return 1;
        }
 
+       /* If guest state is invalid, start emulating.  L2 is handled above. */
+       if (vmx->emulation_required)
+               return handle_invalid_guest_state(vcpu);
+
        if (exit_reason.failed_vmentry) {
                dump_vmcs(vcpu);
                vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY;
@@ -6608,9 +6628,7 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
         * consistency check VM-Exit due to invalid guest state and bail.
         */
        if (unlikely(vmx->emulation_required)) {
-
-               /* We don't emulate invalid state of a nested guest */
-               vmx->fail = is_guest_mode(vcpu);
+               vmx->fail = 0;
 
                vmx->exit_reason.full = EXIT_REASON_INVALID_STATE;
                vmx->exit_reason.failed_vmentry = 1;
@@ -7579,6 +7597,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
        .cache_reg = vmx_cache_reg,
        .get_rflags = vmx_get_rflags,
        .set_rflags = vmx_set_rflags,
+       .get_if_flag = vmx_get_if_flag,
 
        .tlb_flush_all = vmx_flush_tlb_all,
        .tlb_flush_current = vmx_flush_tlb_current,
index 9a2972f..e50e97a 100644 (file)
@@ -1331,7 +1331,7 @@ static const u32 msrs_to_save_all[] = {
        MSR_IA32_UMWAIT_CONTROL,
 
        MSR_ARCH_PERFMON_FIXED_CTR0, MSR_ARCH_PERFMON_FIXED_CTR1,
-       MSR_ARCH_PERFMON_FIXED_CTR0 + 2, MSR_ARCH_PERFMON_FIXED_CTR0 + 3,
+       MSR_ARCH_PERFMON_FIXED_CTR0 + 2,
        MSR_CORE_PERF_FIXED_CTR_CTRL, MSR_CORE_PERF_GLOBAL_STATUS,
        MSR_CORE_PERF_GLOBAL_CTRL, MSR_CORE_PERF_GLOBAL_OVF_CTRL,
        MSR_ARCH_PERFMON_PERFCTR0, MSR_ARCH_PERFMON_PERFCTR1,
@@ -9001,14 +9001,7 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *kvm_run = vcpu->run;
 
-       /*
-        * if_flag is obsolete and useless, so do not bother
-        * setting it for SEV-ES guests.  Userspace can just
-        * use kvm_run->ready_for_interrupt_injection.
-        */
-       kvm_run->if_flag = !vcpu->arch.guest_state_protected
-               && (kvm_get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
-
+       kvm_run->if_flag = static_call(kvm_x86_get_if_flag)(vcpu);
        kvm_run->cr8 = kvm_get_cr8(vcpu);
        kvm_run->apic_base = kvm_get_apic_base(vcpu);
 
index c736cf2..e2c5b29 100644 (file)
@@ -68,7 +68,7 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
        "(__parainstructions|__alt_instructions)(_end)?|"
        "(__iommu_table|__apicdrivers|__smp_locks)(_end)?|"
        "__(start|end)_pci_.*|"
-#if CONFIG_FW_LOADER_BUILTIN
+#if CONFIG_FW_LOADER
        "__(start|end)_builtin_fw|"
 #endif
        "__(start|stop)___ksymtab(_gpl)?|"
index b62c87b..e4fd5a8 100644 (file)
@@ -118,6 +118,8 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);
  */
 #define NUM_RETRIES 500ULL
 
+#define OVER_16BTS_MASK ~0xFFFFULL
+
 #define define_one_cppc_ro(_name)              \
 static struct kobj_attribute _name =           \
 __ATTR(_name, 0444, show_##_name, NULL)
@@ -411,7 +413,7 @@ bool acpi_cpc_valid(void)
        struct cpc_desc *cpc_ptr;
        int cpu;
 
-       for_each_possible_cpu(cpu) {
+       for_each_present_cpu(cpu) {
                cpc_ptr = per_cpu(cpc_desc_ptr, cpu);
                if (!cpc_ptr)
                        return false;
@@ -746,9 +748,26 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
                                                goto out_free;
                                        cpc_ptr->cpc_regs[i-2].sys_mem_vaddr = addr;
                                }
+                       } else if (gas_t->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+                               if (gas_t->access_width < 1 || gas_t->access_width > 3) {
+                                       /*
+                                        * 1 = 8-bit, 2 = 16-bit, and 3 = 32-bit.
+                                        * SystemIO doesn't implement 64-bit
+                                        * registers.
+                                        */
+                                       pr_debug("Invalid access width %d for SystemIO register\n",
+                                               gas_t->access_width);
+                                       goto out_free;
+                               }
+                               if (gas_t->address & OVER_16BTS_MASK) {
+                                       /* SystemIO registers use 16-bit integer addresses */
+                                       pr_debug("Invalid IO port %llu for SystemIO register\n",
+                                               gas_t->address);
+                                       goto out_free;
+                               }
                        } else {
                                if (gas_t->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE || !cpc_ffh_supported()) {
-                                       /* Support only PCC ,SYS MEM and FFH type regs */
+                                       /* Support only PCC, SystemMemory, SystemIO, and FFH type regs. */
                                        pr_debug("Unsupported register type: %d\n", gas_t->space_id);
                                        goto out_free;
                                }
@@ -923,7 +942,21 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
        }
 
        *val = 0;
-       if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0)
+
+       if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+               u32 width = 8 << (reg->access_width - 1);
+               acpi_status status;
+
+               status = acpi_os_read_port((acpi_io_address)reg->address,
+                                          (u32 *)val, width);
+               if (ACPI_FAILURE(status)) {
+                       pr_debug("Error: Failed to read SystemIO port %llx\n",
+                                reg->address);
+                       return -EFAULT;
+               }
+
+               return 0;
+       } else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0)
                vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id);
        else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
                vaddr = reg_res->sys_mem_vaddr;
@@ -962,7 +995,20 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
        int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
        struct cpc_reg *reg = &reg_res->cpc_entry.reg;
 
-       if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0)
+       if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+               u32 width = 8 << (reg->access_width - 1);
+               acpi_status status;
+
+               status = acpi_os_write_port((acpi_io_address)reg->address,
+                                           (u32)val, width);
+               if (ACPI_FAILURE(status)) {
+                       pr_debug("Error: Failed to write SystemIO port %llx\n",
+                                reg->address);
+                       return -EFAULT;
+               }
+
+               return 0;
+       } else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0)
                vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id);
        else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
                vaddr = reg_res->sys_mem_vaddr;
@@ -1229,6 +1275,51 @@ out_err:
 }
 EXPORT_SYMBOL_GPL(cppc_get_perf_ctrs);
 
+/**
+ * cppc_set_enable - Set to enable CPPC on the processor by writing the
+ * Continuous Performance Control package EnableRegister field.
+ * @cpu: CPU for which to enable CPPC register.
+ * @enable: 0 - disable, 1 - enable CPPC feature on the processor.
+ *
+ * Return: 0 for success, -ERRNO or -EIO otherwise.
+ */
+int cppc_set_enable(int cpu, bool enable)
+{
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
+       struct cpc_register_resource *enable_reg;
+       struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
+       struct cppc_pcc_data *pcc_ss_data = NULL;
+       int ret = -EINVAL;
+
+       if (!cpc_desc) {
+               pr_debug("No CPC descriptor for CPU:%d\n", cpu);
+               return -EINVAL;
+       }
+
+       enable_reg = &cpc_desc->cpc_regs[ENABLE];
+
+       if (CPC_IN_PCC(enable_reg)) {
+
+               if (pcc_ss_id < 0)
+                       return -EIO;
+
+               ret = cpc_write(cpu, enable_reg, enable);
+               if (ret)
+                       return ret;
+
+               pcc_ss_data = pcc_data[pcc_ss_id];
+
+               down_write(&pcc_ss_data->pcc_lock);
+               /* after writing CPC, transfer the ownership of PCC to platfrom */
+               ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE);
+               up_write(&pcc_ss_data->pcc_lock);
+               return ret;
+       }
+
+       return cpc_write(cpu, enable_reg, enable);
+}
+EXPORT_SYMBOL_GPL(cppc_set_enable);
+
 /**
  * cppc_set_perf - Set a CPU's performance controls.
  * @cpu: CPU for which to set performance controls.
index eaa4775..4dfbfc6 100644 (file)
@@ -877,11 +877,11 @@ static inline void acpi_sleep_syscore_init(void) {}
 #ifdef CONFIG_HIBERNATION
 static unsigned long s4_hardware_signature;
 static struct acpi_table_facs *facs;
-static bool nosigcheck;
+static int sigcheck = -1; /* Default behaviour is just to warn */
 
-void __init acpi_no_s4_hw_signature(void)
+void __init acpi_check_s4_hw_signature(int check)
 {
-       nosigcheck = true;
+       sigcheck = check;
 }
 
 static int acpi_hibernation_begin(pm_message_t stage)
@@ -1009,12 +1009,28 @@ static void acpi_sleep_hibernate_setup(void)
        hibernation_set_ops(old_suspend_ordering ?
                        &acpi_hibernation_ops_old : &acpi_hibernation_ops);
        sleep_states[ACPI_STATE_S4] = 1;
-       if (nosigcheck)
+       if (!sigcheck)
                return;
 
        acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs);
-       if (facs)
+       if (facs) {
+               /*
+                * s4_hardware_signature is the local variable which is just
+                * used to warn about mismatch after we're attempting to
+                * resume (in violation of the ACPI specification.)
+                */
                s4_hardware_signature = facs->hardware_signature;
+
+               if (sigcheck > 0) {
+                       /*
+                        * If we're actually obeying the ACPI specification
+                        * then the signature is written out as part of the
+                        * swsusp header, in order to allow the boot kernel
+                        * to gracefully decline to resume.
+                        */
+                       swsusp_hardware_signature = facs->hardware_signature;
+               }
+       }
 }
 #else /* !CONFIG_HIBERNATION */
 static inline void acpi_sleep_hibernate_setup(void) {}
index 340515f..47bc74a 100644 (file)
@@ -671,7 +671,7 @@ static void binder_free_buf_locked(struct binder_alloc *alloc,
        BUG_ON(buffer->user_data > alloc->buffer + alloc->buffer_size);
 
        if (buffer->async_transaction) {
-               alloc->free_async_space += size + sizeof(struct binder_buffer);
+               alloc->free_async_space += buffer_size + sizeof(struct binder_buffer);
 
                binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
                             "%d: binder_free_buf size %zd async free %zd\n",
index 304accd..6d309e4 100644 (file)
@@ -37,7 +37,7 @@ struct charlcd_priv {
        bool must_clear;
 
        /* contains the LCD config state */
-       unsigned long int flags;
+       unsigned long flags;
 
        /* Current escape sequence and it's length or -1 if outside */
        struct {
@@ -578,6 +578,9 @@ static int charlcd_init(struct charlcd *lcd)
         * Since charlcd_init_display() needs to write data, we have to
         * enable mark the LCD initialized just before.
         */
+       if (WARN_ON(!lcd->ops->init_display))
+               return -EINVAL;
+
        ret = lcd->ops->init_display(lcd);
        if (ret)
                return ret;
index ff16a36..9761541 100644 (file)
@@ -22,6 +22,7 @@
 static DEFINE_PER_CPU(struct scale_freq_data __rcu *, sft_data);
 static struct cpumask scale_freq_counters_mask;
 static bool scale_freq_invariant;
+static DEFINE_PER_CPU(u32, freq_factor) = 1;
 
 static bool supports_scale_freq_counters(const struct cpumask *cpus)
 {
@@ -155,15 +156,49 @@ void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity)
 
 DEFINE_PER_CPU(unsigned long, thermal_pressure);
 
-void topology_set_thermal_pressure(const struct cpumask *cpus,
-                              unsigned long th_pressure)
+/**
+ * topology_update_thermal_pressure() - Update thermal pressure for CPUs
+ * @cpus        : The related CPUs for which capacity has been reduced
+ * @capped_freq : The maximum allowed frequency that CPUs can run at
+ *
+ * Update the value of thermal pressure for all @cpus in the mask. The
+ * cpumask should include all (online+offline) affected CPUs, to avoid
+ * operating on stale data when hot-plug is used for some CPUs. The
+ * @capped_freq reflects the currently allowed max CPUs frequency due to
+ * thermal capping. It might be also a boost frequency value, which is bigger
+ * than the internal 'freq_factor' max frequency. In such case the pressure
+ * value should simply be removed, since this is an indication that there is
+ * no thermal throttling. The @capped_freq must be provided in kHz.
+ */
+void topology_update_thermal_pressure(const struct cpumask *cpus,
+                                     unsigned long capped_freq)
 {
+       unsigned long max_capacity, capacity, th_pressure;
+       u32 max_freq;
        int cpu;
 
+       cpu = cpumask_first(cpus);
+       max_capacity = arch_scale_cpu_capacity(cpu);
+       max_freq = per_cpu(freq_factor, cpu);
+
+       /* Convert to MHz scale which is used in 'freq_factor' */
+       capped_freq /= 1000;
+
+       /*
+        * Handle properly the boost frequencies, which should simply clean
+        * the thermal pressure value.
+        */
+       if (max_freq <= capped_freq)
+               capacity = max_capacity;
+       else
+               capacity = mult_frac(max_capacity, capped_freq, max_freq);
+
+       th_pressure = max_capacity - capacity;
+
        for_each_cpu(cpu, cpus)
                WRITE_ONCE(per_cpu(thermal_pressure, cpu), th_pressure);
 }
-EXPORT_SYMBOL_GPL(topology_set_thermal_pressure);
+EXPORT_SYMBOL_GPL(topology_update_thermal_pressure);
 
 static ssize_t cpu_capacity_show(struct device *dev,
                                 struct device_attribute *attr,
@@ -217,7 +252,6 @@ static void update_topology_flags_workfn(struct work_struct *work)
        update_topology = 0;
 }
 
-static DEFINE_PER_CPU(u32, freq_factor) = 1;
 static u32 *raw_capacity;
 
 static int free_raw_capacity(void)
index fd034d7..b191bd1 100644 (file)
@@ -485,8 +485,7 @@ static void device_link_release_fn(struct work_struct *work)
        /* Ensure that all references to the link object have been dropped. */
        device_link_synchronize_removal();
 
-       while (refcount_dec_not_one(&link->rpm_active))
-               pm_runtime_put(link->supplier);
+       pm_runtime_release_supplier(link, true);
 
        put_device(link->consumer);
        put_device(link->supplier);
index f4d0c55..04ea92c 100644 (file)
@@ -1902,7 +1902,7 @@ int dpm_prepare(pm_message_t state)
        device_block_probing();
 
        mutex_lock(&dpm_list_mtx);
-       while (!list_empty(&dpm_list)) {
+       while (!list_empty(&dpm_list) && !error) {
                struct device *dev = to_device(dpm_list.next);
 
                get_device(dev);
index d504cd4..2f3cce1 100644 (file)
@@ -305,19 +305,40 @@ static int rpm_get_suppliers(struct device *dev)
        return 0;
 }
 
+/**
+ * pm_runtime_release_supplier - Drop references to device link's supplier.
+ * @link: Target device link.
+ * @check_idle: Whether or not to check if the supplier device is idle.
+ *
+ * Drop all runtime PM references associated with @link to its supplier device
+ * and if @check_idle is set, check if that device is idle (and so it can be
+ * suspended).
+ */
+void pm_runtime_release_supplier(struct device_link *link, bool check_idle)
+{
+       struct device *supplier = link->supplier;
+
+       /*
+        * The additional power.usage_count check is a safety net in case
+        * the rpm_active refcount becomes saturated, in which case
+        * refcount_dec_not_one() would return true forever, but it is not
+        * strictly necessary.
+        */
+       while (refcount_dec_not_one(&link->rpm_active) &&
+              atomic_read(&supplier->power.usage_count) > 0)
+               pm_runtime_put_noidle(supplier);
+
+       if (check_idle)
+               pm_request_idle(supplier);
+}
+
 static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
 {
        struct device_link *link;
 
        list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
-                               device_links_read_lock_held()) {
-
-               while (refcount_dec_not_one(&link->rpm_active))
-                       pm_runtime_put_noidle(link->supplier);
-
-               if (try_to_suspend)
-                       pm_request_idle(link->supplier);
-       }
+                               device_links_read_lock_held())
+               pm_runtime_release_supplier(link, try_to_suspend);
 }
 
 static void rpm_put_suppliers(struct device *dev)
@@ -742,13 +763,15 @@ static int rpm_resume(struct device *dev, int rpmflags)
        trace_rpm_resume_rcuidle(dev, rpmflags);
 
  repeat:
-       if (dev->power.runtime_error)
+       if (dev->power.runtime_error) {
                retval = -EINVAL;
-       else if (dev->power.disable_depth == 1 && dev->power.is_suspended
-           && dev->power.runtime_status == RPM_ACTIVE)
-               retval = 1;
-       else if (dev->power.disable_depth > 0)
-               retval = -EACCES;
+       } else if (dev->power.disable_depth > 0) {
+               if (dev->power.runtime_status == RPM_ACTIVE &&
+                   dev->power.last_status == RPM_ACTIVE)
+                       retval = 1;
+               else
+                       retval = -EACCES;
+       }
        if (retval)
                goto out;
 
@@ -1410,8 +1433,10 @@ void __pm_runtime_disable(struct device *dev, bool check_resume)
        /* Update time accounting before disabling PM-runtime. */
        update_pm_runtime_accounting(dev);
 
-       if (!dev->power.disable_depth++)
+       if (!dev->power.disable_depth++) {
                __pm_runtime_barrier(dev);
+               dev->power.last_status = dev->power.runtime_status;
+       }
 
  out:
        spin_unlock_irq(&dev->power.lock);
@@ -1428,23 +1453,23 @@ void pm_runtime_enable(struct device *dev)
 
        spin_lock_irqsave(&dev->power.lock, flags);
 
-       if (dev->power.disable_depth > 0) {
-               dev->power.disable_depth--;
-
-               /* About to enable runtime pm, set accounting_timestamp to now */
-               if (!dev->power.disable_depth)
-                       dev->power.accounting_timestamp = ktime_get_mono_fast_ns();
-       } else {
+       if (!dev->power.disable_depth) {
                dev_warn(dev, "Unbalanced %s!\n", __func__);
+               goto out;
        }
 
-       WARN(!dev->power.disable_depth &&
-            dev->power.runtime_status == RPM_SUSPENDED &&
-            !dev->power.ignore_children &&
-            atomic_read(&dev->power.child_count) > 0,
-            "Enabling runtime PM for inactive device (%s) with active children\n",
-            dev_name(dev));
+       if (--dev->power.disable_depth > 0)
+               goto out;
+
+       dev->power.last_status = RPM_INVALID;
+       dev->power.accounting_timestamp = ktime_get_mono_fast_ns();
+
+       if (dev->power.runtime_status == RPM_SUSPENDED &&
+           !dev->power.ignore_children &&
+           atomic_read(&dev->power.child_count) > 0)
+               dev_warn(dev, "Enabling runtime PM for inactive device with active children\n");
 
+out:
        spin_unlock_irqrestore(&dev->power.lock, flags);
 }
 EXPORT_SYMBOL_GPL(pm_runtime_enable);
@@ -1640,6 +1665,7 @@ EXPORT_SYMBOL_GPL(__pm_runtime_use_autosuspend);
 void pm_runtime_init(struct device *dev)
 {
        dev->power.runtime_status = RPM_SUSPENDED;
+       dev->power.last_status = RPM_INVALID;
        dev->power.idle_notification = false;
 
        dev->power.disable_depth = 1;
@@ -1722,8 +1748,6 @@ void pm_runtime_get_suppliers(struct device *dev)
 void pm_runtime_put_suppliers(struct device *dev)
 {
        struct device_link *link;
-       unsigned long flags;
-       bool put;
        int idx;
 
        idx = device_links_read_lock();
@@ -1731,11 +1755,17 @@ void pm_runtime_put_suppliers(struct device *dev)
        list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
                                device_links_read_lock_held())
                if (link->supplier_preactivated) {
+                       bool put;
+
                        link->supplier_preactivated = false;
-                       spin_lock_irqsave(&dev->power.lock, flags);
+
+                       spin_lock_irq(&dev->power.lock);
+
                        put = pm_runtime_status_suspended(dev) &&
                              refcount_dec_not_one(&link->rpm_active);
-                       spin_unlock_irqrestore(&dev->power.lock, flags);
+
+                       spin_unlock_irq(&dev->power.lock);
+
                        if (put)
                                pm_runtime_put(link->supplier);
                }
@@ -1772,9 +1802,7 @@ void pm_runtime_drop_link(struct device_link *link)
                return;
 
        pm_runtime_drop_link_count(link->consumer);
-
-       while (refcount_dec_not_one(&link->rpm_active))
-               pm_runtime_put(link->supplier);
+       pm_runtime_release_supplier(link, true);
 }
 
 static bool pm_runtime_need_not_resume(struct device *dev)
index 8e3983e..286cf1a 100644 (file)
@@ -1512,9 +1512,12 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
        unsigned long flags;
        struct blkfront_ring_info *rinfo = (struct blkfront_ring_info *)dev_id;
        struct blkfront_info *info = rinfo->dev_info;
+       unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
 
-       if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
+       if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) {
+               xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS);
                return IRQ_HANDLED;
+       }
 
        spin_lock_irqsave(&rinfo->ring_lock, flags);
  again:
@@ -1530,6 +1533,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
                unsigned long id;
                unsigned int op;
 
+               eoiflag = 0;
+
                RING_COPY_RESPONSE(&rinfo->ring, i, &bret);
                id = bret.id;
 
@@ -1646,6 +1651,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
 
        spin_unlock_irqrestore(&rinfo->ring_lock, flags);
 
+       xen_irq_lateeoi(irq, eoiflag);
+
        return IRQ_HANDLED;
 
  err:
@@ -1653,6 +1660,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
 
        spin_unlock_irqrestore(&rinfo->ring_lock, flags);
 
+       /* No EOI in order to avoid further interrupts. */
+
        pr_alert("%s disabled for further use\n", info->gd->disk_name);
        return IRQ_HANDLED;
 }
@@ -1692,8 +1701,8 @@ static int setup_blkring(struct xenbus_device *dev,
        if (err)
                goto fail;
 
-       err = bind_evtchn_to_irqhandler(rinfo->evtchn, blkif_interrupt, 0,
-                                       "blkif", rinfo);
+       err = bind_evtchn_to_irqhandler_lateeoi(rinfo->evtchn, blkif_interrupt,
+                                               0, "blkif", rinfo);
        if (err <= 0) {
                xenbus_dev_fatal(dev, err,
                                 "bind_evtchn_to_irqhandler failed");
index 6f225dd..4566e73 100644 (file)
@@ -687,11 +687,11 @@ err_clk_disable:
 
 static void sunxi_rsb_hw_exit(struct sunxi_rsb *rsb)
 {
-       /* Keep the clock and PM reference counts consistent. */
-       if (pm_runtime_status_suspended(rsb->dev))
-               pm_runtime_resume(rsb->dev);
        reset_control_assert(rsb->rstc);
-       clk_disable_unprepare(rsb->clk);
+
+       /* Keep the clock and PM reference counts consistent. */
+       if (!pm_runtime_status_suspended(rsb->dev))
+               clk_disable_unprepare(rsb->clk);
 }
 
 static int __maybe_unused sunxi_rsb_runtime_suspend(struct device *dev)
index c837d54..c592651 100644 (file)
@@ -3031,7 +3031,7 @@ cleanup_bmc_device(struct kref *ref)
         * with removing the device attributes while reading a device
         * attribute.
         */
-       schedule_work(&bmc->remove_work);
+       queue_work(remove_work_wq, &bmc->remove_work);
 }
 
 /*
@@ -5392,22 +5392,27 @@ static int ipmi_init_msghandler(void)
        if (initialized)
                goto out;
 
-       init_srcu_struct(&ipmi_interfaces_srcu);
-
-       timer_setup(&ipmi_timer, ipmi_timeout, 0);
-       mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
-
-       atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
+       rv = init_srcu_struct(&ipmi_interfaces_srcu);
+       if (rv)
+               goto out;
 
        remove_work_wq = create_singlethread_workqueue("ipmi-msghandler-remove-wq");
        if (!remove_work_wq) {
                pr_err("unable to create ipmi-msghandler-remove-wq workqueue");
                rv = -ENOMEM;
-               goto out;
+               goto out_wq;
        }
 
+       timer_setup(&ipmi_timer, ipmi_timeout, 0);
+       mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
+
+       atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
+
        initialized = true;
 
+out_wq:
+       if (rv)
+               cleanup_srcu_struct(&ipmi_interfaces_srcu);
 out:
        mutex_unlock(&ipmi_interfaces_mutex);
        return rv;
index 0c62e57..48aab77 100644 (file)
@@ -1659,6 +1659,9 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
                }
        }
 
+       ssif_info->client = client;
+       i2c_set_clientdata(client, ssif_info);
+
        rv = ssif_check_and_remove(client, ssif_info);
        /* If rv is 0 and addr source is not SI_ACPI, continue probing */
        if (!rv && ssif_info->addr_source == SI_ACPI) {
@@ -1679,9 +1682,6 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
                ipmi_addr_src_to_str(ssif_info->addr_source),
                client->addr, client->adapter->name, slave_addr);
 
-       ssif_info->client = client;
-       i2c_set_clientdata(client, ssif_info);
-
        /* Now check for system interface capabilities */
        msg[0] = IPMI_NETFN_APP_REQUEST << 2;
        msg[1] = IPMI_GET_SYSTEM_INTERFACE_CAPABILITIES_CMD;
@@ -1881,6 +1881,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
                dev_err(&ssif_info->client->dev,
                        "Unable to start IPMI SSIF: %d\n", rv);
+               i2c_set_clientdata(client, NULL);
                kfree(ssif_info);
        }
        kfree(resp);
index 92701a1..5551604 100644 (file)
@@ -34,6 +34,23 @@ config X86_PCC_CPUFREQ
 
          If in doubt, say N.
 
+config X86_AMD_PSTATE
+       tristate "AMD Processor P-State driver"
+       depends on X86 && ACPI
+       select ACPI_PROCESSOR
+       select ACPI_CPPC_LIB if X86_64
+       select CPU_FREQ_GOV_SCHEDUTIL if SMP
+       help
+         This driver adds a CPUFreq driver which utilizes a fine grain
+         processor performance frequency control range instead of legacy
+         performance levels. _CPC needs to be present in the ACPI tables
+         of the system.
+
+         For details, take a look at:
+         <file:Documentation/admin-guide/pm/amd-pstate.rst>.
+
+         If in doubt, say N.
+
 config X86_ACPI_CPUFREQ
        tristate "ACPI Processor P-States driver"
        depends on ACPI_PROCESSOR
index 48ee585..285de70 100644 (file)
@@ -17,6 +17,10 @@ obj-$(CONFIG_CPU_FREQ_GOV_ATTR_SET)  += cpufreq_governor_attr_set.o
 obj-$(CONFIG_CPUFREQ_DT)               += cpufreq-dt.o
 obj-$(CONFIG_CPUFREQ_DT_PLATDEV)       += cpufreq-dt-platdev.o
 
+# Traces
+CFLAGS_amd-pstate-trace.o               := -I$(src)
+amd_pstate-y                           := amd-pstate.o amd-pstate-trace.o
+
 ##################################################################################
 # x86 drivers.
 # Link order matters. K8 is preferred to ACPI because of firmware bugs in early
@@ -25,6 +29,7 @@ obj-$(CONFIG_CPUFREQ_DT_PLATDEV)      += cpufreq-dt-platdev.o
 # speedstep-* is preferred over p4-clockmod.
 
 obj-$(CONFIG_X86_ACPI_CPUFREQ)         += acpi-cpufreq.o
+obj-$(CONFIG_X86_AMD_PSTATE)           += amd_pstate.o
 obj-$(CONFIG_X86_POWERNOW_K8)          += powernow-k8.o
 obj-$(CONFIG_X86_PCC_CPUFREQ)          += pcc-cpufreq.o
 obj-$(CONFIG_X86_POWERNOW_K6)          += powernow-k6.o
diff --git a/drivers/cpufreq/amd-pstate-trace.c b/drivers/cpufreq/amd-pstate-trace.c
new file mode 100644 (file)
index 0000000..891b696
--- /dev/null
@@ -0,0 +1,2 @@
+#define CREATE_TRACE_POINTS
+#include "amd-pstate-trace.h"
diff --git a/drivers/cpufreq/amd-pstate-trace.h b/drivers/cpufreq/amd-pstate-trace.h
new file mode 100644 (file)
index 0000000..6475059
--- /dev/null
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * amd-pstate-trace.h - AMD Processor P-state Frequency Driver Tracer
+ *
+ * Copyright (C) 2021 Advanced Micro Devices, Inc. All Rights Reserved.
+ *
+ * Author: Huang Rui <ray.huang@amd.com>
+ */
+
+#if !defined(_AMD_PSTATE_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _AMD_PSTATE_TRACE_H
+
+#include <linux/cpufreq.h>
+#include <linux/tracepoint.h>
+#include <linux/trace_events.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM amd_cpu
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE amd-pstate-trace
+
+#define TPS(x)  tracepoint_string(x)
+
+TRACE_EVENT(amd_pstate_perf,
+
+       TP_PROTO(unsigned long min_perf,
+                unsigned long target_perf,
+                unsigned long capacity,
+                unsigned int cpu_id,
+                bool changed,
+                bool fast_switch
+                ),
+
+       TP_ARGS(min_perf,
+               target_perf,
+               capacity,
+               cpu_id,
+               changed,
+               fast_switch
+               ),
+
+       TP_STRUCT__entry(
+               __field(unsigned long, min_perf)
+               __field(unsigned long, target_perf)
+               __field(unsigned long, capacity)
+               __field(unsigned int, cpu_id)
+               __field(bool, changed)
+               __field(bool, fast_switch)
+               ),
+
+       TP_fast_assign(
+               __entry->min_perf = min_perf;
+               __entry->target_perf = target_perf;
+               __entry->capacity = capacity;
+               __entry->cpu_id = cpu_id;
+               __entry->changed = changed;
+               __entry->fast_switch = fast_switch;
+               ),
+
+       TP_printk("amd_min_perf=%lu amd_des_perf=%lu amd_max_perf=%lu cpu_id=%u changed=%s fast_switch=%s",
+                 (unsigned long)__entry->min_perf,
+                 (unsigned long)__entry->target_perf,
+                 (unsigned long)__entry->capacity,
+                 (unsigned int)__entry->cpu_id,
+                 (__entry->changed) ? "true" : "false",
+                 (__entry->fast_switch) ? "true" : "false"
+                )
+);
+
+#endif /* _AMD_PSTATE_TRACE_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#include <trace/define_trace.h>
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
new file mode 100644 (file)
index 0000000..9ce75ed
--- /dev/null
@@ -0,0 +1,645 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * amd-pstate.c - AMD Processor P-state Frequency Driver
+ *
+ * Copyright (C) 2021 Advanced Micro Devices, Inc. All Rights Reserved.
+ *
+ * Author: Huang Rui <ray.huang@amd.com>
+ *
+ * AMD P-State introduces a new CPU performance scaling design for AMD
+ * processors using the ACPI Collaborative Performance and Power Control (CPPC)
+ * feature which works with the AMD SMU firmware providing a finer grained
+ * frequency control range. It is to replace the legacy ACPI P-States control,
+ * allows a flexible, low-latency interface for the Linux kernel to directly
+ * communicate the performance hints to hardware.
+ *
+ * AMD P-State is supported on recent AMD Zen base CPU series include some of
+ * Zen2 and Zen3 processors. _CPC needs to be present in the ACPI tables of AMD
+ * P-State supported system. And there are two types of hardware implementations
+ * for AMD P-State: 1) Full MSR Solution and 2) Shared Memory Solution.
+ * X86_FEATURE_CPPC CPU feature flag is used to distinguish the different types.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/sched.h>
+#include <linux/cpufreq.h>
+#include <linux/compiler.h>
+#include <linux/dmi.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/static_call.h>
+
+#include <acpi/processor.h>
+#include <acpi/cppc_acpi.h>
+
+#include <asm/msr.h>
+#include <asm/processor.h>
+#include <asm/cpufeature.h>
+#include <asm/cpu_device_id.h>
+#include "amd-pstate-trace.h"
+
+#define AMD_PSTATE_TRANSITION_LATENCY  0x20000
+#define AMD_PSTATE_TRANSITION_DELAY    500
+
+/*
+ * TODO: We need more time to fine tune processors with shared memory solution
+ * with community together.
+ *
+ * There are some performance drops on the CPU benchmarks which reports from
+ * Suse. We are co-working with them to fine tune the shared memory solution. So
+ * we disable it by default to go acpi-cpufreq on these processors and add a
+ * module parameter to be able to enable it manually for debugging.
+ */
+static bool shared_mem = false;
+module_param(shared_mem, bool, 0444);
+MODULE_PARM_DESC(shared_mem,
+                "enable amd-pstate on processors with shared memory solution (false = disabled (default), true = enabled)");
+
+static struct cpufreq_driver amd_pstate_driver;
+
+/**
+ * struct amd_cpudata - private CPU data for AMD P-State
+ * @cpu: CPU number
+ * @req: constraint request to apply
+ * @cppc_req_cached: cached performance request hints
+ * @highest_perf: the maximum performance an individual processor may reach,
+ *               assuming ideal conditions
+ * @nominal_perf: the maximum sustained performance level of the processor,
+ *               assuming ideal operating conditions
+ * @lowest_nonlinear_perf: the lowest performance level at which nonlinear power
+ *                        savings are achieved
+ * @lowest_perf: the absolute lowest performance level of the processor
+ * @max_freq: the frequency that mapped to highest_perf
+ * @min_freq: the frequency that mapped to lowest_perf
+ * @nominal_freq: the frequency that mapped to nominal_perf
+ * @lowest_nonlinear_freq: the frequency that mapped to lowest_nonlinear_perf
+ * @boost_supported: check whether the Processor or SBIOS supports boost mode
+ *
+ * The amd_cpudata is key private data for each CPU thread in AMD P-State, and
+ * represents all the attributes and goals that AMD P-State requests at runtime.
+ */
+struct amd_cpudata {
+       int     cpu;
+
+       struct  freq_qos_request req[2];
+       u64     cppc_req_cached;
+
+       u32     highest_perf;
+       u32     nominal_perf;
+       u32     lowest_nonlinear_perf;
+       u32     lowest_perf;
+
+       u32     max_freq;
+       u32     min_freq;
+       u32     nominal_freq;
+       u32     lowest_nonlinear_freq;
+
+       bool    boost_supported;
+};
+
+static inline int pstate_enable(bool enable)
+{
+       return wrmsrl_safe(MSR_AMD_CPPC_ENABLE, enable);
+}
+
+static int cppc_enable(bool enable)
+{
+       int cpu, ret = 0;
+
+       for_each_present_cpu(cpu) {
+               ret = cppc_set_enable(cpu, enable);
+               if (ret)
+                       return ret;
+       }
+
+       return ret;
+}
+
+DEFINE_STATIC_CALL(amd_pstate_enable, pstate_enable);
+
+static inline int amd_pstate_enable(bool enable)
+{
+       return static_call(amd_pstate_enable)(enable);
+}
+
+static int pstate_init_perf(struct amd_cpudata *cpudata)
+{
+       u64 cap1;
+
+       int ret = rdmsrl_safe_on_cpu(cpudata->cpu, MSR_AMD_CPPC_CAP1,
+                                    &cap1);
+       if (ret)
+               return ret;
+
+       /*
+        * TODO: Introduce AMD specific power feature.
+        *
+        * CPPC entry doesn't indicate the highest performance in some ASICs.
+        */
+       WRITE_ONCE(cpudata->highest_perf, amd_get_highest_perf());
+
+       WRITE_ONCE(cpudata->nominal_perf, AMD_CPPC_NOMINAL_PERF(cap1));
+       WRITE_ONCE(cpudata->lowest_nonlinear_perf, AMD_CPPC_LOWNONLIN_PERF(cap1));
+       WRITE_ONCE(cpudata->lowest_perf, AMD_CPPC_LOWEST_PERF(cap1));
+
+       return 0;
+}
+
+static int cppc_init_perf(struct amd_cpudata *cpudata)
+{
+       struct cppc_perf_caps cppc_perf;
+
+       int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf);
+       if (ret)
+               return ret;
+
+       WRITE_ONCE(cpudata->highest_perf, amd_get_highest_perf());
+
+       WRITE_ONCE(cpudata->nominal_perf, cppc_perf.nominal_perf);
+       WRITE_ONCE(cpudata->lowest_nonlinear_perf,
+                  cppc_perf.lowest_nonlinear_perf);
+       WRITE_ONCE(cpudata->lowest_perf, cppc_perf.lowest_perf);
+
+       return 0;
+}
+
+DEFINE_STATIC_CALL(amd_pstate_init_perf, pstate_init_perf);
+
+static inline int amd_pstate_init_perf(struct amd_cpudata *cpudata)
+{
+       return static_call(amd_pstate_init_perf)(cpudata);
+}
+
+static void pstate_update_perf(struct amd_cpudata *cpudata, u32 min_perf,
+                              u32 des_perf, u32 max_perf, bool fast_switch)
+{
+       if (fast_switch)
+               wrmsrl(MSR_AMD_CPPC_REQ, READ_ONCE(cpudata->cppc_req_cached));
+       else
+               wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ,
+                             READ_ONCE(cpudata->cppc_req_cached));
+}
+
+static void cppc_update_perf(struct amd_cpudata *cpudata,
+                            u32 min_perf, u32 des_perf,
+                            u32 max_perf, bool fast_switch)
+{
+       struct cppc_perf_ctrls perf_ctrls;
+
+       perf_ctrls.max_perf = max_perf;
+       perf_ctrls.min_perf = min_perf;
+       perf_ctrls.desired_perf = des_perf;
+
+       cppc_set_perf(cpudata->cpu, &perf_ctrls);
+}
+
+DEFINE_STATIC_CALL(amd_pstate_update_perf, pstate_update_perf);
+
+static inline void amd_pstate_update_perf(struct amd_cpudata *cpudata,
+                                         u32 min_perf, u32 des_perf,
+                                         u32 max_perf, bool fast_switch)
+{
+       static_call(amd_pstate_update_perf)(cpudata, min_perf, des_perf,
+                                           max_perf, fast_switch);
+}
+
+static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf,
+                             u32 des_perf, u32 max_perf, bool fast_switch)
+{
+       u64 prev = READ_ONCE(cpudata->cppc_req_cached);
+       u64 value = prev;
+
+       value &= ~AMD_CPPC_MIN_PERF(~0L);
+       value |= AMD_CPPC_MIN_PERF(min_perf);
+
+       value &= ~AMD_CPPC_DES_PERF(~0L);
+       value |= AMD_CPPC_DES_PERF(des_perf);
+
+       value &= ~AMD_CPPC_MAX_PERF(~0L);
+       value |= AMD_CPPC_MAX_PERF(max_perf);
+
+       trace_amd_pstate_perf(min_perf, des_perf, max_perf,
+                             cpudata->cpu, (value != prev), fast_switch);
+
+       if (value == prev)
+               return;
+
+       WRITE_ONCE(cpudata->cppc_req_cached, value);
+
+       amd_pstate_update_perf(cpudata, min_perf, des_perf,
+                              max_perf, fast_switch);
+}
+
+static int amd_pstate_verify(struct cpufreq_policy_data *policy)
+{
+       cpufreq_verify_within_cpu_limits(policy);
+
+       return 0;
+}
+
+static int amd_pstate_target(struct cpufreq_policy *policy,
+                            unsigned int target_freq,
+                            unsigned int relation)
+{
+       struct cpufreq_freqs freqs;
+       struct amd_cpudata *cpudata = policy->driver_data;
+       unsigned long max_perf, min_perf, des_perf, cap_perf;
+
+       if (!cpudata->max_freq)
+               return -ENODEV;
+
+       cap_perf = READ_ONCE(cpudata->highest_perf);
+       min_perf = READ_ONCE(cpudata->lowest_nonlinear_perf);
+       max_perf = cap_perf;
+
+       freqs.old = policy->cur;
+       freqs.new = target_freq;
+
+       des_perf = DIV_ROUND_CLOSEST(target_freq * cap_perf,
+                                    cpudata->max_freq);
+
+       cpufreq_freq_transition_begin(policy, &freqs);
+       amd_pstate_update(cpudata, min_perf, des_perf,
+                         max_perf, false);
+       cpufreq_freq_transition_end(policy, &freqs, false);
+
+       return 0;
+}
+
+static void amd_pstate_adjust_perf(unsigned int cpu,
+                                  unsigned long _min_perf,
+                                  unsigned long target_perf,
+                                  unsigned long capacity)
+{
+       unsigned long max_perf, min_perf, des_perf,
+                     cap_perf, lowest_nonlinear_perf;
+       struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+       struct amd_cpudata *cpudata = policy->driver_data;
+
+       cap_perf = READ_ONCE(cpudata->highest_perf);
+       lowest_nonlinear_perf = READ_ONCE(cpudata->lowest_nonlinear_perf);
+
+       des_perf = cap_perf;
+       if (target_perf < capacity)
+               des_perf = DIV_ROUND_UP(cap_perf * target_perf, capacity);
+
+       min_perf = READ_ONCE(cpudata->highest_perf);
+       if (_min_perf < capacity)
+               min_perf = DIV_ROUND_UP(cap_perf * _min_perf, capacity);
+
+       if (min_perf < lowest_nonlinear_perf)
+               min_perf = lowest_nonlinear_perf;
+
+       max_perf = cap_perf;
+       if (max_perf < min_perf)
+               max_perf = min_perf;
+
+       des_perf = clamp_t(unsigned long, des_perf, min_perf, max_perf);
+
+       amd_pstate_update(cpudata, min_perf, des_perf, max_perf, true);
+}
+
+static int amd_get_min_freq(struct amd_cpudata *cpudata)
+{
+       struct cppc_perf_caps cppc_perf;
+
+       int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf);
+       if (ret)
+               return ret;
+
+       /* Switch to khz */
+       return cppc_perf.lowest_freq * 1000;
+}
+
+static int amd_get_max_freq(struct amd_cpudata *cpudata)
+{
+       struct cppc_perf_caps cppc_perf;
+       u32 max_perf, max_freq, nominal_freq, nominal_perf;
+       u64 boost_ratio;
+
+       int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf);
+       if (ret)
+               return ret;
+
+       nominal_freq = cppc_perf.nominal_freq;
+       nominal_perf = READ_ONCE(cpudata->nominal_perf);
+       max_perf = READ_ONCE(cpudata->highest_perf);
+
+       boost_ratio = div_u64(max_perf << SCHED_CAPACITY_SHIFT,
+                             nominal_perf);
+
+       max_freq = nominal_freq * boost_ratio >> SCHED_CAPACITY_SHIFT;
+
+       /* Switch to khz */
+       return max_freq * 1000;
+}
+
+static int amd_get_nominal_freq(struct amd_cpudata *cpudata)
+{
+       struct cppc_perf_caps cppc_perf;
+
+       int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf);
+       if (ret)
+               return ret;
+
+       /* Switch to khz */
+       return cppc_perf.nominal_freq * 1000;
+}
+
+static int amd_get_lowest_nonlinear_freq(struct amd_cpudata *cpudata)
+{
+       struct cppc_perf_caps cppc_perf;
+       u32 lowest_nonlinear_freq, lowest_nonlinear_perf,
+           nominal_freq, nominal_perf;
+       u64 lowest_nonlinear_ratio;
+
+       int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf);
+       if (ret)
+               return ret;
+
+       nominal_freq = cppc_perf.nominal_freq;
+       nominal_perf = READ_ONCE(cpudata->nominal_perf);
+
+       lowest_nonlinear_perf = cppc_perf.lowest_nonlinear_perf;
+
+       lowest_nonlinear_ratio = div_u64(lowest_nonlinear_perf << SCHED_CAPACITY_SHIFT,
+                                        nominal_perf);
+
+       lowest_nonlinear_freq = nominal_freq * lowest_nonlinear_ratio >> SCHED_CAPACITY_SHIFT;
+
+       /* Switch to khz */
+       return lowest_nonlinear_freq * 1000;
+}
+
+static int amd_pstate_set_boost(struct cpufreq_policy *policy, int state)
+{
+       struct amd_cpudata *cpudata = policy->driver_data;
+       int ret;
+
+       if (!cpudata->boost_supported) {
+               pr_err("Boost mode is not supported by this processor or SBIOS\n");
+               return -EINVAL;
+       }
+
+       if (state)
+               policy->cpuinfo.max_freq = cpudata->max_freq;
+       else
+               policy->cpuinfo.max_freq = cpudata->nominal_freq;
+
+       policy->max = policy->cpuinfo.max_freq;
+
+       ret = freq_qos_update_request(&cpudata->req[1],
+                                     policy->cpuinfo.max_freq);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static void amd_pstate_boost_init(struct amd_cpudata *cpudata)
+{
+       u32 highest_perf, nominal_perf;
+
+       highest_perf = READ_ONCE(cpudata->highest_perf);
+       nominal_perf = READ_ONCE(cpudata->nominal_perf);
+
+       if (highest_perf <= nominal_perf)
+               return;
+
+       cpudata->boost_supported = true;
+       amd_pstate_driver.boost_enabled = true;
+}
+
+static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
+{
+       int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret;
+       struct device *dev;
+       struct amd_cpudata *cpudata;
+
+       dev = get_cpu_device(policy->cpu);
+       if (!dev)
+               return -ENODEV;
+
+       cpudata = kzalloc(sizeof(*cpudata), GFP_KERNEL);
+       if (!cpudata)
+               return -ENOMEM;
+
+       cpudata->cpu = policy->cpu;
+
+       ret = amd_pstate_init_perf(cpudata);
+       if (ret)
+               goto free_cpudata1;
+
+       min_freq = amd_get_min_freq(cpudata);
+       max_freq = amd_get_max_freq(cpudata);
+       nominal_freq = amd_get_nominal_freq(cpudata);
+       lowest_nonlinear_freq = amd_get_lowest_nonlinear_freq(cpudata);
+
+       if (min_freq < 0 || max_freq < 0 || min_freq > max_freq) {
+               dev_err(dev, "min_freq(%d) or max_freq(%d) value is incorrect\n",
+                       min_freq, max_freq);
+               ret = -EINVAL;
+               goto free_cpudata1;
+       }
+
+       policy->cpuinfo.transition_latency = AMD_PSTATE_TRANSITION_LATENCY;
+       policy->transition_delay_us = AMD_PSTATE_TRANSITION_DELAY;
+
+       policy->min = min_freq;
+       policy->max = max_freq;
+
+       policy->cpuinfo.min_freq = min_freq;
+       policy->cpuinfo.max_freq = max_freq;
+
+       /* It will be updated by governor */
+       policy->cur = policy->cpuinfo.min_freq;
+
+       if (boot_cpu_has(X86_FEATURE_CPPC))
+               policy->fast_switch_possible = true;
+
+       ret = freq_qos_add_request(&policy->constraints, &cpudata->req[0],
+                                  FREQ_QOS_MIN, policy->cpuinfo.min_freq);
+       if (ret < 0) {
+               dev_err(dev, "Failed to add min-freq constraint (%d)\n", ret);
+               goto free_cpudata1;
+       }
+
+       ret = freq_qos_add_request(&policy->constraints, &cpudata->req[1],
+                                  FREQ_QOS_MAX, policy->cpuinfo.max_freq);
+       if (ret < 0) {
+               dev_err(dev, "Failed to add max-freq constraint (%d)\n", ret);
+               goto free_cpudata2;
+       }
+
+       /* Initial processor data capability frequencies */
+       cpudata->max_freq = max_freq;
+       cpudata->min_freq = min_freq;
+       cpudata->nominal_freq = nominal_freq;
+       cpudata->lowest_nonlinear_freq = lowest_nonlinear_freq;
+
+       policy->driver_data = cpudata;
+
+       amd_pstate_boost_init(cpudata);
+
+       return 0;
+
+free_cpudata2:
+       freq_qos_remove_request(&cpudata->req[0]);
+free_cpudata1:
+       kfree(cpudata);
+       return ret;
+}
+
+static int amd_pstate_cpu_exit(struct cpufreq_policy *policy)
+{
+       struct amd_cpudata *cpudata;
+
+       cpudata = policy->driver_data;
+
+       freq_qos_remove_request(&cpudata->req[1]);
+       freq_qos_remove_request(&cpudata->req[0]);
+       kfree(cpudata);
+
+       return 0;
+}
+
+/* Sysfs attributes */
+
+/*
+ * This frequency is to indicate the maximum hardware frequency.
+ * If boost is not active but supported, the frequency will be larger than the
+ * one in cpuinfo.
+ */
+static ssize_t show_amd_pstate_max_freq(struct cpufreq_policy *policy,
+                                       char *buf)
+{
+       int max_freq;
+       struct amd_cpudata *cpudata;
+
+       cpudata = policy->driver_data;
+
+       max_freq = amd_get_max_freq(cpudata);
+       if (max_freq < 0)
+               return max_freq;
+
+       return sprintf(&buf[0], "%u\n", max_freq);
+}
+
+static ssize_t show_amd_pstate_lowest_nonlinear_freq(struct cpufreq_policy *policy,
+                                                    char *buf)
+{
+       int freq;
+       struct amd_cpudata *cpudata;
+
+       cpudata = policy->driver_data;
+
+       freq = amd_get_lowest_nonlinear_freq(cpudata);
+       if (freq < 0)
+               return freq;
+
+       return sprintf(&buf[0], "%u\n", freq);
+}
+
+/*
+ * In some of ASICs, the highest_perf is not the one in the _CPC table, so we
+ * need to expose it to sysfs.
+ */
+static ssize_t show_amd_pstate_highest_perf(struct cpufreq_policy *policy,
+                                           char *buf)
+{
+       u32 perf;
+       struct amd_cpudata *cpudata = policy->driver_data;
+
+       perf = READ_ONCE(cpudata->highest_perf);
+
+       return sprintf(&buf[0], "%u\n", perf);
+}
+
+cpufreq_freq_attr_ro(amd_pstate_max_freq);
+cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq);
+
+cpufreq_freq_attr_ro(amd_pstate_highest_perf);
+
+static struct freq_attr *amd_pstate_attr[] = {
+       &amd_pstate_max_freq,
+       &amd_pstate_lowest_nonlinear_freq,
+       &amd_pstate_highest_perf,
+       NULL,
+};
+
+static struct cpufreq_driver amd_pstate_driver = {
+       .flags          = CPUFREQ_CONST_LOOPS | CPUFREQ_NEED_UPDATE_LIMITS,
+       .verify         = amd_pstate_verify,
+       .target         = amd_pstate_target,
+       .init           = amd_pstate_cpu_init,
+       .exit           = amd_pstate_cpu_exit,
+       .set_boost      = amd_pstate_set_boost,
+       .name           = "amd-pstate",
+       .attr           = amd_pstate_attr,
+};
+
+static int __init amd_pstate_init(void)
+{
+       int ret;
+
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+               return -ENODEV;
+
+       if (!acpi_cpc_valid()) {
+               pr_debug("the _CPC object is not present in SBIOS\n");
+               return -ENODEV;
+       }
+
+       /* don't keep reloading if cpufreq_driver exists */
+       if (cpufreq_get_current_driver())
+               return -EEXIST;
+
+       /* capability check */
+       if (boot_cpu_has(X86_FEATURE_CPPC)) {
+               pr_debug("AMD CPPC MSR based functionality is supported\n");
+               amd_pstate_driver.adjust_perf = amd_pstate_adjust_perf;
+       } else if (shared_mem) {
+               static_call_update(amd_pstate_enable, cppc_enable);
+               static_call_update(amd_pstate_init_perf, cppc_init_perf);
+               static_call_update(amd_pstate_update_perf, cppc_update_perf);
+       } else {
+               pr_info("This processor supports shared memory solution, you can enable it with amd_pstate.shared_mem=1\n");
+               return -ENODEV;
+       }
+
+       /* enable amd pstate feature */
+       ret = amd_pstate_enable(true);
+       if (ret) {
+               pr_err("failed to enable amd-pstate with return %d\n", ret);
+               return ret;
+       }
+
+       ret = cpufreq_register_driver(&amd_pstate_driver);
+       if (ret)
+               pr_err("failed to register amd_pstate_driver with return %d\n",
+                      ret);
+
+       return ret;
+}
+
+static void __exit amd_pstate_exit(void)
+{
+       cpufreq_unregister_driver(&amd_pstate_driver);
+
+       amd_pstate_enable(false);
+}
+
+module_init(amd_pstate_init);
+module_exit(amd_pstate_exit);
+
+MODULE_AUTHOR("Huang Rui <ray.huang@amd.com>");
+MODULE_DESCRIPTION("AMD Processor P-state Frequency Driver");
+MODULE_LICENSE("GPL");
index 096c384..b8d9553 100644 (file)
@@ -924,7 +924,7 @@ cpufreq_freq_attr_rw(scaling_max_freq);
 cpufreq_freq_attr_rw(scaling_governor);
 cpufreq_freq_attr_rw(scaling_setspeed);
 
-static struct attribute *default_attrs[] = {
+static struct attribute *cpufreq_attrs[] = {
        &cpuinfo_min_freq.attr,
        &cpuinfo_max_freq.attr,
        &cpuinfo_transition_latency.attr,
@@ -938,6 +938,7 @@ static struct attribute *default_attrs[] = {
        &scaling_setspeed.attr,
        NULL
 };
+ATTRIBUTE_GROUPS(cpufreq);
 
 #define to_policy(k) container_of(k, struct cpufreq_policy, kobj)
 #define to_attr(a) container_of(a, struct freq_attr, attr)
@@ -1000,7 +1001,7 @@ static const struct sysfs_ops sysfs_ops = {
 
 static struct kobj_type ktype_cpufreq = {
        .sysfs_ops      = &sysfs_ops,
-       .default_attrs  = default_attrs,
+       .default_groups = cpufreq_groups,
        .release        = cpufreq_sysfs_release,
 };
 
@@ -1403,7 +1404,7 @@ static int cpufreq_online(unsigned int cpu)
 
                ret = freq_qos_add_request(&policy->constraints,
                                           policy->min_freq_req, FREQ_QOS_MIN,
-                                          policy->min);
+                                          FREQ_QOS_MIN_DEFAULT_VALUE);
                if (ret < 0) {
                        /*
                         * So we don't call freq_qos_remove_request() for an
@@ -1423,7 +1424,7 @@ static int cpufreq_online(unsigned int cpu)
 
                ret = freq_qos_add_request(&policy->constraints,
                                           policy->max_freq_req, FREQ_QOS_MAX,
-                                          policy->max);
+                                          FREQ_QOS_MAX_DEFAULT_VALUE);
                if (ret < 0) {
                        policy->max_freq_req = NULL;
                        goto out_destroy_policy;
index 0879ec3..08515f7 100644 (file)
@@ -257,7 +257,7 @@ gov_attr_rw(ignore_nice_load);
 gov_attr_rw(down_threshold);
 gov_attr_rw(freq_step);
 
-static struct attribute *cs_attributes[] = {
+static struct attribute *cs_attrs[] = {
        &sampling_rate.attr,
        &sampling_down_factor.attr,
        &up_threshold.attr,
@@ -266,6 +266,7 @@ static struct attribute *cs_attributes[] = {
        &freq_step.attr,
        NULL
 };
+ATTRIBUTE_GROUPS(cs);
 
 /************************** sysfs end ************************/
 
@@ -315,7 +316,7 @@ static void cs_start(struct cpufreq_policy *policy)
 
 static struct dbs_governor cs_governor = {
        .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
-       .kobj_type = { .default_attrs = cs_attributes },
+       .kobj_type = { .default_groups = cs_groups },
        .gov_dbs_update = cs_dbs_update,
        .alloc = cs_alloc,
        .free = cs_free,
index 3b8f924..6a41ea4 100644 (file)
@@ -328,7 +328,7 @@ gov_attr_rw(sampling_down_factor);
 gov_attr_rw(ignore_nice_load);
 gov_attr_rw(powersave_bias);
 
-static struct attribute *od_attributes[] = {
+static struct attribute *od_attrs[] = {
        &sampling_rate.attr,
        &up_threshold.attr,
        &sampling_down_factor.attr,
@@ -337,6 +337,7 @@ static struct attribute *od_attributes[] = {
        &io_is_busy.attr,
        NULL
 };
+ATTRIBUTE_GROUPS(od);
 
 /************************** sysfs end ************************/
 
@@ -401,7 +402,7 @@ static struct od_ops od_ops = {
 
 static struct dbs_governor od_dbs_gov = {
        .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("ondemand"),
-       .kobj_type = { .default_attrs = od_attributes },
+       .kobj_type = { .default_groups = od_groups },
        .gov_dbs_update = od_dbs_update,
        .alloc = od_alloc,
        .free = od_free,
index dec2a56..bc7f7e6 100644 (file)
@@ -664,19 +664,29 @@ static int intel_pstate_set_epb(int cpu, s16 pref)
  *     3               balance_power
  *     4               power
  */
+
+enum energy_perf_value_index {
+       EPP_INDEX_DEFAULT = 0,
+       EPP_INDEX_PERFORMANCE,
+       EPP_INDEX_BALANCE_PERFORMANCE,
+       EPP_INDEX_BALANCE_POWERSAVE,
+       EPP_INDEX_POWERSAVE,
+};
+
 static const char * const energy_perf_strings[] = {
-       "default",
-       "performance",
-       "balance_performance",
-       "balance_power",
-       "power",
+       [EPP_INDEX_DEFAULT] = "default",
+       [EPP_INDEX_PERFORMANCE] = "performance",
+       [EPP_INDEX_BALANCE_PERFORMANCE] = "balance_performance",
+       [EPP_INDEX_BALANCE_POWERSAVE] = "balance_power",
+       [EPP_INDEX_POWERSAVE] = "power",
        NULL
 };
-static const unsigned int epp_values[] = {
-       HWP_EPP_PERFORMANCE,
-       HWP_EPP_BALANCE_PERFORMANCE,
-       HWP_EPP_BALANCE_POWERSAVE,
-       HWP_EPP_POWERSAVE
+static unsigned int epp_values[] = {
+       [EPP_INDEX_DEFAULT] = 0, /* Unused index */
+       [EPP_INDEX_PERFORMANCE] = HWP_EPP_PERFORMANCE,
+       [EPP_INDEX_BALANCE_PERFORMANCE] = HWP_EPP_BALANCE_PERFORMANCE,
+       [EPP_INDEX_BALANCE_POWERSAVE] = HWP_EPP_BALANCE_POWERSAVE,
+       [EPP_INDEX_POWERSAVE] = HWP_EPP_POWERSAVE,
 };
 
 static int intel_pstate_get_energy_pref_index(struct cpudata *cpu_data, int *raw_epp)
@@ -690,14 +700,14 @@ static int intel_pstate_get_energy_pref_index(struct cpudata *cpu_data, int *raw
                return epp;
 
        if (boot_cpu_has(X86_FEATURE_HWP_EPP)) {
-               if (epp == HWP_EPP_PERFORMANCE)
-                       return 1;
-               if (epp == HWP_EPP_BALANCE_PERFORMANCE)
-                       return 2;
-               if (epp == HWP_EPP_BALANCE_POWERSAVE)
-                       return 3;
-               if (epp == HWP_EPP_POWERSAVE)
-                       return 4;
+               if (epp == epp_values[EPP_INDEX_PERFORMANCE])
+                       return EPP_INDEX_PERFORMANCE;
+               if (epp == epp_values[EPP_INDEX_BALANCE_PERFORMANCE])
+                       return EPP_INDEX_BALANCE_PERFORMANCE;
+               if (epp == epp_values[EPP_INDEX_BALANCE_POWERSAVE])
+                       return EPP_INDEX_BALANCE_POWERSAVE;
+               if (epp == epp_values[EPP_INDEX_POWERSAVE])
+                       return EPP_INDEX_POWERSAVE;
                *raw_epp = epp;
                return 0;
        } else if (boot_cpu_has(X86_FEATURE_EPB)) {
@@ -757,7 +767,7 @@ static int intel_pstate_set_energy_pref_index(struct cpudata *cpu_data,
                if (use_raw)
                        epp = raw_epp;
                else if (epp == -EINVAL)
-                       epp = epp_values[pref_index - 1];
+                       epp = epp_values[pref_index];
 
                /*
                 * To avoid confusion, refuse to set EPP to any values different
@@ -843,7 +853,7 @@ static ssize_t store_energy_performance_preference(
                 * upfront.
                 */
                if (!raw)
-                       epp = ret ? epp_values[ret - 1] : cpu->epp_default;
+                       epp = ret ? epp_values[ret] : cpu->epp_default;
 
                if (cpu->epp_cached != epp) {
                        int err;
@@ -1124,19 +1134,22 @@ static void intel_pstate_update_policies(void)
                cpufreq_update_policy(cpu);
 }
 
+static void __intel_pstate_update_max_freq(struct cpudata *cpudata,
+                                          struct cpufreq_policy *policy)
+{
+       policy->cpuinfo.max_freq = global.turbo_disabled_mf ?
+                       cpudata->pstate.max_freq : cpudata->pstate.turbo_freq;
+       refresh_frequency_limits(policy);
+}
+
 static void intel_pstate_update_max_freq(unsigned int cpu)
 {
        struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu);
-       struct cpudata *cpudata;
 
        if (!policy)
                return;
 
-       cpudata = all_cpu_data[cpu];
-       policy->cpuinfo.max_freq = global.turbo_disabled_mf ?
-                       cpudata->pstate.max_freq : cpudata->pstate.turbo_freq;
-
-       refresh_frequency_limits(policy);
+       __intel_pstate_update_max_freq(all_cpu_data[cpu], policy);
 
        cpufreq_cpu_release(policy);
 }
@@ -1584,8 +1597,15 @@ static void intel_pstate_notify_work(struct work_struct *work)
 {
        struct cpudata *cpudata =
                container_of(to_delayed_work(work), struct cpudata, hwp_notify_work);
+       struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpudata->cpu);
+
+       if (policy) {
+               intel_pstate_get_hwp_cap(cpudata);
+               __intel_pstate_update_max_freq(cpudata, policy);
+
+               cpufreq_cpu_release(policy);
+       }
 
-       cpufreq_update_policy(cpudata->cpu);
        wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_STATUS, 0);
 }
 
@@ -1679,10 +1699,18 @@ static void intel_pstate_hwp_enable(struct cpudata *cpudata)
                wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x00);
 
        wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1);
-       if (cpudata->epp_default == -EINVAL)
-               cpudata->epp_default = intel_pstate_get_epp(cpudata, 0);
 
        intel_pstate_enable_hwp_interrupt(cpudata);
+
+       if (cpudata->epp_default >= 0)
+               return;
+
+       if (epp_values[EPP_INDEX_BALANCE_PERFORMANCE] == HWP_EPP_BALANCE_PERFORMANCE) {
+               cpudata->epp_default = intel_pstate_get_epp(cpudata, 0);
+       } else {
+               cpudata->epp_default = epp_values[EPP_INDEX_BALANCE_PERFORMANCE];
+               intel_pstate_set_epp(cpudata, cpudata->epp_default);
+       }
 }
 
 static int atom_get_min_pstate(void)
@@ -2486,18 +2514,14 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu,
         * HWP needs some special consideration, because HWP_REQUEST uses
         * abstract values to represent performance rather than pure ratios.
         */
-       if (hwp_active) {
-               intel_pstate_get_hwp_cap(cpu);
+       if (hwp_active && cpu->pstate.scaling != perf_ctl_scaling) {
+               int scaling = cpu->pstate.scaling;
+               int freq;
 
-               if (cpu->pstate.scaling != perf_ctl_scaling) {
-                       int scaling = cpu->pstate.scaling;
-                       int freq;
-
-                       freq = max_policy_perf * perf_ctl_scaling;
-                       max_policy_perf = DIV_ROUND_UP(freq, scaling);
-                       freq = min_policy_perf * perf_ctl_scaling;
-                       min_policy_perf = DIV_ROUND_UP(freq, scaling);
-               }
+               freq = max_policy_perf * perf_ctl_scaling;
+               max_policy_perf = DIV_ROUND_UP(freq, scaling);
+               freq = min_policy_perf * perf_ctl_scaling;
+               min_policy_perf = DIV_ROUND_UP(freq, scaling);
        }
 
        pr_debug("cpu:%d min_policy_perf:%d max_policy_perf:%d\n",
@@ -3349,6 +3373,16 @@ static bool intel_pstate_hwp_is_enabled(void)
        return !!(value & 0x1);
 }
 
+static const struct x86_cpu_id intel_epp_balance_perf[] = {
+       /*
+        * Set EPP value as 102, this is the max suggested EPP
+        * which can result in one core turbo frequency for
+        * AlderLake Mobile CPUs.
+        */
+       X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, 102),
+       {}
+};
+
 static int __init intel_pstate_init(void)
 {
        static struct cpudata **_all_cpu_data;
@@ -3438,6 +3472,13 @@ hwp_cpu_matched:
 
        intel_pstate_sysfs_expose_params();
 
+       if (hwp_active) {
+               const struct x86_cpu_id *id = x86_match_cpu(intel_epp_balance_perf);
+
+               if (id)
+                       epp_values[EPP_INDEX_BALANCE_PERFORMANCE] = id->driver_data;
+       }
+
        mutex_lock(&intel_pstate_driver_lock);
        rc = intel_pstate_register_driver(default_driver);
        mutex_unlock(&intel_pstate_driver_lock);
index 8ddbd0c..0a94c56 100644 (file)
@@ -36,6 +36,8 @@ enum {
 struct mtk_cpufreq_data {
        struct cpufreq_frequency_table *table;
        void __iomem *reg_bases[REG_ARRAY_SIZE];
+       struct resource *res;
+       void __iomem *base;
        int nr_opp;
 };
 
@@ -156,6 +158,7 @@ static int mtk_cpu_resources_init(struct platform_device *pdev,
 {
        struct mtk_cpufreq_data *data;
        struct device *dev = &pdev->dev;
+       struct resource *res;
        void __iomem *base;
        int ret, i;
        int index;
@@ -170,9 +173,26 @@ static int mtk_cpu_resources_init(struct platform_device *pdev,
        if (index < 0)
                return index;
 
-       base = devm_platform_ioremap_resource(pdev, index);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, index);
+       if (!res) {
+               dev_err(dev, "failed to get mem resource %d\n", index);
+               return -ENODEV;
+       }
+
+       if (!request_mem_region(res->start, resource_size(res), res->name)) {
+               dev_err(dev, "failed to request resource %pR\n", res);
+               return -EBUSY;
+       }
+
+       base = ioremap(res->start, resource_size(res));
+       if (!base) {
+               dev_err(dev, "failed to map resource %pR\n", res);
+               ret = -ENOMEM;
+               goto release_region;
+       }
+
+       data->base = base;
+       data->res = res;
 
        for (i = REG_FREQ_LUT_TABLE; i < REG_ARRAY_SIZE; i++)
                data->reg_bases[i] = base + offsets[i];
@@ -187,6 +207,9 @@ static int mtk_cpu_resources_init(struct platform_device *pdev,
        policy->driver_data = data;
 
        return 0;
+release_region:
+       release_mem_region(res->start, resource_size(res));
+       return ret;
 }
 
 static int mtk_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
@@ -233,9 +256,13 @@ static int mtk_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
 static int mtk_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
 {
        struct mtk_cpufreq_data *data = policy->driver_data;
+       struct resource *res = data->res;
+       void __iomem *base = data->base;
 
        /* HW should be in paused state now */
        writel_relaxed(0x0, data->reg_bases[REG_FREQ_ENABLE]);
+       iounmap(base);
+       release_mem_region(res->start, resource_size(res));
 
        return 0;
 }
index a2be0df..05f3d78 100644 (file)
@@ -46,6 +46,7 @@ struct qcom_cpufreq_data {
         */
        struct mutex throttle_lock;
        int throttle_irq;
+       char irq_name[15];
        bool cancel_throttle;
        struct delayed_work throttle_work;
        struct cpufreq_policy *policy;
@@ -275,10 +276,10 @@ static unsigned int qcom_lmh_get_throttle_freq(struct qcom_cpufreq_data *data)
 
 static void qcom_lmh_dcvs_notify(struct qcom_cpufreq_data *data)
 {
-       unsigned long max_capacity, capacity, freq_hz, throttled_freq;
        struct cpufreq_policy *policy = data->policy;
        int cpu = cpumask_first(policy->cpus);
        struct device *dev = get_cpu_device(cpu);
+       unsigned long freq_hz, throttled_freq;
        struct dev_pm_opp *opp;
        unsigned int freq;
 
@@ -295,16 +296,8 @@ static void qcom_lmh_dcvs_notify(struct qcom_cpufreq_data *data)
 
        throttled_freq = freq_hz / HZ_PER_KHZ;
 
-       /* Update thermal pressure */
-
-       max_capacity = arch_scale_cpu_capacity(cpu);
-       capacity = mult_frac(max_capacity, throttled_freq, policy->cpuinfo.max_freq);
-
-       /* Don't pass boost capacity to scheduler */
-       if (capacity > max_capacity)
-               capacity = max_capacity;
-
-       arch_set_thermal_pressure(policy->cpus, max_capacity - capacity);
+       /* Update thermal pressure (the boost frequencies are accepted) */
+       arch_update_thermal_pressure(policy->related_cpus, throttled_freq);
 
        /*
         * In the unlikely case policy is unregistered do not enable
@@ -342,9 +335,9 @@ static irqreturn_t qcom_lmh_dcvs_handle_irq(int irq, void *data)
 
        /* Disable interrupt and enable polling */
        disable_irq_nosync(c_data->throttle_irq);
-       qcom_lmh_dcvs_notify(c_data);
+       schedule_delayed_work(&c_data->throttle_work, 0);
 
-       return 0;
+       return IRQ_HANDLED;
 }
 
 static const struct qcom_cpufreq_soc_data qcom_soc_data = {
@@ -375,16 +368,17 @@ static int qcom_cpufreq_hw_lmh_init(struct cpufreq_policy *policy, int index)
 {
        struct qcom_cpufreq_data *data = policy->driver_data;
        struct platform_device *pdev = cpufreq_get_driver_data();
-       char irq_name[15];
        int ret;
 
        /*
         * Look for LMh interrupt. If no interrupt line is specified /
         * if there is an error, allow cpufreq to be enabled as usual.
         */
-       data->throttle_irq = platform_get_irq(pdev, index);
-       if (data->throttle_irq <= 0)
-               return data->throttle_irq == -EPROBE_DEFER ? -EPROBE_DEFER : 0;
+       data->throttle_irq = platform_get_irq_optional(pdev, index);
+       if (data->throttle_irq == -ENXIO)
+               return 0;
+       if (data->throttle_irq < 0)
+               return data->throttle_irq;
 
        data->cancel_throttle = false;
        data->policy = policy;
@@ -392,14 +386,19 @@ static int qcom_cpufreq_hw_lmh_init(struct cpufreq_policy *policy, int index)
        mutex_init(&data->throttle_lock);
        INIT_DEFERRABLE_WORK(&data->throttle_work, qcom_lmh_dcvs_poll);
 
-       snprintf(irq_name, sizeof(irq_name), "dcvsh-irq-%u", policy->cpu);
+       snprintf(data->irq_name, sizeof(data->irq_name), "dcvsh-irq-%u", policy->cpu);
        ret = request_threaded_irq(data->throttle_irq, NULL, qcom_lmh_dcvs_handle_irq,
-                                  IRQF_ONESHOT, irq_name, data);
+                                  IRQF_ONESHOT, data->irq_name, data);
        if (ret) {
-               dev_err(&pdev->dev, "Error registering %s: %d\n", irq_name, ret);
+               dev_err(&pdev->dev, "Error registering %s: %d\n", data->irq_name, ret);
                return 0;
        }
 
+       ret = irq_set_affinity_hint(data->throttle_irq, policy->cpus);
+       if (ret)
+               dev_err(&pdev->dev, "Failed to set CPU affinity of %s[%d]\n",
+                       data->irq_name, data->throttle_irq);
+
        return 0;
 }
 
index 2e56704..c492268 100644 (file)
@@ -34,7 +34,7 @@
  * 1) Energy break even point
  * 2) Performance impact
  * 3) Latency tolerance (from pmqos infrastructure)
- * These these three factors are treated independently.
+ * These three factors are treated independently.
  *
  * Energy break even point
  * -----------------------
index 469e185..2b496a5 100644 (file)
@@ -335,6 +335,7 @@ static struct attribute *cpuidle_state_default_attrs[] = {
        &attr_default_status.attr,
        NULL
 };
+ATTRIBUTE_GROUPS(cpuidle_state_default);
 
 struct cpuidle_state_kobj {
        struct cpuidle_state *state;
@@ -448,7 +449,7 @@ static void cpuidle_state_sysfs_release(struct kobject *kobj)
 
 static struct kobj_type ktype_state_cpuidle = {
        .sysfs_ops = &cpuidle_state_sysfs_ops,
-       .default_attrs = cpuidle_state_default_attrs,
+       .default_groups = cpuidle_state_default_groups,
        .release = cpuidle_state_sysfs_release,
 };
 
@@ -505,7 +506,7 @@ error_state:
 }
 
 /**
- * cpuidle_remove_driver_sysfs - removes the cpuidle states sysfs attributes
+ * cpuidle_remove_state_sysfs - removes the cpuidle states sysfs attributes
  * @device: the target device
  */
 static void cpuidle_remove_state_sysfs(struct cpuidle_device *device)
@@ -591,10 +592,11 @@ static struct attribute *cpuidle_driver_default_attrs[] = {
        &attr_driver_name.attr,
        NULL
 };
+ATTRIBUTE_GROUPS(cpuidle_driver_default);
 
 static struct kobj_type ktype_driver_cpuidle = {
        .sysfs_ops = &cpuidle_driver_sysfs_ops,
-       .default_attrs = cpuidle_driver_default_attrs,
+       .default_groups = cpuidle_driver_default_groups,
        .release = cpuidle_driver_sysfs_release,
 };
 
index fa768f1..fd29861 100644 (file)
@@ -211,6 +211,12 @@ static u32 uof_get_ae_mask(u32 obj_num)
        return adf_4xxx_fw_config[obj_num].ae_mask;
 }
 
+static u32 get_vf2pf_sources(void __iomem *pmisc_addr)
+{
+       /* For the moment do not report vf2pf sources */
+       return 0;
+}
+
 void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data)
 {
        hw_data->dev_class = &adf_4xxx_class;
@@ -254,6 +260,7 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data)
        hw_data->set_msix_rttable = set_msix_default_rttable;
        hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer;
        hw_data->enable_pfvf_comms = pfvf_comms_disabled;
+       hw_data->get_vf2pf_sources = get_vf2pf_sources;
        hw_data->disable_iov = adf_disable_sriov;
        hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION;
 
index e87d01c..87eb2b8 100644 (file)
@@ -132,6 +132,15 @@ config ARM_RK3399_DMC_DEVFREQ
          It sets the frequency for the memory controller and reads the usage counts
          from hardware.
 
+config ARM_SUN8I_A33_MBUS_DEVFREQ
+       tristate "sun8i/sun50i MBUS DEVFREQ Driver"
+       depends on ARCH_SUNXI || COMPILE_TEST
+       depends on COMMON_CLK
+       select DEVFREQ_GOV_SIMPLE_ONDEMAND
+       help
+         This adds the DEVFREQ driver for the MBUS controller in some
+         Allwinner sun8i (A33 through H3) and sun50i (A64 and H5) SoCs.
+
 source "drivers/devfreq/event/Kconfig"
 
 endif # PM_DEVFREQ
index a16333e..0b6be92 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)  += exynos-bus.o
 obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)      += imx-bus.o
 obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)   += imx8m-ddrc.o
 obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)   += rk3399_dmc.o
+obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ)       += sun8i-a33-mbus.o
 obj-$(CONFIG_ARM_TEGRA_DEVFREQ)                += tegra30-devfreq.o
 
 # DEVFREQ Event Drivers
index 7906220..a525a60 100644 (file)
@@ -382,8 +382,8 @@ static int devfreq_set_target(struct devfreq *devfreq, unsigned long new_freq,
        devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
 
        if (devfreq_update_status(devfreq, new_freq))
-               dev_err(&devfreq->dev,
-                       "Couldn't update frequency transition information.\n");
+               dev_warn(&devfreq->dev,
+                        "Couldn't update frequency transition information.\n");
 
        devfreq->previous_freq = new_freq;
 
diff --git a/drivers/devfreq/sun8i-a33-mbus.c b/drivers/devfreq/sun8i-a33-mbus.c
new file mode 100644 (file)
index 0000000..13d3221
--- /dev/null
@@ -0,0 +1,511 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright (C) 2020-2021 Samuel Holland <samuel@sholland.org>
+//
+
+#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#define MBUS_CR                                0x0000
+#define MBUS_CR_GET_DRAM_TYPE(x)       (((x) >> 16) & 0x7)
+#define MBUS_CR_DRAM_TYPE_DDR2         2
+#define MBUS_CR_DRAM_TYPE_DDR3         3
+#define MBUS_CR_DRAM_TYPE_DDR4         4
+#define MBUS_CR_DRAM_TYPE_LPDDR2       6
+#define MBUS_CR_DRAM_TYPE_LPDDR3       7
+
+#define MBUS_TMR                       0x000c
+#define MBUS_TMR_PERIOD(x)             ((x) - 1)
+
+#define MBUS_PMU_CFG                   0x009c
+#define MBUS_PMU_CFG_PERIOD(x)         (((x) - 1) << 16)
+#define MBUS_PMU_CFG_UNIT              (0x3 << 1)
+#define MBUS_PMU_CFG_UNIT_B            (0x0 << 1)
+#define MBUS_PMU_CFG_UNIT_KB           (0x1 << 1)
+#define MBUS_PMU_CFG_UNIT_MB           (0x2 << 1)
+#define MBUS_PMU_CFG_ENABLE            (0x1 << 0)
+
+#define MBUS_PMU_BWCR(n)               (0x00a0 + (0x04 * (n)))
+
+#define MBUS_TOTAL_BWCR                        MBUS_PMU_BWCR(5)
+#define MBUS_TOTAL_BWCR_H616           MBUS_PMU_BWCR(13)
+
+#define MBUS_MDFSCR                    0x0100
+#define MBUS_MDFSCR_BUFFER_TIMING      (0x1 << 15)
+#define MBUS_MDFSCR_PAD_HOLD           (0x1 << 13)
+#define MBUS_MDFSCR_BYPASS             (0x1 << 4)
+#define MBUS_MDFSCR_MODE               (0x1 << 1)
+#define MBUS_MDFSCR_MODE_DFS           (0x0 << 1)
+#define MBUS_MDFSCR_MODE_CFS           (0x1 << 1)
+#define MBUS_MDFSCR_START              (0x1 << 0)
+
+#define MBUS_MDFSMRMR                  0x0108
+
+#define DRAM_PWRCTL                    0x0004
+#define DRAM_PWRCTL_SELFREF_EN         (0x1 << 0)
+
+#define DRAM_RFSHTMG                   0x0090
+#define DRAM_RFSHTMG_TREFI(x)          ((x) << 16)
+#define DRAM_RFSHTMG_TRFC(x)           ((x) << 0)
+
+#define DRAM_VTFCR                     0x00b8
+#define DRAM_VTFCR_VTF_ENABLE          (0x3 << 8)
+
+#define DRAM_ODTMAP                    0x0120
+
+#define DRAM_DX_MAX                    4
+
+#define DRAM_DXnGCR0(n)                        (0x0344 + 0x80 * (n))
+#define DRAM_DXnGCR0_DXODT             (0x3 << 4)
+#define DRAM_DXnGCR0_DXODT_DYNAMIC     (0x0 << 4)
+#define DRAM_DXnGCR0_DXODT_ENABLED     (0x1 << 4)
+#define DRAM_DXnGCR0_DXODT_DISABLED    (0x2 << 4)
+#define DRAM_DXnGCR0_DXEN              (0x1 << 0)
+
+struct sun8i_a33_mbus_variant {
+       u32                                     min_dram_divider;
+       u32                                     max_dram_divider;
+       u32                                     odt_freq_mhz;
+};
+
+struct sun8i_a33_mbus {
+       const struct sun8i_a33_mbus_variant     *variant;
+       void __iomem                            *reg_dram;
+       void __iomem                            *reg_mbus;
+       struct clk                              *clk_bus;
+       struct clk                              *clk_dram;
+       struct clk                              *clk_mbus;
+       struct devfreq                          *devfreq_dram;
+       struct devfreq_simple_ondemand_data     gov_data;
+       struct devfreq_dev_profile              profile;
+       u32                                     data_width;
+       u32                                     nominal_bw;
+       u32                                     odtmap;
+       u32                                     tREFI_ns;
+       u32                                     tRFC_ns;
+       unsigned long                           freq_table[];
+};
+
+/*
+ * The unit for this value is (MBUS clock cycles / MBUS_TMR_PERIOD). When
+ * MBUS_TMR_PERIOD is programmed to match the MBUS clock frequency in MHz, as
+ * it is during DRAM init and during probe, the resulting unit is microseconds.
+ */
+static int pmu_period = 50000;
+module_param(pmu_period, int, 0644);
+MODULE_PARM_DESC(pmu_period, "Bandwidth measurement period (microseconds)");
+
+static u32 sun8i_a33_mbus_get_peak_bw(struct sun8i_a33_mbus *priv)
+{
+       /* Returns the peak transfer (in KiB) during any single PMU period. */
+       return readl_relaxed(priv->reg_mbus + MBUS_TOTAL_BWCR);
+}
+
+static void sun8i_a33_mbus_restart_pmu_counters(struct sun8i_a33_mbus *priv)
+{
+       u32 pmu_cfg = MBUS_PMU_CFG_PERIOD(pmu_period) | MBUS_PMU_CFG_UNIT_KB;
+
+       /* All PMU counters are cleared on a disable->enable transition. */
+       writel_relaxed(pmu_cfg,
+                      priv->reg_mbus + MBUS_PMU_CFG);
+       writel_relaxed(pmu_cfg | MBUS_PMU_CFG_ENABLE,
+                      priv->reg_mbus + MBUS_PMU_CFG);
+
+}
+
+static void sun8i_a33_mbus_update_nominal_bw(struct sun8i_a33_mbus *priv,
+                                            u32 ddr_freq_mhz)
+{
+       /*
+        * Nominal bandwidth (KiB per PMU period):
+        *
+        *   DDR transfers   microseconds     KiB
+        *   ------------- * ------------ * --------
+        *    microsecond     PMU period    transfer
+        */
+       priv->nominal_bw = ddr_freq_mhz * pmu_period * priv->data_width / 1024;
+}
+
+static int sun8i_a33_mbus_set_dram_freq(struct sun8i_a33_mbus *priv,
+                                       unsigned long freq)
+{
+       u32  ddr_freq_mhz = freq / USEC_PER_SEC; /* DDR */
+       u32 dram_freq_mhz =    ddr_freq_mhz / 2; /* SDR */
+       u32 mctl_freq_mhz =   dram_freq_mhz / 2; /* HDR */
+       u32 dxodt, mdfscr, pwrctl, vtfcr;
+       u32 i, tREFI_32ck, tRFC_ck;
+       int ret;
+
+       /* The rate change is not effective until the MDFS process runs. */
+       ret = clk_set_rate(priv->clk_dram, freq);
+       if (ret)
+               return ret;
+
+       /* Disable automatic self-refesh and VTF before starting MDFS. */
+       pwrctl = readl_relaxed(priv->reg_dram + DRAM_PWRCTL) &
+                ~DRAM_PWRCTL_SELFREF_EN;
+       writel_relaxed(pwrctl, priv->reg_dram + DRAM_PWRCTL);
+       vtfcr = readl_relaxed(priv->reg_dram + DRAM_VTFCR);
+       writel_relaxed(vtfcr & ~DRAM_VTFCR_VTF_ENABLE,
+                      priv->reg_dram + DRAM_VTFCR);
+
+       /* Set up MDFS and enable double buffering for timing registers. */
+       mdfscr = MBUS_MDFSCR_MODE_DFS |
+                MBUS_MDFSCR_BYPASS |
+                MBUS_MDFSCR_PAD_HOLD |
+                MBUS_MDFSCR_BUFFER_TIMING;
+       writel(mdfscr, priv->reg_mbus + MBUS_MDFSCR);
+
+       /* Update the buffered copy of RFSHTMG. */
+       tREFI_32ck = priv->tREFI_ns * mctl_freq_mhz / 1000 / 32;
+       tRFC_ck = DIV_ROUND_UP(priv->tRFC_ns * mctl_freq_mhz, 1000);
+       writel(DRAM_RFSHTMG_TREFI(tREFI_32ck) | DRAM_RFSHTMG_TRFC(tRFC_ck),
+              priv->reg_dram + DRAM_RFSHTMG);
+
+       /* Enable ODT if needed, or disable it to save power. */
+       if (priv->odtmap && dram_freq_mhz > priv->variant->odt_freq_mhz) {
+               dxodt = DRAM_DXnGCR0_DXODT_DYNAMIC;
+               writel(priv->odtmap, priv->reg_dram + DRAM_ODTMAP);
+       } else {
+               dxodt = DRAM_DXnGCR0_DXODT_DISABLED;
+               writel(0, priv->reg_dram + DRAM_ODTMAP);
+       }
+       for (i = 0; i < DRAM_DX_MAX; ++i) {
+               void __iomem *reg = priv->reg_dram + DRAM_DXnGCR0(i);
+
+               writel((readl(reg) & ~DRAM_DXnGCR0_DXODT) | dxodt, reg);
+       }
+
+       dev_dbg(priv->devfreq_dram->dev.parent,
+               "Setting DRAM to %u MHz, tREFI=%u, tRFC=%u, ODT=%s\n",
+               dram_freq_mhz, tREFI_32ck, tRFC_ck,
+               dxodt == DRAM_DXnGCR0_DXODT_DYNAMIC ? "dynamic" : "disabled");
+
+       /* Trigger hardware MDFS. */
+       writel(mdfscr | MBUS_MDFSCR_START, priv->reg_mbus + MBUS_MDFSCR);
+       ret = readl_poll_timeout_atomic(priv->reg_mbus + MBUS_MDFSCR, mdfscr,
+                                       !(mdfscr & MBUS_MDFSCR_START), 10, 1000);
+       if (ret)
+               return ret;
+
+       /* Disable double buffering. */
+       writel(0, priv->reg_mbus + MBUS_MDFSCR);
+
+       /* Restore VTF configuration. */
+       writel_relaxed(vtfcr, priv->reg_dram + DRAM_VTFCR);
+
+       /* Enable automatic self-refresh at the lowest frequency only. */
+       if (freq == priv->freq_table[0])
+               pwrctl |= DRAM_PWRCTL_SELFREF_EN;
+       writel_relaxed(pwrctl, priv->reg_dram + DRAM_PWRCTL);
+
+       sun8i_a33_mbus_restart_pmu_counters(priv);
+       sun8i_a33_mbus_update_nominal_bw(priv, ddr_freq_mhz);
+
+       return 0;
+}
+
+static int sun8i_a33_mbus_set_dram_target(struct device *dev,
+                                         unsigned long *freq, u32 flags)
+{
+       struct sun8i_a33_mbus *priv = dev_get_drvdata(dev);
+       struct devfreq *devfreq = priv->devfreq_dram;
+       struct dev_pm_opp *opp;
+       int ret;
+
+       opp = devfreq_recommended_opp(dev, freq, flags);
+       if (IS_ERR(opp))
+               return PTR_ERR(opp);
+
+       dev_pm_opp_put(opp);
+
+       if (*freq == devfreq->previous_freq)
+               return 0;
+
+       ret = sun8i_a33_mbus_set_dram_freq(priv, *freq);
+       if (ret) {
+               dev_warn(dev, "failed to set DRAM frequency: %d\n", ret);
+               *freq = devfreq->previous_freq;
+       }
+
+       return ret;
+}
+
+static int sun8i_a33_mbus_get_dram_status(struct device *dev,
+                                         struct devfreq_dev_status *stat)
+{
+       struct sun8i_a33_mbus *priv = dev_get_drvdata(dev);
+
+       stat->busy_time         = sun8i_a33_mbus_get_peak_bw(priv);
+       stat->total_time        = priv->nominal_bw;
+       stat->current_frequency = priv->devfreq_dram->previous_freq;
+
+       sun8i_a33_mbus_restart_pmu_counters(priv);
+
+       dev_dbg(dev, "Using %lu/%lu (%lu%%) at %lu MHz\n",
+               stat->busy_time, stat->total_time,
+               DIV_ROUND_CLOSEST(stat->busy_time * 100, stat->total_time),
+               stat->current_frequency / USEC_PER_SEC);
+
+       return 0;
+}
+
+static int sun8i_a33_mbus_hw_init(struct device *dev,
+                                 struct sun8i_a33_mbus *priv,
+                                 unsigned long ddr_freq)
+{
+       u32 i, mbus_cr, mbus_freq_mhz;
+
+       /* Choose tREFI and tRFC to match the configured DRAM type. */
+       mbus_cr = readl_relaxed(priv->reg_mbus + MBUS_CR);
+       switch (MBUS_CR_GET_DRAM_TYPE(mbus_cr)) {
+       case MBUS_CR_DRAM_TYPE_DDR2:
+       case MBUS_CR_DRAM_TYPE_DDR3:
+       case MBUS_CR_DRAM_TYPE_DDR4:
+               priv->tREFI_ns = 7800;
+               priv->tRFC_ns = 350;
+               break;
+       case MBUS_CR_DRAM_TYPE_LPDDR2:
+       case MBUS_CR_DRAM_TYPE_LPDDR3:
+               priv->tREFI_ns = 3900;
+               priv->tRFC_ns = 210;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Save ODTMAP so it can be restored when raising the frequency. */
+       priv->odtmap = readl_relaxed(priv->reg_dram + DRAM_ODTMAP);
+
+       /* Compute the DRAM data bus width by counting enabled DATx8 blocks. */
+       for (i = 0; i < DRAM_DX_MAX; ++i) {
+               void __iomem *reg = priv->reg_dram + DRAM_DXnGCR0(i);
+
+               if (!(readl_relaxed(reg) & DRAM_DXnGCR0_DXEN))
+                       break;
+       }
+       priv->data_width = i;
+
+       dev_dbg(dev, "Detected %u-bit %sDDRx with%s ODT\n",
+               priv->data_width * 8,
+               MBUS_CR_GET_DRAM_TYPE(mbus_cr) > 4 ? "LP" : "",
+               priv->odtmap ? "" : "out");
+
+       /* Program MBUS_TMR such that the PMU period unit is microseconds. */
+       mbus_freq_mhz = clk_get_rate(priv->clk_mbus) / USEC_PER_SEC;
+       writel_relaxed(MBUS_TMR_PERIOD(mbus_freq_mhz),
+                      priv->reg_mbus + MBUS_TMR);
+
+       /* "Master Ready Mask Register" bits must be set or MDFS will block. */
+       writel_relaxed(0xffffffff, priv->reg_mbus + MBUS_MDFSMRMR);
+
+       sun8i_a33_mbus_restart_pmu_counters(priv);
+       sun8i_a33_mbus_update_nominal_bw(priv, ddr_freq / USEC_PER_SEC);
+
+       return 0;
+}
+
+static int __maybe_unused sun8i_a33_mbus_suspend(struct device *dev)
+{
+       struct sun8i_a33_mbus *priv = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(priv->clk_bus);
+
+       return 0;
+}
+
+static int __maybe_unused sun8i_a33_mbus_resume(struct device *dev)
+{
+       struct sun8i_a33_mbus *priv = dev_get_drvdata(dev);
+
+       return clk_prepare_enable(priv->clk_bus);
+}
+
+static int sun8i_a33_mbus_probe(struct platform_device *pdev)
+{
+       const struct sun8i_a33_mbus_variant *variant;
+       struct device *dev = &pdev->dev;
+       struct sun8i_a33_mbus *priv;
+       unsigned long base_freq;
+       unsigned int max_state;
+       const char *err;
+       int i, ret;
+
+       variant = device_get_match_data(dev);
+       if (!variant)
+               return -EINVAL;
+
+       max_state = variant->max_dram_divider - variant->min_dram_divider + 1;
+
+       priv = devm_kzalloc(dev, struct_size(priv, freq_table, max_state), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, priv);
+
+       priv->variant = variant;
+
+       priv->reg_dram = devm_platform_ioremap_resource_byname(pdev, "dram");
+       if (IS_ERR(priv->reg_dram))
+               return PTR_ERR(priv->reg_dram);
+
+       priv->reg_mbus = devm_platform_ioremap_resource_byname(pdev, "mbus");
+       if (IS_ERR(priv->reg_mbus))
+               return PTR_ERR(priv->reg_mbus);
+
+       priv->clk_bus = devm_clk_get(dev, "bus");
+       if (IS_ERR(priv->clk_bus))
+               return dev_err_probe(dev, PTR_ERR(priv->clk_bus),
+                                    "failed to get bus clock\n");
+
+       priv->clk_dram = devm_clk_get(dev, "dram");
+       if (IS_ERR(priv->clk_dram))
+               return dev_err_probe(dev, PTR_ERR(priv->clk_dram),
+                                    "failed to get dram clock\n");
+
+       priv->clk_mbus = devm_clk_get(dev, "mbus");
+       if (IS_ERR(priv->clk_mbus))
+               return dev_err_probe(dev, PTR_ERR(priv->clk_mbus),
+                                    "failed to get mbus clock\n");
+
+       ret = clk_prepare_enable(priv->clk_bus);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "failed to enable bus clock\n");
+
+       /* Lock the DRAM clock rate to keep priv->nominal_bw in sync. */
+       ret = clk_rate_exclusive_get(priv->clk_dram);
+       if (ret) {
+               err = "failed to lock dram clock rate\n";
+               goto err_disable_bus;
+       }
+
+       /* Lock the MBUS clock rate to keep MBUS_TMR_PERIOD in sync. */
+       ret = clk_rate_exclusive_get(priv->clk_mbus);
+       if (ret) {
+               err = "failed to lock mbus clock rate\n";
+               goto err_unlock_dram;
+       }
+
+       priv->gov_data.upthreshold      = 10;
+       priv->gov_data.downdifferential =  5;
+
+       priv->profile.initial_freq      = clk_get_rate(priv->clk_dram);
+       priv->profile.polling_ms        = 1000;
+       priv->profile.target            = sun8i_a33_mbus_set_dram_target;
+       priv->profile.get_dev_status    = sun8i_a33_mbus_get_dram_status;
+       priv->profile.freq_table        = priv->freq_table;
+       priv->profile.max_state         = max_state;
+
+       ret = devm_pm_opp_set_clkname(dev, "dram");
+       if (ret) {
+               err = "failed to add OPP table\n";
+               goto err_unlock_mbus;
+       }
+
+       base_freq = clk_get_rate(clk_get_parent(priv->clk_dram));
+       for (i = 0; i < max_state; ++i) {
+               unsigned int div = variant->max_dram_divider - i;
+
+               priv->freq_table[i] = base_freq / div;
+
+               ret = dev_pm_opp_add(dev, priv->freq_table[i], 0);
+               if (ret) {
+                       err = "failed to add OPPs\n";
+                       goto err_remove_opps;
+               }
+       }
+
+       ret = sun8i_a33_mbus_hw_init(dev, priv, priv->profile.initial_freq);
+       if (ret) {
+               err = "failed to init hardware\n";
+               goto err_remove_opps;
+       }
+
+       priv->devfreq_dram = devfreq_add_device(dev, &priv->profile,
+                                               DEVFREQ_GOV_SIMPLE_ONDEMAND,
+                                               &priv->gov_data);
+       if (IS_ERR(priv->devfreq_dram)) {
+               ret = PTR_ERR(priv->devfreq_dram);
+               err = "failed to add devfreq device\n";
+               goto err_remove_opps;
+       }
+
+       /*
+        * This must be set manually after registering the devfreq device,
+        * because there is no way to select a dynamic OPP as the suspend OPP.
+        */
+       priv->devfreq_dram->suspend_freq = priv->freq_table[0];
+
+       return 0;
+
+err_remove_opps:
+       dev_pm_opp_remove_all_dynamic(dev);
+err_unlock_mbus:
+       clk_rate_exclusive_put(priv->clk_mbus);
+err_unlock_dram:
+       clk_rate_exclusive_put(priv->clk_dram);
+err_disable_bus:
+       clk_disable_unprepare(priv->clk_bus);
+
+       return dev_err_probe(dev, ret, err);
+}
+
+static int sun8i_a33_mbus_remove(struct platform_device *pdev)
+{
+       struct sun8i_a33_mbus *priv = platform_get_drvdata(pdev);
+       unsigned long initial_freq = priv->profile.initial_freq;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       devfreq_remove_device(priv->devfreq_dram);
+
+       ret = sun8i_a33_mbus_set_dram_freq(priv, initial_freq);
+       if (ret)
+               dev_warn(dev, "failed to restore DRAM frequency: %d\n", ret);
+
+       dev_pm_opp_remove_all_dynamic(dev);
+       clk_rate_exclusive_put(priv->clk_mbus);
+       clk_rate_exclusive_put(priv->clk_dram);
+       clk_disable_unprepare(priv->clk_bus);
+
+       return 0;
+}
+
+static const struct sun8i_a33_mbus_variant sun50i_a64_mbus = {
+       .min_dram_divider       = 1,
+       .max_dram_divider       = 4,
+       .odt_freq_mhz           = 400,
+};
+
+static const struct of_device_id sun8i_a33_mbus_of_match[] = {
+       { .compatible = "allwinner,sun50i-a64-mbus", .data = &sun50i_a64_mbus },
+       { .compatible = "allwinner,sun50i-h5-mbus", .data = &sun50i_a64_mbus },
+       { },
+};
+MODULE_DEVICE_TABLE(of, sun8i_a33_mbus_of_match);
+
+static SIMPLE_DEV_PM_OPS(sun8i_a33_mbus_pm_ops,
+                        sun8i_a33_mbus_suspend, sun8i_a33_mbus_resume);
+
+static struct platform_driver sun8i_a33_mbus_driver = {
+       .probe  = sun8i_a33_mbus_probe,
+       .remove = sun8i_a33_mbus_remove,
+       .driver = {
+               .name           = "sun8i-a33-mbus",
+               .of_match_table = sun8i_a33_mbus_of_match,
+               .pm             = pm_ptr(&sun8i_a33_mbus_pm_ops),
+       },
+};
+module_platform_driver(sun8i_a33_mbus_driver);
+
+MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
+MODULE_DESCRIPTION("Allwinner sun8i/sun50i MBUS DEVFREQ Driver");
+MODULE_LICENSE("GPL v2");
index 026903e..08b9e2c 100644 (file)
@@ -46,6 +46,7 @@
 struct dln2_gpio {
        struct platform_device *pdev;
        struct gpio_chip gpio;
+       struct irq_chip irqchip;
 
        /*
         * Cache pin direction to save us one transfer, since the hardware has
@@ -383,15 +384,6 @@ static void dln2_irq_bus_unlock(struct irq_data *irqd)
        mutex_unlock(&dln2->irq_lock);
 }
 
-static struct irq_chip dln2_gpio_irqchip = {
-       .name = "dln2-irq",
-       .irq_mask = dln2_irq_mask,
-       .irq_unmask = dln2_irq_unmask,
-       .irq_set_type = dln2_irq_set_type,
-       .irq_bus_lock = dln2_irq_bus_lock,
-       .irq_bus_sync_unlock = dln2_irq_bus_unlock,
-};
-
 static void dln2_gpio_event(struct platform_device *pdev, u16 echo,
                            const void *data, int len)
 {
@@ -473,8 +465,15 @@ static int dln2_gpio_probe(struct platform_device *pdev)
        dln2->gpio.direction_output = dln2_gpio_direction_output;
        dln2->gpio.set_config = dln2_gpio_set_config;
 
+       dln2->irqchip.name = "dln2-irq",
+       dln2->irqchip.irq_mask = dln2_irq_mask,
+       dln2->irqchip.irq_unmask = dln2_irq_unmask,
+       dln2->irqchip.irq_set_type = dln2_irq_set_type,
+       dln2->irqchip.irq_bus_lock = dln2_irq_bus_lock,
+       dln2->irqchip.irq_bus_sync_unlock = dln2_irq_bus_unlock,
+
        girq = &dln2->gpio.irq;
-       girq->chip = &dln2_gpio_irqchip;
+       girq->chip = &dln2->irqchip;
        /* The event comes from the outside so no parent handler */
        girq->parent_handler = NULL;
        girq->num_parents = 0;
index 84f96b7..9f4941b 100644 (file)
@@ -100,11 +100,7 @@ static int _virtio_gpio_req(struct virtio_gpio *vgpio, u16 type, u16 gpio,
        virtqueue_kick(vgpio->request_vq);
        mutex_unlock(&vgpio->lock);
 
-       if (!wait_for_completion_timeout(&line->completion, HZ)) {
-               dev_err(dev, "GPIO operation timed out\n");
-               ret = -ETIMEDOUT;
-               goto out;
-       }
+       wait_for_completion(&line->completion);
 
        if (unlikely(res->status != VIRTIO_GPIO_STATUS_OK)) {
                dev_err(dev, "GPIO request failed: %d\n", gpio);
index 1e651b9..694c372 100644 (file)
@@ -3166,6 +3166,12 @@ static void amdgpu_device_detect_sriov_bios(struct amdgpu_device *adev)
 bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type)
 {
        switch (asic_type) {
+#ifdef CONFIG_DRM_AMDGPU_SI
+       case CHIP_HAINAN:
+#endif
+       case CHIP_TOPAZ:
+               /* chips with no display hardware */
+               return false;
 #if defined(CONFIG_DRM_AMD_DC)
        case CHIP_TAHITI:
        case CHIP_PITCAIRN:
@@ -4461,7 +4467,7 @@ int amdgpu_device_mode1_reset(struct amdgpu_device *adev)
 int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
                                 struct amdgpu_reset_context *reset_context)
 {
-       int i, j, r = 0;
+       int i, r = 0;
        struct amdgpu_job *job = NULL;
        bool need_full_reset =
                test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags);
@@ -4483,15 +4489,8 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
 
                /*clear job fence from fence drv to avoid force_completion
                 *leave NULL and vm flush fence in fence drv */
-               for (j = 0; j <= ring->fence_drv.num_fences_mask; j++) {
-                       struct dma_fence *old, **ptr;
+               amdgpu_fence_driver_clear_job_fences(ring);
 
-                       ptr = &ring->fence_drv.fences[j];
-                       old = rcu_dereference_protected(*ptr, 1);
-                       if (old && test_bit(AMDGPU_FENCE_FLAG_EMBED_IN_JOB_BIT, &old->flags)) {
-                               RCU_INIT_POINTER(*ptr, NULL);
-                       }
-               }
                /* after all hw jobs are reset, hw fence is meaningless, so force_completion */
                amdgpu_fence_driver_force_completion(ring);
        }
index ea00090..bcc9343 100644 (file)
@@ -526,10 +526,15 @@ void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev)
        }
 }
 
+union gc_info {
+       struct gc_info_v1_0 v1;
+       struct gc_info_v2_0 v2;
+};
+
 int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev)
 {
        struct binary_header *bhdr;
-       struct gc_info_v1_0 *gc_info;
+       union gc_info *gc_info;
 
        if (!adev->mman.discovery_bin) {
                DRM_ERROR("ip discovery uninitialized\n");
@@ -537,28 +542,55 @@ int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev)
        }
 
        bhdr = (struct binary_header *)adev->mman.discovery_bin;
-       gc_info = (struct gc_info_v1_0 *)(adev->mman.discovery_bin +
+       gc_info = (union gc_info *)(adev->mman.discovery_bin +
                        le16_to_cpu(bhdr->table_list[GC].offset));
-
-       adev->gfx.config.max_shader_engines = le32_to_cpu(gc_info->gc_num_se);
-       adev->gfx.config.max_cu_per_sh = 2 * (le32_to_cpu(gc_info->gc_num_wgp0_per_sa) +
-                                             le32_to_cpu(gc_info->gc_num_wgp1_per_sa));
-       adev->gfx.config.max_sh_per_se = le32_to_cpu(gc_info->gc_num_sa_per_se);
-       adev->gfx.config.max_backends_per_se = le32_to_cpu(gc_info->gc_num_rb_per_se);
-       adev->gfx.config.max_texture_channel_caches = le32_to_cpu(gc_info->gc_num_gl2c);
-       adev->gfx.config.max_gprs = le32_to_cpu(gc_info->gc_num_gprs);
-       adev->gfx.config.max_gs_threads = le32_to_cpu(gc_info->gc_num_max_gs_thds);
-       adev->gfx.config.gs_vgt_table_depth = le32_to_cpu(gc_info->gc_gs_table_depth);
-       adev->gfx.config.gs_prim_buffer_depth = le32_to_cpu(gc_info->gc_gsprim_buff_depth);
-       adev->gfx.config.double_offchip_lds_buf = le32_to_cpu(gc_info->gc_double_offchip_lds_buffer);
-       adev->gfx.cu_info.wave_front_size = le32_to_cpu(gc_info->gc_wave_size);
-       adev->gfx.cu_info.max_waves_per_simd = le32_to_cpu(gc_info->gc_max_waves_per_simd);
-       adev->gfx.cu_info.max_scratch_slots_per_cu = le32_to_cpu(gc_info->gc_max_scratch_slots_per_cu);
-       adev->gfx.cu_info.lds_size = le32_to_cpu(gc_info->gc_lds_size);
-       adev->gfx.config.num_sc_per_sh = le32_to_cpu(gc_info->gc_num_sc_per_se) /
-                                        le32_to_cpu(gc_info->gc_num_sa_per_se);
-       adev->gfx.config.num_packer_per_sc = le32_to_cpu(gc_info->gc_num_packer_per_sc);
-
+       switch (gc_info->v1.header.version_major) {
+       case 1:
+               adev->gfx.config.max_shader_engines = le32_to_cpu(gc_info->v1.gc_num_se);
+               adev->gfx.config.max_cu_per_sh = 2 * (le32_to_cpu(gc_info->v1.gc_num_wgp0_per_sa) +
+                                                     le32_to_cpu(gc_info->v1.gc_num_wgp1_per_sa));
+               adev->gfx.config.max_sh_per_se = le32_to_cpu(gc_info->v1.gc_num_sa_per_se);
+               adev->gfx.config.max_backends_per_se = le32_to_cpu(gc_info->v1.gc_num_rb_per_se);
+               adev->gfx.config.max_texture_channel_caches = le32_to_cpu(gc_info->v1.gc_num_gl2c);
+               adev->gfx.config.max_gprs = le32_to_cpu(gc_info->v1.gc_num_gprs);
+               adev->gfx.config.max_gs_threads = le32_to_cpu(gc_info->v1.gc_num_max_gs_thds);
+               adev->gfx.config.gs_vgt_table_depth = le32_to_cpu(gc_info->v1.gc_gs_table_depth);
+               adev->gfx.config.gs_prim_buffer_depth = le32_to_cpu(gc_info->v1.gc_gsprim_buff_depth);
+               adev->gfx.config.double_offchip_lds_buf = le32_to_cpu(gc_info->v1.gc_double_offchip_lds_buffer);
+               adev->gfx.cu_info.wave_front_size = le32_to_cpu(gc_info->v1.gc_wave_size);
+               adev->gfx.cu_info.max_waves_per_simd = le32_to_cpu(gc_info->v1.gc_max_waves_per_simd);
+               adev->gfx.cu_info.max_scratch_slots_per_cu = le32_to_cpu(gc_info->v1.gc_max_scratch_slots_per_cu);
+               adev->gfx.cu_info.lds_size = le32_to_cpu(gc_info->v1.gc_lds_size);
+               adev->gfx.config.num_sc_per_sh = le32_to_cpu(gc_info->v1.gc_num_sc_per_se) /
+                       le32_to_cpu(gc_info->v1.gc_num_sa_per_se);
+               adev->gfx.config.num_packer_per_sc = le32_to_cpu(gc_info->v1.gc_num_packer_per_sc);
+               break;
+       case 2:
+               adev->gfx.config.max_shader_engines = le32_to_cpu(gc_info->v2.gc_num_se);
+               adev->gfx.config.max_cu_per_sh = le32_to_cpu(gc_info->v2.gc_num_cu_per_sh);
+               adev->gfx.config.max_sh_per_se = le32_to_cpu(gc_info->v2.gc_num_sh_per_se);
+               adev->gfx.config.max_backends_per_se = le32_to_cpu(gc_info->v2.gc_num_rb_per_se);
+               adev->gfx.config.max_texture_channel_caches = le32_to_cpu(gc_info->v2.gc_num_tccs);
+               adev->gfx.config.max_gprs = le32_to_cpu(gc_info->v2.gc_num_gprs);
+               adev->gfx.config.max_gs_threads = le32_to_cpu(gc_info->v2.gc_num_max_gs_thds);
+               adev->gfx.config.gs_vgt_table_depth = le32_to_cpu(gc_info->v2.gc_gs_table_depth);
+               adev->gfx.config.gs_prim_buffer_depth = le32_to_cpu(gc_info->v2.gc_gsprim_buff_depth);
+               adev->gfx.config.double_offchip_lds_buf = le32_to_cpu(gc_info->v2.gc_double_offchip_lds_buffer);
+               adev->gfx.cu_info.wave_front_size = le32_to_cpu(gc_info->v2.gc_wave_size);
+               adev->gfx.cu_info.max_waves_per_simd = le32_to_cpu(gc_info->v2.gc_max_waves_per_simd);
+               adev->gfx.cu_info.max_scratch_slots_per_cu = le32_to_cpu(gc_info->v2.gc_max_scratch_slots_per_cu);
+               adev->gfx.cu_info.lds_size = le32_to_cpu(gc_info->v2.gc_lds_size);
+               adev->gfx.config.num_sc_per_sh = le32_to_cpu(gc_info->v2.gc_num_sc_per_se) /
+                       le32_to_cpu(gc_info->v2.gc_num_sh_per_se);
+               adev->gfx.config.num_packer_per_sc = le32_to_cpu(gc_info->v2.gc_num_packer_per_sc);
+               break;
+       default:
+               dev_err(adev->dev,
+                       "Unhandled GC info table %d.%d\n",
+                       gc_info->v1.header.version_major,
+                       gc_info->v1.header.version_minor);
+               return -EINVAL;
+       }
        return 0;
 }
 
index ae6ab93..7444484 100644 (file)
@@ -384,7 +384,7 @@ amdgpu_dma_buf_move_notify(struct dma_buf_attachment *attach)
        struct amdgpu_vm_bo_base *bo_base;
        int r;
 
-       if (bo->tbo.resource->mem_type == TTM_PL_SYSTEM)
+       if (!bo->tbo.resource || bo->tbo.resource->mem_type == TTM_PL_SYSTEM)
                return;
 
        r = ttm_bo_validate(&bo->tbo, &placement, &ctx);
index ad95de6..86ca80d 100644 (file)
@@ -328,10 +328,11 @@ module_param_named(aspm, amdgpu_aspm, int, 0444);
 
 /**
  * DOC: runpm (int)
- * Override for runtime power management control for dGPUs in PX/HG laptops. The amdgpu driver can dynamically power down
- * the dGPU on PX/HG laptops when it is idle. The default is -1 (auto enable). Setting the value to 0 disables this functionality.
+ * Override for runtime power management control for dGPUs. The amdgpu driver can dynamically power down
+ * the dGPUs when they are idle if supported. The default is -1 (auto enable).
+ * Setting the value to 0 disables this functionality.
  */
-MODULE_PARM_DESC(runpm, "PX runtime pm (2 = force enable with BAMACO, 1 = force enable with BACO, 0 = disable, -1 = PX only default)");
+MODULE_PARM_DESC(runpm, "PX runtime pm (2 = force enable with BAMACO, 1 = force enable with BACO, 0 = disable, -1 = auto)");
 module_param_named(runpm, amdgpu_runtime_pm, int, 0444);
 
 /**
@@ -2153,7 +2154,10 @@ static int amdgpu_pmops_suspend(struct device *dev)
        adev->in_s3 = true;
        r = amdgpu_device_suspend(drm_dev, true);
        adev->in_s3 = false;
-
+       if (r)
+               return r;
+       if (!adev->in_s0ix)
+               r = amdgpu_asic_reset(adev);
        return r;
 }
 
@@ -2234,12 +2238,27 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev)
        if (amdgpu_device_supports_px(drm_dev))
                drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
 
+       /*
+        * By setting mp1_state as PP_MP1_STATE_UNLOAD, MP1 will do some
+        * proper cleanups and put itself into a state ready for PNP. That
+        * can address some random resuming failure observed on BOCO capable
+        * platforms.
+        * TODO: this may be also needed for PX capable platform.
+        */
+       if (amdgpu_device_supports_boco(drm_dev))
+               adev->mp1_state = PP_MP1_STATE_UNLOAD;
+
        ret = amdgpu_device_suspend(drm_dev, false);
        if (ret) {
                adev->in_runpm = false;
+               if (amdgpu_device_supports_boco(drm_dev))
+                       adev->mp1_state = PP_MP1_STATE_NONE;
                return ret;
        }
 
+       if (amdgpu_device_supports_boco(drm_dev))
+               adev->mp1_state = PP_MP1_STATE_NONE;
+
        if (amdgpu_device_supports_px(drm_dev)) {
                /* Only need to handle PCI state in the driver for ATPX
                 * PCI core handles it for _PR3.
index 3b7e86e..9afd11c 100644 (file)
@@ -77,11 +77,13 @@ void amdgpu_fence_slab_fini(void)
  * Cast helper
  */
 static const struct dma_fence_ops amdgpu_fence_ops;
+static const struct dma_fence_ops amdgpu_job_fence_ops;
 static inline struct amdgpu_fence *to_amdgpu_fence(struct dma_fence *f)
 {
        struct amdgpu_fence *__f = container_of(f, struct amdgpu_fence, base);
 
-       if (__f->base.ops == &amdgpu_fence_ops)
+       if (__f->base.ops == &amdgpu_fence_ops ||
+           __f->base.ops == &amdgpu_job_fence_ops)
                return __f;
 
        return NULL;
@@ -158,19 +160,18 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, struct amd
        }
 
        seq = ++ring->fence_drv.sync_seq;
-       if (job != NULL && job->job_run_counter) {
+       if (job && job->job_run_counter) {
                /* reinit seq for resubmitted jobs */
                fence->seqno = seq;
        } else {
-               dma_fence_init(fence, &amdgpu_fence_ops,
-                               &ring->fence_drv.lock,
-                               adev->fence_context + ring->idx,
-                               seq);
-       }
-
-       if (job != NULL) {
-               /* mark this fence has a parent job */
-               set_bit(AMDGPU_FENCE_FLAG_EMBED_IN_JOB_BIT, &fence->flags);
+               if (job)
+                       dma_fence_init(fence, &amdgpu_job_fence_ops,
+                                      &ring->fence_drv.lock,
+                                      adev->fence_context + ring->idx, seq);
+               else
+                       dma_fence_init(fence, &amdgpu_fence_ops,
+                                      &ring->fence_drv.lock,
+                                      adev->fence_context + ring->idx, seq);
        }
 
        amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
@@ -620,6 +621,25 @@ void amdgpu_fence_driver_hw_init(struct amdgpu_device *adev)
        }
 }
 
+/**
+ * amdgpu_fence_driver_clear_job_fences - clear job embedded fences of ring
+ *
+ * @ring: fence of the ring to be cleared
+ *
+ */
+void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring)
+{
+       int i;
+       struct dma_fence *old, **ptr;
+
+       for (i = 0; i <= ring->fence_drv.num_fences_mask; i++) {
+               ptr = &ring->fence_drv.fences[i];
+               old = rcu_dereference_protected(*ptr, 1);
+               if (old && old->ops == &amdgpu_job_fence_ops)
+                       RCU_INIT_POINTER(*ptr, NULL);
+       }
+}
+
 /**
  * amdgpu_fence_driver_force_completion - force signal latest fence of ring
  *
@@ -643,16 +663,14 @@ static const char *amdgpu_fence_get_driver_name(struct dma_fence *fence)
 
 static const char *amdgpu_fence_get_timeline_name(struct dma_fence *f)
 {
-       struct amdgpu_ring *ring;
+       return (const char *)to_amdgpu_fence(f)->ring->name;
+}
 
-       if (test_bit(AMDGPU_FENCE_FLAG_EMBED_IN_JOB_BIT, &f->flags)) {
-               struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence);
+static const char *amdgpu_job_fence_get_timeline_name(struct dma_fence *f)
+{
+       struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence);
 
-               ring = to_amdgpu_ring(job->base.sched);
-       } else {
-               ring = to_amdgpu_fence(f)->ring;
-       }
-       return (const char *)ring->name;
+       return (const char *)to_amdgpu_ring(job->base.sched)->name;
 }
 
 /**
@@ -665,18 +683,25 @@ static const char *amdgpu_fence_get_timeline_name(struct dma_fence *f)
  */
 static bool amdgpu_fence_enable_signaling(struct dma_fence *f)
 {
-       struct amdgpu_ring *ring;
+       if (!timer_pending(&to_amdgpu_fence(f)->ring->fence_drv.fallback_timer))
+               amdgpu_fence_schedule_fallback(to_amdgpu_fence(f)->ring);
 
-       if (test_bit(AMDGPU_FENCE_FLAG_EMBED_IN_JOB_BIT, &f->flags)) {
-               struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence);
+       return true;
+}
 
-               ring = to_amdgpu_ring(job->base.sched);
-       } else {
-               ring = to_amdgpu_fence(f)->ring;
-       }
+/**
+ * amdgpu_job_fence_enable_signaling - enable signalling on job fence
+ * @f: fence
+ *
+ * This is the simliar function with amdgpu_fence_enable_signaling above, it
+ * only handles the job embedded fence.
+ */
+static bool amdgpu_job_fence_enable_signaling(struct dma_fence *f)
+{
+       struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence);
 
-       if (!timer_pending(&ring->fence_drv.fallback_timer))
-               amdgpu_fence_schedule_fallback(ring);
+       if (!timer_pending(&to_amdgpu_ring(job->base.sched)->fence_drv.fallback_timer))
+               amdgpu_fence_schedule_fallback(to_amdgpu_ring(job->base.sched));
 
        return true;
 }
@@ -692,19 +717,23 @@ static void amdgpu_fence_free(struct rcu_head *rcu)
 {
        struct dma_fence *f = container_of(rcu, struct dma_fence, rcu);
 
-       if (test_bit(AMDGPU_FENCE_FLAG_EMBED_IN_JOB_BIT, &f->flags)) {
-       /* free job if fence has a parent job */
-               struct amdgpu_job *job;
-
-               job = container_of(f, struct amdgpu_job, hw_fence);
-               kfree(job);
-       } else {
        /* free fence_slab if it's separated fence*/
-               struct amdgpu_fence *fence;
+       kmem_cache_free(amdgpu_fence_slab, to_amdgpu_fence(f));
+}
 
-               fence = to_amdgpu_fence(f);
-               kmem_cache_free(amdgpu_fence_slab, fence);
-       }
+/**
+ * amdgpu_job_fence_free - free up the job with embedded fence
+ *
+ * @rcu: RCU callback head
+ *
+ * Free up the job with embedded fence after the RCU grace period.
+ */
+static void amdgpu_job_fence_free(struct rcu_head *rcu)
+{
+       struct dma_fence *f = container_of(rcu, struct dma_fence, rcu);
+
+       /* free job if fence has a parent job */
+       kfree(container_of(f, struct amdgpu_job, hw_fence));
 }
 
 /**
@@ -720,6 +749,19 @@ static void amdgpu_fence_release(struct dma_fence *f)
        call_rcu(&f->rcu, amdgpu_fence_free);
 }
 
+/**
+ * amdgpu_job_fence_release - callback that job embedded fence can be freed
+ *
+ * @f: fence
+ *
+ * This is the simliar function with amdgpu_fence_release above, it
+ * only handles the job embedded fence.
+ */
+static void amdgpu_job_fence_release(struct dma_fence *f)
+{
+       call_rcu(&f->rcu, amdgpu_job_fence_free);
+}
+
 static const struct dma_fence_ops amdgpu_fence_ops = {
        .get_driver_name = amdgpu_fence_get_driver_name,
        .get_timeline_name = amdgpu_fence_get_timeline_name,
@@ -727,6 +769,12 @@ static const struct dma_fence_ops amdgpu_fence_ops = {
        .release = amdgpu_fence_release,
 };
 
+static const struct dma_fence_ops amdgpu_job_fence_ops = {
+       .get_driver_name = amdgpu_fence_get_driver_name,
+       .get_timeline_name = amdgpu_job_fence_get_timeline_name,
+       .enable_signaling = amdgpu_job_fence_enable_signaling,
+       .release = amdgpu_job_fence_release,
+};
 
 /*
  * Fence debugfs
index 4d380e7..fae7d18 100644 (file)
@@ -53,9 +53,6 @@ enum amdgpu_ring_priority_level {
 #define AMDGPU_FENCE_FLAG_INT           (1 << 1)
 #define AMDGPU_FENCE_FLAG_TC_WB_ONLY    (1 << 2)
 
-/* fence flag bit to indicate the face is embedded in job*/
-#define AMDGPU_FENCE_FLAG_EMBED_IN_JOB_BIT             (DMA_FENCE_FLAG_USER_BITS + 1)
-
 #define to_amdgpu_ring(s) container_of((s), struct amdgpu_ring, sched)
 
 #define AMDGPU_IB_POOL_SIZE    (1024 * 1024)
@@ -114,6 +111,7 @@ struct amdgpu_fence_driver {
        struct dma_fence                **fences;
 };
 
+void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring);
 void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring);
 
 int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring,
index d54d720..3799226 100644 (file)
@@ -246,6 +246,13 @@ static int vcn_v1_0_suspend(void *handle)
 {
        int r;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       bool idle_work_unexecuted;
+
+       idle_work_unexecuted = cancel_delayed_work_sync(&adev->vcn.idle_work);
+       if (idle_work_unexecuted) {
+               if (adev->pm.dpm_enabled)
+                       amdgpu_dpm_enable_uvd(adev, false);
+       }
 
        r = vcn_v1_0_hw_fini(adev);
        if (r)
index f4c9a45..9df38e2 100644 (file)
@@ -158,6 +158,7 @@ static void dcn31_update_clocks(struct clk_mgr *clk_mgr_base,
                                union display_idle_optimization_u idle_info = { 0 };
                                idle_info.idle_info.df_request_disabled = 1;
                                idle_info.idle_info.phy_ref_clk_off = 1;
+                               idle_info.idle_info.s0i2_rdy = 1;
                                dcn31_smu_set_display_idle_optimization(clk_mgr, idle_info.data);
                                /* update power state */
                                clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
index c8457ba..c0bdc23 100644 (file)
@@ -3945,12 +3945,9 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
                config.dig_be = pipe_ctx->stream->link->link_enc_hw_inst;
 #if defined(CONFIG_DRM_AMD_DC_DCN)
                config.stream_enc_idx = pipe_ctx->stream_res.stream_enc->id - ENGINE_ID_DIGA;
-               
+
                if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_PHY ||
                                pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
-                       link_enc = pipe_ctx->stream->link->link_enc;
-                       config.dio_output_type = pipe_ctx->stream->link->ep_type;
-                       config.dio_output_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A;
                        if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_PHY)
                                link_enc = pipe_ctx->stream->link->link_enc;
                        else if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
index 34001a3..10e613e 100644 (file)
@@ -78,6 +78,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
        .get_clock = dcn10_get_clock,
        .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
        .calc_vupdate_position = dcn10_calc_vupdate_position,
+       .power_down = dce110_power_down,
        .set_backlight_level = dce110_set_backlight_level,
        .set_abm_immediate_disable = dce110_set_abm_immediate_disable,
        .set_pipe = dce110_set_pipe,
index 3883f91..83f5d9a 100644 (file)
@@ -1069,7 +1069,7 @@ static const struct dc_debug_options debug_defaults_drv = {
                .timing_trace = false,
                .clock_trace = true,
                .disable_pplib_clock_request = true,
-               .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP,
+               .pipe_split_policy = MPC_SPLIT_DYNAMIC,
                .force_single_disp_pipe_split = false,
                .disable_dcc = DCC_ENABLE,
                .vsr_support = true,
index 0fa3810..faec029 100644 (file)
@@ -603,7 +603,7 @@ static const struct dc_debug_options debug_defaults_drv = {
                .timing_trace = false,
                .clock_trace = true,
                .disable_pplib_clock_request = true,
-               .pipe_split_policy = MPC_SPLIT_AVOID,
+               .pipe_split_policy = MPC_SPLIT_DYNAMIC,
                .force_single_disp_pipe_split = false,
                .disable_dcc = DCC_ENABLE,
                .vsr_support = true,
index d452a0d..79313d1 100644 (file)
@@ -874,7 +874,7 @@ static const struct dc_debug_options debug_defaults_drv = {
                .clock_trace = true,
                .disable_pplib_clock_request = true,
                .min_disp_clk_khz = 100000,
-               .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP,
+               .pipe_split_policy = MPC_SPLIT_DYNAMIC,
                .force_single_disp_pipe_split = false,
                .disable_dcc = DCC_ENABLE,
                .vsr_support = true,
index 79a66e0..98852b5 100644 (file)
@@ -840,7 +840,7 @@ static const struct dc_debug_options debug_defaults_drv = {
        .timing_trace = false,
        .clock_trace = true,
        .disable_pplib_clock_request = true,
-       .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP,
+       .pipe_split_policy = MPC_SPLIT_DYNAMIC,
        .force_single_disp_pipe_split = false,
        .disable_dcc = DCC_ENABLE,
        .vsr_support = true,
index fbaa03f..e472b72 100644 (file)
@@ -686,7 +686,7 @@ static const struct dc_debug_options debug_defaults_drv = {
        .disable_clock_gate = true,
        .disable_pplib_clock_request = true,
        .disable_pplib_wm_range = true,
-       .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP,
+       .pipe_split_policy = MPC_SPLIT_DYNAMIC,
        .force_single_disp_pipe_split = false,
        .disable_dcc = DCC_ENABLE,
        .vsr_support = true,
index fcf96cf..16e7059 100644 (file)
@@ -211,7 +211,7 @@ static const struct dc_debug_options debug_defaults_drv = {
                .timing_trace = false,
                .clock_trace = true,
                .disable_pplib_clock_request = true,
-               .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP,
+               .pipe_split_policy = MPC_SPLIT_DYNAMIC,
                .force_single_disp_pipe_split = false,
                .disable_dcc = DCC_ENABLE,
                .vsr_support = true,
index 4a9b640..87cec14 100644 (file)
@@ -193,7 +193,7 @@ static const struct dc_debug_options debug_defaults_drv = {
                .timing_trace = false,
                .clock_trace = true,
                .disable_pplib_clock_request = true,
-               .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP,
+               .pipe_split_policy = MPC_SPLIT_DYNAMIC,
                .force_single_disp_pipe_split = false,
                .disable_dcc = DCC_ENABLE,
                .vsr_support = true,
index 4f6e639..17e2f2b 100644 (file)
@@ -101,6 +101,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
        .z10_restore = dcn31_z10_restore,
        .z10_save_init = dcn31_z10_save_init,
        .set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
+       .optimize_pwr_state = dcn21_optimize_pwr_state,
        .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state,
        .update_visual_confirm_color = dcn20_update_visual_confirm_color,
 };
index 1889629..27afbe6 100644 (file)
@@ -355,6 +355,14 @@ static const struct dce110_clk_src_regs clk_src_regs[] = {
        clk_src_regs(3, D),
        clk_src_regs(4, E)
 };
+/*pll_id being rempped in dmub, in driver it is logical instance*/
+static const struct dce110_clk_src_regs clk_src_regs_b0[] = {
+       clk_src_regs(0, A),
+       clk_src_regs(1, B),
+       clk_src_regs(2, F),
+       clk_src_regs(3, G),
+       clk_src_regs(4, E)
+};
 
 static const struct dce110_clk_src_shift cs_shift = {
                CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT)
@@ -994,7 +1002,7 @@ static const struct dc_debug_options debug_defaults_drv = {
        .timing_trace = false,
        .clock_trace = true,
        .disable_pplib_clock_request = false,
-       .pipe_split_policy = MPC_SPLIT_AVOID,
+       .pipe_split_policy = MPC_SPLIT_DYNAMIC,
        .force_single_disp_pipe_split = false,
        .disable_dcc = DCC_ENABLE,
        .vsr_support = true,
@@ -2276,14 +2284,27 @@ static bool dcn31_resource_construct(
                        dcn30_clock_source_create(ctx, ctx->dc_bios,
                                CLOCK_SOURCE_COMBO_PHY_PLL1,
                                &clk_src_regs[1], false);
-       pool->base.clock_sources[DCN31_CLK_SRC_PLL2] =
+       /*move phypllx_pixclk_resync to dmub next*/
+       if (dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) {
+               pool->base.clock_sources[DCN31_CLK_SRC_PLL2] =
+                       dcn30_clock_source_create(ctx, ctx->dc_bios,
+                               CLOCK_SOURCE_COMBO_PHY_PLL2,
+                               &clk_src_regs_b0[2], false);
+               pool->base.clock_sources[DCN31_CLK_SRC_PLL3] =
+                       dcn30_clock_source_create(ctx, ctx->dc_bios,
+                               CLOCK_SOURCE_COMBO_PHY_PLL3,
+                               &clk_src_regs_b0[3], false);
+       } else {
+               pool->base.clock_sources[DCN31_CLK_SRC_PLL2] =
                        dcn30_clock_source_create(ctx, ctx->dc_bios,
                                CLOCK_SOURCE_COMBO_PHY_PLL2,
                                &clk_src_regs[2], false);
-       pool->base.clock_sources[DCN31_CLK_SRC_PLL3] =
+               pool->base.clock_sources[DCN31_CLK_SRC_PLL3] =
                        dcn30_clock_source_create(ctx, ctx->dc_bios,
                                CLOCK_SOURCE_COMBO_PHY_PLL3,
                                &clk_src_regs[3], false);
+       }
+
        pool->base.clock_sources[DCN31_CLK_SRC_PLL4] =
                        dcn30_clock_source_create(ctx, ctx->dc_bios,
                                CLOCK_SOURCE_COMBO_PHY_PLL4,
index 416fe7a..a513363 100644 (file)
@@ -49,4 +49,35 @@ struct resource_pool *dcn31_create_resource_pool(
                const struct dc_init_data *init_data,
                struct dc *dc);
 
+/*temp: B0 specific before switch to dcn313 headers*/
+#ifndef regPHYPLLF_PIXCLK_RESYNC_CNTL
+#define regPHYPLLF_PIXCLK_RESYNC_CNTL 0x007e
+#define regPHYPLLF_PIXCLK_RESYNC_CNTL_BASE_IDX 1
+#define regPHYPLLG_PIXCLK_RESYNC_CNTL 0x005f
+#define regPHYPLLG_PIXCLK_RESYNC_CNTL_BASE_IDX 1
+
+//PHYPLLF_PIXCLK_RESYNC_CNTL
+#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_RESYNC_ENABLE__SHIFT 0x0
+#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DEEP_COLOR_DTO_ENABLE_STATUS__SHIFT 0x1
+#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DCCG_DEEP_COLOR_CNTL__SHIFT 0x4
+#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_ENABLE__SHIFT 0x8
+#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_DOUBLE_RATE_ENABLE__SHIFT 0x9
+#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_RESYNC_ENABLE_MASK 0x00000001L
+#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DEEP_COLOR_DTO_ENABLE_STATUS_MASK 0x00000002L
+#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DCCG_DEEP_COLOR_CNTL_MASK 0x00000030L
+#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_ENABLE_MASK 0x00000100L
+#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_DOUBLE_RATE_ENABLE_MASK 0x00000200L
+
+//PHYPLLG_PIXCLK_RESYNC_CNTL
+#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_RESYNC_ENABLE__SHIFT 0x0
+#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DEEP_COLOR_DTO_ENABLE_STATUS__SHIFT 0x1
+#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DCCG_DEEP_COLOR_CNTL__SHIFT 0x4
+#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_ENABLE__SHIFT 0x8
+#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_DOUBLE_RATE_ENABLE__SHIFT 0x9
+#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_RESYNC_ENABLE_MASK 0x00000001L
+#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DEEP_COLOR_DTO_ENABLE_STATUS_MASK 0x00000002L
+#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DCCG_DEEP_COLOR_CNTL_MASK 0x00000030L
+#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_ENABLE_MASK 0x00000100L
+#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_DOUBLE_RATE_ENABLE_MASK 0x00000200L
+#endif
 #endif /* _DCN31_RESOURCE_H_ */
index 7ec4331..a486769 100644 (file)
@@ -143,6 +143,55 @@ struct gc_info_v1_0 {
        uint32_t gc_num_gl2a;
 };
 
+struct gc_info_v1_1 {
+       struct gpu_info_header header;
+
+       uint32_t gc_num_se;
+       uint32_t gc_num_wgp0_per_sa;
+       uint32_t gc_num_wgp1_per_sa;
+       uint32_t gc_num_rb_per_se;
+       uint32_t gc_num_gl2c;
+       uint32_t gc_num_gprs;
+       uint32_t gc_num_max_gs_thds;
+       uint32_t gc_gs_table_depth;
+       uint32_t gc_gsprim_buff_depth;
+       uint32_t gc_parameter_cache_depth;
+       uint32_t gc_double_offchip_lds_buffer;
+       uint32_t gc_wave_size;
+       uint32_t gc_max_waves_per_simd;
+       uint32_t gc_max_scratch_slots_per_cu;
+       uint32_t gc_lds_size;
+       uint32_t gc_num_sc_per_se;
+       uint32_t gc_num_sa_per_se;
+       uint32_t gc_num_packer_per_sc;
+       uint32_t gc_num_gl2a;
+       uint32_t gc_num_tcp_per_sa;
+       uint32_t gc_num_sdp_interface;
+       uint32_t gc_num_tcps;
+};
+
+struct gc_info_v2_0 {
+       struct gpu_info_header header;
+
+       uint32_t gc_num_se;
+       uint32_t gc_num_cu_per_sh;
+       uint32_t gc_num_sh_per_se;
+       uint32_t gc_num_rb_per_se;
+       uint32_t gc_num_tccs;
+       uint32_t gc_num_gprs;
+       uint32_t gc_num_max_gs_thds;
+       uint32_t gc_gs_table_depth;
+       uint32_t gc_gsprim_buff_depth;
+       uint32_t gc_parameter_cache_depth;
+       uint32_t gc_double_offchip_lds_buffer;
+       uint32_t gc_wave_size;
+       uint32_t gc_max_waves_per_simd;
+       uint32_t gc_max_scratch_slots_per_cu;
+       uint32_t gc_lds_size;
+       uint32_t gc_num_sc_per_se;
+       uint32_t gc_num_packer_per_sc;
+};
+
 typedef struct harvest_info_header {
        uint32_t signature; /* Table Signature */
        uint32_t version;   /* Table Version */
index 8a32445..8a81793 100644 (file)
@@ -1568,9 +1568,7 @@ static int smu_suspend(void *handle)
 
        smu->watermarks_bitmap &= ~(WATERMARKS_LOADED);
 
-       /* skip CGPG when in S0ix */
-       if (smu->is_apu && !adev->in_s0ix)
-               smu_set_gfx_cgpg(&adev->smu, false);
+       smu_set_gfx_cgpg(&adev->smu, false);
 
        return 0;
 }
@@ -1601,8 +1599,7 @@ static int smu_resume(void *handle)
                return ret;
        }
 
-       if (smu->is_apu)
-               smu_set_gfx_cgpg(&adev->smu, true);
+       smu_set_gfx_cgpg(&adev->smu, true);
 
        smu->disable_uclk_switch = 0;
 
index 43028f2..9c91e79 100644 (file)
@@ -120,7 +120,8 @@ int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate)
 
 int smu_v12_0_set_gfx_cgpg(struct smu_context *smu, bool enable)
 {
-       if (!(smu->adev->pg_flags & AMD_PG_SUPPORT_GFX_PG))
+       /* Until now the SMU12 only implemented for Renoir series so here neen't do APU check. */
+       if (!(smu->adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) || smu->adev->in_s0ix)
                return 0;
 
        return smu_cmn_send_smc_msg_with_param(smu,
index 59a7d27..7d50827 100644 (file)
@@ -1621,7 +1621,7 @@ static int aldebaran_allow_xgmi_power_down(struct smu_context *smu, bool en)
 {
        return smu_cmn_send_smc_msg_with_param(smu,
                                               SMU_MSG_GmiPwrDnControl,
-                                              en ? 1 : 0,
+                                              en ? 0 : 1,
                                               NULL);
 }
 
index fb33d03..c37c9f0 100644 (file)
@@ -564,6 +564,7 @@ set_proto_ctx_engines_parallel_submit(struct i915_user_extension __user *base,
                container_of_user(base, typeof(*ext), base);
        const struct set_proto_ctx_engines *set = data;
        struct drm_i915_private *i915 = set->i915;
+       struct i915_engine_class_instance prev_engine;
        u64 flags;
        int err = 0, n, i, j;
        u16 slot, width, num_siblings;
@@ -629,7 +630,6 @@ set_proto_ctx_engines_parallel_submit(struct i915_user_extension __user *base,
        /* Create contexts / engines */
        for (i = 0; i < width; ++i) {
                intel_engine_mask_t current_mask = 0;
-               struct i915_engine_class_instance prev_engine;
 
                for (j = 0; j < num_siblings; ++j) {
                        struct i915_engine_class_instance ci;
index 9b24d9b..cb0bf6f 100644 (file)
@@ -3017,7 +3017,7 @@ eb_composite_fence_create(struct i915_execbuffer *eb, int out_fence_fd)
        fence_array = dma_fence_array_create(eb->num_batches,
                                             fences,
                                             eb->context->parallel.fence_context,
-                                            eb->context->parallel.seqno,
+                                            eb->context->parallel.seqno++,
                                             false);
        if (!fence_array) {
                kfree(fences);
index c48557d..302e9ff 100644 (file)
@@ -1662,11 +1662,11 @@ static int steal_guc_id(struct intel_guc *guc, struct intel_context *ce)
                GEM_BUG_ON(intel_context_is_parent(cn));
 
                list_del_init(&cn->guc_id.link);
-               ce->guc_id = cn->guc_id;
+               ce->guc_id.id = cn->guc_id.id;
 
-               spin_lock(&ce->guc_state.lock);
+               spin_lock(&cn->guc_state.lock);
                clr_context_registered(cn);
-               spin_unlock(&ce->guc_state.lock);
+               spin_unlock(&cn->guc_state.lock);
 
                set_context_guc_id_invalid(cn);
 
index 5838c44..3196189 100644 (file)
@@ -1224,12 +1224,14 @@ static int mtk_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
                        return MODE_BAD;
        }
 
-       if (hdmi->conf->cea_modes_only && !drm_match_cea_mode(mode))
-               return MODE_BAD;
+       if (hdmi->conf) {
+               if (hdmi->conf->cea_modes_only && !drm_match_cea_mode(mode))
+                       return MODE_BAD;
 
-       if (hdmi->conf->max_mode_clock &&
-           mode->clock > hdmi->conf->max_mode_clock)
-               return MODE_CLOCK_HIGH;
+               if (hdmi->conf->max_mode_clock &&
+                   mode->clock > hdmi->conf->max_mode_clock)
+                       return MODE_CLOCK_HIGH;
+       }
 
        if (mode->clock < 27000)
                return MODE_CLOCK_LOW;
index 05d0b3e..0ae416a 100644 (file)
@@ -353,15 +353,22 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e
 
                if (ret)
                        return ret;
-       }
 
-       fobj = dma_resv_shared_list(resv);
-       fence = dma_resv_excl_fence(resv);
+               fobj = NULL;
+       } else {
+               fobj = dma_resv_shared_list(resv);
+       }
 
-       if (fence) {
+       /* Waiting for the exclusive fence first causes performance regressions
+        * under some circumstances. So manually wait for the shared ones first.
+        */
+       for (i = 0; i < (fobj ? fobj->shared_count : 0) && !ret; ++i) {
                struct nouveau_channel *prev = NULL;
                bool must_wait = true;
 
+               fence = rcu_dereference_protected(fobj->shared[i],
+                                               dma_resv_held(resv));
+
                f = nouveau_local_fence(fence, chan->drm);
                if (f) {
                        rcu_read_lock();
@@ -373,20 +380,13 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e
 
                if (must_wait)
                        ret = dma_fence_wait(fence, intr);
-
-               return ret;
        }
 
-       if (!exclusive || !fobj)
-               return ret;
-
-       for (i = 0; i < fobj->shared_count && !ret; ++i) {
+       fence = dma_resv_excl_fence(resv);
+       if (fence) {
                struct nouveau_channel *prev = NULL;
                bool must_wait = true;
 
-               fence = rcu_dereference_protected(fobj->shared[i],
-                                               dma_resv_held(resv));
-
                f = nouveau_local_fence(fence, chan->drm);
                if (f) {
                        rcu_read_lock();
@@ -398,6 +398,8 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e
 
                if (must_wait)
                        ret = dma_fence_wait(fence, intr);
+
+               return ret;
        }
 
        return ret;
index b7172c4..7c90793 100644 (file)
@@ -65,8 +65,23 @@ static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 static int holtek_mouse_probe(struct hid_device *hdev,
                              const struct hid_device_id *id)
 {
+       int ret;
+
        if (!hid_is_usb(hdev))
                return -EINVAL;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               hid_err(hdev, "hid parse failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               hid_err(hdev, "hw start failed: %d\n", ret);
+               return ret;
+       }
+
        return 0;
 }
 
index cd7ada4..72957a9 100644 (file)
@@ -57,6 +57,9 @@ static int vivaldi_probe(struct hid_device *hdev,
        int ret;
 
        drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+
        hid_set_drvdata(hdev, drvdata);
 
        ret = hid_parse(hdev);
index 618052c..74019df 100644 (file)
  * explicitly as max6659, or if its address is not 0x4c.
  * These chips lack the remote temperature offset feature.
  *
- * This driver also supports the MAX6654 chip made by Maxim. This chip can
- * be at 9 different addresses, similar to MAX6680/MAX6681. The MAX6654 is
- * otherwise similar to MAX6657/MAX6658/MAX6659. Extended range is available
- * by setting the configuration register accordingly, and is done during
- * initialization. Extended precision is only available at conversion rates
- * of 1 Hz and slower. Note that extended precision is not enabled by
- * default, as this driver initializes all chips to 2 Hz by design.
+ * This driver also supports the MAX6654 chip made by Maxim. This chip can be
+ * at 9 different addresses, similar to MAX6680/MAX6681. The MAX6654 is similar
+ * to MAX6657/MAX6658/MAX6659, but does not support critical temperature
+ * limits. Extended range is available by setting the configuration register
+ * accordingly, and is done during initialization. Extended precision is only
+ * available at conversion rates of 1 Hz and slower. Note that extended
+ * precision is not enabled by default, as this driver initializes all chips
+ * to 2 Hz by design.
  *
  * This driver also supports the MAX6646, MAX6647, MAX6648, MAX6649 and
  * MAX6692 chips made by Maxim.  These are again similar to the LM86,
@@ -188,6 +189,8 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
 #define LM90_HAVE_BROKEN_ALERT (1 << 7) /* Broken alert                */
 #define LM90_HAVE_EXTENDED_TEMP        (1 << 8) /* extended temperature support*/
 #define LM90_PAUSE_FOR_CONFIG  (1 << 9) /* Pause conversion for config */
+#define LM90_HAVE_CRIT         (1 << 10)/* Chip supports CRIT/OVERT register   */
+#define LM90_HAVE_CRIT_ALRM_SWP        (1 << 11)/* critical alarm bits swapped */
 
 /* LM90 status */
 #define LM90_STATUS_LTHRM      (1 << 0) /* local THERM limit tripped */
@@ -197,6 +200,7 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
 #define LM90_STATUS_RHIGH      (1 << 4) /* remote high temp limit tripped */
 #define LM90_STATUS_LLOW       (1 << 5) /* local low temp limit tripped */
 #define LM90_STATUS_LHIGH      (1 << 6) /* local high temp limit tripped */
+#define LM90_STATUS_BUSY       (1 << 7) /* conversion is ongoing */
 
 #define MAX6696_STATUS2_R2THRM (1 << 1) /* remote2 THERM limit tripped */
 #define MAX6696_STATUS2_R2OPEN (1 << 2) /* remote2 is an open circuit */
@@ -354,38 +358,43 @@ struct lm90_params {
 static const struct lm90_params lm90_params[] = {
        [adm1032] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-                 | LM90_HAVE_BROKEN_ALERT,
+                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT,
                .alert_alarms = 0x7c,
                .max_convrate = 10,
        },
        [adt7461] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP,
+                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP
+                 | LM90_HAVE_CRIT,
                .alert_alarms = 0x7c,
                .max_convrate = 10,
        },
        [g781] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-                 | LM90_HAVE_BROKEN_ALERT,
+                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT,
                .alert_alarms = 0x7c,
                .max_convrate = 8,
        },
        [lm86] = {
-               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+                 | LM90_HAVE_CRIT,
                .alert_alarms = 0x7b,
                .max_convrate = 9,
        },
        [lm90] = {
-               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+                 | LM90_HAVE_CRIT,
                .alert_alarms = 0x7b,
                .max_convrate = 9,
        },
        [lm99] = {
-               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+                 | LM90_HAVE_CRIT,
                .alert_alarms = 0x7b,
                .max_convrate = 9,
        },
        [max6646] = {
+               .flags = LM90_HAVE_CRIT,
                .alert_alarms = 0x7c,
                .max_convrate = 6,
                .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
@@ -396,50 +405,51 @@ static const struct lm90_params lm90_params[] = {
                .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [max6657] = {
-               .flags = LM90_PAUSE_FOR_CONFIG,
+               .flags = LM90_PAUSE_FOR_CONFIG | LM90_HAVE_CRIT,
                .alert_alarms = 0x7c,
                .max_convrate = 8,
                .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [max6659] = {
-               .flags = LM90_HAVE_EMERGENCY,
+               .flags = LM90_HAVE_EMERGENCY | LM90_HAVE_CRIT,
                .alert_alarms = 0x7c,
                .max_convrate = 8,
                .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [max6680] = {
-               .flags = LM90_HAVE_OFFSET,
+               .flags = LM90_HAVE_OFFSET | LM90_HAVE_CRIT
+                 | LM90_HAVE_CRIT_ALRM_SWP,
                .alert_alarms = 0x7c,
                .max_convrate = 7,
        },
        [max6696] = {
                .flags = LM90_HAVE_EMERGENCY
-                 | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3,
+                 | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3 | LM90_HAVE_CRIT,
                .alert_alarms = 0x1c7c,
                .max_convrate = 6,
                .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [w83l771] = {
-               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT,
                .alert_alarms = 0x7c,
                .max_convrate = 8,
        },
        [sa56004] = {
-               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT,
                .alert_alarms = 0x7b,
                .max_convrate = 9,
                .reg_local_ext = SA56004_REG_R_LOCAL_TEMPL,
        },
        [tmp451] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP,
+                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT,
                .alert_alarms = 0x7c,
                .max_convrate = 9,
                .reg_local_ext = TMP451_REG_R_LOCAL_TEMPL,
        },
        [tmp461] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP,
+                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT,
                .alert_alarms = 0x7c,
                .max_convrate = 9,
                .reg_local_ext = TMP451_REG_R_LOCAL_TEMPL,
@@ -668,20 +678,22 @@ static int lm90_update_limits(struct device *dev)
        struct i2c_client *client = data->client;
        int val;
 
-       val = lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT);
-       if (val < 0)
-               return val;
-       data->temp8[LOCAL_CRIT] = val;
+       if (data->flags & LM90_HAVE_CRIT) {
+               val = lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT);
+               if (val < 0)
+                       return val;
+               data->temp8[LOCAL_CRIT] = val;
 
-       val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT);
-       if (val < 0)
-               return val;
-       data->temp8[REMOTE_CRIT] = val;
+               val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT);
+               if (val < 0)
+                       return val;
+               data->temp8[REMOTE_CRIT] = val;
 
-       val = lm90_read_reg(client, LM90_REG_R_TCRIT_HYST);
-       if (val < 0)
-               return val;
-       data->temp_hyst = val;
+               val = lm90_read_reg(client, LM90_REG_R_TCRIT_HYST);
+               if (val < 0)
+                       return val;
+               data->temp_hyst = val;
+       }
 
        val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH);
        if (val < 0)
@@ -809,7 +821,7 @@ static int lm90_update_device(struct device *dev)
                val = lm90_read_reg(client, LM90_REG_R_STATUS);
                if (val < 0)
                        return val;
-               data->alarms = val;     /* lower 8 bit of alarms */
+               data->alarms = val & ~LM90_STATUS_BUSY;
 
                if (data->kind == max6696) {
                        val = lm90_select_remote_channel(data, 1);
@@ -1160,8 +1172,8 @@ static int lm90_set_temphyst(struct lm90_data *data, long val)
        else
                temp = temp_from_s8(data->temp8[LOCAL_CRIT]);
 
-       /* prevent integer underflow */
-       val = max(val, -128000l);
+       /* prevent integer overflow/underflow */
+       val = clamp_val(val, -128000l, 255000l);
 
        data->temp_hyst = hyst_to_reg(temp - val);
        err = i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST,
@@ -1192,6 +1204,7 @@ static const u8 lm90_temp_emerg_index[3] = {
 static const u8 lm90_min_alarm_bits[3] = { 5, 3, 11 };
 static const u8 lm90_max_alarm_bits[3] = { 6, 4, 12 };
 static const u8 lm90_crit_alarm_bits[3] = { 0, 1, 9 };
+static const u8 lm90_crit_alarm_bits_swapped[3] = { 1, 0, 9 };
 static const u8 lm90_emergency_alarm_bits[3] = { 15, 13, 14 };
 static const u8 lm90_fault_bits[3] = { 0, 2, 10 };
 
@@ -1217,7 +1230,10 @@ static int lm90_temp_read(struct device *dev, u32 attr, int channel, long *val)
                *val = (data->alarms >> lm90_max_alarm_bits[channel]) & 1;
                break;
        case hwmon_temp_crit_alarm:
-               *val = (data->alarms >> lm90_crit_alarm_bits[channel]) & 1;
+               if (data->flags & LM90_HAVE_CRIT_ALRM_SWP)
+                       *val = (data->alarms >> lm90_crit_alarm_bits_swapped[channel]) & 1;
+               else
+                       *val = (data->alarms >> lm90_crit_alarm_bits[channel]) & 1;
                break;
        case hwmon_temp_emergency_alarm:
                *val = (data->alarms >> lm90_emergency_alarm_bits[channel]) & 1;
@@ -1465,12 +1481,11 @@ static int lm90_detect(struct i2c_client *client,
        if (man_id < 0 || chip_id < 0 || config1 < 0 || convrate < 0)
                return -ENODEV;
 
-       if (man_id == 0x01 || man_id == 0x5C || man_id == 0x41) {
+       if (man_id == 0x01 || man_id == 0x5C || man_id == 0xA1) {
                config2 = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG2);
                if (config2 < 0)
                        return -ENODEV;
-       } else
-               config2 = 0;            /* Make compiler happy */
+       }
 
        if ((address == 0x4C || address == 0x4D)
         && man_id == 0x01) { /* National Semiconductor */
@@ -1903,11 +1918,14 @@ static int lm90_probe(struct i2c_client *client)
        info->config = data->channel_config;
 
        data->channel_config[0] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
-               HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
-               HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM;
+               HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM;
        data->channel_config[1] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
-               HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
-               HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT;
+               HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM | HWMON_T_FAULT;
+
+       if (data->flags & LM90_HAVE_CRIT) {
+               data->channel_config[0] |= HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_CRIT_HYST;
+               data->channel_config[1] |= HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_CRIT_HYST;
+       }
 
        if (data->flags & LM90_HAVE_OFFSET)
                data->channel_config[1] |= HWMON_T_OFFSET;
index bce0e8b..cf5d049 100644 (file)
@@ -535,6 +535,9 @@ static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned lo
                                   sizeof(rdwr_arg)))
                        return -EFAULT;
 
+               if (!rdwr_arg.msgs || rdwr_arg.nmsgs == 0)
+                       return -EINVAL;
+
                if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
                        return -EINVAL;
 
index bbfa133..eb0defa 100644 (file)
@@ -1594,11 +1594,17 @@ static int hns_roce_config_global_param(struct hns_roce_dev *hr_dev)
 {
        struct hns_roce_cmq_desc desc;
        struct hns_roce_cmq_req *req = (struct hns_roce_cmq_req *)desc.data;
+       u32 clock_cycles_of_1us;
 
        hns_roce_cmq_setup_basic_desc(&desc, HNS_ROCE_OPC_CFG_GLOBAL_PARAM,
                                      false);
 
-       hr_reg_write(req, CFG_GLOBAL_PARAM_1US_CYCLES, 0x3e8);
+       if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08)
+               clock_cycles_of_1us = HNS_ROCE_1NS_CFG;
+       else
+               clock_cycles_of_1us = HNS_ROCE_1US_CFG;
+
+       hr_reg_write(req, CFG_GLOBAL_PARAM_1US_CYCLES, clock_cycles_of_1us);
        hr_reg_write(req, CFG_GLOBAL_PARAM_UDP_PORT, ROCE_V2_UDP_DPORT);
 
        return hns_roce_cmq_send(hr_dev, &desc, 1);
@@ -4802,6 +4808,30 @@ static int hns_roce_v2_set_abs_fields(struct ib_qp *ibqp,
        return ret;
 }
 
+static bool check_qp_timeout_cfg_range(struct hns_roce_dev *hr_dev, u8 *timeout)
+{
+#define QP_ACK_TIMEOUT_MAX_HIP08 20
+#define QP_ACK_TIMEOUT_OFFSET 10
+#define QP_ACK_TIMEOUT_MAX 31
+
+       if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08) {
+               if (*timeout > QP_ACK_TIMEOUT_MAX_HIP08) {
+                       ibdev_warn(&hr_dev->ib_dev,
+                                  "Local ACK timeout shall be 0 to 20.\n");
+                       return false;
+               }
+               *timeout += QP_ACK_TIMEOUT_OFFSET;
+       } else if (hr_dev->pci_dev->revision > PCI_REVISION_ID_HIP08) {
+               if (*timeout > QP_ACK_TIMEOUT_MAX) {
+                       ibdev_warn(&hr_dev->ib_dev,
+                                  "Local ACK timeout shall be 0 to 31.\n");
+                       return false;
+               }
+       }
+
+       return true;
+}
+
 static int hns_roce_v2_set_opt_fields(struct ib_qp *ibqp,
                                      const struct ib_qp_attr *attr,
                                      int attr_mask,
@@ -4811,6 +4841,7 @@ static int hns_roce_v2_set_opt_fields(struct ib_qp *ibqp,
        struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
        struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
        int ret = 0;
+       u8 timeout;
 
        if (attr_mask & IB_QP_AV) {
                ret = hns_roce_v2_set_path(ibqp, attr, attr_mask, context,
@@ -4820,12 +4851,10 @@ static int hns_roce_v2_set_opt_fields(struct ib_qp *ibqp,
        }
 
        if (attr_mask & IB_QP_TIMEOUT) {
-               if (attr->timeout < 31) {
-                       hr_reg_write(context, QPC_AT, attr->timeout);
+               timeout = attr->timeout;
+               if (check_qp_timeout_cfg_range(hr_dev, &timeout)) {
+                       hr_reg_write(context, QPC_AT, timeout);
                        hr_reg_clear(qpc_mask, QPC_AT);
-               } else {
-                       ibdev_warn(&hr_dev->ib_dev,
-                                  "Local ACK timeout shall be 0 to 30.\n");
                }
        }
 
@@ -4882,7 +4911,9 @@ static int hns_roce_v2_set_opt_fields(struct ib_qp *ibqp,
                set_access_flags(hr_qp, context, qpc_mask, attr, attr_mask);
 
        if (attr_mask & IB_QP_MIN_RNR_TIMER) {
-               hr_reg_write(context, QPC_MIN_RNR_TIME, attr->min_rnr_timer);
+               hr_reg_write(context, QPC_MIN_RNR_TIME,
+                           hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08 ?
+                           HNS_ROCE_RNR_TIMER_10NS : attr->min_rnr_timer);
                hr_reg_clear(qpc_mask, QPC_MIN_RNR_TIME);
        }
 
@@ -5499,6 +5530,16 @@ static int hns_roce_v2_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period)
 
        hr_reg_write(cq_context, CQC_CQ_MAX_CNT, cq_count);
        hr_reg_clear(cqc_mask, CQC_CQ_MAX_CNT);
+
+       if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08) {
+               if (cq_period * HNS_ROCE_CLOCK_ADJUST > USHRT_MAX) {
+                       dev_info(hr_dev->dev,
+                                "cq_period(%u) reached the upper limit, adjusted to 65.\n",
+                                cq_period);
+                       cq_period = HNS_ROCE_MAX_CQ_PERIOD;
+               }
+               cq_period *= HNS_ROCE_CLOCK_ADJUST;
+       }
        hr_reg_write(cq_context, CQC_CQ_PERIOD, cq_period);
        hr_reg_clear(cqc_mask, CQC_CQ_PERIOD);
 
@@ -5894,6 +5935,15 @@ static int config_eqc(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq,
        hr_reg_write(eqc, EQC_EQ_PROD_INDX, HNS_ROCE_EQ_INIT_PROD_IDX);
        hr_reg_write(eqc, EQC_EQ_MAX_CNT, eq->eq_max_cnt);
 
+       if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08) {
+               if (eq->eq_period * HNS_ROCE_CLOCK_ADJUST > USHRT_MAX) {
+                       dev_info(hr_dev->dev, "eq_period(%u) reached the upper limit, adjusted to 65.\n",
+                                eq->eq_period);
+                       eq->eq_period = HNS_ROCE_MAX_EQ_PERIOD;
+               }
+               eq->eq_period *= HNS_ROCE_CLOCK_ADJUST;
+       }
+
        hr_reg_write(eqc, EQC_EQ_PERIOD, eq->eq_period);
        hr_reg_write(eqc, EQC_EQE_REPORT_TIMER, HNS_ROCE_EQ_INIT_REPORT_TIMER);
        hr_reg_write(eqc, EQC_EQE_BA_L, bt_ba >> 3);
index 4d904d5..35c61da 100644 (file)
@@ -1444,6 +1444,14 @@ struct hns_roce_dip {
        struct list_head node;  /* all dips are on a list */
 };
 
+/* only for RNR timeout issue of HIP08 */
+#define HNS_ROCE_CLOCK_ADJUST 1000
+#define HNS_ROCE_MAX_CQ_PERIOD 65
+#define HNS_ROCE_MAX_EQ_PERIOD 65
+#define HNS_ROCE_RNR_TIMER_10NS 1
+#define HNS_ROCE_1US_CFG 999
+#define HNS_ROCE_1NS_CFG 0
+
 #define HNS_ROCE_AEQ_DEFAULT_BURST_NUM 0x0
 #define HNS_ROCE_AEQ_DEFAULT_INTERVAL  0x0
 #define HNS_ROCE_CEQ_DEFAULT_BURST_NUM 0x0
index 6eee9de..e64ef69 100644 (file)
@@ -259,7 +259,7 @@ static int alloc_srq_wrid(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq)
 
 static void free_srq_wrid(struct hns_roce_srq *srq)
 {
-       kfree(srq->wrid);
+       kvfree(srq->wrid);
        srq->wrid = NULL;
 }
 
index ac11943..bf2f30d 100644 (file)
@@ -941,7 +941,7 @@ static int qib_user_sdma_queue_pkts(const struct qib_devdata *dd,
                                               &addrlimit) ||
                            addrlimit > type_max(typeof(pkt->addrlimit))) {
                                ret = -EINVAL;
-                               goto free_pbc;
+                               goto free_pkt;
                        }
                        pkt->addrlimit = addrlimit;
 
index 429411c..a85a4f3 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/input.h>
 #include <linux/serio.h>
+#include <asm/unaligned.h>
 
 #define DRIVER_DESC    "SpaceTec SpaceBall 2003/3003/4000 FLX driver"
 
@@ -75,9 +76,15 @@ static void spaceball_process_packet(struct spaceball* spaceball)
 
                case 'D':                                       /* Ball data */
                        if (spaceball->idx != 15) return;
-                       for (i = 0; i < 6; i++)
+                       /*
+                        * Skip first three bytes; read six axes worth of data.
+                        * Axis values are signed 16-bit big-endian.
+                        */
+                       data += 3;
+                       for (i = 0; i < ARRAY_SIZE(spaceball_axes); i++) {
                                input_report_abs(dev, spaceball_axes[i],
-                                       (__s16)((data[2 * i + 3] << 8) | data[2 * i + 2]));
+                                       (__s16)get_unaligned_be16(&data[i * 2]));
+                       }
                        break;
 
                case 'K':                                       /* Button data */
index d57e996..23b5dd9 100644 (file)
@@ -456,9 +456,10 @@ struct iqs626_private {
        unsigned int suspend_mode;
 };
 
-static int iqs626_parse_events(struct iqs626_private *iqs626,
-                              const struct fwnode_handle *ch_node,
-                              enum iqs626_ch_id ch_id)
+static noinline_for_stack int
+iqs626_parse_events(struct iqs626_private *iqs626,
+                   const struct fwnode_handle *ch_node,
+                   enum iqs626_ch_id ch_id)
 {
        struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;
        struct i2c_client *client = iqs626->client;
@@ -604,9 +605,10 @@ static int iqs626_parse_events(struct iqs626_private *iqs626,
        return 0;
 }
 
-static int iqs626_parse_ati_target(struct iqs626_private *iqs626,
-                                  const struct fwnode_handle *ch_node,
-                                  enum iqs626_ch_id ch_id)
+static noinline_for_stack int
+iqs626_parse_ati_target(struct iqs626_private *iqs626,
+                       const struct fwnode_handle *ch_node,
+                       enum iqs626_ch_id ch_id)
 {
        struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;
        struct i2c_client *client = iqs626->client;
@@ -885,9 +887,10 @@ static int iqs626_parse_trackpad(struct iqs626_private *iqs626,
        return 0;
 }
 
-static int iqs626_parse_channel(struct iqs626_private *iqs626,
-                               const struct fwnode_handle *ch_node,
-                               enum iqs626_ch_id ch_id)
+static noinline_for_stack int
+iqs626_parse_channel(struct iqs626_private *iqs626,
+                    const struct fwnode_handle *ch_node,
+                    enum iqs626_ch_id ch_id)
 {
        struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;
        struct i2c_client *client = iqs626->client;
index bfa2665..627048b 100644 (file)
@@ -916,6 +916,8 @@ static int atp_probe(struct usb_interface *iface,
        set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
        set_bit(BTN_LEFT, input_dev->keybit);
 
+       INIT_WORK(&dev->work, atp_reinit);
+
        error = input_register_device(dev->input);
        if (error)
                goto err_free_buffer;
@@ -923,8 +925,6 @@ static int atp_probe(struct usb_interface *iface,
        /* save our data pointer in this interface device */
        usb_set_intfdata(iface, dev);
 
-       INIT_WORK(&dev->work, atp_reinit);
-
        return 0;
 
  err_free_buffer:
index 956d9cd..ece97f8 100644 (file)
@@ -1588,7 +1588,13 @@ static const struct dmi_system_id no_hw_res_dmi_table[] = {
  */
 static int elantech_change_report_id(struct psmouse *psmouse)
 {
-       unsigned char param[2] = { 0x10, 0x03 };
+       /*
+        * NOTE: the code is expecting to receive param[] as an array of 3
+        * items (see __ps2_command()), even if in this case only 2 are
+        * actually needed. Make sure the array size is 3 to avoid potential
+        * stack out-of-bound accesses.
+        */
+       unsigned char param[3] = { 0x10, 0x03 };
 
        if (elantech_write_reg_params(psmouse, 0x7, param) ||
            elantech_read_reg_params(psmouse, 0x7, param) ||
index aedd055..148a7c5 100644 (file)
@@ -995,6 +995,24 @@ static const struct dmi_system_id __initconst i8042_dmi_kbdreset_table[] = {
        { }
 };
 
+static const struct dmi_system_id i8042_dmi_probe_defer_table[] __initconst = {
+       {
+               /* ASUS ZenBook UX425UA */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX425UA"),
+               },
+       },
+       {
+               /* ASUS ZenBook UM325UA */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"),
+               },
+       },
+       { }
+};
+
 #endif /* CONFIG_X86 */
 
 #ifdef CONFIG_PNP
@@ -1315,6 +1333,9 @@ static int __init i8042_platform_init(void)
        if (dmi_check_system(i8042_dmi_kbdreset_table))
                i8042_kbdreset = true;
 
+       if (dmi_check_system(i8042_dmi_probe_defer_table))
+               i8042_probe_defer = true;
+
        /*
         * A20 was already enabled during early kernel init. But some buggy
         * BIOSes (in MSI Laptops) require A20 to be enabled using 8042 to
index 0b9f1d0..3fc0a89 100644 (file)
@@ -45,6 +45,10 @@ static bool i8042_unlock;
 module_param_named(unlock, i8042_unlock, bool, 0);
 MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
 
+static bool i8042_probe_defer;
+module_param_named(probe_defer, i8042_probe_defer, bool, 0);
+MODULE_PARM_DESC(probe_defer, "Allow deferred probing.");
+
 enum i8042_controller_reset_mode {
        I8042_RESET_NEVER,
        I8042_RESET_ALWAYS,
@@ -711,7 +715,7 @@ static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version)
  * LCS/Telegraphics.
  */
 
-static int __init i8042_check_mux(void)
+static int i8042_check_mux(void)
 {
        unsigned char mux_version;
 
@@ -740,10 +744,10 @@ static int __init i8042_check_mux(void)
 /*
  * The following is used to test AUX IRQ delivery.
  */
-static struct completion i8042_aux_irq_delivered __initdata;
-static bool i8042_irq_being_tested __initdata;
+static struct completion i8042_aux_irq_delivered;
+static bool i8042_irq_being_tested;
 
-static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id)
+static irqreturn_t i8042_aux_test_irq(int irq, void *dev_id)
 {
        unsigned long flags;
        unsigned char str, data;
@@ -770,7 +774,7 @@ static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id)
  * verifies success by readinng CTR. Used when testing for presence of AUX
  * port.
  */
-static int __init i8042_toggle_aux(bool on)
+static int i8042_toggle_aux(bool on)
 {
        unsigned char param;
        int i;
@@ -798,7 +802,7 @@ static int __init i8042_toggle_aux(bool on)
  * the presence of an AUX interface.
  */
 
-static int __init i8042_check_aux(void)
+static int i8042_check_aux(void)
 {
        int retval = -1;
        bool irq_registered = false;
@@ -1005,7 +1009,7 @@ static int i8042_controller_init(void)
 
                if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) {
                        pr_err("Can't read CTR while initializing i8042\n");
-                       return -EIO;
+                       return i8042_probe_defer ? -EPROBE_DEFER : -EIO;
                }
 
        } while (n < 2 || ctr[0] != ctr[1]);
@@ -1320,7 +1324,7 @@ static void i8042_shutdown(struct platform_device *dev)
        i8042_controller_reset(false);
 }
 
-static int __init i8042_create_kbd_port(void)
+static int i8042_create_kbd_port(void)
 {
        struct serio *serio;
        struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];
@@ -1349,7 +1353,7 @@ static int __init i8042_create_kbd_port(void)
        return 0;
 }
 
-static int __init i8042_create_aux_port(int idx)
+static int i8042_create_aux_port(int idx)
 {
        struct serio *serio;
        int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx;
@@ -1386,13 +1390,13 @@ static int __init i8042_create_aux_port(int idx)
        return 0;
 }
 
-static void __init i8042_free_kbd_port(void)
+static void i8042_free_kbd_port(void)
 {
        kfree(i8042_ports[I8042_KBD_PORT_NO].serio);
        i8042_ports[I8042_KBD_PORT_NO].serio = NULL;
 }
 
-static void __init i8042_free_aux_ports(void)
+static void i8042_free_aux_ports(void)
 {
        int i;
 
@@ -1402,7 +1406,7 @@ static void __init i8042_free_aux_ports(void)
        }
 }
 
-static void __init i8042_register_ports(void)
+static void i8042_register_ports(void)
 {
        int i;
 
@@ -1443,7 +1447,7 @@ static void i8042_free_irqs(void)
        i8042_aux_irq_registered = i8042_kbd_irq_registered = false;
 }
 
-static int __init i8042_setup_aux(void)
+static int i8042_setup_aux(void)
 {
        int (*aux_enable)(void);
        int error;
@@ -1485,7 +1489,7 @@ static int __init i8042_setup_aux(void)
        return error;
 }
 
-static int __init i8042_setup_kbd(void)
+static int i8042_setup_kbd(void)
 {
        int error;
 
@@ -1535,7 +1539,7 @@ static int i8042_kbd_bind_notifier(struct notifier_block *nb,
        return 0;
 }
 
-static int __init i8042_probe(struct platform_device *dev)
+static int i8042_probe(struct platform_device *dev)
 {
        int error;
 
@@ -1600,6 +1604,7 @@ static struct platform_driver i8042_driver = {
                .pm     = &i8042_pm_ops,
 #endif
        },
+       .probe          = i8042_probe,
        .remove         = i8042_remove,
        .shutdown       = i8042_shutdown,
 };
@@ -1610,7 +1615,6 @@ static struct notifier_block i8042_kbd_bind_notifier_block = {
 
 static int __init i8042_init(void)
 {
-       struct platform_device *pdev;
        int err;
 
        dbg_init();
@@ -1626,17 +1630,29 @@ static int __init i8042_init(void)
        /* Set this before creating the dev to allow i8042_command to work right away */
        i8042_present = true;
 
-       pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0);
-       if (IS_ERR(pdev)) {
-               err = PTR_ERR(pdev);
+       err = platform_driver_register(&i8042_driver);
+       if (err)
                goto err_platform_exit;
+
+       i8042_platform_device = platform_device_alloc("i8042", -1);
+       if (!i8042_platform_device) {
+               err = -ENOMEM;
+               goto err_unregister_driver;
        }
 
+       err = platform_device_add(i8042_platform_device);
+       if (err)
+               goto err_free_device;
+
        bus_register_notifier(&serio_bus, &i8042_kbd_bind_notifier_block);
        panic_blink = i8042_panic_blink;
 
        return 0;
 
+err_free_device:
+       platform_device_put(i8042_platform_device);
+err_unregister_driver:
+       platform_driver_unregister(&i8042_driver);
  err_platform_exit:
        i8042_platform_exit();
        return err;
index 05de92c..eb66cd2 100644 (file)
@@ -1882,7 +1882,7 @@ static int mxt_read_info_block(struct mxt_data *data)
        if (error) {
                dev_err(&client->dev, "Error %d parsing object table\n", error);
                mxt_free_object_table(data);
-               goto err_free_mem;
+               return error;
        }
 
        data->object_table = (struct mxt_object *)(id_buf + MXT_OBJECT_START);
index 7e13a66..879a4d9 100644 (file)
 #define ELAN_POWERON_DELAY_USEC        500
 #define ELAN_RESET_DELAY_MSEC  20
 
+/* FW boot code version */
+#define BC_VER_H_BYTE_FOR_EKTH3900x1_I2C        0x72
+#define BC_VER_H_BYTE_FOR_EKTH3900x2_I2C        0x82
+#define BC_VER_H_BYTE_FOR_EKTH3900x3_I2C        0x92
+#define BC_VER_H_BYTE_FOR_EKTH5312x1_I2C        0x6D
+#define BC_VER_H_BYTE_FOR_EKTH5312x2_I2C        0x6E
+#define BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C       0x77
+#define BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C       0x78
+#define BC_VER_H_BYTE_FOR_EKTH5312x1_I2C_USB    0x67
+#define BC_VER_H_BYTE_FOR_EKTH5312x2_I2C_USB    0x68
+#define BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C_USB   0x74
+#define BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C_USB   0x75
+
 enum elants_chip_id {
        EKTH3500,
        EKTF3624,
@@ -736,6 +749,37 @@ static int elants_i2c_validate_remark_id(struct elants_data *ts,
        return 0;
 }
 
+static bool elants_i2c_should_check_remark_id(struct elants_data *ts)
+{
+       struct i2c_client *client = ts->client;
+       const u8 bootcode_version = ts->iap_version;
+       bool check;
+
+       /* I2C eKTH3900 and eKTH5312 are NOT support Remark ID */
+       if ((bootcode_version == BC_VER_H_BYTE_FOR_EKTH3900x1_I2C) ||
+           (bootcode_version == BC_VER_H_BYTE_FOR_EKTH3900x2_I2C) ||
+           (bootcode_version == BC_VER_H_BYTE_FOR_EKTH3900x3_I2C) ||
+           (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x1_I2C) ||
+           (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x2_I2C) ||
+           (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C) ||
+           (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C) ||
+           (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x1_I2C_USB) ||
+           (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x2_I2C_USB) ||
+           (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C_USB) ||
+           (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C_USB)) {
+               dev_dbg(&client->dev,
+                       "eKTH3900/eKTH5312(0x%02x) are not support remark id\n",
+                       bootcode_version);
+               check = false;
+       } else if (bootcode_version >= 0x60) {
+               check = true;
+       } else {
+               check = false;
+       }
+
+       return check;
+}
+
 static int elants_i2c_do_update_firmware(struct i2c_client *client,
                                         const struct firmware *fw,
                                         bool force)
@@ -749,7 +793,7 @@ static int elants_i2c_do_update_firmware(struct i2c_client *client,
        u16 send_id;
        int page, n_fw_pages;
        int error;
-       bool check_remark_id = ts->iap_version >= 0x60;
+       bool check_remark_id = elants_i2c_should_check_remark_id(ts);
 
        /* Recovery mode detection! */
        if (force) {
index b5cc917..aaa3c45 100644 (file)
@@ -102,6 +102,7 @@ static const struct goodix_chip_id goodix_chip_ids[] = {
        { .id = "911", .data = &gt911_chip_data },
        { .id = "9271", .data = &gt911_chip_data },
        { .id = "9110", .data = &gt911_chip_data },
+       { .id = "9111", .data = &gt911_chip_data },
        { .id = "927", .data = &gt911_chip_data },
        { .id = "928", .data = &gt911_chip_data },
 
@@ -650,10 +651,16 @@ int goodix_reset_no_int_sync(struct goodix_ts_data *ts)
 
        usleep_range(6000, 10000);              /* T4: > 5ms */
 
-       /* end select I2C slave addr */
-       error = gpiod_direction_input(ts->gpiod_rst);
-       if (error)
-               goto error;
+       /*
+        * Put the reset pin back in to input / high-impedance mode to save
+        * power. Only do this in the non ACPI case since some ACPI boards
+        * don't have a pull-up, so there the reset pin must stay active-high.
+        */
+       if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_GPIO) {
+               error = gpiod_direction_input(ts->gpiod_rst);
+               if (error)
+                       goto error;
+       }
 
        return 0;
 
@@ -787,6 +794,14 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
                return -EINVAL;
        }
 
+       /*
+        * Normally we put the reset pin in input / high-impedance mode to save
+        * power. But some x86/ACPI boards don't have a pull-up, so for the ACPI
+        * case, leave the pin as is. This results in the pin not being touched
+        * at all on x86/ACPI boards, except when needed for error-recover.
+        */
+       ts->gpiod_rst_flags = GPIOD_ASIS;
+
        return devm_acpi_dev_add_driver_gpios(dev, gpio_mapping);
 }
 #else
@@ -812,6 +827,12 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
                return -EINVAL;
        dev = &ts->client->dev;
 
+       /*
+        * By default we request the reset pin as input, leaving it in
+        * high-impedance when not resetting the controller to save power.
+        */
+       ts->gpiod_rst_flags = GPIOD_IN;
+
        ts->avdd28 = devm_regulator_get(dev, "AVDD28");
        if (IS_ERR(ts->avdd28)) {
                error = PTR_ERR(ts->avdd28);
@@ -849,7 +870,7 @@ retry_get_irq_gpio:
        ts->gpiod_int = gpiod;
 
        /* Get the reset line GPIO pin number */
-       gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_IN);
+       gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, ts->gpiod_rst_flags);
        if (IS_ERR(gpiod)) {
                error = PTR_ERR(gpiod);
                if (error != -EPROBE_DEFER)
index 62138f9..02065d1 100644 (file)
@@ -87,6 +87,7 @@ struct goodix_ts_data {
        struct gpio_desc *gpiod_rst;
        int gpio_count;
        int gpio_int_idx;
+       enum gpiod_flags gpiod_rst_flags;
        char id[GOODIX_ID_MAX_LEN + 1];
        char cfg_name[64];
        u16 version;
index c1e7a24..191d4f3 100644 (file)
@@ -207,7 +207,7 @@ static int goodix_firmware_upload(struct goodix_ts_data *ts)
 
        error = goodix_reset_no_int_sync(ts);
        if (error)
-               return error;
+               goto release;
 
        error = goodix_enter_upload_mode(ts->client);
        if (error)
index 55891e4..a41b4b2 100644 (file)
@@ -381,7 +381,7 @@ mISDNInit(void)
        err = mISDN_inittimer(&debug);
        if (err)
                goto error2;
-       err = l1_init(&debug);
+       err = Isdnl1_Init(&debug);
        if (err)
                goto error3;
        err = Isdnl2_Init(&debug);
@@ -395,7 +395,7 @@ mISDNInit(void)
 error5:
        Isdnl2_cleanup();
 error4:
-       l1_cleanup();
+       Isdnl1_cleanup();
 error3:
        mISDN_timer_cleanup();
 error2:
@@ -408,7 +408,7 @@ static void mISDN_cleanup(void)
 {
        misdn_sock_cleanup();
        Isdnl2_cleanup();
-       l1_cleanup();
+       Isdnl1_cleanup();
        mISDN_timer_cleanup();
        class_unregister(&mISDN_class);
 
index 23b44d3..42599f4 100644 (file)
@@ -60,8 +60,8 @@ struct Bprotocol      *get_Bprotocol4id(u_int);
 extern int     mISDN_inittimer(u_int *);
 extern void    mISDN_timer_cleanup(void);
 
-extern int     l1_init(u_int *);
-extern void    l1_cleanup(void);
+extern int     Isdnl1_Init(u_int *);
+extern void    Isdnl1_cleanup(void);
 extern int     Isdnl2_Init(u_int *);
 extern void    Isdnl2_cleanup(void);
 
index 98a3bc6..7b31c25 100644 (file)
@@ -398,7 +398,7 @@ create_l1(struct dchannel *dch, dchannel_l1callback *dcb) {
 EXPORT_SYMBOL(create_l1);
 
 int
-l1_init(u_int *deb)
+Isdnl1_Init(u_int *deb)
 {
        debug = deb;
        l1fsm_s.state_count = L1S_STATE_COUNT;
@@ -409,7 +409,7 @@ l1_init(u_int *deb)
 }
 
 void
-l1_cleanup(void)
+Isdnl1_cleanup(void)
 {
        mISDN_FsmFree(&l1fsm_s);
 }
index 240c5af..368f104 100644 (file)
@@ -2264,7 +2264,7 @@ void mmc_start_host(struct mmc_host *host)
        _mmc_detect_change(host, 0, false);
 }
 
-void mmc_stop_host(struct mmc_host *host)
+void __mmc_stop_host(struct mmc_host *host)
 {
        if (host->slot.cd_irq >= 0) {
                mmc_gpio_set_cd_wake(host, false);
@@ -2273,6 +2273,11 @@ void mmc_stop_host(struct mmc_host *host)
 
        host->rescan_disable = 1;
        cancel_delayed_work_sync(&host->detect);
+}
+
+void mmc_stop_host(struct mmc_host *host)
+{
+       __mmc_stop_host(host);
 
        /* clear pm flags now and let card drivers set them as needed */
        host->pm_flags = 0;
index 7931a4f..f5f3f62 100644 (file)
@@ -70,6 +70,7 @@ static inline void mmc_delay(unsigned int ms)
 
 void mmc_rescan(struct work_struct *work);
 void mmc_start_host(struct mmc_host *host);
+void __mmc_stop_host(struct mmc_host *host);
 void mmc_stop_host(struct mmc_host *host);
 
 void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
index d4683b1..cf140f4 100644 (file)
@@ -80,9 +80,18 @@ static void mmc_host_classdev_release(struct device *dev)
        kfree(host);
 }
 
+static int mmc_host_classdev_shutdown(struct device *dev)
+{
+       struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+       __mmc_stop_host(host);
+       return 0;
+}
+
 static struct class mmc_host_class = {
        .name           = "mmc_host",
        .dev_release    = mmc_host_classdev_release,
+       .shutdown_pre   = mmc_host_classdev_shutdown,
        .pm             = MMC_HOST_CLASS_DEV_PM_OPS,
 };
 
index 80a2c27..bb612fc 100644 (file)
@@ -1103,17 +1103,17 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __maybe_unused jz4740_mmc_suspend(struct device *dev)
+static int jz4740_mmc_suspend(struct device *dev)
 {
        return pinctrl_pm_select_sleep_state(dev);
 }
 
-static int __maybe_unused jz4740_mmc_resume(struct device *dev)
+static int jz4740_mmc_resume(struct device *dev)
 {
        return pinctrl_select_default_state(dev);
 }
 
-static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
+DEFINE_SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
        jz4740_mmc_resume);
 
 static struct platform_driver jz4740_mmc_driver = {
@@ -1123,7 +1123,7 @@ static struct platform_driver jz4740_mmc_driver = {
                .name = "jz4740-mmc",
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
                .of_match_table = of_match_ptr(jz4740_mmc_of_match),
-               .pm = pm_ptr(&jz4740_mmc_pm_ops),
+               .pm = pm_sleep_ptr(&jz4740_mmc_pm_ops),
        },
 };
 
index 7cd9c0e..8fdd0bb 100644 (file)
@@ -135,6 +135,7 @@ static void meson_mx_sdhc_start_cmd(struct mmc_host *mmc,
                                    struct mmc_command *cmd)
 {
        struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+       bool manual_stop = false;
        u32 ictl, send;
        int pack_len;
 
@@ -172,12 +173,27 @@ static void meson_mx_sdhc_start_cmd(struct mmc_host *mmc,
                else
                        /* software flush: */
                        ictl |= MESON_SDHC_ICTL_DATA_XFER_OK;
+
+               /*
+                * Mimic the logic from the vendor driver where (only)
+                * SD_IO_RW_EXTENDED commands with more than one block set the
+                * MESON_SDHC_MISC_MANUAL_STOP bit. This fixes the firmware
+                * download in the brcmfmac driver for a BCM43362/1 card.
+                * Without this sdio_memcpy_toio() (with a size of 219557
+                * bytes) times out if MESON_SDHC_MISC_MANUAL_STOP is not set.
+                */
+               manual_stop = cmd->data->blocks > 1 &&
+                             cmd->opcode == SD_IO_RW_EXTENDED;
        } else {
                pack_len = 0;
 
                ictl |= MESON_SDHC_ICTL_RESP_OK;
        }
 
+       regmap_update_bits(host->regmap, MESON_SDHC_MISC,
+                          MESON_SDHC_MISC_MANUAL_STOP,
+                          manual_stop ? MESON_SDHC_MISC_MANUAL_STOP : 0);
+
        if (cmd->opcode == MMC_STOP_TRANSMISSION)
                send |= MESON_SDHC_SEND_DATA_STOP;
 
index fdaa11f..a75d3dd 100644 (file)
@@ -441,6 +441,8 @@ static int sdmmc_dlyb_phase_tuning(struct mmci_host *host, u32 opcode)
                return -EINVAL;
        }
 
+       writel_relaxed(0, dlyb->base + DLYB_CR);
+
        phase = end_of_len - max_len / 2;
        sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false);
 
index 2fe6fcd..98c218b 100644 (file)
@@ -1183,7 +1183,6 @@ static int mxcmci_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int mxcmci_suspend(struct device *dev)
 {
        struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -1210,9 +1209,8 @@ static int mxcmci_resume(struct device *dev)
 
        return ret;
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
+DEFINE_SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
 
 static struct platform_driver mxcmci_driver = {
        .probe          = mxcmci_probe,
@@ -1220,7 +1218,7 @@ static struct platform_driver mxcmci_driver = {
        .driver         = {
                .name           = DRIVER_NAME,
                .probe_type     = PROBE_PREFER_ASYNCHRONOUS,
-               .pm     = &mxcmci_pm_ops,
+               .pm     = pm_sleep_ptr(&mxcmci_pm_ops),
                .of_match_table = mxcmci_of_match,
        }
 };
index a500187..9762ffa 100644 (file)
@@ -356,23 +356,6 @@ static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap)
        }
 }
 
-static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc,
-                                             struct mmc_ios *ios)
-{
-       struct sdhci_host *host = mmc_priv(mmc);
-       u32 val;
-
-       val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
-
-       if (ios->enhanced_strobe)
-               val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
-       else
-               val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
-
-       sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
-
-}
-
 static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -793,6 +776,32 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
        }
 }
 
+static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc,
+                                             struct mmc_ios *ios)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+       u32 val;
+
+       val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
+
+       if (ios->enhanced_strobe) {
+               val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
+               /*
+                * When CMD13 is sent from mmc_select_hs400es() after
+                * switching to HS400ES mode, the bus is operating at
+                * either MMC_HIGH_26_MAX_DTR or MMC_HIGH_52_MAX_DTR.
+                * To meet Tegra SDHCI requirement at HS400ES mode, force SDHCI
+                * interface clock to MMC_HS200_MAX_DTR (200 MHz) so that host
+                * controller CAR clock and the interface clock are rate matched.
+                */
+               tegra_sdhci_set_clock(host, MMC_HS200_MAX_DTR);
+       } else {
+               val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
+       }
+
+       sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
+}
+
 static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
index a8fde3b..b93337b 100644 (file)
@@ -1526,7 +1526,7 @@ static int bond_option_ad_actor_system_set(struct bonding *bond,
                mac = (u8 *)&newval->value;
        }
 
-       if (!is_valid_ether_addr(mac))
+       if (is_multicast_ether_addr(mac))
                goto err;
 
        netdev_dbg(bond->dev, "Setting ad_actor_system to %pM\n", mac);
index 81b3756..77e76c9 100644 (file)
@@ -366,6 +366,10 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
                if (!buff->is_eop) {
                        buff_ = buff;
                        do {
+                               if (buff_->next >= self->size) {
+                                       err = -EIO;
+                                       goto err_exit;
+                               }
                                next_ = buff_->next,
                                buff_ = &self->buff_ring[next_];
                                is_rsc_completed =
@@ -389,6 +393,10 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
                            (buff->is_lro && buff->is_cso_err)) {
                                buff_ = buff;
                                do {
+                                       if (buff_->next >= self->size) {
+                                               err = -EIO;
+                                               goto err_exit;
+                                       }
                                        next_ = buff_->next,
                                        buff_ = &self->buff_ring[next_];
 
index 88d2ab7..4579ddf 100644 (file)
@@ -1913,15 +1913,12 @@ static int ag71xx_probe(struct platform_device *pdev)
        ag->mac_reset = devm_reset_control_get(&pdev->dev, "mac");
        if (IS_ERR(ag->mac_reset)) {
                netif_err(ag, probe, ndev, "missing mac reset\n");
-               err = PTR_ERR(ag->mac_reset);
-               goto err_free;
+               return PTR_ERR(ag->mac_reset);
        }
 
        ag->mac_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-       if (!ag->mac_base) {
-               err = -ENOMEM;
-               goto err_free;
-       }
+       if (!ag->mac_base)
+               return -ENOMEM;
 
        ndev->irq = platform_get_irq(pdev, 0);
        err = devm_request_irq(&pdev->dev, ndev->irq, ag71xx_interrupt,
@@ -1929,7 +1926,7 @@ static int ag71xx_probe(struct platform_device *pdev)
        if (err) {
                netif_err(ag, probe, ndev, "unable to request IRQ %d\n",
                          ndev->irq);
-               goto err_free;
+               return err;
        }
 
        ndev->netdev_ops = &ag71xx_netdev_ops;
@@ -1957,10 +1954,8 @@ static int ag71xx_probe(struct platform_device *pdev)
        ag->stop_desc = dmam_alloc_coherent(&pdev->dev,
                                            sizeof(struct ag71xx_desc),
                                            &ag->stop_desc_dma, GFP_KERNEL);
-       if (!ag->stop_desc) {
-               err = -ENOMEM;
-               goto err_free;
-       }
+       if (!ag->stop_desc)
+               return -ENOMEM;
 
        ag->stop_desc->data = 0;
        ag->stop_desc->ctrl = 0;
@@ -1975,7 +1970,7 @@ static int ag71xx_probe(struct platform_device *pdev)
        err = of_get_phy_mode(np, &ag->phy_if_mode);
        if (err) {
                netif_err(ag, probe, ndev, "missing phy-mode property in DT\n");
-               goto err_free;
+               return err;
        }
 
        netif_napi_add(ndev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT);
@@ -1983,7 +1978,7 @@ static int ag71xx_probe(struct platform_device *pdev)
        err = clk_prepare_enable(ag->clk_eth);
        if (err) {
                netif_err(ag, probe, ndev, "Failed to enable eth clk.\n");
-               goto err_free;
+               return err;
        }
 
        ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, 0);
@@ -2019,8 +2014,6 @@ err_mdio_remove:
        ag71xx_mdio_remove(ag);
 err_put_clk:
        clk_disable_unprepare(ag->clk_eth);
-err_free:
-       free_netdev(ndev);
        return err;
 }
 
index d9baac0..4c9d05c 100644 (file)
@@ -1805,7 +1805,7 @@ static int fman_port_probe(struct platform_device *of_dev)
        fman = dev_get_drvdata(&fm_pdev->dev);
        if (!fman) {
                err = -EINVAL;
-               goto return_err;
+               goto put_device;
        }
 
        err = of_property_read_u32(port_node, "cell-index", &val);
@@ -1813,7 +1813,7 @@ static int fman_port_probe(struct platform_device *of_dev)
                dev_err(port->dev, "%s: reading cell-index for %pOF failed\n",
                        __func__, port_node);
                err = -EINVAL;
-               goto return_err;
+               goto put_device;
        }
        port_id = (u8)val;
        port->dts_params.id = port_id;
@@ -1847,7 +1847,7 @@ static int fman_port_probe(struct platform_device *of_dev)
        }  else {
                dev_err(port->dev, "%s: Illegal port type\n", __func__);
                err = -EINVAL;
-               goto return_err;
+               goto put_device;
        }
 
        port->dts_params.type = port_type;
@@ -1861,7 +1861,7 @@ static int fman_port_probe(struct platform_device *of_dev)
                        dev_err(port->dev, "%s: incorrect qman-channel-id\n",
                                __func__);
                        err = -EINVAL;
-                       goto return_err;
+                       goto put_device;
                }
                port->dts_params.qman_channel_id = qman_channel_id;
        }
@@ -1871,7 +1871,7 @@ static int fman_port_probe(struct platform_device *of_dev)
                dev_err(port->dev, "%s: of_address_to_resource() failed\n",
                        __func__);
                err = -ENOMEM;
-               goto return_err;
+               goto put_device;
        }
 
        port->dts_params.fman = fman;
@@ -1896,6 +1896,8 @@ static int fman_port_probe(struct platform_device *of_dev)
 
        return 0;
 
+put_device:
+       put_device(&fm_pdev->dev);
 return_err:
        of_node_put(port_node);
 free_port:
index 83ae56c..326b56b 100644 (file)
@@ -738,10 +738,7 @@ int gve_adminq_describe_device(struct gve_priv *priv)
         * is not set to GqiRda, choose the queue format in a priority order:
         * DqoRda, GqiRda, GqiQpl. Use GqiQpl as default.
         */
-       if (priv->queue_format == GVE_GQI_RDA_FORMAT) {
-               dev_info(&priv->pdev->dev,
-                        "Driver is running with GQI RDA queue format.\n");
-       } else if (dev_op_dqo_rda) {
+       if (dev_op_dqo_rda) {
                priv->queue_format = GVE_DQO_RDA_FORMAT;
                dev_info(&priv->pdev->dev,
                         "Driver is running with DQO RDA queue format.\n");
@@ -753,6 +750,9 @@ int gve_adminq_describe_device(struct gve_priv *priv)
                         "Driver is running with GQI RDA queue format.\n");
                supported_features_mask =
                        be32_to_cpu(dev_op_gqi_rda->supported_features_mask);
+       } else if (priv->queue_format == GVE_GQI_RDA_FORMAT) {
+               dev_info(&priv->pdev->dev,
+                        "Driver is running with GQI RDA queue format.\n");
        } else {
                priv->queue_format = GVE_GQI_QPL_FORMAT;
                if (dev_op_gqi_qpl)
index 1efc635..fafe020 100644 (file)
@@ -6,6 +6,18 @@
 #include "ice_lib.h"
 #include "ice_dcb_lib.h"
 
+static bool ice_alloc_rx_buf_zc(struct ice_rx_ring *rx_ring)
+{
+       rx_ring->xdp_buf = kcalloc(rx_ring->count, sizeof(*rx_ring->xdp_buf), GFP_KERNEL);
+       return !!rx_ring->xdp_buf;
+}
+
+static bool ice_alloc_rx_buf(struct ice_rx_ring *rx_ring)
+{
+       rx_ring->rx_buf = kcalloc(rx_ring->count, sizeof(*rx_ring->rx_buf), GFP_KERNEL);
+       return !!rx_ring->rx_buf;
+}
+
 /**
  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
@@ -492,8 +504,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
                        xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
                                         ring->q_index, ring->q_vector->napi.napi_id);
 
+               kfree(ring->rx_buf);
                ring->xsk_pool = ice_xsk_pool(ring);
                if (ring->xsk_pool) {
+                       if (!ice_alloc_rx_buf_zc(ring))
+                               return -ENOMEM;
                        xdp_rxq_info_unreg_mem_model(&ring->xdp_rxq);
 
                        ring->rx_buf_len =
@@ -508,6 +523,8 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
                        dev_info(dev, "Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx ring %d\n",
                                 ring->q_index);
                } else {
+                       if (!ice_alloc_rx_buf(ring))
+                               return -ENOMEM;
                        if (!xdp_rxq_info_is_reg(&ring->xdp_rxq))
                                /* coverity[check_return] */
                                xdp_rxq_info_reg(&ring->xdp_rxq,
index bc3ba19..dccf09e 100644 (file)
@@ -419,7 +419,10 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
        }
 
 rx_skip_free:
-       memset(rx_ring->rx_buf, 0, sizeof(*rx_ring->rx_buf) * rx_ring->count);
+       if (rx_ring->xsk_pool)
+               memset(rx_ring->xdp_buf, 0, array_size(rx_ring->count, sizeof(*rx_ring->xdp_buf)));
+       else
+               memset(rx_ring->rx_buf, 0, array_size(rx_ring->count, sizeof(*rx_ring->rx_buf)));
 
        /* Zero out the descriptor ring */
        size = ALIGN(rx_ring->count * sizeof(union ice_32byte_rx_desc),
@@ -446,8 +449,13 @@ void ice_free_rx_ring(struct ice_rx_ring *rx_ring)
                if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq))
                        xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
        rx_ring->xdp_prog = NULL;
-       devm_kfree(rx_ring->dev, rx_ring->rx_buf);
-       rx_ring->rx_buf = NULL;
+       if (rx_ring->xsk_pool) {
+               kfree(rx_ring->xdp_buf);
+               rx_ring->xdp_buf = NULL;
+       } else {
+               kfree(rx_ring->rx_buf);
+               rx_ring->rx_buf = NULL;
+       }
 
        if (rx_ring->desc) {
                size = ALIGN(rx_ring->count * sizeof(union ice_32byte_rx_desc),
@@ -475,8 +483,7 @@ int ice_setup_rx_ring(struct ice_rx_ring *rx_ring)
        /* warn if we are about to overwrite the pointer */
        WARN_ON(rx_ring->rx_buf);
        rx_ring->rx_buf =
-               devm_kcalloc(dev, sizeof(*rx_ring->rx_buf), rx_ring->count,
-                            GFP_KERNEL);
+               kcalloc(rx_ring->count, sizeof(*rx_ring->rx_buf), GFP_KERNEL);
        if (!rx_ring->rx_buf)
                return -ENOMEM;
 
@@ -505,7 +512,7 @@ int ice_setup_rx_ring(struct ice_rx_ring *rx_ring)
        return 0;
 
 err:
-       devm_kfree(dev, rx_ring->rx_buf);
+       kfree(rx_ring->rx_buf);
        rx_ring->rx_buf = NULL;
        return -ENOMEM;
 }
index c56dd17..b7b3bd4 100644 (file)
@@ -24,7 +24,6 @@
 #define ICE_MAX_DATA_PER_TXD_ALIGNED \
        (~(ICE_MAX_READ_REQ_SIZE - 1) & ICE_MAX_DATA_PER_TXD)
 
-#define ICE_RX_BUF_WRITE       16      /* Must be power of 2 */
 #define ICE_MAX_TXQ_PER_TXQG   128
 
 /* Attempt to maximize the headroom available for incoming frames. We use a 2K
index bb9a808..c895351 100644 (file)
 #include "ice_txrx_lib.h"
 #include "ice_lib.h"
 
+static struct xdp_buff **ice_xdp_buf(struct ice_rx_ring *rx_ring, u32 idx)
+{
+       return &rx_ring->xdp_buf[idx];
+}
+
 /**
  * ice_qp_reset_stats - Resets all stats for rings of given index
  * @vsi: VSI that contains rings of interest
@@ -372,7 +377,7 @@ bool ice_alloc_rx_bufs_zc(struct ice_rx_ring *rx_ring, u16 count)
        dma_addr_t dma;
 
        rx_desc = ICE_RX_DESC(rx_ring, ntu);
-       xdp = &rx_ring->xdp_buf[ntu];
+       xdp = ice_xdp_buf(rx_ring, ntu);
 
        nb_buffs = min_t(u16, count, rx_ring->count - ntu);
        nb_buffs = xsk_buff_alloc_batch(rx_ring->xsk_pool, xdp, nb_buffs);
@@ -390,14 +395,9 @@ bool ice_alloc_rx_bufs_zc(struct ice_rx_ring *rx_ring, u16 count)
        }
 
        ntu += nb_buffs;
-       if (ntu == rx_ring->count) {
-               rx_desc = ICE_RX_DESC(rx_ring, 0);
-               xdp = rx_ring->xdp_buf;
+       if (ntu == rx_ring->count)
                ntu = 0;
-       }
 
-       /* clear the status bits for the next_to_use descriptor */
-       rx_desc->wb.status_error0 = 0;
        ice_release_rx_desc(rx_ring, ntu);
 
        return count == nb_buffs;
@@ -419,19 +419,18 @@ static void ice_bump_ntc(struct ice_rx_ring *rx_ring)
 /**
  * ice_construct_skb_zc - Create an sk_buff from zero-copy buffer
  * @rx_ring: Rx ring
- * @xdp_arr: Pointer to the SW ring of xdp_buff pointers
+ * @xdp: Pointer to XDP buffer
  *
  * This function allocates a new skb from a zero-copy Rx buffer.
  *
  * Returns the skb on success, NULL on failure.
  */
 static struct sk_buff *
-ice_construct_skb_zc(struct ice_rx_ring *rx_ring, struct xdp_buff **xdp_arr)
+ice_construct_skb_zc(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp)
 {
-       struct xdp_buff *xdp = *xdp_arr;
+       unsigned int datasize_hard = xdp->data_end - xdp->data_hard_start;
        unsigned int metasize = xdp->data - xdp->data_meta;
        unsigned int datasize = xdp->data_end - xdp->data;
-       unsigned int datasize_hard = xdp->data_end - xdp->data_hard_start;
        struct sk_buff *skb;
 
        skb = __napi_alloc_skb(&rx_ring->q_vector->napi, datasize_hard,
@@ -445,7 +444,6 @@ ice_construct_skb_zc(struct ice_rx_ring *rx_ring, struct xdp_buff **xdp_arr)
                skb_metadata_set(skb, metasize);
 
        xsk_buff_free(xdp);
-       *xdp_arr = NULL;
        return skb;
 }
 
@@ -507,7 +505,6 @@ out_failure:
 int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)
 {
        unsigned int total_rx_bytes = 0, total_rx_packets = 0;
-       u16 cleaned_count = ICE_DESC_UNUSED(rx_ring);
        struct ice_tx_ring *xdp_ring;
        unsigned int xdp_xmit = 0;
        struct bpf_prog *xdp_prog;
@@ -522,7 +519,7 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)
        while (likely(total_rx_packets < (unsigned int)budget)) {
                union ice_32b_rx_flex_desc *rx_desc;
                unsigned int size, xdp_res = 0;
-               struct xdp_buff **xdp;
+               struct xdp_buff *xdp;
                struct sk_buff *skb;
                u16 stat_err_bits;
                u16 vlan_tag = 0;
@@ -540,31 +537,35 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)
                 */
                dma_rmb();
 
+               xdp = *ice_xdp_buf(rx_ring, rx_ring->next_to_clean);
+
                size = le16_to_cpu(rx_desc->wb.pkt_len) &
                                   ICE_RX_FLX_DESC_PKT_LEN_M;
-               if (!size)
-                       break;
+               if (!size) {
+                       xdp->data = NULL;
+                       xdp->data_end = NULL;
+                       xdp->data_hard_start = NULL;
+                       xdp->data_meta = NULL;
+                       goto construct_skb;
+               }
 
-               xdp = &rx_ring->xdp_buf[rx_ring->next_to_clean];
-               xsk_buff_set_size(*xdp, size);
-               xsk_buff_dma_sync_for_cpu(*xdp, rx_ring->xsk_pool);
+               xsk_buff_set_size(xdp, size);
+               xsk_buff_dma_sync_for_cpu(xdp, rx_ring->xsk_pool);
 
-               xdp_res = ice_run_xdp_zc(rx_ring, *xdp, xdp_prog, xdp_ring);
+               xdp_res = ice_run_xdp_zc(rx_ring, xdp, xdp_prog, xdp_ring);
                if (xdp_res) {
                        if (xdp_res & (ICE_XDP_TX | ICE_XDP_REDIR))
                                xdp_xmit |= xdp_res;
                        else
-                               xsk_buff_free(*xdp);
+                               xsk_buff_free(xdp);
 
-                       *xdp = NULL;
                        total_rx_bytes += size;
                        total_rx_packets++;
-                       cleaned_count++;
 
                        ice_bump_ntc(rx_ring);
                        continue;
                }
-
+construct_skb:
                /* XDP_PASS path */
                skb = ice_construct_skb_zc(rx_ring, xdp);
                if (!skb) {
@@ -572,7 +573,6 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)
                        break;
                }
 
-               cleaned_count++;
                ice_bump_ntc(rx_ring);
 
                if (eth_skb_pad(skb)) {
@@ -594,8 +594,7 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)
                ice_receive_skb(rx_ring, skb, vlan_tag);
        }
 
-       if (cleaned_count >= ICE_RX_BUF_WRITE)
-               failure = !ice_alloc_rx_bufs_zc(rx_ring, cleaned_count);
+       failure = !ice_alloc_rx_bufs_zc(rx_ring, ICE_DESC_UNUSED(rx_ring));
 
        ice_finalize_xdp_rx(xdp_ring, xdp_xmit);
        ice_update_rx_ring_stats(rx_ring, total_rx_packets, total_rx_bytes);
@@ -811,15 +810,14 @@ bool ice_xsk_any_rx_ring_ena(struct ice_vsi *vsi)
  */
 void ice_xsk_clean_rx_ring(struct ice_rx_ring *rx_ring)
 {
-       u16 i;
-
-       for (i = 0; i < rx_ring->count; i++) {
-               struct xdp_buff **xdp = &rx_ring->xdp_buf[i];
+       u16 count_mask = rx_ring->count - 1;
+       u16 ntc = rx_ring->next_to_clean;
+       u16 ntu = rx_ring->next_to_use;
 
-               if (!xdp)
-                       continue;
+       for ( ; ntc != ntu; ntc = (ntc + 1) & count_mask) {
+               struct xdp_buff *xdp = *ice_xdp_buf(rx_ring, ntc);
 
-               *xdp = NULL;
+               xsk_buff_free(xdp);
        }
 }
 
index b597b8b..446894d 100644 (file)
@@ -9254,7 +9254,7 @@ static int __maybe_unused igb_suspend(struct device *dev)
        return __igb_shutdown(to_pci_dev(dev), NULL, 0);
 }
 
-static int __maybe_unused igb_resume(struct device *dev)
+static int __maybe_unused __igb_resume(struct device *dev, bool rpm)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct net_device *netdev = pci_get_drvdata(pdev);
@@ -9297,17 +9297,24 @@ static int __maybe_unused igb_resume(struct device *dev)
 
        wr32(E1000_WUS, ~0);
 
-       rtnl_lock();
+       if (!rpm)
+               rtnl_lock();
        if (!err && netif_running(netdev))
                err = __igb_open(netdev, true);
 
        if (!err)
                netif_device_attach(netdev);
-       rtnl_unlock();
+       if (!rpm)
+               rtnl_unlock();
 
        return err;
 }
 
+static int __maybe_unused igb_resume(struct device *dev)
+{
+       return __igb_resume(dev, false);
+}
+
 static int __maybe_unused igb_runtime_idle(struct device *dev)
 {
        struct net_device *netdev = dev_get_drvdata(dev);
@@ -9326,7 +9333,7 @@ static int __maybe_unused igb_runtime_suspend(struct device *dev)
 
 static int __maybe_unused igb_runtime_resume(struct device *dev)
 {
-       return igb_resume(dev);
+       return __igb_resume(dev, true);
 }
 
 static void igb_shutdown(struct pci_dev *pdev)
@@ -9442,7 +9449,7 @@ static pci_ers_result_t igb_io_error_detected(struct pci_dev *pdev,
  *  @pdev: Pointer to PCI device
  *
  *  Restart the card from scratch, as if from a cold-boot. Implementation
- *  resembles the first-half of the igb_resume routine.
+ *  resembles the first-half of the __igb_resume routine.
  **/
 static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev)
 {
@@ -9482,7 +9489,7 @@ static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev)
  *
  *  This callback is called when the error recovery driver tells us that
  *  its OK to resume normal operation. Implementation resembles the
- *  second-half of the igb_resume routine.
+ *  second-half of the __igb_resume routine.
  */
 static void igb_io_resume(struct pci_dev *pdev)
 {
index 8e44828..d28a80a 100644 (file)
@@ -5467,6 +5467,9 @@ static irqreturn_t igc_intr_msi(int irq, void *data)
                        mod_timer(&adapter->watchdog_timer, jiffies + 1);
        }
 
+       if (icr & IGC_ICR_TS)
+               igc_tsync_interrupt(adapter);
+
        napi_schedule(&q_vector->napi);
 
        return IRQ_HANDLED;
@@ -5510,6 +5513,9 @@ static irqreturn_t igc_intr(int irq, void *data)
                        mod_timer(&adapter->watchdog_timer, jiffies + 1);
        }
 
+       if (icr & IGC_ICR_TS)
+               igc_tsync_interrupt(adapter);
+
        napi_schedule(&q_vector->napi);
 
        return IRQ_HANDLED;
index 30568e3..4f9245a 100644 (file)
@@ -768,7 +768,20 @@ int igc_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr)
  */
 static bool igc_is_crosststamp_supported(struct igc_adapter *adapter)
 {
-       return IS_ENABLED(CONFIG_X86_TSC) ? pcie_ptm_enabled(adapter->pdev) : false;
+       if (!IS_ENABLED(CONFIG_X86_TSC))
+               return false;
+
+       /* FIXME: it was noticed that enabling support for PCIe PTM in
+        * some i225-V models could cause lockups when bringing the
+        * interface up/down. There should be no downsides to
+        * disabling crosstimestamping support for i225-V, as it
+        * doesn't have any PTP support. That way we gain some time
+        * while root causing the issue.
+        */
+       if (adapter->pdev->device == IGC_DEV_ID_I225_V)
+               return false;
+
+       return pcie_ptm_enabled(adapter->pdev);
 }
 
 static struct system_counterval_t igc_device_tstamp_to_system(u64 tstamp)
index 0da09ea..80bfaf2 100644 (file)
@@ -71,6 +71,8 @@ struct xrx200_priv {
        struct xrx200_chan chan_tx;
        struct xrx200_chan chan_rx;
 
+       u16 rx_buf_size;
+
        struct net_device *net_dev;
        struct device *dev;
 
@@ -97,6 +99,16 @@ static void xrx200_pmac_mask(struct xrx200_priv *priv, u32 clear, u32 set,
        xrx200_pmac_w32(priv, val, offset);
 }
 
+static int xrx200_max_frame_len(int mtu)
+{
+       return VLAN_ETH_HLEN + mtu;
+}
+
+static int xrx200_buffer_size(int mtu)
+{
+       return round_up(xrx200_max_frame_len(mtu), 4 * XRX200_DMA_BURST_LEN);
+}
+
 /* drop all the packets from the DMA ring */
 static void xrx200_flush_dma(struct xrx200_chan *ch)
 {
@@ -109,8 +121,7 @@ static void xrx200_flush_dma(struct xrx200_chan *ch)
                        break;
 
                desc->ctl = LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
-                           (ch->priv->net_dev->mtu + VLAN_ETH_HLEN +
-                            ETH_FCS_LEN);
+                           ch->priv->rx_buf_size;
                ch->dma.desc++;
                ch->dma.desc %= LTQ_DESC_NUM;
        }
@@ -158,21 +169,21 @@ static int xrx200_close(struct net_device *net_dev)
 
 static int xrx200_alloc_skb(struct xrx200_chan *ch)
 {
-       int len = ch->priv->net_dev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
        struct sk_buff *skb = ch->skb[ch->dma.desc];
+       struct xrx200_priv *priv = ch->priv;
        dma_addr_t mapping;
        int ret = 0;
 
-       ch->skb[ch->dma.desc] = netdev_alloc_skb_ip_align(ch->priv->net_dev,
-                                                         len);
+       ch->skb[ch->dma.desc] = netdev_alloc_skb_ip_align(priv->net_dev,
+                                                         priv->rx_buf_size);
        if (!ch->skb[ch->dma.desc]) {
                ret = -ENOMEM;
                goto skip;
        }
 
-       mapping = dma_map_single(ch->priv->dev, ch->skb[ch->dma.desc]->data,
-                                len, DMA_FROM_DEVICE);
-       if (unlikely(dma_mapping_error(ch->priv->dev, mapping))) {
+       mapping = dma_map_single(priv->dev, ch->skb[ch->dma.desc]->data,
+                                priv->rx_buf_size, DMA_FROM_DEVICE);
+       if (unlikely(dma_mapping_error(priv->dev, mapping))) {
                dev_kfree_skb_any(ch->skb[ch->dma.desc]);
                ch->skb[ch->dma.desc] = skb;
                ret = -ENOMEM;
@@ -184,7 +195,7 @@ static int xrx200_alloc_skb(struct xrx200_chan *ch)
        wmb();
 skip:
        ch->dma.desc_base[ch->dma.desc].ctl =
-               LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) | len;
+               LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) | priv->rx_buf_size;
 
        return ret;
 }
@@ -213,7 +224,7 @@ static int xrx200_hw_receive(struct xrx200_chan *ch)
        skb->protocol = eth_type_trans(skb, net_dev);
        netif_receive_skb(skb);
        net_dev->stats.rx_packets++;
-       net_dev->stats.rx_bytes += len - ETH_FCS_LEN;
+       net_dev->stats.rx_bytes += len;
 
        return 0;
 }
@@ -356,6 +367,7 @@ xrx200_change_mtu(struct net_device *net_dev, int new_mtu)
        int ret = 0;
 
        net_dev->mtu = new_mtu;
+       priv->rx_buf_size = xrx200_buffer_size(new_mtu);
 
        if (new_mtu <= old_mtu)
                return ret;
@@ -375,6 +387,7 @@ xrx200_change_mtu(struct net_device *net_dev, int new_mtu)
                ret = xrx200_alloc_skb(ch_rx);
                if (ret) {
                        net_dev->mtu = old_mtu;
+                       priv->rx_buf_size = xrx200_buffer_size(old_mtu);
                        break;
                }
                dev_kfree_skb_any(skb);
@@ -505,7 +518,8 @@ static int xrx200_probe(struct platform_device *pdev)
        net_dev->netdev_ops = &xrx200_netdev_ops;
        SET_NETDEV_DEV(net_dev, dev);
        net_dev->min_mtu = ETH_ZLEN;
-       net_dev->max_mtu = XRX200_DMA_DATA_LEN - VLAN_ETH_HLEN - ETH_FCS_LEN;
+       net_dev->max_mtu = XRX200_DMA_DATA_LEN - xrx200_max_frame_len(0);
+       priv->rx_buf_size = xrx200_buffer_size(ETH_DATA_LEN);
 
        /* load the memory ranges */
        priv->pmac_reg = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
index 4369a3f..c687dc9 100644 (file)
@@ -54,12 +54,14 @@ int prestera_port_pvid_set(struct prestera_port *port, u16 vid)
 struct prestera_port *prestera_port_find_by_hwid(struct prestera_switch *sw,
                                                 u32 dev_id, u32 hw_id)
 {
-       struct prestera_port *port = NULL;
+       struct prestera_port *port = NULL, *tmp;
 
        read_lock(&sw->port_list_lock);
-       list_for_each_entry(port, &sw->port_list, list) {
-               if (port->dev_id == dev_id && port->hw_id == hw_id)
+       list_for_each_entry(tmp, &sw->port_list, list) {
+               if (tmp->dev_id == dev_id && tmp->hw_id == hw_id) {
+                       port = tmp;
                        break;
+               }
        }
        read_unlock(&sw->port_list_lock);
 
@@ -68,12 +70,14 @@ struct prestera_port *prestera_port_find_by_hwid(struct prestera_switch *sw,
 
 struct prestera_port *prestera_find_port(struct prestera_switch *sw, u32 id)
 {
-       struct prestera_port *port = NULL;
+       struct prestera_port *port = NULL, *tmp;
 
        read_lock(&sw->port_list_lock);
-       list_for_each_entry(port, &sw->port_list, list) {
-               if (port->id == id)
+       list_for_each_entry(tmp, &sw->port_list, list) {
+               if (tmp->id == id) {
+                       port = tmp;
                        break;
+               }
        }
        read_unlock(&sw->port_list_lock);
 
@@ -764,23 +768,27 @@ static int prestera_netdev_port_event(struct net_device *lower,
                                      struct net_device *dev,
                                      unsigned long event, void *ptr)
 {
-       struct netdev_notifier_changeupper_info *info = ptr;
+       struct netdev_notifier_info *info = ptr;
+       struct netdev_notifier_changeupper_info *cu_info;
        struct prestera_port *port = netdev_priv(dev);
        struct netlink_ext_ack *extack;
        struct net_device *upper;
 
-       extack = netdev_notifier_info_to_extack(&info->info);
-       upper = info->upper_dev;
+       extack = netdev_notifier_info_to_extack(info);
+       cu_info = container_of(info,
+                              struct netdev_notifier_changeupper_info,
+                              info);
 
        switch (event) {
        case NETDEV_PRECHANGEUPPER:
+               upper = cu_info->upper_dev;
                if (!netif_is_bridge_master(upper) &&
                    !netif_is_lag_master(upper)) {
                        NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
                        return -EINVAL;
                }
 
-               if (!info->linking)
+               if (!cu_info->linking)
                        break;
 
                if (netdev_has_any_upper_dev(upper)) {
@@ -789,7 +797,7 @@ static int prestera_netdev_port_event(struct net_device *lower,
                }
 
                if (netif_is_lag_master(upper) &&
-                   !prestera_lag_master_check(upper, info->upper_info, extack))
+                   !prestera_lag_master_check(upper, cu_info->upper_info, extack))
                        return -EOPNOTSUPP;
                if (netif_is_lag_master(upper) && vlan_uses_dev(dev)) {
                        NL_SET_ERR_MSG_MOD(extack,
@@ -805,14 +813,15 @@ static int prestera_netdev_port_event(struct net_device *lower,
                break;
 
        case NETDEV_CHANGEUPPER:
+               upper = cu_info->upper_dev;
                if (netif_is_bridge_master(upper)) {
-                       if (info->linking)
+                       if (cu_info->linking)
                                return prestera_bridge_port_join(upper, port,
                                                                 extack);
                        else
                                prestera_bridge_port_leave(upper, port);
                } else if (netif_is_lag_master(upper)) {
-                       if (info->linking)
+                       if (cu_info->linking)
                                return prestera_lag_port_add(port, upper);
                        else
                                prestera_lag_port_del(port);
index f0ac6b0..b47a0d3 100644 (file)
@@ -783,6 +783,8 @@ struct mlx5e_channel {
        DECLARE_BITMAP(state, MLX5E_CHANNEL_NUM_STATES);
        int                        ix;
        int                        cpu;
+       /* Sync between icosq recovery and XSK enable/disable. */
+       struct mutex               icosq_recovery_lock;
 };
 
 struct mlx5e_ptp;
@@ -1014,9 +1016,6 @@ int mlx5e_create_rq(struct mlx5e_rq *rq, struct mlx5e_rq_param *param);
 void mlx5e_destroy_rq(struct mlx5e_rq *rq);
 
 struct mlx5e_sq_param;
-int mlx5e_open_icosq(struct mlx5e_channel *c, struct mlx5e_params *params,
-                    struct mlx5e_sq_param *param, struct mlx5e_icosq *sq);
-void mlx5e_close_icosq(struct mlx5e_icosq *sq);
 int mlx5e_open_xdpsq(struct mlx5e_channel *c, struct mlx5e_params *params,
                     struct mlx5e_sq_param *param, struct xsk_buff_pool *xsk_pool,
                     struct mlx5e_xdpsq *sq, bool is_redirect);
index d5b7110..0107e4e 100644 (file)
@@ -30,6 +30,8 @@ void mlx5e_reporter_rx_destroy(struct mlx5e_priv *priv);
 void mlx5e_reporter_icosq_cqe_err(struct mlx5e_icosq *icosq);
 void mlx5e_reporter_rq_cqe_err(struct mlx5e_rq *rq);
 void mlx5e_reporter_rx_timeout(struct mlx5e_rq *rq);
+void mlx5e_reporter_icosq_suspend_recovery(struct mlx5e_channel *c);
+void mlx5e_reporter_icosq_resume_recovery(struct mlx5e_channel *c);
 
 #define MLX5E_REPORTER_PER_Q_MAX_LEN 256
 
index d6c7c81..7c9dd3a 100644 (file)
@@ -66,7 +66,7 @@ mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
 
 static inline void
 mlx5e_rep_tc_receive(struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq,
-                    struct sk_buff *skb) {}
+                    struct sk_buff *skb) { napi_gro_receive(rq->cq.napi, skb); }
 
 #endif /* CONFIG_MLX5_CLS_ACT */
 
index 74086eb..2684e9d 100644 (file)
@@ -62,6 +62,7 @@ static void mlx5e_reset_icosq_cc_pc(struct mlx5e_icosq *icosq)
 
 static int mlx5e_rx_reporter_err_icosq_cqe_recover(void *ctx)
 {
+       struct mlx5e_rq *xskrq = NULL;
        struct mlx5_core_dev *mdev;
        struct mlx5e_icosq *icosq;
        struct net_device *dev;
@@ -70,7 +71,13 @@ static int mlx5e_rx_reporter_err_icosq_cqe_recover(void *ctx)
        int err;
 
        icosq = ctx;
+
+       mutex_lock(&icosq->channel->icosq_recovery_lock);
+
+       /* mlx5e_close_rq cancels this work before RQ and ICOSQ are killed. */
        rq = &icosq->channel->rq;
+       if (test_bit(MLX5E_RQ_STATE_ENABLED, &icosq->channel->xskrq.state))
+               xskrq = &icosq->channel->xskrq;
        mdev = icosq->channel->mdev;
        dev = icosq->channel->netdev;
        err = mlx5_core_query_sq_state(mdev, icosq->sqn, &state);
@@ -84,6 +91,9 @@ static int mlx5e_rx_reporter_err_icosq_cqe_recover(void *ctx)
                goto out;
 
        mlx5e_deactivate_rq(rq);
+       if (xskrq)
+               mlx5e_deactivate_rq(xskrq);
+
        err = mlx5e_wait_for_icosq_flush(icosq);
        if (err)
                goto out;
@@ -97,15 +107,28 @@ static int mlx5e_rx_reporter_err_icosq_cqe_recover(void *ctx)
                goto out;
 
        mlx5e_reset_icosq_cc_pc(icosq);
+
        mlx5e_free_rx_in_progress_descs(rq);
+       if (xskrq)
+               mlx5e_free_rx_in_progress_descs(xskrq);
+
        clear_bit(MLX5E_SQ_STATE_RECOVERING, &icosq->state);
        mlx5e_activate_icosq(icosq);
-       mlx5e_activate_rq(rq);
 
+       mlx5e_activate_rq(rq);
        rq->stats->recover++;
+
+       if (xskrq) {
+               mlx5e_activate_rq(xskrq);
+               xskrq->stats->recover++;
+       }
+
+       mutex_unlock(&icosq->channel->icosq_recovery_lock);
+
        return 0;
 out:
        clear_bit(MLX5E_SQ_STATE_RECOVERING, &icosq->state);
+       mutex_unlock(&icosq->channel->icosq_recovery_lock);
        return err;
 }
 
@@ -706,6 +729,16 @@ void mlx5e_reporter_icosq_cqe_err(struct mlx5e_icosq *icosq)
        mlx5e_health_report(priv, priv->rx_reporter, err_str, &err_ctx);
 }
 
+void mlx5e_reporter_icosq_suspend_recovery(struct mlx5e_channel *c)
+{
+       mutex_lock(&c->icosq_recovery_lock);
+}
+
+void mlx5e_reporter_icosq_resume_recovery(struct mlx5e_channel *c)
+{
+       mutex_unlock(&c->icosq_recovery_lock);
+}
+
 static const struct devlink_health_reporter_ops mlx5_rx_reporter_ops = {
        .name = "rx",
        .recover = mlx5e_rx_reporter_recover,
index 4f4bc87..614cd94 100644 (file)
@@ -466,6 +466,14 @@ static int mlx5e_tx_reporter_dump_sq(struct mlx5e_priv *priv, struct devlink_fms
        return mlx5e_health_fmsg_named_obj_nest_end(fmsg);
 }
 
+static int mlx5e_tx_reporter_timeout_dump(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg,
+                                         void *ctx)
+{
+       struct mlx5e_tx_timeout_ctx *to_ctx = ctx;
+
+       return mlx5e_tx_reporter_dump_sq(priv, fmsg, to_ctx->sq);
+}
+
 static int mlx5e_tx_reporter_dump_all_sqs(struct mlx5e_priv *priv,
                                          struct devlink_fmsg *fmsg)
 {
@@ -561,7 +569,7 @@ int mlx5e_reporter_tx_timeout(struct mlx5e_txqsq *sq)
        to_ctx.sq = sq;
        err_ctx.ctx = &to_ctx;
        err_ctx.recover = mlx5e_tx_reporter_timeout_recover;
-       err_ctx.dump = mlx5e_tx_reporter_dump_sq;
+       err_ctx.dump = mlx5e_tx_reporter_timeout_dump;
        snprintf(err_str, sizeof(err_str),
                 "TX timeout on queue: %d, SQ: 0x%x, CQ: 0x%x, SQ Cons: 0x%x SQ Prod: 0x%x, usecs since last trans: %u",
                 sq->ch_ix, sq->sqn, sq->cq.mcq.cqn, sq->cc, sq->pc,
index 538bc24..8526a5f 100644 (file)
@@ -4,6 +4,7 @@
 #include "setup.h"
 #include "en/params.h"
 #include "en/txrx.h"
+#include "en/health.h"
 
 /* It matches XDP_UMEM_MIN_CHUNK_SIZE, but as this constant is private and may
  * change unexpectedly, and mlx5e has a minimum valid stride size for striding
@@ -170,7 +171,13 @@ void mlx5e_close_xsk(struct mlx5e_channel *c)
 
 void mlx5e_activate_xsk(struct mlx5e_channel *c)
 {
+       /* ICOSQ recovery deactivates RQs. Suspend the recovery to avoid
+        * activating XSKRQ in the middle of recovery.
+        */
+       mlx5e_reporter_icosq_suspend_recovery(c);
        set_bit(MLX5E_RQ_STATE_ENABLED, &c->xskrq.state);
+       mlx5e_reporter_icosq_resume_recovery(c);
+
        /* TX queue is created active. */
 
        spin_lock_bh(&c->async_icosq_lock);
@@ -180,6 +187,13 @@ void mlx5e_activate_xsk(struct mlx5e_channel *c)
 
 void mlx5e_deactivate_xsk(struct mlx5e_channel *c)
 {
-       mlx5e_deactivate_rq(&c->xskrq);
+       /* ICOSQ recovery may reactivate XSKRQ if clear_bit is called in the
+        * middle of recovery. Suspend the recovery to avoid it.
+        */
+       mlx5e_reporter_icosq_suspend_recovery(c);
+       clear_bit(MLX5E_RQ_STATE_ENABLED, &c->xskrq.state);
+       mlx5e_reporter_icosq_resume_recovery(c);
+       synchronize_net(); /* Sync with NAPI to prevent mlx5e_post_rx_wqes. */
+
        /* TX queue is disabled on close. */
 }
index 6557159..4137984 100644 (file)
@@ -1087,8 +1087,6 @@ void mlx5e_deactivate_rq(struct mlx5e_rq *rq)
 void mlx5e_close_rq(struct mlx5e_rq *rq)
 {
        cancel_work_sync(&rq->dim.work);
-       if (rq->icosq)
-               cancel_work_sync(&rq->icosq->recover_work);
        cancel_work_sync(&rq->recover_work);
        mlx5e_destroy_rq(rq);
        mlx5e_free_rx_descs(rq);
@@ -1216,9 +1214,20 @@ static void mlx5e_icosq_err_cqe_work(struct work_struct *recover_work)
        mlx5e_reporter_icosq_cqe_err(sq);
 }
 
+static void mlx5e_async_icosq_err_cqe_work(struct work_struct *recover_work)
+{
+       struct mlx5e_icosq *sq = container_of(recover_work, struct mlx5e_icosq,
+                                             recover_work);
+
+       /* Not implemented yet. */
+
+       netdev_warn(sq->channel->netdev, "async_icosq recovery is not implemented\n");
+}
+
 static int mlx5e_alloc_icosq(struct mlx5e_channel *c,
                             struct mlx5e_sq_param *param,
-                            struct mlx5e_icosq *sq)
+                            struct mlx5e_icosq *sq,
+                            work_func_t recover_work_func)
 {
        void *sqc_wq               = MLX5_ADDR_OF(sqc, param->sqc, wq);
        struct mlx5_core_dev *mdev = c->mdev;
@@ -1239,7 +1248,7 @@ static int mlx5e_alloc_icosq(struct mlx5e_channel *c,
        if (err)
                goto err_sq_wq_destroy;
 
-       INIT_WORK(&sq->recover_work, mlx5e_icosq_err_cqe_work);
+       INIT_WORK(&sq->recover_work, recover_work_func);
 
        return 0;
 
@@ -1575,13 +1584,14 @@ void mlx5e_tx_err_cqe_work(struct work_struct *recover_work)
        mlx5e_reporter_tx_err_cqe(sq);
 }
 
-int mlx5e_open_icosq(struct mlx5e_channel *c, struct mlx5e_params *params,
-                    struct mlx5e_sq_param *param, struct mlx5e_icosq *sq)
+static int mlx5e_open_icosq(struct mlx5e_channel *c, struct mlx5e_params *params,
+                           struct mlx5e_sq_param *param, struct mlx5e_icosq *sq,
+                           work_func_t recover_work_func)
 {
        struct mlx5e_create_sq_param csp = {};
        int err;
 
-       err = mlx5e_alloc_icosq(c, param, sq);
+       err = mlx5e_alloc_icosq(c, param, sq, recover_work_func);
        if (err)
                return err;
 
@@ -1620,7 +1630,7 @@ void mlx5e_deactivate_icosq(struct mlx5e_icosq *icosq)
        synchronize_net(); /* Sync with NAPI. */
 }
 
-void mlx5e_close_icosq(struct mlx5e_icosq *sq)
+static void mlx5e_close_icosq(struct mlx5e_icosq *sq)
 {
        struct mlx5e_channel *c = sq->channel;
 
@@ -2084,11 +2094,15 @@ static int mlx5e_open_queues(struct mlx5e_channel *c,
 
        spin_lock_init(&c->async_icosq_lock);
 
-       err = mlx5e_open_icosq(c, params, &cparam->async_icosq, &c->async_icosq);
+       err = mlx5e_open_icosq(c, params, &cparam->async_icosq, &c->async_icosq,
+                              mlx5e_async_icosq_err_cqe_work);
        if (err)
                goto err_close_xdpsq_cq;
 
-       err = mlx5e_open_icosq(c, params, &cparam->icosq, &c->icosq);
+       mutex_init(&c->icosq_recovery_lock);
+
+       err = mlx5e_open_icosq(c, params, &cparam->icosq, &c->icosq,
+                              mlx5e_icosq_err_cqe_work);
        if (err)
                goto err_close_async_icosq;
 
@@ -2156,9 +2170,12 @@ static void mlx5e_close_queues(struct mlx5e_channel *c)
        mlx5e_close_xdpsq(&c->xdpsq);
        if (c->xdp)
                mlx5e_close_xdpsq(&c->rq_xdpsq);
+       /* The same ICOSQ is used for UMRs for both RQ and XSKRQ. */
+       cancel_work_sync(&c->icosq.recover_work);
        mlx5e_close_rq(&c->rq);
        mlx5e_close_sqs(c);
        mlx5e_close_icosq(&c->icosq);
+       mutex_destroy(&c->icosq_recovery_lock);
        mlx5e_close_icosq(&c->async_icosq);
        if (c->xdp)
                mlx5e_close_cq(&c->rq_xdpsq.cq);
@@ -3724,12 +3741,11 @@ static int set_feature_arfs(struct net_device *netdev, bool enable)
 
 static int mlx5e_handle_feature(struct net_device *netdev,
                                netdev_features_t *features,
-                               netdev_features_t wanted_features,
                                netdev_features_t feature,
                                mlx5e_feature_handler feature_handler)
 {
-       netdev_features_t changes = wanted_features ^ netdev->features;
-       bool enable = !!(wanted_features & feature);
+       netdev_features_t changes = *features ^ netdev->features;
+       bool enable = !!(*features & feature);
        int err;
 
        if (!(changes & feature))
@@ -3737,22 +3753,22 @@ static int mlx5e_handle_feature(struct net_device *netdev,
 
        err = feature_handler(netdev, enable);
        if (err) {
+               MLX5E_SET_FEATURE(features, feature, !enable);
                netdev_err(netdev, "%s feature %pNF failed, err %d\n",
                           enable ? "Enable" : "Disable", &feature, err);
                return err;
        }
 
-       MLX5E_SET_FEATURE(features, feature, enable);
        return 0;
 }
 
 int mlx5e_set_features(struct net_device *netdev, netdev_features_t features)
 {
-       netdev_features_t oper_features = netdev->features;
+       netdev_features_t oper_features = features;
        int err = 0;
 
 #define MLX5E_HANDLE_FEATURE(feature, handler) \
-       mlx5e_handle_feature(netdev, &oper_features, features, feature, handler)
+       mlx5e_handle_feature(netdev, &oper_features, feature, handler)
 
        err |= MLX5E_HANDLE_FEATURE(NETIF_F_LRO, set_feature_lro);
        err |= MLX5E_HANDLE_FEATURE(NETIF_F_GRO_HW, set_feature_hw_gro);
index 3d45f4a..5e454a1 100644 (file)
@@ -1196,21 +1196,16 @@ void mlx5e_tc_unoffload_fdb_rules(struct mlx5_eswitch *esw,
        if (attr->flags & MLX5_ESW_ATTR_FLAG_SLOW_PATH)
                goto offload_rule_0;
 
-       if (flow_flag_test(flow, CT)) {
-               mlx5_tc_ct_delete_flow(get_ct_priv(flow->priv), flow, attr);
-               return;
-       }
-
-       if (flow_flag_test(flow, SAMPLE)) {
-               mlx5e_tc_sample_unoffload(get_sample_priv(flow->priv), flow->rule[0], attr);
-               return;
-       }
-
        if (attr->esw_attr->split_count)
                mlx5_eswitch_del_fwd_rule(esw, flow->rule[1], attr);
 
+       if (flow_flag_test(flow, CT))
+               mlx5_tc_ct_delete_flow(get_ct_priv(flow->priv), flow, attr);
+       else if (flow_flag_test(flow, SAMPLE))
+               mlx5e_tc_sample_unoffload(get_sample_priv(flow->priv), flow->rule[0], attr);
+       else
 offload_rule_0:
-       mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr);
+               mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr);
 }
 
 struct mlx5_flow_handle *
@@ -1445,7 +1440,9 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
                                                        MLX5_FLOW_NAMESPACE_FDB, VPORT_TO_REG,
                                                        metadata);
                        if (err)
-                               return err;
+                               goto err_out;
+
+                       attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
                }
        }
 
@@ -1461,13 +1458,15 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
                if (attr->chain) {
                        NL_SET_ERR_MSG_MOD(extack,
                                           "Internal port rule is only supported on chain 0");
-                       return -EOPNOTSUPP;
+                       err = -EOPNOTSUPP;
+                       goto err_out;
                }
 
                if (attr->dest_chain) {
                        NL_SET_ERR_MSG_MOD(extack,
                                           "Internal port rule offload doesn't support goto action");
-                       return -EOPNOTSUPP;
+                       err = -EOPNOTSUPP;
+                       goto err_out;
                }
 
                int_port = mlx5e_tc_int_port_get(mlx5e_get_int_port_priv(priv),
@@ -1475,8 +1474,10 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
                                                 flow_flag_test(flow, EGRESS) ?
                                                 MLX5E_TC_INT_PORT_EGRESS :
                                                 MLX5E_TC_INT_PORT_INGRESS);
-               if (IS_ERR(int_port))
-                       return PTR_ERR(int_port);
+               if (IS_ERR(int_port)) {
+                       err = PTR_ERR(int_port);
+                       goto err_out;
+               }
 
                esw_attr->int_port = int_port;
        }
index 97e5845..d5e4763 100644 (file)
@@ -121,6 +121,9 @@ u32 mlx5_chains_get_nf_ft_chain(struct mlx5_fs_chains *chains)
 
 u32 mlx5_chains_get_prio_range(struct mlx5_fs_chains *chains)
 {
+       if (!mlx5_chains_prios_supported(chains))
+               return 1;
+
        if (mlx5_chains_ignore_flow_level_supported(chains))
                return UINT_MAX;
 
index 7df9c7f..6508349 100644 (file)
@@ -1809,12 +1809,13 @@ void mlx5_disable_device(struct mlx5_core_dev *dev)
 
 int mlx5_recover_device(struct mlx5_core_dev *dev)
 {
-       int ret = -EIO;
+       if (!mlx5_core_is_sf(dev)) {
+               mlx5_pci_disable_device(dev);
+               if (mlx5_pci_slot_reset(dev->pdev) != PCI_ERS_RESULT_RECOVERED)
+                       return -EIO;
+       }
 
-       mlx5_pci_disable_device(dev);
-       if (mlx5_pci_slot_reset(dev->pdev) == PCI_ERS_RESULT_RECOVERED)
-               ret = mlx5_load_one(dev);
-       return ret;
+       return mlx5_load_one(dev);
 }
 
 static struct pci_driver mlx5_core_driver = {
index 830444f..bcee30f 100644 (file)
@@ -356,8 +356,8 @@ static struct mlx5_irq *irq_pool_request_affinity(struct mlx5_irq_pool *pool,
        new_irq = irq_pool_create_irq(pool, affinity);
        if (IS_ERR(new_irq)) {
                if (!least_loaded_irq) {
-                       mlx5_core_err(pool->dev, "Didn't find IRQ for cpu = %u\n",
-                                     cpumask_first(affinity));
+                       mlx5_core_err(pool->dev, "Didn't find a matching IRQ. err = %ld\n",
+                                     PTR_ERR(new_irq));
                        mutex_unlock(&pool->lock);
                        return new_irq;
                }
@@ -398,7 +398,7 @@ irq_pool_request_vector(struct mlx5_irq_pool *pool, int vecidx,
        cpumask_copy(irq->mask, affinity);
        if (!irq_pool_is_sf_pool(pool) && !pool->xa_num_irqs.max &&
            cpumask_empty(irq->mask))
-               cpumask_set_cpu(0, irq->mask);
+               cpumask_set_cpu(cpumask_first(cpu_online_mask), irq->mask);
        irq_set_affinity_hint(irq->irqn, irq->mask);
 unlock:
        mutex_unlock(&pool->lock);
index 8cbd36c..c54cc45 100644 (file)
@@ -2,6 +2,7 @@
 /* Copyright (c) 2019 Mellanox Technologies. */
 
 #include <linux/mlx5/eswitch.h>
+#include <linux/err.h>
 #include "dr_types.h"
 
 #define DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, dmn_type) \
@@ -72,9 +73,9 @@ static int dr_domain_init_resources(struct mlx5dr_domain *dmn)
        }
 
        dmn->uar = mlx5_get_uars_page(dmn->mdev);
-       if (!dmn->uar) {
+       if (IS_ERR(dmn->uar)) {
                mlx5dr_err(dmn, "Couldn't allocate UAR\n");
-               ret = -ENOMEM;
+               ret = PTR_ERR(dmn->uar);
                goto clean_pd;
        }
 
@@ -163,9 +164,7 @@ static int dr_domain_query_vport(struct mlx5dr_domain *dmn,
 
 static int dr_domain_query_esw_mngr(struct mlx5dr_domain *dmn)
 {
-       return dr_domain_query_vport(dmn,
-                                    dmn->info.caps.is_ecpf ? MLX5_VPORT_ECPF : 0,
-                                    false,
+       return dr_domain_query_vport(dmn, 0, false,
                                     &dmn->info.caps.vports.esw_manager_caps);
 }
 
index 2e25798..7f49042 100644 (file)
@@ -321,6 +321,8 @@ static int ks8851_probe_par(struct platform_device *pdev)
                return ret;
 
        netdev->irq = platform_get_irq(pdev, 0);
+       if (netdev->irq < 0)
+               return netdev->irq;
 
        return ks8851_probe_common(netdev, dev, msg_enable);
 }
index 63f8a81..2ff7be1 100644 (file)
@@ -3135,7 +3135,7 @@ int ionic_lif_init(struct ionic_lif *lif)
                return -EINVAL;
        }
 
-       lif->dbid_inuse = bitmap_alloc(lif->dbid_count, GFP_KERNEL);
+       lif->dbid_inuse = bitmap_zalloc(lif->dbid_count, GFP_KERNEL);
        if (!lif->dbid_inuse) {
                dev_err(dev, "Failed alloc doorbell id bitmap, aborting\n");
                return -ENOMEM;
index 7160b42..d0111cb 100644 (file)
@@ -201,7 +201,7 @@ int qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter *,
                                   struct qlcnic_info *, u16);
 int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *, u16, u8);
 void qlcnic_sriov_free_vlans(struct qlcnic_adapter *);
-void qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *);
+int qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *);
 bool qlcnic_sriov_check_any_vlan(struct qlcnic_vf_info *);
 void qlcnic_sriov_del_vlan_id(struct qlcnic_sriov *,
                              struct qlcnic_vf_info *, u16);
index dd03be3..42a44c9 100644 (file)
@@ -432,7 +432,7 @@ static int qlcnic_sriov_set_guest_vlan_mode(struct qlcnic_adapter *adapter,
                                            struct qlcnic_cmd_args *cmd)
 {
        struct qlcnic_sriov *sriov = adapter->ahw->sriov;
-       int i, num_vlans;
+       int i, num_vlans, ret;
        u16 *vlans;
 
        if (sriov->allowed_vlans)
@@ -443,7 +443,9 @@ static int qlcnic_sriov_set_guest_vlan_mode(struct qlcnic_adapter *adapter,
        dev_info(&adapter->pdev->dev, "Number of allowed Guest VLANs = %d\n",
                 sriov->num_allowed_vlans);
 
-       qlcnic_sriov_alloc_vlans(adapter);
+       ret = qlcnic_sriov_alloc_vlans(adapter);
+       if (ret)
+               return ret;
 
        if (!sriov->any_vlan)
                return 0;
@@ -2154,7 +2156,7 @@ static int qlcnic_sriov_vf_resume(struct qlcnic_adapter *adapter)
        return err;
 }
 
-void qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *adapter)
+int qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_sriov *sriov = adapter->ahw->sriov;
        struct qlcnic_vf_info *vf;
@@ -2164,7 +2166,11 @@ void qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *adapter)
                vf = &sriov->vf_info[i];
                vf->sriov_vlans = kcalloc(sriov->num_allowed_vlans,
                                          sizeof(*vf->sriov_vlans), GFP_KERNEL);
+               if (!vf->sriov_vlans)
+                       return -ENOMEM;
        }
+
+       return 0;
 }
 
 void qlcnic_sriov_free_vlans(struct qlcnic_adapter *adapter)
index 447720b..e90fa97 100644 (file)
@@ -597,7 +597,9 @@ static int __qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter,
        if (err)
                goto del_flr_queue;
 
-       qlcnic_sriov_alloc_vlans(adapter);
+       err = qlcnic_sriov_alloc_vlans(adapter);
+       if (err)
+               goto del_flr_queue;
 
        return err;
 
index 86c44bc..6b81f95 100644 (file)
@@ -5441,7 +5441,9 @@ static struct pci_driver rtl8169_pci_driver = {
        .probe          = rtl_init_one,
        .remove         = rtl_remove_one,
        .shutdown       = rtl_shutdown,
-       .driver.pm      = pm_ptr(&rtl8169_pm_ops),
+#ifdef CONFIG_PM
+       .driver.pm      = &rtl8169_pm_ops,
+#endif
 };
 
 module_pci_driver(rtl8169_pci_driver);
index 966f13e..11a6aee 100644 (file)
@@ -728,7 +728,10 @@ static void ef4_init_rx_recycle_ring(struct ef4_nic *efx,
                                            efx->rx_bufs_per_page);
        rx_queue->page_ring = kcalloc(page_ring_size,
                                      sizeof(*rx_queue->page_ring), GFP_KERNEL);
-       rx_queue->page_ptr_mask = page_ring_size - 1;
+       if (!rx_queue->page_ring)
+               rx_queue->page_ptr_mask = 0;
+       else
+               rx_queue->page_ptr_mask = page_ring_size - 1;
 }
 
 void ef4_init_rx_queue(struct ef4_rx_queue *rx_queue)
index 68fc7d3..0983abc 100644 (file)
@@ -150,7 +150,10 @@ static void efx_init_rx_recycle_ring(struct efx_rx_queue *rx_queue)
                                            efx->rx_bufs_per_page);
        rx_queue->page_ring = kcalloc(page_ring_size,
                                      sizeof(*rx_queue->page_ring), GFP_KERNEL);
-       rx_queue->page_ptr_mask = page_ring_size - 1;
+       if (!rx_queue->page_ring)
+               rx_queue->page_ptr_mask = 0;
+       else
+               rx_queue->page_ptr_mask = page_ring_size - 1;
 }
 
 static void efx_fini_rx_recycle_ring(struct efx_rx_queue *rx_queue)
index 89381f7..dd6f69c 100644 (file)
@@ -2072,6 +2072,11 @@ static int smc911x_drv_probe(struct platform_device *pdev)
 
        ndev->dma = (unsigned char)-1;
        ndev->irq = platform_get_irq(pdev, 0);
+       if (ndev->irq < 0) {
+               ret = ndev->irq;
+               goto release_both;
+       }
+
        lp = netdev_priv(ndev);
        lp->netdev = ndev;
 #ifdef SMC_DYNAMIC_BUS_CONFIG
index 66fc8be..e2e0f97 100644 (file)
@@ -26,7 +26,7 @@
 #define ETHER_CLK_SEL_FREQ_SEL_125M    (BIT(9) | BIT(8))
 #define ETHER_CLK_SEL_FREQ_SEL_50M     BIT(9)
 #define ETHER_CLK_SEL_FREQ_SEL_25M     BIT(8)
-#define ETHER_CLK_SEL_FREQ_SEL_2P5M    BIT(0)
+#define ETHER_CLK_SEL_FREQ_SEL_2P5M    0
 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_IN BIT(0)
 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC BIT(10)
 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV BIT(11)
index 580cc03..be9b58b 100644 (file)
@@ -102,7 +102,7 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
                time.tv_nsec = priv->plat->est->btr_reserve[0];
                time.tv_sec = priv->plat->est->btr_reserve[1];
                basetime = timespec64_to_ktime(time);
-               cycle_time = priv->plat->est->ctr[1] * NSEC_PER_SEC +
+               cycle_time = (u64)priv->plat->est->ctr[1] * NSEC_PER_SEC +
                             priv->plat->est->ctr[0];
                time = stmmac_calc_tas_basetime(basetime,
                                                current_time_ns,
index b06c17a..ebd2870 100644 (file)
@@ -1262,6 +1262,11 @@ static int fjes_probe(struct platform_device *plat_dev)
        hw->hw_res.start = res->start;
        hw->hw_res.size = resource_size(res);
        hw->hw_res.irq = platform_get_irq(plat_dev, 0);
+       if (hw->hw_res.irq < 0) {
+               err = hw->hw_res.irq;
+               goto err_free_control_wq;
+       }
+
        err = fjes_hw_init(&adapter->hw);
        if (err)
                goto err_free_control_wq;
index 7da2bb8..edde9c3 100644 (file)
@@ -794,14 +794,14 @@ static void mkiss_close(struct tty_struct *tty)
         */
        netif_stop_queue(ax->dev);
 
-       ax->tty = NULL;
-
        unregister_netdev(ax->dev);
 
        /* Free all AX25 frame buffers after unreg. */
        kfree(ax->rbuff);
        kfree(ax->xbuff);
 
+       ax->tty = NULL;
+
        free_netdev(ax->dev);
 }
 
index c65fb5f..a0c256b 100644 (file)
@@ -239,8 +239,8 @@ static struct phy_device *__fixed_phy_register(unsigned int irq,
        /* Check if we have a GPIO associated with this fixed phy */
        if (!gpiod) {
                gpiod = fixed_phy_get_gpiod(np);
-               if (IS_ERR(gpiod))
-                       return ERR_CAST(gpiod);
+               if (!gpiod)
+                       return ERR_PTR(-EINVAL);
        }
 
        /* Get the next available PHY address, up to PHY_MAX_ADDR */
index 1572878..45a67e7 100644 (file)
@@ -209,6 +209,9 @@ struct tun_struct {
        struct tun_prog __rcu *steering_prog;
        struct tun_prog __rcu *filter_prog;
        struct ethtool_link_ksettings link_ksettings;
+       /* init args */
+       struct file *file;
+       struct ifreq *ifr;
 };
 
 struct veth {
@@ -216,6 +219,9 @@ struct veth {
        __be16 h_vlan_TCI;
 };
 
+static void tun_flow_init(struct tun_struct *tun);
+static void tun_flow_uninit(struct tun_struct *tun);
+
 static int tun_napi_receive(struct napi_struct *napi, int budget)
 {
        struct tun_file *tfile = container_of(napi, struct tun_file, napi);
@@ -953,6 +959,49 @@ static int check_filter(struct tap_filter *filter, const struct sk_buff *skb)
 
 static const struct ethtool_ops tun_ethtool_ops;
 
+static int tun_net_init(struct net_device *dev)
+{
+       struct tun_struct *tun = netdev_priv(dev);
+       struct ifreq *ifr = tun->ifr;
+       int err;
+
+       dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+       if (!dev->tstats)
+               return -ENOMEM;
+
+       spin_lock_init(&tun->lock);
+
+       err = security_tun_dev_alloc_security(&tun->security);
+       if (err < 0) {
+               free_percpu(dev->tstats);
+               return err;
+       }
+
+       tun_flow_init(tun);
+
+       dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
+                          TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
+                          NETIF_F_HW_VLAN_STAG_TX;
+       dev->features = dev->hw_features | NETIF_F_LLTX;
+       dev->vlan_features = dev->features &
+                            ~(NETIF_F_HW_VLAN_CTAG_TX |
+                              NETIF_F_HW_VLAN_STAG_TX);
+
+       tun->flags = (tun->flags & ~TUN_FEATURES) |
+                     (ifr->ifr_flags & TUN_FEATURES);
+
+       INIT_LIST_HEAD(&tun->disabled);
+       err = tun_attach(tun, tun->file, false, ifr->ifr_flags & IFF_NAPI,
+                        ifr->ifr_flags & IFF_NAPI_FRAGS, false);
+       if (err < 0) {
+               tun_flow_uninit(tun);
+               security_tun_dev_free_security(tun->security);
+               free_percpu(dev->tstats);
+               return err;
+       }
+       return 0;
+}
+
 /* Net device detach from fd. */
 static void tun_net_uninit(struct net_device *dev)
 {
@@ -1169,6 +1218,7 @@ static int tun_net_change_carrier(struct net_device *dev, bool new_carrier)
 }
 
 static const struct net_device_ops tun_netdev_ops = {
+       .ndo_init               = tun_net_init,
        .ndo_uninit             = tun_net_uninit,
        .ndo_open               = tun_net_open,
        .ndo_stop               = tun_net_close,
@@ -1252,6 +1302,7 @@ static int tun_xdp_tx(struct net_device *dev, struct xdp_buff *xdp)
 }
 
 static const struct net_device_ops tap_netdev_ops = {
+       .ndo_init               = tun_net_init,
        .ndo_uninit             = tun_net_uninit,
        .ndo_open               = tun_net_open,
        .ndo_stop               = tun_net_close,
@@ -1292,7 +1343,7 @@ static void tun_flow_uninit(struct tun_struct *tun)
 #define MAX_MTU 65535
 
 /* Initialize net device. */
-static void tun_net_init(struct net_device *dev)
+static void tun_net_initialize(struct net_device *dev)
 {
        struct tun_struct *tun = netdev_priv(dev);
 
@@ -2206,11 +2257,6 @@ static void tun_free_netdev(struct net_device *dev)
        BUG_ON(!(list_empty(&tun->disabled)));
 
        free_percpu(dev->tstats);
-       /* We clear tstats so that tun_set_iff() can tell if
-        * tun_free_netdev() has been called from register_netdevice().
-        */
-       dev->tstats = NULL;
-
        tun_flow_uninit(tun);
        security_tun_dev_free_security(tun->security);
        __tun_set_ebpf(tun, &tun->steering_prog, NULL);
@@ -2716,41 +2762,16 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                tun->rx_batched = 0;
                RCU_INIT_POINTER(tun->steering_prog, NULL);
 
-               dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
-               if (!dev->tstats) {
-                       err = -ENOMEM;
-                       goto err_free_dev;
-               }
-
-               spin_lock_init(&tun->lock);
-
-               err = security_tun_dev_alloc_security(&tun->security);
-               if (err < 0)
-                       goto err_free_stat;
-
-               tun_net_init(dev);
-               tun_flow_init(tun);
+               tun->ifr = ifr;
+               tun->file = file;
 
-               dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
-                                  TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
-                                  NETIF_F_HW_VLAN_STAG_TX;
-               dev->features = dev->hw_features | NETIF_F_LLTX;
-               dev->vlan_features = dev->features &
-                                    ~(NETIF_F_HW_VLAN_CTAG_TX |
-                                      NETIF_F_HW_VLAN_STAG_TX);
-
-               tun->flags = (tun->flags & ~TUN_FEATURES) |
-                             (ifr->ifr_flags & TUN_FEATURES);
-
-               INIT_LIST_HEAD(&tun->disabled);
-               err = tun_attach(tun, file, false, ifr->ifr_flags & IFF_NAPI,
-                                ifr->ifr_flags & IFF_NAPI_FRAGS, false);
-               if (err < 0)
-                       goto err_free_flow;
+               tun_net_initialize(dev);
 
                err = register_netdevice(tun->dev);
-               if (err < 0)
-                       goto err_detach;
+               if (err < 0) {
+                       free_netdev(dev);
+                       return err;
+               }
                /* free_netdev() won't check refcnt, to avoid race
                 * with dev_put() we need publish tun after registration.
                 */
@@ -2767,24 +2788,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 
        strcpy(ifr->ifr_name, tun->dev->name);
        return 0;
-
-err_detach:
-       tun_detach_all(dev);
-       /* We are here because register_netdevice() has failed.
-        * If register_netdevice() already called tun_free_netdev()
-        * while dealing with the error, dev->stats has been cleared.
-        */
-       if (!dev->tstats)
-               goto err_free_dev;
-
-err_free_flow:
-       tun_flow_uninit(tun);
-       security_tun_dev_free_security(tun->security);
-err_free_stat:
-       free_percpu(dev->tstats);
-err_free_dev:
-       free_netdev(dev);
-       return err;
 }
 
 static void tun_get_iff(struct tun_struct *tun, struct ifreq *ifr)
index 42ba4af..7168297 100644 (file)
@@ -9,6 +9,8 @@
 
 #include "asix.h"
 
+#define AX_HOST_EN_RETRIES     30
+
 int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
                  u16 size, void *data, int in_pm)
 {
@@ -68,7 +70,7 @@ static int asix_check_host_enable(struct usbnet *dev, int in_pm)
        int i, ret;
        u8 smsr;
 
-       for (i = 0; i < 30; ++i) {
+       for (i = 0; i < AX_HOST_EN_RETRIES; ++i) {
                ret = asix_set_sw_mii(dev, in_pm);
                if (ret == -ENODEV || ret == -ETIMEDOUT)
                        break;
@@ -77,13 +79,13 @@ static int asix_check_host_enable(struct usbnet *dev, int in_pm)
                                    0, 0, 1, &smsr, in_pm);
                if (ret == -ENODEV)
                        break;
-               else if (ret < 0)
+               else if (ret < sizeof(smsr))
                        continue;
                else if (smsr & AX_HOST_EN)
                        break;
        }
 
-       return ret;
+       return i >= AX_HOST_EN_RETRIES ? -ETIMEDOUT : ret;
 }
 
 static void reset_asix_rx_fixup_info(struct asix_rx_fixup_info *rx)
index c4cd40b..feb247e 100644 (file)
@@ -493,11 +493,11 @@ static void read_bulk_callback(struct urb *urb)
                goto goon;
 
        rx_status = buf[count - 2];
-       if (rx_status & 0x1e) {
+       if (rx_status & 0x1c) {
                netif_dbg(pegasus, rx_err, net,
                          "RX packet error %x\n", rx_status);
                net->stats.rx_errors++;
-               if (rx_status & 0x06)   /* long or runt */
+               if (rx_status & 0x04)   /* runt */
                        net->stats.rx_length_errors++;
                if (rx_status & 0x08)
                        net->stats.rx_crc_errors++;
index f9877a3..3085e81 100644 (file)
@@ -32,7 +32,7 @@
 #define NETNEXT_VERSION                "12"
 
 /* Information for net */
-#define NET_VERSION            "11"
+#define NET_VERSION            "12"
 
 #define DRIVER_VERSION         "v1." NETNEXT_VERSION "." NET_VERSION
 #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
@@ -4016,6 +4016,11 @@ static void rtl_clear_bp(struct r8152 *tp, u16 type)
        ocp_write_word(tp, type, PLA_BP_BA, 0);
 }
 
+static inline void rtl_reset_ocp_base(struct r8152 *tp)
+{
+       tp->ocp_base = -1;
+}
+
 static int rtl_phy_patch_request(struct r8152 *tp, bool request, bool wait)
 {
        u16 data, check;
@@ -4087,8 +4092,6 @@ static int rtl_post_ram_code(struct r8152 *tp, u16 key_addr, bool wait)
 
        rtl_phy_patch_request(tp, false, wait);
 
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, tp->ocp_base);
-
        return 0;
 }
 
@@ -4800,6 +4803,8 @@ static void rtl_ram_code_speed_up(struct r8152 *tp, struct fw_phy_speed_up *phy,
        u32 len;
        u8 *data;
 
+       rtl_reset_ocp_base(tp);
+
        if (sram_read(tp, SRAM_GPHY_FW_VER) >= __le16_to_cpu(phy->version)) {
                dev_dbg(&tp->intf->dev, "PHY firmware has been the newest\n");
                return;
@@ -4845,7 +4850,8 @@ static void rtl_ram_code_speed_up(struct r8152 *tp, struct fw_phy_speed_up *phy,
                }
        }
 
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, tp->ocp_base);
+       rtl_reset_ocp_base(tp);
+
        rtl_phy_patch_request(tp, false, wait);
 
        if (sram_read(tp, SRAM_GPHY_FW_VER) == __le16_to_cpu(phy->version))
@@ -4861,6 +4867,8 @@ static int rtl8152_fw_phy_ver(struct r8152 *tp, struct fw_phy_ver *phy_ver)
        ver_addr = __le16_to_cpu(phy_ver->ver.addr);
        ver = __le16_to_cpu(phy_ver->ver.data);
 
+       rtl_reset_ocp_base(tp);
+
        if (sram_read(tp, ver_addr) >= ver) {
                dev_dbg(&tp->intf->dev, "PHY firmware has been the newest\n");
                return 0;
@@ -4877,6 +4885,8 @@ static void rtl8152_fw_phy_fixup(struct r8152 *tp, struct fw_phy_fixup *fix)
 {
        u16 addr, data;
 
+       rtl_reset_ocp_base(tp);
+
        addr = __le16_to_cpu(fix->setting.addr);
        data = ocp_reg_read(tp, addr);
 
@@ -4908,6 +4918,8 @@ static void rtl8152_fw_phy_union_apply(struct r8152 *tp, struct fw_phy_union *ph
        u32 length;
        int i, num;
 
+       rtl_reset_ocp_base(tp);
+
        num = phy->pre_num;
        for (i = 0; i < num; i++)
                sram_write(tp, __le16_to_cpu(phy->pre_set[i].addr),
@@ -4938,6 +4950,8 @@ static void rtl8152_fw_phy_nc_apply(struct r8152 *tp, struct fw_phy_nc *phy)
        u32 length, i, num;
        __le16 *data;
 
+       rtl_reset_ocp_base(tp);
+
        mode_reg = __le16_to_cpu(phy->mode_reg);
        sram_write(tp, mode_reg, __le16_to_cpu(phy->mode_pre));
        sram_write(tp, __le16_to_cpu(phy->ba_reg),
@@ -5107,6 +5121,7 @@ post_fw:
        if (rtl_fw->post_fw)
                rtl_fw->post_fw(tp);
 
+       rtl_reset_ocp_base(tp);
        strscpy(rtl_fw->version, fw_hdr->version, RTL_VER_SIZE);
        dev_info(&tp->intf->dev, "load %s successfully\n", rtl_fw->version);
 }
@@ -6584,6 +6599,21 @@ static bool rtl8153_in_nway(struct r8152 *tp)
                return true;
 }
 
+static void r8156_mdio_force_mode(struct r8152 *tp)
+{
+       u16 data;
+
+       /* Select force mode through 0xa5b4 bit 15
+        * 0: MDIO force mode
+        * 1: MMD force mode
+        */
+       data = ocp_reg_read(tp, 0xa5b4);
+       if (data & BIT(15)) {
+               data &= ~BIT(15);
+               ocp_reg_write(tp, 0xa5b4, data);
+       }
+}
+
 static void set_carrier(struct r8152 *tp)
 {
        struct net_device *netdev = tp->netdev;
@@ -8016,6 +8046,7 @@ static void r8156_init(struct r8152 *tp)
        ocp_data |= ACT_ODMA;
        ocp_write_byte(tp, MCU_TYPE_USB, USB_BMU_CONFIG, ocp_data);
 
+       r8156_mdio_force_mode(tp);
        rtl_tally_reset(tp);
 
        tp->coalesce = 15000;   /* 15 us */
@@ -8145,6 +8176,7 @@ static void r8156b_init(struct r8152 *tp)
        ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
        ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
 
+       r8156_mdio_force_mode(tp);
        rtl_tally_reset(tp);
 
        tp->coalesce = 15000;   /* 15 us */
@@ -8467,6 +8499,8 @@ static int rtl8152_resume(struct usb_interface *intf)
 
        mutex_lock(&tp->control);
 
+       rtl_reset_ocp_base(tp);
+
        if (test_bit(SELECTIVE_SUSPEND, &tp->flags))
                ret = rtl8152_runtime_resume(tp);
        else
@@ -8482,6 +8516,7 @@ static int rtl8152_reset_resume(struct usb_interface *intf)
        struct r8152 *tp = usb_get_intfdata(intf);
 
        clear_bit(SELECTIVE_SUSPEND, &tp->flags);
+       rtl_reset_ocp_base(tp);
        tp->rtl_ops.init(tp);
        queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0);
        set_ethernet_addr(tp, true);
index 50eb43e..2acdb8a 100644 (file)
@@ -879,8 +879,12 @@ static int veth_xdp_rcv(struct veth_rq *rq, int budget,
 
                        stats->xdp_bytes += skb->len;
                        skb = veth_xdp_rcv_skb(rq, skb, bq, stats);
-                       if (skb)
-                               napi_gro_receive(&rq->xdp_napi, skb);
+                       if (skb) {
+                               if (skb_shared(skb) || skb_unclone(skb, GFP_ATOMIC))
+                                       netif_receive_skb(skb);
+                               else
+                                       napi_gro_receive(&rq->xdp_napi, skb);
+                       }
                }
                done++;
        }
index 4a16d6e..d9dea48 100644 (file)
@@ -203,6 +203,7 @@ struct xenvif_queue { /* Per-queue data for xenvif */
        unsigned int rx_queue_max;
        unsigned int rx_queue_len;
        unsigned long last_rx_time;
+       unsigned int rx_slots_needed;
        bool stalled;
 
        struct xenvif_copy_state rx_copy;
index accc991..dbac4c0 100644 (file)
 #include <xen/xen.h>
 #include <xen/events.h>
 
-static bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue)
+/*
+ * Update the needed ring page slots for the first SKB queued.
+ * Note that any call sequence outside the RX thread calling this function
+ * needs to wake up the RX thread via a call of xenvif_kick_thread()
+ * afterwards in order to avoid a race with putting the thread to sleep.
+ */
+static void xenvif_update_needed_slots(struct xenvif_queue *queue,
+                                      const struct sk_buff *skb)
 {
-       RING_IDX prod, cons;
-       struct sk_buff *skb;
-       int needed;
-       unsigned long flags;
-
-       spin_lock_irqsave(&queue->rx_queue.lock, flags);
+       unsigned int needed = 0;
 
-       skb = skb_peek(&queue->rx_queue);
-       if (!skb) {
-               spin_unlock_irqrestore(&queue->rx_queue.lock, flags);
-               return false;
+       if (skb) {
+               needed = DIV_ROUND_UP(skb->len, XEN_PAGE_SIZE);
+               if (skb_is_gso(skb))
+                       needed++;
+               if (skb->sw_hash)
+                       needed++;
        }
 
-       needed = DIV_ROUND_UP(skb->len, XEN_PAGE_SIZE);
-       if (skb_is_gso(skb))
-               needed++;
-       if (skb->sw_hash)
-               needed++;
+       WRITE_ONCE(queue->rx_slots_needed, needed);
+}
 
-       spin_unlock_irqrestore(&queue->rx_queue.lock, flags);
+static bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue)
+{
+       RING_IDX prod, cons;
+       unsigned int needed;
+
+       needed = READ_ONCE(queue->rx_slots_needed);
+       if (!needed)
+               return false;
 
        do {
                prod = queue->rx.sring->req_prod;
@@ -80,13 +88,19 @@ void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb)
 
        spin_lock_irqsave(&queue->rx_queue.lock, flags);
 
-       __skb_queue_tail(&queue->rx_queue, skb);
-
-       queue->rx_queue_len += skb->len;
-       if (queue->rx_queue_len > queue->rx_queue_max) {
+       if (queue->rx_queue_len >= queue->rx_queue_max) {
                struct net_device *dev = queue->vif->dev;
 
                netif_tx_stop_queue(netdev_get_tx_queue(dev, queue->id));
+               kfree_skb(skb);
+               queue->vif->dev->stats.rx_dropped++;
+       } else {
+               if (skb_queue_empty(&queue->rx_queue))
+                       xenvif_update_needed_slots(queue, skb);
+
+               __skb_queue_tail(&queue->rx_queue, skb);
+
+               queue->rx_queue_len += skb->len;
        }
 
        spin_unlock_irqrestore(&queue->rx_queue.lock, flags);
@@ -100,6 +114,8 @@ static struct sk_buff *xenvif_rx_dequeue(struct xenvif_queue *queue)
 
        skb = __skb_dequeue(&queue->rx_queue);
        if (skb) {
+               xenvif_update_needed_slots(queue, skb_peek(&queue->rx_queue));
+
                queue->rx_queue_len -= skb->len;
                if (queue->rx_queue_len < queue->rx_queue_max) {
                        struct netdev_queue *txq;
@@ -134,6 +150,7 @@ static void xenvif_rx_queue_drop_expired(struct xenvif_queue *queue)
                        break;
                xenvif_rx_dequeue(queue);
                kfree_skb(skb);
+               queue->vif->dev->stats.rx_dropped++;
        }
 }
 
@@ -487,27 +504,31 @@ void xenvif_rx_action(struct xenvif_queue *queue)
        xenvif_rx_copy_flush(queue);
 }
 
-static bool xenvif_rx_queue_stalled(struct xenvif_queue *queue)
+static RING_IDX xenvif_rx_queue_slots(const struct xenvif_queue *queue)
 {
        RING_IDX prod, cons;
 
        prod = queue->rx.sring->req_prod;
        cons = queue->rx.req_cons;
 
+       return prod - cons;
+}
+
+static bool xenvif_rx_queue_stalled(const struct xenvif_queue *queue)
+{
+       unsigned int needed = READ_ONCE(queue->rx_slots_needed);
+
        return !queue->stalled &&
-               prod - cons < 1 &&
+               xenvif_rx_queue_slots(queue) < needed &&
                time_after(jiffies,
                           queue->last_rx_time + queue->vif->stall_timeout);
 }
 
 static bool xenvif_rx_queue_ready(struct xenvif_queue *queue)
 {
-       RING_IDX prod, cons;
-
-       prod = queue->rx.sring->req_prod;
-       cons = queue->rx.req_cons;
+       unsigned int needed = READ_ONCE(queue->rx_slots_needed);
 
-       return queue->stalled && prod - cons >= 1;
+       return queue->stalled && xenvif_rx_queue_slots(queue) >= needed;
 }
 
 bool xenvif_have_rx_work(struct xenvif_queue *queue, bool test_kthread)
index 911f439..d514d96 100644 (file)
@@ -148,6 +148,9 @@ struct netfront_queue {
        grant_ref_t gref_rx_head;
        grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
 
+       unsigned int rx_rsp_unconsumed;
+       spinlock_t rx_cons_lock;
+
        struct page_pool *page_pool;
        struct xdp_rxq_info xdp_rxq;
 };
@@ -376,12 +379,13 @@ static int xennet_open(struct net_device *dev)
        return 0;
 }
 
-static void xennet_tx_buf_gc(struct netfront_queue *queue)
+static bool xennet_tx_buf_gc(struct netfront_queue *queue)
 {
        RING_IDX cons, prod;
        unsigned short id;
        struct sk_buff *skb;
        bool more_to_do;
+       bool work_done = false;
        const struct device *dev = &queue->info->netdev->dev;
 
        BUG_ON(!netif_carrier_ok(queue->info->netdev));
@@ -398,6 +402,8 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue)
                for (cons = queue->tx.rsp_cons; cons != prod; cons++) {
                        struct xen_netif_tx_response txrsp;
 
+                       work_done = true;
+
                        RING_COPY_RESPONSE(&queue->tx, cons, &txrsp);
                        if (txrsp.status == XEN_NETIF_RSP_NULL)
                                continue;
@@ -441,11 +447,13 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue)
 
        xennet_maybe_wake_tx(queue);
 
-       return;
+       return work_done;
 
  err:
        queue->info->broken = true;
        dev_alert(dev, "Disabled for further use\n");
+
+       return work_done;
 }
 
 struct xennet_gnttab_make_txreq {
@@ -834,6 +842,16 @@ static int xennet_close(struct net_device *dev)
        return 0;
 }
 
+static void xennet_set_rx_rsp_cons(struct netfront_queue *queue, RING_IDX val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&queue->rx_cons_lock, flags);
+       queue->rx.rsp_cons = val;
+       queue->rx_rsp_unconsumed = RING_HAS_UNCONSUMED_RESPONSES(&queue->rx);
+       spin_unlock_irqrestore(&queue->rx_cons_lock, flags);
+}
+
 static void xennet_move_rx_slot(struct netfront_queue *queue, struct sk_buff *skb,
                                grant_ref_t ref)
 {
@@ -885,7 +903,7 @@ static int xennet_get_extras(struct netfront_queue *queue,
                xennet_move_rx_slot(queue, skb, ref);
        } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
 
-       queue->rx.rsp_cons = cons;
+       xennet_set_rx_rsp_cons(queue, cons);
        return err;
 }
 
@@ -1039,7 +1057,7 @@ next:
        }
 
        if (unlikely(err))
-               queue->rx.rsp_cons = cons + slots;
+               xennet_set_rx_rsp_cons(queue, cons + slots);
 
        return err;
 }
@@ -1093,7 +1111,8 @@ static int xennet_fill_frags(struct netfront_queue *queue,
                        __pskb_pull_tail(skb, pull_to - skb_headlen(skb));
                }
                if (unlikely(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) {
-                       queue->rx.rsp_cons = ++cons + skb_queue_len(list);
+                       xennet_set_rx_rsp_cons(queue,
+                                              ++cons + skb_queue_len(list));
                        kfree_skb(nskb);
                        return -ENOENT;
                }
@@ -1106,7 +1125,7 @@ static int xennet_fill_frags(struct netfront_queue *queue,
                kfree_skb(nskb);
        }
 
-       queue->rx.rsp_cons = cons;
+       xennet_set_rx_rsp_cons(queue, cons);
 
        return 0;
 }
@@ -1229,7 +1248,9 @@ err:
 
                        if (unlikely(xennet_set_skb_gso(skb, gso))) {
                                __skb_queue_head(&tmpq, skb);
-                               queue->rx.rsp_cons += skb_queue_len(&tmpq);
+                               xennet_set_rx_rsp_cons(queue,
+                                                      queue->rx.rsp_cons +
+                                                      skb_queue_len(&tmpq));
                                goto err;
                        }
                }
@@ -1253,7 +1274,8 @@ err:
 
                __skb_queue_tail(&rxq, skb);
 
-               i = ++queue->rx.rsp_cons;
+               i = queue->rx.rsp_cons + 1;
+               xennet_set_rx_rsp_cons(queue, i);
                work_done++;
        }
        if (need_xdp_flush)
@@ -1417,40 +1439,79 @@ static int xennet_set_features(struct net_device *dev,
        return 0;
 }
 
-static irqreturn_t xennet_tx_interrupt(int irq, void *dev_id)
+static bool xennet_handle_tx(struct netfront_queue *queue, unsigned int *eoi)
 {
-       struct netfront_queue *queue = dev_id;
        unsigned long flags;
 
-       if (queue->info->broken)
-               return IRQ_HANDLED;
+       if (unlikely(queue->info->broken))
+               return false;
 
        spin_lock_irqsave(&queue->tx_lock, flags);
-       xennet_tx_buf_gc(queue);
+       if (xennet_tx_buf_gc(queue))
+               *eoi = 0;
        spin_unlock_irqrestore(&queue->tx_lock, flags);
 
+       return true;
+}
+
+static irqreturn_t xennet_tx_interrupt(int irq, void *dev_id)
+{
+       unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
+
+       if (likely(xennet_handle_tx(dev_id, &eoiflag)))
+               xen_irq_lateeoi(irq, eoiflag);
+
        return IRQ_HANDLED;
 }
 
-static irqreturn_t xennet_rx_interrupt(int irq, void *dev_id)
+static bool xennet_handle_rx(struct netfront_queue *queue, unsigned int *eoi)
 {
-       struct netfront_queue *queue = dev_id;
-       struct net_device *dev = queue->info->netdev;
+       unsigned int work_queued;
+       unsigned long flags;
 
-       if (queue->info->broken)
-               return IRQ_HANDLED;
+       if (unlikely(queue->info->broken))
+               return false;
+
+       spin_lock_irqsave(&queue->rx_cons_lock, flags);
+       work_queued = RING_HAS_UNCONSUMED_RESPONSES(&queue->rx);
+       if (work_queued > queue->rx_rsp_unconsumed) {
+               queue->rx_rsp_unconsumed = work_queued;
+               *eoi = 0;
+       } else if (unlikely(work_queued < queue->rx_rsp_unconsumed)) {
+               const struct device *dev = &queue->info->netdev->dev;
+
+               spin_unlock_irqrestore(&queue->rx_cons_lock, flags);
+               dev_alert(dev, "RX producer index going backwards\n");
+               dev_alert(dev, "Disabled for further use\n");
+               queue->info->broken = true;
+               return false;
+       }
+       spin_unlock_irqrestore(&queue->rx_cons_lock, flags);
 
-       if (likely(netif_carrier_ok(dev) &&
-                  RING_HAS_UNCONSUMED_RESPONSES(&queue->rx)))
+       if (likely(netif_carrier_ok(queue->info->netdev) && work_queued))
                napi_schedule(&queue->napi);
 
+       return true;
+}
+
+static irqreturn_t xennet_rx_interrupt(int irq, void *dev_id)
+{
+       unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
+
+       if (likely(xennet_handle_rx(dev_id, &eoiflag)))
+               xen_irq_lateeoi(irq, eoiflag);
+
        return IRQ_HANDLED;
 }
 
 static irqreturn_t xennet_interrupt(int irq, void *dev_id)
 {
-       xennet_tx_interrupt(irq, dev_id);
-       xennet_rx_interrupt(irq, dev_id);
+       unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
+
+       if (xennet_handle_tx(dev_id, &eoiflag) &&
+           xennet_handle_rx(dev_id, &eoiflag))
+               xen_irq_lateeoi(irq, eoiflag);
+
        return IRQ_HANDLED;
 }
 
@@ -1768,9 +1829,10 @@ static int setup_netfront_single(struct netfront_queue *queue)
        if (err < 0)
                goto fail;
 
-       err = bind_evtchn_to_irqhandler(queue->tx_evtchn,
-                                       xennet_interrupt,
-                                       0, queue->info->netdev->name, queue);
+       err = bind_evtchn_to_irqhandler_lateeoi(queue->tx_evtchn,
+                                               xennet_interrupt, 0,
+                                               queue->info->netdev->name,
+                                               queue);
        if (err < 0)
                goto bind_fail;
        queue->rx_evtchn = queue->tx_evtchn;
@@ -1798,18 +1860,18 @@ static int setup_netfront_split(struct netfront_queue *queue)
 
        snprintf(queue->tx_irq_name, sizeof(queue->tx_irq_name),
                 "%s-tx", queue->name);
-       err = bind_evtchn_to_irqhandler(queue->tx_evtchn,
-                                       xennet_tx_interrupt,
-                                       0, queue->tx_irq_name, queue);
+       err = bind_evtchn_to_irqhandler_lateeoi(queue->tx_evtchn,
+                                               xennet_tx_interrupt, 0,
+                                               queue->tx_irq_name, queue);
        if (err < 0)
                goto bind_tx_fail;
        queue->tx_irq = err;
 
        snprintf(queue->rx_irq_name, sizeof(queue->rx_irq_name),
                 "%s-rx", queue->name);
-       err = bind_evtchn_to_irqhandler(queue->rx_evtchn,
-                                       xennet_rx_interrupt,
-                                       0, queue->rx_irq_name, queue);
+       err = bind_evtchn_to_irqhandler_lateeoi(queue->rx_evtchn,
+                                               xennet_rx_interrupt, 0,
+                                               queue->rx_irq_name, queue);
        if (err < 0)
                goto bind_rx_fail;
        queue->rx_irq = err;
@@ -1911,6 +1973,7 @@ static int xennet_init_queue(struct netfront_queue *queue)
 
        spin_lock_init(&queue->tx_lock);
        spin_lock_init(&queue->rx_lock);
+       spin_lock_init(&queue->rx_cons_lock);
 
        timer_setup(&queue->rx_refill_timer, rx_refill_timeout, 0);
 
index f126ce9..35b32fb 100644 (file)
@@ -524,7 +524,8 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
        phy->gpiod_ena = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
        if (IS_ERR(phy->gpiod_ena)) {
                nfc_err(dev, "Unable to get ENABLE GPIO\n");
-               return PTR_ERR(phy->gpiod_ena);
+               r = PTR_ERR(phy->gpiod_ena);
+               goto out_free;
        }
 
        phy->se_status.is_ese_present =
@@ -535,7 +536,7 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
        r = st21nfca_hci_platform_init(phy);
        if (r < 0) {
                nfc_err(&client->dev, "Unable to reboot st21nfca\n");
-               return r;
+               goto out_free;
        }
 
        r = devm_request_threaded_irq(&client->dev, client->irq, NULL,
@@ -544,15 +545,23 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
                                ST21NFCA_HCI_DRIVER_NAME, phy);
        if (r < 0) {
                nfc_err(&client->dev, "Unable to register IRQ handler\n");
-               return r;
+               goto out_free;
        }
 
-       return st21nfca_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
-                                       ST21NFCA_FRAME_HEADROOM,
-                                       ST21NFCA_FRAME_TAILROOM,
-                                       ST21NFCA_HCI_LLC_MAX_PAYLOAD,
-                                       &phy->hdev,
-                                       &phy->se_status);
+       r = st21nfca_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
+                              ST21NFCA_FRAME_HEADROOM,
+                              ST21NFCA_FRAME_TAILROOM,
+                              ST21NFCA_HCI_LLC_MAX_PAYLOAD,
+                              &phy->hdev,
+                              &phy->se_status);
+       if (r)
+               goto out_free;
+
+       return 0;
+
+out_free:
+       kfree_skb(phy->pending_skb);
+       return r;
 }
 
 static int st21nfca_hci_i2c_remove(struct i2c_client *client)
@@ -563,6 +572,8 @@ static int st21nfca_hci_i2c_remove(struct i2c_client *client)
 
        if (phy->powered)
                st21nfca_hci_i2c_disable(phy);
+       if (phy->pending_skb)
+               kfree_skb(phy->pending_skb);
 
        return 0;
 }
index 2abcc6c..b607d10 100644 (file)
@@ -1244,6 +1244,18 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
                raw_spin_lock_init(&pc->irq_lock[i]);
        }
 
+       pc->pctl_desc = *pdata->pctl_desc;
+       pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc);
+       if (IS_ERR(pc->pctl_dev)) {
+               gpiochip_remove(&pc->gpio_chip);
+               return PTR_ERR(pc->pctl_dev);
+       }
+
+       pc->gpio_range = *pdata->gpio_range;
+       pc->gpio_range.base = pc->gpio_chip.base;
+       pc->gpio_range.gc = &pc->gpio_chip;
+       pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
+
        girq = &pc->gpio_chip.irq;
        girq->chip = &bcm2835_gpio_irq_chip;
        girq->parent_handler = bcm2835_gpio_irq_handler;
@@ -1251,8 +1263,10 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
        girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS,
                                     sizeof(*girq->parents),
                                     GFP_KERNEL);
-       if (!girq->parents)
+       if (!girq->parents) {
+               pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
                return -ENOMEM;
+       }
 
        if (is_7211) {
                pc->wake_irq = devm_kcalloc(dev, BCM2835_NUM_IRQS,
@@ -1307,21 +1321,10 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
        err = gpiochip_add_data(&pc->gpio_chip, pc);
        if (err) {
                dev_err(dev, "could not add GPIO chip\n");
+               pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
                return err;
        }
 
-       pc->pctl_desc = *pdata->pctl_desc;
-       pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc);
-       if (IS_ERR(pc->pctl_dev)) {
-               gpiochip_remove(&pc->gpio_chip);
-               return PTR_ERR(pc->pctl_dev);
-       }
-
-       pc->gpio_range = *pdata->gpio_range;
-       pc->gpio_range.base = pc->gpio_chip.base;
-       pc->gpio_range.gc = &pc->gpio_chip;
-       pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
-
        return 0;
 }
 
index 91553b2..5377982 100644 (file)
@@ -285,8 +285,12 @@ static int mtk_xt_get_gpio_n(void *data, unsigned long eint_n,
        desc = (const struct mtk_pin_desc *)hw->soc->pins;
        *gpio_chip = &hw->chip;
 
-       /* Be greedy to guess first gpio_n is equal to eint_n */
-       if (desc[eint_n].eint.eint_n == eint_n)
+       /*
+        * Be greedy to guess first gpio_n is equal to eint_n.
+        * Only eint virtual eint number is greater than gpio number.
+        */
+       if (hw->soc->npins > eint_n &&
+           desc[eint_n].eint.eint_n == eint_n)
                *gpio_n = eint_n;
        else
                *gpio_n = mtk_xt_find_eint_num(hw, eint_n);
index 24764eb..9ed7647 100644 (file)
@@ -1251,10 +1251,10 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl,
                bank_nr = args.args[1] / STM32_GPIO_PINS_PER_BANK;
                bank->gpio_chip.base = args.args[1];
 
-               npins = args.args[2];
-               while (!of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,
-                                                        ++i, &args))
-                       npins += args.args[2];
+               /* get the last defined gpio line (offset + nb of pins) */
+               npins = args.args[0] + args.args[2];
+               while (!of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, ++i, &args))
+                       npins = max(npins, (int)(args.args[0] + args.args[2]));
        } else {
                bank_nr = pctl->nbanks;
                bank->gpio_chip.base = bank_nr * STM32_GPIO_PINS_PER_BANK;
index 04bc3b5..65b4a81 100644 (file)
@@ -1374,8 +1374,8 @@ static int mlxbf_pmc_map_counters(struct device *dev)
                pmc->block[i].counters = info[2];
                pmc->block[i].type = info[3];
 
-               if (IS_ERR(pmc->block[i].mmio_base))
-                       return PTR_ERR(pmc->block[i].mmio_base);
+               if (!pmc->block[i].mmio_base)
+                       return -ENOMEM;
 
                ret = mlxbf_pmc_create_groups(dev, i);
                if (ret)
index 2194780..253a096 100644 (file)
@@ -68,7 +68,7 @@ obj-$(CONFIG_THINKPAD_ACPI)   += thinkpad_acpi.o
 obj-$(CONFIG_THINKPAD_LMI)     += think-lmi.o
 
 # Intel
-obj-$(CONFIG_X86_PLATFORM_DRIVERS_INTEL)               += intel/
+obj-y                          += intel/
 
 # MSI
 obj-$(CONFIG_MSI_LAPTOP)       += msi-laptop.o
index 841c44c..230593a 100644 (file)
@@ -508,7 +508,8 @@ static int __maybe_unused amd_pmc_resume(struct device *dev)
 }
 
 static const struct dev_pm_ops amd_pmc_pm_ops = {
-       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(amd_pmc_suspend, amd_pmc_resume)
+       .suspend_noirq = amd_pmc_suspend,
+       .resume_noirq = amd_pmc_resume,
 };
 
 static const struct pci_device_id pmc_pci_ids[] = {
index 9aae45a..57553f9 100644 (file)
@@ -625,7 +625,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
        }
 
        gmux_data->iostart = res->start;
-       gmux_data->iolen = res->end - res->start;
+       gmux_data->iolen = resource_size(res);
 
        if (gmux_data->iolen < GMUX_MIN_IO_LEN) {
                pr_err("gmux I/O region too small (%lu < %u)\n",
index 38ce3e3..40096b2 100644 (file)
@@ -3,19 +3,6 @@
 # Intel x86 Platform Specific Drivers
 #
 
-menuconfig X86_PLATFORM_DRIVERS_INTEL
-       bool "Intel x86 Platform Specific Device Drivers"
-       default y
-       help
-         Say Y here to get to see options for device drivers for
-         various Intel x86 platforms, including vendor-specific
-         drivers. This option alone does not add any kernel code.
-
-         If you say N, all options in this submenu will be skipped
-         and disabled.
-
-if X86_PLATFORM_DRIVERS_INTEL
-
 source "drivers/platform/x86/intel/atomisp2/Kconfig"
 source "drivers/platform/x86/intel/int1092/Kconfig"
 source "drivers/platform/x86/intel/int33fe/Kconfig"
@@ -183,5 +170,3 @@ config INTEL_UNCORE_FREQ_CONTROL
 
          To compile this driver as a module, choose M here: the module
          will be called intel-uncore-frequency.
-
-endif # X86_PLATFORM_DRIVERS_INTEL
index 7379768..15ca8af 100644 (file)
@@ -65,7 +65,7 @@ static int __init pmc_core_platform_init(void)
 
        retval = platform_device_register(pmc_core_device);
        if (retval)
-               kfree(pmc_core_device);
+               platform_device_put(pmc_core_device);
 
        return retval;
 }
index 8b292ee..7299ad0 100644 (file)
@@ -35,6 +35,7 @@ struct system76_data {
        union acpi_object *nfan;
        union acpi_object *ntmp;
        struct input_dev *input;
+       bool has_open_ec;
 };
 
 static const struct acpi_device_id device_ids[] = {
@@ -279,20 +280,12 @@ static struct acpi_battery_hook system76_battery_hook = {
 
 static void system76_battery_init(void)
 {
-       acpi_handle handle;
-
-       handle = ec_get_handle();
-       if (handle && acpi_has_method(handle, "GBCT"))
-               battery_hook_register(&system76_battery_hook);
+       battery_hook_register(&system76_battery_hook);
 }
 
 static void system76_battery_exit(void)
 {
-       acpi_handle handle;
-
-       handle = ec_get_handle();
-       if (handle && acpi_has_method(handle, "GBCT"))
-               battery_hook_unregister(&system76_battery_hook);
+       battery_hook_unregister(&system76_battery_hook);
 }
 
 // Get the airplane mode LED brightness
@@ -673,6 +666,10 @@ static int system76_add(struct acpi_device *acpi_dev)
        acpi_dev->driver_data = data;
        data->acpi_dev = acpi_dev;
 
+       // Some models do not run open EC firmware. Check for an ACPI method
+       // that only exists on open EC to guard functionality specific to it.
+       data->has_open_ec = acpi_has_method(acpi_device_handle(data->acpi_dev), "NFAN");
+
        err = system76_get(data, "INIT");
        if (err)
                return err;
@@ -718,27 +715,31 @@ static int system76_add(struct acpi_device *acpi_dev)
        if (err)
                goto error;
 
-       err = system76_get_object(data, "NFAN", &data->nfan);
-       if (err)
-               goto error;
+       if (data->has_open_ec) {
+               err = system76_get_object(data, "NFAN", &data->nfan);
+               if (err)
+                       goto error;
 
-       err = system76_get_object(data, "NTMP", &data->ntmp);
-       if (err)
-               goto error;
+               err = system76_get_object(data, "NTMP", &data->ntmp);
+               if (err)
+                       goto error;
 
-       data->therm = devm_hwmon_device_register_with_info(&acpi_dev->dev,
-               "system76_acpi", data, &thermal_chip_info, NULL);
-       err = PTR_ERR_OR_ZERO(data->therm);
-       if (err)
-               goto error;
+               data->therm = devm_hwmon_device_register_with_info(&acpi_dev->dev,
+                       "system76_acpi", data, &thermal_chip_info, NULL);
+               err = PTR_ERR_OR_ZERO(data->therm);
+               if (err)
+                       goto error;
 
-       system76_battery_init();
+               system76_battery_init();
+       }
 
        return 0;
 
 error:
-       kfree(data->ntmp);
-       kfree(data->nfan);
+       if (data->has_open_ec) {
+               kfree(data->ntmp);
+               kfree(data->nfan);
+       }
        return err;
 }
 
@@ -749,14 +750,15 @@ static int system76_remove(struct acpi_device *acpi_dev)
 
        data = acpi_driver_data(acpi_dev);
 
-       system76_battery_exit();
+       if (data->has_open_ec) {
+               system76_battery_exit();
+               kfree(data->nfan);
+               kfree(data->ntmp);
+       }
 
        devm_led_classdev_unregister(&acpi_dev->dev, &data->ap_led);
        devm_led_classdev_unregister(&acpi_dev->dev, &data->kb_led);
 
-       kfree(data->nfan);
-       kfree(data->ntmp);
-
        system76_get(data, "FINI");
 
        return 0;
index 284b939..059dae8 100644 (file)
@@ -3100,6 +3100,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
 {
        struct iscsi_conn *conn = cls_conn->dd_data;
        struct iscsi_session *session = conn->session;
+       char *tmp_persistent_address = conn->persistent_address;
+       char *tmp_local_ipaddr = conn->local_ipaddr;
 
        del_timer_sync(&conn->transport_timer);
 
@@ -3121,8 +3123,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
        spin_lock_bh(&session->frwd_lock);
        free_pages((unsigned long) conn->data,
                   get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
-       kfree(conn->persistent_address);
-       kfree(conn->local_ipaddr);
        /* regular RX path uses back_lock */
        spin_lock_bh(&session->back_lock);
        kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
@@ -3134,6 +3134,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
        mutex_unlock(&session->eh_mutex);
 
        iscsi_destroy_conn(cls_conn);
+       kfree(tmp_persistent_address);
+       kfree(tmp_local_ipaddr);
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_teardown);
 
index bd6d459..08b2e85 100644 (file)
@@ -2954,8 +2954,8 @@ lpfc_debugfs_nvmeio_trc_write(struct file *file, const char __user *buf,
        char mybuf[64];
        char *pbuf;
 
-       if (nbytes > 64)
-               nbytes = 64;
+       if (nbytes > 63)
+               nbytes = 63;
 
        memset(mybuf, 0, sizeof(mybuf));
 
index c2ba652..1f037b8 100644 (file)
@@ -586,9 +586,12 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter,
                         * Commands like INQUIRY may transfer less data than
                         * requested by the initiator via bufflen. Set residual
                         * count to make upper layer aware of the actual amount
-                        * of data returned.
+                        * of data returned. There are cases when controller
+                        * returns zero dataLen with non zero data - do not set
+                        * residual count in that case.
                         */
-                       scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen);
+                       if (e->dataLen && (e->dataLen < scsi_bufflen(cmd)))
+                               scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen);
                        cmd->result = (DID_OK << 16);
                        break;
 
index 46feafe..d8cc4b2 100644 (file)
@@ -901,7 +901,7 @@ static int a3700_spi_probe(struct platform_device *pdev)
        return 0;
 
 error_clk:
-       clk_disable_unprepare(spi->clk);
+       clk_unprepare(spi->clk);
 error:
        spi_master_put(master);
 out:
index ab2edfc..2a66a52 100644 (file)
@@ -48,10 +48,8 @@ int optee_pool_op_alloc_helper(struct tee_shm_pool_mgr *poolm,
                        goto err;
                }
 
-               for (i = 0; i < nr_pages; i++) {
-                       pages[i] = page;
-                       page++;
-               }
+               for (i = 0; i < nr_pages; i++)
+                       pages[i] = page + i;
 
                shm->flags |= TEE_SHM_REGISTER;
                rc = shm_register(shm->ctx, shm, pages, nr_pages,
index 6196d7c..cf2e329 100644 (file)
@@ -23,6 +23,7 @@
 #include "optee_private.h"
 #include "optee_smc.h"
 #include "optee_rpc_cmd.h"
+#include <linux/kmemleak.h>
 #define CREATE_TRACE_POINTS
 #include "optee_trace.h"
 
@@ -783,6 +784,7 @@ static void optee_handle_rpc(struct tee_context *ctx,
                        param->a4 = 0;
                        param->a5 = 0;
                }
+               kmemleak_not_leak(shm);
                break;
        case OPTEE_SMC_RPC_FUNC_FREE:
                shm = reg_pair_to_ptr(param->a1, param->a2);
index 8a8deb9..499fccb 100644 (file)
@@ -1,20 +1,17 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2016, Linaro Limited
+ * Copyright (c) 2015-2017, 2019-2021 Linaro Limited
  */
+#include <linux/anon_inodes.h>
 #include <linux/device.h>
-#include <linux/dma-buf.h>
-#include <linux/fdtable.h>
 #include <linux/idr.h>
+#include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/tee_drv.h>
 #include <linux/uio.h>
-#include <linux/module.h>
 #include "tee_private.h"
 
-MODULE_IMPORT_NS(DMA_BUF);
-
 static void release_registered_pages(struct tee_shm *shm)
 {
        if (shm->pages) {
@@ -31,16 +28,8 @@ static void release_registered_pages(struct tee_shm *shm)
        }
 }
 
-static void tee_shm_release(struct tee_shm *shm)
+static void tee_shm_release(struct tee_device *teedev, struct tee_shm *shm)
 {
-       struct tee_device *teedev = shm->ctx->teedev;
-
-       if (shm->flags & TEE_SHM_DMA_BUF) {
-               mutex_lock(&teedev->mutex);
-               idr_remove(&teedev->idr, shm->id);
-               mutex_unlock(&teedev->mutex);
-       }
-
        if (shm->flags & TEE_SHM_POOL) {
                struct tee_shm_pool_mgr *poolm;
 
@@ -67,45 +56,6 @@ static void tee_shm_release(struct tee_shm *shm)
        tee_device_put(teedev);
 }
 
-static struct sg_table *tee_shm_op_map_dma_buf(struct dma_buf_attachment
-                       *attach, enum dma_data_direction dir)
-{
-       return NULL;
-}
-
-static void tee_shm_op_unmap_dma_buf(struct dma_buf_attachment *attach,
-                                    struct sg_table *table,
-                                    enum dma_data_direction dir)
-{
-}
-
-static void tee_shm_op_release(struct dma_buf *dmabuf)
-{
-       struct tee_shm *shm = dmabuf->priv;
-
-       tee_shm_release(shm);
-}
-
-static int tee_shm_op_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
-{
-       struct tee_shm *shm = dmabuf->priv;
-       size_t size = vma->vm_end - vma->vm_start;
-
-       /* Refuse sharing shared memory provided by application */
-       if (shm->flags & TEE_SHM_USER_MAPPED)
-               return -EINVAL;
-
-       return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT,
-                              size, vma->vm_page_prot);
-}
-
-static const struct dma_buf_ops tee_shm_dma_buf_ops = {
-       .map_dma_buf = tee_shm_op_map_dma_buf,
-       .unmap_dma_buf = tee_shm_op_unmap_dma_buf,
-       .release = tee_shm_op_release,
-       .mmap = tee_shm_op_mmap,
-};
-
 struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
 {
        struct tee_device *teedev = ctx->teedev;
@@ -140,6 +90,7 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
                goto err_dev_put;
        }
 
+       refcount_set(&shm->refcount, 1);
        shm->flags = flags | TEE_SHM_POOL;
        shm->ctx = ctx;
        if (flags & TEE_SHM_DMA_BUF)
@@ -153,10 +104,7 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
                goto err_kfree;
        }
 
-
        if (flags & TEE_SHM_DMA_BUF) {
-               DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
-
                mutex_lock(&teedev->mutex);
                shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL);
                mutex_unlock(&teedev->mutex);
@@ -164,28 +112,11 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
                        ret = ERR_PTR(shm->id);
                        goto err_pool_free;
                }
-
-               exp_info.ops = &tee_shm_dma_buf_ops;
-               exp_info.size = shm->size;
-               exp_info.flags = O_RDWR;
-               exp_info.priv = shm;
-
-               shm->dmabuf = dma_buf_export(&exp_info);
-               if (IS_ERR(shm->dmabuf)) {
-                       ret = ERR_CAST(shm->dmabuf);
-                       goto err_rem;
-               }
        }
 
        teedev_ctx_get(ctx);
 
        return shm;
-err_rem:
-       if (flags & TEE_SHM_DMA_BUF) {
-               mutex_lock(&teedev->mutex);
-               idr_remove(&teedev->idr, shm->id);
-               mutex_unlock(&teedev->mutex);
-       }
 err_pool_free:
        poolm->ops->free(poolm, shm);
 err_kfree:
@@ -246,6 +177,7 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
                goto err;
        }
 
+       refcount_set(&shm->refcount, 1);
        shm->flags = flags | TEE_SHM_REGISTER;
        shm->ctx = ctx;
        shm->id = -1;
@@ -306,22 +238,6 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
                goto err;
        }
 
-       if (flags & TEE_SHM_DMA_BUF) {
-               DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
-
-               exp_info.ops = &tee_shm_dma_buf_ops;
-               exp_info.size = shm->size;
-               exp_info.flags = O_RDWR;
-               exp_info.priv = shm;
-
-               shm->dmabuf = dma_buf_export(&exp_info);
-               if (IS_ERR(shm->dmabuf)) {
-                       ret = ERR_CAST(shm->dmabuf);
-                       teedev->desc->ops->shm_unregister(ctx, shm);
-                       goto err;
-               }
-       }
-
        return shm;
 err:
        if (shm) {
@@ -339,6 +255,35 @@ err:
 }
 EXPORT_SYMBOL_GPL(tee_shm_register);
 
+static int tee_shm_fop_release(struct inode *inode, struct file *filp)
+{
+       tee_shm_put(filp->private_data);
+       return 0;
+}
+
+static int tee_shm_fop_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct tee_shm *shm = filp->private_data;
+       size_t size = vma->vm_end - vma->vm_start;
+
+       /* Refuse sharing shared memory provided by application */
+       if (shm->flags & TEE_SHM_USER_MAPPED)
+               return -EINVAL;
+
+       /* check for overflowing the buffer's size */
+       if (vma->vm_pgoff + vma_pages(vma) > shm->size >> PAGE_SHIFT)
+               return -EINVAL;
+
+       return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT,
+                              size, vma->vm_page_prot);
+}
+
+static const struct file_operations tee_shm_fops = {
+       .owner = THIS_MODULE,
+       .release = tee_shm_fop_release,
+       .mmap = tee_shm_fop_mmap,
+};
+
 /**
  * tee_shm_get_fd() - Increase reference count and return file descriptor
  * @shm:       Shared memory handle
@@ -351,10 +296,11 @@ int tee_shm_get_fd(struct tee_shm *shm)
        if (!(shm->flags & TEE_SHM_DMA_BUF))
                return -EINVAL;
 
-       get_dma_buf(shm->dmabuf);
-       fd = dma_buf_fd(shm->dmabuf, O_CLOEXEC);
+       /* matched by tee_shm_put() in tee_shm_op_release() */
+       refcount_inc(&shm->refcount);
+       fd = anon_inode_getfd("tee_shm", &tee_shm_fops, shm, O_RDWR);
        if (fd < 0)
-               dma_buf_put(shm->dmabuf);
+               tee_shm_put(shm);
        return fd;
 }
 
@@ -364,17 +310,7 @@ int tee_shm_get_fd(struct tee_shm *shm)
  */
 void tee_shm_free(struct tee_shm *shm)
 {
-       /*
-        * dma_buf_put() decreases the dmabuf reference counter and will
-        * call tee_shm_release() when the last reference is gone.
-        *
-        * In the case of driver private memory we call tee_shm_release
-        * directly instead as it doesn't have a reference counter.
-        */
-       if (shm->flags & TEE_SHM_DMA_BUF)
-               dma_buf_put(shm->dmabuf);
-       else
-               tee_shm_release(shm);
+       tee_shm_put(shm);
 }
 EXPORT_SYMBOL_GPL(tee_shm_free);
 
@@ -481,10 +417,15 @@ struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id)
        teedev = ctx->teedev;
        mutex_lock(&teedev->mutex);
        shm = idr_find(&teedev->idr, id);
+       /*
+        * If the tee_shm was found in the IDR it must have a refcount
+        * larger than 0 due to the guarantee in tee_shm_put() below. So
+        * it's safe to use refcount_inc().
+        */
        if (!shm || shm->ctx != ctx)
                shm = ERR_PTR(-EINVAL);
-       else if (shm->flags & TEE_SHM_DMA_BUF)
-               get_dma_buf(shm->dmabuf);
+       else
+               refcount_inc(&shm->refcount);
        mutex_unlock(&teedev->mutex);
        return shm;
 }
@@ -496,7 +437,24 @@ EXPORT_SYMBOL_GPL(tee_shm_get_from_id);
  */
 void tee_shm_put(struct tee_shm *shm)
 {
-       if (shm->flags & TEE_SHM_DMA_BUF)
-               dma_buf_put(shm->dmabuf);
+       struct tee_device *teedev = shm->ctx->teedev;
+       bool do_release = false;
+
+       mutex_lock(&teedev->mutex);
+       if (refcount_dec_and_test(&shm->refcount)) {
+               /*
+                * refcount has reached 0, we must now remove it from the
+                * IDR before releasing the mutex. This will guarantee that
+                * the refcount_inc() in tee_shm_get_from_id() never starts
+                * from 0.
+                */
+               if (shm->flags & TEE_SHM_DMA_BUF)
+                       idr_remove(&teedev->idr, shm->id);
+               do_release = true;
+       }
+       mutex_unlock(&teedev->mutex);
+
+       if (do_release)
+               tee_shm_release(teedev, shm);
 }
 EXPORT_SYMBOL_GPL(tee_shm_put);
index 43b1ae8..0bfb8ee 100644 (file)
@@ -462,7 +462,6 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
        struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
        struct cpumask *cpus;
        unsigned int frequency;
-       unsigned long max_capacity, capacity;
        int ret;
 
        /* Request state should be less than max_level */
@@ -479,10 +478,7 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
        if (ret >= 0) {
                cpufreq_cdev->cpufreq_state = state;
                cpus = cpufreq_cdev->policy->related_cpus;
-               max_capacity = arch_scale_cpu_capacity(cpumask_first(cpus));
-               capacity = frequency * max_capacity;
-               capacity /= cpufreq_cdev->policy->cpuinfo.max_freq;
-               arch_set_thermal_pressure(cpus, max_capacity - capacity);
+               arch_update_thermal_pressure(cpus, frequency);
                ret = 0;
        }
 
index 71e0dd2..ebaf750 100644 (file)
@@ -37,6 +37,8 @@ struct xencons_info {
        struct xenbus_device *xbdev;
        struct xencons_interface *intf;
        unsigned int evtchn;
+       XENCONS_RING_IDX out_cons;
+       unsigned int out_cons_same;
        struct hvc_struct *hvc;
        int irq;
        int vtermno;
@@ -138,6 +140,8 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len)
        XENCONS_RING_IDX cons, prod;
        int recv = 0;
        struct xencons_info *xencons = vtermno_to_xencons(vtermno);
+       unsigned int eoiflag = 0;
+
        if (xencons == NULL)
                return -EINVAL;
        intf = xencons->intf;
@@ -157,7 +161,27 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len)
        mb();                   /* read ring before consuming */
        intf->in_cons = cons;
 
-       notify_daemon(xencons);
+       /*
+        * When to mark interrupt having been spurious:
+        * - there was no new data to be read, and
+        * - the backend did not consume some output bytes, and
+        * - the previous round with no read data didn't see consumed bytes
+        *   (we might have a race with an interrupt being in flight while
+        *   updating xencons->out_cons, so account for that by allowing one
+        *   round without any visible reason)
+        */
+       if (intf->out_cons != xencons->out_cons) {
+               xencons->out_cons = intf->out_cons;
+               xencons->out_cons_same = 0;
+       }
+       if (recv) {
+               notify_daemon(xencons);
+       } else if (xencons->out_cons_same++ > 1) {
+               eoiflag = XEN_EOI_FLAG_SPURIOUS;
+       }
+
+       xen_irq_lateeoi(xencons->irq, eoiflag);
+
        return recv;
 }
 
@@ -386,7 +410,7 @@ static int xencons_connect_backend(struct xenbus_device *dev,
        if (ret)
                return ret;
        info->evtchn = evtchn;
-       irq = bind_evtchn_to_irq(evtchn);
+       irq = bind_interdomain_evtchn_to_irq_lateeoi(dev, evtchn);
        if (irq < 0)
                return irq;
        info->irq = irq;
@@ -551,7 +575,7 @@ static int __init xen_hvc_init(void)
                        return r;
 
                info = vtermno_to_xencons(HVC_COOKIE);
-               info->irq = bind_evtchn_to_irq(info->evtchn);
+               info->irq = bind_evtchn_to_irq_lateeoi(info->evtchn);
        }
        if (info->irq < 0)
                info->irq = 0; /* NO_IRQ */
index e20c19a..a7e069b 100644 (file)
@@ -1773,11 +1773,15 @@ static void ffs_data_clear(struct ffs_data *ffs)
 
        BUG_ON(ffs->gadget);
 
-       if (ffs->epfiles)
+       if (ffs->epfiles) {
                ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
+               ffs->epfiles = NULL;
+       }
 
-       if (ffs->ffs_eventfd)
+       if (ffs->ffs_eventfd) {
                eventfd_ctx_put(ffs->ffs_eventfd);
+               ffs->ffs_eventfd = NULL;
+       }
 
        kfree(ffs->raw_descs_data);
        kfree(ffs->raw_strings);
@@ -1790,7 +1794,6 @@ static void ffs_data_reset(struct ffs_data *ffs)
 
        ffs_data_clear(ffs);
 
-       ffs->epfiles = NULL;
        ffs->raw_descs_data = NULL;
        ffs->raw_descs = NULL;
        ffs->raw_strings = NULL;
index 3af0178..5c35197 100644 (file)
@@ -123,7 +123,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
        /* Look for vendor-specific quirks */
        if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
                        (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK ||
-                        pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1100 ||
                         pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1400)) {
                if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK &&
                                pdev->revision == 0x0) {
@@ -158,6 +157,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                        pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1009)
                xhci->quirks |= XHCI_BROKEN_STREAMS;
 
+       if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
+                       pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1100)
+               xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+
        if (pdev->vendor == PCI_VENDOR_ID_NEC)
                xhci->quirks |= XHCI_NEC_HOST;
 
index a9a65b4..9977600 100644 (file)
@@ -77,7 +77,7 @@ static int mtu3_ep_enable(struct mtu3_ep *mep)
                if (usb_endpoint_xfer_int(desc) ||
                                usb_endpoint_xfer_isoc(desc)) {
                        interval = desc->bInterval;
-                       interval = clamp_val(interval, 1, 16) - 1;
+                       interval = clamp_val(interval, 1, 16);
                        if (usb_endpoint_xfer_isoc(desc) && comp_desc)
                                mult = comp_desc->bmAttributes;
                }
@@ -89,9 +89,16 @@ static int mtu3_ep_enable(struct mtu3_ep *mep)
                if (usb_endpoint_xfer_isoc(desc) ||
                                usb_endpoint_xfer_int(desc)) {
                        interval = desc->bInterval;
-                       interval = clamp_val(interval, 1, 16) - 1;
+                       interval = clamp_val(interval, 1, 16);
                        mult = usb_endpoint_maxp_mult(desc) - 1;
                }
+               break;
+       case USB_SPEED_FULL:
+               if (usb_endpoint_xfer_isoc(desc))
+                       interval = clamp_val(desc->bInterval, 1, 16);
+               else if (usb_endpoint_xfer_int(desc))
+                       interval = clamp_val(desc->bInterval, 1, 255);
+
                break;
        default:
                break; /*others are ignored */
@@ -235,6 +242,7 @@ struct usb_request *mtu3_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
        mreq->request.dma = DMA_ADDR_INVALID;
        mreq->epnum = mep->epnum;
        mreq->mep = mep;
+       INIT_LIST_HEAD(&mreq->list);
        trace_mtu3_alloc_request(mreq);
 
        return &mreq->request;
index 3f414f9..2ea3157 100644 (file)
@@ -273,6 +273,8 @@ static int mtu3_prepare_tx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
                        gpd->dw3_info |= cpu_to_le32(GPD_EXT_FLAG_ZLP);
        }
 
+       /* prevent reorder, make sure GPD's HWO is set last */
+       mb();
        gpd->dw0_info |= cpu_to_le32(GPD_FLAGS_IOC | GPD_FLAGS_HWO);
 
        mreq->gpd = gpd;
@@ -306,6 +308,8 @@ static int mtu3_prepare_rx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
        gpd->next_gpd = cpu_to_le32(lower_32_bits(enq_dma));
        ext_addr |= GPD_EXT_NGP(mtu, upper_32_bits(enq_dma));
        gpd->dw3_info = cpu_to_le32(ext_addr);
+       /* prevent reorder, make sure GPD's HWO is set last */
+       mb();
        gpd->dw0_info |= cpu_to_le32(GPD_FLAGS_IOC | GPD_FLAGS_HWO);
 
        mreq->gpd = gpd;
@@ -445,7 +449,8 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum)
                return;
        }
        mtu3_setbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_TXPKTRDY);
-
+       /* prevent reorder, make sure GPD's HWO is set last */
+       mb();
        /* by pass the current GDP */
        gpd_current->dw0_info |= cpu_to_le32(GPD_FLAGS_BPS | GPD_FLAGS_HWO);
 
index 6aa2838..08561bf 100644 (file)
@@ -1150,7 +1150,9 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
                ret = 0;
        }
 
-       if (UCSI_CONSTAT_PWR_OPMODE(con->status.flags) == UCSI_CONSTAT_PWR_OPMODE_PD) {
+       if (con->partner &&
+           UCSI_CONSTAT_PWR_OPMODE(con->status.flags) ==
+           UCSI_CONSTAT_PWR_OPMODE_PD) {
                ucsi_get_src_pdos(con);
                ucsi_check_altmodes(con);
        }
index 8939612..6894ccb 100644 (file)
@@ -886,8 +886,9 @@ static int ne_set_user_memory_region_ioctl(struct ne_enclave *ne_enclave,
                        goto put_pages;
                }
 
-               gup_rc = get_user_pages(mem_region.userspace_addr + memory_size, 1, FOLL_GET,
-                                       ne_mem_region->pages + i, NULL);
+               gup_rc = get_user_pages_unlocked(mem_region.userspace_addr + memory_size, 1,
+                                                ne_mem_region->pages + i, FOLL_GET);
+
                if (gup_rc < 0) {
                        rc = gup_rc;
 
index a78704a..46d9295 100644 (file)
@@ -1251,6 +1251,12 @@ int bind_evtchn_to_irq(evtchn_port_t evtchn)
 }
 EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
 
+int bind_evtchn_to_irq_lateeoi(evtchn_port_t evtchn)
+{
+       return bind_evtchn_to_irq_chip(evtchn, &xen_lateeoi_chip, NULL);
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irq_lateeoi);
+
 static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
 {
        struct evtchn_bind_ipi bind_ipi;
index d5ab0e9..fb2a0cb 100644 (file)
@@ -2891,9 +2891,13 @@ static int io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe)
                req->flags |= io_file_get_flags(file) << REQ_F_SUPPORT_NOWAIT_BIT;
 
        kiocb->ki_pos = READ_ONCE(sqe->off);
-       if (kiocb->ki_pos == -1 && !(file->f_mode & FMODE_STREAM)) {
-               req->flags |= REQ_F_CUR_POS;
-               kiocb->ki_pos = file->f_pos;
+       if (kiocb->ki_pos == -1) {
+               if (!(file->f_mode & FMODE_STREAM)) {
+                       req->flags |= REQ_F_CUR_POS;
+                       kiocb->ki_pos = file->f_pos;
+               } else {
+                       kiocb->ki_pos = 0;
+               }
        }
        kiocb->ki_flags = iocb_flags(file);
        ret = kiocb_set_rw_flags(kiocb, READ_ONCE(sqe->rw_flags));
index 8317f7c..5052be9 100644 (file)
@@ -148,7 +148,7 @@ static int ndr_read_int16(struct ndr *n, __u16 *value)
 static int ndr_read_int32(struct ndr *n, __u32 *value)
 {
        if (n->offset + sizeof(__u32) > n->length)
-               return 0;
+               return -EINVAL;
 
        if (value)
                *value = le32_to_cpu(*(__le32 *)ndr_get_field(n));
index 0a5d845..02a44d2 100644 (file)
@@ -271,9 +271,6 @@ int init_smb3_11_server(struct ksmbd_conn *conn)
        if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES)
                conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING;
 
-       if (conn->cipher_type)
-               conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
-
        if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
                conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL;
 
index 49c9da3..b8b3a4c 100644 (file)
@@ -915,6 +915,25 @@ static void decode_encrypt_ctxt(struct ksmbd_conn *conn,
        }
 }
 
+/**
+ * smb3_encryption_negotiated() - checks if server and client agreed on enabling encryption
+ * @conn:      smb connection
+ *
+ * Return:     true if connection should be encrypted, else false
+ */
+static bool smb3_encryption_negotiated(struct ksmbd_conn *conn)
+{
+       if (!conn->ops->generate_encryptionkey)
+               return false;
+
+       /*
+        * SMB 3.0 and 3.0.2 dialects use the SMB2_GLOBAL_CAP_ENCRYPTION flag.
+        * SMB 3.1.1 uses the cipher_type field.
+        */
+       return (conn->vals->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) ||
+           conn->cipher_type;
+}
+
 static void decode_compress_ctxt(struct ksmbd_conn *conn,
                                 struct smb2_compression_capabilities_context *pneg_ctxt)
 {
@@ -1469,8 +1488,7 @@ static int ntlm_authenticate(struct ksmbd_work *work)
                    (req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED))
                        sess->sign = true;
 
-               if (conn->vals->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION &&
-                   conn->ops->generate_encryptionkey &&
+               if (smb3_encryption_negotiated(conn) &&
                    !(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
                        rc = conn->ops->generate_encryptionkey(sess);
                        if (rc) {
@@ -1559,8 +1577,7 @@ static int krb5_authenticate(struct ksmbd_work *work)
            (req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED))
                sess->sign = true;
 
-       if ((conn->vals->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) &&
-           conn->ops->generate_encryptionkey) {
+       if (smb3_encryption_negotiated(conn)) {
                retval = conn->ops->generate_encryptionkey(sess);
                if (retval) {
                        ksmbd_debug(SMB,
@@ -2962,6 +2979,10 @@ int smb2_open(struct ksmbd_work *work)
                                                            &pntsd_size, &fattr);
                                        posix_acl_release(fattr.cf_acls);
                                        posix_acl_release(fattr.cf_dacls);
+                                       if (rc) {
+                                               kfree(pntsd);
+                                               goto err_out;
+                                       }
 
                                        rc = ksmbd_vfs_set_sd_xattr(conn,
                                                                    user_ns,
index 659a8f3..b696543 100644 (file)
@@ -4263,12 +4263,11 @@ SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path,
                return err;
 
        err = user_path_at(dfd, path, kattr.lookup_flags, &target);
-       if (err)
-               return err;
-
-       err = do_mount_setattr(&target, &kattr);
+       if (!err) {
+               err = do_mount_setattr(&target, &kattr);
+               path_put(&target);
+       }
        finish_mount_kattr(&kattr);
-       path_put(&target);
        return err;
 }
 
index 4418517..15dac36 100644 (file)
@@ -438,22 +438,19 @@ nfsd3_proc_link(struct svc_rqst *rqstp)
 
 static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,
                                     struct nfsd3_readdirres *resp,
-                                    int count)
+                                    u32 count)
 {
        struct xdr_buf *buf = &resp->dirlist;
        struct xdr_stream *xdr = &resp->xdr;
 
-       count = min_t(u32, count, svc_max_payload(rqstp));
+       count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp));
 
        memset(buf, 0, sizeof(*buf));
 
        /* Reserve room for the NULL ptr & eof flag (-2 words) */
        buf->buflen = count - XDR_UNIT * 2;
        buf->pages = rqstp->rq_next_page;
-       while (count > 0) {
-               rqstp->rq_next_page++;
-               count -= PAGE_SIZE;
-       }
+       rqstp->rq_next_page += (buf->buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
        /* This is xdr_init_encode(), but it assumes that
         * the head kvec has already been consumed. */
@@ -462,7 +459,7 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,
        xdr->page_ptr = buf->pages;
        xdr->iov = NULL;
        xdr->p = page_address(*buf->pages);
-       xdr->end = xdr->p + (PAGE_SIZE >> 2);
+       xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE);
        xdr->rqst = NULL;
 }
 
index eea5b59..de282f3 100644 (file)
@@ -556,17 +556,17 @@ nfsd_proc_rmdir(struct svc_rqst *rqstp)
 
 static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp,
                                    struct nfsd_readdirres *resp,
-                                   int count)
+                                   u32 count)
 {
        struct xdr_buf *buf = &resp->dirlist;
        struct xdr_stream *xdr = &resp->xdr;
 
-       count = min_t(u32, count, PAGE_SIZE);
+       count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp));
 
        memset(buf, 0, sizeof(*buf));
 
        /* Reserve room for the NULL ptr & eof flag (-2 words) */
-       buf->buflen = count - sizeof(__be32) * 2;
+       buf->buflen = count - XDR_UNIT * 2;
        buf->pages = rqstp->rq_next_page;
        rqstp->rq_next_page++;
 
@@ -577,7 +577,7 @@ static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp,
        xdr->page_ptr = buf->pages;
        xdr->iov = NULL;
        xdr->p = page_address(*buf->pages);
-       xdr->end = xdr->p + (PAGE_SIZE >> 2);
+       xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE);
        xdr->rqst = NULL;
 }
 
index bc159a9..92b7ea8 100644 (file)
@@ -138,6 +138,7 @@ extern int cppc_get_desired_perf(int cpunum, u64 *desired_perf);
 extern int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf);
 extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs);
 extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
+extern int cppc_set_enable(int cpu, bool enable);
 extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps);
 extern bool acpi_cpc_valid(void);
 extern int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data);
@@ -162,6 +163,10 @@ static inline int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 {
        return -ENOTSUPP;
 }
+static inline int cppc_set_enable(int cpu, bool enable)
+{
+       return -ENOTSUPP;
+}
 static inline int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps)
 {
        return -ENOTSUPP;
index b28f879..6c0798d 100644 (file)
@@ -506,7 +506,7 @@ acpi_status acpi_release_memory(acpi_handle handle, struct resource *res,
 int acpi_resources_are_enforced(void);
 
 #ifdef CONFIG_HIBERNATION
-void __init acpi_no_s4_hw_signature(void);
+void __init acpi_check_s4_hw_signature(int check);
 #endif
 
 #ifdef CONFIG_PM_SLEEP
index b97cea8..cce6136 100644 (file)
@@ -56,8 +56,8 @@ static inline unsigned long topology_get_thermal_pressure(int cpu)
        return per_cpu(thermal_pressure, cpu);
 }
 
-void topology_set_thermal_pressure(const struct cpumask *cpus,
-                                  unsigned long th_pressure);
+void topology_update_thermal_pressure(const struct cpumask *cpus,
+                                     unsigned long capped_freq);
 
 struct cpu_topology {
        int thread_id;
index 3d5af56..429dceb 100644 (file)
@@ -121,7 +121,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
        asm volatile(__stringify_label(c) ":\n\t"                       \
                     ".pushsection .discard.reachable\n\t"              \
                     ".long " __stringify_label(c) "b - .\n\t"          \
-                    ".popsection\n\t");                                \
+                    ".popsection\n\t" : : "i" (c));                    \
 })
 #define annotate_reachable() __annotate_reachable(__COUNTER__)
 
@@ -129,7 +129,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
        asm volatile(__stringify_label(c) ":\n\t"                       \
                     ".pushsection .discard.unreachable\n\t"            \
                     ".long " __stringify_label(c) "b - .\n\t"          \
-                    ".popsection\n\t");                                \
+                    ".popsection\n\t" : : "i" (c));                    \
 })
 #define annotate_unreachable() __annotate_unreachable(__COUNTER__)
 
index dbd39b2..ef8dbc0 100644 (file)
@@ -1283,4 +1283,10 @@ static inline struct efi_mokvar_table_entry *efi_mokvar_entry_find(
 }
 #endif
 
+#ifdef CONFIG_SYSFB
+extern void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
+#else
+static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt) { }
+#endif
+
 #endif /* _LINUX_EFI_H */
index b976c41..8fcc384 100644 (file)
@@ -624,7 +624,7 @@ extern unsigned long get_zeroed_page(gfp_t gfp_mask);
 
 void *alloc_pages_exact(size_t size, gfp_t gfp_mask) __alloc_size(1);
 void free_pages_exact(void *virt, size_t size);
-__meminit void *alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask) __alloc_size(1);
+__meminit void *alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask) __alloc_size(2);
 
 #define __get_free_page(gfp_mask) \
                __get_free_pages((gfp_mask), 0)
index fa2cd8c..24359b4 100644 (file)
@@ -11,7 +11,7 @@
        asm volatile(__stringify(c) ": nop\n\t"                         \
                     ".pushsection .discard.instr_begin\n\t"            \
                     ".long " __stringify(c) "b - .\n\t"                \
-                    ".popsection\n\t");                                \
+                    ".popsection\n\t" : : "i" (c));                    \
 })
 #define instrumentation_begin() __instrumentation_begin(__COUNTER__)
 
@@ -50,7 +50,7 @@
        asm volatile(__stringify(c) ": nop\n\t"                         \
                     ".pushsection .discard.instr_end\n\t"              \
                     ".long " __stringify(c) "b - .\n\t"                \
-                    ".popsection\n\t");                                \
+                    ".popsection\n\t" : : "i" (c));                    \
 })
 #define instrumentation_end() __instrumentation_end(__COUNTER__)
 #else
index 8adcf1f..9dc7cb2 100644 (file)
@@ -405,8 +405,8 @@ phys_addr_t memblock_alloc_range_nid(phys_addr_t size,
                                      phys_addr_t end, int nid, bool exact_nid);
 phys_addr_t memblock_phys_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid);
 
-static inline phys_addr_t memblock_phys_alloc(phys_addr_t size,
-                                             phys_addr_t align)
+static __always_inline phys_addr_t memblock_phys_alloc(phys_addr_t size,
+                                                      phys_addr_t align)
 {
        return memblock_phys_alloc_range(size, align, 0,
                                         MEMBLOCK_ALLOC_ACCESSIBLE);
index 58e744b..936dc0b 100644 (file)
@@ -277,6 +277,7 @@ enum vmscan_throttle_state {
        VMSCAN_THROTTLE_WRITEBACK,
        VMSCAN_THROTTLE_ISOLATED,
        VMSCAN_THROTTLE_NOPROGRESS,
+       VMSCAN_THROTTLE_CONGESTED,
        NR_VMSCAN_THROTTLE,
 };
 
index be5cb33..6aadcc0 100644 (file)
@@ -1937,7 +1937,7 @@ enum netdev_ml_priv_type {
  *     @udp_tunnel_nic:        UDP tunnel offload state
  *     @xdp_state:             stores info on attached XDP BPF programs
  *
- *     @nested_level:  Used as as a parameter of spin_lock_nested() of
+ *     @nested_level:  Used as a parameter of spin_lock_nested() of
  *                     dev->addr_list_lock.
  *     @unlink_list:   As netif_addr_lock() can be called recursively,
  *                     keep a list of interfaces to be deleted.
index 6052464..d150a90 100644 (file)
@@ -285,7 +285,6 @@ static inline struct inode *folio_inode(struct folio *folio)
 
 static inline bool page_cache_add_speculative(struct page *page, int count)
 {
-       VM_BUG_ON_PAGE(PageTail(page), page);
        return folio_ref_try_add_rcu((struct folio *)page, count);
 }
 
index 1d8209c..e1e9402 100644 (file)
@@ -300,47 +300,59 @@ struct dev_pm_ops {
        int (*runtime_idle)(struct device *dev);
 };
 
+#define SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
+       .suspend = pm_sleep_ptr(suspend_fn), \
+       .resume = pm_sleep_ptr(resume_fn), \
+       .freeze = pm_sleep_ptr(suspend_fn), \
+       .thaw = pm_sleep_ptr(resume_fn), \
+       .poweroff = pm_sleep_ptr(suspend_fn), \
+       .restore = pm_sleep_ptr(resume_fn),
+
+#define LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
+       .suspend_late = pm_sleep_ptr(suspend_fn), \
+       .resume_early = pm_sleep_ptr(resume_fn), \
+       .freeze_late = pm_sleep_ptr(suspend_fn), \
+       .thaw_early = pm_sleep_ptr(resume_fn), \
+       .poweroff_late = pm_sleep_ptr(suspend_fn), \
+       .restore_early = pm_sleep_ptr(resume_fn),
+
+#define NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
+       .suspend_noirq = pm_sleep_ptr(suspend_fn), \
+       .resume_noirq = pm_sleep_ptr(resume_fn), \
+       .freeze_noirq = pm_sleep_ptr(suspend_fn), \
+       .thaw_noirq = pm_sleep_ptr(resume_fn), \
+       .poweroff_noirq = pm_sleep_ptr(suspend_fn), \
+       .restore_noirq = pm_sleep_ptr(resume_fn),
+
+#define RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
+       .runtime_suspend = suspend_fn, \
+       .runtime_resume = resume_fn, \
+       .runtime_idle = idle_fn,
+
 #ifdef CONFIG_PM_SLEEP
 #define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
-       .suspend = suspend_fn, \
-       .resume = resume_fn, \
-       .freeze = suspend_fn, \
-       .thaw = resume_fn, \
-       .poweroff = suspend_fn, \
-       .restore = resume_fn,
+       SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
 #else
 #define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
 #endif
 
 #ifdef CONFIG_PM_SLEEP
 #define SET_LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
-       .suspend_late = suspend_fn, \
-       .resume_early = resume_fn, \
-       .freeze_late = suspend_fn, \
-       .thaw_early = resume_fn, \
-       .poweroff_late = suspend_fn, \
-       .restore_early = resume_fn,
+       LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
 #else
 #define SET_LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
 #endif
 
 #ifdef CONFIG_PM_SLEEP
 #define SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
-       .suspend_noirq = suspend_fn, \
-       .resume_noirq = resume_fn, \
-       .freeze_noirq = suspend_fn, \
-       .thaw_noirq = resume_fn, \
-       .poweroff_noirq = suspend_fn, \
-       .restore_noirq = resume_fn,
+       NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
 #else
 #define SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
 #endif
 
 #ifdef CONFIG_PM
 #define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
-       .runtime_suspend = suspend_fn, \
-       .runtime_resume = resume_fn, \
-       .runtime_idle = idle_fn,
+       RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn)
 #else
 #define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn)
 #endif
@@ -349,9 +361,9 @@ struct dev_pm_ops {
  * Use this if you want to use the same suspend and resume callbacks for suspend
  * to RAM and hibernation.
  */
-#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
-const struct dev_pm_ops __maybe_unused name = { \
-       SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
+#define DEFINE_SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
+static const struct dev_pm_ops name = { \
+       SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
 }
 
 /*
@@ -367,17 +379,27 @@ const struct dev_pm_ops __maybe_unused name = { \
  * .resume_early(), to the same routines as .runtime_suspend() and
  * .runtime_resume(), respectively (and analogously for hibernation).
  */
+#define DEFINE_UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \
+static const struct dev_pm_ops name = { \
+       SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
+       RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
+}
+
+/* Deprecated. Use DEFINE_SIMPLE_DEV_PM_OPS() instead. */
+#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
+const struct dev_pm_ops __maybe_unused name = { \
+       SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
+}
+
+/* Deprecated. Use DEFINE_UNIVERSAL_DEV_PM_OPS() instead. */
 #define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \
 const struct dev_pm_ops __maybe_unused name = { \
        SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
        SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
 }
 
-#ifdef CONFIG_PM
-#define pm_ptr(_ptr) (_ptr)
-#else
-#define pm_ptr(_ptr) NULL
-#endif
+#define pm_ptr(_ptr) PTR_IF(IS_ENABLED(CONFIG_PM), (_ptr))
+#define pm_sleep_ptr(_ptr) PTR_IF(IS_ENABLED(CONFIG_PM_SLEEP), (_ptr))
 
 /*
  * PM_EVENT_ messages
@@ -499,6 +521,7 @@ const struct dev_pm_ops __maybe_unused name = { \
  */
 
 enum rpm_status {
+       RPM_INVALID = -1,
        RPM_ACTIVE = 0,
        RPM_RESUMING,
        RPM_SUSPENDED,
@@ -612,6 +635,7 @@ struct dev_pm_info {
        unsigned int            links_count;
        enum rpm_request        request;
        enum rpm_status         runtime_status;
+       enum rpm_status         last_status;
        int                     runtime_error;
        int                     autosuspend_delay;
        u64                     last_busy;
index eddd66d..016de57 100644 (file)
@@ -58,6 +58,7 @@ extern void pm_runtime_get_suppliers(struct device *dev);
 extern void pm_runtime_put_suppliers(struct device *dev);
 extern void pm_runtime_new_link(struct device *dev);
 extern void pm_runtime_drop_link(struct device_link *link);
+extern void pm_runtime_release_supplier(struct device_link *link, bool check_idle);
 
 extern int devm_pm_runtime_enable(struct device *dev);
 
@@ -283,6 +284,8 @@ static inline void pm_runtime_get_suppliers(struct device *dev) {}
 static inline void pm_runtime_put_suppliers(struct device *dev) {}
 static inline void pm_runtime_new_link(struct device *dev) {}
 static inline void pm_runtime_drop_link(struct device_link *link) {}
+static inline void pm_runtime_release_supplier(struct device_link *link,
+                                              bool check_idle) {}
 
 #endif /* !CONFIG_PM */
 
index c07bfa2..8054641 100644 (file)
@@ -266,10 +266,10 @@ unsigned long arch_scale_thermal_pressure(int cpu)
 }
 #endif
 
-#ifndef arch_set_thermal_pressure
+#ifndef arch_update_thermal_pressure
 static __always_inline
-void arch_set_thermal_pressure(const struct cpumask *cpus,
-                              unsigned long th_pressure)
+void arch_update_thermal_pressure(const struct cpumask *cpus,
+                                 unsigned long capped_frequency)
 { }
 #endif
 
index c8cb7e6..4507d77 100644 (file)
@@ -286,6 +286,7 @@ struct nf_bridge_info {
 struct tc_skb_ext {
        __u32 chain;
        __u16 mru;
+       __u16 zone;
        bool post_ct;
 };
 #endif
@@ -1380,7 +1381,7 @@ skb_flow_dissect_ct(const struct sk_buff *skb,
                    struct flow_dissector *flow_dissector,
                    void *target_container,
                    u16 *ctinfo_map, size_t mapsize,
-                   bool post_ct);
+                   bool post_ct, u16 zone);
 void
 skb_flow_dissect_tunnel_info(const struct sk_buff *skb,
                             struct flow_dissector *flow_dissector,
index 8af13ba..5785d90 100644 (file)
@@ -446,6 +446,7 @@ extern unsigned long get_safe_page(gfp_t gfp_mask);
 extern asmlinkage int swsusp_arch_suspend(void);
 extern asmlinkage int swsusp_arch_resume(void);
 
+extern u32 swsusp_hardware_signature;
 extern void hibernation_set_ops(const struct platform_hibernation_ops *ops);
 extern int hibernate(void);
 extern bool system_entering_hibernation(void);
index a1f0346..cf59996 100644 (file)
@@ -195,7 +195,7 @@ int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
  * @offset:    offset of buffer in user space
  * @pages:     locked pages from userspace
  * @num_pages: number of locked pages
- * @dmabuf:    dmabuf used to for exporting to user space
+ * @refcount:  reference counter
  * @flags:     defined by TEE_SHM_* in tee_drv.h
  * @id:                unique id of a shared memory object on this device, shared
  *             with user space
@@ -214,7 +214,7 @@ struct tee_shm {
        unsigned int offset;
        struct page **pages;
        size_t num_pages;
-       struct dma_buf *dmabuf;
+       refcount_t refcount;
        u32 flags;
        int id;
        u64 sec_world_id;
index 04e87f4..a960de6 100644 (file)
@@ -7,9 +7,27 @@
 #include <uapi/linux/udp.h>
 #include <uapi/linux/virtio_net.h>
 
+static inline bool virtio_net_hdr_match_proto(__be16 protocol, __u8 gso_type)
+{
+       switch (gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
+       case VIRTIO_NET_HDR_GSO_TCPV4:
+               return protocol == cpu_to_be16(ETH_P_IP);
+       case VIRTIO_NET_HDR_GSO_TCPV6:
+               return protocol == cpu_to_be16(ETH_P_IPV6);
+       case VIRTIO_NET_HDR_GSO_UDP:
+               return protocol == cpu_to_be16(ETH_P_IP) ||
+                      protocol == cpu_to_be16(ETH_P_IPV6);
+       default:
+               return false;
+       }
+}
+
 static inline int virtio_net_hdr_set_proto(struct sk_buff *skb,
                                           const struct virtio_net_hdr *hdr)
 {
+       if (skb->protocol)
+               return 0;
+
        switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
        case VIRTIO_NET_HDR_GSO_TCPV4:
        case VIRTIO_NET_HDR_GSO_UDP:
@@ -88,9 +106,12 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
                        if (!skb->protocol) {
                                __be16 protocol = dev_parse_header_protocol(skb);
 
-                               virtio_net_hdr_set_proto(skb, hdr);
-                               if (protocol && protocol != skb->protocol)
+                               if (!protocol)
+                                       virtio_net_hdr_set_proto(skb, hdr);
+                               else if (!virtio_net_hdr_match_proto(protocol, hdr->gso_type))
                                        return -EINVAL;
+                               else
+                                       skb->protocol = protocol;
                        }
 retry:
                        if (!skb_flow_dissect_flow_keys_basic(NULL, skb, &keys,
index bf79f3a..9e71691 100644 (file)
@@ -193,4 +193,20 @@ static inline void skb_txtime_consumed(struct sk_buff *skb)
        skb->tstamp = ktime_set(0, 0);
 }
 
+struct tc_skb_cb {
+       struct qdisc_skb_cb qdisc_cb;
+
+       u16 mru;
+       bool post_ct;
+       u16 zone; /* Only valid if post_ct = true */
+};
+
+static inline struct tc_skb_cb *tc_skb_cb(const struct sk_buff *skb)
+{
+       struct tc_skb_cb *cb = (struct tc_skb_cb *)skb->cb;
+
+       BUILD_BUG_ON(sizeof(*cb) > sizeof_field(struct sk_buff, cb));
+       return cb;
+}
+
 #endif
index 22179b2..c70e6d2 100644 (file)
@@ -447,8 +447,6 @@ struct qdisc_skb_cb {
        };
 #define QDISC_CB_PRIV_LEN 20
        unsigned char           data[QDISC_CB_PRIV_LEN];
-       u16                     mru;
-       bool                    post_ct;
 };
 
 typedef void tcf_chain_head_change_t(struct tcf_proto *tp_head, void *priv);
index 189fdb9..d314a18 100644 (file)
@@ -105,6 +105,7 @@ extern struct percpu_counter sctp_sockets_allocated;
 int sctp_asconf_mgmt(struct sctp_sock *, struct sctp_sockaddr_entry *);
 struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
 
+typedef int (*sctp_callback_t)(struct sctp_endpoint *, struct sctp_transport *, void *);
 void sctp_transport_walk_start(struct rhashtable_iter *iter);
 void sctp_transport_walk_stop(struct rhashtable_iter *iter);
 struct sctp_transport *sctp_transport_get_next(struct net *net,
@@ -115,9 +116,8 @@ int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *),
                                  struct net *net,
                                  const union sctp_addr *laddr,
                                  const union sctp_addr *paddr, void *p);
-int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *),
-                           int (*cb_done)(struct sctp_transport *, void *),
-                           struct net *net, int *pos, void *p);
+int sctp_transport_traverse_process(sctp_callback_t cb, sctp_callback_t cb_done,
+                                   struct net *net, int *pos, void *p);
 int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *), void *p);
 int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc,
                       struct sctp_info *info);
index 899c29c..8dabd88 100644 (file)
@@ -1355,6 +1355,7 @@ struct sctp_endpoint {
              reconf_enable:1;
 
        __u8  strreset_enable;
+       struct rcu_head rcu;
 };
 
 /* Recover the outter endpoint structure. */
@@ -1370,7 +1371,7 @@ static inline struct sctp_endpoint *sctp_ep(struct sctp_ep_common *base)
 struct sctp_endpoint *sctp_endpoint_new(struct sock *, gfp_t);
 void sctp_endpoint_free(struct sctp_endpoint *);
 void sctp_endpoint_put(struct sctp_endpoint *);
-void sctp_endpoint_hold(struct sctp_endpoint *);
+int sctp_endpoint_hold(struct sctp_endpoint *ep);
 void sctp_endpoint_add_asoc(struct sctp_endpoint *, struct sctp_association *);
 struct sctp_association *sctp_endpoint_lookup_assoc(
        const struct sctp_endpoint *ep,
index bea21ff..d47e965 100644 (file)
@@ -431,7 +431,7 @@ struct sock {
 #ifdef CONFIG_XFRM
        struct xfrm_policy __rcu *sk_policy[2];
 #endif
-       struct dst_entry        *sk_rx_dst;
+       struct dst_entry __rcu  *sk_rx_dst;
        int                     sk_rx_dst_ifindex;
        u32                     sk_rx_dst_cookie;
 
index f25a614..ca2e900 100644 (file)
 #define _VMSCAN_THROTTLE_WRITEBACK     (1 << VMSCAN_THROTTLE_WRITEBACK)
 #define _VMSCAN_THROTTLE_ISOLATED      (1 << VMSCAN_THROTTLE_ISOLATED)
 #define _VMSCAN_THROTTLE_NOPROGRESS    (1 << VMSCAN_THROTTLE_NOPROGRESS)
+#define _VMSCAN_THROTTLE_CONGESTED     (1 << VMSCAN_THROTTLE_CONGESTED)
 
 #define show_throttle_flags(flags)                                             \
        (flags) ? __print_flags(flags, "|",                                     \
                {_VMSCAN_THROTTLE_WRITEBACK,    "VMSCAN_THROTTLE_WRITEBACK"},   \
                {_VMSCAN_THROTTLE_ISOLATED,     "VMSCAN_THROTTLE_ISOLATED"},    \
-               {_VMSCAN_THROTTLE_NOPROGRESS,   "VMSCAN_THROTTLE_NOPROGRESS"}   \
+               {_VMSCAN_THROTTLE_NOPROGRESS,   "VMSCAN_THROTTLE_NOPROGRESS"},  \
+               {_VMSCAN_THROTTLE_CONGESTED,    "VMSCAN_THROTTLE_CONGESTED"}    \
                ) : "VMSCAN_THROTTLE_NONE"
 
 
index 2199adc..80aa5c4 100644 (file)
@@ -9,6 +9,7 @@
 #define __BIG_ENDIAN_BITFIELD
 #endif
 
+#include <linux/stddef.h>
 #include <linux/types.h>
 #include <linux/swab.h>
 
index 601c904..cd98982 100644 (file)
@@ -9,6 +9,7 @@
 #define __LITTLE_ENDIAN_BITFIELD
 #endif
 
+#include <linux/stddef.h>
 #include <linux/types.h>
 #include <linux/swab.h>
 
index f6e3c8c..4fa4e97 100644 (file)
@@ -263,7 +263,7 @@ enum nfc_sdp_attr {
 #define NFC_SE_ENABLED  0x1
 
 struct sockaddr_nfc {
-       sa_family_t sa_family;
+       __kernel_sa_family_t sa_family;
        __u32 dev_idx;
        __u32 target_idx;
        __u32 nfc_protocol;
@@ -271,14 +271,14 @@ struct sockaddr_nfc {
 
 #define NFC_LLCP_MAX_SERVICE_NAME 63
 struct sockaddr_nfc_llcp {
-       sa_family_t sa_family;
+       __kernel_sa_family_t sa_family;
        __u32 dev_idx;
        __u32 target_idx;
        __u32 nfc_protocol;
        __u8 dsap; /* Destination SAP, if known */
        __u8 ssap; /* Source SAP to be bound to */
        char service_name[NFC_LLCP_MAX_SERVICE_NAME]; /* Service name URI */;
-       size_t service_name_len;
+       __kernel_size_t service_name_len;
 };
 
 /* NFC socket protocols */
index c204262..344081e 100644 (file)
@@ -17,6 +17,7 @@ struct xenbus_device;
 unsigned xen_evtchn_nr_channels(void);
 
 int bind_evtchn_to_irq(evtchn_port_t evtchn);
+int bind_evtchn_to_irq_lateeoi(evtchn_port_t evtchn);
 int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
                              irq_handler_t handler,
                              unsigned long irqflags, const char *devname,
index 4b7bac1..69da9c4 100644 (file)
@@ -550,7 +550,7 @@ config SCHED_THERMAL_PRESSURE
          i.e. put less load on throttled CPUs than on non/less throttled ones.
 
          This requires the architecture to implement
-         arch_set_thermal_pressure() and arch_scale_thermal_pressure().
+         arch_update_thermal_pressure() and arch_scale_thermal_pressure().
 
 config BSD_PROCESS_ACCT
        bool "BSD Process Accounting"
index eb53f5e..256cf6d 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/buildid.h>
 #include <linux/crash_core.h>
+#include <linux/init.h>
 #include <linux/utsname.h>
 #include <linux/vmalloc.h>
 
@@ -295,6 +296,16 @@ int __init parse_crashkernel_low(char *cmdline,
                                "crashkernel=", suffix_tbl[SUFFIX_LOW]);
 }
 
+/*
+ * Add a dummy early_param handler to mark crashkernel= as a known command line
+ * parameter and suppress incorrect warnings in init/main.c.
+ */
+static int __init parse_crashkernel_dummy(char *arg)
+{
+       return 0;
+}
+early_param("crashkernel", parse_crashkernel_dummy);
+
 Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type,
                          void *data, size_t data_len)
 {
index 326f8d0..b4f4339 100644 (file)
@@ -170,6 +170,7 @@ extern int swsusp_swap_in_use(void);
 #define SF_PLATFORM_MODE       1
 #define SF_NOCOMPRESS_MODE     2
 #define SF_CRC32_MODE          4
+#define SF_HW_SIG              8
 
 /* kernel/power/hibernate.c */
 extern int swsusp_check(void);
index ff326c2..ad10359 100644 (file)
@@ -36,6 +36,8 @@
 
 #define HIBERNATE_SIG  "S1SUSPEND"
 
+u32 swsusp_hardware_signature;
+
 /*
  * When reading an {un,}compressed image, we may restore pages in place,
  * in which case some architectures need these pages cleaning before they
@@ -104,7 +106,8 @@ struct swap_map_handle {
 
 struct swsusp_header {
        char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int) -
-                     sizeof(u32)];
+                     sizeof(u32) - sizeof(u32)];
+       u32     hw_sig;
        u32     crc32;
        sector_t image;
        unsigned int flags;     /* Flags to pass to the "boot" kernel */
@@ -312,7 +315,6 @@ static int hib_wait_io(struct hib_bio_batch *hb)
 /*
  * Saving part
  */
-
 static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
 {
        int error;
@@ -324,6 +326,10 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
                memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
                memcpy(swsusp_header->sig, HIBERNATE_SIG, 10);
                swsusp_header->image = handle->first_sector;
+               if (swsusp_hardware_signature) {
+                       swsusp_header->hw_sig = swsusp_hardware_signature;
+                       flags |= SF_HW_SIG;
+               }
                swsusp_header->flags = flags;
                if (flags & SF_CRC32_MODE)
                        swsusp_header->crc32 = handle->crc32;
@@ -1537,6 +1543,12 @@ int swsusp_check(void)
                } else {
                        error = -EINVAL;
                }
+               if (!error && swsusp_header->flags & SF_HW_SIG &&
+                   swsusp_header->hw_sig != swsusp_hardware_signature) {
+                       pr_info("Suspend image hardware signature mismatch (%08x now %08x); aborting resume.\n",
+                               swsusp_header->hw_sig, swsusp_hardware_signature);
+                       error = -EINVAL;
+               }
 
 put:
                if (error)
index 4f5613d..7b32c35 100644 (file)
@@ -264,15 +264,16 @@ void dec_ucount(struct ucounts *ucounts, enum ucount_type type)
 long inc_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v)
 {
        struct ucounts *iter;
+       long max = LONG_MAX;
        long ret = 0;
 
        for (iter = ucounts; iter; iter = iter->ns->ucounts) {
-               long max = READ_ONCE(iter->ns->ucount_max[type]);
                long new = atomic_long_add_return(v, &iter->ucount[type]);
                if (new < 0 || new > max)
                        ret = LONG_MAX;
                else if (iter == ucounts)
                        ret = new;
+               max = READ_ONCE(iter->ns->ucount_max[type]);
        }
        return ret;
 }
@@ -312,15 +313,16 @@ long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum ucount_type type)
 {
        /* Caller must hold a reference to ucounts */
        struct ucounts *iter;
+       long max = LONG_MAX;
        long dec, ret = 0;
 
        for (iter = ucounts; iter; iter = iter->ns->ucounts) {
-               long max = READ_ONCE(iter->ns->ucount_max[type]);
                long new = atomic_long_add_return(1, &iter->ucount[type]);
                if (new < 0 || new > max)
                        goto unwind;
                if (iter == ucounts)
                        ret = new;
+               max = READ_ONCE(iter->ns->ucount_max[type]);
                /*
                 * Grab an extra ucount reference for the caller when
                 * the rlimit count was previously 0.
@@ -339,15 +341,16 @@ unwind:
        return 0;
 }
 
-bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long max)
+bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long rlimit)
 {
        struct ucounts *iter;
-       if (get_ucounts_value(ucounts, type) > max)
-               return true;
+       long max = rlimit;
+       if (rlimit > LONG_MAX)
+               max = LONG_MAX;
        for (iter = ucounts; iter; iter = iter->ns->ucounts) {
-               max = READ_ONCE(iter->ns->ucount_max[type]);
                if (get_ucounts_value(iter, type) > max)
                        return true;
+               max = READ_ONCE(iter->ns->ucount_max[type]);
        }
        return false;
 }
index 1efac00..ad65436 100644 (file)
@@ -353,6 +353,7 @@ static ssize_t dbgfs_target_ids_write(struct file *file,
                const char __user *buf, size_t count, loff_t *ppos)
 {
        struct damon_ctx *ctx = file->private_data;
+       struct damon_target *t, *next_t;
        bool id_is_pid = true;
        char *kbuf, *nrs;
        unsigned long *targets;
@@ -397,8 +398,12 @@ static ssize_t dbgfs_target_ids_write(struct file *file,
                goto unlock_out;
        }
 
-       /* remove targets with previously-set primitive */
-       damon_set_targets(ctx, NULL, 0);
+       /* remove previously set targets */
+       damon_for_each_target_safe(t, next_t, ctx) {
+               if (targetid_is_pid(ctx))
+                       put_pid((struct pid *)t->id);
+               damon_destroy_target(t);
+       }
 
        /* Configure the context for the address space type */
        if (id_is_pid)
@@ -650,10 +655,12 @@ static void dbgfs_before_terminate(struct damon_ctx *ctx)
        if (!targetid_is_pid(ctx))
                return;
 
+       mutex_lock(&ctx->kdamond_lock);
        damon_for_each_target_safe(t, next, ctx) {
                put_pid((struct pid *)t->id);
                damon_destroy_target(t);
        }
+       mutex_unlock(&ctx->kdamond_lock);
 }
 
 static struct damon_ctx *dbgfs_new_ctx(void)
index 0994578..a19154a 100644 (file)
@@ -683,6 +683,7 @@ static const struct file_operations objects_fops = {
        .open = open_objects,
        .read = seq_read,
        .llseek = seq_lseek,
+       .release = seq_release,
 };
 
 static int __init kfence_debugfs_init(void)
index 07c875f..3a27446 100644 (file)
@@ -1470,17 +1470,12 @@ static int memory_failure_hugetlb(unsigned long pfn, int flags)
        if (!(flags & MF_COUNT_INCREASED)) {
                res = get_hwpoison_page(p, flags);
                if (!res) {
-                       /*
-                        * Check "filter hit" and "race with other subpage."
-                        */
                        lock_page(head);
-                       if (PageHWPoison(head)) {
-                               if ((hwpoison_filter(p) && TestClearPageHWPoison(p))
-                                   || (p != head && TestSetPageHWPoison(head))) {
+                       if (hwpoison_filter(p)) {
+                               if (TestClearPageHWPoison(head))
                                        num_poisoned_pages_dec();
-                                       unlock_page(head);
-                                       return 0;
-                               }
+                               unlock_page(head);
+                               return 0;
                        }
                        unlock_page(head);
                        res = MF_FAILED;
@@ -2239,6 +2234,7 @@ retry:
        } else if (ret == 0) {
                if (soft_offline_free_page(page) && try_again) {
                        try_again = false;
+                       flags &= ~MF_COUNT_INCREASED;
                        goto retry;
                }
        }
index 10e9c87..f6248af 100644 (file)
@@ -2140,8 +2140,7 @@ struct page *alloc_pages_vma(gfp_t gfp, int order, struct vm_area_struct *vma,
                         * memory with both reclaim and compact as well.
                         */
                        if (!page && (gfp & __GFP_DIRECT_RECLAIM))
-                               page = __alloc_pages_node(hpage_node,
-                                                               gfp, order);
+                               page = __alloc_pages(gfp, order, hpage_node, nmask);
 
                        goto out;
                }
index fb95846..700434d 100644 (file)
@@ -1021,6 +1021,39 @@ static void handle_write_error(struct address_space *mapping,
        unlock_page(page);
 }
 
+static bool skip_throttle_noprogress(pg_data_t *pgdat)
+{
+       int reclaimable = 0, write_pending = 0;
+       int i;
+
+       /*
+        * If kswapd is disabled, reschedule if necessary but do not
+        * throttle as the system is likely near OOM.
+        */
+       if (pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES)
+               return true;
+
+       /*
+        * If there are a lot of dirty/writeback pages then do not
+        * throttle as throttling will occur when the pages cycle
+        * towards the end of the LRU if still under writeback.
+        */
+       for (i = 0; i < MAX_NR_ZONES; i++) {
+               struct zone *zone = pgdat->node_zones + i;
+
+               if (!populated_zone(zone))
+                       continue;
+
+               reclaimable += zone_reclaimable_pages(zone);
+               write_pending += zone_page_state_snapshot(zone,
+                                                 NR_ZONE_WRITE_PENDING);
+       }
+       if (2 * write_pending <= reclaimable)
+               return true;
+
+       return false;
+}
+
 void reclaim_throttle(pg_data_t *pgdat, enum vmscan_throttle_state reason)
 {
        wait_queue_head_t *wqh = &pgdat->reclaim_wait[reason];
@@ -1056,8 +1089,16 @@ void reclaim_throttle(pg_data_t *pgdat, enum vmscan_throttle_state reason)
                }
 
                break;
+       case VMSCAN_THROTTLE_CONGESTED:
+               fallthrough;
        case VMSCAN_THROTTLE_NOPROGRESS:
-               timeout = HZ/2;
+               if (skip_throttle_noprogress(pgdat)) {
+                       cond_resched();
+                       return;
+               }
+
+               timeout = 1;
+
                break;
        case VMSCAN_THROTTLE_ISOLATED:
                timeout = HZ/50;
@@ -3321,7 +3362,7 @@ again:
        if (!current_is_kswapd() && current_may_throttle() &&
            !sc->hibernation_mode &&
            test_bit(LRUVEC_CONGESTED, &target_lruvec->flags))
-               reclaim_throttle(pgdat, VMSCAN_THROTTLE_WRITEBACK);
+               reclaim_throttle(pgdat, VMSCAN_THROTTLE_CONGESTED);
 
        if (should_continue_reclaim(pgdat, sc->nr_reclaimed - nr_reclaimed,
                                    sc))
@@ -3386,16 +3427,16 @@ static void consider_reclaim_throttle(pg_data_t *pgdat, struct scan_control *sc)
        }
 
        /*
-        * Do not throttle kswapd on NOPROGRESS as it will throttle on
-        * VMSCAN_THROTTLE_WRITEBACK if there are too many pages under
-        * writeback and marked for immediate reclaim at the tail of
-        * the LRU.
+        * Do not throttle kswapd or cgroup reclaim on NOPROGRESS as it will
+        * throttle on VMSCAN_THROTTLE_WRITEBACK if there are too many pages
+        * under writeback and marked for immediate reclaim at the tail of the
+        * LRU.
         */
-       if (current_is_kswapd())
+       if (current_is_kswapd() || cgroup_reclaim(sc))
                return;
 
        /* Throttle if making no progress at high prioities. */
-       if (sc->priority < DEF_PRIORITY - 2)
+       if (sc->priority == 1 && !sc->nr_reclaimed)
                reclaim_throttle(pgdat, VMSCAN_THROTTLE_NOPROGRESS);
 }
 
@@ -3415,6 +3456,7 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
        unsigned long nr_soft_scanned;
        gfp_t orig_mask;
        pg_data_t *last_pgdat = NULL;
+       pg_data_t *first_pgdat = NULL;
 
        /*
         * If the number of buffer_heads in the machine exceeds the maximum
@@ -3478,14 +3520,19 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                        /* need some check for avoid more shrink_zone() */
                }
 
+               if (!first_pgdat)
+                       first_pgdat = zone->zone_pgdat;
+
                /* See comment about same check for global reclaim above */
                if (zone->zone_pgdat == last_pgdat)
                        continue;
                last_pgdat = zone->zone_pgdat;
                shrink_node(zone->zone_pgdat, sc);
-               consider_reclaim_throttle(zone->zone_pgdat, sc);
        }
 
+       if (first_pgdat)
+               consider_reclaim_throttle(first_pgdat, sc);
+
        /*
         * Restore to original mask to avoid the impact on the caller if we
         * promoted it to __GFP_HIGHMEM.
index 2f34bbd..cfca99e 100644 (file)
@@ -85,8 +85,10 @@ static void ax25_kill_by_device(struct net_device *dev)
 again:
        ax25_for_each(s, &ax25_list) {
                if (s->ax25_dev == ax25_dev) {
-                       s->ax25_dev = NULL;
                        spin_unlock_bh(&ax25_list_lock);
+                       lock_sock(s->sk);
+                       s->ax25_dev = NULL;
+                       release_sock(s->sk);
                        ax25_disconnect(s, ENETUNREACH);
                        spin_lock_bh(&ax25_list_lock);
 
index db4ab2c..891cfcf 100644 (file)
@@ -337,7 +337,7 @@ static int old_deviceless(struct net *net, void __user *uarg)
 
                args[2] = get_bridge_ifindices(net, indices, args[2]);
 
-               ret = copy_to_user(uarg, indices,
+               ret = copy_to_user((void __user *)args[1], indices,
                                   array_size(args[2], sizeof(int)))
                        ? -EFAULT : args[2];
 
index f3d7511..de24098 100644 (file)
@@ -4522,6 +4522,38 @@ int br_multicast_set_mld_version(struct net_bridge_mcast *brmctx,
 }
 #endif
 
+void br_multicast_set_query_intvl(struct net_bridge_mcast *brmctx,
+                                 unsigned long val)
+{
+       unsigned long intvl_jiffies = clock_t_to_jiffies(val);
+
+       if (intvl_jiffies < BR_MULTICAST_QUERY_INTVL_MIN) {
+               br_info(brmctx->br,
+                       "trying to set multicast query interval below minimum, setting to %lu (%ums)\n",
+                       jiffies_to_clock_t(BR_MULTICAST_QUERY_INTVL_MIN),
+                       jiffies_to_msecs(BR_MULTICAST_QUERY_INTVL_MIN));
+               intvl_jiffies = BR_MULTICAST_QUERY_INTVL_MIN;
+       }
+
+       brmctx->multicast_query_interval = intvl_jiffies;
+}
+
+void br_multicast_set_startup_query_intvl(struct net_bridge_mcast *brmctx,
+                                         unsigned long val)
+{
+       unsigned long intvl_jiffies = clock_t_to_jiffies(val);
+
+       if (intvl_jiffies < BR_MULTICAST_STARTUP_QUERY_INTVL_MIN) {
+               br_info(brmctx->br,
+                       "trying to set multicast startup query interval below minimum, setting to %lu (%ums)\n",
+                       jiffies_to_clock_t(BR_MULTICAST_STARTUP_QUERY_INTVL_MIN),
+                       jiffies_to_msecs(BR_MULTICAST_STARTUP_QUERY_INTVL_MIN));
+               intvl_jiffies = BR_MULTICAST_STARTUP_QUERY_INTVL_MIN;
+       }
+
+       brmctx->multicast_startup_query_interval = intvl_jiffies;
+}
+
 /**
  * br_multicast_list_adjacent - Returns snooped multicast addresses
  * @dev:       The bridge port adjacent to which to retrieve addresses
index 0c8b5f1..2ff83d8 100644 (file)
@@ -1357,7 +1357,7 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
        if (data[IFLA_BR_MCAST_QUERY_INTVL]) {
                u64 val = nla_get_u64(data[IFLA_BR_MCAST_QUERY_INTVL]);
 
-               br->multicast_ctx.multicast_query_interval = clock_t_to_jiffies(val);
+               br_multicast_set_query_intvl(&br->multicast_ctx, val);
        }
 
        if (data[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]) {
@@ -1369,7 +1369,7 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
        if (data[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]) {
                u64 val = nla_get_u64(data[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]);
 
-               br->multicast_ctx.multicast_startup_query_interval = clock_t_to_jiffies(val);
+               br_multicast_set_startup_query_intvl(&br->multicast_ctx, val);
        }
 
        if (data[IFLA_BR_MCAST_STATS_ENABLED]) {
index c0efd69..e8c6ee3 100644 (file)
@@ -28,6 +28,8 @@
 #define BR_MAX_PORTS   (1<<BR_PORT_BITS)
 
 #define BR_MULTICAST_DEFAULT_HASH_MAX 4096
+#define BR_MULTICAST_QUERY_INTVL_MIN msecs_to_jiffies(1000)
+#define BR_MULTICAST_STARTUP_QUERY_INTVL_MIN BR_MULTICAST_QUERY_INTVL_MIN
 
 #define BR_HWDOM_MAX BITS_PER_LONG
 
@@ -963,6 +965,10 @@ int br_multicast_dump_querier_state(struct sk_buff *skb,
                                    int nest_attr);
 size_t br_multicast_querier_state_size(void);
 size_t br_rports_size(const struct net_bridge_mcast *brmctx);
+void br_multicast_set_query_intvl(struct net_bridge_mcast *brmctx,
+                                 unsigned long val);
+void br_multicast_set_startup_query_intvl(struct net_bridge_mcast *brmctx,
+                                         unsigned long val);
 
 static inline bool br_group_is_l2(const struct br_ip *group)
 {
@@ -1147,9 +1153,9 @@ br_multicast_port_ctx_get_global(const struct net_bridge_mcast_port *pmctx)
 static inline bool
 br_multicast_ctx_vlan_global_disabled(const struct net_bridge_mcast *brmctx)
 {
-       return br_opt_get(brmctx->br, BROPT_MCAST_VLAN_SNOOPING_ENABLED) &&
-              br_multicast_ctx_is_vlan(brmctx) &&
-              !(brmctx->vlan->priv_flags & BR_VLFLAG_GLOBAL_MCAST_ENABLED);
+       return br_multicast_ctx_is_vlan(brmctx) &&
+              (!br_opt_get(brmctx->br, BROPT_MCAST_VLAN_SNOOPING_ENABLED) ||
+               !(brmctx->vlan->priv_flags & BR_VLFLAG_GLOBAL_MCAST_ENABLED));
 }
 
 static inline bool
index d9a89dd..7b0c197 100644 (file)
@@ -658,7 +658,7 @@ static ssize_t multicast_query_interval_show(struct device *d,
 static int set_query_interval(struct net_bridge *br, unsigned long val,
                              struct netlink_ext_ack *extack)
 {
-       br->multicast_ctx.multicast_query_interval = clock_t_to_jiffies(val);
+       br_multicast_set_query_intvl(&br->multicast_ctx, val);
        return 0;
 }
 
@@ -706,7 +706,7 @@ static ssize_t multicast_startup_query_interval_show(
 static int set_startup_query_interval(struct net_bridge *br, unsigned long val,
                                      struct netlink_ext_ack *extack)
 {
-       br->multicast_ctx.multicast_startup_query_interval = clock_t_to_jiffies(val);
+       br_multicast_set_startup_query_intvl(&br->multicast_ctx, val);
        return 0;
 }
 
index 8ffd4ed..a638297 100644 (file)
@@ -521,7 +521,7 @@ static int br_vlan_process_global_one_opts(const struct net_bridge *br,
                u64 val;
 
                val = nla_get_u64(tb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL]);
-               v->br_mcast_ctx.multicast_query_interval = clock_t_to_jiffies(val);
+               br_multicast_set_query_intvl(&v->br_mcast_ctx, val);
                *changed = true;
        }
        if (tb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL]) {
@@ -535,7 +535,7 @@ static int br_vlan_process_global_one_opts(const struct net_bridge *br,
                u64 val;
 
                val = nla_get_u64(tb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL]);
-               v->br_mcast_ctx.multicast_startup_query_interval = clock_t_to_jiffies(val);
+               br_multicast_set_startup_query_intvl(&v->br_mcast_ctx, val);
                *changed = true;
        }
        if (tb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER]) {
index 2a352e6..c4708e2 100644 (file)
@@ -3941,8 +3941,8 @@ sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)
                return skb;
 
        /* qdisc_skb_cb(skb)->pkt_len was already set by the caller. */
-       qdisc_skb_cb(skb)->mru = 0;
-       qdisc_skb_cb(skb)->post_ct = false;
+       tc_skb_cb(skb)->mru = 0;
+       tc_skb_cb(skb)->post_ct = false;
        mini_qdisc_bstats_cpu_update(miniq, skb);
 
        switch (tcf_classify(skb, miniq->block, miniq->filter_list, &cl_res, false)) {
@@ -5103,8 +5103,8 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,
        }
 
        qdisc_skb_cb(skb)->pkt_len = skb->len;
-       qdisc_skb_cb(skb)->mru = 0;
-       qdisc_skb_cb(skb)->post_ct = false;
+       tc_skb_cb(skb)->mru = 0;
+       tc_skb_cb(skb)->post_ct = false;
        skb->tc_at_ingress = 1;
        mini_qdisc_bstats_cpu_update(miniq, skb);
 
index 3255f57..1b094c4 100644 (file)
@@ -238,7 +238,7 @@ void
 skb_flow_dissect_ct(const struct sk_buff *skb,
                    struct flow_dissector *flow_dissector,
                    void *target_container, u16 *ctinfo_map,
-                   size_t mapsize, bool post_ct)
+                   size_t mapsize, bool post_ct, u16 zone)
 {
 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
        struct flow_dissector_key_ct *key;
@@ -260,6 +260,7 @@ skb_flow_dissect_ct(const struct sk_buff *skb,
        if (!ct) {
                key->ct_state = TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
                                TCA_FLOWER_KEY_CT_FLAGS_INVALID;
+               key->ct_zone = zone;
                return;
        }
 
index de1c849..4ed74d5 100644 (file)
@@ -47,9 +47,13 @@ static void ocelot_xmit_common(struct sk_buff *skb, struct net_device *netdev,
        void *injection;
        __be32 *prefix;
        u32 rew_op = 0;
+       u64 qos_class;
 
        ocelot_xmit_get_vlan_info(skb, dp, &vlan_tci, &tag_type);
 
+       qos_class = netdev_get_num_tc(netdev) ?
+                   netdev_get_prio_tc_map(netdev, skb->priority) : skb->priority;
+
        injection = skb_push(skb, OCELOT_TAG_LEN);
        prefix = skb_push(skb, OCELOT_SHORT_PREFIX_LEN);
 
@@ -57,7 +61,7 @@ static void ocelot_xmit_common(struct sk_buff *skb, struct net_device *netdev,
        memset(injection, 0, OCELOT_TAG_LEN);
        ocelot_ifh_set_bypass(injection, 1);
        ocelot_ifh_set_src(injection, ds->num_ports);
-       ocelot_ifh_set_qos_class(injection, skb->priority);
+       ocelot_ifh_set_qos_class(injection, qos_class);
        ocelot_ifh_set_vlan_tci(injection, vlan_tci);
        ocelot_ifh_set_tag_type(injection, tag_type);
 
index 0189e3c..5f70ffd 100644 (file)
@@ -154,7 +154,7 @@ void inet_sock_destruct(struct sock *sk)
 
        kfree(rcu_dereference_protected(inet->inet_opt, 1));
        dst_release(rcu_dereference_protected(sk->sk_dst_cache, 1));
-       dst_release(sk->sk_rx_dst);
+       dst_release(rcu_dereference_protected(sk->sk_rx_dst, 1));
        sk_refcnt_debug_dec(sk);
 }
 EXPORT_SYMBOL(inet_sock_destruct);
@@ -1994,6 +1994,10 @@ static int __init inet_init(void)
 
        ip_init();
 
+       /* Initialise per-cpu ipv4 mibs */
+       if (init_ipv4_mibs())
+               panic("%s: Cannot init ipv4 mibs\n", __func__);
+
        /* Setup TCP slab cache for open requests. */
        tcp_init();
 
@@ -2024,12 +2028,6 @@ static int __init inet_init(void)
 
        if (init_inet_pernet_ops())
                pr_crit("%s: Cannot init ipv4 inet pernet ops\n", __func__);
-       /*
-        *      Initialise per-cpu ipv4 mibs
-        */
-
-       if (init_ipv4_mibs())
-               pr_crit("%s: Cannot init ipv4 mibs\n", __func__);
 
        ipv4_proc_init();
 
index bbb3d39..2bb28bf 100644 (file)
@@ -3012,8 +3012,7 @@ int tcp_disconnect(struct sock *sk, int flags)
        icsk->icsk_ack.rcv_mss = TCP_MIN_MSS;
        memset(&tp->rx_opt, 0, sizeof(tp->rx_opt));
        __sk_dst_reset(sk);
-       dst_release(sk->sk_rx_dst);
-       sk->sk_rx_dst = NULL;
+       dst_release(xchg((__force struct dst_entry **)&sk->sk_rx_dst, NULL));
        tcp_saved_syn_free(tp);
        tp->compressed_ack = 0;
        tp->segs_in = 0;
index 246ab7b..0ce4684 100644 (file)
@@ -5787,7 +5787,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb)
        trace_tcp_probe(sk, skb);
 
        tcp_mstamp_refresh(tp);
-       if (unlikely(!sk->sk_rx_dst))
+       if (unlikely(!rcu_access_pointer(sk->sk_rx_dst)))
                inet_csk(sk)->icsk_af_ops->sk_rx_dst_set(sk, skb);
        /*
         *      Header prediction.
index 13d868c..084df22 100644 (file)
@@ -1701,7 +1701,10 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
        struct sock *rsk;
 
        if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
-               struct dst_entry *dst = sk->sk_rx_dst;
+               struct dst_entry *dst;
+
+               dst = rcu_dereference_protected(sk->sk_rx_dst,
+                                               lockdep_sock_is_held(sk));
 
                sock_rps_save_rxhash(sk, skb);
                sk_mark_napi_id(sk, skb);
@@ -1709,8 +1712,8 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
                        if (sk->sk_rx_dst_ifindex != skb->skb_iif ||
                            !INDIRECT_CALL_1(dst->ops->check, ipv4_dst_check,
                                             dst, 0)) {
+                               RCU_INIT_POINTER(sk->sk_rx_dst, NULL);
                                dst_release(dst);
-                               sk->sk_rx_dst = NULL;
                        }
                }
                tcp_rcv_established(sk, skb);
@@ -1786,7 +1789,7 @@ int tcp_v4_early_demux(struct sk_buff *skb)
                skb->sk = sk;
                skb->destructor = sock_edemux;
                if (sk_fullsock(sk)) {
-                       struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst);
+                       struct dst_entry *dst = rcu_dereference(sk->sk_rx_dst);
 
                        if (dst)
                                dst = dst_check(dst, 0);
@@ -2201,7 +2204,7 @@ void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
        struct dst_entry *dst = skb_dst(skb);
 
        if (dst && dst_hold_safe(dst)) {
-               sk->sk_rx_dst = dst;
+               rcu_assign_pointer(sk->sk_rx_dst, dst);
                sk->sk_rx_dst_ifindex = skb->skb_iif;
        }
 }
index 23b05e2..0cd6b85 100644 (file)
@@ -2250,7 +2250,7 @@ bool udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst)
        struct dst_entry *old;
 
        if (dst_hold_safe(dst)) {
-               old = xchg(&sk->sk_rx_dst, dst);
+               old = xchg((__force struct dst_entry **)&sk->sk_rx_dst, dst);
                dst_release(old);
                return old != dst;
        }
@@ -2440,7 +2440,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
                struct dst_entry *dst = skb_dst(skb);
                int ret;
 
-               if (unlikely(sk->sk_rx_dst != dst))
+               if (unlikely(rcu_dereference(sk->sk_rx_dst) != dst))
                        udp_sk_rx_dst_set(sk, dst);
 
                ret = udp_unicast_rcv_skb(sk, skb, uh);
@@ -2599,7 +2599,7 @@ int udp_v4_early_demux(struct sk_buff *skb)
 
        skb->sk = sk;
        skb->destructor = sock_efree;
-       dst = READ_ONCE(sk->sk_rx_dst);
+       dst = rcu_dereference(sk->sk_rx_dst);
 
        if (dst)
                dst = dst_check(dst, 0);
@@ -3075,7 +3075,7 @@ int udp4_seq_show(struct seq_file *seq, void *v)
 {
        seq_setwidth(seq, 127);
        if (v == SEQ_START_TOKEN)
-               seq_puts(seq, "  sl  local_address rem_address   st tx_queue "
+               seq_puts(seq, "   sl  local_address rem_address   st tx_queue "
                           "rx_queue tr tm->when retrnsmt   uid  timeout "
                           "inode ref pointer drops");
        else {
index 527e9ea..5e9474b 100644 (file)
@@ -808,6 +808,8 @@ vti6_siocdevprivate(struct net_device *dev, struct ifreq *ifr, void __user *data
        struct net *net = dev_net(dev);
        struct vti6_net *ip6n = net_generic(net, vti6_net_id);
 
+       memset(&p1, 0, sizeof(p1));
+
        switch (cmd) {
        case SIOCGETTUNNEL:
                if (dev == ip6n->fb_tnl_dev) {
index 60f1e4f..c51d5ce 100644 (file)
@@ -1020,6 +1020,9 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname,
        struct raw6_sock *rp = raw6_sk(sk);
        int val;
 
+       if (optlen < sizeof(val))
+               return -EINVAL;
+
        if (copy_from_sockptr(&val, optval, sizeof(val)))
                return -EFAULT;
 
index 551fce4..680e648 100644 (file)
@@ -107,7 +107,7 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
        if (dst && dst_hold_safe(dst)) {
                const struct rt6_info *rt = (const struct rt6_info *)dst;
 
-               sk->sk_rx_dst = dst;
+               rcu_assign_pointer(sk->sk_rx_dst, dst);
                sk->sk_rx_dst_ifindex = skb->skb_iif;
                sk->sk_rx_dst_cookie = rt6_get_cookie(rt);
        }
@@ -1505,7 +1505,10 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
                opt_skb = skb_clone(skb, sk_gfp_mask(sk, GFP_ATOMIC));
 
        if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
-               struct dst_entry *dst = sk->sk_rx_dst;
+               struct dst_entry *dst;
+
+               dst = rcu_dereference_protected(sk->sk_rx_dst,
+                                               lockdep_sock_is_held(sk));
 
                sock_rps_save_rxhash(sk, skb);
                sk_mark_napi_id(sk, skb);
@@ -1513,8 +1516,8 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
                        if (sk->sk_rx_dst_ifindex != skb->skb_iif ||
                            INDIRECT_CALL_1(dst->ops->check, ip6_dst_check,
                                            dst, sk->sk_rx_dst_cookie) == NULL) {
+                               RCU_INIT_POINTER(sk->sk_rx_dst, NULL);
                                dst_release(dst);
-                               sk->sk_rx_dst = NULL;
                        }
                }
 
@@ -1874,7 +1877,7 @@ INDIRECT_CALLABLE_SCOPE void tcp_v6_early_demux(struct sk_buff *skb)
                skb->sk = sk;
                skb->destructor = sock_edemux;
                if (sk_fullsock(sk)) {
-                       struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst);
+                       struct dst_entry *dst = rcu_dereference(sk->sk_rx_dst);
 
                        if (dst)
                                dst = dst_check(dst, sk->sk_rx_dst_cookie);
index e43b31d..8cde9ef 100644 (file)
@@ -956,7 +956,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
                struct dst_entry *dst = skb_dst(skb);
                int ret;
 
-               if (unlikely(sk->sk_rx_dst != dst))
+               if (unlikely(rcu_dereference(sk->sk_rx_dst) != dst))
                        udp6_sk_rx_dst_set(sk, dst);
 
                if (!uh->check && !udp_sk(sk)->no_check6_rx) {
@@ -1070,7 +1070,7 @@ INDIRECT_CALLABLE_SCOPE void udp_v6_early_demux(struct sk_buff *skb)
 
        skb->sk = sk;
        skb->destructor = sock_efree;
-       dst = READ_ONCE(sk->sk_rx_dst);
+       dst = rcu_dereference(sk->sk_rx_dst);
 
        if (dst)
                dst = dst_check(dst, sk->sk_rx_dst_cookie);
@@ -1204,7 +1204,7 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6,
                        kfree_skb(skb);
                        return -EINVAL;
                }
-               if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) {
+               if (datalen > cork->gso_size * UDP_MAX_SEGMENTS) {
                        kfree_skb(skb);
                        return -EINVAL;
                }
index bd3d319..2d0dd69 100644 (file)
@@ -1264,7 +1264,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 
 error:
+       mutex_lock(&local->mtx);
        ieee80211_vif_release_channel(sdata);
+       mutex_unlock(&local->mtx);
+
        return err;
 }
 
index bb5f165..c189b4c 100644 (file)
@@ -112,7 +112,11 @@ static int ncsi_write_package_info(struct sk_buff *skb,
                pnest = nla_nest_start_noflag(skb, NCSI_PKG_ATTR);
                if (!pnest)
                        return -ENOMEM;
-               nla_put_u32(skb, NCSI_PKG_ATTR_ID, np->id);
+               rc = nla_put_u32(skb, NCSI_PKG_ATTR_ID, np->id);
+               if (rc) {
+                       nla_nest_cancel(skb, pnest);
+                       return rc;
+               }
                if ((0x1 << np->id) == ndp->package_whitelist)
                        nla_put_flag(skb, NCSI_PKG_ATTR_FORCED);
                cnest = nla_nest_start_noflag(skb, NCSI_PKG_ATTR_CHANNEL_LIST);
index 81d03ac..ec4164c 100644 (file)
@@ -1195,8 +1195,6 @@ restart:
                }
                hlist_nulls_for_each_entry(h, n, &nf_conntrack_hash[cb->args[0]],
                                           hnnode) {
-                       if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
-                               continue;
                        ct = nf_ct_tuplehash_to_ctrack(h);
                        if (nf_ct_is_expired(ct)) {
                                if (i < ARRAY_SIZE(nf_ct_evict) &&
@@ -1208,6 +1206,9 @@ restart:
                        if (!net_eq(net, nf_ct_net(ct)))
                                continue;
 
+                       if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
+                               continue;
+
                        if (cb->args[1]) {
                                if (ct != last)
                                        continue;
index c0851fe..c207728 100644 (file)
@@ -4481,9 +4481,9 @@ struct nft_set_elem_catchall {
 static void nft_set_catchall_destroy(const struct nft_ctx *ctx,
                                     struct nft_set *set)
 {
-       struct nft_set_elem_catchall *catchall;
+       struct nft_set_elem_catchall *next, *catchall;
 
-       list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
+       list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
                list_del_rcu(&catchall->list);
                nft_set_elem_destroy(set, catchall->elem, true);
                kfree_rcu(catchall);
index 691ef4c..7f83f96 100644 (file)
@@ -556,7 +556,8 @@ __build_packet_message(struct nfnl_log_net *log,
                goto nla_put_failure;
 
        if (indev && skb->dev &&
-           skb->mac_header != skb->network_header) {
+           skb_mac_header_was_set(skb) &&
+           skb_mac_header_len(skb) != 0) {
                struct nfulnl_msg_packet_hw phw;
                int len;
 
index 5837e8e..f0b9e21 100644 (file)
@@ -560,7 +560,8 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
                goto nla_put_failure;
 
        if (indev && entskb->dev &&
-           skb_mac_header_was_set(entskb)) {
+           skb_mac_header_was_set(entskb) &&
+           skb_mac_header_len(entskb) != 0) {
                struct nfqnl_msg_packet_hw phw;
                int len;
 
index 9713035..6d262d9 100644 (file)
@@ -34,6 +34,7 @@
 #include <net/mpls.h>
 #include <net/ndisc.h>
 #include <net/nsh.h>
+#include <net/netfilter/nf_conntrack_zones.h>
 
 #include "conntrack.h"
 #include "datapath.h"
@@ -860,6 +861,7 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
 #endif
        bool post_ct = false;
        int res, err;
+       u16 zone = 0;
 
        /* Extract metadata from packet. */
        if (tun_info) {
@@ -898,6 +900,7 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
                key->recirc_id = tc_ext ? tc_ext->chain : 0;
                OVS_CB(skb)->mru = tc_ext ? tc_ext->mru : 0;
                post_ct = tc_ext ? tc_ext->post_ct : false;
+               zone = post_ct ? tc_ext->zone : 0;
        } else {
                key->recirc_id = 0;
        }
@@ -906,8 +909,11 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
 #endif
 
        err = key_extract(skb, key);
-       if (!err)
+       if (!err) {
                ovs_ct_fill_key(skb, key, post_ct);   /* Must be after key_extract(). */
+               if (post_ct && !skb_get_nfct(skb))
+                       key->ct_zone = zone;
+       }
        return err;
 }
 
index b4f90af..65d463a 100644 (file)
@@ -947,6 +947,8 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg)
                        ret =  -EBUSY;
                else if (sk->sk_state == TCP_ESTABLISHED)
                        ret = -EISCONN;
+               else if (!pn->pn_sk.sobject)
+                       ret = -EADDRNOTAVAIL;
                else
                        ret = pep_sock_enable(sk, NULL, 0);
                release_sock(sk);
index 90866ae..ab35914 100644 (file)
@@ -690,10 +690,10 @@ static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
                                   u8 family, u16 zone, bool *defrag)
 {
        enum ip_conntrack_info ctinfo;
-       struct qdisc_skb_cb cb;
        struct nf_conn *ct;
        int err = 0;
        bool frag;
+       u16 mru;
 
        /* Previously seen (loopback)? Ignore. */
        ct = nf_ct_get(skb, &ctinfo);
@@ -708,7 +708,7 @@ static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
                return err;
 
        skb_get(skb);
-       cb = *qdisc_skb_cb(skb);
+       mru = tc_skb_cb(skb)->mru;
 
        if (family == NFPROTO_IPV4) {
                enum ip_defrag_users user = IP_DEFRAG_CONNTRACK_IN + zone;
@@ -722,7 +722,7 @@ static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
 
                if (!err) {
                        *defrag = true;
-                       cb.mru = IPCB(skb)->frag_max_size;
+                       mru = IPCB(skb)->frag_max_size;
                }
        } else { /* NFPROTO_IPV6 */
 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
@@ -735,7 +735,7 @@ static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
 
                if (!err) {
                        *defrag = true;
-                       cb.mru = IP6CB(skb)->frag_max_size;
+                       mru = IP6CB(skb)->frag_max_size;
                }
 #else
                err = -EOPNOTSUPP;
@@ -744,7 +744,7 @@ static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
        }
 
        if (err != -EINPROGRESS)
-               *qdisc_skb_cb(skb) = cb;
+               tc_skb_cb(skb)->mru = mru;
        skb_clear_hash(skb);
        skb->ignore_df = 1;
        return err;
@@ -963,7 +963,7 @@ static int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a,
        tcf_action_update_bstats(&c->common, skb);
 
        if (clear) {
-               qdisc_skb_cb(skb)->post_ct = false;
+               tc_skb_cb(skb)->post_ct = false;
                ct = nf_ct_get(skb, &ctinfo);
                if (ct) {
                        nf_conntrack_put(&ct->ct_general);
@@ -1048,7 +1048,8 @@ do_nat:
 out_push:
        skb_push_rcsum(skb, nh_ofs);
 
-       qdisc_skb_cb(skb)->post_ct = true;
+       tc_skb_cb(skb)->post_ct = true;
+       tc_skb_cb(skb)->zone = p->zone;
 out_clear:
        if (defrag)
                qdisc_skb_cb(skb)->pkt_len = skb->len;
index e54f0a4..35c74bd 100644 (file)
@@ -1617,12 +1617,15 @@ int tcf_classify(struct sk_buff *skb,
 
        /* If we missed on some chain */
        if (ret == TC_ACT_UNSPEC && last_executed_chain) {
+               struct tc_skb_cb *cb = tc_skb_cb(skb);
+
                ext = tc_skb_ext_alloc(skb);
                if (WARN_ON_ONCE(!ext))
                        return TC_ACT_SHOT;
                ext->chain = last_executed_chain;
-               ext->mru = qdisc_skb_cb(skb)->mru;
-               ext->post_ct = qdisc_skb_cb(skb)->post_ct;
+               ext->mru = cb->mru;
+               ext->post_ct = cb->post_ct;
+               ext->zone = cb->zone;
        }
 
        return ret;
index aab13ba..ef54ed3 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <net/sch_generic.h>
 #include <net/pkt_cls.h>
+#include <net/pkt_sched.h>
 #include <net/ip.h>
 #include <net/flow_dissector.h>
 #include <net/geneve.h>
@@ -309,7 +310,8 @@ static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
                       struct tcf_result *res)
 {
        struct cls_fl_head *head = rcu_dereference_bh(tp->root);
-       bool post_ct = qdisc_skb_cb(skb)->post_ct;
+       bool post_ct = tc_skb_cb(skb)->post_ct;
+       u16 zone = tc_skb_cb(skb)->zone;
        struct fl_flow_key skb_key;
        struct fl_flow_mask *mask;
        struct cls_fl_filter *f;
@@ -327,7 +329,7 @@ static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
                skb_flow_dissect_ct(skb, &mask->dissector, &skb_key,
                                    fl_ct_info_to_flower_map,
                                    ARRAY_SIZE(fl_ct_info_to_flower_map),
-                                   post_ct);
+                                   post_ct, zone);
                skb_flow_dissect_hash(skb, &mask->dissector, &skb_key);
                skb_flow_dissect(skb, &mask->dissector, &skb_key,
                                 FLOW_DISSECTOR_F_STOP_BEFORE_ENCAP);
index 8c06381..5ded4c8 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 #include <net/netlink.h>
 #include <net/sch_generic.h>
+#include <net/pkt_sched.h>
 #include <net/dst.h>
 #include <net/ip.h>
 #include <net/ip6_fib.h>
@@ -137,7 +138,7 @@ err:
 
 int sch_frag_xmit_hook(struct sk_buff *skb, int (*xmit)(struct sk_buff *skb))
 {
-       u16 mru = qdisc_skb_cb(skb)->mru;
+       u16 mru = tc_skb_cb(skb)->mru;
        int err;
 
        if (mru && skb->len > mru + skb->dev->hard_header_len)
index 760b367..a7d6231 100644 (file)
@@ -290,9 +290,8 @@ out:
        return err;
 }
 
-static int sctp_sock_dump(struct sctp_transport *tsp, void *p)
+static int sctp_sock_dump(struct sctp_endpoint *ep, struct sctp_transport *tsp, void *p)
 {
-       struct sctp_endpoint *ep = tsp->asoc->ep;
        struct sctp_comm_param *commp = p;
        struct sock *sk = ep->base.sk;
        struct sk_buff *skb = commp->skb;
@@ -302,6 +301,8 @@ static int sctp_sock_dump(struct sctp_transport *tsp, void *p)
        int err = 0;
 
        lock_sock(sk);
+       if (ep != tsp->asoc->ep)
+               goto release;
        list_for_each_entry(assoc, &ep->asocs, asocs) {
                if (cb->args[4] < cb->args[1])
                        goto next;
@@ -344,9 +345,8 @@ release:
        return err;
 }
 
-static int sctp_sock_filter(struct sctp_transport *tsp, void *p)
+static int sctp_sock_filter(struct sctp_endpoint *ep, struct sctp_transport *tsp, void *p)
 {
-       struct sctp_endpoint *ep = tsp->asoc->ep;
        struct sctp_comm_param *commp = p;
        struct sock *sk = ep->base.sk;
        const struct inet_diag_req_v2 *r = commp->r;
@@ -505,8 +505,8 @@ skip:
        if (!(idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE)))
                goto done;
 
-       sctp_for_each_transport(sctp_sock_filter, sctp_sock_dump,
-                               net, &pos, &commp);
+       sctp_transport_traverse_process(sctp_sock_filter, sctp_sock_dump,
+                                       net, &pos, &commp);
        cb->args[2] = pos;
 
 done:
index 48c9c2c..efffde7 100644 (file)
@@ -184,6 +184,18 @@ void sctp_endpoint_free(struct sctp_endpoint *ep)
 }
 
 /* Final destructor for endpoint.  */
+static void sctp_endpoint_destroy_rcu(struct rcu_head *head)
+{
+       struct sctp_endpoint *ep = container_of(head, struct sctp_endpoint, rcu);
+       struct sock *sk = ep->base.sk;
+
+       sctp_sk(sk)->ep = NULL;
+       sock_put(sk);
+
+       kfree(ep);
+       SCTP_DBG_OBJCNT_DEC(ep);
+}
+
 static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
 {
        struct sock *sk;
@@ -213,18 +225,13 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
        if (sctp_sk(sk)->bind_hash)
                sctp_put_port(sk);
 
-       sctp_sk(sk)->ep = NULL;
-       /* Give up our hold on the sock */
-       sock_put(sk);
-
-       kfree(ep);
-       SCTP_DBG_OBJCNT_DEC(ep);
+       call_rcu(&ep->rcu, sctp_endpoint_destroy_rcu);
 }
 
 /* Hold a reference to an endpoint. */
-void sctp_endpoint_hold(struct sctp_endpoint *ep)
+int sctp_endpoint_hold(struct sctp_endpoint *ep)
 {
-       refcount_inc(&ep->base.refcnt);
+       return refcount_inc_not_zero(&ep->base.refcnt);
 }
 
 /* Release a reference to an endpoint and clean up if there are
index 3339125..ad5028a 100644 (file)
@@ -5338,11 +5338,12 @@ int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *),
 }
 EXPORT_SYMBOL_GPL(sctp_transport_lookup_process);
 
-int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *),
-                           int (*cb_done)(struct sctp_transport *, void *),
-                           struct net *net, int *pos, void *p) {
+int sctp_transport_traverse_process(sctp_callback_t cb, sctp_callback_t cb_done,
+                                   struct net *net, int *pos, void *p)
+{
        struct rhashtable_iter hti;
        struct sctp_transport *tsp;
+       struct sctp_endpoint *ep;
        int ret;
 
 again:
@@ -5351,26 +5352,32 @@ again:
 
        tsp = sctp_transport_get_idx(net, &hti, *pos + 1);
        for (; !IS_ERR_OR_NULL(tsp); tsp = sctp_transport_get_next(net, &hti)) {
-               ret = cb(tsp, p);
-               if (ret)
-                       break;
+               ep = tsp->asoc->ep;
+               if (sctp_endpoint_hold(ep)) { /* asoc can be peeled off */
+                       ret = cb(ep, tsp, p);
+                       if (ret)
+                               break;
+                       sctp_endpoint_put(ep);
+               }
                (*pos)++;
                sctp_transport_put(tsp);
        }
        sctp_transport_walk_stop(&hti);
 
        if (ret) {
-               if (cb_done && !cb_done(tsp, p)) {
+               if (cb_done && !cb_done(ep, tsp, p)) {
                        (*pos)++;
+                       sctp_endpoint_put(ep);
                        sctp_transport_put(tsp);
                        goto again;
                }
+               sctp_endpoint_put(ep);
                sctp_transport_put(tsp);
        }
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(sctp_for_each_transport);
+EXPORT_SYMBOL_GPL(sctp_transport_traverse_process);
 
 /* 7.2.1 Association Status (SCTP_STATUS)
 
index f4286ca..1a4fc1c 100644 (file)
@@ -180,6 +180,11 @@ struct smc_connection {
        u16                     tx_cdc_seq;     /* sequence # for CDC send */
        u16                     tx_cdc_seq_fin; /* sequence # - tx completed */
        spinlock_t              send_lock;      /* protect wr_sends */
+       atomic_t                cdc_pend_tx_wr; /* number of pending tx CDC wqe
+                                                * - inc when post wqe,
+                                                * - dec on polled tx cqe
+                                                */
+       wait_queue_head_t       cdc_pend_tx_wq; /* wakeup on no cdc_pend_tx_wr*/
        struct delayed_work     tx_work;        /* retry of smc_cdc_msg_send */
        u32                     tx_off;         /* base offset in peer rmb */
 
index 99acd33..84c8a43 100644 (file)
@@ -31,10 +31,6 @@ static void smc_cdc_tx_handler(struct smc_wr_tx_pend_priv *pnd_snd,
        struct smc_sock *smc;
        int diff;
 
-       if (!conn)
-               /* already dismissed */
-               return;
-
        smc = container_of(conn, struct smc_sock, conn);
        bh_lock_sock(&smc->sk);
        if (!wc_status) {
@@ -51,6 +47,12 @@ static void smc_cdc_tx_handler(struct smc_wr_tx_pend_priv *pnd_snd,
                              conn);
                conn->tx_cdc_seq_fin = cdcpend->ctrl_seq;
        }
+
+       if (atomic_dec_and_test(&conn->cdc_pend_tx_wr) &&
+           unlikely(wq_has_sleeper(&conn->cdc_pend_tx_wq)))
+               wake_up(&conn->cdc_pend_tx_wq);
+       WARN_ON(atomic_read(&conn->cdc_pend_tx_wr) < 0);
+
        smc_tx_sndbuf_nonfull(smc);
        bh_unlock_sock(&smc->sk);
 }
@@ -107,6 +109,10 @@ int smc_cdc_msg_send(struct smc_connection *conn,
        conn->tx_cdc_seq++;
        conn->local_tx_ctrl.seqno = conn->tx_cdc_seq;
        smc_host_msg_to_cdc((struct smc_cdc_msg *)wr_buf, conn, &cfed);
+
+       atomic_inc(&conn->cdc_pend_tx_wr);
+       smp_mb__after_atomic(); /* Make sure cdc_pend_tx_wr added before post */
+
        rc = smc_wr_tx_send(link, (struct smc_wr_tx_pend_priv *)pend);
        if (!rc) {
                smc_curs_copy(&conn->rx_curs_confirmed, &cfed, conn);
@@ -114,6 +120,7 @@ int smc_cdc_msg_send(struct smc_connection *conn,
        } else {
                conn->tx_cdc_seq--;
                conn->local_tx_ctrl.seqno = conn->tx_cdc_seq;
+               atomic_dec(&conn->cdc_pend_tx_wr);
        }
 
        return rc;
@@ -136,7 +143,18 @@ int smcr_cdc_msg_send_validation(struct smc_connection *conn,
        peer->token = htonl(local->token);
        peer->prod_flags.failover_validation = 1;
 
+       /* We need to set pend->conn here to make sure smc_cdc_tx_handler()
+        * can handle properly
+        */
+       smc_cdc_add_pending_send(conn, pend);
+
+       atomic_inc(&conn->cdc_pend_tx_wr);
+       smp_mb__after_atomic(); /* Make sure cdc_pend_tx_wr added before post */
+
        rc = smc_wr_tx_send(link, (struct smc_wr_tx_pend_priv *)pend);
+       if (unlikely(rc))
+               atomic_dec(&conn->cdc_pend_tx_wr);
+
        return rc;
 }
 
@@ -193,31 +211,9 @@ int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn)
        return rc;
 }
 
-static bool smc_cdc_tx_filter(struct smc_wr_tx_pend_priv *tx_pend,
-                             unsigned long data)
+void smc_cdc_wait_pend_tx_wr(struct smc_connection *conn)
 {
-       struct smc_connection *conn = (struct smc_connection *)data;
-       struct smc_cdc_tx_pend *cdc_pend =
-               (struct smc_cdc_tx_pend *)tx_pend;
-
-       return cdc_pend->conn == conn;
-}
-
-static void smc_cdc_tx_dismisser(struct smc_wr_tx_pend_priv *tx_pend)
-{
-       struct smc_cdc_tx_pend *cdc_pend =
-               (struct smc_cdc_tx_pend *)tx_pend;
-
-       cdc_pend->conn = NULL;
-}
-
-void smc_cdc_tx_dismiss_slots(struct smc_connection *conn)
-{
-       struct smc_link *link = conn->lnk;
-
-       smc_wr_tx_dismiss_slots(link, SMC_CDC_MSG_TYPE,
-                               smc_cdc_tx_filter, smc_cdc_tx_dismisser,
-                               (unsigned long)conn);
+       wait_event(conn->cdc_pend_tx_wq, !atomic_read(&conn->cdc_pend_tx_wr));
 }
 
 /* Send a SMC-D CDC header.
index 0a0a89a..696cc11 100644 (file)
@@ -291,7 +291,7 @@ int smc_cdc_get_free_slot(struct smc_connection *conn,
                          struct smc_wr_buf **wr_buf,
                          struct smc_rdma_wr **wr_rdma_buf,
                          struct smc_cdc_tx_pend **pend);
-void smc_cdc_tx_dismiss_slots(struct smc_connection *conn);
+void smc_cdc_wait_pend_tx_wr(struct smc_connection *conn);
 int smc_cdc_msg_send(struct smc_connection *conn, struct smc_wr_buf *wr_buf,
                     struct smc_cdc_tx_pend *pend);
 int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn);
index 387d28b..a684936 100644 (file)
@@ -647,7 +647,7 @@ static void smcr_lgr_link_deactivate_all(struct smc_link_group *lgr)
        for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
                struct smc_link *lnk = &lgr->lnk[i];
 
-               if (smc_link_usable(lnk))
+               if (smc_link_sendable(lnk))
                        lnk->state = SMC_LNK_INACTIVE;
        }
        wake_up_all(&lgr->llc_msg_waiter);
@@ -1127,7 +1127,7 @@ void smc_conn_free(struct smc_connection *conn)
                        smc_ism_unset_conn(conn);
                tasklet_kill(&conn->rx_tsklet);
        } else {
-               smc_cdc_tx_dismiss_slots(conn);
+               smc_cdc_wait_pend_tx_wr(conn);
                if (current_work() != &conn->abort_work)
                        cancel_work_sync(&conn->abort_work);
        }
@@ -1204,7 +1204,7 @@ void smcr_link_clear(struct smc_link *lnk, bool log)
        smc_llc_link_clear(lnk, log);
        smcr_buf_unmap_lgr(lnk);
        smcr_rtoken_clear_link(lnk);
-       smc_ib_modify_qp_reset(lnk);
+       smc_ib_modify_qp_error(lnk);
        smc_wr_free_link(lnk);
        smc_ib_destroy_queue_pair(lnk);
        smc_ib_dealloc_protection_domain(lnk);
@@ -1336,7 +1336,7 @@ static void smc_conn_kill(struct smc_connection *conn, bool soft)
                else
                        tasklet_unlock_wait(&conn->rx_tsklet);
        } else {
-               smc_cdc_tx_dismiss_slots(conn);
+               smc_cdc_wait_pend_tx_wr(conn);
        }
        smc_lgr_unregister_conn(conn);
        smc_close_active_abort(smc);
@@ -1459,11 +1459,16 @@ void smc_smcd_terminate_all(struct smcd_dev *smcd)
 /* Called when an SMCR device is removed or the smc module is unloaded.
  * If smcibdev is given, all SMCR link groups using this device are terminated.
  * If smcibdev is NULL, all SMCR link groups are terminated.
+ *
+ * We must wait here for QPs been destroyed before we destroy the CQs,
+ * or we won't received any CQEs and cdc_pend_tx_wr cannot reach 0 thus
+ * smc_sock cannot be released.
  */
 void smc_smcr_terminate_all(struct smc_ib_device *smcibdev)
 {
        struct smc_link_group *lgr, *lg;
        LIST_HEAD(lgr_free_list);
+       LIST_HEAD(lgr_linkdown_list);
        int i;
 
        spin_lock_bh(&smc_lgr_list.lock);
@@ -1475,7 +1480,7 @@ void smc_smcr_terminate_all(struct smc_ib_device *smcibdev)
                list_for_each_entry_safe(lgr, lg, &smc_lgr_list.list, list) {
                        for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
                                if (lgr->lnk[i].smcibdev == smcibdev)
-                                       smcr_link_down_cond_sched(&lgr->lnk[i]);
+                                       list_move_tail(&lgr->list, &lgr_linkdown_list);
                        }
                }
        }
@@ -1487,6 +1492,16 @@ void smc_smcr_terminate_all(struct smc_ib_device *smcibdev)
                __smc_lgr_terminate(lgr, false);
        }
 
+       list_for_each_entry_safe(lgr, lg, &lgr_linkdown_list, list) {
+               for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
+                       if (lgr->lnk[i].smcibdev == smcibdev) {
+                               mutex_lock(&lgr->llc_conf_mutex);
+                               smcr_link_down_cond(&lgr->lnk[i]);
+                               mutex_unlock(&lgr->llc_conf_mutex);
+                       }
+               }
+       }
+
        if (smcibdev) {
                if (atomic_read(&smcibdev->lnk_cnt))
                        wait_event(smcibdev->lnks_deleted,
@@ -1586,7 +1601,6 @@ static void smcr_link_down(struct smc_link *lnk)
        if (!lgr || lnk->state == SMC_LNK_UNUSED || list_empty(&lgr->list))
                return;
 
-       smc_ib_modify_qp_reset(lnk);
        to_lnk = smc_switch_conns(lgr, lnk, true);
        if (!to_lnk) { /* no backup link available */
                smcr_link_clear(lnk, true);
@@ -1824,6 +1838,7 @@ create:
        conn->local_tx_ctrl.common.type = SMC_CDC_MSG_TYPE;
        conn->local_tx_ctrl.len = SMC_WR_TX_SIZE;
        conn->urg_state = SMC_URG_READ;
+       init_waitqueue_head(&conn->cdc_pend_tx_wq);
        INIT_WORK(&smc->conn.abort_work, smc_conn_abort_work);
        if (ini->is_smcd) {
                conn->rx_off = sizeof(struct smcd_cdc_msg);
index 59cef3b..d63b082 100644 (file)
@@ -415,6 +415,12 @@ static inline bool smc_link_usable(struct smc_link *lnk)
        return true;
 }
 
+static inline bool smc_link_sendable(struct smc_link *lnk)
+{
+       return smc_link_usable(lnk) &&
+               lnk->qp_attr.cur_qp_state == IB_QPS_RTS;
+}
+
 static inline bool smc_link_active(struct smc_link *lnk)
 {
        return lnk->state == SMC_LNK_ACTIVE;
index d93055e..fe5d539 100644 (file)
@@ -109,12 +109,12 @@ int smc_ib_modify_qp_rts(struct smc_link *lnk)
                            IB_QP_MAX_QP_RD_ATOMIC);
 }
 
-int smc_ib_modify_qp_reset(struct smc_link *lnk)
+int smc_ib_modify_qp_error(struct smc_link *lnk)
 {
        struct ib_qp_attr qp_attr;
 
        memset(&qp_attr, 0, sizeof(qp_attr));
-       qp_attr.qp_state = IB_QPS_RESET;
+       qp_attr.qp_state = IB_QPS_ERR;
        return ib_modify_qp(lnk->roce_qp, &qp_attr, IB_QP_STATE);
 }
 
index 0758593..bfa1c6b 100644 (file)
@@ -90,6 +90,7 @@ int smc_ib_create_queue_pair(struct smc_link *lnk);
 int smc_ib_ready_link(struct smc_link *lnk);
 int smc_ib_modify_qp_rts(struct smc_link *lnk);
 int smc_ib_modify_qp_reset(struct smc_link *lnk);
+int smc_ib_modify_qp_error(struct smc_link *lnk);
 long smc_ib_setup_per_ibdev(struct smc_ib_device *smcibdev);
 int smc_ib_get_memory_region(struct ib_pd *pd, int access_flags,
                             struct smc_buf_desc *buf_slot, u8 link_idx);
index b102680..3e9fd8a 100644 (file)
@@ -1630,7 +1630,7 @@ void smc_llc_send_link_delete_all(struct smc_link_group *lgr, bool ord, u32 rsn)
        delllc.reason = htonl(rsn);
 
        for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
-               if (!smc_link_usable(&lgr->lnk[i]))
+               if (!smc_link_sendable(&lgr->lnk[i]))
                        continue;
                if (!smc_llc_send_message_wait(&lgr->lnk[i], &delllc))
                        break;
index 600ab58..c6cfdea 100644 (file)
@@ -62,13 +62,9 @@ static inline bool smc_wr_is_tx_pend(struct smc_link *link)
 }
 
 /* wait till all pending tx work requests on the given link are completed */
-int smc_wr_tx_wait_no_pending_sends(struct smc_link *link)
+void smc_wr_tx_wait_no_pending_sends(struct smc_link *link)
 {
-       if (wait_event_timeout(link->wr_tx_wait, !smc_wr_is_tx_pend(link),
-                              SMC_WR_TX_WAIT_PENDING_TIME))
-               return 0;
-       else /* timeout */
-               return -EPIPE;
+       wait_event(link->wr_tx_wait, !smc_wr_is_tx_pend(link));
 }
 
 static inline int smc_wr_tx_find_pending_index(struct smc_link *link, u64 wr_id)
@@ -87,7 +83,6 @@ static inline void smc_wr_tx_process_cqe(struct ib_wc *wc)
        struct smc_wr_tx_pend pnd_snd;
        struct smc_link *link;
        u32 pnd_snd_idx;
-       int i;
 
        link = wc->qp->qp_context;
 
@@ -128,14 +123,6 @@ static inline void smc_wr_tx_process_cqe(struct ib_wc *wc)
        }
 
        if (wc->status) {
-               for_each_set_bit(i, link->wr_tx_mask, link->wr_tx_cnt) {
-                       /* clear full struct smc_wr_tx_pend including .priv */
-                       memset(&link->wr_tx_pends[i], 0,
-                              sizeof(link->wr_tx_pends[i]));
-                       memset(&link->wr_tx_bufs[i], 0,
-                              sizeof(link->wr_tx_bufs[i]));
-                       clear_bit(i, link->wr_tx_mask);
-               }
                if (link->lgr->smc_version == SMC_V2) {
                        memset(link->wr_tx_v2_pend, 0,
                               sizeof(*link->wr_tx_v2_pend));
@@ -188,7 +175,7 @@ void smc_wr_tx_cq_handler(struct ib_cq *ib_cq, void *cq_context)
 static inline int smc_wr_tx_get_free_slot_index(struct smc_link *link, u32 *idx)
 {
        *idx = link->wr_tx_cnt;
-       if (!smc_link_usable(link))
+       if (!smc_link_sendable(link))
                return -ENOLINK;
        for_each_clear_bit(*idx, link->wr_tx_mask, link->wr_tx_cnt) {
                if (!test_and_set_bit(*idx, link->wr_tx_mask))
@@ -231,7 +218,7 @@ int smc_wr_tx_get_free_slot(struct smc_link *link,
        } else {
                rc = wait_event_interruptible_timeout(
                        link->wr_tx_wait,
-                       !smc_link_usable(link) ||
+                       !smc_link_sendable(link) ||
                        lgr->terminating ||
                        (smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY),
                        SMC_WR_TX_WAIT_FREE_SLOT_TIME);
@@ -358,18 +345,20 @@ int smc_wr_tx_send_wait(struct smc_link *link, struct smc_wr_tx_pend_priv *priv,
                        unsigned long timeout)
 {
        struct smc_wr_tx_pend *pend;
+       u32 pnd_idx;
        int rc;
 
        pend = container_of(priv, struct smc_wr_tx_pend, priv);
        pend->compl_requested = 1;
-       init_completion(&link->wr_tx_compl[pend->idx]);
+       pnd_idx = pend->idx;
+       init_completion(&link->wr_tx_compl[pnd_idx]);
 
        rc = smc_wr_tx_send(link, priv);
        if (rc)
                return rc;
        /* wait for completion by smc_wr_tx_process_cqe() */
        rc = wait_for_completion_interruptible_timeout(
-                                       &link->wr_tx_compl[pend->idx], timeout);
+                                       &link->wr_tx_compl[pnd_idx], timeout);
        if (rc <= 0)
                rc = -ENODATA;
        if (rc > 0)
@@ -419,25 +408,6 @@ int smc_wr_reg_send(struct smc_link *link, struct ib_mr *mr)
        return rc;
 }
 
-void smc_wr_tx_dismiss_slots(struct smc_link *link, u8 wr_tx_hdr_type,
-                            smc_wr_tx_filter filter,
-                            smc_wr_tx_dismisser dismisser,
-                            unsigned long data)
-{
-       struct smc_wr_tx_pend_priv *tx_pend;
-       struct smc_wr_rx_hdr *wr_tx;
-       int i;
-
-       for_each_set_bit(i, link->wr_tx_mask, link->wr_tx_cnt) {
-               wr_tx = (struct smc_wr_rx_hdr *)&link->wr_tx_bufs[i];
-               if (wr_tx->type != wr_tx_hdr_type)
-                       continue;
-               tx_pend = &link->wr_tx_pends[i].priv;
-               if (filter(tx_pend, data))
-                       dismisser(tx_pend);
-       }
-}
-
 /****************************** receive queue ********************************/
 
 int smc_wr_rx_register_handler(struct smc_wr_rx_handler *handler)
@@ -673,10 +643,7 @@ void smc_wr_free_link(struct smc_link *lnk)
        smc_wr_wakeup_reg_wait(lnk);
        smc_wr_wakeup_tx_wait(lnk);
 
-       if (smc_wr_tx_wait_no_pending_sends(lnk))
-               memset(lnk->wr_tx_mask, 0,
-                      BITS_TO_LONGS(SMC_WR_BUF_CNT) *
-                                               sizeof(*lnk->wr_tx_mask));
+       smc_wr_tx_wait_no_pending_sends(lnk);
        wait_event(lnk->wr_reg_wait, (!atomic_read(&lnk->wr_reg_refcnt)));
        wait_event(lnk->wr_tx_wait, (!atomic_read(&lnk->wr_tx_refcnt)));
 
index f353311..47512cc 100644 (file)
@@ -22,7 +22,6 @@
 #define SMC_WR_BUF_CNT 16      /* # of ctrl buffers per link */
 
 #define SMC_WR_TX_WAIT_FREE_SLOT_TIME  (10 * HZ)
-#define SMC_WR_TX_WAIT_PENDING_TIME    (5 * HZ)
 
 #define SMC_WR_TX_SIZE 44 /* actual size of wr_send data (<=SMC_WR_BUF_SIZE) */
 
@@ -62,7 +61,7 @@ static inline void smc_wr_tx_set_wr_id(atomic_long_t *wr_tx_id, long val)
 
 static inline bool smc_wr_tx_link_hold(struct smc_link *link)
 {
-       if (!smc_link_usable(link))
+       if (!smc_link_sendable(link))
                return false;
        atomic_inc(&link->wr_tx_refcnt);
        return true;
@@ -130,7 +129,7 @@ void smc_wr_tx_dismiss_slots(struct smc_link *lnk, u8 wr_rx_hdr_type,
                             smc_wr_tx_filter filter,
                             smc_wr_tx_dismisser dismisser,
                             unsigned long data);
-int smc_wr_tx_wait_no_pending_sends(struct smc_link *link);
+void smc_wr_tx_wait_no_pending_sends(struct smc_link *link);
 
 int smc_wr_rx_register_handler(struct smc_wr_rx_handler *handler);
 int smc_wr_rx_post_init(struct smc_link *link);
index b4d9419..d293614 100644 (file)
@@ -524,7 +524,7 @@ static int tipc_aead_init(struct tipc_aead **aead, struct tipc_aead_key *ukey,
                return -EEXIST;
 
        /* Allocate a new AEAD */
-       tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+       tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC);
        if (unlikely(!tmp))
                return -ENOMEM;
 
@@ -1474,7 +1474,7 @@ int tipc_crypto_start(struct tipc_crypto **crypto, struct net *net,
                return -EEXIST;
 
        /* Allocate crypto */
-       c = kzalloc(sizeof(*c), GFP_KERNEL);
+       c = kzalloc(sizeof(*c), GFP_ATOMIC);
        if (!c)
                return -ENOMEM;
 
@@ -1488,7 +1488,7 @@ int tipc_crypto_start(struct tipc_crypto **crypto, struct net *net,
        }
 
        /* Allocate statistic structure */
-       c->stats = alloc_percpu(struct tipc_crypto_stats);
+       c->stats = alloc_percpu_gfp(struct tipc_crypto_stats, GFP_ATOMIC);
        if (!c->stats) {
                if (c->wq)
                        destroy_workqueue(c->wq);
@@ -2461,7 +2461,7 @@ static void tipc_crypto_work_tx(struct work_struct *work)
        }
 
        /* Lets duplicate it first */
-       skey = kmemdup(aead->key, tipc_aead_key_size(aead->key), GFP_KERNEL);
+       skey = kmemdup(aead->key, tipc_aead_key_size(aead->key), GFP_ATOMIC);
        rcu_read_unlock();
 
        /* Now, generate new key, initiate & distribute it */
index bc4ad48..fd39bb6 100644 (file)
@@ -83,6 +83,7 @@ struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs,
                xskb = &pool->heads[i];
                xskb->pool = pool;
                xskb->xdp.frame_sz = umem->chunk_size - umem->headroom;
+               INIT_LIST_HEAD(&xskb->free_list_node);
                if (pool->unaligned)
                        pool->free_heads[i] = xskb;
                else
index 52a000b..3ccb2c7 100755 (executable)
@@ -219,7 +219,7 @@ if ($arch eq "x86_64") {
 
 } elsif ($arch eq "s390" && $bits == 64) {
     if ($cc =~ /-DCC_USING_HOTPATCH/) {
-       $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*(bcrl\\s*0,|jgnop\\s*)[0-9a-f]+ <([^\+]*)>\$";
+       $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*(brcl\\s*0,|jgnop\\s*)[0-9a-f]+ <([^\+]*)>\$";
        $mcount_adjust = 0;
     }
     $alignment = 8;
index 1afc06f..dde4ecc 100644 (file)
@@ -5785,7 +5785,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
        struct sk_security_struct *sksec;
        struct common_audit_data ad;
        struct lsm_network_audit net = {0,};
-       u8 proto;
+       u8 proto = 0;
 
        sk = skb_to_full_sk(skb);
        if (sk == NULL)
index 1da2e37..6799b11 100644 (file)
@@ -1051,10 +1051,11 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
                return false;
        if (!domain)
                return true;
+       if (READ_ONCE(domain->flags[TOMOYO_DIF_QUOTA_WARNED]))
+               return false;
        list_for_each_entry_rcu(ptr, &domain->acl_info_list, list,
                                srcu_read_lock_held(&tomoyo_ss)) {
                u16 perm;
-               u8 i;
 
                if (ptr->is_deleted)
                        continue;
@@ -1065,23 +1066,23 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
                 */
                switch (ptr->type) {
                case TOMOYO_TYPE_PATH_ACL:
-                       data_race(perm = container_of(ptr, struct tomoyo_path_acl, head)->perm);
+                       perm = data_race(container_of(ptr, struct tomoyo_path_acl, head)->perm);
                        break;
                case TOMOYO_TYPE_PATH2_ACL:
-                       data_race(perm = container_of(ptr, struct tomoyo_path2_acl, head)->perm);
+                       perm = data_race(container_of(ptr, struct tomoyo_path2_acl, head)->perm);
                        break;
                case TOMOYO_TYPE_PATH_NUMBER_ACL:
-                       data_race(perm = container_of(ptr, struct tomoyo_path_number_acl, head)
+                       perm = data_race(container_of(ptr, struct tomoyo_path_number_acl, head)
                                  ->perm);
                        break;
                case TOMOYO_TYPE_MKDEV_ACL:
-                       data_race(perm = container_of(ptr, struct tomoyo_mkdev_acl, head)->perm);
+                       perm = data_race(container_of(ptr, struct tomoyo_mkdev_acl, head)->perm);
                        break;
                case TOMOYO_TYPE_INET_ACL:
-                       data_race(perm = container_of(ptr, struct tomoyo_inet_acl, head)->perm);
+                       perm = data_race(container_of(ptr, struct tomoyo_inet_acl, head)->perm);
                        break;
                case TOMOYO_TYPE_UNIX_ACL:
-                       data_race(perm = container_of(ptr, struct tomoyo_unix_acl, head)->perm);
+                       perm = data_race(container_of(ptr, struct tomoyo_unix_acl, head)->perm);
                        break;
                case TOMOYO_TYPE_MANUAL_TASK_ACL:
                        perm = 0;
@@ -1089,21 +1090,17 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
                default:
                        perm = 1;
                }
-               for (i = 0; i < 16; i++)
-                       if (perm & (1 << i))
-                               count++;
+               count += hweight16(perm);
        }
        if (count < tomoyo_profile(domain->ns, domain->profile)->
            pref[TOMOYO_PREF_MAX_LEARNING_ENTRY])
                return true;
-       if (!domain->flags[TOMOYO_DIF_QUOTA_WARNED]) {
-               domain->flags[TOMOYO_DIF_QUOTA_WARNED] = true;
-               /* r->granted = false; */
-               tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]);
+       WRITE_ONCE(domain->flags[TOMOYO_DIF_QUOTA_WARNED], true);
+       /* r->granted = false; */
+       tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]);
 #ifndef CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING
-               pr_warn("WARNING: Domain '%s' has too many ACLs to hold. Stopped learning mode.\n",
-                       domain->domainname->name);
+       pr_warn("WARNING: Domain '%s' has too many ACLs to hold. Stopped learning mode.\n",
+               domain->domainname->name);
 #endif
-       }
        return false;
 }
index 32350c6..537df1e 100644 (file)
@@ -509,6 +509,10 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
                return -ENOMEM;
 
        jack->id = kstrdup(id, GFP_KERNEL);
+       if (jack->id == NULL) {
+               kfree(jack);
+               return -ENOMEM;
+       }
 
        /* don't creat input device for phantom jack */
        if (!phantom_jack) {
index 6f30231..befa980 100644 (file)
@@ -447,6 +447,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
                err = -ENOMEM;
                goto __error;
        }
+       rawmidi_file->user_pversion = 0;
        init_waitqueue_entry(&wait, current);
        add_wait_queue(&rmidi->open_wait, &wait);
        while (1) {
index e1b69c6..e2b7be6 100644 (file)
@@ -397,7 +397,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
        }
        if (instr_4op) {
                vp2 = &opl3->voices[voice + 3];
-               if (vp->state > 0) {
+               if (vp2->state > 0) {
                        opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK +
                                               voice_offset + 3);
                        reg_val = vp->keyon_reg & ~OPL3_KEYON_BIT;
index c0123bc..b7758db 100644 (file)
@@ -132,8 +132,6 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
                return AE_NOT_FOUND;
        }
 
-       info->handle = handle;
-
        /*
         * On some Intel platforms, multiple children of the HDAS
         * device can be found, but only one of them is the SoundWire
@@ -144,6 +142,9 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
        if (FIELD_GET(GENMASK(31, 28), adr) != SDW_LINK_TYPE)
                return AE_OK; /* keep going */
 
+       /* found the correct SoundWire controller */
+       info->handle = handle;
+
        /* device found, stop namespace walk */
        return AE_CTRL_TERMINATE;
 }
@@ -164,8 +165,14 @@ int sdw_intel_acpi_scan(acpi_handle *parent_handle,
        acpi_status status;
 
        info->handle = NULL;
+       /*
+        * In the HDAS ACPI scope, 'SNDW' may be either the child of
+        * 'HDAS' or the grandchild of 'HDAS'. So let's go through
+        * the ACPI from 'HDAS' at max depth of 2 to find the 'SNDW'
+        * device.
+        */
        status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
-                                    parent_handle, 1,
+                                    parent_handle, 2,
                                     sdw_intel_acpi_cb,
                                     NULL, info, NULL);
        if (ACPI_FAILURE(status) || info->handle == NULL)
index 415701b..ffcde74 100644 (file)
@@ -2947,7 +2947,8 @@ static int parse_intel_hdmi(struct hda_codec *codec)
 
 /* Intel Haswell and onwards; audio component with eld notifier */
 static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
-                                const int *port_map, int port_num, int dev_num)
+                                const int *port_map, int port_num, int dev_num,
+                                bool send_silent_stream)
 {
        struct hdmi_spec *spec;
        int err;
@@ -2980,7 +2981,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
         * Enable silent stream feature, if it is enabled via
         * module param or Kconfig option
         */
-       if (enable_silent_stream)
+       if (send_silent_stream)
                spec->send_silent_stream = true;
 
        return parse_intel_hdmi(codec);
@@ -2988,12 +2989,18 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
 
 static int patch_i915_hsw_hdmi(struct hda_codec *codec)
 {
-       return intel_hsw_common_init(codec, 0x08, NULL, 0, 3);
+       return intel_hsw_common_init(codec, 0x08, NULL, 0, 3,
+                                    enable_silent_stream);
 }
 
 static int patch_i915_glk_hdmi(struct hda_codec *codec)
 {
-       return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3);
+       /*
+        * Silent stream calls audio component .get_power() from
+        * .pin_eld_notify(). On GLK this will deadlock in i915 due
+        * to the audio vs. CDCLK workaround.
+        */
+       return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3, false);
 }
 
 static int patch_i915_icl_hdmi(struct hda_codec *codec)
@@ -3004,7 +3011,8 @@ static int patch_i915_icl_hdmi(struct hda_codec *codec)
         */
        static const int map[] = {0x0, 0x4, 0x6, 0x8, 0xa, 0xb};
 
-       return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 3);
+       return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 3,
+                                    enable_silent_stream);
 }
 
 static int patch_i915_tgl_hdmi(struct hda_codec *codec)
@@ -3016,7 +3024,8 @@ static int patch_i915_tgl_hdmi(struct hda_codec *codec)
        static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
        int ret;
 
-       ret = intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4);
+       ret = intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4,
+                                   enable_silent_stream);
        if (!ret) {
                struct hdmi_spec *spec = codec->spec;
 
index 3599f4c..28255e7 100644 (file)
@@ -6546,6 +6546,23 @@ static void alc233_fixup_no_audio_jack(struct hda_codec *codec,
        alc_process_coef_fw(codec, alc233_fixup_no_audio_jack_coefs);
 }
 
+static void alc256_fixup_mic_no_presence_and_resume(struct hda_codec *codec,
+                                                   const struct hda_fixup *fix,
+                                                   int action)
+{
+       /*
+        * The Clevo NJ51CU comes either with the ALC293 or the ALC256 codec,
+        * but uses the 0x8686 subproduct id in both cases. The ALC256 codec
+        * needs an additional quirk for sound working after suspend and resume.
+        */
+       if (codec->core.vendor_id == 0x10ec0256) {
+               alc_update_coef_idx(codec, 0x10, 1<<9, 0);
+               snd_hda_codec_set_pincfg(codec, 0x19, 0x04a11120);
+       } else {
+               snd_hda_codec_set_pincfg(codec, 0x1a, 0x04a1113c);
+       }
+}
+
 enum {
        ALC269_FIXUP_GPIO2,
        ALC269_FIXUP_SONY_VAIO,
@@ -6766,6 +6783,7 @@ enum {
        ALC256_FIXUP_SET_COEF_DEFAULTS,
        ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
        ALC233_FIXUP_NO_AUDIO_JACK,
+       ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -8490,6 +8508,12 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc233_fixup_no_audio_jack,
        },
+       [ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc256_fixup_mic_no_presence_and_resume,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -8660,6 +8684,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x84da, "HP OMEN dc0019-ur", ALC295_FIXUP_HP_OMEN),
        SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3),
        SND_PCI_QUIRK(0x103c, 0x8519, "HP Spectre x360 15-df0xxx", ALC285_FIXUP_HP_SPECTRE_X360),
+       SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT),
        SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT),
        SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED),
        SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
@@ -8705,6 +8730,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8896, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_MUTE_LED),
        SND_PCI_QUIRK(0x103c, 0x8898, "HP EliteBook 845 G8 Notebook PC", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x103c, 0x88d0, "HP Pavilion 15-eh1xxx (mainboard 88D0)", ALC287_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -8829,7 +8855,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1558, 0x8562, "Clevo NH[57][0-9]RZ[Q]", ALC269_FIXUP_DMIC),
        SND_PCI_QUIRK(0x1558, 0x8668, "Clevo NP50B[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8680, "Clevo NJ50LU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8686, "Clevo NH50[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8686, "Clevo NH50[CZ]U", ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME),
        SND_PCI_QUIRK(0x1558, 0x8a20, "Clevo NH55DCQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8a51, "Clevo NH70RCQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8d50, "Clevo NH55RCQ-M", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -9123,6 +9149,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP, .name = "alc287-ideapad-bass-spk-amp"},
        {.id = ALC623_FIXUP_LENOVO_THINKSTATION_P340, .name = "alc623-lenovo-thinkstation-p340"},
        {.id = ALC255_FIXUP_ACER_HEADPHONE_AND_MIC, .name = "alc255-acer-headphone-and-mic"},
+       {.id = ALC285_FIXUP_HP_GPIO_AMP_INIT, .name = "alc285-hp-amp-init"},
        {}
 };
 #define ALC225_STANDARD_PINS \
index 5224123..b34a854 100644 (file)
@@ -929,6 +929,8 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
        unsigned int val, count;
 
        if (jack_insert) {
+               snd_soc_dapm_mutex_lock(dapm);
+
                snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1,
                        RT5682_PWR_VREF2 | RT5682_PWR_MB,
                        RT5682_PWR_VREF2 | RT5682_PWR_MB);
@@ -979,6 +981,8 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
                snd_soc_component_update_bits(component, RT5682_MICBIAS_2,
                        RT5682_PWR_CLK25M_MASK | RT5682_PWR_CLK1M_MASK,
                        RT5682_PWR_CLK25M_PU | RT5682_PWR_CLK1M_PU);
+
+               snd_soc_dapm_mutex_unlock(dapm);
        } else {
                rt5682_enable_push_button_irq(component, false);
                snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
index 172e79c..6549e7f 100644 (file)
@@ -291,11 +291,11 @@ static int tas2770_set_samplerate(struct tas2770_priv *tas2770, int samplerate)
                ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_44_1KHZ |
                                TAS2770_TDM_CFG_REG0_31_88_2_96KHZ;
                break;
-       case 19200:
+       case 192000:
                ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_48KHZ |
                                TAS2770_TDM_CFG_REG0_31_176_4_192KHZ;
                break;
-       case 17640:
+       case 176400:
                ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_44_1KHZ |
                                TAS2770_TDM_CFG_REG0_31_176_4_192KHZ;
                break;
index 9322245..67729de 100644 (file)
@@ -18,7 +18,6 @@
 #define AIU_RST_SOFT_I2S_FAST          BIT(0)
 
 #define AIU_I2S_DAC_CFG_MSB_FIRST      BIT(2)
-#define AIU_I2S_MISC_HOLD_EN           BIT(2)
 #define AIU_CLK_CTRL_I2S_DIV_EN                BIT(0)
 #define AIU_CLK_CTRL_I2S_DIV           GENMASK(3, 2)
 #define AIU_CLK_CTRL_AOCLK_INVERT      BIT(6)
@@ -36,37 +35,6 @@ static void aiu_encoder_i2s_divider_enable(struct snd_soc_component *component,
                                      enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0);
 }
 
-static void aiu_encoder_i2s_hold(struct snd_soc_component *component,
-                                bool enable)
-{
-       snd_soc_component_update_bits(component, AIU_I2S_MISC,
-                                     AIU_I2S_MISC_HOLD_EN,
-                                     enable ? AIU_I2S_MISC_HOLD_EN : 0);
-}
-
-static int aiu_encoder_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
-                                  struct snd_soc_dai *dai)
-{
-       struct snd_soc_component *component = dai->component;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               aiu_encoder_i2s_hold(component, false);
-               return 0;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               aiu_encoder_i2s_hold(component, true);
-               return 0;
-
-       default:
-               return -EINVAL;
-       }
-}
-
 static int aiu_encoder_i2s_setup_desc(struct snd_soc_component *component,
                                      struct snd_pcm_hw_params *params)
 {
@@ -353,7 +321,6 @@ static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream,
 }
 
 const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops = {
-       .trigger        = aiu_encoder_i2s_trigger,
        .hw_params      = aiu_encoder_i2s_hw_params,
        .hw_free        = aiu_encoder_i2s_hw_free,
        .set_fmt        = aiu_encoder_i2s_set_fmt,
index 2388a2d..57e6e71 100644 (file)
@@ -20,6 +20,8 @@
 #define AIU_MEM_I2S_CONTROL_MODE_16BIT BIT(6)
 #define AIU_MEM_I2S_BUF_CNTL_INIT      BIT(0)
 #define AIU_RST_SOFT_I2S_FAST          BIT(0)
+#define AIU_I2S_MISC_HOLD_EN           BIT(2)
+#define AIU_I2S_MISC_FORCE_LEFT_RIGHT  BIT(4)
 
 #define AIU_FIFO_I2S_BLOCK             256
 
@@ -90,6 +92,10 @@ static int aiu_fifo_i2s_hw_params(struct snd_pcm_substream *substream,
        unsigned int val;
        int ret;
 
+       snd_soc_component_update_bits(component, AIU_I2S_MISC,
+                                     AIU_I2S_MISC_HOLD_EN,
+                                     AIU_I2S_MISC_HOLD_EN);
+
        ret = aiu_fifo_hw_params(substream, params, dai);
        if (ret)
                return ret;
@@ -117,6 +123,19 @@ static int aiu_fifo_i2s_hw_params(struct snd_pcm_substream *substream,
        snd_soc_component_update_bits(component, AIU_MEM_I2S_MASKS,
                                      AIU_MEM_I2S_MASKS_IRQ_BLOCK, val);
 
+       /*
+        * Most (all?) supported SoCs have this bit set by default. The vendor
+        * driver however sets it manually (depending on the version either
+        * while un-setting AIU_I2S_MISC_HOLD_EN or right before that). Follow
+        * the same approach for consistency with the vendor driver.
+        */
+       snd_soc_component_update_bits(component, AIU_I2S_MISC,
+                                     AIU_I2S_MISC_FORCE_LEFT_RIGHT,
+                                     AIU_I2S_MISC_FORCE_LEFT_RIGHT);
+
+       snd_soc_component_update_bits(component, AIU_I2S_MISC,
+                                     AIU_I2S_MISC_HOLD_EN, 0);
+
        return 0;
 }
 
index 4ad2326..d67ff4c 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/bitfield.h>
 #include <linux/clk.h>
+#include <linux/dma-mapping.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
@@ -179,6 +180,11 @@ int aiu_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd,
        struct snd_card *card = rtd->card->snd_card;
        struct aiu_fifo *fifo = dai->playback_dma_data;
        size_t size = fifo->pcm->buffer_bytes_max;
+       int ret;
+
+       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
 
        snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
                                       card->dev, size, size);
index f2ea34d..fd46210 100644 (file)
@@ -112,8 +112,12 @@ static const struct pci_device_id sof_pci_ids[] = {
                .driver_data = (unsigned long)&adls_desc},
        { PCI_DEVICE(0x8086, 0x51c8), /* ADL-P */
                .driver_data = (unsigned long)&adl_desc},
+       { PCI_DEVICE(0x8086, 0x51cd), /* ADL-P */
+               .driver_data = (unsigned long)&adl_desc},
        { PCI_DEVICE(0x8086, 0x51cc), /* ADL-M */
                .driver_data = (unsigned long)&adl_desc},
+       { PCI_DEVICE(0x8086, 0x54c8), /* ADL-N */
+               .driver_data = (unsigned long)&adl_desc},
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, sof_pci_ids);
index b95438c..a734048 100644 (file)
@@ -116,16 +116,24 @@ static const struct snd_kcontrol_new tegra_machine_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
        SOC_DAPM_PIN_SWITCH("Internal Mic 1"),
        SOC_DAPM_PIN_SWITCH("Internal Mic 2"),
+       SOC_DAPM_PIN_SWITCH("Headphones"),
+       SOC_DAPM_PIN_SWITCH("Mic Jack"),
 };
 
 int tegra_asoc_machine_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_card *card = rtd->card;
        struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
+       const char *jack_name;
        int err;
 
        if (machine->gpiod_hp_det && machine->asoc->add_hp_jack) {
-               err = snd_soc_card_jack_new(card, "Headphones Jack",
+               if (machine->asoc->hp_jack_name)
+                       jack_name = machine->asoc->hp_jack_name;
+               else
+                       jack_name = "Headphones Jack";
+
+               err = snd_soc_card_jack_new(card, jack_name,
                                            SND_JACK_HEADPHONE,
                                            &tegra_machine_hp_jack,
                                            tegra_machine_hp_jack_pins,
@@ -658,6 +666,7 @@ static struct snd_soc_card snd_soc_tegra_max98090 = {
 static const struct tegra_asoc_data tegra_max98090_data = {
        .mclk_rate = tegra_machine_mclk_rate_12mhz,
        .card = &snd_soc_tegra_max98090,
+       .hp_jack_name = "Headphones",
        .add_common_dapm_widgets = true,
        .add_common_controls = true,
        .add_common_snd_ops = true,
index d6a8d13..6f795d7 100644 (file)
@@ -14,6 +14,7 @@ struct snd_soc_pcm_runtime;
 struct tegra_asoc_data {
        unsigned int (*mclk_rate)(unsigned int srate);
        const char *codec_dev_name;
+       const char *hp_jack_name;
        struct snd_soc_card *card;
        unsigned int mclk_id;
        bool hp_jack_gpio_active_low;
index 9434367..c82b033 100644 (file)
@@ -2473,7 +2473,7 @@ static int process_switch_event(struct perf_tool *tool,
        if (perf_event__process_switch(tool, event, sample, machine) < 0)
                return -1;
 
-       if (scripting_ops && scripting_ops->process_switch)
+       if (scripting_ops && scripting_ops->process_switch && !filter_cpu(sample))
                scripting_ops->process_switch(event, sample, machine);
 
        if (!script->show_switch_events)
index 1d3a189..66452a8 100644 (file)
@@ -32,8 +32,7 @@ try:
 except:
        broken_pipe_exception = IOError
 
-glb_switch_str         = None
-glb_switch_printed     = True
+glb_switch_str         = {}
 glb_insn               = False
 glb_disassembler       = None
 glb_src                        = False
@@ -70,6 +69,7 @@ def trace_begin():
        ap = argparse.ArgumentParser(usage = "", add_help = False)
        ap.add_argument("--insn-trace", action='store_true')
        ap.add_argument("--src-trace", action='store_true')
+       ap.add_argument("--all-switch-events", action='store_true')
        global glb_args
        global glb_insn
        global glb_src
@@ -256,10 +256,6 @@ def print_srccode(comm, param_dict, sample, symbol, dso, with_insn):
        print(start_str, src_str)
 
 def do_process_event(param_dict):
-       global glb_switch_printed
-       if not glb_switch_printed:
-               print(glb_switch_str)
-               glb_switch_printed = True
        event_attr = param_dict["attr"]
        sample     = param_dict["sample"]
        raw_buf    = param_dict["raw_buf"]
@@ -274,6 +270,11 @@ def do_process_event(param_dict):
        dso    = get_optional(param_dict, "dso")
        symbol = get_optional(param_dict, "symbol")
 
+       cpu = sample["cpu"]
+       if cpu in glb_switch_str:
+               print(glb_switch_str[cpu])
+               del glb_switch_str[cpu]
+
        if name[0:12] == "instructions":
                if glb_src:
                        print_srccode(comm, param_dict, sample, symbol, dso, True)
@@ -336,8 +337,6 @@ def auxtrace_error(typ, code, cpu, pid, tid, ip, ts, msg, cpumode, *x):
                sys.exit(1)
 
 def context_switch(ts, cpu, pid, tid, np_pid, np_tid, machine_pid, out, out_preempt, *x):
-       global glb_switch_printed
-       global glb_switch_str
        if out:
                out_str = "Switch out "
        else:
@@ -350,6 +349,10 @@ def context_switch(ts, cpu, pid, tid, np_pid, np_tid, machine_pid, out, out_pree
                machine_str = ""
        else:
                machine_str = "machine PID %d" % machine_pid
-       glb_switch_str = "%16s %5d/%-5d [%03u] %9u.%09u %5d/%-5d %s %s" % \
+       switch_str = "%16s %5d/%-5d [%03u] %9u.%09u %5d/%-5d %s %s" % \
                (out_str, pid, tid, cpu, ts / 1000000000, ts %1000000000, np_pid, np_tid, machine_str, preempt_str)
-       glb_switch_printed = False
+       if glb_args.all_switch_events:
+               print(switch_str);
+       else:
+               global glb_switch_str
+               glb_switch_str[cpu] = switch_str
index e9bfe85..b1be59b 100644 (file)
@@ -170,9 +170,11 @@ void ui__exit(bool wait_for_ok)
                                    "Press any key...", 0);
 
        SLtt_set_cursor_visibility(1);
-       SLsmg_refresh();
-       SLsmg_reset_smg();
+       if (!pthread_mutex_trylock(&ui__lock)) {
+               SLsmg_refresh();
+               SLsmg_reset_smg();
+               pthread_mutex_unlock(&ui__lock);
+       }
        SLang_reset_tty();
-
        perf_error__unregister(&perf_tui_eops);
 }
index 2546010..666b59b 100644 (file)
@@ -66,7 +66,12 @@ static bool key_equal(const void *key1, const void *key2,
 
 struct hashmap *ids__new(void)
 {
-       return hashmap__new(key_hash, key_equal, NULL);
+       struct hashmap *hash;
+
+       hash = hashmap__new(key_hash, key_equal, NULL);
+       if (IS_ERR(hash))
+               return NULL;
+       return hash;
 }
 
 void ids__free(struct hashmap *ids)
index 10c3187..e8613cb 100644 (file)
@@ -3625,6 +3625,7 @@ static int intel_pt_parse_vm_tm_corr_arg(struct intel_pt *pt, char **args)
                *args = p;
                return 0;
        }
+       p += 1;
        while (1) {
                vmcs = strtoull(p, &p, 0);
                if (errno)
index 6ae5840..8dfbba1 100644 (file)
@@ -1659,6 +1659,21 @@ bool is_pmu_core(const char *name)
        return !strcmp(name, "cpu") || is_arm_pmu_core(name);
 }
 
+static bool pmu_alias_is_duplicate(struct sevent *alias_a,
+                                  struct sevent *alias_b)
+{
+       /* Different names -> never duplicates */
+       if (strcmp(alias_a->name, alias_b->name))
+               return false;
+
+       /* Don't remove duplicates for hybrid PMUs */
+       if (perf_pmu__is_hybrid(alias_a->pmu) &&
+           perf_pmu__is_hybrid(alias_b->pmu))
+               return false;
+
+       return true;
+}
+
 void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
                        bool long_desc, bool details_flag, bool deprecated,
                        const char *pmu_name)
@@ -1744,12 +1759,8 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
        qsort(aliases, len, sizeof(struct sevent), cmp_sevent);
        for (j = 0; j < len; j++) {
                /* Skip duplicates */
-               if (j > 0 && !strcmp(aliases[j].name, aliases[j - 1].name)) {
-                       if (!aliases[j].pmu || !aliases[j - 1].pmu ||
-                           !strcmp(aliases[j].pmu, aliases[j - 1].pmu)) {
-                               continue;
-                       }
-               }
+               if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1]))
+                       continue;
 
                if (name_only) {
                        printf("%s ", aliases[j].name);
index 00814c0..3cb5ac5 100644 (file)
@@ -35,6 +35,7 @@
 /x86_64/vmx_apic_access_test
 /x86_64/vmx_close_while_nested_test
 /x86_64/vmx_dirty_log_test
+/x86_64/vmx_invalid_nested_guest_state
 /x86_64/vmx_preemption_timer_test
 /x86_64/vmx_set_nested_state_test
 /x86_64/vmx_tsc_adjust_test
index f307c9f..17342b5 100644 (file)
@@ -64,6 +64,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/userspace_msr_exit_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_apic_access_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_close_while_nested_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_dirty_log_test
+TEST_GEN_PROGS_x86_64 += x86_64/vmx_invalid_nested_guest_state
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_set_nested_state_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_nested_tsc_scaling_test
index da2b702..2d62edc 100644 (file)
@@ -71,15 +71,6 @@ enum vm_guest_mode {
 
 #endif
 
-#if defined(__x86_64__)
-unsigned long vm_compute_max_gfn(struct kvm_vm *vm);
-#else
-static inline unsigned long vm_compute_max_gfn(struct kvm_vm *vm)
-{
-       return ((1ULL << vm->pa_bits) >> vm->page_shift) - 1;
-}
-#endif
-
 #define MIN_PAGE_SIZE          (1U << MIN_PAGE_SHIFT)
 #define PTES_PER_MIN_PAGE      ptes_per_page(MIN_PAGE_SIZE)
 
@@ -330,6 +321,7 @@ bool vm_is_unrestricted_guest(struct kvm_vm *vm);
 
 unsigned int vm_get_page_size(struct kvm_vm *vm);
 unsigned int vm_get_page_shift(struct kvm_vm *vm);
+unsigned long vm_compute_max_gfn(struct kvm_vm *vm);
 uint64_t vm_get_max_gfn(struct kvm_vm *vm);
 int vm_get_fd(struct kvm_vm *vm);
 
index daf6fdb..53d2b5d 100644 (file)
@@ -2328,6 +2328,11 @@ unsigned int vm_get_page_shift(struct kvm_vm *vm)
        return vm->page_shift;
 }
 
+unsigned long __attribute__((weak)) vm_compute_max_gfn(struct kvm_vm *vm)
+{
+       return ((1ULL << vm->pa_bits) >> vm->page_shift) - 1;
+}
+
 uint64_t vm_get_max_gfn(struct kvm_vm *vm)
 {
        return vm->max_gfn;
diff --git a/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c b/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c
new file mode 100644 (file)
index 0000000..489fbed
--- /dev/null
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+#include "vmx.h"
+
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "kselftest.h"
+
+#define VCPU_ID        0
+#define ARBITRARY_IO_PORT 0x2000
+
+static struct kvm_vm *vm;
+
+static void l2_guest_code(void)
+{
+       /*
+        * Generate an exit to L0 userspace, i.e. main(), via I/O to an
+        * arbitrary port.
+        */
+       asm volatile("inb %%dx, %%al"
+                    : : [port] "d" (ARBITRARY_IO_PORT) : "rax");
+}
+
+static void l1_guest_code(struct vmx_pages *vmx_pages)
+{
+#define L2_GUEST_STACK_SIZE 64
+       unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
+
+       GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages));
+       GUEST_ASSERT(load_vmcs(vmx_pages));
+
+       /* Prepare the VMCS for L2 execution. */
+       prepare_vmcs(vmx_pages, l2_guest_code,
+                    &l2_guest_stack[L2_GUEST_STACK_SIZE]);
+
+       /*
+        * L2 must be run without unrestricted guest, verify that the selftests
+        * library hasn't enabled it.  Because KVM selftests jump directly to
+        * 64-bit mode, unrestricted guest support isn't required.
+        */
+       GUEST_ASSERT(!(vmreadz(CPU_BASED_VM_EXEC_CONTROL) & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) ||
+                    !(vmreadz(SECONDARY_VM_EXEC_CONTROL) & SECONDARY_EXEC_UNRESTRICTED_GUEST));
+
+       GUEST_ASSERT(!vmlaunch());
+
+       /* L2 should triple fault after main() stuffs invalid guest state. */
+       GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_TRIPLE_FAULT);
+       GUEST_DONE();
+}
+
+int main(int argc, char *argv[])
+{
+       vm_vaddr_t vmx_pages_gva;
+       struct kvm_sregs sregs;
+       struct kvm_run *run;
+       struct ucall uc;
+
+       nested_vmx_check_supported();
+
+       vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code);
+
+       /* Allocate VMX pages and shared descriptors (vmx_pages). */
+       vcpu_alloc_vmx(vm, &vmx_pages_gva);
+       vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva);
+
+       vcpu_run(vm, VCPU_ID);
+
+       run = vcpu_state(vm, VCPU_ID);
+
+       /*
+        * The first exit to L0 userspace should be an I/O access from L2.
+        * Running L1 should launch L2 without triggering an exit to userspace.
+        */
+       TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+                   "Expected KVM_EXIT_IO, got: %u (%s)\n",
+                   run->exit_reason, exit_reason_str(run->exit_reason));
+
+       TEST_ASSERT(run->io.port == ARBITRARY_IO_PORT,
+                   "Expected IN from port %d from L2, got port %d",
+                   ARBITRARY_IO_PORT, run->io.port);
+
+       /*
+        * Stuff invalid guest state for L2 by making TR unusuable.  The next
+        * KVM_RUN should induce a TRIPLE_FAULT in L2 as KVM doesn't support
+        * emulating invalid guest state for L2.
+        */
+       memset(&sregs, 0, sizeof(sregs));
+       vcpu_sregs_get(vm, VCPU_ID, &sregs);
+       sregs.tr.unusable = 1;
+       vcpu_sregs_set(vm, VCPU_ID, &sregs);
+
+       vcpu_run(vm, VCPU_ID);
+
+       switch (get_ucall(vm, VCPU_ID, &uc)) {
+       case UCALL_DONE:
+               break;
+       case UCALL_ABORT:
+               TEST_FAIL("%s", (const char *)uc.args[0]);
+       default:
+               TEST_FAIL("Unexpected ucall: %lu", uc.cmd);
+       }
+}
index 0faaccd..2b82628 100644 (file)
@@ -9,7 +9,6 @@ CONFIG_NETFILTER=y
 CONFIG_NETFILTER_ADVANCED=y
 CONFIG_NETFILTER_NETLINK=m
 CONFIG_NF_TABLES=m
-CONFIG_NFT_COUNTER=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XTABLES=m
 CONFIG_NETFILTER_XT_MATCH_BPF=m
index 7f26591..3ea7301 100755 (executable)
@@ -132,7 +132,7 @@ run_test() {
        local rcv=`ip netns exec $NS_DST $ipt"-save" -c | grep 'dport 8000' | \
                                                          sed -e 's/\[//' -e 's/:.*//'`
        if [ $rcv != $pkts ]; then
-               echo " fail - received $rvs packets, expected $pkts"
+               echo " fail - received $rcv packets, expected $pkts"
                ret=1
                return
        fi
@@ -185,6 +185,7 @@ for family in 4 6; do
        IPT=iptables
        SUFFIX=24
        VXDEV=vxlan
+       PING=ping
 
        if [ $family = 6 ]; then
                BM_NET=$BM_NET_V6
@@ -192,6 +193,7 @@ for family in 4 6; do
                SUFFIX="64 nodad"
                VXDEV=vxlan6
                IPT=ip6tables
+               PING="ping6"
        fi
 
        echo "IPv$family"
@@ -237,7 +239,7 @@ for family in 4 6; do
 
        # load arp cache before running the test to reduce the amount of
        # stray traffic on top of the UDP tunnel
-       ip netns exec $NS_SRC ping -q -c 1 $OL_NET$DST_NAT >/dev/null
+       ip netns exec $NS_SRC $PING -q -c 1 $OL_NET$DST_NAT >/dev/null
        run_test "GRO fwd over UDP tunnel" $OL_NET$DST_NAT 1 1 $OL_NET$DST
        cleanup
 
index c66da6f..7badaf2 100644 (file)
@@ -156,13 +156,13 @@ struct testcase testcases_v4[] = {
        },
        {
                /* send max number of min sized segments */
-               .tlen = UDP_MAX_SEGMENTS - CONST_HDRLEN_V4,
+               .tlen = UDP_MAX_SEGMENTS,
                .gso_len = 1,
-               .r_num_mss = UDP_MAX_SEGMENTS - CONST_HDRLEN_V4,
+               .r_num_mss = UDP_MAX_SEGMENTS,
        },
        {
                /* send max number + 1 of min sized segments: fail */
-               .tlen = UDP_MAX_SEGMENTS - CONST_HDRLEN_V4 + 1,
+               .tlen = UDP_MAX_SEGMENTS + 1,
                .gso_len = 1,
                .tfail = true,
        },
@@ -259,13 +259,13 @@ struct testcase testcases_v6[] = {
        },
        {
                /* send max number of min sized segments */
-               .tlen = UDP_MAX_SEGMENTS - CONST_HDRLEN_V6,
+               .tlen = UDP_MAX_SEGMENTS,
                .gso_len = 1,
-               .r_num_mss = UDP_MAX_SEGMENTS - CONST_HDRLEN_V6,
+               .r_num_mss = UDP_MAX_SEGMENTS,
        },
        {
                /* send max number + 1 of min sized segments: fail */
-               .tlen = UDP_MAX_SEGMENTS - CONST_HDRLEN_V6 + 1,
+               .tlen = UDP_MAX_SEGMENTS + 1,
                .gso_len = 1,
                .tfail = true,
        },
index 17512a4..f1fdaa2 100644 (file)
@@ -419,6 +419,7 @@ static void usage(const char *filepath)
 
 static void parse_opts(int argc, char **argv)
 {
+       const char *bind_addr = NULL;
        int max_len, hdrlen;
        int c;
 
@@ -446,7 +447,7 @@ static void parse_opts(int argc, char **argv)
                        cfg_cpu = strtol(optarg, NULL, 0);
                        break;
                case 'D':
-                       setup_sockaddr(cfg_family, optarg, &cfg_dst_addr);
+                       bind_addr = optarg;
                        break;
                case 'l':
                        cfg_runtime_ms = strtoul(optarg, NULL, 10) * 1000;
@@ -492,6 +493,11 @@ static void parse_opts(int argc, char **argv)
                }
        }
 
+       if (!bind_addr)
+               bind_addr = cfg_family == PF_INET6 ? "::" : "0.0.0.0";
+
+       setup_sockaddr(cfg_family, bind_addr, &cfg_dst_addr);
+
        if (optind != argc)
                usage(argv[0]);
 
index 8a09057..9354a5e 100644 (file)
@@ -87,7 +87,7 @@ static bool test_uffdio_minor = false;
 
 static bool map_shared;
 static int shm_fd;
-static int huge_fd;
+static int huge_fd = -1;       /* only used for hugetlb_shared test */
 static char *huge_fd_off0;
 static unsigned long long *count_verify;
 static int uffd = -1;
@@ -223,6 +223,9 @@ static void noop_alias_mapping(__u64 *start, size_t len, unsigned long offset)
 
 static void hugetlb_release_pages(char *rel_area)
 {
+       if (huge_fd == -1)
+               return;
+
        if (fallocate(huge_fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
                      rel_area == huge_fd_off0 ? 0 : nr_pages * page_size,
                      nr_pages * page_size))
@@ -235,16 +238,17 @@ static void hugetlb_allocate_area(void **alloc_area)
        char **alloc_area_alias;
 
        *alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE,
-                          (map_shared ? MAP_SHARED : MAP_PRIVATE) |
-                          MAP_HUGETLB,
-                          huge_fd, *alloc_area == area_src ? 0 :
-                          nr_pages * page_size);
+                          map_shared ? MAP_SHARED :
+                          MAP_PRIVATE | MAP_HUGETLB |
+                          (*alloc_area == area_src ? 0 : MAP_NORESERVE),
+                          huge_fd,
+                          *alloc_area == area_src ? 0 : nr_pages * page_size);
        if (*alloc_area == MAP_FAILED)
                err("mmap of hugetlbfs file failed");
 
        if (map_shared) {
                area_alias = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE,
-                                 MAP_SHARED | MAP_HUGETLB,
+                                 MAP_SHARED,
                                  huge_fd, *alloc_area == area_src ? 0 :
                                  nr_pages * page_size);
                if (area_alias == MAP_FAILED)