mirror of
https://github.com/torvalds/linux.git
synced 2024-11-29 07:31:29 +00:00
Merge drm/drm-next into drm-intel-next
Need to bring commit d8bb92e70a
("drm/dp: Factor out a function to
probe a DPCD address") back as a dependency to further work in
drm-intel-next.
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
This commit is contained in:
commit
3e8d34ed49
4
.mailmap
4
.mailmap
@ -391,6 +391,10 @@ Uwe Kleine-König <ukleinek@strlen.de>
|
||||
Uwe Kleine-König <ukl@pengutronix.de>
|
||||
Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com>
|
||||
Valdis Kletnieks <Valdis.Kletnieks@vt.edu>
|
||||
Vasily Averin <vasily.averin@linux.dev> <vvs@virtuozzo.com>
|
||||
Vasily Averin <vasily.averin@linux.dev> <vvs@openvz.org>
|
||||
Vasily Averin <vasily.averin@linux.dev> <vvs@parallels.com>
|
||||
Vasily Averin <vasily.averin@linux.dev> <vvs@sw.ru>
|
||||
Vinod Koul <vkoul@kernel.org> <vinod.koul@intel.com>
|
||||
Vinod Koul <vkoul@kernel.org> <vinod.koul@linux.intel.com>
|
||||
Vinod Koul <vkoul@kernel.org> <vkoul@infradead.org>
|
||||
|
@ -41,13 +41,18 @@ or ``VFAT_FS``. To run ``FAT_KUNIT_TEST``, the ``.kunitconfig`` has:
|
||||
CONFIG_MSDOS_FS=y
|
||||
CONFIG_FAT_KUNIT_TEST=y
|
||||
|
||||
1. A good starting point for the ``.kunitconfig``, is the KUnit default
|
||||
config. Run the command:
|
||||
1. A good starting point for the ``.kunitconfig`` is the KUnit default config.
|
||||
You can generate it by running:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd $PATH_TO_LINUX_REPO
|
||||
cp tools/testing/kunit/configs/default.config .kunitconfig
|
||||
tools/testing/kunit/kunit.py config
|
||||
cat .kunit/.kunitconfig
|
||||
|
||||
.. note ::
|
||||
``.kunitconfig`` lives in the ``--build_dir`` used by kunit.py, which is
|
||||
``.kunit`` by default.
|
||||
|
||||
.. note ::
|
||||
You may want to remove CONFIG_KUNIT_ALL_TESTS from the ``.kunitconfig`` as
|
||||
|
@ -41,17 +41,32 @@ properties:
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
Video port for MIPI DSI input
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes:
|
||||
description: array of physical DSI data lane indexes.
|
||||
minItems: 1
|
||||
items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
- const: 3
|
||||
- const: 4
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Video port for MIPI DPI output (panel or connector).
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
required:
|
||||
|
@ -38,6 +38,9 @@ properties:
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
|
@ -0,0 +1,117 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/bridge/lontium,lt9211.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Lontium LT9211 DSI/LVDS/DPI to DSI/LVDS/DPI bridge.
|
||||
|
||||
maintainers:
|
||||
- Marek Vasut <marex@denx.de>
|
||||
|
||||
description: |
|
||||
The LT9211 are bridge devices which convert Single/Dual-Link DSI/LVDS
|
||||
or Single DPI to Single/Dual-Link DSI/LVDS or Single DPI.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- lontium,lt9211
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
description: GPIO connected to active high RESET pin.
|
||||
|
||||
vccio-supply:
|
||||
description: Regulator for 1.8V IO power.
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Primary MIPI DSI port-1 for MIPI input or
|
||||
LVDS port-1 for LVDS input or DPI input.
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Additional MIPI port-2 for MIPI input or LVDS port-2
|
||||
for LVDS input. Used in combination with primary
|
||||
port-1 to drive higher resolution displays
|
||||
|
||||
port@2:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Primary MIPI DSI port-1 for MIPI output or
|
||||
LVDS port-1 for LVDS output or DPI output.
|
||||
|
||||
port@3:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Additional MIPI port-2 for MIPI output or LVDS port-2
|
||||
for LVDS output. Used in combination with primary
|
||||
port-1 to drive higher resolution displays.
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vccio-supply
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
hdmi-bridge@3b {
|
||||
compatible = "lontium,lt9211";
|
||||
reg = <0x3b>;
|
||||
|
||||
reset-gpios = <&tlmm 128 GPIO_ACTIVE_HIGH>;
|
||||
interrupts-extended = <&tlmm 84 IRQ_TYPE_EDGE_FALLING>;
|
||||
|
||||
vccio-supply = <<9211_1v8>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
endpoint {
|
||||
remote-endpoint = <&dsi0_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
|
||||
endpoint {
|
||||
remote-endpoint = <&panel_in_lvds>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -39,7 +39,6 @@ properties:
|
||||
Video port for MIPI DPI output (panel or connector).
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
required:
|
||||
|
@ -53,16 +53,32 @@ properties:
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: |
|
||||
DSI input port. The remote endpoint phandle should be a
|
||||
reference to a valid DSI output endpoint node
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes:
|
||||
description: array of physical DSI data lane indexes.
|
||||
minItems: 1
|
||||
items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
- const: 3
|
||||
- const: 4
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: |
|
||||
DPI input port. The remote endpoint phandle should be a
|
||||
reference to a valid DPI output endpoint node
|
||||
DPI input/output port. The remote endpoint phandle should be a
|
||||
reference to a valid DPI output or input endpoint node.
|
||||
|
||||
port@2:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
|
@ -0,0 +1,59 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/leadtek,ltk035c5444t.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Leadtek ltk035c5444t 3.5" (640x480 pixels) 24-bit IPS LCD panel
|
||||
|
||||
maintainers:
|
||||
- Paul Cercueil <paul@crapouillou.net>
|
||||
- Christophe Branchereau <cbranchereau@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: leadtek,ltk035c5444t
|
||||
|
||||
backlight: true
|
||||
port: true
|
||||
power-supply: true
|
||||
reg: true
|
||||
reset-gpios: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- power-supply
|
||||
- reset-gpios
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
panel@0 {
|
||||
compatible = "leadtek,ltk035c5444t";
|
||||
reg = <0>;
|
||||
|
||||
spi-3wire;
|
||||
spi-max-frequency = <3125000>;
|
||||
|
||||
reset-gpios = <&gpe 2 GPIO_ACTIVE_LOW>;
|
||||
|
||||
backlight = <&backlight>;
|
||||
power-supply = <&vcc>;
|
||||
|
||||
port {
|
||||
panel_input: endpoint {
|
||||
remote-endpoint = <&panel_output>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -83,6 +83,8 @@ properties:
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- width-mm
|
||||
- height-mm
|
||||
- panel-timing
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
@ -32,15 +32,13 @@ properties:
|
||||
- okaya,rh128128t
|
||||
- const: sitronix,st7715r
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 32000000
|
||||
|
||||
dc-gpios:
|
||||
maxItems: 1
|
||||
description: Display data/command selection (D/CX)
|
||||
|
||||
backlight: true
|
||||
reg: true
|
||||
spi-max-frequency: true
|
||||
reset-gpios: true
|
||||
rotation: true
|
||||
|
||||
@ -48,7 +46,6 @@ required:
|
||||
- compatible
|
||||
- reg
|
||||
- dc-gpios
|
||||
- reset-gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
@ -72,6 +69,7 @@ examples:
|
||||
dc-gpios = <&gpio 43 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio 80 GPIO_ACTIVE_HIGH>;
|
||||
rotation = <270>;
|
||||
backlight = <&backlight>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -12,11 +12,22 @@ maintainers:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- solomon,ssd1305fb-i2c
|
||||
- solomon,ssd1306fb-i2c
|
||||
- solomon,ssd1307fb-i2c
|
||||
- solomon,ssd1309fb-i2c
|
||||
oneOf:
|
||||
# Deprecated compatible strings
|
||||
- items:
|
||||
- enum:
|
||||
- solomon,ssd1305fb-i2c
|
||||
- solomon,ssd1306fb-i2c
|
||||
- solomon,ssd1307fb-i2c
|
||||
- solomon,ssd1309fb-i2c
|
||||
deprecated: true
|
||||
- items:
|
||||
- enum:
|
||||
- sinowealth,sh1106
|
||||
- solomon,ssd1305
|
||||
- solomon,ssd1306
|
||||
- solomon,ssd1307
|
||||
- solomon,ssd1309
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@ -27,9 +38,20 @@ properties:
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
# Only required for SPI
|
||||
dc-gpios:
|
||||
description:
|
||||
GPIO connected to the controller's D/C# (Data/Command) pin,
|
||||
that is needed for 4-wire SPI to tell the controller if the
|
||||
data sent is for a command register or the display data RAM
|
||||
maxItems: 1
|
||||
|
||||
vbat-supply:
|
||||
description: The supply for VBAT
|
||||
|
||||
# Only required for SPI
|
||||
spi-max-frequency: true
|
||||
|
||||
solomon,height:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 16
|
||||
@ -135,7 +157,21 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: solomon,ssd1305fb-i2c
|
||||
const: sinowealth,sh1106
|
||||
then:
|
||||
properties:
|
||||
solomon,dclk-div:
|
||||
default: 1
|
||||
solomon,dclk-frq:
|
||||
default: 5
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- solomon,ssd1305-i2c
|
||||
- solomon,ssd1305
|
||||
then:
|
||||
properties:
|
||||
solomon,dclk-div:
|
||||
@ -147,7 +183,9 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: solomon,ssd1306fb-i2c
|
||||
enum:
|
||||
- solomon,ssd1306-i2c
|
||||
- solomon,ssd1306
|
||||
then:
|
||||
properties:
|
||||
solomon,dclk-div:
|
||||
@ -159,7 +197,9 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: solomon,ssd1307fb-i2c
|
||||
enum:
|
||||
- solomon,ssd1307-i2c
|
||||
- solomon,ssd1307
|
||||
then:
|
||||
properties:
|
||||
solomon,dclk-div:
|
||||
@ -173,7 +213,9 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: solomon,ssd1309fb-i2c
|
||||
enum:
|
||||
- solomon,ssd1309-i2c
|
||||
- solomon,ssd1309
|
||||
then:
|
||||
properties:
|
||||
solomon,dclk-div:
|
||||
@ -189,15 +231,15 @@ examples:
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ssd1307: oled@3c {
|
||||
compatible = "solomon,ssd1307fb-i2c";
|
||||
ssd1307_i2c: oled@3c {
|
||||
compatible = "solomon,ssd1307";
|
||||
reg = <0x3c>;
|
||||
pwms = <&pwm 4 3000>;
|
||||
reset-gpios = <&gpio2 7>;
|
||||
};
|
||||
|
||||
ssd1306: oled@3d {
|
||||
compatible = "solomon,ssd1306fb-i2c";
|
||||
ssd1306_i2c: oled@3d {
|
||||
compatible = "solomon,ssd1306";
|
||||
reg = <0x3c>;
|
||||
pwms = <&pwm 4 3000>;
|
||||
reset-gpios = <&gpio2 7>;
|
||||
@ -207,3 +249,30 @@ examples:
|
||||
solomon,lookup-table = /bits/ 8 <0x3f 0x3f 0x3f 0x3f>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ssd1307_spi: oled@0 {
|
||||
compatible = "solomon,ssd1307";
|
||||
reg = <0x0>;
|
||||
pwms = <&pwm 4 3000>;
|
||||
reset-gpios = <&gpio2 7>;
|
||||
dc-gpios = <&gpio2 8>;
|
||||
spi-max-frequency = <10000000>;
|
||||
};
|
||||
|
||||
ssd1306_spi: oled@1 {
|
||||
compatible = "solomon,ssd1306";
|
||||
reg = <0x1>;
|
||||
pwms = <&pwm 4 3000>;
|
||||
reset-gpios = <&gpio2 7>;
|
||||
dc-gpios = <&gpio2 8>;
|
||||
spi-max-frequency = <10000000>;
|
||||
solomon,com-lrremap;
|
||||
solomon,com-invdir;
|
||||
solomon,com-offset = <32>;
|
||||
solomon,lookup-table = /bits/ 8 <0x3f 0x3f 0x3f 0x3f>;
|
||||
};
|
||||
};
|
||||
|
@ -106,6 +106,12 @@ properties:
|
||||
phy-mode:
|
||||
$ref: "#/properties/phy-connection-type"
|
||||
|
||||
pcs-handle:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Specifies a reference to a node representing a PCS PHY device on a MDIO
|
||||
bus to link with an external PHY (phy-handle) if exists.
|
||||
|
||||
phy-handle:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
|
@ -45,20 +45,3 @@ Optional properties:
|
||||
|
||||
In fiber mode, auto-negotiation is disabled and the PHY can only work in
|
||||
100base-fx (full and half duplex) modes.
|
||||
|
||||
- lan8814,ignore-ts: If present the PHY will not support timestamping.
|
||||
|
||||
This option acts as check whether Timestamping is supported by
|
||||
hardware or not. LAN8814 phy support hardware tmestamping.
|
||||
|
||||
- lan8814,latency_rx_10: Configures Latency value of phy in ingress at 10 Mbps.
|
||||
|
||||
- lan8814,latency_tx_10: Configures Latency value of phy in egress at 10 Mbps.
|
||||
|
||||
- lan8814,latency_rx_100: Configures Latency value of phy in ingress at 100 Mbps.
|
||||
|
||||
- lan8814,latency_tx_100: Configures Latency value of phy in egress at 100 Mbps.
|
||||
|
||||
- lan8814,latency_rx_1000: Configures Latency value of phy in ingress at 1000 Mbps.
|
||||
|
||||
- lan8814,latency_tx_1000: Configures Latency value of phy in egress at 1000 Mbps.
|
||||
|
@ -26,7 +26,8 @@ Required properties:
|
||||
specified, the TX/RX DMA interrupts should be on that node
|
||||
instead, and only the Ethernet core interrupt is optionally
|
||||
specified here.
|
||||
- phy-handle : Should point to the external phy device.
|
||||
- phy-handle : Should point to the external phy device if exists. Pointing
|
||||
this to the PCS/PMA PHY is deprecated and should be avoided.
|
||||
See ethernet.txt file in the same directory.
|
||||
- xlnx,rxmem : Set to allocated memory buffer for Rx/Tx in the hardware
|
||||
|
||||
@ -68,6 +69,11 @@ Optional properties:
|
||||
required through the core's MDIO interface (i.e. always,
|
||||
unless the PHY is accessed through a different bus).
|
||||
|
||||
- pcs-handle: Phandle to the internal PCS/PMA PHY in SGMII or 1000Base-X
|
||||
modes, where "pcs-handle" should be used to point
|
||||
to the PCS/PMA PHY, and "phy-handle" should point to an
|
||||
external PHY if exists.
|
||||
|
||||
Example:
|
||||
axi_ethernet_eth: ethernet@40c00000 {
|
||||
compatible = "xlnx,axi-ethernet-1.00.a";
|
||||
|
@ -1130,6 +1130,8 @@ patternProperties:
|
||||
description: Sinlinx Electronics Technology Co., LTD
|
||||
"^sinovoip,.*":
|
||||
description: SinoVoip Co., Ltd
|
||||
"^sinowealth,.*":
|
||||
description: SINO WEALTH Electronic Ltd.
|
||||
"^sipeed,.*":
|
||||
description: Shenzhen Sipeed Technology Co., Ltd.
|
||||
"^sirf,.*":
|
||||
|
@ -185,6 +185,12 @@ DMA Fence Chain
|
||||
.. kernel-doc:: include/linux/dma-fence-chain.h
|
||||
:internal:
|
||||
|
||||
DMA Fence unwrap
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. kernel-doc:: include/linux/dma-fence-unwrap.h
|
||||
:internal:
|
||||
|
||||
DMA Fence uABI/Sync File
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -466,6 +466,15 @@ DRM MM Range Allocator Function References
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_mm.c
|
||||
:export:
|
||||
|
||||
DRM Buddy Allocator
|
||||
===================
|
||||
|
||||
DRM Buddy Function References
|
||||
-----------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_buddy.c
|
||||
:export:
|
||||
|
||||
DRM Cache Handling and Fast WC memcpy()
|
||||
=======================================
|
||||
|
||||
|
@ -148,7 +148,9 @@ clients together with the legacy drmAuth authentication procedure.
|
||||
If a driver advertises render node support, DRM core will create a
|
||||
separate render node called renderD<num>. There will be one render node
|
||||
per device. No ioctls except PRIME-related ioctls will be allowed on
|
||||
this node. Especially GEM_OPEN will be explicitly prohibited. Render
|
||||
this node. Especially GEM_OPEN will be explicitly prohibited. For a
|
||||
complete list of driver-independent ioctls that can be used on render
|
||||
nodes, see the ioctls marked DRM_RENDER_ALLOW in drm_ioctl.c Render
|
||||
nodes are designed to avoid the buffer-leaks, which occur if clients
|
||||
guess the flink names or mmap offsets on the legacy interface.
|
||||
Additionally to this basic interface, drivers must mark their
|
||||
|
@ -10,21 +10,21 @@ in joining the effort.
|
||||
Design principles
|
||||
=================
|
||||
|
||||
The Distributed Switch Architecture is a subsystem which was primarily designed
|
||||
to support Marvell Ethernet switches (MV88E6xxx, a.k.a Linkstreet product line)
|
||||
using Linux, but has since evolved to support other vendors as well.
|
||||
The Distributed Switch Architecture subsystem was primarily designed to
|
||||
support Marvell Ethernet switches (MV88E6xxx, a.k.a. Link Street product
|
||||
line) using Linux, but has since evolved to support other vendors as well.
|
||||
|
||||
The original philosophy behind this design was to be able to use unmodified
|
||||
Linux tools such as bridge, iproute2, ifconfig to work transparently whether
|
||||
they configured/queried a switch port network device or a regular network
|
||||
device.
|
||||
|
||||
An Ethernet switch is typically comprised of multiple front-panel ports, and one
|
||||
or more CPU or management port. The DSA subsystem currently relies on the
|
||||
An Ethernet switch typically comprises multiple front-panel ports and one
|
||||
or more CPU or management ports. The DSA subsystem currently relies on the
|
||||
presence of a management port connected to an Ethernet controller capable of
|
||||
receiving Ethernet frames from the switch. This is a very common setup for all
|
||||
kinds of Ethernet switches found in Small Home and Office products: routers,
|
||||
gateways, or even top-of-the rack switches. This host Ethernet controller will
|
||||
gateways, or even top-of-rack switches. This host Ethernet controller will
|
||||
be later referred to as "master" and "cpu" in DSA terminology and code.
|
||||
|
||||
The D in DSA stands for Distributed, because the subsystem has been designed
|
||||
@ -33,14 +33,14 @@ using upstream and downstream Ethernet links between switches. These specific
|
||||
ports are referred to as "dsa" ports in DSA terminology and code. A collection
|
||||
of multiple switches connected to each other is called a "switch tree".
|
||||
|
||||
For each front-panel port, DSA will create specialized network devices which are
|
||||
For each front-panel port, DSA creates specialized network devices which are
|
||||
used as controlling and data-flowing endpoints for use by the Linux networking
|
||||
stack. These specialized network interfaces are referred to as "slave" network
|
||||
interfaces in DSA terminology and code.
|
||||
|
||||
The ideal case for using DSA is when an Ethernet switch supports a "switch tag"
|
||||
which is a hardware feature making the switch insert a specific tag for each
|
||||
Ethernet frames it received to/from specific ports to help the management
|
||||
Ethernet frame it receives to/from specific ports to help the management
|
||||
interface figure out:
|
||||
|
||||
- what port is this frame coming from
|
||||
@ -125,7 +125,7 @@ other switches from the same fabric, and in this case, the outermost switch
|
||||
ports must decapsulate the packet.
|
||||
|
||||
Note that in certain cases, it might be the case that the tagging format used
|
||||
by a leaf switch (not connected directly to the CPU) to not be the same as what
|
||||
by a leaf switch (not connected directly to the CPU) is not the same as what
|
||||
the network stack sees. This can be seen with Marvell switch trees, where the
|
||||
CPU port can be configured to use either the DSA or the Ethertype DSA (EDSA)
|
||||
format, but the DSA links are configured to use the shorter (without Ethertype)
|
||||
@ -270,21 +270,21 @@ These interfaces are specialized in order to:
|
||||
to/from specific switch ports
|
||||
- query the switch for ethtool operations: statistics, link state,
|
||||
Wake-on-LAN, register dumps...
|
||||
- external/internal PHY management: link, auto-negotiation etc.
|
||||
- manage external/internal PHY: link, auto-negotiation, etc.
|
||||
|
||||
These slave network devices have custom net_device_ops and ethtool_ops function
|
||||
pointers which allow DSA to introduce a level of layering between the networking
|
||||
stack/ethtool, and the switch driver implementation.
|
||||
stack/ethtool and the switch driver implementation.
|
||||
|
||||
Upon frame transmission from these slave network devices, DSA will look up which
|
||||
switch tagging protocol is currently registered with these network devices, and
|
||||
switch tagging protocol is currently registered with these network devices and
|
||||
invoke a specific transmit routine which takes care of adding the relevant
|
||||
switch tag in the Ethernet frames.
|
||||
|
||||
These frames are then queued for transmission using the master network device
|
||||
``ndo_start_xmit()`` function, since they contain the appropriate switch tag, the
|
||||
``ndo_start_xmit()`` function. Since they contain the appropriate switch tag, the
|
||||
Ethernet switch will be able to process these incoming frames from the
|
||||
management interface and delivers these frames to the physical switch port.
|
||||
management interface and deliver them to the physical switch port.
|
||||
|
||||
Graphical representation
|
||||
------------------------
|
||||
@ -330,9 +330,9 @@ MDIO reads/writes towards specific PHY addresses. In most MDIO-connected
|
||||
switches, these functions would utilize direct or indirect PHY addressing mode
|
||||
to return standard MII registers from the switch builtin PHYs, allowing the PHY
|
||||
library and/or to return link status, link partner pages, auto-negotiation
|
||||
results etc..
|
||||
results, etc.
|
||||
|
||||
For Ethernet switches which have both external and internal MDIO busses, the
|
||||
For Ethernet switches which have both external and internal MDIO buses, the
|
||||
slave MII bus can be utilized to mux/demux MDIO reads and writes towards either
|
||||
internal or external MDIO devices this switch might be connected to: internal
|
||||
PHYs, external PHYs, or even external switches.
|
||||
@ -349,7 +349,7 @@ DSA data structures are defined in ``include/net/dsa.h`` as well as
|
||||
table indication (when cascading switches)
|
||||
|
||||
- ``dsa_platform_data``: platform device configuration data which can reference
|
||||
a collection of dsa_chip_data structure if multiples switches are cascaded,
|
||||
a collection of dsa_chip_data structures if multiple switches are cascaded,
|
||||
the master network device this switch tree is attached to needs to be
|
||||
referenced
|
||||
|
||||
@ -426,7 +426,7 @@ logic basically looks like this:
|
||||
"phy-handle" property, if found, this PHY device is created and registered
|
||||
using ``of_phy_connect()``
|
||||
|
||||
- if Device Tree is used, and the PHY device is "fixed", that is, conforms to
|
||||
- if Device Tree is used and the PHY device is "fixed", that is, conforms to
|
||||
the definition of a non-MDIO managed PHY as defined in
|
||||
``Documentation/devicetree/bindings/net/fixed-link.txt``, the PHY is registered
|
||||
and connected transparently using the special fixed MDIO bus driver
|
||||
@ -481,7 +481,7 @@ Device Tree
|
||||
DSA features a standardized binding which is documented in
|
||||
``Documentation/devicetree/bindings/net/dsa/dsa.txt``. PHY/MDIO library helper
|
||||
functions such as ``of_get_phy_mode()``, ``of_phy_connect()`` are also used to query
|
||||
per-port PHY specific details: interface connection, MDIO bus location etc..
|
||||
per-port PHY specific details: interface connection, MDIO bus location, etc.
|
||||
|
||||
Driver development
|
||||
==================
|
||||
@ -509,7 +509,7 @@ Switch configuration
|
||||
|
||||
- ``setup``: setup function for the switch, this function is responsible for setting
|
||||
up the ``dsa_switch_ops`` private structure with all it needs: register maps,
|
||||
interrupts, mutexes, locks etc.. This function is also expected to properly
|
||||
interrupts, mutexes, locks, etc. This function is also expected to properly
|
||||
configure the switch to separate all network interfaces from each other, that
|
||||
is, they should be isolated by the switch hardware itself, typically by creating
|
||||
a Port-based VLAN ID for each port and allowing only the CPU port and the
|
||||
@ -526,13 +526,13 @@ PHY devices and link management
|
||||
- ``get_phy_flags``: Some switches are interfaced to various kinds of Ethernet PHYs,
|
||||
if the PHY library PHY driver needs to know about information it cannot obtain
|
||||
on its own (e.g.: coming from switch memory mapped registers), this function
|
||||
should return a 32-bits bitmask of "flags", that is private between the switch
|
||||
should return a 32-bit bitmask of "flags" that is private between the switch
|
||||
driver and the Ethernet PHY driver in ``drivers/net/phy/\*``.
|
||||
|
||||
- ``phy_read``: Function invoked by the DSA slave MDIO bus when attempting to read
|
||||
the switch port MDIO registers. If unavailable, return 0xffff for each read.
|
||||
For builtin switch Ethernet PHYs, this function should allow reading the link
|
||||
status, auto-negotiation results, link partner pages etc..
|
||||
status, auto-negotiation results, link partner pages, etc.
|
||||
|
||||
- ``phy_write``: Function invoked by the DSA slave MDIO bus when attempting to write
|
||||
to the switch port MDIO registers. If unavailable return a negative error
|
||||
@ -554,7 +554,7 @@ Ethtool operations
|
||||
------------------
|
||||
|
||||
- ``get_strings``: ethtool function used to query the driver's strings, will
|
||||
typically return statistics strings, private flags strings etc.
|
||||
typically return statistics strings, private flags strings, etc.
|
||||
|
||||
- ``get_ethtool_stats``: ethtool function used to query per-port statistics and
|
||||
return their values. DSA overlays slave network devices general statistics:
|
||||
@ -564,7 +564,7 @@ Ethtool operations
|
||||
- ``get_sset_count``: ethtool function used to query the number of statistics items
|
||||
|
||||
- ``get_wol``: ethtool function used to obtain Wake-on-LAN settings per-port, this
|
||||
function may, for certain implementations also query the master network device
|
||||
function may for certain implementations also query the master network device
|
||||
Wake-on-LAN settings if this interface needs to participate in Wake-on-LAN
|
||||
|
||||
- ``set_wol``: ethtool function used to configure Wake-on-LAN settings per-port,
|
||||
@ -607,14 +607,14 @@ Power management
|
||||
in a fully active state
|
||||
|
||||
- ``port_enable``: function invoked by the DSA slave network device ndo_open
|
||||
function when a port is administratively brought up, this function should be
|
||||
fully enabling a given switch port. DSA takes care of marking the port with
|
||||
function when a port is administratively brought up, this function should
|
||||
fully enable a given switch port. DSA takes care of marking the port with
|
||||
``BR_STATE_BLOCKING`` if the port is a bridge member, or ``BR_STATE_FORWARDING`` if it
|
||||
was not, and propagating these changes down to the hardware
|
||||
|
||||
- ``port_disable``: function invoked by the DSA slave network device ndo_close
|
||||
function when a port is administratively brought down, this function should be
|
||||
fully disabling a given switch port. DSA takes care of marking the port with
|
||||
function when a port is administratively brought down, this function should
|
||||
fully disable a given switch port. DSA takes care of marking the port with
|
||||
``BR_STATE_DISABLED`` and propagating changes to the hardware if this port is
|
||||
disabled while being a bridge member
|
||||
|
||||
@ -622,12 +622,12 @@ Bridge layer
|
||||
------------
|
||||
|
||||
- ``port_bridge_join``: bridge layer function invoked when a given switch port is
|
||||
added to a bridge, this function should be doing the necessary at the switch
|
||||
level to permit the joining port from being added to the relevant logical
|
||||
added to a bridge, this function should do what's necessary at the switch
|
||||
level to permit the joining port to be added to the relevant logical
|
||||
domain for it to ingress/egress traffic with other members of the bridge.
|
||||
|
||||
- ``port_bridge_leave``: bridge layer function invoked when a given switch port is
|
||||
removed from a bridge, this function should be doing the necessary at the
|
||||
removed from a bridge, this function should do what's necessary at the
|
||||
switch level to deny the leaving port from ingress/egress traffic from the
|
||||
remaining bridge members. When the port leaves the bridge, it should be aged
|
||||
out at the switch hardware for the switch to (re) learn MAC addresses behind
|
||||
@ -663,7 +663,7 @@ Bridge layer
|
||||
point for drivers that need to configure the hardware for enabling this
|
||||
feature.
|
||||
|
||||
- ``port_bridge_tx_fwd_unoffload``: bridge layer function invoken when a driver
|
||||
- ``port_bridge_tx_fwd_unoffload``: bridge layer function invoked when a driver
|
||||
leaves a bridge port which had the TX forwarding offload feature enabled.
|
||||
|
||||
Bridge VLAN filtering
|
||||
|
29
MAINTAINERS
29
MAINTAINERS
@ -4791,6 +4791,7 @@ F: .clang-format
|
||||
CLANG/LLVM BUILD SUPPORT
|
||||
M: Nathan Chancellor <nathan@kernel.org>
|
||||
M: Nick Desaulniers <ndesaulniers@google.com>
|
||||
R: Tom Rix <trix@redhat.com>
|
||||
L: llvm@lists.linux.dev
|
||||
S: Supported
|
||||
W: https://clangbuiltlinux.github.io/
|
||||
@ -5715,7 +5716,7 @@ W: http://lanana.org/docs/device-list/index.html
|
||||
|
||||
DEVICE RESOURCE MANAGEMENT HELPERS
|
||||
M: Hans de Goede <hdegoede@redhat.com>
|
||||
R: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||
R: Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
S: Maintained
|
||||
F: include/linux/devm-helpers.h
|
||||
|
||||
@ -6307,6 +6308,11 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino.yaml
|
||||
F: drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
|
||||
|
||||
DRM DRIVER FOR PARADE PS8640 BRIDGE CHIP
|
||||
R: Douglas Anderson <dianders@chromium.org>
|
||||
F: Documentation/devicetree/bindings/display/bridge/ps8640.yaml
|
||||
F: drivers/gpu/drm/bridge/parade-ps8640.c
|
||||
|
||||
DRM DRIVER FOR PERVASIVE DISPLAYS REPAPER PANELS
|
||||
M: Noralf Trønnes <noralf@tronnes.org>
|
||||
S: Maintained
|
||||
@ -6420,6 +6426,11 @@ DRM DRIVER FOR TDFX VIDEO CARDS
|
||||
S: Orphan / Obsolete
|
||||
F: drivers/gpu/drm/tdfx/
|
||||
|
||||
DRM DRIVER FOR TI SN65DSI86 BRIDGE CHIP
|
||||
R: Douglas Anderson <dianders@chromium.org>
|
||||
F: Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.yaml
|
||||
F: drivers/gpu/drm/bridge/ti-sn65dsi86.c
|
||||
|
||||
DRM DRIVER FOR TPO TPG110 PANELS
|
||||
M: Linus Walleij <linus.walleij@linaro.org>
|
||||
S: Maintained
|
||||
@ -6539,6 +6550,7 @@ R: Jonas Karlman <jonas@kwiboo.se>
|
||||
R: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
S: Maintained
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
F: Documentation/devicetree/bindings/display/bridge/
|
||||
F: drivers/gpu/drm/bridge/
|
||||
|
||||
DRM DRIVERS FOR EXYNOS
|
||||
@ -8675,7 +8687,6 @@ F: include/linux/cciss*.h
|
||||
F: include/uapi/linux/cciss*.h
|
||||
|
||||
HFI1 DRIVER
|
||||
M: Mike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
|
||||
M: Dennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
|
||||
L: linux-rdma@vger.kernel.org
|
||||
S: Supported
|
||||
@ -9598,6 +9609,7 @@ F: drivers/iio/pressure/dps310.c
|
||||
|
||||
INFINIBAND SUBSYSTEM
|
||||
M: Jason Gunthorpe <jgg@nvidia.com>
|
||||
M: Leon Romanovsky <leonro@nvidia.com>
|
||||
L: linux-rdma@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://github.com/linux-rdma/rdma-core
|
||||
@ -11208,7 +11220,7 @@ F: scripts/spdxcheck.py
|
||||
|
||||
LINEAR RANGES HELPERS
|
||||
M: Mark Brown <broonie@kernel.org>
|
||||
R: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||
R: Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
F: lib/linear_ranges.c
|
||||
F: lib/test_linear_ranges.c
|
||||
F: include/linux/linear_range.h
|
||||
@ -14656,7 +14668,6 @@ F: drivers/rtc/rtc-optee.c
|
||||
|
||||
OPA-VNIC DRIVER
|
||||
M: Dennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
|
||||
M: Mike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
|
||||
L: linux-rdma@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/infiniband/ulp/opa_vnic
|
||||
@ -16098,7 +16109,6 @@ F: include/uapi/linux/qemu_fw_cfg.h
|
||||
|
||||
QIB DRIVER
|
||||
M: Dennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
|
||||
M: Mike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
|
||||
L: linux-rdma@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/infiniband/hw/qib/
|
||||
@ -16616,7 +16626,6 @@ F: drivers/net/ethernet/rdc/r6040.c
|
||||
|
||||
RDMAVT - RDMA verbs software
|
||||
M: Dennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
|
||||
M: Mike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
|
||||
L: linux-rdma@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/infiniband/sw/rdmavt
|
||||
@ -17011,8 +17020,7 @@ S: Odd Fixes
|
||||
F: drivers/tty/serial/rp2.*
|
||||
|
||||
ROHM BD99954 CHARGER IC
|
||||
R: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||
L: linux-power@fi.rohmeurope.com
|
||||
R: Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
S: Supported
|
||||
F: drivers/power/supply/bd99954-charger.c
|
||||
F: drivers/power/supply/bd99954-charger.h
|
||||
@ -17035,8 +17043,7 @@ F: drivers/regulator/bd9571mwv-regulator.c
|
||||
F: include/linux/mfd/bd9571mwv.h
|
||||
|
||||
ROHM POWER MANAGEMENT IC DEVICE DRIVERS
|
||||
R: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||
L: linux-power@fi.rohmeurope.com
|
||||
R: Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
S: Supported
|
||||
F: drivers/clk/clk-bd718x7.c
|
||||
F: drivers/gpio/gpio-bd71815.c
|
||||
@ -21118,7 +21125,7 @@ F: include/linux/regulator/
|
||||
K: regulator_get_optional
|
||||
|
||||
VOLTAGE AND CURRENT REGULATOR IRQ HELPERS
|
||||
R: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||
R: Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
F: drivers/regulator/irq_helpers.c
|
||||
|
||||
VRF
|
||||
|
2
Makefile
2
Makefile
@ -2,7 +2,7 @@
|
||||
VERSION = 5
|
||||
PATCHLEVEL = 18
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc1
|
||||
EXTRAVERSION = -rc2
|
||||
NAME = Superb Owl
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
@ -75,6 +75,7 @@
|
||||
#define ARM_CPU_PART_CORTEX_A77 0xD0D
|
||||
#define ARM_CPU_PART_NEOVERSE_V1 0xD40
|
||||
#define ARM_CPU_PART_CORTEX_A78 0xD41
|
||||
#define ARM_CPU_PART_CORTEX_A78AE 0xD42
|
||||
#define ARM_CPU_PART_CORTEX_X1 0xD44
|
||||
#define ARM_CPU_PART_CORTEX_A510 0xD46
|
||||
#define ARM_CPU_PART_CORTEX_A710 0xD47
|
||||
@ -130,6 +131,7 @@
|
||||
#define MIDR_CORTEX_A77 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77)
|
||||
#define MIDR_NEOVERSE_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V1)
|
||||
#define MIDR_CORTEX_A78 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78)
|
||||
#define MIDR_CORTEX_A78AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78AE)
|
||||
#define MIDR_CORTEX_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1)
|
||||
#define MIDR_CORTEX_A510 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A510)
|
||||
#define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710)
|
||||
|
@ -107,7 +107,7 @@
|
||||
isb // Make sure SRE is now set
|
||||
mrs_s x0, SYS_ICC_SRE_EL2 // Read SRE back,
|
||||
tbz x0, #0, .Lskip_gicv3_\@ // and check that it sticks
|
||||
msr_s SYS_ICH_HCR_EL2, xzr // Reset ICC_HCR_EL2 to defaults
|
||||
msr_s SYS_ICH_HCR_EL2, xzr // Reset ICH_HCR_EL2 to defaults
|
||||
.Lskip_gicv3_\@:
|
||||
.endm
|
||||
|
||||
|
@ -42,7 +42,7 @@ bool alternative_is_applied(u16 cpufeature)
|
||||
/*
|
||||
* Check if the target PC is within an alternative block.
|
||||
*/
|
||||
static bool branch_insn_requires_update(struct alt_instr *alt, unsigned long pc)
|
||||
static __always_inline bool branch_insn_requires_update(struct alt_instr *alt, unsigned long pc)
|
||||
{
|
||||
unsigned long replptr = (unsigned long)ALT_REPL_PTR(alt);
|
||||
return !(pc >= replptr && pc <= (replptr + alt->alt_len));
|
||||
@ -50,7 +50,7 @@ static bool branch_insn_requires_update(struct alt_instr *alt, unsigned long pc)
|
||||
|
||||
#define align_down(x, a) ((unsigned long)(x) & ~(((unsigned long)(a)) - 1))
|
||||
|
||||
static u32 get_alt_insn(struct alt_instr *alt, __le32 *insnptr, __le32 *altinsnptr)
|
||||
static __always_inline u32 get_alt_insn(struct alt_instr *alt, __le32 *insnptr, __le32 *altinsnptr)
|
||||
{
|
||||
u32 insn;
|
||||
|
||||
@ -95,7 +95,7 @@ static u32 get_alt_insn(struct alt_instr *alt, __le32 *insnptr, __le32 *altinsnp
|
||||
return insn;
|
||||
}
|
||||
|
||||
static void patch_alternative(struct alt_instr *alt,
|
||||
static noinstr void patch_alternative(struct alt_instr *alt,
|
||||
__le32 *origptr, __le32 *updptr, int nr_inst)
|
||||
{
|
||||
__le32 *replptr;
|
||||
|
@ -8,16 +8,9 @@
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/mte.h>
|
||||
|
||||
#ifndef VMA_ITERATOR
|
||||
#define VMA_ITERATOR(name, mm, addr) \
|
||||
struct mm_struct *name = mm
|
||||
#define for_each_vma(vmi, vma) \
|
||||
for (vma = vmi->mmap; vma; vma = vma->vm_next)
|
||||
#endif
|
||||
|
||||
#define for_each_mte_vma(vmi, vma) \
|
||||
#define for_each_mte_vma(tsk, vma) \
|
||||
if (system_supports_mte()) \
|
||||
for_each_vma(vmi, vma) \
|
||||
for (vma = tsk->mm->mmap; vma; vma = vma->vm_next) \
|
||||
if (vma->vm_flags & VM_MTE)
|
||||
|
||||
static unsigned long mte_vma_tag_dump_size(struct vm_area_struct *vma)
|
||||
@ -32,10 +25,11 @@ static unsigned long mte_vma_tag_dump_size(struct vm_area_struct *vma)
|
||||
static int mte_dump_tag_range(struct coredump_params *cprm,
|
||||
unsigned long start, unsigned long end)
|
||||
{
|
||||
int ret = 1;
|
||||
unsigned long addr;
|
||||
void *tags = NULL;
|
||||
|
||||
for (addr = start; addr < end; addr += PAGE_SIZE) {
|
||||
char tags[MTE_PAGE_TAG_STORAGE];
|
||||
struct page *page = get_dump_page(addr);
|
||||
|
||||
/*
|
||||
@ -59,22 +53,36 @@ static int mte_dump_tag_range(struct coredump_params *cprm,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!tags) {
|
||||
tags = mte_allocate_tag_storage();
|
||||
if (!tags) {
|
||||
put_page(page);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mte_save_page_tags(page_address(page), tags);
|
||||
put_page(page);
|
||||
if (!dump_emit(cprm, tags, MTE_PAGE_TAG_STORAGE))
|
||||
return 0;
|
||||
if (!dump_emit(cprm, tags, MTE_PAGE_TAG_STORAGE)) {
|
||||
mte_free_tag_storage(tags);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
if (tags)
|
||||
mte_free_tag_storage(tags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Elf_Half elf_core_extra_phdrs(void)
|
||||
{
|
||||
struct vm_area_struct *vma;
|
||||
int vma_count = 0;
|
||||
VMA_ITERATOR(vmi, current->mm, 0);
|
||||
|
||||
for_each_mte_vma(vmi, vma)
|
||||
for_each_mte_vma(current, vma)
|
||||
vma_count++;
|
||||
|
||||
return vma_count;
|
||||
@ -83,9 +91,8 @@ Elf_Half elf_core_extra_phdrs(void)
|
||||
int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
|
||||
{
|
||||
struct vm_area_struct *vma;
|
||||
VMA_ITERATOR(vmi, current->mm, 0);
|
||||
|
||||
for_each_mte_vma(vmi, vma) {
|
||||
for_each_mte_vma(current, vma) {
|
||||
struct elf_phdr phdr;
|
||||
|
||||
phdr.p_type = PT_ARM_MEMTAG_MTE;
|
||||
@ -109,9 +116,8 @@ size_t elf_core_extra_data_size(void)
|
||||
{
|
||||
struct vm_area_struct *vma;
|
||||
size_t data_size = 0;
|
||||
VMA_ITERATOR(vmi, current->mm, 0);
|
||||
|
||||
for_each_mte_vma(vmi, vma)
|
||||
for_each_mte_vma(current, vma)
|
||||
data_size += mte_vma_tag_dump_size(vma);
|
||||
|
||||
return data_size;
|
||||
@ -120,9 +126,8 @@ size_t elf_core_extra_data_size(void)
|
||||
int elf_core_write_extra_data(struct coredump_params *cprm)
|
||||
{
|
||||
struct vm_area_struct *vma;
|
||||
VMA_ITERATOR(vmi, current->mm, 0);
|
||||
|
||||
for_each_mte_vma(vmi, vma) {
|
||||
for_each_mte_vma(current, vma) {
|
||||
if (vma->vm_flags & VM_DONTDUMP)
|
||||
continue;
|
||||
|
||||
|
@ -701,7 +701,7 @@ NOKPROBE_SYMBOL(breakpoint_handler);
|
||||
* addresses. There is no straight-forward way, short of disassembling the
|
||||
* offending instruction, to map that address back to the watchpoint. This
|
||||
* function computes the distance of the memory access from the watchpoint as a
|
||||
* heuristic for the likelyhood that a given access triggered the watchpoint.
|
||||
* heuristic for the likelihood that a given access triggered the watchpoint.
|
||||
*
|
||||
* See Section D2.10.5 "Determining the memory location that caused a Watchpoint
|
||||
* exception" of ARMv8 Architecture Reference Manual for details.
|
||||
|
@ -220,7 +220,7 @@ static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num,
|
||||
* increasing the section's alignment so that the
|
||||
* resulting address of this instruction is guaranteed
|
||||
* to equal the offset in that particular bit (as well
|
||||
* as all less signficant bits). This ensures that the
|
||||
* as all less significant bits). This ensures that the
|
||||
* address modulo 4 KB != 0xfff8 or 0xfffc (which would
|
||||
* have all ones in bits [11:3])
|
||||
*/
|
||||
|
@ -117,8 +117,8 @@ static int __kprobes aarch64_insn_patch_text_cb(void *arg)
|
||||
int i, ret = 0;
|
||||
struct aarch64_insn_patch *pp = arg;
|
||||
|
||||
/* The first CPU becomes master */
|
||||
if (atomic_inc_return(&pp->cpu_count) == 1) {
|
||||
/* The last CPU becomes master */
|
||||
if (atomic_inc_return(&pp->cpu_count) == num_online_cpus()) {
|
||||
for (i = 0; ret == 0 && i < pp->insn_cnt; i++)
|
||||
ret = aarch64_insn_patch_text_nosync(pp->text_addrs[i],
|
||||
pp->new_insns[i]);
|
||||
|
@ -853,6 +853,7 @@ u8 spectre_bhb_loop_affected(int scope)
|
||||
if (scope == SCOPE_LOCAL_CPU) {
|
||||
static const struct midr_range spectre_bhb_k32_list[] = {
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A78),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A78AE),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A78C),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_X1),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
|
||||
|
@ -234,6 +234,7 @@ asmlinkage notrace void secondary_start_kernel(void)
|
||||
* Log the CPU info before it is marked online and might get read.
|
||||
*/
|
||||
cpuinfo_store_cpu();
|
||||
store_cpu_topology(cpu);
|
||||
|
||||
/*
|
||||
* Enable GIC and timers.
|
||||
@ -242,7 +243,6 @@ asmlinkage notrace void secondary_start_kernel(void)
|
||||
|
||||
ipi_setup(cpu);
|
||||
|
||||
store_cpu_topology(cpu);
|
||||
numa_add_cpu(cpu);
|
||||
|
||||
/*
|
||||
|
@ -140,7 +140,7 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
|
||||
/*
|
||||
* Restore pstate flags. OS lock and mdscr have been already
|
||||
* restored, so from this point onwards, debugging is fully
|
||||
* renabled if it was enabled when core started shutdown.
|
||||
* reenabled if it was enabled when core started shutdown.
|
||||
*/
|
||||
local_daif_restore(flags);
|
||||
|
||||
|
@ -73,7 +73,7 @@ EXPORT_SYMBOL(memstart_addr);
|
||||
* In this scheme a comparatively quicker boot is observed.
|
||||
*
|
||||
* If ZONE_DMA configs are defined, crash kernel memory reservation
|
||||
* is delayed until DMA zone memory range size initilazation performed in
|
||||
* is delayed until DMA zone memory range size initialization performed in
|
||||
* zone_sizes_init(). The defer is necessary to steer clear of DMA zone
|
||||
* memory range to avoid overlap allocation. So crash kernel memory boundaries
|
||||
* are not known when mapping all bank memory ranges, which otherwise means
|
||||
@ -81,7 +81,7 @@ EXPORT_SYMBOL(memstart_addr);
|
||||
* so page-granularity mappings are created for the entire memory range.
|
||||
* Hence a slightly slower boot is observed.
|
||||
*
|
||||
* Note: Page-granularity mapppings are necessary for crash kernel memory
|
||||
* Note: Page-granularity mappings are necessary for crash kernel memory
|
||||
* range for shrinking its size via /sys/kernel/kexec_crash_size interface.
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_ZONE_DMA) || IS_ENABLED(CONFIG_ZONE_DMA32)
|
||||
|
@ -16,18 +16,6 @@
|
||||
#include <asm/ppc-opcode.h>
|
||||
#include <asm/pte-walk.h>
|
||||
|
||||
#ifdef CONFIG_PPC_PSERIES
|
||||
static inline bool kvmhv_on_pseries(void)
|
||||
{
|
||||
return !cpu_has_feature(CPU_FTR_HVMODE);
|
||||
}
|
||||
#else
|
||||
static inline bool kvmhv_on_pseries(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Structure for a nested guest, that is, for a guest that is managed by
|
||||
* one of our guests.
|
||||
|
@ -586,6 +586,18 @@ static inline bool kvm_hv_mode_active(void) { return false; }
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PPC_PSERIES
|
||||
static inline bool kvmhv_on_pseries(void)
|
||||
{
|
||||
return !cpu_has_feature(CPU_FTR_HVMODE);
|
||||
}
|
||||
#else
|
||||
static inline bool kvmhv_on_pseries(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KVM_XICS
|
||||
static inline int kvmppc_xics_enabled(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
|
@ -132,7 +132,11 @@ static inline bool pfn_valid(unsigned long pfn)
|
||||
#define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr))
|
||||
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
|
||||
|
||||
#define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr))
|
||||
#define virt_addr_valid(vaddr) ({ \
|
||||
unsigned long _addr = (unsigned long)vaddr; \
|
||||
_addr >= PAGE_OFFSET && _addr < (unsigned long)high_memory && \
|
||||
pfn_valid(virt_to_pfn(_addr)); \
|
||||
})
|
||||
|
||||
/*
|
||||
* On Book-E parts we need __va to parse the device tree and we can't
|
||||
|
@ -28,11 +28,13 @@ void setup_panic(void);
|
||||
#define ARCH_PANIC_TIMEOUT 180
|
||||
|
||||
#ifdef CONFIG_PPC_PSERIES
|
||||
extern bool pseries_reloc_on_exception(void);
|
||||
extern bool pseries_enable_reloc_on_exc(void);
|
||||
extern void pseries_disable_reloc_on_exc(void);
|
||||
extern void pseries_big_endian_exceptions(void);
|
||||
void __init pseries_little_endian_exceptions(void);
|
||||
#else
|
||||
static inline bool pseries_reloc_on_exception(void) { return false; }
|
||||
static inline bool pseries_enable_reloc_on_exc(void) { return false; }
|
||||
static inline void pseries_disable_reloc_on_exc(void) {}
|
||||
static inline void pseries_big_endian_exceptions(void) {}
|
||||
|
@ -24,5 +24,6 @@
|
||||
|
||||
#define ARCH_DEFINE_STATIC_CALL_TRAMP(name, func) __PPC_SCT(name, "b " #func)
|
||||
#define ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name) __PPC_SCT(name, "blr")
|
||||
#define ARCH_DEFINE_STATIC_CALL_RET0_TRAMP(name) __PPC_SCT(name, "b .+20")
|
||||
|
||||
#endif /* _ASM_POWERPC_STATIC_CALL_H */
|
||||
|
@ -809,6 +809,10 @@ __start_interrupts:
|
||||
* - MSR_EE|MSR_RI is clear (no reentrant exceptions)
|
||||
* - Standard kernel environment is set up (stack, paca, etc)
|
||||
*
|
||||
* KVM:
|
||||
* These interrupts do not elevate HV 0->1, so HV is not involved. PR KVM
|
||||
* ensures that FSCR[SCV] is disabled whenever it has to force AIL off.
|
||||
*
|
||||
* Call convention:
|
||||
*
|
||||
* syscall register convention is in Documentation/powerpc/syscall64-abi.rst
|
||||
|
@ -196,6 +196,34 @@ static void __init configure_exceptions(void)
|
||||
|
||||
/* Under a PAPR hypervisor, we need hypercalls */
|
||||
if (firmware_has_feature(FW_FEATURE_SET_MODE)) {
|
||||
/*
|
||||
* - PR KVM does not support AIL mode interrupts in the host
|
||||
* while a PR guest is running.
|
||||
*
|
||||
* - SCV system call interrupt vectors are only implemented for
|
||||
* AIL mode interrupts.
|
||||
*
|
||||
* - On pseries, AIL mode can only be enabled and disabled
|
||||
* system-wide so when a PR VM is created on a pseries host,
|
||||
* all CPUs of the host are set to AIL=0 mode.
|
||||
*
|
||||
* - Therefore host CPUs must not execute scv while a PR VM
|
||||
* exists.
|
||||
*
|
||||
* - SCV support can not be disabled dynamically because the
|
||||
* feature is advertised to host userspace. Disabling the
|
||||
* facility and emulating it would be possible but is not
|
||||
* implemented.
|
||||
*
|
||||
* - So SCV support is blanket disabled if PR KVM could possibly
|
||||
* run. That is, PR support compiled in, booting on pseries
|
||||
* with hash MMU.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_KVM_BOOK3S_PR_POSSIBLE) && !radix_enabled()) {
|
||||
init_task.thread.fscr &= ~FSCR_SCV;
|
||||
cur_cpu_spec->cpu_user_features2 &= ~PPC_FEATURE2_SCV;
|
||||
}
|
||||
|
||||
/* Enable AIL if possible */
|
||||
if (!pseries_enable_reloc_on_exc()) {
|
||||
init_task.thread.fscr &= ~FSCR_SCV;
|
||||
|
@ -112,12 +112,21 @@ config KVM_BOOK3S_64_PR
|
||||
guest in user mode (problem state) and emulating all
|
||||
privileged instructions and registers.
|
||||
|
||||
This is only available for hash MMU mode and only supports
|
||||
guests that use hash MMU mode.
|
||||
|
||||
This is not as fast as using hypervisor mode, but works on
|
||||
machines where hypervisor mode is not available or not usable,
|
||||
and can emulate processors that are different from the host
|
||||
processor, including emulating 32-bit processors on a 64-bit
|
||||
host.
|
||||
|
||||
Selecting this option will cause the SCV facility to be
|
||||
disabled when the kernel is booted on the pseries platform in
|
||||
hash MMU mode (regardless of PR VMs running). When any PR VMs
|
||||
are running, "AIL" mode is disabled which may slow interrupts
|
||||
and system calls on the host.
|
||||
|
||||
config KVM_BOOK3S_HV_EXIT_TIMING
|
||||
bool "Detailed timing for hypervisor real-mode code"
|
||||
depends on KVM_BOOK3S_HV_POSSIBLE && DEBUG_FS
|
||||
|
@ -414,10 +414,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_DAWR1)
|
||||
*/
|
||||
ld r10,HSTATE_SCRATCH0(r13)
|
||||
cmpwi r10,BOOK3S_INTERRUPT_MACHINE_CHECK
|
||||
beq machine_check_common
|
||||
beq .Lcall_machine_check_common
|
||||
|
||||
cmpwi r10,BOOK3S_INTERRUPT_SYSTEM_RESET
|
||||
beq system_reset_common
|
||||
beq .Lcall_system_reset_common
|
||||
|
||||
b .
|
||||
|
||||
.Lcall_machine_check_common:
|
||||
b machine_check_common
|
||||
|
||||
.Lcall_system_reset_common:
|
||||
b system_reset_common
|
||||
#endif
|
||||
|
@ -225,6 +225,13 @@ static void kvmppc_fast_vcpu_kick_hv(struct kvm_vcpu *vcpu)
|
||||
int cpu;
|
||||
struct rcuwait *waitp;
|
||||
|
||||
/*
|
||||
* rcuwait_wake_up contains smp_mb() which orders prior stores that
|
||||
* create pending work vs below loads of cpu fields. The other side
|
||||
* is the barrier in vcpu run that orders setting the cpu fields vs
|
||||
* testing for pending work.
|
||||
*/
|
||||
|
||||
waitp = kvm_arch_vcpu_get_wait(vcpu);
|
||||
if (rcuwait_wake_up(waitp))
|
||||
++vcpu->stat.generic.halt_wakeup;
|
||||
@ -1089,7 +1096,7 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
|
||||
break;
|
||||
}
|
||||
tvcpu->arch.prodded = 1;
|
||||
smp_mb();
|
||||
smp_mb(); /* This orders prodded store vs ceded load */
|
||||
if (tvcpu->arch.ceded)
|
||||
kvmppc_fast_vcpu_kick_hv(tvcpu);
|
||||
break;
|
||||
@ -3766,6 +3773,14 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
|
||||
pvc = core_info.vc[sub];
|
||||
pvc->pcpu = pcpu + thr;
|
||||
for_each_runnable_thread(i, vcpu, pvc) {
|
||||
/*
|
||||
* XXX: is kvmppc_start_thread called too late here?
|
||||
* It updates vcpu->cpu and vcpu->arch.thread_cpu
|
||||
* which are used by kvmppc_fast_vcpu_kick_hv(), but
|
||||
* kick is called after new exceptions become available
|
||||
* and exceptions are checked earlier than here, by
|
||||
* kvmppc_core_prepare_to_enter.
|
||||
*/
|
||||
kvmppc_start_thread(vcpu, pvc);
|
||||
kvmppc_create_dtl_entry(vcpu, pvc);
|
||||
trace_kvm_guest_enter(vcpu);
|
||||
@ -4487,6 +4502,21 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
|
||||
if (need_resched() || !kvm->arch.mmu_ready)
|
||||
goto out;
|
||||
|
||||
vcpu->cpu = pcpu;
|
||||
vcpu->arch.thread_cpu = pcpu;
|
||||
vc->pcpu = pcpu;
|
||||
local_paca->kvm_hstate.kvm_vcpu = vcpu;
|
||||
local_paca->kvm_hstate.ptid = 0;
|
||||
local_paca->kvm_hstate.fake_suspend = 0;
|
||||
|
||||
/*
|
||||
* Orders set cpu/thread_cpu vs testing for pending interrupts and
|
||||
* doorbells below. The other side is when these fields are set vs
|
||||
* kvmppc_fast_vcpu_kick_hv reading the cpu/thread_cpu fields to
|
||||
* kick a vCPU to notice the pending interrupt.
|
||||
*/
|
||||
smp_mb();
|
||||
|
||||
if (!nested) {
|
||||
kvmppc_core_prepare_to_enter(vcpu);
|
||||
if (test_bit(BOOK3S_IRQPRIO_EXTERNAL,
|
||||
@ -4506,13 +4536,6 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
|
||||
|
||||
tb = mftb();
|
||||
|
||||
vcpu->cpu = pcpu;
|
||||
vcpu->arch.thread_cpu = pcpu;
|
||||
vc->pcpu = pcpu;
|
||||
local_paca->kvm_hstate.kvm_vcpu = vcpu;
|
||||
local_paca->kvm_hstate.ptid = 0;
|
||||
local_paca->kvm_hstate.fake_suspend = 0;
|
||||
|
||||
__kvmppc_create_dtl_entry(vcpu, pcpu, tb + vc->tb_offset, 0);
|
||||
|
||||
trace_kvm_guest_enter(vcpu);
|
||||
@ -4614,6 +4637,8 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
|
||||
run->exit_reason = KVM_EXIT_INTR;
|
||||
vcpu->arch.ret = -EINTR;
|
||||
out:
|
||||
vcpu->cpu = -1;
|
||||
vcpu->arch.thread_cpu = -1;
|
||||
powerpc_local_irq_pmu_restore(flags);
|
||||
preempt_enable();
|
||||
goto done;
|
||||
|
@ -137,12 +137,15 @@ static void kvmppc_core_vcpu_load_pr(struct kvm_vcpu *vcpu, int cpu)
|
||||
svcpu->slb_max = to_book3s(vcpu)->slb_shadow_max;
|
||||
svcpu->in_use = 0;
|
||||
svcpu_put(svcpu);
|
||||
#endif
|
||||
|
||||
/* Disable AIL if supported */
|
||||
if (cpu_has_feature(CPU_FTR_HVMODE) &&
|
||||
cpu_has_feature(CPU_FTR_ARCH_207S))
|
||||
mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~LPCR_AIL);
|
||||
if (cpu_has_feature(CPU_FTR_HVMODE)) {
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_207S))
|
||||
mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~LPCR_AIL);
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_300) && (current->thread.fscr & FSCR_SCV))
|
||||
mtspr(SPRN_FSCR, mfspr(SPRN_FSCR) & ~FSCR_SCV);
|
||||
}
|
||||
#endif
|
||||
|
||||
vcpu->cpu = smp_processor_id();
|
||||
#ifdef CONFIG_PPC_BOOK3S_32
|
||||
@ -165,6 +168,14 @@ static void kvmppc_core_vcpu_put_pr(struct kvm_vcpu *vcpu)
|
||||
memcpy(to_book3s(vcpu)->slb_shadow, svcpu->slb, sizeof(svcpu->slb));
|
||||
to_book3s(vcpu)->slb_shadow_max = svcpu->slb_max;
|
||||
svcpu_put(svcpu);
|
||||
|
||||
/* Enable AIL if supported */
|
||||
if (cpu_has_feature(CPU_FTR_HVMODE)) {
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_207S))
|
||||
mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_AIL_3);
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_300) && (current->thread.fscr & FSCR_SCV))
|
||||
mtspr(SPRN_FSCR, mfspr(SPRN_FSCR) | FSCR_SCV);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (kvmppc_is_split_real(vcpu))
|
||||
@ -174,11 +185,6 @@ static void kvmppc_core_vcpu_put_pr(struct kvm_vcpu *vcpu)
|
||||
kvmppc_giveup_fac(vcpu, FSCR_TAR_LG);
|
||||
kvmppc_save_tm_pr(vcpu);
|
||||
|
||||
/* Enable AIL if supported */
|
||||
if (cpu_has_feature(CPU_FTR_HVMODE) &&
|
||||
cpu_has_feature(CPU_FTR_ARCH_207S))
|
||||
mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_AIL_3);
|
||||
|
||||
vcpu->cpu = -1;
|
||||
}
|
||||
|
||||
@ -1037,6 +1043,8 @@ static int kvmppc_handle_fac(struct kvm_vcpu *vcpu, ulong fac)
|
||||
|
||||
void kvmppc_set_fscr(struct kvm_vcpu *vcpu, u64 fscr)
|
||||
{
|
||||
if (fscr & FSCR_SCV)
|
||||
fscr &= ~FSCR_SCV; /* SCV must not be enabled */
|
||||
if ((vcpu->arch.fscr & FSCR_TAR) && !(fscr & FSCR_TAR)) {
|
||||
/* TAR got dropped, drop it in shadow too */
|
||||
kvmppc_giveup_fac(vcpu, FSCR_TAR_LG);
|
||||
|
@ -281,6 +281,22 @@ static int kvmppc_h_pr_logical_ci_store(struct kvm_vcpu *vcpu)
|
||||
return EMULATE_DONE;
|
||||
}
|
||||
|
||||
static int kvmppc_h_pr_set_mode(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long mflags = kvmppc_get_gpr(vcpu, 4);
|
||||
unsigned long resource = kvmppc_get_gpr(vcpu, 5);
|
||||
|
||||
if (resource == H_SET_MODE_RESOURCE_ADDR_TRANS_MODE) {
|
||||
/* KVM PR does not provide AIL!=0 to guests */
|
||||
if (mflags == 0)
|
||||
kvmppc_set_gpr(vcpu, 3, H_SUCCESS);
|
||||
else
|
||||
kvmppc_set_gpr(vcpu, 3, H_UNSUPPORTED_FLAG_START - 63);
|
||||
return EMULATE_DONE;
|
||||
}
|
||||
return EMULATE_FAIL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPAPR_TCE_IOMMU
|
||||
static int kvmppc_h_pr_put_tce(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
@ -384,6 +400,8 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)
|
||||
return kvmppc_h_pr_logical_ci_load(vcpu);
|
||||
case H_LOGICAL_CI_STORE:
|
||||
return kvmppc_h_pr_logical_ci_store(vcpu);
|
||||
case H_SET_MODE:
|
||||
return kvmppc_h_pr_set_mode(vcpu);
|
||||
case H_XIRR:
|
||||
case H_CPPR:
|
||||
case H_EOI:
|
||||
@ -421,6 +439,7 @@ int kvmppc_hcall_impl_pr(unsigned long cmd)
|
||||
case H_CEDE:
|
||||
case H_LOGICAL_CI_LOAD:
|
||||
case H_LOGICAL_CI_STORE:
|
||||
case H_SET_MODE:
|
||||
#ifdef CONFIG_KVM_XICS
|
||||
case H_XIRR:
|
||||
case H_CPPR:
|
||||
@ -447,6 +466,7 @@ static unsigned int default_hcall_list[] = {
|
||||
H_BULK_REMOVE,
|
||||
H_PUT_TCE,
|
||||
H_CEDE,
|
||||
H_SET_MODE,
|
||||
#ifdef CONFIG_KVM_XICS
|
||||
H_XIRR,
|
||||
H_CPPR,
|
||||
|
@ -705,6 +705,23 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
||||
r = 1;
|
||||
break;
|
||||
#endif
|
||||
case KVM_CAP_PPC_AIL_MODE_3:
|
||||
r = 0;
|
||||
/*
|
||||
* KVM PR, POWER7, and some POWER9s don't support AIL=3 mode.
|
||||
* The POWER9s can support it if the guest runs in hash mode,
|
||||
* but QEMU doesn't necessarily query the capability in time.
|
||||
*/
|
||||
if (hv_enabled) {
|
||||
if (kvmhv_on_pseries()) {
|
||||
if (pseries_reloc_on_exception())
|
||||
r = 1;
|
||||
} else if (cpu_has_feature(CPU_FTR_ARCH_207S) &&
|
||||
!cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG)) {
|
||||
r = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
r = 0;
|
||||
break;
|
||||
|
@ -255,7 +255,7 @@ void __init mem_init(void)
|
||||
#endif
|
||||
|
||||
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
|
||||
set_max_mapnr(max_low_pfn);
|
||||
set_max_mapnr(max_pfn);
|
||||
|
||||
kasan_late_init();
|
||||
|
||||
|
@ -1436,7 +1436,7 @@ int find_and_online_cpu_nid(int cpu)
|
||||
if (new_nid < 0 || !node_possible(new_nid))
|
||||
new_nid = first_online_node;
|
||||
|
||||
if (NODE_DATA(new_nid) == NULL) {
|
||||
if (!node_online(new_nid)) {
|
||||
#ifdef CONFIG_MEMORY_HOTPLUG
|
||||
/*
|
||||
* Need to ensure that NODE_DATA is initialized for a node from
|
||||
|
@ -353,6 +353,14 @@ static void pseries_lpar_idle(void)
|
||||
pseries_idle_epilog();
|
||||
}
|
||||
|
||||
static bool pseries_reloc_on_exception_enabled;
|
||||
|
||||
bool pseries_reloc_on_exception(void)
|
||||
{
|
||||
return pseries_reloc_on_exception_enabled;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pseries_reloc_on_exception);
|
||||
|
||||
/*
|
||||
* Enable relocation on during exceptions. This has partition wide scope and
|
||||
* may take a while to complete, if it takes longer than one second we will
|
||||
@ -377,6 +385,7 @@ bool pseries_enable_reloc_on_exc(void)
|
||||
" on exceptions: %ld\n", rc);
|
||||
return false;
|
||||
}
|
||||
pseries_reloc_on_exception_enabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -404,7 +413,9 @@ void pseries_disable_reloc_on_exc(void)
|
||||
break;
|
||||
mdelay(get_longbusy_msecs(rc));
|
||||
}
|
||||
if (rc != H_SUCCESS)
|
||||
if (rc == H_SUCCESS)
|
||||
pseries_reloc_on_exception_enabled = false;
|
||||
else
|
||||
pr_warn("Warning: Failed to disable relocation on exceptions: %ld\n",
|
||||
rc);
|
||||
}
|
||||
|
@ -99,6 +99,7 @@ static struct attribute *vas_def_capab_attrs[] = {
|
||||
&nr_used_credits_attribute.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(vas_def_capab);
|
||||
|
||||
static struct attribute *vas_qos_capab_attrs[] = {
|
||||
&nr_total_credits_attribute.attr,
|
||||
@ -106,6 +107,7 @@ static struct attribute *vas_qos_capab_attrs[] = {
|
||||
&update_total_credits_attribute.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(vas_qos_capab);
|
||||
|
||||
static ssize_t vas_type_show(struct kobject *kobj, struct attribute *attr,
|
||||
char *buf)
|
||||
@ -154,13 +156,13 @@ static const struct sysfs_ops vas_sysfs_ops = {
|
||||
static struct kobj_type vas_def_attr_type = {
|
||||
.release = vas_type_release,
|
||||
.sysfs_ops = &vas_sysfs_ops,
|
||||
.default_attrs = vas_def_capab_attrs,
|
||||
.default_groups = vas_def_capab_groups,
|
||||
};
|
||||
|
||||
static struct kobj_type vas_qos_attr_type = {
|
||||
.release = vas_type_release,
|
||||
.sysfs_ops = &vas_sysfs_ops,
|
||||
.default_attrs = vas_qos_capab_attrs,
|
||||
.default_groups = vas_qos_capab_groups,
|
||||
};
|
||||
|
||||
static char *vas_caps_kobj_name(struct vas_caps_entry *centry,
|
||||
|
@ -940,6 +940,12 @@ config GART_IOMMU
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config BOOT_VESA_SUPPORT
|
||||
bool
|
||||
help
|
||||
If true, at least one selected framebuffer driver can take advantage
|
||||
of VESA video modes set at an early boot stage via the vga= parameter.
|
||||
|
||||
config MAXSMP
|
||||
bool "Enable Maximum number of SMP Processors and NUMA Nodes"
|
||||
depends on X86_64 && SMP && DEBUG_KERNEL
|
||||
|
@ -83,7 +83,7 @@ static int vesa_probe(void)
|
||||
(vminfo.memory_layout == 4 ||
|
||||
vminfo.memory_layout == 6) &&
|
||||
vminfo.memory_planes == 1) {
|
||||
#ifdef CONFIG_FB_BOOT_VESA_SUPPORT
|
||||
#ifdef CONFIG_BOOT_VESA_SUPPORT
|
||||
/* Graphics mode, color, linear frame buffer
|
||||
supported. Only register the mode if
|
||||
if framebuffer is configured, however,
|
||||
@ -121,7 +121,7 @@ static int vesa_set_mode(struct mode_info *mode)
|
||||
if ((vminfo.mode_attr & 0x15) == 0x05) {
|
||||
/* It's a supported text mode */
|
||||
is_graphic = 0;
|
||||
#ifdef CONFIG_FB_BOOT_VESA_SUPPORT
|
||||
#ifdef CONFIG_BOOT_VESA_SUPPORT
|
||||
} else if ((vminfo.mode_attr & 0x99) == 0x99) {
|
||||
/* It's a graphics mode with linear frame buffer */
|
||||
is_graphic = 1;
|
||||
|
@ -302,7 +302,7 @@ static struct extra_reg intel_spr_extra_regs[] __read_mostly = {
|
||||
INTEL_UEVENT_EXTRA_REG(0x012a, MSR_OFFCORE_RSP_0, 0x3fffffffffull, RSP_0),
|
||||
INTEL_UEVENT_EXTRA_REG(0x012b, MSR_OFFCORE_RSP_1, 0x3fffffffffull, RSP_1),
|
||||
INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd),
|
||||
INTEL_UEVENT_EXTRA_REG(0x01c6, MSR_PEBS_FRONTEND, 0x7fff17, FE),
|
||||
INTEL_UEVENT_EXTRA_REG(0x01c6, MSR_PEBS_FRONTEND, 0x7fff1f, FE),
|
||||
INTEL_UEVENT_EXTRA_REG(0x40ad, MSR_PEBS_FRONTEND, 0x7, FE),
|
||||
INTEL_UEVENT_EXTRA_REG(0x04c2, MSR_PEBS_FRONTEND, 0x8, FE),
|
||||
EVENT_EXTRA_END
|
||||
@ -5536,7 +5536,11 @@ static void intel_pmu_check_event_constraints(struct event_constraint *event_con
|
||||
/* Disabled fixed counters which are not in CPUID */
|
||||
c->idxmsk64 &= intel_ctrl;
|
||||
|
||||
if (c->idxmsk64 != INTEL_PMC_MSK_FIXED_REF_CYCLES)
|
||||
/*
|
||||
* Don't extend the pseudo-encoding to the
|
||||
* generic counters
|
||||
*/
|
||||
if (!use_fixed_pseudo_encoding(c->code))
|
||||
c->idxmsk64 |= (1ULL << num_counters) - 1;
|
||||
}
|
||||
c->idxmsk64 &=
|
||||
@ -6212,6 +6216,7 @@ __init int intel_pmu_init(void)
|
||||
|
||||
case INTEL_FAM6_ALDERLAKE:
|
||||
case INTEL_FAM6_ALDERLAKE_L:
|
||||
case INTEL_FAM6_RAPTORLAKE:
|
||||
/*
|
||||
* Alder Lake has 2 types of CPU, core and atom.
|
||||
*
|
||||
|
@ -40,7 +40,7 @@
|
||||
* Model specific counters:
|
||||
* MSR_CORE_C1_RES: CORE C1 Residency Counter
|
||||
* perf code: 0x00
|
||||
* Available model: SLM,AMT,GLM,CNL,ICX,TNT,ADL
|
||||
* Available model: SLM,AMT,GLM,CNL,ICX,TNT,ADL,RPL
|
||||
* Scope: Core (each processor core has a MSR)
|
||||
* MSR_CORE_C3_RESIDENCY: CORE C3 Residency Counter
|
||||
* perf code: 0x01
|
||||
@ -51,49 +51,50 @@
|
||||
* perf code: 0x02
|
||||
* Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,
|
||||
* SKL,KNL,GLM,CNL,KBL,CML,ICL,ICX,
|
||||
* TGL,TNT,RKL,ADL
|
||||
* TGL,TNT,RKL,ADL,RPL
|
||||
* Scope: Core
|
||||
* MSR_CORE_C7_RESIDENCY: CORE C7 Residency Counter
|
||||
* perf code: 0x03
|
||||
* Available model: SNB,IVB,HSW,BDW,SKL,CNL,KBL,CML,
|
||||
* ICL,TGL,RKL,ADL
|
||||
* ICL,TGL,RKL,ADL,RPL
|
||||
* Scope: Core
|
||||
* MSR_PKG_C2_RESIDENCY: Package C2 Residency Counter.
|
||||
* perf code: 0x00
|
||||
* Available model: SNB,IVB,HSW,BDW,SKL,KNL,GLM,CNL,
|
||||
* KBL,CML,ICL,ICX,TGL,TNT,RKL,ADL
|
||||
* KBL,CML,ICL,ICX,TGL,TNT,RKL,ADL,
|
||||
* RPL
|
||||
* Scope: Package (physical package)
|
||||
* MSR_PKG_C3_RESIDENCY: Package C3 Residency Counter.
|
||||
* perf code: 0x01
|
||||
* Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,KNL,
|
||||
* GLM,CNL,KBL,CML,ICL,TGL,TNT,RKL,
|
||||
* ADL
|
||||
* ADL,RPL
|
||||
* Scope: Package (physical package)
|
||||
* MSR_PKG_C6_RESIDENCY: Package C6 Residency Counter.
|
||||
* perf code: 0x02
|
||||
* Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,
|
||||
* SKL,KNL,GLM,CNL,KBL,CML,ICL,ICX,
|
||||
* TGL,TNT,RKL,ADL
|
||||
* TGL,TNT,RKL,ADL,RPL
|
||||
* Scope: Package (physical package)
|
||||
* MSR_PKG_C7_RESIDENCY: Package C7 Residency Counter.
|
||||
* perf code: 0x03
|
||||
* Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,CNL,
|
||||
* KBL,CML,ICL,TGL,RKL,ADL
|
||||
* KBL,CML,ICL,TGL,RKL,ADL,RPL
|
||||
* Scope: Package (physical package)
|
||||
* MSR_PKG_C8_RESIDENCY: Package C8 Residency Counter.
|
||||
* perf code: 0x04
|
||||
* Available model: HSW ULT,KBL,CNL,CML,ICL,TGL,RKL,
|
||||
* ADL
|
||||
* ADL,RPL
|
||||
* Scope: Package (physical package)
|
||||
* MSR_PKG_C9_RESIDENCY: Package C9 Residency Counter.
|
||||
* perf code: 0x05
|
||||
* Available model: HSW ULT,KBL,CNL,CML,ICL,TGL,RKL,
|
||||
* ADL
|
||||
* ADL,RPL
|
||||
* Scope: Package (physical package)
|
||||
* MSR_PKG_C10_RESIDENCY: Package C10 Residency Counter.
|
||||
* perf code: 0x06
|
||||
* Available model: HSW ULT,KBL,GLM,CNL,CML,ICL,TGL,
|
||||
* TNT,RKL,ADL
|
||||
* TNT,RKL,ADL,RPL
|
||||
* Scope: Package (physical package)
|
||||
*
|
||||
*/
|
||||
@ -680,6 +681,7 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = {
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE, &icl_cstates),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, &adl_cstates),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, &adl_cstates),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, &adl_cstates),
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match);
|
||||
|
@ -1828,6 +1828,7 @@ static const struct x86_cpu_id intel_uncore_match[] __initconst = {
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE, &rkl_uncore_init),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, &adl_uncore_init),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, &adl_uncore_init),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, &adl_uncore_init),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, &spr_uncore_init),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_D, &snr_uncore_init),
|
||||
{},
|
||||
|
@ -79,6 +79,10 @@
|
||||
#define PCI_DEVICE_ID_INTEL_ADL_14_IMC 0x4650
|
||||
#define PCI_DEVICE_ID_INTEL_ADL_15_IMC 0x4668
|
||||
#define PCI_DEVICE_ID_INTEL_ADL_16_IMC 0x4670
|
||||
#define PCI_DEVICE_ID_INTEL_RPL_1_IMC 0xA700
|
||||
#define PCI_DEVICE_ID_INTEL_RPL_2_IMC 0xA702
|
||||
#define PCI_DEVICE_ID_INTEL_RPL_3_IMC 0xA706
|
||||
#define PCI_DEVICE_ID_INTEL_RPL_4_IMC 0xA709
|
||||
|
||||
/* SNB event control */
|
||||
#define SNB_UNC_CTL_EV_SEL_MASK 0x000000ff
|
||||
@ -1406,6 +1410,22 @@ static const struct pci_device_id tgl_uncore_pci_ids[] = {
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_16_IMC),
|
||||
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||
},
|
||||
{ /* IMC */
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_RPL_1_IMC),
|
||||
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||
},
|
||||
{ /* IMC */
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_RPL_2_IMC),
|
||||
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||
},
|
||||
{ /* IMC */
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_RPL_3_IMC),
|
||||
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||
},
|
||||
{ /* IMC */
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_RPL_4_IMC),
|
||||
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||
},
|
||||
{ /* end: all zeroes */ }
|
||||
};
|
||||
|
||||
|
@ -103,6 +103,7 @@ static bool test_intel(int idx, void *data)
|
||||
case INTEL_FAM6_ROCKETLAKE:
|
||||
case INTEL_FAM6_ALDERLAKE:
|
||||
case INTEL_FAM6_ALDERLAKE_L:
|
||||
case INTEL_FAM6_RAPTORLAKE:
|
||||
if (idx == PERF_MSR_SMI || idx == PERF_MSR_PPERF)
|
||||
return true;
|
||||
break;
|
||||
|
@ -154,24 +154,24 @@
|
||||
|
||||
# define DEFINE_EXTABLE_TYPE_REG \
|
||||
".macro extable_type_reg type:req reg:req\n" \
|
||||
".set found, 0\n" \
|
||||
".set regnr, 0\n" \
|
||||
".set .Lfound, 0\n" \
|
||||
".set .Lregnr, 0\n" \
|
||||
".irp rs,rax,rcx,rdx,rbx,rsp,rbp,rsi,rdi,r8,r9,r10,r11,r12,r13,r14,r15\n" \
|
||||
".ifc \\reg, %%\\rs\n" \
|
||||
".set found, found+1\n" \
|
||||
".long \\type + (regnr << 8)\n" \
|
||||
".set .Lfound, .Lfound+1\n" \
|
||||
".long \\type + (.Lregnr << 8)\n" \
|
||||
".endif\n" \
|
||||
".set regnr, regnr+1\n" \
|
||||
".set .Lregnr, .Lregnr+1\n" \
|
||||
".endr\n" \
|
||||
".set regnr, 0\n" \
|
||||
".set .Lregnr, 0\n" \
|
||||
".irp rs,eax,ecx,edx,ebx,esp,ebp,esi,edi,r8d,r9d,r10d,r11d,r12d,r13d,r14d,r15d\n" \
|
||||
".ifc \\reg, %%\\rs\n" \
|
||||
".set found, found+1\n" \
|
||||
".long \\type + (regnr << 8)\n" \
|
||||
".set .Lfound, .Lfound+1\n" \
|
||||
".long \\type + (.Lregnr << 8)\n" \
|
||||
".endif\n" \
|
||||
".set regnr, regnr+1\n" \
|
||||
".set .Lregnr, .Lregnr+1\n" \
|
||||
".endr\n" \
|
||||
".if (found != 1)\n" \
|
||||
".if (.Lfound != 1)\n" \
|
||||
".error \"extable_type_reg: bad register argument\"\n" \
|
||||
".endif\n" \
|
||||
".endm\n"
|
||||
|
@ -78,9 +78,9 @@ do { \
|
||||
*/
|
||||
#define __WARN_FLAGS(flags) \
|
||||
do { \
|
||||
__auto_type f = BUGFLAG_WARNING|(flags); \
|
||||
__auto_type __flags = BUGFLAG_WARNING|(flags); \
|
||||
instrumentation_begin(); \
|
||||
_BUG_FLAGS(ASM_UD2, f, ASM_REACHABLE); \
|
||||
_BUG_FLAGS(ASM_UD2, __flags, ASM_REACHABLE); \
|
||||
instrumentation_end(); \
|
||||
} while (0)
|
||||
|
||||
|
@ -12,14 +12,17 @@ int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
|
||||
/* Structs and defines for the X86 specific MSI message format */
|
||||
|
||||
typedef struct x86_msi_data {
|
||||
u32 vector : 8,
|
||||
delivery_mode : 3,
|
||||
dest_mode_logical : 1,
|
||||
reserved : 2,
|
||||
active_low : 1,
|
||||
is_level : 1;
|
||||
|
||||
u32 dmar_subhandle;
|
||||
union {
|
||||
struct {
|
||||
u32 vector : 8,
|
||||
delivery_mode : 3,
|
||||
dest_mode_logical : 1,
|
||||
reserved : 2,
|
||||
active_low : 1,
|
||||
is_level : 1;
|
||||
};
|
||||
u32 dmar_subhandle;
|
||||
};
|
||||
} __attribute__ ((packed)) arch_msi_msg_data_t;
|
||||
#define arch_msi_msg_data x86_msi_data
|
||||
|
||||
|
@ -38,9 +38,9 @@
|
||||
#define arch_raw_cpu_ptr(ptr) \
|
||||
({ \
|
||||
unsigned long tcp_ptr__; \
|
||||
asm volatile("add " __percpu_arg(1) ", %0" \
|
||||
: "=r" (tcp_ptr__) \
|
||||
: "m" (this_cpu_off), "0" (ptr)); \
|
||||
asm ("add " __percpu_arg(1) ", %0" \
|
||||
: "=r" (tcp_ptr__) \
|
||||
: "m" (this_cpu_off), "0" (ptr)); \
|
||||
(typeof(*(ptr)) __kernel __force *)tcp_ptr__; \
|
||||
})
|
||||
#else
|
||||
|
@ -241,6 +241,11 @@ struct x86_pmu_capability {
|
||||
#define INTEL_PMC_IDX_FIXED_SLOTS (INTEL_PMC_IDX_FIXED + 3)
|
||||
#define INTEL_PMC_MSK_FIXED_SLOTS (1ULL << INTEL_PMC_IDX_FIXED_SLOTS)
|
||||
|
||||
static inline bool use_fixed_pseudo_encoding(u64 code)
|
||||
{
|
||||
return !(code & 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* We model BTS tracing as another fixed-mode PMC.
|
||||
*
|
||||
|
@ -38,6 +38,8 @@
|
||||
#define ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name) \
|
||||
__ARCH_DEFINE_STATIC_CALL_TRAMP(name, "ret; int3; nop; nop; nop")
|
||||
|
||||
#define ARCH_DEFINE_STATIC_CALL_RET0_TRAMP(name) \
|
||||
ARCH_DEFINE_STATIC_CALL_TRAMP(name, __static_call_return0)
|
||||
|
||||
#define ARCH_ADD_TRAMP_KEY(name) \
|
||||
asm(".pushsection .static_call_tramp_key, \"a\" \n" \
|
||||
|
@ -12,10 +12,9 @@ enum insn_type {
|
||||
};
|
||||
|
||||
/*
|
||||
* data16 data16 xorq %rax, %rax - a single 5 byte instruction that clears %rax
|
||||
* The REX.W cancels the effect of any data16.
|
||||
* cs cs cs xorl %eax, %eax - a single 5 byte instruction that clears %[er]ax
|
||||
*/
|
||||
static const u8 xor5rax[] = { 0x66, 0x66, 0x48, 0x31, 0xc0 };
|
||||
static const u8 xor5rax[] = { 0x2e, 0x2e, 0x2e, 0x31, 0xc0 };
|
||||
|
||||
static const u8 retinsn[] = { RET_INSN_OPCODE, 0xcc, 0xcc, 0xcc, 0xcc };
|
||||
|
||||
|
@ -855,13 +855,11 @@ done:
|
||||
nr_invalidate);
|
||||
}
|
||||
|
||||
static bool tlb_is_not_lazy(int cpu)
|
||||
static bool tlb_is_not_lazy(int cpu, void *data)
|
||||
{
|
||||
return !per_cpu(cpu_tlbstate_shared.is_lazy, cpu);
|
||||
}
|
||||
|
||||
static DEFINE_PER_CPU(cpumask_t, flush_tlb_mask);
|
||||
|
||||
DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state_shared, cpu_tlbstate_shared);
|
||||
EXPORT_PER_CPU_SYMBOL(cpu_tlbstate_shared);
|
||||
|
||||
@ -890,36 +888,11 @@ STATIC_NOPV void native_flush_tlb_multi(const struct cpumask *cpumask,
|
||||
* up on the new contents of what used to be page tables, while
|
||||
* doing a speculative memory access.
|
||||
*/
|
||||
if (info->freed_tables) {
|
||||
if (info->freed_tables)
|
||||
on_each_cpu_mask(cpumask, flush_tlb_func, (void *)info, true);
|
||||
} else {
|
||||
/*
|
||||
* Although we could have used on_each_cpu_cond_mask(),
|
||||
* open-coding it has performance advantages, as it eliminates
|
||||
* the need for indirect calls or retpolines. In addition, it
|
||||
* allows to use a designated cpumask for evaluating the
|
||||
* condition, instead of allocating one.
|
||||
*
|
||||
* This code works under the assumption that there are no nested
|
||||
* TLB flushes, an assumption that is already made in
|
||||
* flush_tlb_mm_range().
|
||||
*
|
||||
* cond_cpumask is logically a stack-local variable, but it is
|
||||
* more efficient to have it off the stack and not to allocate
|
||||
* it on demand. Preemption is disabled and this code is
|
||||
* non-reentrant.
|
||||
*/
|
||||
struct cpumask *cond_cpumask = this_cpu_ptr(&flush_tlb_mask);
|
||||
int cpu;
|
||||
|
||||
cpumask_clear(cond_cpumask);
|
||||
|
||||
for_each_cpu(cpu, cpumask) {
|
||||
if (tlb_is_not_lazy(cpu))
|
||||
__cpumask_set_cpu(cpu, cond_cpumask);
|
||||
}
|
||||
on_each_cpu_mask(cond_cpumask, flush_tlb_func, (void *)info, true);
|
||||
}
|
||||
else
|
||||
on_each_cpu_cond_mask(tlb_is_not_lazy, flush_tlb_func,
|
||||
(void *)info, 1, cpumask);
|
||||
}
|
||||
|
||||
void flush_tlb_multi(const struct cpumask *cpumask,
|
||||
|
@ -412,6 +412,7 @@ static void emit_indirect_jump(u8 **pprog, int reg, u8 *ip)
|
||||
EMIT_LFENCE();
|
||||
EMIT2(0xFF, 0xE0 + reg);
|
||||
} else if (cpu_feature_enabled(X86_FEATURE_RETPOLINE)) {
|
||||
OPTIMIZER_HIDE_VAR(reg);
|
||||
emit_jump(&prog, &__x86_indirect_thunk_array[reg], ip);
|
||||
} else
|
||||
#endif
|
||||
|
@ -40,7 +40,8 @@ static void msr_save_context(struct saved_context *ctxt)
|
||||
struct saved_msr *end = msr + ctxt->saved_msrs.num;
|
||||
|
||||
while (msr < end) {
|
||||
msr->valid = !rdmsrl_safe(msr->info.msr_no, &msr->info.reg.q);
|
||||
if (msr->valid)
|
||||
rdmsrl(msr->info.msr_no, msr->info.reg.q);
|
||||
msr++;
|
||||
}
|
||||
}
|
||||
@ -424,8 +425,10 @@ static int msr_build_context(const u32 *msr_id, const int num)
|
||||
}
|
||||
|
||||
for (i = saved_msrs->num, j = 0; i < total_num; i++, j++) {
|
||||
u64 dummy;
|
||||
|
||||
msr_array[i].info.msr_no = msr_id[j];
|
||||
msr_array[i].valid = false;
|
||||
msr_array[i].valid = !rdmsrl_safe(msr_id[j], &dummy);
|
||||
msr_array[i].info.reg.q = 0;
|
||||
}
|
||||
saved_msrs->num = total_num;
|
||||
@ -500,10 +503,24 @@ static int pm_cpu_check(const struct x86_cpu_id *c)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pm_save_spec_msr(void)
|
||||
{
|
||||
u32 spec_msr_id[] = {
|
||||
MSR_IA32_SPEC_CTRL,
|
||||
MSR_IA32_TSX_CTRL,
|
||||
MSR_TSX_FORCE_ABORT,
|
||||
MSR_IA32_MCU_OPT_CTRL,
|
||||
MSR_AMD64_LS_CFG,
|
||||
};
|
||||
|
||||
msr_build_context(spec_msr_id, ARRAY_SIZE(spec_msr_id));
|
||||
}
|
||||
|
||||
static int pm_check_save_msr(void)
|
||||
{
|
||||
dmi_check_system(msr_save_dmi_table);
|
||||
pm_cpu_check(msr_save_cpu_table);
|
||||
pm_save_spec_msr();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -570,8 +570,7 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index)
|
||||
{
|
||||
struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
|
||||
|
||||
if (cx->type == ACPI_STATE_C3)
|
||||
ACPI_FLUSH_CPU_CACHE();
|
||||
ACPI_FLUSH_CPU_CACHE();
|
||||
|
||||
while (1) {
|
||||
|
||||
|
@ -588,19 +588,6 @@ static struct acpi_device *handle_to_device(acpi_handle handle,
|
||||
return adev;
|
||||
}
|
||||
|
||||
int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
|
||||
{
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
*device = handle_to_device(handle, NULL);
|
||||
if (!*device)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_bus_get_device);
|
||||
|
||||
/**
|
||||
* acpi_fetch_acpi_dev - Retrieve ACPI device object.
|
||||
* @handle: ACPI handle associated with the requested ACPI device object.
|
||||
|
@ -115,14 +115,16 @@ config SATA_AHCI
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SATA_LPM_POLICY
|
||||
config SATA_MOBILE_LPM_POLICY
|
||||
int "Default SATA Link Power Management policy for low power chipsets"
|
||||
range 0 4
|
||||
default 0
|
||||
depends on SATA_AHCI
|
||||
help
|
||||
Select the Default SATA Link Power Management (LPM) policy to use
|
||||
for chipsets / "South Bridges" designated as supporting low power.
|
||||
for chipsets / "South Bridges" supporting low-power modes. Such
|
||||
chipsets are typically found on most laptops but desktops and
|
||||
servers now also widely use chipsets supporting low power modes.
|
||||
|
||||
The value set has the following meanings:
|
||||
0 => Keep firmware settings
|
||||
|
@ -1595,7 +1595,7 @@ static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports,
|
||||
static void ahci_update_initial_lpm_policy(struct ata_port *ap,
|
||||
struct ahci_host_priv *hpriv)
|
||||
{
|
||||
int policy = CONFIG_SATA_LPM_POLICY;
|
||||
int policy = CONFIG_SATA_MOBILE_LPM_POLICY;
|
||||
|
||||
|
||||
/* Ignore processing for chipsets that don't use policy */
|
||||
|
@ -236,7 +236,7 @@ enum {
|
||||
AHCI_HFLAG_NO_WRITE_TO_RO = (1 << 24), /* don't write to read
|
||||
only registers */
|
||||
AHCI_HFLAG_USE_LPM_POLICY = (1 << 25), /* chipset that should use
|
||||
SATA_LPM_POLICY
|
||||
SATA_MOBILE_LPM_POLICY
|
||||
as default lpm_policy */
|
||||
AHCI_HFLAG_SUSPEND_PHYS = (1 << 26), /* handle PHYs during
|
||||
suspend/resume */
|
||||
|
@ -4014,6 +4014,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
|
||||
ATA_HORKAGE_ZERO_AFTER_TRIM, },
|
||||
{ "Crucial_CT*MX100*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
|
||||
ATA_HORKAGE_ZERO_AFTER_TRIM, },
|
||||
{ "Samsung SSD 840 EVO*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
|
||||
ATA_HORKAGE_NO_DMA_LOG |
|
||||
ATA_HORKAGE_ZERO_AFTER_TRIM, },
|
||||
{ "Samsung SSD 840*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
|
||||
ATA_HORKAGE_ZERO_AFTER_TRIM, },
|
||||
{ "Samsung SSD 850*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
|
||||
|
@ -1634,7 +1634,7 @@ EXPORT_SYMBOL_GPL(ata_sff_interrupt);
|
||||
|
||||
void ata_sff_lost_interrupt(struct ata_port *ap)
|
||||
{
|
||||
u8 status;
|
||||
u8 status = 0;
|
||||
struct ata_queued_cmd *qc;
|
||||
|
||||
/* Only one outstanding command per SFF channel */
|
||||
|
@ -137,7 +137,11 @@ struct sata_dwc_device {
|
||||
#endif
|
||||
};
|
||||
|
||||
#define SATA_DWC_QCMD_MAX 32
|
||||
/*
|
||||
* Allow one extra special slot for commands and DMA management
|
||||
* to account for libata internal commands.
|
||||
*/
|
||||
#define SATA_DWC_QCMD_MAX (ATA_MAX_QUEUE + 1)
|
||||
|
||||
struct sata_dwc_device_port {
|
||||
struct sata_dwc_device *hsdev;
|
||||
|
@ -1638,22 +1638,22 @@ struct sib_info {
|
||||
};
|
||||
void drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib);
|
||||
|
||||
extern void notify_resource_state(struct sk_buff *,
|
||||
extern int notify_resource_state(struct sk_buff *,
|
||||
unsigned int,
|
||||
struct drbd_resource *,
|
||||
struct resource_info *,
|
||||
enum drbd_notification_type);
|
||||
extern void notify_device_state(struct sk_buff *,
|
||||
extern int notify_device_state(struct sk_buff *,
|
||||
unsigned int,
|
||||
struct drbd_device *,
|
||||
struct device_info *,
|
||||
enum drbd_notification_type);
|
||||
extern void notify_connection_state(struct sk_buff *,
|
||||
extern int notify_connection_state(struct sk_buff *,
|
||||
unsigned int,
|
||||
struct drbd_connection *,
|
||||
struct connection_info *,
|
||||
enum drbd_notification_type);
|
||||
extern void notify_peer_device_state(struct sk_buff *,
|
||||
extern int notify_peer_device_state(struct sk_buff *,
|
||||
unsigned int,
|
||||
struct drbd_peer_device *,
|
||||
struct peer_device_info *,
|
||||
|
@ -2719,6 +2719,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
|
||||
sprintf(disk->disk_name, "drbd%d", minor);
|
||||
disk->private_data = device;
|
||||
|
||||
blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, disk->queue);
|
||||
blk_queue_write_cache(disk->queue, true, true);
|
||||
/* Setting the max_hw_sectors to an odd value of 8kibyte here
|
||||
This triggers a max_bio_size message upon first attach or connect */
|
||||
@ -2773,12 +2774,12 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
|
||||
|
||||
if (init_submitter(device)) {
|
||||
err = ERR_NOMEM;
|
||||
goto out_idr_remove_vol;
|
||||
goto out_idr_remove_from_resource;
|
||||
}
|
||||
|
||||
err = add_disk(disk);
|
||||
if (err)
|
||||
goto out_idr_remove_vol;
|
||||
goto out_idr_remove_from_resource;
|
||||
|
||||
/* inherit the connection state */
|
||||
device->state.conn = first_connection(resource)->cstate;
|
||||
@ -2792,8 +2793,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
|
||||
drbd_debugfs_device_add(device);
|
||||
return NO_ERROR;
|
||||
|
||||
out_idr_remove_vol:
|
||||
idr_remove(&connection->peer_devices, vnr);
|
||||
out_idr_remove_from_resource:
|
||||
for_each_connection(connection, resource) {
|
||||
peer_device = idr_remove(&connection->peer_devices, vnr);
|
||||
|
@ -4549,7 +4549,7 @@ static int nla_put_notification_header(struct sk_buff *msg,
|
||||
return drbd_notification_header_to_skb(msg, &nh, true);
|
||||
}
|
||||
|
||||
void notify_resource_state(struct sk_buff *skb,
|
||||
int notify_resource_state(struct sk_buff *skb,
|
||||
unsigned int seq,
|
||||
struct drbd_resource *resource,
|
||||
struct resource_info *resource_info,
|
||||
@ -4591,16 +4591,17 @@ void notify_resource_state(struct sk_buff *skb,
|
||||
if (err && err != -ESRCH)
|
||||
goto failed;
|
||||
}
|
||||
return;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_free(skb);
|
||||
failed:
|
||||
drbd_err(resource, "Error %d while broadcasting event. Event seq:%u\n",
|
||||
err, seq);
|
||||
return err;
|
||||
}
|
||||
|
||||
void notify_device_state(struct sk_buff *skb,
|
||||
int notify_device_state(struct sk_buff *skb,
|
||||
unsigned int seq,
|
||||
struct drbd_device *device,
|
||||
struct device_info *device_info,
|
||||
@ -4640,16 +4641,17 @@ void notify_device_state(struct sk_buff *skb,
|
||||
if (err && err != -ESRCH)
|
||||
goto failed;
|
||||
}
|
||||
return;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_free(skb);
|
||||
failed:
|
||||
drbd_err(device, "Error %d while broadcasting event. Event seq:%u\n",
|
||||
err, seq);
|
||||
return err;
|
||||
}
|
||||
|
||||
void notify_connection_state(struct sk_buff *skb,
|
||||
int notify_connection_state(struct sk_buff *skb,
|
||||
unsigned int seq,
|
||||
struct drbd_connection *connection,
|
||||
struct connection_info *connection_info,
|
||||
@ -4689,16 +4691,17 @@ void notify_connection_state(struct sk_buff *skb,
|
||||
if (err && err != -ESRCH)
|
||||
goto failed;
|
||||
}
|
||||
return;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_free(skb);
|
||||
failed:
|
||||
drbd_err(connection, "Error %d while broadcasting event. Event seq:%u\n",
|
||||
err, seq);
|
||||
return err;
|
||||
}
|
||||
|
||||
void notify_peer_device_state(struct sk_buff *skb,
|
||||
int notify_peer_device_state(struct sk_buff *skb,
|
||||
unsigned int seq,
|
||||
struct drbd_peer_device *peer_device,
|
||||
struct peer_device_info *peer_device_info,
|
||||
@ -4739,13 +4742,14 @@ void notify_peer_device_state(struct sk_buff *skb,
|
||||
if (err && err != -ESRCH)
|
||||
goto failed;
|
||||
}
|
||||
return;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_free(skb);
|
||||
failed:
|
||||
drbd_err(peer_device, "Error %d while broadcasting event. Event seq:%u\n",
|
||||
err, seq);
|
||||
return err;
|
||||
}
|
||||
|
||||
void notify_helper(enum drbd_notification_type type,
|
||||
@ -4796,7 +4800,7 @@ fail:
|
||||
err, seq);
|
||||
}
|
||||
|
||||
static void notify_initial_state_done(struct sk_buff *skb, unsigned int seq)
|
||||
static int notify_initial_state_done(struct sk_buff *skb, unsigned int seq)
|
||||
{
|
||||
struct drbd_genlmsghdr *dh;
|
||||
int err;
|
||||
@ -4810,11 +4814,12 @@ static void notify_initial_state_done(struct sk_buff *skb, unsigned int seq)
|
||||
if (nla_put_notification_header(skb, NOTIFY_EXISTS))
|
||||
goto nla_put_failure;
|
||||
genlmsg_end(skb, dh);
|
||||
return;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_free(skb);
|
||||
pr_err("Error %d sending event. Event seq:%u\n", err, seq);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void free_state_changes(struct list_head *list)
|
||||
@ -4841,6 +4846,7 @@ static int get_initial_state(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
unsigned int seq = cb->args[2];
|
||||
unsigned int n;
|
||||
enum drbd_notification_type flags = 0;
|
||||
int err = 0;
|
||||
|
||||
/* There is no need for taking notification_mutex here: it doesn't
|
||||
matter if the initial state events mix with later state chage
|
||||
@ -4849,32 +4855,32 @@ static int get_initial_state(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
|
||||
cb->args[5]--;
|
||||
if (cb->args[5] == 1) {
|
||||
notify_initial_state_done(skb, seq);
|
||||
err = notify_initial_state_done(skb, seq);
|
||||
goto out;
|
||||
}
|
||||
n = cb->args[4]++;
|
||||
if (cb->args[4] < cb->args[3])
|
||||
flags |= NOTIFY_CONTINUES;
|
||||
if (n < 1) {
|
||||
notify_resource_state_change(skb, seq, state_change->resource,
|
||||
err = notify_resource_state_change(skb, seq, state_change->resource,
|
||||
NOTIFY_EXISTS | flags);
|
||||
goto next;
|
||||
}
|
||||
n--;
|
||||
if (n < state_change->n_connections) {
|
||||
notify_connection_state_change(skb, seq, &state_change->connections[n],
|
||||
err = notify_connection_state_change(skb, seq, &state_change->connections[n],
|
||||
NOTIFY_EXISTS | flags);
|
||||
goto next;
|
||||
}
|
||||
n -= state_change->n_connections;
|
||||
if (n < state_change->n_devices) {
|
||||
notify_device_state_change(skb, seq, &state_change->devices[n],
|
||||
err = notify_device_state_change(skb, seq, &state_change->devices[n],
|
||||
NOTIFY_EXISTS | flags);
|
||||
goto next;
|
||||
}
|
||||
n -= state_change->n_devices;
|
||||
if (n < state_change->n_devices * state_change->n_connections) {
|
||||
notify_peer_device_state_change(skb, seq, &state_change->peer_devices[n],
|
||||
err = notify_peer_device_state_change(skb, seq, &state_change->peer_devices[n],
|
||||
NOTIFY_EXISTS | flags);
|
||||
goto next;
|
||||
}
|
||||
@ -4889,7 +4895,10 @@ next:
|
||||
cb->args[4] = 0;
|
||||
}
|
||||
out:
|
||||
return skb->len;
|
||||
if (err)
|
||||
return err;
|
||||
else
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
int drbd_adm_get_initial_state(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
|
@ -1537,7 +1537,7 @@ int drbd_bitmap_io_from_worker(struct drbd_device *device,
|
||||
return rv;
|
||||
}
|
||||
|
||||
void notify_resource_state_change(struct sk_buff *skb,
|
||||
int notify_resource_state_change(struct sk_buff *skb,
|
||||
unsigned int seq,
|
||||
struct drbd_resource_state_change *resource_state_change,
|
||||
enum drbd_notification_type type)
|
||||
@ -1550,10 +1550,10 @@ void notify_resource_state_change(struct sk_buff *skb,
|
||||
.res_susp_fen = resource_state_change->susp_fen[NEW],
|
||||
};
|
||||
|
||||
notify_resource_state(skb, seq, resource, &resource_info, type);
|
||||
return notify_resource_state(skb, seq, resource, &resource_info, type);
|
||||
}
|
||||
|
||||
void notify_connection_state_change(struct sk_buff *skb,
|
||||
int notify_connection_state_change(struct sk_buff *skb,
|
||||
unsigned int seq,
|
||||
struct drbd_connection_state_change *connection_state_change,
|
||||
enum drbd_notification_type type)
|
||||
@ -1564,10 +1564,10 @@ void notify_connection_state_change(struct sk_buff *skb,
|
||||
.conn_role = connection_state_change->peer_role[NEW],
|
||||
};
|
||||
|
||||
notify_connection_state(skb, seq, connection, &connection_info, type);
|
||||
return notify_connection_state(skb, seq, connection, &connection_info, type);
|
||||
}
|
||||
|
||||
void notify_device_state_change(struct sk_buff *skb,
|
||||
int notify_device_state_change(struct sk_buff *skb,
|
||||
unsigned int seq,
|
||||
struct drbd_device_state_change *device_state_change,
|
||||
enum drbd_notification_type type)
|
||||
@ -1577,10 +1577,10 @@ void notify_device_state_change(struct sk_buff *skb,
|
||||
.dev_disk_state = device_state_change->disk_state[NEW],
|
||||
};
|
||||
|
||||
notify_device_state(skb, seq, device, &device_info, type);
|
||||
return notify_device_state(skb, seq, device, &device_info, type);
|
||||
}
|
||||
|
||||
void notify_peer_device_state_change(struct sk_buff *skb,
|
||||
int notify_peer_device_state_change(struct sk_buff *skb,
|
||||
unsigned int seq,
|
||||
struct drbd_peer_device_state_change *p,
|
||||
enum drbd_notification_type type)
|
||||
@ -1594,7 +1594,7 @@ void notify_peer_device_state_change(struct sk_buff *skb,
|
||||
.peer_resync_susp_dependency = p->resync_susp_dependency[NEW],
|
||||
};
|
||||
|
||||
notify_peer_device_state(skb, seq, peer_device, &peer_device_info, type);
|
||||
return notify_peer_device_state(skb, seq, peer_device, &peer_device_info, type);
|
||||
}
|
||||
|
||||
static void broadcast_state_change(struct drbd_state_change *state_change)
|
||||
@ -1602,7 +1602,7 @@ static void broadcast_state_change(struct drbd_state_change *state_change)
|
||||
struct drbd_resource_state_change *resource_state_change = &state_change->resource[0];
|
||||
bool resource_state_has_changed;
|
||||
unsigned int n_device, n_connection, n_peer_device, n_peer_devices;
|
||||
void (*last_func)(struct sk_buff *, unsigned int, void *,
|
||||
int (*last_func)(struct sk_buff *, unsigned int, void *,
|
||||
enum drbd_notification_type) = NULL;
|
||||
void *last_arg = NULL;
|
||||
|
||||
|
@ -44,19 +44,19 @@ extern struct drbd_state_change *remember_old_state(struct drbd_resource *, gfp_
|
||||
extern void copy_old_to_new_state_change(struct drbd_state_change *);
|
||||
extern void forget_state_change(struct drbd_state_change *);
|
||||
|
||||
extern void notify_resource_state_change(struct sk_buff *,
|
||||
extern int notify_resource_state_change(struct sk_buff *,
|
||||
unsigned int,
|
||||
struct drbd_resource_state_change *,
|
||||
enum drbd_notification_type type);
|
||||
extern void notify_connection_state_change(struct sk_buff *,
|
||||
extern int notify_connection_state_change(struct sk_buff *,
|
||||
unsigned int,
|
||||
struct drbd_connection_state_change *,
|
||||
enum drbd_notification_type type);
|
||||
extern void notify_device_state_change(struct sk_buff *,
|
||||
extern int notify_device_state_change(struct sk_buff *,
|
||||
unsigned int,
|
||||
struct drbd_device_state_change *,
|
||||
enum drbd_notification_type type);
|
||||
extern void notify_peer_device_state_change(struct sk_buff *,
|
||||
extern int notify_peer_device_state_change(struct sk_buff *,
|
||||
unsigned int,
|
||||
struct drbd_peer_device_state_change *,
|
||||
enum drbd_notification_type type);
|
||||
|
@ -1365,7 +1365,6 @@ out_free:
|
||||
*/
|
||||
int cdrom_number_of_slots(struct cdrom_device_info *cdi)
|
||||
{
|
||||
int status;
|
||||
int nslots = 1;
|
||||
struct cdrom_changer_info *info;
|
||||
|
||||
@ -1377,7 +1376,7 @@ int cdrom_number_of_slots(struct cdrom_device_info *cdi)
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
if ((status = cdrom_read_mech_status(cdi, info)) == 0)
|
||||
if (cdrom_read_mech_status(cdi, info) == 0)
|
||||
nslots = info->hdr.nslots;
|
||||
|
||||
kfree(info);
|
||||
|
@ -437,11 +437,8 @@ static void crng_make_state(u32 chacha_state[CHACHA_STATE_WORDS],
|
||||
* This shouldn't be set by functions like add_device_randomness(),
|
||||
* where we can't trust the buffer passed to it is guaranteed to be
|
||||
* unpredictable (so it might not have any entropy at all).
|
||||
*
|
||||
* Returns the number of bytes processed from input, which is bounded
|
||||
* by CRNG_INIT_CNT_THRESH if account is true.
|
||||
*/
|
||||
static size_t crng_pre_init_inject(const void *input, size_t len, bool account)
|
||||
static void crng_pre_init_inject(const void *input, size_t len, bool account)
|
||||
{
|
||||
static int crng_init_cnt = 0;
|
||||
struct blake2s_state hash;
|
||||
@ -452,18 +449,15 @@ static size_t crng_pre_init_inject(const void *input, size_t len, bool account)
|
||||
spin_lock_irqsave(&base_crng.lock, flags);
|
||||
if (crng_init != 0) {
|
||||
spin_unlock_irqrestore(&base_crng.lock, flags);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (account)
|
||||
len = min_t(size_t, len, CRNG_INIT_CNT_THRESH - crng_init_cnt);
|
||||
|
||||
blake2s_update(&hash, base_crng.key, sizeof(base_crng.key));
|
||||
blake2s_update(&hash, input, len);
|
||||
blake2s_final(&hash, base_crng.key);
|
||||
|
||||
if (account) {
|
||||
crng_init_cnt += len;
|
||||
crng_init_cnt += min_t(size_t, len, CRNG_INIT_CNT_THRESH - crng_init_cnt);
|
||||
if (crng_init_cnt >= CRNG_INIT_CNT_THRESH) {
|
||||
++base_crng.generation;
|
||||
crng_init = 1;
|
||||
@ -474,8 +468,6 @@ static size_t crng_pre_init_inject(const void *input, size_t len, bool account)
|
||||
|
||||
if (crng_init == 1)
|
||||
pr_notice("fast init done\n");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void _get_random_bytes(void *buf, size_t nbytes)
|
||||
@ -531,7 +523,6 @@ EXPORT_SYMBOL(get_random_bytes);
|
||||
|
||||
static ssize_t get_random_bytes_user(void __user *buf, size_t nbytes)
|
||||
{
|
||||
bool large_request = nbytes > 256;
|
||||
ssize_t ret = 0;
|
||||
size_t len;
|
||||
u32 chacha_state[CHACHA_STATE_WORDS];
|
||||
@ -540,22 +531,23 @@ static ssize_t get_random_bytes_user(void __user *buf, size_t nbytes)
|
||||
if (!nbytes)
|
||||
return 0;
|
||||
|
||||
len = min_t(size_t, 32, nbytes);
|
||||
crng_make_state(chacha_state, output, len);
|
||||
|
||||
if (copy_to_user(buf, output, len))
|
||||
return -EFAULT;
|
||||
nbytes -= len;
|
||||
buf += len;
|
||||
ret += len;
|
||||
|
||||
while (nbytes) {
|
||||
if (large_request && need_resched()) {
|
||||
if (signal_pending(current))
|
||||
break;
|
||||
schedule();
|
||||
}
|
||||
/*
|
||||
* Immediately overwrite the ChaCha key at index 4 with random
|
||||
* bytes, in case userspace causes copy_to_user() below to sleep
|
||||
* forever, so that we still retain forward secrecy in that case.
|
||||
*/
|
||||
crng_make_state(chacha_state, (u8 *)&chacha_state[4], CHACHA_KEY_SIZE);
|
||||
/*
|
||||
* However, if we're doing a read of len <= 32, we don't need to
|
||||
* use chacha_state after, so we can simply return those bytes to
|
||||
* the user directly.
|
||||
*/
|
||||
if (nbytes <= CHACHA_KEY_SIZE) {
|
||||
ret = copy_to_user(buf, &chacha_state[4], nbytes) ? -EFAULT : nbytes;
|
||||
goto out_zero_chacha;
|
||||
}
|
||||
|
||||
do {
|
||||
chacha20_block(chacha_state, output);
|
||||
if (unlikely(chacha_state[12] == 0))
|
||||
++chacha_state[13];
|
||||
@ -569,10 +561,18 @@ static ssize_t get_random_bytes_user(void __user *buf, size_t nbytes)
|
||||
nbytes -= len;
|
||||
buf += len;
|
||||
ret += len;
|
||||
}
|
||||
|
||||
memzero_explicit(chacha_state, sizeof(chacha_state));
|
||||
BUILD_BUG_ON(PAGE_SIZE % CHACHA_BLOCK_SIZE != 0);
|
||||
if (!(ret % PAGE_SIZE) && nbytes) {
|
||||
if (signal_pending(current))
|
||||
break;
|
||||
cond_resched();
|
||||
}
|
||||
} while (nbytes);
|
||||
|
||||
memzero_explicit(output, sizeof(output));
|
||||
out_zero_chacha:
|
||||
memzero_explicit(chacha_state, sizeof(chacha_state));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1141,12 +1141,9 @@ void add_hwgenerator_randomness(const void *buffer, size_t count,
|
||||
size_t entropy)
|
||||
{
|
||||
if (unlikely(crng_init == 0 && entropy < POOL_MIN_BITS)) {
|
||||
size_t ret = crng_pre_init_inject(buffer, count, true);
|
||||
mix_pool_bytes(buffer, ret);
|
||||
count -= ret;
|
||||
buffer += ret;
|
||||
if (!count || crng_init == 0)
|
||||
return;
|
||||
crng_pre_init_inject(buffer, count, true);
|
||||
mix_pool_bytes(buffer, count);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1545,6 +1542,13 @@ static ssize_t urandom_read(struct file *file, char __user *buf, size_t nbytes,
|
||||
{
|
||||
static int maxwarn = 10;
|
||||
|
||||
/*
|
||||
* Opportunistically attempt to initialize the RNG on platforms that
|
||||
* have fast cycle counters, but don't (for now) require it to succeed.
|
||||
*/
|
||||
if (!crng_ready())
|
||||
try_to_generate_entropy();
|
||||
|
||||
if (!crng_ready() && maxwarn > 0) {
|
||||
maxwarn--;
|
||||
if (__ratelimit(&urandom_warning))
|
||||
|
@ -436,7 +436,6 @@ static int wait_for_media_ready(struct cxl_dev_state *cxlds)
|
||||
|
||||
for (i = mbox_ready_timeout; i; i--) {
|
||||
u32 temp;
|
||||
int rc;
|
||||
|
||||
rc = pci_read_config_dword(
|
||||
pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(0), &temp);
|
||||
|
@ -12,6 +12,7 @@ dmabuf_selftests-y := \
|
||||
selftest.o \
|
||||
st-dma-fence.o \
|
||||
st-dma-fence-chain.o \
|
||||
st-dma-fence-unwrap.o \
|
||||
st-dma-resv.o
|
||||
|
||||
obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
|
||||
|
@ -216,7 +216,8 @@ static bool dma_buf_poll_add_cb(struct dma_resv *resv, bool write,
|
||||
struct dma_fence *fence;
|
||||
int r;
|
||||
|
||||
dma_resv_for_each_fence(&cursor, resv, write, fence) {
|
||||
dma_resv_for_each_fence(&cursor, resv, dma_resv_usage_rw(write),
|
||||
fence) {
|
||||
dma_fence_get(fence);
|
||||
r = dma_fence_add_callback(fence, &dcb->cb, dma_buf_poll_cb);
|
||||
if (!r)
|
||||
@ -443,7 +444,7 @@ err_alloc_file:
|
||||
* as a file descriptor by calling dma_buf_fd().
|
||||
*
|
||||
* 2. Userspace passes this file-descriptors to all drivers it wants this buffer
|
||||
* to share with: First the filedescriptor is converted to a &dma_buf using
|
||||
* to share with: First the file descriptor is converted to a &dma_buf using
|
||||
* dma_buf_get(). Then the buffer is attached to the device using
|
||||
* dma_buf_attach().
|
||||
*
|
||||
@ -660,12 +661,24 @@ static struct sg_table * __map_dma_buf(struct dma_buf_attachment *attach,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
struct sg_table *sg_table;
|
||||
signed long ret;
|
||||
|
||||
sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
|
||||
if (IS_ERR_OR_NULL(sg_table))
|
||||
return sg_table;
|
||||
|
||||
if (!IS_ERR_OR_NULL(sg_table))
|
||||
mangle_sg_table(sg_table);
|
||||
if (!dma_buf_attachment_is_dynamic(attach)) {
|
||||
ret = dma_resv_wait_timeout(attach->dmabuf->resv,
|
||||
DMA_RESV_USAGE_KERNEL, true,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
attach->dmabuf->ops->unmap_dma_buf(attach, sg_table,
|
||||
direction);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
|
||||
mangle_sg_table(sg_table);
|
||||
return sg_table;
|
||||
}
|
||||
|
||||
@ -1124,7 +1137,8 @@ static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
|
||||
long ret;
|
||||
|
||||
/* Wait on any implicit rendering fences */
|
||||
ret = dma_resv_wait_timeout(resv, write, true, MAX_SCHEDULE_TIMEOUT);
|
||||
ret = dma_resv_wait_timeout(resv, dma_resv_usage_rw(write),
|
||||
true, MAX_SCHEDULE_TIMEOUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -159,6 +159,8 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
|
||||
struct dma_fence_array *array;
|
||||
size_t size = sizeof(*array);
|
||||
|
||||
WARN_ON(!num_fences || !fences);
|
||||
|
||||
/* Allocate the callback structures behind the array. */
|
||||
size += num_fences * sizeof(struct dma_fence_array_cb);
|
||||
array = kzalloc(size, GFP_KERNEL);
|
||||
@ -219,3 +221,33 @@ bool dma_fence_match_context(struct dma_fence *fence, u64 context)
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_fence_match_context);
|
||||
|
||||
struct dma_fence *dma_fence_array_first(struct dma_fence *head)
|
||||
{
|
||||
struct dma_fence_array *array;
|
||||
|
||||
if (!head)
|
||||
return NULL;
|
||||
|
||||
array = to_dma_fence_array(head);
|
||||
if (!array)
|
||||
return head;
|
||||
|
||||
if (!array->num_fences)
|
||||
return NULL;
|
||||
|
||||
return array->fences[0];
|
||||
}
|
||||
EXPORT_SYMBOL(dma_fence_array_first);
|
||||
|
||||
struct dma_fence *dma_fence_array_next(struct dma_fence *head,
|
||||
unsigned int index)
|
||||
{
|
||||
struct dma_fence_array *array = to_dma_fence_array(head);
|
||||
|
||||
if (!array || index >= array->num_fences)
|
||||
return NULL;
|
||||
|
||||
return array->fences[index];
|
||||
}
|
||||
EXPORT_SYMBOL(dma_fence_array_next);
|
||||
|
@ -34,6 +34,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/dma-resv.h>
|
||||
#include <linux/dma-fence-array.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched/mm.h>
|
||||
@ -43,12 +44,12 @@
|
||||
/**
|
||||
* DOC: Reservation Object Overview
|
||||
*
|
||||
* The reservation object provides a mechanism to manage shared and
|
||||
* exclusive fences associated with a buffer. A reservation object
|
||||
* can have attached one exclusive fence (normally associated with
|
||||
* write operations) or N shared fences (read operations). The RCU
|
||||
* mechanism is used to protect read access to fences from locked
|
||||
* write-side updates.
|
||||
* The reservation object provides a mechanism to manage a container of
|
||||
* dma_fence object associated with a resource. A reservation object
|
||||
* can have any number of fences attaches to it. Each fence carries an usage
|
||||
* parameter determining how the operation represented by the fence is using the
|
||||
* resource. The RCU mechanism is used to protect read access to fences from
|
||||
* locked write-side updates.
|
||||
*
|
||||
* See struct dma_resv for more details.
|
||||
*/
|
||||
@ -56,33 +57,59 @@
|
||||
DEFINE_WD_CLASS(reservation_ww_class);
|
||||
EXPORT_SYMBOL(reservation_ww_class);
|
||||
|
||||
/**
|
||||
* dma_resv_list_alloc - allocate fence list
|
||||
* @shared_max: number of fences we need space for
|
||||
*
|
||||
/* Mask for the lower fence pointer bits */
|
||||
#define DMA_RESV_LIST_MASK 0x3
|
||||
|
||||
struct dma_resv_list {
|
||||
struct rcu_head rcu;
|
||||
u32 num_fences, max_fences;
|
||||
struct dma_fence __rcu *table[];
|
||||
};
|
||||
|
||||
/* Extract the fence and usage flags from an RCU protected entry in the list. */
|
||||
static void dma_resv_list_entry(struct dma_resv_list *list, unsigned int index,
|
||||
struct dma_resv *resv, struct dma_fence **fence,
|
||||
enum dma_resv_usage *usage)
|
||||
{
|
||||
long tmp;
|
||||
|
||||
tmp = (long)rcu_dereference_check(list->table[index],
|
||||
resv ? dma_resv_held(resv) : true);
|
||||
*fence = (struct dma_fence *)(tmp & ~DMA_RESV_LIST_MASK);
|
||||
if (usage)
|
||||
*usage = tmp & DMA_RESV_LIST_MASK;
|
||||
}
|
||||
|
||||
/* Set the fence and usage flags at the specific index in the list. */
|
||||
static void dma_resv_list_set(struct dma_resv_list *list,
|
||||
unsigned int index,
|
||||
struct dma_fence *fence,
|
||||
enum dma_resv_usage usage)
|
||||
{
|
||||
long tmp = ((long)fence) | usage;
|
||||
|
||||
RCU_INIT_POINTER(list->table[index], (struct dma_fence *)tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new dma_resv_list and make sure to correctly initialize
|
||||
* shared_max.
|
||||
* max_fences.
|
||||
*/
|
||||
static struct dma_resv_list *dma_resv_list_alloc(unsigned int shared_max)
|
||||
static struct dma_resv_list *dma_resv_list_alloc(unsigned int max_fences)
|
||||
{
|
||||
struct dma_resv_list *list;
|
||||
|
||||
list = kmalloc(struct_size(list, shared, shared_max), GFP_KERNEL);
|
||||
list = kmalloc(struct_size(list, table, max_fences), GFP_KERNEL);
|
||||
if (!list)
|
||||
return NULL;
|
||||
|
||||
list->shared_max = (ksize(list) - offsetof(typeof(*list), shared)) /
|
||||
sizeof(*list->shared);
|
||||
list->max_fences = (ksize(list) - offsetof(typeof(*list), table)) /
|
||||
sizeof(*list->table);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_resv_list_free - free fence list
|
||||
* @list: list to free
|
||||
*
|
||||
* Free a dma_resv_list and make sure to drop all references.
|
||||
*/
|
||||
/* Free a dma_resv_list and make sure to drop all references. */
|
||||
static void dma_resv_list_free(struct dma_resv_list *list)
|
||||
{
|
||||
unsigned int i;
|
||||
@ -90,9 +117,12 @@ static void dma_resv_list_free(struct dma_resv_list *list)
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
for (i = 0; i < list->shared_count; ++i)
|
||||
dma_fence_put(rcu_dereference_protected(list->shared[i], true));
|
||||
for (i = 0; i < list->num_fences; ++i) {
|
||||
struct dma_fence *fence;
|
||||
|
||||
dma_resv_list_entry(list, i, NULL, &fence, NULL);
|
||||
dma_fence_put(fence);
|
||||
}
|
||||
kfree_rcu(list, rcu);
|
||||
}
|
||||
|
||||
@ -103,10 +133,8 @@ static void dma_resv_list_free(struct dma_resv_list *list)
|
||||
void dma_resv_init(struct dma_resv *obj)
|
||||
{
|
||||
ww_mutex_init(&obj->lock, &reservation_ww_class);
|
||||
seqcount_ww_mutex_init(&obj->seq, &obj->lock);
|
||||
|
||||
RCU_INIT_POINTER(obj->fence, NULL);
|
||||
RCU_INIT_POINTER(obj->fence_excl, NULL);
|
||||
RCU_INIT_POINTER(obj->fences, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_init);
|
||||
|
||||
@ -116,51 +144,48 @@ EXPORT_SYMBOL(dma_resv_init);
|
||||
*/
|
||||
void dma_resv_fini(struct dma_resv *obj)
|
||||
{
|
||||
struct dma_resv_list *fobj;
|
||||
struct dma_fence *excl;
|
||||
|
||||
/*
|
||||
* This object should be dead and all references must have
|
||||
* been released to it, so no need to be protected with rcu.
|
||||
*/
|
||||
excl = rcu_dereference_protected(obj->fence_excl, 1);
|
||||
if (excl)
|
||||
dma_fence_put(excl);
|
||||
|
||||
fobj = rcu_dereference_protected(obj->fence, 1);
|
||||
dma_resv_list_free(fobj);
|
||||
dma_resv_list_free(rcu_dereference_protected(obj->fences, true));
|
||||
ww_mutex_destroy(&obj->lock);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_fini);
|
||||
|
||||
/* Dereference the fences while ensuring RCU rules */
|
||||
static inline struct dma_resv_list *dma_resv_fences_list(struct dma_resv *obj)
|
||||
{
|
||||
return rcu_dereference_check(obj->fences, dma_resv_held(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_resv_reserve_shared - Reserve space to add shared fences to
|
||||
* a dma_resv.
|
||||
* dma_resv_reserve_fences - Reserve space to add fences to a dma_resv object.
|
||||
* @obj: reservation object
|
||||
* @num_fences: number of fences we want to add
|
||||
*
|
||||
* Should be called before dma_resv_add_shared_fence(). Must
|
||||
* be called with @obj locked through dma_resv_lock().
|
||||
* Should be called before dma_resv_add_fence(). Must be called with @obj
|
||||
* locked through dma_resv_lock().
|
||||
*
|
||||
* Note that the preallocated slots need to be re-reserved if @obj is unlocked
|
||||
* at any time before calling dma_resv_add_shared_fence(). This is validated
|
||||
* when CONFIG_DEBUG_MUTEXES is enabled.
|
||||
* at any time before calling dma_resv_add_fence(). This is validated when
|
||||
* CONFIG_DEBUG_MUTEXES is enabled.
|
||||
*
|
||||
* RETURNS
|
||||
* Zero for success, or -errno
|
||||
*/
|
||||
int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
|
||||
int dma_resv_reserve_fences(struct dma_resv *obj, unsigned int num_fences)
|
||||
{
|
||||
struct dma_resv_list *old, *new;
|
||||
unsigned int i, j, k, max;
|
||||
|
||||
dma_resv_assert_held(obj);
|
||||
|
||||
old = dma_resv_shared_list(obj);
|
||||
if (old && old->shared_max) {
|
||||
if ((old->shared_count + num_fences) <= old->shared_max)
|
||||
old = dma_resv_fences_list(obj);
|
||||
if (old && old->max_fences) {
|
||||
if ((old->num_fences + num_fences) <= old->max_fences)
|
||||
return 0;
|
||||
max = max(old->shared_count + num_fences, old->shared_max * 2);
|
||||
max = max(old->num_fences + num_fences, old->max_fences * 2);
|
||||
} else {
|
||||
max = max(4ul, roundup_pow_of_two(num_fences));
|
||||
}
|
||||
@ -175,27 +200,27 @@ int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
|
||||
* references from the old struct are carried over to
|
||||
* the new.
|
||||
*/
|
||||
for (i = 0, j = 0, k = max; i < (old ? old->shared_count : 0); ++i) {
|
||||
for (i = 0, j = 0, k = max; i < (old ? old->num_fences : 0); ++i) {
|
||||
enum dma_resv_usage usage;
|
||||
struct dma_fence *fence;
|
||||
|
||||
fence = rcu_dereference_protected(old->shared[i],
|
||||
dma_resv_held(obj));
|
||||
dma_resv_list_entry(old, i, obj, &fence, &usage);
|
||||
if (dma_fence_is_signaled(fence))
|
||||
RCU_INIT_POINTER(new->shared[--k], fence);
|
||||
RCU_INIT_POINTER(new->table[--k], fence);
|
||||
else
|
||||
RCU_INIT_POINTER(new->shared[j++], fence);
|
||||
dma_resv_list_set(new, j++, fence, usage);
|
||||
}
|
||||
new->shared_count = j;
|
||||
new->num_fences = j;
|
||||
|
||||
/*
|
||||
* We are not changing the effective set of fences here so can
|
||||
* merely update the pointer to the new array; both existing
|
||||
* readers and new readers will see exactly the same set of
|
||||
* active (unsignaled) shared fences. Individual fences and the
|
||||
* active (unsignaled) fences. Individual fences and the
|
||||
* old array are protected by RCU and so will not vanish under
|
||||
* the gaze of the rcu_read_lock() readers.
|
||||
*/
|
||||
rcu_assign_pointer(obj->fence, new);
|
||||
rcu_assign_pointer(obj->fences, new);
|
||||
|
||||
if (!old)
|
||||
return 0;
|
||||
@ -204,7 +229,7 @@ int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
|
||||
for (i = k; i < max; ++i) {
|
||||
struct dma_fence *fence;
|
||||
|
||||
fence = rcu_dereference_protected(new->shared[i],
|
||||
fence = rcu_dereference_protected(new->table[i],
|
||||
dma_resv_held(obj));
|
||||
dma_fence_put(fence);
|
||||
}
|
||||
@ -212,41 +237,43 @@ int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_reserve_shared);
|
||||
EXPORT_SYMBOL(dma_resv_reserve_fences);
|
||||
|
||||
#ifdef CONFIG_DEBUG_MUTEXES
|
||||
/**
|
||||
* dma_resv_reset_shared_max - reset shared fences for debugging
|
||||
* dma_resv_reset_max_fences - reset fences for debugging
|
||||
* @obj: the dma_resv object to reset
|
||||
*
|
||||
* Reset the number of pre-reserved shared slots to test that drivers do
|
||||
* correct slot allocation using dma_resv_reserve_shared(). See also
|
||||
* &dma_resv_list.shared_max.
|
||||
* Reset the number of pre-reserved fence slots to test that drivers do
|
||||
* correct slot allocation using dma_resv_reserve_fences(). See also
|
||||
* &dma_resv_list.max_fences.
|
||||
*/
|
||||
void dma_resv_reset_shared_max(struct dma_resv *obj)
|
||||
void dma_resv_reset_max_fences(struct dma_resv *obj)
|
||||
{
|
||||
struct dma_resv_list *fences = dma_resv_shared_list(obj);
|
||||
struct dma_resv_list *fences = dma_resv_fences_list(obj);
|
||||
|
||||
dma_resv_assert_held(obj);
|
||||
|
||||
/* Test shared fence slot reservation */
|
||||
/* Test fence slot reservation */
|
||||
if (fences)
|
||||
fences->shared_max = fences->shared_count;
|
||||
fences->max_fences = fences->num_fences;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_reset_shared_max);
|
||||
EXPORT_SYMBOL(dma_resv_reset_max_fences);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* dma_resv_add_shared_fence - Add a fence to a shared slot
|
||||
* dma_resv_add_fence - Add a fence to the dma_resv obj
|
||||
* @obj: the reservation object
|
||||
* @fence: the shared fence to add
|
||||
* @fence: the fence to add
|
||||
* @usage: how the fence is used, see enum dma_resv_usage
|
||||
*
|
||||
* Add a fence to a shared slot, @obj must be locked with dma_resv_lock(), and
|
||||
* dma_resv_reserve_shared() has been called.
|
||||
* Add a fence to a slot, @obj must be locked with dma_resv_lock(), and
|
||||
* dma_resv_reserve_fences() has been called.
|
||||
*
|
||||
* See also &dma_resv.fence for a discussion of the semantics.
|
||||
*/
|
||||
void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
|
||||
void dma_resv_add_fence(struct dma_resv *obj, struct dma_fence *fence,
|
||||
enum dma_resv_usage usage)
|
||||
{
|
||||
struct dma_resv_list *fobj;
|
||||
struct dma_fence *old;
|
||||
@ -261,118 +288,105 @@ void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
|
||||
*/
|
||||
WARN_ON(dma_fence_is_container(fence));
|
||||
|
||||
fobj = dma_resv_shared_list(obj);
|
||||
count = fobj->shared_count;
|
||||
|
||||
write_seqcount_begin(&obj->seq);
|
||||
fobj = dma_resv_fences_list(obj);
|
||||
count = fobj->num_fences;
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
enum dma_resv_usage old_usage;
|
||||
|
||||
old = rcu_dereference_protected(fobj->shared[i],
|
||||
dma_resv_held(obj));
|
||||
if (old->context == fence->context ||
|
||||
dma_fence_is_signaled(old))
|
||||
goto replace;
|
||||
dma_resv_list_entry(fobj, i, obj, &old, &old_usage);
|
||||
if ((old->context == fence->context && old_usage >= usage) ||
|
||||
dma_fence_is_signaled(old)) {
|
||||
dma_resv_list_set(fobj, i, fence, usage);
|
||||
dma_fence_put(old);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BUG_ON(fobj->shared_count >= fobj->shared_max);
|
||||
old = NULL;
|
||||
BUG_ON(fobj->num_fences >= fobj->max_fences);
|
||||
count++;
|
||||
|
||||
replace:
|
||||
RCU_INIT_POINTER(fobj->shared[i], fence);
|
||||
/* pointer update must be visible before we extend the shared_count */
|
||||
smp_store_mb(fobj->shared_count, count);
|
||||
|
||||
write_seqcount_end(&obj->seq);
|
||||
dma_fence_put(old);
|
||||
dma_resv_list_set(fobj, i, fence, usage);
|
||||
/* pointer update must be visible before we extend the num_fences */
|
||||
smp_store_mb(fobj->num_fences, count);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_add_shared_fence);
|
||||
EXPORT_SYMBOL(dma_resv_add_fence);
|
||||
|
||||
/**
|
||||
* dma_resv_add_excl_fence - Add an exclusive fence.
|
||||
* dma_resv_replace_fences - replace fences in the dma_resv obj
|
||||
* @obj: the reservation object
|
||||
* @fence: the exclusive fence to add
|
||||
* @context: the context of the fences to replace
|
||||
* @replacement: the new fence to use instead
|
||||
* @usage: how the new fence is used, see enum dma_resv_usage
|
||||
*
|
||||
* Add a fence to the exclusive slot. @obj must be locked with dma_resv_lock().
|
||||
* Note that this function replaces all fences attached to @obj, see also
|
||||
* &dma_resv.fence_excl for a discussion of the semantics.
|
||||
* Replace fences with a specified context with a new fence. Only valid if the
|
||||
* operation represented by the original fence has no longer access to the
|
||||
* resources represented by the dma_resv object when the new fence completes.
|
||||
*
|
||||
* And example for using this is replacing a preemption fence with a page table
|
||||
* update fence which makes the resource inaccessible.
|
||||
*/
|
||||
void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
|
||||
void dma_resv_replace_fences(struct dma_resv *obj, uint64_t context,
|
||||
struct dma_fence *replacement,
|
||||
enum dma_resv_usage usage)
|
||||
{
|
||||
struct dma_fence *old_fence = dma_resv_excl_fence(obj);
|
||||
struct dma_resv_list *old;
|
||||
u32 i = 0;
|
||||
struct dma_resv_list *list;
|
||||
unsigned int i;
|
||||
|
||||
dma_resv_assert_held(obj);
|
||||
|
||||
old = dma_resv_shared_list(obj);
|
||||
if (old)
|
||||
i = old->shared_count;
|
||||
list = dma_resv_fences_list(obj);
|
||||
for (i = 0; list && i < list->num_fences; ++i) {
|
||||
struct dma_fence *old;
|
||||
|
||||
dma_fence_get(fence);
|
||||
dma_resv_list_entry(list, i, obj, &old, NULL);
|
||||
if (old->context != context)
|
||||
continue;
|
||||
|
||||
write_seqcount_begin(&obj->seq);
|
||||
/* write_seqcount_begin provides the necessary memory barrier */
|
||||
RCU_INIT_POINTER(obj->fence_excl, fence);
|
||||
if (old)
|
||||
old->shared_count = 0;
|
||||
write_seqcount_end(&obj->seq);
|
||||
|
||||
/* inplace update, no shared fences */
|
||||
while (i--)
|
||||
dma_fence_put(rcu_dereference_protected(old->shared[i],
|
||||
dma_resv_held(obj)));
|
||||
|
||||
dma_fence_put(old_fence);
|
||||
dma_resv_list_set(list, i, replacement, usage);
|
||||
dma_fence_put(old);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_add_excl_fence);
|
||||
EXPORT_SYMBOL(dma_resv_replace_fences);
|
||||
|
||||
/* Restart the iterator by initializing all the necessary fields, but not the
|
||||
* relation to the dma_resv object. */
|
||||
/* Restart the unlocked iteration by initializing the cursor object. */
|
||||
static void dma_resv_iter_restart_unlocked(struct dma_resv_iter *cursor)
|
||||
{
|
||||
cursor->seq = read_seqcount_begin(&cursor->obj->seq);
|
||||
cursor->index = -1;
|
||||
cursor->shared_count = 0;
|
||||
if (cursor->all_fences) {
|
||||
cursor->fences = dma_resv_shared_list(cursor->obj);
|
||||
if (cursor->fences)
|
||||
cursor->shared_count = cursor->fences->shared_count;
|
||||
} else {
|
||||
cursor->fences = NULL;
|
||||
}
|
||||
cursor->index = 0;
|
||||
cursor->num_fences = 0;
|
||||
cursor->fences = dma_resv_fences_list(cursor->obj);
|
||||
if (cursor->fences)
|
||||
cursor->num_fences = cursor->fences->num_fences;
|
||||
cursor->is_restarted = true;
|
||||
}
|
||||
|
||||
/* Walk to the next not signaled fence and grab a reference to it */
|
||||
static void dma_resv_iter_walk_unlocked(struct dma_resv_iter *cursor)
|
||||
{
|
||||
struct dma_resv *obj = cursor->obj;
|
||||
if (!cursor->fences)
|
||||
return;
|
||||
|
||||
do {
|
||||
/* Drop the reference from the previous round */
|
||||
dma_fence_put(cursor->fence);
|
||||
|
||||
if (cursor->index == -1) {
|
||||
cursor->fence = dma_resv_excl_fence(obj);
|
||||
cursor->index++;
|
||||
if (!cursor->fence)
|
||||
continue;
|
||||
|
||||
} else if (!cursor->fences ||
|
||||
cursor->index >= cursor->shared_count) {
|
||||
if (cursor->index >= cursor->num_fences) {
|
||||
cursor->fence = NULL;
|
||||
break;
|
||||
|
||||
} else {
|
||||
struct dma_resv_list *fences = cursor->fences;
|
||||
unsigned int idx = cursor->index++;
|
||||
|
||||
cursor->fence = rcu_dereference(fences->shared[idx]);
|
||||
}
|
||||
|
||||
dma_resv_list_entry(cursor->fences, cursor->index++,
|
||||
cursor->obj, &cursor->fence,
|
||||
&cursor->fence_usage);
|
||||
cursor->fence = dma_fence_get_rcu(cursor->fence);
|
||||
if (!cursor->fence || !dma_fence_is_signaled(cursor->fence))
|
||||
if (!cursor->fence) {
|
||||
dma_resv_iter_restart_unlocked(cursor);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!dma_fence_is_signaled(cursor->fence) &&
|
||||
cursor->usage >= cursor->fence_usage)
|
||||
break;
|
||||
} while (true);
|
||||
}
|
||||
@ -395,7 +409,7 @@ struct dma_fence *dma_resv_iter_first_unlocked(struct dma_resv_iter *cursor)
|
||||
do {
|
||||
dma_resv_iter_restart_unlocked(cursor);
|
||||
dma_resv_iter_walk_unlocked(cursor);
|
||||
} while (read_seqcount_retry(&cursor->obj->seq, cursor->seq));
|
||||
} while (dma_resv_fences_list(cursor->obj) != cursor->fences);
|
||||
rcu_read_unlock();
|
||||
|
||||
return cursor->fence;
|
||||
@ -418,13 +432,13 @@ struct dma_fence *dma_resv_iter_next_unlocked(struct dma_resv_iter *cursor)
|
||||
|
||||
rcu_read_lock();
|
||||
cursor->is_restarted = false;
|
||||
restart = read_seqcount_retry(&cursor->obj->seq, cursor->seq);
|
||||
restart = dma_resv_fences_list(cursor->obj) != cursor->fences;
|
||||
do {
|
||||
if (restart)
|
||||
dma_resv_iter_restart_unlocked(cursor);
|
||||
dma_resv_iter_walk_unlocked(cursor);
|
||||
restart = true;
|
||||
} while (read_seqcount_retry(&cursor->obj->seq, cursor->seq));
|
||||
} while (dma_resv_fences_list(cursor->obj) != cursor->fences);
|
||||
rcu_read_unlock();
|
||||
|
||||
return cursor->fence;
|
||||
@ -447,15 +461,9 @@ struct dma_fence *dma_resv_iter_first(struct dma_resv_iter *cursor)
|
||||
dma_resv_assert_held(cursor->obj);
|
||||
|
||||
cursor->index = 0;
|
||||
if (cursor->all_fences)
|
||||
cursor->fences = dma_resv_shared_list(cursor->obj);
|
||||
else
|
||||
cursor->fences = NULL;
|
||||
|
||||
fence = dma_resv_excl_fence(cursor->obj);
|
||||
if (!fence)
|
||||
fence = dma_resv_iter_next(cursor);
|
||||
cursor->fences = dma_resv_fences_list(cursor->obj);
|
||||
|
||||
fence = dma_resv_iter_next(cursor);
|
||||
cursor->is_restarted = true;
|
||||
return fence;
|
||||
}
|
||||
@ -470,17 +478,22 @@ EXPORT_SYMBOL_GPL(dma_resv_iter_first);
|
||||
*/
|
||||
struct dma_fence *dma_resv_iter_next(struct dma_resv_iter *cursor)
|
||||
{
|
||||
unsigned int idx;
|
||||
struct dma_fence *fence;
|
||||
|
||||
dma_resv_assert_held(cursor->obj);
|
||||
|
||||
cursor->is_restarted = false;
|
||||
if (!cursor->fences || cursor->index >= cursor->fences->shared_count)
|
||||
return NULL;
|
||||
|
||||
idx = cursor->index++;
|
||||
return rcu_dereference_protected(cursor->fences->shared[idx],
|
||||
dma_resv_held(cursor->obj));
|
||||
do {
|
||||
if (!cursor->fences ||
|
||||
cursor->index >= cursor->fences->num_fences)
|
||||
return NULL;
|
||||
|
||||
dma_resv_list_entry(cursor->fences, cursor->index++,
|
||||
cursor->obj, &fence, &cursor->fence_usage);
|
||||
} while (cursor->fence_usage > cursor->usage);
|
||||
|
||||
return fence;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_resv_iter_next);
|
||||
|
||||
@ -495,60 +508,43 @@ int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src)
|
||||
{
|
||||
struct dma_resv_iter cursor;
|
||||
struct dma_resv_list *list;
|
||||
struct dma_fence *f, *excl;
|
||||
struct dma_fence *f;
|
||||
|
||||
dma_resv_assert_held(dst);
|
||||
|
||||
list = NULL;
|
||||
excl = NULL;
|
||||
|
||||
dma_resv_iter_begin(&cursor, src, true);
|
||||
dma_resv_iter_begin(&cursor, src, DMA_RESV_USAGE_BOOKKEEP);
|
||||
dma_resv_for_each_fence_unlocked(&cursor, f) {
|
||||
|
||||
if (dma_resv_iter_is_restarted(&cursor)) {
|
||||
dma_resv_list_free(list);
|
||||
dma_fence_put(excl);
|
||||
|
||||
if (cursor.shared_count) {
|
||||
list = dma_resv_list_alloc(cursor.shared_count);
|
||||
if (!list) {
|
||||
dma_resv_iter_end(&cursor);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
list->shared_count = 0;
|
||||
|
||||
} else {
|
||||
list = NULL;
|
||||
list = dma_resv_list_alloc(cursor.num_fences);
|
||||
if (!list) {
|
||||
dma_resv_iter_end(&cursor);
|
||||
return -ENOMEM;
|
||||
}
|
||||
excl = NULL;
|
||||
list->num_fences = 0;
|
||||
}
|
||||
|
||||
dma_fence_get(f);
|
||||
if (dma_resv_iter_is_exclusive(&cursor))
|
||||
excl = f;
|
||||
else
|
||||
RCU_INIT_POINTER(list->shared[list->shared_count++], f);
|
||||
dma_resv_list_set(list, list->num_fences++, f,
|
||||
dma_resv_iter_usage(&cursor));
|
||||
}
|
||||
dma_resv_iter_end(&cursor);
|
||||
|
||||
write_seqcount_begin(&dst->seq);
|
||||
excl = rcu_replace_pointer(dst->fence_excl, excl, dma_resv_held(dst));
|
||||
list = rcu_replace_pointer(dst->fence, list, dma_resv_held(dst));
|
||||
write_seqcount_end(&dst->seq);
|
||||
|
||||
list = rcu_replace_pointer(dst->fences, list, dma_resv_held(dst));
|
||||
dma_resv_list_free(list);
|
||||
dma_fence_put(excl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_copy_fences);
|
||||
|
||||
/**
|
||||
* dma_resv_get_fences - Get an object's shared and exclusive
|
||||
* dma_resv_get_fences - Get an object's fences
|
||||
* fences without update side lock held
|
||||
* @obj: the reservation object
|
||||
* @write: true if we should return all fences
|
||||
* @usage: controls which fences to include, see enum dma_resv_usage.
|
||||
* @num_fences: the number of fences returned
|
||||
* @fences: the array of fence ptrs returned (array is krealloc'd to the
|
||||
* required size, and must be freed by caller)
|
||||
@ -556,7 +552,7 @@ EXPORT_SYMBOL(dma_resv_copy_fences);
|
||||
* Retrieve all fences from the reservation object.
|
||||
* Returns either zero or -ENOMEM.
|
||||
*/
|
||||
int dma_resv_get_fences(struct dma_resv *obj, bool write,
|
||||
int dma_resv_get_fences(struct dma_resv *obj, enum dma_resv_usage usage,
|
||||
unsigned int *num_fences, struct dma_fence ***fences)
|
||||
{
|
||||
struct dma_resv_iter cursor;
|
||||
@ -565,7 +561,7 @@ int dma_resv_get_fences(struct dma_resv *obj, bool write,
|
||||
*num_fences = 0;
|
||||
*fences = NULL;
|
||||
|
||||
dma_resv_iter_begin(&cursor, obj, write);
|
||||
dma_resv_iter_begin(&cursor, obj, usage);
|
||||
dma_resv_for_each_fence_unlocked(&cursor, fence) {
|
||||
|
||||
if (dma_resv_iter_is_restarted(&cursor)) {
|
||||
@ -574,7 +570,7 @@ int dma_resv_get_fences(struct dma_resv *obj, bool write,
|
||||
while (*num_fences)
|
||||
dma_fence_put((*fences)[--(*num_fences)]);
|
||||
|
||||
count = cursor.shared_count + 1;
|
||||
count = cursor.num_fences + 1;
|
||||
|
||||
/* Eventually re-allocate the array */
|
||||
*fences = krealloc_array(*fences, count,
|
||||
@ -595,10 +591,62 @@ int dma_resv_get_fences(struct dma_resv *obj, bool write,
|
||||
EXPORT_SYMBOL_GPL(dma_resv_get_fences);
|
||||
|
||||
/**
|
||||
* dma_resv_wait_timeout - Wait on reservation's objects
|
||||
* shared and/or exclusive fences.
|
||||
* dma_resv_get_singleton - Get a single fence for all the fences
|
||||
* @obj: the reservation object
|
||||
* @wait_all: if true, wait on all fences, else wait on just exclusive fence
|
||||
* @usage: controls which fences to include, see enum dma_resv_usage.
|
||||
* @fence: the resulting fence
|
||||
*
|
||||
* Get a single fence representing all the fences inside the resv object.
|
||||
* Returns either 0 for success or -ENOMEM.
|
||||
*
|
||||
* Warning: This can't be used like this when adding the fence back to the resv
|
||||
* object since that can lead to stack corruption when finalizing the
|
||||
* dma_fence_array.
|
||||
*
|
||||
* Returns 0 on success and negative error values on failure.
|
||||
*/
|
||||
int dma_resv_get_singleton(struct dma_resv *obj, enum dma_resv_usage usage,
|
||||
struct dma_fence **fence)
|
||||
{
|
||||
struct dma_fence_array *array;
|
||||
struct dma_fence **fences;
|
||||
unsigned count;
|
||||
int r;
|
||||
|
||||
r = dma_resv_get_fences(obj, usage, &count, &fences);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (count == 0) {
|
||||
*fence = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count == 1) {
|
||||
*fence = fences[0];
|
||||
kfree(fences);
|
||||
return 0;
|
||||
}
|
||||
|
||||
array = dma_fence_array_create(count, fences,
|
||||
dma_fence_context_alloc(1),
|
||||
1, false);
|
||||
if (!array) {
|
||||
while (count--)
|
||||
dma_fence_put(fences[count]);
|
||||
kfree(fences);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*fence = &array->base;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_resv_get_singleton);
|
||||
|
||||
/**
|
||||
* dma_resv_wait_timeout - Wait on reservation's objects fences
|
||||
* @obj: the reservation object
|
||||
* @usage: controls which fences to include, see enum dma_resv_usage.
|
||||
* @intr: if true, do interruptible wait
|
||||
* @timeout: timeout value in jiffies or zero to return immediately
|
||||
*
|
||||
@ -608,14 +656,14 @@ EXPORT_SYMBOL_GPL(dma_resv_get_fences);
|
||||
* Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
|
||||
* greater than zer on success.
|
||||
*/
|
||||
long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr,
|
||||
unsigned long timeout)
|
||||
long dma_resv_wait_timeout(struct dma_resv *obj, enum dma_resv_usage usage,
|
||||
bool intr, unsigned long timeout)
|
||||
{
|
||||
long ret = timeout ? timeout : 1;
|
||||
struct dma_resv_iter cursor;
|
||||
struct dma_fence *fence;
|
||||
|
||||
dma_resv_iter_begin(&cursor, obj, wait_all);
|
||||
dma_resv_iter_begin(&cursor, obj, usage);
|
||||
dma_resv_for_each_fence_unlocked(&cursor, fence) {
|
||||
|
||||
ret = dma_fence_wait_timeout(fence, intr, ret);
|
||||
@ -635,8 +683,7 @@ EXPORT_SYMBOL_GPL(dma_resv_wait_timeout);
|
||||
* dma_resv_test_signaled - Test if a reservation object's fences have been
|
||||
* signaled.
|
||||
* @obj: the reservation object
|
||||
* @test_all: if true, test all fences, otherwise only test the exclusive
|
||||
* fence
|
||||
* @usage: controls which fences to include, see enum dma_resv_usage.
|
||||
*
|
||||
* Callers are not required to hold specific locks, but maybe hold
|
||||
* dma_resv_lock() already.
|
||||
@ -645,12 +692,12 @@ EXPORT_SYMBOL_GPL(dma_resv_wait_timeout);
|
||||
*
|
||||
* True if all fences signaled, else false.
|
||||
*/
|
||||
bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all)
|
||||
bool dma_resv_test_signaled(struct dma_resv *obj, enum dma_resv_usage usage)
|
||||
{
|
||||
struct dma_resv_iter cursor;
|
||||
struct dma_fence *fence;
|
||||
|
||||
dma_resv_iter_begin(&cursor, obj, test_all);
|
||||
dma_resv_iter_begin(&cursor, obj, usage);
|
||||
dma_resv_for_each_fence_unlocked(&cursor, fence) {
|
||||
dma_resv_iter_end(&cursor);
|
||||
return false;
|
||||
@ -670,13 +717,13 @@ EXPORT_SYMBOL_GPL(dma_resv_test_signaled);
|
||||
*/
|
||||
void dma_resv_describe(struct dma_resv *obj, struct seq_file *seq)
|
||||
{
|
||||
static const char *usage[] = { "kernel", "write", "read", "bookkeep" };
|
||||
struct dma_resv_iter cursor;
|
||||
struct dma_fence *fence;
|
||||
|
||||
dma_resv_for_each_fence(&cursor, obj, true, fence) {
|
||||
dma_resv_for_each_fence(&cursor, obj, DMA_RESV_USAGE_READ, fence) {
|
||||
seq_printf(seq, "\t%s fence:",
|
||||
dma_resv_iter_is_exclusive(&cursor) ?
|
||||
"Exclusive" : "Shared");
|
||||
usage[dma_resv_iter_usage(&cursor)]);
|
||||
dma_fence_describe(fence, seq);
|
||||
}
|
||||
}
|
||||
|
@ -12,4 +12,5 @@
|
||||
selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
|
||||
selftest(dma_fence, dma_fence)
|
||||
selftest(dma_fence_chain, dma_fence_chain)
|
||||
selftest(dma_fence_unwrap, dma_fence_unwrap)
|
||||
selftest(dma_resv, dma_resv)
|
||||
|
261
drivers/dma-buf/st-dma-fence-unwrap.c
Normal file
261
drivers/dma-buf/st-dma-fence-unwrap.c
Normal file
@ -0,0 +1,261 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/dma-fence-unwrap.h>
|
||||
#if 0
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/random.h>
|
||||
#endif
|
||||
|
||||
#include "selftest.h"
|
||||
|
||||
#define CHAIN_SZ (4 << 10)
|
||||
|
||||
static inline struct mock_fence {
|
||||
struct dma_fence base;
|
||||
spinlock_t lock;
|
||||
} *to_mock_fence(struct dma_fence *f) {
|
||||
return container_of(f, struct mock_fence, base);
|
||||
}
|
||||
|
||||
static const char *mock_name(struct dma_fence *f)
|
||||
{
|
||||
return "mock";
|
||||
}
|
||||
|
||||
static const struct dma_fence_ops mock_ops = {
|
||||
.get_driver_name = mock_name,
|
||||
.get_timeline_name = mock_name,
|
||||
};
|
||||
|
||||
static struct dma_fence *mock_fence(void)
|
||||
{
|
||||
struct mock_fence *f;
|
||||
|
||||
f = kmalloc(sizeof(*f), GFP_KERNEL);
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
spin_lock_init(&f->lock);
|
||||
dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
|
||||
|
||||
return &f->base;
|
||||
}
|
||||
|
||||
static struct dma_fence *mock_array(unsigned int num_fences, ...)
|
||||
{
|
||||
struct dma_fence_array *array;
|
||||
struct dma_fence **fences;
|
||||
va_list valist;
|
||||
int i;
|
||||
|
||||
fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
|
||||
if (!fences)
|
||||
return NULL;
|
||||
|
||||
va_start(valist, num_fences);
|
||||
for (i = 0; i < num_fences; ++i)
|
||||
fences[i] = va_arg(valist, typeof(*fences));
|
||||
va_end(valist);
|
||||
|
||||
array = dma_fence_array_create(num_fences, fences,
|
||||
dma_fence_context_alloc(1),
|
||||
1, false);
|
||||
if (!array)
|
||||
goto cleanup;
|
||||
return &array->base;
|
||||
|
||||
cleanup:
|
||||
for (i = 0; i < num_fences; ++i)
|
||||
dma_fence_put(fences[i]);
|
||||
kfree(fences);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dma_fence *mock_chain(struct dma_fence *prev,
|
||||
struct dma_fence *fence)
|
||||
{
|
||||
struct dma_fence_chain *f;
|
||||
|
||||
f = dma_fence_chain_alloc();
|
||||
if (!f) {
|
||||
dma_fence_put(prev);
|
||||
dma_fence_put(fence);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dma_fence_chain_init(f, prev, fence, 1);
|
||||
return &f->base;
|
||||
}
|
||||
|
||||
static int sanitycheck(void *arg)
|
||||
{
|
||||
struct dma_fence *f, *chain, *array;
|
||||
int err = 0;
|
||||
|
||||
f = mock_fence();
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
array = mock_array(1, f);
|
||||
if (!array)
|
||||
return -ENOMEM;
|
||||
|
||||
chain = mock_chain(NULL, array);
|
||||
if (!chain)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_fence_signal(f);
|
||||
dma_fence_put(chain);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int unwrap_array(void *arg)
|
||||
{
|
||||
struct dma_fence *fence, *f1, *f2, *array;
|
||||
struct dma_fence_unwrap iter;
|
||||
int err = 0;
|
||||
|
||||
f1 = mock_fence();
|
||||
if (!f1)
|
||||
return -ENOMEM;
|
||||
|
||||
f2 = mock_fence();
|
||||
if (!f2) {
|
||||
dma_fence_put(f1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
array = mock_array(2, f1, f2);
|
||||
if (!array)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_fence_unwrap_for_each(fence, &iter, array) {
|
||||
if (fence == f1) {
|
||||
f1 = NULL;
|
||||
} else if (fence == f2) {
|
||||
f2 = NULL;
|
||||
} else {
|
||||
pr_err("Unexpected fence!\n");
|
||||
err = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (f1 || f2) {
|
||||
pr_err("Not all fences seen!\n");
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
dma_fence_signal(f1);
|
||||
dma_fence_signal(f2);
|
||||
dma_fence_put(array);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unwrap_chain(void *arg)
|
||||
{
|
||||
struct dma_fence *fence, *f1, *f2, *chain;
|
||||
struct dma_fence_unwrap iter;
|
||||
int err = 0;
|
||||
|
||||
f1 = mock_fence();
|
||||
if (!f1)
|
||||
return -ENOMEM;
|
||||
|
||||
f2 = mock_fence();
|
||||
if (!f2) {
|
||||
dma_fence_put(f1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
chain = mock_chain(f1, f2);
|
||||
if (!chain)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_fence_unwrap_for_each(fence, &iter, chain) {
|
||||
if (fence == f1) {
|
||||
f1 = NULL;
|
||||
} else if (fence == f2) {
|
||||
f2 = NULL;
|
||||
} else {
|
||||
pr_err("Unexpected fence!\n");
|
||||
err = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (f1 || f2) {
|
||||
pr_err("Not all fences seen!\n");
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
dma_fence_signal(f1);
|
||||
dma_fence_signal(f2);
|
||||
dma_fence_put(chain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unwrap_chain_array(void *arg)
|
||||
{
|
||||
struct dma_fence *fence, *f1, *f2, *array, *chain;
|
||||
struct dma_fence_unwrap iter;
|
||||
int err = 0;
|
||||
|
||||
f1 = mock_fence();
|
||||
if (!f1)
|
||||
return -ENOMEM;
|
||||
|
||||
f2 = mock_fence();
|
||||
if (!f2) {
|
||||
dma_fence_put(f1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
array = mock_array(2, f1, f2);
|
||||
if (!array)
|
||||
return -ENOMEM;
|
||||
|
||||
chain = mock_chain(NULL, array);
|
||||
if (!chain)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_fence_unwrap_for_each(fence, &iter, chain) {
|
||||
if (fence == f1) {
|
||||
f1 = NULL;
|
||||
} else if (fence == f2) {
|
||||
f2 = NULL;
|
||||
} else {
|
||||
pr_err("Unexpected fence!\n");
|
||||
err = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (f1 || f2) {
|
||||
pr_err("Not all fences seen!\n");
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
dma_fence_signal(f1);
|
||||
dma_fence_signal(f2);
|
||||
dma_fence_put(chain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dma_fence_unwrap(void)
|
||||
{
|
||||
static const struct subtest tests[] = {
|
||||
SUBTEST(sanitycheck),
|
||||
SUBTEST(unwrap_array),
|
||||
SUBTEST(unwrap_chain),
|
||||
SUBTEST(unwrap_chain_array),
|
||||
};
|
||||
|
||||
return subtests(tests, NULL);
|
||||
}
|
@ -58,8 +58,9 @@ static int sanitycheck(void *arg)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int test_signaling(void *arg, bool shared)
|
||||
static int test_signaling(void *arg)
|
||||
{
|
||||
enum dma_resv_usage usage = (unsigned long)arg;
|
||||
struct dma_resv resv;
|
||||
struct dma_fence *f;
|
||||
int r;
|
||||
@ -75,25 +76,20 @@ static int test_signaling(void *arg, bool shared)
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (shared) {
|
||||
r = dma_resv_reserve_shared(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
dma_resv_add_shared_fence(&resv, f);
|
||||
} else {
|
||||
dma_resv_add_excl_fence(&resv, f);
|
||||
r = dma_resv_reserve_fences(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
if (dma_resv_test_signaled(&resv, shared)) {
|
||||
dma_resv_add_fence(&resv, f, usage);
|
||||
if (dma_resv_test_signaled(&resv, usage)) {
|
||||
pr_err("Resv unexpectedly signaled\n");
|
||||
r = -EINVAL;
|
||||
goto err_unlock;
|
||||
}
|
||||
dma_fence_signal(f);
|
||||
if (!dma_resv_test_signaled(&resv, shared)) {
|
||||
if (!dma_resv_test_signaled(&resv, usage)) {
|
||||
pr_err("Resv not reporting signaled\n");
|
||||
r = -EINVAL;
|
||||
goto err_unlock;
|
||||
@ -106,18 +102,9 @@ err_free:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int test_excl_signaling(void *arg)
|
||||
{
|
||||
return test_signaling(arg, false);
|
||||
}
|
||||
|
||||
static int test_shared_signaling(void *arg)
|
||||
{
|
||||
return test_signaling(arg, true);
|
||||
}
|
||||
|
||||
static int test_for_each(void *arg, bool shared)
|
||||
static int test_for_each(void *arg)
|
||||
{
|
||||
enum dma_resv_usage usage = (unsigned long)arg;
|
||||
struct dma_resv_iter cursor;
|
||||
struct dma_fence *f, *fence;
|
||||
struct dma_resv resv;
|
||||
@ -134,20 +121,16 @@ static int test_for_each(void *arg, bool shared)
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (shared) {
|
||||
r = dma_resv_reserve_shared(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
dma_resv_add_shared_fence(&resv, f);
|
||||
} else {
|
||||
dma_resv_add_excl_fence(&resv, f);
|
||||
r = dma_resv_reserve_fences(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
dma_resv_add_fence(&resv, f, usage);
|
||||
|
||||
r = -ENOENT;
|
||||
dma_resv_for_each_fence(&cursor, &resv, shared, fence) {
|
||||
dma_resv_for_each_fence(&cursor, &resv, usage, fence) {
|
||||
if (!r) {
|
||||
pr_err("More than one fence found\n");
|
||||
r = -EINVAL;
|
||||
@ -158,7 +141,7 @@ static int test_for_each(void *arg, bool shared)
|
||||
r = -EINVAL;
|
||||
goto err_unlock;
|
||||
}
|
||||
if (dma_resv_iter_is_exclusive(&cursor) != !shared) {
|
||||
if (dma_resv_iter_usage(&cursor) != usage) {
|
||||
pr_err("Unexpected fence usage\n");
|
||||
r = -EINVAL;
|
||||
goto err_unlock;
|
||||
@ -178,18 +161,9 @@ err_free:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int test_excl_for_each(void *arg)
|
||||
{
|
||||
return test_for_each(arg, false);
|
||||
}
|
||||
|
||||
static int test_shared_for_each(void *arg)
|
||||
{
|
||||
return test_for_each(arg, true);
|
||||
}
|
||||
|
||||
static int test_for_each_unlocked(void *arg, bool shared)
|
||||
static int test_for_each_unlocked(void *arg)
|
||||
{
|
||||
enum dma_resv_usage usage = (unsigned long)arg;
|
||||
struct dma_resv_iter cursor;
|
||||
struct dma_fence *f, *fence;
|
||||
struct dma_resv resv;
|
||||
@ -206,22 +180,18 @@ static int test_for_each_unlocked(void *arg, bool shared)
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (shared) {
|
||||
r = dma_resv_reserve_shared(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
dma_resv_unlock(&resv);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
dma_resv_add_shared_fence(&resv, f);
|
||||
} else {
|
||||
dma_resv_add_excl_fence(&resv, f);
|
||||
r = dma_resv_reserve_fences(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
dma_resv_unlock(&resv);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
dma_resv_add_fence(&resv, f, usage);
|
||||
dma_resv_unlock(&resv);
|
||||
|
||||
r = -ENOENT;
|
||||
dma_resv_iter_begin(&cursor, &resv, shared);
|
||||
dma_resv_iter_begin(&cursor, &resv, usage);
|
||||
dma_resv_for_each_fence_unlocked(&cursor, fence) {
|
||||
if (!r) {
|
||||
pr_err("More than one fence found\n");
|
||||
@ -237,7 +207,7 @@ static int test_for_each_unlocked(void *arg, bool shared)
|
||||
r = -EINVAL;
|
||||
goto err_iter_end;
|
||||
}
|
||||
if (dma_resv_iter_is_exclusive(&cursor) != !shared) {
|
||||
if (dma_resv_iter_usage(&cursor) != usage) {
|
||||
pr_err("Unexpected fence usage\n");
|
||||
r = -EINVAL;
|
||||
goto err_iter_end;
|
||||
@ -247,7 +217,7 @@ static int test_for_each_unlocked(void *arg, bool shared)
|
||||
if (r == -ENOENT) {
|
||||
r = -EINVAL;
|
||||
/* That should trigger an restart */
|
||||
cursor.seq--;
|
||||
cursor.fences = (void*)~0;
|
||||
} else if (r == -EINVAL) {
|
||||
r = 0;
|
||||
}
|
||||
@ -263,18 +233,9 @@ err_free:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int test_excl_for_each_unlocked(void *arg)
|
||||
{
|
||||
return test_for_each_unlocked(arg, false);
|
||||
}
|
||||
|
||||
static int test_shared_for_each_unlocked(void *arg)
|
||||
{
|
||||
return test_for_each_unlocked(arg, true);
|
||||
}
|
||||
|
||||
static int test_get_fences(void *arg, bool shared)
|
||||
static int test_get_fences(void *arg)
|
||||
{
|
||||
enum dma_resv_usage usage = (unsigned long)arg;
|
||||
struct dma_fence *f, **fences = NULL;
|
||||
struct dma_resv resv;
|
||||
int r, i;
|
||||
@ -290,21 +251,17 @@ static int test_get_fences(void *arg, bool shared)
|
||||
goto err_resv;
|
||||
}
|
||||
|
||||
if (shared) {
|
||||
r = dma_resv_reserve_shared(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
dma_resv_unlock(&resv);
|
||||
goto err_resv;
|
||||
}
|
||||
|
||||
dma_resv_add_shared_fence(&resv, f);
|
||||
} else {
|
||||
dma_resv_add_excl_fence(&resv, f);
|
||||
r = dma_resv_reserve_fences(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
dma_resv_unlock(&resv);
|
||||
goto err_resv;
|
||||
}
|
||||
|
||||
dma_resv_add_fence(&resv, f, usage);
|
||||
dma_resv_unlock(&resv);
|
||||
|
||||
r = dma_resv_get_fences(&resv, shared, &i, &fences);
|
||||
r = dma_resv_get_fences(&resv, usage, &i, &fences);
|
||||
if (r) {
|
||||
pr_err("get_fences failed\n");
|
||||
goto err_free;
|
||||
@ -326,30 +283,24 @@ err_resv:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int test_excl_get_fences(void *arg)
|
||||
{
|
||||
return test_get_fences(arg, false);
|
||||
}
|
||||
|
||||
static int test_shared_get_fences(void *arg)
|
||||
{
|
||||
return test_get_fences(arg, true);
|
||||
}
|
||||
|
||||
int dma_resv(void)
|
||||
{
|
||||
static const struct subtest tests[] = {
|
||||
SUBTEST(sanitycheck),
|
||||
SUBTEST(test_excl_signaling),
|
||||
SUBTEST(test_shared_signaling),
|
||||
SUBTEST(test_excl_for_each),
|
||||
SUBTEST(test_shared_for_each),
|
||||
SUBTEST(test_excl_for_each_unlocked),
|
||||
SUBTEST(test_shared_for_each_unlocked),
|
||||
SUBTEST(test_excl_get_fences),
|
||||
SUBTEST(test_shared_get_fences),
|
||||
SUBTEST(test_signaling),
|
||||
SUBTEST(test_for_each),
|
||||
SUBTEST(test_for_each_unlocked),
|
||||
SUBTEST(test_get_fences),
|
||||
};
|
||||
enum dma_resv_usage usage;
|
||||
int r;
|
||||
|
||||
spin_lock_init(&fence_lock);
|
||||
return subtests(tests, NULL);
|
||||
for (usage = DMA_RESV_USAGE_KERNEL; usage <= DMA_RESV_USAGE_BOOKKEEP;
|
||||
++usage) {
|
||||
r = subtests(tests, (void *)(unsigned long)usage);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright (C) 2012 Google, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/dma-fence-unwrap.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
@ -172,20 +173,6 @@ static int sync_file_set_fence(struct sync_file *sync_file,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dma_fence **get_fences(struct sync_file *sync_file,
|
||||
int *num_fences)
|
||||
{
|
||||
if (dma_fence_is_array(sync_file->fence)) {
|
||||
struct dma_fence_array *array = to_dma_fence_array(sync_file->fence);
|
||||
|
||||
*num_fences = array->num_fences;
|
||||
return array->fences;
|
||||
}
|
||||
|
||||
*num_fences = 1;
|
||||
return &sync_file->fence;
|
||||
}
|
||||
|
||||
static void add_fence(struct dma_fence **fences,
|
||||
int *i, struct dma_fence *fence)
|
||||
{
|
||||
@ -210,86 +197,97 @@ static void add_fence(struct dma_fence **fences,
|
||||
static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
|
||||
struct sync_file *b)
|
||||
{
|
||||
struct dma_fence *a_fence, *b_fence, **fences;
|
||||
struct dma_fence_unwrap a_iter, b_iter;
|
||||
unsigned int index, num_fences;
|
||||
struct sync_file *sync_file;
|
||||
struct dma_fence **fences = NULL, **nfences, **a_fences, **b_fences;
|
||||
int i = 0, i_a, i_b, num_fences, a_num_fences, b_num_fences;
|
||||
|
||||
sync_file = sync_file_alloc();
|
||||
if (!sync_file)
|
||||
return NULL;
|
||||
|
||||
a_fences = get_fences(a, &a_num_fences);
|
||||
b_fences = get_fences(b, &b_num_fences);
|
||||
if (a_num_fences > INT_MAX - b_num_fences)
|
||||
goto err;
|
||||
num_fences = 0;
|
||||
dma_fence_unwrap_for_each(a_fence, &a_iter, a->fence)
|
||||
++num_fences;
|
||||
dma_fence_unwrap_for_each(b_fence, &b_iter, b->fence)
|
||||
++num_fences;
|
||||
|
||||
num_fences = a_num_fences + b_num_fences;
|
||||
if (num_fences > INT_MAX)
|
||||
goto err_free_sync_file;
|
||||
|
||||
fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
|
||||
if (!fences)
|
||||
goto err;
|
||||
goto err_free_sync_file;
|
||||
|
||||
/*
|
||||
* Assume sync_file a and b are both ordered and have no
|
||||
* duplicates with the same context.
|
||||
* We can't guarantee that fences in both a and b are ordered, but it is
|
||||
* still quite likely.
|
||||
*
|
||||
* If a sync_file can only be created with sync_file_merge
|
||||
* and sync_file_create, this is a reasonable assumption.
|
||||
* So attempt to order the fences as we pass over them and merge fences
|
||||
* with the same context.
|
||||
*/
|
||||
for (i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) {
|
||||
struct dma_fence *pt_a = a_fences[i_a];
|
||||
struct dma_fence *pt_b = b_fences[i_b];
|
||||
|
||||
if (pt_a->context < pt_b->context) {
|
||||
add_fence(fences, &i, pt_a);
|
||||
index = 0;
|
||||
for (a_fence = dma_fence_unwrap_first(a->fence, &a_iter),
|
||||
b_fence = dma_fence_unwrap_first(b->fence, &b_iter);
|
||||
a_fence || b_fence; ) {
|
||||
|
||||
i_a++;
|
||||
} else if (pt_a->context > pt_b->context) {
|
||||
add_fence(fences, &i, pt_b);
|
||||
if (!b_fence) {
|
||||
add_fence(fences, &index, a_fence);
|
||||
a_fence = dma_fence_unwrap_next(&a_iter);
|
||||
|
||||
} else if (!a_fence) {
|
||||
add_fence(fences, &index, b_fence);
|
||||
b_fence = dma_fence_unwrap_next(&b_iter);
|
||||
|
||||
} else if (a_fence->context < b_fence->context) {
|
||||
add_fence(fences, &index, a_fence);
|
||||
a_fence = dma_fence_unwrap_next(&a_iter);
|
||||
|
||||
} else if (b_fence->context < a_fence->context) {
|
||||
add_fence(fences, &index, b_fence);
|
||||
b_fence = dma_fence_unwrap_next(&b_iter);
|
||||
|
||||
} else if (__dma_fence_is_later(a_fence->seqno, b_fence->seqno,
|
||||
a_fence->ops)) {
|
||||
add_fence(fences, &index, a_fence);
|
||||
a_fence = dma_fence_unwrap_next(&a_iter);
|
||||
b_fence = dma_fence_unwrap_next(&b_iter);
|
||||
|
||||
i_b++;
|
||||
} else {
|
||||
if (__dma_fence_is_later(pt_a->seqno, pt_b->seqno,
|
||||
pt_a->ops))
|
||||
add_fence(fences, &i, pt_a);
|
||||
else
|
||||
add_fence(fences, &i, pt_b);
|
||||
|
||||
i_a++;
|
||||
i_b++;
|
||||
add_fence(fences, &index, b_fence);
|
||||
a_fence = dma_fence_unwrap_next(&a_iter);
|
||||
b_fence = dma_fence_unwrap_next(&b_iter);
|
||||
}
|
||||
}
|
||||
|
||||
for (; i_a < a_num_fences; i_a++)
|
||||
add_fence(fences, &i, a_fences[i_a]);
|
||||
if (index == 0)
|
||||
fences[index++] = dma_fence_get_stub();
|
||||
|
||||
for (; i_b < b_num_fences; i_b++)
|
||||
add_fence(fences, &i, b_fences[i_b]);
|
||||
if (num_fences > index) {
|
||||
struct dma_fence **tmp;
|
||||
|
||||
if (i == 0)
|
||||
fences[i++] = dma_fence_get(a_fences[0]);
|
||||
|
||||
if (num_fences > i) {
|
||||
nfences = krealloc_array(fences, i, sizeof(*fences), GFP_KERNEL);
|
||||
if (!nfences)
|
||||
goto err;
|
||||
|
||||
fences = nfences;
|
||||
/* Keep going even when reducing the size failed */
|
||||
tmp = krealloc_array(fences, index, sizeof(*fences),
|
||||
GFP_KERNEL);
|
||||
if (tmp)
|
||||
fences = tmp;
|
||||
}
|
||||
|
||||
if (sync_file_set_fence(sync_file, fences, i) < 0)
|
||||
goto err;
|
||||
if (sync_file_set_fence(sync_file, fences, index) < 0)
|
||||
goto err_put_fences;
|
||||
|
||||
strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
|
||||
return sync_file;
|
||||
|
||||
err:
|
||||
while (i)
|
||||
dma_fence_put(fences[--i]);
|
||||
err_put_fences:
|
||||
while (index)
|
||||
dma_fence_put(fences[--index]);
|
||||
kfree(fences);
|
||||
|
||||
err_free_sync_file:
|
||||
fput(sync_file->file);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static int sync_file_release(struct inode *inode, struct file *file)
|
||||
@ -398,11 +396,13 @@ static int sync_fill_fence_info(struct dma_fence *fence,
|
||||
static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct sync_file_info info;
|
||||
struct sync_fence_info *fence_info = NULL;
|
||||
struct dma_fence **fences;
|
||||
struct dma_fence_unwrap iter;
|
||||
struct sync_file_info info;
|
||||
unsigned int num_fences;
|
||||
struct dma_fence *fence;
|
||||
int ret;
|
||||
__u32 size;
|
||||
int num_fences, ret, i;
|
||||
|
||||
if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
|
||||
return -EFAULT;
|
||||
@ -410,7 +410,9 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
|
||||
if (info.flags || info.pad)
|
||||
return -EINVAL;
|
||||
|
||||
fences = get_fences(sync_file, &num_fences);
|
||||
num_fences = 0;
|
||||
dma_fence_unwrap_for_each(fence, &iter, sync_file->fence)
|
||||
++num_fences;
|
||||
|
||||
/*
|
||||
* Passing num_fences = 0 means that userspace doesn't want to
|
||||
@ -433,8 +435,11 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
|
||||
if (!fence_info)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num_fences; i++) {
|
||||
int status = sync_fill_fence_info(fences[i], &fence_info[i]);
|
||||
num_fences = 0;
|
||||
dma_fence_unwrap_for_each(fence, &iter, sync_file->fence) {
|
||||
int status;
|
||||
|
||||
status = sync_fill_fence_info(fence, &fence_info[num_fences++]);
|
||||
info.status = info.status <= 0 ? info.status : status;
|
||||
}
|
||||
|
||||
|
@ -219,12 +219,12 @@ config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
|
||||
|
||||
config SYSFB
|
||||
bool
|
||||
default y
|
||||
depends on X86 || EFI
|
||||
select BOOT_VESA_SUPPORT
|
||||
|
||||
config SYSFB_SIMPLEFB
|
||||
bool "Mark VGA/VBE/EFI FB as generic system framebuffer"
|
||||
depends on SYSFB
|
||||
depends on X86 || EFI
|
||||
select SYSFB
|
||||
help
|
||||
Firmwares often provide initial graphics framebuffers so the BIOS,
|
||||
bootloader or kernel can show basic video-output during boot for
|
||||
|
@ -1404,6 +1404,16 @@ static int gpiochip_to_irq(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct irq_domain *domain = gc->irq.domain;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB_IRQCHIP
|
||||
/*
|
||||
* Avoid race condition with other code, which tries to lookup
|
||||
* an IRQ before the irqchip has been properly registered,
|
||||
* i.e. while gpiochip is still being brought up.
|
||||
*/
|
||||
if (!gc->irq.initialized)
|
||||
return -EPROBE_DEFER;
|
||||
#endif
|
||||
|
||||
if (!gpiochip_irqchip_irq_valid(gc, offset))
|
||||
return -ENXIO;
|
||||
|
||||
@ -1593,6 +1603,15 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc,
|
||||
|
||||
acpi_gpiochip_request_interrupts(gc);
|
||||
|
||||
/*
|
||||
* Using barrier() here to prevent compiler from reordering
|
||||
* gc->irq.initialized before initialization of above
|
||||
* GPIO chip irq members.
|
||||
*/
|
||||
barrier();
|
||||
|
||||
gc->irq.initialized = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -280,6 +280,7 @@ config DRM_AMDGPU
|
||||
select HWMON
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
select INTERVAL_TREE
|
||||
select DRM_BUDDY
|
||||
help
|
||||
Choose this option if you have a recent AMD Radeon graphics card.
|
||||
|
||||
|
@ -119,6 +119,7 @@
|
||||
#define CONNECTOR_OBJECT_ID_eDP 0x14
|
||||
#define CONNECTOR_OBJECT_ID_MXM 0x15
|
||||
#define CONNECTOR_OBJECT_ID_LVDS_eDP 0x16
|
||||
#define CONNECTOR_OBJECT_ID_USBC 0x17
|
||||
|
||||
/* deleted */
|
||||
|
||||
|
@ -253,53 +253,18 @@ void amdgpu_amdkfd_release_notify(struct amdgpu_bo *bo)
|
||||
static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
|
||||
struct amdgpu_amdkfd_fence *ef)
|
||||
{
|
||||
struct dma_resv *resv = bo->tbo.base.resv;
|
||||
struct dma_resv_list *old, *new;
|
||||
unsigned int i, j, k;
|
||||
struct dma_fence *replacement;
|
||||
|
||||
if (!ef)
|
||||
return -EINVAL;
|
||||
|
||||
old = dma_resv_shared_list(resv);
|
||||
if (!old)
|
||||
return 0;
|
||||
|
||||
new = kmalloc(struct_size(new, shared, old->shared_max), GFP_KERNEL);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Go through all the shared fences in the resevation object and sort
|
||||
* the interesting ones to the end of the list.
|
||||
/* TODO: Instead of block before we should use the fence of the page
|
||||
* table update and TLB flush here directly.
|
||||
*/
|
||||
for (i = 0, j = old->shared_count, k = 0; i < old->shared_count; ++i) {
|
||||
struct dma_fence *f;
|
||||
|
||||
f = rcu_dereference_protected(old->shared[i],
|
||||
dma_resv_held(resv));
|
||||
|
||||
if (f->context == ef->base.context)
|
||||
RCU_INIT_POINTER(new->shared[--j], f);
|
||||
else
|
||||
RCU_INIT_POINTER(new->shared[k++], f);
|
||||
}
|
||||
new->shared_max = old->shared_max;
|
||||
new->shared_count = k;
|
||||
|
||||
/* Install the new fence list, seqcount provides the barriers */
|
||||
write_seqcount_begin(&resv->seq);
|
||||
RCU_INIT_POINTER(resv->fence, new);
|
||||
write_seqcount_end(&resv->seq);
|
||||
|
||||
/* Drop the references to the removed fences or move them to ef_list */
|
||||
for (i = j; i < old->shared_count; ++i) {
|
||||
struct dma_fence *f;
|
||||
|
||||
f = rcu_dereference_protected(new->shared[i],
|
||||
dma_resv_held(resv));
|
||||
dma_fence_put(f);
|
||||
}
|
||||
kfree_rcu(old, rcu);
|
||||
|
||||
replacement = dma_fence_get_stub();
|
||||
dma_resv_replace_fences(bo->tbo.base.resv, ef->base.context,
|
||||
replacement, DMA_RESV_USAGE_READ);
|
||||
dma_fence_put(replacement);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1268,7 +1233,7 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info,
|
||||
AMDGPU_FENCE_OWNER_KFD, false);
|
||||
if (ret)
|
||||
goto wait_pd_fail;
|
||||
ret = dma_resv_reserve_shared(vm->root.bo->tbo.base.resv, 1);
|
||||
ret = dma_resv_reserve_fences(vm->root.bo->tbo.base.resv, 1);
|
||||
if (ret)
|
||||
goto reserve_shared_fail;
|
||||
amdgpu_bo_fence(vm->root.bo,
|
||||
@ -2482,6 +2447,8 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef)
|
||||
struct amdgpu_bo *bo = mem->bo;
|
||||
uint32_t domain = mem->domain;
|
||||
struct kfd_mem_attachment *attachment;
|
||||
struct dma_resv_iter cursor;
|
||||
struct dma_fence *fence;
|
||||
|
||||
total_size += amdgpu_bo_size(bo);
|
||||
|
||||
@ -2496,10 +2463,13 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef)
|
||||
goto validate_map_fail;
|
||||
}
|
||||
}
|
||||
ret = amdgpu_sync_fence(&sync_obj, bo->tbo.moving);
|
||||
if (ret) {
|
||||
pr_debug("Memory eviction: Sync BO fence failed. Try again\n");
|
||||
goto validate_map_fail;
|
||||
dma_resv_for_each_fence(&cursor, bo->tbo.base.resv,
|
||||
DMA_RESV_USAGE_KERNEL, fence) {
|
||||
ret = amdgpu_sync_fence(&sync_obj, fence);
|
||||
if (ret) {
|
||||
pr_debug("Memory eviction: Sync BO fence failed. Try again\n");
|
||||
goto validate_map_fail;
|
||||
}
|
||||
}
|
||||
list_for_each_entry(attachment, &mem->attachments, list) {
|
||||
if (!attachment->is_mapped)
|
||||
@ -2606,7 +2576,7 @@ int amdgpu_amdkfd_add_gws_to_process(void *info, void *gws, struct kgd_mem **mem
|
||||
* Add process eviction fence to bo so they can
|
||||
* evict each other.
|
||||
*/
|
||||
ret = dma_resv_reserve_shared(gws_bo->tbo.base.resv, 1);
|
||||
ret = dma_resv_reserve_fences(gws_bo->tbo.base.resv, 1);
|
||||
if (ret)
|
||||
goto reserve_shared_fail;
|
||||
amdgpu_bo_fence(gws_bo, &process_info->eviction_fence->base, true);
|
||||
|
@ -34,7 +34,6 @@ struct amdgpu_fpriv;
|
||||
struct amdgpu_bo_list_entry {
|
||||
struct ttm_validate_buffer tv;
|
||||
struct amdgpu_bo_va *bo_va;
|
||||
struct dma_fence_chain *chain;
|
||||
uint32_t priority;
|
||||
struct page **user_pages;
|
||||
bool user_invalidated;
|
||||
|
@ -55,8 +55,8 @@ static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p,
|
||||
bo = amdgpu_bo_ref(gem_to_amdgpu_bo(gobj));
|
||||
p->uf_entry.priority = 0;
|
||||
p->uf_entry.tv.bo = &bo->tbo;
|
||||
/* One for TTM and one for the CS job */
|
||||
p->uf_entry.tv.num_shared = 2;
|
||||
/* One for TTM and two for the CS job */
|
||||
p->uf_entry.tv.num_shared = 3;
|
||||
|
||||
drm_gem_object_put(gobj);
|
||||
|
||||
@ -574,14 +574,6 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
|
||||
struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo);
|
||||
|
||||
e->bo_va = amdgpu_vm_bo_find(vm, bo);
|
||||
|
||||
if (bo->tbo.base.dma_buf && !amdgpu_bo_explicit_sync(bo)) {
|
||||
e->chain = dma_fence_chain_alloc();
|
||||
if (!e->chain) {
|
||||
r = -ENOMEM;
|
||||
goto error_validate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Move fence waiting after getting reservation lock of
|
||||
@ -642,13 +634,8 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
|
||||
}
|
||||
|
||||
error_validate:
|
||||
if (r) {
|
||||
amdgpu_bo_list_for_each_entry(e, p->bo_list) {
|
||||
dma_fence_chain_free(e->chain);
|
||||
e->chain = NULL;
|
||||
}
|
||||
if (r)
|
||||
ttm_eu_backoff_reservation(&p->ticket, &p->validated);
|
||||
}
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
@ -688,17 +675,9 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error,
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (error && backoff) {
|
||||
struct amdgpu_bo_list_entry *e;
|
||||
|
||||
amdgpu_bo_list_for_each_entry(e, parser->bo_list) {
|
||||
dma_fence_chain_free(e->chain);
|
||||
e->chain = NULL;
|
||||
}
|
||||
|
||||
if (error && backoff)
|
||||
ttm_eu_backoff_reservation(&parser->ticket,
|
||||
&parser->validated);
|
||||
}
|
||||
|
||||
for (i = 0; i < parser->num_post_deps; i++) {
|
||||
drm_syncobj_put(parser->post_deps[i].syncobj);
|
||||
@ -1272,24 +1251,9 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
|
||||
|
||||
amdgpu_vm_move_to_lru_tail(p->adev, &fpriv->vm);
|
||||
|
||||
amdgpu_bo_list_for_each_entry(e, p->bo_list) {
|
||||
struct dma_resv *resv = e->tv.bo->base.resv;
|
||||
struct dma_fence_chain *chain = e->chain;
|
||||
|
||||
if (!chain)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Work around dma_resv shortcomings by wrapping up the
|
||||
* submission in a dma_fence_chain and add it as exclusive
|
||||
* fence.
|
||||
*/
|
||||
dma_fence_chain_init(chain, dma_resv_excl_fence(resv),
|
||||
dma_fence_get(p->fence), 1);
|
||||
|
||||
rcu_assign_pointer(resv->fence_excl, &chain->base);
|
||||
e->chain = NULL;
|
||||
}
|
||||
/* Make sure all BOs are remembered as writers */
|
||||
amdgpu_bo_list_for_each_entry(e, p->bo_list)
|
||||
e->tv.num_shared = 0;
|
||||
|
||||
ttm_eu_fence_buffer_objects(&p->ticket, &p->validated, p->fence);
|
||||
mutex_unlock(&p->adev->notifier_lock);
|
||||
|
@ -5733,7 +5733,7 @@ void amdgpu_device_flush_hdp(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
if ((adev->flags & AMD_IS_APU) && !amdgpu_passthrough(adev))
|
||||
return;
|
||||
#endif
|
||||
if (adev->gmc.xgmi.connected_to_cpu)
|
||||
@ -5749,7 +5749,7 @@ void amdgpu_device_invalidate_hdp(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
if ((adev->flags & AMD_IS_APU) && !amdgpu_passthrough(adev))
|
||||
return;
|
||||
#endif
|
||||
if (adev->gmc.xgmi.connected_to_cpu)
|
||||
|
@ -200,8 +200,7 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc,
|
||||
goto unpin;
|
||||
}
|
||||
|
||||
/* TODO: Unify this with other drivers */
|
||||
r = dma_resv_get_fences(new_abo->tbo.base.resv, true,
|
||||
r = dma_resv_get_fences(new_abo->tbo.base.resv, DMA_RESV_USAGE_WRITE,
|
||||
&work->shared_count,
|
||||
&work->shared);
|
||||
if (unlikely(r != 0)) {
|
||||
|
@ -102,21 +102,9 @@ static int amdgpu_dma_buf_pin(struct dma_buf_attachment *attach)
|
||||
{
|
||||
struct drm_gem_object *obj = attach->dmabuf->priv;
|
||||
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
|
||||
int r;
|
||||
|
||||
/* pin buffer into GTT */
|
||||
r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (bo->tbo.moving) {
|
||||
r = dma_fence_wait(bo->tbo.moving, true);
|
||||
if (r) {
|
||||
amdgpu_bo_unpin(bo);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user