mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Cross-merge networking fixes after downstream PR (net-7.1-rc6). Conflicts: drivers/net/phy/air_en8811h.cd895767c33("net: phy: air_en8811h: add AN8811HB MCU assert/deassert support")dddfadd751("net: phy: Add Airoha phy library for shared code")5226bb6634("net: phy: air_phy_lib: Factorize BuckPBus register accessors")e08f0ea6da("net: phy: Rename Airoha common BuckPBus register accessors") net/sched/sch_netem.ca2f6ed7b48("net/sched: netem: add per-impairment extended statistics")9552b11e3e("net/sched: fix packet loop on netem when duplicate is on") Adjacent changes: drivers/dpll/zl3073x/core.cc1224569ce("dpll: zl3073x: make frequency monitor a per-device attribute")54e65df8cf("dpll: zl3073x: report FFO as DPLL vs input reference offset") net/iucv/af_iucv.c347fdd4df8("af_iucv: convert to getsockopt_iter")3589d20a66("net/iucv: fix locking in .getsockopt") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
d44646fc9e
6
.mailmap
6
.mailmap
|
|
@ -263,8 +263,9 @@ Enric Balletbo i Serra <eballetbo@kernel.org> <enric.balletbo@collabora.com>
|
|||
Enric Balletbo i Serra <eballetbo@kernel.org> <eballetbo@iseebcn.com>
|
||||
Erik Kaneda <erik.kaneda@intel.com> <erik.schmauss@intel.com>
|
||||
Ethan Carter Edwards <ethan@ethancedwards.com> Ethan Edwards <ethancarteredwards@gmail.com>
|
||||
Eugen Hristev <eugen.hristev@linaro.org> <eugen.hristev@microchip.com>
|
||||
Eugen Hristev <eugen.hristev@linaro.org> <eugen.hristev@collabora.com>
|
||||
Eugen Hristev <ehristev@kernel.org> <eugen.hristev@microchip.com>
|
||||
Eugen Hristev <ehristev@kernel.org> <eugen.hristev@linaro.org>
|
||||
Eugen Hristev <ehristev@kernel.org> <eugen.hristev@collabora.com>
|
||||
Evgeniy Polyakov <johnpol@2ka.mipt.ru>
|
||||
Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> <ezequiel@collabora.com>
|
||||
Faith Ekstrand <faith.ekstrand@collabora.com> <jason@jlekstrand.net>
|
||||
|
|
@ -339,6 +340,7 @@ Henrik Rydberg <rydberg@bitmath.org>
|
|||
Herbert Xu <herbert@gondor.apana.org.au>
|
||||
Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com>
|
||||
Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
|
||||
Ian Ray <ian.ray@gehealthcare.com> <ian.ray@ge.com>
|
||||
Ignat Korchagin <ignat@linux.win> <ignat@cloudflare.com>
|
||||
Igor Korotin <igor.korotin@linux.dev> <igor.korotin.linux@gmail.com>
|
||||
Ike Panhc <ikepanhc@gmail.com> <ike.pan@canonical.com>
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@ Support for changing the platform performance mode is currently not implemented.
|
|||
Battery Charging Control
|
||||
------------------------
|
||||
|
||||
.. warning:: Some devices do not properly implement the charging threshold interface. Forcing
|
||||
the driver to enable access to said interface on such devices might damage the
|
||||
battery [1]_. Because of this the driver will not enable said feature even when
|
||||
using the ``force`` module parameter.
|
||||
|
||||
The ``uniwill-laptop`` driver supports controlling the battery charge limit. This happens over
|
||||
the standard ``charge_control_end_threshold`` power supply sysfs attribute. All values
|
||||
between 1 and 100 percent are supported.
|
||||
|
|
@ -70,3 +75,8 @@ The ``uniwill-laptop`` driver allows to set the configurable TGP for devices wit
|
|||
allow it.
|
||||
|
||||
See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://www.reddit.com/r/XMG_gg/comments/ld9yyf/battery_limit_hidden_function_discovered_on/
|
||||
|
|
|
|||
|
|
@ -358,9 +358,9 @@ Dynamic energy performance profile
|
|||
The amd-pstate driver supports dynamically selecting the energy performance
|
||||
profile based on whether the machine is running on AC or DC power.
|
||||
|
||||
Whether this behavior is enabled by default depends on the kernel
|
||||
config option `CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP`. This behavior can also be overridden
|
||||
at runtime by the sysfs file ``/sys/devices/system/cpu/cpufreq/policyX/dynamic_epp``.
|
||||
Whether this behavior is enabled by default depends on the kernel command line option
|
||||
``amd_dynamic_epp`` is set. This behavior can also be overridden
|
||||
at runtime by the sysfs file ``/sys/devices/system/cpu/amd_pstate/dynamic_epp``.
|
||||
|
||||
When set to enabled, the driver will select a different energy performance
|
||||
profile when the machine is running on battery or AC power. The driver will
|
||||
|
|
@ -485,9 +485,8 @@ kernel parameter ``amd_prefcore=disable``.
|
|||
``amd_dynamic_epp``
|
||||
|
||||
When AMD pstate is in auto mode, dynamic EPP will control whether the kernel
|
||||
autonomously changes the EPP mode. The default is configured by
|
||||
``CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP`` but can be explicitly enabled with
|
||||
``amd_dynamic_epp=enable`` or disabled with ``amd_dynamic_epp=disable``.
|
||||
autonomously changes the EPP mode. The default is disabled. It can be enabled
|
||||
with the kernel parameter ``amd_dynamic_epp=enable``.
|
||||
|
||||
User Space Interface in ``sysfs`` - General
|
||||
===========================================
|
||||
|
|
|
|||
|
|
@ -355,11 +355,12 @@ HyperThreading (HT) in the context of Intel processors, is enabled on at least
|
|||
one core, ``intel_pstate`` assigns performance-based priorities to CPUs. Namely,
|
||||
the priority of a given CPU reflects its highest HWP performance level which
|
||||
causes the CPU scheduler to generally prefer more performant CPUs, so the less
|
||||
performant CPUs are used when the other ones are fully loaded. However, SMT
|
||||
siblings (that is, logical CPUs sharing one physical core) are treated in a
|
||||
special way such that if one of them is in use, the effective priority of the
|
||||
other ones is lowered below the priorities of the CPUs located in the other
|
||||
physical cores.
|
||||
performant CPUs are used when the other ones are fully loaded. SMT siblings
|
||||
(that is, logical CPUs sharing one physical core) are given the same priority.
|
||||
The scheduler can pull tasks from lower-priority cores and place them on any
|
||||
sibling. Since the scheduler spreads tasks among physical cores, tasks will be
|
||||
placed on the SMT siblings of physical cores only after all physical cores are
|
||||
busy.
|
||||
|
||||
This approach maximizes performance in the majority of cases, but unfortunately
|
||||
it also leads to excessive energy usage in some important scenarios, like video
|
||||
|
|
|
|||
|
|
@ -219,6 +219,7 @@ allOf:
|
|||
- required:
|
||||
- "#sound-dai-cells"
|
||||
else:
|
||||
$ref: /schemas/sound/dai-common.yaml#
|
||||
properties:
|
||||
aux-bus: false
|
||||
required:
|
||||
|
|
@ -243,7 +244,7 @@ allOf:
|
|||
clocks:
|
||||
minItems: 5
|
||||
maxItems: 5
|
||||
clocks-names:
|
||||
clock-names:
|
||||
minItems: 5
|
||||
maxItems: 5
|
||||
|
||||
|
|
@ -264,7 +265,7 @@ allOf:
|
|||
clocks:
|
||||
minItems: 5
|
||||
maxItems: 6
|
||||
clocks-names:
|
||||
clock-names:
|
||||
minItems: 5
|
||||
maxItems: 6
|
||||
|
||||
|
|
@ -277,7 +278,6 @@ allOf:
|
|||
- qcom,sc8180x-dp
|
||||
- qcom,sdm845-dp
|
||||
- qcom,sm8350-dp
|
||||
- qcom,sm8650-dp
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
|
|
@ -286,6 +286,24 @@ allOf:
|
|||
clocks:
|
||||
minItems: 6
|
||||
maxItems: 6
|
||||
clock-names:
|
||||
minItems: 6
|
||||
maxItems: 6
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sm8650-dp
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 5
|
||||
maxItems: 9
|
||||
clocks:
|
||||
minItems: 6
|
||||
maxItems: 6
|
||||
clocks-names:
|
||||
minItems: 6
|
||||
maxItems: 6
|
||||
|
|
@ -306,7 +324,7 @@ allOf:
|
|||
clocks:
|
||||
minItems: 6
|
||||
maxItems: 8
|
||||
clocks-names:
|
||||
clock-names:
|
||||
minItems: 6
|
||||
maxItems: 8
|
||||
|
||||
|
|
@ -326,7 +344,7 @@ allOf:
|
|||
clocks:
|
||||
minItems: 5
|
||||
maxItems: 6
|
||||
clocks-names:
|
||||
clock-names:
|
||||
minItems: 5
|
||||
maxItems: 6
|
||||
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ examples:
|
|||
mdss_mdp: display-controller@ae01000 {
|
||||
compatible = "qcom,eliza-dpu";
|
||||
reg = <0x0ae01000 0x93000>,
|
||||
<0x0aeb0000 0x2008>;
|
||||
<0x0aeb0000 0x3000>;
|
||||
reg-names = "mdp",
|
||||
"vbif";
|
||||
|
||||
|
|
@ -304,7 +304,7 @@ examples:
|
|||
mdss_dsi0_phy: phy@ae95000 {
|
||||
compatible = "qcom,eliza-dsi-phy-4nm", "qcom,sm8650-dsi-phy-4nm";
|
||||
reg = <0x0ae95000 0x200>,
|
||||
<0x0ae95200 0x280>,
|
||||
<0x0ae95200 0x300>,
|
||||
<0x0ae95500 0x400>;
|
||||
reg-names = "dsi_phy",
|
||||
"dsi_phy_lane",
|
||||
|
|
@ -388,7 +388,7 @@ examples:
|
|||
mdss_dsi1_phy: phy@ae97000 {
|
||||
compatible = "qcom,eliza-dsi-phy-4nm", "qcom,sm8650-dsi-phy-4nm";
|
||||
reg = <0x0ae97000 0x200>,
|
||||
<0x0ae97200 0x280>,
|
||||
<0x0ae97200 0x300>,
|
||||
<0x0ae97500 0x400>;
|
||||
reg-names = "dsi_phy",
|
||||
"dsi_phy_lane",
|
||||
|
|
@ -407,11 +407,15 @@ examples:
|
|||
|
||||
displayport-controller@af54000 {
|
||||
compatible = "qcom,eliza-dp", "qcom,sm8650-dp";
|
||||
reg = <0xaf54000 0x104>,
|
||||
<0xaf54200 0xc0>,
|
||||
<0xaf55000 0x770>,
|
||||
<0xaf56000 0x9c>,
|
||||
<0xaf57000 0x9c>;
|
||||
reg = <0x0af54000 0x200>,
|
||||
<0x0af54200 0x200>,
|
||||
<0x0af55000 0xc00>,
|
||||
<0x0af56000 0x400>,
|
||||
<0x0af57000 0x400>,
|
||||
<0x0af58000 0x400>,
|
||||
<0x0af59000 0x400>,
|
||||
<0x0af5a000 0x600>,
|
||||
<0x0af5b000 0x600>;
|
||||
|
||||
interrupts-extended = <&mdss 12>;
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ examples:
|
|||
display-controller@ae01000 {
|
||||
compatible = "qcom,sm8650-dpu";
|
||||
reg = <0x0ae01000 0x8f000>,
|
||||
<0x0aeb0000 0x2008>;
|
||||
<0x0aeb0000 0x3000>;
|
||||
reg-names = "mdp", "vbif";
|
||||
|
||||
clocks = <&gcc_axi_clk>,
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ examples:
|
|||
display-controller@ae01000 {
|
||||
compatible = "qcom,sm8650-dpu";
|
||||
reg = <0x0ae01000 0x8f000>,
|
||||
<0x0aeb0000 0x2008>;
|
||||
<0x0aeb0000 0x3000>;
|
||||
reg-names = "mdp", "vbif";
|
||||
|
||||
clocks = <&gcc_axi_clk>,
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ examples:
|
|||
display-controller@ae01000 {
|
||||
compatible = "qcom,sm8750-dpu";
|
||||
reg = <0x0ae01000 0x93000>,
|
||||
<0x0aeb0000 0x2008>;
|
||||
<0x0aeb0000 0x3000>;
|
||||
reg-names = "mdp",
|
||||
"vbif";
|
||||
|
||||
|
|
@ -389,11 +389,15 @@ examples:
|
|||
|
||||
displayport-controller@af54000 {
|
||||
compatible = "qcom,sm8750-dp", "qcom,sm8650-dp";
|
||||
reg = <0xaf54000 0x104>,
|
||||
<0xaf54200 0xc0>,
|
||||
<0xaf55000 0x770>,
|
||||
<0xaf56000 0x9c>,
|
||||
<0xaf57000 0x9c>;
|
||||
reg = <0x0af54000 0x200>,
|
||||
<0x0af54200 0x200>,
|
||||
<0x0af55000 0xc00>,
|
||||
<0x0af56000 0x400>,
|
||||
<0x0af57000 0x400>,
|
||||
<0x0af58000 0x400>,
|
||||
<0x0af59000 0x400>,
|
||||
<0x0af5a000 0x600>,
|
||||
<0x0af5b000 0x600>;
|
||||
|
||||
interrupts-extended = <&mdss 12>;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ properties:
|
|||
description: Phandles of rt5650 and rt5514 codecs
|
||||
items:
|
||||
- description: phandle of rt5650 codec
|
||||
maxItems: 1
|
||||
- description: phandle of rt5514 codec
|
||||
maxItems: 1
|
||||
|
||||
mediatek,platform:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ properties:
|
|||
- fsl,ls1021a-qspi
|
||||
- fsl,ls2080a-qspi
|
||||
- spacemit,k1-qspi
|
||||
- items:
|
||||
- const: spacemit,k3-qspi
|
||||
- const: spacemit,k1-qspi
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,ls1043a-qspi
|
||||
|
|
|
|||
|
|
@ -12,6 +12,12 @@ protocol: genetlink
|
|||
doc: Netlink protocol to request a transport layer security handshake.
|
||||
|
||||
definitions:
|
||||
-
|
||||
type: const
|
||||
name: max-errno
|
||||
value: 4095
|
||||
header: linux/err.h
|
||||
scope: kernel
|
||||
-
|
||||
type: enum
|
||||
name: handler-class
|
||||
|
|
@ -80,6 +86,8 @@ attribute-sets:
|
|||
-
|
||||
name: status
|
||||
type: u32
|
||||
checks:
|
||||
max: max-errno
|
||||
-
|
||||
name: sockfd
|
||||
type: s32
|
||||
|
|
|
|||
32
MAINTAINERS
32
MAINTAINERS
|
|
@ -10843,7 +10843,7 @@ F: include/linux/generic-radix-tree.h
|
|||
F: lib/generic-radix-tree.c
|
||||
|
||||
GENERIC RESISTIVE TOUCHSCREEN ADC DRIVER
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
L: linux-input@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/input/touchscreen/resistive-adc-touch.c
|
||||
|
|
@ -12799,7 +12799,6 @@ M: Cezary Rojewski <cezary.rojewski@intel.com>
|
|||
M: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
M: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
|
||||
M: Bard Liao <yung-chuan.liao@linux.intel.com>
|
||||
M: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
|
||||
M: Kai Vehmanen <kai.vehmanen@linux.intel.com>
|
||||
R: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
|
||||
L: linux-sound@vger.kernel.org
|
||||
|
|
@ -16515,7 +16514,7 @@ F: drivers/usb/mtu3/
|
|||
|
||||
MEGACHIPS STDPXXXX-GE-B850V3-FW LVDS/DP++ BRIDGES
|
||||
M: Peter Senna Tschudin <peter.senna@gmail.com>
|
||||
M: Ian Ray <ian.ray@ge.com>
|
||||
M: Ian Ray <ian.ray@gehealthcare.com>
|
||||
M: Martyn Welch <martyn.welch@collabora.co.uk>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt
|
||||
|
|
@ -17354,7 +17353,7 @@ F: Documentation/devicetree/bindings/sound/mikroe,mikroe-proto.txt
|
|||
F: sound/soc/atmel
|
||||
|
||||
MICROCHIP CSI2DC DRIVER
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/media/microchip,csi2dc.yaml
|
||||
|
|
@ -17381,7 +17380,7 @@ F: drivers/i2c/busses/i2c-at91-*.c
|
|||
F: drivers/i2c/busses/i2c-at91.h
|
||||
|
||||
MICROCHIP ISC DRIVER
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/media/atmel,isc.yaml
|
||||
|
|
@ -17393,7 +17392,7 @@ F: drivers/staging/media/deprecated/atmel/atmel-sama*-isc*
|
|||
F: include/linux/atmel-isc-media.h
|
||||
|
||||
MICROCHIP ISI DRIVER
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/media/platform/atmel/atmel-isi.c
|
||||
|
|
@ -17583,7 +17582,7 @@ F: Documentation/devicetree/bindings/display/bridge/microchip,sam9x75-lvds.yaml
|
|||
F: drivers/gpu/drm/bridge/microchip-lvds.c
|
||||
|
||||
MICROCHIP SAMA5D2-COMPATIBLE ADC DRIVER
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml
|
||||
|
|
@ -18955,7 +18954,8 @@ F: drivers/hid/hid-nintendo*
|
|||
|
||||
NIOS2 ARCHITECTURE
|
||||
M: Dinh Nguyen <dinguyen@kernel.org>
|
||||
S: Maintained
|
||||
M: Simon Schuster <schuster.simon@siemens-energy.com>
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git
|
||||
F: arch/nios2/
|
||||
|
||||
|
|
@ -19480,7 +19480,6 @@ F: include/misc/ocxl*
|
|||
F: include/uapi/misc/ocxl.h
|
||||
|
||||
OMAP AUDIO SUPPORT
|
||||
M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
M: Jarkko Nikula <jarkko.nikula@bitmer.com>
|
||||
L: linux-sound@vger.kernel.org
|
||||
L: linux-omap@vger.kernel.org
|
||||
|
|
@ -20763,15 +20762,13 @@ F: Documentation/devicetree/bindings/pci/intel,keembay-pcie*
|
|||
F: drivers/pci/controller/dwc/pcie-keembay.c
|
||||
|
||||
PCIE DRIVER FOR INTEL LGM GW SOC
|
||||
M: Chuanhua Lei <lchuanhua@maxlinear.com>
|
||||
L: linux-pci@vger.kernel.org
|
||||
S: Maintained
|
||||
S: Orphan
|
||||
F: Documentation/devicetree/bindings/pci/intel-gw-pcie.yaml
|
||||
F: drivers/pci/controller/dwc/pcie-intel-gw.c
|
||||
|
||||
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 (moderated for non-subscribers)
|
||||
S: Supported
|
||||
|
|
@ -24146,7 +24143,7 @@ F: drivers/mmc/host/sdhci*
|
|||
|
||||
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER
|
||||
M: Aubin Constans <aubin.constans@microchip.com>
|
||||
R: Eugen Hristev <eugen.hristev@collabora.com>
|
||||
R: Eugen Hristev <ehristev@kernel.org>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/mmc/host/sdhci-of-at91.c
|
||||
|
|
@ -25091,7 +25088,6 @@ SOUND - SOUND OPEN FIRMWARE (SOF) DRIVERS
|
|||
M: Liam Girdwood <lgirdwood@gmail.com>
|
||||
M: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
|
||||
M: Bard Liao <yung-chuan.liao@linux.intel.com>
|
||||
M: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
|
||||
M: Daniel Baluta <daniel.baluta@nxp.com>
|
||||
R: Kai Vehmanen <kai.vehmanen@linux.intel.com>
|
||||
R: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
|
||||
|
|
@ -26384,7 +26380,7 @@ F: arch/xtensa/
|
|||
F: drivers/irqchip/irq-xtensa-*
|
||||
|
||||
TEXAS INSTRUMENTS ASoC DRIVERS
|
||||
M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
M: Sen Wang <sen@ti.com>
|
||||
L: linux-sound@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml
|
||||
|
|
@ -26886,12 +26882,6 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/iio/adc/ti,tsc2046.yaml
|
||||
F: drivers/iio/adc/ti-tsc2046.c
|
||||
|
||||
TI TWL4030 SERIES SOC CODEC DRIVER
|
||||
M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
L: linux-sound@vger.kernel.org
|
||||
S: Maintained
|
||||
F: sound/soc/codecs/twl4030*
|
||||
|
||||
TI VPE/CAL DRIVERS
|
||||
M: Yemike Abhilash Chandra <y-abhilashchandra@ti.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
VERSION = 7
|
||||
PATCHLEVEL = 1
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc4
|
||||
EXTRAVERSION = -rc5
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
|
|||
|
|
@ -409,7 +409,7 @@ __AARCH64_INSN_FUNCS(cbz, 0x7F000000, 0x34000000)
|
|||
__AARCH64_INSN_FUNCS(cbnz, 0x7F000000, 0x35000000)
|
||||
__AARCH64_INSN_FUNCS(tbz, 0x7F000000, 0x36000000)
|
||||
__AARCH64_INSN_FUNCS(tbnz, 0x7F000000, 0x37000000)
|
||||
__AARCH64_INSN_FUNCS(bcond, 0xFF000010, 0x54000000)
|
||||
__AARCH64_INSN_FUNCS(bcond, 0xFF000000, 0x54000000)
|
||||
__AARCH64_INSN_FUNCS(svc, 0xFFE0001F, 0xD4000001)
|
||||
__AARCH64_INSN_FUNCS(hvc, 0xFFE0001F, 0xD4000002)
|
||||
__AARCH64_INSN_FUNCS(smc, 0xFFE0001F, 0xD4000003)
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ static inline int tlb_get_level(struct mmu_gather *tlb)
|
|||
static inline void tlb_flush(struct mmu_gather *tlb)
|
||||
{
|
||||
struct vm_area_struct vma = TLB_FLUSH_VMA(tlb->mm, 0);
|
||||
tlbf_t flags = tlb->freed_tables ? TLBF_NONE : TLBF_NOWALKCACHE;
|
||||
tlbf_t flags = (tlb->freed_tables || tlb->unshared_tables) ?
|
||||
TLBF_NONE : TLBF_NOWALKCACHE;
|
||||
unsigned long stride = tlb_get_unmap_size(tlb);
|
||||
int tlb_level = tlb_get_level(tlb);
|
||||
|
||||
|
|
|
|||
|
|
@ -555,8 +555,10 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
|
|||
kvm_destroy_mpidr_data(vcpu->kvm);
|
||||
|
||||
err = kvm_vgic_vcpu_init(vcpu);
|
||||
if (err)
|
||||
if (err) {
|
||||
kvm_vgic_vcpu_destroy(vcpu);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = kvm_share_hyp(vcpu, vcpu + 1);
|
||||
if (err)
|
||||
|
|
|
|||
|
|
@ -164,13 +164,16 @@ static int hyp_trace_buffer_load(struct hyp_trace_buffer *trace_buffer,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool hyp_trace_desc_validate(struct hyp_trace_desc *desc, size_t desc_size)
|
||||
static bool hyp_trace_desc_is_valid(struct hyp_trace_desc *desc, size_t desc_size)
|
||||
{
|
||||
struct ring_buffer_desc *rb_desc;
|
||||
unsigned int cpu;
|
||||
size_t nr_bpages;
|
||||
void *desc_end;
|
||||
|
||||
if (!is_protected_kvm_enabled())
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Both desc_size and bpages_backing_size are untrusted host-provided
|
||||
* values. We rely on __pkvm_host_donate_hyp() to enforce their validity.
|
||||
|
|
@ -212,8 +215,10 @@ int __tracing_load(unsigned long desc_hva, size_t desc_size)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!hyp_trace_desc_validate(desc, desc_size))
|
||||
if (!hyp_trace_desc_is_valid(desc, desc_size)) {
|
||||
ret = -EINVAL;
|
||||
goto err_release_desc;
|
||||
}
|
||||
|
||||
hyp_spin_lock(&trace_buffer.lock);
|
||||
|
||||
|
|
|
|||
|
|
@ -2307,6 +2307,10 @@ static int vgic_its_restore_dte(struct vgic_its *its, u32 id,
|
|||
/* dte entry is valid */
|
||||
offset = (entry & KVM_ITS_DTE_NEXT_MASK) >> KVM_ITS_DTE_NEXT_SHIFT;
|
||||
|
||||
/* Mimic the MAPD behaviour and reject invalid EID bits. */
|
||||
if (num_eventid_bits > VITS_TYPER_IDBITS)
|
||||
return -EINVAL;
|
||||
|
||||
if (!vgic_its_check_id(its, baser, id, NULL))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ static inline unsigned long efi_get_kimg_min_align(void)
|
|||
return SZ_2M;
|
||||
}
|
||||
|
||||
#define EFI_KIMG_PREFERRED_ADDRESS PHYSADDR(VMLINUX_LOAD_ADDRESS)
|
||||
unsigned long efi_get_kimg_kaslr_address(void);
|
||||
|
||||
#define EFI_KIMG_PREFERRED_ADDRESS efi_get_kimg_kaslr_address()
|
||||
|
||||
#endif /* _ASM_LOONGARCH_EFI_H */
|
||||
|
|
|
|||
|
|
@ -4,6 +4,12 @@
|
|||
|
||||
#ifdef CONFIG_PARAVIRT
|
||||
|
||||
#include <linux/jump_label.h>
|
||||
|
||||
DECLARE_STATIC_KEY_FALSE(virt_preempt_key);
|
||||
DECLARE_STATIC_KEY_FALSE(virt_spin_lock_key);
|
||||
DECLARE_PER_CPU(struct kvm_steal_time, steal_time);
|
||||
|
||||
int __init pv_ipi_init(void);
|
||||
int __init pv_time_init(void);
|
||||
int __init pv_spinlock_init(void);
|
||||
|
|
|
|||
|
|
@ -3,12 +3,9 @@
|
|||
#define _ASM_LOONGARCH_QSPINLOCK_H
|
||||
|
||||
#include <asm/kvm_para.h>
|
||||
#include <linux/jump_label.h>
|
||||
#include <asm/paravirt.h>
|
||||
|
||||
#ifdef CONFIG_PARAVIRT
|
||||
DECLARE_STATIC_KEY_FALSE(virt_preempt_key);
|
||||
DECLARE_STATIC_KEY_FALSE(virt_spin_lock_key);
|
||||
DECLARE_PER_CPU(struct kvm_steal_time, steal_time);
|
||||
|
||||
#define virt_spin_lock virt_spin_lock
|
||||
|
||||
|
|
|
|||
|
|
@ -60,16 +60,18 @@ NOKPROBE_SYMBOL(arch_prepare_kprobe);
|
|||
/* Install breakpoint in text */
|
||||
void arch_arm_kprobe(struct kprobe *p)
|
||||
{
|
||||
*p->addr = KPROBE_BP_INSN;
|
||||
flush_insn_slot(p);
|
||||
u32 insn = KPROBE_BP_INSN;
|
||||
|
||||
larch_insn_text_copy(p->addr, &insn, LOONGARCH_INSN_SIZE);
|
||||
}
|
||||
NOKPROBE_SYMBOL(arch_arm_kprobe);
|
||||
|
||||
/* Remove breakpoint from text */
|
||||
void arch_disarm_kprobe(struct kprobe *p)
|
||||
{
|
||||
*p->addr = p->opcode;
|
||||
flush_insn_slot(p);
|
||||
u32 insn = p->opcode;
|
||||
|
||||
larch_insn_text_copy(p->addr, &insn, LOONGARCH_INSN_SIZE);
|
||||
}
|
||||
NOKPROBE_SYMBOL(arch_disarm_kprobe);
|
||||
|
||||
|
|
@ -184,16 +186,16 @@ static bool reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
|
|||
struct kprobe_ctlblk *kcb)
|
||||
{
|
||||
switch (kcb->kprobe_status) {
|
||||
case KPROBE_HIT_SS:
|
||||
case KPROBE_HIT_SSDONE:
|
||||
case KPROBE_HIT_ACTIVE:
|
||||
kprobes_inc_nmissed_count(p);
|
||||
setup_singlestep(p, regs, kcb, 1);
|
||||
break;
|
||||
case KPROBE_HIT_SS:
|
||||
case KPROBE_REENTER:
|
||||
pr_warn("Failed to recover from reentered kprobes.\n");
|
||||
dump_kprobe(p);
|
||||
WARN_ON_ONCE(1);
|
||||
BUG();
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
|
|
|
|||
|
|
@ -134,11 +134,23 @@ early_param("nokaslr", nokaslr);
|
|||
|
||||
#define KASLR_DISABLED_MESSAGE "KASLR is disabled by %s in %s cmdline.\n"
|
||||
|
||||
/*
|
||||
* Note: strictly-defined KASLR means the kernel's final runtime address
|
||||
* has a random offset from the kernel's load address, which is implemented
|
||||
* in relocate.c; broadly-defined KALSR means the kernel's final runtime
|
||||
* address has a random offset from the kernel's link address (a.k.a.
|
||||
* VMLINUX_LOAD_ADDRESS), which also include the efistlub implementation,
|
||||
* kexec_file implementation and QEMU direct kernel boot. kaslr_disabled()
|
||||
* return true only means strictly-defined KASLR is disabled.
|
||||
*/
|
||||
static inline __init bool kaslr_disabled(void)
|
||||
{
|
||||
char *str;
|
||||
const char *builtin_cmdline = CONFIG_CMDLINE;
|
||||
|
||||
if (kaslr_offset())
|
||||
return true; /* KASLR is performed during early boot. */
|
||||
|
||||
str = strstr(builtin_cmdline, "nokaslr");
|
||||
if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' ')) {
|
||||
pr_info(KASLR_DISABLED_MESSAGE, "\'nokaslr\'", "built-in");
|
||||
|
|
@ -210,14 +222,52 @@ static inline void __init *determine_relocation_address(void)
|
|||
return RELOCATED_KASLR(destination);
|
||||
}
|
||||
|
||||
static unsigned long __init determine_initrd_address(unsigned long *size)
|
||||
{
|
||||
unsigned long start = 0;
|
||||
unsigned long key_length;
|
||||
char *p, *endp, *key = "initrd=";
|
||||
|
||||
key_length = strlen(key);
|
||||
p = strstr(boot_command_line, key);
|
||||
|
||||
if (!p) {
|
||||
key = "initrdmem=";
|
||||
key_length = strlen(key);
|
||||
p = strstr(boot_command_line, key);
|
||||
}
|
||||
|
||||
if (p == boot_command_line || (p > boot_command_line && *(p - 1) == ' ')) {
|
||||
p += key_length;
|
||||
start = memparse(p, &endp);
|
||||
if (*endp == ',')
|
||||
*size = memparse(endp + 1, NULL);
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
static inline int __init relocation_addr_valid(void *location_new)
|
||||
{
|
||||
unsigned long kernel_start, kernel_size;
|
||||
unsigned long initrd_start, initrd_size = 0;
|
||||
|
||||
if ((unsigned long)location_new & 0x00000ffff)
|
||||
return 0; /* Inappropriately aligned new location */
|
||||
|
||||
if ((unsigned long)location_new < (unsigned long)_end)
|
||||
return 0; /* New location overlaps original kernel */
|
||||
|
||||
initrd_start = determine_initrd_address(&initrd_size);
|
||||
if (initrd_start && initrd_size) {
|
||||
kernel_start = PHYSADDR(location_new);
|
||||
kernel_size = (unsigned long)_end - (unsigned long)_text;
|
||||
|
||||
if (kernel_start < (initrd_start + initrd_size) &&
|
||||
initrd_start < (kernel_start + kernel_size))
|
||||
return 0; /* initrd/initramfs overlaps kernel */
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -123,11 +123,7 @@ void arch_remove_memory(u64 start, u64 size, struct vmem_altmap *altmap)
|
|||
{
|
||||
unsigned long start_pfn = start >> PAGE_SHIFT;
|
||||
unsigned long nr_pages = size >> PAGE_SHIFT;
|
||||
struct page *page = pfn_to_page(start_pfn);
|
||||
|
||||
/* With altmap the first mapped page is offset from @start */
|
||||
if (altmap)
|
||||
page += vmem_altmap_offset(altmap);
|
||||
__remove_pages(start_pfn, nr_pages, altmap);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -12,4 +12,6 @@
|
|||
#define __ALIGN .align 4
|
||||
#define __ALIGN_STR ".align 4"
|
||||
|
||||
#define _THIS_IP_ ({ unsigned long __ip; asm volatile("nextpc %0" : "=r" (__ip)); __ip; })
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -415,7 +415,6 @@ int kvm_riscv_vcpu_mmio_load(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
|||
shift = 8 * (sizeof(ulong) - len);
|
||||
} else if ((insn & INSN_MASK_LBU) == INSN_MATCH_LBU) {
|
||||
len = 1;
|
||||
shift = 8 * (sizeof(ulong) - len);
|
||||
#ifdef CONFIG_64BIT
|
||||
} else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
|
||||
len = 8;
|
||||
|
|
@ -649,22 +648,22 @@ int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
case 1:
|
||||
data8 = *((u8 *)run->mmio.data);
|
||||
SET_RD(insn, &vcpu->arch.guest_context,
|
||||
(ulong)data8 << shift >> shift);
|
||||
(long)((ulong)data8 << shift) >> shift);
|
||||
break;
|
||||
case 2:
|
||||
data16 = *((u16 *)run->mmio.data);
|
||||
SET_RD(insn, &vcpu->arch.guest_context,
|
||||
(ulong)data16 << shift >> shift);
|
||||
(long)((ulong)data16 << shift) >> shift);
|
||||
break;
|
||||
case 4:
|
||||
data32 = *((u32 *)run->mmio.data);
|
||||
SET_RD(insn, &vcpu->arch.guest_context,
|
||||
(ulong)data32 << shift >> shift);
|
||||
(long)((ulong)data32 << shift) >> shift);
|
||||
break;
|
||||
case 8:
|
||||
data64 = *((u64 *)run->mmio.data);
|
||||
SET_RD(insn, &vcpu->arch.guest_context,
|
||||
(ulong)data64 << shift >> shift);
|
||||
(long)((ulong)data64 << shift) >> shift);
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
|
|
|||
|
|
@ -453,8 +453,10 @@ int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long s
|
|||
}
|
||||
|
||||
kvpmu->sdata = kzalloc(snapshot_area_size, GFP_ATOMIC);
|
||||
if (!kvpmu->sdata)
|
||||
return -ENOMEM;
|
||||
if (!kvpmu->sdata) {
|
||||
sbiret = SBI_ERR_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* No need to check writable slot explicitly as kvm_vcpu_write_guest does it internally */
|
||||
if (kvm_vcpu_write_guest(vcpu, saddr, kvpmu->sdata, snapshot_area_size)) {
|
||||
|
|
@ -499,8 +501,10 @@ int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low
|
|||
}
|
||||
|
||||
einfo = kzalloc(shmem_size, GFP_KERNEL);
|
||||
if (!einfo)
|
||||
return -ENOMEM;
|
||||
if (!einfo) {
|
||||
ret = SBI_ERR_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = kvm_vcpu_read_guest(vcpu, shmem, einfo, shmem_size);
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ void kvm_riscv_vcpu_record_steal_time(struct kvm_vcpu *vcpu)
|
|||
gfn = shmem >> PAGE_SHIFT;
|
||||
hva = kvm_vcpu_gfn_to_hva(vcpu, gfn);
|
||||
|
||||
if (WARN_ON(kvm_is_error_hva(hva))) {
|
||||
if (kvm_is_error_hva(hva)) {
|
||||
vcpu->arch.sta.shmem = INVALID_GPA;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ static int kvm_sbi_ext_v01_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
|||
|
||||
for_each_set_bit(i, &hmask, BITS_PER_LONG) {
|
||||
rvcpu = kvm_get_vcpu_by_id(vcpu->kvm, i);
|
||||
if (!rvcpu)
|
||||
continue;
|
||||
ret = kvm_riscv_vcpu_set_interrupt(rvcpu, IRQ_VS_SOFT);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -186,6 +186,13 @@ static u64 pai_getctr(unsigned long *page, int nr, unsigned long offset)
|
|||
return page[nr];
|
||||
}
|
||||
|
||||
static void pai_setctr(unsigned long *page, int nr, unsigned long offset, u64 v)
|
||||
{
|
||||
if (offset)
|
||||
nr += offset / sizeof(*page);
|
||||
page[nr] = v;
|
||||
}
|
||||
|
||||
/* Read the counter values. Return value from location in CMP. For base
|
||||
* event xxx_ALL sum up all events. Returns counter value.
|
||||
*/
|
||||
|
|
@ -551,6 +558,8 @@ static void paicrypt_del(struct perf_event *event, int flags)
|
|||
/* Create raw data and save it in buffer. Calculate the delta for each
|
||||
* counter between this invocation and the last invocation.
|
||||
* Returns number of bytes copied.
|
||||
* After reading from PAI counter page, save the read value to the old
|
||||
* page to calculate PAI counter deltas.
|
||||
* Saves only entries with positive counter difference of the form
|
||||
* 2 bytes: Number of counter
|
||||
* 8 bytes: Value of counter
|
||||
|
|
@ -562,16 +571,22 @@ static size_t pai_copy(struct pai_userdata *userdata, unsigned long *page,
|
|||
int i, outidx = 0;
|
||||
|
||||
for (i = 1; i <= pp->num_avail; i++) {
|
||||
u64 val = 0, val_old = 0;
|
||||
u64 val = 0, val_old = 0, val_k = 0, val_old_k = 0;
|
||||
|
||||
if (!exclude_kernel) {
|
||||
val += pai_getctr(page, i, pp->kernel_offset);
|
||||
val_old += pai_getctr(page_old, i, pp->kernel_offset);
|
||||
val_k = pai_getctr(page, i, pp->kernel_offset);
|
||||
val_old_k = pai_getctr(page_old, i, pp->kernel_offset);
|
||||
if (val_k != val_old_k)
|
||||
pai_setctr(page_old, i, pp->kernel_offset, val_k);
|
||||
}
|
||||
if (!exclude_user) {
|
||||
val += pai_getctr(page, i, 0);
|
||||
val_old += pai_getctr(page_old, i, 0);
|
||||
val = pai_getctr(page, i, 0);
|
||||
val_old = pai_getctr(page_old, i, 0);
|
||||
if (val != val_old)
|
||||
pai_setctr(page_old, i, 0, val);
|
||||
}
|
||||
val += val_k;
|
||||
val_old += val_old_k;
|
||||
if (val >= val_old)
|
||||
val -= val_old;
|
||||
else
|
||||
|
|
@ -602,8 +617,6 @@ static size_t pai_copy(struct pai_userdata *userdata, unsigned long *page,
|
|||
static int pai_push_sample(size_t rawsize, struct pai_map *cpump,
|
||||
struct perf_event *event)
|
||||
{
|
||||
int idx = PAI_PMU_IDX(event);
|
||||
struct pai_pmu *pp = &pai_pmu[idx];
|
||||
struct perf_sample_data data;
|
||||
struct perf_raw_record raw;
|
||||
struct pt_regs regs;
|
||||
|
|
@ -634,8 +647,6 @@ static int pai_push_sample(size_t rawsize, struct pai_map *cpump,
|
|||
|
||||
overflow = perf_event_overflow(event, &data, ®s);
|
||||
perf_event_update_userpage(event);
|
||||
/* Save crypto counter lowcore page after reading event data. */
|
||||
memcpy((void *)PAI_SAVE_AREA(event), cpump->area, pp->area_size);
|
||||
return overflow;
|
||||
}
|
||||
|
||||
|
|
@ -651,7 +662,7 @@ static void pai_have_sample(struct perf_event *event, struct pai_map *cpump)
|
|||
rawsize = pai_copy(cpump->save, cpump->area, pp,
|
||||
(unsigned long *)PAI_SAVE_AREA(event),
|
||||
event->attr.exclude_user,
|
||||
event->attr.exclude_kernel);
|
||||
!pp->kernel_offset ? true : event->attr.exclude_kernel);
|
||||
if (rawsize) /* No incremented counters */
|
||||
pai_push_sample(rawsize, cpump, event);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,17 +192,21 @@ static void tl_to_masks(struct sysinfo_15_1_x *info)
|
|||
end = (union topology_entry *)((unsigned long)info + info->length);
|
||||
while (tle < end) {
|
||||
switch (tle->nl) {
|
||||
/*
|
||||
* Adjust drawer_id, book_id, and socked_id so they match the
|
||||
* numbering scheme of e.g. the hardware management console.
|
||||
*/
|
||||
case 3:
|
||||
drawer = drawer->next;
|
||||
drawer->id = tle->container.id;
|
||||
drawer->id = tle->container.id - 1;
|
||||
break;
|
||||
case 2:
|
||||
book = book->next;
|
||||
book->id = tle->container.id;
|
||||
book->id = tle->container.id - 1;
|
||||
break;
|
||||
case 1:
|
||||
socket = socket->next;
|
||||
socket->id = tle->container.id;
|
||||
socket->id = tle->container.id - 1;
|
||||
break;
|
||||
case 0:
|
||||
add_cpus_to_mask(&tle->cpu, drawer, book, socket);
|
||||
|
|
|
|||
|
|
@ -267,6 +267,7 @@ static int dat_split_ste(struct kvm_s390_mmu_cache *mc, union pmd *pmdp, gfn_t g
|
|||
/* No need to take locks as the page table is not installed yet. */
|
||||
pgste_init.prefix_notif = old.s.fc1.prefix_notif;
|
||||
pgste_init.vsie_notif = old.s.fc1.vsie_notif;
|
||||
pgste_init.vsie_gmem = old.s.fc1.vsie_notif;
|
||||
pgste_init.pcl = uses_skeys && init.h.i;
|
||||
dat_init_pgstes(pt, pgste_init.val);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -145,7 +145,8 @@ union pgste {
|
|||
unsigned long cmma_d : 1; /* Dirty flag for CMMA bits */
|
||||
unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */
|
||||
unsigned long vsie_notif : 1; /* Referenced in a shadow table */
|
||||
unsigned long : 5;
|
||||
unsigned long vsie_gmem : 1; /* Contains nested guest memory */
|
||||
unsigned long : 4;
|
||||
unsigned long : 8;
|
||||
};
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -1445,6 +1445,7 @@ static int _do_shadow_pte(struct gmap *sg, gpa_t raddr, union pte *ptep_h, union
|
|||
} else {
|
||||
pgste = _gmap_ptep_xchg(sg->parent, ptep_h, newpte, pgste, f->gfn, false);
|
||||
pgste.vsie_notif = 1;
|
||||
pgste.vsie_gmem = 1;
|
||||
}
|
||||
pgste_set_unlock(ptep_h, pgste);
|
||||
if (rc)
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ struct gmap *gmap_new_child(struct gmap *parent, gfn_t limit)
|
|||
|
||||
int gmap_set_limit(struct gmap *gmap, gfn_t limit)
|
||||
{
|
||||
struct kvm_s390_mmu_cache *mc;
|
||||
struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
|
||||
int rc, type;
|
||||
|
||||
type = gmap_limit_to_type(limit);
|
||||
|
|
@ -142,7 +142,6 @@ int gmap_set_limit(struct gmap *gmap, gfn_t limit)
|
|||
rc = dat_set_asce_limit(mc, &gmap->asce, type);
|
||||
} while (rc == -ENOMEM);
|
||||
|
||||
kvm_s390_free_mmu_cache(mc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -822,8 +821,8 @@ int gmap_ucas_translate(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, gpa_t
|
|||
|
||||
int gmap_ucas_map(struct gmap *gmap, gfn_t p_gfn, gfn_t c_gfn, unsigned long count)
|
||||
{
|
||||
struct kvm_s390_mmu_cache *mc;
|
||||
int rc;
|
||||
struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
|
||||
int rc = 0;
|
||||
|
||||
mc = kvm_s390_new_mmu_cache();
|
||||
if (!mc)
|
||||
|
|
@ -1026,13 +1025,15 @@ int gmap_insert_rmap(struct gmap *sg, gfn_t p_gfn, gfn_t r_gfn, int level)
|
|||
int gmap_protect_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gfn, gfn_t r_gfn,
|
||||
kvm_pfn_t pfn, int level, bool wr)
|
||||
{
|
||||
unsigned long bitmask;
|
||||
union crste *crstep;
|
||||
union pgste pgste;
|
||||
union pte *ptep;
|
||||
union pte pte;
|
||||
int flags, rc;
|
||||
|
||||
KVM_BUG_ON(!is_shadow(sg), sg->kvm);
|
||||
if (KVM_BUG_ON(!is_shadow(sg) || level <= TABLE_TYPE_PAGE_TABLE, sg->kvm))
|
||||
return -EINVAL;
|
||||
lockdep_assert_held(&sg->parent->children_lock);
|
||||
|
||||
flags = DAT_WALK_SPLIT_ALLOC | (uses_skeys(sg->parent) ? DAT_WALK_USES_SKEYS : 0);
|
||||
|
|
@ -1041,8 +1042,9 @@ int gmap_protect_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gf
|
|||
if (rc)
|
||||
return rc;
|
||||
if (level <= TABLE_TYPE_REGION1) {
|
||||
bitmask = -1UL << (8 + 11 * level);
|
||||
scoped_guard(spinlock, &sg->host_to_rmap_lock)
|
||||
rc = gmap_insert_rmap(sg, p_gfn, r_gfn, level);
|
||||
rc = gmap_insert_rmap(sg, p_gfn, r_gfn & bitmask, level);
|
||||
}
|
||||
if (rc)
|
||||
return rc;
|
||||
|
|
@ -1143,8 +1145,10 @@ void _gmap_handle_vsie_unshadow_event(struct gmap *parent, gfn_t gfn)
|
|||
}
|
||||
scoped_guard(spinlock, &sg->host_to_rmap_lock)
|
||||
head = radix_tree_delete(&sg->host_to_rmap, gfn);
|
||||
gmap_for_each_rmap_safe(rmap, rnext, head)
|
||||
gmap_for_each_rmap_safe(rmap, rnext, head) {
|
||||
gmap_unshadow_level(sg, rmap->r_gfn, rmap->level);
|
||||
kfree(rmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -167,6 +167,36 @@ static inline bool gmap_unmap_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end)
|
|||
return _gmap_unmap_prefix(gmap, gfn, end, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* pte_needs_unshadow() -- Check if the pte operations triggers unshadowing.
|
||||
* @oldpte: the previous value for the guest pte.
|
||||
* @newpte: the new pte being set.
|
||||
* @pgste: the pgste for the pte entry.
|
||||
*
|
||||
* If the pgste.vsie_notif bit is not set, return false: the page is not
|
||||
* involved in vsie and thus should not trigger an unshadow operation.
|
||||
*
|
||||
* If the pgste.vsie_gmem bit is set, this pte represents shadowed guest
|
||||
* memory. The access rights on g3's memory should be synchronized with g1's
|
||||
* and g2's. Therefore unshadowing is triggered if the new and old pte
|
||||
* differ in protection, or if the new pte is invalid.
|
||||
*
|
||||
* If the pgste.vsie_gmem bit is not set, this pte maps the g2 dat tables
|
||||
* for g3. If the entry becomes writable or absent, it becomes impossible to
|
||||
* guarantee that the shadow mapping will match g2's mapping. In that case,
|
||||
* trigger an unshadow event.
|
||||
*
|
||||
* Return: true if an unshadow event should be triggered, otherwise false.
|
||||
*/
|
||||
static inline bool pte_needs_unshadow(union pte oldpte, union pte newpte, union pgste pgste)
|
||||
{
|
||||
if (!pgste.vsie_notif)
|
||||
return false;
|
||||
if (pgste.vsie_gmem)
|
||||
return (oldpte.h.p != newpte.h.p) || newpte.h.i;
|
||||
return !newpte.h.p || !newpte.s.pr;
|
||||
}
|
||||
|
||||
static inline union pgste _gmap_ptep_xchg(struct gmap *gmap, union pte *ptep, union pte newpte,
|
||||
union pgste pgste, gfn_t gfn, bool needs_lock)
|
||||
{
|
||||
|
|
@ -180,8 +210,9 @@ static inline union pgste _gmap_ptep_xchg(struct gmap *gmap, union pte *ptep, un
|
|||
pgste.prefix_notif = 0;
|
||||
gmap_unmap_prefix(gmap, gfn, gfn + 1);
|
||||
}
|
||||
if (pgste.vsie_notif && (ptep->h.p != newpte.h.p || newpte.h.i)) {
|
||||
if (pte_needs_unshadow(*ptep, newpte, pgste)) {
|
||||
pgste.vsie_notif = 0;
|
||||
pgste.vsie_gmem = 0;
|
||||
if (needs_lock)
|
||||
gmap_handle_vsie_unshadow_event(gmap, gfn);
|
||||
else
|
||||
|
|
@ -189,6 +220,7 @@ static inline union pgste _gmap_ptep_xchg(struct gmap *gmap, union pte *ptep, un
|
|||
}
|
||||
if (!ptep->s.d && newpte.s.d && !newpte.s.s)
|
||||
SetPageDirty(pfn_to_page(newpte.h.pfra));
|
||||
pgste.zero = 0;
|
||||
return __dat_ptep_xchg(ptep, pgste, newpte, gfn, gmap->asce, uses_skeys(gmap));
|
||||
}
|
||||
|
||||
|
|
@ -198,6 +230,30 @@ static inline union pgste gmap_ptep_xchg(struct gmap *gmap, union pte *ptep, uni
|
|||
return _gmap_ptep_xchg(gmap, ptep, newpte, pgste, gfn, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* crste_needs_unshadow() -- Check if the crste operations triggers unshadowing.
|
||||
* @oldcrste: the previous value for the crste.
|
||||
* @newcrste: the new value for the crste.
|
||||
*
|
||||
* If the old crste did not have the vsie_notif bit set, return false: the
|
||||
* page is not involved in vsie and thus should not trigger an unshadow
|
||||
* operation. Conversely, if the bit is set, it can only be g3 memory, since
|
||||
* dat tables are never mapped using large pages.
|
||||
*
|
||||
* Similar to the pgste.vsie_gmem case of pte_needs_unshadow(), if the
|
||||
* protection bit is changing or the new page is invalid, trigger an
|
||||
* unshadow event. Also trigger an unshadow event if the new crste does not
|
||||
* have the vsie_notif bit set.
|
||||
*
|
||||
* Return: true if an unshadow event should be triggered, otherwise false.
|
||||
*/
|
||||
static inline bool crste_needs_unshadow(union crste oldcrste, union crste newcrste)
|
||||
{
|
||||
if (!oldcrste.s.fc1.vsie_notif)
|
||||
return false;
|
||||
return (newcrste.h.p != oldcrste.h.p) || newcrste.h.i || !newcrste.s.fc1.vsie_notif;
|
||||
}
|
||||
|
||||
static inline bool __must_check _gmap_crstep_xchg_atomic(struct gmap *gmap, union crste *crstep,
|
||||
union crste oldcrste, union crste newcrste,
|
||||
gfn_t gfn, bool needs_lock)
|
||||
|
|
@ -216,8 +272,7 @@ static inline bool __must_check _gmap_crstep_xchg_atomic(struct gmap *gmap, unio
|
|||
newcrste.s.fc1.prefix_notif = 0;
|
||||
gmap_unmap_prefix(gmap, gfn, gfn + align);
|
||||
}
|
||||
if (crste_leaf(oldcrste) && oldcrste.s.fc1.vsie_notif &&
|
||||
(newcrste.h.p || newcrste.h.i || !newcrste.s.fc1.vsie_notif)) {
|
||||
if (crste_leaf(oldcrste) && crste_needs_unshadow(oldcrste, newcrste)) {
|
||||
newcrste.s.fc1.vsie_notif = 0;
|
||||
if (needs_lock)
|
||||
gmap_handle_vsie_unshadow_event(gmap, gfn);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ CFLAGS_REMOVE_syscall_64.o = $(CC_FLAGS_FTRACE)
|
|||
CFLAGS_syscall_32.o += -fno-stack-protector
|
||||
CFLAGS_syscall_64.o += -fno-stack-protector
|
||||
|
||||
obj-y := entry.o entry_$(BITS).o syscall_$(BITS).o
|
||||
obj-y := entry.o entry_$(BITS).o syscall_$(BITS).o common.o
|
||||
|
||||
obj-y += vdso/
|
||||
obj-y += vsyscall/
|
||||
|
|
|
|||
61
arch/x86/entry/common.c
Normal file
61
arch/x86/entry/common.c
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#include <linux/entry-common.h>
|
||||
#include <linux/kvm_types.h>
|
||||
#include <linux/hrtimer_rearm.h>
|
||||
#include <asm/fred.h>
|
||||
#include <asm/desc.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_KVM_INTEL)
|
||||
/*
|
||||
* On VMX, NMIs and IRQs (as configured by KVM) are acknowledged by hardware as
|
||||
* part of the VM-Exit, i.e. the event itself is consumed as part the VM-Exit.
|
||||
* x86_entry_from_kvm() is invoked by KVM to effectively forward NMIs and IRQs
|
||||
* to the kernel for servicing. On SVM, a.k.a. AMD, the NMI/IRQ VM-Exit is
|
||||
* purely a signal that an NMI/IRQ is pending, i.e. the event that triggered
|
||||
* the VM-Exit is held pending until it's unblocked in the host.
|
||||
*/
|
||||
noinstr void x86_entry_from_kvm(unsigned int event_type, unsigned int vector)
|
||||
{
|
||||
if (event_type == EVENT_TYPE_EXTINT) {
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* Use FRED dispatch, even when running IDT. The dispatch
|
||||
* tables are kept in sync between FRED and IDT, and the FRED
|
||||
* dispatch works well with CFI.
|
||||
*/
|
||||
fred_entry_from_kvm(event_type, vector);
|
||||
#else
|
||||
idt_entry_from_kvm(vector);
|
||||
#endif
|
||||
/*
|
||||
* Strictly speaking, only the NMI path requires noinstr.
|
||||
*/
|
||||
instrumentation_begin();
|
||||
/*
|
||||
* KVM/VMX will dispatch from IRQ-disabled but for a context
|
||||
* that will have IRQs-enabled. This confuses the entry code
|
||||
* and it will not have reprogrammed the timer. Do so now.
|
||||
*/
|
||||
hrtimer_rearm_deferred();
|
||||
instrumentation_end();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(event_type != EVENT_TYPE_NMI);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
if (cpu_feature_enabled(X86_FEATURE_FRED))
|
||||
return fred_entry_from_kvm(event_type, vector);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Notably, we must use IDT dispatch for NMI when running in IDT mode.
|
||||
* The FRED NMI context is significantly different and will not work
|
||||
* right (specifically FRED fixed the NMI recursion issue).
|
||||
*/
|
||||
idt_entry_from_kvm(vector);
|
||||
}
|
||||
EXPORT_SYMBOL_FOR_KVM(x86_entry_from_kvm);
|
||||
#endif
|
||||
|
|
@ -75,3 +75,49 @@ THUNK warn_thunk_thunk, __warn_thunk
|
|||
#if defined(CONFIG_STACKPROTECTOR) && defined(CONFIG_SMP)
|
||||
EXPORT_SYMBOL(__ref_stack_chk_guard);
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_KVM_INTEL)
|
||||
.macro IDT_DO_EVENT_IRQOFF call_insn call_target
|
||||
/*
|
||||
* Unconditionally create a stack frame, getting the correct RSP on the
|
||||
* stack (for x86-64) would take two instructions anyways, and RBP can
|
||||
* be used to restore RSP to make objtool happy (see below).
|
||||
*/
|
||||
push %_ASM_BP
|
||||
mov %_ASM_SP, %_ASM_BP
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* Align RSP to a 16-byte boundary (to emulate CPU behavior) before
|
||||
* creating the synthetic interrupt stack frame for the IRQ/NMI.
|
||||
*/
|
||||
and $-16, %rsp
|
||||
push $__KERNEL_DS
|
||||
push %rbp
|
||||
#endif
|
||||
pushf
|
||||
push $__KERNEL_CS
|
||||
\call_insn \call_target
|
||||
|
||||
/*
|
||||
* "Restore" RSP from RBP, even though IRET has already unwound RSP to
|
||||
* the correct value. objtool doesn't know the callee will IRET and,
|
||||
* without the explicit restore, thinks the stack is getting walloped.
|
||||
* Using an unwind hint is problematic due to x86-64's dynamic alignment.
|
||||
*/
|
||||
leave
|
||||
RET
|
||||
.endm
|
||||
|
||||
.pushsection .text, "ax"
|
||||
SYM_FUNC_START(idt_do_interrupt_irqoff)
|
||||
IDT_DO_EVENT_IRQOFF CALL_NOSPEC _ASM_ARG1
|
||||
SYM_FUNC_END(idt_do_interrupt_irqoff)
|
||||
.popsection
|
||||
|
||||
.pushsection .noinstr.text, "ax"
|
||||
SYM_FUNC_START(idt_do_nmi_irqoff)
|
||||
IDT_DO_EVENT_IRQOFF call asm_exc_nmi_kvm_vmx
|
||||
SYM_FUNC_END(idt_do_nmi_irqoff)
|
||||
.popsection
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -147,5 +147,4 @@ SYM_FUNC_START(asm_fred_entry_from_kvm)
|
|||
RET
|
||||
|
||||
SYM_FUNC_END(asm_fred_entry_from_kvm)
|
||||
EXPORT_SYMBOL_FOR_KVM(asm_fred_entry_from_kvm);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ static int map_vdso(const struct vdso_image *image, unsigned long addr)
|
|||
if (IS_ERR(vma)) {
|
||||
ret = PTR_ERR(vma);
|
||||
do_munmap(mm, text_start, image->size, NULL);
|
||||
do_munmap(mm, addr, image->size, NULL);
|
||||
do_munmap(mm, addr, VDSO_NR_PAGES * PAGE_SIZE, NULL);
|
||||
goto up_fail;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -438,6 +438,10 @@ extern void idt_setup_traps(void);
|
|||
extern void idt_setup_apic_and_irq_gates(void);
|
||||
extern bool idt_is_f00f_address(unsigned long address);
|
||||
|
||||
extern void idt_do_interrupt_irqoff(unsigned long address);
|
||||
extern void idt_do_nmi_irqoff(void);
|
||||
extern void idt_entry_from_kvm(unsigned int vector);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
extern void idt_setup_early_pf(void);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ struct gate_struct {
|
|||
typedef struct gate_struct gate_desc;
|
||||
|
||||
#ifndef _SETUP
|
||||
static inline unsigned long gate_offset(const gate_desc *g)
|
||||
static __always_inline unsigned long gate_offset(const gate_desc *g)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
return g->offset_low | ((unsigned long)g->offset_middle << 16) |
|
||||
|
|
|
|||
|
|
@ -97,4 +97,6 @@ static __always_inline void arch_exit_to_user_mode(void)
|
|||
}
|
||||
#define arch_exit_to_user_mode arch_exit_to_user_mode
|
||||
|
||||
extern void x86_entry_from_kvm(unsigned int entry_type, unsigned int vector);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -110,7 +110,6 @@ static __always_inline unsigned long fred_event_data(struct pt_regs *regs) { ret
|
|||
static inline void cpu_init_fred_exceptions(void) { }
|
||||
static inline void cpu_init_fred_rsps(void) { }
|
||||
static inline void fred_complete_exception_setup(void) { }
|
||||
static inline void fred_entry_from_kvm(unsigned int type, unsigned int vector) { }
|
||||
static inline void fred_sync_rsp0(unsigned long rsp0) { }
|
||||
static inline void fred_update_rsp0(void) { }
|
||||
#endif /* CONFIG_X86_FRED */
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ static const struct cpuid_dep cpuid_deps[] = {
|
|||
{ X86_FEATURE_FRED, X86_FEATURE_LKGS },
|
||||
{ X86_FEATURE_SPEC_CTRL_SSBD, X86_FEATURE_SPEC_CTRL },
|
||||
{ X86_FEATURE_LASS, X86_FEATURE_SMAP },
|
||||
{ X86_FEATURE_INVLPGB, X86_FEATURE_PCID },
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -268,6 +268,21 @@ void __init idt_setup_early_pf(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_KVM_INTEL)
|
||||
noinstr void idt_entry_from_kvm(unsigned int vector)
|
||||
{
|
||||
if (vector == NMI_VECTOR)
|
||||
return idt_do_nmi_irqoff();
|
||||
|
||||
/*
|
||||
* Only the NMI path requires noinstr.
|
||||
*/
|
||||
instrumentation_begin();
|
||||
idt_do_interrupt_irqoff(gate_offset(idt_table + vector));
|
||||
instrumentation_end();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __init idt_map_in_cea(void)
|
||||
{
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ DEFINE_IDTENTRY_RAW(exc_nmi_kvm_vmx)
|
|||
{
|
||||
exc_nmi(regs);
|
||||
}
|
||||
EXPORT_SYMBOL_FOR_KVM(asm_exc_nmi_kvm_vmx);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NMI_CHECK_CPU
|
||||
|
|
|
|||
|
|
@ -1300,12 +1300,14 @@ bool __init avic_hardware_setup(void)
|
|||
}
|
||||
|
||||
/*
|
||||
* Disable IPI virtualization for AMD Family 17h CPUs (Zen1 and Zen2)
|
||||
* due to erratum 1235, which results in missed VM-Exits on the sender
|
||||
* and thus missed wake events for blocking vCPUs due to the CPU
|
||||
* failing to see a software update to clear IsRunning.
|
||||
* Disable IPI virtualization for AMD Family 17h (Zen1 and Zen2) and
|
||||
* Hygon Family 18h (derived from AMD Zen1) CPUs due to erratum 1235,
|
||||
* which results in missed VM-Exits on the sender and thus missed wake
|
||||
* events for blocking vCPUs due to the CPU failing to see a software
|
||||
* update to clear IsRunning.
|
||||
*/
|
||||
enable_ipiv = enable_ipiv && boot_cpu_data.x86 != 0x17;
|
||||
if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18)
|
||||
enable_ipiv = false;
|
||||
|
||||
amd_iommu_register_ga_log_notifier(&avic_ga_log_notifier);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,38 +31,6 @@
|
|||
#define VCPU_R15 __VCPU_REGS_R15 * WORD_SIZE
|
||||
#endif
|
||||
|
||||
.macro VMX_DO_EVENT_IRQOFF call_insn call_target
|
||||
/*
|
||||
* Unconditionally create a stack frame, getting the correct RSP on the
|
||||
* stack (for x86-64) would take two instructions anyways, and RBP can
|
||||
* be used to restore RSP to make objtool happy (see below).
|
||||
*/
|
||||
push %_ASM_BP
|
||||
mov %_ASM_SP, %_ASM_BP
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* Align RSP to a 16-byte boundary (to emulate CPU behavior) before
|
||||
* creating the synthetic interrupt stack frame for the IRQ/NMI.
|
||||
*/
|
||||
and $-16, %rsp
|
||||
push $__KERNEL_DS
|
||||
push %rbp
|
||||
#endif
|
||||
pushf
|
||||
push $__KERNEL_CS
|
||||
\call_insn \call_target
|
||||
|
||||
/*
|
||||
* "Restore" RSP from RBP, even though IRET has already unwound RSP to
|
||||
* the correct value. objtool doesn't know the callee will IRET and,
|
||||
* without the explicit restore, thinks the stack is getting walloped.
|
||||
* Using an unwind hint is problematic due to x86-64's dynamic alignment.
|
||||
*/
|
||||
leave
|
||||
RET
|
||||
.endm
|
||||
|
||||
.section .noinstr.text, "ax"
|
||||
|
||||
/**
|
||||
|
|
@ -320,10 +288,6 @@ SYM_INNER_LABEL_ALIGN(vmx_vmexit, SYM_L_GLOBAL)
|
|||
|
||||
SYM_FUNC_END(__vmx_vcpu_run)
|
||||
|
||||
SYM_FUNC_START(vmx_do_nmi_irqoff)
|
||||
VMX_DO_EVENT_IRQOFF call asm_exc_nmi_kvm_vmx
|
||||
SYM_FUNC_END(vmx_do_nmi_irqoff)
|
||||
|
||||
#ifndef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
|
||||
|
||||
/**
|
||||
|
|
@ -375,13 +339,3 @@ SYM_FUNC_START(vmread_error_trampoline)
|
|||
RET
|
||||
SYM_FUNC_END(vmread_error_trampoline)
|
||||
#endif
|
||||
|
||||
.section .text, "ax"
|
||||
|
||||
#ifndef CONFIG_X86_FRED
|
||||
|
||||
SYM_FUNC_START(vmx_do_interrupt_irqoff)
|
||||
VMX_DO_EVENT_IRQOFF CALL_NOSPEC _ASM_ARG1
|
||||
SYM_FUNC_END(vmx_do_interrupt_irqoff)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -7117,9 +7117,6 @@ void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
|
|||
vmcs_write64(EOI_EXIT_BITMAP3, eoi_exit_bitmap[3]);
|
||||
}
|
||||
|
||||
void vmx_do_interrupt_irqoff(unsigned long entry);
|
||||
void vmx_do_nmi_irqoff(void);
|
||||
|
||||
static void handle_nm_fault_irqoff(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
|
|
@ -7161,17 +7158,8 @@ static void handle_external_interrupt_irqoff(struct kvm_vcpu *vcpu,
|
|||
"unexpected VM-Exit interrupt info: 0x%x", intr_info))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Invoke the kernel's IRQ handler for the vector. Use the FRED path
|
||||
* when it's available even if FRED isn't fully enabled, e.g. even if
|
||||
* FRED isn't supported in hardware, in order to avoid the indirect
|
||||
* CALL in the non-FRED path.
|
||||
*/
|
||||
kvm_before_interrupt(vcpu, KVM_HANDLING_IRQ);
|
||||
if (IS_ENABLED(CONFIG_X86_FRED))
|
||||
fred_entry_from_kvm(EVENT_TYPE_EXTINT, vector);
|
||||
else
|
||||
vmx_do_interrupt_irqoff(gate_offset((gate_desc *)host_idt_base + vector));
|
||||
x86_entry_from_kvm(EVENT_TYPE_EXTINT, vector);
|
||||
kvm_after_interrupt(vcpu);
|
||||
|
||||
vcpu->arch.at_instruction_boundary = true;
|
||||
|
|
@ -7481,10 +7469,7 @@ noinstr void vmx_handle_nmi(struct kvm_vcpu *vcpu)
|
|||
return;
|
||||
|
||||
kvm_before_interrupt(vcpu, KVM_HANDLING_NMI);
|
||||
if (cpu_feature_enabled(X86_FEATURE_FRED))
|
||||
fred_entry_from_kvm(EVENT_TYPE_NMI, NMI_VECTOR);
|
||||
else
|
||||
vmx_do_nmi_irqoff();
|
||||
x86_entry_from_kvm(EVENT_TYPE_NMI, NMI_VECTOR);
|
||||
kvm_after_interrupt(vcpu);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4876,7 +4876,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|||
r = tdp_enabled;
|
||||
break;
|
||||
case KVM_CAP_X86_APIC_BUS_CYCLES_NS:
|
||||
r = APIC_BUS_CYCLE_NS_DEFAULT;
|
||||
r = kvm ? kvm->arch.apic_bus_cycle_ns : APIC_BUS_CYCLE_NS_DEFAULT;
|
||||
break;
|
||||
case KVM_CAP_EXIT_HYPERCALL:
|
||||
r = KVM_EXIT_HYPERCALL_VALID_MASK;
|
||||
|
|
|
|||
|
|
@ -55,6 +55,10 @@ int fs_bio_integrity_verify(struct bio *bio, sector_t sector, unsigned int size)
|
|||
{
|
||||
struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
|
||||
struct bio_integrity_payload *bip = bio_integrity(bio);
|
||||
struct bvec_iter data_iter = {
|
||||
.bi_sector = sector,
|
||||
.bi_size = size,
|
||||
};
|
||||
|
||||
/*
|
||||
* Reinitialize bip->bip_iter.
|
||||
|
|
@ -65,7 +69,7 @@ int fs_bio_integrity_verify(struct bio *bio, sector_t sector, unsigned int size)
|
|||
memset(&bip->bip_iter, 0, sizeof(bip->bip_iter));
|
||||
bip->bip_iter.bi_sector = sector;
|
||||
bip->bip_iter.bi_size = bio_integrity_bytes(bi, size >> SECTOR_SHIFT);
|
||||
return blk_status_to_errno(bio_integrity_verify(bio, &bip->bip_iter));
|
||||
return blk_status_to_errno(bio_integrity_verify(bio, &data_iter));
|
||||
}
|
||||
|
||||
static int __init fs_bio_integrity_init(void)
|
||||
|
|
|
|||
|
|
@ -2241,7 +2241,7 @@ void blk_cgroup_bio_start(struct bio *bio)
|
|||
}
|
||||
|
||||
u64_stats_update_end_irqrestore(&bis->sync, flags);
|
||||
css_rstat_updated(&blkcg->css, cpu);
|
||||
__css_rstat_updated(&blkcg->css, cpu);
|
||||
put_cpu();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3077,7 +3077,7 @@ static struct request *blk_mq_get_new_requests(struct request_queue *q,
|
|||
/*
|
||||
* Check if there is a suitable cached request and return it.
|
||||
*/
|
||||
static struct request *blk_mq_peek_cached_request(struct blk_plug *plug,
|
||||
static struct request *blk_mq_get_cached_request(struct blk_plug *plug,
|
||||
struct request_queue *q, blk_opf_t opf)
|
||||
{
|
||||
enum hctx_type type = blk_mq_get_hctx_type(opf);
|
||||
|
|
@ -3093,27 +3093,10 @@ static struct request *blk_mq_peek_cached_request(struct blk_plug *plug,
|
|||
return NULL;
|
||||
if (op_is_flush(rq->cmd_flags) != op_is_flush(opf))
|
||||
return NULL;
|
||||
rq_list_pop(&plug->cached_rqs);
|
||||
return rq;
|
||||
}
|
||||
|
||||
static void blk_mq_use_cached_rq(struct request *rq, struct blk_plug *plug,
|
||||
struct bio *bio)
|
||||
{
|
||||
if (rq_list_pop(&plug->cached_rqs) != rq)
|
||||
WARN_ON_ONCE(1);
|
||||
|
||||
/*
|
||||
* If any qos ->throttle() end up blocking, we will have flushed the
|
||||
* plug and hence killed the cached_rq list as well. Pop this entry
|
||||
* before we throttle.
|
||||
*/
|
||||
rq_qos_throttle(rq->q, bio);
|
||||
|
||||
blk_mq_rq_time_init(rq, blk_time_get_ns());
|
||||
rq->cmd_flags = bio->bi_opf;
|
||||
INIT_LIST_HEAD(&rq->queuelist);
|
||||
}
|
||||
|
||||
static bool bio_unaligned(const struct bio *bio, struct request_queue *q)
|
||||
{
|
||||
unsigned int bs_mask = queue_logical_block_size(q) - 1;
|
||||
|
|
@ -3152,7 +3135,7 @@ void blk_mq_submit_bio(struct bio *bio)
|
|||
/*
|
||||
* If the plug has a cached request for this queue, try to use it.
|
||||
*/
|
||||
rq = blk_mq_peek_cached_request(plug, q, bio->bi_opf);
|
||||
rq = blk_mq_get_cached_request(plug, q, bio->bi_opf);
|
||||
|
||||
/*
|
||||
* A BIO that was released from a zone write plug has already been
|
||||
|
|
@ -3211,7 +3194,10 @@ void blk_mq_submit_bio(struct bio *bio)
|
|||
|
||||
new_request:
|
||||
if (rq) {
|
||||
blk_mq_use_cached_rq(rq, plug, bio);
|
||||
rq_qos_throttle(rq->q, bio);
|
||||
blk_mq_rq_time_init(rq, blk_time_get_ns());
|
||||
rq->cmd_flags = bio->bi_opf;
|
||||
INIT_LIST_HEAD(&rq->queuelist);
|
||||
} else {
|
||||
rq = blk_mq_get_new_requests(q, plug, bio);
|
||||
if (unlikely(!rq)) {
|
||||
|
|
@ -3257,12 +3243,10 @@ void blk_mq_submit_bio(struct bio *bio)
|
|||
return;
|
||||
|
||||
queue_exit:
|
||||
/*
|
||||
* Don't drop the queue reference if we were trying to use a cached
|
||||
* request and thus didn't acquire one.
|
||||
*/
|
||||
if (!rq)
|
||||
blk_queue_exit(q);
|
||||
else
|
||||
blk_mq_free_request(rq);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_MQ_STACKING
|
||||
|
|
|
|||
|
|
@ -2001,8 +2001,10 @@ static void disk_set_zones_cond_array(struct gendisk *disk, u8 *zones_cond)
|
|||
|
||||
void disk_free_zone_resources(struct gendisk *disk)
|
||||
{
|
||||
if (disk->zone_wplugs_worker)
|
||||
if (disk->zone_wplugs_worker) {
|
||||
kthread_stop(disk->zone_wplugs_worker);
|
||||
disk->zone_wplugs_worker = NULL;
|
||||
}
|
||||
WARN_ON_ONCE(!list_empty(&disk->zone_wplugs_list));
|
||||
|
||||
if (disk->zone_wplugs_wq) {
|
||||
|
|
@ -2135,9 +2137,6 @@ static int disk_update_zone_resources(struct gendisk *disk,
|
|||
ret = queue_limits_commit_update(q, &lim);
|
||||
|
||||
unfreeze:
|
||||
if (ret)
|
||||
disk_free_zone_resources(disk);
|
||||
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -490,6 +490,9 @@ static struct dma_buf *amdxdna_gem_prime_export(struct drm_gem_object *gobj, int
|
|||
struct amdxdna_gem_obj *abo = to_xdna_obj(gobj);
|
||||
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
|
||||
|
||||
if (abo->private_buffer)
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
if (abo->dma_buf) {
|
||||
get_dma_buf(abo->dma_buf);
|
||||
return abo->dma_buf;
|
||||
|
|
@ -685,6 +688,7 @@ amdxdna_gem_create_ubuf_object(struct drm_device *dev, struct amdxdna_drm_create
|
|||
{
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(dev);
|
||||
struct amdxdna_drm_va_tbl va_tbl;
|
||||
struct amdxdna_gem_obj *abo;
|
||||
struct drm_gem_object *gobj;
|
||||
struct dma_buf *dma_buf;
|
||||
|
||||
|
|
@ -711,7 +715,10 @@ amdxdna_gem_create_ubuf_object(struct drm_device *dev, struct amdxdna_drm_create
|
|||
|
||||
dma_buf_put(dma_buf);
|
||||
|
||||
return to_xdna_obj(gobj);
|
||||
abo = to_xdna_obj(gobj);
|
||||
abo->private_buffer = true;
|
||||
|
||||
return abo;
|
||||
}
|
||||
|
||||
struct drm_gem_object *
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ struct amdxdna_gem_obj {
|
|||
|
||||
/* True, if BO is managed by XRT, not application */
|
||||
bool internal;
|
||||
/* True, if BO is not exportable */
|
||||
bool private_buffer;
|
||||
};
|
||||
|
||||
#define to_gobj(obj) (&(obj)->base.base)
|
||||
|
|
|
|||
|
|
@ -69,60 +69,10 @@ static void amdxdna_ubuf_release(struct dma_buf *dbuf)
|
|||
kfree(ubuf);
|
||||
}
|
||||
|
||||
static vm_fault_t amdxdna_ubuf_vm_fault(struct vm_fault *vmf)
|
||||
{
|
||||
struct vm_area_struct *vma = vmf->vma;
|
||||
struct amdxdna_ubuf_priv *ubuf;
|
||||
unsigned long pfn;
|
||||
pgoff_t pgoff;
|
||||
|
||||
ubuf = vma->vm_private_data;
|
||||
pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
|
||||
|
||||
pfn = page_to_pfn(ubuf->pages[pgoff]);
|
||||
return vmf_insert_pfn(vma, vmf->address, pfn);
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct amdxdna_ubuf_vm_ops = {
|
||||
.fault = amdxdna_ubuf_vm_fault,
|
||||
};
|
||||
|
||||
static int amdxdna_ubuf_mmap(struct dma_buf *dbuf, struct vm_area_struct *vma)
|
||||
{
|
||||
struct amdxdna_ubuf_priv *ubuf = dbuf->priv;
|
||||
|
||||
vma->vm_ops = &amdxdna_ubuf_vm_ops;
|
||||
vma->vm_private_data = ubuf;
|
||||
vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdxdna_ubuf_vmap(struct dma_buf *dbuf, struct iosys_map *map)
|
||||
{
|
||||
struct amdxdna_ubuf_priv *ubuf = dbuf->priv;
|
||||
void *kva;
|
||||
|
||||
kva = vmap(ubuf->pages, ubuf->nr_pages, VM_MAP, PAGE_KERNEL);
|
||||
if (!kva)
|
||||
return -EINVAL;
|
||||
|
||||
iosys_map_set_vaddr(map, kva);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amdxdna_ubuf_vunmap(struct dma_buf *dbuf, struct iosys_map *map)
|
||||
{
|
||||
vunmap(map->vaddr);
|
||||
}
|
||||
|
||||
static const struct dma_buf_ops amdxdna_ubuf_dmabuf_ops = {
|
||||
.map_dma_buf = amdxdna_ubuf_map,
|
||||
.unmap_dma_buf = amdxdna_ubuf_unmap,
|
||||
.release = amdxdna_ubuf_release,
|
||||
.mmap = amdxdna_ubuf_mmap,
|
||||
.vmap = amdxdna_ubuf_vmap,
|
||||
.vunmap = amdxdna_ubuf_vunmap,
|
||||
};
|
||||
|
||||
struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ struct acpi_battery {
|
|||
struct power_supply *bat;
|
||||
struct power_supply_desc bat_desc;
|
||||
struct acpi_device *device;
|
||||
struct device *phys_dev;
|
||||
struct notifier_block pm_nb;
|
||||
struct list_head list;
|
||||
unsigned long update_time;
|
||||
|
|
@ -1033,7 +1034,7 @@ static int acpi_battery_update(struct acpi_battery *battery, bool resume)
|
|||
if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) ||
|
||||
(test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
|
||||
(battery->capacity_now <= battery->alarm)))
|
||||
acpi_pm_wakeup_event(&battery->device->dev);
|
||||
acpi_pm_wakeup_event(battery->phys_dev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1231,6 +1232,7 @@ static int acpi_battery_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, battery);
|
||||
|
||||
battery->phys_dev = &pdev->dev;
|
||||
battery->device = device;
|
||||
|
||||
result = devm_mutex_init(&pdev->dev, &battery->update_lock);
|
||||
|
|
|
|||
|
|
@ -606,6 +606,12 @@ static void platform_device_release(struct device *dev)
|
|||
kfree(pa);
|
||||
}
|
||||
|
||||
static void platform_device_release_full(struct device *dev)
|
||||
{
|
||||
device_remove_software_node(dev);
|
||||
platform_device_release(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* platform_device_alloc - create a platform device
|
||||
* @name: base name of the device we're adding
|
||||
|
|
@ -848,7 +854,13 @@ struct platform_device *platform_device_register_full(const struct platform_devi
|
|||
int ret;
|
||||
struct platform_device *pdev;
|
||||
|
||||
if (pdevinfo->swnode && pdevinfo->properties)
|
||||
/*
|
||||
* Only one software node per device is allowed. Make sure we don't
|
||||
* accept or create two.
|
||||
*/
|
||||
if ((pdevinfo->swnode && pdevinfo->properties) ||
|
||||
(pdevinfo->swnode && is_software_node(pdevinfo->fwnode)) ||
|
||||
(pdevinfo->properties && is_software_node(pdevinfo->fwnode)))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id);
|
||||
|
|
@ -878,6 +890,8 @@ struct platform_device *platform_device_register_full(const struct platform_devi
|
|||
ret = device_add_software_node(&pdev->dev, pdevinfo->swnode);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
pdev->dev.release = platform_device_release_full;
|
||||
} else if (pdevinfo->properties) {
|
||||
ret = device_create_managed_software_node(&pdev->dev,
|
||||
pdevinfo->properties, NULL);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <linux/cpuhotplug.h>
|
||||
#include <linux/part_stat.h>
|
||||
#include <linux/kernel_read_file.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
#include "zram_drv.h"
|
||||
|
||||
|
|
@ -504,6 +505,7 @@ struct zram_wb_ctl {
|
|||
wait_queue_head_t done_wait;
|
||||
spinlock_t done_lock;
|
||||
atomic_t num_inflight;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
struct zram_wb_req {
|
||||
|
|
@ -847,7 +849,7 @@ static void release_wb_ctl(struct zram_wb_ctl *wb_ctl)
|
|||
release_wb_req(req);
|
||||
}
|
||||
|
||||
kfree(wb_ctl);
|
||||
kfree_rcu(wb_ctl, rcu);
|
||||
}
|
||||
|
||||
static struct zram_wb_ctl *init_wb_ctl(struct zram *zram)
|
||||
|
|
@ -964,11 +966,13 @@ static void zram_writeback_endio(struct bio *bio)
|
|||
struct zram_wb_ctl *wb_ctl = bio->bi_private;
|
||||
unsigned long flags;
|
||||
|
||||
rcu_read_lock();
|
||||
spin_lock_irqsave(&wb_ctl->done_lock, flags);
|
||||
list_add(&req->entry, &wb_ctl->done_reqs);
|
||||
spin_unlock_irqrestore(&wb_ctl->done_lock, flags);
|
||||
|
||||
wake_up(&wb_ctl->done_wait);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void zram_submit_wb_request(struct zram *zram,
|
||||
|
|
|
|||
|
|
@ -70,18 +70,6 @@ config X86_AMD_PSTATE_DEFAULT_MODE
|
|||
For details, take a look at:
|
||||
<file:Documentation/admin-guide/pm/amd-pstate.rst>.
|
||||
|
||||
config X86_AMD_PSTATE_DYNAMIC_EPP
|
||||
bool "AMD Processor P-State dynamic EPP support"
|
||||
depends on X86_AMD_PSTATE
|
||||
default n
|
||||
help
|
||||
Allow the kernel to dynamically change the energy performance
|
||||
value from events like ACPI platform profile and AC adapter plug
|
||||
events.
|
||||
|
||||
This feature can also be changed at runtime, this configuration
|
||||
option only sets the kernel default value behavior.
|
||||
|
||||
config X86_AMD_PSTATE_UT
|
||||
tristate "selftest for AMD Processor P-State driver"
|
||||
depends on X86 && ACPI_PROCESSOR
|
||||
|
|
|
|||
|
|
@ -274,20 +274,21 @@ static int amd_pstate_set_mode(enum amd_pstate_mode mode)
|
|||
|
||||
static int amd_pstate_ut_epp(u32 index)
|
||||
{
|
||||
struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
|
||||
char *buf __free(cleanup_page) = NULL;
|
||||
static const char * const epp_strings[] = {
|
||||
"performance",
|
||||
"balance_performance",
|
||||
"balance_power",
|
||||
"power",
|
||||
"balance_power",
|
||||
"balance_performance",
|
||||
"performance",
|
||||
};
|
||||
struct amd_cpudata *cpudata;
|
||||
char *buf __free(cleanup_page) = NULL;
|
||||
struct cpufreq_policy *policy = NULL;
|
||||
enum amd_pstate_mode orig_mode;
|
||||
struct amd_cpudata *cpudata;
|
||||
unsigned long orig_policy;
|
||||
bool orig_dynamic_epp;
|
||||
int ret, cpu = 0;
|
||||
int i;
|
||||
u16 epp;
|
||||
int i;
|
||||
|
||||
policy = cpufreq_cpu_get(cpu);
|
||||
if (!policy)
|
||||
|
|
@ -297,6 +298,10 @@ static int amd_pstate_ut_epp(u32 index)
|
|||
orig_mode = amd_pstate_get_status();
|
||||
orig_dynamic_epp = cpudata->dynamic_epp;
|
||||
|
||||
/* Drop reference before potential driver change. */
|
||||
cpufreq_cpu_put(policy);
|
||||
policy = NULL;
|
||||
|
||||
/* disable dynamic EPP before running test */
|
||||
if (cpudata->dynamic_epp) {
|
||||
pr_debug("Dynamic EPP is enabled, disabling it\n");
|
||||
|
|
@ -311,6 +316,17 @@ static int amd_pstate_ut_epp(u32 index)
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
policy = cpufreq_cpu_get(cpu);
|
||||
if (!policy) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
down_write(&policy->rwsem);
|
||||
cpudata = policy->driver_data;
|
||||
orig_policy = cpudata->policy;
|
||||
cpudata->policy = CPUFREQ_POLICY_POWERSAVE;
|
||||
|
||||
for (epp = 0; epp <= U8_MAX; epp++) {
|
||||
u8 val;
|
||||
|
||||
|
|
@ -358,6 +374,12 @@ static int amd_pstate_ut_epp(u32 index)
|
|||
ret = 0;
|
||||
|
||||
out:
|
||||
if (policy) {
|
||||
cpudata->policy = orig_policy;
|
||||
up_write(&policy->rwsem);
|
||||
cpufreq_cpu_put(policy);
|
||||
}
|
||||
|
||||
if (orig_dynamic_epp) {
|
||||
int ret2;
|
||||
|
||||
|
|
|
|||
|
|
@ -87,11 +87,7 @@ static struct cpufreq_driver amd_pstate_driver;
|
|||
static struct cpufreq_driver amd_pstate_epp_driver;
|
||||
static int cppc_state = AMD_PSTATE_UNDEFINED;
|
||||
static bool amd_pstate_prefcore = true;
|
||||
#ifdef CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP
|
||||
static bool dynamic_epp = CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP;
|
||||
#else
|
||||
static bool dynamic_epp;
|
||||
#endif
|
||||
static struct quirk_entry *quirks;
|
||||
|
||||
/*
|
||||
|
|
@ -1291,6 +1287,8 @@ static int amd_pstate_set_dynamic_epp(struct cpufreq_policy *policy)
|
|||
return ret;
|
||||
|
||||
cpudata->profile_name = kasprintf(GFP_KERNEL, "amd-pstate-epp-cpu%d", cpudata->cpu);
|
||||
if (!cpudata->profile_name)
|
||||
return -ENOMEM;
|
||||
|
||||
cpudata->ppdev = platform_profile_register(get_cpu_device(policy->cpu),
|
||||
cpudata->profile_name,
|
||||
|
|
@ -1427,7 +1425,7 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
|
|||
if (ret)
|
||||
epp = epp_values[ret];
|
||||
else
|
||||
epp = amd_pstate_get_balanced_epp(policy);
|
||||
epp = cpudata->epp_default_dc;
|
||||
}
|
||||
|
||||
if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) {
|
||||
|
|
@ -1707,6 +1705,8 @@ static int amd_pstate_change_driver_mode(int mode)
|
|||
{
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&amd_pstate_driver_lock);
|
||||
|
||||
ret = amd_pstate_unregister_driver(0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -1821,8 +1821,16 @@ static ssize_t dynamic_epp_store(struct device *a, struct device_attribute *b,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (dynamic_epp == enabled)
|
||||
guard(mutex)(&amd_pstate_driver_lock);
|
||||
|
||||
if (cppc_state != AMD_PSTATE_ACTIVE) {
|
||||
pr_debug("dynamic_epp can only be toggled in active mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Nothing to do */
|
||||
if (dynamic_epp == enabled)
|
||||
return count;
|
||||
|
||||
/* reinitialize with desired dynamic EPP value */
|
||||
dynamic_epp = enabled;
|
||||
|
|
@ -1942,7 +1950,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
|
|||
if (dynamic_epp)
|
||||
ret = amd_pstate_set_dynamic_epp(policy);
|
||||
else
|
||||
ret = amd_pstate_set_epp(policy, amd_pstate_get_balanced_epp(policy));
|
||||
ret = amd_pstate_set_epp(policy, cpudata->epp_default_dc);
|
||||
if (ret)
|
||||
goto free_cpudata1;
|
||||
|
||||
|
|
@ -1970,12 +1978,13 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
|
|||
if (cpudata) {
|
||||
union perf_cached perf = READ_ONCE(cpudata->perf);
|
||||
|
||||
if (cpudata->dynamic_epp)
|
||||
amd_pstate_clear_dynamic_epp(policy);
|
||||
|
||||
/* Reset CPPC_REQ MSR to the BIOS value */
|
||||
amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);
|
||||
amd_pstate_set_floor_perf(policy, cpudata->bios_floor_perf);
|
||||
|
||||
if (cpudata->dynamic_epp)
|
||||
amd_pstate_clear_dynamic_epp(policy);
|
||||
kfree(cpudata);
|
||||
policy->driver_data = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2279,7 +2279,7 @@ static int hwp_get_cpu_scaling(int cpu)
|
|||
* Return the hybrid scaling factor for P-cores and use the
|
||||
* default core scaling for E-cores.
|
||||
*/
|
||||
if (hybrid_get_cpu_type(cpu) == INTEL_CPU_TYPE_CORE)
|
||||
if (hybrid_get_cpu_type(cpu) != INTEL_CPU_TYPE_ATOM)
|
||||
return hybrid_scaling_factor;
|
||||
|
||||
return core_get_scaling();
|
||||
|
|
@ -3734,6 +3734,7 @@ static const struct x86_cpu_id intel_hybrid_scaling_factor[] = {
|
|||
X86_MATCH_VFM(INTEL_RAPTORLAKE, HYBRID_SCALING_FACTOR_ADL),
|
||||
X86_MATCH_VFM(INTEL_RAPTORLAKE_P, HYBRID_SCALING_FACTOR_ADL),
|
||||
X86_MATCH_VFM(INTEL_RAPTORLAKE_S, HYBRID_SCALING_FACTOR_ADL),
|
||||
X86_MATCH_VFM(INTEL_BARTLETTLAKE, HYBRID_SCALING_FACTOR_ADL),
|
||||
X86_MATCH_VFM(INTEL_METEORLAKE_L, HYBRID_SCALING_FACTOR_MTL),
|
||||
X86_MATCH_VFM(INTEL_LUNARLAKE_M, HYBRID_SCALING_FACTOR_LNL),
|
||||
{}
|
||||
|
|
|
|||
|
|
@ -847,12 +847,21 @@ int dpll_device_delete_ntf(struct dpll_device *dpll)
|
|||
return dpll_device_event_send(DPLL_CMD_DEVICE_DELETE_NTF, dpll);
|
||||
}
|
||||
|
||||
static int
|
||||
__dpll_device_change_ntf(struct dpll_device *dpll)
|
||||
/**
|
||||
* __dpll_device_change_ntf - notify that the dpll device has been changed
|
||||
* @dpll: registered dpll pointer
|
||||
*
|
||||
* Context: caller must hold dpll_lock. Suitable for use inside device
|
||||
* callbacks which are already invoked under dpll_lock.
|
||||
* Return: 0 if succeeds, error code otherwise.
|
||||
*/
|
||||
int __dpll_device_change_ntf(struct dpll_device *dpll)
|
||||
{
|
||||
lockdep_assert_held(&dpll_lock);
|
||||
dpll_device_notify(dpll, DPLL_DEVICE_CHANGED);
|
||||
return dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__dpll_device_change_ntf);
|
||||
|
||||
/**
|
||||
* dpll_device_change_ntf - notify that the dpll device has been changed
|
||||
|
|
|
|||
|
|
@ -724,18 +724,15 @@ zl3073x_dev_periodic_work(struct kthread_work *work)
|
|||
dev_warn(zldev->dev, "Failed to update phase offsets: %pe\n",
|
||||
ERR_PTR(rc));
|
||||
|
||||
/* Update measured input reference frequencies if any DPLL has
|
||||
* frequency monitoring enabled.
|
||||
/* Update measured input reference frequencies if frequency
|
||||
* monitoring is enabled.
|
||||
*/
|
||||
list_for_each_entry(zldpll, &zldev->dplls, list) {
|
||||
if (zldpll->freq_monitor) {
|
||||
rc = zl3073x_ref_freq_meas_update(zldev);
|
||||
if (rc)
|
||||
dev_warn(zldev->dev,
|
||||
"Failed to update measured frequencies: %pe\n",
|
||||
ERR_PTR(rc));
|
||||
break;
|
||||
}
|
||||
if (zldev->freq_monitor) {
|
||||
rc = zl3073x_ref_freq_meas_update(zldev);
|
||||
if (rc)
|
||||
dev_warn(zldev->dev,
|
||||
"Failed to update measured frequencies: %pe\n",
|
||||
ERR_PTR(rc));
|
||||
}
|
||||
|
||||
list_for_each_entry(zldpll, &zldev->dplls, list)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ struct zl3073x_chip_info {
|
|||
* @work: periodic work
|
||||
* @clock_id: clock id of the device
|
||||
* @phase_avg_factor: phase offset measurement averaging factor
|
||||
* @freq_monitor: is frequency monitor enabled
|
||||
*/
|
||||
struct zl3073x_dev {
|
||||
struct device *dev;
|
||||
|
|
@ -77,9 +78,10 @@ struct zl3073x_dev {
|
|||
struct kthread_worker *kworker;
|
||||
struct kthread_delayed_work work;
|
||||
|
||||
/* Devlink parameters */
|
||||
/* Per-chip parameters */
|
||||
u64 clock_id;
|
||||
u8 phase_avg_factor;
|
||||
bool freq_monitor;
|
||||
};
|
||||
|
||||
extern const struct regmap_config zl3073x_regmap_config;
|
||||
|
|
|
|||
|
|
@ -1117,15 +1117,6 @@ zl3073x_dpll_phase_offset_avg_factor_get(const struct dpll_device *dpll,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
zl3073x_dpll_change_work(struct work_struct *work)
|
||||
{
|
||||
struct zl3073x_dpll *zldpll;
|
||||
|
||||
zldpll = container_of(work, struct zl3073x_dpll, change_work);
|
||||
dpll_device_change_ntf(zldpll->dpll_dev);
|
||||
}
|
||||
|
||||
static int
|
||||
zl3073x_dpll_phase_offset_avg_factor_set(const struct dpll_device *dpll,
|
||||
void *dpll_priv, u32 factor,
|
||||
|
|
@ -1151,8 +1142,10 @@ zl3073x_dpll_phase_offset_avg_factor_set(const struct dpll_device *dpll,
|
|||
* we have to send a notification for other DPLL devices.
|
||||
*/
|
||||
list_for_each_entry(item, &zldpll->dev->dplls, list) {
|
||||
if (item != zldpll)
|
||||
schedule_work(&item->change_work);
|
||||
struct dpll_device *dpll_dev = READ_ONCE(item->dpll_dev);
|
||||
|
||||
if (item != zldpll && dpll_dev)
|
||||
__dpll_device_change_ntf(dpll_dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1257,7 +1250,7 @@ zl3073x_dpll_freq_monitor_get(const struct dpll_device *dpll,
|
|||
{
|
||||
struct zl3073x_dpll *zldpll = dpll_priv;
|
||||
|
||||
if (zldpll->freq_monitor)
|
||||
if (zldpll->dev->freq_monitor)
|
||||
*state = DPLL_FEATURE_STATE_ENABLE;
|
||||
else
|
||||
*state = DPLL_FEATURE_STATE_DISABLE;
|
||||
|
|
@ -1271,9 +1264,19 @@ zl3073x_dpll_freq_monitor_set(const struct dpll_device *dpll,
|
|||
enum dpll_feature_state state,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct zl3073x_dpll *zldpll = dpll_priv;
|
||||
struct zl3073x_dpll *item, *zldpll = dpll_priv;
|
||||
|
||||
zldpll->freq_monitor = (state == DPLL_FEATURE_STATE_ENABLE);
|
||||
zldpll->dev->freq_monitor = (state == DPLL_FEATURE_STATE_ENABLE);
|
||||
|
||||
/* The frequency monitoring is common for all DPLL channels so after
|
||||
* change we have to send a notification for other DPLL devices.
|
||||
*/
|
||||
list_for_each_entry(item, &zldpll->dev->dplls, list) {
|
||||
struct dpll_device *dpll_dev = READ_ONCE(item->dpll_dev);
|
||||
|
||||
if (item != zldpll && dpll_dev)
|
||||
__dpll_device_change_ntf(dpll_dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1667,13 +1670,13 @@ zl3073x_dpll_device_register(struct zl3073x_dpll *zldpll)
|
|||
static void
|
||||
zl3073x_dpll_device_unregister(struct zl3073x_dpll *zldpll)
|
||||
{
|
||||
WARN(!zldpll->dpll_dev, "DPLL device is not registered\n");
|
||||
struct dpll_device *dpll_dev = READ_ONCE(zldpll->dpll_dev);
|
||||
|
||||
cancel_work_sync(&zldpll->change_work);
|
||||
WARN(!dpll_dev, "DPLL device is not registered\n");
|
||||
|
||||
dpll_device_unregister(zldpll->dpll_dev, &zldpll->ops, zldpll);
|
||||
dpll_device_put(zldpll->dpll_dev, &zldpll->tracker);
|
||||
zldpll->dpll_dev = NULL;
|
||||
WRITE_ONCE(zldpll->dpll_dev, NULL);
|
||||
dpll_device_unregister(dpll_dev, &zldpll->ops, zldpll);
|
||||
dpll_device_put(dpll_dev, &zldpll->tracker);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1784,7 +1787,7 @@ zl3073x_dpll_pin_measured_freq_check(struct zl3073x_dpll_pin *pin)
|
|||
u8 ref_id;
|
||||
u32 freq;
|
||||
|
||||
if (!zldpll->freq_monitor)
|
||||
if (!zldpll->dev->freq_monitor)
|
||||
return false;
|
||||
|
||||
ref_id = zl3073x_input_pin_ref_get(pin->id);
|
||||
|
|
@ -1817,10 +1820,8 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
|
|||
struct zl3073x_dev *zldev = zldpll->dev;
|
||||
enum dpll_lock_status lock_status;
|
||||
struct device *dev = zldev->dev;
|
||||
const struct zl3073x_chan *chan;
|
||||
struct zl3073x_dpll_pin *pin;
|
||||
int rc;
|
||||
u8 mode;
|
||||
|
||||
zldpll->check_count++;
|
||||
|
||||
|
|
@ -1839,15 +1840,6 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
|
|||
dpll_device_change_ntf(zldpll->dpll_dev);
|
||||
}
|
||||
|
||||
/* Input pin monitoring does make sense only in automatic
|
||||
* or forced reference modes.
|
||||
*/
|
||||
chan = zl3073x_chan_state_get(zldev, zldpll->id);
|
||||
mode = zl3073x_chan_mode_get(chan);
|
||||
if (mode != ZL_DPLL_MODE_REFSEL_MODE_AUTO &&
|
||||
mode != ZL_DPLL_MODE_REFSEL_MODE_REFLOCK)
|
||||
return;
|
||||
|
||||
/* Update phase offset latch registers for this DPLL if the phase
|
||||
* offset monitor feature is enabled.
|
||||
*/
|
||||
|
|
@ -1958,7 +1950,6 @@ zl3073x_dpll_alloc(struct zl3073x_dev *zldev, u8 ch)
|
|||
zldpll->dev = zldev;
|
||||
zldpll->id = ch;
|
||||
INIT_LIST_HEAD(&zldpll->pins);
|
||||
INIT_WORK(&zldpll->change_work, zl3073x_dpll_change_work);
|
||||
|
||||
return zldpll;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,13 +15,11 @@
|
|||
* @id: DPLL index
|
||||
* @check_count: periodic check counter
|
||||
* @phase_monitor: is phase offset monitor enabled
|
||||
* @freq_monitor: is frequency monitor enabled
|
||||
* @ops: DPLL device operations for this instance
|
||||
* @dpll_dev: pointer to registered DPLL device
|
||||
* @tracker: tracking object for the acquired reference
|
||||
* @lock_status: last saved DPLL lock status
|
||||
* @pins: list of pins
|
||||
* @change_work: device change notification work
|
||||
*/
|
||||
struct zl3073x_dpll {
|
||||
struct list_head list;
|
||||
|
|
@ -29,13 +27,11 @@ struct zl3073x_dpll {
|
|||
u8 id;
|
||||
u8 check_count;
|
||||
bool phase_monitor;
|
||||
bool freq_monitor;
|
||||
struct dpll_device_ops ops;
|
||||
struct dpll_device *dpll_dev;
|
||||
dpll_tracker tracker;
|
||||
enum dpll_lock_status lock_status;
|
||||
struct list_head pins;
|
||||
struct work_struct change_work;
|
||||
};
|
||||
|
||||
struct zl3073x_dpll *zl3073x_dpll_alloc(struct zl3073x_dev *zldev, u8 ch);
|
||||
|
|
|
|||
|
|
@ -79,6 +79,10 @@ efi_status_t efi_parse_options(char const *cmdline)
|
|||
efi_noinitrd = true;
|
||||
} else if (IS_ENABLED(CONFIG_X86_64) && !strcmp(param, "no5lvl")) {
|
||||
efi_no5lvl = true;
|
||||
} else if (IS_ENABLED(CONFIG_LOONGARCH) &&
|
||||
IS_ENABLED(CONFIG_HIBERNATION) &&
|
||||
!strcmp(param, "resume") && val) {
|
||||
efi_nokaslr = true; /* LoongArch can't KASLR for hibernation */
|
||||
} else if (IS_ENABLED(CONFIG_ARCH_HAS_MEM_ENCRYPT) &&
|
||||
!strcmp(param, "mem_encrypt") && val) {
|
||||
if (parse_option_str(val, "on"))
|
||||
|
|
|
|||
|
|
@ -23,6 +23,22 @@ void efi_cache_sync_image(unsigned long image_base, unsigned long alloc_size)
|
|||
asm volatile ("ibar 0" ::: "memory");
|
||||
}
|
||||
|
||||
unsigned long efi_get_kimg_kaslr_address(void)
|
||||
{
|
||||
unsigned int random_offset = 0;
|
||||
|
||||
#ifdef CONFIG_RANDOMIZE_BASE
|
||||
if (!efi_nokaslr) {
|
||||
efi_get_random_bytes(sizeof(random_offset), (u8 *)&random_offset);
|
||||
random_offset ^= (random_get_entropy() << 16);
|
||||
random_offset &= (CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1);
|
||||
random_offset = ALIGN(random_offset + SZ_64K, SZ_64K);
|
||||
}
|
||||
#endif
|
||||
|
||||
return PHYSADDR(VMLINUX_LOAD_ADDRESS) + random_offset;
|
||||
}
|
||||
|
||||
struct exit_boot_struct {
|
||||
efi_memory_desc_t *runtime_map;
|
||||
int runtime_entry_count;
|
||||
|
|
|
|||
|
|
@ -362,6 +362,9 @@ static void *pdsfc_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
|
|||
void *out = NULL;
|
||||
int err;
|
||||
|
||||
if (in_len < sizeof(*rpc))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
err = pdsfc_validate_rpc(pdsfc, rpc, scope);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
|
|
|||
|
|
@ -237,7 +237,9 @@ static irqreturn_t adnp_irq(int irq, void *data)
|
|||
unsigned long pending;
|
||||
int err;
|
||||
|
||||
scoped_guard(mutex, &adnp->i2c_lock) {
|
||||
{
|
||||
guard(mutex)(&adnp->i2c_lock);
|
||||
|
||||
err = adnp_read(adnp, GPIO_PLR(adnp) + i, &level);
|
||||
if (err < 0)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -968,9 +968,12 @@ static int gpio_aggregator_activate(struct gpio_aggregator *aggr)
|
|||
}
|
||||
|
||||
wait_for_device_probe();
|
||||
if (!device_is_bound(&pdev->dev)) {
|
||||
ret = -ENXIO;
|
||||
goto err_unregister_pdev;
|
||||
|
||||
scoped_guard(device, &pdev->dev) {
|
||||
if (!device_is_bound(&pdev->dev)) {
|
||||
ret = -ENXIO;
|
||||
goto err_unregister_pdev;
|
||||
}
|
||||
}
|
||||
|
||||
aggr->pdev = pdev;
|
||||
|
|
@ -979,8 +982,8 @@ static int gpio_aggregator_activate(struct gpio_aggregator *aggr)
|
|||
err_unregister_pdev:
|
||||
platform_device_unregister(pdev);
|
||||
err_remove_lookup_table:
|
||||
kfree(aggr->lookups->dev_id);
|
||||
gpiod_remove_lookup_table(aggr->lookups);
|
||||
kfree(aggr->lookups->dev_id);
|
||||
err_remove_swnode:
|
||||
fwnode_remove_software_node(swnode);
|
||||
err_remove_lookups:
|
||||
|
|
@ -991,11 +994,15 @@ static int gpio_aggregator_activate(struct gpio_aggregator *aggr)
|
|||
|
||||
static void gpio_aggregator_deactivate(struct gpio_aggregator *aggr)
|
||||
{
|
||||
struct fwnode_handle *swnode;
|
||||
|
||||
swnode = dev_fwnode(&aggr->pdev->dev);
|
||||
platform_device_unregister(aggr->pdev);
|
||||
aggr->pdev = NULL;
|
||||
gpiod_remove_lookup_table(aggr->lookups);
|
||||
kfree(aggr->lookups->dev_id);
|
||||
kfree(aggr->lookups);
|
||||
fwnode_remove_software_node(swnode);
|
||||
}
|
||||
|
||||
static void gpio_aggregator_lockup_configfs(struct gpio_aggregator *aggr,
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
|||
* the handler is needed only once, but doing it for every port
|
||||
* is more robust and easier.
|
||||
*/
|
||||
port->irq_high = -1;
|
||||
port->irq_high = 0;
|
||||
port->mx_irq_handler = mx2_gpio_irq_handler;
|
||||
} else
|
||||
port->mx_irq_handler = mx3_gpio_irq_handler;
|
||||
|
|
|
|||
|
|
@ -1411,7 +1411,7 @@ static int pca953x_resume(struct device *dev)
|
|||
ret = regulator_enable(chip->regulator);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable regulator: %d\n", ret);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -638,10 +638,17 @@ static int rockchip_gpiolib_register(struct rockchip_pin_bank *bank)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void rockchip_clk_put(void *data)
|
||||
{
|
||||
struct clk *clk = data;
|
||||
|
||||
clk_put(clk);
|
||||
}
|
||||
|
||||
static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
|
||||
{
|
||||
struct resource res;
|
||||
int id = 0;
|
||||
int id = 0, ret;
|
||||
|
||||
if (of_address_to_resource(bank->of_node, 0, &res)) {
|
||||
dev_err(bank->dev, "cannot find IO resource for bank\n");
|
||||
|
|
@ -656,11 +663,10 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
|
|||
if (!bank->irq)
|
||||
return -EINVAL;
|
||||
|
||||
bank->clk = of_clk_get(bank->of_node, 0);
|
||||
bank->clk = devm_clk_get_enabled(bank->dev, NULL);
|
||||
if (IS_ERR(bank->clk))
|
||||
return PTR_ERR(bank->clk);
|
||||
|
||||
clk_prepare_enable(bank->clk);
|
||||
id = readl(bank->reg_base + gpio_regs_v2.version_id);
|
||||
|
||||
switch (id) {
|
||||
|
|
@ -672,9 +678,13 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
|
|||
bank->db_clk = of_clk_get(bank->of_node, 1);
|
||||
if (IS_ERR(bank->db_clk)) {
|
||||
dev_err(bank->dev, "cannot find debounce clk\n");
|
||||
clk_disable_unprepare(bank->clk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(bank->dev, rockchip_clk_put,
|
||||
bank->db_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case GPIO_TYPE_V1:
|
||||
bank->gpio_regs = &gpio_regs_v1;
|
||||
|
|
@ -751,7 +761,6 @@ static int rockchip_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
ret = rockchip_gpiolib_register(bank);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(bank->clk);
|
||||
mutex_unlock(&bank->deferred_lock);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -792,7 +801,9 @@ static void rockchip_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct rockchip_pin_bank *bank = platform_get_drvdata(pdev);
|
||||
|
||||
clk_disable_unprepare(bank->clk);
|
||||
irq_set_chained_handler_and_data(bank->irq, NULL, NULL);
|
||||
if (bank->domain)
|
||||
irq_domain_remove(bank->domain);
|
||||
gpiochip_remove(&bank->gpio_chip);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -103,9 +103,18 @@ static void gpio_shared_proxy_free(struct gpio_chip *gc, unsigned int offset)
|
|||
{
|
||||
struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
|
||||
struct gpio_shared_desc *shared_desc = proxy->shared_desc;
|
||||
int ret;
|
||||
|
||||
guard(gpio_shared_desc_lock)(shared_desc);
|
||||
|
||||
if (proxy->voted_high) {
|
||||
ret = gpio_shared_proxy_set_unlocked(proxy,
|
||||
shared_desc->can_sleep ? gpiod_set_value_cansleep : gpiod_set_value, 0);
|
||||
if (ret)
|
||||
dev_err(proxy->dev,
|
||||
"Failed to unset the shared GPIO value on release: %d\n", ret);
|
||||
}
|
||||
|
||||
proxy->shared_desc->usecnt--;
|
||||
|
||||
dev_dbg(proxy->dev, "Shared GPIO freed, number of users: %u\n",
|
||||
|
|
|
|||
|
|
@ -901,7 +901,7 @@ static int gpio_sim_device_activate(struct gpio_sim_device *dev)
|
|||
struct platform_device *pdev;
|
||||
struct fwnode_handle *swnode;
|
||||
struct gpio_sim_bank *bank;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
lockdep_assert_held(&dev->lock);
|
||||
|
||||
|
|
@ -945,9 +945,12 @@ static int gpio_sim_device_activate(struct gpio_sim_device *dev)
|
|||
}
|
||||
|
||||
wait_for_device_probe();
|
||||
if (!device_is_bound(&pdev->dev)) {
|
||||
ret = -ENXIO;
|
||||
goto err_unregister_pdev;
|
||||
|
||||
scoped_guard(device, &pdev->dev) {
|
||||
if (!device_is_bound(&pdev->dev)) {
|
||||
ret = -ENXIO;
|
||||
goto err_unregister_pdev;
|
||||
}
|
||||
}
|
||||
|
||||
dev->pdev = pdev;
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ static ssize_t gpio_virtuser_direction_do_write(struct file *file,
|
|||
char buf[32], *trimmed;
|
||||
int ret, dir, val = 0;
|
||||
|
||||
if (count >= sizeof(buf))
|
||||
if (*ppos != 0 || count >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
|
||||
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
|
||||
|
|
@ -622,7 +622,7 @@ static ssize_t gpio_virtuser_consumer_write(struct file *file,
|
|||
char buf[GPIO_VIRTUSER_NAME_BUF_LEN + 2];
|
||||
int ret;
|
||||
|
||||
if (count >= sizeof(buf))
|
||||
if (*ppos != 0 || count >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
|
||||
ret = simple_write_to_buffer(buf, GPIO_VIRTUSER_NAME_BUF_LEN, ppos,
|
||||
|
|
@ -1477,9 +1477,12 @@ gpio_virtuser_device_activate(struct gpio_virtuser_device *dev)
|
|||
}
|
||||
|
||||
wait_for_device_probe();
|
||||
if (!device_is_bound(&pdev->dev)) {
|
||||
ret = -ENXIO;
|
||||
goto err_unregister_pdev;
|
||||
|
||||
scoped_guard(device, &pdev->dev) {
|
||||
if (!device_is_bound(&pdev->dev)) {
|
||||
ret = -ENXIO;
|
||||
goto err_unregister_pdev;
|
||||
}
|
||||
}
|
||||
|
||||
dev->pdev = pdev;
|
||||
|
|
|
|||
|
|
@ -1184,6 +1184,7 @@ static int gpio_v2_line_flags_validate(u64 flags)
|
|||
static int gpio_v2_line_config_validate(struct gpio_v2_line_config *lc,
|
||||
unsigned int num_lines)
|
||||
{
|
||||
size_t unused_attrs;
|
||||
unsigned int i;
|
||||
u64 flags;
|
||||
int ret;
|
||||
|
|
@ -1191,9 +1192,21 @@ static int gpio_v2_line_config_validate(struct gpio_v2_line_config *lc,
|
|||
if (lc->num_attrs > GPIO_V2_LINE_NUM_ATTRS_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
unused_attrs = GPIO_V2_LINE_NUM_ATTRS_MAX - lc->num_attrs;
|
||||
|
||||
if (!mem_is_zero(lc->padding, sizeof(lc->padding)))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < lc->num_attrs; i++) {
|
||||
if (lc->attrs[i].attr.padding != 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (unused_attrs) {
|
||||
if (!mem_is_zero(&lc->attrs[lc->num_attrs], unused_attrs * sizeof(*lc->attrs)))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_lines; i++) {
|
||||
flags = gpio_v2_line_config_flags(lc, i);
|
||||
ret = gpio_v2_line_flags_validate(flags);
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ struct gpio_shared_entry {
|
|||
unsigned int offset;
|
||||
/* Index in the property value array. */
|
||||
size_t index;
|
||||
/* Synchronizes the modification of shared_desc. */
|
||||
/* Synchronizes the modification of shared_desc and offset. */
|
||||
struct mutex lock;
|
||||
struct gpio_shared_desc *shared_desc;
|
||||
struct kref ref;
|
||||
|
|
@ -598,16 +598,13 @@ void gpio_device_teardown_shared(struct gpio_device *gdev)
|
|||
struct gpio_shared_ref *ref;
|
||||
|
||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||
guard(mutex)(&entry->lock);
|
||||
|
||||
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
|
||||
continue;
|
||||
|
||||
gpiod_free_commit(&gdev->descs[entry->offset]);
|
||||
scoped_guard(mutex, &entry->lock)
|
||||
gpiod_free_commit(&gdev->descs[entry->offset]);
|
||||
|
||||
list_for_each_entry(ref, &entry->refs, list) {
|
||||
guard(mutex)(&ref->lock);
|
||||
|
||||
if (ref->lookup) {
|
||||
gpiod_remove_lookup_table(ref->lookup);
|
||||
kfree(ref->lookup->table[0].key);
|
||||
|
|
|
|||
|
|
@ -1190,7 +1190,6 @@ struct amdgpu_device {
|
|||
bool apu_prefer_gtt;
|
||||
|
||||
bool userq_halt_for_enforce_isolation;
|
||||
struct work_struct userq_reset_work;
|
||||
struct amdgpu_uid *uid_info;
|
||||
|
||||
struct amdgpu_uma_carveout_info uma_info;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@
|
|||
#include "amdgpu_ras.h"
|
||||
#include "amdgpu_umc.h"
|
||||
#include "amdgpu_reset.h"
|
||||
#if IS_ENABLED(CONFIG_HSA_AMD)
|
||||
#include "kfd_priv.h"
|
||||
#endif
|
||||
|
||||
/* Total memory size in system memory and all GPU VRAM. Used to
|
||||
* estimate worst case amount of memory to reserve for page tables
|
||||
|
|
@ -320,6 +323,28 @@ void amdgpu_amdkfd_gpu_reset(struct amdgpu_device *adev)
|
|||
(void)amdgpu_reset_domain_schedule(adev->reset_domain, &adev->kfd.reset_work);
|
||||
}
|
||||
|
||||
void amdgpu_amdkfd_clear_kfd_mapping(struct amdgpu_device *adev)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_HSA_AMD)
|
||||
struct kfd_dev *kfd = adev->kfd.dev;
|
||||
unsigned int i;
|
||||
|
||||
if (!kfd)
|
||||
return;
|
||||
|
||||
for (i = 0; i < kfd->num_nodes; i++) {
|
||||
struct kfd_node *node = kfd->nodes[i];
|
||||
|
||||
kfd_dev_unmap_mapping_range(KFD_MMAP_TYPE_DOORBELL |
|
||||
KFD_MMAP_GPU_ID(node->id),
|
||||
kfd_doorbell_process_slice(kfd));
|
||||
kfd_dev_unmap_mapping_range(KFD_MMAP_TYPE_MMIO |
|
||||
KFD_MMAP_GPU_ID(node->id),
|
||||
PAGE_SIZE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int amdgpu_amdkfd_alloc_kernel_mem(struct amdgpu_device *adev, size_t size,
|
||||
u32 domain, void **mem_obj, uint64_t *gpu_addr,
|
||||
void **cpu_ptr, bool cp_mqd_gfx9)
|
||||
|
|
|
|||
|
|
@ -358,6 +358,7 @@ int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev,
|
|||
uint64_t size, u32 alloc_flag, int8_t xcp_id);
|
||||
void amdgpu_amdkfd_unreserve_mem_limit(struct amdgpu_device *adev,
|
||||
uint64_t size, u32 alloc_flag, int8_t xcp_id);
|
||||
void amdgpu_amdkfd_clear_kfd_mapping(struct amdgpu_device *adev);
|
||||
|
||||
u64 amdgpu_amdkfd_xcp_memory_size(struct amdgpu_device *adev, int xcp_id);
|
||||
|
||||
|
|
|
|||
|
|
@ -3787,7 +3787,6 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
|||
}
|
||||
|
||||
INIT_WORK(&adev->xgmi_reset_work, amdgpu_device_xgmi_reset_func);
|
||||
INIT_WORK(&adev->userq_reset_work, amdgpu_userq_reset_work);
|
||||
|
||||
amdgpu_coredump_init(adev);
|
||||
|
||||
|
|
@ -5478,7 +5477,7 @@ static inline void amdgpu_device_stop_pending_resets(struct amdgpu_device *adev)
|
|||
if (!amdgpu_sriov_vf(adev))
|
||||
cancel_work(&adev->reset_work);
|
||||
#endif
|
||||
cancel_work(&adev->userq_reset_work);
|
||||
amdgpu_userq_mgr_cancel_reset_work(adev);
|
||||
|
||||
if (adev->kfd.dev)
|
||||
cancel_work(&adev->kfd.reset_work);
|
||||
|
|
@ -5836,6 +5835,12 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
|
|||
/* We need to lock reset domain only once both for XGMI and single device */
|
||||
amdgpu_device_recovery_get_reset_lock(adev, &device_list);
|
||||
|
||||
/* unmap all the mappings of doorbell and framebuffer to prevent user space from
|
||||
* accessing them
|
||||
*/
|
||||
unmap_mapping_range(adev->ddev.anon_inode->i_mapping, 0, 0, 1);
|
||||
amdgpu_amdkfd_clear_kfd_mapping(adev);
|
||||
|
||||
amdgpu_device_halt_activities(adev, job, reset_context, &device_list,
|
||||
hive, need_emergency_restart);
|
||||
if (need_emergency_restart)
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ static int amdgpu_discovery_get_tmr_info(struct amdgpu_device *adev,
|
|||
adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].offset;
|
||||
adev->discovery.size =
|
||||
adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].size_kb << 10;
|
||||
if (!adev->discovery.offset || !adev->discovery.size)
|
||||
if (!adev->discovery.size)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/dma-fence-unwrap.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include <drm/drm_drv.h>
|
||||
|
|
@ -508,6 +509,9 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
|
|||
if (offset_in_page(args->addr | args->size))
|
||||
return -EINVAL;
|
||||
|
||||
if (!access_ok((void __user *)(uintptr_t)args->addr, args->size))
|
||||
return -EFAULT;
|
||||
|
||||
/* reject unknown flag values */
|
||||
if (args->flags & ~(AMDGPU_GEM_USERPTR_READONLY |
|
||||
AMDGPU_GEM_USERPTR_ANONONLY | AMDGPU_GEM_USERPTR_VALIDATE |
|
||||
|
|
@ -821,7 +825,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
|
|||
struct drm_syncobj *timeline_syncobj = NULL;
|
||||
struct dma_fence_chain *timeline_chain = NULL;
|
||||
struct drm_exec exec;
|
||||
uint64_t vm_size;
|
||||
uint64_t vm_size, tmp;
|
||||
int r = 0;
|
||||
|
||||
/* Validate virtual address range against reserved regions. */
|
||||
|
|
@ -845,7 +849,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
|
|||
|
||||
vm_size = adev->vm_manager.max_pfn * AMDGPU_GPU_PAGE_SIZE;
|
||||
vm_size -= AMDGPU_VA_RESERVED_TOP;
|
||||
if (args->va_address + args->map_size > vm_size) {
|
||||
if (check_add_overflow(args->va_address, args->map_size, &tmp) || tmp > vm_size) {
|
||||
dev_dbg(dev->dev,
|
||||
"va_address 0x%llx is in top reserved area 0x%llx\n",
|
||||
args->va_address + args->map_size, vm_size);
|
||||
|
|
|
|||
|
|
@ -199,11 +199,18 @@ int amdgpu_gtt_mgr_alloc_entries(struct amdgpu_gtt_mgr *mgr,
|
|||
enum drm_mm_insert_mode mode)
|
||||
{
|
||||
struct amdgpu_device *adev = container_of(mgr, typeof(*adev), mman.gtt_mgr);
|
||||
u32 alignment = 0;
|
||||
int r;
|
||||
|
||||
/* Align to TLB L2 cache entry size to work around "V bit HW bug" */
|
||||
if (adev->asic_type == CHIP_TAHITI) {
|
||||
alignment = 32 * 1024 / AMDGPU_GPU_PAGE_SIZE;
|
||||
num_pages = ALIGN(num_pages, alignment);
|
||||
}
|
||||
|
||||
spin_lock(&mgr->lock);
|
||||
r = drm_mm_insert_node_in_range(&mgr->mm, mm_node, num_pages,
|
||||
0, GART_ENTRY_WITHOUT_BO_COLOR, 0,
|
||||
alignment, GART_ENTRY_WITHOUT_BO_COLOR, 0,
|
||||
adev->gmc.gart_size >> PAGE_SHIFT,
|
||||
mode);
|
||||
spin_unlock(&mgr->lock);
|
||||
|
|
|
|||
|
|
@ -96,7 +96,8 @@ struct amdgpu_bo_va {
|
|||
* if non-zero, cannot unmap from GPU because user queues may still access it
|
||||
*/
|
||||
unsigned int queue_refcount;
|
||||
atomic_t userq_va_mapped;
|
||||
/* Indicates if this buffer is mapped for any user queue. Once set, never reset. */
|
||||
bool userq_va_mapped;
|
||||
};
|
||||
|
||||
struct amdgpu_bo {
|
||||
|
|
|
|||
|
|
@ -175,11 +175,14 @@ int amdgpu_seq64_alloc(struct amdgpu_device *adev, u64 *va,
|
|||
{
|
||||
unsigned long bit_pos;
|
||||
|
||||
bit_pos = find_first_zero_bit(adev->seq64.used, adev->seq64.num_sem);
|
||||
if (bit_pos >= adev->seq64.num_sem)
|
||||
return -ENOSPC;
|
||||
for (;;) {
|
||||
bit_pos = find_first_zero_bit(adev->seq64.used, adev->seq64.num_sem);
|
||||
if (bit_pos >= adev->seq64.num_sem)
|
||||
return -ENOSPC;
|
||||
|
||||
__set_bit(bit_pos, adev->seq64.used);
|
||||
if (!test_and_set_bit(bit_pos, adev->seq64.used))
|
||||
break;
|
||||
}
|
||||
|
||||
*va = bit_pos * sizeof(u64) + amdgpu_seq64_get_va_base(adev);
|
||||
|
||||
|
|
@ -205,7 +208,7 @@ void amdgpu_seq64_free(struct amdgpu_device *adev, u64 va)
|
|||
|
||||
bit_pos = (va - amdgpu_seq64_get_va_base(adev)) / sizeof(u64);
|
||||
if (bit_pos < adev->seq64.num_sem)
|
||||
__clear_bit(bit_pos, adev->seq64.used);
|
||||
clear_bit(bit_pos, adev->seq64.used);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ void amdgpu_umc_handle_bad_pages(struct amdgpu_device *adev,
|
|||
if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops &&
|
||||
adev->umc.ras->ras_block.hw_ops->query_ras_error_address &&
|
||||
adev->umc.max_ras_err_cnt_per_query) {
|
||||
kfree(err_data->err_addr);
|
||||
err_data->err_addr =
|
||||
kzalloc_objs(struct eeprom_table_record,
|
||||
adev->umc.max_ras_err_cnt_per_query);
|
||||
|
|
@ -160,6 +161,7 @@ void amdgpu_umc_handle_bad_pages(struct amdgpu_device *adev,
|
|||
if (adev->umc.ras &&
|
||||
adev->umc.ras->ecc_info_query_ras_error_address &&
|
||||
adev->umc.max_ras_err_cnt_per_query) {
|
||||
kfree(err_data->err_addr);
|
||||
err_data->err_addr =
|
||||
kzalloc_objs(struct eeprom_table_record,
|
||||
adev->umc.max_ras_err_cnt_per_query);
|
||||
|
|
|
|||
|
|
@ -82,19 +82,11 @@ static bool amdgpu_userq_is_reset_type_supported(struct amdgpu_device *adev,
|
|||
return false;
|
||||
}
|
||||
|
||||
static void amdgpu_userq_gpu_reset(struct amdgpu_device *adev)
|
||||
{
|
||||
if (amdgpu_device_should_recover_gpu(adev)) {
|
||||
amdgpu_reset_domain_schedule(adev->reset_domain,
|
||||
&adev->userq_reset_work);
|
||||
/* Wait for the reset job to complete */
|
||||
flush_work(&adev->userq_reset_work);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
amdgpu_userq_detect_and_reset_queues(struct amdgpu_userq_mgr *uq_mgr)
|
||||
static void amdgpu_userq_mgr_reset_work(struct work_struct *work)
|
||||
{
|
||||
struct amdgpu_userq_mgr *uq_mgr =
|
||||
container_of(work, struct amdgpu_userq_mgr,
|
||||
reset_work);
|
||||
struct amdgpu_device *adev = uq_mgr->adev;
|
||||
const int queue_types[] = {
|
||||
AMDGPU_RING_TYPE_COMPUTE,
|
||||
|
|
@ -103,12 +95,11 @@ amdgpu_userq_detect_and_reset_queues(struct amdgpu_userq_mgr *uq_mgr)
|
|||
};
|
||||
const int num_queue_types = ARRAY_SIZE(queue_types);
|
||||
bool gpu_reset = false;
|
||||
int r = 0;
|
||||
int i;
|
||||
int i, r;
|
||||
|
||||
if (unlikely(adev->debug_disable_gpu_ring_reset)) {
|
||||
dev_err(adev->dev, "userq reset disabled by debug mask\n");
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -116,7 +107,7 @@ amdgpu_userq_detect_and_reset_queues(struct amdgpu_userq_mgr *uq_mgr)
|
|||
* skip all reset detection logic
|
||||
*/
|
||||
if (!amdgpu_gpu_recovery)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
/*
|
||||
* Iterate through all queue types to detect and reset problematic queues
|
||||
|
|
@ -141,10 +132,19 @@ amdgpu_userq_detect_and_reset_queues(struct amdgpu_userq_mgr *uq_mgr)
|
|||
}
|
||||
}
|
||||
|
||||
if (gpu_reset)
|
||||
amdgpu_userq_gpu_reset(adev);
|
||||
if (gpu_reset) {
|
||||
struct amdgpu_reset_context reset_context;
|
||||
|
||||
return r;
|
||||
memset(&reset_context, 0, sizeof(reset_context));
|
||||
|
||||
reset_context.method = AMD_RESET_METHOD_NONE;
|
||||
reset_context.reset_req_dev = adev;
|
||||
reset_context.src = AMDGPU_RESET_SRC_USERQ;
|
||||
set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
|
||||
/*set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);*/
|
||||
|
||||
amdgpu_device_gpu_recover(adev, NULL, &reset_context);
|
||||
}
|
||||
}
|
||||
|
||||
static void amdgpu_userq_hang_detect_work(struct work_struct *work)
|
||||
|
|
@ -153,7 +153,11 @@ static void amdgpu_userq_hang_detect_work(struct work_struct *work)
|
|||
container_of(work, struct amdgpu_usermode_queue,
|
||||
hang_detect_work.work);
|
||||
|
||||
amdgpu_userq_detect_and_reset_queues(queue->userq_mgr);
|
||||
/*
|
||||
* Don't schedule the work here! Scheduling or queue work from one reset
|
||||
* handler to another is illegal if you don't take extra precautions!
|
||||
*/
|
||||
amdgpu_userq_mgr_reset_work(&queue->userq_mgr->reset_work);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -182,8 +186,8 @@ void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue)
|
|||
break;
|
||||
}
|
||||
|
||||
schedule_delayed_work(&queue->hang_detect_work,
|
||||
msecs_to_jiffies(timeout_ms));
|
||||
queue_delayed_work(adev->reset_domain->wq, &queue->hang_detect_work,
|
||||
msecs_to_jiffies(timeout_ms));
|
||||
}
|
||||
|
||||
void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell)
|
||||
|
|
@ -223,7 +227,7 @@ static int amdgpu_userq_buffer_va_list_add(struct amdgpu_usermode_queue *queue,
|
|||
|
||||
INIT_LIST_HEAD(&va_cursor->list);
|
||||
va_cursor->gpu_addr = addr;
|
||||
atomic_set(&va_map->bo_va->userq_va_mapped, 1);
|
||||
va_map->bo_va->userq_va_mapped = true;
|
||||
list_add(&va_cursor->list, &queue->userq_va_list);
|
||||
|
||||
return 0;
|
||||
|
|
@ -270,7 +274,7 @@ static bool amdgpu_userq_buffer_va_mapped(struct amdgpu_vm *vm, u64 addr)
|
|||
dma_resv_assert_held(vm->root.bo->tbo.base.resv);
|
||||
|
||||
mapping = amdgpu_vm_bo_lookup_mapping(vm, addr);
|
||||
if (!IS_ERR_OR_NULL(mapping) && atomic_read(&mapping->bo_va->userq_va_mapped))
|
||||
if (!IS_ERR_OR_NULL(mapping) && mapping->bo_va->userq_va_mapped)
|
||||
r = true;
|
||||
else
|
||||
r = false;
|
||||
|
|
@ -296,16 +300,8 @@ static bool amdgpu_userq_buffer_vas_mapped(struct amdgpu_usermode_queue *queue)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void amdgpu_userq_buffer_va_list_del(struct amdgpu_bo_va_mapping *mapping,
|
||||
struct amdgpu_userq_va_cursor *va_cursor)
|
||||
{
|
||||
atomic_set(&mapping->bo_va->userq_va_mapped, 0);
|
||||
list_del(&va_cursor->list);
|
||||
kfree(va_cursor);
|
||||
}
|
||||
|
||||
static int amdgpu_userq_buffer_vas_list_cleanup(struct amdgpu_device *adev,
|
||||
struct amdgpu_usermode_queue *queue)
|
||||
static void amdgpu_userq_buffer_vas_list_cleanup(struct amdgpu_device *adev,
|
||||
struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
struct amdgpu_userq_va_cursor *va_cursor, *tmp;
|
||||
struct amdgpu_bo_va_mapping *mapping;
|
||||
|
|
@ -315,15 +311,12 @@ static int amdgpu_userq_buffer_vas_list_cleanup(struct amdgpu_device *adev,
|
|||
|
||||
list_for_each_entry_safe(va_cursor, tmp, &queue->userq_va_list, list) {
|
||||
mapping = amdgpu_vm_bo_lookup_mapping(queue->vm, va_cursor->gpu_addr);
|
||||
if (!mapping) {
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_dbg(adev->dev, "delete the userq:%p va:%llx\n",
|
||||
queue, va_cursor->gpu_addr);
|
||||
amdgpu_userq_buffer_va_list_del(mapping, va_cursor);
|
||||
if (mapping)
|
||||
dev_dbg(adev->dev, "delete the userq:%p va:%llx\n",
|
||||
queue, va_cursor->gpu_addr);
|
||||
list_del(&va_cursor->list);
|
||||
kfree(va_cursor);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_userq_preempt_helper(struct amdgpu_usermode_queue *queue)
|
||||
|
|
@ -504,16 +497,20 @@ int amdgpu_userq_create_object(struct amdgpu_userq_mgr *uq_mgr,
|
|||
goto free_obj;
|
||||
}
|
||||
|
||||
r = amdgpu_bo_pin(userq_obj->obj, AMDGPU_GEM_DOMAIN_GTT);
|
||||
if (r)
|
||||
goto unresv;
|
||||
|
||||
r = amdgpu_ttm_alloc_gart(&(userq_obj->obj)->tbo);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to alloc GART for userqueue object (%d)", r);
|
||||
goto unresv;
|
||||
goto unpin_bo;
|
||||
}
|
||||
|
||||
r = amdgpu_bo_kmap(userq_obj->obj, &userq_obj->cpu_ptr);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to map BO for userqueue (%d)", r);
|
||||
goto unresv;
|
||||
goto unpin_bo;
|
||||
}
|
||||
|
||||
userq_obj->gpu_addr = amdgpu_bo_gpu_offset(userq_obj->obj);
|
||||
|
|
@ -521,11 +518,13 @@ int amdgpu_userq_create_object(struct amdgpu_userq_mgr *uq_mgr,
|
|||
memset(userq_obj->cpu_ptr, 0, size);
|
||||
return 0;
|
||||
|
||||
unpin_bo:
|
||||
amdgpu_bo_unpin(userq_obj->obj);
|
||||
unresv:
|
||||
amdgpu_bo_unreserve(userq_obj->obj);
|
||||
|
||||
free_obj:
|
||||
amdgpu_bo_unref(&userq_obj->obj);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -533,6 +532,7 @@ void amdgpu_userq_destroy_object(struct amdgpu_userq_mgr *uq_mgr,
|
|||
struct amdgpu_userq_obj *userq_obj)
|
||||
{
|
||||
amdgpu_bo_kunmap(userq_obj->obj);
|
||||
amdgpu_bo_unpin(userq_obj->obj);
|
||||
amdgpu_bo_unref(&userq_obj->obj);
|
||||
}
|
||||
|
||||
|
|
@ -708,14 +708,14 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
const struct amdgpu_userq_funcs *uq_funcs;
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
struct amdgpu_db_info db_info;
|
||||
bool skip_map_queue;
|
||||
u32 qid;
|
||||
uint64_t index;
|
||||
int r = 0;
|
||||
int priority =
|
||||
(args->in.flags & AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_MASK) >>
|
||||
AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_SHIFT;
|
||||
int priority;
|
||||
u32 qid;
|
||||
int r;
|
||||
|
||||
priority =
|
||||
(args->in.flags & AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_MASK)
|
||||
>> AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_SHIFT;
|
||||
r = amdgpu_userq_priority_permit(filp, priority);
|
||||
if (r)
|
||||
return r;
|
||||
|
|
@ -728,40 +728,43 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
|
||||
uq_funcs = adev->userq_funcs[args->in.ip_type];
|
||||
if (!uq_funcs) {
|
||||
drm_file_err(uq_mgr->file, "Usermode queue is not supported for this IP (%u)\n",
|
||||
args->in.ip_type);
|
||||
r = -EINVAL;
|
||||
goto err_pm_runtime;
|
||||
}
|
||||
|
||||
queue = kzalloc_obj(struct amdgpu_usermode_queue);
|
||||
if (!queue) {
|
||||
drm_file_err(uq_mgr->file, "Failed to allocate memory for queue\n");
|
||||
r = -ENOMEM;
|
||||
goto err_pm_runtime;
|
||||
}
|
||||
|
||||
kref_init(&queue->refcount);
|
||||
INIT_LIST_HEAD(&queue->userq_va_list);
|
||||
queue->doorbell_handle = args->in.doorbell_handle;
|
||||
queue->queue_type = args->in.ip_type;
|
||||
queue->vm = &fpriv->vm;
|
||||
queue->priority = priority;
|
||||
|
||||
db_info.queue_type = queue->queue_type;
|
||||
db_info.doorbell_handle = queue->doorbell_handle;
|
||||
db_info.db_obj = &queue->db_obj;
|
||||
db_info.doorbell_offset = args->in.doorbell_offset;
|
||||
|
||||
queue->userq_mgr = uq_mgr;
|
||||
INIT_DELAYED_WORK(&queue->hang_detect_work,
|
||||
amdgpu_userq_hang_detect_work);
|
||||
|
||||
/* Validate the userq virtual address.*/
|
||||
r = amdgpu_bo_reserve(fpriv->vm.root.bo, false);
|
||||
mutex_init(&queue->fence_drv_lock);
|
||||
xa_init_flags(&queue->fence_drv_xa, XA_FLAGS_ALLOC);
|
||||
r = amdgpu_userq_fence_driver_alloc(adev, &queue->fence_drv);
|
||||
if (r)
|
||||
goto free_queue;
|
||||
|
||||
if (amdgpu_userq_input_va_validate(adev, queue, args->in.queue_va, args->in.queue_size) ||
|
||||
amdgpu_userq_input_va_validate(adev, queue, args->in.rptr_va, AMDGPU_GPU_PAGE_SIZE) ||
|
||||
amdgpu_userq_input_va_validate(adev, queue, args->in.wptr_va, AMDGPU_GPU_PAGE_SIZE)) {
|
||||
/* Make sure the queue can actually run with those virtual addresses. */
|
||||
r = amdgpu_bo_reserve(fpriv->vm.root.bo, false);
|
||||
if (r)
|
||||
goto free_fence_drv;
|
||||
|
||||
if (amdgpu_userq_input_va_validate(adev, queue, args->in.queue_va,
|
||||
args->in.queue_size) ||
|
||||
amdgpu_userq_input_va_validate(adev, queue, args->in.rptr_va,
|
||||
AMDGPU_GPU_PAGE_SIZE) ||
|
||||
amdgpu_userq_input_va_validate(adev, queue, args->in.wptr_va,
|
||||
AMDGPU_GPU_PAGE_SIZE)) {
|
||||
r = -EINVAL;
|
||||
amdgpu_bo_unreserve(fpriv->vm.root.bo);
|
||||
goto clean_mapping;
|
||||
|
|
@ -769,6 +772,10 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
amdgpu_bo_unreserve(fpriv->vm.root.bo);
|
||||
|
||||
/* Convert relative doorbell offset into absolute doorbell index */
|
||||
db_info.queue_type = queue->queue_type;
|
||||
db_info.doorbell_handle = queue->doorbell_handle;
|
||||
db_info.db_obj = &queue->db_obj;
|
||||
db_info.doorbell_offset = args->in.doorbell_offset;
|
||||
index = amdgpu_userq_get_doorbell_index(uq_mgr, &db_info, filp);
|
||||
if (index == (uint64_t)-EINVAL) {
|
||||
drm_file_err(uq_mgr->file, "Failed to get doorbell for queue\n");
|
||||
|
|
@ -777,82 +784,64 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
}
|
||||
|
||||
queue->doorbell_index = index;
|
||||
mutex_init(&queue->fence_drv_lock);
|
||||
xa_init_flags(&queue->fence_drv_xa, XA_FLAGS_ALLOC);
|
||||
r = amdgpu_userq_fence_driver_alloc(adev, &queue->fence_drv);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to alloc fence driver\n");
|
||||
goto clean_mapping;
|
||||
}
|
||||
|
||||
r = uq_funcs->mqd_create(queue, &args->in);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to create Queue\n");
|
||||
goto clean_fence_driver;
|
||||
goto clean_mapping;
|
||||
}
|
||||
|
||||
/* Update VM owner at userq submit-time for page-fault attribution. */
|
||||
amdgpu_vm_set_task_info(&fpriv->vm);
|
||||
|
||||
r = xa_err(xa_store_irq(&adev->userq_doorbell_xa, index, queue,
|
||||
GFP_KERNEL));
|
||||
if (r)
|
||||
goto clean_mqd;
|
||||
|
||||
amdgpu_userq_ensure_ev_fence(&fpriv->userq_mgr, &fpriv->evf_mgr);
|
||||
|
||||
/* don't map the queue if scheduling is halted */
|
||||
if (adev->userq_halt_for_enforce_isolation &&
|
||||
((queue->queue_type == AMDGPU_HW_IP_GFX) ||
|
||||
(queue->queue_type == AMDGPU_HW_IP_COMPUTE)))
|
||||
skip_map_queue = true;
|
||||
else
|
||||
skip_map_queue = false;
|
||||
if (!skip_map_queue) {
|
||||
if (!adev->userq_halt_for_enforce_isolation ||
|
||||
((queue->queue_type != AMDGPU_HW_IP_GFX) &&
|
||||
(queue->queue_type != AMDGPU_HW_IP_COMPUTE))) {
|
||||
r = amdgpu_userq_map_helper(queue);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to map Queue\n");
|
||||
goto clean_mqd;
|
||||
mutex_unlock(&uq_mgr->userq_mutex);
|
||||
goto clean_doorbell;
|
||||
}
|
||||
}
|
||||
|
||||
/* drop this refcount during queue destroy */
|
||||
kref_init(&queue->refcount);
|
||||
|
||||
/* Wait for mode-1 reset to complete */
|
||||
down_read(&adev->reset_domain->sem);
|
||||
|
||||
r = xa_alloc(&uq_mgr->userq_xa, &qid, queue,
|
||||
XA_LIMIT(1, AMDGPU_MAX_USERQ_COUNT), GFP_KERNEL);
|
||||
if (r) {
|
||||
if (!skip_map_queue)
|
||||
amdgpu_userq_unmap_helper(queue);
|
||||
r = -ENOMEM;
|
||||
goto clean_reset_domain;
|
||||
}
|
||||
|
||||
r = xa_err(xa_store_irq(&adev->userq_doorbell_xa, index, queue, GFP_KERNEL));
|
||||
if (r) {
|
||||
xa_erase(&uq_mgr->userq_xa, qid);
|
||||
if (!skip_map_queue)
|
||||
amdgpu_userq_unmap_helper(queue);
|
||||
goto clean_reset_domain;
|
||||
}
|
||||
up_read(&adev->reset_domain->sem);
|
||||
|
||||
amdgpu_debugfs_userq_init(filp, queue, qid);
|
||||
INIT_DELAYED_WORK(&queue->hang_detect_work,
|
||||
amdgpu_userq_hang_detect_work);
|
||||
|
||||
args->out.queue_id = qid;
|
||||
atomic_inc(&uq_mgr->userq_count[queue->queue_type]);
|
||||
mutex_unlock(&uq_mgr->userq_mutex);
|
||||
|
||||
r = xa_alloc(&uq_mgr->userq_xa, &qid, queue,
|
||||
XA_LIMIT(1, AMDGPU_MAX_USERQ_COUNT),
|
||||
GFP_KERNEL);
|
||||
if (r) {
|
||||
/*
|
||||
* This drops the last reference which should take care of
|
||||
* all cleanup.
|
||||
*/
|
||||
amdgpu_userq_put(queue);
|
||||
return r;
|
||||
}
|
||||
|
||||
amdgpu_debugfs_userq_init(filp, queue, qid);
|
||||
args->out.queue_id = qid;
|
||||
return 0;
|
||||
|
||||
clean_reset_domain:
|
||||
up_read(&adev->reset_domain->sem);
|
||||
clean_doorbell:
|
||||
xa_erase_irq(&adev->userq_doorbell_xa, index);
|
||||
clean_mqd:
|
||||
mutex_unlock(&uq_mgr->userq_mutex);
|
||||
uq_funcs->mqd_destroy(queue);
|
||||
clean_fence_driver:
|
||||
amdgpu_userq_fence_driver_free(queue);
|
||||
clean_mapping:
|
||||
amdgpu_bo_reserve(fpriv->vm.root.bo, true);
|
||||
amdgpu_userq_buffer_vas_list_cleanup(adev, queue);
|
||||
amdgpu_bo_unreserve(fpriv->vm.root.bo);
|
||||
mutex_destroy(&queue->fence_drv_lock);
|
||||
free_fence_drv:
|
||||
amdgpu_userq_fence_driver_free(queue);
|
||||
free_queue:
|
||||
kfree(queue);
|
||||
err_pm_runtime:
|
||||
|
|
@ -1252,28 +1241,13 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
|
|||
if (ret) {
|
||||
drm_file_err(uq_mgr->file,
|
||||
"Couldn't unmap all the queues, eviction failed ret=%d\n", ret);
|
||||
amdgpu_userq_detect_and_reset_queues(uq_mgr);
|
||||
amdgpu_reset_domain_schedule(uq_mgr->adev->reset_domain,
|
||||
&uq_mgr->reset_work);
|
||||
flush_work(&uq_mgr->reset_work);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void amdgpu_userq_reset_work(struct work_struct *work)
|
||||
{
|
||||
struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
|
||||
userq_reset_work);
|
||||
struct amdgpu_reset_context reset_context;
|
||||
|
||||
memset(&reset_context, 0, sizeof(reset_context));
|
||||
|
||||
reset_context.method = AMD_RESET_METHOD_NONE;
|
||||
reset_context.reset_req_dev = adev;
|
||||
reset_context.src = AMDGPU_RESET_SRC_USERQ;
|
||||
set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
|
||||
/*set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);*/
|
||||
|
||||
amdgpu_device_gpu_recover(adev, NULL, &reset_context);
|
||||
}
|
||||
|
||||
static void
|
||||
amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr)
|
||||
{
|
||||
|
|
@ -1307,9 +1281,24 @@ int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *f
|
|||
userq_mgr->file = file_priv;
|
||||
|
||||
INIT_DELAYED_WORK(&userq_mgr->resume_work, amdgpu_userq_restore_worker);
|
||||
INIT_WORK(&userq_mgr->reset_work, amdgpu_userq_mgr_reset_work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void amdgpu_userq_mgr_cancel_reset_work(struct amdgpu_device *adev)
|
||||
{
|
||||
struct xarray *xa = &adev->userq_doorbell_xa;
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
unsigned long flags, queue_id;
|
||||
|
||||
xa_lock_irqsave(xa, flags);
|
||||
xa_for_each(xa, queue_id, queue) {
|
||||
cancel_delayed_work(&queue->hang_detect_work);
|
||||
cancel_work(&queue->userq_mgr->reset_work);
|
||||
}
|
||||
xa_unlock_irqrestore(xa, flags);
|
||||
}
|
||||
|
||||
void amdgpu_userq_mgr_cancel_resume(struct amdgpu_userq_mgr *userq_mgr)
|
||||
{
|
||||
cancel_delayed_work_sync(&userq_mgr->resume_work);
|
||||
|
|
@ -1335,6 +1324,14 @@ void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr)
|
|||
}
|
||||
|
||||
xa_destroy(&userq_mgr->userq_xa);
|
||||
|
||||
/*
|
||||
* Drain any in-flight reset_work. By this point all queues are freed
|
||||
* and userq_count is 0, so if reset_work starts now it exits early.
|
||||
* We still need to wait in case it was already executing gpu_recover.
|
||||
*/
|
||||
cancel_work_sync(&userq_mgr->reset_work);
|
||||
|
||||
mutex_destroy(&userq_mgr->userq_mutex);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,13 @@ struct amdgpu_usermode_queue {
|
|||
u32 xcp_id;
|
||||
int priority;
|
||||
struct dentry *debugfs_queue;
|
||||
struct delayed_work hang_detect_work;
|
||||
|
||||
/**
|
||||
* @hang_detect_work:
|
||||
*
|
||||
* Delayed work which runs when userq_fences time out.
|
||||
*/
|
||||
struct delayed_work hang_detect_work;
|
||||
struct kref refcount;
|
||||
|
||||
struct list_head userq_va_list;
|
||||
|
|
@ -116,6 +122,13 @@ struct amdgpu_userq_mgr {
|
|||
struct amdgpu_device *adev;
|
||||
struct delayed_work resume_work;
|
||||
struct drm_file *file;
|
||||
|
||||
/**
|
||||
* @reset_work:
|
||||
*
|
||||
* Reset work which is used when eviction fails.
|
||||
*/
|
||||
struct work_struct reset_work;
|
||||
atomic_t userq_count[AMDGPU_RING_TYPE_MAX];
|
||||
};
|
||||
|
||||
|
|
@ -134,6 +147,7 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data, struct drm_file *filp
|
|||
int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *file_priv,
|
||||
struct amdgpu_device *adev);
|
||||
|
||||
void amdgpu_userq_mgr_cancel_reset_work(struct amdgpu_device *adev);
|
||||
void amdgpu_userq_mgr_cancel_resume(struct amdgpu_userq_mgr *userq_mgr);
|
||||
void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr);
|
||||
|
||||
|
|
|
|||
|
|
@ -370,51 +370,48 @@ static int amdgpu_userq_fence_read_wptr(struct amdgpu_device *adev,
|
|||
{
|
||||
struct amdgpu_bo_va_mapping *mapping;
|
||||
struct amdgpu_bo *bo;
|
||||
struct drm_exec exec;
|
||||
u64 addr, *ptr;
|
||||
int r;
|
||||
|
||||
r = amdgpu_bo_reserve(queue->vm->root.bo, false);
|
||||
if (r)
|
||||
return r;
|
||||
int ret;
|
||||
|
||||
addr = queue->userq_prop->wptr_gpu_addr;
|
||||
addr &= AMDGPU_GMC_HOLE_MASK;
|
||||
|
||||
mapping = amdgpu_vm_bo_lookup_mapping(queue->vm, addr >> PAGE_SHIFT);
|
||||
if (!mapping) {
|
||||
amdgpu_bo_unreserve(queue->vm->root.bo);
|
||||
DRM_ERROR("Failed to lookup amdgpu_bo_va_mapping\n");
|
||||
return -EINVAL;
|
||||
drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 2);
|
||||
drm_exec_until_all_locked(&exec) {
|
||||
ret = amdgpu_vm_lock_pd(queue->vm, &exec, 1);
|
||||
drm_exec_retry_on_contention(&exec);
|
||||
if (unlikely(ret))
|
||||
goto lock_error;
|
||||
|
||||
mapping = amdgpu_vm_bo_lookup_mapping(queue->vm, addr >> PAGE_SHIFT);
|
||||
if (!mapping) {
|
||||
ret = -EINVAL;
|
||||
goto lock_error;
|
||||
}
|
||||
|
||||
ret = drm_exec_lock_obj(&exec, &mapping->bo_va->base.bo->tbo.base);
|
||||
drm_exec_retry_on_contention(&exec);
|
||||
if (unlikely(ret))
|
||||
goto lock_error;
|
||||
}
|
||||
|
||||
bo = amdgpu_bo_ref(mapping->bo_va->base.bo);
|
||||
amdgpu_bo_unreserve(queue->vm->root.bo);
|
||||
r = amdgpu_bo_reserve(bo, true);
|
||||
if (r) {
|
||||
amdgpu_bo_unref(&bo);
|
||||
DRM_ERROR("Failed to reserve userqueue wptr bo");
|
||||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_bo_kmap(bo, (void **)&ptr);
|
||||
if (r) {
|
||||
bo = mapping->bo_va->base.bo;
|
||||
ret = amdgpu_bo_kmap(bo, (void **)&ptr);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed mapping the userqueue wptr bo");
|
||||
goto map_error;
|
||||
goto lock_error;
|
||||
}
|
||||
|
||||
*wptr = le64_to_cpu(*ptr);
|
||||
|
||||
amdgpu_bo_kunmap(bo);
|
||||
amdgpu_bo_unreserve(bo);
|
||||
amdgpu_bo_unref(&bo);
|
||||
|
||||
drm_exec_fini(&exec);
|
||||
return 0;
|
||||
|
||||
map_error:
|
||||
amdgpu_bo_unreserve(bo);
|
||||
amdgpu_bo_unref(&bo);
|
||||
|
||||
return r;
|
||||
lock_error:
|
||||
drm_exec_fini(&exec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -2002,7 +2002,7 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
|
|||
* during user requests GEM unmap IOCTL except for forcing the unmap
|
||||
* from user space.
|
||||
*/
|
||||
if (unlikely(atomic_read(&bo_va->userq_va_mapped) > 0))
|
||||
if (unlikely(bo_va->userq_va_mapped))
|
||||
amdgpu_userq_gem_va_unmap_validate(adev, mapping, saddr);
|
||||
|
||||
list_del(&mapping->list);
|
||||
|
|
|
|||
|
|
@ -562,6 +562,11 @@ static void vpe_ring_emit_fence(struct amdgpu_ring *ring, uint64_t addr,
|
|||
amdgpu_ring_write(ring, 0);
|
||||
}
|
||||
|
||||
/* WA: Force sync after TRAP to avoid VPE1 fail to power off */
|
||||
if (ring->adev->vpe.collaborate_mode) {
|
||||
amdgpu_ring_write(ring, VPE_CMD_HEADER(VPE_CMD_OPCODE_COLLAB_SYNC, 0));
|
||||
amdgpu_ring_write(ring, 0xabcd);
|
||||
}
|
||||
}
|
||||
|
||||
static void vpe_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
|
||||
|
|
@ -968,7 +973,7 @@ static const struct amdgpu_ring_funcs vpe_ring_funcs = {
|
|||
.emit_frame_size =
|
||||
5 + /* vpe_ring_init_cond_exec */
|
||||
6 + /* vpe_ring_emit_pipeline_sync */
|
||||
10 + 10 + 10 + /* vpe_ring_emit_fence */
|
||||
12 + 12 + 12 + /* vpe_ring_emit_fence */
|
||||
/* vpe_ring_emit_vm_flush */
|
||||
SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 +
|
||||
SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 6,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user