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:
@@ -74,7 +74,6 @@ modules.order
|
||||
#
|
||||
# RPM spec file (make rpm-pkg)
|
||||
#
|
||||
/kernel.spec
|
||||
/rpmbuild/
|
||||
|
||||
#
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
================
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -31,9 +31,6 @@ ifeq ($(CONFIG_RELOCATABLE),y)
|
||||
$(call if_changed,relocs)
|
||||
endif
|
||||
|
||||
%.ko: FORCE
|
||||
@true
|
||||
|
||||
clean:
|
||||
@true
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -35,9 +35,6 @@ ifdef CONFIG_RELOCATABLE
|
||||
$(call if_changed,relocs_check)
|
||||
endif
|
||||
|
||||
%.ko: FORCE
|
||||
@true
|
||||
|
||||
clean:
|
||||
rm -f .tmp_symbols.txt
|
||||
|
||||
|
||||
+3
-6
@@ -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
|
||||
|
||||
@@ -36,9 +36,6 @@ ifdef CONFIG_RELOCATABLE
|
||||
$(call if_changed,relocs_strip)
|
||||
endif
|
||||
|
||||
%.ko: FORCE
|
||||
@true
|
||||
|
||||
clean:
|
||||
@true
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 $@
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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*
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(µcode_nmi_handler_enable);
|
||||
}
|
||||
#else
|
||||
static __always_inline bool microcode_nmi_handler_enabled(void) { return false; }
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_MICROCODE_H */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) { };
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(µcode_nmi_handler_enable);
|
||||
|
||||
stop_machine_cpuslocked(load_cpus_stopped, NULL, cpu_online_mask);
|
||||
|
||||
if (microcode_ops->use_nmi)
|
||||
static_branch_disable_cpuslocked(µcode_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, µcode_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, µcode_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);
|
||||
|
||||
@@ -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, µcode_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, µcode_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(¤t_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, µcode_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 µcode_intel_ops;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user