Merge d2f51b3516 ("Merge tag 'rtc-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux") into android-mainline

Steps on the way to 6.7-rc1

Change-Id: I2a4d4491ef0eacf554f7b88efc56f1cc9166a5ac
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2023-11-07 15:09:38 +00:00
744 changed files with 34690 additions and 5422 deletions
-1
View File
@@ -74,7 +74,6 @@ modules.order
#
# RPM spec file (make rpm-pkg)
#
/kernel.spec
/rpmbuild/
#
+82
View File
@@ -0,0 +1,82 @@
What: /sys/kernel/config/tsm/report/$name/inblob
Date: September, 2023
KernelVersion: v6.7
Contact: linux-coco@lists.linux.dev
Description:
(WO) Up to 64 bytes of user specified binary data. For replay
protection this should include a nonce, but the kernel does not
place any restrictions on the content.
What: /sys/kernel/config/tsm/report/$name/outblob
Date: September, 2023
KernelVersion: v6.7
Contact: linux-coco@lists.linux.dev
Description:
(RO) Binary attestation report generated from @inblob and other
options The format of the report is implementation specific
where the implementation is conveyed via the @provider
attribute.
What: /sys/kernel/config/tsm/report/$name/auxblob
Date: October, 2023
KernelVersion: v6.7
Contact: linux-coco@lists.linux.dev
Description:
(RO) Optional supplemental data that a TSM may emit, visibility
of this attribute depends on TSM, and may be empty if no
auxiliary data is available.
When @provider is "sev_guest" this file contains the
"cert_table" from SEV-ES Guest-Hypervisor Communication Block
Standardization v2.03 Section 4.1.8.1 MSG_REPORT_REQ.
https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/56421.pdf
What: /sys/kernel/config/tsm/report/$name/provider
Date: September, 2023
KernelVersion: v6.7
Contact: linux-coco@lists.linux.dev
Description:
(RO) A name for the format-specification of @outblob like
"sev_guest" [1] or "tdx_guest" [2] in the near term, or a
common standard format in the future.
[1]: SEV Secure Nested Paging Firmware ABI Specification
Revision 1.55 Table 22
https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/56860.pdf
[2]: Intel® Trust Domain Extensions Data Center Attestation
Primitives : Quote Generation Library and Quote Verification
Library Revision 0.8 Appendix 4,5
https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_TDX_DCAP_Quoting_Library_API.pdf
What: /sys/kernel/config/tsm/report/$name/generation
Date: September, 2023
KernelVersion: v6.7
Contact: linux-coco@lists.linux.dev
Description:
(RO) The value in this attribute increments each time @inblob or
any option is written. Userspace can detect conflicts by
checking generation before writing to any attribute and making
sure the number of writes matches expectations after reading
@outblob, or it can prevent conflicts by creating a report
instance per requesting context.
What: /sys/kernel/config/tsm/report/$name/privlevel
Date: September, 2023
KernelVersion: v6.7
Contact: linux-coco@lists.linux.dev
Description:
(WO) Attribute is visible if a TSM implementation provider
supports the concept of attestation reports for TVMs running at
different privilege levels, like SEV-SNP "VMPL", specify the
privilege level via this attribute. The minimum acceptable
value is conveyed via @privlevel_floor and the maximum
acceptable value is TSM_PRIVLEVEL_MAX (3).
What: /sys/kernel/config/tsm/report/$name/privlevel_floor
Date: September, 2023
KernelVersion: v6.7
Contact: linux-coco@lists.linux.dev
Description:
(RO) Indicates the minimum permissible value that can be written
to @privlevel.
+30
View File
@@ -178,6 +178,21 @@ Description:
hardware decoder target list.
What: /sys/bus/cxl/devices/portX/decoders_committed
Date: October, 2023
KernelVersion: v6.7
Contact: linux-cxl@vger.kernel.org
Description:
(RO) A memory device is considered active when any of its
decoders are in the "committed" state (See CXL 3.0 8.2.4.19.7
CXL HDM Decoder n Control Register). Hotplug and destructive
operations like "sanitize" are blocked while device is actively
decoding a Host Physical Address range. Note that this number
may be elevated without any regionX objects active or even
enumerated, as this may be due to decoders established by
platform firwmare or a previous kernel (kexec).
What: /sys/bus/cxl/devices/decoderX.Y
Date: June, 2021
KernelVersion: v5.14
@@ -369,6 +384,21 @@ Description:
provided it is currently idle / not bound to a driver.
What: /sys/bus/cxl/devices/decoderX.Y/qos_class
Date: May, 2023
KernelVersion: v6.5
Contact: linux-cxl@vger.kernel.org
Description:
(RO) For CXL host platforms that support "QoS Telemmetry" this
root-decoder-only attribute conveys a platform specific cookie
that identifies a QoS performance class for the CXL Window.
This class-id can be compared against a similar "qos_class"
published for each memory-type that an endpoint supports. While
it is not required that endpoints map their local memory-class
to a matching platform class, mismatches are not recommended and
there are platform specific side-effects that may result.
What: /sys/bus/cxl/devices/regionZ/uuid
Date: May, 2022
KernelVersion: v6.0
+2 -2
View File
@@ -67,7 +67,7 @@ What: /sys/bus/i3c/devices/i3c-<bus-id>/pid
KernelVersion: 5.0
Contact: linux-i3c@vger.kernel.org
Description:
PID stands for Provisional ID and is used to uniquely identify
PID stands for Provisioned ID and is used to uniquely identify
a device on a bus. This PID contains information about the
vendor, the part and an instance ID so that several devices of
the same type can be connected on the same bus.
@@ -123,7 +123,7 @@ What: /sys/bus/i3c/devices/i3c-<bus-id>/<bus-id>-<device-pid>/pid
KernelVersion: 5.0
Contact: linux-i3c@vger.kernel.org
Description:
PID stands for Provisional ID and is used to uniquely identify
PID stands for Provisioned ID and is used to uniquely identify
a device on a bus. This PID contains information about the
vendor, the part and an instance ID so that several devices of
the same type can be connected on the same bus.
+2 -2
View File
@@ -1,4 +1,4 @@
What: /sys/bus/vdpa/driver_autoprobe
What: /sys/bus/vdpa/drivers_autoprobe
Date: March 2020
Contact: virtualization@lists.linux-foundation.org
Description:
@@ -17,7 +17,7 @@ Description:
Writing a device name to this file will cause the kernel binds
devices to a compatible driver.
This can be useful when /sys/bus/vdpa/driver_autoprobe is
This can be useful when /sys/bus/vdpa/drivers_autoprobe is
disabled.
What: /sys/bus/vdpa/drivers/.../bind
@@ -3337,6 +3337,11 @@
mga= [HW,DRM]
microcode.force_minrev= [X86]
Format: <bool>
Enable or disable the microcode minimal revision
enforcement for the runtime microcode loader.
min_addr=nn[KMG] [KNL,BOOT,IA-64] All physical memory below this
physical address is ignored.
@@ -68,10 +68,14 @@ properties:
pattern: cs16$
- items:
pattern: c32$
- items:
pattern: c32d-wl$
- items:
pattern: cs32$
- items:
pattern: c64$
- items:
pattern: c64d-wl$
- items:
pattern: cs64$
- items:
@@ -1,135 +0,0 @@
Pinctrl-based I2C Bus DeMux
This binding describes an I2C bus demultiplexer that uses pin multiplexing to
route the I2C signals, and represents the pin multiplexing configuration using
the pinctrl device tree bindings. This may be used to select one I2C IP core at
runtime which may have a better feature set for a given task than another I2C
IP core on the SoC. The most simple example is to fall back to GPIO bitbanging
if your current runtime configuration hits an errata of the internal IP core.
+-------------------------------+
| SoC |
| | +-----+ +-----+
| +------------+ | | dev | | dev |
| |I2C IP Core1|--\ | +-----+ +-----+
| +------------+ \-------+ | | |
| |Pinctrl|--|------+--------+
| +------------+ +-------+ |
| |I2C IP Core2|--/ |
| +------------+ |
| |
+-------------------------------+
Required properties:
- compatible: "i2c-demux-pinctrl"
- i2c-parent: List of phandles of I2C masters available for selection. The first
one will be used as default.
- i2c-bus-name: The name of this bus. Also needed as pinctrl-name for the I2C
parents.
Furthermore, I2C mux properties and child nodes. See i2c-mux.yaml in this
directory.
Example:
Here is a snipplet for a bus to be demuxed. It contains various i2c clients for
HDMI, so the bus is named "i2c-hdmi":
i2chdmi: i2c@8 {
compatible = "i2c-demux-pinctrl";
i2c-parent = <&gpioi2c>, <&iic2>, <&i2c2>;
i2c-bus-name = "i2c-hdmi";
#address-cells = <1>;
#size-cells = <0>;
ak4643: sound-codec@12 {
compatible = "asahi-kasei,ak4643";
#sound-dai-cells = <0>;
reg = <0x12>;
};
composite-in@20 {
compatible = "adi,adv7180";
reg = <0x20>;
remote = <&vin1>;
port {
adv7180: endpoint {
bus-width = <8>;
remote-endpoint = <&vin1ep0>;
};
};
};
hdmi@39 {
compatible = "adi,adv7511w";
reg = <0x39>;
interrupt-parent = <&gpio1>;
interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
adi,input-depth = <8>;
adi,input-colorspace = "rgb";
adi,input-clock = "1x";
adi,input-style = <1>;
adi,input-justification = "evenly";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
adv7511_in: endpoint {
remote-endpoint = <&du_out_lvds0>;
};
};
port@1 {
reg = <1>;
adv7511_out: endpoint {
remote-endpoint = <&hdmi_con>;
};
};
};
};
};
And for clarification, here are the snipplets for the i2c-parents:
gpioi2c: i2c@9 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "i2c-gpio";
gpios = <&gpio5 6 GPIO_ACTIVE_HIGH /* sda */
&gpio5 5 GPIO_ACTIVE_HIGH /* scl */
>;
i2c-gpio,delay-us = <5>;
};
...
&i2c2 {
pinctrl-0 = <&i2c2_pins>;
pinctrl-names = "i2c-hdmi";
clock-frequency = <100000>;
};
...
&iic2 {
pinctrl-0 = <&iic2_pins>;
pinctrl-names = "i2c-hdmi";
clock-frequency = <100000>;
};
Please note:
- pinctrl properties for the parent I2C controllers need a pinctrl state
with the same name as i2c-bus-name, not "default"!
- the i2c masters must have their status "disabled". This driver will
enable them at runtime when needed.
@@ -0,0 +1,172 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/i2c-demux-pinctrl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Pinctrl-based I2C Bus Demultiplexer
maintainers:
- Wolfram Sang <wsa+renesas@sang-engineering.com>
description: |
This binding describes an I2C bus demultiplexer that uses pin multiplexing to
route the I2C signals, and represents the pin multiplexing configuration
using the pinctrl device tree bindings. This may be used to select one I2C
IP core at runtime which may have a better feature set for a given task than
another I2C IP core on the SoC. The most simple example is to fall back to
GPIO bitbanging if your current runtime configuration hits an errata of the
internal IP core.
+-------------------------------+
| SoC |
| | +-----+ +-----+
| +------------+ | | dev | | dev |
| |I2C IP Core1|--\ | +-----+ +-----+
| +------------+ \-------+ | | |
| |Pinctrl|--|------+--------+
| +------------+ +-------+ |
| |I2C IP Core2|--/ |
| +------------+ |
| |
+-------------------------------+
allOf:
- $ref: i2c-mux.yaml
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
const: i2c-demux-pinctrl
i2c-parent:
$ref: /schemas/types.yaml#/definitions/phandle-array
description:
List of phandles of I2C masters available for selection. The first one
will be used as default.
i2c-bus-name:
$ref: /schemas/types.yaml#/definitions/string
description:
The name of this bus. Also needed as pinctrl-name for the I2C parents.
required:
- compatible
- i2c-parent
- i2c-bus-name
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
gpioi2c2: i2c-9 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "i2c-gpio";
scl-gpios = <&gpio5 5 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
sda-gpios = <&gpio5 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
i2c-gpio,delay-us = <5>;
// The I2C controller must have its status "disabled". The I2C bus
// demultiplexer will enable it at runtime when needed.
status = "disabled";
};
iic2: i2c@e6520000 {
reg = <0xe6520000 0x425>;
pinctrl-0 = <&iic2_pins>;
// The pinctrl property for the parent I2C controller needs a pinctrl
// state with the same name as i2c-bus-name in the I2C bus demultiplexer
// node, not "default"!
pinctrl-names = "i2c-hdmi";
clock-frequency = <100000>;
// The I2C controller must have its status "disabled". The I2C bus
// demultiplexer will enable it at runtime when needed.
status = "disabled";
};
i2c2: i2c@e6530000 {
reg = <0 0xe6530000 0 0x40>;
pinctrl-0 = <&i2c2_pins>;
// The pinctrl property for the parent I2C controller needs a pinctrl
// state with the same name as i2c-bus-name in the I2C bus demultiplexer
// node, not "default"!
pinctrl-names = "i2c-hdmi";
clock-frequency = <100000>;
// The I2C controller must have its status "disabled". The I2C bus
// demultiplexer will enable it at runtime when needed.
status = "disabled";
};
// Example for a bus to be demuxed. It contains various I2C clients for
// HDMI, so the bus is named "i2c-hdmi":
i2chdmi: i2c-mux3 {
compatible = "i2c-demux-pinctrl";
i2c-parent = <&iic2>, <&i2c2>, <&gpioi2c2>;
i2c-bus-name = "i2c-hdmi";
#address-cells = <1>;
#size-cells = <0>;
ak4643: codec@12 {
compatible = "asahi-kasei,ak4643";
#sound-dai-cells = <0>;
reg = <0x12>;
};
composite-in@20 {
compatible = "adi,adv7180";
reg = <0x20>;
port {
adv7180: endpoint {
bus-width = <8>;
remote-endpoint = <&vin1ep0>;
};
};
};
hdmi@39 {
compatible = "adi,adv7511w";
reg = <0x39>;
interrupt-parent = <&gpio1>;
interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
clocks = <&cec_clock>;
clock-names = "cec";
avdd-supply = <&fixedregulator1v8>;
dvdd-supply = <&fixedregulator1v8>;
pvdd-supply = <&fixedregulator1v8>;
dvdd-3v-supply = <&fixedregulator3v3>;
bgvdd-supply = <&fixedregulator1v8>;
adi,input-depth = <8>;
adi,input-colorspace = "rgb";
adi,input-clock = "1x";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
adv7511_in: endpoint {
remote-endpoint = <&lvds0_out>;
};
};
port@1 {
reg = <1>;
adv7511_out: endpoint {
remote-endpoint = <&hdmi_con_out>;
};
};
};
};
};
@@ -25,6 +25,7 @@ properties:
- items:
- enum:
- qcom,sc7280-cci
- qcom,sdm845-cci
- qcom,sm6350-cci
- qcom,sm8250-cci
@@ -159,6 +160,7 @@ allOf:
compatible:
contains:
enum:
- qcom,sc7280-cci
- qcom,sm8250-cci
- qcom,sm8450-cci
then:
@@ -125,12 +125,12 @@ patternProperties:
minimum: 0
maximum: 0x7f
- description: |
First half of the Provisional ID (following the PID
First half of the Provisioned ID (following the PID
definition provided by the I3C specification).
Contains the manufacturer ID left-shifted by 1.
- description: |
Second half of the Provisional ID (following the PID
Second half of the Provisioned ID (following the PID
definition provided by the I3C specification).
Contains the ORing of the part ID left-shifted by 16,
@@ -72,9 +72,9 @@ properties:
type : Channel type
channel : Channel number
This MU support 5 type of unidirectional channels, each type
This MU support 6 type of unidirectional channels, each type
has 4 channels except RST channel which only has 1 channel.
A total of 17 channels. Following types are
A total of 21 channels. Following types are
supported:
0 - TX channel with 32bit transmit register and IRQ transmit
acknowledgment support.
@@ -82,6 +82,7 @@ properties:
2 - TX doorbell channel. Without own register and no ACK support.
3 - RX doorbell channel.
4 - RST channel
5 - Tx doorbell channel. With S/W ACK from the other side.
const: 2
clocks:
@@ -125,10 +125,12 @@ allOf:
items:
- description: primary pll parent of the clock driver
- description: XO clock
- description: GCC GPLL0 clock source
clock-names:
items:
- const: pll
- const: xo
- const: gpll0
- if:
properties:
@@ -34,6 +34,7 @@ properties:
- qcom,sm8350-ipcc
- qcom,sm8450-ipcc
- qcom,sm8550-ipcc
- qcom,sm8650-ipcc
- const: qcom,ipcc
reg:
@@ -74,6 +74,10 @@ patternProperties:
type: object # DT nodes are json objects
additionalProperties: false
properties:
compatible:
const: xlnx,zynqmp-ipi-dest-mailbox
xlnx,ipi-id:
description:
Remote Xilinx IPI agent ID of which the mailbox is connected to.
@@ -95,6 +99,7 @@ patternProperties:
- const: remote_response_region
required:
- compatible
- reg
- reg-names
- "#mbox-cells"
@@ -124,6 +129,7 @@ examples:
ranges;
mailbox: mailbox@ff9905c0 {
compatible = "xlnx,zynqmp-ipi-dest-mailbox";
reg = <0x0 0xff9905c0 0x0 0x20>,
<0x0 0xff9905e0 0x0 0x20>,
<0x0 0xff990e80 0x0 0x20>,
@@ -148,47 +148,47 @@ examples:
pinctrl_nand: nand-pins {
function = "nand";
group = "nand_grp";
pins = "nand_grp";
};
pinctrl_gpio35_alt: gpio35_alt-pins {
function = "gpio35_alt";
pin = "gpio35";
pins = "gpio35";
};
pinctrl_dectpd: dectpd-pins {
function = "dectpd";
group = "dectpd_grp";
pins = "dectpd_grp";
};
pinctrl_vdsl_phy_override_0: vdsl_phy_override_0-pins {
function = "vdsl_phy_override_0";
group = "vdsl_phy_override_0_grp";
pins = "vdsl_phy_override_0_grp";
};
pinctrl_vdsl_phy_override_1: vdsl_phy_override_1-pins {
function = "vdsl_phy_override_1";
group = "vdsl_phy_override_1_grp";
pins = "vdsl_phy_override_1_grp";
};
pinctrl_vdsl_phy_override_2: vdsl_phy_override_2-pins {
function = "vdsl_phy_override_2";
group = "vdsl_phy_override_2_grp";
pins = "vdsl_phy_override_2_grp";
};
pinctrl_vdsl_phy_override_3: vdsl_phy_override_3-pins {
function = "vdsl_phy_override_3";
group = "vdsl_phy_override_3_grp";
pins = "vdsl_phy_override_3_grp";
};
pinctrl_dsl_gpio8: dsl_gpio8-pins {
function = "dsl_gpio8";
group = "dsl_gpio8";
pins = "dsl_gpio8";
};
pinctrl_dsl_gpio9: dsl_gpio9-pins {
function = "dsl_gpio9";
group = "dsl_gpio9";
pins = "dsl_gpio9";
};
};
};
@@ -230,7 +230,7 @@ examples:
pinctrl_nand: nand-pins {
function = "nand";
group = "nand_grp";
pins = "nand_grp";
};
};
};
@@ -240,7 +240,7 @@ examples:
pinctrl_uart1: uart1-pins {
function = "uart1";
group = "uart1_grp";
pins = "uart1_grp";
};
};
};
@@ -29,6 +29,24 @@ properties:
"#size-cells": true
compression:
$ref: /schemas/types.yaml#/definitions/string
description: |
Compression algorithm used to store the data in this partition, chosen
from a list of well-known algorithms.
The contents are compressed using this algorithm.
enum:
- none
- bzip2
- gzip
- lzop
- lz4
- lzma
- xz
- zstd
patternProperties:
"@[0-9a-f]+$":
$ref: partition.yaml#
@@ -64,6 +82,7 @@ examples:
uimage@100000 {
reg = <0x0100000 0x200000>;
compress = "lzma";
};
};
@@ -16,6 +16,7 @@ properties:
compatible:
enum:
- amlogic,c3-periphs-pinctrl
- amlogic,t7-periphs-pinctrl
- amlogic,meson-a1-periphs-pinctrl
- amlogic,meson-s4-periphs-pinctrl
@@ -24,6 +24,7 @@ patternProperties:
'-pins$':
type: object
$ref: pinmux-node.yaml#
additionalProperties: false
properties:
function:
@@ -37,6 +38,10 @@ patternProperties:
enum: [ gpio0, gpio1, gpio2, gpio3, gpio4, gpio5, gpio6, gpio7,
gpio8, gpio9, gpio10, gpio11, gpio12, gpio13, gpio40 ]
patternProperties:
'-pins$':
$ref: '#/patternProperties/-pins$'
allOf:
- $ref: pinctrl.yaml#
@@ -24,6 +24,7 @@ patternProperties:
'-pins$':
type: object
$ref: pinmux-node.yaml#
unevaluatedProperties: false
properties:
function:
@@ -36,11 +37,15 @@ patternProperties:
pins:
enum: [ gpio0, gpio1, gpio16, gpio17, gpio8, gpio9, gpio18, gpio19,
gpio22, gpio23, gpio30, gpio31, nand_grp, gpio35
gpio22, gpio23, gpio30, gpio31, nand_grp, gpio35,
dectpd_grp, vdsl_phy_override_0_grp,
vdsl_phy_override_1_grp, vdsl_phy_override_2_grp,
vdsl_phy_override_3_grp, dsl_gpio8, dsl_gpio9 ]
patternProperties:
'-pins$':
$ref: '#/patternProperties/-pins$'
allOf:
- $ref: pinctrl.yaml#
@@ -122,46 +127,46 @@ examples:
pinctrl_nand: nand-pins {
function = "nand";
group = "nand_grp";
pins = "nand_grp";
};
pinctrl_gpio35_alt: gpio35_alt-pins {
function = "gpio35_alt";
pin = "gpio35";
pins = "gpio35";
};
pinctrl_dectpd: dectpd-pins {
function = "dectpd";
group = "dectpd_grp";
pins = "dectpd_grp";
};
pinctrl_vdsl_phy_override_0: vdsl_phy_override_0-pins {
function = "vdsl_phy_override_0";
group = "vdsl_phy_override_0_grp";
pins = "vdsl_phy_override_0_grp";
};
pinctrl_vdsl_phy_override_1: vdsl_phy_override_1-pins {
function = "vdsl_phy_override_1";
group = "vdsl_phy_override_1_grp";
pins = "vdsl_phy_override_1_grp";
};
pinctrl_vdsl_phy_override_2: vdsl_phy_override_2-pins {
function = "vdsl_phy_override_2";
group = "vdsl_phy_override_2_grp";
pins = "vdsl_phy_override_2_grp";
};
pinctrl_vdsl_phy_override_3: vdsl_phy_override_3-pins {
function = "vdsl_phy_override_3";
group = "vdsl_phy_override_3_grp";
pins = "vdsl_phy_override_3_grp";
};
pinctrl_dsl_gpio8: dsl_gpio8-pins {
function = "dsl_gpio8";
group = "dsl_gpio8";
pins = "dsl_gpio8";
};
pinctrl_dsl_gpio9: dsl_gpio9-pins {
function = "dsl_gpio9";
group = "dsl_gpio9";
pins = "dsl_gpio9";
};
};
@@ -24,6 +24,7 @@ patternProperties:
'-pins$':
type: object
$ref: pinmux-node.yaml#
unevaluatedProperties: false
properties:
function:
@@ -36,6 +37,10 @@ patternProperties:
gpio20, gpio25, gpio26, gpio27, gpio28, hsspi_cs1,
usb_port1 ]
patternProperties:
'-pins$':
$ref: '#/patternProperties/-pins$'
allOf:
- $ref: pinctrl.yaml#
@@ -24,15 +24,16 @@ patternProperties:
'-pins$':
type: object
$ref: pinmux-node.yaml#
unevaluatedProperties: false
properties:
function:
enum: [ ebi_cs, uart1, serial_led, legacy_led, led, spi_cs, utopia,
pwm_syn_clk, sys_irq ]
pins:
groups:
enum: [ ebi_cs_grp, uart1_grp, serial_led_grp, legacy_led_grp,
led_grp, spi_cs_grp, utopia_grp, pwm_syn_clk, sys_irq_grp ]
led_grp, spi_cs_grp, utopia_grp, pwm_syn_clk_grp, sys_irq_grp ]
allOf:
- $ref: pinctrl.yaml#
@@ -24,6 +24,7 @@ patternProperties:
'-pins$':
type: object
$ref: pinmux-node.yaml#
unevaluatedProperties: false
properties:
function:
@@ -41,6 +42,10 @@ patternProperties:
gpio15, gpio16, gpio17, gpio18, gpio19, gpio20, gpio21,
gpio22, gpio23, gpio24, gpio25, gpio26, gpio27, nand_grp ]
patternProperties:
'-pins$':
$ref: '#/patternProperties/-pins$'
allOf:
- $ref: pinctrl.yaml#
@@ -204,6 +209,6 @@ examples:
pinctrl_nand: nand-pins {
function = "nand";
group = "nand_grp";
pins = "nand_grp";
};
};
@@ -24,6 +24,7 @@ patternProperties:
'-pins$':
type: object
$ref: pinmux-node.yaml#
unevaluatedProperties: false
properties:
function:
@@ -42,6 +43,10 @@ patternProperties:
gpio24, gpio25, gpio26, gpio27, gpio28, gpio29, gpio30,
gpio31, uart1_grp ]
patternProperties:
'-pins$':
$ref: '#/patternProperties/-pins$'
allOf:
- $ref: pinctrl.yaml#
@@ -215,6 +220,6 @@ examples:
pinctrl_uart1: uart1-pins {
function = "uart1";
group = "uart1_grp";
pins = "uart1_grp";
};
};
@@ -0,0 +1,217 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/pinctrl/nuvoton,npcm845-pinctrl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Nuvoton NPCM845 Pin Controller and GPIO
maintainers:
- Tomer Maimon <tmaimon77@gmail.com>
description:
The Nuvoton BMC NPCM8XX Pin Controller multi-function routed through
the multiplexing block, Each pin supports GPIO functionality (GPIOx)
and multiple functions that directly connect the pin to different
hardware blocks.
properties:
compatible:
const: nuvoton,npcm845-pinctrl
ranges:
maxItems: 1
'#address-cells':
const: 1
'#size-cells':
const: 1
nuvoton,sysgcr:
$ref: /schemas/types.yaml#/definitions/phandle
description: a phandle to access GCR registers.
patternProperties:
'^gpio@':
type: object
additionalProperties: false
description:
Eight GPIO banks that each contain 32 GPIOs.
properties:
gpio-controller: true
'#gpio-cells':
const: 2
reg:
maxItems: 1
interrupts:
maxItems: 1
gpio-ranges:
maxItems: 1
required:
- gpio-controller
- '#gpio-cells'
- reg
- interrupts
- gpio-ranges
'-mux$':
$ref: pinmux-node.yaml#
properties:
groups:
description:
One or more groups of pins to mux to a certain function
items:
enum: [ iox1, iox2, smb1d, smb2d, lkgpo1, lkgpo2, ioxh, gspi,
smb5b, smb5c, lkgpo0, pspi, jm1, jm2, smb4den, smb4b,
smb4c, smb15, smb16, smb17, smb18, smb19, smb20, smb21,
smb22, smb23, smb23b, smb4d, smb14, smb5, smb4, smb3,
spi0cs1, spi0cs2, spi0cs3, spi1cs0, spi1cs1, spi1cs2,
spi1cs3, spi1cs23, smb3c, smb3b, bmcuart0a, uart1, jtag2,
bmcuart1, uart2, sg1mdio, bmcuart0b, r1err, r1md, r1oen,
r2oen, rmii3, r3oen, smb3d, fanin0, fanin1, fanin2, fanin3,
fanin4, fanin5, fanin6, fanin7, fanin8, fanin9, fanin10,
fanin11, fanin12, fanin13, fanin14, fanin15, pwm0, pwm1, pwm2,
pwm3, r2, r2err, r2md, r3rxer, ga20kbc, smb5d, lpc, espi, rg2,
ddr, i3c0, i3c1, i3c2, i3c3, i3c4, i3c5, smb0, smb1, smb2,
smb2c, smb2b, smb1c, smb1b, smb8, smb9, smb10, smb11, sd1,
sd1pwr, pwm4, pwm5, pwm6, pwm7, pwm8, pwm9, pwm10, pwm11,
mmc8, mmc, mmcwp, mmccd, mmcrst, clkout, serirq, lpcclk,
scipme, smi, smb6, smb7, spi1, faninx, r1, spi3, spi3cs1,
spi3quad, spi3cs2, spi3cs3, nprd_smi, smb0b, smb0c, smb0den,
smb0d, ddc, rg2mdio, wdog1, wdog2, smb12, smb13, spix,
spixcs1, clkreq, hgpio0, hgpio1, hgpio2, hgpio3, hgpio4,
hgpio5, hgpio6, hgpio7 ]
function:
description:
The function that a group of pins is muxed to
enum: [ iox1, iox2, smb1d, smb2d, lkgpo1, lkgpo2, ioxh, gspi,
smb5b, smb5c, lkgpo0, pspi, jm1, jm2, smb4den, smb4b,
smb4c, smb15, smb16, smb17, smb18, smb19, smb20, smb21,
smb22, smb23, smb23b, smb4d, smb14, smb5, smb4, smb3,
spi0cs1, spi0cs2, spi0cs3, spi1cs0, spi1cs1, spi1cs2,
spi1cs3, spi1cs23, smb3c, smb3b, bmcuart0a, uart1, jtag2,
bmcuart1, uart2, sg1mdio, bmcuart0b, r1err, r1md, r1oen,
r2oen, rmii3, r3oen, smb3d, fanin0, fanin1, fanin2, fanin3,
fanin4, fanin5, fanin6, fanin7, fanin8, fanin9, fanin10,
fanin11, fanin12, fanin13, fanin14, fanin15, pwm0, pwm1, pwm2,
pwm3, r2, r2err, r2md, r3rxer, ga20kbc, smb5d, lpc, espi, rg2,
ddr, i3c0, i3c1, i3c2, i3c3, i3c4, i3c5, smb0, smb1, smb2,
smb2c, smb2b, smb1c, smb1b, smb8, smb9, smb10, smb11, sd1,
sd1pwr, pwm4, pwm5, pwm6, pwm7, pwm8, pwm9, pwm10, pwm11,
mmc8, mmc, mmcwp, mmccd, mmcrst, clkout, serirq, lpcclk,
scipme, smi, smb6, smb7, spi1, faninx, r1, spi3, spi3cs1,
spi3quad, spi3cs2, spi3cs3, nprd_smi, smb0b, smb0c, smb0den,
smb0d, ddc, rg2mdio, wdog1, wdog2, smb12, smb13, spix,
spixcs1, clkreq, hgpio0, hgpio1, hgpio2, hgpio3, hgpio4,
hgpio5, hgpio6, hgpio7 ]
dependencies:
groups: [ function ]
function: [ groups ]
additionalProperties: false
'^pin':
$ref: pincfg-node.yaml#
properties:
pins:
description:
A list of pins to configure in certain ways, such as enabling
debouncing
items:
pattern: '^GPIO([0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-6])'
bias-disable: true
bias-pull-up: true
bias-pull-down: true
input-enable: true
output-low: true
output-high: true
drive-push-pull: true
drive-open-drain: true
input-debounce:
description:
Debouncing periods in microseconds, one period per interrupt
bank found in the controller
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 4
slew-rate:
description: |
0: Low rate
1: High rate
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
drive-strength:
enum: [ 0, 1, 2, 4, 8, 12 ]
additionalProperties: false
allOf:
- $ref: pinctrl.yaml#
required:
- compatible
- ranges
- '#address-cells'
- '#size-cells'
- nuvoton,sysgcr
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/gpio/gpio.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
pinctrl: pinctrl@f0010000 {
compatible = "nuvoton,npcm845-pinctrl";
ranges = <0x0 0x0 0xf0010000 0x8000>;
#address-cells = <1>;
#size-cells = <1>;
nuvoton,sysgcr = <&gcr>;
gpio0: gpio@0 {
gpio-controller;
#gpio-cells = <2>;
reg = <0x0 0xb0>;
interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
gpio-ranges = <&pinctrl 0 0 32>;
};
fanin0_pin: fanin0-mux {
groups = "fanin0";
function = "fanin0";
};
pin34_slew: pin34-slew {
pins = "GPIO34/I3C4_SDA";
bias-disable;
};
};
};
@@ -43,7 +43,8 @@ patternProperties:
"-state$":
oneOf:
- $ref: "#/$defs/qcom-mdm9607-tlmm-state"
- patternProperties:
- additionalProperties: false
patternProperties:
".*":
$ref: "#/$defs/qcom-mdm9607-tlmm-state"
@@ -67,8 +67,8 @@ $defs:
Specify the alternative function to be configured for the specified
pins. Functions are only valid for gpio pins.
enum: [ gpio, cci_i2c0, blsp_uim1, blsp_uim2, blsp_uim3, blsp_uim5,
blsp_i2c1, blsp_i2c2, blsp_i2c3, blsp_i2c4, blsp_i2c5, blsp_spi1,
blsp_spi2, blsp_spi3, blsp_spi5, blsp_uart1, blsp_uart2,
blsp_i2c1, blsp_i2c2, blsp_i2c3, blsp_i2c4, blsp_i2c5, blsp_i2c6,
blsp_spi1, blsp_spi2, blsp_spi3, blsp_spi5, blsp_uart1, blsp_uart2,
blsp_uart3, blsp_uart4, blsp_uart5, cam_mclk0, cam_mclk1,
gp0_clk, gp1_clk, sdc3, wlan ]
@@ -28,6 +28,7 @@ properties:
gpio-controller: true
"#gpio-cells": true
gpio-ranges: true
wakeup-parent: true
gpio-reserved-ranges:
minItems: 1
@@ -41,6 +41,10 @@ properties:
gpio-ranges:
maxItems: 1
gpio-reserved-ranges:
minItems: 1
maxItems: 88
gpio-line-names:
maxItems: 175
@@ -0,0 +1,188 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright 2023 Realtek Semiconductor Corporation
%YAML 1.2
---
$id: http://devicetree.org/schemas/pinctrl/realtek,rtd1315e-pinctrl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Realtek DHC RTD1315E Pin Controller
maintainers:
- TY Chang <tychang@realtek.com>
description:
The Realtek DHC RTD1315E is a high-definition media processor SoC. The
RTD1315E pin controller is used to control pin function, pull up/down
resistor, drive strength, schmitt trigger and power source.
properties:
compatible:
const: realtek,rtd1315e-pinctrl
reg:
maxItems: 1
patternProperties:
'-pins$':
type: object
allOf:
- $ref: pincfg-node.yaml#
- $ref: pinmux-node.yaml#
properties:
pins:
items:
enum: [ gpio_0, gpio_1, emmc_rst_n, emmc_dd_sb, emmc_clk, emmc_cmd,
gpio_6, gpio_7, gpio_8, gpio_9, gpio_10, gpio_11, gpio_12,
gpio_13, gpio_14, gpio_15, gpio_16, gpio_17, gpio_18, gpio_19,
gpio_20, emmc_data_0, emmc_data_1, emmc_data_2, usb_cc2, gpio_25,
gpio_26, gpio_27, gpio_28, gpio_29, gpio_30, gpio_31, gpio_32,
gpio_33, gpio_34, gpio_35, hif_data, hif_en, hif_rdy, hif_clk,
gpio_dummy_40, gpio_dummy_41, gpio_dummy_42, gpio_dummy_43,
gpio_dummy_44, gpio_dummy_45, gpio_46, gpio_47, gpio_48, gpio_49,
gpio_50, usb_cc1, emmc_data_3, emmc_data_4, ir_rx, ur0_rx, ur0_tx,
gpio_57, gpio_58, gpio_59, gpio_60, gpio_61, gpio_62, gpio_dummy_63,
gpio_dummy_64, gpio_dummy_65, gpio_66, gpio_67, gpio_68, gpio_69,
gpio_70, gpio_71, gpio_72, gpio_dummy_73, emmc_data_5, emmc_data_6,
emmc_data_7, gpio_dummy_77, gpio_78, gpio_79, gpio_80, gpio_81,
ur2_loc, gspi_loc, hi_width, sf_en, arm_trace_dbg_en,
ejtag_aucpu_loc, ejtag_acpu_loc, ejtag_vcpu_loc, ejtag_scpu_loc,
dmic_loc, vtc_dmic_loc, vtc_tdm_loc, vtc_i2si_loc, tdm_ai_loc,
ai_loc, spdif_loc, hif_en_loc, scan_switch, wd_rset, boot_sel,
reset_n, testmode ]
function:
enum: [ gpio, nf, emmc, ao, gspi_loc0, gspi_loc1, uart0, uart1,
uart2_loc0, uart2_loc1, i2c0, i2c1, i2c4, i2c5, pcie1,
etn_led, etn_phy, spi, pwm0_loc0, pwm0_loc1, pwm1_loc0,
pwm1_loc1, pwm2_loc0, pwm2_loc1, pwm3_loc0, pwm3_loc1,
spdif_optical_loc0, spdif_optical_loc1, usb_cc1, usb_cc2,
sd, dmic_loc0, dmic_loc1, ai_loc0, ai_loc1, tdm_ai_loc0,
tdm_ai_loc1, hi_loc0, hi_m, vtc_i2so, vtc_i2si_loc0,
vtc_i2si_loc1, vtc_dmic_loc0, vtc_dmic_loc1, vtc_tdm_loc0,
vtc_tdm_loc1, dc_fan, pll_test_loc0, pll_test_loc1,
ir_rx, uart2_disable, gspi_disable, hi_width_disable,
hi_width_1bit, sf_disable, sf_enable, scpu_ejtag_loc0,
scpu_ejtag_loc1, scpu_ejtag_loc2, scpu_ejtag_loc3,
acpu_ejtag_loc0, acpu_ejtag_loc1, acpu_ejtag_loc2,
vcpu_ejtag_loc0, vcpu_ejtag_loc1, vcpu_ejtag_loc2,
aucpu_ejtag_loc0, aucpu_ejtag_loc1, aucpu_ejtag_loc2,
gpu_ejtag, iso_tristate, dbg_out0, dbg_out1, standby_dbg,
spdif, arm_trace_debug_disable, arm_trace_debug_enable,
aucpu_ejtag_disable, acpu_ejtag_disable, vcpu_ejtag_disable,
scpu_ejtag_disable, vtc_dmic_loc_disable, vtc_tdm_disable,
vtc_i2si_disable, tdm_ai_disable, ai_disable, spdif_disable,
hif_disable, hif_enable, test_loop, pmic_pwrup ]
drive-strength:
enum: [4, 8]
bias-pull-down: true
bias-pull-up: true
bias-disable: true
input-schmitt-enable: true
input-schmitt-disable: true
drive-push-pull: true
power-source:
description: |
Valid arguments are described as below:
0: power supply of 1.8V
1: power supply of 3.3V
enum: [0, 1]
realtek,drive-strength-p:
description: |
Some of pins can be driven using the P-MOS and N-MOS transistor to
achieve finer adjustments. The block-diagram representation is as
follows:
VDD
|
||--+
+-----o|| P-MOS-FET
| ||--+
IN --+ +----- out
| ||--+
+------|| N-MOS-FET
||--+
|
GND
The driving strength of the P-MOS/N-MOS transistors impacts the
waveform's rise/fall times. Greater driving strength results in
shorter rise/fall times. Each P-MOS and N-MOS transistor offers
8 configurable levels (0 to 7), with higher values indicating
greater driving strength, contributing to achieving the desired
speed.
The realtek,drive-strength-p is used to control the driving strength
of the P-MOS output.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 7
realtek,drive-strength-n:
description: |
Similar to the realtek,drive-strength-p, the realtek,drive-strength-n
is used to control the driving strength of the N-MOS output.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 7
realtek,duty-cycle:
description: |
An integer describing the level to adjust output duty cycle, controlling
the proportion of positive and negative waveforms in nanoseconds.
Valid arguments are described as below:
0: 0ns
2: + 0.25ns
3: + 0.5ns
4: -0.25ns
5: -0.5ns
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 0, 2, 3, 4, 5 ]
required:
- pins
additionalProperties: false
required:
- compatible
- reg
additionalProperties: false
examples:
- |
pinctrl@4e000 {
compatible = "realtek,rtd1315e-pinctrl";
reg = <0x4e000 0x130>;
emmc-hs200-pins {
pins = "emmc_clk",
"emmc_cmd",
"emmc_data_0",
"emmc_data_1",
"emmc_data_2",
"emmc_data_3",
"emmc_data_4",
"emmc_data_5",
"emmc_data_6",
"emmc_data_7";
function = "emmc";
realtek,drive-strength-p = <0x2>;
realtek,drive-strength-n = <0x2>;
};
i2c-0-pins {
pins = "gpio_12",
"gpio_13";
function = "i2c0";
drive-strength = <4>;
};
};
@@ -0,0 +1,187 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright 2023 Realtek Semiconductor Corporation
%YAML 1.2
---
$id: http://devicetree.org/schemas/pinctrl/realtek,rtd1319d-pinctrl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Realtek DHC RTD1319D Pin Controller
maintainers:
- TY Chang <tychang@realtek.com>
description:
The Realtek DHC RTD1319D is a high-definition media processor SoC. The
RTD1319D pin controller is used to control pin function, pull up/down
resistor, drive strength, schmitt trigger and power source.
properties:
compatible:
const: realtek,rtd1319d-pinctrl
reg:
maxItems: 1
patternProperties:
'-pins$':
type: object
allOf:
- $ref: pincfg-node.yaml#
- $ref: pinmux-node.yaml#
properties:
pins:
items:
enum: [ gpio_0, gpio_1, gpio_2, gpio_3, gpio_4, gpio_5, gpio_6, gpio_7,
gpio_8, gpio_9, gpio_10, gpio_11, gpio_12, gpio_13, gpio_14,
gpio_15, gpio_16, gpio_17, gpio_18, gpio_19, gpio_20, gpio_21,
gpio_22, gpio_23, usb_cc2, gpio_25, gpio_26, gpio_27, gpio_28,
gpio_29, gpio_30, gpio_31, gpio_32, gpio_33, gpio_34, gpio_35,
hif_data, hif_en, hif_rdy, hif_clk, gpio_40, gpio_41, gpio_42,
gpio_43, gpio_44, gpio_45, gpio_46, gpio_47, gpio_48, gpio_49,
gpio_50, usb_cc1, gpio_52, gpio_53, ir_rx, ur0_rx, ur0_tx,
gpio_57, gpio_58, gpio_59, gpio_60, gpio_61, gpio_62, gpio_63,
gpio_64, emmc_rst_n, emmc_dd_sb, emmc_clk, emmc_cmd, emmc_data_0,
emmc_data_1, emmc_data_2, emmc_data_3, emmc_data_4, emmc_data_5,
emmc_data_6, emmc_data_7, dummy, gpio_78, gpio_79, gpio_80,
gpio_81, ur2_loc, gspi_loc, hi_width, sf_en, arm_trace_dbg_en,
ejtag_aucpu_loc, ejtag_acpu_loc, ejtag_vcpu_loc, ejtag_scpu_loc,
dmic_loc, ejtag_secpu_loc, vtc_dmic_loc, vtc_tdm_loc, vtc_i2si_loc,
tdm_ai_loc, ai_loc, spdif_loc, hif_en_loc, sc0_loc, sc1_loc,
scan_switch, wd_rset, boot_sel, reset_n, testmode ]
function:
enum: [ gpio, nf, emmc, tp0, tp1, sc0, sc0_data0, sc0_data1, sc0_data2,
sc1, sc1_data0, sc1_data1, sc1_data2, ao, gspi_loc0, gspi_loc1,
uart0, uart1, uart2_loc0, uart2_loc1, i2c0, i2c1, i2c3, i2c4,
i2c5, pcie1, sdio, etn_led, etn_phy, spi, pwm0_loc0, pwm0_loc1,
pwm1_loc0, pwm1_loc1, pwm2_loc0, pwm2_loc1, pwm3_loc0, pwm3_loc1,
qam_agc_if0, qam_agc_if1, spdif_optical_loc0, spdif_optical_loc1,
usb_cc1, usb_cc2, vfd, sd, dmic_loc0, dmic_loc1, ai_loc0, ai_loc1,
tdm_ai_loc0, tdm_ai_loc1, hi_loc0, hi_m, vtc_i2so, vtc_i2si_loc0,
vtc_i2si_loc1, vtc_dmic_loc0, vtc_dmic_loc1, vtc_tdm_loc0,
vtc_tdm_loc1, dc_fan, pll_test_loc0, pll_test_loc1, ir_rx,
uart2_disable, gspi_disable, hi_width_disable, hi_width_1bit,
sf_disable, sf_enable, scpu_ejtag_loc0, scpu_ejtag_loc1,
scpu_ejtag_loc2, acpu_ejtag_loc0, acpu_ejtag_loc1, acpu_ejtag_loc2,
vcpu_ejtag_loc0, vcpu_ejtag_loc1, vcpu_ejtag_loc2, secpu_ejtag_loc0,
secpu_ejtag_loc1, secpu_ejtag_loc2, aucpu_ejtag_loc0, aucpu_ejtag_loc1,
aucpu_ejtag_loc2, iso_tristate, dbg_out0, dbg_out1, standby_dbg,
spdif, arm_trace_debug_disable, arm_trace_debug_enable,
aucpu_ejtag_disable, acpu_ejtag_disable, vcpu_ejtag_disable,
scpu_ejtag_disable, secpu_ejtag_disable, vtc_dmic_loc_disable,
vtc_tdm_disable, vtc_i2si_disable, tdm_ai_disable, ai_disable,
spdif_disable, hif_disable, hif_enable, test_loop, pmic_pwrup ]
drive-strength:
enum: [4, 8]
bias-pull-down: true
bias-pull-up: true
bias-disable: true
input-schmitt-enable: true
input-schmitt-disable: true
drive-push-pull: true
power-source:
description: |
Valid arguments are described as below:
0: power supply of 1.8V
1: power supply of 3.3V
enum: [0, 1]
realtek,drive-strength-p:
description: |
Some of pins can be driven using the P-MOS and N-MOS transistor to
achieve finer adjustments. The block-diagram representation is as
follows:
VDD
|
||--+
+-----o|| P-MOS-FET
| ||--+
IN --+ +----- out
| ||--+
+------|| N-MOS-FET
||--+
|
GND
The driving strength of the P-MOS/N-MOS transistors impacts the
waveform's rise/fall times. Greater driving strength results in
shorter rise/fall times. Each P-MOS and N-MOS transistor offers
8 configurable levels (0 to 7), with higher values indicating
greater driving strength, contributing to achieving the desired
speed.
The realtek,drive-strength-p is used to control the driving strength
of the P-MOS output.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 7
realtek,drive-strength-n:
description: |
Similar to the realtek,drive-strength-p, the realtek,drive-strength-n
is used to control the driving strength of the N-MOS output.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 7
realtek,duty-cycle:
description: |
An integer describing the level to adjust output duty cycle, controlling
the proportion of positive and negative waveforms in nanoseconds.
Valid arguments are described as below:
0: 0ns
2: + 0.25ns
3: + 0.5ns
4: -0.25ns
5: -0.5ns
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 0, 2, 3, 4, 5 ]
required:
- pins
additionalProperties: false
required:
- compatible
- reg
additionalProperties: false
examples:
- |
pinctrl@4e000 {
compatible = "realtek,rtd1319d-pinctrl";
reg = <0x4e000 0x130>;
emmc-hs200-pins {
pins = "emmc_clk",
"emmc_cmd",
"emmc_data_0",
"emmc_data_1",
"emmc_data_2",
"emmc_data_3",
"emmc_data_4",
"emmc_data_5",
"emmc_data_6",
"emmc_data_7";
function = "emmc";
realtek,drive-strength-p = <0x2>;
realtek,drive-strength-n = <0x2>;
};
i2c-0-pins {
pins = "gpio_12",
"gpio_13";
function = "i2c0";
drive-strength = <4>;
};
};
@@ -0,0 +1,186 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright 2023 Realtek Semiconductor Corporation
%YAML 1.2
---
$id: http://devicetree.org/schemas/pinctrl/realtek,rtd1619b-pinctrl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Realtek DHC RTD1619B Pin Controller
maintainers:
- TY Chang <tychang@realtek.com>
description:
The Realtek DHC RTD1619B is a high-definition media processor SoC. The
RTD1619B pin controller is used to control pin function, pull up/down
resistor, drive strength, schmitt trigger and power source.
properties:
compatible:
const: realtek,rtd1619b-pinctrl
reg:
maxItems: 1
patternProperties:
'-pins$':
type: object
allOf:
- $ref: pincfg-node.yaml#
- $ref: pinmux-node.yaml#
properties:
pins:
items:
enum: [ gpio_0, gpio_1, gpio_2, gpio_3, gpio_4, gpio_5, gpio_6, gpio_7,
gpio_8, gpio_9, gpio_10, gpio_11, gpio_12, gpio_13, gpio_14,
gpio_15, gpio_16, gpio_17, gpio_18, gpio_19, gpio_20, gpio_21,
gpio_22, gpio_23, usb_cc2, gpio_25, gpio_26, gpio_27, gpio_28,
gpio_29, gpio_30, gpio_31, gpio_32, gpio_33, gpio_34, gpio_35,
hif_data, hif_en, hif_rdy, hif_clk, gpio_40, gpio_41, gpio_42,
gpio_43, gpio_44, gpio_45, gpio_46, gpio_47, gpio_48, gpio_49,
gpio_50, usb_cc1, gpio_52, gpio_53, ir_rx, ur0_rx, ur0_tx,
gpio_57, gpio_58, gpio_59, gpio_60, gpio_61, gpio_62, gpio_63,
gpio_64, gpio_65, gpio_66, gpio_67, gpio_68, gpio_69, gpio_70,
gpio_71, gpio_72, gpio_73, gpio_74, gpio_75, gpio_76, emmc_cmd,
spi_ce_n, spi_sck, spi_so, spi_si, emmc_rst_n, emmc_dd_sb,
emmc_clk, emmc_data_0, emmc_data_1, emmc_data_2, emmc_data_3,
emmc_data_4, emmc_data_5, emmc_data_6, emmc_data_7, ur2_loc,
gspi_loc, sdio_loc, hi_loc, hi_width, sf_en, arm_trace_dbg_en,
pwm_01_open_drain_en_loc0, pwm_23_open_drain_en_loc0,
pwm_01_open_drain_en_loc1, pwm_23_open_drain_en_loc1,
ejtag_acpu_loc, ejtag_vcpu_loc, ejtag_scpu_loc, dmic_loc,
iso_gspi_loc, ejtag_ve3_loc, ejtag_aucpu0_loc, ejtag_aucpu1_loc ]
function:
enum: [ gpio, nf, nf_spi, spi, pmic, spdif, spdif_coaxial, spdif_optical_loc0,
spdif_optical_loc1, emmc_spi, emmc, sc1, uart0, uart1, uart2_loc0, uart2_loc1,
gspi_loc1, iso_gspi_loc1, i2c0, i2c1, i2c3, i2c4, i2c5, pwm0, pwm1, pwm2,
pwm3, etn_led, etn_phy, etn_clk, sc0, vfd, gspi_loc0, iso_gspi_loc0, pcie1,
pcie2, sd, sdio_loc0, sdio_loc1, hi, hi_m, dc_fan, pll_test_loc0, pll_test_loc1,
usb_cc1, usb_cc2, ir_rx, tdm_ai_loc0, tdm_ai_loc1, dmic_loc0, dmic_loc1,
ai_loc0, ai_loc1, tp0, tp1, ao, uart2_disable, gspi_disable, sdio_disable,
hi_loc_disable, hi_loc0, hi_width_disable, hi_width_1bit, vtc_i2si_loc0,
vtc_tdm_loc0, vtc_dmic_loc0, vtc_i2si_loc1, vtc_tdm_loc1, vtc_dmic_loc1,
vtc_i2so, ve3_ejtag_loc0, aucpu0_ejtag_loc0, aucpu1_ejtag_loc0, ve3_ejtag_loc1,
aucpu0_ejtag_loc1, aucpu1_ejtag_loc1, ve3_ejtag_loc2, aucpu0_ejtag_loc2,
aucpu1_ejtag_loc2, scpu_ejtag_loc0, acpu_ejtag_loc0, vcpu_ejtag_loc0,
scpu_ejtag_loc1, acpu_ejtag_loc1, vcpu_ejtag_loc1, scpu_ejtag_loc2,
acpu_ejtag_loc2, vcpu_ejtag_loc2, ve3_ejtag_disable, aucpu0_ejtag_disable,
aucpu1_ejtag_disable, acpu_ejtag_disable, vcpu_ejtag_disable,
scpu_ejtag_disable, iso_gspi_disable, sf_disable, sf_enable,
arm_trace_debug_disable, arm_trace_debug_enable, pwm_normal, pwm_open_drain,
standby_dbg, test_loop_dis ]
drive-strength:
enum: [4, 8]
bias-pull-down: true
bias-pull-up: true
bias-disable: true
input-schmitt-enable: true
input-schmitt-disable: true
drive-push-pull: true
power-source:
description: |
Valid arguments are described as below:
0: power supply of 1.8V
1: power supply of 3.3V
enum: [0, 1]
realtek,drive-strength-p:
description: |
Some of pins can be driven using the P-MOS and N-MOS transistor to
achieve finer adjustments. The block-diagram representation is as
follows:
VDD
|
||--+
+-----o|| P-MOS-FET
| ||--+
IN --+ +----- out
| ||--+
+------|| N-MOS-FET
||--+
|
GND
The driving strength of the P-MOS/N-MOS transistors impacts the
waveform's rise/fall times. Greater driving strength results in
shorter rise/fall times. Each P-MOS and N-MOS transistor offers
8 configurable levels (0 to 7), with higher values indicating
greater driving strength, contributing to achieving the desired
speed.
The realtek,drive-strength-p is used to control the driving strength
of the P-MOS output.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 7
realtek,drive-strength-n:
description: |
Similar to the realtek,drive-strength-p, the realtek,drive-strength-n
is used to control the driving strength of the N-MOS output.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 7
realtek,duty-cycle:
description: |
An integer describing the level to adjust output duty cycle, controlling
the proportion of positive and negative waveforms in nanoseconds.
Valid arguments are described as below:
0: 0ns
2: + 0.25ns
3: + 0.5ns
4: -0.25ns
5: -0.5ns
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 0, 2, 3, 4, 5 ]
required:
- pins
additionalProperties: false
required:
- compatible
- reg
additionalProperties: false
examples:
- |
pinctrl@4e000 {
compatible = "realtek,rtd1619b-pinctrl";
reg = <0x4e000 0x130>;
emmc-hs200-pins {
pins = "emmc_clk",
"emmc_cmd",
"emmc_data_0",
"emmc_data_1",
"emmc_data_2",
"emmc_data_3",
"emmc_data_4",
"emmc_data_5",
"emmc_data_6",
"emmc_data_7";
function = "emmc";
realtek,drive-strength-p = <0x2>;
realtek,drive-strength-n = <0x2>;
};
i2c-0-pins {
pins = "gpio_12",
"gpio_13";
function = "i2c0";
drive-strength = <4>;
};
};
@@ -25,6 +25,7 @@ properties:
- enum:
- renesas,r9a07g043-pinctrl # RZ/G2UL{Type-1,Type-2} and RZ/Five
- renesas,r9a07g044-pinctrl # RZ/G2{L,LC}
- renesas,r9a08g045-pinctrl # RZ/G3S
- items:
- enum:
@@ -73,10 +74,26 @@ properties:
additionalProperties:
anyOf:
- type: object
additionalProperties: false
allOf:
- $ref: pincfg-node.yaml#
- $ref: pinmux-node.yaml#
- if:
properties:
compatible:
contains:
enum:
- renesas,r9a08g045-pinctrl
then:
properties:
drive-strength: false
output-impedance-ohms: false
slew-rate: false
else:
properties:
drive-strength-microamp: false
description:
Pin controller client devices use pin configuration subnodes (children
and grandchildren) for desired pin configuration.
@@ -91,6 +108,10 @@ additionalProperties:
pins: true
drive-strength:
enum: [ 2, 4, 8, 12 ]
drive-strength-microamp:
enum: [ 1900, 2200, 4000, 4400, 4500, 4700, 5200, 5300, 5700,
5800, 6000, 6050, 6100, 6550, 6800, 7000, 8000, 9000,
10000 ]
output-impedance-ohms:
enum: [ 33, 50, 66, 100 ]
power-source:
@@ -53,6 +53,7 @@ properties:
additionalProperties:
anyOf:
- type: object
additionalProperties: false
allOf:
- $ref: pincfg-node.yaml#
- $ref: pinmux-node.yaml#
@@ -115,6 +115,8 @@ additionalProperties:
type: object
additionalProperties:
type: object
additionalProperties: false
properties:
rockchip,pins:
$ref: /schemas/types.yaml#/definitions/uint32-matrix
@@ -48,7 +48,8 @@ properties:
description: Phandle+args to the syscon node which includes IRQ mux selection.
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- items:
- minItems: 2
items:
- description: syscon node which includes IRQ mux selection
- description: The offset of the IRQ mux selection register
- description: The field mask of IRQ mux, needed if different of 0xf
@@ -0,0 +1,42 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/cirrus,ep9301-rtc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Cirrus EP93xx Real Time Clock controller
maintainers:
- Hartley Sweeten <hsweeten@visionengravers.com>
- Alexander Sverdlin <alexander.sverdlin@gmail.com>
allOf:
- $ref: rtc.yaml#
properties:
compatible:
oneOf:
- const: cirrus,ep9301-rtc
- items:
- enum:
- cirrus,ep9302-rtc
- cirrus,ep9307-rtc
- cirrus,ep9312-rtc
- cirrus,ep9315-rtc
- const: cirrus,ep9301-rtc
reg:
maxItems: 1
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
rtc@80920000 {
compatible = "cirrus,ep9301-rtc";
reg = <0x80920000 0x100>;
};
@@ -1,16 +0,0 @@
EPSON TOYOCOM RTC-7301SF/DG
Required properties:
- compatible: Should be "epson,rtc7301sf" or "epson,rtc7301dg"
- reg: Specifies base physical address and size of the registers.
- interrupts: A single interrupt specifier.
Example:
rtc: rtc@44a00000 {
compatible = "epson,rtc7301dg";
reg = <0x44a00000 0x10000>;
interrupt-parent = <&axi_intc_0>;
interrupts = <3 2>;
};
@@ -0,0 +1,51 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/epson,rtc7301.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Epson Toyocom RTC-7301SF/DG
description:
The only difference between the two variants is the packaging.
The DG variant is a DIL package, and the SF variant is a flat
package.
maintainers:
- Akinobu Mita <akinobu.mita@gmail.com>
properties:
compatible:
enum:
- epson,rtc7301dg
- epson,rtc7301sf
reg:
maxItems: 1
reg-io-width:
description:
The size (in bytes) of the IO accesses that should be performed
on the device.
enum: [1, 4]
default: 4
interrupts:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
rtc: rtc@44a00000 {
compatible = "epson,rtc7301dg";
reg = <0x44a00000 0x10000>;
reg-io-width = <4>;
interrupt-parent = <&axi_intc_0>;
interrupts = <3 2>;
};
@@ -1,11 +0,0 @@
* Maxim MCP795 SPI Serial Real-Time Clock
Required properties:
- compatible: Should contain "maxim,mcp795".
- reg: SPI address for chip
Example:
mcp795: rtc@0 {
compatible = "maxim,mcp795";
reg = <0>;
};
@@ -38,6 +38,8 @@ properties:
- 3000
- 4400
wakeup-source: true
required:
- compatible
- reg
@@ -0,0 +1,35 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/mstar,ssd202d-rtc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mstar SSD202D Real Time Clock
maintainers:
- Daniel Palmer <daniel@0x0f.com>
- Romain Perier <romain.perier@gmail.com>
allOf:
- $ref: rtc.yaml#
properties:
compatible:
enum:
- mstar,ssd202d-rtc
reg:
maxItems: 1
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
rtc@6800 {
compatible = "mstar,ssd202d-rtc";
reg = <0x6800 0x200>;
};
...
@@ -0,0 +1,47 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/nxp,pcf2123.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP PCF2123 SPI Real Time Clock
maintainers:
- Javier Carrasco <javier.carrasco.cruz@gmail.com>
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
- $ref: rtc.yaml#
properties:
compatible:
enum:
- nxp,pcf2123
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
rtc@3 {
compatible = "nxp,pcf2123";
reg = <3>;
interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_LOW>;
spi-cs-high;
};
};
...
@@ -1,18 +0,0 @@
* NXP PCF8523 Real Time Clock
Required properties:
- compatible: Should contain "nxp,pcf8523".
- reg: I2C address for chip.
Optional property:
- quartz-load-femtofarads: The capacitive load of the quartz(x-tal),
expressed in femto Farad (fF). Valid values are 7000 and 12500.
Default value (if no value is specified) is 12500fF.
Example:
pcf8523: rtc@68 {
compatible = "nxp,pcf8523";
reg = <0x68>;
quartz-load-femtofarads = <7000>;
};
@@ -0,0 +1,45 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/nxp,pcf8523.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP PCF8523 Real Time Clock
maintainers:
- Sam Ravnborg <sam@ravnborg.org>
allOf:
- $ref: rtc.yaml#
properties:
compatible:
const: nxp,pcf8523
reg:
maxItems: 1
quartz-load-femtofarads:
description:
The capacitive load of the crystal, expressed in femto Farad (fF).
enum: [ 7000, 12500 ]
default: 12500
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
rtc@68 {
compatible = "nxp,pcf8523";
reg = <0x68>;
quartz-load-femtofarads = <7000>;
};
};
@@ -1,17 +0,0 @@
NXP PCF2123 SPI Real Time Clock
Required properties:
- compatible: should be: "nxp,pcf2123"
or "microcrystal,rv2123"
- reg: should be the SPI slave chipselect address
Optional properties:
- spi-cs-high: PCF2123 needs chipselect high
Example:
pcf2123: rtc@3 {
compatible = "nxp,pcf2123"
reg = <3>
spi-cs-high;
};
@@ -45,6 +45,8 @@ properties:
- isil,isl1208
# Intersil ISL1218 Low Power RTC with Battery Backed SRAM
- isil,isl1218
# SPI-BUS INTERFACE REAL TIME CLOCK MODULE
- maxim,mcp795
# Real Time Clock Module with I2C-Bus
- microcrystal,rv3029
# Real Time Clock
+2 -2
View File
@@ -71,8 +71,8 @@ During DAA, each I3C device reports 3 important things:
related capabilities
* DCR: Device Characteristic Register. This 8-bit register describes the
functionalities provided by the device
* Provisional ID: A 48-bit unique identifier. On a given bus there should be no
Provisional ID collision, otherwise the discovery mechanism may fail.
* Provisioned ID: A 48-bit unique identifier. On a given bus there should be no
Provisioned ID collision, otherwise the discovery mechanism may fail.
I3C slave events
================
+1
View File
@@ -47,6 +47,7 @@ Supported adapters:
* Intel Alder Lake (PCH)
* Intel Raptor Lake (PCH)
* Intel Meteor Lake (SOC and PCH)
* Intel Birch Stream (SOC)
Datasheets: Publicly available at the Intel website
+4
View File
@@ -39,6 +39,10 @@ Also, codes returned by adapter probe methods follow rules which are
specific to their host bus (such as PCI, or the platform bus).
EAFNOSUPPORT
Returned by I2C adapters not supporting 10 bit addresses when
they are requested to use such an address.
EAGAIN
Returned by I2C adapters when they lose arbitration in master
transmit mode: some other master was transmitting different
+6
View File
@@ -243,6 +243,12 @@ The output directory is often set using "O=..." on the commandline.
The value can be overridden in which case the default value is ignored.
INSTALL_DTBS_PATH
-----------------
INSTALL_DTBS_PATH specifies where to install device tree blobs for
relocations required by build roots. This is not defined in the
makefile but the argument can be passed to make if needed.
KBUILD_ABS_SRCTREE
--------------------------------------------------
Kbuild uses a relative path to point to the tree when possible. For instance,
+11
View File
@@ -937,6 +937,10 @@ Example::
# net/bpfilter/Makefile
bpfilter_umh-userldflags += -static
To specify libraries linked to a userspace program, you can use
``<executable>-userldlibs``. The ``userldlibs`` syntax specifies libraries
linked to all userspace programs created in the current Makefile.
When linking bpfilter_umh, it will be passed the extra option -static.
From command line, :ref:`USERCFLAGS and USERLDFLAGS <userkbuildflags>` will also be used.
@@ -1623,6 +1627,13 @@ INSTALL_MOD_STRIP
INSTALL_MOD_STRIP value will be used as the option(s) to the strip
command.
INSTALL_DTBS_PATH
This variable specifies a prefix for relocations required by build
roots. It defines a place for installing the device tree blobs. Like
INSTALL_MOD_PATH, it isn't defined in the Makefile, but can be passed
by the user if desired. Otherwise it defaults to the kernel install
path.
Makefile language
=================
+19 -1
View File
@@ -294,6 +294,8 @@ F: drivers/pnp/pnpacpi/
F: include/acpi/
F: include/linux/acpi.h
F: include/linux/fwnode.h
F: include/linux/fw_table.h
F: lib/fw_table.c
F: tools/power/acpi/
ACPI APEI
@@ -3781,7 +3783,7 @@ F: net/sched/act_bpf.c
F: net/sched/cls_bpf.c
F: samples/bpf/
F: scripts/bpf_doc.py
F: scripts/pahole-flags.sh
F: scripts/Makefile.btf
F: scripts/pahole-version.sh
F: tools/bpf/
F: tools/lib/bpf/
@@ -5244,6 +5246,7 @@ L: linux-cxl@vger.kernel.org
S: Maintained
F: drivers/cxl/
F: include/uapi/linux/cxl_mem.h
F: tools/testing/cxl/
COMPUTE EXPRESS LINK PMU (CPMU)
M: Jonathan Cameron <jonathan.cameron@huawei.com>
@@ -8822,6 +8825,7 @@ F: include/linux/phy/
GENERIC PINCTRL I2C DEMULTIPLEXER DRIVER
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
S: Supported
F: Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.yaml
F: drivers/i2c/muxes/i2c-demux-pinctrl.c
GENERIC PM DOMAINS
@@ -13793,6 +13797,12 @@ F: drivers/infiniband/hw/mlx5/
F: include/linux/mlx5/
F: include/uapi/rdma/mlx5-abi.h
MELLANOX MLX5 VDPA DRIVER
M: Dragos Tatulea <dtatulea@nvidia.com>
L: virtualization@lists.linux-foundation.org
S: Supported
F: drivers/vdpa/mlx5/
MELLANOX MLXCPLD I2C AND MUX DRIVER
M: Vadim Pasternak <vadimp@nvidia.com>
M: Michael Shych <michaelsh@nvidia.com>
@@ -22065,6 +22075,14 @@ W: https://github.com/srcres258/linux-doc
T: git git://github.com/srcres258/linux-doc.git doc-zh-tw
F: Documentation/translations/zh_TW/
TRUSTED SECURITY MODULE (TSM) ATTESTATION REPORTS
M: Dan Williams <dan.j.williams@intel.com>
L: linux-coco@lists.linux.dev
S: Maintained
F: Documentation/ABI/testing/configfs-tsm
F: drivers/virt/coco/tsm.c
F: include/linux/tsm.h
TTY LAYER AND SERIAL DRIVERS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
M: Jiri Slaby <jirislaby@kernel.org>
+18 -20
View File
@@ -295,10 +295,6 @@ no-dot-config-targets := $(clean-targets) \
$(version_h) headers headers_% archheaders archscripts \
%asm-generic kernelversion %src-pkg dt_binding_check \
outputmakefile rustavailable rustfmt rustfmtcheck
# Installation targets should not require compiler. Unfortunately, vdso_install
# is an exception where build artifacts may be updated. This must be fixed.
no-compiler-targets := $(no-dot-config-targets) install dtbs_install \
headers_install modules_install modules_sign kernelrelease image_name
no-sync-config-targets := $(no-dot-config-targets) %install modules_sign kernelrelease \
image_name
single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %.symtypes %/
@@ -306,7 +302,6 @@ single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %.symtypes %
config-build :=
mixed-build :=
need-config := 1
need-compiler := 1
may-sync-config := 1
single-build :=
@@ -316,18 +311,14 @@ ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
endif
endif
ifneq ($(filter $(no-compiler-targets), $(MAKECMDGOALS)),)
ifeq ($(filter-out $(no-compiler-targets), $(MAKECMDGOALS)),)
need-compiler :=
endif
endif
ifneq ($(filter $(no-sync-config-targets), $(MAKECMDGOALS)),)
ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),)
may-sync-config :=
endif
endif
need-compiler := $(may-sync-config)
ifneq ($(KBUILD_EXTMOD),)
may-sync-config :=
endif
@@ -540,8 +531,6 @@ LZ4 = lz4
XZ = xz
ZSTD = zstd
PAHOLE_FLAGS = $(shell PAHOLE=$(PAHOLE) $(srctree)/scripts/pahole-flags.sh)
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
-Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF)
NOSTDINC_FLAGS :=
@@ -632,7 +621,6 @@ export KBUILD_RUSTFLAGS RUSTFLAGS_KERNEL RUSTFLAGS_MODULE
export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_RUSTFLAGS_MODULE KBUILD_LDFLAGS_MODULE
export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL KBUILD_RUSTFLAGS_KERNEL
export PAHOLE_FLAGS
# Files to ignore in find ... statements
@@ -702,7 +690,7 @@ ifdef config-build
# *config targets only - make sure prerequisites are updated, and descend
# in scripts/kconfig to make the *config target
# Read arch specific Makefile to set KBUILD_DEFCONFIG as needed.
# Read arch-specific Makefile to set KBUILD_DEFCONFIG as needed.
# KBUILD_DEFCONFIG may point out an alternative default configuration
# used for 'make defconfig'
include $(srctree)/arch/$(SRCARCH)/Makefile
@@ -716,7 +704,7 @@ config: outputmakefile scripts_basic FORCE
else #!config-build
# ===========================================================================
# Build targets only - this includes vmlinux, arch specific targets, clean
# Build targets only - this includes vmlinux, arch-specific targets, clean
# targets and others. In general all targets except *config targets.
# If building an external module we do not care about the all: rule
@@ -1037,6 +1025,7 @@ KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
# include additional Makefiles when needed
include-y := scripts/Makefile.extrawarn
include-$(CONFIG_DEBUG_INFO) += scripts/Makefile.debug
include-$(CONFIG_DEBUG_INFO_BTF)+= scripts/Makefile.btf
include-$(CONFIG_KASAN) += scripts/Makefile.kasan
include-$(CONFIG_KCSAN) += scripts/Makefile.kcsan
include-$(CONFIG_KMSAN) += scripts/Makefile.kmsan
@@ -1353,6 +1342,14 @@ scripts_unifdef: scripts_basic
quiet_cmd_install = INSTALL $(INSTALL_PATH)
cmd_install = unset sub_make_done; $(srctree)/scripts/install.sh
# ---------------------------------------------------------------------------
# vDSO install
PHONY += vdso_install
vdso_install: export INSTALL_FILES = $(vdso-install-y)
vdso_install:
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vdsoinst
# ---------------------------------------------------------------------------
# Tools
@@ -1524,7 +1521,7 @@ MRPROPER_FILES += include/config include/generated \
certs/signing_key.pem \
certs/x509.genkey \
vmlinux-gdb.py \
kernel.spec rpmbuild \
rpmbuild \
rust/libmacros.so
# clean - Delete most, but leave enough to build external modules
@@ -1598,6 +1595,7 @@ help:
@echo '* vmlinux - Build the bare kernel'
@echo '* modules - Build all modules'
@echo ' modules_install - Install all modules to INSTALL_MOD_PATH (default: /)'
@echo ' vdso_install - Install unstripped vdso to INSTALL_MOD_PATH (default: /)'
@echo ' dir/ - Build all files in dir and below'
@echo ' dir/file.[ois] - Build specified target only'
@echo ' dir/file.ll - Build the LLVM assembly file'
@@ -1675,9 +1673,9 @@ help:
@echo 'Documentation targets:'
@$(MAKE) -f $(srctree)/Documentation/Makefile dochelp
@echo ''
@echo 'Architecture specific targets ($(SRCARCH)):'
@echo 'Architecture-specific targets ($(SRCARCH)):'
@$(or $(archhelp),\
echo ' No architecture specific help defined for $(SRCARCH)')
echo ' No architecture-specific help defined for $(SRCARCH)')
@echo ''
@$(if $(boards), \
$(foreach b, $(boards), \
@@ -1719,7 +1717,7 @@ help-boards: $(help-board-dirs)
boards-per-dir = $(sort $(notdir $(wildcard $(srctree)/arch/$(SRCARCH)/configs/$*/*_defconfig)))
$(help-board-dirs): help-%:
@echo 'Architecture specific targets ($(SRCARCH) $*):'
@echo 'Architecture-specific targets ($(SRCARCH) $*):'
@$(if $(boards-per-dir), \
$(foreach b, $(boards-per-dir), \
printf " %-24s - Build for %s\\n" $*/$(b) $(subst _defconfig,,$(b));) \
+1 -6
View File
@@ -304,11 +304,7 @@ $(INSTALL_TARGETS): KBUILD_IMAGE = $(boot)/$(patsubst %install,%Image,$@)
$(INSTALL_TARGETS):
$(call cmd,install)
PHONY += vdso_install
vdso_install:
ifeq ($(CONFIG_VDSO),y)
$(Q)$(MAKE) $(build)=arch/arm/vdso $@
endif
vdso-install-$(CONFIG_VDSO) += arch/arm/vdso/vdso.so.dbg
# My testing targets (bypasses dependencies)
bp:; $(Q)$(MAKE) $(build)=$(boot) $(boot)/bootpImage
@@ -331,7 +327,6 @@ define archhelp
echo ' Install using (your) ~/bin/$(INSTALLKERNEL) or'
echo ' (distribution) /sbin/$(INSTALLKERNEL) or'
echo ' install to $$(INSTALL_PATH) and run lilo'
echo ' vdso_install - Install unstripped vdso.so to $$(INSTALL_MOD_PATH)/vdso'
echo
echo ' multi_v7_lpae_defconfig - multi_v7_defconfig with CONFIG_ARM_LPAE enabled'
endef
+33
View File
@@ -242,6 +242,17 @@
status = "disabled";
};
blsp1_uart2: serial@f991e000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0xf991e000 0x1000>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>,
<&gcc GCC_BLSP1_AHB_CLK>;
clock-names = "core",
"iface";
status = "disabled";
};
blsp1_uart3: serial@f991f000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0xf991f000 0x1000>;
@@ -325,6 +336,21 @@
#size-cells = <0>;
};
blsp1_i2c6: i2c@f9928000 {
compatible = "qcom,i2c-qup-v2.1.1";
reg = <0xf9928000 0x1000>;
interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&gcc GCC_BLSP1_QUP6_I2C_APPS_CLK>,
<&gcc GCC_BLSP1_AHB_CLK>;
clock-names = "core",
"iface";
pinctrl-0 = <&blsp1_i2c6_pins>;
pinctrl-names = "default";
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
cci: cci@fda0c000 {
compatible = "qcom,msm8226-cci";
#address-cells = <1>;
@@ -472,6 +498,13 @@
bias-disable;
};
blsp1_i2c6_pins: blsp1-i2c6-state {
pins = "gpio22", "gpio23";
function = "blsp_i2c6";
drive-strength = <2>;
bias-disable;
};
cci_default: cci-default-state {
pins = "gpio29", "gpio30";
function = "cci_i2c0";
-25
View File
@@ -63,28 +63,3 @@ quiet_cmd_vdsold_and_vdso_check = LD $@
quiet_cmd_vdsomunge = MUNGE $@
cmd_vdsomunge = $(objtree)/$(obj)/vdsomunge $< $@
#
# Install the unstripped copy of vdso.so.dbg. If our toolchain
# supports build-id, install .build-id links as well.
#
# Cribbed from arch/x86/vdso/Makefile.
#
quiet_cmd_vdso_install = INSTALL $<
define cmd_vdso_install
cp $< "$(MODLIB)/vdso/vdso.so"; \
if readelf -n $< | grep -q 'Build ID'; then \
buildid=`readelf -n $< |grep 'Build ID' |sed -e 's/^.*Build ID: \(.*\)$$/\1/'`; \
first=`echo $$buildid | cut -b-2`; \
last=`echo $$buildid | cut -b3-`; \
mkdir -p "$(MODLIB)/vdso/.build-id/$$first"; \
ln -sf "../../vdso.so" "$(MODLIB)/vdso/.build-id/$$first/$$last.debug"; \
fi
endef
$(MODLIB)/vdso: FORCE
@mkdir -p $(MODLIB)/vdso
PHONY += vdso_install
vdso_install: $(obj)/vdso.so.dbg $(MODLIB)/vdso
$(call cmd,vdso_install)
+3 -6
View File
@@ -172,12 +172,6 @@ install: KBUILD_IMAGE := $(boot)/Image
install zinstall:
$(call cmd,install)
PHONY += vdso_install
vdso_install:
$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@
$(if $(CONFIG_COMPAT_VDSO), \
$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 $@)
archprepare:
$(Q)$(MAKE) $(build)=arch/arm64/tools kapi
ifeq ($(CONFIG_ARM64_ERRATUM_843419),y)
@@ -208,6 +202,9 @@ ifdef CONFIG_COMPAT_VDSO
endif
endif
vdso-install-y += arch/arm64/kernel/vdso/vdso.so.dbg
vdso-install-$(CONFIG_COMPAT_VDSO) += arch/arm64/kernel/vdso32/vdso.so.dbg:vdso32.so
include $(srctree)/scripts/Makefile.defconf
PHONY += virtconfig
-10
View File
@@ -78,13 +78,3 @@ include/generated/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE
# Actual build commands
quiet_cmd_vdsold_and_vdso_check = LD $@
cmd_vdsold_and_vdso_check = $(cmd_ld); $(cmd_vdso_check)
# Install commands for the unstripped file
quiet_cmd_vdso_install = INSTALL $@
cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
vdso.so: $(obj)/vdso.so.dbg
@mkdir -p $(MODLIB)/vdso
$(call cmd,vdso_install)
vdso_install: vdso.so
-10
View File
@@ -172,13 +172,3 @@ gen-vdsosym := $(srctree)/$(src)/../vdso/gen_vdso_offsets.sh
quiet_cmd_vdsosym = VDSOSYM $@
# The AArch64 nm should be able to read an AArch32 binary
cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
# Install commands for the unstripped file
quiet_cmd_vdso_install = INSTALL32 $@
cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/vdso32.so
vdso.so: $(obj)/vdso.so.dbg
@mkdir -p $(MODLIB)/vdso
$(call cmd,vdso_install)
vdso_install: vdso.so
-10
View File
@@ -58,13 +58,3 @@ quiet_cmd_vdsold = VDSOLD $@
# that contains the same symbols at the same offsets.
quiet_cmd_so2s = SO2S $@
cmd_so2s = $(NM) -D $< | $(srctree)/$(src)/so2s.sh > $@
# install commands for the unstripped file
quiet_cmd_vdso_install = INSTALL $@
cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
vdso.so: $(obj)/vdso.so.dbg
@mkdir -p $(MODLIB)/vdso
$(call cmd,vdso_install)
vdso_install: vdso.so
+1 -3
View File
@@ -136,9 +136,7 @@ vdso_prepare: prepare0
$(Q)$(MAKE) $(build)=arch/loongarch/vdso include/generated/vdso-offsets.h
endif
PHONY += vdso_install
vdso_install:
$(Q)$(MAKE) $(build)=arch/loongarch/vdso $@
vdso-install-y += arch/loongarch/vdso/vdso.so.dbg
all: $(notdir $(KBUILD_IMAGE))
-10
View File
@@ -83,13 +83,3 @@ $(obj)/vdso.so: $(obj)/vdso.so.dbg FORCE
obj-y += vdso.o
$(obj)/vdso.o : $(obj)/vdso.so
# install commands for the unstripped file
quiet_cmd_vdso_install = INSTALL $@
cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
vdso.so: $(obj)/vdso.so.dbg
@mkdir -p $(MODLIB)/vdso
$(call cmd,vdso_install)
vdso_install: vdso.so
-3
View File
@@ -31,9 +31,6 @@ ifeq ($(CONFIG_RELOCATABLE),y)
$(call if_changed,relocs)
endif
%.ko: FORCE
@true
clean:
@true
+2 -6
View File
@@ -177,12 +177,8 @@ vdso_prepare: prepare0
$(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso32 include/generated/vdso32-offsets.h
endif
PHONY += vdso_install
vdso_install:
$(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso $@
$(if $(CONFIG_COMPAT_VDSO), \
$(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso32 $@)
vdso-install-y += arch/parisc/kernel/vdso32/vdso32.so
vdso-install-$(CONFIG_64BIT) += arch/parisc/kernel/vdso64/vdso64.so
install: KBUILD_IMAGE := vmlinux
zinstall: KBUILD_IMAGE := vmlinuz
-3
View File
@@ -35,9 +35,6 @@ ifdef CONFIG_RELOCATABLE
$(call if_changed,relocs_check)
endif
%.ko: FORCE
@true
clean:
rm -f .tmp_symbols.txt
+3 -6
View File
@@ -130,12 +130,6 @@ endif
libs-y += arch/riscv/lib/
libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
PHONY += vdso_install
vdso_install:
$(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@
$(if $(CONFIG_COMPAT),$(Q)$(MAKE) \
$(build)=arch/riscv/kernel/compat_vdso compat_$@)
ifeq ($(KBUILD_EXTMOD),)
ifeq ($(CONFIG_MMU),y)
prepare: vdso_prepare
@@ -147,6 +141,9 @@ vdso_prepare: prepare0
endif
endif
vdso-install-y += arch/riscv/kernel/vdso/vdso.so.dbg
vdso-install-$(CONFIG_COMPAT) += arch/riscv/kernel/compat_vdso/compat_vdso.so.dbg:../compat_vdso/compat_vdso.so
ifneq ($(CONFIG_XIP_KERNEL),y)
ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_ARCH_CANAAN),yy)
KBUILD_IMAGE := $(boot)/loader.bin
-3
View File
@@ -36,9 +36,6 @@ ifdef CONFIG_RELOCATABLE
$(call if_changed,relocs_strip)
endif
%.ko: FORCE
@true
clean:
@true
-10
View File
@@ -76,13 +76,3 @@ quiet_cmd_compat_vdsold = VDSOLD $@
# actual build commands
quiet_cmd_compat_vdsoas = VDSOAS $@
cmd_compat_vdsoas = $(COMPAT_CC) $(a_flags) $(COMPAT_CC_FLAGS) -c -o $@ $<
# install commands for the unstripped file
quiet_cmd_compat_vdso_install = INSTALL $@
cmd_compat_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/compat_vdso/$@
compat_vdso.so: $(obj)/compat_vdso.so.dbg
@mkdir -p $(MODLIB)/compat_vdso
$(call cmd,compat_vdso_install)
compat_vdso_install: compat_vdso.so
-10
View File
@@ -73,13 +73,3 @@ quiet_cmd_vdsold = VDSOLD $@
cmd_vdsold = $(LD) $(ld_flags) -T $(filter-out FORCE,$^) -o $@.tmp && \
$(OBJCOPY) $(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@ && \
rm $@.tmp
# install commands for the unstripped file
quiet_cmd_vdso_install = INSTALL $@
cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
vdso.so: $(obj)/vdso.so.dbg
@mkdir -p $(MODLIB)/vdso
$(call cmd,vdso_install)
vdso_install: vdso.so
+3 -3
View File
@@ -138,9 +138,6 @@ bzImage: vmlinux
zfcpdump:
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
vdso_install:
$(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso64 $@
archheaders:
$(Q)$(MAKE) $(build)=$(syscalls) uapi
@@ -160,6 +157,9 @@ vdso_prepare: prepare0
$(if $(CONFIG_COMPAT),$(Q)$(MAKE) \
$(build)=arch/s390/kernel/vdso32 include/generated/vdso32-offsets.h)
vdso-install-y += arch/s390/kernel/vdso64/vdso64.so.dbg
vdso-install-$(CONFIG_COMPAT) += arch/s390/kernel/vdso32/vdso32.so.dbg
ifdef CONFIG_EXPOLINE_EXTERN
modules_prepare: expoline_prepare
expoline_prepare: scripts
-10
View File
@@ -61,16 +61,6 @@ quiet_cmd_vdso32as = VDSO32A $@
quiet_cmd_vdso32cc = VDSO32C $@
cmd_vdso32cc = $(CC) $(c_flags) -c -o $@ $<
# install commands for the unstripped file
quiet_cmd_vdso_install = INSTALL $@
cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
vdso32.so: $(obj)/vdso32.so.dbg
@mkdir -p $(MODLIB)/vdso
$(call cmd,vdso_install)
vdso_install: vdso32.so
# Generate VDSO offsets using helper script
gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh
quiet_cmd_vdsosym = VDSOSYM $@
-10
View File
@@ -70,16 +70,6 @@ quiet_cmd_vdso64as = VDSO64A $@
quiet_cmd_vdso64cc = VDSO64C $@
cmd_vdso64cc = $(CC) $(c_flags) -c -o $@ $<
# install commands for the unstripped file
quiet_cmd_vdso_install = INSTALL $@
cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
vdso64.so: $(obj)/vdso64.so.dbg
@mkdir -p $(MODLIB)/vdso
$(call cmd,vdso_install)
vdso_install: vdso64.so
# Generate VDSO offsets using helper script
gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh
quiet_cmd_vdsosym = VDSOSYM $@
+2 -3
View File
@@ -76,9 +76,8 @@ install:
archheaders:
$(Q)$(MAKE) $(build)=arch/sparc/kernel/syscalls all
PHONY += vdso_install
vdso_install:
$(Q)$(MAKE) $(build)=arch/sparc/vdso $@
vdso-install-$(CONFIG_SPARC64) += arch/sparc/vdso/vdso64.so.dbg
vdso-install-$(CONFIG_COMPAT) += arch/sparc/vdso/vdso32.so.dbg
# This is the image used for packaging
KBUILD_IMAGE := $(boot)/zImage
-27
View File
@@ -116,30 +116,3 @@ quiet_cmd_vdso = VDSO $@
VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic
GCOV_PROFILE := n
#
# Install the unstripped copies of vdso*.so. If our toolchain supports
# build-id, install .build-id links as well.
#
quiet_cmd_vdso_install = INSTALL $(@:install_%=%)
define cmd_vdso_install
cp $< "$(MODLIB)/vdso/$(@:install_%=%)"; \
if readelf -n $< |grep -q 'Build ID'; then \
buildid=`readelf -n $< |grep 'Build ID' |sed -e 's/^.*Build ID: \(.*\)$$/\1/'`; \
first=`echo $$buildid | cut -b-2`; \
last=`echo $$buildid | cut -b3-`; \
mkdir -p "$(MODLIB)/vdso/.build-id/$$first"; \
ln -sf "../../$(@:install_%=%)" "$(MODLIB)/vdso/.build-id/$$first/$$last.debug"; \
fi
endef
vdso_img_insttargets := $(vdso_img_sodbg:%.dbg=install_%)
$(MODLIB)/vdso: FORCE
@mkdir -p $(MODLIB)/vdso
$(vdso_img_insttargets): install_%: $(obj)/%.dbg $(MODLIB)/vdso FORCE
$(call cmd,vdso_install)
PHONY += vdso_install $(vdso_img_insttargets)
vdso_install: $(vdso_img_insttargets) FORCE
+27 -2
View File
@@ -1313,16 +1313,41 @@ config MICROCODE
def_bool y
depends on CPU_SUP_AMD || CPU_SUP_INTEL
config MICROCODE_INITRD32
def_bool y
depends on MICROCODE && X86_32 && BLK_DEV_INITRD
config MICROCODE_LATE_LOADING
bool "Late microcode loading (DANGEROUS)"
default n
depends on MICROCODE
depends on MICROCODE && SMP
help
Loading microcode late, when the system is up and executing instructions
is a tricky business and should be avoided if possible. Just the sequence
of synchronizing all cores and SMT threads is one fragile dance which does
not guarantee that cores might not softlock after the loading. Therefore,
use this at your own risk. Late loading taints the kernel too.
use this at your own risk. Late loading taints the kernel unless the
microcode header indicates that it is safe for late loading via the
minimal revision check. This minimal revision check can be enforced on
the kernel command line with "microcode.minrev=Y".
config MICROCODE_LATE_FORCE_MINREV
bool "Enforce late microcode loading minimal revision check"
default n
depends on MICROCODE_LATE_LOADING
help
To prevent that users load microcode late which modifies already
in use features, newer microcode patches have a minimum revision field
in the microcode header, which tells the kernel which minimum
revision must be active in the CPU to safely load that new microcode
late into the running system. If disabled the check will not
be enforced but the kernel will be tainted when the minimal
revision check fails.
This minimal revision check can also be controlled via the
"microcode.minrev" parameter on the kernel command line.
If unsure say Y.
config X86_MSR
tristate "/dev/cpu/*/msr - Model-specific register support"
+4 -3
View File
@@ -297,9 +297,10 @@ PHONY += install
install:
$(call cmd,install)
PHONY += vdso_install
vdso_install:
$(Q)$(MAKE) $(build)=arch/x86/entry/vdso $@
vdso-install-$(CONFIG_X86_64) += arch/x86/entry/vdso/vdso64.so.dbg
vdso-install-$(CONFIG_X86_X32_ABI) += arch/x86/entry/vdso/vdsox32.so.dbg
vdso-install-$(CONFIG_X86_32) += arch/x86/entry/vdso/vdso32.so.dbg
vdso-install-$(CONFIG_IA32_EMULATION) += arch/x86/entry/vdso/vdso32.so.dbg
archprepare: checkbin
checkbin:
-3
View File
@@ -34,9 +34,6 @@ ifeq ($(CONFIG_X86_NEED_RELOCS),y)
$(call cmd,strip_relocs)
endif
%.ko: FORCE
@true
clean:
@rm -f $(OUT_RELOCS)/vmlinux.relocs
+21
View File
@@ -106,6 +106,27 @@ int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport)
}
EXPORT_SYMBOL_GPL(tdx_mcall_get_report0);
/**
* tdx_hcall_get_quote() - Wrapper to request TD Quote using GetQuote
* hypercall.
* @buf: Address of the directly mapped shared kernel buffer which
* contains TDREPORT. The same buffer will be used by VMM to
* store the generated TD Quote output.
* @size: size of the tdquote buffer (4KB-aligned).
*
* Refer to section titled "TDG.VP.VMCALL<GetQuote>" in the TDX GHCI
* v1.0 specification for more information on GetQuote hypercall.
* It is used in the TDX guest driver module to get the TD Quote.
*
* Return 0 on success or error code on failure.
*/
u64 tdx_hcall_get_quote(u8 *buf, size_t size)
{
/* Since buf is a shared memory, set the shared (decrypted) bits */
return _tdx_hypercall(TDVMCALL_GET_QUOTE, cc_mkdec(virt_to_phys(buf)), size, 0, 0);
}
EXPORT_SYMBOL_GPL(tdx_hcall_get_quote);
static void __noreturn tdx_panic(const char *msg)
{
struct tdx_module_args args = {
-27
View File
@@ -191,31 +191,4 @@ GCOV_PROFILE := n
quiet_cmd_vdso_and_check = VDSO $@
cmd_vdso_and_check = $(cmd_vdso); $(cmd_vdso_check)
#
# Install the unstripped copies of vdso*.so. If our toolchain supports
# build-id, install .build-id links as well.
#
quiet_cmd_vdso_install = INSTALL $(@:install_%=%)
define cmd_vdso_install
cp $< "$(MODLIB)/vdso/$(@:install_%=%)"; \
if readelf -n $< |grep -q 'Build ID'; then \
buildid=`readelf -n $< |grep 'Build ID' |sed -e 's/^.*Build ID: \(.*\)$$/\1/'`; \
first=`echo $$buildid | cut -b-2`; \
last=`echo $$buildid | cut -b3-`; \
mkdir -p "$(MODLIB)/vdso/.build-id/$$first"; \
ln -sf "../../$(@:install_%=%)" "$(MODLIB)/vdso/.build-id/$$first/$$last.debug"; \
fi
endef
vdso_img_insttargets := $(vdso_img_sodbg:%.dbg=install_%)
$(MODLIB)/vdso: FORCE
@mkdir -p $(MODLIB)/vdso
$(vdso_img_insttargets): install_%: $(obj)/%.dbg $(MODLIB)/vdso
$(call cmd,vdso_install)
PHONY += vdso_install $(vdso_img_insttargets)
vdso_install: $(vdso_img_insttargets)
clean-files := vdso32.so vdso32.so.dbg vdso64* vdso-image-*.c vdsox32.so*
+4 -1
View File
@@ -276,7 +276,8 @@ struct apic {
u32 disable_esr : 1,
dest_mode_logical : 1,
x2apic_set_max_apicid : 1;
x2apic_set_max_apicid : 1,
nmi_to_offline_cpu : 1;
u32 (*calc_dest_apicid)(unsigned int cpu);
@@ -531,6 +532,8 @@ extern u32 apic_flat_calc_apicid(unsigned int cpu);
extern void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap);
extern u32 default_cpu_present_to_apicid(int mps_cpu);
void apic_send_nmi_to_offline_cpu(unsigned int cpu);
#else /* CONFIG_X86_LOCAL_APIC */
static inline u32 read_apic_id(void) { return 0; }
+3 -17
View File
@@ -71,26 +71,12 @@ static inline void init_ia32_feat_ctl(struct cpuinfo_x86 *c) {}
extern __noendbr void cet_disable(void);
struct ucode_cpu_info;
struct cpu_signature;
int intel_cpu_collect_info(struct ucode_cpu_info *uci);
static inline bool intel_cpu_signatures_match(unsigned int s1, unsigned int p1,
unsigned int s2, unsigned int p2)
{
if (s1 != s2)
return false;
/* Processor flags are either both 0 ... */
if (!p1 && !p2)
return true;
/* ... or they intersect. */
return p1 & p2;
}
void intel_collect_cpu_info(struct cpu_signature *sig);
extern u64 x86_read_arch_cap_msr(void);
int intel_find_matching_signature(void *mc, unsigned int csig, int cpf);
bool intel_find_matching_signature(void *mc, struct cpu_signature *sig);
int intel_microcode_sanity_check(void *mc, bool print_err, int hdr_type);
extern struct cpumask cpus_stop_mask;
+17 -6
View File
@@ -23,6 +23,8 @@ static inline void load_ucode_ap(void) { }
static inline void microcode_bsp_resume(void) { }
#endif
extern unsigned long initrd_start_early;
#ifdef CONFIG_CPU_SUP_INTEL
/* Intel specific microcode defines. Public for IFS */
struct microcode_header_intel {
@@ -36,7 +38,8 @@ struct microcode_header_intel {
unsigned int datasize;
unsigned int totalsize;
unsigned int metasize;
unsigned int reserved[2];
unsigned int min_req_ver;
unsigned int reserved;
};
struct microcode_intel {
@@ -68,11 +71,19 @@ static inline u32 intel_get_microcode_revision(void)
return rev;
}
void show_ucode_info_early(void);
#else /* CONFIG_CPU_SUP_INTEL */
static inline void show_ucode_info_early(void) { }
#endif /* !CONFIG_CPU_SUP_INTEL */
bool microcode_nmi_handler(void);
void microcode_offline_nmi_handler(void);
#ifdef CONFIG_MICROCODE_LATE_LOADING
DECLARE_STATIC_KEY_FALSE(microcode_nmi_handler_enable);
static __always_inline bool microcode_nmi_handler_enabled(void)
{
return static_branch_unlikely(&microcode_nmi_handler_enable);
}
#else
static __always_inline bool microcode_nmi_handler_enabled(void) { return false; }
#endif
#endif /* _ASM_X86_MICROCODE_H */
+1
View File
@@ -126,6 +126,7 @@ void clear_bss(void);
#ifdef __i386__
asmlinkage void __init __noreturn i386_start_kernel(void);
void __init mk_early_pgtbl_32(void);
#else
asmlinkage void __init __noreturn x86_64_start_kernel(char *real_mode);
+1
View File
@@ -23,6 +23,7 @@
/* TDX hypercall Leaf IDs */
#define TDVMCALL_MAP_GPA 0x10001
#define TDVMCALL_GET_QUOTE 0x10002
#define TDVMCALL_REPORT_FATAL_ERROR 0x10003
#define TDVMCALL_STATUS_RETRY 1
+2
View File
@@ -56,6 +56,8 @@ bool tdx_early_handle_ve(struct pt_regs *regs);
int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport);
u64 tdx_hcall_get_quote(u8 *buf, size_t size);
#else
static inline void tdx_early_init(void) { };
+1
View File
@@ -16,6 +16,7 @@ CFLAGS_REMOVE_kvmclock.o = -pg
CFLAGS_REMOVE_ftrace.o = -pg
CFLAGS_REMOVE_early_printk.o = -pg
CFLAGS_REMOVE_head64.o = -pg
CFLAGS_REMOVE_head32.o = -pg
CFLAGS_REMOVE_sev.o = -pg
CFLAGS_REMOVE_rethook.o = -pg
endif
+2
View File
@@ -103,6 +103,7 @@ static struct apic apic_flat __ro_after_init = {
.send_IPI_allbutself = default_send_IPI_allbutself,
.send_IPI_all = default_send_IPI_all,
.send_IPI_self = default_send_IPI_self,
.nmi_to_offline_cpu = true,
.read = native_apic_mem_read,
.write = native_apic_mem_write,
@@ -173,6 +174,7 @@ static struct apic apic_physflat __ro_after_init = {
.send_IPI_allbutself = default_send_IPI_allbutself,
.send_IPI_all = default_send_IPI_all,
.send_IPI_self = default_send_IPI_self,
.nmi_to_offline_cpu = true,
.read = native_apic_mem_read,
.write = native_apic_mem_write,
+8
View File
@@ -97,6 +97,14 @@ sendmask:
__apic_send_IPI_mask(mask, CALL_FUNCTION_VECTOR);
}
void apic_send_nmi_to_offline_cpu(unsigned int cpu)
{
if (WARN_ON_ONCE(!apic->nmi_to_offline_cpu))
return;
if (WARN_ON_ONCE(!cpumask_test_cpu(cpu, &cpus_booted_once_mask)))
return;
apic->send_IPI(cpu, NMI_VECTOR);
}
#endif /* CONFIG_SMP */
static inline int __prepare_ICR2(unsigned int mask)
+1
View File
@@ -251,6 +251,7 @@ static struct apic apic_x2apic_cluster __ro_after_init = {
.send_IPI_allbutself = x2apic_send_IPI_allbutself,
.send_IPI_all = x2apic_send_IPI_all,
.send_IPI_self = x2apic_send_IPI_self,
.nmi_to_offline_cpu = true,
.read = native_apic_msr_read,
.write = native_apic_msr_write,
+1
View File
@@ -166,6 +166,7 @@ static struct apic apic_x2apic_phys __ro_after_init = {
.send_IPI_allbutself = x2apic_send_IPI_allbutself,
.send_IPI_all = x2apic_send_IPI_all,
.send_IPI_self = x2apic_send_IPI_self,
.nmi_to_offline_cpu = true,
.read = native_apic_msr_read,
.write = native_apic_msr_write,
-12
View File
@@ -2164,8 +2164,6 @@ static inline void setup_getcpu(int cpu)
}
#ifdef CONFIG_X86_64
static inline void ucode_cpu_init(int cpu) { }
static inline void tss_setup_ist(struct tss_struct *tss)
{
/* Set up the per-CPU TSS IST stacks */
@@ -2176,16 +2174,8 @@ static inline void tss_setup_ist(struct tss_struct *tss)
/* Only mapped when SEV-ES is active */
tss->x86_tss.ist[IST_INDEX_VC] = __this_cpu_ist_top_va(VC);
}
#else /* CONFIG_X86_64 */
static inline void ucode_cpu_init(int cpu)
{
show_ucode_info_early();
}
static inline void tss_setup_ist(struct tss_struct *tss) { }
#endif /* !CONFIG_X86_64 */
static inline void tss_setup_io_bitmap(struct tss_struct *tss)
@@ -2241,8 +2231,6 @@ void cpu_init(void)
struct task_struct *cur = current;
int cpu = raw_smp_processor_id();
ucode_cpu_init(cpu);
#ifdef CONFIG_NUMA
if (this_cpu_read(numa_node) == 0 &&
early_cpu_to_node(cpu) != NUMA_NO_NODE)
+70 -87
View File
@@ -37,6 +37,16 @@
#include "internal.h"
struct ucode_patch {
struct list_head plist;
void *data;
unsigned int size;
u32 patch_id;
u16 equiv_cpu;
};
static LIST_HEAD(microcode_cache);
#define UCODE_MAGIC 0x00414d44
#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
#define UCODE_UCODE_TYPE 0x00000001
@@ -121,24 +131,20 @@ static u16 find_equiv_id(struct equiv_cpu_table *et, u32 sig)
/*
* Check whether there is a valid microcode container file at the beginning
* of @buf of size @buf_size. Set @early to use this function in the early path.
* of @buf of size @buf_size.
*/
static bool verify_container(const u8 *buf, size_t buf_size, bool early)
static bool verify_container(const u8 *buf, size_t buf_size)
{
u32 cont_magic;
if (buf_size <= CONTAINER_HDR_SZ) {
if (!early)
pr_debug("Truncated microcode container header.\n");
pr_debug("Truncated microcode container header.\n");
return false;
}
cont_magic = *(const u32 *)buf;
if (cont_magic != UCODE_MAGIC) {
if (!early)
pr_debug("Invalid magic value (0x%08x).\n", cont_magic);
pr_debug("Invalid magic value (0x%08x).\n", cont_magic);
return false;
}
@@ -147,23 +153,20 @@ static bool verify_container(const u8 *buf, size_t buf_size, bool early)
/*
* Check whether there is a valid, non-truncated CPU equivalence table at the
* beginning of @buf of size @buf_size. Set @early to use this function in the
* early path.
* beginning of @buf of size @buf_size.
*/
static bool verify_equivalence_table(const u8 *buf, size_t buf_size, bool early)
static bool verify_equivalence_table(const u8 *buf, size_t buf_size)
{
const u32 *hdr = (const u32 *)buf;
u32 cont_type, equiv_tbl_len;
if (!verify_container(buf, buf_size, early))
if (!verify_container(buf, buf_size))
return false;
cont_type = hdr[1];
if (cont_type != UCODE_EQUIV_CPU_TABLE_TYPE) {
if (!early)
pr_debug("Wrong microcode container equivalence table type: %u.\n",
cont_type);
pr_debug("Wrong microcode container equivalence table type: %u.\n",
cont_type);
return false;
}
@@ -172,9 +175,7 @@ static bool verify_equivalence_table(const u8 *buf, size_t buf_size, bool early)
equiv_tbl_len = hdr[2];
if (equiv_tbl_len < sizeof(struct equiv_cpu_entry) ||
buf_size < equiv_tbl_len) {
if (!early)
pr_debug("Truncated equivalence table.\n");
pr_debug("Truncated equivalence table.\n");
return false;
}
@@ -183,22 +184,19 @@ static bool verify_equivalence_table(const u8 *buf, size_t buf_size, bool early)
/*
* Check whether there is a valid, non-truncated microcode patch section at the
* beginning of @buf of size @buf_size. Set @early to use this function in the
* early path.
* beginning of @buf of size @buf_size.
*
* On success, @sh_psize returns the patch size according to the section header,
* to the caller.
*/
static bool
__verify_patch_section(const u8 *buf, size_t buf_size, u32 *sh_psize, bool early)
__verify_patch_section(const u8 *buf, size_t buf_size, u32 *sh_psize)
{
u32 p_type, p_size;
const u32 *hdr;
if (buf_size < SECTION_HDR_SIZE) {
if (!early)
pr_debug("Truncated patch section.\n");
pr_debug("Truncated patch section.\n");
return false;
}
@@ -207,17 +205,13 @@ __verify_patch_section(const u8 *buf, size_t buf_size, u32 *sh_psize, bool early
p_size = hdr[1];
if (p_type != UCODE_UCODE_TYPE) {
if (!early)
pr_debug("Invalid type field (0x%x) in container file section header.\n",
p_type);
pr_debug("Invalid type field (0x%x) in container file section header.\n",
p_type);
return false;
}
if (p_size < sizeof(struct microcode_header_amd)) {
if (!early)
pr_debug("Patch of size %u too short.\n", p_size);
pr_debug("Patch of size %u too short.\n", p_size);
return false;
}
@@ -269,7 +263,7 @@ static unsigned int __verify_patch_size(u8 family, u32 sh_psize, size_t buf_size
* 0: success
*/
static int
verify_patch(u8 family, const u8 *buf, size_t buf_size, u32 *patch_size, bool early)
verify_patch(u8 family, const u8 *buf, size_t buf_size, u32 *patch_size)
{
struct microcode_header_amd *mc_hdr;
unsigned int ret;
@@ -277,7 +271,7 @@ verify_patch(u8 family, const u8 *buf, size_t buf_size, u32 *patch_size, bool ea
u16 proc_id;
u8 patch_fam;
if (!__verify_patch_section(buf, buf_size, &sh_psize, early))
if (!__verify_patch_section(buf, buf_size, &sh_psize))
return -1;
/*
@@ -292,16 +286,13 @@ verify_patch(u8 family, const u8 *buf, size_t buf_size, u32 *patch_size, bool ea
* size sh_psize, as the section claims.
*/
if (buf_size < sh_psize) {
if (!early)
pr_debug("Patch of size %u truncated.\n", sh_psize);
pr_debug("Patch of size %u truncated.\n", sh_psize);
return -1;
}
ret = __verify_patch_size(family, sh_psize, buf_size);
if (!ret) {
if (!early)
pr_debug("Per-family patch size mismatch.\n");
pr_debug("Per-family patch size mismatch.\n");
return -1;
}
@@ -309,8 +300,7 @@ verify_patch(u8 family, const u8 *buf, size_t buf_size, u32 *patch_size, bool ea
mc_hdr = (struct microcode_header_amd *)(buf + SECTION_HDR_SIZE);
if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) {
if (!early)
pr_err("Patch-ID 0x%08x: chipset-specific code unsupported.\n", mc_hdr->patch_id);
pr_err("Patch-ID 0x%08x: chipset-specific code unsupported.\n", mc_hdr->patch_id);
return -1;
}
@@ -337,7 +327,7 @@ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc)
u16 eq_id;
u8 *buf;
if (!verify_equivalence_table(ucode, size, true))
if (!verify_equivalence_table(ucode, size))
return 0;
buf = ucode;
@@ -364,7 +354,7 @@ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc)
u32 patch_size;
int ret;
ret = verify_patch(x86_family(desc->cpuid_1_eax), buf, size, &patch_size, true);
ret = verify_patch(x86_family(desc->cpuid_1_eax), buf, size, &patch_size);
if (ret < 0) {
/*
* Patch verification failed, skip to the next container, if
@@ -456,14 +446,8 @@ static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size)
{
struct cont_desc desc = { 0 };
struct microcode_amd *mc;
u32 rev, dummy, *new_rev;
bool ret = false;
#ifdef CONFIG_X86_32
new_rev = (u32 *)__pa_nodebug(&ucode_new_rev);
#else
new_rev = &ucode_new_rev;
#endif
u32 rev, dummy;
desc.cpuid_1_eax = cpuid_1_eax;
@@ -484,8 +468,8 @@ static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size)
return ret;
if (!__apply_microcode_amd(mc)) {
*new_rev = mc->hdr.patch_id;
ret = true;
ucode_new_rev = mc->hdr.patch_id;
ret = true;
}
return ret;
@@ -501,7 +485,7 @@ static bool get_builtin_microcode(struct cpio_data *cp, unsigned int family)
if (family >= 0x15)
snprintf(fw_name, sizeof(fw_name),
"amd-ucode/microcode_amd_fam%.2xh.bin", family);
"amd-ucode/microcode_amd_fam%02hhxh.bin", family);
if (firmware_request_builtin(&fw, fw_name)) {
cp->size = fw.size;
@@ -512,36 +496,23 @@ static bool get_builtin_microcode(struct cpio_data *cp, unsigned int family)
return false;
}
static void find_blobs_in_containers(unsigned int cpuid_1_eax, struct cpio_data *ret)
static void __init find_blobs_in_containers(unsigned int cpuid_1_eax, struct cpio_data *ret)
{
struct ucode_cpu_info *uci;
struct cpio_data cp;
const char *path;
bool use_pa;
if (IS_ENABLED(CONFIG_X86_32)) {
uci = (struct ucode_cpu_info *)__pa_nodebug(ucode_cpu_info);
path = (const char *)__pa_nodebug(ucode_path);
use_pa = true;
} else {
uci = ucode_cpu_info;
path = ucode_path;
use_pa = false;
}
if (!get_builtin_microcode(&cp, x86_family(cpuid_1_eax)))
cp = find_microcode_in_initrd(path, use_pa);
/* Needed in load_microcode_amd() */
uci->cpu_sig.sig = cpuid_1_eax;
cp = find_microcode_in_initrd(ucode_path);
*ret = cp;
}
static void apply_ucode_from_containers(unsigned int cpuid_1_eax)
void __init load_ucode_amd_bsp(unsigned int cpuid_1_eax)
{
struct cpio_data cp = { };
/* Needed in load_microcode_amd() */
ucode_cpu_info[0].cpu_sig.sig = cpuid_1_eax;
find_blobs_in_containers(cpuid_1_eax, &cp);
if (!(cp.data && cp.size))
return;
@@ -549,20 +520,20 @@ static void apply_ucode_from_containers(unsigned int cpuid_1_eax)
early_apply_microcode(cpuid_1_eax, cp.data, cp.size);
}
void load_ucode_amd_early(unsigned int cpuid_1_eax)
{
return apply_ucode_from_containers(cpuid_1_eax);
}
static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size);
int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
static int __init save_microcode_in_initrd(void)
{
unsigned int cpuid_1_eax = native_cpuid_eax(1);
struct cpuinfo_x86 *c = &boot_cpu_data;
struct cont_desc desc = { 0 };
enum ucode_state ret;
struct cpio_data cp;
cp = find_microcode_in_initrd(ucode_path, false);
if (dis_ucode_ldr || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10)
return 0;
find_blobs_in_containers(cpuid_1_eax, &cp);
if (!(cp.data && cp.size))
return -EINVAL;
@@ -578,6 +549,7 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
return 0;
}
early_initcall(save_microcode_in_initrd);
/*
* a small, trivial cache of per-family ucode patches
@@ -631,7 +603,6 @@ static struct ucode_patch *find_patch(unsigned int cpu)
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
u16 equiv_id;
equiv_id = find_equiv_id(&equiv_table, uci->cpu_sig.sig);
if (!equiv_id)
return NULL;
@@ -733,12 +704,20 @@ out:
return ret;
}
void load_ucode_amd_ap(unsigned int cpuid_1_eax)
{
unsigned int cpu = smp_processor_id();
ucode_cpu_info[cpu].cpu_sig.sig = cpuid_1_eax;
apply_microcode_amd(cpu);
}
static size_t install_equiv_cpu_table(const u8 *buf, size_t buf_size)
{
u32 equiv_tbl_len;
const u32 *hdr;
if (!verify_equivalence_table(buf, buf_size, false))
if (!verify_equivalence_table(buf, buf_size))
return 0;
hdr = (const u32 *)buf;
@@ -784,7 +763,7 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover,
u16 proc_id;
int ret;
ret = verify_patch(family, fw, leftover, patch_size, false);
ret = verify_patch(family, fw, leftover, patch_size);
if (ret)
return ret;
@@ -909,6 +888,9 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device)
enum ucode_state ret = UCODE_NFOUND;
const struct firmware *fw;
if (force_minrev)
return UCODE_NFOUND;
if (c->x86 >= 0x15)
snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
@@ -918,7 +900,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device)
}
ret = UCODE_ERROR;
if (!verify_container(fw->data, fw->size, false))
if (!verify_container(fw->data, fw->size))
goto fw_release;
ret = load_microcode_amd(c->x86, fw->data, fw->size);
@@ -938,10 +920,11 @@ static void microcode_fini_cpu_amd(int cpu)
}
static struct microcode_ops microcode_amd_ops = {
.request_microcode_fw = request_microcode_amd,
.collect_cpu_info = collect_cpu_info_amd,
.apply_microcode = apply_microcode_amd,
.microcode_fini_cpu = microcode_fini_cpu_amd,
.request_microcode_fw = request_microcode_amd,
.collect_cpu_info = collect_cpu_info_amd,
.apply_microcode = apply_microcode_amd,
.microcode_fini_cpu = microcode_fini_cpu_amd,
.nmi_safe = true,
};
struct microcode_ops * __init init_amd_microcode(void)
+444 -264
View File
@@ -23,6 +23,7 @@
#include <linux/miscdevice.h>
#include <linux/capability.h>
#include <linux/firmware.h>
#include <linux/cpumask.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/mutex.h>
@@ -31,6 +32,7 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <asm/apic.h>
#include <asm/cpu_device_id.h>
#include <asm/perf_event.h>
#include <asm/processor.h>
@@ -42,11 +44,10 @@
#define DRIVER_VERSION "2.2"
static struct microcode_ops *microcode_ops;
static bool dis_ucode_ldr = true;
bool dis_ucode_ldr = true;
bool initrd_gone;
LIST_HEAD(microcode_cache);
bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV);
module_param(force_minrev, bool, S_IRUSR | S_IWUSR);
/*
* Synchronization.
@@ -90,10 +91,7 @@ static bool amd_check_current_patch_level(void)
native_rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy);
if (IS_ENABLED(CONFIG_X86_32))
levels = (u32 *)__pa_nodebug(&final_levels);
else
levels = final_levels;
levels = final_levels;
for (i = 0; levels[i]; i++) {
if (lvl == levels[i])
@@ -105,17 +103,8 @@ static bool amd_check_current_patch_level(void)
static bool __init check_loader_disabled_bsp(void)
{
static const char *__dis_opt_str = "dis_ucode_ldr";
#ifdef CONFIG_X86_32
const char *cmdline = (const char *)__pa_nodebug(boot_command_line);
const char *option = (const char *)__pa_nodebug(__dis_opt_str);
bool *res = (bool *)__pa_nodebug(&dis_ucode_ldr);
#else /* CONFIG_X86_64 */
const char *cmdline = boot_command_line;
const char *option = __dis_opt_str;
bool *res = &dis_ucode_ldr;
#endif
/*
* CPUID(1).ECX[31]: reserved for hypervisor use. This is still not
@@ -123,17 +112,17 @@ static bool __init check_loader_disabled_bsp(void)
* that's good enough as they don't land on the BSP path anyway.
*/
if (native_cpuid_ecx(1) & BIT(31))
return *res;
return true;
if (x86_cpuid_vendor() == X86_VENDOR_AMD) {
if (amd_check_current_patch_level())
return *res;
return true;
}
if (cmdline_find_option_bool(cmdline, option) <= 0)
*res = false;
dis_ucode_ldr = false;
return *res;
return dis_ucode_ldr;
}
void __init load_ucode_bsp(void)
@@ -168,23 +157,14 @@ void __init load_ucode_bsp(void)
if (intel)
load_ucode_intel_bsp();
else
load_ucode_amd_early(cpuid_1_eax);
}
static bool check_loader_disabled_ap(void)
{
#ifdef CONFIG_X86_32
return *((bool *)__pa_nodebug(&dis_ucode_ldr));
#else
return dis_ucode_ldr;
#endif
load_ucode_amd_bsp(cpuid_1_eax);
}
void load_ucode_ap(void)
{
unsigned int cpuid_1_eax;
if (check_loader_disabled_ap())
if (dis_ucode_ldr)
return;
cpuid_1_eax = native_cpuid_eax(1);
@@ -196,97 +176,44 @@ void load_ucode_ap(void)
break;
case X86_VENDOR_AMD:
if (x86_family(cpuid_1_eax) >= 0x10)
load_ucode_amd_early(cpuid_1_eax);
load_ucode_amd_ap(cpuid_1_eax);
break;
default:
break;
}
}
static int __init save_microcode_in_initrd(void)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
int ret = -EINVAL;
switch (c->x86_vendor) {
case X86_VENDOR_INTEL:
if (c->x86 >= 6)
ret = save_microcode_in_initrd_intel();
break;
case X86_VENDOR_AMD:
if (c->x86 >= 0x10)
ret = save_microcode_in_initrd_amd(cpuid_eax(1));
break;
default:
break;
}
initrd_gone = true;
return ret;
}
struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa)
struct cpio_data __init find_microcode_in_initrd(const char *path)
{
#ifdef CONFIG_BLK_DEV_INITRD
unsigned long start = 0;
size_t size;
#ifdef CONFIG_X86_32
struct boot_params *params;
if (use_pa)
params = (struct boot_params *)__pa_nodebug(&boot_params);
else
params = &boot_params;
size = params->hdr.ramdisk_size;
/*
* Set start only if we have an initrd image. We cannot use initrd_start
* because it is not set that early yet.
*/
size = boot_params.hdr.ramdisk_size;
/* Early load on BSP has a temporary mapping. */
if (size)
start = params->hdr.ramdisk_image;
start = initrd_start_early;
# else /* CONFIG_X86_64 */
#else /* CONFIG_X86_64 */
size = (unsigned long)boot_params.ext_ramdisk_size << 32;
size |= boot_params.hdr.ramdisk_size;
if (size) {
start = (unsigned long)boot_params.ext_ramdisk_image << 32;
start |= boot_params.hdr.ramdisk_image;
start += PAGE_OFFSET;
}
# endif
#endif
/*
* Fixup the start address: after reserve_initrd() runs, initrd_start
* has the virtual address of the beginning of the initrd. It also
* possibly relocates the ramdisk. In either case, initrd_start contains
* the updated address so use that instead.
*
* initrd_gone is for the hotplug case where we've thrown out initrd
* already.
*/
if (!use_pa) {
if (initrd_gone)
return (struct cpio_data){ NULL, 0, "" };
if (initrd_start)
start = initrd_start;
} else {
/*
* The picture with physical addresses is a bit different: we
* need to get the *physical* address to which the ramdisk was
* relocated, i.e., relocated_ramdisk (not initrd_start) and
* since we're running from physical addresses, we need to access
* relocated_ramdisk through its *physical* address too.
*/
u64 *rr = (u64 *)__pa_nodebug(&relocated_ramdisk);
if (*rr)
start = *rr;
}
if (initrd_start)
start = initrd_start;
return find_cpio_data(path, (void *)start, size, NULL);
#else /* !CONFIG_BLK_DEV_INITRD */
@@ -330,117 +257,298 @@ static struct platform_device *microcode_pdev;
* requirement can be relaxed in the future. Right now, this is conservative
* and good.
*/
#define SPINUNIT 100 /* 100 nsec */
enum sibling_ctrl {
/* Spinwait with timeout */
SCTRL_WAIT,
/* Invoke the microcode_apply() callback */
SCTRL_APPLY,
/* Proceed without invoking the microcode_apply() callback */
SCTRL_DONE,
};
static int check_online_cpus(void)
struct microcode_ctrl {
enum sibling_ctrl ctrl;
enum ucode_state result;
unsigned int ctrl_cpu;
bool nmi_enabled;
};
DEFINE_STATIC_KEY_FALSE(microcode_nmi_handler_enable);
static DEFINE_PER_CPU(struct microcode_ctrl, ucode_ctrl);
static atomic_t late_cpus_in, offline_in_nmi;
static unsigned int loops_per_usec;
static cpumask_t cpu_offline_mask;
static noinstr bool wait_for_cpus(atomic_t *cnt)
{
unsigned int timeout, loops;
WARN_ON_ONCE(raw_atomic_dec_return(cnt) < 0);
for (timeout = 0; timeout < USEC_PER_SEC; timeout++) {
if (!raw_atomic_read(cnt))
return true;
for (loops = 0; loops < loops_per_usec; loops++)
cpu_relax();
/* If invoked directly, tickle the NMI watchdog */
if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) {
instrumentation_begin();
touch_nmi_watchdog();
instrumentation_end();
}
}
/* Prevent the late comers from making progress and let them time out */
raw_atomic_inc(cnt);
return false;
}
static noinstr bool wait_for_ctrl(void)
{
unsigned int timeout, loops;
for (timeout = 0; timeout < USEC_PER_SEC; timeout++) {
if (raw_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT)
return true;
for (loops = 0; loops < loops_per_usec; loops++)
cpu_relax();
/* If invoked directly, tickle the NMI watchdog */
if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) {
instrumentation_begin();
touch_nmi_watchdog();
instrumentation_end();
}
}
return false;
}
/*
* Protected against instrumentation up to the point where the primary
* thread completed the update. See microcode_nmi_handler() for details.
*/
static noinstr bool load_secondary_wait(unsigned int ctrl_cpu)
{
/* Initial rendezvous to ensure that all CPUs have arrived */
if (!wait_for_cpus(&late_cpus_in)) {
raw_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT);
return false;
}
/*
* Wait for primary threads to complete. If one of them hangs due
* to the update, there is no way out. This is non-recoverable
* because the CPU might hold locks or resources and confuse the
* scheduler, watchdogs etc. There is no way to safely evacuate the
* machine.
*/
if (wait_for_ctrl())
return true;
instrumentation_begin();
panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu);
instrumentation_end();
}
/*
* Protected against instrumentation up to the point where the primary
* thread completed the update. See microcode_nmi_handler() for details.
*/
static noinstr void load_secondary(unsigned int cpu)
{
unsigned int ctrl_cpu = raw_cpu_read(ucode_ctrl.ctrl_cpu);
enum ucode_state ret;
if (!load_secondary_wait(ctrl_cpu)) {
instrumentation_begin();
pr_err_once("load: %d CPUs timed out\n",
atomic_read(&late_cpus_in) - 1);
instrumentation_end();
return;
}
/* Primary thread completed. Allow to invoke instrumentable code */
instrumentation_begin();
/*
* If the primary succeeded then invoke the apply() callback,
* otherwise copy the state from the primary thread.
*/
if (this_cpu_read(ucode_ctrl.ctrl) == SCTRL_APPLY)
ret = microcode_ops->apply_microcode(cpu);
else
ret = per_cpu(ucode_ctrl.result, ctrl_cpu);
this_cpu_write(ucode_ctrl.result, ret);
this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE);
instrumentation_end();
}
static void __load_primary(unsigned int cpu)
{
struct cpumask *secondaries = topology_sibling_cpumask(cpu);
enum sibling_ctrl ctrl;
enum ucode_state ret;
unsigned int sibling;
/* Initial rendezvous to ensure that all CPUs have arrived */
if (!wait_for_cpus(&late_cpus_in)) {
this_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT);
pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1);
return;
}
ret = microcode_ops->apply_microcode(cpu);
this_cpu_write(ucode_ctrl.result, ret);
this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE);
/*
* If the update was successful, let the siblings run the apply()
* callback. If not, tell them it's done. This also covers the
* case where the CPU has uniform loading at package or system
* scope implemented but does not advertise it.
*/
if (ret == UCODE_UPDATED || ret == UCODE_OK)
ctrl = SCTRL_APPLY;
else
ctrl = SCTRL_DONE;
for_each_cpu(sibling, secondaries) {
if (sibling != cpu)
per_cpu(ucode_ctrl.ctrl, sibling) = ctrl;
}
}
static bool kick_offline_cpus(unsigned int nr_offl)
{
unsigned int cpu, timeout;
for_each_cpu(cpu, &cpu_offline_mask) {
/* Enable the rendezvous handler and send NMI */
per_cpu(ucode_ctrl.nmi_enabled, cpu) = true;
apic_send_nmi_to_offline_cpu(cpu);
}
/* Wait for them to arrive */
for (timeout = 0; timeout < (USEC_PER_SEC / 2); timeout++) {
if (atomic_read(&offline_in_nmi) == nr_offl)
return true;
udelay(1);
}
/* Let the others time out */
return false;
}
static void release_offline_cpus(void)
{
unsigned int cpu;
/*
* Make sure all CPUs are online. It's fine for SMT to be disabled if
* all the primary threads are still online.
*/
for_each_present_cpu(cpu) {
if (topology_is_primary_thread(cpu) && !cpu_online(cpu)) {
pr_err("Not all CPUs online, aborting microcode update.\n");
return -EINVAL;
}
}
return 0;
for_each_cpu(cpu, &cpu_offline_mask)
per_cpu(ucode_ctrl.ctrl, cpu) = SCTRL_DONE;
}
static atomic_t late_cpus_in;
static atomic_t late_cpus_out;
static int __wait_for_cpus(atomic_t *t, long long timeout)
static void load_primary(unsigned int cpu)
{
int all_cpus = num_online_cpus();
unsigned int nr_offl = cpumask_weight(&cpu_offline_mask);
bool proceed = true;
atomic_inc(t);
/* Kick soft-offlined SMT siblings if required */
if (!cpu && nr_offl)
proceed = kick_offline_cpus(nr_offl);
while (atomic_read(t) < all_cpus) {
if (timeout < SPINUNIT) {
pr_err("Timeout while waiting for CPUs rendezvous, remaining: %d\n",
all_cpus - atomic_read(t));
return 1;
}
/* If the soft-offlined CPUs did not respond, abort */
if (proceed)
__load_primary(cpu);
ndelay(SPINUNIT);
timeout -= SPINUNIT;
/* Unconditionally release soft-offlined SMT siblings if required */
if (!cpu && nr_offl)
release_offline_cpus();
}
touch_nmi_watchdog();
/*
* Minimal stub rendezvous handler for soft-offlined CPUs which participate
* in the NMI rendezvous to protect against a concurrent NMI on affected
* CPUs.
*/
void noinstr microcode_offline_nmi_handler(void)
{
if (!raw_cpu_read(ucode_ctrl.nmi_enabled))
return;
raw_cpu_write(ucode_ctrl.nmi_enabled, false);
raw_cpu_write(ucode_ctrl.result, UCODE_OFFLINE);
raw_atomic_inc(&offline_in_nmi);
wait_for_ctrl();
}
static noinstr bool microcode_update_handler(void)
{
unsigned int cpu = raw_smp_processor_id();
if (raw_cpu_read(ucode_ctrl.ctrl_cpu) == cpu) {
instrumentation_begin();
load_primary(cpu);
instrumentation_end();
} else {
load_secondary(cpu);
}
instrumentation_begin();
touch_nmi_watchdog();
instrumentation_end();
return true;
}
/*
* Protection against instrumentation is required for CPUs which are not
* safe against an NMI which is delivered to the secondary SMT sibling
* while the primary thread updates the microcode. Instrumentation can end
* up in #INT3, #DB and #PF. The IRET from those exceptions reenables NMI
* which is the opposite of what the NMI rendezvous is trying to achieve.
*
* The primary thread is safe versus instrumentation as the actual
* microcode update handles this correctly. It's only the sibling code
* path which must be NMI safe until the primary thread completed the
* update.
*/
bool noinstr microcode_nmi_handler(void)
{
if (!raw_cpu_read(ucode_ctrl.nmi_enabled))
return false;
raw_cpu_write(ucode_ctrl.nmi_enabled, false);
return microcode_update_handler();
}
static int load_cpus_stopped(void *unused)
{
if (microcode_ops->use_nmi) {
/* Enable the NMI handler and raise NMI */
this_cpu_write(ucode_ctrl.nmi_enabled, true);
apic->send_IPI(smp_processor_id(), NMI_VECTOR);
} else {
/* Just invoke the handler directly */
microcode_update_handler();
}
return 0;
}
/*
* Returns:
* < 0 - on error
* 0 - success (no update done or microcode was updated)
*/
static int __reload_late(void *info)
static int load_late_stop_cpus(bool is_safe)
{
int cpu = smp_processor_id();
enum ucode_state err;
int ret = 0;
/*
* Wait for all CPUs to arrive. A load will not be attempted unless all
* CPUs show up.
* */
if (__wait_for_cpus(&late_cpus_in, NSEC_PER_SEC))
return -1;
/*
* On an SMT system, it suffices to load the microcode on one sibling of
* the core because the microcode engine is shared between the threads.
* Synchronization still needs to take place so that no concurrent
* loading attempts happen on multiple threads of an SMT core. See
* below.
*/
if (cpumask_first(topology_sibling_cpumask(cpu)) == cpu)
err = microcode_ops->apply_microcode(cpu);
else
goto wait_for_siblings;
if (err >= UCODE_NFOUND) {
if (err == UCODE_ERROR) {
pr_warn("Error reloading microcode on CPU %d\n", cpu);
ret = -1;
}
}
wait_for_siblings:
if (__wait_for_cpus(&late_cpus_out, NSEC_PER_SEC))
panic("Timeout during microcode update!\n");
/*
* At least one thread has completed update on each core.
* For others, simply call the update to make sure the
* per-cpu cpuinfo can be updated with right microcode
* revision.
*/
if (cpumask_first(topology_sibling_cpumask(cpu)) != cpu)
err = microcode_ops->apply_microcode(cpu);
return ret;
}
/*
* Reload microcode late on all CPUs. Wait for a sec until they
* all gather together.
*/
static int microcode_reload_late(void)
{
int old = boot_cpu_data.microcode, ret;
unsigned int cpu, updated = 0, failed = 0, timedout = 0, siblings = 0;
unsigned int nr_offl, offline = 0;
int old_rev = boot_cpu_data.microcode;
struct cpuinfo_x86 prev_info;
pr_err("Attempting late microcode loading - it is dangerous and taints the kernel.\n");
pr_err("You should switch to early loading, if possible.\n");
if (!is_safe) {
pr_err("Late microcode loading without minimal revision check.\n");
pr_err("You should switch to early loading, if possible.\n");
}
atomic_set(&late_cpus_in, 0);
atomic_set(&late_cpus_out, 0);
atomic_set(&late_cpus_in, num_online_cpus());
atomic_set(&offline_in_nmi, 0);
loops_per_usec = loops_per_jiffy / (TICK_NSEC / 1000);
/*
* Take a snapshot before the microcode update in order to compare and
@@ -448,52 +556,162 @@ static int microcode_reload_late(void)
*/
store_cpu_caps(&prev_info);
ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask);
if (!ret) {
pr_info("Reload succeeded, microcode revision: 0x%x -> 0x%x\n",
old, boot_cpu_data.microcode);
microcode_check(&prev_info);
} else {
pr_info("Reload failed, current microcode revision: 0x%x\n",
boot_cpu_data.microcode);
if (microcode_ops->use_nmi)
static_branch_enable_cpuslocked(&microcode_nmi_handler_enable);
stop_machine_cpuslocked(load_cpus_stopped, NULL, cpu_online_mask);
if (microcode_ops->use_nmi)
static_branch_disable_cpuslocked(&microcode_nmi_handler_enable);
/* Analyze the results */
for_each_cpu_and(cpu, cpu_present_mask, &cpus_booted_once_mask) {
switch (per_cpu(ucode_ctrl.result, cpu)) {
case UCODE_UPDATED: updated++; break;
case UCODE_TIMEOUT: timedout++; break;
case UCODE_OK: siblings++; break;
case UCODE_OFFLINE: offline++; break;
default: failed++; break;
}
}
return ret;
if (microcode_ops->finalize_late_load)
microcode_ops->finalize_late_load(!updated);
if (!updated) {
/* Nothing changed. */
if (!failed && !timedout)
return 0;
nr_offl = cpumask_weight(&cpu_offline_mask);
if (offline < nr_offl) {
pr_warn("%u offline siblings did not respond.\n",
nr_offl - atomic_read(&offline_in_nmi));
return -EIO;
}
pr_err("update failed: %u CPUs failed %u CPUs timed out\n",
failed, timedout);
return -EIO;
}
if (!is_safe || failed || timedout)
add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
pr_info("load: updated on %u primary CPUs with %u siblings\n", updated, siblings);
if (failed || timedout) {
pr_err("load incomplete. %u CPUs timed out or failed\n",
num_online_cpus() - (updated + siblings));
}
pr_info("revision: 0x%x -> 0x%x\n", old_rev, boot_cpu_data.microcode);
microcode_check(&prev_info);
return updated + siblings == num_online_cpus() ? 0 : -EIO;
}
/*
* This function does two things:
*
* 1) Ensure that all required CPUs which are present and have been booted
* once are online.
*
* To pass this check, all primary threads must be online.
*
* If the microcode load is not safe against NMI then all SMT threads
* must be online as well because they still react to NMIs when they are
* soft-offlined and parked in one of the play_dead() variants. So if a
* NMI hits while the primary thread updates the microcode the resulting
* behaviour is undefined. The default play_dead() implementation on
* modern CPUs uses MWAIT, which is also not guaranteed to be safe
* against a microcode update which affects MWAIT.
*
* As soft-offlined CPUs still react on NMIs, the SMT sibling
* restriction can be lifted when the vendor driver signals to use NMI
* for rendezvous and the APIC provides a mechanism to send an NMI to a
* soft-offlined CPU. The soft-offlined CPUs are then able to
* participate in the rendezvous in a trivial stub handler.
*
* 2) Initialize the per CPU control structure and create a cpumask
* which contains "offline"; secondary threads, so they can be handled
* correctly by a control CPU.
*/
static bool setup_cpus(void)
{
struct microcode_ctrl ctrl = { .ctrl = SCTRL_WAIT, .result = -1, };
bool allow_smt_offline;
unsigned int cpu;
allow_smt_offline = microcode_ops->nmi_safe ||
(microcode_ops->use_nmi && apic->nmi_to_offline_cpu);
cpumask_clear(&cpu_offline_mask);
for_each_cpu_and(cpu, cpu_present_mask, &cpus_booted_once_mask) {
/*
* Offline CPUs sit in one of the play_dead() functions
* with interrupts disabled, but they still react on NMIs
* and execute arbitrary code. Also MWAIT being updated
* while the offline CPU sits there is not necessarily safe
* on all CPU variants.
*
* Mark them in the offline_cpus mask which will be handled
* by CPU0 later in the update process.
*
* Ensure that the primary thread is online so that it is
* guaranteed that all cores are updated.
*/
if (!cpu_online(cpu)) {
if (topology_is_primary_thread(cpu) || !allow_smt_offline) {
pr_err("CPU %u not online, loading aborted\n", cpu);
return false;
}
cpumask_set_cpu(cpu, &cpu_offline_mask);
per_cpu(ucode_ctrl, cpu) = ctrl;
continue;
}
/*
* Initialize the per CPU state. This is core scope for now,
* but prepared to take package or system scope into account.
*/
ctrl.ctrl_cpu = cpumask_first(topology_sibling_cpumask(cpu));
per_cpu(ucode_ctrl, cpu) = ctrl;
}
return true;
}
static int load_late_locked(void)
{
if (!setup_cpus())
return -EBUSY;
switch (microcode_ops->request_microcode_fw(0, &microcode_pdev->dev)) {
case UCODE_NEW:
return load_late_stop_cpus(false);
case UCODE_NEW_SAFE:
return load_late_stop_cpus(true);
case UCODE_NFOUND:
return -ENOENT;
default:
return -EBADFD;
}
}
static ssize_t reload_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
enum ucode_state tmp_ret = UCODE_OK;
int bsp = boot_cpu_data.cpu_index;
unsigned long val;
ssize_t ret = 0;
ssize_t ret;
ret = kstrtoul(buf, 0, &val);
if (ret || val != 1)
return -EINVAL;
cpus_read_lock();
ret = check_online_cpus();
if (ret)
goto put;
tmp_ret = microcode_ops->request_microcode_fw(bsp, &microcode_pdev->dev);
if (tmp_ret != UCODE_NEW)
goto put;
ret = microcode_reload_late();
put:
ret = load_late_locked();
cpus_read_unlock();
if (ret == 0)
ret = size;
add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
return ret;
return ret ? : size;
}
static DEVICE_ATTR_WO(reload);
@@ -535,17 +753,6 @@ static void microcode_fini_cpu(int cpu)
microcode_ops->microcode_fini_cpu(cpu);
}
static enum ucode_state microcode_init_cpu(int cpu)
{
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
memset(uci, 0, sizeof(*uci));
microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig);
return microcode_ops->apply_microcode(cpu);
}
/**
* microcode_bsp_resume - Update boot CPU microcode during resume.
*/
@@ -564,19 +771,18 @@ static struct syscore_ops mc_syscore_ops = {
.resume = microcode_bsp_resume,
};
static int mc_cpu_starting(unsigned int cpu)
{
enum ucode_state err = microcode_ops->apply_microcode(cpu);
pr_debug("%s: CPU%d, err: %d\n", __func__, cpu, err);
return err == UCODE_ERROR;
}
static int mc_cpu_online(unsigned int cpu)
{
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
struct device *dev = get_cpu_device(cpu);
memset(uci, 0, sizeof(*uci));
microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig);
cpu_data(cpu).microcode = uci->cpu_sig.rev;
if (!cpu)
boot_cpu_data.microcode = uci->cpu_sig.rev;
if (sysfs_create_group(&dev->kobj, &mc_attr_group))
pr_err("Failed to create group for CPU%d\n", cpu);
return 0;
@@ -584,33 +790,13 @@ static int mc_cpu_online(unsigned int cpu)
static int mc_cpu_down_prep(unsigned int cpu)
{
struct device *dev;
dev = get_cpu_device(cpu);
struct device *dev = get_cpu_device(cpu);
microcode_fini_cpu(cpu);
/* Suspend is in progress, only remove the interface */
sysfs_remove_group(&dev->kobj, &mc_attr_group);
pr_debug("%s: CPU%d\n", __func__, cpu);
return 0;
}
static void setup_online_cpu(struct work_struct *work)
{
int cpu = smp_processor_id();
enum ucode_state err;
err = microcode_init_cpu(cpu);
if (err == UCODE_ERROR) {
pr_err("Error applying microcode on CPU%d\n", cpu);
return;
}
mc_cpu_online(cpu);
}
static struct attribute *cpu_root_microcode_attrs[] = {
#ifdef CONFIG_MICROCODE_LATE_LOADING
&dev_attr_reload.attr,
@@ -656,14 +842,9 @@ static int __init microcode_init(void)
}
}
/* Do per-CPU setup */
schedule_on_each_cpu(setup_online_cpu);
register_syscore_ops(&mc_syscore_ops);
cpuhp_setup_state_nocalls(CPUHP_AP_MICROCODE_LOADER, "x86/microcode:starting",
mc_cpu_starting, NULL);
cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "x86/microcode:online",
mc_cpu_online, mc_cpu_down_prep);
cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/microcode:online",
mc_cpu_online, mc_cpu_down_prep);
pr_info("Microcode Update Driver: v%s.", DRIVER_VERSION);
@@ -674,5 +855,4 @@ static int __init microcode_init(void)
return error;
}
fs_initcall(save_microcode_in_initrd);
late_initcall(microcode_init);
+244 -480
View File
@@ -14,7 +14,6 @@
#include <linux/earlycpio.h>
#include <linux/firmware.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/initrd.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -32,11 +31,14 @@
static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin";
#define UCODE_BSP_LOADED ((struct microcode_intel *)0x1UL)
/* Current microcode patch used in early patching on the APs. */
static struct microcode_intel *intel_ucode_patch;
static struct microcode_intel *ucode_patch_va __read_mostly;
static struct microcode_intel *ucode_patch_late __read_mostly;
/* last level cache size per core */
static int llc_size_per_core;
static unsigned int llc_size_per_core __ro_after_init;
/* microcode format is extended from prescott processors */
struct extended_signature {
@@ -66,60 +68,52 @@ static inline unsigned int exttable_size(struct extended_sigtable *et)
return et->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE;
}
int intel_cpu_collect_info(struct ucode_cpu_info *uci)
void intel_collect_cpu_info(struct cpu_signature *sig)
{
unsigned int val[2];
unsigned int family, model;
struct cpu_signature csig = { 0 };
unsigned int eax, ebx, ecx, edx;
sig->sig = cpuid_eax(1);
sig->pf = 0;
sig->rev = intel_get_microcode_revision();
memset(uci, 0, sizeof(*uci));
if (x86_model(sig->sig) >= 5 || x86_family(sig->sig) > 6) {
unsigned int val[2];
eax = 0x00000001;
ecx = 0;
native_cpuid(&eax, &ebx, &ecx, &edx);
csig.sig = eax;
family = x86_family(eax);
model = x86_model(eax);
if (model >= 5 || family > 6) {
/* get processor flags from MSR 0x17 */
native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
csig.pf = 1 << ((val[1] >> 18) & 7);
sig->pf = 1 << ((val[1] >> 18) & 7);
}
csig.rev = intel_get_microcode_revision();
uci->cpu_sig = csig;
return 0;
}
EXPORT_SYMBOL_GPL(intel_cpu_collect_info);
EXPORT_SYMBOL_GPL(intel_collect_cpu_info);
/*
* Returns 1 if update has been found, 0 otherwise.
*/
int intel_find_matching_signature(void *mc, unsigned int csig, int cpf)
static inline bool cpu_signatures_match(struct cpu_signature *s1, unsigned int sig2,
unsigned int pf2)
{
if (s1->sig != sig2)
return false;
/* Processor flags are either both 0 or they intersect. */
return ((!s1->pf && !pf2) || (s1->pf & pf2));
}
bool intel_find_matching_signature(void *mc, struct cpu_signature *sig)
{
struct microcode_header_intel *mc_hdr = mc;
struct extended_sigtable *ext_hdr;
struct extended_signature *ext_sig;
struct extended_sigtable *ext_hdr;
int i;
if (intel_cpu_signatures_match(csig, cpf, mc_hdr->sig, mc_hdr->pf))
return 1;
if (cpu_signatures_match(sig, mc_hdr->sig, mc_hdr->pf))
return true;
/* Look for ext. headers: */
if (get_totalsize(mc_hdr) <= intel_microcode_get_datasize(mc_hdr) + MC_HEADER_SIZE)
return 0;
return false;
ext_hdr = mc + intel_microcode_get_datasize(mc_hdr) + MC_HEADER_SIZE;
ext_sig = (void *)ext_hdr + EXT_HEADER_SIZE;
for (i = 0; i < ext_hdr->count; i++) {
if (intel_cpu_signatures_match(csig, cpf, ext_sig->sig, ext_sig->pf))
return 1;
if (cpu_signatures_match(sig, ext_sig->sig, ext_sig->pf))
return true;
ext_sig++;
}
return 0;
@@ -240,264 +234,91 @@ int intel_microcode_sanity_check(void *mc, bool print_err, int hdr_type)
}
EXPORT_SYMBOL_GPL(intel_microcode_sanity_check);
/*
* Returns 1 if update has been found, 0 otherwise.
*/
static int has_newer_microcode(void *mc, unsigned int csig, int cpf, int new_rev)
static void update_ucode_pointer(struct microcode_intel *mc)
{
struct microcode_header_intel *mc_hdr = mc;
if (mc_hdr->rev <= new_rev)
return 0;
return intel_find_matching_signature(mc, csig, cpf);
}
static struct ucode_patch *memdup_patch(void *data, unsigned int size)
{
struct ucode_patch *p;
p = kzalloc(sizeof(struct ucode_patch), GFP_KERNEL);
if (!p)
return NULL;
p->data = kmemdup(data, size, GFP_KERNEL);
if (!p->data) {
kfree(p);
return NULL;
}
return p;
}
static void save_microcode_patch(struct ucode_cpu_info *uci, void *data, unsigned int size)
{
struct microcode_header_intel *mc_hdr, *mc_saved_hdr;
struct ucode_patch *iter, *tmp, *p = NULL;
bool prev_found = false;
unsigned int sig, pf;
mc_hdr = (struct microcode_header_intel *)data;
list_for_each_entry_safe(iter, tmp, &microcode_cache, plist) {
mc_saved_hdr = (struct microcode_header_intel *)iter->data;
sig = mc_saved_hdr->sig;
pf = mc_saved_hdr->pf;
if (intel_find_matching_signature(data, sig, pf)) {
prev_found = true;
if (mc_hdr->rev <= mc_saved_hdr->rev)
continue;
p = memdup_patch(data, size);
if (!p)
pr_err("Error allocating buffer %p\n", data);
else {
list_replace(&iter->plist, &p->plist);
kfree(iter->data);
kfree(iter);
}
}
}
kvfree(ucode_patch_va);
/*
* There weren't any previous patches found in the list cache; save the
* newly found.
* Save the virtual address for early loading and for eventual free
* on late loading.
*/
if (!prev_found) {
p = memdup_patch(data, size);
if (!p)
pr_err("Error allocating buffer for %p\n", data);
else
list_add_tail(&p->plist, &microcode_cache);
}
ucode_patch_va = mc;
}
if (!p)
return;
static void save_microcode_patch(struct microcode_intel *patch)
{
unsigned int size = get_totalsize(&patch->hdr);
struct microcode_intel *mc;
if (!intel_find_matching_signature(p->data, uci->cpu_sig.sig, uci->cpu_sig.pf))
return;
/*
* Save for early loading. On 32-bit, that needs to be a physical
* address as the APs are running from physical addresses, before
* paging has been enabled.
*/
if (IS_ENABLED(CONFIG_X86_32))
intel_ucode_patch = (struct microcode_intel *)__pa_nodebug(p->data);
mc = kvmemdup(patch, size, GFP_KERNEL);
if (mc)
update_ucode_pointer(mc);
else
intel_ucode_patch = p->data;
pr_err("Unable to allocate microcode memory size: %u\n", size);
}
/*
* Get microcode matching with BSP's model. Only CPUs with the same model as
* BSP can stay in the platform.
*/
static struct microcode_intel *
scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, bool save)
/* Scan blob for microcode matching the boot CPUs family, model, stepping */
static __init struct microcode_intel *scan_microcode(void *data, size_t size,
struct ucode_cpu_info *uci,
bool save)
{
struct microcode_header_intel *mc_header;
struct microcode_intel *patch = NULL;
u32 cur_rev = uci->cpu_sig.rev;
unsigned int mc_size;
while (size) {
if (size < sizeof(struct microcode_header_intel))
break;
for (; size >= sizeof(struct microcode_header_intel); size -= mc_size, data += mc_size) {
mc_header = (struct microcode_header_intel *)data;
mc_size = get_totalsize(mc_header);
if (!mc_size ||
mc_size > size ||
if (!mc_size || mc_size > size ||
intel_microcode_sanity_check(data, false, MC_HEADER_TYPE_MICROCODE) < 0)
break;
size -= mc_size;
if (!intel_find_matching_signature(data, &uci->cpu_sig))
continue;
if (!intel_find_matching_signature(data, uci->cpu_sig.sig,
uci->cpu_sig.pf)) {
data += mc_size;
/*
* For saving the early microcode, find the matching revision which
* was loaded on the BSP.
*
* On the BSP during early boot, find a newer revision than
* actually loaded in the CPU.
*/
if (save) {
if (cur_rev != mc_header->rev)
continue;
} else if (cur_rev >= mc_header->rev) {
continue;
}
if (save) {
save_microcode_patch(uci, data, mc_size);
goto next;
}
if (!patch) {
if (!has_newer_microcode(data,
uci->cpu_sig.sig,
uci->cpu_sig.pf,
uci->cpu_sig.rev))
goto next;
} else {
struct microcode_header_intel *phdr = &patch->hdr;
if (!has_newer_microcode(data,
phdr->sig,
phdr->pf,
phdr->rev))
goto next;
}
/* We have a newer patch, save it. */
patch = data;
next:
data += mc_size;
cur_rev = mc_header->rev;
}
if (size)
return NULL;
return patch;
return size ? NULL : patch;
}
static bool load_builtin_intel_microcode(struct cpio_data *cp)
static enum ucode_state __apply_microcode(struct ucode_cpu_info *uci,
struct microcode_intel *mc,
u32 *cur_rev)
{
unsigned int eax = 1, ebx, ecx = 0, edx;
struct firmware fw;
char name[30];
u32 rev;
if (IS_ENABLED(CONFIG_X86_32))
return false;
native_cpuid(&eax, &ebx, &ecx, &edx);
sprintf(name, "intel-ucode/%02x-%02x-%02x",
x86_family(eax), x86_model(eax), x86_stepping(eax));
if (firmware_request_builtin(&fw, name)) {
cp->size = fw.size;
cp->data = (void *)fw.data;
return true;
}
return false;
}
static void print_ucode_info(int old_rev, int new_rev, unsigned int date)
{
pr_info_once("updated early: 0x%x -> 0x%x, date = %04x-%02x-%02x\n",
old_rev,
new_rev,
date & 0xffff,
date >> 24,
(date >> 16) & 0xff);
}
#ifdef CONFIG_X86_32
static int delay_ucode_info;
static int current_mc_date;
static int early_old_rev;
/*
* Print early updated ucode info after printk works. This is delayed info dump.
*/
void show_ucode_info_early(void)
{
struct ucode_cpu_info uci;
if (delay_ucode_info) {
intel_cpu_collect_info(&uci);
print_ucode_info(early_old_rev, uci.cpu_sig.rev, current_mc_date);
delay_ucode_info = 0;
}
}
/*
* At this point, we can not call printk() yet. Delay printing microcode info in
* show_ucode_info_early() until printk() works.
*/
static void print_ucode(int old_rev, int new_rev, int date)
{
int *delay_ucode_info_p;
int *current_mc_date_p;
int *early_old_rev_p;
delay_ucode_info_p = (int *)__pa_nodebug(&delay_ucode_info);
current_mc_date_p = (int *)__pa_nodebug(&current_mc_date);
early_old_rev_p = (int *)__pa_nodebug(&early_old_rev);
*delay_ucode_info_p = 1;
*current_mc_date_p = date;
*early_old_rev_p = old_rev;
}
#else
static inline void print_ucode(int old_rev, int new_rev, int date)
{
print_ucode_info(old_rev, new_rev, date);
}
#endif
static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
{
struct microcode_intel *mc;
u32 rev, old_rev;
mc = uci->mc;
if (!mc)
return 0;
return UCODE_NFOUND;
/*
* Save us the MSR write below - which is a particular expensive
* operation - when the other hyperthread has updated the microcode
* already.
*/
rev = intel_get_microcode_revision();
if (rev >= mc->hdr.rev) {
uci->cpu_sig.rev = rev;
*cur_rev = intel_get_microcode_revision();
if (*cur_rev >= mc->hdr.rev) {
uci->cpu_sig.rev = *cur_rev;
return UCODE_OK;
}
old_rev = rev;
/*
* Writeback and invalidate caches before updating microcode to avoid
* internal issues depending on what the microcode is updating.
@@ -509,247 +330,182 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
rev = intel_get_microcode_revision();
if (rev != mc->hdr.rev)
return -1;
return UCODE_ERROR;
uci->cpu_sig.rev = rev;
if (early)
print_ucode(old_rev, uci->cpu_sig.rev, mc->hdr.date);
else
print_ucode_info(old_rev, uci->cpu_sig.rev, mc->hdr.date);
return 0;
return UCODE_UPDATED;
}
int __init save_microcode_in_initrd_intel(void)
static enum ucode_state apply_microcode_early(struct ucode_cpu_info *uci)
{
struct ucode_cpu_info uci;
struct cpio_data cp;
struct microcode_intel *mc = uci->mc;
enum ucode_state ret;
u32 cur_rev, date;
/*
* initrd is going away, clear patch ptr. We will scan the microcode one
* last time before jettisoning and save a patch, if found. Then we will
* update that pointer too, with a stable patch address to use when
* resuming the cores.
*/
intel_ucode_patch = NULL;
if (!load_builtin_intel_microcode(&cp))
cp = find_microcode_in_initrd(ucode_path, false);
if (!(cp.data && cp.size))
return 0;
intel_cpu_collect_info(&uci);
scan_microcode(cp.data, cp.size, &uci, true);
return 0;
}
/*
* @res_patch, output: a pointer to the patch we found.
*/
static struct microcode_intel *__load_ucode_intel(struct ucode_cpu_info *uci)
{
static const char *path;
struct cpio_data cp;
bool use_pa;
if (IS_ENABLED(CONFIG_X86_32)) {
path = (const char *)__pa_nodebug(ucode_path);
use_pa = true;
} else {
path = ucode_path;
use_pa = false;
ret = __apply_microcode(uci, mc, &cur_rev);
if (ret == UCODE_UPDATED) {
date = mc->hdr.date;
pr_info_once("updated early: 0x%x -> 0x%x, date = %04x-%02x-%02x\n",
cur_rev, mc->hdr.rev, date & 0xffff, date >> 24, (date >> 16) & 0xff);
}
return ret;
}
static __init bool load_builtin_intel_microcode(struct cpio_data *cp)
{
unsigned int eax = 1, ebx, ecx = 0, edx;
struct firmware fw;
char name[30];
if (IS_ENABLED(CONFIG_X86_32))
return false;
native_cpuid(&eax, &ebx, &ecx, &edx);
sprintf(name, "intel-ucode/%02x-%02x-%02x",
x86_family(eax), x86_model(eax), x86_stepping(eax));
if (firmware_request_builtin(&fw, name)) {
cp->size = fw.size;
cp->data = (void *)fw.data;
return true;
}
return false;
}
static __init struct microcode_intel *get_microcode_blob(struct ucode_cpu_info *uci, bool save)
{
struct cpio_data cp;
/* try built-in microcode first */
if (!load_builtin_intel_microcode(&cp))
cp = find_microcode_in_initrd(path, use_pa);
cp = find_microcode_in_initrd(ucode_path);
if (!(cp.data && cp.size))
return NULL;
intel_cpu_collect_info(uci);
intel_collect_cpu_info(&uci->cpu_sig);
return scan_microcode(cp.data, cp.size, uci, false);
return scan_microcode(cp.data, cp.size, uci, save);
}
void __init load_ucode_intel_bsp(void)
/*
* Invoked from an early init call to save the microcode blob which was
* selected during early boot when mm was not usable. The microcode must be
* saved because initrd is going away. It's an early init call so the APs
* just can use the pointer and do not have to scan initrd/builtin firmware
* again.
*/
static int __init save_builtin_microcode(void)
{
struct microcode_intel *patch;
struct ucode_cpu_info uci;
patch = __load_ucode_intel(&uci);
if (!patch)
return;
if (xchg(&ucode_patch_va, NULL) != UCODE_BSP_LOADED)
return 0;
uci.mc = patch;
if (dis_ucode_ldr || boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
return 0;
apply_microcode_early(&uci, true);
uci.mc = get_microcode_blob(&uci, true);
if (uci.mc)
save_microcode_patch(uci.mc);
return 0;
}
early_initcall(save_builtin_microcode);
/* Load microcode on BSP from initrd or builtin blobs */
void __init load_ucode_intel_bsp(void)
{
struct ucode_cpu_info uci;
uci.mc = get_microcode_blob(&uci, false);
if (uci.mc && apply_microcode_early(&uci) == UCODE_UPDATED)
ucode_patch_va = UCODE_BSP_LOADED;
}
void load_ucode_intel_ap(void)
{
struct microcode_intel *patch, **iup;
struct ucode_cpu_info uci;
if (IS_ENABLED(CONFIG_X86_32))
iup = (struct microcode_intel **) __pa_nodebug(&intel_ucode_patch);
else
iup = &intel_ucode_patch;
if (!*iup) {
patch = __load_ucode_intel(&uci);
if (!patch)
return;
*iup = patch;
}
uci.mc = *iup;
apply_microcode_early(&uci, true);
}
static struct microcode_intel *find_patch(struct ucode_cpu_info *uci)
{
struct microcode_header_intel *phdr;
struct ucode_patch *iter, *tmp;
list_for_each_entry_safe(iter, tmp, &microcode_cache, plist) {
phdr = (struct microcode_header_intel *)iter->data;
if (phdr->rev <= uci->cpu_sig.rev)
continue;
if (!intel_find_matching_signature(phdr,
uci->cpu_sig.sig,
uci->cpu_sig.pf))
continue;
return iter->data;
}
return NULL;
uci.mc = ucode_patch_va;
if (uci.mc)
apply_microcode_early(&uci);
}
/* Reload microcode on resume */
void reload_ucode_intel(void)
{
struct microcode_intel *p;
struct ucode_cpu_info uci;
struct ucode_cpu_info uci = { .mc = ucode_patch_va, };
intel_cpu_collect_info(&uci);
p = find_patch(&uci);
if (!p)
return;
uci.mc = p;
apply_microcode_early(&uci, false);
if (uci.mc)
apply_microcode_early(&uci);
}
static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
{
struct cpuinfo_x86 *c = &cpu_data(cpu_num);
unsigned int val[2];
memset(csig, 0, sizeof(*csig));
csig->sig = cpuid_eax(0x00000001);
if ((c->x86_model >= 5) || (c->x86 > 6)) {
/* get processor flags from MSR 0x17 */
rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
csig->pf = 1 << ((val[1] >> 18) & 7);
}
csig->rev = c->microcode;
intel_collect_cpu_info(csig);
return 0;
}
static enum ucode_state apply_microcode_intel(int cpu)
static enum ucode_state apply_microcode_late(int cpu)
{
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
struct cpuinfo_x86 *c = &cpu_data(cpu);
bool bsp = c->cpu_index == boot_cpu_data.cpu_index;
struct microcode_intel *mc;
struct microcode_intel *mc = ucode_patch_late;
enum ucode_state ret;
static int prev_rev;
u32 rev;
u32 cur_rev;
/* We should bind the task to the CPU */
if (WARN_ON(raw_smp_processor_id() != cpu))
if (WARN_ON_ONCE(smp_processor_id() != cpu))
return UCODE_ERROR;
/* Look for a newer patch in our cache: */
mc = find_patch(uci);
if (!mc) {
mc = uci->mc;
if (!mc)
return UCODE_NFOUND;
}
ret = __apply_microcode(uci, mc, &cur_rev);
if (ret != UCODE_UPDATED && ret != UCODE_OK)
return ret;
/*
* Save us the MSR write below - which is a particular expensive
* operation - when the other hyperthread has updated the microcode
* already.
*/
rev = intel_get_microcode_revision();
if (rev >= mc->hdr.rev) {
ret = UCODE_OK;
goto out;
}
/*
* Writeback and invalidate caches before updating microcode to avoid
* internal issues depending on what the microcode is updating.
*/
native_wbinvd();
/* write microcode via MSR 0x79 */
wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
rev = intel_get_microcode_revision();
if (rev != mc->hdr.rev) {
pr_err("CPU%d update to revision 0x%x failed\n",
cpu, mc->hdr.rev);
return UCODE_ERROR;
}
if (bsp && rev != prev_rev) {
pr_info("updated to revision 0x%x, date = %04x-%02x-%02x\n",
rev,
mc->hdr.date & 0xffff,
mc->hdr.date >> 24,
if (!cpu && uci->cpu_sig.rev != cur_rev) {
pr_info("Updated to revision 0x%x, date = %04x-%02x-%02x\n",
uci->cpu_sig.rev, mc->hdr.date & 0xffff, mc->hdr.date >> 24,
(mc->hdr.date >> 16) & 0xff);
prev_rev = rev;
}
ret = UCODE_UPDATED;
out:
uci->cpu_sig.rev = rev;
c->microcode = rev;
/* Update boot_cpu_data's revision too, if we're on the BSP: */
if (bsp)
boot_cpu_data.microcode = rev;
cpu_data(cpu).microcode = uci->cpu_sig.rev;
if (!cpu)
boot_cpu_data.microcode = uci->cpu_sig.rev;
return ret;
}
static enum ucode_state generic_load_microcode(int cpu, struct iov_iter *iter)
static bool ucode_validate_minrev(struct microcode_header_intel *mc_header)
{
int cur_rev = boot_cpu_data.microcode;
/*
* When late-loading, ensure the header declares a minimum revision
* required to perform a late-load. The previously reserved field
* is 0 in older microcode blobs.
*/
if (!mc_header->min_req_ver) {
pr_info("Unsafe microcode update: Microcode header does not specify a required min version\n");
return false;
}
/*
* Check whether the current revision is either greater or equal to
* to the minimum revision specified in the header.
*/
if (cur_rev < mc_header->min_req_ver) {
pr_info("Unsafe microcode update: Current revision 0x%x too old\n", cur_rev);
pr_info("Current should be at 0x%x or higher. Use early loading instead\n", mc_header->min_req_ver);
return false;
}
return true;
}
static enum ucode_state parse_microcode_blobs(int cpu, struct iov_iter *iter)
{
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
unsigned int curr_mc_size = 0, new_mc_size = 0;
enum ucode_state ret = UCODE_OK;
int new_rev = uci->cpu_sig.rev;
bool is_safe, new_is_safe = false;
int cur_rev = uci->cpu_sig.rev;
unsigned int curr_mc_size = 0;
u8 *new_mc = NULL, *mc = NULL;
unsigned int csig, cpf;
while (iov_iter_count(iter)) {
struct microcode_header_intel mc_header;
@@ -758,68 +514,66 @@ static enum ucode_state generic_load_microcode(int cpu, struct iov_iter *iter)
if (!copy_from_iter_full(&mc_header, sizeof(mc_header), iter)) {
pr_err("error! Truncated or inaccessible header in microcode data file\n");
break;
goto fail;
}
mc_size = get_totalsize(&mc_header);
if (mc_size < sizeof(mc_header)) {
pr_err("error! Bad data in microcode data file (totalsize too small)\n");
break;
goto fail;
}
data_size = mc_size - sizeof(mc_header);
if (data_size > iov_iter_count(iter)) {
pr_err("error! Bad data in microcode data file (truncated file?)\n");
break;
goto fail;
}
/* For performance reasons, reuse mc area when possible */
if (!mc || mc_size > curr_mc_size) {
vfree(mc);
mc = vmalloc(mc_size);
kvfree(mc);
mc = kvmalloc(mc_size, GFP_KERNEL);
if (!mc)
break;
goto fail;
curr_mc_size = mc_size;
}
memcpy(mc, &mc_header, sizeof(mc_header));
data = mc + sizeof(mc_header);
if (!copy_from_iter_full(data, data_size, iter) ||
intel_microcode_sanity_check(mc, true, MC_HEADER_TYPE_MICROCODE) < 0) {
break;
}
intel_microcode_sanity_check(mc, true, MC_HEADER_TYPE_MICROCODE) < 0)
goto fail;
csig = uci->cpu_sig.sig;
cpf = uci->cpu_sig.pf;
if (has_newer_microcode(mc, csig, cpf, new_rev)) {
vfree(new_mc);
new_rev = mc_header.rev;
new_mc = mc;
new_mc_size = mc_size;
mc = NULL; /* trigger new vmalloc */
ret = UCODE_NEW;
}
if (cur_rev >= mc_header.rev)
continue;
if (!intel_find_matching_signature(mc, &uci->cpu_sig))
continue;
is_safe = ucode_validate_minrev(&mc_header);
if (force_minrev && !is_safe)
continue;
kvfree(new_mc);
cur_rev = mc_header.rev;
new_mc = mc;
new_is_safe = is_safe;
mc = NULL;
}
vfree(mc);
if (iov_iter_count(iter)) {
vfree(new_mc);
return UCODE_ERROR;
}
if (iov_iter_count(iter))
goto fail;
kvfree(mc);
if (!new_mc)
return UCODE_NFOUND;
vfree(uci->mc);
uci->mc = (struct microcode_intel *)new_mc;
ucode_patch_late = (struct microcode_intel *)new_mc;
return new_is_safe ? UCODE_NEW_SAFE : UCODE_NEW;
/* Save for CPU hotplug */
save_microcode_patch(uci, new_mc, new_mc_size);
pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
cpu, new_rev, uci->cpu_sig.rev);
return ret;
fail:
kvfree(mc);
kvfree(new_mc);
return UCODE_ERROR;
}
static bool is_blacklisted(unsigned int cpu)
@@ -868,26 +622,36 @@ static enum ucode_state request_microcode_fw(int cpu, struct device *device)
kvec.iov_base = (void *)firmware->data;
kvec.iov_len = firmware->size;
iov_iter_kvec(&iter, ITER_SOURCE, &kvec, 1, firmware->size);
ret = generic_load_microcode(cpu, &iter);
ret = parse_microcode_blobs(cpu, &iter);
release_firmware(firmware);
return ret;
}
static void finalize_late_load(int result)
{
if (!result)
update_ucode_pointer(ucode_patch_late);
else
kvfree(ucode_patch_late);
ucode_patch_late = NULL;
}
static struct microcode_ops microcode_intel_ops = {
.request_microcode_fw = request_microcode_fw,
.collect_cpu_info = collect_cpu_info,
.apply_microcode = apply_microcode_intel,
.request_microcode_fw = request_microcode_fw,
.collect_cpu_info = collect_cpu_info,
.apply_microcode = apply_microcode_late,
.finalize_late_load = finalize_late_load,
.use_nmi = IS_ENABLED(CONFIG_X86_64),
};
static int __init calc_llc_size_per_core(struct cpuinfo_x86 *c)
static __init void calc_llc_size_per_core(struct cpuinfo_x86 *c)
{
u64 llc_size = c->x86_cache_size * 1024ULL;
do_div(llc_size, c->x86_max_cores);
return (int)llc_size;
llc_size_per_core = (unsigned int)llc_size;
}
struct microcode_ops * __init init_intel_microcode(void)
@@ -900,7 +664,7 @@ struct microcode_ops * __init init_intel_microcode(void)
return NULL;
}
llc_size_per_core = calc_llc_size_per_core(c);
calc_llc_size_per_core(c);
return &microcode_intel_ops;
}
+13 -22
View File
@@ -8,43 +8,37 @@
#include <asm/cpu.h>
#include <asm/microcode.h>
struct ucode_patch {
struct list_head plist;
void *data; /* Intel uses only this one */
unsigned int size;
u32 patch_id;
u16 equiv_cpu;
};
extern struct list_head microcode_cache;
struct device;
enum ucode_state {
UCODE_OK = 0,
UCODE_NEW,
UCODE_NEW_SAFE,
UCODE_UPDATED,
UCODE_NFOUND,
UCODE_ERROR,
UCODE_TIMEOUT,
UCODE_OFFLINE,
};
struct microcode_ops {
enum ucode_state (*request_microcode_fw)(int cpu, struct device *dev);
void (*microcode_fini_cpu)(int cpu);
/*
* The generic 'microcode_core' part guarantees that
* the callbacks below run on a target cpu when they
* are being called.
* The generic 'microcode_core' part guarantees that the callbacks
* below run on a target CPU when they are being called.
* See also the "Synchronization" section in microcode_core.c.
*/
enum ucode_state (*apply_microcode)(int cpu);
int (*collect_cpu_info)(int cpu, struct cpu_signature *csig);
enum ucode_state (*apply_microcode)(int cpu);
int (*collect_cpu_info)(int cpu, struct cpu_signature *csig);
void (*finalize_late_load)(int result);
unsigned int nmi_safe : 1,
use_nmi : 1;
};
extern struct ucode_cpu_info ucode_cpu_info[];
struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa);
struct cpio_data find_microcode_in_initrd(const char *path);
#define MAX_UCODE_COUNT 128
@@ -94,12 +88,12 @@ static inline unsigned int x86_cpuid_family(void)
return x86_family(eax);
}
extern bool initrd_gone;
extern bool dis_ucode_ldr;
extern bool force_minrev;
#ifdef CONFIG_CPU_SUP_AMD
void load_ucode_amd_bsp(unsigned int family);
void load_ucode_amd_ap(unsigned int family);
void load_ucode_amd_early(unsigned int cpuid_1_eax);
int save_microcode_in_initrd_amd(unsigned int family);
void reload_ucode_amd(unsigned int cpu);
struct microcode_ops *init_amd_microcode(void);
@@ -107,7 +101,6 @@ void exit_amd_microcode(void);
#else /* CONFIG_CPU_SUP_AMD */
static inline void load_ucode_amd_bsp(unsigned int family) { }
static inline void load_ucode_amd_ap(unsigned int family) { }
static inline void load_ucode_amd_early(unsigned int family) { }
static inline int save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; }
static inline void reload_ucode_amd(unsigned int cpu) { }
static inline struct microcode_ops *init_amd_microcode(void) { return NULL; }
@@ -117,13 +110,11 @@ static inline void exit_amd_microcode(void) { }
#ifdef CONFIG_CPU_SUP_INTEL
void load_ucode_intel_bsp(void);
void load_ucode_intel_ap(void);
int save_microcode_in_initrd_intel(void);
void reload_ucode_intel(void);
struct microcode_ops *init_intel_microcode(void);
#else /* CONFIG_CPU_SUP_INTEL */
static inline void load_ucode_intel_bsp(void) { }
static inline void load_ucode_intel_ap(void) { }
static inline int save_microcode_in_initrd_intel(void) { return -EINVAL; }
static inline void reload_ucode_intel(void) { }
static inline struct microcode_ops *init_intel_microcode(void) { return NULL; }
#endif /* !CONFIG_CPU_SUP_INTEL */
+88 -34
View File
@@ -19,6 +19,7 @@
#include <asm/apic.h>
#include <asm/io_apic.h>
#include <asm/bios_ebda.h>
#include <asm/microcode.h>
#include <asm/tlbflush.h>
#include <asm/bootparam_utils.h>
@@ -29,11 +30,33 @@ static void __init i386_default_early_setup(void)
x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc;
}
#ifdef CONFIG_MICROCODE_INITRD32
unsigned long __initdata initrd_start_early;
static pte_t __initdata *initrd_pl2p_start, *initrd_pl2p_end;
static void zap_early_initrd_mapping(void)
{
pte_t *pl2p = initrd_pl2p_start;
for (; pl2p < initrd_pl2p_end; pl2p++) {
*pl2p = (pte_t){ .pte = 0 };
if (!IS_ENABLED(CONFIG_X86_PAE))
*(pl2p + ((PAGE_OFFSET >> PGDIR_SHIFT))) = (pte_t) {.pte = 0};
}
}
#else
static inline void zap_early_initrd_mapping(void) { }
#endif
asmlinkage __visible void __init __noreturn i386_start_kernel(void)
{
/* Make sure IDT is set up before any exception happens */
idt_setup_early_handler();
load_ucode_bsp();
zap_early_initrd_mapping();
cr4_init_shadow();
sanitize_boot_params(&boot_params);
@@ -69,52 +92,83 @@ asmlinkage __visible void __init __noreturn i386_start_kernel(void)
* to the first kernel PMD. Note the upper half of each PMD or PTE are
* always zero at this stage.
*/
void __init mk_early_pgtbl_32(void);
void __init mk_early_pgtbl_32(void)
{
#ifdef __pa
#undef __pa
#endif
#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET)
pte_t pte, *ptep;
int i;
unsigned long *ptr;
/* Enough space to fit pagetables for the low memory linear map */
const unsigned long limit = __pa(_end) +
(PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT);
#ifdef CONFIG_X86_PAE
pmd_t pl2, *pl2p = (pmd_t *)__pa(initial_pg_pmd);
#define SET_PL2(pl2, val) { (pl2).pmd = (val); }
typedef pmd_t pl2_t;
#define pl2_base initial_pg_pmd
#define SET_PL2(val) { .pmd = (val), }
#else
pgd_t pl2, *pl2p = (pgd_t *)__pa(initial_page_table);
#define SET_PL2(pl2, val) { (pl2).pgd = (val); }
typedef pgd_t pl2_t;
#define pl2_base initial_page_table
#define SET_PL2(val) { .pgd = (val), }
#endif
ptep = (pte_t *)__pa(__brk_base);
pte.pte = PTE_IDENT_ATTR;
static __init __no_stack_protector pte_t init_map(pte_t pte, pte_t **ptep, pl2_t **pl2p,
const unsigned long limit)
{
while ((pte.pte & PTE_PFN_MASK) < limit) {
pl2_t pl2 = SET_PL2((unsigned long)*ptep | PDE_IDENT_ATTR);
int i;
SET_PL2(pl2, (unsigned long)ptep | PDE_IDENT_ATTR);
*pl2p = pl2;
#ifndef CONFIG_X86_PAE
/* Kernel PDE entry */
*(pl2p + ((PAGE_OFFSET >> PGDIR_SHIFT))) = pl2;
#endif
for (i = 0; i < PTRS_PER_PTE; i++) {
*ptep = pte;
pte.pte += PAGE_SIZE;
ptep++;
**pl2p = pl2;
if (!IS_ENABLED(CONFIG_X86_PAE)) {
/* Kernel PDE entry */
*(*pl2p + ((PAGE_OFFSET >> PGDIR_SHIFT))) = pl2;
}
pl2p++;
for (i = 0; i < PTRS_PER_PTE; i++) {
**ptep = pte;
pte.pte += PAGE_SIZE;
(*ptep)++;
}
(*pl2p)++;
}
return pte;
}
ptr = (unsigned long *)__pa(&max_pfn_mapped);
void __init __no_stack_protector mk_early_pgtbl_32(void)
{
/* Enough space to fit pagetables for the low memory linear map */
unsigned long limit = __pa_nodebug(_end) + (PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT);
pte_t pte, *ptep = (pte_t *)__pa_nodebug(__brk_base);
struct boot_params __maybe_unused *params;
pl2_t *pl2p = (pl2_t *)__pa_nodebug(pl2_base);
unsigned long *ptr;
pte.pte = PTE_IDENT_ATTR;
pte = init_map(pte, &ptep, &pl2p, limit);
ptr = (unsigned long *)__pa_nodebug(&max_pfn_mapped);
/* Can't use pte_pfn() since it's a call with CONFIG_PARAVIRT */
*ptr = (pte.pte & PTE_PFN_MASK) >> PAGE_SHIFT;
ptr = (unsigned long *)__pa(&_brk_end);
ptr = (unsigned long *)__pa_nodebug(&_brk_end);
*ptr = (unsigned long)ptep + PAGE_OFFSET;
}
#ifdef CONFIG_MICROCODE_INITRD32
/* Running on a hypervisor? */
if (native_cpuid_ecx(1) & BIT(31))
return;
params = (struct boot_params *)__pa_nodebug(&boot_params);
if (!params->hdr.ramdisk_size || !params->hdr.ramdisk_image)
return;
/* Save the virtual start address */
ptr = (unsigned long *)__pa_nodebug(&initrd_start_early);
*ptr = (pte.pte & PTE_PFN_MASK) + PAGE_OFFSET;
*ptr += ((unsigned long)params->hdr.ramdisk_image) & ~PAGE_MASK;
/* Save PLP2 for cleanup */
ptr = (unsigned long *)__pa_nodebug(&initrd_pl2p_start);
*ptr = (unsigned long)pl2p + PAGE_OFFSET;
limit = (unsigned long)params->hdr.ramdisk_image;
pte.pte = PTE_IDENT_ATTR | PFN_ALIGN(limit);
limit = (unsigned long)params->hdr.ramdisk_image + params->hdr.ramdisk_size;
init_map(pte, &ptep, &pl2p, limit);
ptr = (unsigned long *)__pa_nodebug(&initrd_pl2p_end);
*ptr = (unsigned long)pl2p + PAGE_OFFSET;
#endif
}
-10
View File
@@ -118,11 +118,6 @@ SYM_CODE_START(startup_32)
movl %eax, pa(olpc_ofw_pgd)
#endif
#ifdef CONFIG_MICROCODE
/* Early load ucode on BSP. */
call load_ucode_bsp
#endif
/* Create early pagetables. */
call mk_early_pgtbl_32
@@ -157,11 +152,6 @@ SYM_FUNC_START(startup_32_smp)
movl %eax,%ss
leal -__PAGE_OFFSET(%ecx),%esp
#ifdef CONFIG_MICROCODE
/* Early load ucode on AP. */
call load_ucode_ap
#endif
.Ldefault_entry:
movl $(CR0_STATE & ~X86_CR0_PG),%eax
movl %eax,%cr0

Some files were not shown because too many files have changed in this diff Show More