diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index fd8622aed1b7..d8cd68ed43e4 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2007,7 +2007,7 @@ for the device. By default it is set to false (0). ieee754= [MIPS] Select IEEE Std 754 conformance mode - Format: { strict | legacy | 2008 | relaxed } + Format: { strict | legacy | 2008 | relaxed | emulated } Default: strict Choose which programs will be accepted for execution @@ -2027,6 +2027,8 @@ by the FPU relaxed accept any binaries regardless of whether supported by the FPU + emulated accept any binaries but enable FPU emulator + if binary mode is unsupported by the FPU. The FPU emulator is always able to support both NaN encodings, so if no FPU hardware is present or it has @@ -2724,6 +2726,24 @@ [KVM,ARM,EARLY] Allow use of GICv4 for direct injection of LPIs. + kvm-arm.wfe_trap_policy= + [KVM,ARM] Control when to set WFE instruction trap for + KVM VMs. Traps are allowed but not guaranteed by the + CPU architecture. + + trap: set WFE instruction trap + + notrap: clear WFE instruction trap + + kvm-arm.wfi_trap_policy= + [KVM,ARM] Control when to set WFI instruction trap for + KVM VMs. Traps are allowed but not guaranteed by the + CPU architecture. + + trap: set WFI instruction trap + + notrap: clear WFI instruction trap + kvm_cma_resv_ratio=n [PPC,EARLY] Reserves given percentage from system memory area for contiguous memory allocation for KVM hash pagetable @@ -4038,9 +4058,9 @@ prediction) vulnerability. System may allow data leaks with this option. - no-steal-acc [X86,PV_OPS,ARM64,PPC/PSERIES,RISCV,EARLY] Disable - paravirtualized steal time accounting. steal time is - computed, but won't influence scheduler behaviour + no-steal-acc [X86,PV_OPS,ARM64,PPC/PSERIES,RISCV,LOONGARCH,EARLY] + Disable paravirtualized steal time accounting. steal time + is computed, but won't influence scheduler behaviour nosync [HW,M68K] Disables sync negotiation for all devices. diff --git a/Documentation/arch/powerpc/cpu_families.rst b/Documentation/arch/powerpc/cpu_families.rst index eb7e60649b43..f55433c6b8f3 100644 --- a/Documentation/arch/powerpc/cpu_families.rst +++ b/Documentation/arch/powerpc/cpu_families.rst @@ -128,24 +128,6 @@ IBM BookE - All 32 bit:: +--------------+ - | 401 | - +--------------+ - | - | - v - +--------------+ - | 403 | - +--------------+ - | - | - v - +--------------+ - | 405 | - +--------------+ - | - | - v - +--------------+ | 440 | +--------------+ | diff --git a/Documentation/arch/powerpc/elf_hwcaps.rst b/Documentation/arch/powerpc/elf_hwcaps.rst index 4c896cf077c2..fce7489877b5 100644 --- a/Documentation/arch/powerpc/elf_hwcaps.rst +++ b/Documentation/arch/powerpc/elf_hwcaps.rst @@ -91,6 +91,7 @@ PPC_FEATURE_HAS_MMU PPC_FEATURE_HAS_4xxMAC The processor is 40x or 44x family. + Unused in the kernel since 732b32daef80 ("powerpc: Remove core support for 40x") PPC_FEATURE_UNIFIED_CACHE The processor has a unified L1 cache for instructions and data, as diff --git a/Documentation/arch/powerpc/kvm-nested.rst b/Documentation/arch/powerpc/kvm-nested.rst index 630602a8aa00..5defd13cc6c1 100644 --- a/Documentation/arch/powerpc/kvm-nested.rst +++ b/Documentation/arch/powerpc/kvm-nested.rst @@ -546,7 +546,9 @@ table information. +--------+-------+----+--------+----------------------------------+ | 0x1052 | 0x08 | RW | T | CTRL | +--------+-------+----+--------+----------------------------------+ -| 0x1053-| | | | Reserved | +| 0x1053 | 0x08 | RW | T | DPDES | ++--------+-------+----+--------+----------------------------------+ +| 0x1054-| | | | Reserved | | 0x1FFF | | | | | +--------+-------+----+--------+----------------------------------+ | 0x2000 | 0x04 | RW | T | CR | diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst index 204cd4433af5..02eb4d98b7de 100644 --- a/Documentation/arch/riscv/hwprobe.rst +++ b/Documentation/arch/riscv/hwprobe.rst @@ -192,6 +192,53 @@ The following keys are defined: supported as defined in the RISC-V ISA manual starting from commit d8ab5c78c207 ("Zihintpause is ratified"). + * :c:macro:`RISCV_HWPROBE_EXT_ZVE32X`: The Vector sub-extension Zve32x is + supported, as defined by version 1.0 of the RISC-V Vector extension manual. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVE32F`: The Vector sub-extension Zve32f is + supported, as defined by version 1.0 of the RISC-V Vector extension manual. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVE64X`: The Vector sub-extension Zve64x is + supported, as defined by version 1.0 of the RISC-V Vector extension manual. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVE64F`: The Vector sub-extension Zve64f is + supported, as defined by version 1.0 of the RISC-V Vector extension manual. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVE64D`: The Vector sub-extension Zve64d is + supported, as defined by version 1.0 of the RISC-V Vector extension manual. + + * :c:macro:`RISCV_HWPROBE_EXT_ZIMOP`: The Zimop May-Be-Operations extension is + supported as defined in the RISC-V ISA manual starting from commit + 58220614a5f ("Zimop is ratified/1.0"). + + * :c:macro:`RISCV_HWPROBE_EXT_ZCA`: The Zca extension part of Zc* standard + extensions for code size reduction, as ratified in commit 8be3419c1c0 + ("Zcf doesn't exist on RV64 as it contains no instructions") of + riscv-code-size-reduction. + + * :c:macro:`RISCV_HWPROBE_EXT_ZCB`: The Zcb extension part of Zc* standard + extensions for code size reduction, as ratified in commit 8be3419c1c0 + ("Zcf doesn't exist on RV64 as it contains no instructions") of + riscv-code-size-reduction. + + * :c:macro:`RISCV_HWPROBE_EXT_ZCD`: The Zcd extension part of Zc* standard + extensions for code size reduction, as ratified in commit 8be3419c1c0 + ("Zcf doesn't exist on RV64 as it contains no instructions") of + riscv-code-size-reduction. + + * :c:macro:`RISCV_HWPROBE_EXT_ZCF`: The Zcf extension part of Zc* standard + extensions for code size reduction, as ratified in commit 8be3419c1c0 + ("Zcf doesn't exist on RV64 as it contains no instructions") of + riscv-code-size-reduction. + + * :c:macro:`RISCV_HWPROBE_EXT_ZCMOP`: The Zcmop May-Be-Operations extension is + supported as defined in the RISC-V ISA manual starting from commit + c732a4f39a4 ("Zcmop is ratified/1.0"). + + * :c:macro:`RISCV_HWPROBE_EXT_ZAWRS`: The Zawrs extension is supported as + ratified in commit 98918c844281 ("Merge pull request #1217 from + riscv/zawrs") of riscv-isa-manual. + * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: A bitmask that contains performance information about the selected set of processors. @@ -214,3 +261,6 @@ The following keys are defined: * :c:macro:`RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE`: An unsigned int which represents the size of the Zicboz block in bytes. + +* :c:macro:`RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS`: An unsigned long which + represent the highest userspace virtual address usable. diff --git a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml index 308af58180d1..4d823f3b1f0e 100644 --- a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml +++ b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml @@ -255,7 +255,9 @@ properties: type: object allOf: - $ref: '#/$defs/protocol-node' - - $ref: /schemas/pinctrl/pinctrl.yaml + - anyOf: + - $ref: /schemas/pinctrl/pinctrl.yaml + - $ref: /schemas/firmware/nxp,imx95-scmi-pinctrl.yaml unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/firmware/nxp,imx95-scmi-pinctrl.yaml b/Documentation/devicetree/bindings/firmware/nxp,imx95-scmi-pinctrl.yaml new file mode 100644 index 000000000000..a96fc6cce502 --- /dev/null +++ b/Documentation/devicetree/bindings/firmware/nxp,imx95-scmi-pinctrl.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2024 NXP +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/firmware/nxp,imx95-scmi-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: i.MX System Control and Management Interface (SCMI) Pinctrl Protocol + +maintainers: + - Peng Fan + +allOf: + - $ref: /schemas/pinctrl/pinctrl.yaml + +patternProperties: + 'grp$': + type: object + description: + Pinctrl node's client devices use subnodes for desired pin configuration. + Client device subnodes use below standard properties. + + unevaluatedProperties: false + + properties: + fsl,pins: + description: + each entry consists of 6 integers and represents the mux and config + setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can + be found in . The last + integer CONFIG is the pad setting value like pull-up on this pin. + Please refer to i.MX95 Reference Manual for detailed CONFIG settings. + $ref: /schemas/types.yaml#/definitions/uint32-matrix + items: + items: + - description: | + "mux_reg" indicates the offset of mux register. + - description: | + "conf_reg" indicates the offset of pad configuration register. + - description: | + "input_reg" indicates the offset of select input register. + - description: | + "mux_val" indicates the mux value to be applied. + - description: | + "input_val" indicates the select input value to be applied. + - description: | + "pad_setting" indicates the pad configuration value to be applied. + + required: + - fsl,pins + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-intc.yaml index fb5593724059..833a01cdd1b1 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-intc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-intc.yaml @@ -25,6 +25,7 @@ properties: - items: - enum: - realtek,rtl8380-intc + - realtek,rtl9300-intc - const: realtek,rtl-intc - const: realtek,rtl-intc deprecated: true @@ -35,7 +36,10 @@ properties: const: 1 reg: - maxItems: 1 + minItems: 1 + items: + - description: vpe0 registers + - description: vpe1 registers interrupts: minItems: 1 @@ -71,6 +75,20 @@ allOf: else: required: - interrupts + - if: + properties: + compatible: + contains: + const: realtek,rtl9300-intc + then: + properties: + reg: + minItems: 2 + maxItems: 2 + else: + properties: + reg: + maxItems: 1 additionalProperties: false diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.txt deleted file mode 100644 index 265b223cd978..000000000000 --- a/Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.txt +++ /dev/null @@ -1,52 +0,0 @@ -RISC-V Hart-Level Interrupt Controller (HLIC) ---------------------------------------------- - -RISC-V cores include Control Status Registers (CSRs) which are local to each -CPU core (HART in RISC-V terminology) and can be read or written by software. -Some of these CSRs are used to control local interrupts connected to the core. -Every interrupt is ultimately routed through a hart's HLIC before it -interrupts that hart. - -The RISC-V supervisor ISA manual specifies three interrupt sources that are -attached to every HLIC: software interrupts, the timer interrupt, and external -interrupts. Software interrupts are used to send IPIs between cores. The -timer interrupt comes from an architecturally mandated real-time timer that is -controlled via Supervisor Binary Interface (SBI) calls and CSR reads. External -interrupts connect all other device interrupts to the HLIC, which are routed -via the platform-level interrupt controller (PLIC). - -All RISC-V systems that conform to the supervisor ISA specification are -required to have a HLIC with these three interrupt sources present. Since the -interrupt map is defined by the ISA it's not listed in the HLIC's device tree -entry, though external interrupt controllers (like the PLIC, for example) will -need to define how their interrupts map to the relevant HLICs. This means -a PLIC interrupt property will typically list the HLICs for all present HARTs -in the system. - -Required properties: -- compatible : "riscv,cpu-intc" -- #interrupt-cells : should be <1>. The interrupt sources are defined by the - RISC-V supervisor ISA manual, with only the following three interrupts being - defined for supervisor mode: - - Source 1 is the supervisor software interrupt, which can be sent by an SBI - call and is reserved for use by software. - - Source 5 is the supervisor timer interrupt, which can be configured by - SBI calls and implements a one-shot timer. - - Source 9 is the supervisor external interrupt, which chains to all other - device interrupts. -- interrupt-controller : Identifies the node as an interrupt controller - -Furthermore, this interrupt-controller MUST be embedded inside the cpu -definition of the hart whose CSRs control these local interrupts. - -An example device tree entry for a HLIC is show below. - - cpu1: cpu@1 { - compatible = "riscv"; - ... - cpu1-intc: interrupt-controller { - #interrupt-cells = <1>; - compatible = "sifive,fu540-c000-cpu-intc", "riscv,cpu-intc"; - interrupt-controller; - }; - }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.yaml new file mode 100644 index 000000000000..83256cc0bd5c --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/riscv,cpu-intc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V Hart-Level Interrupt Controller (HLIC) + +description: + RISC-V cores include Control Status Registers (CSRs) which are local to + each CPU core (HART in RISC-V terminology) and can be read or written by + software. Some of these CSRs are used to control local interrupts connected + to the core. Every interrupt is ultimately routed through a hart's HLIC + before it interrupts that hart. + + The RISC-V supervisor ISA manual specifies three interrupt sources that are + attached to every HLIC namely software interrupts, the timer interrupt, and + external interrupts. Software interrupts are used to send IPIs between + cores. The timer interrupt comes from an architecturally mandated real- + time timer that is controlled via Supervisor Binary Interface (SBI) calls + and CSR reads. External interrupts connect all other device interrupts to + the HLIC, which are routed via the platform-level interrupt controller + (PLIC). + + All RISC-V systems that conform to the supervisor ISA specification are + required to have a HLIC with these three interrupt sources present. Since + the interrupt map is defined by the ISA it's not listed in the HLIC's device + tree entry, though external interrupt controllers (like the PLIC, for + example) will need to define how their interrupts map to the relevant HLICs. + This means a PLIC interrupt property will typically list the HLICs for all + present HARTs in the system. + +maintainers: + - Palmer Dabbelt + - Paul Walmsley + +properties: + compatible: + oneOf: + - items: + - const: andestech,cpu-intc + - const: riscv,cpu-intc + - const: riscv,cpu-intc + + interrupt-controller: true + + '#interrupt-cells': + const: 1 + description: | + The interrupt sources are defined by the RISC-V supervisor ISA manual, + with only the following three interrupts being defined for + supervisor mode: + - Source 1 is the supervisor software interrupt, which can be sent by + an SBI call and is reserved for use by software. + - Source 5 is the supervisor timer interrupt, which can be configured + by SBI calls and implements a one-shot timer. + - Source 9 is the supervisor external interrupt, which chains to all + other device interrupts. + +required: + - compatible + - '#interrupt-cells' + - interrupt-controller + +additionalProperties: false + +examples: + - | + interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; diff --git a/Documentation/devicetree/bindings/mips/brcm/soc.yaml b/Documentation/devicetree/bindings/mips/brcm/soc.yaml index 975945ca2888..0cc634482a6a 100644 --- a/Documentation/devicetree/bindings/mips/brcm/soc.yaml +++ b/Documentation/devicetree/bindings/mips/brcm/soc.yaml @@ -55,6 +55,16 @@ properties: under the "cpus" node. $ref: /schemas/types.yaml#/definitions/uint32 + brcm,bmips-cbr-reg: + description: Reference address of the CBR. + Some SoC suffer from a BUG where CBR(Core Base Register) + address might be badly or never initialized by the Bootloader + or reading it from co-processor registers, if the system boots + from secondary CPU, results in invalid address. + The CBR address is always the same on the SoC hence it + can be provided in DT to handle these broken case. + $ref: /schemas/types.yaml#/definitions/uint32 + patternProperties: "^cpu@[0-9]$": type: object @@ -64,6 +74,20 @@ properties: required: - mips-hpt-frequency +if: + properties: + compatible: + contains: + enum: + - brcm,bcm6358 + - brcm,bcm6368 + +then: + properties: + cpus: + required: + - brcm,bmips-cbr-reg + additionalProperties: true examples: diff --git a/Documentation/devicetree/bindings/mips/mobileye.yaml b/Documentation/devicetree/bindings/mips/mobileye.yaml index 831975f6b479..d60744550e46 100644 --- a/Documentation/devicetree/bindings/mips/mobileye.yaml +++ b/Documentation/devicetree/bindings/mips/mobileye.yaml @@ -26,6 +26,11 @@ properties: - enum: - mobileye,eyeq5-epm5 - const: mobileye,eyeq5 + - description: Boards with Mobileye EyeQ6H SoC + items: + - enum: + - mobileye,eyeq6h-epm6 + - const: mobileye,eyeq6h additionalProperties: true diff --git a/Documentation/devicetree/bindings/mips/realtek-rtl.yaml b/Documentation/devicetree/bindings/mips/realtek-rtl.yaml index f8ac309d2994..d337655bfbf8 100644 --- a/Documentation/devicetree/bindings/mips/realtek-rtl.yaml +++ b/Documentation/devicetree/bindings/mips/realtek-rtl.yaml @@ -20,5 +20,9 @@ properties: - enum: - cisco,sg220-26 - const: realtek,rtl8382-soc + - items: + - enum: + - cameo,rtl9302c-2x-rtl8224-2xge + - const: realtek,rtl9302-soc additionalProperties: true diff --git a/Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml b/Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml index 57b6957c8415..284f0f882c32 100644 --- a/Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml @@ -64,11 +64,29 @@ patternProperties: items: maximum: 0 + amlogic,boot-pages: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Number of pages starting from offset 0, where a special ECC + configuration must be used because it is accessed by the ROM + code. This ECC configuration uses 384 bytes data blocks. + Also scrambling mode is enabled for such pages. + + amlogic,boot-page-step: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Interval between pages, accessed by the ROM code. For example + we have 8 pages [0, 7]. Pages 0,2,4,6 are accessed by the + ROM code, so this field will be 2 (e.g. every 2nd page). Rest + of pages - 1,3,5,7 are read/written without this mode. + unevaluatedProperties: false dependencies: nand-ecc-strength: [nand-ecc-step-size] nand-ecc-step-size: [nand-ecc-strength] + amlogic,boot-pages: [nand-is-boot-medium, "amlogic,boot-page-step"] + amlogic,boot-page-step: [nand-is-boot-medium, "amlogic,boot-pages"] required: diff --git a/Documentation/devicetree/bindings/mtd/gpmi-nand.yaml b/Documentation/devicetree/bindings/mtd/gpmi-nand.yaml index 021c0da0b072..f9eb1868ca1f 100644 --- a/Documentation/devicetree/bindings/mtd/gpmi-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/gpmi-nand.yaml @@ -24,6 +24,7 @@ properties: - fsl,imx6q-gpmi-nand - fsl,imx6sx-gpmi-nand - fsl,imx7d-gpmi-nand + - fsl,imx8qxp-gpmi-nand - items: - enum: - fsl,imx8mm-gpmi-nand @@ -151,6 +152,27 @@ allOf: - const: gpmi_io - const: gpmi_bch_apb + - if: + properties: + compatible: + contains: + enum: + - fsl,imx8qxp-gpmi-nand + then: + properties: + clocks: + items: + - description: SoC gpmi io clock + - description: SoC gpmi apb clock + - description: SoC gpmi bch clock + - description: SoC gpmi bch apb clock + clock-names: + items: + - const: gpmi_io + - const: gpmi_apb + - const: gpmi_bch + - const: gpmi_bch_apb + examples: - | nand-controller@8000c000 { diff --git a/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml b/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml index 4ada60fbf81d..35b4206ea918 100644 --- a/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml +++ b/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml @@ -31,6 +31,18 @@ properties: - const: core - const: aon + qcom,cmd-crci: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Must contain the ADM command type CRCI block instance number specified for + the NAND controller on the given platform + + qcom,data-crci: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Must contain the ADM data type CRCI block instance number specified for + the NAND controller on the given platform + patternProperties: "^nand@[a-f0-9]$": type: object @@ -83,18 +95,6 @@ allOf: items: - const: rxtx - qcom,cmd-crci: - $ref: /schemas/types.yaml#/definitions/uint32 - description: - Must contain the ADM command type CRCI block instance number - specified for the NAND controller on the given platform - - qcom,data-crci: - $ref: /schemas/types.yaml#/definitions/uint32 - description: - Must contain the ADM data type CRCI block instance number - specified for the NAND controller on the given platform - - if: properties: compatible: @@ -119,19 +119,9 @@ allOf: - const: rx - const: cmd - - if: - properties: - compatible: - contains: - enum: - - qcom,ipq806x-nand + qcom,cmd-crci: false + qcom,data-crci: false - then: - patternProperties: - "^nand@[a-f0-9]$": - properties: - qcom,boot-partitions: true - else: patternProperties: "^nand@[a-f0-9]$": properties: diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml index 37c0a74c7c01..23ed9a8b6689 100644 --- a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml @@ -35,22 +35,159 @@ additionalProperties: patternProperties: "^function|groups$": - enum: [ ACPI, ADC0, ADC1, ADC10, ADC11, ADC12, ADC13, ADC14, ADC15, - ADC2, ADC3, ADC4, ADC5, ADC6, ADC7, ADC8, ADC9, BMCINT, DDCCLK, DDCDAT, - EXTRST, FLACK, FLBUSY, FLWP, GPID, GPID0, GPID2, GPID4, GPID6, GPIE0, - GPIE2, GPIE4, GPIE6, I2C10, I2C11, I2C12, I2C13, I2C14, I2C3, I2C4, - I2C5, I2C6, I2C7, I2C8, I2C9, LPCPD, LPCPME, LPCRST, LPCSMI, MAC1LINK, - MAC2LINK, MDIO1, MDIO2, NCTS1, NCTS2, NCTS3, NCTS4, NDCD1, NDCD2, - NDCD3, NDCD4, NDSR1, NDSR2, NDSR3, NDSR4, NDTR1, NDTR2, NDTR3, NDTR4, - NDTS4, NRI1, NRI2, NRI3, NRI4, NRTS1, NRTS2, NRTS3, OSCCLK, PWM0, - PWM1, PWM2, PWM3, PWM4, PWM5, PWM6, PWM7, RGMII1, RGMII2, RMII1, - RMII2, ROM16, ROM8, ROMCS1, ROMCS2, ROMCS3, ROMCS4, RXD1, RXD2, RXD3, - RXD4, SALT1, SALT2, SALT3, SALT4, SD1, SD2, SGPMCK, SGPMI, SGPMLD, - SGPMO, SGPSCK, SGPSI0, SGPSI1, SGPSLD, SIOONCTRL, SIOPBI, SIOPBO, - SIOPWREQ, SIOPWRGD, SIOS3, SIOS5, SIOSCI, SPI1, SPI1DEBUG, SPI1PASSTHRU, - SPICS1, TIMER3, TIMER4, TIMER5, TIMER6, TIMER7, TIMER8, TXD1, TXD2, - TXD3, TXD4, UART6, USB11D1, USB11H2, USB2D1, USB2H1, USBCKI, VGABIOS_ROM, - VGAHS, VGAVS, VPI18, VPI24, VPI30, VPO12, VPO24, WDTRST1, WDTRST2] + enum: + - ACPI + - ADC0 + - ADC1 + - ADC10 + - ADC11 + - ADC12 + - ADC13 + - ADC14 + - ADC15 + - ADC2 + - ADC3 + - ADC4 + - ADC5 + - ADC6 + - ADC7 + - ADC8 + - ADC9 + - BMCINT + - DDCCLK + - DDCDAT + - EXTRST + - FLACK + - FLBUSY + - FLWP + - GPID + - GPID0 + - GPID2 + - GPID4 + - GPID6 + - GPIE0 + - GPIE2 + - GPIE4 + - GPIE6 + - I2C10 + - I2C11 + - I2C12 + - I2C13 + - I2C14 + - I2C3 + - I2C4 + - I2C5 + - I2C6 + - I2C7 + - I2C8 + - I2C9 + - LPCPD + - LPCPME + - LPCRST + - LPCSMI + - MAC1LINK + - MAC2LINK + - MDIO1 + - MDIO2 + - NCTS1 + - NCTS2 + - NCTS3 + - NCTS4 + - NDCD1 + - NDCD2 + - NDCD3 + - NDCD4 + - NDSR1 + - NDSR2 + - NDSR3 + - NDSR4 + - NDTR1 + - NDTR2 + - NDTR3 + - NDTR4 + - NDTS4 + - NRI1 + - NRI2 + - NRI3 + - NRI4 + - NRTS1 + - NRTS2 + - NRTS3 + - OSCCLK + - PWM0 + - PWM1 + - PWM2 + - PWM3 + - PWM4 + - PWM5 + - PWM6 + - PWM7 + - RGMII1 + - RGMII2 + - RMII1 + - RMII2 + - ROM16 + - ROM8 + - ROMCS1 + - ROMCS2 + - ROMCS3 + - ROMCS4 + - RXD1 + - RXD2 + - RXD3 + - RXD4 + - SALT1 + - SALT2 + - SALT3 + - SALT4 + - SD1 + - SD2 + - SGPMCK + - SGPMI + - SGPMLD + - SGPMO + - SGPSCK + - SGPSI0 + - SGPSI1 + - SGPSLD + - SIOONCTRL + - SIOPBI + - SIOPBO + - SIOPWREQ + - SIOPWRGD + - SIOS3 + - SIOS5 + - SIOSCI + - SPI1 + - SPI1DEBUG + - SPI1PASSTHRU + - SPICS1 + - TIMER3 + - TIMER4 + - TIMER5 + - TIMER6 + - TIMER7 + - TIMER8 + - TXD1 + - TXD2 + - TXD3 + - TXD4 + - UART6 + - USB11D1 + - USB11H2 + - USB2D1 + - USB2H1 + - USBCKI + - VGABIOS_ROM + - VGAHS + - VGAVS + - VPI18 + - VPI24 + - VPI30 + - VPO12 + - VPO24 + - WDTRST1 + - WDTRST2 allOf: - $ref: pinctrl.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml index 863da5d80826..35bd0e1eadae 100644 --- a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml @@ -35,7 +35,7 @@ properties: description: | A cell of phandles to external controller nodes: 0: compatible with "aspeed,ast2500-gfx", "syscon" - 1: compatible with "aspeed,ast2500-lhc", "syscon" + 1: compatible with "aspeed,ast2500-lpc", "syscon" additionalProperties: $ref: pinmux-node.yaml# @@ -47,24 +47,174 @@ additionalProperties: patternProperties: "^function|groups$": - enum: [ ACPI, ADC0, ADC1, ADC10, ADC11, ADC12, ADC13, ADC14, ADC15, - ADC2, ADC3, ADC4, ADC5, ADC6, ADC7, ADC8, ADC9, BMCINT, DDCCLK, DDCDAT, - ESPI, FWSPICS1, FWSPICS2, GPID0, GPID2, GPID4, GPID6, GPIE0, GPIE2, - GPIE4, GPIE6, I2C10, I2C11, I2C12, I2C13, I2C14, I2C3, I2C4, I2C5, - I2C6, I2C7, I2C8, I2C9, LAD0, LAD1, LAD2, LAD3, LCLK, LFRAME, LPCHC, - LPCPD, LPCPLUS, LPCPME, LPCRST, LPCSMI, LSIRQ, MAC1LINK, MAC2LINK, - MDIO1, MDIO2, NCTS1, NCTS2, NCTS3, NCTS4, NDCD1, NDCD2, NDCD3, NDCD4, - NDSR1, NDSR2, NDSR3, NDSR4, NDTR1, NDTR2, NDTR3, NDTR4, NRI1, NRI2, - NRI3, NRI4, NRTS1, NRTS2, NRTS3, NRTS4, OSCCLK, PEWAKE, PNOR, PWM0, - PWM1, PWM2, PWM3, PWM4, PWM5, PWM6, PWM7, RGMII1, RGMII2, RMII1, - RMII2, RXD1, RXD2, RXD3, RXD4, SALT1, SALT10, SALT11, SALT12, SALT13, - SALT14, SALT2, SALT3, SALT4, SALT5, SALT6, SALT7, SALT8, SALT9, SCL1, - SCL2, SD1, SD2, SDA1, SDA2, SGPS1, SGPS2, SIOONCTRL, SIOPBI, SIOPBO, - SIOPWREQ, SIOPWRGD, SIOS3, SIOS5, SIOSCI, SPI1, SPI1CS1, SPI1DEBUG, - SPI1PASSTHRU, SPI2CK, SPI2CS0, SPI2CS1, SPI2MISO, SPI2MOSI, TIMER3, - TIMER4, TIMER5, TIMER6, TIMER7, TIMER8, TXD1, TXD2, TXD3, TXD4, UART6, - USB11BHID, USB2AD, USB2AH, USB2BD, USB2BH, USBCKI, VGABIOSROM, VGAHS, - VGAVS, VPI24, VPO, WDTRST1, WDTRST2] + enum: + - ACPI + - ADC0 + - ADC1 + - ADC10 + - ADC11 + - ADC12 + - ADC13 + - ADC14 + - ADC15 + - ADC2 + - ADC3 + - ADC4 + - ADC5 + - ADC6 + - ADC7 + - ADC8 + - ADC9 + - BMCINT + - DDCCLK + - DDCDAT + - ESPI + - FWSPICS1 + - FWSPICS2 + - GPID0 + - GPID2 + - GPID4 + - GPID6 + - GPIE0 + - GPIE2 + - GPIE4 + - GPIE6 + - I2C10 + - I2C11 + - I2C12 + - I2C13 + - I2C14 + - I2C3 + - I2C4 + - I2C5 + - I2C6 + - I2C7 + - I2C8 + - I2C9 + - LAD0 + - LAD1 + - LAD2 + - LAD3 + - LCLK + - LFRAME + - LPCHC + - LPCPD + - LPCPLUS + - LPCPME + - LPCRST + - LPCSMI + - LSIRQ + - MAC1LINK + - MAC2LINK + - MDIO1 + - MDIO2 + - NCTS1 + - NCTS2 + - NCTS3 + - NCTS4 + - NDCD1 + - NDCD2 + - NDCD3 + - NDCD4 + - NDSR1 + - NDSR2 + - NDSR3 + - NDSR4 + - NDTR1 + - NDTR2 + - NDTR3 + - NDTR4 + - NRI1 + - NRI2 + - NRI3 + - NRI4 + - NRTS1 + - NRTS2 + - NRTS3 + - NRTS4 + - OSCCLK + - PEWAKE + - PNOR + - PWM0 + - PWM1 + - PWM2 + - PWM3 + - PWM4 + - PWM5 + - PWM6 + - PWM7 + - RGMII1 + - RGMII2 + - RMII1 + - RMII2 + - RXD1 + - RXD2 + - RXD3 + - RXD4 + - SALT1 + - SALT10 + - SALT11 + - SALT12 + - SALT13 + - SALT14 + - SALT2 + - SALT3 + - SALT4 + - SALT5 + - SALT6 + - SALT7 + - SALT8 + - SALT9 + - SCL1 + - SCL2 + - SD1 + - SD2 + - SDA1 + - SDA2 + - SGPM + - SGPS1 + - SGPS2 + - SIOONCTRL + - SIOPBI + - SIOPBO + - SIOPWREQ + - SIOPWRGD + - SIOS3 + - SIOS5 + - SIOSCI + - SPI1 + - SPI1CS1 + - SPI1DEBUG + - SPI1PASSTHRU + - SPI2CK + - SPI2CS0 + - SPI2CS1 + - SPI2MISO + - SPI2MOSI + - TIMER3 + - TIMER4 + - TIMER5 + - TIMER6 + - TIMER7 + - TIMER8 + - TXD1 + - TXD2 + - TXD3 + - TXD4 + - UART6 + - USB11BHID + - USB2AD + - USB2AH + - USB2BD + - USB2BH + - USBCKI + - VGABIOSROM + - VGAHS + - VGAVS + - VPI24 + - VPO + - WDTRST1 + - WDTRST2 allOf: - $ref: pinctrl.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml index 612464aef98b..80974c46f3ef 100644 --- a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml @@ -19,6 +19,11 @@ description: |+ Refer to the bindings described in Documentation/devicetree/bindings/mfd/syscon.yaml + Note: According to the NCSI specification, the reference clock output pin + (RMIIXRCLKO) is not required on the management controller side. To optimize + pin usage, add "NCSI" pin groups that are equivalent to the RMII pin groups, + but without the RMIIXRCLKO pin. + properties: compatible: const: aspeed,ast2600-pinctrl @@ -29,56 +34,469 @@ additionalProperties: properties: function: - enum: [ ADC0, ADC1, ADC10, ADC11, ADC12, ADC13, ADC14, ADC15, ADC2, - ADC3, ADC4, ADC5, ADC6, ADC7, ADC8, ADC9, BMCINT, EMMC, ESPI, ESPIALT, - FSI1, FSI2, FWQSPI, FWSPIABR, FWSPID, FWSPIWP, GPIT0, GPIT1, GPIT2, GPIT3, - GPIT4, GPIT5, GPIT6, GPIT7, GPIU0, GPIU1, GPIU2, GPIU3, GPIU4, GPIU5, - GPIU6, GPIU7, I2C1, I2C10, I2C11, I2C12, I2C13, I2C14, I2C15, I2C16, - I2C2, I2C3, I2C4, I2C5, I2C6, I2C7, I2C8, I2C9, I3C3, I3C4, I3C5, - I3C6, JTAGM, LHPD, LHSIRQ, LPC, LPCHC, LPCPD, LPCPME, LPCSMI, LSIRQ, - MACLINK1, MACLINK2, MACLINK3, MACLINK4, MDIO1, MDIO2, MDIO3, MDIO4, - NCTS1, NCTS2, NCTS3, NCTS4, NDCD1, NDCD2, NDCD3, NDCD4, NDSR1, NDSR2, - NDSR3, NDSR4, NDTR1, NDTR2, NDTR3, NDTR4, NRI1, NRI2, NRI3, NRI4, - NRTS1, NRTS2, NRTS3, NRTS4, OSCCLK, PEWAKE, PWM0, PWM1, PWM10, PWM11, - PWM12, PWM13, PWM14, PWM15, PWM2, PWM3, PWM4, PWM5, PWM6, PWM7, PWM8, - PWM9, RGMII1, RGMII2, RGMII3, RGMII4, RMII1, RMII2, RMII3, RMII4, - RXD1, RXD2, RXD3, RXD4, SALT1, SALT10, SALT11, SALT12, SALT13, SALT14, - SALT15, SALT16, SALT2, SALT3, SALT4, SALT5, SALT6, SALT7, SALT8, - SALT9, SD1, SD2, SGPM1, SGPM2, SGPS1, SGPS2, SIOONCTRL, SIOPBI, SIOPBO, - SIOPWREQ, SIOPWRGD, SIOS3, SIOS5, SIOSCI, SPI1, SPI1ABR, SPI1CS1, SPI1WP, SPI2, - SPI2CS1, SPI2CS2, TACH0, TACH1, TACH10, TACH11, TACH12, TACH13, TACH14, - TACH15, TACH2, TACH3, TACH4, TACH5, TACH6, TACH7, TACH8, TACH9, THRU0, - THRU1, THRU2, THRU3, TXD1, TXD2, TXD3, TXD4, UART10, UART11, UART12, - UART13, UART6, UART7, UART8, UART9, USBAD, USBADP, USB2AH, USB2AHP, - USB2BD, USB2BH, VB, VGAHS, VGAVS, WDTRST1, WDTRST2, WDTRST3, WDTRST4 ] + enum: + - ADC0 + - ADC1 + - ADC10 + - ADC11 + - ADC12 + - ADC13 + - ADC14 + - ADC15 + - ADC2 + - ADC3 + - ADC4 + - ADC5 + - ADC6 + - ADC7 + - ADC8 + - ADC9 + - BMCINT + - EMMC + - ESPI + - ESPIALT + - FSI1 + - FSI2 + - FWQSPI + - FWSPIABR + - FWSPID + - FWSPIWP + - GPIT0 + - GPIT1 + - GPIT2 + - GPIT3 + - GPIT4 + - GPIT5 + - GPIT6 + - GPIT7 + - GPIU0 + - GPIU1 + - GPIU2 + - GPIU3 + - GPIU4 + - GPIU5 + - GPIU6 + - GPIU7 + - I2C1 + - I2C10 + - I2C11 + - I2C12 + - I2C13 + - I2C14 + - I2C15 + - I2C16 + - I2C2 + - I2C3 + - I2C4 + - I2C5 + - I2C6 + - I2C7 + - I2C8 + - I2C9 + - I3C1 + - I3C2 + - I3C3 + - I3C4 + - I3C5 + - I3C6 + - JTAGM + - LHPD + - LHSIRQ + - LPC + - LPCHC + - LPCPD + - LPCPME + - LPCSMI + - LSIRQ + - MACLINK1 + - MACLINK2 + - MACLINK3 + - MACLINK4 + - MDIO1 + - MDIO2 + - MDIO3 + - MDIO4 + - NCTS1 + - NCTS2 + - NCTS3 + - NCTS4 + - NDCD1 + - NDCD2 + - NDCD3 + - NDCD4 + - NDSR1 + - NDSR2 + - NDSR3 + - NDSR4 + - NDTR1 + - NDTR2 + - NDTR3 + - NDTR4 + - NRI1 + - NRI2 + - NRI3 + - NRI4 + - NRTS1 + - NRTS2 + - NRTS3 + - NRTS4 + - OSCCLK + - PEWAKE + - PWM0 + - PWM1 + - PWM10 + - PWM11 + - PWM12 + - PWM13 + - PWM14 + - PWM15 + - PWM2 + - PWM3 + - PWM4 + - PWM5 + - PWM6 + - PWM7 + - PWM8 + - PWM9 + - RGMII1 + - RGMII2 + - RGMII3 + - RGMII4 + - RMII1 + - RMII2 + - RMII3 + - RMII4 + - RXD1 + - RXD2 + - RXD3 + - RXD4 + - SALT1 + - SALT10 + - SALT11 + - SALT12 + - SALT13 + - SALT14 + - SALT15 + - SALT16 + - SALT2 + - SALT3 + - SALT4 + - SALT5 + - SALT6 + - SALT7 + - SALT8 + - SALT9 + - SD1 + - SD2 + - SGPM1 + - SGPM2 + - SGPS1 + - SGPS2 + - SIOONCTRL + - SIOPBI + - SIOPBO + - SIOPWREQ + - SIOPWRGD + - SIOS3 + - SIOS5 + - SIOSCI + - SPI1 + - SPI1ABR + - SPI1CS1 + - SPI1WP + - SPI2 + - SPI2CS1 + - SPI2CS2 + - TACH0 + - TACH1 + - TACH10 + - TACH11 + - TACH12 + - TACH13 + - TACH14 + - TACH15 + - TACH2 + - TACH3 + - TACH4 + - TACH5 + - TACH6 + - TACH7 + - TACH8 + - TACH9 + - THRU0 + - THRU1 + - THRU2 + - THRU3 + - TXD1 + - TXD2 + - TXD3 + - TXD4 + - UART10 + - UART11 + - UART12 + - UART13 + - UART6 + - UART7 + - UART8 + - UART9 + - USB11BHID + - USB2AD + - USB2AH + - USB2AHP + - USB2BD + - USB2BH + - USBAD + - USBADP + - VB + - VGAHS + - VGAVS + - WDTRST1 + - WDTRST2 + - WDTRST3 + - WDTRST4 groups: - enum: [ ADC0, ADC1, ADC10, ADC11, ADC12, ADC13, ADC14, ADC15, ADC2, - ADC3, ADC4, ADC5, ADC6, ADC7, ADC8, ADC9, BMCINT, EMMCG1, EMMCG4, - EMMCG8, ESPI, ESPIALT, FSI1, FSI2, FWQSPI, FWSPIABR, FWSPID, FWSPIWP, - GPIT0, GPIT1, GPIT2, GPIT3, GPIT4, GPIT5, GPIT6, GPIT7, GPIU0, GPIU1, - GPIU2, GPIU3, GPIU4, GPIU5, GPIU6, GPIU7, HVI3C3, HVI3C4, I2C1, I2C10, - I2C11, I2C12, I2C13, I2C14, I2C15, I2C16, I2C2, I2C3, I2C4, I2C5, - I2C6, I2C7, I2C8, I2C9, I3C3, I3C4, I3C5, I3C6, JTAGM, LHPD, LHSIRQ, - LPC, LPCHC, LPCPD, LPCPME, LPCSMI, LSIRQ, MACLINK1, MACLINK2, MACLINK3, - MACLINK4, MDIO1, MDIO2, MDIO3, MDIO4, NCTS1, NCTS2, NCTS3, NCTS4, - NDCD1, NDCD2, NDCD3, NDCD4, NDSR1, NDSR2, NDSR3, NDSR4, NDTR1, NDTR2, - NDTR3, NDTR4, NRI1, NRI2, NRI3, NRI4, NRTS1, NRTS2, NRTS3, NRTS4, - OSCCLK, PEWAKE, PWM0, PWM1, PWM10G0, PWM10G1, PWM11G0, PWM11G1, PWM12G0, - PWM12G1, PWM13G0, PWM13G1, PWM14G0, PWM14G1, PWM15G0, PWM15G1, PWM2, - PWM3, PWM4, PWM5, PWM6, PWM7, PWM8G0, PWM8G1, PWM9G0, PWM9G1, QSPI1, - QSPI2, RGMII1, RGMII2, RGMII3, RGMII4, RMII1, RMII2, RMII3, RMII4, - RXD1, RXD2, RXD3, RXD4, SALT1, SALT10G0, SALT10G1, SALT11G0, SALT11G1, - SALT12G0, SALT12G1, SALT13G0, SALT13G1, SALT14G0, SALT14G1, SALT15G0, - SALT15G1, SALT16G0, SALT16G1, SALT2, SALT3, SALT4, SALT5, SALT6, - SALT7, SALT8, SALT9G0, SALT9G1, SD1, SD2, SD3, SGPM1, SGPM2, SGPS1, SGPS2, - SIOONCTRL, SIOPBI, SIOPBO, SIOPWREQ, SIOPWRGD, SIOS3, SIOS5, SIOSCI, SPI1, - SPI1ABR, SPI1CS1, SPI1WP, SPI2, SPI2CS1, SPI2CS2, TACH0, TACH1, TACH10, TACH11, - TACH12, TACH13, TACH14, TACH15, TACH2, TACH3, TACH4, TACH5, TACH6, - TACH7, TACH8, TACH9, THRU0, THRU1, THRU2, THRU3, TXD1, TXD2, TXD3, - TXD4, UART10, UART11, UART12G0, UART12G1, UART13G0, UART13G1, UART6, - UART7, UART8, UART9, USBA, USBB, VB, VGAHS, VGAVS, WDTRST1, WDTRST2, - WDTRST3, WDTRST4] + enum: + - ADC0 + - ADC1 + - ADC10 + - ADC11 + - ADC12 + - ADC13 + - ADC14 + - ADC15 + - ADC2 + - ADC3 + - ADC4 + - ADC5 + - ADC6 + - ADC7 + - ADC8 + - ADC9 + - BMCINT + - EMMCG1 + - EMMCG4 + - EMMCG8 + - ESPI + - ESPIALT + - FSI1 + - FSI2 + - FWQSPI + - FWSPIABR + - FWSPID + - FWSPIWP + - GPIT0 + - GPIT1 + - GPIT2 + - GPIT3 + - GPIT4 + - GPIT5 + - GPIT6 + - GPIT7 + - GPIU0 + - GPIU1 + - GPIU2 + - GPIU3 + - GPIU4 + - GPIU5 + - GPIU6 + - GPIU7 + - HVI3C3 + - HVI3C4 + - I2C1 + - I2C10 + - I2C11 + - I2C12 + - I2C13 + - I2C14 + - I2C15 + - I2C16 + - I2C2 + - I2C3 + - I2C4 + - I2C5 + - I2C6 + - I2C7 + - I2C8 + - I2C9 + - I3C1 + - I3C2 + - I3C3 + - I3C4 + - I3C5 + - I3C6 + - JTAGM + - LHPD + - LHSIRQ + - LPC + - LPCHC + - LPCPD + - LPCPME + - LPCSMI + - LSIRQ + - MACLINK1 + - MACLINK2 + - MACLINK3 + - MACLINK4 + - MDIO1 + - MDIO2 + - MDIO3 + - MDIO4 + - NCSI3 + - NCSI4 + - NCTS1 + - NCTS2 + - NCTS3 + - NCTS4 + - NDCD1 + - NDCD2 + - NDCD3 + - NDCD4 + - NDSR1 + - NDSR2 + - NDSR3 + - NDSR4 + - NDTR1 + - NDTR2 + - NDTR3 + - NDTR4 + - NRI1 + - NRI2 + - NRI3 + - NRI4 + - NRTS1 + - NRTS2 + - NRTS3 + - NRTS4 + - OSCCLK + - PEWAKE + - PWM0 + - PWM1 + - PWM10G0 + - PWM10G1 + - PWM11G0 + - PWM11G1 + - PWM12G0 + - PWM12G1 + - PWM13G0 + - PWM13G1 + - PWM14G0 + - PWM14G1 + - PWM15G0 + - PWM15G1 + - PWM2 + - PWM3 + - PWM4 + - PWM5 + - PWM6 + - PWM7 + - PWM8G0 + - PWM8G1 + - PWM9G0 + - PWM9G1 + - QSPI1 + - QSPI2 + - RGMII1 + - RGMII2 + - RGMII3 + - RGMII4 + - RMII1 + - RMII2 + - RMII3 + - RMII4 + - RXD1 + - RXD2 + - RXD3 + - RXD4 + - SALT1 + - SALT10G0 + - SALT10G1 + - SALT11G0 + - SALT11G1 + - SALT12G0 + - SALT12G1 + - SALT13G0 + - SALT13G1 + - SALT14G0 + - SALT14G1 + - SALT15G0 + - SALT15G1 + - SALT16G0 + - SALT16G1 + - SALT2 + - SALT3 + - SALT4 + - SALT5 + - SALT6 + - SALT7 + - SALT8 + - SALT9G0 + - SALT9G1 + - SD1 + - SD2 + - SD3 + - SGPM1 + - SGPM2 + - SGPS1 + - SGPS2 + - SIOONCTRL + - SIOPBI + - SIOPBO + - SIOPWREQ + - SIOPWRGD + - SIOS3 + - SIOS5 + - SIOSCI + - SPI1 + - SPI1ABR + - SPI1CS1 + - SPI1WP + - SPI2 + - SPI2CS1 + - SPI2CS2 + - TACH0 + - TACH1 + - TACH10 + - TACH11 + - TACH12 + - TACH13 + - TACH14 + - TACH15 + - TACH2 + - TACH3 + - TACH4 + - TACH5 + - TACH6 + - TACH7 + - TACH8 + - TACH9 + - THRU0 + - THRU1 + - THRU2 + - THRU3 + - TXD1 + - TXD2 + - TXD3 + - TXD4 + - UART10 + - UART11 + - UART12G0 + - UART12G1 + - UART13G0 + - UART13G1 + - UART6 + - UART7 + - UART8 + - UART9 + - USBA + - USBB + - VB + - VGAHS + - VGAVS + - WDTRST1 + - WDTRST2 + - WDTRST3 + - WDTRST4 pins: true bias-disable: true diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx93-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/fsl,imx9-pinctrl.yaml similarity index 93% rename from Documentation/devicetree/bindings/pinctrl/fsl,imx93-pinctrl.yaml rename to Documentation/devicetree/bindings/pinctrl/fsl,imx9-pinctrl.yaml index 2f2405102996..a438db8884f2 100644 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx93-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx9-pinctrl.yaml @@ -1,10 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- -$id: http://devicetree.org/schemas/pinctrl/fsl,imx93-pinctrl.yaml# +$id: http://devicetree.org/schemas/pinctrl/fsl,imx9-pinctrl.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Freescale IMX93 IOMUX Controller +title: Freescale IMX9 IOMUX Controller maintainers: - Peng Fan @@ -18,7 +18,9 @@ allOf: properties: compatible: - const: fsl,imx93-iomuxc + enum: + - fsl,imx91-iomuxc + - fsl,imx93-iomuxc reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/pinctrl/nuvoton,ma35d1-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/nuvoton,ma35d1-pinctrl.yaml new file mode 100644 index 000000000000..763a49bd07dc --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/nuvoton,ma35d1-pinctrl.yaml @@ -0,0 +1,178 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/nuvoton,ma35d1-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nuvoton MA35D1 pin control and GPIO + +maintainers: + - Shan-Chun Hung + - Jacky Huang + +allOf: + - $ref: pinctrl.yaml# + +properties: + compatible: + enum: + - nuvoton,ma35d1-pinctrl + + reg: + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 1 + + nuvoton,sys: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle of the system-management node. + + ranges: true + +patternProperties: + "^gpio@[0-9a-f]+$": + type: object + properties: + gpio-controller: true + + '#gpio-cells': + const: 2 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + interrupt-controller: true + + '#interrupt-cells': + const: 2 + + interrupts: + description: + The interrupt outputs to sysirq. + maxItems: 1 + + required: + - gpio-controller + - '#gpio-cells' + - reg + - clocks + - interrupt-controller + - '#interrupt-cells' + - interrupts + + additionalProperties: false + + "-grp$": + type: object + description: + Pinctrl node's client devices use subnodes for desired pin configuration. + Client device subnodes use below standard properties. + patternProperties: + "-pins$": + type: object + description: + A pinctrl node should contain at least one subnodes representing the + pinctrl groups available on the machine. Each subnode will list the + pins it needs, and how they should be configured, with regard to muxer + configuration, pullups, drive strength, input enable/disable and input + schmitt. + $ref: /schemas/pinctrl/pincfg-node.yaml + + properties: + nuvoton,pins: + description: + Each entry consists of 4 parameters and represents the mux and config + setting for one pin. + $ref: /schemas/types.yaml#/definitions/uint32-matrix + minItems: 1 + items: + items: + - minimum: 0 + maximum: 13 + description: + Pin bank. + - minimum: 0 + maximum: 15 + description: + Pin bank index. + - minimum: 0 + maximum: 15 + description: + Mux 0 means GPIO and mux 1 to 15 means the specific device function. + + power-source: + description: | + Valid arguments are described as below: + 0: power supply of 1.8V + 1: power supply of 3.3V + enum: [0, 1] + + drive-strength-microamp: + oneOf: + - enum: [ 2900, 4400, 5800, 7300, 8600, 10100, 11500, 13000 ] + description: 1.8V I/O driving strength + - enum: [ 17100, 25600, 34100, 42800, 48000, 56000, 77000, 82000 ] + description: 3.3V I/O driving strength + + bias-disable: true + + bias-pull-up: true + + bias-pull-down: true + + input-schmitt-disable: true + + additionalProperties: false + + additionalProperties: false + +required: + - compatible + - reg + - nuvoton,sys + +additionalProperties: false + +examples: + - | + #include + #include + #include + + pinctrl@40040000 { + compatible = "nuvoton,ma35d1-pinctrl"; + reg = <0x40040000 0xc00>; + #address-cells = <1>; + #size-cells = <1>; + nuvoton,sys = <&sys>; + ranges = <0x0 0x40040000 0x400>; + + gpio@0 { + reg = <0x0 0x40>; + interrupts = ; + clocks = <&clk GPA_GATE>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + uart-grp { + uart11-pins { + nuvoton,pins = <11 0 2>, + <11 1 2>, + <11 2 2>, + <11 3 2>; + power-source = <1>; + bias-disable; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/nuvoton,npcm845-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/nuvoton,npcm845-pinctrl.yaml index b55d9c316659..814b9598edd1 100644 --- a/Documentation/devicetree/bindings/pinctrl/nuvoton,npcm845-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/nuvoton,npcm845-pinctrl.yaml @@ -85,11 +85,12 @@ patternProperties: 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 ] + scipme, smi, smb6, smb6b, smb6c, smb6d, smb7, smb7b, smb7c, + smb7d, 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, bu4, + bu4b, bu5, bu5b, bu6, gpo187 ] function: description: @@ -109,11 +110,12 @@ patternProperties: 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 ] + scipme, smi, smb6, smb6b, smb6c, smb6d, smb7, smb7b, smb7c, + smb7d, 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, bu4, + bu4b, bu5, bu5b, bu6, gpo187 ] dependencies: groups: [ function ] diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml index c11495524dd2..e02595316c9f 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml @@ -75,11 +75,11 @@ properties: description: Optional list of pin base, nr pins & gpio function $ref: /schemas/types.yaml#/definitions/phandle-array items: - - items: - - description: phandle of a gpio-range node - - description: pin base - - description: number of pins - - description: gpio function + items: + - description: phandle of a gpio-range node + - description: pin base + - description: number of pins + - description: gpio function '#gpio-range-cells': description: No longer needed, may exist in older files for gpio-ranges @@ -144,6 +144,13 @@ patternProperties: - description: drive strength mask pinctrl-single,input-schmitt: + description: Optional schmitt strength configuration + $ref: /schemas/types.yaml#/definitions/uint32-array + items: + - description: schmitt strength current + - description: schmitt strength mask + + pinctrl-single,input-schmitt-enable: description: Optional input schmitt configuration $ref: /schemas/types.yaml#/definitions/uint32-array items: diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml index 0bf2d9f093b5..2784d32fdde2 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml @@ -56,6 +56,7 @@ properties: - qcom,pma8084-gpio - qcom,pmc8180-gpio - qcom,pmc8180c-gpio + - qcom,pmc8380-gpio - qcom,pmd8028-gpio - qcom,pmi632-gpio - qcom,pmi8950-gpio @@ -223,6 +224,7 @@ allOf: - qcom,pm8150-gpio - qcom,pm8350-gpio - qcom,pmc8180-gpio + - qcom,pmc8380-gpio - qcom,pmi8994-gpio - qcom,pmm8155au-gpio then: diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm4250-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm4250-lpass-lpi-pinctrl.yaml new file mode 100644 index 000000000000..9612e21183fa --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm4250-lpass-lpi-pinctrl.yaml @@ -0,0 +1,118 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/qcom,sm4250-lpass-lpi-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM4250 SoC LPASS LPI TLMM + +maintainers: + - Srinivas Kandagatla + +description: + Top Level Mode Multiplexer pin controller in the Low Power Audio SubSystem + (LPASS) Low Power Island (LPI) of Qualcomm SM4250 SoC. + +properties: + compatible: + const: qcom,sm4250-lpass-lpi-pinctrl + + reg: + items: + - description: LPASS LPI TLMM Control and Status registers + - description: LPASS LPI MCC registers + + clocks: + items: + - description: LPASS Audio voting clock + + clock-names: + items: + - const: audio + +patternProperties: + "-state$": + oneOf: + - $ref: "#/$defs/qcom-sm4250-lpass-state" + - patternProperties: + "-pins$": + $ref: "#/$defs/qcom-sm4250-lpass-state" + additionalProperties: false + +$defs: + qcom-sm4250-lpass-state: + type: object + description: + Pinctrl node's client devices use subnodes for desired pin configuration. + Client device subnodes use below standard properties. + $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state + unevaluatedProperties: false + + properties: + pins: + description: + List of gpio pins affected by the properties specified in this + subnode. + items: + pattern: "^gpio([0-9]|1[0-9]|2[0-6])$" + + function: + enum: [ gpio, dmic01_clk, dmic01_data, dmic23_clk, dmic23_data, + dmic4_clk, dmic4_data, ext_mclk0_a, ext_mclk0_b, ext_mclk1_a, + ext_mclk1_b, ext_mclk1_c, i2s1_clk, i2s1_data, i2s1_ws, + i2s2_clk, i2s2_data, i2s2_ws, i2s3_clk, i2s3_data, i2s3_ws, + qua_mi2s_data, qua_mi2s_sclk, qua_mi2s_ws, slim_clk, slim_data, + swr_rx_clk, swr_rx_data, swr_tx_clk, swr_tx_data, swr_wsa_clk, + swr_wsa_data ] + description: + Specify the alternative function to be configured for the specified + pins. + +allOf: + - $ref: qcom,lpass-lpi-common.yaml# + +required: + - compatible + - reg + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + #include + lpi_tlmm: pinctrl@a7c0000 { + compatible = "qcom,sm4250-lpass-lpi-pinctrl"; + reg = <0xa7c0000 0x20000>, + <0xa950000 0x10000>; + clocks = <&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>; + clock-names = "audio"; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&lpi_tlmm 0 0 19>; + + i2s2-active-state { + clk-pins { + pins = "gpio10"; + function = "i2s2_clk"; + drive-strength = <2>; + slew-rate = <1>; + bias-disable; + }; + + data-pins { + pins = "gpio12"; + function = "i2s2_data"; + drive-strength = <2>; + slew-rate = <1>; + }; + }; + + i2s2-sleep-clk-state { + pins = "gpio10"; + function = "i2s2_clk"; + drive-strength = <2>; + bias-pull-down; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml index 4d5a957fa232..56d90c8e1fa3 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml @@ -26,6 +26,7 @@ properties: - renesas,r9a07g043-pinctrl # RZ/G2UL{Type-1,Type-2} and RZ/Five - renesas,r9a07g044-pinctrl # RZ/G2{L,LC} - renesas,r9a08g045-pinctrl # RZ/G3S + - renesas,r9a09g057-pinctrl # RZ/V2H(P) - items: - enum: @@ -66,10 +67,14 @@ properties: maxItems: 1 resets: - items: - - description: GPIO_RSTN signal - - description: GPIO_PORT_RESETN signal - - description: GPIO_SPARE_RESETN signal + oneOf: + - items: + - description: GPIO_RSTN signal + - description: GPIO_PORT_RESETN signal + - description: GPIO_SPARE_RESETN signal + - items: + - description: PFC main reset + - description: Reset for the control register related to WDTUDFCA and WDTUDFFCM pins additionalProperties: anyOf: @@ -79,21 +84,6 @@ additionalProperties: - $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. @@ -126,6 +116,16 @@ additionalProperties: output-high: true output-low: true line-name: true + bias-disable: true + bias-pull-down: true + bias-pull-up: true + renesas,output-impedance: + description: + Output impedance for pins on the RZ/V2H(P) SoC. The value provided by this + property corresponds to register bit values that can be set in the PFC_IOLH_mn + register, which adjusts the drive strength value and is pin-dependent. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3] - type: object additionalProperties: @@ -134,6 +134,20 @@ additionalProperties: allOf: - $ref: pinctrl.yaml# + - if: + properties: + compatible: + contains: + const: renesas,r9a09g057-pinctrl + then: + properties: + resets: + maxItems: 2 + else: + properties: + resets: + minItems: 3 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/pinctrl/xlnx,zynqmp-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/xlnx,zynqmp-pinctrl.yaml index f13d315b5d5e..ce66fd15ff9c 100644 --- a/Documentation/devicetree/bindings/pinctrl/xlnx,zynqmp-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/xlnx,zynqmp-pinctrl.yaml @@ -42,179 +42,187 @@ patternProperties: $ref: pinmux-node.yaml# properties: + pins: + description: + List of pins to select (either this or "groups" must be specified) + items: + pattern: '^MIO([0-9]|[1-6][0-9]|7[0-7])$' + groups: description: List of groups to select (either this or "pins" must be specified), available groups for this subnode. items: - enum: [ethernet0_0_grp, ethernet1_0_grp, ethernet2_0_grp, - ethernet3_0_grp, gemtsu0_0_grp, gemtsu0_1_grp, - gemtsu0_2_grp, mdio0_0_grp, mdio1_0_grp, - mdio1_1_grp, mdio2_0_grp, mdio3_0_grp, - qspi0_0_grp, qspi_ss_0_grp, qspi_fbclk_0_grp, - spi0_0_grp, spi0_ss_0_grp, spi0_ss_1_grp, - spi0_ss_2_grp, spi0_1_grp, spi0_ss_3_grp, - spi0_ss_4_grp, spi0_ss_5_grp, spi0_2_grp, - spi0_ss_6_grp, spi0_ss_7_grp, spi0_ss_8_grp, - spi0_3_grp, spi0_ss_9_grp, spi0_ss_10_grp, - spi0_ss_11_grp, spi0_4_grp, spi0_ss_12_grp, - spi0_ss_13_grp, spi0_ss_14_grp, spi0_5_grp, - spi0_ss_15_grp, spi0_ss_16_grp, spi0_ss_17_grp, - spi1_0_grp, spi1_ss_0_grp, spi1_ss_1_grp, - spi1_ss_2_grp, spi1_1_grp, spi1_ss_3_grp, - spi1_ss_4_grp, spi1_ss_5_grp, spi1_2_grp, - spi1_ss_6_grp, spi1_ss_7_grp, spi1_ss_8_grp, - spi1_3_grp, spi1_ss_9_grp, spi1_ss_10_grp, - spi1_ss_11_grp, spi1_4_grp, spi1_ss_12_grp, - spi1_ss_13_grp, spi1_ss_14_grp, spi1_5_grp, - spi1_ss_15_grp, spi1_ss_16_grp, spi1_ss_17_grp, - sdio0_0_grp, sdio0_1_grp, sdio0_2_grp, - sdio0_3_grp, sdio0_4_grp, sdio0_5_grp, - sdio0_6_grp, sdio0_7_grp, sdio0_8_grp, - sdio0_9_grp, sdio0_10_grp, sdio0_11_grp, - sdio0_12_grp, sdio0_13_grp, sdio0_14_grp, - sdio0_15_grp, sdio0_16_grp, sdio0_17_grp, - sdio0_18_grp, sdio0_19_grp, sdio0_20_grp, - sdio0_21_grp, sdio0_22_grp, sdio0_23_grp, - sdio0_24_grp, sdio0_25_grp, sdio0_26_grp, - sdio0_27_grp, sdio0_28_grp, sdio0_29_grp, - sdio0_30_grp, sdio0_31_grp, sdio0_32_grp, - sdio0_pc_0_grp, sdio0_cd_0_grp, sdio0_wp_0_grp, - sdio0_pc_1_grp, sdio0_cd_1_grp, sdio0_wp_1_grp, - sdio0_pc_2_grp, sdio0_cd_2_grp, sdio0_wp_2_grp, - sdio1_0_grp, sdio1_1_grp, sdio1_2_grp, - sdio1_3_grp, sdio1_4_grp, sdio1_5_grp, - sdio1_6_grp, sdio1_7_grp, sdio1_8_grp, - sdio1_9_grp, sdio1_10_grp, sdio1_11_grp, - sdio1_12_grp, sdio1_13_grp, sdio1_14_grp, - sdio1_15_grp, sdio1_pc_0_grp, sdio1_cd_0_grp, - sdio1_wp_0_grp, sdio1_pc_1_grp, sdio1_cd_1_grp, - sdio1_wp_1_grp, nand0_0_grp, nand0_ce_0_grp, - nand0_rb_0_grp, nand0_dqs_0_grp, nand0_ce_1_grp, - nand0_rb_1_grp, nand0_dqs_1_grp, can0_0_grp, - can0_1_grp, can0_2_grp, can0_3_grp, - can0_4_grp, can0_5_grp, can0_6_grp, - can0_7_grp, can0_8_grp, can0_9_grp, - can0_10_grp, can0_11_grp, can0_12_grp, - can0_13_grp, can0_14_grp, can0_15_grp, - can0_16_grp, can0_17_grp, can0_18_grp, - can1_0_grp, can1_1_grp, can1_2_grp, - can1_3_grp, can1_4_grp, can1_5_grp, - can1_6_grp, can1_7_grp, can1_8_grp, - can1_9_grp, can1_10_grp, can1_11_grp, - can1_12_grp, can1_13_grp, can1_14_grp, - can1_15_grp, can1_16_grp, can1_17_grp, - can1_18_grp, can1_19_grp, uart0_0_grp, - uart0_1_grp, uart0_2_grp, uart0_3_grp, - uart0_4_grp, uart0_5_grp, uart0_6_grp, - uart0_7_grp, uart0_8_grp, uart0_9_grp, - uart0_10_grp, uart0_11_grp, uart0_12_grp, - uart0_13_grp, uart0_14_grp, uart0_15_grp, - uart0_16_grp, uart0_17_grp, uart0_18_grp, - uart1_0_grp, uart1_1_grp, uart1_2_grp, - uart1_3_grp, uart1_4_grp, uart1_5_grp, - uart1_6_grp, uart1_7_grp, uart1_8_grp, - uart1_9_grp, uart1_10_grp, uart1_11_grp, - uart1_12_grp, uart1_13_grp, uart1_14_grp, - uart1_15_grp, uart1_16_grp, uart1_17_grp, - uart1_18_grp, i2c0_0_grp, i2c0_1_grp, - i2c0_2_grp, i2c0_3_grp, i2c0_4_grp, - i2c0_5_grp, i2c0_6_grp, i2c0_7_grp, - i2c0_8_grp, i2c0_9_grp, i2c0_10_grp, - i2c0_11_grp, i2c0_12_grp, i2c0_13_grp, - i2c0_14_grp, i2c0_15_grp, i2c0_16_grp, - i2c0_17_grp, i2c0_18_grp, i2c1_0_grp, - i2c1_1_grp, i2c1_2_grp, i2c1_3_grp, - i2c1_4_grp, i2c1_5_grp, i2c1_6_grp, - i2c1_7_grp, i2c1_8_grp, i2c1_9_grp, - i2c1_10_grp, i2c1_11_grp, i2c1_12_grp, - i2c1_13_grp, i2c1_14_grp, i2c1_15_grp, - i2c1_16_grp, i2c1_17_grp, i2c1_18_grp, - i2c1_19_grp, ttc0_clk_0_grp, ttc0_wav_0_grp, - ttc0_clk_1_grp, ttc0_wav_1_grp, ttc0_clk_2_grp, - ttc0_wav_2_grp, ttc0_clk_3_grp, ttc0_wav_3_grp, - ttc0_clk_4_grp, ttc0_wav_4_grp, ttc0_clk_5_grp, - ttc0_wav_5_grp, ttc0_clk_6_grp, ttc0_wav_6_grp, - ttc0_clk_7_grp, ttc0_wav_7_grp, ttc0_clk_8_grp, - ttc0_wav_8_grp, ttc1_clk_0_grp, ttc1_wav_0_grp, - ttc1_clk_1_grp, ttc1_wav_1_grp, ttc1_clk_2_grp, - ttc1_wav_2_grp, ttc1_clk_3_grp, ttc1_wav_3_grp, - ttc1_clk_4_grp, ttc1_wav_4_grp, ttc1_clk_5_grp, - ttc1_wav_5_grp, ttc1_clk_6_grp, ttc1_wav_6_grp, - ttc1_clk_7_grp, ttc1_wav_7_grp, ttc1_clk_8_grp, - ttc1_wav_8_grp, ttc2_clk_0_grp, ttc2_wav_0_grp, - ttc2_clk_1_grp, ttc2_wav_1_grp, ttc2_clk_2_grp, - ttc2_wav_2_grp, ttc2_clk_3_grp, ttc2_wav_3_grp, - ttc2_clk_4_grp, ttc2_wav_4_grp, ttc2_clk_5_grp, - ttc2_wav_5_grp, ttc2_clk_6_grp, ttc2_wav_6_grp, - ttc2_clk_7_grp, ttc2_wav_7_grp, ttc2_clk_8_grp, - ttc2_wav_8_grp, ttc3_clk_0_grp, ttc3_wav_0_grp, - ttc3_clk_1_grp, ttc3_wav_1_grp, ttc3_clk_2_grp, - ttc3_wav_2_grp, ttc3_clk_3_grp, ttc3_wav_3_grp, - ttc3_clk_4_grp, ttc3_wav_4_grp, ttc3_clk_5_grp, - ttc3_wav_5_grp, ttc3_clk_6_grp, ttc3_wav_6_grp, - ttc3_clk_7_grp, ttc3_wav_7_grp, ttc3_clk_8_grp, - ttc3_wav_8_grp, swdt0_clk_0_grp, swdt0_rst_0_grp, - swdt0_clk_1_grp, swdt0_rst_1_grp, swdt0_clk_2_grp, - swdt0_rst_2_grp, swdt0_clk_3_grp, swdt0_rst_3_grp, - swdt0_clk_4_grp, swdt0_rst_4_grp, swdt0_clk_5_grp, - swdt0_rst_5_grp, swdt0_clk_6_grp, swdt0_rst_6_grp, - swdt0_clk_7_grp, swdt0_rst_7_grp, swdt0_clk_8_grp, - swdt0_rst_8_grp, swdt0_clk_9_grp, swdt0_rst_9_grp, - swdt0_clk_10_grp, swdt0_rst_10_grp, swdt0_clk_11_grp, - swdt0_rst_11_grp, swdt0_clk_12_grp, swdt0_rst_12_grp, - swdt1_clk_0_grp, swdt1_rst_0_grp, swdt1_clk_1_grp, - swdt1_rst_1_grp, swdt1_clk_2_grp, swdt1_rst_2_grp, - swdt1_clk_3_grp, swdt1_rst_3_grp, swdt1_clk_4_grp, - swdt1_rst_4_grp, swdt1_clk_5_grp, swdt1_rst_5_grp, - swdt1_clk_6_grp, swdt1_rst_6_grp, swdt1_clk_7_grp, - swdt1_rst_7_grp, swdt1_clk_8_grp, swdt1_rst_8_grp, - swdt1_clk_9_grp, swdt1_rst_9_grp, swdt1_clk_10_grp, - swdt1_rst_10_grp, swdt1_clk_11_grp, swdt1_rst_11_grp, - swdt1_clk_12_grp, swdt1_rst_12_grp, gpio0_0_grp, - gpio0_1_grp, gpio0_2_grp, gpio0_3_grp, - gpio0_4_grp, gpio0_5_grp, gpio0_6_grp, - gpio0_7_grp, gpio0_8_grp, gpio0_9_grp, - gpio0_10_grp, gpio0_11_grp, gpio0_12_grp, - gpio0_13_grp, gpio0_14_grp, gpio0_15_grp, - gpio0_16_grp, gpio0_17_grp, gpio0_18_grp, - gpio0_19_grp, gpio0_20_grp, gpio0_21_grp, - gpio0_22_grp, gpio0_23_grp, gpio0_24_grp, - gpio0_25_grp, gpio0_26_grp, gpio0_27_grp, - gpio0_28_grp, gpio0_29_grp, gpio0_30_grp, - gpio0_31_grp, gpio0_32_grp, gpio0_33_grp, - gpio0_34_grp, gpio0_35_grp, gpio0_36_grp, - gpio0_37_grp, gpio0_38_grp, gpio0_39_grp, - gpio0_40_grp, gpio0_41_grp, gpio0_42_grp, - gpio0_43_grp, gpio0_44_grp, gpio0_45_grp, - gpio0_46_grp, gpio0_47_grp, gpio0_48_grp, - gpio0_49_grp, gpio0_50_grp, gpio0_51_grp, - gpio0_52_grp, gpio0_53_grp, gpio0_54_grp, - gpio0_55_grp, gpio0_56_grp, gpio0_57_grp, - gpio0_58_grp, gpio0_59_grp, gpio0_60_grp, - gpio0_61_grp, gpio0_62_grp, gpio0_63_grp, - gpio0_64_grp, gpio0_65_grp, gpio0_66_grp, - gpio0_67_grp, gpio0_68_grp, gpio0_69_grp, - gpio0_70_grp, gpio0_71_grp, gpio0_72_grp, - gpio0_73_grp, gpio0_74_grp, gpio0_75_grp, - gpio0_76_grp, gpio0_77_grp, usb0_0_grp, - usb1_0_grp, pmu0_0_grp, pmu0_1_grp, - pmu0_2_grp, pmu0_3_grp, pmu0_4_grp, - pmu0_5_grp, pmu0_6_grp, pmu0_7_grp, - pmu0_8_grp, pmu0_9_grp, pmu0_10_grp, - pmu0_11_grp, pcie0_0_grp, pcie0_1_grp, - pcie0_2_grp, pcie0_3_grp, pcie0_4_grp, - pcie0_5_grp, pcie0_6_grp, pcie0_7_grp, - csu0_0_grp, csu0_1_grp, csu0_2_grp, - csu0_3_grp, csu0_4_grp, csu0_5_grp, - csu0_6_grp, csu0_7_grp, csu0_8_grp, - csu0_9_grp, csu0_10_grp, csu0_11_grp, - dpaux0_0_grp, dpaux0_1_grp, dpaux0_2_grp, - dpaux0_3_grp, pjtag0_0_grp, pjtag0_1_grp, - pjtag0_2_grp, pjtag0_3_grp, pjtag0_4_grp, - pjtag0_5_grp, trace0_0_grp, trace0_clk_0_grp, - trace0_1_grp, trace0_clk_1_grp, trace0_2_grp, - trace0_clk_2_grp, testscan0_0_grp] + anyOf: + - pattern: '^MIO([0-9]|[1-6][0-9]|7[0-7])$' + - enum: [ethernet0_0_grp, ethernet1_0_grp, ethernet2_0_grp, + ethernet3_0_grp, gemtsu0_0_grp, gemtsu0_1_grp, + gemtsu0_2_grp, mdio0_0_grp, mdio1_0_grp, + mdio1_1_grp, mdio2_0_grp, mdio3_0_grp, + qspi0_0_grp, qspi_ss_0_grp, qspi_fbclk_0_grp, + spi0_0_grp, spi0_ss_0_grp, spi0_ss_1_grp, + spi0_ss_2_grp, spi0_1_grp, spi0_ss_3_grp, + spi0_ss_4_grp, spi0_ss_5_grp, spi0_2_grp, + spi0_ss_6_grp, spi0_ss_7_grp, spi0_ss_8_grp, + spi0_3_grp, spi0_ss_9_grp, spi0_ss_10_grp, + spi0_ss_11_grp, spi0_4_grp, spi0_ss_12_grp, + spi0_ss_13_grp, spi0_ss_14_grp, spi0_5_grp, + spi0_ss_15_grp, spi0_ss_16_grp, spi0_ss_17_grp, + spi1_0_grp, spi1_ss_0_grp, spi1_ss_1_grp, + spi1_ss_2_grp, spi1_1_grp, spi1_ss_3_grp, + spi1_ss_4_grp, spi1_ss_5_grp, spi1_2_grp, + spi1_ss_6_grp, spi1_ss_7_grp, spi1_ss_8_grp, + spi1_3_grp, spi1_ss_9_grp, spi1_ss_10_grp, + spi1_ss_11_grp, spi1_4_grp, spi1_ss_12_grp, + spi1_ss_13_grp, spi1_ss_14_grp, spi1_5_grp, + spi1_ss_15_grp, spi1_ss_16_grp, spi1_ss_17_grp, + sdio0_0_grp, sdio0_1_grp, sdio0_2_grp, + sdio0_3_grp, sdio0_4_grp, sdio0_5_grp, + sdio0_6_grp, sdio0_7_grp, sdio0_8_grp, + sdio0_9_grp, sdio0_10_grp, sdio0_11_grp, + sdio0_12_grp, sdio0_13_grp, sdio0_14_grp, + sdio0_15_grp, sdio0_16_grp, sdio0_17_grp, + sdio0_18_grp, sdio0_19_grp, sdio0_20_grp, + sdio0_21_grp, sdio0_22_grp, sdio0_23_grp, + sdio0_24_grp, sdio0_25_grp, sdio0_26_grp, + sdio0_27_grp, sdio0_28_grp, sdio0_29_grp, + sdio0_30_grp, sdio0_31_grp, sdio0_32_grp, + sdio0_pc_0_grp, sdio0_cd_0_grp, sdio0_wp_0_grp, + sdio0_pc_1_grp, sdio0_cd_1_grp, sdio0_wp_1_grp, + sdio0_pc_2_grp, sdio0_cd_2_grp, sdio0_wp_2_grp, + sdio1_0_grp, sdio1_1_grp, sdio1_2_grp, + sdio1_3_grp, sdio1_4_grp, sdio1_5_grp, + sdio1_6_grp, sdio1_7_grp, sdio1_8_grp, + sdio1_9_grp, sdio1_10_grp, sdio1_11_grp, + sdio1_12_grp, sdio1_13_grp, sdio1_14_grp, + sdio1_15_grp, sdio1_pc_0_grp, sdio1_cd_0_grp, + sdio1_wp_0_grp, sdio1_pc_1_grp, sdio1_cd_1_grp, + sdio1_wp_1_grp, nand0_0_grp, nand0_ce_0_grp, + nand0_rb_0_grp, nand0_dqs_0_grp, nand0_ce_1_grp, + nand0_rb_1_grp, nand0_dqs_1_grp, can0_0_grp, + can0_1_grp, can0_2_grp, can0_3_grp, + can0_4_grp, can0_5_grp, can0_6_grp, + can0_7_grp, can0_8_grp, can0_9_grp, + can0_10_grp, can0_11_grp, can0_12_grp, + can0_13_grp, can0_14_grp, can0_15_grp, + can0_16_grp, can0_17_grp, can0_18_grp, + can1_0_grp, can1_1_grp, can1_2_grp, + can1_3_grp, can1_4_grp, can1_5_grp, + can1_6_grp, can1_7_grp, can1_8_grp, + can1_9_grp, can1_10_grp, can1_11_grp, + can1_12_grp, can1_13_grp, can1_14_grp, + can1_15_grp, can1_16_grp, can1_17_grp, + can1_18_grp, can1_19_grp, uart0_0_grp, + uart0_1_grp, uart0_2_grp, uart0_3_grp, + uart0_4_grp, uart0_5_grp, uart0_6_grp, + uart0_7_grp, uart0_8_grp, uart0_9_grp, + uart0_10_grp, uart0_11_grp, uart0_12_grp, + uart0_13_grp, uart0_14_grp, uart0_15_grp, + uart0_16_grp, uart0_17_grp, uart0_18_grp, + uart1_0_grp, uart1_1_grp, uart1_2_grp, + uart1_3_grp, uart1_4_grp, uart1_5_grp, + uart1_6_grp, uart1_7_grp, uart1_8_grp, + uart1_9_grp, uart1_10_grp, uart1_11_grp, + uart1_12_grp, uart1_13_grp, uart1_14_grp, + uart1_15_grp, uart1_16_grp, uart1_17_grp, + uart1_18_grp, i2c0_0_grp, i2c0_1_grp, + i2c0_2_grp, i2c0_3_grp, i2c0_4_grp, + i2c0_5_grp, i2c0_6_grp, i2c0_7_grp, + i2c0_8_grp, i2c0_9_grp, i2c0_10_grp, + i2c0_11_grp, i2c0_12_grp, i2c0_13_grp, + i2c0_14_grp, i2c0_15_grp, i2c0_16_grp, + i2c0_17_grp, i2c0_18_grp, i2c1_0_grp, + i2c1_1_grp, i2c1_2_grp, i2c1_3_grp, + i2c1_4_grp, i2c1_5_grp, i2c1_6_grp, + i2c1_7_grp, i2c1_8_grp, i2c1_9_grp, + i2c1_10_grp, i2c1_11_grp, i2c1_12_grp, + i2c1_13_grp, i2c1_14_grp, i2c1_15_grp, + i2c1_16_grp, i2c1_17_grp, i2c1_18_grp, + i2c1_19_grp, ttc0_clk_0_grp, ttc0_wav_0_grp, + ttc0_clk_1_grp, ttc0_wav_1_grp, ttc0_clk_2_grp, + ttc0_wav_2_grp, ttc0_clk_3_grp, ttc0_wav_3_grp, + ttc0_clk_4_grp, ttc0_wav_4_grp, ttc0_clk_5_grp, + ttc0_wav_5_grp, ttc0_clk_6_grp, ttc0_wav_6_grp, + ttc0_clk_7_grp, ttc0_wav_7_grp, ttc0_clk_8_grp, + ttc0_wav_8_grp, ttc1_clk_0_grp, ttc1_wav_0_grp, + ttc1_clk_1_grp, ttc1_wav_1_grp, ttc1_clk_2_grp, + ttc1_wav_2_grp, ttc1_clk_3_grp, ttc1_wav_3_grp, + ttc1_clk_4_grp, ttc1_wav_4_grp, ttc1_clk_5_grp, + ttc1_wav_5_grp, ttc1_clk_6_grp, ttc1_wav_6_grp, + ttc1_clk_7_grp, ttc1_wav_7_grp, ttc1_clk_8_grp, + ttc1_wav_8_grp, ttc2_clk_0_grp, ttc2_wav_0_grp, + ttc2_clk_1_grp, ttc2_wav_1_grp, ttc2_clk_2_grp, + ttc2_wav_2_grp, ttc2_clk_3_grp, ttc2_wav_3_grp, + ttc2_clk_4_grp, ttc2_wav_4_grp, ttc2_clk_5_grp, + ttc2_wav_5_grp, ttc2_clk_6_grp, ttc2_wav_6_grp, + ttc2_clk_7_grp, ttc2_wav_7_grp, ttc2_clk_8_grp, + ttc2_wav_8_grp, ttc3_clk_0_grp, ttc3_wav_0_grp, + ttc3_clk_1_grp, ttc3_wav_1_grp, ttc3_clk_2_grp, + ttc3_wav_2_grp, ttc3_clk_3_grp, ttc3_wav_3_grp, + ttc3_clk_4_grp, ttc3_wav_4_grp, ttc3_clk_5_grp, + ttc3_wav_5_grp, ttc3_clk_6_grp, ttc3_wav_6_grp, + ttc3_clk_7_grp, ttc3_wav_7_grp, ttc3_clk_8_grp, + ttc3_wav_8_grp, swdt0_clk_0_grp, swdt0_rst_0_grp, + swdt0_clk_1_grp, swdt0_rst_1_grp, swdt0_clk_2_grp, + swdt0_rst_2_grp, swdt0_clk_3_grp, swdt0_rst_3_grp, + swdt0_clk_4_grp, swdt0_rst_4_grp, swdt0_clk_5_grp, + swdt0_rst_5_grp, swdt0_clk_6_grp, swdt0_rst_6_grp, + swdt0_clk_7_grp, swdt0_rst_7_grp, swdt0_clk_8_grp, + swdt0_rst_8_grp, swdt0_clk_9_grp, swdt0_rst_9_grp, + swdt0_clk_10_grp, swdt0_rst_10_grp, swdt0_clk_11_grp, + swdt0_rst_11_grp, swdt0_clk_12_grp, swdt0_rst_12_grp, + swdt1_clk_0_grp, swdt1_rst_0_grp, swdt1_clk_1_grp, + swdt1_rst_1_grp, swdt1_clk_2_grp, swdt1_rst_2_grp, + swdt1_clk_3_grp, swdt1_rst_3_grp, swdt1_clk_4_grp, + swdt1_rst_4_grp, swdt1_clk_5_grp, swdt1_rst_5_grp, + swdt1_clk_6_grp, swdt1_rst_6_grp, swdt1_clk_7_grp, + swdt1_rst_7_grp, swdt1_clk_8_grp, swdt1_rst_8_grp, + swdt1_clk_9_grp, swdt1_rst_9_grp, swdt1_clk_10_grp, + swdt1_rst_10_grp, swdt1_clk_11_grp, swdt1_rst_11_grp, + swdt1_clk_12_grp, swdt1_rst_12_grp, gpio0_0_grp, + gpio0_1_grp, gpio0_2_grp, gpio0_3_grp, + gpio0_4_grp, gpio0_5_grp, gpio0_6_grp, + gpio0_7_grp, gpio0_8_grp, gpio0_9_grp, + gpio0_10_grp, gpio0_11_grp, gpio0_12_grp, + gpio0_13_grp, gpio0_14_grp, gpio0_15_grp, + gpio0_16_grp, gpio0_17_grp, gpio0_18_grp, + gpio0_19_grp, gpio0_20_grp, gpio0_21_grp, + gpio0_22_grp, gpio0_23_grp, gpio0_24_grp, + gpio0_25_grp, gpio0_26_grp, gpio0_27_grp, + gpio0_28_grp, gpio0_29_grp, gpio0_30_grp, + gpio0_31_grp, gpio0_32_grp, gpio0_33_grp, + gpio0_34_grp, gpio0_35_grp, gpio0_36_grp, + gpio0_37_grp, gpio0_38_grp, gpio0_39_grp, + gpio0_40_grp, gpio0_41_grp, gpio0_42_grp, + gpio0_43_grp, gpio0_44_grp, gpio0_45_grp, + gpio0_46_grp, gpio0_47_grp, gpio0_48_grp, + gpio0_49_grp, gpio0_50_grp, gpio0_51_grp, + gpio0_52_grp, gpio0_53_grp, gpio0_54_grp, + gpio0_55_grp, gpio0_56_grp, gpio0_57_grp, + gpio0_58_grp, gpio0_59_grp, gpio0_60_grp, + gpio0_61_grp, gpio0_62_grp, gpio0_63_grp, + gpio0_64_grp, gpio0_65_grp, gpio0_66_grp, + gpio0_67_grp, gpio0_68_grp, gpio0_69_grp, + gpio0_70_grp, gpio0_71_grp, gpio0_72_grp, + gpio0_73_grp, gpio0_74_grp, gpio0_75_grp, + gpio0_76_grp, gpio0_77_grp, usb0_0_grp, + usb1_0_grp, pmu0_0_grp, pmu0_1_grp, + pmu0_2_grp, pmu0_3_grp, pmu0_4_grp, + pmu0_5_grp, pmu0_6_grp, pmu0_7_grp, + pmu0_8_grp, pmu0_9_grp, pmu0_10_grp, + pmu0_11_grp, pcie0_0_grp, pcie0_1_grp, + pcie0_2_grp, pcie0_3_grp, pcie0_4_grp, + pcie0_5_grp, pcie0_6_grp, pcie0_7_grp, + csu0_0_grp, csu0_1_grp, csu0_2_grp, + csu0_3_grp, csu0_4_grp, csu0_5_grp, + csu0_6_grp, csu0_7_grp, csu0_8_grp, + csu0_9_grp, csu0_10_grp, csu0_11_grp, + dpaux0_0_grp, dpaux0_1_grp, dpaux0_2_grp, + dpaux0_3_grp, pjtag0_0_grp, pjtag0_1_grp, + pjtag0_2_grp, pjtag0_3_grp, pjtag0_4_grp, + pjtag0_5_grp, trace0_0_grp, trace0_clk_0_grp, + trace0_1_grp, trace0_clk_1_grp, trace0_2_grp, + trace0_clk_2_grp, testscan0_0_grp] maxItems: 78 function: @@ -230,9 +238,12 @@ patternProperties: pcie0, csu0, dpaux0, pjtag0, trace0, trace0_clk, testscan0] required: - - groups - function + oneOf: + - required: [ groups ] + - required: [ pins ] + additionalProperties: false '^conf': diff --git a/Documentation/devicetree/bindings/reset/nuvoton,ma35d1-reset.yaml b/Documentation/devicetree/bindings/reset/nuvoton,ma35d1-reset.yaml index 34c5c1c08ec1..3ce7dcecd87a 100644 --- a/Documentation/devicetree/bindings/reset/nuvoton,ma35d1-reset.yaml +++ b/Documentation/devicetree/bindings/reset/nuvoton,ma35d1-reset.yaml @@ -18,6 +18,7 @@ properties: compatible: items: - const: nuvoton,ma35d1-reset + - const: syscon reg: maxItems: 1 @@ -37,7 +38,7 @@ examples: - | system-management@40460000 { - compatible = "nuvoton,ma35d1-reset"; + compatible = "nuvoton,ma35d1-reset", "syscon"; reg = <0x40460000 0x200>; #reset-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml index d067f2a468ee..8edc8261241a 100644 --- a/Documentation/devicetree/bindings/riscv/cpus.yaml +++ b/Documentation/devicetree/bindings/riscv/cpus.yaml @@ -103,26 +103,7 @@ properties: interrupt-controller: type: object - additionalProperties: false - description: Describes the CPU's local interrupt controller - - properties: - '#interrupt-cells': - const: 1 - - compatible: - oneOf: - - items: - - const: andestech,cpu-intc - - const: riscv,cpu-intc - - const: riscv,cpu-intc - - interrupt-controller: true - - required: - - '#interrupt-cells' - - compatible - - interrupt-controller + $ref: /schemas/interrupt-controller/riscv,cpu-intc.yaml# cpu-idle-states: $ref: /schemas/types.yaml#/definitions/phandle-array diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml index 468c646247aa..a06dbc6b4928 100644 --- a/Documentation/devicetree/bindings/riscv/extensions.yaml +++ b/Documentation/devicetree/bindings/riscv/extensions.yaml @@ -177,6 +177,13 @@ properties: is supported as ratified at commit 5059e0ca641c ("update to ratified") of the riscv-zacas. + - const: zawrs + description: | + The Zawrs extension for entering a low-power state or for trapping + to a hypervisor while waiting on a store to a memory location, as + ratified in commit 98918c844281 ("Merge pull request #1217 from + riscv/zawrs") of riscv-isa-manual. + - const: zba description: | The standard Zba bit-manipulation extension for address generation @@ -220,6 +227,43 @@ properties: instructions as ratified at commit 6d33919 ("Merge pull request #158 from hirooih/clmul-fix-loop-end-condition") of riscv-bitmanip. + - const: zca + description: | + The Zca extension part of Zc* standard extensions for code size + reduction, as ratified in commit 8be3419c1c0 ("Zcf doesn't exist on + RV64 as it contains no instructions") of riscv-code-size-reduction, + merged in the riscv-isa-manual by commit dbc79cf28a2 ("Initial seed + of zc.adoc to src tree."). + + - const: zcb + description: | + The Zcb extension part of Zc* standard extensions for code size + reduction, as ratified in commit 8be3419c1c0 ("Zcf doesn't exist on + RV64 as it contains no instructions") of riscv-code-size-reduction, + merged in the riscv-isa-manual by commit dbc79cf28a2 ("Initial seed + of zc.adoc to src tree."). + + - const: zcd + description: | + The Zcd extension part of Zc* standard extensions for code size + reduction, as ratified in commit 8be3419c1c0 ("Zcf doesn't exist on + RV64 as it contains no instructions") of riscv-code-size-reduction, + merged in the riscv-isa-manual by commit dbc79cf28a2 ("Initial seed + of zc.adoc to src tree."). + + - const: zcf + description: | + The Zcf extension part of Zc* standard extensions for code size + reduction, as ratified in commit 8be3419c1c0 ("Zcf doesn't exist on + RV64 as it contains no instructions") of riscv-code-size-reduction, + merged in the riscv-isa-manual by commit dbc79cf28a2 ("Initial seed + of zc.adoc to src tree."). + + - const: zcmop + description: + The standard Zcmop extension version 1.0, as ratified in commit + c732a4f39a4 ("Zcmop is ratified/1.0") of the riscv-isa-manual. + - const: zfa description: The standard Zfa extension for additional floating point @@ -363,6 +407,11 @@ properties: ratified in the 20191213 version of the unprivileged ISA specification. + - const: zimop + description: + The standard Zimop extension version 1.0, as ratified in commit + 58220614a5f ("Zimop is ratified/1.0") of the riscv-isa-manual. + - const: ztso description: The standard Ztso extension for total store ordering, as ratified @@ -381,6 +430,36 @@ properties: instructions, as ratified in commit 56ed795 ("Update riscv-crypto-spec-vector.adoc") of riscv-crypto. + - const: zve32f + description: + The standard Zve32f extension for embedded processors, as ratified + in commit 6f702a2 ("Vector extensions are now ratified") of + riscv-v-spec. + + - const: zve32x + description: + The standard Zve32x extension for embedded processors, as ratified + in commit 6f702a2 ("Vector extensions are now ratified") of + riscv-v-spec. + + - const: zve64d + description: + The standard Zve64d extension for embedded processors, as ratified + in commit 6f702a2 ("Vector extensions are now ratified") of + riscv-v-spec. + + - const: zve64f + description: + The standard Zve64f extension for embedded processors, as ratified + in commit 6f702a2 ("Vector extensions are now ratified") of + riscv-v-spec. + + - const: zve64x + description: + The standard Zve64x extension for embedded processors, as ratified + in commit 6f702a2 ("Vector extensions are now ratified") of + riscv-v-spec. + - const: zvfh description: The standard Zvfh extension for vectored half-precision @@ -484,5 +563,58 @@ properties: Registers in the AX45MP datasheet. https://www.andestech.com/wp-content/uploads/AX45MP-1C-Rev.-5.0.0-Datasheet.pdf + allOf: + # Zcb depends on Zca + - if: + contains: + const: zcb + then: + contains: + const: zca + # Zcd depends on Zca and D + - if: + contains: + const: zcd + then: + allOf: + - contains: + const: zca + - contains: + const: d + # Zcf depends on Zca and F + - if: + contains: + const: zcf + then: + allOf: + - contains: + const: zca + - contains: + const: f + # Zcmop depends on Zca + - if: + contains: + const: zcmop + then: + contains: + const: zca + +allOf: + # Zcf extension does not exist on rv64 + - if: + properties: + riscv,isa-extensions: + contains: + const: zcf + riscv,isa-base: + contains: + const: rv64i + then: + properties: + riscv,isa-extensions: + not: + contains: + const: zcf + additionalProperties: true ... diff --git a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml new file mode 100644 index 000000000000..f7e606d45ebc --- /dev/null +++ b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml @@ -0,0 +1,374 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/mobileye/mobileye,eyeq5-olb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mobileye EyeQ SoC system controller + +maintainers: + - Grégory Clement + - Théo Lebrun + - Vladimir Kondratiev + +description: + OLB ("Other Logic Block") is a hardware block grouping smaller blocks. Clocks, + resets, pinctrl are being handled from here. EyeQ5 and EyeQ6L host a single + instance. EyeQ6H hosts seven instances. + +properties: + compatible: + items: + - enum: + - mobileye,eyeq5-olb + - mobileye,eyeq6l-olb + - mobileye,eyeq6h-acc-olb + - mobileye,eyeq6h-central-olb + - mobileye,eyeq6h-east-olb + - mobileye,eyeq6h-west-olb + - mobileye,eyeq6h-south-olb + - mobileye,eyeq6h-ddr0-olb + - mobileye,eyeq6h-ddr1-olb + - const: syscon + + reg: + maxItems: 1 + + '#reset-cells': + description: + First cell is domain and optional if compatible has a single reset domain. + Second cell is reset index inside that domain. + enum: [ 1, 2 ] + + '#clock-cells': + description: + Cell is clock index. Optional if compatible has a single clock. + enum: [ 0, 1 ] + + clocks: + maxItems: 1 + description: + Input parent clock to all PLLs. Expected to be the main crystal. + + clock-names: + const: ref + +patternProperties: + '-pins?$': + type: object + description: Pin muxing configuration. + $ref: /schemas/pinctrl/pinmux-node.yaml# + additionalProperties: false + properties: + pins: true + function: + enum: [gpio, + # Bank A + timer0, timer1, timer2, timer5, uart0, uart1, can0, can1, spi0, + spi1, refclk0, + # Bank B + timer3, timer4, timer6, uart2, can2, spi2, spi3, mclk0] + bias-disable: true + bias-pull-down: true + bias-pull-up: true + drive-strength: true + required: + - pins + - function + allOf: + - if: + properties: + function: + const: gpio + then: + properties: + pins: + items: # PA0 - PA28, PB0 - PB22 + pattern: '^(P(A|B)1?[0-9]|PA2[0-8]|PB2[0-2])$' + - if: + properties: + function: + const: timer0 + then: + properties: + pins: + items: + enum: [PA0, PA1] + - if: + properties: + function: + const: timer1 + then: + properties: + pins: + items: + enum: [PA2, PA3] + - if: + properties: + function: + const: timer2 + then: + properties: + pins: + items: + enum: [PA4, PA5] + - if: + properties: + function: + const: timer5 + then: + properties: + pins: + items: + enum: [PA6, PA7, PA8, PA9] + - if: + properties: + function: + const: uart0 + then: + properties: + pins: + items: + enum: [PA10, PA11] + - if: + properties: + function: + const: uart1 + then: + properties: + pins: + items: + enum: [PA12, PA13] + - if: + properties: + function: + const: can0 + then: + properties: + pins: + items: + enum: [PA14, PA15] + - if: + properties: + function: + const: can1 + then: + properties: + pins: + items: + enum: [PA16, PA17] + - if: + properties: + function: + const: spi0 + then: + properties: + pins: + items: + enum: [PA18, PA19, PA20, PA21, PA22] + - if: + properties: + function: + const: spi1 + then: + properties: + pins: + items: + enum: [PA23, PA24, PA25, PA26, PA27] + - if: + properties: + function: + const: refclk0 + then: + properties: + pins: + items: + enum: [PA28] + - if: + properties: + function: + const: timer3 + then: + properties: + pins: + items: + enum: [PB0, PB1] + - if: + properties: + function: + const: timer4 + then: + properties: + pins: + items: + enum: [PB2, PB3] + - if: + properties: + function: + const: timer6 + then: + properties: + pins: + items: + enum: [PB4, PB5, PB6, PB7] + - if: + properties: + function: + const: uart2 + then: + properties: + pins: + items: + enum: [PB8, PB9] + - if: + properties: + function: + const: can2 + then: + properties: + pins: + items: + enum: [PB10, PB11] + - if: + properties: + function: + const: spi2 + then: + properties: + pins: + items: + enum: [PB12, PB13, PB14, PB15, PB16] + - if: + properties: + function: + const: spi3 + then: + properties: + pins: + items: + enum: [PB17, PB18, PB19, PB20, PB21] + - if: + properties: + function: + const: mclk0 + then: + properties: + pins: + items: + enum: [PB22] + +required: + - compatible + - reg + - '#clock-cells' + - clocks + - clock-names + +additionalProperties: false + +allOf: + # Compatibles exposing a single reset domain. + - if: + properties: + compatible: + contains: + enum: + - mobileye,eyeq6h-acc-olb + - mobileye,eyeq6h-east-olb + - mobileye,eyeq6h-west-olb + then: + properties: + '#reset-cells': + const: 1 + required: + - '#reset-cells' + + # Compatibles exposing two reset domains. + - if: + properties: + compatible: + contains: + enum: + - mobileye,eyeq5-olb + - mobileye,eyeq6l-olb + then: + properties: + '#reset-cells': + const: 2 + required: + - '#reset-cells' + + # Compatibles not exposing resets. + - if: + properties: + compatible: + contains: + enum: + - mobileye,eyeq6h-central-olb + - mobileye,eyeq6h-south-olb + - mobileye,eyeq6h-ddr0-olb + - mobileye,eyeq6h-ddr1-olb + then: + properties: + '#reset-cells': false + + # Compatibles exposing a single clock. + - if: + properties: + compatible: + contains: + enum: + - mobileye,eyeq6h-central-olb + - mobileye,eyeq6h-east-olb + - mobileye,eyeq6h-west-olb + - mobileye,eyeq6h-ddr0-olb + - mobileye,eyeq6h-ddr1-olb + then: + properties: + '#clock-cells': + const: 0 + else: + properties: + '#clock-cells': + const: 1 + + # Only EyeQ5 has pinctrl in OLB. + - if: + not: + properties: + compatible: + contains: + const: mobileye,eyeq5-olb + then: + patternProperties: + '-pins?$': false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + + system-controller@e00000 { + compatible = "mobileye,eyeq5-olb", "syscon"; + reg = <0 0xe00000 0x0 0x400>; + #reset-cells = <2>; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "ref"; + }; + }; + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + + system-controller@d2003000 { + compatible = "mobileye,eyeq6h-acc-olb", "syscon"; + reg = <0x0 0xd2003000 0x0 0x1000>; + #reset-cells = <1>; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "ref"; + }; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 928e687385ab..a70ce43b3dc0 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -246,6 +246,8 @@ patternProperties: description: CALAO Systems SAS "^calxeda,.*": description: Calxeda + "^cameo,.*": + description: Cameo Communications, Inc "^canaan,.*": description: Canaan, Inc. "^caninos,.*": diff --git a/Documentation/userspace-api/landlock.rst b/Documentation/userspace-api/landlock.rst index 07b63aec56fa..37dafce8038b 100644 --- a/Documentation/userspace-api/landlock.rst +++ b/Documentation/userspace-api/landlock.rst @@ -8,7 +8,7 @@ Landlock: unprivileged access control ===================================== :Author: Mickaël Salaün -:Date: April 2024 +:Date: July 2024 The goal of Landlock is to enable to restrict ambient rights (e.g. global filesystem or network access) for a set of processes. Because Landlock diff --git a/Documentation/virt/coco/sev-guest.rst b/Documentation/virt/coco/sev-guest.rst index 9d00967a5b2b..93debceb6eb0 100644 --- a/Documentation/virt/coco/sev-guest.rst +++ b/Documentation/virt/coco/sev-guest.rst @@ -176,6 +176,25 @@ to SNP_CONFIG command defined in the SEV-SNP spec. The current values of the firmware parameters affected by this command can be queried via SNP_PLATFORM_STATUS. +2.7 SNP_VLEK_LOAD +----------------- +:Technology: sev-snp +:Type: hypervisor ioctl cmd +:Parameters (in): struct sev_user_data_snp_vlek_load +:Returns (out): 0 on success, -negative on error + +When requesting an attestation report a guest is able to specify whether +it wants SNP firmware to sign the report using either a Versioned Chip +Endorsement Key (VCEK), which is derived from chip-unique secrets, or a +Versioned Loaded Endorsement Key (VLEK) which is obtained from an AMD +Key Derivation Service (KDS) and derived from seeds allocated to +enrolled cloud service providers. + +In the case of VLEK keys, the SNP_VLEK_LOAD SNP command is used to load +them into the system after obtaining them from the KDS, and corresponds +closely to the SNP_VLEK_LOAD firmware command specified in the SEV-SNP +spec. + 3. SEV-SNP CPUID Enforcement ============================ diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index a71d91978d9e..fe722c5dada9 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -891,12 +891,12 @@ like this:: The irq_type field has the following values: -- irq_type[0]: +- KVM_ARM_IRQ_TYPE_CPU: out-of-kernel GIC: irq_id 0 is IRQ, irq_id 1 is FIQ -- irq_type[1]: +- KVM_ARM_IRQ_TYPE_SPI: in-kernel GIC: SPI, irq_id between 32 and 1019 (incl.) (the vcpu_index field is ignored) -- irq_type[2]: +- KVM_ARM_IRQ_TYPE_PPI: in-kernel GIC: PPI, irq_id between 16 and 31 (incl.) (The irq_id field thus corresponds nicely to the IRQ ID in the ARM GIC specs) @@ -1403,6 +1403,12 @@ Instead, an abort (data abort if the cause of the page-table update was a load or a store, instruction abort if it was an instruction fetch) is injected in the guest. +S390: +^^^^^ + +Returns -EINVAL if the VM has the KVM_VM_S390_UCONTROL flag set. +Returns -EINVAL if called on a protected VM. + 4.36 KVM_SET_TSS_ADDR --------------------- @@ -1921,7 +1927,7 @@ flags: If KVM_MSI_VALID_DEVID is set, devid contains a unique device identifier for the device that wrote the MSI message. For PCI, this is usually a -BFD identifier in the lower 16 bits. +BDF identifier in the lower 16 bits. On x86, address_hi is ignored unless the KVM_X2APIC_API_USE_32BIT_IDS feature of KVM_CAP_X2APIC_API capability is enabled. If it is enabled, @@ -2439,8 +2445,11 @@ registers, find a list below: PPC KVM_REG_PPC_PSSCR 64 PPC KVM_REG_PPC_DEC_EXPIRY 64 PPC KVM_REG_PPC_PTCR 64 + PPC KVM_REG_PPC_HASHKEYR 64 + PPC KVM_REG_PPC_HASHPKEYR 64 PPC KVM_REG_PPC_DAWR1 64 PPC KVM_REG_PPC_DAWRX1 64 + PPC KVM_REG_PPC_DEXCR 64 PPC KVM_REG_PPC_TM_GPR0 64 ... PPC KVM_REG_PPC_TM_GPR31 64 @@ -2986,7 +2995,7 @@ flags: If KVM_MSI_VALID_DEVID is set, devid contains a unique device identifier for the device that wrote the MSI message. For PCI, this is usually a -BFD identifier in the lower 16 bits. +BDF identifier in the lower 16 bits. On x86, address_hi is ignored unless the KVM_X2APIC_API_USE_32BIT_IDS feature of KVM_CAP_X2APIC_API capability is enabled. If it is enabled, @@ -6273,6 +6282,12 @@ state. At VM creation time, all memory is shared, i.e. the PRIVATE attribute is '0' for all gfns. Userspace can control whether memory is shared/private by toggling KVM_MEMORY_ATTRIBUTE_PRIVATE via KVM_SET_MEMORY_ATTRIBUTES as needed. +S390: +^^^^^ + +Returns -EINVAL if the VM has the KVM_VM_S390_UCONTROL flag set. +Returns -EINVAL if called on a protected VM. + 4.141 KVM_SET_MEMORY_ATTRIBUTES ------------------------------- @@ -6352,6 +6367,61 @@ a single guest_memfd file, but the bound ranges must not overlap). See KVM_SET_USER_MEMORY_REGION2 for additional details. +4.143 KVM_PRE_FAULT_MEMORY +------------------------ + +:Capability: KVM_CAP_PRE_FAULT_MEMORY +:Architectures: none +:Type: vcpu ioctl +:Parameters: struct kvm_pre_fault_memory (in/out) +:Returns: 0 if at least one page is processed, < 0 on error + +Errors: + + ========== =============================================================== + EINVAL The specified `gpa` and `size` were invalid (e.g. not + page aligned, causes an overflow, or size is zero). + ENOENT The specified `gpa` is outside defined memslots. + EINTR An unmasked signal is pending and no page was processed. + EFAULT The parameter address was invalid. + EOPNOTSUPP Mapping memory for a GPA is unsupported by the + hypervisor, and/or for the current vCPU state/mode. + EIO unexpected error conditions (also causes a WARN) + ========== =============================================================== + +:: + + struct kvm_pre_fault_memory { + /* in/out */ + __u64 gpa; + __u64 size; + /* in */ + __u64 flags; + __u64 padding[5]; + }; + +KVM_PRE_FAULT_MEMORY populates KVM's stage-2 page tables used to map memory +for the current vCPU state. KVM maps memory as if the vCPU generated a +stage-2 read page fault, e.g. faults in memory as needed, but doesn't break +CoW. However, KVM does not mark any newly created stage-2 PTE as Accessed. + +In some cases, multiple vCPUs might share the page tables. In this +case, the ioctl can be called in parallel. + +When the ioctl returns, the input values are updated to point to the +remaining range. If `size` > 0 on return, the caller can just issue +the ioctl again with the same `struct kvm_map_memory` argument. + +Shadow page tables cannot support this ioctl because they +are indexed by virtual address or nested guest physical address. +Calling this ioctl when the guest is using shadow page tables (for +example because it is running a nested guest with nested page tables) +will fail with `EOPNOTSUPP` even if `KVM_CHECK_EXTENSION` reports +the capability to be present. + +`flags` must currently be zero. + + 5. The kvm_run structure ======================== @@ -6416,9 +6486,12 @@ More architecture-specific flags detailing state of the VCPU that may affect the device's behavior. Current defined flags:: /* x86, set if the VCPU is in system management mode */ - #define KVM_RUN_X86_SMM (1 << 0) + #define KVM_RUN_X86_SMM (1 << 0) /* x86, set if bus lock detected in VM */ - #define KVM_RUN_BUS_LOCK (1 << 1) + #define KVM_RUN_X86_BUS_LOCK (1 << 1) + /* x86, set if the VCPU is executing a nested (L2) guest */ + #define KVM_RUN_X86_GUEST_MODE (1 << 2) + /* arm64, set for KVM_EXIT_DEBUG */ #define KVM_DEBUG_ARCH_HSR_HIGH_VALID (1 << 0) @@ -7764,29 +7837,31 @@ Valid bits in args[0] are:: #define KVM_BUS_LOCK_DETECTION_OFF (1 << 0) #define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1) -Enabling this capability on a VM provides userspace with a way to select -a policy to handle the bus locks detected in guest. Userspace can obtain -the supported modes from the result of KVM_CHECK_EXTENSION and define it -through the KVM_ENABLE_CAP. +Enabling this capability on a VM provides userspace with a way to select a +policy to handle the bus locks detected in guest. Userspace can obtain the +supported modes from the result of KVM_CHECK_EXTENSION and define it through +the KVM_ENABLE_CAP. The supported modes are mutually-exclusive. -KVM_BUS_LOCK_DETECTION_OFF and KVM_BUS_LOCK_DETECTION_EXIT are supported -currently and mutually exclusive with each other. More bits can be added in -the future. +This capability allows userspace to force VM exits on bus locks detected in the +guest, irrespective whether or not the host has enabled split-lock detection +(which triggers an #AC exception that KVM intercepts). This capability is +intended to mitigate attacks where a malicious/buggy guest can exploit bus +locks to degrade the performance of the whole system. -With KVM_BUS_LOCK_DETECTION_OFF set, bus locks in guest will not cause vm exits -so that no additional actions are needed. This is the default mode. +If KVM_BUS_LOCK_DETECTION_OFF is set, KVM doesn't force guest bus locks to VM +exit, although the host kernel's split-lock #AC detection still applies, if +enabled. -With KVM_BUS_LOCK_DETECTION_EXIT set, vm exits happen when bus lock detected -in VM. KVM just exits to userspace when handling them. Userspace can enforce -its own throttling or other policy based mitigations. +If KVM_BUS_LOCK_DETECTION_EXIT is set, KVM enables a CPU feature that ensures +bus locks in the guest trigger a VM exit, and KVM exits to userspace for all +such VM exits, e.g. to allow userspace to throttle the offending guest and/or +apply some other policy-based mitigation. When exiting to userspace, KVM sets +KVM_RUN_X86_BUS_LOCK in vcpu-run->flags, and conditionally sets the exit_reason +to KVM_EXIT_X86_BUS_LOCK. -This capability is aimed to address the thread that VM can exploit bus locks to -degree the performance of the whole system. Once the userspace enable this -capability and select the KVM_BUS_LOCK_DETECTION_EXIT mode, KVM will set the -KVM_RUN_BUS_LOCK flag in vcpu-run->flags field and exit to userspace. Concerning -the bus lock vm exit can be preempted by a higher priority VM exit, the exit -notifications to userspace can be KVM_EXIT_BUS_LOCK or other reasons. -KVM_RUN_BUS_LOCK flag is used to distinguish between them. +Note! Detected bus locks may be coincident with other exits to userspace, i.e. +KVM_RUN_X86_BUS_LOCK should be checked regardless of the primary exit reason if +userspace wants to take action on all detected bus locks. 7.23 KVM_CAP_PPC_DAWR1 ---------------------- @@ -7902,10 +7977,10 @@ perform a bulk copy of tags to/from the guest. 7.29 KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM ------------------------------------- -Architectures: x86 SEV enabled -Type: vm -Parameters: args[0] is the fd of the source vm -Returns: 0 on success +:Architectures: x86 SEV enabled +:Type: vm +:Parameters: args[0] is the fd of the source vm +:Returns: 0 on success This capability enables userspace to migrate the encryption context from the VM indicated by the fd to the VM this is called on. @@ -7953,7 +8028,11 @@ The valid bits in cap.args[0] are: When this quirk is disabled, the reset value is 0x10000 (APIC_LVT_MASKED). - KVM_X86_QUIRK_CD_NW_CLEARED By default, KVM clears CR0.CD and CR0.NW. + KVM_X86_QUIRK_CD_NW_CLEARED By default, KVM clears CR0.CD and CR0.NW on + AMD CPUs to workaround buggy guest firmware + that runs in perpetuity with CR0.CD, i.e. + with caches in "no fill" mode. + When this quirk is disabled, KVM does not change the value of CR0.CD and CR0.NW. @@ -8070,6 +8149,37 @@ error/annotated fault. See KVM_EXIT_MEMORY_FAULT for more information. +7.35 KVM_CAP_X86_APIC_BUS_CYCLES_NS +----------------------------------- + +:Architectures: x86 +:Target: VM +:Parameters: args[0] is the desired APIC bus clock rate, in nanoseconds +:Returns: 0 on success, -EINVAL if args[0] contains an invalid value for the + frequency or if any vCPUs have been created, -ENXIO if a virtual + local APIC has not been created using KVM_CREATE_IRQCHIP. + +This capability sets the VM's APIC bus clock frequency, used by KVM's in-kernel +virtual APIC when emulating APIC timers. KVM's default value can be retrieved +by KVM_CHECK_EXTENSION. + +Note: Userspace is responsible for correctly configuring CPUID 0x15, a.k.a. the +core crystal clock frequency, if a non-zero CPUID 0x15 is exposed to the guest. + +7.36 KVM_CAP_X86_GUEST_MODE +------------------------------ + +:Architectures: x86 +:Returns: Informational only, -EINVAL on direct KVM_ENABLE_CAP. + +The presence of this capability indicates that KVM_RUN will update the +KVM_RUN_X86_GUEST_MODE bit in kvm_run.flags to indicate whether the +vCPU was executing nested guest code when it exited. + +KVM exits with the register state of either the L1 or L2 guest +depending on which executed at the time of an exit. Userspace must +take care to differentiate between these cases. + 8. Other capabilities. ====================== diff --git a/Documentation/virt/kvm/devices/arm-vgic.rst b/Documentation/virt/kvm/devices/arm-vgic.rst index 40bdeea1d86e..19f0c6756891 100644 --- a/Documentation/virt/kvm/devices/arm-vgic.rst +++ b/Documentation/virt/kvm/devices/arm-vgic.rst @@ -31,7 +31,7 @@ Groups: KVM_VGIC_V2_ADDR_TYPE_CPU (rw, 64-bit) Base address in the guest physical address space of the GIC virtual cpu interface register mappings. Only valid for KVM_DEV_TYPE_ARM_VGIC_V2. - This address needs to be 4K aligned and the region covers 4 KByte. + This address needs to be 4K aligned and the region covers 8 KByte. Errors: diff --git a/Documentation/virt/kvm/halt-polling.rst b/Documentation/virt/kvm/halt-polling.rst index c82a04b709b4..a6790a67e205 100644 --- a/Documentation/virt/kvm/halt-polling.rst +++ b/Documentation/virt/kvm/halt-polling.rst @@ -79,11 +79,11 @@ adjustment of the polling interval. Module Parameters ================= -The kvm module has 3 tuneable module parameters to adjust the global max -polling interval as well as the rate at which the polling interval is grown and -shrunk. These variables are defined in include/linux/kvm_host.h and as module -parameters in virt/kvm/kvm_main.c, or arch/powerpc/kvm/book3s_hv.c in the -powerpc kvm-hv case. +The kvm module has 4 tunable module parameters to adjust the global max polling +interval, the initial value (to grow from 0), and the rate at which the polling +interval is grown and shrunk. These variables are defined in +include/linux/kvm_host.h and as module parameters in virt/kvm/kvm_main.c, or +arch/powerpc/kvm/book3s_hv.c in the powerpc kvm-hv case. +-----------------------+---------------------------+-------------------------+ |Module Parameter | Description | Default Value | @@ -105,7 +105,7 @@ powerpc kvm-hv case. | | grow_halt_poll_ns() | | | | function. | | +-----------------------+---------------------------+-------------------------+ -|halt_poll_ns_shrink | The value by which the | 0 | +|halt_poll_ns_shrink | The value by which the | 2 | | | halt polling interval is | | | | divided in the | | | | shrink_halt_poll_ns() | | diff --git a/Documentation/virt/kvm/x86/amd-memory-encryption.rst b/Documentation/virt/kvm/x86/amd-memory-encryption.rst index 9677a0714a39..1ddb6a86ce7f 100644 --- a/Documentation/virt/kvm/x86/amd-memory-encryption.rst +++ b/Documentation/virt/kvm/x86/amd-memory-encryption.rst @@ -466,6 +466,112 @@ issued by the hypervisor to make the guest ready for execution. Returns: 0 on success, -negative on error +18. KVM_SEV_SNP_LAUNCH_START +---------------------------- + +The KVM_SNP_LAUNCH_START command is used for creating the memory encryption +context for the SEV-SNP guest. It must be called prior to issuing +KVM_SEV_SNP_LAUNCH_UPDATE or KVM_SEV_SNP_LAUNCH_FINISH; + +Parameters (in): struct kvm_sev_snp_launch_start + +Returns: 0 on success, -negative on error + +:: + + struct kvm_sev_snp_launch_start { + __u64 policy; /* Guest policy to use. */ + __u8 gosvw[16]; /* Guest OS visible workarounds. */ + __u16 flags; /* Must be zero. */ + __u8 pad0[6]; + __u64 pad1[4]; + }; + +See SNP_LAUNCH_START in the SEV-SNP specification [snp-fw-abi]_ for further +details on the input parameters in ``struct kvm_sev_snp_launch_start``. + +19. KVM_SEV_SNP_LAUNCH_UPDATE +----------------------------- + +The KVM_SEV_SNP_LAUNCH_UPDATE command is used for loading userspace-provided +data into a guest GPA range, measuring the contents into the SNP guest context +created by KVM_SEV_SNP_LAUNCH_START, and then encrypting/validating that GPA +range so that it will be immediately readable using the encryption key +associated with the guest context once it is booted, after which point it can +attest the measurement associated with its context before unlocking any +secrets. + +It is required that the GPA ranges initialized by this command have had the +KVM_MEMORY_ATTRIBUTE_PRIVATE attribute set in advance. See the documentation +for KVM_SET_MEMORY_ATTRIBUTES for more details on this aspect. + +Upon success, this command is not guaranteed to have processed the entire +range requested. Instead, the ``gfn_start``, ``uaddr``, and ``len`` fields of +``struct kvm_sev_snp_launch_update`` will be updated to correspond to the +remaining range that has yet to be processed. The caller should continue +calling this command until those fields indicate the entire range has been +processed, e.g. ``len`` is 0, ``gfn_start`` is equal to the last GFN in the +range plus 1, and ``uaddr`` is the last byte of the userspace-provided source +buffer address plus 1. In the case where ``type`` is KVM_SEV_SNP_PAGE_TYPE_ZERO, +``uaddr`` will be ignored completely. + +Parameters (in): struct kvm_sev_snp_launch_update + +Returns: 0 on success, < 0 on error, -EAGAIN if caller should retry + +:: + + struct kvm_sev_snp_launch_update { + __u64 gfn_start; /* Guest page number to load/encrypt data into. */ + __u64 uaddr; /* Userspace address of data to be loaded/encrypted. */ + __u64 len; /* 4k-aligned length in bytes to copy into guest memory.*/ + __u8 type; /* The type of the guest pages being initialized. */ + __u8 pad0; + __u16 flags; /* Must be zero. */ + __u32 pad1; + __u64 pad2[4]; + + }; + +where the allowed values for page_type are #define'd as:: + + KVM_SEV_SNP_PAGE_TYPE_NORMAL + KVM_SEV_SNP_PAGE_TYPE_ZERO + KVM_SEV_SNP_PAGE_TYPE_UNMEASURED + KVM_SEV_SNP_PAGE_TYPE_SECRETS + KVM_SEV_SNP_PAGE_TYPE_CPUID + +See the SEV-SNP spec [snp-fw-abi]_ for further details on how each page type is +used/measured. + +20. KVM_SEV_SNP_LAUNCH_FINISH +----------------------------- + +After completion of the SNP guest launch flow, the KVM_SEV_SNP_LAUNCH_FINISH +command can be issued to make the guest ready for execution. + +Parameters (in): struct kvm_sev_snp_launch_finish + +Returns: 0 on success, -negative on error + +:: + + struct kvm_sev_snp_launch_finish { + __u64 id_block_uaddr; + __u64 id_auth_uaddr; + __u8 id_block_en; + __u8 auth_key_en; + __u8 vcek_disabled; + __u8 host_data[32]; + __u8 pad0[3]; + __u16 flags; /* Must be zero */ + __u64 pad1[4]; + }; + + +See SNP_LAUNCH_FINISH in the SEV-SNP specification [snp-fw-abi]_ for further +details on the input parameters in ``struct kvm_sev_snp_launch_finish``. + Device attribute API ==================== @@ -497,9 +603,11 @@ References ========== -See [white-paper]_, [api-spec]_, [amd-apm]_ and [kvm-forum]_ for more info. +See [white-paper]_, [api-spec]_, [amd-apm]_, [kvm-forum]_, and [snp-fw-abi]_ +for more info. .. [white-paper] https://developer.amd.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf .. [api-spec] https://support.amd.com/TechDocs/55766_SEV-KM_API_Specification.pdf .. [amd-apm] https://support.amd.com/TechDocs/24593.pdf (section 15.34) .. [kvm-forum] https://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf +.. [snp-fw-abi] https://www.amd.com/system/files/TechDocs/56860.pdf diff --git a/Documentation/virt/kvm/x86/errata.rst b/Documentation/virt/kvm/x86/errata.rst index 49a05f24747b..4116045a8744 100644 --- a/Documentation/virt/kvm/x86/errata.rst +++ b/Documentation/virt/kvm/x86/errata.rst @@ -48,3 +48,21 @@ have the same physical APIC ID, KVM will deliver events targeting that APIC ID only to the vCPU with the lowest vCPU ID. If KVM_X2APIC_API_USE_32BIT_IDS is not enabled, KVM follows x86 architecture when processing interrupts (all vCPUs matching the target APIC ID receive the interrupt). + +MTRRs +----- +KVM does not virtualize guest MTRR memory types. KVM emulates accesses to MTRR +MSRs, i.e. {RD,WR}MSR in the guest will behave as expected, but KVM does not +honor guest MTRRs when determining the effective memory type, and instead +treats all of guest memory as having Writeback (WB) MTRRs. + +CR0.CD +------ +KVM does not virtualize CR0.CD on Intel CPUs. Similar to MTRR MSRs, KVM +emulates CR0.CD accesses so that loads and stores from/to CR0 behave as +expected, but setting CR0.CD=1 has no impact on the cachaeability of guest +memory. + +Note, this erratum does not affect AMD CPUs, which fully virtualize CR0.CD in +hardware, i.e. put the CPU caches into "no fill" mode when CR0.CD=1, even when +running in the guest. \ No newline at end of file diff --git a/MAINTAINERS b/MAINTAINERS index e45b3e150678..b8806f9df157 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12255,6 +12255,8 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: kvmarm@lists.linux.dev S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git +F: Documentation/virt/kvm/arm/ +F: Documentation/virt/kvm/devices/arm* F: arch/arm64/include/asm/kvm* F: arch/arm64/include/uapi/asm/kvm* F: arch/arm64/kvm/ @@ -12931,7 +12933,6 @@ F: arch/powerpc/platforms/52xx/ LINUX FOR POWERPC EMBEDDED PPC4XX L: linuxppc-dev@lists.ozlabs.org S: Orphan -F: arch/powerpc/platforms/40x/ F: arch/powerpc/platforms/44x/ LINUX FOR POWERPC EMBEDDED PPC85XX @@ -15414,9 +15415,14 @@ M: Théo Lebrun L: linux-mips@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/mips/mobileye.yaml +F: Documentation/devicetree/bindings/soc/mobileye/ F: arch/mips/boot/dts/mobileye/ F: arch/mips/configs/eyeq5_defconfig F: arch/mips/mobileye/board-epm5.its.S +F: drivers/clk/clk-eyeq.c +F: drivers/pinctrl/pinctrl-eyeq5.c +F: drivers/reset/reset-eyeq.c +F: include/dt-bindings/clock/mobileye,eyeq5-clk.h MODULE SUPPORT M: Luis Chamberlain diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h index 3f482500f71f..56c148890daf 100644 --- a/arch/arm64/include/asm/esr.h +++ b/arch/arm64/include/asm/esr.h @@ -160,6 +160,7 @@ #define ESR_ELx_Xs_MASK (GENMASK_ULL(4, 0)) /* ISS field definitions for exceptions taken in to Hyp */ +#define ESR_ELx_FSC_ADDRSZ (0x00) #define ESR_ELx_CV (UL(1) << 24) #define ESR_ELx_COND_SHIFT (20) #define ESR_ELx_COND_MASK (UL(0xF) << ESR_ELx_COND_SHIFT) @@ -387,6 +388,11 @@ #ifndef __ASSEMBLY__ #include +static inline unsigned long esr_brk_comment(unsigned long esr) +{ + return esr & ESR_ELx_BRK64_ISS_COMMENT_MASK; +} + static inline bool esr_is_data_abort(unsigned long esr) { const unsigned long ec = ESR_ELx_EC(esr); @@ -394,6 +400,12 @@ static inline bool esr_is_data_abort(unsigned long esr) return ec == ESR_ELx_EC_DABT_LOW || ec == ESR_ELx_EC_DABT_CUR; } +static inline bool esr_is_cfi_brk(unsigned long esr) +{ + return ESR_ELx_EC(esr) == ESR_ELx_EC_BRK64 && + (esr_brk_comment(esr) & ~CFI_BRK_IMM_MASK) == CFI_BRK_IMM_BASE; +} + static inline bool esr_fsc_is_translation_fault(unsigned long esr) { esr = esr & ESR_ELx_FSC; diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index b2adc2c6c82a..d81cc746e0eb 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -102,7 +102,6 @@ #define HCR_HOST_NVHE_PROTECTED_FLAGS (HCR_HOST_NVHE_FLAGS | HCR_TSC) #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H) -#define HCRX_GUEST_FLAGS (HCRX_EL2_SMPME | HCRX_EL2_TCR2En) #define HCRX_HOST_FLAGS (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En | HCRX_EL2_EnFPM) /* TCR_EL2 Registers bits */ diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index a6330460d9e5..2181a11b9d92 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -232,6 +232,8 @@ extern void __kvm_tlb_flush_vmid_range(struct kvm_s2_mmu *mmu, phys_addr_t start, unsigned long pages); extern void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu); +extern int __kvm_tlbi_s1e2(struct kvm_s2_mmu *mmu, u64 va, u64 sys_encoding); + extern void __kvm_timer_set_cntvoff(u64 cntvoff); extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 21650e7924d4..a601a9305b10 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -11,6 +11,7 @@ #ifndef __ARM64_KVM_EMULATE_H__ #define __ARM64_KVM_EMULATE_H__ +#include #include #include @@ -55,6 +56,14 @@ void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu); int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2); int kvm_inject_nested_irq(struct kvm_vcpu *vcpu); +static inline void kvm_inject_nested_sve_trap(struct kvm_vcpu *vcpu) +{ + u64 esr = FIELD_PREP(ESR_ELx_EC_MASK, ESR_ELx_EC_SVE) | + ESR_ELx_IL; + + kvm_inject_nested_sync(vcpu, esr); +} + #if defined(__KVM_VHE_HYPERVISOR__) || defined(__KVM_NVHE_HYPERVISOR__) static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu) { @@ -69,39 +78,17 @@ static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu) static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu) { - vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS; - if (has_vhe() || has_hvhe()) - vcpu->arch.hcr_el2 |= HCR_E2H; - if (cpus_have_final_cap(ARM64_HAS_RAS_EXTN)) { - /* route synchronous external abort exceptions to EL2 */ - vcpu->arch.hcr_el2 |= HCR_TEA; - /* trap error record accesses */ - vcpu->arch.hcr_el2 |= HCR_TERR; - } + if (!vcpu_has_run_once(vcpu)) + vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS; - if (cpus_have_final_cap(ARM64_HAS_STAGE2_FWB)) { - vcpu->arch.hcr_el2 |= HCR_FWB; - } else { - /* - * For non-FWB CPUs, we trap VM ops (HCR_EL2.TVM) until M+C - * get set in SCTLR_EL1 such that we can detect when the guest - * MMU gets turned on and do the necessary cache maintenance - * then. - */ + /* + * For non-FWB CPUs, we trap VM ops (HCR_EL2.TVM) until M+C + * get set in SCTLR_EL1 such that we can detect when the guest + * MMU gets turned on and do the necessary cache maintenance + * then. + */ + if (!cpus_have_final_cap(ARM64_HAS_STAGE2_FWB)) vcpu->arch.hcr_el2 |= HCR_TVM; - } - - if (cpus_have_final_cap(ARM64_HAS_EVT) && - !cpus_have_final_cap(ARM64_MISMATCHED_CACHE_TYPE)) - vcpu->arch.hcr_el2 |= HCR_TID4; - else - vcpu->arch.hcr_el2 |= HCR_TID2; - - if (vcpu_el1_is_32bit(vcpu)) - vcpu->arch.hcr_el2 &= ~HCR_RW; - - if (kvm_has_mte(vcpu->kvm)) - vcpu->arch.hcr_el2 |= HCR_ATA; } static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu) @@ -660,4 +647,50 @@ static __always_inline void kvm_reset_cptr_el2(struct kvm_vcpu *vcpu) kvm_write_cptr_el2(val); } + +/* + * Returns a 'sanitised' view of CPTR_EL2, translating from nVHE to the VHE + * format if E2H isn't set. + */ +static inline u64 vcpu_sanitised_cptr_el2(const struct kvm_vcpu *vcpu) +{ + u64 cptr = __vcpu_sys_reg(vcpu, CPTR_EL2); + + if (!vcpu_el2_e2h_is_set(vcpu)) + cptr = translate_cptr_el2_to_cpacr_el1(cptr); + + return cptr; +} + +static inline bool ____cptr_xen_trap_enabled(const struct kvm_vcpu *vcpu, + unsigned int xen) +{ + switch (xen) { + case 0b00: + case 0b10: + return true; + case 0b01: + return vcpu_el2_tge_is_set(vcpu) && !vcpu_is_el2(vcpu); + case 0b11: + default: + return false; + } +} + +#define __guest_hyp_cptr_xen_trap_enabled(vcpu, xen) \ + (!vcpu_has_nv(vcpu) ? false : \ + ____cptr_xen_trap_enabled(vcpu, \ + SYS_FIELD_GET(CPACR_ELx, xen, \ + vcpu_sanitised_cptr_el2(vcpu)))) + +static inline bool guest_hyp_fpsimd_traps_enabled(const struct kvm_vcpu *vcpu) +{ + return __guest_hyp_cptr_xen_trap_enabled(vcpu, FPEN); +} + +static inline bool guest_hyp_sve_traps_enabled(const struct kvm_vcpu *vcpu) +{ + return __guest_hyp_cptr_xen_trap_enabled(vcpu, ZEN); +} + #endif /* __ARM64_KVM_EMULATE_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 36b8e97bf49e..a33f5996ca9f 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -189,6 +189,33 @@ struct kvm_s2_mmu { uint64_t split_page_chunk_size; struct kvm_arch *arch; + + /* + * For a shadow stage-2 MMU, the virtual vttbr used by the + * host to parse the guest S2. + * This either contains: + * - the virtual VTTBR programmed by the guest hypervisor with + * CnP cleared + * - The value 1 (VMID=0, BADDR=0, CnP=1) if invalid + * + * We also cache the full VTCR which gets used for TLB invalidation, + * taking the ARM ARM's "Any of the bits in VTCR_EL2 are permitted + * to be cached in a TLB" to the letter. + */ + u64 tlb_vttbr; + u64 tlb_vtcr; + + /* + * true when this represents a nested context where virtual + * HCR_EL2.VM == 1 + */ + bool nested_stage2_enabled; + + /* + * 0: Nobody is currently using this, check vttbr for validity + * >0: Somebody is actively using this. + */ + atomic_t refcnt; }; struct kvm_arch_memory_slot { @@ -256,6 +283,14 @@ struct kvm_arch { */ u64 fgu[__NR_FGT_GROUP_IDS__]; + /* + * Stage 2 paging state for VMs with nested S2 using a virtual + * VMID. + */ + struct kvm_s2_mmu *nested_mmus; + size_t nested_mmus_size; + int nested_mmus_next; + /* Interrupt controller */ struct vgic_dist vgic; @@ -327,11 +362,11 @@ struct kvm_arch { * Atomic access to multiple idregs are guarded by kvm_arch.config_lock. */ #define IDREG_IDX(id) (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id)) -#define IDX_IDREG(idx) sys_reg(3, 0, 0, ((idx) >> 3) + 1, (idx) & Op2_mask) -#define IDREG(kvm, id) ((kvm)->arch.id_regs[IDREG_IDX(id)]) #define KVM_ARM_ID_REG_NUM (IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1) u64 id_regs[KVM_ARM_ID_REG_NUM]; + u64 ctr_el0; + /* Masks for VNCR-baked sysregs */ struct kvm_sysreg_masks *sysreg_masks; @@ -423,6 +458,7 @@ enum vcpu_sysreg { MDCR_EL2, /* Monitor Debug Configuration Register (EL2) */ CPTR_EL2, /* Architectural Feature Trap Register (EL2) */ HACR_EL2, /* Hypervisor Auxiliary Control Register */ + ZCR_EL2, /* SVE Control Register (EL2) */ TTBR0_EL2, /* Translation Table Base Register 0 (EL2) */ TTBR1_EL2, /* Translation Table Base Register 1 (EL2) */ TCR_EL2, /* Translation Control Register (EL2) */ @@ -867,6 +903,9 @@ struct kvm_vcpu_arch { #define vcpu_sve_max_vq(vcpu) sve_vq_from_vl((vcpu)->arch.sve_max_vl) +#define vcpu_sve_zcr_elx(vcpu) \ + (unlikely(is_hyp_ctxt(vcpu)) ? ZCR_EL2 : ZCR_EL1) + #define vcpu_sve_state_size(vcpu) ({ \ size_t __size_ret; \ unsigned int __vcpu_vq; \ @@ -991,6 +1030,7 @@ static inline bool __vcpu_read_sys_reg_from_cpu(int reg, u64 *val) case DACR32_EL2: *val = read_sysreg_s(SYS_DACR32_EL2); break; case IFSR32_EL2: *val = read_sysreg_s(SYS_IFSR32_EL2); break; case DBGVCR32_EL2: *val = read_sysreg_s(SYS_DBGVCR32_EL2); break; + case ZCR_EL1: *val = read_sysreg_s(SYS_ZCR_EL12); break; default: return false; } @@ -1036,6 +1076,7 @@ static inline bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg) case DACR32_EL2: write_sysreg_s(val, SYS_DACR32_EL2); break; case IFSR32_EL2: write_sysreg_s(val, SYS_IFSR32_EL2); break; case DBGVCR32_EL2: write_sysreg_s(val, SYS_DBGVCR32_EL2); break; + case ZCR_EL1: write_sysreg_s(val, SYS_ZCR_EL12); break; default: return false; } @@ -1145,7 +1186,7 @@ int __init populate_nv_trap_config(void); bool lock_all_vcpus(struct kvm *kvm); void unlock_all_vcpus(struct kvm *kvm); -void kvm_init_sysreg(struct kvm_vcpu *); +void kvm_calculate_traps(struct kvm_vcpu *vcpu); /* MMIO helpers */ void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data); @@ -1248,7 +1289,6 @@ static inline bool kvm_system_needs_idmapped_vectors(void) } static inline void kvm_arch_sync_events(struct kvm *kvm) {} -static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} void kvm_arm_init_debug(void); void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu); @@ -1306,6 +1346,7 @@ void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu); void kvm_vcpu_put_vhe(struct kvm_vcpu *vcpu); int __init kvm_set_ipa_limit(void); +u32 kvm_get_pa_bits(struct kvm *kvm); #define __KVM_HAVE_ARCH_VM_ALLOC struct kvm *kvm_arch_alloc_vm(void); @@ -1355,6 +1396,24 @@ static inline void kvm_hyp_reserve(void) { } void kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu); bool kvm_arm_vcpu_stopped(struct kvm_vcpu *vcpu); +static inline u64 *__vm_id_reg(struct kvm_arch *ka, u32 reg) +{ + switch (reg) { + case sys_reg(3, 0, 0, 1, 0) ... sys_reg(3, 0, 0, 7, 7): + return &ka->id_regs[IDREG_IDX(reg)]; + case SYS_CTR_EL0: + return &ka->ctr_el0; + default: + WARN_ON_ONCE(1); + return NULL; + } +} + +#define kvm_read_vm_id_reg(kvm, reg) \ + ({ u64 __val = *__vm_id_reg(&(kvm)->arch, reg); __val; }) + +void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val); + #define __expand_field_sign_unsigned(id, fld, val) \ ((u64)SYS_FIELD_VALUE(id, fld, val)) @@ -1371,7 +1430,7 @@ bool kvm_arm_vcpu_stopped(struct kvm_vcpu *vcpu); #define get_idreg_field_unsigned(kvm, id, fld) \ ({ \ - u64 __val = IDREG((kvm), SYS_##id); \ + u64 __val = kvm_read_vm_id_reg((kvm), SYS_##id); \ FIELD_GET(id##_##fld##_MASK, __val); \ }) diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h index b05bceca3385..c838309e4ec4 100644 --- a/arch/arm64/include/asm/kvm_hyp.h +++ b/arch/arm64/include/asm/kvm_hyp.h @@ -124,8 +124,8 @@ void __noreturn __hyp_do_panic(struct kvm_cpu_context *host_ctxt, u64 spsr, #endif #ifdef __KVM_NVHE_HYPERVISOR__ -void __pkvm_init_switch_pgd(phys_addr_t phys, unsigned long size, - phys_addr_t pgd, void *sp, void *cont_fn); +void __pkvm_init_switch_pgd(phys_addr_t pgd, unsigned long sp, + void (*fn)(void)); int __pkvm_init(phys_addr_t phys, unsigned long size, unsigned long nr_cpus, unsigned long *per_cpu_base, u32 hyp_va_bits); void __noreturn __host_enter(struct kvm_cpu_context *host_ctxt); diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index d5e48d870461..216ca424bb16 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -98,6 +98,7 @@ alternative_cb_end #include #include #include +#include void kvm_update_va_mask(struct alt_instr *alt, __le32 *origptr, __le32 *updptr, int nr_inst); @@ -165,6 +166,10 @@ int create_hyp_exec_mappings(phys_addr_t phys_addr, size_t size, int create_hyp_stack(phys_addr_t phys_addr, unsigned long *haddr); void __init free_hyp_pgds(void); +void kvm_stage2_unmap_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 size); +void kvm_stage2_flush_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, phys_addr_t end); +void kvm_stage2_wp_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, phys_addr_t end); + void stage2_unmap_vm(struct kvm *kvm); int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long type); void kvm_uninit_stage2_mmu(struct kvm *kvm); @@ -326,5 +331,26 @@ static inline struct kvm *kvm_s2_mmu_to_kvm(struct kvm_s2_mmu *mmu) { return container_of(mmu->arch, struct kvm, arch); } + +static inline u64 get_vmid(u64 vttbr) +{ + return (vttbr & VTTBR_VMID_MASK(kvm_get_vmid_bits())) >> + VTTBR_VMID_SHIFT; +} + +static inline bool kvm_s2_mmu_valid(struct kvm_s2_mmu *mmu) +{ + return !(mmu->tlb_vttbr & VTTBR_CNP_BIT); +} + +static inline bool kvm_is_nested_s2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu) +{ + /* + * Be careful, mmu may not be fully initialised so do look at + * *any* of its fields. + */ + return &kvm->arch.mmu != mmu; +} + #endif /* __ASSEMBLY__ */ #endif /* __ARM64_KVM_MMU_H__ */ diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h index 5e0ab0596246..5b06c31035a2 100644 --- a/arch/arm64/include/asm/kvm_nested.h +++ b/arch/arm64/include/asm/kvm_nested.h @@ -5,6 +5,7 @@ #include #include #include +#include static inline bool vcpu_has_nv(const struct kvm_vcpu *vcpu) { @@ -32,7 +33,7 @@ static inline u64 translate_tcr_el2_to_tcr_el1(u64 tcr) static inline u64 translate_cptr_el2_to_cpacr_el1(u64 cptr_el2) { - u64 cpacr_el1 = 0; + u64 cpacr_el1 = CPACR_ELx_RES1; if (cptr_el2 & CPTR_EL2_TTA) cpacr_el1 |= CPACR_ELx_TTA; @@ -41,6 +42,8 @@ static inline u64 translate_cptr_el2_to_cpacr_el1(u64 cptr_el2) if (!(cptr_el2 & CPTR_EL2_TZ)) cpacr_el1 |= CPACR_ELx_ZEN; + cpacr_el1 |= cptr_el2 & (CPTR_EL2_TCPAC | CPTR_EL2_TAM); + return cpacr_el1; } @@ -61,6 +64,125 @@ static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0) } extern bool forward_smc_trap(struct kvm_vcpu *vcpu); +extern void kvm_init_nested(struct kvm *kvm); +extern int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu); +extern void kvm_init_nested_s2_mmu(struct kvm_s2_mmu *mmu); +extern struct kvm_s2_mmu *lookup_s2_mmu(struct kvm_vcpu *vcpu); + +union tlbi_info; + +extern void kvm_s2_mmu_iterate_by_vmid(struct kvm *kvm, u16 vmid, + const union tlbi_info *info, + void (*)(struct kvm_s2_mmu *, + const union tlbi_info *)); +extern void kvm_vcpu_load_hw_mmu(struct kvm_vcpu *vcpu); +extern void kvm_vcpu_put_hw_mmu(struct kvm_vcpu *vcpu); + +struct kvm_s2_trans { + phys_addr_t output; + unsigned long block_size; + bool writable; + bool readable; + int level; + u32 esr; + u64 upper_attr; +}; + +static inline phys_addr_t kvm_s2_trans_output(struct kvm_s2_trans *trans) +{ + return trans->output; +} + +static inline unsigned long kvm_s2_trans_size(struct kvm_s2_trans *trans) +{ + return trans->block_size; +} + +static inline u32 kvm_s2_trans_esr(struct kvm_s2_trans *trans) +{ + return trans->esr; +} + +static inline bool kvm_s2_trans_readable(struct kvm_s2_trans *trans) +{ + return trans->readable; +} + +static inline bool kvm_s2_trans_writable(struct kvm_s2_trans *trans) +{ + return trans->writable; +} + +static inline bool kvm_s2_trans_executable(struct kvm_s2_trans *trans) +{ + return !(trans->upper_attr & BIT(54)); +} + +extern int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t gipa, + struct kvm_s2_trans *result); +extern int kvm_s2_handle_perm_fault(struct kvm_vcpu *vcpu, + struct kvm_s2_trans *trans); +extern int kvm_inject_s2_fault(struct kvm_vcpu *vcpu, u64 esr_el2); +extern void kvm_nested_s2_wp(struct kvm *kvm); +extern void kvm_nested_s2_unmap(struct kvm *kvm); +extern void kvm_nested_s2_flush(struct kvm *kvm); + +unsigned long compute_tlb_inval_range(struct kvm_s2_mmu *mmu, u64 val); + +static inline bool kvm_supported_tlbi_s1e1_op(struct kvm_vcpu *vpcu, u32 instr) +{ + struct kvm *kvm = vpcu->kvm; + u8 CRm = sys_reg_CRm(instr); + + if (!(sys_reg_Op0(instr) == TLBI_Op0 && + sys_reg_Op1(instr) == TLBI_Op1_EL1)) + return false; + + if (!(sys_reg_CRn(instr) == TLBI_CRn_XS || + (sys_reg_CRn(instr) == TLBI_CRn_nXS && + kvm_has_feat(kvm, ID_AA64ISAR1_EL1, XS, IMP)))) + return false; + + if (CRm == TLBI_CRm_nROS && + !kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, OS)) + return false; + + if ((CRm == TLBI_CRm_RIS || CRm == TLBI_CRm_ROS || + CRm == TLBI_CRm_RNS) && + !kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, RANGE)) + return false; + + return true; +} + +static inline bool kvm_supported_tlbi_s1e2_op(struct kvm_vcpu *vpcu, u32 instr) +{ + struct kvm *kvm = vpcu->kvm; + u8 CRm = sys_reg_CRm(instr); + + if (!(sys_reg_Op0(instr) == TLBI_Op0 && + sys_reg_Op1(instr) == TLBI_Op1_EL2)) + return false; + + if (!(sys_reg_CRn(instr) == TLBI_CRn_XS || + (sys_reg_CRn(instr) == TLBI_CRn_nXS && + kvm_has_feat(kvm, ID_AA64ISAR1_EL1, XS, IMP)))) + return false; + + if (CRm == TLBI_CRm_IPAIS || CRm == TLBI_CRm_IPAONS) + return false; + + if (CRm == TLBI_CRm_nROS && + !kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, OS)) + return false; + + if ((CRm == TLBI_CRm_RIS || CRm == TLBI_CRm_ROS || + CRm == TLBI_CRm_RNS) && + !kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, RANGE)) + return false; + + return true; +} int kvm_init_nv_sysregs(struct kvm *kvm); @@ -76,4 +198,11 @@ static inline bool kvm_auth_eretax(struct kvm_vcpu *vcpu, u64 *elr) } #endif +#define KVM_NV_GUEST_MAP_SZ (KVM_PGTABLE_PROT_SW1 | KVM_PGTABLE_PROT_SW0) + +static inline u64 kvm_encode_nested_level(struct kvm_s2_trans *trans) +{ + return FIELD_PREP(KVM_NV_GUEST_MAP_SZ, trans->level); +} + #endif /* __ARM64_KVM_NESTED_H */ diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 1b6e436dbb55..4a9ea103817e 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -654,6 +654,23 @@ #define OP_AT_S12E0W sys_insn(AT_Op0, 4, AT_CRn, 8, 7) /* TLBI instructions */ +#define TLBI_Op0 1 + +#define TLBI_Op1_EL1 0 /* Accessible from EL1 or higher */ +#define TLBI_Op1_EL2 4 /* Accessible from EL2 or higher */ + +#define TLBI_CRn_XS 8 /* Extra Slow (the common one) */ +#define TLBI_CRn_nXS 9 /* not Extra Slow (which nobody uses)*/ + +#define TLBI_CRm_IPAIS 0 /* S2 Inner-Shareable */ +#define TLBI_CRm_nROS 1 /* non-Range, Outer-Sharable */ +#define TLBI_CRm_RIS 2 /* Range, Inner-Sharable */ +#define TLBI_CRm_nRIS 3 /* non-Range, Inner-Sharable */ +#define TLBI_CRm_IPAONS 4 /* S2 Outer and Non-Shareable */ +#define TLBI_CRm_ROS 5 /* Range, Outer-Sharable */ +#define TLBI_CRm_RNS 6 /* Range, Non-Sharable */ +#define TLBI_CRm_nRNS 7 /* non-Range, Non-Sharable */ + #define OP_TLBI_VMALLE1OS sys_insn(1, 0, 8, 1, 0) #define OP_TLBI_VAE1OS sys_insn(1, 0, 8, 1, 1) #define OP_TLBI_ASIDE1OS sys_insn(1, 0, 8, 1, 2) diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 81496083c041..27de1dddb0ab 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -128,6 +128,7 @@ int main(void) DEFINE(VCPU_FAULT_DISR, offsetof(struct kvm_vcpu, arch.fault.disr_el1)); DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2)); DEFINE(CPU_USER_PT_REGS, offsetof(struct kvm_cpu_context, regs)); + DEFINE(CPU_ELR_EL2, offsetof(struct kvm_cpu_context, sys_regs[ELR_EL2])); DEFINE(CPU_RGSR_EL1, offsetof(struct kvm_cpu_context, sys_regs[RGSR_EL1])); DEFINE(CPU_GCR_EL1, offsetof(struct kvm_cpu_context, sys_regs[GCR_EL1])); DEFINE(CPU_APIAKEYLO_EL1, offsetof(struct kvm_cpu_context, sys_regs[APIAKEYLO_EL1])); diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c index 2da6d8634e40..ab202cd7ad3a 100644 --- a/arch/arm64/kernel/debug-monitors.c +++ b/arch/arm64/kernel/debug-monitors.c @@ -316,9 +316,7 @@ static int call_break_hook(struct pt_regs *regs, unsigned long esr) * entirely not preemptible, and we can use rcu list safely here. */ list_for_each_entry_rcu(hook, list, node) { - unsigned long comment = esr & ESR_ELx_BRK64_ISS_COMMENT_MASK; - - if ((comment & ~hook->mask) == hook->imm) + if ((esr_brk_comment(esr) & ~hook->mask) == hook->imm) fn = hook->fn; } diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 215e6d7f2df8..9e22683aa921 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -1105,8 +1105,6 @@ static struct break_hook ubsan_break_hook = { }; #endif -#define esr_comment(esr) ((esr) & ESR_ELx_BRK64_ISS_COMMENT_MASK) - /* * Initial handler for AArch64 BRK exceptions * This handler only used until debug_traps_init(). @@ -1115,15 +1113,15 @@ int __init early_brk64(unsigned long addr, unsigned long esr, struct pt_regs *regs) { #ifdef CONFIG_CFI_CLANG - if ((esr_comment(esr) & ~CFI_BRK_IMM_MASK) == CFI_BRK_IMM_BASE) + if (esr_is_cfi_brk(esr)) return cfi_handler(regs, esr) != DBG_HOOK_HANDLED; #endif #ifdef CONFIG_KASAN_SW_TAGS - if ((esr_comment(esr) & ~KASAN_BRK_MASK) == KASAN_BRK_IMM) + if ((esr_brk_comment(esr) & ~KASAN_BRK_MASK) == KASAN_BRK_IMM) return kasan_handler(regs, esr) != DBG_HOOK_HANDLED; #endif #ifdef CONFIG_UBSAN_TRAP - if ((esr_comment(esr) & ~UBSAN_BRK_MASK) == UBSAN_BRK_IMM) + if ((esr_brk_comment(esr) & ~UBSAN_BRK_MASK) == UBSAN_BRK_IMM) return ubsan_handler(regs, esr) != DBG_HOOK_HANDLED; #endif return bug_handler(regs, esr) != DBG_HOOK_HANDLED; diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 59716789fe0f..a7ca776b51ec 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -48,6 +48,15 @@ static enum kvm_mode kvm_mode = KVM_MODE_DEFAULT; +enum kvm_wfx_trap_policy { + KVM_WFX_NOTRAP_SINGLE_TASK, /* Default option */ + KVM_WFX_NOTRAP, + KVM_WFX_TRAP, +}; + +static enum kvm_wfx_trap_policy kvm_wfi_trap_policy __read_mostly = KVM_WFX_NOTRAP_SINGLE_TASK; +static enum kvm_wfx_trap_policy kvm_wfe_trap_policy __read_mostly = KVM_WFX_NOTRAP_SINGLE_TASK; + DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector); DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page); @@ -170,6 +179,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) mutex_unlock(&kvm->lock); #endif + kvm_init_nested(kvm); + ret = kvm_share_hyp(kvm, kvm + 1); if (ret) return ret; @@ -546,11 +557,32 @@ static void vcpu_set_pauth_traps(struct kvm_vcpu *vcpu) } } +static bool kvm_vcpu_should_clear_twi(struct kvm_vcpu *vcpu) +{ + if (unlikely(kvm_wfi_trap_policy != KVM_WFX_NOTRAP_SINGLE_TASK)) + return kvm_wfi_trap_policy == KVM_WFX_NOTRAP; + + return single_task_running() && + (atomic_read(&vcpu->arch.vgic_cpu.vgic_v3.its_vpe.vlpi_count) || + vcpu->kvm->arch.vgic.nassgireq); +} + +static bool kvm_vcpu_should_clear_twe(struct kvm_vcpu *vcpu) +{ + if (unlikely(kvm_wfe_trap_policy != KVM_WFX_NOTRAP_SINGLE_TASK)) + return kvm_wfe_trap_policy == KVM_WFX_NOTRAP; + + return single_task_running(); +} + void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { struct kvm_s2_mmu *mmu; int *last_ran; + if (vcpu_has_nv(vcpu)) + kvm_vcpu_load_hw_mmu(vcpu); + mmu = vcpu->arch.hw_mmu; last_ran = this_cpu_ptr(mmu->last_vcpu_ran); @@ -579,10 +611,15 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) if (kvm_arm_is_pvtime_enabled(&vcpu->arch)) kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu); - if (single_task_running()) - vcpu_clear_wfx_traps(vcpu); + if (kvm_vcpu_should_clear_twe(vcpu)) + vcpu->arch.hcr_el2 &= ~HCR_TWE; else - vcpu_set_wfx_traps(vcpu); + vcpu->arch.hcr_el2 |= HCR_TWE; + + if (kvm_vcpu_should_clear_twi(vcpu)) + vcpu->arch.hcr_el2 &= ~HCR_TWI; + else + vcpu->arch.hcr_el2 |= HCR_TWI; vcpu_set_pauth_traps(vcpu); @@ -601,6 +638,8 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_timer_vcpu_put(vcpu); kvm_vgic_put(vcpu); kvm_vcpu_pmu_restore_host(vcpu); + if (vcpu_has_nv(vcpu)) + kvm_vcpu_put_hw_mmu(vcpu); kvm_arm_vmid_clear_active(); vcpu_clear_on_unsupported_cpu(vcpu); @@ -797,7 +836,7 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu) * This needs to happen after NV has imposed its own restrictions on * the feature set */ - kvm_init_sysreg(vcpu); + kvm_calculate_traps(vcpu); ret = kvm_timer_enable(vcpu); if (ret) @@ -1099,7 +1138,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) vcpu_load(vcpu); - if (run->immediate_exit) { + if (!vcpu->wants_to_run) { ret = -EINTR; goto out; } @@ -1419,11 +1458,6 @@ static int kvm_vcpu_init_check_features(struct kvm_vcpu *vcpu, test_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, &features)) return -EINVAL; - /* Disallow NV+SVE for the time being */ - if (test_bit(KVM_ARM_VCPU_HAS_EL2, &features) && - test_bit(KVM_ARM_VCPU_SVE, &features)) - return -EINVAL; - if (!test_bit(KVM_ARM_VCPU_EL1_32BIT, &features)) return 0; @@ -1459,6 +1493,10 @@ static int kvm_setup_vcpu(struct kvm_vcpu *vcpu) if (kvm_vcpu_has_pmu(vcpu) && !kvm->arch.arm_pmu) ret = kvm_arm_set_default_pmu(kvm); + /* Prepare for nested if required */ + if (!ret && vcpu_has_nv(vcpu)) + ret = kvm_vcpu_init_nested(vcpu); + return ret; } @@ -2858,6 +2896,36 @@ static int __init early_kvm_mode_cfg(char *arg) } early_param("kvm-arm.mode", early_kvm_mode_cfg); +static int __init early_kvm_wfx_trap_policy_cfg(char *arg, enum kvm_wfx_trap_policy *p) +{ + if (!arg) + return -EINVAL; + + if (strcmp(arg, "trap") == 0) { + *p = KVM_WFX_TRAP; + return 0; + } + + if (strcmp(arg, "notrap") == 0) { + *p = KVM_WFX_NOTRAP; + return 0; + } + + return -EINVAL; +} + +static int __init early_kvm_wfi_trap_policy_cfg(char *arg) +{ + return early_kvm_wfx_trap_policy_cfg(arg, &kvm_wfi_trap_policy); +} +early_param("kvm-arm.wfi_trap_policy", early_kvm_wfi_trap_policy_cfg); + +static int __init early_kvm_wfe_trap_policy_cfg(char *arg) +{ + return early_kvm_wfx_trap_policy_cfg(arg, &kvm_wfe_trap_policy); +} +early_param("kvm-arm.wfe_trap_policy", early_kvm_wfe_trap_policy_cfg); + enum kvm_mode kvm_get_mode(void) { return kvm_mode; diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index 54090967a335..05166eccea0a 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -79,6 +79,12 @@ enum cgt_group_id { CGT_MDCR_E2TB, CGT_MDCR_TDCC, + CGT_CPACR_E0POE, + CGT_CPTR_TAM, + CGT_CPTR_TCPAC, + + CGT_HCRX_TCR2En, + /* * Anything after this point is a combination of coarse trap * controls, which must all be evaluated to decide what to do. @@ -89,6 +95,7 @@ enum cgt_group_id { CGT_HCR_TTLB_TTLBIS, CGT_HCR_TTLB_TTLBOS, CGT_HCR_TVM_TRVM, + CGT_HCR_TVM_TRVM_HCRX_TCR2En, CGT_HCR_TPU_TICAB, CGT_HCR_TPU_TOCU, CGT_HCR_NV1_nNV2_ENSCXT, @@ -106,6 +113,8 @@ enum cgt_group_id { CGT_CNTHCTL_EL1PCTEN = __COMPLEX_CONDITIONS__, CGT_CNTHCTL_EL1PTEN, + CGT_CPTR_TTA, + /* Must be last */ __NR_CGT_GROUP_IDS__ }; @@ -345,6 +354,30 @@ static const struct trap_bits coarse_trap_bits[] = { .mask = MDCR_EL2_TDCC, .behaviour = BEHAVE_FORWARD_ANY, }, + [CGT_CPACR_E0POE] = { + .index = CPTR_EL2, + .value = CPACR_ELx_E0POE, + .mask = CPACR_ELx_E0POE, + .behaviour = BEHAVE_FORWARD_ANY, + }, + [CGT_CPTR_TAM] = { + .index = CPTR_EL2, + .value = CPTR_EL2_TAM, + .mask = CPTR_EL2_TAM, + .behaviour = BEHAVE_FORWARD_ANY, + }, + [CGT_CPTR_TCPAC] = { + .index = CPTR_EL2, + .value = CPTR_EL2_TCPAC, + .mask = CPTR_EL2_TCPAC, + .behaviour = BEHAVE_FORWARD_ANY, + }, + [CGT_HCRX_TCR2En] = { + .index = HCRX_EL2, + .value = 0, + .mask = HCRX_EL2_TCR2En, + .behaviour = BEHAVE_FORWARD_ANY, + }, }; #define MCB(id, ...) \ @@ -359,6 +392,8 @@ static const enum cgt_group_id *coarse_control_combo[] = { MCB(CGT_HCR_TTLB_TTLBIS, CGT_HCR_TTLB, CGT_HCR_TTLBIS), MCB(CGT_HCR_TTLB_TTLBOS, CGT_HCR_TTLB, CGT_HCR_TTLBOS), MCB(CGT_HCR_TVM_TRVM, CGT_HCR_TVM, CGT_HCR_TRVM), + MCB(CGT_HCR_TVM_TRVM_HCRX_TCR2En, + CGT_HCR_TVM, CGT_HCR_TRVM, CGT_HCRX_TCR2En), MCB(CGT_HCR_TPU_TICAB, CGT_HCR_TPU, CGT_HCR_TICAB), MCB(CGT_HCR_TPU_TOCU, CGT_HCR_TPU, CGT_HCR_TOCU), MCB(CGT_HCR_NV1_nNV2_ENSCXT, CGT_HCR_NV1_nNV2, CGT_HCR_ENSCXT), @@ -410,12 +445,26 @@ static enum trap_behaviour check_cnthctl_el1pten(struct kvm_vcpu *vcpu) return BEHAVE_FORWARD_ANY; } +static enum trap_behaviour check_cptr_tta(struct kvm_vcpu *vcpu) +{ + u64 val = __vcpu_sys_reg(vcpu, CPTR_EL2); + + if (!vcpu_el2_e2h_is_set(vcpu)) + val = translate_cptr_el2_to_cpacr_el1(val); + + if (val & CPACR_ELx_TTA) + return BEHAVE_FORWARD_ANY; + + return BEHAVE_HANDLE_LOCALLY; +} + #define CCC(id, fn) \ [id - __COMPLEX_CONDITIONS__] = fn static const complex_condition_check ccc[] = { CCC(CGT_CNTHCTL_EL1PCTEN, check_cnthctl_el1pcten), CCC(CGT_CNTHCTL_EL1PTEN, check_cnthctl_el1pten), + CCC(CGT_CPTR_TTA, check_cptr_tta), }; /* @@ -622,6 +671,7 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = { SR_TRAP(SYS_MAIR_EL1, CGT_HCR_TVM_TRVM), SR_TRAP(SYS_AMAIR_EL1, CGT_HCR_TVM_TRVM), SR_TRAP(SYS_CONTEXTIDR_EL1, CGT_HCR_TVM_TRVM), + SR_TRAP(SYS_TCR2_EL1, CGT_HCR_TVM_TRVM_HCRX_TCR2En), SR_TRAP(SYS_DC_ZVA, CGT_HCR_TDZ), SR_TRAP(SYS_DC_GVA, CGT_HCR_TDZ), SR_TRAP(SYS_DC_GZVA, CGT_HCR_TDZ), @@ -1000,6 +1050,59 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = { SR_TRAP(SYS_TRBPTR_EL1, CGT_MDCR_E2TB), SR_TRAP(SYS_TRBSR_EL1, CGT_MDCR_E2TB), SR_TRAP(SYS_TRBTRG_EL1, CGT_MDCR_E2TB), + SR_TRAP(SYS_CPACR_EL1, CGT_CPTR_TCPAC), + SR_TRAP(SYS_AMUSERENR_EL0, CGT_CPTR_TAM), + SR_TRAP(SYS_AMCFGR_EL0, CGT_CPTR_TAM), + SR_TRAP(SYS_AMCGCR_EL0, CGT_CPTR_TAM), + SR_TRAP(SYS_AMCNTENCLR0_EL0, CGT_CPTR_TAM), + SR_TRAP(SYS_AMCNTENCLR1_EL0, CGT_CPTR_TAM), + SR_TRAP(SYS_AMCNTENSET0_EL0, CGT_CPTR_TAM), + SR_TRAP(SYS_AMCNTENSET1_EL0, CGT_CPTR_TAM), + SR_TRAP(SYS_AMCR_EL0, CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR0_EL0(0), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR0_EL0(1), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR0_EL0(2), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR0_EL0(3), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(0), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(1), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(2), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(3), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(4), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(5), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(6), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(7), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(8), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(9), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(10), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(11), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(12), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(13), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(14), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVCNTR1_EL0(15), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER0_EL0(0), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER0_EL0(1), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER0_EL0(2), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER0_EL0(3), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(0), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(1), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(2), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(3), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(4), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(5), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(6), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(7), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(8), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(9), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(10), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(11), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(12), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(13), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(14), CGT_CPTR_TAM), + SR_TRAP(SYS_AMEVTYPER1_EL0(15), CGT_CPTR_TAM), + SR_TRAP(SYS_POR_EL0, CGT_CPACR_E0POE), + /* op0=2, op1=1, and CRn<0b1000 */ + SR_RANGE_TRAP(sys_reg(2, 1, 0, 0, 0), + sys_reg(2, 1, 7, 15, 7), CGT_CPTR_TTA), SR_TRAP(SYS_CNTP_TVAL_EL0, CGT_CNTHCTL_EL1PTEN), SR_TRAP(SYS_CNTP_CVAL_EL0, CGT_CNTHCTL_EL1PTEN), SR_TRAP(SYS_CNTP_CTL_EL0, CGT_CNTHCTL_EL1PTEN), @@ -1071,6 +1174,7 @@ static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = { SR_FGT(SYS_TPIDRRO_EL0, HFGxTR, TPIDRRO_EL0, 1), SR_FGT(SYS_TPIDR_EL1, HFGxTR, TPIDR_EL1, 1), SR_FGT(SYS_TCR_EL1, HFGxTR, TCR_EL1, 1), + SR_FGT(SYS_TCR2_EL1, HFGxTR, TCR_EL1, 1), SR_FGT(SYS_SCXTNUM_EL0, HFGxTR, SCXTNUM_EL0, 1), SR_FGT(SYS_SCXTNUM_EL1, HFGxTR, SCXTNUM_EL1, 1), SR_FGT(SYS_SCTLR_EL1, HFGxTR, SCTLR_EL1, 1), diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c index 521b32868d0d..c53e5b14038d 100644 --- a/arch/arm64/kvm/fpsimd.c +++ b/arch/arm64/kvm/fpsimd.c @@ -178,7 +178,13 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu) if (guest_owns_fp_regs()) { if (vcpu_has_sve(vcpu)) { - __vcpu_sys_reg(vcpu, ZCR_EL1) = read_sysreg_el1(SYS_ZCR); + u64 zcr = read_sysreg_el1(SYS_ZCR); + + /* + * If the vCPU is in the hyp context then ZCR_EL1 is + * loaded with its vEL2 counterpart. + */ + __vcpu_sys_reg(vcpu, vcpu_sve_zcr_elx(vcpu)) = zcr; /* * Restore the VL that was saved when bound to the CPU, @@ -189,11 +195,14 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu) * Note that this means that at guest exit ZCR_EL1 is * not necessarily the same as on guest entry. * - * Restoring the VL isn't needed in VHE mode since - * ZCR_EL2 (accessed via ZCR_EL1) would fulfill the same - * role when doing the save from EL2. + * ZCR_EL2 holds the guest hypervisor's VL when running + * a nested guest, which could be smaller than the + * max for the vCPU. Similar to above, we first need to + * switch to a VL consistent with the layout of the + * vCPU's SVE state. KVM support for NV implies VHE, so + * using the ZCR_EL1 alias is safe. */ - if (!has_vhe()) + if (!has_vhe() || (vcpu_has_nv(vcpu) && !is_hyp_ctxt(vcpu))) sve_cond_update_zcr_vq(vcpu_sve_max_vq(vcpu) - 1, SYS_ZCR_EL1); } diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index b037f0a0e27e..d7c2990e7c9e 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -94,11 +94,19 @@ static int handle_smc(struct kvm_vcpu *vcpu) } /* - * Guest access to FP/ASIMD registers are routed to this handler only - * when the system doesn't support FP/ASIMD. + * This handles the cases where the system does not support FP/ASIMD or when + * we are running nested virtualization and the guest hypervisor is trapping + * FP/ASIMD accesses by its guest guest. + * + * All other handling of guest vs. host FP/ASIMD register state is handled in + * fixup_guest_exit(). */ -static int handle_no_fpsimd(struct kvm_vcpu *vcpu) +static int kvm_handle_fpasimd(struct kvm_vcpu *vcpu) { + if (guest_hyp_fpsimd_traps_enabled(vcpu)) + return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_esr(vcpu)); + + /* This is the case when the system doesn't support FP/ASIMD. */ kvm_inject_undefined(vcpu); return 1; } @@ -209,6 +217,9 @@ static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu) */ static int handle_sve(struct kvm_vcpu *vcpu) { + if (guest_hyp_sve_traps_enabled(vcpu)) + return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_esr(vcpu)); + kvm_inject_undefined(vcpu); return 1; } @@ -304,7 +315,7 @@ static exit_handle_fn arm_exit_handlers[] = { [ESR_ELx_EC_BREAKPT_LOW]= kvm_handle_guest_debug, [ESR_ELx_EC_BKPT32] = kvm_handle_guest_debug, [ESR_ELx_EC_BRK64] = kvm_handle_guest_debug, - [ESR_ELx_EC_FP_ASIMD] = handle_no_fpsimd, + [ESR_ELx_EC_FP_ASIMD] = kvm_handle_fpasimd, [ESR_ELx_EC_PAC] = kvm_handle_ptrauth, }; @@ -411,6 +422,20 @@ void handle_exit_early(struct kvm_vcpu *vcpu, int exception_index) kvm_handle_guest_serror(vcpu, kvm_vcpu_get_esr(vcpu)); } +static void print_nvhe_hyp_panic(const char *name, u64 panic_addr) +{ + kvm_err("nVHE hyp %s at: [<%016llx>] %pB!\n", name, panic_addr, + (void *)(panic_addr + kaslr_offset())); +} + +static void kvm_nvhe_report_cfi_failure(u64 panic_addr) +{ + print_nvhe_hyp_panic("CFI failure", panic_addr); + + if (IS_ENABLED(CONFIG_CFI_PERMISSIVE)) + kvm_err(" (CONFIG_CFI_PERMISSIVE ignored for hyp failures)\n"); +} + void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, u64 elr_virt, u64 elr_phys, u64 par, uintptr_t vcpu, @@ -423,7 +448,7 @@ void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, if (mode != PSR_MODE_EL2t && mode != PSR_MODE_EL2h) { kvm_err("Invalid host exception to nVHE hyp!\n"); } else if (ESR_ELx_EC(esr) == ESR_ELx_EC_BRK64 && - (esr & ESR_ELx_BRK64_ISS_COMMENT_MASK) == BUG_BRK_IMM) { + esr_brk_comment(esr) == BUG_BRK_IMM) { const char *file = NULL; unsigned int line = 0; @@ -439,11 +464,11 @@ void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, if (file) kvm_err("nVHE hyp BUG at: %s:%u!\n", file, line); else - kvm_err("nVHE hyp BUG at: [<%016llx>] %pB!\n", panic_addr, - (void *)(panic_addr + kaslr_offset())); + print_nvhe_hyp_panic("BUG", panic_addr); + } else if (IS_ENABLED(CONFIG_CFI_CLANG) && esr_is_cfi_brk(esr)) { + kvm_nvhe_report_cfi_failure(panic_addr); } else { - kvm_err("nVHE hyp panic at: [<%016llx>] %pB!\n", panic_addr, - (void *)(panic_addr + kaslr_offset())); + print_nvhe_hyp_panic("panic", panic_addr); } /* Dump the nVHE hypervisor backtrace */ diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S index f3aa7738b477..4433a234aa9b 100644 --- a/arch/arm64/kvm/hyp/entry.S +++ b/arch/arm64/kvm/hyp/entry.S @@ -83,6 +83,14 @@ alternative_else_nop_endif eret sb +SYM_INNER_LABEL(__guest_exit_restore_elr_and_panic, SYM_L_GLOBAL) + // x2-x29,lr: vcpu regs + // vcpu x0-x1 on the stack + + adr_this_cpu x0, kvm_hyp_ctxt, x1 + ldr x0, [x0, #CPU_ELR_EL2] + msr elr_el2, x0 + SYM_INNER_LABEL(__guest_exit_panic, SYM_L_GLOBAL) // x2-x29,lr: vcpu regs // vcpu x0-x1 on the stack diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h index 0c4de44534b7..f59ccfe11ab9 100644 --- a/arch/arm64/kvm/hyp/include/hyp/switch.h +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h @@ -314,11 +314,24 @@ static bool kvm_hyp_handle_mops(struct kvm_vcpu *vcpu, u64 *exit_code) static inline void __hyp_sve_restore_guest(struct kvm_vcpu *vcpu) { + /* + * The vCPU's saved SVE state layout always matches the max VL of the + * vCPU. Start off with the max VL so we can load the SVE state. + */ sve_cond_update_zcr_vq(vcpu_sve_max_vq(vcpu) - 1, SYS_ZCR_EL2); __sve_restore_state(vcpu_sve_pffr(vcpu), &vcpu->arch.ctxt.fp_regs.fpsr, true); - write_sysreg_el1(__vcpu_sys_reg(vcpu, ZCR_EL1), SYS_ZCR); + + /* + * The effective VL for a VM could differ from the max VL when running a + * nested guest, as the guest hypervisor could select a smaller VL. Slap + * that into hardware before wrapping up. + */ + if (vcpu_has_nv(vcpu) && !is_hyp_ctxt(vcpu)) + sve_cond_update_zcr_vq(__vcpu_sys_reg(vcpu, ZCR_EL2), SYS_ZCR_EL2); + + write_sysreg_el1(__vcpu_sys_reg(vcpu, vcpu_sve_zcr_elx(vcpu)), SYS_ZCR); } static inline void __hyp_sve_save_host(void) @@ -354,10 +367,19 @@ static bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code) /* Only handle traps the vCPU can support here: */ switch (esr_ec) { case ESR_ELx_EC_FP_ASIMD: + /* Forward traps to the guest hypervisor as required */ + if (guest_hyp_fpsimd_traps_enabled(vcpu)) + return false; break; + case ESR_ELx_EC_SYS64: + if (WARN_ON_ONCE(!is_hyp_ctxt(vcpu))) + return false; + fallthrough; case ESR_ELx_EC_SVE: if (!sve_guest) return false; + if (guest_hyp_sve_traps_enabled(vcpu)) + return false; break; default: return false; @@ -693,7 +715,7 @@ guest: static inline void __kvm_unexpected_el2_exception(void) { - extern char __guest_exit_panic[]; + extern char __guest_exit_restore_elr_and_panic[]; unsigned long addr, fixup; struct kvm_exception_table_entry *entry, *end; unsigned long elr_el2 = read_sysreg(elr_el2); @@ -715,7 +737,8 @@ static inline void __kvm_unexpected_el2_exception(void) } /* Trigger a panic after restoring the hyp context. */ - write_sysreg(__guest_exit_panic, elr_el2); + this_cpu_ptr(&kvm_hyp_ctxt)->sys_regs[ELR_EL2] = elr_el2; + write_sysreg(__guest_exit_restore_elr_and_panic, elr_el2); } #endif /* __ARM64_KVM_HYP_SWITCH_H__ */ diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h index 4be6a7fa0070..4c0fdabaf8ae 100644 --- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h +++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h @@ -55,6 +55,17 @@ static inline bool ctxt_has_s1pie(struct kvm_cpu_context *ctxt) return kvm_has_feat(kern_hyp_va(vcpu->kvm), ID_AA64MMFR3_EL1, S1PIE, IMP); } +static inline bool ctxt_has_tcrx(struct kvm_cpu_context *ctxt) +{ + struct kvm_vcpu *vcpu; + + if (!cpus_have_final_cap(ARM64_HAS_TCR2)) + return false; + + vcpu = ctxt_to_vcpu(ctxt); + return kvm_has_feat(kern_hyp_va(vcpu->kvm), ID_AA64MMFR3_EL1, TCRX, IMP); +} + static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt) { ctxt_sys_reg(ctxt, SCTLR_EL1) = read_sysreg_el1(SYS_SCTLR); @@ -62,8 +73,14 @@ static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt) ctxt_sys_reg(ctxt, TTBR0_EL1) = read_sysreg_el1(SYS_TTBR0); ctxt_sys_reg(ctxt, TTBR1_EL1) = read_sysreg_el1(SYS_TTBR1); ctxt_sys_reg(ctxt, TCR_EL1) = read_sysreg_el1(SYS_TCR); - if (cpus_have_final_cap(ARM64_HAS_TCR2)) + if (ctxt_has_tcrx(ctxt)) { ctxt_sys_reg(ctxt, TCR2_EL1) = read_sysreg_el1(SYS_TCR2); + + if (ctxt_has_s1pie(ctxt)) { + ctxt_sys_reg(ctxt, PIR_EL1) = read_sysreg_el1(SYS_PIR); + ctxt_sys_reg(ctxt, PIRE0_EL1) = read_sysreg_el1(SYS_PIRE0); + } + } ctxt_sys_reg(ctxt, ESR_EL1) = read_sysreg_el1(SYS_ESR); ctxt_sys_reg(ctxt, AFSR0_EL1) = read_sysreg_el1(SYS_AFSR0); ctxt_sys_reg(ctxt, AFSR1_EL1) = read_sysreg_el1(SYS_AFSR1); @@ -73,10 +90,6 @@ static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt) ctxt_sys_reg(ctxt, CONTEXTIDR_EL1) = read_sysreg_el1(SYS_CONTEXTIDR); ctxt_sys_reg(ctxt, AMAIR_EL1) = read_sysreg_el1(SYS_AMAIR); ctxt_sys_reg(ctxt, CNTKCTL_EL1) = read_sysreg_el1(SYS_CNTKCTL); - if (ctxt_has_s1pie(ctxt)) { - ctxt_sys_reg(ctxt, PIR_EL1) = read_sysreg_el1(SYS_PIR); - ctxt_sys_reg(ctxt, PIRE0_EL1) = read_sysreg_el1(SYS_PIRE0); - } ctxt_sys_reg(ctxt, PAR_EL1) = read_sysreg_par(); ctxt_sys_reg(ctxt, TPIDR_EL1) = read_sysreg(tpidr_el1); @@ -138,8 +151,14 @@ static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt) write_sysreg_el1(ctxt_sys_reg(ctxt, CPACR_EL1), SYS_CPACR); write_sysreg_el1(ctxt_sys_reg(ctxt, TTBR0_EL1), SYS_TTBR0); write_sysreg_el1(ctxt_sys_reg(ctxt, TTBR1_EL1), SYS_TTBR1); - if (cpus_have_final_cap(ARM64_HAS_TCR2)) + if (ctxt_has_tcrx(ctxt)) { write_sysreg_el1(ctxt_sys_reg(ctxt, TCR2_EL1), SYS_TCR2); + + if (ctxt_has_s1pie(ctxt)) { + write_sysreg_el1(ctxt_sys_reg(ctxt, PIR_EL1), SYS_PIR); + write_sysreg_el1(ctxt_sys_reg(ctxt, PIRE0_EL1), SYS_PIRE0); + } + } write_sysreg_el1(ctxt_sys_reg(ctxt, ESR_EL1), SYS_ESR); write_sysreg_el1(ctxt_sys_reg(ctxt, AFSR0_EL1), SYS_AFSR0); write_sysreg_el1(ctxt_sys_reg(ctxt, AFSR1_EL1), SYS_AFSR1); @@ -149,10 +168,6 @@ static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt) write_sysreg_el1(ctxt_sys_reg(ctxt, CONTEXTIDR_EL1), SYS_CONTEXTIDR); write_sysreg_el1(ctxt_sys_reg(ctxt, AMAIR_EL1), SYS_AMAIR); write_sysreg_el1(ctxt_sys_reg(ctxt, CNTKCTL_EL1), SYS_CNTKCTL); - if (ctxt_has_s1pie(ctxt)) { - write_sysreg_el1(ctxt_sys_reg(ctxt, PIR_EL1), SYS_PIR); - write_sysreg_el1(ctxt_sys_reg(ctxt, PIRE0_EL1), SYS_PIRE0); - } write_sysreg(ctxt_sys_reg(ctxt, PAR_EL1), par_el1); write_sysreg(ctxt_sys_reg(ctxt, TPIDR_EL1), tpidr_el1); diff --git a/arch/arm64/kvm/hyp/include/nvhe/ffa.h b/arch/arm64/kvm/hyp/include/nvhe/ffa.h index d9fd5e6c7d3c..146e0aebfa1c 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/ffa.h +++ b/arch/arm64/kvm/hyp/include/nvhe/ffa.h @@ -9,7 +9,7 @@ #include #define FFA_MIN_FUNC_NUM 0x60 -#define FFA_MAX_FUNC_NUM 0x7F +#define FFA_MAX_FUNC_NUM 0xFF int hyp_ffa_init(void *pages); bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id); diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile index 50fa0ffb6b7e..782b34b004be 100644 --- a/arch/arm64/kvm/hyp/nvhe/Makefile +++ b/arch/arm64/kvm/hyp/nvhe/Makefile @@ -89,9 +89,9 @@ quiet_cmd_hyprel = HYPREL $@ quiet_cmd_hypcopy = HYPCOPY $@ cmd_hypcopy = $(OBJCOPY) --prefix-symbols=__kvm_nvhe_ $< $@ -# Remove ftrace, Shadow Call Stack, and CFI CFLAGS. -# This is equivalent to the 'notrace', '__noscs', and '__nocfi' annotations. -KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) $(CC_FLAGS_CFI), $(KBUILD_CFLAGS)) +# Remove ftrace and Shadow Call Stack CFLAGS. +# This is equivalent to the 'notrace' and '__noscs' annotations. +KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS), $(KBUILD_CFLAGS)) # Starting from 13.0.0 llvm emits SHT_REL section '.llvm.call-graph-profile' # when profile optimization is applied. gen-hyprel does not support SHT_REL and # causes a build failure. Remove profile optimization flags. diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c index efb053af331c..e715c157c2c4 100644 --- a/arch/arm64/kvm/hyp/nvhe/ffa.c +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c @@ -67,6 +67,9 @@ struct kvm_ffa_buffers { */ static struct kvm_ffa_buffers hyp_buffers; static struct kvm_ffa_buffers host_buffers; +static u32 hyp_ffa_version; +static bool has_version_negotiated; +static hyp_spinlock_t version_lock; static void ffa_to_smccc_error(struct arm_smccc_res *res, u64 ffa_errno) { @@ -462,7 +465,7 @@ static __always_inline void do_ffa_mem_xfer(const u64 func_id, memcpy(buf, host_buffers.tx, fraglen); ep_mem_access = (void *)buf + - ffa_mem_desc_offset(buf, 0, FFA_VERSION_1_0); + ffa_mem_desc_offset(buf, 0, hyp_ffa_version); offset = ep_mem_access->composite_off; if (!offset || buf->ep_count != 1 || buf->sender_id != HOST_FFA_ID) { ret = FFA_RET_INVALID_PARAMETERS; @@ -541,7 +544,7 @@ static void do_ffa_mem_reclaim(struct arm_smccc_res *res, fraglen = res->a2; ep_mem_access = (void *)buf + - ffa_mem_desc_offset(buf, 0, FFA_VERSION_1_0); + ffa_mem_desc_offset(buf, 0, hyp_ffa_version); offset = ep_mem_access->composite_off; /* * We can trust the SPMD to get this right, but let's at least @@ -651,91 +654,10 @@ out_handled: return true; } -bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id) +static int hyp_ffa_post_init(void) { - struct arm_smccc_res res; - - /* - * There's no way we can tell what a non-standard SMC call might - * be up to. Ideally, we would terminate these here and return - * an error to the host, but sadly devices make use of custom - * firmware calls for things like power management, debugging, - * RNG access and crash reporting. - * - * Given that the architecture requires us to trust EL3 anyway, - * we forward unrecognised calls on under the assumption that - * the firmware doesn't expose a mechanism to access arbitrary - * non-secure memory. Short of a per-device table of SMCs, this - * is the best we can do. - */ - if (!is_ffa_call(func_id)) - return false; - - switch (func_id) { - case FFA_FEATURES: - if (!do_ffa_features(&res, host_ctxt)) - return false; - goto out_handled; - /* Memory management */ - case FFA_FN64_RXTX_MAP: - do_ffa_rxtx_map(&res, host_ctxt); - goto out_handled; - case FFA_RXTX_UNMAP: - do_ffa_rxtx_unmap(&res, host_ctxt); - goto out_handled; - case FFA_MEM_SHARE: - case FFA_FN64_MEM_SHARE: - do_ffa_mem_xfer(FFA_FN64_MEM_SHARE, &res, host_ctxt); - goto out_handled; - case FFA_MEM_RECLAIM: - do_ffa_mem_reclaim(&res, host_ctxt); - goto out_handled; - case FFA_MEM_LEND: - case FFA_FN64_MEM_LEND: - do_ffa_mem_xfer(FFA_FN64_MEM_LEND, &res, host_ctxt); - goto out_handled; - case FFA_MEM_FRAG_TX: - do_ffa_mem_frag_tx(&res, host_ctxt); - goto out_handled; - } - - if (ffa_call_supported(func_id)) - return false; /* Pass through */ - - ffa_to_smccc_error(&res, FFA_RET_NOT_SUPPORTED); -out_handled: - ffa_set_retval(host_ctxt, &res); - return true; -} - -int hyp_ffa_init(void *pages) -{ - struct arm_smccc_res res; size_t min_rxtx_sz; - void *tx, *rx; - - if (kvm_host_psci_config.smccc_version < ARM_SMCCC_VERSION_1_2) - return 0; - - arm_smccc_1_1_smc(FFA_VERSION, FFA_VERSION_1_0, 0, 0, 0, 0, 0, 0, &res); - if (res.a0 == FFA_RET_NOT_SUPPORTED) - return 0; - - /* - * Firmware returns the maximum supported version of the FF-A - * implementation. Check that the returned version is - * backwards-compatible with the hyp according to the rules in DEN0077A - * v1.1 REL0 13.2.1. - * - * Of course, things are never simple when dealing with firmware. v1.1 - * broke ABI with v1.0 on several structures, which is itself - * incompatible with the aforementioned versioning scheme. The - * expectation is that v1.x implementations that do not support the v1.0 - * ABI return NOT_SUPPORTED rather than a version number, according to - * DEN0077A v1.1 REL0 18.6.4. - */ - if (FFA_MAJOR_VERSION(res.a0) != 1) - return -EOPNOTSUPP; + struct arm_smccc_res res; arm_smccc_1_1_smc(FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0, &res); if (res.a0 != FFA_SUCCESS) @@ -766,6 +688,199 @@ int hyp_ffa_init(void *pages) if (min_rxtx_sz > PAGE_SIZE) return -EOPNOTSUPP; + return 0; +} + +static void do_ffa_version(struct arm_smccc_res *res, + struct kvm_cpu_context *ctxt) +{ + DECLARE_REG(u32, ffa_req_version, ctxt, 1); + + if (FFA_MAJOR_VERSION(ffa_req_version) != 1) { + res->a0 = FFA_RET_NOT_SUPPORTED; + return; + } + + hyp_spin_lock(&version_lock); + if (has_version_negotiated) { + res->a0 = hyp_ffa_version; + goto unlock; + } + + /* + * If the client driver tries to downgrade the version, we need to ask + * first if TEE supports it. + */ + if (FFA_MINOR_VERSION(ffa_req_version) < FFA_MINOR_VERSION(hyp_ffa_version)) { + arm_smccc_1_1_smc(FFA_VERSION, ffa_req_version, 0, + 0, 0, 0, 0, 0, + res); + if (res->a0 == FFA_RET_NOT_SUPPORTED) + goto unlock; + + hyp_ffa_version = ffa_req_version; + } + + if (hyp_ffa_post_init()) + res->a0 = FFA_RET_NOT_SUPPORTED; + else { + has_version_negotiated = true; + res->a0 = hyp_ffa_version; + } +unlock: + hyp_spin_unlock(&version_lock); +} + +static void do_ffa_part_get(struct arm_smccc_res *res, + struct kvm_cpu_context *ctxt) +{ + DECLARE_REG(u32, uuid0, ctxt, 1); + DECLARE_REG(u32, uuid1, ctxt, 2); + DECLARE_REG(u32, uuid2, ctxt, 3); + DECLARE_REG(u32, uuid3, ctxt, 4); + DECLARE_REG(u32, flags, ctxt, 5); + u32 count, partition_sz, copy_sz; + + hyp_spin_lock(&host_buffers.lock); + if (!host_buffers.rx) { + ffa_to_smccc_res(res, FFA_RET_BUSY); + goto out_unlock; + } + + arm_smccc_1_1_smc(FFA_PARTITION_INFO_GET, uuid0, uuid1, + uuid2, uuid3, flags, 0, 0, + res); + + if (res->a0 != FFA_SUCCESS) + goto out_unlock; + + count = res->a2; + if (!count) + goto out_unlock; + + if (hyp_ffa_version > FFA_VERSION_1_0) { + /* Get the number of partitions deployed in the system */ + if (flags & 0x1) + goto out_unlock; + + partition_sz = res->a3; + } else { + /* FFA_VERSION_1_0 lacks the size in the response */ + partition_sz = FFA_1_0_PARTITON_INFO_SZ; + } + + copy_sz = partition_sz * count; + if (copy_sz > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE) { + ffa_to_smccc_res(res, FFA_RET_ABORTED); + goto out_unlock; + } + + memcpy(host_buffers.rx, hyp_buffers.rx, copy_sz); +out_unlock: + hyp_spin_unlock(&host_buffers.lock); +} + +bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id) +{ + struct arm_smccc_res res; + + /* + * There's no way we can tell what a non-standard SMC call might + * be up to. Ideally, we would terminate these here and return + * an error to the host, but sadly devices make use of custom + * firmware calls for things like power management, debugging, + * RNG access and crash reporting. + * + * Given that the architecture requires us to trust EL3 anyway, + * we forward unrecognised calls on under the assumption that + * the firmware doesn't expose a mechanism to access arbitrary + * non-secure memory. Short of a per-device table of SMCs, this + * is the best we can do. + */ + if (!is_ffa_call(func_id)) + return false; + + if (!has_version_negotiated && func_id != FFA_VERSION) { + ffa_to_smccc_error(&res, FFA_RET_INVALID_PARAMETERS); + goto out_handled; + } + + switch (func_id) { + case FFA_FEATURES: + if (!do_ffa_features(&res, host_ctxt)) + return false; + goto out_handled; + /* Memory management */ + case FFA_FN64_RXTX_MAP: + do_ffa_rxtx_map(&res, host_ctxt); + goto out_handled; + case FFA_RXTX_UNMAP: + do_ffa_rxtx_unmap(&res, host_ctxt); + goto out_handled; + case FFA_MEM_SHARE: + case FFA_FN64_MEM_SHARE: + do_ffa_mem_xfer(FFA_FN64_MEM_SHARE, &res, host_ctxt); + goto out_handled; + case FFA_MEM_RECLAIM: + do_ffa_mem_reclaim(&res, host_ctxt); + goto out_handled; + case FFA_MEM_LEND: + case FFA_FN64_MEM_LEND: + do_ffa_mem_xfer(FFA_FN64_MEM_LEND, &res, host_ctxt); + goto out_handled; + case FFA_MEM_FRAG_TX: + do_ffa_mem_frag_tx(&res, host_ctxt); + goto out_handled; + case FFA_VERSION: + do_ffa_version(&res, host_ctxt); + goto out_handled; + case FFA_PARTITION_INFO_GET: + do_ffa_part_get(&res, host_ctxt); + goto out_handled; + } + + if (ffa_call_supported(func_id)) + return false; /* Pass through */ + + ffa_to_smccc_error(&res, FFA_RET_NOT_SUPPORTED); +out_handled: + ffa_set_retval(host_ctxt, &res); + return true; +} + +int hyp_ffa_init(void *pages) +{ + struct arm_smccc_res res; + void *tx, *rx; + + if (kvm_host_psci_config.smccc_version < ARM_SMCCC_VERSION_1_2) + return 0; + + arm_smccc_1_1_smc(FFA_VERSION, FFA_VERSION_1_1, 0, 0, 0, 0, 0, 0, &res); + if (res.a0 == FFA_RET_NOT_SUPPORTED) + return 0; + + /* + * Firmware returns the maximum supported version of the FF-A + * implementation. Check that the returned version is + * backwards-compatible with the hyp according to the rules in DEN0077A + * v1.1 REL0 13.2.1. + * + * Of course, things are never simple when dealing with firmware. v1.1 + * broke ABI with v1.0 on several structures, which is itself + * incompatible with the aforementioned versioning scheme. The + * expectation is that v1.x implementations that do not support the v1.0 + * ABI return NOT_SUPPORTED rather than a version number, according to + * DEN0077A v1.1 REL0 18.6.4. + */ + if (FFA_MAJOR_VERSION(res.a0) != 1) + return -EOPNOTSUPP; + + if (FFA_MINOR_VERSION(res.a0) < FFA_MINOR_VERSION(FFA_VERSION_1_1)) + hyp_ffa_version = res.a0; + else + hyp_ffa_version = FFA_VERSION_1_1; + tx = pages; pages += KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE; rx = pages; @@ -787,5 +902,6 @@ int hyp_ffa_init(void *pages) .lock = __HYP_SPIN_LOCK_UNLOCKED, }; + version_lock = __HYP_SPIN_LOCK_UNLOCKED; return 0; } diff --git a/arch/arm64/kvm/hyp/nvhe/gen-hyprel.c b/arch/arm64/kvm/hyp/nvhe/gen-hyprel.c index 6bc88a756cb7..b63f4e1c1033 100644 --- a/arch/arm64/kvm/hyp/nvhe/gen-hyprel.c +++ b/arch/arm64/kvm/hyp/nvhe/gen-hyprel.c @@ -50,6 +50,9 @@ #ifndef R_AARCH64_ABS64 #define R_AARCH64_ABS64 257 #endif +#ifndef R_AARCH64_ABS32 +#define R_AARCH64_ABS32 258 +#endif #ifndef R_AARCH64_PREL64 #define R_AARCH64_PREL64 260 #endif @@ -383,6 +386,9 @@ static void emit_rela_section(Elf64_Shdr *sh_rela) case R_AARCH64_ABS64: emit_rela_abs64(rela, sh_orig_name); break; + /* Allow 32-bit absolute relocation, for kCFI type hashes. */ + case R_AARCH64_ABS32: + break; /* Allow position-relative data relocations. */ case R_AARCH64_PREL64: case R_AARCH64_PREL32: diff --git a/arch/arm64/kvm/hyp/nvhe/host.S b/arch/arm64/kvm/hyp/nvhe/host.S index 135cfb294ee5..3d610fc51f4d 100644 --- a/arch/arm64/kvm/hyp/nvhe/host.S +++ b/arch/arm64/kvm/hyp/nvhe/host.S @@ -197,12 +197,6 @@ SYM_FUNC_END(__host_hvc) sub x0, sp, x0 // x0'' = sp' - x0' = (sp + x0) - sp = x0 sub sp, sp, x0 // sp'' = sp' - x0 = (sp + x0) - x0 = sp - /* If a guest is loaded, panic out of it. */ - stp x0, x1, [sp, #-16]! - get_loaded_vcpu x0, x1 - cbnz x0, __guest_exit_panic - add sp, sp, #16 - /* * The panic may not be clean if the exception is taken before the host * context has been saved by __host_exit or after the hyp context has diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-init.S b/arch/arm64/kvm/hyp/nvhe/hyp-init.S index 2994878d68ea..07120b37da35 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-init.S +++ b/arch/arm64/kvm/hyp/nvhe/hyp-init.S @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -265,33 +266,38 @@ alternative_else_nop_endif SYM_CODE_END(__kvm_handle_stub_hvc) -SYM_FUNC_START(__pkvm_init_switch_pgd) +/* + * void __pkvm_init_switch_pgd(phys_addr_t pgd, unsigned long sp, + * void (*fn)(void)); + * + * SYM_TYPED_FUNC_START() allows C to call this ID-mapped function indirectly + * using a physical pointer without triggering a kCFI failure. + */ +SYM_TYPED_FUNC_START(__pkvm_init_switch_pgd) /* Turn the MMU off */ pre_disable_mmu_workaround - mrs x2, sctlr_el2 - bic x3, x2, #SCTLR_ELx_M - msr sctlr_el2, x3 + mrs x3, sctlr_el2 + bic x4, x3, #SCTLR_ELx_M + msr sctlr_el2, x4 isb tlbi alle2 /* Install the new pgtables */ - ldr x3, [x0, #NVHE_INIT_PGD_PA] - phys_to_ttbr x4, x3 + phys_to_ttbr x5, x0 alternative_if ARM64_HAS_CNP - orr x4, x4, #TTBR_CNP_BIT + orr x5, x5, #TTBR_CNP_BIT alternative_else_nop_endif - msr ttbr0_el2, x4 + msr ttbr0_el2, x5 /* Set the new stack pointer */ - ldr x0, [x0, #NVHE_INIT_STACK_HYP_VA] - mov sp, x0 + mov sp, x1 /* And turn the MMU back on! */ dsb nsh isb - set_sctlr_el2 x2 - ret x1 + set_sctlr_el2 x3 + ret x2 SYM_FUNC_END(__pkvm_init_switch_pgd) .popsection diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c index f4350ba07b0b..174007f3fadd 100644 --- a/arch/arm64/kvm/hyp/nvhe/setup.c +++ b/arch/arm64/kvm/hyp/nvhe/setup.c @@ -339,7 +339,7 @@ int __pkvm_init(phys_addr_t phys, unsigned long size, unsigned long nr_cpus, { struct kvm_nvhe_init_params *params; void *virt = hyp_phys_to_virt(phys); - void (*fn)(phys_addr_t params_pa, void *finalize_fn_va); + typeof(__pkvm_init_switch_pgd) *fn; int ret; BUG_ON(kvm_check_pvm_sysreg_table()); @@ -363,7 +363,7 @@ int __pkvm_init(phys_addr_t phys, unsigned long size, unsigned long nr_cpus, /* Jump in the idmap page to switch to the new page-tables */ params = this_cpu_ptr(&kvm_init_params); fn = (typeof(fn))__hyp_pa(__pkvm_init_switch_pgd); - fn(__hyp_pa(params), __pkvm_init_finalise); + fn(params->pgd_pa, params->stack_hyp_va, __pkvm_init_finalise); unreachable(); } diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c index 8fbb6a2e0559..77010b76c150 100644 --- a/arch/arm64/kvm/hyp/vhe/switch.c +++ b/arch/arm64/kvm/hyp/vhe/switch.c @@ -65,6 +65,77 @@ static u64 __compute_hcr(struct kvm_vcpu *vcpu) return hcr | (__vcpu_sys_reg(vcpu, HCR_EL2) & ~NV_HCR_GUEST_EXCLUDE); } +static void __activate_cptr_traps(struct kvm_vcpu *vcpu) +{ + u64 cptr; + + /* + * With VHE (HCR.E2H == 1), accesses to CPACR_EL1 are routed to + * CPTR_EL2. In general, CPACR_EL1 has the same layout as CPTR_EL2, + * except for some missing controls, such as TAM. + * In this case, CPTR_EL2.TAM has the same position with or without + * VHE (HCR.E2H == 1) which allows us to use here the CPTR_EL2.TAM + * shift value for trapping the AMU accesses. + */ + u64 val = CPACR_ELx_TTA | CPTR_EL2_TAM; + + if (guest_owns_fp_regs()) { + val |= CPACR_ELx_FPEN; + if (vcpu_has_sve(vcpu)) + val |= CPACR_ELx_ZEN; + } else { + __activate_traps_fpsimd32(vcpu); + } + + if (!vcpu_has_nv(vcpu)) + goto write; + + /* + * The architecture is a bit crap (what a surprise): an EL2 guest + * writing to CPTR_EL2 via CPACR_EL1 can't set any of TCPAC or TTA, + * as they are RES0 in the guest's view. To work around it, trap the + * sucker using the very same bit it can't set... + */ + if (vcpu_el2_e2h_is_set(vcpu) && is_hyp_ctxt(vcpu)) + val |= CPTR_EL2_TCPAC; + + /* + * Layer the guest hypervisor's trap configuration on top of our own if + * we're in a nested context. + */ + if (is_hyp_ctxt(vcpu)) + goto write; + + cptr = vcpu_sanitised_cptr_el2(vcpu); + + /* + * Pay attention, there's some interesting detail here. + * + * The CPTR_EL2.xEN fields are 2 bits wide, although there are only two + * meaningful trap states when HCR_EL2.TGE = 0 (running a nested guest): + * + * - CPTR_EL2.xEN = x0, traps are enabled + * - CPTR_EL2.xEN = x1, traps are disabled + * + * In other words, bit[0] determines if guest accesses trap or not. In + * the interest of simplicity, clear the entire field if the guest + * hypervisor has traps enabled to dispel any illusion of something more + * complicated taking place. + */ + if (!(SYS_FIELD_GET(CPACR_ELx, FPEN, cptr) & BIT(0))) + val &= ~CPACR_ELx_FPEN; + if (!(SYS_FIELD_GET(CPACR_ELx, ZEN, cptr) & BIT(0))) + val &= ~CPACR_ELx_ZEN; + + if (kvm_has_feat(vcpu->kvm, ID_AA64MMFR3_EL1, S2POE, IMP)) + val |= cptr & CPACR_ELx_E0POE; + + val |= cptr & CPTR_EL2_TCPAC; + +write: + write_sysreg(val, cpacr_el1); +} + static void __activate_traps(struct kvm_vcpu *vcpu) { u64 val; @@ -91,30 +162,7 @@ static void __activate_traps(struct kvm_vcpu *vcpu) } } - val = read_sysreg(cpacr_el1); - val |= CPACR_ELx_TTA; - val &= ~(CPACR_ELx_ZEN | CPACR_ELx_SMEN); - - /* - * With VHE (HCR.E2H == 1), accesses to CPACR_EL1 are routed to - * CPTR_EL2. In general, CPACR_EL1 has the same layout as CPTR_EL2, - * except for some missing controls, such as TAM. - * In this case, CPTR_EL2.TAM has the same position with or without - * VHE (HCR.E2H == 1) which allows us to use here the CPTR_EL2.TAM - * shift value for trapping the AMU accesses. - */ - - val |= CPTR_EL2_TAM; - - if (guest_owns_fp_regs()) { - if (vcpu_has_sve(vcpu)) - val |= CPACR_ELx_ZEN; - } else { - val &= ~CPACR_ELx_FPEN; - __activate_traps_fpsimd32(vcpu); - } - - write_sysreg(val, cpacr_el1); + __activate_cptr_traps(vcpu); write_sysreg(__this_cpu_read(kvm_hyp_vector), vbar_el1); } @@ -266,10 +314,111 @@ static void kvm_hyp_save_fpsimd_host(struct kvm_vcpu *vcpu) __fpsimd_save_state(*host_data_ptr(fpsimd_state)); } +static bool kvm_hyp_handle_tlbi_el2(struct kvm_vcpu *vcpu, u64 *exit_code) +{ + int ret = -EINVAL; + u32 instr; + u64 val; + + /* + * Ideally, we would never trap on EL2 S1 TLB invalidations using + * the EL1 instructions when the guest's HCR_EL2.{E2H,TGE}=={1,1}. + * But "thanks" to FEAT_NV2, we don't trap writes to HCR_EL2, + * meaning that we can't track changes to the virtual TGE bit. So we + * have to leave HCR_EL2.TTLB set on the host. Oopsie... + * + * Try and handle these invalidation as quickly as possible, without + * fully exiting. Note that we don't need to consider any forwarding + * here, as having E2H+TGE set is the very definition of being + * InHost. + * + * For the lesser hypervisors out there that have failed to get on + * with the VHE program, we can also handle the nVHE style of EL2 + * invalidation. + */ + if (!(is_hyp_ctxt(vcpu))) + return false; + + instr = esr_sys64_to_sysreg(kvm_vcpu_get_esr(vcpu)); + val = vcpu_get_reg(vcpu, kvm_vcpu_sys_get_rt(vcpu)); + + if ((kvm_supported_tlbi_s1e1_op(vcpu, instr) && + vcpu_el2_e2h_is_set(vcpu) && vcpu_el2_tge_is_set(vcpu)) || + kvm_supported_tlbi_s1e2_op (vcpu, instr)) + ret = __kvm_tlbi_s1e2(NULL, val, instr); + + if (ret) + return false; + + __kvm_skip_instr(vcpu); + + return true; +} + +static bool kvm_hyp_handle_cpacr_el1(struct kvm_vcpu *vcpu, u64 *exit_code) +{ + u64 esr = kvm_vcpu_get_esr(vcpu); + int rt; + + if (!is_hyp_ctxt(vcpu) || esr_sys64_to_sysreg(esr) != SYS_CPACR_EL1) + return false; + + rt = kvm_vcpu_sys_get_rt(vcpu); + + if ((esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ) { + vcpu_set_reg(vcpu, rt, __vcpu_sys_reg(vcpu, CPTR_EL2)); + } else { + vcpu_write_sys_reg(vcpu, vcpu_get_reg(vcpu, rt), CPTR_EL2); + __activate_cptr_traps(vcpu); + } + + __kvm_skip_instr(vcpu); + + return true; +} + +static bool kvm_hyp_handle_zcr_el2(struct kvm_vcpu *vcpu, u64 *exit_code) +{ + u32 sysreg = esr_sys64_to_sysreg(kvm_vcpu_get_esr(vcpu)); + + if (!vcpu_has_nv(vcpu)) + return false; + + if (sysreg != SYS_ZCR_EL2) + return false; + + if (guest_owns_fp_regs()) + return false; + + /* + * ZCR_EL2 traps are handled in the slow path, with the expectation + * that the guest's FP context has already been loaded onto the CPU. + * + * Load the guest's FP context and unconditionally forward to the + * slow path for handling (i.e. return false). + */ + kvm_hyp_handle_fpsimd(vcpu, exit_code); + return false; +} + +static bool kvm_hyp_handle_sysreg_vhe(struct kvm_vcpu *vcpu, u64 *exit_code) +{ + if (kvm_hyp_handle_tlbi_el2(vcpu, exit_code)) + return true; + + if (kvm_hyp_handle_cpacr_el1(vcpu, exit_code)) + return true; + + if (kvm_hyp_handle_zcr_el2(vcpu, exit_code)) + return true; + + return kvm_hyp_handle_sysreg(vcpu, exit_code); +} + static const exit_handler_fn hyp_exit_handlers[] = { [0 ... ESR_ELx_EC_MAX] = NULL, [ESR_ELx_EC_CP15_32] = kvm_hyp_handle_cp15_32, - [ESR_ELx_EC_SYS64] = kvm_hyp_handle_sysreg, + [ESR_ELx_EC_SYS64] = kvm_hyp_handle_sysreg_vhe, [ESR_ELx_EC_SVE] = kvm_hyp_handle_fpsimd, [ESR_ELx_EC_FP_ASIMD] = kvm_hyp_handle_fpsimd, [ESR_ELx_EC_IABT_LOW] = kvm_hyp_handle_iabt_low, @@ -388,7 +537,7 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu) return ret; } -static void __hyp_call_panic(u64 spsr, u64 elr, u64 par) +static void __noreturn __hyp_call_panic(u64 spsr, u64 elr, u64 par) { struct kvm_cpu_context *host_ctxt; struct kvm_vcpu *vcpu; @@ -413,7 +562,6 @@ void __noreturn hyp_panic(void) u64 par = read_sysreg_par(); __hyp_call_panic(spsr, elr, par); - unreachable(); } asmlinkage void kvm_unexpected_el2_exception(void) diff --git a/arch/arm64/kvm/hyp/vhe/tlb.c b/arch/arm64/kvm/hyp/vhe/tlb.c index 5fa0359f3a87..3d50a1bd2bdb 100644 --- a/arch/arm64/kvm/hyp/vhe/tlb.c +++ b/arch/arm64/kvm/hyp/vhe/tlb.c @@ -219,3 +219,150 @@ void __kvm_flush_vm_context(void) __tlbi(alle1is); dsb(ish); } + +/* + * TLB invalidation emulation for NV. For any given instruction, we + * perform the following transformtions: + * + * - a TLBI targeting EL2 S1 is remapped to EL1 S1 + * - a non-shareable TLBI is upgraded to being inner-shareable + * - an outer-shareable TLBI is also mapped to inner-shareable + * - an nXS TLBI is upgraded to XS + */ +int __kvm_tlbi_s1e2(struct kvm_s2_mmu *mmu, u64 va, u64 sys_encoding) +{ + struct tlb_inv_context cxt; + int ret = 0; + + /* + * The guest will have provided its own DSB ISHST before trapping. + * If it hasn't, that's its own problem, and we won't paper over it + * (plus, there is plenty of extra synchronisation before we even + * get here...). + */ + + if (mmu) + enter_vmid_context(mmu, &cxt); + + switch (sys_encoding) { + case OP_TLBI_ALLE2: + case OP_TLBI_ALLE2IS: + case OP_TLBI_ALLE2OS: + case OP_TLBI_VMALLE1: + case OP_TLBI_VMALLE1IS: + case OP_TLBI_VMALLE1OS: + case OP_TLBI_ALLE2NXS: + case OP_TLBI_ALLE2ISNXS: + case OP_TLBI_ALLE2OSNXS: + case OP_TLBI_VMALLE1NXS: + case OP_TLBI_VMALLE1ISNXS: + case OP_TLBI_VMALLE1OSNXS: + __tlbi(vmalle1is); + break; + case OP_TLBI_VAE2: + case OP_TLBI_VAE2IS: + case OP_TLBI_VAE2OS: + case OP_TLBI_VAE1: + case OP_TLBI_VAE1IS: + case OP_TLBI_VAE1OS: + case OP_TLBI_VAE2NXS: + case OP_TLBI_VAE2ISNXS: + case OP_TLBI_VAE2OSNXS: + case OP_TLBI_VAE1NXS: + case OP_TLBI_VAE1ISNXS: + case OP_TLBI_VAE1OSNXS: + __tlbi(vae1is, va); + break; + case OP_TLBI_VALE2: + case OP_TLBI_VALE2IS: + case OP_TLBI_VALE2OS: + case OP_TLBI_VALE1: + case OP_TLBI_VALE1IS: + case OP_TLBI_VALE1OS: + case OP_TLBI_VALE2NXS: + case OP_TLBI_VALE2ISNXS: + case OP_TLBI_VALE2OSNXS: + case OP_TLBI_VALE1NXS: + case OP_TLBI_VALE1ISNXS: + case OP_TLBI_VALE1OSNXS: + __tlbi(vale1is, va); + break; + case OP_TLBI_ASIDE1: + case OP_TLBI_ASIDE1IS: + case OP_TLBI_ASIDE1OS: + case OP_TLBI_ASIDE1NXS: + case OP_TLBI_ASIDE1ISNXS: + case OP_TLBI_ASIDE1OSNXS: + __tlbi(aside1is, va); + break; + case OP_TLBI_VAAE1: + case OP_TLBI_VAAE1IS: + case OP_TLBI_VAAE1OS: + case OP_TLBI_VAAE1NXS: + case OP_TLBI_VAAE1ISNXS: + case OP_TLBI_VAAE1OSNXS: + __tlbi(vaae1is, va); + break; + case OP_TLBI_VAALE1: + case OP_TLBI_VAALE1IS: + case OP_TLBI_VAALE1OS: + case OP_TLBI_VAALE1NXS: + case OP_TLBI_VAALE1ISNXS: + case OP_TLBI_VAALE1OSNXS: + __tlbi(vaale1is, va); + break; + case OP_TLBI_RVAE2: + case OP_TLBI_RVAE2IS: + case OP_TLBI_RVAE2OS: + case OP_TLBI_RVAE1: + case OP_TLBI_RVAE1IS: + case OP_TLBI_RVAE1OS: + case OP_TLBI_RVAE2NXS: + case OP_TLBI_RVAE2ISNXS: + case OP_TLBI_RVAE2OSNXS: + case OP_TLBI_RVAE1NXS: + case OP_TLBI_RVAE1ISNXS: + case OP_TLBI_RVAE1OSNXS: + __tlbi(rvae1is, va); + break; + case OP_TLBI_RVALE2: + case OP_TLBI_RVALE2IS: + case OP_TLBI_RVALE2OS: + case OP_TLBI_RVALE1: + case OP_TLBI_RVALE1IS: + case OP_TLBI_RVALE1OS: + case OP_TLBI_RVALE2NXS: + case OP_TLBI_RVALE2ISNXS: + case OP_TLBI_RVALE2OSNXS: + case OP_TLBI_RVALE1NXS: + case OP_TLBI_RVALE1ISNXS: + case OP_TLBI_RVALE1OSNXS: + __tlbi(rvale1is, va); + break; + case OP_TLBI_RVAAE1: + case OP_TLBI_RVAAE1IS: + case OP_TLBI_RVAAE1OS: + case OP_TLBI_RVAAE1NXS: + case OP_TLBI_RVAAE1ISNXS: + case OP_TLBI_RVAAE1OSNXS: + __tlbi(rvaae1is, va); + break; + case OP_TLBI_RVAALE1: + case OP_TLBI_RVAALE1IS: + case OP_TLBI_RVAALE1OS: + case OP_TLBI_RVAALE1NXS: + case OP_TLBI_RVAALE1ISNXS: + case OP_TLBI_RVAALE1OSNXS: + __tlbi(rvaale1is, va); + break; + default: + ret = -EINVAL; + } + dsb(ish); + isb(); + + if (mmu) + exit_vmid_context(&cxt); + + return ret; +} diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 8bcab0cc3fe9..6981b1bc0946 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -328,18 +328,23 @@ static void __unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 may_block)); } -static void unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 size) +void kvm_stage2_unmap_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 size) { __unmap_stage2_range(mmu, start, size, true); } +void kvm_stage2_flush_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, phys_addr_t end) +{ + stage2_apply_range_resched(mmu, addr, end, kvm_pgtable_stage2_flush); +} + static void stage2_flush_memslot(struct kvm *kvm, struct kvm_memory_slot *memslot) { phys_addr_t addr = memslot->base_gfn << PAGE_SHIFT; phys_addr_t end = addr + PAGE_SIZE * memslot->npages; - stage2_apply_range_resched(&kvm->arch.mmu, addr, end, kvm_pgtable_stage2_flush); + kvm_stage2_flush_range(&kvm->arch.mmu, addr, end); } /** @@ -362,6 +367,8 @@ static void stage2_flush_vm(struct kvm *kvm) kvm_for_each_memslot(memslot, bkt, slots) stage2_flush_memslot(kvm, memslot); + kvm_nested_s2_flush(kvm); + write_unlock(&kvm->mmu_lock); srcu_read_unlock(&kvm->srcu, idx); } @@ -855,21 +862,9 @@ static struct kvm_pgtable_mm_ops kvm_s2_mm_ops = { .icache_inval_pou = invalidate_icache_guest_page, }; -/** - * kvm_init_stage2_mmu - Initialise a S2 MMU structure - * @kvm: The pointer to the KVM structure - * @mmu: The pointer to the s2 MMU structure - * @type: The machine type of the virtual machine - * - * Allocates only the stage-2 HW PGD level table(s). - * Note we don't need locking here as this is only called when the VM is - * created, which can only be done once. - */ -int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long type) +static int kvm_init_ipa_range(struct kvm_s2_mmu *mmu, unsigned long type) { u32 kvm_ipa_limit = get_kvm_ipa_limit(); - int cpu, err; - struct kvm_pgtable *pgt; u64 mmfr0, mmfr1; u32 phys_shift; @@ -896,11 +891,51 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1); mmu->vtcr = kvm_get_vtcr(mmfr0, mmfr1, phys_shift); + return 0; +} + +/** + * kvm_init_stage2_mmu - Initialise a S2 MMU structure + * @kvm: The pointer to the KVM structure + * @mmu: The pointer to the s2 MMU structure + * @type: The machine type of the virtual machine + * + * Allocates only the stage-2 HW PGD level table(s). + * Note we don't need locking here as this is only called in two cases: + * + * - when the VM is created, which can't race against anything + * + * - when secondary kvm_s2_mmu structures are initialised for NV + * guests, and the caller must hold kvm->lock as this is called on a + * per-vcpu basis. + */ +int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long type) +{ + int cpu, err; + struct kvm_pgtable *pgt; + + /* + * If we already have our page tables in place, and that the + * MMU context is the canonical one, we have a bug somewhere, + * as this is only supposed to ever happen once per VM. + * + * Otherwise, we're building nested page tables, and that's + * probably because userspace called KVM_ARM_VCPU_INIT more + * than once on the same vcpu. Since that's actually legal, + * don't kick a fuss and leave gracefully. + */ if (mmu->pgt != NULL) { + if (kvm_is_nested_s2_mmu(kvm, mmu)) + return 0; + kvm_err("kvm_arch already initialized?\n"); return -EINVAL; } + err = kvm_init_ipa_range(mmu, type); + if (err) + return err; + pgt = kzalloc(sizeof(*pgt), GFP_KERNEL_ACCOUNT); if (!pgt) return -ENOMEM; @@ -925,6 +960,10 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t mmu->pgt = pgt; mmu->pgd_phys = __pa(pgt->pgd); + + if (kvm_is_nested_s2_mmu(kvm, mmu)) + kvm_init_nested_s2_mmu(mmu); + return 0; out_destroy_pgtable: @@ -976,7 +1015,7 @@ static void stage2_unmap_memslot(struct kvm *kvm, if (!(vma->vm_flags & VM_PFNMAP)) { gpa_t gpa = addr + (vm_start - memslot->userspace_addr); - unmap_stage2_range(&kvm->arch.mmu, gpa, vm_end - vm_start); + kvm_stage2_unmap_range(&kvm->arch.mmu, gpa, vm_end - vm_start); } hva = vm_end; } while (hva < reg_end); @@ -1003,6 +1042,8 @@ void stage2_unmap_vm(struct kvm *kvm) kvm_for_each_memslot(memslot, bkt, slots) stage2_unmap_memslot(kvm, memslot); + kvm_nested_s2_unmap(kvm); + write_unlock(&kvm->mmu_lock); mmap_read_unlock(current->mm); srcu_read_unlock(&kvm->srcu, idx); @@ -1102,12 +1143,12 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa, } /** - * stage2_wp_range() - write protect stage2 memory region range + * kvm_stage2_wp_range() - write protect stage2 memory region range * @mmu: The KVM stage-2 MMU pointer * @addr: Start address of range * @end: End address of range */ -static void stage2_wp_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, phys_addr_t end) +void kvm_stage2_wp_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, phys_addr_t end) { stage2_apply_range_resched(mmu, addr, end, kvm_pgtable_stage2_wrprotect); } @@ -1138,7 +1179,8 @@ static void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot) end = (memslot->base_gfn + memslot->npages) << PAGE_SHIFT; write_lock(&kvm->mmu_lock); - stage2_wp_range(&kvm->arch.mmu, start, end); + kvm_stage2_wp_range(&kvm->arch.mmu, start, end); + kvm_nested_s2_wp(kvm); write_unlock(&kvm->mmu_lock); kvm_flush_remote_tlbs_memslot(kvm, memslot); } @@ -1192,7 +1234,7 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm, lockdep_assert_held_write(&kvm->mmu_lock); - stage2_wp_range(&kvm->arch.mmu, start, end); + kvm_stage2_wp_range(&kvm->arch.mmu, start, end); /* * Eager-splitting is done when manual-protect is set. We @@ -1204,6 +1246,8 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm, */ if (kvm_dirty_log_manual_protect_and_init_set(kvm)) kvm_mmu_split_huge_pages(kvm, start, end); + + kvm_nested_s2_wp(kvm); } static void kvm_send_hwpoison_signal(unsigned long address, short lsb) @@ -1375,6 +1419,7 @@ static bool kvm_vma_mte_allowed(struct vm_area_struct *vma) } static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, + struct kvm_s2_trans *nested, struct kvm_memory_slot *memslot, unsigned long hva, bool fault_is_perm) { @@ -1383,6 +1428,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, bool exec_fault, mte_allowed; bool device = false, vfio_allow_any_uc = false; unsigned long mmu_seq; + phys_addr_t ipa = fault_ipa; struct kvm *kvm = vcpu->kvm; struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache; struct vm_area_struct *vma; @@ -1466,10 +1512,38 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, } vma_pagesize = 1UL << vma_shift; + + if (nested) { + unsigned long max_map_size; + + max_map_size = force_pte ? PAGE_SIZE : PUD_SIZE; + + ipa = kvm_s2_trans_output(nested); + + /* + * If we're about to create a shadow stage 2 entry, then we + * can only create a block mapping if the guest stage 2 page + * table uses at least as big a mapping. + */ + max_map_size = min(kvm_s2_trans_size(nested), max_map_size); + + /* + * Be careful that if the mapping size falls between + * two host sizes, take the smallest of the two. + */ + if (max_map_size >= PMD_SIZE && max_map_size < PUD_SIZE) + max_map_size = PMD_SIZE; + else if (max_map_size >= PAGE_SIZE && max_map_size < PMD_SIZE) + max_map_size = PAGE_SIZE; + + force_pte = (max_map_size == PAGE_SIZE); + vma_pagesize = min(vma_pagesize, (long)max_map_size); + } + if (vma_pagesize == PMD_SIZE || vma_pagesize == PUD_SIZE) fault_ipa &= ~(vma_pagesize - 1); - gfn = fault_ipa >> PAGE_SHIFT; + gfn = ipa >> PAGE_SHIFT; mte_allowed = kvm_vma_mte_allowed(vma); vfio_allow_any_uc = vma->vm_flags & VM_ALLOW_ANY_UNCACHED; @@ -1520,6 +1594,25 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, if (exec_fault && device) return -ENOEXEC; + /* + * Potentially reduce shadow S2 permissions to match the guest's own + * S2. For exec faults, we'd only reach this point if the guest + * actually allowed it (see kvm_s2_handle_perm_fault). + * + * Also encode the level of the original translation in the SW bits + * of the leaf entry as a proxy for the span of that translation. + * This will be retrieved on TLB invalidation from the guest and + * used to limit the invalidation scope if a TTL hint or a range + * isn't provided. + */ + if (nested) { + writable &= kvm_s2_trans_writable(nested); + if (!kvm_s2_trans_readable(nested)) + prot &= ~KVM_PGTABLE_PROT_R; + + prot |= kvm_encode_nested_level(nested); + } + read_lock(&kvm->mmu_lock); pgt = vcpu->arch.hw_mmu->pgt; if (mmu_invalidate_retry(kvm, mmu_seq)) { @@ -1566,7 +1659,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, prot |= KVM_PGTABLE_PROT_NORMAL_NC; else prot |= KVM_PGTABLE_PROT_DEVICE; - } else if (cpus_have_final_cap(ARM64_HAS_CACHE_DIC)) { + } else if (cpus_have_final_cap(ARM64_HAS_CACHE_DIC) && + (!nested || kvm_s2_trans_executable(nested))) { prot |= KVM_PGTABLE_PROT_X; } @@ -1575,14 +1669,21 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, * permissions only if vma_pagesize equals fault_granule. Otherwise, * kvm_pgtable_stage2_map() should be called to change block size. */ - if (fault_is_perm && vma_pagesize == fault_granule) + if (fault_is_perm && vma_pagesize == fault_granule) { + /* + * Drop the SW bits in favour of those stored in the + * PTE, which will be preserved. + */ + prot &= ~KVM_NV_GUEST_MAP_SZ; ret = kvm_pgtable_stage2_relax_perms(pgt, fault_ipa, prot); - else + } else { ret = kvm_pgtable_stage2_map(pgt, fault_ipa, vma_pagesize, __pfn_to_phys(pfn), prot, memcache, KVM_PGTABLE_WALK_HANDLE_FAULT | KVM_PGTABLE_WALK_SHARED); + } + out_unlock: read_unlock(&kvm->mmu_lock); @@ -1626,8 +1727,10 @@ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa) */ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) { + struct kvm_s2_trans nested_trans, *nested = NULL; unsigned long esr; - phys_addr_t fault_ipa; + phys_addr_t fault_ipa; /* The address we faulted on */ + phys_addr_t ipa; /* Always the IPA in the L1 guest phys space */ struct kvm_memory_slot *memslot; unsigned long hva; bool is_iabt, write_fault, writable; @@ -1636,7 +1739,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) esr = kvm_vcpu_get_esr(vcpu); - fault_ipa = kvm_vcpu_get_fault_ipa(vcpu); + ipa = fault_ipa = kvm_vcpu_get_fault_ipa(vcpu); is_iabt = kvm_vcpu_trap_is_iabt(vcpu); if (esr_fsc_is_translation_fault(esr)) { @@ -1686,7 +1789,42 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) idx = srcu_read_lock(&vcpu->kvm->srcu); - gfn = fault_ipa >> PAGE_SHIFT; + /* + * We may have faulted on a shadow stage 2 page table if we are + * running a nested guest. In this case, we have to resolve the L2 + * IPA to the L1 IPA first, before knowing what kind of memory should + * back the L1 IPA. + * + * If the shadow stage 2 page table walk faults, then we simply inject + * this to the guest and carry on. + * + * If there are no shadow S2 PTs because S2 is disabled, there is + * nothing to walk and we treat it as a 1:1 before going through the + * canonical translation. + */ + if (kvm_is_nested_s2_mmu(vcpu->kvm,vcpu->arch.hw_mmu) && + vcpu->arch.hw_mmu->nested_stage2_enabled) { + u32 esr; + + ret = kvm_walk_nested_s2(vcpu, fault_ipa, &nested_trans); + if (ret) { + esr = kvm_s2_trans_esr(&nested_trans); + kvm_inject_s2_fault(vcpu, esr); + goto out_unlock; + } + + ret = kvm_s2_handle_perm_fault(vcpu, &nested_trans); + if (ret) { + esr = kvm_s2_trans_esr(&nested_trans); + kvm_inject_s2_fault(vcpu, esr); + goto out_unlock; + } + + ipa = kvm_s2_trans_output(&nested_trans); + nested = &nested_trans; + } + + gfn = ipa >> PAGE_SHIFT; memslot = gfn_to_memslot(vcpu->kvm, gfn); hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable); write_fault = kvm_is_write_fault(vcpu); @@ -1730,13 +1868,13 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) * faulting VA. This is always 12 bits, irrespective * of the page size. */ - fault_ipa |= kvm_vcpu_get_hfar(vcpu) & ((1 << 12) - 1); - ret = io_mem_abort(vcpu, fault_ipa); + ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0); + ret = io_mem_abort(vcpu, ipa); goto out_unlock; } /* Userspace should not be able to register out-of-bounds IPAs */ - VM_BUG_ON(fault_ipa >= kvm_phys_size(vcpu->arch.hw_mmu)); + VM_BUG_ON(ipa >= kvm_phys_size(vcpu->arch.hw_mmu)); if (esr_fsc_is_access_flag_fault(esr)) { handle_access_fault(vcpu, fault_ipa); @@ -1744,7 +1882,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) goto out_unlock; } - ret = user_mem_abort(vcpu, fault_ipa, memslot, hva, + ret = user_mem_abort(vcpu, fault_ipa, nested, memslot, hva, esr_fsc_is_permission_fault(esr)); if (ret == 0) ret = 1; @@ -1767,6 +1905,7 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range) (range->end - range->start) << PAGE_SHIFT, range->may_block); + kvm_nested_s2_unmap(kvm); return false; } @@ -1780,6 +1919,10 @@ bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) return kvm_pgtable_stage2_test_clear_young(kvm->arch.mmu.pgt, range->start << PAGE_SHIFT, size, true); + /* + * TODO: Handle nested_mmu structures here using the reverse mapping in + * a later version of patch series. + */ } bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) @@ -2022,11 +2165,6 @@ void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) { } -void kvm_arch_flush_shadow_all(struct kvm *kvm) -{ - kvm_uninit_stage2_mmu(kvm); -} - void kvm_arch_flush_shadow_memslot(struct kvm *kvm, struct kvm_memory_slot *slot) { @@ -2034,7 +2172,8 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm, phys_addr_t size = slot->npages << PAGE_SHIFT; write_lock(&kvm->mmu_lock); - unmap_stage2_range(&kvm->arch.mmu, gpa, size); + kvm_stage2_unmap_range(&kvm->arch.mmu, gpa, size); + kvm_nested_s2_unmap(kvm); write_unlock(&kvm->mmu_lock); } diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index bae8536cbf00..de789e0f1ae9 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -4,10 +4,13 @@ * Author: Jintack Lim */ +#include #include #include +#include #include +#include #include #include @@ -16,6 +19,779 @@ /* Protection against the sysreg repainting madness... */ #define NV_FTR(r, f) ID_AA64##r##_EL1_##f +/* + * Ratio of live shadow S2 MMU per vcpu. This is a trade-off between + * memory usage and potential number of different sets of S2 PTs in + * the guests. Running out of S2 MMUs only affects performance (we + * will invalidate them more often). + */ +#define S2_MMU_PER_VCPU 2 + +void kvm_init_nested(struct kvm *kvm) +{ + kvm->arch.nested_mmus = NULL; + kvm->arch.nested_mmus_size = 0; +} + +static int init_nested_s2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu) +{ + /* + * We only initialise the IPA range on the canonical MMU, which + * defines the contract between KVM and userspace on where the + * "hardware" is in the IPA space. This affects the validity of MMIO + * exits forwarded to userspace, for example. + * + * For nested S2s, we use the PARange as exposed to the guest, as it + * is allowed to use it at will to expose whatever memory map it + * wants to its own guests as it would be on real HW. + */ + return kvm_init_stage2_mmu(kvm, mmu, kvm_get_pa_bits(kvm)); +} + +int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm = vcpu->kvm; + struct kvm_s2_mmu *tmp; + int num_mmus, ret = 0; + + /* + * Let's treat memory allocation failures as benign: If we fail to + * allocate anything, return an error and keep the allocated array + * alive. Userspace may try to recover by intializing the vcpu + * again, and there is no reason to affect the whole VM for this. + */ + num_mmus = atomic_read(&kvm->online_vcpus) * S2_MMU_PER_VCPU; + tmp = kvrealloc(kvm->arch.nested_mmus, + size_mul(sizeof(*kvm->arch.nested_mmus), kvm->arch.nested_mmus_size), + size_mul(sizeof(*kvm->arch.nested_mmus), num_mmus), + GFP_KERNEL_ACCOUNT | __GFP_ZERO); + if (!tmp) + return -ENOMEM; + + /* + * If we went through a realocation, adjust the MMU back-pointers in + * the previously initialised kvm_pgtable structures. + */ + if (kvm->arch.nested_mmus != tmp) + for (int i = 0; i < kvm->arch.nested_mmus_size; i++) + tmp[i].pgt->mmu = &tmp[i]; + + for (int i = kvm->arch.nested_mmus_size; !ret && i < num_mmus; i++) + ret = init_nested_s2_mmu(kvm, &tmp[i]); + + if (ret) { + for (int i = kvm->arch.nested_mmus_size; i < num_mmus; i++) + kvm_free_stage2_pgd(&tmp[i]); + + return ret; + } + + kvm->arch.nested_mmus_size = num_mmus; + kvm->arch.nested_mmus = tmp; + + return 0; +} + +struct s2_walk_info { + int (*read_desc)(phys_addr_t pa, u64 *desc, void *data); + void *data; + u64 baddr; + unsigned int max_oa_bits; + unsigned int pgshift; + unsigned int sl; + unsigned int t0sz; + bool be; +}; + +static unsigned int ps_to_output_size(unsigned int ps) +{ + switch (ps) { + case 0: return 32; + case 1: return 36; + case 2: return 40; + case 3: return 42; + case 4: return 44; + case 5: + default: + return 48; + } +} + +static u32 compute_fsc(int level, u32 fsc) +{ + return fsc | (level & 0x3); +} + +static int esr_s2_fault(struct kvm_vcpu *vcpu, int level, u32 fsc) +{ + u32 esr; + + esr = kvm_vcpu_get_esr(vcpu) & ~ESR_ELx_FSC; + esr |= compute_fsc(level, fsc); + return esr; +} + +static int get_ia_size(struct s2_walk_info *wi) +{ + return 64 - wi->t0sz; +} + +static int check_base_s2_limits(struct s2_walk_info *wi, + int level, int input_size, int stride) +{ + int start_size, ia_size; + + ia_size = get_ia_size(wi); + + /* Check translation limits */ + switch (BIT(wi->pgshift)) { + case SZ_64K: + if (level == 0 || (level == 1 && ia_size <= 42)) + return -EFAULT; + break; + case SZ_16K: + if (level == 0 || (level == 1 && ia_size <= 40)) + return -EFAULT; + break; + case SZ_4K: + if (level < 0 || (level == 0 && ia_size <= 42)) + return -EFAULT; + break; + } + + /* Check input size limits */ + if (input_size > ia_size) + return -EFAULT; + + /* Check number of entries in starting level table */ + start_size = input_size - ((3 - level) * stride + wi->pgshift); + if (start_size < 1 || start_size > stride + 4) + return -EFAULT; + + return 0; +} + +/* Check if output is within boundaries */ +static int check_output_size(struct s2_walk_info *wi, phys_addr_t output) +{ + unsigned int output_size = wi->max_oa_bits; + + if (output_size != 48 && (output & GENMASK_ULL(47, output_size))) + return -1; + + return 0; +} + +/* + * This is essentially a C-version of the pseudo code from the ARM ARM + * AArch64.TranslationTableWalk function. I strongly recommend looking at + * that pseudocode in trying to understand this. + * + * Must be called with the kvm->srcu read lock held + */ +static int walk_nested_s2_pgd(phys_addr_t ipa, + struct s2_walk_info *wi, struct kvm_s2_trans *out) +{ + int first_block_level, level, stride, input_size, base_lower_bound; + phys_addr_t base_addr; + unsigned int addr_top, addr_bottom; + u64 desc; /* page table entry */ + int ret; + phys_addr_t paddr; + + switch (BIT(wi->pgshift)) { + default: + case SZ_64K: + case SZ_16K: + level = 3 - wi->sl; + first_block_level = 2; + break; + case SZ_4K: + level = 2 - wi->sl; + first_block_level = 1; + break; + } + + stride = wi->pgshift - 3; + input_size = get_ia_size(wi); + if (input_size > 48 || input_size < 25) + return -EFAULT; + + ret = check_base_s2_limits(wi, level, input_size, stride); + if (WARN_ON(ret)) + return ret; + + base_lower_bound = 3 + input_size - ((3 - level) * stride + + wi->pgshift); + base_addr = wi->baddr & GENMASK_ULL(47, base_lower_bound); + + if (check_output_size(wi, base_addr)) { + out->esr = compute_fsc(level, ESR_ELx_FSC_ADDRSZ); + return 1; + } + + addr_top = input_size - 1; + + while (1) { + phys_addr_t index; + + addr_bottom = (3 - level) * stride + wi->pgshift; + index = (ipa & GENMASK_ULL(addr_top, addr_bottom)) + >> (addr_bottom - 3); + + paddr = base_addr | index; + ret = wi->read_desc(paddr, &desc, wi->data); + if (ret < 0) + return ret; + + /* + * Handle reversedescriptors if endianness differs between the + * host and the guest hypervisor. + */ + if (wi->be) + desc = be64_to_cpu((__force __be64)desc); + else + desc = le64_to_cpu((__force __le64)desc); + + /* Check for valid descriptor at this point */ + if (!(desc & 1) || ((desc & 3) == 1 && level == 3)) { + out->esr = compute_fsc(level, ESR_ELx_FSC_FAULT); + out->upper_attr = desc; + return 1; + } + + /* We're at the final level or block translation level */ + if ((desc & 3) == 1 || level == 3) + break; + + if (check_output_size(wi, desc)) { + out->esr = compute_fsc(level, ESR_ELx_FSC_ADDRSZ); + out->upper_attr = desc; + return 1; + } + + base_addr = desc & GENMASK_ULL(47, wi->pgshift); + + level += 1; + addr_top = addr_bottom - 1; + } + + if (level < first_block_level) { + out->esr = compute_fsc(level, ESR_ELx_FSC_FAULT); + out->upper_attr = desc; + return 1; + } + + /* + * We don't use the contiguous bit in the stage-2 ptes, so skip check + * for misprogramming of the contiguous bit. + */ + + if (check_output_size(wi, desc)) { + out->esr = compute_fsc(level, ESR_ELx_FSC_ADDRSZ); + out->upper_attr = desc; + return 1; + } + + if (!(desc & BIT(10))) { + out->esr = compute_fsc(level, ESR_ELx_FSC_ACCESS); + out->upper_attr = desc; + return 1; + } + + /* Calculate and return the result */ + paddr = (desc & GENMASK_ULL(47, addr_bottom)) | + (ipa & GENMASK_ULL(addr_bottom - 1, 0)); + out->output = paddr; + out->block_size = 1UL << ((3 - level) * stride + wi->pgshift); + out->readable = desc & (0b01 << 6); + out->writable = desc & (0b10 << 6); + out->level = level; + out->upper_attr = desc & GENMASK_ULL(63, 52); + return 0; +} + +static int read_guest_s2_desc(phys_addr_t pa, u64 *desc, void *data) +{ + struct kvm_vcpu *vcpu = data; + + return kvm_read_guest(vcpu->kvm, pa, desc, sizeof(*desc)); +} + +static void vtcr_to_walk_info(u64 vtcr, struct s2_walk_info *wi) +{ + wi->t0sz = vtcr & TCR_EL2_T0SZ_MASK; + + switch (vtcr & VTCR_EL2_TG0_MASK) { + case VTCR_EL2_TG0_4K: + wi->pgshift = 12; break; + case VTCR_EL2_TG0_16K: + wi->pgshift = 14; break; + case VTCR_EL2_TG0_64K: + default: /* IMPDEF: treat any other value as 64k */ + wi->pgshift = 16; break; + } + + wi->sl = FIELD_GET(VTCR_EL2_SL0_MASK, vtcr); + /* Global limit for now, should eventually be per-VM */ + wi->max_oa_bits = min(get_kvm_ipa_limit(), + ps_to_output_size(FIELD_GET(VTCR_EL2_PS_MASK, vtcr))); +} + +int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t gipa, + struct kvm_s2_trans *result) +{ + u64 vtcr = vcpu_read_sys_reg(vcpu, VTCR_EL2); + struct s2_walk_info wi; + int ret; + + result->esr = 0; + + if (!vcpu_has_nv(vcpu)) + return 0; + + wi.read_desc = read_guest_s2_desc; + wi.data = vcpu; + wi.baddr = vcpu_read_sys_reg(vcpu, VTTBR_EL2); + + vtcr_to_walk_info(vtcr, &wi); + + wi.be = vcpu_read_sys_reg(vcpu, SCTLR_EL2) & SCTLR_ELx_EE; + + ret = walk_nested_s2_pgd(gipa, &wi, result); + if (ret) + result->esr |= (kvm_vcpu_get_esr(vcpu) & ~ESR_ELx_FSC); + + return ret; +} + +static unsigned int ttl_to_size(u8 ttl) +{ + int level = ttl & 3; + int gran = (ttl >> 2) & 3; + unsigned int max_size = 0; + + switch (gran) { + case TLBI_TTL_TG_4K: + switch (level) { + case 0: + break; + case 1: + max_size = SZ_1G; + break; + case 2: + max_size = SZ_2M; + break; + case 3: + max_size = SZ_4K; + break; + } + break; + case TLBI_TTL_TG_16K: + switch (level) { + case 0: + case 1: + break; + case 2: + max_size = SZ_32M; + break; + case 3: + max_size = SZ_16K; + break; + } + break; + case TLBI_TTL_TG_64K: + switch (level) { + case 0: + case 1: + /* No 52bit IPA support */ + break; + case 2: + max_size = SZ_512M; + break; + case 3: + max_size = SZ_64K; + break; + } + break; + default: /* No size information */ + break; + } + + return max_size; +} + +/* + * Compute the equivalent of the TTL field by parsing the shadow PT. The + * granule size is extracted from the cached VTCR_EL2.TG0 while the level is + * retrieved from first entry carrying the level as a tag. + */ +static u8 get_guest_mapping_ttl(struct kvm_s2_mmu *mmu, u64 addr) +{ + u64 tmp, sz = 0, vtcr = mmu->tlb_vtcr; + kvm_pte_t pte; + u8 ttl, level; + + lockdep_assert_held_write(&kvm_s2_mmu_to_kvm(mmu)->mmu_lock); + + switch (vtcr & VTCR_EL2_TG0_MASK) { + case VTCR_EL2_TG0_4K: + ttl = (TLBI_TTL_TG_4K << 2); + break; + case VTCR_EL2_TG0_16K: + ttl = (TLBI_TTL_TG_16K << 2); + break; + case VTCR_EL2_TG0_64K: + default: /* IMPDEF: treat any other value as 64k */ + ttl = (TLBI_TTL_TG_64K << 2); + break; + } + + tmp = addr; + +again: + /* Iteratively compute the block sizes for a particular granule size */ + switch (vtcr & VTCR_EL2_TG0_MASK) { + case VTCR_EL2_TG0_4K: + if (sz < SZ_4K) sz = SZ_4K; + else if (sz < SZ_2M) sz = SZ_2M; + else if (sz < SZ_1G) sz = SZ_1G; + else sz = 0; + break; + case VTCR_EL2_TG0_16K: + if (sz < SZ_16K) sz = SZ_16K; + else if (sz < SZ_32M) sz = SZ_32M; + else sz = 0; + break; + case VTCR_EL2_TG0_64K: + default: /* IMPDEF: treat any other value as 64k */ + if (sz < SZ_64K) sz = SZ_64K; + else if (sz < SZ_512M) sz = SZ_512M; + else sz = 0; + break; + } + + if (sz == 0) + return 0; + + tmp &= ~(sz - 1); + if (kvm_pgtable_get_leaf(mmu->pgt, tmp, &pte, NULL)) + goto again; + if (!(pte & PTE_VALID)) + goto again; + level = FIELD_GET(KVM_NV_GUEST_MAP_SZ, pte); + if (!level) + goto again; + + ttl |= level; + + /* + * We now have found some level information in the shadow S2. Check + * that the resulting range is actually including the original IPA. + */ + sz = ttl_to_size(ttl); + if (addr < (tmp + sz)) + return ttl; + + return 0; +} + +unsigned long compute_tlb_inval_range(struct kvm_s2_mmu *mmu, u64 val) +{ + struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu); + unsigned long max_size; + u8 ttl; + + ttl = FIELD_GET(TLBI_TTL_MASK, val); + + if (!ttl || !kvm_has_feat(kvm, ID_AA64MMFR2_EL1, TTL, IMP)) { + /* No TTL, check the shadow S2 for a hint */ + u64 addr = (val & GENMASK_ULL(35, 0)) << 12; + ttl = get_guest_mapping_ttl(mmu, addr); + } + + max_size = ttl_to_size(ttl); + + if (!max_size) { + /* Compute the maximum extent of the invalidation */ + switch (mmu->tlb_vtcr & VTCR_EL2_TG0_MASK) { + case VTCR_EL2_TG0_4K: + max_size = SZ_1G; + break; + case VTCR_EL2_TG0_16K: + max_size = SZ_32M; + break; + case VTCR_EL2_TG0_64K: + default: /* IMPDEF: treat any other value as 64k */ + /* + * No, we do not support 52bit IPA in nested yet. Once + * we do, this should be 4TB. + */ + max_size = SZ_512M; + break; + } + } + + WARN_ON(!max_size); + return max_size; +} + +/* + * We can have multiple *different* MMU contexts with the same VMID: + * + * - S2 being enabled or not, hence differing by the HCR_EL2.VM bit + * + * - Multiple vcpus using private S2s (huh huh...), hence differing by the + * VBBTR_EL2.BADDR address + * + * - A combination of the above... + * + * We can always identify which MMU context to pick at run-time. However, + * TLB invalidation involving a VMID must take action on all the TLBs using + * this particular VMID. This translates into applying the same invalidation + * operation to all the contexts that are using this VMID. Moar phun! + */ +void kvm_s2_mmu_iterate_by_vmid(struct kvm *kvm, u16 vmid, + const union tlbi_info *info, + void (*tlbi_callback)(struct kvm_s2_mmu *, + const union tlbi_info *)) +{ + write_lock(&kvm->mmu_lock); + + for (int i = 0; i < kvm->arch.nested_mmus_size; i++) { + struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; + + if (!kvm_s2_mmu_valid(mmu)) + continue; + + if (vmid == get_vmid(mmu->tlb_vttbr)) + tlbi_callback(mmu, info); + } + + write_unlock(&kvm->mmu_lock); +} + +struct kvm_s2_mmu *lookup_s2_mmu(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm = vcpu->kvm; + bool nested_stage2_enabled; + u64 vttbr, vtcr, hcr; + + lockdep_assert_held_write(&kvm->mmu_lock); + + vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2); + vtcr = vcpu_read_sys_reg(vcpu, VTCR_EL2); + hcr = vcpu_read_sys_reg(vcpu, HCR_EL2); + + nested_stage2_enabled = hcr & HCR_VM; + + /* Don't consider the CnP bit for the vttbr match */ + vttbr &= ~VTTBR_CNP_BIT; + + /* + * Two possibilities when looking up a S2 MMU context: + * + * - either S2 is enabled in the guest, and we need a context that is + * S2-enabled and matches the full VTTBR (VMID+BADDR) and VTCR, + * which makes it safe from a TLB conflict perspective (a broken + * guest won't be able to generate them), + * + * - or S2 is disabled, and we need a context that is S2-disabled + * and matches the VMID only, as all TLBs are tagged by VMID even + * if S2 translation is disabled. + */ + for (int i = 0; i < kvm->arch.nested_mmus_size; i++) { + struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; + + if (!kvm_s2_mmu_valid(mmu)) + continue; + + if (nested_stage2_enabled && + mmu->nested_stage2_enabled && + vttbr == mmu->tlb_vttbr && + vtcr == mmu->tlb_vtcr) + return mmu; + + if (!nested_stage2_enabled && + !mmu->nested_stage2_enabled && + get_vmid(vttbr) == get_vmid(mmu->tlb_vttbr)) + return mmu; + } + return NULL; +} + +static struct kvm_s2_mmu *get_s2_mmu_nested(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm = vcpu->kvm; + struct kvm_s2_mmu *s2_mmu; + int i; + + lockdep_assert_held_write(&vcpu->kvm->mmu_lock); + + s2_mmu = lookup_s2_mmu(vcpu); + if (s2_mmu) + goto out; + + /* + * Make sure we don't always search from the same point, or we + * will always reuse a potentially active context, leaving + * free contexts unused. + */ + for (i = kvm->arch.nested_mmus_next; + i < (kvm->arch.nested_mmus_size + kvm->arch.nested_mmus_next); + i++) { + s2_mmu = &kvm->arch.nested_mmus[i % kvm->arch.nested_mmus_size]; + + if (atomic_read(&s2_mmu->refcnt) == 0) + break; + } + BUG_ON(atomic_read(&s2_mmu->refcnt)); /* We have struct MMUs to spare */ + + /* Set the scene for the next search */ + kvm->arch.nested_mmus_next = (i + 1) % kvm->arch.nested_mmus_size; + + /* Clear the old state */ + if (kvm_s2_mmu_valid(s2_mmu)) + kvm_stage2_unmap_range(s2_mmu, 0, kvm_phys_size(s2_mmu)); + + /* + * The virtual VMID (modulo CnP) will be used as a key when matching + * an existing kvm_s2_mmu. + * + * We cache VTCR at allocation time, once and for all. It'd be great + * if the guest didn't screw that one up, as this is not very + * forgiving... + */ + s2_mmu->tlb_vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2) & ~VTTBR_CNP_BIT; + s2_mmu->tlb_vtcr = vcpu_read_sys_reg(vcpu, VTCR_EL2); + s2_mmu->nested_stage2_enabled = vcpu_read_sys_reg(vcpu, HCR_EL2) & HCR_VM; + +out: + atomic_inc(&s2_mmu->refcnt); + return s2_mmu; +} + +void kvm_init_nested_s2_mmu(struct kvm_s2_mmu *mmu) +{ + /* CnP being set denotes an invalid entry */ + mmu->tlb_vttbr = VTTBR_CNP_BIT; + mmu->nested_stage2_enabled = false; + atomic_set(&mmu->refcnt, 0); +} + +void kvm_vcpu_load_hw_mmu(struct kvm_vcpu *vcpu) +{ + if (is_hyp_ctxt(vcpu)) { + vcpu->arch.hw_mmu = &vcpu->kvm->arch.mmu; + } else { + write_lock(&vcpu->kvm->mmu_lock); + vcpu->arch.hw_mmu = get_s2_mmu_nested(vcpu); + write_unlock(&vcpu->kvm->mmu_lock); + } +} + +void kvm_vcpu_put_hw_mmu(struct kvm_vcpu *vcpu) +{ + if (kvm_is_nested_s2_mmu(vcpu->kvm, vcpu->arch.hw_mmu)) { + atomic_dec(&vcpu->arch.hw_mmu->refcnt); + vcpu->arch.hw_mmu = NULL; + } +} + +/* + * Returns non-zero if permission fault is handled by injecting it to the next + * level hypervisor. + */ +int kvm_s2_handle_perm_fault(struct kvm_vcpu *vcpu, struct kvm_s2_trans *trans) +{ + bool forward_fault = false; + + trans->esr = 0; + + if (!kvm_vcpu_trap_is_permission_fault(vcpu)) + return 0; + + if (kvm_vcpu_trap_is_iabt(vcpu)) { + forward_fault = !kvm_s2_trans_executable(trans); + } else { + bool write_fault = kvm_is_write_fault(vcpu); + + forward_fault = ((write_fault && !trans->writable) || + (!write_fault && !trans->readable)); + } + + if (forward_fault) + trans->esr = esr_s2_fault(vcpu, trans->level, ESR_ELx_FSC_PERM); + + return forward_fault; +} + +int kvm_inject_s2_fault(struct kvm_vcpu *vcpu, u64 esr_el2) +{ + vcpu_write_sys_reg(vcpu, vcpu->arch.fault.far_el2, FAR_EL2); + vcpu_write_sys_reg(vcpu, vcpu->arch.fault.hpfar_el2, HPFAR_EL2); + + return kvm_inject_nested_sync(vcpu, esr_el2); +} + +void kvm_nested_s2_wp(struct kvm *kvm) +{ + int i; + + lockdep_assert_held_write(&kvm->mmu_lock); + + for (i = 0; i < kvm->arch.nested_mmus_size; i++) { + struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; + + if (kvm_s2_mmu_valid(mmu)) + kvm_stage2_wp_range(mmu, 0, kvm_phys_size(mmu)); + } +} + +void kvm_nested_s2_unmap(struct kvm *kvm) +{ + int i; + + lockdep_assert_held_write(&kvm->mmu_lock); + + for (i = 0; i < kvm->arch.nested_mmus_size; i++) { + struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; + + if (kvm_s2_mmu_valid(mmu)) + kvm_stage2_unmap_range(mmu, 0, kvm_phys_size(mmu)); + } +} + +void kvm_nested_s2_flush(struct kvm *kvm) +{ + int i; + + lockdep_assert_held_write(&kvm->mmu_lock); + + for (i = 0; i < kvm->arch.nested_mmus_size; i++) { + struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; + + if (kvm_s2_mmu_valid(mmu)) + kvm_stage2_flush_range(mmu, 0, kvm_phys_size(mmu)); + } +} + +void kvm_arch_flush_shadow_all(struct kvm *kvm) +{ + int i; + + for (i = 0; i < kvm->arch.nested_mmus_size; i++) { + struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; + + if (!WARN_ON(atomic_read(&mmu->refcnt))) + kvm_free_stage2_pgd(mmu); + } + kfree(kvm->arch.nested_mmus); + kvm->arch.nested_mmus = NULL; + kvm->arch.nested_mmus_size = 0; + kvm_uninit_stage2_mmu(kvm); +} + /* * Our emulated CPU doesn't support all the possible features. For the * sake of simplicity (and probably mental sanity), wipe out a number @@ -23,143 +799,131 @@ * This list should get updated as new features get added to the NV * support, and new extension to the architecture. */ -static u64 limit_nv_id_reg(u32 id, u64 val) +static void limit_nv_id_regs(struct kvm *kvm) { - u64 tmp; + u64 val, tmp; - switch (id) { - case SYS_ID_AA64ISAR0_EL1: - /* Support everything but TME, O.S. and Range TLBIs */ - val &= ~(NV_FTR(ISAR0, TLB) | - NV_FTR(ISAR0, TME)); - break; + /* Support everything but TME */ + val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64ISAR0_EL1); + val &= ~NV_FTR(ISAR0, TME); + kvm_set_vm_id_reg(kvm, SYS_ID_AA64ISAR0_EL1, val); - case SYS_ID_AA64ISAR1_EL1: - /* Support everything but Spec Invalidation */ - val &= ~(GENMASK_ULL(63, 56) | - NV_FTR(ISAR1, SPECRES)); - break; + /* Support everything but Spec Invalidation and LS64 */ + val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64ISAR1_EL1); + val &= ~(NV_FTR(ISAR1, LS64) | + NV_FTR(ISAR1, SPECRES)); + kvm_set_vm_id_reg(kvm, SYS_ID_AA64ISAR1_EL1, val); - case SYS_ID_AA64PFR0_EL1: - /* No AMU, MPAM, S-EL2, RAS or SVE */ - val &= ~(GENMASK_ULL(55, 52) | - NV_FTR(PFR0, AMU) | - NV_FTR(PFR0, MPAM) | - NV_FTR(PFR0, SEL2) | - NV_FTR(PFR0, RAS) | - NV_FTR(PFR0, SVE) | - NV_FTR(PFR0, EL3) | - NV_FTR(PFR0, EL2) | - NV_FTR(PFR0, EL1)); - /* 64bit EL1/EL2/EL3 only */ - val |= FIELD_PREP(NV_FTR(PFR0, EL1), 0b0001); - val |= FIELD_PREP(NV_FTR(PFR0, EL2), 0b0001); - val |= FIELD_PREP(NV_FTR(PFR0, EL3), 0b0001); - break; + /* No AMU, MPAM, S-EL2, or RAS */ + val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1); + val &= ~(GENMASK_ULL(55, 52) | + NV_FTR(PFR0, AMU) | + NV_FTR(PFR0, MPAM) | + NV_FTR(PFR0, SEL2) | + NV_FTR(PFR0, RAS) | + NV_FTR(PFR0, EL3) | + NV_FTR(PFR0, EL2) | + NV_FTR(PFR0, EL1)); + /* 64bit EL1/EL2/EL3 only */ + val |= FIELD_PREP(NV_FTR(PFR0, EL1), 0b0001); + val |= FIELD_PREP(NV_FTR(PFR0, EL2), 0b0001); + val |= FIELD_PREP(NV_FTR(PFR0, EL3), 0b0001); + kvm_set_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1, val); - case SYS_ID_AA64PFR1_EL1: - /* Only support BTI, SSBS, CSV2_frac */ - val &= (NV_FTR(PFR1, BT) | - NV_FTR(PFR1, SSBS) | - NV_FTR(PFR1, CSV2_frac)); - break; + /* Only support BTI, SSBS, CSV2_frac */ + val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64PFR1_EL1); + val &= (NV_FTR(PFR1, BT) | + NV_FTR(PFR1, SSBS) | + NV_FTR(PFR1, CSV2_frac)); + kvm_set_vm_id_reg(kvm, SYS_ID_AA64PFR1_EL1, val); - case SYS_ID_AA64MMFR0_EL1: - /* Hide ECV, ExS, Secure Memory */ - val &= ~(NV_FTR(MMFR0, ECV) | - NV_FTR(MMFR0, EXS) | - NV_FTR(MMFR0, TGRAN4_2) | - NV_FTR(MMFR0, TGRAN16_2) | - NV_FTR(MMFR0, TGRAN64_2) | - NV_FTR(MMFR0, SNSMEM)); + /* Hide ECV, ExS, Secure Memory */ + val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64MMFR0_EL1); + val &= ~(NV_FTR(MMFR0, ECV) | + NV_FTR(MMFR0, EXS) | + NV_FTR(MMFR0, TGRAN4_2) | + NV_FTR(MMFR0, TGRAN16_2) | + NV_FTR(MMFR0, TGRAN64_2) | + NV_FTR(MMFR0, SNSMEM)); - /* Disallow unsupported S2 page sizes */ - switch (PAGE_SIZE) { - case SZ_64K: - val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN16_2), 0b0001); - fallthrough; - case SZ_16K: - val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN4_2), 0b0001); - fallthrough; - case SZ_4K: - /* Support everything */ - break; - } - /* - * Since we can't support a guest S2 page size smaller than - * the host's own page size (due to KVM only populating its - * own S2 using the kernel's page size), advertise the - * limitation using FEAT_GTG. - */ - switch (PAGE_SIZE) { - case SZ_4K: - val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN4_2), 0b0010); - fallthrough; - case SZ_16K: - val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN16_2), 0b0010); - fallthrough; - case SZ_64K: - val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN64_2), 0b0010); - break; - } - /* Cap PARange to 48bits */ - tmp = FIELD_GET(NV_FTR(MMFR0, PARANGE), val); - if (tmp > 0b0101) { - val &= ~NV_FTR(MMFR0, PARANGE); - val |= FIELD_PREP(NV_FTR(MMFR0, PARANGE), 0b0101); - } - break; - - case SYS_ID_AA64MMFR1_EL1: - val &= (NV_FTR(MMFR1, HCX) | - NV_FTR(MMFR1, PAN) | - NV_FTR(MMFR1, LO) | - NV_FTR(MMFR1, HPDS) | - NV_FTR(MMFR1, VH) | - NV_FTR(MMFR1, VMIDBits)); - break; - - case SYS_ID_AA64MMFR2_EL1: - val &= ~(NV_FTR(MMFR2, BBM) | - NV_FTR(MMFR2, TTL) | - GENMASK_ULL(47, 44) | - NV_FTR(MMFR2, ST) | - NV_FTR(MMFR2, CCIDX) | - NV_FTR(MMFR2, VARange)); - - /* Force TTL support */ - val |= FIELD_PREP(NV_FTR(MMFR2, TTL), 0b0001); - break; - - case SYS_ID_AA64MMFR4_EL1: - val = 0; - if (!cpus_have_final_cap(ARM64_HAS_HCR_NV1)) - val |= FIELD_PREP(NV_FTR(MMFR4, E2H0), - ID_AA64MMFR4_EL1_E2H0_NI_NV1); - break; - - case SYS_ID_AA64DFR0_EL1: - /* Only limited support for PMU, Debug, BPs and WPs */ - val &= (NV_FTR(DFR0, PMUVer) | - NV_FTR(DFR0, WRPs) | - NV_FTR(DFR0, BRPs) | - NV_FTR(DFR0, DebugVer)); - - /* Cap Debug to ARMv8.1 */ - tmp = FIELD_GET(NV_FTR(DFR0, DebugVer), val); - if (tmp > 0b0111) { - val &= ~NV_FTR(DFR0, DebugVer); - val |= FIELD_PREP(NV_FTR(DFR0, DebugVer), 0b0111); - } - break; - - default: - /* Unknown register, just wipe it clean */ - val = 0; + /* Disallow unsupported S2 page sizes */ + switch (PAGE_SIZE) { + case SZ_64K: + val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN16_2), 0b0001); + fallthrough; + case SZ_16K: + val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN4_2), 0b0001); + fallthrough; + case SZ_4K: + /* Support everything */ break; } + /* + * Since we can't support a guest S2 page size smaller than + * the host's own page size (due to KVM only populating its + * own S2 using the kernel's page size), advertise the + * limitation using FEAT_GTG. + */ + switch (PAGE_SIZE) { + case SZ_4K: + val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN4_2), 0b0010); + fallthrough; + case SZ_16K: + val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN16_2), 0b0010); + fallthrough; + case SZ_64K: + val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN64_2), 0b0010); + break; + } + /* Cap PARange to 48bits */ + tmp = FIELD_GET(NV_FTR(MMFR0, PARANGE), val); + if (tmp > 0b0101) { + val &= ~NV_FTR(MMFR0, PARANGE); + val |= FIELD_PREP(NV_FTR(MMFR0, PARANGE), 0b0101); + } + kvm_set_vm_id_reg(kvm, SYS_ID_AA64MMFR0_EL1, val); - return val; + val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64MMFR1_EL1); + val &= (NV_FTR(MMFR1, HCX) | + NV_FTR(MMFR1, PAN) | + NV_FTR(MMFR1, LO) | + NV_FTR(MMFR1, HPDS) | + NV_FTR(MMFR1, VH) | + NV_FTR(MMFR1, VMIDBits)); + kvm_set_vm_id_reg(kvm, SYS_ID_AA64MMFR1_EL1, val); + + val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64MMFR2_EL1); + val &= ~(NV_FTR(MMFR2, BBM) | + NV_FTR(MMFR2, TTL) | + GENMASK_ULL(47, 44) | + NV_FTR(MMFR2, ST) | + NV_FTR(MMFR2, CCIDX) | + NV_FTR(MMFR2, VARange)); + + /* Force TTL support */ + val |= FIELD_PREP(NV_FTR(MMFR2, TTL), 0b0001); + kvm_set_vm_id_reg(kvm, SYS_ID_AA64MMFR2_EL1, val); + + val = 0; + if (!cpus_have_final_cap(ARM64_HAS_HCR_NV1)) + val |= FIELD_PREP(NV_FTR(MMFR4, E2H0), + ID_AA64MMFR4_EL1_E2H0_NI_NV1); + kvm_set_vm_id_reg(kvm, SYS_ID_AA64MMFR4_EL1, val); + + /* Only limited support for PMU, Debug, BPs and WPs */ + val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64DFR0_EL1); + val &= (NV_FTR(DFR0, PMUVer) | + NV_FTR(DFR0, WRPs) | + NV_FTR(DFR0, BRPs) | + NV_FTR(DFR0, DebugVer)); + + /* Cap Debug to ARMv8.1 */ + tmp = FIELD_GET(NV_FTR(DFR0, DebugVer), val); + if (tmp > 0b0111) { + val &= ~NV_FTR(DFR0, DebugVer); + val |= FIELD_PREP(NV_FTR(DFR0, DebugVer), 0b0111); + } + kvm_set_vm_id_reg(kvm, SYS_ID_AA64DFR0_EL1, val); } u64 kvm_vcpu_sanitise_vncr_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg sr) @@ -198,15 +962,13 @@ int kvm_init_nv_sysregs(struct kvm *kvm) goto out; kvm->arch.sysreg_masks = kzalloc(sizeof(*(kvm->arch.sysreg_masks)), - GFP_KERNEL); + GFP_KERNEL_ACCOUNT); if (!kvm->arch.sysreg_masks) { ret = -ENOMEM; goto out; } - for (int i = 0; i < KVM_ARM_ID_REG_NUM; i++) - kvm->arch.id_regs[i] = limit_nv_id_reg(IDX_IDREG(i), - kvm->arch.id_regs[i]); + limit_nv_id_regs(kvm); /* VTTBR_EL2 */ res0 = res1 = 0; diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index d1a476b08f54..82a2a003259c 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -53,7 +53,7 @@ static u32 __kvm_pmu_event_mask(unsigned int pmuver) static u32 kvm_pmu_event_mask(struct kvm *kvm) { - u64 dfr0 = IDREG(kvm, SYS_ID_AA64DFR0_EL1); + u64 dfr0 = kvm_read_vm_id_reg(kvm, SYS_ID_AA64DFR0_EL1); u8 pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer, dfr0); return __kvm_pmu_event_mask(pmuver); diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 3fc8ca164dbe..0b0ae5ae7bc2 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -268,6 +268,12 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu) preempt_enable(); } +u32 kvm_get_pa_bits(struct kvm *kvm) +{ + /* Fixed limit until we can configure ID_AA64MMFR0.PARange */ + return kvm_ipa_limit; +} + u32 get_kvm_ipa_limit(void) { return kvm_ipa_limit; diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 22b45a15d068..c90324060436 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -121,6 +121,7 @@ static bool get_el2_to_el1_mapping(unsigned int reg, MAPPED_EL2_SYSREG(AMAIR_EL2, AMAIR_EL1, NULL ); MAPPED_EL2_SYSREG(ELR_EL2, ELR_EL1, NULL ); MAPPED_EL2_SYSREG(SPSR_EL2, SPSR_EL1, NULL ); + MAPPED_EL2_SYSREG(ZCR_EL2, ZCR_EL1, NULL ); default: return false; } @@ -383,6 +384,12 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu, bool was_enabled = vcpu_has_cache_enabled(vcpu); u64 val, mask, shift; + if (reg_to_encoding(r) == SYS_TCR2_EL1 && + !kvm_has_feat(vcpu->kvm, ID_AA64MMFR3_EL1, TCRX, IMP)) { + kvm_inject_undefined(vcpu); + return false; + } + BUG_ON(!p->is_write); get_access_mask(r, &mask, &shift); @@ -1565,7 +1572,7 @@ static u64 kvm_read_sanitised_id_reg(struct kvm_vcpu *vcpu, static u64 read_id_reg(const struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) { - return IDREG(vcpu->kvm, reg_to_encoding(r)); + return kvm_read_vm_id_reg(vcpu->kvm, reg_to_encoding(r)); } static bool is_feature_id_reg(u32 encoding) @@ -1583,6 +1590,9 @@ static bool is_feature_id_reg(u32 encoding) */ static inline bool is_vm_ftr_id_reg(u32 id) { + if (id == SYS_CTR_EL0) + return true; + return (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 && sys_reg_CRn(id) == 0 && sys_reg_CRm(id) >= 1 && sys_reg_CRm(id) < 8); @@ -1851,7 +1861,7 @@ static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, ret = arm64_check_features(vcpu, rd, val); if (!ret) - IDREG(vcpu->kvm, id) = val; + kvm_set_vm_id_reg(vcpu->kvm, id, val); mutex_unlock(&vcpu->kvm->arch.config_lock); @@ -1867,6 +1877,18 @@ static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, return ret; } +void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val) +{ + u64 *p = __vm_id_reg(&kvm->arch, reg); + + lockdep_assert_held(&kvm->arch.config_lock); + + if (KVM_BUG_ON(kvm_vm_has_ran_once(kvm) || !p, kvm)) + return; + + *p = val; +} + static int get_raz_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, u64 *val) { @@ -1886,7 +1908,7 @@ static bool access_ctr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, if (p->is_write) return write_to_read_only(vcpu, p, r); - p->regval = read_sanitised_ftr_reg(SYS_CTR_EL0); + p->regval = kvm_read_vm_id_reg(vcpu->kvm, SYS_CTR_EL0); return true; } @@ -2199,6 +2221,40 @@ static u64 reset_hcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) return __vcpu_sys_reg(vcpu, r->reg) = val; } +static unsigned int sve_el2_visibility(const struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd) +{ + unsigned int r; + + r = el2_visibility(vcpu, rd); + if (r) + return r; + + return sve_visibility(vcpu, rd); +} + +static bool access_zcr_el2(struct kvm_vcpu *vcpu, + struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + unsigned int vq; + + if (guest_hyp_sve_traps_enabled(vcpu)) { + kvm_inject_nested_sve_trap(vcpu); + return true; + } + + if (!p->is_write) { + p->regval = vcpu_read_sys_reg(vcpu, ZCR_EL2); + return true; + } + + vq = SYS_FIELD_GET(ZCR_ELx, LEN, p->regval) + 1; + vq = min(vq, vcpu_sve_max_vq(vcpu)); + vcpu_write_sys_reg(vcpu, vq - 1, ZCR_EL2); + return true; +} + /* * Architected system registers. * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2 @@ -2471,11 +2527,14 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_CCSIDR_EL1), access_ccsidr }, { SYS_DESC(SYS_CLIDR_EL1), access_clidr, reset_clidr, CLIDR_EL1, - .set_user = set_clidr }, + .set_user = set_clidr, .val = ~CLIDR_EL1_RES0 }, { SYS_DESC(SYS_CCSIDR2_EL1), undef_access }, { SYS_DESC(SYS_SMIDR_EL1), undef_access }, { SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 }, - { SYS_DESC(SYS_CTR_EL0), access_ctr }, + ID_WRITABLE(CTR_EL0, CTR_EL0_DIC_MASK | + CTR_EL0_IDC_MASK | + CTR_EL0_DminLine_MASK | + CTR_EL0_IminLine_MASK), { SYS_DESC(SYS_SVCR), undef_access }, { PMU_SYS_REG(PMCR_EL0), .access = access_pmcr, .reset = reset_pmcr, @@ -2688,6 +2747,9 @@ static const struct sys_reg_desc sys_reg_descs[] = { EL2_REG_VNCR(HFGITR_EL2, reset_val, 0), EL2_REG_VNCR(HACR_EL2, reset_val, 0), + { SYS_DESC(SYS_ZCR_EL2), .access = access_zcr_el2, .reset = reset_val, + .visibility = sve_el2_visibility, .reg = ZCR_EL2 }, + EL2_REG_VNCR(HCRX_EL2, reset_val, 0), EL2_REG(TTBR0_EL2, access_rw, reset_val, 0), @@ -2741,6 +2803,264 @@ static const struct sys_reg_desc sys_reg_descs[] = { EL2_REG(SP_EL2, NULL, reset_unknown, 0), }; +static bool kvm_supported_tlbi_s12_op(struct kvm_vcpu *vpcu, u32 instr) +{ + struct kvm *kvm = vpcu->kvm; + u8 CRm = sys_reg_CRm(instr); + + if (sys_reg_CRn(instr) == TLBI_CRn_nXS && + !kvm_has_feat(kvm, ID_AA64ISAR1_EL1, XS, IMP)) + return false; + + if (CRm == TLBI_CRm_nROS && + !kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, OS)) + return false; + + return true; +} + +static bool handle_alle1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + u32 sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2); + + if (!kvm_supported_tlbi_s12_op(vcpu, sys_encoding)) { + kvm_inject_undefined(vcpu); + return false; + } + + write_lock(&vcpu->kvm->mmu_lock); + + /* + * Drop all shadow S2s, resulting in S1/S2 TLBIs for each of the + * corresponding VMIDs. + */ + kvm_nested_s2_unmap(vcpu->kvm); + + write_unlock(&vcpu->kvm->mmu_lock); + + return true; +} + +static bool kvm_supported_tlbi_ipas2_op(struct kvm_vcpu *vpcu, u32 instr) +{ + struct kvm *kvm = vpcu->kvm; + u8 CRm = sys_reg_CRm(instr); + u8 Op2 = sys_reg_Op2(instr); + + if (sys_reg_CRn(instr) == TLBI_CRn_nXS && + !kvm_has_feat(kvm, ID_AA64ISAR1_EL1, XS, IMP)) + return false; + + if (CRm == TLBI_CRm_IPAIS && (Op2 == 2 || Op2 == 6) && + !kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, RANGE)) + return false; + + if (CRm == TLBI_CRm_IPAONS && (Op2 == 0 || Op2 == 4) && + !kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, OS)) + return false; + + if (CRm == TLBI_CRm_IPAONS && (Op2 == 3 || Op2 == 7) && + !kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, RANGE)) + return false; + + return true; +} + +/* Only defined here as this is an internal "abstraction" */ +union tlbi_info { + struct { + u64 start; + u64 size; + } range; + + struct { + u64 addr; + } ipa; + + struct { + u64 addr; + u32 encoding; + } va; +}; + +static void s2_mmu_unmap_range(struct kvm_s2_mmu *mmu, + const union tlbi_info *info) +{ + kvm_stage2_unmap_range(mmu, info->range.start, info->range.size); +} + +static bool handle_vmalls12e1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + u32 sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2); + u64 limit, vttbr; + + if (!kvm_supported_tlbi_s12_op(vcpu, sys_encoding)) { + kvm_inject_undefined(vcpu); + return false; + } + + vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2); + limit = BIT_ULL(kvm_get_pa_bits(vcpu->kvm)); + + kvm_s2_mmu_iterate_by_vmid(vcpu->kvm, get_vmid(vttbr), + &(union tlbi_info) { + .range = { + .start = 0, + .size = limit, + }, + }, + s2_mmu_unmap_range); + + return true; +} + +static bool handle_ripas2e1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + u32 sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2); + u64 vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2); + u64 base, range, tg, num, scale; + int shift; + + if (!kvm_supported_tlbi_ipas2_op(vcpu, sys_encoding)) { + kvm_inject_undefined(vcpu); + return false; + } + + /* + * Because the shadow S2 structure doesn't necessarily reflect that + * of the guest's S2 (different base granule size, for example), we + * decide to ignore TTL and only use the described range. + */ + tg = FIELD_GET(GENMASK(47, 46), p->regval); + scale = FIELD_GET(GENMASK(45, 44), p->regval); + num = FIELD_GET(GENMASK(43, 39), p->regval); + base = p->regval & GENMASK(36, 0); + + switch(tg) { + case 1: + shift = 12; + break; + case 2: + shift = 14; + break; + case 3: + default: /* IMPDEF: handle tg==0 as 64k */ + shift = 16; + break; + } + + base <<= shift; + range = __TLBI_RANGE_PAGES(num, scale) << shift; + + kvm_s2_mmu_iterate_by_vmid(vcpu->kvm, get_vmid(vttbr), + &(union tlbi_info) { + .range = { + .start = base, + .size = range, + }, + }, + s2_mmu_unmap_range); + + return true; +} + +static void s2_mmu_unmap_ipa(struct kvm_s2_mmu *mmu, + const union tlbi_info *info) +{ + unsigned long max_size; + u64 base_addr; + + /* + * We drop a number of things from the supplied value: + * + * - NS bit: we're non-secure only. + * + * - IPA[51:48]: We don't support 52bit IPA just yet... + * + * And of course, adjust the IPA to be on an actual address. + */ + base_addr = (info->ipa.addr & GENMASK_ULL(35, 0)) << 12; + max_size = compute_tlb_inval_range(mmu, info->ipa.addr); + base_addr &= ~(max_size - 1); + + kvm_stage2_unmap_range(mmu, base_addr, max_size); +} + +static bool handle_ipas2e1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + u32 sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2); + u64 vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2); + + if (!kvm_supported_tlbi_ipas2_op(vcpu, sys_encoding)) { + kvm_inject_undefined(vcpu); + return false; + } + + kvm_s2_mmu_iterate_by_vmid(vcpu->kvm, get_vmid(vttbr), + &(union tlbi_info) { + .ipa = { + .addr = p->regval, + }, + }, + s2_mmu_unmap_ipa); + + return true; +} + +static void s2_mmu_tlbi_s1e1(struct kvm_s2_mmu *mmu, + const union tlbi_info *info) +{ + WARN_ON(__kvm_tlbi_s1e2(mmu, info->va.addr, info->va.encoding)); +} + +static bool handle_tlbi_el1(struct kvm_vcpu *vcpu, struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + u32 sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2); + u64 vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2); + + /* + * If we're here, this is because we've trapped on a EL1 TLBI + * instruction that affects the EL1 translation regime while + * we're running in a context that doesn't allow us to let the + * HW do its thing (aka vEL2): + * + * - HCR_EL2.E2H == 0 : a non-VHE guest + * - HCR_EL2.{E2H,TGE} == { 1, 0 } : a VHE guest in guest mode + * + * We don't expect these helpers to ever be called when running + * in a vEL1 context. + */ + + WARN_ON(!vcpu_is_el2(vcpu)); + + if (!kvm_supported_tlbi_s1e1_op(vcpu, sys_encoding)) { + kvm_inject_undefined(vcpu); + return false; + } + + kvm_s2_mmu_iterate_by_vmid(vcpu->kvm, get_vmid(vttbr), + &(union tlbi_info) { + .va = { + .addr = p->regval, + .encoding = sys_encoding, + }, + }, + s2_mmu_tlbi_s1e1); + + return true; +} + +#define SYS_INSN(insn, access_fn) \ + { \ + SYS_DESC(OP_##insn), \ + .access = (access_fn), \ + } + static struct sys_reg_desc sys_insn_descs[] = { { SYS_DESC(SYS_DC_ISW), access_dcsw }, { SYS_DESC(SYS_DC_IGSW), access_dcgsw }, @@ -2751,9 +3071,147 @@ static struct sys_reg_desc sys_insn_descs[] = { { SYS_DESC(SYS_DC_CISW), access_dcsw }, { SYS_DESC(SYS_DC_CIGSW), access_dcgsw }, { SYS_DESC(SYS_DC_CIGDSW), access_dcgsw }, -}; -static const struct sys_reg_desc *first_idreg; + SYS_INSN(TLBI_VMALLE1OS, handle_tlbi_el1), + SYS_INSN(TLBI_VAE1OS, handle_tlbi_el1), + SYS_INSN(TLBI_ASIDE1OS, handle_tlbi_el1), + SYS_INSN(TLBI_VAAE1OS, handle_tlbi_el1), + SYS_INSN(TLBI_VALE1OS, handle_tlbi_el1), + SYS_INSN(TLBI_VAALE1OS, handle_tlbi_el1), + + SYS_INSN(TLBI_RVAE1IS, handle_tlbi_el1), + SYS_INSN(TLBI_RVAAE1IS, handle_tlbi_el1), + SYS_INSN(TLBI_RVALE1IS, handle_tlbi_el1), + SYS_INSN(TLBI_RVAALE1IS, handle_tlbi_el1), + + SYS_INSN(TLBI_VMALLE1IS, handle_tlbi_el1), + SYS_INSN(TLBI_VAE1IS, handle_tlbi_el1), + SYS_INSN(TLBI_ASIDE1IS, handle_tlbi_el1), + SYS_INSN(TLBI_VAAE1IS, handle_tlbi_el1), + SYS_INSN(TLBI_VALE1IS, handle_tlbi_el1), + SYS_INSN(TLBI_VAALE1IS, handle_tlbi_el1), + + SYS_INSN(TLBI_RVAE1OS, handle_tlbi_el1), + SYS_INSN(TLBI_RVAAE1OS, handle_tlbi_el1), + SYS_INSN(TLBI_RVALE1OS, handle_tlbi_el1), + SYS_INSN(TLBI_RVAALE1OS, handle_tlbi_el1), + + SYS_INSN(TLBI_RVAE1, handle_tlbi_el1), + SYS_INSN(TLBI_RVAAE1, handle_tlbi_el1), + SYS_INSN(TLBI_RVALE1, handle_tlbi_el1), + SYS_INSN(TLBI_RVAALE1, handle_tlbi_el1), + + SYS_INSN(TLBI_VMALLE1, handle_tlbi_el1), + SYS_INSN(TLBI_VAE1, handle_tlbi_el1), + SYS_INSN(TLBI_ASIDE1, handle_tlbi_el1), + SYS_INSN(TLBI_VAAE1, handle_tlbi_el1), + SYS_INSN(TLBI_VALE1, handle_tlbi_el1), + SYS_INSN(TLBI_VAALE1, handle_tlbi_el1), + + SYS_INSN(TLBI_VMALLE1OSNXS, handle_tlbi_el1), + SYS_INSN(TLBI_VAE1OSNXS, handle_tlbi_el1), + SYS_INSN(TLBI_ASIDE1OSNXS, handle_tlbi_el1), + SYS_INSN(TLBI_VAAE1OSNXS, handle_tlbi_el1), + SYS_INSN(TLBI_VALE1OSNXS, handle_tlbi_el1), + SYS_INSN(TLBI_VAALE1OSNXS, handle_tlbi_el1), + + SYS_INSN(TLBI_RVAE1ISNXS, handle_tlbi_el1), + SYS_INSN(TLBI_RVAAE1ISNXS, handle_tlbi_el1), + SYS_INSN(TLBI_RVALE1ISNXS, handle_tlbi_el1), + SYS_INSN(TLBI_RVAALE1ISNXS, handle_tlbi_el1), + + SYS_INSN(TLBI_VMALLE1ISNXS, handle_tlbi_el1), + SYS_INSN(TLBI_VAE1ISNXS, handle_tlbi_el1), + SYS_INSN(TLBI_ASIDE1ISNXS, handle_tlbi_el1), + SYS_INSN(TLBI_VAAE1ISNXS, handle_tlbi_el1), + SYS_INSN(TLBI_VALE1ISNXS, handle_tlbi_el1), + SYS_INSN(TLBI_VAALE1ISNXS, handle_tlbi_el1), + + SYS_INSN(TLBI_RVAE1OSNXS, handle_tlbi_el1), + SYS_INSN(TLBI_RVAAE1OSNXS, handle_tlbi_el1), + SYS_INSN(TLBI_RVALE1OSNXS, handle_tlbi_el1), + SYS_INSN(TLBI_RVAALE1OSNXS, handle_tlbi_el1), + + SYS_INSN(TLBI_RVAE1NXS, handle_tlbi_el1), + SYS_INSN(TLBI_RVAAE1NXS, handle_tlbi_el1), + SYS_INSN(TLBI_RVALE1NXS, handle_tlbi_el1), + SYS_INSN(TLBI_RVAALE1NXS, handle_tlbi_el1), + + SYS_INSN(TLBI_VMALLE1NXS, handle_tlbi_el1), + SYS_INSN(TLBI_VAE1NXS, handle_tlbi_el1), + SYS_INSN(TLBI_ASIDE1NXS, handle_tlbi_el1), + SYS_INSN(TLBI_VAAE1NXS, handle_tlbi_el1), + SYS_INSN(TLBI_VALE1NXS, handle_tlbi_el1), + SYS_INSN(TLBI_VAALE1NXS, handle_tlbi_el1), + + SYS_INSN(TLBI_IPAS2E1IS, handle_ipas2e1is), + SYS_INSN(TLBI_RIPAS2E1IS, handle_ripas2e1is), + SYS_INSN(TLBI_IPAS2LE1IS, handle_ipas2e1is), + SYS_INSN(TLBI_RIPAS2LE1IS, handle_ripas2e1is), + + SYS_INSN(TLBI_ALLE2OS, trap_undef), + SYS_INSN(TLBI_VAE2OS, trap_undef), + SYS_INSN(TLBI_ALLE1OS, handle_alle1is), + SYS_INSN(TLBI_VALE2OS, trap_undef), + SYS_INSN(TLBI_VMALLS12E1OS, handle_vmalls12e1is), + + SYS_INSN(TLBI_RVAE2IS, trap_undef), + SYS_INSN(TLBI_RVALE2IS, trap_undef), + + SYS_INSN(TLBI_ALLE1IS, handle_alle1is), + SYS_INSN(TLBI_VMALLS12E1IS, handle_vmalls12e1is), + SYS_INSN(TLBI_IPAS2E1OS, handle_ipas2e1is), + SYS_INSN(TLBI_IPAS2E1, handle_ipas2e1is), + SYS_INSN(TLBI_RIPAS2E1, handle_ripas2e1is), + SYS_INSN(TLBI_RIPAS2E1OS, handle_ripas2e1is), + SYS_INSN(TLBI_IPAS2LE1OS, handle_ipas2e1is), + SYS_INSN(TLBI_IPAS2LE1, handle_ipas2e1is), + SYS_INSN(TLBI_RIPAS2LE1, handle_ripas2e1is), + SYS_INSN(TLBI_RIPAS2LE1OS, handle_ripas2e1is), + SYS_INSN(TLBI_RVAE2OS, trap_undef), + SYS_INSN(TLBI_RVALE2OS, trap_undef), + SYS_INSN(TLBI_RVAE2, trap_undef), + SYS_INSN(TLBI_RVALE2, trap_undef), + SYS_INSN(TLBI_ALLE1, handle_alle1is), + SYS_INSN(TLBI_VMALLS12E1, handle_vmalls12e1is), + + SYS_INSN(TLBI_IPAS2E1ISNXS, handle_ipas2e1is), + SYS_INSN(TLBI_RIPAS2E1ISNXS, handle_ripas2e1is), + SYS_INSN(TLBI_IPAS2LE1ISNXS, handle_ipas2e1is), + SYS_INSN(TLBI_RIPAS2LE1ISNXS, handle_ripas2e1is), + + SYS_INSN(TLBI_ALLE2OSNXS, trap_undef), + SYS_INSN(TLBI_VAE2OSNXS, trap_undef), + SYS_INSN(TLBI_ALLE1OSNXS, handle_alle1is), + SYS_INSN(TLBI_VALE2OSNXS, trap_undef), + SYS_INSN(TLBI_VMALLS12E1OSNXS, handle_vmalls12e1is), + + SYS_INSN(TLBI_RVAE2ISNXS, trap_undef), + SYS_INSN(TLBI_RVALE2ISNXS, trap_undef), + SYS_INSN(TLBI_ALLE2ISNXS, trap_undef), + SYS_INSN(TLBI_VAE2ISNXS, trap_undef), + + SYS_INSN(TLBI_ALLE1ISNXS, handle_alle1is), + SYS_INSN(TLBI_VALE2ISNXS, trap_undef), + SYS_INSN(TLBI_VMALLS12E1ISNXS, handle_vmalls12e1is), + SYS_INSN(TLBI_IPAS2E1OSNXS, handle_ipas2e1is), + SYS_INSN(TLBI_IPAS2E1NXS, handle_ipas2e1is), + SYS_INSN(TLBI_RIPAS2E1NXS, handle_ripas2e1is), + SYS_INSN(TLBI_RIPAS2E1OSNXS, handle_ripas2e1is), + SYS_INSN(TLBI_IPAS2LE1OSNXS, handle_ipas2e1is), + SYS_INSN(TLBI_IPAS2LE1NXS, handle_ipas2e1is), + SYS_INSN(TLBI_RIPAS2LE1NXS, handle_ripas2e1is), + SYS_INSN(TLBI_RIPAS2LE1OSNXS, handle_ripas2e1is), + SYS_INSN(TLBI_RVAE2OSNXS, trap_undef), + SYS_INSN(TLBI_RVALE2OSNXS, trap_undef), + SYS_INSN(TLBI_RVAE2NXS, trap_undef), + SYS_INSN(TLBI_RVALE2NXS, trap_undef), + SYS_INSN(TLBI_ALLE2NXS, trap_undef), + SYS_INSN(TLBI_VAE2NXS, trap_undef), + SYS_INSN(TLBI_ALLE1NXS, handle_alle1is), + SYS_INSN(TLBI_VALE2NXS, trap_undef), + SYS_INSN(TLBI_VMALLS12E1NXS, handle_vmalls12e1is), +}; static bool trap_dbgdidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, @@ -2762,7 +3220,7 @@ static bool trap_dbgdidr(struct kvm_vcpu *vcpu, if (p->is_write) { return ignore_write(vcpu, p); } else { - u64 dfr = IDREG(vcpu->kvm, SYS_ID_AA64DFR0_EL1); + u64 dfr = kvm_read_vm_id_reg(vcpu->kvm, SYS_ID_AA64DFR0_EL1); u32 el3 = kvm_has_feat(vcpu->kvm, ID_AA64PFR0_EL1, EL3, IMP); p->regval = ((SYS_FIELD_GET(ID_AA64DFR0_EL1, WRPs, dfr) << 28) | @@ -3440,6 +3898,25 @@ static bool emulate_sys_reg(struct kvm_vcpu *vcpu, return false; } +static const struct sys_reg_desc *idregs_debug_find(struct kvm *kvm, u8 pos) +{ + unsigned long i, idreg_idx = 0; + + for (i = 0; i < ARRAY_SIZE(sys_reg_descs); i++) { + const struct sys_reg_desc *r = &sys_reg_descs[i]; + + if (!is_vm_ftr_id_reg(reg_to_encoding(r))) + continue; + + if (idreg_idx == pos) + return r; + + idreg_idx++; + } + + return NULL; +} + static void *idregs_debug_start(struct seq_file *s, loff_t *pos) { struct kvm *kvm = s->private; @@ -3451,7 +3928,7 @@ static void *idregs_debug_start(struct seq_file *s, loff_t *pos) if (test_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags) && *iter == (u8)~0) { *iter = *pos; - if (*iter >= KVM_ARM_ID_REG_NUM) + if (!idregs_debug_find(kvm, *iter)) iter = NULL; } else { iter = ERR_PTR(-EBUSY); @@ -3468,7 +3945,7 @@ static void *idregs_debug_next(struct seq_file *s, void *v, loff_t *pos) (*pos)++; - if ((kvm->arch.idreg_debugfs_iter + 1) < KVM_ARM_ID_REG_NUM) { + if (idregs_debug_find(kvm, kvm->arch.idreg_debugfs_iter + 1)) { kvm->arch.idreg_debugfs_iter++; return &kvm->arch.idreg_debugfs_iter; @@ -3493,16 +3970,16 @@ static void idregs_debug_stop(struct seq_file *s, void *v) static int idregs_debug_show(struct seq_file *s, void *v) { - struct kvm *kvm = s->private; const struct sys_reg_desc *desc; + struct kvm *kvm = s->private; - desc = first_idreg + kvm->arch.idreg_debugfs_iter; + desc = idregs_debug_find(kvm, kvm->arch.idreg_debugfs_iter); if (!desc->name) return 0; seq_printf(s, "%20s:\t%016llx\n", - desc->name, IDREG(kvm, IDX_IDREG(kvm->arch.idreg_debugfs_iter))); + desc->name, kvm_read_vm_id_reg(kvm, reg_to_encoding(desc))); return 0; } @@ -3532,8 +4009,7 @@ static void reset_vm_ftr_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc if (test_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags)) return; - lockdep_assert_held(&kvm->arch.config_lock); - IDREG(kvm, id) = reg->reset(vcpu, reg); + kvm_set_vm_id_reg(kvm, id, reg->reset(vcpu, reg)); } static void reset_vcpu_ftr_id_reg(struct kvm_vcpu *vcpu, @@ -3686,8 +4162,8 @@ id_to_sys_reg_desc(struct kvm_vcpu *vcpu, u64 id, */ #define FUNCTION_INVARIANT(reg) \ - static u64 get_##reg(struct kvm_vcpu *v, \ - const struct sys_reg_desc *r) \ + static u64 reset_##reg(struct kvm_vcpu *v, \ + const struct sys_reg_desc *r) \ { \ ((struct sys_reg_desc *)r)->val = read_sysreg(reg); \ return ((struct sys_reg_desc *)r)->val; \ @@ -3697,18 +4173,11 @@ FUNCTION_INVARIANT(midr_el1) FUNCTION_INVARIANT(revidr_el1) FUNCTION_INVARIANT(aidr_el1) -static u64 get_ctr_el0(struct kvm_vcpu *v, const struct sys_reg_desc *r) -{ - ((struct sys_reg_desc *)r)->val = read_sanitised_ftr_reg(SYS_CTR_EL0); - return ((struct sys_reg_desc *)r)->val; -} - /* ->val is filled in by kvm_sys_reg_table_init() */ static struct sys_reg_desc invariant_sys_regs[] __ro_after_init = { - { SYS_DESC(SYS_MIDR_EL1), NULL, get_midr_el1 }, - { SYS_DESC(SYS_REVIDR_EL1), NULL, get_revidr_el1 }, - { SYS_DESC(SYS_AIDR_EL1), NULL, get_aidr_el1 }, - { SYS_DESC(SYS_CTR_EL0), NULL, get_ctr_el0 }, + { SYS_DESC(SYS_MIDR_EL1), NULL, reset_midr_el1 }, + { SYS_DESC(SYS_REVIDR_EL1), NULL, reset_revidr_el1 }, + { SYS_DESC(SYS_AIDR_EL1), NULL, reset_aidr_el1 }, }; static int get_invariant_sys_reg(u64 id, u64 __user *uaddr) @@ -4019,20 +4488,11 @@ int kvm_vm_ioctl_get_reg_writable_masks(struct kvm *kvm, struct reg_mask_range * if (!is_feature_id_reg(encoding) || !reg->set_user) continue; - /* - * For ID registers, we return the writable mask. Other feature - * registers return a full 64bit mask. That's not necessary - * compliant with a given revision of the architecture, but the - * RES0/RES1 definitions allow us to do that. - */ - if (is_vm_ftr_id_reg(encoding)) { - if (!reg->val || - (is_aa32_id_reg(encoding) && !kvm_supports_32bit_el0())) - continue; - val = reg->val; - } else { - val = ~0UL; + if (!reg->val || + (is_aa32_id_reg(encoding) && !kvm_supports_32bit_el0())) { + continue; } + val = reg->val; if (put_user(val, (masks + KVM_ARM_FEATURE_ID_RANGE_INDEX(encoding)))) return -EFAULT; @@ -4041,11 +4501,34 @@ int kvm_vm_ioctl_get_reg_writable_masks(struct kvm *kvm, struct reg_mask_range * return 0; } -void kvm_init_sysreg(struct kvm_vcpu *vcpu) +static void vcpu_set_hcr(struct kvm_vcpu *vcpu) { struct kvm *kvm = vcpu->kvm; - mutex_lock(&kvm->arch.config_lock); + if (has_vhe() || has_hvhe()) + vcpu->arch.hcr_el2 |= HCR_E2H; + if (cpus_have_final_cap(ARM64_HAS_RAS_EXTN)) { + /* route synchronous external abort exceptions to EL2 */ + vcpu->arch.hcr_el2 |= HCR_TEA; + /* trap error record accesses */ + vcpu->arch.hcr_el2 |= HCR_TERR; + } + + if (cpus_have_final_cap(ARM64_HAS_STAGE2_FWB)) + vcpu->arch.hcr_el2 |= HCR_FWB; + + if (cpus_have_final_cap(ARM64_HAS_EVT) && + !cpus_have_final_cap(ARM64_MISMATCHED_CACHE_TYPE) && + kvm_read_vm_id_reg(kvm, SYS_CTR_EL0) == read_sanitised_ftr_reg(SYS_CTR_EL0)) + vcpu->arch.hcr_el2 |= HCR_TID4; + else + vcpu->arch.hcr_el2 |= HCR_TID2; + + if (vcpu_el1_is_32bit(vcpu)) + vcpu->arch.hcr_el2 &= ~HCR_RW; + + if (kvm_has_mte(vcpu->kvm)) + vcpu->arch.hcr_el2 |= HCR_ATA; /* * In the absence of FGT, we cannot independently trap TLBI @@ -4054,12 +4537,29 @@ void kvm_init_sysreg(struct kvm_vcpu *vcpu) */ if (!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, OS)) vcpu->arch.hcr_el2 |= HCR_TTLBOS; +} + +void kvm_calculate_traps(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm = vcpu->kvm; + + mutex_lock(&kvm->arch.config_lock); + vcpu_set_hcr(vcpu); if (cpus_have_final_cap(ARM64_HAS_HCX)) { - vcpu->arch.hcrx_el2 = HCRX_GUEST_FLAGS; + /* + * In general, all HCRX_EL2 bits are gated by a feature. + * The only reason we can set SMPME without checking any + * feature is that its effects are not directly observable + * from the guest. + */ + vcpu->arch.hcrx_el2 = HCRX_EL2_SMPME; if (kvm_has_feat(kvm, ID_AA64ISAR2_EL1, MOPS, IMP)) vcpu->arch.hcrx_el2 |= (HCRX_EL2_MSCEn | HCRX_EL2_MCE2); + + if (kvm_has_feat(kvm, ID_AA64MMFR3_EL1, TCRX, IMP)) + vcpu->arch.hcrx_el2 |= HCRX_EL2_TCR2En; } if (test_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags)) @@ -4115,7 +4615,6 @@ out: int __init kvm_sys_reg_table_init(void) { - struct sys_reg_params params; bool valid = true; unsigned int i; int ret = 0; @@ -4136,12 +4635,6 @@ int __init kvm_sys_reg_table_init(void) for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++) invariant_sys_regs[i].reset(NULL, &invariant_sys_regs[i]); - /* Find the first idreg (SYS_ID_PFR0_EL1) in sys_reg_descs. */ - params = encoding_to_params(SYS_ID_PFR0_EL1); - first_idreg = find_reg(¶ms, sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); - if (!first_idreg) - return -EINVAL; - ret = populate_nv_trap_config(); for (i = 0; !ret && i < ARRAY_SIZE(sys_reg_descs); i++) diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index ddc042895d01..b81d0eba5c7e 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -649,6 +649,17 @@ config PARAVIRT over full virtualization. However, when run without a hypervisor the kernel is theoretically slower and slightly larger. +config PARAVIRT_TIME_ACCOUNTING + bool "Paravirtual steal time accounting" + depends on PARAVIRT + help + Select this option to enable fine granularity task steal time + accounting. Time spent executing other tasks in parallel with + the current vCPU is discounted from the vCPU power. To account for + that, there can be a small performance impact. + + If in doubt, say N here. + endmenu config ARCH_SELECT_MEMORY_MODEL diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h index c87b6ea0ec47..44b54965f5b4 100644 --- a/arch/loongarch/include/asm/kvm_host.h +++ b/arch/loongarch/include/asm/kvm_host.h @@ -30,12 +30,17 @@ #define KVM_PRIVATE_MEM_SLOTS 0 #define KVM_HALT_POLL_NS_DEFAULT 500000 +#define KVM_REQ_TLB_FLUSH_GPA KVM_ARCH_REQ(0) +#define KVM_REQ_STEAL_UPDATE KVM_ARCH_REQ(1) #define KVM_GUESTDBG_SW_BP_MASK \ (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP) #define KVM_GUESTDBG_VALID_MASK \ (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP | KVM_GUESTDBG_SINGLESTEP) +#define KVM_DIRTY_LOG_MANUAL_CAPS \ + (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | KVM_DIRTY_LOG_INITIALLY_SET) + struct kvm_vm_stat { struct kvm_vm_stat_generic generic; u64 pages; @@ -190,6 +195,7 @@ struct kvm_vcpu_arch { /* vcpu's vpid */ u64 vpid; + gpa_t flush_gpa; /* Frequency of stable timer in Hz */ u64 timer_mhz; @@ -201,6 +207,13 @@ struct kvm_vcpu_arch { struct kvm_mp_state mp_state; /* cpucfg */ u32 cpucfg[KVM_MAX_CPUCFG_REGS]; + + /* paravirt steal time */ + struct { + u64 guest_addr; + u64 last_steal; + struct gfn_to_hva_cache cache; + } st; }; static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg) @@ -261,7 +274,6 @@ static inline bool kvm_is_ifetch_fault(struct kvm_vcpu_arch *arch) static inline void kvm_arch_hardware_unsetup(void) {} static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {} -static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {} diff --git a/arch/loongarch/include/asm/kvm_para.h b/arch/loongarch/include/asm/kvm_para.h index 4ba2312e5f8c..335fb86778e2 100644 --- a/arch/loongarch/include/asm/kvm_para.h +++ b/arch/loongarch/include/asm/kvm_para.h @@ -14,6 +14,7 @@ #define KVM_HCALL_SERVICE HYPERCALL_ENCODE(HYPERVISOR_KVM, KVM_HCALL_CODE_SERVICE) #define KVM_HCALL_FUNC_IPI 1 +#define KVM_HCALL_FUNC_NOTIFY 2 #define KVM_HCALL_SWDBG HYPERCALL_ENCODE(HYPERVISOR_KVM, KVM_HCALL_CODE_SWDBG) @@ -24,6 +25,16 @@ #define KVM_HCALL_INVALID_CODE -1UL #define KVM_HCALL_INVALID_PARAMETER -2UL +#define KVM_STEAL_PHYS_VALID BIT_ULL(0) +#define KVM_STEAL_PHYS_MASK GENMASK_ULL(63, 6) + +struct kvm_steal_time { + __u64 steal; + __u32 version; + __u32 flags; + __u32 pad[12]; +}; + /* * Hypercall interface for KVM hypervisor * diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h index 590a92cb5416..c416cb7125c0 100644 --- a/arch/loongarch/include/asm/kvm_vcpu.h +++ b/arch/loongarch/include/asm/kvm_vcpu.h @@ -120,4 +120,9 @@ static inline void kvm_write_reg(struct kvm_vcpu *vcpu, int num, unsigned long v vcpu->arch.gprs[num] = val; } +static inline bool kvm_pvtime_supported(void) +{ + return !!sched_info_on(); +} + #endif /* __ASM_LOONGARCH_KVM_VCPU_H__ */ diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h index eb09adda54b7..7a4633ef284b 100644 --- a/arch/loongarch/include/asm/loongarch.h +++ b/arch/loongarch/include/asm/loongarch.h @@ -169,6 +169,7 @@ #define KVM_SIGNATURE "KVM\0" #define CPUCFG_KVM_FEATURE (CPUCFG_KVM_BASE + 4) #define KVM_FEATURE_IPI BIT(1) +#define KVM_FEATURE_STEAL_TIME BIT(2) #ifndef __ASSEMBLY__ diff --git a/arch/loongarch/include/asm/paravirt.h b/arch/loongarch/include/asm/paravirt.h index 0965710f47f2..dddec49671ae 100644 --- a/arch/loongarch/include/asm/paravirt.h +++ b/arch/loongarch/include/asm/paravirt.h @@ -18,6 +18,7 @@ static inline u64 paravirt_steal_clock(int cpu) } int __init pv_ipi_init(void); +int __init pv_time_init(void); #else @@ -26,5 +27,9 @@ static inline int pv_ipi_init(void) return 0; } +static inline int pv_time_init(void) +{ + return 0; +} #endif // CONFIG_PARAVIRT #endif diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h index f9abef382317..ddc5cab0ffd0 100644 --- a/arch/loongarch/include/uapi/asm/kvm.h +++ b/arch/loongarch/include/uapi/asm/kvm.h @@ -81,7 +81,11 @@ struct kvm_fpu { #define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT)) #define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG) #define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG) + +/* Device Control API on vcpu fd */ #define KVM_LOONGARCH_VCPU_CPUCFG 0 +#define KVM_LOONGARCH_VCPU_PVTIME_CTRL 1 +#define KVM_LOONGARCH_VCPU_PVTIME_GPA 0 struct kvm_debug_exit_arch { }; diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c index 1633ed4f692f..9abe8b71aa48 100644 --- a/arch/loongarch/kernel/paravirt.c +++ b/arch/loongarch/kernel/paravirt.c @@ -4,11 +4,14 @@ #include #include #include +#include #include #include +static int has_steal_clock; struct static_key paravirt_steal_enabled; struct static_key paravirt_steal_rq_enabled; +static DEFINE_PER_CPU(struct kvm_steal_time, steal_time) __aligned(64); static u64 native_steal_clock(int cpu) { @@ -17,6 +20,34 @@ static u64 native_steal_clock(int cpu) DEFINE_STATIC_CALL(pv_steal_clock, native_steal_clock); +static bool steal_acc = true; + +static int __init parse_no_stealacc(char *arg) +{ + steal_acc = false; + return 0; +} +early_param("no-steal-acc", parse_no_stealacc); + +static u64 paravt_steal_clock(int cpu) +{ + int version; + u64 steal; + struct kvm_steal_time *src; + + src = &per_cpu(steal_time, cpu); + do { + + version = src->version; + virt_rmb(); /* Make sure that the version is read before the steal */ + steal = src->steal; + virt_rmb(); /* Make sure that the steal is read before the next version */ + + } while ((version & 1) || (version != src->version)); + + return steal; +} + #ifdef CONFIG_SMP static void pv_send_ipi_single(int cpu, unsigned int action) { @@ -149,3 +180,117 @@ int __init pv_ipi_init(void) return 0; } + +static int pv_enable_steal_time(void) +{ + int cpu = smp_processor_id(); + unsigned long addr; + struct kvm_steal_time *st; + + if (!has_steal_clock) + return -EPERM; + + st = &per_cpu(steal_time, cpu); + addr = per_cpu_ptr_to_phys(st); + + /* The whole structure kvm_steal_time should be in one page */ + if (PFN_DOWN(addr) != PFN_DOWN(addr + sizeof(*st))) { + pr_warn("Illegal PV steal time addr %lx\n", addr); + return -EFAULT; + } + + addr |= KVM_STEAL_PHYS_VALID; + kvm_hypercall2(KVM_HCALL_FUNC_NOTIFY, KVM_FEATURE_STEAL_TIME, addr); + + return 0; +} + +static void pv_disable_steal_time(void) +{ + if (has_steal_clock) + kvm_hypercall2(KVM_HCALL_FUNC_NOTIFY, KVM_FEATURE_STEAL_TIME, 0); +} + +#ifdef CONFIG_SMP +static int pv_time_cpu_online(unsigned int cpu) +{ + unsigned long flags; + + local_irq_save(flags); + pv_enable_steal_time(); + local_irq_restore(flags); + + return 0; +} + +static int pv_time_cpu_down_prepare(unsigned int cpu) +{ + unsigned long flags; + + local_irq_save(flags); + pv_disable_steal_time(); + local_irq_restore(flags); + + return 0; +} +#endif + +static void pv_cpu_reboot(void *unused) +{ + pv_disable_steal_time(); +} + +static int pv_reboot_notify(struct notifier_block *nb, unsigned long code, void *unused) +{ + on_each_cpu(pv_cpu_reboot, NULL, 1); + return NOTIFY_DONE; +} + +static struct notifier_block pv_reboot_nb = { + .notifier_call = pv_reboot_notify, +}; + +int __init pv_time_init(void) +{ + int r, feature; + + if (!cpu_has_hypervisor) + return 0; + if (!kvm_para_available()) + return 0; + + feature = read_cpucfg(CPUCFG_KVM_FEATURE); + if (!(feature & KVM_FEATURE_STEAL_TIME)) + return 0; + + has_steal_clock = 1; + r = pv_enable_steal_time(); + if (r < 0) { + has_steal_clock = 0; + return 0; + } + register_reboot_notifier(&pv_reboot_nb); + +#ifdef CONFIG_SMP + r = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, + "loongarch/pv_time:online", + pv_time_cpu_online, pv_time_cpu_down_prepare); + if (r < 0) { + has_steal_clock = 0; + pr_err("Failed to install cpu hotplug callbacks\n"); + return r; + } +#endif + + static_call_update(pv_steal_clock, paravt_steal_clock); + + static_key_slow_inc(¶virt_steal_enabled); +#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING + if (steal_acc) + static_key_slow_inc(¶virt_steal_rq_enabled); +#endif + + pr_info("Using paravirt steal-time\n"); + + return 0; +} diff --git a/arch/loongarch/kernel/time.c b/arch/loongarch/kernel/time.c index fd5354f9be7c..46d7d40c87e3 100644 --- a/arch/loongarch/kernel/time.c +++ b/arch/loongarch/kernel/time.c @@ -15,6 +15,7 @@ #include #include +#include #include u64 cpu_clock_freq; @@ -214,4 +215,5 @@ void __init time_init(void) constant_clockevent_init(); constant_clocksource_init(); + pv_time_init(); } diff --git a/arch/loongarch/kvm/Kconfig b/arch/loongarch/kvm/Kconfig index c4ef2b4d9797..248744b4d086 100644 --- a/arch/loongarch/kvm/Kconfig +++ b/arch/loongarch/kvm/Kconfig @@ -29,6 +29,7 @@ config KVM select KVM_MMIO select HAVE_KVM_READONLY_MEM select KVM_XFER_TO_GUEST_WORK + select SCHED_INFO help Support hosting virtualized guest machines using hardware virtualization extensions. You will need diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c index a68573e091c0..ea73f9dc2cc6 100644 --- a/arch/loongarch/kvm/exit.c +++ b/arch/loongarch/kvm/exit.c @@ -24,7 +24,7 @@ static int kvm_emu_cpucfg(struct kvm_vcpu *vcpu, larch_inst inst) { int rd, rj; - unsigned int index; + unsigned int index, ret; if (inst.reg2_format.opcode != cpucfg_op) return EMULATE_FAIL; @@ -50,7 +50,10 @@ static int kvm_emu_cpucfg(struct kvm_vcpu *vcpu, larch_inst inst) vcpu->arch.gprs[rd] = *(unsigned int *)KVM_SIGNATURE; break; case CPUCFG_KVM_FEATURE: - vcpu->arch.gprs[rd] = KVM_FEATURE_IPI; + ret = KVM_FEATURE_IPI; + if (kvm_pvtime_supported()) + ret |= KVM_FEATURE_STEAL_TIME; + vcpu->arch.gprs[rd] = ret; break; default: vcpu->arch.gprs[rd] = 0; @@ -687,6 +690,34 @@ static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu) return RESUME_GUEST; } +static long kvm_save_notify(struct kvm_vcpu *vcpu) +{ + unsigned long id, data; + + id = kvm_read_reg(vcpu, LOONGARCH_GPR_A1); + data = kvm_read_reg(vcpu, LOONGARCH_GPR_A2); + switch (id) { + case KVM_FEATURE_STEAL_TIME: + if (!kvm_pvtime_supported()) + return KVM_HCALL_INVALID_CODE; + + if (data & ~(KVM_STEAL_PHYS_MASK | KVM_STEAL_PHYS_VALID)) + return KVM_HCALL_INVALID_PARAMETER; + + vcpu->arch.st.guest_addr = data; + if (!(data & KVM_STEAL_PHYS_VALID)) + break; + + vcpu->arch.st.last_steal = current->sched_info.run_delay; + kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu); + break; + default: + break; + }; + + return 0; +}; + /* * kvm_handle_lsx_disabled() - Guest used LSX while disabled in root. * @vcpu: Virtual CPU context. @@ -758,6 +789,9 @@ static void kvm_handle_service(struct kvm_vcpu *vcpu) kvm_send_pv_ipi(vcpu); ret = KVM_HCALL_SUCCESS; break; + case KVM_HCALL_FUNC_NOTIFY: + ret = kvm_save_notify(vcpu); + break; default: ret = KVM_HCALL_INVALID_CODE; break; diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c index 86a2f2d0cb27..844736b99d38 100644 --- a/arch/loongarch/kvm/main.c +++ b/arch/loongarch/kvm/main.c @@ -242,6 +242,7 @@ void kvm_check_vpid(struct kvm_vcpu *vcpu) kvm_update_vpid(vcpu, cpu); trace_kvm_vpid_change(vcpu, vcpu->arch.vpid); vcpu->cpu = cpu; + kvm_clear_request(KVM_REQ_TLB_FLUSH_GPA, vcpu); } /* Restore GSTAT(0x50).vpid */ diff --git a/arch/loongarch/kvm/mmu.c b/arch/loongarch/kvm/mmu.c index 98883aa23ab8..2634a9e8d82c 100644 --- a/arch/loongarch/kvm/mmu.c +++ b/arch/loongarch/kvm/mmu.c @@ -163,6 +163,7 @@ static kvm_pte_t *kvm_populate_gpa(struct kvm *kvm, child = kvm_mmu_memory_cache_alloc(cache); _kvm_pte_init(child, ctx.invalid_ptes[ctx.level - 1]); + smp_wmb(); /* Make pte visible before pmd */ kvm_set_pte(entry, __pa(child)); } else if (kvm_pte_huge(*entry)) { return entry; @@ -444,6 +445,17 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, enum kvm_mr_change change) { int needs_flush; + u32 old_flags = old ? old->flags : 0; + u32 new_flags = new ? new->flags : 0; + bool log_dirty_pages = new_flags & KVM_MEM_LOG_DIRTY_PAGES; + + /* Only track memslot flags changed */ + if (change != KVM_MR_FLAGS_ONLY) + return; + + /* Discard dirty page tracking on readonly memslot */ + if ((old_flags & new_flags) & KVM_MEM_READONLY) + return; /* * If dirty page logging is enabled, write protect all pages in the slot @@ -454,9 +466,14 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, * MOVE/DELETE: The old mappings will already have been cleaned up by * kvm_arch_flush_shadow_memslot() */ - if (change == KVM_MR_FLAGS_ONLY && - (!(old->flags & KVM_MEM_LOG_DIRTY_PAGES) && - new->flags & KVM_MEM_LOG_DIRTY_PAGES)) { + if (!(old_flags & KVM_MEM_LOG_DIRTY_PAGES) && log_dirty_pages) { + /* + * Initially-all-set does not require write protecting any page + * because they're all assumed to be dirty. + */ + if (kvm_dirty_log_manual_protect_and_init_set(kvm)) + return; + spin_lock(&kvm->mmu_lock); /* Write protect GPA page table entries */ needs_flush = kvm_mkclean_gpa_pt(kvm, new->base_gfn, @@ -540,6 +557,7 @@ static int kvm_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa, bool writ gfn_t gfn = gpa >> PAGE_SHIFT; struct kvm *kvm = vcpu->kvm; struct kvm_memory_slot *slot; + struct page *page; spin_lock(&kvm->mmu_lock); @@ -551,10 +569,8 @@ static int kvm_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa, bool writ } /* Track access to pages marked old */ - new = *ptep; - if (!kvm_pte_young(new)) - new = kvm_pte_mkyoung(new); - /* call kvm_set_pfn_accessed() after unlock */ + new = kvm_pte_mkyoung(*ptep); + /* call kvm_set_pfn_accessed() after unlock */ if (write && !kvm_pte_dirty(new)) { if (!kvm_pte_write(new)) { @@ -582,19 +598,22 @@ static int kvm_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa, bool writ if (changed) { kvm_set_pte(ptep, new); pfn = kvm_pte_pfn(new); + page = kvm_pfn_to_refcounted_page(pfn); + if (page) + get_page(page); } spin_unlock(&kvm->mmu_lock); - /* - * Fixme: pfn may be freed after mmu_lock - * kvm_try_get_pfn(pfn)/kvm_release_pfn pair to prevent this? - */ - if (kvm_pte_young(changed)) - kvm_set_pfn_accessed(pfn); + if (changed) { + if (kvm_pte_young(changed)) + kvm_set_pfn_accessed(pfn); - if (kvm_pte_dirty(changed)) { - mark_page_dirty(kvm, gfn); - kvm_set_pfn_dirty(pfn); + if (kvm_pte_dirty(changed)) { + mark_page_dirty(kvm, gfn); + kvm_set_pfn_dirty(pfn); + } + if (page) + put_page(page); } return ret; out: @@ -737,6 +756,7 @@ static kvm_pte_t *kvm_split_huge(struct kvm_vcpu *vcpu, kvm_pte_t *ptep, gfn_t g val += PAGE_SIZE; } + smp_wmb(); /* Make pte visible before pmd */ /* The later kvm_flush_tlb_gpa() will flush hugepage tlb */ kvm_set_pte(ptep, __pa(child)); @@ -858,10 +878,20 @@ retry: /* Disable dirty logging on HugePages */ level = 0; - if (!fault_supports_huge_mapping(memslot, hva, write)) { - level = 0; - } else { + if (fault_supports_huge_mapping(memslot, hva, write)) { + /* Check page level about host mmu*/ level = host_pfn_mapping_level(kvm, gfn, memslot); + if (level == 1) { + /* + * Check page level about secondary mmu + * Disable hugepage if it is normal page on + * secondary mmu already + */ + ptep = kvm_populate_gpa(kvm, NULL, gpa, 0); + if (ptep && !kvm_pte_huge(*ptep)) + level = 0; + } + if (level == 1) { gfn = gfn & ~(PTRS_PER_PTE - 1); pfn = pfn & ~(PTRS_PER_PTE - 1); @@ -892,7 +922,6 @@ retry: kvm_set_pfn_dirty(pfn); } - kvm_set_pfn_accessed(pfn); kvm_release_pfn_clean(pfn); out: srcu_read_unlock(&kvm->srcu, srcu_idx); @@ -908,7 +937,8 @@ int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long gpa, bool write) return ret; /* Invalidate this entry in the TLB */ - kvm_flush_tlb_gpa(vcpu, gpa); + vcpu->arch.flush_gpa = gpa; + kvm_make_request(KVM_REQ_TLB_FLUSH_GPA, vcpu); return 0; } diff --git a/arch/loongarch/kvm/tlb.c b/arch/loongarch/kvm/tlb.c index 02535df6b51f..ebdbe9264e9c 100644 --- a/arch/loongarch/kvm/tlb.c +++ b/arch/loongarch/kvm/tlb.c @@ -23,10 +23,7 @@ void kvm_flush_tlb_all(void) void kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa) { - unsigned long flags; - - local_irq_save(flags); + lockdep_assert_irqs_disabled(); gpa &= (PAGE_MASK << 1); invtlb(INVTLB_GID_ADDR, read_csr_gstat() & CSR_GSTAT_GID, gpa); - local_irq_restore(flags); } diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c index 9e8030d45129..16756ffb55e8 100644 --- a/arch/loongarch/kvm/vcpu.c +++ b/arch/loongarch/kvm/vcpu.c @@ -31,6 +31,50 @@ const struct kvm_stats_header kvm_vcpu_stats_header = { sizeof(kvm_vcpu_stats_desc), }; +static void kvm_update_stolen_time(struct kvm_vcpu *vcpu) +{ + u32 version; + u64 steal; + gpa_t gpa; + struct kvm_memslots *slots; + struct kvm_steal_time __user *st; + struct gfn_to_hva_cache *ghc; + + ghc = &vcpu->arch.st.cache; + gpa = vcpu->arch.st.guest_addr; + if (!(gpa & KVM_STEAL_PHYS_VALID)) + return; + + gpa &= KVM_STEAL_PHYS_MASK; + slots = kvm_memslots(vcpu->kvm); + if (slots->generation != ghc->generation || gpa != ghc->gpa) { + if (kvm_gfn_to_hva_cache_init(vcpu->kvm, ghc, gpa, sizeof(*st))) { + ghc->gpa = INVALID_GPA; + return; + } + } + + st = (struct kvm_steal_time __user *)ghc->hva; + unsafe_get_user(version, &st->version, out); + if (version & 1) + version += 1; /* first time write, random junk */ + + version += 1; + unsafe_put_user(version, &st->version, out); + smp_wmb(); + + unsafe_get_user(steal, &st->steal, out); + steal += current->sched_info.run_delay - vcpu->arch.st.last_steal; + vcpu->arch.st.last_steal = current->sched_info.run_delay; + unsafe_put_user(steal, &st->steal, out); + + smp_wmb(); + version += 1; + unsafe_put_user(version, &st->version, out); +out: + mark_page_dirty_in_slot(vcpu->kvm, ghc->memslot, gpa_to_gfn(ghc->gpa)); +} + /* * kvm_check_requests - check and handle pending vCPU requests * @@ -48,9 +92,22 @@ static int kvm_check_requests(struct kvm_vcpu *vcpu) if (kvm_dirty_ring_check_request(vcpu)) return RESUME_HOST; + if (kvm_check_request(KVM_REQ_STEAL_UPDATE, vcpu)) + kvm_update_stolen_time(vcpu); + return RESUME_GUEST; } +static void kvm_late_check_requests(struct kvm_vcpu *vcpu) +{ + lockdep_assert_irqs_disabled(); + if (kvm_check_request(KVM_REQ_TLB_FLUSH_GPA, vcpu)) + if (vcpu->arch.flush_gpa != INVALID_GPA) { + kvm_flush_tlb_gpa(vcpu, vcpu->arch.flush_gpa); + vcpu->arch.flush_gpa = INVALID_GPA; + } +} + /* * Check and handle pending signal and vCPU requests etc * Run with irq enabled and preempt enabled @@ -101,6 +158,13 @@ static int kvm_pre_enter_guest(struct kvm_vcpu *vcpu) /* Make sure the vcpu mode has been written */ smp_store_mb(vcpu->mode, IN_GUEST_MODE); kvm_check_vpid(vcpu); + + /* + * Called after function kvm_check_vpid() + * Since it updates CSR.GSTAT used by kvm_flush_tlb_gpa(), + * and it may also clear KVM_REQ_TLB_FLUSH_GPA pending bit + */ + kvm_late_check_requests(vcpu); vcpu->arch.host_eentry = csr_read64(LOONGARCH_CSR_EENTRY); /* Clear KVM_LARCH_SWCSR_LATEST as CSR will change when enter guest */ vcpu->arch.aux_inuse &= ~KVM_LARCH_SWCSR_LATEST; @@ -354,6 +418,17 @@ static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val) return -EINVAL; if (id == LOONGARCH_CSR_ESTAT) { + preempt_disable(); + vcpu_load(vcpu); + /* + * Sync pending interrupts into ESTAT so that interrupt + * remains during VM migration stage + */ + kvm_deliver_intr(vcpu); + vcpu->arch.aux_inuse &= ~KVM_LARCH_SWCSR_LATEST; + vcpu_put(vcpu); + preempt_enable(); + /* ESTAT IP0~IP7 get from GINTC */ gintc = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_GINTC) & 0xff; *val = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_ESTAT) | (gintc << 2); @@ -662,6 +737,16 @@ static int kvm_loongarch_cpucfg_has_attr(struct kvm_vcpu *vcpu, return -ENXIO; } +static int kvm_loongarch_pvtime_has_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + if (!kvm_pvtime_supported() || + attr->attr != KVM_LOONGARCH_VCPU_PVTIME_GPA) + return -ENXIO; + + return 0; +} + static int kvm_loongarch_vcpu_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) { @@ -671,6 +756,9 @@ static int kvm_loongarch_vcpu_has_attr(struct kvm_vcpu *vcpu, case KVM_LOONGARCH_VCPU_CPUCFG: ret = kvm_loongarch_cpucfg_has_attr(vcpu, attr); break; + case KVM_LOONGARCH_VCPU_PVTIME_CTRL: + ret = kvm_loongarch_pvtime_has_attr(vcpu, attr); + break; default: break; } @@ -678,7 +766,7 @@ static int kvm_loongarch_vcpu_has_attr(struct kvm_vcpu *vcpu, return ret; } -static int kvm_loongarch_get_cpucfg_attr(struct kvm_vcpu *vcpu, +static int kvm_loongarch_cpucfg_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) { int ret = 0; @@ -694,6 +782,23 @@ static int kvm_loongarch_get_cpucfg_attr(struct kvm_vcpu *vcpu, return ret; } +static int kvm_loongarch_pvtime_get_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + u64 gpa; + u64 __user *user = (u64 __user *)attr->addr; + + if (!kvm_pvtime_supported() || + attr->attr != KVM_LOONGARCH_VCPU_PVTIME_GPA) + return -ENXIO; + + gpa = vcpu->arch.st.guest_addr; + if (put_user(gpa, user)) + return -EFAULT; + + return 0; +} + static int kvm_loongarch_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) { @@ -701,7 +806,10 @@ static int kvm_loongarch_vcpu_get_attr(struct kvm_vcpu *vcpu, switch (attr->group) { case KVM_LOONGARCH_VCPU_CPUCFG: - ret = kvm_loongarch_get_cpucfg_attr(vcpu, attr); + ret = kvm_loongarch_cpucfg_get_attr(vcpu, attr); + break; + case KVM_LOONGARCH_VCPU_PVTIME_CTRL: + ret = kvm_loongarch_pvtime_get_attr(vcpu, attr); break; default: break; @@ -716,6 +824,43 @@ static int kvm_loongarch_cpucfg_set_attr(struct kvm_vcpu *vcpu, return -ENXIO; } +static int kvm_loongarch_pvtime_set_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + int idx, ret = 0; + u64 gpa, __user *user = (u64 __user *)attr->addr; + struct kvm *kvm = vcpu->kvm; + + if (!kvm_pvtime_supported() || + attr->attr != KVM_LOONGARCH_VCPU_PVTIME_GPA) + return -ENXIO; + + if (get_user(gpa, user)) + return -EFAULT; + + if (gpa & ~(KVM_STEAL_PHYS_MASK | KVM_STEAL_PHYS_VALID)) + return -EINVAL; + + if (!(gpa & KVM_STEAL_PHYS_VALID)) { + vcpu->arch.st.guest_addr = gpa; + return 0; + } + + /* Check the address is in a valid memslot */ + idx = srcu_read_lock(&kvm->srcu); + if (kvm_is_error_hva(gfn_to_hva(kvm, gpa >> PAGE_SHIFT))) + ret = -EINVAL; + srcu_read_unlock(&kvm->srcu, idx); + + if (!ret) { + vcpu->arch.st.guest_addr = gpa; + vcpu->arch.st.last_steal = current->sched_info.run_delay; + kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu); + } + + return ret; +} + static int kvm_loongarch_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) { @@ -725,6 +870,9 @@ static int kvm_loongarch_vcpu_set_attr(struct kvm_vcpu *vcpu, case KVM_LOONGARCH_VCPU_CPUCFG: ret = kvm_loongarch_cpucfg_set_attr(vcpu, attr); break; + case KVM_LOONGARCH_VCPU_PVTIME_CTRL: + ret = kvm_loongarch_pvtime_set_attr(vcpu, attr); + break; default: break; } @@ -994,6 +1142,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) struct loongarch_csrs *csr; vcpu->arch.vpid = 0; + vcpu->arch.flush_gpa = INVALID_GPA; hrtimer_init(&vcpu->arch.swtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED); vcpu->arch.swtimer.function = kvm_swtimer_wakeup; @@ -1084,6 +1233,7 @@ static int _kvm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) /* Control guest page CCA attribute */ change_csr_gcfg(CSR_GCFG_MATC_MASK, CSR_GCFG_MATC_ROOT); + kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu); /* Don't bother restoring registers multiple times unless necessary */ if (vcpu->arch.aux_inuse & KVM_LARCH_HWCSR_USABLE) @@ -1266,7 +1416,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) kvm_complete_iocsr_read(vcpu, run); } - if (run->immediate_exit) + if (!vcpu->wants_to_run) return r; /* Clear exit_reason */ diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index 5c145b67d3bf..bca37ddf974b 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms @@ -8,6 +8,7 @@ platform-$(CONFIG_BCM47XX) += bcm47xx/ platform-$(CONFIG_BCM63XX) += bcm63xx/ platform-$(CONFIG_BMIPS_GENERIC) += bmips/ platform-$(CONFIG_CAVIUM_OCTEON_SOC) += cavium-octeon/ +platform-$(CONFIG_EYEQ) += mobileye/ platform-$(CONFIG_MIPS_COBALT) += cobalt/ platform-$(CONFIG_MACH_DECSTATION) += dec/ platform-$(CONFIG_MIPS_GENERIC) += generic/ @@ -17,7 +18,6 @@ platform-$(CONFIG_MACH_LOONGSON2EF) += loongson2ef/ platform-$(CONFIG_MACH_LOONGSON32) += loongson32/ platform-$(CONFIG_MACH_LOONGSON64) += loongson64/ platform-$(CONFIG_MIPS_MALTA) += mti-malta/ -platform-$(CONFIG_MACH_EYEQ5) += mobileye/ platform-$(CONFIG_MACH_NINTENDO64) += n64/ platform-$(CONFIG_PIC32MZDA) += pic32/ platform-$(CONFIG_RALINK) += ralink/ diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index f1aa1bf11166..28af3d9e6bc0 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -30,7 +30,7 @@ config MIPS select BUILDTIME_TABLE_SORT select CLONE_BACKWARDS select CPU_NO_EFFICIENT_FFS if (TARGET_ISA_REV < 1) - select CPU_PM if CPU_IDLE + select CPU_PM if CPU_IDLE || SUSPEND select GENERIC_ATOMIC64 if !64BIT select GENERIC_CMOS_UPDATE select GENERIC_CPU_AUTOPROBE @@ -575,8 +575,8 @@ config MACH_PIC32 Microchip PIC32 is a family of general-purpose 32 bit MIPS core microcontrollers. -config MACH_EYEQ5 - bool "Mobileye EyeQ5 SoC" +config EYEQ + bool "Mobileye EyeQ SoC" select MACH_GENERIC_CORE select ARM_AMBA select PHYSICAL_START_BOOL @@ -615,7 +615,7 @@ config MACH_EYEQ5 select USB_UHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN select USE_OF help - Select this to build a kernel supporting EyeQ5 SoC from Mobileye. + Select this to build a kernel supporting EyeQ SoC from Mobileye. bool @@ -667,6 +667,7 @@ config MACH_REALTEK_RTL select BOOT_RAW select PINCTRL select USE_OF + select REALTEK_OTTO_TIMER config SGI_IP22 bool "SGI IP22 (Indy/Indigo2)" @@ -1021,6 +1022,7 @@ source "arch/mips/generic/Kconfig" source "arch/mips/ingenic/Kconfig" source "arch/mips/jazz/Kconfig" source "arch/mips/lantiq/Kconfig" +source "arch/mips/mobileye/Kconfig" source "arch/mips/pic32/Kconfig" source "arch/mips/ralink/Kconfig" source "arch/mips/sgi-ip27/Kconfig" @@ -1083,6 +1085,7 @@ config CSRC_IOASIC config CSRC_R4K select CLOCKSOURCE_WATCHDOG if CPU_FREQ + select HAVE_UNSTABLE_SCHED_CLOCK if SMP && 64BIT bool config CSRC_SB1250 diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 80aecba24892..5785a3d5ccfb 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -170,7 +170,7 @@ cflags-$(CONFIG_CPU_NEVADA) += $(call cc-option,-march=rm5200,-march=mips4) \ -Wa,--trap cflags-$(CONFIG_CPU_RM7000) += $(call cc-option,-march=rm7000,-march=mips4) \ -Wa,--trap -cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-march=sb1,-march=mips64r1) \ +cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-march=sb1,-march=mips64) \ -Wa,--trap cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-mno-mdmx) cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-mno-mips3d) diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c index d4ab34b3b404..da74cae6b43a 100644 --- a/arch/mips/alchemy/common/platform.c +++ b/arch/mips/alchemy/common/platform.c @@ -409,8 +409,8 @@ static void __init alchemy_setup_macs(int ctype) if (alchemy_get_macs(ctype) < 1) return; - macres = kmemdup(au1xxx_eth0_resources[ctype], - sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL); + macres = kmemdup_array(au1xxx_eth0_resources[ctype], MAC_RES_COUNT, + sizeof(*macres), GFP_KERNEL); if (!macres) { printk(KERN_INFO "Alchemy: no memory for MAC0 resources\n"); return; @@ -430,8 +430,8 @@ static void __init alchemy_setup_macs(int ctype) if (alchemy_get_macs(ctype) < 2) return; - macres = kmemdup(au1xxx_eth1_resources[ctype], - sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL); + macres = kmemdup_array(au1xxx_eth1_resources[ctype], MAC_RES_COUNT, + sizeof(*macres), GFP_KERNEL); if (!macres) { printk(KERN_INFO "Alchemy: no memory for MAC1 resources\n"); return; diff --git a/arch/mips/alchemy/devboards/db1000.c b/arch/mips/alchemy/devboards/db1000.c index 7b9f91db227f..6984cd5169b5 100644 --- a/arch/mips/alchemy/devboards/db1000.c +++ b/arch/mips/alchemy/devboards/db1000.c @@ -10,15 +10,16 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include -#include #include #include #include @@ -374,22 +375,20 @@ static struct platform_device db1100_mmc1_dev = { /******************************************************************************/ -static struct ads7846_platform_data db1100_touch_pd = { - .model = 7846, - .vref_mv = 3300, +static const struct software_node db1100_alchemy2_gpiochip = { + .name = "alchemy-gpio2", }; -static struct spi_gpio_platform_data db1100_spictl_pd = { - .num_chipselect = 1, +static const struct property_entry db1100_ads7846_properties[] = { + PROPERTY_ENTRY_U16("ti,vref_min", 3300), + PROPERTY_ENTRY_GPIO("pendown-gpios", + &db1100_alchemy2_gpiochip, 21, GPIO_ACTIVE_LOW), + { } }; -static struct gpiod_lookup_table db1100_touch_gpio_table = { - .dev_id = "spi0.0", - .table = { - GPIO_LOOKUP("alchemy-gpio2", 21, - "pendown", GPIO_ACTIVE_LOW), - { } - }, +static const struct software_node db1100_ads7846_swnode = { + .name = "ads7846", + .properties = db1100_ads7846_properties, }; static struct spi_board_info db1100_spi_info[] __initdata = { @@ -400,37 +399,37 @@ static struct spi_board_info db1100_spi_info[] __initdata = { .chip_select = 0, .mode = 0, .irq = AU1100_GPIO21_INT, - .platform_data = &db1100_touch_pd, + .swnode = &db1100_ads7846_swnode, }, }; -static struct platform_device db1100_spi_dev = { - .name = "spi_gpio", - .id = 0, - .dev = { - .platform_data = &db1100_spictl_pd, - .dma_mask = &au1xxx_all_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, +static const struct spi_gpio_platform_data db1100_spictl_pd __initconst = { + .num_chipselect = 1, }; /* * Alchemy GPIO 2 has its base at 200 so the GPIO lines * 207 thru 210 are GPIOs at offset 7 thru 10 at this chip. */ -static struct gpiod_lookup_table db1100_spi_gpiod_table = { - .dev_id = "spi_gpio", - .table = { - GPIO_LOOKUP("alchemy-gpio2", 9, - "sck", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("alchemy-gpio2", 8, - "mosi", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("alchemy-gpio2", 7, - "miso", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("alchemy-gpio2", 10, - "cs", GPIO_ACTIVE_HIGH), - { }, - }, +static const struct property_entry db1100_spi_dev_properties[] __initconst = { + PROPERTY_ENTRY_GPIO("miso-gpios", + &db1100_alchemy2_gpiochip, 7, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("mosi-gpios", + &db1100_alchemy2_gpiochip, 8, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("sck-gpios", + &db1100_alchemy2_gpiochip, 9, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("cs-gpios", + &db1100_alchemy2_gpiochip, 10, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct platform_device_info db1100_spi_dev_info __initconst = { + .name = "spi_gpio", + .id = 0, + .data = &db1100_spictl_pd, + .size_data = sizeof(db1100_spictl_pd), + .dma_mask = DMA_BIT_MASK(32), + .properties = db1100_spi_dev_properties, }; static struct platform_device *db1x00_devs[] = { @@ -452,8 +451,10 @@ int __init db1000_dev_setup(void) { int board = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)); int c0, c1, d0, d1, s0, s1, flashsize = 32, twosocks = 1; + int err; unsigned long pfc; struct clk *c, *p; + struct platform_device *spi_dev; if (board == BCSR_WHOAMI_DB1500) { c0 = AU1500_GPIO2_INT; @@ -480,7 +481,7 @@ int __init db1000_dev_setup(void) pfc |= (1 << 0); /* SSI0 pins as GPIOs */ alchemy_wrsys(pfc, AU1000_SYS_PINFUNC); - gpiod_add_lookup_table(&db1100_touch_gpio_table); + software_node_register(&db1100_alchemy2_gpiochip); spi_register_board_info(db1100_spi_info, ARRAY_SIZE(db1100_spi_info)); @@ -497,8 +498,11 @@ int __init db1000_dev_setup(void) clk_put(p); platform_add_devices(db1100_devs, ARRAY_SIZE(db1100_devs)); - gpiod_add_lookup_table(&db1100_spi_gpiod_table); - platform_device_register(&db1100_spi_dev); + + spi_dev = platform_device_register_full(&db1100_spi_dev_info); + err = PTR_ERR_OR_ZERO(spi_dev); + if (err) + pr_err("failed to register SPI controller: %d\n", err); } else if (board == BCSR_WHOAMI_DB1000) { c0 = AU1000_GPIO2_INT; c1 = AU1000_GPIO5_INT; diff --git a/arch/mips/bcm47xx/prom.c b/arch/mips/bcm47xx/prom.c index 58fb7c2dc3b8..66e3ee2b04e6 100644 --- a/arch/mips/bcm47xx/prom.c +++ b/arch/mips/bcm47xx/prom.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -110,6 +111,8 @@ static __init void prom_init_mem(void) void __init prom_init(void) { + /* Cache CBR addr before CPU/DMA setup */ + bmips_cbr_addr = BMIPS_GET_CBR(); prom_init_mem(); setup_8250_early_printk_port(CKSEG1ADDR(BCM47XX_SERIAL_ADDR), 0, 0); } diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 94bf839576c1..247be207f293 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,13 @@ #include #include +/* + * CBR addr doesn't change and we can cache it. + * For broken SoC/Bootloader CBR addr might also be provided via DT + * with "brcm,bmips-cbr-reg" in the "cpus" node. + */ +void __iomem *bmips_cbr_addr __read_mostly; + union bcm47xx_bus bcm47xx_bus; EXPORT_SYMBOL(bcm47xx_bus); diff --git a/arch/mips/bcm63xx/prom.c b/arch/mips/bcm63xx/prom.c index c3a2ea62c5c3..f21dd168171a 100644 --- a/arch/mips/bcm63xx/prom.c +++ b/arch/mips/bcm63xx/prom.c @@ -22,6 +22,9 @@ void __init prom_init(void) { u32 reg, mask; + /* Cache CBR addr before CPU/DMA setup */ + bmips_cbr_addr = BMIPS_GET_CBR(); + bcm63xx_cpu_init(); /* stop any running watchdog */ diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c index c13ddb544a23..81529084bc75 100644 --- a/arch/mips/bcm63xx/setup.c +++ b/arch/mips/bcm63xx/setup.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,13 @@ #include #include +/* + * CBR addr doesn't change and we can cache it. + * For broken SoC/Bootloader CBR addr might also be provided via DT + * with "brcm,bmips-cbr-reg" in the "cpus" node. + */ +void __iomem *bmips_cbr_addr __read_mostly; + void bcm63xx_machine_halt(void) { pr_info("System halted\n"); diff --git a/arch/mips/bmips/dma.c b/arch/mips/bmips/dma.c index 3779e7855bd7..2bc9c0d4402f 100644 --- a/arch/mips/bmips/dma.c +++ b/arch/mips/bmips/dma.c @@ -9,7 +9,7 @@ bool bmips_rac_flush_disable; void arch_sync_dma_for_cpu_all(void) { - void __iomem *cbr = BMIPS_GET_CBR(); + void __iomem *cbr = bmips_cbr_addr; u32 cfg; if (boot_cpu_type() != CPU_BMIPS3300 && diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c index 66a8ba19c287..2572fd49a6e9 100644 --- a/arch/mips/bmips/setup.c +++ b/arch/mips/bmips/setup.c @@ -34,6 +34,13 @@ #define REG_BCM6328_OTP ((void __iomem *)CKSEG1ADDR(0x1000062c)) #define BCM6328_TP1_DISABLED BIT(9) +/* + * CBR addr doesn't change and we can cache it. + * For broken SoC/Bootloader CBR addr might also be provided via DT + * with "brcm,bmips-cbr-reg" in the "cpus" node. + */ +void __iomem *bmips_cbr_addr __read_mostly; + extern bool bmips_rac_flush_disable; static const unsigned long kbase = VMLINUX_LOAD_ADDRESS & 0xfff00000; @@ -111,7 +118,7 @@ static void bcm6358_quirks(void) * because the bootloader is not initializing it properly. */ bmips_rac_flush_disable = !!(read_c0_brcm_cmt_local() & (1 << 31)) || - !!BMIPS_GET_CBR(); + !!bmips_cbr_addr; } static void bcm6368_quirks(void) @@ -144,6 +151,8 @@ static void __init bmips_init_cfe(void) void __init prom_init(void) { + /* Cache CBR addr before CPU/DMA setup */ + bmips_cbr_addr = BMIPS_GET_CBR(); bmips_init_cfe(); bmips_cpu_setup(); register_bmips_smp_ops(); @@ -203,13 +212,35 @@ void __init plat_mem_setup(void) void __init device_tree_init(void) { struct device_node *np; + u32 addr; unflatten_and_copy_device_tree(); /* Disable SMP boot unless both CPUs are listed in DT and !disabled */ np = of_find_node_by_name(NULL, "cpus"); - if (np && of_get_available_child_count(np) <= 1) + if (!np) + return; + + if (of_get_available_child_count(np) <= 1) bmips_smp_enabled = 0; + + /* Check if DT provide a CBR address */ + if (of_property_read_u32(np, "brcm,bmips-cbr-reg", &addr)) + goto exit; + + /* Make sure CBR address is outside DRAM window */ + if (addr >= (u32)memblock_start_of_DRAM() && + addr < (u32)memblock_end_of_DRAM()) { + WARN(1, "DT CBR %x inside DRAM window. Ignoring DT CBR.\n", + addr); + goto exit; + } + + bmips_cbr_addr = (void __iomem *)addr; + /* Since CBR is provided by DT, enable RAC flush */ + bmips_rac_flush_disable = false; + +exit: of_node_put(np); } diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile index efff87cb33a9..e2476b12bb0c 100644 --- a/arch/mips/boot/dts/Makefile +++ b/arch/mips/boot/dts/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 subdir-$(CONFIG_BMIPS_GENERIC) += brcm subdir-$(CONFIG_CAVIUM_OCTEON_SOC) += cavium-octeon +subdir-$(CONFIG_EYEQ) += mobileye subdir-$(CONFIG_FIT_IMAGE_FDT_MARDUK) += img subdir-$(CONFIG_FIT_IMAGE_FDT_BOSTON) += img subdir-$(CONFIG_MACH_INGENIC) += ingenic @@ -8,7 +9,6 @@ subdir-$(CONFIG_LANTIQ) += lantiq subdir-$(CONFIG_MACH_LOONGSON64) += loongson subdir-$(CONFIG_SOC_VCOREIII) += mscc subdir-$(CONFIG_MIPS_MALTA) += mti -subdir-$(CONFIG_MACH_EYEQ5) += mobileye subdir-$(CONFIG_LEGACY_BOARD_SEAD3) += mti subdir-$(CONFIG_FIT_IMAGE_FDT_NI169445) += ni subdir-$(CONFIG_MACH_PIC32) += pic32 diff --git a/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi b/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi index ee3e2153dd13..cc7747c5f21f 100644 --- a/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi +++ b/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi @@ -23,14 +23,6 @@ }; }; - memory@200000 { - compatible = "memory"; - device_type = "memory"; - reg = <0x00000000 0x00200000 0x00000000 0x0ee00000>, /* 238 MB at 2 MB */ - <0x00000000 0x20000000 0x00000000 0x1f000000>, /* 496 MB at 512 MB */ - <0x00000001 0x10000000 0x00000001 0xb0000000>; /* 6912 MB at 4352MB */ - }; - cpu_clk: cpu_clk { #clock-cells = <0>; compatible = "fixed-clock"; @@ -52,6 +44,13 @@ 0 0x40000000 0 0x40000000 0 0x40000000 0xfe 0x00000000 0xfe 0x00000000 0 0x40000000>; + isa@18000000 { + compatible = "isa"; + #size-cells = <1>; + #address-cells = <2>; + ranges = <1 0x0 0x0 0x18000000 0x4000>; + }; + pm: reset-controller@1fe07000 { compatible = "loongson,ls2k-pm"; reg = <0 0x1fe07000 0 0x422>; @@ -100,8 +99,8 @@ rtc0: rtc@1fe07800 { compatible = "loongson,ls2k1000-rtc"; reg = <0 0x1fe07800 0 0x78>; - interrupt-parent = <&liointc0>; - interrupts = <60 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&liointc1>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; }; uart0: serial@1fe00000 { @@ -109,7 +108,7 @@ reg = <0 0x1fe00000 0 0x8>; clock-frequency = <125000000>; interrupt-parent = <&liointc0>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; no-loopback-test; }; @@ -118,7 +117,6 @@ device_type = "pci"; #address-cells = <3>; #size-cells = <2>; - #interrupt-cells = <2>; reg = <0 0x1a000000 0 0x02000000>, <0xfe 0x00000000 0 0x20000000>; @@ -133,11 +131,12 @@ "pciclass0c03"; reg = <0x1800 0x0 0x0 0x0 0x0>; - interrupts = <12 IRQ_TYPE_LEVEL_LOW>, - <13 IRQ_TYPE_LEVEL_LOW>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, + <13 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq", "eth_lpi"; interrupt-parent = <&liointc0>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; + phy-handle = <&phy1>; mdio { #address-cells = <1>; #size-cells = <0>; @@ -156,11 +155,12 @@ "loongson, pci-gmac"; reg = <0x1900 0x0 0x0 0x0 0x0>; - interrupts = <14 IRQ_TYPE_LEVEL_LOW>, - <15 IRQ_TYPE_LEVEL_LOW>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH>, + <15 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq", "eth_lpi"; interrupt-parent = <&liointc0>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; + phy-handle = <&phy1>; mdio { #address-cells = <1>; #size-cells = <0>; @@ -178,7 +178,7 @@ "pciclass0c03"; reg = <0x2100 0x0 0x0 0x0 0x0>; - interrupts = <18 IRQ_TYPE_LEVEL_LOW>; + interrupts = <18 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&liointc1>; }; @@ -189,7 +189,7 @@ "pciclass0c03"; reg = <0x2200 0x0 0x0 0x0 0x0>; - interrupts = <19 IRQ_TYPE_LEVEL_LOW>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&liointc1>; }; @@ -200,97 +200,121 @@ "pciclass0106"; reg = <0x4000 0x0 0x0 0x0 0x0>; - interrupts = <19 IRQ_TYPE_LEVEL_LOW>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&liointc0>; }; - pci_bridge@9,0 { + pcie@9,0 { compatible = "pci0014,7a19.0", "pci0014,7a19", "pciclass060400", "pciclass0604"; reg = <0x4800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&liointc1>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &liointc1 0 IRQ_TYPE_LEVEL_LOW>; + interrupt-map = <0 0 0 0 &liointc1 0 IRQ_TYPE_LEVEL_HIGH>; + ranges; external-facing; }; - pci_bridge@a,0 { + pcie@a,0 { compatible = "pci0014,7a09.0", "pci0014,7a09", "pciclass060400", "pciclass0604"; reg = <0x5000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; - interrupts = <1 IRQ_TYPE_LEVEL_LOW>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&liointc1>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &liointc1 1 IRQ_TYPE_LEVEL_LOW>; + interrupt-map = <0 0 0 0 &liointc1 1 IRQ_TYPE_LEVEL_HIGH>; + ranges; external-facing; }; - pci_bridge@b,0 { + pcie@b,0 { compatible = "pci0014,7a09.0", "pci0014,7a09", "pciclass060400", "pciclass0604"; reg = <0x5800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&liointc1>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &liointc1 2 IRQ_TYPE_LEVEL_LOW>; + interrupt-map = <0 0 0 0 &liointc1 2 IRQ_TYPE_LEVEL_HIGH>; + ranges; external-facing; }; - pci_bridge@c,0 { + pcie@c,0 { compatible = "pci0014,7a09.0", "pci0014,7a09", "pciclass060400", "pciclass0604"; reg = <0x6000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; - interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&liointc1>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &liointc1 3 IRQ_TYPE_LEVEL_LOW>; + interrupt-map = <0 0 0 0 &liointc1 3 IRQ_TYPE_LEVEL_HIGH>; + ranges; external-facing; }; - pci_bridge@d,0 { + pcie@d,0 { compatible = "pci0014,7a19.0", "pci0014,7a19", "pciclass060400", "pciclass0604"; reg = <0x6800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; - interrupts = <4 IRQ_TYPE_LEVEL_LOW>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&liointc1>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &liointc1 4 IRQ_TYPE_LEVEL_LOW>; + interrupt-map = <0 0 0 0 &liointc1 4 IRQ_TYPE_LEVEL_HIGH>; + ranges; external-facing; }; - pci_bridge@e,0 { + pcie@e,0 { compatible = "pci0014,7a09.0", "pci0014,7a09", "pciclass060400", "pciclass0604"; reg = <0x7000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; - interrupts = <5 IRQ_TYPE_LEVEL_LOW>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&liointc1>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &liointc1 5 IRQ_TYPE_LEVEL_LOW>; + interrupt-map = <0 0 0 0 &liointc1 5 IRQ_TYPE_LEVEL_HIGH>; + ranges; external-facing; }; diff --git a/arch/mips/boot/dts/loongson/loongson64g_4core_ls7a.dts b/arch/mips/boot/dts/loongson/loongson64g_4core_ls7a.dts index c945f8565d54..fb180cb2b8e2 100644 --- a/arch/mips/boot/dts/loongson/loongson64g_4core_ls7a.dts +++ b/arch/mips/boot/dts/loongson/loongson64g_4core_ls7a.dts @@ -33,6 +33,7 @@ compatible = "loongson,pch-msi-1.0"; reg = <0 0x2ff00000 0 0x8>; interrupt-controller; + #interrupt-cells = <1>; msi-controller; loongson,msi-base-vec = <64>; loongson,msi-num-vecs = <192>; diff --git a/arch/mips/boot/dts/mobileye/Makefile b/arch/mips/boot/dts/mobileye/Makefile index 01c01c3aad81..7cc89968aaac 100644 --- a/arch/mips/boot/dts/mobileye/Makefile +++ b/arch/mips/boot/dts/mobileye/Makefile @@ -2,3 +2,4 @@ # Copyright 2023 Mobileye Vision Technologies Ltd. dtb-$(CONFIG_MACH_EYEQ5) += eyeq5-epm5.dtb +dtb-$(CONFIG_MACH_EYEQ6H) += eyeq6h-epm6.dtb diff --git a/arch/mips/boot/dts/mobileye/eyeq5-fixed-clocks.dtsi b/arch/mips/boot/dts/mobileye/eyeq5-clocks.dtsi similarity index 88% rename from arch/mips/boot/dts/mobileye/eyeq5-fixed-clocks.dtsi rename to arch/mips/boot/dts/mobileye/eyeq5-clocks.dtsi index 78f5533a95c6..17a342cc744e 100644 --- a/arch/mips/boot/dts/mobileye/eyeq5-fixed-clocks.dtsi +++ b/arch/mips/boot/dts/mobileye/eyeq5-clocks.dtsi @@ -3,42 +3,20 @@ * Copyright 2023 Mobileye Vision Technologies Ltd. */ +#include + / { /* Fixed clock */ - pll_cpu: pll-cpu { + xtal: xtal { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <1500000000>; - }; - - pll_vdi: pll-vdi { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <1280000000>; - }; - - pll_per: pll-per { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <2000000000>; - }; - - pll_ddr0: pll-ddr0 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <1857210000>; - }; - - pll_ddr1: pll-ddr1 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <1857210000>; + clock-frequency = <30000000>; }; /* PLL_CPU derivatives */ occ_cpu: occ-cpu { compatible = "fixed-factor-clock"; - clocks = <&pll_cpu>; + clocks = <&olb EQ5C_PLL_CPU>; #clock-cells = <0>; clock-div = <1>; clock-mult = <1>; @@ -101,7 +79,7 @@ }; occ_isram: occ-isram { compatible = "fixed-factor-clock"; - clocks = <&pll_cpu>; + clocks = <&olb EQ5C_PLL_CPU>; #clock-cells = <0>; clock-div = <2>; clock-mult = <1>; @@ -115,7 +93,7 @@ }; occ_dbu: occ-dbu { compatible = "fixed-factor-clock"; - clocks = <&pll_cpu>; + clocks = <&olb EQ5C_PLL_CPU>; #clock-cells = <0>; clock-div = <10>; clock-mult = <1>; @@ -130,7 +108,7 @@ /* PLL_VDI derivatives */ occ_vdi: occ-vdi { compatible = "fixed-factor-clock"; - clocks = <&pll_vdi>; + clocks = <&olb EQ5C_PLL_VDI>; #clock-cells = <0>; clock-div = <2>; clock-mult = <1>; @@ -144,7 +122,7 @@ }; occ_can_ser: occ-can-ser { compatible = "fixed-factor-clock"; - clocks = <&pll_vdi>; + clocks = <&olb EQ5C_PLL_VDI>; #clock-cells = <0>; clock-div = <16>; clock-mult = <1>; @@ -158,7 +136,7 @@ }; i2c_ser_clk: i2c-ser-clk { compatible = "fixed-factor-clock"; - clocks = <&pll_vdi>; + clocks = <&olb EQ5C_PLL_VDI>; #clock-cells = <0>; clock-div = <20>; clock-mult = <1>; @@ -166,7 +144,7 @@ /* PLL_PER derivatives */ occ_periph: occ-periph { compatible = "fixed-factor-clock"; - clocks = <&pll_per>; + clocks = <&olb EQ5C_PLL_PER>; #clock-cells = <0>; clock-div = <16>; clock-mult = <1>; @@ -225,7 +203,7 @@ }; emmc_sys_clk: emmc-sys-clk { compatible = "fixed-factor-clock"; - clocks = <&pll_per>; + clocks = <&olb EQ5C_PLL_PER>; #clock-cells = <0>; clock-div = <10>; clock-mult = <1>; @@ -233,7 +211,7 @@ }; ccf_ctrl_clk: ccf-ctrl-clk { compatible = "fixed-factor-clock"; - clocks = <&pll_per>; + clocks = <&olb EQ5C_PLL_PER>; #clock-cells = <0>; clock-div = <4>; clock-mult = <1>; @@ -241,7 +219,7 @@ }; occ_mjpeg_core: occ-mjpeg-core { compatible = "fixed-factor-clock"; - clocks = <&pll_per>; + clocks = <&olb EQ5C_PLL_PER>; #clock-cells = <0>; clock-div = <2>; clock-mult = <1>; @@ -265,7 +243,7 @@ }; fcmu_a_clk: fcmu-a-clk { compatible = "fixed-factor-clock"; - clocks = <&pll_per>; + clocks = <&olb EQ5C_PLL_PER>; #clock-cells = <0>; clock-div = <20>; clock-mult = <1>; @@ -273,7 +251,7 @@ }; occ_pci_sys: occ-pci-sys { compatible = "fixed-factor-clock"; - clocks = <&pll_per>; + clocks = <&olb EQ5C_PLL_PER>; #clock-cells = <0>; clock-div = <8>; clock-mult = <1>; diff --git a/arch/mips/boot/dts/mobileye/eyeq5-pins.dtsi b/arch/mips/boot/dts/mobileye/eyeq5-pins.dtsi new file mode 100644 index 000000000000..0b3671013ab4 --- /dev/null +++ b/arch/mips/boot/dts/mobileye/eyeq5-pins.dtsi @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +/* + * Default pin configuration for Mobileye EyeQ5 boards. We mostly create one + * pin configuration node per function. + */ + +&olb { + timer0_pins: timer0-pins { + function = "timer0"; + pins = "PA0", "PA1"; + }; + timer1_pins: timer1-pins { + function = "timer1"; + pins = "PA2", "PA3"; + }; + timer2_pins: timer2-pins { + function = "timer2"; + pins = "PA4", "PA5"; + }; + pps0_pins: pps0-pin { + function = "timer2"; + pins = "PA4"; + }; + pps1_pins: pps1-pin { + function = "timer2"; + pins = "PA5"; + }; + timer5_ext_pins: timer5-ext-pins { + function = "timer5"; + pins = "PA6", "PA7", "PA8", "PA9"; + }; + timer5_ext_input_pins: timer5-ext-input-pins { + function = "timer5"; + pins = "PA6", "PA7"; + }; + timer5_ext_incap_a_pins: timer5-ext-incap-a-pin { + function = "timer5"; + pins = "PA6"; + }; + timer5_ext_incap_b_pins: timer5-ext-incap-b-pin { + function = "timer5"; + pins = "PA7"; + }; + can0_pins: can0-pins { + function = "can0"; + pins = "PA14", "PA15"; + }; + can1_pins: can1-pins { + function = "can1"; + pins = "PA16", "PA17"; + }; + uart0_pins: uart0-pins { + function = "uart0"; + pins = "PA10", "PA11"; + }; + uart1_pins: uart1-pins { + function = "uart1"; + pins = "PA12", "PA13"; + }; + spi0_pins: spi0-pins { + function = "spi0"; + pins = "PA18", "PA19", "PA20", "PA21", "PA22"; + }; + spi1_pins: spi1-pins { + function = "spi1"; + pins = "PA23", "PA24", "PA25", "PA26", "PA27"; + }; + spi1_slave_pins: spi1-slave-pins { + function = "spi1"; + pins = "PA24", "PA25", "PA26"; + }; + refclk0_pins: refclk0-pin { + function = "refclk0"; + pins = "PA28"; + }; + timer3_pins: timer3-pins { + function = "timer3"; + pins = "PB0", "PB1"; + }; + timer4_pins: timer4-pins { + function = "timer4"; + pins = "PB2", "PB3"; + }; + timer6_ext_pins: timer6-ext-pins { + function = "timer6"; + pins = "PB4", "PB5", "PB6", "PB7"; + }; + timer6_ext_input_pins: timer6-ext-input-pins { + function = "timer6"; + pins = "PB4", "PB5"; + }; + timer6_ext_incap_a_pins: timer6-ext-incap-a-pin { + function = "timer6"; + pins = "PB4"; + }; + timer6_ext_incap_b_pins: timer6-ext-incap-b-pin { + function = "timer6"; + pins = "PB5"; + }; + can2_pins: can2-pins { + function = "can2"; + pins = "PB10", "PB11"; + }; + uart2_pins: uart2-pins { + function = "uart2"; + pins = "PB8", "PB9"; + }; + spi2_pins: spi2-pins { + function = "spi2"; + pins = "PB12", "PB13", "PB14", "PB15", "PB16"; + }; + spi3_pins: spi3-pins { + function = "spi3"; + pins = "PB17", "PB18", "PB19", "PB20", "PB21"; + }; + spi3_slave_pins: spi3-slave-pins { + function = "spi3"; + pins = "PB18", "PB19", "PB20"; + }; + mclk0_pins: mclk0-pin { + function = "mclk0"; + pins = "PB22"; + }; +}; diff --git a/arch/mips/boot/dts/mobileye/eyeq5.dtsi b/arch/mips/boot/dts/mobileye/eyeq5.dtsi index 6cc5980e2fa1..0708771c193d 100644 --- a/arch/mips/boot/dts/mobileye/eyeq5.dtsi +++ b/arch/mips/boot/dts/mobileye/eyeq5.dtsi @@ -5,7 +5,7 @@ #include -#include "eyeq5-fixed-clocks.dtsi" +#include "eyeq5-clocks.dtsi" / { #address-cells = <2>; @@ -78,6 +78,9 @@ interrupts = ; clocks = <&uart_clk>, <&occ_periph>; clock-names = "uartclk", "apb_pclk"; + resets = <&olb 0 10>; + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; }; uart1: serial@900000 { @@ -88,6 +91,9 @@ interrupts = ; clocks = <&uart_clk>, <&occ_periph>; clock-names = "uartclk", "apb_pclk"; + resets = <&olb 0 11>; + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; }; uart2: serial@a00000 { @@ -98,6 +104,18 @@ interrupts = ; clocks = <&uart_clk>, <&occ_periph>; clock-names = "uartclk", "apb_pclk"; + resets = <&olb 0 12>; + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + }; + + olb: system-controller@e00000 { + compatible = "mobileye,eyeq5-olb", "syscon"; + reg = <0 0xe00000 0x0 0x400>; + #reset-cells = <2>; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "ref"; }; gic: interrupt-controller@140000 { @@ -122,3 +140,5 @@ }; }; }; + +#include "eyeq5-pins.dtsi" diff --git a/arch/mips/boot/dts/mobileye/eyeq6h-epm6.dts b/arch/mips/boot/dts/mobileye/eyeq6h-epm6.dts new file mode 100644 index 000000000000..ebc0d363fbf8 --- /dev/null +++ b/arch/mips/boot/dts/mobileye/eyeq6h-epm6.dts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Copyright 2024 Mobileye Vision Technologies Ltd. + */ + +/dts-v1/; + +#include "eyeq6h.dtsi" + +/ { + compatible = "mobileye,eyeq6-epm6", "mobileye,eyeq6"; + model = "Mobile EyeQ6H MP6 Evaluation board"; + + chosen { + stdout-path = "serial0:921600n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x1 0x00000000 0x1 0x00000000>; + }; +}; diff --git a/arch/mips/boot/dts/mobileye/eyeq6h-fixed-clocks.dtsi b/arch/mips/boot/dts/mobileye/eyeq6h-fixed-clocks.dtsi new file mode 100644 index 000000000000..5fa99e06fde7 --- /dev/null +++ b/arch/mips/boot/dts/mobileye/eyeq6h-fixed-clocks.dtsi @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Copyright 2023 Mobileye Vision Technologies Ltd. + */ + +#include + +/ { + xtal: clock-30000000 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <30000000>; + }; + + pll_west: clock-2000000000-west { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <2000000000>; + }; + + pll_cpu: clock-2000000000-cpu { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <2000000000>; + }; + + /* pll-cpu derivatives */ + occ_cpu: clock-2000000000-occ-cpu { + compatible = "fixed-factor-clock"; + clocks = <&pll_cpu>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + + /* pll-west derivatives */ + occ_periph_w: clock-200000000 { + compatible = "fixed-factor-clock"; + clocks = <&pll_west>; + #clock-cells = <0>; + clock-div = <10>; + clock-mult = <1>; + }; + uart_clk: clock-200000000-uart { + compatible = "fixed-factor-clock"; + clocks = <&occ_periph_w>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + }; + +}; diff --git a/arch/mips/boot/dts/mobileye/eyeq6h-pins.dtsi b/arch/mips/boot/dts/mobileye/eyeq6h-pins.dtsi new file mode 100644 index 000000000000..a3d1b3684893 --- /dev/null +++ b/arch/mips/boot/dts/mobileye/eyeq6h-pins.dtsi @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Copyright 2024 Mobileye Vision Technologies Ltd. + */ + +/* + * MUX register structure + * bits | field | comment + * [0] | MUX_SEL | 0 - GPIO, 1 - alternative func + * [4] | SW_LOOPBACK| + * [5] | SW_OUT_HZ | + * [7] | DBG_IN | + * [11:8] | DS | drive strength + * [13:12] | PUD | pull-up/pull-down. 0, 3 - no, 1 - PD, 2 - PU + * [14] | OD | Open drain + * [15] | ST_CFG | Hysteretic input enable (Schmitt trigger) + */ + +&pinctrl_west { + // TODO: use pinctrl-single,bias-pullup + // TODO: use pinctrl-single,bias-pulldown + // TODO: use pinctrl-single,drive-strength + // TODO: use pinctrl-single,input-schmitt + + i2c0_pins: i2c0-pins { + pinctrl-single,pins = < + 0x000 0x200 // I2C0_SCL pin + 0x004 0x200 // I2C0_SDA pin + >; + }; + i2c1_pins: i2c1-pins { + pinctrl-single,pins = < + 0x008 0x200 // I2C1_SCL pin + 0x00c 0x200 // I2C1_SDA pin + >; + }; + eth0_pins: eth0-pins { + pinctrl-single,pins = < + 0x080 1 // GPIO_C4__SMA0_MDC pin + 0x084 1 // GPIO_C5__SMA0_MDIO pin + >; + }; + uart0_pins: uart0-pins { + pinctrl-single,pins = <0x0a8 1>; // UART0 pin group + }; + uart1_pins: uart1-pins { + pinctrl-single,pins = <0x0a0 1>; // UART1 pin group + }; + spi0_pins: spi0-pins { + pinctrl-single,pins = <0x0ac 1>; // SPI0 pin group + }; + spi1_pins: spi1-pins { + pinctrl-single,pins = <0x0a4 1>; // SPI1 pin group + }; +}; + +&pinctrl_east { + i2c2_pins: i2c2-pins { + pinctrl-single,pins = < + 0x000 0x200 // i2c2_SCL pin + 0x004 0x200 // i2c2_SDA pin + >; + }; + i2c3_pins: i2c3-pins { + pinctrl-single,pins = < + 0x008 0x200 // i2c3_SCL pin + 0x00c 0x200 // i2c3_SDA pin + >; + }; + eth1_pins: eth1-pins { + pinctrl-single,pins = < + 0x080 1 // GPIO_D4__SMA1_MDC pin + 0x084 1 // GPIO_D5__SMA1_MDIO pin + >; + }; + uart2_sel_pins: uart2-pins { + pinctrl-single,pins = <0x0a4 1>; // UART2 pin group + }; + uart3_pins: uart3-pins { + pinctrl-single,pins = <0x09c 1>; // UART3 pin group + }; + spi2_pins: spi2-pins { + pinctrl-single,pins = <0x0a8 1>; // SPI2 pin group + }; + spi3_pins: spi3-pins { + pinctrl-single,pins = <0x0a0 1>; // SPI3 pin group + }; +}; diff --git a/arch/mips/boot/dts/mobileye/eyeq6h.dtsi b/arch/mips/boot/dts/mobileye/eyeq6h.dtsi new file mode 100644 index 000000000000..1db3c3cda2e3 --- /dev/null +++ b/arch/mips/boot/dts/mobileye/eyeq6h.dtsi @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +/* + * Copyright 2024 Mobileye Vision Technologies Ltd. + */ + +#include + +#include "eyeq6h-fixed-clocks.dtsi" + +/ { + #address-cells = <2>; + #size-cells = <2>; + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + device_type = "cpu"; + compatible = "img,i6500"; + reg = <0>; + clocks = <&occ_cpu>; + }; + }; + + aliases { + serial0 = &uart0; + }; + + cpu_intc: interrupt-controller { + compatible = "mti,cpu-interrupt-controller"; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + soc: soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + uart0: serial@d3331000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0 0xd3331000 0x0 0x1000>; + reg-io-width = <4>; + interrupt-parent = <&gic>; + interrupts = ; + clocks = <&occ_periph_w>, <&occ_periph_w>; + clock-names = "uartclk", "apb_pclk"; + }; + + pinctrl_west: pinctrl@d3337000 { + compatible = "pinctrl-single"; + reg = <0x0 0xd3337000 0x0 0xb0>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffff>; + }; + + pinctrl_east: pinctrl@d3357000 { + compatible = "pinctrl-single"; + reg = <0x0 0xd3357000 0x0 0xb0>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffff>; + }; + + pinctrl_south: pinctrl@d8014000 { + compatible = "pinctrl-single"; + reg = <0x0 0xd8014000 0x0 0xf8>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffff>; + }; + + gic: interrupt-controller@f0920000 { + compatible = "mti,gic"; + reg = <0x0 0xf0920000 0x0 0x20000>; + interrupt-controller; + #interrupt-cells = <3>; + + /* + * Declare the interrupt-parent even though the mti,gic + * binding doesn't require it, such that the kernel can + * figure out that cpu_intc is the root interrupt + * controller & should be probed first. + */ + interrupt-parent = <&cpu_intc>; + + timer { + compatible = "mti,gic-timer"; + interrupts = ; + clocks = <&occ_cpu>; + }; + }; + }; +}; + +#include "eyeq6h-pins.dtsi" diff --git a/arch/mips/boot/dts/realtek/Makefile b/arch/mips/boot/dts/realtek/Makefile index fba4e93187a6..d2709798763f 100644 --- a/arch/mips/boot/dts/realtek/Makefile +++ b/arch/mips/boot/dts/realtek/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 dtb-y += cisco_sg220-26.dtb +dtb-y += cameo-rtl9302c-2x-rtl8224-2xge.dtb diff --git a/arch/mips/boot/dts/realtek/cameo-rtl9302c-2x-rtl8224-2xge.dts b/arch/mips/boot/dts/realtek/cameo-rtl9302c-2x-rtl8224-2xge.dts new file mode 100644 index 000000000000..77d2566545f2 --- /dev/null +++ b/arch/mips/boot/dts/realtek/cameo-rtl9302c-2x-rtl8224-2xge.dts @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/dts-v1/; + +#include "rtl930x.dtsi" + +#include +#include +#include +#include + +/ { + compatible = "cameo,rtl9302c-2x-rtl8224-2xge", "realtek,rtl9302-soc"; + model = "RTL9302C Development Board"; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x8000000>; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&uart0 { + status = "okay"; +}; + +&spi0 { + status = "okay"; + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <10000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "LOADER"; + reg = <0x0 0xe0000>; + read-only; + }; + partition@e0000 { + label = "BDINFO"; + reg = <0xe0000 0x10000>; + }; + partition@f0000 { + label = "SYSINFO"; + reg = <0xf0000 0x10000>; + read-only; + }; + partition@100000 { + label = "JFFS2 CFG"; + reg = <0x100000 0x100000>; + }; + partition@200000 { + label = "JFFS2 LOG"; + reg = <0x200000 0x100000>; + }; + partition@300000 { + label = "RUNTIME"; + reg = <0x300000 0xe80000>; + }; + partition@1180000 { + label = "RUNTIME2"; + reg = <0x1180000 0xe80000>; + }; + }; + }; +}; diff --git a/arch/mips/boot/dts/realtek/rtl838x.dtsi b/arch/mips/boot/dts/realtek/rtl838x.dtsi index 6cc4ff5c0d19..722106e39194 100644 --- a/arch/mips/boot/dts/realtek/rtl838x.dtsi +++ b/arch/mips/boot/dts/realtek/rtl838x.dtsi @@ -6,6 +6,7 @@ #size-cells = <0>; cpu@0 { + device_type = "cpu"; compatible = "mips,mips4KEc"; reg = <0>; clocks = <&baseclk 0>; diff --git a/arch/mips/boot/dts/realtek/rtl83xx.dtsi b/arch/mips/boot/dts/realtek/rtl83xx.dtsi index de65a111b626..03ddc61f7c9e 100644 --- a/arch/mips/boot/dts/realtek/rtl83xx.dtsi +++ b/arch/mips/boot/dts/realtek/rtl83xx.dtsi @@ -22,7 +22,7 @@ #size-cells = <1>; ranges = <0x0 0x18000000 0x10000>; - uart0: uart@2000 { + uart0: serial@2000 { compatible = "ns16550a"; reg = <0x2000 0x100>; @@ -39,7 +39,7 @@ status = "disabled"; }; - uart1: uart@2100 { + uart1: serial@2100 { compatible = "ns16550a"; reg = <0x2100 0x100>; diff --git a/arch/mips/boot/dts/realtek/rtl930x.dtsi b/arch/mips/boot/dts/realtek/rtl930x.dtsi new file mode 100644 index 000000000000..f271940f82be --- /dev/null +++ b/arch/mips/boot/dts/realtek/rtl930x.dtsi @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause + +#include "rtl83xx.dtsi" + +/ { + compatible = "realtek,rtl9302-soc"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "mips,mips34Kc"; + reg = <0>; + clocks = <&baseclk 0>; + clock-names = "cpu"; + }; + }; + + baseclk: clock-800mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <800000000>; + }; + + lx_clk: clock-175mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <175000000>; + }; +}; + +&soc { + intc: interrupt-controller@3000 { + compatible = "realtek,rtl9300-intc", "realtek,rtl-intc"; + reg = <0x3000 0x18>, <0x3018 0x18>; + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpuintc>; + interrupts = <2>, <3>, <4>, <5>, <6>, <7>; + }; + + spi0: spi@1200 { + compatible = "realtek,rtl8380-spi"; + reg = <0x1200 0x100>; + + #address-cells = <1>; + #size-cells = <0>; + }; + + timer0: timer@3200 { + compatible = "realtek,rtl9302-timer", "realtek,otto-timer"; + reg = <0x3200 0x10>, <0x3210 0x10>, <0x3220 0x10>, + <0x3230 0x10>, <0x3240 0x10>; + + interrupt-parent = <&intc>; + interrupts = <7>, <8>, <9>, <10>, <11>; + clocks = <&lx_clk>; + }; +}; + +&uart0 { + /delete-property/ clock-frequency; + clocks = <&lx_clk>; + + interrupt-parent = <&intc>; + interrupts = <30>; +}; + +&uart1 { + /delete-property/ clock-frequency; + clocks = <&lx_clk>; + + interrupt-parent = <&intc>; + interrupts = <31>; +}; + diff --git a/arch/mips/configs/ci20_defconfig b/arch/mips/configs/ci20_defconfig index 7827b2b392f6..90536cab417e 100644 --- a/arch/mips/configs/ci20_defconfig +++ b/arch/mips/configs/ci20_defconfig @@ -122,6 +122,7 @@ CONFIG_IR_GPIO_TX=m CONFIG_MEDIA_SUPPORT=m CONFIG_DRM=m CONFIG_DRM_DISPLAY_CONNECTOR=m +CONFIG_DRM_DW_HDMI=m CONFIG_DRM_INGENIC=m CONFIG_DRM_INGENIC_DW_HDMI=m CONFIG_FB=y diff --git a/arch/mips/configs/db1xxx_defconfig b/arch/mips/configs/db1xxx_defconfig index b2d9253ff786..6eff21ff15d5 100644 --- a/arch/mips/configs/db1xxx_defconfig +++ b/arch/mips/configs/db1xxx_defconfig @@ -12,7 +12,6 @@ CONFIG_MEMCG=y CONFIG_BLK_CGROUP=y CONFIG_CGROUP_SCHED=y CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_CPUACCT=y diff --git a/arch/mips/configs/eyeq5_defconfig b/arch/mips/configs/eyeq5_defconfig index c35c29a4d479..ae9a09b16e40 100644 --- a/arch/mips/configs/eyeq5_defconfig +++ b/arch/mips/configs/eyeq5_defconfig @@ -8,7 +8,6 @@ CONFIG_IKCONFIG_PROC=y CONFIG_MEMCG=y CONFIG_BLK_CGROUP=y CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_PIDS=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y @@ -19,6 +18,7 @@ CONFIG_USER_NS=y CONFIG_SCHED_AUTOGROUP=y CONFIG_BLK_DEV_INITRD=y CONFIG_EXPERT=y +CONFIG_EYEQ=y CONFIG_MACH_EYEQ5=y CONFIG_FIT_IMAGE_FDT_EPM5=y CONFIG_PAGE_SIZE_16KB=y diff --git a/arch/mips/configs/eyeq6_defconfig b/arch/mips/configs/eyeq6_defconfig new file mode 100644 index 000000000000..6597d5e88b33 --- /dev/null +++ b/arch/mips/configs/eyeq6_defconfig @@ -0,0 +1,111 @@ +CONFIG_SYSVIPC=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_SYSCALL=y +CONFIG_TASKSTATS=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_EYEQ=y +CONFIG_MACH_EYEQ6H=y +CONFIG_MIPS_CPS=y +CONFIG_CPU_HAS_MSA=y +CONFIG_NR_CPUS=16 +CONFIG_MIPS_RAW_APPENDED_DTB=y +CONFIG_JUMP_LABEL=y +CONFIG_PAGE_SIZE_16KB=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_TRIM_UNUSED_KSYMS=y +# CONFIG_COMPAT_BRK is not set +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_USERFAULTFD=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_NETFILTER=y +CONFIG_CAN=y +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_DEBUG=y +CONFIG_PCI_ENDPOINT=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BLOCK=y +CONFIG_SCSI=y +CONFIG_NETDEVICES=y +CONFIG_MACVLAN=y +CONFIG_IPVLAN=y +CONFIG_MACB=y +CONFIG_MARVELL_PHY=y +CONFIG_MICREL_PHY=y +CONFIG_CAN_M_CAN=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +# CONFIG_PTP_1588_CLOCK is not set +CONFIG_PINCTRL=y +CONFIG_PINCTRL_SINGLE=y +CONFIG_MFD_SYSCON=y +CONFIG_HID_A4TECH=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_EZKEY=y +CONFIG_HID_ITE=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_REDRAGON=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_RESET_CONTROLLER=y +# CONFIG_NVMEM is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_FS_ENCRYPTION=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_ROOT_NFS=y +CONFIG_CRYPTO_CRC32_MIPS=y +CONFIG_FRAME_WARN=1024 +CONFIG_DEBUG_FS=y +# CONFIG_RCU_TRACE is not set +# CONFIG_FTRACE is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="earlycon" diff --git a/arch/mips/configs/generic/64r6.config b/arch/mips/configs/generic/64r6.config index 5dd8e8503e34..63b4e95f303d 100644 --- a/arch/mips/configs/generic/64r6.config +++ b/arch/mips/configs/generic/64r6.config @@ -3,4 +3,6 @@ CONFIG_64BIT=y CONFIG_MIPS32_O32=y CONFIG_MIPS32_N32=y +CONFIG_CPU_HAS_MSA=y CONFIG_CRYPTO_CRC32_MIPS=y +CONFIG_VIRTUALIZATION=y diff --git a/arch/mips/configs/generic/board-litex.config b/arch/mips/configs/generic/board-litex.config new file mode 100644 index 000000000000..f372d0647bfc --- /dev/null +++ b/arch/mips/configs/generic/board-litex.config @@ -0,0 +1,8 @@ +CONFIG_LITEX_LITEETH=y +CONFIG_SERIAL_LITEUART=y +CONFIG_SERIAL_LITEUART_CONSOLE=y +CONFIG_MMC=y +CONFIG_MMC_LITEX=y +CONFIG_LITEX_SOC_CONTROLLER=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y diff --git a/arch/mips/configs/generic_defconfig b/arch/mips/configs/generic_defconfig index 071e2205c7ed..fa916407bdd4 100644 --- a/arch/mips/configs/generic_defconfig +++ b/arch/mips/configs/generic_defconfig @@ -5,7 +5,6 @@ CONFIG_IKCONFIG_PROC=y CONFIG_MEMCG=y CONFIG_BLK_CGROUP=y CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_PIDS=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y diff --git a/arch/mips/configs/ip30_defconfig b/arch/mips/configs/ip30_defconfig new file mode 100644 index 000000000000..178d61645cea --- /dev/null +++ b/arch/mips/configs/ip30_defconfig @@ -0,0 +1,183 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=15 +CONFIG_CGROUPS=y +CONFIG_CPUSETS=y +CONFIG_RELAY=y +CONFIG_EXPERT=y +CONFIG_SGI_IP30=y +CONFIG_SMP=y +CONFIG_NR_CPUS=2 +CONFIG_HZ_1000=y +CONFIG_MIPS32_O32=y +CONFIG_MIPS32_N32=y +CONFIG_PM=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_SGI_PARTITION=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=m +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_MIP6=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_PIMSM_V2=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=m +CONFIG_NET_CLS_CGROUP=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SKBEDIT=m +# CONFIG_VGA_ARB is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_CDROM_PKTCDVD=m +CONFIG_ATA_OVER_ETH=m +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +CONFIG_BLK_DEV_SR=m +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_SPI_ATTRS=y +CONFIG_SCSI_FC_ATTRS=y +CONFIG_LIBFC=m +CONFIG_SCSI_QLOGIC_1280=y +CONFIG_SCSI_BFA_FC=m +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=m +CONFIG_SCSI_DH_HP_SW=m +CONFIG_SCSI_DH_EMC=m +CONFIG_SCSI_DH_ALUA=m +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_RAID0=y +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=y +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_LOG_USERSPACE=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_QL=m +CONFIG_DM_MULTIPATH_ST=m +CONFIG_DM_UEVENT=y +CONFIG_NETDEVICES=y +CONFIG_SGI_IOC3_ETH=y +CONFIG_INPUT_SPARSEKMAP=y +CONFIG_INPUT_MATRIXKMAP=y +CONFIG_INPUT_EVDEV=y +CONFIG_SERIO_SGI_IOC3=y +CONFIG_SERIO_RAW=m +CONFIG_SERIO_ALTERA_PS2=m +# CONFIG_VT is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_IOC3=y +CONFIG_NOZOMI=m +CONFIG_HW_RANDOM_TIMERIOMEM=m +# CONFIG_PTP_1588_CLOCK is not set +# CONFIG_HWMON is not set +CONFIG_THERMAL=y +CONFIG_SGI_MFD_IOC3=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_M48T35=y +CONFIG_UIO=y +CONFIG_UIO_AEC=m +CONFIG_UIO_SERCOS3=m +CONFIG_UIO_PCI_GENERIC=m +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_XFS_FS=m +CONFIG_XFS_QUOTA=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_FUSE_FS=m +CONFIG_CUSE=m +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_SQUASHFS=m +CONFIG_OMFS_FS=m +CONFIG_NFS_FS=y +CONFIG_SECURITYFS=y +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_LZO=m +CONFIG_CRC_T10DIF=m diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig index 3389e6e885d9..71d6340497c9 100644 --- a/arch/mips/configs/lemote2f_defconfig +++ b/arch/mips/configs/lemote2f_defconfig @@ -12,15 +12,14 @@ CONFIG_LOG_BUF_SHIFT=15 CONFIG_BLK_DEV_INITRD=y CONFIG_EXPERT=y CONFIG_PROFILING=y +CONFIG_KEXEC=y CONFIG_MACH_LOONGSON2EF=y CONFIG_LEMOTE_MACH2F=y -CONFIG_KEXEC=y -# CONFIG_SECCOMP is not set -CONFIG_PCI=y CONFIG_MIPS32_O32=y CONFIG_MIPS32_N32=y CONFIG_HIBERNATION=y CONFIG_PM_STD_PARTITION="/dev/hda3" +# CONFIG_SECCOMP is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y @@ -68,10 +67,10 @@ CONFIG_BT_HIDP=m CONFIG_BT_HCIBTUSB=m CONFIG_BT_HCIBFUSB=m CONFIG_BT_HCIVHCI=m -CONFIG_CFG80211=m -CONFIG_MAC80211=m +CONFIG_CFG80211=y +CONFIG_MAC80211=y CONFIG_MAC80211_LEDS=y -CONFIG_RFKILL=m +CONFIG_RFKILL=y CONFIG_RFKILL_INPUT=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y @@ -83,13 +82,10 @@ CONFIG_ATA=y CONFIG_PATA_AMD=y CONFIG_MD=y CONFIG_BLK_DEV_MD=m -CONFIG_MD_LINEAR=m CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m CONFIG_MD_RAID10=m CONFIG_MD_RAID456=m -CONFIG_MD_MULTIPATH=m -CONFIG_MD_FAULTY=m CONFIG_BLK_DEV_DM=m CONFIG_DM_DEBUG=y CONFIG_DM_CRYPT=m @@ -112,6 +108,10 @@ CONFIG_8139TOO=y CONFIG_R8169=y CONFIG_USB_USBNET=m CONFIG_USB_NET_CDC_EEM=m +CONFIG_RTL8180=m +CONFIG_RTL8187=y +CONFIG_RTL_CARDS=m +CONFIG_RTL8XXXU=m CONFIG_INPUT_EVDEV=y # CONFIG_MOUSE_PS2_ALPS is not set # CONFIG_MOUSE_PS2_LOGIPS2PP is not set @@ -119,27 +119,27 @@ CONFIG_INPUT_EVDEV=y CONFIG_MOUSE_APPLETOUCH=m # CONFIG_SERIO_SERPORT is not set CONFIG_LEGACY_PTY_COUNT=16 -CONFIG_SERIAL_NONSTANDARD=y CONFIG_SERIAL_8250=m # CONFIG_SERIAL_8250_PCI is not set CONFIG_SERIAL_8250_NR_UARTS=16 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_FOURPORT=y +CONFIG_SERIAL_NONSTANDARD=y CONFIG_HW_RANDOM=y CONFIG_GPIO_LOONGSON=y CONFIG_THERMAL=y CONFIG_MEDIA_SUPPORT=m CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y -CONFIG_FB_MODE_HELPERS=y -CONFIG_FB_TILEBLITTING=y CONFIG_FB_SIS=y CONFIG_FB_SIS_300=y CONFIG_FB_SIS_315=y -# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_FB_SIMPLE=y +CONFIG_FB_SM712=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y CONFIG_BACKLIGHT_CLASS_DEVICE=y -# CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y CONFIG_LOGO=y @@ -238,7 +238,6 @@ CONFIG_BTRFS_FS=m CONFIG_QUOTA=y CONFIG_QFMT_V2=m CONFIG_AUTOFS_FS=m -CONFIG_NETFS_SUPPORT=m CONFIG_FSCACHE=y CONFIG_CACHEFILES=m CONFIG_ISO9660_FS=m @@ -247,7 +246,6 @@ CONFIG_ZISOFS=y CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=m CONFIG_NTFS_FS=m -CONFIG_NTFS_RW=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=m @@ -299,29 +297,23 @@ CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_U=m CONFIG_NLS_UTF8=y CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_AUTHENC=m CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_LRW=m -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_XTS=m -CONFIG_CRYPTO_XCBC=m -CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_SHA1=m -CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_ANUBIS=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_FCRYPT=m -CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_DEFLATE=m -CONFIG_CRYPTO_LZO=m CONFIG_FONTS=y CONFIG_FONT_8x8=y CONFIG_FONT_6x11=y diff --git a/arch/mips/crypto/poly1305-glue.c b/arch/mips/crypto/poly1305-glue.c index bc6110fb98e0..867728ee535a 100644 --- a/arch/mips/crypto/poly1305-glue.c +++ b/arch/mips/crypto/poly1305-glue.c @@ -186,6 +186,7 @@ static void __exit mips_poly1305_mod_exit(void) module_init(mips_poly1305_mod_init); module_exit(mips_poly1305_mod_exit); +MODULE_DESCRIPTION("Poly1305 transform (MIPS accelerated"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS_CRYPTO("poly1305"); MODULE_ALIAS_CRYPTO("poly1305-mips"); diff --git a/arch/mips/generic/Makefile b/arch/mips/generic/Makefile index 56011d738441..ea0e4ad5e600 100644 --- a/arch/mips/generic/Makefile +++ b/arch/mips/generic/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_LEGACY_BOARD_SEAD3) += board-sead3.o obj-$(CONFIG_LEGACY_BOARD_OCELOT) += board-ocelot.o obj-$(CONFIG_MACH_INGENIC) += board-ingenic.o obj-$(CONFIG_VIRT_BOARD_RANCHU) += board-ranchu.o +obj-$(CONFIG_MACH_REALTEK_RTL) += board-realtek.o diff --git a/arch/mips/generic/board-realtek.c b/arch/mips/generic/board-realtek.c new file mode 100644 index 000000000000..9cce6103d24e --- /dev/null +++ b/arch/mips/generic/board-realtek.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 Allied Telesis + */ + +#include +#include +#include +#include + +#include +#include + +static __init int realtek_add_initrd(void *fdt) +{ + int node, err; + u32 start, size; + + node = fdt_path_offset(fdt, "/chosen"); + if (node < 0) { + pr_err("/chosen node not found\n"); + return -ENOENT; + } + + start = fw_getenvl("initrd_start"); + size = fw_getenvl("initrd_size"); + + if (start == 0 && size == 0) + return 0; + + pr_info("Adding initrd info from environment\n"); + + err = fdt_setprop_u32(fdt, node, "linux,initrd-start", start); + if (err) { + pr_err("unable to set initrd-start: %d\n", err); + return err; + } + + err = fdt_setprop_u32(fdt, node, "linux,initrd-end", start + size); + if (err) { + pr_err("unable to set initrd-end: %d\n", err); + return err; + } + + return 0; +} + +static const struct mips_fdt_fixup realtek_fdt_fixups[] __initconst = { + { realtek_add_initrd, "add initrd" }, + {}, +}; + +static __init const void *realtek_fixup_fdt(const void *fdt, const void *match_data) +{ + static unsigned char fdt_buf[16 << 10] __initdata; + int err; + + if (fdt_check_header(fdt)) + panic("Corrupt DT"); + + fw_init_cmdline(); + + err = apply_mips_fdt_fixups(fdt_buf, sizeof(fdt_buf), fdt, realtek_fdt_fixups); + if (err) + panic("Unable to fixup FDT: %d", err); + + return fdt_buf; + +} + +static const struct of_device_id realtek_of_match[] __initconst = { + { .compatible = "realtek,rtl9302-soc" }, + {} +}; + +MIPS_MACHINE(realtek) = { + .matches = realtek_of_match, + .fixup_fdt = realtek_fixup_fdt, +}; diff --git a/arch/mips/include/asm/bmips.h b/arch/mips/include/asm/bmips.h index 581a6a3c66e4..3a1cdfddb987 100644 --- a/arch/mips/include/asm/bmips.h +++ b/arch/mips/include/asm/bmips.h @@ -81,6 +81,7 @@ extern char bmips_smp_movevec[]; extern char bmips_smp_int_vec[]; extern char bmips_smp_int_vec_end[]; +extern void __iomem *bmips_cbr_addr; extern int bmips_smp_enabled; extern int bmips_cpu_offset; extern cpumask_t bmips_booted_mask; diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h index 86310d6e1035..bc5ac9887d09 100644 --- a/arch/mips/include/asm/fpu.h +++ b/arch/mips/include/asm/fpu.h @@ -129,6 +129,18 @@ static inline int __own_fpu(void) if (ret) return ret; + if (current->thread.fpu.fcr31 & FPU_CSR_NAN2008) { + if (!cpu_has_nan_2008) { + ret = SIGFPE; + goto failed; + } + } else { + if (!cpu_has_nan_legacy) { + ret = SIGFPE; + goto failed; + } + } + KSTK_STATUS(current) |= ST0_CU1; if (mode == FPU_64BIT || mode == FPU_HYBRID) KSTK_STATUS(current) |= ST0_FR; @@ -137,6 +149,9 @@ static inline int __own_fpu(void) set_thread_flag(TIF_USEDFPU); return 0; +failed: + __disable_fpu(); + return ret; } static inline int own_fpu_inatomic(int restore) diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index 179f320cc231..6743a57c1ab4 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h @@ -890,7 +890,6 @@ static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot) {} static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {} -static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {} diff --git a/arch/mips/include/asm/mach-loongson64/boot_param.h b/arch/mips/include/asm/mach-loongson64/boot_param.h index e007edd6b60a..9218b3ae3383 100644 --- a/arch/mips/include/asm/mach-loongson64/boot_param.h +++ b/arch/mips/include/asm/mach-loongson64/boot_param.h @@ -42,12 +42,14 @@ enum loongson_cpu_type { Legacy_1B = 0x5, Legacy_2G = 0x6, Legacy_2H = 0x7, + Legacy_2K = 0x8, Loongson_1A = 0x100, Loongson_1B = 0x101, Loongson_2E = 0x200, Loongson_2F = 0x201, Loongson_2G = 0x202, Loongson_2H = 0x203, + Loongson_2K = 0x204, Loongson_3A = 0x300, Loongson_3B = 0x301 }; diff --git a/arch/mips/include/asm/mips-cps.h b/arch/mips/include/asm/mips-cps.h index c077e8d100f5..917009b80e69 100644 --- a/arch/mips/include/asm/mips-cps.h +++ b/arch/mips/include/asm/mips-cps.h @@ -8,6 +8,7 @@ #define __MIPS_ASM_MIPS_CPS_H__ #include +#include #include #include @@ -228,4 +229,42 @@ static inline unsigned int mips_cps_numvps(unsigned int cluster, unsigned int co return FIELD_GET(CM_GCR_Cx_CONFIG_PVPE, cfg + 1); } +/** + * mips_cps_multicluster_cpus() - Detect whether CPUs are in multiple clusters + * + * Determine whether the system includes CPUs in multiple clusters - ie. + * whether we can treat the system as single or multi-cluster as far as CPUs + * are concerned. Note that this is slightly different to simply checking + * whether multiple clusters are present - it is possible for there to be + * clusters which contain no CPUs, which this function will effectively ignore. + * + * Returns true if CPUs are spread across multiple clusters, else false. + */ +static inline bool mips_cps_multicluster_cpus(void) +{ + unsigned int first_cl, last_cl; + + /* + * CPUs are numbered sequentially by cluster - ie. CPUs 0..X will be in + * cluster 0, CPUs X+1..Y in cluster 1, CPUs Y+1..Z in cluster 2 etc. + * + * Thus we can detect multiple clusters trivially by checking whether + * the first & last CPUs belong to the same cluster. + */ + first_cl = cpu_cluster(&boot_cpu_data); + last_cl = cpu_cluster(&cpu_data[nr_cpu_ids - 1]); + return first_cl != last_cl; +} + +/** + * mips_cps_first_online_in_cluster() - Detect if CPU is first online in cluster + * + * Determine whether the local CPU is the first to be brought online in its + * cluster - that is, whether there are any other online CPUs in the local + * cluster. + * + * Returns true if this CPU is first online, else false. + */ +extern unsigned int mips_cps_first_online_in_cluster(void); + #endif /* __MIPS_ASM_MIPS_CPS_H__ */ diff --git a/arch/mips/include/asm/mips-gic.h b/arch/mips/include/asm/mips-gic.h index 084cac1c5ea2..fd9da5e3beaa 100644 --- a/arch/mips/include/asm/mips-gic.h +++ b/arch/mips/include/asm/mips-gic.h @@ -28,11 +28,13 @@ extern void __iomem *mips_gic_base; /* For read-only shared registers */ #define GIC_ACCESSOR_RO(sz, off, name) \ - CPS_ACCESSOR_RO(gic, sz, MIPS_GIC_SHARED_OFS + off, name) + CPS_ACCESSOR_RO(gic, sz, MIPS_GIC_SHARED_OFS + off, name) \ + CPS_ACCESSOR_RO(gic, sz, MIPS_GIC_REDIR_OFS + off, redir_##name) /* For read-write shared registers */ #define GIC_ACCESSOR_RW(sz, off, name) \ - CPS_ACCESSOR_RW(gic, sz, MIPS_GIC_SHARED_OFS + off, name) + CPS_ACCESSOR_RW(gic, sz, MIPS_GIC_SHARED_OFS + off, name) \ + CPS_ACCESSOR_RW(gic, sz, MIPS_GIC_REDIR_OFS + off, redir_##name) /* For read-only local registers */ #define GIC_VX_ACCESSOR_RO(sz, off, name) \ @@ -45,7 +47,7 @@ extern void __iomem *mips_gic_base; CPS_ACCESSOR_RW(gic, sz, MIPS_GIC_REDIR_OFS + off, vo_##name) /* For read-only shared per-interrupt registers */ -#define GIC_ACCESSOR_RO_INTR_REG(sz, off, stride, name) \ +#define _GIC_ACCESSOR_RO_INTR_REG(sz, off, stride, name) \ static inline void __iomem *addr_gic_##name(unsigned int intr) \ { \ return mips_gic_base + (off) + (intr * (stride)); \ @@ -58,8 +60,8 @@ static inline unsigned int read_gic_##name(unsigned int intr) \ } /* For read-write shared per-interrupt registers */ -#define GIC_ACCESSOR_RW_INTR_REG(sz, off, stride, name) \ - GIC_ACCESSOR_RO_INTR_REG(sz, off, stride, name) \ +#define _GIC_ACCESSOR_RW_INTR_REG(sz, off, stride, name) \ + _GIC_ACCESSOR_RO_INTR_REG(sz, off, stride, name) \ \ static inline void write_gic_##name(unsigned int intr, \ unsigned int val) \ @@ -68,22 +70,30 @@ static inline void write_gic_##name(unsigned int intr, \ __raw_writel(val, addr_gic_##name(intr)); \ } +#define GIC_ACCESSOR_RO_INTR_REG(sz, off, stride, name) \ + _GIC_ACCESSOR_RO_INTR_REG(sz, off, stride, name) \ + _GIC_ACCESSOR_RO_INTR_REG(sz, MIPS_GIC_REDIR_OFS + off, stride, redir_##name) + +#define GIC_ACCESSOR_RW_INTR_REG(sz, off, stride, name) \ + _GIC_ACCESSOR_RW_INTR_REG(sz, off, stride, name) \ + _GIC_ACCESSOR_RW_INTR_REG(sz, MIPS_GIC_REDIR_OFS + off, stride, redir_##name) + /* For read-only local per-interrupt registers */ #define GIC_VX_ACCESSOR_RO_INTR_REG(sz, off, stride, name) \ - GIC_ACCESSOR_RO_INTR_REG(sz, MIPS_GIC_LOCAL_OFS + off, \ + _GIC_ACCESSOR_RO_INTR_REG(sz, MIPS_GIC_LOCAL_OFS + off, \ stride, vl_##name) \ - GIC_ACCESSOR_RO_INTR_REG(sz, MIPS_GIC_REDIR_OFS + off, \ + _GIC_ACCESSOR_RO_INTR_REG(sz, MIPS_GIC_REDIR_OFS + off, \ stride, vo_##name) /* For read-write local per-interrupt registers */ #define GIC_VX_ACCESSOR_RW_INTR_REG(sz, off, stride, name) \ - GIC_ACCESSOR_RW_INTR_REG(sz, MIPS_GIC_LOCAL_OFS + off, \ + _GIC_ACCESSOR_RW_INTR_REG(sz, MIPS_GIC_LOCAL_OFS + off, \ stride, vl_##name) \ - GIC_ACCESSOR_RW_INTR_REG(sz, MIPS_GIC_REDIR_OFS + off, \ + _GIC_ACCESSOR_RW_INTR_REG(sz, MIPS_GIC_REDIR_OFS + off, \ stride, vo_##name) /* For read-only shared bit-per-interrupt registers */ -#define GIC_ACCESSOR_RO_INTR_BIT(off, name) \ +#define _GIC_ACCESSOR_RO_INTR_BIT(off, name) \ static inline void __iomem *addr_gic_##name(void) \ { \ return mips_gic_base + (off); \ @@ -106,8 +116,8 @@ static inline unsigned int read_gic_##name(unsigned int intr) \ } /* For read-write shared bit-per-interrupt registers */ -#define GIC_ACCESSOR_RW_INTR_BIT(off, name) \ - GIC_ACCESSOR_RO_INTR_BIT(off, name) \ +#define _GIC_ACCESSOR_RW_INTR_BIT(off, name) \ + _GIC_ACCESSOR_RO_INTR_BIT(off, name) \ \ static inline void write_gic_##name(unsigned int intr) \ { \ @@ -146,6 +156,14 @@ static inline void change_gic_##name(unsigned int intr, \ } \ } +#define GIC_ACCESSOR_RO_INTR_BIT(off, name) \ + _GIC_ACCESSOR_RO_INTR_BIT(off, name) \ + _GIC_ACCESSOR_RO_INTR_BIT(MIPS_GIC_REDIR_OFS + off, redir_##name) + +#define GIC_ACCESSOR_RW_INTR_BIT(off, name) \ + _GIC_ACCESSOR_RW_INTR_BIT(off, name) \ + _GIC_ACCESSOR_RW_INTR_BIT(MIPS_GIC_REDIR_OFS + off, redir_##name) + /* For read-only local bit-per-interrupt registers */ #define GIC_VX_ACCESSOR_RO_INTR_BIT(sz, off, name) \ GIC_ACCESSOR_RO_INTR_BIT(sz, MIPS_GIC_LOCAL_OFS + off, \ @@ -155,10 +173,10 @@ static inline void change_gic_##name(unsigned int intr, \ /* For read-write local bit-per-interrupt registers */ #define GIC_VX_ACCESSOR_RW_INTR_BIT(sz, off, name) \ - GIC_ACCESSOR_RW_INTR_BIT(sz, MIPS_GIC_LOCAL_OFS + off, \ - vl_##name) \ - GIC_ACCESSOR_RW_INTR_BIT(sz, MIPS_GIC_REDIR_OFS + off, \ - vo_##name) + _GIC_ACCESSOR_RW_INTR_BIT(sz, MIPS_GIC_LOCAL_OFS + off, \ + vl_##name) \ + _GIC_ACCESSOR_RW_INTR_BIT(sz, MIPS_GIC_REDIR_OFS + off, \ + vo_##name) /* GIC_SH_CONFIG - Information about the GIC configuration */ GIC_ACCESSOR_RW(32, 0x000, config) diff --git a/arch/mips/include/asm/pm.h b/arch/mips/include/asm/pm.h index 10bb7b640738..7ecd4dfe3846 100644 --- a/arch/mips/include/asm/pm.h +++ b/arch/mips/include/asm/pm.h @@ -17,7 +17,7 @@ /* Save CPU state to stack for suspend to RAM */ .macro SUSPEND_SAVE_REGS - subu sp, PT_SIZE + PTR_SUBU sp, PT_SIZE /* Call preserved GPRs */ LONG_S $16, PT_R16(sp) LONG_S $17, PT_R17(sp) @@ -56,13 +56,13 @@ LONG_L $31, PT_R31(sp) /* Pop and return */ jr ra - addiu sp, PT_SIZE + PTR_ADDIU sp, PT_SIZE .set pop .endm /* Get address of static suspend state into t1 */ .macro LA_STATIC_SUSPEND - la t1, mips_static_suspend_state + PTR_LA t1, mips_static_suspend_state .endm /* Save important CPU state for early restoration to global data */ @@ -72,11 +72,11 @@ * Segment configuration is saved in global data where it can be easily * reloaded without depending on the segment configuration. */ - mfc0 k0, CP0_PAGEMASK, 2 /* SegCtl0 */ + mfc0 k0, CP0_SEGCTL0 LONG_S k0, SSS_SEGCTL0(t1) - mfc0 k0, CP0_PAGEMASK, 3 /* SegCtl1 */ + mfc0 k0, CP0_SEGCTL1 LONG_S k0, SSS_SEGCTL1(t1) - mfc0 k0, CP0_PAGEMASK, 4 /* SegCtl2 */ + mfc0 k0, CP0_SEGCTL2 LONG_S k0, SSS_SEGCTL2(t1) #endif /* save stack pointer (pointing to GPRs) */ @@ -92,11 +92,11 @@ * segments. */ LONG_L k0, SSS_SEGCTL0(t1) - mtc0 k0, CP0_PAGEMASK, 2 /* SegCtl0 */ + mtc0 k0, CP0_SEGCTL0 LONG_L k0, SSS_SEGCTL1(t1) - mtc0 k0, CP0_PAGEMASK, 3 /* SegCtl1 */ + mtc0 k0, CP0_SEGCTL1 LONG_L k0, SSS_SEGCTL2(t1) - mtc0 k0, CP0_PAGEMASK, 4 /* SegCtl2 */ + mtc0 k0, CP0_SEGCTL2 tlbw_use_hazard #endif /* restore stack pointer (pointing to GPRs) */ @@ -105,10 +105,10 @@ /* flush caches to make sure context has reached memory */ .macro SUSPEND_CACHE_FLUSH - .extern __wback_cache_all + .extern __flush_cache_all .set push .set noreorder - la t1, __wback_cache_all + PTR_LA t1, __flush_cache_all LONG_L t0, 0(t1) jalr t0 nop diff --git a/arch/mips/include/asm/r4k-timer.h b/arch/mips/include/asm/r4k-timer.h index 6e7361629348..432e61dd5204 100644 --- a/arch/mips/include/asm/r4k-timer.h +++ b/arch/mips/include/asm/r4k-timer.h @@ -12,15 +12,10 @@ #ifdef CONFIG_SYNC_R4K -extern void synchronise_count_master(int cpu); extern void synchronise_count_slave(int cpu); #else -static inline void synchronise_count_master(int cpu) -{ -} - static inline void synchronise_count_slave(int cpu) { } diff --git a/arch/mips/include/asm/sgi/ip22.h b/arch/mips/include/asm/sgi/ip22.h index 87ec9eaa04e3..57942afb5c86 100644 --- a/arch/mips/include/asm/sgi/ip22.h +++ b/arch/mips/include/asm/sgi/ip22.h @@ -76,5 +76,8 @@ extern unsigned short ip22_eeprom_read(unsigned int *ctrl, int reg); extern unsigned short ip22_nvram_read(int reg); +extern void ip22_be_interrupt(int irq); +extern void ip22_be_init(void) __init; +extern void indy_8254timer_irq(void); #endif diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c index edc4afc080fa..bdb1fa8931f4 100644 --- a/arch/mips/kernel/csrc-r4k.c +++ b/arch/mips/kernel/csrc-r4k.c @@ -21,7 +21,9 @@ static struct clocksource clocksource_mips = { .name = "MIPS", .read = c0_hpt_read, .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .flags = CLOCK_SOURCE_IS_CONTINUOUS | + CLOCK_SOURCE_MUST_VERIFY | + CLOCK_SOURCE_VERIFY_PERCPU, }; static u64 __maybe_unused notrace r4k_read_sched_clock(void) @@ -66,6 +68,18 @@ static bool rdhwr_count_usable(void) return false; } +static inline __init bool count_can_be_sched_clock(void) +{ + if (IS_ENABLED(CONFIG_CPU_FREQ)) + return false; + + if (num_possible_cpus() > 1 && + !IS_ENABLED(CONFIG_HAVE_UNSTABLE_SCHED_CLOCK)) + return false; + + return true; +} + #ifdef CONFIG_CPU_FREQ static bool __read_mostly r4k_clock_unstable; @@ -111,7 +125,8 @@ int __init init_r4k_clocksource(void) return -ENXIO; /* Calculate a somewhat reasonable rating value */ - clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; + clocksource_mips.rating = 200; + clocksource_mips.rating += clamp(mips_hpt_frequency / 10000000, 0, 99); /* * R2 onwards makes the count accessible to user mode so it can be used @@ -122,9 +137,8 @@ int __init init_r4k_clocksource(void) clocksource_register_hz(&clocksource_mips, mips_hpt_frequency); -#ifndef CONFIG_CPU_FREQ - sched_clock_register(r4k_read_sched_clock, 32, mips_hpt_frequency); -#endif + if (count_can_be_sched_clock()) + sched_clock_register(r4k_read_sched_clock, 32, mips_hpt_frequency); return 0; } diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index 7aa2c2360ff6..f0e7fe85a42a 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -318,6 +318,10 @@ void mips_set_personality_nan(struct arch_elf_state *state) t->thread.fpu.fcr31 = c->fpu_csr31; switch (state->nan_2008) { case 0: + if (!(c->fpu_msk31 & FPU_CSR_NAN2008)) + t->thread.fpu.fcr31 &= ~FPU_CSR_NAN2008; + if (!(c->fpu_msk31 & FPU_CSR_ABS2008)) + t->thread.fpu.fcr31 &= ~FPU_CSR_ABS2008; break; case 1: if (!(c->fpu_msk31 & FPU_CSR_NAN2008)) diff --git a/arch/mips/kernel/fpu-probe.c b/arch/mips/kernel/fpu-probe.c index e689d6a83234..6bf3f19b1c33 100644 --- a/arch/mips/kernel/fpu-probe.c +++ b/arch/mips/kernel/fpu-probe.c @@ -144,7 +144,7 @@ static void cpu_set_fpu_2008(struct cpuinfo_mips *c) * IEEE 754 conformance mode to use. Affects the NaN encoding and the * ABS.fmt/NEG.fmt execution mode. */ -static enum { STRICT, LEGACY, STD2008, RELAXED } ieee754 = STRICT; +static enum { STRICT, EMULATED, LEGACY, STD2008, RELAXED } ieee754 = STRICT; /* * Set the IEEE 754 NaN encodings and the ABS.fmt/NEG.fmt execution modes @@ -160,6 +160,7 @@ static void cpu_set_nofpu_2008(struct cpuinfo_mips *c) switch (ieee754) { case STRICT: + case EMULATED: if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5 | @@ -204,6 +205,10 @@ static void cpu_set_nan_2008(struct cpuinfo_mips *c) mips_use_nan_legacy = !cpu_has_nan_2008; mips_use_nan_2008 = !!cpu_has_nan_2008; break; + case EMULATED: + /* Pretend ABS2008/NAN2008 options are dynamic */ + c->fpu_msk31 &= ~(FPU_CSR_NAN2008 | FPU_CSR_ABS2008); + fallthrough; case RELAXED: mips_use_nan_legacy = true; mips_use_nan_2008 = true; @@ -226,6 +231,8 @@ static int __init ieee754_setup(char *s) return -1; else if (!strcmp(s, "strict")) ieee754 = STRICT; + else if (!strcmp(s, "emulated")) + ieee754 = EMULATED; else if (!strcmp(s, "legacy")) ieee754 = LEGACY; else if (!strcmp(s, "2008")) diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 3a115fab5573..3eb2cfb893e1 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -512,3 +512,40 @@ void mips_cm_error_report(void) /* reprime cause register */ write_gcr_error_cause(cm_error); } + +unsigned int mips_cps_first_online_in_cluster(void) +{ + unsigned int local_cl; + int i; + + local_cl = cpu_cluster(¤t_cpu_data); + + /* + * We rely upon knowledge that CPUs are numbered sequentially by + * cluster - ie. CPUs 0..X will be in cluster 0, CPUs X+1..Y in cluster + * 1, CPUs Y+1..Z in cluster 2 etc. This means that CPUs in the same + * cluster will immediately precede or follow one another. + * + * First we scan backwards, until we find an online CPU in the cluster + * or we move on to another cluster. + */ + for (i = smp_processor_id() - 1; i >= 0; i--) { + if (cpu_cluster(&cpu_data[i]) != local_cl) + break; + if (!cpu_online(i)) + continue; + return false; + } + + /* Then do the same for higher numbered CPUs */ + for (i = smp_processor_id() + 1; i < nr_cpu_ids; i++) { + if (cpu_cluster(&cpu_data[i]) != local_cl) + break; + if (!cpu_online(i)) + continue; + return false; + } + + /* We found no online CPUs in the local cluster */ + return true; +} diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index b3dbf9ecb0d6..35b8d810833c 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -518,7 +518,7 @@ static void bmips_set_reset_vec(int cpu, u32 val) info.val = val; bmips_set_reset_vec_remote(&info); } else { - void __iomem *cbr = BMIPS_GET_CBR(); + void __iomem *cbr = bmips_cbr_addr; if (cpu == 0) __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_0); @@ -591,7 +591,8 @@ asmlinkage void __weak plat_wired_tlb_setup(void) void bmips_cpu_setup(void) { - void __iomem __maybe_unused *cbr = BMIPS_GET_CBR(); + void __iomem __maybe_unused *cbr = bmips_cbr_addr; + u32 __maybe_unused rac_addr; u32 __maybe_unused cfg; switch (current_cpu_type()) { @@ -620,6 +621,23 @@ void bmips_cpu_setup(void) __raw_readl(cbr + BMIPS_RAC_ADDRESS_RANGE); break; + case CPU_BMIPS4350: + rac_addr = BMIPS_RAC_CONFIG_1; + + if (!(read_c0_brcm_cmt_local() & (1 << 31))) + rac_addr = BMIPS_RAC_CONFIG; + + /* Enable data RAC */ + cfg = __raw_readl(cbr + rac_addr); + __raw_writel(cfg | 0xf, cbr + rac_addr); + __raw_readl(cbr + rac_addr); + + /* Flush stale data out of the readahead cache */ + cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG); + __raw_writel(cfg | 0x100, cbr + BMIPS_RAC_CONFIG); + __raw_readl(cbr + BMIPS_RAC_CONFIG); + break; + case CPU_BMIPS4380: /* CBG workaround for early BMIPS4380 CPUs */ switch (read_c0_prid()) { diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 0b53d35a116e..0362fc5df7b0 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -462,8 +462,6 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) return -EIO; } - synchronise_count_master(cpu); - /* Wait for CPU to finish startup & mark itself online before return */ wait_for_completion(&cpu_running); return 0; diff --git a/arch/mips/kernel/sync-r4k.c b/arch/mips/kernel/sync-r4k.c index abdd7aaa3311..39156592582e 100644 --- a/arch/mips/kernel/sync-r4k.c +++ b/arch/mips/kernel/sync-r4k.c @@ -2,121 +2,244 @@ /* * Count register synchronisation. * - * All CPUs will have their count registers synchronised to the CPU0 next time - * value. This can cause a small timewarp for CPU0. All other CPU's should - * not have done anything significant (but they may have had interrupts - * enabled briefly - prom_smp_finish() should not be responsible for enabling - * interrupts...) + * Derived from arch/x86/kernel/tsc_sync.c + * Copyright (C) 2006, Red Hat, Inc., Ingo Molnar */ #include #include #include +#include +#include +#include +#include #include -#include -#include #include +#include -static unsigned int initcount = 0; -static atomic_t count_count_start = ATOMIC_INIT(0); -static atomic_t count_count_stop = ATOMIC_INIT(0); +#define COUNTON 100 +#define NR_LOOPS 3 +#define LOOP_TIMEOUT 20 -#define COUNTON 100 -#define NR_LOOPS 3 +/* + * Entry/exit counters that make sure that both CPUs + * run the measurement code at once: + */ +static atomic_t start_count; +static atomic_t stop_count; +static atomic_t test_runs; -void synchronise_count_master(int cpu) +/* + * We use a raw spinlock in this exceptional case, because + * we want to have the fastest, inlined, non-debug version + * of a critical section, to be able to prove counter time-warps: + */ +static arch_spinlock_t sync_lock = __ARCH_SPIN_LOCK_UNLOCKED; + +static uint32_t last_counter; +static uint32_t max_warp; +static int nr_warps; +static int random_warps; + +/* + * Counter warp measurement loop running on both CPUs. + */ +static uint32_t check_counter_warp(void) { - int i; - unsigned long flags; + uint32_t start, now, prev, end, cur_max_warp = 0; + int i, cur_warps = 0; - pr_info("Synchronize counters for CPU %u: ", cpu); + start = read_c0_count(); + end = start + (uint32_t) mips_hpt_frequency / 1000 * LOOP_TIMEOUT; - local_irq_save(flags); - - /* - * We loop a few times to get a primed instruction cache, - * then the last pass is more or less synchronised and - * the master and slaves each set their cycle counters to a known - * value all at once. This reduces the chance of having random offsets - * between the processors, and guarantees that the maximum - * delay between the cycle counters is never bigger than - * the latency of information-passing (cachelines) between - * two CPUs. - */ - - for (i = 0; i < NR_LOOPS; i++) { - /* slaves loop on '!= 2' */ - while (atomic_read(&count_count_start) != 1) - mb(); - atomic_set(&count_count_stop, 0); - smp_wmb(); - - /* Let the slave writes its count register */ - atomic_inc(&count_count_start); - - /* Count will be initialised to current timer */ - if (i == 1) - initcount = read_c0_count(); + for (i = 0; ; i++) { + /* + * We take the global lock, measure counter, save the + * previous counter that was measured (possibly on + * another CPU) and update the previous counter timestamp. + */ + arch_spin_lock(&sync_lock); + prev = last_counter; + now = read_c0_count(); + last_counter = now; + arch_spin_unlock(&sync_lock); /* - * Everyone initialises count in the last loop: + * Be nice every now and then (and also check whether + * measurement is done [we also insert a 10 million + * loops safety exit, so we dont lock up in case the + * counter is totally broken]): */ - if (i == NR_LOOPS-1) - write_c0_count(initcount); - + if (unlikely(!(i & 7))) { + if (now > end || i > 10000000) + break; + cpu_relax(); + touch_nmi_watchdog(); + } /* - * Wait for slave to leave the synchronization point: + * Outside the critical section we can now see whether + * we saw a time-warp of the counter going backwards: */ - while (atomic_read(&count_count_stop) != 1) - mb(); - atomic_set(&count_count_start, 0); - smp_wmb(); - atomic_inc(&count_count_stop); + if (unlikely(prev > now)) { + arch_spin_lock(&sync_lock); + max_warp = max(max_warp, prev - now); + cur_max_warp = max_warp; + /* + * Check whether this bounces back and forth. Only + * one CPU should observe time going backwards. + */ + if (cur_warps != nr_warps) + random_warps++; + nr_warps++; + cur_warps = nr_warps; + arch_spin_unlock(&sync_lock); + } } - /* Arrange for an interrupt in a short while */ - write_c0_compare(read_c0_count() + COUNTON); - - local_irq_restore(flags); - - /* - * i386 code reported the skew here, but the - * count registers were almost certainly out of sync - * so no point in alarming people - */ - pr_cont("done.\n"); + WARN(!(now-start), + "Warning: zero counter calibration delta: %d [max: %d]\n", + now-start, end-start); + return cur_max_warp; } +/* + * The freshly booted CPU initiates this via an async SMP function call. + */ +static void check_counter_sync_source(void *__cpu) +{ + unsigned int cpu = (unsigned long)__cpu; + int cpus = 2; + + atomic_set(&test_runs, NR_LOOPS); +retry: + /* Wait for the target to start. */ + while (atomic_read(&start_count) != cpus - 1) + cpu_relax(); + + /* + * Trigger the target to continue into the measurement too: + */ + atomic_inc(&start_count); + + check_counter_warp(); + + while (atomic_read(&stop_count) != cpus-1) + cpu_relax(); + + /* + * If the test was successful set the number of runs to zero and + * stop. If not, decrement the number of runs an check if we can + * retry. In case of random warps no retry is attempted. + */ + if (!nr_warps) { + atomic_set(&test_runs, 0); + + pr_info("Counter synchronization [CPU#%d -> CPU#%u]: passed\n", + smp_processor_id(), cpu); + } else if (atomic_dec_and_test(&test_runs) || random_warps) { + /* Force it to 0 if random warps brought us here */ + atomic_set(&test_runs, 0); + + pr_info("Counter synchronization [CPU#%d -> CPU#%u]:\n", + smp_processor_id(), cpu); + pr_info("Measured %d cycles counter warp between CPUs", max_warp); + if (random_warps) + pr_warn("Counter warped randomly between CPUs\n"); + } + + /* + * Reset it - just in case we boot another CPU later: + */ + atomic_set(&start_count, 0); + random_warps = 0; + nr_warps = 0; + max_warp = 0; + last_counter = 0; + + /* + * Let the target continue with the bootup: + */ + atomic_inc(&stop_count); + + /* + * Retry, if there is a chance to do so. + */ + if (atomic_read(&test_runs) > 0) + goto retry; +} + +/* + * Freshly booted CPUs call into this: + */ void synchronise_count_slave(int cpu) { - int i; - unsigned long flags; + uint32_t cur_max_warp, gbl_max_warp, count; + int cpus = 2; - local_irq_save(flags); + if (!cpu_has_counter || !mips_hpt_frequency) + return; + + /* Kick the control CPU into the counter synchronization function */ + smp_call_function_single(cpumask_first(cpu_online_mask), + check_counter_sync_source, + (unsigned long *)(unsigned long)cpu, 0); +retry: + /* + * Register this CPU's participation and wait for the + * source CPU to start the measurement: + */ + atomic_inc(&start_count); + while (atomic_read(&start_count) != cpus) + cpu_relax(); + + cur_max_warp = check_counter_warp(); /* - * Not every cpu is online at the time this gets called, - * so we first wait for the master to say everyone is ready + * Store the maximum observed warp value for a potential retry: */ + gbl_max_warp = max_warp; - for (i = 0; i < NR_LOOPS; i++) { - atomic_inc(&count_count_start); - while (atomic_read(&count_count_start) != 2) - mb(); + /* + * Ok, we are done: + */ + atomic_inc(&stop_count); - /* - * Everyone initialises count in the last loop: - */ - if (i == NR_LOOPS-1) - write_c0_count(initcount); + /* + * Wait for the source CPU to print stuff: + */ + while (atomic_read(&stop_count) != cpus) + cpu_relax(); - atomic_inc(&count_count_stop); - while (atomic_read(&count_count_stop) != 2) - mb(); + /* + * Reset it for the next sync test: + */ + atomic_set(&stop_count, 0); + + /* + * Check the number of remaining test runs. If not zero, the test + * failed and a retry with adjusted counter is possible. If zero the + * test was either successful or failed terminally. + */ + if (!atomic_read(&test_runs)) { + /* Arrange for an interrupt in a short while */ + write_c0_compare(read_c0_count() + COUNTON); + return; } - /* Arrange for an interrupt in a short while */ - write_c0_compare(read_c0_count() + COUNTON); - local_irq_restore(flags); + /* + * If the warp value of this CPU is 0, then the other CPU + * observed time going backwards so this counter was ahead and + * needs to move backwards. + */ + if (!cur_max_warp) + cur_max_warp = -gbl_max_warp; + + count = read_c0_count(); + count += cur_max_warp; + write_c0_count(count); + + pr_debug("Counter compensate: CPU%u observed %d warp\n", cpu, cur_max_warp); + + goto retry; + } -#undef NR_LOOPS diff --git a/arch/mips/kvm/interrupt.h b/arch/mips/kvm/interrupt.h index e529ea2bb34b..07bc0160bc94 100644 --- a/arch/mips/kvm/interrupt.h +++ b/arch/mips/kvm/interrupt.h @@ -37,3 +37,7 @@ u32 kvm_irq_to_priority(u32 irq); int kvm_mips_pending_timer(struct kvm_vcpu *vcpu); void kvm_mips_deliver_interrupts(struct kvm_vcpu *vcpu, u32 cause); + +#ifdef CONFIG_CPU_LOONGSON64 +extern void kvm_init_loongson_ipi(struct kvm *kvm); +#endif diff --git a/arch/mips/kvm/loongson_ipi.c b/arch/mips/kvm/loongson_ipi.c index 5d53f32d837c..6ac83a31148c 100644 --- a/arch/mips/kvm/loongson_ipi.c +++ b/arch/mips/kvm/loongson_ipi.c @@ -10,6 +10,8 @@ #include +#include "interrupt.h" + #define IPI_BASE 0x3ff01000ULL #define CORE0_STATUS_OFF 0x000 diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 231ac052b506..b5de770b092e 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -135,8 +135,6 @@ void kvm_arch_hardware_disable(void) kvm_mips_callbacks->hardware_disable(); } -extern void kvm_init_loongson_ipi(struct kvm *kvm); - int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) { switch (type) { @@ -436,7 +434,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) vcpu->mmio_needed = 0; } - if (vcpu->run->immediate_exit) + if (!vcpu->wants_to_run) goto out; lose_fpu(1); diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c index 3ed078225222..5a75283d17f1 100644 --- a/arch/mips/lantiq/xway/sysctrl.c +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -247,6 +247,25 @@ static void pmu_disable(struct clk *clk) pr_warn("deactivating PMU module failed!"); } +static void usb_set_clock(void) +{ + unsigned int val = ltq_cgu_r32(ifccr); + + if (of_machine_is_compatible("lantiq,ar10") || + of_machine_is_compatible("lantiq,grx390")) { + val &= ~0x03; /* XTAL divided by 3 */ + } else if (of_machine_is_compatible("lantiq,ar9") || + of_machine_is_compatible("lantiq,vr9")) { + /* TODO: this depends on the XTAL frequency */ + val |= 0x03; /* XTAL divided by 3 */ + } else if (of_machine_is_compatible("lantiq,ase")) { + val |= 0x20; /* from XTAL */ + } else if (of_machine_is_compatible("lantiq,danube")) { + val |= 0x30; /* 12 MHz, generated from 36 MHz */ + } + ltq_cgu_w32(val, ifccr); +} + /* the pci enable helper */ static int pci_enable(struct clk *clk) { @@ -588,4 +607,5 @@ void __init ltq_soc_init(void) clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE); clkdev_add_pmu("1e100400.serial", NULL, 1, 0, PMU_ASC0); } + usb_set_clock(); } diff --git a/arch/mips/loongson64/Makefile b/arch/mips/loongson64/Makefile index e806280bbb85..cbba30dfddf5 100644 --- a/arch/mips/loongson64/Makefile +++ b/arch/mips/loongson64/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_MACH_LOONGSON64) += cop2-ex.o dma.o \ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_NUMA) += numa.o obj-$(CONFIG_RS780_HPET) += hpet.o -obj-$(CONFIG_SUSPEND) += pm.o +obj-$(CONFIG_SUSPEND) += pm.o sleeper.o obj-$(CONFIG_PCI_QUIRKS) += vbios_quirk.o obj-$(CONFIG_CPU_LOONGSON3_CPUCFG_EMULATION) += cpucfg-emul.o obj-$(CONFIG_SYSFS) += boardinfo.o diff --git a/arch/mips/loongson64/dma.c b/arch/mips/loongson64/dma.c index 8220a1bc0db6..52801442ea86 100644 --- a/arch/mips/loongson64/dma.c +++ b/arch/mips/loongson64/dma.c @@ -2,6 +2,7 @@ #include #include #include +#include #include dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) diff --git a/arch/mips/loongson64/env.c b/arch/mips/loongson64/env.c index ef3750a6ffac..09ff05269861 100644 --- a/arch/mips/loongson64/env.c +++ b/arch/mips/loongson64/env.c @@ -88,6 +88,12 @@ void __init prom_lefi_init_env(void) cpu_clock_freq = ecpu->cpu_clock_freq; loongson_sysconf.cputype = ecpu->cputype; switch (ecpu->cputype) { + case Legacy_2K: + case Loongson_2K: + smp_group[0] = 0x900000001fe11000; + loongson_sysconf.cores_per_node = 2; + loongson_sysconf.cores_per_package = 2; + break; case Legacy_3A: case Loongson_3A: loongson_sysconf.cores_per_node = 4; @@ -221,6 +227,8 @@ void __init prom_lefi_init_env(void) default: break; } + } else if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64R) { + loongson_fdt_blob = __dtb_loongson64_2core_2k1000_begin; } else if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64G) { if (loongson_sysconf.bridgetype == LS7A) loongson_fdt_blob = __dtb_loongson64g_4core_ls7a_begin; diff --git a/arch/mips/loongson64/pm.c b/arch/mips/loongson64/pm.c index 7c8556f09781..5f0604af8f13 100644 --- a/arch/mips/loongson64/pm.c +++ b/arch/mips/loongson64/pm.c @@ -6,98 +6,46 @@ * Author: Wu Zhangjin */ #include -#include #include -#include #include #include -static unsigned int __maybe_unused cached_master_mask; /* i8259A */ -static unsigned int __maybe_unused cached_slave_mask; -static unsigned int __maybe_unused cached_bonito_irq_mask; /* bonito */ +asmlinkage void loongson_lefi_sleep(unsigned long sleep_addr); -void arch_suspend_disable_irqs(void) -{ - /* disable all mips events */ - local_irq_disable(); - -#ifdef CONFIG_I8259 - /* disable all events of i8259A */ - cached_slave_mask = inb(PIC_SLAVE_IMR); - cached_master_mask = inb(PIC_MASTER_IMR); - - outb(0xff, PIC_SLAVE_IMR); - inb(PIC_SLAVE_IMR); - outb(0xff, PIC_MASTER_IMR); - inb(PIC_MASTER_IMR); -#endif - /* disable all events of bonito */ - cached_bonito_irq_mask = LOONGSON_INTEN; - LOONGSON_INTENCLR = 0xffff; - (void)LOONGSON_INTENCLR; -} - -void arch_suspend_enable_irqs(void) -{ - /* enable all mips events */ - local_irq_enable(); -#ifdef CONFIG_I8259 - /* only enable the cached events of i8259A */ - outb(cached_slave_mask, PIC_SLAVE_IMR); - outb(cached_master_mask, PIC_MASTER_IMR); -#endif - /* enable all cached events of bonito */ - LOONGSON_INTENSET = cached_bonito_irq_mask; - (void)LOONGSON_INTENSET; -} - -/* - * Setup the board-specific events for waking up loongson from wait mode - */ -void __weak setup_wakeup_events(void) -{ -} - -void __weak mach_suspend(void) -{ -} - -void __weak mach_resume(void) -{ -} - -static int loongson_pm_enter(suspend_state_t state) -{ - mach_suspend(); - - mach_resume(); - - return 0; -} - -static int loongson_pm_valid_state(suspend_state_t state) +static int lefi_pm_enter(suspend_state_t state) { switch (state) { - case PM_SUSPEND_ON: - case PM_SUSPEND_STANDBY: case PM_SUSPEND_MEM: - return 1; + pm_set_suspend_via_firmware(); + loongson_lefi_sleep(loongson_sysconf.suspend_addr); + pm_set_resume_via_firmware(); + return 0; + default: + return -EINVAL; + } +} +static int lefi_pm_valid_state(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_MEM: + return !!loongson_sysconf.suspend_addr; default: return 0; } } -static const struct platform_suspend_ops loongson_pm_ops = { - .valid = loongson_pm_valid_state, - .enter = loongson_pm_enter, +static const struct platform_suspend_ops lefi_pm_ops = { + .valid = lefi_pm_valid_state, + .enter = lefi_pm_enter, }; static int __init loongson_pm_init(void) { - suspend_set_ops(&loongson_pm_ops); + if (loongson_sysconf.fw_interface == LOONGSON_LEFI) + suspend_set_ops(&lefi_pm_ops); return 0; } diff --git a/arch/mips/loongson64/reset.c b/arch/mips/loongson64/reset.c index e01c8d4a805a..3e20ade0503a 100644 --- a/arch/mips/loongson64/reset.c +++ b/arch/mips/loongson64/reset.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -21,36 +22,21 @@ #include #include -static void loongson_restart(char *command) +static int firmware_restart(struct sys_off_data *unusedd) { void (*fw_restart)(void) = (void *)loongson_sysconf.restart_addr; fw_restart(); - while (1) { - if (cpu_wait) - cpu_wait(); - } + return NOTIFY_DONE; } -static void loongson_poweroff(void) +static int firmware_poweroff(struct sys_off_data *unused) { void (*fw_poweroff)(void) = (void *)loongson_sysconf.poweroff_addr; fw_poweroff(); - while (1) { - if (cpu_wait) - cpu_wait(); - } -} - -static void loongson_halt(void) -{ - pr_notice("\n\n** You can safely turn off the power now **\n\n"); - while (1) { - if (cpu_wait) - cpu_wait(); - } + return NOTIFY_DONE; } #ifdef CONFIG_KEXEC_CORE @@ -154,9 +140,17 @@ static void loongson_crash_shutdown(struct pt_regs *regs) static int __init mips_reboot_setup(void) { - _machine_restart = loongson_restart; - _machine_halt = loongson_halt; - pm_power_off = loongson_poweroff; + if (loongson_sysconf.restart_addr) { + register_sys_off_handler(SYS_OFF_MODE_RESTART, + SYS_OFF_PRIO_FIRMWARE, + firmware_restart, NULL); + } + + if (loongson_sysconf.poweroff_addr) { + register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_FIRMWARE, + firmware_poweroff, NULL); + } #ifdef CONFIG_KEXEC_CORE kexec_argv = kmalloc(KEXEC_ARGV_SIZE, GFP_KERNEL); diff --git a/arch/mips/loongson64/sleeper.S b/arch/mips/loongson64/sleeper.S new file mode 100644 index 000000000000..cf16877409e2 --- /dev/null +++ b/arch/mips/loongson64/sleeper.S @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024, Jiaxun Yang + * Loongson EFI firmware sleeper routine + */ + +#include +#include + +#include + +LEAF(loongson_lefi_sleep) + SUSPEND_SAVE + move t9, a0 + PTR_LA a0, wake + move a1, sp + jalr t9 +wake: + smp_slave_setup + RESUME_RESTORE_REGS_RETURN +END(loongson_lefi_sleep) diff --git a/arch/mips/loongson64/smp.c b/arch/mips/loongson64/smp.c index 5a990cdef91a..66d049cdcf14 100644 --- a/arch/mips/loongson64/smp.c +++ b/arch/mips/loongson64/smp.c @@ -466,12 +466,25 @@ static void loongson3_smp_finish(void) static void __init loongson3_smp_setup(void) { int i = 0, num = 0; /* i: physical id, num: logical id */ + int max_cpus = 0; init_cpu_possible(cpu_none_mask); + for (i = 0; i < ARRAY_SIZE(smp_group); i++) { + if (!smp_group[i]) + break; + max_cpus += loongson_sysconf.cores_per_node; + } + + if (max_cpus < loongson_sysconf.nr_cpus) { + pr_err("SMP Groups are less than the number of CPUs\n"); + loongson_sysconf.nr_cpus = max_cpus ? max_cpus : 1; + } + /* For unified kernel, NR_CPUS is the maximum possible value, * loongson_sysconf.nr_cpus is the really present value */ + i = 0; while (i < loongson_sysconf.nr_cpus) { if (loongson_sysconf.reserved_cpus_mask & (1<giopar; @@ -395,7 +395,7 @@ static struct resource gio_bus_resource = { .flags = IORESOURCE_MEM, }; -int __init ip22_gio_init(void) +static int __init ip22_gio_init(void) { unsigned int pbdma __maybe_unused; int ret; diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c index 96798a4ab2de..11f8adc98cb5 100644 --- a/arch/mips/sgi-ip22/ip22-int.c +++ b/arch/mips/sgi-ip22/ip22-int.c @@ -165,8 +165,6 @@ static void __irq_entry indy_buserror_irq(void) #define SGI_INTERRUPTS SGINT_LOCAL3 #endif -extern void indy_8254timer_irq(void); - /* * IRQs on the INDY look basically (barring software IRQs which we don't use * at all) like: diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c index b69daa02401b..e06a818fe792 100644 --- a/arch/mips/sgi-ip22/ip22-setup.c +++ b/arch/mips/sgi-ip22/ip22-setup.c @@ -26,8 +26,6 @@ #include #include -extern void ip22_be_init(void) __init; - void __init plat_mem_setup(void) { char *ctype; diff --git a/arch/mips/sgi-ip30/ip30-console.c b/arch/mips/sgi-ip30/ip30-console.c index 7c6dcf6e73f7..a5f10097b985 100644 --- a/arch/mips/sgi-ip30/ip30-console.c +++ b/arch/mips/sgi-ip30/ip30-console.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include #include diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index c88c6d46a5bc..f8891fbe7c16 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -149,7 +149,7 @@ config PPC select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_SCALED_CPUTIME if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64 select ARCH_HAS_SET_MEMORY - select ARCH_HAS_STRICT_KERNEL_RWX if (PPC_BOOK3S || PPC_8xx || 40x) && !HIBERNATION + select ARCH_HAS_STRICT_KERNEL_RWX if (PPC_BOOK3S || PPC_8xx) && !HIBERNATION select ARCH_HAS_STRICT_KERNEL_RWX if PPC_85xx && !HIBERNATION && !RANDOMIZE_BASE select ARCH_HAS_STRICT_MODULE_RWX if ARCH_HAS_STRICT_KERNEL_RWX select ARCH_HAS_SYSCALL_WRAPPER if !SPU_BASE && !COMPAT @@ -167,7 +167,7 @@ config PPC select ARCH_SPLIT_ARG64 if PPC32 select ARCH_STACKWALK select ARCH_SUPPORTS_ATOMIC_RMW - select ARCH_SUPPORTS_DEBUG_PAGEALLOC if PPC_BOOK3S || PPC_8xx || 40x + select ARCH_SUPPORTS_DEBUG_PAGEALLOC if PPC_BOOK3S || PPC_8xx select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF if PPC64 select ARCH_USE_MEMTEST @@ -389,7 +389,7 @@ config ARCH_SUSPEND_POSSIBLE def_bool y depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \ (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \ - || 44x || 40x + || 44x config ARCH_SUSPEND_NONZERO_CPU def_bool y @@ -443,7 +443,7 @@ config ARCH_SUPPORTS_UPROBES config PPC_ADV_DEBUG_REGS bool - depends on 40x || BOOKE + depends on BOOKE default y config PPC_ADV_DEBUG_IACS @@ -490,7 +490,7 @@ source "kernel/Kconfig.hz" config MATH_EMULATION bool "Math emulation" - depends on 4xx || PPC_8xx || PPC_MPC832x || BOOKE || PPC_MICROWATT + depends on 44x || PPC_8xx || PPC_MPC832x || BOOKE || PPC_MICROWATT select PPC_FPU_REGS help Some PowerPC chips designed for embedded applications do not have @@ -1077,7 +1077,7 @@ config GENERIC_ISA_DMA config PPC_INDIRECT_PCI bool depends on PCI - default y if 40x || 44x + default y if 44x config SBUS bool @@ -1102,15 +1102,12 @@ config FSL_PMC config PPC4xx_CPM bool default y - depends on SUSPEND && (44x || 40x) + depends on SUSPEND && 44x help PPC4xx Clock Power Management (CPM) support (suspend/resume). It also enables support for two different idle states (idle-wait and idle-doze). -config 4xx_SOC - bool - config FSL_LBC bool "Freescale Local Bus support" help diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 8c80b154e814..3799ceceb04a 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -244,14 +244,6 @@ config PPC_EARLY_DEBUG_44x inbuilt serial port. If you enable this, ensure you set PPC_EARLY_DEBUG_44x_PHYSLOW below to suit your target board. -config PPC_EARLY_DEBUG_40x - bool "Early serial debugging for IBM/AMCC 40x CPUs" - depends on 40x - help - Select this to enable early debugging for IBM 40x chips via the - inbuilt serial port. This works on chips with a 16550 compatible - UART. - config PPC_EARLY_DEBUG_CPM bool "Early serial debugging for Freescale CPM-based serial ports" depends on SERIAL_CPM=y @@ -356,11 +348,6 @@ config PPC_EARLY_DEBUG_44x_PHYSHIGH depends on PPC_EARLY_DEBUG_44x default "0x1" -config PPC_EARLY_DEBUG_40x_PHYSADDR - hex "Early debug UART physical address" - depends on PPC_EARLY_DEBUG_40x - default "0xef600300" - config PPC_EARLY_DEBUG_CPM_ADDR hex "CPM UART early debug transmit descriptor address" depends on PPC_EARLY_DEBUG_CPM diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index a8479c881cac..bbfe4a1f06ef 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -301,11 +301,6 @@ ppc32_allmodconfig: $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/powerpc/configs/book3s_32.config \ -f $(srctree)/Makefile allmodconfig -generated_configs += ppc40x_allmodconfig -ppc40x_allmodconfig: - $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/powerpc/configs/40x.config \ - -f $(srctree)/Makefile allmodconfig - generated_configs += ppc44x_allmodconfig ppc44x_allmodconfig: $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/powerpc/configs/44x.config \ diff --git a/arch/powerpc/boot/4xx.c b/arch/powerpc/boot/4xx.c index 00c4d843a023..682ca3827892 100644 --- a/arch/powerpc/boot/4xx.c +++ b/arch/powerpc/boot/4xx.c @@ -253,7 +253,6 @@ void ibm4xx_denali_fixup_memsize(void) dt_fixup_memory(0, memsize); } -#define SPRN_DBCR0_40X 0x3F2 #define SPRN_DBCR0_44X 0x134 #define DBCR0_RST_SYSTEM 0x30000000 @@ -270,18 +269,6 @@ void ibm44x_dbcr_reset(void) } -void ibm40x_dbcr_reset(void) -{ - unsigned long tmp; - - asm volatile ( - "mfspr %0,%1\n" - "oris %0,%0,%2@h\n" - "mtspr %1,%0" - : "=&r"(tmp) : "i"(SPRN_DBCR0_40X), "i"(DBCR0_RST_SYSTEM) - ); -} - #define EMAC_RESET 0x20000000 void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1) { @@ -544,256 +531,3 @@ void ibm440spe_fixup_clocks(unsigned int sys_clk, eplike_fixup_uart_clk(1, "/plb/opb/serial@f0000300", ser_clk, plb_clk); eplike_fixup_uart_clk(2, "/plb/opb/serial@f0000600", ser_clk, plb_clk); } - -void ibm405gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk) -{ - u32 pllmr = mfdcr(DCRN_CPC0_PLLMR); - u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0); - u32 cpc0_cr1 = mfdcr(DCRN_405_CPC0_CR1); - u32 psr = mfdcr(DCRN_405_CPC0_PSR); - u32 cpu, plb, opb, ebc, tb, uart0, uart1, m; - u32 fwdv, fwdvb, fbdv, cbdv, opdv, epdv, ppdv, udiv; - - fwdv = (8 - ((pllmr & 0xe0000000) >> 29)); - fbdv = (pllmr & 0x1e000000) >> 25; - if (fbdv == 0) - fbdv = 16; - cbdv = ((pllmr & 0x00060000) >> 17) + 1; /* CPU:PLB */ - opdv = ((pllmr & 0x00018000) >> 15) + 1; /* PLB:OPB */ - ppdv = ((pllmr & 0x00006000) >> 13) + 1; /* PLB:PCI */ - epdv = ((pllmr & 0x00001800) >> 11) + 2; /* PLB:EBC */ - udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1; - - /* check for 405GPr */ - if ((mfpvr() & 0xfffffff0) == (0x50910951 & 0xfffffff0)) { - fwdvb = 8 - (pllmr & 0x00000007); - if (!(psr & 0x00001000)) /* PCI async mode enable == 0 */ - if (psr & 0x00000020) /* New mode enable */ - m = fwdvb * 2 * ppdv; - else - m = fwdvb * cbdv * ppdv; - else if (psr & 0x00000020) /* New mode enable */ - if (psr & 0x00000800) /* PerClk synch mode */ - m = fwdvb * 2 * epdv; - else - m = fbdv * fwdv; - else if (epdv == fbdv) - m = fbdv * cbdv * epdv; - else - m = fbdv * fwdvb * cbdv; - - cpu = sys_clk * m / fwdv; - plb = sys_clk * m / (fwdvb * cbdv); - } else { - m = fwdv * fbdv * cbdv; - cpu = sys_clk * m / fwdv; - plb = cpu / cbdv; - } - opb = plb / opdv; - ebc = plb / epdv; - - if (cpc0_cr0 & 0x80) - /* uart0 uses the external clock */ - uart0 = ser_clk; - else - uart0 = cpu / udiv; - - if (cpc0_cr0 & 0x40) - /* uart1 uses the external clock */ - uart1 = ser_clk; - else - uart1 = cpu / udiv; - - /* setup the timebase clock to tick at the cpu frequency */ - cpc0_cr1 = cpc0_cr1 & ~0x00800000; - mtdcr(DCRN_405_CPC0_CR1, cpc0_cr1); - tb = cpu; - - dt_fixup_cpu_clocks(cpu, tb, 0); - dt_fixup_clock("/plb", plb); - dt_fixup_clock("/plb/opb", opb); - dt_fixup_clock("/plb/ebc", ebc); - dt_fixup_clock("/plb/opb/serial@ef600300", uart0); - dt_fixup_clock("/plb/opb/serial@ef600400", uart1); -} - - -void ibm405ep_fixup_clocks(unsigned int sys_clk) -{ - u32 pllmr0 = mfdcr(DCRN_CPC0_PLLMR0); - u32 pllmr1 = mfdcr(DCRN_CPC0_PLLMR1); - u32 cpc0_ucr = mfdcr(DCRN_CPC0_UCR); - u32 cpu, plb, opb, ebc, uart0, uart1; - u32 fwdva, fwdvb, fbdv, cbdv, opdv, epdv; - u32 pllmr0_ccdv, tb, m; - - fwdva = 8 - ((pllmr1 & 0x00070000) >> 16); - fwdvb = 8 - ((pllmr1 & 0x00007000) >> 12); - fbdv = (pllmr1 & 0x00f00000) >> 20; - if (fbdv == 0) - fbdv = 16; - - cbdv = ((pllmr0 & 0x00030000) >> 16) + 1; /* CPU:PLB */ - epdv = ((pllmr0 & 0x00000300) >> 8) + 2; /* PLB:EBC */ - opdv = ((pllmr0 & 0x00003000) >> 12) + 1; /* PLB:OPB */ - - m = fbdv * fwdvb; - - pllmr0_ccdv = ((pllmr0 & 0x00300000) >> 20) + 1; - if (pllmr1 & 0x80000000) - cpu = sys_clk * m / (fwdva * pllmr0_ccdv); - else - cpu = sys_clk / pllmr0_ccdv; - - plb = cpu / cbdv; - opb = plb / opdv; - ebc = plb / epdv; - tb = cpu; - uart0 = cpu / (cpc0_ucr & 0x0000007f); - uart1 = cpu / ((cpc0_ucr & 0x00007f00) >> 8); - - dt_fixup_cpu_clocks(cpu, tb, 0); - dt_fixup_clock("/plb", plb); - dt_fixup_clock("/plb/opb", opb); - dt_fixup_clock("/plb/ebc", ebc); - dt_fixup_clock("/plb/opb/serial@ef600300", uart0); - dt_fixup_clock("/plb/opb/serial@ef600400", uart1); -} - -static u8 ibm405ex_fwdv_multi_bits[] = { - /* values for: 1 - 16 */ - 0x01, 0x02, 0x0e, 0x09, 0x04, 0x0b, 0x10, 0x0d, 0x0c, 0x05, - 0x06, 0x0f, 0x0a, 0x07, 0x08, 0x03 -}; - -u32 ibm405ex_get_fwdva(unsigned long cpr_fwdv) -{ - u32 index; - - for (index = 0; index < ARRAY_SIZE(ibm405ex_fwdv_multi_bits); index++) - if (cpr_fwdv == (u32)ibm405ex_fwdv_multi_bits[index]) - return index + 1; - - return 0; -} - -static u8 ibm405ex_fbdv_multi_bits[] = { - /* values for: 1 - 100 */ - 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4, - 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb, - 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96, - 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde, - 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb, - 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91, - 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b, - 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95, - 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4, - 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc, - /* values for: 101 - 200 */ - 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3, - 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90, - 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe, - 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6, - 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd, - 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1, - 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6, - 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9, - 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e, - 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf, - /* values for: 201 - 255 */ - 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae, - 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2, - 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2, - 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98, - 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81, - 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */ -}; - -u32 ibm405ex_get_fbdv(unsigned long cpr_fbdv) -{ - u32 index; - - for (index = 0; index < ARRAY_SIZE(ibm405ex_fbdv_multi_bits); index++) - if (cpr_fbdv == (u32)ibm405ex_fbdv_multi_bits[index]) - return index + 1; - - return 0; -} - -void ibm405ex_fixup_clocks(unsigned int sys_clk, unsigned int uart_clk) -{ - /* PLL config */ - u32 pllc = CPR0_READ(DCRN_CPR0_PLLC); - u32 plld = CPR0_READ(DCRN_CPR0_PLLD); - u32 cpud = CPR0_READ(DCRN_CPR0_PRIMAD); - u32 plbd = CPR0_READ(DCRN_CPR0_PRIMBD); - u32 opbd = CPR0_READ(DCRN_CPR0_OPBD); - u32 perd = CPR0_READ(DCRN_CPR0_PERD); - - /* Dividers */ - u32 fbdv = ibm405ex_get_fbdv(__fix_zero((plld >> 24) & 0xff, 1)); - - u32 fwdva = ibm405ex_get_fwdva(__fix_zero((plld >> 16) & 0x0f, 1)); - - u32 cpudv0 = __fix_zero((cpud >> 24) & 7, 8); - - /* PLBDV0 is hardwared to 010. */ - u32 plbdv0 = 2; - u32 plb2xdv0 = __fix_zero((plbd >> 16) & 7, 8); - - u32 opbdv0 = __fix_zero((opbd >> 24) & 3, 4); - - u32 perdv0 = __fix_zero((perd >> 24) & 3, 4); - - /* Resulting clocks */ - u32 cpu, plb, opb, ebc, vco, tb, uart0, uart1; - - /* PLL's VCO is the source for primary forward ? */ - if (pllc & 0x40000000) { - u32 m; - - /* Feedback path */ - switch ((pllc >> 24) & 7) { - case 0: - /* PLLOUTx */ - m = fbdv; - break; - case 1: - /* CPU */ - m = fbdv * fwdva * cpudv0; - break; - case 5: - /* PERClk */ - m = fbdv * fwdva * plb2xdv0 * plbdv0 * opbdv0 * perdv0; - break; - default: - printf("WARNING ! Invalid PLL feedback source !\n"); - goto bypass; - } - - vco = (unsigned int)(sys_clk * m); - } else { -bypass: - /* Bypass system PLL */ - vco = 0; - } - - /* CPU = VCO / ( FWDVA x CPUDV0) */ - cpu = vco / (fwdva * cpudv0); - /* PLB = VCO / ( FWDVA x PLB2XDV0 x PLBDV0) */ - plb = vco / (fwdva * plb2xdv0 * plbdv0); - /* OPB = PLB / OPBDV0 */ - opb = plb / opbdv0; - /* EBC = OPB / PERDV0 */ - ebc = opb / perdv0; - - tb = cpu; - uart0 = uart1 = uart_clk; - - dt_fixup_cpu_clocks(cpu, tb, 0); - dt_fixup_clock("/plb", plb); - dt_fixup_clock("/plb/opb", opb); - dt_fixup_clock("/plb/opb/ebc", ebc); - dt_fixup_clock("/plb/opb/serial@ef600200", uart0); - dt_fixup_clock("/plb/opb/serial@ef600300", uart1); -} diff --git a/arch/powerpc/boot/4xx.h b/arch/powerpc/boot/4xx.h index 77f15d124c81..62df496b7ba6 100644 --- a/arch/powerpc/boot/4xx.h +++ b/arch/powerpc/boot/4xx.h @@ -12,13 +12,9 @@ void ibm4xx_sdram_fixup_memsize(void); void ibm440spe_fixup_memsize(void); void ibm4xx_denali_fixup_memsize(void); void ibm44x_dbcr_reset(void); -void ibm40x_dbcr_reset(void); void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1); void ibm4xx_fixup_ebc_ranges(const char *ebc); -void ibm405gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk); -void ibm405ep_fixup_clocks(unsigned int sys_clk); -void ibm405ex_fixup_clocks(unsigned int sys_clk, unsigned int uart_clk); void ibm440gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk); void ibm440ep_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk, unsigned int tmr_clk); diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 35f6b15e4c47..fa8518067d38 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -54,10 +54,8 @@ endif $(obj)/4xx.o: BOOTTARGETFLAGS += -mcpu=405 $(obj)/ebony.o: BOOTTARGETFLAGS += -mcpu=440 -$(obj)/cuboot-hotfoot.o: BOOTTARGETFLAGS += -mcpu=405 $(obj)/cuboot-taishan.o: BOOTTARGETFLAGS += -mcpu=440 $(obj)/cuboot-katmai.o: BOOTTARGETFLAGS += -mcpu=440 -$(obj)/cuboot-acadia.o: BOOTTARGETFLAGS += -mcpu=405 $(obj)/treeboot-iss4xx.o: BOOTTARGETFLAGS += -mcpu=405 $(obj)/treeboot-currituck.o: BOOTTARGETFLAGS += -mcpu=405 $(obj)/treeboot-akebono.o: BOOTTARGETFLAGS += -mcpu=405 @@ -146,7 +144,6 @@ src-wlib-$(CONFIG_PPC_POWERNV) += opal-calls.S opal.c ifndef CONFIG_PPC64_BOOT_WRAPPER src-wlib-y += crtsavres.S endif -src-wlib-$(CONFIG_40x) += 4xx.c planetcore.c src-wlib-$(CONFIG_44x) += 4xx.c ebony.c bamboo.c src-wlib-$(CONFIG_PPC_8xx) += mpc8xx.c planetcore.c fsl-soc.c src-wlib-$(CONFIG_PPC_82xx) += pq2.c fsl-soc.c planetcore.c @@ -154,9 +151,6 @@ src-wlib-$(CONFIG_EMBEDDED6xx) += ugecon.c fsl-soc.c src-wlib-$(CONFIG_CPM) += cpm-serial.c src-plat-y := of.c epapr.c -src-plat-$(CONFIG_40x) += fixed-head.S cuboot-hotfoot.c \ - cuboot-acadia.c \ - cuboot-kilauea.c simpleboot.c src-plat-$(CONFIG_44x) += treeboot-ebony.c cuboot-ebony.c treeboot-bamboo.c \ cuboot-bamboo.c cuboot-sam440ep.c \ cuboot-sequoia.c cuboot-rainier.c \ @@ -300,11 +294,6 @@ image-$(CONFIG_EPAPR_BOOT) += zImage.epapr # Boards with newish u-boot firmware can use the uImage target above # -# Board ports in arch/powerpc/platform/40x/Kconfig -image-$(CONFIG_HOTFOOT) += cuImage.hotfoot -image-$(CONFIG_ACADIA) += cuImage.acadia -image-$(CONFIG_OBS600) += uImage.obs600 - # Board ports in arch/powerpc/platform/44x/Kconfig image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony image-$(CONFIG_BAMBOO) += treeImage.bamboo cuImage.bamboo diff --git a/arch/powerpc/boot/cuboot-acadia.c b/arch/powerpc/boot/cuboot-acadia.c deleted file mode 100644 index 46e96756cfe1..000000000000 --- a/arch/powerpc/boot/cuboot-acadia.c +++ /dev/null @@ -1,171 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Old U-boot compatibility for Acadia - * - * Author: Josh Boyer - * - * Copyright 2008 IBM Corporation - */ - -#include "ops.h" -#include "io.h" -#include "dcr.h" -#include "stdio.h" -#include "4xx.h" -#include "44x.h" -#include "cuboot.h" - -#define TARGET_4xx -#include "ppcboot.h" - -static bd_t bd; - -#define CPR_PERD0_SPIDV_MASK 0x000F0000 /* SPI Clock Divider */ - -#define PLLC_SRC_MASK 0x20000000 /* PLL feedback source */ - -#define PLLD_FBDV_MASK 0x1F000000 /* PLL feedback divider value */ -#define PLLD_FWDVA_MASK 0x000F0000 /* PLL forward divider A value */ -#define PLLD_FWDVB_MASK 0x00000700 /* PLL forward divider B value */ - -#define PRIMAD_CPUDV_MASK 0x0F000000 /* CPU Clock Divisor Mask */ -#define PRIMAD_PLBDV_MASK 0x000F0000 /* PLB Clock Divisor Mask */ -#define PRIMAD_OPBDV_MASK 0x00000F00 /* OPB Clock Divisor Mask */ -#define PRIMAD_EBCDV_MASK 0x0000000F /* EBC Clock Divisor Mask */ - -#define PERD0_PWMDV_MASK 0xFF000000 /* PWM Divider Mask */ -#define PERD0_SPIDV_MASK 0x000F0000 /* SPI Divider Mask */ -#define PERD0_U0DV_MASK 0x0000FF00 /* UART 0 Divider Mask */ -#define PERD0_U1DV_MASK 0x000000FF /* UART 1 Divider Mask */ - -static void get_clocks(void) -{ - unsigned long sysclk, cpr_plld, cpr_pllc, cpr_primad, plloutb, i; - unsigned long pllFwdDiv, pllFwdDivB, pllFbkDiv, pllPlbDiv, pllExtBusDiv; - unsigned long pllOpbDiv, freqEBC, freqUART, freqOPB; - unsigned long div; /* total divisor udiv * bdiv */ - unsigned long umin; /* minimum udiv */ - unsigned short diff; /* smallest diff */ - unsigned long udiv; /* best udiv */ - unsigned short idiff; /* current diff */ - unsigned short ibdiv; /* current bdiv */ - unsigned long est; /* current estimate */ - unsigned long baud; - void *np; - - /* read the sysclk value from the CPLD */ - sysclk = (in_8((unsigned char *)0x80000000) == 0xc) ? 66666666 : 33333000; - - /* - * Read PLL Mode registers - */ - cpr_plld = CPR0_READ(DCRN_CPR0_PLLD); - cpr_pllc = CPR0_READ(DCRN_CPR0_PLLC); - - /* - * Determine forward divider A - */ - pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16); - - /* - * Determine forward divider B - */ - pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8); - if (pllFwdDivB == 0) - pllFwdDivB = 8; - - /* - * Determine FBK_DIV. - */ - pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24); - if (pllFbkDiv == 0) - pllFbkDiv = 256; - - /* - * Read CPR_PRIMAD register - */ - cpr_primad = CPR0_READ(DCRN_CPR0_PRIMAD); - - /* - * Determine PLB_DIV. - */ - pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16); - if (pllPlbDiv == 0) - pllPlbDiv = 16; - - /* - * Determine EXTBUS_DIV. - */ - pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK); - if (pllExtBusDiv == 0) - pllExtBusDiv = 16; - - /* - * Determine OPB_DIV. - */ - pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8); - if (pllOpbDiv == 0) - pllOpbDiv = 16; - - /* There is a bug in U-Boot that prevents us from using - * bd.bi_opbfreq because U-Boot doesn't populate it for - * 405EZ. We get to calculate it, yay! - */ - freqOPB = (sysclk *pllFbkDiv) /pllOpbDiv; - - freqEBC = (sysclk * pllFbkDiv) / pllExtBusDiv; - - plloutb = ((sysclk * ((cpr_pllc & PLLC_SRC_MASK) ? - pllFwdDivB : pllFwdDiv) * - pllFbkDiv) / pllFwdDivB); - - np = find_node_by_alias("serial0"); - if (getprop(np, "current-speed", &baud, sizeof(baud)) != sizeof(baud)) - fatal("no current-speed property\n\r"); - - udiv = 256; /* Assume lowest possible serial clk */ - div = plloutb / (16 * baud); /* total divisor */ - umin = (plloutb / freqOPB) << 1; /* 2 x OPB divisor */ - diff = 256; /* highest possible */ - - /* i is the test udiv value -- start with the largest - * possible (256) to minimize serial clock and constrain - * search to umin. - */ - for (i = 256; i > umin; i--) { - ibdiv = div / i; - est = i * ibdiv; - idiff = (est > div) ? (est-div) : (div-est); - if (idiff == 0) { - udiv = i; - break; /* can't do better */ - } else if (idiff < diff) { - udiv = i; /* best so far */ - diff = idiff; /* update lowest diff*/ - } - } - freqUART = plloutb / udiv; - - dt_fixup_cpu_clocks(bd.bi_procfreq, bd.bi_intfreq, bd.bi_plb_busfreq); - dt_fixup_clock("/plb/ebc", freqEBC); - dt_fixup_clock("/plb/opb", freqOPB); - dt_fixup_clock("/plb/opb/serial@ef600300", freqUART); - dt_fixup_clock("/plb/opb/serial@ef600400", freqUART); -} - -static void acadia_fixups(void) -{ - dt_fixup_memory(bd.bi_memstart, bd.bi_memsize); - get_clocks(); - dt_fixup_mac_address_by_alias("ethernet0", bd.bi_enetaddr); -} - -void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - CUBOOT_INIT(); - platform_ops.fixups = acadia_fixups; - platform_ops.exit = ibm40x_dbcr_reset; - fdt_init(_dtb_start); - serial_console_init(); -} diff --git a/arch/powerpc/boot/cuboot-hotfoot.c b/arch/powerpc/boot/cuboot-hotfoot.c deleted file mode 100644 index 0e5532f855d6..000000000000 --- a/arch/powerpc/boot/cuboot-hotfoot.c +++ /dev/null @@ -1,139 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Old U-boot compatibility for Esteem 195E Hotfoot CPU Board - * - * Author: Solomon Peachy - */ - -#include "ops.h" -#include "stdio.h" -#include "reg.h" -#include "dcr.h" -#include "4xx.h" -#include "cuboot.h" - -#define TARGET_4xx -#define TARGET_HOTFOOT - -#include "ppcboot-hotfoot.h" - -static bd_t bd; - -#define NUM_REGS 3 - -static void hotfoot_fixups(void) -{ - u32 uart = mfdcr(DCRN_CPC0_UCR) & 0x7f; - - dt_fixup_memory(bd.bi_memstart, bd.bi_memsize); - - dt_fixup_cpu_clocks(bd.bi_procfreq, bd.bi_procfreq, 0); - dt_fixup_clock("/plb", bd.bi_plb_busfreq); - dt_fixup_clock("/plb/opb", bd.bi_opbfreq); - dt_fixup_clock("/plb/ebc", bd.bi_pci_busfreq); - dt_fixup_clock("/plb/opb/serial@ef600300", bd.bi_procfreq / uart); - dt_fixup_clock("/plb/opb/serial@ef600400", bd.bi_procfreq / uart); - - dt_fixup_mac_address_by_alias("ethernet0", bd.bi_enetaddr); - dt_fixup_mac_address_by_alias("ethernet1", bd.bi_enet1addr); - - /* Is this a single eth/serial board? */ - if ((bd.bi_enet1addr[0] == 0) && - (bd.bi_enet1addr[1] == 0) && - (bd.bi_enet1addr[2] == 0) && - (bd.bi_enet1addr[3] == 0) && - (bd.bi_enet1addr[4] == 0) && - (bd.bi_enet1addr[5] == 0)) { - void *devp; - - printf("Trimming devtree for single serial/eth board\n"); - - devp = finddevice("/plb/opb/serial@ef600300"); - if (!devp) - fatal("Can't find node for /plb/opb/serial@ef600300"); - del_node(devp); - - devp = finddevice("/plb/opb/ethernet@ef600900"); - if (!devp) - fatal("Can't find node for /plb/opb/ethernet@ef600900"); - del_node(devp); - } - - ibm4xx_quiesce_eth((u32 *)0xef600800, (u32 *)0xef600900); - - /* Fix up flash size in fdt for 4M boards. */ - if (bd.bi_flashsize < 0x800000) { - u32 regs[NUM_REGS]; - void *devp = finddevice("/plb/ebc/nor_flash@0"); - if (!devp) - fatal("Can't find FDT node for nor_flash!??"); - - printf("Fixing devtree for 4M Flash\n"); - - /* First fix up the base address */ - getprop(devp, "reg", regs, sizeof(regs)); - regs[0] = 0; - regs[1] = 0xffc00000; - regs[2] = 0x00400000; - setprop(devp, "reg", regs, sizeof(regs)); - - /* Then the offsets */ - devp = finddevice("/plb/ebc/nor_flash@0/partition@0"); - if (!devp) - fatal("Can't find FDT node for partition@0"); - getprop(devp, "reg", regs, 2*sizeof(u32)); - regs[0] -= 0x400000; - setprop(devp, "reg", regs, 2*sizeof(u32)); - - devp = finddevice("/plb/ebc/nor_flash@0/partition@1"); - if (!devp) - fatal("Can't find FDT node for partition@1"); - getprop(devp, "reg", regs, 2*sizeof(u32)); - regs[0] -= 0x400000; - setprop(devp, "reg", regs, 2*sizeof(u32)); - - devp = finddevice("/plb/ebc/nor_flash@0/partition@2"); - if (!devp) - fatal("Can't find FDT node for partition@2"); - getprop(devp, "reg", regs, 2*sizeof(u32)); - regs[0] -= 0x400000; - setprop(devp, "reg", regs, 2*sizeof(u32)); - - devp = finddevice("/plb/ebc/nor_flash@0/partition@3"); - if (!devp) - fatal("Can't find FDT node for partition@3"); - getprop(devp, "reg", regs, 2*sizeof(u32)); - regs[0] -= 0x400000; - setprop(devp, "reg", regs, 2*sizeof(u32)); - - devp = finddevice("/plb/ebc/nor_flash@0/partition@4"); - if (!devp) - fatal("Can't find FDT node for partition@4"); - getprop(devp, "reg", regs, 2*sizeof(u32)); - regs[0] -= 0x400000; - setprop(devp, "reg", regs, 2*sizeof(u32)); - - devp = finddevice("/plb/ebc/nor_flash@0/partition@6"); - if (!devp) - fatal("Can't find FDT node for partition@6"); - getprop(devp, "reg", regs, 2*sizeof(u32)); - regs[0] -= 0x400000; - setprop(devp, "reg", regs, 2*sizeof(u32)); - - /* Delete the FeatFS node */ - devp = finddevice("/plb/ebc/nor_flash@0/partition@5"); - if (!devp) - fatal("Can't find FDT node for partition@5"); - del_node(devp); - } -} - -void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - CUBOOT_INIT(); - platform_ops.fixups = hotfoot_fixups; - platform_ops.exit = ibm40x_dbcr_reset; - fdt_init(_dtb_start); - serial_console_init(); -} diff --git a/arch/powerpc/boot/cuboot-kilauea.c b/arch/powerpc/boot/cuboot-kilauea.c deleted file mode 100644 index fda182f518a2..000000000000 --- a/arch/powerpc/boot/cuboot-kilauea.c +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Old U-boot compatibility for PPC405EX. This image is already included - * a dtb. - * - * Author: Tiejun Chen - * - * Copyright (C) 2009 Wind River Systems, Inc. - */ - -#include "ops.h" -#include "io.h" -#include "dcr.h" -#include "stdio.h" -#include "4xx.h" -#include "44x.h" -#include "cuboot.h" - -#define TARGET_4xx -#define TARGET_44x -#include "ppcboot.h" - -#define KILAUEA_SYS_EXT_SERIAL_CLOCK 11059200 /* ext. 11.059MHz clk */ - -static bd_t bd; - -static void kilauea_fixups(void) -{ - unsigned long sysclk = 33333333; - - ibm405ex_fixup_clocks(sysclk, KILAUEA_SYS_EXT_SERIAL_CLOCK); - dt_fixup_memory(bd.bi_memstart, bd.bi_memsize); - ibm4xx_fixup_ebc_ranges("/plb/opb/ebc"); - dt_fixup_mac_address_by_alias("ethernet0", bd.bi_enetaddr); - dt_fixup_mac_address_by_alias("ethernet1", bd.bi_enet1addr); -} - -void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - CUBOOT_INIT(); - platform_ops.fixups = kilauea_fixups; - platform_ops.exit = ibm40x_dbcr_reset; - fdt_init(_dtb_start); - serial_console_init(); -} diff --git a/arch/powerpc/boot/dcr.h b/arch/powerpc/boot/dcr.h index 334ab8b5a668..91dc3a302cc8 100644 --- a/arch/powerpc/boot/dcr.h +++ b/arch/powerpc/boot/dcr.h @@ -153,17 +153,6 @@ static const unsigned long sdram_bxcr[] = { SDRAM0_B0CR, SDRAM0_B1CR, #define CPR0_SCPID 0x120 #define CPR0_PLLC0 0x40 -/* 405GP Clocking/Power Management/Chip Control regs */ -#define DCRN_CPC0_PLLMR 0xb0 -#define DCRN_405_CPC0_CR0 0xb1 -#define DCRN_405_CPC0_CR1 0xb2 -#define DCRN_405_CPC0_PSR 0xb4 - -/* 405EP Clocking/Power Management/Chip Control regs */ -#define DCRN_CPC0_PLLMR0 0xf0 -#define DCRN_CPC0_PLLMR1 0xf4 -#define DCRN_CPC0_UCR 0xf5 - /* 440GX/405EX Clock Control reg */ #define DCRN_CPR0_CLKUPD 0x020 #define DCRN_CPR0_PLLC 0x040 diff --git a/arch/powerpc/boot/dts/acadia.dts b/arch/powerpc/boot/dts/acadia.dts deleted file mode 100644 index 5fedda811378..000000000000 --- a/arch/powerpc/boot/dts/acadia.dts +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Device Tree Source for AMCC Acadia (405EZ) - * - * Copyright IBM Corp. 2008 - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -/dts-v1/; - -/ { - #address-cells = <1>; - #size-cells = <1>; - model = "amcc,acadia"; - compatible = "amcc,acadia"; - dcr-parent = <&{/cpus/cpu@0}>; - - aliases { - ethernet0 = &EMAC0; - serial0 = &UART0; - serial1 = &UART1; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - model = "PowerPC,405EZ"; - reg = <0x0>; - clock-frequency = <0>; /* Filled in by wrapper */ - timebase-frequency = <0>; /* Filled in by wrapper */ - i-cache-line-size = <32>; - d-cache-line-size = <32>; - i-cache-size = <16384>; - d-cache-size = <16384>; - dcr-controller; - dcr-access-method = "native"; - }; - }; - - memory { - device_type = "memory"; - reg = <0x0 0x0>; /* Filled in by wrapper */ - }; - - UIC0: interrupt-controller { - compatible = "ibm,uic-405ez", "ibm,uic"; - interrupt-controller; - dcr-reg = <0x0c0 0x009>; - cell-index = <0>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - }; - - plb { - compatible = "ibm,plb-405ez", "ibm,plb3"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - clock-frequency = <0>; /* Filled in by wrapper */ - - MAL0: mcmal { - compatible = "ibm,mcmal-405ez", "ibm,mcmal"; - dcr-reg = <0x380 0x62>; - num-tx-chans = <1>; - num-rx-chans = <1>; - interrupt-parent = <&UIC0>; - /* 405EZ has only 3 interrupts to the UIC, as - * SERR, TXDE, and RXDE are or'd together into - * one UIC bit - */ - interrupts = < - 0x13 0x4 /* TXEOB */ - 0x15 0x4 /* RXEOB */ - 0x12 0x4 /* SERR, TXDE, RXDE */>; - }; - - POB0: opb { - compatible = "ibm,opb-405ez", "ibm,opb"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - dcr-reg = <0x0a 0x05>; - clock-frequency = <0>; /* Filled in by wrapper */ - - UART0: serial@ef600300 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0xef600300 0x8>; - virtual-reg = <0xef600300>; - clock-frequency = <0>; /* Filled in by wrapper */ - current-speed = <115200>; - interrupt-parent = <&UIC0>; - interrupts = <0x5 0x4>; - }; - - UART1: serial@ef600400 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0xef600400 0x8>; - clock-frequency = <0>; /* Filled in by wrapper */ - current-speed = <115200>; - interrupt-parent = <&UIC0>; - interrupts = <0x6 0x4>; - }; - - IIC: i2c@ef600500 { - compatible = "ibm,iic-405ez", "ibm,iic"; - reg = <0xef600500 0x11>; - interrupt-parent = <&UIC0>; - interrupts = <0xa 0x4>; - }; - - GPIO0: gpio@ef600700 { - compatible = "ibm,gpio-405ez"; - reg = <0xef600700 0x20>; - }; - - GPIO1: gpio@ef600800 { - compatible = "ibm,gpio-405ez"; - reg = <0xef600800 0x20>; - }; - - EMAC0: ethernet@ef600900 { - device_type = "network"; - compatible = "ibm,emac-405ez", "ibm,emac"; - interrupt-parent = <&UIC0>; - interrupts = < - 0x10 0x4 /* Ethernet */ - 0x11 0x4 /* Ethernet Wake up */>; - local-mac-address = [000000000000]; /* Filled in by wrapper */ - reg = <0xef600900 0x70>; - mal-device = <&MAL0>; - mal-tx-channel = <0>; - mal-rx-channel = <0>; - cell-index = <0>; - max-frame-size = <1500>; - rx-fifo-size = <4096>; - tx-fifo-size = <2048>; - phy-mode = "mii"; - phy-map = <0x0>; - }; - - CAN0: can@ef601000 { - compatible = "amcc,can-405ez"; - reg = <0xef601000 0x620>; - interrupt-parent = <&UIC0>; - interrupts = <0x7 0x4>; - }; - - CAN1: can@ef601800 { - compatible = "amcc,can-405ez"; - reg = <0xef601800 0x620>; - interrupt-parent = <&UIC0>; - interrupts = <0x8 0x4>; - }; - - cameleon@ef602000 { - compatible = "amcc,cameleon-405ez"; - reg = <0xef602000 0x800>; - interrupt-parent = <&UIC0>; - interrupts = <0xb 0x4 0xc 0x4>; - }; - - ieee1588@ef602800 { - compatible = "amcc,ieee1588-405ez"; - reg = <0xef602800 0x60>; - interrupt-parent = <&UIC0>; - interrupts = <0x4 0x4>; - /* This thing is a bit weird. It has its own UIC - * that it uses to generate snapshot triggers. We - * don't really support this device yet, and it needs - * work to figure this out. - */ - dcr-reg = <0xe0 0x9>; - }; - - usb@ef603000 { - compatible = "ohci-be"; - reg = <0xef603000 0x80>; - interrupt-parent = <&UIC0>; - interrupts = <0xd 0x4 0xe 0x4>; - }; - - dac@ef603300 { - compatible = "amcc,dac-405ez"; - reg = <0xef603300 0x40>; - interrupt-parent = <&UIC0>; - interrupts = <0x18 0x4>; - }; - - adc@ef603400 { - compatible = "amcc,adc-405ez"; - reg = <0xef603400 0x40>; - interrupt-parent = <&UIC0>; - interrupts = <0x17 0x4>; - }; - - spi@ef603500 { - compatible = "amcc,spi-405ez"; - reg = <0xef603500 0x100>; - interrupt-parent = <&UIC0>; - interrupts = <0x9 0x4>; - }; - }; - - EBC0: ebc { - compatible = "ibm,ebc-405ez", "ibm,ebc"; - dcr-reg = <0x12 0x2>; - #address-cells = <2>; - #size-cells = <1>; - clock-frequency = <0>; /* Filled in by wrapper */ - }; - }; - - chosen { - stdout-path = "/plb/opb/serial@ef600300"; - }; -}; diff --git a/arch/powerpc/boot/dts/haleakala.dts b/arch/powerpc/boot/dts/haleakala.dts deleted file mode 100644 index f81ce8786d59..000000000000 --- a/arch/powerpc/boot/dts/haleakala.dts +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Device Tree Source for AMCC Haleakala (405EXr) - * - * Copyright 2008 DENX Software Engineering, Stefan Roese - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without - * any warranty of any kind, whether express or implied. - */ - -/dts-v1/; - -/ { - #address-cells = <1>; - #size-cells = <1>; - model = "amcc,haleakala"; - compatible = "amcc,haleakala", "amcc,kilauea"; - dcr-parent = <&{/cpus/cpu@0}>; - - aliases { - ethernet0 = &EMAC0; - serial0 = &UART0; - serial1 = &UART1; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - model = "PowerPC,405EXr"; - reg = <0x00000000>; - clock-frequency = <0>; /* Filled in by U-Boot */ - timebase-frequency = <0>; /* Filled in by U-Boot */ - i-cache-line-size = <32>; - d-cache-line-size = <32>; - i-cache-size = <16384>; /* 16 kB */ - d-cache-size = <16384>; /* 16 kB */ - dcr-controller; - dcr-access-method = "native"; - }; - }; - - memory { - device_type = "memory"; - reg = <0x00000000 0x00000000>; /* Filled in by U-Boot */ - }; - - UIC0: interrupt-controller { - compatible = "ibm,uic-405exr", "ibm,uic"; - interrupt-controller; - cell-index = <0>; - dcr-reg = <0x0c0 0x009>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - }; - - UIC1: interrupt-controller1 { - compatible = "ibm,uic-405exr","ibm,uic"; - interrupt-controller; - cell-index = <1>; - dcr-reg = <0x0d0 0x009>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */ - interrupt-parent = <&UIC0>; - }; - - UIC2: interrupt-controller2 { - compatible = "ibm,uic-405exr","ibm,uic"; - interrupt-controller; - cell-index = <2>; - dcr-reg = <0x0e0 0x009>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - interrupts = <0x1c 0x4 0x1d 0x4>; /* cascade */ - interrupt-parent = <&UIC0>; - }; - - plb { - compatible = "ibm,plb-405exr", "ibm,plb4"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - clock-frequency = <0>; /* Filled in by U-Boot */ - - SDRAM0: memory-controller { - compatible = "ibm,sdram-405exr", "ibm,sdram-4xx-ddr2"; - dcr-reg = <0x010 0x002>; - interrupt-parent = <&UIC2>; - interrupts = <0x5 0x4 /* ECC DED Error */ - 0x6 0x4>; /* ECC SEC Error */ - }; - - MAL0: mcmal { - compatible = "ibm,mcmal-405exr", "ibm,mcmal2"; - dcr-reg = <0x180 0x062>; - num-tx-chans = <2>; - num-rx-chans = <2>; - interrupt-parent = <&MAL0>; - interrupts = <0x0 0x1 0x2 0x3 0x4>; - #interrupt-cells = <1>; - #address-cells = <0>; - #size-cells = <0>; - interrupt-map = ; - interrupt-map-mask = <0xffffffff>; - }; - - POB0: opb { - compatible = "ibm,opb-405exr", "ibm,opb"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x80000000 0x80000000 0x10000000 - 0xef600000 0xef600000 0x00a00000 - 0xf0000000 0xf0000000 0x10000000>; - dcr-reg = <0x0a0 0x005>; - clock-frequency = <0>; /* Filled in by U-Boot */ - - EBC0: ebc { - compatible = "ibm,ebc-405exr", "ibm,ebc"; - dcr-reg = <0x012 0x002>; - #address-cells = <2>; - #size-cells = <1>; - clock-frequency = <0>; /* Filled in by U-Boot */ - /* ranges property is supplied by U-Boot */ - interrupts = <0x5 0x1>; - interrupt-parent = <&UIC1>; - - nor_flash@0,0 { - compatible = "amd,s29gl512n", "cfi-flash"; - bank-width = <2>; - reg = <0x00000000 0x00000000 0x04000000>; - #address-cells = <1>; - #size-cells = <1>; - partition@0 { - label = "kernel"; - reg = <0x00000000 0x00200000>; - }; - partition@200000 { - label = "root"; - reg = <0x00200000 0x00200000>; - }; - partition@400000 { - label = "user"; - reg = <0x00400000 0x03b60000>; - }; - partition@3f60000 { - label = "env"; - reg = <0x03f60000 0x00040000>; - }; - partition@3fa0000 { - label = "u-boot"; - reg = <0x03fa0000 0x00060000>; - }; - }; - }; - - UART0: serial@ef600200 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0xef600200 0x00000008>; - virtual-reg = <0xef600200>; - clock-frequency = <0>; /* Filled in by U-Boot */ - current-speed = <0>; - interrupt-parent = <&UIC0>; - interrupts = <0x1a 0x4>; - }; - - UART1: serial@ef600300 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0xef600300 0x00000008>; - virtual-reg = <0xef600300>; - clock-frequency = <0>; /* Filled in by U-Boot */ - current-speed = <0>; - interrupt-parent = <&UIC0>; - interrupts = <0x1 0x4>; - }; - - IIC0: i2c@ef600400 { - compatible = "ibm,iic-405exr", "ibm,iic"; - reg = <0xef600400 0x00000014>; - interrupt-parent = <&UIC0>; - interrupts = <0x2 0x4>; - }; - - IIC1: i2c@ef600500 { - compatible = "ibm,iic-405exr", "ibm,iic"; - reg = <0xef600500 0x00000014>; - interrupt-parent = <&UIC0>; - interrupts = <0x7 0x4>; - }; - - - RGMII0: emac-rgmii@ef600b00 { - compatible = "ibm,rgmii-405exr", "ibm,rgmii"; - reg = <0xef600b00 0x00000104>; - has-mdio; - }; - - EMAC0: ethernet@ef600900 { - linux,network-index = <0x0>; - device_type = "network"; - compatible = "ibm,emac-405exr", "ibm,emac4sync"; - interrupt-parent = <&EMAC0>; - interrupts = <0x0 0x1>; - #interrupt-cells = <1>; - #address-cells = <0>; - #size-cells = <0>; - interrupt-map = ; - reg = <0xef600900 0x000000c4>; - local-mac-address = [000000000000]; /* Filled in by U-Boot */ - mal-device = <&MAL0>; - mal-tx-channel = <0>; - mal-rx-channel = <0>; - cell-index = <0>; - max-frame-size = <9000>; - rx-fifo-size = <4096>; - tx-fifo-size = <2048>; - rx-fifo-size-gige = <16384>; - tx-fifo-size-gige = <16384>; - phy-mode = "rgmii"; - phy-map = <0x00000000>; - rgmii-device = <&RGMII0>; - rgmii-channel = <0>; - has-inverted-stacr-oc; - has-new-stacr-staopc; - }; - }; - - PCIE0: pcie@a0000000 { - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - compatible = "ibm,plb-pciex-405ex", "ibm,plb-pciex"; - primary; - port = <0x0>; /* port number */ - reg = <0xa0000000 0x20000000 /* Config space access */ - 0xef000000 0x00001000>; /* Registers */ - dcr-reg = <0x040 0x020>; - sdr-base = <0x400>; - - /* Outbound ranges, one memory and one IO, - * later cannot be changed - */ - ranges = <0x02000000 0x00000000 0x80000000 0x90000000 0x00000000 0x08000000 - 0x01000000 0x00000000 0x00000000 0xe0000000 0x00000000 0x00010000>; - - /* Inbound 2GB range starting at 0 */ - dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x80000000>; - - /* This drives busses 0x00 to 0x3f */ - bus-range = <0x0 0x3f>; - - /* Legacy interrupts (note the weird polarity, the bridge seems - * to invert PCIe legacy interrupts). - * We are de-swizzling here because the numbers are actually for - * port of the root complex virtual P2P bridge. But I want - * to avoid putting a node for it in the tree, so the numbers - * below are basically de-swizzled numbers. - * The real slot is on idsel 0, so the swizzling is 1:1 - */ - interrupt-map-mask = <0x0 0x0 0x0 0x7>; - interrupt-map = < - 0x0 0x0 0x0 0x1 &UIC2 0x0 0x4 /* swizzled int A */ - 0x0 0x0 0x0 0x2 &UIC2 0x1 0x4 /* swizzled int B */ - 0x0 0x0 0x0 0x3 &UIC2 0x2 0x4 /* swizzled int C */ - 0x0 0x0 0x0 0x4 &UIC2 0x3 0x4 /* swizzled int D */>; - }; - }; -}; diff --git a/arch/powerpc/boot/dts/hotfoot.dts b/arch/powerpc/boot/dts/hotfoot.dts deleted file mode 100644 index b93bf2d9dd5b..000000000000 --- a/arch/powerpc/boot/dts/hotfoot.dts +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Device Tree Source for ESTeem 195E Hotfoot - * - * Copyright 2009 AbsoluteValue Systems - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without - * any warranty of any kind, whether express or implied. - */ - -/dts-v1/; - -/ { - #address-cells = <1>; - #size-cells = <1>; - model = "est,hotfoot"; - compatible = "est,hotfoot"; - dcr-parent = <&{/cpus/cpu@0}>; - - aliases { - ethernet0 = &EMAC0; - ethernet1 = &EMAC1; - serial0 = &UART0; - serial1 = &UART1; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - model = "PowerPC,405EP"; - reg = <0x00000000>; - clock-frequency = <0>; /* Filled in by zImage */ - timebase-frequency = <0>; /* Filled in by zImage */ - i-cache-line-size = <0x20>; - d-cache-line-size = <0x20>; - i-cache-size = <0x4000>; - d-cache-size = <0x4000>; - dcr-controller; - dcr-access-method = "native"; - }; - }; - - memory { - device_type = "memory"; - reg = <0x00000000 0x00000000>; /* Filled in by zImage */ - }; - - UIC0: interrupt-controller { - compatible = "ibm,uic"; - interrupt-controller; - cell-index = <0>; - dcr-reg = <0x0c0 0x009>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - }; - - plb { - compatible = "ibm,plb3"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - clock-frequency = <0>; /* Filled in by zImage */ - - SDRAM0: memory-controller { - compatible = "ibm,sdram-405ep"; - dcr-reg = <0x010 0x002>; - }; - - MAL: mcmal { - compatible = "ibm,mcmal-405ep", "ibm,mcmal"; - dcr-reg = <0x180 0x062>; - num-tx-chans = <4>; - num-rx-chans = <2>; - interrupt-parent = <&UIC0>; - interrupts = < - 0xb 0x4 /* TXEOB */ - 0xc 0x4 /* RXEOB */ - 0xa 0x4 /* SERR */ - 0xd 0x4 /* TXDE */ - 0xe 0x4 /* RXDE */>; - }; - - POB0: opb { - compatible = "ibm,opb-405ep", "ibm,opb"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0xef600000 0xef600000 0x00a00000>; - dcr-reg = <0x0a0 0x005>; - clock-frequency = <0>; /* Filled in by zImage */ - - /* Hotfoot has UART0/UART1 swapped */ - - UART0: serial@ef600400 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0xef600400 0x00000008>; - virtual-reg = <0xef600400>; - clock-frequency = <0>; /* Filled in by zImage */ - current-speed = <0x9600>; - interrupt-parent = <&UIC0>; - interrupts = <0x1 0x4>; - }; - - UART1: serial@ef600300 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0xef600300 0x00000008>; - virtual-reg = <0xef600300>; - clock-frequency = <0>; /* Filled in by zImage */ - current-speed = <0x9600>; - interrupt-parent = <&UIC0>; - interrupts = <0x0 0x4>; - }; - - IIC: i2c@ef600500 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "ibm,iic-405ep", "ibm,iic"; - reg = <0xef600500 0x00000011>; - interrupt-parent = <&UIC0>; - interrupts = <0x2 0x4>; - - rtc@68 { - /* Actually a DS1339 */ - compatible = "dallas,ds1307"; - reg = <0x68>; - }; - - temp@4a { - /* Not present on all boards */ - compatible = "national,lm75"; - reg = <0x4a>; - }; - }; - - GPIO: gpio@ef600700 { - #gpio-cells = <2>; - compatible = "ibm,ppc4xx-gpio"; - reg = <0xef600700 0x00000020>; - gpio-controller; - }; - - gpio-leds { - compatible = "gpio-leds"; - status { - label = "Status"; - gpios = <&GPIO 1 0>; - }; - radiorx { - label = "Rx"; - gpios = <&GPIO 0xe 0>; - }; - }; - - EMAC0: ethernet@ef600800 { - linux,network-index = <0x0>; - device_type = "network"; - compatible = "ibm,emac-405ep", "ibm,emac"; - interrupt-parent = <&UIC0>; - interrupts = < - 0xf 0x4 /* Ethernet */ - 0x9 0x4 /* Ethernet Wake Up */>; - local-mac-address = [000000000000]; /* Filled in by zImage */ - reg = <0xef600800 0x00000070>; - mal-device = <&MAL>; - mal-tx-channel = <0>; - mal-rx-channel = <0>; - cell-index = <0>; - max-frame-size = <0x5dc>; - rx-fifo-size = <0x1000>; - tx-fifo-size = <0x800>; - phy-mode = "mii"; - phy-map = <0x00000000>; - }; - - EMAC1: ethernet@ef600900 { - linux,network-index = <0x1>; - device_type = "network"; - compatible = "ibm,emac-405ep", "ibm,emac"; - interrupt-parent = <&UIC0>; - interrupts = < - 0x11 0x4 /* Ethernet */ - 0x9 0x4 /* Ethernet Wake Up */>; - local-mac-address = [000000000000]; /* Filled in by zImage */ - reg = <0xef600900 0x00000070>; - mal-device = <&MAL>; - mal-tx-channel = <2>; - mal-rx-channel = <1>; - cell-index = <1>; - max-frame-size = <0x5dc>; - rx-fifo-size = <0x1000>; - tx-fifo-size = <0x800>; - mdio-device = <&EMAC0>; - phy-mode = "mii"; - phy-map = <0x0000001>; - }; - }; - - EBC0: ebc { - compatible = "ibm,ebc-405ep", "ibm,ebc"; - dcr-reg = <0x012 0x002>; - #address-cells = <2>; - #size-cells = <1>; - - /* The ranges property is supplied by the bootwrapper - * and is based on the firmware's configuration of the - * EBC bridge - */ - clock-frequency = <0>; /* Filled in by zImage */ - - nor_flash@0 { - compatible = "cfi-flash"; - bank-width = <2>; - reg = <0x0 0xff800000 0x00800000>; - #address-cells = <1>; - #size-cells = <1>; - - /* This mapping is for the 8M flash - 4M flash has all ofssets -= 4M, - and FeatFS partition is not present */ - partition@0 { - label = "Bootloader"; - reg = <0x7c0000 0x40000>; - /* read-only; */ - }; - partition@1 { - label = "Env_and_Config_Primary"; - reg = <0x400000 0x10000>; - }; - partition@2 { - label = "Kernel"; - reg = <0x420000 0x100000>; - }; - partition@3 { - label = "Filesystem"; - reg = <0x520000 0x2a0000>; - }; - partition@4 { - label = "Env_and_Config_Secondary"; - reg = <0x410000 0x10000>; - }; - partition@5 { - label = "FeatFS"; - reg = <0x000000 0x400000>; - }; - partition@6 { - label = "Bootloader_Env"; - reg = <0x7d0000 0x10000>; - }; - }; - }; - - PCI0: pci@ec000000 { - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - compatible = "ibm,plb405ep-pci", "ibm,plb-pci"; - primary; - reg = <0xeec00000 0x00000008 /* Config space access */ - 0xeed80000 0x00000004 /* IACK */ - 0xeed80000 0x00000004 /* Special cycle */ - 0xef480000 0x00000040>; /* Internal registers */ - - /* Outbound ranges, one memory and one IO, - * later cannot be changed. Chip supports a second - * IO range but we don't use it for now - */ - ranges = <0x02000000 0x00000000 0x80000000 0x80000000 0x00000000 0x20000000 - 0x01000000 0x00000000 0x00000000 0xe8000000 0x00000000 0x00010000>; - - /* Inbound 2GB range starting at 0 */ - dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x80000000>; - - interrupt-parent = <&UIC0>; - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - /* IDSEL 3 -- slot1 (optional) 27/29 A/B IRQ2/4 */ - 0x1800 0x0 0x0 0x1 &UIC0 0x1b 0x8 - 0x1800 0x0 0x0 0x2 &UIC0 0x1d 0x8 - - /* IDSEL 4 -- slot0, 26/28 A/B IRQ1/3 */ - 0x2000 0x0 0x0 0x1 &UIC0 0x1a 0x8 - 0x2000 0x0 0x0 0x2 &UIC0 0x1c 0x8 - >; - }; - }; - - chosen { - stdout-path = &UART0; - }; -}; diff --git a/arch/powerpc/boot/dts/kilauea.dts b/arch/powerpc/boot/dts/kilauea.dts deleted file mode 100644 index c07a7525a72c..000000000000 --- a/arch/powerpc/boot/dts/kilauea.dts +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Device Tree Source for AMCC Kilauea (405EX) - * - * Copyright 2007-2009 DENX Software Engineering, Stefan Roese - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without - * any warranty of any kind, whether express or implied. - */ - -/dts-v1/; - -/ { - #address-cells = <1>; - #size-cells = <1>; - model = "amcc,kilauea"; - compatible = "amcc,kilauea"; - dcr-parent = <&{/cpus/cpu@0}>; - - aliases { - ethernet0 = &EMAC0; - ethernet1 = &EMAC1; - serial0 = &UART0; - serial1 = &UART1; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - model = "PowerPC,405EX"; - reg = <0x00000000>; - clock-frequency = <0>; /* Filled in by U-Boot */ - timebase-frequency = <0>; /* Filled in by U-Boot */ - i-cache-line-size = <32>; - d-cache-line-size = <32>; - i-cache-size = <16384>; /* 16 kB */ - d-cache-size = <16384>; /* 16 kB */ - dcr-controller; - dcr-access-method = "native"; - }; - }; - - memory { - device_type = "memory"; - reg = <0x00000000 0x00000000>; /* Filled in by U-Boot */ - }; - - UIC0: interrupt-controller { - compatible = "ibm,uic-405ex", "ibm,uic"; - interrupt-controller; - cell-index = <0>; - dcr-reg = <0x0c0 0x009>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - }; - - UIC1: interrupt-controller1 { - compatible = "ibm,uic-405ex","ibm,uic"; - interrupt-controller; - cell-index = <1>; - dcr-reg = <0x0d0 0x009>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */ - interrupt-parent = <&UIC0>; - }; - - UIC2: interrupt-controller2 { - compatible = "ibm,uic-405ex","ibm,uic"; - interrupt-controller; - cell-index = <2>; - dcr-reg = <0x0e0 0x009>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - interrupts = <0x1c 0x4 0x1d 0x4>; /* cascade */ - interrupt-parent = <&UIC0>; - }; - - CPM0: cpm { - compatible = "ibm,cpm"; - dcr-access-method = "native"; - dcr-reg = <0x0b0 0x003>; - unused-units = <0x00000000>; - idle-doze = <0x02000000>; - standby = <0xe3e74800>; - }; - - plb { - compatible = "ibm,plb-405ex", "ibm,plb4"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - clock-frequency = <0>; /* Filled in by U-Boot */ - - SDRAM0: memory-controller { - compatible = "ibm,sdram-405ex", "ibm,sdram-4xx-ddr2"; - dcr-reg = <0x010 0x002>; - interrupt-parent = <&UIC2>; - interrupts = <0x5 0x4 /* ECC DED Error */ - 0x6 0x4>; /* ECC SEC Error */ - }; - - CRYPTO: crypto@ef700000 { - compatible = "amcc,ppc405ex-crypto", "amcc,ppc4xx-crypto"; - reg = <0xef700000 0x80400>; - interrupt-parent = <&UIC0>; - interrupts = <0x17 0x2>; - }; - - MAL0: mcmal { - compatible = "ibm,mcmal-405ex", "ibm,mcmal2"; - dcr-reg = <0x180 0x062>; - num-tx-chans = <2>; - num-rx-chans = <2>; - interrupt-parent = <&MAL0>; - interrupts = <0x0 0x1 0x2 0x3 0x4>; - #interrupt-cells = <1>; - #address-cells = <0>; - #size-cells = <0>; - interrupt-map = ; - interrupt-map-mask = <0xffffffff>; - }; - - POB0: opb { - compatible = "ibm,opb-405ex", "ibm,opb"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x80000000 0x80000000 0x10000000 - 0xef600000 0xef600000 0x00a00000 - 0xf0000000 0xf0000000 0x10000000>; - dcr-reg = <0x0a0 0x005>; - clock-frequency = <0>; /* Filled in by U-Boot */ - - EBC0: ebc { - compatible = "ibm,ebc-405ex", "ibm,ebc"; - dcr-reg = <0x012 0x002>; - #address-cells = <2>; - #size-cells = <1>; - clock-frequency = <0>; /* Filled in by U-Boot */ - /* ranges property is supplied by U-Boot */ - interrupts = <0x5 0x1>; - interrupt-parent = <&UIC1>; - - nor_flash@0,0 { - compatible = "amd,s29gl512n", "cfi-flash"; - bank-width = <2>; - reg = <0x00000000 0x00000000 0x04000000>; - #address-cells = <1>; - #size-cells = <1>; - partition@0 { - label = "kernel"; - reg = <0x00000000 0x001e0000>; - }; - partition@1e0000 { - label = "dtb"; - reg = <0x001e0000 0x00020000>; - }; - partition@200000 { - label = "root"; - reg = <0x00200000 0x00200000>; - }; - partition@400000 { - label = "user"; - reg = <0x00400000 0x03b60000>; - }; - partition@3f60000 { - label = "env"; - reg = <0x03f60000 0x00040000>; - }; - partition@3fa0000 { - label = "u-boot"; - reg = <0x03fa0000 0x00060000>; - }; - }; - - ndfc@1,0 { - compatible = "ibm,ndfc"; - reg = <0x00000001 0x00000000 0x00002000>; - ccr = <0x00001000>; - bank-settings = <0x80002222>; - #address-cells = <1>; - #size-cells = <1>; - - nand { - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "u-boot"; - reg = <0x00000000 0x00100000>; - }; - partition@100000 { - label = "user"; - reg = <0x00000000 0x03f00000>; - }; - }; - }; - }; - - UART0: serial@ef600200 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0xef600200 0x00000008>; - virtual-reg = <0xef600200>; - clock-frequency = <0>; /* Filled in by U-Boot */ - current-speed = <0>; - interrupt-parent = <&UIC0>; - interrupts = <0x1a 0x4>; - }; - - UART1: serial@ef600300 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0xef600300 0x00000008>; - virtual-reg = <0xef600300>; - clock-frequency = <0>; /* Filled in by U-Boot */ - current-speed = <0>; - interrupt-parent = <&UIC0>; - interrupts = <0x1 0x4>; - }; - - IIC0: i2c@ef600400 { - compatible = "ibm,iic-405ex", "ibm,iic"; - reg = <0xef600400 0x00000014>; - interrupt-parent = <&UIC0>; - interrupts = <0x2 0x4>; - #address-cells = <1>; - #size-cells = <0>; - - rtc@68 { - compatible = "dallas,ds1338"; - reg = <0x68>; - }; - - dtt@48 { - compatible = "dallas,ds1775"; - reg = <0x48>; - }; - }; - - IIC1: i2c@ef600500 { - compatible = "ibm,iic-405ex", "ibm,iic"; - reg = <0xef600500 0x00000014>; - interrupt-parent = <&UIC0>; - interrupts = <0x7 0x4>; - }; - - RGMII0: emac-rgmii@ef600b00 { - compatible = "ibm,rgmii-405ex", "ibm,rgmii"; - reg = <0xef600b00 0x00000104>; - has-mdio; - }; - - EMAC0: ethernet@ef600900 { - linux,network-index = <0x0>; - device_type = "network"; - compatible = "ibm,emac-405ex", "ibm,emac4sync"; - interrupt-parent = <&EMAC0>; - interrupts = <0x0 0x1>; - #interrupt-cells = <1>; - #address-cells = <0>; - #size-cells = <0>; - interrupt-map = ; - reg = <0xef600900 0x000000c4>; - local-mac-address = [000000000000]; /* Filled in by U-Boot */ - mal-device = <&MAL0>; - mal-tx-channel = <0>; - mal-rx-channel = <0>; - cell-index = <0>; - max-frame-size = <9000>; - rx-fifo-size = <4096>; - tx-fifo-size = <2048>; - rx-fifo-size-gige = <16384>; - tx-fifo-size-gige = <16384>; - phy-mode = "rgmii"; - phy-map = <0x00000000>; - rgmii-device = <&RGMII0>; - rgmii-channel = <0>; - has-inverted-stacr-oc; - has-new-stacr-staopc; - }; - - EMAC1: ethernet@ef600a00 { - linux,network-index = <0x1>; - device_type = "network"; - compatible = "ibm,emac-405ex", "ibm,emac4sync"; - interrupt-parent = <&EMAC1>; - interrupts = <0x0 0x1>; - #interrupt-cells = <1>; - #address-cells = <0>; - #size-cells = <0>; - interrupt-map = ; - reg = <0xef600a00 0x000000c4>; - local-mac-address = [000000000000]; /* Filled in by U-Boot */ - mal-device = <&MAL0>; - mal-tx-channel = <1>; - mal-rx-channel = <1>; - cell-index = <1>; - max-frame-size = <9000>; - rx-fifo-size = <4096>; - tx-fifo-size = <2048>; - rx-fifo-size-gige = <16384>; - tx-fifo-size-gige = <16384>; - phy-mode = "rgmii"; - phy-map = <0x00000000>; - rgmii-device = <&RGMII0>; - rgmii-channel = <1>; - has-inverted-stacr-oc; - has-new-stacr-staopc; - }; - }; - - PCIE0: pcie@a0000000 { - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - compatible = "ibm,plb-pciex-405ex", "ibm,plb-pciex"; - primary; - port = <0x0>; /* port number */ - reg = <0xa0000000 0x20000000 /* Config space access */ - 0xef000000 0x00001000>; /* Registers */ - dcr-reg = <0x040 0x020>; - sdr-base = <0x400>; - - /* Outbound ranges, one memory and one IO, - * later cannot be changed - */ - ranges = <0x02000000 0x00000000 0x80000000 0x90000000 0x00000000 0x08000000 - 0x01000000 0x00000000 0x00000000 0xe0000000 0x00000000 0x00010000>; - - /* Inbound 2GB range starting at 0 */ - dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x80000000>; - - /* This drives busses 0x00 to 0x3f */ - bus-range = <0x0 0x3f>; - - /* Legacy interrupts (note the weird polarity, the bridge seems - * to invert PCIe legacy interrupts). - * We are de-swizzling here because the numbers are actually for - * port of the root complex virtual P2P bridge. But I want - * to avoid putting a node for it in the tree, so the numbers - * below are basically de-swizzled numbers. - * The real slot is on idsel 0, so the swizzling is 1:1 - */ - interrupt-map-mask = <0x0 0x0 0x0 0x7>; - interrupt-map = < - 0x0 0x0 0x0 0x1 &UIC2 0x0 0x4 /* swizzled int A */ - 0x0 0x0 0x0 0x2 &UIC2 0x1 0x4 /* swizzled int B */ - 0x0 0x0 0x0 0x3 &UIC2 0x2 0x4 /* swizzled int C */ - 0x0 0x0 0x0 0x4 &UIC2 0x3 0x4 /* swizzled int D */>; - }; - - PCIE1: pcie@c0000000 { - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - compatible = "ibm,plb-pciex-405ex", "ibm,plb-pciex"; - primary; - port = <0x1>; /* port number */ - reg = <0xc0000000 0x20000000 /* Config space access */ - 0xef001000 0x00001000>; /* Registers */ - dcr-reg = <0x060 0x020>; - sdr-base = <0x440>; - - /* Outbound ranges, one memory and one IO, - * later cannot be changed - */ - ranges = <0x02000000 0x00000000 0x80000000 0x98000000 0x00000000 0x08000000 - 0x01000000 0x00000000 0x00000000 0xe0010000 0x00000000 0x00010000>; - - /* Inbound 2GB range starting at 0 */ - dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x80000000>; - - /* This drives busses 0x40 to 0x7f */ - bus-range = <0x40 0x7f>; - - /* Legacy interrupts (note the weird polarity, the bridge seems - * to invert PCIe legacy interrupts). - * We are de-swizzling here because the numbers are actually for - * port of the root complex virtual P2P bridge. But I want - * to avoid putting a node for it in the tree, so the numbers - * below are basically de-swizzled numbers. - * The real slot is on idsel 0, so the swizzling is 1:1 - */ - interrupt-map-mask = <0x0 0x0 0x0 0x7>; - interrupt-map = < - 0x0 0x0 0x0 0x1 &UIC2 0xb 0x4 /* swizzled int A */ - 0x0 0x0 0x0 0x2 &UIC2 0xc 0x4 /* swizzled int B */ - 0x0 0x0 0x0 0x3 &UIC2 0xd 0x4 /* swizzled int C */ - 0x0 0x0 0x0 0x4 &UIC2 0xe 0x4 /* swizzled int D */>; - }; - }; -}; diff --git a/arch/powerpc/boot/dts/klondike.dts b/arch/powerpc/boot/dts/klondike.dts deleted file mode 100644 index 97432177892a..000000000000 --- a/arch/powerpc/boot/dts/klondike.dts +++ /dev/null @@ -1,212 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Device Tree for Klondike (APM8018X) board. - * - * Copyright (c) 2010, Applied Micro Circuits Corporation - * Author: Tanmay Inamdar - */ - -/dts-v1/; - -/ { - #address-cells = <1>; - #size-cells = <1>; - model = "apm,klondike"; - compatible = "apm,klondike"; - dcr-parent = <&{/cpus/cpu@0}>; - - aliases { - ethernet0 = &EMAC0; - ethernet1 = &EMAC1; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - model = "PowerPC,apm8018x"; - reg = <0x00000000>; - clock-frequency = <300000000>; /* Filled in by U-Boot */ - timebase-frequency = <300000000>; /* Filled in by U-Boot */ - i-cache-line-size = <32>; - d-cache-line-size = <32>; - i-cache-size = <16384>; /* 16 kB */ - d-cache-size = <16384>; /* 16 kB */ - dcr-controller; - dcr-access-method = "native"; - }; - }; - - memory { - device_type = "memory"; - reg = <0x00000000 0x20000000>; /* Filled in by U-Boot */ - }; - - UIC0: interrupt-controller { - compatible = "ibm,uic"; - interrupt-controller; - cell-index = <0>; - dcr-reg = <0x0c0 0x010>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - }; - - UIC1: interrupt-controller1 { - compatible = "ibm,uic"; - interrupt-controller; - cell-index = <1>; - dcr-reg = <0x0d0 0x010>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */ - interrupt-parent = <&UIC0>; - }; - - UIC2: interrupt-controller2 { - compatible = "ibm,uic"; - interrupt-controller; - cell-index = <2>; - dcr-reg = <0x0e0 0x010>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - interrupts = <0x0a 0x4 0x0b 0x4>; /* cascade */ - interrupt-parent = <&UIC0>; - }; - - UIC3: interrupt-controller3 { - compatible = "ibm,uic"; - interrupt-controller; - cell-index = <3>; - dcr-reg = <0x0f0 0x010>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - interrupts = <0x10 0x4 0x11 0x4>; /* cascade */ - interrupt-parent = <&UIC0>; - }; - - plb { - compatible = "ibm,plb4"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - clock-frequency = <0>; /* Filled in by U-Boot */ - - SDRAM0: memory-controller { - compatible = "ibm,sdram-apm8018x"; - dcr-reg = <0x010 0x002>; - }; - - MAL0: mcmal { - compatible = "ibm,mcmal2"; - dcr-reg = <0x180 0x062>; - num-tx-chans = <2>; - num-rx-chans = <16>; - #address-cells = <0>; - #size-cells = <0>; - interrupt-parent = <&UIC1>; - interrupts = ; - }; - - POB0: opb { - compatible = "ibm,opb"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x20000000 0x20000000 0x30000000 - 0x50000000 0x50000000 0x10000000 - 0x60000000 0x60000000 0x10000000 - 0xFE000000 0xFE000000 0x00010000>; - dcr-reg = <0x100 0x020>; - clock-frequency = <300000000>; /* Filled in by U-Boot */ - - RGMII0: emac-rgmii@400a2000 { - compatible = "ibm,rgmii"; - reg = <0x400a2000 0x00000010>; - has-mdio; - }; - - TAH0: emac-tah@400a3000 { - compatible = "ibm,tah"; - reg = <0x400a3000 0x100>; - }; - - TAH1: emac-tah@400a4000 { - compatible = "ibm,tah"; - reg = <0x400a4000 0x100>; - }; - - EMAC0: ethernet@400a0000 { - compatible = "ibm,emac4", "ibm-emac4sync"; - interrupt-parent = <&EMAC0>; - interrupts = <0x0>; - #interrupt-cells = <1>; - #address-cells = <0>; - #size-cells = <0>; - interrupt-map = ; - reg = <0x400a0000 0x00000100>; - local-mac-address = [000000000000]; /* Filled in by U-Boot */ - mal-device = <&MAL0>; - mal-tx-channel = <0x0>; - mal-rx-channel = <0x0>; - cell-index = <0>; - max-frame-size = <9000>; - rx-fifo-size = <4096>; - tx-fifo-size = <2048>; - phy-mode = "rgmii"; - phy-address = <0x2>; - turbo = "no"; - phy-map = <0x00000000>; - rgmii-device = <&RGMII0>; - rgmii-channel = <0>; - tah-device = <&TAH0>; - tah-channel = <0>; - has-inverted-stacr-oc; - has-new-stacr-staopc; - }; - - EMAC1: ethernet@400a1000 { - compatible = "ibm,emac4", "ibm-emac4sync"; - status = "disabled"; - interrupt-parent = <&EMAC1>; - interrupts = <0x0>; - #interrupt-cells = <1>; - #address-cells = <0>; - #size-cells = <0>; - interrupt-map = ; - reg = <0x400a1000 0x00000100>; - local-mac-address = [000000000000]; /* Filled in by U-Boot */ - mal-device = <&MAL0>; - mal-tx-channel = <1>; - mal-rx-channel = <8>; - cell-index = <1>; - max-frame-size = <9000>; - rx-fifo-size = <4096>; - tx-fifo-size = <2048>; - phy-mode = "rgmii"; - phy-address = <0x3>; - turbo = "no"; - phy-map = <0x00000000>; - rgmii-device = <&RGMII0>; - rgmii-channel = <1>; - tah-device = <&TAH1>; - tah-channel = <0>; - has-inverted-stacr-oc; - has-new-stacr-staopc; - mdio-device = <&EMAC0>; - }; - }; - }; - - chosen { - stdout-path = "/plb/opb/serial@50001000"; - }; -}; diff --git a/arch/powerpc/boot/dts/makalu.dts b/arch/powerpc/boot/dts/makalu.dts deleted file mode 100644 index c473cd911bca..000000000000 --- a/arch/powerpc/boot/dts/makalu.dts +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Device Tree Source for AMCC Makalu (405EX) - * - * Copyright 2007 DENX Software Engineering, Stefan Roese - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without - * any warranty of any kind, whether express or implied. - */ - -/dts-v1/; - -/ { - #address-cells = <1>; - #size-cells = <1>; - model = "amcc,makalu"; - compatible = "amcc,makalu"; - dcr-parent = <&{/cpus/cpu@0}>; - - aliases { - ethernet0 = &EMAC0; - ethernet1 = &EMAC1; - serial0 = &UART0; - serial1 = &UART1; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - model = "PowerPC,405EX"; - reg = <0x00000000>; - clock-frequency = <0>; /* Filled in by U-Boot */ - timebase-frequency = <0>; /* Filled in by U-Boot */ - i-cache-line-size = <32>; - d-cache-line-size = <32>; - i-cache-size = <16384>; /* 16 kB */ - d-cache-size = <16384>; /* 16 kB */ - dcr-controller; - dcr-access-method = "native"; - }; - }; - - memory { - device_type = "memory"; - reg = <0x00000000 0x00000000>; /* Filled in by U-Boot */ - }; - - UIC0: interrupt-controller { - compatible = "ibm,uic-405ex", "ibm,uic"; - interrupt-controller; - cell-index = <0>; - dcr-reg = <0x0c0 0x009>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - }; - - UIC1: interrupt-controller1 { - compatible = "ibm,uic-405ex","ibm,uic"; - interrupt-controller; - cell-index = <1>; - dcr-reg = <0x0d0 0x009>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */ - interrupt-parent = <&UIC0>; - }; - - UIC2: interrupt-controller2 { - compatible = "ibm,uic-405ex","ibm,uic"; - interrupt-controller; - cell-index = <2>; - dcr-reg = <0x0e0 0x009>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - interrupts = <0x1c 0x4 0x1d 0x4>; /* cascade */ - interrupt-parent = <&UIC0>; - }; - - plb { - compatible = "ibm,plb-405ex", "ibm,plb4"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - clock-frequency = <0>; /* Filled in by U-Boot */ - - SDRAM0: memory-controller { - compatible = "ibm,sdram-405ex", "ibm,sdram-4xx-ddr2"; - dcr-reg = <0x010 0x002>; - interrupt-parent = <&UIC2>; - interrupts = <0x5 0x4 /* ECC DED Error */ - 0x6 0x4 /* ECC SEC Error */ >; - }; - - MAL0: mcmal { - compatible = "ibm,mcmal-405ex", "ibm,mcmal2"; - dcr-reg = <0x180 0x062>; - num-tx-chans = <2>; - num-rx-chans = <2>; - interrupt-parent = <&MAL0>; - interrupts = <0x0 0x1 0x2 0x3 0x4>; - #interrupt-cells = <1>; - #address-cells = <0>; - #size-cells = <0>; - interrupt-map = ; - interrupt-map-mask = <0xffffffff>; - }; - - POB0: opb { - compatible = "ibm,opb-405ex", "ibm,opb"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x80000000 0x80000000 0x10000000 - 0xef600000 0xef600000 0x00a00000 - 0xf0000000 0xf0000000 0x10000000>; - dcr-reg = <0x0a0 0x005>; - clock-frequency = <0>; /* Filled in by U-Boot */ - - EBC0: ebc { - compatible = "ibm,ebc-405ex", "ibm,ebc"; - dcr-reg = <0x012 0x002>; - #address-cells = <2>; - #size-cells = <1>; - clock-frequency = <0>; /* Filled in by U-Boot */ - /* ranges property is supplied by U-Boot */ - interrupts = <0x5 0x1>; - interrupt-parent = <&UIC1>; - - nor_flash@0,0 { - compatible = "amd,s29gl512n", "cfi-flash"; - bank-width = <2>; - reg = <0x00000000 0x00000000 0x04000000>; - #address-cells = <1>; - #size-cells = <1>; - partition@0 { - label = "kernel"; - reg = <0x00000000 0x00200000>; - }; - partition@200000 { - label = "root"; - reg = <0x00200000 0x00200000>; - }; - partition@400000 { - label = "user"; - reg = <0x00400000 0x03b60000>; - }; - partition@3f60000 { - label = "env"; - reg = <0x03f60000 0x00040000>; - }; - partition@3fa0000 { - label = "u-boot"; - reg = <0x03fa0000 0x00060000>; - }; - }; - }; - - UART0: serial@ef600200 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0xef600200 0x00000008>; - virtual-reg = <0xef600200>; - clock-frequency = <0>; /* Filled in by U-Boot */ - current-speed = <0>; - interrupt-parent = <&UIC0>; - interrupts = <0x1a 0x4>; - }; - - UART1: serial@ef600300 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0xef600300 0x00000008>; - virtual-reg = <0xef600300>; - clock-frequency = <0>; /* Filled in by U-Boot */ - current-speed = <0>; - interrupt-parent = <&UIC0>; - interrupts = <0x1 0x4>; - }; - - IIC0: i2c@ef600400 { - compatible = "ibm,iic-405ex", "ibm,iic"; - reg = <0xef600400 0x00000014>; - interrupt-parent = <&UIC0>; - interrupts = <0x2 0x4>; - }; - - IIC1: i2c@ef600500 { - compatible = "ibm,iic-405ex", "ibm,iic"; - reg = <0xef600500 0x00000014>; - interrupt-parent = <&UIC0>; - interrupts = <0x7 0x4>; - }; - - - RGMII0: emac-rgmii@ef600b00 { - compatible = "ibm,rgmii-405ex", "ibm,rgmii"; - reg = <0xef600b00 0x00000104>; - has-mdio; - }; - - EMAC0: ethernet@ef600900 { - linux,network-index = <0x0>; - device_type = "network"; - compatible = "ibm,emac-405ex", "ibm,emac4sync"; - interrupt-parent = <&EMAC0>; - interrupts = <0x0 0x1>; - #interrupt-cells = <1>; - #address-cells = <0>; - #size-cells = <0>; - interrupt-map = ; - reg = <0xef600900 0x000000c4>; - local-mac-address = [000000000000]; /* Filled in by U-Boot */ - mal-device = <&MAL0>; - mal-tx-channel = <0>; - mal-rx-channel = <0>; - cell-index = <0>; - max-frame-size = <9000>; - rx-fifo-size = <4096>; - tx-fifo-size = <2048>; - rx-fifo-size-gige = <16384>; - tx-fifo-size-gige = <16384>; - phy-mode = "rgmii"; - phy-map = <0x0000003f>; /* Start at 6 */ - rgmii-device = <&RGMII0>; - rgmii-channel = <0>; - has-inverted-stacr-oc; - has-new-stacr-staopc; - }; - - EMAC1: ethernet@ef600a00 { - linux,network-index = <0x1>; - device_type = "network"; - compatible = "ibm,emac-405ex", "ibm,emac4sync"; - interrupt-parent = <&EMAC1>; - interrupts = <0x0 0x1>; - #interrupt-cells = <1>; - #address-cells = <0>; - #size-cells = <0>; - interrupt-map = ; - reg = <0xef600a00 0x000000c4>; - local-mac-address = [000000000000]; /* Filled in by U-Boot */ - mal-device = <&MAL0>; - mal-tx-channel = <1>; - mal-rx-channel = <1>; - cell-index = <1>; - max-frame-size = <9000>; - rx-fifo-size = <4096>; - tx-fifo-size = <2048>; - rx-fifo-size-gige = <16384>; - tx-fifo-size-gige = <16384>; - phy-mode = "rgmii"; - phy-map = <0x00000000>; - rgmii-device = <&RGMII0>; - rgmii-channel = <1>; - has-inverted-stacr-oc; - has-new-stacr-staopc; - }; - }; - - PCIE0: pcie@a0000000 { - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - compatible = "ibm,plb-pciex-405ex", "ibm,plb-pciex"; - primary; - port = <0x0>; /* port number */ - reg = <0xa0000000 0x20000000 /* Config space access */ - 0xef000000 0x00001000>; /* Registers */ - dcr-reg = <0x040 0x020>; - sdr-base = <0x400>; - - /* Outbound ranges, one memory and one IO, - * later cannot be changed - */ - ranges = <0x02000000 0x00000000 0x80000000 0x90000000 0x00000000 0x08000000 - 0x01000000 0x00000000 0x00000000 0xe0000000 0x00000000 0x00010000>; - - /* Inbound 2GB range starting at 0 */ - dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x80000000>; - - /* This drives busses 0x00 to 0x3f */ - bus-range = <0x0 0x3f>; - - /* Legacy interrupts (note the weird polarity, the bridge seems - * to invert PCIe legacy interrupts). - * We are de-swizzling here because the numbers are actually for - * port of the root complex virtual P2P bridge. But I want - * to avoid putting a node for it in the tree, so the numbers - * below are basically de-swizzled numbers. - * The real slot is on idsel 0, so the swizzling is 1:1 - */ - interrupt-map-mask = <0x0 0x0 0x0 0x7>; - interrupt-map = < - 0x0 0x0 0x0 0x1 &UIC2 0x0 0x4 /* swizzled int A */ - 0x0 0x0 0x0 0x2 &UIC2 0x1 0x4 /* swizzled int B */ - 0x0 0x0 0x0 0x3 &UIC2 0x2 0x4 /* swizzled int C */ - 0x0 0x0 0x0 0x4 &UIC2 0x3 0x4 /* swizzled int D */>; - }; - - PCIE1: pcie@c0000000 { - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - compatible = "ibm,plb-pciex-405ex", "ibm,plb-pciex"; - primary; - port = <0x1>; /* port number */ - reg = <0xc0000000 0x20000000 /* Config space access */ - 0xef001000 0x00001000>; /* Registers */ - dcr-reg = <0x060 0x020>; - sdr-base = <0x440>; - - /* Outbound ranges, one memory and one IO, - * later cannot be changed - */ - ranges = <0x02000000 0x00000000 0x80000000 0x98000000 0x00000000 0x08000000 - 0x01000000 0x00000000 0x00000000 0xe0010000 0x00000000 0x00010000>; - - /* Inbound 2GB range starting at 0 */ - dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x80000000>; - - /* This drives busses 0x40 to 0x7f */ - bus-range = <0x40 0x7f>; - - /* Legacy interrupts (note the weird polarity, the bridge seems - * to invert PCIe legacy interrupts). - * We are de-swizzling here because the numbers are actually for - * port of the root complex virtual P2P bridge. But I want - * to avoid putting a node for it in the tree, so the numbers - * below are basically de-swizzled numbers. - * The real slot is on idsel 0, so the swizzling is 1:1 - */ - interrupt-map-mask = <0x0 0x0 0x0 0x7>; - interrupt-map = < - 0x0 0x0 0x0 0x1 &UIC2 0xb 0x4 /* swizzled int A */ - 0x0 0x0 0x0 0x2 &UIC2 0xc 0x4 /* swizzled int B */ - 0x0 0x0 0x0 0x3 &UIC2 0xd 0x4 /* swizzled int C */ - 0x0 0x0 0x0 0x4 &UIC2 0xe 0x4 /* swizzled int D */>; - }; - }; -}; diff --git a/arch/powerpc/boot/dts/obs600.dts b/arch/powerpc/boot/dts/obs600.dts deleted file mode 100644 index d10b0411809b..000000000000 --- a/arch/powerpc/boot/dts/obs600.dts +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Device Tree Source for PlatHome OpenBlockS 600 (405EX) - * - * Copyright 2011 Ben Herrenschmidt, IBM Corp. - * - * Based on Kilauea by: - * - * Copyright 2007-2009 DENX Software Engineering, Stefan Roese - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without - * any warranty of any kind, whether express or implied. - */ - -/dts-v1/; - -/ { - #address-cells = <1>; - #size-cells = <1>; - model = "PlatHome,OpenBlockS 600"; - compatible = "plathome,obs600"; - dcr-parent = <&{/cpus/cpu@0}>; - - aliases { - ethernet0 = &EMAC0; - ethernet1 = &EMAC1; - serial0 = &UART0; - serial1 = &UART1; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - model = "PowerPC,405EX"; - reg = <0x00000000>; - clock-frequency = <0>; /* Filled in by U-Boot */ - timebase-frequency = <0>; /* Filled in by U-Boot */ - i-cache-line-size = <32>; - d-cache-line-size = <32>; - i-cache-size = <16384>; /* 16 kB */ - d-cache-size = <16384>; /* 16 kB */ - dcr-controller; - dcr-access-method = "native"; - }; - }; - - memory { - device_type = "memory"; - reg = <0x00000000 0x00000000>; /* Filled in by U-Boot */ - }; - - UIC0: interrupt-controller { - compatible = "ibm,uic-405ex", "ibm,uic"; - interrupt-controller; - cell-index = <0>; - dcr-reg = <0x0c0 0x009>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - }; - - UIC1: interrupt-controller1 { - compatible = "ibm,uic-405ex","ibm,uic"; - interrupt-controller; - cell-index = <1>; - dcr-reg = <0x0d0 0x009>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */ - interrupt-parent = <&UIC0>; - }; - - UIC2: interrupt-controller2 { - compatible = "ibm,uic-405ex","ibm,uic"; - interrupt-controller; - cell-index = <2>; - dcr-reg = <0x0e0 0x009>; - #address-cells = <0>; - #size-cells = <0>; - #interrupt-cells = <2>; - interrupts = <0x1c 0x4 0x1d 0x4>; /* cascade */ - interrupt-parent = <&UIC0>; - }; - - CPM0: cpm { - compatible = "ibm,cpm"; - dcr-access-method = "native"; - dcr-reg = <0x0b0 0x003>; - unused-units = <0x00000000>; - idle-doze = <0x02000000>; - standby = <0xe3e74800>; - }; - - plb { - compatible = "ibm,plb-405ex", "ibm,plb4"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - clock-frequency = <0>; /* Filled in by U-Boot */ - - SDRAM0: memory-controller { - compatible = "ibm,sdram-405ex", "ibm,sdram-4xx-ddr2"; - dcr-reg = <0x010 0x002>; - interrupt-parent = <&UIC2>; - interrupts = <0x5 0x4 /* ECC DED Error */ - 0x6 0x4>; /* ECC SEC Error */ - }; - - CRYPTO: crypto@ef700000 { - compatible = "amcc,ppc405ex-crypto", "amcc,ppc4xx-crypto"; - reg = <0xef700000 0x80400>; - interrupt-parent = <&UIC0>; - interrupts = <0x17 0x2>; - }; - - MAL0: mcmal { - compatible = "ibm,mcmal-405ex", "ibm,mcmal2"; - dcr-reg = <0x180 0x062>; - num-tx-chans = <2>; - num-rx-chans = <2>; - interrupt-parent = <&MAL0>; - interrupts = <0x0 0x1 0x2 0x3 0x4>; - #interrupt-cells = <1>; - #address-cells = <0>; - #size-cells = <0>; - interrupt-map = ; - interrupt-map-mask = <0xffffffff>; - }; - - POB0: opb { - compatible = "ibm,opb-405ex", "ibm,opb"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x80000000 0x80000000 0x10000000 - 0xef600000 0xef600000 0x00a00000 - 0xf0000000 0xf0000000 0x10000000>; - dcr-reg = <0x0a0 0x005>; - clock-frequency = <0>; /* Filled in by U-Boot */ - - EBC0: ebc { - compatible = "ibm,ebc-405ex", "ibm,ebc"; - dcr-reg = <0x012 0x002>; - #address-cells = <2>; - #size-cells = <1>; - clock-frequency = <0>; /* Filled in by U-Boot */ - /* ranges property is supplied by U-Boot */ - interrupts = <0x5 0x1>; - interrupt-parent = <&UIC1>; - - nor_flash@0,0 { - compatible = "amd,s29gl512n", "cfi-flash"; - bank-width = <2>; - reg = <0x00000000 0x00000000 0x08000000>; - #address-cells = <1>; - #size-cells = <1>; - partition@0 { - label = "kernel + initrd"; - reg = <0x00000000 0x03de0000>; - }; - partition@3de0000 { - label = "user config area"; - reg = <0x03de0000 0x00080000>; - }; - partition@3e60000 { - label = "user program area"; - reg = <0x03e60000 0x04000000>; - }; - partition@7e60000 { - label = "flat device tree"; - reg = <0x07e60000 0x00080000>; - }; - partition@7ee0000 { - label = "test program"; - reg = <0x07ee0000 0x00080000>; - }; - partition@7f60000 { - label = "u-boot env"; - reg = <0x07f60000 0x00040000>; - }; - partition@7fa0000 { - label = "u-boot"; - reg = <0x07fa0000 0x00060000>; - }; - }; - }; - - UART0: serial@ef600200 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0xef600200 0x00000008>; - virtual-reg = <0xef600200>; - clock-frequency = <0>; /* Filled in by U-Boot */ - current-speed = <0>; - interrupt-parent = <&UIC0>; - interrupts = <0x1a 0x4>; - }; - - UART1: serial@ef600300 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0xef600300 0x00000008>; - virtual-reg = <0xef600300>; - clock-frequency = <0>; /* Filled in by U-Boot */ - current-speed = <0>; - interrupt-parent = <&UIC0>; - interrupts = <0x1 0x4>; - }; - - IIC0: i2c@ef600400 { - compatible = "ibm,iic-405ex", "ibm,iic"; - reg = <0xef600400 0x00000014>; - interrupt-parent = <&UIC0>; - interrupts = <0x2 0x4>; - #address-cells = <1>; - #size-cells = <0>; - - rtc@68 { - compatible = "dallas,ds1340"; - reg = <0x68>; - }; - }; - - IIC1: i2c@ef600500 { - compatible = "ibm,iic-405ex", "ibm,iic"; - reg = <0xef600500 0x00000014>; - interrupt-parent = <&UIC0>; - interrupts = <0x7 0x4>; - }; - - RGMII0: emac-rgmii@ef600b00 { - compatible = "ibm,rgmii-405ex", "ibm,rgmii"; - reg = <0xef600b00 0x00000104>; - has-mdio; - }; - - EMAC0: ethernet@ef600900 { - linux,network-index = <0x0>; - device_type = "network"; - compatible = "ibm,emac-405ex", "ibm,emac4sync"; - interrupt-parent = <&EMAC0>; - interrupts = <0x0 0x1>; - #interrupt-cells = <1>; - #address-cells = <0>; - #size-cells = <0>; - interrupt-map = ; - reg = <0xef600900 0x000000c4>; - local-mac-address = [000000000000]; /* Filled in by U-Boot */ - mal-device = <&MAL0>; - mal-tx-channel = <0>; - mal-rx-channel = <0>; - cell-index = <0>; - max-frame-size = <9000>; - rx-fifo-size = <4096>; - tx-fifo-size = <2048>; - rx-fifo-size-gige = <16384>; - tx-fifo-size-gige = <16384>; - phy-mode = "rgmii"; - phy-map = <0x00000000>; - rgmii-device = <&RGMII0>; - rgmii-channel = <0>; - has-inverted-stacr-oc; - has-new-stacr-staopc; - }; - - EMAC1: ethernet@ef600a00 { - linux,network-index = <0x1>; - device_type = "network"; - compatible = "ibm,emac-405ex", "ibm,emac4sync"; - interrupt-parent = <&EMAC1>; - interrupts = <0x0 0x1>; - #interrupt-cells = <1>; - #address-cells = <0>; - #size-cells = <0>; - interrupt-map = ; - reg = <0xef600a00 0x000000c4>; - local-mac-address = [000000000000]; /* Filled in by U-Boot */ - mal-device = <&MAL0>; - mal-tx-channel = <1>; - mal-rx-channel = <1>; - cell-index = <1>; - max-frame-size = <9000>; - rx-fifo-size = <4096>; - tx-fifo-size = <2048>; - rx-fifo-size-gige = <16384>; - tx-fifo-size-gige = <16384>; - phy-mode = "rgmii"; - phy-map = <0x00000000>; - rgmii-device = <&RGMII0>; - rgmii-channel = <1>; - has-inverted-stacr-oc; - has-new-stacr-staopc; - }; - - GPIO: gpio@ef600800 { - device_type = "gpio"; - compatible = "ibm,gpio-405ex", "ibm,ppc4xx-gpio"; - reg = <0xef600800 0x50>; - }; - }; - }; - chosen { - stdout-path = "/plb/opb/serial@ef600200"; - }; -}; diff --git a/arch/powerpc/boot/ppcboot-hotfoot.h b/arch/powerpc/boot/ppcboot-hotfoot.h deleted file mode 100644 index 4728db95f58a..000000000000 --- a/arch/powerpc/boot/ppcboot-hotfoot.h +++ /dev/null @@ -1,119 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * This interface is used for compatibility with old U-boots *ONLY*. - * Please do not imitate or extend this. - */ - -/* - * Unfortunately, the ESTeem Hotfoot board uses a mangled version of - * ppcboot.h for historical reasons, and in the interest of having a - * mainline kernel boot on the production board+bootloader, this was the - * least-offensive solution. Please direct all flames to: - * - * Solomon Peachy - * - * (This header is identical to ppcboot.h except for the - * TARGET_HOTFOOT bits) - */ - -/* - * (C) Copyright 2000, 2001 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - */ - -#ifndef __PPCBOOT_H__ -#define __PPCBOOT_H__ - -/* - * Board information passed to kernel from PPCBoot - * - * include/asm-ppc/ppcboot.h - */ - -#include "types.h" - -typedef struct bd_info { - unsigned long bi_memstart; /* start of DRAM memory */ - unsigned long bi_memsize; /* size of DRAM memory in bytes */ - unsigned long bi_flashstart; /* start of FLASH memory */ - unsigned long bi_flashsize; /* size of FLASH memory */ - unsigned long bi_flashoffset; /* reserved area for startup monitor */ - unsigned long bi_sramstart; /* start of SRAM memory */ - unsigned long bi_sramsize; /* size of SRAM memory */ -#if defined(TARGET_8xx) || defined(TARGET_CPM2) || defined(TARGET_85xx) ||\ - defined(TARGET_83xx) - unsigned long bi_immr_base; /* base of IMMR register */ -#endif -#if defined(TARGET_PPC_MPC52xx) - unsigned long bi_mbar_base; /* base of internal registers */ -#endif - unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */ - unsigned long bi_ip_addr; /* IP Address */ - unsigned char bi_enetaddr[6]; /* Ethernet address */ -#if defined(TARGET_HOTFOOT) - /* second onboard ethernet port */ - unsigned char bi_enet1addr[6]; -#define HAVE_ENET1ADDR -#endif /* TARGET_HOOTFOOT */ - unsigned short bi_ethspeed; /* Ethernet speed in Mbps */ - unsigned long bi_intfreq; /* Internal Freq, in MHz */ - unsigned long bi_busfreq; /* Bus Freq, in MHz */ -#if defined(TARGET_CPM2) - unsigned long bi_cpmfreq; /* CPM_CLK Freq, in MHz */ - unsigned long bi_brgfreq; /* BRG_CLK Freq, in MHz */ - unsigned long bi_sccfreq; /* SCC_CLK Freq, in MHz */ - unsigned long bi_vco; /* VCO Out from PLL, in MHz */ -#endif -#if defined(TARGET_PPC_MPC52xx) - unsigned long bi_ipbfreq; /* IPB Bus Freq, in MHz */ - unsigned long bi_pcifreq; /* PCI Bus Freq, in MHz */ -#endif - unsigned long bi_baudrate; /* Console Baudrate */ -#if defined(TARGET_4xx) - unsigned char bi_s_version[4]; /* Version of this structure */ - unsigned char bi_r_version[32]; /* Version of the ROM (IBM) */ - unsigned int bi_procfreq; /* CPU (Internal) Freq, in Hz */ - unsigned int bi_plb_busfreq; /* PLB Bus speed, in Hz */ - unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ - unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */ -#endif -#if defined(TARGET_HOTFOOT) - unsigned int bi_pllouta_freq; /* PLL OUTA speed, in Hz */ -#endif -#if defined(TARGET_HYMOD) - hymod_conf_t bi_hymod_conf; /* hymod configuration information */ -#endif -#if defined(TARGET_EVB64260) || defined(TARGET_405EP) || defined(TARGET_44x) || \ - defined(TARGET_85xx) || defined(TARGET_83xx) || defined(TARGET_HAS_ETH1) - /* second onboard ethernet port */ - unsigned char bi_enet1addr[6]; -#define HAVE_ENET1ADDR -#endif -#if defined(TARGET_EVB64260) || defined(TARGET_440GX) || \ - defined(TARGET_85xx) || defined(TARGET_HAS_ETH2) - /* third onboard ethernet ports */ - unsigned char bi_enet2addr[6]; -#define HAVE_ENET2ADDR -#endif -#if defined(TARGET_440GX) || defined(TARGET_HAS_ETH3) - /* fourth onboard ethernet ports */ - unsigned char bi_enet3addr[6]; -#define HAVE_ENET3ADDR -#endif -#if defined(TARGET_HOTFOOT) - int bi_phynum[2]; /* Determines phy mapping */ - int bi_phymode[2]; /* Determines phy mode */ -#endif -#if defined(TARGET_4xx) - unsigned int bi_opbfreq; /* OB clock in Hz */ - int bi_iic_fast[2]; /* Use fast i2c mode */ -#endif -#if defined(TARGET_440GX) - int bi_phynum[4]; /* phy mapping */ - int bi_phymode[4]; /* phy mode */ -#endif -} bd_t; - -#define bi_tbfreq bi_intfreq - -#endif /* __PPCBOOT_H__ */ diff --git a/arch/powerpc/boot/ppcboot.h b/arch/powerpc/boot/ppcboot.h index a78b0b257698..90c8f452fe6e 100644 --- a/arch/powerpc/boot/ppcboot.h +++ b/arch/powerpc/boot/ppcboot.h @@ -63,7 +63,7 @@ typedef struct bd_info { #if defined(TARGET_HYMOD) hymod_conf_t bi_hymod_conf; /* hymod configuration information */ #endif -#if defined(TARGET_EVB64260) || defined(TARGET_405EP) || defined(TARGET_44x) || \ +#if defined(TARGET_EVB64260) || defined(TARGET_44x) || \ defined(TARGET_85xx) || defined(TARGET_83xx) || defined(TARGET_HAS_ETH1) /* second onboard ethernet port */ unsigned char bi_enet1addr[6]; diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index 352d7de24018..b1f5549a3c9c 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -337,7 +337,7 @@ ps3) make_space=n pie= ;; -ep88xc|ep405|ep8248e) +ep88xc|ep8248e) platformo="$object/fixed-head.o $object/$platform.o" binary=y ;; @@ -468,26 +468,6 @@ uboot) fi exit 0 ;; -uboot-obs600) - rm -f "$ofile" - # obs600 wants a multi image with an initrd, so we need to put a fake - # one in even when building a "normal" image. - if [ -n "$initrd" ]; then - real_rd="$initrd" - else - real_rd=`mktemp` - echo "\0" >>"$real_rd" - fi - ${MKIMAGE} -A ppc -O linux -T multi -C gzip -a $membase -e $membase \ - $uboot_version -d "$vmz":"$real_rd":"$dtb" "$ofile" - if [ -z "$initrd" ]; then - rm -f "$real_rd" - fi - if [ -z "$cacheit" ]; then - rm -f "$vmz" - fi - exit 0 - ;; esac addsec() { diff --git a/arch/powerpc/configs/40x.config b/arch/powerpc/configs/40x.config deleted file mode 100644 index 82a9d58ddb81..000000000000 --- a/arch/powerpc/configs/40x.config +++ /dev/null @@ -1,2 +0,0 @@ -CONFIG_PPC64=n -CONFIG_40x=y diff --git a/arch/powerpc/configs/40x/acadia_defconfig b/arch/powerpc/configs/40x/acadia_defconfig deleted file mode 100644 index 25eed86ec528..000000000000 --- a/arch/powerpc/configs/40x/acadia_defconfig +++ /dev/null @@ -1,61 +0,0 @@ -CONFIG_40x=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -CONFIG_KALLSYMS_ALL=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_ACADIA=y -CONFIG_PCI=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IPV6 is not set -CONFIG_CONNECTOR=y -CONFIG_MTD=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_BLOCK=m -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP_OF=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=35000 -CONFIG_NETDEVICES=y -CONFIG_IBM_EMAC=y -CONFIG_IBM_EMAC_RXB=256 -CONFIG_IBM_EMAC_TXB=256 -CONFIG_IBM_EMAC_DEBUG=y -# CONFIG_INPUT is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -CONFIG_SERIAL_OF_PLATFORM=y -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -CONFIG_THERMAL=y -# CONFIG_USB_SUPPORT is not set -CONFIG_EXT2_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -CONFIG_DEBUG_FS=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DETECT_HUNG_TASK=y -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/40x/kilauea_defconfig b/arch/powerpc/configs/40x/kilauea_defconfig deleted file mode 100644 index 3549c9e950e8..000000000000 --- a/arch/powerpc/configs/40x/kilauea_defconfig +++ /dev/null @@ -1,69 +0,0 @@ -CONFIG_40x=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -CONFIG_KALLSYMS_ALL=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_KILAUEA=y -CONFIG_PCI=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IPV6 is not set -CONFIG_CONNECTOR=y -CONFIG_MTD=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_RAW_NAND=y -CONFIG_MTD_NAND_NDFC=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=35000 -CONFIG_NETDEVICES=y -CONFIG_IBM_EMAC=y -CONFIG_IBM_EMAC_RXB=256 -CONFIG_IBM_EMAC_TXB=256 -# CONFIG_INPUT is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -CONFIG_SERIAL_OF_PLATFORM=y -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_IBM_IIC=y -CONFIG_SENSORS_LM75=y -CONFIG_THERMAL=y -# CONFIG_USB_SUPPORT is not set -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_DS1307=y -CONFIG_EXT2_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -CONFIG_DEBUG_FS=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DETECT_HUNG_TASK=y -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/40x/klondike_defconfig b/arch/powerpc/configs/40x/klondike_defconfig deleted file mode 100644 index a974d1e945cc..000000000000 --- a/arch/powerpc/configs/40x/klondike_defconfig +++ /dev/null @@ -1,43 +0,0 @@ -CONFIG_40x=y -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED=y -CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_APM8018X=y -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_MATH_EMULATION=y -# CONFIG_SUSPEND is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=35000 -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_SAS_ATTRS=y -# CONFIG_INPUT is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -# CONFIG_UNIX98_PTYS is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -# CONFIG_USB_SUPPORT is not set -# CONFIG_IOMMU_SUPPORT is not set -CONFIG_EXT2_FS=y -CONFIG_EXT4_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_UTF8=y -CONFIG_MAGIC_SYSRQ=y -# CONFIG_SCHED_DEBUG is not set -# CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_FTRACE is not set diff --git a/arch/powerpc/configs/40x/makalu_defconfig b/arch/powerpc/configs/40x/makalu_defconfig deleted file mode 100644 index 4563f88acf0c..000000000000 --- a/arch/powerpc/configs/40x/makalu_defconfig +++ /dev/null @@ -1,59 +0,0 @@ -CONFIG_40x=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -CONFIG_KALLSYMS_ALL=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_MAKALU=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IPV6 is not set -CONFIG_CONNECTOR=y -CONFIG_MTD=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_BLOCK=m -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP_OF=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=35000 -CONFIG_NETDEVICES=y -CONFIG_IBM_EMAC=y -CONFIG_IBM_EMAC_RXB=256 -CONFIG_IBM_EMAC_TXB=256 -# CONFIG_INPUT is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -CONFIG_SERIAL_OF_PLATFORM=y -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -CONFIG_THERMAL=y -# CONFIG_USB_SUPPORT is not set -CONFIG_EXT2_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -CONFIG_DEBUG_FS=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DETECT_HUNG_TASK=y -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/40x/obs600_defconfig b/arch/powerpc/configs/40x/obs600_defconfig deleted file mode 100644 index 2a2bb3f46847..000000000000 --- a/arch/powerpc/configs/40x/obs600_defconfig +++ /dev/null @@ -1,69 +0,0 @@ -CONFIG_40x=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -CONFIG_KALLSYMS_ALL=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_OBS600=y -CONFIG_MATH_EMULATION=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IPV6 is not set -CONFIG_CONNECTOR=y -CONFIG_MTD=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_RAW_NAND=y -CONFIG_MTD_NAND_NDFC=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=35000 -CONFIG_NETDEVICES=y -CONFIG_IBM_EMAC=y -CONFIG_IBM_EMAC_RXB=256 -CONFIG_IBM_EMAC_TXB=256 -# CONFIG_INPUT is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -CONFIG_SERIAL_OF_PLATFORM=y -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_IBM_IIC=y -CONFIG_SENSORS_LM75=y -CONFIG_THERMAL=y -# CONFIG_USB_SUPPORT is not set -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_DS1307=y -CONFIG_EXT2_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -CONFIG_DEBUG_FS=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DETECT_HUNG_TASK=y -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/40x/walnut_defconfig b/arch/powerpc/configs/40x/walnut_defconfig deleted file mode 100644 index 9eaaf1a1d2c6..000000000000 --- a/arch/powerpc/configs/40x/walnut_defconfig +++ /dev/null @@ -1,55 +0,0 @@ -CONFIG_40x=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -CONFIG_KALLSYMS_ALL=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IPV6 is not set -CONFIG_CONNECTOR=y -CONFIG_MTD=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_BLOCK=m -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP_OF=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=35000 -CONFIG_NETDEVICES=y -CONFIG_IBM_EMAC=y -# CONFIG_INPUT is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -CONFIG_SERIAL_OF_PLATFORM=y -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -CONFIG_THERMAL=y -CONFIG_EXT2_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -CONFIG_DEBUG_FS=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DETECT_HUNG_TASK=y -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/85xx-hw.config b/arch/powerpc/configs/85xx-hw.config index 524db76f47b7..8aff83217397 100644 --- a/arch/powerpc/configs/85xx-hw.config +++ b/arch/powerpc/configs/85xx-hw.config @@ -24,6 +24,7 @@ CONFIG_FS_ENET=y CONFIG_FSL_CORENET_CF=y CONFIG_FSL_DMA=y CONFIG_FSL_HV_MANAGER=y +CONFIG_FSL_IFC=y CONFIG_FSL_PQ_MDIO=y CONFIG_FSL_RIO=y CONFIG_FSL_XGMAC_MDIO=y @@ -58,6 +59,7 @@ CONFIG_INPUT_FF_MEMLESS=m CONFIG_MARVELL_PHY=y CONFIG_MDIO_BUS_MUX_GPIO=y CONFIG_MDIO_BUS_MUX_MMIOREG=y +CONFIG_MEMORY=y CONFIG_MMC_SDHCI_OF_ESDHC=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI=y diff --git a/arch/powerpc/configs/ppc40x_defconfig b/arch/powerpc/configs/ppc40x_defconfig deleted file mode 100644 index 7e48693775f4..000000000000 --- a/arch/powerpc/configs/ppc40x_defconfig +++ /dev/null @@ -1,74 +0,0 @@ -CONFIG_40x=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -CONFIG_KALLSYMS_ALL=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_PPC4xx_GPIO=y -CONFIG_ACADIA=y -CONFIG_HOTFOOT=y -CONFIG_KILAUEA=y -CONFIG_MAKALU=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_CONNECTOR=y -CONFIG_MTD=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_BLOCK=m -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_UBI=m -CONFIG_MTD_UBI_GLUEBI=m -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=35000 -CONFIG_NETDEVICES=y -CONFIG_IBM_EMAC=y -# CONFIG_INPUT is not set -CONFIG_SERIO=m -# CONFIG_SERIO_I8042 is not set -# CONFIG_SERIO_SERPORT is not set -# CONFIG_VT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -CONFIG_SERIAL_OF_PLATFORM=y -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=m -CONFIG_I2C_CHARDEV=m -CONFIG_I2C_GPIO=m -CONFIG_I2C_IBM_IIC=m -# CONFIG_HWMON is not set -CONFIG_THERMAL=y -CONFIG_FB=m -CONFIG_EXT2_FS=y -CONFIG_EXT4_FS=m -CONFIG_VFAT_FS=m -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=m -CONFIG_UBIFS_FS=m -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -CONFIG_NLS_CODEPAGE_437=m -CONFIG_NLS_ISO8859_1=m -CONFIG_DEBUG_FS=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DETECT_HUNG_TASK=y -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 66c7b28d7450..c06344db0eb3 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -12,7 +12,6 @@ CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_CGROUPS=y CONFIG_CGROUP_SCHED=y -CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_CPUACCT=y CONFIG_USER_NS=y diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index ef7d2de33b89..f2656774aaa9 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -121,7 +121,7 @@ static inline void invalidate_dcache_range(unsigned long start, mb(); /* sync */ } -#ifdef CONFIG_4xx +#ifdef CONFIG_44x static inline void flush_instruction_cache(void) { iccci((void *)KERNELBASE); diff --git a/arch/powerpc/include/asm/cpu_has_feature.h b/arch/powerpc/include/asm/cpu_has_feature.h index 0efabccd820c..bf8a228229fa 100644 --- a/arch/powerpc/include/asm/cpu_has_feature.h +++ b/arch/powerpc/include/asm/cpu_has_feature.h @@ -24,9 +24,8 @@ static __always_inline bool cpu_has_feature(unsigned long feature) { int i; -#ifndef __clang__ /* clang can't cope with this */ BUILD_BUG_ON(!__builtin_constant_p(feature)); -#endif + BUILD_BUG_ON(__builtin_popcountl(feature) > 1); #ifdef CONFIG_JUMP_LABEL_FEATURE_CHECK_DEBUG if (!static_key_feature_checks_initialized) { diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 07a204d21034..201218faed61 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -353,7 +353,6 @@ static inline void cpu_feature_keys_init(void) { } CPU_FTR_COMMON | CPU_FTR_FPU_UNAVAILABLE | CPU_FTR_NOEXECUTE) #define CPU_FTRS_CLASSIC32 (CPU_FTR_COMMON) #define CPU_FTRS_8XX (CPU_FTR_NOEXECUTE) -#define CPU_FTRS_40X (CPU_FTR_NOEXECUTE) #define CPU_FTRS_44X (CPU_FTR_NOEXECUTE) #define CPU_FTRS_440x6 (CPU_FTR_NOEXECUTE | \ CPU_FTR_INDEXED_DCR) @@ -507,9 +506,6 @@ enum { #ifdef CONFIG_PPC_8xx CPU_FTRS_8XX | #endif -#ifdef CONFIG_40x - CPU_FTRS_40X | -#endif #ifdef CONFIG_PPC_47x CPU_FTRS_47X | CPU_FTR_476_DD2 | #elif defined(CONFIG_44x) @@ -582,9 +578,6 @@ enum { #ifdef CONFIG_PPC_8xx CPU_FTRS_8XX & #endif -#ifdef CONFIG_40x - CPU_FTRS_40X & -#endif #ifdef CONFIG_PPC_47x CPU_FTRS_47X & #elif defined(CONFIG_44x) diff --git a/arch/powerpc/include/asm/guest-state-buffer.h b/arch/powerpc/include/asm/guest-state-buffer.h index 808149f31576..d107abe1468f 100644 --- a/arch/powerpc/include/asm/guest-state-buffer.h +++ b/arch/powerpc/include/asm/guest-state-buffer.h @@ -81,6 +81,7 @@ #define KVMPPC_GSID_HASHKEYR 0x1050 #define KVMPPC_GSID_HASHPKEYR 0x1051 #define KVMPPC_GSID_CTRL 0x1052 +#define KVMPPC_GSID_DPDES 0x1053 #define KVMPPC_GSID_CR 0x2000 #define KVMPPC_GSID_PIDR 0x2001 @@ -110,7 +111,7 @@ #define KVMPPC_GSE_META_COUNT (KVMPPC_GSE_META_END - KVMPPC_GSE_META_START + 1) #define KVMPPC_GSE_DW_REGS_START KVMPPC_GSID_GPR(0) -#define KVMPPC_GSE_DW_REGS_END KVMPPC_GSID_CTRL +#define KVMPPC_GSE_DW_REGS_END KVMPPC_GSID_DPDES #define KVMPPC_GSE_DW_REGS_COUNT \ (KVMPPC_GSE_DW_REGS_END - KVMPPC_GSE_DW_REGS_START + 1) diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index 317659fdeacf..569ac1165b06 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h @@ -63,7 +63,7 @@ static inline void __hard_irq_enable(void) { - if (IS_ENABLED(CONFIG_BOOKE_OR_40x)) + if (IS_ENABLED(CONFIG_BOOKE)) wrtee(MSR_EE); else if (IS_ENABLED(CONFIG_PPC_8xx)) wrtspr(SPRN_EIE); @@ -75,7 +75,7 @@ static inline void __hard_irq_enable(void) static inline void __hard_irq_disable(void) { - if (IS_ENABLED(CONFIG_BOOKE_OR_40x)) + if (IS_ENABLED(CONFIG_BOOKE)) wrtee(0); else if (IS_ENABLED(CONFIG_PPC_8xx)) wrtspr(SPRN_EID); @@ -87,7 +87,7 @@ static inline void __hard_irq_disable(void) static inline void __hard_EE_RI_disable(void) { - if (IS_ENABLED(CONFIG_BOOKE_OR_40x)) + if (IS_ENABLED(CONFIG_BOOKE)) wrtee(0); else if (IS_ENABLED(CONFIG_PPC_8xx)) wrtspr(SPRN_NRI); @@ -99,7 +99,7 @@ static inline void __hard_EE_RI_disable(void) static inline void __hard_RI_enable(void) { - if (IS_ENABLED(CONFIG_BOOKE_OR_40x)) + if (IS_ENABLED(CONFIG_BOOKE)) return; if (IS_ENABLED(CONFIG_PPC_8xx)) diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h index 026695943550..04072b5f8962 100644 --- a/arch/powerpc/include/asm/iommu.h +++ b/arch/powerpc/include/asm/iommu.h @@ -31,6 +31,8 @@ #define DIRECT64_PROPNAME "linux,direct64-ddr-window-info" #define DMA64_PROPNAME "linux,dma64-ddr-window-info" +#define MIN_DDW_VPMEM_DMA_WINDOW SZ_2G + /* Boot time flags */ extern int iommu_is_off; extern int iommu_force_on; @@ -156,6 +158,9 @@ extern int iommu_tce_table_put(struct iommu_table *tbl); extern struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid, unsigned long res_start, unsigned long res_end); bool iommu_table_in_use(struct iommu_table *tbl); +extern void iommu_table_reserve_pages(struct iommu_table *tbl, + unsigned long res_start, unsigned long res_end); +extern void iommu_table_clear(struct iommu_table *tbl); #define IOMMU_TABLE_GROUP_MAX_TABLES 2 @@ -178,9 +183,9 @@ struct iommu_table_group_ops { long (*unset_window)(struct iommu_table_group *table_group, int num); /* Switch ownership from platform code to external user (e.g. VFIO) */ - long (*take_ownership)(struct iommu_table_group *table_group); + long (*take_ownership)(struct iommu_table_group *table_group, struct device *dev); /* Switch ownership from external user (e.g. VFIO) back to core */ - void (*release_ownership)(struct iommu_table_group *table_group); + void (*release_ownership)(struct iommu_table_group *table_group, struct device *dev); }; struct iommu_table_group_link { @@ -217,8 +222,8 @@ extern long iommu_tce_xchg_no_kill(struct mm_struct *mm, enum dma_data_direction *direction); extern void iommu_tce_kill(struct iommu_table *tbl, unsigned long entry, unsigned long pages); +int dev_has_iommu_table(struct device *dev, void *data); -extern struct iommu_table_group_ops spapr_tce_table_group_ops; #else static inline void iommu_register_group(struct iommu_table_group *table_group, int pci_domain_number, @@ -231,6 +236,11 @@ static inline int iommu_add_device(struct iommu_table_group *table_group, { return 0; } + +static inline int dev_has_iommu_table(struct device *dev, void *data) +{ + return 0; +} #endif /* !CONFIG_IOMMU_API */ u64 dma_iommu_get_required_mask(struct device *dev); diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index ba1a5974e714..aa3751960ffd 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -33,7 +33,7 @@ extern int distribute_irqs; struct pt_regs; -#ifdef CONFIG_BOOKE_OR_40x +#ifdef CONFIG_BOOKE /* * Per-cpu stacks for handling critical, debug and machine check * level interrupts. diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h index 95a98b390d62..270ee93a0f7d 100644 --- a/arch/powerpc/include/asm/kexec.h +++ b/arch/powerpc/include/asm/kexec.h @@ -103,10 +103,8 @@ int load_crashdump_segments_ppc64(struct kimage *image, int setup_purgatory_ppc64(struct kimage *image, const void *slave_code, const void *fdt, unsigned long kernel_load_addr, unsigned long fdt_load_addr); -unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image); -int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, - unsigned long initrd_load_addr, - unsigned long initrd_len, const char *cmdline); +unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image, struct crash_mem *rmem); +int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, struct crash_mem *rmem); #endif /* CONFIG_PPC64 */ #endif /* CONFIG_KEXEC_FILE */ diff --git a/arch/powerpc/include/asm/kfence.h b/arch/powerpc/include/asm/kfence.h index 424ceef82ae6..fab124ada1c7 100644 --- a/arch/powerpc/include/asm/kfence.h +++ b/arch/powerpc/include/asm/kfence.h @@ -15,10 +15,19 @@ #define ARCH_FUNC_PREFIX "." #endif +#ifdef CONFIG_KFENCE +extern bool kfence_disabled; + +static inline void disable_kfence(void) +{ + kfence_disabled = true; +} + static inline bool arch_kfence_init_pool(void) { - return true; + return !kfence_disabled; } +#endif #ifdef CONFIG_PPC64 static inline bool kfence_protect_page(unsigned long addr, bool protect) diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h index ad7e8c5aec3f..2bb03d941e3e 100644 --- a/arch/powerpc/include/asm/kup.h +++ b/arch/powerpc/include/asm/kup.h @@ -20,7 +20,7 @@ static __always_inline bool kuap_is_disabled(void); #include #endif -#ifdef CONFIG_BOOKE_OR_40x +#ifdef CONFIG_BOOKE #include #endif diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index 3e1e2a698c9e..10618622d7ef 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -594,6 +594,7 @@ static inline u##size kvmppc_get_##reg(struct kvm_vcpu *vcpu) \ KVMPPC_BOOK3S_VCORE_ACCESSOR(vtb, 64, KVMPPC_GSID_VTB) +KVMPPC_BOOK3S_VCORE_ACCESSOR(dpdes, 64, KVMPPC_GSID_DPDES) KVMPPC_BOOK3S_VCORE_ACCESSOR_GET(arch_compat, 32, KVMPPC_GSID_LOGICAL_PVR) KVMPPC_BOOK3S_VCORE_ACCESSOR_GET(lpcr, 64, KVMPPC_GSID_LPCR) KVMPPC_BOOK3S_VCORE_ACCESSOR_SET(tb_offset, 64, KVMPPC_GSID_TB_OFFSET) diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index d8729ec81ca0..2ef9a5f4e5d1 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -684,6 +684,11 @@ int kvmhv_nestedv2_set_ptbl_entry(unsigned long lpid, u64 dw0, u64 dw1); int kvmhv_nestedv2_parse_output(struct kvm_vcpu *vcpu); int kvmhv_nestedv2_set_vpa(struct kvm_vcpu *vcpu, unsigned long vpa); +int kmvhv_counters_tracepoint_regfunc(void); +void kmvhv_counters_tracepoint_unregfunc(void); +int kvmhv_get_l2_counters_status(void); +void kvmhv_set_l2_counters_status(int cpu, bool status); + #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ #endif /* __ASM_KVM_BOOK3S_64_H__ */ diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 8abac532146e..37e581c5b201 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -599,6 +599,9 @@ struct kvm_vcpu_arch { ulong dawrx0; ulong dawr1; ulong dawrx1; + ulong dexcr; + ulong hashkeyr; + ulong hashpkeyr; ulong ciabr; ulong cfar; ulong ppr; @@ -897,7 +900,6 @@ struct kvm_vcpu_arch { static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {} static inline void kvm_arch_flush_shadow_all(struct kvm *kvm) {} -static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {} diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h index 61ec2447dabf..f40a646bee3c 100644 --- a/arch/powerpc/include/asm/lppaca.h +++ b/arch/powerpc/include/asm/lppaca.h @@ -62,7 +62,8 @@ struct lppaca { u8 donate_dedicated_cpu; /* Donate dedicated CPU cycles */ u8 fpregs_in_use; u8 pmcregs_in_use; - u8 reserved8[28]; + u8 l2_counters_enable; /* Enable usage of counters for KVM guest */ + u8 reserved8[27]; __be64 wait_state_cycles; /* Wait cycles for this proc */ u8 reserved9[28]; __be16 slb_count; /* # of SLBs to maintain */ @@ -92,9 +93,13 @@ struct lppaca { /* cacheline 4-5 */ __be32 page_ins; /* CMO Hint - # page ins by OS */ - u8 reserved12[148]; + u8 reserved12[28]; + volatile __be64 l1_to_l2_cs_tb; + volatile __be64 l2_to_l1_cs_tb; + volatile __be64 l2_runtime_tb; + u8 reserved13[96]; volatile __be64 dtl_idx; /* Dispatch Trace Log head index */ - u8 reserved13[96]; + u8 reserved14[96]; } ____cacheline_aligned; #define lppaca_of(cpu) (*paca_ptrs[cpu]->lppaca_ptr) diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index 8a27b046c6a2..4182d68d9cd1 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -16,7 +16,6 @@ */ #define MMU_FTR_HPTE_TABLE ASM_CONST(0x00000001) #define MMU_FTR_TYPE_8xx ASM_CONST(0x00000002) -#define MMU_FTR_TYPE_40x ASM_CONST(0x00000004) #define MMU_FTR_TYPE_44x ASM_CONST(0x00000008) #define MMU_FTR_TYPE_FSL_E ASM_CONST(0x00000010) #define MMU_FTR_TYPE_47x ASM_CONST(0x00000020) @@ -153,9 +152,6 @@ enum { #ifdef CONFIG_PPC_8xx MMU_FTR_TYPE_8xx | #endif -#ifdef CONFIG_40x - MMU_FTR_TYPE_40x | -#endif #ifdef CONFIG_PPC_47x MMU_FTR_TYPE_47x | MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL | #elif defined(CONFIG_44x) @@ -202,9 +198,6 @@ enum { #ifdef CONFIG_PPC_8xx #define MMU_FTRS_ALWAYS MMU_FTR_TYPE_8xx #endif -#ifdef CONFIG_40x -#define MMU_FTRS_ALWAYS MMU_FTR_TYPE_40x -#endif #ifdef CONFIG_PPC_47x #define MMU_FTRS_ALWAYS MMU_FTR_TYPE_47x #elif defined(CONFIG_44x) @@ -246,9 +239,8 @@ static __always_inline bool mmu_has_feature(unsigned long feature) { int i; -#ifndef __clang__ /* clang can't cope with this */ BUILD_BUG_ON(!__builtin_constant_p(feature)); -#endif + BUILD_BUG_ON(__builtin_popcountl(feature) > 1); #ifdef CONFIG_JUMP_LABEL_FEATURE_CHECK_DEBUG if (!static_key_feature_checks_initialized) { diff --git a/arch/powerpc/include/asm/nohash/32/mmu-40x.h b/arch/powerpc/include/asm/nohash/32/mmu-40x.h deleted file mode 100644 index 8a8f13a22cf4..000000000000 --- a/arch/powerpc/include/asm/nohash/32/mmu-40x.h +++ /dev/null @@ -1,68 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_POWERPC_MMU_40X_H_ -#define _ASM_POWERPC_MMU_40X_H_ - -/* - * PPC40x support - */ - -#define PPC40X_TLB_SIZE 64 - -/* - * TLB entries are defined by a "high" tag portion and a "low" data - * portion. On all architectures, the data portion is 32-bits. - * - * TLB entries are managed entirely under software control by reading, - * writing, and searchoing using the 4xx-specific tlbre, tlbwr, and tlbsx - * instructions. - */ - -#define TLB_LO 1 -#define TLB_HI 0 - -#define TLB_DATA TLB_LO -#define TLB_TAG TLB_HI - -/* Tag portion */ - -#define TLB_EPN_MASK 0xFFFFFC00 /* Effective Page Number */ -#define TLB_PAGESZ_MASK 0x00000380 -#define TLB_PAGESZ(x) (((x) & 0x7) << 7) -#define PAGESZ_1K 0 -#define PAGESZ_4K 1 -#define PAGESZ_16K 2 -#define PAGESZ_64K 3 -#define PAGESZ_256K 4 -#define PAGESZ_1M 5 -#define PAGESZ_4M 6 -#define PAGESZ_16M 7 -#define TLB_VALID 0x00000040 /* Entry is valid */ - -/* Data portion */ - -#define TLB_RPN_MASK 0xFFFFFC00 /* Real Page Number */ -#define TLB_PERM_MASK 0x00000300 -#define TLB_EX 0x00000200 /* Instruction execution allowed */ -#define TLB_WR 0x00000100 /* Writes permitted */ -#define TLB_ZSEL_MASK 0x000000F0 -#define TLB_ZSEL(x) (((x) & 0xF) << 4) -#define TLB_ATTR_MASK 0x0000000F -#define TLB_W 0x00000008 /* Caching is write-through */ -#define TLB_I 0x00000004 /* Caching is inhibited */ -#define TLB_M 0x00000002 /* Memory is coherent */ -#define TLB_G 0x00000001 /* Memory is guarded from prefetch */ - -#ifndef __ASSEMBLY__ - -typedef struct { - unsigned int id; - unsigned int active; - void __user *vdso; -} mm_context_t; - -#endif /* !__ASSEMBLY__ */ - -#define mmu_virtual_psize MMU_PAGE_4K -#define mmu_linear_psize MMU_PAGE_256M - -#endif /* _ASM_POWERPC_MMU_40X_H_ */ diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h index 9164a9e41b02..9508399dd036 100644 --- a/arch/powerpc/include/asm/nohash/32/pgtable.h +++ b/arch/powerpc/include/asm/nohash/32/pgtable.h @@ -118,9 +118,7 @@ * (hardware-defined) PowerPC PTE as closely as possible. */ -#if defined(CONFIG_40x) -#include -#elif defined(CONFIG_44x) +#if defined(CONFIG_44x) #include #elif defined(CONFIG_PPC_85xx) && defined(CONFIG_PTE_64BIT) #include diff --git a/arch/powerpc/include/asm/nohash/32/pte-40x.h b/arch/powerpc/include/asm/nohash/32/pte-40x.h deleted file mode 100644 index d759cfd74754..000000000000 --- a/arch/powerpc/include/asm/nohash/32/pte-40x.h +++ /dev/null @@ -1,73 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_POWERPC_NOHASH_32_PTE_40x_H -#define _ASM_POWERPC_NOHASH_32_PTE_40x_H -#ifdef __KERNEL__ - -/* - * At present, all PowerPC 400-class processors share a similar TLB - * architecture. The instruction and data sides share a unified, - * 64-entry, fully-associative TLB which is maintained totally under - * software control. In addition, the instruction side has a - * hardware-managed, 4-entry, fully-associative TLB which serves as a - * first level to the shared TLB. These two TLBs are known as the UTLB - * and ITLB, respectively (see "mmu.h" for definitions). - * - * There are several potential gotchas here. The 40x hardware TLBLO - * field looks like this: - * - * 0 1 2 3 4 ... 18 19 20 21 22 23 24 25 26 27 28 29 30 31 - * RPN..................... 0 0 EX WR ZSEL....... W I M G - * - * Where possible we make the Linux PTE bits match up with this - * - * - bits 20 and 21 must be cleared, because we use 4k pages (40x can - * support down to 1k pages), this is done in the TLBMiss exception - * handler. - * - We use only zones 0 (for kernel pages) and 1 (for user pages) - * of the 16 available. Bit 24-26 of the TLB are cleared in the TLB - * miss handler. Bit 27 is PAGE_USER, thus selecting the correct - * zone. - * - PRESENT *must* be in the bottom two bits because swap PTEs - * use the top 30 bits. Because 40x doesn't support SMP anyway, M is - * irrelevant so we borrow it for PAGE_PRESENT. Bit 30 - * is cleared in the TLB miss handler before the TLB entry is loaded. - * - All other bits of the PTE are loaded into TLBLO without - * modification, leaving us only the bits 20, 21, 24, 25, 26, 30 for - * software PTE bits. We actually use bits 21, 24, 25, and - * 30 respectively for the software bits: ACCESSED, DIRTY, RW, and - * PRESENT. - */ - -#define _PAGE_GUARDED 0x001 /* G: page is guarded from prefetch */ -#define _PAGE_PRESENT 0x002 /* software: PTE contains a translation */ -#define _PAGE_NO_CACHE 0x004 /* I: caching is inhibited */ -#define _PAGE_WRITETHRU 0x008 /* W: caching is write-through */ -#define _PAGE_READ 0x010 /* software: read permission */ -#define _PAGE_SPECIAL 0x020 /* software: Special page */ -#define _PAGE_DIRTY 0x080 /* software: dirty page */ -#define _PAGE_WRITE 0x100 /* hardware: WR, anded with dirty in exception */ -#define _PAGE_EXEC 0x200 /* hardware: EX permission */ -#define _PAGE_ACCESSED 0x400 /* software: R: page referenced */ - -/* No page size encoding in the linux PTE */ -#define _PAGE_PSIZE 0 - -/* cache related flags non existing on 40x */ -#define _PAGE_COHERENT 0 - -#define _PMD_PRESENT 0x400 /* PMD points to page of PTEs */ -#define _PMD_PRESENT_MASK _PMD_PRESENT -#define _PMD_BAD 0x802 -#define _PMD_SIZE_4M 0x0c0 -#define _PMD_SIZE_16M 0x0e0 -#define _PMD_USER 0 - -#define _PTE_NONE_MASK 0 - -#define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED) -#define _PAGE_BASE (_PAGE_BASE_NC) - -#include - -#endif /* __KERNEL__ */ -#endif /* _ASM_POWERPC_NOHASH_32_PTE_40x_H */ diff --git a/arch/powerpc/include/asm/nohash/mmu.h b/arch/powerpc/include/asm/nohash/mmu.h index e264be219fdb..4cc795044103 100644 --- a/arch/powerpc/include/asm/nohash/mmu.h +++ b/arch/powerpc/include/asm/nohash/mmu.h @@ -2,10 +2,7 @@ #ifndef _ASM_POWERPC_NOHASH_MMU_H_ #define _ASM_POWERPC_NOHASH_MMU_H_ -#if defined(CONFIG_40x) -/* 40x-style software loaded TLB */ -#include -#elif defined(CONFIG_44x) +#if defined(CONFIG_44x) /* 44x-style software loaded TLB */ #include #elif defined(CONFIG_PPC_E500) diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h index e2221d29fdf9..5995614e9062 100644 --- a/arch/powerpc/include/asm/perf_event_server.h +++ b/arch/powerpc/include/asm/perf_event_server.h @@ -89,7 +89,8 @@ struct power_pmu { #define PPMU_NO_SIAR 0x00000100 /* Do not use SIAR */ #define PPMU_ARCH_31 0x00000200 /* Has MMCR3, SIER2 and SIER3 */ #define PPMU_P10_DD1 0x00000400 /* Is power10 DD1 processor version */ -#define PPMU_HAS_ATTR_CONFIG1 0x00000800 /* Using config1 attribute */ +#define PPMU_P10 0x00000800 /* For power10 pmu */ +#define PPMU_HAS_ATTR_CONFIG1 0x00001000 /* Using config1 attribute */ /* * Values for flags to get_alternatives() diff --git a/arch/powerpc/include/asm/plpar_wrappers.h b/arch/powerpc/include/asm/plpar_wrappers.h index b3ee44a40c2f..71648c126970 100644 --- a/arch/powerpc/include/asm/plpar_wrappers.h +++ b/arch/powerpc/include/asm/plpar_wrappers.h @@ -18,16 +18,6 @@ static inline long poll_pending(void) return plpar_hcall_norets(H_POLL_PENDING); } -static inline u8 get_cede_latency_hint(void) -{ - return get_lppaca()->cede_latency_hint; -} - -static inline void set_cede_latency_hint(u8 latency_hint) -{ - get_lppaca()->cede_latency_hint = latency_hint; -} - static inline long cede_processor(void) { /* @@ -37,24 +27,6 @@ static inline long cede_processor(void) return plpar_hcall_norets_notrace(H_CEDE); } -static inline long extended_cede_processor(unsigned long latency_hint) -{ - long rc; - u8 old_latency_hint = get_cede_latency_hint(); - - set_cede_latency_hint(latency_hint); - - rc = cede_processor(); - - /* Ensure that H_CEDE returns with IRQs on */ - if (WARN_ON(IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG) && !(mfmsr() & MSR_EE))) - __hard_irq_enable(); - - set_cede_latency_hint(old_latency_hint); - - return rc; -} - static inline long vpa_call(unsigned long flags, unsigned long cpu, unsigned long vpa) { diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 076ae60b4a55..b98a9e982c03 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -471,6 +471,7 @@ #define PPC_RAW_VCMPEQUB_RC(vrt, vra, vrb) \ (0x10000006 | ___PPC_RT(vrt) | ___PPC_RA(vra) | ___PPC_RB(vrb) | __PPC_RC21) #define PPC_RAW_LD(r, base, i) (0xe8000000 | ___PPC_RT(r) | ___PPC_RA(base) | IMM_DS(i)) +#define PPC_RAW_LWA(r, base, i) (0xe8000002 | ___PPC_RT(r) | ___PPC_RA(base) | IMM_DS(i)) #define PPC_RAW_LWZ(r, base, i) (0x80000000 | ___PPC_RT(r) | ___PPC_RA(base) | IMM_L(i)) #define PPC_RAW_LWZX(t, a, b) (0x7c00002e | ___PPC_RT(t) | ___PPC_RA(a) | ___PPC_RB(b)) #define PPC_RAW_STD(r, base, i) (0xf8000000 | ___PPC_RS(r) | ___PPC_RA(base) | IMM_DS(i)) @@ -535,6 +536,7 @@ #define PPC_RAW_MULI(d, a, i) (0x1c000000 | ___PPC_RT(d) | ___PPC_RA(a) | IMM_L(i)) #define PPC_RAW_DIVW(d, a, b) (0x7c0003d6 | ___PPC_RT(d) | ___PPC_RA(a) | ___PPC_RB(b)) #define PPC_RAW_DIVWU(d, a, b) (0x7c000396 | ___PPC_RT(d) | ___PPC_RA(a) | ___PPC_RB(b)) +#define PPC_RAW_DIVD(d, a, b) (0x7c0003d2 | ___PPC_RT(d) | ___PPC_RA(a) | ___PPC_RB(b)) #define PPC_RAW_DIVDU(d, a, b) (0x7c000392 | ___PPC_RT(d) | ___PPC_RA(a) | ___PPC_RB(b)) #define PPC_RAW_DIVDE(t, a, b) (0x7c000352 | ___PPC_RT(t) | ___PPC_RA(a) | ___PPC_RB(b)) #define PPC_RAW_DIVDE_DOT(t, a, b) (0x7c000352 | ___PPC_RT(t) | ___PPC_RA(a) | ___PPC_RB(b) | 0x1) diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index 1d1018c1e482..02897f4b0dbf 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -482,7 +482,7 @@ END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96) * and they must be used. */ -#if !defined(CONFIG_4xx) && !defined(CONFIG_PPC_8xx) +#if !defined(CONFIG_44x) && !defined(CONFIG_PPC_8xx) #define tlbia \ li r4,1024; \ mtctr r4; \ diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index e44cac0da346..6b94de17201c 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -159,7 +159,7 @@ struct thread_struct { unsigned long sr0; #endif #endif /* CONFIG_PPC32 */ -#if defined(CONFIG_BOOKE_OR_40x) && defined(CONFIG_PPC_KUAP) +#if defined(CONFIG_BOOKE) && defined(CONFIG_PPC_KUAP) unsigned long pid; /* value written in PID reg. at interrupt exit */ #endif /* Debug Registers */ diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index ea8f91fbc62f..7b9350756875 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h @@ -310,7 +310,7 @@ static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc) static inline bool cpu_has_msr_ri(void) { - return !IS_ENABLED(CONFIG_BOOKE_OR_40x); + return !IS_ENABLED(CONFIG_BOOKE); } static inline bool regs_is_unrecoverable(struct pt_regs *regs) diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index eed33cb916d0..0228c90bbcc7 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -18,7 +18,7 @@ #include /* Pickup Book E specific registers. */ -#ifdef CONFIG_BOOKE_OR_40x +#ifdef CONFIG_BOOKE #include #endif @@ -233,14 +233,10 @@ /* Special Purpose Registers (SPRNs)*/ -#ifdef CONFIG_40x -#define SPRN_PID 0x3B1 /* Process ID */ -#else #define SPRN_PID 0x030 /* Process ID */ #ifdef CONFIG_BOOKE #define SPRN_PID0 SPRN_PID/* Process ID Register 0 */ #endif -#endif #define SPRN_CTR 0x009 /* Count Register */ #define SPRN_DSCR 0x11 @@ -527,7 +523,7 @@ #define SPRN_TSCR 0x399 /* Thread Switch Control Register */ #define SPRN_DEC 0x016 /* Decrement Register */ -#define SPRN_PIT 0x3DB /* Programmable Interval Timer (40x/BOOKE) */ +#define SPRN_PIT 0x3DB /* Programmable Interval Timer (BOOKE) */ #define SPRN_DER 0x095 /* Debug Enable Register */ #define DER_RSTE 0x40000000 /* Reset Interrupt */ @@ -1116,15 +1112,6 @@ * - SPRG2 indicator that we are in RTAS * - SPRG4 (603 only) pseudo TLB LRU data * - * 32-bit 40x: - * - SPRG0 scratch for exception vectors - * - SPRG1 scratch for exception vectors - * - SPRG2 scratch for exception vectors - * - SPRG4 scratch for exception vectors (not 403) - * - SPRG5 scratch for exception vectors (not 403) - * - SPRG6 scratch for exception vectors (not 403) - * - SPRG7 scratch for exception vectors (not 403) - * * 32-bit 440 and FSL BookE: * - SPRG0 scratch for exception vectors * - SPRG1 scratch for exception vectors (*) @@ -1216,16 +1203,6 @@ #define SPRN_SPRG_603_LRU SPRN_SPRG4 #endif -#ifdef CONFIG_40x -#define SPRN_SPRG_SCRATCH0 SPRN_SPRG0 -#define SPRN_SPRG_SCRATCH1 SPRN_SPRG1 -#define SPRN_SPRG_SCRATCH2 SPRN_SPRG2 -#define SPRN_SPRG_SCRATCH3 SPRN_SPRG4 -#define SPRN_SPRG_SCRATCH4 SPRN_SPRG5 -#define SPRN_SPRG_SCRATCH5 SPRN_SPRG6 -#define SPRN_SPRG_SCRATCH6 SPRN_SPRG7 -#endif - #ifdef CONFIG_BOOKE #define SPRN_SPRG_RSCRATCH0 SPRN_SPRG0 #define SPRN_SPRG_WSCRATCH0 SPRN_SPRG0 diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index af56980b6cdb..656bfaf91526 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h @@ -1,10 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Contains register definitions common to the Book E PowerPC - * specification. Notice that while the IBM-40x series of CPUs - * are not true Book E PowerPCs, they borrowed a number of features - * before Book E was finalized, and are included here as well. Unfortunately, - * they sometimes used different locations than true Book E CPUs did. + * specification. * * Copyright 2009-2010 Freescale Semiconductor, Inc. */ @@ -42,9 +39,6 @@ #define MSR_KERNEL (MSR_ | MSR_64BIT) #define MSR_USER32 (MSR_ | MSR_PR | MSR_EE) #define MSR_USER64 (MSR_USER32 | MSR_64BIT) -#elif defined (CONFIG_40x) -#define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE) -#define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE) #else #define MSR_KERNEL (MSR_ME|MSR_RI|MSR_CE) #define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE) @@ -157,7 +151,6 @@ #define SPRN_TLB3CFG 0x2B3 /* TLB 3 Config Register */ #define SPRN_EPR 0x2BE /* External Proxy Register */ #define SPRN_CCR1 0x378 /* Core Configuration Register 1 */ -#define SPRN_ZPR 0x3B0 /* Zone Protection Register (40x) */ #define SPRN_MAS7 0x3B0 /* MMU Assist Register 7 */ #define SPRN_MMUCR 0x3B2 /* MMU Control Register */ #define SPRN_CCR0 0x3B3 /* Core Configuration Register 0 */ @@ -166,7 +159,6 @@ #define SPRN_SGR 0x3B9 /* Storage Guarded Register */ #define SPRN_DCWR 0x3BA /* Data Cache Write-thru Register */ #define SPRN_SLER 0x3BB /* Little-endian real mode */ -#define SPRN_SU0R 0x3BC /* "User 0" real mode (40x) */ #define SPRN_DCMP 0x3D1 /* Data TLB Compare Register */ #define SPRN_ICDBDR 0x3D3 /* Instruction Cache Debug Data Register */ #define SPRN_EVPR 0x3D6 /* Exception Vector Prefix Register */ @@ -183,10 +175,8 @@ #define SPRN_SVR 0x3FF /* System Version Register */ /* - * SPRs which have conflicting definitions on true Book E versus classic, - * or IBM 40x. + * SPRs which have conflicting definitions on true Book E versus classic. */ -#ifdef CONFIG_BOOKE #define SPRN_CSRR0 0x03A /* Critical Save and Restore Register 0 */ #define SPRN_CSRR1 0x03B /* Critical Save and Restore Register 1 */ #define SPRN_DEAR 0x03D /* Data Error Address Register */ @@ -201,22 +191,6 @@ #define SPRN_DAC2 0x13D /* Data Address Compare 2 */ #define SPRN_TSR 0x150 /* Timer Status Register */ #define SPRN_TCR 0x154 /* Timer Control Register */ -#endif /* Book E */ -#ifdef CONFIG_40x -#define SPRN_DBCR1 0x3BD /* Debug Control Register 1 */ -#define SPRN_ESR 0x3D4 /* Exception Syndrome Register */ -#define SPRN_DEAR 0x3D5 /* Data Error Address Register */ -#define SPRN_TSR 0x3D8 /* Timer Status Register */ -#define SPRN_TCR 0x3DA /* Timer Control Register */ -#define SPRN_SRR2 0x3DE /* Save/Restore Register 2 */ -#define SPRN_SRR3 0x3DF /* Save/Restore Register 3 */ -#define SPRN_DBSR 0x3F0 /* Debug Status Register */ -#define SPRN_DBCR0 0x3F2 /* Debug Control Register 0 */ -#define SPRN_DAC1 0x3F6 /* Data Address Compare 1 */ -#define SPRN_DAC2 0x3F7 /* Data Address Compare 2 */ -#define SPRN_CSRR0 SPRN_SRR2 /* Critical Save and Restore Register 0 */ -#define SPRN_CSRR1 SPRN_SRR3 /* Critical Save and Restore Register 1 */ -#endif #define SPRN_HACOP 0x15F /* Hypervisor Available Coprocessor Register */ /* Bit definitions for CCR1. */ @@ -296,10 +270,6 @@ #endif /* Bit definitions for the DBSR. */ -/* - * DBSR bits which have conflicting definitions on true Book E versus IBM 40x. - */ -#ifdef CONFIG_BOOKE #define DBSR_IDE 0x80000000 /* Imprecise Debug Event */ #define DBSR_MRR 0x30000000 /* Most Recent Reset */ #define DBSR_IC 0x08000000 /* Instruction Completion */ @@ -319,21 +289,6 @@ #define DBSR_CRET 0x00000020 /* Critical Return Debug Event */ #define DBSR_IAC12ATS 0x00000002 /* Instr Address Compare 1/2 Toggle */ #define DBSR_IAC34ATS 0x00000001 /* Instr Address Compare 3/4 Toggle */ -#endif -#ifdef CONFIG_40x -#define DBSR_IC 0x80000000 /* Instruction Completion */ -#define DBSR_BT 0x40000000 /* Branch taken */ -#define DBSR_IRPT 0x20000000 /* Exception Debug Event */ -#define DBSR_TIE 0x10000000 /* Trap Instruction debug Event */ -#define DBSR_IAC1 0x04000000 /* Instruction Address Compare 1 Event */ -#define DBSR_IAC2 0x02000000 /* Instruction Address Compare 2 Event */ -#define DBSR_IAC3 0x00080000 /* Instruction Address Compare 3 Event */ -#define DBSR_IAC4 0x00040000 /* Instruction Address Compare 4 Event */ -#define DBSR_DAC1R 0x01000000 /* Data Address Compare 1 Read Event */ -#define DBSR_DAC1W 0x00800000 /* Data Address Compare 1 Write Event */ -#define DBSR_DAC2R 0x00400000 /* Data Address Compare 2 Read Event */ -#define DBSR_DAC2W 0x00200000 /* Data Address Compare 2 Write Event */ -#endif /* Bit definitions related to the ESR. */ #define ESR_MCI 0x80000000 /* Machine Check - Instruction */ @@ -355,69 +310,6 @@ #define ESR_SPV 0x00000080 /* Signal Processing operation */ /* Bit definitions related to the DBCR0. */ -#if defined(CONFIG_40x) -#define DBCR0_EDM 0x80000000 /* External Debug Mode */ -#define DBCR0_IDM 0x40000000 /* Internal Debug Mode */ -#define DBCR0_RST 0x30000000 /* all the bits in the RST field */ -#define DBCR0_RST_SYSTEM 0x30000000 /* System Reset */ -#define DBCR0_RST_CHIP 0x20000000 /* Chip Reset */ -#define DBCR0_RST_CORE 0x10000000 /* Core Reset */ -#define DBCR0_RST_NONE 0x00000000 /* No Reset */ -#define DBCR0_IC 0x08000000 /* Instruction Completion */ -#define DBCR0_ICMP DBCR0_IC -#define DBCR0_BT 0x04000000 /* Branch Taken */ -#define DBCR0_BRT DBCR0_BT -#define DBCR0_EDE 0x02000000 /* Exception Debug Event */ -#define DBCR0_IRPT DBCR0_EDE -#define DBCR0_TDE 0x01000000 /* TRAP Debug Event */ -#define DBCR0_IA1 0x00800000 /* Instr Addr compare 1 enable */ -#define DBCR0_IAC1 DBCR0_IA1 -#define DBCR0_IA2 0x00400000 /* Instr Addr compare 2 enable */ -#define DBCR0_IAC2 DBCR0_IA2 -#define DBCR0_IA12 0x00200000 /* Instr Addr 1-2 range enable */ -#define DBCR0_IA12X 0x00100000 /* Instr Addr 1-2 range eXclusive */ -#define DBCR0_IA3 0x00080000 /* Instr Addr compare 3 enable */ -#define DBCR0_IAC3 DBCR0_IA3 -#define DBCR0_IA4 0x00040000 /* Instr Addr compare 4 enable */ -#define DBCR0_IAC4 DBCR0_IA4 -#define DBCR0_IA34 0x00020000 /* Instr Addr 3-4 range Enable */ -#define DBCR0_IA34X 0x00010000 /* Instr Addr 3-4 range eXclusive */ -#define DBCR0_IA12T 0x00008000 /* Instr Addr 1-2 range Toggle */ -#define DBCR0_IA34T 0x00004000 /* Instr Addr 3-4 range Toggle */ -#define DBCR0_FT 0x00000001 /* Freeze Timers on debug event */ - -#define dbcr_iac_range(task) ((task)->thread.debug.dbcr0) -#define DBCR_IAC12I DBCR0_IA12 /* Range Inclusive */ -#define DBCR_IAC12X (DBCR0_IA12 | DBCR0_IA12X) /* Range Exclusive */ -#define DBCR_IAC12MODE (DBCR0_IA12 | DBCR0_IA12X) /* IAC 1-2 Mode Bits */ -#define DBCR_IAC34I DBCR0_IA34 /* Range Inclusive */ -#define DBCR_IAC34X (DBCR0_IA34 | DBCR0_IA34X) /* Range Exclusive */ -#define DBCR_IAC34MODE (DBCR0_IA34 | DBCR0_IA34X) /* IAC 3-4 Mode Bits */ - -/* Bit definitions related to the DBCR1. */ -#define DBCR1_DAC1R 0x80000000 /* DAC1 Read Debug Event */ -#define DBCR1_DAC2R 0x40000000 /* DAC2 Read Debug Event */ -#define DBCR1_DAC1W 0x20000000 /* DAC1 Write Debug Event */ -#define DBCR1_DAC2W 0x10000000 /* DAC2 Write Debug Event */ - -#define dbcr_dac(task) ((task)->thread.debug.dbcr1) -#define DBCR_DAC1R DBCR1_DAC1R -#define DBCR_DAC1W DBCR1_DAC1W -#define DBCR_DAC2R DBCR1_DAC2R -#define DBCR_DAC2W DBCR1_DAC2W - -/* - * Are there any active Debug Events represented in the - * Debug Control Registers? - */ -#define DBCR0_ACTIVE_EVENTS (DBCR0_ICMP | DBCR0_IAC1 | DBCR0_IAC2 | \ - DBCR0_IAC3 | DBCR0_IAC4) -#define DBCR1_ACTIVE_EVENTS (DBCR1_DAC1R | DBCR1_DAC2R | \ - DBCR1_DAC1W | DBCR1_DAC2W) -#define DBCR_ACTIVE_EVENTS(dbcr0, dbcr1) (((dbcr0) & DBCR0_ACTIVE_EVENTS) || \ - ((dbcr1) & DBCR1_ACTIVE_EVENTS)) - -#elif defined(CONFIG_BOOKE) #define DBCR0_EDM 0x80000000 /* External Debug Mode */ #define DBCR0_IDM 0x40000000 /* Internal Debug Mode */ #define DBCR0_RST 0x30000000 /* all the bits in the RST field */ @@ -518,7 +410,6 @@ #define DBCR_ACTIVE_EVENTS(dbcr0, dbcr1) (((dbcr0) & DBCR0_ACTIVE_EVENTS) || \ ((dbcr1) & DBCR1_ACTIVE_EVENTS)) -#endif /* #elif defined(CONFIG_BOOKE) */ /* Bit definitions related to the TCR. */ #define TCR_WP(x) (((x)&0x3)<<30) /* WDT Period */ diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h index 9f50766c4623..221c8f8ff89b 100644 --- a/arch/powerpc/include/asm/time.h +++ b/arch/powerpc/include/asm/time.h @@ -58,9 +58,6 @@ static inline u64 get_vtb(void) */ static inline u64 get_dec(void) { - if (IS_ENABLED(CONFIG_40x)) - return mfspr(SPRN_PIT); - return mfspr(SPRN_DEC); } @@ -71,9 +68,7 @@ static inline u64 get_dec(void) */ static inline void set_dec(u64 val) { - if (IS_ENABLED(CONFIG_40x)) - mtspr(SPRN_PIT, (u32)val); - else if (IS_ENABLED(CONFIG_BOOKE)) + if (IS_ENABLED(CONFIG_BOOKE)) mtspr(SPRN_DEC, val); else mtspr(SPRN_DEC, val - 1); diff --git a/arch/powerpc/include/asm/udbg.h b/arch/powerpc/include/asm/udbg.h index b1f094728b35..289023f7a656 100644 --- a/arch/powerpc/include/asm/udbg.h +++ b/arch/powerpc/include/asm/udbg.h @@ -44,7 +44,6 @@ void __init udbg_init_rtas_panel(void); void __init udbg_init_rtas_console(void); void __init udbg_init_btext(void); void __init udbg_init_44x_as1(void); -void __init udbg_init_40x_realmode(void); void __init udbg_init_cpm(void); void __init udbg_init_usbgecko(void); void __init udbg_init_memcons(void); diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h index 1691297a766a..eaeda001784e 100644 --- a/arch/powerpc/include/uapi/asm/kvm.h +++ b/arch/powerpc/include/uapi/asm/kvm.h @@ -645,6 +645,9 @@ struct kvm_ppc_cpu_char { #define KVM_REG_PPC_SIER3 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc3) #define KVM_REG_PPC_DAWR1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc4) #define KVM_REG_PPC_DAWRX1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc5) +#define KVM_REG_PPC_DEXCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc6) +#define KVM_REG_PPC_HASHKEYR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc7) +#define KVM_REG_PPC_HASHPKEYR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc8) /* Transactional Memory checkpointed state: * This is all GPRs, all VSX regs and a subset of SPRs diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 8585d03c02d3..1784b6a6ca1d 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -123,7 +123,6 @@ obj-$(CONFIG_JUMP_LABEL) += jump_label.o obj-$(CONFIG_PPC64) += head_64.o obj-$(CONFIG_PPC_BOOK3S_32) += head_book3s_32.o -obj-$(CONFIG_40x) += head_40x.o obj-$(CONFIG_44x) += head_44x.o obj-$(CONFIG_PPC_8xx) += head_8xx.o obj-$(CONFIG_PPC_85xx) += head_85xx.o diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index f029755f9e69..23733282de4d 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -54,7 +54,7 @@ #endif #ifdef CONFIG_PPC32 -#ifdef CONFIG_BOOKE_OR_40x +#ifdef CONFIG_BOOKE #include "head_booke.h" #endif #endif diff --git a/arch/powerpc/kernel/cpu_specs.h b/arch/powerpc/kernel/cpu_specs.h index 85ded3f77204..5ea14605bb41 100644 --- a/arch/powerpc/kernel/cpu_specs.h +++ b/arch/powerpc/kernel/cpu_specs.h @@ -1,9 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifdef CONFIG_40x -#include "cpu_specs_40x.h" -#endif - #ifdef CONFIG_PPC_47x #include "cpu_specs_47x.h" #elif defined(CONFIG_44x) diff --git a/arch/powerpc/kernel/cpu_specs_40x.h b/arch/powerpc/kernel/cpu_specs_40x.h deleted file mode 100644 index a1362a75b8c8..000000000000 --- a/arch/powerpc/kernel/cpu_specs_40x.h +++ /dev/null @@ -1,280 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) - */ - -static struct cpu_spec cpu_specs[] __initdata = { - { /* STB 04xxx */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x41810000, - .cpu_name = "STB04xxx", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* NP405L */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x41610000, - .cpu_name = "NP405L", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* NP4GS3 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x40B10000, - .cpu_name = "NP4GS3", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* NP405H */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x41410000, - .cpu_name = "NP405H", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* 405GPr */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x50910000, - .cpu_name = "405GPr", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* STBx25xx */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x51510000, - .cpu_name = "STBx25xx", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* 405LP */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x41F10000, - .cpu_name = "405LP", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* 405EP */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x51210000, - .cpu_name = "405EP", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* 405EX Rev. A/B with Security */ - .pvr_mask = 0xffff000f, - .pvr_value = 0x12910007, - .cpu_name = "405EX Rev. A/B", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* 405EX Rev. C without Security */ - .pvr_mask = 0xffff000f, - .pvr_value = 0x1291000d, - .cpu_name = "405EX Rev. C", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* 405EX Rev. C with Security */ - .pvr_mask = 0xffff000f, - .pvr_value = 0x1291000f, - .cpu_name = "405EX Rev. C", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* 405EX Rev. D without Security */ - .pvr_mask = 0xffff000f, - .pvr_value = 0x12910003, - .cpu_name = "405EX Rev. D", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* 405EX Rev. D with Security */ - .pvr_mask = 0xffff000f, - .pvr_value = 0x12910005, - .cpu_name = "405EX Rev. D", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* 405EXr Rev. A/B without Security */ - .pvr_mask = 0xffff000f, - .pvr_value = 0x12910001, - .cpu_name = "405EXr Rev. A/B", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* 405EXr Rev. C without Security */ - .pvr_mask = 0xffff000f, - .pvr_value = 0x12910009, - .cpu_name = "405EXr Rev. C", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* 405EXr Rev. C with Security */ - .pvr_mask = 0xffff000f, - .pvr_value = 0x1291000b, - .cpu_name = "405EXr Rev. C", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* 405EXr Rev. D without Security */ - .pvr_mask = 0xffff000f, - .pvr_value = 0x12910000, - .cpu_name = "405EXr Rev. D", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* 405EXr Rev. D with Security */ - .pvr_mask = 0xffff000f, - .pvr_value = 0x12910002, - .cpu_name = "405EXr Rev. D", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { - /* 405EZ */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x41510000, - .cpu_name = "405EZ", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* APM8018X */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x7ff11432, - .cpu_name = "APM8018X", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - }, - { /* default match */ - .pvr_mask = 0x00000000, - .pvr_value = 0x00000000, - .cpu_name = "(generic 40x PPC)", - .cpu_features = CPU_FTRS_40X, - .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | - PPC_FEATURE_HAS_4xxMAC, - .mmu_features = MMU_FTR_TYPE_40x, - .icache_bsize = 32, - .dcache_bsize = 32, - .machine_check = machine_check_4xx, - .platform = "ppc405", - } -}; diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 6670063a7a6c..d03f17987fca 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -1273,22 +1273,6 @@ EXPORT_SYMBOL(eeh_dev_release); #ifdef CONFIG_IOMMU_API -static int dev_has_iommu_table(struct device *dev, void *data) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct pci_dev **ppdev = data; - - if (!dev) - return 0; - - if (device_iommu_mapped(dev)) { - *ppdev = pdev; - return 1; - } - - return 0; -} - /** * eeh_iommu_group_to_pe - Convert IOMMU group to EEH PE * @group: IOMMU group diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 7eda33a24bb4..f4a8c9877249 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -108,7 +108,7 @@ transfer_to_syscall: stw r11, 0(r1) mflr r12 stw r12, _LINK(r1) -#ifdef CONFIG_BOOKE_OR_40x +#ifdef CONFIG_BOOKE rlwinm r9,r9,0,14,12 /* clear MSR_WE (necessary?) */ #endif lis r12,STACK_FRAME_REGS_MARKER@ha /* exception frame marker */ @@ -158,9 +158,6 @@ syscall_exit_finish: 1: REST_GPR(2, r1) REST_GPR(1, r1) rfi -#ifdef CONFIG_40x - b . /* Prevent prefetch past rfi */ -#endif 3: mtcr r5 lwz r4,_CTR(r1) @@ -214,7 +211,7 @@ start_kernel_thread: .globl fast_exception_return fast_exception_return: -#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) +#ifndef CONFIG_BOOKE andi. r10,r9,MSR_RI /* check for recoverable interrupt */ beq 3f /* if not, we've got problems */ #endif @@ -237,9 +234,6 @@ fast_exception_return: REST_GPR(12, r11) REST_GPR(11, r11) rfi -#ifdef CONFIG_40x - b . /* Prevent prefetch past rfi */ -#endif _ASM_NOKPROBE_SYMBOL(fast_exception_return) /* aargh, a nonrecoverable interrupt, panic */ @@ -296,9 +290,6 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) REST_GPR(0, r1) REST_GPR(1, r1) rfi -#ifdef CONFIG_40x - b . /* Prevent prefetch past rfi */ -#endif .Lrestore_nvgprs: REST_NVGPRS(r1) @@ -346,9 +337,6 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) REST_GPR(0, r1) REST_GPR(1, r1) rfi -#ifdef CONFIG_40x - b . /* Prevent prefetch past rfi */ -#endif 1: /* * Emulate stack store with update. New r1 value was already calculated @@ -375,12 +363,9 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) mfspr r9, SPRN_SPRG_SCRATCH0 #endif rfi -#ifdef CONFIG_40x - b . /* Prevent prefetch past rfi */ -#endif _ASM_NOKPROBE_SYMBOL(interrupt_return) -#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) +#ifdef CONFIG_BOOKE /* * Returning from a critical interrupt in user mode doesn't need @@ -395,17 +380,6 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return) * time of the critical interrupt. * */ -#ifdef CONFIG_40x -#define PPC_40x_TURN_OFF_MSR_DR \ - /* avoid any possible TLB misses here by turning off MSR.DR, we \ - * assume the instructions here are mapped by a pinned TLB entry */ \ - li r10,MSR_IR; \ - mtmsr r10; \ - isync; \ - tophys(r1, r1); -#else -#define PPC_40x_TURN_OFF_MSR_DR -#endif #define RET_FROM_EXC_LEVEL(exc_lvl_srr0, exc_lvl_srr1, exc_lvl_rfi) \ REST_NVGPRS(r1); \ @@ -423,7 +397,6 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return) mtlr r11; \ lwz r10,_CCR(r1); \ mtcrf 0xff,r10; \ - PPC_40x_TURN_OFF_MSR_DR; \ lwz r9,_DEAR(r1); \ lwz r10,_ESR(r1); \ mtspr SPRN_DEAR,r9; \ @@ -471,20 +444,6 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return) #define RESTORE_MMU_REGS #endif -#ifdef CONFIG_40x - .globl ret_from_crit_exc -ret_from_crit_exc: - lis r9,crit_srr0@ha; - lwz r9,crit_srr0@l(r9); - lis r10,crit_srr1@ha; - lwz r10,crit_srr1@l(r10); - mtspr SPRN_SRR0,r9; - mtspr SPRN_SRR1,r10; - RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, PPC_RFCI) -_ASM_NOKPROBE_SYMBOL(ret_from_crit_exc) -#endif /* CONFIG_40x */ - -#ifdef CONFIG_BOOKE .globl ret_from_crit_exc ret_from_crit_exc: RESTORE_xSRR(SRR0,SRR1); @@ -509,4 +468,3 @@ ret_from_mcheck_exc: RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, PPC_RFMCI) _ASM_NOKPROBE_SYMBOL(ret_from_mcheck_exc) #endif /* CONFIG_BOOKE */ -#endif /* !(CONFIG_4xx || CONFIG_BOOKE) */ diff --git a/arch/powerpc/kernel/epapr_hcalls.S b/arch/powerpc/kernel/epapr_hcalls.S index 1a9b5ae8ccb2..6a414ed5a411 100644 --- a/arch/powerpc/kernel/epapr_hcalls.S +++ b/arch/powerpc/kernel/epapr_hcalls.S @@ -21,7 +21,7 @@ _GLOBAL(epapr_ev_idle) ori r4, r4,_TLF_NAPPING /* so when we take an exception */ PPC_STL r4, TI_LOCAL_FLAGS(r2) /* it will return to our caller */ -#ifdef CONFIG_BOOKE_OR_40x +#ifdef CONFIG_BOOKE wrteei 1 #else mfmsr r4 diff --git a/arch/powerpc/kernel/head_32.h b/arch/powerpc/kernel/head_32.h index f8e2911478a7..9cba7dbf58dd 100644 --- a/arch/powerpc/kernel/head_32.h +++ b/arch/powerpc/kernel/head_32.h @@ -21,17 +21,9 @@ mtspr SPRN_SPRG_SCRATCH1,r11 mfspr r10, SPRN_SPRG_THREAD .if \handle_dar_dsisr -#ifdef CONFIG_40x - mfspr r11, SPRN_DEAR -#else mfspr r11, SPRN_DAR -#endif stw r11, DAR(r10) -#ifdef CONFIG_40x - mfspr r11, SPRN_ESR -#else mfspr r11, SPRN_DSISR -#endif stw r11, DSISR(r10) .endif mfspr r11, SPRN_SRR0 @@ -96,9 +88,7 @@ .endif lwz r9, SRR1(r12) lwz r12, SRR0(r12) -#ifdef CONFIG_40x - rlwinm r9,r9,0,14,12 /* clear MSR_WE (necessary?) */ -#elif defined(CONFIG_PPC_8xx) +#ifdef CONFIG_PPC_8xx mtspr SPRN_EID, r2 /* Set MSR_RI */ #else li r10, MSR_KERNEL /* can take exceptions */ diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S deleted file mode 100644 index 9fc90410b385..000000000000 --- a/arch/powerpc/kernel/head_40x.S +++ /dev/null @@ -1,721 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (c) 1995-1996 Gary Thomas - * Initial PowerPC version. - * Copyright (c) 1996 Cort Dougan - * Rewritten for PReP - * Copyright (c) 1996 Paul Mackerras - * Low-level exception handers, MMU support, and rewrite. - * Copyright (c) 1997 Dan Malek - * PowerPC 8xx modifications. - * Copyright (c) 1998-1999 TiVo, Inc. - * PowerPC 403GCX modifications. - * Copyright (c) 1999 Grant Erickson - * PowerPC 403GCX/405GP modifications. - * Copyright 2000 MontaVista Software Inc. - * PPC405 modifications - * PowerPC 403GCX/405GP modifications. - * Author: MontaVista Software, Inc. - * frank_rowand@mvista.com or source@mvista.com - * debbie_chu@mvista.com - * - * Module name: head_4xx.S - * - * Description: - * Kernel execution entry point code. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "head_32.h" - -/* As with the other PowerPC ports, it is expected that when code - * execution begins here, the following registers contain valid, yet - * optional, information: - * - * r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.) - * r4 - Starting address of the init RAM disk - * r5 - Ending address of the init RAM disk - * r6 - Start of kernel command line string (e.g. "mem=96m") - * r7 - End of kernel command line string - * - * This is all going to change RSN when we add bi_recs....... -- Dan - */ - __HEAD -_GLOBAL(_stext); -_GLOBAL(_start); - - mr r31,r3 /* save device tree ptr */ - - /* We have to turn on the MMU right away so we get cache modes - * set correctly. - */ - bl initial_mmu - -/* We now have the lower 16 Meg mapped into TLB entries, and the caches - * ready to work. - */ -turn_on_mmu: - lis r0,MSR_KERNEL@h - ori r0,r0,MSR_KERNEL@l - mtspr SPRN_SRR1,r0 - lis r0,start_here@h - ori r0,r0,start_here@l - mtspr SPRN_SRR0,r0 - rfi /* enables MMU */ - b . /* prevent prefetch past rfi */ - -/* - * This area is used for temporarily saving registers during the - * critical exception prolog. - */ - . = 0xc0 -crit_save: -_GLOBAL(crit_r10) - .space 4 -_GLOBAL(crit_r11) - .space 4 -_GLOBAL(crit_srr0) - .space 4 -_GLOBAL(crit_srr1) - .space 4 -_GLOBAL(crit_r1) - .space 4 -_GLOBAL(crit_dear) - .space 4 -_GLOBAL(crit_esr) - .space 4 - -/* - * Exception prolog for critical exceptions. This is a little different - * from the normal exception prolog above since a critical exception - * can potentially occur at any point during normal exception processing. - * Thus we cannot use the same SPRG registers as the normal prolog above. - * Instead we use a couple of words of memory at low physical addresses. - * This is OK since we don't support SMP on these processors. - */ -.macro CRITICAL_EXCEPTION_PROLOG trapno name - stw r10,crit_r10@l(0) /* save two registers to work with */ - stw r11,crit_r11@l(0) - mfspr r10,SPRN_SRR0 - mfspr r11,SPRN_SRR1 - stw r10,crit_srr0@l(0) - stw r11,crit_srr1@l(0) - mfspr r10,SPRN_DEAR - mfspr r11,SPRN_ESR - stw r10,crit_dear@l(0) - stw r11,crit_esr@l(0) - mfcr r10 /* save CR in r10 for now */ - mfspr r11,SPRN_SRR3 /* check whether user or kernel */ - andi. r11,r11,MSR_PR - lis r11,(critirq_ctx-PAGE_OFFSET)@ha - lwz r11,(critirq_ctx-PAGE_OFFSET)@l(r11) - beq 1f - /* COMING FROM USER MODE */ - mfspr r11,SPRN_SPRG_THREAD /* if from user, start at top of */ - lwz r11,TASK_STACK-THREAD(r11) /* this thread's kernel stack */ -1: stw r1,crit_r1@l(0) - addi r1,r11,THREAD_SIZE-INT_FRAME_SIZE /* Alloc an excpt frm */ - LOAD_REG_IMMEDIATE(r11, MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)) /* re-enable MMU */ - mtspr SPRN_SRR1, r11 - lis r11, 1f@h - ori r11, r11, 1f@l - mtspr SPRN_SRR0, r11 - rfi - - .text -1: -\name\()_virt: - lwz r11,crit_r1@l(0) - stw r11,GPR1(r1) - stw r11,0(r1) - mr r11,r1 - stw r10,_CCR(r11) /* save various registers */ - stw r12,GPR12(r11) - stw r9,GPR9(r11) - mflr r10 - stw r10,_LINK(r11) - lis r9,PAGE_OFFSET@ha - lwz r10,crit_r10@l(r9) - lwz r12,crit_r11@l(r9) - stw r10,GPR10(r11) - stw r12,GPR11(r11) - lwz r12,crit_dear@l(r9) - lwz r9,crit_esr@l(r9) - stw r12,_DEAR(r11) /* since they may have had stuff */ - stw r9,_ESR(r11) /* exception was taken */ - mfspr r12,SPRN_SRR2 - mfspr r9,SPRN_SRR3 - rlwinm r9,r9,0,14,12 /* clear MSR_WE (necessary?) */ - COMMON_EXCEPTION_PROLOG_END \trapno + 2 -_ASM_NOKPROBE_SYMBOL(\name\()_virt) -.endm - - /* - * State at this point: - * r9 saved in stack frame, now saved SRR3 & ~MSR_WE - * r10 saved in crit_r10 and in stack frame, trashed - * r11 saved in crit_r11 and in stack frame, - * now phys stack/exception frame pointer - * r12 saved in stack frame, now saved SRR2 - * CR saved in stack frame, CR0.EQ = !SRR3.PR - * LR, DEAR, ESR in stack frame - * r1 saved in stack frame, now virt stack/excframe pointer - * r0, r3-r8 saved in stack frame - */ - -/* - * Exception vectors. - */ -#define CRITICAL_EXCEPTION(n, label, hdlr) \ - START_EXCEPTION(n, label); \ - CRITICAL_EXCEPTION_PROLOG n label; \ - prepare_transfer_to_handler; \ - bl hdlr; \ - b ret_from_crit_exc - -/* - * 0x0100 - Critical Interrupt Exception - */ - CRITICAL_EXCEPTION(0x0100, CriticalInterrupt, unknown_exception) - -/* - * 0x0200 - Machine Check Exception - */ - CRITICAL_EXCEPTION(0x0200, MachineCheck, machine_check_exception) - -/* - * 0x0300 - Data Storage Exception - * This happens for just a few reasons. U0 set (but we don't do that), - * or zone protection fault (user violation, write to protected page). - * The other Data TLB exceptions bail out to this point - * if they can't resolve the lightweight TLB fault. - */ - START_EXCEPTION(0x0300, DataStorage) - EXCEPTION_PROLOG 0x300 DataStorage handle_dar_dsisr=1 - prepare_transfer_to_handler - bl do_page_fault - b interrupt_return - -/* - * 0x0400 - Instruction Storage Exception - * This is caused by a fetch from non-execute or guarded pages. - */ - START_EXCEPTION(0x0400, InstructionAccess) - EXCEPTION_PROLOG 0x400 InstructionAccess - li r5,0 - stw r5, _ESR(r11) /* Zero ESR */ - stw r12, _DEAR(r11) /* SRR0 as DEAR */ - prepare_transfer_to_handler - bl do_page_fault - b interrupt_return - -/* 0x0500 - External Interrupt Exception */ - EXCEPTION(0x0500, HardwareInterrupt, do_IRQ) - -/* 0x0600 - Alignment Exception */ - START_EXCEPTION(0x0600, Alignment) - EXCEPTION_PROLOG 0x600 Alignment handle_dar_dsisr=1 - prepare_transfer_to_handler - bl alignment_exception - REST_NVGPRS(r1) - b interrupt_return - -/* 0x0700 - Program Exception */ - START_EXCEPTION(0x0700, ProgramCheck) - EXCEPTION_PROLOG 0x700 ProgramCheck handle_dar_dsisr=1 - prepare_transfer_to_handler - bl program_check_exception - REST_NVGPRS(r1) - b interrupt_return - - EXCEPTION(0x0800, Trap_08, unknown_exception) - EXCEPTION(0x0900, Trap_09, unknown_exception) - EXCEPTION(0x0A00, Trap_0A, unknown_exception) - EXCEPTION(0x0B00, Trap_0B, unknown_exception) - -/* 0x0C00 - System Call Exception */ - START_EXCEPTION(0x0C00, SystemCall) - SYSCALL_ENTRY 0xc00 -/* Trap_0D is commented out to get more space for system call exception */ - -/* EXCEPTION(0x0D00, Trap_0D, unknown_exception) */ - EXCEPTION(0x0E00, Trap_0E, unknown_exception) - EXCEPTION(0x0F00, Trap_0F, unknown_exception) - -/* 0x1000 - Programmable Interval Timer (PIT) Exception */ - START_EXCEPTION(0x1000, DecrementerTrap) - b Decrementer - -/* 0x1010 - Fixed Interval Timer (FIT) Exception */ - START_EXCEPTION(0x1010, FITExceptionTrap) - b FITException - -/* 0x1020 - Watchdog Timer (WDT) Exception */ - START_EXCEPTION(0x1020, WDTExceptionTrap) - b WDTException - -/* 0x1100 - Data TLB Miss Exception - * As the name implies, translation is not in the MMU, so search the - * page tables and fix it. The only purpose of this function is to - * load TLB entries from the page table if they exist. - */ - START_EXCEPTION(0x1100, DTLBMiss) - mtspr SPRN_SPRG_SCRATCH5, r10 /* Save some working registers */ - mtspr SPRN_SPRG_SCRATCH6, r11 - mtspr SPRN_SPRG_SCRATCH3, r12 - mtspr SPRN_SPRG_SCRATCH4, r9 - mfcr r12 - mfspr r9, SPRN_PID - rlwimi r12, r9, 0, 0xff - mfspr r10, SPRN_DEAR /* Get faulting address */ - - /* If we are faulting a kernel address, we have to use the - * kernel page tables. - */ - lis r11, PAGE_OFFSET@h - cmplw r10, r11 - blt+ 3f - lis r11, swapper_pg_dir@h - ori r11, r11, swapper_pg_dir@l - li r9, 0 - mtspr SPRN_PID, r9 /* TLB will have 0 TID */ - b 4f - - /* Get the PGD for the current thread. - */ -3: - mfspr r11,SPRN_SPRG_THREAD - lwz r11,PGDIR(r11) -#ifdef CONFIG_PPC_KUAP - rlwinm. r9, r9, 0, 0xff - beq 5f /* Kuap fault */ -#endif -4: - tophys(r11, r11) - rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ - lwz r11, 0(r11) /* Get L1 entry */ - andi. r9, r11, _PMD_PRESENT /* Check if it points to a PTE page */ - beq 2f /* Bail if no table */ - - rlwimi r11, r10, 22, 20, 29 /* Compute PTE address */ - lwz r11, 0(r11) /* Get Linux PTE */ - li r9, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_READ - andc. r9, r9, r11 /* Check permission */ - bne 5f - - rlwinm r9, r11, 1, _PAGE_WRITE /* dirty => w */ - and r9, r9, r11 /* hwwrite = dirty & w */ - rlwimi r11, r9, 0, _PAGE_WRITE /* replace w by hwwrite */ - - /* Create TLB tag. This is the faulting address plus a static - * set of bits. These are size, valid, E, U0. - */ - li r9, 0x00c0 - rlwimi r10, r9, 0, 20, 31 - - b finish_tlb_load - -2: /* Check for possible large-page pmd entry */ - rlwinm. r9, r11, 2, 22, 24 - beq 5f - - /* Create TLB tag. This is the faulting address, plus a static - * set of bits (valid, E, U0) plus the size from the PMD. - */ - ori r9, r9, 0x40 - rlwimi r10, r9, 0, 20, 31 - - b finish_tlb_load - -5: - /* The bailout. Restore registers to pre-exception conditions - * and call the heavyweights to help us out. - */ - mtspr SPRN_PID, r12 - mtcrf 0x80, r12 - mfspr r9, SPRN_SPRG_SCRATCH4 - mfspr r12, SPRN_SPRG_SCRATCH3 - mfspr r11, SPRN_SPRG_SCRATCH6 - mfspr r10, SPRN_SPRG_SCRATCH5 - b DataStorage - -/* 0x1200 - Instruction TLB Miss Exception - * Nearly the same as above, except we get our information from different - * registers and bailout to a different point. - */ - START_EXCEPTION(0x1200, ITLBMiss) - mtspr SPRN_SPRG_SCRATCH5, r10 /* Save some working registers */ - mtspr SPRN_SPRG_SCRATCH6, r11 - mtspr SPRN_SPRG_SCRATCH3, r12 - mtspr SPRN_SPRG_SCRATCH4, r9 - mfcr r12 - mfspr r9, SPRN_PID - rlwimi r12, r9, 0, 0xff - mfspr r10, SPRN_SRR0 /* Get faulting address */ - - /* If we are faulting a kernel address, we have to use the - * kernel page tables. - */ - lis r11, PAGE_OFFSET@h - cmplw r10, r11 - blt+ 3f - lis r11, swapper_pg_dir@h - ori r11, r11, swapper_pg_dir@l - li r9, 0 - mtspr SPRN_PID, r9 /* TLB will have 0 TID */ - b 4f - - /* Get the PGD for the current thread. - */ -3: - mfspr r11,SPRN_SPRG_THREAD - lwz r11,PGDIR(r11) -#ifdef CONFIG_PPC_KUAP - rlwinm. r9, r9, 0, 0xff - beq 5f /* Kuap fault */ -#endif -4: - tophys(r11, r11) - rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ - lwz r11, 0(r11) /* Get L1 entry */ - andi. r9, r11, _PMD_PRESENT /* Check if it points to a PTE page */ - beq 2f /* Bail if no table */ - - rlwimi r11, r10, 22, 20, 29 /* Compute PTE address */ - lwz r11, 0(r11) /* Get Linux PTE */ - li r9, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC - andc. r9, r9, r11 /* Check permission */ - bne 5f - - rlwinm r9, r11, 1, _PAGE_WRITE /* dirty => w */ - and r9, r9, r11 /* hwwrite = dirty & w */ - rlwimi r11, r9, 0, _PAGE_WRITE /* replace w by hwwrite */ - - /* Create TLB tag. This is the faulting address plus a static - * set of bits. These are size, valid, E, U0. - */ - li r9, 0x00c0 - rlwimi r10, r9, 0, 20, 31 - - b finish_tlb_load - -2: /* Check for possible large-page pmd entry */ - rlwinm. r9, r11, 2, 22, 24 - beq 5f - - /* Create TLB tag. This is the faulting address, plus a static - * set of bits (valid, E, U0) plus the size from the PMD. - */ - ori r9, r9, 0x40 - rlwimi r10, r9, 0, 20, 31 - - b finish_tlb_load - -5: - /* The bailout. Restore registers to pre-exception conditions - * and call the heavyweights to help us out. - */ - mtspr SPRN_PID, r12 - mtcrf 0x80, r12 - mfspr r9, SPRN_SPRG_SCRATCH4 - mfspr r12, SPRN_SPRG_SCRATCH3 - mfspr r11, SPRN_SPRG_SCRATCH6 - mfspr r10, SPRN_SPRG_SCRATCH5 - b InstructionAccess - - EXCEPTION(0x1300, Trap_13, unknown_exception) - EXCEPTION(0x1400, Trap_14, unknown_exception) - EXCEPTION(0x1500, Trap_15, unknown_exception) - EXCEPTION(0x1600, Trap_16, unknown_exception) - EXCEPTION(0x1700, Trap_17, unknown_exception) - EXCEPTION(0x1800, Trap_18, unknown_exception) - EXCEPTION(0x1900, Trap_19, unknown_exception) - EXCEPTION(0x1A00, Trap_1A, unknown_exception) - EXCEPTION(0x1B00, Trap_1B, unknown_exception) - EXCEPTION(0x1C00, Trap_1C, unknown_exception) - EXCEPTION(0x1D00, Trap_1D, unknown_exception) - EXCEPTION(0x1E00, Trap_1E, unknown_exception) - EXCEPTION(0x1F00, Trap_1F, unknown_exception) - -/* Check for a single step debug exception while in an exception - * handler before state has been saved. This is to catch the case - * where an instruction that we are trying to single step causes - * an exception (eg ITLB/DTLB miss) and thus the first instruction of - * the exception handler generates a single step debug exception. - * - * If we get a debug trap on the first instruction of an exception handler, - * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is - * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR). - * The exception handler was handling a non-critical interrupt, so it will - * save (and later restore) the MSR via SPRN_SRR1, which will still have - * the MSR_DE bit set. - */ - /* 0x2000 - Debug Exception */ - START_EXCEPTION(0x2000, DebugTrap) - CRITICAL_EXCEPTION_PROLOG 0x2000 DebugTrap - - /* - * If this is a single step or branch-taken exception in an - * exception entry sequence, it was probably meant to apply to - * the code where the exception occurred (since exception entry - * doesn't turn off DE automatically). We simulate the effect - * of turning off DE on entry to an exception handler by turning - * off DE in the SRR3 value and clearing the debug status. - */ - mfspr r10,SPRN_DBSR /* check single-step/branch taken */ - andis. r10,r10,DBSR_IC@h - beq+ 2f - - andi. r10,r9,MSR_IR|MSR_PR /* check supervisor + MMU off */ - beq 1f /* branch and fix it up */ - - mfspr r10,SPRN_SRR2 /* Faulting instruction address */ - cmplwi r10,0x2100 - bgt+ 2f /* address above exception vectors */ - - /* here it looks like we got an inappropriate debug exception. */ -1: rlwinm r9,r9,0,~MSR_DE /* clear DE in the SRR3 value */ - lis r10,DBSR_IC@h /* clear the IC event */ - mtspr SPRN_DBSR,r10 - /* restore state and get out */ - lwz r10,_CCR(r11) - lwz r0,GPR0(r11) - lwz r1,GPR1(r11) - mtcrf 0x80,r10 - mtspr SPRN_SRR2,r12 - mtspr SPRN_SRR3,r9 - lwz r9,GPR9(r11) - lwz r12,GPR12(r11) - lwz r10,crit_r10@l(0) - lwz r11,crit_r11@l(0) - rfci - b . - - /* continue normal handling for a critical exception... */ -2: mfspr r4,SPRN_DBSR - stw r4,_ESR(r11) /* DebugException takes DBSR in _ESR */ - prepare_transfer_to_handler - bl DebugException - b ret_from_crit_exc - - /* Programmable Interval Timer (PIT) Exception. (from 0x1000) */ - __HEAD -Decrementer: - EXCEPTION_PROLOG 0x1000 Decrementer - lis r0,TSR_PIS@h - mtspr SPRN_TSR,r0 /* Clear the PIT exception */ - prepare_transfer_to_handler - bl timer_interrupt - b interrupt_return - - /* Fixed Interval Timer (FIT) Exception. (from 0x1010) */ - __HEAD -FITException: - EXCEPTION_PROLOG 0x1010 FITException - prepare_transfer_to_handler - bl unknown_exception - b interrupt_return - - /* Watchdog Timer (WDT) Exception. (from 0x1020) */ - __HEAD -WDTException: - CRITICAL_EXCEPTION_PROLOG 0x1020 WDTException - prepare_transfer_to_handler - bl WatchdogException - b ret_from_crit_exc - -/* Other PowerPC processors, namely those derived from the 6xx-series - * have vectors from 0x2100 through 0x2F00 defined, but marked as reserved. - * However, for the 4xx-series processors these are neither defined nor - * reserved. - */ - - __HEAD - /* Damn, I came up one instruction too many to fit into the - * exception space :-). Both the instruction and data TLB - * miss get to this point to load the TLB. - * r10 - TLB_TAG value - * r11 - Linux PTE - * r9 - available to use - * PID - loaded with proper value when we get here - * Upon exit, we reload everything and RFI. - * Actually, it will fit now, but oh well.....a common place - * to load the TLB. - */ -tlb_4xx_index: - .long 0 -finish_tlb_load: - /* - * Clear out the software-only bits in the PTE to generate the - * TLB_DATA value. These are the bottom 2 bits of the RPM, the - * 4 bits of the zone field, and M. - */ - li r9, 0x0cf2 - andc r11, r11, r9 - rlwimi r11, r10, 8, 24, 27 /* Copy 4 upper address bit into zone */ - - /* load the next available TLB index. */ - lwz r9, tlb_4xx_index@l(0) - addi r9, r9, 1 - andi. r9, r9, PPC40X_TLB_SIZE - 1 - stw r9, tlb_4xx_index@l(0) - - tlbwe r11, r9, TLB_DATA /* Load TLB LO */ - tlbwe r10, r9, TLB_TAG /* Load TLB HI */ - - /* Done...restore registers and get out of here. - */ - mtspr SPRN_PID, r12 - mtcrf 0x80, r12 - mfspr r9, SPRN_SPRG_SCRATCH4 - mfspr r12, SPRN_SPRG_SCRATCH3 - mfspr r11, SPRN_SPRG_SCRATCH6 - mfspr r10, SPRN_SPRG_SCRATCH5 - rfi /* Should sync shadow TLBs */ - b . /* prevent prefetch past rfi */ - -/* This is where the main kernel code starts. - */ -start_here: - - /* ptr to current */ - lis r2,init_task@h - ori r2,r2,init_task@l - - /* ptr to phys current thread */ - tophys(r4,r2) - addi r4,r4,THREAD /* init task's THREAD */ - mtspr SPRN_SPRG_THREAD,r4 - - /* stack */ - lis r1,init_thread_union@ha - addi r1,r1,init_thread_union@l - li r0,0 - stwu r0,THREAD_SIZE-STACK_FRAME_MIN_SIZE(r1) - - bl early_init /* We have to do this with MMU on */ - -/* - * Decide what sort of machine this is and initialize the MMU. - */ -#ifdef CONFIG_KASAN - bl kasan_early_init -#endif - li r3,0 - mr r4,r31 - bl machine_init - bl MMU_init - -/* Go back to running unmapped so we can load up new values - * and change to using our exception vectors. - * On the 4xx, all we have to do is invalidate the TLB to clear - * the old 16M byte TLB mappings. - */ - lis r4,2f@h - ori r4,r4,2f@l - tophys(r4,r4) - lis r3,(MSR_KERNEL & ~(MSR_IR|MSR_DR))@h - ori r3,r3,(MSR_KERNEL & ~(MSR_IR|MSR_DR))@l - mtspr SPRN_SRR0,r4 - mtspr SPRN_SRR1,r3 - rfi - b . /* prevent prefetch past rfi */ - -/* Load up the kernel context */ -2: - sync /* Flush to memory before changing TLB */ - tlbia - isync /* Flush shadow TLBs */ - - /* set up the PTE pointers for the Abatron bdiGDB. - */ - lis r6, swapper_pg_dir@h - ori r6, r6, swapper_pg_dir@l - lis r5, abatron_pteptrs@h - ori r5, r5, abatron_pteptrs@l - stw r5, 0xf0(0) /* Must match your Abatron config file */ - tophys(r5,r5) - stw r6, 0(r5) - -/* Now turn on the MMU for real! */ - lis r4,MSR_KERNEL@h - ori r4,r4,MSR_KERNEL@l - lis r3,start_kernel@h - ori r3,r3,start_kernel@l - mtspr SPRN_SRR0,r3 - mtspr SPRN_SRR1,r4 - rfi /* enable MMU and jump to start_kernel */ - b . /* prevent prefetch past rfi */ - -/* Set up the initial MMU state so we can do the first level of - * kernel initialization. This maps the first 32 MBytes of memory 1:1 - * virtual to physical and more importantly sets the cache mode. - */ -SYM_FUNC_START_LOCAL(initial_mmu) - tlbia /* Invalidate all TLB entries */ - isync - - /* We should still be executing code at physical address 0x0000xxxx - * at this point. However, start_here is at virtual address - * 0xC000xxxx. So, set up a TLB mapping to cover this once - * translation is enabled. - */ - - lis r3,KERNELBASE@h /* Load the kernel virtual address */ - ori r3,r3,KERNELBASE@l - tophys(r4,r3) /* Load the kernel physical address */ - - iccci r0,r3 /* Invalidate the i-cache before use */ - - /* Load the kernel PID. - */ - li r0,0 - mtspr SPRN_PID,r0 - sync - - /* Configure and load one entry into TLB slots 63 */ - clrrwi r4,r4,10 /* Mask off the real page number */ - ori r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */ - - clrrwi r3,r3,10 /* Mask off the effective page number */ - ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M)) - - li r0,63 /* TLB slot 63 */ - - tlbwe r4,r0,TLB_DATA /* Load the data portion of the entry */ - tlbwe r3,r0,TLB_TAG /* Load the tag portion of the entry */ - - li r0,62 /* TLB slot 62 */ - addis r4,r4,SZ_16M@h - addis r3,r3,SZ_16M@h - tlbwe r4,r0,TLB_DATA /* Load the data portion of the entry */ - tlbwe r3,r0,TLB_TAG /* Load the tag portion of the entry */ - - isync - - /* Establish the exception vector base - */ - lis r4,KERNELBASE@h /* EVPR only uses the high 16-bits */ - tophys(r0,r4) /* Use the physical address */ - mtspr SPRN_EVPR,r0 - - blr -SYM_FUNC_END(initial_mmu) - -_GLOBAL(abort) - mfspr r13,SPRN_DBCR0 - oris r13,r13,DBCR0_RST_SYSTEM@h - mtspr SPRN_DBCR0,r13 diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h index b6b5b01a173c..0b5c1993809e 100644 --- a/arch/powerpc/kernel/head_booke.h +++ b/arch/powerpc/kernel/head_booke.h @@ -145,10 +145,9 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_EMB_HV) b transfer_to_syscall /* jump to handler */ .endm -/* To handle the additional exception priority levels on 40x and Book-E +/* To handle the additional exception priority levels on Book-E * processors we allocate a stack per additional priority level. * - * On 40x critical is the only additional level * On 44x/e500 we have critical and machine check * * Additionally we reserve a SPRG for each priority level so we can free up a diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index b70b4f93561f..76381e14e800 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -643,7 +643,7 @@ void ppc_iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, tbl->it_ops->flush(tbl); } -static void iommu_table_clear(struct iommu_table *tbl) +void iommu_table_clear(struct iommu_table *tbl) { /* * In case of firmware assisted dump system goes through clean @@ -684,7 +684,7 @@ static void iommu_table_clear(struct iommu_table *tbl) #endif } -static void iommu_table_reserve_pages(struct iommu_table *tbl, +void iommu_table_reserve_pages(struct iommu_table *tbl, unsigned long res_start, unsigned long res_end) { int i; @@ -988,6 +988,23 @@ unsigned long iommu_direction_to_tce_perm(enum dma_data_direction dir) EXPORT_SYMBOL_GPL(iommu_direction_to_tce_perm); #ifdef CONFIG_IOMMU_API + +int dev_has_iommu_table(struct device *dev, void *data) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct pci_dev **ppdev = data; + + if (!dev) + return 0; + + if (device_iommu_mapped(dev)) { + *ppdev = pdev; + return 1; + } + + return 0; +} + /* * SPAPR TCE API */ @@ -1102,59 +1119,6 @@ void iommu_tce_kill(struct iommu_table *tbl, } EXPORT_SYMBOL_GPL(iommu_tce_kill); -#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) -static int iommu_take_ownership(struct iommu_table *tbl) -{ - unsigned long flags, i, sz = (tbl->it_size + 7) >> 3; - int ret = 0; - - /* - * VFIO does not control TCE entries allocation and the guest - * can write new TCEs on top of existing ones so iommu_tce_build() - * must be able to release old pages. This functionality - * requires exchange() callback defined so if it is not - * implemented, we disallow taking ownership over the table. - */ - if (!tbl->it_ops->xchg_no_kill) - return -EINVAL; - - spin_lock_irqsave(&tbl->large_pool.lock, flags); - for (i = 0; i < tbl->nr_pools; i++) - spin_lock_nest_lock(&tbl->pools[i].lock, &tbl->large_pool.lock); - - if (iommu_table_in_use(tbl)) { - pr_err("iommu_tce: it_map is not empty"); - ret = -EBUSY; - } else { - memset(tbl->it_map, 0xff, sz); - } - - for (i = 0; i < tbl->nr_pools; i++) - spin_unlock(&tbl->pools[i].lock); - spin_unlock_irqrestore(&tbl->large_pool.lock, flags); - - return ret; -} - -static void iommu_release_ownership(struct iommu_table *tbl) -{ - unsigned long flags, i, sz = (tbl->it_size + 7) >> 3; - - spin_lock_irqsave(&tbl->large_pool.lock, flags); - for (i = 0; i < tbl->nr_pools; i++) - spin_lock_nest_lock(&tbl->pools[i].lock, &tbl->large_pool.lock); - - memset(tbl->it_map, 0, sz); - - iommu_table_reserve_pages(tbl, tbl->it_reserved_start, - tbl->it_reserved_end); - - for (i = 0; i < tbl->nr_pools; i++) - spin_unlock(&tbl->pools[i].lock); - spin_unlock_irqrestore(&tbl->large_pool.lock, flags); -} -#endif - int iommu_add_device(struct iommu_table_group *table_group, struct device *dev) { /* @@ -1186,98 +1150,6 @@ int iommu_add_device(struct iommu_table_group *table_group, struct device *dev) EXPORT_SYMBOL_GPL(iommu_add_device); #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) -/* - * A simple iommu_table_group_ops which only allows reusing the existing - * iommu_table. This handles VFIO for POWER7 or the nested KVM. - * The ops does not allow creating windows and only allows reusing the existing - * one if it matches table_group->tce32_start/tce32_size/page_shift. - */ -static unsigned long spapr_tce_get_table_size(__u32 page_shift, - __u64 window_size, __u32 levels) -{ - unsigned long size; - - if (levels > 1) - return ~0U; - size = window_size >> (page_shift - 3); - return size; -} - -static long spapr_tce_create_table(struct iommu_table_group *table_group, int num, - __u32 page_shift, __u64 window_size, __u32 levels, - struct iommu_table **ptbl) -{ - struct iommu_table *tbl = table_group->tables[0]; - - if (num > 0) - return -EPERM; - - if (tbl->it_page_shift != page_shift || - tbl->it_size != (window_size >> page_shift) || - tbl->it_indirect_levels != levels - 1) - return -EINVAL; - - *ptbl = iommu_tce_table_get(tbl); - return 0; -} - -static long spapr_tce_set_window(struct iommu_table_group *table_group, - int num, struct iommu_table *tbl) -{ - return tbl == table_group->tables[num] ? 0 : -EPERM; -} - -static long spapr_tce_unset_window(struct iommu_table_group *table_group, int num) -{ - return 0; -} - -static long spapr_tce_take_ownership(struct iommu_table_group *table_group) -{ - int i, j, rc = 0; - - for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { - struct iommu_table *tbl = table_group->tables[i]; - - if (!tbl || !tbl->it_map) - continue; - - rc = iommu_take_ownership(tbl); - if (!rc) - continue; - - for (j = 0; j < i; ++j) - iommu_release_ownership(table_group->tables[j]); - return rc; - } - return 0; -} - -static void spapr_tce_release_ownership(struct iommu_table_group *table_group) -{ - int i; - - for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { - struct iommu_table *tbl = table_group->tables[i]; - - if (!tbl) - continue; - - iommu_table_clear(tbl); - if (tbl->it_map) - iommu_release_ownership(tbl); - } -} - -struct iommu_table_group_ops spapr_tce_table_group_ops = { - .get_table_size = spapr_tce_get_table_size, - .create_table = spapr_tce_create_table, - .set_window = spapr_tce_set_window, - .unset_window = spapr_tce_unset_window, - .take_ownership = spapr_tce_take_ownership, - .release_ownership = spapr_tce_release_ownership, -}; - /* * A simple iommu_ops to allow less cruft in generic VFIO code. */ @@ -1299,7 +1171,7 @@ spapr_tce_platform_iommu_attach_dev(struct iommu_domain *platform_domain, * The domain being set to PLATFORM from earlier * BLOCKED. The table_group ownership has to be released. */ - table_group->ops->release_ownership(table_group); + table_group->ops->release_ownership(table_group, dev); iommu_group_put(grp); return 0; @@ -1327,7 +1199,7 @@ spapr_tce_blocked_iommu_attach_dev(struct iommu_domain *platform_domain, * also sets the dma_api ops */ table_group = iommu_group_get_iommudata(grp); - ret = table_group->ops->take_ownership(table_group); + ret = table_group->ops->take_ownership(table_group, dev); iommu_group_put(grp); return ret; diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 7504ceec5c58..2e1600a8bbbb 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -333,7 +333,7 @@ void __init init_IRQ(void) static_call_update(ppc_get_irq, ppc_md.get_irq); } -#ifdef CONFIG_BOOKE_OR_40x +#ifdef CONFIG_BOOKE void *critirq_ctx[NR_CPUS] __read_mostly; void *dbgirq_ctx[NR_CPUS] __read_mostly; void *mcheckirq_ctx[NR_CPUS] __read_mostly; diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index ebe4d1645ca1..7a8bc03a00af 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -45,7 +45,7 @@ static struct hard_trap_info { 0x0800, 0x08 /* SIGFPE */ }, /* fp unavailable */ { 0x0900, 0x0e /* SIGALRM */ }, /* decrementer */ { 0x0c00, 0x14 /* SIGCHLD */ }, /* system call */ -#ifdef CONFIG_BOOKE_OR_40x +#ifdef CONFIG_BOOKE { 0x2002, 0x05 /* SIGTRAP */ }, /* debug */ #if defined(CONFIG_PPC_85xx) { 0x2010, 0x08 /* SIGFPE */ }, /* spe unavailable */ @@ -64,7 +64,7 @@ static struct hard_trap_info { 0x2010, 0x08 /* SIGFPE */ }, /* fp unavailable */ { 0x2020, 0x08 /* SIGFPE */ }, /* ap unavailable */ #endif -#else /* !CONFIG_BOOKE_OR_40x */ +#else /* !CONFIG_BOOKE */ { 0x0d00, 0x05 /* SIGTRAP */ }, /* single-step */ #if defined(CONFIG_PPC_8xx) { 0x1000, 0x04 /* SIGILL */ }, /* software emulation */ diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 2eabb15687a6..033cd00aa0fc 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -176,46 +176,6 @@ _GLOBAL(low_choose_7447a_dfs) #endif /* CONFIG_CPU_FREQ_PMAC && CONFIG_PPC_BOOK3S_32 */ -#ifdef CONFIG_40x - -/* - * Do an IO access in real mode - */ -_GLOBAL(real_readb) - mfmsr r7 - rlwinm r0,r7,0,~MSR_DR - sync - mtmsr r0 - sync - isync - lbz r3,0(r3) - sync - mtmsr r7 - sync - isync - blr -_ASM_NOKPROBE_SYMBOL(real_readb) - - /* - * Do an IO access in real mode - */ -_GLOBAL(real_writeb) - mfmsr r7 - rlwinm r0,r7,0,~MSR_DR - sync - mtmsr r0 - sync - isync - stb r3,0(r4) - sync - mtmsr r7 - sync - isync - blr -_ASM_NOKPROBE_SYMBOL(real_writeb) - -#endif /* CONFIG_40x */ - /* * Copy a whole page. We use the dcbz instruction on the destination * to reduce memory traffic (it eliminates the unnecessary reads of diff --git a/arch/powerpc/kernel/pci-hotplug.c b/arch/powerpc/kernel/pci-hotplug.c index 0fe251c6ac2c..9ea74973d78d 100644 --- a/arch/powerpc/kernel/pci-hotplug.c +++ b/arch/powerpc/kernel/pci-hotplug.c @@ -93,6 +93,36 @@ void pci_hp_remove_devices(struct pci_bus *bus) } EXPORT_SYMBOL_GPL(pci_hp_remove_devices); +static void traverse_siblings_and_scan_slot(struct device_node *start, struct pci_bus *bus) +{ + struct device_node *dn; + int slotno; + + u32 class = 0; + + if (!of_property_read_u32(start->child, "class-code", &class)) { + /* Call of pci_scan_slot for non-bridge/EP case */ + if (!((class >> 8) == PCI_CLASS_BRIDGE_PCI)) { + slotno = PCI_SLOT(PCI_DN(start->child)->devfn); + pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); + return; + } + } + + /* Iterate all siblings */ + for_each_child_of_node(start, dn) { + class = 0; + + if (!of_property_read_u32(start->child, "class-code", &class)) { + /* Call of pci_scan_slot on each sibling-nodes/bridge-ports */ + if ((class >> 8) == PCI_CLASS_BRIDGE_PCI) { + slotno = PCI_SLOT(PCI_DN(dn)->devfn); + pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); + } + } + } +} + /** * pci_hp_add_devices - adds new pci devices to bus * @bus: the indicated PCI bus @@ -106,7 +136,7 @@ EXPORT_SYMBOL_GPL(pci_hp_remove_devices); */ void pci_hp_add_devices(struct pci_bus *bus) { - int slotno, mode, max; + int mode, max; struct pci_dev *dev; struct pci_controller *phb; struct device_node *dn = pci_bus_to_OF_node(bus); @@ -129,8 +159,7 @@ void pci_hp_add_devices(struct pci_bus *bus) * order for fully rescan all the way down to pick them up. * They can have been removed during partial hotplug. */ - slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); - pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); + traverse_siblings_and_scan_slot(dn, bus); max = bus->busn_res.start; /* * Scan bridges that are already configured. We don't touch diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index a7671786764b..3b506d4c55f3 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1573,7 +1573,7 @@ static void __show_regs(struct pt_regs *regs) if (trap == INTERRUPT_MACHINE_CHECK || trap == INTERRUPT_DATA_STORAGE || trap == INTERRUPT_ALIGNMENT) { - if (IS_ENABLED(CONFIG_4xx) || IS_ENABLED(CONFIG_BOOKE)) + if (IS_ENABLED(CONFIG_BOOKE)) pr_cont("DEAR: "REG" ESR: "REG" ", regs->dear, regs->esr); else pr_cont("DAR: "REG" DSISR: %08lx ", regs->dar, regs->dsisr); @@ -1875,7 +1875,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) #if defined(CONFIG_PPC_BOOK3S_32) && defined(CONFIG_PPC_KUAP) p->thread.kuap = KUAP_NONE; #endif -#if defined(CONFIG_BOOKE_OR_40x) && defined(CONFIG_PPC_KUAP) +#if defined(CONFIG_BOOKE) && defined(CONFIG_PPC_KUAP) p->thread.pid = MMU_NO_CONTEXT; #endif diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 60819751e55e..0be07ed407c7 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -331,6 +331,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, void *data) { const char *type = of_get_flat_dt_prop(node, "device_type", NULL); + const __be32 *cpu_version = NULL; const __be32 *prop; const __be32 *intserv; int i, nthreads; @@ -420,7 +421,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, prop = of_get_flat_dt_prop(node, "cpu-version", NULL); if (prop && (be32_to_cpup(prop) & 0xff000000) == 0x0f000000) { identify_cpu(0, be32_to_cpup(prop)); - seq_buf_printf(&ppc_hw_desc, "0x%04x ", be32_to_cpup(prop)); + cpu_version = prop; } check_cpu_feature_properties(node); @@ -431,6 +432,12 @@ static int __init early_init_dt_scan_cpus(unsigned long node, } identical_pvr_fixup(node); + + // We can now add the CPU name & PVR to the hardware description + seq_buf_printf(&ppc_hw_desc, "%s 0x%04lx ", cur_cpu_spec->cpu_name, mfspr(SPRN_PVR)); + if (cpu_version) + seq_buf_printf(&ppc_hw_desc, "0x%04x ", be32_to_cpup(cpu_version)); + init_mmu_slb_size(node); #ifdef CONFIG_PPC64 @@ -881,9 +888,6 @@ void __init early_init_devtree(void *params) dt_cpu_ftrs_scan(); - // We can now add the CPU name & PVR to the hardware description - seq_buf_printf(&ppc_hw_desc, "%s 0x%04lx ", cur_cpu_spec->cpu_name, mfspr(SPRN_PVR)); - /* Retrieve CPU related informations from the flat tree * (altivec support, boot CPU ID, ...) */ diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 8064d9c3de86..f7e86e09c49f 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1916,6 +1917,9 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs) || nargs + nret > ARRAY_SIZE(args.args)) return -EINVAL; + nargs = array_index_nospec(nargs, ARRAY_SIZE(args.args)); + nret = array_index_nospec(nret, ARRAY_SIZE(args.args) - nargs); + /* Copy in args. */ if (copy_from_user(args.args, uargs->args, nargs * sizeof(rtas_arg_t)) != 0) diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index 359577ec1680..5407024881e5 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c @@ -773,4 +773,5 @@ static void __exit rtas_flash_cleanup(void) module_init(rtas_flash_init); module_exit(rtas_flash_cleanup); +MODULE_DESCRIPTION("PPC procfs firmware flash interface"); MODULE_LICENSE("GPL"); diff --git a/arch/powerpc/kernel/setup.h b/arch/powerpc/kernel/setup.h index 7912bb50a7cb..385a00a2e2ca 100644 --- a/arch/powerpc/kernel/setup.h +++ b/arch/powerpc/kernel/setup.h @@ -29,7 +29,7 @@ void setup_tlb_core_data(void); static inline void setup_tlb_core_data(void) { } #endif -#ifdef CONFIG_BOOKE_OR_40x +#ifdef CONFIG_BOOKE void exc_lvl_early_init(void); #else static inline void exc_lvl_early_init(void) { } diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index b761cc1a403c..e515c1f7d8d3 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -176,7 +176,7 @@ void __init emergency_stack_init(void) } #endif -#ifdef CONFIG_BOOKE_OR_40x +#ifdef CONFIG_BOOKE void __init exc_lvl_early_init(void) { unsigned int i, hw_cpu; diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index c0fdc6d94fee..0ff9f038e800 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -695,7 +695,7 @@ static int __init get_freq(char *name, int cells, unsigned long *val) static void start_cpu_decrementer(void) { -#ifdef CONFIG_BOOKE_OR_40x +#ifdef CONFIG_BOOKE unsigned int tcr; /* Clear any pending timer interrupts */ diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index f23430adb68a..28d6472c380a 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -2244,7 +2244,7 @@ void __noreturn unrecoverable_exception(struct pt_regs *regs) ; } -#if defined(CONFIG_BOOKE_WDT) || defined(CONFIG_40x) +#ifdef CONFIG_BOOKE_WDT DEFINE_INTERRUPT_HANDLER_NMI(WatchdogException) { printk (KERN_EMERG "PowerPC Book-E Watchdog Exception\n"); diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index 92b3fc258d11..4b99208f5adc 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -49,9 +49,6 @@ void __init udbg_early_init(void) #elif defined(CONFIG_PPC_EARLY_DEBUG_44x) /* PPC44x debug */ udbg_init_44x_as1(); -#elif defined(CONFIG_PPC_EARLY_DEBUG_40x) - /* PPC40x debug */ - udbg_init_40x_realmode(); #elif defined(CONFIG_PPC_EARLY_DEBUG_CPM) udbg_init_cpm(); #elif defined(CONFIG_PPC_EARLY_DEBUG_USBGECKO) diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c index a0467e528b70..313802aff571 100644 --- a/arch/powerpc/kernel/udbg_16550.c +++ b/arch/powerpc/kernel/udbg_16550.c @@ -274,29 +274,6 @@ void __init udbg_init_44x_as1(void) #endif /* CONFIG_PPC_EARLY_DEBUG_44x */ -#ifdef CONFIG_PPC_EARLY_DEBUG_40x - -static u8 udbg_uart_in_40x(unsigned int reg) -{ - return real_readb((void __iomem *)CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR - + reg); -} - -static void udbg_uart_out_40x(unsigned int reg, u8 val) -{ - real_writeb(val, (void __iomem *)CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR - + reg); -} - -void __init udbg_init_40x_realmode(void) -{ - udbg_uart_in = udbg_uart_in_40x; - udbg_uart_out = udbg_uart_out_40x; - udbg_use_uart(); -} - -#endif /* CONFIG_PPC_EARLY_DEBUG_40x */ - #ifdef CONFIG_PPC_EARLY_DEBUG_16550 static void __iomem *udbg_uart_early_addr; diff --git a/arch/powerpc/kexec/core_64.c b/arch/powerpc/kexec/core_64.c index 72b12bc10f90..222aa326dace 100644 --- a/arch/powerpc/kexec/core_64.c +++ b/arch/powerpc/kexec/core_64.c @@ -467,9 +467,15 @@ static int add_node_props(void *fdt, int node_offset, const struct device_node * * @fdt: Flattened device tree of the kernel. * * Returns 0 on success, negative errno on error. + * + * Note: expecting no subnodes under /cpus/ with device_type == "cpu". + * If this changes, update this function to include them. */ int update_cpus_node(void *fdt) { + int prev_node_offset; + const char *device_type; + const struct fdt_property *prop; struct device_node *cpus_node, *dn; int cpus_offset, cpus_subnode_offset, ret = 0; @@ -480,30 +486,44 @@ int update_cpus_node(void *fdt) return cpus_offset; } - if (cpus_offset > 0) { - ret = fdt_del_node(fdt, cpus_offset); - if (ret < 0) { - pr_err("Error deleting /cpus node: %s\n", fdt_strerror(ret)); - return -EINVAL; + prev_node_offset = cpus_offset; + /* Delete sub-nodes of /cpus node with device_type == "cpu" */ + for (cpus_subnode_offset = fdt_first_subnode(fdt, cpus_offset); cpus_subnode_offset >= 0;) { + /* Ignore nodes that do not have a device_type property or device_type != "cpu" */ + prop = fdt_get_property(fdt, cpus_subnode_offset, "device_type", NULL); + if (!prop || strcmp(prop->data, "cpu")) { + prev_node_offset = cpus_subnode_offset; + goto next_node; } + + ret = fdt_del_node(fdt, cpus_subnode_offset); + if (ret < 0) { + pr_err("Failed to delete a cpus sub-node: %s\n", fdt_strerror(ret)); + return ret; + } +next_node: + if (prev_node_offset == cpus_offset) + cpus_subnode_offset = fdt_first_subnode(fdt, cpus_offset); + else + cpus_subnode_offset = fdt_next_subnode(fdt, prev_node_offset); } - /* Add cpus node to fdt */ - cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), "cpus"); - if (cpus_offset < 0) { - pr_err("Error creating /cpus node: %s\n", fdt_strerror(cpus_offset)); + cpus_node = of_find_node_by_path("/cpus"); + /* Fail here to avoid kexec/kdump kernel boot hung */ + if (!cpus_node) { + pr_err("No /cpus node found\n"); return -EINVAL; } - /* Add cpus node properties */ - cpus_node = of_find_node_by_path("/cpus"); - ret = add_node_props(fdt, cpus_offset, cpus_node); - of_node_put(cpus_node); - if (ret < 0) - return ret; + /* Add all /cpus sub-nodes of device_type == "cpu" to FDT */ + for_each_child_of_node(cpus_node, dn) { + /* Ignore device nodes that do not have a device_type property + * or device_type != "cpu". + */ + device_type = of_get_property(dn, "device_type", NULL); + if (!device_type || strcmp(device_type, "cpu")) + continue; - /* Loop through all subnodes of cpus and add them to fdt */ - for_each_node_by_type(dn, "cpu") { cpus_subnode_offset = fdt_add_subnode(fdt, cpus_offset, dn->full_name); if (cpus_subnode_offset < 0) { pr_err("Unable to add %s subnode: %s\n", dn->full_name, @@ -517,6 +537,7 @@ int update_cpus_node(void *fdt) goto out; } out: + of_node_put(cpus_node); of_node_put(dn); return ret; } diff --git a/arch/powerpc/kexec/elf_64.c b/arch/powerpc/kexec/elf_64.c index 214c071c58ed..5d6d616404cf 100644 --- a/arch/powerpc/kexec/elf_64.c +++ b/arch/powerpc/kexec/elf_64.c @@ -23,6 +23,7 @@ #include #include #include +#include static void *elf64_load(struct kimage *image, char *kernel_buf, unsigned long kernel_len, char *initrd, @@ -36,6 +37,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, const void *slave_code; struct elfhdr ehdr; char *modified_cmdline = NULL; + struct crash_mem *rmem = NULL; struct kexec_elf_info elf_info; struct kexec_buf kbuf = { .image = image, .buf_min = 0, .buf_max = ppc64_rma_size }; @@ -102,17 +104,20 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, kexec_dprintk("Loaded initrd at 0x%lx\n", initrd_load_addr); } + ret = get_reserved_memory_ranges(&rmem); + if (ret) + goto out; + fdt = of_kexec_alloc_and_setup_fdt(image, initrd_load_addr, initrd_len, cmdline, - kexec_extra_fdt_size_ppc64(image)); + kexec_extra_fdt_size_ppc64(image, rmem)); if (!fdt) { pr_err("Error setting up the new device tree.\n"); ret = -EINVAL; goto out; } - ret = setup_new_fdt_ppc64(image, fdt, initrd_load_addr, - initrd_len, cmdline); + ret = setup_new_fdt_ppc64(image, fdt, rmem); if (ret) goto out_free_fdt; @@ -146,6 +151,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, out_free_fdt: kvfree(fdt); out: + kfree(rmem); kfree(modified_cmdline); kexec_free_elf_info(&elf_info); diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c index 925a69ad2468..9738adabeb1f 100644 --- a/arch/powerpc/kexec/file_load_64.c +++ b/arch/powerpc/kexec/file_load_64.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -376,11 +377,10 @@ static int kdump_setup_usable_lmb(struct drmem_lmb *lmb, const __be32 **usm, static int add_usable_mem_property(void *fdt, struct device_node *dn, struct umem_info *um_info) { - int n_mem_addr_cells, n_mem_size_cells, node; + int node; char path[NODE_PATH_LEN]; - int i, len, ranges, ret; - const __be32 *prop; - u64 base, end; + int i, ret; + u64 base, size; of_node_get(dn); @@ -399,41 +399,30 @@ static int add_usable_mem_property(void *fdt, struct device_node *dn, goto out; } - /* Get the address & size cells */ - n_mem_addr_cells = of_n_addr_cells(dn); - n_mem_size_cells = of_n_size_cells(dn); - kexec_dprintk("address cells: %d, size cells: %d\n", n_mem_addr_cells, - n_mem_size_cells); - um_info->idx = 0; if (!check_realloc_usable_mem(um_info, 2)) { ret = -ENOMEM; goto out; } - prop = of_get_property(dn, "reg", &len); - if (!prop || len <= 0) { - ret = 0; - goto out; - } - /* * "reg" property represents sequence of (addr,size) tuples * each representing a memory range. */ - ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells); + for (i = 0; ; i++) { + ret = of_property_read_reg(dn, i, &base, &size); + if (ret) + break; - for (i = 0; i < ranges; i++) { - base = of_read_number(prop, n_mem_addr_cells); - prop += n_mem_addr_cells; - end = base + of_read_number(prop, n_mem_size_cells) - 1; - prop += n_mem_size_cells; - - ret = add_usable_mem(um_info, base, end); + ret = add_usable_mem(um_info, base, base + size - 1); if (ret) goto out; } + // No reg or empty reg? Skip this node. + if (i == 0) + goto out; + /* * No kdump kernel usable memory found in this memory node. * Write (0,0) tuple in linux,usable-memory property for @@ -803,10 +792,9 @@ static unsigned int cpu_node_size(void) return size; } -static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image) +static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image, unsigned int cpu_nodes) { - unsigned int cpu_nodes, extra_size = 0; - struct device_node *dn; + unsigned int extra_size = 0; u64 usm_entries; #ifdef CONFIG_CRASH_HOTPLUG unsigned int possible_cpu_nodes; @@ -826,18 +814,6 @@ static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image) extra_size += (unsigned int)(usm_entries * sizeof(u64)); } - /* - * Get the number of CPU nodes in the current DT. This allows to - * reserve places for CPU nodes added since the boot time. - */ - cpu_nodes = 0; - for_each_node_by_type(dn, "cpu") { - cpu_nodes++; - } - - if (cpu_nodes > boot_cpu_node_count) - extra_size += (cpu_nodes - boot_cpu_node_count) * cpu_node_size(); - #ifdef CONFIG_CRASH_HOTPLUG /* * Make sure enough space is reserved to accommodate possible CPU nodes @@ -861,16 +837,30 @@ static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image) * * Returns the estimated extra size needed for kexec/kdump kernel FDT. */ -unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image) +unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image, struct crash_mem *rmem) { - unsigned int extra_size = 0; + struct device_node *dn; + unsigned int cpu_nodes = 0, extra_size = 0; // Budget some space for the password blob. There's already extra space // for the key name if (plpks_is_available()) extra_size += (unsigned int)plpks_get_passwordlen(); - return extra_size + kdump_extra_fdt_size_ppc64(image); + /* Get the number of CPU nodes in the current device tree */ + for_each_node_by_type(dn, "cpu") { + cpu_nodes++; + } + + /* Consider extra space for CPU nodes added since the boot time */ + if (cpu_nodes > boot_cpu_node_count) + extra_size += (cpu_nodes - boot_cpu_node_count) * cpu_node_size(); + + /* Consider extra space for reserved memory ranges if any */ + if (rmem->nr_ranges > 0) + extra_size += sizeof(struct fdt_reserve_entry) * rmem->nr_ranges; + + return extra_size + kdump_extra_fdt_size_ppc64(image, cpu_nodes); } static int copy_property(void *fdt, int node_offset, const struct device_node *dn, @@ -924,18 +914,13 @@ static int update_pci_dma_nodes(void *fdt, const char *dmapropname) * being loaded. * @image: kexec image being loaded. * @fdt: Flattened device tree for the next kernel. - * @initrd_load_addr: Address where the next initrd will be loaded. - * @initrd_len: Size of the next initrd, or 0 if there will be none. - * @cmdline: Command line for the next kernel, or NULL if there will - * be none. + * @rmem: Reserved memory ranges. * * Returns 0 on success, negative errno on error. */ -int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, - unsigned long initrd_load_addr, - unsigned long initrd_len, const char *cmdline) +int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, struct crash_mem *rmem) { - struct crash_mem *umem = NULL, *rmem = NULL; + struct crash_mem *umem = NULL; int i, nr_ranges, ret; #ifdef CONFIG_CRASH_DUMP @@ -991,10 +976,6 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, goto out; /* Update memory reserve map */ - ret = get_reserved_memory_ranges(&rmem); - if (ret) - goto out; - nr_ranges = rmem ? rmem->nr_ranges : 0; for (i = 0; i < nr_ranges; i++) { u64 base, size; @@ -1014,7 +995,6 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, ret = plpks_populate_fdt(fdt); out: - kfree(rmem); kfree(umem); return ret; } diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index daaf7faf21a5..8f7d7e37bc8c 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -2305,7 +2305,7 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, *val = get_reg_val(id, kvmppc_get_siar_hv(vcpu)); break; case KVM_REG_PPC_SDAR: - *val = get_reg_val(id, kvmppc_get_siar_hv(vcpu)); + *val = get_reg_val(id, kvmppc_get_sdar_hv(vcpu)); break; case KVM_REG_PPC_SIER: *val = get_reg_val(id, kvmppc_get_sier_hv(vcpu, 0)); @@ -2349,6 +2349,15 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, case KVM_REG_PPC_DAWRX1: *val = get_reg_val(id, kvmppc_get_dawrx1_hv(vcpu)); break; + case KVM_REG_PPC_DEXCR: + *val = get_reg_val(id, kvmppc_get_dexcr_hv(vcpu)); + break; + case KVM_REG_PPC_HASHKEYR: + *val = get_reg_val(id, kvmppc_get_hashkeyr_hv(vcpu)); + break; + case KVM_REG_PPC_HASHPKEYR: + *val = get_reg_val(id, kvmppc_get_hashpkeyr_hv(vcpu)); + break; case KVM_REG_PPC_CIABR: *val = get_reg_val(id, kvmppc_get_ciabr_hv(vcpu)); break; @@ -2540,7 +2549,7 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, vcpu->arch.mmcrs = set_reg_val(id, *val); break; case KVM_REG_PPC_MMCR3: - *val = get_reg_val(id, vcpu->arch.mmcr[3]); + kvmppc_set_mmcr_hv(vcpu, 3, set_reg_val(id, *val)); break; case KVM_REG_PPC_PMC1 ... KVM_REG_PPC_PMC8: i = id - KVM_REG_PPC_PMC1; @@ -2592,6 +2601,15 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, case KVM_REG_PPC_DAWRX1: kvmppc_set_dawrx1_hv(vcpu, set_reg_val(id, *val) & ~DAWRX_HYP); break; + case KVM_REG_PPC_DEXCR: + kvmppc_set_dexcr_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_HASHKEYR: + kvmppc_set_hashkeyr_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_HASHPKEYR: + kvmppc_set_hashpkeyr_hv(vcpu, set_reg_val(id, *val)); + break; case KVM_REG_PPC_CIABR: kvmppc_set_ciabr_hv(vcpu, set_reg_val(id, *val)); /* Don't allow setting breakpoints in hypervisor code */ @@ -4108,6 +4126,77 @@ static void vcpu_vpa_increment_dispatch(struct kvm_vcpu *vcpu) } } +/* Helper functions for reading L2's stats from L1's VPA */ +#ifdef CONFIG_PPC_PSERIES +static DEFINE_PER_CPU(u64, l1_to_l2_cs); +static DEFINE_PER_CPU(u64, l2_to_l1_cs); +static DEFINE_PER_CPU(u64, l2_runtime_agg); + +int kvmhv_get_l2_counters_status(void) +{ + return firmware_has_feature(FW_FEATURE_LPAR) && + get_lppaca()->l2_counters_enable; +} + +void kvmhv_set_l2_counters_status(int cpu, bool status) +{ + if (!firmware_has_feature(FW_FEATURE_LPAR)) + return; + if (status) + lppaca_of(cpu).l2_counters_enable = 1; + else + lppaca_of(cpu).l2_counters_enable = 0; +} + +int kmvhv_counters_tracepoint_regfunc(void) +{ + int cpu; + + for_each_present_cpu(cpu) { + kvmhv_set_l2_counters_status(cpu, true); + } + return 0; +} + +void kmvhv_counters_tracepoint_unregfunc(void) +{ + int cpu; + + for_each_present_cpu(cpu) { + kvmhv_set_l2_counters_status(cpu, false); + } +} + +static void do_trace_nested_cs_time(struct kvm_vcpu *vcpu) +{ + struct lppaca *lp = get_lppaca(); + u64 l1_to_l2_ns, l2_to_l1_ns, l2_runtime_ns; + u64 *l1_to_l2_cs_ptr = this_cpu_ptr(&l1_to_l2_cs); + u64 *l2_to_l1_cs_ptr = this_cpu_ptr(&l2_to_l1_cs); + u64 *l2_runtime_agg_ptr = this_cpu_ptr(&l2_runtime_agg); + + l1_to_l2_ns = tb_to_ns(be64_to_cpu(lp->l1_to_l2_cs_tb)); + l2_to_l1_ns = tb_to_ns(be64_to_cpu(lp->l2_to_l1_cs_tb)); + l2_runtime_ns = tb_to_ns(be64_to_cpu(lp->l2_runtime_tb)); + trace_kvmppc_vcpu_stats(vcpu, l1_to_l2_ns - *l1_to_l2_cs_ptr, + l2_to_l1_ns - *l2_to_l1_cs_ptr, + l2_runtime_ns - *l2_runtime_agg_ptr); + *l1_to_l2_cs_ptr = l1_to_l2_ns; + *l2_to_l1_cs_ptr = l2_to_l1_ns; + *l2_runtime_agg_ptr = l2_runtime_ns; +} + +#else +int kvmhv_get_l2_counters_status(void) +{ + return 0; +} + +static void do_trace_nested_cs_time(struct kvm_vcpu *vcpu) +{ +} +#endif + static int kvmhv_vcpu_entry_nestedv2(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcr, u64 *tb) { @@ -4116,6 +4205,11 @@ static int kvmhv_vcpu_entry_nestedv2(struct kvm_vcpu *vcpu, u64 time_limit, int trap; long rc; + if (vcpu->arch.doorbell_request) { + vcpu->arch.doorbell_request = 0; + kvmppc_set_dpdes(vcpu, 1); + } + io = &vcpu->arch.nestedv2_io; msr = mfmsr(); @@ -4156,6 +4250,10 @@ static int kvmhv_vcpu_entry_nestedv2(struct kvm_vcpu *vcpu, u64 time_limit, timer_rearm_host_dec(*tb); + /* Record context switch and guest_run_time data */ + if (kvmhv_get_l2_counters_status()) + do_trace_nested_cs_time(vcpu); + return trap; } @@ -6519,6 +6617,7 @@ static void kvmppc_book3s_exit_hv(void) module_init(kvmppc_book3s_init_hv); module_exit(kvmppc_book3s_exit_hv); +MODULE_DESCRIPTION("KVM on Book3S (POWER8 and later) in hypervisor mode"); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(KVM_MINOR); MODULE_ALIAS("devname:kvm"); diff --git a/arch/powerpc/kvm/book3s_hv.h b/arch/powerpc/kvm/book3s_hv.h index 47b2c815641e..a404c9b221c1 100644 --- a/arch/powerpc/kvm/book3s_hv.h +++ b/arch/powerpc/kvm/book3s_hv.h @@ -116,6 +116,9 @@ KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawr0, 64, KVMPPC_GSID_DAWR0) KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawr1, 64, KVMPPC_GSID_DAWR1) KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawrx0, 64, KVMPPC_GSID_DAWRX0) KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawrx1, 64, KVMPPC_GSID_DAWRX1) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dexcr, 64, KVMPPC_GSID_DEXCR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(hashkeyr, 64, KVMPPC_GSID_HASHKEYR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(hashpkeyr, 64, KVMPPC_GSID_HASHPKEYR) KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(ciabr, 64, KVMPPC_GSID_CIABR) KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(wort, 64, KVMPPC_GSID_WORT) KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(ppr, 64, KVMPPC_GSID_PPR) diff --git a/arch/powerpc/kvm/book3s_hv_nestedv2.c b/arch/powerpc/kvm/book3s_hv_nestedv2.c index 1091f7a83b25..eeecea8f202b 100644 --- a/arch/powerpc/kvm/book3s_hv_nestedv2.c +++ b/arch/powerpc/kvm/book3s_hv_nestedv2.c @@ -193,6 +193,15 @@ static int gs_msg_ops_vcpu_fill_info(struct kvmppc_gs_buff *gsb, case KVMPPC_GSID_DAWRX1: rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.dawrx1); break; + case KVMPPC_GSID_DEXCR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.dexcr); + break; + case KVMPPC_GSID_HASHKEYR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.hashkeyr); + break; + case KVMPPC_GSID_HASHPKEYR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.hashpkeyr); + break; case KVMPPC_GSID_CIABR: rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.ciabr); break; @@ -311,6 +320,10 @@ static int gs_msg_ops_vcpu_fill_info(struct kvmppc_gs_buff *gsb, rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.vcore->vtb); break; + case KVMPPC_GSID_DPDES: + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.vcore->dpdes); + break; case KVMPPC_GSID_LPCR: rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.vcore->lpcr); @@ -441,6 +454,15 @@ static int gs_msg_ops_vcpu_refresh_info(struct kvmppc_gs_msg *gsm, case KVMPPC_GSID_DAWRX1: vcpu->arch.dawrx1 = kvmppc_gse_get_u32(gse); break; + case KVMPPC_GSID_DEXCR: + vcpu->arch.dexcr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_HASHKEYR: + vcpu->arch.hashkeyr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_HASHPKEYR: + vcpu->arch.hashpkeyr = kvmppc_gse_get_u64(gse); + break; case KVMPPC_GSID_CIABR: vcpu->arch.ciabr = kvmppc_gse_get_u64(gse); break; @@ -543,6 +565,9 @@ static int gs_msg_ops_vcpu_refresh_info(struct kvmppc_gs_msg *gsm, case KVMPPC_GSID_VTB: vcpu->arch.vcore->vtb = kvmppc_gse_get_u64(gse); break; + case KVMPPC_GSID_DPDES: + vcpu->arch.vcore->dpdes = kvmppc_gse_get_u64(gse); + break; case KVMPPC_GSID_LPCR: vcpu->arch.vcore->lpcr = kvmppc_gse_get_u64(gse); break; diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index a7d7137ea0c8..7b8ae509328f 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -2111,6 +2111,7 @@ void kvmppc_book3s_exit_pr(void) module_init(kvmppc_book3s_init_pr); module_exit(kvmppc_book3s_exit_pr); +MODULE_DESCRIPTION("KVM on Book3S without using hypervisor mode"); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(KVM_MINOR); MODULE_ALIAS("devname:kvm"); diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index d32abe7fe6ab..961aadc71de2 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -1852,7 +1852,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) kvm_sigset_activate(vcpu); - if (run->immediate_exit) + if (!vcpu->wants_to_run) r = -EINTR; else r = kvmppc_vcpu_run(vcpu); diff --git a/arch/powerpc/kvm/test-guest-state-buffer.c b/arch/powerpc/kvm/test-guest-state-buffer.c index 4720b8dc8837..bfd225329a18 100644 --- a/arch/powerpc/kvm/test-guest-state-buffer.c +++ b/arch/powerpc/kvm/test-guest-state-buffer.c @@ -151,7 +151,7 @@ static void test_gs_bitmap(struct kunit *test) i++; } - for (u16 iden = KVMPPC_GSID_GPR(0); iden <= KVMPPC_GSID_CTRL; iden++) { + for (u16 iden = KVMPPC_GSID_GPR(0); iden <= KVMPPC_GSE_DW_REGS_END; iden++) { kvmppc_gsbm_set(&gsbm, iden); kvmppc_gsbm_set(&gsbm1, iden); KUNIT_EXPECT_TRUE(test, kvmppc_gsbm_test(&gsbm, iden)); @@ -325,4 +325,5 @@ static struct kunit_suite guest_state_buffer_test_suite = { kunit_test_suites(&guest_state_buffer_test_suite); +MODULE_DESCRIPTION("KUnit tests for Guest State Buffer APIs"); MODULE_LICENSE("GPL"); diff --git a/arch/powerpc/kvm/trace_hv.h b/arch/powerpc/kvm/trace_hv.h index 8d57c8428531..77ebc724e6cd 100644 --- a/arch/powerpc/kvm/trace_hv.h +++ b/arch/powerpc/kvm/trace_hv.h @@ -512,6 +512,35 @@ TRACE_EVENT(kvmppc_run_vcpu_exit, __entry->vcpu_id, __entry->exit, __entry->ret) ); +#ifdef CONFIG_PPC_PSERIES + +TRACE_EVENT_FN_COND(kvmppc_vcpu_stats, + TP_PROTO(struct kvm_vcpu *vcpu, u64 l1_to_l2_cs, u64 l2_to_l1_cs, u64 l2_runtime), + + TP_ARGS(vcpu, l1_to_l2_cs, l2_to_l1_cs, l2_runtime), + + TP_CONDITION(l1_to_l2_cs || l2_to_l1_cs || l2_runtime), + + TP_STRUCT__entry( + __field(int, vcpu_id) + __field(u64, l1_to_l2_cs) + __field(u64, l2_to_l1_cs) + __field(u64, l2_runtime) + ), + + TP_fast_assign( + __entry->vcpu_id = vcpu->vcpu_id; + __entry->l1_to_l2_cs = l1_to_l2_cs; + __entry->l2_to_l1_cs = l2_to_l1_cs; + __entry->l2_runtime = l2_runtime; + ), + + TP_printk("VCPU %d: l1_to_l2_cs_time=%llu ns l2_to_l1_cs_time=%llu ns l2_runtime=%llu ns", + __entry->vcpu_id, __entry->l1_to_l2_cs, + __entry->l2_to_l1_cs, __entry->l2_runtime), + kmvhv_counters_tracepoint_regfunc, kmvhv_counters_tracepoint_unregfunc +); +#endif #endif /* _TRACE_KVM_HV_H */ /* This part must be outside protection */ diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c index 15e88f1439ec..b0d927009af8 100644 --- a/arch/powerpc/mm/book3s64/radix_pgtable.c +++ b/arch/powerpc/mm/book3s64/radix_pgtable.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,7 @@ #include #include #include +#include #include @@ -293,7 +295,8 @@ static unsigned long next_boundary(unsigned long addr, unsigned long end) static int __meminit create_physical_mapping(unsigned long start, unsigned long end, - int nid, pgprot_t _prot) + int nid, pgprot_t _prot, + unsigned long mapping_sz_limit) { unsigned long vaddr, addr, mapping_size = 0; bool prev_exec, exec = false; @@ -301,7 +304,10 @@ static int __meminit create_physical_mapping(unsigned long start, int psize; unsigned long max_mapping_size = memory_block_size; - if (debug_pagealloc_enabled_or_kfence()) + if (mapping_sz_limit < max_mapping_size) + max_mapping_size = mapping_sz_limit; + + if (debug_pagealloc_enabled()) max_mapping_size = PAGE_SIZE; start = ALIGN(start, PAGE_SIZE); @@ -356,8 +362,74 @@ static int __meminit create_physical_mapping(unsigned long start, return 0; } +#ifdef CONFIG_KFENCE +static bool __ro_after_init kfence_early_init = !!CONFIG_KFENCE_SAMPLE_INTERVAL; + +static int __init parse_kfence_early_init(char *arg) +{ + int val; + + if (get_option(&arg, &val)) + kfence_early_init = !!val; + return 0; +} +early_param("kfence.sample_interval", parse_kfence_early_init); + +static inline phys_addr_t alloc_kfence_pool(void) +{ + phys_addr_t kfence_pool; + + /* + * TODO: Support to enable KFENCE after bootup depends on the ability to + * split page table mappings. As such support is not currently + * implemented for radix pagetables, support enabling KFENCE + * only at system startup for now. + * + * After support for splitting mappings is available on radix, + * alloc_kfence_pool() & map_kfence_pool() can be dropped and + * mapping for __kfence_pool memory can be + * split during arch_kfence_init_pool(). + */ + if (!kfence_early_init) + goto no_kfence; + + kfence_pool = memblock_phys_alloc(KFENCE_POOL_SIZE, PAGE_SIZE); + if (!kfence_pool) + goto no_kfence; + + memblock_mark_nomap(kfence_pool, KFENCE_POOL_SIZE); + return kfence_pool; + +no_kfence: + disable_kfence(); + return 0; +} + +static inline void map_kfence_pool(phys_addr_t kfence_pool) +{ + if (!kfence_pool) + return; + + if (create_physical_mapping(kfence_pool, kfence_pool + KFENCE_POOL_SIZE, + -1, PAGE_KERNEL, PAGE_SIZE)) + goto err; + + memblock_clear_nomap(kfence_pool, KFENCE_POOL_SIZE); + __kfence_pool = __va(kfence_pool); + return; + +err: + memblock_phys_free(kfence_pool, KFENCE_POOL_SIZE); + disable_kfence(); +} +#else +static inline phys_addr_t alloc_kfence_pool(void) { return 0; } +static inline void map_kfence_pool(phys_addr_t kfence_pool) { } +#endif + static void __init radix_init_pgtable(void) { + phys_addr_t kfence_pool; unsigned long rts_field; phys_addr_t start, end; u64 i; @@ -365,6 +437,8 @@ static void __init radix_init_pgtable(void) /* We don't support slb for radix */ slb_set_size(0); + kfence_pool = alloc_kfence_pool(); + /* * Create the linear mapping */ @@ -381,9 +455,11 @@ static void __init radix_init_pgtable(void) } WARN_ON(create_physical_mapping(start, end, - -1, PAGE_KERNEL)); + -1, PAGE_KERNEL, ~0UL)); } + map_kfence_pool(kfence_pool); + if (!cpu_has_feature(CPU_FTR_HVMODE) && cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG)) { /* @@ -875,7 +951,7 @@ int __meminit radix__create_section_mapping(unsigned long start, } return create_physical_mapping(__pa(start), __pa(end), - nid, prot); + nid, prot, ~0UL); } int __meminit radix__remove_section_mapping(unsigned long start, unsigned long end) diff --git a/arch/powerpc/mm/drmem.c b/arch/powerpc/mm/drmem.c index c110ab8fa8a3..8dd7b340d51f 100644 --- a/arch/powerpc/mm/drmem.c +++ b/arch/powerpc/mm/drmem.c @@ -491,10 +491,8 @@ static int __init drmem_init(void) const __be32 *prop; dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); - if (!dn) { - pr_info("No dynamic reconfiguration memory found\n"); + if (!dn) return 0; - } if (init_drmem_lmb_size(dn)) { of_node_put(dn); diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 215690452495..81c77ddce2e3 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -368,13 +368,13 @@ static void sanity_check_fault(bool is_write, bool is_user, * Define the correct "is_write" bit in error_code based * on the processor family */ -#if (defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) +#ifdef CONFIG_BOOKE #define page_fault_is_write(__err) ((__err) & ESR_DST) #else #define page_fault_is_write(__err) ((__err) & DSISR_ISSTORE) #endif -#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) +#ifdef CONFIG_BOOKE #define page_fault_is_bad(__err) (0) #elif defined(CONFIG_PPC_8xx) #define page_fault_is_bad(__err) ((__err) & DSISR_NOEXEC_OR_G) diff --git a/arch/powerpc/mm/init-common.c b/arch/powerpc/mm/init-common.c index d3a7726ecf51..21131b96d209 100644 --- a/arch/powerpc/mm/init-common.c +++ b/arch/powerpc/mm/init-common.c @@ -31,6 +31,9 @@ EXPORT_SYMBOL_GPL(kernstart_virt_addr); bool disable_kuep = !IS_ENABLED(CONFIG_PPC_KUEP); bool disable_kuap = !IS_ENABLED(CONFIG_PPC_KUAP); +#ifdef CONFIG_KFENCE +bool __ro_after_init kfence_disabled; +#endif static int __init parse_nosmep(char *p) { diff --git a/arch/powerpc/mm/mmu_context.c b/arch/powerpc/mm/mmu_context.c index b24c19078eb1..3e3af29b4523 100644 --- a/arch/powerpc/mm/mmu_context.c +++ b/arch/powerpc/mm/mmu_context.c @@ -21,7 +21,7 @@ static inline void switch_mm_pgdir(struct task_struct *tsk, #ifdef CONFIG_PPC_BOOK3S_32 tsk->thread.sr0 = mm->context.sr0; #endif -#if defined(CONFIG_BOOKE_OR_40x) && defined(CONFIG_PPC_KUAP) +#if defined(CONFIG_BOOKE) && defined(CONFIG_PPC_KUAP) tsk->thread.pid = mm->context.id; #endif } diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index 6949c2c937e7..b2d1eea09761 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h @@ -20,9 +20,9 @@ #include /* - * On 40x and 8xx, we directly inline tlbia and tlbivax + * On 8xx, we directly inline tlbia */ -#if defined(CONFIG_40x) || defined(CONFIG_PPC_8xx) +#ifdef CONFIG_PPC_8xx static inline void _tlbil_all(void) { asm volatile ("sync; tlbia; isync" : : : "memory"); @@ -35,7 +35,7 @@ static inline void _tlbil_pid(unsigned int pid) } #define _tlbil_pid_noind(pid) _tlbil_pid(pid) -#else /* CONFIG_40x || CONFIG_PPC_8xx */ +#else /* CONFIG_PPC_8xx */ extern void _tlbil_all(void); extern void _tlbil_pid(unsigned int pid); #ifdef CONFIG_PPC_BOOK3E_64 @@ -43,7 +43,7 @@ extern void _tlbil_pid_noind(unsigned int pid); #else #define _tlbil_pid_noind(pid) _tlbil_pid(pid) #endif -#endif /* !(CONFIG_40x || CONFIG_PPC_8xx) */ +#endif /* !CONFIG_PPC_8xx */ /* * On 8xx, we directly inline tlbie, on others, it's extern diff --git a/arch/powerpc/mm/nohash/40x.c b/arch/powerpc/mm/nohash/40x.c deleted file mode 100644 index e835e80c09db..000000000000 --- a/arch/powerpc/mm/nohash/40x.c +++ /dev/null @@ -1,161 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * This file contains the routines for initializing the MMU - * on the 4xx series of chips. - * -- paulus - * - * Derived from arch/ppc/mm/init.c: - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) - * and Cort Dougan (PReP) (cort@cs.nmt.edu) - * Copyright (C) 1996 Paul Mackerras - * - * Derived from "arch/i386/mm/init.c" - * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * MMU_init_hw does the chip-specific initialization of the MMU hardware. - */ -void __init MMU_init_hw(void) -{ - int i; - unsigned long zpr; - - /* - * The Zone Protection Register (ZPR) defines how protection will - * be applied to every page which is a member of a given zone. - * The zone index bits (of ZSEL) in the PTE are used for software - * indicators. We use the 4 upper bits of virtual address to select - * the zone. We set all zones above TASK_SIZE to zero, allowing - * only kernel access as indicated in the PTE. For zones below - * TASK_SIZE, we set a 01 binary (a value of 10 will not work) - * to allow user access as indicated in the PTE. This also allows - * kernel access as indicated in the PTE. - */ - - for (i = 0, zpr = 0; i < TASK_SIZE >> 28; i++) - zpr |= 1 << (30 - i * 2); - - mtspr(SPRN_ZPR, zpr); - - flush_instruction_cache(); - - /* - * Set up the real-mode cache parameters for the exception vector - * handlers (which are run in real-mode). - */ - - mtspr(SPRN_DCWR, 0x00000000); /* All caching is write-back */ - - /* - * Cache instruction and data space where the exception - * vectors and the kernel live in real-mode. - */ - - mtspr(SPRN_DCCR, 0xFFFF0000); /* 2GByte of data space at 0x0. */ - mtspr(SPRN_ICCR, 0xFFFF0000); /* 2GByte of instr. space at 0x0. */ -} - -#define LARGE_PAGE_SIZE_16M (1<<24) -#define LARGE_PAGE_SIZE_4M (1<<22) - -unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top) -{ - unsigned long v, s, mapped; - phys_addr_t p; - - v = KERNELBASE; - p = 0; - s = total_lowmem; - - if (IS_ENABLED(CONFIG_KFENCE)) - return 0; - - if (debug_pagealloc_enabled()) - return 0; - - if (strict_kernel_rwx_enabled()) - return 0; - - while (s >= LARGE_PAGE_SIZE_16M) { - pmd_t *pmdp; - unsigned long val = p | _PMD_SIZE_16M | _PAGE_EXEC | _PAGE_RW; - - pmdp = pmd_off_k(v); - *pmdp++ = __pmd(val); - *pmdp++ = __pmd(val); - *pmdp++ = __pmd(val); - *pmdp++ = __pmd(val); - - v += LARGE_PAGE_SIZE_16M; - p += LARGE_PAGE_SIZE_16M; - s -= LARGE_PAGE_SIZE_16M; - } - - while (s >= LARGE_PAGE_SIZE_4M) { - pmd_t *pmdp; - unsigned long val = p | _PMD_SIZE_4M | _PAGE_EXEC | _PAGE_RW; - - pmdp = pmd_off_k(v); - *pmdp = __pmd(val); - - v += LARGE_PAGE_SIZE_4M; - p += LARGE_PAGE_SIZE_4M; - s -= LARGE_PAGE_SIZE_4M; - } - - mapped = total_lowmem - s; - - /* If the size of RAM is not an exact power of two, we may not - * have covered RAM in its entirety with 16 and 4 MiB - * pages. Consequently, restrict the top end of RAM currently - * allocable so that calls to the MEMBLOCK to allocate PTEs for "tail" - * coverage with normal-sized pages (or other reasons) do not - * attempt to allocate outside the allowed range. - */ - memblock_set_current_limit(mapped); - - return mapped; -} - -void setup_initial_memory_limit(phys_addr_t first_memblock_base, - phys_addr_t first_memblock_size) -{ - /* We don't currently support the first MEMBLOCK not mapping 0 - * physical on those processors - */ - BUG_ON(first_memblock_base != 0); - - /* 40x can only access 16MB at the moment (see head_40x.S) */ - memblock_set_current_limit(min_t(u64, first_memblock_size, 0x00800000)); -} diff --git a/arch/powerpc/mm/nohash/Makefile b/arch/powerpc/mm/nohash/Makefile index b3f0498dd42f..86d0fe434824 100644 --- a/arch/powerpc/mm/nohash/Makefile +++ b/arch/powerpc/mm/nohash/Makefile @@ -2,7 +2,6 @@ obj-y += mmu_context.o tlb.o tlb_low.o kup.o obj-$(CONFIG_PPC_BOOK3E_64) += tlb_low_64e.o book3e_pgtable.o -obj-$(CONFIG_40x) += 40x.o obj-$(CONFIG_44x) += 44x.o obj-$(CONFIG_PPC_8xx) += 8xx.o obj-$(CONFIG_PPC_E500) += e500.o diff --git a/arch/powerpc/mm/nohash/kup.c b/arch/powerpc/mm/nohash/kup.c index e1f7de2e54ec..c20c4f357fbf 100644 --- a/arch/powerpc/mm/nohash/kup.c +++ b/arch/powerpc/mm/nohash/kup.c @@ -15,8 +15,6 @@ void setup_kuap(bool disabled) { if (disabled) { - if (IS_ENABLED(CONFIG_40x)) - disable_kuep = true; if (smp_processor_id() == boot_cpuid) cur_cpu_spec->mmu_features &= ~MMU_FTR_KUAP; return; diff --git a/arch/powerpc/mm/nohash/mmu_context.c b/arch/powerpc/mm/nohash/mmu_context.c index ccd5819b1bd9..0b181da40ddb 100644 --- a/arch/powerpc/mm/nohash/mmu_context.c +++ b/arch/powerpc/mm/nohash/mmu_context.c @@ -219,9 +219,6 @@ static void set_context(unsigned long id, pgd_t *pgd) /* sync */ mb(); } else if (kuap_is_disabled()) { - if (IS_ENABLED(CONFIG_40x)) - mb(); /* sync */ - mtspr(SPRN_PID, id); isync(); } @@ -306,7 +303,7 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next, if (IS_ENABLED(CONFIG_BDI_SWITCH)) abatron_pteptrs[1] = next->pgd; set_context(id, next->pgd); -#if defined(CONFIG_BOOKE_OR_40x) && defined(CONFIG_PPC_KUAP) +#if defined(CONFIG_BOOKE) && defined(CONFIG_PPC_KUAP) tsk->thread.pid = id; #endif raw_spin_unlock(&context_lock); diff --git a/arch/powerpc/mm/nohash/tlb_low.S b/arch/powerpc/mm/nohash/tlb_low.S index e1199608ff4d..c4d296e73731 100644 --- a/arch/powerpc/mm/nohash/tlb_low.S +++ b/arch/powerpc/mm/nohash/tlb_low.S @@ -32,32 +32,7 @@ #include #include -#if defined(CONFIG_40x) - -/* - * 40x implementation needs only tlbil_va - */ -_GLOBAL(__tlbil_va) - /* We run the search with interrupts disabled because we have to change - * the PID and I don't want to preempt when that happens. - */ - mfmsr r5 - mfspr r6,SPRN_PID - wrteei 0 - mtspr SPRN_PID,r4 - tlbsx. r3, 0, r3 - mtspr SPRN_PID,r6 - wrtee r5 - bne 1f - sync - /* There are only 64 TLB entries, so r3 < 64, which means bit 25 is - * clear. Since 25 is the V bit in the TLB_TAG, loading this value - * will invalidate the TLB entry. */ - tlbwe r3, r3, TLB_TAG - isync -1: blr - -#elif defined(CONFIG_PPC_8xx) +#if defined(CONFIG_PPC_8xx) /* * Nothing to do for 8xx, everything is inline diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index a490724e84ad..aa89899f0c1a 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -896,7 +896,7 @@ static int __init numa_setup_drmem_lmb(struct drmem_lmb *lmb, static int __init parse_numa_properties(void) { - struct device_node *memory; + struct device_node *memory, *pci; int default_nid = 0; unsigned long i; const __be32 *associativity; @@ -1010,6 +1010,18 @@ new_range: goto new_range; } + for_each_node_by_name(pci, "pci") { + int nid = NUMA_NO_NODE; + + associativity = of_get_associativity(pci); + if (associativity) { + nid = associativity_to_nid(associativity); + initialize_form1_numa_distance(associativity); + } + if (likely(nid >= 0) && !node_online(nid)) + node_set_online(nid); + } + /* * Now do the same thing for each MEMBLOCK listed in the * ibm,dynamic-memory property in the diff --git a/arch/powerpc/mm/ptdump/Makefile b/arch/powerpc/mm/ptdump/Makefile index dc896d2874f3..0f7a050f327e 100644 --- a/arch/powerpc/mm/ptdump/Makefile +++ b/arch/powerpc/mm/ptdump/Makefile @@ -2,7 +2,7 @@ obj-y += ptdump.o -obj-$(CONFIG_4xx) += shared.o +obj-$(CONFIG_44x) += shared.o obj-$(CONFIG_PPC_8xx) += 8xx.o obj-$(CONFIG_PPC_E500) += shared.o obj-$(CONFIG_PPC_BOOK3S_32) += shared.o diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c index 7703dcf48be8..2cbcdf93cc19 100644 --- a/arch/powerpc/net/bpf_jit_comp64.c +++ b/arch/powerpc/net/bpf_jit_comp64.c @@ -510,20 +510,33 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code case BPF_ALU | BPF_DIV | BPF_X: /* (u32) dst /= (u32) src */ case BPF_ALU | BPF_MOD | BPF_X: /* (u32) dst %= (u32) src */ if (BPF_OP(code) == BPF_MOD) { - EMIT(PPC_RAW_DIVWU(tmp1_reg, dst_reg, src_reg)); + if (off) + EMIT(PPC_RAW_DIVW(tmp1_reg, dst_reg, src_reg)); + else + EMIT(PPC_RAW_DIVWU(tmp1_reg, dst_reg, src_reg)); + EMIT(PPC_RAW_MULW(tmp1_reg, src_reg, tmp1_reg)); EMIT(PPC_RAW_SUB(dst_reg, dst_reg, tmp1_reg)); } else - EMIT(PPC_RAW_DIVWU(dst_reg, dst_reg, src_reg)); + if (off) + EMIT(PPC_RAW_DIVW(dst_reg, dst_reg, src_reg)); + else + EMIT(PPC_RAW_DIVWU(dst_reg, dst_reg, src_reg)); goto bpf_alu32_trunc; case BPF_ALU64 | BPF_DIV | BPF_X: /* dst /= src */ case BPF_ALU64 | BPF_MOD | BPF_X: /* dst %= src */ if (BPF_OP(code) == BPF_MOD) { - EMIT(PPC_RAW_DIVDU(tmp1_reg, dst_reg, src_reg)); + if (off) + EMIT(PPC_RAW_DIVD(tmp1_reg, dst_reg, src_reg)); + else + EMIT(PPC_RAW_DIVDU(tmp1_reg, dst_reg, src_reg)); EMIT(PPC_RAW_MULD(tmp1_reg, src_reg, tmp1_reg)); EMIT(PPC_RAW_SUB(dst_reg, dst_reg, tmp1_reg)); } else - EMIT(PPC_RAW_DIVDU(dst_reg, dst_reg, src_reg)); + if (off) + EMIT(PPC_RAW_DIVD(dst_reg, dst_reg, src_reg)); + else + EMIT(PPC_RAW_DIVDU(dst_reg, dst_reg, src_reg)); break; case BPF_ALU | BPF_MOD | BPF_K: /* (u32) dst %= (u32) imm */ case BPF_ALU | BPF_DIV | BPF_K: /* (u32) dst /= (u32) imm */ @@ -544,19 +557,31 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code switch (BPF_CLASS(code)) { case BPF_ALU: if (BPF_OP(code) == BPF_MOD) { - EMIT(PPC_RAW_DIVWU(tmp2_reg, dst_reg, tmp1_reg)); + if (off) + EMIT(PPC_RAW_DIVW(tmp2_reg, dst_reg, tmp1_reg)); + else + EMIT(PPC_RAW_DIVWU(tmp2_reg, dst_reg, tmp1_reg)); EMIT(PPC_RAW_MULW(tmp1_reg, tmp1_reg, tmp2_reg)); EMIT(PPC_RAW_SUB(dst_reg, dst_reg, tmp1_reg)); } else - EMIT(PPC_RAW_DIVWU(dst_reg, dst_reg, tmp1_reg)); + if (off) + EMIT(PPC_RAW_DIVW(dst_reg, dst_reg, tmp1_reg)); + else + EMIT(PPC_RAW_DIVWU(dst_reg, dst_reg, tmp1_reg)); break; case BPF_ALU64: if (BPF_OP(code) == BPF_MOD) { - EMIT(PPC_RAW_DIVDU(tmp2_reg, dst_reg, tmp1_reg)); + if (off) + EMIT(PPC_RAW_DIVD(tmp2_reg, dst_reg, tmp1_reg)); + else + EMIT(PPC_RAW_DIVDU(tmp2_reg, dst_reg, tmp1_reg)); EMIT(PPC_RAW_MULD(tmp1_reg, tmp1_reg, tmp2_reg)); EMIT(PPC_RAW_SUB(dst_reg, dst_reg, tmp1_reg)); } else - EMIT(PPC_RAW_DIVDU(dst_reg, dst_reg, tmp1_reg)); + if (off) + EMIT(PPC_RAW_DIVD(dst_reg, dst_reg, tmp1_reg)); + else + EMIT(PPC_RAW_DIVDU(dst_reg, dst_reg, tmp1_reg)); break; } goto bpf_alu32_trunc; @@ -676,8 +701,14 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code /* special mov32 for zext */ EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg, 0, 0, 31)); break; - } - EMIT(PPC_RAW_MR(dst_reg, src_reg)); + } else if (off == 8) { + EMIT(PPC_RAW_EXTSB(dst_reg, src_reg)); + } else if (off == 16) { + EMIT(PPC_RAW_EXTSH(dst_reg, src_reg)); + } else if (off == 32) { + EMIT(PPC_RAW_EXTSW(dst_reg, src_reg)); + } else if (dst_reg != src_reg) + EMIT(PPC_RAW_MR(dst_reg, src_reg)); goto bpf_alu32_trunc; case BPF_ALU | BPF_MOV | BPF_K: /* (u32) dst = imm */ case BPF_ALU64 | BPF_MOV | BPF_K: /* dst = (s64) imm */ @@ -699,11 +730,12 @@ bpf_alu32_trunc: */ case BPF_ALU | BPF_END | BPF_FROM_LE: case BPF_ALU | BPF_END | BPF_FROM_BE: + case BPF_ALU64 | BPF_END | BPF_FROM_LE: #ifdef __BIG_ENDIAN__ if (BPF_SRC(code) == BPF_FROM_BE) goto emit_clear; #else /* !__BIG_ENDIAN__ */ - if (BPF_SRC(code) == BPF_FROM_LE) + if (BPF_CLASS(code) == BPF_ALU && BPF_SRC(code) == BPF_FROM_LE) goto emit_clear; #endif switch (imm) { @@ -936,13 +968,19 @@ emit_clear: */ /* dst = *(u8 *)(ul) (src + off) */ case BPF_LDX | BPF_MEM | BPF_B: + case BPF_LDX | BPF_MEMSX | BPF_B: case BPF_LDX | BPF_PROBE_MEM | BPF_B: + case BPF_LDX | BPF_PROBE_MEMSX | BPF_B: /* dst = *(u16 *)(ul) (src + off) */ case BPF_LDX | BPF_MEM | BPF_H: + case BPF_LDX | BPF_MEMSX | BPF_H: case BPF_LDX | BPF_PROBE_MEM | BPF_H: + case BPF_LDX | BPF_PROBE_MEMSX | BPF_H: /* dst = *(u32 *)(ul) (src + off) */ case BPF_LDX | BPF_MEM | BPF_W: + case BPF_LDX | BPF_MEMSX | BPF_W: case BPF_LDX | BPF_PROBE_MEM | BPF_W: + case BPF_LDX | BPF_PROBE_MEMSX | BPF_W: /* dst = *(u64 *)(ul) (src + off) */ case BPF_LDX | BPF_MEM | BPF_DW: case BPF_LDX | BPF_PROBE_MEM | BPF_DW: @@ -952,7 +990,7 @@ emit_clear: * load only if addr is kernel address (see is_kernel_addr()), otherwise * set dst_reg=0 and move on. */ - if (BPF_MODE(code) == BPF_PROBE_MEM) { + if (BPF_MODE(code) == BPF_PROBE_MEM || BPF_MODE(code) == BPF_PROBE_MEMSX) { EMIT(PPC_RAW_ADDI(tmp1_reg, src_reg, off)); if (IS_ENABLED(CONFIG_PPC_BOOK3E_64)) PPC_LI64(tmp2_reg, 0x8000000000000000ul); @@ -965,30 +1003,47 @@ emit_clear: * Check if 'off' is word aligned for BPF_DW, because * we might generate two instructions. */ - if (BPF_SIZE(code) == BPF_DW && (off & 3)) + if ((BPF_SIZE(code) == BPF_DW || + (BPF_SIZE(code) == BPF_B && BPF_MODE(code) == BPF_PROBE_MEMSX)) && + (off & 3)) PPC_JMP((ctx->idx + 3) * 4); else PPC_JMP((ctx->idx + 2) * 4); } - switch (size) { - case BPF_B: - EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off)); - break; - case BPF_H: - EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off)); - break; - case BPF_W: - EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off)); - break; - case BPF_DW: - if (off % 4) { - EMIT(PPC_RAW_LI(tmp1_reg, off)); - EMIT(PPC_RAW_LDX(dst_reg, src_reg, tmp1_reg)); - } else { - EMIT(PPC_RAW_LD(dst_reg, src_reg, off)); + if (BPF_MODE(code) == BPF_MEMSX || BPF_MODE(code) == BPF_PROBE_MEMSX) { + switch (size) { + case BPF_B: + EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off)); + EMIT(PPC_RAW_EXTSB(dst_reg, dst_reg)); + break; + case BPF_H: + EMIT(PPC_RAW_LHA(dst_reg, src_reg, off)); + break; + case BPF_W: + EMIT(PPC_RAW_LWA(dst_reg, src_reg, off)); + break; + } + } else { + switch (size) { + case BPF_B: + EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off)); + break; + case BPF_H: + EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off)); + break; + case BPF_W: + EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off)); + break; + case BPF_DW: + if (off % 4) { + EMIT(PPC_RAW_LI(tmp1_reg, off)); + EMIT(PPC_RAW_LDX(dst_reg, src_reg, tmp1_reg)); + } else { + EMIT(PPC_RAW_LD(dst_reg, src_reg, off)); + } + break; } - break; } if (size != BPF_DW && insn_is_zext(&insn[i + 1])) @@ -1065,6 +1120,9 @@ emit_clear: case BPF_JMP | BPF_JA: PPC_JMP(addrs[i + 1 + off]); break; + case BPF_JMP32 | BPF_JA: + PPC_JMP(addrs[i + 1 + imm]); + break; case BPF_JMP | BPF_JGT | BPF_K: case BPF_JMP | BPF_JGT | BPF_X: diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 6b5f8a94e7d8..42867469752d 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -266,31 +266,12 @@ static inline u32 perf_flags_from_msr(struct pt_regs *regs) static inline u32 perf_get_misc_flags(struct pt_regs *regs) { bool use_siar = regs_use_siar(regs); - unsigned long mmcra = regs->dsisr; - int marked = mmcra & MMCRA_SAMPLE_ENABLE; + unsigned long siar; + unsigned long addr; if (!use_siar) return perf_flags_from_msr(regs); - /* - * Check the address in SIAR to identify the - * privilege levels since the SIER[MSR_HV, MSR_PR] - * bits are not set for marked events in power10 - * DD1. - */ - if (marked && (ppmu->flags & PPMU_P10_DD1)) { - unsigned long siar = mfspr(SPRN_SIAR); - if (siar) { - if (is_kernel_addr(siar)) - return PERF_RECORD_MISC_KERNEL; - return PERF_RECORD_MISC_USER; - } else { - if (is_kernel_addr(regs->nip)) - return PERF_RECORD_MISC_KERNEL; - return PERF_RECORD_MISC_USER; - } - } - /* * If we don't have flags in MMCRA, rather than using * the MSR, we intuit the flags from the address in @@ -298,19 +279,31 @@ static inline u32 perf_get_misc_flags(struct pt_regs *regs) * results */ if (ppmu->flags & PPMU_NO_SIPR) { - unsigned long siar = mfspr(SPRN_SIAR); + siar = mfspr(SPRN_SIAR); if (is_kernel_addr(siar)) return PERF_RECORD_MISC_KERNEL; return PERF_RECORD_MISC_USER; } /* PR has priority over HV, so order below is important */ - if (regs_sipr(regs)) - return PERF_RECORD_MISC_USER; - - if (regs_sihv(regs) && (freeze_events_kernel != MMCR0_FCHV)) + if (regs_sipr(regs)) { + if (!(ppmu->flags & PPMU_P10)) + return PERF_RECORD_MISC_USER; + } else if (regs_sihv(regs) && (freeze_events_kernel != MMCR0_FCHV)) return PERF_RECORD_MISC_HYPERVISOR; + /* + * Check the address in SIAR to identify the + * privilege levels since the SIER[MSR_HV, MSR_PR] + * bits are not set correctly in power10 sometimes + */ + if (ppmu->flags & PPMU_P10) { + siar = mfspr(SPRN_SIAR); + addr = siar ? siar : regs->nip; + if (!is_kernel_addr(addr)) + return PERF_RECORD_MISC_USER; + } + return PERF_RECORD_MISC_KERNEL; } diff --git a/arch/powerpc/perf/power10-pmu.c b/arch/powerpc/perf/power10-pmu.c index 62a68b6b2d4b..bb57b7cfe640 100644 --- a/arch/powerpc/perf/power10-pmu.c +++ b/arch/powerpc/perf/power10-pmu.c @@ -593,7 +593,8 @@ static struct power_pmu power10_pmu = { .get_mem_weight = isa207_get_mem_weight, .disable_pmc = isa207_disable_pmc, .flags = PPMU_HAS_SIER | PPMU_ARCH_207S | - PPMU_ARCH_31 | PPMU_HAS_ATTR_CONFIG1, + PPMU_ARCH_31 | PPMU_HAS_ATTR_CONFIG1 | + PPMU_P10, .n_generic = ARRAY_SIZE(power10_generic_events), .generic_events = power10_generic_events, .cache_events = &power10_cache_events, diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig deleted file mode 100644 index b3c466c50535..000000000000 --- a/arch/powerpc/platforms/40x/Kconfig +++ /dev/null @@ -1,78 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config ACADIA - bool "Acadia" - depends on 40x - select PPC40x_SIMPLE - select 405EZ - help - This option enables support for the AMCC 405EZ Acadia evaluation board. - -config HOTFOOT - bool "Hotfoot" - depends on 40x - select PPC40x_SIMPLE - select FORCE_PCI - help - This option enables support for the ESTEEM 195E Hotfoot board. - -config KILAUEA - bool "Kilauea" - depends on 40x - select 405EX - select PPC40x_SIMPLE - select PPC4xx_PCI_EXPRESS - select FORCE_PCI - select PCI_MSI - help - This option enables support for the AMCC PPC405EX evaluation board. - -config MAKALU - bool "Makalu" - depends on 40x - select 405EX - select FORCE_PCI - select PPC4xx_PCI_EXPRESS - select PPC40x_SIMPLE - help - This option enables support for the AMCC PPC405EX board. - -config OBS600 - bool "OpenBlockS 600" - depends on 40x - select 405EX - select PPC40x_SIMPLE - help - This option enables support for PlatHome OpenBlockS 600 server - -config PPC40x_SIMPLE - bool "Simple PowerPC 40x board support" - depends on 40x - help - This option enables the simple PowerPC 40x platform support. - -config 405EX - bool - select IBM_EMAC_EMAC4 if IBM_EMAC - select IBM_EMAC_RGMII if IBM_EMAC - -config 405EZ - bool - select IBM_EMAC_NO_FLOW_CTRL if IBM_EMAC - select IBM_EMAC_MAL_CLR_ICINTSTAT if IBM_EMAC - select IBM_EMAC_MAL_COMMON_ERR if IBM_EMAC - -config PPC4xx_GPIO - bool "PPC4xx GPIO support" - depends on 40x - select GPIOLIB - select OF_GPIO_MM_GPIOCHIP - help - Enable gpiolib support for ppc40x based boards - -config APM8018X - bool "APM8018X" - depends on 40x - select PPC40x_SIMPLE - help - This option enables support for the AppliedMicro APM8018X evaluation - board. diff --git a/arch/powerpc/platforms/40x/Makefile b/arch/powerpc/platforms/40x/Makefile deleted file mode 100644 index 122de98527c4..000000000000 --- a/arch/powerpc/platforms/40x/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_PPC40x_SIMPLE) += ppc40x_simple.o diff --git a/arch/powerpc/platforms/40x/ppc40x_simple.c b/arch/powerpc/platforms/40x/ppc40x_simple.c deleted file mode 100644 index 294ab2728588..000000000000 --- a/arch/powerpc/platforms/40x/ppc40x_simple.c +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Generic PowerPC 40x platform support - * - * Copyright 2008 IBM Corporation - * - * This implements simple platform support for PowerPC 44x chips. This is - * mostly used for eval boards or other simple and "generic" 44x boards. If - * your board has custom functions or hardware, then you will likely want to - * implement your own board.c file to accommodate it. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -static const struct of_device_id ppc40x_of_bus[] __initconst = { - { .compatible = "ibm,plb3", }, - { .compatible = "ibm,plb4", }, - { .compatible = "ibm,opb", }, - { .compatible = "ibm,ebc", }, - { .compatible = "simple-bus", }, - {}, -}; - -static int __init ppc40x_device_probe(void) -{ - of_platform_bus_probe(NULL, ppc40x_of_bus, NULL); - - return 0; -} -machine_device_initcall(ppc40x_simple, ppc40x_device_probe); - -/* This is the list of boards that can be supported by this simple - * platform code. This does _not_ mean the boards are compatible, - * as they most certainly are not from a device tree perspective. - * However, their differences are handled by the device tree and the - * drivers and therefore they don't need custom board support files. - * - * Again, if your board needs to do things differently then create a - * board.c file for it rather than adding it to this list. - */ -static const char * const board[] __initconst = { - "amcc,acadia", - "amcc,haleakala", - "amcc,kilauea", - "amcc,makalu", - "apm,klondike", - "est,hotfoot", - "plathome,obs600", - NULL -}; - -static int __init ppc40x_probe(void) -{ - pci_set_flags(PCI_REASSIGN_ALL_RSRC); - return 1; -} - -define_machine(ppc40x_simple) { - .name = "PowerPC 40x Platform", - .compatibles = board, - .probe = ppc40x_probe, - .progress = udbg_progress, - .init_IRQ = uic_init_tree, - .get_irq = uic_get_irq, - .restart = ppc4xx_reset_system, -}; diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile index 5ba031f57652..ca7b1bb442d9 100644 --- a/arch/powerpc/platforms/44x/Makefile +++ b/arch/powerpc/platforms/44x/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y += misc_44x.o machine_check.o +obj-y += misc_44x.o machine_check.o uic.o soc.o ifneq ($(CONFIG_PPC4xx_CPM),y) obj-y += idle.o endif @@ -12,3 +12,7 @@ obj-$(CONFIG_CANYONLANDS)+= canyonlands.o obj-$(CONFIG_CURRITUCK) += ppc476.o obj-$(CONFIG_AKEBONO) += ppc476.o obj-$(CONFIG_FSP2) += fsp2.o +obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_PPC4xx_HSTA_MSI) += hsta_msi.o +obj-$(CONFIG_PPC4xx_CPM) += cpm.o +obj-$(CONFIG_PPC4xx_GPIO) += gpio.o diff --git a/arch/powerpc/platforms/4xx/cpm.c b/arch/powerpc/platforms/44x/cpm.c similarity index 100% rename from arch/powerpc/platforms/4xx/cpm.c rename to arch/powerpc/platforms/44x/cpm.c diff --git a/arch/powerpc/platforms/4xx/gpio.c b/arch/powerpc/platforms/44x/gpio.c similarity index 100% rename from arch/powerpc/platforms/4xx/gpio.c rename to arch/powerpc/platforms/44x/gpio.c diff --git a/arch/powerpc/platforms/4xx/hsta_msi.c b/arch/powerpc/platforms/44x/hsta_msi.c similarity index 100% rename from arch/powerpc/platforms/4xx/hsta_msi.c rename to arch/powerpc/platforms/44x/hsta_msi.c diff --git a/arch/powerpc/platforms/44x/machine_check.c b/arch/powerpc/platforms/44x/machine_check.c index 5d19daacd78a..85ff33a8d9b6 100644 --- a/arch/powerpc/platforms/44x/machine_check.c +++ b/arch/powerpc/platforms/44x/machine_check.c @@ -9,6 +9,21 @@ #include #include +int machine_check_4xx(struct pt_regs *regs) +{ + unsigned long reason = regs->esr; + + if (reason & ESR_IMCP) { + printk("Instruction"); + mtspr(SPRN_ESR, reason & ~ESR_IMCP); + } else + printk("Data"); + + printk(" machine check in kernel mode.\n"); + + return 0; +} + int machine_check_440A(struct pt_regs *regs) { unsigned long reason = regs->esr; diff --git a/arch/powerpc/platforms/4xx/pci.c b/arch/powerpc/platforms/44x/pci.c similarity index 95% rename from arch/powerpc/platforms/4xx/pci.c rename to arch/powerpc/platforms/44x/pci.c index 48626615b18b..db6d33ca753f 100644 --- a/arch/powerpc/platforms/4xx/pci.c +++ b/arch/powerpc/platforms/44x/pci.c @@ -1263,102 +1263,6 @@ static struct ppc4xx_pciex_hwops ppc460sx_pcie_hwops __initdata = { #endif /* CONFIG_44x */ -#ifdef CONFIG_40x - -static int __init ppc405ex_pciex_core_init(struct device_node *np) -{ - /* Nothing to do, return 2 ports */ - return 2; -} - -static void __init ppc405ex_pcie_phy_reset(struct ppc4xx_pciex_port *port) -{ - /* Assert the PE0_PHY reset */ - mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01010000); - msleep(1); - - /* deassert the PE0_hotreset */ - if (port->endpoint) - mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01111000); - else - mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01101000); - - /* poll for phy !reset */ - /* XXX FIXME add timeout */ - while (!(mfdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSTA) & 0x00001000)) - ; - - /* deassert the PE0_gpl_utl_reset */ - mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x00101000); -} - -static int __init ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) -{ - u32 val; - - if (port->endpoint) - val = PTYPE_LEGACY_ENDPOINT; - else - val = PTYPE_ROOT_PORT; - - mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, - 1 << 24 | val << 20 | LNKW_X1 << 12); - - mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x00000000); - mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01010000); - mtdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSET1, 0x720F0000); - mtdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSET2, 0x70600003); - - /* - * Only reset the PHY when no link is currently established. - * This is for the Atheros PCIe board which has problems to establish - * the link (again) after this PHY reset. All other currently tested - * PCIe boards don't show this problem. - * This has to be re-tested and fixed in a later release! - */ - val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP); - if (!(val & 0x00001000)) - ppc405ex_pcie_phy_reset(port); - - dcr_write(port->dcrs, DCRO_PEGPL_CFG, 0x10000000); /* guarded on */ - - port->has_ibpre = 1; - - return ppc4xx_pciex_port_reset_sdr(port); -} - -static int ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port *port) -{ - dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x0); - - /* - * Set buffer allocations and then assert VRB and TXE. - */ - out_be32(port->utl_base + PEUTL_OUTTR, 0x02000000); - out_be32(port->utl_base + PEUTL_INTR, 0x02000000); - out_be32(port->utl_base + PEUTL_OPDBSZ, 0x04000000); - out_be32(port->utl_base + PEUTL_PBBSZ, 0x21000000); - out_be32(port->utl_base + PEUTL_IPHBSZ, 0x02000000); - out_be32(port->utl_base + PEUTL_IPDBSZ, 0x04000000); - out_be32(port->utl_base + PEUTL_RCIRQEN, 0x00f00000); - out_be32(port->utl_base + PEUTL_PCTL, 0x80800066); - - out_be32(port->utl_base + PEUTL_PBCTL, 0x08000000); - - return 0; -} - -static struct ppc4xx_pciex_hwops ppc405ex_pcie_hwops __initdata = -{ - .want_sdr = true, - .core_init = ppc405ex_pciex_core_init, - .port_init_hw = ppc405ex_pciex_init_port_hw, - .setup_utl = ppc405ex_pciex_init_utl, - .check_link = ppc4xx_pciex_check_link_sdr, -}; - -#endif /* CONFIG_40x */ - #ifdef CONFIG_476FPE static int __init ppc_476fpe_pciex_core_init(struct device_node *np) { @@ -1427,10 +1331,6 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np) if (of_device_is_compatible(np, "ibm,plb-pciex-apm821xx")) ppc4xx_pciex_hwops = &apm821xx_pcie_hwops; #endif /* CONFIG_44x */ -#ifdef CONFIG_40x - if (of_device_is_compatible(np, "ibm,plb-pciex-405ex")) - ppc4xx_pciex_hwops = &ppc405ex_pcie_hwops; -#endif #ifdef CONFIG_476FPE if (of_device_is_compatible(np, "ibm,plb-pciex-476fpe") || of_device_is_compatible(np, "ibm,plb-pciex-476gtr")) diff --git a/arch/powerpc/platforms/4xx/pci.h b/arch/powerpc/platforms/44x/pci.h similarity index 100% rename from arch/powerpc/platforms/4xx/pci.h rename to arch/powerpc/platforms/44x/pci.h diff --git a/arch/powerpc/platforms/4xx/soc.c b/arch/powerpc/platforms/44x/soc.c similarity index 100% rename from arch/powerpc/platforms/4xx/soc.c rename to arch/powerpc/platforms/44x/soc.c diff --git a/arch/powerpc/platforms/4xx/uic.c b/arch/powerpc/platforms/44x/uic.c similarity index 100% rename from arch/powerpc/platforms/4xx/uic.c rename to arch/powerpc/platforms/44x/uic.c diff --git a/arch/powerpc/platforms/4xx/Makefile b/arch/powerpc/platforms/4xx/Makefile deleted file mode 100644 index 2071a0abe09b..000000000000 --- a/arch/powerpc/platforms/4xx/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-y += uic.o machine_check.o -obj-$(CONFIG_4xx_SOC) += soc.o -obj-$(CONFIG_PCI) += pci.o -obj-$(CONFIG_PPC4xx_HSTA_MSI) += hsta_msi.o -obj-$(CONFIG_PPC4xx_CPM) += cpm.o -obj-$(CONFIG_PPC4xx_GPIO) += gpio.o diff --git a/arch/powerpc/platforms/4xx/machine_check.c b/arch/powerpc/platforms/4xx/machine_check.c deleted file mode 100644 index a905da1d6f41..000000000000 --- a/arch/powerpc/platforms/4xx/machine_check.c +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - */ - -#include -#include -#include - -#include - -int machine_check_4xx(struct pt_regs *regs) -{ - unsigned long reason = regs->esr; - - if (reason & ESR_IMCP) { - printk("Instruction"); - mtspr(SPRN_ESR, reason & ~ESR_IMCP); - } else - printk("Data"); - printk(" machine check in kernel mode.\n"); - - return 0; -} diff --git a/arch/powerpc/platforms/85xx/t1042rdb_diu.c b/arch/powerpc/platforms/85xx/t1042rdb_diu.c index 767eed98a0a8..d4fbb6eff38a 100644 --- a/arch/powerpc/platforms/85xx/t1042rdb_diu.c +++ b/arch/powerpc/platforms/85xx/t1042rdb_diu.c @@ -149,4 +149,5 @@ static int __init t1042rdb_diu_init(void) early_initcall(t1042rdb_diu_init); +MODULE_DESCRIPTION("Freescale T1042 DIU driver"); MODULE_LICENSE("GPL"); diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 1fd253f92a77..1112a5831619 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -18,7 +18,6 @@ source "arch/powerpc/platforms/85xx/Kconfig" source "arch/powerpc/platforms/86xx/Kconfig" source "arch/powerpc/platforms/embedded6xx/Kconfig" source "arch/powerpc/platforms/44x/Kconfig" -source "arch/powerpc/platforms/40x/Kconfig" source "arch/powerpc/platforms/amigaone/Kconfig" source "arch/powerpc/platforms/book3s/Kconfig" source "arch/powerpc/platforms/microwatt/Kconfig" diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index b2d8c0da2ad9..4b0d7d4f88f6 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -43,19 +43,10 @@ config PPC_8xx select HAVE_ARCH_VMAP_STACK select HUGETLBFS -config 40x - bool "AMCC 40x" - select PPC_DCR_NATIVE - select PPC_UDBG_16550 - select 4xx_SOC - select HAVE_PCI - select PPC_KUEP if PPC_KUAP - config 44x bool "AMCC 44x, 46x or 47x" select PPC_DCR_NATIVE select PPC_UDBG_16550 - select 4xx_SOC select HAVE_PCI select PHYS_64BIT select PPC_KUEP @@ -194,11 +185,6 @@ config E6500_CPU depends on !CC_IS_CLANG select PPC_HAS_LBARX_LHARX -config 405_CPU - bool "40x family" - depends on 40x - depends on !CC_IS_CLANG - config 440_CPU bool "440 (44x family)" depends on 44x @@ -264,7 +250,6 @@ config TARGET_CPU default "e6500" if E6500_CPU default "power4" if POWERPC64_CPU && !CPU_LITTLE_ENDIAN default "power8" if POWERPC64_CPU && CPU_LITTLE_ENDIAN - default "405" if 405_CPU default "440" if 440_CPU default "464" if 464_CPU default "476" if 476_CPU @@ -340,7 +325,7 @@ config FSL_EMB_PERF_EVENT_E500 config 4xx bool - depends on 40x || 44x + depends on 44x default y config BOOKE @@ -348,11 +333,6 @@ config BOOKE depends on PPC_E500 || 44x default y -config BOOKE_OR_40x - bool - depends on BOOKE || 40x - default y - config PTE_64BIT bool depends on 44x || PPC_E500 || PPC_86xx @@ -495,8 +475,8 @@ config PPC_KERNEL_PCREL This option builds the kernel with the pc relative ABI model. config PPC_KUEP - bool "Kernel Userspace Execution Prevention" if !40x - default y if !40x + bool "Kernel Userspace Execution Prevention" + default y help Enable support for Kernel Userspace Execution Prevention (KUEP) @@ -582,7 +562,7 @@ config NR_CPUS config NOT_COHERENT_CACHE bool - depends on 4xx || PPC_8xx || PPC_MPC512x || \ + depends on 44x || PPC_8xx || PPC_MPC512x || \ GAMECUBE_COMMON || AMIGAONE select ARCH_HAS_DMA_PREP_COHERENT select ARCH_HAS_SYNC_DMA_FOR_DEVICE diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 94470fb27c99..786d374bff31 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -4,8 +4,6 @@ obj-$(CONFIG_FSL_ULI1575) += fsl_uli1575.o obj-$(CONFIG_PPC_PMAC) += powermac/ obj-$(CONFIG_PPC_CHRP) += chrp/ -obj-$(CONFIG_4xx) += 4xx/ -obj-$(CONFIG_40x) += 40x/ obj-$(CONFIG_44x) += 44x/ obj-$(CONFIG_PPC_MPC512x) += 512x/ obj-$(CONFIG_PPC_MPC52xx) += 52xx/ diff --git a/arch/powerpc/platforms/cell/cbe_powerbutton.c b/arch/powerpc/platforms/cell/cbe_powerbutton.c index a3ee397486f6..3d121acdf69b 100644 --- a/arch/powerpc/platforms/cell/cbe_powerbutton.c +++ b/arch/powerpc/platforms/cell/cbe_powerbutton.c @@ -101,5 +101,6 @@ static void __exit cbe_powerbutton_exit(void) module_init(cbe_powerbutton_init); module_exit(cbe_powerbutton_exit); +MODULE_DESCRIPTION("Driver for powerbutton on IBM cell blades"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Krafft "); diff --git a/arch/powerpc/platforms/cell/cbe_thermal.c b/arch/powerpc/platforms/cell/cbe_thermal.c index 2f45428e32c8..c295c6714f9b 100644 --- a/arch/powerpc/platforms/cell/cbe_thermal.c +++ b/arch/powerpc/platforms/cell/cbe_thermal.c @@ -381,6 +381,7 @@ static void __exit thermal_exit(void) } module_exit(thermal_exit); +MODULE_DESCRIPTION("Cell processor thermal driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Krafft "); diff --git a/arch/powerpc/platforms/cell/cpufreq_spudemand.c b/arch/powerpc/platforms/cell/cpufreq_spudemand.c index ca7849e113d7..79172ba36eca 100644 --- a/arch/powerpc/platforms/cell/cpufreq_spudemand.c +++ b/arch/powerpc/platforms/cell/cpufreq_spudemand.c @@ -129,5 +129,6 @@ static struct cpufreq_governor spu_governor = { cpufreq_governor_init(spu_governor); cpufreq_governor_exit(spu_governor); +MODULE_DESCRIPTION("SPU-aware cpufreq governor for the cell processor"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Krafft "); diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 030de2b8c145..70236d1df3d3 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -822,6 +822,7 @@ static void __exit spufs_exit(void) } module_exit(spufs_exit); +MODULE_DESCRIPTION("SPU file system"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Arnd Bergmann "); diff --git a/arch/powerpc/platforms/chrp/nvram.c b/arch/powerpc/platforms/chrp/nvram.c index 0eedae96498c..d3bf56a46656 100644 --- a/arch/powerpc/platforms/chrp/nvram.c +++ b/arch/powerpc/platforms/chrp/nvram.c @@ -92,4 +92,5 @@ void __init chrp_nvram_init(void) return; } +MODULE_DESCRIPTION("PPC NVRAM device driver"); MODULE_LICENSE("GPL v2"); diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 23f5b5093ec1..b0a14e48175c 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -1537,7 +1537,8 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus) } } -static long pnv_ioda2_take_ownership(struct iommu_table_group *table_group) +static long pnv_ioda2_take_ownership(struct iommu_table_group *table_group, + struct device *dev __maybe_unused) { struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe, table_group); @@ -1562,7 +1563,8 @@ static long pnv_ioda2_take_ownership(struct iommu_table_group *table_group) return 0; } -static void pnv_ioda2_release_ownership(struct iommu_table_group *table_group) +static void pnv_ioda2_release_ownership(struct iommu_table_group *table_group, + struct device *dev __maybe_unused) { struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe, table_group); diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index b1e6d275cda9..534cd159e9ab 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,10 @@ static struct iommu_table *iommu_pseries_alloc_table(int node) return tbl; } +#ifdef CONFIG_IOMMU_API +static struct iommu_table_group_ops spapr_tce_table_group_ops; +#endif + static struct iommu_table_group *iommu_pseries_alloc_group(int node) { struct iommu_table_group *table_group; @@ -102,7 +107,7 @@ static void iommu_pseries_free_group(struct iommu_table_group *table_group, #endif /* Default DMA window table is at index 0, while DDW at 1. SR-IOV - * adapters only have table on index 1. + * adapters only have table on index 0(if not direct mapped). */ if (table_group->tables[0]) iommu_tce_table_put(table_group->tables[0]); @@ -143,7 +148,7 @@ static int tce_build_pSeries(struct iommu_table *tbl, long index, } -static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages) +static void tce_clear_pSeries(struct iommu_table *tbl, long index, long npages) { __be64 *tcep; @@ -162,6 +167,39 @@ static unsigned long tce_get_pseries(struct iommu_table *tbl, long index) return be64_to_cpu(*tcep); } +#ifdef CONFIG_IOMMU_API +static long pseries_tce_iommu_userspace_view_alloc(struct iommu_table *tbl) +{ + unsigned long cb = ALIGN(sizeof(tbl->it_userspace[0]) * tbl->it_size, PAGE_SIZE); + unsigned long *uas; + + if (tbl->it_indirect_levels) /* Impossible */ + return -EPERM; + + WARN_ON(tbl->it_userspace); + + uas = vzalloc(cb); + if (!uas) + return -ENOMEM; + + tbl->it_userspace = (__be64 *) uas; + + return 0; +} +#endif + +static void tce_iommu_userspace_view_free(struct iommu_table *tbl) +{ + vfree(tbl->it_userspace); + tbl->it_userspace = NULL; +} + +static void tce_free_pSeries(struct iommu_table *tbl) +{ + if (!tbl->it_userspace) + tce_iommu_userspace_view_free(tbl); +} + static void tce_free_pSeriesLP(unsigned long liobn, long, long, long); static void tce_freemulti_pSeriesLP(struct iommu_table*, long, long); @@ -576,7 +614,7 @@ struct iommu_table_ops iommu_table_lpar_multi_ops; struct iommu_table_ops iommu_table_pseries_ops = { .set = tce_build_pSeries, - .clear = tce_free_pSeries, + .clear = tce_clear_pSeries, .get = tce_get_pseries }; @@ -685,17 +723,47 @@ static int tce_exchange_pseries(struct iommu_table *tbl, long index, unsigned return rc; } + +static __be64 *tce_useraddr_pSeriesLP(struct iommu_table *tbl, long index, + bool __always_unused alloc) +{ + return tbl->it_userspace ? &tbl->it_userspace[index - tbl->it_offset] : NULL; +} #endif struct iommu_table_ops iommu_table_lpar_multi_ops = { .set = tce_buildmulti_pSeriesLP, #ifdef CONFIG_IOMMU_API .xchg_no_kill = tce_exchange_pseries, + .useraddrptr = tce_useraddr_pSeriesLP, #endif .clear = tce_freemulti_pSeriesLP, - .get = tce_get_pSeriesLP + .get = tce_get_pSeriesLP, + .free = tce_free_pSeries }; +#ifdef CONFIG_IOMMU_API +/* + * When the DMA window properties might have been removed, + * the parent node has the table_group setup on it. + */ +static struct device_node *pci_dma_find_parent_node(struct pci_dev *dev, + struct iommu_table_group *table_group) +{ + struct device_node *dn = pci_device_to_OF_node(dev); + struct pci_dn *rpdn; + + for (; dn && PCI_DN(dn); dn = dn->parent) { + rpdn = PCI_DN(dn); + + if (table_group == rpdn->table_group) + return dn; + } + + return NULL; +} +#endif + /* * Find nearest ibm,dma-window (default DMA window) or direct DMA window or * dynamic 64bit DMA window, walking up the device tree. @@ -812,13 +880,6 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) be32_to_cpu(prop.tce_shift), NULL, &iommu_table_lpar_multi_ops); - /* Only for normal boot with default window. Doesn't matter even - * if we set these with DDW which is 64bit during kdump, since - * these will not be used during kdump. - */ - ppci->table_group->tce32_start = be64_to_cpu(prop.dma_base); - ppci->table_group->tce32_size = 1 << be32_to_cpu(prop.window_shift); - if (!iommu_init_table(tbl, ppci->phb->node, 0, 0)) panic("Failed to initialize iommu table"); @@ -917,7 +978,7 @@ static void __remove_dma_window(struct device_node *np, u32 *ddw_avail, u64 liob } static void remove_dma_window(struct device_node *np, u32 *ddw_avail, - struct property *win) + struct property *win, bool cleanup) { struct dynamic_dma_window_prop *dwp; u64 liobn; @@ -925,11 +986,44 @@ static void remove_dma_window(struct device_node *np, u32 *ddw_avail, dwp = win->value; liobn = (u64)be32_to_cpu(dwp->liobn); - clean_dma_window(np, dwp); + if (cleanup) + clean_dma_window(np, dwp); __remove_dma_window(np, ddw_avail, liobn); } -static int remove_ddw(struct device_node *np, bool remove_prop, const char *win_name) +static void copy_property(struct device_node *pdn, const char *from, const char *to) +{ + struct property *src, *dst; + + src = of_find_property(pdn, from, NULL); + if (!src) + return; + + dst = kzalloc(sizeof(*dst), GFP_KERNEL); + if (!dst) + return; + + dst->name = kstrdup(to, GFP_KERNEL); + dst->value = kmemdup(src->value, src->length, GFP_KERNEL); + dst->length = src->length; + if (!dst->name || !dst->value) + return; + + if (of_add_property(pdn, dst)) { + pr_err("Unable to add DMA window property for %pOF", pdn); + goto free_prop; + } + + return; + +free_prop: + kfree(dst->name); + kfree(dst->value); + kfree(dst); +} + +static int remove_dma_window_named(struct device_node *np, bool remove_prop, const char *win_name, + bool cleanup) { struct property *win; u32 ddw_avail[DDW_APPLICABLE_SIZE]; @@ -944,13 +1038,20 @@ static int remove_ddw(struct device_node *np, bool remove_prop, const char *win_ if (ret) return 0; - if (win->length >= sizeof(struct dynamic_dma_window_prop)) - remove_dma_window(np, ddw_avail, win); + remove_dma_window(np, ddw_avail, win, cleanup); if (!remove_prop) return 0; + /* Default window property if removed is lost as reset-pe doesn't restore it. + * Though FDT has a copy of it, the DLPAR hotplugged devices will not have a + * node on FDT until next reboot. So, back it up. + */ + if ((strcmp(win_name, "ibm,dma-window") == 0) && + !of_find_property(np, "ibm,dma-window-saved", NULL)) + copy_property(np, win_name, "ibm,dma-window-saved"); + ret = of_remove_property(np, win); if (ret) pr_warn("%pOF: failed to remove DMA window property: %d\n", @@ -1008,7 +1109,7 @@ static void find_existing_ddw_windows_named(const char *name) for_each_node_with_property(pdn, name) { dma64 = of_get_property(pdn, name, &len); if (!dma64 || len < sizeof(*dma64)) { - remove_ddw(pdn, true, name); + remove_dma_window_named(pdn, true, name, true); continue; } @@ -1304,7 +1405,7 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn) struct ddw_query_response query; struct ddw_create_response create; int page_shift; - u64 win_addr; + u64 win_addr, dynamic_offset = 0; const char *win_name; struct device_node *dn; u32 ddw_avail[DDW_APPLICABLE_SIZE]; @@ -1312,6 +1413,7 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn) struct property *win64; struct failed_ddw_pdn *fpdn; bool default_win_removed = false, direct_mapping = false; + bool dynamic_mapping = false; bool pmem_present; struct pci_dn *pci = PCI_DN(pdn); struct property *default_win = NULL; @@ -1385,7 +1487,7 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn) if (reset_win_ext) goto out_failed; - remove_dma_window(pdn, ddw_avail, default_win); + remove_dma_window(pdn, ddw_avail, default_win, true); default_win_removed = true; /* Query again, to check if the window is available */ @@ -1407,7 +1509,6 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn) goto out_failed; } - /* * The "ibm,pmemory" can appear anywhere in the address space. * Assuming it is still backed by page structs, try MAX_PHYSMEM_BITS @@ -1432,14 +1533,42 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn) 1ULL << page_shift); len = order_base_2(query.largest_available_block << page_shift); - win_name = DMA64_PROPNAME; + + dynamic_mapping = true; } else { direct_mapping = !default_win_removed || (len == MAX_PHYSMEM_BITS) || (!pmem_present && (len == max_ram_len)); - win_name = direct_mapping ? DIRECT64_PROPNAME : DMA64_PROPNAME; + + /* DDW is big enough to direct map RAM. If there is vPMEM, check + * if enough space is left in DDW where we can dynamically + * allocate TCEs for vPMEM. For now, this Hybrid sharing of DDW + * is only for SR-IOV devices. + */ + if (default_win_removed && pmem_present && !direct_mapping) { + /* DDW is big enough to be split */ + if ((query.largest_available_block << page_shift) >= + MIN_DDW_VPMEM_DMA_WINDOW + (1ULL << max_ram_len)) { + direct_mapping = true; + + /* offset of the Dynamic part of DDW */ + dynamic_offset = 1ULL << max_ram_len; + } + + /* DDW will at least have dynamic allocation */ + dynamic_mapping = true; + + /* create max size DDW possible */ + len = order_base_2(query.largest_available_block + << page_shift); + } } + /* Even if the DDW is split into both direct mapped RAM and dynamically + * mapped vPMEM, the DDW property in OF will be marked as Direct. + */ + win_name = direct_mapping ? DIRECT64_PROPNAME : DMA64_PROPNAME; + ret = create_ddw(dev, ddw_avail, &create, page_shift, len); if (ret != 0) goto out_failed; @@ -1467,9 +1596,9 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn) if (!window) goto out_del_prop; - if (direct_mapping) { - window->direct = true; + window->direct = direct_mapping; + if (direct_mapping) { /* DDW maps the whole partition, so enable direct DMA mapping */ ret = walk_system_ram_range(0, memblock_end_of_DRAM() >> PAGE_SHIFT, win64->value, tce_setrange_multi_pSeriesLP_walk); @@ -1481,12 +1610,18 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn) clean_dma_window(pdn, win64->value); goto out_del_list; } - } else { + if (default_win_removed) { + iommu_tce_table_put(pci->table_group->tables[0]); + pci->table_group->tables[0] = NULL; + set_iommu_table_base(&dev->dev, NULL); + } + } + + if (dynamic_mapping) { struct iommu_table *newtbl; int i; unsigned long start = 0, end = 0; - - window->direct = false; + u64 dynamic_addr, dynamic_len; for (i = 0; i < ARRAY_SIZE(pci->phb->mem_resources); i++) { const unsigned long mask = IORESOURCE_MEM_64 | IORESOURCE_MEM; @@ -1506,20 +1641,26 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn) goto out_del_list; } - iommu_table_setparms_common(newtbl, pci->phb->bus->number, create.liobn, win_addr, - 1UL << len, page_shift, NULL, &iommu_table_lpar_multi_ops); + /* If the DDW is split between directly mapped RAM and Dynamic + * mapped for TCES, offset into the DDW where the dynamic part + * begins. + */ + dynamic_addr = win_addr + dynamic_offset; + dynamic_len = (1UL << len) - dynamic_offset; + iommu_table_setparms_common(newtbl, pci->phb->bus->number, create.liobn, + dynamic_addr, dynamic_len, page_shift, NULL, + &iommu_table_lpar_multi_ops); iommu_init_table(newtbl, pci->phb->node, start, end); - pci->table_group->tables[1] = newtbl; + pci->table_group->tables[default_win_removed ? 0 : 1] = newtbl; set_iommu_table_base(&dev->dev, newtbl); } if (default_win_removed) { - iommu_tce_table_put(pci->table_group->tables[0]); - pci->table_group->tables[0] = NULL; - /* default_win is valid here because default_win_removed == true */ + if (!of_find_property(pdn, "ibm,dma-window-saved", NULL)) + copy_property(pdn, "ibm,dma-window", "ibm,dma-window-saved"); of_remove_property(pdn, default_win); dev_info(&dev->dev, "Removed default DMA window for %pOF\n", pdn); } @@ -1559,17 +1700,81 @@ out_failed: out_unlock: mutex_unlock(&dma_win_init_mutex); - /* - * If we have persistent memory and the window size is only as big - * as RAM, then we failed to create a window to cover persistent - * memory and need to set the DMA limit. + /* If we have persistent memory and the window size is not big enough + * to directly map both RAM and vPMEM, then we need to set DMA limit. */ - if (pmem_present && direct_mapping && len == max_ram_len) - dev->dev.bus_dma_limit = dev->dev.archdata.dma_offset + (1ULL << len); + if (pmem_present && direct_mapping && len != MAX_PHYSMEM_BITS) + dev->dev.bus_dma_limit = dev->dev.archdata.dma_offset + + (1ULL << max_ram_len); return direct_mapping; } +static __u64 query_page_size_to_mask(u32 query_page_size) +{ + const long shift[] = { + (SZ_4K), (SZ_64K), (SZ_16M), + (SZ_32M), (SZ_64M), (SZ_128M), + (SZ_256M), (SZ_16G), (SZ_2M) + }; + int i, ret = 0; + + for (i = 0; i < ARRAY_SIZE(shift); i++) { + if (query_page_size & (1 << i)) + ret |= shift[i]; + } + + return ret; +} + +static void spapr_tce_init_table_group(struct pci_dev *pdev, + struct device_node *pdn, + struct dynamic_dma_window_prop prop) +{ + struct iommu_table_group *table_group = PCI_DN(pdn)->table_group; + u32 ddw_avail[DDW_APPLICABLE_SIZE]; + + struct ddw_query_response query; + int ret; + + /* Only for normal boot with default window. Doesn't matter during + * kdump, since these will not be used during kdump. + */ + if (is_kdump_kernel()) + return; + + if (table_group->max_dynamic_windows_supported != 0) + return; /* already initialized */ + + table_group->tce32_start = be64_to_cpu(prop.dma_base); + table_group->tce32_size = 1 << be32_to_cpu(prop.window_shift); + + if (!of_find_property(pdn, "ibm,dma-window", NULL)) + dev_err(&pdev->dev, "default dma window missing!\n"); + + ret = of_property_read_u32_array(pdn, "ibm,ddw-applicable", + &ddw_avail[0], DDW_APPLICABLE_SIZE); + if (ret) { + table_group->max_dynamic_windows_supported = -1; + return; + } + + ret = query_ddw(pdev, ddw_avail, &query, pdn); + if (ret) { + dev_err(&pdev->dev, "%s: query_ddw failed\n", __func__); + table_group->max_dynamic_windows_supported = -1; + return; + } + + if (query.windows_available == 0) + table_group->max_dynamic_windows_supported = 1; + else + table_group->max_dynamic_windows_supported = IOMMU_TABLE_GROUP_MAX_TABLES; + + table_group->max_levels = 1; + table_group->pgsizes |= query_page_size_to_mask(query.page_size); +} + static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) { struct device_node *pdn, *dn; @@ -1609,13 +1814,6 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) be32_to_cpu(prop.tce_shift), NULL, &iommu_table_lpar_multi_ops); - /* Only for normal boot with default window. Doesn't matter even - * if we set these with DDW which is 64bit during kdump, since - * these will not be used during kdump. - */ - pci->table_group->tce32_start = be64_to_cpu(prop.dma_base); - pci->table_group->tce32_size = 1 << be32_to_cpu(prop.window_shift); - iommu_init_table(tbl, pci->phb->node, 0, 0); iommu_register_group(pci->table_group, pci_domain_nr(pci->phb->bus), 0); @@ -1624,6 +1822,8 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) pr_debug(" found DMA window, table: %p\n", pci->table_group); } + spapr_tce_init_table_group(dev, pdn, prop); + set_iommu_table_base(&dev->dev, pci->table_group->tables[0]); iommu_add_device(pci->table_group, &dev->dev); } @@ -1651,6 +1851,491 @@ static bool iommu_bypass_supported_pSeriesLP(struct pci_dev *pdev, u64 dma_mask) return false; } +#ifdef CONFIG_IOMMU_API +/* + * A simple iommu_table_group_ops which only allows reusing the existing + * iommu_table. This handles VFIO for POWER7 or the nested KVM. + * The ops does not allow creating windows and only allows reusing the existing + * one if it matches table_group->tce32_start/tce32_size/page_shift. + */ +static unsigned long spapr_tce_get_table_size(__u32 page_shift, + __u64 window_size, __u32 levels) +{ + unsigned long size; + + if (levels > 1) + return ~0U; + size = window_size >> (page_shift - 3); + return size; +} + +static struct pci_dev *iommu_group_get_first_pci_dev(struct iommu_group *group) +{ + struct pci_dev *pdev = NULL; + int ret; + + /* No IOMMU group ? */ + if (!group) + return NULL; + + ret = iommu_group_for_each_dev(group, &pdev, dev_has_iommu_table); + if (!ret || !pdev) + return NULL; + return pdev; +} + +static void restore_default_dma_window(struct pci_dev *pdev, struct device_node *pdn) +{ + reset_dma_window(pdev, pdn); + copy_property(pdn, "ibm,dma-window-saved", "ibm,dma-window"); +} + +static long remove_dynamic_dma_windows(struct pci_dev *pdev, struct device_node *pdn) +{ + struct pci_dn *pci = PCI_DN(pdn); + struct dma_win *window; + bool direct_mapping; + int len; + + if (find_existing_ddw(pdn, &pdev->dev.archdata.dma_offset, &len, &direct_mapping)) { + remove_dma_window_named(pdn, true, direct_mapping ? + DIRECT64_PROPNAME : DMA64_PROPNAME, true); + if (!direct_mapping) { + WARN_ON(!pci->table_group->tables[0] && !pci->table_group->tables[1]); + + if (pci->table_group->tables[1]) { + iommu_tce_table_put(pci->table_group->tables[1]); + pci->table_group->tables[1] = NULL; + } else if (pci->table_group->tables[0]) { + /* Default window was removed and only the DDW exists */ + iommu_tce_table_put(pci->table_group->tables[0]); + pci->table_group->tables[0] = NULL; + } + } + spin_lock(&dma_win_list_lock); + list_for_each_entry(window, &dma_win_list, list) { + if (window->device == pdn) { + list_del(&window->list); + kfree(window); + break; + } + } + spin_unlock(&dma_win_list_lock); + } + + return 0; +} + +static long pseries_setup_default_iommu_config(struct iommu_table_group *table_group, + struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + const __be32 *default_prop; + long liobn, offset, size; + struct device_node *pdn; + struct iommu_table *tbl; + struct pci_dn *pci; + + pdn = pci_dma_find_parent_node(pdev, table_group); + if (!pdn || !PCI_DN(pdn)) { + dev_warn(&pdev->dev, "No table_group configured for the node %pOF\n", pdn); + return -1; + } + pci = PCI_DN(pdn); + + /* The default window is restored if not present already on removal of DDW. + * However, if used by VFIO SPAPR sub driver, the user's order of removal of + * windows might have been different to not leading to auto restoration, + * suppose the DDW was removed first followed by the default one. + * So, restore the default window with reset-pe-dma call explicitly. + */ + restore_default_dma_window(pdev, pdn); + + default_prop = of_get_property(pdn, "ibm,dma-window", NULL); + of_parse_dma_window(pdn, default_prop, &liobn, &offset, &size); + tbl = iommu_pseries_alloc_table(pci->phb->node); + if (!tbl) { + dev_err(&pdev->dev, "couldn't create new IOMMU table\n"); + return -1; + } + + iommu_table_setparms_common(tbl, pci->phb->bus->number, liobn, offset, + size, IOMMU_PAGE_SHIFT_4K, NULL, + &iommu_table_lpar_multi_ops); + iommu_init_table(tbl, pci->phb->node, 0, 0); + + pci->table_group->tables[0] = tbl; + set_iommu_table_base(&pdev->dev, tbl); + + return 0; +} + +static bool is_default_window_request(struct iommu_table_group *table_group, __u32 page_shift, + __u64 window_size) +{ + if ((window_size <= table_group->tce32_size) && + (page_shift == IOMMU_PAGE_SHIFT_4K)) + return true; + + return false; +} + +static long spapr_tce_create_table(struct iommu_table_group *table_group, int num, + __u32 page_shift, __u64 window_size, __u32 levels, + struct iommu_table **ptbl) +{ + struct pci_dev *pdev = iommu_group_get_first_pci_dev(table_group->group); + u32 ddw_avail[DDW_APPLICABLE_SIZE]; + struct ddw_create_response create; + unsigned long liobn, offset, size; + unsigned long start = 0, end = 0; + struct ddw_query_response query; + const __be32 *default_prop; + struct failed_ddw_pdn *fpdn; + unsigned int window_shift; + struct device_node *pdn; + struct iommu_table *tbl; + struct dma_win *window; + struct property *win64; + struct pci_dn *pci; + u64 win_addr; + int len, i; + long ret; + + if (!is_power_of_2(window_size) || levels > 1) + return -EINVAL; + + window_shift = order_base_2(window_size); + + mutex_lock(&dma_win_init_mutex); + + ret = -ENODEV; + + pdn = pci_dma_find_parent_node(pdev, table_group); + if (!pdn || !PCI_DN(pdn)) { /* Niether of 32s|64-bit exist! */ + dev_warn(&pdev->dev, "No dma-windows exist for the node %pOF\n", pdn); + goto out_failed; + } + pci = PCI_DN(pdn); + + /* If the enable DDW failed for the pdn, dont retry! */ + list_for_each_entry(fpdn, &failed_ddw_pdn_list, list) { + if (fpdn->pdn == pdn) { + dev_info(&pdev->dev, "%pOF in failed DDW device list\n", pdn); + goto out_unlock; + } + } + + tbl = iommu_pseries_alloc_table(pci->phb->node); + if (!tbl) { + dev_dbg(&pdev->dev, "couldn't create new IOMMU table\n"); + goto out_unlock; + } + + if (num == 0) { + bool direct_mapping; + /* The request is not for default window? Ensure there is no DDW window already */ + if (!is_default_window_request(table_group, page_shift, window_size)) { + if (find_existing_ddw(pdn, &pdev->dev.archdata.dma_offset, &len, + &direct_mapping)) { + dev_warn(&pdev->dev, "%pOF: 64-bit window already present.", pdn); + ret = -EPERM; + goto out_unlock; + } + } else { + /* Request is for Default window, ensure there is no DDW if there is a + * need to reset. reset-pe otherwise removes the DDW also + */ + default_prop = of_get_property(pdn, "ibm,dma-window", NULL); + if (!default_prop) { + if (find_existing_ddw(pdn, &pdev->dev.archdata.dma_offset, &len, + &direct_mapping)) { + dev_warn(&pdev->dev, "%pOF: Attempt to create window#0 when 64-bit window is present. Preventing the attempt as that would destroy the 64-bit window", + pdn); + ret = -EPERM; + goto out_unlock; + } + + restore_default_dma_window(pdev, pdn); + + default_prop = of_get_property(pdn, "ibm,dma-window", NULL); + of_parse_dma_window(pdn, default_prop, &liobn, &offset, &size); + /* Limit the default window size to window_size */ + iommu_table_setparms_common(tbl, pci->phb->bus->number, liobn, + offset, 1UL << window_shift, + IOMMU_PAGE_SHIFT_4K, NULL, + &iommu_table_lpar_multi_ops); + iommu_init_table(tbl, pci->phb->node, start, end); + + table_group->tables[0] = tbl; + + mutex_unlock(&dma_win_init_mutex); + + goto exit; + } + } + } + + ret = of_property_read_u32_array(pdn, "ibm,ddw-applicable", + &ddw_avail[0], DDW_APPLICABLE_SIZE); + if (ret) { + dev_info(&pdev->dev, "ibm,ddw-applicable not found\n"); + goto out_failed; + } + ret = -ENODEV; + + pr_err("%s: Calling query %pOF\n", __func__, pdn); + ret = query_ddw(pdev, ddw_avail, &query, pdn); + if (ret) + goto out_failed; + ret = -ENODEV; + + len = window_shift; + if (query.largest_available_block < (1ULL << (len - page_shift))) { + dev_dbg(&pdev->dev, "can't map window 0x%llx with %llu %llu-sized pages\n", + 1ULL << len, query.largest_available_block, + 1ULL << page_shift); + ret = -EINVAL; /* Retry with smaller window size */ + goto out_unlock; + } + + if (create_ddw(pdev, ddw_avail, &create, page_shift, len)) { + pr_err("%s: Create ddw failed %pOF\n", __func__, pdn); + goto out_failed; + } + + win_addr = ((u64)create.addr_hi << 32) | create.addr_lo; + win64 = ddw_property_create(DMA64_PROPNAME, create.liobn, win_addr, page_shift, len); + if (!win64) + goto remove_window; + + ret = of_add_property(pdn, win64); + if (ret) { + dev_err(&pdev->dev, "unable to add DMA window property for %pOF: %ld", pdn, ret); + goto free_property; + } + ret = -ENODEV; + + window = ddw_list_new_entry(pdn, win64->value); + if (!window) + goto remove_property; + + window->direct = false; + + for (i = 0; i < ARRAY_SIZE(pci->phb->mem_resources); i++) { + const unsigned long mask = IORESOURCE_MEM_64 | IORESOURCE_MEM; + + /* Look for MMIO32 */ + if ((pci->phb->mem_resources[i].flags & mask) == IORESOURCE_MEM) { + start = pci->phb->mem_resources[i].start; + end = pci->phb->mem_resources[i].end; + break; + } + } + + /* New table for using DDW instead of the default DMA window */ + iommu_table_setparms_common(tbl, pci->phb->bus->number, create.liobn, win_addr, + 1UL << len, page_shift, NULL, &iommu_table_lpar_multi_ops); + iommu_init_table(tbl, pci->phb->node, start, end); + + pci->table_group->tables[num] = tbl; + set_iommu_table_base(&pdev->dev, tbl); + pdev->dev.archdata.dma_offset = win_addr; + + spin_lock(&dma_win_list_lock); + list_add(&window->list, &dma_win_list); + spin_unlock(&dma_win_list_lock); + + mutex_unlock(&dma_win_init_mutex); + + goto exit; + +remove_property: + of_remove_property(pdn, win64); +free_property: + kfree(win64->name); + kfree(win64->value); + kfree(win64); +remove_window: + __remove_dma_window(pdn, ddw_avail, create.liobn); + +out_failed: + fpdn = kzalloc(sizeof(*fpdn), GFP_KERNEL); + if (!fpdn) + goto out_unlock; + fpdn->pdn = pdn; + list_add(&fpdn->list, &failed_ddw_pdn_list); + +out_unlock: + mutex_unlock(&dma_win_init_mutex); + + return ret; +exit: + /* Allocate the userspace view */ + pseries_tce_iommu_userspace_view_alloc(tbl); + tbl->it_allocated_size = spapr_tce_get_table_size(page_shift, window_size, levels); + + *ptbl = iommu_tce_table_get(tbl); + + return 0; +} + +static bool is_default_window_table(struct iommu_table_group *table_group, struct iommu_table *tbl) +{ + if (((tbl->it_size << tbl->it_page_shift) <= table_group->tce32_size) && + (tbl->it_page_shift == IOMMU_PAGE_SHIFT_4K)) + return true; + + return false; +} + +static long spapr_tce_set_window(struct iommu_table_group *table_group, + int num, struct iommu_table *tbl) +{ + return tbl == table_group->tables[num] ? 0 : -EPERM; +} + +static long spapr_tce_unset_window(struct iommu_table_group *table_group, int num) +{ + struct pci_dev *pdev = iommu_group_get_first_pci_dev(table_group->group); + struct device_node *dn = pci_device_to_OF_node(pdev), *pdn; + struct iommu_table *tbl = table_group->tables[num]; + struct failed_ddw_pdn *fpdn; + struct dma_win *window; + const char *win_name; + int ret = -ENODEV; + + mutex_lock(&dma_win_init_mutex); + + if ((num == 0) && is_default_window_table(table_group, tbl)) + win_name = "ibm,dma-window"; + else + win_name = DMA64_PROPNAME; + + pdn = pci_dma_find(dn, NULL); + if (!pdn || !PCI_DN(pdn)) { /* Niether of 32s|64-bit exist! */ + dev_warn(&pdev->dev, "No dma-windows exist for the node %pOF\n", pdn); + goto out_failed; + } + + /* Dont clear the TCEs, User should have done it */ + if (remove_dma_window_named(pdn, true, win_name, false)) { + pr_err("%s: The existing DDW removal failed for node %pOF\n", __func__, pdn); + goto out_failed; /* Could not remove it either! */ + } + + if (strcmp(win_name, DMA64_PROPNAME) == 0) { + spin_lock(&dma_win_list_lock); + list_for_each_entry(window, &dma_win_list, list) { + if (window->device == pdn) { + list_del(&window->list); + kfree(window); + break; + } + } + spin_unlock(&dma_win_list_lock); + } + + iommu_tce_table_put(table_group->tables[num]); + table_group->tables[num] = NULL; + + ret = 0; + + goto out_unlock; + +out_failed: + fpdn = kzalloc(sizeof(*fpdn), GFP_KERNEL); + if (!fpdn) + goto out_unlock; + fpdn->pdn = pdn; + list_add(&fpdn->list, &failed_ddw_pdn_list); + +out_unlock: + mutex_unlock(&dma_win_init_mutex); + + return ret; +} + +static long spapr_tce_take_ownership(struct iommu_table_group *table_group, struct device *dev) +{ + struct iommu_table *tbl = table_group->tables[0]; + struct pci_dev *pdev = to_pci_dev(dev); + struct device_node *dn = pci_device_to_OF_node(pdev); + struct device_node *pdn; + + /* SRIOV VFs using direct map by the host driver OR multifunction devices + * where the ownership was taken on the attempt by the first function + */ + if (!tbl && (table_group->max_dynamic_windows_supported != 1)) + return 0; + + mutex_lock(&dma_win_init_mutex); + + pdn = pci_dma_find(dn, NULL); + if (!pdn || !PCI_DN(pdn)) { /* Niether of 32s|64-bit exist! */ + dev_warn(&pdev->dev, "No dma-windows exist for the node %pOF\n", pdn); + mutex_unlock(&dma_win_init_mutex); + return -1; + } + + /* + * Though rtas call reset-pe removes the DDW, it doesn't clear the entries on the table + * if there are any. In case of direct map, the entries will be left over, which + * is fine for PEs with 2 DMA windows where the second window is created with create-pe + * at which point the table is cleared. However, on VFs having only one DMA window, the + * default window would end up seeing the entries left over from the direct map done + * on the second window. So, remove the ddw explicitly so that clean_dma_window() + * cleans up the entries if any. + */ + if (remove_dynamic_dma_windows(pdev, pdn)) { + dev_warn(&pdev->dev, "The existing DDW removal failed for node %pOF\n", pdn); + mutex_unlock(&dma_win_init_mutex); + return -1; + } + + /* The table_group->tables[0] is not null now, it must be the default window + * Remove it, let the userspace create it as it needs. + */ + if (table_group->tables[0]) { + remove_dma_window_named(pdn, true, "ibm,dma-window", true); + iommu_tce_table_put(tbl); + table_group->tables[0] = NULL; + } + set_iommu_table_base(dev, NULL); + + mutex_unlock(&dma_win_init_mutex); + + return 0; +} + +static void spapr_tce_release_ownership(struct iommu_table_group *table_group, struct device *dev) +{ + struct iommu_table *tbl = table_group->tables[0]; + + if (tbl) { /* Default window already restored */ + return; + } + + mutex_lock(&dma_win_init_mutex); + + /* Restore the default window */ + pseries_setup_default_iommu_config(table_group, dev); + + mutex_unlock(&dma_win_init_mutex); + + return; +} + +static struct iommu_table_group_ops spapr_tce_table_group_ops = { + .get_table_size = spapr_tce_get_table_size, + .create_table = spapr_tce_create_table, + .set_window = spapr_tce_set_window, + .unset_window = spapr_tce_unset_window, + .take_ownership = spapr_tce_take_ownership, + .release_ownership = spapr_tce_release_ownership, +}; +#endif + static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action, void *data) { @@ -1712,8 +2397,8 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti * we have to remove the property when releasing * the device node. */ - if (remove_ddw(np, false, DIRECT64_PROPNAME)) - remove_ddw(np, false, DMA64_PROPNAME); + if (remove_dma_window_named(np, false, DIRECT64_PROPNAME, true)) + remove_dma_window_named(np, false, DMA64_PROPNAME, true); if (pci && pci->table_group) iommu_pseries_free_group(pci->table_group, diff --git a/arch/powerpc/platforms/pseries/papr_scm.c b/arch/powerpc/platforms/pseries/papr_scm.c index 9b6420eb3567..f6a70bc92e83 100644 --- a/arch/powerpc/platforms/pseries/papr_scm.c +++ b/arch/powerpc/platforms/pseries/papr_scm.c @@ -1536,5 +1536,6 @@ static void __exit papr_scm_exit(void) module_exit(papr_scm_exit); MODULE_DEVICE_TABLE(of, papr_scm_match); +MODULE_DESCRIPTION("PAPR Storage Class Memory interface driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("IBM Corporation"); diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 4448386268d9..52e2623a741d 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -21,9 +22,22 @@ struct pci_controller *init_phb_dynamic(struct device_node *dn) { struct pci_controller *phb; + int nid; pr_debug("PCI: Initializing new hotplug PHB %pOF\n", dn); + nid = of_node_to_nid(dn); + if (likely((nid) >= 0)) { + if (!node_online(nid)) { + if (__register_one_node(nid)) { + pr_err("PCI: Failed to register node %d\n", nid); + } else { + update_numa_distance(dn); + node_set_online(nid); + } + } + } + phb = pcibios_alloc_controller(dn); if (!phb) return NULL; diff --git a/arch/powerpc/platforms/pseries/vas.c b/arch/powerpc/platforms/pseries/vas.c index ba3fb7a7f2ea..c25eb1a38185 100644 --- a/arch/powerpc/platforms/pseries/vas.c +++ b/arch/powerpc/platforms/pseries/vas.c @@ -38,7 +38,27 @@ static long hcall_return_busy_check(long rc) { /* Check if we are stalled for some time */ if (H_IS_LONG_BUSY(rc)) { - msleep(get_longbusy_msecs(rc)); + unsigned int ms; + /* + * Allocate, Modify and Deallocate HCALLs returns + * H_LONG_BUSY_ORDER_1_MSEC or H_LONG_BUSY_ORDER_10_MSEC + * for the long delay. So the sleep time should always + * be either 1 or 10msecs, but in case if the HCALL + * returns the long delay > 10 msecs, clamp the sleep + * time to 10msecs. + */ + ms = clamp(get_longbusy_msecs(rc), 1, 10); + + /* + * msleep() will often sleep at least 20 msecs even + * though the hypervisor suggests that the OS reissue + * HCALLs after 1 or 10msecs. Also the delay hint from + * the HCALL is just a suggestion. So OK to pause for + * less time than the hinted delay. Use usleep_range() + * to ensure we don't sleep much longer than actually + * needed. + */ + usleep_range(ms * (USEC_PER_MSEC / 10), ms * USEC_PER_MSEC); rc = H_BUSY; } else if (rc == H_BUSY) { cond_resched(); diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index 5aa92ff3622d..18ff2c4a814a 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -5,12 +5,12 @@ config PPC4xx_PCI_EXPRESS bool - depends on PCI && 4xx + depends on PCI && 44x config PPC4xx_HSTA_MSI bool depends on PCI_MSI - depends on PCI && 4xx + depends on PCI && 44x config PPC_MSI_BITMAP bool diff --git a/arch/powerpc/sysdev/rtc_cmos_setup.c b/arch/powerpc/sysdev/rtc_cmos_setup.c index 47cc87bd6a33..9a232ae5e360 100644 --- a/arch/powerpc/sysdev/rtc_cmos_setup.c +++ b/arch/powerpc/sysdev/rtc_cmos_setup.c @@ -66,4 +66,5 @@ static int __init add_rtc(void) } fs_initcall(add_rtc); +MODULE_DESCRIPTION("PPC RTC CMOS driver"); MODULE_LICENSE("GPL"); diff --git a/arch/powerpc/xmon/ppc-dis.c b/arch/powerpc/xmon/ppc-dis.c index 75fa98221d48..af105e1bc3fc 100644 --- a/arch/powerpc/xmon/ppc-dis.c +++ b/arch/powerpc/xmon/ppc-dis.c @@ -122,32 +122,21 @@ int print_insn_powerpc (unsigned long insn, unsigned long memaddr) bool insn_is_short; ppc_cpu_t dialect; - dialect = PPC_OPCODE_PPC | PPC_OPCODE_COMMON - | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_ALTIVEC; + dialect = PPC_OPCODE_PPC | PPC_OPCODE_COMMON; - if (cpu_has_feature(CPU_FTRS_POWER5)) - dialect |= PPC_OPCODE_POWER5; + if (IS_ENABLED(CONFIG_PPC64)) + dialect |= PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_CELL | + PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | + PPC_OPCODE_POWER9; - if (cpu_has_feature(CPU_FTRS_CELL)) - dialect |= (PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC); + if (cpu_has_feature(CPU_FTR_TM)) + dialect |= PPC_OPCODE_HTM; - if (cpu_has_feature(CPU_FTRS_POWER6)) - dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC); + if (cpu_has_feature(CPU_FTR_ALTIVEC)) + dialect |= PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2; - if (cpu_has_feature(CPU_FTRS_POWER7)) - dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 - | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX); - - if (cpu_has_feature(CPU_FTRS_POWER8)) - dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 - | PPC_OPCODE_POWER8 | PPC_OPCODE_HTM - | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX); - - if (cpu_has_feature(CPU_FTRS_POWER9)) - dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 - | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 | PPC_OPCODE_HTM - | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 - | PPC_OPCODE_VSX | PPC_OPCODE_VSX3); + if (cpu_has_feature(CPU_FTR_VSX)) + dialect |= PPC_OPCODE_VSX | PPC_OPCODE_VSX3; /* Get the major opcode of the insn. */ opcode = NULL; diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 9f38a5ecbee3..736457a5898a 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -16,6 +16,8 @@ config RISCV select ACPI_REDUCED_HARDWARE_ONLY if ACPI select ARCH_DMA_DEFAULT_COHERENT select ARCH_ENABLE_HUGEPAGE_MIGRATION if HUGETLB_PAGE && MIGRATION + select ARCH_ENABLE_MEMORY_HOTPLUG if SPARSEMEM_VMEMMAP + select ARCH_ENABLE_MEMORY_HOTREMOVE if MEMORY_HOTPLUG select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2 select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE select ARCH_HAS_BINFMT_FLAT @@ -35,6 +37,7 @@ config RISCV select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE select ARCH_HAS_PMEM_API select ARCH_HAS_PREPARE_SYNC_CORE_CMD + select ARCH_HAS_PTE_DEVMAP if 64BIT && MMU select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_SET_DIRECT_MAP if MMU select ARCH_HAS_SET_MEMORY if MMU @@ -46,6 +49,7 @@ config RISCV select ARCH_HAS_UBSAN select ARCH_HAS_VDSO_DATA select ARCH_KEEP_MEMBLOCK if ACPI + select ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE if 64BIT && MMU select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT select ARCH_STACKWALK @@ -69,6 +73,7 @@ config RISCV select ARCH_WANT_GENERAL_HUGETLB if !RISCV_ISA_SVNAPOT select ARCH_WANT_HUGE_PMD_SHARE if 64BIT select ARCH_WANT_LD_ORPHAN_WARN if !XIP_KERNEL + select ARCH_WANT_OPTIMIZE_DAX_VMEMMAP select ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP select ARCH_WANTS_NO_INSTR select ARCH_WANTS_THP_SWAP if HAVE_ARCH_TRANSPARENT_HUGEPAGE @@ -595,6 +600,19 @@ config RISCV_ISA_V_PREEMPTIVE preemption. Enabling this config will result in higher memory consumption due to the allocation of per-task's kernel Vector context. +config RISCV_ISA_ZAWRS + bool "Zawrs extension support for more efficient busy waiting" + depends on RISCV_ALTERNATIVE + default y + help + The Zawrs extension defines instructions to be used in polling loops + which allow a hart to enter a low-power state or to trap to the + hypervisor while waiting on a store to a memory location. Enable the + use of these instructions in the kernel when the Zawrs extension is + detected at boot. + + If you don't know what to do here, say Y. + config TOOLCHAIN_HAS_ZBB bool default y @@ -637,6 +655,29 @@ config RISCV_ISA_ZBB If you don't know what to do here, say Y. +config TOOLCHAIN_HAS_ZBC + bool + default y + depends on !64BIT || $(cc-option,-mabi=lp64 -march=rv64ima_zbc) + depends on !32BIT || $(cc-option,-mabi=ilp32 -march=rv32ima_zbc) + depends on LLD_VERSION >= 150000 || LD_VERSION >= 23900 + depends on AS_HAS_OPTION_ARCH + +config RISCV_ISA_ZBC + bool "Zbc extension support for carry-less multiplication instructions" + depends on TOOLCHAIN_HAS_ZBC + depends on MMU + depends on RISCV_ALTERNATIVE + default y + help + Adds support to dynamically detect the presence of the Zbc + extension (carry-less multiplication) and enable its usage. + + The Zbc extension could accelerate CRC (cyclic redundancy check) + calculations. + + If you don't know what to do here, say Y. + config RISCV_ISA_ZICBOM bool "Zicbom extension support for non-coherent DMA operation" depends on MMU @@ -666,13 +707,6 @@ config RISCV_ISA_ZICBOZ If you don't know what to do here, say Y. -config TOOLCHAIN_HAS_ZIHINTPAUSE - bool - default y - depends on !64BIT || $(cc-option,-mabi=lp64 -march=rv64ima_zihintpause) - depends on !32BIT || $(cc-option,-mabi=ilp32 -march=rv32ima_zihintpause) - depends on LLD_VERSION >= 150000 || LD_VERSION >= 23600 - config TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI def_bool y # https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=aed44286efa8ae8717a77d94b51ac3614e2ca6dc @@ -979,6 +1013,17 @@ config EFI allow the kernel to be booted as an EFI application. This is only useful on systems that have UEFI firmware. +config DMI + bool "Enable support for SMBIOS (DMI) tables" + depends on EFI + default y + help + This enables SMBIOS/DMI feature for systems. + + This option is only useful on systems that have UEFI firmware. + However, even with this option, the resultant kernel should + continue to boot on existing non-UEFI platforms. + config CC_HAVE_STACKPROTECTOR_TLS def_bool $(cc-option,-mstack-protector-guard=tls -mstack-protector-guard-reg=tp -mstack-protector-guard-offset=0) diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 06de9d365088..6fe682139d2e 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -82,9 +82,6 @@ else riscv-march-$(CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI) := $(riscv-march-y)_zicsr_zifencei endif -# Check if the toolchain supports Zihintpause extension -riscv-march-$(CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE) := $(riscv-march-y)_zihintpause - # Remove F,D,V from isa string for all. Keep extensions between "fd" and "v" by # matching non-v and non-multi-letter extensions out with the filter ([^v_]*) KBUILD_CFLAGS += -march=$(shell echo $(riscv-march-y) | sed -E 's/(rv32ima|rv64ima)fd([^v_]*)v?/\1\2/') diff --git a/arch/riscv/include/asm/arch_hweight.h b/arch/riscv/include/asm/arch_hweight.h index 85b2c443823e..613769b9cdc9 100644 --- a/arch/riscv/include/asm/arch_hweight.h +++ b/arch/riscv/include/asm/arch_hweight.h @@ -26,9 +26,9 @@ static __always_inline unsigned int __arch_hweight32(unsigned int w) asm (".option push\n" ".option arch,+zbb\n" - CPOPW "%0, %0\n" + CPOPW "%0, %1\n" ".option pop\n" - : "+r" (w) : :); + : "=r" (w) : "r" (w) :); return w; @@ -57,9 +57,9 @@ static __always_inline unsigned long __arch_hweight64(__u64 w) asm (".option push\n" ".option arch,+zbb\n" - "cpop %0, %0\n" + "cpop %0, %1\n" ".option pop\n" - : "+r" (w) : :); + : "=r" (w) : "r" (w) :); return w; diff --git a/arch/riscv/include/asm/barrier.h b/arch/riscv/include/asm/barrier.h index 880b56d8480d..e1d9bf1deca6 100644 --- a/arch/riscv/include/asm/barrier.h +++ b/arch/riscv/include/asm/barrier.h @@ -11,6 +11,7 @@ #define _ASM_RISCV_BARRIER_H #ifndef __ASSEMBLY__ +#include #include #define nop() __asm__ __volatile__ ("nop") @@ -28,21 +29,6 @@ #define __smp_rmb() RISCV_FENCE(r, r) #define __smp_wmb() RISCV_FENCE(w, w) -#define __smp_store_release(p, v) \ -do { \ - compiletime_assert_atomic_type(*p); \ - RISCV_FENCE(rw, w); \ - WRITE_ONCE(*p, v); \ -} while (0) - -#define __smp_load_acquire(p) \ -({ \ - typeof(*p) ___p1 = READ_ONCE(*p); \ - compiletime_assert_atomic_type(*p); \ - RISCV_FENCE(r, rw); \ - ___p1; \ -}) - /* * This is a very specific barrier: it's currently only used in two places in * the kernel, both in the scheduler. See include/linux/spinlock.h for the two @@ -70,6 +56,35 @@ do { \ */ #define smp_mb__after_spinlock() RISCV_FENCE(iorw, iorw) +#define __smp_store_release(p, v) \ +do { \ + compiletime_assert_atomic_type(*p); \ + RISCV_FENCE(rw, w); \ + WRITE_ONCE(*p, v); \ +} while (0) + +#define __smp_load_acquire(p) \ +({ \ + typeof(*p) ___p1 = READ_ONCE(*p); \ + compiletime_assert_atomic_type(*p); \ + RISCV_FENCE(r, rw); \ + ___p1; \ +}) + +#ifdef CONFIG_RISCV_ISA_ZAWRS +#define smp_cond_load_relaxed(ptr, cond_expr) ({ \ + typeof(ptr) __PTR = (ptr); \ + __unqual_scalar_typeof(*ptr) VAL; \ + for (;;) { \ + VAL = READ_ONCE(*__PTR); \ + if (cond_expr) \ + break; \ + __cmpwait_relaxed(ptr, VAL); \ + } \ + (typeof(*ptr))VAL; \ +}) +#endif + #include #endif /* __ASSEMBLY__ */ diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h index 808b4c78462e..ebbce134917c 100644 --- a/arch/riscv/include/asm/cmpxchg.h +++ b/arch/riscv/include/asm/cmpxchg.h @@ -8,7 +8,10 @@ #include +#include #include +#include +#include #define __arch_xchg_masked(sc_sfx, prepend, append, r, p, n) \ ({ \ @@ -223,4 +226,59 @@ arch_cmpxchg_release((ptr), (o), (n)); \ }) +#ifdef CONFIG_RISCV_ISA_ZAWRS +/* + * Despite wrs.nto being "WRS-with-no-timeout", in the absence of changes to + * @val we expect it to still terminate within a "reasonable" amount of time + * for an implementation-specific other reason, a pending, locally-enabled + * interrupt, or because it has been configured to raise an illegal + * instruction exception. + */ +static __always_inline void __cmpwait(volatile void *ptr, + unsigned long val, + int size) +{ + unsigned long tmp; + + asm goto(ALTERNATIVE("j %l[no_zawrs]", "nop", + 0, RISCV_ISA_EXT_ZAWRS, 1) + : : : : no_zawrs); + + switch (size) { + case 4: + asm volatile( + " lr.w %0, %1\n" + " xor %0, %0, %2\n" + " bnez %0, 1f\n" + ZAWRS_WRS_NTO "\n" + "1:" + : "=&r" (tmp), "+A" (*(u32 *)ptr) + : "r" (val)); + break; +#if __riscv_xlen == 64 + case 8: + asm volatile( + " lr.d %0, %1\n" + " xor %0, %0, %2\n" + " bnez %0, 1f\n" + ZAWRS_WRS_NTO "\n" + "1:" + : "=&r" (tmp), "+A" (*(u64 *)ptr) + : "r" (val)); + break; +#endif + default: + BUILD_BUG(); + } + + return; + +no_zawrs: + asm volatile(RISCV_PAUSE : : : "memory"); +} + +#define __cmpwait_relaxed(ptr, val) \ + __cmpwait((ptr), (unsigned long)(val), sizeof(*(ptr))) +#endif + #endif /* _ASM_RISCV_CMPXCHG_H */ diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h index 347805446151..000796c2d0b1 100644 --- a/arch/riscv/include/asm/cpufeature.h +++ b/arch/riscv/include/asm/cpufeature.h @@ -70,6 +70,7 @@ struct riscv_isa_ext_data { const char *property; const unsigned int *subset_ext_ids; const unsigned int subset_ext_size; + int (*validate)(const struct riscv_isa_ext_data *data, const unsigned long *isa_bitmap); }; extern const struct riscv_isa_ext_data riscv_isa_ext[]; diff --git a/arch/riscv/include/asm/dmi.h b/arch/riscv/include/asm/dmi.h new file mode 100644 index 000000000000..ca7cce557ef7 --- /dev/null +++ b/arch/riscv/include/asm/dmi.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024 Intel Corporation + * + * based on arch/arm64/include/asm/dmi.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef __ASM_DMI_H +#define __ASM_DMI_H + +#include +#include + +#define dmi_early_remap(x, l) memremap(x, l, MEMREMAP_WB) +#define dmi_early_unmap(x, l) memunmap(x) +#define dmi_remap(x, l) memremap(x, l, MEMREMAP_WB) +#define dmi_unmap(x) memunmap(x) +#define dmi_alloc(l) kzalloc(l, GFP_KERNEL) + +#endif diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index e17d0078a651..b18b202ca141 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -81,6 +81,18 @@ #define RISCV_ISA_EXT_ZTSO 72 #define RISCV_ISA_EXT_ZACAS 73 #define RISCV_ISA_EXT_XANDESPMU 74 +#define RISCV_ISA_EXT_ZVE32X 75 +#define RISCV_ISA_EXT_ZVE32F 76 +#define RISCV_ISA_EXT_ZVE64X 77 +#define RISCV_ISA_EXT_ZVE64F 78 +#define RISCV_ISA_EXT_ZVE64D 79 +#define RISCV_ISA_EXT_ZIMOP 80 +#define RISCV_ISA_EXT_ZCA 81 +#define RISCV_ISA_EXT_ZCB 82 +#define RISCV_ISA_EXT_ZCD 83 +#define RISCV_ISA_EXT_ZCF 84 +#define RISCV_ISA_EXT_ZCMOP 85 +#define RISCV_ISA_EXT_ZAWRS 86 #define RISCV_ISA_EXT_XLINUXENVCFG 127 diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h index 630507dff5ea..150a9877b0af 100644 --- a/arch/riscv/include/asm/hwprobe.h +++ b/arch/riscv/include/asm/hwprobe.h @@ -8,7 +8,7 @@ #include -#define RISCV_HWPROBE_MAX_KEY 6 +#define RISCV_HWPROBE_MAX_KEY 7 static inline bool riscv_hwprobe_key_is_valid(__s64 key) { diff --git a/arch/riscv/include/asm/insn-def.h b/arch/riscv/include/asm/insn-def.h index e27179b26086..9a913010cdd9 100644 --- a/arch/riscv/include/asm/insn-def.h +++ b/arch/riscv/include/asm/insn-def.h @@ -196,4 +196,8 @@ INSN_I(OPCODE_MISC_MEM, FUNC3(2), __RD(0), \ RS1(base), SIMM12(4)) +#define RISCV_PAUSE ".4byte 0x100000f" +#define ZAWRS_WRS_NTO ".4byte 0x00d00073" +#define ZAWRS_WRS_STO ".4byte 0x01d00073" + #endif /* __ASM_INSN_DEF_H */ diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h index 4a35d787c019..1c768d02bd0c 100644 --- a/arch/riscv/include/asm/jump_label.h +++ b/arch/riscv/include/asm/jump_label.h @@ -12,6 +12,8 @@ #include #include +#define HAVE_JUMP_LABEL_BATCH + #define JUMP_LABEL_NOP_SIZE 4 static __always_inline bool arch_static_branch(struct static_key * const key, @@ -44,7 +46,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key * const ke " .option push \n\t" " .option norelax \n\t" " .option norvc \n\t" - "1: jal zero, %l[label] \n\t" + "1: j %l[label] \n\t" " .option pop \n\t" " .pushsection __jump_table, \"aw\" \n\t" " .align " RISCV_LGPTR " \n\t" diff --git a/arch/riscv/include/asm/kasan.h b/arch/riscv/include/asm/kasan.h index 0b85e363e778..e6a0071bdb56 100644 --- a/arch/riscv/include/asm/kasan.h +++ b/arch/riscv/include/asm/kasan.h @@ -6,8 +6,6 @@ #ifndef __ASSEMBLY__ -#ifdef CONFIG_KASAN - /* * The following comment was copied from arm64: * KASAN_SHADOW_START: beginning of the kernel virtual addresses. @@ -34,6 +32,8 @@ */ #define KASAN_SHADOW_START ((KASAN_SHADOW_END - KASAN_SHADOW_SIZE) & PGDIR_MASK) #define KASAN_SHADOW_END MODULES_LOWEST_VADDR + +#ifdef CONFIG_KASAN #define KASAN_SHADOW_OFFSET _AC(CONFIG_KASAN_SHADOW_OFFSET, UL) void kasan_init(void); diff --git a/arch/riscv/include/asm/kvm_aia_aplic.h b/arch/riscv/include/asm/kvm_aia_aplic.h deleted file mode 100644 index 6dd1a4809ec1..000000000000 --- a/arch/riscv/include/asm/kvm_aia_aplic.h +++ /dev/null @@ -1,58 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2021 Western Digital Corporation or its affiliates. - * Copyright (C) 2022 Ventana Micro Systems Inc. - */ -#ifndef __KVM_RISCV_AIA_IMSIC_H -#define __KVM_RISCV_AIA_IMSIC_H - -#include - -#define APLIC_MAX_IDC BIT(14) -#define APLIC_MAX_SOURCE 1024 - -#define APLIC_DOMAINCFG 0x0000 -#define APLIC_DOMAINCFG_RDONLY 0x80000000 -#define APLIC_DOMAINCFG_IE BIT(8) -#define APLIC_DOMAINCFG_DM BIT(2) -#define APLIC_DOMAINCFG_BE BIT(0) - -#define APLIC_SOURCECFG_BASE 0x0004 -#define APLIC_SOURCECFG_D BIT(10) -#define APLIC_SOURCECFG_CHILDIDX_MASK 0x000003ff -#define APLIC_SOURCECFG_SM_MASK 0x00000007 -#define APLIC_SOURCECFG_SM_INACTIVE 0x0 -#define APLIC_SOURCECFG_SM_DETACH 0x1 -#define APLIC_SOURCECFG_SM_EDGE_RISE 0x4 -#define APLIC_SOURCECFG_SM_EDGE_FALL 0x5 -#define APLIC_SOURCECFG_SM_LEVEL_HIGH 0x6 -#define APLIC_SOURCECFG_SM_LEVEL_LOW 0x7 - -#define APLIC_IRQBITS_PER_REG 32 - -#define APLIC_SETIP_BASE 0x1c00 -#define APLIC_SETIPNUM 0x1cdc - -#define APLIC_CLRIP_BASE 0x1d00 -#define APLIC_CLRIPNUM 0x1ddc - -#define APLIC_SETIE_BASE 0x1e00 -#define APLIC_SETIENUM 0x1edc - -#define APLIC_CLRIE_BASE 0x1f00 -#define APLIC_CLRIENUM 0x1fdc - -#define APLIC_SETIPNUM_LE 0x2000 -#define APLIC_SETIPNUM_BE 0x2004 - -#define APLIC_GENMSI 0x3000 - -#define APLIC_TARGET_BASE 0x3004 -#define APLIC_TARGET_HART_IDX_SHIFT 18 -#define APLIC_TARGET_HART_IDX_MASK 0x3fff -#define APLIC_TARGET_GUEST_IDX_SHIFT 12 -#define APLIC_TARGET_GUEST_IDX_MASK 0x3f -#define APLIC_TARGET_IPRIO_MASK 0xff -#define APLIC_TARGET_EIID_MASK 0x7ff - -#endif diff --git a/arch/riscv/include/asm/kvm_aia_imsic.h b/arch/riscv/include/asm/kvm_aia_imsic.h deleted file mode 100644 index da5881d2bde0..000000000000 --- a/arch/riscv/include/asm/kvm_aia_imsic.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2021 Western Digital Corporation or its affiliates. - * Copyright (C) 2022 Ventana Micro Systems Inc. - */ -#ifndef __KVM_RISCV_AIA_IMSIC_H -#define __KVM_RISCV_AIA_IMSIC_H - -#include -#include - -#define IMSIC_MMIO_PAGE_SHIFT 12 -#define IMSIC_MMIO_PAGE_SZ (1UL << IMSIC_MMIO_PAGE_SHIFT) -#define IMSIC_MMIO_PAGE_LE 0x00 -#define IMSIC_MMIO_PAGE_BE 0x04 - -#define IMSIC_MIN_ID 63 -#define IMSIC_MAX_ID 2048 - -#define IMSIC_EIDELIVERY 0x70 - -#define IMSIC_EITHRESHOLD 0x72 - -#define IMSIC_EIP0 0x80 -#define IMSIC_EIP63 0xbf -#define IMSIC_EIPx_BITS 32 - -#define IMSIC_EIE0 0xc0 -#define IMSIC_EIE63 0xff -#define IMSIC_EIEx_BITS 32 - -#define IMSIC_FIRST IMSIC_EIDELIVERY -#define IMSIC_LAST IMSIC_EIE63 - -#define IMSIC_MMIO_SETIPNUM_LE 0x00 -#define IMSIC_MMIO_SETIPNUM_BE 0x04 - -#endif diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index d96281278586..2e2254fd2a2a 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -80,6 +80,7 @@ struct kvm_vcpu_stat { struct kvm_vcpu_stat_generic generic; u64 ecall_exit_stat; u64 wfi_exit_stat; + u64 wrs_exit_stat; u64 mmio_exit_user; u64 mmio_exit_kernel; u64 csr_exit_user; @@ -286,7 +287,6 @@ struct kvm_vcpu_arch { }; static inline void kvm_arch_sync_events(struct kvm *kvm) {} -static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} #define KVM_RISCV_GSTAGE_TLB_MIN_ORDER 12 diff --git a/arch/riscv/include/asm/mmu.h b/arch/riscv/include/asm/mmu.h index 947fd60f9051..c9e03e9da3dc 100644 --- a/arch/riscv/include/asm/mmu.h +++ b/arch/riscv/include/asm/mmu.h @@ -31,8 +31,8 @@ typedef struct { #define cntx2asid(cntx) ((cntx) & SATP_ASID_MASK) #define cntx2version(cntx) ((cntx) & ~SATP_ASID_MASK) -void __init create_pgd_mapping(pgd_t *pgdp, uintptr_t va, phys_addr_t pa, - phys_addr_t sz, pgprot_t prot); +void __meminit create_pgd_mapping(pgd_t *pgdp, uintptr_t va, phys_addr_t pa, phys_addr_t sz, + pgprot_t prot); #endif /* __ASSEMBLY__ */ #endif /* _ASM_RISCV_MMU_H */ diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h index 115ac98b8d72..235fd45d998d 100644 --- a/arch/riscv/include/asm/page.h +++ b/arch/riscv/include/asm/page.h @@ -188,6 +188,11 @@ extern phys_addr_t __phys_addr_symbol(unsigned long x); unsigned long kaslr_offset(void); +static __always_inline void *pfn_to_kaddr(unsigned long pfn) +{ + return __va(pfn << PAGE_SHIFT); +} + #endif /* __ASSEMBLY__ */ #define virt_addr_valid(vaddr) ({ \ diff --git a/arch/riscv/include/asm/patch.h b/arch/riscv/include/asm/patch.h index 9f5d6e14c405..7228e266b9a1 100644 --- a/arch/riscv/include/asm/patch.h +++ b/arch/riscv/include/asm/patch.h @@ -9,7 +9,7 @@ int patch_insn_write(void *addr, const void *insn, size_t len); int patch_text_nosync(void *addr, const void *insns, size_t len); int patch_text_set_nosync(void *addr, u8 c, size_t len); -int patch_text(void *addr, u32 *insns, int ninsns); +int patch_text(void *addr, u32 *insns, size_t len); extern int riscv_patch_in_stop_machine; diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h index 8c36a8818432..0897dd99ab8d 100644 --- a/arch/riscv/include/asm/pgtable-64.h +++ b/arch/riscv/include/asm/pgtable-64.h @@ -398,4 +398,24 @@ static inline struct page *pgd_page(pgd_t pgd) #define p4d_offset p4d_offset p4d_t *p4d_offset(pgd_t *pgd, unsigned long address); +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +static inline int pte_devmap(pte_t pte); +static inline pte_t pmd_pte(pmd_t pmd); + +static inline int pmd_devmap(pmd_t pmd) +{ + return pte_devmap(pmd_pte(pmd)); +} + +static inline int pud_devmap(pud_t pud) +{ + return 0; +} + +static inline int pgd_devmap(pgd_t pgd) +{ + return 0; +} +#endif + #endif /* _ASM_RISCV_PGTABLE_64_H */ diff --git a/arch/riscv/include/asm/pgtable-bits.h b/arch/riscv/include/asm/pgtable-bits.h index 179bd4afece4..a8f5205cea54 100644 --- a/arch/riscv/include/asm/pgtable-bits.h +++ b/arch/riscv/include/asm/pgtable-bits.h @@ -19,6 +19,7 @@ #define _PAGE_SOFT (3 << 8) /* Reserved for software */ #define _PAGE_SPECIAL (1 << 8) /* RSW: 0x1 */ +#define _PAGE_DEVMAP (1 << 9) /* RSW, devmap */ #define _PAGE_TABLE _PAGE_PRESENT /* diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index aad8b8ca51f1..ab7a759e1a8c 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -165,7 +165,7 @@ struct pt_alloc_ops { #endif }; -extern struct pt_alloc_ops pt_ops __initdata; +extern struct pt_alloc_ops pt_ops __meminitdata; #ifdef CONFIG_MMU /* Number of PGD entries that a user-mode program can use */ @@ -350,6 +350,19 @@ static inline int pte_present(pte_t pte) return (pte_val(pte) & (_PAGE_PRESENT | _PAGE_PROT_NONE)); } +#define pte_accessible pte_accessible +static inline unsigned long pte_accessible(struct mm_struct *mm, pte_t a) +{ + if (pte_val(a) & _PAGE_PRESENT) + return true; + + if ((pte_val(a) & _PAGE_PROT_NONE) && + atomic_read(&mm->tlb_flush_pending)) + return true; + + return false; +} + static inline int pte_none(pte_t pte) { return (pte_val(pte) == 0); @@ -390,6 +403,13 @@ static inline int pte_special(pte_t pte) return pte_val(pte) & _PAGE_SPECIAL; } +#ifdef CONFIG_ARCH_HAS_PTE_DEVMAP +static inline int pte_devmap(pte_t pte) +{ + return pte_val(pte) & _PAGE_DEVMAP; +} +#endif + /* static inline pte_t pte_rdprotect(pte_t pte) */ static inline pte_t pte_wrprotect(pte_t pte) @@ -431,6 +451,11 @@ static inline pte_t pte_mkspecial(pte_t pte) return __pte(pte_val(pte) | _PAGE_SPECIAL); } +static inline pte_t pte_mkdevmap(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_DEVMAP); +} + static inline pte_t pte_mkhuge(pte_t pte) { return pte; @@ -721,6 +746,11 @@ static inline pmd_t pmd_mkdirty(pmd_t pmd) return pte_pmd(pte_mkdirty(pmd_pte(pmd))); } +static inline pmd_t pmd_mkdevmap(pmd_t pmd) +{ + return pte_pmd(pte_mkdevmap(pmd_pte(pmd))); +} + static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pmd_t pmd) { diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index 68c3432dc6ea..8702b8721a27 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -57,6 +57,12 @@ #define STACK_TOP DEFAULT_MAP_WINDOW +#ifdef CONFIG_MMU +#define user_max_virt_addr() arch_get_mmap_end(ULONG_MAX, 0, 0) +#else +#define user_max_virt_addr() 0 +#endif /* CONFIG_MMU */ + /* * This decides where the kernel will search for a free chunk of vm * space during mmap's. diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 1079e214fe85..7cffd4ffecd0 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -304,10 +304,12 @@ struct sbiret { }; void sbi_init(void); -struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, - unsigned long arg1, unsigned long arg2, - unsigned long arg3, unsigned long arg4, - unsigned long arg5); +struct sbiret __sbi_ecall(unsigned long arg0, unsigned long arg1, + unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5, + int fid, int ext); +#define sbi_ecall(e, f, a0, a1, a2, a3, a4, a5) \ + __sbi_ecall(a0, a1, a2, a3, a4, a5, f, e) #ifdef CONFIG_RISCV_SBI_V01 void sbi_console_putchar(int ch); diff --git a/arch/riscv/include/asm/trace.h b/arch/riscv/include/asm/trace.h new file mode 100644 index 000000000000..6151cee5450c --- /dev/null +++ b/arch/riscv/include/asm/trace.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM riscv + +#if !defined(_TRACE_RISCV_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_RISCV_H + +#include + +TRACE_EVENT_CONDITION(sbi_call, + TP_PROTO(int ext, int fid), + TP_ARGS(ext, fid), + TP_CONDITION(ext != SBI_EXT_HSM), + + TP_STRUCT__entry( + __field(int, ext) + __field(int, fid) + ), + + TP_fast_assign( + __entry->ext = ext; + __entry->fid = fid; + ), + + TP_printk("ext=0x%x fid=%d", __entry->ext, __entry->fid) +); + +TRACE_EVENT_CONDITION(sbi_return, + TP_PROTO(int ext, long error, long value), + TP_ARGS(ext, error, value), + TP_CONDITION(ext != SBI_EXT_HSM), + + TP_STRUCT__entry( + __field(long, error) + __field(long, value) + ), + + TP_fast_assign( + __entry->error = error; + __entry->value = value; + ), + + TP_printk("error=%ld value=0x%lx", __entry->error, __entry->value) +); + +#endif /* _TRACE_RISCV_H */ + +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE + +#define TRACE_INCLUDE_PATH asm +#define TRACE_INCLUDE_FILE trace + +#include diff --git a/arch/riscv/include/asm/vdso/processor.h b/arch/riscv/include/asm/vdso/processor.h index 96b65a5396df..8f383f05a290 100644 --- a/arch/riscv/include/asm/vdso/processor.h +++ b/arch/riscv/include/asm/vdso/processor.h @@ -5,6 +5,7 @@ #ifndef __ASSEMBLY__ #include +#include static inline void cpu_relax(void) { @@ -14,16 +15,11 @@ static inline void cpu_relax(void) __asm__ __volatile__ ("div %0, %0, zero" : "=r" (dummy)); #endif -#ifdef CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE /* * Reduce instruction retirement. * This assumes the PC changes. */ - __asm__ __volatile__ ("pause"); -#else - /* Encoding of the pause instruction */ - __asm__ __volatile__ (".4byte 0x100000F"); -#endif + __asm__ __volatile__ (RISCV_PAUSE); barrier(); } diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h index 731dcd0ed4de..be7d309cca8a 100644 --- a/arch/riscv/include/asm/vector.h +++ b/arch/riscv/include/asm/vector.h @@ -37,7 +37,7 @@ static inline u32 riscv_v_flags(void) static __always_inline bool has_vector(void) { - return riscv_has_extension_unlikely(RISCV_ISA_EXT_v); + return riscv_has_extension_unlikely(RISCV_ISA_EXT_ZVE32X); } static inline void __riscv_v_vstate_clean(struct pt_regs *regs) @@ -91,7 +91,7 @@ static __always_inline void __vstate_csr_restore(struct __riscv_v_ext_state *src { asm volatile ( ".option push\n\t" - ".option arch, +v\n\t" + ".option arch, +zve32x\n\t" "vsetvl x0, %2, %1\n\t" ".option pop\n\t" "csrw " __stringify(CSR_VSTART) ", %0\n\t" @@ -109,7 +109,7 @@ static inline void __riscv_v_vstate_save(struct __riscv_v_ext_state *save_to, __vstate_csr_save(save_to); asm volatile ( ".option push\n\t" - ".option arch, +v\n\t" + ".option arch, +zve32x\n\t" "vsetvli %0, x0, e8, m8, ta, ma\n\t" "vse8.v v0, (%1)\n\t" "add %1, %1, %0\n\t" @@ -131,7 +131,7 @@ static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_ riscv_v_enable(); asm volatile ( ".option push\n\t" - ".option arch, +v\n\t" + ".option arch, +zve32x\n\t" "vsetvli %0, x0, e8, m8, ta, ma\n\t" "vle8.v v0, (%1)\n\t" "add %1, %1, %0\n\t" @@ -153,7 +153,7 @@ static inline void __riscv_v_vstate_discard(void) riscv_v_enable(); asm volatile ( ".option push\n\t" - ".option arch, +v\n\t" + ".option arch, +zve32x\n\t" "vsetvli %0, x0, e8, m8, ta, ma\n\t" "vmv.v.i v0, -1\n\t" "vmv.v.i v8, -1\n\t" diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h index dda76a05420b..8b8f6ac0eae2 100644 --- a/arch/riscv/include/uapi/asm/hwprobe.h +++ b/arch/riscv/include/uapi/asm/hwprobe.h @@ -60,6 +60,18 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34) #define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35) #define RISCV_HWPROBE_EXT_ZIHINTPAUSE (1ULL << 36) +#define RISCV_HWPROBE_EXT_ZVE32X (1ULL << 37) +#define RISCV_HWPROBE_EXT_ZVE32F (1ULL << 38) +#define RISCV_HWPROBE_EXT_ZVE64X (1ULL << 39) +#define RISCV_HWPROBE_EXT_ZVE64F (1ULL << 40) +#define RISCV_HWPROBE_EXT_ZVE64D (1ULL << 41) +#define RISCV_HWPROBE_EXT_ZIMOP (1ULL << 42) +#define RISCV_HWPROBE_EXT_ZCA (1ULL << 43) +#define RISCV_HWPROBE_EXT_ZCB (1ULL << 44) +#define RISCV_HWPROBE_EXT_ZCD (1ULL << 45) +#define RISCV_HWPROBE_EXT_ZCF (1ULL << 46) +#define RISCV_HWPROBE_EXT_ZCMOP (1ULL << 47) +#define RISCV_HWPROBE_EXT_ZAWRS (1ULL << 48) #define RISCV_HWPROBE_KEY_CPUPERF_0 5 #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) #define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) @@ -68,6 +80,7 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) #define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) #define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 +#define RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS 7 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */ /* Flags */ diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index e878e7cc3978..e97db3296456 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -168,6 +168,13 @@ enum KVM_RISCV_ISA_EXT_ID { KVM_RISCV_ISA_EXT_ZTSO, KVM_RISCV_ISA_EXT_ZACAS, KVM_RISCV_ISA_EXT_SSCOFPMF, + KVM_RISCV_ISA_EXT_ZIMOP, + KVM_RISCV_ISA_EXT_ZCA, + KVM_RISCV_ISA_EXT_ZCB, + KVM_RISCV_ISA_EXT_ZCD, + KVM_RISCV_ISA_EXT_ZCF, + KVM_RISCV_ISA_EXT_ZCMOP, + KVM_RISCV_ISA_EXT_ZAWRS, KVM_RISCV_ISA_EXT_MAX, }; diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 5ef48cb20ee1..0366dc3baf33 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -72,51 +72,89 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned i } EXPORT_SYMBOL_GPL(__riscv_isa_extension_available); -static bool riscv_isa_extension_check(int id) +static int riscv_ext_zicbom_validate(const struct riscv_isa_ext_data *data, + const unsigned long *isa_bitmap) { - switch (id) { - case RISCV_ISA_EXT_ZICBOM: - if (!riscv_cbom_block_size) { - pr_err("Zicbom detected in ISA string, disabling as no cbom-block-size found\n"); - return false; - } else if (!is_power_of_2(riscv_cbom_block_size)) { - pr_err("Zicbom disabled as cbom-block-size present, but is not a power-of-2\n"); - return false; - } - return true; - case RISCV_ISA_EXT_ZICBOZ: - if (!riscv_cboz_block_size) { - pr_err("Zicboz detected in ISA string, disabling as no cboz-block-size found\n"); - return false; - } else if (!is_power_of_2(riscv_cboz_block_size)) { - pr_err("Zicboz disabled as cboz-block-size present, but is not a power-of-2\n"); - return false; - } - return true; - case RISCV_ISA_EXT_INVALID: - return false; + if (!riscv_cbom_block_size) { + pr_err("Zicbom detected in ISA string, disabling as no cbom-block-size found\n"); + return -EINVAL; } - - return true; + if (!is_power_of_2(riscv_cbom_block_size)) { + pr_err("Zicbom disabled as cbom-block-size present, but is not a power-of-2\n"); + return -EINVAL; + } + return 0; } -#define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size) { \ - .name = #_name, \ - .property = #_name, \ - .id = _id, \ - .subset_ext_ids = _subset_exts, \ - .subset_ext_size = _subset_exts_size \ +static int riscv_ext_zicboz_validate(const struct riscv_isa_ext_data *data, + const unsigned long *isa_bitmap) +{ + if (!riscv_cboz_block_size) { + pr_err("Zicboz detected in ISA string, disabling as no cboz-block-size found\n"); + return -EINVAL; + } + if (!is_power_of_2(riscv_cboz_block_size)) { + pr_err("Zicboz disabled as cboz-block-size present, but is not a power-of-2\n"); + return -EINVAL; + } + return 0; } -#define __RISCV_ISA_EXT_DATA(_name, _id) _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0) +#define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size, _validate) { \ + .name = #_name, \ + .property = #_name, \ + .id = _id, \ + .subset_ext_ids = _subset_exts, \ + .subset_ext_size = _subset_exts_size, \ + .validate = _validate \ +} + +#define __RISCV_ISA_EXT_DATA(_name, _id) _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0, NULL) + +#define __RISCV_ISA_EXT_DATA_VALIDATE(_name, _id, _validate) \ + _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0, _validate) /* Used to declare pure "lasso" extension (Zk for instance) */ #define __RISCV_ISA_EXT_BUNDLE(_name, _bundled_exts) \ - _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, ARRAY_SIZE(_bundled_exts)) + _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, \ + ARRAY_SIZE(_bundled_exts), NULL) /* Used to declare extensions that are a superset of other extensions (Zvbb for instance) */ #define __RISCV_ISA_EXT_SUPERSET(_name, _id, _sub_exts) \ - _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts)) + _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), NULL) +#define __RISCV_ISA_EXT_SUPERSET_VALIDATE(_name, _id, _sub_exts, _validate) \ + _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), _validate) + +static int riscv_ext_zca_depends(const struct riscv_isa_ext_data *data, + const unsigned long *isa_bitmap) +{ + if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZCA)) + return 0; + + return -EPROBE_DEFER; +} +static int riscv_ext_zcd_validate(const struct riscv_isa_ext_data *data, + const unsigned long *isa_bitmap) +{ + if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZCA) && + __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_d)) + return 0; + + return -EPROBE_DEFER; +} + +static int riscv_ext_zcf_validate(const struct riscv_isa_ext_data *data, + const unsigned long *isa_bitmap) +{ + if (IS_ENABLED(CONFIG_64BIT)) + return -EINVAL; + + if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZCA) && + __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_f)) + return 0; + + return -EPROBE_DEFER; +} static const unsigned int riscv_zk_bundled_exts[] = { RISCV_ISA_EXT_ZBKB, @@ -188,6 +226,40 @@ static const unsigned int riscv_zvbb_exts[] = { RISCV_ISA_EXT_ZVKB }; +#define RISCV_ISA_EXT_ZVE64F_IMPLY_LIST \ + RISCV_ISA_EXT_ZVE64X, \ + RISCV_ISA_EXT_ZVE32F, \ + RISCV_ISA_EXT_ZVE32X + +#define RISCV_ISA_EXT_ZVE64D_IMPLY_LIST \ + RISCV_ISA_EXT_ZVE64F, \ + RISCV_ISA_EXT_ZVE64F_IMPLY_LIST + +#define RISCV_ISA_EXT_V_IMPLY_LIST \ + RISCV_ISA_EXT_ZVE64D, \ + RISCV_ISA_EXT_ZVE64D_IMPLY_LIST + +static const unsigned int riscv_zve32f_exts[] = { + RISCV_ISA_EXT_ZVE32X +}; + +static const unsigned int riscv_zve64f_exts[] = { + RISCV_ISA_EXT_ZVE64F_IMPLY_LIST +}; + +static const unsigned int riscv_zve64d_exts[] = { + RISCV_ISA_EXT_ZVE64D_IMPLY_LIST +}; + +static const unsigned int riscv_v_exts[] = { + RISCV_ISA_EXT_V_IMPLY_LIST +}; + +static const unsigned int riscv_zve64x_exts[] = { + RISCV_ISA_EXT_ZVE32X, + RISCV_ISA_EXT_ZVE64X +}; + /* * While the [ms]envcfg CSRs were not defined until version 1.12 of the RISC-V * privileged ISA, the existence of the CSRs is implied by any extension which @@ -198,6 +270,21 @@ static const unsigned int riscv_xlinuxenvcfg_exts[] = { RISCV_ISA_EXT_XLINUXENVCFG }; +/* + * Zc* spec states that: + * - C always implies Zca + * - C+F implies Zcf (RV32 only) + * - C+D implies Zcd + * + * These extensions will be enabled and then validated depending on the + * availability of F/D RV32. + */ +static const unsigned int riscv_c_exts[] = { + RISCV_ISA_EXT_ZCA, + RISCV_ISA_EXT_ZCF, + RISCV_ISA_EXT_ZCD, +}; + /* * The canonical order of ISA extension names in the ISA string is defined in * chapter 27 of the unprivileged specification. @@ -244,11 +331,13 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { __RISCV_ISA_EXT_DATA(f, RISCV_ISA_EXT_f), __RISCV_ISA_EXT_DATA(d, RISCV_ISA_EXT_d), __RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_q), - __RISCV_ISA_EXT_DATA(c, RISCV_ISA_EXT_c), - __RISCV_ISA_EXT_DATA(v, RISCV_ISA_EXT_v), + __RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_c, riscv_c_exts), + __RISCV_ISA_EXT_SUPERSET(v, RISCV_ISA_EXT_v, riscv_v_exts), __RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h), - __RISCV_ISA_EXT_SUPERSET(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts), - __RISCV_ISA_EXT_SUPERSET(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts), + __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, + riscv_ext_zicbom_validate), + __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, + riscv_ext_zicboz_validate), __RISCV_ISA_EXT_DATA(zicntr, RISCV_ISA_EXT_ZICNTR), __RISCV_ISA_EXT_DATA(zicond, RISCV_ISA_EXT_ZICOND), __RISCV_ISA_EXT_DATA(zicsr, RISCV_ISA_EXT_ZICSR), @@ -256,10 +345,17 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { __RISCV_ISA_EXT_DATA(zihintntl, RISCV_ISA_EXT_ZIHINTNTL), __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), __RISCV_ISA_EXT_DATA(zihpm, RISCV_ISA_EXT_ZIHPM), + __RISCV_ISA_EXT_DATA(zimop, RISCV_ISA_EXT_ZIMOP), __RISCV_ISA_EXT_DATA(zacas, RISCV_ISA_EXT_ZACAS), + __RISCV_ISA_EXT_DATA(zawrs, RISCV_ISA_EXT_ZAWRS), __RISCV_ISA_EXT_DATA(zfa, RISCV_ISA_EXT_ZFA), __RISCV_ISA_EXT_DATA(zfh, RISCV_ISA_EXT_ZFH), __RISCV_ISA_EXT_DATA(zfhmin, RISCV_ISA_EXT_ZFHMIN), + __RISCV_ISA_EXT_DATA(zca, RISCV_ISA_EXT_ZCA), + __RISCV_ISA_EXT_DATA_VALIDATE(zcb, RISCV_ISA_EXT_ZCB, riscv_ext_zca_depends), + __RISCV_ISA_EXT_DATA_VALIDATE(zcd, RISCV_ISA_EXT_ZCD, riscv_ext_zcd_validate), + __RISCV_ISA_EXT_DATA_VALIDATE(zcf, RISCV_ISA_EXT_ZCF, riscv_ext_zcf_validate), + __RISCV_ISA_EXT_DATA_VALIDATE(zcmop, RISCV_ISA_EXT_ZCMOP, riscv_ext_zca_depends), __RISCV_ISA_EXT_DATA(zba, RISCV_ISA_EXT_ZBA), __RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB), __RISCV_ISA_EXT_DATA(zbc, RISCV_ISA_EXT_ZBC), @@ -280,6 +376,11 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { __RISCV_ISA_EXT_DATA(ztso, RISCV_ISA_EXT_ZTSO), __RISCV_ISA_EXT_SUPERSET(zvbb, RISCV_ISA_EXT_ZVBB, riscv_zvbb_exts), __RISCV_ISA_EXT_DATA(zvbc, RISCV_ISA_EXT_ZVBC), + __RISCV_ISA_EXT_SUPERSET(zve32f, RISCV_ISA_EXT_ZVE32F, riscv_zve32f_exts), + __RISCV_ISA_EXT_DATA(zve32x, RISCV_ISA_EXT_ZVE32X), + __RISCV_ISA_EXT_SUPERSET(zve64d, RISCV_ISA_EXT_ZVE64D, riscv_zve64d_exts), + __RISCV_ISA_EXT_SUPERSET(zve64f, RISCV_ISA_EXT_ZVE64F, riscv_zve64f_exts), + __RISCV_ISA_EXT_SUPERSET(zve64x, RISCV_ISA_EXT_ZVE64X, riscv_zve64x_exts), __RISCV_ISA_EXT_DATA(zvfh, RISCV_ISA_EXT_ZVFH), __RISCV_ISA_EXT_DATA(zvfhmin, RISCV_ISA_EXT_ZVFHMIN), __RISCV_ISA_EXT_DATA(zvkb, RISCV_ISA_EXT_ZVKB), @@ -309,33 +410,93 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { const size_t riscv_isa_ext_count = ARRAY_SIZE(riscv_isa_ext); -static void __init match_isa_ext(const struct riscv_isa_ext_data *ext, const char *name, - const char *name_end, struct riscv_isainfo *isainfo) +static void riscv_isa_set_ext(const struct riscv_isa_ext_data *ext, unsigned long *bitmap) { - if ((name_end - name == strlen(ext->name)) && - !strncasecmp(name, ext->name, name_end - name)) { - /* - * If this is a bundle, enable all the ISA extensions that - * comprise the bundle. - */ - if (ext->subset_ext_size) { - for (int i = 0; i < ext->subset_ext_size; i++) { - if (riscv_isa_extension_check(ext->subset_ext_ids[i])) - set_bit(ext->subset_ext_ids[i], isainfo->isa); - } - } + if (ext->id != RISCV_ISA_EXT_INVALID) + set_bit(ext->id, bitmap); - /* - * This is valid even for bundle extensions which uses the RISCV_ISA_EXT_INVALID id - * (rejected by riscv_isa_extension_check()). - */ - if (riscv_isa_extension_check(ext->id)) - set_bit(ext->id, isainfo->isa); + for (int i = 0; i < ext->subset_ext_size; i++) { + if (ext->subset_ext_ids[i] != RISCV_ISA_EXT_INVALID) + set_bit(ext->subset_ext_ids[i], bitmap); } } -static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct riscv_isainfo *isainfo, - unsigned long *isa2hwcap, const char *isa) +static const struct riscv_isa_ext_data *riscv_get_isa_ext_data(unsigned int ext_id) +{ + for (int i = 0; i < riscv_isa_ext_count; i++) { + if (riscv_isa_ext[i].id == ext_id) + return &riscv_isa_ext[i]; + } + + return NULL; +} + +/* + * "Resolve" a source ISA bitmap into one that matches kernel configuration as + * well as correct extension dependencies. Some extensions depends on specific + * kernel configuration to be usable (V needs CONFIG_RISCV_ISA_V for instance) + * and this function will actually validate all the extensions provided in + * source_isa into the resolved_isa based on extensions validate() callbacks. + */ +static void __init riscv_resolve_isa(unsigned long *source_isa, + unsigned long *resolved_isa, unsigned long *this_hwcap, + unsigned long *isa2hwcap) +{ + bool loop; + const struct riscv_isa_ext_data *ext; + DECLARE_BITMAP(prev_resolved_isa, RISCV_ISA_EXT_MAX); + int max_loop_count = riscv_isa_ext_count, ret; + unsigned int bit; + + do { + loop = false; + if (max_loop_count-- < 0) { + pr_err("Failed to reach a stable ISA state\n"); + return; + } + bitmap_copy(prev_resolved_isa, resolved_isa, RISCV_ISA_EXT_MAX); + for_each_set_bit(bit, source_isa, RISCV_ISA_EXT_MAX) { + ext = riscv_get_isa_ext_data(bit); + if (!ext) + continue; + + if (ext->validate) { + ret = ext->validate(ext, resolved_isa); + if (ret == -EPROBE_DEFER) { + loop = true; + continue; + } else if (ret) { + /* Disable the extension entirely */ + clear_bit(ext->id, source_isa); + continue; + } + } + + set_bit(ext->id, resolved_isa); + /* No need to keep it in source isa now that it is enabled */ + clear_bit(ext->id, source_isa); + + /* Single letter extensions get set in hwcap */ + if (ext->id < RISCV_ISA_EXT_BASE) + *this_hwcap |= isa2hwcap[ext->id]; + } + } while (loop && memcmp(prev_resolved_isa, resolved_isa, sizeof(prev_resolved_isa))); +} + +static void __init match_isa_ext(const char *name, const char *name_end, unsigned long *bitmap) +{ + for (int i = 0; i < riscv_isa_ext_count; i++) { + const struct riscv_isa_ext_data *ext = &riscv_isa_ext[i]; + + if ((name_end - name == strlen(ext->name)) && + !strncasecmp(name, ext->name, name_end - name)) { + riscv_isa_set_ext(ext, bitmap); + break; + } + } +} + +static void __init riscv_parse_isa_string(const char *isa, unsigned long *bitmap) { /* * For all possible cpus, we have already validated in @@ -348,7 +509,7 @@ static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct risc while (*isa) { const char *ext = isa++; const char *ext_end = isa; - bool ext_long = false, ext_err = false; + bool ext_err = false; switch (*ext) { case 's': @@ -388,7 +549,6 @@ static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct risc * character itself while eliminating the extensions version number. * A simple re-increment solves this problem. */ - ext_long = true; for (; *isa && *isa != '_'; ++isa) if (unlikely(!isalnum(*isa))) ext_err = true; @@ -468,17 +628,8 @@ static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct risc if (unlikely(ext_err)) continue; - if (!ext_long) { - int nr = tolower(*ext) - 'a'; - if (riscv_isa_extension_check(nr)) { - *this_hwcap |= isa2hwcap[nr]; - set_bit(nr, isainfo->isa); - } - } else { - for (int i = 0; i < riscv_isa_ext_count; i++) - match_isa_ext(&riscv_isa_ext[i], ext, ext_end, isainfo); - } + match_isa_ext(ext, ext_end, bitmap); } } @@ -505,6 +656,7 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap) for_each_possible_cpu(cpu) { struct riscv_isainfo *isainfo = &hart_isa[cpu]; unsigned long this_hwcap = 0; + DECLARE_BITMAP(source_isa, RISCV_ISA_EXT_MAX) = { 0 }; if (acpi_disabled) { node = of_cpu_device_node_get(cpu); @@ -527,7 +679,7 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap) } } - riscv_parse_isa_string(&this_hwcap, isainfo, isa2hwcap, isa); + riscv_parse_isa_string(isa, source_isa); /* * These ones were as they were part of the base ISA when the @@ -535,10 +687,10 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap) * unconditionally where `i` is in riscv,isa on DT systems. */ if (acpi_disabled) { - set_bit(RISCV_ISA_EXT_ZICSR, isainfo->isa); - set_bit(RISCV_ISA_EXT_ZIFENCEI, isainfo->isa); - set_bit(RISCV_ISA_EXT_ZICNTR, isainfo->isa); - set_bit(RISCV_ISA_EXT_ZIHPM, isainfo->isa); + set_bit(RISCV_ISA_EXT_ZICSR, source_isa); + set_bit(RISCV_ISA_EXT_ZIFENCEI, source_isa); + set_bit(RISCV_ISA_EXT_ZICNTR, source_isa); + set_bit(RISCV_ISA_EXT_ZIHPM, source_isa); } /* @@ -551,9 +703,11 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap) */ if (acpi_disabled && boot_vendorid == THEAD_VENDOR_ID && boot_archid == 0x0) { this_hwcap &= ~isa2hwcap[RISCV_ISA_EXT_v]; - clear_bit(RISCV_ISA_EXT_v, isainfo->isa); + clear_bit(RISCV_ISA_EXT_v, source_isa); } + riscv_resolve_isa(source_isa, isainfo->isa, &this_hwcap, isa2hwcap); + /* * All "okay" hart should have same isa. Set HWCAP based on * common capabilities of every "okay" hart, in case they don't @@ -582,6 +736,7 @@ static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap) unsigned long this_hwcap = 0; struct device_node *cpu_node; struct riscv_isainfo *isainfo = &hart_isa[cpu]; + DECLARE_BITMAP(source_isa, RISCV_ISA_EXT_MAX) = { 0 }; cpu_node = of_cpu_device_node_get(cpu); if (!cpu_node) { @@ -601,22 +756,11 @@ static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap) ext->property) < 0) continue; - if (ext->subset_ext_size) { - for (int j = 0; j < ext->subset_ext_size; j++) { - if (riscv_isa_extension_check(ext->subset_ext_ids[j])) - set_bit(ext->subset_ext_ids[j], isainfo->isa); - } - } - - if (riscv_isa_extension_check(ext->id)) { - set_bit(ext->id, isainfo->isa); - - /* Only single letter extensions get set in hwcap */ - if (strnlen(riscv_isa_ext[i].name, 2) == 1) - this_hwcap |= isa2hwcap[riscv_isa_ext[i].id]; - } + riscv_isa_set_ext(ext, source_isa); } + riscv_resolve_isa(source_isa, isainfo->isa, &this_hwcap, isa2hwcap); + of_node_put(cpu_node); /* @@ -686,8 +830,14 @@ void __init riscv_fill_hwcap(void) elf_hwcap &= ~COMPAT_HWCAP_ISA_F; } - if (elf_hwcap & COMPAT_HWCAP_ISA_V) { + if (__riscv_isa_extension_available(NULL, RISCV_ISA_EXT_ZVE32X)) { + /* + * This cannot fail when called on the boot hart + */ riscv_v_setup_vsize(); + } + + if (elf_hwcap & COMPAT_HWCAP_ISA_V) { /* * ISA string in device tree might have 'v' flag, but * CONFIG_RISCV_ISA_V is disabled in kernel. diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S index 4236a69c35cb..356d5397b2a2 100644 --- a/arch/riscv/kernel/head.S +++ b/arch/riscv/kernel/head.S @@ -165,9 +165,20 @@ secondary_start_sbi: #endif call .Lsetup_trap_vector scs_load_current - tail smp_callin + call smp_callin #endif /* CONFIG_SMP */ +.align 2 +.Lsecondary_park: + /* + * Park this hart if we: + * - have too many harts on CONFIG_RISCV_BOOT_SPINWAIT + * - receive an early trap, before setup_trap_vector finished + * - fail in smp_callin(), as a successful one wouldn't return + */ + wfi + j .Lsecondary_park + .align 2 .Lsetup_trap_vector: /* Set trap vector to exception handler */ @@ -181,12 +192,6 @@ secondary_start_sbi: csrw CSR_SCRATCH, zero ret -.align 2 -.Lsecondary_park: - /* We lack SMP support or have too many harts, so park this hart */ - wfi - j .Lsecondary_park - SYM_CODE_END(_start) SYM_CODE_START(_start_kernel) @@ -300,6 +305,9 @@ SYM_CODE_START(_start_kernel) #else mv a0, a1 #endif /* CONFIG_BUILTIN_DTB */ + /* Set trap vector to spin forever to help debug */ + la a3, .Lsecondary_park + csrw CSR_TVEC, a3 call setup_vm #ifdef CONFIG_MMU la a0, early_pg_dir diff --git a/arch/riscv/kernel/jump_label.c b/arch/riscv/kernel/jump_label.c index e6694759dbd0..11ad789c60c6 100644 --- a/arch/riscv/kernel/jump_label.c +++ b/arch/riscv/kernel/jump_label.c @@ -9,13 +9,14 @@ #include #include #include +#include #include #define RISCV_INSN_NOP 0x00000013U #define RISCV_INSN_JAL 0x0000006fU -void arch_jump_label_transform(struct jump_entry *entry, - enum jump_label_type type) +bool arch_jump_label_transform_queue(struct jump_entry *entry, + enum jump_label_type type) { void *addr = (void *)jump_entry_code(entry); u32 insn; @@ -24,7 +25,7 @@ void arch_jump_label_transform(struct jump_entry *entry, long offset = jump_entry_target(entry) - jump_entry_code(entry); if (WARN_ON(offset & 1 || offset < -524288 || offset >= 524288)) - return; + return true; insn = RISCV_INSN_JAL | (((u32)offset & GENMASK(19, 12)) << (12 - 12)) | @@ -36,6 +37,13 @@ void arch_jump_label_transform(struct jump_entry *entry, } mutex_lock(&text_mutex); - patch_text_nosync(addr, &insn, sizeof(insn)); + patch_insn_write(addr, &insn, sizeof(insn)); mutex_unlock(&text_mutex); + + return true; +} + +void arch_jump_label_transform_apply(void) +{ + flush_icache_all(); } diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c index ab03732d06c4..69e5796fc51f 100644 --- a/arch/riscv/kernel/patch.c +++ b/arch/riscv/kernel/patch.c @@ -19,7 +19,7 @@ struct patch_insn { void *addr; u32 *insns; - int ninsns; + size_t len; atomic_t cpu_count; }; @@ -54,7 +54,7 @@ static __always_inline void *patch_map(void *addr, const unsigned int fixmap) BUG_ON(!page); return (void *)set_fixmap_offset(fixmap, page_to_phys(page) + - (uintaddr & ~PAGE_MASK)); + offset_in_page(addr)); } static void patch_unmap(int fixmap) @@ -65,8 +65,8 @@ NOKPROBE_SYMBOL(patch_unmap); static int __patch_insn_set(void *addr, u8 c, size_t len) { + bool across_pages = (offset_in_page(addr) + len) > PAGE_SIZE; void *waddr = addr; - bool across_pages = (((uintptr_t)addr & ~PAGE_MASK) + len) > PAGE_SIZE; /* * Only two pages can be mapped at a time for writing. @@ -110,8 +110,8 @@ NOKPROBE_SYMBOL(__patch_insn_set); static int __patch_insn_write(void *addr, const void *insn, size_t len) { + bool across_pages = (offset_in_page(addr) + len) > PAGE_SIZE; void *waddr = addr; - bool across_pages = (((uintptr_t) addr & ~PAGE_MASK) + len) > PAGE_SIZE; int ret; /* @@ -179,31 +179,32 @@ NOKPROBE_SYMBOL(__patch_insn_write); static int patch_insn_set(void *addr, u8 c, size_t len) { - size_t patched = 0; size_t size; - int ret = 0; + int ret; /* * __patch_insn_set() can only work on 2 pages at a time so call it in a * loop with len <= 2 * PAGE_SIZE. */ - while (patched < len && !ret) { - size = min_t(size_t, PAGE_SIZE * 2 - offset_in_page(addr + patched), len - patched); - ret = __patch_insn_set(addr + patched, c, size); + while (len) { + size = min(len, PAGE_SIZE * 2 - offset_in_page(addr)); + ret = __patch_insn_set(addr, c, size); + if (ret) + return ret; - patched += size; + addr += size; + len -= size; } - return ret; + return 0; } NOKPROBE_SYMBOL(patch_insn_set); int patch_text_set_nosync(void *addr, u8 c, size_t len) { - u32 *tp = addr; int ret; - ret = patch_insn_set(tp, c, len); + ret = patch_insn_set(addr, c, len); return ret; } @@ -211,31 +212,33 @@ NOKPROBE_SYMBOL(patch_text_set_nosync); int patch_insn_write(void *addr, const void *insn, size_t len) { - size_t patched = 0; size_t size; - int ret = 0; + int ret; /* * Copy the instructions to the destination address, two pages at a time * because __patch_insn_write() can only handle len <= 2 * PAGE_SIZE. */ - while (patched < len && !ret) { - size = min_t(size_t, PAGE_SIZE * 2 - offset_in_page(addr + patched), len - patched); - ret = __patch_insn_write(addr + patched, insn + patched, size); + while (len) { + size = min(len, PAGE_SIZE * 2 - offset_in_page(addr)); + ret = __patch_insn_write(addr, insn, size); + if (ret) + return ret; - patched += size; + addr += size; + insn += size; + len -= size; } - return ret; + return 0; } NOKPROBE_SYMBOL(patch_insn_write); int patch_text_nosync(void *addr, const void *insns, size_t len) { - u32 *tp = addr; int ret; - ret = patch_insn_write(tp, insns, len); + ret = patch_insn_write(addr, insns, len); return ret; } @@ -244,14 +247,10 @@ NOKPROBE_SYMBOL(patch_text_nosync); static int patch_text_cb(void *data) { struct patch_insn *patch = data; - unsigned long len; - int i, ret = 0; + int ret = 0; if (atomic_inc_return(&patch->cpu_count) == num_online_cpus()) { - for (i = 0; ret == 0 && i < patch->ninsns; i++) { - len = GET_INSN_LENGTH(patch->insns[i]); - ret = patch_insn_write(patch->addr + i * len, &patch->insns[i], len); - } + ret = patch_insn_write(patch->addr, patch->insns, patch->len); /* * Make sure the patching store is effective *before* we * increment the counter which releases all waiting CPUs @@ -271,13 +270,13 @@ static int patch_text_cb(void *data) } NOKPROBE_SYMBOL(patch_text_cb); -int patch_text(void *addr, u32 *insns, int ninsns) +int patch_text(void *addr, u32 *insns, size_t len) { int ret; struct patch_insn patch = { .addr = addr, .insns = insns, - .ninsns = ninsns, + .len = len, .cpu_count = ATOMIC_INIT(0), }; diff --git a/arch/riscv/kernel/probes/kprobes.c b/arch/riscv/kernel/probes/kprobes.c index dfb28e57d900..474a65213657 100644 --- a/arch/riscv/kernel/probes/kprobes.c +++ b/arch/riscv/kernel/probes/kprobes.c @@ -24,14 +24,13 @@ post_kprobe_handler(struct kprobe *, struct kprobe_ctlblk *, struct pt_regs *); static void __kprobes arch_prepare_ss_slot(struct kprobe *p) { + size_t len = GET_INSN_LENGTH(p->opcode); u32 insn = __BUG_INSN_32; - unsigned long offset = GET_INSN_LENGTH(p->opcode); - p->ainsn.api.restore = (unsigned long)p->addr + offset; + p->ainsn.api.restore = (unsigned long)p->addr + len; - patch_text(p->ainsn.api.insn, &p->opcode, 1); - patch_text((void *)((unsigned long)(p->ainsn.api.insn) + offset), - &insn, 1); + patch_text_nosync(p->ainsn.api.insn, &p->opcode, len); + patch_text_nosync(p->ainsn.api.insn + len, &insn, GET_INSN_LENGTH(insn)); } static void __kprobes arch_prepare_simulate(struct kprobe *p) @@ -108,16 +107,18 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) /* install breakpoint in text */ void __kprobes arch_arm_kprobe(struct kprobe *p) { - u32 insn = (p->opcode & __INSN_LENGTH_MASK) == __INSN_LENGTH_32 ? - __BUG_INSN_32 : __BUG_INSN_16; + size_t len = GET_INSN_LENGTH(p->opcode); + u32 insn = len == 4 ? __BUG_INSN_32 : __BUG_INSN_16; - patch_text(p->addr, &insn, 1); + patch_text(p->addr, &insn, len); } /* remove breakpoint from text */ void __kprobes arch_disarm_kprobe(struct kprobe *p) { - patch_text(p->addr, &p->opcode, 1); + size_t len = GET_INSN_LENGTH(p->opcode); + + patch_text(p->addr, &p->opcode, len); } void __kprobes arch_remove_kprobe(struct kprobe *p) diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c index e66e0999a800..837bdab2601b 100644 --- a/arch/riscv/kernel/sbi.c +++ b/arch/riscv/kernel/sbi.c @@ -14,6 +14,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + /* default SBI version is 0.1 */ unsigned long sbi_spec_version __ro_after_init = SBI_SPEC_VERSION_DEFAULT; EXPORT_SYMBOL(sbi_spec_version); @@ -24,13 +27,15 @@ static int (*__sbi_rfence)(int fid, const struct cpumask *cpu_mask, unsigned long start, unsigned long size, unsigned long arg4, unsigned long arg5) __ro_after_init; -struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, - unsigned long arg1, unsigned long arg2, - unsigned long arg3, unsigned long arg4, - unsigned long arg5) +struct sbiret __sbi_ecall(unsigned long arg0, unsigned long arg1, + unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5, + int fid, int ext) { struct sbiret ret; + trace_sbi_call(ext, fid); + register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0); register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1); register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2); @@ -46,9 +51,11 @@ struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, ret.error = a0; ret.value = a1; + trace_sbi_return(ext, ret.error, ret.value); + return ret; } -EXPORT_SYMBOL(sbi_ecall); +EXPORT_SYMBOL(__sbi_ecall); int sbi_err_map_linux_errno(int err) { diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index 1319b29ce3b5..19baf0d574d3 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c @@ -214,6 +214,15 @@ asmlinkage __visible void smp_callin(void) struct mm_struct *mm = &init_mm; unsigned int curr_cpuid = smp_processor_id(); + if (has_vector()) { + /* + * Return as early as possible so the hart with a mismatching + * vlen won't boot. + */ + if (riscv_v_setup_vsize()) + return; + } + /* All kernel threads share the same mm context. */ mmgrab(mm); current->active_mm = mm; @@ -226,11 +235,6 @@ asmlinkage __visible void smp_callin(void) numa_add_cpu(curr_cpuid); set_cpu_online(curr_cpuid, true); - if (has_vector()) { - if (riscv_v_setup_vsize()) - elf_hwcap &= ~COMPAT_HWCAP_ISA_V; - } - riscv_user_isa_enable(); /* diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c index 969ef3d59dbe..685594769535 100644 --- a/arch/riscv/kernel/sys_hwprobe.c +++ b/arch/riscv/kernel/sys_hwprobe.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +70,7 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, if (riscv_isa_extension_available(NULL, c)) pair->value |= RISCV_HWPROBE_IMA_C; - if (has_vector()) + if (has_vector() && riscv_isa_extension_available(NULL, v)) pair->value |= RISCV_HWPROBE_IMA_V; /* @@ -112,8 +113,22 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, EXT_KEY(ZACAS); EXT_KEY(ZICOND); EXT_KEY(ZIHINTPAUSE); + EXT_KEY(ZIMOP); + EXT_KEY(ZCA); + EXT_KEY(ZCB); + EXT_KEY(ZCMOP); + EXT_KEY(ZAWRS); + /* + * All the following extensions must depend on the kernel + * support of V. + */ if (has_vector()) { + EXT_KEY(ZVE32X); + EXT_KEY(ZVE32F); + EXT_KEY(ZVE64X); + EXT_KEY(ZVE64F); + EXT_KEY(ZVE64D); EXT_KEY(ZVBB); EXT_KEY(ZVBC); EXT_KEY(ZVKB); @@ -132,6 +147,8 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, EXT_KEY(ZFH); EXT_KEY(ZFHMIN); EXT_KEY(ZFA); + EXT_KEY(ZCD); + EXT_KEY(ZCF); } #undef EXT_KEY } @@ -216,6 +233,9 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair, if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOZ)) pair->value = riscv_cboz_block_size; break; + case RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS: + pair->value = user_max_virt_addr(); + break; /* * For forward compatibility, unknown keys don't fail the whole diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c index 6727d1d3b8f2..682b3feee451 100644 --- a/arch/riscv/kernel/vector.c +++ b/arch/riscv/kernel/vector.c @@ -173,8 +173,11 @@ bool riscv_v_first_use_handler(struct pt_regs *regs) u32 __user *epc = (u32 __user *)regs->epc; u32 insn = (u32)regs->badaddr; + if (!has_vector()) + return false; + /* Do not handle if V is not supported, or disabled */ - if (!(ELF_HWCAP & COMPAT_HWCAP_ISA_V)) + if (!riscv_v_vstate_ctrl_user_allowed()) return false; /* If V has been enabled then it is not the first-use trap */ diff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c index 0f0a9d11bb5f..2967d305c442 100644 --- a/arch/riscv/kvm/aia.c +++ b/arch/riscv/kvm/aia.c @@ -10,12 +10,12 @@ #include #include #include +#include #include #include #include #include #include -#include struct aia_hgei_control { raw_spinlock_t lock; @@ -394,6 +394,8 @@ int kvm_riscv_aia_alloc_hgei(int cpu, struct kvm_vcpu *owner, { int ret = -ENOENT; unsigned long flags; + const struct imsic_global_config *gc; + const struct imsic_local_config *lc; struct aia_hgei_control *hgctrl = per_cpu_ptr(&aia_hgei, cpu); if (!kvm_riscv_aia_available() || !hgctrl) @@ -409,11 +411,14 @@ int kvm_riscv_aia_alloc_hgei(int cpu, struct kvm_vcpu *owner, raw_spin_unlock_irqrestore(&hgctrl->lock, flags); - /* TODO: To be updated later by AIA IMSIC HW guest file support */ - if (hgei_va) - *hgei_va = NULL; - if (hgei_pa) - *hgei_pa = 0; + gc = imsic_get_global_config(); + lc = (gc) ? per_cpu_ptr(gc->local, cpu) : NULL; + if (lc && ret > 0) { + if (hgei_va) + *hgei_va = lc->msi_va + (ret * IMSIC_MMIO_PAGE_SZ); + if (hgei_pa) + *hgei_pa = lc->msi_pa + (ret * IMSIC_MMIO_PAGE_SZ); + } return ret; } @@ -605,9 +610,11 @@ void kvm_riscv_aia_disable(void) int kvm_riscv_aia_init(void) { int rc; + const struct imsic_global_config *gc; if (!riscv_isa_extension_available(NULL, SxAIA)) return -ENODEV; + gc = imsic_get_global_config(); /* Figure-out number of bits in HGEIE */ csr_write(CSR_HGEIE, -1UL); @@ -619,17 +626,17 @@ int kvm_riscv_aia_init(void) /* * Number of usable HGEI lines should be minimum of per-HART * IMSIC guest files and number of bits in HGEIE - * - * TODO: To be updated later by AIA IMSIC HW guest file support */ - kvm_riscv_aia_nr_hgei = 0; + if (gc) + kvm_riscv_aia_nr_hgei = min((ulong)kvm_riscv_aia_nr_hgei, + BIT(gc->guest_index_bits) - 1); + else + kvm_riscv_aia_nr_hgei = 0; - /* - * Find number of guest MSI IDs - * - * TODO: To be updated later by AIA IMSIC HW guest file support - */ + /* Find number of guest MSI IDs */ kvm_riscv_aia_max_ids = IMSIC_MAX_ID; + if (gc && kvm_riscv_aia_nr_hgei) + kvm_riscv_aia_max_ids = gc->nr_guest_ids + 1; /* Initialize guest external interrupt line management */ rc = aia_hgei_init(); diff --git a/arch/riscv/kvm/aia_aplic.c b/arch/riscv/kvm/aia_aplic.c index b467ba5ed910..da6ff1bade0d 100644 --- a/arch/riscv/kvm/aia_aplic.c +++ b/arch/riscv/kvm/aia_aplic.c @@ -7,12 +7,12 @@ * Anup Patel */ +#include #include #include #include #include #include -#include struct aplic_irq { raw_spinlock_t lock; diff --git a/arch/riscv/kvm/aia_device.c b/arch/riscv/kvm/aia_device.c index 5cd407c6a8e4..39cd26af5a69 100644 --- a/arch/riscv/kvm/aia_device.c +++ b/arch/riscv/kvm/aia_device.c @@ -8,9 +8,9 @@ */ #include +#include #include #include -#include static void unlock_vcpus(struct kvm *kvm, int vcpu_lock_idx) { diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c index e808723a85f1..0a1e859323b4 100644 --- a/arch/riscv/kvm/aia_imsic.c +++ b/arch/riscv/kvm/aia_imsic.c @@ -9,13 +9,13 @@ #include #include +#include #include #include #include #include #include #include -#include #define IMSIC_MAX_EIX (IMSIC_MAX_ID / BITS_PER_TYPE(u64)) diff --git a/arch/riscv/kvm/trace.h b/arch/riscv/kvm/trace.h new file mode 100644 index 000000000000..3d54175d805c --- /dev/null +++ b/arch/riscv/kvm/trace.h @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Tracepoints for RISC-V KVM + * + * Copyright 2024 Beijing ESWIN Computing Technology Co., Ltd. + * + */ +#if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_KVM_H + +#include + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM kvm + +TRACE_EVENT(kvm_entry, + TP_PROTO(struct kvm_vcpu *vcpu), + TP_ARGS(vcpu), + + TP_STRUCT__entry( + __field(unsigned long, pc) + ), + + TP_fast_assign( + __entry->pc = vcpu->arch.guest_context.sepc; + ), + + TP_printk("PC: 0x016%lx", __entry->pc) +); + +TRACE_EVENT(kvm_exit, + TP_PROTO(struct kvm_cpu_trap *trap), + TP_ARGS(trap), + + TP_STRUCT__entry( + __field(unsigned long, sepc) + __field(unsigned long, scause) + __field(unsigned long, stval) + __field(unsigned long, htval) + __field(unsigned long, htinst) + ), + + TP_fast_assign( + __entry->sepc = trap->sepc; + __entry->scause = trap->scause; + __entry->stval = trap->stval; + __entry->htval = trap->htval; + __entry->htinst = trap->htinst; + ), + + TP_printk("SEPC:0x%lx, SCAUSE:0x%lx, STVAL:0x%lx, HTVAL:0x%lx, HTINST:0x%lx", + __entry->sepc, + __entry->scause, + __entry->stval, + __entry->htval, + __entry->htinst) +); + +#endif /* _TRACE_RSICV_KVM_H */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +/* This part must be outside protection */ +#include diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index 17e21df36cc1..8d7d381737ee 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -21,10 +21,14 @@ #include #include +#define CREATE_TRACE_POINTS +#include "trace.h" + const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { KVM_GENERIC_VCPU_STATS(), STATS_DESC_COUNTER(VCPU, ecall_exit_stat), STATS_DESC_COUNTER(VCPU, wfi_exit_stat), + STATS_DESC_COUNTER(VCPU, wrs_exit_stat), STATS_DESC_COUNTER(VCPU, mmio_exit_user), STATS_DESC_COUNTER(VCPU, mmio_exit_kernel), STATS_DESC_COUNTER(VCPU, csr_exit_user), @@ -760,7 +764,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) return ret; } - if (run->immediate_exit) { + if (!vcpu->wants_to_run) { kvm_vcpu_srcu_read_unlock(vcpu); return -EINTR; } @@ -831,6 +835,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) */ kvm_riscv_local_tlb_sanitize(vcpu); + trace_kvm_entry(vcpu); + guest_timing_enter_irqoff(); kvm_riscv_vcpu_enter_exit(vcpu); @@ -869,6 +875,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) local_irq_enable(); + trace_kvm_exit(&trap); + preempt_enable(); kvm_vcpu_srcu_read_lock(vcpu); diff --git a/arch/riscv/kvm/vcpu_exit.c b/arch/riscv/kvm/vcpu_exit.c index 5761f95abb60..fa98e5c024b2 100644 --- a/arch/riscv/kvm/vcpu_exit.c +++ b/arch/riscv/kvm/vcpu_exit.c @@ -185,6 +185,8 @@ int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, case EXC_INST_ILLEGAL: case EXC_LOAD_MISALIGNED: case EXC_STORE_MISALIGNED: + case EXC_LOAD_ACCESS: + case EXC_STORE_ACCESS: if (vcpu->arch.guest_context.hstatus & HSTATUS_SPV) { kvm_riscv_vcpu_trap_redirect(vcpu, trap); ret = 1; diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c index ee7215f4071f..97dec18e6989 100644 --- a/arch/riscv/kvm/vcpu_insn.c +++ b/arch/riscv/kvm/vcpu_insn.c @@ -16,6 +16,9 @@ #define INSN_MASK_WFI 0xffffffff #define INSN_MATCH_WFI 0x10500073 +#define INSN_MASK_WRS 0xffffffff +#define INSN_MATCH_WRS 0x00d00073 + #define INSN_MATCH_CSRRW 0x1073 #define INSN_MASK_CSRRW 0x707f #define INSN_MATCH_CSRRS 0x2073 @@ -203,6 +206,13 @@ static int wfi_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn) return KVM_INSN_CONTINUE_NEXT_SEPC; } +static int wrs_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn) +{ + vcpu->stat.wrs_exit_stat++; + kvm_vcpu_on_spin(vcpu, vcpu->arch.guest_context.sstatus & SR_SPP); + return KVM_INSN_CONTINUE_NEXT_SEPC; +} + struct csr_func { unsigned int base; unsigned int count; @@ -378,6 +388,11 @@ static const struct insn_func system_opcode_funcs[] = { .match = INSN_MATCH_WFI, .func = wfi_insn, }, + { + .mask = INSN_MASK_WRS, + .match = INSN_MATCH_WRS, + .func = wrs_insn, + }, }; static int system_opcode_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 62874fbca29f..b319c4c13c54 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -42,6 +42,7 @@ static const unsigned long kvm_isa_ext_arr[] = { KVM_ISA_EXT_ARR(SVNAPOT), KVM_ISA_EXT_ARR(SVPBMT), KVM_ISA_EXT_ARR(ZACAS), + KVM_ISA_EXT_ARR(ZAWRS), KVM_ISA_EXT_ARR(ZBA), KVM_ISA_EXT_ARR(ZBB), KVM_ISA_EXT_ARR(ZBC), @@ -49,6 +50,11 @@ static const unsigned long kvm_isa_ext_arr[] = { KVM_ISA_EXT_ARR(ZBKC), KVM_ISA_EXT_ARR(ZBKX), KVM_ISA_EXT_ARR(ZBS), + KVM_ISA_EXT_ARR(ZCA), + KVM_ISA_EXT_ARR(ZCB), + KVM_ISA_EXT_ARR(ZCD), + KVM_ISA_EXT_ARR(ZCF), + KVM_ISA_EXT_ARR(ZCMOP), KVM_ISA_EXT_ARR(ZFA), KVM_ISA_EXT_ARR(ZFH), KVM_ISA_EXT_ARR(ZFHMIN), @@ -61,6 +67,7 @@ static const unsigned long kvm_isa_ext_arr[] = { KVM_ISA_EXT_ARR(ZIHINTNTL), KVM_ISA_EXT_ARR(ZIHINTPAUSE), KVM_ISA_EXT_ARR(ZIHPM), + KVM_ISA_EXT_ARR(ZIMOP), KVM_ISA_EXT_ARR(ZKND), KVM_ISA_EXT_ARR(ZKNE), KVM_ISA_EXT_ARR(ZKNH), @@ -126,6 +133,7 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_SVINVAL: case KVM_RISCV_ISA_EXT_SVNAPOT: case KVM_RISCV_ISA_EXT_ZACAS: + case KVM_RISCV_ISA_EXT_ZAWRS: case KVM_RISCV_ISA_EXT_ZBA: case KVM_RISCV_ISA_EXT_ZBB: case KVM_RISCV_ISA_EXT_ZBC: @@ -133,6 +141,11 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_ZBKC: case KVM_RISCV_ISA_EXT_ZBKX: case KVM_RISCV_ISA_EXT_ZBS: + case KVM_RISCV_ISA_EXT_ZCA: + case KVM_RISCV_ISA_EXT_ZCB: + case KVM_RISCV_ISA_EXT_ZCD: + case KVM_RISCV_ISA_EXT_ZCF: + case KVM_RISCV_ISA_EXT_ZCMOP: case KVM_RISCV_ISA_EXT_ZFA: case KVM_RISCV_ISA_EXT_ZFH: case KVM_RISCV_ISA_EXT_ZFHMIN: @@ -143,6 +156,7 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_ZIHINTNTL: case KVM_RISCV_ISA_EXT_ZIHINTPAUSE: case KVM_RISCV_ISA_EXT_ZIHPM: + case KVM_RISCV_ISA_EXT_ZIMOP: case KVM_RISCV_ISA_EXT_ZKND: case KVM_RISCV_ISA_EXT_ZKNE: case KVM_RISCV_ISA_EXT_ZKNH: diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index bd6e6c1b0497..2b369f51b0a5 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile @@ -13,6 +13,7 @@ endif lib-$(CONFIG_MMU) += uaccess.o lib-$(CONFIG_64BIT) += tishift.o lib-$(CONFIG_RISCV_ISA_ZICBOZ) += clear_page.o +lib-$(CONFIG_RISCV_ISA_ZBC) += crc32.o obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o lib-$(CONFIG_RISCV_ISA_V) += xor.o diff --git a/arch/riscv/lib/crc32.c b/arch/riscv/lib/crc32.c new file mode 100644 index 000000000000..d7dc599af3ef --- /dev/null +++ b/arch/riscv/lib/crc32.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Accelerated CRC32 implementation with Zbc extension. + * + * Copyright (C) 2024 Intel Corporation + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Refer to https://www.corsix.org/content/barrett-reduction-polynomials for + * better understanding of how this math works. + * + * let "+" denotes polynomial add (XOR) + * let "-" denotes polynomial sub (XOR) + * let "*" denotes polynomial multiplication + * let "/" denotes polynomial floor division + * let "S" denotes source data, XLEN bit wide + * let "P" denotes CRC32 polynomial + * let "T" denotes 2^(XLEN+32) + * let "QT" denotes quotient of T/P, with the bit for 2^XLEN being implicit + * + * crc32(S, P) + * => S * (2^32) - S * (2^32) / P * P + * => lowest 32 bits of: S * (2^32) / P * P + * => lowest 32 bits of: S * (2^32) * (T / P) / T * P + * => lowest 32 bits of: S * (2^32) * quotient / T * P + * => lowest 32 bits of: S * quotient / 2^XLEN * P + * => lowest 32 bits of: (clmul_high_part(S, QT) + S) * P + * => clmul_low_part(clmul_high_part(S, QT) + S, P) + * + * In terms of below implementations, the BE case is more intuitive, since the + * higher order bit sits at more significant position. + */ + +#if __riscv_xlen == 64 +/* Slide by XLEN bits per iteration */ +# define STEP_ORDER 3 + +/* Each below polynomial quotient has an implicit bit for 2^XLEN */ + +/* Polynomial quotient of (2^(XLEN+32))/CRC32_POLY, in LE format */ +# define CRC32_POLY_QT_LE 0x5a72d812fb808b20 + +/* Polynomial quotient of (2^(XLEN+32))/CRC32C_POLY, in LE format */ +# define CRC32C_POLY_QT_LE 0xa434f61c6f5389f8 + +/* Polynomial quotient of (2^(XLEN+32))/CRC32_POLY, in BE format, it should be + * the same as the bit-reversed version of CRC32_POLY_QT_LE + */ +# define CRC32_POLY_QT_BE 0x04d101df481b4e5a + +static inline u64 crc32_le_prep(u32 crc, unsigned long const *ptr) +{ + return (u64)crc ^ (__force u64)__cpu_to_le64(*ptr); +} + +static inline u32 crc32_le_zbc(unsigned long s, u32 poly, unsigned long poly_qt) +{ + u32 crc; + + /* We don't have a "clmulrh" insn, so use clmul + slli instead. */ + asm volatile (".option push\n" + ".option arch,+zbc\n" + "clmul %0, %1, %2\n" + "slli %0, %0, 1\n" + "xor %0, %0, %1\n" + "clmulr %0, %0, %3\n" + "srli %0, %0, 32\n" + ".option pop\n" + : "=&r" (crc) + : "r" (s), + "r" (poly_qt), + "r" ((u64)poly << 32) + :); + return crc; +} + +static inline u64 crc32_be_prep(u32 crc, unsigned long const *ptr) +{ + return ((u64)crc << 32) ^ (__force u64)__cpu_to_be64(*ptr); +} + +#elif __riscv_xlen == 32 +# define STEP_ORDER 2 +/* Each quotient should match the upper half of its analog in RV64 */ +# define CRC32_POLY_QT_LE 0xfb808b20 +# define CRC32C_POLY_QT_LE 0x6f5389f8 +# define CRC32_POLY_QT_BE 0x04d101df + +static inline u32 crc32_le_prep(u32 crc, unsigned long const *ptr) +{ + return crc ^ (__force u32)__cpu_to_le32(*ptr); +} + +static inline u32 crc32_le_zbc(unsigned long s, u32 poly, unsigned long poly_qt) +{ + u32 crc; + + /* We don't have a "clmulrh" insn, so use clmul + slli instead. */ + asm volatile (".option push\n" + ".option arch,+zbc\n" + "clmul %0, %1, %2\n" + "slli %0, %0, 1\n" + "xor %0, %0, %1\n" + "clmulr %0, %0, %3\n" + ".option pop\n" + : "=&r" (crc) + : "r" (s), + "r" (poly_qt), + "r" (poly) + :); + return crc; +} + +static inline u32 crc32_be_prep(u32 crc, unsigned long const *ptr) +{ + return crc ^ (__force u32)__cpu_to_be32(*ptr); +} + +#else +# error "Unexpected __riscv_xlen" +#endif + +static inline u32 crc32_be_zbc(unsigned long s) +{ + u32 crc; + + asm volatile (".option push\n" + ".option arch,+zbc\n" + "clmulh %0, %1, %2\n" + "xor %0, %0, %1\n" + "clmul %0, %0, %3\n" + ".option pop\n" + : "=&r" (crc) + : "r" (s), + "r" (CRC32_POLY_QT_BE), + "r" (CRC32_POLY_BE) + :); + return crc; +} + +#define STEP (1 << STEP_ORDER) +#define OFFSET_MASK (STEP - 1) + +typedef u32 (*fallback)(u32 crc, unsigned char const *p, size_t len); + +static inline u32 crc32_le_unaligned(u32 crc, unsigned char const *p, + size_t len, u32 poly, + unsigned long poly_qt) +{ + size_t bits = len * 8; + unsigned long s = 0; + u32 crc_low = 0; + + for (int i = 0; i < len; i++) + s = ((unsigned long)*p++ << (__riscv_xlen - 8)) | (s >> 8); + + s ^= (unsigned long)crc << (__riscv_xlen - bits); + if (__riscv_xlen == 32 || len < sizeof(u32)) + crc_low = crc >> bits; + + crc = crc32_le_zbc(s, poly, poly_qt); + crc ^= crc_low; + + return crc; +} + +static inline u32 __pure crc32_le_generic(u32 crc, unsigned char const *p, + size_t len, u32 poly, + unsigned long poly_qt, + fallback crc_fb) +{ + size_t offset, head_len, tail_len; + unsigned long const *p_ul; + unsigned long s; + + asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0, + RISCV_ISA_EXT_ZBC, 1) + : : : : legacy); + + /* Handle the unaligned head. */ + offset = (unsigned long)p & OFFSET_MASK; + if (offset && len) { + head_len = min(STEP - offset, len); + crc = crc32_le_unaligned(crc, p, head_len, poly, poly_qt); + p += head_len; + len -= head_len; + } + + tail_len = len & OFFSET_MASK; + len = len >> STEP_ORDER; + p_ul = (unsigned long const *)p; + + for (int i = 0; i < len; i++) { + s = crc32_le_prep(crc, p_ul); + crc = crc32_le_zbc(s, poly, poly_qt); + p_ul++; + } + + /* Handle the tail bytes. */ + p = (unsigned char const *)p_ul; + if (tail_len) + crc = crc32_le_unaligned(crc, p, tail_len, poly, poly_qt); + + return crc; + +legacy: + return crc_fb(crc, p, len); +} + +u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len) +{ + return crc32_le_generic(crc, p, len, CRC32_POLY_LE, CRC32_POLY_QT_LE, + crc32_le_base); +} + +u32 __pure __crc32c_le(u32 crc, unsigned char const *p, size_t len) +{ + return crc32_le_generic(crc, p, len, CRC32C_POLY_LE, + CRC32C_POLY_QT_LE, __crc32c_le_base); +} + +static inline u32 crc32_be_unaligned(u32 crc, unsigned char const *p, + size_t len) +{ + size_t bits = len * 8; + unsigned long s = 0; + u32 crc_low = 0; + + s = 0; + for (int i = 0; i < len; i++) + s = *p++ | (s << 8); + + if (__riscv_xlen == 32 || len < sizeof(u32)) { + s ^= crc >> (32 - bits); + crc_low = crc << bits; + } else { + s ^= (unsigned long)crc << (bits - 32); + } + + crc = crc32_be_zbc(s); + crc ^= crc_low; + + return crc; +} + +u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len) +{ + size_t offset, head_len, tail_len; + unsigned long const *p_ul; + unsigned long s; + + asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0, + RISCV_ISA_EXT_ZBC, 1) + : : : : legacy); + + /* Handle the unaligned head. */ + offset = (unsigned long)p & OFFSET_MASK; + if (offset && len) { + head_len = min(STEP - offset, len); + crc = crc32_be_unaligned(crc, p, head_len); + p += head_len; + len -= head_len; + } + + tail_len = len & OFFSET_MASK; + len = len >> STEP_ORDER; + p_ul = (unsigned long const *)p; + + for (int i = 0; i < len; i++) { + s = crc32_be_prep(crc, p_ul); + crc = crc32_be_zbc(s); + p_ul++; + } + + /* Handle the tail bytes. */ + p = (unsigned char const *)p_ul; + if (tail_len) + crc = crc32_be_unaligned(crc, p, tail_len); + + return crc; + +legacy: + return crc32_be_base(crc, p, len); +} diff --git a/arch/riscv/lib/uaccess.S b/arch/riscv/lib/uaccess.S index 1399d797d81b..6a9f116bb545 100644 --- a/arch/riscv/lib/uaccess.S +++ b/arch/riscv/lib/uaccess.S @@ -14,7 +14,7 @@ SYM_FUNC_START(__asm_copy_to_user) #ifdef CONFIG_RISCV_ISA_V - ALTERNATIVE("j fallback_scalar_usercopy", "nop", 0, RISCV_ISA_EXT_v, CONFIG_RISCV_ISA_V) + ALTERNATIVE("j fallback_scalar_usercopy", "nop", 0, RISCV_ISA_EXT_ZVE32X, CONFIG_RISCV_ISA_V) REG_L t0, riscv_v_usercopy_threshold bltu a2, t0, fallback_scalar_usercopy tail enter_vector_usercopy diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index e3405e4b99af..bfa2dea95354 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -296,7 +297,7 @@ static void __init setup_bootmem(void) } #ifdef CONFIG_MMU -struct pt_alloc_ops pt_ops __initdata; +struct pt_alloc_ops pt_ops __meminitdata; pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_bss; pgd_t trampoline_pg_dir[PTRS_PER_PGD] __page_aligned_bss; @@ -358,7 +359,7 @@ static inline pte_t *__init get_pte_virt_fixmap(phys_addr_t pa) return (pte_t *)set_fixmap_offset(FIX_PTE, pa); } -static inline pte_t *__init get_pte_virt_late(phys_addr_t pa) +static inline pte_t *__meminit get_pte_virt_late(phys_addr_t pa) { return (pte_t *) __va(pa); } @@ -377,7 +378,7 @@ static inline phys_addr_t __init alloc_pte_fixmap(uintptr_t va) return memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); } -static phys_addr_t __init alloc_pte_late(uintptr_t va) +static phys_addr_t __meminit alloc_pte_late(uintptr_t va) { struct ptdesc *ptdesc = pagetable_alloc(GFP_KERNEL & ~__GFP_HIGHMEM, 0); @@ -385,9 +386,8 @@ static phys_addr_t __init alloc_pte_late(uintptr_t va) return __pa((pte_t *)ptdesc_address(ptdesc)); } -static void __init create_pte_mapping(pte_t *ptep, - uintptr_t va, phys_addr_t pa, - phys_addr_t sz, pgprot_t prot) +static void __meminit create_pte_mapping(pte_t *ptep, uintptr_t va, phys_addr_t pa, phys_addr_t sz, + pgprot_t prot) { uintptr_t pte_idx = pte_index(va); @@ -441,7 +441,7 @@ static pmd_t *__init get_pmd_virt_fixmap(phys_addr_t pa) return (pmd_t *)set_fixmap_offset(FIX_PMD, pa); } -static pmd_t *__init get_pmd_virt_late(phys_addr_t pa) +static pmd_t *__meminit get_pmd_virt_late(phys_addr_t pa) { return (pmd_t *) __va(pa); } @@ -458,7 +458,7 @@ static phys_addr_t __init alloc_pmd_fixmap(uintptr_t va) return memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); } -static phys_addr_t __init alloc_pmd_late(uintptr_t va) +static phys_addr_t __meminit alloc_pmd_late(uintptr_t va) { struct ptdesc *ptdesc = pagetable_alloc(GFP_KERNEL & ~__GFP_HIGHMEM, 0); @@ -466,9 +466,9 @@ static phys_addr_t __init alloc_pmd_late(uintptr_t va) return __pa((pmd_t *)ptdesc_address(ptdesc)); } -static void __init create_pmd_mapping(pmd_t *pmdp, - uintptr_t va, phys_addr_t pa, - phys_addr_t sz, pgprot_t prot) +static void __meminit create_pmd_mapping(pmd_t *pmdp, + uintptr_t va, phys_addr_t pa, + phys_addr_t sz, pgprot_t prot) { pte_t *ptep; phys_addr_t pte_phys; @@ -504,7 +504,7 @@ static pud_t *__init get_pud_virt_fixmap(phys_addr_t pa) return (pud_t *)set_fixmap_offset(FIX_PUD, pa); } -static pud_t *__init get_pud_virt_late(phys_addr_t pa) +static pud_t *__meminit get_pud_virt_late(phys_addr_t pa) { return (pud_t *)__va(pa); } @@ -522,7 +522,7 @@ static phys_addr_t __init alloc_pud_fixmap(uintptr_t va) return memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); } -static phys_addr_t alloc_pud_late(uintptr_t va) +static phys_addr_t __meminit alloc_pud_late(uintptr_t va) { unsigned long vaddr; @@ -542,7 +542,7 @@ static p4d_t *__init get_p4d_virt_fixmap(phys_addr_t pa) return (p4d_t *)set_fixmap_offset(FIX_P4D, pa); } -static p4d_t *__init get_p4d_virt_late(phys_addr_t pa) +static p4d_t *__meminit get_p4d_virt_late(phys_addr_t pa) { return (p4d_t *)__va(pa); } @@ -560,7 +560,7 @@ static phys_addr_t __init alloc_p4d_fixmap(uintptr_t va) return memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); } -static phys_addr_t alloc_p4d_late(uintptr_t va) +static phys_addr_t __meminit alloc_p4d_late(uintptr_t va) { unsigned long vaddr; @@ -569,9 +569,8 @@ static phys_addr_t alloc_p4d_late(uintptr_t va) return __pa(vaddr); } -static void __init create_pud_mapping(pud_t *pudp, - uintptr_t va, phys_addr_t pa, - phys_addr_t sz, pgprot_t prot) +static void __meminit create_pud_mapping(pud_t *pudp, uintptr_t va, phys_addr_t pa, phys_addr_t sz, + pgprot_t prot) { pmd_t *nextp; phys_addr_t next_phys; @@ -596,9 +595,8 @@ static void __init create_pud_mapping(pud_t *pudp, create_pmd_mapping(nextp, va, pa, sz, prot); } -static void __init create_p4d_mapping(p4d_t *p4dp, - uintptr_t va, phys_addr_t pa, - phys_addr_t sz, pgprot_t prot) +static void __meminit create_p4d_mapping(p4d_t *p4dp, uintptr_t va, phys_addr_t pa, phys_addr_t sz, + pgprot_t prot) { pud_t *nextp; phys_addr_t next_phys; @@ -654,9 +652,8 @@ static void __init create_p4d_mapping(p4d_t *p4dp, #define create_pmd_mapping(__pmdp, __va, __pa, __sz, __prot) do {} while(0) #endif /* __PAGETABLE_PMD_FOLDED */ -void __init create_pgd_mapping(pgd_t *pgdp, - uintptr_t va, phys_addr_t pa, - phys_addr_t sz, pgprot_t prot) +void __meminit create_pgd_mapping(pgd_t *pgdp, uintptr_t va, phys_addr_t pa, phys_addr_t sz, + pgprot_t prot) { pgd_next_t *nextp; phys_addr_t next_phys; @@ -681,8 +678,7 @@ void __init create_pgd_mapping(pgd_t *pgdp, create_pgd_next_mapping(nextp, va, pa, sz, prot); } -static uintptr_t __init best_map_size(phys_addr_t pa, uintptr_t va, - phys_addr_t size) +static uintptr_t __meminit best_map_size(phys_addr_t pa, uintptr_t va, phys_addr_t size) { if (debug_pagealloc_enabled()) return PAGE_SIZE; @@ -718,7 +714,7 @@ asmlinkage void __init __copy_data(void) #endif #ifdef CONFIG_STRICT_KERNEL_RWX -static __init pgprot_t pgprot_from_va(uintptr_t va) +static __meminit pgprot_t pgprot_from_va(uintptr_t va) { if (is_va_kernel_text(va)) return PAGE_KERNEL_READ_EXEC; @@ -743,7 +739,7 @@ void mark_rodata_ro(void) set_memory_ro); } #else -static __init pgprot_t pgprot_from_va(uintptr_t va) +static __meminit pgprot_t pgprot_from_va(uintptr_t va) { if (IS_ENABLED(CONFIG_64BIT) && !is_kernel_mapping(va)) return PAGE_KERNEL; @@ -1235,9 +1231,8 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) pt_ops_set_fixmap(); } -static void __init create_linear_mapping_range(phys_addr_t start, - phys_addr_t end, - uintptr_t fixed_map_size) +static void __meminit create_linear_mapping_range(phys_addr_t start, phys_addr_t end, + uintptr_t fixed_map_size, const pgprot_t *pgprot) { phys_addr_t pa; uintptr_t va, map_size; @@ -1248,7 +1243,7 @@ static void __init create_linear_mapping_range(phys_addr_t start, best_map_size(pa, va, end - pa); create_pgd_mapping(swapper_pg_dir, va, pa, map_size, - pgprot_from_va(va)); + pgprot ? *pgprot : pgprot_from_va(va)); } } @@ -1292,22 +1287,19 @@ static void __init create_linear_mapping_page_table(void) if (end >= __pa(PAGE_OFFSET) + memory_limit) end = __pa(PAGE_OFFSET) + memory_limit; - create_linear_mapping_range(start, end, 0); + create_linear_mapping_range(start, end, 0, NULL); } #ifdef CONFIG_STRICT_KERNEL_RWX - create_linear_mapping_range(ktext_start, ktext_start + ktext_size, 0); - create_linear_mapping_range(krodata_start, - krodata_start + krodata_size, 0); + create_linear_mapping_range(ktext_start, ktext_start + ktext_size, 0, NULL); + create_linear_mapping_range(krodata_start, krodata_start + krodata_size, 0, NULL); memblock_clear_nomap(ktext_start, ktext_size); memblock_clear_nomap(krodata_start, krodata_size); #endif #ifdef CONFIG_KFENCE - create_linear_mapping_range(kfence_pool, - kfence_pool + KFENCE_POOL_SIZE, - PAGE_SIZE); + create_linear_mapping_range(kfence_pool, kfence_pool + KFENCE_POOL_SIZE, PAGE_SIZE, NULL); memblock_clear_nomap(kfence_pool, KFENCE_POOL_SIZE); #endif @@ -1439,7 +1431,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node, * memory hotplug, we are not able to update all the page tables with * the new PMDs. */ - return vmemmap_populate_hugepages(start, end, node, NULL); + return vmemmap_populate_hugepages(start, end, node, altmap); } #endif @@ -1493,11 +1485,19 @@ failed: panic("Failed to pre-allocate %s pages for %s area\n", lvl, area); } +#define PAGE_END KASAN_SHADOW_START + void __init pgtable_cache_init(void) { preallocate_pgd_pages_range(VMALLOC_START, VMALLOC_END, "vmalloc"); if (IS_ENABLED(CONFIG_MODULES)) preallocate_pgd_pages_range(MODULES_VADDR, MODULES_END, "bpf/modules"); + if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG)) { + preallocate_pgd_pages_range(VMEMMAP_START, VMEMMAP_END, "vmemmap"); + preallocate_pgd_pages_range(PAGE_OFFSET, PAGE_END, "direct map"); + if (IS_ENABLED(CONFIG_KASAN)) + preallocate_pgd_pages_range(KASAN_SHADOW_START, KASAN_SHADOW_END, "kasan"); + } } #endif @@ -1534,3 +1534,270 @@ struct execmem_info __init *execmem_arch_setup(void) } #endif /* CONFIG_MMU */ #endif /* CONFIG_EXECMEM */ + +#ifdef CONFIG_MEMORY_HOTPLUG +static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd) +{ + struct page *page = pmd_page(*pmd); + struct ptdesc *ptdesc = page_ptdesc(page); + pte_t *pte; + int i; + + for (i = 0; i < PTRS_PER_PTE; i++) { + pte = pte_start + i; + if (!pte_none(*pte)) + return; + } + + pagetable_pte_dtor(ptdesc); + if (PageReserved(page)) + free_reserved_page(page); + else + pagetable_free(ptdesc); + pmd_clear(pmd); +} + +static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud) +{ + struct page *page = pud_page(*pud); + struct ptdesc *ptdesc = page_ptdesc(page); + pmd_t *pmd; + int i; + + for (i = 0; i < PTRS_PER_PMD; i++) { + pmd = pmd_start + i; + if (!pmd_none(*pmd)) + return; + } + + pagetable_pmd_dtor(ptdesc); + if (PageReserved(page)) + free_reserved_page(page); + else + pagetable_free(ptdesc); + pud_clear(pud); +} + +static void __meminit free_pud_table(pud_t *pud_start, p4d_t *p4d) +{ + struct page *page = p4d_page(*p4d); + pud_t *pud; + int i; + + for (i = 0; i < PTRS_PER_PUD; i++) { + pud = pud_start + i; + if (!pud_none(*pud)) + return; + } + + if (PageReserved(page)) + free_reserved_page(page); + else + free_pages((unsigned long)page_address(page), 0); + p4d_clear(p4d); +} + +static void __meminit free_vmemmap_storage(struct page *page, size_t size, + struct vmem_altmap *altmap) +{ + int order = get_order(size); + + if (altmap) { + vmem_altmap_free(altmap, size >> PAGE_SHIFT); + return; + } + + if (PageReserved(page)) { + unsigned int nr_pages = 1 << order; + + while (nr_pages--) + free_reserved_page(page++); + return; + } + + free_pages((unsigned long)page_address(page), order); +} + +static void __meminit remove_pte_mapping(pte_t *pte_base, unsigned long addr, unsigned long end, + bool is_vmemmap, struct vmem_altmap *altmap) +{ + unsigned long next; + pte_t *ptep, pte; + + for (; addr < end; addr = next) { + next = (addr + PAGE_SIZE) & PAGE_MASK; + if (next > end) + next = end; + + ptep = pte_base + pte_index(addr); + pte = ptep_get(ptep); + if (!pte_present(*ptep)) + continue; + + pte_clear(&init_mm, addr, ptep); + if (is_vmemmap) + free_vmemmap_storage(pte_page(pte), PAGE_SIZE, altmap); + } +} + +static void __meminit remove_pmd_mapping(pmd_t *pmd_base, unsigned long addr, unsigned long end, + bool is_vmemmap, struct vmem_altmap *altmap) +{ + unsigned long next; + pte_t *pte_base; + pmd_t *pmdp, pmd; + + for (; addr < end; addr = next) { + next = pmd_addr_end(addr, end); + pmdp = pmd_base + pmd_index(addr); + pmd = pmdp_get(pmdp); + if (!pmd_present(pmd)) + continue; + + if (pmd_leaf(pmd)) { + pmd_clear(pmdp); + if (is_vmemmap) + free_vmemmap_storage(pmd_page(pmd), PMD_SIZE, altmap); + continue; + } + + pte_base = (pte_t *)pmd_page_vaddr(*pmdp); + remove_pte_mapping(pte_base, addr, next, is_vmemmap, altmap); + free_pte_table(pte_base, pmdp); + } +} + +static void __meminit remove_pud_mapping(pud_t *pud_base, unsigned long addr, unsigned long end, + bool is_vmemmap, struct vmem_altmap *altmap) +{ + unsigned long next; + pud_t *pudp, pud; + pmd_t *pmd_base; + + for (; addr < end; addr = next) { + next = pud_addr_end(addr, end); + pudp = pud_base + pud_index(addr); + pud = pudp_get(pudp); + if (!pud_present(pud)) + continue; + + if (pud_leaf(pud)) { + if (pgtable_l4_enabled) { + pud_clear(pudp); + if (is_vmemmap) + free_vmemmap_storage(pud_page(pud), PUD_SIZE, altmap); + } + continue; + } + + pmd_base = pmd_offset(pudp, 0); + remove_pmd_mapping(pmd_base, addr, next, is_vmemmap, altmap); + + if (pgtable_l4_enabled) + free_pmd_table(pmd_base, pudp); + } +} + +static void __meminit remove_p4d_mapping(p4d_t *p4d_base, unsigned long addr, unsigned long end, + bool is_vmemmap, struct vmem_altmap *altmap) +{ + unsigned long next; + p4d_t *p4dp, p4d; + pud_t *pud_base; + + for (; addr < end; addr = next) { + next = p4d_addr_end(addr, end); + p4dp = p4d_base + p4d_index(addr); + p4d = p4dp_get(p4dp); + if (!p4d_present(p4d)) + continue; + + if (p4d_leaf(p4d)) { + if (pgtable_l5_enabled) { + p4d_clear(p4dp); + if (is_vmemmap) + free_vmemmap_storage(p4d_page(p4d), P4D_SIZE, altmap); + } + continue; + } + + pud_base = pud_offset(p4dp, 0); + remove_pud_mapping(pud_base, addr, next, is_vmemmap, altmap); + + if (pgtable_l5_enabled) + free_pud_table(pud_base, p4dp); + } +} + +static void __meminit remove_pgd_mapping(unsigned long va, unsigned long end, bool is_vmemmap, + struct vmem_altmap *altmap) +{ + unsigned long addr, next; + p4d_t *p4d_base; + pgd_t *pgd; + + for (addr = va; addr < end; addr = next) { + next = pgd_addr_end(addr, end); + pgd = pgd_offset_k(addr); + + if (!pgd_present(*pgd)) + continue; + + if (pgd_leaf(*pgd)) + continue; + + p4d_base = p4d_offset(pgd, 0); + remove_p4d_mapping(p4d_base, addr, next, is_vmemmap, altmap); + } + + flush_tlb_all(); +} + +static void __meminit remove_linear_mapping(phys_addr_t start, u64 size) +{ + unsigned long va = (unsigned long)__va(start); + unsigned long end = (unsigned long)__va(start + size); + + remove_pgd_mapping(va, end, false, NULL); +} + +struct range arch_get_mappable_range(void) +{ + struct range mhp_range; + + mhp_range.start = __pa(PAGE_OFFSET); + mhp_range.end = __pa(PAGE_END - 1); + return mhp_range; +} + +int __ref arch_add_memory(int nid, u64 start, u64 size, struct mhp_params *params) +{ + int ret = 0; + + create_linear_mapping_range(start, start + size, 0, ¶ms->pgprot); + ret = __add_pages(nid, start >> PAGE_SHIFT, size >> PAGE_SHIFT, params); + if (ret) { + remove_linear_mapping(start, size); + goto out; + } + + max_pfn = PFN_UP(start + size); + max_low_pfn = max_pfn; + + out: + flush_tlb_all(); + return ret; +} + +void __ref arch_remove_memory(u64 start, u64 size, struct vmem_altmap *altmap) +{ + __remove_pages(start >> PAGE_SHIFT, size >> PAGE_SHIFT, altmap); + remove_linear_mapping(start, size); + flush_tlb_all(); +} + +void __ref vmemmap_free(unsigned long start, unsigned long end, struct vmem_altmap *altmap) +{ + remove_pgd_mapping(start, end, true, altmap); +} +#endif /* CONFIG_MEMORY_HOTPLUG */ diff --git a/arch/riscv/mm/ptdump.c b/arch/riscv/mm/ptdump.c index 1289cc6d3700..9d5f657a251b 100644 --- a/arch/riscv/mm/ptdump.c +++ b/arch/riscv/mm/ptdump.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -370,7 +371,9 @@ bool ptdump_check_wx(void) static int ptdump_show(struct seq_file *m, void *v) { + get_online_mems(); ptdump_walk(m, m->private); + put_online_mems(); return 0; } diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 0795efdd3519..99f34409fb60 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -17,6 +17,7 @@ #define RV_MAX_REG_ARGS 8 #define RV_FENTRY_NINSNS 2 +#define RV_FENTRY_NBYTES (RV_FENTRY_NINSNS * 4) /* imm that allows emit_imm to emit max count insns */ #define RV_MAX_COUNT_IMM 0x7FFF7FF7FF7FF7FF @@ -676,7 +677,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type, if (ret) return ret; - if (memcmp(ip, old_insns, RV_FENTRY_NINSNS * 4)) + if (memcmp(ip, old_insns, RV_FENTRY_NBYTES)) return -EFAULT; ret = gen_jump_or_nops(new_addr, ip, new_insns, is_call); @@ -685,8 +686,8 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type, cpus_read_lock(); mutex_lock(&text_mutex); - if (memcmp(ip, new_insns, RV_FENTRY_NINSNS * 4)) - ret = patch_text(ip, new_insns, RV_FENTRY_NINSNS); + if (memcmp(ip, new_insns, RV_FENTRY_NBYTES)) + ret = patch_text(ip, new_insns, RV_FENTRY_NBYTES); mutex_unlock(&text_mutex); cpus_read_unlock(); diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index a0479c4892f8..8e77afbed58e 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -1047,7 +1046,6 @@ extern int kvm_s390_gisc_register(struct kvm *kvm, u32 gisc); extern int kvm_s390_gisc_unregister(struct kvm *kvm, u32 gisc); static inline void kvm_arch_sync_events(struct kvm *kvm) {} -static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} static inline void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot) {} static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {} diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 06a14e717178..0fd96860fc45 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2997,14 +2997,9 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) break; } case KVM_CREATE_IRQCHIP: { - struct kvm_irq_routing_entry routing; - r = -EINVAL; - if (kvm->arch.use_irqchip) { - /* Set up dummy routing. */ - memset(&routing, 0, sizeof(routing)); - r = kvm_set_irq_routing(kvm, &routing, 0, 0); - } + if (kvm->arch.use_irqchip) + r = 0; break; } case KVM_SET_DEVICE_ATTR: { @@ -5033,7 +5028,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) if (vcpu->kvm->arch.pv.dumping) return -EINVAL; - if (kvm_run->immediate_exit) + if (!vcpu->wants_to_run) return -EINTR; if (kvm_run->kvm_valid_regs & ~KVM_SYNC_S390_VALID_FIELDS || @@ -5750,6 +5745,9 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, { gpa_t size; + if (kvm_is_ucontrol(kvm)) + return -EINVAL; + /* When we are protected, we should not change the memory slots */ if (kvm_s390_pv_get_handle(kvm)) return -EINVAL; diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 97a70c2b83ee..89cafea4c41f 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -1304,10 +1304,24 @@ static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) if (rc == -EAGAIN) rc = 0; - if (rc || scb_s->icptcode || signal_pending(current) || - kvm_s390_vcpu_has_irq(vcpu, 0) || - kvm_s390_vcpu_sie_inhibited(vcpu)) + + /* + * Exit the loop if the guest needs to process the intercept + */ + if (rc || scb_s->icptcode) break; + + /* + * Exit the loop if the host needs to process an intercept, + * but rewind the PSW to re-enter SIE once that's completed + * instead of passing a "no action" intercept to the guest. + */ + if (signal_pending(current) || + kvm_s390_vcpu_has_irq(vcpu, 0) || + kvm_s390_vcpu_sie_inhibited(vcpu)) { + kvm_s390_rewind_psw(vcpu, 4); + break; + } cond_resched(); } @@ -1426,8 +1440,10 @@ int kvm_s390_handle_vsie(struct kvm_vcpu *vcpu) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); if (signal_pending(current) || kvm_s390_vcpu_has_irq(vcpu, 0) || - kvm_s390_vcpu_sie_inhibited(vcpu)) + kvm_s390_vcpu_sie_inhibited(vcpu)) { + kvm_s390_rewind_psw(vcpu, 4); return 0; + } vsie_page = get_vsie_page(vcpu->kvm, scb_addr); if (IS_ERR(vsie_page)) diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h index 5187fcf4b610..68ad4f923664 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -9,8 +9,7 @@ BUILD_BUG_ON(1) * "static_call_update()" calls. * * KVM_X86_OP_OPTIONAL() can be used for those functions that can have - * a NULL definition, for example if "static_call_cond()" will be used - * at the call sites. KVM_X86_OP_OPTIONAL_RET0() can be used likewise + * a NULL definition. KVM_X86_OP_OPTIONAL_RET0() can be used likewise * to make a definition optional, but in this case the default will * be __static_call_return0. */ @@ -85,7 +84,6 @@ KVM_X86_OP_OPTIONAL(update_cr8_intercept) KVM_X86_OP(refresh_apicv_exec_ctrl) KVM_X86_OP_OPTIONAL(hwapic_irr_update) KVM_X86_OP_OPTIONAL(hwapic_isr_update) -KVM_X86_OP_OPTIONAL_RET0(guest_apic_has_interrupt) KVM_X86_OP_OPTIONAL(load_eoi_exitmap) KVM_X86_OP_OPTIONAL(set_virtual_apic_mode) KVM_X86_OP_OPTIONAL(set_apic_access_page_addr) @@ -103,7 +101,6 @@ KVM_X86_OP(write_tsc_multiplier) KVM_X86_OP(get_exit_info) KVM_X86_OP(check_intercept) KVM_X86_OP(handle_exit_irqoff) -KVM_X86_OP(sched_in) KVM_X86_OP_OPTIONAL(update_cpu_dirty_logging) KVM_X86_OP_OPTIONAL(vcpu_blocking) KVM_X86_OP_OPTIONAL(vcpu_unblocking) @@ -139,6 +136,9 @@ KVM_X86_OP(vcpu_deliver_sipi_vector) KVM_X86_OP_OPTIONAL_RET0(vcpu_get_apicv_inhibit_reasons); KVM_X86_OP_OPTIONAL(get_untagged_addr) KVM_X86_OP_OPTIONAL(alloc_apic_backing_page) +KVM_X86_OP_OPTIONAL_RET0(gmem_prepare) +KVM_X86_OP_OPTIONAL_RET0(private_max_mapping_level) +KVM_X86_OP_OPTIONAL(gmem_invalidate) #undef KVM_X86_OP #undef KVM_X86_OP_OPTIONAL diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h index f852b13aeefe..9159bf1a4730 100644 --- a/arch/x86/include/asm/kvm-x86-pmu-ops.h +++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h @@ -9,8 +9,7 @@ BUILD_BUG_ON(1) * "static_call_update()" calls. * * KVM_X86_PMU_OP_OPTIONAL() can be used for those functions that can have - * a NULL definition, for example if "static_call_cond()" will be used - * at the call sites. + * a NULL definition. */ KVM_X86_PMU_OP(rdpmc_ecx_to_pmc) KVM_X86_PMU_OP(msr_idx_to_pmc) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f8ca74e7678f..950a03e0181e 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -121,6 +121,7 @@ KVM_ARCH_REQ_FLAGS(31, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) #define KVM_REQ_HV_TLB_FLUSH \ KVM_ARCH_REQ_FLAGS(32, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) +#define KVM_REQ_UPDATE_PROTECTED_GUEST_STATE KVM_ARCH_REQ(34) #define CR0_RESERVED_BITS \ (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \ @@ -159,7 +160,6 @@ #define KVM_MIN_FREE_MMU_PAGES 5 #define KVM_REFILL_PAGES 25 #define KVM_MAX_CPUID_ENTRIES 256 -#define KVM_NR_FIXED_MTRR_REGION 88 #define KVM_NR_VAR_MTRR 8 #define ASYNC_PF_PER_VCPU 64 @@ -533,12 +533,16 @@ struct kvm_pmc { }; /* More counters may conflict with other existing Architectural MSRs */ -#define KVM_INTEL_PMC_MAX_GENERIC 8 -#define MSR_ARCH_PERFMON_PERFCTR_MAX (MSR_ARCH_PERFMON_PERFCTR0 + KVM_INTEL_PMC_MAX_GENERIC - 1) -#define MSR_ARCH_PERFMON_EVENTSEL_MAX (MSR_ARCH_PERFMON_EVENTSEL0 + KVM_INTEL_PMC_MAX_GENERIC - 1) -#define KVM_PMC_MAX_FIXED 3 -#define MSR_ARCH_PERFMON_FIXED_CTR_MAX (MSR_ARCH_PERFMON_FIXED_CTR0 + KVM_PMC_MAX_FIXED - 1) -#define KVM_AMD_PMC_MAX_GENERIC 6 +#define KVM_MAX(a, b) ((a) >= (b) ? (a) : (b)) +#define KVM_MAX_NR_INTEL_GP_COUNTERS 8 +#define KVM_MAX_NR_AMD_GP_COUNTERS 6 +#define KVM_MAX_NR_GP_COUNTERS KVM_MAX(KVM_MAX_NR_INTEL_GP_COUNTERS, \ + KVM_MAX_NR_AMD_GP_COUNTERS) + +#define KVM_MAX_NR_INTEL_FIXED_COUTNERS 3 +#define KVM_MAX_NR_AMD_FIXED_COUTNERS 0 +#define KVM_MAX_NR_FIXED_COUNTERS KVM_MAX(KVM_MAX_NR_INTEL_FIXED_COUTNERS, \ + KVM_MAX_NR_AMD_FIXED_COUTNERS) struct kvm_pmu { u8 version; @@ -546,16 +550,16 @@ struct kvm_pmu { unsigned nr_arch_fixed_counters; unsigned available_event_types; u64 fixed_ctr_ctrl; - u64 fixed_ctr_ctrl_mask; + u64 fixed_ctr_ctrl_rsvd; u64 global_ctrl; u64 global_status; u64 counter_bitmask[2]; - u64 global_ctrl_mask; - u64 global_status_mask; + u64 global_ctrl_rsvd; + u64 global_status_rsvd; u64 reserved_bits; u64 raw_event_mask; - struct kvm_pmc gp_counters[KVM_INTEL_PMC_MAX_GENERIC]; - struct kvm_pmc fixed_counters[KVM_PMC_MAX_FIXED]; + struct kvm_pmc gp_counters[KVM_MAX_NR_GP_COUNTERS]; + struct kvm_pmc fixed_counters[KVM_MAX_NR_FIXED_COUNTERS]; /* * Overlay the bitmap with a 64-bit atomic so that all bits can be @@ -571,9 +575,9 @@ struct kvm_pmu { u64 ds_area; u64 pebs_enable; - u64 pebs_enable_mask; + u64 pebs_enable_rsvd; u64 pebs_data_cfg; - u64 pebs_data_cfg_mask; + u64 pebs_data_cfg_rsvd; /* * If a guest counter is cross-mapped to host counter with different @@ -604,18 +608,12 @@ enum { KVM_DEBUGREG_WONT_EXIT = 2, }; -struct kvm_mtrr_range { - u64 base; - u64 mask; - struct list_head node; -}; - struct kvm_mtrr { - struct kvm_mtrr_range var_ranges[KVM_NR_VAR_MTRR]; - mtrr_type fixed_ranges[KVM_NR_FIXED_MTRR_REGION]; + u64 var[KVM_NR_VAR_MTRR * 2]; + u64 fixed_64k; + u64 fixed_16k[2]; + u64 fixed_4k[8]; u64 deftype; - - struct list_head head; }; /* Hyper-V SynIC timer */ @@ -1207,7 +1205,7 @@ enum kvm_apicv_inhibit { * APIC acceleration is disabled by a module parameter * and/or not supported in hardware. */ - APICV_INHIBIT_REASON_DISABLE, + APICV_INHIBIT_REASON_DISABLED, /* * APIC acceleration is inhibited because AutoEOI feature is @@ -1277,8 +1275,27 @@ enum kvm_apicv_inhibit { * mapping between logical ID and vCPU. */ APICV_INHIBIT_REASON_LOGICAL_ID_ALIASED, + + NR_APICV_INHIBIT_REASONS, }; +#define __APICV_INHIBIT_REASON(reason) \ + { BIT(APICV_INHIBIT_REASON_##reason), #reason } + +#define APICV_INHIBIT_REASONS \ + __APICV_INHIBIT_REASON(DISABLED), \ + __APICV_INHIBIT_REASON(HYPERV), \ + __APICV_INHIBIT_REASON(ABSENT), \ + __APICV_INHIBIT_REASON(BLOCKIRQ), \ + __APICV_INHIBIT_REASON(PHYSICAL_ID_ALIASED), \ + __APICV_INHIBIT_REASON(APIC_ID_MODIFIED), \ + __APICV_INHIBIT_REASON(APIC_BASE_MODIFIED), \ + __APICV_INHIBIT_REASON(NESTED), \ + __APICV_INHIBIT_REASON(IRQWIN), \ + __APICV_INHIBIT_REASON(PIT_REINJ), \ + __APICV_INHIBIT_REASON(SEV), \ + __APICV_INHIBIT_REASON(LOGICAL_ID_ALIASED) + struct kvm_arch { unsigned long n_used_mmu_pages; unsigned long n_requested_mmu_pages; @@ -1364,6 +1381,7 @@ struct kvm_arch { u32 default_tsc_khz; bool user_set_tsc; + u64 apic_bus_cycle_ns; seqcount_raw_spinlock_t pvclock_sc; bool use_master_clock; @@ -1708,13 +1726,11 @@ struct kvm_x86_ops { void (*enable_nmi_window)(struct kvm_vcpu *vcpu); void (*enable_irq_window)(struct kvm_vcpu *vcpu); void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr); - bool (*check_apicv_inhibit_reasons)(enum kvm_apicv_inhibit reason); const unsigned long required_apicv_inhibits; bool allow_apicv_in_x2apic_without_x2apic_virtualization; void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu); void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr); void (*hwapic_isr_update)(int isr); - bool (*guest_apic_has_interrupt)(struct kvm_vcpu *vcpu); void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); void (*set_virtual_apic_mode)(struct kvm_vcpu *vcpu); void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu); @@ -1749,8 +1765,6 @@ struct kvm_x86_ops { struct x86_exception *exception); void (*handle_exit_irqoff)(struct kvm_vcpu *vcpu); - void (*sched_in)(struct kvm_vcpu *vcpu, int cpu); - /* * Size of the CPU's dirty log buffer, i.e. VMX's PML buffer. A zero * value indicates CPU dirty logging is unsupported or disabled. @@ -1812,6 +1826,9 @@ struct kvm_x86_ops { gva_t (*get_untagged_addr)(struct kvm_vcpu *vcpu, gva_t gva, unsigned int flags); void *(*alloc_apic_backing_page)(struct kvm_vcpu *vcpu); + int (*gmem_prepare)(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, int max_order); + void (*gmem_invalidate)(kvm_pfn_t start, kvm_pfn_t end); + int (*private_max_mapping_level)(struct kvm *kvm, kvm_pfn_t pfn); }; struct kvm_x86_nested_ops { @@ -1819,7 +1836,7 @@ struct kvm_x86_nested_ops { bool (*is_exception_vmexit)(struct kvm_vcpu *vcpu, u8 vector, u32 error_code); int (*check_events)(struct kvm_vcpu *vcpu); - bool (*has_events)(struct kvm_vcpu *vcpu); + bool (*has_events)(struct kvm_vcpu *vcpu, bool for_injection); void (*triple_fault)(struct kvm_vcpu *vcpu); int (*get_state)(struct kvm_vcpu *vcpu, struct kvm_nested_state __user *user_kvm_nested_state, @@ -1853,11 +1870,13 @@ struct kvm_arch_async_pf { }; extern u32 __read_mostly kvm_nr_uret_msrs; -extern u64 __read_mostly host_efer; extern bool __read_mostly allow_smaller_maxphyaddr; extern bool __read_mostly enable_apicv; extern struct kvm_x86_ops kvm_x86_ops; +#define kvm_x86_call(func) static_call(kvm_x86_##func) +#define kvm_pmu_call(func) static_call(kvm_x86_pmu_##func) + #define KVM_X86_OP(func) \ DECLARE_STATIC_CALL(kvm_x86_##func, *(((struct kvm_x86_ops *)0)->func)); #define KVM_X86_OP_OPTIONAL KVM_X86_OP @@ -1881,7 +1900,7 @@ void kvm_arch_free_vm(struct kvm *kvm); static inline int kvm_arch_flush_remote_tlbs(struct kvm *kvm) { if (kvm_x86_ops.flush_remote_tlbs && - !static_call(kvm_x86_flush_remote_tlbs)(kvm)) + !kvm_x86_call(flush_remote_tlbs)(kvm)) return 0; else return -ENOTSUPP; @@ -1894,7 +1913,7 @@ static inline int kvm_arch_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, if (!kvm_x86_ops.flush_remote_tlbs_range) return -EOPNOTSUPP; - return static_call(kvm_x86_flush_remote_tlbs_range)(kvm, gfn, nr_pages); + return kvm_x86_call(flush_remote_tlbs_range)(kvm, gfn, nr_pages); } #endif /* CONFIG_HYPERV */ @@ -1939,6 +1958,7 @@ void kvm_mmu_slot_leaf_clear_dirty(struct kvm *kvm, const struct kvm_memory_slot *memslot); void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen); void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned long kvm_nr_mmu_pages); +void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end); int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3); @@ -2292,12 +2312,12 @@ static inline bool kvm_irq_is_postable(struct kvm_lapic_irq *irq) static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) { - static_call_cond(kvm_x86_vcpu_blocking)(vcpu); + kvm_x86_call(vcpu_blocking)(vcpu); } static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) { - static_call_cond(kvm_x86_vcpu_unblocking)(vcpu); + kvm_x86_call(vcpu_unblocking)(vcpu); } static inline int kvm_cpu_get_apicid(int mps_cpu) diff --git a/arch/x86/include/asm/sev-common.h b/arch/x86/include/asm/sev-common.h index e90d403f2068..98726c2b04f8 100644 --- a/arch/x86/include/asm/sev-common.h +++ b/arch/x86/include/asm/sev-common.h @@ -59,6 +59,14 @@ #define GHCB_MSR_AP_RESET_HOLD_RESULT_POS 12 #define GHCB_MSR_AP_RESET_HOLD_RESULT_MASK GENMASK_ULL(51, 0) +/* Preferred GHCB GPA Request */ +#define GHCB_MSR_PREF_GPA_REQ 0x010 +#define GHCB_MSR_GPA_VALUE_POS 12 +#define GHCB_MSR_GPA_VALUE_MASK GENMASK_ULL(51, 0) + +#define GHCB_MSR_PREF_GPA_RESP 0x011 +#define GHCB_MSR_PREF_GPA_NONE 0xfffffffffffff + /* GHCB GPA Register */ #define GHCB_MSR_REG_GPA_REQ 0x012 #define GHCB_MSR_REG_GPA_REQ_VAL(v) \ @@ -93,11 +101,17 @@ enum psc_op { /* GHCBData[11:0] */ \ GHCB_MSR_PSC_REQ) +#define GHCB_MSR_PSC_REQ_TO_GFN(msr) (((msr) & GENMASK_ULL(51, 12)) >> 12) +#define GHCB_MSR_PSC_REQ_TO_OP(msr) (((msr) & GENMASK_ULL(55, 52)) >> 52) + #define GHCB_MSR_PSC_RESP 0x015 #define GHCB_MSR_PSC_RESP_VAL(val) \ /* GHCBData[63:32] */ \ (((u64)(val) & GENMASK_ULL(63, 32)) >> 32) +/* Set highest bit as a generic error response */ +#define GHCB_MSR_PSC_RESP_ERROR (BIT_ULL(63) | GHCB_MSR_PSC_RESP) + /* GHCB Run at VMPL Request/Response */ #define GHCB_MSR_VMPL_REQ 0x016 #define GHCB_MSR_VMPL_REQ_LEVEL(v) \ @@ -129,8 +143,19 @@ enum psc_op { * The VMGEXIT_PSC_MAX_ENTRY determines the size of the PSC structure, which * is a local stack variable in set_pages_state(). Do not increase this value * without evaluating the impact to stack usage. + * + * Use VMGEXIT_PSC_MAX_COUNT in cases where the actual GHCB-defined max value + * is needed, such as when processing GHCB requests on the hypervisor side. */ #define VMGEXIT_PSC_MAX_ENTRY 64 +#define VMGEXIT_PSC_MAX_COUNT 253 + +#define VMGEXIT_PSC_ERROR_GENERIC (0x100UL << 32) +#define VMGEXIT_PSC_ERROR_INVALID_HDR ((1UL << 32) | 1) +#define VMGEXIT_PSC_ERROR_INVALID_ENTRY ((1UL << 32) | 2) + +#define VMGEXIT_PSC_OP_PRIVATE 1 +#define VMGEXIT_PSC_OP_SHARED 2 struct psc_hdr { u16 cur_entry; diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h index ac5886ce252e..79bbe2be900e 100644 --- a/arch/x86/include/asm/sev.h +++ b/arch/x86/include/asm/sev.h @@ -91,6 +91,9 @@ extern bool handle_vc_boot_ghcb(struct pt_regs *regs); /* RMUPDATE detected 4K page and 2MB page overlap. */ #define RMPUPDATE_FAIL_OVERLAP 4 +/* PSMASH failed due to concurrent access by another CPU */ +#define PSMASH_FAIL_INUSE 3 + /* RMP page size */ #define RMP_PG_SIZE_4K 0 #define RMP_PG_SIZE_2M 1 @@ -116,6 +119,54 @@ struct snp_req_data { unsigned int data_npages; }; +#define MAX_AUTHTAG_LEN 32 + +/* See SNP spec SNP_GUEST_REQUEST section for the structure */ +enum msg_type { + SNP_MSG_TYPE_INVALID = 0, + SNP_MSG_CPUID_REQ, + SNP_MSG_CPUID_RSP, + SNP_MSG_KEY_REQ, + SNP_MSG_KEY_RSP, + SNP_MSG_REPORT_REQ, + SNP_MSG_REPORT_RSP, + SNP_MSG_EXPORT_REQ, + SNP_MSG_EXPORT_RSP, + SNP_MSG_IMPORT_REQ, + SNP_MSG_IMPORT_RSP, + SNP_MSG_ABSORB_REQ, + SNP_MSG_ABSORB_RSP, + SNP_MSG_VMRK_REQ, + SNP_MSG_VMRK_RSP, + + SNP_MSG_TYPE_MAX +}; + +enum aead_algo { + SNP_AEAD_INVALID, + SNP_AEAD_AES_256_GCM, +}; + +struct snp_guest_msg_hdr { + u8 authtag[MAX_AUTHTAG_LEN]; + u64 msg_seqno; + u8 rsvd1[8]; + u8 algo; + u8 hdr_version; + u16 hdr_sz; + u8 msg_type; + u8 msg_version; + u16 msg_sz; + u32 rsvd2; + u8 msg_vmpck; + u8 rsvd3[35]; +} __packed; + +struct snp_guest_msg { + struct snp_guest_msg_hdr hdr; + u8 payload[4000]; +} __packed; + struct sev_guest_platform_data { u64 secrets_gpa; }; diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index 728c98175b9c..f0dea3750ca9 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -285,7 +285,14 @@ static_assert((X2AVIC_MAX_PHYSICAL_ID & AVIC_PHYSICAL_MAX_INDEX_MASK) == X2AVIC_ #define AVIC_HPA_MASK ~((0xFFFULL << 52) | 0xFFF) -#define SVM_SEV_FEAT_DEBUG_SWAP BIT(5) +#define SVM_SEV_FEAT_SNP_ACTIVE BIT(0) +#define SVM_SEV_FEAT_RESTRICTED_INJECTION BIT(3) +#define SVM_SEV_FEAT_ALTERNATE_INJECTION BIT(4) +#define SVM_SEV_FEAT_DEBUG_SWAP BIT(5) + +#define SVM_SEV_FEAT_INT_INJ_MODES \ + (SVM_SEV_FEAT_RESTRICTED_INJECTION | \ + SVM_SEV_FEAT_ALTERNATE_INJECTION) struct vmcb_seg { u16 selector; diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 9fae1b73b529..bf57a824f722 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -106,6 +106,7 @@ struct kvm_ioapic_state { #define KVM_RUN_X86_SMM (1 << 0) #define KVM_RUN_X86_BUS_LOCK (1 << 1) +#define KVM_RUN_X86_GUEST_MODE (1 << 2) /* for KVM_GET_REGS and KVM_SET_REGS */ struct kvm_regs { @@ -697,6 +698,11 @@ enum sev_cmd_id { /* Second time is the charm; improved versions of the above ioctls. */ KVM_SEV_INIT2, + /* SNP-specific commands */ + KVM_SEV_SNP_LAUNCH_START = 100, + KVM_SEV_SNP_LAUNCH_UPDATE, + KVM_SEV_SNP_LAUNCH_FINISH, + KVM_SEV_NR_MAX, }; @@ -824,6 +830,48 @@ struct kvm_sev_receive_update_data { __u32 pad2; }; +struct kvm_sev_snp_launch_start { + __u64 policy; + __u8 gosvw[16]; + __u16 flags; + __u8 pad0[6]; + __u64 pad1[4]; +}; + +/* Kept in sync with firmware values for simplicity. */ +#define KVM_SEV_SNP_PAGE_TYPE_NORMAL 0x1 +#define KVM_SEV_SNP_PAGE_TYPE_ZERO 0x3 +#define KVM_SEV_SNP_PAGE_TYPE_UNMEASURED 0x4 +#define KVM_SEV_SNP_PAGE_TYPE_SECRETS 0x5 +#define KVM_SEV_SNP_PAGE_TYPE_CPUID 0x6 + +struct kvm_sev_snp_launch_update { + __u64 gfn_start; + __u64 uaddr; + __u64 len; + __u8 type; + __u8 pad0; + __u16 flags; + __u32 pad1; + __u64 pad2[4]; +}; + +#define KVM_SEV_SNP_ID_BLOCK_SIZE 96 +#define KVM_SEV_SNP_ID_AUTH_SIZE 4096 +#define KVM_SEV_SNP_FINISH_DATA_SIZE 32 + +struct kvm_sev_snp_launch_finish { + __u64 id_block_uaddr; + __u64 id_auth_uaddr; + __u8 id_block_en; + __u8 auth_key_en; + __u8 vcek_disabled; + __u8 host_data[KVM_SEV_SNP_FINISH_DATA_SIZE]; + __u8 pad0[3]; + __u16 flags; + __u64 pad1[4]; +}; + #define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0) #define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1) @@ -874,5 +922,6 @@ struct kvm_hyperv_eventfd { #define KVM_X86_SW_PROTECTED_VM 1 #define KVM_X86_SEV_VM 2 #define KVM_X86_SEV_ES_VM 3 +#define KVM_X86_SNP_VM 4 #endif /* _ASM_X86_KVM_H */ diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index fec95a770270..4287a8071a3a 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -44,6 +44,7 @@ config KVM select KVM_VFIO select HAVE_KVM_PM_NOTIFIER if PM select KVM_GENERIC_HARDWARE_ENABLING + select KVM_GENERIC_PRE_FAULT_MEMORY select KVM_WERROR if WERROR help Support hosting fully virtualized guest machines using hardware @@ -139,6 +140,9 @@ config KVM_AMD_SEV depends on KVM_AMD && X86_64 depends on CRYPTO_DEV_SP_PSP && !(KVM_AMD=y && CRYPTO_DEV_CCP_DD=m) select ARCH_HAS_CC_PLATFORM + select KVM_GENERIC_PRIVATE_MEM + select HAVE_KVM_GMEM_PREPARE + select HAVE_KVM_GMEM_INVALIDATE help Provides support for launching Encrypted VMs (SEV) and Encrypted VMs with Encrypted State (SEV-ES) on AMD processors. diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index f2f2be5d1141..2617be544480 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -335,6 +335,18 @@ static bool kvm_cpuid_has_hyperv(struct kvm_cpuid_entry2 *entries, int nent) #endif } +static bool guest_cpuid_is_amd_or_hygon(struct kvm_vcpu *vcpu) +{ + struct kvm_cpuid_entry2 *entry; + + entry = kvm_find_cpuid_entry(vcpu, 0); + if (!entry) + return false; + + return is_guest_vendor_amd(entry->ebx, entry->ecx, entry->edx) || + is_guest_vendor_hygon(entry->ebx, entry->ecx, entry->edx); +} + static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; @@ -388,7 +400,7 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) vcpu->arch.cpuid_nent)); /* Invoke the vendor callback only after the above state is updated. */ - static_call(kvm_x86_vcpu_after_set_cpuid)(vcpu); + kvm_x86_call(vcpu_after_set_cpuid)(vcpu); /* * Except for the MMU, which needs to do its thing any vendor specific diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index 23dbb9eb277c..41697cca354e 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -102,24 +102,6 @@ static __always_inline void guest_cpuid_clear(struct kvm_vcpu *vcpu, *reg &= ~__feature_bit(x86_feature); } -static inline bool guest_cpuid_is_amd_or_hygon(struct kvm_vcpu *vcpu) -{ - struct kvm_cpuid_entry2 *best; - - best = kvm_find_cpuid_entry(vcpu, 0); - return best && - (is_guest_vendor_amd(best->ebx, best->ecx, best->edx) || - is_guest_vendor_hygon(best->ebx, best->ecx, best->edx)); -} - -static inline bool guest_cpuid_is_intel(struct kvm_vcpu *vcpu) -{ - struct kvm_cpuid_entry2 *best; - - best = kvm_find_cpuid_entry(vcpu, 0); - return best && is_guest_vendor_intel(best->ebx, best->ecx, best->edx); -} - static inline bool guest_cpuid_is_amd_compatible(struct kvm_vcpu *vcpu) { return vcpu->arch.is_amd_compatible; diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index c8cc578646d0..e72aed25d721 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -2354,50 +2354,6 @@ setup_syscalls_segments(struct desc_struct *cs, struct desc_struct *ss) ss->avl = 0; } -static bool vendor_intel(struct x86_emulate_ctxt *ctxt) -{ - u32 eax, ebx, ecx, edx; - - eax = ecx = 0; - ctxt->ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx, true); - return is_guest_vendor_intel(ebx, ecx, edx); -} - -static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt) -{ - const struct x86_emulate_ops *ops = ctxt->ops; - u32 eax, ebx, ecx, edx; - - /* - * syscall should always be enabled in longmode - so only become - * vendor specific (cpuid) if other modes are active... - */ - if (ctxt->mode == X86EMUL_MODE_PROT64) - return true; - - eax = 0x00000000; - ecx = 0x00000000; - ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx, true); - /* - * remark: Intel CPUs only support "syscall" in 64bit longmode. Also a - * 64bit guest with a 32bit compat-app running will #UD !! While this - * behaviour can be fixed (by emulating) into AMD response - CPUs of - * AMD can't behave like Intel. - */ - if (is_guest_vendor_intel(ebx, ecx, edx)) - return false; - - if (is_guest_vendor_amd(ebx, ecx, edx) || - is_guest_vendor_hygon(ebx, ecx, edx)) - return true; - - /* - * default: (not Intel, not AMD, not Hygon), apply Intel's - * stricter rules... - */ - return false; -} - static int em_syscall(struct x86_emulate_ctxt *ctxt) { const struct x86_emulate_ops *ops = ctxt->ops; @@ -2411,7 +2367,15 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt) ctxt->mode == X86EMUL_MODE_VM86) return emulate_ud(ctxt); - if (!(em_syscall_is_enabled(ctxt))) + /* + * Intel compatible CPUs only support SYSCALL in 64-bit mode, whereas + * AMD allows SYSCALL in any flavor of protected mode. Note, it's + * infeasible to emulate Intel behavior when running on AMD hardware, + * as SYSCALL won't fault in the "wrong" mode, i.e. there is no #UD + * for KVM to trap-and-emulate, unlike emulating AMD on Intel. + */ + if (ctxt->mode != X86EMUL_MODE_PROT64 && + ctxt->ops->guest_cpuid_is_intel_compatible(ctxt)) return emulate_ud(ctxt); ops->get_msr(ctxt, MSR_EFER, &efer); @@ -2471,11 +2435,11 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) return emulate_gp(ctxt, 0); /* - * Not recognized on AMD in compat mode (but is recognized in legacy - * mode). + * Intel's architecture allows SYSENTER in compatibility mode, but AMD + * does not. Note, AMD does allow SYSENTER in legacy protected mode. */ - if ((ctxt->mode != X86EMUL_MODE_PROT64) && (efer & EFER_LMA) - && !vendor_intel(ctxt)) + if ((ctxt->mode != X86EMUL_MODE_PROT64) && (efer & EFER_LMA) && + !ctxt->ops->guest_cpuid_is_intel_compatible(ctxt)) return emulate_ud(ctxt); /* sysenter/sysexit have not been tested in 64bit mode. */ @@ -2647,7 +2611,14 @@ static void string_registers_quirk(struct x86_emulate_ctxt *ctxt) * manner when ECX is zero due to REP-string optimizations. */ #ifdef CONFIG_X86_64 - if (ctxt->ad_bytes != 4 || !vendor_intel(ctxt)) + u32 eax, ebx, ecx, edx; + + if (ctxt->ad_bytes != 4) + return; + + eax = ecx = 0; + ctxt->ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx, true); + if (!is_guest_vendor_intel(ebx, ecx, edx)) return; *reg_write(ctxt, VCPU_REGS_RCX) = 0; diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 8a47f8541eab..4f0a94346d00 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1417,7 +1417,7 @@ static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data, } /* vmcall/vmmcall */ - static_call(kvm_x86_patch_hypercall)(vcpu, instructions + i); + kvm_x86_call(patch_hypercall)(vcpu, instructions + i); i += 3; /* ret */ @@ -1737,7 +1737,8 @@ static int kvm_hv_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, data = (u64)vcpu->arch.virtual_tsc_khz * 1000; break; case HV_X64_MSR_APIC_FREQUENCY: - data = APIC_BUS_FREQUENCY; + data = div64_u64(1000000000ULL, + vcpu->kvm->arch.apic_bus_cycle_ns); break; default: kvm_pr_unimpl_rdmsr(vcpu, msr); @@ -1985,7 +1986,7 @@ int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu) */ gva = entries[i] & PAGE_MASK; for (j = 0; j < (entries[i] & ~PAGE_MASK) + 1; j++) - static_call(kvm_x86_flush_tlb_gva)(vcpu, gva + j * PAGE_SIZE); + kvm_x86_call(flush_tlb_gva)(vcpu, gva + j * PAGE_SIZE); ++vcpu->stat.tlb_flush; } @@ -2526,7 +2527,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) * hypercall generates UD from non zero cpl and real mode * per HYPER-V spec */ - if (static_call(kvm_x86_get_cpl)(vcpu) != 0 || !is_protmode(vcpu)) { + if (kvm_x86_call(get_cpl)(vcpu) != 0 || !is_protmode(vcpu)) { kvm_queue_exception(vcpu, UD_VECTOR); return 1; } diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index ad9ca8a60144..3d7eb11d0e45 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c @@ -157,7 +157,7 @@ void __kvm_migrate_timers(struct kvm_vcpu *vcpu) { __kvm_migrate_apic_timer(vcpu); __kvm_migrate_pit_timer(vcpu); - static_call_cond(kvm_x86_migrate_timers)(vcpu); + kvm_x86_call(migrate_timers)(vcpu); } bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args) diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index c2d7cfe82d00..76d46b2f41dd 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h @@ -106,7 +106,6 @@ void __kvm_migrate_timers(struct kvm_vcpu *vcpu); int apic_has_pending_timer(struct kvm_vcpu *vcpu); int kvm_setup_default_irq_routing(struct kvm *kvm); -int kvm_setup_empty_irq_routing(struct kvm *kvm); int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, struct kvm_lapic_irq *irq, struct dest_map *dest_map); diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c index 68f3f6c26046..8136695f7b96 100644 --- a/arch/x86/kvm/irq_comm.c +++ b/arch/x86/kvm/irq_comm.c @@ -395,13 +395,6 @@ int kvm_setup_default_irq_routing(struct kvm *kvm) ARRAY_SIZE(default_routing), 0); } -static const struct kvm_irq_routing_entry empty_routing[] = {}; - -int kvm_setup_empty_irq_routing(struct kvm *kvm) -{ - return kvm_set_irq_routing(kvm, empty_routing, 0, 0); -} - void kvm_arch_post_irq_routing_update(struct kvm *kvm) { if (!irqchip_split(kvm)) diff --git a/arch/x86/kvm/kvm_cache_regs.h b/arch/x86/kvm/kvm_cache_regs.h index 75eae9c4998a..b1eb46e26b2e 100644 --- a/arch/x86/kvm/kvm_cache_regs.h +++ b/arch/x86/kvm/kvm_cache_regs.h @@ -98,7 +98,7 @@ static inline unsigned long kvm_register_read_raw(struct kvm_vcpu *vcpu, int reg return 0; if (!kvm_register_is_available(vcpu, reg)) - static_call(kvm_x86_cache_reg)(vcpu, reg); + kvm_x86_call(cache_reg)(vcpu, reg); return vcpu->arch.regs[reg]; } @@ -138,7 +138,7 @@ static inline u64 kvm_pdptr_read(struct kvm_vcpu *vcpu, int index) might_sleep(); /* on svm */ if (!kvm_register_is_available(vcpu, VCPU_EXREG_PDPTR)) - static_call(kvm_x86_cache_reg)(vcpu, VCPU_EXREG_PDPTR); + kvm_x86_call(cache_reg)(vcpu, VCPU_EXREG_PDPTR); return vcpu->arch.walk_mmu->pdptrs[index]; } @@ -153,7 +153,7 @@ static inline ulong kvm_read_cr0_bits(struct kvm_vcpu *vcpu, ulong mask) ulong tmask = mask & KVM_POSSIBLE_CR0_GUEST_BITS; if ((tmask & vcpu->arch.cr0_guest_owned_bits) && !kvm_register_is_available(vcpu, VCPU_EXREG_CR0)) - static_call(kvm_x86_cache_reg)(vcpu, VCPU_EXREG_CR0); + kvm_x86_call(cache_reg)(vcpu, VCPU_EXREG_CR0); return vcpu->arch.cr0 & mask; } @@ -175,7 +175,7 @@ static inline ulong kvm_read_cr4_bits(struct kvm_vcpu *vcpu, ulong mask) ulong tmask = mask & KVM_POSSIBLE_CR4_GUEST_BITS; if ((tmask & vcpu->arch.cr4_guest_owned_bits) && !kvm_register_is_available(vcpu, VCPU_EXREG_CR4)) - static_call(kvm_x86_cache_reg)(vcpu, VCPU_EXREG_CR4); + kvm_x86_call(cache_reg)(vcpu, VCPU_EXREG_CR4); return vcpu->arch.cr4 & mask; } @@ -190,7 +190,7 @@ static __always_inline bool kvm_is_cr4_bit_set(struct kvm_vcpu *vcpu, static inline ulong kvm_read_cr3(struct kvm_vcpu *vcpu) { if (!kvm_register_is_available(vcpu, VCPU_EXREG_CR3)) - static_call(kvm_x86_cache_reg)(vcpu, VCPU_EXREG_CR3); + kvm_x86_call(cache_reg)(vcpu, VCPU_EXREG_CR3); return vcpu->arch.cr3; } diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h index 29ea4313e1bb..55a18e2f2dcd 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -223,6 +223,7 @@ struct x86_emulate_ops { bool (*guest_has_movbe)(struct x86_emulate_ctxt *ctxt); bool (*guest_has_fxsr)(struct x86_emulate_ctxt *ctxt); bool (*guest_has_rdpid)(struct x86_emulate_ctxt *ctxt); + bool (*guest_cpuid_is_intel_compatible)(struct x86_emulate_ctxt *ctxt); void (*set_nmi_mask)(struct x86_emulate_ctxt *ctxt, bool masked); diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index acd7d48100a1..a7172ba59ad2 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -738,8 +738,8 @@ static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) if (unlikely(apic->apicv_active)) { /* need to update RVI */ kvm_lapic_clear_vector(vec, apic->regs + APIC_IRR); - static_call_cond(kvm_x86_hwapic_irr_update)(apic->vcpu, - apic_find_highest_irr(apic)); + kvm_x86_call(hwapic_irr_update)(apic->vcpu, + apic_find_highest_irr(apic)); } else { apic->irr_pending = false; kvm_lapic_clear_vector(vec, apic->regs + APIC_IRR); @@ -765,7 +765,7 @@ static inline void apic_set_isr(int vec, struct kvm_lapic *apic) * just set SVI. */ if (unlikely(apic->apicv_active)) - static_call_cond(kvm_x86_hwapic_isr_update)(vec); + kvm_x86_call(hwapic_isr_update)(vec); else { ++apic->isr_count; BUG_ON(apic->isr_count > MAX_APIC_VECTOR); @@ -810,7 +810,7 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic) * and must be left alone. */ if (unlikely(apic->apicv_active)) - static_call_cond(kvm_x86_hwapic_isr_update)(apic_find_highest_isr(apic)); + kvm_x86_call(hwapic_isr_update)(apic_find_highest_isr(apic)); else { --apic->isr_count; BUG_ON(apic->isr_count < 0); @@ -946,7 +946,7 @@ static int apic_has_interrupt_for_ppr(struct kvm_lapic *apic, u32 ppr) { int highest_irr; if (kvm_x86_ops.sync_pir_to_irr) - highest_irr = static_call(kvm_x86_sync_pir_to_irr)(apic->vcpu); + highest_irr = kvm_x86_call(sync_pir_to_irr)(apic->vcpu); else highest_irr = apic_find_highest_irr(apic); if (highest_irr == -1 || (highest_irr & 0xF0) <= ppr) @@ -1338,8 +1338,8 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, apic->regs + APIC_TMR); } - static_call(kvm_x86_deliver_interrupt)(apic, delivery_mode, - trig_mode, vector); + kvm_x86_call(deliver_interrupt)(apic, delivery_mode, + trig_mode, vector); break; case APIC_DM_REMRD: @@ -1557,7 +1557,8 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic) remaining = 0; ns = mod_64(ktime_to_ns(remaining), apic->lapic_timer.period); - return div64_u64(ns, (APIC_BUS_CYCLE_NS * apic->divide_count)); + return div64_u64(ns, (apic->vcpu->kvm->arch.apic_bus_cycle_ns * + apic->divide_count)); } static void __report_tpr_access(struct kvm_lapic *apic, bool write) @@ -1973,7 +1974,8 @@ static void start_sw_tscdeadline(struct kvm_lapic *apic) static inline u64 tmict_to_ns(struct kvm_lapic *apic, u32 tmict) { - return (u64)tmict * APIC_BUS_CYCLE_NS * (u64)apic->divide_count; + return (u64)tmict * apic->vcpu->kvm->arch.apic_bus_cycle_ns * + (u64)apic->divide_count; } static void update_target_expiration(struct kvm_lapic *apic, uint32_t old_divisor) @@ -2103,7 +2105,7 @@ static void cancel_hv_timer(struct kvm_lapic *apic) { WARN_ON(preemptible()); WARN_ON(!apic->lapic_timer.hv_timer_in_use); - static_call(kvm_x86_cancel_hv_timer)(apic->vcpu); + kvm_x86_call(cancel_hv_timer)(apic->vcpu); apic->lapic_timer.hv_timer_in_use = false; } @@ -2120,7 +2122,7 @@ static bool start_hv_timer(struct kvm_lapic *apic) if (!ktimer->tscdeadline) return false; - if (static_call(kvm_x86_set_hv_timer)(vcpu, ktimer->tscdeadline, &expired)) + if (kvm_x86_call(set_hv_timer)(vcpu, ktimer->tscdeadline, &expired)) return false; ktimer->hv_timer_in_use = true; @@ -2575,7 +2577,7 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) if ((old_value ^ value) & (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE)) { kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu); - static_call_cond(kvm_x86_set_virtual_apic_mode)(vcpu); + kvm_x86_call(set_virtual_apic_mode)(vcpu); } apic->base_address = apic->vcpu->arch.apic_base & @@ -2685,7 +2687,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event) u64 msr_val; int i; - static_call_cond(kvm_x86_apicv_pre_state_restore)(vcpu); + kvm_x86_call(apicv_pre_state_restore)(vcpu); if (!init_event) { msr_val = APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE; @@ -2740,9 +2742,9 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event) vcpu->arch.pv_eoi.msr_val = 0; apic_update_ppr(apic); if (apic->apicv_active) { - static_call_cond(kvm_x86_apicv_post_state_restore)(vcpu); - static_call_cond(kvm_x86_hwapic_irr_update)(vcpu, -1); - static_call_cond(kvm_x86_hwapic_isr_update)(-1); + kvm_x86_call(apicv_post_state_restore)(vcpu); + kvm_x86_call(hwapic_irr_update)(vcpu, -1); + kvm_x86_call(hwapic_isr_update)(-1); } vcpu->arch.apic_arb_prio = 0; @@ -2838,7 +2840,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu) vcpu->arch.apic = apic; if (kvm_x86_ops.alloc_apic_backing_page) - apic->regs = static_call(kvm_x86_alloc_apic_backing_page)(vcpu); + apic->regs = kvm_x86_call(alloc_apic_backing_page)(vcpu); else apic->regs = (void *)get_zeroed_page(GFP_KERNEL_ACCOUNT); if (!apic->regs) { @@ -3017,7 +3019,7 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s) struct kvm_lapic *apic = vcpu->arch.apic; int r; - static_call_cond(kvm_x86_apicv_pre_state_restore)(vcpu); + kvm_x86_call(apicv_pre_state_restore)(vcpu); kvm_lapic_set_base(vcpu, vcpu->arch.apic_base); /* set SPIV separately to get count of SW disabled APICs right */ @@ -3044,9 +3046,10 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s) kvm_lapic_set_reg(apic, APIC_TMCCT, 0); kvm_apic_update_apicv(vcpu); if (apic->apicv_active) { - static_call_cond(kvm_x86_apicv_post_state_restore)(vcpu); - static_call_cond(kvm_x86_hwapic_irr_update)(vcpu, apic_find_highest_irr(apic)); - static_call_cond(kvm_x86_hwapic_isr_update)(apic_find_highest_isr(apic)); + kvm_x86_call(apicv_post_state_restore)(vcpu); + kvm_x86_call(hwapic_irr_update)(vcpu, + apic_find_highest_irr(apic)); + kvm_x86_call(hwapic_isr_update)(apic_find_highest_isr(apic)); } kvm_make_request(KVM_REQ_EVENT, vcpu); if (ioapic_in_kernel(vcpu->kvm)) @@ -3334,7 +3337,8 @@ int kvm_apic_accept_events(struct kvm_vcpu *vcpu) /* evaluate pending_events before reading the vector */ smp_rmb(); sipi_vector = apic->sipi_vector; - static_call(kvm_x86_vcpu_deliver_sipi_vector)(vcpu, sipi_vector); + kvm_x86_call(vcpu_deliver_sipi_vector)(vcpu, + sipi_vector); vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; } } diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index a69e706b9080..7ef8ae73e82d 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -16,8 +16,7 @@ #define APIC_DEST_NOSHORT 0x0 #define APIC_DEST_MASK 0x800 -#define APIC_BUS_CYCLE_NS 1 -#define APIC_BUS_FREQUENCY (1000000000ULL / APIC_BUS_CYCLE_NS) +#define APIC_BUS_CYCLE_NS_DEFAULT 1 #define APIC_BROADCAST 0xFF #define X2APIC_BROADCAST 0xFFFFFFFFul @@ -236,7 +235,7 @@ static inline bool kvm_apic_has_pending_init_or_sipi(struct kvm_vcpu *vcpu) static inline bool kvm_apic_init_sipi_allowed(struct kvm_vcpu *vcpu) { return !is_smm(vcpu) && - !static_call(kvm_x86_apic_init_signal_blocked)(vcpu); + !kvm_x86_call(apic_init_signal_blocked)(vcpu); } static inline bool kvm_lowest_prio_delivery(struct kvm_lapic_irq *irq) diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 2e454316f2a2..4341e0e28571 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -57,12 +57,6 @@ static __always_inline u64 rsvd_bits(int s, int e) return ((2ULL << (e - s)) - 1) << s; } -/* - * The number of non-reserved physical address bits irrespective of features - * that repurpose legal bits, e.g. MKTME. - */ -extern u8 __read_mostly shadow_phys_bits; - static inline gfn_t kvm_mmu_max_gfn(void) { /* @@ -76,30 +70,11 @@ static inline gfn_t kvm_mmu_max_gfn(void) * than hardware's real MAXPHYADDR. Using the host MAXPHYADDR * disallows such SPTEs entirely and simplifies the TDP MMU. */ - int max_gpa_bits = likely(tdp_enabled) ? shadow_phys_bits : 52; + int max_gpa_bits = likely(tdp_enabled) ? kvm_host.maxphyaddr : 52; return (1ULL << (max_gpa_bits - PAGE_SHIFT)) - 1; } -static inline u8 kvm_get_shadow_phys_bits(void) -{ - /* - * boot_cpu_data.x86_phys_bits is reduced when MKTME or SME are detected - * in CPU detection code, but the processor treats those reduced bits as - * 'keyID' thus they are not reserved bits. Therefore KVM needs to look at - * the physical address bits reported by CPUID. - */ - if (likely(boot_cpu_data.extended_cpuid_level >= 0x80000008)) - return cpuid_eax(0x80000008) & 0xff; - - /* - * Quite weird to have VMX or SVM but not MAXPHYADDR; probably a VM with - * custom CPUID. Proceed with whatever the kernel found since these features - * aren't virtualizable (SME/SEV also require CPUIDs higher than 0x80000008). - */ - return boot_cpu_data.x86_phys_bits; -} - u8 kvm_mmu_get_max_tdp_level(void); void kvm_mmu_set_mmio_spte_mask(u64 mmio_value, u64 mmio_mask, u64 access_mask); @@ -163,8 +138,8 @@ static inline void kvm_mmu_load_pgd(struct kvm_vcpu *vcpu) if (!VALID_PAGE(root_hpa)) return; - static_call(kvm_x86_load_mmu_pgd)(vcpu, root_hpa, - vcpu->arch.mmu->root_role.level); + kvm_x86_call(load_mmu_pgd)(vcpu, root_hpa, + vcpu->arch.mmu->root_role.level); } static inline void kvm_mmu_refresh_passthrough_bits(struct kvm_vcpu *vcpu, @@ -199,7 +174,7 @@ static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, { /* strip nested paging fault error codes */ unsigned int pfec = access; - unsigned long rflags = static_call(kvm_x86_get_rflags)(vcpu); + unsigned long rflags = kvm_x86_call(get_rflags)(vcpu); /* * For explicit supervisor accesses, SMAP is disabled if EFLAGS.AC = 1. @@ -246,14 +221,7 @@ static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, return -(u32)fault & errcode; } -bool __kvm_mmu_honors_guest_mtrrs(bool vm_has_noncoherent_dma); - -static inline bool kvm_mmu_honors_guest_mtrrs(struct kvm *kvm) -{ - return __kvm_mmu_honors_guest_mtrrs(kvm_arch_has_noncoherent_dma(kvm)); -} - -void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end); +bool kvm_mmu_may_ignore_guest_pat(void); int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 8d74bdef68c1..901be9e420a4 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -722,7 +722,7 @@ static gfn_t kvm_mmu_page_get_gfn(struct kvm_mmu_page *sp, int index) if (sp->role.passthrough) return sp->gfn; - if (!sp->role.direct) + if (sp->shadowed_translation) return sp->shadowed_translation[index] >> PAGE_SHIFT; return sp->gfn + (index << ((sp->role.level - 1) * SPTE_LEVEL_BITS)); @@ -736,7 +736,7 @@ static gfn_t kvm_mmu_page_get_gfn(struct kvm_mmu_page *sp, int index) */ static u32 kvm_mmu_page_get_access(struct kvm_mmu_page *sp, int index) { - if (sp_has_gptes(sp)) + if (sp->shadowed_translation) return sp->shadowed_translation[index] & ACC_ALL; /* @@ -757,7 +757,7 @@ static u32 kvm_mmu_page_get_access(struct kvm_mmu_page *sp, int index) static void kvm_mmu_page_set_translation(struct kvm_mmu_page *sp, int index, gfn_t gfn, unsigned int access) { - if (sp_has_gptes(sp)) { + if (sp->shadowed_translation) { sp->shadowed_translation[index] = (gfn << PAGE_SHIFT) | access; return; } @@ -1700,8 +1700,7 @@ static void kvm_mmu_free_shadow_page(struct kvm_mmu_page *sp) hlist_del(&sp->hash_link); list_del(&sp->link); free_page((unsigned long)sp->spt); - if (!sp->role.direct) - free_page((unsigned long)sp->shadowed_translation); + free_page((unsigned long)sp->shadowed_translation); kmem_cache_free(mmu_page_header_cache, sp); } @@ -2203,7 +2202,7 @@ static struct kvm_mmu_page *kvm_mmu_alloc_shadow_page(struct kvm *kvm, sp = kvm_mmu_memory_cache_alloc(caches->page_header_cache); sp->spt = kvm_mmu_memory_cache_alloc(caches->shadow_page_cache); - if (!role.direct) + if (!role.direct && role.level <= KVM_MAX_HUGEPAGE_LEVEL) sp->shadowed_translation = kvm_mmu_memory_cache_alloc(caches->shadowed_info_cache); set_page_private(virt_to_page(sp->spt), (unsigned long)sp); @@ -3308,7 +3307,7 @@ static int kvm_handle_noslot_fault(struct kvm_vcpu *vcpu, return RET_PF_CONTINUE; } -static bool page_fault_can_be_fast(struct kvm_page_fault *fault) +static bool page_fault_can_be_fast(struct kvm *kvm, struct kvm_page_fault *fault) { /* * Page faults with reserved bits set, i.e. faults on MMIO SPTEs, only @@ -3319,6 +3318,26 @@ static bool page_fault_can_be_fast(struct kvm_page_fault *fault) if (fault->rsvd) return false; + /* + * For hardware-protected VMs, certain conditions like attempting to + * perform a write to a page which is not in the state that the guest + * expects it to be in can result in a nested/extended #PF. In this + * case, the below code might misconstrue this situation as being the + * result of a write-protected access, and treat it as a spurious case + * rather than taking any action to satisfy the real source of the #PF + * such as generating a KVM_EXIT_MEMORY_FAULT. This can lead to the + * guest spinning on a #PF indefinitely, so don't attempt the fast path + * in this case. + * + * Note that the kvm_mem_is_private() check might race with an + * attribute update, but this will either result in the guest spinning + * on RET_PF_SPURIOUS until the update completes, or an actual spurious + * case might go down the slow path. Either case will resolve itself. + */ + if (kvm->arch.has_private_mem && + fault->is_private != kvm_mem_is_private(kvm, fault->gfn)) + return false; + /* * #PF can be fast if: * @@ -3419,7 +3438,7 @@ static int fast_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) u64 *sptep; uint retry_count = 0; - if (!page_fault_can_be_fast(fault)) + if (!page_fault_can_be_fast(vcpu->kvm, fault)) return ret; walk_shadow_page_lockless_begin(vcpu); @@ -3428,7 +3447,7 @@ static int fast_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) u64 new_spte; if (tdp_mmu_enabled) - sptep = kvm_tdp_mmu_fast_pf_get_last_sptep(vcpu, fault->addr, &spte); + sptep = kvm_tdp_mmu_fast_pf_get_last_sptep(vcpu, fault->gfn, &spte); else sptep = fast_pf_get_last_sptep(vcpu, fault->addr, &spte); @@ -3438,7 +3457,7 @@ static int fast_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) * available as the vCPU holds a reference to its root(s). */ if (WARN_ON_ONCE(!sptep)) - spte = REMOVED_SPTE; + spte = FROZEN_SPTE; if (!is_shadow_present_pte(spte)) break; @@ -4271,7 +4290,16 @@ void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu, struct kvm_async_pf *work) work->arch.cr3 != kvm_mmu_get_guest_pgd(vcpu, vcpu->arch.mmu)) return; - kvm_mmu_do_page_fault(vcpu, work->cr2_or_gpa, work->arch.error_code, true, NULL); + r = kvm_mmu_do_page_fault(vcpu, work->cr2_or_gpa, work->arch.error_code, + true, NULL, NULL); + + /* + * Account fixed page faults, otherwise they'll never be counted, but + * ignore stats for all other return times. Page-ready "faults" aren't + * truly spurious and never trigger emulation + */ + if (r == RET_PF_FIXED) + vcpu->stat.pf_fixed++; } static inline u8 kvm_max_level_for_order(int order) @@ -4291,6 +4319,25 @@ static inline u8 kvm_max_level_for_order(int order) return PG_LEVEL_4K; } +static u8 kvm_max_private_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, + u8 max_level, int gmem_order) +{ + u8 req_max_level; + + if (max_level == PG_LEVEL_4K) + return PG_LEVEL_4K; + + max_level = min(kvm_max_level_for_order(gmem_order), max_level); + if (max_level == PG_LEVEL_4K) + return PG_LEVEL_4K; + + req_max_level = kvm_x86_call(private_max_mapping_level)(kvm, pfn); + if (req_max_level) + max_level = min(max_level, req_max_level); + + return req_max_level; +} + static int kvm_faultin_pfn_private(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) { @@ -4308,9 +4355,9 @@ static int kvm_faultin_pfn_private(struct kvm_vcpu *vcpu, return r; } - fault->max_level = min(kvm_max_level_for_order(max_order), - fault->max_level); fault->map_writable = !(fault->slot->flags & KVM_MEM_READONLY); + fault->max_level = kvm_max_private_mapping_level(vcpu->kvm, fault->pfn, + fault->max_level, max_order); return RET_PF_CONTINUE; } @@ -4561,7 +4608,10 @@ int kvm_handle_page_fault(struct kvm_vcpu *vcpu, u64 error_code, if (WARN_ON_ONCE(error_code >> 32)) error_code = lower_32_bits(error_code); - /* Ensure the above sanity check also covers KVM-defined flags. */ + /* + * Restrict KVM-defined flags to bits 63:32 so that it's impossible for + * them to conflict with #PF error codes, which are limited to 32 bits. + */ BUILD_BUG_ON(lower_32_bits(PFERR_SYNTHETIC_MASK)); vcpu->arch.l1tf_flush_l1d = true; @@ -4621,38 +4671,23 @@ out_unlock: } #endif -bool __kvm_mmu_honors_guest_mtrrs(bool vm_has_noncoherent_dma) +bool kvm_mmu_may_ignore_guest_pat(void) { /* - * If host MTRRs are ignored (shadow_memtype_mask is non-zero), and the - * VM has non-coherent DMA (DMA doesn't snoop CPU caches), KVM's ABI is - * to honor the memtype from the guest's MTRRs so that guest accesses - * to memory that is DMA'd aren't cached against the guest's wishes. - * - * Note, KVM may still ultimately ignore guest MTRRs for certain PFNs, - * e.g. KVM will force UC memtype for host MMIO. + * When EPT is enabled (shadow_memtype_mask is non-zero), the CPU does + * not support self-snoop (or is affected by an erratum), and the VM + * has non-coherent DMA (DMA doesn't snoop CPU caches), KVM's ABI is to + * honor the memtype from the guest's PAT so that guest accesses to + * memory that is DMA'd aren't cached against the guest's wishes. As a + * result, KVM _may_ ignore guest PAT, whereas without non-coherent DMA, + * KVM _always_ ignores or honors guest PAT, i.e. doesn't toggle SPTE + * bits in response to non-coherent device (un)registration. */ - return vm_has_noncoherent_dma && shadow_memtype_mask; + return !static_cpu_has(X86_FEATURE_SELFSNOOP) && shadow_memtype_mask; } int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) { - /* - * If the guest's MTRRs may be used to compute the "real" memtype, - * restrict the mapping level to ensure KVM uses a consistent memtype - * across the entire mapping. - */ - if (kvm_mmu_honors_guest_mtrrs(vcpu->kvm)) { - for ( ; fault->max_level > PG_LEVEL_4K; --fault->max_level) { - int page_num = KVM_PAGES_PER_HPAGE(fault->max_level); - gfn_t base = gfn_round_for_level(fault->gfn, - fault->max_level); - - if (kvm_mtrr_check_gfn_range_consistency(vcpu, base, page_num)) - break; - } - } - #ifdef CONFIG_X86_64 if (tdp_mmu_enabled) return kvm_tdp_mmu_page_fault(vcpu, fault); @@ -4661,6 +4696,79 @@ int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) return direct_page_fault(vcpu, fault); } +static int kvm_tdp_map_page(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code, + u8 *level) +{ + int r; + + /* + * Restrict to TDP page fault, since that's the only case where the MMU + * is indexed by GPA. + */ + if (vcpu->arch.mmu->page_fault != kvm_tdp_page_fault) + return -EOPNOTSUPP; + + do { + if (signal_pending(current)) + return -EINTR; + cond_resched(); + r = kvm_mmu_do_page_fault(vcpu, gpa, error_code, true, NULL, level); + } while (r == RET_PF_RETRY); + + if (r < 0) + return r; + + switch (r) { + case RET_PF_FIXED: + case RET_PF_SPURIOUS: + return 0; + + case RET_PF_EMULATE: + return -ENOENT; + + case RET_PF_RETRY: + case RET_PF_CONTINUE: + case RET_PF_INVALID: + default: + WARN_ONCE(1, "could not fix page fault during prefault"); + return -EIO; + } +} + +long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, + struct kvm_pre_fault_memory *range) +{ + u64 error_code = PFERR_GUEST_FINAL_MASK; + u8 level = PG_LEVEL_4K; + u64 end; + int r; + + /* + * reload is efficient when called repeatedly, so we can do it on + * every iteration. + */ + kvm_mmu_reload(vcpu); + + if (kvm_arch_has_private_mem(vcpu->kvm) && + kvm_mem_is_private(vcpu->kvm, gpa_to_gfn(range->gpa))) + error_code |= PFERR_PRIVATE_ACCESS; + + /* + * Shadow paging uses GVA for kvm page fault, so restrict to + * two-dimensional paging. + */ + r = kvm_tdp_map_page(vcpu, range->gpa, error_code, &level); + if (r < 0) + return r; + + /* + * If the mapping that covers range->gpa can use a huge page, it + * may start below it or end after range->gpa + range->size. + */ + end = (range->gpa & KVM_HPAGE_MASK(level)) + KVM_HPAGE_SIZE(level); + return min(range->size, end - range->gpa); +} + static void nonpaging_init_context(struct kvm_mmu *context) { context->page_fault = nonpaging_page_fault; @@ -4988,7 +5096,7 @@ static void reset_rsvds_bits_mask_ept(struct kvm_vcpu *vcpu, static inline u64 reserved_hpa_bits(void) { - return rsvd_bits(shadow_phys_bits, 63); + return rsvd_bits(kvm_host.maxphyaddr, 63); } /* @@ -5633,7 +5741,7 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu) * stale entries. Flushing on alloc also allows KVM to skip the TLB * flush when freeing a root (see kvm_tdp_mmu_put_root()). */ - static_call(kvm_x86_flush_tlb_current)(vcpu); + kvm_x86_call(flush_tlb_current)(vcpu); out: return r; } @@ -5886,14 +5994,24 @@ int noinline kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, u64 err } if (r == RET_PF_INVALID) { + vcpu->stat.pf_taken++; + r = kvm_mmu_do_page_fault(vcpu, cr2_or_gpa, error_code, false, - &emulation_type); + &emulation_type, NULL); if (KVM_BUG_ON(r == RET_PF_INVALID, vcpu->kvm)) return -EIO; } if (r < 0) return r; + + if (r == RET_PF_FIXED) + vcpu->stat.pf_fixed++; + else if (r == RET_PF_EMULATE) + vcpu->stat.pf_emulate++; + else if (r == RET_PF_SPURIOUS) + vcpu->stat.pf_spurious++; + if (r != RET_PF_EMULATE) return 1; @@ -5995,7 +6113,7 @@ void kvm_mmu_invalidate_addr(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, if (is_noncanonical_address(addr, vcpu)) return; - static_call(kvm_x86_flush_tlb_gva)(vcpu, addr); + kvm_x86_call(flush_tlb_gva)(vcpu, addr); } if (!mmu->sync_spte) @@ -6787,6 +6905,7 @@ restart: return need_tlb_flush; } +EXPORT_SYMBOL_GPL(kvm_zap_gfn_range); static void kvm_rmap_zap_collapsible_sptes(struct kvm *kvm, const struct kvm_memory_slot *slot) @@ -6917,7 +7036,6 @@ static unsigned long mmu_shrink_scan(struct shrinker *shrink, list_for_each_entry(kvm, &vm_list, vm_list) { int idx; - LIST_HEAD(invalid_list); /* * Never scan more than sc->nr_to_scan VM instances. diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h index ce2fcd19ba6b..1721d97743e9 100644 --- a/arch/x86/kvm/mmu/mmu_internal.h +++ b/arch/x86/kvm/mmu/mmu_internal.h @@ -288,7 +288,8 @@ static inline void kvm_mmu_prepare_memory_fault_exit(struct kvm_vcpu *vcpu, } static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, - u64 err, bool prefetch, int *emulation_type) + u64 err, bool prefetch, + int *emulation_type, u8 *level) { struct kvm_page_fault fault = { .addr = cr2_or_gpa, @@ -318,14 +319,6 @@ static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, fault.slot = kvm_vcpu_gfn_to_memslot(vcpu, fault.gfn); } - /* - * Async #PF "faults", a.k.a. prefetch faults, are not faults from the - * guest perspective and have already been counted at the time of the - * original fault. - */ - if (!prefetch) - vcpu->stat.pf_taken++; - if (IS_ENABLED(CONFIG_MITIGATION_RETPOLINE) && fault.is_tdp) r = kvm_tdp_page_fault(vcpu, &fault); else @@ -344,20 +337,9 @@ static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, if (fault.write_fault_to_shadow_pgtable && emulation_type) *emulation_type |= EMULTYPE_WRITE_PF_TO_SP; + if (level) + *level = fault.goal_level; - /* - * Similar to above, prefetch faults aren't truly spurious, and the - * async #PF path doesn't do emulation. Do count faults that are fixed - * by the async #PF handler though, otherwise they'll never be counted. - */ - if (r == RET_PF_FIXED) - vcpu->stat.pf_fixed++; - else if (prefetch) - ; - else if (r == RET_PF_EMULATE) - vcpu->stat.pf_emulate++; - else if (r == RET_PF_SPURIOUS) - vcpu->stat.pf_spurious++; return r; } diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index d3dbcf382ed2..69941cebb3a8 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -911,7 +911,8 @@ static int FNAME(sync_spte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, int gpa_t pte_gpa; gfn_t gfn; - if (WARN_ON_ONCE(sp->spt[i] == SHADOW_NONPRESENT_VALUE)) + if (WARN_ON_ONCE(sp->spt[i] == SHADOW_NONPRESENT_VALUE || + !sp->shadowed_translation)) return 0; first_pte_gpa = FNAME(get_level1_sp_gpa)(sp); diff --git a/arch/x86/kvm/mmu/spte.c b/arch/x86/kvm/mmu/spte.c index a5e014d7bc62..d4527965e48c 100644 --- a/arch/x86/kvm/mmu/spte.c +++ b/arch/x86/kvm/mmu/spte.c @@ -43,7 +43,25 @@ u64 __read_mostly shadow_acc_track_mask; u64 __read_mostly shadow_nonpresent_or_rsvd_mask; u64 __read_mostly shadow_nonpresent_or_rsvd_lower_gfn_mask; -u8 __read_mostly shadow_phys_bits; +static u8 __init kvm_get_host_maxphyaddr(void) +{ + /* + * boot_cpu_data.x86_phys_bits is reduced when MKTME or SME are detected + * in CPU detection code, but the processor treats those reduced bits as + * 'keyID' thus they are not reserved bits. Therefore KVM needs to look at + * the physical address bits reported by CPUID, i.e. the raw MAXPHYADDR, + * when reasoning about CPU behavior with respect to MAXPHYADDR. + */ + if (likely(boot_cpu_data.extended_cpuid_level >= 0x80000008)) + return cpuid_eax(0x80000008) & 0xff; + + /* + * Quite weird to have VMX or SVM but not MAXPHYADDR; probably a VM with + * custom CPUID. Proceed with whatever the kernel found since these features + * aren't virtualizable (SME/SEV also require CPUIDs higher than 0x80000008). + */ + return boot_cpu_data.x86_phys_bits; +} void __init kvm_mmu_spte_module_init(void) { @@ -55,6 +73,8 @@ void __init kvm_mmu_spte_module_init(void) * will change when the vendor module is (re)loaded. */ allow_mmio_caching = enable_mmio_caching; + + kvm_host.maxphyaddr = kvm_get_host_maxphyaddr(); } static u64 generation_mmio_spte_mask(u64 gen) @@ -190,8 +210,8 @@ bool make_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, spte |= PT_PAGE_SIZE_MASK; if (shadow_memtype_mask) - spte |= static_call(kvm_x86_get_mt_mask)(vcpu, gfn, - kvm_is_mmio_pfn(pfn)); + spte |= kvm_x86_call(get_mt_mask)(vcpu, gfn, + kvm_is_mmio_pfn(pfn)); if (host_writable) spte |= shadow_host_writable_mask; else @@ -271,18 +291,12 @@ static u64 make_spte_executable(u64 spte) * This is used during huge page splitting to build the SPTEs that make up the * new page table. */ -u64 make_huge_page_split_spte(struct kvm *kvm, u64 huge_spte, union kvm_mmu_page_role role, - int index) +u64 make_huge_page_split_spte(struct kvm *kvm, u64 huge_spte, + union kvm_mmu_page_role role, int index) { - u64 child_spte; + u64 child_spte = huge_spte; - if (WARN_ON_ONCE(!is_shadow_present_pte(huge_spte))) - return 0; - - if (WARN_ON_ONCE(!is_large_pte(huge_spte))) - return 0; - - child_spte = huge_spte; + KVM_BUG_ON(!is_shadow_present_pte(huge_spte) || !is_large_pte(huge_spte), kvm); /* * The child_spte already has the base address of the huge page being @@ -383,7 +397,7 @@ void kvm_mmu_set_mmio_spte_mask(u64 mmio_value, u64 mmio_mask, u64 access_mask) * not set any RWX bits. */ if (WARN_ON((mmio_value & mmio_mask) != mmio_value) || - WARN_ON(mmio_value && (REMOVED_SPTE & mmio_mask) == mmio_value)) + WARN_ON(mmio_value && (FROZEN_SPTE & mmio_mask) == mmio_value)) mmio_value = 0; if (!mmio_value) @@ -441,8 +455,6 @@ void kvm_mmu_reset_all_pte_masks(void) u8 low_phys_bits; u64 mask; - shadow_phys_bits = kvm_get_shadow_phys_bits(); - /* * If the CPU has 46 or less physical address bits, then set an * appropriate mask to guard against L1TF attacks. Otherwise, it is @@ -494,7 +506,7 @@ void kvm_mmu_reset_all_pte_masks(void) * 52-bit physical addresses then there are no reserved PA bits in the * PTEs and so the reserved PA approach must be disabled. */ - if (shadow_phys_bits < 52) + if (kvm_host.maxphyaddr < 52) mask = BIT_ULL(51) | PT_PRESENT_MASK; else mask = 0; diff --git a/arch/x86/kvm/mmu/spte.h b/arch/x86/kvm/mmu/spte.h index 52fa004a1fbc..ef793c459b05 100644 --- a/arch/x86/kvm/mmu/spte.h +++ b/arch/x86/kvm/mmu/spte.h @@ -202,7 +202,7 @@ extern u64 __read_mostly shadow_nonpresent_or_rsvd_mask; /* * If a thread running without exclusive control of the MMU lock must perform a - * multi-part operation on an SPTE, it can set the SPTE to REMOVED_SPTE as a + * multi-part operation on an SPTE, it can set the SPTE to FROZEN_SPTE as a * non-present intermediate value. Other threads which encounter this value * should not modify the SPTE. * @@ -212,14 +212,14 @@ extern u64 __read_mostly shadow_nonpresent_or_rsvd_mask; * * Only used by the TDP MMU. */ -#define REMOVED_SPTE (SHADOW_NONPRESENT_VALUE | 0x5a0ULL) +#define FROZEN_SPTE (SHADOW_NONPRESENT_VALUE | 0x5a0ULL) /* Removed SPTEs must not be misconstrued as shadow present PTEs. */ -static_assert(!(REMOVED_SPTE & SPTE_MMU_PRESENT_MASK)); +static_assert(!(FROZEN_SPTE & SPTE_MMU_PRESENT_MASK)); -static inline bool is_removed_spte(u64 spte) +static inline bool is_frozen_spte(u64 spte) { - return spte == REMOVED_SPTE; + return spte == FROZEN_SPTE; } /* Get an SPTE's index into its parent's page table (and the spt array). */ diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 36539c1b36cd..c7dc49ee7388 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -365,8 +365,8 @@ static void handle_removed_pt(struct kvm *kvm, tdp_ptep_t pt, bool shared) * value to the removed SPTE value. */ for (;;) { - old_spte = kvm_tdp_mmu_write_spte_atomic(sptep, REMOVED_SPTE); - if (!is_removed_spte(old_spte)) + old_spte = kvm_tdp_mmu_write_spte_atomic(sptep, FROZEN_SPTE); + if (!is_frozen_spte(old_spte)) break; cpu_relax(); } @@ -397,11 +397,11 @@ static void handle_removed_pt(struct kvm *kvm, tdp_ptep_t pt, bool shared) * No retry is needed in the atomic update path as the * sole concern is dropping a Dirty bit, i.e. no other * task can zap/remove the SPTE as mmu_lock is held for - * write. Marking the SPTE as a removed SPTE is not + * write. Marking the SPTE as a frozen SPTE is not * strictly necessary for the same reason, but using - * the remove SPTE value keeps the shared/exclusive + * the frozen SPTE value keeps the shared/exclusive * paths consistent and allows the handle_changed_spte() - * call below to hardcode the new value to REMOVED_SPTE. + * call below to hardcode the new value to FROZEN_SPTE. * * Note, even though dropping a Dirty bit is the only * scenario where a non-atomic update could result in a @@ -413,10 +413,10 @@ static void handle_removed_pt(struct kvm *kvm, tdp_ptep_t pt, bool shared) * it here. */ old_spte = kvm_tdp_mmu_write_spte(sptep, old_spte, - REMOVED_SPTE, level); + FROZEN_SPTE, level); } handle_changed_spte(kvm, kvm_mmu_page_as_id(sp), gfn, - old_spte, REMOVED_SPTE, level, shared); + old_spte, FROZEN_SPTE, level, shared); } call_rcu(&sp->rcu_head, tdp_mmu_free_sp_rcu_callback); @@ -490,19 +490,19 @@ static void handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn, */ if (!was_present && !is_present) { /* - * If this change does not involve a MMIO SPTE or removed SPTE, + * If this change does not involve a MMIO SPTE or frozen SPTE, * it is unexpected. Log the change, though it should not * impact the guest since both the former and current SPTEs * are nonpresent. */ if (WARN_ON_ONCE(!is_mmio_spte(kvm, old_spte) && !is_mmio_spte(kvm, new_spte) && - !is_removed_spte(new_spte))) + !is_frozen_spte(new_spte))) pr_err("Unexpected SPTE change! Nonpresent SPTEs\n" "should not be replaced with another,\n" "different nonpresent SPTE, unless one or both\n" "are MMIO SPTEs, or the new SPTE is\n" - "a temporary removed SPTE.\n" + "a temporary frozen SPTE.\n" "as_id: %d gfn: %llx old_spte: %llx new_spte: %llx level: %d", as_id, gfn, old_spte, new_spte, level); return; @@ -530,7 +530,8 @@ static void handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn, kvm_set_pfn_accessed(spte_to_pfn(old_spte)); } -static inline int __tdp_mmu_set_spte_atomic(struct tdp_iter *iter, u64 new_spte) +static inline int __must_check __tdp_mmu_set_spte_atomic(struct tdp_iter *iter, + u64 new_spte) { u64 *sptep = rcu_dereference(iter->sptep); @@ -540,7 +541,7 @@ static inline int __tdp_mmu_set_spte_atomic(struct tdp_iter *iter, u64 new_spte) * and pre-checking before inserting a new SPTE is advantageous as it * avoids unnecessary work. */ - WARN_ON_ONCE(iter->yielded || is_removed_spte(iter->old_spte)); + WARN_ON_ONCE(iter->yielded || is_frozen_spte(iter->old_spte)); /* * Note, fast_pf_fix_direct_spte() can also modify TDP MMU SPTEs and @@ -572,9 +573,9 @@ static inline int __tdp_mmu_set_spte_atomic(struct tdp_iter *iter, u64 new_spte) * no side-effects other than setting iter->old_spte to the last * known value of the spte. */ -static inline int tdp_mmu_set_spte_atomic(struct kvm *kvm, - struct tdp_iter *iter, - u64 new_spte) +static inline int __must_check tdp_mmu_set_spte_atomic(struct kvm *kvm, + struct tdp_iter *iter, + u64 new_spte) { int ret; @@ -590,8 +591,8 @@ static inline int tdp_mmu_set_spte_atomic(struct kvm *kvm, return 0; } -static inline int tdp_mmu_zap_spte_atomic(struct kvm *kvm, - struct tdp_iter *iter) +static inline int __must_check tdp_mmu_zap_spte_atomic(struct kvm *kvm, + struct tdp_iter *iter) { int ret; @@ -603,26 +604,26 @@ static inline int tdp_mmu_zap_spte_atomic(struct kvm *kvm, * in its place before the TLBs are flushed. * * Delay processing of the zapped SPTE until after TLBs are flushed and - * the REMOVED_SPTE is replaced (see below). + * the FROZEN_SPTE is replaced (see below). */ - ret = __tdp_mmu_set_spte_atomic(iter, REMOVED_SPTE); + ret = __tdp_mmu_set_spte_atomic(iter, FROZEN_SPTE); if (ret) return ret; kvm_flush_remote_tlbs_gfn(kvm, iter->gfn, iter->level); /* - * No other thread can overwrite the removed SPTE as they must either + * No other thread can overwrite the frozen SPTE as they must either * wait on the MMU lock or use tdp_mmu_set_spte_atomic() which will not - * overwrite the special removed SPTE value. Use the raw write helper to + * overwrite the special frozen SPTE value. Use the raw write helper to * avoid an unnecessary check on volatile bits. */ __kvm_tdp_mmu_write_spte(iter->sptep, SHADOW_NONPRESENT_VALUE); /* * Process the zapped SPTE after flushing TLBs, and after replacing - * REMOVED_SPTE with 0. This minimizes the amount of time vCPUs are - * blocked by the REMOVED_SPTE and reduces contention on the child + * FROZEN_SPTE with 0. This minimizes the amount of time vCPUs are + * blocked by the FROZEN_SPTE and reduces contention on the child * SPTEs. */ handle_changed_spte(kvm, iter->as_id, iter->gfn, iter->old_spte, @@ -652,12 +653,12 @@ static u64 tdp_mmu_set_spte(struct kvm *kvm, int as_id, tdp_ptep_t sptep, /* * No thread should be using this function to set SPTEs to or from the - * temporary removed SPTE value. + * temporary frozen SPTE value. * If operating under the MMU lock in read mode, tdp_mmu_set_spte_atomic * should be used. If operating under the MMU lock in write mode, the - * use of the removed SPTE should not be necessary. + * use of the frozen SPTE should not be necessary. */ - WARN_ON_ONCE(is_removed_spte(old_spte) || is_removed_spte(new_spte)); + WARN_ON_ONCE(is_frozen_spte(old_spte) || is_frozen_spte(new_spte)); old_spte = kvm_tdp_mmu_write_spte(sptep, old_spte, new_spte, level); @@ -1126,7 +1127,7 @@ int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) * If SPTE has been frozen by another thread, just give up and * retry, avoiding unnecessary page table allocation and free. */ - if (is_removed_spte(iter.old_spte)) + if (is_frozen_spte(iter.old_spte)) goto retry; if (iter.level == fault->goal_level) @@ -1339,17 +1340,15 @@ bool kvm_tdp_mmu_wrprot_slot(struct kvm *kvm, return spte_set; } -static struct kvm_mmu_page *__tdp_mmu_alloc_sp_for_split(gfp_t gfp) +static struct kvm_mmu_page *tdp_mmu_alloc_sp_for_split(void) { struct kvm_mmu_page *sp; - gfp |= __GFP_ZERO; - - sp = kmem_cache_alloc(mmu_page_header_cache, gfp); + sp = kmem_cache_zalloc(mmu_page_header_cache, GFP_KERNEL_ACCOUNT); if (!sp) return NULL; - sp->spt = (void *)__get_free_page(gfp); + sp->spt = (void *)get_zeroed_page(GFP_KERNEL_ACCOUNT); if (!sp->spt) { kmem_cache_free(mmu_page_header_cache, sp); return NULL; @@ -1358,47 +1357,6 @@ static struct kvm_mmu_page *__tdp_mmu_alloc_sp_for_split(gfp_t gfp) return sp; } -static struct kvm_mmu_page *tdp_mmu_alloc_sp_for_split(struct kvm *kvm, - struct tdp_iter *iter, - bool shared) -{ - struct kvm_mmu_page *sp; - - kvm_lockdep_assert_mmu_lock_held(kvm, shared); - - /* - * Since we are allocating while under the MMU lock we have to be - * careful about GFP flags. Use GFP_NOWAIT to avoid blocking on direct - * reclaim and to avoid making any filesystem callbacks (which can end - * up invoking KVM MMU notifiers, resulting in a deadlock). - * - * If this allocation fails we drop the lock and retry with reclaim - * allowed. - */ - sp = __tdp_mmu_alloc_sp_for_split(GFP_NOWAIT | __GFP_ACCOUNT); - if (sp) - return sp; - - rcu_read_unlock(); - - if (shared) - read_unlock(&kvm->mmu_lock); - else - write_unlock(&kvm->mmu_lock); - - iter->yielded = true; - sp = __tdp_mmu_alloc_sp_for_split(GFP_KERNEL_ACCOUNT); - - if (shared) - read_lock(&kvm->mmu_lock); - else - write_lock(&kvm->mmu_lock); - - rcu_read_lock(); - - return sp; -} - /* Note, the caller is responsible for initializing @sp. */ static int tdp_mmu_split_huge_page(struct kvm *kvm, struct tdp_iter *iter, struct kvm_mmu_page *sp, bool shared) @@ -1445,7 +1403,6 @@ static int tdp_mmu_split_huge_pages_root(struct kvm *kvm, { struct kvm_mmu_page *sp = NULL; struct tdp_iter iter; - int ret = 0; rcu_read_lock(); @@ -1469,17 +1426,31 @@ retry: continue; if (!sp) { - sp = tdp_mmu_alloc_sp_for_split(kvm, &iter, shared); + rcu_read_unlock(); + + if (shared) + read_unlock(&kvm->mmu_lock); + else + write_unlock(&kvm->mmu_lock); + + sp = tdp_mmu_alloc_sp_for_split(); + + if (shared) + read_lock(&kvm->mmu_lock); + else + write_lock(&kvm->mmu_lock); + if (!sp) { - ret = -ENOMEM; trace_kvm_mmu_split_huge_page(iter.gfn, iter.old_spte, - iter.level, ret); - break; + iter.level, -ENOMEM); + return -ENOMEM; } - if (iter.yielded) - continue; + rcu_read_lock(); + + iter.yielded = true; + continue; } tdp_mmu_init_child_sp(sp, &iter); @@ -1500,7 +1471,7 @@ retry: if (sp) tdp_mmu_free_sp(sp); - return ret; + return 0; } @@ -1801,12 +1772,11 @@ int kvm_tdp_mmu_get_walk(struct kvm_vcpu *vcpu, u64 addr, u64 *sptes, * * WARNING: This function is only intended to be called during fast_page_fault. */ -u64 *kvm_tdp_mmu_fast_pf_get_last_sptep(struct kvm_vcpu *vcpu, u64 addr, +u64 *kvm_tdp_mmu_fast_pf_get_last_sptep(struct kvm_vcpu *vcpu, gfn_t gfn, u64 *spte) { struct tdp_iter iter; struct kvm_mmu *mmu = vcpu->arch.mmu; - gfn_t gfn = addr >> PAGE_SHIFT; tdp_ptep_t sptep = NULL; tdp_mmu_for_each_pte(iter, mmu, gfn, gfn + 1) { diff --git a/arch/x86/kvm/mmu/tdp_mmu.h b/arch/x86/kvm/mmu/tdp_mmu.h index 58b55e61bd33..1b74e058a81c 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.h +++ b/arch/x86/kvm/mmu/tdp_mmu.h @@ -64,7 +64,7 @@ static inline void kvm_tdp_mmu_walk_lockless_end(void) int kvm_tdp_mmu_get_walk(struct kvm_vcpu *vcpu, u64 addr, u64 *sptes, int *root_level); -u64 *kvm_tdp_mmu_fast_pf_get_last_sptep(struct kvm_vcpu *vcpu, u64 addr, +u64 *kvm_tdp_mmu_fast_pf_get_last_sptep(struct kvm_vcpu *vcpu, gfn_t gfn, u64 *spte); #ifdef CONFIG_X86_64 diff --git a/arch/x86/kvm/mtrr.c b/arch/x86/kvm/mtrr.c index a67c28a56417..05490b9d8a43 100644 --- a/arch/x86/kvm/mtrr.c +++ b/arch/x86/kvm/mtrr.c @@ -19,33 +19,21 @@ #include #include "cpuid.h" -#include "mmu.h" -#define IA32_MTRR_DEF_TYPE_E (1ULL << 11) -#define IA32_MTRR_DEF_TYPE_FE (1ULL << 10) -#define IA32_MTRR_DEF_TYPE_TYPE_MASK (0xff) - -static bool is_mtrr_base_msr(unsigned int msr) +static u64 *find_mtrr(struct kvm_vcpu *vcpu, unsigned int msr) { - /* MTRR base MSRs use even numbers, masks use odd numbers. */ - return !(msr & 0x1); -} + int index; -static struct kvm_mtrr_range *var_mtrr_msr_to_range(struct kvm_vcpu *vcpu, - unsigned int msr) -{ - int index = (msr - MTRRphysBase_MSR(0)) / 2; - - return &vcpu->arch.mtrr_state.var_ranges[index]; -} - -static bool msr_mtrr_valid(unsigned msr) -{ switch (msr) { case MTRRphysBase_MSR(0) ... MTRRphysMask_MSR(KVM_NR_VAR_MTRR - 1): + index = msr - MTRRphysBase_MSR(0); + return &vcpu->arch.mtrr_state.var[index]; case MSR_MTRRfix64K_00000: + return &vcpu->arch.mtrr_state.fixed_64k; case MSR_MTRRfix16K_80000: case MSR_MTRRfix16K_A0000: + index = msr - MSR_MTRRfix16K_80000; + return &vcpu->arch.mtrr_state.fixed_16k[index]; case MSR_MTRRfix4K_C0000: case MSR_MTRRfix4K_C8000: case MSR_MTRRfix4K_D0000: @@ -54,10 +42,14 @@ static bool msr_mtrr_valid(unsigned msr) case MSR_MTRRfix4K_E8000: case MSR_MTRRfix4K_F0000: case MSR_MTRRfix4K_F8000: + index = msr - MSR_MTRRfix4K_C0000; + return &vcpu->arch.mtrr_state.fixed_4k[index]; case MSR_MTRRdefType: - return true; + return &vcpu->arch.mtrr_state.deftype; + default: + break; } - return false; + return NULL; } static bool valid_mtrr_type(unsigned t) @@ -70,9 +62,6 @@ static bool kvm_mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data) int i; u64 mask; - if (!msr_mtrr_valid(msr)) - return false; - if (msr == MSR_MTRRdefType) { if (data & ~0xcff) return false; @@ -85,8 +74,9 @@ static bool kvm_mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data) } /* variable MTRRs */ - WARN_ON(!(msr >= MTRRphysBase_MSR(0) && - msr <= MTRRphysMask_MSR(KVM_NR_VAR_MTRR - 1))); + if (WARN_ON_ONCE(!(msr >= MTRRphysBase_MSR(0) && + msr <= MTRRphysMask_MSR(KVM_NR_VAR_MTRR - 1)))) + return false; mask = kvm_vcpu_reserved_gpa_bits_raw(vcpu); if ((msr & 1) == 0) { @@ -94,309 +84,32 @@ static bool kvm_mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data) if (!valid_mtrr_type(data & 0xff)) return false; mask |= 0xf00; - } else + } else { /* MTRR mask */ mask |= 0x7ff; + } return (data & mask) == 0; } -static bool mtrr_is_enabled(struct kvm_mtrr *mtrr_state) -{ - return !!(mtrr_state->deftype & IA32_MTRR_DEF_TYPE_E); -} - -static bool fixed_mtrr_is_enabled(struct kvm_mtrr *mtrr_state) -{ - return !!(mtrr_state->deftype & IA32_MTRR_DEF_TYPE_FE); -} - -static u8 mtrr_default_type(struct kvm_mtrr *mtrr_state) -{ - return mtrr_state->deftype & IA32_MTRR_DEF_TYPE_TYPE_MASK; -} - -static u8 mtrr_disabled_type(struct kvm_vcpu *vcpu) -{ - /* - * Intel SDM 11.11.2.2: all MTRRs are disabled when - * IA32_MTRR_DEF_TYPE.E bit is cleared, and the UC - * memory type is applied to all of physical memory. - * - * However, virtual machines can be run with CPUID such that - * there are no MTRRs. In that case, the firmware will never - * enable MTRRs and it is obviously undesirable to run the - * guest entirely with UC memory and we use WB. - */ - if (guest_cpuid_has(vcpu, X86_FEATURE_MTRR)) - return MTRR_TYPE_UNCACHABLE; - else - return MTRR_TYPE_WRBACK; -} - -/* -* Three terms are used in the following code: -* - segment, it indicates the address segments covered by fixed MTRRs. -* - unit, it corresponds to the MSR entry in the segment. -* - range, a range is covered in one memory cache type. -*/ -struct fixed_mtrr_segment { - u64 start; - u64 end; - - int range_shift; - - /* the start position in kvm_mtrr.fixed_ranges[]. */ - int range_start; -}; - -static struct fixed_mtrr_segment fixed_seg_table[] = { - /* MSR_MTRRfix64K_00000, 1 unit. 64K fixed mtrr. */ - { - .start = 0x0, - .end = 0x80000, - .range_shift = 16, /* 64K */ - .range_start = 0, - }, - - /* - * MSR_MTRRfix16K_80000 ... MSR_MTRRfix16K_A0000, 2 units, - * 16K fixed mtrr. - */ - { - .start = 0x80000, - .end = 0xc0000, - .range_shift = 14, /* 16K */ - .range_start = 8, - }, - - /* - * MSR_MTRRfix4K_C0000 ... MSR_MTRRfix4K_F8000, 8 units, - * 4K fixed mtrr. - */ - { - .start = 0xc0000, - .end = 0x100000, - .range_shift = 12, /* 12K */ - .range_start = 24, - } -}; - -/* - * The size of unit is covered in one MSR, one MSR entry contains - * 8 ranges so that unit size is always 8 * 2^range_shift. - */ -static u64 fixed_mtrr_seg_unit_size(int seg) -{ - return 8 << fixed_seg_table[seg].range_shift; -} - -static bool fixed_msr_to_seg_unit(u32 msr, int *seg, int *unit) -{ - switch (msr) { - case MSR_MTRRfix64K_00000: - *seg = 0; - *unit = 0; - break; - case MSR_MTRRfix16K_80000 ... MSR_MTRRfix16K_A0000: - *seg = 1; - *unit = array_index_nospec( - msr - MSR_MTRRfix16K_80000, - MSR_MTRRfix16K_A0000 - MSR_MTRRfix16K_80000 + 1); - break; - case MSR_MTRRfix4K_C0000 ... MSR_MTRRfix4K_F8000: - *seg = 2; - *unit = array_index_nospec( - msr - MSR_MTRRfix4K_C0000, - MSR_MTRRfix4K_F8000 - MSR_MTRRfix4K_C0000 + 1); - break; - default: - return false; - } - - return true; -} - -static void fixed_mtrr_seg_unit_range(int seg, int unit, u64 *start, u64 *end) -{ - struct fixed_mtrr_segment *mtrr_seg = &fixed_seg_table[seg]; - u64 unit_size = fixed_mtrr_seg_unit_size(seg); - - *start = mtrr_seg->start + unit * unit_size; - *end = *start + unit_size; - WARN_ON(*end > mtrr_seg->end); -} - -static int fixed_mtrr_seg_unit_range_index(int seg, int unit) -{ - struct fixed_mtrr_segment *mtrr_seg = &fixed_seg_table[seg]; - - WARN_ON(mtrr_seg->start + unit * fixed_mtrr_seg_unit_size(seg) - > mtrr_seg->end); - - /* each unit has 8 ranges. */ - return mtrr_seg->range_start + 8 * unit; -} - -static int fixed_mtrr_seg_end_range_index(int seg) -{ - struct fixed_mtrr_segment *mtrr_seg = &fixed_seg_table[seg]; - int n; - - n = (mtrr_seg->end - mtrr_seg->start) >> mtrr_seg->range_shift; - return mtrr_seg->range_start + n - 1; -} - -static bool fixed_msr_to_range(u32 msr, u64 *start, u64 *end) -{ - int seg, unit; - - if (!fixed_msr_to_seg_unit(msr, &seg, &unit)) - return false; - - fixed_mtrr_seg_unit_range(seg, unit, start, end); - return true; -} - -static int fixed_msr_to_range_index(u32 msr) -{ - int seg, unit; - - if (!fixed_msr_to_seg_unit(msr, &seg, &unit)) - return -1; - - return fixed_mtrr_seg_unit_range_index(seg, unit); -} - -static int fixed_mtrr_addr_to_seg(u64 addr) -{ - struct fixed_mtrr_segment *mtrr_seg; - int seg, seg_num = ARRAY_SIZE(fixed_seg_table); - - for (seg = 0; seg < seg_num; seg++) { - mtrr_seg = &fixed_seg_table[seg]; - if (mtrr_seg->start <= addr && addr < mtrr_seg->end) - return seg; - } - - return -1; -} - -static int fixed_mtrr_addr_seg_to_range_index(u64 addr, int seg) -{ - struct fixed_mtrr_segment *mtrr_seg; - int index; - - mtrr_seg = &fixed_seg_table[seg]; - index = mtrr_seg->range_start; - index += (addr - mtrr_seg->start) >> mtrr_seg->range_shift; - return index; -} - -static u64 fixed_mtrr_range_end_addr(int seg, int index) -{ - struct fixed_mtrr_segment *mtrr_seg = &fixed_seg_table[seg]; - int pos = index - mtrr_seg->range_start; - - return mtrr_seg->start + ((pos + 1) << mtrr_seg->range_shift); -} - -static void var_mtrr_range(struct kvm_mtrr_range *range, u64 *start, u64 *end) -{ - u64 mask; - - *start = range->base & PAGE_MASK; - - mask = range->mask & PAGE_MASK; - - /* This cannot overflow because writing to the reserved bits of - * variable MTRRs causes a #GP. - */ - *end = (*start | ~mask) + 1; -} - -static void update_mtrr(struct kvm_vcpu *vcpu, u32 msr) -{ - struct kvm_mtrr *mtrr_state = &vcpu->arch.mtrr_state; - gfn_t start, end; - - if (!kvm_mmu_honors_guest_mtrrs(vcpu->kvm)) - return; - - if (!mtrr_is_enabled(mtrr_state) && msr != MSR_MTRRdefType) - return; - - /* fixed MTRRs. */ - if (fixed_msr_to_range(msr, &start, &end)) { - if (!fixed_mtrr_is_enabled(mtrr_state)) - return; - } else if (msr == MSR_MTRRdefType) { - start = 0x0; - end = ~0ULL; - } else { - /* variable range MTRRs. */ - var_mtrr_range(var_mtrr_msr_to_range(vcpu, msr), &start, &end); - } - - kvm_zap_gfn_range(vcpu->kvm, gpa_to_gfn(start), gpa_to_gfn(end)); -} - -static bool var_mtrr_range_is_valid(struct kvm_mtrr_range *range) -{ - return (range->mask & (1 << 11)) != 0; -} - -static void set_var_mtrr_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data) -{ - struct kvm_mtrr *mtrr_state = &vcpu->arch.mtrr_state; - struct kvm_mtrr_range *tmp, *cur; - - cur = var_mtrr_msr_to_range(vcpu, msr); - - /* remove the entry if it's in the list. */ - if (var_mtrr_range_is_valid(cur)) - list_del(&cur->node); - - /* - * Set all illegal GPA bits in the mask, since those bits must - * implicitly be 0. The bits are then cleared when reading them. - */ - if (is_mtrr_base_msr(msr)) - cur->base = data; - else - cur->mask = data | kvm_vcpu_reserved_gpa_bits_raw(vcpu); - - /* add it to the list if it's enabled. */ - if (var_mtrr_range_is_valid(cur)) { - list_for_each_entry(tmp, &mtrr_state->head, node) - if (cur->base >= tmp->base) - break; - list_add_tail(&cur->node, &tmp->node); - } -} - int kvm_mtrr_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data) { - int index; + u64 *mtrr; + + mtrr = find_mtrr(vcpu, msr); + if (!mtrr) + return 1; if (!kvm_mtrr_valid(vcpu, msr, data)) return 1; - index = fixed_msr_to_range_index(msr); - if (index >= 0) - *(u64 *)&vcpu->arch.mtrr_state.fixed_ranges[index] = data; - else if (msr == MSR_MTRRdefType) - vcpu->arch.mtrr_state.deftype = data; - else - set_var_mtrr_msr(vcpu, msr, data); - - update_mtrr(vcpu, msr); + *mtrr = data; return 0; } int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) { - int index; + u64 *mtrr; /* MSR_MTRRcap is a readonly MSR. */ if (msr == MSR_MTRRcap) { @@ -410,311 +123,10 @@ int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) return 0; } - if (!msr_mtrr_valid(msr)) + mtrr = find_mtrr(vcpu, msr); + if (!mtrr) return 1; - index = fixed_msr_to_range_index(msr); - if (index >= 0) { - *pdata = *(u64 *)&vcpu->arch.mtrr_state.fixed_ranges[index]; - } else if (msr == MSR_MTRRdefType) { - *pdata = vcpu->arch.mtrr_state.deftype; - } else { - /* Variable MTRRs */ - if (is_mtrr_base_msr(msr)) - *pdata = var_mtrr_msr_to_range(vcpu, msr)->base; - else - *pdata = var_mtrr_msr_to_range(vcpu, msr)->mask; - - *pdata &= ~kvm_vcpu_reserved_gpa_bits_raw(vcpu); - } - + *pdata = *mtrr; return 0; } - -void kvm_vcpu_mtrr_init(struct kvm_vcpu *vcpu) -{ - INIT_LIST_HEAD(&vcpu->arch.mtrr_state.head); -} - -struct mtrr_iter { - /* input fields. */ - struct kvm_mtrr *mtrr_state; - u64 start; - u64 end; - - /* output fields. */ - int mem_type; - /* mtrr is completely disabled? */ - bool mtrr_disabled; - /* [start, end) is not fully covered in MTRRs? */ - bool partial_map; - - /* private fields. */ - union { - /* used for fixed MTRRs. */ - struct { - int index; - int seg; - }; - - /* used for var MTRRs. */ - struct { - struct kvm_mtrr_range *range; - /* max address has been covered in var MTRRs. */ - u64 start_max; - }; - }; - - bool fixed; -}; - -static bool mtrr_lookup_fixed_start(struct mtrr_iter *iter) -{ - int seg, index; - - if (!fixed_mtrr_is_enabled(iter->mtrr_state)) - return false; - - seg = fixed_mtrr_addr_to_seg(iter->start); - if (seg < 0) - return false; - - iter->fixed = true; - index = fixed_mtrr_addr_seg_to_range_index(iter->start, seg); - iter->index = index; - iter->seg = seg; - return true; -} - -static bool match_var_range(struct mtrr_iter *iter, - struct kvm_mtrr_range *range) -{ - u64 start, end; - - var_mtrr_range(range, &start, &end); - if (!(start >= iter->end || end <= iter->start)) { - iter->range = range; - - /* - * the function is called when we do kvm_mtrr.head walking. - * Range has the minimum base address which interleaves - * [looker->start_max, looker->end). - */ - iter->partial_map |= iter->start_max < start; - - /* update the max address has been covered. */ - iter->start_max = max(iter->start_max, end); - return true; - } - - return false; -} - -static void __mtrr_lookup_var_next(struct mtrr_iter *iter) -{ - struct kvm_mtrr *mtrr_state = iter->mtrr_state; - - list_for_each_entry_continue(iter->range, &mtrr_state->head, node) - if (match_var_range(iter, iter->range)) - return; - - iter->range = NULL; - iter->partial_map |= iter->start_max < iter->end; -} - -static void mtrr_lookup_var_start(struct mtrr_iter *iter) -{ - struct kvm_mtrr *mtrr_state = iter->mtrr_state; - - iter->fixed = false; - iter->start_max = iter->start; - iter->range = NULL; - iter->range = list_prepare_entry(iter->range, &mtrr_state->head, node); - - __mtrr_lookup_var_next(iter); -} - -static void mtrr_lookup_fixed_next(struct mtrr_iter *iter) -{ - /* terminate the lookup. */ - if (fixed_mtrr_range_end_addr(iter->seg, iter->index) >= iter->end) { - iter->fixed = false; - iter->range = NULL; - return; - } - - iter->index++; - - /* have looked up for all fixed MTRRs. */ - if (iter->index >= ARRAY_SIZE(iter->mtrr_state->fixed_ranges)) - return mtrr_lookup_var_start(iter); - - /* switch to next segment. */ - if (iter->index > fixed_mtrr_seg_end_range_index(iter->seg)) - iter->seg++; -} - -static void mtrr_lookup_var_next(struct mtrr_iter *iter) -{ - __mtrr_lookup_var_next(iter); -} - -static void mtrr_lookup_start(struct mtrr_iter *iter) -{ - if (!mtrr_is_enabled(iter->mtrr_state)) { - iter->mtrr_disabled = true; - return; - } - - if (!mtrr_lookup_fixed_start(iter)) - mtrr_lookup_var_start(iter); -} - -static void mtrr_lookup_init(struct mtrr_iter *iter, - struct kvm_mtrr *mtrr_state, u64 start, u64 end) -{ - iter->mtrr_state = mtrr_state; - iter->start = start; - iter->end = end; - iter->mtrr_disabled = false; - iter->partial_map = false; - iter->fixed = false; - iter->range = NULL; - - mtrr_lookup_start(iter); -} - -static bool mtrr_lookup_okay(struct mtrr_iter *iter) -{ - if (iter->fixed) { - iter->mem_type = iter->mtrr_state->fixed_ranges[iter->index]; - return true; - } - - if (iter->range) { - iter->mem_type = iter->range->base & 0xff; - return true; - } - - return false; -} - -static void mtrr_lookup_next(struct mtrr_iter *iter) -{ - if (iter->fixed) - mtrr_lookup_fixed_next(iter); - else - mtrr_lookup_var_next(iter); -} - -#define mtrr_for_each_mem_type(_iter_, _mtrr_, _gpa_start_, _gpa_end_) \ - for (mtrr_lookup_init(_iter_, _mtrr_, _gpa_start_, _gpa_end_); \ - mtrr_lookup_okay(_iter_); mtrr_lookup_next(_iter_)) - -u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn) -{ - struct kvm_mtrr *mtrr_state = &vcpu->arch.mtrr_state; - struct mtrr_iter iter; - u64 start, end; - int type = -1; - const int wt_wb_mask = (1 << MTRR_TYPE_WRBACK) - | (1 << MTRR_TYPE_WRTHROUGH); - - start = gfn_to_gpa(gfn); - end = start + PAGE_SIZE; - - mtrr_for_each_mem_type(&iter, mtrr_state, start, end) { - int curr_type = iter.mem_type; - - /* - * Please refer to Intel SDM Volume 3: 11.11.4.1 MTRR - * Precedences. - */ - - if (type == -1) { - type = curr_type; - continue; - } - - /* - * If two or more variable memory ranges match and the - * memory types are identical, then that memory type is - * used. - */ - if (type == curr_type) - continue; - - /* - * If two or more variable memory ranges match and one of - * the memory types is UC, the UC memory type used. - */ - if (curr_type == MTRR_TYPE_UNCACHABLE) - return MTRR_TYPE_UNCACHABLE; - - /* - * If two or more variable memory ranges match and the - * memory types are WT and WB, the WT memory type is used. - */ - if (((1 << type) & wt_wb_mask) && - ((1 << curr_type) & wt_wb_mask)) { - type = MTRR_TYPE_WRTHROUGH; - continue; - } - - /* - * For overlaps not defined by the above rules, processor - * behavior is undefined. - */ - - /* We use WB for this undefined behavior. :( */ - return MTRR_TYPE_WRBACK; - } - - if (iter.mtrr_disabled) - return mtrr_disabled_type(vcpu); - - /* not contained in any MTRRs. */ - if (type == -1) - return mtrr_default_type(mtrr_state); - - /* - * We just check one page, partially covered by MTRRs is - * impossible. - */ - WARN_ON(iter.partial_map); - - return type; -} -EXPORT_SYMBOL_GPL(kvm_mtrr_get_guest_memory_type); - -bool kvm_mtrr_check_gfn_range_consistency(struct kvm_vcpu *vcpu, gfn_t gfn, - int page_num) -{ - struct kvm_mtrr *mtrr_state = &vcpu->arch.mtrr_state; - struct mtrr_iter iter; - u64 start, end; - int type = -1; - - start = gfn_to_gpa(gfn); - end = gfn_to_gpa(gfn + page_num); - mtrr_for_each_mem_type(&iter, mtrr_state, start, end) { - if (type == -1) { - type = iter.mem_type; - continue; - } - - if (type != iter.mem_type) - return false; - } - - if (iter.mtrr_disabled) - return true; - - if (!iter.partial_map) - return true; - - if (type == -1) - return true; - - return type == mtrr_default_type(mtrr_state); -} diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index a593b03c9aed..47a46283c866 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -34,16 +34,16 @@ EXPORT_SYMBOL_GPL(kvm_pmu_eventsel); /* Precise Distribution of Instructions Retired (PDIR) */ static const struct x86_cpu_id vmx_pebs_pdir_cpu[] = { - X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, NULL), - X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, NULL), + X86_MATCH_VFM(INTEL_ICELAKE_D, NULL), + X86_MATCH_VFM(INTEL_ICELAKE_X, NULL), /* Instruction-Accurate PDIR (PDIR++) */ - X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, NULL), + X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, NULL), {} }; /* Precise Distribution (PDist) */ static const struct x86_cpu_id vmx_pebs_pdist_cpu[] = { - X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, NULL), + X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, NULL), {} }; @@ -69,7 +69,7 @@ static const struct x86_cpu_id vmx_pebs_pdist_cpu[] = { * code. Each pmc, stored in kvm_pmc.idx field, is unique across * all perf counters (both gp and fixed). The mapping relationship * between pmc and perf counters is as the following: - * * Intel: [0 .. KVM_INTEL_PMC_MAX_GENERIC-1] <=> gp counters + * * Intel: [0 .. KVM_MAX_NR_INTEL_GP_COUNTERS-1] <=> gp counters * [KVM_FIXED_PMC_BASE_IDX .. KVM_FIXED_PMC_BASE_IDX + 2] <=> fixed * * AMD: [0 .. AMD64_NUM_COUNTERS-1] and, for families 15H * and later, [0 .. AMD64_NUM_COUNTERS_CORE-1] <=> gp counters @@ -194,7 +194,7 @@ static int pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, u64 config, attr.sample_period = get_sample_period(pmc, pmc->counter); if ((attr.config & HSW_IN_TX_CHECKPOINTED) && - guest_cpuid_is_intel(pmc->vcpu)) { + (boot_cpu_has(X86_FEATURE_RTM) || boot_cpu_has(X86_FEATURE_HLE))) { /* * HSW_IN_TX_CHECKPOINTED is not supported with nonzero * period. Just clear the sample period so at least @@ -469,11 +469,11 @@ static int reprogram_counter(struct kvm_pmc *pmc) if (pmc_is_fixed(pmc)) { fixed_ctr_ctrl = fixed_ctrl_field(pmu->fixed_ctr_ctrl, pmc->idx - KVM_FIXED_PMC_BASE_IDX); - if (fixed_ctr_ctrl & 0x1) + if (fixed_ctr_ctrl & INTEL_FIXED_0_KERNEL) eventsel |= ARCH_PERFMON_EVENTSEL_OS; - if (fixed_ctr_ctrl & 0x2) + if (fixed_ctr_ctrl & INTEL_FIXED_0_USER) eventsel |= ARCH_PERFMON_EVENTSEL_USR; - if (fixed_ctr_ctrl & 0x8) + if (fixed_ctr_ctrl & INTEL_FIXED_0_ENABLE_PMI) eventsel |= ARCH_PERFMON_EVENTSEL_INT; new_config = (u64)fixed_ctr_ctrl; } @@ -521,9 +521,9 @@ void kvm_pmu_handle_event(struct kvm_vcpu *vcpu) } /* - * Unused perf_events are only released if the corresponding MSRs - * weren't accessed during the last vCPU time slice. kvm_arch_sched_in - * triggers KVM_REQ_PMU if cleanup is needed. + * Release unused perf_events if the corresponding guest MSRs weren't + * accessed during the last vCPU time slice (need_cleanup is set when + * the vCPU is scheduled back in). */ if (unlikely(pmu->need_cleanup)) kvm_pmu_cleanup(vcpu); @@ -542,7 +542,7 @@ int kvm_pmu_check_rdpmc_early(struct kvm_vcpu *vcpu, unsigned int idx) if (!kvm_pmu_ops.check_rdpmc_early) return 0; - return static_call(kvm_x86_pmu_check_rdpmc_early)(vcpu, idx); + return kvm_pmu_call(check_rdpmc_early)(vcpu, idx); } bool is_vmware_backdoor_pmc(u32 pmc_idx) @@ -591,12 +591,12 @@ int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data) if (is_vmware_backdoor_pmc(idx)) return kvm_pmu_rdpmc_vmware(vcpu, idx, data); - pmc = static_call(kvm_x86_pmu_rdpmc_ecx_to_pmc)(vcpu, idx, &mask); + pmc = kvm_pmu_call(rdpmc_ecx_to_pmc)(vcpu, idx, &mask); if (!pmc) return 1; if (!kvm_is_cr4_bit_set(vcpu, X86_CR4_PCE) && - (static_call(kvm_x86_get_cpl)(vcpu) != 0) && + (kvm_x86_call(get_cpl)(vcpu) != 0) && kvm_is_cr0_bit_set(vcpu, X86_CR0_PE)) return 1; @@ -607,7 +607,7 @@ int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data) void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu) { if (lapic_in_kernel(vcpu)) { - static_call_cond(kvm_x86_pmu_deliver_pmi)(vcpu); + kvm_pmu_call(deliver_pmi)(vcpu); kvm_apic_local_deliver(vcpu->arch.apic, APIC_LVTPC); } } @@ -622,14 +622,14 @@ bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) default: break; } - return static_call(kvm_x86_pmu_msr_idx_to_pmc)(vcpu, msr) || - static_call(kvm_x86_pmu_is_valid_msr)(vcpu, msr); + return kvm_pmu_call(msr_idx_to_pmc)(vcpu, msr) || + kvm_pmu_call(is_valid_msr)(vcpu, msr); } static void kvm_pmu_mark_pmc_in_use(struct kvm_vcpu *vcpu, u32 msr) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); - struct kvm_pmc *pmc = static_call(kvm_x86_pmu_msr_idx_to_pmc)(vcpu, msr); + struct kvm_pmc *pmc = kvm_pmu_call(msr_idx_to_pmc)(vcpu, msr); if (pmc) __set_bit(pmc->idx, pmu->pmc_in_use); @@ -654,7 +654,7 @@ int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = 0; break; default: - return static_call(kvm_x86_pmu_get_msr)(vcpu, msr_info); + return kvm_pmu_call(get_msr)(vcpu, msr_info); } return 0; @@ -681,13 +681,13 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (!msr_info->host_initiated) break; - if (data & pmu->global_status_mask) + if (data & pmu->global_status_rsvd) return 1; pmu->global_status = data; break; case MSR_AMD64_PERF_CNTR_GLOBAL_CTL: - data &= ~pmu->global_ctrl_mask; + data &= ~pmu->global_ctrl_rsvd; fallthrough; case MSR_CORE_PERF_GLOBAL_CTRL: if (!kvm_valid_perf_global_ctrl(pmu, data)) @@ -704,7 +704,7 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) * GLOBAL_OVF_CTRL, a.k.a. GLOBAL STATUS_RESET, clears bits in * GLOBAL_STATUS, and so the set of reserved bits is the same. */ - if (data & pmu->global_status_mask) + if (data & pmu->global_status_rsvd) return 1; fallthrough; case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR: @@ -713,7 +713,7 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; default: kvm_pmu_mark_pmc_in_use(vcpu, msr_info->index); - return static_call(kvm_x86_pmu_set_msr)(vcpu, msr_info); + return kvm_pmu_call(set_msr)(vcpu, msr_info); } return 0; @@ -740,7 +740,7 @@ static void kvm_pmu_reset(struct kvm_vcpu *vcpu) pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status = 0; - static_call_cond(kvm_x86_pmu_reset)(vcpu); + kvm_pmu_call(reset)(vcpu); } @@ -768,17 +768,17 @@ void kvm_pmu_refresh(struct kvm_vcpu *vcpu) pmu->counter_bitmask[KVM_PMC_FIXED] = 0; pmu->reserved_bits = 0xffffffff00200000ull; pmu->raw_event_mask = X86_RAW_EVENT_MASK; - pmu->global_ctrl_mask = ~0ull; - pmu->global_status_mask = ~0ull; - pmu->fixed_ctr_ctrl_mask = ~0ull; - pmu->pebs_enable_mask = ~0ull; - pmu->pebs_data_cfg_mask = ~0ull; + pmu->global_ctrl_rsvd = ~0ull; + pmu->global_status_rsvd = ~0ull; + pmu->fixed_ctr_ctrl_rsvd = ~0ull; + pmu->pebs_enable_rsvd = ~0ull; + pmu->pebs_data_cfg_rsvd = ~0ull; bitmap_zero(pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX); if (!vcpu->kvm->arch.enable_pmu) return; - static_call(kvm_x86_pmu_refresh)(vcpu); + kvm_pmu_call(refresh)(vcpu); /* * At RESET, both Intel and AMD CPUs set all enable bits for general @@ -796,7 +796,7 @@ void kvm_pmu_init(struct kvm_vcpu *vcpu) struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); memset(pmu, 0, sizeof(*pmu)); - static_call(kvm_x86_pmu_init)(vcpu); + kvm_pmu_call(init)(vcpu); kvm_pmu_refresh(vcpu); } @@ -818,7 +818,7 @@ void kvm_pmu_cleanup(struct kvm_vcpu *vcpu) pmc_stop_counter(pmc); } - static_call_cond(kvm_x86_pmu_cleanup)(vcpu); + kvm_pmu_call(cleanup)(vcpu); bitmap_zero(pmu->pmc_in_use, X86_PMC_IDX_MAX); } @@ -846,8 +846,8 @@ static inline bool cpl_is_matched(struct kvm_pmc *pmc) } else { config = fixed_ctrl_field(pmc_to_pmu(pmc)->fixed_ctr_ctrl, pmc->idx - KVM_FIXED_PMC_BASE_IDX); - select_os = config & 0x1; - select_user = config & 0x2; + select_os = config & INTEL_FIXED_0_KERNEL; + select_user = config & INTEL_FIXED_0_USER; } /* @@ -857,7 +857,8 @@ static inline bool cpl_is_matched(struct kvm_pmc *pmc) if (select_os == select_user) return select_os; - return (static_call(kvm_x86_get_cpl)(pmc->vcpu) == 0) ? select_os : select_user; + return (kvm_x86_call(get_cpl)(pmc->vcpu) == 0) ? select_os : + select_user; } void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 eventsel) diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 4d52b0b539ba..ad89d0bd6005 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -14,7 +14,8 @@ MSR_IA32_MISC_ENABLE_BTS_UNAVAIL) /* retrieve the 4 bits for EN and PMI out of IA32_FIXED_CTR_CTRL */ -#define fixed_ctrl_field(ctrl_reg, idx) (((ctrl_reg) >> ((idx)*4)) & 0xf) +#define fixed_ctrl_field(ctrl_reg, idx) \ + (((ctrl_reg) >> ((idx) * INTEL_FIXED_BITS_STRIDE)) & INTEL_FIXED_BITS_MASK) #define VMWARE_BACKDOOR_PMC_HOST_TSC 0x10000 #define VMWARE_BACKDOOR_PMC_REAL_TIME 0x10001 @@ -129,7 +130,7 @@ static inline bool pmc_is_fixed(struct kvm_pmc *pmc) static inline bool kvm_valid_perf_global_ctrl(struct kvm_pmu *pmu, u64 data) { - return !(pmu->global_ctrl_mask & data); + return !(pmu->global_ctrl_rsvd & data); } /* returns general purpose PMC with the specified MSR. Note that it can be @@ -170,7 +171,8 @@ static inline bool pmc_speculative_in_use(struct kvm_pmc *pmc) if (pmc_is_fixed(pmc)) return fixed_ctrl_field(pmu->fixed_ctr_ctrl, - pmc->idx - KVM_FIXED_PMC_BASE_IDX) & 0x3; + pmc->idx - KVM_FIXED_PMC_BASE_IDX) & + (INTEL_FIXED_0_KERNEL | INTEL_FIXED_0_USER); return pmc->eventsel & ARCH_PERFMON_EVENTSEL_ENABLE; } @@ -217,7 +219,7 @@ static inline void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops) kvm_pmu_cap.num_counters_gp = min(kvm_pmu_cap.num_counters_gp, pmu_ops->MAX_NR_GP_COUNTERS); kvm_pmu_cap.num_counters_fixed = min(kvm_pmu_cap.num_counters_fixed, - KVM_PMC_MAX_FIXED); + KVM_MAX_NR_FIXED_COUNTERS); kvm_pmu_eventsel.INSTRUCTIONS_RETIRED = perf_get_hw_event_config(PERF_COUNT_HW_INSTRUCTIONS); diff --git a/arch/x86/kvm/smm.c b/arch/x86/kvm/smm.c index d06d43d8d2aa..00e3c27d2a87 100644 --- a/arch/x86/kvm/smm.c +++ b/arch/x86/kvm/smm.c @@ -200,11 +200,11 @@ static void enter_smm_save_state_32(struct kvm_vcpu *vcpu, enter_smm_save_seg_32(vcpu, &smram->tr, &smram->tr_sel, VCPU_SREG_TR); enter_smm_save_seg_32(vcpu, &smram->ldtr, &smram->ldtr_sel, VCPU_SREG_LDTR); - static_call(kvm_x86_get_gdt)(vcpu, &dt); + kvm_x86_call(get_gdt)(vcpu, &dt); smram->gdtr.base = dt.address; smram->gdtr.limit = dt.size; - static_call(kvm_x86_get_idt)(vcpu, &dt); + kvm_x86_call(get_idt)(vcpu, &dt); smram->idtr.base = dt.address; smram->idtr.limit = dt.size; @@ -220,7 +220,7 @@ static void enter_smm_save_state_32(struct kvm_vcpu *vcpu, smram->smm_revision = 0x00020000; smram->smbase = vcpu->arch.smbase; - smram->int_shadow = static_call(kvm_x86_get_interrupt_shadow)(vcpu); + smram->int_shadow = kvm_x86_call(get_interrupt_shadow)(vcpu); } #ifdef CONFIG_X86_64 @@ -250,13 +250,13 @@ static void enter_smm_save_state_64(struct kvm_vcpu *vcpu, enter_smm_save_seg_64(vcpu, &smram->tr, VCPU_SREG_TR); - static_call(kvm_x86_get_idt)(vcpu, &dt); + kvm_x86_call(get_idt)(vcpu, &dt); smram->idtr.limit = dt.size; smram->idtr.base = dt.address; enter_smm_save_seg_64(vcpu, &smram->ldtr, VCPU_SREG_LDTR); - static_call(kvm_x86_get_gdt)(vcpu, &dt); + kvm_x86_call(get_gdt)(vcpu, &dt); smram->gdtr.limit = dt.size; smram->gdtr.base = dt.address; @@ -267,7 +267,7 @@ static void enter_smm_save_state_64(struct kvm_vcpu *vcpu, enter_smm_save_seg_64(vcpu, &smram->fs, VCPU_SREG_FS); enter_smm_save_seg_64(vcpu, &smram->gs, VCPU_SREG_GS); - smram->int_shadow = static_call(kvm_x86_get_interrupt_shadow)(vcpu); + smram->int_shadow = kvm_x86_call(get_interrupt_shadow)(vcpu); } #endif @@ -297,7 +297,7 @@ void enter_smm(struct kvm_vcpu *vcpu) * Kill the VM in the unlikely case of failure, because the VM * can be in undefined state in this case. */ - if (static_call(kvm_x86_enter_smm)(vcpu, &smram)) + if (kvm_x86_call(enter_smm)(vcpu, &smram)) goto error; kvm_smm_changed(vcpu, true); @@ -305,24 +305,24 @@ void enter_smm(struct kvm_vcpu *vcpu) if (kvm_vcpu_write_guest(vcpu, vcpu->arch.smbase + 0xfe00, &smram, sizeof(smram))) goto error; - if (static_call(kvm_x86_get_nmi_mask)(vcpu)) + if (kvm_x86_call(get_nmi_mask)(vcpu)) vcpu->arch.hflags |= HF_SMM_INSIDE_NMI_MASK; else - static_call(kvm_x86_set_nmi_mask)(vcpu, true); + kvm_x86_call(set_nmi_mask)(vcpu, true); kvm_set_rflags(vcpu, X86_EFLAGS_FIXED); kvm_rip_write(vcpu, 0x8000); - static_call(kvm_x86_set_interrupt_shadow)(vcpu, 0); + kvm_x86_call(set_interrupt_shadow)(vcpu, 0); cr0 = vcpu->arch.cr0 & ~(X86_CR0_PE | X86_CR0_EM | X86_CR0_TS | X86_CR0_PG); - static_call(kvm_x86_set_cr0)(vcpu, cr0); + kvm_x86_call(set_cr0)(vcpu, cr0); - static_call(kvm_x86_set_cr4)(vcpu, 0); + kvm_x86_call(set_cr4)(vcpu, 0); /* Undocumented: IDT limit is set to zero on entry to SMM. */ dt.address = dt.size = 0; - static_call(kvm_x86_set_idt)(vcpu, &dt); + kvm_x86_call(set_idt)(vcpu, &dt); if (WARN_ON_ONCE(kvm_set_dr(vcpu, 7, DR7_FIXED_1))) goto error; @@ -354,7 +354,7 @@ void enter_smm(struct kvm_vcpu *vcpu) #ifdef CONFIG_X86_64 if (guest_cpuid_has(vcpu, X86_FEATURE_LM)) - if (static_call(kvm_x86_set_efer)(vcpu, 0)) + if (kvm_x86_call(set_efer)(vcpu, 0)) goto error; #endif @@ -479,11 +479,11 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, dt.address = smstate->gdtr.base; dt.size = smstate->gdtr.limit; - static_call(kvm_x86_set_gdt)(vcpu, &dt); + kvm_x86_call(set_gdt)(vcpu, &dt); dt.address = smstate->idtr.base; dt.size = smstate->idtr.limit; - static_call(kvm_x86_set_idt)(vcpu, &dt); + kvm_x86_call(set_idt)(vcpu, &dt); rsm_load_seg_32(vcpu, &smstate->es, smstate->es_sel, VCPU_SREG_ES); rsm_load_seg_32(vcpu, &smstate->cs, smstate->cs_sel, VCPU_SREG_CS); @@ -501,7 +501,7 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, if (r != X86EMUL_CONTINUE) return r; - static_call(kvm_x86_set_interrupt_shadow)(vcpu, 0); + kvm_x86_call(set_interrupt_shadow)(vcpu, 0); ctxt->interruptibility = (u8)smstate->int_shadow; return r; @@ -535,13 +535,13 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, dt.size = smstate->idtr.limit; dt.address = smstate->idtr.base; - static_call(kvm_x86_set_idt)(vcpu, &dt); + kvm_x86_call(set_idt)(vcpu, &dt); rsm_load_seg_64(vcpu, &smstate->ldtr, VCPU_SREG_LDTR); dt.size = smstate->gdtr.limit; dt.address = smstate->gdtr.base; - static_call(kvm_x86_set_gdt)(vcpu, &dt); + kvm_x86_call(set_gdt)(vcpu, &dt); r = rsm_enter_protected_mode(vcpu, smstate->cr0, smstate->cr3, smstate->cr4); if (r != X86EMUL_CONTINUE) @@ -554,7 +554,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, rsm_load_seg_64(vcpu, &smstate->fs, VCPU_SREG_FS); rsm_load_seg_64(vcpu, &smstate->gs, VCPU_SREG_GS); - static_call(kvm_x86_set_interrupt_shadow)(vcpu, 0); + kvm_x86_call(set_interrupt_shadow)(vcpu, 0); ctxt->interruptibility = (u8)smstate->int_shadow; return X86EMUL_CONTINUE; @@ -576,7 +576,7 @@ int emulator_leave_smm(struct x86_emulate_ctxt *ctxt) return X86EMUL_UNHANDLEABLE; if ((vcpu->arch.hflags & HF_SMM_INSIDE_NMI_MASK) == 0) - static_call(kvm_x86_set_nmi_mask)(vcpu, false); + kvm_x86_call(set_nmi_mask)(vcpu, false); kvm_smm_changed(vcpu, false); @@ -628,7 +628,7 @@ int emulator_leave_smm(struct x86_emulate_ctxt *ctxt) * state (e.g. enter guest mode) before loading state from the SMM * state-save area. */ - if (static_call(kvm_x86_leave_smm)(vcpu, &smram)) + if (kvm_x86_call(leave_smm)(vcpu, &smram)) return X86EMUL_UNHANDLEABLE; #ifdef CONFIG_X86_64 diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 55b9a6d96bcf..6f704c1037e5 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -1181,7 +1181,7 @@ int svm_allocate_nested(struct vcpu_svm *svm) if (svm->nested.initialized) return 0; - vmcb02_page = snp_safe_alloc_page(&svm->vcpu); + vmcb02_page = snp_safe_alloc_page(); if (!vmcb02_page) return -ENOMEM; svm->nested.vmcb02.ptr = page_address(vmcb02_page); diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index dfcc38bd97d3..22d5a65b410c 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -199,8 +199,8 @@ static void amd_pmu_refresh(struct kvm_vcpu *vcpu) kvm_pmu_cap.num_counters_gp); if (pmu->version > 1) { - pmu->global_ctrl_mask = ~((1ull << pmu->nr_arch_gp_counters) - 1); - pmu->global_status_mask = pmu->global_ctrl_mask; + pmu->global_ctrl_rsvd = ~((1ull << pmu->nr_arch_gp_counters) - 1); + pmu->global_status_rsvd = pmu->global_ctrl_rsvd; } pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << 48) - 1; @@ -217,10 +217,9 @@ static void amd_pmu_init(struct kvm_vcpu *vcpu) struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); int i; - BUILD_BUG_ON(KVM_AMD_PMC_MAX_GENERIC > AMD64_NUM_COUNTERS_CORE); - BUILD_BUG_ON(KVM_AMD_PMC_MAX_GENERIC > INTEL_PMC_MAX_GENERIC); + BUILD_BUG_ON(KVM_MAX_NR_AMD_GP_COUNTERS > AMD64_NUM_COUNTERS_CORE); - for (i = 0; i < KVM_AMD_PMC_MAX_GENERIC ; i++) { + for (i = 0; i < KVM_MAX_NR_AMD_GP_COUNTERS; i++) { pmu->gp_counters[i].type = KVM_PMC_GP; pmu->gp_counters[i].vcpu = vcpu; pmu->gp_counters[i].idx = i; @@ -238,6 +237,6 @@ struct kvm_pmu_ops amd_pmu_ops __initdata = { .refresh = amd_pmu_refresh, .init = amd_pmu_init, .EVENTSEL_EVENT = AMD64_EVENTSEL_EVENT, - .MAX_NR_GP_COUNTERS = KVM_AMD_PMC_MAX_GENERIC, + .MAX_NR_GP_COUNTERS = KVM_MAX_NR_AMD_GP_COUNTERS, .MIN_NR_GP_COUNTERS = AMD64_NUM_COUNTERS, }; diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 95095a233a45..a16c873b3232 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -19,12 +19,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include "mmu.h" #include "x86.h" @@ -37,7 +39,7 @@ #define GHCB_VERSION_DEFAULT 2ULL #define GHCB_VERSION_MIN 1ULL -#define GHCB_HV_FT_SUPPORTED GHCB_HV_FT_SNP +#define GHCB_HV_FT_SUPPORTED (GHCB_HV_FT_SNP | GHCB_HV_FT_SNP_AP_CREATION) /* enable/disable SEV support */ static bool sev_enabled = true; @@ -47,6 +49,10 @@ module_param_named(sev, sev_enabled, bool, 0444); static bool sev_es_enabled = true; module_param_named(sev_es, sev_es_enabled, bool, 0444); +/* enable/disable SEV-SNP support */ +static bool sev_snp_enabled = true; +module_param_named(sev_snp, sev_snp_enabled, bool, 0444); + /* enable/disable SEV-ES DebugSwap support */ static bool sev_es_debug_swap_enabled = true; module_param_named(debug_swap, sev_es_debug_swap_enabled, bool, 0444); @@ -56,6 +62,23 @@ static u64 sev_supported_vmsa_features; #define AP_RESET_HOLD_NAE_EVENT 1 #define AP_RESET_HOLD_MSR_PROTO 2 +/* As defined by SEV-SNP Firmware ABI, under "Guest Policy". */ +#define SNP_POLICY_MASK_API_MINOR GENMASK_ULL(7, 0) +#define SNP_POLICY_MASK_API_MAJOR GENMASK_ULL(15, 8) +#define SNP_POLICY_MASK_SMT BIT_ULL(16) +#define SNP_POLICY_MASK_RSVD_MBO BIT_ULL(17) +#define SNP_POLICY_MASK_DEBUG BIT_ULL(19) +#define SNP_POLICY_MASK_SINGLE_SOCKET BIT_ULL(20) + +#define SNP_POLICY_MASK_VALID (SNP_POLICY_MASK_API_MINOR | \ + SNP_POLICY_MASK_API_MAJOR | \ + SNP_POLICY_MASK_SMT | \ + SNP_POLICY_MASK_RSVD_MBO | \ + SNP_POLICY_MASK_DEBUG | \ + SNP_POLICY_MASK_SINGLE_SOCKET) + +#define INITIAL_VMSA_GPA 0xFFFFFFFFF000 + static u8 sev_enc_bit; static DECLARE_RWSEM(sev_deactivate_lock); static DEFINE_MUTEX(sev_bitmap_lock); @@ -66,6 +89,8 @@ static unsigned int nr_asids; static unsigned long *sev_asid_bitmap; static unsigned long *sev_reclaim_asid_bitmap; +static int snp_decommission_context(struct kvm *kvm); + struct enc_region { struct list_head list; unsigned long npages; @@ -92,12 +117,17 @@ static int sev_flush_asids(unsigned int min_asid, unsigned int max_asid) down_write(&sev_deactivate_lock); wbinvd_on_all_cpus(); - ret = sev_guest_df_flush(&error); + + if (sev_snp_enabled) + ret = sev_do_cmd(SEV_CMD_SNP_DF_FLUSH, NULL, &error); + else + ret = sev_guest_df_flush(&error); up_write(&sev_deactivate_lock); if (ret) - pr_err("SEV: DF_FLUSH failed, ret=%d, error=%#x\n", ret, error); + pr_err("SEV%s: DF_FLUSH failed, ret=%d, error=%#x\n", + sev_snp_enabled ? "-SNP" : "", ret, error); return ret; } @@ -233,6 +263,53 @@ static void sev_decommission(unsigned int handle) sev_guest_decommission(&decommission, NULL); } +/* + * Transition a page to hypervisor-owned/shared state in the RMP table. This + * should not fail under normal conditions, but leak the page should that + * happen since it will no longer be usable by the host due to RMP protections. + */ +static int kvm_rmp_make_shared(struct kvm *kvm, u64 pfn, enum pg_level level) +{ + if (KVM_BUG_ON(rmp_make_shared(pfn, level), kvm)) { + snp_leak_pages(pfn, page_level_size(level) >> PAGE_SHIFT); + return -EIO; + } + + return 0; +} + +/* + * Certain page-states, such as Pre-Guest and Firmware pages (as documented + * in Chapter 5 of the SEV-SNP Firmware ABI under "Page States") cannot be + * directly transitioned back to normal/hypervisor-owned state via RMPUPDATE + * unless they are reclaimed first. + * + * Until they are reclaimed and subsequently transitioned via RMPUPDATE, they + * might not be usable by the host due to being set as immutable or still + * being associated with a guest ASID. + * + * Bug the VM and leak the page if reclaim fails, or if the RMP entry can't be + * converted back to shared, as the page is no longer usable due to RMP + * protections, and it's infeasible for the guest to continue on. + */ +static int snp_page_reclaim(struct kvm *kvm, u64 pfn) +{ + struct sev_data_snp_page_reclaim data = {0}; + int fw_err, rc; + + data.paddr = __sme_set(pfn << PAGE_SHIFT); + rc = sev_do_cmd(SEV_CMD_SNP_PAGE_RECLAIM, &data, &fw_err); + if (KVM_BUG(rc, kvm, "Failed to reclaim PFN %llx, rc %d fw_err %d", pfn, rc, fw_err)) { + snp_leak_pages(pfn, 1); + return -EIO; + } + + if (kvm_rmp_make_shared(kvm, pfn, PG_LEVEL_4K)) + return -EIO; + + return rc; +} + static void sev_unbind_asid(struct kvm *kvm, unsigned int handle) { struct sev_data_deactivate deactivate; @@ -250,6 +327,78 @@ static void sev_unbind_asid(struct kvm *kvm, unsigned int handle) sev_decommission(handle); } +/* + * This sets up bounce buffers/firmware pages to handle SNP Guest Request + * messages (e.g. attestation requests). See "SNP Guest Request" in the GHCB + * 2.0 specification for more details. + * + * Technically, when an SNP Guest Request is issued, the guest will provide its + * own request/response pages, which could in theory be passed along directly + * to firmware rather than using bounce pages. However, these pages would need + * special care: + * + * - Both pages are from shared guest memory, so they need to be protected + * from migration/etc. occurring while firmware reads/writes to them. At a + * minimum, this requires elevating the ref counts and potentially needing + * an explicit pinning of the memory. This places additional restrictions + * on what type of memory backends userspace can use for shared guest + * memory since there is some reliance on using refcounted pages. + * + * - The response page needs to be switched to Firmware-owned[1] state + * before the firmware can write to it, which can lead to potential + * host RMP #PFs if the guest is misbehaved and hands the host a + * guest page that KVM might write to for other reasons (e.g. virtio + * buffers/etc.). + * + * Both of these issues can be avoided completely by using separately-allocated + * bounce pages for both the request/response pages and passing those to + * firmware instead. So that's what is being set up here. + * + * Guest requests rely on message sequence numbers to ensure requests are + * issued to firmware in the order the guest issues them, so concurrent guest + * requests generally shouldn't happen. But a misbehaved guest could issue + * concurrent guest requests in theory, so a mutex is used to serialize + * access to the bounce buffers. + * + * [1] See the "Page States" section of the SEV-SNP Firmware ABI for more + * details on Firmware-owned pages, along with "RMP and VMPL Access Checks" + * in the APM for details on the related RMP restrictions. + */ +static int snp_guest_req_init(struct kvm *kvm) +{ + struct kvm_sev_info *sev = to_kvm_sev_info(kvm); + struct page *req_page; + + req_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); + if (!req_page) + return -ENOMEM; + + sev->guest_resp_buf = snp_alloc_firmware_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); + if (!sev->guest_resp_buf) { + __free_page(req_page); + return -EIO; + } + + sev->guest_req_buf = page_address(req_page); + mutex_init(&sev->guest_req_mutex); + + return 0; +} + +static void snp_guest_req_cleanup(struct kvm *kvm) +{ + struct kvm_sev_info *sev = to_kvm_sev_info(kvm); + + if (sev->guest_resp_buf) + snp_free_firmware_page(sev->guest_resp_buf); + + if (sev->guest_req_buf) + __free_page(virt_to_page(sev->guest_req_buf)); + + sev->guest_req_buf = NULL; + sev->guest_resp_buf = NULL; +} + static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, struct kvm_sev_init *data, unsigned long vm_type) @@ -288,6 +437,9 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, if (sev->es_active && !sev->ghcb_version) sev->ghcb_version = GHCB_VERSION_DEFAULT; + if (vm_type == KVM_X86_SNP_VM) + sev->vmsa_features |= SVM_SEV_FEAT_SNP_ACTIVE; + ret = sev_asid_new(sev); if (ret) goto e_no_asid; @@ -297,6 +449,10 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, if (ret) goto e_free; + /* This needs to happen after SEV/SNP firmware initialization. */ + if (vm_type == KVM_X86_SNP_VM && snp_guest_req_init(kvm)) + goto e_free; + INIT_LIST_HEAD(&sev->regions_list); INIT_LIST_HEAD(&sev->mirror_vms); sev->need_init = false; @@ -348,7 +504,8 @@ static int sev_guest_init2(struct kvm *kvm, struct kvm_sev_cmd *argp) return -EINVAL; if (kvm->arch.vm_type != KVM_X86_SEV_VM && - kvm->arch.vm_type != KVM_X86_SEV_ES_VM) + kvm->arch.vm_type != KVM_X86_SEV_ES_VM && + kvm->arch.vm_type != KVM_X86_SNP_VM) return -EINVAL; if (copy_from_user(&data, u64_to_user_ptr(argp->data), sizeof(data))) @@ -1999,6 +2156,410 @@ int sev_dev_get_attr(u32 group, u64 attr, u64 *val) } } +/* + * The guest context contains all the information, keys and metadata + * associated with the guest that the firmware tracks to implement SEV + * and SNP features. The firmware stores the guest context in hypervisor + * provide page via the SNP_GCTX_CREATE command. + */ +static void *snp_context_create(struct kvm *kvm, struct kvm_sev_cmd *argp) +{ + struct sev_data_snp_addr data = {}; + void *context; + int rc; + + /* Allocate memory for context page */ + context = snp_alloc_firmware_page(GFP_KERNEL_ACCOUNT); + if (!context) + return NULL; + + data.address = __psp_pa(context); + rc = __sev_issue_cmd(argp->sev_fd, SEV_CMD_SNP_GCTX_CREATE, &data, &argp->error); + if (rc) { + pr_warn("Failed to create SEV-SNP context, rc %d fw_error %d", + rc, argp->error); + snp_free_firmware_page(context); + return NULL; + } + + return context; +} + +static int snp_bind_asid(struct kvm *kvm, int *error) +{ + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; + struct sev_data_snp_activate data = {0}; + + data.gctx_paddr = __psp_pa(sev->snp_context); + data.asid = sev_get_asid(kvm); + return sev_issue_cmd(kvm, SEV_CMD_SNP_ACTIVATE, &data, error); +} + +static int snp_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp) +{ + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; + struct sev_data_snp_launch_start start = {0}; + struct kvm_sev_snp_launch_start params; + int rc; + + if (!sev_snp_guest(kvm)) + return -ENOTTY; + + if (copy_from_user(¶ms, u64_to_user_ptr(argp->data), sizeof(params))) + return -EFAULT; + + /* Don't allow userspace to allocate memory for more than 1 SNP context. */ + if (sev->snp_context) + return -EINVAL; + + sev->snp_context = snp_context_create(kvm, argp); + if (!sev->snp_context) + return -ENOTTY; + + if (params.flags) + return -EINVAL; + + if (params.policy & ~SNP_POLICY_MASK_VALID) + return -EINVAL; + + /* Check for policy bits that must be set */ + if (!(params.policy & SNP_POLICY_MASK_RSVD_MBO) || + !(params.policy & SNP_POLICY_MASK_SMT)) + return -EINVAL; + + if (params.policy & SNP_POLICY_MASK_SINGLE_SOCKET) + return -EINVAL; + + start.gctx_paddr = __psp_pa(sev->snp_context); + start.policy = params.policy; + memcpy(start.gosvw, params.gosvw, sizeof(params.gosvw)); + rc = __sev_issue_cmd(argp->sev_fd, SEV_CMD_SNP_LAUNCH_START, &start, &argp->error); + if (rc) { + pr_debug("%s: SEV_CMD_SNP_LAUNCH_START firmware command failed, rc %d\n", + __func__, rc); + goto e_free_context; + } + + sev->fd = argp->sev_fd; + rc = snp_bind_asid(kvm, &argp->error); + if (rc) { + pr_debug("%s: Failed to bind ASID to SEV-SNP context, rc %d\n", + __func__, rc); + goto e_free_context; + } + + return 0; + +e_free_context: + snp_decommission_context(kvm); + + return rc; +} + +struct sev_gmem_populate_args { + __u8 type; + int sev_fd; + int fw_error; +}; + +static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn_start, kvm_pfn_t pfn, + void __user *src, int order, void *opaque) +{ + struct sev_gmem_populate_args *sev_populate_args = opaque; + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; + int n_private = 0, ret, i; + int npages = (1 << order); + gfn_t gfn; + + if (WARN_ON_ONCE(sev_populate_args->type != KVM_SEV_SNP_PAGE_TYPE_ZERO && !src)) + return -EINVAL; + + for (gfn = gfn_start, i = 0; gfn < gfn_start + npages; gfn++, i++) { + struct sev_data_snp_launch_update fw_args = {0}; + bool assigned; + int level; + + if (!kvm_mem_is_private(kvm, gfn)) { + pr_debug("%s: Failed to ensure GFN 0x%llx has private memory attribute set\n", + __func__, gfn); + ret = -EINVAL; + goto err; + } + + ret = snp_lookup_rmpentry((u64)pfn + i, &assigned, &level); + if (ret || assigned) { + pr_debug("%s: Failed to ensure GFN 0x%llx RMP entry is initial shared state, ret: %d assigned: %d\n", + __func__, gfn, ret, assigned); + ret = -EINVAL; + goto err; + } + + if (src) { + void *vaddr = kmap_local_pfn(pfn + i); + + ret = copy_from_user(vaddr, src + i * PAGE_SIZE, PAGE_SIZE); + if (ret) + goto err; + kunmap_local(vaddr); + } + + ret = rmp_make_private(pfn + i, gfn << PAGE_SHIFT, PG_LEVEL_4K, + sev_get_asid(kvm), true); + if (ret) + goto err; + + n_private++; + + fw_args.gctx_paddr = __psp_pa(sev->snp_context); + fw_args.address = __sme_set(pfn_to_hpa(pfn + i)); + fw_args.page_size = PG_LEVEL_TO_RMP(PG_LEVEL_4K); + fw_args.page_type = sev_populate_args->type; + + ret = __sev_issue_cmd(sev_populate_args->sev_fd, SEV_CMD_SNP_LAUNCH_UPDATE, + &fw_args, &sev_populate_args->fw_error); + if (ret) + goto fw_err; + } + + return 0; + +fw_err: + /* + * If the firmware command failed handle the reclaim and cleanup of that + * PFN specially vs. prior pages which can be cleaned up below without + * needing to reclaim in advance. + * + * Additionally, when invalid CPUID function entries are detected, + * firmware writes the expected values into the page and leaves it + * unencrypted so it can be used for debugging and error-reporting. + * + * Copy this page back into the source buffer so userspace can use this + * information to provide information on which CPUID leaves/fields + * failed CPUID validation. + */ + if (!snp_page_reclaim(kvm, pfn + i) && + sev_populate_args->type == KVM_SEV_SNP_PAGE_TYPE_CPUID && + sev_populate_args->fw_error == SEV_RET_INVALID_PARAM) { + void *vaddr = kmap_local_pfn(pfn + i); + + if (copy_to_user(src + i * PAGE_SIZE, vaddr, PAGE_SIZE)) + pr_debug("Failed to write CPUID page back to userspace\n"); + + kunmap_local(vaddr); + } + + /* pfn + i is hypervisor-owned now, so skip below cleanup for it. */ + n_private--; + +err: + pr_debug("%s: exiting with error ret %d (fw_error %d), restoring %d gmem PFNs to shared.\n", + __func__, ret, sev_populate_args->fw_error, n_private); + for (i = 0; i < n_private; i++) + kvm_rmp_make_shared(kvm, pfn + i, PG_LEVEL_4K); + + return ret; +} + +static int snp_launch_update(struct kvm *kvm, struct kvm_sev_cmd *argp) +{ + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; + struct sev_gmem_populate_args sev_populate_args = {0}; + struct kvm_sev_snp_launch_update params; + struct kvm_memory_slot *memslot; + long npages, count; + void __user *src; + int ret = 0; + + if (!sev_snp_guest(kvm) || !sev->snp_context) + return -EINVAL; + + if (copy_from_user(¶ms, u64_to_user_ptr(argp->data), sizeof(params))) + return -EFAULT; + + pr_debug("%s: GFN start 0x%llx length 0x%llx type %d flags %d\n", __func__, + params.gfn_start, params.len, params.type, params.flags); + + if (!PAGE_ALIGNED(params.len) || params.flags || + (params.type != KVM_SEV_SNP_PAGE_TYPE_NORMAL && + params.type != KVM_SEV_SNP_PAGE_TYPE_ZERO && + params.type != KVM_SEV_SNP_PAGE_TYPE_UNMEASURED && + params.type != KVM_SEV_SNP_PAGE_TYPE_SECRETS && + params.type != KVM_SEV_SNP_PAGE_TYPE_CPUID)) + return -EINVAL; + + npages = params.len / PAGE_SIZE; + + /* + * For each GFN that's being prepared as part of the initial guest + * state, the following pre-conditions are verified: + * + * 1) The backing memslot is a valid private memslot. + * 2) The GFN has been set to private via KVM_SET_MEMORY_ATTRIBUTES + * beforehand. + * 3) The PFN of the guest_memfd has not already been set to private + * in the RMP table. + * + * The KVM MMU relies on kvm->mmu_invalidate_seq to retry nested page + * faults if there's a race between a fault and an attribute update via + * KVM_SET_MEMORY_ATTRIBUTES, and a similar approach could be utilized + * here. However, kvm->slots_lock guards against both this as well as + * concurrent memslot updates occurring while these checks are being + * performed, so use that here to make it easier to reason about the + * initial expected state and better guard against unexpected + * situations. + */ + mutex_lock(&kvm->slots_lock); + + memslot = gfn_to_memslot(kvm, params.gfn_start); + if (!kvm_slot_can_be_private(memslot)) { + ret = -EINVAL; + goto out; + } + + sev_populate_args.sev_fd = argp->sev_fd; + sev_populate_args.type = params.type; + src = params.type == KVM_SEV_SNP_PAGE_TYPE_ZERO ? NULL : u64_to_user_ptr(params.uaddr); + + count = kvm_gmem_populate(kvm, params.gfn_start, src, npages, + sev_gmem_post_populate, &sev_populate_args); + if (count < 0) { + argp->error = sev_populate_args.fw_error; + pr_debug("%s: kvm_gmem_populate failed, ret %ld (fw_error %d)\n", + __func__, count, argp->error); + ret = -EIO; + } else { + params.gfn_start += count; + params.len -= count * PAGE_SIZE; + if (params.type != KVM_SEV_SNP_PAGE_TYPE_ZERO) + params.uaddr += count * PAGE_SIZE; + + ret = 0; + if (copy_to_user(u64_to_user_ptr(argp->data), ¶ms, sizeof(params))) + ret = -EFAULT; + } + +out: + mutex_unlock(&kvm->slots_lock); + + return ret; +} + +static int snp_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp) +{ + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; + struct sev_data_snp_launch_update data = {}; + struct kvm_vcpu *vcpu; + unsigned long i; + int ret; + + data.gctx_paddr = __psp_pa(sev->snp_context); + data.page_type = SNP_PAGE_TYPE_VMSA; + + kvm_for_each_vcpu(i, vcpu, kvm) { + struct vcpu_svm *svm = to_svm(vcpu); + u64 pfn = __pa(svm->sev_es.vmsa) >> PAGE_SHIFT; + + ret = sev_es_sync_vmsa(svm); + if (ret) + return ret; + + /* Transition the VMSA page to a firmware state. */ + ret = rmp_make_private(pfn, INITIAL_VMSA_GPA, PG_LEVEL_4K, sev->asid, true); + if (ret) + return ret; + + /* Issue the SNP command to encrypt the VMSA */ + data.address = __sme_pa(svm->sev_es.vmsa); + ret = __sev_issue_cmd(argp->sev_fd, SEV_CMD_SNP_LAUNCH_UPDATE, + &data, &argp->error); + if (ret) { + snp_page_reclaim(kvm, pfn); + + return ret; + } + + svm->vcpu.arch.guest_state_protected = true; + /* + * SEV-ES (and thus SNP) guest mandates LBR Virtualization to + * be _always_ ON. Enable it only after setting + * guest_state_protected because KVM_SET_MSRS allows dynamic + * toggling of LBRV (for performance reason) on write access to + * MSR_IA32_DEBUGCTLMSR when guest_state_protected is not set. + */ + svm_enable_lbrv(vcpu); + } + + return 0; +} + +static int snp_launch_finish(struct kvm *kvm, struct kvm_sev_cmd *argp) +{ + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; + struct kvm_sev_snp_launch_finish params; + struct sev_data_snp_launch_finish *data; + void *id_block = NULL, *id_auth = NULL; + int ret; + + if (!sev_snp_guest(kvm)) + return -ENOTTY; + + if (!sev->snp_context) + return -EINVAL; + + if (copy_from_user(¶ms, u64_to_user_ptr(argp->data), sizeof(params))) + return -EFAULT; + + if (params.flags) + return -EINVAL; + + /* Measure all vCPUs using LAUNCH_UPDATE before finalizing the launch flow. */ + ret = snp_launch_update_vmsa(kvm, argp); + if (ret) + return ret; + + data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT); + if (!data) + return -ENOMEM; + + if (params.id_block_en) { + id_block = psp_copy_user_blob(params.id_block_uaddr, KVM_SEV_SNP_ID_BLOCK_SIZE); + if (IS_ERR(id_block)) { + ret = PTR_ERR(id_block); + goto e_free; + } + + data->id_block_en = 1; + data->id_block_paddr = __sme_pa(id_block); + + id_auth = psp_copy_user_blob(params.id_auth_uaddr, KVM_SEV_SNP_ID_AUTH_SIZE); + if (IS_ERR(id_auth)) { + ret = PTR_ERR(id_auth); + goto e_free_id_block; + } + + data->id_auth_paddr = __sme_pa(id_auth); + + if (params.auth_key_en) + data->auth_key_en = 1; + } + + data->vcek_disabled = params.vcek_disabled; + + memcpy(data->host_data, params.host_data, KVM_SEV_SNP_FINISH_DATA_SIZE); + data->gctx_paddr = __psp_pa(sev->snp_context); + ret = sev_issue_cmd(kvm, SEV_CMD_SNP_LAUNCH_FINISH, data, &argp->error); + + kfree(id_auth); + +e_free_id_block: + kfree(id_block); + +e_free: + kfree(data); + + return ret; +} + int sev_mem_enc_ioctl(struct kvm *kvm, void __user *argp) { struct kvm_sev_cmd sev_cmd; @@ -2022,6 +2583,15 @@ int sev_mem_enc_ioctl(struct kvm *kvm, void __user *argp) goto out; } + /* + * Once KVM_SEV_INIT2 initializes a KVM instance as an SNP guest, only + * allow the use of SNP-specific commands. + */ + if (sev_snp_guest(kvm) && sev_cmd.id < KVM_SEV_SNP_LAUNCH_START) { + r = -EPERM; + goto out; + } + switch (sev_cmd.id) { case KVM_SEV_ES_INIT: if (!sev_es_enabled) { @@ -2086,6 +2656,15 @@ int sev_mem_enc_ioctl(struct kvm *kvm, void __user *argp) case KVM_SEV_RECEIVE_FINISH: r = sev_receive_finish(kvm, &sev_cmd); break; + case KVM_SEV_SNP_LAUNCH_START: + r = snp_launch_start(kvm, &sev_cmd); + break; + case KVM_SEV_SNP_LAUNCH_UPDATE: + r = snp_launch_update(kvm, &sev_cmd); + break; + case KVM_SEV_SNP_LAUNCH_FINISH: + r = snp_launch_finish(kvm, &sev_cmd); + break; default: r = -EINVAL; goto out; @@ -2281,6 +2860,31 @@ e_source_fput: return ret; } +static int snp_decommission_context(struct kvm *kvm) +{ + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; + struct sev_data_snp_addr data = {}; + int ret; + + /* If context is not created then do nothing */ + if (!sev->snp_context) + return 0; + + /* Do the decommision, which will unbind the ASID from the SNP context */ + data.address = __sme_pa(sev->snp_context); + down_write(&sev_deactivate_lock); + ret = sev_do_cmd(SEV_CMD_SNP_DECOMMISSION, &data, NULL); + up_write(&sev_deactivate_lock); + + if (WARN_ONCE(ret, "Failed to release guest context, ret %d", ret)) + return ret; + + snp_free_firmware_page(sev->snp_context); + sev->snp_context = NULL; + + return 0; +} + void sev_vm_destroy(struct kvm *kvm) { struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; @@ -2322,7 +2926,19 @@ void sev_vm_destroy(struct kvm *kvm) } } - sev_unbind_asid(kvm, sev->handle); + if (sev_snp_guest(kvm)) { + snp_guest_req_cleanup(kvm); + + /* + * Decomission handles unbinding of the ASID. If it fails for + * some unexpected reason, just leak the ASID. + */ + if (snp_decommission_context(kvm)) + return; + } else { + sev_unbind_asid(kvm, sev->handle); + } + sev_asid_free(sev); } @@ -2336,11 +2952,16 @@ void __init sev_set_cpu_caps(void) kvm_cpu_cap_set(X86_FEATURE_SEV_ES); kvm_caps.supported_vm_types |= BIT(KVM_X86_SEV_ES_VM); } + if (sev_snp_enabled) { + kvm_cpu_cap_set(X86_FEATURE_SEV_SNP); + kvm_caps.supported_vm_types |= BIT(KVM_X86_SNP_VM); + } } void __init sev_hardware_setup(void) { unsigned int eax, ebx, ecx, edx, sev_asid_count, sev_es_asid_count; + bool sev_snp_supported = false; bool sev_es_supported = false; bool sev_supported = false; @@ -2427,6 +3048,7 @@ void __init sev_hardware_setup(void) sev_es_asid_count = min_sev_asid - 1; WARN_ON_ONCE(misc_cg_set_capacity(MISC_CG_RES_SEV_ES, sev_es_asid_count)); sev_es_supported = true; + sev_snp_supported = sev_snp_enabled && cc_platform_has(CC_ATTR_HOST_SEV_SNP); out: if (boot_cpu_has(X86_FEATURE_SEV)) @@ -2439,9 +3061,15 @@ out: pr_info("SEV-ES %s (ASIDs %u - %u)\n", sev_es_supported ? "enabled" : "disabled", min_sev_asid > 1 ? 1 : 0, min_sev_asid - 1); + if (boot_cpu_has(X86_FEATURE_SEV_SNP)) + pr_info("SEV-SNP %s (ASIDs %u - %u)\n", + sev_snp_supported ? "enabled" : "disabled", + min_sev_asid > 1 ? 1 : 0, min_sev_asid - 1); sev_enabled = sev_supported; sev_es_enabled = sev_es_supported; + sev_snp_enabled = sev_snp_supported; + if (!sev_es_enabled || !cpu_feature_enabled(X86_FEATURE_DEBUG_SWAP) || !cpu_feature_enabled(X86_FEATURE_NO_NESTED_DATA_BP)) sev_es_debug_swap_enabled = false; @@ -2520,7 +3148,13 @@ do_wbinvd: void sev_guest_memory_reclaimed(struct kvm *kvm) { - if (!sev_guest(kvm)) + /* + * With SNP+gmem, private/encrypted memory is unreachable via the + * hva-based mmu notifiers, so these events are only actually + * pertaining to shared pages where there is no need to perform + * the WBINVD to flush associated caches. + */ + if (!sev_guest(kvm) || sev_snp_guest(kvm)) return; wbinvd_on_all_cpus(); @@ -2535,11 +3169,24 @@ void sev_free_vcpu(struct kvm_vcpu *vcpu) svm = to_svm(vcpu); + /* + * If it's an SNP guest, then the VMSA was marked in the RMP table as + * a guest-owned page. Transition the page to hypervisor state before + * releasing it back to the system. + */ + if (sev_snp_guest(vcpu->kvm)) { + u64 pfn = __pa(svm->sev_es.vmsa) >> PAGE_SHIFT; + + if (kvm_rmp_make_shared(vcpu->kvm, pfn, PG_LEVEL_4K)) + goto skip_vmsa_free; + } + if (vcpu->arch.guest_state_protected) sev_flush_encrypted_page(vcpu, svm->sev_es.vmsa); __free_page(virt_to_page(svm->sev_es.vmsa)); +skip_vmsa_free: if (svm->sev_es.ghcb_sa_free) kvfree(svm->sev_es.ghcb_sa); } @@ -2735,6 +3382,13 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm) if (!kvm_ghcb_sw_scratch_is_valid(svm)) goto vmgexit_err; break; + case SVM_VMGEXIT_AP_CREATION: + if (!sev_snp_guest(vcpu->kvm)) + goto vmgexit_err; + if (lower_32_bits(control->exit_info_1) != SVM_VMGEXIT_AP_DESTROY) + if (!kvm_ghcb_rax_is_valid(svm)) + goto vmgexit_err; + break; case SVM_VMGEXIT_NMI_COMPLETE: case SVM_VMGEXIT_AP_HLT_LOOP: case SVM_VMGEXIT_AP_JUMP_TABLE: @@ -2742,6 +3396,18 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm) case SVM_VMGEXIT_HV_FEATURES: case SVM_VMGEXIT_TERM_REQUEST: break; + case SVM_VMGEXIT_PSC: + if (!sev_snp_guest(vcpu->kvm) || !kvm_ghcb_sw_scratch_is_valid(svm)) + goto vmgexit_err; + break; + case SVM_VMGEXIT_GUEST_REQUEST: + case SVM_VMGEXIT_EXT_GUEST_REQUEST: + if (!sev_snp_guest(vcpu->kvm) || + !PAGE_ALIGNED(control->exit_info_1) || + !PAGE_ALIGNED(control->exit_info_2) || + control->exit_info_1 == control->exit_info_2) + goto vmgexit_err; + break; default: reason = GHCB_ERR_INVALID_EVENT; goto vmgexit_err; @@ -2929,6 +3595,534 @@ static void set_ghcb_msr(struct vcpu_svm *svm, u64 value) svm->vmcb->control.ghcb_gpa = value; } +static int snp_rmptable_psmash(kvm_pfn_t pfn) +{ + int ret; + + pfn = pfn & ~(KVM_PAGES_PER_HPAGE(PG_LEVEL_2M) - 1); + + /* + * PSMASH_FAIL_INUSE indicates another processor is modifying the + * entry, so retry until that's no longer the case. + */ + do { + ret = psmash(pfn); + } while (ret == PSMASH_FAIL_INUSE); + + return ret; +} + +static int snp_complete_psc_msr(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + if (vcpu->run->hypercall.ret) + set_ghcb_msr(svm, GHCB_MSR_PSC_RESP_ERROR); + else + set_ghcb_msr(svm, GHCB_MSR_PSC_RESP); + + return 1; /* resume guest */ +} + +static int snp_begin_psc_msr(struct vcpu_svm *svm, u64 ghcb_msr) +{ + u64 gpa = gfn_to_gpa(GHCB_MSR_PSC_REQ_TO_GFN(ghcb_msr)); + u8 op = GHCB_MSR_PSC_REQ_TO_OP(ghcb_msr); + struct kvm_vcpu *vcpu = &svm->vcpu; + + if (op != SNP_PAGE_STATE_PRIVATE && op != SNP_PAGE_STATE_SHARED) { + set_ghcb_msr(svm, GHCB_MSR_PSC_RESP_ERROR); + return 1; /* resume guest */ + } + + if (!(vcpu->kvm->arch.hypercall_exit_enabled & (1 << KVM_HC_MAP_GPA_RANGE))) { + set_ghcb_msr(svm, GHCB_MSR_PSC_RESP_ERROR); + return 1; /* resume guest */ + } + + vcpu->run->exit_reason = KVM_EXIT_HYPERCALL; + vcpu->run->hypercall.nr = KVM_HC_MAP_GPA_RANGE; + vcpu->run->hypercall.args[0] = gpa; + vcpu->run->hypercall.args[1] = 1; + vcpu->run->hypercall.args[2] = (op == SNP_PAGE_STATE_PRIVATE) + ? KVM_MAP_GPA_RANGE_ENCRYPTED + : KVM_MAP_GPA_RANGE_DECRYPTED; + vcpu->run->hypercall.args[2] |= KVM_MAP_GPA_RANGE_PAGE_SZ_4K; + + vcpu->arch.complete_userspace_io = snp_complete_psc_msr; + + return 0; /* forward request to userspace */ +} + +struct psc_buffer { + struct psc_hdr hdr; + struct psc_entry entries[]; +} __packed; + +static int snp_begin_psc(struct vcpu_svm *svm, struct psc_buffer *psc); + +static void snp_complete_psc(struct vcpu_svm *svm, u64 psc_ret) +{ + svm->sev_es.psc_inflight = 0; + svm->sev_es.psc_idx = 0; + svm->sev_es.psc_2m = false; + ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, psc_ret); +} + +static void __snp_complete_one_psc(struct vcpu_svm *svm) +{ + struct psc_buffer *psc = svm->sev_es.ghcb_sa; + struct psc_entry *entries = psc->entries; + struct psc_hdr *hdr = &psc->hdr; + __u16 idx; + + /* + * Everything in-flight has been processed successfully. Update the + * corresponding entries in the guest's PSC buffer and zero out the + * count of in-flight PSC entries. + */ + for (idx = svm->sev_es.psc_idx; svm->sev_es.psc_inflight; + svm->sev_es.psc_inflight--, idx++) { + struct psc_entry *entry = &entries[idx]; + + entry->cur_page = entry->pagesize ? 512 : 1; + } + + hdr->cur_entry = idx; +} + +static int snp_complete_one_psc(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + struct psc_buffer *psc = svm->sev_es.ghcb_sa; + + if (vcpu->run->hypercall.ret) { + snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC); + return 1; /* resume guest */ + } + + __snp_complete_one_psc(svm); + + /* Handle the next range (if any). */ + return snp_begin_psc(svm, psc); +} + +static int snp_begin_psc(struct vcpu_svm *svm, struct psc_buffer *psc) +{ + struct psc_entry *entries = psc->entries; + struct kvm_vcpu *vcpu = &svm->vcpu; + struct psc_hdr *hdr = &psc->hdr; + struct psc_entry entry_start; + u16 idx, idx_start, idx_end; + int npages; + bool huge; + u64 gfn; + + if (!(vcpu->kvm->arch.hypercall_exit_enabled & (1 << KVM_HC_MAP_GPA_RANGE))) { + snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC); + return 1; + } + +next_range: + /* There should be no other PSCs in-flight at this point. */ + if (WARN_ON_ONCE(svm->sev_es.psc_inflight)) { + snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC); + return 1; + } + + /* + * The PSC descriptor buffer can be modified by a misbehaved guest after + * validation, so take care to only use validated copies of values used + * for things like array indexing. + */ + idx_start = hdr->cur_entry; + idx_end = hdr->end_entry; + + if (idx_end >= VMGEXIT_PSC_MAX_COUNT) { + snp_complete_psc(svm, VMGEXIT_PSC_ERROR_INVALID_HDR); + return 1; + } + + /* Find the start of the next range which needs processing. */ + for (idx = idx_start; idx <= idx_end; idx++, hdr->cur_entry++) { + entry_start = entries[idx]; + + gfn = entry_start.gfn; + huge = entry_start.pagesize; + npages = huge ? 512 : 1; + + if (entry_start.cur_page > npages || !IS_ALIGNED(gfn, npages)) { + snp_complete_psc(svm, VMGEXIT_PSC_ERROR_INVALID_ENTRY); + return 1; + } + + if (entry_start.cur_page) { + /* + * If this is a partially-completed 2M range, force 4K handling + * for the remaining pages since they're effectively split at + * this point. Subsequent code should ensure this doesn't get + * combined with adjacent PSC entries where 2M handling is still + * possible. + */ + npages -= entry_start.cur_page; + gfn += entry_start.cur_page; + huge = false; + } + + if (npages) + break; + } + + if (idx > idx_end) { + /* Nothing more to process. */ + snp_complete_psc(svm, 0); + return 1; + } + + svm->sev_es.psc_2m = huge; + svm->sev_es.psc_idx = idx; + svm->sev_es.psc_inflight = 1; + + /* + * Find all subsequent PSC entries that contain adjacent GPA + * ranges/operations and can be combined into a single + * KVM_HC_MAP_GPA_RANGE exit. + */ + while (++idx <= idx_end) { + struct psc_entry entry = entries[idx]; + + if (entry.operation != entry_start.operation || + entry.gfn != entry_start.gfn + npages || + entry.cur_page || !!entry.pagesize != huge) + break; + + svm->sev_es.psc_inflight++; + npages += huge ? 512 : 1; + } + + switch (entry_start.operation) { + case VMGEXIT_PSC_OP_PRIVATE: + case VMGEXIT_PSC_OP_SHARED: + vcpu->run->exit_reason = KVM_EXIT_HYPERCALL; + vcpu->run->hypercall.nr = KVM_HC_MAP_GPA_RANGE; + vcpu->run->hypercall.args[0] = gfn_to_gpa(gfn); + vcpu->run->hypercall.args[1] = npages; + vcpu->run->hypercall.args[2] = entry_start.operation == VMGEXIT_PSC_OP_PRIVATE + ? KVM_MAP_GPA_RANGE_ENCRYPTED + : KVM_MAP_GPA_RANGE_DECRYPTED; + vcpu->run->hypercall.args[2] |= entry_start.pagesize + ? KVM_MAP_GPA_RANGE_PAGE_SZ_2M + : KVM_MAP_GPA_RANGE_PAGE_SZ_4K; + vcpu->arch.complete_userspace_io = snp_complete_one_psc; + return 0; /* forward request to userspace */ + default: + /* + * Only shared/private PSC operations are currently supported, so if the + * entire range consists of unsupported operations (e.g. SMASH/UNSMASH), + * then consider the entire range completed and avoid exiting to + * userspace. In theory snp_complete_psc() can always be called directly + * at this point to complete the current range and start the next one, + * but that could lead to unexpected levels of recursion. + */ + __snp_complete_one_psc(svm); + goto next_range; + } + + unreachable(); +} + +static int __sev_snp_update_protected_guest_state(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + WARN_ON(!mutex_is_locked(&svm->sev_es.snp_vmsa_mutex)); + + /* Mark the vCPU as offline and not runnable */ + vcpu->arch.pv.pv_unhalted = false; + vcpu->arch.mp_state = KVM_MP_STATE_HALTED; + + /* Clear use of the VMSA */ + svm->vmcb->control.vmsa_pa = INVALID_PAGE; + + if (VALID_PAGE(svm->sev_es.snp_vmsa_gpa)) { + gfn_t gfn = gpa_to_gfn(svm->sev_es.snp_vmsa_gpa); + struct kvm_memory_slot *slot; + kvm_pfn_t pfn; + + slot = gfn_to_memslot(vcpu->kvm, gfn); + if (!slot) + return -EINVAL; + + /* + * The new VMSA will be private memory guest memory, so + * retrieve the PFN from the gmem backend. + */ + if (kvm_gmem_get_pfn(vcpu->kvm, slot, gfn, &pfn, NULL)) + return -EINVAL; + + /* + * From this point forward, the VMSA will always be a + * guest-mapped page rather than the initial one allocated + * by KVM in svm->sev_es.vmsa. In theory, svm->sev_es.vmsa + * could be free'd and cleaned up here, but that involves + * cleanups like wbinvd_on_all_cpus() which would ideally + * be handled during teardown rather than guest boot. + * Deferring that also allows the existing logic for SEV-ES + * VMSAs to be re-used with minimal SNP-specific changes. + */ + svm->sev_es.snp_has_guest_vmsa = true; + + /* Use the new VMSA */ + svm->vmcb->control.vmsa_pa = pfn_to_hpa(pfn); + + /* Mark the vCPU as runnable */ + vcpu->arch.pv.pv_unhalted = false; + vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; + + svm->sev_es.snp_vmsa_gpa = INVALID_PAGE; + + /* + * gmem pages aren't currently migratable, but if this ever + * changes then care should be taken to ensure + * svm->sev_es.vmsa is pinned through some other means. + */ + kvm_release_pfn_clean(pfn); + } + + /* + * When replacing the VMSA during SEV-SNP AP creation, + * mark the VMCB dirty so that full state is always reloaded. + */ + vmcb_mark_all_dirty(svm->vmcb); + + return 0; +} + +/* + * Invoked as part of svm_vcpu_reset() processing of an init event. + */ +void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + int ret; + + if (!sev_snp_guest(vcpu->kvm)) + return; + + mutex_lock(&svm->sev_es.snp_vmsa_mutex); + + if (!svm->sev_es.snp_ap_waiting_for_reset) + goto unlock; + + svm->sev_es.snp_ap_waiting_for_reset = false; + + ret = __sev_snp_update_protected_guest_state(vcpu); + if (ret) + vcpu_unimpl(vcpu, "snp: AP state update on init failed\n"); + +unlock: + mutex_unlock(&svm->sev_es.snp_vmsa_mutex); +} + +static int sev_snp_ap_creation(struct vcpu_svm *svm) +{ + struct kvm_sev_info *sev = &to_kvm_svm(svm->vcpu.kvm)->sev_info; + struct kvm_vcpu *vcpu = &svm->vcpu; + struct kvm_vcpu *target_vcpu; + struct vcpu_svm *target_svm; + unsigned int request; + unsigned int apic_id; + bool kick; + int ret; + + request = lower_32_bits(svm->vmcb->control.exit_info_1); + apic_id = upper_32_bits(svm->vmcb->control.exit_info_1); + + /* Validate the APIC ID */ + target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, apic_id); + if (!target_vcpu) { + vcpu_unimpl(vcpu, "vmgexit: invalid AP APIC ID [%#x] from guest\n", + apic_id); + return -EINVAL; + } + + ret = 0; + + target_svm = to_svm(target_vcpu); + + /* + * The target vCPU is valid, so the vCPU will be kicked unless the + * request is for CREATE_ON_INIT. For any errors at this stage, the + * kick will place the vCPU in an non-runnable state. + */ + kick = true; + + mutex_lock(&target_svm->sev_es.snp_vmsa_mutex); + + target_svm->sev_es.snp_vmsa_gpa = INVALID_PAGE; + target_svm->sev_es.snp_ap_waiting_for_reset = true; + + /* Interrupt injection mode shouldn't change for AP creation */ + if (request < SVM_VMGEXIT_AP_DESTROY) { + u64 sev_features; + + sev_features = vcpu->arch.regs[VCPU_REGS_RAX]; + sev_features ^= sev->vmsa_features; + + if (sev_features & SVM_SEV_FEAT_INT_INJ_MODES) { + vcpu_unimpl(vcpu, "vmgexit: invalid AP injection mode [%#lx] from guest\n", + vcpu->arch.regs[VCPU_REGS_RAX]); + ret = -EINVAL; + goto out; + } + } + + switch (request) { + case SVM_VMGEXIT_AP_CREATE_ON_INIT: + kick = false; + fallthrough; + case SVM_VMGEXIT_AP_CREATE: + if (!page_address_valid(vcpu, svm->vmcb->control.exit_info_2)) { + vcpu_unimpl(vcpu, "vmgexit: invalid AP VMSA address [%#llx] from guest\n", + svm->vmcb->control.exit_info_2); + ret = -EINVAL; + goto out; + } + + /* + * Malicious guest can RMPADJUST a large page into VMSA which + * will hit the SNP erratum where the CPU will incorrectly signal + * an RMP violation #PF if a hugepage collides with the RMP entry + * of VMSA page, reject the AP CREATE request if VMSA address from + * guest is 2M aligned. + */ + if (IS_ALIGNED(svm->vmcb->control.exit_info_2, PMD_SIZE)) { + vcpu_unimpl(vcpu, + "vmgexit: AP VMSA address [%llx] from guest is unsafe as it is 2M aligned\n", + svm->vmcb->control.exit_info_2); + ret = -EINVAL; + goto out; + } + + target_svm->sev_es.snp_vmsa_gpa = svm->vmcb->control.exit_info_2; + break; + case SVM_VMGEXIT_AP_DESTROY: + break; + default: + vcpu_unimpl(vcpu, "vmgexit: invalid AP creation request [%#x] from guest\n", + request); + ret = -EINVAL; + break; + } + +out: + if (kick) { + kvm_make_request(KVM_REQ_UPDATE_PROTECTED_GUEST_STATE, target_vcpu); + kvm_vcpu_kick(target_vcpu); + } + + mutex_unlock(&target_svm->sev_es.snp_vmsa_mutex); + + return ret; +} + +static int snp_handle_guest_req(struct vcpu_svm *svm, gpa_t req_gpa, gpa_t resp_gpa) +{ + struct sev_data_snp_guest_request data = {0}; + struct kvm *kvm = svm->vcpu.kvm; + struct kvm_sev_info *sev = to_kvm_sev_info(kvm); + sev_ret_code fw_err = 0; + int ret; + + if (!sev_snp_guest(kvm)) + return -EINVAL; + + mutex_lock(&sev->guest_req_mutex); + + if (kvm_read_guest(kvm, req_gpa, sev->guest_req_buf, PAGE_SIZE)) { + ret = -EIO; + goto out_unlock; + } + + data.gctx_paddr = __psp_pa(sev->snp_context); + data.req_paddr = __psp_pa(sev->guest_req_buf); + data.res_paddr = __psp_pa(sev->guest_resp_buf); + + /* + * Firmware failures are propagated on to guest, but any other failure + * condition along the way should be reported to userspace. E.g. if + * the PSP is dead and commands are timing out. + */ + ret = sev_issue_cmd(kvm, SEV_CMD_SNP_GUEST_REQUEST, &data, &fw_err); + if (ret && !fw_err) + goto out_unlock; + + if (kvm_write_guest(kvm, resp_gpa, sev->guest_resp_buf, PAGE_SIZE)) { + ret = -EIO; + goto out_unlock; + } + + ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, SNP_GUEST_ERR(0, fw_err)); + + ret = 1; /* resume guest */ + +out_unlock: + mutex_unlock(&sev->guest_req_mutex); + return ret; +} + +static int snp_handle_ext_guest_req(struct vcpu_svm *svm, gpa_t req_gpa, gpa_t resp_gpa) +{ + struct kvm *kvm = svm->vcpu.kvm; + u8 msg_type; + + if (!sev_snp_guest(kvm)) + return -EINVAL; + + if (kvm_read_guest(kvm, req_gpa + offsetof(struct snp_guest_msg_hdr, msg_type), + &msg_type, 1)) + return -EIO; + + /* + * As per GHCB spec, requests of type MSG_REPORT_REQ also allow for + * additional certificate data to be provided alongside the attestation + * report via the guest-provided data pages indicated by RAX/RBX. The + * certificate data is optional and requires additional KVM enablement + * to provide an interface for userspace to provide it, but KVM still + * needs to be able to handle extended guest requests either way. So + * provide a stub implementation that will always return an empty + * certificate table in the guest-provided data pages. + */ + if (msg_type == SNP_MSG_REPORT_REQ) { + struct kvm_vcpu *vcpu = &svm->vcpu; + u64 data_npages; + gpa_t data_gpa; + + if (!kvm_ghcb_rax_is_valid(svm) || !kvm_ghcb_rbx_is_valid(svm)) + goto request_invalid; + + data_gpa = vcpu->arch.regs[VCPU_REGS_RAX]; + data_npages = vcpu->arch.regs[VCPU_REGS_RBX]; + + if (!PAGE_ALIGNED(data_gpa)) + goto request_invalid; + + /* + * As per GHCB spec (see "SNP Extended Guest Request"), the + * certificate table is terminated by 24-bytes of zeroes. + */ + if (data_npages && kvm_clear_guest(kvm, data_gpa, 24)) + return -EIO; + } + + return snp_handle_guest_req(svm, req_gpa, resp_gpa); + +request_invalid: + ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 2); + ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, GHCB_ERR_INVALID_INPUT); + return 1; /* resume guest */ +} + static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm) { struct vmcb_control_area *control = &svm->vmcb->control; @@ -3008,6 +4202,38 @@ static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm) set_ghcb_msr_bits(svm, GHCB_MSR_HV_FT_RESP, GHCB_MSR_INFO_MASK, GHCB_MSR_INFO_POS); break; + case GHCB_MSR_PREF_GPA_REQ: + if (!sev_snp_guest(vcpu->kvm)) + goto out_terminate; + + set_ghcb_msr_bits(svm, GHCB_MSR_PREF_GPA_NONE, GHCB_MSR_GPA_VALUE_MASK, + GHCB_MSR_GPA_VALUE_POS); + set_ghcb_msr_bits(svm, GHCB_MSR_PREF_GPA_RESP, GHCB_MSR_INFO_MASK, + GHCB_MSR_INFO_POS); + break; + case GHCB_MSR_REG_GPA_REQ: { + u64 gfn; + + if (!sev_snp_guest(vcpu->kvm)) + goto out_terminate; + + gfn = get_ghcb_msr_bits(svm, GHCB_MSR_GPA_VALUE_MASK, + GHCB_MSR_GPA_VALUE_POS); + + svm->sev_es.ghcb_registered_gpa = gfn_to_gpa(gfn); + + set_ghcb_msr_bits(svm, gfn, GHCB_MSR_GPA_VALUE_MASK, + GHCB_MSR_GPA_VALUE_POS); + set_ghcb_msr_bits(svm, GHCB_MSR_REG_GPA_RESP, GHCB_MSR_INFO_MASK, + GHCB_MSR_INFO_POS); + break; + } + case GHCB_MSR_PSC_REQ: + if (!sev_snp_guest(vcpu->kvm)) + goto out_terminate; + + ret = snp_begin_psc_msr(svm, control->ghcb_gpa); + break; case GHCB_MSR_TERM_REQ: { u64 reason_set, reason_code; @@ -3020,12 +4246,7 @@ static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm) pr_info("SEV-ES guest requested termination: %#llx:%#llx\n", reason_set, reason_code); - vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT; - vcpu->run->system_event.type = KVM_SYSTEM_EVENT_SEV_TERM; - vcpu->run->system_event.ndata = 1; - vcpu->run->system_event.data[0] = control->ghcb_gpa; - - return 0; + goto out_terminate; } default: /* Error, keep GHCB MSR value as-is */ @@ -3036,6 +4257,14 @@ static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm) control->ghcb_gpa, ret); return ret; + +out_terminate: + vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT; + vcpu->run->system_event.type = KVM_SYSTEM_EVENT_SEV_TERM; + vcpu->run->system_event.ndata = 1; + vcpu->run->system_event.data[0] = control->ghcb_gpa; + + return 0; } int sev_handle_vmgexit(struct kvm_vcpu *vcpu) @@ -3071,6 +4300,13 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) trace_kvm_vmgexit_enter(vcpu->vcpu_id, svm->sev_es.ghcb); sev_es_sync_from_ghcb(svm); + + /* SEV-SNP guest requires that the GHCB GPA must be registered */ + if (sev_snp_guest(svm->vcpu.kvm) && !ghcb_gpa_is_registered(svm, ghcb_gpa)) { + vcpu_unimpl(&svm->vcpu, "vmgexit: GHCB GPA [%#llx] is not registered.\n", ghcb_gpa); + return -EINVAL; + } + ret = sev_es_validate_vmgexit(svm); if (ret) return ret; @@ -3145,6 +4381,28 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) vcpu->run->system_event.ndata = 1; vcpu->run->system_event.data[0] = control->ghcb_gpa; break; + case SVM_VMGEXIT_PSC: + ret = setup_vmgexit_scratch(svm, true, control->exit_info_2); + if (ret) + break; + + ret = snp_begin_psc(svm, svm->sev_es.ghcb_sa); + break; + case SVM_VMGEXIT_AP_CREATION: + ret = sev_snp_ap_creation(svm); + if (ret) { + ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 2); + ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, GHCB_ERR_INVALID_INPUT); + } + + ret = 1; + break; + case SVM_VMGEXIT_GUEST_REQUEST: + ret = snp_handle_guest_req(svm, control->exit_info_1, control->exit_info_2); + break; + case SVM_VMGEXIT_EXT_GUEST_REQUEST: + ret = snp_handle_ext_guest_req(svm, control->exit_info_1, control->exit_info_2); + break; case SVM_VMGEXIT_UNSUPPORTED_EVENT: vcpu_unimpl(vcpu, "vmgexit: unsupported event - exit_info_1=%#llx, exit_info_2=%#llx\n", @@ -3238,7 +4496,7 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm) * the VMSA will be NULL if this vCPU is the destination for intrahost * migration, and will be copied later. */ - if (svm->sev_es.vmsa) + if (svm->sev_es.vmsa && !svm->sev_es.snp_has_guest_vmsa) svm->vmcb->control.vmsa_pa = __pa(svm->sev_es.vmsa); /* Can't intercept CR register access, HV can't modify CR registers */ @@ -3310,6 +4568,8 @@ void sev_es_vcpu_reset(struct vcpu_svm *svm) set_ghcb_msr(svm, GHCB_MSR_SEV_INFO((__u64)sev->ghcb_version, GHCB_VERSION_MIN, sev_enc_bit)); + + mutex_init(&svm->sev_es.snp_vmsa_mutex); } void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_area *hostsa) @@ -3331,9 +4591,9 @@ void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_are * isn't saved by VMRUN, that isn't already saved by VMSAVE (performed * by common SVM code). */ - hostsa->xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); + hostsa->xcr0 = kvm_host.xcr0; hostsa->pkru = read_pkru(); - hostsa->xss = host_xss; + hostsa->xss = kvm_host.xss; /* * If DebugSwap is enabled, debug registers are loaded but NOT saved by @@ -3389,13 +4649,13 @@ void sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector) } } -struct page *snp_safe_alloc_page(struct kvm_vcpu *vcpu) +struct page *snp_safe_alloc_page_node(int node, gfp_t gfp) { unsigned long pfn; struct page *p; if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP)) - return alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); + return alloc_pages_node(node, gfp | __GFP_ZERO, 0); /* * Allocate an SNP-safe page to workaround the SNP erratum where @@ -3406,7 +4666,7 @@ struct page *snp_safe_alloc_page(struct kvm_vcpu *vcpu) * Allocate one extra page, choose a page which is not * 2MB-aligned, and free the other. */ - p = alloc_pages(GFP_KERNEL_ACCOUNT | __GFP_ZERO, 1); + p = alloc_pages_node(node, gfp | __GFP_ZERO, 1); if (!p) return NULL; @@ -3420,3 +4680,271 @@ struct page *snp_safe_alloc_page(struct kvm_vcpu *vcpu) return p; } + +void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code) +{ + struct kvm_memory_slot *slot; + struct kvm *kvm = vcpu->kvm; + int order, rmp_level, ret; + bool assigned; + kvm_pfn_t pfn; + gfn_t gfn; + + gfn = gpa >> PAGE_SHIFT; + + /* + * The only time RMP faults occur for shared pages is when the guest is + * triggering an RMP fault for an implicit page-state change from + * shared->private. Implicit page-state changes are forwarded to + * userspace via KVM_EXIT_MEMORY_FAULT events, however, so RMP faults + * for shared pages should not end up here. + */ + if (!kvm_mem_is_private(kvm, gfn)) { + pr_warn_ratelimited("SEV: Unexpected RMP fault for non-private GPA 0x%llx\n", + gpa); + return; + } + + slot = gfn_to_memslot(kvm, gfn); + if (!kvm_slot_can_be_private(slot)) { + pr_warn_ratelimited("SEV: Unexpected RMP fault, non-private slot for GPA 0x%llx\n", + gpa); + return; + } + + ret = kvm_gmem_get_pfn(kvm, slot, gfn, &pfn, &order); + if (ret) { + pr_warn_ratelimited("SEV: Unexpected RMP fault, no backing page for private GPA 0x%llx\n", + gpa); + return; + } + + ret = snp_lookup_rmpentry(pfn, &assigned, &rmp_level); + if (ret || !assigned) { + pr_warn_ratelimited("SEV: Unexpected RMP fault, no assigned RMP entry found for GPA 0x%llx PFN 0x%llx error %d\n", + gpa, pfn, ret); + goto out_no_trace; + } + + /* + * There are 2 cases where a PSMASH may be needed to resolve an #NPF + * with PFERR_GUEST_RMP_BIT set: + * + * 1) RMPADJUST/PVALIDATE can trigger an #NPF with PFERR_GUEST_SIZEM + * bit set if the guest issues them with a smaller granularity than + * what is indicated by the page-size bit in the 2MB RMP entry for + * the PFN that backs the GPA. + * + * 2) Guest access via NPT can trigger an #NPF if the NPT mapping is + * smaller than what is indicated by the 2MB RMP entry for the PFN + * that backs the GPA. + * + * In both these cases, the corresponding 2M RMP entry needs to + * be PSMASH'd to 512 4K RMP entries. If the RMP entry is already + * split into 4K RMP entries, then this is likely a spurious case which + * can occur when there are concurrent accesses by the guest to a 2MB + * GPA range that is backed by a 2MB-aligned PFN who's RMP entry is in + * the process of being PMASH'd into 4K entries. These cases should + * resolve automatically on subsequent accesses, so just ignore them + * here. + */ + if (rmp_level == PG_LEVEL_4K) + goto out; + + ret = snp_rmptable_psmash(pfn); + if (ret) { + /* + * Look it up again. If it's 4K now then the PSMASH may have + * raced with another process and the issue has already resolved + * itself. + */ + if (!snp_lookup_rmpentry(pfn, &assigned, &rmp_level) && + assigned && rmp_level == PG_LEVEL_4K) + goto out; + + pr_warn_ratelimited("SEV: Unable to split RMP entry for GPA 0x%llx PFN 0x%llx ret %d\n", + gpa, pfn, ret); + } + + kvm_zap_gfn_range(kvm, gfn, gfn + PTRS_PER_PMD); +out: + trace_kvm_rmp_fault(vcpu, gpa, pfn, error_code, rmp_level, ret); +out_no_trace: + put_page(pfn_to_page(pfn)); +} + +static bool is_pfn_range_shared(kvm_pfn_t start, kvm_pfn_t end) +{ + kvm_pfn_t pfn = start; + + while (pfn < end) { + int ret, rmp_level; + bool assigned; + + ret = snp_lookup_rmpentry(pfn, &assigned, &rmp_level); + if (ret) { + pr_warn_ratelimited("SEV: Failed to retrieve RMP entry: PFN 0x%llx GFN start 0x%llx GFN end 0x%llx RMP level %d error %d\n", + pfn, start, end, rmp_level, ret); + return false; + } + + if (assigned) { + pr_debug("%s: overlap detected, PFN 0x%llx start 0x%llx end 0x%llx RMP level %d\n", + __func__, pfn, start, end, rmp_level); + return false; + } + + pfn++; + } + + return true; +} + +static u8 max_level_for_order(int order) +{ + if (order >= KVM_HPAGE_GFN_SHIFT(PG_LEVEL_2M)) + return PG_LEVEL_2M; + + return PG_LEVEL_4K; +} + +static bool is_large_rmp_possible(struct kvm *kvm, kvm_pfn_t pfn, int order) +{ + kvm_pfn_t pfn_aligned = ALIGN_DOWN(pfn, PTRS_PER_PMD); + + /* + * If this is a large folio, and the entire 2M range containing the + * PFN is currently shared, then the entire 2M-aligned range can be + * set to private via a single 2M RMP entry. + */ + if (max_level_for_order(order) > PG_LEVEL_4K && + is_pfn_range_shared(pfn_aligned, pfn_aligned + PTRS_PER_PMD)) + return true; + + return false; +} + +int sev_gmem_prepare(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, int max_order) +{ + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; + kvm_pfn_t pfn_aligned; + gfn_t gfn_aligned; + int level, rc; + bool assigned; + + if (!sev_snp_guest(kvm)) + return 0; + + rc = snp_lookup_rmpentry(pfn, &assigned, &level); + if (rc) { + pr_err_ratelimited("SEV: Failed to look up RMP entry: GFN %llx PFN %llx error %d\n", + gfn, pfn, rc); + return -ENOENT; + } + + if (assigned) { + pr_debug("%s: already assigned: gfn %llx pfn %llx max_order %d level %d\n", + __func__, gfn, pfn, max_order, level); + return 0; + } + + if (is_large_rmp_possible(kvm, pfn, max_order)) { + level = PG_LEVEL_2M; + pfn_aligned = ALIGN_DOWN(pfn, PTRS_PER_PMD); + gfn_aligned = ALIGN_DOWN(gfn, PTRS_PER_PMD); + } else { + level = PG_LEVEL_4K; + pfn_aligned = pfn; + gfn_aligned = gfn; + } + + rc = rmp_make_private(pfn_aligned, gfn_to_gpa(gfn_aligned), level, sev->asid, false); + if (rc) { + pr_err_ratelimited("SEV: Failed to update RMP entry: GFN %llx PFN %llx level %d error %d\n", + gfn, pfn, level, rc); + return -EINVAL; + } + + pr_debug("%s: updated: gfn %llx pfn %llx pfn_aligned %llx max_order %d level %d\n", + __func__, gfn, pfn, pfn_aligned, max_order, level); + + return 0; +} + +void sev_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end) +{ + kvm_pfn_t pfn; + + if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP)) + return; + + pr_debug("%s: PFN start 0x%llx PFN end 0x%llx\n", __func__, start, end); + + for (pfn = start; pfn < end;) { + bool use_2m_update = false; + int rc, rmp_level; + bool assigned; + + rc = snp_lookup_rmpentry(pfn, &assigned, &rmp_level); + if (rc || !assigned) + goto next_pfn; + + use_2m_update = IS_ALIGNED(pfn, PTRS_PER_PMD) && + end >= (pfn + PTRS_PER_PMD) && + rmp_level > PG_LEVEL_4K; + + /* + * If an unaligned PFN corresponds to a 2M region assigned as a + * large page in the RMP table, PSMASH the region into individual + * 4K RMP entries before attempting to convert a 4K sub-page. + */ + if (!use_2m_update && rmp_level > PG_LEVEL_4K) { + /* + * This shouldn't fail, but if it does, report it, but + * still try to update RMP entry to shared and pray this + * was a spurious error that can be addressed later. + */ + rc = snp_rmptable_psmash(pfn); + WARN_ONCE(rc, "SEV: Failed to PSMASH RMP entry for PFN 0x%llx error %d\n", + pfn, rc); + } + + rc = rmp_make_shared(pfn, use_2m_update ? PG_LEVEL_2M : PG_LEVEL_4K); + if (WARN_ONCE(rc, "SEV: Failed to update RMP entry for PFN 0x%llx error %d\n", + pfn, rc)) + goto next_pfn; + + /* + * SEV-ES avoids host/guest cache coherency issues through + * WBINVD hooks issued via MMU notifiers during run-time, and + * KVM's VM destroy path at shutdown. Those MMU notifier events + * don't cover gmem since there is no requirement to map pages + * to a HVA in order to use them for a running guest. While the + * shutdown path would still likely cover things for SNP guests, + * userspace may also free gmem pages during run-time via + * hole-punching operations on the guest_memfd, so flush the + * cache entries for these pages before free'ing them back to + * the host. + */ + clflush_cache_range(__va(pfn_to_hpa(pfn)), + use_2m_update ? PMD_SIZE : PAGE_SIZE); +next_pfn: + pfn += use_2m_update ? PTRS_PER_PMD : 1; + cond_resched(); + } +} + +int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn) +{ + int level, rc; + bool assigned; + + if (!sev_snp_guest(kvm)) + return 0; + + rc = snp_lookup_rmpentry(pfn, &assigned, &level); + if (rc || !assigned) + return PG_LEVEL_4K; + + return level; +} diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index c95d3900fe56..c115d26844f7 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -53,6 +53,7 @@ #include "svm_onhyperv.h" MODULE_AUTHOR("Qumranet"); +MODULE_DESCRIPTION("KVM support for SVM (AMD-V) extensions"); MODULE_LICENSE("GPL"); #ifdef MODULE @@ -570,6 +571,11 @@ static void __svm_write_tsc_multiplier(u64 multiplier) __this_cpu_write(current_tsc_ratio, multiplier); } +static __always_inline struct sev_es_save_area *sev_es_host_save_area(struct svm_cpu_data *sd) +{ + return page_address(sd->save_area) + 0x400; +} + static inline void kvm_cpu_svm_disable(void) { uint64_t efer; @@ -674,12 +680,9 @@ static int svm_hardware_enable(void) * TSC_AUX field now to avoid a RDMSR on every vCPU run. */ if (boot_cpu_has(X86_FEATURE_V_TSC_AUX)) { - struct sev_es_save_area *hostsa; u32 __maybe_unused msr_hi; - hostsa = (struct sev_es_save_area *)(page_address(sd->save_area) + 0x400); - - rdmsr(MSR_TSC_AUX, hostsa->tsc_aux, msr_hi); + rdmsr(MSR_TSC_AUX, sev_es_host_save_area(sd)->tsc_aux, msr_hi); } return 0; @@ -704,7 +707,7 @@ static int svm_cpu_init(int cpu) int ret = -ENOMEM; memset(sd, 0, sizeof(struct svm_cpu_data)); - sd->save_area = snp_safe_alloc_page(NULL); + sd->save_area = snp_safe_alloc_page_node(cpu_to_node(cpu), GFP_KERNEL); if (!sd->save_area) return ret; @@ -1202,7 +1205,7 @@ static inline void init_vmcb_after_set_cpuid(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); - if (guest_cpuid_is_intel(vcpu)) { + if (guest_cpuid_is_intel_compatible(vcpu)) { /* * We must intercept SYSENTER_EIP and SYSENTER_ESP * accesses because the processor only stores 32 bits. @@ -1404,6 +1407,9 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) svm->spec_ctrl = 0; svm->virt_spec_ctrl = 0; + if (init_event) + sev_snp_init_protected_guest_state(vcpu); + init_vmcb(vcpu); if (!init_event) @@ -1427,7 +1433,7 @@ static int svm_vcpu_create(struct kvm_vcpu *vcpu) svm = to_svm(vcpu); err = -ENOMEM; - vmcb01_page = snp_safe_alloc_page(vcpu); + vmcb01_page = snp_safe_alloc_page(); if (!vmcb01_page) goto out; @@ -1436,7 +1442,7 @@ static int svm_vcpu_create(struct kvm_vcpu *vcpu) * SEV-ES guests require a separate VMSA page used to contain * the encrypted register state of the guest. */ - vmsa_page = snp_safe_alloc_page(vcpu); + vmsa_page = snp_safe_alloc_page(); if (!vmsa_page) goto error_free_vmcb_page; } @@ -1501,11 +1507,6 @@ static void svm_vcpu_free(struct kvm_vcpu *vcpu) __free_pages(virt_to_page(svm->msrpm), get_order(MSRPM_SIZE)); } -static struct sev_es_save_area *sev_es_host_save_area(struct svm_cpu_data *sd) -{ - return page_address(sd->save_area) + 0x400; -} - static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -1551,6 +1552,9 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) struct vcpu_svm *svm = to_svm(vcpu); struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, cpu); + if (vcpu->scheduled_out && !kvm_pause_in_guest(vcpu->kvm)) + shrink_ple_window(vcpu); + if (sd->current_vmcb != svm->vmcb) { sd->current_vmcb = svm->vmcb; @@ -2050,6 +2054,7 @@ static int pf_interception(struct kvm_vcpu *vcpu) static int npf_interception(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); + int rc; u64 fault_address = svm->vmcb->control.exit_info_2; u64 error_code = svm->vmcb->control.exit_info_1; @@ -2063,11 +2068,19 @@ static int npf_interception(struct kvm_vcpu *vcpu) if (WARN_ON_ONCE(error_code & PFERR_SYNTHETIC_MASK)) error_code &= ~PFERR_SYNTHETIC_MASK; + if (sev_snp_guest(vcpu->kvm) && (error_code & PFERR_GUEST_ENC_MASK)) + error_code |= PFERR_PRIVATE_ACCESS; + trace_kvm_page_fault(vcpu, fault_address, error_code); - return kvm_mmu_page_fault(vcpu, fault_address, error_code, - static_cpu_has(X86_FEATURE_DECODEASSISTS) ? - svm->vmcb->control.insn_bytes : NULL, - svm->vmcb->control.insn_len); + rc = kvm_mmu_page_fault(vcpu, fault_address, error_code, + static_cpu_has(X86_FEATURE_DECODEASSISTS) ? + svm->vmcb->control.insn_bytes : NULL, + svm->vmcb->control.insn_len); + + if (rc > 0 && error_code & PFERR_GUEST_RMP_MASK) + sev_handle_rmp_fault(vcpu, fault_address, error_code); + + return rc; } static int db_interception(struct kvm_vcpu *vcpu) @@ -2875,12 +2888,12 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; case MSR_IA32_SYSENTER_EIP: msr_info->data = (u32)svm->vmcb01.ptr->save.sysenter_eip; - if (guest_cpuid_is_intel(vcpu)) + if (guest_cpuid_is_intel_compatible(vcpu)) msr_info->data |= (u64)svm->sysenter_eip_hi << 32; break; case MSR_IA32_SYSENTER_ESP: msr_info->data = svm->vmcb01.ptr->save.sysenter_esp; - if (guest_cpuid_is_intel(vcpu)) + if (guest_cpuid_is_intel_compatible(vcpu)) msr_info->data |= (u64)svm->sysenter_esp_hi << 32; break; case MSR_TSC_AUX: @@ -3107,11 +3120,11 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) * 32 bit part of these msrs to support Intel's * implementation of SYSENTER/SYSEXIT. */ - svm->sysenter_eip_hi = guest_cpuid_is_intel(vcpu) ? (data >> 32) : 0; + svm->sysenter_eip_hi = guest_cpuid_is_intel_compatible(vcpu) ? (data >> 32) : 0; break; case MSR_IA32_SYSENTER_ESP: svm->vmcb01.ptr->save.sysenter_esp = (u32)data; - svm->sysenter_esp_hi = guest_cpuid_is_intel(vcpu) ? (data >> 32) : 0; + svm->sysenter_esp_hi = guest_cpuid_is_intel_compatible(vcpu) ? (data >> 32) : 0; break; case MSR_TSC_AUX: /* @@ -4372,11 +4385,11 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_LBRV); /* - * Intercept VMLOAD if the vCPU mode is Intel in order to emulate that + * Intercept VMLOAD if the vCPU model is Intel in order to emulate that * VMLOAD drops bits 63:32 of SYSENTER (ignoring the fact that exposing * SVM on Intel is bonkers and extremely unlikely to work). */ - if (!guest_cpuid_is_intel(vcpu)) + if (!guest_cpuid_is_intel_compatible(vcpu)) kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD); kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_PAUSEFILTER); @@ -4595,12 +4608,6 @@ static void svm_handle_exit_irqoff(struct kvm_vcpu *vcpu) vcpu->arch.at_instruction_boundary = true; } -static void svm_sched_in(struct kvm_vcpu *vcpu, int cpu) -{ - if (!kvm_pause_in_guest(vcpu->kvm)) - shrink_ple_window(vcpu); -} - static void svm_setup_mce(struct kvm_vcpu *vcpu) { /* [63:9] are reserved. */ @@ -4937,8 +4944,11 @@ static int svm_vm_init(struct kvm *kvm) if (type != KVM_X86_DEFAULT_VM && type != KVM_X86_SW_PROTECTED_VM) { - kvm->arch.has_protected_state = (type == KVM_X86_SEV_ES_VM); + kvm->arch.has_protected_state = + (type == KVM_X86_SEV_ES_VM || type == KVM_X86_SNP_VM); to_kvm_sev_info(kvm)->need_init = true; + + kvm->arch.has_private_mem = (type == KVM_X86_SNP_VM); } if (!pause_filter_count || !pause_filter_thresh) @@ -4955,7 +4965,7 @@ static int svm_vm_init(struct kvm *kvm) static void *svm_alloc_apic_backing_page(struct kvm_vcpu *vcpu) { - struct page *page = snp_safe_alloc_page(vcpu); + struct page *page = snp_safe_alloc_page(); if (!page) return NULL; @@ -5060,8 +5070,6 @@ static struct kvm_x86_ops svm_x86_ops __initdata = { .check_intercept = svm_check_intercept, .handle_exit_irqoff = svm_handle_exit_irqoff, - .sched_in = svm_sched_in, - .nested_ops = &svm_nested_ops, .deliver_interrupt = svm_deliver_interrupt, @@ -5095,6 +5103,10 @@ static struct kvm_x86_ops svm_x86_ops __initdata = { .vcpu_deliver_sipi_vector = svm_vcpu_deliver_sipi_vector, .vcpu_get_apicv_inhibit_reasons = avic_vcpu_get_apicv_inhibit_reasons, .alloc_apic_backing_page = svm_alloc_apic_backing_page, + + .gmem_prepare = sev_gmem_prepare, + .gmem_invalidate = sev_gmem_invalidate, + .private_max_mapping_level = sev_private_max_mapping_level, }; /* diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 0f1472690b59..76107c7d0595 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -94,6 +94,10 @@ struct kvm_sev_info { struct list_head mirror_entry; /* Use as a list entry of mirrors */ struct misc_cg *misc_cg; /* For misc cgroup accounting */ atomic_t migration_in_progress; + void *snp_context; /* SNP guest context page */ + void *guest_req_buf; /* Bounce buffer for SNP Guest Request input */ + void *guest_resp_buf; /* Bounce buffer for SNP Guest Request output */ + struct mutex guest_req_mutex; /* Must acquire before using bounce buffers */ }; struct kvm_svm { @@ -209,6 +213,18 @@ struct vcpu_sev_es_state { u32 ghcb_sa_len; bool ghcb_sa_sync; bool ghcb_sa_free; + + /* SNP Page-State-Change buffer entries currently being processed */ + u16 psc_idx; + u16 psc_inflight; + bool psc_2m; + + u64 ghcb_registered_gpa; + + struct mutex snp_vmsa_mutex; /* Used to handle concurrent updates of VMSA. */ + gpa_t snp_vmsa_gpa; + bool snp_ap_waiting_for_reset; + bool snp_has_guest_vmsa; }; struct vcpu_svm { @@ -350,6 +366,23 @@ static __always_inline bool sev_es_guest(struct kvm *kvm) #endif } +static __always_inline bool sev_snp_guest(struct kvm *kvm) +{ +#ifdef CONFIG_KVM_AMD_SEV + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; + + return (sev->vmsa_features & SVM_SEV_FEAT_SNP_ACTIVE) && + !WARN_ON_ONCE(!sev_es_guest(kvm)); +#else + return false; +#endif +} + +static inline bool ghcb_gpa_is_registered(struct vcpu_svm *svm, u64 val) +{ + return svm->sev_es.ghcb_registered_gpa == val; +} + static inline void vmcb_mark_all_dirty(struct vmcb *vmcb) { vmcb->control.clean = 0; @@ -638,7 +671,7 @@ extern struct kvm_x86_nested_ops svm_nested_ops; /* avic.c */ #define AVIC_REQUIRED_APICV_INHIBITS \ ( \ - BIT(APICV_INHIBIT_REASON_DISABLE) | \ + BIT(APICV_INHIBIT_REASON_DISABLED) | \ BIT(APICV_INHIBIT_REASON_ABSENT) | \ BIT(APICV_INHIBIT_REASON_HYPERV) | \ BIT(APICV_INHIBIT_REASON_NESTED) | \ @@ -696,7 +729,13 @@ void sev_guest_memory_reclaimed(struct kvm *kvm); int sev_handle_vmgexit(struct kvm_vcpu *vcpu); /* These symbols are used in common code and are stubbed below. */ -struct page *snp_safe_alloc_page(struct kvm_vcpu *vcpu); + +struct page *snp_safe_alloc_page_node(int node, gfp_t gfp); +static inline struct page *snp_safe_alloc_page(void) +{ + return snp_safe_alloc_page_node(numa_node_id(), GFP_KERNEL_ACCOUNT); +} + void sev_free_vcpu(struct kvm_vcpu *vcpu); void sev_vm_destroy(struct kvm *kvm); void __init sev_set_cpu_caps(void); @@ -705,9 +744,20 @@ void sev_hardware_unsetup(void); int sev_cpu_init(struct svm_cpu_data *sd); int sev_dev_get_attr(u32 group, u64 attr, u64 *val); extern unsigned int max_sev_asid; +void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code); +void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu); +int sev_gmem_prepare(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, int max_order); +void sev_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end); +int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn); #else -static inline struct page *snp_safe_alloc_page(struct kvm_vcpu *vcpu) { - return alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); +static inline struct page *snp_safe_alloc_page_node(int node, gfp_t gfp) +{ + return alloc_pages_node(node, gfp | __GFP_ZERO, 0); +} + +static inline struct page *snp_safe_alloc_page(void) +{ + return snp_safe_alloc_page_node(numa_node_id(), GFP_KERNEL_ACCOUNT); } static inline void sev_free_vcpu(struct kvm_vcpu *vcpu) {} @@ -718,6 +768,18 @@ static inline void sev_hardware_unsetup(void) {} static inline int sev_cpu_init(struct svm_cpu_data *sd) { return 0; } static inline int sev_dev_get_attr(u32 group, u64 attr, u64 *val) { return -ENXIO; } #define max_sev_asid 0 +static inline void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code) {} +static inline void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu) {} +static inline int sev_gmem_prepare(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, int max_order) +{ + return 0; +} +static inline void sev_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end) {} +static inline int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn) +{ + return 0; +} + #endif /* vmenter.S */ diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index e19fed438a67..d3aeffd6ae75 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -314,12 +314,12 @@ TRACE_EVENT(name, \ __entry->guest_rip = kvm_rip_read(vcpu); \ __entry->isa = isa; \ __entry->vcpu_id = vcpu->vcpu_id; \ - static_call(kvm_x86_get_exit_info)(vcpu, \ - &__entry->exit_reason, \ - &__entry->info1, \ - &__entry->info2, \ - &__entry->intr_info, \ - &__entry->error_code); \ + kvm_x86_call(get_exit_info)(vcpu, \ + &__entry->exit_reason, \ + &__entry->info1, \ + &__entry->info2, \ + &__entry->intr_info, \ + &__entry->error_code); \ ), \ \ TP_printk("vcpu %u reason %s%s%s rip 0x%lx info1 0x%016llx " \ @@ -828,7 +828,8 @@ TRACE_EVENT(kvm_emulate_insn, ), TP_fast_assign( - __entry->csbase = static_call(kvm_x86_get_segment_base)(vcpu, VCPU_SREG_CS); + __entry->csbase = kvm_x86_call(get_segment_base)(vcpu, + VCPU_SREG_CS); __entry->len = vcpu->arch.emulate_ctxt->fetch.ptr - vcpu->arch.emulate_ctxt->fetch.data; __entry->rip = vcpu->arch.emulate_ctxt->_eip - __entry->len; @@ -1375,6 +1376,10 @@ TRACE_EVENT(kvm_hv_stimer_cleanup, __entry->vcpu_id, __entry->timer_index) ); +#define kvm_print_apicv_inhibit_reasons(inhibits) \ + (inhibits), (inhibits) ? " " : "", \ + (inhibits) ? __print_flags(inhibits, "|", APICV_INHIBIT_REASONS) : "" + TRACE_EVENT(kvm_apicv_inhibit_changed, TP_PROTO(int reason, bool set, unsigned long inhibits), TP_ARGS(reason, set, inhibits), @@ -1391,9 +1396,10 @@ TRACE_EVENT(kvm_apicv_inhibit_changed, __entry->inhibits = inhibits; ), - TP_printk("%s reason=%u, inhibits=0x%lx", + TP_printk("%s reason=%u, inhibits=0x%lx%s%s", __entry->set ? "set" : "cleared", - __entry->reason, __entry->inhibits) + __entry->reason, + kvm_print_apicv_inhibit_reasons(__entry->inhibits)) ); TRACE_EVENT(kvm_apicv_accept_irq, @@ -1834,6 +1840,37 @@ TRACE_EVENT(kvm_vmgexit_msr_protocol_exit, __entry->vcpu_id, __entry->ghcb_gpa, __entry->result) ); +/* + * Tracepoint for #NPFs due to RMP faults. + */ +TRACE_EVENT(kvm_rmp_fault, + TP_PROTO(struct kvm_vcpu *vcpu, u64 gpa, u64 pfn, u64 error_code, + int rmp_level, int psmash_ret), + TP_ARGS(vcpu, gpa, pfn, error_code, rmp_level, psmash_ret), + + TP_STRUCT__entry( + __field(unsigned int, vcpu_id) + __field(u64, gpa) + __field(u64, pfn) + __field(u64, error_code) + __field(int, rmp_level) + __field(int, psmash_ret) + ), + + TP_fast_assign( + __entry->vcpu_id = vcpu->vcpu_id; + __entry->gpa = gpa; + __entry->pfn = pfn; + __entry->error_code = error_code; + __entry->rmp_level = rmp_level; + __entry->psmash_ret = psmash_ret; + ), + + TP_printk("vcpu %u gpa %016llx pfn 0x%llx error_code 0x%llx rmp_level %d psmash_ret %d", + __entry->vcpu_id, __entry->gpa, __entry->pfn, + __entry->error_code, __entry->rmp_level, __entry->psmash_ret) +); + #endif /* _TRACE_KVM_H */ #undef TRACE_INCLUDE_PATH diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c index d4ed681785fd..0bf35ebe8a1b 100644 --- a/arch/x86/kvm/vmx/main.c +++ b/arch/x86/kvm/vmx/main.c @@ -8,7 +8,7 @@ #include "posted_intr.h" #define VMX_REQUIRED_APICV_INHIBITS \ - (BIT(APICV_INHIBIT_REASON_DISABLE)| \ + (BIT(APICV_INHIBIT_REASON_DISABLED) | \ BIT(APICV_INHIBIT_REASON_ABSENT) | \ BIT(APICV_INHIBIT_REASON_HYPERV) | \ BIT(APICV_INHIBIT_REASON_BLOCKIRQ) | \ @@ -97,7 +97,6 @@ struct kvm_x86_ops vt_x86_ops __initdata = { .required_apicv_inhibits = VMX_REQUIRED_APICV_INHIBITS, .hwapic_irr_update = vmx_hwapic_irr_update, .hwapic_isr_update = vmx_hwapic_isr_update, - .guest_apic_has_interrupt = vmx_guest_apic_has_interrupt, .sync_pir_to_irr = vmx_sync_pir_to_irr, .deliver_interrupt = vmx_deliver_interrupt, .dy_apicv_has_pending_interrupt = pi_has_pending_interrupt, @@ -122,8 +121,6 @@ struct kvm_x86_ops vt_x86_ops __initdata = { .check_intercept = vmx_check_intercept, .handle_exit_irqoff = vmx_handle_exit_irqoff, - .sched_in = vmx_sched_in, - .cpu_dirty_log_size = PML_ENTITY_NUM, .update_cpu_dirty_logging = vmx_update_cpu_dirty_logging, diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 643935a0f70a..2392a7ef254d 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -12,6 +12,7 @@ #include "mmu.h" #include "nested.h" #include "pmu.h" +#include "posted_intr.h" #include "sgx.h" #include "trace.h" #include "vmx.h" @@ -2425,7 +2426,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0 if (cpu_has_load_ia32_efer()) { if (guest_efer & EFER_LMA) exec_control |= VM_ENTRY_IA32E_MODE; - if (guest_efer != host_efer) + if (guest_efer != kvm_host.efer) exec_control |= VM_ENTRY_LOAD_IA32_EFER; } vm_entry_controls_set(vmx, exec_control); @@ -2438,7 +2439,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0 * bits may be modified by vmx_set_efer() in prepare_vmcs02(). */ exec_control = __vm_exit_controls_get(vmcs01); - if (cpu_has_load_ia32_efer() && guest_efer != host_efer) + if (cpu_has_load_ia32_efer() && guest_efer != kvm_host.efer) exec_control |= VM_EXIT_LOAD_IA32_EFER; else exec_control &= ~VM_EXIT_LOAD_IA32_EFER; @@ -3899,8 +3900,8 @@ static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu) if (!pi_test_and_clear_on(vmx->nested.pi_desc)) return 0; - max_irr = find_last_bit((unsigned long *)vmx->nested.pi_desc->pir, 256); - if (max_irr != 256) { + max_irr = pi_find_highest_vector(vmx->nested.pi_desc); + if (max_irr > 0) { vapic_page = vmx->nested.virtual_apic_map.hva; if (!vapic_page) goto mmio_needed; @@ -4031,10 +4032,46 @@ static bool nested_vmx_preemption_timer_pending(struct kvm_vcpu *vcpu) to_vmx(vcpu)->nested.preemption_timer_expired; } -static bool vmx_has_nested_events(struct kvm_vcpu *vcpu) +static bool vmx_has_nested_events(struct kvm_vcpu *vcpu, bool for_injection) { - return nested_vmx_preemption_timer_pending(vcpu) || - to_vmx(vcpu)->nested.mtf_pending; + struct vcpu_vmx *vmx = to_vmx(vcpu); + void *vapic = vmx->nested.virtual_apic_map.hva; + int max_irr, vppr; + + if (nested_vmx_preemption_timer_pending(vcpu) || + vmx->nested.mtf_pending) + return true; + + /* + * Virtual Interrupt Delivery doesn't require manual injection. Either + * the interrupt is already in GUEST_RVI and will be recognized by CPU + * at VM-Entry, or there is a KVM_REQ_EVENT pending and KVM will move + * the interrupt from the PIR to RVI prior to entering the guest. + */ + if (for_injection) + return false; + + if (!nested_cpu_has_vid(get_vmcs12(vcpu)) || + __vmx_interrupt_blocked(vcpu)) + return false; + + if (!vapic) + return false; + + vppr = *((u32 *)(vapic + APIC_PROCPRI)); + + max_irr = vmx_get_rvi(); + if ((max_irr & 0xf0) > (vppr & 0xf0)) + return true; + + if (vmx->nested.pi_pending && vmx->nested.pi_desc && + pi_test_on(vmx->nested.pi_desc)) { + max_irr = pi_find_highest_vector(vmx->nested.pi_desc); + if (max_irr > 0 && (max_irr & 0xf0) > (vppr & 0xf0)) + return true; + } + + return false; } /* @@ -4665,7 +4702,7 @@ static inline u64 nested_vmx_get_vmcs01_guest_efer(struct vcpu_vmx *vmx) return vmcs_read64(GUEST_IA32_EFER); if (cpu_has_load_ia32_efer()) - return host_efer; + return kvm_host.efer; for (i = 0; i < vmx->msr_autoload.guest.nr; ++i) { if (vmx->msr_autoload.guest.val[i].index == MSR_EFER) @@ -4676,7 +4713,7 @@ static inline u64 nested_vmx_get_vmcs01_guest_efer(struct vcpu_vmx *vmx) if (efer_msr) return efer_msr->data; - return host_efer; + return kvm_host.efer; } static void nested_vmx_restore_host_state(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index be40474de6e4..83382a4d1d66 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -348,14 +348,14 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) switch (msr) { case MSR_CORE_PERF_FIXED_CTR_CTRL: - if (data & pmu->fixed_ctr_ctrl_mask) + if (data & pmu->fixed_ctr_ctrl_rsvd) return 1; if (pmu->fixed_ctr_ctrl != data) reprogram_fixed_counters(pmu, data); break; case MSR_IA32_PEBS_ENABLE: - if (data & pmu->pebs_enable_mask) + if (data & pmu->pebs_enable_rsvd) return 1; if (pmu->pebs_enable != data) { @@ -371,7 +371,7 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) pmu->ds_area = data; break; case MSR_PEBS_DATA_CFG: - if (data & pmu->pebs_data_cfg_mask) + if (data & pmu->pebs_data_cfg_rsvd) return 1; pmu->pebs_data_cfg = data; @@ -436,8 +436,8 @@ static __always_inline u64 intel_get_fixed_pmc_eventsel(unsigned int index) }; u64 eventsel; - BUILD_BUG_ON(ARRAY_SIZE(fixed_pmc_perf_ids) != KVM_PMC_MAX_FIXED); - BUILD_BUG_ON(index >= KVM_PMC_MAX_FIXED); + BUILD_BUG_ON(ARRAY_SIZE(fixed_pmc_perf_ids) != KVM_MAX_NR_INTEL_FIXED_COUTNERS); + BUILD_BUG_ON(index >= KVM_MAX_NR_INTEL_FIXED_COUTNERS); /* * Yell if perf reports support for a fixed counter but perf doesn't @@ -448,6 +448,14 @@ static __always_inline u64 intel_get_fixed_pmc_eventsel(unsigned int index) return eventsel; } +static void intel_pmu_enable_fixed_counter_bits(struct kvm_pmu *pmu, u64 bits) +{ + int i; + + for (i = 0; i < pmu->nr_arch_fixed_counters; i++) + pmu->fixed_ctr_ctrl_rsvd &= ~intel_fixed_bits_by_idx(i, bits); +} + static void intel_pmu_refresh(struct kvm_vcpu *vcpu) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); @@ -456,8 +464,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) union cpuid10_eax eax; union cpuid10_edx edx; u64 perf_capabilities; - u64 counter_mask; - int i; + u64 counter_rsvd; memset(&lbr_desc->records, 0, sizeof(lbr_desc->records)); @@ -501,22 +508,24 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) ((u64)1 << edx.split.bit_width_fixed) - 1; } - for (i = 0; i < pmu->nr_arch_fixed_counters; i++) - pmu->fixed_ctr_ctrl_mask &= ~(0xbull << (i * 4)); - counter_mask = ~(((1ull << pmu->nr_arch_gp_counters) - 1) | + intel_pmu_enable_fixed_counter_bits(pmu, INTEL_FIXED_0_KERNEL | + INTEL_FIXED_0_USER | + INTEL_FIXED_0_ENABLE_PMI); + + counter_rsvd = ~(((1ull << pmu->nr_arch_gp_counters) - 1) | (((1ull << pmu->nr_arch_fixed_counters) - 1) << KVM_FIXED_PMC_BASE_IDX)); - pmu->global_ctrl_mask = counter_mask; + pmu->global_ctrl_rsvd = counter_rsvd; /* * GLOBAL_STATUS and GLOBAL_OVF_CONTROL (a.k.a. GLOBAL_STATUS_RESET) * share reserved bit definitions. The kernel just happens to use * OVF_CTRL for the names. */ - pmu->global_status_mask = pmu->global_ctrl_mask + pmu->global_status_rsvd = pmu->global_ctrl_rsvd & ~(MSR_CORE_PERF_GLOBAL_OVF_CTRL_OVF_BUF | MSR_CORE_PERF_GLOBAL_OVF_CTRL_COND_CHGD); if (vmx_pt_mode_is_host_guest()) - pmu->global_status_mask &= + pmu->global_status_rsvd &= ~MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI; entry = kvm_find_cpuid_entry_index(vcpu, 7, 0); @@ -544,15 +553,12 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) if (perf_capabilities & PERF_CAP_PEBS_FORMAT) { if (perf_capabilities & PERF_CAP_PEBS_BASELINE) { - pmu->pebs_enable_mask = counter_mask; + pmu->pebs_enable_rsvd = counter_rsvd; pmu->reserved_bits &= ~ICL_EVENTSEL_ADAPTIVE; - for (i = 0; i < pmu->nr_arch_fixed_counters; i++) { - pmu->fixed_ctr_ctrl_mask &= - ~(1ULL << (KVM_FIXED_PMC_BASE_IDX + i * 4)); - } - pmu->pebs_data_cfg_mask = ~0xff00000full; + pmu->pebs_data_cfg_rsvd = ~0xff00000full; + intel_pmu_enable_fixed_counter_bits(pmu, ICL_FIXED_0_ADAPTIVE); } else { - pmu->pebs_enable_mask = + pmu->pebs_enable_rsvd = ~((1ull << pmu->nr_arch_gp_counters) - 1); } } @@ -564,14 +570,14 @@ static void intel_pmu_init(struct kvm_vcpu *vcpu) struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu); - for (i = 0; i < KVM_INTEL_PMC_MAX_GENERIC; i++) { + for (i = 0; i < KVM_MAX_NR_INTEL_GP_COUNTERS; i++) { pmu->gp_counters[i].type = KVM_PMC_GP; pmu->gp_counters[i].vcpu = vcpu; pmu->gp_counters[i].idx = i; pmu->gp_counters[i].current_config = 0; } - for (i = 0; i < KVM_PMC_MAX_FIXED; i++) { + for (i = 0; i < KVM_MAX_NR_INTEL_FIXED_COUTNERS; i++) { pmu->fixed_counters[i].type = KVM_PMC_FIXED; pmu->fixed_counters[i].vcpu = vcpu; pmu->fixed_counters[i].idx = i + KVM_FIXED_PMC_BASE_IDX; @@ -731,6 +737,6 @@ struct kvm_pmu_ops intel_pmu_ops __initdata = { .deliver_pmi = intel_pmu_deliver_pmi, .cleanup = intel_pmu_cleanup, .EVENTSEL_EVENT = ARCH_PERFMON_EVENTSEL_EVENT, - .MAX_NR_GP_COUNTERS = KVM_INTEL_PMC_MAX_GENERIC, + .MAX_NR_GP_COUNTERS = KVM_MAX_NR_INTEL_GP_COUNTERS, .MIN_NR_GP_COUNTERS = 1, }; diff --git a/arch/x86/kvm/vmx/posted_intr.h b/arch/x86/kvm/vmx/posted_intr.h index 6b2a0226257e..1715d2ab07be 100644 --- a/arch/x86/kvm/vmx/posted_intr.h +++ b/arch/x86/kvm/vmx/posted_intr.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __KVM_X86_VMX_POSTED_INTR_H #define __KVM_X86_VMX_POSTED_INTR_H + +#include #include void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu); @@ -12,4 +14,12 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq, uint32_t guest_irq, bool set); void vmx_pi_start_assignment(struct kvm *kvm); +static inline int pi_find_highest_vector(struct pi_desc *pi_desc) +{ + int vec; + + vec = find_last_bit((unsigned long *)pi_desc->pir, 256); + return vec < 256 ? vec : -1; +} + #endif /* __KVM_X86_VMX_POSTED_INTR_H */ diff --git a/arch/x86/kvm/vmx/vmcs12.h b/arch/x86/kvm/vmx/vmcs12.h index 01936013428b..56fd150a6f24 100644 --- a/arch/x86/kvm/vmx/vmcs12.h +++ b/arch/x86/kvm/vmx/vmcs12.h @@ -188,12 +188,13 @@ struct __packed vmcs12 { }; /* - * VMCS12_REVISION is an arbitrary id that should be changed if the content or - * layout of struct vmcs12 is changed. MSR_IA32_VMX_BASIC returns this id, and - * VMPTRLD verifies that the VMCS region that L1 is loading contains this id. + * VMCS12_REVISION is KVM's arbitrary ID for the layout of struct vmcs12. KVM + * enumerates this value to L1 via MSR_IA32_VMX_BASIC, and checks the revision + * ID during nested VMPTRLD to verify that L1 is loading a VMCS that adhere's + * to KVM's virtual CPU definition. * - * IMPORTANT: Changing this value will break save/restore compatibility with - * older kvm releases. + * DO NOT change this value, as it will break save/restore compatibility with + * older KVM releases. */ #define VMCS12_REVISION 0x11e57ed0 @@ -206,7 +207,8 @@ struct __packed vmcs12 { #define VMCS12_SIZE KVM_STATE_NESTED_VMX_VMCS_SIZE /* - * For save/restore compatibility, the vmcs12 field offsets must not change. + * For save/restore compatibility, the vmcs12 field offsets must not change, + * although appending fields and/or filling gaps is obviously allowed. */ #define CHECK_OFFSET(field, loc) \ ASSERT_STRUCT_OFFSET(struct vmcs12, field, loc) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index b3c83c06f826..f18c2d8c7476 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -74,6 +74,7 @@ #include "posted_intr.h" MODULE_AUTHOR("Qumranet"); +MODULE_DESCRIPTION("KVM support for VMX (Intel VT-x) extensions"); MODULE_LICENSE("GPL"); #ifdef MODULE @@ -259,7 +260,7 @@ static int vmx_setup_l1d_flush(enum vmx_l1d_flush_state l1tf) return 0; } - if (host_arch_capabilities & ARCH_CAP_SKIP_VMENTRY_L1DFLUSH) { + if (kvm_host.arch_capabilities & ARCH_CAP_SKIP_VMENTRY_L1DFLUSH) { l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_NOT_REQUIRED; return 0; } @@ -404,7 +405,7 @@ static void vmx_update_fb_clear_dis(struct kvm_vcpu *vcpu, struct vcpu_vmx *vmx) * and VM-Exit. */ vmx->disable_fb_clear = !cpu_feature_enabled(X86_FEATURE_CLEAR_CPU_BUF) && - (host_arch_capabilities & ARCH_CAP_FB_CLEAR_CTRL) && + (kvm_host.arch_capabilities & ARCH_CAP_FB_CLEAR_CTRL) && !boot_cpu_has_bug(X86_BUG_MDS) && !boot_cpu_has_bug(X86_BUG_TAA); @@ -1123,12 +1124,12 @@ static bool update_transition_efer(struct vcpu_vmx *vmx) * atomically, since it's faster than switching it manually. */ if (cpu_has_load_ia32_efer() || - (enable_ept && ((vmx->vcpu.arch.efer ^ host_efer) & EFER_NX))) { + (enable_ept && ((vmx->vcpu.arch.efer ^ kvm_host.efer) & EFER_NX))) { if (!(guest_efer & EFER_LMA)) guest_efer &= ~EFER_LME; - if (guest_efer != host_efer) + if (guest_efer != kvm_host.efer) add_atomic_switch_msr(vmx, MSR_EFER, - guest_efer, host_efer, false); + guest_efer, kvm_host.efer, false); else clear_atomic_switch_msr(vmx, MSR_EFER); return false; @@ -1141,7 +1142,7 @@ static bool update_transition_efer(struct vcpu_vmx *vmx) clear_atomic_switch_msr(vmx, MSR_EFER); guest_efer &= ~ignore_bits; - guest_efer |= host_efer & ignore_bits; + guest_efer |= kvm_host.efer & ignore_bits; vmx->guest_uret_msrs[i].data = guest_efer; vmx->guest_uret_msrs[i].mask = ~ignore_bits; @@ -1411,6 +1412,38 @@ static void vmx_write_guest_kernel_gs_base(struct vcpu_vmx *vmx, u64 data) } #endif +static void grow_ple_window(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + unsigned int old = vmx->ple_window; + + vmx->ple_window = __grow_ple_window(old, ple_window, + ple_window_grow, + ple_window_max); + + if (vmx->ple_window != old) { + vmx->ple_window_dirty = true; + trace_kvm_ple_window_update(vcpu->vcpu_id, + vmx->ple_window, old); + } +} + +static void shrink_ple_window(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + unsigned int old = vmx->ple_window; + + vmx->ple_window = __shrink_ple_window(old, ple_window, + ple_window_shrink, + ple_window); + + if (vmx->ple_window != old) { + vmx->ple_window_dirty = true; + trace_kvm_ple_window_update(vcpu->vcpu_id, + vmx->ple_window, old); + } +} + void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu, struct loaded_vmcs *buddy) { @@ -1486,6 +1519,9 @@ void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); + if (vcpu->scheduled_out && !kvm_pause_in_guest(vcpu->kvm)) + shrink_ple_window(vcpu); + vmx_vcpu_load_vmcs(vcpu, cpu, NULL); vmx_vcpu_pi_load(vcpu, cpu); @@ -2525,17 +2561,15 @@ static bool cpu_has_sgx(void) */ static bool cpu_has_perf_global_ctrl_bug(void) { - if (boot_cpu_data.x86 == 0x6) { - switch (boot_cpu_data.x86_model) { - case INTEL_FAM6_NEHALEM_EP: /* AAK155 */ - case INTEL_FAM6_NEHALEM: /* AAP115 */ - case INTEL_FAM6_WESTMERE: /* AAT100 */ - case INTEL_FAM6_WESTMERE_EP: /* BC86,AAY89,BD102 */ - case INTEL_FAM6_NEHALEM_EX: /* BA97 */ - return true; - default: - break; - } + switch (boot_cpu_data.x86_vfm) { + case INTEL_NEHALEM_EP: /* AAK155 */ + case INTEL_NEHALEM: /* AAP115 */ + case INTEL_WESTMERE: /* AAT100 */ + case INTEL_WESTMERE_EP: /* BC86,AAY89,BD102 */ + case INTEL_NEHALEM_EX: /* BA97 */ + return true; + default: + break; } return false; @@ -2834,9 +2868,6 @@ int vmx_hardware_enable(void) return r; } - if (enable_ept) - ept_sync_global(); - return 0; } @@ -4108,26 +4139,6 @@ void pt_update_intercept_for_msr(struct kvm_vcpu *vcpu) } } -bool vmx_guest_apic_has_interrupt(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - void *vapic_page; - u32 vppr; - int rvi; - - if (WARN_ON_ONCE(!is_guest_mode(vcpu)) || - !nested_cpu_has_vid(get_vmcs12(vcpu)) || - WARN_ON_ONCE(!vmx->nested.virtual_apic_map.gfn)) - return false; - - rvi = vmx_get_rvi(); - - vapic_page = vmx->nested.virtual_apic_map.hva; - vppr = *((u32 *)(vapic_page + APIC_PROCPRI)); - - return ((rvi & 0xf0) > (vppr & 0xf0)); -} - void vmx_msr_filter_changed(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -4357,7 +4368,7 @@ void vmx_set_constant_host_state(struct vcpu_vmx *vmx) } if (cpu_has_load_ia32_efer()) - vmcs_write64(HOST_IA32_EFER, host_efer); + vmcs_write64(HOST_IA32_EFER, kvm_host.efer); } void set_cr4_guest_host_mask(struct vcpu_vmx *vmx) @@ -5052,14 +5063,19 @@ int vmx_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection) return !vmx_nmi_blocked(vcpu); } +bool __vmx_interrupt_blocked(struct kvm_vcpu *vcpu) +{ + return !(vmx_get_rflags(vcpu) & X86_EFLAGS_IF) || + (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & + (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)); +} + bool vmx_interrupt_blocked(struct kvm_vcpu *vcpu) { if (is_guest_mode(vcpu) && nested_exit_on_intr(vcpu)) return false; - return !(vmx_get_rflags(vcpu) & X86_EFLAGS_IF) || - (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & - (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)); + return __vmx_interrupt_blocked(vcpu); } int vmx_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection) @@ -5897,38 +5913,6 @@ int vmx_vcpu_pre_run(struct kvm_vcpu *vcpu) return 1; } -static void grow_ple_window(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - unsigned int old = vmx->ple_window; - - vmx->ple_window = __grow_ple_window(old, ple_window, - ple_window_grow, - ple_window_max); - - if (vmx->ple_window != old) { - vmx->ple_window_dirty = true; - trace_kvm_ple_window_update(vcpu->vcpu_id, - vmx->ple_window, old); - } -} - -static void shrink_ple_window(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - unsigned int old = vmx->ple_window; - - vmx->ple_window = __shrink_ple_window(old, ple_window, - ple_window_shrink, - ple_window); - - if (vmx->ple_window != old) { - vmx->ple_window_dirty = true; - trace_kvm_ple_window_update(vcpu->vcpu_id, - vmx->ple_window, old); - } -} - /* * Indicate a busy-waiting vcpu in spinlock. We do not enable the PAUSE * exiting, so only get here on cpu with PAUSE-Loop-Exiting. @@ -6677,9 +6661,10 @@ static noinstr void vmx_l1d_flush(struct kvm_vcpu *vcpu) bool flush_l1d; /* - * Clear the per-vcpu flush bit, it gets set again - * either from vcpu_run() or from one of the unsafe - * VMEXIT handlers. + * Clear the per-vcpu flush bit, it gets set again if the vCPU + * is reloaded, i.e. if the vCPU is scheduled out or if KVM + * exits to userspace, or if KVM reaches one of the unsafe + * VMEXIT handlers, e.g. if KVM calls into the emulator. */ flush_l1d = vcpu->arch.l1tf_flush_l1d; vcpu->arch.l1tf_flush_l1d = false; @@ -7665,39 +7650,25 @@ int vmx_vm_init(struct kvm *kvm) u8 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio) { - /* We wanted to honor guest CD/MTRR/PAT, but doing so could result in - * memory aliases with conflicting memory types and sometimes MCEs. - * We have to be careful as to what are honored and when. - * - * For MMIO, guest CD/MTRR are ignored. The EPT memory type is set to - * UC. The effective memory type is UC or WC depending on guest PAT. - * This was historically the source of MCEs and we want to be - * conservative. - * - * When there is no need to deal with noncoherent DMA (e.g., no VT-d - * or VT-d has snoop control), guest CD/MTRR/PAT are all ignored. The - * EPT memory type is set to WB. The effective memory type is forced - * WB. - * - * Otherwise, we trust guest. Guest CD/MTRR/PAT are all honored. The - * EPT memory type is used to emulate guest CD/MTRR. + /* + * Force UC for host MMIO regions, as allowing the guest to access MMIO + * with cacheable accesses will result in Machine Checks. */ - if (is_mmio) return MTRR_TYPE_UNCACHABLE << VMX_EPT_MT_EPTE_SHIFT; - if (!kvm_arch_has_noncoherent_dma(vcpu->kvm)) + /* + * Force WB and ignore guest PAT if the VM does NOT have a non-coherent + * device attached and the CPU doesn't support self-snoop. Letting the + * guest control memory types on Intel CPUs without self-snoop may + * result in unexpected behavior, and so KVM's (historical) ABI is to + * trust the guest to behave only as a last resort. + */ + if (!static_cpu_has(X86_FEATURE_SELFSNOOP) && + !kvm_arch_has_noncoherent_dma(vcpu->kvm)) return (MTRR_TYPE_WRBACK << VMX_EPT_MT_EPTE_SHIFT) | VMX_EPT_IPAT_BIT; - if (kvm_read_cr0_bits(vcpu, X86_CR0_CD)) { - if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_CD_NW_CLEARED)) - return MTRR_TYPE_WRBACK << VMX_EPT_MT_EPTE_SHIFT; - else - return (MTRR_TYPE_UNCACHABLE << VMX_EPT_MT_EPTE_SHIFT) | - VMX_EPT_IPAT_BIT; - } - - return kvm_mtrr_get_guest_memory_type(vcpu, gfn) << VMX_EPT_MT_EPTE_SHIFT; + return (MTRR_TYPE_WRBACK << VMX_EPT_MT_EPTE_SHIFT); } static void vmcs_set_secondary_exec_control(struct vcpu_vmx *vmx, u32 new_ctl) @@ -8179,12 +8150,6 @@ void vmx_cancel_hv_timer(struct kvm_vcpu *vcpu) } #endif -void vmx_sched_in(struct kvm_vcpu *vcpu, int cpu) -{ - if (!kvm_pause_in_guest(vcpu->kvm)) - shrink_ple_window(vcpu); -} - void vmx_update_cpu_dirty_logging(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -8396,18 +8361,16 @@ static void __init vmx_setup_me_spte_mask(void) u64 me_mask = 0; /* - * kvm_get_shadow_phys_bits() returns shadow_phys_bits. Use - * the former to avoid exposing shadow_phys_bits. - * * On pre-MKTME system, boot_cpu_data.x86_phys_bits equals to - * shadow_phys_bits. On MKTME and/or TDX capable systems, + * kvm_host.maxphyaddr. On MKTME and/or TDX capable systems, * boot_cpu_data.x86_phys_bits holds the actual physical address - * w/o the KeyID bits, and shadow_phys_bits equals to MAXPHYADDR - * reported by CPUID. Those bits between are KeyID bits. + * w/o the KeyID bits, and kvm_host.maxphyaddr equals to + * MAXPHYADDR reported by CPUID. Those bits between are KeyID bits. */ - if (boot_cpu_data.x86_phys_bits != kvm_get_shadow_phys_bits()) + if (boot_cpu_data.x86_phys_bits != kvm_host.maxphyaddr) me_mask = rsvd_bits(boot_cpu_data.x86_phys_bits, - kvm_get_shadow_phys_bits() - 1); + kvm_host.maxphyaddr - 1); + /* * Unlike SME, host kernel doesn't support setting up any * MKTME KeyID on Intel platforms. No memory encryption @@ -8629,9 +8592,9 @@ static void __vmx_exit(void) static void vmx_exit(void) { kvm_exit(); + __vmx_exit(); kvm_x86_vendor_exit(); - __vmx_exit(); } module_exit(vmx_exit); diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index 7b64e271a931..42498fa63abb 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -406,6 +406,7 @@ u64 construct_eptp(struct kvm_vcpu *vcpu, hpa_t root_hpa, int root_level); bool vmx_guest_inject_ac(struct kvm_vcpu *vcpu); void vmx_update_exception_bitmap(struct kvm_vcpu *vcpu); bool vmx_nmi_blocked(struct kvm_vcpu *vcpu); +bool __vmx_interrupt_blocked(struct kvm_vcpu *vcpu); bool vmx_interrupt_blocked(struct kvm_vcpu *vcpu); bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu); void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked); @@ -727,7 +728,7 @@ static inline bool vmx_need_pf_intercept(struct kvm_vcpu *vcpu) return true; return allow_smaller_maxphyaddr && - cpuid_maxphyaddr(vcpu) < kvm_get_shadow_phys_bits(); + cpuid_maxphyaddr(vcpu) < kvm_host.maxphyaddr; } static inline bool is_unrestricted_guest(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/vmx/x86_ops.h b/arch/x86/kvm/vmx/x86_ops.h index 502704596c83..ce3221cd1d01 100644 --- a/arch/x86/kvm/vmx/x86_ops.h +++ b/arch/x86/kvm/vmx/x86_ops.h @@ -46,10 +46,8 @@ bool vmx_apic_init_signal_blocked(struct kvm_vcpu *vcpu); void vmx_migrate_timers(struct kvm_vcpu *vcpu); void vmx_set_virtual_apic_mode(struct kvm_vcpu *vcpu); void vmx_apicv_pre_state_restore(struct kvm_vcpu *vcpu); -bool vmx_check_apicv_inhibit_reasons(enum kvm_apicv_inhibit reason); void vmx_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr); void vmx_hwapic_isr_update(int max_isr); -bool vmx_guest_apic_has_interrupt(struct kvm_vcpu *vcpu); int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu); void vmx_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode, int trig_mode, int vector); @@ -111,8 +109,6 @@ u64 vmx_get_l2_tsc_offset(struct kvm_vcpu *vcpu); u64 vmx_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu); void vmx_write_tsc_offset(struct kvm_vcpu *vcpu); void vmx_write_tsc_multiplier(struct kvm_vcpu *vcpu); -void vmx_request_immediate_exit(struct kvm_vcpu *vcpu); -void vmx_sched_in(struct kvm_vcpu *vcpu, int cpu); void vmx_update_cpu_dirty_logging(struct kvm_vcpu *vcpu); #ifdef CONFIG_X86_64 int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0763a0f72a06..af6c8cf6a37a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -100,6 +100,9 @@ struct kvm_caps kvm_caps __read_mostly; EXPORT_SYMBOL_GPL(kvm_caps); +struct kvm_host_values kvm_host __read_mostly; +EXPORT_SYMBOL_GPL(kvm_host); + #define ERR_PTR_USR(e) ((void __user *)ERR_PTR(e)) #define emul_to_vcpu(ctxt) \ @@ -220,21 +223,12 @@ static struct kvm_user_return_msrs __percpu *user_return_msrs; | XFEATURE_MASK_BNDCSR | XFEATURE_MASK_AVX512 \ | XFEATURE_MASK_PKRU | XFEATURE_MASK_XTILE) -u64 __read_mostly host_efer; -EXPORT_SYMBOL_GPL(host_efer); - bool __read_mostly allow_smaller_maxphyaddr = 0; EXPORT_SYMBOL_GPL(allow_smaller_maxphyaddr); bool __read_mostly enable_apicv = true; EXPORT_SYMBOL_GPL(enable_apicv); -u64 __read_mostly host_xss; -EXPORT_SYMBOL_GPL(host_xss); - -u64 __read_mostly host_arch_capabilities; -EXPORT_SYMBOL_GPL(host_arch_capabilities); - const struct _kvm_stats_desc kvm_vm_stats_desc[] = { KVM_GENERIC_VM_STATS(), STATS_DESC_COUNTER(VM, mmu_shadow_zapped), @@ -308,8 +302,6 @@ const struct kvm_stats_header kvm_vcpu_stats_header = { sizeof(kvm_vcpu_stats_desc), }; -u64 __read_mostly host_xcr0; - static struct kmem_cache *x86_emulator_cache; /* @@ -833,7 +825,7 @@ EXPORT_SYMBOL_GPL(kvm_requeue_exception_e); */ bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl) { - if (static_call(kvm_x86_get_cpl)(vcpu) <= required_cpl) + if (kvm_x86_call(get_cpl)(vcpu) <= required_cpl) return true; kvm_queue_exception_e(vcpu, GP_VECTOR, 0); return false; @@ -917,7 +909,7 @@ static bool kvm_is_valid_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) return false; - return static_call(kvm_x86_is_valid_cr0)(vcpu, cr0); + return kvm_x86_call(is_valid_cr0)(vcpu, cr0); } void kvm_post_set_cr0(struct kvm_vcpu *vcpu, unsigned long old_cr0, unsigned long cr0) @@ -954,11 +946,6 @@ void kvm_post_set_cr0(struct kvm_vcpu *vcpu, unsigned long old_cr0, unsigned lon if ((cr0 ^ old_cr0) & KVM_MMU_CR0_ROLE_BITS) kvm_mmu_reset_context(vcpu); - - if (((cr0 ^ old_cr0) & X86_CR0_CD) && - kvm_mmu_honors_guest_mtrrs(vcpu->kvm) && - !kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_CD_NW_CLEARED)) - kvm_zap_gfn_range(vcpu->kvm, 0, ~0ULL); } EXPORT_SYMBOL_GPL(kvm_post_set_cr0); @@ -981,7 +968,7 @@ int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) if (!is_pae(vcpu)) return 1; - static_call(kvm_x86_get_cs_db_l_bits)(vcpu, &cs_db, &cs_l); + kvm_x86_call(get_cs_db_l_bits)(vcpu, &cs_db, &cs_l); if (cs_l) return 1; } @@ -995,7 +982,7 @@ int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) (is_64_bit_mode(vcpu) || kvm_is_cr4_bit_set(vcpu, X86_CR4_PCIDE))) return 1; - static_call(kvm_x86_set_cr0)(vcpu, cr0); + kvm_x86_call(set_cr0)(vcpu, cr0); kvm_post_set_cr0(vcpu, old_cr0, cr0); @@ -1016,11 +1003,11 @@ void kvm_load_guest_xsave_state(struct kvm_vcpu *vcpu) if (kvm_is_cr4_bit_set(vcpu, X86_CR4_OSXSAVE)) { - if (vcpu->arch.xcr0 != host_xcr0) + if (vcpu->arch.xcr0 != kvm_host.xcr0) xsetbv(XCR_XFEATURE_ENABLED_MASK, vcpu->arch.xcr0); if (guest_can_use(vcpu, X86_FEATURE_XSAVES) && - vcpu->arch.ia32_xss != host_xss) + vcpu->arch.ia32_xss != kvm_host.xss) wrmsrl(MSR_IA32_XSS, vcpu->arch.ia32_xss); } @@ -1047,12 +1034,12 @@ void kvm_load_host_xsave_state(struct kvm_vcpu *vcpu) if (kvm_is_cr4_bit_set(vcpu, X86_CR4_OSXSAVE)) { - if (vcpu->arch.xcr0 != host_xcr0) - xsetbv(XCR_XFEATURE_ENABLED_MASK, host_xcr0); + if (vcpu->arch.xcr0 != kvm_host.xcr0) + xsetbv(XCR_XFEATURE_ENABLED_MASK, kvm_host.xcr0); if (guest_can_use(vcpu, X86_FEATURE_XSAVES) && - vcpu->arch.ia32_xss != host_xss) - wrmsrl(MSR_IA32_XSS, host_xss); + vcpu->arch.ia32_xss != kvm_host.xss) + wrmsrl(MSR_IA32_XSS, kvm_host.xss); } } @@ -1113,7 +1100,7 @@ static int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr) int kvm_emulate_xsetbv(struct kvm_vcpu *vcpu) { /* Note, #UD due to CR4.OSXSAVE=0 has priority over the intercept. */ - if (static_call(kvm_x86_get_cpl)(vcpu) != 0 || + if (kvm_x86_call(get_cpl)(vcpu) != 0 || __kvm_set_xcr(vcpu, kvm_rcx_read(vcpu), kvm_read_edx_eax(vcpu))) { kvm_inject_gp(vcpu, 0); return 1; @@ -1138,7 +1125,7 @@ EXPORT_SYMBOL_GPL(__kvm_is_valid_cr4); static bool kvm_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) { return __kvm_is_valid_cr4(vcpu, cr4) && - static_call(kvm_x86_is_valid_cr4)(vcpu, cr4); + kvm_x86_call(is_valid_cr4)(vcpu, cr4); } void kvm_post_set_cr4(struct kvm_vcpu *vcpu, unsigned long old_cr4, unsigned long cr4) @@ -1206,7 +1193,7 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) return 1; } - static_call(kvm_x86_set_cr4)(vcpu, cr4); + kvm_x86_call(set_cr4)(vcpu, cr4); kvm_post_set_cr4(vcpu, old_cr4, cr4); @@ -1345,7 +1332,7 @@ void kvm_update_dr7(struct kvm_vcpu *vcpu) dr7 = vcpu->arch.guest_debug_dr7; else dr7 = vcpu->arch.dr7; - static_call(kvm_x86_set_dr7)(vcpu, dr7); + kvm_x86_call(set_dr7)(vcpu, dr7); vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_BP_ENABLED; if (dr7 & DR7_BP_EN_MASK) vcpu->arch.switch_db_regs |= KVM_DEBUGREG_BP_ENABLED; @@ -1461,10 +1448,10 @@ static const u32 msrs_to_save_pmu[] = { MSR_ARCH_PERFMON_FIXED_CTR0, MSR_ARCH_PERFMON_FIXED_CTR1, MSR_ARCH_PERFMON_FIXED_CTR0 + 2, MSR_CORE_PERF_FIXED_CTR_CTRL, MSR_CORE_PERF_GLOBAL_STATUS, - MSR_CORE_PERF_GLOBAL_CTRL, MSR_CORE_PERF_GLOBAL_OVF_CTRL, + MSR_CORE_PERF_GLOBAL_CTRL, MSR_IA32_PEBS_ENABLE, MSR_IA32_DS_AREA, MSR_PEBS_DATA_CFG, - /* This part of MSRs should match KVM_INTEL_PMC_MAX_GENERIC. */ + /* This part of MSRs should match KVM_MAX_NR_INTEL_GP_COUNTERS. */ MSR_ARCH_PERFMON_PERFCTR0, MSR_ARCH_PERFMON_PERFCTR1, MSR_ARCH_PERFMON_PERFCTR0 + 2, MSR_ARCH_PERFMON_PERFCTR0 + 3, MSR_ARCH_PERFMON_PERFCTR0 + 4, MSR_ARCH_PERFMON_PERFCTR0 + 5, @@ -1477,7 +1464,7 @@ static const u32 msrs_to_save_pmu[] = { MSR_K7_EVNTSEL0, MSR_K7_EVNTSEL1, MSR_K7_EVNTSEL2, MSR_K7_EVNTSEL3, MSR_K7_PERFCTR0, MSR_K7_PERFCTR1, MSR_K7_PERFCTR2, MSR_K7_PERFCTR3, - /* This part of MSRs should match KVM_AMD_PMC_MAX_GENERIC. */ + /* This part of MSRs should match KVM_MAX_NR_AMD_GP_COUNTERS. */ MSR_F15H_PERF_CTL0, MSR_F15H_PERF_CTL1, MSR_F15H_PERF_CTL2, MSR_F15H_PERF_CTL3, MSR_F15H_PERF_CTL4, MSR_F15H_PERF_CTL5, MSR_F15H_PERF_CTR0, MSR_F15H_PERF_CTR1, MSR_F15H_PERF_CTR2, @@ -1619,7 +1606,7 @@ static bool kvm_is_immutable_feature_msr(u32 msr) static u64 kvm_get_arch_capabilities(void) { - u64 data = host_arch_capabilities & KVM_SUPPORTED_ARCH_CAP; + u64 data = kvm_host.arch_capabilities & KVM_SUPPORTED_ARCH_CAP; /* * If nx_huge_pages is enabled, KVM's shadow paging will ensure that @@ -1688,7 +1675,7 @@ static int kvm_get_msr_feature(struct kvm_msr_entry *msr) rdmsrl_safe(msr->index, &msr->data); break; default: - return static_call(kvm_x86_get_msr_feature)(msr); + return kvm_x86_call(get_msr_feature)(msr); } return 0; } @@ -1762,7 +1749,7 @@ static int set_efer(struct kvm_vcpu *vcpu, struct msr_data *msr_info) efer &= ~EFER_LMA; efer |= vcpu->arch.efer & EFER_LMA; - r = static_call(kvm_x86_set_efer)(vcpu, efer); + r = kvm_x86_call(set_efer)(vcpu, efer); if (r) { WARN_ON(r > 0); return r; @@ -1877,11 +1864,11 @@ static int __kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data, * incomplete and conflicting architectural behavior. Current * AMD CPUs completely ignore bits 63:32, i.e. they aren't * reserved and always read as zeros. Enforce Intel's reserved - * bits check if and only if the guest CPU is Intel, and clear - * the bits in all other cases. This ensures cross-vendor - * migration will provide consistent behavior for the guest. + * bits check if the guest CPU is Intel compatible, otherwise + * clear the bits. This ensures cross-vendor migration will + * provide consistent behavior for the guest. */ - if (guest_cpuid_is_intel(vcpu) && (data >> 32) != 0) + if (guest_cpuid_is_intel_compatible(vcpu) && (data >> 32) != 0) return 1; data = (u32)data; @@ -1892,7 +1879,7 @@ static int __kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data, msr.index = index; msr.host_initiated = host_initiated; - return static_call(kvm_x86_set_msr)(vcpu, &msr); + return kvm_x86_call(set_msr)(vcpu, &msr); } static int kvm_set_msr_ignored_check(struct kvm_vcpu *vcpu, @@ -1934,7 +1921,7 @@ int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data, msr.index = index; msr.host_initiated = host_initiated; - ret = static_call(kvm_x86_get_msr)(vcpu, &msr); + ret = kvm_x86_call(get_msr)(vcpu, &msr); if (!ret) *data = msr.data; return ret; @@ -2002,7 +1989,7 @@ static int complete_emulated_rdmsr(struct kvm_vcpu *vcpu) static int complete_fast_msr_access(struct kvm_vcpu *vcpu) { - return static_call(kvm_x86_complete_emulated_msr)(vcpu, vcpu->run->msr.error); + return kvm_x86_call(complete_emulated_msr)(vcpu, vcpu->run->msr.error); } static int complete_fast_rdmsr(struct kvm_vcpu *vcpu) @@ -2066,7 +2053,7 @@ int kvm_emulate_rdmsr(struct kvm_vcpu *vcpu) trace_kvm_msr_read_ex(ecx); } - return static_call(kvm_x86_complete_emulated_msr)(vcpu, r); + return kvm_x86_call(complete_emulated_msr)(vcpu, r); } EXPORT_SYMBOL_GPL(kvm_emulate_rdmsr); @@ -2091,7 +2078,7 @@ int kvm_emulate_wrmsr(struct kvm_vcpu *vcpu) trace_kvm_msr_write_ex(ecx, data); } - return static_call(kvm_x86_complete_emulated_msr)(vcpu, r); + return kvm_x86_call(complete_emulated_msr)(vcpu, r); } EXPORT_SYMBOL_GPL(kvm_emulate_wrmsr); @@ -2616,12 +2603,12 @@ static void kvm_vcpu_write_tsc_offset(struct kvm_vcpu *vcpu, u64 l1_offset) if (is_guest_mode(vcpu)) vcpu->arch.tsc_offset = kvm_calc_nested_tsc_offset( l1_offset, - static_call(kvm_x86_get_l2_tsc_offset)(vcpu), - static_call(kvm_x86_get_l2_tsc_multiplier)(vcpu)); + kvm_x86_call(get_l2_tsc_offset)(vcpu), + kvm_x86_call(get_l2_tsc_multiplier)(vcpu)); else vcpu->arch.tsc_offset = l1_offset; - static_call(kvm_x86_write_tsc_offset)(vcpu); + kvm_x86_call(write_tsc_offset)(vcpu); } static void kvm_vcpu_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 l1_multiplier) @@ -2632,12 +2619,12 @@ static void kvm_vcpu_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 l1_multipli if (is_guest_mode(vcpu)) vcpu->arch.tsc_scaling_ratio = kvm_calc_nested_tsc_multiplier( l1_multiplier, - static_call(kvm_x86_get_l2_tsc_multiplier)(vcpu)); + kvm_x86_call(get_l2_tsc_multiplier)(vcpu)); else vcpu->arch.tsc_scaling_ratio = l1_multiplier; if (kvm_caps.has_tsc_control) - static_call(kvm_x86_write_tsc_multiplier)(vcpu); + kvm_x86_call(write_tsc_multiplier)(vcpu); } static inline bool kvm_check_tsc_unstable(void) @@ -3610,7 +3597,7 @@ static void kvmclock_reset(struct kvm_vcpu *vcpu) static void kvm_vcpu_flush_tlb_all(struct kvm_vcpu *vcpu) { ++vcpu->stat.tlb_flush; - static_call(kvm_x86_flush_tlb_all)(vcpu); + kvm_x86_call(flush_tlb_all)(vcpu); /* Flushing all ASIDs flushes the current ASID... */ kvm_clear_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu); @@ -3631,7 +3618,7 @@ static void kvm_vcpu_flush_tlb_guest(struct kvm_vcpu *vcpu) kvm_mmu_sync_prev_roots(vcpu); } - static_call(kvm_x86_flush_tlb_guest)(vcpu); + kvm_x86_call(flush_tlb_guest)(vcpu); /* * Flushing all "guest" TLB is always a superset of Hyper-V's fine @@ -3644,7 +3631,7 @@ static void kvm_vcpu_flush_tlb_guest(struct kvm_vcpu *vcpu) static inline void kvm_vcpu_flush_tlb_current(struct kvm_vcpu *vcpu) { ++vcpu->stat.tlb_flush; - static_call(kvm_x86_flush_tlb_current)(vcpu); + kvm_x86_call(flush_tlb_current)(vcpu); } /* @@ -4703,8 +4690,15 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_VM_DISABLE_NX_HUGE_PAGES: case KVM_CAP_IRQFD_RESAMPLE: case KVM_CAP_MEMORY_FAULT_INFO: + case KVM_CAP_X86_GUEST_MODE: r = 1; break; + case KVM_CAP_PRE_FAULT_MEMORY: + r = tdp_enabled; + break; + case KVM_CAP_X86_APIC_BUS_CYCLES_NS: + r = APIC_BUS_CYCLE_NS_DEFAULT; + break; case KVM_CAP_EXIT_HYPERCALL: r = KVM_EXIT_HYPERCALL_VALID_MASK; break; @@ -4753,7 +4747,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) * fringe case that is not enabled except via specific settings * of the module parameters. */ - r = static_call(kvm_x86_has_emulated_msr)(kvm, MSR_IA32_SMBASE); + r = kvm_x86_call(has_emulated_msr)(kvm, MSR_IA32_SMBASE); break; case KVM_CAP_NR_VCPUS: r = min_t(unsigned int, num_online_cpus(), KVM_MAX_VCPUS); @@ -4833,7 +4827,7 @@ static int __kvm_x86_dev_get_attr(struct kvm_device_attr *attr, u64 *val) { if (attr->group) { if (kvm_x86_ops.dev_get_attr) - return static_call(kvm_x86_dev_get_attr)(attr->group, attr->attr, val); + return kvm_x86_call(dev_get_attr)(attr->group, attr->attr, val); return -ENXIO; } @@ -4995,16 +4989,25 @@ static bool need_emulate_wbinvd(struct kvm_vcpu *vcpu) void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { + struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); + + vcpu->arch.l1tf_flush_l1d = true; + + if (vcpu->scheduled_out && pmu->version && pmu->event_count) { + pmu->need_cleanup = true; + kvm_make_request(KVM_REQ_PMU, vcpu); + } + /* Address WBINVD may be executed by guest */ if (need_emulate_wbinvd(vcpu)) { - if (static_call(kvm_x86_has_wbinvd_exit)()) + if (kvm_x86_call(has_wbinvd_exit)()) cpumask_set_cpu(cpu, vcpu->arch.wbinvd_dirty_mask); else if (vcpu->cpu != -1 && vcpu->cpu != cpu) smp_call_function_single(vcpu->cpu, wbinvd_ipi, NULL, 1); } - static_call(kvm_x86_vcpu_load)(vcpu, cpu); + kvm_x86_call(vcpu_load)(vcpu, cpu); /* Save host pkru register if supported */ vcpu->arch.host_pkru = read_pkru(); @@ -5112,14 +5115,14 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) srcu_read_unlock(&vcpu->kvm->srcu, idx); } - static_call(kvm_x86_vcpu_put)(vcpu); + kvm_x86_call(vcpu_put)(vcpu); vcpu->arch.last_host_tsc = rdtsc(); } static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s) { - static_call_cond(kvm_x86_sync_pir_to_irr)(vcpu); + kvm_x86_call(sync_pir_to_irr)(vcpu); return kvm_apic_get_state(vcpu, s); } @@ -5236,7 +5239,7 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu, kvm_apic_after_set_mcg_cap(vcpu); - static_call(kvm_x86_setup_mce)(vcpu); + kvm_x86_call(setup_mce)(vcpu); out: return r; } @@ -5396,11 +5399,11 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu, events->interrupt.injected = vcpu->arch.interrupt.injected && !vcpu->arch.interrupt.soft; events->interrupt.nr = vcpu->arch.interrupt.nr; - events->interrupt.shadow = static_call(kvm_x86_get_interrupt_shadow)(vcpu); + events->interrupt.shadow = kvm_x86_call(get_interrupt_shadow)(vcpu); events->nmi.injected = vcpu->arch.nmi_injected; events->nmi.pending = kvm_get_nr_pending_nmis(vcpu); - events->nmi.masked = static_call(kvm_x86_get_nmi_mask)(vcpu); + events->nmi.masked = kvm_x86_call(get_nmi_mask)(vcpu); /* events->sipi_vector is never valid when reporting to user space */ @@ -5482,8 +5485,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, vcpu->arch.interrupt.nr = events->interrupt.nr; vcpu->arch.interrupt.soft = events->interrupt.soft; if (events->flags & KVM_VCPUEVENT_VALID_SHADOW) - static_call(kvm_x86_set_interrupt_shadow)(vcpu, - events->interrupt.shadow); + kvm_x86_call(set_interrupt_shadow)(vcpu, + events->interrupt.shadow); vcpu->arch.nmi_injected = events->nmi.injected; if (events->flags & KVM_VCPUEVENT_VALID_NMI_PENDING) { @@ -5492,7 +5495,7 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, if (events->nmi.pending) kvm_make_request(KVM_REQ_NMI, vcpu); } - static_call(kvm_x86_set_nmi_mask)(vcpu, events->nmi.masked); + kvm_x86_call(set_nmi_mask)(vcpu, events->nmi.masked); if (events->flags & KVM_VCPUEVENT_VALID_SIPI_VECTOR && lapic_in_kernel(vcpu)) @@ -5840,7 +5843,7 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, if (!kvm_x86_ops.enable_l2_tlb_flush) return -ENOTTY; - return static_call(kvm_x86_enable_l2_tlb_flush)(vcpu); + return kvm_x86_call(enable_l2_tlb_flush)(vcpu); case KVM_CAP_HYPERV_ENFORCE_CPUID: return kvm_hv_set_enforce_cpuid(vcpu, cap->args[0]); @@ -5879,8 +5882,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r = -EINVAL; if (!lapic_in_kernel(vcpu)) goto out; - u.lapic = kzalloc(sizeof(struct kvm_lapic_state), - GFP_KERNEL_ACCOUNT); + u.lapic = kzalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL); r = -ENOMEM; if (!u.lapic) @@ -6073,7 +6075,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, if (vcpu->arch.guest_fpu.uabi_size > sizeof(struct kvm_xsave)) break; - u.xsave = kzalloc(sizeof(struct kvm_xsave), GFP_KERNEL_ACCOUNT); + u.xsave = kzalloc(sizeof(struct kvm_xsave), GFP_KERNEL); r = -ENOMEM; if (!u.xsave) break; @@ -6104,7 +6106,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, case KVM_GET_XSAVE2: { int size = vcpu->arch.guest_fpu.uabi_size; - u.xsave = kzalloc(size, GFP_KERNEL_ACCOUNT); + u.xsave = kzalloc(size, GFP_KERNEL); r = -ENOMEM; if (!u.xsave) break; @@ -6122,7 +6124,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, } case KVM_GET_XCRS: { - u.xcrs = kzalloc(sizeof(struct kvm_xcrs), GFP_KERNEL_ACCOUNT); + u.xcrs = kzalloc(sizeof(struct kvm_xcrs), GFP_KERNEL); r = -ENOMEM; if (!u.xcrs) break; @@ -6330,14 +6332,14 @@ static int kvm_vm_ioctl_set_tss_addr(struct kvm *kvm, unsigned long addr) if (addr > (unsigned int)(-3 * PAGE_SIZE)) return -EINVAL; - ret = static_call(kvm_x86_set_tss_addr)(kvm, addr); + ret = kvm_x86_call(set_tss_addr)(kvm, addr); return ret; } static int kvm_vm_ioctl_set_identity_map_addr(struct kvm *kvm, u64 ident_addr) { - return static_call(kvm_x86_set_identity_map_addr)(kvm, ident_addr); + return kvm_x86_call(set_identity_map_addr)(kvm, ident_addr); } static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm, @@ -6543,9 +6545,6 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, goto split_irqchip_unlock; if (kvm->created_vcpus) goto split_irqchip_unlock; - r = kvm_setup_empty_irq_routing(kvm); - if (r) - goto split_irqchip_unlock; /* Pairs with irqchip_in_kernel. */ smp_wmb(); kvm->arch.irqchip_mode = KVM_IRQCHIP_SPLIT; @@ -6650,14 +6649,14 @@ split_irqchip_unlock: if (!kvm_x86_ops.vm_copy_enc_context_from) break; - r = static_call(kvm_x86_vm_copy_enc_context_from)(kvm, cap->args[0]); + r = kvm_x86_call(vm_copy_enc_context_from)(kvm, cap->args[0]); break; case KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM: r = -EINVAL; if (!kvm_x86_ops.vm_move_enc_context_from) break; - r = static_call(kvm_x86_vm_move_enc_context_from)(kvm, cap->args[0]); + r = kvm_x86_call(vm_move_enc_context_from)(kvm, cap->args[0]); break; case KVM_CAP_EXIT_HYPERCALL: if (cap->args[0] & ~KVM_EXIT_HYPERCALL_VALID_MASK) { @@ -6692,7 +6691,9 @@ split_irqchip_unlock: break; mutex_lock(&kvm->lock); - if (kvm->arch.max_vcpu_ids == cap->args[0]) { + if (kvm->arch.bsp_vcpu_id > cap->args[0]) { + ; + } else if (kvm->arch.max_vcpu_ids == cap->args[0]) { r = 0; } else if (!kvm->arch.max_vcpu_ids) { kvm->arch.max_vcpu_ids = cap->args[0]; @@ -6745,6 +6746,30 @@ split_irqchip_unlock: } mutex_unlock(&kvm->lock); break; + case KVM_CAP_X86_APIC_BUS_CYCLES_NS: { + u64 bus_cycle_ns = cap->args[0]; + u64 unused; + + /* + * Guard against overflow in tmict_to_ns(). 128 is the highest + * divide value that can be programmed in APIC_TDCR. + */ + r = -EINVAL; + if (!bus_cycle_ns || + check_mul_overflow((u64)U32_MAX * 128, bus_cycle_ns, &unused)) + break; + + r = 0; + mutex_lock(&kvm->lock); + if (!irqchip_in_kernel(kvm)) + r = -ENXIO; + else if (kvm->created_vcpus) + r = -EINVAL; + else + kvm->arch.apic_bus_cycle_ns = bus_cycle_ns; + mutex_unlock(&kvm->lock); + break; + } default: r = -EINVAL; break; @@ -7213,6 +7238,9 @@ set_pit2_out: mutex_lock(&kvm->lock); if (kvm->created_vcpus) r = -EBUSY; + else if (arg > KVM_MAX_VCPU_IDS || + (kvm->arch.max_vcpu_ids && arg > kvm->arch.max_vcpu_ids)) + r = -EINVAL; else kvm->arch.bsp_vcpu_id = arg; mutex_unlock(&kvm->lock); @@ -7289,7 +7317,7 @@ set_pit2_out: if (!kvm_x86_ops.mem_enc_ioctl) goto out; - r = static_call(kvm_x86_mem_enc_ioctl)(kvm, argp); + r = kvm_x86_call(mem_enc_ioctl)(kvm, argp); break; } case KVM_MEMORY_ENCRYPT_REG_REGION: { @@ -7303,7 +7331,7 @@ set_pit2_out: if (!kvm_x86_ops.mem_enc_register_region) goto out; - r = static_call(kvm_x86_mem_enc_register_region)(kvm, ®ion); + r = kvm_x86_call(mem_enc_register_region)(kvm, ®ion); break; } case KVM_MEMORY_ENCRYPT_UNREG_REGION: { @@ -7317,7 +7345,7 @@ set_pit2_out: if (!kvm_x86_ops.mem_enc_unregister_region) goto out; - r = static_call(kvm_x86_mem_enc_unregister_region)(kvm, ®ion); + r = kvm_x86_call(mem_enc_unregister_region)(kvm, ®ion); break; } #ifdef CONFIG_KVM_HYPERV @@ -7411,17 +7439,20 @@ static void kvm_probe_msr_to_save(u32 msr_index) intel_pt_validate_hw_cap(PT_CAP_num_address_ranges) * 2)) return; break; - case MSR_ARCH_PERFMON_PERFCTR0 ... MSR_ARCH_PERFMON_PERFCTR_MAX: + case MSR_ARCH_PERFMON_PERFCTR0 ... + MSR_ARCH_PERFMON_PERFCTR0 + KVM_MAX_NR_GP_COUNTERS - 1: if (msr_index - MSR_ARCH_PERFMON_PERFCTR0 >= kvm_pmu_cap.num_counters_gp) return; break; - case MSR_ARCH_PERFMON_EVENTSEL0 ... MSR_ARCH_PERFMON_EVENTSEL_MAX: + case MSR_ARCH_PERFMON_EVENTSEL0 ... + MSR_ARCH_PERFMON_EVENTSEL0 + KVM_MAX_NR_GP_COUNTERS - 1: if (msr_index - MSR_ARCH_PERFMON_EVENTSEL0 >= kvm_pmu_cap.num_counters_gp) return; break; - case MSR_ARCH_PERFMON_FIXED_CTR0 ... MSR_ARCH_PERFMON_FIXED_CTR_MAX: + case MSR_ARCH_PERFMON_FIXED_CTR0 ... + MSR_ARCH_PERFMON_FIXED_CTR0 + KVM_MAX_NR_FIXED_COUNTERS - 1: if (msr_index - MSR_ARCH_PERFMON_FIXED_CTR0 >= kvm_pmu_cap.num_counters_fixed) return; @@ -7452,7 +7483,7 @@ static void kvm_init_msr_lists(void) { unsigned i; - BUILD_BUG_ON_MSG(KVM_PMC_MAX_FIXED != 3, + BUILD_BUG_ON_MSG(KVM_MAX_NR_FIXED_COUNTERS != 3, "Please update the fixed PMCs in msrs_to_save_pmu[]"); num_msrs_to_save = 0; @@ -7468,7 +7499,8 @@ static void kvm_init_msr_lists(void) } for (i = 0; i < ARRAY_SIZE(emulated_msrs_all); i++) { - if (!static_call(kvm_x86_has_emulated_msr)(NULL, emulated_msrs_all[i])) + if (!kvm_x86_call(has_emulated_msr)(NULL, + emulated_msrs_all[i])) continue; emulated_msrs[num_emulated_msrs++] = emulated_msrs_all[i]; @@ -7527,13 +7559,13 @@ static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v) void kvm_set_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg) { - static_call(kvm_x86_set_segment)(vcpu, var, seg); + kvm_x86_call(set_segment)(vcpu, var, seg); } void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg) { - static_call(kvm_x86_get_segment)(vcpu, var, seg); + kvm_x86_call(get_segment)(vcpu, var, seg); } gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u64 access, @@ -7556,7 +7588,7 @@ gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, { struct kvm_mmu *mmu = vcpu->arch.walk_mmu; - u64 access = (static_call(kvm_x86_get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0; + u64 access = (kvm_x86_call(get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0; return mmu->gva_to_gpa(vcpu, mmu, gva, access, exception); } EXPORT_SYMBOL_GPL(kvm_mmu_gva_to_gpa_read); @@ -7566,7 +7598,7 @@ gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, { struct kvm_mmu *mmu = vcpu->arch.walk_mmu; - u64 access = (static_call(kvm_x86_get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0; + u64 access = (kvm_x86_call(get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0; access |= PFERR_WRITE_MASK; return mmu->gva_to_gpa(vcpu, mmu, gva, access, exception); } @@ -7619,7 +7651,7 @@ static int kvm_fetch_guest_virt(struct x86_emulate_ctxt *ctxt, { struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); struct kvm_mmu *mmu = vcpu->arch.walk_mmu; - u64 access = (static_call(kvm_x86_get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0; + u64 access = (kvm_x86_call(get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0; unsigned offset; int ret; @@ -7644,7 +7676,7 @@ int kvm_read_guest_virt(struct kvm_vcpu *vcpu, gva_t addr, void *val, unsigned int bytes, struct x86_exception *exception) { - u64 access = (static_call(kvm_x86_get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0; + u64 access = (kvm_x86_call(get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0; /* * FIXME: this should call handle_emulation_failure if X86EMUL_IO_NEEDED @@ -7667,7 +7699,7 @@ static int emulator_read_std(struct x86_emulate_ctxt *ctxt, if (system) access |= PFERR_IMPLICIT_ACCESS; - else if (static_call(kvm_x86_get_cpl)(vcpu) == 3) + else if (kvm_x86_call(get_cpl)(vcpu) == 3) access |= PFERR_USER_MASK; return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access, exception); @@ -7712,7 +7744,7 @@ static int emulator_write_std(struct x86_emulate_ctxt *ctxt, gva_t addr, void *v if (system) access |= PFERR_IMPLICIT_ACCESS; - else if (static_call(kvm_x86_get_cpl)(vcpu) == 3) + else if (kvm_x86_call(get_cpl)(vcpu) == 3) access |= PFERR_USER_MASK; return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, @@ -7733,8 +7765,8 @@ EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system); static int kvm_check_emulate_insn(struct kvm_vcpu *vcpu, int emul_type, void *insn, int insn_len) { - return static_call(kvm_x86_check_emulate_instruction)(vcpu, emul_type, - insn, insn_len); + return kvm_x86_call(check_emulate_instruction)(vcpu, emul_type, + insn, insn_len); } int handle_ud(struct kvm_vcpu *vcpu) @@ -7784,8 +7816,8 @@ static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva, bool write) { struct kvm_mmu *mmu = vcpu->arch.walk_mmu; - u64 access = ((static_call(kvm_x86_get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0) - | (write ? PFERR_WRITE_MASK : 0); + u64 access = ((kvm_x86_call(get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0) + | (write ? PFERR_WRITE_MASK : 0); /* * currently PKRU is only applied to ept enabled guest so @@ -8211,7 +8243,7 @@ static int emulator_pio_out_emulated(struct x86_emulate_ctxt *ctxt, static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) { - return static_call(kvm_x86_get_segment_base)(vcpu, seg); + return kvm_x86_call(get_segment_base)(vcpu, seg); } static void emulator_invlpg(struct x86_emulate_ctxt *ctxt, ulong address) @@ -8224,7 +8256,7 @@ static int kvm_emulate_wbinvd_noskip(struct kvm_vcpu *vcpu) if (!need_emulate_wbinvd(vcpu)) return X86EMUL_CONTINUE; - if (static_call(kvm_x86_has_wbinvd_exit)()) { + if (kvm_x86_call(has_wbinvd_exit)()) { int cpu = get_cpu(); cpumask_set_cpu(cpu, vcpu->arch.wbinvd_dirty_mask); @@ -8328,27 +8360,27 @@ static int emulator_set_cr(struct x86_emulate_ctxt *ctxt, int cr, ulong val) static int emulator_get_cpl(struct x86_emulate_ctxt *ctxt) { - return static_call(kvm_x86_get_cpl)(emul_to_vcpu(ctxt)); + return kvm_x86_call(get_cpl)(emul_to_vcpu(ctxt)); } static void emulator_get_gdt(struct x86_emulate_ctxt *ctxt, struct desc_ptr *dt) { - static_call(kvm_x86_get_gdt)(emul_to_vcpu(ctxt), dt); + kvm_x86_call(get_gdt)(emul_to_vcpu(ctxt), dt); } static void emulator_get_idt(struct x86_emulate_ctxt *ctxt, struct desc_ptr *dt) { - static_call(kvm_x86_get_idt)(emul_to_vcpu(ctxt), dt); + kvm_x86_call(get_idt)(emul_to_vcpu(ctxt), dt); } static void emulator_set_gdt(struct x86_emulate_ctxt *ctxt, struct desc_ptr *dt) { - static_call(kvm_x86_set_gdt)(emul_to_vcpu(ctxt), dt); + kvm_x86_call(set_gdt)(emul_to_vcpu(ctxt), dt); } static void emulator_set_idt(struct x86_emulate_ctxt *ctxt, struct desc_ptr *dt) { - static_call(kvm_x86_set_idt)(emul_to_vcpu(ctxt), dt); + kvm_x86_call(set_idt)(emul_to_vcpu(ctxt), dt); } static unsigned long emulator_get_cached_segment_base( @@ -8495,8 +8527,8 @@ static int emulator_intercept(struct x86_emulate_ctxt *ctxt, struct x86_instruction_info *info, enum x86_intercept_stage stage) { - return static_call(kvm_x86_check_intercept)(emul_to_vcpu(ctxt), info, stage, - &ctxt->exception); + return kvm_x86_call(check_intercept)(emul_to_vcpu(ctxt), info, stage, + &ctxt->exception); } static bool emulator_get_cpuid(struct x86_emulate_ctxt *ctxt, @@ -8521,6 +8553,11 @@ static bool emulator_guest_has_rdpid(struct x86_emulate_ctxt *ctxt) return guest_cpuid_has(emul_to_vcpu(ctxt), X86_FEATURE_RDPID); } +static bool emulator_guest_cpuid_is_intel_compatible(struct x86_emulate_ctxt *ctxt) +{ + return guest_cpuid_is_intel_compatible(emul_to_vcpu(ctxt)); +} + static ulong emulator_read_gpr(struct x86_emulate_ctxt *ctxt, unsigned reg) { return kvm_register_read_raw(emul_to_vcpu(ctxt), reg); @@ -8533,7 +8570,7 @@ static void emulator_write_gpr(struct x86_emulate_ctxt *ctxt, unsigned reg, ulon static void emulator_set_nmi_mask(struct x86_emulate_ctxt *ctxt, bool masked) { - static_call(kvm_x86_set_nmi_mask)(emul_to_vcpu(ctxt), masked); + kvm_x86_call(set_nmi_mask)(emul_to_vcpu(ctxt), masked); } static bool emulator_is_smm(struct x86_emulate_ctxt *ctxt) @@ -8578,7 +8615,8 @@ static gva_t emulator_get_untagged_addr(struct x86_emulate_ctxt *ctxt, if (!kvm_x86_ops.get_untagged_addr) return addr; - return static_call(kvm_x86_get_untagged_addr)(emul_to_vcpu(ctxt), addr, flags); + return kvm_x86_call(get_untagged_addr)(emul_to_vcpu(ctxt), + addr, flags); } static const struct x86_emulate_ops emulate_ops = { @@ -8619,6 +8657,7 @@ static const struct x86_emulate_ops emulate_ops = { .guest_has_movbe = emulator_guest_has_movbe, .guest_has_fxsr = emulator_guest_has_fxsr, .guest_has_rdpid = emulator_guest_has_rdpid, + .guest_cpuid_is_intel_compatible = emulator_guest_cpuid_is_intel_compatible, .set_nmi_mask = emulator_set_nmi_mask, .is_smm = emulator_is_smm, .is_guest_mode = emulator_is_guest_mode, @@ -8630,7 +8669,7 @@ static const struct x86_emulate_ops emulate_ops = { static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask) { - u32 int_shadow = static_call(kvm_x86_get_interrupt_shadow)(vcpu); + u32 int_shadow = kvm_x86_call(get_interrupt_shadow)(vcpu); /* * an sti; sti; sequence only disable interrupts for the first * instruction. So, if the last instruction, be it emulated or @@ -8641,7 +8680,7 @@ static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask) if (int_shadow & mask) mask = 0; if (unlikely(int_shadow || mask)) { - static_call(kvm_x86_set_interrupt_shadow)(vcpu, mask); + kvm_x86_call(set_interrupt_shadow)(vcpu, mask); if (!mask) kvm_make_request(KVM_REQ_EVENT, vcpu); } @@ -8682,7 +8721,7 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu) struct x86_emulate_ctxt *ctxt = vcpu->arch.emulate_ctxt; int cs_db, cs_l; - static_call(kvm_x86_get_cs_db_l_bits)(vcpu, &cs_db, &cs_l); + kvm_x86_call(get_cs_db_l_bits)(vcpu, &cs_db, &cs_l); ctxt->gpa_available = false; ctxt->eflags = kvm_get_rflags(vcpu); @@ -8738,9 +8777,8 @@ static void prepare_emulation_failure_exit(struct kvm_vcpu *vcpu, u64 *data, */ memset(&info, 0, sizeof(info)); - static_call(kvm_x86_get_exit_info)(vcpu, (u32 *)&info[0], &info[1], - &info[2], (u32 *)&info[3], - (u32 *)&info[4]); + kvm_x86_call(get_exit_info)(vcpu, (u32 *)&info[0], &info[1], &info[2], + (u32 *)&info[3], (u32 *)&info[4]); run->exit_reason = KVM_EXIT_INTERNAL_ERROR; run->emulation_failure.suberror = KVM_INTERNAL_ERROR_EMULATION; @@ -8817,7 +8855,7 @@ static int handle_emulation_failure(struct kvm_vcpu *vcpu, int emulation_type) kvm_queue_exception(vcpu, UD_VECTOR); - if (!is_guest_mode(vcpu) && static_call(kvm_x86_get_cpl)(vcpu) == 0) { + if (!is_guest_mode(vcpu) && kvm_x86_call(get_cpl)(vcpu) == 0) { prepare_emulation_ctxt_failure_exit(vcpu); return 0; } @@ -8975,10 +9013,10 @@ static int kvm_vcpu_do_singlestep(struct kvm_vcpu *vcpu) int kvm_skip_emulated_instruction(struct kvm_vcpu *vcpu) { - unsigned long rflags = static_call(kvm_x86_get_rflags)(vcpu); + unsigned long rflags = kvm_x86_call(get_rflags)(vcpu); int r; - r = static_call(kvm_x86_skip_emulated_instruction)(vcpu); + r = kvm_x86_call(skip_emulated_instruction)(vcpu); if (unlikely(!r)) return 0; @@ -9000,19 +9038,17 @@ EXPORT_SYMBOL_GPL(kvm_skip_emulated_instruction); static bool kvm_is_code_breakpoint_inhibited(struct kvm_vcpu *vcpu) { - u32 shadow; - if (kvm_get_rflags(vcpu) & X86_EFLAGS_RF) return true; /* - * Intel CPUs inhibit code #DBs when MOV/POP SS blocking is active, - * but AMD CPUs do not. MOV/POP SS blocking is rare, check that first - * to avoid the relatively expensive CPUID lookup. + * Intel compatible CPUs inhibit code #DBs when MOV/POP SS blocking is + * active, but AMD compatible CPUs do not. */ - shadow = static_call(kvm_x86_get_interrupt_shadow)(vcpu); - return (shadow & KVM_X86_SHADOW_INT_MOV_SS) && - guest_cpuid_is_intel(vcpu); + if (!guest_cpuid_is_intel_compatible(vcpu)) + return false; + + return kvm_x86_call(get_interrupt_shadow)(vcpu) & KVM_X86_SHADOW_INT_MOV_SS; } static bool kvm_vcpu_check_code_breakpoint(struct kvm_vcpu *vcpu, @@ -9284,7 +9320,7 @@ restart: writeback: if (writeback) { - unsigned long rflags = static_call(kvm_x86_get_rflags)(vcpu); + unsigned long rflags = kvm_x86_call(get_rflags)(vcpu); toggle_interruptibility(vcpu, ctxt->interruptibility); vcpu->arch.emulate_regs_need_sync_to_vcpu = false; @@ -9301,7 +9337,7 @@ writeback: kvm_rip_write(vcpu, ctxt->eip); if (r && (ctxt->tf || (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP))) r = kvm_vcpu_do_singlestep(vcpu); - static_call_cond(kvm_x86_update_emulated_instruction)(vcpu); + kvm_x86_call(update_emulated_instruction)(vcpu); __kvm_set_rflags(vcpu, ctxt->eflags); } @@ -9700,7 +9736,7 @@ static int kvm_x86_check_processor_compatibility(void) __cr4_reserved_bits(cpu_has, &boot_cpu_data)) return -EIO; - return static_call(kvm_x86_check_processor_compatibility)(); + return kvm_x86_call(check_processor_compatibility)(); } static void kvm_x86_check_cpu_compat(void *ret) @@ -9772,19 +9808,19 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) kvm_caps.supported_mce_cap = MCG_CTL_P | MCG_SER_P; if (boot_cpu_has(X86_FEATURE_XSAVE)) { - host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); - kvm_caps.supported_xcr0 = host_xcr0 & KVM_SUPPORTED_XCR0; + kvm_host.xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); + kvm_caps.supported_xcr0 = kvm_host.xcr0 & KVM_SUPPORTED_XCR0; } - rdmsrl_safe(MSR_EFER, &host_efer); + rdmsrl_safe(MSR_EFER, &kvm_host.efer); if (boot_cpu_has(X86_FEATURE_XSAVES)) - rdmsrl(MSR_IA32_XSS, host_xss); + rdmsrl(MSR_IA32_XSS, kvm_host.xss); kvm_init_pmu_capability(ops->pmu_ops); if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) - rdmsrl(MSR_IA32_ARCH_CAPABILITIES, host_arch_capabilities); + rdmsrl(MSR_IA32_ARCH_CAPABILITIES, kvm_host.arch_capabilities); r = ops->hardware_setup(); if (r != 0) @@ -9843,7 +9879,7 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) out_unwind_ops: kvm_x86_ops.hardware_enable = NULL; - static_call(kvm_x86_hardware_unsetup)(); + kvm_x86_call(hardware_unsetup)(); out_mmu_exit: kvm_mmu_vendor_module_exit(); out_free_percpu: @@ -9874,7 +9910,7 @@ void kvm_x86_vendor_exit(void) irq_work_sync(&pvclock_irq_work); cancel_work_sync(&pvclock_gtod_work); #endif - static_call(kvm_x86_hardware_unsetup)(); + kvm_x86_call(hardware_unsetup)(); kvm_mmu_vendor_module_exit(); free_percpu(user_return_msrs); kmem_cache_destroy(x86_emulator_cache); @@ -10000,7 +10036,8 @@ EXPORT_SYMBOL_GPL(kvm_apicv_activated); bool kvm_vcpu_apicv_activated(struct kvm_vcpu *vcpu) { ulong vm_reasons = READ_ONCE(vcpu->kvm->arch.apicv_inhibit_reasons); - ulong vcpu_reasons = static_call(kvm_x86_vcpu_get_apicv_inhibit_reasons)(vcpu); + ulong vcpu_reasons = + kvm_x86_call(vcpu_get_apicv_inhibit_reasons)(vcpu); return (vm_reasons | vcpu_reasons) == 0; } @@ -10009,6 +10046,10 @@ EXPORT_SYMBOL_GPL(kvm_vcpu_apicv_activated); static void set_or_clear_apicv_inhibit(unsigned long *inhibits, enum kvm_apicv_inhibit reason, bool set) { + const struct trace_print_flags apicv_inhibits[] = { APICV_INHIBIT_REASONS }; + + BUILD_BUG_ON(ARRAY_SIZE(apicv_inhibits) != NR_APICV_INHIBIT_REASONS); + if (set) __set_bit(reason, inhibits); else @@ -10020,7 +10061,7 @@ static void set_or_clear_apicv_inhibit(unsigned long *inhibits, static void kvm_apicv_init(struct kvm *kvm) { enum kvm_apicv_inhibit reason = enable_apicv ? APICV_INHIBIT_REASON_ABSENT : - APICV_INHIBIT_REASON_DISABLE; + APICV_INHIBIT_REASON_DISABLED; set_or_clear_apicv_inhibit(&kvm->arch.apicv_inhibit_reasons, reason, true); @@ -10182,7 +10223,7 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) a2 = kvm_rdx_read(vcpu); a3 = kvm_rsi_read(vcpu); op_64_bit = is_64_bit_hypercall(vcpu); - cpl = static_call(kvm_x86_get_cpl)(vcpu); + cpl = kvm_x86_call(get_cpl)(vcpu); ret = __kvm_emulate_hypercall(vcpu, nr, a0, a1, a2, a3, op_64_bit, cpl); if (nr == KVM_HC_MAP_GPA_RANGE && !ret) @@ -10214,7 +10255,7 @@ static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt) return X86EMUL_PROPAGATE_FAULT; } - static_call(kvm_x86_patch_hypercall)(vcpu, instruction); + kvm_x86_call(patch_hypercall)(vcpu, instruction); return emulator_write_emulated(ctxt, rip, instruction, 3, &ctxt->exception); @@ -10231,7 +10272,7 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu) { struct kvm_run *kvm_run = vcpu->run; - kvm_run->if_flag = static_call(kvm_x86_get_if_flag)(vcpu); + kvm_run->if_flag = kvm_x86_call(get_if_flag)(vcpu); kvm_run->cr8 = kvm_get_cr8(vcpu); kvm_run->apic_base = kvm_get_apic_base(vcpu); @@ -10241,6 +10282,8 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu) if (is_smm(vcpu)) kvm_run->flags |= KVM_RUN_X86_SMM; + if (is_guest_mode(vcpu)) + kvm_run->flags |= KVM_RUN_X86_GUEST_MODE; } static void update_cr8_intercept(struct kvm_vcpu *vcpu) @@ -10266,7 +10309,7 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu) tpr = kvm_lapic_get_cr8(vcpu); - static_call(kvm_x86_update_cr8_intercept)(vcpu, tpr, max_irr); + kvm_x86_call(update_cr8_intercept)(vcpu, tpr, max_irr); } @@ -10296,7 +10339,7 @@ static void kvm_inject_exception(struct kvm_vcpu *vcpu) vcpu->arch.exception.error_code, vcpu->arch.exception.injected); - static_call(kvm_x86_inject_exception)(vcpu); + kvm_x86_call(inject_exception)(vcpu); } /* @@ -10382,9 +10425,9 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu, else if (kvm_is_exception_pending(vcpu)) ; /* see above */ else if (vcpu->arch.nmi_injected) - static_call(kvm_x86_inject_nmi)(vcpu); + kvm_x86_call(inject_nmi)(vcpu); else if (vcpu->arch.interrupt.injected) - static_call(kvm_x86_inject_irq)(vcpu, true); + kvm_x86_call(inject_irq)(vcpu, true); /* * Exceptions that morph to VM-Exits are handled above, and pending @@ -10469,7 +10512,8 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu, */ #ifdef CONFIG_KVM_SMM if (vcpu->arch.smi_pending) { - r = can_inject ? static_call(kvm_x86_smi_allowed)(vcpu, true) : -EBUSY; + r = can_inject ? kvm_x86_call(smi_allowed)(vcpu, true) : + -EBUSY; if (r < 0) goto out; if (r) { @@ -10478,27 +10522,29 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu, enter_smm(vcpu); can_inject = false; } else - static_call(kvm_x86_enable_smi_window)(vcpu); + kvm_x86_call(enable_smi_window)(vcpu); } #endif if (vcpu->arch.nmi_pending) { - r = can_inject ? static_call(kvm_x86_nmi_allowed)(vcpu, true) : -EBUSY; + r = can_inject ? kvm_x86_call(nmi_allowed)(vcpu, true) : + -EBUSY; if (r < 0) goto out; if (r) { --vcpu->arch.nmi_pending; vcpu->arch.nmi_injected = true; - static_call(kvm_x86_inject_nmi)(vcpu); + kvm_x86_call(inject_nmi)(vcpu); can_inject = false; - WARN_ON(static_call(kvm_x86_nmi_allowed)(vcpu, true) < 0); + WARN_ON(kvm_x86_call(nmi_allowed)(vcpu, true) < 0); } if (vcpu->arch.nmi_pending) - static_call(kvm_x86_enable_nmi_window)(vcpu); + kvm_x86_call(enable_nmi_window)(vcpu); } if (kvm_cpu_has_injectable_intr(vcpu)) { - r = can_inject ? static_call(kvm_x86_interrupt_allowed)(vcpu, true) : -EBUSY; + r = can_inject ? kvm_x86_call(interrupt_allowed)(vcpu, true) : + -EBUSY; if (r < 0) goto out; if (r) { @@ -10506,17 +10552,17 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu, if (!WARN_ON_ONCE(irq == -1)) { kvm_queue_interrupt(vcpu, irq, false); - static_call(kvm_x86_inject_irq)(vcpu, false); - WARN_ON(static_call(kvm_x86_interrupt_allowed)(vcpu, true) < 0); + kvm_x86_call(inject_irq)(vcpu, false); + WARN_ON(kvm_x86_call(interrupt_allowed)(vcpu, true) < 0); } } if (kvm_cpu_has_injectable_intr(vcpu)) - static_call(kvm_x86_enable_irq_window)(vcpu); + kvm_x86_call(enable_irq_window)(vcpu); } if (is_guest_mode(vcpu) && kvm_x86_ops.nested_ops->has_events && - kvm_x86_ops.nested_ops->has_events(vcpu)) + kvm_x86_ops.nested_ops->has_events(vcpu, true)) *req_immediate_exit = true; /* @@ -10557,7 +10603,7 @@ static void process_nmi(struct kvm_vcpu *vcpu) * blocks NMIs). KVM will immediately inject one of the two NMIs, and * will request an NMI window to handle the second NMI. */ - if (static_call(kvm_x86_get_nmi_mask)(vcpu) || vcpu->arch.nmi_injected) + if (kvm_x86_call(get_nmi_mask)(vcpu) || vcpu->arch.nmi_injected) limit = 1; else limit = 2; @@ -10566,14 +10612,14 @@ static void process_nmi(struct kvm_vcpu *vcpu) * Adjust the limit to account for pending virtual NMIs, which aren't * tracked in vcpu->arch.nmi_pending. */ - if (static_call(kvm_x86_is_vnmi_pending)(vcpu)) + if (kvm_x86_call(is_vnmi_pending)(vcpu)) limit--; vcpu->arch.nmi_pending += atomic_xchg(&vcpu->arch.nmi_queued, 0); vcpu->arch.nmi_pending = min(vcpu->arch.nmi_pending, limit); if (vcpu->arch.nmi_pending && - (static_call(kvm_x86_set_vnmi_pending)(vcpu))) + (kvm_x86_call(set_vnmi_pending)(vcpu))) vcpu->arch.nmi_pending--; if (vcpu->arch.nmi_pending) @@ -10584,7 +10630,7 @@ static void process_nmi(struct kvm_vcpu *vcpu) int kvm_get_nr_pending_nmis(struct kvm_vcpu *vcpu) { return vcpu->arch.nmi_pending + - static_call(kvm_x86_is_vnmi_pending)(vcpu); + kvm_x86_call(is_vnmi_pending)(vcpu); } void kvm_make_scan_ioapic_request_mask(struct kvm *kvm, @@ -10618,7 +10664,7 @@ void __kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu) apic->apicv_active = activate; kvm_apic_update_apicv(vcpu); - static_call(kvm_x86_refresh_apicv_exec_ctrl)(vcpu); + kvm_x86_call(refresh_apicv_exec_ctrl)(vcpu); /* * When APICv gets disabled, we may still have injected interrupts @@ -10718,7 +10764,7 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu) bitmap_zero(vcpu->arch.ioapic_handled_vectors, 256); - static_call_cond(kvm_x86_sync_pir_to_irr)(vcpu); + kvm_x86_call(sync_pir_to_irr)(vcpu); if (irqchip_split(vcpu->kvm)) kvm_scan_ioapic_routes(vcpu, vcpu->arch.ioapic_handled_vectors); @@ -10743,17 +10789,17 @@ static void vcpu_load_eoi_exitmap(struct kvm_vcpu *vcpu) bitmap_or((ulong *)eoi_exit_bitmap, vcpu->arch.ioapic_handled_vectors, to_hv_synic(vcpu)->vec_bitmap, 256); - static_call_cond(kvm_x86_load_eoi_exitmap)(vcpu, eoi_exit_bitmap); + kvm_x86_call(load_eoi_exitmap)(vcpu, eoi_exit_bitmap); return; } #endif - static_call_cond(kvm_x86_load_eoi_exitmap)( + kvm_x86_call(load_eoi_exitmap)( vcpu, (u64 *)vcpu->arch.ioapic_handled_vectors); } void kvm_arch_guest_memory_reclaimed(struct kvm *kvm) { - static_call_cond(kvm_x86_guest_memory_reclaimed)(kvm); + kvm_x86_call(guest_memory_reclaimed)(kvm); } static void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu) @@ -10761,7 +10807,7 @@ static void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu) if (!lapic_in_kernel(vcpu)) return; - static_call_cond(kvm_x86_set_apic_access_page_addr)(vcpu); + kvm_x86_call(set_apic_access_page_addr)(vcpu); } /* @@ -10925,10 +10971,18 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) if (kvm_check_request(KVM_REQ_APF_READY, vcpu)) kvm_check_async_pf_completion(vcpu); if (kvm_check_request(KVM_REQ_MSR_FILTER_CHANGED, vcpu)) - static_call(kvm_x86_msr_filter_changed)(vcpu); + kvm_x86_call(msr_filter_changed)(vcpu); if (kvm_check_request(KVM_REQ_UPDATE_CPU_DIRTY_LOGGING, vcpu)) - static_call(kvm_x86_update_cpu_dirty_logging)(vcpu); + kvm_x86_call(update_cpu_dirty_logging)(vcpu); + + if (kvm_check_request(KVM_REQ_UPDATE_PROTECTED_GUEST_STATE, vcpu)) { + kvm_vcpu_reset(vcpu, true); + if (vcpu->arch.mp_state != KVM_MP_STATE_RUNNABLE) { + r = 1; + goto out; + } + } } if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win || @@ -10950,7 +11004,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) goto out; } if (req_int_win) - static_call(kvm_x86_enable_irq_window)(vcpu); + kvm_x86_call(enable_irq_window)(vcpu); if (kvm_lapic_enabled(vcpu)) { update_cr8_intercept(vcpu); @@ -10965,7 +11019,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) preempt_disable(); - static_call(kvm_x86_prepare_switch_to_guest)(vcpu); + kvm_x86_call(prepare_switch_to_guest)(vcpu); /* * Disable IRQs before setting IN_GUEST_MODE. Posted interrupt @@ -11001,7 +11055,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) * i.e. they can post interrupts even if APICv is temporarily disabled. */ if (kvm_lapic_enabled(vcpu)) - static_call_cond(kvm_x86_sync_pir_to_irr)(vcpu); + kvm_x86_call(sync_pir_to_irr)(vcpu); if (kvm_vcpu_exit_request(vcpu)) { vcpu->mode = OUTSIDE_GUEST_MODE; @@ -11045,12 +11099,13 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) WARN_ON_ONCE((kvm_vcpu_apicv_activated(vcpu) != kvm_vcpu_apicv_active(vcpu)) && (kvm_get_apic_mode(vcpu) != LAPIC_MODE_DISABLED)); - exit_fastpath = static_call(kvm_x86_vcpu_run)(vcpu, req_immediate_exit); + exit_fastpath = kvm_x86_call(vcpu_run)(vcpu, + req_immediate_exit); if (likely(exit_fastpath != EXIT_FASTPATH_REENTER_GUEST)) break; if (kvm_lapic_enabled(vcpu)) - static_call_cond(kvm_x86_sync_pir_to_irr)(vcpu); + kvm_x86_call(sync_pir_to_irr)(vcpu); if (unlikely(kvm_vcpu_exit_request(vcpu))) { exit_fastpath = EXIT_FASTPATH_EXIT_HANDLED; @@ -11069,7 +11124,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) */ if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) { WARN_ON(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP); - static_call(kvm_x86_sync_dirty_debug_regs)(vcpu); + kvm_x86_call(sync_dirty_debug_regs)(vcpu); kvm_update_dr0123(vcpu); kvm_update_dr7(vcpu); } @@ -11098,7 +11153,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) if (vcpu->arch.xfd_no_write_intercept) fpu_sync_guest_vmexit_xfd_state(); - static_call(kvm_x86_handle_exit_irqoff)(vcpu); + kvm_x86_call(handle_exit_irqoff)(vcpu); if (vcpu->arch.guest_fpu.xfd_err) wrmsrl(MSR_IA32_XFD_ERR, 0); @@ -11130,6 +11185,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) kvm_vcpu_srcu_read_lock(vcpu); + /* + * Call this to ensure WC buffers in guest are evicted after each VM + * Exit, so that the evicted WC writes can be snooped across all cpus + */ + smp_mb__after_srcu_read_lock(); + /* * Profile KVM exit RIPs: */ @@ -11144,13 +11205,13 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) if (vcpu->arch.apic_attention) kvm_lapic_sync_from_vapic(vcpu); - r = static_call(kvm_x86_handle_exit)(vcpu, exit_fastpath); + r = kvm_x86_call(handle_exit)(vcpu, exit_fastpath); return r; cancel_injection: if (req_immediate_exit) kvm_make_request(KVM_REQ_EVENT, vcpu); - static_call(kvm_x86_cancel_injection)(vcpu); + kvm_x86_call(cancel_injection)(vcpu); if (unlikely(vcpu->arch.apic_attention)) kvm_lapic_sync_from_vapic(vcpu); out: @@ -11200,7 +11261,10 @@ static inline int vcpu_block(struct kvm_vcpu *vcpu) * causes a spurious wakeup from HLT). */ if (is_guest_mode(vcpu)) { - if (kvm_check_nested_events(vcpu) < 0) + int r = kvm_check_nested_events(vcpu); + + WARN_ON_ONCE(r == -EBUSY); + if (r < 0) return 0; } @@ -11237,7 +11301,6 @@ static int vcpu_run(struct kvm_vcpu *vcpu) int r; vcpu->run->exit_reason = KVM_EXIT_UNKNOWN; - vcpu->arch.l1tf_flush_l1d = true; for (;;) { /* @@ -11387,7 +11450,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) kvm_vcpu_srcu_read_lock(vcpu); if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)) { - if (kvm_run->immediate_exit) { + if (!vcpu->wants_to_run) { r = -EINTR; goto out; } @@ -11465,12 +11528,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) WARN_ON_ONCE(vcpu->mmio_needed); } - if (kvm_run->immediate_exit) { + if (!vcpu->wants_to_run) { r = -EINTR; goto out; } - r = static_call(kvm_x86_vcpu_pre_run)(vcpu); + r = kvm_x86_call(vcpu_pre_run)(vcpu); if (r <= 0) goto out; @@ -11598,10 +11661,10 @@ static void __get_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) kvm_get_segment(vcpu, &sregs->tr, VCPU_SREG_TR); kvm_get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); - static_call(kvm_x86_get_idt)(vcpu, &dt); + kvm_x86_call(get_idt)(vcpu, &dt); sregs->idt.limit = dt.size; sregs->idt.base = dt.address; - static_call(kvm_x86_get_gdt)(vcpu, &dt); + kvm_x86_call(get_gdt)(vcpu, &dt); sregs->gdt.limit = dt.size; sregs->gdt.base = dt.address; @@ -11743,7 +11806,13 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index, ret = emulator_task_switch(ctxt, tss_selector, idt_index, reason, has_error_code, error_code); - if (ret) { + + /* + * Report an error userspace if MMIO is needed, as KVM doesn't support + * MMIO during a task switch (or any other complex operation). + */ + if (ret || vcpu->mmio_needed) { + vcpu->mmio_needed = false; vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; vcpu->run->internal.ndata = 0; @@ -11801,27 +11870,27 @@ static int __set_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs, dt.size = sregs->idt.limit; dt.address = sregs->idt.base; - static_call(kvm_x86_set_idt)(vcpu, &dt); + kvm_x86_call(set_idt)(vcpu, &dt); dt.size = sregs->gdt.limit; dt.address = sregs->gdt.base; - static_call(kvm_x86_set_gdt)(vcpu, &dt); + kvm_x86_call(set_gdt)(vcpu, &dt); vcpu->arch.cr2 = sregs->cr2; *mmu_reset_needed |= kvm_read_cr3(vcpu) != sregs->cr3; vcpu->arch.cr3 = sregs->cr3; kvm_register_mark_dirty(vcpu, VCPU_EXREG_CR3); - static_call_cond(kvm_x86_post_set_cr3)(vcpu, sregs->cr3); + kvm_x86_call(post_set_cr3)(vcpu, sregs->cr3); kvm_set_cr8(vcpu, sregs->cr8); *mmu_reset_needed |= vcpu->arch.efer != sregs->efer; - static_call(kvm_x86_set_efer)(vcpu, sregs->efer); + kvm_x86_call(set_efer)(vcpu, sregs->efer); *mmu_reset_needed |= kvm_read_cr0(vcpu) != sregs->cr0; - static_call(kvm_x86_set_cr0)(vcpu, sregs->cr0); + kvm_x86_call(set_cr0)(vcpu, sregs->cr0); *mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4; - static_call(kvm_x86_set_cr4)(vcpu, sregs->cr4); + kvm_x86_call(set_cr4)(vcpu, sregs->cr4); if (update_pdptrs) { idx = srcu_read_lock(&vcpu->kvm->srcu); @@ -11999,7 +12068,7 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, */ kvm_set_rflags(vcpu, rflags); - static_call(kvm_x86_update_exception_bitmap)(vcpu); + kvm_x86_call(update_exception_bitmap)(vcpu); kvm_arch_vcpu_guestdbg_update_apicv_inhibit(vcpu->kvm); @@ -12136,7 +12205,7 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id) if (id >= kvm->arch.max_vcpu_ids) return -EINVAL; - return static_call(kvm_x86_vcpu_precreate)(kvm); + return kvm_x86_call(vcpu_precreate)(kvm); } int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) @@ -12207,14 +12276,13 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) vcpu->arch.hv_root_tdp = INVALID_PAGE; #endif - r = static_call(kvm_x86_vcpu_create)(vcpu); + r = kvm_x86_call(vcpu_create)(vcpu); if (r) goto free_guest_fpu; vcpu->arch.arch_capabilities = kvm_get_arch_capabilities(); vcpu->arch.msr_platform_info = MSR_PLATFORM_INFO_CPUID_FAULT; kvm_xen_init_vcpu(vcpu); - kvm_vcpu_mtrr_init(vcpu); vcpu_load(vcpu); kvm_set_tsc_khz(vcpu, vcpu->kvm->arch.default_tsc_khz); kvm_vcpu_reset(vcpu, false); @@ -12265,7 +12333,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) kvmclock_reset(vcpu); - static_call(kvm_x86_vcpu_free)(vcpu); + kvm_x86_call(vcpu_free)(vcpu); kmem_cache_free(x86_emulator_cache, vcpu->arch.emulate_ctxt); free_cpumask_var(vcpu->arch.wbinvd_dirty_mask); @@ -12383,7 +12451,7 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) cpuid_0x1 = kvm_find_cpuid_entry(vcpu, 1); kvm_rdx_write(vcpu, cpuid_0x1 ? cpuid_0x1->eax : 0x600); - static_call(kvm_x86_vcpu_reset)(vcpu, init_event); + kvm_x86_call(vcpu_reset)(vcpu, init_event); kvm_set_rflags(vcpu, X86_EFLAGS_FIXED); kvm_rip_write(vcpu, 0xfff0); @@ -12402,10 +12470,10 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) else new_cr0 |= X86_CR0_NW | X86_CR0_CD; - static_call(kvm_x86_set_cr0)(vcpu, new_cr0); - static_call(kvm_x86_set_cr4)(vcpu, 0); - static_call(kvm_x86_set_efer)(vcpu, 0); - static_call(kvm_x86_update_exception_bitmap)(vcpu); + kvm_x86_call(set_cr0)(vcpu, new_cr0); + kvm_x86_call(set_cr4)(vcpu, 0); + kvm_x86_call(set_efer)(vcpu, 0); + kvm_x86_call(update_exception_bitmap)(vcpu); /* * On the standard CR0/CR4/EFER modification paths, there are several @@ -12462,7 +12530,7 @@ int kvm_arch_hardware_enable(void) if (ret) return ret; - ret = static_call(kvm_x86_hardware_enable)(); + ret = kvm_x86_call(hardware_enable)(); if (ret != 0) return ret; @@ -12544,7 +12612,7 @@ int kvm_arch_hardware_enable(void) void kvm_arch_hardware_disable(void) { - static_call(kvm_x86_hardware_disable)(); + kvm_x86_call(hardware_disable)(); drop_user_return_notifiers(); } @@ -12558,18 +12626,6 @@ bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu) return (vcpu->arch.apic_base & MSR_IA32_APICBASE_BSP) != 0; } -void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) -{ - struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); - - vcpu->arch.l1tf_flush_l1d = true; - if (pmu->version && unlikely(pmu->event_count)) { - pmu->need_cleanup = true; - kvm_make_request(KVM_REQ_PMU, vcpu); - } - static_call(kvm_x86_sched_in)(vcpu, cpu); -} - void kvm_arch_free_vm(struct kvm *kvm) { #if IS_ENABLED(CONFIG_HYPERV) @@ -12597,7 +12653,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) kvm_mmu_init_vm(kvm); - ret = static_call(kvm_x86_vm_init)(kvm); + ret = kvm_x86_call(vm_init)(kvm); if (ret) goto out_uninit_mmu; @@ -12620,6 +12676,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags); kvm->arch.default_tsc_khz = max_tsc_khz ? : tsc_khz; + kvm->arch.apic_bus_cycle_ns = APIC_BUS_CYCLE_NS_DEFAULT; kvm->arch.guest_can_read_msr_platform_info = true; kvm->arch.enable_pmu = enable_pmu; @@ -12771,7 +12828,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) mutex_unlock(&kvm->slots_lock); } kvm_unload_vcpu_mmus(kvm); - static_call_cond(kvm_x86_vm_destroy)(kvm); + kvm_x86_call(vm_destroy)(kvm); kvm_free_msr_filter(srcu_dereference_check(kvm->arch.msr_filter, &kvm->srcu, 1)); kvm_pic_destroy(kvm); kvm_ioapic_destroy(kvm); @@ -13100,12 +13157,6 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, kvm_arch_free_memslot(kvm, old); } -static inline bool kvm_guest_apic_has_interrupt(struct kvm_vcpu *vcpu) -{ - return (is_guest_mode(vcpu) && - static_call(kvm_x86_guest_apic_has_interrupt)(vcpu)); -} - static inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu) { if (!list_empty_careful(&vcpu->async_pf.done)) @@ -13123,22 +13174,23 @@ static inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu) if (kvm_test_request(KVM_REQ_NMI, vcpu) || (vcpu->arch.nmi_pending && - static_call(kvm_x86_nmi_allowed)(vcpu, false))) + kvm_x86_call(nmi_allowed)(vcpu, false))) return true; #ifdef CONFIG_KVM_SMM if (kvm_test_request(KVM_REQ_SMI, vcpu) || (vcpu->arch.smi_pending && - static_call(kvm_x86_smi_allowed)(vcpu, false))) + kvm_x86_call(smi_allowed)(vcpu, false))) return true; #endif if (kvm_test_request(KVM_REQ_PMI, vcpu)) return true; - if (kvm_arch_interrupt_allowed(vcpu) && - (kvm_cpu_has_interrupt(vcpu) || - kvm_guest_apic_has_interrupt(vcpu))) + if (kvm_test_request(KVM_REQ_UPDATE_PROTECTED_GUEST_STATE, vcpu)) + return true; + + if (kvm_arch_interrupt_allowed(vcpu) && kvm_cpu_has_interrupt(vcpu)) return true; if (kvm_hv_has_stimer_pending(vcpu)) @@ -13146,7 +13198,7 @@ static inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu) if (is_guest_mode(vcpu) && kvm_x86_ops.nested_ops->has_events && - kvm_x86_ops.nested_ops->has_events(vcpu)) + kvm_x86_ops.nested_ops->has_events(vcpu, false)) return true; if (kvm_xen_has_pending_events(vcpu)) @@ -13163,7 +13215,7 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) bool kvm_arch_dy_has_pending_interrupt(struct kvm_vcpu *vcpu) { return kvm_vcpu_apicv_active(vcpu) && - static_call(kvm_x86_dy_apicv_has_pending_interrupt)(vcpu); + kvm_x86_call(dy_apicv_has_pending_interrupt)(vcpu); } bool kvm_arch_vcpu_preempted_in_kernel(struct kvm_vcpu *vcpu) @@ -13191,7 +13243,7 @@ bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu) if (vcpu->arch.guest_state_protected) return true; - return static_call(kvm_x86_get_cpl)(vcpu) == 0; + return kvm_x86_call(get_cpl)(vcpu) == 0; } unsigned long kvm_arch_vcpu_get_ip(struct kvm_vcpu *vcpu) @@ -13206,7 +13258,7 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu) { - return static_call(kvm_x86_interrupt_allowed)(vcpu, false); + return kvm_x86_call(interrupt_allowed)(vcpu, false); } unsigned long kvm_get_linear_rip(struct kvm_vcpu *vcpu) @@ -13232,7 +13284,7 @@ unsigned long kvm_get_rflags(struct kvm_vcpu *vcpu) { unsigned long rflags; - rflags = static_call(kvm_x86_get_rflags)(vcpu); + rflags = kvm_x86_call(get_rflags)(vcpu); if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) rflags &= ~X86_EFLAGS_TF; return rflags; @@ -13244,7 +13296,7 @@ static void __kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP && kvm_is_linear_rip(vcpu, vcpu->arch.singlestep_rip)) rflags |= X86_EFLAGS_TF; - static_call(kvm_x86_set_rflags)(vcpu, rflags); + kvm_x86_call(set_rflags)(vcpu, rflags); } void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) @@ -13356,7 +13408,7 @@ static bool kvm_can_deliver_async_pf(struct kvm_vcpu *vcpu) return false; if (vcpu->arch.apf.send_user_only && - static_call(kvm_x86_get_cpl)(vcpu) == 0) + kvm_x86_call(get_cpl)(vcpu) == 0) return false; if (is_guest_mode(vcpu)) { @@ -13467,7 +13519,7 @@ bool kvm_arch_can_dequeue_async_page_present(struct kvm_vcpu *vcpu) void kvm_arch_start_assignment(struct kvm *kvm) { if (atomic_inc_return(&kvm->arch.assigned_device_count) == 1) - static_call_cond(kvm_x86_pi_start_assignment)(kvm); + kvm_x86_call(pi_start_assignment)(kvm); } EXPORT_SYMBOL_GPL(kvm_arch_start_assignment); @@ -13486,13 +13538,13 @@ EXPORT_SYMBOL_GPL(kvm_arch_has_assigned_device); static void kvm_noncoherent_dma_assignment_start_or_stop(struct kvm *kvm) { /* - * Non-coherent DMA assignment and de-assignment will affect - * whether KVM honors guest MTRRs and cause changes in memtypes - * in TDP. - * So, pass %true unconditionally to indicate non-coherent DMA was, - * or will be involved, and that zapping SPTEs might be necessary. + * Non-coherent DMA assignment and de-assignment may affect whether or + * not KVM honors guest PAT, and thus may cause changes in EPT SPTEs + * due to toggling the "ignore PAT" bit. Zap all SPTEs when the first + * (or last) non-coherent device is (un)registered to so that new SPTEs + * with the correct "ignore guest PAT" setting are created. */ - if (__kvm_mmu_honors_guest_mtrrs(true)) + if (kvm_mmu_may_ignore_guest_pat()) kvm_zap_gfn_range(kvm, gpa_to_gfn(0), gpa_to_gfn(~0ULL)); } @@ -13530,9 +13582,8 @@ int kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *cons, irqfd->producer = prod; kvm_arch_start_assignment(irqfd->kvm); - ret = static_call(kvm_x86_pi_update_irte)(irqfd->kvm, - prod->irq, irqfd->gsi, 1); - + ret = kvm_x86_call(pi_update_irte)(irqfd->kvm, + prod->irq, irqfd->gsi, 1); if (ret) kvm_arch_end_assignment(irqfd->kvm); @@ -13555,7 +13606,8 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons, * when the irq is masked/disabled or the consumer side (KVM * int this case doesn't want to receive the interrupts. */ - ret = static_call(kvm_x86_pi_update_irte)(irqfd->kvm, prod->irq, irqfd->gsi, 0); + ret = kvm_x86_call(pi_update_irte)(irqfd->kvm, + prod->irq, irqfd->gsi, 0); if (ret) printk(KERN_INFO "irq bypass consumer (token %p) unregistration" " fails: %d\n", irqfd->consumer.token, ret); @@ -13566,7 +13618,7 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons, int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq, uint32_t guest_irq, bool set) { - return static_call(kvm_x86_pi_update_irte)(kvm, host_irq, guest_irq, set); + return kvm_x86_call(pi_update_irte)(kvm, host_irq, guest_irq, set); } bool kvm_arch_irqfd_route_changed(struct kvm_kernel_irq_routing_entry *old, @@ -13589,6 +13641,24 @@ bool kvm_arch_no_poll(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_arch_no_poll); +#ifdef CONFIG_HAVE_KVM_GMEM_PREPARE +bool kvm_arch_gmem_prepare_needed(struct kvm *kvm) +{ + return kvm->arch.vm_type == KVM_X86_SNP_VM; +} + +int kvm_arch_gmem_prepare(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, int max_order) +{ + return kvm_x86_call(gmem_prepare)(kvm, pfn, gfn, max_order); +} +#endif + +#ifdef CONFIG_HAVE_KVM_GMEM_INVALIDATE +void kvm_arch_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end) +{ + kvm_x86_call(gmem_invalidate)(start, end); +} +#endif int kvm_spec_ctrl_test_value(u64 value) { @@ -13974,6 +14044,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_vmgexit_enter); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_vmgexit_exit); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_vmgexit_msr_protocol_enter); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_vmgexit_msr_protocol_exit); +EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_rmp_fault); static int __init kvm_x86_init(void) { diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index d80a4c6b5a38..50596f6f8320 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -33,6 +33,20 @@ struct kvm_caps { u64 supported_perf_cap; }; +struct kvm_host_values { + /* + * The host's raw MAXPHYADDR, i.e. the number of non-reserved physical + * address bits irrespective of features that repurpose legal bits, + * e.g. MKTME. + */ + u8 maxphyaddr; + + u64 efer; + u64 xcr0; + u64 xss; + u64 arch_capabilities; +}; + void kvm_spurious_fault(void); #define KVM_NESTED_VMENTER_CONSISTENCY_CHECK(consistency_check) \ @@ -159,7 +173,7 @@ static inline bool is_64_bit_mode(struct kvm_vcpu *vcpu) if (!is_long_mode(vcpu)) return false; - static_call(kvm_x86_get_cs_db_l_bits)(vcpu, &cs_db, &cs_l); + kvm_x86_call(get_cs_db_l_bits)(vcpu, &cs_db, &cs_l); return cs_l; } @@ -311,12 +325,8 @@ int handle_ud(struct kvm_vcpu *vcpu); void kvm_deliver_exception_payload(struct kvm_vcpu *vcpu, struct kvm_queued_exception *ex); -void kvm_vcpu_mtrr_init(struct kvm_vcpu *vcpu); -u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn); int kvm_mtrr_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data); int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); -bool kvm_mtrr_check_gfn_range_consistency(struct kvm_vcpu *vcpu, gfn_t gfn, - int page_num); bool kvm_vector_hashing_enabled(void); void kvm_fixup_and_inject_pf_error(struct kvm_vcpu *vcpu, gva_t gva, u16 error_code); int x86_decode_emulated_instruction(struct kvm_vcpu *vcpu, int emulation_type, @@ -325,11 +335,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, int emulation_type, void *insn, int insn_len); fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu); -extern u64 host_xcr0; -extern u64 host_xss; -extern u64 host_arch_capabilities; - extern struct kvm_caps kvm_caps; +extern struct kvm_host_values kvm_host; extern bool enable_pmu; diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index f65b35a05d91..622fe24da910 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -741,7 +741,7 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data) } else { void __user * hva = u64_to_user_ptr(data->u.shared_info.hva); - if (!PAGE_ALIGNED(hva) || !access_ok(hva, PAGE_SIZE)) { + if (!PAGE_ALIGNED(hva)) { r = -EINVAL; } else if (!hva) { kvm_gpc_deactivate(&kvm->arch.xen.shinfo_cache); @@ -1270,7 +1270,7 @@ int kvm_xen_write_hypercall_page(struct kvm_vcpu *vcpu, u64 data) instructions[0] = 0xb8; /* vmcall / vmmcall */ - static_call(kvm_x86_patch_hypercall)(vcpu, instructions + 5); + kvm_x86_call(patch_hypercall)(vcpu, instructions + 5); /* ret */ instructions[8] = 0xc3; @@ -1650,7 +1650,7 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu) params[5] = (u64)kvm_r9_read(vcpu); } #endif - cpl = static_call(kvm_x86_get_cpl)(vcpu); + cpl = kvm_x86_call(get_cpl)(vcpu); trace_kvm_xen_hypercall(cpl, input, params[0], params[1], params[2], params[3], params[4], params[5]); diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index d4595d1985b1..5429ec9ef06f 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -3531,5 +3531,6 @@ static __exit void nfit_exit(void) module_init(nfit_init); module_exit(nfit_exit); +MODULE_DESCRIPTION("ACPI NVDIMM Firmware Interface Table (NFIT) driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Intel Corporation"); diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 1912bee22dd4..9810edbb272d 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -2033,6 +2033,39 @@ static int sev_ioctl_do_snp_set_config(struct sev_issue_cmd *argp, bool writable return __sev_do_cmd_locked(SEV_CMD_SNP_CONFIG, &config, &argp->error); } +static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable) +{ + struct sev_device *sev = psp_master->sev_data; + struct sev_user_data_snp_vlek_load input; + void *blob; + int ret; + + if (!sev->snp_initialized || !argp->data) + return -EINVAL; + + if (!writable) + return -EPERM; + + if (copy_from_user(&input, u64_to_user_ptr(argp->data), sizeof(input))) + return -EFAULT; + + if (input.len != sizeof(input) || input.vlek_wrapped_version != 0) + return -EINVAL; + + blob = psp_copy_user_blob(input.vlek_wrapped_address, + sizeof(struct sev_user_data_snp_wrapped_vlek_hashstick)); + if (IS_ERR(blob)) + return PTR_ERR(blob); + + input.vlek_wrapped_address = __psp_pa(blob); + + ret = __sev_do_cmd_locked(SEV_CMD_SNP_VLEK_LOAD, &input, &argp->error); + + kfree(blob); + + return ret; +} + static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg) { void __user *argp = (void __user *)arg; @@ -2093,6 +2126,9 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg) case SNP_SET_CONFIG: ret = sev_ioctl_do_snp_set_config(&input, writable); break; + case SNP_VLEK_LOAD: + ret = sev_ioctl_do_snp_vlek_load(&input, writable); + break; default: ret = -EINVAL; goto out; diff --git a/drivers/dax/cxl.c b/drivers/dax/cxl.c index c696837ab23c..9b29e732b39a 100644 --- a/drivers/dax/cxl.c +++ b/drivers/dax/cxl.c @@ -43,6 +43,7 @@ static struct cxl_driver cxl_dax_region_driver = { module_cxl_driver(cxl_dax_region_driver); MODULE_ALIAS_CXL(CXL_DEVICE_DAX_REGION); +MODULE_DESCRIPTION("CXL DAX: direct access to CXL regions"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Intel Corporation"); MODULE_IMPORT_NS(CXL); diff --git a/drivers/dax/device.c b/drivers/dax/device.c index eb61598247a9..2051e4f73c8a 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -482,6 +482,7 @@ static void __exit dax_exit(void) } MODULE_AUTHOR("Intel Corporation"); +MODULE_DESCRIPTION("Device DAX: direct access device driver"); MODULE_LICENSE("GPL v2"); module_init(dax_init); module_exit(dax_exit); diff --git a/drivers/dax/hmem/hmem.c b/drivers/dax/hmem/hmem.c index b9da69f92697..5e7c53f18491 100644 --- a/drivers/dax/hmem/hmem.c +++ b/drivers/dax/hmem/hmem.c @@ -168,5 +168,6 @@ MODULE_SOFTDEP("pre: cxl_acpi"); MODULE_ALIAS("platform:hmem*"); MODULE_ALIAS("platform:hmem_platform*"); +MODULE_DESCRIPTION("HMEM DAX: direct access to 'specific purpose' memory"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Intel Corporation"); diff --git a/drivers/dax/kmem.c b/drivers/dax/kmem.c index 4fe9d040e375..e97d47f42ee2 100644 --- a/drivers/dax/kmem.c +++ b/drivers/dax/kmem.c @@ -299,6 +299,7 @@ static void __exit dax_kmem_exit(void) } MODULE_AUTHOR("Intel Corporation"); +MODULE_DESCRIPTION("KMEM DAX: map dax-devices as System-RAM"); MODULE_LICENSE("GPL v2"); module_init(dax_kmem_init); module_exit(dax_kmem_exit); diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index f3c6c67b8412..c8ebf4e281f2 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -94,6 +94,7 @@ static void __exit dax_pmem_exit(void) } module_exit(dax_pmem_exit); +MODULE_DESCRIPTION("PMEM DAX: direct access to persistent memory"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Intel Corporation"); MODULE_ALIAS_ND_DEVICE(ND_DEVICE_DAX_PMEM); diff --git a/drivers/dax/super.c b/drivers/dax/super.c index aca71d7fccc1..e16d1d40d773 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -606,6 +606,7 @@ static void __exit dax_core_exit(void) } MODULE_AUTHOR("Intel Corporation"); +MODULE_DESCRIPTION("DAX: direct access to differentiated memory"); MODULE_LICENSE("GPL v2"); subsys_initcall(dax_core_init); module_exit(dax_core_exit); diff --git a/drivers/firewire/.kunitconfig b/drivers/firewire/.kunitconfig index 60d9e7c35417..21b7e9eef63d 100644 --- a/drivers/firewire/.kunitconfig +++ b/drivers/firewire/.kunitconfig @@ -4,3 +4,5 @@ CONFIG_FIREWIRE=y CONFIG_FIREWIRE_KUNIT_UAPI_TEST=y CONFIG_FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST=y CONFIG_FIREWIRE_KUNIT_PACKET_SERDES_TEST=y +CONFIG_FIREWIRE_KUNIT_SELF_ID_SEQUENCE_HELPER_TEST=y +CONFIG_FIREWIRE_KUNIT_OHCI_SERDES_TEST=y diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index 5268b3f0a25a..905c82e26ce7 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -66,6 +66,21 @@ config FIREWIRE_KUNIT_PACKET_SERDES_TEST For more information on KUnit and unit tests in general, refer to the KUnit documentation in Documentation/dev-tools/kunit/. +config FIREWIRE_KUNIT_SELF_ID_SEQUENCE_HELPER_TEST + tristate "KUnit tests for helpers of self ID sequence" if !KUNIT_ALL_TESTS + depends on FIREWIRE && KUNIT + default KUNIT_ALL_TESTS + help + This builds the KUnit tests for helpers of self ID sequence. + + KUnit tests run during boot and output the results to the debug + log in TAP format (https://testanything.org/). Only useful for + kernel devs running KUnit test harness and are not for inclusion + into a production build. + + For more information on KUnit and unit tests in general, refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + config FIREWIRE_OHCI tristate "OHCI-1394 controllers" depends on PCI && FIREWIRE && MMU @@ -77,6 +92,22 @@ config FIREWIRE_OHCI To compile this driver as a module, say M here: The module will be called firewire-ohci. +config FIREWIRE_KUNIT_OHCI_SERDES_TEST + tristate "KUnit tests for serialization/deserialization of data in buffers/registers" if !KUNIT_ALL_TESTS + depends on FIREWIRE && KUNIT + default KUNIT_ALL_TESTS + help + This builds the KUnit tests to check serialization and deserialization + of data in buffers and registers defined in 1394 OHCI specification. + + KUnit tests run during boot and output the results to the debug + log in TAP format (https://testanything.org/). Only useful for + kernel devs running KUnit test harness and are not for inclusion + into a production build. + + For more information on KUnit and unit tests in general, refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + config FIREWIRE_SBP2 tristate "Storage devices (SBP-2 protocol)" depends on FIREWIRE && SCSI diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile index 75c47d046925..1ff550e93a8c 100644 --- a/drivers/firewire/Makefile +++ b/drivers/firewire/Makefile @@ -18,3 +18,5 @@ obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o obj-$(CONFIG_FIREWIRE_KUNIT_UAPI_TEST) += uapi-test.o obj-$(CONFIG_FIREWIRE_KUNIT_PACKET_SERDES_TEST) += packet-serdes-test.o +obj-$(CONFIG_FIREWIRE_KUNIT_SELF_ID_SEQUENCE_HELPER_TEST) += self-id-sequence-helper-test.o +obj-$(CONFIG_FIREWIRE_KUNIT_OHCI_SERDES_TEST) += ohci-serdes-test.o diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index af70e74f9a7e..b3eda38a36f3 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -22,6 +22,8 @@ #include "core.h" +#include + /* * Isochronous DMA context management */ @@ -148,12 +150,20 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card, ctx->callback.sc = callback; ctx->callback_data = callback_data; + trace_isoc_outbound_allocate(ctx, channel, speed); + trace_isoc_inbound_single_allocate(ctx, channel, header_size); + trace_isoc_inbound_multiple_allocate(ctx); + return ctx; } EXPORT_SYMBOL(fw_iso_context_create); void fw_iso_context_destroy(struct fw_iso_context *ctx) { + trace_isoc_outbound_destroy(ctx); + trace_isoc_inbound_single_destroy(ctx); + trace_isoc_inbound_multiple_destroy(ctx); + ctx->card->driver->free_iso_context(ctx); } EXPORT_SYMBOL(fw_iso_context_destroy); @@ -161,12 +171,18 @@ EXPORT_SYMBOL(fw_iso_context_destroy); int fw_iso_context_start(struct fw_iso_context *ctx, int cycle, int sync, int tags) { + trace_isoc_outbound_start(ctx, cycle); + trace_isoc_inbound_single_start(ctx, cycle, sync, tags); + trace_isoc_inbound_multiple_start(ctx, cycle, sync, tags); + return ctx->card->driver->start_iso(ctx, cycle, sync, tags); } EXPORT_SYMBOL(fw_iso_context_start); int fw_iso_context_set_channels(struct fw_iso_context *ctx, u64 *channels) { + trace_isoc_inbound_multiple_channels(ctx, *channels); + return ctx->card->driver->set_iso_channels(ctx, channels); } @@ -175,24 +191,40 @@ int fw_iso_context_queue(struct fw_iso_context *ctx, struct fw_iso_buffer *buffer, unsigned long payload) { + trace_isoc_outbound_queue(ctx, payload, packet); + trace_isoc_inbound_single_queue(ctx, payload, packet); + trace_isoc_inbound_multiple_queue(ctx, payload, packet); + return ctx->card->driver->queue_iso(ctx, packet, buffer, payload); } EXPORT_SYMBOL(fw_iso_context_queue); void fw_iso_context_queue_flush(struct fw_iso_context *ctx) { + trace_isoc_outbound_flush(ctx); + trace_isoc_inbound_single_flush(ctx); + trace_isoc_inbound_multiple_flush(ctx); + ctx->card->driver->flush_queue_iso(ctx); } EXPORT_SYMBOL(fw_iso_context_queue_flush); int fw_iso_context_flush_completions(struct fw_iso_context *ctx) { + trace_isoc_outbound_flush_completions(ctx); + trace_isoc_inbound_single_flush_completions(ctx); + trace_isoc_inbound_multiple_flush_completions(ctx); + return ctx->card->driver->flush_iso_completions(ctx); } EXPORT_SYMBOL(fw_iso_context_flush_completions); int fw_iso_context_stop(struct fw_iso_context *ctx) { + trace_isoc_outbound_stop(ctx); + trace_isoc_inbound_single_stop(ctx); + trace_isoc_inbound_multiple_stop(ctx); + return ctx->card->driver->stop_iso(ctx); } EXPORT_SYMBOL(fw_iso_context_stop); diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c index 8107eebd4296..b4e637aa6932 100644 --- a/drivers/firewire/core-topology.c +++ b/drivers/firewire/core-topology.c @@ -20,84 +20,9 @@ #include #include "core.h" +#include "phy-packet-definitions.h" #include -#define SELF_ID_PHY_ID(q) (((q) >> 24) & 0x3f) -#define SELF_ID_EXTENDED(q) (((q) >> 23) & 0x01) -#define SELF_ID_LINK_ON(q) (((q) >> 22) & 0x01) -#define SELF_ID_GAP_COUNT(q) (((q) >> 16) & 0x3f) -#define SELF_ID_PHY_SPEED(q) (((q) >> 14) & 0x03) -#define SELF_ID_CONTENDER(q) (((q) >> 11) & 0x01) -#define SELF_ID_PHY_INITIATOR(q) (((q) >> 1) & 0x01) -#define SELF_ID_MORE_PACKETS(q) (((q) >> 0) & 0x01) - -#define SELF_ID_EXT_SEQUENCE(q) (((q) >> 20) & 0x07) - -#define SELFID_PORT_CHILD 0x3 -#define SELFID_PORT_PARENT 0x2 -#define SELFID_PORT_NCONN 0x1 -#define SELFID_PORT_NONE 0x0 - -static u32 *count_ports(u32 *sid, int *total_port_count, int *child_port_count) -{ - u32 q; - int port_type, shift, seq; - - *total_port_count = 0; - *child_port_count = 0; - - shift = 6; - q = *sid; - seq = 0; - - while (1) { - port_type = (q >> shift) & 0x03; - switch (port_type) { - case SELFID_PORT_CHILD: - (*child_port_count)++; - fallthrough; - case SELFID_PORT_PARENT: - case SELFID_PORT_NCONN: - (*total_port_count)++; - fallthrough; - case SELFID_PORT_NONE: - break; - } - - shift -= 2; - if (shift == 0) { - if (!SELF_ID_MORE_PACKETS(q)) - return sid + 1; - - shift = 16; - sid++; - q = *sid; - - /* - * Check that the extra packets actually are - * extended self ID packets and that the - * sequence numbers in the extended self ID - * packets increase as expected. - */ - - if (!SELF_ID_EXTENDED(q) || - seq != SELF_ID_EXT_SEQUENCE(q)) - return NULL; - - seq++; - } - } -} - -static int get_port_type(u32 *sid, int port_index) -{ - int index, shift; - - index = (port_index + 5) / 8; - shift = 16 - ((port_index + 5) & 7) * 2; - return (sid[index] >> shift) & 0x03; -} - static struct fw_node *fw_node_create(u32 sid, int port_count, int color) { struct fw_node *node; @@ -107,10 +32,11 @@ static struct fw_node *fw_node_create(u32 sid, int port_count, int color) return NULL; node->color = color; - node->node_id = LOCAL_BUS | SELF_ID_PHY_ID(sid); - node->link_on = SELF_ID_LINK_ON(sid); - node->phy_speed = SELF_ID_PHY_SPEED(sid); - node->initiated_reset = SELF_ID_PHY_INITIATOR(sid); + node->node_id = LOCAL_BUS | phy_packet_self_id_get_phy_id(sid); + node->link_on = phy_packet_self_id_zero_get_link_active(sid); + // NOTE: Only two bits, thus only for SCODE_100, SCODE_200, SCODE_400, and SCODE_BETA. + node->phy_speed = phy_packet_self_id_zero_get_scode(sid); + node->initiated_reset = phy_packet_self_id_zero_get_initiated_reset(sid); node->port_count = port_count; refcount_set(&node->ref_count, 1); @@ -169,13 +95,16 @@ static inline struct fw_node *fw_node(struct list_head *l) * internally consistent. On success this function returns the * fw_node corresponding to the local card otherwise NULL. */ -static struct fw_node *build_tree(struct fw_card *card, - u32 *sid, int self_id_count) +static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self_id_count, + unsigned int generation) { + struct self_id_sequence_enumerator enumerator = { + .cursor = sid, + .quadlet_count = self_id_count, + }; struct fw_node *node, *child, *local_node, *irm_node; - struct list_head stack, *h; - u32 *next_sid, *end, q; - int i, port_count, child_port_count, phy_id, parent_count, stack_depth; + struct list_head stack; + int phy_id, stack_depth; int gap_count; bool beta_repeaters_present; @@ -183,24 +112,56 @@ static struct fw_node *build_tree(struct fw_card *card, node = NULL; INIT_LIST_HEAD(&stack); stack_depth = 0; - end = sid + self_id_count; phy_id = 0; irm_node = NULL; - gap_count = SELF_ID_GAP_COUNT(*sid); + gap_count = phy_packet_self_id_zero_get_gap_count(*sid); beta_repeaters_present = false; - while (sid < end) { - next_sid = count_ports(sid, &port_count, &child_port_count); + while (enumerator.quadlet_count > 0) { + unsigned int child_port_count = 0; + unsigned int total_port_count = 0; + unsigned int parent_count = 0; + unsigned int quadlet_count; + const u32 *self_id_sequence; + unsigned int port_capacity; + enum phy_packet_self_id_port_status port_status; + unsigned int port_index; + struct list_head *h; + int i; - if (next_sid == NULL) { - fw_err(card, "inconsistent extended self IDs\n"); - return NULL; + self_id_sequence = self_id_sequence_enumerator_next(&enumerator, &quadlet_count); + if (IS_ERR(self_id_sequence)) { + if (PTR_ERR(self_id_sequence) != -ENODATA) { + fw_err(card, "inconsistent extended self IDs: %ld\n", + PTR_ERR(self_id_sequence)); + return NULL; + } + break; } - q = *sid; - if (phy_id != SELF_ID_PHY_ID(q)) { + port_capacity = self_id_sequence_get_port_capacity(quadlet_count); + trace_self_id_sequence(card->index, self_id_sequence, quadlet_count, generation); + + for (port_index = 0; port_index < port_capacity; ++port_index) { + port_status = self_id_sequence_get_port_status(self_id_sequence, quadlet_count, + port_index); + switch (port_status) { + case PHY_PACKET_SELF_ID_PORT_STATUS_CHILD: + ++child_port_count; + fallthrough; + case PHY_PACKET_SELF_ID_PORT_STATUS_PARENT: + case PHY_PACKET_SELF_ID_PORT_STATUS_NCONN: + ++total_port_count; + fallthrough; + case PHY_PACKET_SELF_ID_PORT_STATUS_NONE: + default: + break; + } + } + + if (phy_id != phy_packet_self_id_get_phy_id(self_id_sequence[0])) { fw_err(card, "PHY ID mismatch in self ID: %d != %d\n", - phy_id, SELF_ID_PHY_ID(q)); + phy_id, phy_packet_self_id_get_phy_id(self_id_sequence[0])); return NULL; } @@ -221,7 +182,7 @@ static struct fw_node *build_tree(struct fw_card *card, */ child = fw_node(h); - node = fw_node_create(q, port_count, card->color); + node = fw_node_create(self_id_sequence[0], total_port_count, card->color); if (node == NULL) { fw_err(card, "out of memory while building topology\n"); return NULL; @@ -230,48 +191,40 @@ static struct fw_node *build_tree(struct fw_card *card, if (phy_id == (card->node_id & 0x3f)) local_node = node; - if (SELF_ID_CONTENDER(q)) + if (phy_packet_self_id_zero_get_contender(self_id_sequence[0])) irm_node = node; - parent_count = 0; - - for (i = 0; i < port_count; i++) { - switch (get_port_type(sid, i)) { - case SELFID_PORT_PARENT: - /* - * Who's your daddy? We dont know the - * parent node at this time, so we - * temporarily abuse node->color for - * remembering the entry in the - * node->ports array where the parent - * node should be. Later, when we - * handle the parent node, we fix up - * the reference. - */ - parent_count++; + for (port_index = 0; port_index < total_port_count; ++port_index) { + port_status = self_id_sequence_get_port_status(self_id_sequence, quadlet_count, + port_index); + switch (port_status) { + case PHY_PACKET_SELF_ID_PORT_STATUS_PARENT: + // Who's your daddy? We dont know the parent node at this time, so + // we temporarily abuse node->color for remembering the entry in + // the node->ports array where the parent node should be. Later, + // when we handle the parent node, we fix up the reference. + ++parent_count; node->color = i; break; - case SELFID_PORT_CHILD: - node->ports[i] = child; - /* - * Fix up parent reference for this - * child node. - */ + case PHY_PACKET_SELF_ID_PORT_STATUS_CHILD: + node->ports[port_index] = child; + // Fix up parent reference for this child node. child->ports[child->color] = node; child->color = card->color; child = fw_node(child->link.next); break; + case PHY_PACKET_SELF_ID_PORT_STATUS_NCONN: + case PHY_PACKET_SELF_ID_PORT_STATUS_NONE: + default: + break; } } - /* - * Check that the node reports exactly one parent - * port, except for the root, which of course should - * have no parents. - */ - if ((next_sid == end && parent_count != 0) || - (next_sid < end && parent_count != 1)) { + // Check that the node reports exactly one parent port, except for the root, which + // of course should have no parents. + if ((enumerator.quadlet_count == 0 && parent_count != 0) || + (enumerator.quadlet_count > 0 && parent_count != 1)) { fw_err(card, "parent port inconsistency for node %d: " "parent_count=%d\n", phy_id, parent_count); return NULL; @@ -282,20 +235,16 @@ static struct fw_node *build_tree(struct fw_card *card, list_add_tail(&node->link, &stack); stack_depth += 1 - child_port_count; - if (node->phy_speed == SCODE_BETA && - parent_count + child_port_count > 1) + if (node->phy_speed == SCODE_BETA && parent_count + child_port_count > 1) beta_repeaters_present = true; - /* - * If PHYs report different gap counts, set an invalid count - * which will force a gap count reconfiguration and a reset. - */ - if (SELF_ID_GAP_COUNT(q) != gap_count) + // If PHYs report different gap counts, set an invalid count which will force a gap + // count reconfiguration and a reset. + if (phy_packet_self_id_zero_get_gap_count(self_id_sequence[0]) != gap_count) gap_count = 0; update_hop_count(node); - sid = next_sid; phy_id++; } @@ -536,7 +485,7 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, card->bm_abdicate = bm_abdicate; fw_schedule_bm_work(card, 0); - local_node = build_tree(card, self_ids, self_id_count); + local_node = build_tree(card, self_ids, self_id_count, generation); update_topology_map(card, self_ids, self_id_count); diff --git a/drivers/firewire/core-trace.c b/drivers/firewire/core-trace.c index 96cbd9d384dc..b70947fc7b8d 100644 --- a/drivers/firewire/core-trace.c +++ b/drivers/firewire/core-trace.c @@ -1,5 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright (c) 2024 Takashi Sakamoto +#include +#include +#include "packet-header-definitions.h" +#include "phy-packet-definitions.h" + #define CREATE_TRACE_POINTS #include + +#ifdef TRACEPOINTS_ENABLED +EXPORT_TRACEPOINT_SYMBOL_GPL(isoc_inbound_single_completions); +EXPORT_TRACEPOINT_SYMBOL_GPL(isoc_inbound_multiple_completions); +EXPORT_TRACEPOINT_SYMBOL_GPL(isoc_outbound_completions); +#endif diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 76ab6a209768..4d2fc1f31fec 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -29,20 +29,13 @@ #include #include "core.h" -#include #include "packet-header-definitions.h" +#include "phy-packet-definitions.h" +#include #define HEADER_DESTINATION_IS_BROADCAST(header) \ ((async_header_get_destination(header) & 0x3f) == 0x3f) -#define PHY_PACKET_CONFIG 0x0 -#define PHY_PACKET_LINK_ON 0x1 -#define PHY_PACKET_SELF_ID 0x2 - -#define PHY_CONFIG_GAP_COUNT(gap_count) (((gap_count) << 16) | (1 << 22)) -#define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) -#define PHY_IDENTIFIER(id) ((id) << 30) - /* returns 0 if the split timeout handler is already running */ static int try_cancel_split_timeout(struct fw_transaction *t) { @@ -481,10 +474,14 @@ void fw_send_phy_config(struct fw_card *card, int node_id, int generation, int gap_count) { long timeout = DIV_ROUND_UP(HZ, 10); - u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG); + u32 data = 0; - if (node_id != FW_PHY_CONFIG_NO_NODE_ID) - data |= PHY_CONFIG_ROOT_ID(node_id); + phy_packet_set_packet_identifier(&data, PHY_PACKET_PACKET_IDENTIFIER_PHY_CONFIG); + + if (node_id != FW_PHY_CONFIG_NO_NODE_ID) { + phy_packet_phy_config_set_root_id(&data, node_id); + phy_packet_phy_config_set_force_root_node(&data, true); + } if (gap_count == FW_PHY_CONFIG_CURRENT_GAP_COUNT) { gap_count = card->driver->read_phy_reg(card, 1); @@ -495,7 +492,8 @@ void fw_send_phy_config(struct fw_card *card, if (gap_count == 63) return; } - data |= PHY_CONFIG_GAP_COUNT(gap_count); + phy_packet_phy_config_set_gap_count(&data, gap_count); + phy_packet_phy_config_set_gap_count_optimization(&data, true); mutex_lock(&phy_config_mutex); diff --git a/drivers/firewire/ohci-serdes-test.c b/drivers/firewire/ohci-serdes-test.c new file mode 100644 index 000000000000..304a09ff528e --- /dev/null +++ b/drivers/firewire/ohci-serdes-test.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// ohci-serdes-test.c - An application of Kunit to check serialization/deserialization of data in +// buffers and registers defined in 1394 OHCI specification. +// +// Copyright (c) 2024 Takashi Sakamoto + +#include + +#include "ohci.h" + + +static void test_self_id_count_register_deserialization(struct kunit *test) +{ + const u32 expected = 0x803d0594; + + bool is_error = ohci1394_self_id_count_is_error(expected); + u8 generation = ohci1394_self_id_count_get_generation(expected); + u32 size = ohci1394_self_id_count_get_size(expected); + + KUNIT_EXPECT_TRUE(test, is_error); + KUNIT_EXPECT_EQ(test, 0x3d, generation); + KUNIT_EXPECT_EQ(test, 0x165, size); +} + +static void test_self_id_receive_buffer_deserialization(struct kunit *test) +{ + const u32 buffer[] = { + 0x0006f38b, + 0x807fcc56, + 0x7f8033a9, + 0x8145cc5e, + 0x7eba33a1, + }; + + u8 generation = ohci1394_self_id_receive_q0_get_generation(buffer[0]); + u16 timestamp = ohci1394_self_id_receive_q0_get_timestamp(buffer[0]); + + KUNIT_EXPECT_EQ(test, 0x6, generation); + KUNIT_EXPECT_EQ(test, 0xf38b, timestamp); +} + +static struct kunit_case ohci_serdes_test_cases[] = { + KUNIT_CASE(test_self_id_count_register_deserialization), + KUNIT_CASE(test_self_id_receive_buffer_deserialization), + {} +}; + +static struct kunit_suite ohci_serdes_test_suite = { + .name = "firewire-ohci-serdes", + .test_cases = ohci_serdes_test_cases, +}; +kunit_test_suite(ohci_serdes_test_suite); + +MODULE_DESCRIPTION("FireWire buffers and registers serialization/deserialization unit test suite"); +MODULE_LICENSE("GPL"); diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index f6de0b3a9a55..314a29c0fd3e 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -41,6 +41,14 @@ #include "core.h" #include "ohci.h" #include "packet-header-definitions.h" +#include "phy-packet-definitions.h" + +#include + +static u32 cond_le32_to_cpu(__le32 value, bool has_be_header_quirk); + +#define CREATE_TRACE_POINTS +#include #define ohci_info(ohci, f, args...) dev_info(ohci->card.device, f, ##args) #define ohci_notice(ohci, f, args...) dev_notice(ohci->card.device, f, ##args) @@ -437,23 +445,25 @@ static void log_irqs(struct fw_ohci *ohci, u32 evt) ? " ?" : ""); } -static const char *speed[] = { - [0] = "S100", [1] = "S200", [2] = "S400", [3] = "beta", -}; -static const char *power[] = { - [0] = "+0W", [1] = "+15W", [2] = "+30W", [3] = "+45W", - [4] = "-3W", [5] = " ?W", [6] = "-3..-6W", [7] = "-3..-10W", -}; -static const char port[] = { '.', '-', 'p', 'c', }; - -static char _p(u32 *s, int shift) -{ - return port[*s >> shift & 3]; -} - static void log_selfids(struct fw_ohci *ohci, int generation, int self_id_count) { - u32 *s; + static const char *const speed[] = { + [0] = "S100", [1] = "S200", [2] = "S400", [3] = "beta", + }; + static const char *const power[] = { + [0] = "+0W", [1] = "+15W", [2] = "+30W", [3] = "+45W", + [4] = "-3W", [5] = " ?W", [6] = "-3..-6W", [7] = "-3..-10W", + }; + static const char port[] = { + [PHY_PACKET_SELF_ID_PORT_STATUS_NONE] = '.', + [PHY_PACKET_SELF_ID_PORT_STATUS_NCONN] = '-', + [PHY_PACKET_SELF_ID_PORT_STATUS_PARENT] = 'p', + [PHY_PACKET_SELF_ID_PORT_STATUS_CHILD] = 'c', + }; + struct self_id_sequence_enumerator enumerator = { + .cursor = ohci->self_id_buffer, + .quadlet_count = self_id_count, + }; if (likely(!(param_debug & OHCI_PARAM_DEBUG_SELFIDS))) return; @@ -461,20 +471,46 @@ static void log_selfids(struct fw_ohci *ohci, int generation, int self_id_count) ohci_notice(ohci, "%d selfIDs, generation %d, local node ID %04x\n", self_id_count, generation, ohci->node_id); - for (s = ohci->self_id_buffer; self_id_count--; ++s) - if ((*s & 1 << 23) == 0) - ohci_notice(ohci, - "selfID 0: %08x, phy %d [%c%c%c] %s gc=%d %s %s%s%s\n", - *s, *s >> 24 & 63, _p(s, 6), _p(s, 4), _p(s, 2), - speed[*s >> 14 & 3], *s >> 16 & 63, - power[*s >> 8 & 7], *s >> 22 & 1 ? "L" : "", - *s >> 11 & 1 ? "c" : "", *s & 2 ? "i" : ""); - else + while (enumerator.quadlet_count > 0) { + unsigned int quadlet_count; + unsigned int port_index; + const u32 *s; + int i; + + s = self_id_sequence_enumerator_next(&enumerator, &quadlet_count); + if (IS_ERR(s)) + break; + + ohci_notice(ohci, + "selfID 0: %08x, phy %d [%c%c%c] %s gc=%d %s %s%s%s\n", + *s, + phy_packet_self_id_get_phy_id(*s), + port[self_id_sequence_get_port_status(s, quadlet_count, 0)], + port[self_id_sequence_get_port_status(s, quadlet_count, 1)], + port[self_id_sequence_get_port_status(s, quadlet_count, 2)], + speed[*s >> 14 & 3], *s >> 16 & 63, + power[*s >> 8 & 7], *s >> 22 & 1 ? "L" : "", + *s >> 11 & 1 ? "c" : "", *s & 2 ? "i" : ""); + + port_index = 3; + for (i = 1; i < quadlet_count; ++i) { ohci_notice(ohci, "selfID n: %08x, phy %d [%c%c%c%c%c%c%c%c]\n", - *s, *s >> 24 & 63, - _p(s, 16), _p(s, 14), _p(s, 12), _p(s, 10), - _p(s, 8), _p(s, 6), _p(s, 4), _p(s, 2)); + s[i], + phy_packet_self_id_get_phy_id(s[i]), + port[self_id_sequence_get_port_status(s, quadlet_count, port_index)], + port[self_id_sequence_get_port_status(s, quadlet_count, port_index + 1)], + port[self_id_sequence_get_port_status(s, quadlet_count, port_index + 2)], + port[self_id_sequence_get_port_status(s, quadlet_count, port_index + 3)], + port[self_id_sequence_get_port_status(s, quadlet_count, port_index + 4)], + port[self_id_sequence_get_port_status(s, quadlet_count, port_index + 5)], + port[self_id_sequence_get_port_status(s, quadlet_count, port_index + 6)], + port[self_id_sequence_get_port_status(s, quadlet_count, port_index + 7)] + ); + + port_index += 8; + } + } } static const char *evts[] = { @@ -841,10 +877,25 @@ static void ar_sync_buffers_for_cpu(struct ar_context *ctx, } #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) -#define cond_le32_to_cpu(v) \ - (ohci->quirks & QUIRK_BE_HEADERS ? (__force __u32)(v) : le32_to_cpu(v)) +static u32 cond_le32_to_cpu(__le32 value, bool has_be_header_quirk) +{ + return has_be_header_quirk ? (__force __u32)value : le32_to_cpu(value); +} + +static bool has_be_header_quirk(const struct fw_ohci *ohci) +{ + return !!(ohci->quirks & QUIRK_BE_HEADERS); +} #else -#define cond_le32_to_cpu(v) le32_to_cpu(v) +static u32 cond_le32_to_cpu(__le32 value, bool has_be_header_quirk __maybe_unused) +{ + return le32_to_cpu(value); +} + +static bool has_be_header_quirk(const struct fw_ohci *ohci) +{ + return false; +} #endif static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) @@ -854,9 +905,9 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) u32 status, length, tcode; int evt; - p.header[0] = cond_le32_to_cpu(buffer[0]); - p.header[1] = cond_le32_to_cpu(buffer[1]); - p.header[2] = cond_le32_to_cpu(buffer[2]); + p.header[0] = cond_le32_to_cpu(buffer[0], has_be_header_quirk(ohci)); + p.header[1] = cond_le32_to_cpu(buffer[1], has_be_header_quirk(ohci)); + p.header[2] = cond_le32_to_cpu(buffer[2], has_be_header_quirk(ohci)); tcode = async_header_get_tcode(p.header); switch (tcode) { @@ -868,7 +919,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) break; case TCODE_READ_BLOCK_REQUEST : - p.header[3] = cond_le32_to_cpu(buffer[3]); + p.header[3] = cond_le32_to_cpu(buffer[3], has_be_header_quirk(ohci)); p.header_length = 16; p.payload_length = 0; break; @@ -877,7 +928,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) case TCODE_READ_BLOCK_RESPONSE: case TCODE_LOCK_REQUEST: case TCODE_LOCK_RESPONSE: - p.header[3] = cond_le32_to_cpu(buffer[3]); + p.header[3] = cond_le32_to_cpu(buffer[3], has_be_header_quirk(ohci)); p.header_length = 16; p.payload_length = async_header_get_data_length(p.header); if (p.payload_length > MAX_ASYNC_PAYLOAD) { @@ -902,7 +953,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) /* FIXME: What to do about evt_* errors? */ length = (p.header_length + p.payload_length + 3) / 4; - status = cond_le32_to_cpu(buffer[length]); + status = cond_le32_to_cpu(buffer[length], has_be_header_quirk(ohci)); evt = (status >> 16) & 0x1f; p.ack = evt - 16; @@ -1817,7 +1868,8 @@ static u32 update_bus_time(struct fw_ohci *ohci) return ohci->bus_time | cycle_time_seconds; } -static int get_status_for_port(struct fw_ohci *ohci, int port_index) +static int get_status_for_port(struct fw_ohci *ohci, int port_index, + enum phy_packet_self_id_port_status *status) { int reg; @@ -1831,33 +1883,44 @@ static int get_status_for_port(struct fw_ohci *ohci, int port_index) switch (reg & 0x0f) { case 0x06: - return 2; /* is child node (connected to parent node) */ + // is child node (connected to parent node) + *status = PHY_PACKET_SELF_ID_PORT_STATUS_PARENT; + break; case 0x0e: - return 3; /* is parent node (connected to child node) */ + // is parent node (connected to child node) + *status = PHY_PACKET_SELF_ID_PORT_STATUS_CHILD; + break; + default: + // not connected + *status = PHY_PACKET_SELF_ID_PORT_STATUS_NCONN; + break; } - return 1; /* not connected */ + + return 0; } static int get_self_id_pos(struct fw_ohci *ohci, u32 self_id, int self_id_count) { + unsigned int left_phy_id = phy_packet_self_id_get_phy_id(self_id); int i; - u32 entry; for (i = 0; i < self_id_count; i++) { - entry = ohci->self_id_buffer[i]; - if ((self_id & 0xff000000) == (entry & 0xff000000)) + u32 entry = ohci->self_id_buffer[i]; + unsigned int right_phy_id = phy_packet_self_id_get_phy_id(entry); + + if (left_phy_id == right_phy_id) return -1; - if ((self_id & 0xff000000) < (entry & 0xff000000)) + if (left_phy_id < right_phy_id) return i; } return i; } -static int initiated_reset(struct fw_ohci *ohci) +static bool initiated_reset(struct fw_ohci *ohci) { int reg; - int ret = 0; + int ret = false; mutex_lock(&ohci->phy_reg_mutex); reg = write_phy_reg(ohci, 7, 0xe0); /* Select page 7 */ @@ -1870,7 +1933,7 @@ static int initiated_reset(struct fw_ohci *ohci) if (reg >= 0) { if ((reg & 0x08) == 0x08) { /* bit 3 indicates "initiated reset" */ - ret = 0x2; + ret = true; } } } @@ -1886,9 +1949,14 @@ static int initiated_reset(struct fw_ohci *ohci) */ static int find_and_insert_self_id(struct fw_ohci *ohci, int self_id_count) { - int reg, i, pos, status; - /* link active 1, speed 3, bridge 0, contender 1, more packets 0 */ - u32 self_id = 0x8040c800; + int reg, i, pos; + u32 self_id = 0; + + // link active 1, speed 3, bridge 0, contender 1, more packets 0. + phy_packet_set_packet_identifier(&self_id, PHY_PACKET_PACKET_IDENTIFIER_SELF_ID); + phy_packet_self_id_zero_set_link_active(&self_id, true); + phy_packet_self_id_zero_set_scode(&self_id, SCODE_800); + phy_packet_self_id_zero_set_contender(&self_id, true); reg = reg_read(ohci, OHCI1394_NodeID); if (!(reg & OHCI1394_NodeID_idValid)) { @@ -1896,26 +1964,30 @@ static int find_and_insert_self_id(struct fw_ohci *ohci, int self_id_count) "node ID not valid, new bus reset in progress\n"); return -EBUSY; } - self_id |= ((reg & 0x3f) << 24); /* phy ID */ + phy_packet_self_id_set_phy_id(&self_id, reg & 0x3f); reg = ohci_read_phy_reg(&ohci->card, 4); if (reg < 0) return reg; - self_id |= ((reg & 0x07) << 8); /* power class */ + phy_packet_self_id_zero_set_power_class(&self_id, reg & 0x07); reg = ohci_read_phy_reg(&ohci->card, 1); if (reg < 0) return reg; - self_id |= ((reg & 0x3f) << 16); /* gap count */ + phy_packet_self_id_zero_set_gap_count(&self_id, reg & 0x3f); for (i = 0; i < 3; i++) { - status = get_status_for_port(ohci, i); - if (status < 0) - return status; - self_id |= ((status & 0x3) << (6 - (i * 2))); + enum phy_packet_self_id_port_status status; + int err; + + err = get_status_for_port(ohci, i, &status); + if (err < 0) + return err; + + self_id_sequence_set_port_status(&self_id, 1, i, status); } - self_id |= initiated_reset(ohci); + phy_packet_self_id_zero_set_initiated_reset(&self_id, initiated_reset(ohci)); pos = get_self_id_pos(ohci, self_id, self_id_count); if (pos >= 0) { @@ -1933,7 +2005,7 @@ static void bus_reset_work(struct work_struct *work) struct fw_ohci *ohci = container_of(work, struct fw_ohci, bus_reset_work); int self_id_count, generation, new_generation, i, j; - u32 reg; + u32 reg, quadlet; void *free_rom = NULL; dma_addr_t free_rom_bus = 0; bool is_new_root; @@ -1958,7 +2030,7 @@ static void bus_reset_work(struct work_struct *work) ohci->is_root = is_new_root; reg = reg_read(ohci, OHCI1394_SelfIDCount); - if (reg & OHCI1394_SelfIDCount_selfIDError) { + if (ohci1394_self_id_count_is_error(reg)) { ohci_notice(ohci, "self ID receive error\n"); return; } @@ -1968,19 +2040,20 @@ static void bus_reset_work(struct work_struct *work) * the inverted quadlets and a header quadlet, we shift one * bit extra to get the actual number of self IDs. */ - self_id_count = (reg >> 3) & 0xff; + self_id_count = ohci1394_self_id_count_get_size(reg) >> 1; if (self_id_count > 252) { ohci_notice(ohci, "bad selfIDSize (%08x)\n", reg); return; } - generation = (cond_le32_to_cpu(ohci->self_id[0]) >> 16) & 0xff; + quadlet = cond_le32_to_cpu(ohci->self_id[0], has_be_header_quirk(ohci)); + generation = ohci1394_self_id_receive_q0_get_generation(quadlet); rmb(); for (i = 1, j = 0; j < self_id_count; i += 2, j++) { - u32 id = cond_le32_to_cpu(ohci->self_id[i]); - u32 id2 = cond_le32_to_cpu(ohci->self_id[i + 1]); + u32 id = cond_le32_to_cpu(ohci->self_id[i], has_be_header_quirk(ohci)); + u32 id2 = cond_le32_to_cpu(ohci->self_id[i + 1], has_be_header_quirk(ohci)); if (id != ~id2) { /* @@ -2032,7 +2105,8 @@ static void bus_reset_work(struct work_struct *work) * of self IDs. */ - new_generation = (reg_read(ohci, OHCI1394_SelfIDCount) >> 16) & 0xff; + reg = reg_read(ohci, OHCI1394_SelfIDCount); + new_generation = ohci1394_self_id_count_get_generation(reg); if (new_generation != generation) { ohci_notice(ohci, "new bus reset, discarding self ids\n"); return; @@ -2130,13 +2204,21 @@ static irqreturn_t irq_handler(int irq, void *data) */ reg_write(ohci, OHCI1394_IntEventClear, event & ~(OHCI1394_busReset | OHCI1394_postedWriteErr)); + trace_irqs(ohci->card.index, event); log_irqs(ohci, event); // The flag is masked again at bus_reset_work() scheduled by selfID event. if (event & OHCI1394_busReset) reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset); - if (event & OHCI1394_selfIDComplete) + if (event & OHCI1394_selfIDComplete) { + if (trace_self_id_complete_enabled()) { + u32 reg = reg_read(ohci, OHCI1394_SelfIDCount); + + trace_self_id_complete(ohci->card.index, reg, ohci->self_id, + has_be_header_quirk(ohci)); + } queue_work(selfid_workqueue, &ohci->bus_reset_work); + } if (event & OHCI1394_RQPkt) tasklet_schedule(&ohci->ar_request_ctx.tasklet); @@ -2781,8 +2863,13 @@ static void ohci_write_csr(struct fw_card *card, int csr_offset, u32 value) } } -static void flush_iso_completions(struct iso_context *ctx) +static void flush_iso_completions(struct iso_context *ctx, enum fw_iso_context_completions_cause cause) { + trace_isoc_inbound_single_completions(&ctx->base, ctx->last_timestamp, cause, ctx->header, + ctx->header_length); + trace_isoc_outbound_completions(&ctx->base, ctx->last_timestamp, cause, ctx->header, + ctx->header_length); + ctx->base.callback.sc(&ctx->base, ctx->last_timestamp, ctx->header_length, ctx->header, ctx->base.callback_data); @@ -2796,7 +2883,7 @@ static void copy_iso_headers(struct iso_context *ctx, const u32 *dma_hdr) if (ctx->header_length + ctx->base.header_size > PAGE_SIZE) { if (ctx->base.drop_overflow_headers) return; - flush_iso_completions(ctx); + flush_iso_completions(ctx, FW_ISO_CONTEXT_COMPLETIONS_CAUSE_HEADER_OVERFLOW); } ctx_hdr = ctx->header + ctx->header_length; @@ -2845,7 +2932,7 @@ static int handle_ir_packet_per_buffer(struct context *context, copy_iso_headers(ctx, (u32 *) (last + 1)); if (last->control & cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS)) - flush_iso_completions(ctx); + flush_iso_completions(ctx, FW_ISO_CONTEXT_COMPLETIONS_CAUSE_IRQ); return 1; } @@ -2880,6 +2967,9 @@ static int handle_ir_buffer_fill(struct context *context, completed, DMA_FROM_DEVICE); if (last->control & cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS)) { + trace_isoc_inbound_multiple_completions(&ctx->base, completed, + FW_ISO_CONTEXT_COMPLETIONS_CAUSE_IRQ); + ctx->base.callback.mc(&ctx->base, buffer_dma + completed, ctx->base.callback_data); @@ -2896,6 +2986,9 @@ static void flush_ir_buffer_fill(struct iso_context *ctx) ctx->mc_buffer_bus & ~PAGE_MASK, ctx->mc_completed, DMA_FROM_DEVICE); + trace_isoc_inbound_multiple_completions(&ctx->base, ctx->mc_completed, + FW_ISO_CONTEXT_COMPLETIONS_CAUSE_FLUSH); + ctx->base.callback.mc(&ctx->base, ctx->mc_buffer_bus + ctx->mc_completed, ctx->base.callback_data); @@ -2960,7 +3053,7 @@ static int handle_it_packet(struct context *context, if (ctx->header_length + 4 > PAGE_SIZE) { if (ctx->base.drop_overflow_headers) return 1; - flush_iso_completions(ctx); + flush_iso_completions(ctx, FW_ISO_CONTEXT_COMPLETIONS_CAUSE_HEADER_OVERFLOW); } ctx_hdr = ctx->header + ctx->header_length; @@ -2971,7 +3064,7 @@ static int handle_it_packet(struct context *context, ctx->header_length += 4; if (last->control & cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS)) - flush_iso_completions(ctx); + flush_iso_completions(ctx, FW_ISO_CONTEXT_COMPLETIONS_CAUSE_IRQ); return 1; } @@ -3536,7 +3629,7 @@ static int ohci_flush_iso_completions(struct fw_iso_context *base) case FW_ISO_CONTEXT_TRANSMIT: case FW_ISO_CONTEXT_RECEIVE: if (ctx->header_length != 0) - flush_iso_completions(ctx); + flush_iso_completions(ctx, FW_ISO_CONTEXT_COMPLETIONS_CAUSE_FLUSH); break; case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: if (ctx->mc_completed != 0) diff --git a/drivers/firewire/ohci.h b/drivers/firewire/ohci.h index c4d005a9901a..71c2ed84cafb 100644 --- a/drivers/firewire/ohci.h +++ b/drivers/firewire/ohci.h @@ -31,7 +31,6 @@ #define OHCI1394_HCControl_softReset 0x00010000 #define OHCI1394_SelfIDBuffer 0x064 #define OHCI1394_SelfIDCount 0x068 -#define OHCI1394_SelfIDCount_selfIDError 0x80000000 #define OHCI1394_IRMultiChanMaskHiSet 0x070 #define OHCI1394_IRMultiChanMaskHiClear 0x074 #define OHCI1394_IRMultiChanMaskLoSet 0x078 @@ -156,4 +155,46 @@ #define OHCI1394_phy_tcode 0xe +// Self-ID DMA. + +#define OHCI1394_SelfIDCount_selfIDError_MASK 0x80000000 +#define OHCI1394_SelfIDCount_selfIDError_SHIFT 31 +#define OHCI1394_SelfIDCount_selfIDGeneration_MASK 0x00ff0000 +#define OHCI1394_SelfIDCount_selfIDGeneration_SHIFT 16 +#define OHCI1394_SelfIDCount_selfIDSize_MASK 0x000007fc +#define OHCI1394_SelfIDCount_selfIDSize_SHIFT 2 + +static inline bool ohci1394_self_id_count_is_error(u32 value) +{ + return !!((value & OHCI1394_SelfIDCount_selfIDError_MASK) >> OHCI1394_SelfIDCount_selfIDError_SHIFT); +} + +static inline u8 ohci1394_self_id_count_get_generation(u32 value) +{ + return (value & OHCI1394_SelfIDCount_selfIDGeneration_MASK) >> OHCI1394_SelfIDCount_selfIDGeneration_SHIFT; +} + +// In 1394 OHCI specification, the maximum size of self ID stream is 504 quadlets +// (= 63 devices * 4 self ID packets * 2 quadlets). The selfIDSize field accommodates it and its +// additional first quadlet, since the field is 9 bits (0x1ff = 511). +static inline u32 ohci1394_self_id_count_get_size(u32 value) +{ + return (value & OHCI1394_SelfIDCount_selfIDSize_MASK) >> OHCI1394_SelfIDCount_selfIDSize_SHIFT; +} + +#define OHCI1394_SELF_ID_RECEIVE_Q0_GENERATION_MASK 0x00ff0000 +#define OHCI1394_SELF_ID_RECEIVE_Q0_GENERATION_SHIFT 16 +#define OHCI1394_SELF_ID_RECEIVE_Q0_TIMESTAMP_MASK 0x0000ffff +#define OHCI1394_SELF_ID_RECEIVE_Q0_TIMESTAMP_SHIFT 0 + +static inline u8 ohci1394_self_id_receive_q0_get_generation(u32 quadlet0) +{ + return (quadlet0 & OHCI1394_SELF_ID_RECEIVE_Q0_GENERATION_MASK) >> OHCI1394_SELF_ID_RECEIVE_Q0_GENERATION_SHIFT; +} + +static inline u16 ohci1394_self_id_receive_q0_get_timestamp(u32 quadlet0) +{ + return (quadlet0 & OHCI1394_SELF_ID_RECEIVE_Q0_TIMESTAMP_MASK) >> OHCI1394_SELF_ID_RECEIVE_Q0_TIMESTAMP_SHIFT; +} + #endif /* _FIREWIRE_OHCI_H */ diff --git a/drivers/firewire/packet-header-definitions.h b/drivers/firewire/packet-header-definitions.h index ab9d0fa790d4..87a5a31845c3 100644 --- a/drivers/firewire/packet-header-definitions.h +++ b/drivers/firewire/packet-header-definitions.h @@ -7,6 +7,8 @@ #ifndef _FIREWIRE_PACKET_HEADER_DEFINITIONS_H #define _FIREWIRE_PACKET_HEADER_DEFINITIONS_H +#include + #define ASYNC_HEADER_QUADLET_COUNT 4 #define ASYNC_HEADER_Q0_DESTINATION_SHIFT 16 diff --git a/drivers/firewire/packet-serdes-test.c b/drivers/firewire/packet-serdes-test.c index e83b1fece780..62ba433756ae 100644 --- a/drivers/firewire/packet-serdes-test.c +++ b/drivers/firewire/packet-serdes-test.c @@ -10,6 +10,7 @@ #include #include "packet-header-definitions.h" +#include "phy-packet-definitions.h" static void serialize_async_header_common(u32 header[ASYNC_HEADER_QUADLET_COUNT], unsigned int dst_id, unsigned int tlabel, @@ -187,6 +188,89 @@ static void deserialize_isoc_header(u32 header, unsigned int *data_length, unsig *sy = isoc_header_get_sy(header); } +static void serialize_phy_packet_self_id_zero(u32 *quadlet, unsigned int packet_identifier, + unsigned int phy_id, bool extended, + bool link_is_active, unsigned int gap_count, + unsigned int scode, bool is_contender, + unsigned int power_class, bool is_initiated_reset, + bool has_more_packets) +{ + phy_packet_set_packet_identifier(quadlet, packet_identifier); + phy_packet_self_id_set_phy_id(quadlet, phy_id); + phy_packet_self_id_set_extended(quadlet, extended); + phy_packet_self_id_zero_set_link_active(quadlet, link_is_active); + phy_packet_self_id_zero_set_gap_count(quadlet, gap_count); + phy_packet_self_id_zero_set_scode(quadlet, scode); + phy_packet_self_id_zero_set_contender(quadlet, is_contender); + phy_packet_self_id_zero_set_power_class(quadlet, power_class); + phy_packet_self_id_zero_set_initiated_reset(quadlet, is_initiated_reset); + phy_packet_self_id_set_more_packets(quadlet, has_more_packets); +} + +static void deserialize_phy_packet_self_id_zero(u32 quadlet, unsigned int *packet_identifier, + unsigned int *phy_id, bool *extended, + bool *link_is_active, unsigned int *gap_count, + unsigned int *scode, bool *is_contender, + unsigned int *power_class, + bool *is_initiated_reset, bool *has_more_packets) +{ + *packet_identifier = phy_packet_get_packet_identifier(quadlet); + *phy_id = phy_packet_self_id_get_phy_id(quadlet); + *extended = phy_packet_self_id_get_extended(quadlet); + *link_is_active = phy_packet_self_id_zero_get_link_active(quadlet); + *gap_count = phy_packet_self_id_zero_get_gap_count(quadlet); + *scode = phy_packet_self_id_zero_get_scode(quadlet); + *is_contender = phy_packet_self_id_zero_get_contender(quadlet); + *power_class = phy_packet_self_id_zero_get_power_class(quadlet); + *is_initiated_reset = phy_packet_self_id_zero_get_initiated_reset(quadlet); + *has_more_packets = phy_packet_self_id_get_more_packets(quadlet); +} + +static void serialize_phy_packet_self_id_extended(u32 *quadlet, unsigned int packet_identifier, + unsigned int phy_id, bool extended, + unsigned int sequence, bool has_more_packets) +{ + phy_packet_set_packet_identifier(quadlet, packet_identifier); + phy_packet_self_id_set_phy_id(quadlet, phy_id); + phy_packet_self_id_set_extended(quadlet, extended); + phy_packet_self_id_extended_set_sequence(quadlet, sequence); + phy_packet_self_id_set_more_packets(quadlet, has_more_packets); +} + +static void deserialize_phy_packet_self_id_extended(u32 quadlet, unsigned int *packet_identifier, + unsigned int *phy_id, bool *extended, + unsigned int *sequence, bool *has_more_packets) +{ + *packet_identifier = phy_packet_get_packet_identifier(quadlet); + *phy_id = phy_packet_self_id_get_phy_id(quadlet); + *extended = phy_packet_self_id_get_extended(quadlet); + *sequence = phy_packet_self_id_extended_get_sequence(quadlet); + *has_more_packets = phy_packet_self_id_get_more_packets(quadlet); +} + +static void serialize_phy_packet_phy_config(u32 *quadlet, unsigned int packet_identifier, + unsigned int root_id, bool has_force_root_node, + bool has_gap_count_optimization, unsigned int gap_count) +{ + phy_packet_set_packet_identifier(quadlet, packet_identifier); + phy_packet_phy_config_set_root_id(quadlet, root_id); + phy_packet_phy_config_set_force_root_node(quadlet, has_force_root_node); + phy_packet_phy_config_set_gap_count_optimization(quadlet, has_gap_count_optimization); + phy_packet_phy_config_set_gap_count(quadlet, gap_count); +} + +static void deserialize_phy_packet_phy_config(u32 quadlet, unsigned int *packet_identifier, + unsigned int *root_id, bool *has_force_root_node, + bool *has_gap_count_optimization, + unsigned int *gap_count) +{ + *packet_identifier = phy_packet_get_packet_identifier(quadlet); + *root_id = phy_packet_phy_config_get_root_id(quadlet); + *has_force_root_node = phy_packet_phy_config_get_force_root_node(quadlet); + *has_gap_count_optimization = phy_packet_phy_config_get_gap_count_optimization(quadlet); + *gap_count = phy_packet_phy_config_get_gap_count(quadlet); +} + static void test_async_header_write_quadlet_request(struct kunit *test) { static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { @@ -559,6 +643,251 @@ static void test_isoc_header(struct kunit *test) KUNIT_EXPECT_EQ(test, header, expected); } +static void test_phy_packet_self_id_zero_case0(struct kunit *test) +{ + // TSB41AB1/2 with 1 port. + const u32 expected[] = {0x80458c80}; + u32 quadlets[] = {0}; + + unsigned int packet_identifier; + unsigned int phy_id; + bool extended; + bool link_is_active; + unsigned int gap_count; + unsigned int scode; + bool is_contender; + unsigned int power_class; + enum phy_packet_self_id_port_status port_status[3]; + bool is_initiated_reset; + bool has_more_packets; + unsigned int port_index; + + deserialize_phy_packet_self_id_zero(expected[0], &packet_identifier, &phy_id, &extended, + &link_is_active, &gap_count, &scode, &is_contender, + &power_class, &is_initiated_reset, &has_more_packets); + + KUNIT_EXPECT_EQ(test, PHY_PACKET_PACKET_IDENTIFIER_SELF_ID, packet_identifier); + KUNIT_EXPECT_EQ(test, 0, phy_id); + KUNIT_EXPECT_FALSE(test, extended); + KUNIT_EXPECT_TRUE(test, link_is_active); + KUNIT_EXPECT_EQ(test, 0x05, gap_count); + KUNIT_EXPECT_EQ(test, SCODE_400, scode); + KUNIT_EXPECT_TRUE(test, is_contender); + KUNIT_EXPECT_EQ(test, 0x4, power_class); + KUNIT_EXPECT_FALSE(test, is_initiated_reset); + KUNIT_EXPECT_FALSE(test, has_more_packets); + + serialize_phy_packet_self_id_zero(quadlets, packet_identifier, phy_id, extended, + link_is_active, gap_count, scode, is_contender, + power_class, is_initiated_reset, has_more_packets); + + for (port_index = 0; port_index < ARRAY_SIZE(port_status); ++port_index) { + port_status[port_index] = + self_id_sequence_get_port_status(expected, ARRAY_SIZE(expected), port_index); + } + + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_PARENT, port_status[0]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[1]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[2]); + + for (port_index = 0; port_index < ARRAY_SIZE(port_status); ++port_index) { + self_id_sequence_set_port_status(quadlets, ARRAY_SIZE(quadlets), port_index, + port_status[port_index]); + } + + KUNIT_EXPECT_MEMEQ(test, quadlets, expected, sizeof(expected)); +} + +static void test_phy_packet_self_id_zero_case1(struct kunit *test) +{ + // XIO2213 and TSB81BA3E with 3 ports. + const u32 expected[] = {0x817fcc5e}; + u32 quadlets[] = {0}; + + unsigned int packet_identifier; + unsigned int phy_id; + bool extended; + bool link_is_active; + unsigned int gap_count; + unsigned int scode; + bool is_contender; + unsigned int power_class; + enum phy_packet_self_id_port_status port_status[3]; + bool is_initiated_reset; + bool has_more_packets; + unsigned int port_index; + + deserialize_phy_packet_self_id_zero(expected[0], &packet_identifier, &phy_id, &extended, + &link_is_active, &gap_count, &scode, &is_contender, + &power_class, &is_initiated_reset, &has_more_packets); + + KUNIT_EXPECT_EQ(test, PHY_PACKET_PACKET_IDENTIFIER_SELF_ID, packet_identifier); + KUNIT_EXPECT_EQ(test, 1, phy_id); + KUNIT_EXPECT_FALSE(test, extended); + KUNIT_EXPECT_TRUE(test, link_is_active); + KUNIT_EXPECT_EQ(test, 0x3f, gap_count); + KUNIT_EXPECT_EQ(test, SCODE_800, scode); + KUNIT_EXPECT_TRUE(test, is_contender); + KUNIT_EXPECT_EQ(test, 0x4, power_class); + KUNIT_EXPECT_TRUE(test, is_initiated_reset); + KUNIT_EXPECT_FALSE(test, has_more_packets); + + serialize_phy_packet_self_id_zero(quadlets, packet_identifier, phy_id, extended, + link_is_active, gap_count, scode, is_contender, + power_class, is_initiated_reset, has_more_packets); + + for (port_index = 0; port_index < ARRAY_SIZE(port_status); ++port_index) { + port_status[port_index] = + self_id_sequence_get_port_status(expected, ARRAY_SIZE(expected), port_index); + } + + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[0]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[1]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_CHILD, port_status[2]); + + for (port_index = 0; port_index < ARRAY_SIZE(port_status); ++port_index) { + self_id_sequence_set_port_status(quadlets, ARRAY_SIZE(quadlets), port_index, + port_status[port_index]); + } + + KUNIT_EXPECT_MEMEQ(test, quadlets, expected, sizeof(expected)); +} + +static void test_phy_packet_self_id_zero_and_one(struct kunit *test) +{ + // TSB41LV06A with 6 ports. + const u32 expected[] = { + 0x803f8459, + 0x80815000, + }; + u32 quadlets[] = {0, 0}; + + unsigned int packet_identifier; + unsigned int phy_id; + bool extended; + bool link_is_active; + unsigned int gap_count; + unsigned int scode; + bool is_contender; + unsigned int power_class; + enum phy_packet_self_id_port_status port_status[11]; + bool is_initiated_reset; + bool has_more_packets; + + unsigned int sequence; + unsigned int port_index; + + deserialize_phy_packet_self_id_zero(expected[0], &packet_identifier, &phy_id, &extended, + &link_is_active, &gap_count, &scode, &is_contender, + &power_class, &is_initiated_reset, &has_more_packets); + + KUNIT_EXPECT_EQ(test, PHY_PACKET_PACKET_IDENTIFIER_SELF_ID, packet_identifier); + KUNIT_EXPECT_EQ(test, 0, phy_id); + KUNIT_EXPECT_FALSE(test, extended); + KUNIT_EXPECT_FALSE(test, link_is_active); + KUNIT_EXPECT_EQ(test, 0x3f, gap_count); + KUNIT_EXPECT_EQ(test, SCODE_400, scode); + KUNIT_EXPECT_FALSE(test, is_contender); + KUNIT_EXPECT_EQ(test, 0x4, power_class); + KUNIT_EXPECT_FALSE(test, is_initiated_reset); + KUNIT_EXPECT_TRUE(test, has_more_packets); + + serialize_phy_packet_self_id_zero(quadlets, packet_identifier, phy_id, extended, + link_is_active, gap_count, scode, is_contender, + power_class, is_initiated_reset, has_more_packets); + + deserialize_phy_packet_self_id_extended(expected[1], &packet_identifier, &phy_id, &extended, + &sequence, &has_more_packets); + + KUNIT_EXPECT_EQ(test, PHY_PACKET_PACKET_IDENTIFIER_SELF_ID, packet_identifier); + KUNIT_EXPECT_EQ(test, 0, phy_id); + KUNIT_EXPECT_TRUE(test, extended); + KUNIT_EXPECT_EQ(test, 0, sequence); + KUNIT_EXPECT_FALSE(test, has_more_packets); + + serialize_phy_packet_self_id_extended(&quadlets[1], packet_identifier, phy_id, extended, + sequence, has_more_packets); + + + for (port_index = 0; port_index < ARRAY_SIZE(port_status); ++port_index) { + port_status[port_index] = + self_id_sequence_get_port_status(expected, ARRAY_SIZE(expected), port_index); + } + + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[0]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[1]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_PARENT, port_status[2]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[3]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[4]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[5]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[6]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[7]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[8]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[9]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[10]); + + for (port_index = 0; port_index < ARRAY_SIZE(port_status); ++port_index) { + self_id_sequence_set_port_status(quadlets, ARRAY_SIZE(quadlets), port_index, + port_status[port_index]); + } + + KUNIT_EXPECT_MEMEQ(test, quadlets, expected, sizeof(expected)); +} + +static void test_phy_packet_phy_config_force_root_node(struct kunit *test) +{ + const u32 expected = 0x02800000; + u32 quadlet = 0; + + unsigned int packet_identifier; + unsigned int root_id; + bool has_force_root_node; + bool has_gap_count_optimization; + unsigned int gap_count; + + deserialize_phy_packet_phy_config(expected, &packet_identifier, &root_id, + &has_force_root_node, &has_gap_count_optimization, + &gap_count); + + KUNIT_EXPECT_EQ(test, PHY_PACKET_PACKET_IDENTIFIER_PHY_CONFIG, packet_identifier); + KUNIT_EXPECT_EQ(test, 0x02, root_id); + KUNIT_EXPECT_TRUE(test, has_force_root_node); + KUNIT_EXPECT_FALSE(test, has_gap_count_optimization); + KUNIT_EXPECT_EQ(test, 0, gap_count); + + serialize_phy_packet_phy_config(&quadlet, packet_identifier, root_id, has_force_root_node, + has_gap_count_optimization, gap_count); + + KUNIT_EXPECT_EQ(test, quadlet, expected); +} + +static void test_phy_packet_phy_config_gap_count_optimization(struct kunit *test) +{ + const u32 expected = 0x034f0000; + u32 quadlet = 0; + + unsigned int packet_identifier; + unsigned int root_id; + bool has_force_root_node; + bool has_gap_count_optimization; + unsigned int gap_count; + + deserialize_phy_packet_phy_config(expected, &packet_identifier, &root_id, + &has_force_root_node, &has_gap_count_optimization, + &gap_count); + + KUNIT_EXPECT_EQ(test, PHY_PACKET_PACKET_IDENTIFIER_PHY_CONFIG, packet_identifier); + KUNIT_EXPECT_EQ(test, 0x03, root_id); + KUNIT_EXPECT_FALSE(test, has_force_root_node); + KUNIT_EXPECT_TRUE(test, has_gap_count_optimization); + KUNIT_EXPECT_EQ(test, 0x0f, gap_count); + + serialize_phy_packet_phy_config(&quadlet, packet_identifier, root_id, has_force_root_node, + has_gap_count_optimization, gap_count); + + KUNIT_EXPECT_EQ(test, quadlet, expected); +} + static struct kunit_case packet_serdes_test_cases[] = { KUNIT_CASE(test_async_header_write_quadlet_request), KUNIT_CASE(test_async_header_write_block_request), @@ -570,6 +899,11 @@ static struct kunit_case packet_serdes_test_cases[] = { KUNIT_CASE(test_async_header_lock_request), KUNIT_CASE(test_async_header_lock_response), KUNIT_CASE(test_isoc_header), + KUNIT_CASE(test_phy_packet_self_id_zero_case0), + KUNIT_CASE(test_phy_packet_self_id_zero_case1), + KUNIT_CASE(test_phy_packet_self_id_zero_and_one), + KUNIT_CASE(test_phy_packet_phy_config_force_root_node), + KUNIT_CASE(test_phy_packet_phy_config_gap_count_optimization), {} }; diff --git a/drivers/firewire/phy-packet-definitions.h b/drivers/firewire/phy-packet-definitions.h new file mode 100644 index 000000000000..03c7c606759f --- /dev/null +++ b/drivers/firewire/phy-packet-definitions.h @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// phy-packet-definitions.h - The definitions of phy packet for IEEE 1394. +// +// Copyright (c) 2024 Takashi Sakamoto + +#ifndef _FIREWIRE_PHY_PACKET_DEFINITIONS_H +#define _FIREWIRE_PHY_PACKET_DEFINITIONS_H + +#define PACKET_IDENTIFIER_MASK 0xc0000000 +#define PACKET_IDENTIFIER_SHIFT 30 + +static inline unsigned int phy_packet_get_packet_identifier(u32 quadlet) +{ + return (quadlet & PACKET_IDENTIFIER_MASK) >> PACKET_IDENTIFIER_SHIFT; +} + +static inline void phy_packet_set_packet_identifier(u32 *quadlet, unsigned int packet_identifier) +{ + *quadlet &= ~PACKET_IDENTIFIER_MASK; + *quadlet |= (packet_identifier << PACKET_IDENTIFIER_SHIFT) & PACKET_IDENTIFIER_MASK; +} + +#define PHY_PACKET_PACKET_IDENTIFIER_PHY_CONFIG 0 + +#define PHY_CONFIG_ROOT_ID_MASK 0x3f000000 +#define PHY_CONFIG_ROOT_ID_SHIFT 24 +#define PHY_CONFIG_FORCE_ROOT_NODE_MASK 0x00800000 +#define PHY_CONFIG_FORCE_ROOT_NODE_SHIFT 23 +#define PHY_CONFIG_GAP_COUNT_OPTIMIZATION_MASK 0x00400000 +#define PHY_CONFIG_GAP_COUNT_OPTIMIZATION_SHIFT 22 +#define PHY_CONFIG_GAP_COUNT_MASK 0x003f0000 +#define PHY_CONFIG_GAP_COUNT_SHIFT 16 + +static inline unsigned int phy_packet_phy_config_get_root_id(u32 quadlet) +{ + return (quadlet & PHY_CONFIG_ROOT_ID_MASK) >> PHY_CONFIG_ROOT_ID_SHIFT; +} + +static inline void phy_packet_phy_config_set_root_id(u32 *quadlet, unsigned int root_id) +{ + *quadlet &= ~PHY_CONFIG_ROOT_ID_MASK; + *quadlet |= (root_id << PHY_CONFIG_ROOT_ID_SHIFT) & PHY_CONFIG_ROOT_ID_MASK; +} + +static inline bool phy_packet_phy_config_get_force_root_node(u32 quadlet) +{ + return (quadlet & PHY_CONFIG_FORCE_ROOT_NODE_MASK) >> PHY_CONFIG_FORCE_ROOT_NODE_SHIFT; +} + +static inline void phy_packet_phy_config_set_force_root_node(u32 *quadlet, bool has_force_root_node) +{ + *quadlet &= ~PHY_CONFIG_FORCE_ROOT_NODE_MASK; + *quadlet |= (has_force_root_node << PHY_CONFIG_FORCE_ROOT_NODE_SHIFT) & PHY_CONFIG_FORCE_ROOT_NODE_MASK; +} + +static inline bool phy_packet_phy_config_get_gap_count_optimization(u32 quadlet) +{ + return (quadlet & PHY_CONFIG_GAP_COUNT_OPTIMIZATION_MASK) >> PHY_CONFIG_GAP_COUNT_OPTIMIZATION_SHIFT; +} + +static inline void phy_packet_phy_config_set_gap_count_optimization(u32 *quadlet, bool has_gap_count_optimization) +{ + *quadlet &= ~PHY_CONFIG_GAP_COUNT_OPTIMIZATION_MASK; + *quadlet |= (has_gap_count_optimization << PHY_CONFIG_GAP_COUNT_OPTIMIZATION_SHIFT) & PHY_CONFIG_GAP_COUNT_OPTIMIZATION_MASK; +} + +static inline unsigned int phy_packet_phy_config_get_gap_count(u32 quadlet) +{ + return (quadlet & PHY_CONFIG_GAP_COUNT_MASK) >> PHY_CONFIG_GAP_COUNT_SHIFT; +} + +static inline void phy_packet_phy_config_set_gap_count(u32 *quadlet, unsigned int gap_count) +{ + *quadlet &= ~PHY_CONFIG_GAP_COUNT_MASK; + *quadlet |= (gap_count << PHY_CONFIG_GAP_COUNT_SHIFT) & PHY_CONFIG_GAP_COUNT_MASK; +} + +#define PHY_PACKET_PACKET_IDENTIFIER_SELF_ID 2 + +#define SELF_ID_PHY_ID_MASK 0x3f000000 +#define SELF_ID_PHY_ID_SHIFT 24 +#define SELF_ID_EXTENDED_MASK 0x00800000 +#define SELF_ID_EXTENDED_SHIFT 23 +#define SELF_ID_MORE_PACKETS_MASK 0x00000001 +#define SELF_ID_MORE_PACKETS_SHIFT 0 + +#define SELF_ID_ZERO_LINK_ACTIVE_MASK 0x00400000 +#define SELF_ID_ZERO_LINK_ACTIVE_SHIFT 22 +#define SELF_ID_ZERO_GAP_COUNT_MASK 0x003f0000 +#define SELF_ID_ZERO_GAP_COUNT_SHIFT 16 +#define SELF_ID_ZERO_SCODE_MASK 0x0000c000 +#define SELF_ID_ZERO_SCODE_SHIFT 14 +#define SELF_ID_ZERO_CONTENDER_MASK 0x00000800 +#define SELF_ID_ZERO_CONTENDER_SHIFT 11 +#define SELF_ID_ZERO_POWER_CLASS_MASK 0x00000700 +#define SELF_ID_ZERO_POWER_CLASS_SHIFT 8 +#define SELF_ID_ZERO_INITIATED_RESET_MASK 0x00000002 +#define SELF_ID_ZERO_INITIATED_RESET_SHIFT 1 + +#define SELF_ID_EXTENDED_SEQUENCE_MASK 0x00700000 +#define SELF_ID_EXTENDED_SEQUENCE_SHIFT 20 + +#define SELF_ID_PORT_STATUS_MASK 0x3 + +#define SELF_ID_SEQUENCE_MAXIMUM_QUADLET_COUNT 4 + +static inline unsigned int phy_packet_self_id_get_phy_id(u32 quadlet) +{ + return (quadlet & SELF_ID_PHY_ID_MASK) >> SELF_ID_PHY_ID_SHIFT; +} + +static inline void phy_packet_self_id_set_phy_id(u32 *quadlet, unsigned int phy_id) +{ + *quadlet &= ~SELF_ID_PHY_ID_MASK; + *quadlet |= (phy_id << SELF_ID_PHY_ID_SHIFT) & SELF_ID_PHY_ID_MASK; +} + +static inline bool phy_packet_self_id_get_extended(u32 quadlet) +{ + return (quadlet & SELF_ID_EXTENDED_MASK) >> SELF_ID_EXTENDED_SHIFT; +} + +static inline void phy_packet_self_id_set_extended(u32 *quadlet, bool extended) +{ + *quadlet &= ~SELF_ID_EXTENDED_MASK; + *quadlet |= (extended << SELF_ID_EXTENDED_SHIFT) & SELF_ID_EXTENDED_MASK; +} + +static inline bool phy_packet_self_id_zero_get_link_active(u32 quadlet) +{ + return (quadlet & SELF_ID_ZERO_LINK_ACTIVE_MASK) >> SELF_ID_ZERO_LINK_ACTIVE_SHIFT; +} + +static inline void phy_packet_self_id_zero_set_link_active(u32 *quadlet, bool is_active) +{ + *quadlet &= ~SELF_ID_ZERO_LINK_ACTIVE_MASK; + *quadlet |= (is_active << SELF_ID_ZERO_LINK_ACTIVE_SHIFT) & SELF_ID_ZERO_LINK_ACTIVE_MASK; +} + +static inline unsigned int phy_packet_self_id_zero_get_gap_count(u32 quadlet) +{ + return (quadlet & SELF_ID_ZERO_GAP_COUNT_MASK) >> SELF_ID_ZERO_GAP_COUNT_SHIFT; +} + +static inline void phy_packet_self_id_zero_set_gap_count(u32 *quadlet, unsigned int gap_count) +{ + *quadlet &= ~SELF_ID_ZERO_GAP_COUNT_MASK; + *quadlet |= (gap_count << SELF_ID_ZERO_GAP_COUNT_SHIFT) & SELF_ID_ZERO_GAP_COUNT_MASK; +} + +static inline unsigned int phy_packet_self_id_zero_get_scode(u32 quadlet) +{ + return (quadlet & SELF_ID_ZERO_SCODE_MASK) >> SELF_ID_ZERO_SCODE_SHIFT; +} + +static inline void phy_packet_self_id_zero_set_scode(u32 *quadlet, unsigned int speed) +{ + *quadlet &= ~SELF_ID_ZERO_SCODE_MASK; + *quadlet |= (speed << SELF_ID_ZERO_SCODE_SHIFT) & SELF_ID_ZERO_SCODE_MASK; +} + +static inline bool phy_packet_self_id_zero_get_contender(u32 quadlet) +{ + return (quadlet & SELF_ID_ZERO_CONTENDER_MASK) >> SELF_ID_ZERO_CONTENDER_SHIFT; +} + +static inline void phy_packet_self_id_zero_set_contender(u32 *quadlet, bool is_contender) +{ + *quadlet &= ~SELF_ID_ZERO_CONTENDER_MASK; + *quadlet |= (is_contender << SELF_ID_ZERO_CONTENDER_SHIFT) & SELF_ID_ZERO_CONTENDER_MASK; +} + +static inline unsigned int phy_packet_self_id_zero_get_power_class(u32 quadlet) +{ + return (quadlet & SELF_ID_ZERO_POWER_CLASS_MASK) >> SELF_ID_ZERO_POWER_CLASS_SHIFT; +} + +static inline void phy_packet_self_id_zero_set_power_class(u32 *quadlet, unsigned int power_class) +{ + *quadlet &= ~SELF_ID_ZERO_POWER_CLASS_MASK; + *quadlet |= (power_class << SELF_ID_ZERO_POWER_CLASS_SHIFT) & SELF_ID_ZERO_POWER_CLASS_MASK; +} + +static inline bool phy_packet_self_id_zero_get_initiated_reset(u32 quadlet) +{ + return (quadlet & SELF_ID_ZERO_INITIATED_RESET_MASK) >> SELF_ID_ZERO_INITIATED_RESET_SHIFT; +} + +static inline void phy_packet_self_id_zero_set_initiated_reset(u32 *quadlet, bool is_initiated_reset) +{ + *quadlet &= ~SELF_ID_ZERO_INITIATED_RESET_MASK; + *quadlet |= (is_initiated_reset << SELF_ID_ZERO_INITIATED_RESET_SHIFT) & SELF_ID_ZERO_INITIATED_RESET_MASK; +} + +static inline bool phy_packet_self_id_get_more_packets(u32 quadlet) +{ + return (quadlet & SELF_ID_MORE_PACKETS_MASK) >> SELF_ID_MORE_PACKETS_SHIFT; +} + +static inline void phy_packet_self_id_set_more_packets(u32 *quadlet, bool is_more_packets) +{ + *quadlet &= ~SELF_ID_MORE_PACKETS_MASK; + *quadlet |= (is_more_packets << SELF_ID_MORE_PACKETS_SHIFT) & SELF_ID_MORE_PACKETS_MASK; +} + +static inline unsigned int phy_packet_self_id_extended_get_sequence(u32 quadlet) +{ + return (quadlet & SELF_ID_EXTENDED_SEQUENCE_MASK) >> SELF_ID_EXTENDED_SEQUENCE_SHIFT; +} + +static inline void phy_packet_self_id_extended_set_sequence(u32 *quadlet, unsigned int sequence) +{ + *quadlet &= ~SELF_ID_EXTENDED_SEQUENCE_MASK; + *quadlet |= (sequence << SELF_ID_EXTENDED_SHIFT) & SELF_ID_EXTENDED_SEQUENCE_MASK; +} + +struct self_id_sequence_enumerator { + const u32 *cursor; + unsigned int quadlet_count; +}; + +static inline const u32 *self_id_sequence_enumerator_next( + struct self_id_sequence_enumerator *enumerator, unsigned int *quadlet_count) +{ + const u32 *self_id_sequence, *cursor; + u32 quadlet; + unsigned int count; + unsigned int sequence; + + if (enumerator->cursor == NULL || enumerator->quadlet_count == 0) + return ERR_PTR(-ENODATA); + cursor = enumerator->cursor; + count = 1; + + quadlet = *cursor; + sequence = 0; + while (phy_packet_self_id_get_more_packets(quadlet)) { + if (count >= enumerator->quadlet_count || + count >= SELF_ID_SEQUENCE_MAXIMUM_QUADLET_COUNT) + return ERR_PTR(-EPROTO); + ++cursor; + ++count; + quadlet = *cursor; + + if (!phy_packet_self_id_get_extended(quadlet) || + sequence != phy_packet_self_id_extended_get_sequence(quadlet)) + return ERR_PTR(-EPROTO); + ++sequence; + } + + *quadlet_count = count; + self_id_sequence = enumerator->cursor; + + enumerator->cursor += count; + enumerator->quadlet_count -= count; + + return self_id_sequence; +} + +enum phy_packet_self_id_port_status { + PHY_PACKET_SELF_ID_PORT_STATUS_NONE = 0, + PHY_PACKET_SELF_ID_PORT_STATUS_NCONN = 1, + PHY_PACKET_SELF_ID_PORT_STATUS_PARENT = 2, + PHY_PACKET_SELF_ID_PORT_STATUS_CHILD = 3, +}; + +static inline unsigned int self_id_sequence_get_port_capacity(unsigned int quadlet_count) +{ + return quadlet_count * 8 - 5; +} + +static inline enum phy_packet_self_id_port_status self_id_sequence_get_port_status( + const u32 *self_id_sequence, unsigned int quadlet_count, unsigned int port_index) +{ + unsigned int index, shift; + + index = (port_index + 5) / 8; + shift = 16 - ((port_index + 5) % 8) * 2; + + if (index < quadlet_count && index < SELF_ID_SEQUENCE_MAXIMUM_QUADLET_COUNT) + return (self_id_sequence[index] >> shift) & SELF_ID_PORT_STATUS_MASK; + + return PHY_PACKET_SELF_ID_PORT_STATUS_NONE; +} + +static inline void self_id_sequence_set_port_status(u32 *self_id_sequence, unsigned int quadlet_count, + unsigned int port_index, + enum phy_packet_self_id_port_status status) +{ + unsigned int index, shift; + + index = (port_index + 5) / 8; + shift = 16 - ((port_index + 5) % 8) * 2; + + if (index < quadlet_count) { + self_id_sequence[index] &= ~(SELF_ID_PORT_STATUS_MASK << shift); + self_id_sequence[index] |= status << shift; + } +} + +#endif // _FIREWIRE_PHY_PACKET_DEFINITIONS_H diff --git a/drivers/firewire/self-id-sequence-helper-test.c b/drivers/firewire/self-id-sequence-helper-test.c new file mode 100644 index 000000000000..eed7a2294e64 --- /dev/null +++ b/drivers/firewire/self-id-sequence-helper-test.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// self-id-sequence-helper-test.c - An application of Kunit to test helpers of self ID sequence. +// +// Copyright (c) 2024 Takashi Sakamoto + +#include + +#include "phy-packet-definitions.h" + +static void test_self_id_sequence_enumerator_valid(struct kunit *test) +{ + static const u32 valid_sequences[] = { + 0x00000000, + 0x00000001, 0x00800000, + 0x00000001, 0x00800001, 0x00900000, + 0x00000000, + }; + struct self_id_sequence_enumerator enumerator; + const u32 *entry; + unsigned int quadlet_count; + + enumerator.cursor = valid_sequences; + enumerator.quadlet_count = ARRAY_SIZE(valid_sequences); + + entry = self_id_sequence_enumerator_next(&enumerator, &quadlet_count); + KUNIT_EXPECT_PTR_EQ(test, entry, &valid_sequences[0]); + KUNIT_EXPECT_EQ(test, quadlet_count, 1); + KUNIT_EXPECT_EQ(test, enumerator.quadlet_count, 6); + + entry = self_id_sequence_enumerator_next(&enumerator, &quadlet_count); + KUNIT_EXPECT_PTR_EQ(test, entry, &valid_sequences[1]); + KUNIT_EXPECT_EQ(test, quadlet_count, 2); + KUNIT_EXPECT_EQ(test, enumerator.quadlet_count, 4); + + entry = self_id_sequence_enumerator_next(&enumerator, &quadlet_count); + KUNIT_EXPECT_PTR_EQ(test, entry, &valid_sequences[3]); + KUNIT_EXPECT_EQ(test, quadlet_count, 3); + KUNIT_EXPECT_EQ(test, enumerator.quadlet_count, 1); + + entry = self_id_sequence_enumerator_next(&enumerator, &quadlet_count); + KUNIT_EXPECT_PTR_EQ(test, entry, &valid_sequences[6]); + KUNIT_EXPECT_EQ(test, quadlet_count, 1); + KUNIT_EXPECT_EQ(test, enumerator.quadlet_count, 0); + + entry = self_id_sequence_enumerator_next(&enumerator, &quadlet_count); + KUNIT_EXPECT_EQ(test, PTR_ERR(entry), -ENODATA); +} + +static void test_self_id_sequence_enumerator_invalid(struct kunit *test) +{ + static const u32 invalid_sequences[] = { + 0x00000001, + }; + struct self_id_sequence_enumerator enumerator; + const u32 *entry; + unsigned int count; + + enumerator.cursor = invalid_sequences; + enumerator.quadlet_count = ARRAY_SIZE(invalid_sequences); + + entry = self_id_sequence_enumerator_next(&enumerator, &count); + KUNIT_EXPECT_EQ(test, PTR_ERR(entry), -EPROTO); +} + +static void test_self_id_sequence_get_port_status(struct kunit *test) +{ + static const u32 expected[] = { + 0x000000e5, + 0x00839e79, + 0x0091e79d, + 0x00a279e4, + }; + u32 quadlets [] = { + 0x00000001, + 0x00800001, + 0x00900001, + 0x00a00000, + }; + enum phy_packet_self_id_port_status port_status[28]; + unsigned int port_capacity; + unsigned int port_index; + + KUNIT_ASSERT_EQ(test, ARRAY_SIZE(expected), ARRAY_SIZE(quadlets)); + + // With an extra port. + port_capacity = self_id_sequence_get_port_capacity(ARRAY_SIZE(expected)) + 1; + KUNIT_ASSERT_EQ(test, port_capacity, ARRAY_SIZE(port_status)); + + for (port_index = 0; port_index < port_capacity; ++port_index) { + port_status[port_index] = + self_id_sequence_get_port_status(expected, ARRAY_SIZE(expected), port_index); + self_id_sequence_set_port_status(quadlets, ARRAY_SIZE(quadlets), port_index, + port_status[port_index]); + } + + // Self ID zero. + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_CHILD, port_status[0]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_PARENT, port_status[1]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[2]); + + // Self ID one. + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_CHILD, port_status[3]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_PARENT, port_status[4]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[5]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_CHILD, port_status[6]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_PARENT, port_status[7]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[8]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_CHILD, port_status[9]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_PARENT, port_status[10]); + + // Self ID two. + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[11]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_CHILD, port_status[12]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_PARENT, port_status[13]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[14]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_CHILD, port_status[15]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_PARENT, port_status[16]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[17]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_CHILD, port_status[18]); + + // Self ID three. + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_PARENT, port_status[19]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[20]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_CHILD, port_status[21]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_PARENT, port_status[22]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[23]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_CHILD, port_status[24]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_PARENT, port_status[25]); + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NCONN, port_status[26]); + + // Our of order. + KUNIT_EXPECT_EQ(test, PHY_PACKET_SELF_ID_PORT_STATUS_NONE, port_status[27]); + + KUNIT_EXPECT_MEMEQ(test, quadlets, expected, sizeof(expected)); +} + +static struct kunit_case self_id_sequence_helper_test_cases[] = { + KUNIT_CASE(test_self_id_sequence_enumerator_valid), + KUNIT_CASE(test_self_id_sequence_enumerator_invalid), + KUNIT_CASE(test_self_id_sequence_get_port_status), + {} +}; + +static struct kunit_suite self_id_sequence_helper_test_suite = { + .name = "self-id-sequence-helper", + .test_cases = self_id_sequence_helper_test_cases, +}; +kunit_test_suite(self_id_sequence_helper_test_suite); + +MODULE_DESCRIPTION("Unit test suite for helpers of self ID sequence"); +MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/efi/riscv-runtime.c b/drivers/firmware/efi/riscv-runtime.c index 01f0f90ea418..fa71cd898120 100644 --- a/drivers/firmware/efi/riscv-runtime.c +++ b/drivers/firmware/efi/riscv-runtime.c @@ -152,3 +152,16 @@ void arch_efi_call_virt_teardown(void) { efi_virtmap_unload(); } + +static int __init riscv_dmi_init(void) +{ + /* + * On riscv, DMI depends on UEFI, and dmi_setup() needs to + * be called early because dmi_id_init(), which is an arch_initcall + * itself, depends on dmi_scan_machine() having been called already. + */ + dmi_setup(); + + return 0; +} +core_initcall(riscv_dmi_init); diff --git a/drivers/macintosh/ams/ams-i2c.c b/drivers/macintosh/ams/ams-i2c.c index f9bfe84b1c73..d5cdbba6e7c7 100644 --- a/drivers/macintosh/ams/ams-i2c.c +++ b/drivers/macintosh/ams/ams-i2c.c @@ -60,7 +60,7 @@ static int ams_i2c_probe(struct i2c_client *client); static void ams_i2c_remove(struct i2c_client *client); static const struct i2c_device_id ams_id[] = { - { "MAC,accelerometer_1", 0 }, + { "MAC,accelerometer_1" }, { } }; MODULE_DEVICE_TABLE(i2c, ams_id); diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c index 1ae3539beff5..b7b3ef1e58dc 100644 --- a/drivers/macintosh/mac_hid.c +++ b/drivers/macintosh/mac_hid.c @@ -16,6 +16,7 @@ #include #include +MODULE_DESCRIPTION("Mouse button 2+3 emulation"); MODULE_LICENSE("GPL"); static int mouse_emulate_buttons; diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 37cdc6931f6d..2576a53f247e 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -549,7 +549,7 @@ g4fan_exit( void ) platform_driver_unregister( &therm_of_driver ); if( x.of_dev ) - of_device_unregister( x.of_dev ); + of_platform_device_destroy(&x.of_dev->dev, NULL); } module_init(g4fan_init); diff --git a/drivers/macintosh/windfarm_ad7417_sensor.c b/drivers/macintosh/windfarm_ad7417_sensor.c index 49ce37fde930..3ff4577ba847 100644 --- a/drivers/macintosh/windfarm_ad7417_sensor.c +++ b/drivers/macintosh/windfarm_ad7417_sensor.c @@ -304,7 +304,7 @@ static void wf_ad7417_remove(struct i2c_client *client) } static const struct i2c_device_id wf_ad7417_id[] = { - { "MAC,ad7417", 0 }, + { "MAC,ad7417" }, { } }; MODULE_DEVICE_TABLE(i2c, wf_ad7417_id); diff --git a/drivers/macintosh/windfarm_fcu_controls.c b/drivers/macintosh/windfarm_fcu_controls.c index 603ef6c600ba..82365f19adb4 100644 --- a/drivers/macintosh/windfarm_fcu_controls.c +++ b/drivers/macintosh/windfarm_fcu_controls.c @@ -573,7 +573,7 @@ static void wf_fcu_remove(struct i2c_client *client) } static const struct i2c_device_id wf_fcu_id[] = { - { "MAC,fcu", 0 }, + { "MAC,fcu" }, { } }; MODULE_DEVICE_TABLE(i2c, wf_fcu_id); diff --git a/drivers/macintosh/windfarm_lm87_sensor.c b/drivers/macintosh/windfarm_lm87_sensor.c index 975361c23a93..16635e2b180b 100644 --- a/drivers/macintosh/windfarm_lm87_sensor.c +++ b/drivers/macintosh/windfarm_lm87_sensor.c @@ -156,7 +156,7 @@ static void wf_lm87_remove(struct i2c_client *client) } static const struct i2c_device_id wf_lm87_id[] = { - { "MAC,lm87cimt", 0 }, + { "MAC,lm87cimt" }, { } }; MODULE_DEVICE_TABLE(i2c, wf_lm87_id); diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index 02856d1f0313..d734b31b8236 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c @@ -112,7 +112,7 @@ static void wf_max6690_remove(struct i2c_client *client) } static const struct i2c_device_id wf_max6690_id[] = { - { "MAC,max6690", 0 }, + { "MAC,max6690" }, { } }; MODULE_DEVICE_TABLE(i2c, wf_max6690_id); diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index 50baa062c9df..ff8805ecf2e5 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -333,7 +333,7 @@ static void wf_sat_remove(struct i2c_client *client) } static const struct i2c_device_id wf_sat_id[] = { - { "MAC,smu-sat", 0 }, + { "MAC,smu-sat" }, { } }; MODULE_DEVICE_TABLE(i2c, wf_sat_id); diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 60c7f6f751c7..5e5266e2c2e1 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -1399,4 +1399,5 @@ static void cfi_staa_destroy(struct mtd_info *mtd) kfree(cfi); } +MODULE_DESCRIPTION("MTD chip driver for ST Advanced Architecture Command Set (ID 0x0020)"); MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index 140c69a67e82..ef0aa6890bc0 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c @@ -441,4 +441,5 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, EXPORT_SYMBOL(cfi_varsize_frob); +MODULE_DESCRIPTION("Common Flash Interface Generic utility functions"); MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index a9083c888e3b..019f1e92cc41 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -17,13 +17,12 @@ obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o -physmap-objs-y += physmap-core.o -physmap-objs-$(CONFIG_MTD_PHYSMAP_BT1_ROM) += physmap-bt1-rom.o -physmap-objs-$(CONFIG_MTD_PHYSMAP_VERSATILE) += physmap-versatile.o -physmap-objs-$(CONFIG_MTD_PHYSMAP_GEMINI) += physmap-gemini.o -physmap-objs-$(CONFIG_MTD_PHYSMAP_IXP4XX) += physmap-ixp4xx.o -physmap-objs := $(physmap-objs-y) obj-$(CONFIG_MTD_PHYSMAP) += physmap.o +physmap-y := physmap-core.o +physmap-$(CONFIG_MTD_PHYSMAP_BT1_ROM) += physmap-bt1-rom.o +physmap-$(CONFIG_MTD_PHYSMAP_VERSATILE) += physmap-versatile.o +physmap-$(CONFIG_MTD_PHYSMAP_GEMINI) += physmap-gemini.o +physmap-$(CONFIG_MTD_PHYSMAP_IXP4XX) += physmap-ixp4xx.o obj-$(CONFIG_MTD_PISMO) += pismo.o obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o diff --git a/drivers/mtd/maps/map_funcs.c b/drivers/mtd/maps/map_funcs.c index 5b684c170d4e..1a4add9e119a 100644 --- a/drivers/mtd/maps/map_funcs.c +++ b/drivers/mtd/maps/map_funcs.c @@ -41,4 +41,5 @@ void simple_map_init(struct map_info *map) } EXPORT_SYMBOL(simple_map_init); +MODULE_DESCRIPTION("Out-of-line map I/O"); MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c index 04f84d87c657..ff92c17def83 100644 --- a/drivers/mtd/nand/raw/cadence-nand-controller.c +++ b/drivers/mtd/nand/raw/cadence-nand-controller.c @@ -531,11 +531,6 @@ struct cdns_nand_chip { u8 cs[] __counted_by(nsels); }; -struct ecc_info { - int (*calc_ecc_bytes)(int step_size, int strength); - int max_step_size; -}; - static inline struct cdns_nand_chip *to_cdns_nand_chip(struct nand_chip *chip) { diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index e71ad2fcec23..e1b515304e3c 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -983,7 +983,7 @@ static int gpmi_setup_interface(struct nand_chip *chip, int chipnr, return PTR_ERR(sdr); /* Only MX28/MX6 GPMI controller can reach EDO timings */ - if (sdr->tRC_min <= 25000 && !GPMI_IS_MX28(this) && !GPMI_IS_MX6(this)) + if (sdr->tRC_min <= 25000 && !this->devdata->support_edo_timing) return -ENOTSUPP; /* Stop here if this call was just a check */ @@ -1142,6 +1142,7 @@ static const struct gpmi_devdata gpmi_devdata_imx28 = { .type = IS_MX28, .bch_max_ecc_strength = 20, .max_chain_delay = 16000, + .support_edo_timing = true, .clks = gpmi_clks_for_mx2x, .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x), }; @@ -1154,6 +1155,7 @@ static const struct gpmi_devdata gpmi_devdata_imx6q = { .type = IS_MX6Q, .bch_max_ecc_strength = 40, .max_chain_delay = 12000, + .support_edo_timing = true, .clks = gpmi_clks_for_mx6, .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6), }; @@ -1162,6 +1164,7 @@ static const struct gpmi_devdata gpmi_devdata_imx6sx = { .type = IS_MX6SX, .bch_max_ecc_strength = 62, .max_chain_delay = 12000, + .support_edo_timing = true, .clks = gpmi_clks_for_mx6, .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6), }; @@ -1174,10 +1177,24 @@ static const struct gpmi_devdata gpmi_devdata_imx7d = { .type = IS_MX7D, .bch_max_ecc_strength = 62, .max_chain_delay = 12000, + .support_edo_timing = true, .clks = gpmi_clks_for_mx7d, .clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d), }; +static const char *gpmi_clks_for_mx8qxp[GPMI_CLK_MAX] = { + "gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", +}; + +static const struct gpmi_devdata gpmi_devdata_imx8qxp = { + .type = IS_MX8QXP, + .bch_max_ecc_strength = 62, + .max_chain_delay = 12000, + .support_edo_timing = true, + .clks = gpmi_clks_for_mx8qxp, + .clks_count = ARRAY_SIZE(gpmi_clks_for_mx8qxp), +}; + static int acquire_register_block(struct gpmi_nand_data *this, const char *res_name) { @@ -2721,6 +2738,7 @@ static const struct of_device_id gpmi_nand_id_table[] = { { .compatible = "fsl,imx6q-gpmi-nand", .data = &gpmi_devdata_imx6q, }, { .compatible = "fsl,imx6sx-gpmi-nand", .data = &gpmi_devdata_imx6sx, }, { .compatible = "fsl,imx7d-gpmi-nand", .data = &gpmi_devdata_imx7d,}, + { .compatible = "fsl,imx8qxp-gpmi-nand", .data = &gpmi_devdata_imx8qxp, }, {} }; MODULE_DEVICE_TABLE(of, gpmi_nand_id_table); diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h index c3ff56ac62a7..3e9bc985e44a 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h @@ -78,6 +78,7 @@ enum gpmi_type { IS_MX6Q, IS_MX6SX, IS_MX7D, + IS_MX8QXP, }; struct gpmi_devdata { @@ -86,6 +87,7 @@ struct gpmi_devdata { int max_chain_delay; /* See the SDR EDO mode */ const char * const *clks; const int clks_count; + bool support_edo_timing; }; /** @@ -172,8 +174,10 @@ struct gpmi_nand_data { #define GPMI_IS_MX6Q(x) ((x)->devdata->type == IS_MX6Q) #define GPMI_IS_MX6SX(x) ((x)->devdata->type == IS_MX6SX) #define GPMI_IS_MX7D(x) ((x)->devdata->type == IS_MX7D) +#define GPMI_IS_MX8QXP(x) ((x)->devdata->type == IS_MX8QXP) #define GPMI_IS_MX6(x) (GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x) || \ - GPMI_IS_MX7D(x)) + GPMI_IS_MX7D(x) || GPMI_IS_MX8QXP(x)) + #define GPMI_IS_MXS(x) (GPMI_IS_MX23(x) || GPMI_IS_MX28(x)) #endif diff --git a/drivers/mtd/nand/raw/intel-nand-controller.c b/drivers/mtd/nand/raw/intel-nand-controller.c index f0ad2308f6d5..78174c463b36 100644 --- a/drivers/mtd/nand/raw/intel-nand-controller.c +++ b/drivers/mtd/nand/raw/intel-nand-controller.c @@ -295,7 +295,7 @@ static int ebu_dma_start(struct ebu_nand_controller *ebu_host, u32 dir, unsigned long flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; dma_addr_t buf_dma; int ret; - u32 timeout; + unsigned long time_left; if (dir == DMA_DEV_TO_MEM) { chan = ebu_host->dma_rx; @@ -335,8 +335,8 @@ static int ebu_dma_start(struct ebu_nand_controller *ebu_host, u32 dir, dma_async_issue_pending(chan); /* Wait DMA to finish the data transfer.*/ - timeout = wait_for_completion_timeout(dma_completion, msecs_to_jiffies(1000)); - if (!timeout) { + time_left = wait_for_completion_timeout(dma_completion, msecs_to_jiffies(1000)); + if (!time_left) { dev_err(ebu_host->dev, "I/O Error in DMA RX (status %d)\n", dmaengine_tx_status(chan, cookie, NULL)); dmaengine_terminate_sync(chan); diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c index 677fcb03f9be..b9c3adc54c01 100644 --- a/drivers/mtd/nand/raw/lpc32xx_mlc.c +++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c @@ -574,18 +574,22 @@ static int lpc32xx_dma_setup(struct lpc32xx_nand_host *host) struct mtd_info *mtd = nand_to_mtd(&host->nand_chip); dma_cap_mask_t mask; - if (!host->pdata || !host->pdata->dma_filter) { - dev_err(mtd->dev.parent, "no DMA platform data\n"); - return -ENOENT; - } + host->dma_chan = dma_request_chan(mtd->dev.parent, "rx-tx"); + if (IS_ERR(host->dma_chan)) { + /* fallback to request using platform data */ + if (!host->pdata || !host->pdata->dma_filter) { + dev_err(mtd->dev.parent, "no DMA platform data\n"); + return -ENOENT; + } - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter, - "nand-mlc"); - if (!host->dma_chan) { - dev_err(mtd->dev.parent, "Failed to request DMA channel\n"); - return -EBUSY; + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter, "nand-mlc"); + + if (!host->dma_chan) { + dev_err(mtd->dev.parent, "Failed to request DMA channel\n"); + return -EBUSY; + } } /* diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c index 1c5fa855b9f2..ade971e4cc3b 100644 --- a/drivers/mtd/nand/raw/lpc32xx_slc.c +++ b/drivers/mtd/nand/raw/lpc32xx_slc.c @@ -721,18 +721,22 @@ static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host) struct mtd_info *mtd = nand_to_mtd(&host->nand_chip); dma_cap_mask_t mask; - if (!host->pdata || !host->pdata->dma_filter) { - dev_err(mtd->dev.parent, "no DMA platform data\n"); - return -ENOENT; - } + host->dma_chan = dma_request_chan(mtd->dev.parent, "rx-tx"); + if (IS_ERR(host->dma_chan)) { + /* fallback to request using platform data */ + if (!host->pdata || !host->pdata->dma_filter) { + dev_err(mtd->dev.parent, "no DMA platform data\n"); + return -ENOENT; + } - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter, - "nand-slc"); - if (!host->dma_chan) { - dev_err(mtd->dev.parent, "Failed to request DMA channel\n"); - return -EBUSY; + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter, "nand-slc"); + + if (!host->dma_chan) { + dev_err(mtd->dev.parent, "Failed to request DMA channel\n"); + return -EBUSY; + } } return 0; diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index 2a96a87cf79c..9eb5470344d0 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -35,6 +35,7 @@ #define NFC_CMD_RB BIT(20) #define NFC_CMD_SCRAMBLER_ENABLE BIT(19) #define NFC_CMD_SCRAMBLER_DISABLE 0 +#define NFC_CMD_SHORTMODE_ENABLE 1 #define NFC_CMD_SHORTMODE_DISABLE 0 #define NFC_CMD_RB_INT BIT(14) #define NFC_CMD_RB_INT_NO_PIN ((0xb << 10) | BIT(18) | BIT(16)) @@ -78,6 +79,8 @@ #define DMA_DIR(dir) ((dir) ? NFC_CMD_N2M : NFC_CMD_M2N) #define DMA_ADDR_ALIGN 8 +#define NFC_SHORT_MODE_ECC_SZ 384 + #define ECC_CHECK_RETURN_FF (-1) #define NAND_CE0 (0xe << 10) @@ -125,6 +128,8 @@ struct meson_nfc_nand_chip { u32 twb; u32 tadl; u32 tbers_max; + u32 boot_pages; + u32 boot_page_step; u32 bch_mode; u8 *data_buf; @@ -298,28 +303,49 @@ static void meson_nfc_cmd_seed(struct meson_nfc *nfc, u32 seed) nfc->reg_base + NFC_REG_CMD); } -static void meson_nfc_cmd_access(struct nand_chip *nand, int raw, bool dir, - int scrambler) +static int meson_nfc_is_boot_page(struct nand_chip *nand, int page) { + const struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand); + + return (nand->options & NAND_IS_BOOT_MEDIUM) && + !(page % meson_chip->boot_page_step) && + (page < meson_chip->boot_pages); +} + +static void meson_nfc_cmd_access(struct nand_chip *nand, int raw, bool dir, int page) +{ + const struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand); struct mtd_info *mtd = nand_to_mtd(nand); struct meson_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); - struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand); - u32 bch = meson_chip->bch_mode, cmd; int len = mtd->writesize, pagesize, pages; + int scrambler; + u32 cmd; - pagesize = nand->ecc.size; + if (nand->options & NAND_NEED_SCRAMBLING) + scrambler = NFC_CMD_SCRAMBLER_ENABLE; + else + scrambler = NFC_CMD_SCRAMBLER_DISABLE; if (raw) { len = mtd->writesize + mtd->oobsize; cmd = len | scrambler | DMA_DIR(dir); - writel(cmd, nfc->reg_base + NFC_REG_CMD); - return; + } else if (meson_nfc_is_boot_page(nand, page)) { + pagesize = NFC_SHORT_MODE_ECC_SZ >> 3; + pages = mtd->writesize / 512; + + scrambler = NFC_CMD_SCRAMBLER_ENABLE; + cmd = CMDRWGEN(DMA_DIR(dir), scrambler, NFC_ECC_BCH8_1K, + NFC_CMD_SHORTMODE_ENABLE, pagesize, pages); + } else { + pagesize = nand->ecc.size >> 3; + pages = len / nand->ecc.size; + + cmd = CMDRWGEN(DMA_DIR(dir), scrambler, meson_chip->bch_mode, + NFC_CMD_SHORTMODE_DISABLE, pagesize, pages); } - pages = len / nand->ecc.size; - - cmd = CMDRWGEN(DMA_DIR(dir), scrambler, bch, - NFC_CMD_SHORTMODE_DISABLE, pagesize, pages); + if (scrambler == NFC_CMD_SCRAMBLER_ENABLE) + meson_nfc_cmd_seed(nfc, page); writel(cmd, nfc->reg_base + NFC_REG_CMD); } @@ -743,14 +769,7 @@ static int meson_nfc_write_page_sub(struct nand_chip *nand, if (ret) return ret; - if (nand->options & NAND_NEED_SCRAMBLING) { - meson_nfc_cmd_seed(nfc, page); - meson_nfc_cmd_access(nand, raw, DIRWRITE, - NFC_CMD_SCRAMBLER_ENABLE); - } else { - meson_nfc_cmd_access(nand, raw, DIRWRITE, - NFC_CMD_SCRAMBLER_DISABLE); - } + meson_nfc_cmd_access(nand, raw, DIRWRITE, page); cmd = nfc->param.chip_select | NFC_CMD_CLE | NAND_CMD_PAGEPROG; writel(cmd, nfc->reg_base + NFC_REG_CMD); @@ -829,14 +848,7 @@ static int meson_nfc_read_page_sub(struct nand_chip *nand, if (ret) return ret; - if (nand->options & NAND_NEED_SCRAMBLING) { - meson_nfc_cmd_seed(nfc, page); - meson_nfc_cmd_access(nand, raw, DIRREAD, - NFC_CMD_SCRAMBLER_ENABLE); - } else { - meson_nfc_cmd_access(nand, raw, DIRREAD, - NFC_CMD_SCRAMBLER_DISABLE); - } + meson_nfc_cmd_access(nand, raw, DIRREAD, page); ret = meson_nfc_wait_dma_finish(nfc); meson_nfc_check_ecc_pages_valid(nfc, nand, raw); @@ -1431,6 +1443,26 @@ meson_nfc_nand_chip_init(struct device *dev, if (ret) return ret; + if (nand->options & NAND_IS_BOOT_MEDIUM) { + ret = of_property_read_u32(np, "amlogic,boot-pages", + &meson_chip->boot_pages); + if (ret) { + dev_err(dev, "could not retrieve 'amlogic,boot-pages' property: %d", + ret); + nand_cleanup(nand); + return ret; + } + + ret = of_property_read_u32(np, "amlogic,boot-page-step", + &meson_chip->boot_page_step); + if (ret) { + dev_err(dev, "could not retrieve 'amlogic,boot-page-step' property: %d", + ret); + nand_cleanup(nand); + return ret; + } + } + ret = mtd_device_register(mtd, NULL, 0); if (ret) { dev_err(dev, "failed to register MTD device: %d\n", ret); diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c index 003008355b3c..736808150e74 100644 --- a/drivers/mtd/nand/raw/mxc_nand.c +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -20,6 +20,7 @@ #include #include #include +#include #define DRIVER_NAME "mxc_nand" @@ -47,6 +48,8 @@ #define NFC_V1_V2_CONFIG1 (host->regs + 0x1a) #define NFC_V1_V2_CONFIG2 (host->regs + 0x1c) +#define NFC_V1_V2_ECC_STATUS_RESULT_ERM GENMASK(3, 2) + #define NFC_V2_CONFIG1_ECC_MODE_4 (1 << 0) #define NFC_V1_V2_CONFIG1_SP_EN (1 << 2) #define NFC_V1_V2_CONFIG1_ECC_EN (1 << 3) @@ -123,8 +126,7 @@ struct mxc_nand_host; struct mxc_nand_devtype_data { void (*preset)(struct mtd_info *); - int (*read_page)(struct nand_chip *chip, void *buf, void *oob, bool ecc, - int page); + int (*read_page)(struct nand_chip *chip); void (*send_cmd)(struct mxc_nand_host *, uint16_t, int); void (*send_addr)(struct mxc_nand_host *, uint16_t, int); void (*send_page)(struct mtd_info *, unsigned int); @@ -132,7 +134,7 @@ struct mxc_nand_devtype_data { uint16_t (*get_dev_status)(struct mxc_nand_host *); int (*check_int)(struct mxc_nand_host *); void (*irq_control)(struct mxc_nand_host *, int); - u32 (*get_ecc_status)(struct mxc_nand_host *); + u32 (*get_ecc_status)(struct nand_chip *); const struct mtd_ooblayout_ops *ooblayout; void (*select_chip)(struct nand_chip *chip, int cs); int (*setup_interface)(struct nand_chip *chip, int csline, @@ -175,11 +177,11 @@ struct mxc_nand_host { int eccsize; int used_oobsize; int active_cs; + unsigned int ecc_stats_v1; struct completion op_completion; - uint8_t *data_buf; - unsigned int buf_start; + void *data_buf; const struct mxc_nand_devtype_data *devtype_data; }; @@ -281,63 +283,6 @@ static void copy_spare(struct mtd_info *mtd, bool bfrom, void *buf) } } -/* - * MXC NANDFC can only perform full page+spare or spare-only read/write. When - * the upper layers perform a read/write buf operation, the saved column address - * is used to index into the full page. So usually this function is called with - * column == 0 (unless no column cycle is needed indicated by column == -1) - */ -static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); - - /* Write out column address, if necessary */ - if (column != -1) { - host->devtype_data->send_addr(host, column & 0xff, - page_addr == -1); - if (mtd->writesize > 512) - /* another col addr cycle for 2k page */ - host->devtype_data->send_addr(host, - (column >> 8) & 0xff, - false); - } - - /* Write out page address, if necessary */ - if (page_addr != -1) { - /* paddr_0 - p_addr_7 */ - host->devtype_data->send_addr(host, (page_addr & 0xff), false); - - if (mtd->writesize > 512) { - if (mtd->size >= 0x10000000) { - /* paddr_8 - paddr_15 */ - host->devtype_data->send_addr(host, - (page_addr >> 8) & 0xff, - false); - host->devtype_data->send_addr(host, - (page_addr >> 16) & 0xff, - true); - } else - /* paddr_8 - paddr_15 */ - host->devtype_data->send_addr(host, - (page_addr >> 8) & 0xff, true); - } else { - if (nand_chip->options & NAND_ROW_ADDR_3) { - /* paddr_8 - paddr_15 */ - host->devtype_data->send_addr(host, - (page_addr >> 8) & 0xff, - false); - host->devtype_data->send_addr(host, - (page_addr >> 16) & 0xff, - true); - } else - /* paddr_8 - paddr_15 */ - host->devtype_data->send_addr(host, - (page_addr >> 8) & 0xff, true); - } - } -} - static int check_int_v3(struct mxc_nand_host *host) { uint32_t tmp; @@ -406,19 +351,81 @@ static void irq_control(struct mxc_nand_host *host, int activate) } } -static u32 get_ecc_status_v1(struct mxc_nand_host *host) +static u32 get_ecc_status_v1(struct nand_chip *chip) { - return readw(NFC_V1_V2_ECC_STATUS_RESULT); + struct mtd_info *mtd = nand_to_mtd(chip); + struct mxc_nand_host *host = nand_get_controller_data(chip); + unsigned int ecc_stats, max_bitflips = 0; + int no_subpages, i; + + no_subpages = mtd->writesize >> 9; + + ecc_stats = host->ecc_stats_v1; + + for (i = 0; i < no_subpages; i++) { + switch (ecc_stats & 0x3) { + case 0: + default: + break; + case 1: + mtd->ecc_stats.corrected++; + max_bitflips = 1; + break; + case 2: + mtd->ecc_stats.failed++; + break; + } + + ecc_stats >>= 2; + } + + return max_bitflips; } -static u32 get_ecc_status_v2(struct mxc_nand_host *host) +static u32 get_ecc_status_v2_v3(struct nand_chip *chip, unsigned int ecc_stat) { - return readl(NFC_V1_V2_ECC_STATUS_RESULT); + struct mtd_info *mtd = nand_to_mtd(chip); + struct mxc_nand_host *host = nand_get_controller_data(chip); + u8 ecc_bit_mask, err_limit; + unsigned int max_bitflips = 0; + int no_subpages, err; + + ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf; + err_limit = (host->eccsize == 4) ? 0x4 : 0x8; + + no_subpages = mtd->writesize >> 9; + + do { + err = ecc_stat & ecc_bit_mask; + if (err > err_limit) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += err; + max_bitflips = max_t(unsigned int, max_bitflips, err); + } + + ecc_stat >>= 4; + } while (--no_subpages); + + return max_bitflips; } -static u32 get_ecc_status_v3(struct mxc_nand_host *host) +static u32 get_ecc_status_v2(struct nand_chip *chip) { - return readl(NFC_V3_ECC_STATUS_RESULT); + struct mxc_nand_host *host = nand_get_controller_data(chip); + + u32 ecc_stat = readl(NFC_V1_V2_ECC_STATUS_RESULT); + + return get_ecc_status_v2_v3(chip, ecc_stat); +} + +static u32 get_ecc_status_v3(struct nand_chip *chip) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + + u32 ecc_stat = readl(NFC_V3_ECC_STATUS_RESULT); + + return get_ecc_status_v2_v3(chip, ecc_stat); } static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) @@ -450,14 +457,14 @@ static int wait_op_done(struct mxc_nand_host *host, int useirq) return 0; if (useirq) { - unsigned long timeout; + unsigned long time_left; reinit_completion(&host->op_completion); irq_control(host, 1); - timeout = wait_for_completion_timeout(&host->op_completion, HZ); - if (!timeout && !host->devtype_data->check_int(host)) { + time_left = wait_for_completion_timeout(&host->op_completion, HZ); + if (!time_left && !host->devtype_data->check_int(host)) { dev_dbg(host->dev, "timeout waiting for irq\n"); ret = -ETIMEDOUT; } @@ -697,38 +704,21 @@ static void mxc_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable) writel(config2, NFC_V3_CONFIG2); } -/* This functions is used by upper layer to checks if device is ready */ -static int mxc_nand_dev_ready(struct nand_chip *chip) -{ - /* - * NFC handles R/B internally. Therefore, this function - * always returns status as ready. - */ - return 1; -} - -static int mxc_nand_read_page_v1(struct nand_chip *chip, void *buf, void *oob, - bool ecc, int page) +static int mxc_nand_read_page_v1(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); struct mxc_nand_host *host = nand_get_controller_data(chip); - unsigned int bitflips_corrected = 0; int no_subpages; int i; + unsigned int ecc_stats = 0; - host->devtype_data->enable_hwecc(chip, ecc); - - host->devtype_data->send_cmd(host, NAND_CMD_READ0, false); - mxc_do_addr_cycle(mtd, 0, page); - - if (mtd->writesize > 512) - host->devtype_data->send_cmd(host, NAND_CMD_READSTART, true); - - no_subpages = mtd->writesize >> 9; + if (mtd->writesize) + no_subpages = mtd->writesize >> 9; + else + /* READ PARAMETER PAGE is called when mtd->writesize is not yet set */ + no_subpages = 1; for (i = 0; i < no_subpages; i++) { - uint16_t ecc_stats; - /* NANDFC buffer 0 is used for page read/write */ writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR); @@ -737,135 +727,74 @@ static int mxc_nand_read_page_v1(struct nand_chip *chip, void *buf, void *oob, /* Wait for operation to complete */ wait_op_done(host, true); - ecc_stats = get_ecc_status_v1(host); - - ecc_stats >>= 2; - - if (buf && ecc) { - switch (ecc_stats & 0x3) { - case 0: - default: - break; - case 1: - mtd->ecc_stats.corrected++; - bitflips_corrected = 1; - break; - case 2: - mtd->ecc_stats.failed++; - break; - } - } + ecc_stats |= FIELD_GET(NFC_V1_V2_ECC_STATUS_RESULT_ERM, + readw(NFC_V1_V2_ECC_STATUS_RESULT)) << i * 2; } - if (buf) - memcpy32_fromio(buf, host->main_area0, mtd->writesize); - if (oob) - copy_spare(mtd, true, oob); + host->ecc_stats_v1 = ecc_stats; - return bitflips_corrected; + return 0; } -static int mxc_nand_read_page_v2_v3(struct nand_chip *chip, void *buf, - void *oob, bool ecc, int page) +static int mxc_nand_read_page_v2_v3(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); struct mxc_nand_host *host = nand_get_controller_data(chip); - unsigned int max_bitflips = 0; - u32 ecc_stat, err; - int no_subpages; - u8 ecc_bit_mask, err_limit; - - host->devtype_data->enable_hwecc(chip, ecc); - - host->devtype_data->send_cmd(host, NAND_CMD_READ0, false); - mxc_do_addr_cycle(mtd, 0, page); - - if (mtd->writesize > 512) - host->devtype_data->send_cmd(host, - NAND_CMD_READSTART, true); host->devtype_data->send_page(mtd, NFC_OUTPUT); - if (buf) - memcpy32_fromio(buf, host->main_area0, mtd->writesize); - if (oob) - copy_spare(mtd, true, oob); - - ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf; - err_limit = (host->eccsize == 4) ? 0x4 : 0x8; - - no_subpages = mtd->writesize >> 9; - - ecc_stat = host->devtype_data->get_ecc_status(host); - - do { - err = ecc_stat & ecc_bit_mask; - if (err > err_limit) { - mtd->ecc_stats.failed++; - } else { - mtd->ecc_stats.corrected += err; - max_bitflips = max_t(unsigned int, max_bitflips, err); - } - - ecc_stat >>= 4; - } while (--no_subpages); - - return max_bitflips; + return 0; } static int mxc_nand_read_page(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct mxc_nand_host *host = nand_get_controller_data(chip); - void *oob_buf; + int ret; + + host->devtype_data->enable_hwecc(chip, true); + + ret = nand_read_page_op(chip, page, 0, buf, mtd->writesize); + + host->devtype_data->enable_hwecc(chip, false); + + if (ret) + return ret; if (oob_required) - oob_buf = chip->oob_poi; - else - oob_buf = NULL; + copy_spare(mtd, true, chip->oob_poi); - return host->devtype_data->read_page(chip, buf, oob_buf, 1, page); + return host->devtype_data->get_ecc_status(chip); } static int mxc_nand_read_page_raw(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { - struct mxc_nand_host *host = nand_get_controller_data(chip); - void *oob_buf; + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + + ret = nand_read_page_op(chip, page, 0, buf, mtd->writesize); + if (ret) + return ret; if (oob_required) - oob_buf = chip->oob_poi; - else - oob_buf = NULL; + copy_spare(mtd, true, chip->oob_poi); - return host->devtype_data->read_page(chip, buf, oob_buf, 0, page); + return 0; } static int mxc_nand_read_oob(struct nand_chip *chip, int page) -{ - struct mxc_nand_host *host = nand_get_controller_data(chip); - - return host->devtype_data->read_page(chip, NULL, chip->oob_poi, 0, - page); -} - -static int mxc_nand_write_page(struct nand_chip *chip, const uint8_t *buf, - bool ecc, int page) { struct mtd_info *mtd = nand_to_mtd(chip); struct mxc_nand_host *host = nand_get_controller_data(chip); + int ret; - host->devtype_data->enable_hwecc(chip, ecc); + ret = nand_read_page_op(chip, page, 0, host->data_buf, mtd->writesize); + if (ret) + return ret; - host->devtype_data->send_cmd(host, NAND_CMD_SEQIN, false); - mxc_do_addr_cycle(mtd, 0, page); - - memcpy32_toio(host->main_area0, buf, mtd->writesize); - copy_spare(mtd, false, chip->oob_poi); - - host->devtype_data->send_page(mtd, NFC_INPUT); - host->devtype_data->send_cmd(host, NAND_CMD_PAGEPROG, true); - mxc_do_addr_cycle(mtd, 0, page); + copy_spare(mtd, true, chip->oob_poi); return 0; } @@ -873,13 +802,29 @@ static int mxc_nand_write_page(struct nand_chip *chip, const uint8_t *buf, static int mxc_nand_write_page_ecc(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { - return mxc_nand_write_page(chip, buf, true, page); + struct mtd_info *mtd = nand_to_mtd(chip); + struct mxc_nand_host *host = nand_get_controller_data(chip); + int ret; + + copy_spare(mtd, false, chip->oob_poi); + + host->devtype_data->enable_hwecc(chip, true); + + ret = nand_prog_page_op(chip, page, 0, buf, mtd->writesize); + + host->devtype_data->enable_hwecc(chip, false); + + return ret; } static int mxc_nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { - return mxc_nand_write_page(chip, buf, false, page); + struct mtd_info *mtd = nand_to_mtd(chip); + + copy_spare(mtd, false, chip->oob_poi); + + return nand_prog_page_op(chip, page, 0, buf, mtd->writesize); } static int mxc_nand_write_oob(struct nand_chip *chip, int page) @@ -888,68 +833,9 @@ static int mxc_nand_write_oob(struct nand_chip *chip, int page) struct mxc_nand_host *host = nand_get_controller_data(chip); memset(host->data_buf, 0xff, mtd->writesize); + copy_spare(mtd, false, chip->oob_poi); - return mxc_nand_write_page(chip, host->data_buf, false, page); -} - -static u_char mxc_nand_read_byte(struct nand_chip *nand_chip) -{ - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); - uint8_t ret; - - /* Check for status request */ - if (host->status_request) - return host->devtype_data->get_dev_status(host) & 0xFF; - - if (nand_chip->options & NAND_BUSWIDTH_16) { - /* only take the lower byte of each word */ - ret = *(uint16_t *)(host->data_buf + host->buf_start); - - host->buf_start += 2; - } else { - ret = *(uint8_t *)(host->data_buf + host->buf_start); - host->buf_start++; - } - - dev_dbg(host->dev, "%s: ret=0x%hhx (start=%u)\n", __func__, ret, host->buf_start); - return ret; -} - -/* Write data of length len to buffer buf. The data to be - * written on NAND Flash is first copied to RAMbuffer. After the Data Input - * Operation by the NFC, the data is written to NAND Flash */ -static void mxc_nand_write_buf(struct nand_chip *nand_chip, const u_char *buf, - int len) -{ - struct mtd_info *mtd = nand_to_mtd(nand_chip); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); - u16 col = host->buf_start; - int n = mtd->oobsize + mtd->writesize - col; - - n = min(n, len); - - memcpy(host->data_buf + col, buf, n); - - host->buf_start += n; -} - -/* Read the data buffer from the NAND Flash. To read the data from NAND - * Flash first the data output cycle is initiated by the NFC, which copies - * the data to RAMbuffer. This data of length len is then copied to buffer buf. - */ -static void mxc_nand_read_buf(struct nand_chip *nand_chip, u_char *buf, - int len) -{ - struct mtd_info *mtd = nand_to_mtd(nand_chip); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); - u16 col = host->buf_start; - int n = mtd->oobsize + mtd->writesize - col; - - n = min(n, len); - - memcpy(buf, host->data_buf + col, n); - - host->buf_start += n; + return nand_prog_page_op(chip, page, 0, host->data_buf, mtd->writesize); } /* This function is used by upper layer for select and @@ -1328,107 +1214,6 @@ static void preset_v3(struct mtd_info *mtd) writel(0, NFC_V3_DELAY_LINE); } -/* Used by the upper layer to write command to NAND Flash for - * different operations to be carried out on NAND Flash */ -static void mxc_nand_command(struct nand_chip *nand_chip, unsigned command, - int column, int page_addr) -{ - struct mtd_info *mtd = nand_to_mtd(nand_chip); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); - - dev_dbg(host->dev, "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", - command, column, page_addr); - - /* Reset command state information */ - host->status_request = false; - - /* Command pre-processing step */ - switch (command) { - case NAND_CMD_RESET: - host->devtype_data->preset(mtd); - host->devtype_data->send_cmd(host, command, false); - break; - - case NAND_CMD_STATUS: - host->buf_start = 0; - host->status_request = true; - - host->devtype_data->send_cmd(host, command, true); - WARN_ONCE(column != -1 || page_addr != -1, - "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", - command, column, page_addr); - mxc_do_addr_cycle(mtd, column, page_addr); - break; - - case NAND_CMD_READID: - host->devtype_data->send_cmd(host, command, true); - mxc_do_addr_cycle(mtd, column, page_addr); - host->devtype_data->send_read_id(host); - host->buf_start = 0; - break; - - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - host->devtype_data->send_cmd(host, command, false); - WARN_ONCE(column != -1, - "Unexpected column value (cmd=%u, col=%d)\n", - command, column); - mxc_do_addr_cycle(mtd, column, page_addr); - - break; - case NAND_CMD_PARAM: - host->devtype_data->send_cmd(host, command, false); - mxc_do_addr_cycle(mtd, column, page_addr); - host->devtype_data->send_page(mtd, NFC_OUTPUT); - memcpy32_fromio(host->data_buf, host->main_area0, 512); - host->buf_start = 0; - break; - default: - WARN_ONCE(1, "Unimplemented command (cmd=%u)\n", - command); - break; - } -} - -static int mxc_nand_set_features(struct nand_chip *chip, int addr, - u8 *subfeature_param) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct mxc_nand_host *host = nand_get_controller_data(chip); - int i; - - host->buf_start = 0; - - for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) - chip->legacy.write_byte(chip, subfeature_param[i]); - - memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize); - host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false); - mxc_do_addr_cycle(mtd, addr, -1); - host->devtype_data->send_page(mtd, NFC_INPUT); - - return 0; -} - -static int mxc_nand_get_features(struct nand_chip *chip, int addr, - u8 *subfeature_param) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct mxc_nand_host *host = nand_get_controller_data(chip); - int i; - - host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false); - mxc_do_addr_cycle(mtd, addr, -1); - host->devtype_data->send_page(mtd, NFC_OUTPUT); - memcpy32_fromio(host->data_buf, host->main_area0, 512); - host->buf_start = 0; - - for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) - *subfeature_param++ = chip->legacy.read_byte(chip); - - return 0; -} - /* * The generic flash bbt descriptors overlap with our ecc * hardware, so define some i.MX specific ones. @@ -1617,10 +1402,10 @@ static int mxcnd_attach_chip(struct nand_chip *chip) chip->ecc.bytes = host->devtype_data->eccbytes; host->eccsize = host->devtype_data->eccsize; chip->ecc.size = 512; - mtd_set_ooblayout(mtd, host->devtype_data->ooblayout); switch (chip->ecc.engine_type) { case NAND_ECC_ENGINE_TYPE_ON_HOST: + mtd_set_ooblayout(mtd, host->devtype_data->ooblayout); chip->ecc.read_page = mxc_nand_read_page; chip->ecc.read_page_raw = mxc_nand_read_page_raw; chip->ecc.read_oob = mxc_nand_read_oob; @@ -1630,6 +1415,8 @@ static int mxcnd_attach_chip(struct nand_chip *chip) break; case NAND_ECC_ENGINE_TYPE_SOFT: + chip->ecc.write_page_raw = nand_monolithic_write_page_raw; + chip->ecc.read_page_raw = nand_monolithic_read_page_raw; break; default: @@ -1685,9 +1472,217 @@ static int mxcnd_setup_interface(struct nand_chip *chip, int chipnr, return host->devtype_data->setup_interface(chip, chipnr, conf); } +static void memff16_toio(void *buf, int n) +{ + __iomem u16 *t = buf; + int i; + + for (i = 0; i < (n >> 1); i++) + __raw_writew(0xffff, t++); +} + +static void copy_page_to_sram(struct mtd_info *mtd, const void *buf, int buf_len) +{ + struct nand_chip *this = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(this); + unsigned int no_subpages = mtd->writesize / 512; + int oob_per_subpage, i; + + oob_per_subpage = (mtd->oobsize / no_subpages) & ~1; + + /* + * During a page write the i.MX NAND controller will read 512b from + * main_area0 SRAM, then oob_per_subpage bytes from spare0 SRAM, then + * 512b from main_area1 SRAM and so on until the full page is written. + * For software ECC we want to have a 1:1 mapping between the raw page + * data on the NAND chip and the view of the NAND core. This is + * necessary to make the NAND_CMD_RNDOUT read the data it expects. + * To accomplish this we have to write the data in the order the controller + * reads it. This is reversed in copy_page_from_sram() below. + * + * buf_len can either be the full page including the OOB or user data only. + * When it's user data only make sure that we fill up the rest of the + * SRAM with 0xff. + */ + for (i = 0; i < no_subpages; i++) { + int now = min(buf_len, 512); + + if (now) + memcpy16_toio(host->main_area0 + i * 512, buf, now); + + if (now < 512) + memff16_toio(host->main_area0 + i * 512 + now, 512 - now); + + buf += 512; + buf_len -= now; + + now = min(buf_len, oob_per_subpage); + if (now) + memcpy16_toio(host->spare0 + i * host->devtype_data->spare_len, + buf, now); + + if (now < oob_per_subpage) + memff16_toio(host->spare0 + i * host->devtype_data->spare_len + now, + oob_per_subpage - now); + + buf += oob_per_subpage; + buf_len -= now; + } +} + +static void copy_page_from_sram(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(this); + void *buf = host->data_buf; + unsigned int no_subpages = mtd->writesize / 512; + int oob_per_subpage, i; + + /* mtd->writesize is not set during ident scanning */ + if (!no_subpages) + no_subpages = 1; + + oob_per_subpage = (mtd->oobsize / no_subpages) & ~1; + + for (i = 0; i < no_subpages; i++) { + memcpy16_fromio(buf, host->main_area0 + i * 512, 512); + buf += 512; + + memcpy16_fromio(buf, host->spare0 + i * host->devtype_data->spare_len, + oob_per_subpage); + buf += oob_per_subpage; + } +} + +static int mxcnd_do_exec_op(struct nand_chip *chip, + const struct nand_subop *op) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + struct mtd_info *mtd = nand_to_mtd(chip); + int i, j, buf_len; + void *buf_read = NULL; + const void *buf_write = NULL; + const struct nand_op_instr *instr; + bool readid = false; + bool statusreq = false; + + for (i = 0; i < op->ninstrs; i++) { + instr = &op->instrs[i]; + + switch (instr->type) { + case NAND_OP_WAITRDY_INSTR: + /* NFC handles R/B internally, nothing to do here */ + break; + case NAND_OP_CMD_INSTR: + host->devtype_data->send_cmd(host, instr->ctx.cmd.opcode, true); + + if (instr->ctx.cmd.opcode == NAND_CMD_READID) + readid = true; + if (instr->ctx.cmd.opcode == NAND_CMD_STATUS) + statusreq = true; + + break; + case NAND_OP_ADDR_INSTR: + for (j = 0; j < instr->ctx.addr.naddrs; j++) { + bool islast = j == instr->ctx.addr.naddrs - 1; + host->devtype_data->send_addr(host, instr->ctx.addr.addrs[j], islast); + } + break; + case NAND_OP_DATA_OUT_INSTR: + buf_write = instr->ctx.data.buf.out; + buf_len = instr->ctx.data.len; + + if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) + memcpy32_toio(host->main_area0, buf_write, buf_len); + else + copy_page_to_sram(mtd, buf_write, buf_len); + + host->devtype_data->send_page(mtd, NFC_INPUT); + + break; + case NAND_OP_DATA_IN_INSTR: + + buf_read = instr->ctx.data.buf.in; + buf_len = instr->ctx.data.len; + + if (readid) { + host->devtype_data->send_read_id(host); + readid = false; + + memcpy32_fromio(host->data_buf, host->main_area0, buf_len * 2); + + if (chip->options & NAND_BUSWIDTH_16) { + u8 *bufr = buf_read; + u16 *bufw = host->data_buf; + for (j = 0; j < buf_len; j++) + bufr[j] = bufw[j]; + } else { + memcpy(buf_read, host->data_buf, buf_len); + } + break; + } + + if (statusreq) { + *(u8*)buf_read = host->devtype_data->get_dev_status(host); + statusreq = false; + break; + } + + host->devtype_data->read_page(chip); + + if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) { + if (IS_ALIGNED(buf_len, 4)) { + memcpy32_fromio(buf_read, host->main_area0, buf_len); + } else { + memcpy32_fromio(host->data_buf, host->main_area0, mtd->writesize); + memcpy(buf_read, host->data_buf, buf_len); + } + } else { + copy_page_from_sram(mtd); + memcpy(buf_read, host->data_buf, buf_len); + } + + break; + } + } + + return 0; +} + +#define MAX_DATA_SIZE (4096 + 512) + +static const struct nand_op_parser mxcnd_op_parser = NAND_OP_PARSER( + NAND_OP_PARSER_PATTERN(mxcnd_do_exec_op, + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_ADDR_ELEM(true, 7), + NAND_OP_PARSER_PAT_CMD_ELEM(true), + NAND_OP_PARSER_PAT_WAITRDY_ELEM(true), + NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, MAX_DATA_SIZE)), + NAND_OP_PARSER_PATTERN(mxcnd_do_exec_op, + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_ADDR_ELEM(false, 7), + NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, MAX_DATA_SIZE), + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)), + NAND_OP_PARSER_PATTERN(mxcnd_do_exec_op, + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_ADDR_ELEM(false, 7), + NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, MAX_DATA_SIZE), + NAND_OP_PARSER_PAT_CMD_ELEM(true), + NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)), + ); + +static int mxcnd_exec_op(struct nand_chip *chip, + const struct nand_operation *op, bool check_only) +{ + return nand_op_parser_exec_op(chip, &mxcnd_op_parser, + op, check_only); +} + static const struct nand_controller_ops mxcnd_controller_ops = { .attach_chip = mxcnd_attach_chip, .setup_interface = mxcnd_setup_interface, + .exec_op = mxcnd_exec_op, }; static int mxcnd_probe(struct platform_device *pdev) @@ -1720,13 +1715,6 @@ static int mxcnd_probe(struct platform_device *pdev) nand_set_controller_data(this, host); nand_set_flash_node(this, pdev->dev.of_node); - this->legacy.dev_ready = mxc_nand_dev_ready; - this->legacy.cmdfunc = mxc_nand_command; - this->legacy.read_byte = mxc_nand_read_byte; - this->legacy.write_buf = mxc_nand_write_buf; - this->legacy.read_buf = mxc_nand_read_buf; - this->legacy.set_features = mxc_nand_set_features; - this->legacy.get_features = mxc_nand_get_features; host->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(host->clk)) diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c index 3dfc7e1e5241..3f9e9c572854 100644 --- a/drivers/mtd/nand/spi/macronix.c +++ b/drivers/mtd/nand/spi/macronix.c @@ -121,7 +121,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_INFO("MX35LF2GE4AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x26), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x26, 0x03), NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -131,7 +131,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35LF4GE4AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37, 0x03), NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -141,7 +141,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35LF1G24AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14, 0x03), NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -150,7 +150,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_INFO("MX35LF2G24AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24, 0x03), NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -158,8 +158,17 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), + SPINAND_INFO("MX35LF2G24AD-Z4I8", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x64, 0x03), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_INFO("MX35LF4G24AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35, 0x03), NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -167,6 +176,15 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), + SPINAND_INFO("MX35LF4G24AD-Z4I8", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x75, 0x03), + NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_INFO("MX31LF1GE4BC", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), @@ -199,7 +217,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35UF4G24AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5, 0x03), NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -208,8 +226,18 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), + SPINAND_INFO("MX35UF4G24AD-Z4I8", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xf5, 0x03), + NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, + mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35UF4GE4AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7, 0x03), NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -229,7 +257,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35UF2G24AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4, 0x03), NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -238,8 +266,18 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), + SPINAND_INFO("MX35UF2G24AD-Z4I8", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe4, 0x03), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, + mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35UF2GE4AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6, 0x03), NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -249,7 +287,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35UF2GE4AC", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2, 0x01), NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(4, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -269,7 +307,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35UF1G24AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94, 0x03), NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -279,7 +317,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35UF1GE4AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96, 0x03), NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -289,7 +327,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35UF1GE4AC", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92, 0x01), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(4, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, diff --git a/drivers/mtd/parsers/brcm_u-boot.c b/drivers/mtd/parsers/brcm_u-boot.c index 7c338dc7b8f3..984f98923446 100644 --- a/drivers/mtd/parsers/brcm_u-boot.c +++ b/drivers/mtd/parsers/brcm_u-boot.c @@ -81,4 +81,5 @@ static struct mtd_part_parser brcm_u_boot_mtd_parser = { }; module_mtd_part_parser(brcm_u_boot_mtd_parser); +MODULE_DESCRIPTION("Broadcom's U-Boot partition parser"); MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/parsers/cmdlinepart.c b/drivers/mtd/parsers/cmdlinepart.c index b34856def816..504e5fa2b45b 100644 --- a/drivers/mtd/parsers/cmdlinepart.c +++ b/drivers/mtd/parsers/cmdlinepart.c @@ -44,14 +44,6 @@ #include #include -/* debug macro */ -#if 0 -#define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0) -#else -#define dbg(x) -#endif - - /* special size referring to all the remaining space in a partition */ #define SIZE_REMAINING ULLONG_MAX #define OFFSET_CONTINUOUS ULLONG_MAX @@ -199,9 +191,9 @@ static struct mtd_partition * newpart(char *s, parts[this_part].name = extra_mem; extra_mem += name_len + 1; - dbg(("partition %d: name <%s>, offset %llx, size %llx, mask flags %x\n", + pr_debug("partition %d: name <%s>, offset %llx, size %llx, mask flags %x\n", this_part, parts[this_part].name, parts[this_part].offset, - parts[this_part].size, parts[this_part].mask_flags)); + parts[this_part].size, parts[this_part].mask_flags); /* return (updated) pointer to extra_mem memory */ if (extra_mem_ptr) @@ -267,7 +259,7 @@ static int mtdpart_setup_real(char *s) } mtd_id_len = p - mtd_id; - dbg(("parsing <%s>\n", p+1)); + pr_debug("parsing <%s>\n", p+1); /* * parse one mtd. have it reserve memory for the @@ -304,8 +296,8 @@ static int mtdpart_setup_real(char *s) this_mtd->next = partitions; partitions = this_mtd; - dbg(("mtdid=<%s> num_parts=<%d>\n", - this_mtd->mtd_id, this_mtd->num_parts)); + pr_debug("mtdid=<%s> num_parts=<%d>\n", + this_mtd->mtd_id, this_mtd->num_parts); /* EOS - we're done */ diff --git a/drivers/mtd/parsers/tplink_safeloader.c b/drivers/mtd/parsers/tplink_safeloader.c index 1c689dafca2a..e358a029dc70 100644 --- a/drivers/mtd/parsers/tplink_safeloader.c +++ b/drivers/mtd/parsers/tplink_safeloader.c @@ -149,4 +149,5 @@ static struct mtd_part_parser mtd_parser_tplink_safeloader = { }; module_mtd_part_parser(mtd_parser_tplink_safeloader); +MODULE_DESCRIPTION("TP-Link Safeloader partitions parser"); MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile index 5e68468b72fc..5dd9c35f6b6f 100644 --- a/drivers/mtd/spi-nor/Makefile +++ b/drivers/mtd/spi-nor/Makefile @@ -13,7 +13,6 @@ spi-nor-objs += micron-st.o spi-nor-objs += spansion.o spi-nor-objs += sst.o spi-nor-objs += winbond.o -spi-nor-objs += xilinx.o spi-nor-objs += xmc.o spi-nor-$(CONFIG_DEBUG_FS) += debugfs.o obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 028514c6996f..e0c4efc424f4 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1463,14 +1463,6 @@ static void spi_nor_unlock_and_unprep_rd(struct spi_nor *nor, loff_t start, size spi_nor_unprep(nor); } -static u32 spi_nor_convert_addr(struct spi_nor *nor, loff_t addr) -{ - if (!nor->params->convert_addr) - return addr; - - return nor->params->convert_addr(nor, addr); -} - /* * Initiate the erasure of a single sector */ @@ -1478,8 +1470,6 @@ int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) { int i; - addr = spi_nor_convert_addr(nor, addr); - if (nor->spimem) { struct spi_mem_op op = SPI_NOR_SECTOR_ERASE_OP(nor->erase_opcode, @@ -1986,7 +1976,6 @@ static const struct spi_nor_manufacturer *manufacturers[] = { &spi_nor_spansion, &spi_nor_sst, &spi_nor_winbond, - &spi_nor_xilinx, &spi_nor_xmc, }; @@ -2065,8 +2054,6 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, while (len) { loff_t addr = from; - addr = spi_nor_convert_addr(nor, addr); - ret = spi_nor_read_data(nor, addr, len, buf); if (ret == 0) { /* We shouldn't see 0-length reads */ @@ -2099,7 +2086,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct spi_nor *nor = mtd_to_spi_nor(mtd); - size_t page_offset, page_remain, i; + size_t i; ssize_t ret; u32 page_size = nor->params->page_size; @@ -2112,23 +2099,9 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, for (i = 0; i < len; ) { ssize_t written; loff_t addr = to + i; - - /* - * If page_size is a power of two, the offset can be quickly - * calculated with an AND operation. On the other cases we - * need to do a modulus operation (more expensive). - */ - if (is_power_of_2(page_size)) { - page_offset = addr & (page_size - 1); - } else { - u64 aux = addr; - - page_offset = do_div(aux, page_size); - } + size_t page_offset = addr & (page_size - 1); /* the size of data remaining on the first page */ - page_remain = min_t(size_t, page_size - page_offset, len - i); - - addr = spi_nor_convert_addr(nor, addr); + size_t page_remain = min_t(size_t, page_size - page_offset, len - i); ret = spi_nor_lock_device(nor); if (ret) @@ -2581,8 +2554,51 @@ static int spi_nor_select_erase(struct spi_nor *nor) return 0; } -static int spi_nor_default_setup(struct spi_nor *nor, - const struct spi_nor_hwcaps *hwcaps) +static int spi_nor_set_addr_nbytes(struct spi_nor *nor) +{ + if (nor->params->addr_nbytes) { + nor->addr_nbytes = nor->params->addr_nbytes; + } else if (nor->read_proto == SNOR_PROTO_8_8_8_DTR) { + /* + * In 8D-8D-8D mode, one byte takes half a cycle to transfer. So + * in this protocol an odd addr_nbytes cannot be used because + * then the address phase would only span a cycle and a half. + * Half a cycle would be left over. We would then have to start + * the dummy phase in the middle of a cycle and so too the data + * phase, and we will end the transaction with half a cycle left + * over. + * + * Force all 8D-8D-8D flashes to use an addr_nbytes of 4 to + * avoid this situation. + */ + nor->addr_nbytes = 4; + } else if (nor->info->addr_nbytes) { + nor->addr_nbytes = nor->info->addr_nbytes; + } else { + nor->addr_nbytes = 3; + } + + if (nor->addr_nbytes == 3 && nor->params->size > 0x1000000) { + /* enable 4-byte addressing if the device exceeds 16MiB */ + nor->addr_nbytes = 4; + } + + if (nor->addr_nbytes > SPI_NOR_MAX_ADDR_NBYTES) { + dev_dbg(nor->dev, "The number of address bytes is too large: %u\n", + nor->addr_nbytes); + return -EINVAL; + } + + /* Set 4byte opcodes when possible. */ + if (nor->addr_nbytes == 4 && nor->flags & SNOR_F_4B_OPCODES && + !(nor->flags & SNOR_F_HAS_4BAIT)) + spi_nor_set_4byte_opcodes(nor); + + return 0; +} + +static int spi_nor_setup(struct spi_nor *nor, + const struct spi_nor_hwcaps *hwcaps) { struct spi_nor_flash_parameter *params = nor->params; u32 ignored_mask, shared_mask; @@ -2639,64 +2655,6 @@ static int spi_nor_default_setup(struct spi_nor *nor, return err; } - return 0; -} - -static int spi_nor_set_addr_nbytes(struct spi_nor *nor) -{ - if (nor->params->addr_nbytes) { - nor->addr_nbytes = nor->params->addr_nbytes; - } else if (nor->read_proto == SNOR_PROTO_8_8_8_DTR) { - /* - * In 8D-8D-8D mode, one byte takes half a cycle to transfer. So - * in this protocol an odd addr_nbytes cannot be used because - * then the address phase would only span a cycle and a half. - * Half a cycle would be left over. We would then have to start - * the dummy phase in the middle of a cycle and so too the data - * phase, and we will end the transaction with half a cycle left - * over. - * - * Force all 8D-8D-8D flashes to use an addr_nbytes of 4 to - * avoid this situation. - */ - nor->addr_nbytes = 4; - } else if (nor->info->addr_nbytes) { - nor->addr_nbytes = nor->info->addr_nbytes; - } else { - nor->addr_nbytes = 3; - } - - if (nor->addr_nbytes == 3 && nor->params->size > 0x1000000) { - /* enable 4-byte addressing if the device exceeds 16MiB */ - nor->addr_nbytes = 4; - } - - if (nor->addr_nbytes > SPI_NOR_MAX_ADDR_NBYTES) { - dev_dbg(nor->dev, "The number of address bytes is too large: %u\n", - nor->addr_nbytes); - return -EINVAL; - } - - /* Set 4byte opcodes when possible. */ - if (nor->addr_nbytes == 4 && nor->flags & SNOR_F_4B_OPCODES && - !(nor->flags & SNOR_F_HAS_4BAIT)) - spi_nor_set_4byte_opcodes(nor); - - return 0; -} - -static int spi_nor_setup(struct spi_nor *nor, - const struct spi_nor_hwcaps *hwcaps) -{ - int ret; - - if (nor->params->setup) - ret = nor->params->setup(nor, hwcaps); - else - ret = spi_nor_default_setup(nor, hwcaps); - if (ret) - return ret; - return spi_nor_set_addr_nbytes(nor); } @@ -2965,15 +2923,10 @@ static void spi_nor_init_default_params(struct spi_nor *nor) params->page_size = info->page_size ?: SPI_NOR_DEFAULT_PAGE_SIZE; params->n_banks = info->n_banks ?: SPI_NOR_DEFAULT_N_BANKS; - if (!(info->flags & SPI_NOR_NO_FR)) { - /* Default to Fast Read for DT and non-DT platform devices. */ + /* Default to Fast Read for non-DT and enable it if requested by DT. */ + if (!np || of_property_read_bool(np, "m25p,fast-read")) params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST; - /* Mask out Fast Read if not requested at DT instantiation. */ - if (np && !of_property_read_bool(np, "m25p,fast-read")) - params->hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST; - } - /* (Fast) Read settings. */ params->hwcaps.mask |= SNOR_HWCAPS_READ; spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ], @@ -3055,7 +3008,14 @@ static int spi_nor_init_params(struct spi_nor *nor) spi_nor_init_params_deprecated(nor); } - return spi_nor_late_init_params(nor); + ret = spi_nor_late_init_params(nor); + if (ret) + return ret; + + if (WARN_ON(!is_power_of_2(nor->params->page_size))) + return -EINVAL; + + return 0; } /** spi_nor_set_octal_dtr() - enable or disable Octal DTR I/O. @@ -3338,32 +3298,28 @@ static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor, if (name) info = spi_nor_match_name(nor, name); - /* Try to auto-detect if chip name wasn't specified or not found */ - if (!info) - return spi_nor_detect(nor); - /* - * If caller has specified name of flash model that can normally be - * detected using JEDEC, let's verify it. + * Auto-detect if chip name wasn't specified or not found, or the chip + * has an ID. If the chip supposedly has an ID, we also do an + * auto-detection to compare it later. */ - if (name && info->id) { + if (!info || info->id) { const struct flash_info *jinfo; jinfo = spi_nor_detect(nor); - if (IS_ERR(jinfo)) { + if (IS_ERR(jinfo)) return jinfo; - } else if (jinfo != info) { - /* - * JEDEC knows better, so overwrite platform ID. We - * can't trust partitions any longer, but we'll let - * mtd apply them anyway, since some partitions may be - * marked read-only, and we don't want to loose that - * information, even if it's not 100% accurate. - */ + + /* + * If caller has specified name of flash model that can normally + * be detected using JEDEC, let's verify it. + */ + if (info && jinfo != info) dev_warn(nor->dev, "found %s, expected %s\n", jinfo->name, info->name); - info = jinfo; - } + + /* If info was set before, JEDEC knows better. */ + info = jinfo; } return info; diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 442786685515..1516b6d0dc37 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -366,13 +366,6 @@ struct spi_nor_otp { * @set_octal_dtr: enables or disables SPI NOR octal DTR mode. * @quad_enable: enables SPI NOR quad mode. * @set_4byte_addr_mode: puts the SPI NOR in 4 byte addressing mode. - * @convert_addr: converts an absolute address into something the flash - * will understand. Particularly useful when pagesize is - * not a power-of-2. - * @setup: (optional) configures the SPI NOR memory. Useful for - * SPI NOR flashes that have peculiarities to the SPI NOR - * standard e.g. different opcodes, specific address - * calculation, page size, etc. * @ready: (optional) flashes might use a different mechanism * than reading the status register to indicate they * are ready for a new command @@ -403,8 +396,6 @@ struct spi_nor_flash_parameter { int (*set_octal_dtr)(struct spi_nor *nor, bool enable); int (*quad_enable)(struct spi_nor *nor); int (*set_4byte_addr_mode)(struct spi_nor *nor, bool enable); - u32 (*convert_addr)(struct spi_nor *nor, u32 addr); - int (*setup)(struct spi_nor *nor, const struct spi_nor_hwcaps *hwcaps); int (*ready)(struct spi_nor *nor); const struct spi_nor_locking_ops *locking_ops; @@ -479,7 +470,6 @@ struct spi_nor_id { * Usually these will power-up in a write-protected * state. * SPI_NOR_NO_ERASE: no erase command needed. - * SPI_NOR_NO_FR: can't do fastread. * SPI_NOR_QUAD_PP: flash supports Quad Input Page Program. * SPI_NOR_RWW: flash supports reads while write. * @@ -528,7 +518,6 @@ struct flash_info { #define SPI_NOR_BP3_SR_BIT6 BIT(4) #define SPI_NOR_SWP_IS_VOLATILE BIT(5) #define SPI_NOR_NO_ERASE BIT(6) -#define SPI_NOR_NO_FR BIT(7) #define SPI_NOR_QUAD_PP BIT(8) #define SPI_NOR_RWW BIT(9) @@ -603,7 +592,6 @@ extern const struct spi_nor_manufacturer spi_nor_st; extern const struct spi_nor_manufacturer spi_nor_spansion; extern const struct spi_nor_manufacturer spi_nor_sst; extern const struct spi_nor_manufacturer spi_nor_winbond; -extern const struct spi_nor_manufacturer spi_nor_xilinx; extern const struct spi_nor_manufacturer spi_nor_xmc; extern const struct attribute_group *spi_nor_sysfs_groups[]; diff --git a/drivers/mtd/spi-nor/everspin.c b/drivers/mtd/spi-nor/everspin.c index 5f321e24ae7d..add37104d673 100644 --- a/drivers/mtd/spi-nor/everspin.c +++ b/drivers/mtd/spi-nor/everspin.c @@ -14,28 +14,39 @@ static const struct flash_info everspin_nor_parts[] = { .size = SZ_16K, .sector_size = SZ_16K, .addr_nbytes = 2, - .flags = SPI_NOR_NO_ERASE | SPI_NOR_NO_FR, + .flags = SPI_NOR_NO_ERASE, }, { .name = "mr25h256", .size = SZ_32K, .sector_size = SZ_32K, .addr_nbytes = 2, - .flags = SPI_NOR_NO_ERASE | SPI_NOR_NO_FR, + .flags = SPI_NOR_NO_ERASE, }, { .name = "mr25h10", .size = SZ_128K, .sector_size = SZ_128K, - .flags = SPI_NOR_NO_ERASE | SPI_NOR_NO_FR, + .flags = SPI_NOR_NO_ERASE, }, { .name = "mr25h40", .size = SZ_512K, .sector_size = SZ_512K, - .flags = SPI_NOR_NO_ERASE | SPI_NOR_NO_FR, + .flags = SPI_NOR_NO_ERASE, } }; +static void everspin_nor_default_init(struct spi_nor *nor) +{ + /* Everspin FRAMs don't support the fast read opcode. */ + nor->params->hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST; +} + +static const struct spi_nor_fixups everspin_nor_fixups = { + .default_init = everspin_nor_default_init, +}; + const struct spi_nor_manufacturer spi_nor_everspin = { .name = "everspin", .parts = everspin_nor_parts, .nparts = ARRAY_SIZE(everspin_nor_parts), + .fixups = &everspin_nor_fixups, }; diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index 142fb27b2ea9..e065e4fd42a3 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -105,7 +105,9 @@ static const struct flash_info winbond_nor_parts[] = { }, { .id = SNOR_ID(0xef, 0x40, 0x18), .name = "w25q128", + .size = SZ_16M, .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, + .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, }, { .id = SNOR_ID(0xef, 0x40, 0x19), .name = "w25q256", diff --git a/drivers/mtd/spi-nor/xilinx.c b/drivers/mtd/spi-nor/xilinx.c deleted file mode 100644 index f99118c691b0..000000000000 --- a/drivers/mtd/spi-nor/xilinx.c +++ /dev/null @@ -1,169 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2005, Intec Automation Inc. - * Copyright (C) 2014, Freescale Semiconductor, Inc. - */ - -#include - -#include "core.h" - -#define XILINX_OP_SE 0x50 /* Sector erase */ -#define XILINX_OP_PP 0x82 /* Page program */ -#define XILINX_OP_RDSR 0xd7 /* Read status register */ - -#define XSR_PAGESIZE BIT(0) /* Page size in Po2 or Linear */ -#define XSR_RDY BIT(7) /* Ready */ - -#define XILINX_RDSR_OP(buf) \ - SPI_MEM_OP(SPI_MEM_OP_CMD(XILINX_OP_RDSR, 0), \ - SPI_MEM_OP_NO_ADDR, \ - SPI_MEM_OP_NO_DUMMY, \ - SPI_MEM_OP_DATA_IN(1, buf, 0)) - -#define S3AN_FLASH(_id, _name, _n_sectors, _page_size) \ - .id = _id, \ - .name = _name, \ - .size = 8 * (_page_size) * (_n_sectors), \ - .sector_size = (8 * (_page_size)), \ - .page_size = (_page_size), \ - .flags = SPI_NOR_NO_FR - -/* Xilinx S3AN share MFR with Atmel SPI NOR */ -static const struct flash_info xilinx_nor_parts[] = { - /* Xilinx S3AN Internal Flash */ - { S3AN_FLASH(SNOR_ID(0x1f, 0x22, 0x00), "3S50AN", 64, 264) }, - { S3AN_FLASH(SNOR_ID(0x1f, 0x24, 0x00), "3S200AN", 256, 264) }, - { S3AN_FLASH(SNOR_ID(0x1f, 0x24, 0x00), "3S400AN", 256, 264) }, - { S3AN_FLASH(SNOR_ID(0x1f, 0x25, 0x00), "3S700AN", 512, 264) }, - { S3AN_FLASH(SNOR_ID(0x1f, 0x26, 0x00), "3S1400AN", 512, 528) }, -}; - -/* - * This code converts an address to the Default Address Mode, that has non - * power of two page sizes. We must support this mode because it is the default - * mode supported by Xilinx tools, it can access the whole flash area and - * changing over to the Power-of-two mode is irreversible and corrupts the - * original data. - * Addr can safely be unsigned int, the biggest S3AN device is smaller than - * 4 MiB. - */ -static u32 s3an_nor_convert_addr(struct spi_nor *nor, u32 addr) -{ - u32 page_size = nor->params->page_size; - u32 offset, page; - - offset = addr % page_size; - page = addr / page_size; - page <<= (page_size > 512) ? 10 : 9; - - return page | offset; -} - -/** - * xilinx_nor_read_sr() - Read the Status Register on S3AN flashes. - * @nor: pointer to 'struct spi_nor'. - * @sr: pointer to a DMA-able buffer where the value of the - * Status Register will be written. - * - * Return: 0 on success, -errno otherwise. - */ -static int xilinx_nor_read_sr(struct spi_nor *nor, u8 *sr) -{ - int ret; - - if (nor->spimem) { - struct spi_mem_op op = XILINX_RDSR_OP(sr); - - spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); - - ret = spi_mem_exec_op(nor->spimem, &op); - } else { - ret = spi_nor_controller_ops_read_reg(nor, XILINX_OP_RDSR, sr, - 1); - } - - if (ret) - dev_dbg(nor->dev, "error %d reading SR\n", ret); - - return ret; -} - -/** - * xilinx_nor_sr_ready() - Query the Status Register of the S3AN flash to see - * if the flash is ready for new commands. - * @nor: pointer to 'struct spi_nor'. - * - * Return: 1 if ready, 0 if not ready, -errno on errors. - */ -static int xilinx_nor_sr_ready(struct spi_nor *nor) -{ - int ret; - - ret = xilinx_nor_read_sr(nor, nor->bouncebuf); - if (ret) - return ret; - - return !!(nor->bouncebuf[0] & XSR_RDY); -} - -static int xilinx_nor_setup(struct spi_nor *nor, - const struct spi_nor_hwcaps *hwcaps) -{ - u32 page_size; - int ret; - - ret = xilinx_nor_read_sr(nor, nor->bouncebuf); - if (ret) - return ret; - - nor->erase_opcode = XILINX_OP_SE; - nor->program_opcode = XILINX_OP_PP; - nor->read_opcode = SPINOR_OP_READ; - nor->flags |= SNOR_F_NO_OP_CHIP_ERASE; - - /* - * This flashes have a page size of 264 or 528 bytes (known as - * Default addressing mode). It can be changed to a more standard - * Power of two mode where the page size is 256/512. This comes - * with a price: there is 3% less of space, the data is corrupted - * and the page size cannot be changed back to default addressing - * mode. - * - * The current addressing mode can be read from the XRDSR register - * and should not be changed, because is a destructive operation. - */ - if (nor->bouncebuf[0] & XSR_PAGESIZE) { - /* Flash in Power of 2 mode */ - page_size = (nor->params->page_size == 264) ? 256 : 512; - nor->params->page_size = page_size; - nor->mtd.writebufsize = page_size; - nor->params->size = nor->info->size; - nor->mtd.erasesize = 8 * page_size; - } else { - /* Flash in Default addressing mode */ - nor->params->convert_addr = s3an_nor_convert_addr; - nor->mtd.erasesize = nor->info->sector_size; - } - - return 0; -} - -static int xilinx_nor_late_init(struct spi_nor *nor) -{ - nor->params->setup = xilinx_nor_setup; - nor->params->ready = xilinx_nor_sr_ready; - - return 0; -} - -static const struct spi_nor_fixups xilinx_nor_fixups = { - .late_init = xilinx_nor_late_init, -}; - -const struct spi_nor_manufacturer spi_nor_xilinx = { - .name = "xilinx", - .parts = xilinx_nor_parts, - .nparts = ARRAY_SIZE(xilinx_nor_parts), - .fixups = &xilinx_nor_fixups, -}; diff --git a/drivers/mtd/tests/Makefile b/drivers/mtd/tests/Makefile index 5de0378f90db..7dae831ee8b6 100644 --- a/drivers/mtd/tests/Makefile +++ b/drivers/mtd/tests/Makefile @@ -1,19 +1,19 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_MTD_TESTS) += mtd_oobtest.o -obj-$(CONFIG_MTD_TESTS) += mtd_pagetest.o -obj-$(CONFIG_MTD_TESTS) += mtd_readtest.o -obj-$(CONFIG_MTD_TESTS) += mtd_speedtest.o -obj-$(CONFIG_MTD_TESTS) += mtd_stresstest.o -obj-$(CONFIG_MTD_TESTS) += mtd_subpagetest.o -obj-$(CONFIG_MTD_TESTS) += mtd_torturetest.o -obj-$(CONFIG_MTD_TESTS) += mtd_nandecctest.o -obj-$(CONFIG_MTD_TESTS) += mtd_nandbiterrs.o +obj-$(CONFIG_MTD_TESTS) += mtd_oobtest.o mtd_test.o +obj-$(CONFIG_MTD_TESTS) += mtd_pagetest.o mtd_test.o +obj-$(CONFIG_MTD_TESTS) += mtd_readtest.o mtd_test.o +obj-$(CONFIG_MTD_TESTS) += mtd_speedtest.o mtd_test.o +obj-$(CONFIG_MTD_TESTS) += mtd_stresstest.o mtd_test.o +obj-$(CONFIG_MTD_TESTS) += mtd_subpagetest.o mtd_test.o +obj-$(CONFIG_MTD_TESTS) += mtd_torturetest.o mtd_test.o +obj-$(CONFIG_MTD_TESTS) += mtd_nandecctest.o mtd_test.o +obj-$(CONFIG_MTD_TESTS) += mtd_nandbiterrs.o mtd_test.o -mtd_oobtest-objs := oobtest.o mtd_test.o -mtd_pagetest-objs := pagetest.o mtd_test.o -mtd_readtest-objs := readtest.o mtd_test.o -mtd_speedtest-objs := speedtest.o mtd_test.o -mtd_stresstest-objs := stresstest.o mtd_test.o -mtd_subpagetest-objs := subpagetest.o mtd_test.o -mtd_torturetest-objs := torturetest.o mtd_test.o -mtd_nandbiterrs-objs := nandbiterrs.o mtd_test.o +mtd_oobtest-objs := oobtest.o +mtd_pagetest-objs := pagetest.o +mtd_readtest-objs := readtest.o +mtd_speedtest-objs := speedtest.o +mtd_stresstest-objs := stresstest.o +mtd_subpagetest-objs := subpagetest.o +mtd_torturetest-objs := torturetest.o +mtd_nandbiterrs-objs := nandbiterrs.o diff --git a/drivers/mtd/tests/mtd_test.c b/drivers/mtd/tests/mtd_test.c index c84250beffdc..f391e0300cdc 100644 --- a/drivers/mtd/tests/mtd_test.c +++ b/drivers/mtd/tests/mtd_test.c @@ -25,6 +25,7 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum) return 0; } +EXPORT_SYMBOL_GPL(mtdtest_erase_eraseblock); static int is_block_bad(struct mtd_info *mtd, unsigned int ebnum) { @@ -57,6 +58,7 @@ int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, return 0; } +EXPORT_SYMBOL_GPL(mtdtest_scan_for_bad_eraseblocks); int mtdtest_erase_good_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, unsigned int eb, int ebcnt) @@ -75,6 +77,7 @@ int mtdtest_erase_good_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, return 0; } +EXPORT_SYMBOL_GPL(mtdtest_erase_good_eraseblocks); int mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf) { @@ -92,6 +95,7 @@ int mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf) return err; } +EXPORT_SYMBOL_GPL(mtdtest_read); int mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size, const void *buf) @@ -107,3 +111,8 @@ int mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size, return err; } +EXPORT_SYMBOL_GPL(mtdtest_write); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MTD function test helpers"); +MODULE_AUTHOR("Akinobu Mita"); diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index e79c06d65bb7..423dcd190906 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -751,7 +751,7 @@ static struct arena_info *alloc_arena(struct btt *btt, size_t size, u64 logsize, mapsize, datasize; u64 available = size; - arena = kzalloc(sizeof(struct arena_info), GFP_KERNEL); + arena = kzalloc(sizeof(*arena), GFP_KERNEL); if (!arena) return NULL; arena->nd_btt = btt->nd_btt; @@ -978,7 +978,7 @@ static int btt_arena_write_layout(struct arena_info *arena) if (ret) return ret; - super = kzalloc(sizeof(struct btt_sb), GFP_NOIO); + super = kzalloc(sizeof(*super), GFP_NOIO); if (!super) return -ENOMEM; @@ -1716,6 +1716,7 @@ static void __exit nd_btt_exit(void) MODULE_ALIAS_ND_DEVICE(ND_DEVICE_BTT); MODULE_AUTHOR("Vishal Verma "); +MODULE_DESCRIPTION("NVDIMM Block Translation Table"); MODULE_LICENSE("GPL v2"); module_init(nd_btt_init); module_exit(nd_btt_exit); diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c index 2023a661bbb0..eaa796629c27 100644 --- a/drivers/nvdimm/core.c +++ b/drivers/nvdimm/core.c @@ -540,6 +540,7 @@ static __exit void libnvdimm_exit(void) nvdimm_devs_exit(); } +MODULE_DESCRIPTION("NVDIMM (Non-Volatile Memory Device) core"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Intel Corporation"); subsys_initcall(libnvdimm_init); diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c index 4cd18be9d0e9..008b9aae74ff 100644 --- a/drivers/nvdimm/e820.c +++ b/drivers/nvdimm/e820.c @@ -69,5 +69,6 @@ static struct platform_driver e820_pmem_driver = { module_platform_driver(e820_pmem_driver); MODULE_ALIAS("platform:e820_pmem*"); +MODULE_DESCRIPTION("NVDIMM support for e820 type-12 memory"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Intel Corporation"); diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c index 1f8c667c6f1e..35c8fbbba10e 100644 --- a/drivers/nvdimm/nd_virtio.c +++ b/drivers/nvdimm/nd_virtio.c @@ -123,4 +123,5 @@ int async_pmem_flush(struct nd_region *nd_region, struct bio *bio) return 0; }; EXPORT_SYMBOL_GPL(async_pmem_flush); +MODULE_DESCRIPTION("Virtio Persistent Memory Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/nvdimm/of_pmem.c b/drivers/nvdimm/of_pmem.c index d3fca0ab6290..5134a8d08bf9 100644 --- a/drivers/nvdimm/of_pmem.c +++ b/drivers/nvdimm/of_pmem.c @@ -111,5 +111,6 @@ static struct platform_driver of_pmem_region_driver = { module_platform_driver(of_pmem_region_driver); MODULE_DEVICE_TABLE(of, of_pmem_region_match); +MODULE_DESCRIPTION("NVDIMM Device Tree support"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("IBM Corporation"); diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 1dd74c969d5a..1ae8b2351654 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -766,4 +766,5 @@ static struct nd_device_driver nd_pmem_driver = { module_nd_driver(nd_pmem_driver); MODULE_AUTHOR("Ross Zwisler "); +MODULE_DESCRIPTION("NVDIMM Persistent Memory Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c index 694349be9d0a..573a41869c15 100644 --- a/drivers/pci/hotplug/pnv_php.c +++ b/drivers/pci/hotplug/pnv_php.c @@ -40,7 +40,6 @@ static void pnv_php_disable_irq(struct pnv_php_slot *php_slot, bool disable_device) { struct pci_dev *pdev = php_slot->pdev; - int irq = php_slot->irq; u16 ctrl; if (php_slot->irq > 0) { @@ -59,7 +58,7 @@ static void pnv_php_disable_irq(struct pnv_php_slot *php_slot, php_slot->wq = NULL; } - if (disable_device || irq > 0) { + if (disable_device) { if (pdev->msix_enabled) pci_disable_msix(pdev); else if (pdev->msi_enabled) diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c index 029efe16f8cc..6ecc656abc44 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c @@ -249,7 +249,9 @@ PIN_DECL_2(E26, GPIOD3, RGMII3RXD3, RMII3RXER); FUNC_GROUP_DECL(RGMII3, H24, J22, H22, H23, G22, F22, G23, G24, F23, F26, F25, E26); -FUNC_GROUP_DECL(RMII3, H24, J22, H22, H23, G23, F23, F26, F25, E26); +GROUP_DECL(RMII3, H24, J22, H22, H23, G23, F23, F26, F25, E26); +GROUP_DECL(NCSI3, J22, H22, H23, G23, F23, F26, F25, E26); +FUNC_DECL_2(RMII3, RMII3, NCSI3); #define F24 28 SIG_EXPR_LIST_DECL_SESG(F24, NCTS3, NCTS3, SIG_DESC_SET(SCU410, 28)); @@ -355,7 +357,9 @@ FUNC_GROUP_DECL(NRTS4, B24); FUNC_GROUP_DECL(RGMII4, F24, E23, E24, E25, D26, D24, C25, C26, C24, B26, B25, B24); -FUNC_GROUP_DECL(RMII4, F24, E23, E24, E25, C25, C24, B26, B25, B24); +GROUP_DECL(RMII4, F24, E23, E24, E25, C25, C24, B26, B25, B24); +GROUP_DECL(NCSI4, E23, E24, E25, C25, C24, B26, B25, B24); +FUNC_DECL_2(RMII4, RMII4, NCSI4); #define D22 40 SIG_EXPR_LIST_DECL_SESG(D22, SD1CLK, SD1, SIG_DESC_SET(SCU414, 8)); @@ -1977,6 +1981,8 @@ static const struct aspeed_pin_group aspeed_g6_groups[] = { ASPEED_PINCTRL_GROUP(MDIO2), ASPEED_PINCTRL_GROUP(MDIO3), ASPEED_PINCTRL_GROUP(MDIO4), + ASPEED_PINCTRL_GROUP(NCSI3), + ASPEED_PINCTRL_GROUP(NCSI4), ASPEED_PINCTRL_GROUP(NCTS1), ASPEED_PINCTRL_GROUP(NCTS2), ASPEED_PINCTRL_GROUP(NCTS3), diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c index 27fd54795791..184641e221d4 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -752,7 +753,7 @@ static void bcm2835_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, int irq = irq_find_mapping(chip->irq.domain, offset); seq_printf(s, "function %s in %s; irq %d (%s)", - fname, value ? "hi" : "lo", + fname, str_hi_lo(value), irq, irq_type_names[pc->irq_type[offset]]); } @@ -1428,7 +1429,7 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) } dev_info(dev, "GPIO_OUT persistence: %s\n", - persist_gpio_outputs ? "yes" : "no"); + str_yes_no(persist_gpio_outputs)); return 0; diff --git a/drivers/pinctrl/bcm/pinctrl-bcm4908.c b/drivers/pinctrl/bcm/pinctrl-bcm4908.c index cdfa165fc033..f190e0997f1f 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm4908.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm4908.c @@ -559,5 +559,6 @@ static struct platform_driver bcm4908_pinctrl_driver = { module_platform_driver(bcm4908_pinctrl_driver); MODULE_AUTHOR("RafaÅ‚ MiÅ‚ecki"); +MODULE_DESCRIPTION("Broadcom BCM4908 pinmux driver"); MODULE_LICENSE("GPL v2"); MODULE_DEVICE_TABLE(of, bcm4908_pinctrl_of_match_table); diff --git a/drivers/pinctrl/bcm/pinctrl-bcm63xx.c b/drivers/pinctrl/bcm/pinctrl-bcm63xx.c index e1285fe2fbc0..59d2ce8462d8 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm63xx.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm63xx.c @@ -67,7 +67,6 @@ int bcm63xx_pinctrl_probe(struct platform_device *pdev, { struct device *dev = &pdev->dev; struct bcm63xx_pinctrl *pc; - struct device_node *node; int err; pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); @@ -94,12 +93,11 @@ int bcm63xx_pinctrl_probe(struct platform_device *pdev, if (IS_ERR(pc->pctl_dev)) return PTR_ERR(pc->pctl_dev); - for_each_child_of_node(dev->parent->of_node, node) { + for_each_child_of_node_scoped(dev->parent->of_node, node) { if (of_match_node(bcm63xx_gpio_of_match, node)) { err = bcm63xx_gpio_probe(dev, node, soc, pc); if (err) { dev_err(dev, "could not add GPIO chip\n"); - of_node_put(node); return err; } } diff --git a/drivers/pinctrl/berlin/berlin.c b/drivers/pinctrl/berlin/berlin.c index 9550cc8095c2..c372a2a24be4 100644 --- a/drivers/pinctrl/berlin/berlin.c +++ b/drivers/pinctrl/berlin/berlin.c @@ -27,7 +27,7 @@ struct berlin_pinctrl { struct regmap *regmap; struct device *dev; const struct berlin_pinctrl_desc *desc; - struct berlin_pinctrl_function *functions; + struct pinfunction *functions; unsigned nfunctions; struct pinctrl_dev *pctrl_dev; }; @@ -120,12 +120,12 @@ static const char *berlin_pinmux_get_function_name(struct pinctrl_dev *pctrl_dev static int berlin_pinmux_get_function_groups(struct pinctrl_dev *pctrl_dev, unsigned function, const char * const **groups, - unsigned * const num_groups) + unsigned * const ngroups) { struct berlin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev); *groups = pctrl->functions[function].groups; - *num_groups = pctrl->functions[function].ngroups; + *ngroups = pctrl->functions[function].ngroups; return 0; } @@ -153,7 +153,7 @@ static int berlin_pinmux_set(struct pinctrl_dev *pctrl_dev, { struct berlin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev); const struct berlin_desc_group *group_desc = pctrl->desc->groups + group; - struct berlin_pinctrl_function *func = pctrl->functions + function; + struct pinfunction *func = pctrl->functions + function; struct berlin_desc_function *function_desc = berlin_pinctrl_find_function_by_name(pctrl, group_desc, func->name); @@ -180,7 +180,7 @@ static const struct pinmux_ops berlin_pinmux_ops = { static int berlin_pinctrl_add_function(struct berlin_pinctrl *pctrl, const char *name) { - struct berlin_pinctrl_function *function = pctrl->functions; + struct pinfunction *function = pctrl->functions; while (function->name) { if (!strcmp(function->name, name)) { @@ -214,8 +214,7 @@ static int berlin_pinctrl_build_state(struct platform_device *pdev) } /* we will reallocate later */ - pctrl->functions = kcalloc(max_functions, - sizeof(*pctrl->functions), GFP_KERNEL); + pctrl->functions = kcalloc(max_functions, sizeof(*pctrl->functions), GFP_KERNEL); if (!pctrl->functions) return -ENOMEM; @@ -242,8 +241,7 @@ static int berlin_pinctrl_build_state(struct platform_device *pdev) desc_function = desc_group->functions; while (desc_function->name) { - struct berlin_pinctrl_function - *function = pctrl->functions; + struct pinfunction *function = pctrl->functions; const char **groups; bool found = false; @@ -264,16 +262,15 @@ static int berlin_pinctrl_build_state(struct platform_device *pdev) function->groups = devm_kcalloc(&pdev->dev, function->ngroups, - sizeof(char *), + sizeof(*function->groups), GFP_KERNEL); - if (!function->groups) { kfree(pctrl->functions); return -ENOMEM; } } - groups = function->groups; + groups = (const char **)function->groups; while (*groups) groups++; diff --git a/drivers/pinctrl/berlin/berlin.h b/drivers/pinctrl/berlin/berlin.h index d7787754d1ed..231aab61d415 100644 --- a/drivers/pinctrl/berlin/berlin.h +++ b/drivers/pinctrl/berlin/berlin.h @@ -28,12 +28,6 @@ struct berlin_pinctrl_desc { unsigned ngroups; }; -struct berlin_pinctrl_function { - const char *name; - const char **groups; - unsigned ngroups; -}; - #define BERLIN_PINCTRL_GROUP(_name, _offset, _width, _lsb, ...) \ { \ .name = _name, \ diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index f424a57f0013..314ab93d7691 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -1670,13 +1670,23 @@ static int pinctrl_pins_show(struct seq_file *s, void *what) seq_printf(s, "pin %d (%s) ", pin, desc->name); #ifdef CONFIG_GPIOLIB + gdev = NULL; gpio_num = -1; list_for_each_entry(range, &pctldev->gpio_ranges, node) { - if ((pin >= range->pin_base) && - (pin < (range->pin_base + range->npins))) { - gpio_num = range->base + (pin - range->pin_base); - break; + if (range->pins != NULL) { + for (int i = 0; i < range->npins; ++i) { + if (range->pins[i] == pin) { + gpio_num = range->base + i; + break; + } + } + } else if ((pin >= range->pin_base) && + (pin < (range->pin_base + range->npins))) { + gpio_num = + range->base + (pin - range->pin_base); } + if (gpio_num != -1) + break; } if (gpio_num >= 0) /* @@ -2080,6 +2090,14 @@ out_err: return ERR_PTR(ret); } +static void pinctrl_uninit_controller(struct pinctrl_dev *pctldev, struct pinctrl_desc *pctldesc) +{ + pinctrl_free_pindescs(pctldev, pctldesc->pins, + pctldesc->npins); + mutex_destroy(&pctldev->mutex); + kfree(pctldev); +} + static int pinctrl_claim_hogs(struct pinctrl_dev *pctldev) { pctldev->p = create_pinctrl(pctldev->dev, pctldev); @@ -2160,8 +2178,10 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, return pctldev; error = pinctrl_enable(pctldev); - if (error) + if (error) { + pinctrl_uninit_controller(pctldev, pctldesc); return ERR_PTR(error); + } return pctldev; } diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 837fd5bd903d..4e07707d2435 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -206,7 +206,7 @@ struct group_desc { void *data; }; -/* Convenience macro to define a generic pin group descriptor */ +/* Convenient macro to define a generic pin group descriptor */ #define PINCTRL_GROUP_DESC(_name, _pins, _num_pins, _data) \ (struct group_desc) { \ .grp = PINCTRL_PINGROUP(_name, _pins, _num_pins), \ diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index 27bdc548f3a7..3b59d7189004 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -7,6 +7,17 @@ config PINCTRL_IMX select PINCONF select REGMAP +config PINCTRL_IMX_SCMI + tristate "i.MX95 pinctrl driver using SCMI protocol interface" + depends on ARM_SCMI_PROTOCOL && OF || COMPILE_TEST + select PINMUX + select GENERIC_PINCONF + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + help + i.MX95 SCMI firmware provides pinctrl protocol. This driver + utilizes the SCMI interface to do pinctrl configuration. + config PINCTRL_IMX_SCU tristate depends on IMX_SCU @@ -184,6 +195,13 @@ config PINCTRL_IMXRT1050 help Say Y here to enable the imxrt1050 pinctrl driver +config PINCTRL_IMX91 + tristate "IMX91 pinctrl driver" + depends on ARCH_MXC + select PINCTRL_IMX + help + Say Y here to enable the imx91 pinctrl driver + config PINCTRL_IMX93 tristate "IMX93 pinctrl driver" depends on ARCH_MXC diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile index 647dff060477..d27085c2b4c4 100644 --- a/drivers/pinctrl/freescale/Makefile +++ b/drivers/pinctrl/freescale/Makefile @@ -2,6 +2,7 @@ # Freescale pin control drivers obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o obj-$(CONFIG_PINCTRL_IMX_SCU) += pinctrl-scu.o +obj-$(CONFIG_PINCTRL_IMX_SCMI) += pinctrl-imx-scmi.o obj-$(CONFIG_PINCTRL_IMX1_CORE) += pinctrl-imx1-core.o obj-$(CONFIG_PINCTRL_IMX1) += pinctrl-imx1.o obj-$(CONFIG_PINCTRL_IMX27) += pinctrl-imx27.o @@ -25,6 +26,7 @@ obj-$(CONFIG_PINCTRL_IMX8QM) += pinctrl-imx8qm.o obj-$(CONFIG_PINCTRL_IMX8QXP) += pinctrl-imx8qxp.o obj-$(CONFIG_PINCTRL_IMX8DXL) += pinctrl-imx8dxl.o obj-$(CONFIG_PINCTRL_IMX8ULP) += pinctrl-imx8ulp.o +obj-$(CONFIG_PINCTRL_IMX91) += pinctrl-imx91.o obj-$(CONFIG_PINCTRL_IMX93) += pinctrl-imx93.o obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o diff --git a/drivers/pinctrl/freescale/pinctrl-imx-scmi.c b/drivers/pinctrl/freescale/pinctrl-imx-scmi.c new file mode 100644 index 000000000000..2991047535bc --- /dev/null +++ b/drivers/pinctrl/freescale/pinctrl-imx-scmi.c @@ -0,0 +1,357 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * System Control and Power Interface (SCMI) Protocol based i.MX pinctrl driver + * + * Copyright 2024 NXP + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../pinctrl-utils.h" +#include "../core.h" +#include "../pinconf.h" +#include "../pinmux.h" + +#define DRV_NAME "scmi-pinctrl-imx" + +struct scmi_pinctrl_imx { + struct device *dev; + struct scmi_protocol_handle *ph; + struct pinctrl_dev *pctldev; + struct pinctrl_desc pctl_desc; + const struct scmi_pinctrl_proto_ops *ops; +}; + +/* SCMI pin control types, aligned with SCMI firmware */ +#define IMX_SCMI_NUM_CFG 4 +#define IMX_SCMI_PIN_MUX 192 +#define IMX_SCMI_PIN_CONFIG 193 +#define IMX_SCMI_PIN_DAISY_ID 194 +#define IMX_SCMI_PIN_DAISY_CFG 195 + +#define IMX_SCMI_NO_PAD_CTL BIT(31) +#define IMX_SCMI_PAD_SION BIT(30) +#define IMX_SCMI_IOMUXC_CONFIG_SION BIT(4) + +#define IMX_SCMI_PIN_SIZE 24 + +#define IMX95_DAISY_OFF 0x408 + +static int pinctrl_scmi_imx_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + struct pinctrl_map *new_map; + const __be32 *list; + unsigned long *configs = NULL; + unsigned long cfg[IMX_SCMI_NUM_CFG]; + int map_num, size, pin_size, pin_id, num_pins; + int mux_reg, conf_reg, input_reg, mux_val, conf_val, input_val; + int i, j; + uint32_t ncfg; + static uint32_t daisy_off; + + if (!daisy_off) { + if (of_machine_is_compatible("fsl,imx95")) { + daisy_off = IMX95_DAISY_OFF; + } else { + dev_err(pctldev->dev, "platform not support scmi pinctrl\n"); + return -EINVAL; + } + } + + list = of_get_property(np, "fsl,pins", &size); + if (!list) { + dev_err(pctldev->dev, "no fsl,pins property in node %pOF\n", np); + return -EINVAL; + } + + pin_size = IMX_SCMI_PIN_SIZE; + + if (!size || size % pin_size) { + dev_err(pctldev->dev, "Invalid fsl,pins or pins property in node %pOF\n", np); + return -EINVAL; + } + + num_pins = size / pin_size; + map_num = num_pins; + + new_map = kmalloc_array(map_num, sizeof(struct pinctrl_map), + GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + *map = new_map; + *num_maps = map_num; + + /* create config map */ + for (i = 0; i < num_pins; i++) { + j = 0; + ncfg = IMX_SCMI_NUM_CFG; + mux_reg = be32_to_cpu(*list++); + conf_reg = be32_to_cpu(*list++); + input_reg = be32_to_cpu(*list++); + mux_val = be32_to_cpu(*list++); + input_val = be32_to_cpu(*list++); + conf_val = be32_to_cpu(*list++); + if (conf_val & IMX_SCMI_PAD_SION) + mux_val |= IMX_SCMI_IOMUXC_CONFIG_SION; + + pin_id = mux_reg / 4; + + cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_MUX, mux_val); + + if (!conf_reg || (conf_val & IMX_SCMI_NO_PAD_CTL)) + ncfg--; + else + cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_CONFIG, conf_val); + + if (!input_reg) { + ncfg -= 2; + } else { + cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_DAISY_ID, + (input_reg - daisy_off) / 4); + cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_DAISY_CFG, input_val); + } + + configs = kmemdup(cfg, ncfg * sizeof(unsigned long), GFP_KERNEL); + + new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; + new_map[i].data.configs.group_or_pin = pin_get_name(pctldev, pin_id); + new_map[i].data.configs.configs = configs; + new_map[i].data.configs.num_configs = ncfg; + } + + return 0; +} + +static void pinctrl_scmi_imx_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned int num_maps) +{ + kfree(map); +} + +static const struct pinctrl_ops pinctrl_scmi_imx_pinctrl_ops = { + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, + .dt_node_to_map = pinctrl_scmi_imx_dt_node_to_map, + .dt_free_map = pinctrl_scmi_imx_dt_free_map, +}; + +static int pinctrl_scmi_imx_func_set_mux(struct pinctrl_dev *pctldev, + unsigned int selector, unsigned int group) +{ + /* + * For i.MX SCMI PINCTRL , postpone the mux setting + * until config is set as they can be set together + * in one IPC call + */ + return 0; +} + +static const struct pinmux_ops pinctrl_scmi_imx_pinmux_ops = { + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, + .set_mux = pinctrl_scmi_imx_func_set_mux, +}; + +static int pinctrl_scmi_imx_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + int ret; + struct scmi_pinctrl_imx *pmx = pinctrl_dev_get_drvdata(pctldev); + u32 config_type, val; + + if (!config) + return -EINVAL; + + config_type = pinconf_to_config_param(*config); + + ret = pmx->ops->settings_get_one(pmx->ph, pin, PIN_TYPE, config_type, &val); + /* Convert SCMI error code to PINCTRL expected error code */ + if (ret == -EOPNOTSUPP) + return -ENOTSUPP; + if (ret) + return ret; + + *config = pinconf_to_config_packed(config_type, val); + + dev_dbg(pmx->dev, "pin:%s, conf:0x%x", pin_get_name(pctldev, pin), val); + + return 0; +} + +static int pinctrl_scmi_imx_pinconf_set(struct pinctrl_dev *pctldev, + unsigned int pin, + unsigned long *configs, + unsigned int num_configs) +{ + struct scmi_pinctrl_imx *pmx = pinctrl_dev_get_drvdata(pctldev); + enum scmi_pinctrl_conf_type config_type[IMX_SCMI_NUM_CFG]; + u32 config_value[IMX_SCMI_NUM_CFG]; + enum scmi_pinctrl_conf_type *p_config_type = config_type; + u32 *p_config_value = config_value; + int ret; + int i; + + if (!configs || !num_configs) + return -EINVAL; + + if (num_configs > IMX_SCMI_NUM_CFG) { + dev_err(pmx->dev, "num_configs(%d) too large\n", num_configs); + return -EINVAL; + } + + for (i = 0; i < num_configs; i++) { + /* cast to avoid build warning */ + p_config_type[i] = + (enum scmi_pinctrl_conf_type)pinconf_to_config_param(configs[i]); + p_config_value[i] = pinconf_to_config_argument(configs[i]); + + dev_dbg(pmx->dev, "pin: %u, type: %u, val: 0x%x\n", + pin, p_config_type[i], p_config_value[i]); + } + + ret = pmx->ops->settings_conf(pmx->ph, pin, PIN_TYPE, num_configs, + p_config_type, p_config_value); + if (ret) + dev_err(pmx->dev, "Error set config %d\n", ret); + + return ret; +} + +static void pinctrl_scmi_imx_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int pin_id) +{ + unsigned long config = pinconf_to_config_packed(IMX_SCMI_PIN_CONFIG, 0); + int ret; + + ret = pinctrl_scmi_imx_pinconf_get(pctldev, pin_id, &config); + if (ret) + config = 0; + else + config = pinconf_to_config_argument(config); + + seq_printf(s, "0x%lx", config); +} + +static const struct pinconf_ops pinctrl_scmi_imx_pinconf_ops = { + .pin_config_get = pinctrl_scmi_imx_pinconf_get, + .pin_config_set = pinctrl_scmi_imx_pinconf_set, + .pin_config_dbg_show = pinctrl_scmi_imx_pinconf_dbg_show, +}; + +static int +scmi_pinctrl_imx_get_pins(struct scmi_pinctrl_imx *pmx, struct pinctrl_desc *desc) +{ + struct pinctrl_pin_desc *pins; + unsigned int npins; + int ret, i; + + npins = pmx->ops->count_get(pmx->ph, PIN_TYPE); + pins = devm_kmalloc_array(pmx->dev, npins, sizeof(*pins), GFP_KERNEL); + if (!pins) + return -ENOMEM; + + for (i = 0; i < npins; i++) { + pins[i].number = i; + /* no need free name, firmware driver handles it */ + ret = pmx->ops->name_get(pmx->ph, i, PIN_TYPE, &pins[i].name); + if (ret) + return dev_err_probe(pmx->dev, ret, + "Can't get name for pin %d", i); + } + + desc->npins = npins; + desc->pins = pins; + dev_dbg(pmx->dev, "got pins %u", npins); + + return 0; +} + +static const char * const scmi_pinctrl_imx_allowlist[] = { + "fsl,imx95", + NULL +}; + +static int scmi_pinctrl_imx_probe(struct scmi_device *sdev) +{ + struct device *dev = &sdev->dev; + const struct scmi_handle *handle = sdev->handle; + struct scmi_pinctrl_imx *pmx; + struct scmi_protocol_handle *ph; + const struct scmi_pinctrl_proto_ops *pinctrl_ops; + int ret; + + if (!handle) + return -EINVAL; + + if (!of_machine_compatible_match(scmi_pinctrl_imx_allowlist)) + return -ENODEV; + + pinctrl_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_PINCTRL, &ph); + if (IS_ERR(pinctrl_ops)) + return PTR_ERR(pinctrl_ops); + + pmx = devm_kzalloc(dev, sizeof(*pmx), GFP_KERNEL); + if (!pmx) + return -ENOMEM; + + pmx->ph = ph; + pmx->ops = pinctrl_ops; + + pmx->dev = dev; + pmx->pctl_desc.name = DRV_NAME; + pmx->pctl_desc.owner = THIS_MODULE; + pmx->pctl_desc.pctlops = &pinctrl_scmi_imx_pinctrl_ops; + pmx->pctl_desc.pmxops = &pinctrl_scmi_imx_pinmux_ops; + pmx->pctl_desc.confops = &pinctrl_scmi_imx_pinconf_ops; + + ret = scmi_pinctrl_imx_get_pins(pmx, &pmx->pctl_desc); + if (ret) + return ret; + + pmx->dev = &sdev->dev; + + ret = devm_pinctrl_register_and_init(dev, &pmx->pctl_desc, pmx, + &pmx->pctldev); + if (ret) + return dev_err_probe(dev, ret, "Failed to register pinctrl\n"); + + return pinctrl_enable(pmx->pctldev); +} + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_PINCTRL, "pinctrl-imx" }, + { } +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_pinctrl_imx_driver = { + .name = DRV_NAME, + .probe = scmi_pinctrl_imx_probe, + .id_table = scmi_id_table, +}; +module_scmi_driver(scmi_pinctrl_imx_driver); + +MODULE_AUTHOR("Peng Fan "); +MODULE_DESCRIPTION("i.MX SCMI pin controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index 2d3d80921c0d..9c2680df082c 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -266,7 +266,7 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, npins = grp->grp.npins; dev_dbg(ipctl->dev, "enable function %s group %s\n", - func->name, grp->grp.name); + func->func.name, grp->grp.name); for (i = 0; i < npins; i++) { /* @@ -580,7 +580,6 @@ static int imx_pinctrl_parse_functions(struct device_node *np, u32 index) { struct pinctrl_dev *pctl = ipctl->pctl; - struct device_node *child; struct function_desc *func; struct group_desc *grp; const char **group_names; @@ -593,29 +592,27 @@ static int imx_pinctrl_parse_functions(struct device_node *np, return -EINVAL; /* Initialise function */ - func->name = np->name; - func->num_group_names = of_get_child_count(np); - if (func->num_group_names == 0) { + func->func.name = np->name; + func->func.ngroups = of_get_child_count(np); + if (func->func.ngroups == 0) { dev_info(ipctl->dev, "no groups defined in %pOF\n", np); return -EINVAL; } - group_names = devm_kcalloc(ipctl->dev, func->num_group_names, - sizeof(char *), GFP_KERNEL); + group_names = devm_kcalloc(ipctl->dev, func->func.ngroups, + sizeof(*func->func.groups), GFP_KERNEL); if (!group_names) return -ENOMEM; i = 0; - for_each_child_of_node(np, child) + for_each_child_of_node_scoped(np, child) group_names[i++] = child->name; - func->group_names = group_names; + func->func.groups = group_names; i = 0; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { grp = devm_kzalloc(ipctl->dev, sizeof(*grp), GFP_KERNEL); - if (!grp) { - of_node_put(child); + if (!grp) return -ENOMEM; - } mutex_lock(&ipctl->mutex); radix_tree_insert(&pctl->pin_group_tree, @@ -635,21 +632,13 @@ static int imx_pinctrl_parse_functions(struct device_node *np, */ static bool imx_pinctrl_dt_is_flat_functions(struct device_node *np) { - struct device_node *function_np; - struct device_node *pinctrl_np; - - for_each_child_of_node(np, function_np) { - if (of_property_read_bool(function_np, "fsl,pins")) { - of_node_put(function_np); + for_each_child_of_node_scoped(np, function_np) { + if (of_property_read_bool(function_np, "fsl,pins")) return true; - } - for_each_child_of_node(function_np, pinctrl_np) { - if (of_property_read_bool(pinctrl_np, "fsl,pins")) { - of_node_put(pinctrl_np); - of_node_put(function_np); + for_each_child_of_node_scoped(function_np, pinctrl_np) { + if (of_property_read_bool(pinctrl_np, "fsl,pins")) return false; - } } } diff --git a/drivers/pinctrl/freescale/pinctrl-imx1-core.c b/drivers/pinctrl/freescale/pinctrl-imx1-core.c index 90c696046b38..af1ccfc90bff 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx1-core.c +++ b/drivers/pinctrl/freescale/pinctrl-imx1-core.c @@ -508,7 +508,6 @@ static int imx1_pinctrl_parse_functions(struct device_node *np, struct imx1_pinctrl_soc_info *info, u32 index) { - struct device_node *child; struct imx1_pmx_func *func; struct imx1_pin_group *grp; int ret; @@ -531,14 +530,12 @@ static int imx1_pinctrl_parse_functions(struct device_node *np, if (!func->groups) return -ENOMEM; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { func->groups[i] = child->name; grp = &info->groups[grp_index++]; ret = imx1_pinctrl_parse_groups(child, grp, info, i++); - if (ret == -ENOMEM) { - of_node_put(child); + if (ret == -ENOMEM) return ret; - } } return 0; @@ -548,7 +545,6 @@ static int imx1_pinctrl_parse_dt(struct platform_device *pdev, struct imx1_pinctrl *pctl, struct imx1_pinctrl_soc_info *info) { struct device_node *np = pdev->dev.of_node; - struct device_node *child; int ret; u32 nfuncs = 0; u32 ngroups = 0; @@ -557,7 +553,7 @@ static int imx1_pinctrl_parse_dt(struct platform_device *pdev, if (!np) return -ENODEV; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { ++nfuncs; ngroups += of_get_child_count(child); } @@ -579,12 +575,10 @@ static int imx1_pinctrl_parse_dt(struct platform_device *pdev, if (!info->functions || !info->groups) return -ENOMEM; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { ret = imx1_pinctrl_parse_functions(child, info, ifunc++); - if (ret == -ENOMEM) { - of_node_put(child); + if (ret == -ENOMEM) return -ENOMEM; - } } return 0; diff --git a/drivers/pinctrl/freescale/pinctrl-imx91.c b/drivers/pinctrl/freescale/pinctrl-imx91.c new file mode 100644 index 000000000000..5421141c586a --- /dev/null +++ b/drivers/pinctrl/freescale/pinctrl-imx91.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2024 NXP + */ + +#include +#include +#include +#include +#include + +#include "pinctrl-imx.h" + +enum imx91_pads { + IMX91_PAD_DAP_TDI = 0, + IMX91_PAD_DAP_TMS_SWDIO = 1, + IMX91_PAD_DAP_TCLK_SWCLK = 2, + IMX91_PAD_DAP_TDO_TRACESWO = 3, + IMX91_PAD_GPIO_IO00 = 4, + IMX91_PAD_GPIO_IO01 = 5, + IMX91_PAD_GPIO_IO02 = 6, + IMX91_PAD_GPIO_IO03 = 7, + IMX91_PAD_GPIO_IO04 = 8, + IMX91_PAD_GPIO_IO05 = 9, + IMX91_PAD_GPIO_IO06 = 10, + IMX91_PAD_GPIO_IO07 = 11, + IMX91_PAD_GPIO_IO08 = 12, + IMX91_PAD_GPIO_IO09 = 13, + IMX91_PAD_GPIO_IO10 = 14, + IMX91_PAD_GPIO_IO11 = 15, + IMX91_PAD_GPIO_IO12 = 16, + IMX91_PAD_GPIO_IO13 = 17, + IMX91_PAD_GPIO_IO14 = 18, + IMX91_PAD_GPIO_IO15 = 19, + IMX91_PAD_GPIO_IO16 = 20, + IMX91_PAD_GPIO_IO17 = 21, + IMX91_PAD_GPIO_IO18 = 22, + IMX91_PAD_GPIO_IO19 = 23, + IMX91_PAD_GPIO_IO20 = 24, + IMX91_PAD_GPIO_IO21 = 25, + IMX91_PAD_GPIO_IO22 = 26, + IMX91_PAD_GPIO_IO23 = 27, + IMX91_PAD_GPIO_IO24 = 28, + IMX91_PAD_GPIO_IO25 = 29, + IMX91_PAD_GPIO_IO26 = 30, + IMX91_PAD_GPIO_IO27 = 31, + IMX91_PAD_GPIO_IO28 = 32, + IMX91_PAD_GPIO_IO29 = 33, + IMX91_PAD_CCM_CLKO1 = 34, + IMX91_PAD_CCM_CLKO2 = 35, + IMX91_PAD_CCM_CLKO3 = 36, + IMX91_PAD_CCM_CLKO4 = 37, + IMX91_PAD_ENET1_MDC = 38, + IMX91_PAD_ENET1_MDIO = 39, + IMX91_PAD_ENET1_TD3 = 40, + IMX91_PAD_ENET1_TD2 = 41, + IMX91_PAD_ENET1_TD1 = 42, + IMX91_PAD_ENET1_TD0 = 43, + IMX91_PAD_ENET1_TX_CTL = 44, + IMX91_PAD_ENET1_TXC = 45, + IMX91_PAD_ENET1_RX_CTL = 46, + IMX91_PAD_ENET1_RXC = 47, + IMX91_PAD_ENET1_RD0 = 48, + IMX91_PAD_ENET1_RD1 = 49, + IMX91_PAD_ENET1_RD2 = 50, + IMX91_PAD_ENET1_RD3 = 51, + IMX91_PAD_ENET2_MDC = 52, + IMX91_PAD_ENET2_MDIO = 53, + IMX91_PAD_ENET2_TD3 = 54, + IMX91_PAD_ENET2_TD2 = 55, + IMX91_PAD_ENET2_TD1 = 56, + IMX91_PAD_ENET2_TD0 = 57, + IMX91_PAD_ENET2_TX_CTL = 58, + IMX91_PAD_ENET2_TXC = 59, + IMX91_PAD_ENET2_RX_CTL = 60, + IMX91_PAD_ENET2_RXC = 61, + IMX91_PAD_ENET2_RD0 = 62, + IMX91_PAD_ENET2_RD1 = 63, + IMX91_PAD_ENET2_RD2 = 64, + IMX91_PAD_ENET2_RD3 = 65, + IMX91_PAD_SD1_CLK = 66, + IMX91_PAD_SD1_CMD = 67, + IMX91_PAD_SD1_DATA0 = 68, + IMX91_PAD_SD1_DATA1 = 69, + IMX91_PAD_SD1_DATA2 = 70, + IMX91_PAD_SD1_DATA3 = 71, + IMX91_PAD_SD1_DATA4 = 72, + IMX91_PAD_SD1_DATA5 = 73, + IMX91_PAD_SD1_DATA6 = 74, + IMX91_PAD_SD1_DATA7 = 75, + IMX91_PAD_SD1_STROBE = 76, + IMX91_PAD_SD2_VSELECT = 77, + IMX91_PAD_SD3_CLK = 78, + IMX91_PAD_SD3_CMD = 79, + IMX91_PAD_SD3_DATA0 = 80, + IMX91_PAD_SD3_DATA1 = 81, + IMX91_PAD_SD3_DATA2 = 82, + IMX91_PAD_SD3_DATA3 = 83, + IMX91_PAD_SD2_CD_B = 84, + IMX91_PAD_SD2_CLK = 85, + IMX91_PAD_SD2_CMD = 86, + IMX91_PAD_SD2_DATA0 = 87, + IMX91_PAD_SD2_DATA1 = 88, + IMX91_PAD_SD2_DATA2 = 89, + IMX91_PAD_SD2_DATA3 = 90, + IMX91_PAD_SD2_RESET_B = 91, + IMX91_PAD_I2C1_SCL = 92, + IMX91_PAD_I2C1_SDA = 93, + IMX91_PAD_I2C2_SCL = 94, + IMX91_PAD_I2C2_SDA = 95, + IMX91_PAD_UART1_RXD = 96, + IMX91_PAD_UART1_TXD = 97, + IMX91_PAD_UART2_RXD = 98, + IMX91_PAD_UART2_TXD = 99, + IMX91_PAD_PDM_CLK = 100, + IMX91_PAD_PDM_BIT_STREAM0 = 101, + IMX91_PAD_PDM_BIT_STREAM1 = 102, + IMX91_PAD_SAI1_TXFS = 103, + IMX91_PAD_SAI1_TXC = 104, + IMX91_PAD_SAI1_TXD0 = 105, + IMX91_PAD_SAI1_RXD0 = 106, + IMX91_PAD_WDOG_ANY = 107, +}; + +/* Pad names for the pinmux subsystem */ +static const struct pinctrl_pin_desc imx91_pinctrl_pads[] = { + IMX_PINCTRL_PIN(IMX91_PAD_DAP_TDI), + IMX_PINCTRL_PIN(IMX91_PAD_DAP_TMS_SWDIO), + IMX_PINCTRL_PIN(IMX91_PAD_DAP_TCLK_SWCLK), + IMX_PINCTRL_PIN(IMX91_PAD_DAP_TDO_TRACESWO), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO00), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO01), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO02), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO03), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO04), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO05), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO06), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO07), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO08), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO09), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO10), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO11), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO12), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO13), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO14), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO15), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO16), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO17), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO18), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO19), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO20), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO21), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO22), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO23), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO24), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO25), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO26), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO27), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO28), + IMX_PINCTRL_PIN(IMX91_PAD_GPIO_IO29), + IMX_PINCTRL_PIN(IMX91_PAD_CCM_CLKO1), + IMX_PINCTRL_PIN(IMX91_PAD_CCM_CLKO2), + IMX_PINCTRL_PIN(IMX91_PAD_CCM_CLKO3), + IMX_PINCTRL_PIN(IMX91_PAD_CCM_CLKO4), + IMX_PINCTRL_PIN(IMX91_PAD_ENET1_MDC), + IMX_PINCTRL_PIN(IMX91_PAD_ENET1_MDIO), + IMX_PINCTRL_PIN(IMX91_PAD_ENET1_TD3), + IMX_PINCTRL_PIN(IMX91_PAD_ENET1_TD2), + IMX_PINCTRL_PIN(IMX91_PAD_ENET1_TD1), + IMX_PINCTRL_PIN(IMX91_PAD_ENET1_TD0), + IMX_PINCTRL_PIN(IMX91_PAD_ENET1_TX_CTL), + IMX_PINCTRL_PIN(IMX91_PAD_ENET1_TXC), + IMX_PINCTRL_PIN(IMX91_PAD_ENET1_RX_CTL), + IMX_PINCTRL_PIN(IMX91_PAD_ENET1_RXC), + IMX_PINCTRL_PIN(IMX91_PAD_ENET1_RD0), + IMX_PINCTRL_PIN(IMX91_PAD_ENET1_RD1), + IMX_PINCTRL_PIN(IMX91_PAD_ENET1_RD2), + IMX_PINCTRL_PIN(IMX91_PAD_ENET1_RD3), + IMX_PINCTRL_PIN(IMX91_PAD_ENET2_MDC), + IMX_PINCTRL_PIN(IMX91_PAD_ENET2_MDIO), + IMX_PINCTRL_PIN(IMX91_PAD_ENET2_TD3), + IMX_PINCTRL_PIN(IMX91_PAD_ENET2_TD2), + IMX_PINCTRL_PIN(IMX91_PAD_ENET2_TD1), + IMX_PINCTRL_PIN(IMX91_PAD_ENET2_TD0), + IMX_PINCTRL_PIN(IMX91_PAD_ENET2_TX_CTL), + IMX_PINCTRL_PIN(IMX91_PAD_ENET2_TXC), + IMX_PINCTRL_PIN(IMX91_PAD_ENET2_RX_CTL), + IMX_PINCTRL_PIN(IMX91_PAD_ENET2_RXC), + IMX_PINCTRL_PIN(IMX91_PAD_ENET2_RD0), + IMX_PINCTRL_PIN(IMX91_PAD_ENET2_RD1), + IMX_PINCTRL_PIN(IMX91_PAD_ENET2_RD2), + IMX_PINCTRL_PIN(IMX91_PAD_ENET2_RD3), + IMX_PINCTRL_PIN(IMX91_PAD_SD1_CLK), + IMX_PINCTRL_PIN(IMX91_PAD_SD1_CMD), + IMX_PINCTRL_PIN(IMX91_PAD_SD1_DATA0), + IMX_PINCTRL_PIN(IMX91_PAD_SD1_DATA1), + IMX_PINCTRL_PIN(IMX91_PAD_SD1_DATA2), + IMX_PINCTRL_PIN(IMX91_PAD_SD1_DATA3), + IMX_PINCTRL_PIN(IMX91_PAD_SD1_DATA4), + IMX_PINCTRL_PIN(IMX91_PAD_SD1_DATA5), + IMX_PINCTRL_PIN(IMX91_PAD_SD1_DATA6), + IMX_PINCTRL_PIN(IMX91_PAD_SD1_DATA7), + IMX_PINCTRL_PIN(IMX91_PAD_SD1_STROBE), + IMX_PINCTRL_PIN(IMX91_PAD_SD2_VSELECT), + IMX_PINCTRL_PIN(IMX91_PAD_SD3_CLK), + IMX_PINCTRL_PIN(IMX91_PAD_SD3_CMD), + IMX_PINCTRL_PIN(IMX91_PAD_SD3_DATA0), + IMX_PINCTRL_PIN(IMX91_PAD_SD3_DATA1), + IMX_PINCTRL_PIN(IMX91_PAD_SD3_DATA2), + IMX_PINCTRL_PIN(IMX91_PAD_SD3_DATA3), + IMX_PINCTRL_PIN(IMX91_PAD_SD2_CD_B), + IMX_PINCTRL_PIN(IMX91_PAD_SD2_CLK), + IMX_PINCTRL_PIN(IMX91_PAD_SD2_CMD), + IMX_PINCTRL_PIN(IMX91_PAD_SD2_DATA0), + IMX_PINCTRL_PIN(IMX91_PAD_SD2_DATA1), + IMX_PINCTRL_PIN(IMX91_PAD_SD2_DATA2), + IMX_PINCTRL_PIN(IMX91_PAD_SD2_DATA3), + IMX_PINCTRL_PIN(IMX91_PAD_SD2_RESET_B), + IMX_PINCTRL_PIN(IMX91_PAD_I2C1_SCL), + IMX_PINCTRL_PIN(IMX91_PAD_I2C1_SDA), + IMX_PINCTRL_PIN(IMX91_PAD_I2C2_SCL), + IMX_PINCTRL_PIN(IMX91_PAD_I2C2_SDA), + IMX_PINCTRL_PIN(IMX91_PAD_UART1_RXD), + IMX_PINCTRL_PIN(IMX91_PAD_UART1_TXD), + IMX_PINCTRL_PIN(IMX91_PAD_UART2_RXD), + IMX_PINCTRL_PIN(IMX91_PAD_UART2_TXD), + IMX_PINCTRL_PIN(IMX91_PAD_PDM_CLK), + IMX_PINCTRL_PIN(IMX91_PAD_PDM_BIT_STREAM0), + IMX_PINCTRL_PIN(IMX91_PAD_PDM_BIT_STREAM1), + IMX_PINCTRL_PIN(IMX91_PAD_SAI1_TXFS), + IMX_PINCTRL_PIN(IMX91_PAD_SAI1_TXC), + IMX_PINCTRL_PIN(IMX91_PAD_SAI1_TXD0), + IMX_PINCTRL_PIN(IMX91_PAD_SAI1_RXD0), + IMX_PINCTRL_PIN(IMX91_PAD_WDOG_ANY), +}; + +static const struct imx_pinctrl_soc_info imx91_pinctrl_info = { + .pins = imx91_pinctrl_pads, + .npins = ARRAY_SIZE(imx91_pinctrl_pads), + .flags = ZERO_OFFSET_VALID, +}; + +static int imx91_pinctrl_probe(struct platform_device *pdev) +{ + return imx_pinctrl_probe(pdev, &imx91_pinctrl_info); +} + +static const struct of_device_id imx91_pinctrl_of_match[] = { + { .compatible = "fsl,imx91-iomuxc", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx91_pinctrl_of_match); + +static struct platform_driver imx91_pinctrl_driver = { + .driver = { + .name = "imx91-pinctrl", + .of_match_table = imx91_pinctrl_of_match, + .suppress_bind_attrs = true, + }, + .probe = imx91_pinctrl_probe, +}; + +static int __init imx91_pinctrl_init(void) +{ + return platform_driver_register(&imx91_pinctrl_driver); +} +arch_initcall(imx91_pinctrl_init); + +MODULE_AUTHOR("Peng Fan "); +MODULE_DESCRIPTION("NXP i.MX91 pinctrl driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/freescale/pinctrl-mxs.c b/drivers/pinctrl/freescale/pinctrl-mxs.c index e77311f26262..edb242d30609 100644 --- a/drivers/pinctrl/freescale/pinctrl-mxs.c +++ b/drivers/pinctrl/freescale/pinctrl-mxs.c @@ -413,8 +413,8 @@ static int mxs_pinctrl_probe_dt(struct platform_device *pdev, int ret; u32 val; - child = of_get_next_child(np, NULL); - if (!child) { + val = of_get_child_count(np); + if (val == 0) { dev_err(&pdev->dev, "no group is defined\n"); return -ENOENT; } @@ -490,16 +490,14 @@ static int mxs_pinctrl_probe_dt(struct platform_device *pdev, /* Get groups for each function */ idxf = 0; fn = fnull; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { if (is_mxs_gpio(child)) continue; if (of_property_read_u32(child, "reg", &val)) { ret = mxs_pinctrl_parse_group(pdev, child, idxg++, NULL); - if (ret) { - of_node_put(child); + if (ret) return ret; - } continue; } @@ -509,19 +507,15 @@ static int mxs_pinctrl_probe_dt(struct platform_device *pdev, f->ngroups, sizeof(*f->groups), GFP_KERNEL); - if (!f->groups) { - of_node_put(child); + if (!f->groups) return -ENOMEM; - } fn = child->name; i = 0; } ret = mxs_pinctrl_parse_group(pdev, child, idxg++, &f->groups[i++]); - if (ret) { - of_node_put(child); + if (ret) return ret; - } } return 0; diff --git a/drivers/pinctrl/mediatek/pinctrl-moore.c b/drivers/pinctrl/mediatek/pinctrl-moore.c index d972584c0519..aad4891223d3 100644 --- a/drivers/pinctrl/mediatek/pinctrl-moore.c +++ b/drivers/pinctrl/mediatek/pinctrl-moore.c @@ -56,7 +56,7 @@ static int mtk_pinmux_set_mux(struct pinctrl_dev *pctldev, return -EINVAL; dev_dbg(pctldev->dev, "enable function %s group %s\n", - func->name, grp->grp.name); + func->func.name, grp->grp.name); for (i = 0; i < grp->grp.npins; i++) { const struct mtk_pin_desc *desc; @@ -620,12 +620,12 @@ static int mtk_build_functions(struct mtk_pinctrl *hw) int i, err; for (i = 0; i < hw->soc->nfuncs ; i++) { - const struct function_desc *func = hw->soc->funcs + i; + const struct function_desc *function = hw->soc->funcs + i; + const struct pinfunction *func = &function->func; err = pinmux_generic_add_function(hw->pctrl, func->name, - func->group_names, - func->num_group_names, - func->data); + func->groups, func->ngroups, + function->data); if (err < 0) { dev_err(hw->dev, "Failed to register function %s\n", func->name); diff --git a/drivers/pinctrl/mediatek/pinctrl-moore.h b/drivers/pinctrl/mediatek/pinctrl-moore.h index e0313e7a1fe0..229d19561e22 100644 --- a/drivers/pinctrl/mediatek/pinctrl-moore.h +++ b/drivers/pinctrl/mediatek/pinctrl-moore.h @@ -43,6 +43,12 @@ .data = id##_funcs, \ } +#define PINCTRL_PIN_FUNCTION(_name_, id) \ + { \ + .func = PINCTRL_PINFUNCTION(_name_, id##_groups, ARRAY_SIZE(id##_groups)), \ + .data = NULL, \ + } + int mtk_moore_pinctrl_probe(struct platform_device *pdev, const struct mtk_pin_soc *soc); diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7622.c b/drivers/pinctrl/mediatek/pinctrl-mt7622.c index 3c1148d59eff..2dc101991066 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7622.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7622.c @@ -823,22 +823,22 @@ static const char *mt7622_uart_groups[] = { "uart0_0_tx_rx", static const char *mt7622_wdt_groups[] = { "watchdog", }; static const struct function_desc mt7622_functions[] = { - {"antsel", mt7622_antsel_groups, ARRAY_SIZE(mt7622_antsel_groups)}, - {"emmc", mt7622_emmc_groups, ARRAY_SIZE(mt7622_emmc_groups)}, - {"eth", mt7622_ethernet_groups, ARRAY_SIZE(mt7622_ethernet_groups)}, - {"i2c", mt7622_i2c_groups, ARRAY_SIZE(mt7622_i2c_groups)}, - {"i2s", mt7622_i2s_groups, ARRAY_SIZE(mt7622_i2s_groups)}, - {"ir", mt7622_ir_groups, ARRAY_SIZE(mt7622_ir_groups)}, - {"led", mt7622_led_groups, ARRAY_SIZE(mt7622_led_groups)}, - {"flash", mt7622_flash_groups, ARRAY_SIZE(mt7622_flash_groups)}, - {"pcie", mt7622_pcie_groups, ARRAY_SIZE(mt7622_pcie_groups)}, - {"pmic", mt7622_pmic_bus_groups, ARRAY_SIZE(mt7622_pmic_bus_groups)}, - {"pwm", mt7622_pwm_groups, ARRAY_SIZE(mt7622_pwm_groups)}, - {"sd", mt7622_sd_groups, ARRAY_SIZE(mt7622_sd_groups)}, - {"spi", mt7622_spic_groups, ARRAY_SIZE(mt7622_spic_groups)}, - {"tdm", mt7622_tdm_groups, ARRAY_SIZE(mt7622_tdm_groups)}, - {"uart", mt7622_uart_groups, ARRAY_SIZE(mt7622_uart_groups)}, - {"watchdog", mt7622_wdt_groups, ARRAY_SIZE(mt7622_wdt_groups)}, + PINCTRL_PIN_FUNCTION("antsel", mt7622_antsel), + PINCTRL_PIN_FUNCTION("emmc", mt7622_emmc), + PINCTRL_PIN_FUNCTION("eth", mt7622_ethernet), + PINCTRL_PIN_FUNCTION("i2c", mt7622_i2c), + PINCTRL_PIN_FUNCTION("i2s", mt7622_i2s), + PINCTRL_PIN_FUNCTION("ir", mt7622_ir), + PINCTRL_PIN_FUNCTION("led", mt7622_led), + PINCTRL_PIN_FUNCTION("flash", mt7622_flash), + PINCTRL_PIN_FUNCTION("pcie", mt7622_pcie), + PINCTRL_PIN_FUNCTION("pmic", mt7622_pmic_bus), + PINCTRL_PIN_FUNCTION("pwm", mt7622_pwm), + PINCTRL_PIN_FUNCTION("sd", mt7622_sd), + PINCTRL_PIN_FUNCTION("spi", mt7622_spic), + PINCTRL_PIN_FUNCTION("tdm", mt7622_tdm), + PINCTRL_PIN_FUNCTION("uart", mt7622_uart), + PINCTRL_PIN_FUNCTION("watchdog", mt7622_wdt), }; static const struct mtk_eint_hw mt7622_eint_hw = { diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7623.c b/drivers/pinctrl/mediatek/pinctrl-mt7623.c index 699977074697..3e59eada2825 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7623.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7623.c @@ -1341,27 +1341,27 @@ static const char *mt7623_uart_groups[] = { "uart0_0_txd_rxd", static const char *mt7623_wdt_groups[] = { "watchdog_0", "watchdog_1", }; static const struct function_desc mt7623_functions[] = { - {"audck", mt7623_aud_clk_groups, ARRAY_SIZE(mt7623_aud_clk_groups)}, - {"disp", mt7623_disp_pwm_groups, ARRAY_SIZE(mt7623_disp_pwm_groups)}, - {"eth", mt7623_ethernet_groups, ARRAY_SIZE(mt7623_ethernet_groups)}, - {"sdio", mt7623_ext_sdio_groups, ARRAY_SIZE(mt7623_ext_sdio_groups)}, - {"hdmi", mt7623_hdmi_groups, ARRAY_SIZE(mt7623_hdmi_groups)}, - {"i2c", mt7623_i2c_groups, ARRAY_SIZE(mt7623_i2c_groups)}, - {"i2s", mt7623_i2s_groups, ARRAY_SIZE(mt7623_i2s_groups)}, - {"ir", mt7623_ir_groups, ARRAY_SIZE(mt7623_ir_groups)}, - {"lcd", mt7623_lcd_groups, ARRAY_SIZE(mt7623_lcd_groups)}, - {"msdc", mt7623_msdc_groups, ARRAY_SIZE(mt7623_msdc_groups)}, - {"nand", mt7623_nandc_groups, ARRAY_SIZE(mt7623_nandc_groups)}, - {"otg", mt7623_otg_groups, ARRAY_SIZE(mt7623_otg_groups)}, - {"pcie", mt7623_pcie_groups, ARRAY_SIZE(mt7623_pcie_groups)}, - {"pcm", mt7623_pcm_groups, ARRAY_SIZE(mt7623_pcm_groups)}, - {"pwm", mt7623_pwm_groups, ARRAY_SIZE(mt7623_pwm_groups)}, - {"pwrap", mt7623_pwrap_groups, ARRAY_SIZE(mt7623_pwrap_groups)}, - {"rtc", mt7623_rtc_groups, ARRAY_SIZE(mt7623_rtc_groups)}, - {"spi", mt7623_spi_groups, ARRAY_SIZE(mt7623_spi_groups)}, - {"spdif", mt7623_spdif_groups, ARRAY_SIZE(mt7623_spdif_groups)}, - {"uart", mt7623_uart_groups, ARRAY_SIZE(mt7623_uart_groups)}, - {"watchdog", mt7623_wdt_groups, ARRAY_SIZE(mt7623_wdt_groups)}, + PINCTRL_PIN_FUNCTION("audck", mt7623_aud_clk), + PINCTRL_PIN_FUNCTION("disp", mt7623_disp_pwm), + PINCTRL_PIN_FUNCTION("eth", mt7623_ethernet), + PINCTRL_PIN_FUNCTION("sdio", mt7623_ext_sdio), + PINCTRL_PIN_FUNCTION("hdmi", mt7623_hdmi), + PINCTRL_PIN_FUNCTION("i2c", mt7623_i2c), + PINCTRL_PIN_FUNCTION("i2s", mt7623_i2s), + PINCTRL_PIN_FUNCTION("ir", mt7623_ir), + PINCTRL_PIN_FUNCTION("lcd", mt7623_lcd), + PINCTRL_PIN_FUNCTION("msdc", mt7623_msdc), + PINCTRL_PIN_FUNCTION("nand", mt7623_nandc), + PINCTRL_PIN_FUNCTION("otg", mt7623_otg), + PINCTRL_PIN_FUNCTION("pcie", mt7623_pcie), + PINCTRL_PIN_FUNCTION("pcm", mt7623_pcm), + PINCTRL_PIN_FUNCTION("pwm", mt7623_pwm), + PINCTRL_PIN_FUNCTION("pwrap", mt7623_pwrap), + PINCTRL_PIN_FUNCTION("rtc", mt7623_rtc), + PINCTRL_PIN_FUNCTION("spi", mt7623_spi), + PINCTRL_PIN_FUNCTION("spdif", mt7623_spdif), + PINCTRL_PIN_FUNCTION("uart", mt7623_uart), + PINCTRL_PIN_FUNCTION("watchdog", mt7623_wdt), }; static const struct mtk_eint_hw mt7623_eint_hw = { diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7629.c b/drivers/pinctrl/mediatek/pinctrl-mt7629.c index 2ce411cb9c6e..98142e8c9801 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7629.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7629.c @@ -385,16 +385,16 @@ static const char *mt7629_wifi_groups[] = { "wf0_5g", "wf0_2g", }; static const char *mt7629_flash_groups[] = { "snfi", "spi_nor" }; static const struct function_desc mt7629_functions[] = { - {"eth", mt7629_ethernet_groups, ARRAY_SIZE(mt7629_ethernet_groups)}, - {"i2c", mt7629_i2c_groups, ARRAY_SIZE(mt7629_i2c_groups)}, - {"led", mt7629_led_groups, ARRAY_SIZE(mt7629_led_groups)}, - {"pcie", mt7629_pcie_groups, ARRAY_SIZE(mt7629_pcie_groups)}, - {"pwm", mt7629_pwm_groups, ARRAY_SIZE(mt7629_pwm_groups)}, - {"spi", mt7629_spi_groups, ARRAY_SIZE(mt7629_spi_groups)}, - {"uart", mt7629_uart_groups, ARRAY_SIZE(mt7629_uart_groups)}, - {"watchdog", mt7629_wdt_groups, ARRAY_SIZE(mt7629_wdt_groups)}, - {"wifi", mt7629_wifi_groups, ARRAY_SIZE(mt7629_wifi_groups)}, - {"flash", mt7629_flash_groups, ARRAY_SIZE(mt7629_flash_groups)}, + PINCTRL_PIN_FUNCTION("eth", mt7629_ethernet), + PINCTRL_PIN_FUNCTION("i2c", mt7629_i2c), + PINCTRL_PIN_FUNCTION("led", mt7629_led), + PINCTRL_PIN_FUNCTION("pcie", mt7629_pcie), + PINCTRL_PIN_FUNCTION("pwm", mt7629_pwm), + PINCTRL_PIN_FUNCTION("spi", mt7629_spi), + PINCTRL_PIN_FUNCTION("uart", mt7629_uart), + PINCTRL_PIN_FUNCTION("watchdog", mt7629_wdt), + PINCTRL_PIN_FUNCTION("wifi", mt7629_wifi), + PINCTRL_PIN_FUNCTION("flash", mt7629_flash), }; static const struct mtk_eint_hw mt7629_eint_hw = { diff --git a/drivers/pinctrl/mediatek/pinctrl-mt76x8.c b/drivers/pinctrl/mediatek/pinctrl-mt76x8.c index e7d6ad2f62e4..2bc8d4409ca2 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt76x8.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt76x8.c @@ -37,36 +37,30 @@ static struct mtmips_pmx_func pwm1_grp[] = { FUNC("sdxc d6", 3, 19, 1), - FUNC("utif", 2, 19, 1), - FUNC("gpio", 1, 19, 1), + FUNC("pwm1 utif", 2, 19, 1), FUNC("pwm1", 0, 19, 1), }; static struct mtmips_pmx_func pwm0_grp[] = { FUNC("sdxc d7", 3, 18, 1), - FUNC("utif", 2, 18, 1), - FUNC("gpio", 1, 18, 1), + FUNC("pwm0 utif", 2, 18, 1), FUNC("pwm0", 0, 18, 1), }; static struct mtmips_pmx_func uart2_grp[] = { FUNC("sdxc d5 d4", 3, 20, 2), - FUNC("pwm", 2, 20, 2), - FUNC("gpio", 1, 20, 2), + FUNC("uart2 pwm", 2, 20, 2), FUNC("uart2", 0, 20, 2), }; static struct mtmips_pmx_func uart1_grp[] = { FUNC("sw_r", 3, 45, 2), - FUNC("pwm", 2, 45, 2), - FUNC("gpio", 1, 45, 2), + FUNC("uart1 pwm", 2, 45, 2), FUNC("uart1", 0, 45, 2), }; static struct mtmips_pmx_func i2c_grp[] = { - FUNC("-", 3, 4, 2), FUNC("debug", 2, 4, 2), - FUNC("gpio", 1, 4, 2), FUNC("i2c", 0, 4, 2), }; @@ -76,128 +70,100 @@ static struct mtmips_pmx_func wdt_grp[] = { FUNC("wdt", 0, 38, 1) }; static struct mtmips_pmx_func spi_grp[] = { FUNC("spi", 0, 7, 4) }; static struct mtmips_pmx_func sd_mode_grp[] = { - FUNC("jtag", 3, 22, 8), - FUNC("utif", 2, 22, 8), - FUNC("gpio", 1, 22, 8), + FUNC("sdxc jtag", 3, 22, 8), + FUNC("sdxc utif", 2, 22, 8), FUNC("sdxc", 0, 22, 8), }; static struct mtmips_pmx_func uart0_grp[] = { - FUNC("-", 3, 12, 2), - FUNC("-", 2, 12, 2), - FUNC("gpio", 1, 12, 2), FUNC("uart0", 0, 12, 2), }; static struct mtmips_pmx_func i2s_grp[] = { FUNC("antenna", 3, 0, 4), FUNC("pcm", 2, 0, 4), - FUNC("gpio", 1, 0, 4), FUNC("i2s", 0, 0, 4), }; static struct mtmips_pmx_func spi_cs1_grp[] = { - FUNC("-", 3, 6, 1), - FUNC("refclk", 2, 6, 1), - FUNC("gpio", 1, 6, 1), + FUNC("spi refclk", 2, 6, 1), FUNC("spi cs1", 0, 6, 1), }; static struct mtmips_pmx_func spis_grp[] = { FUNC("pwm_uart2", 3, 14, 4), - FUNC("utif", 2, 14, 4), - FUNC("gpio", 1, 14, 4), + FUNC("spis utif", 2, 14, 4), FUNC("spis", 0, 14, 4), }; static struct mtmips_pmx_func gpio_grp[] = { FUNC("pcie", 3, 11, 1), - FUNC("refclk", 2, 11, 1), - FUNC("gpio", 1, 11, 1), - FUNC("gpio", 0, 11, 1), + FUNC("gpio refclk", 2, 11, 1), }; static struct mtmips_pmx_func p4led_kn_grp[] = { - FUNC("jtag", 3, 30, 1), - FUNC("utif", 2, 30, 1), - FUNC("gpio", 1, 30, 1), + FUNC("p4led_kn jtag", 3, 30, 1), + FUNC("p4led_kn utif", 2, 30, 1), FUNC("p4led_kn", 0, 30, 1), }; static struct mtmips_pmx_func p3led_kn_grp[] = { - FUNC("jtag", 3, 31, 1), - FUNC("utif", 2, 31, 1), - FUNC("gpio", 1, 31, 1), + FUNC("p3led_kn jtag", 3, 31, 1), + FUNC("p3led_kn utif", 2, 31, 1), FUNC("p3led_kn", 0, 31, 1), }; static struct mtmips_pmx_func p2led_kn_grp[] = { - FUNC("jtag", 3, 32, 1), - FUNC("utif", 2, 32, 1), - FUNC("gpio", 1, 32, 1), + FUNC("p2led_kn jtag", 3, 32, 1), + FUNC("p2led_kn utif", 2, 32, 1), FUNC("p2led_kn", 0, 32, 1), }; static struct mtmips_pmx_func p1led_kn_grp[] = { - FUNC("jtag", 3, 33, 1), - FUNC("utif", 2, 33, 1), - FUNC("gpio", 1, 33, 1), + FUNC("p1led_kn jtag", 3, 33, 1), + FUNC("p1led_kn utif", 2, 33, 1), FUNC("p1led_kn", 0, 33, 1), }; static struct mtmips_pmx_func p0led_kn_grp[] = { - FUNC("jtag", 3, 34, 1), - FUNC("rsvd", 2, 34, 1), - FUNC("gpio", 1, 34, 1), + FUNC("p0led_kn jtag", 3, 34, 1), FUNC("p0led_kn", 0, 34, 1), }; static struct mtmips_pmx_func wled_kn_grp[] = { - FUNC("rsvd", 3, 35, 1), - FUNC("rsvd", 2, 35, 1), - FUNC("gpio", 1, 35, 1), FUNC("wled_kn", 0, 35, 1), }; static struct mtmips_pmx_func p4led_an_grp[] = { - FUNC("jtag", 3, 39, 1), - FUNC("utif", 2, 39, 1), - FUNC("gpio", 1, 39, 1), + FUNC("p4led_an jtag", 3, 39, 1), + FUNC("p4led_an utif", 2, 39, 1), FUNC("p4led_an", 0, 39, 1), }; static struct mtmips_pmx_func p3led_an_grp[] = { - FUNC("jtag", 3, 40, 1), - FUNC("utif", 2, 40, 1), - FUNC("gpio", 1, 40, 1), + FUNC("p3led_an jtag", 3, 40, 1), + FUNC("p3led_an utif", 2, 40, 1), FUNC("p3led_an", 0, 40, 1), }; static struct mtmips_pmx_func p2led_an_grp[] = { - FUNC("jtag", 3, 41, 1), - FUNC("utif", 2, 41, 1), - FUNC("gpio", 1, 41, 1), + FUNC("p2led_an jtag", 3, 41, 1), + FUNC("p2led_an utif", 2, 41, 1), FUNC("p2led_an", 0, 41, 1), }; static struct mtmips_pmx_func p1led_an_grp[] = { - FUNC("jtag", 3, 42, 1), - FUNC("utif", 2, 42, 1), - FUNC("gpio", 1, 42, 1), + FUNC("p1led_an jtag", 3, 42, 1), + FUNC("p1led_an utif", 2, 42, 1), FUNC("p1led_an", 0, 42, 1), }; static struct mtmips_pmx_func p0led_an_grp[] = { - FUNC("jtag", 3, 43, 1), - FUNC("rsvd", 2, 43, 1), - FUNC("gpio", 1, 43, 1), + FUNC("p0led_an jtag", 3, 43, 1), FUNC("p0led_an", 0, 43, 1), }; static struct mtmips_pmx_func wled_an_grp[] = { - FUNC("rsvd", 3, 44, 1), - FUNC("rsvd", 2, 44, 1), - FUNC("gpio", 1, 44, 1), FUNC("wled_an", 0, 44, 1), }; diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7981.c b/drivers/pinctrl/mediatek/pinctrl-mt7981.c index ef6123765885..83092be5b614 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7981.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7981.c @@ -978,23 +978,23 @@ static const char *mt7981_ethernet_groups[] = { "smi_mdc_mdio", "gbe_ext_mdc_mdi static const char *mt7981_ant_groups[] = { "ant_sel", }; static const struct function_desc mt7981_functions[] = { - {"wa_aice", mt7981_wa_aice_groups, ARRAY_SIZE(mt7981_wa_aice_groups)}, - {"dfd", mt7981_dfd_groups, ARRAY_SIZE(mt7981_dfd_groups)}, - {"jtag", mt7981_jtag_groups, ARRAY_SIZE(mt7981_jtag_groups)}, - {"pta", mt7981_pta_groups, ARRAY_SIZE(mt7981_pta_groups)}, - {"pcm", mt7981_pcm_groups, ARRAY_SIZE(mt7981_pcm_groups)}, - {"udi", mt7981_udi_groups, ARRAY_SIZE(mt7981_udi_groups)}, - {"usb", mt7981_usb_groups, ARRAY_SIZE(mt7981_usb_groups)}, - {"ant", mt7981_ant_groups, ARRAY_SIZE(mt7981_ant_groups)}, - {"eth", mt7981_ethernet_groups, ARRAY_SIZE(mt7981_ethernet_groups)}, - {"i2c", mt7981_i2c_groups, ARRAY_SIZE(mt7981_i2c_groups)}, - {"led", mt7981_led_groups, ARRAY_SIZE(mt7981_led_groups)}, - {"pwm", mt7981_pwm_groups, ARRAY_SIZE(mt7981_pwm_groups)}, - {"spi", mt7981_spi_groups, ARRAY_SIZE(mt7981_spi_groups)}, - {"uart", mt7981_uart_groups, ARRAY_SIZE(mt7981_uart_groups)}, - {"watchdog", mt7981_wdt_groups, ARRAY_SIZE(mt7981_wdt_groups)}, - {"flash", mt7981_flash_groups, ARRAY_SIZE(mt7981_flash_groups)}, - {"pcie", mt7981_pcie_groups, ARRAY_SIZE(mt7981_pcie_groups)}, + PINCTRL_PIN_FUNCTION("wa_aice", mt7981_wa_aice), + PINCTRL_PIN_FUNCTION("dfd", mt7981_dfd), + PINCTRL_PIN_FUNCTION("jtag", mt7981_jtag), + PINCTRL_PIN_FUNCTION("pta", mt7981_pta), + PINCTRL_PIN_FUNCTION("pcm", mt7981_pcm), + PINCTRL_PIN_FUNCTION("udi", mt7981_udi), + PINCTRL_PIN_FUNCTION("usb", mt7981_usb), + PINCTRL_PIN_FUNCTION("ant", mt7981_ant), + PINCTRL_PIN_FUNCTION("eth", mt7981_ethernet), + PINCTRL_PIN_FUNCTION("i2c", mt7981_i2c), + PINCTRL_PIN_FUNCTION("led", mt7981_led), + PINCTRL_PIN_FUNCTION("pwm", mt7981_pwm), + PINCTRL_PIN_FUNCTION("spi", mt7981_spi), + PINCTRL_PIN_FUNCTION("uart", mt7981_uart), + PINCTRL_PIN_FUNCTION("watchdog", mt7981_wdt), + PINCTRL_PIN_FUNCTION("flash", mt7981_flash), + PINCTRL_PIN_FUNCTION("pcie", mt7981_pcie), }; static const struct mtk_eint_hw mt7981_eint_hw = { diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7986.c b/drivers/pinctrl/mediatek/pinctrl-mt7986.c index 39e80fa644c1..5816b5fdb7ca 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7986.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7986.c @@ -879,18 +879,18 @@ static const char *mt7986_wdt_groups[] = { "watchdog", }; static const char *mt7986_wf_groups[] = { "wf_2g", "wf_5g", "wf_dbdc", }; static const struct function_desc mt7986_functions[] = { - {"audio", mt7986_audio_groups, ARRAY_SIZE(mt7986_audio_groups)}, - {"emmc", mt7986_emmc_groups, ARRAY_SIZE(mt7986_emmc_groups)}, - {"eth", mt7986_ethernet_groups, ARRAY_SIZE(mt7986_ethernet_groups)}, - {"i2c", mt7986_i2c_groups, ARRAY_SIZE(mt7986_i2c_groups)}, - {"led", mt7986_led_groups, ARRAY_SIZE(mt7986_led_groups)}, - {"flash", mt7986_flash_groups, ARRAY_SIZE(mt7986_flash_groups)}, - {"pcie", mt7986_pcie_groups, ARRAY_SIZE(mt7986_pcie_groups)}, - {"pwm", mt7986_pwm_groups, ARRAY_SIZE(mt7986_pwm_groups)}, - {"spi", mt7986_spi_groups, ARRAY_SIZE(mt7986_spi_groups)}, - {"uart", mt7986_uart_groups, ARRAY_SIZE(mt7986_uart_groups)}, - {"watchdog", mt7986_wdt_groups, ARRAY_SIZE(mt7986_wdt_groups)}, - {"wifi", mt7986_wf_groups, ARRAY_SIZE(mt7986_wf_groups)}, + PINCTRL_PIN_FUNCTION("audio", mt7986_audio), + PINCTRL_PIN_FUNCTION("emmc", mt7986_emmc), + PINCTRL_PIN_FUNCTION("eth", mt7986_ethernet), + PINCTRL_PIN_FUNCTION("i2c", mt7986_i2c), + PINCTRL_PIN_FUNCTION("led", mt7986_led), + PINCTRL_PIN_FUNCTION("flash", mt7986_flash), + PINCTRL_PIN_FUNCTION("pcie", mt7986_pcie), + PINCTRL_PIN_FUNCTION("pwm", mt7986_pwm), + PINCTRL_PIN_FUNCTION("spi", mt7986_spi), + PINCTRL_PIN_FUNCTION("uart", mt7986_uart), + PINCTRL_PIN_FUNCTION("watchdog", mt7986_wdt), + PINCTRL_PIN_FUNCTION("wifi", mt7986_wf), }; static const struct mtk_eint_hw mt7986a_eint_hw = { diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index d39afc122516..91edb539925a 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -621,7 +621,6 @@ static int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps) { - struct device_node *np; unsigned reserved_maps; int ret; @@ -629,12 +628,11 @@ static int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, *num_maps = 0; reserved_maps = 0; - for_each_child_of_node(np_config, np) { + for_each_child_of_node_scoped(np_config, np) { ret = mtk_pctrl_dt_subnode_to_map(pctldev, np, map, &reserved_maps, num_maps); if (ret < 0) { pinctrl_utils_free_map(pctldev, *map, *num_maps); - of_node_put(np); return ret; } } diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c index b19bc391705e..e12316c42698 100644 --- a/drivers/pinctrl/mediatek/pinctrl-paris.c +++ b/drivers/pinctrl/mediatek/pinctrl-paris.c @@ -536,7 +536,6 @@ static int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, struct pinctrl_map **map, unsigned *num_maps) { - struct device_node *np; unsigned reserved_maps; int ret; @@ -544,13 +543,12 @@ static int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, *num_maps = 0; reserved_maps = 0; - for_each_child_of_node(np_config, np) { + for_each_child_of_node_scoped(np_config, np) { ret = mtk_pctrl_dt_subnode_to_map(pctldev, np, map, &reserved_maps, num_maps); if (ret < 0) { pinctrl_utils_free_map(pctldev, *map, *num_maps); - of_node_put(np); return ret; } } diff --git a/drivers/pinctrl/meson/pinctrl-meson-a1.c b/drivers/pinctrl/meson/pinctrl-meson-a1.c index 50a87d9618a8..d2ac9ca72a3e 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-a1.c +++ b/drivers/pinctrl/meson/pinctrl-meson-a1.c @@ -936,4 +936,5 @@ static struct platform_driver meson_a1_pinctrl_driver = { }; module_platform_driver(meson_a1_pinctrl_driver); +MODULE_DESCRIPTION("Amlogic Meson A1 SoC pinctrl driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c b/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c index ae3f8d0da05f..cad411d90727 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c +++ b/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c @@ -117,4 +117,5 @@ const struct pinmux_ops meson_axg_pmx_ops = { }; EXPORT_SYMBOL_GPL(meson_axg_pmx_ops); +MODULE_DESCRIPTION("Amlogic Meson AXG second generation pinmux driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg.c b/drivers/pinctrl/meson/pinctrl-meson-axg.c index 6667c9d0238f..8f4e7154b73f 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-axg.c +++ b/drivers/pinctrl/meson/pinctrl-meson-axg.c @@ -1091,4 +1091,5 @@ static struct platform_driver meson_axg_pinctrl_driver = { }; module_platform_driver(meson_axg_pinctrl_driver); +MODULE_DESCRIPTION("Amlogic Meson AXG pinctrl driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/pinctrl/meson/pinctrl-meson-g12a.c b/drivers/pinctrl/meson/pinctrl-meson-g12a.c index 2c17891ba6a9..32830269a5b4 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-g12a.c +++ b/drivers/pinctrl/meson/pinctrl-meson-g12a.c @@ -1426,4 +1426,5 @@ static struct platform_driver meson_g12a_pinctrl_driver = { }; module_platform_driver(meson_g12a_pinctrl_driver); +MODULE_DESCRIPTION("Amlogic Meson G12A SoC pinctrl driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c index f51fc3939252..2867f397fec6 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c +++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c @@ -910,4 +910,5 @@ static struct platform_driver meson_gxbb_pinctrl_driver = { }, }; module_platform_driver(meson_gxbb_pinctrl_driver); +MODULE_DESCRIPTION("Amlogic Meson GXBB pinctrl driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c index 51408996255b..a2f25fa02852 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c +++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c @@ -871,4 +871,5 @@ static struct platform_driver meson_gxl_pinctrl_driver = { }, }; module_platform_driver(meson_gxl_pinctrl_driver); +MODULE_DESCRIPTION("Amlogic Meson GXL pinctrl driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/meson/pinctrl-meson-s4.c b/drivers/pinctrl/meson/pinctrl-meson-s4.c index cea77864b880..60c7d5003e8a 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-s4.c +++ b/drivers/pinctrl/meson/pinctrl-meson-s4.c @@ -1230,4 +1230,5 @@ static struct platform_driver meson_s4_pinctrl_driver = { }; module_platform_driver(meson_s4_pinctrl_driver); +MODULE_DESCRIPTION("Amlogic Meson S4 SoC pinctrl driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index 524424ee6c4e..ef002b9dd464 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -767,4 +767,5 @@ int meson_pinctrl_probe(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(meson_pinctrl_probe); +MODULE_DESCRIPTION("Amlogic Meson SoCs core pinctrl driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/meson/pinctrl-meson8-pmx.c b/drivers/pinctrl/meson/pinctrl-meson8-pmx.c index f767b6923f9f..7f22aa0f8e36 100644 --- a/drivers/pinctrl/meson/pinctrl-meson8-pmx.c +++ b/drivers/pinctrl/meson/pinctrl-meson8-pmx.c @@ -101,4 +101,5 @@ const struct pinmux_ops meson8_pmx_ops = { .gpio_request_enable = meson8_pmx_request_gpio, }; EXPORT_SYMBOL_GPL(meson8_pmx_ops); +MODULE_DESCRIPTION("Amlogic Meson SoCs first generation pinmux driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index 80e3ac333136..47f62c89955a 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -811,19 +811,17 @@ static int abx500_dt_node_to_map(struct pinctrl_dev *pctldev, struct pinctrl_map **map, unsigned *num_maps) { unsigned reserved_maps; - struct device_node *np; int ret; reserved_maps = 0; *map = NULL; *num_maps = 0; - for_each_child_of_node(np_config, np) { + for_each_child_of_node_scoped(np_config, np) { ret = abx500_dt_subnode_to_map(pctldev, np, map, &reserved_maps, num_maps); if (ret < 0) { pinctrl_utils_free_map(pctldev, *map, *num_maps); - of_node_put(np); return ret; } } diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index cb0f0d5a5e45..fa78d5ecc685 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -804,19 +804,17 @@ static int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, unsigned int *num_maps) { unsigned int reserved_maps; - struct device_node *np; int ret; reserved_maps = 0; *map = NULL; *num_maps = 0; - for_each_child_of_node(np_config, np) { + for_each_child_of_node_scoped(np_config, np) { ret = nmk_pinctrl_dt_subnode_to_map(pctldev, np, map, &reserved_maps, num_maps); if (ret < 0) { pinctrl_utils_free_map(pctldev, *map, *num_maps); - of_node_put(np); return ret; } } diff --git a/drivers/pinctrl/nuvoton/Kconfig b/drivers/pinctrl/nuvoton/Kconfig index 2abbfcec1fae..7eadaaf48d6e 100644 --- a/drivers/pinctrl/nuvoton/Kconfig +++ b/drivers/pinctrl/nuvoton/Kconfig @@ -45,3 +45,22 @@ config PINCTRL_NPCM8XX Say Y or M here to enable pin controller and GPIO support for the Nuvoton NPCM8XX SoC. This is strongly recommended when building a kernel that will run on this chip. + +config PINCTRL_MA35 + bool + depends on (ARCH_MA35 || COMPILE_TEST) && OF + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select GENERIC_PINCONF + select GPIOLIB + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + select MFD_SYSCON + +config PINCTRL_MA35D1 + bool "Pinctrl and GPIO driver for Nuvoton MA35D1" + depends on (ARCH_MA35 || COMPILE_TEST) && OF + select PINCTRL_MA35 + help + Say Y here to enable pin controller and GPIO support + for Nuvoton MA35D1 SoC. diff --git a/drivers/pinctrl/nuvoton/Makefile b/drivers/pinctrl/nuvoton/Makefile index 08031eab0af6..346c5082bc60 100644 --- a/drivers/pinctrl/nuvoton/Makefile +++ b/drivers/pinctrl/nuvoton/Makefile @@ -4,3 +4,5 @@ obj-$(CONFIG_PINCTRL_WPCM450) += pinctrl-wpcm450.o obj-$(CONFIG_PINCTRL_NPCM7XX) += pinctrl-npcm7xx.o obj-$(CONFIG_PINCTRL_NPCM8XX) += pinctrl-npcm8xx.o +obj-$(CONFIG_PINCTRL_MA35) += pinctrl-ma35.o +obj-$(CONFIG_PINCTRL_MA35D1) += pinctrl-ma35d1.o diff --git a/drivers/pinctrl/nuvoton/pinctrl-ma35.c b/drivers/pinctrl/nuvoton/pinctrl-ma35.c new file mode 100644 index 000000000000..1fa00a23534a --- /dev/null +++ b/drivers/pinctrl/nuvoton/pinctrl-ma35.c @@ -0,0 +1,1187 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Nuvoton Technology Corp. + * + * Author: Shan-Chun Hung + * * Jacky Huang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "../core.h" +#include "../pinconf.h" +#include "pinctrl-ma35.h" + +#define MA35_MFP_REG_BASE 0x80 +#define MA35_MFP_REG_SZ_PER_BANK 8 +#define MA35_MFP_BITS_PER_PORT 4 + +#define MA35_GPIO_BANK_MAX 14 +#define MA35_GPIO_PORT_MAX 16 + +/* GPIO control registers */ +#define MA35_GP_REG_MODE 0x00 +#define MA35_GP_REG_DINOFF 0x04 +#define MA35_GP_REG_DOUT 0x08 +#define MA35_GP_REG_DATMSK 0x0c +#define MA35_GP_REG_PIN 0x10 +#define MA35_GP_REG_DBEN 0x14 +#define MA35_GP_REG_INTTYPE 0x18 +#define MA35_GP_REG_INTEN 0x1c +#define MA35_GP_REG_INTSRC 0x20 +#define MA35_GP_REG_SMTEN 0x24 +#define MA35_GP_REG_SLEWCTL 0x28 +#define MA35_GP_REG_SPW 0x2c +#define MA35_GP_REG_PUSEL 0x30 +#define MA35_GP_REG_DSL 0x38 +#define MA35_GP_REG_DSH 0x3c + +/* GPIO mode control */ +#define MA35_GP_MODE_INPUT 0x0 +#define MA35_GP_MODE_OUTPUT 0x1 +#define MA35_GP_MODE_OPEN_DRAIN 0x2 +#define MA35_GP_MODE_QUASI 0x3 +#define MA35_GP_MODE_MASK(n) GENMASK(n * 2 + 1, n * 2) + +#define MA35_GP_SLEWCTL_MASK(n) GENMASK(n * 2 + 1, n * 2) + +/* GPIO pull-up and pull-down selection control */ +#define MA35_GP_PUSEL_DISABLE 0x0 +#define MA35_GP_PUSEL_PULL_UP 0x1 +#define MA35_GP_PUSEL_PULL_DOWN 0x2 +#define MA35_GP_PUSEL_MASK(n) GENMASK(n * 2 + 1, n * 2) + +/* + * The MA35_GP_REG_INTEN bits 0 ~ 15 control low-level or falling edge trigger, + * while bits 16 ~ 31 control high-level or rising edge trigger. + */ +#define MA35_GP_INTEN_L(n) BIT(n) +#define MA35_GP_INTEN_H(n) BIT(n + 16) +#define MA35_GP_INTEN_BOTH(n) (MA35_GP_INTEN_H(n) | MA35_GP_INTEN_L(n)) + +/* + * The MA35_GP_REG_DSL register controls ports 0 to 7, while the MA35_GP_REG_DSH + * register controls ports 8 to 15. Each port occupies a width of 4 bits, with 3 + * bits being effective. + */ +#define MA35_GP_DS_REG(n) (n < 8 ? MA35_GP_REG_DSL : MA35_GP_REG_DSH) +#define MA35_GP_DS_MASK(n) GENMASK((n % 8) * 4 + 3, (n % 8) * 4) + +#define MVOLT_1800 0 +#define MVOLT_3300 1 + +/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) + +static const char * const gpio_group_name[] = { + "gpioa", "gpiob", "gpioc", "gpiod", "gpioe", "gpiof", "gpiog", + "gpioh", "gpioi", "gpioj", "gpiok", "gpiol", "gpiom", "gpion", +}; + +static const u32 ds_1800mv_tbl[] = { + 2900, 4400, 5800, 7300, 8600, 10100, 11500, 13000, +}; + +static const u32 ds_3300mv_tbl[] = { + 17100, 25600, 34100, 42800, 48000, 56000, 77000, 82000, +}; + +struct ma35_pin_func { + const char *name; + const char **groups; + u32 ngroups; +}; + +struct ma35_pin_setting { + u32 offset; + u32 shift; + u32 muxval; + unsigned long *configs; + unsigned int nconfigs; +}; + +struct ma35_pin_group { + const char *name; + unsigned int npins; + unsigned int *pins; + struct ma35_pin_setting *settings; +}; + +struct ma35_pin_bank { + void __iomem *reg_base; + struct clk *clk; + int irq; + u8 bank_num; + u8 nr_pins; + bool valid; + const char *name; + struct fwnode_handle *fwnode; + struct gpio_chip chip; + u32 irqtype; + u32 irqinten; + struct regmap *regmap; + struct device *dev; +}; + +struct ma35_pin_ctrl { + struct ma35_pin_bank *pin_banks; + u32 nr_banks; + u32 nr_pins; +}; + +struct ma35_pinctrl { + struct device *dev; + struct ma35_pin_ctrl *ctrl; + struct pinctrl_dev *pctl; + const struct ma35_pinctrl_soc_info *info; + struct regmap *regmap; + struct ma35_pin_group *groups; + unsigned int ngroups; + struct ma35_pin_func *functions; + unsigned int nfunctions; +}; + +static DEFINE_RAW_SPINLOCK(ma35_lock); + +static int ma35_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); + + return npctl->ngroups; +} + +static const char *ma35_get_group_name(struct pinctrl_dev *pctldev, unsigned int selector) +{ + struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); + + return npctl->groups[selector].name; +} + +static int ma35_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, + const unsigned int **pins, unsigned int *npins) +{ + struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); + + if (selector >= npctl->ngroups) + return -EINVAL; + + *pins = npctl->groups[selector].pins; + *npins = npctl->groups[selector].npins; + + return 0; +} + +static struct ma35_pin_group *ma35_pinctrl_find_group_by_name( + const struct ma35_pinctrl *npctl, const char *name) +{ + int i; + + for (i = 0; i < npctl->ngroups; i++) { + if (!strcmp(npctl->groups[i].name, name)) + return &npctl->groups[i]; + } + return NULL; +} + +static int ma35_pinctrl_dt_node_to_map_func(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); + struct ma35_pin_group *grp; + struct pinctrl_map *new_map; + struct device_node *parent; + int map_num = 1; + int i; + + /* + * first find the group of this node and check if we need create + * config maps for pins + */ + grp = ma35_pinctrl_find_group_by_name(npctl, np->name); + if (!grp) { + dev_err(npctl->dev, "unable to find group for node %s\n", np->name); + return -EINVAL; + } + + map_num += grp->npins; + new_map = devm_kcalloc(pctldev->dev, map_num, sizeof(*new_map), GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + *map = new_map; + *num_maps = map_num; + /* create mux map */ + parent = of_get_parent(np); + if (!parent) + return -EINVAL; + + new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; + new_map[0].data.mux.function = parent->name; + new_map[0].data.mux.group = np->name; + of_node_put(parent); + + new_map++; + for (i = 0; i < grp->npins; i++) { + new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; + new_map[i].data.configs.group_or_pin = pin_get_name(pctldev, grp->pins[i]); + new_map[i].data.configs.configs = grp->settings[i].configs; + new_map[i].data.configs.num_configs = grp->settings[i].nconfigs; + } + dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", + (*map)->data.mux.function, (*map)->data.mux.group, map_num); + + return 0; +} + +static const struct pinctrl_ops ma35_pctrl_ops = { + .get_groups_count = ma35_get_groups_count, + .get_group_name = ma35_get_group_name, + .get_group_pins = ma35_get_group_pins, + .dt_node_to_map = ma35_pinctrl_dt_node_to_map_func, + .dt_free_map = pinconf_generic_dt_free_map, +}; + +static int ma35_pinmux_get_func_count(struct pinctrl_dev *pctldev) +{ + struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); + + return npctl->nfunctions; +} + +static const char *ma35_pinmux_get_func_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); + + return npctl->functions[selector].name; +} + +static int ma35_pinmux_get_func_groups(struct pinctrl_dev *pctldev, + unsigned int function, + const char *const **groups, + unsigned int *const num_groups) +{ + struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); + + *groups = npctl->functions[function].groups; + *num_groups = npctl->functions[function].ngroups; + + return 0; +} + +static int ma35_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int selector, + unsigned int group) +{ + struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); + struct ma35_pin_group *grp = &npctl->groups[group]; + struct ma35_pin_setting *setting = grp->settings; + u32 i, regval; + + dev_dbg(npctl->dev, "enable function %s group %s\n", + npctl->functions[selector].name, npctl->groups[group].name); + + for (i = 0; i < grp->npins; i++) { + regmap_read(npctl->regmap, setting->offset, ®val); + regval &= ~GENMASK(setting->shift + MA35_MFP_BITS_PER_PORT - 1, + setting->shift); + regval |= setting->muxval << setting->shift; + regmap_write(npctl->regmap, setting->offset, regval); + setting++; + } + return 0; +} + +static const struct pinmux_ops ma35_pmx_ops = { + .get_functions_count = ma35_pinmux_get_func_count, + .get_function_name = ma35_pinmux_get_func_name, + .get_function_groups = ma35_pinmux_get_func_groups, + .set_mux = ma35_pinmux_set_mux, + .strict = true, +}; + +static void ma35_gpio_set_mode(void __iomem *reg_mode, unsigned int gpio, u32 mode) +{ + u32 regval = readl(reg_mode); + + regval &= ~MA35_GP_MODE_MASK(gpio); + regval |= field_prep(MA35_GP_MODE_MASK(gpio), mode); + + writel(regval, reg_mode); +} + +static u32 ma35_gpio_get_mode(void __iomem *reg_mode, unsigned int gpio) +{ + u32 regval = readl(reg_mode); + + return field_get(MA35_GP_MODE_MASK(gpio), regval); +} + +static int ma35_gpio_core_direction_in(struct gpio_chip *gc, unsigned int gpio) +{ + struct ma35_pin_bank *bank = gpiochip_get_data(gc); + void __iomem *reg_mode = bank->reg_base + MA35_GP_REG_MODE; + + guard(raw_spinlock_irqsave)(&ma35_lock); + + ma35_gpio_set_mode(reg_mode, gpio, MA35_GP_MODE_INPUT); + + return 0; +} + +static int ma35_gpio_core_direction_out(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct ma35_pin_bank *bank = gpiochip_get_data(gc); + void __iomem *reg_dout = bank->reg_base + MA35_GP_REG_DOUT; + void __iomem *reg_mode = bank->reg_base + MA35_GP_REG_MODE; + unsigned int regval; + + guard(raw_spinlock_irqsave)(&ma35_lock); + + regval = readl(reg_dout); + if (val) + regval |= BIT(gpio); + else + regval &= ~BIT(gpio); + writel(regval, reg_dout); + + ma35_gpio_set_mode(reg_mode, gpio, MA35_GP_MODE_OUTPUT); + + return 0; +} + +static int ma35_gpio_core_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct ma35_pin_bank *bank = gpiochip_get_data(gc); + void __iomem *reg_pin = bank->reg_base + MA35_GP_REG_PIN; + + return !!(readl(reg_pin) & BIT(gpio)); +} + +static void ma35_gpio_core_set(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct ma35_pin_bank *bank = gpiochip_get_data(gc); + void __iomem *reg_dout = bank->reg_base + MA35_GP_REG_DOUT; + u32 regval; + + if (val) + regval = readl(reg_dout) | BIT(gpio); + else + regval = readl(reg_dout) & ~BIT(gpio); + + writel(regval, reg_dout); +} + +static int ma35_gpio_core_to_request(struct gpio_chip *gc, unsigned int gpio) +{ + struct ma35_pin_bank *bank = gpiochip_get_data(gc); + u32 reg_offs, bit_offs, regval; + + if (gpio < 8) { + /* The MFP low register controls port 0 ~ 7 */ + reg_offs = bank->bank_num * MA35_MFP_REG_SZ_PER_BANK; + bit_offs = gpio * MA35_MFP_BITS_PER_PORT; + } else { + /* The MFP high register controls port 8 ~ 15 */ + reg_offs = bank->bank_num * MA35_MFP_REG_SZ_PER_BANK + 4; + bit_offs = (gpio - 8) * MA35_MFP_BITS_PER_PORT; + } + + regmap_read(bank->regmap, MA35_MFP_REG_BASE + reg_offs, ®val); + regval &= ~GENMASK(bit_offs + MA35_MFP_BITS_PER_PORT - 1, bit_offs); + regmap_write(bank->regmap, MA35_MFP_REG_BASE + reg_offs, regval); + + return 0; +} + +static void ma35_irq_gpio_ack(struct irq_data *d) +{ + struct ma35_pin_bank *bank = gpiochip_get_data(irq_data_get_irq_chip_data(d)); + void __iomem *reg_intsrc = bank->reg_base + MA35_GP_REG_INTSRC; + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + writel(BIT(hwirq), reg_intsrc); +} + +static void ma35_irq_gpio_mask(struct irq_data *d) +{ + struct ma35_pin_bank *bank = gpiochip_get_data(irq_data_get_irq_chip_data(d)); + void __iomem *reg_ien = bank->reg_base + MA35_GP_REG_INTEN; + irq_hw_number_t hwirq = irqd_to_hwirq(d); + u32 regval; + + regval = readl(reg_ien); + + regval &= ~MA35_GP_INTEN_BOTH(hwirq); + + writel(regval, reg_ien); +} + +static void ma35_irq_gpio_unmask(struct irq_data *d) +{ + struct ma35_pin_bank *bank = gpiochip_get_data(irq_data_get_irq_chip_data(d)); + void __iomem *reg_itype = bank->reg_base + MA35_GP_REG_INTTYPE; + void __iomem *reg_ien = bank->reg_base + MA35_GP_REG_INTEN; + irq_hw_number_t hwirq = irqd_to_hwirq(d); + u32 bval, regval; + + bval = bank->irqtype & BIT(hwirq); + regval = readl(reg_itype); + regval &= ~BIT(hwirq); + writel(regval | bval, reg_itype); + + bval = bank->irqinten & MA35_GP_INTEN_BOTH(hwirq); + regval = readl(reg_ien); + regval &= ~MA35_GP_INTEN_BOTH(hwirq); + writel(regval | bval, reg_ien); +} + +static int ma35_irq_irqtype(struct irq_data *d, unsigned int type) +{ + struct ma35_pin_bank *bank = gpiochip_get_data(irq_data_get_irq_chip_data(d)); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + switch (type) { + case IRQ_TYPE_EDGE_BOTH: + irq_set_handler_locked(d, handle_edge_irq); + bank->irqtype &= ~BIT(hwirq); + bank->irqinten |= MA35_GP_INTEN_BOTH(hwirq); + break; + case IRQ_TYPE_EDGE_RISING: + case IRQ_TYPE_LEVEL_HIGH: + irq_set_handler_locked(d, handle_edge_irq); + bank->irqtype &= ~BIT(hwirq); + bank->irqinten |= MA35_GP_INTEN_H(hwirq); + bank->irqinten &= ~MA35_GP_INTEN_L(hwirq); + break; + case IRQ_TYPE_EDGE_FALLING: + case IRQ_TYPE_LEVEL_LOW: + irq_set_handler_locked(d, handle_edge_irq); + bank->irqtype &= ~BIT(hwirq); + bank->irqinten |= MA35_GP_INTEN_L(hwirq); + bank->irqinten &= ~MA35_GP_INTEN_H(hwirq); + break; + default: + return -EINVAL; + } + + writel(bank->irqtype, bank->reg_base + MA35_GP_REG_INTTYPE); + writel(bank->irqinten, bank->reg_base + MA35_GP_REG_INTEN); + + return 0; +} + +static struct irq_chip ma35_gpio_irqchip = { + .name = "MA35-GPIO-IRQ", + .irq_disable = ma35_irq_gpio_mask, + .irq_enable = ma35_irq_gpio_unmask, + .irq_ack = ma35_irq_gpio_ack, + .irq_mask = ma35_irq_gpio_mask, + .irq_unmask = ma35_irq_gpio_unmask, + .irq_set_type = ma35_irq_irqtype, + .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static void ma35_irq_demux_intgroup(struct irq_desc *desc) +{ + struct ma35_pin_bank *bank = gpiochip_get_data(irq_desc_get_handler_data(desc)); + struct irq_domain *irqdomain = bank->chip.irq.domain; + struct irq_chip *irqchip = irq_desc_get_chip(desc); + unsigned long isr; + int offset; + + chained_irq_enter(irqchip, desc); + + isr = readl(bank->reg_base + MA35_GP_REG_INTSRC); + + for_each_set_bit(offset, &isr, bank->nr_pins) + generic_handle_irq(irq_find_mapping(irqdomain, offset)); + + chained_irq_exit(irqchip, desc); +} + +static int ma35_gpiolib_register(struct platform_device *pdev, struct ma35_pinctrl *npctl) +{ + struct ma35_pin_ctrl *ctrl = npctl->ctrl; + struct ma35_pin_bank *bank = ctrl->pin_banks; + int ret; + int i; + + for (i = 0; i < ctrl->nr_banks; i++, bank++) { + if (!bank->valid) { + dev_warn(&pdev->dev, "%pfw: bank is not valid\n", bank->fwnode); + continue; + } + bank->irqtype = 0; + bank->irqinten = 0; + bank->chip.label = bank->name; + bank->chip.of_gpio_n_cells = 2; + bank->chip.parent = &pdev->dev; + bank->chip.request = ma35_gpio_core_to_request; + bank->chip.direction_input = ma35_gpio_core_direction_in; + bank->chip.direction_output = ma35_gpio_core_direction_out; + bank->chip.get = ma35_gpio_core_get; + bank->chip.set = ma35_gpio_core_set; + bank->chip.base = -1; + bank->chip.ngpio = bank->nr_pins; + bank->chip.can_sleep = false; + + if (bank->irq > 0) { + struct gpio_irq_chip *girq; + + girq = &bank->chip.irq; + gpio_irq_chip_set_chip(girq, &ma35_gpio_irqchip); + girq->parent_handler = ma35_irq_demux_intgroup; + girq->num_parents = 1; + + girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, + sizeof(*girq->parents), GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + + girq->parents[0] = bank->irq; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + } + + ret = devm_gpiochip_add_data(&pdev->dev, &bank->chip, bank); + if (ret) { + dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n", + bank->chip.label, ret); + return ret; + } + } + return 0; +} + +static int ma35_get_bank_data(struct ma35_pin_bank *bank) +{ + bank->reg_base = fwnode_iomap(bank->fwnode, 0); + if (!bank->reg_base) + return -ENOMEM; + + bank->irq = fwnode_irq_get(bank->fwnode, 0); + + bank->nr_pins = MA35_GPIO_PORT_MAX; + + bank->clk = of_clk_get(to_of_node(bank->fwnode), 0); + if (IS_ERR(bank->clk)) + return PTR_ERR(bank->clk); + + return clk_prepare_enable(bank->clk); +} + +static int ma35_pinctrl_get_soc_data(struct ma35_pinctrl *pctl, struct platform_device *pdev) +{ + struct fwnode_handle *child; + struct ma35_pin_ctrl *ctrl; + struct ma35_pin_bank *bank; + int i, id = 0; + + ctrl = pctl->ctrl; + ctrl->nr_banks = MA35_GPIO_BANK_MAX; + + ctrl->pin_banks = devm_kcalloc(&pdev->dev, ctrl->nr_banks, + sizeof(*ctrl->pin_banks), GFP_KERNEL); + if (!ctrl->pin_banks) + return -ENOMEM; + + for (i = 0; i < ctrl->nr_banks; i++) { + ctrl->pin_banks[i].bank_num = i; + ctrl->pin_banks[i].name = gpio_group_name[i]; + } + + for_each_gpiochip_node(&pdev->dev, child) { + bank = &ctrl->pin_banks[id]; + bank->fwnode = child; + bank->regmap = pctl->regmap; + bank->dev = &pdev->dev; + if (!ma35_get_bank_data(bank)) + bank->valid = true; + id++; + } + return 0; +} + +static void ma35_gpio_cla_port(unsigned int gpio_num, unsigned int *group, + unsigned int *num) +{ + *group = gpio_num / MA35_GPIO_PORT_MAX; + *num = gpio_num % MA35_GPIO_PORT_MAX; +} + +static int ma35_pinconf_set_pull(struct ma35_pinctrl *npctl, unsigned int pin, + int pull_up) +{ + unsigned int port, group_num; + void __iomem *base; + u32 regval, pull_sel = MA35_GP_PUSEL_DISABLE; + + ma35_gpio_cla_port(pin, &group_num, &port); + base = npctl->ctrl->pin_banks[group_num].reg_base; + + regval = readl(base + MA35_GP_REG_PUSEL); + regval &= ~MA35_GP_PUSEL_MASK(port); + + switch (pull_up) { + case PIN_CONFIG_BIAS_PULL_UP: + pull_sel = MA35_GP_PUSEL_PULL_UP; + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + pull_sel = MA35_GP_PUSEL_PULL_DOWN; + break; + + case PIN_CONFIG_BIAS_DISABLE: + pull_sel = MA35_GP_PUSEL_DISABLE; + break; + } + + regval |= field_prep(MA35_GP_PUSEL_MASK(port), pull_sel); + writel(regval, base + MA35_GP_REG_PUSEL); + + return 0; +} + +static int ma35_pinconf_get_output(struct ma35_pinctrl *npctl, unsigned int pin) +{ + unsigned int port, group_num; + void __iomem *base; + u32 mode; + + ma35_gpio_cla_port(pin, &group_num, &port); + base = npctl->ctrl->pin_banks[group_num].reg_base; + + mode = ma35_gpio_get_mode(base + MA35_GP_REG_MODE, port); + if (mode == MA35_GP_MODE_OUTPUT) + return 1; + + return 0; +} + +static int ma35_pinconf_get_pull(struct ma35_pinctrl *npctl, unsigned int pin) +{ + unsigned int port, group_num; + void __iomem *base; + u32 regval, pull_sel; + + ma35_gpio_cla_port(pin, &group_num, &port); + base = npctl->ctrl->pin_banks[group_num].reg_base; + + regval = readl(base + MA35_GP_REG_PUSEL); + + pull_sel = field_get(MA35_GP_PUSEL_MASK(port), regval); + + switch (pull_sel) { + case MA35_GP_PUSEL_PULL_UP: + return PIN_CONFIG_BIAS_PULL_UP; + + case MA35_GP_PUSEL_PULL_DOWN: + return PIN_CONFIG_BIAS_PULL_DOWN; + + case MA35_GP_PUSEL_DISABLE: + return PIN_CONFIG_BIAS_DISABLE; + } + + return PIN_CONFIG_BIAS_DISABLE; +} + +static int ma35_pinconf_set_output(struct ma35_pinctrl *npctl, unsigned int pin, bool out) +{ + unsigned int port, group_num; + void __iomem *base; + + ma35_gpio_cla_port(pin, &group_num, &port); + base = npctl->ctrl->pin_banks[group_num].reg_base; + + ma35_gpio_set_mode(base + MA35_GP_REG_MODE, port, MA35_GP_MODE_OUTPUT); + + return 0; +} + +static int ma35_pinconf_get_power_source(struct ma35_pinctrl *npctl, unsigned int pin) +{ + unsigned int port, group_num; + void __iomem *base; + u32 regval; + + ma35_gpio_cla_port(pin, &group_num, &port); + base = npctl->ctrl->pin_banks[group_num].reg_base; + + regval = readl(base + MA35_GP_REG_SPW); + + if (regval & BIT(port)) + return MVOLT_3300; + else + return MVOLT_1800; +} + +static int ma35_pinconf_set_power_source(struct ma35_pinctrl *npctl, + unsigned int pin, int arg) +{ + unsigned int port, group_num; + void __iomem *base; + u32 regval; + + if ((arg != MVOLT_1800) && (arg != MVOLT_3300)) + return -EINVAL; + + ma35_gpio_cla_port(pin, &group_num, &port); + base = npctl->ctrl->pin_banks[group_num].reg_base; + + regval = readl(base + MA35_GP_REG_SPW); + + if (arg == MVOLT_1800) + regval &= ~BIT(port); + else + regval |= BIT(port); + + writel(regval, base + MA35_GP_REG_SPW); + + return 0; +} + +static int ma35_pinconf_get_drive_strength(struct ma35_pinctrl *npctl, unsigned int pin, + u32 *strength) +{ + unsigned int port, group_num; + void __iomem *base; + u32 regval, ds_val; + + ma35_gpio_cla_port(pin, &group_num, &port); + base = npctl->ctrl->pin_banks[group_num].reg_base; + + regval = readl(base + MA35_GP_DS_REG(port)); + ds_val = field_get(MA35_GP_DS_MASK(port), regval); + + if (ma35_pinconf_get_power_source(npctl, pin) == MVOLT_1800) + *strength = ds_1800mv_tbl[ds_val]; + else + *strength = ds_3300mv_tbl[ds_val]; + + return 0; +} + +static int ma35_pinconf_set_drive_strength(struct ma35_pinctrl *npctl, unsigned int pin, + int strength) +{ + unsigned int port, group_num; + void __iomem *base; + int i, ds_val = -1; + u32 regval; + + if (ma35_pinconf_get_power_source(npctl, pin) == MVOLT_1800) { + for (i = 0; i < ARRAY_SIZE(ds_1800mv_tbl); i++) { + if (ds_1800mv_tbl[i] == strength) { + ds_val = i; + break; + } + } + } else { + for (i = 0; i < ARRAY_SIZE(ds_3300mv_tbl); i++) { + if (ds_3300mv_tbl[i] == strength) { + ds_val = i; + break; + } + } + } + if (ds_val == -1) + return -EINVAL; + + ma35_gpio_cla_port(pin, &group_num, &port); + base = npctl->ctrl->pin_banks[group_num].reg_base; + + regval = readl(base + MA35_GP_DS_REG(port)); + regval &= ~MA35_GP_DS_MASK(port); + regval |= field_prep(MA35_GP_DS_MASK(port), ds_val); + + writel(regval, base + MA35_GP_DS_REG(port)); + + return 0; +} + +static int ma35_pinconf_get_schmitt_enable(struct ma35_pinctrl *npctl, unsigned int pin) +{ + unsigned int port, group_num; + void __iomem *base; + u32 regval; + + ma35_gpio_cla_port(pin, &group_num, &port); + base = npctl->ctrl->pin_banks[group_num].reg_base; + + regval = readl(base + MA35_GP_REG_SMTEN); + + return !!(regval & BIT(port)); +} + +static int ma35_pinconf_set_schmitt(struct ma35_pinctrl *npctl, unsigned int pin, int enable) +{ + unsigned int port, group_num; + void __iomem *base; + u32 regval; + + ma35_gpio_cla_port(pin, &group_num, &port); + base = npctl->ctrl->pin_banks[group_num].reg_base; + + regval = readl(base + MA35_GP_REG_SMTEN); + + if (enable) + regval |= BIT(port); + else + regval &= ~BIT(port); + + writel(regval, base + MA35_GP_REG_SMTEN); + + return 0; +} + +static int ma35_pinconf_get_slew_rate(struct ma35_pinctrl *npctl, unsigned int pin) +{ + unsigned int port, group_num; + void __iomem *base; + u32 regval; + + ma35_gpio_cla_port(pin, &group_num, &port); + base = npctl->ctrl->pin_banks[group_num].reg_base; + + regval = readl(base + MA35_GP_REG_SLEWCTL); + + return field_get(MA35_GP_SLEWCTL_MASK(port), regval); +} + +static int ma35_pinconf_set_slew_rate(struct ma35_pinctrl *npctl, unsigned int pin, int rate) +{ + unsigned int port, group_num; + void __iomem *base; + u32 regval; + + ma35_gpio_cla_port(pin, &group_num, &port); + base = npctl->ctrl->pin_banks[group_num].reg_base; + + regval = readl(base + MA35_GP_REG_SLEWCTL); + regval &= ~MA35_GP_SLEWCTL_MASK(port); + regval |= field_prep(MA35_GP_SLEWCTL_MASK(port), rate); + + writel(regval, base + MA35_GP_REG_SLEWCTL); + + return 0; +} + +static int ma35_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, unsigned long *config) +{ + struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param = pinconf_to_config_param(*config); + u32 arg; + int ret; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + if (ma35_pinconf_get_pull(npctl, pin) != param) + return -EINVAL; + arg = 1; + break; + + case PIN_CONFIG_DRIVE_STRENGTH: + ret = ma35_pinconf_get_drive_strength(npctl, pin, &arg); + if (ret) + return ret; + break; + + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + arg = ma35_pinconf_get_schmitt_enable(npctl, pin); + break; + + case PIN_CONFIG_SLEW_RATE: + arg = ma35_pinconf_get_slew_rate(npctl, pin); + break; + + case PIN_CONFIG_OUTPUT_ENABLE: + arg = ma35_pinconf_get_output(npctl, pin); + break; + + case PIN_CONFIG_POWER_SOURCE: + arg = ma35_pinconf_get_power_source(npctl, pin); + break; + + default: + return -EINVAL; + } + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int ma35_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param; + unsigned int arg = 0; + int i, ret = 0; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = ma35_pinconf_set_pull(npctl, pin, param); + break; + + case PIN_CONFIG_DRIVE_STRENGTH: + ret = ma35_pinconf_set_drive_strength(npctl, pin, arg); + break; + + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + ret = ma35_pinconf_set_schmitt(npctl, pin, 1); + break; + + case PIN_CONFIG_INPUT_SCHMITT: + ret = ma35_pinconf_set_schmitt(npctl, pin, arg); + break; + + case PIN_CONFIG_SLEW_RATE: + ret = ma35_pinconf_set_slew_rate(npctl, pin, arg); + break; + + case PIN_CONFIG_OUTPUT_ENABLE: + ret = ma35_pinconf_set_output(npctl, pin, arg); + break; + + case PIN_CONFIG_POWER_SOURCE: + ret = ma35_pinconf_set_power_source(npctl, pin, arg); + break; + + default: + return -EINVAL; + } + + if (ret) + break; + } + return ret; +} + +static const struct pinconf_ops ma35_pinconf_ops = { + .pin_config_get = ma35_pinconf_get, + .pin_config_set = ma35_pinconf_set, + .is_generic = true, +}; + +static int ma35_pinctrl_parse_groups(struct device_node *np, struct ma35_pin_group *grp, + struct ma35_pinctrl *npctl, u32 index) +{ + struct ma35_pin_setting *pin; + unsigned long *configs; + unsigned int nconfigs; + int i, j, count, ret; + u32 *elems; + + grp->name = np->name; + + ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &nconfigs); + if (ret) + return ret; + + count = of_property_count_elems_of_size(np, "nuvoton,pins", sizeof(u32)); + if (!count || count % 3) + return -EINVAL; + + elems = devm_kmalloc_array(npctl->dev, count, sizeof(u32), GFP_KERNEL); + if (!elems) + return -ENOMEM; + + ret = of_property_read_u32_array(np, "nuvoton,pins", elems, count); + if (ret) + return -EINVAL; + + grp->npins = count / 3; + + grp->pins = devm_kcalloc(npctl->dev, grp->npins, sizeof(*grp->pins), GFP_KERNEL); + if (!grp->pins) + return -ENOMEM; + + grp->settings = devm_kcalloc(npctl->dev, grp->npins, sizeof(*grp->settings), GFP_KERNEL); + if (!grp->settings) + return -ENOMEM; + + pin = grp->settings; + + for (i = 0, j = 0; i < count; i += 3, j++) { + pin->offset = elems[i] * MA35_MFP_REG_SZ_PER_BANK + MA35_MFP_REG_BASE; + pin->shift = (elems[i + 1] * MA35_MFP_BITS_PER_PORT) % 32; + pin->muxval = elems[i + 2]; + pin->configs = configs; + pin->nconfigs = nconfigs; + grp->pins[j] = npctl->info->get_pin_num(pin->offset, pin->shift); + pin++; + } + return 0; +} + +static int ma35_pinctrl_parse_functions(struct device_node *np, struct ma35_pinctrl *npctl, + u32 index) +{ + struct device_node *child; + struct ma35_pin_func *func; + struct ma35_pin_group *grp; + static u32 grp_index; + u32 ret, i = 0; + + dev_dbg(npctl->dev, "parse function(%d): %s\n", index, np->name); + + func = &npctl->functions[index]; + func->name = np->name; + func->ngroups = of_get_child_count(np); + + if (func->ngroups <= 0) + return 0; + + func->groups = devm_kcalloc(npctl->dev, func->ngroups, sizeof(char *), GFP_KERNEL); + if (!func->groups) + return -ENOMEM; + + for_each_child_of_node(np, child) { + func->groups[i] = child->name; + grp = &npctl->groups[grp_index++]; + ret = ma35_pinctrl_parse_groups(child, grp, npctl, i++); + if (ret) { + of_node_put(child); + return ret; + } + } + return 0; +} + +static int ma35_pinctrl_probe_dt(struct platform_device *pdev, struct ma35_pinctrl *npctl) +{ + struct fwnode_handle *child; + u32 idx = 0; + int ret; + + device_for_each_child_node(&pdev->dev, child) { + if (fwnode_property_present(child, "gpio-controller")) + continue; + npctl->nfunctions++; + npctl->ngroups += of_get_child_count(to_of_node(child)); + } + + if (!npctl->nfunctions) + return -EINVAL; + + npctl->functions = devm_kcalloc(&pdev->dev, npctl->nfunctions, + sizeof(*npctl->functions), GFP_KERNEL); + if (!npctl->functions) + return -ENOMEM; + + npctl->groups = devm_kcalloc(&pdev->dev, npctl->ngroups, + sizeof(*npctl->groups), GFP_KERNEL); + if (!npctl->groups) + return -ENOMEM; + + device_for_each_child_node(&pdev->dev, child) { + if (fwnode_property_present(child, "gpio-controller")) + continue; + + ret = ma35_pinctrl_parse_functions(to_of_node(child), npctl, idx++); + if (ret) { + fwnode_handle_put(child); + dev_err(&pdev->dev, "failed to parse function\n"); + return ret; + } + } + return 0; +} + +int ma35_pinctrl_probe(struct platform_device *pdev, const struct ma35_pinctrl_soc_info *info) +{ + struct pinctrl_desc *ma35_pinctrl_desc; + struct device *dev = &pdev->dev; + struct ma35_pinctrl *npctl; + int ret; + + if (!info || !info->pins || !info->npins) { + dev_err(&pdev->dev, "wrong pinctrl info\n"); + return -EINVAL; + } + + npctl = devm_kzalloc(&pdev->dev, sizeof(*npctl), GFP_KERNEL); + if (!npctl) + return -ENOMEM; + + ma35_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*ma35_pinctrl_desc), GFP_KERNEL); + if (!ma35_pinctrl_desc) + return -ENOMEM; + + npctl->ctrl = devm_kzalloc(&pdev->dev, sizeof(*npctl->ctrl), GFP_KERNEL); + if (!npctl->ctrl) + return -ENOMEM; + + ma35_pinctrl_desc->name = dev_name(&pdev->dev); + ma35_pinctrl_desc->pins = info->pins; + ma35_pinctrl_desc->npins = info->npins; + ma35_pinctrl_desc->pctlops = &ma35_pctrl_ops; + ma35_pinctrl_desc->pmxops = &ma35_pmx_ops; + ma35_pinctrl_desc->confops = &ma35_pinconf_ops; + ma35_pinctrl_desc->owner = THIS_MODULE; + + npctl->info = info; + npctl->dev = &pdev->dev; + + npctl->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "nuvoton,sys"); + if (IS_ERR(npctl->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(npctl->regmap), + "No syscfg phandle specified\n"); + + ret = ma35_pinctrl_get_soc_data(npctl, pdev); + if (ret) + return dev_err_probe(&pdev->dev, ret, "fail to get soc data\n"); + + platform_set_drvdata(pdev, npctl); + + ret = ma35_pinctrl_probe_dt(pdev, npctl); + if (ret) + return dev_err_probe(&pdev->dev, ret, "fail to probe MA35 pinctrl dt\n"); + + ret = devm_pinctrl_register_and_init(dev, ma35_pinctrl_desc, npctl, &npctl->pctl); + if (ret) + return dev_err_probe(&pdev->dev, ret, "fail to register MA35 pinctrl\n"); + + ret = pinctrl_enable(npctl->pctl); + if (ret) + return dev_err_probe(&pdev->dev, ret, "fail to enable MA35 pinctrl\n"); + + return ma35_gpiolib_register(pdev, npctl); +} + +int ma35_pinctrl_suspend(struct device *dev) +{ + struct ma35_pinctrl *npctl = dev_get_drvdata(dev); + + return pinctrl_force_sleep(npctl->pctl); +} + +int ma35_pinctrl_resume(struct device *dev) +{ + struct ma35_pinctrl *npctl = dev_get_drvdata(dev); + + return pinctrl_force_default(npctl->pctl); +} diff --git a/drivers/pinctrl/nuvoton/pinctrl-ma35.h b/drivers/pinctrl/nuvoton/pinctrl-ma35.h new file mode 100644 index 000000000000..218084100541 --- /dev/null +++ b/drivers/pinctrl/nuvoton/pinctrl-ma35.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024 Nuvoton Technology Corp. + * + * Author: Shan-Chun Hung + * * Jacky Huang + */ +#ifndef __PINCTRL_MA35_H +#define __PINCTRL_MA35_H + +#include +#include +#include + +struct ma35_mux_desc { + const char *name; + u32 muxval; +}; + +struct ma35_pin_data { + u32 offset; + u32 shift; + struct ma35_mux_desc *muxes; +}; + +struct ma35_pinctrl_soc_info { + const struct pinctrl_pin_desc *pins; + unsigned int npins; + int (*get_pin_num)(int offset, int shift); +}; + +#define MA35_PIN(num, n, o, s, ...) { \ + .number = num, \ + .name = #n, \ + .drv_data = &(struct ma35_pin_data) { \ + .offset = o, \ + .shift = s, \ + .muxes = (struct ma35_mux_desc[]) { \ + __VA_ARGS__, { } }, \ + }, \ +} + +#define MA35_MUX(_val, _name) { \ + .name = _name, \ + .muxval = _val, \ +} + +int ma35_pinctrl_probe(struct platform_device *pdev, const struct ma35_pinctrl_soc_info *info); +int ma35_pinctrl_suspend(struct device *dev); +int ma35_pinctrl_resume(struct device *dev); + +#endif /* __PINCTRL_MA35_H */ diff --git a/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c b/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c new file mode 100644 index 000000000000..8bb9a5a35954 --- /dev/null +++ b/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c @@ -0,0 +1,1799 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Nuvoton Technology Corp. + * + * Author: Shan-Chun Hung + * * Jacky Huang + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "pinctrl-ma35.h" + +static const struct pinctrl_pin_desc ma35d1_pins[] = { + MA35_PIN(0, PA0, 0x80, 0x0, + MA35_MUX(0x0, "GPA0"), + MA35_MUX(0x2, "UART1_nCTS"), + MA35_MUX(0x3, "UART16_RXD"), + MA35_MUX(0x6, "NAND_DATA0"), + MA35_MUX(0x7, "EBI_AD0"), + MA35_MUX(0x9, "EBI_ADR0")), + MA35_PIN(1, PA1, 0x80, 0x4, + MA35_MUX(0x0, "GPA1"), + MA35_MUX(0x2, "UART1_nRTS"), + MA35_MUX(0x3, "UART16_TXD"), + MA35_MUX(0x6, "NAND_DATA1"), + MA35_MUX(0x7, "EBI_AD1"), + MA35_MUX(0x9, "EBI_ADR1")), + MA35_PIN(2, PA2, 0x80, 0x8, + MA35_MUX(0x0, "GPA2"), + MA35_MUX(0x2, "UART1_RXD"), + MA35_MUX(0x6, "NAND_DATA2"), + MA35_MUX(0x7, "EBI_AD2"), + MA35_MUX(0x9, "EBI_ADR2")), + MA35_PIN(3, PA3, 0x80, 0xc, + MA35_MUX(0x0, "GPA3"), + MA35_MUX(0x2, "UART1_TXD"), + MA35_MUX(0x6, "NAND_DATA3"), + MA35_MUX(0x7, "EBI_AD3"), + MA35_MUX(0x9, "EBI_ADR3")), + MA35_PIN(4, PA4, 0x80, 0x10, + MA35_MUX(0x0, "GPA4"), + MA35_MUX(0x2, "UART3_nCTS"), + MA35_MUX(0x3, "UART2_RXD"), + MA35_MUX(0x6, "NAND_DATA4"), + MA35_MUX(0x7, "EBI_AD4"), + MA35_MUX(0x9, "EBI_ADR4")), + MA35_PIN(5, PA5, 0x80, 0x14, + MA35_MUX(0x0, "GPA5"), + MA35_MUX(0x2, "UART3_nRTS"), + MA35_MUX(0x3, "UART2_TXD"), + MA35_MUX(0x6, "NAND_DATA5"), + MA35_MUX(0x7, "EBI_AD5"), + MA35_MUX(0x9, "EBI_ADR5")), + MA35_PIN(6, PA6, 0x80, 0x18, + MA35_MUX(0x0, "GPA6"), + MA35_MUX(0x2, "UART3_RXD"), + MA35_MUX(0x6, "NAND_DATA6"), + MA35_MUX(0x7, "EBI_AD6"), + MA35_MUX(0x9, "EBI_ADR6")), + MA35_PIN(7, PA7, 0x80, 0x1c, + MA35_MUX(0x0, "GPA7"), + MA35_MUX(0x2, "UART3_TXD"), + MA35_MUX(0x6, "NAND_DATA7"), + MA35_MUX(0x7, "EBI_AD7"), + MA35_MUX(0x9, "EBI_ADR7")), + MA35_PIN(8, PA8, 0x84, 0x0, + MA35_MUX(0x0, "GPA8"), + MA35_MUX(0x2, "UART5_nCTS"), + MA35_MUX(0x3, "UART4_RXD"), + MA35_MUX(0x6, "NAND_RDY0"), + MA35_MUX(0x7, "EBI_AD8"), + MA35_MUX(0x9, "EBI_ADR8")), + MA35_PIN(9, PA9, 0x84, 0x4, + MA35_MUX(0x0, "GPA9"), + MA35_MUX(0x2, "UART5_nRTS"), + MA35_MUX(0x3, "UART4_TXD"), + MA35_MUX(0x6, "NAND_nRE"), + MA35_MUX(0x7, "EBI_AD9"), + MA35_MUX(0x9, "EBI_ADR9")), + MA35_PIN(10, PA10, 0x84, 0x8, + MA35_MUX(0x0, "GPA10"), + MA35_MUX(0x2, "UART5_RXD"), + MA35_MUX(0x6, "NAND_nWE"), + MA35_MUX(0x7, "EBI_AD10"), + MA35_MUX(0x9, "EBI_ADR10")), + MA35_PIN(11, PA11, 0x84, 0xc, + MA35_MUX(0x0, "GPA11"), + MA35_MUX(0x2, "UART5_TXD"), + MA35_MUX(0x6, "NAND_CLE"), + MA35_MUX(0x7, "EBI_AD11"), + MA35_MUX(0x9, "EBI_ADR11")), + MA35_PIN(12, PA12, 0x84, 0x10, + MA35_MUX(0x0, "GPA12"), + MA35_MUX(0x2, "UART7_nCTS"), + MA35_MUX(0x3, "UART8_RXD"), + MA35_MUX(0x6, "NAND_ALE"), + MA35_MUX(0x7, "EBI_AD12"), + MA35_MUX(0x9, "EBI_ADR12")), + MA35_PIN(13, PA13, 0x84, 0x14, + MA35_MUX(0x0, "GPA13"), + MA35_MUX(0x2, "UART7_nRTS"), + MA35_MUX(0x3, "UART8_TXD"), + MA35_MUX(0x6, "NAND_nCS0"), + MA35_MUX(0x7, "EBI_AD13"), + MA35_MUX(0x9, "EBI_ADR13")), + MA35_PIN(14, PA14, 0x84, 0x18, + MA35_MUX(0x0, "GPA14"), + MA35_MUX(0x2, "UART7_RXD"), + MA35_MUX(0x3, "CAN3_RXD"), + MA35_MUX(0x6, "NAND_nWP"), + MA35_MUX(0x7, "EBI_AD14"), + MA35_MUX(0x9, "EBI_ADR14")), + MA35_PIN(15, PA15, 0x84, 0x1c, + MA35_MUX(0x0, "GPA15"), + MA35_MUX(0x1, "EPWM0_CH2"), + MA35_MUX(0x2, "UART9_nCTS"), + MA35_MUX(0x3, "UART6_RXD"), + MA35_MUX(0x4, "I2C4_SDA"), + MA35_MUX(0x5, "CAN2_RXD"), + MA35_MUX(0x7, "EBI_ALE"), + MA35_MUX(0x9, "QEI0_A"), + MA35_MUX(0xb, "TM1"), + MA35_MUX(0xe, "RGMII0_PPS"), + MA35_MUX(0xf, "RMII0_PPS")), + MA35_PIN(16, PB0, 0x88, 0x0, + MA35_MUX(0x0, "GPB0"), + MA35_MUX(0x8, "EADC0_CH0")), + MA35_PIN(17, PB1, 0x88, 0x4, + MA35_MUX(0x0, "GPB1"), + MA35_MUX(0x8, "EADC0_CH1")), + MA35_PIN(18, PB2, 0x88, 0x8, + MA35_MUX(0x0, "GPB2"), + MA35_MUX(0x8, "EADC0_CH2")), + MA35_PIN(19, PB3, 0x88, 0xc, + MA35_MUX(0x0, "GPB3"), + MA35_MUX(0x8, "EADC0_CH3")), + MA35_PIN(20, PB4, 0x88, 0x10, + MA35_MUX(0x0, "GPB4"), + MA35_MUX(0x8, "EADC0_CH4")), + MA35_PIN(21, PB5, 0x88, 0x14, + MA35_MUX(0x0, "GPB5"), + MA35_MUX(0x8, "EADC0_CH5")), + MA35_PIN(22, PB6, 0x88, 0x18, + MA35_MUX(0x0, "GPB6"), + MA35_MUX(0x8, "EADC0_CH6")), + MA35_PIN(23, PB7, 0x88, 0x1c, + MA35_MUX(0x0, "GPB7"), + MA35_MUX(0x8, "EADC0_CH7")), + MA35_PIN(24, PB8, 0x8c, 0x0, + MA35_MUX(0x0, "GPB8"), + MA35_MUX(0x1, "EPWM2_BRAKE0"), + MA35_MUX(0x2, "UART2_nCTS"), + MA35_MUX(0x3, "UART1_RXD"), + MA35_MUX(0x4, "I2C2_SDA"), + MA35_MUX(0x5, "SPI0_SS1"), + MA35_MUX(0x6, "SPI0_I2SMCLK"), + MA35_MUX(0x8, "ADC0_CH0"), + MA35_MUX(0x9, "EBI_nCS0"), + MA35_MUX(0xb, "TM4"), + MA35_MUX(0xe, "QEI2_INDEX"), + MA35_MUX(0xf, "KPI_ROW6")), + MA35_PIN(25, PB9, 0x8c, 0x4, + MA35_MUX(0x0, "GPB9"), + MA35_MUX(0x1, "EPWM2_CH4"), + MA35_MUX(0x2, "UART2_nRTS"), + MA35_MUX(0x3, "UART1_TXD"), + MA35_MUX(0x4, "I2C2_SCL"), + MA35_MUX(0x5, "SPI0_CLK"), + MA35_MUX(0x6, "I2S0_MCLK"), + MA35_MUX(0x7, "CCAP1_HSYNC"), + MA35_MUX(0x8, "ADC0_CH1"), + MA35_MUX(0x9, "EBI_ALE"), + MA35_MUX(0xa, "EBI_AD13"), + MA35_MUX(0xb, "TM0_EXT"), + MA35_MUX(0xc, "I2S1_MCLK"), + MA35_MUX(0xd, "SC0_nCD"), + MA35_MUX(0xe, "QEI2_A"), + MA35_MUX(0xf, "KPI_ROW7")), + MA35_PIN(26, PB10, 0x8c, 0x8, + MA35_MUX(0x0, "GPB10"), + MA35_MUX(0x1, "EPWM2_CH5"), + MA35_MUX(0x2, "UART2_RXD"), + MA35_MUX(0x3, "CAN0_RXD"), + MA35_MUX(0x5, "SPI0_MOSI"), + MA35_MUX(0x6, "EBI_MCLK"), + MA35_MUX(0x7, "CCAP1_VSYNC"), + MA35_MUX(0x8, "ADC0_CH2"), + MA35_MUX(0x9, "EBI_ADR15"), + MA35_MUX(0xa, "EBI_AD14"), + MA35_MUX(0xb, "TM5"), + MA35_MUX(0xc, "I2C1_SDA"), + MA35_MUX(0xd, "INT1"), + MA35_MUX(0xe, "QEI2_B")), + MA35_PIN(27, PB11, 0x8c, 0xc, + MA35_MUX(0x0, "GPB11"), + MA35_MUX(0x1, "EPWM2_BRAKE1"), + MA35_MUX(0x2, "UART2_TXD"), + MA35_MUX(0x3, "CAN0_TXD"), + MA35_MUX(0x5, "SPI0_MISO"), + MA35_MUX(0x6, "I2S1_MCLK"), + MA35_MUX(0x7, "CCAP1_SFIELD"), + MA35_MUX(0x8, "ADC0_CH3"), + MA35_MUX(0x9, "EBI_nCS2"), + MA35_MUX(0xa, "EBI_ALE"), + MA35_MUX(0xb, "TM5_EXT"), + MA35_MUX(0xc, "I2C1_SCL"), + MA35_MUX(0xd, "INT2"), + MA35_MUX(0xe, "QEI2_INDEX")), + MA35_PIN(28, PB12, 0x8c, 0x10, + MA35_MUX(0x0, "GPB12"), + MA35_MUX(0x1, "EPWM2_CH0"), + MA35_MUX(0x2, "UART4_nCTS"), + MA35_MUX(0x3, "UART3_RXD"), + MA35_MUX(0x4, "I2C3_SDA"), + MA35_MUX(0x5, "CAN2_RXD"), + MA35_MUX(0x6, "I2S1_LRCK"), + MA35_MUX(0x8, "ADC0_CH4"), + MA35_MUX(0x9, "EBI_ADR16"), + MA35_MUX(0xe, "ECAP2_IC0")), + MA35_PIN(29, PB13, 0x8c, 0x14, + MA35_MUX(0x0, "GPB13"), + MA35_MUX(0x1, "EPWM2_CH1"), + MA35_MUX(0x2, "UART4_nRTS"), + MA35_MUX(0x3, "UART3_TXD"), + MA35_MUX(0x4, "I2C3_SCL"), + MA35_MUX(0x5, "CAN2_TXD"), + MA35_MUX(0x6, "I2S1_BCLK"), + MA35_MUX(0x8, "ADC0_CH5"), + MA35_MUX(0x9, "EBI_ADR17"), + MA35_MUX(0xe, "ECAP2_IC1")), + MA35_PIN(30, PB14, 0x8c, 0x18, + MA35_MUX(0x0, "GPB14"), + MA35_MUX(0x1, "EPWM2_CH2"), + MA35_MUX(0x2, "UART4_RXD"), + MA35_MUX(0x3, "CAN1_RXD"), + MA35_MUX(0x5, "I2C4_SDA"), + MA35_MUX(0x6, "I2S1_DI"), + MA35_MUX(0x8, "ADC0_CH6"), + MA35_MUX(0x9, "EBI_ADR18"), + MA35_MUX(0xe, "ECAP2_IC2")), + MA35_PIN(31, PB15, 0x8c, 0x1c, + MA35_MUX(0x0, "GPB15"), + MA35_MUX(0x1, "EPWM2_CH3"), + MA35_MUX(0x2, "UART4_TXD"), + MA35_MUX(0x3, "CAN1_TXD"), + MA35_MUX(0x5, "I2C4_SCL"), + MA35_MUX(0x6, "I2S1_DO"), + MA35_MUX(0x8, "ADC0_CH7"), + MA35_MUX(0x9, "EBI_ADR19")), + MA35_PIN(32, PC0, 0x90, 0x0, + MA35_MUX(0x0, "GPC0"), + MA35_MUX(0x4, "I2C4_SDA"), + MA35_MUX(0x6, "SD0_CMD/eMMC0_CMD")), + MA35_PIN(33, PC1, 0x90, 0x4, + MA35_MUX(0x0, "GPC1"), + MA35_MUX(0x4, "I2C4_SCL"), + MA35_MUX(0x6, "SD0_CLK/eMMC0_CLK")), + MA35_PIN(34, PC2, 0x90, 0x8, + MA35_MUX(0x0, "GPC2"), + MA35_MUX(0x3, "CAN0_RXD"), + MA35_MUX(0x6, "SD0_DAT0/eMMC0_DAT0")), + MA35_PIN(35, PC3, 0x90, 0xc, + MA35_MUX(0x0, "GPC3"), + MA35_MUX(0x3, "CAN0_TXD"), + MA35_MUX(0x6, "SD0_DAT1/eMMC0_DAT1")), + MA35_PIN(36, PC4, 0x90, 0x10, + MA35_MUX(0x0, "GPC4"), + MA35_MUX(0x4, "I2C5_SDA"), + MA35_MUX(0x6, "SD0_DAT2/eMMC0_DAT2")), + MA35_PIN(37, PC5, 0x90, 0x14, + MA35_MUX(0x0, "GPC5"), + MA35_MUX(0x4, "I2C5_SCL"), + MA35_MUX(0x6, "SD0_DAT3/eMMC0_DAT3")), + MA35_PIN(38, PC6, 0x90, 0x18, + MA35_MUX(0x0, "GPC6"), + MA35_MUX(0x3, "CAN1_RXD"), + MA35_MUX(0x6, "SD0_nCD")), + MA35_PIN(39, PC7, 0x90, 0x1c, + MA35_MUX(0x0, "GPC7"), + MA35_MUX(0x3, "CAN1_TXD"), + MA35_MUX(0x6, "SD0_WP")), + MA35_PIN(40, PC12, 0x94, 0x10, + MA35_MUX(0x0, "GPC12"), + MA35_MUX(0x2, "UART12_nCTS"), + MA35_MUX(0x3, "UART11_RXD"), + MA35_MUX(0x6, "LCM_DATA16")), + MA35_PIN(41, PC13, 0x94, 0x14, + MA35_MUX(0x0, "GPC13"), + MA35_MUX(0x2, "UART12_nRTS"), + MA35_MUX(0x3, "UART11_TXD"), + MA35_MUX(0x6, "LCM_DATA17")), + MA35_PIN(42, PC14, 0x94, 0x18, + MA35_MUX(0x0, "GPC14"), + MA35_MUX(0x2, "UART12_RXD"), + MA35_MUX(0x6, "LCM_DATA18")), + MA35_PIN(43, PC15, 0x94, 0x1c, + MA35_MUX(0x0, "GPC15"), + MA35_MUX(0x2, "UART12_TXD"), + MA35_MUX(0x6, "LCM_DATA19"), + MA35_MUX(0x7, "LCM_MPU_TE"), + MA35_MUX(0x8, "LCM_MPU_VSYNC")), + MA35_PIN(44, PD0, 0x98, 0x0, + MA35_MUX(0x0, "GPD0"), + MA35_MUX(0x2, "UART3_nCTS"), + MA35_MUX(0x3, "UART4_RXD"), + MA35_MUX(0x5, "QSPI0_SS0")), + MA35_PIN(45, PD1, 0x98, 0x4, + MA35_MUX(0x0, "GPD1"), + MA35_MUX(0x2, "UART3_nRTS"), + MA35_MUX(0x3, "UART4_TXD"), + MA35_MUX(0x5, "QSPI0_CLK")), + MA35_PIN(46, PD2, 0x98, 0x8, + MA35_MUX(0x0, "GPD2"), + MA35_MUX(0x2, "UART3_RXD"), + MA35_MUX(0x5, "QSPI0_MOSI0")), + MA35_PIN(47, PD3, 0x98, 0xc, + MA35_MUX(0x0, "GPD3"), + MA35_MUX(0x2, "UART3_TXD"), + MA35_MUX(0x5, "QSPI0_MISO0")), + MA35_PIN(48, PD4, 0x98, 0x10, + MA35_MUX(0x0, "GPD4"), + MA35_MUX(0x2, "UART1_nCTS"), + MA35_MUX(0x3, "UART2_RXD"), + MA35_MUX(0x4, "I2C2_SDA"), + MA35_MUX(0x5, "QSPI0_MOSI1")), + MA35_PIN(49, PD5, 0x98, 0x14, + MA35_MUX(0x0, "GPD5"), + MA35_MUX(0x2, "UART1_nRTS"), + MA35_MUX(0x3, "UART2_TXD"), + MA35_MUX(0x4, "I2C2_SCL"), + MA35_MUX(0x5, "QSPI0_MISO1")), + MA35_PIN(50, PD6, 0x98, 0x18, + MA35_MUX(0x0, "GPD6"), + MA35_MUX(0x1, "EPWM0_SYNC_IN"), + MA35_MUX(0x2, "UART1_RXD"), + MA35_MUX(0x5, "QSPI1_MOSI1"), + MA35_MUX(0x6, "I2C0_SDA"), + MA35_MUX(0x7, "I2S0_MCLK"), + MA35_MUX(0x8, "EPWM0_CH0"), + MA35_MUX(0x9, "EBI_AD5"), + MA35_MUX(0xa, "SPI3_SS1"), + MA35_MUX(0xb, "TRACE_CLK")), + MA35_PIN(51, PD7, 0x98, 0x1c, + MA35_MUX(0x0, "GPD7"), + MA35_MUX(0x1, "EPWM0_SYNC_OUT"), + MA35_MUX(0x2, "UART1_TXD"), + MA35_MUX(0x5, "QSPI1_MISO1"), + MA35_MUX(0x6, "I2C0_SCL"), + MA35_MUX(0x7, "I2S1_MCLK"), + MA35_MUX(0x8, "EPWM0_CH1"), + MA35_MUX(0x9, "EBI_AD6"), + MA35_MUX(0xa, "SC1_nCD"), + MA35_MUX(0xb, "EADC0_ST")), + MA35_PIN(52, PD8, 0x9c, 0x0, + MA35_MUX(0x0, "GPD8"), + MA35_MUX(0x1, "EPWM0_BRAKE0"), + MA35_MUX(0x2, "UART16_nCTS"), + MA35_MUX(0x3, "UART15_RXD"), + MA35_MUX(0x5, "QSPI1_SS0"), + MA35_MUX(0x7, "I2S1_LRCK"), + MA35_MUX(0x8, "EPWM0_CH2"), + MA35_MUX(0x9, "EBI_AD7"), + MA35_MUX(0xa, "SC1_CLK"), + MA35_MUX(0xb, "TM0")), + MA35_PIN(53, PD9, 0x9c, 0x4, + MA35_MUX(0x0, "GPD9"), + MA35_MUX(0x1, "EPWM0_BRAKE1"), + MA35_MUX(0x2, "UART16_nRTS"), + MA35_MUX(0x3, "UART15_TXD"), + MA35_MUX(0x5, "QSPI1_CLK"), + MA35_MUX(0x7, "I2S1_BCLK"), + MA35_MUX(0x8, "EPWM0_CH3"), + MA35_MUX(0x9, "EBI_AD8"), + MA35_MUX(0xa, "SC1_DAT"), + MA35_MUX(0xb, "TM0_EXT")), + MA35_PIN(54, PD10, 0x9c, 0x8, + MA35_MUX(0x0, "GPD10"), + MA35_MUX(0x1, "EPWM1_BRAKE0"), + MA35_MUX(0x2, "UART16_RXD"), + MA35_MUX(0x5, "QSPI1_MOSI0"), + MA35_MUX(0x7, "I2S1_DI"), + MA35_MUX(0x8, "EPWM0_CH4"), + MA35_MUX(0x9, "EBI_AD9"), + MA35_MUX(0xa, "SC1_RST"), + MA35_MUX(0xb, "TM2")), + MA35_PIN(55, PD11, 0x9c, 0xc, + MA35_MUX(0x0, "GPD11"), + MA35_MUX(0x1, "EPWM1_BRAKE1"), + MA35_MUX(0x2, "UART16_TXD"), + MA35_MUX(0x5, "QSPI1_MISO0"), + MA35_MUX(0x7, "I2S1_DO"), + MA35_MUX(0x8, "EPWM0_CH5"), + MA35_MUX(0x9, "EBI_AD10"), + MA35_MUX(0xa, "SC1_PWR"), + MA35_MUX(0xb, "TM2_EXT")), + MA35_PIN(56, PD12, 0x9c, 0x10, + MA35_MUX(0x0, "GPD12"), + MA35_MUX(0x1, "EPWM0_BRAKE0"), + MA35_MUX(0x2, "UART11_TXD"), + MA35_MUX(0x3, "UART10_RXD"), + MA35_MUX(0x4, "I2C4_SDA"), + MA35_MUX(0x6, "TRACE_DATA0"), + MA35_MUX(0x7, "EBI_nCS1"), + MA35_MUX(0x8, "EBI_AD4"), + MA35_MUX(0x9, "QEI0_INDEX"), + MA35_MUX(0xb, "TM5"), + MA35_MUX(0xc, "I2S1_LRCK"), + MA35_MUX(0xd, "INT1")), + MA35_PIN(57, PD13, 0x9c, 0x14, + MA35_MUX(0x0, "GPD13"), + MA35_MUX(0x1, "EPWM0_BRAKE1"), + MA35_MUX(0x2, "UART11_RXD"), + MA35_MUX(0x3, "UART10_TXD"), + MA35_MUX(0x4, "I2C4_SCL"), + MA35_MUX(0x6, "TRACE_DATA1"), + MA35_MUX(0x7, "EBI_nCS2"), + MA35_MUX(0x8, "EBI_AD5"), + MA35_MUX(0x9, "ECAP0_IC0"), + MA35_MUX(0xb, "TM5_EXT"), + MA35_MUX(0xc, "I2S1_BCLK")), + MA35_PIN(58, PD14, 0x9c, 0x18, + MA35_MUX(0x0, "GPD14"), + MA35_MUX(0x1, "EPWM0_SYNC_IN"), + MA35_MUX(0x2, "UART11_nCTS"), + MA35_MUX(0x3, "CAN3_RXD"), + MA35_MUX(0x6, "TRACE_DATA2"), + MA35_MUX(0x7, "EBI_MCLK"), + MA35_MUX(0x8, "EBI_AD6"), + MA35_MUX(0x9, "ECAP0_IC1"), + MA35_MUX(0xb, "TM6"), + MA35_MUX(0xc, "I2S1_DI"), + MA35_MUX(0xd, "INT3")), + MA35_PIN(59, PD15, 0x9c, 0x1c, + MA35_MUX(0x0, "GPD15"), + MA35_MUX(0x1, "EPWM0_SYNC_OUT"), + MA35_MUX(0x2, "UART11_nRTS"), + MA35_MUX(0x3, "CAN3_TXD"), + MA35_MUX(0x6, "TRACE_DATA3"), + MA35_MUX(0x7, "EBI_ALE"), + MA35_MUX(0x8, "EBI_AD7"), + MA35_MUX(0x9, "ECAP0_IC2"), + MA35_MUX(0xb, "TM6_EXT"), + MA35_MUX(0xc, "I2S1_DO")), + MA35_PIN(60, PE0, 0xa0, 0x0, + MA35_MUX(0x0, "GPE0"), + MA35_MUX(0x2, "UART9_nCTS"), + MA35_MUX(0x3, "UART8_RXD"), + MA35_MUX(0x7, "CCAP1_DATA0"), + MA35_MUX(0x8, "RGMII0_MDC"), + MA35_MUX(0x9, "RMII0_MDC")), + MA35_PIN(61, PE1, 0xa0, 0x4, + MA35_MUX(0x0, "GPE1"), + MA35_MUX(0x2, "UART9_nRTS"), + MA35_MUX(0x3, "UART8_TXD"), + MA35_MUX(0x7, "CCAP1_DATA1"), + MA35_MUX(0x8, "RGMII0_MDIO"), + MA35_MUX(0x9, "RMII0_MDIO")), + MA35_PIN(62, PE2, 0xa0, 0x8, + MA35_MUX(0x0, "GPE2"), + MA35_MUX(0x2, "UART9_RXD"), + MA35_MUX(0x7, "CCAP1_DATA2"), + MA35_MUX(0x8, "RGMII0_TXCTL"), + MA35_MUX(0x9, "RMII0_TXEN")), + MA35_PIN(63, PE3, 0xa0, 0xc, + MA35_MUX(0x0, "GPE3"), + MA35_MUX(0x2, "UART9_TXD"), + MA35_MUX(0x7, "CCAP1_DATA3"), + MA35_MUX(0x8, "RGMII0_TXD0"), + MA35_MUX(0x9, "RMII0_TXD0")), + MA35_PIN(64, PE4, 0xa0, 0x10, + MA35_MUX(0x0, "GPE4"), + MA35_MUX(0x2, "UART4_nCTS"), + MA35_MUX(0x3, "UART3_RXD"), + MA35_MUX(0x7, "CCAP1_DATA4"), + MA35_MUX(0x8, "RGMII0_TXD1"), + MA35_MUX(0x9, "RMII0_TXD1")), + MA35_PIN(65, PE5, 0xa0, 0x14, + MA35_MUX(0x0, "GPE5"), + MA35_MUX(0x2, "UART4_nRTS"), + MA35_MUX(0x3, "UART3_TXD"), + MA35_MUX(0x7, "CCAP1_DATA5"), + MA35_MUX(0x8, "RGMII0_RXCLK"), + MA35_MUX(0x9, "RMII0_REFCLK")), + MA35_PIN(66, PE6, 0xa0, 0x18, + MA35_MUX(0x0, "GPE6"), + MA35_MUX(0x2, "UART4_RXD"), + MA35_MUX(0x7, "CCAP1_DATA6"), + MA35_MUX(0x8, "RGMII0_RXCTL"), + MA35_MUX(0x9, "RMII0_CRSDV")), + MA35_PIN(67, PE7, 0xa0, 0x1c, + MA35_MUX(0x0, "GPE7"), + MA35_MUX(0x2, "UART4_TXD"), + MA35_MUX(0x7, "CCAP1_DATA7"), + MA35_MUX(0x8, "RGMII0_RXD0"), + MA35_MUX(0x9, "RMII0_RXD0")), + MA35_PIN(68, PE8, 0xa4, 0x0, + MA35_MUX(0x0, "GPE8"), + MA35_MUX(0x2, "UART13_nCTS"), + MA35_MUX(0x3, "UART12_RXD"), + MA35_MUX(0x7, "CCAP1_SCLK"), + MA35_MUX(0x8, "RGMII0_RXD1"), + MA35_MUX(0x9, "RMII0_RXD1")), + MA35_PIN(69, PE9, 0xa4, 0x4, + MA35_MUX(0x0, "GPE9"), + MA35_MUX(0x2, "UART13_nRTS"), + MA35_MUX(0x3, "UART12_TXD"), + MA35_MUX(0x7, "CCAP1_PIXCLK"), + MA35_MUX(0x8, "RGMII0_RXD2"), + MA35_MUX(0x9, "RMII0_RXERR")), + MA35_PIN(70, PE10, 0xa4, 0x8, + MA35_MUX(0x0, "GPE10"), + MA35_MUX(0x2, "UART15_nCTS"), + MA35_MUX(0x3, "UART14_RXD"), + MA35_MUX(0x5, "SPI1_SS0"), + MA35_MUX(0x7, "CCAP1_HSYNC"), + MA35_MUX(0x8, "RGMII0_RXD3")), + MA35_PIN(71, PE11, 0xa4, 0xc, + MA35_MUX(0x0, "GPE11"), + MA35_MUX(0x2, "UART15_nRTS"), + MA35_MUX(0x3, "UART14_TXD"), + MA35_MUX(0x5, "SPI1_CLK"), + MA35_MUX(0x7, "CCAP1_VSYNC"), + MA35_MUX(0x8, "RGMII0_TXCLK")), + MA35_PIN(72, PE12, 0xa4, 0x10, + MA35_MUX(0x0, "GPE12"), + MA35_MUX(0x2, "UART15_RXD"), + MA35_MUX(0x5, "SPI1_MOSI"), + MA35_MUX(0x7, "CCAP1_DATA8"), + MA35_MUX(0x8, "RGMII0_TXD2")), + MA35_PIN(73, PE13, 0xa4, 0x14, + MA35_MUX(0x0, "GPE13"), + MA35_MUX(0x2, "UART15_TXD"), + MA35_MUX(0x5, "SPI1_MISO"), + MA35_MUX(0x7, "CCAP1_DATA9"), + MA35_MUX(0x8, "RGMII0_TXD3")), + MA35_PIN(74, PE14, 0xa4, 0x18, + MA35_MUX(0x0, "GPE14"), + MA35_MUX(0x1, "UART0_TXD")), + MA35_PIN(75, PE15, 0xa4, 0x1c, + MA35_MUX(0x0, "GPE15"), + MA35_MUX(0x1, "UART0_RXD")), + MA35_PIN(76, PF0, 0xa8, 0x0, + MA35_MUX(0x0, "GPF0"), + MA35_MUX(0x2, "UART2_nCTS"), + MA35_MUX(0x3, "UART1_RXD"), + MA35_MUX(0x6, "RGMII0_RXD3"), + MA35_MUX(0x8, "RGMII1_MDC"), + MA35_MUX(0x9, "RMII1_MDC"), + MA35_MUX(0xe, "KPI_COL0")), + MA35_PIN(77, PF1, 0xa8, 0x4, + MA35_MUX(0x0, "GPF1"), + MA35_MUX(0x2, "UART2_nRTS"), + MA35_MUX(0x3, "UART1_TXD"), + MA35_MUX(0x6, "RGMII0_TXCLK"), + MA35_MUX(0x8, "RGMII1_MDIO"), + MA35_MUX(0x9, "RMII1_MDIO"), + MA35_MUX(0xe, "KPI_COL1")), + MA35_PIN(78, PF2, 0xa8, 0x8, + MA35_MUX(0x0, "GPF2"), + MA35_MUX(0x2, "UART2_RXD"), + MA35_MUX(0x6, "RGMII0_TXD2"), + MA35_MUX(0x8, "RGMII1_TXCTL"), + MA35_MUX(0x9, "RMII1_TXEN"), + MA35_MUX(0xe, "KPI_COL2")), + MA35_PIN(79, PF3, 0xa8, 0xc, + MA35_MUX(0x0, "GPF3"), + MA35_MUX(0x2, "UART2_TXD"), + MA35_MUX(0x6, "RGMII0_TXD3"), + MA35_MUX(0x8, "RGMII1_TXD0"), + MA35_MUX(0x9, "RMII1_TXD0"), + MA35_MUX(0xe, "KPI_COL3")), + MA35_PIN(80, PF4, 0xa8, 0x10, + MA35_MUX(0x0, "GPF4"), + MA35_MUX(0x2, "UART11_nCTS"), + MA35_MUX(0x3, "UART10_RXD"), + MA35_MUX(0x4, "I2S0_LRCK"), + MA35_MUX(0x5, "SPI1_SS0"), + MA35_MUX(0x8, "RGMII1_TXD1"), + MA35_MUX(0x9, "RMII1_TXD1"), + MA35_MUX(0xd, "CAN2_RXD"), + MA35_MUX(0xe, "KPI_ROW0")), + MA35_PIN(81, PF5, 0xa8, 0x14, + MA35_MUX(0x0, "GPF5"), + MA35_MUX(0x2, "UART11_nRTS"), + MA35_MUX(0x3, "UART10_TXD"), + MA35_MUX(0x4, "I2S0_BCLK"), + MA35_MUX(0x5, "SPI1_CLK"), + MA35_MUX(0x8, "RGMII1_RXCLK"), + MA35_MUX(0x9, "RMII1_REFCLK"), + MA35_MUX(0xd, "CAN2_TXD"), + MA35_MUX(0xe, "KPI_ROW1")), + MA35_PIN(82, PF6, 0xa8, 0x18, + MA35_MUX(0x0, "GPF6"), + MA35_MUX(0x2, "UART11_RXD"), + MA35_MUX(0x4, "I2S0_DI"), + MA35_MUX(0x5, "SPI1_MOSI"), + MA35_MUX(0x8, "RGMII1_RXCTL"), + MA35_MUX(0x9, "RMII1_CRSDV"), + MA35_MUX(0xa, "I2C4_SDA"), + MA35_MUX(0xd, "SC0_CLK"), + MA35_MUX(0xe, "KPI_ROW2")), + MA35_PIN(83, PF7, 0xa8, 0x1c, + MA35_MUX(0x0, "GPF7"), + MA35_MUX(0x2, "UART11_TXD"), + MA35_MUX(0x4, "I2S0_DO"), + MA35_MUX(0x5, "SPI1_MISO"), + MA35_MUX(0x8, "RGMII1_RXD0"), + MA35_MUX(0x9, "RMII1_RXD0"), + MA35_MUX(0xa, "I2C4_SCL"), + MA35_MUX(0xd, "SC0_DAT"), + MA35_MUX(0xe, "KPI_ROW3")), + MA35_PIN(84, PF8, 0xac, 0x0, + MA35_MUX(0x0, "GPF8"), + MA35_MUX(0x2, "UART13_RXD"), + MA35_MUX(0x4, "I2C5_SDA"), + MA35_MUX(0x5, "SPI0_SS0"), + MA35_MUX(0x8, "RGMII1_RXD1"), + MA35_MUX(0x9, "RMII1_RXD1"), + MA35_MUX(0xd, "SC0_RST"), + MA35_MUX(0xe, "KPI_COL4")), + MA35_PIN(85, PF9, 0xac, 0x4, + MA35_MUX(0x0, "GPF9"), + MA35_MUX(0x2, "UART13_TXD"), + MA35_MUX(0x4, "I2C5_SCL"), + MA35_MUX(0x5, "SPI0_SS1"), + MA35_MUX(0x8, "RGMII1_RXD2"), + MA35_MUX(0x9, "RMII1_RXERR"), + MA35_MUX(0xd, "SC0_PWR"), + MA35_MUX(0xe, "KPI_COL5")), + MA35_PIN(86, PF10, 0xac, 0x8, + MA35_MUX(0x0, "GPF10"), + MA35_MUX(0x2, "UART13_nCTS"), + MA35_MUX(0x5, "I2S0_LRCK"), + MA35_MUX(0x6, "SPI1_SS0"), + MA35_MUX(0x8, "RGMII1_RXD3"), + MA35_MUX(0x9, "SC0_CLK"), + MA35_MUX(0xe, "KPI_COL6")), + MA35_PIN(87, PF11, 0xac, 0xc, + MA35_MUX(0x0, "GPF11"), + MA35_MUX(0x2, "UART13_nRTS"), + MA35_MUX(0x5, "I2S0_BCLK"), + MA35_MUX(0x6, "SPI1_CLK"), + MA35_MUX(0x8, "RGMII1_TXCLK"), + MA35_MUX(0x9, "SC0_DAT"), + MA35_MUX(0xe, "KPI_COL7")), + MA35_PIN(88, PF12, 0xac, 0x10, + MA35_MUX(0x0, "GPF12"), + MA35_MUX(0x5, "I2S0_DI"), + MA35_MUX(0x6, "SPI1_MOSI"), + MA35_MUX(0x8, "RGMII1_TXD2"), + MA35_MUX(0x9, "SC0_RST"), + MA35_MUX(0xe, "KPI_ROW4")), + MA35_PIN(89, PF13, 0xac, 0x14, + MA35_MUX(0x0, "GPF13"), + MA35_MUX(0x5, "I2S0_DO"), + MA35_MUX(0x6, "SPI1_MISO"), + MA35_MUX(0x8, "RGMII1_TXD3"), + MA35_MUX(0x9, "SC0_PWR"), + MA35_MUX(0xe, "KPI_ROW5")), + MA35_PIN(90, PF14, 0xac, 0x18, + MA35_MUX(0x0, "GPF14"), + MA35_MUX(0x1, "EPWM2_BRAKE0"), + MA35_MUX(0x2, "EADC0_ST"), + MA35_MUX(0x3, "RGMII1_PPS"), + MA35_MUX(0x4, "RMII1_PPS"), + MA35_MUX(0x5, "SPI0_I2SMCLK"), + MA35_MUX(0x6, "SPI1_I2SMCLK"), + MA35_MUX(0x7, "CCAP1_SFIELD"), + MA35_MUX(0x8, "RGMII0_PPS"), + MA35_MUX(0x9, "RMII0_PPS"), + MA35_MUX(0xb, "TM0"), + MA35_MUX(0xc, "INT0"), + MA35_MUX(0xd, "SPI1_SS1"), + MA35_MUX(0xe, "QEI2_INDEX"), + MA35_MUX(0xf, "I2S0_MCLK")), + MA35_PIN(91, PF15, 0xac, 0x1c, + MA35_MUX(0x0, "GPF15"), + MA35_MUX(0x1, "HSUSB0_VBUSVLD")), + MA35_PIN(92, PG0, 0xb0, 0x0, + MA35_MUX(0x0, "GPG0"), + MA35_MUX(0x1, "EPWM0_CH0"), + MA35_MUX(0x2, "UART7_TXD"), + MA35_MUX(0x3, "CAN3_TXD"), + MA35_MUX(0x5, "SPI0_SS0"), + MA35_MUX(0x6, "EADC0_ST"), + MA35_MUX(0x7, "EBI_AD15"), + MA35_MUX(0x9, "I2S1_MCLK"), + MA35_MUX(0xa, "QEI0_INDEX"), + MA35_MUX(0xb, "TM1"), + MA35_MUX(0xc, "CLKO"), + MA35_MUX(0xd, "INT0"), + MA35_MUX(0xf, "EBI_ADR15")), + MA35_PIN(93, PG1, 0xb0, 0x4, + MA35_MUX(0x0, "GPG1"), + MA35_MUX(0x1, "EPWM0_CH3"), + MA35_MUX(0x2, "UART9_nRTS"), + MA35_MUX(0x3, "UART6_TXD"), + MA35_MUX(0x4, "I2C4_SCL"), + MA35_MUX(0x5, "CAN2_TXD"), + MA35_MUX(0x7, "EBI_nCS0"), + MA35_MUX(0x9, "QEI0_B"), + MA35_MUX(0xb, "TM1_EXT"), + MA35_MUX(0xe, "RGMII1_PPS"), + MA35_MUX(0xf, "RMII1_PPS")), + MA35_PIN(94, PG2, 0xb0, 0x8, + MA35_MUX(0x0, "GPG2"), + MA35_MUX(0x1, "EPWM0_CH4"), + MA35_MUX(0x2, "UART9_RXD"), + MA35_MUX(0x3, "CAN0_RXD"), + MA35_MUX(0x5, "SPI0_SS1"), + MA35_MUX(0x7, "EBI_ADR16"), + MA35_MUX(0x8, "EBI_nCS2"), + MA35_MUX(0xa, "QEI0_A"), + MA35_MUX(0xb, "TM3"), + MA35_MUX(0xd, "INT1")), + MA35_PIN(95, PG3, 0xb0, 0xc, + MA35_MUX(0x0, "GPG3"), + MA35_MUX(0x1, "EPWM0_CH5"), + MA35_MUX(0x2, "UART9_TXD"), + MA35_MUX(0x3, "CAN0_TXD"), + MA35_MUX(0x5, "SPI0_I2SMCLK"), + MA35_MUX(0x7, "EBI_ADR17"), + MA35_MUX(0x8, "EBI_nCS1"), + MA35_MUX(0x9, "EBI_MCLK"), + MA35_MUX(0xa, "QEI0_B"), + MA35_MUX(0xb, "TM3_EXT"), + MA35_MUX(0xc, "I2S1_MCLK")), + MA35_PIN(96, PG4, 0xb0, 0x10, + MA35_MUX(0x0, "GPG4"), + MA35_MUX(0x1, "EPWM1_CH0"), + MA35_MUX(0x2, "UART5_nCTS"), + MA35_MUX(0x3, "UART6_RXD"), + MA35_MUX(0x5, "SPI3_SS0"), + MA35_MUX(0x6, "QEI1_INDEX"), + MA35_MUX(0x7, "EBI_ADR18"), + MA35_MUX(0x8, "EBI_nCS0"), + MA35_MUX(0x9, "I2S1_DO"), + MA35_MUX(0xa, "SC1_CLK"), + MA35_MUX(0xb, "TM4"), + MA35_MUX(0xd, "INT2"), + MA35_MUX(0xe, "ECAP1_IC2")), + MA35_PIN(97, PG5, 0xb0, 0x14, + MA35_MUX(0x0, "GPG5"), + MA35_MUX(0x1, "EPWM1_CH1"), + MA35_MUX(0x2, "UART5_nRTS"), + MA35_MUX(0x3, "UART6_TXD"), + MA35_MUX(0x5, "SPI3_CLK"), + MA35_MUX(0x6, "ECAP0_IC0"), + MA35_MUX(0x7, "EBI_ADR19"), + MA35_MUX(0x8, "EBI_ALE"), + MA35_MUX(0x9, "I2S1_DI"), + MA35_MUX(0xa, "SC1_DAT"), + MA35_MUX(0xb, "TM4_EXT")), + MA35_PIN(98, PG6, 0xb0, 0x18, + MA35_MUX(0x0, "GPG6"), + MA35_MUX(0x1, "EPWM1_CH2"), + MA35_MUX(0x2, "UART5_RXD"), + MA35_MUX(0x3, "CAN1_RXD"), + MA35_MUX(0x5, "SPI3_MOSI"), + MA35_MUX(0x6, "ECAP0_IC1"), + MA35_MUX(0x7, "EBI_nRD"), + MA35_MUX(0x9, "I2S1_BCLK"), + MA35_MUX(0xa, "SC1_RST"), + MA35_MUX(0xb, "TM7"), + MA35_MUX(0xd, "INT3")), + MA35_PIN(99, PG7, 0xb0, 0x1c, + MA35_MUX(0x0, "GPG7"), + MA35_MUX(0x1, "EPWM1_CH3"), + MA35_MUX(0x2, "UART5_TXD"), + MA35_MUX(0x3, "CAN1_TXD"), + MA35_MUX(0x5, "SPI3_MISO"), + MA35_MUX(0x6, "ECAP0_IC2"), + MA35_MUX(0x7, "EBI_nWR"), + MA35_MUX(0x9, "I2S1_LRCK"), + MA35_MUX(0xa, "SC1_PWR"), + MA35_MUX(0xb, "TM7_EXT")), + MA35_PIN(100, PG8, 0xb4, 0x0, + MA35_MUX(0x0, "GPG8"), + MA35_MUX(0x1, "EPWM1_CH4"), + MA35_MUX(0x2, "UART12_RXD"), + MA35_MUX(0x3, "CAN3_RXD"), + MA35_MUX(0x5, "SPI2_SS0"), + MA35_MUX(0x6, "LCM_VSYNC"), + MA35_MUX(0x7, "I2C3_SDA"), + MA35_MUX(0xc, "EBI_AD7"), + MA35_MUX(0xd, "EBI_nCS0")), + MA35_PIN(101, PG9, 0xb4, 0x4, + MA35_MUX(0x0, "GPG9"), + MA35_MUX(0x1, "EPWM1_CH5"), + MA35_MUX(0x2, "UART12_TXD"), + MA35_MUX(0x3, "CAN3_TXD"), + MA35_MUX(0x5, "SPI2_CLK"), + MA35_MUX(0x6, "LCM_HSYNC"), + MA35_MUX(0x7, "I2C3_SCL"), + MA35_MUX(0xc, "EBI_AD8"), + MA35_MUX(0xd, "EBI_nCS1")), + MA35_PIN(102, PG10, 0xb4, 0x8, + MA35_MUX(0x0, "GPG10"), + MA35_MUX(0x2, "UART12_nRTS"), + MA35_MUX(0x3, "UART13_TXD"), + MA35_MUX(0x5, "SPI2_MOSI"), + MA35_MUX(0x6, "LCM_CLK"), + MA35_MUX(0xc, "EBI_AD9"), + MA35_MUX(0xd, "EBI_nWRH")), + MA35_PIN(103, PG11, 0xb4, 0xc, + MA35_MUX(0x0, "GPG11"), + MA35_MUX(0x3, "JTAG_TDO"), + MA35_MUX(0x5, "I2S0_MCLK"), + MA35_MUX(0x6, "NAND_RDY1"), + MA35_MUX(0x7, "EBI_nWRH"), + MA35_MUX(0x8, "EBI_nCS1"), + MA35_MUX(0xa, "EBI_AD0")), + MA35_PIN(104, PG12, 0xb4, 0x10, + MA35_MUX(0x0, "GPG12"), + MA35_MUX(0x3, "JTAG_TCK/SW_CLK"), + MA35_MUX(0x5, "I2S0_LRCK"), + MA35_MUX(0x7, "EBI_nWRL"), + MA35_MUX(0xa, "EBI_AD1")), + MA35_PIN(105, PG13, 0xb4, 0x14, + MA35_MUX(0x0, "GPG13"), + MA35_MUX(0x3, "JTAG_TMS/SW_DIO"), + MA35_MUX(0x5, "I2S0_BCLK"), + MA35_MUX(0x7, "EBI_MCLK"), + MA35_MUX(0xa, "EBI_AD2")), + MA35_PIN(106, PG14, 0xb4, 0x18, + MA35_MUX(0x0, "GPG14"), + MA35_MUX(0x3, "JTAG_TDI"), + MA35_MUX(0x5, "I2S0_DI"), + MA35_MUX(0x6, "NAND_nCS1"), + MA35_MUX(0x7, "EBI_ALE"), + MA35_MUX(0xa, "EBI_AD3")), + MA35_PIN(107, PG15, 0xb4, 0x1c, + MA35_MUX(0x0, "GPG15"), + MA35_MUX(0x3, "JTAG_nTRST"), + MA35_MUX(0x5, "I2S0_DO"), + MA35_MUX(0x7, "EBI_nCS0"), + MA35_MUX(0xa, "EBI_AD4")), + MA35_PIN(108, PH0, 0xb8, 0x0, + MA35_MUX(0x0, "GPH0"), + MA35_MUX(0x2, "UART8_nCTS"), + MA35_MUX(0x3, "UART7_RXD"), + MA35_MUX(0x6, "LCM_DATA8")), + MA35_PIN(109, PH1, 0xb8, 0x4, + MA35_MUX(0x0, "GPH1"), + MA35_MUX(0x2, "UART8_nRTS"), + MA35_MUX(0x3, "UART7_TXD"), + MA35_MUX(0x6, "LCM_DATA9")), + MA35_PIN(110, PH2, 0xb8, 0x8, + MA35_MUX(0x0, "GPH2"), + MA35_MUX(0x2, "UART8_RXD"), + MA35_MUX(0x6, "LCM_DATA10")), + MA35_PIN(111, PH3, 0xb8, 0xc, + MA35_MUX(0x0, "GPH3"), + MA35_MUX(0x2, "UART8_TXD"), + MA35_MUX(0x6, "LCM_DATA11")), + MA35_PIN(112, PH4, 0xb8, 0x10, + MA35_MUX(0x0, "GPH4"), + MA35_MUX(0x2, "UART10_nCTS"), + MA35_MUX(0x3, "UART9_RXD"), + MA35_MUX(0x6, "LCM_DATA12")), + MA35_PIN(113, PH5, 0xb8, 0x14, + MA35_MUX(0x0, "GPH5"), + MA35_MUX(0x2, "UART10_nRTS"), + MA35_MUX(0x3, "UART9_TXD"), + MA35_MUX(0x6, "LCM_DATA13")), + MA35_PIN(114, PH6, 0xb8, 0x18, + MA35_MUX(0x0, "GPH6"), + MA35_MUX(0x2, "UART10_RXD"), + MA35_MUX(0x6, "LCM_DATA14")), + MA35_PIN(115, PH7, 0xb8, 0x1c, + MA35_MUX(0x0, "GPH7"), + MA35_MUX(0x2, "UART10_TXD"), + MA35_MUX(0x6, "LCM_DATA15")), + MA35_PIN(116, PH8, 0xbc, 0x0, + MA35_MUX(0x0, "GPH8"), + MA35_MUX(0x6, "TAMPER0")), + MA35_PIN(117, PH9, 0xbc, 0x4, + MA35_MUX(0x0, "GPH9"), + MA35_MUX(0x4, "CLK_32KOUT"), + MA35_MUX(0x6, "TAMPER1")), + MA35_PIN(118, PH12, 0xbc, 0x10, + MA35_MUX(0x0, "GPH12"), + MA35_MUX(0x2, "UART14_nCTS"), + MA35_MUX(0x3, "UART13_RXD"), + MA35_MUX(0x6, "LCM_DATA20")), + MA35_PIN(119, PH13, 0xbc, 0x14, + MA35_MUX(0x0, "GPH13"), + MA35_MUX(0x2, "UART14_nRTS"), + MA35_MUX(0x3, "UART13_TXD"), + MA35_MUX(0x6, "LCM_DATA21")), + MA35_PIN(120, PH14, 0xbc, 0x18, + MA35_MUX(0x0, "GPH14"), + MA35_MUX(0x2, "UART14_RXD"), + MA35_MUX(0x6, "LCM_DATA22")), + MA35_PIN(121, PH15, 0xbc, 0x1c, + MA35_MUX(0x0, "GPH15"), + MA35_MUX(0x2, "UART14_TXD"), + MA35_MUX(0x6, "LCM_DATA23")), + MA35_PIN(122, PI0, 0xc0, 0x0, + MA35_MUX(0x0, "GPI0"), + MA35_MUX(0x1, "EPWM0_CH0"), + MA35_MUX(0x2, "UART12_nCTS"), + MA35_MUX(0x3, "UART11_RXD"), + MA35_MUX(0x4, "I2C2_SDA"), + MA35_MUX(0x5, "SPI3_SS0"), + MA35_MUX(0x7, "SC0_nCD"), + MA35_MUX(0x8, "EBI_ADR0"), + MA35_MUX(0xb, "TM0"), + MA35_MUX(0xc, "ECAP1_IC0")), + MA35_PIN(123, PI1, 0xc0, 0x4, + MA35_MUX(0x0, "GPI1"), + MA35_MUX(0x1, "EPWM0_CH1"), + MA35_MUX(0x2, "UART12_nRTS"), + MA35_MUX(0x3, "UART11_TXD"), + MA35_MUX(0x4, "I2C2_SCL"), + MA35_MUX(0x5, "SPI3_CLK"), + MA35_MUX(0x7, "SC0_CLK"), + MA35_MUX(0x8, "EBI_ADR1"), + MA35_MUX(0xb, "TM0_EXT"), + MA35_MUX(0xc, "ECAP1_IC1")), + MA35_PIN(124, PI2, 0xc0, 0x8, + MA35_MUX(0x0, "GPI2"), + MA35_MUX(0x1, "EPWM0_CH2"), + MA35_MUX(0x2, "UART12_RXD"), + MA35_MUX(0x3, "CAN0_RXD"), + MA35_MUX(0x5, "SPI3_MOSI"), + MA35_MUX(0x7, "SC0_DAT"), + MA35_MUX(0x8, "EBI_ADR2"), + MA35_MUX(0xb, "TM1"), + MA35_MUX(0xc, "ECAP1_IC2")), + MA35_PIN(125, PI3, 0xc0, 0xc, + MA35_MUX(0x0, "GPI3"), + MA35_MUX(0x1, "EPWM0_CH3"), + MA35_MUX(0x2, "UART12_TXD"), + MA35_MUX(0x3, "CAN0_TXD"), + MA35_MUX(0x5, "SPI3_MISO"), + MA35_MUX(0x7, "SC0_RST"), + MA35_MUX(0x8, "EBI_ADR3"), + MA35_MUX(0xb, "TM1_EXT")), + MA35_PIN(126, PI4, 0xc0, 0x10, + MA35_MUX(0x0, "GPI4"), + MA35_MUX(0x1, "EPWM0_CH4"), + MA35_MUX(0x2, "UART14_nCTS"), + MA35_MUX(0x3, "UART13_RXD"), + MA35_MUX(0x4, "I2C3_SDA"), + MA35_MUX(0x5, "SPI2_SS1"), + MA35_MUX(0x6, "I2S1_LRCK"), + MA35_MUX(0x8, "EBI_ADR4"), + MA35_MUX(0xd, "INT0")), + MA35_PIN(127, PI5, 0xc0, 0x14, + MA35_MUX(0x0, "GPI5"), + MA35_MUX(0x1, "EPWM0_CH5"), + MA35_MUX(0x2, "UART14_nRTS"), + MA35_MUX(0x3, "UART13_TXD"), + MA35_MUX(0x4, "I2C3_SCL"), + MA35_MUX(0x6, "I2S1_BCLK"), + MA35_MUX(0x8, "EBI_ADR5"), + MA35_MUX(0xd, "INT1")), + MA35_PIN(128, PI6, 0xc0, 0x18, + MA35_MUX(0x0, "GPI6"), + MA35_MUX(0x1, "EPWM0_BRAKE0"), + MA35_MUX(0x2, "UART14_RXD"), + MA35_MUX(0x3, "CAN1_RXD"), + MA35_MUX(0x6, "I2S1_DI"), + MA35_MUX(0x8, "EBI_ADR6"), + MA35_MUX(0xc, "QEI1_INDEX"), + MA35_MUX(0xd, "INT2")), + MA35_PIN(129, PI7, 0xc0, 0x1c, + MA35_MUX(0x0, "GPI7"), + MA35_MUX(0x1, "EPWM0_BRAKE1"), + MA35_MUX(0x2, "UART14_TXD"), + MA35_MUX(0x3, "CAN1_TXD"), + MA35_MUX(0x6, "I2S1_DO"), + MA35_MUX(0x8, "EBI_ADR7"), + MA35_MUX(0xc, "ECAP0_IC0"), + MA35_MUX(0xd, "INT3")), + MA35_PIN(130, PI8, 0xc4, 0x0, + MA35_MUX(0x0, "GPI8"), + MA35_MUX(0x2, "UART4_nCTS"), + MA35_MUX(0x3, "UART3_RXD"), + MA35_MUX(0x6, "LCM_DATA0"), + MA35_MUX(0xc, "EBI_AD11")), + MA35_PIN(131, PI9, 0xc4, 0x4, + MA35_MUX(0x0, "GPI9"), + MA35_MUX(0x2, "UART4_nRTS"), + MA35_MUX(0x3, "UART3_TXD"), + MA35_MUX(0x6, "LCM_DATA1"), + MA35_MUX(0xc, "EBI_AD12")), + MA35_PIN(132, PI10, 0xc4, 0x8, + MA35_MUX(0x0, "GPI10"), + MA35_MUX(0x2, "UART4_RXD"), + MA35_MUX(0x6, "LCM_DATA2"), + MA35_MUX(0xc, "EBI_AD13")), + MA35_PIN(133, PI11, 0xC4, 0xc, + MA35_MUX(0x0, "GPI11"), + MA35_MUX(0x2, "UART4_TXD"), + MA35_MUX(0x6, "LCM_DATA3"), + MA35_MUX(0xc, "EBI_AD14")), + MA35_PIN(134, PI12, 0xc4, 0x10, + MA35_MUX(0x0, "GPI12"), + MA35_MUX(0x2, "UART6_nCTS"), + MA35_MUX(0x3, "UART5_RXD"), + MA35_MUX(0x6, "LCM_DATA4")), + MA35_PIN(135, PI13, 0xc4, 0x14, + MA35_MUX(0x0, "GPI13"), + MA35_MUX(0x2, "UART6_nRTS"), + MA35_MUX(0x3, "UART5_TXD"), + MA35_MUX(0x6, "LCM_DATA5")), + MA35_PIN(136, PI14, 0xc4, 0x18, + MA35_MUX(0x0, "GPI14"), + MA35_MUX(0x2, "UART6_RXD"), + MA35_MUX(0x6, "LCM_DATA6")), + MA35_PIN(137, PI15, 0xc4, 0x1c, + MA35_MUX(0x0, "GPI15"), + MA35_MUX(0x2, "UART6_TXD"), + MA35_MUX(0x6, "LCM_DATA7")), + MA35_PIN(138, PJ0, 0xc8, 0x0, + MA35_MUX(0x0, "GPJ0"), + MA35_MUX(0x1, "EPWM1_BRAKE0"), + MA35_MUX(0x2, "UART8_nCTS"), + MA35_MUX(0x3, "UART7_RXD"), + MA35_MUX(0x4, "I2C2_SDA"), + MA35_MUX(0x5, "SPI2_SS0"), + MA35_MUX(0x6, "eMMC1_DAT4"), + MA35_MUX(0x7, "I2S0_LRCK"), + MA35_MUX(0x8, "SC0_CLK"), + MA35_MUX(0x9, "EBI_AD11"), + MA35_MUX(0xa, "EBI_ADR16"), + MA35_MUX(0xb, "EBI_nCS0"), + MA35_MUX(0xc, "EBI_AD7")), + MA35_PIN(139, PJ1, 0xc8, 0x4, + MA35_MUX(0x0, "GPJ1"), + MA35_MUX(0x1, "EPWM1_BRAKE1"), + MA35_MUX(0x2, "UART8_nRTS"), + MA35_MUX(0x3, "UART7_TXD"), + MA35_MUX(0x4, "I2C2_SCL"), + MA35_MUX(0x5, "SPI2_CLK"), + MA35_MUX(0x6, "eMMC1_DAT5"), + MA35_MUX(0x7, "I2S0_BCLK"), + MA35_MUX(0x8, "SC0_DAT"), + MA35_MUX(0x9, "EBI_AD12"), + MA35_MUX(0xa, "EBI_ADR17"), + MA35_MUX(0xb, "EBI_nCS1"), + MA35_MUX(0xc, "EBI_AD8")), + MA35_PIN(140, PJ2, 0xc8, 0x8, + MA35_MUX(0x0, "GPJ2"), + MA35_MUX(0x1, "EPWM1_CH4"), + MA35_MUX(0x2, "UART8_RXD"), + MA35_MUX(0x3, "CAN1_RXD"), + MA35_MUX(0x5, "SPI2_MOSI"), + MA35_MUX(0x6, "eMMC1_DAT6"), + MA35_MUX(0x7, "I2S0_DI"), + MA35_MUX(0x8, "SC0_RST"), + MA35_MUX(0x9, "EBI_AD13"), + MA35_MUX(0xa, "EBI_ADR18"), + MA35_MUX(0xb, "EBI_nWRH"), + MA35_MUX(0xc, "EBI_AD9")), + MA35_PIN(141, PJ3, 0xc8, 0xc, + MA35_MUX(0x0, "GPJ3"), + MA35_MUX(0x1, "EPWM1_CH5"), + MA35_MUX(0x2, "UART8_TXD"), + MA35_MUX(0x3, "CAN1_TXD"), + MA35_MUX(0x5, "SPI2_MISO"), + MA35_MUX(0x6, "eMMC1_DAT7"), + MA35_MUX(0x7, "I2S0_DO"), + MA35_MUX(0x8, "SC0_PWR"), + MA35_MUX(0x9, "EBI_AD14"), + MA35_MUX(0xa, "EBI_ADR19"), + MA35_MUX(0xb, "EBI_nWRL"), + MA35_MUX(0xc, "EBI_AD10")), + MA35_PIN(142, PJ4, 0xc8, 0x10, + MA35_MUX(0x0, "GPJ4"), + MA35_MUX(0x4, "I2C3_SDA"), + MA35_MUX(0x6, "SD1_WP")), + MA35_PIN(143, PJ5, 0xc8, 0x14, + MA35_MUX(0x0, "GPJ5"), + MA35_MUX(0x4, "I2C3_SCL"), + MA35_MUX(0x6, "SD1_nCD")), + MA35_PIN(144, PJ6, 0xc8, 0x18, + MA35_MUX(0x0, "GPJ6"), + MA35_MUX(0x3, "CAN3_RXD"), + MA35_MUX(0x6, "SD1_CMD/eMMC1_CMD")), + MA35_PIN(145, PJ7, 0xc8, 0x1c, + MA35_MUX(0x0, "GPJ7"), + MA35_MUX(0x3, "CAN3_TXD"), + MA35_MUX(0x6, "SD1_CLK/eMMC1_CLK")), + MA35_PIN(146, PJ8, 0xcc, 0x0, + MA35_MUX(0x0, "GPJ8"), + MA35_MUX(0x4, "I2C4_SDA"), + MA35_MUX(0x6, "SD1_DAT0/eMMC1_DAT0")), + MA35_PIN(147, PJ9, 0xcc, 0x4, + MA35_MUX(0x0, "GPJ9"), + MA35_MUX(0x4, "I2C4_SCL"), + MA35_MUX(0x6, "SD1_DAT1/eMMC1_DAT1")), + MA35_PIN(148, PJ10, 0xcc, 0x8, + MA35_MUX(0x0, "GPJ10"), + MA35_MUX(0x3, "CAN0_RXD"), + MA35_MUX(0x6, "SD1_DAT2/eMMC1_DAT2")), + MA35_PIN(149, PJ11, 0xcc, 0xc, + MA35_MUX(0x0, "GPJ11"), + MA35_MUX(0x3, "CAN0_TXD"), + MA35_MUX(0x6, "SD1_DAT3/eMMC1_DAT3")), + MA35_PIN(150, PJ12, 0xcc, 0x10, + MA35_MUX(0x0, "GPJ12"), + MA35_MUX(0x1, "EPWM1_CH2"), + MA35_MUX(0x2, "UART2_nCTS"), + MA35_MUX(0x3, "UART1_RXD"), + MA35_MUX(0x4, "I2C5_SDA"), + MA35_MUX(0x5, "SPI3_SS0"), + MA35_MUX(0x7, "SC1_CLK"), + MA35_MUX(0x8, "EBI_ADR12"), + MA35_MUX(0xb, "TM2"), + MA35_MUX(0xc, "QEI0_INDEX")), + MA35_PIN(151, PJ13, 0xcc, 0x14, + MA35_MUX(0x0, "GPJ13"), + MA35_MUX(0x1, "EPWM1_CH3"), + MA35_MUX(0x2, "UART2_nRTS"), + MA35_MUX(0x3, "UART1_TXD"), + MA35_MUX(0x4, "I2C5_SCL"), + MA35_MUX(0x5, "SPI3_MOSI"), + MA35_MUX(0x7, "SC1_DAT"), + MA35_MUX(0x8, "EBI_ADR13"), + MA35_MUX(0xb, "TM2_EXT")), + MA35_PIN(152, PJ14, 0xcc, 0x18, + MA35_MUX(0x0, "GPJ14"), + MA35_MUX(0x1, "EPWM1_CH4"), + MA35_MUX(0x2, "UART2_RXD"), + MA35_MUX(0x3, "CAN3_RXD"), + MA35_MUX(0x5, "SPI3_MISO"), + MA35_MUX(0x7, "SC1_RST"), + MA35_MUX(0x8, "EBI_ADR14"), + MA35_MUX(0xb, "TM3")), + MA35_PIN(153, PJ15, 0xcc, 0x1c, + MA35_MUX(0x0, "GPJ15"), + MA35_MUX(0x1, "EPWM1_CH5"), + MA35_MUX(0x2, "UART2_TXD"), + MA35_MUX(0x3, "CAN3_TXD"), + MA35_MUX(0x5, "SPI3_CLK"), + MA35_MUX(0x6, "EADC0_ST"), + MA35_MUX(0x7, "SC1_PWR"), + MA35_MUX(0x8, "EBI_ADR15"), + MA35_MUX(0xb, "TM3_EXT"), + MA35_MUX(0xd, "INT1")), + MA35_PIN(154, PK0, 0xd0, 0x0, + MA35_MUX(0x0, "GPK0"), + MA35_MUX(0x1, "EPWM0_SYNC_IN"), + MA35_MUX(0x2, "UART16_nCTS"), + MA35_MUX(0x3, "UART15_RXD"), + MA35_MUX(0x4, "I2C4_SDA"), + MA35_MUX(0x6, "I2S1_MCLK"), + MA35_MUX(0x8, "EBI_ADR8"), + MA35_MUX(0xb, "TM7"), + MA35_MUX(0xc, "ECAP0_IC1")), + MA35_PIN(155, PK1, 0xd0, 0x4, + MA35_MUX(0x0, "GPK1"), + MA35_MUX(0x1, "EPWM0_SYNC_OUT"), + MA35_MUX(0x2, "UART16_nRTS"), + MA35_MUX(0x3, "UART15_TXD"), + MA35_MUX(0x4, "I2C4_SCL"), + MA35_MUX(0x6, "EADC0_ST"), + MA35_MUX(0x8, "EBI_ADR9"), + MA35_MUX(0xb, "TM7_EXT"), + MA35_MUX(0xc, "ECAP0_IC2")), + MA35_PIN(156, PK2, 0xd0, 0x8, + MA35_MUX(0x0, "GPK2"), + MA35_MUX(0x1, "EPWM1_CH0"), + MA35_MUX(0x2, "UART16_RXD"), + MA35_MUX(0x3, "CAN2_RXD"), + MA35_MUX(0x5, "SPI3_I2SMCLK"), + MA35_MUX(0x7, "SC0_PWR"), + MA35_MUX(0x8, "EBI_ADR10"), + MA35_MUX(0xc, "QEI0_A")), + MA35_PIN(157, PK3, 0xd0, 0xc, + MA35_MUX(0x0, "GPK3"), + MA35_MUX(0x1, "EPWM1_CH1"), + MA35_MUX(0x2, "UART16_TXD"), + MA35_MUX(0x3, "CAN2_TXD"), + MA35_MUX(0x5, "SPI3_SS1"), + MA35_MUX(0x7, "SC1_nCD"), + MA35_MUX(0x8, "EBI_ADR11"), + MA35_MUX(0xc, "QEI0_B")), + MA35_PIN(158, PK4, 0xd0, 0x10, + MA35_MUX(0x0, "GPK4"), + MA35_MUX(0x2, "UART12_nCTS"), + MA35_MUX(0x3, "UART13_RXD"), + MA35_MUX(0x5, "SPI2_MISO"), + MA35_MUX(0x6, "LCM_DEN"), + MA35_MUX(0xc, "EBI_AD10"), + MA35_MUX(0xd, "EBI_nWRL")), + MA35_PIN(159, PK5, 0xd0, 0x14, + MA35_MUX(0x0, "GPK5"), + MA35_MUX(0x1, "EPWM1_CH1"), + MA35_MUX(0x2, "UART12_nRTS"), + MA35_MUX(0x3, "UART13_TXD"), + MA35_MUX(0x4, "I2C4_SCL"), + MA35_MUX(0x5, "SPI2_CLK"), + MA35_MUX(0x7, "I2S1_DI"), + MA35_MUX(0x8, "SC0_DAT"), + MA35_MUX(0x9, "EADC0_ST"), + MA35_MUX(0xb, "TM8_EXT"), + MA35_MUX(0xd, "INT1")), + MA35_PIN(160, PK6, 0xd0, 0x18, + MA35_MUX(0x0, "GPK6"), + MA35_MUX(0x1, "EPWM1_CH2"), + MA35_MUX(0x2, "UART12_RXD"), + MA35_MUX(0x3, "CAN0_RXD"), + MA35_MUX(0x5, "SPI2_MOSI"), + MA35_MUX(0x7, "I2S1_BCLK"), + MA35_MUX(0x8, "SC0_RST"), + MA35_MUX(0xb, "TM6"), + MA35_MUX(0xd, "INT2")), + MA35_PIN(161, PK7, 0xd0, 0x1c, + MA35_MUX(0x0, "GPK7"), + MA35_MUX(0x1, "EPWM1_CH3"), + MA35_MUX(0x2, "UART12_TXD"), + MA35_MUX(0x3, "CAN0_TXD"), + MA35_MUX(0x5, "SPI2_MISO"), + MA35_MUX(0x7, "I2S1_LRCK"), + MA35_MUX(0x8, "SC0_PWR"), + MA35_MUX(0x9, "CLKO"), + MA35_MUX(0xb, "TM6_EXT"), + MA35_MUX(0xd, "INT3")), + MA35_PIN(162, PK8, 0xd4, 0x0, + MA35_MUX(0x0, "GPK8"), + MA35_MUX(0x1, "EPWM1_CH0"), + MA35_MUX(0x4, "I2C3_SDA"), + MA35_MUX(0x5, "SPI3_CLK"), + MA35_MUX(0x7, "EADC0_ST"), + MA35_MUX(0x8, "EBI_AD15"), + MA35_MUX(0x9, "EBI_MCLK"), + MA35_MUX(0xa, "EBI_ADR15"), + MA35_MUX(0xb, "TM8"), + MA35_MUX(0xc, "QEI1_INDEX")), + MA35_PIN(163, PK9, 0xd4, 0x4, + MA35_MUX(0x0, "GPK9"), + MA35_MUX(0x4, "I2C3_SCL"), + MA35_MUX(0x6, "CCAP0_SCLK"), + MA35_MUX(0x8, "EBI_AD0"), + MA35_MUX(0xa, "EBI_ADR0")), + MA35_PIN(164, PK10, 0xd4, 0x8, + MA35_MUX(0x0, "GPK10"), + MA35_MUX(0x3, "CAN1_RXD"), + MA35_MUX(0x6, "CCAP0_PIXCLK"), + MA35_MUX(0x8, "EBI_AD1"), + MA35_MUX(0xa, "EBI_ADR1")), + MA35_PIN(165, PK11, 0xd4, 0xc, + MA35_MUX(0x0, "GPK11"), + MA35_MUX(0x3, "CAN1_TXD"), + MA35_MUX(0x6, "CCAP0_HSYNC"), + MA35_MUX(0x8, "EBI_AD2"), + MA35_MUX(0xa, "EBI_ADR2")), + MA35_PIN(166, PK12, 0xd4, 0x10, + MA35_MUX(0x0, "GPK12"), + MA35_MUX(0x1, "EPWM2_CH0"), + MA35_MUX(0x2, "UART1_nCTS"), + MA35_MUX(0x3, "UART13_RXD"), + MA35_MUX(0x4, "I2C4_SDA"), + MA35_MUX(0x5, "I2S0_LRCK"), + MA35_MUX(0x6, "SPI1_SS0"), + MA35_MUX(0x8, "SC0_CLK"), + MA35_MUX(0xb, "TM10"), + MA35_MUX(0xd, "INT2")), + MA35_PIN(167, PK13, 0xd4, 0x14, + MA35_MUX(0x0, "GPK13"), + MA35_MUX(0x1, "EPWM2_CH1"), + MA35_MUX(0x2, "UART1_nRTS"), + MA35_MUX(0x3, "UART13_TXD"), + MA35_MUX(0x4, "I2C4_SCL"), + MA35_MUX(0x5, "I2S0_BCLK"), + MA35_MUX(0x6, "SPI1_CLK"), + MA35_MUX(0x8, "SC0_DAT"), + MA35_MUX(0xb, "TM10_EXT")), + MA35_PIN(168, PK14, 0xd4, 0x18, + MA35_MUX(0x0, "GPK14"), + MA35_MUX(0x1, "EPWM2_CH2"), + MA35_MUX(0x2, "UART1_RXD"), + MA35_MUX(0x3, "CAN3_RXD"), + MA35_MUX(0x5, "I2S0_DI"), + MA35_MUX(0x6, "SPI1_MOSI"), + MA35_MUX(0x8, "SC0_RST"), + MA35_MUX(0xa, "I2C5_SDA"), + MA35_MUX(0xb, "TM11"), + MA35_MUX(0xd, "INT3")), + MA35_PIN(169, PK15, 0xd4, 0x1c, + MA35_MUX(0x0, "GPK15"), + MA35_MUX(0x1, "EPWM2_CH3"), + MA35_MUX(0x2, "UART1_TXD"), + MA35_MUX(0x3, "CAN3_TXD"), + MA35_MUX(0x5, "I2S0_DO"), + MA35_MUX(0x6, "SPI1_MISO"), + MA35_MUX(0x8, "SC0_PWR"), + MA35_MUX(0xa, "I2C5_SCL"), + MA35_MUX(0xb, "TM11_EXT")), + MA35_PIN(170, PL0, 0xd8, 0x0, + MA35_MUX(0x0, "GPL0"), + MA35_MUX(0x1, "EPWM1_CH0"), + MA35_MUX(0x2, "UART11_nCTS"), + MA35_MUX(0x3, "UART10_RXD"), + MA35_MUX(0x4, "I2C3_SDA"), + MA35_MUX(0x5, "SPI2_MOSI"), + MA35_MUX(0x6, "QSPI1_MOSI1"), + MA35_MUX(0x7, "I2S0_LRCK"), + MA35_MUX(0x8, "EBI_AD11"), + MA35_MUX(0x9, "SC1_CLK"), + MA35_MUX(0xb, "TM5"), + MA35_MUX(0xc, "QEI1_A")), + MA35_PIN(171, PL1, 0xd8, 0x4, + MA35_MUX(0x0, "GPL1"), + MA35_MUX(0x1, "EPWM1_CH1"), + MA35_MUX(0x2, "UART11_nRTS"), + MA35_MUX(0x3, "UART10_TXD"), + MA35_MUX(0x4, "I2C3_SCL"), + MA35_MUX(0x5, "SPI2_MISO"), + MA35_MUX(0x6, "QSPI1_MISO1"), + MA35_MUX(0x7, "I2S0_BCLK"), + MA35_MUX(0x8, "EBI_AD12"), + MA35_MUX(0x9, "SC1_DAT"), + MA35_MUX(0xb, "TM5_EXT"), + MA35_MUX(0xc, "QEI1_B")), + MA35_PIN(172, PL2, 0xd8, 0x8, + MA35_MUX(0x0, "GPL2"), + MA35_MUX(0x1, "EPWM1_CH2"), + MA35_MUX(0x2, "UART11_RXD"), + MA35_MUX(0x3, "CAN3_RXD"), + MA35_MUX(0x5, "SPI2_SS0"), + MA35_MUX(0x6, "QSPI1_SS1"), + MA35_MUX(0x7, "I2S0_DI"), + MA35_MUX(0x8, "EBI_AD13"), + MA35_MUX(0x9, "SC1_RST"), + MA35_MUX(0xb, "TM7"), + MA35_MUX(0xc, "QEI1_INDEX")), + MA35_PIN(173, PL3, 0xd8, 0xc, + MA35_MUX(0x0, "GPL3"), + MA35_MUX(0x1, "EPWM1_CH3"), + MA35_MUX(0x2, "UART11_TXD"), + MA35_MUX(0x3, "CAN3_TXD"), + MA35_MUX(0x5, "SPI2_CLK"), + MA35_MUX(0x6, "QSPI1_CLK"), + MA35_MUX(0x7, "I2S0_DO"), + MA35_MUX(0x8, "EBI_AD14"), + MA35_MUX(0x9, "SC1_PWR"), + MA35_MUX(0xb, "TM7_EXT"), + MA35_MUX(0xc, "ECAP0_IC0")), + MA35_PIN(174, PL4, 0xd8, 0x10, + MA35_MUX(0x0, "GPL4"), + MA35_MUX(0x1, "EPWM1_CH4"), + MA35_MUX(0x2, "UART2_nCTS"), + MA35_MUX(0x3, "UART1_RXD"), + MA35_MUX(0x4, "I2C4_SDA"), + MA35_MUX(0x5, "SPI3_MOSI"), + MA35_MUX(0x6, "QSPI1_MOSI0"), + MA35_MUX(0x7, "I2S0_MCLK"), + MA35_MUX(0x8, "EBI_nRD"), + MA35_MUX(0x9, "SC1_nCD"), + MA35_MUX(0xb, "TM9"), + MA35_MUX(0xc, "ECAP0_IC1")), + MA35_PIN(175, PL5, 0xd8, 0x14, + MA35_MUX(0x0, "GPL5"), + MA35_MUX(0x1, "EPWM1_CH5"), + MA35_MUX(0x2, "UART2_nRTS"), + MA35_MUX(0x3, "UART1_TXD"), + MA35_MUX(0x4, "I2C4_SCL"), + MA35_MUX(0x5, "SPI3_MISO"), + MA35_MUX(0x6, "QSPI1_MISO0"), + MA35_MUX(0x7, "I2S1_MCLK"), + MA35_MUX(0x8, "EBI_nWR"), + MA35_MUX(0x9, "SC0_nCD"), + MA35_MUX(0xb, "TM9_EXT"), + MA35_MUX(0xc, "ECAP0_IC2")), + MA35_PIN(176, PL6, 0xd8, 0x18, + MA35_MUX(0x0, "GPL6"), + MA35_MUX(0x1, "EPWM0_CH0"), + MA35_MUX(0x2, "UART2_RXD"), + MA35_MUX(0x3, "CAN0_RXD"), + MA35_MUX(0x6, "QSPI1_MOSI1"), + MA35_MUX(0x7, "TRACE_CLK"), + MA35_MUX(0x8, "EBI_AD5"), + MA35_MUX(0xb, "TM3"), + MA35_MUX(0xc, "ECAP1_IC0"), + MA35_MUX(0xd, "INT0")), + MA35_PIN(177, PL7, 0xd8, 0x1c, + MA35_MUX(0x0, "GPL7"), + MA35_MUX(0x1, "EPWM0_CH1"), + MA35_MUX(0x2, "UART2_TXD"), + MA35_MUX(0x3, "CAN0_TXD"), + MA35_MUX(0x6, "QSPI1_MISO1"), + MA35_MUX(0x8, "EBI_AD6"), + MA35_MUX(0xb, "TM3_EXT"), + MA35_MUX(0xc, "ECAP1_IC1"), + MA35_MUX(0xd, "INT1")), + MA35_PIN(178, PL8, 0xdc, 0x0, + MA35_MUX(0x0, "GPL8"), + MA35_MUX(0x1, "EPWM0_CH2"), + MA35_MUX(0x2, "UART14_nCTS"), + MA35_MUX(0x3, "UART13_RXD"), + MA35_MUX(0x4, "I2C5_SDA"), + MA35_MUX(0x5, "SPI3_SS0"), + MA35_MUX(0x6, "EPWM0_CH4"), + MA35_MUX(0x7, "I2S1_LRCK"), + MA35_MUX(0x8, "EBI_AD7"), + MA35_MUX(0x9, "SC0_CLK"), + MA35_MUX(0xb, "TM4"), + MA35_MUX(0xc, "ECAP1_IC2"), + MA35_MUX(0xd, "INT2")), + MA35_PIN(179, PL9, 0xdc, 0x4, + MA35_MUX(0x0, "GPL9"), + MA35_MUX(0x1, "EPWM0_CH3"), + MA35_MUX(0x2, "UART14_nRTS"), + MA35_MUX(0x3, "UART13_TXD"), + MA35_MUX(0x4, "I2C5_SCL"), + MA35_MUX(0x5, "SPI3_CLK"), + MA35_MUX(0x6, "EPWM1_CH4"), + MA35_MUX(0x7, "I2S1_BCLK"), + MA35_MUX(0x8, "EBI_AD8"), + MA35_MUX(0x9, "SC0_DAT"), + MA35_MUX(0xb, "TM4_EXT"), + MA35_MUX(0xc, "QEI0_A"), + MA35_MUX(0xd, "INT3")), + MA35_PIN(180, PL10, 0xdc, 0x8, + MA35_MUX(0x0, "GPL10"), + MA35_MUX(0x1, "EPWM0_CH4"), + MA35_MUX(0x2, "UART14_RXD"), + MA35_MUX(0x3, "CAN3_RXD"), + MA35_MUX(0x5, "SPI3_MOSI"), + MA35_MUX(0x6, "EPWM0_CH5"), + MA35_MUX(0x7, "I2S1_DI"), + MA35_MUX(0x8, "EBI_AD9"), + MA35_MUX(0x9, "SC0_RST"), + MA35_MUX(0xb, "EBI_nWRH"), + MA35_MUX(0xc, "QEI0_B")), + MA35_PIN(181, PL11, 0xdc, 0xc, + MA35_MUX(0x0, "GPL11"), + MA35_MUX(0x1, "EPWM0_CH5"), + MA35_MUX(0x2, "UART14_TXD"), + MA35_MUX(0x3, "CAN3_TXD"), + MA35_MUX(0x5, "SPI3_MISO"), + MA35_MUX(0x6, "EPWM1_CH5"), + MA35_MUX(0x7, "I2S1_DO"), + MA35_MUX(0x8, "EBI_AD10"), + MA35_MUX(0x9, "SC0_PWR"), + MA35_MUX(0xb, "EBI_nWRL"), + MA35_MUX(0xc, "QEI0_INDEX")), + MA35_PIN(182, PL12, 0xdc, 0x10, + MA35_MUX(0x0, "GPL12"), + MA35_MUX(0x1, "EPWM0_SYNC_IN"), + MA35_MUX(0x2, "UART7_nCTS"), + MA35_MUX(0x3, "ECAP1_IC0"), + MA35_MUX(0x4, "UART14_RXD"), + MA35_MUX(0x5, "SPI0_SS0"), + MA35_MUX(0x6, "I2S1_LRCK"), + MA35_MUX(0x7, "SC1_CLK"), + MA35_MUX(0x8, "EBI_AD0"), + MA35_MUX(0x9, "HSUSBH_PWREN"), + MA35_MUX(0xa, "I2C2_SDA"), + MA35_MUX(0xb, "TM0"), + MA35_MUX(0xc, "EPWM0_CH2"), + MA35_MUX(0xd, "EBI_AD11"), + MA35_MUX(0xe, "RGMII0_PPS"), + MA35_MUX(0xf, "RMII0_PPS")), + MA35_PIN(183, PL13, 0xdc, 0x14, + MA35_MUX(0x0, "GPL13"), + MA35_MUX(0x1, "EPWM0_SYNC_OUT"), + MA35_MUX(0x2, "UART7_nRTS"), + MA35_MUX(0x3, "ECAP1_IC1"), + MA35_MUX(0x4, "UART14_TXD"), + MA35_MUX(0x5, "SPI0_CLK"), + MA35_MUX(0x6, "I2S1_BCLK"), + MA35_MUX(0x7, "SC1_DAT"), + MA35_MUX(0x8, "EBI_AD1"), + MA35_MUX(0x9, "HSUSBH_OVC"), + MA35_MUX(0xa, "I2C2_SCL"), + MA35_MUX(0xb, "TM0_EXT"), + MA35_MUX(0xc, "EPWM0_CH3"), + MA35_MUX(0xd, "EBI_AD12"), + MA35_MUX(0xe, "RGMII1_PPS"), + MA35_MUX(0xf, "RMII1_PPS")), + MA35_PIN(184, PL14, 0xdc, 0x18, + MA35_MUX(0x0, "GPL14"), + MA35_MUX(0x1, "EPWM0_CH2"), + MA35_MUX(0x2, "UART7_RXD"), + MA35_MUX(0x4, "CAN1_RXD"), + MA35_MUX(0x5, "SPI0_MOSI"), + MA35_MUX(0x6, "I2S1_DI"), + MA35_MUX(0x7, "SC1_RST"), + MA35_MUX(0x8, "EBI_AD2"), + MA35_MUX(0xb, "TM2"), + MA35_MUX(0xc, "INT0"), + MA35_MUX(0xd, "EBI_AD13")), + MA35_PIN(185, PL15, 0xdc, 0x1c, + MA35_MUX(0x0, "GPL15"), + MA35_MUX(0x1, "EPWM0_CH1"), + MA35_MUX(0x2, "UART7_TXD"), + MA35_MUX(0x3, "TRACE_CLK"), + MA35_MUX(0x4, "CAN1_TXD"), + MA35_MUX(0x5, "SPI0_MISO"), + MA35_MUX(0x6, "I2S1_DO"), + MA35_MUX(0x7, "SC1_PWR"), + MA35_MUX(0x8, "EBI_AD3"), + MA35_MUX(0xb, "TM2_EXT"), + MA35_MUX(0xc, "INT2"), + MA35_MUX(0xd, "EBI_AD14")), + MA35_PIN(186, PM0, 0xe0, 0x0, + MA35_MUX(0x0, "GPM0"), + MA35_MUX(0x4, "I2C4_SDA"), + MA35_MUX(0x6, "CCAP0_VSYNC"), + MA35_MUX(0x8, "EBI_AD3"), + MA35_MUX(0xa, "EBI_ADR3")), + MA35_PIN(187, PM1, 0xe0, 0x4, + MA35_MUX(0x0, "GPM1"), + MA35_MUX(0x4, "I2C4_SCL"), + MA35_MUX(0x5, "SPI3_I2SMCLK"), + MA35_MUX(0x6, "CCAP0_SFIELD"), + MA35_MUX(0x8, "EBI_AD4"), + MA35_MUX(0xa, "EBI_ADR4")), + MA35_PIN(188, PM2, 0xe0, 0x8, + MA35_MUX(0x0, "GPM2"), + MA35_MUX(0x3, "CAN3_RXD"), + MA35_MUX(0x6, "CCAP0_DATA0"), + MA35_MUX(0x8, "EBI_AD5"), + MA35_MUX(0xa, "EBI_ADR5")), + MA35_PIN(189, PM3, 0xe0, 0xc, + MA35_MUX(0x0, "GPM3"), + MA35_MUX(0x3, "CAN3_TXD"), + MA35_MUX(0x6, "CCAP0_DATA1"), + MA35_MUX(0x8, "EBI_AD6"), + MA35_MUX(0xa, "EBI_ADR6")), + MA35_PIN(190, PM4, 0xe0, 0x10, + MA35_MUX(0x0, "GPM4"), + MA35_MUX(0x4, "I2C5_SDA"), + MA35_MUX(0x6, "CCAP0_DATA2"), + MA35_MUX(0x8, "EBI_AD7"), + MA35_MUX(0xa, "EBI_ADR7")), + MA35_PIN(191, PM5, 0xe0, 0x14, + MA35_MUX(0x0, "GPM5"), + MA35_MUX(0x4, "I2C5_SCL"), + MA35_MUX(0x6, "CCAP0_DATA3"), + MA35_MUX(0x8, "EBI_AD8"), + MA35_MUX(0xa, "EBI_ADR8")), + MA35_PIN(192, PM6, 0xe0, 0x18, + MA35_MUX(0x0, "GPM6"), + MA35_MUX(0x3, "CAN0_RXD"), + MA35_MUX(0x6, "CCAP0_DATA4"), + MA35_MUX(0x8, "EBI_AD9"), + MA35_MUX(0xa, "EBI_ADR9")), + MA35_PIN(193, PM7, 0xe0, 0x1c, + MA35_MUX(0x0, "GPM7"), + MA35_MUX(0x3, "CAN0_TXD"), + MA35_MUX(0x6, "CCAP0_DATA5"), + MA35_MUX(0x8, "EBI_AD10"), + MA35_MUX(0xa, "EBI_ADR10")), + MA35_PIN(194, PM8, 0xe4, 0x0, + MA35_MUX(0x0, "GPM8"), + MA35_MUX(0x4, "I2C0_SDA"), + MA35_MUX(0x6, "CCAP0_DATA6"), + MA35_MUX(0x8, "EBI_AD11"), + MA35_MUX(0xa, "EBI_ADR11")), + MA35_PIN(195, PM9, 0xe4, 0x4, + MA35_MUX(0x0, "GPM9"), + MA35_MUX(0x4, "I2C0_SCL"), + MA35_MUX(0x6, "CCAP0_DATA7"), + MA35_MUX(0x8, "EBI_AD12"), + MA35_MUX(0xa, "EBI_ADR12")), + MA35_PIN(196, PM10, 0xe4, 0x8, + MA35_MUX(0x0, "GPM10"), + MA35_MUX(0x1, "EPWM1_CH2"), + MA35_MUX(0x3, "CAN2_RXD"), + MA35_MUX(0x5, "SPI3_SS0"), + MA35_MUX(0x6, "CCAP0_DATA8"), + MA35_MUX(0x7, "SPI2_I2SMCLK"), + MA35_MUX(0x8, "EBI_AD13"), + MA35_MUX(0xa, "EBI_ADR13")), + MA35_PIN(197, PM11, 0xe4, 0xc, + MA35_MUX(0x0, "GPM11"), + MA35_MUX(0x1, "EPWM1_CH3"), + MA35_MUX(0x3, "CAN2_TXD"), + MA35_MUX(0x5, "SPI3_SS1"), + MA35_MUX(0x6, "CCAP0_DATA9"), + MA35_MUX(0x7, "SPI2_SS1"), + MA35_MUX(0x8, "EBI_AD14"), + MA35_MUX(0xa, "EBI_ADR14")), + MA35_PIN(198, PM12, 0xe4, 0x10, + MA35_MUX(0x0, "GPM12"), + MA35_MUX(0x1, "EPWM1_CH4"), + MA35_MUX(0x2, "UART10_nCTS"), + MA35_MUX(0x3, "TRACE_DATA0"), + MA35_MUX(0x4, "UART11_RXD"), + MA35_MUX(0x5, "I2C2_SDA"), + MA35_MUX(0x7, "SC1_nCD"), + MA35_MUX(0x8, "EBI_AD8"), + MA35_MUX(0x9, "I2S1_MCLK"), + MA35_MUX(0xb, "TM8")), + MA35_PIN(199, PM13, 0xe4, 0x14, + MA35_MUX(0x0, "GPM13"), + MA35_MUX(0x1, "EPWM1_CH5"), + MA35_MUX(0x2, "UART10_nRTS"), + MA35_MUX(0x3, "TRACE_DATA1"), + MA35_MUX(0x4, "UART11_TXD"), + MA35_MUX(0x5, "I2C2_SCL"), + MA35_MUX(0x8, "EBI_AD9"), + MA35_MUX(0x9, "ECAP1_IC0"), + MA35_MUX(0xb, "TM8_EXT")), + MA35_PIN(200, PM14, 0xe4, 0x18, + MA35_MUX(0x0, "GPM14"), + MA35_MUX(0x1, "EPWM1_BRAKE0"), + MA35_MUX(0x2, "UART10_RXD"), + MA35_MUX(0x3, "TRACE_DATA2"), + MA35_MUX(0x4, "CAN2_RXD"), + MA35_MUX(0x6, "I2C3_SDA"), + MA35_MUX(0x8, "EBI_AD10"), + MA35_MUX(0x9, "ECAP1_IC1"), + MA35_MUX(0xb, "TM10"), + MA35_MUX(0xd, "INT1")), + MA35_PIN(201, PM15, 0xe4, 0x1c, + MA35_MUX(0x0, "GPM15"), + MA35_MUX(0x1, "EPWM1_BRAKE1"), + MA35_MUX(0x2, "UART10_TXD"), + MA35_MUX(0x3, "TRACE_DATA3"), + MA35_MUX(0x4, "CAN2_TXD"), + MA35_MUX(0x6, "I2C3_SCL"), + MA35_MUX(0x8, "EBI_AD11"), + MA35_MUX(0x9, "ECAP1_IC2"), + MA35_MUX(0xb, "TM10_EXT"), + MA35_MUX(0xd, "INT2")), + MA35_PIN(202, PN0, 0xe8, 0x0, + MA35_MUX(0x0, "GPN0"), + MA35_MUX(0x4, "I2C2_SDA"), + MA35_MUX(0x6, "CCAP1_DATA0")), + MA35_PIN(203, PN1, 0xe8, 0x4, + MA35_MUX(0x0, "GPN1"), + MA35_MUX(0x4, "I2C2_SCL"), + MA35_MUX(0x6, "CCAP1_DATA1")), + MA35_PIN(204, PN2, 0xe8, 0x8, + MA35_MUX(0x0, "GPN2"), + MA35_MUX(0x3, "CAN0_RXD"), + MA35_MUX(0x6, "CCAP1_DATA2")), + MA35_PIN(205, PN3, 0xe8, 0xc, + MA35_MUX(0x0, "GPN3"), + MA35_MUX(0x3, "CAN0_TXD"), + MA35_MUX(0x6, "CCAP1_DATA3")), + MA35_PIN(206, PN4, 0xe8, 0x10, + MA35_MUX(0x0, "GPN4"), + MA35_MUX(0x4, "I2C1_SDA"), + MA35_MUX(0x6, "CCAP1_DATA4")), + MA35_PIN(207, PN5, 0xe8, 0x14, + MA35_MUX(0x0, "GPN5"), + MA35_MUX(0x4, "I2C1_SCL"), + MA35_MUX(0x6, "CCAP1_DATA5")), + MA35_PIN(208, PN6, 0xe8, 0x18, + MA35_MUX(0x0, "GPN6"), + MA35_MUX(0x3, "CAN1_RXD"), + MA35_MUX(0x6, "CCAP1_DATA6")), + MA35_PIN(209, PN7, 0xe8, 0x1c, + MA35_MUX(0x0, "GPN7"), + MA35_MUX(0x3, "CAN1_TXD"), + MA35_MUX(0x6, "CCAP1_DATA7")), + MA35_PIN(210, PN10, 0xec, 0x8, + MA35_MUX(0x0, "GPN10"), + MA35_MUX(0x3, "CAN2_RXD"), + MA35_MUX(0x6, "CCAP1_SCLK")), + MA35_PIN(211, PN11, 0xec, 0xc, + MA35_MUX(0x0, "GPN11"), + MA35_MUX(0x3, "CAN2_TXD"), + MA35_MUX(0x6, "CCAP1_PIXCLK")), + MA35_PIN(212, PN12, 0xec, 0x10, + MA35_MUX(0x0, "GPN12"), + MA35_MUX(0x2, "UART6_nCTS"), + MA35_MUX(0x3, "UART12_RXD"), + MA35_MUX(0x4, "I2C5_SDA"), + MA35_MUX(0x6, "CCAP1_HSYNC")), + MA35_PIN(213, PN13, 0xec, 0x14, + MA35_MUX(0x0, "GPN13"), + MA35_MUX(0x2, "UART6_nRTS"), + MA35_MUX(0x3, "UART12_TXD"), + MA35_MUX(0x4, "I2C5_SCL"), + MA35_MUX(0x6, "CCAP1_VSYNC")), + MA35_PIN(214, PN14, 0xec, 0x18, + MA35_MUX(0x0, "GPN14"), + MA35_MUX(0x2, "UART6_RXD"), + MA35_MUX(0x3, "CAN3_RXD"), + MA35_MUX(0x5, "SPI1_SS1"), + MA35_MUX(0x6, "CCAP1_SFIELD"), + MA35_MUX(0x7, "SPI1_I2SMCLK")), + MA35_PIN(215, PN15, 0xec, 0x1c, + MA35_MUX(0x0, "GPN15"), + MA35_MUX(0x1, "EPWM2_CH4"), + MA35_MUX(0x2, "UART6_TXD"), + MA35_MUX(0x3, "CAN3_TXD"), + MA35_MUX(0x5, "I2S0_MCLK"), + MA35_MUX(0x6, "SPI1_SS1"), + MA35_MUX(0x7, "SPI1_I2SMCLK"), + MA35_MUX(0x8, "SC0_nCD"), + MA35_MUX(0x9, "EADC0_ST"), + MA35_MUX(0xa, "CLKO"), + MA35_MUX(0xb, "TM6")), + MA35_PIN(216, PN8, 0xec, 0x0, + MA35_MUX(0x0, "GPN8"), + MA35_MUX(0x1, "EPWM2_CH4"), + MA35_MUX(0x4, "I2C0_SDA"), + MA35_MUX(0x5, "SPI2_I2SMCLK"), + MA35_MUX(0x6, "CCAP1_DATA8")), + MA35_PIN(217, PN9, 0xec, 0x4, + MA35_MUX(0x0, "GPN9"), + MA35_MUX(0x1, "EPWM2_CH5"), + MA35_MUX(0x4, "I2C0_SCL"), + MA35_MUX(0x5, "SPI1_I2SMCLK"), + MA35_MUX(0x6, "CCAP1_DATA9")), + MA35_PIN(218, PN10, 0xec, 0x8, + MA35_MUX(0x0, "GPN10"), + MA35_MUX(0x3, "CAN2_RXD"), + MA35_MUX(0x4, "USBHL2_DM"), + MA35_MUX(0x6, "CCAP1_SCLK")), + MA35_PIN(219, PN11, 0xec, 0xc, + MA35_MUX(0x0, "GPN11"), + MA35_MUX(0x3, "CAN2_TXD"), + MA35_MUX(0x4, "USBHL2_DP"), + MA35_MUX(0x6, "CCAP1_PIXCLK")), + MA35_PIN(220, PN12, 0xec, 0x10, + MA35_MUX(0x0, "GPN12"), + MA35_MUX(0x2, "UART6_nCTS"), + MA35_MUX(0x3, "UART12_RXD"), + MA35_MUX(0x4, "I2C5_SDA"), + MA35_MUX(0x6, "CCAP1_HSYNC")), + MA35_PIN(221, PN13, 0xec, 0x14, + MA35_MUX(0x0, "GPN13"), + MA35_MUX(0x2, "UART6_nRTS"), + MA35_MUX(0x3, "UART12_TXD"), + MA35_MUX(0x4, "I2C5_SCL"), + MA35_MUX(0x6, "CCAP1_VSYNC")), + MA35_PIN(222, PN14, 0xec, 0x18, + MA35_MUX(0x0, "GPN14"), + MA35_MUX(0x2, "UART6_RXD"), + MA35_MUX(0x3, "CAN3_RXD"), + MA35_MUX(0x4, "USBHL3_DM"), + MA35_MUX(0x5, "SPI1_SS1"), + MA35_MUX(0x6, "CCAP1_SFIELD"), + MA35_MUX(0x7, "SPI1_I2SMCLK")), + MA35_PIN(223, PN15, 0xec, 0x1c, + MA35_MUX(0x0, "GPN15"), + MA35_MUX(0x1, "EPWM2_CH4"), + MA35_MUX(0x2, "UART6_TXD"), + MA35_MUX(0x3, "CAN3_TXD"), + MA35_MUX(0x4, "USBHL3_DP"), + MA35_MUX(0x5, "I2S0_MCLK"), + MA35_MUX(0x6, "SPI1_SS1"), + MA35_MUX(0x7, "SPI1_I2SMCLK"), + MA35_MUX(0x8, "SC0_nCD"), + MA35_MUX(0x9, "EADC0_ST"), + MA35_MUX(0xa, "CLKO"), + MA35_MUX(0xb, "TM6")), +}; + +static int ma35d1_get_pin_num(int offset, int shift) +{ + return (offset - 0x80) * 2 + shift / 4; +} + +static struct ma35_pinctrl_soc_info ma35d1_pinctrl_info = { + .pins = ma35d1_pins, + .npins = ARRAY_SIZE(ma35d1_pins), + .get_pin_num = ma35d1_get_pin_num, +}; + +static DEFINE_NOIRQ_DEV_PM_OPS(ma35_pinctrl_pm_ops, ma35_pinctrl_suspend, ma35_pinctrl_resume); + +static int ma35d1_pinctrl_probe(struct platform_device *pdev) +{ + return ma35_pinctrl_probe(pdev, &ma35d1_pinctrl_info); +} + +static const struct of_device_id ma35d1_pinctrl_of_match[] = { + { .compatible = "nuvoton,ma35d1-pinctrl" }, + { }, +}; + +static struct platform_driver ma35d1_pinctrl_driver = { + .probe = ma35d1_pinctrl_probe, + .driver = { + .name = "ma35d1-pinctrl", + .pm = pm_sleep_ptr(&ma35_pinctrl_pm_ops), + .of_match_table = ma35d1_pinctrl_of_match, + }, +}; + +static int __init ma35d1_pinctrl_init(void) +{ + return platform_driver_register(&ma35d1_pinctrl_driver); +} +arch_initcall(ma35d1_pinctrl_init); + +MODULE_AUTHOR("schung@nuvoton.com"); +MODULE_DESCRIPTION("Nuvoton MA35D1 pinctrl driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/nxp/pinctrl-s32cc.c b/drivers/pinctrl/nxp/pinctrl-s32cc.c index f0cad2c501f7..df3e5d82da4b 100644 --- a/drivers/pinctrl/nxp/pinctrl-s32cc.c +++ b/drivers/pinctrl/nxp/pinctrl-s32cc.c @@ -268,28 +268,23 @@ static int s32_dt_node_to_map(struct pinctrl_dev *pctldev, unsigned int *num_maps) { unsigned int reserved_maps; - struct device_node *np; - int ret = 0; + int ret; reserved_maps = 0; *map = NULL; *num_maps = 0; - for_each_available_child_of_node(np_config, np) { + for_each_available_child_of_node_scoped(np_config, np) { ret = s32_dt_group_node_to_map(pctldev, np, map, &reserved_maps, num_maps, np_config->name); if (ret < 0) { - of_node_put(np); - break; + pinctrl_utils_free_map(pctldev, *map, *num_maps); + return ret; } } - if (ret) - pinctrl_utils_free_map(pctldev, *map, *num_maps); - - return ret; - + return 0; } static const struct pinctrl_ops s32_pctrl_ops = { @@ -786,7 +781,6 @@ static int s32_pinctrl_parse_functions(struct device_node *np, struct s32_pinctrl_soc_info *info, u32 index) { - struct device_node *child; struct pinfunction *func; struct s32_pin_group *grp; const char **groups; @@ -810,14 +804,12 @@ static int s32_pinctrl_parse_functions(struct device_node *np, if (!groups) return -ENOMEM; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { groups[i] = child->name; grp = &info->groups[info->grp_index++]; ret = s32_pinctrl_parse_groups(child, grp, info); - if (ret) { - of_node_put(child); + if (ret) return ret; - } i++; } @@ -831,7 +823,6 @@ static int s32_pinctrl_probe_dt(struct platform_device *pdev, { struct s32_pinctrl_soc_info *info = ipctl->info; struct device_node *np = pdev->dev.of_node; - struct device_node *child; struct resource *res; struct regmap *map; void __iomem *base; @@ -889,7 +880,7 @@ static int s32_pinctrl_probe_dt(struct platform_device *pdev, return -ENOMEM; info->ngroups = 0; - for_each_child_of_node(np, child) + for_each_child_of_node_scoped(np, child) info->ngroups += of_get_child_count(child); info->groups = devm_kcalloc(&pdev->dev, info->ngroups, @@ -898,12 +889,10 @@ static int s32_pinctrl_probe_dt(struct platform_device *pdev, return -ENOMEM; i = 0; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { ret = s32_pinctrl_parse_functions(child, info, i++); - if (ret) { - of_node_put(child); + if (ret) return ret; - } } return 0; diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 80de389199bd..a499b8af5c1f 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -382,7 +382,6 @@ int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, unsigned int *num_maps, enum pinctrl_map_type type) { unsigned int reserved_maps; - struct device_node *np; int ret; reserved_maps = 0; @@ -394,13 +393,11 @@ int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, if (ret < 0) goto exit; - for_each_available_child_of_node(np_config, np) { + for_each_available_child_of_node_scoped(np_config, np) { ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map, &reserved_maps, num_maps, type); - if (ret < 0) { - of_node_put(np); + if (ret < 0) goto exit; - } } return 0; diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index a27c01fcbb47..8b01d312305a 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -632,7 +632,6 @@ static int atmel_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, struct pinctrl_map **map, unsigned int *num_maps) { - struct device_node *np; unsigned int reserved_maps; int ret; @@ -648,13 +647,11 @@ static int atmel_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, ret = atmel_pctl_dt_subnode_to_map(pctldev, np_config, map, &reserved_maps, num_maps); if (ret) { - for_each_child_of_node(np_config, np) { + for_each_child_of_node_scoped(np_config, np) { ret = atmel_pctl_dt_subnode_to_map(pctldev, np, map, &reserved_maps, num_maps); - if (ret < 0) { - of_node_put(np); + if (ret < 0) break; - } } } diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 5aa9d5c533c6..b3c3f5fb2e2e 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1244,7 +1244,6 @@ static int at91_pinctrl_parse_groups(struct device_node *np, static int at91_pinctrl_parse_functions(struct device_node *np, struct at91_pinctrl *info, u32 index) { - struct device_node *child; struct at91_pmx_func *func; struct at91_pin_group *grp; int ret; @@ -1267,14 +1266,12 @@ static int at91_pinctrl_parse_functions(struct device_node *np, if (!func->groups) return -ENOMEM; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { func->groups[i] = child->name; grp = &info->groups[grp_index++]; ret = at91_pinctrl_parse_groups(child, grp, info, i++); - if (ret) { - of_node_put(child); + if (ret) return ret; - } } return 0; @@ -1296,7 +1293,6 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev, int i, j, ngpio_chips_enabled = 0; uint32_t *tmp; struct device_node *np = dev->of_node; - struct device_node *child; if (!np) return -ENODEV; @@ -1349,14 +1345,12 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev, i = 0; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { if (of_device_is_compatible(child, gpio_compat)) continue; ret = at91_pinctrl_parse_functions(child, info, i++); - if (ret) { - of_node_put(child); + if (ret) return dev_err_probe(dev, ret, "failed to parse function\n"); - } } return 0; diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index 981c569bd671..9a92707d2525 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -58,9 +59,14 @@ #define CY8C95X0_PIN_TO_OFFSET(x) (((x) >= 20) ? ((x) + 4) : (x)) -#define CY8C95X0_MUX_REGMAP_TO_PORT(x) ((x) / MUXED_STRIDE) -#define CY8C95X0_MUX_REGMAP_TO_REG(x) (((x) % MUXED_STRIDE) + CY8C95X0_INTMASK) -#define CY8C95X0_MUX_REGMAP_TO_OFFSET(x, p) ((x) - CY8C95X0_INTMASK + (p) * MUXED_STRIDE) +#define MAX_BANK 8 +#define BANK_SZ 8 +#define MAX_LINE (MAX_BANK * BANK_SZ) +#define MUXED_STRIDE (CY8C95X0_DRV_HIZ - CY8C95X0_INTMASK) +#define CY8C95X0_GPIO_MASK GENMASK(7, 0) +#define CY8C95X0_VIRTUAL (CY8C95X0_COMMAND + 1) +#define CY8C95X0_MUX_REGMAP_TO_OFFSET(x, p) \ + (CY8C95X0_VIRTUAL + (x) - CY8C95X0_INTMASK + (p) * MUXED_STRIDE) static const struct i2c_device_id cy8c95x0_id[] = { { "cy8c9520", 20, }, @@ -120,18 +126,11 @@ static const struct dmi_system_id cy8c95x0_dmi_acpi_irq_info[] = { {} }; -#define MAX_BANK 8 -#define BANK_SZ 8 -#define MAX_LINE (MAX_BANK * BANK_SZ) -#define MUXED_STRIDE 16 -#define CY8C95X0_GPIO_MASK GENMASK(7, 0) - /** * struct cy8c95x0_pinctrl - driver data * @regmap: Device's regmap. Only direct access registers. - * @muxed_regmap: Regmap for all muxed registers. * @irq_lock: IRQ bus lock - * @i2c_lock: Mutex for the device internal mux register + * @i2c_lock: Mutex to hold while using the regmap * @irq_mask: I/O bits affected by interrupts * @irq_trig_raise: I/O bits affected by raising voltage level * @irq_trig_fall: I/O bits affected by falling voltage level @@ -152,7 +151,6 @@ static const struct dmi_system_id cy8c95x0_dmi_acpi_irq_info[] = { */ struct cy8c95x0_pinctrl { struct regmap *regmap; - struct regmap *muxed_regmap; struct mutex irq_lock; struct mutex i2c_lock; DECLARE_BITMAP(irq_mask, MAX_LINE); @@ -331,6 +329,9 @@ static int cypress_get_pin_mask(struct cy8c95x0_pinctrl *chip, unsigned int pin) static bool cy8c95x0_readable_register(struct device *dev, unsigned int reg) { + if (reg >= CY8C95X0_VIRTUAL) + return true; + switch (reg) { case 0x24 ... 0x27: return false; @@ -341,6 +342,9 @@ static bool cy8c95x0_readable_register(struct device *dev, unsigned int reg) static bool cy8c95x0_writeable_register(struct device *dev, unsigned int reg) { + if (reg >= CY8C95X0_VIRTUAL) + return true; + switch (reg) { case CY8C95X0_INPUT_(0) ... CY8C95X0_INPUT_(7): return false; @@ -433,115 +437,34 @@ static bool cy8c95x0_quick_path_register(unsigned int reg) } } -static const struct reg_default cy8c95x0_reg_defaults[] = { - { CY8C95X0_OUTPUT_(0), GENMASK(7, 0) }, - { CY8C95X0_OUTPUT_(1), GENMASK(7, 0) }, - { CY8C95X0_OUTPUT_(2), GENMASK(7, 0) }, - { CY8C95X0_OUTPUT_(3), GENMASK(7, 0) }, - { CY8C95X0_OUTPUT_(4), GENMASK(7, 0) }, - { CY8C95X0_OUTPUT_(5), GENMASK(7, 0) }, - { CY8C95X0_OUTPUT_(6), GENMASK(7, 0) }, - { CY8C95X0_OUTPUT_(7), GENMASK(7, 0) }, - { CY8C95X0_PORTSEL, 0 }, - { CY8C95X0_PWMSEL, 0 }, +static const struct regmap_range_cfg cy8c95x0_ranges[] = { + { + .range_min = CY8C95X0_VIRTUAL, + .range_max = 0, /* Updated at runtime */ + .selector_reg = CY8C95X0_PORTSEL, + .selector_mask = 0x07, + .selector_shift = 0x0, + .window_start = CY8C95X0_INTMASK, + .window_len = MUXED_STRIDE, + } }; -static int -cy8c95x0_mux_reg_read(void *context, unsigned int off, unsigned int *val) -{ - struct cy8c95x0_pinctrl *chip = context; - u8 port = CY8C95X0_MUX_REGMAP_TO_PORT(off); - int ret, reg = CY8C95X0_MUX_REGMAP_TO_REG(off); - - mutex_lock(&chip->i2c_lock); - /* Select the correct bank */ - ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port); - if (ret < 0) - goto out; - - /* - * Read the register through direct access regmap. The target range - * is marked volatile. - */ - ret = regmap_read(chip->regmap, reg, val); -out: - mutex_unlock(&chip->i2c_lock); - - return ret; -} - -static int -cy8c95x0_mux_reg_write(void *context, unsigned int off, unsigned int val) -{ - struct cy8c95x0_pinctrl *chip = context; - u8 port = CY8C95X0_MUX_REGMAP_TO_PORT(off); - int ret, reg = CY8C95X0_MUX_REGMAP_TO_REG(off); - - mutex_lock(&chip->i2c_lock); - /* Select the correct bank */ - ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port); - if (ret < 0) - goto out; - - /* - * Write the register through direct access regmap. The target range - * is marked volatile. - */ - ret = regmap_write(chip->regmap, reg, val); -out: - mutex_unlock(&chip->i2c_lock); - - return ret; -} - -static bool cy8c95x0_mux_accessible_register(struct device *dev, unsigned int off) -{ - struct i2c_client *i2c = to_i2c_client(dev); - struct cy8c95x0_pinctrl *chip = i2c_get_clientdata(i2c); - u8 port = CY8C95X0_MUX_REGMAP_TO_PORT(off); - u8 reg = CY8C95X0_MUX_REGMAP_TO_REG(off); - - if (port >= chip->nport) - return false; - - return cy8c95x0_muxed_register(reg); -} - -static struct regmap_bus cy8c95x0_regmap_bus = { - .reg_read = cy8c95x0_mux_reg_read, - .reg_write = cy8c95x0_mux_reg_write, -}; - -/* Regmap for muxed registers CY8C95X0_INTMASK - CY8C95X0_DRV_HIZ */ -static const struct regmap_config cy8c95x0_muxed_regmap = { - .name = "muxed", +static const struct regmap_config cy8c9520_i2c_regmap = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_FLAT, - .use_single_read = true, - .use_single_write = true, - .max_register = MUXED_STRIDE * BANK_SZ, - .num_reg_defaults_raw = MUXED_STRIDE * BANK_SZ, - .readable_reg = cy8c95x0_mux_accessible_register, - .writeable_reg = cy8c95x0_mux_accessible_register, -}; - -/* Direct access regmap */ -static const struct regmap_config cy8c95x0_i2c_regmap = { - .name = "direct", - .reg_bits = 8, - .val_bits = 8, - - .reg_defaults = cy8c95x0_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(cy8c95x0_reg_defaults), .readable_reg = cy8c95x0_readable_register, .writeable_reg = cy8c95x0_writeable_register, .volatile_reg = cy8c95x0_volatile_register, .precious_reg = cy8c95x0_precious_register, - .cache_type = REGCACHE_FLAT, - .max_register = CY8C95X0_COMMAND, + .cache_type = REGCACHE_MAPLE, + .ranges = NULL, /* Updated at runtime */ + .num_ranges = 1, + .max_register = 0, /* Updated at runtime */ + .num_reg_defaults_raw = 0, /* Updated at runtime */ + .use_single_read = true, /* Workaround for regcache bug */ + .disable_locking = true, }; static inline int cy8c95x0_regmap_update_bits_base(struct cy8c95x0_pinctrl *chip, @@ -552,48 +475,42 @@ static inline int cy8c95x0_regmap_update_bits_base(struct cy8c95x0_pinctrl *chip bool *change, bool async, bool force) { - struct regmap *regmap; - int ret, off, i, read_val; + int ret, off, i; /* Caller should never modify PORTSEL directly */ if (reg == CY8C95X0_PORTSEL) return -EINVAL; - /* Registers behind the PORTSEL mux have their own regmap */ + /* Registers behind the PORTSEL mux have their own range in regmap */ if (cy8c95x0_muxed_register(reg)) { - regmap = chip->muxed_regmap; off = CY8C95X0_MUX_REGMAP_TO_OFFSET(reg, port); } else { - regmap = chip->regmap; /* Quick path direct access registers honor the port argument */ if (cy8c95x0_quick_path_register(reg)) off = reg + port; else off = reg; } + guard(mutex)(&chip->i2c_lock); - ret = regmap_update_bits_base(regmap, off, mask, val, change, async, force); + ret = regmap_update_bits_base(chip->regmap, off, mask, val, change, async, force); if (ret < 0) return ret; - /* Update the cache when a WC bit is written */ + /* Mimic what hardware does and update the cache when a WC bit is written. + * Allows to mark the registers as non-volatile and reduces I/O cycles. + */ if (cy8c95x0_wc_register(reg) && (mask & val)) { + /* Writing a 1 clears set bits in the other drive mode registers */ + regcache_cache_only(chip->regmap, true); for (i = CY8C95X0_DRV_PU; i <= CY8C95X0_DRV_HIZ; i++) { if (i == reg) continue; + off = CY8C95X0_MUX_REGMAP_TO_OFFSET(i, port); - - ret = regmap_read(regmap, off, &read_val); - if (ret < 0) - continue; - - if (!(read_val & mask & val)) - continue; - - regcache_cache_only(regmap, true); - regmap_update_bits(regmap, off, mask & val, 0); - regcache_cache_only(regmap, false); + regmap_clear_bits(chip->regmap, off, mask & val); } + regcache_cache_only(chip->regmap, false); } return ret; @@ -666,23 +583,23 @@ static int cy8c95x0_regmap_update_bits(struct cy8c95x0_pinctrl *chip, unsigned i static int cy8c95x0_regmap_read(struct cy8c95x0_pinctrl *chip, unsigned int reg, unsigned int port, unsigned int *read_val) { - struct regmap *regmap; - int off; + int off, ret; - /* Registers behind the PORTSEL mux have their own regmap */ + /* Registers behind the PORTSEL mux have their own range in regmap */ if (cy8c95x0_muxed_register(reg)) { - regmap = chip->muxed_regmap; off = CY8C95X0_MUX_REGMAP_TO_OFFSET(reg, port); } else { - regmap = chip->regmap; /* Quick path direct access registers honor the port argument */ if (cy8c95x0_quick_path_register(reg)) off = reg + port; else off = reg; } + guard(mutex)(&chip->i2c_lock); - return regmap_read(regmap, off, read_val); + ret = regmap_read(chip->regmap, off, read_val); + + return ret; } static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, @@ -1511,6 +1428,8 @@ static int cy8c95x0_detect(struct i2c_client *client, static int cy8c95x0_probe(struct i2c_client *client) { struct cy8c95x0_pinctrl *chip; + struct regmap_config regmap_conf; + struct regmap_range_cfg regmap_range_conf; struct regulator *reg; int ret; @@ -1530,15 +1449,20 @@ static int cy8c95x0_probe(struct i2c_client *client) chip->tpin = chip->driver_data & CY8C95X0_GPIO_MASK; chip->nport = DIV_ROUND_UP(CY8C95X0_PIN_TO_OFFSET(chip->tpin), BANK_SZ); + memcpy(®map_range_conf, &cy8c95x0_ranges[0], sizeof(regmap_range_conf)); + switch (chip->tpin) { case 20: strscpy(chip->name, cy8c95x0_id[0].name, I2C_NAME_SIZE); + regmap_range_conf.range_max = CY8C95X0_VIRTUAL + 3 * MUXED_STRIDE; break; case 40: strscpy(chip->name, cy8c95x0_id[1].name, I2C_NAME_SIZE); + regmap_range_conf.range_max = CY8C95X0_VIRTUAL + 6 * MUXED_STRIDE; break; case 60: strscpy(chip->name, cy8c95x0_id[2].name, I2C_NAME_SIZE); + regmap_range_conf.range_max = CY8C95X0_VIRTUAL + 8 * MUXED_STRIDE; break; default: return -ENODEV; @@ -1571,22 +1495,18 @@ static int cy8c95x0_probe(struct i2c_client *client) gpiod_set_consumer_name(chip->gpio_reset, "CY8C95X0 RESET"); } - /* Generic regmap for direct access registers */ - chip->regmap = devm_regmap_init_i2c(client, &cy8c95x0_i2c_regmap); + /* Regmap for direct and paged registers */ + memcpy(®map_conf, &cy8c9520_i2c_regmap, sizeof(regmap_conf)); + regmap_conf.ranges = ®map_range_conf; + regmap_conf.max_register = regmap_range_conf.range_max; + regmap_conf.num_reg_defaults_raw = regmap_range_conf.range_max; + + chip->regmap = devm_regmap_init_i2c(client, ®map_conf); if (IS_ERR(chip->regmap)) { ret = PTR_ERR(chip->regmap); goto err_exit; } - /* Port specific regmap behind PORTSEL mux */ - chip->muxed_regmap = devm_regmap_init(&client->dev, &cy8c95x0_regmap_bus, - chip, &cy8c95x0_muxed_regmap); - if (IS_ERR(chip->muxed_regmap)) { - ret = dev_err_probe(&client->dev, PTR_ERR(chip->muxed_regmap), - "Failed to register muxed regmap\n"); - goto err_exit; - } - bitmap_zero(chip->push_pull, MAX_LINE); bitmap_zero(chip->shiftmask, MAX_LINE); bitmap_set(chip->shiftmask, 0, 20); diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c index 6e1be38865c3..3a9a0f059090 100644 --- a/drivers/pinctrl/pinctrl-equilibrium.c +++ b/drivers/pinctrl/pinctrl-equilibrium.c @@ -566,8 +566,8 @@ static const struct pinconf_ops eqbr_pinconf_ops = { .pin_config_config_dbg_show = pinconf_generic_dump_config, }; -static bool is_func_exist(struct eqbr_pmx_func *funcs, const char *name, - unsigned int nr_funcs, unsigned int *idx) +static bool is_func_exist(struct pinfunction *funcs, const char *name, + unsigned int nr_funcs, unsigned int *idx) { int i; @@ -584,18 +584,18 @@ static bool is_func_exist(struct eqbr_pmx_func *funcs, const char *name, return false; } -static int funcs_utils(struct device *dev, struct eqbr_pmx_func *funcs, +static int funcs_utils(struct device *dev, struct pinfunction *funcs, unsigned int *nr_funcs, funcs_util_ops op) { struct device_node *node = dev->of_node; - struct device_node *np; struct property *prop; const char *fn_name; + const char **groups; unsigned int fid; int i, j; i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { prop = of_find_property(np, "groups", NULL); if (!prop) continue; @@ -620,20 +620,20 @@ static int funcs_utils(struct device *dev, struct eqbr_pmx_func *funcs, case OP_COUNT_NR_FUNC_GRPS: if (is_func_exist(funcs, fn_name, *nr_funcs, &fid)) - funcs[fid].nr_groups++; + funcs[fid].ngroups++; break; case OP_ADD_FUNC_GRPS: if (is_func_exist(funcs, fn_name, *nr_funcs, &fid)) { - for (j = 0; j < funcs[fid].nr_groups; j++) - if (!funcs[fid].groups[j]) + groups = (const char **)funcs[fid].groups; + for (j = 0; j < funcs[fid].ngroups; j++) + if (!groups[j]) break; - funcs[fid].groups[j] = prop->value; + groups[j] = prop->value; } break; default: - of_node_put(np); return -EINVAL; } i++; @@ -645,7 +645,7 @@ static int funcs_utils(struct device *dev, struct eqbr_pmx_func *funcs, static int eqbr_build_functions(struct eqbr_pinctrl_drv_data *drvdata) { struct device *dev = drvdata->dev; - struct eqbr_pmx_func *funcs = NULL; + struct pinfunction *funcs = NULL; unsigned int nr_funcs = 0; int i, ret; @@ -666,9 +666,9 @@ static int eqbr_build_functions(struct eqbr_pinctrl_drv_data *drvdata) return ret; for (i = 0; i < nr_funcs; i++) { - if (!funcs[i].nr_groups) + if (!funcs[i].ngroups) continue; - funcs[i].groups = devm_kcalloc(dev, funcs[i].nr_groups, + funcs[i].groups = devm_kcalloc(dev, funcs[i].ngroups, sizeof(*(funcs[i].groups)), GFP_KERNEL); if (!funcs[i].groups) @@ -688,7 +688,7 @@ static int eqbr_build_functions(struct eqbr_pinctrl_drv_data *drvdata) ret = pinmux_generic_add_function(drvdata->pctl_dev, funcs[i].name, funcs[i].groups, - funcs[i].nr_groups, + funcs[i].ngroups, drvdata); if (ret < 0) { dev_err(dev, "Failed to register function %s\n", @@ -706,11 +706,10 @@ static int eqbr_build_groups(struct eqbr_pinctrl_drv_data *drvdata) struct device_node *node = dev->of_node; unsigned int *pins, *pinmux, pin_id, pinmux_id; struct pingroup group, *grp = &group; - struct device_node *np; struct property *prop; int j, err; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { prop = of_find_property(np, "groups", NULL); if (!prop) continue; @@ -718,42 +717,35 @@ static int eqbr_build_groups(struct eqbr_pinctrl_drv_data *drvdata) err = of_property_count_u32_elems(np, "pins"); if (err < 0) { dev_err(dev, "No pins in the group: %s\n", prop->name); - of_node_put(np); return err; } grp->npins = err; grp->name = prop->value; pins = devm_kcalloc(dev, grp->npins, sizeof(*pins), GFP_KERNEL); - if (!pins) { - of_node_put(np); + if (!pins) return -ENOMEM; - } + grp->pins = pins; pinmux = devm_kcalloc(dev, grp->npins, sizeof(*pinmux), GFP_KERNEL); - if (!pinmux) { - of_node_put(np); + if (!pinmux) return -ENOMEM; - } for (j = 0; j < grp->npins; j++) { if (of_property_read_u32_index(np, "pins", j, &pin_id)) { dev_err(dev, "Group %s: Read intel pins id failed\n", grp->name); - of_node_put(np); return -EINVAL; } if (pin_id >= drvdata->pctl_desc.npins) { dev_err(dev, "Group %s: Invalid pin ID, idx: %d, pin %u\n", grp->name, j, pin_id); - of_node_put(np); return -EINVAL; } pins[j] = pin_id; if (of_property_read_u32_index(np, "pinmux", j, &pinmux_id)) { dev_err(dev, "Group %s: Read intel pinmux id failed\n", grp->name); - of_node_put(np); return -EINVAL; } pinmux[j] = pinmux_id; @@ -764,7 +756,6 @@ static int eqbr_build_groups(struct eqbr_pinctrl_drv_data *drvdata) pinmux); if (err < 0) { dev_err(dev, "Failed to register group %s\n", grp->name); - of_node_put(np); return err; } memset(&group, 0, sizeof(group)); diff --git a/drivers/pinctrl/pinctrl-equilibrium.h b/drivers/pinctrl/pinctrl-equilibrium.h index 83768cc8b3db..b4d149bde39d 100644 --- a/drivers/pinctrl/pinctrl-equilibrium.h +++ b/drivers/pinctrl/pinctrl-equilibrium.h @@ -67,18 +67,6 @@ struct gpio_irq_type { unsigned int logic_type; }; -/** - * struct eqbr_pmx_func: represent a pin function. - * @name: name of the pin function, used to lookup the function. - * @groups: one or more names of pin groups that provide this function. - * @nr_groups: number of groups included in @groups. - */ -struct eqbr_pmx_func { - const char *name; - const char **groups; - unsigned int nr_groups; -}; - /** * struct eqbr_pin_bank: represent a pin bank. * @membase: base address of the pin bank register. diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c index bc6358a686fc..31703737731b 100644 --- a/drivers/pinctrl/pinctrl-ingenic.c +++ b/drivers/pinctrl/pinctrl-ingenic.c @@ -94,6 +94,12 @@ .data = (void *)func, \ } +#define INGENIC_PIN_FUNCTION(_name_, id) \ + { \ + .func = PINCTRL_PINFUNCTION(_name_, id##_groups, ARRAY_SIZE(id##_groups)), \ + .data = NULL, \ + } + enum jz_version { ID_JZ4730, ID_JZ4740, @@ -238,15 +244,15 @@ static const char *jz4730_pwm0_groups[] = { "pwm0", }; static const char *jz4730_pwm1_groups[] = { "pwm1", }; static const struct function_desc jz4730_functions[] = { - { "mmc", jz4730_mmc_groups, ARRAY_SIZE(jz4730_mmc_groups), }, - { "uart0", jz4730_uart0_groups, ARRAY_SIZE(jz4730_uart0_groups), }, - { "uart1", jz4730_uart1_groups, ARRAY_SIZE(jz4730_uart1_groups), }, - { "uart2", jz4730_uart2_groups, ARRAY_SIZE(jz4730_uart2_groups), }, - { "uart3", jz4730_uart3_groups, ARRAY_SIZE(jz4730_uart3_groups), }, - { "lcd", jz4730_lcd_groups, ARRAY_SIZE(jz4730_lcd_groups), }, - { "nand", jz4730_nand_groups, ARRAY_SIZE(jz4730_nand_groups), }, - { "pwm0", jz4730_pwm0_groups, ARRAY_SIZE(jz4730_pwm0_groups), }, - { "pwm1", jz4730_pwm1_groups, ARRAY_SIZE(jz4730_pwm1_groups), }, + INGENIC_PIN_FUNCTION("mmc", jz4730_mmc), + INGENIC_PIN_FUNCTION("uart0", jz4730_uart0), + INGENIC_PIN_FUNCTION("uart1", jz4730_uart1), + INGENIC_PIN_FUNCTION("uart2", jz4730_uart2), + INGENIC_PIN_FUNCTION("uart3", jz4730_uart3), + INGENIC_PIN_FUNCTION("lcd", jz4730_lcd), + INGENIC_PIN_FUNCTION("nand", jz4730_nand), + INGENIC_PIN_FUNCTION("pwm0", jz4730_pwm0), + INGENIC_PIN_FUNCTION("pwm1", jz4730_pwm1), }; static const struct ingenic_chip_info jz4730_chip_info = { @@ -343,19 +349,19 @@ static const char *jz4740_pwm6_groups[] = { "pwm6", }; static const char *jz4740_pwm7_groups[] = { "pwm7", }; static const struct function_desc jz4740_functions[] = { - { "mmc", jz4740_mmc_groups, ARRAY_SIZE(jz4740_mmc_groups), }, - { "uart0", jz4740_uart0_groups, ARRAY_SIZE(jz4740_uart0_groups), }, - { "uart1", jz4740_uart1_groups, ARRAY_SIZE(jz4740_uart1_groups), }, - { "lcd", jz4740_lcd_groups, ARRAY_SIZE(jz4740_lcd_groups), }, - { "nand", jz4740_nand_groups, ARRAY_SIZE(jz4740_nand_groups), }, - { "pwm0", jz4740_pwm0_groups, ARRAY_SIZE(jz4740_pwm0_groups), }, - { "pwm1", jz4740_pwm1_groups, ARRAY_SIZE(jz4740_pwm1_groups), }, - { "pwm2", jz4740_pwm2_groups, ARRAY_SIZE(jz4740_pwm2_groups), }, - { "pwm3", jz4740_pwm3_groups, ARRAY_SIZE(jz4740_pwm3_groups), }, - { "pwm4", jz4740_pwm4_groups, ARRAY_SIZE(jz4740_pwm4_groups), }, - { "pwm5", jz4740_pwm5_groups, ARRAY_SIZE(jz4740_pwm5_groups), }, - { "pwm6", jz4740_pwm6_groups, ARRAY_SIZE(jz4740_pwm6_groups), }, - { "pwm7", jz4740_pwm7_groups, ARRAY_SIZE(jz4740_pwm7_groups), }, + INGENIC_PIN_FUNCTION("mmc", jz4740_mmc), + INGENIC_PIN_FUNCTION("uart0", jz4740_uart0), + INGENIC_PIN_FUNCTION("uart1", jz4740_uart1), + INGENIC_PIN_FUNCTION("lcd", jz4740_lcd), + INGENIC_PIN_FUNCTION("nand", jz4740_nand), + INGENIC_PIN_FUNCTION("pwm0", jz4740_pwm0), + INGENIC_PIN_FUNCTION("pwm1", jz4740_pwm1), + INGENIC_PIN_FUNCTION("pwm2", jz4740_pwm2), + INGENIC_PIN_FUNCTION("pwm3", jz4740_pwm3), + INGENIC_PIN_FUNCTION("pwm4", jz4740_pwm4), + INGENIC_PIN_FUNCTION("pwm5", jz4740_pwm5), + INGENIC_PIN_FUNCTION("pwm6", jz4740_pwm6), + INGENIC_PIN_FUNCTION("pwm7", jz4740_pwm7), }; static const struct ingenic_chip_info jz4740_chip_info = { @@ -447,17 +453,17 @@ static const char *jz4725b_pwm4_groups[] = { "pwm4", }; static const char *jz4725b_pwm5_groups[] = { "pwm5", }; static const struct function_desc jz4725b_functions[] = { - { "mmc0", jz4725b_mmc0_groups, ARRAY_SIZE(jz4725b_mmc0_groups), }, - { "mmc1", jz4725b_mmc1_groups, ARRAY_SIZE(jz4725b_mmc1_groups), }, - { "uart", jz4725b_uart_groups, ARRAY_SIZE(jz4725b_uart_groups), }, - { "nand", jz4725b_nand_groups, ARRAY_SIZE(jz4725b_nand_groups), }, - { "pwm0", jz4725b_pwm0_groups, ARRAY_SIZE(jz4725b_pwm0_groups), }, - { "pwm1", jz4725b_pwm1_groups, ARRAY_SIZE(jz4725b_pwm1_groups), }, - { "pwm2", jz4725b_pwm2_groups, ARRAY_SIZE(jz4725b_pwm2_groups), }, - { "pwm3", jz4725b_pwm3_groups, ARRAY_SIZE(jz4725b_pwm3_groups), }, - { "pwm4", jz4725b_pwm4_groups, ARRAY_SIZE(jz4725b_pwm4_groups), }, - { "pwm5", jz4725b_pwm5_groups, ARRAY_SIZE(jz4725b_pwm5_groups), }, - { "lcd", jz4725b_lcd_groups, ARRAY_SIZE(jz4725b_lcd_groups), }, + INGENIC_PIN_FUNCTION("mmc0", jz4725b_mmc0), + INGENIC_PIN_FUNCTION("mmc1", jz4725b_mmc1), + INGENIC_PIN_FUNCTION("uart", jz4725b_uart), + INGENIC_PIN_FUNCTION("nand", jz4725b_nand), + INGENIC_PIN_FUNCTION("pwm0", jz4725b_pwm0), + INGENIC_PIN_FUNCTION("pwm1", jz4725b_pwm1), + INGENIC_PIN_FUNCTION("pwm2", jz4725b_pwm2), + INGENIC_PIN_FUNCTION("pwm3", jz4725b_pwm3), + INGENIC_PIN_FUNCTION("pwm4", jz4725b_pwm4), + INGENIC_PIN_FUNCTION("pwm5", jz4725b_pwm5), + INGENIC_PIN_FUNCTION("lcd", jz4725b_lcd), }; static const struct ingenic_chip_info jz4725b_chip_info = { @@ -579,22 +585,22 @@ static const char *jz4750_pwm4_groups[] = { "pwm4", }; static const char *jz4750_pwm5_groups[] = { "pwm5", }; static const struct function_desc jz4750_functions[] = { - { "uart0", jz4750_uart0_groups, ARRAY_SIZE(jz4750_uart0_groups), }, - { "uart1", jz4750_uart1_groups, ARRAY_SIZE(jz4750_uart1_groups), }, - { "uart2", jz4750_uart2_groups, ARRAY_SIZE(jz4750_uart2_groups), }, - { "uart3", jz4750_uart3_groups, ARRAY_SIZE(jz4750_uart3_groups), }, - { "mmc0", jz4750_mmc0_groups, ARRAY_SIZE(jz4750_mmc0_groups), }, - { "mmc1", jz4750_mmc1_groups, ARRAY_SIZE(jz4750_mmc1_groups), }, - { "i2c", jz4750_i2c_groups, ARRAY_SIZE(jz4750_i2c_groups), }, - { "cim", jz4750_cim_groups, ARRAY_SIZE(jz4750_cim_groups), }, - { "lcd", jz4750_lcd_groups, ARRAY_SIZE(jz4750_lcd_groups), }, - { "nand", jz4750_nand_groups, ARRAY_SIZE(jz4750_nand_groups), }, - { "pwm0", jz4750_pwm0_groups, ARRAY_SIZE(jz4750_pwm0_groups), }, - { "pwm1", jz4750_pwm1_groups, ARRAY_SIZE(jz4750_pwm1_groups), }, - { "pwm2", jz4750_pwm2_groups, ARRAY_SIZE(jz4750_pwm2_groups), }, - { "pwm3", jz4750_pwm3_groups, ARRAY_SIZE(jz4750_pwm3_groups), }, - { "pwm4", jz4750_pwm4_groups, ARRAY_SIZE(jz4750_pwm4_groups), }, - { "pwm5", jz4750_pwm5_groups, ARRAY_SIZE(jz4750_pwm5_groups), }, + INGENIC_PIN_FUNCTION("uart0", jz4750_uart0), + INGENIC_PIN_FUNCTION("uart1", jz4750_uart1), + INGENIC_PIN_FUNCTION("uart2", jz4750_uart2), + INGENIC_PIN_FUNCTION("uart3", jz4750_uart3), + INGENIC_PIN_FUNCTION("mmc0", jz4750_mmc0), + INGENIC_PIN_FUNCTION("mmc1", jz4750_mmc1), + INGENIC_PIN_FUNCTION("i2c", jz4750_i2c), + INGENIC_PIN_FUNCTION("cim", jz4750_cim), + INGENIC_PIN_FUNCTION("lcd", jz4750_lcd), + INGENIC_PIN_FUNCTION("nand", jz4750_nand), + INGENIC_PIN_FUNCTION("pwm0", jz4750_pwm0), + INGENIC_PIN_FUNCTION("pwm1", jz4750_pwm1), + INGENIC_PIN_FUNCTION("pwm2", jz4750_pwm2), + INGENIC_PIN_FUNCTION("pwm3", jz4750_pwm3), + INGENIC_PIN_FUNCTION("pwm4", jz4750_pwm4), + INGENIC_PIN_FUNCTION("pwm5", jz4750_pwm5), }; static const struct ingenic_chip_info jz4750_chip_info = { @@ -744,22 +750,22 @@ static const char *jz4755_pwm4_groups[] = { "pwm4", }; static const char *jz4755_pwm5_groups[] = { "pwm5", }; static const struct function_desc jz4755_functions[] = { - { "uart0", jz4755_uart0_groups, ARRAY_SIZE(jz4755_uart0_groups), }, - { "uart1", jz4755_uart1_groups, ARRAY_SIZE(jz4755_uart1_groups), }, - { "uart2", jz4755_uart2_groups, ARRAY_SIZE(jz4755_uart2_groups), }, - { "ssi", jz4755_ssi_groups, ARRAY_SIZE(jz4755_ssi_groups), }, - { "mmc0", jz4755_mmc0_groups, ARRAY_SIZE(jz4755_mmc0_groups), }, - { "mmc1", jz4755_mmc1_groups, ARRAY_SIZE(jz4755_mmc1_groups), }, - { "i2c", jz4755_i2c_groups, ARRAY_SIZE(jz4755_i2c_groups), }, - { "cim", jz4755_cim_groups, ARRAY_SIZE(jz4755_cim_groups), }, - { "lcd", jz4755_lcd_groups, ARRAY_SIZE(jz4755_lcd_groups), }, - { "nand", jz4755_nand_groups, ARRAY_SIZE(jz4755_nand_groups), }, - { "pwm0", jz4755_pwm0_groups, ARRAY_SIZE(jz4755_pwm0_groups), }, - { "pwm1", jz4755_pwm1_groups, ARRAY_SIZE(jz4755_pwm1_groups), }, - { "pwm2", jz4755_pwm2_groups, ARRAY_SIZE(jz4755_pwm2_groups), }, - { "pwm3", jz4755_pwm3_groups, ARRAY_SIZE(jz4755_pwm3_groups), }, - { "pwm4", jz4755_pwm4_groups, ARRAY_SIZE(jz4755_pwm4_groups), }, - { "pwm5", jz4755_pwm5_groups, ARRAY_SIZE(jz4755_pwm5_groups), }, + INGENIC_PIN_FUNCTION("uart0", jz4755_uart0), + INGENIC_PIN_FUNCTION("uart1", jz4755_uart1), + INGENIC_PIN_FUNCTION("uart2", jz4755_uart2), + INGENIC_PIN_FUNCTION("ssi", jz4755_ssi), + INGENIC_PIN_FUNCTION("mmc0", jz4755_mmc0), + INGENIC_PIN_FUNCTION("mmc1", jz4755_mmc1), + INGENIC_PIN_FUNCTION("i2c", jz4755_i2c), + INGENIC_PIN_FUNCTION("cim", jz4755_cim), + INGENIC_PIN_FUNCTION("lcd", jz4755_lcd), + INGENIC_PIN_FUNCTION("nand", jz4755_nand), + INGENIC_PIN_FUNCTION("pwm0", jz4755_pwm0), + INGENIC_PIN_FUNCTION("pwm1", jz4755_pwm1), + INGENIC_PIN_FUNCTION("pwm2", jz4755_pwm2), + INGENIC_PIN_FUNCTION("pwm3", jz4755_pwm3), + INGENIC_PIN_FUNCTION("pwm4", jz4755_pwm4), + INGENIC_PIN_FUNCTION("pwm5", jz4755_pwm5), }; static const struct ingenic_chip_info jz4755_chip_info = { @@ -1079,35 +1085,35 @@ static const char *jz4760_pwm7_groups[] = { "pwm7", }; static const char *jz4760_otg_groups[] = { "otg-vbus", }; static const struct function_desc jz4760_functions[] = { - { "uart0", jz4760_uart0_groups, ARRAY_SIZE(jz4760_uart0_groups), }, - { "uart1", jz4760_uart1_groups, ARRAY_SIZE(jz4760_uart1_groups), }, - { "uart2", jz4760_uart2_groups, ARRAY_SIZE(jz4760_uart2_groups), }, - { "uart3", jz4760_uart3_groups, ARRAY_SIZE(jz4760_uart3_groups), }, - { "ssi0", jz4760_ssi0_groups, ARRAY_SIZE(jz4760_ssi0_groups), }, - { "ssi1", jz4760_ssi1_groups, ARRAY_SIZE(jz4760_ssi1_groups), }, - { "mmc0", jz4760_mmc0_groups, ARRAY_SIZE(jz4760_mmc0_groups), }, - { "mmc1", jz4760_mmc1_groups, ARRAY_SIZE(jz4760_mmc1_groups), }, - { "mmc2", jz4760_mmc2_groups, ARRAY_SIZE(jz4760_mmc2_groups), }, - { "nemc", jz4760_nemc_groups, ARRAY_SIZE(jz4760_nemc_groups), }, - { "nemc-cs1", jz4760_cs1_groups, ARRAY_SIZE(jz4760_cs1_groups), }, - { "nemc-cs2", jz4760_cs2_groups, ARRAY_SIZE(jz4760_cs2_groups), }, - { "nemc-cs3", jz4760_cs3_groups, ARRAY_SIZE(jz4760_cs3_groups), }, - { "nemc-cs4", jz4760_cs4_groups, ARRAY_SIZE(jz4760_cs4_groups), }, - { "nemc-cs5", jz4760_cs5_groups, ARRAY_SIZE(jz4760_cs5_groups), }, - { "nemc-cs6", jz4760_cs6_groups, ARRAY_SIZE(jz4760_cs6_groups), }, - { "i2c0", jz4760_i2c0_groups, ARRAY_SIZE(jz4760_i2c0_groups), }, - { "i2c1", jz4760_i2c1_groups, ARRAY_SIZE(jz4760_i2c1_groups), }, - { "cim", jz4760_cim_groups, ARRAY_SIZE(jz4760_cim_groups), }, - { "lcd", jz4760_lcd_groups, ARRAY_SIZE(jz4760_lcd_groups), }, - { "pwm0", jz4760_pwm0_groups, ARRAY_SIZE(jz4760_pwm0_groups), }, - { "pwm1", jz4760_pwm1_groups, ARRAY_SIZE(jz4760_pwm1_groups), }, - { "pwm2", jz4760_pwm2_groups, ARRAY_SIZE(jz4760_pwm2_groups), }, - { "pwm3", jz4760_pwm3_groups, ARRAY_SIZE(jz4760_pwm3_groups), }, - { "pwm4", jz4760_pwm4_groups, ARRAY_SIZE(jz4760_pwm4_groups), }, - { "pwm5", jz4760_pwm5_groups, ARRAY_SIZE(jz4760_pwm5_groups), }, - { "pwm6", jz4760_pwm6_groups, ARRAY_SIZE(jz4760_pwm6_groups), }, - { "pwm7", jz4760_pwm7_groups, ARRAY_SIZE(jz4760_pwm7_groups), }, - { "otg", jz4760_otg_groups, ARRAY_SIZE(jz4760_otg_groups), }, + INGENIC_PIN_FUNCTION("uart0", jz4760_uart0), + INGENIC_PIN_FUNCTION("uart1", jz4760_uart1), + INGENIC_PIN_FUNCTION("uart2", jz4760_uart2), + INGENIC_PIN_FUNCTION("uart3", jz4760_uart3), + INGENIC_PIN_FUNCTION("ssi0", jz4760_ssi0), + INGENIC_PIN_FUNCTION("ssi1", jz4760_ssi1), + INGENIC_PIN_FUNCTION("mmc0", jz4760_mmc0), + INGENIC_PIN_FUNCTION("mmc1", jz4760_mmc1), + INGENIC_PIN_FUNCTION("mmc2", jz4760_mmc2), + INGENIC_PIN_FUNCTION("nemc", jz4760_nemc), + INGENIC_PIN_FUNCTION("nemc-cs1", jz4760_cs1), + INGENIC_PIN_FUNCTION("nemc-cs2", jz4760_cs2), + INGENIC_PIN_FUNCTION("nemc-cs3", jz4760_cs3), + INGENIC_PIN_FUNCTION("nemc-cs4", jz4760_cs4), + INGENIC_PIN_FUNCTION("nemc-cs5", jz4760_cs5), + INGENIC_PIN_FUNCTION("nemc-cs6", jz4760_cs6), + INGENIC_PIN_FUNCTION("i2c0", jz4760_i2c0), + INGENIC_PIN_FUNCTION("i2c1", jz4760_i2c1), + INGENIC_PIN_FUNCTION("cim", jz4760_cim), + INGENIC_PIN_FUNCTION("lcd", jz4760_lcd), + INGENIC_PIN_FUNCTION("pwm0", jz4760_pwm0), + INGENIC_PIN_FUNCTION("pwm1", jz4760_pwm1), + INGENIC_PIN_FUNCTION("pwm2", jz4760_pwm2), + INGENIC_PIN_FUNCTION("pwm3", jz4760_pwm3), + INGENIC_PIN_FUNCTION("pwm4", jz4760_pwm4), + INGENIC_PIN_FUNCTION("pwm5", jz4760_pwm5), + INGENIC_PIN_FUNCTION("pwm6", jz4760_pwm6), + INGENIC_PIN_FUNCTION("pwm7", jz4760_pwm7), + INGENIC_PIN_FUNCTION("otg", jz4760_otg), }; static const struct ingenic_chip_info jz4760_chip_info = { @@ -1417,37 +1423,37 @@ static const char *jz4770_pwm7_groups[] = { "pwm7", }; static const char *jz4770_mac_groups[] = { "mac-rmii", "mac-mii", }; static const struct function_desc jz4770_functions[] = { - { "uart0", jz4770_uart0_groups, ARRAY_SIZE(jz4770_uart0_groups), }, - { "uart1", jz4770_uart1_groups, ARRAY_SIZE(jz4770_uart1_groups), }, - { "uart2", jz4770_uart2_groups, ARRAY_SIZE(jz4770_uart2_groups), }, - { "uart3", jz4770_uart3_groups, ARRAY_SIZE(jz4770_uart3_groups), }, - { "ssi0", jz4770_ssi0_groups, ARRAY_SIZE(jz4770_ssi0_groups), }, - { "ssi1", jz4770_ssi1_groups, ARRAY_SIZE(jz4770_ssi1_groups), }, - { "mmc0", jz4770_mmc0_groups, ARRAY_SIZE(jz4770_mmc0_groups), }, - { "mmc1", jz4770_mmc1_groups, ARRAY_SIZE(jz4770_mmc1_groups), }, - { "mmc2", jz4770_mmc2_groups, ARRAY_SIZE(jz4770_mmc2_groups), }, - { "nemc", jz4770_nemc_groups, ARRAY_SIZE(jz4770_nemc_groups), }, - { "nemc-cs1", jz4770_cs1_groups, ARRAY_SIZE(jz4770_cs1_groups), }, - { "nemc-cs2", jz4770_cs2_groups, ARRAY_SIZE(jz4770_cs2_groups), }, - { "nemc-cs3", jz4770_cs3_groups, ARRAY_SIZE(jz4770_cs3_groups), }, - { "nemc-cs4", jz4770_cs4_groups, ARRAY_SIZE(jz4770_cs4_groups), }, - { "nemc-cs5", jz4770_cs5_groups, ARRAY_SIZE(jz4770_cs5_groups), }, - { "nemc-cs6", jz4770_cs6_groups, ARRAY_SIZE(jz4770_cs6_groups), }, - { "i2c0", jz4770_i2c0_groups, ARRAY_SIZE(jz4770_i2c0_groups), }, - { "i2c1", jz4770_i2c1_groups, ARRAY_SIZE(jz4770_i2c1_groups), }, - { "i2c2", jz4770_i2c2_groups, ARRAY_SIZE(jz4770_i2c2_groups), }, - { "cim", jz4770_cim_groups, ARRAY_SIZE(jz4770_cim_groups), }, - { "lcd", jz4770_lcd_groups, ARRAY_SIZE(jz4770_lcd_groups), }, - { "pwm0", jz4770_pwm0_groups, ARRAY_SIZE(jz4770_pwm0_groups), }, - { "pwm1", jz4770_pwm1_groups, ARRAY_SIZE(jz4770_pwm1_groups), }, - { "pwm2", jz4770_pwm2_groups, ARRAY_SIZE(jz4770_pwm2_groups), }, - { "pwm3", jz4770_pwm3_groups, ARRAY_SIZE(jz4770_pwm3_groups), }, - { "pwm4", jz4770_pwm4_groups, ARRAY_SIZE(jz4770_pwm4_groups), }, - { "pwm5", jz4770_pwm5_groups, ARRAY_SIZE(jz4770_pwm5_groups), }, - { "pwm6", jz4770_pwm6_groups, ARRAY_SIZE(jz4770_pwm6_groups), }, - { "pwm7", jz4770_pwm7_groups, ARRAY_SIZE(jz4770_pwm7_groups), }, - { "mac", jz4770_mac_groups, ARRAY_SIZE(jz4770_mac_groups), }, - { "otg", jz4760_otg_groups, ARRAY_SIZE(jz4760_otg_groups), }, + INGENIC_PIN_FUNCTION("uart0", jz4770_uart0), + INGENIC_PIN_FUNCTION("uart1", jz4770_uart1), + INGENIC_PIN_FUNCTION("uart2", jz4770_uart2), + INGENIC_PIN_FUNCTION("uart3", jz4770_uart3), + INGENIC_PIN_FUNCTION("ssi0", jz4770_ssi0), + INGENIC_PIN_FUNCTION("ssi1", jz4770_ssi1), + INGENIC_PIN_FUNCTION("mmc0", jz4770_mmc0), + INGENIC_PIN_FUNCTION("mmc1", jz4770_mmc1), + INGENIC_PIN_FUNCTION("mmc2", jz4770_mmc2), + INGENIC_PIN_FUNCTION("nemc", jz4770_nemc), + INGENIC_PIN_FUNCTION("nemc-cs1", jz4770_cs1), + INGENIC_PIN_FUNCTION("nemc-cs2", jz4770_cs2), + INGENIC_PIN_FUNCTION("nemc-cs3", jz4770_cs3), + INGENIC_PIN_FUNCTION("nemc-cs4", jz4770_cs4), + INGENIC_PIN_FUNCTION("nemc-cs5", jz4770_cs5), + INGENIC_PIN_FUNCTION("nemc-cs6", jz4770_cs6), + INGENIC_PIN_FUNCTION("i2c0", jz4770_i2c0), + INGENIC_PIN_FUNCTION("i2c1", jz4770_i2c1), + INGENIC_PIN_FUNCTION("i2c2", jz4770_i2c2), + INGENIC_PIN_FUNCTION("cim", jz4770_cim), + INGENIC_PIN_FUNCTION("lcd", jz4770_lcd), + INGENIC_PIN_FUNCTION("pwm0", jz4770_pwm0), + INGENIC_PIN_FUNCTION("pwm1", jz4770_pwm1), + INGENIC_PIN_FUNCTION("pwm2", jz4770_pwm2), + INGENIC_PIN_FUNCTION("pwm3", jz4770_pwm3), + INGENIC_PIN_FUNCTION("pwm4", jz4770_pwm4), + INGENIC_PIN_FUNCTION("pwm5", jz4770_pwm5), + INGENIC_PIN_FUNCTION("pwm6", jz4770_pwm6), + INGENIC_PIN_FUNCTION("pwm7", jz4770_pwm7), + INGENIC_PIN_FUNCTION("mac", jz4770_mac), + INGENIC_PIN_FUNCTION("otg", jz4760_otg), }; static const struct ingenic_chip_info jz4770_chip_info = { @@ -1696,31 +1702,31 @@ static const char *jz4775_mac_groups[] = { static const char *jz4775_otg_groups[] = { "otg-vbus", }; static const struct function_desc jz4775_functions[] = { - { "uart0", jz4775_uart0_groups, ARRAY_SIZE(jz4775_uart0_groups), }, - { "uart1", jz4775_uart1_groups, ARRAY_SIZE(jz4775_uart1_groups), }, - { "uart2", jz4775_uart2_groups, ARRAY_SIZE(jz4775_uart2_groups), }, - { "uart3", jz4775_uart3_groups, ARRAY_SIZE(jz4775_uart3_groups), }, - { "ssi", jz4775_ssi_groups, ARRAY_SIZE(jz4775_ssi_groups), }, - { "mmc0", jz4775_mmc0_groups, ARRAY_SIZE(jz4775_mmc0_groups), }, - { "mmc1", jz4775_mmc1_groups, ARRAY_SIZE(jz4775_mmc1_groups), }, - { "mmc2", jz4775_mmc2_groups, ARRAY_SIZE(jz4775_mmc2_groups), }, - { "nemc", jz4775_nemc_groups, ARRAY_SIZE(jz4775_nemc_groups), }, - { "nemc-cs1", jz4775_cs1_groups, ARRAY_SIZE(jz4775_cs1_groups), }, - { "nemc-cs2", jz4775_cs2_groups, ARRAY_SIZE(jz4775_cs2_groups), }, - { "nemc-cs3", jz4775_cs3_groups, ARRAY_SIZE(jz4775_cs3_groups), }, - { "i2c0", jz4775_i2c0_groups, ARRAY_SIZE(jz4775_i2c0_groups), }, - { "i2c1", jz4775_i2c1_groups, ARRAY_SIZE(jz4775_i2c1_groups), }, - { "i2c2", jz4775_i2c2_groups, ARRAY_SIZE(jz4775_i2c2_groups), }, - { "i2s", jz4775_i2s_groups, ARRAY_SIZE(jz4775_i2s_groups), }, - { "dmic", jz4775_dmic_groups, ARRAY_SIZE(jz4775_dmic_groups), }, - { "cim", jz4775_cim_groups, ARRAY_SIZE(jz4775_cim_groups), }, - { "lcd", jz4775_lcd_groups, ARRAY_SIZE(jz4775_lcd_groups), }, - { "pwm0", jz4775_pwm0_groups, ARRAY_SIZE(jz4775_pwm0_groups), }, - { "pwm1", jz4775_pwm1_groups, ARRAY_SIZE(jz4775_pwm1_groups), }, - { "pwm2", jz4775_pwm2_groups, ARRAY_SIZE(jz4775_pwm2_groups), }, - { "pwm3", jz4775_pwm3_groups, ARRAY_SIZE(jz4775_pwm3_groups), }, - { "mac", jz4775_mac_groups, ARRAY_SIZE(jz4775_mac_groups), }, - { "otg", jz4775_otg_groups, ARRAY_SIZE(jz4775_otg_groups), }, + INGENIC_PIN_FUNCTION("uart0", jz4775_uart0), + INGENIC_PIN_FUNCTION("uart1", jz4775_uart1), + INGENIC_PIN_FUNCTION("uart2", jz4775_uart2), + INGENIC_PIN_FUNCTION("uart3", jz4775_uart3), + INGENIC_PIN_FUNCTION("ssi", jz4775_ssi), + INGENIC_PIN_FUNCTION("mmc0", jz4775_mmc0), + INGENIC_PIN_FUNCTION("mmc1", jz4775_mmc1), + INGENIC_PIN_FUNCTION("mmc2", jz4775_mmc2), + INGENIC_PIN_FUNCTION("nemc", jz4775_nemc), + INGENIC_PIN_FUNCTION("nemc-cs1", jz4775_cs1), + INGENIC_PIN_FUNCTION("nemc-cs2", jz4775_cs2), + INGENIC_PIN_FUNCTION("nemc-cs3", jz4775_cs3), + INGENIC_PIN_FUNCTION("i2c0", jz4775_i2c0), + INGENIC_PIN_FUNCTION("i2c1", jz4775_i2c1), + INGENIC_PIN_FUNCTION("i2c2", jz4775_i2c2), + INGENIC_PIN_FUNCTION("i2s", jz4775_i2s), + INGENIC_PIN_FUNCTION("dmic", jz4775_dmic), + INGENIC_PIN_FUNCTION("cim", jz4775_cim), + INGENIC_PIN_FUNCTION("lcd", jz4775_lcd), + INGENIC_PIN_FUNCTION("pwm0", jz4775_pwm0), + INGENIC_PIN_FUNCTION("pwm1", jz4775_pwm1), + INGENIC_PIN_FUNCTION("pwm2", jz4775_pwm2), + INGENIC_PIN_FUNCTION("pwm3", jz4775_pwm3), + INGENIC_PIN_FUNCTION("mac", jz4775_mac), + INGENIC_PIN_FUNCTION("otg", jz4775_otg), }; static const struct ingenic_chip_info jz4775_chip_info = { @@ -1949,42 +1955,41 @@ static const char *jz4780_cim_groups[] = { "cim-data", }; static const char *jz4780_hdmi_ddc_groups[] = { "hdmi-ddc", }; static const struct function_desc jz4780_functions[] = { - { "uart0", jz4770_uart0_groups, ARRAY_SIZE(jz4770_uart0_groups), }, - { "uart1", jz4770_uart1_groups, ARRAY_SIZE(jz4770_uart1_groups), }, - { "uart2", jz4780_uart2_groups, ARRAY_SIZE(jz4780_uart2_groups), }, - { "uart3", jz4770_uart3_groups, ARRAY_SIZE(jz4770_uart3_groups), }, - { "uart4", jz4780_uart4_groups, ARRAY_SIZE(jz4780_uart4_groups), }, - { "ssi0", jz4780_ssi0_groups, ARRAY_SIZE(jz4780_ssi0_groups), }, - { "ssi1", jz4780_ssi1_groups, ARRAY_SIZE(jz4780_ssi1_groups), }, - { "mmc0", jz4780_mmc0_groups, ARRAY_SIZE(jz4780_mmc0_groups), }, - { "mmc1", jz4780_mmc1_groups, ARRAY_SIZE(jz4780_mmc1_groups), }, - { "mmc2", jz4780_mmc2_groups, ARRAY_SIZE(jz4780_mmc2_groups), }, - { "nemc", jz4780_nemc_groups, ARRAY_SIZE(jz4780_nemc_groups), }, - { "nemc-cs1", jz4770_cs1_groups, ARRAY_SIZE(jz4770_cs1_groups), }, - { "nemc-cs2", jz4770_cs2_groups, ARRAY_SIZE(jz4770_cs2_groups), }, - { "nemc-cs3", jz4770_cs3_groups, ARRAY_SIZE(jz4770_cs3_groups), }, - { "nemc-cs4", jz4770_cs4_groups, ARRAY_SIZE(jz4770_cs4_groups), }, - { "nemc-cs5", jz4770_cs5_groups, ARRAY_SIZE(jz4770_cs5_groups), }, - { "nemc-cs6", jz4770_cs6_groups, ARRAY_SIZE(jz4770_cs6_groups), }, - { "i2c0", jz4770_i2c0_groups, ARRAY_SIZE(jz4770_i2c0_groups), }, - { "i2c1", jz4770_i2c1_groups, ARRAY_SIZE(jz4770_i2c1_groups), }, - { "i2c2", jz4770_i2c2_groups, ARRAY_SIZE(jz4770_i2c2_groups), }, - { "i2c3", jz4780_i2c3_groups, ARRAY_SIZE(jz4780_i2c3_groups), }, - { "i2c4", jz4780_i2c4_groups, ARRAY_SIZE(jz4780_i2c4_groups), }, - { "i2s", jz4780_i2s_groups, ARRAY_SIZE(jz4780_i2s_groups), }, - { "dmic", jz4780_dmic_groups, ARRAY_SIZE(jz4780_dmic_groups), }, - { "cim", jz4780_cim_groups, ARRAY_SIZE(jz4780_cim_groups), }, - { "lcd", jz4770_lcd_groups, ARRAY_SIZE(jz4770_lcd_groups), }, - { "pwm0", jz4770_pwm0_groups, ARRAY_SIZE(jz4770_pwm0_groups), }, - { "pwm1", jz4770_pwm1_groups, ARRAY_SIZE(jz4770_pwm1_groups), }, - { "pwm2", jz4770_pwm2_groups, ARRAY_SIZE(jz4770_pwm2_groups), }, - { "pwm3", jz4770_pwm3_groups, ARRAY_SIZE(jz4770_pwm3_groups), }, - { "pwm4", jz4770_pwm4_groups, ARRAY_SIZE(jz4770_pwm4_groups), }, - { "pwm5", jz4770_pwm5_groups, ARRAY_SIZE(jz4770_pwm5_groups), }, - { "pwm6", jz4770_pwm6_groups, ARRAY_SIZE(jz4770_pwm6_groups), }, - { "pwm7", jz4770_pwm7_groups, ARRAY_SIZE(jz4770_pwm7_groups), }, - { "hdmi-ddc", jz4780_hdmi_ddc_groups, - ARRAY_SIZE(jz4780_hdmi_ddc_groups), }, + INGENIC_PIN_FUNCTION("uart0", jz4770_uart0), + INGENIC_PIN_FUNCTION("uart1", jz4770_uart1), + INGENIC_PIN_FUNCTION("uart2", jz4780_uart2), + INGENIC_PIN_FUNCTION("uart3", jz4770_uart3), + INGENIC_PIN_FUNCTION("uart4", jz4780_uart4), + INGENIC_PIN_FUNCTION("ssi0", jz4780_ssi0), + INGENIC_PIN_FUNCTION("ssi1", jz4780_ssi1), + INGENIC_PIN_FUNCTION("mmc0", jz4780_mmc0), + INGENIC_PIN_FUNCTION("mmc1", jz4780_mmc1), + INGENIC_PIN_FUNCTION("mmc2", jz4780_mmc2), + INGENIC_PIN_FUNCTION("nemc", jz4780_nemc), + INGENIC_PIN_FUNCTION("nemc-cs1", jz4770_cs1), + INGENIC_PIN_FUNCTION("nemc-cs2", jz4770_cs2), + INGENIC_PIN_FUNCTION("nemc-cs3", jz4770_cs3), + INGENIC_PIN_FUNCTION("nemc-cs4", jz4770_cs4), + INGENIC_PIN_FUNCTION("nemc-cs5", jz4770_cs5), + INGENIC_PIN_FUNCTION("nemc-cs6", jz4770_cs6), + INGENIC_PIN_FUNCTION("i2c0", jz4770_i2c0), + INGENIC_PIN_FUNCTION("i2c1", jz4770_i2c1), + INGENIC_PIN_FUNCTION("i2c2", jz4770_i2c2), + INGENIC_PIN_FUNCTION("i2c3", jz4780_i2c3), + INGENIC_PIN_FUNCTION("i2c4", jz4780_i2c4), + INGENIC_PIN_FUNCTION("i2s", jz4780_i2s), + INGENIC_PIN_FUNCTION("dmic", jz4780_dmic), + INGENIC_PIN_FUNCTION("cim", jz4780_cim), + INGENIC_PIN_FUNCTION("lcd", jz4770_lcd), + INGENIC_PIN_FUNCTION("pwm0", jz4770_pwm0), + INGENIC_PIN_FUNCTION("pwm1", jz4770_pwm1), + INGENIC_PIN_FUNCTION("pwm2", jz4770_pwm2), + INGENIC_PIN_FUNCTION("pwm3", jz4770_pwm3), + INGENIC_PIN_FUNCTION("pwm4", jz4770_pwm4), + INGENIC_PIN_FUNCTION("pwm5", jz4770_pwm5), + INGENIC_PIN_FUNCTION("pwm6", jz4770_pwm6), + INGENIC_PIN_FUNCTION("pwm7", jz4770_pwm7), + INGENIC_PIN_FUNCTION("hdmi-ddc", jz4780_hdmi_ddc), }; static const struct ingenic_chip_info jz4780_chip_info = { @@ -2185,29 +2190,29 @@ static const char *x1000_pwm4_groups[] = { "pwm4", }; static const char *x1000_mac_groups[] = { "mac", }; static const struct function_desc x1000_functions[] = { - { "uart0", x1000_uart0_groups, ARRAY_SIZE(x1000_uart0_groups), }, - { "uart1", x1000_uart1_groups, ARRAY_SIZE(x1000_uart1_groups), }, - { "uart2", x1000_uart2_groups, ARRAY_SIZE(x1000_uart2_groups), }, - { "sfc", x1000_sfc_groups, ARRAY_SIZE(x1000_sfc_groups), }, - { "ssi", x1000_ssi_groups, ARRAY_SIZE(x1000_ssi_groups), }, - { "mmc0", x1000_mmc0_groups, ARRAY_SIZE(x1000_mmc0_groups), }, - { "mmc1", x1000_mmc1_groups, ARRAY_SIZE(x1000_mmc1_groups), }, - { "emc", x1000_emc_groups, ARRAY_SIZE(x1000_emc_groups), }, - { "emc-cs1", x1000_cs1_groups, ARRAY_SIZE(x1000_cs1_groups), }, - { "emc-cs2", x1000_cs2_groups, ARRAY_SIZE(x1000_cs2_groups), }, - { "i2c0", x1000_i2c0_groups, ARRAY_SIZE(x1000_i2c0_groups), }, - { "i2c1", x1000_i2c1_groups, ARRAY_SIZE(x1000_i2c1_groups), }, - { "i2c2", x1000_i2c2_groups, ARRAY_SIZE(x1000_i2c2_groups), }, - { "i2s", x1000_i2s_groups, ARRAY_SIZE(x1000_i2s_groups), }, - { "dmic", x1000_dmic_groups, ARRAY_SIZE(x1000_dmic_groups), }, - { "cim", x1000_cim_groups, ARRAY_SIZE(x1000_cim_groups), }, - { "lcd", x1000_lcd_groups, ARRAY_SIZE(x1000_lcd_groups), }, - { "pwm0", x1000_pwm0_groups, ARRAY_SIZE(x1000_pwm0_groups), }, - { "pwm1", x1000_pwm1_groups, ARRAY_SIZE(x1000_pwm1_groups), }, - { "pwm2", x1000_pwm2_groups, ARRAY_SIZE(x1000_pwm2_groups), }, - { "pwm3", x1000_pwm3_groups, ARRAY_SIZE(x1000_pwm3_groups), }, - { "pwm4", x1000_pwm4_groups, ARRAY_SIZE(x1000_pwm4_groups), }, - { "mac", x1000_mac_groups, ARRAY_SIZE(x1000_mac_groups), }, + INGENIC_PIN_FUNCTION("uart0", x1000_uart0), + INGENIC_PIN_FUNCTION("uart1", x1000_uart1), + INGENIC_PIN_FUNCTION("uart2", x1000_uart2), + INGENIC_PIN_FUNCTION("sfc", x1000_sfc), + INGENIC_PIN_FUNCTION("ssi", x1000_ssi), + INGENIC_PIN_FUNCTION("mmc0", x1000_mmc0), + INGENIC_PIN_FUNCTION("mmc1", x1000_mmc1), + INGENIC_PIN_FUNCTION("emc", x1000_emc), + INGENIC_PIN_FUNCTION("emc-cs1", x1000_cs1), + INGENIC_PIN_FUNCTION("emc-cs2", x1000_cs2), + INGENIC_PIN_FUNCTION("i2c0", x1000_i2c0), + INGENIC_PIN_FUNCTION("i2c1", x1000_i2c1), + INGENIC_PIN_FUNCTION("i2c2", x1000_i2c2), + INGENIC_PIN_FUNCTION("i2s", x1000_i2s), + INGENIC_PIN_FUNCTION("dmic", x1000_dmic), + INGENIC_PIN_FUNCTION("cim", x1000_cim), + INGENIC_PIN_FUNCTION("lcd", x1000_lcd), + INGENIC_PIN_FUNCTION("pwm0", x1000_pwm0), + INGENIC_PIN_FUNCTION("pwm1", x1000_pwm1), + INGENIC_PIN_FUNCTION("pwm2", x1000_pwm2), + INGENIC_PIN_FUNCTION("pwm3", x1000_pwm3), + INGENIC_PIN_FUNCTION("pwm4", x1000_pwm4), + INGENIC_PIN_FUNCTION("mac", x1000_mac), }; static const struct regmap_range x1000_access_ranges[] = { @@ -2315,22 +2320,22 @@ static const char *x1500_pwm3_groups[] = { "pwm3", }; static const char *x1500_pwm4_groups[] = { "pwm4", }; static const struct function_desc x1500_functions[] = { - { "uart0", x1500_uart0_groups, ARRAY_SIZE(x1500_uart0_groups), }, - { "uart1", x1500_uart1_groups, ARRAY_SIZE(x1500_uart1_groups), }, - { "uart2", x1500_uart2_groups, ARRAY_SIZE(x1500_uart2_groups), }, - { "sfc", x1000_sfc_groups, ARRAY_SIZE(x1000_sfc_groups), }, - { "mmc", x1500_mmc_groups, ARRAY_SIZE(x1500_mmc_groups), }, - { "i2c0", x1500_i2c0_groups, ARRAY_SIZE(x1500_i2c0_groups), }, - { "i2c1", x1500_i2c1_groups, ARRAY_SIZE(x1500_i2c1_groups), }, - { "i2c2", x1500_i2c2_groups, ARRAY_SIZE(x1500_i2c2_groups), }, - { "i2s", x1500_i2s_groups, ARRAY_SIZE(x1500_i2s_groups), }, - { "dmic", x1500_dmic_groups, ARRAY_SIZE(x1500_dmic_groups), }, - { "cim", x1500_cim_groups, ARRAY_SIZE(x1500_cim_groups), }, - { "pwm0", x1500_pwm0_groups, ARRAY_SIZE(x1500_pwm0_groups), }, - { "pwm1", x1500_pwm1_groups, ARRAY_SIZE(x1500_pwm1_groups), }, - { "pwm2", x1500_pwm2_groups, ARRAY_SIZE(x1500_pwm2_groups), }, - { "pwm3", x1500_pwm3_groups, ARRAY_SIZE(x1500_pwm3_groups), }, - { "pwm4", x1500_pwm4_groups, ARRAY_SIZE(x1500_pwm4_groups), }, + INGENIC_PIN_FUNCTION("uart0", x1500_uart0), + INGENIC_PIN_FUNCTION("uart1", x1500_uart1), + INGENIC_PIN_FUNCTION("uart2", x1500_uart2), + INGENIC_PIN_FUNCTION("sfc", x1000_sfc), + INGENIC_PIN_FUNCTION("mmc", x1500_mmc), + INGENIC_PIN_FUNCTION("i2c0", x1500_i2c0), + INGENIC_PIN_FUNCTION("i2c1", x1500_i2c1), + INGENIC_PIN_FUNCTION("i2c2", x1500_i2c2), + INGENIC_PIN_FUNCTION("i2s", x1500_i2s), + INGENIC_PIN_FUNCTION("dmic", x1500_dmic), + INGENIC_PIN_FUNCTION("cim", x1500_cim), + INGENIC_PIN_FUNCTION("pwm0", x1500_pwm0), + INGENIC_PIN_FUNCTION("pwm1", x1500_pwm1), + INGENIC_PIN_FUNCTION("pwm2", x1500_pwm2), + INGENIC_PIN_FUNCTION("pwm3", x1500_pwm3), + INGENIC_PIN_FUNCTION("pwm4", x1500_pwm4), }; static const struct ingenic_chip_info x1500_chip_info = { @@ -2526,28 +2531,28 @@ static const char *x1830_pwm7_groups[] = { "pwm7-c-18", "pwm7-c-28", }; static const char *x1830_mac_groups[] = { "mac", }; static const struct function_desc x1830_functions[] = { - { "uart0", x1830_uart0_groups, ARRAY_SIZE(x1830_uart0_groups), }, - { "uart1", x1830_uart1_groups, ARRAY_SIZE(x1830_uart1_groups), }, - { "sfc", x1830_sfc_groups, ARRAY_SIZE(x1830_sfc_groups), }, - { "ssi0", x1830_ssi0_groups, ARRAY_SIZE(x1830_ssi0_groups), }, - { "ssi1", x1830_ssi1_groups, ARRAY_SIZE(x1830_ssi1_groups), }, - { "mmc0", x1830_mmc0_groups, ARRAY_SIZE(x1830_mmc0_groups), }, - { "mmc1", x1830_mmc1_groups, ARRAY_SIZE(x1830_mmc1_groups), }, - { "i2c0", x1830_i2c0_groups, ARRAY_SIZE(x1830_i2c0_groups), }, - { "i2c1", x1830_i2c1_groups, ARRAY_SIZE(x1830_i2c1_groups), }, - { "i2c2", x1830_i2c2_groups, ARRAY_SIZE(x1830_i2c2_groups), }, - { "i2s", x1830_i2s_groups, ARRAY_SIZE(x1830_i2s_groups), }, - { "dmic", x1830_dmic_groups, ARRAY_SIZE(x1830_dmic_groups), }, - { "lcd", x1830_lcd_groups, ARRAY_SIZE(x1830_lcd_groups), }, - { "pwm0", x1830_pwm0_groups, ARRAY_SIZE(x1830_pwm0_groups), }, - { "pwm1", x1830_pwm1_groups, ARRAY_SIZE(x1830_pwm1_groups), }, - { "pwm2", x1830_pwm2_groups, ARRAY_SIZE(x1830_pwm2_groups), }, - { "pwm3", x1830_pwm3_groups, ARRAY_SIZE(x1830_pwm3_groups), }, - { "pwm4", x1830_pwm4_groups, ARRAY_SIZE(x1830_pwm4_groups), }, - { "pwm5", x1830_pwm5_groups, ARRAY_SIZE(x1830_pwm4_groups), }, - { "pwm6", x1830_pwm6_groups, ARRAY_SIZE(x1830_pwm4_groups), }, - { "pwm7", x1830_pwm7_groups, ARRAY_SIZE(x1830_pwm4_groups), }, - { "mac", x1830_mac_groups, ARRAY_SIZE(x1830_mac_groups), }, + INGENIC_PIN_FUNCTION("uart0", x1830_uart0), + INGENIC_PIN_FUNCTION("uart1", x1830_uart1), + INGENIC_PIN_FUNCTION("sfc", x1830_sfc), + INGENIC_PIN_FUNCTION("ssi0", x1830_ssi0), + INGENIC_PIN_FUNCTION("ssi1", x1830_ssi1), + INGENIC_PIN_FUNCTION("mmc0", x1830_mmc0), + INGENIC_PIN_FUNCTION("mmc1", x1830_mmc1), + INGENIC_PIN_FUNCTION("i2c0", x1830_i2c0), + INGENIC_PIN_FUNCTION("i2c1", x1830_i2c1), + INGENIC_PIN_FUNCTION("i2c2", x1830_i2c2), + INGENIC_PIN_FUNCTION("i2s", x1830_i2s), + INGENIC_PIN_FUNCTION("dmic", x1830_dmic), + INGENIC_PIN_FUNCTION("lcd", x1830_lcd), + INGENIC_PIN_FUNCTION("pwm0", x1830_pwm0), + INGENIC_PIN_FUNCTION("pwm1", x1830_pwm1), + INGENIC_PIN_FUNCTION("pwm2", x1830_pwm2), + INGENIC_PIN_FUNCTION("pwm3", x1830_pwm3), + INGENIC_PIN_FUNCTION("pwm4", x1830_pwm4), + INGENIC_PIN_FUNCTION("pwm5", x1830_pwm5), + INGENIC_PIN_FUNCTION("pwm6", x1830_pwm6), + INGENIC_PIN_FUNCTION("pwm7", x1830_pwm7), + INGENIC_PIN_FUNCTION("mac", x1830_mac), }; static const struct regmap_range x1830_access_ranges[] = { @@ -2972,56 +2977,56 @@ static const char *x2000_mac1_groups[] = { "mac1-rmii", "mac1-rgmii", }; static const char *x2000_otg_groups[] = { "otg-vbus", }; static const struct function_desc x2000_functions[] = { - { "uart0", x2000_uart0_groups, ARRAY_SIZE(x2000_uart0_groups), }, - { "uart1", x2000_uart1_groups, ARRAY_SIZE(x2000_uart1_groups), }, - { "uart2", x2000_uart2_groups, ARRAY_SIZE(x2000_uart2_groups), }, - { "uart3", x2000_uart3_groups, ARRAY_SIZE(x2000_uart3_groups), }, - { "uart4", x2000_uart4_groups, ARRAY_SIZE(x2000_uart4_groups), }, - { "uart5", x2000_uart5_groups, ARRAY_SIZE(x2000_uart5_groups), }, - { "uart6", x2000_uart6_groups, ARRAY_SIZE(x2000_uart6_groups), }, - { "uart7", x2000_uart7_groups, ARRAY_SIZE(x2000_uart7_groups), }, - { "uart8", x2000_uart8_groups, ARRAY_SIZE(x2000_uart8_groups), }, - { "uart9", x2000_uart9_groups, ARRAY_SIZE(x2000_uart9_groups), }, - { "sfc", x2000_sfc_groups, ARRAY_SIZE(x2000_sfc_groups), }, - { "ssi0", x2000_ssi0_groups, ARRAY_SIZE(x2000_ssi0_groups), }, - { "ssi1", x2000_ssi1_groups, ARRAY_SIZE(x2000_ssi1_groups), }, - { "mmc0", x2000_mmc0_groups, ARRAY_SIZE(x2000_mmc0_groups), }, - { "mmc1", x2000_mmc1_groups, ARRAY_SIZE(x2000_mmc1_groups), }, - { "mmc2", x2000_mmc2_groups, ARRAY_SIZE(x2000_mmc2_groups), }, - { "emc", x2000_emc_groups, ARRAY_SIZE(x2000_emc_groups), }, - { "emc-cs1", x2000_cs1_groups, ARRAY_SIZE(x2000_cs1_groups), }, - { "emc-cs2", x2000_cs2_groups, ARRAY_SIZE(x2000_cs2_groups), }, - { "i2c0", x2000_i2c0_groups, ARRAY_SIZE(x2000_i2c0_groups), }, - { "i2c1", x2000_i2c1_groups, ARRAY_SIZE(x2000_i2c1_groups), }, - { "i2c2", x2000_i2c2_groups, ARRAY_SIZE(x2000_i2c2_groups), }, - { "i2c3", x2000_i2c3_groups, ARRAY_SIZE(x2000_i2c3_groups), }, - { "i2c4", x2000_i2c4_groups, ARRAY_SIZE(x2000_i2c4_groups), }, - { "i2c5", x2000_i2c5_groups, ARRAY_SIZE(x2000_i2c5_groups), }, - { "i2s1", x2000_i2s1_groups, ARRAY_SIZE(x2000_i2s1_groups), }, - { "i2s2", x2000_i2s2_groups, ARRAY_SIZE(x2000_i2s2_groups), }, - { "i2s3", x2000_i2s3_groups, ARRAY_SIZE(x2000_i2s3_groups), }, - { "dmic", x2000_dmic_groups, ARRAY_SIZE(x2000_dmic_groups), }, - { "cim", x2000_cim_groups, ARRAY_SIZE(x2000_cim_groups), }, - { "lcd", x2000_lcd_groups, ARRAY_SIZE(x2000_lcd_groups), }, - { "pwm0", x2000_pwm0_groups, ARRAY_SIZE(x2000_pwm0_groups), }, - { "pwm1", x2000_pwm1_groups, ARRAY_SIZE(x2000_pwm1_groups), }, - { "pwm2", x2000_pwm2_groups, ARRAY_SIZE(x2000_pwm2_groups), }, - { "pwm3", x2000_pwm3_groups, ARRAY_SIZE(x2000_pwm3_groups), }, - { "pwm4", x2000_pwm4_groups, ARRAY_SIZE(x2000_pwm4_groups), }, - { "pwm5", x2000_pwm5_groups, ARRAY_SIZE(x2000_pwm5_groups), }, - { "pwm6", x2000_pwm6_groups, ARRAY_SIZE(x2000_pwm6_groups), }, - { "pwm7", x2000_pwm7_groups, ARRAY_SIZE(x2000_pwm7_groups), }, - { "pwm8", x2000_pwm8_groups, ARRAY_SIZE(x2000_pwm8_groups), }, - { "pwm9", x2000_pwm9_groups, ARRAY_SIZE(x2000_pwm9_groups), }, - { "pwm10", x2000_pwm10_groups, ARRAY_SIZE(x2000_pwm10_groups), }, - { "pwm11", x2000_pwm11_groups, ARRAY_SIZE(x2000_pwm11_groups), }, - { "pwm12", x2000_pwm12_groups, ARRAY_SIZE(x2000_pwm12_groups), }, - { "pwm13", x2000_pwm13_groups, ARRAY_SIZE(x2000_pwm13_groups), }, - { "pwm14", x2000_pwm14_groups, ARRAY_SIZE(x2000_pwm14_groups), }, - { "pwm15", x2000_pwm15_groups, ARRAY_SIZE(x2000_pwm15_groups), }, - { "mac0", x2000_mac0_groups, ARRAY_SIZE(x2000_mac0_groups), }, - { "mac1", x2000_mac1_groups, ARRAY_SIZE(x2000_mac1_groups), }, - { "otg", x2000_otg_groups, ARRAY_SIZE(x2000_otg_groups), }, + INGENIC_PIN_FUNCTION("uart0", x2000_uart0), + INGENIC_PIN_FUNCTION("uart1", x2000_uart1), + INGENIC_PIN_FUNCTION("uart2", x2000_uart2), + INGENIC_PIN_FUNCTION("uart3", x2000_uart3), + INGENIC_PIN_FUNCTION("uart4", x2000_uart4), + INGENIC_PIN_FUNCTION("uart5", x2000_uart5), + INGENIC_PIN_FUNCTION("uart6", x2000_uart6), + INGENIC_PIN_FUNCTION("uart7", x2000_uart7), + INGENIC_PIN_FUNCTION("uart8", x2000_uart8), + INGENIC_PIN_FUNCTION("uart9", x2000_uart9), + INGENIC_PIN_FUNCTION("sfc", x2000_sfc), + INGENIC_PIN_FUNCTION("ssi0", x2000_ssi0), + INGENIC_PIN_FUNCTION("ssi1", x2000_ssi1), + INGENIC_PIN_FUNCTION("mmc0", x2000_mmc0), + INGENIC_PIN_FUNCTION("mmc1", x2000_mmc1), + INGENIC_PIN_FUNCTION("mmc2", x2000_mmc2), + INGENIC_PIN_FUNCTION("emc", x2000_emc), + INGENIC_PIN_FUNCTION("emc-cs1", x2000_cs1), + INGENIC_PIN_FUNCTION("emc-cs2", x2000_cs2), + INGENIC_PIN_FUNCTION("i2c0", x2000_i2c0), + INGENIC_PIN_FUNCTION("i2c1", x2000_i2c1), + INGENIC_PIN_FUNCTION("i2c2", x2000_i2c2), + INGENIC_PIN_FUNCTION("i2c3", x2000_i2c3), + INGENIC_PIN_FUNCTION("i2c4", x2000_i2c4), + INGENIC_PIN_FUNCTION("i2c5", x2000_i2c5), + INGENIC_PIN_FUNCTION("i2s1", x2000_i2s1), + INGENIC_PIN_FUNCTION("i2s2", x2000_i2s2), + INGENIC_PIN_FUNCTION("i2s3", x2000_i2s3), + INGENIC_PIN_FUNCTION("dmic", x2000_dmic), + INGENIC_PIN_FUNCTION("cim", x2000_cim), + INGENIC_PIN_FUNCTION("lcd", x2000_lcd), + INGENIC_PIN_FUNCTION("pwm0", x2000_pwm0), + INGENIC_PIN_FUNCTION("pwm1", x2000_pwm1), + INGENIC_PIN_FUNCTION("pwm2", x2000_pwm2), + INGENIC_PIN_FUNCTION("pwm3", x2000_pwm3), + INGENIC_PIN_FUNCTION("pwm4", x2000_pwm4), + INGENIC_PIN_FUNCTION("pwm5", x2000_pwm5), + INGENIC_PIN_FUNCTION("pwm6", x2000_pwm6), + INGENIC_PIN_FUNCTION("pwm7", x2000_pwm7), + INGENIC_PIN_FUNCTION("pwm8", x2000_pwm8), + INGENIC_PIN_FUNCTION("pwm9", x2000_pwm9), + INGENIC_PIN_FUNCTION("pwm10", x2000_pwm10), + INGENIC_PIN_FUNCTION("pwm11", x2000_pwm11), + INGENIC_PIN_FUNCTION("pwm12", x2000_pwm12), + INGENIC_PIN_FUNCTION("pwm13", x2000_pwm13), + INGENIC_PIN_FUNCTION("pwm14", x2000_pwm14), + INGENIC_PIN_FUNCTION("pwm15", x2000_pwm15), + INGENIC_PIN_FUNCTION("mac0", x2000_mac0), + INGENIC_PIN_FUNCTION("mac1", x2000_mac1), + INGENIC_PIN_FUNCTION("otg", x2000_otg), }; static const struct regmap_range x2000_access_ranges[] = { @@ -3196,54 +3201,54 @@ static const struct group_desc x2100_groups[] = { static const char *x2100_mac_groups[] = { "mac", }; static const struct function_desc x2100_functions[] = { - { "uart0", x2000_uart0_groups, ARRAY_SIZE(x2000_uart0_groups), }, - { "uart1", x2000_uart1_groups, ARRAY_SIZE(x2000_uart1_groups), }, - { "uart2", x2000_uart2_groups, ARRAY_SIZE(x2000_uart2_groups), }, - { "uart3", x2000_uart3_groups, ARRAY_SIZE(x2000_uart3_groups), }, - { "uart4", x2000_uart4_groups, ARRAY_SIZE(x2000_uart4_groups), }, - { "uart5", x2000_uart5_groups, ARRAY_SIZE(x2000_uart5_groups), }, - { "uart6", x2000_uart6_groups, ARRAY_SIZE(x2000_uart6_groups), }, - { "uart7", x2000_uart7_groups, ARRAY_SIZE(x2000_uart7_groups), }, - { "uart8", x2000_uart8_groups, ARRAY_SIZE(x2000_uart8_groups), }, - { "uart9", x2000_uart9_groups, ARRAY_SIZE(x2000_uart9_groups), }, - { "sfc", x2000_sfc_groups, ARRAY_SIZE(x2000_sfc_groups), }, - { "ssi0", x2000_ssi0_groups, ARRAY_SIZE(x2000_ssi0_groups), }, - { "ssi1", x2000_ssi1_groups, ARRAY_SIZE(x2000_ssi1_groups), }, - { "mmc0", x2000_mmc0_groups, ARRAY_SIZE(x2000_mmc0_groups), }, - { "mmc1", x2000_mmc1_groups, ARRAY_SIZE(x2000_mmc1_groups), }, - { "mmc2", x2000_mmc2_groups, ARRAY_SIZE(x2000_mmc2_groups), }, - { "emc", x2000_emc_groups, ARRAY_SIZE(x2000_emc_groups), }, - { "emc-cs1", x2000_cs1_groups, ARRAY_SIZE(x2000_cs1_groups), }, - { "emc-cs2", x2000_cs2_groups, ARRAY_SIZE(x2000_cs2_groups), }, - { "i2c0", x2000_i2c0_groups, ARRAY_SIZE(x2000_i2c0_groups), }, - { "i2c1", x2000_i2c1_groups, ARRAY_SIZE(x2000_i2c1_groups), }, - { "i2c2", x2000_i2c2_groups, ARRAY_SIZE(x2000_i2c2_groups), }, - { "i2c3", x2000_i2c3_groups, ARRAY_SIZE(x2000_i2c3_groups), }, - { "i2c4", x2000_i2c4_groups, ARRAY_SIZE(x2000_i2c4_groups), }, - { "i2c5", x2000_i2c5_groups, ARRAY_SIZE(x2000_i2c5_groups), }, - { "i2s1", x2000_i2s1_groups, ARRAY_SIZE(x2000_i2s1_groups), }, - { "i2s2", x2000_i2s2_groups, ARRAY_SIZE(x2000_i2s2_groups), }, - { "i2s3", x2000_i2s3_groups, ARRAY_SIZE(x2000_i2s3_groups), }, - { "dmic", x2000_dmic_groups, ARRAY_SIZE(x2000_dmic_groups), }, - { "cim", x2000_cim_groups, ARRAY_SIZE(x2000_cim_groups), }, - { "lcd", x2000_lcd_groups, ARRAY_SIZE(x2000_lcd_groups), }, - { "pwm0", x2000_pwm0_groups, ARRAY_SIZE(x2000_pwm0_groups), }, - { "pwm1", x2000_pwm1_groups, ARRAY_SIZE(x2000_pwm1_groups), }, - { "pwm2", x2000_pwm2_groups, ARRAY_SIZE(x2000_pwm2_groups), }, - { "pwm3", x2000_pwm3_groups, ARRAY_SIZE(x2000_pwm3_groups), }, - { "pwm4", x2000_pwm4_groups, ARRAY_SIZE(x2000_pwm4_groups), }, - { "pwm5", x2000_pwm5_groups, ARRAY_SIZE(x2000_pwm5_groups), }, - { "pwm6", x2000_pwm6_groups, ARRAY_SIZE(x2000_pwm6_groups), }, - { "pwm7", x2000_pwm7_groups, ARRAY_SIZE(x2000_pwm7_groups), }, - { "pwm8", x2000_pwm8_groups, ARRAY_SIZE(x2000_pwm8_groups), }, - { "pwm9", x2000_pwm9_groups, ARRAY_SIZE(x2000_pwm9_groups), }, - { "pwm10", x2000_pwm10_groups, ARRAY_SIZE(x2000_pwm10_groups), }, - { "pwm11", x2000_pwm11_groups, ARRAY_SIZE(x2000_pwm11_groups), }, - { "pwm12", x2000_pwm12_groups, ARRAY_SIZE(x2000_pwm12_groups), }, - { "pwm13", x2000_pwm13_groups, ARRAY_SIZE(x2000_pwm13_groups), }, - { "pwm14", x2000_pwm14_groups, ARRAY_SIZE(x2000_pwm14_groups), }, - { "pwm15", x2000_pwm15_groups, ARRAY_SIZE(x2000_pwm15_groups), }, - { "mac", x2100_mac_groups, ARRAY_SIZE(x2100_mac_groups), }, + INGENIC_PIN_FUNCTION("uart0", x2000_uart0), + INGENIC_PIN_FUNCTION("uart1", x2000_uart1), + INGENIC_PIN_FUNCTION("uart2", x2000_uart2), + INGENIC_PIN_FUNCTION("uart3", x2000_uart3), + INGENIC_PIN_FUNCTION("uart4", x2000_uart4), + INGENIC_PIN_FUNCTION("uart5", x2000_uart5), + INGENIC_PIN_FUNCTION("uart6", x2000_uart6), + INGENIC_PIN_FUNCTION("uart7", x2000_uart7), + INGENIC_PIN_FUNCTION("uart8", x2000_uart8), + INGENIC_PIN_FUNCTION("uart9", x2000_uart9), + INGENIC_PIN_FUNCTION("sfc", x2000_sfc), + INGENIC_PIN_FUNCTION("ssi0", x2000_ssi0), + INGENIC_PIN_FUNCTION("ssi1", x2000_ssi1), + INGENIC_PIN_FUNCTION("mmc0", x2000_mmc0), + INGENIC_PIN_FUNCTION("mmc1", x2000_mmc1), + INGENIC_PIN_FUNCTION("mmc2", x2000_mmc2), + INGENIC_PIN_FUNCTION("emc", x2000_emc), + INGENIC_PIN_FUNCTION("emc-cs1", x2000_cs1), + INGENIC_PIN_FUNCTION("emc-cs2", x2000_cs2), + INGENIC_PIN_FUNCTION("i2c0", x2000_i2c0), + INGENIC_PIN_FUNCTION("i2c1", x2000_i2c1), + INGENIC_PIN_FUNCTION("i2c2", x2000_i2c2), + INGENIC_PIN_FUNCTION("i2c3", x2000_i2c3), + INGENIC_PIN_FUNCTION("i2c4", x2000_i2c4), + INGENIC_PIN_FUNCTION("i2c5", x2000_i2c5), + INGENIC_PIN_FUNCTION("i2s1", x2000_i2s1), + INGENIC_PIN_FUNCTION("i2s2", x2000_i2s2), + INGENIC_PIN_FUNCTION("i2s3", x2000_i2s3), + INGENIC_PIN_FUNCTION("dmic", x2000_dmic), + INGENIC_PIN_FUNCTION("cim", x2000_cim), + INGENIC_PIN_FUNCTION("lcd", x2000_lcd), + INGENIC_PIN_FUNCTION("pwm0", x2000_pwm0), + INGENIC_PIN_FUNCTION("pwm1", x2000_pwm1), + INGENIC_PIN_FUNCTION("pwm2", x2000_pwm2), + INGENIC_PIN_FUNCTION("pwm3", x2000_pwm3), + INGENIC_PIN_FUNCTION("pwm4", x2000_pwm4), + INGENIC_PIN_FUNCTION("pwm5", x2000_pwm5), + INGENIC_PIN_FUNCTION("pwm6", x2000_pwm6), + INGENIC_PIN_FUNCTION("pwm7", x2000_pwm7), + INGENIC_PIN_FUNCTION("pwm8", x2000_pwm8), + INGENIC_PIN_FUNCTION("pwm9", x2000_pwm9), + INGENIC_PIN_FUNCTION("pwm10", x2000_pwm10), + INGENIC_PIN_FUNCTION("pwm11", x2000_pwm11), + INGENIC_PIN_FUNCTION("pwm12", x2000_pwm12), + INGENIC_PIN_FUNCTION("pwm13", x2000_pwm13), + INGENIC_PIN_FUNCTION("pwm14", x2000_pwm14), + INGENIC_PIN_FUNCTION("pwm15", x2000_pwm15), + INGENIC_PIN_FUNCTION("mac", x2100_mac), }; static const struct ingenic_chip_info x2100_chip_info = { @@ -3762,7 +3767,7 @@ static int ingenic_pinmux_set_mux(struct pinctrl_dev *pctldev, return -EINVAL; dev_dbg(pctldev->dev, "enable function %s group %s\n", - func->name, grp->grp.name); + func->func.name, grp->grp.name); mode = (uintptr_t)grp->data; if (mode <= 3) { @@ -4310,14 +4315,14 @@ static int __init ingenic_pinctrl_probe(struct platform_device *pdev) } for (i = 0; i < chip_info->num_functions; i++) { - const struct function_desc *func = &chip_info->functions[i]; + const struct function_desc *function = &chip_info->functions[i]; + const struct pinfunction *func = &function->func; err = pinmux_generic_add_function(jzpc->pctl, func->name, - func->group_names, func->num_group_names, - func->data); + func->groups, func->ngroups, + function->data); if (err < 0) { - dev_err(dev, "Failed to register function %s\n", - func->name); + dev_err(dev, "Failed to register function %s\n", func->name); return err; } } diff --git a/drivers/pinctrl/pinctrl-k210.c b/drivers/pinctrl/pinctrl-k210.c index b6d1ed9ec9a3..2753e14c3e38 100644 --- a/drivers/pinctrl/pinctrl-k210.c +++ b/drivers/pinctrl/pinctrl-k210.c @@ -849,7 +849,6 @@ static int k210_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, unsigned int *num_maps) { unsigned int reserved_maps; - struct device_node *np; int ret; reserved_maps = 0; @@ -861,13 +860,11 @@ static int k210_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, if (ret < 0) goto err; - for_each_available_child_of_node(np_config, np) { + for_each_available_child_of_node_scoped(np_config, np) { ret = k210_pinctrl_dt_subnode_to_map(pctldev, np, map, &reserved_maps, num_maps); - if (ret < 0) { - of_node_put(np); + if (ret < 0) goto err; - } } return 0; diff --git a/drivers/pinctrl/pinctrl-keembay.c b/drivers/pinctrl/pinctrl-keembay.c index b1349ee22799..b693f4787044 100644 --- a/drivers/pinctrl/pinctrl-keembay.c +++ b/drivers/pinctrl/pinctrl-keembay.c @@ -1566,7 +1566,7 @@ static int keembay_add_functions(struct keembay_pinctrl *kpc, unsigned int grp_idx = 0; int j; - group_names = devm_kcalloc(kpc->dev, func->num_group_names, + group_names = devm_kcalloc(kpc->dev, func->func.ngroups, sizeof(*group_names), GFP_KERNEL); if (!group_names) return -ENOMEM; @@ -1576,20 +1576,20 @@ static int keembay_add_functions(struct keembay_pinctrl *kpc, struct keembay_mux_desc *mux; for (mux = pdesc->drv_data; mux->name; mux++) { - if (!strcmp(mux->name, func->name)) + if (!strcmp(mux->name, func->func.name)) group_names[grp_idx++] = pdesc->name; } } - func->group_names = group_names; + func->func.groups = group_names; } /* Add all functions */ for (i = 0; i < kpc->nfuncs; i++) { pinmux_generic_add_function(kpc->pctrl, - functions[i].name, - functions[i].group_names, - functions[i].num_group_names, + functions[i].func.name, + functions[i].func.groups, + functions[i].func.ngroups, functions[i].data); } @@ -1619,17 +1619,17 @@ static int keembay_build_functions(struct keembay_pinctrl *kpc) struct function_desc *fdesc; /* Check if we already have function for this mux */ - for (fdesc = keembay_funcs; fdesc->name; fdesc++) { - if (!strcmp(mux->name, fdesc->name)) { - fdesc->num_group_names++; + for (fdesc = keembay_funcs; fdesc->func.name; fdesc++) { + if (!strcmp(mux->name, fdesc->func.name)) { + fdesc->func.ngroups++; break; } } /* Setup new function for this mux we didn't see before */ - if (!fdesc->name) { - fdesc->name = mux->name; - fdesc->num_group_names = 1; + if (!fdesc->func.name) { + fdesc->func.name = mux->name; + fdesc->func.ngroups = 1; fdesc->data = &mux->mode; kpc->nfuncs++; } diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index 38c3a14c8b58..737d0ae3d0b6 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -696,4 +696,5 @@ int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, } EXPORT_SYMBOL_GPL(mcp23s08_probe_one); +MODULE_DESCRIPTION("MCP23S08 SPI/I2C GPIO driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-mcp23s08_i2c.c b/drivers/pinctrl/pinctrl-mcp23s08_i2c.c index 04e8e7d079f0..94e1add6ddd7 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08_i2c.c +++ b/drivers/pinctrl/pinctrl-mcp23s08_i2c.c @@ -111,4 +111,5 @@ static void mcp23s08_i2c_exit(void) } module_exit(mcp23s08_i2c_exit); +MODULE_DESCRIPTION("MCP23S08 I2C GPIO driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-mcp23s08_spi.c b/drivers/pinctrl/pinctrl-mcp23s08_spi.c index 4a872fff5fe8..54f61c8cb1c0 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08_spi.c +++ b/drivers/pinctrl/pinctrl-mcp23s08_spi.c @@ -263,4 +263,5 @@ static void mcp23s08_spi_exit(void) } module_exit(mcp23s08_spi_exit); +MODULE_DESCRIPTION("MCP23S08 SPI GPIO driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-mlxbf3.c b/drivers/pinctrl/pinctrl-mlxbf3.c index 7d1713824a89..ffb5dda364dc 100644 --- a/drivers/pinctrl/pinctrl-mlxbf3.c +++ b/drivers/pinctrl/pinctrl-mlxbf3.c @@ -259,16 +259,16 @@ static int mlxbf3_pinctrl_probe(struct platform_device *pdev) return PTR_ERR(priv->fw_ctrl_set0); priv->fw_ctrl_clr0 = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(priv->fw_ctrl_set0)) - return PTR_ERR(priv->fw_ctrl_set0); + if (IS_ERR(priv->fw_ctrl_clr0)) + return PTR_ERR(priv->fw_ctrl_clr0); priv->fw_ctrl_set1 = devm_platform_ioremap_resource(pdev, 2); - if (IS_ERR(priv->fw_ctrl_set0)) - return PTR_ERR(priv->fw_ctrl_set0); + if (IS_ERR(priv->fw_ctrl_set1)) + return PTR_ERR(priv->fw_ctrl_set1); priv->fw_ctrl_clr1 = devm_platform_ioremap_resource(pdev, 3); - if (IS_ERR(priv->fw_ctrl_set0)) - return PTR_ERR(priv->fw_ctrl_set0); + if (IS_ERR(priv->fw_ctrl_clr1)) + return PTR_ERR(priv->fw_ctrl_clr1); ret = devm_pinctrl_register_and_init(dev, &mlxbf3_pin_desc, diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 3f56991f5b89..0eacaf10c640 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -915,9 +915,8 @@ static struct rockchip_mux_route_data rk3308_mux_route_data[] = { RK_MUXROUTE_SAME(0, RK_PC3, 1, 0x314, BIT(16 + 0) | BIT(0)), /* rtc_clk */ RK_MUXROUTE_SAME(1, RK_PC6, 2, 0x314, BIT(16 + 2) | BIT(16 + 3)), /* uart2_rxm0 */ RK_MUXROUTE_SAME(4, RK_PD2, 2, 0x314, BIT(16 + 2) | BIT(16 + 3) | BIT(2)), /* uart2_rxm1 */ - RK_MUXROUTE_SAME(0, RK_PB7, 2, 0x608, BIT(16 + 8) | BIT(16 + 9)), /* i2c3_sdam0 */ - RK_MUXROUTE_SAME(3, RK_PB4, 2, 0x608, BIT(16 + 8) | BIT(16 + 9) | BIT(8)), /* i2c3_sdam1 */ - RK_MUXROUTE_SAME(2, RK_PA0, 3, 0x608, BIT(16 + 8) | BIT(16 + 9) | BIT(9)), /* i2c3_sdam2 */ + RK_MUXROUTE_SAME(0, RK_PB7, 2, 0x314, BIT(16 + 4)), /* i2c3_sdam0 */ + RK_MUXROUTE_SAME(3, RK_PB4, 2, 0x314, BIT(16 + 4) | BIT(4)), /* i2c3_sdam1 */ RK_MUXROUTE_SAME(1, RK_PA3, 2, 0x308, BIT(16 + 3)), /* i2s-8ch-1-sclktxm0 */ RK_MUXROUTE_SAME(1, RK_PA4, 2, 0x308, BIT(16 + 3)), /* i2s-8ch-1-sclkrxm0 */ RK_MUXROUTE_SAME(1, RK_PB5, 2, 0x308, BIT(16 + 3) | BIT(3)), /* i2s-8ch-1-sclktxm1 */ @@ -926,18 +925,6 @@ static struct rockchip_mux_route_data rk3308_mux_route_data[] = { RK_MUXROUTE_SAME(1, RK_PB6, 4, 0x308, BIT(16 + 12) | BIT(16 + 13) | BIT(12)), /* pdm-clkm1 */ RK_MUXROUTE_SAME(2, RK_PA6, 2, 0x308, BIT(16 + 12) | BIT(16 + 13) | BIT(13)), /* pdm-clkm2 */ RK_MUXROUTE_SAME(2, RK_PA4, 3, 0x600, BIT(16 + 2) | BIT(2)), /* pdm-clkm-m2 */ - RK_MUXROUTE_SAME(3, RK_PB2, 3, 0x314, BIT(16 + 9)), /* spi1_miso */ - RK_MUXROUTE_SAME(2, RK_PA4, 2, 0x314, BIT(16 + 9) | BIT(9)), /* spi1_miso_m1 */ - RK_MUXROUTE_SAME(0, RK_PB3, 3, 0x314, BIT(16 + 10) | BIT(16 + 11)), /* owire_m0 */ - RK_MUXROUTE_SAME(1, RK_PC6, 7, 0x314, BIT(16 + 10) | BIT(16 + 11) | BIT(10)), /* owire_m1 */ - RK_MUXROUTE_SAME(2, RK_PA2, 5, 0x314, BIT(16 + 10) | BIT(16 + 11) | BIT(11)), /* owire_m2 */ - RK_MUXROUTE_SAME(0, RK_PB3, 2, 0x314, BIT(16 + 12) | BIT(16 + 13)), /* can_rxd_m0 */ - RK_MUXROUTE_SAME(1, RK_PC6, 5, 0x314, BIT(16 + 12) | BIT(16 + 13) | BIT(12)), /* can_rxd_m1 */ - RK_MUXROUTE_SAME(2, RK_PA2, 4, 0x314, BIT(16 + 12) | BIT(16 + 13) | BIT(13)), /* can_rxd_m2 */ - RK_MUXROUTE_SAME(1, RK_PC4, 3, 0x314, BIT(16 + 14)), /* mac_rxd0_m0 */ - RK_MUXROUTE_SAME(4, RK_PA2, 2, 0x314, BIT(16 + 14) | BIT(14)), /* mac_rxd0_m1 */ - RK_MUXROUTE_SAME(3, RK_PB4, 4, 0x314, BIT(16 + 15)), /* uart3_rx */ - RK_MUXROUTE_SAME(0, RK_PC1, 3, 0x314, BIT(16 + 15) | BIT(15)), /* uart3_rx_m1 */ }; static struct rockchip_mux_route_data rk3328_mux_route_data[] = { @@ -3107,7 +3094,6 @@ static int rockchip_pinctrl_parse_functions(struct device_node *np, u32 index) { struct device *dev = info->dev; - struct device_node *child; struct rockchip_pmx_func *func; struct rockchip_pin_group *grp; int ret; @@ -3128,14 +3114,12 @@ static int rockchip_pinctrl_parse_functions(struct device_node *np, if (!func->groups) return -ENOMEM; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { func->groups[i] = child->name; grp = &info->groups[grp_index++]; ret = rockchip_pinctrl_parse_groups(child, grp, info, i++); - if (ret) { - of_node_put(child); + if (ret) return ret; - } } return 0; @@ -3146,7 +3130,6 @@ static int rockchip_pinctrl_parse_dt(struct platform_device *pdev, { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct device_node *child; int ret; int i; @@ -3165,14 +3148,13 @@ static int rockchip_pinctrl_parse_dt(struct platform_device *pdev, i = 0; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { if (of_match_node(rockchip_bank_match, child)) continue; ret = rockchip_pinctrl_parse_functions(child, info, i++); if (ret) { dev_err(dev, "failed to parse function\n"); - of_node_put(child); return ret; } } diff --git a/drivers/pinctrl/pinctrl-scmi.c b/drivers/pinctrl/pinctrl-scmi.c index 036bc1e3fc6c..df4bbcd7d1d5 100644 --- a/drivers/pinctrl/pinctrl-scmi.c +++ b/drivers/pinctrl/pinctrl-scmi.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -504,6 +505,11 @@ static int pinctrl_scmi_get_pins(struct scmi_pinctrl *pmx, return 0; } +static const char * const scmi_pinctrl_blocklist[] = { + "fsl,imx95", + NULL +}; + static int scmi_pinctrl_probe(struct scmi_device *sdev) { int ret; @@ -515,6 +521,9 @@ static int scmi_pinctrl_probe(struct scmi_device *sdev) if (!sdev->handle) return -EINVAL; + if (of_machine_compatible_match(scmi_pinctrl_blocklist)) + return -ENODEV; + handle = sdev->handle; pinctrl_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_PINCTRL, &ph); diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index a798f31d6954..4c6bfabb6bd7 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1329,7 +1329,6 @@ static void pcs_irq_free(struct pcs_device *pcs) static void pcs_free_resources(struct pcs_device *pcs) { pcs_irq_free(pcs); - pinctrl_unregister(pcs->pctl); #if IS_BUILTIN(CONFIG_PINCTRL_SINGLE) if (pcs->missing_nr_pinctrl_cells) @@ -1879,7 +1878,7 @@ static int pcs_probe(struct platform_device *pdev) if (ret < 0) goto free; - ret = pinctrl_register_and_init(&pcs->desc, pcs->dev, pcs, &pcs->pctl); + ret = devm_pinctrl_register_and_init(pcs->dev, &pcs->desc, pcs, &pcs->pctl); if (ret) { dev_err(pcs->dev, "could not register single pinctrl driver\n"); goto free; @@ -1912,8 +1911,10 @@ static int pcs_probe(struct platform_device *pdev) dev_info(pcs->dev, "%i pins, size %u\n", pcs->desc.npins, pcs->size); - return pinctrl_enable(pcs->pctl); + if (pinctrl_enable(pcs->pctl)) + goto free; + return 0; free: pcs_free_resources(pcs); diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c index 5d9abd6547d0..fe2d52e434db 100644 --- a/drivers/pinctrl/pinctrl-st.c +++ b/drivers/pinctrl/pinctrl-st.c @@ -1195,10 +1195,10 @@ static int st_pctl_dt_parse_groups(struct device_node *np, struct property *pp; struct device *dev = info->dev; struct st_pinconf *conf; - struct device_node *pins; + struct device_node *pins __free(device_node) = NULL; phandle bank; unsigned int offset; - int i = 0, npins = 0, nr_props, ret = 0; + int i = 0, npins = 0, nr_props; pins = of_get_child_by_name(np, "st,pins"); if (!pins) @@ -1213,8 +1213,7 @@ static int st_pctl_dt_parse_groups(struct device_node *np, npins++; } else { pr_warn("Invalid st,pins in %pOFn node\n", np); - ret = -EINVAL; - goto out_put_node; + return -EINVAL; } } @@ -1223,10 +1222,8 @@ static int st_pctl_dt_parse_groups(struct device_node *np, grp->pins = devm_kcalloc(dev, npins, sizeof(*grp->pins), GFP_KERNEL); grp->pin_conf = devm_kcalloc(dev, npins, sizeof(*grp->pin_conf), GFP_KERNEL); - if (!grp->pins || !grp->pin_conf) { - ret = -ENOMEM; - goto out_put_node; - } + if (!grp->pins || !grp->pin_conf) + return -ENOMEM; /* */ for_each_property_of_node(pins, pp) { @@ -1260,17 +1257,13 @@ static int st_pctl_dt_parse_groups(struct device_node *np, i++; } -out_put_node: - of_node_put(pins); - - return ret; + return 0; } static int st_pctl_parse_functions(struct device_node *np, struct st_pinctrl *info, u32 index, int *grp_index) { struct device *dev = info->dev; - struct device_node *child; struct st_pmx_func *func; struct st_pctl_group *grp; int ret, i; @@ -1285,15 +1278,13 @@ static int st_pctl_parse_functions(struct device_node *np, return -ENOMEM; i = 0; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { func->groups[i] = child->name; grp = &info->groups[*grp_index]; *grp_index += 1; ret = st_pctl_dt_parse_groups(child, grp, info, i++); - if (ret) { - of_node_put(child); + if (ret) return ret; - } } dev_info(dev, "Function[%d\t name:%s,\tgroups:%d]\n", index, func->name, func->ngroups); @@ -1601,7 +1592,6 @@ static int st_pctl_probe_dt(struct platform_device *pdev, int i = 0, j = 0, k = 0, bank; struct pinctrl_pin_desc *pdesc; struct device_node *np = dev->of_node; - struct device_node *child; int grp_index = 0; int irq = 0; @@ -1646,25 +1636,21 @@ static int st_pctl_probe_dt(struct platform_device *pdev, pctl_desc->pins = pdesc; bank = 0; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { if (of_property_read_bool(child, "gpio-controller")) { const char *bank_name = NULL; char **pin_names; ret = st_gpiolib_register_bank(info, bank, child); - if (ret) { - of_node_put(child); + if (ret) return ret; - } k = info->banks[bank].range.pin_base; bank_name = info->banks[bank].range.name; pin_names = devm_kasprintf_strarray(dev, bank_name, ST_GPIO_PINS_PER_BANK); - if (IS_ERR(pin_names)) { - of_node_put(child); + if (IS_ERR(pin_names)) return PTR_ERR(pin_names); - } for (j = 0; j < ST_GPIO_PINS_PER_BANK; j++, k++) { pdesc->number = k; @@ -1678,7 +1664,6 @@ static int st_pctl_probe_dt(struct platform_device *pdev, i++, &grp_index); if (ret) { dev_err(dev, "No functions found.\n"); - of_node_put(child); return ret; } } diff --git a/drivers/pinctrl/pinctrl-tb10x.c b/drivers/pinctrl/pinctrl-tb10x.c index c3b76e6511ac..4f98f72565f4 100644 --- a/drivers/pinctrl/pinctrl-tb10x.c +++ b/drivers/pinctrl/pinctrl-tb10x.c @@ -830,4 +830,5 @@ static struct platform_driver tb10x_pinctrl_pdrv = { module_platform_driver(tb10x_pinctrl_pdrv); MODULE_AUTHOR("Christian Ruppert "); +MODULE_DESCRIPTION("Abilis Systems TB10x pinctrl driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-tps6594.c b/drivers/pinctrl/pinctrl-tps6594.c index 5e7c7cf93445..54cc810f79d6 100644 --- a/drivers/pinctrl/pinctrl-tps6594.c +++ b/drivers/pinctrl/pinctrl-tps6594.c @@ -237,13 +237,13 @@ struct muxval_remap { u8 remap; }; -struct muxval_remap tps65224_muxval_remap[] = { +static struct muxval_remap tps65224_muxval_remap[] = { {5, TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION, TPS65224_PINCTRL_WKUP_FUNCTION_GPIO5}, {5, TPS65224_PINCTRL_SYNCCLKIN_FUNCTION, TPS65224_PINCTRL_SYNCCLKIN_FUNCTION_GPIO5}, {5, TPS65224_PINCTRL_NSLEEP2_FUNCTION, TPS65224_PINCTRL_NSLEEP2_FUNCTION_GPIO5}, }; -struct muxval_remap tps6594_muxval_remap[] = { +static struct muxval_remap tps6594_muxval_remap[] = { {8, TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION, TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION_GPIO8}, {8, TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION, TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION_GPIO8}, {9, TPS6594_PINCTRL_CLK32KOUT_FUNCTION, TPS6594_PINCTRL_CLK32KOUT_FUNCTION_GPIO9}, diff --git a/drivers/pinctrl/pinctrl-zynqmp.c b/drivers/pinctrl/pinctrl-zynqmp.c index 5c46b7d7ebcb..3c6d56fdb8c9 100644 --- a/drivers/pinctrl/pinctrl-zynqmp.c +++ b/drivers/pinctrl/pinctrl-zynqmp.c @@ -10,6 +10,7 @@ #include +#include #include #include #include @@ -97,7 +98,7 @@ static int zynqmp_pctrl_get_groups_count(struct pinctrl_dev *pctldev) { struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - return pctrl->ngroups; + return pctrl->ngroups + zynqmp_desc.npins; } static const char *zynqmp_pctrl_get_group_name(struct pinctrl_dev *pctldev, @@ -105,7 +106,10 @@ static const char *zynqmp_pctrl_get_group_name(struct pinctrl_dev *pctldev, { struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - return pctrl->groups[selector].name; + if (selector < pctrl->ngroups) + return pctrl->groups[selector].name; + + return zynqmp_desc.pins[selector - pctrl->ngroups].name; } static int zynqmp_pctrl_get_group_pins(struct pinctrl_dev *pctldev, @@ -115,8 +119,13 @@ static int zynqmp_pctrl_get_group_pins(struct pinctrl_dev *pctldev, { struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - *pins = pctrl->groups[selector].pins; - *npins = pctrl->groups[selector].npins; + if (selector < pctrl->ngroups) { + *pins = pctrl->groups[selector].pins; + *npins = pctrl->groups[selector].npins; + } else { + *pins = &zynqmp_desc.pins[selector - pctrl->ngroups].number; + *npins = 1; + } return 0; } @@ -197,17 +206,16 @@ static int zynqmp_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, unsigned int group) { - struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - const struct zynqmp_pctrl_group *pgrp = &pctrl->groups[group]; + const unsigned int *pins; + unsigned int npins; int ret, i; - for (i = 0; i < pgrp->npins; i++) { - unsigned int pin = pgrp->pins[i]; - - ret = zynqmp_pm_pinctrl_set_function(pin, function); + zynqmp_pctrl_get_group_pins(pctldev, group, &pins, &npins); + for (i = 0; i < npins; i++) { + ret = zynqmp_pm_pinctrl_set_function(pins[i], function); if (ret) { dev_err(pctldev->dev, "set mux failed for pin %u\n", - pin); + pins[i]); return ret; } } @@ -467,12 +475,13 @@ static int zynqmp_pinconf_group_set(struct pinctrl_dev *pctldev, unsigned long *configs, unsigned int num_configs) { + const unsigned int *pins; + unsigned int npins; int i, ret; - struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - const struct zynqmp_pctrl_group *pgrp = &pctrl->groups[selector]; - for (i = 0; i < pgrp->npins; i++) { - ret = zynqmp_pinconf_cfg_set(pctldev, pgrp->pins[i], configs, + zynqmp_pctrl_get_group_pins(pctldev, selector, &pins, &npins); + for (i = 0; i < npins; i++) { + ret = zynqmp_pinconf_cfg_set(pctldev, pins[i], configs, num_configs); if (ret) return ret; @@ -560,10 +569,12 @@ static int zynqmp_pinctrl_prepare_func_groups(struct device *dev, u32 fid, { u16 resp[NUM_GROUPS_PER_RESP] = {0}; const char **fgroups; - int ret, index, i; + int ret, index, i, pin; + unsigned int npins; + unsigned long *used_pins __free(bitmap) = + bitmap_zalloc(zynqmp_desc.npins, GFP_KERNEL); - fgroups = devm_kcalloc(dev, func->ngroups, sizeof(*fgroups), GFP_KERNEL); - if (!fgroups) + if (!used_pins) return -ENOMEM; for (index = 0; index < func->ngroups; index += NUM_GROUPS_PER_RESP) { @@ -578,23 +589,37 @@ static int zynqmp_pinctrl_prepare_func_groups(struct device *dev, u32 fid, if (resp[i] == RESERVED_GROUP) continue; - fgroups[index + i] = devm_kasprintf(dev, GFP_KERNEL, - "%s_%d_grp", - func->name, - index + i); - if (!fgroups[index + i]) - return -ENOMEM; - groups[resp[i]].name = devm_kasprintf(dev, GFP_KERNEL, "%s_%d_grp", func->name, index + i); if (!groups[resp[i]].name) return -ENOMEM; + + for (pin = 0; pin < groups[resp[i]].npins; pin++) + __set_bit(groups[resp[i]].pins[pin], used_pins); } } done: + npins = bitmap_weight(used_pins, zynqmp_desc.npins); + fgroups = devm_kcalloc(dev, size_add(func->ngroups, npins), + sizeof(*fgroups), GFP_KERNEL); + if (!fgroups) + return -ENOMEM; + + for (i = 0; i < func->ngroups; i++) { + fgroups[i] = devm_kasprintf(dev, GFP_KERNEL, "%s_%d_grp", + func->name, i); + if (!fgroups[i]) + return -ENOMEM; + } + + pin = 0; + for_each_set_bit(pin, used_pins, zynqmp_desc.npins) + fgroups[i++] = zynqmp_desc.pins[pin].name; + func->groups = fgroups; + func->ngroups += npins; return 0; } @@ -718,7 +743,7 @@ static int zynqmp_pinctrl_prepare_group_pins(struct device *dev, int ret; for (pin = 0; pin < zynqmp_desc.npins; pin++) { - ret = zynqmp_pinctrl_create_pin_groups(dev, groups, pin); + ret = zynqmp_pinctrl_create_pin_groups(dev, groups, zynqmp_desc.pins[pin].number); if (ret) return ret; } @@ -772,6 +797,10 @@ static int zynqmp_pinctrl_prepare_function_info(struct device *dev, if (!groups) return -ENOMEM; + ret = zynqmp_pinctrl_prepare_group_pins(dev, groups, pctrl->ngroups); + if (ret) + return ret; + for (i = 0; i < pctrl->nfuncs; i++) { ret = zynqmp_pinctrl_prepare_func_groups(dev, i, &funcs[i], groups); @@ -779,10 +808,6 @@ static int zynqmp_pinctrl_prepare_function_info(struct device *dev, return ret; } - ret = zynqmp_pinctrl_prepare_group_pins(dev, groups, pctrl->ngroups); - if (ret) - return ret; - pctrl->funcs = funcs; pctrl->groups = groups; diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index addba55334d9..aae71a37219b 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -796,7 +796,7 @@ pinmux_generic_get_function_name(struct pinctrl_dev *pctldev, if (!function) return NULL; - return function->name; + return function->func.name; } EXPORT_SYMBOL_GPL(pinmux_generic_get_function_name); @@ -805,12 +805,12 @@ EXPORT_SYMBOL_GPL(pinmux_generic_get_function_name); * @pctldev: pin controller device * @selector: function number * @groups: array of pin groups - * @num_groups: number of pin groups + * @ngroups: number of pin groups */ int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev, unsigned int selector, const char * const **groups, - unsigned int * const num_groups) + unsigned int * const ngroups) { struct function_desc *function; @@ -821,8 +821,8 @@ int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev, __func__, selector); return -EINVAL; } - *groups = function->group_names; - *num_groups = function->num_group_names; + *groups = function->func.groups; + *ngroups = function->func.ngroups; return 0; } @@ -852,13 +852,13 @@ EXPORT_SYMBOL_GPL(pinmux_generic_get_function); * @pctldev: pin controller device * @name: name of the function * @groups: array of pin groups - * @num_groups: number of pin groups + * @ngroups: number of pin groups * @data: pin controller driver specific data */ int pinmux_generic_add_function(struct pinctrl_dev *pctldev, const char *name, const char * const *groups, - const unsigned int num_groups, + const unsigned int ngroups, void *data) { struct function_desc *function; @@ -877,10 +877,7 @@ int pinmux_generic_add_function(struct pinctrl_dev *pctldev, if (!function) return -ENOMEM; - function->name = name; - function->group_names = groups; - function->num_group_names = num_groups; - function->data = data; + *function = PINCTRL_FUNCTION_DESC(name, groups, ngroups, data); error = radix_tree_insert(&pctldev->pin_function_tree, selector, function); if (error) diff --git a/drivers/pinctrl/pinmux.h b/drivers/pinctrl/pinmux.h index 7c8aa25ccc80..2965ec20b77f 100644 --- a/drivers/pinctrl/pinmux.h +++ b/drivers/pinctrl/pinmux.h @@ -133,18 +133,21 @@ static inline void pinmux_init_device_debugfs(struct dentry *devroot, /** * struct function_desc - generic function descriptor - * @name: name of the function - * @group_names: array of pin group names - * @num_group_names: number of pin group names + * @func: generic data of the pin function (name and groups of pins) * @data: pin controller driver specific data */ struct function_desc { - const char *name; - const char * const *group_names; - int num_group_names; + struct pinfunction func; void *data; }; +/* Convenient macro to define a generic pin function descriptor */ +#define PINCTRL_FUNCTION_DESC(_name, _grps, _num_grps, _data) \ +(struct function_desc) { \ + .func = PINCTRL_PINFUNCTION(_name, _grps, _num_grps), \ + .data = _data, \ +} + int pinmux_generic_get_function_count(struct pinctrl_dev *pctldev); const char * @@ -154,7 +157,7 @@ pinmux_generic_get_function_name(struct pinctrl_dev *pctldev, int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev, unsigned int selector, const char * const **groups, - unsigned int * const num_groups); + unsigned int * const ngroups); struct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev, unsigned int selector); @@ -162,7 +165,7 @@ struct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev, int pinmux_generic_add_function(struct pinctrl_dev *pctldev, const char *name, const char * const *groups, - unsigned int const num_groups, + unsigned int const ngroups, void *data); int pinmux_generic_remove_function(struct pinctrl_dev *pctldev, diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 24619e80b2cc..dd9bbe8f3e11 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -68,6 +68,15 @@ config PINCTRL_SC7280_LPASS_LPI Qualcomm Technologies Inc LPASS (Low Power Audio SubSystem) LPI (Low Power Island) found on the Qualcomm Technologies Inc SC7280 platform. +config PINCTRL_SM4250_LPASS_LPI + tristate "Qualcomm Technologies Inc SM4250 LPASS LPI pin controller driver" + depends on ARM64 || COMPILE_TEST + depends on PINCTRL_LPASS_LPI + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm Technologies Inc LPASS (Low Power Audio SubSystem) LPI + (Low Power Island) found on the Qualcomm Technologies Inc SM4250 platform. + config PINCTRL_SM6115_LPASS_LPI tristate "Qualcomm Technologies Inc SM6115 LPASS LPI pin controller driver" depends on ARM64 || COMPILE_TEST diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index e2e76071d268..eb04297b6388 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o obj-$(CONFIG_PINCTRL_SDX55) += pinctrl-sdx55.o obj-$(CONFIG_PINCTRL_SDX65) += pinctrl-sdx65.o obj-$(CONFIG_PINCTRL_SDX75) += pinctrl-sdx75.o +obj-$(CONFIG_PINCTRL_SM4250_LPASS_LPI) += pinctrl-sm4250-lpass-lpi.o obj-$(CONFIG_PINCTRL_SM4450) += pinctrl-sm4450.o obj-$(CONFIG_PINCTRL_SM6115) += pinctrl-sm6115.o obj-$(CONFIG_PINCTRL_SM6115_LPASS_LPI) += pinctrl-sm6115-lpass-lpi.o diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c index 0d98008e33ee..7366aba5a199 100644 --- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c @@ -20,7 +20,7 @@ #include "pinctrl-lpass-lpi.h" -#define MAX_NR_GPIO 23 +#define MAX_NR_GPIO 32 #define GPIO_FUNC 0 #define MAX_LPI_NUM_CLKS 2 diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670.c b/drivers/pinctrl/qcom/pinctrl-sdm670.c index 1e694a966953..894c042cb524 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm670.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm670.c @@ -1290,6 +1290,22 @@ static const int sdm670_reserved_gpios[] = { 58, 59, 60, 61, 62, 63, 64, 69, 70, 71, 72, 73, 74, 104, -1 }; +static const struct msm_gpio_wakeirq_map sdm670_pdc_map[] = { + { 1, 30 }, { 3, 31 }, { 5, 32 }, { 10, 33 }, { 11, 34 }, + { 20, 35 }, { 22, 36 }, { 24, 37 }, { 26, 38 }, { 30, 39 }, + { 31, 117 }, { 32, 41 }, { 34, 42 }, { 36, 43 }, { 37, 44 }, + { 38, 45 }, { 39, 46 }, { 40, 47 }, { 41, 115 }, { 43, 49 }, + { 44, 50 }, { 46, 51 }, { 48, 52 }, { 49, 118 }, { 52, 54 }, + { 53, 55 }, { 54, 56 }, { 56, 57 }, { 57, 58 }, { 66, 66 }, + { 68, 67 }, { 77, 70 }, { 78, 71 }, { 79, 72 }, { 80, 73 }, + { 84, 74 }, { 85, 75 }, { 86, 76 }, { 88, 77 }, { 89, 116 }, + { 91, 79 }, { 92, 80 }, { 95, 81 }, { 96, 82 }, { 97, 83 }, + { 101, 84 }, { 103, 85 }, { 115, 90 }, { 116, 91 }, { 117, 92 }, + { 118, 93 }, { 119, 94 }, { 120, 95 }, { 121, 96 }, { 122, 97 }, + { 123, 98 }, { 124, 99 }, { 125, 100 }, { 127, 102 }, { 128, 103 }, + { 129, 104 }, { 130, 105 }, { 132, 106 }, { 133, 107 }, { 145, 108 }, +}; + static const struct msm_pinctrl_soc_data sdm670_pinctrl = { .pins = sdm670_pins, .npins = ARRAY_SIZE(sdm670_pins), @@ -1299,6 +1315,9 @@ static const struct msm_pinctrl_soc_data sdm670_pinctrl = { .ngroups = ARRAY_SIZE(sdm670_groups), .ngpios = 151, .reserved_gpios = sdm670_reserved_gpios, + .wakeirq_map = sdm670_pdc_map, + .nwakeirq_map = ARRAY_SIZE(sdm670_pdc_map), + .wakeirq_dual_edge_errata = true, }; static int sdm670_pinctrl_probe(struct platform_device *pdev) diff --git a/drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c new file mode 100644 index 000000000000..2d2c636a3e20 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2020, 2023 Linaro Ltd. + */ + +#include +#include +#include + +#include "pinctrl-lpass-lpi.h" + +enum lpass_lpi_functions { + LPI_MUX_dmic01_clk, + LPI_MUX_dmic01_data, + LPI_MUX_dmic23_clk, + LPI_MUX_dmic23_data, + LPI_MUX_dmic4_clk, + LPI_MUX_dmic4_data, + LPI_MUX_ext_mclk0_a, + LPI_MUX_ext_mclk0_b, + LPI_MUX_ext_mclk1_a, + LPI_MUX_ext_mclk1_b, + LPI_MUX_ext_mclk1_c, + LPI_MUX_i2s1_clk, + LPI_MUX_i2s1_data, + LPI_MUX_i2s1_ws, + LPI_MUX_i2s2_clk, + LPI_MUX_i2s2_data, + LPI_MUX_i2s2_ws, + LPI_MUX_i2s3_clk, + LPI_MUX_i2s3_data, + LPI_MUX_i2s3_ws, + LPI_MUX_qup_io_00, + LPI_MUX_qup_io_01, + LPI_MUX_qup_io_05, + LPI_MUX_qup_io_10, + LPI_MUX_qup_io_11, + LPI_MUX_qup_io_25, + LPI_MUX_qup_io_21, + LPI_MUX_qup_io_26, + LPI_MUX_qup_io_31, + LPI_MUX_qup_io_36, + LPI_MUX_qua_mi2s_data, + LPI_MUX_qua_mi2s_sclk, + LPI_MUX_qua_mi2s_ws, + LPI_MUX_slim_clk, + LPI_MUX_slim_data, + LPI_MUX_sync_out, + LPI_MUX_swr_rx_clk, + LPI_MUX_swr_rx_data, + LPI_MUX_swr_tx_clk, + LPI_MUX_swr_tx_data, + LPI_MUX_swr_wsa_clk, + LPI_MUX_swr_wsa_data, + LPI_MUX_gpio, + LPI_MUX__, +}; + +static const struct pinctrl_pin_desc sm4250_lpi_pins[] = { + PINCTRL_PIN(0, "gpio0"), + PINCTRL_PIN(1, "gpio1"), + PINCTRL_PIN(2, "gpio2"), + PINCTRL_PIN(3, "gpio3"), + PINCTRL_PIN(4, "gpio4"), + PINCTRL_PIN(5, "gpio5"), + PINCTRL_PIN(6, "gpio6"), + PINCTRL_PIN(7, "gpio7"), + PINCTRL_PIN(8, "gpio8"), + PINCTRL_PIN(9, "gpio9"), + PINCTRL_PIN(10, "gpio10"), + PINCTRL_PIN(11, "gpio11"), + PINCTRL_PIN(12, "gpio12"), + PINCTRL_PIN(13, "gpio13"), + PINCTRL_PIN(14, "gpio14"), + PINCTRL_PIN(15, "gpio15"), + PINCTRL_PIN(16, "gpio16"), + PINCTRL_PIN(17, "gpio17"), + PINCTRL_PIN(18, "gpio18"), + PINCTRL_PIN(19, "gpio19"), + PINCTRL_PIN(20, "gpio20"), + PINCTRL_PIN(21, "gpio21"), + PINCTRL_PIN(22, "gpio22"), + PINCTRL_PIN(23, "gpio23"), + PINCTRL_PIN(24, "gpio24"), + PINCTRL_PIN(25, "gpio25"), + PINCTRL_PIN(26, "gpio26"), +}; + +static const char * const dmic01_clk_groups[] = { "gpio6" }; +static const char * const dmic01_data_groups[] = { "gpio7" }; +static const char * const dmic23_clk_groups[] = { "gpio8" }; +static const char * const dmic23_data_groups[] = { "gpio9" }; +static const char * const dmic4_clk_groups[] = { "gpio10" }; +static const char * const dmic4_data_groups[] = { "gpio11" }; +static const char * const ext_mclk0_a_groups[] = { "gpio13" }; +static const char * const ext_mclk0_b_groups[] = { "gpio5" }; +static const char * const ext_mclk1_a_groups[] = { "gpio18" }; +static const char * const ext_mclk1_b_groups[] = { "gpio9" }; +static const char * const ext_mclk1_c_groups[] = { "gpio17" }; +static const char * const slim_clk_groups[] = { "gpio14" }; +static const char * const slim_data_groups[] = { "gpio15" }; +static const char * const i2s1_clk_groups[] = { "gpio6" }; +static const char * const i2s1_data_groups[] = { "gpio8", "gpio9" }; +static const char * const i2s1_ws_groups[] = { "gpio7" }; +static const char * const i2s2_clk_groups[] = { "gpio10" }; +static const char * const i2s2_data_groups[] = { "gpio12", "gpio13" }; +static const char * const i2s2_ws_groups[] = { "gpio11" }; +static const char * const i2s3_clk_groups[] = { "gpio14" }; +static const char * const i2s3_data_groups[] = { "gpio16", "gpio17" }; +static const char * const i2s3_ws_groups[] = { "gpio15" }; +static const char * const qup_io_00_groups[] = { "gpio19" }; +static const char * const qup_io_01_groups[] = { "gpio21" }; +static const char * const qup_io_05_groups[] = { "gpio23" }; +static const char * const qup_io_10_groups[] = { "gpio20" }; +static const char * const qup_io_11_groups[] = { "gpio22" }; +static const char * const qup_io_25_groups[] = { "gpio23" }; +static const char * const qup_io_21_groups[] = { "gpio25" }; +static const char * const qup_io_26_groups[] = { "gpio25" }; +static const char * const qup_io_31_groups[] = { "gpio26" }; +static const char * const qup_io_36_groups[] = { "gpio26" }; +static const char * const qua_mi2s_data_groups[] = { "gpio2", "gpio3", "gpio4", "gpio5" }; +static const char * const qua_mi2s_sclk_groups[] = { "gpio0" }; +static const char * const qua_mi2s_ws_groups[] = { "gpio1" }; +static const char * const sync_out_groups[] = { "gpio19", "gpio20", "gpio21", "gpio22", + "gpio23", "gpio24", "gpio25", "gpio26"}; +static const char * const swr_rx_clk_groups[] = { "gpio3" }; +static const char * const swr_rx_data_groups[] = { "gpio4", "gpio5" }; +static const char * const swr_tx_clk_groups[] = { "gpio0" }; +static const char * const swr_tx_data_groups[] = { "gpio1", "gpio2" }; +static const char * const swr_wsa_clk_groups[] = { "gpio10" }; +static const char * const swr_wsa_data_groups[] = { "gpio11" }; + + +static const struct lpi_pingroup sm4250_groups[] = { + LPI_PINGROUP(0, 0, swr_tx_clk, qua_mi2s_sclk, _, _), + LPI_PINGROUP(1, 2, swr_tx_data, qua_mi2s_ws, _, _), + LPI_PINGROUP(2, 4, swr_tx_data, qua_mi2s_data, _, _), + LPI_PINGROUP(3, 8, swr_rx_clk, qua_mi2s_data, _, _), + LPI_PINGROUP(4, 10, swr_rx_data, qua_mi2s_data, _, _), + LPI_PINGROUP(5, 12, swr_rx_data, ext_mclk0_b, qua_mi2s_data, _), + LPI_PINGROUP(6, LPI_NO_SLEW, dmic01_clk, i2s1_clk, _, _), + LPI_PINGROUP(7, LPI_NO_SLEW, dmic01_data, i2s1_ws, _, _), + LPI_PINGROUP(8, LPI_NO_SLEW, dmic23_clk, i2s1_data, _, _), + LPI_PINGROUP(9, LPI_NO_SLEW, dmic23_data, i2s1_data, ext_mclk1_b, _), + LPI_PINGROUP(10, 16, i2s2_clk, swr_wsa_clk, dmic4_clk, _), + LPI_PINGROUP(11, 18, i2s2_ws, swr_wsa_data, dmic4_data, _), + LPI_PINGROUP(12, LPI_NO_SLEW, dmic23_clk, i2s2_data, _, _), + LPI_PINGROUP(13, LPI_NO_SLEW, dmic23_data, i2s2_data, ext_mclk0_a, _), + LPI_PINGROUP(14, LPI_NO_SLEW, i2s3_clk, slim_clk, _, _), + LPI_PINGROUP(15, LPI_NO_SLEW, i2s3_ws, slim_data, _, _), + LPI_PINGROUP(16, LPI_NO_SLEW, i2s3_data, _, _, _), + LPI_PINGROUP(17, LPI_NO_SLEW, i2s3_data, ext_mclk1_c, _, _), + LPI_PINGROUP(18, 20, ext_mclk1_a, swr_rx_data, _, _), + LPI_PINGROUP(19, LPI_NO_SLEW, qup_io_00, sync_out, _, _), + LPI_PINGROUP(20, LPI_NO_SLEW, qup_io_10, sync_out, _, _), + LPI_PINGROUP(21, LPI_NO_SLEW, qup_io_01, sync_out, _, _), + LPI_PINGROUP(22, LPI_NO_SLEW, qup_io_11, sync_out, _, _), + LPI_PINGROUP(23, LPI_NO_SLEW, qup_io_25, qup_io_05, sync_out, _), + LPI_PINGROUP(25, LPI_NO_SLEW, qup_io_26, qup_io_21, sync_out, _), + LPI_PINGROUP(26, LPI_NO_SLEW, qup_io_36, qup_io_31, sync_out, _), +}; + +static const struct lpi_function sm4250_functions[] = { + LPI_FUNCTION(dmic01_clk), + LPI_FUNCTION(dmic01_data), + LPI_FUNCTION(dmic23_clk), + LPI_FUNCTION(dmic23_data), + LPI_FUNCTION(dmic4_clk), + LPI_FUNCTION(dmic4_data), + LPI_FUNCTION(ext_mclk0_a), + LPI_FUNCTION(ext_mclk0_b), + LPI_FUNCTION(ext_mclk1_a), + LPI_FUNCTION(ext_mclk1_b), + LPI_FUNCTION(ext_mclk1_c), + LPI_FUNCTION(i2s1_clk), + LPI_FUNCTION(i2s1_data), + LPI_FUNCTION(i2s1_ws), + LPI_FUNCTION(i2s2_clk), + LPI_FUNCTION(i2s2_data), + LPI_FUNCTION(i2s2_ws), + LPI_FUNCTION(i2s3_clk), + LPI_FUNCTION(i2s3_data), + LPI_FUNCTION(i2s3_ws), + LPI_FUNCTION(qup_io_00), + LPI_FUNCTION(qup_io_01), + LPI_FUNCTION(qup_io_05), + LPI_FUNCTION(qup_io_10), + LPI_FUNCTION(qup_io_11), + LPI_FUNCTION(qup_io_25), + LPI_FUNCTION(qup_io_21), + LPI_FUNCTION(qup_io_26), + LPI_FUNCTION(qup_io_31), + LPI_FUNCTION(qup_io_36), + LPI_FUNCTION(qua_mi2s_data), + LPI_FUNCTION(qua_mi2s_sclk), + LPI_FUNCTION(qua_mi2s_ws), + LPI_FUNCTION(slim_clk), + LPI_FUNCTION(slim_data), + LPI_FUNCTION(sync_out), + LPI_FUNCTION(swr_rx_clk), + LPI_FUNCTION(swr_rx_data), + LPI_FUNCTION(swr_tx_clk), + LPI_FUNCTION(swr_tx_data), + LPI_FUNCTION(swr_wsa_clk), + LPI_FUNCTION(swr_wsa_data), +}; + +static const struct lpi_pinctrl_variant_data sm4250_lpi_data = { + .pins = sm4250_lpi_pins, + .npins = ARRAY_SIZE(sm4250_lpi_pins), + .groups = sm4250_groups, + .ngroups = ARRAY_SIZE(sm4250_groups), + .functions = sm4250_functions, + .nfunctions = ARRAY_SIZE(sm4250_functions), +}; + +static const struct of_device_id lpi_pinctrl_of_match[] = { + { .compatible = "qcom,sm4250-lpass-lpi-pinctrl", .data = &sm4250_lpi_data }, + { } +}; +MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); + +static struct platform_driver lpi_pinctrl_driver = { + .driver = { + .name = "qcom-sm4250-lpass-lpi-pinctrl", + .of_match_table = lpi_pinctrl_of_match, + }, + .probe = lpi_pinctrl_probe, + .remove_new = lpi_pinctrl_remove, +}; + +module_platform_driver(lpi_pinctrl_driver); +MODULE_DESCRIPTION("QTI SM4250 LPI GPIO pin control driver"); +MODULE_AUTHOR("Srinivas Kandagatla "); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index 4abd6f18bbef..d2dd66769aa8 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -1234,6 +1234,7 @@ static const struct of_device_id pmic_gpio_of_match[] = { { .compatible = "qcom,pm8994-gpio", .data = (void *) 22 }, { .compatible = "qcom,pm8998-gpio", .data = (void *) 26 }, { .compatible = "qcom,pma8084-gpio", .data = (void *) 22 }, + { .compatible = "qcom,pmc8380-gpio", .data = (void *) 10 }, { .compatible = "qcom,pmd8028-gpio", .data = (void *) 4 }, { .compatible = "qcom,pmi632-gpio", .data = (void *) 8 }, { .compatible = "qcom,pmi8950-gpio", .data = (void *) 2 }, diff --git a/drivers/pinctrl/renesas/pfc-r8a779g0.c b/drivers/pinctrl/renesas/pfc-r8a779g0.c index d2de526a3b58..cae3e6553499 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779g0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779g0.c @@ -68,20 +68,20 @@ #define GPSR0_9 F_(MSIOF5_SYNC, IP1SR0_7_4) #define GPSR0_8 F_(MSIOF5_SS1, IP1SR0_3_0) #define GPSR0_7 F_(MSIOF5_SS2, IP0SR0_31_28) -#define GPSR0_6 F_(IRQ0, IP0SR0_27_24) -#define GPSR0_5 F_(IRQ1, IP0SR0_23_20) -#define GPSR0_4 F_(IRQ2, IP0SR0_19_16) -#define GPSR0_3 F_(IRQ3, IP0SR0_15_12) +#define GPSR0_6 F_(IRQ0_A, IP0SR0_27_24) +#define GPSR0_5 F_(IRQ1_A, IP0SR0_23_20) +#define GPSR0_4 F_(IRQ2_A, IP0SR0_19_16) +#define GPSR0_3 F_(IRQ3_A, IP0SR0_15_12) #define GPSR0_2 F_(GP0_02, IP0SR0_11_8) #define GPSR0_1 F_(GP0_01, IP0SR0_7_4) #define GPSR0_0 F_(GP0_00, IP0SR0_3_0) /* GPSR1 */ -#define GPSR1_28 F_(HTX3, IP3SR1_19_16) -#define GPSR1_27 F_(HCTS3_N, IP3SR1_15_12) -#define GPSR1_26 F_(HRTS3_N, IP3SR1_11_8) -#define GPSR1_25 F_(HSCK3, IP3SR1_7_4) -#define GPSR1_24 F_(HRX3, IP3SR1_3_0) +#define GPSR1_28 F_(HTX3_A, IP3SR1_19_16) +#define GPSR1_27 F_(HCTS3_N_A, IP3SR1_15_12) +#define GPSR1_26 F_(HRTS3_N_A, IP3SR1_11_8) +#define GPSR1_25 F_(HSCK3_A, IP3SR1_7_4) +#define GPSR1_24 F_(HRX3_A, IP3SR1_3_0) #define GPSR1_23 F_(GP1_23, IP2SR1_31_28) #define GPSR1_22 F_(AUDIO_CLKIN, IP2SR1_27_24) #define GPSR1_21 F_(AUDIO_CLKOUT, IP2SR1_23_20) @@ -119,14 +119,14 @@ #define GPSR2_11 F_(CANFD0_RX, IP1SR2_15_12) #define GPSR2_10 F_(CANFD0_TX, IP1SR2_11_8) #define GPSR2_9 F_(CAN_CLK, IP1SR2_7_4) -#define GPSR2_8 F_(TPU0TO0, IP1SR2_3_0) -#define GPSR2_7 F_(TPU0TO1, IP0SR2_31_28) +#define GPSR2_8 F_(TPU0TO0_A, IP1SR2_3_0) +#define GPSR2_7 F_(TPU0TO1_A, IP0SR2_31_28) #define GPSR2_6 F_(FXR_TXDB, IP0SR2_27_24) -#define GPSR2_5 F_(FXR_TXENB_N, IP0SR2_23_20) +#define GPSR2_5 F_(FXR_TXENB_N_A, IP0SR2_23_20) #define GPSR2_4 F_(RXDB_EXTFXR, IP0SR2_19_16) #define GPSR2_3 F_(CLK_EXTFXR, IP0SR2_15_12) #define GPSR2_2 F_(RXDA_EXTFXR, IP0SR2_11_8) -#define GPSR2_1 F_(FXR_TXENA_N, IP0SR2_7_4) +#define GPSR2_1 F_(FXR_TXENA_N_A, IP0SR2_7_4) #define GPSR2_0 F_(FXR_TXDA, IP0SR2_3_0) /* GPSR3 */ @@ -275,13 +275,13 @@ /* SR0 */ /* IP0SR0 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP0SR0_3_0 F_(0, 0) FM(ERROROUTC_N_B) FM(TCLK2_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_3_0 F_(0, 0) FM(ERROROUTC_N_B) FM(TCLK2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR0_7_4 F_(0, 0) FM(MSIOF3_SS1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR0_11_8 F_(0, 0) FM(MSIOF3_SS2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR0_15_12 FM(IRQ3) FM(MSIOF3_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR0_19_16 FM(IRQ2) FM(MSIOF3_TXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR0_23_20 FM(IRQ1) FM(MSIOF3_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR0_27_24 FM(IRQ0) FM(MSIOF3_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_15_12 FM(IRQ3_A) FM(MSIOF3_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_19_16 FM(IRQ2_A) FM(MSIOF3_TXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_23_20 FM(IRQ1_A) FM(MSIOF3_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_27_24 FM(IRQ0_A) FM(MSIOF3_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR0_31_28 FM(MSIOF5_SS2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP1SR0 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ @@ -290,72 +290,72 @@ #define IP1SR0_11_8 FM(MSIOF5_TXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR0_15_12 FM(MSIOF5_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR0_19_16 FM(MSIOF5_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR0_23_20 FM(MSIOF2_SS2) FM(TCLK1) FM(IRQ2_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR0_27_24 FM(MSIOF2_SS1) FM(HTX1) FM(TX1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR0_31_28 FM(MSIOF2_SYNC) FM(HRX1) FM(RX1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR0_23_20 FM(MSIOF2_SS2) FM(TCLK1_A) FM(IRQ2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR0_27_24 FM(MSIOF2_SS1) FM(HTX1_A) FM(TX1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR0_31_28 FM(MSIOF2_SYNC) FM(HRX1_A) FM(RX1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP2SR0 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP2SR0_3_0 FM(MSIOF2_TXD) FM(HCTS1_N) FM(CTS1_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR0_7_4 FM(MSIOF2_SCK) FM(HRTS1_N) FM(RTS1_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR0_11_8 FM(MSIOF2_RXD) FM(HSCK1) FM(SCK1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR0_3_0 FM(MSIOF2_TXD) FM(HCTS1_N_A) FM(CTS1_N_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR0_7_4 FM(MSIOF2_SCK) FM(HRTS1_N_A) FM(RTS1_N_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR0_11_8 FM(MSIOF2_RXD) FM(HSCK1_A) FM(SCK1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* SR1 */ /* IP0SR1 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP0SR1_3_0 FM(MSIOF1_SS2) FM(HTX3_A) FM(TX3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR1_7_4 FM(MSIOF1_SS1) FM(HCTS3_N_A) FM(RX3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR1_11_8 FM(MSIOF1_SYNC) FM(HRTS3_N_A) FM(RTS3_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR1_15_12 FM(MSIOF1_SCK) FM(HSCK3_A) FM(CTS3_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR1_19_16 FM(MSIOF1_TXD) FM(HRX3_A) FM(SCK3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR1_3_0 FM(MSIOF1_SS2) FM(HTX3_B) FM(TX3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR1_7_4 FM(MSIOF1_SS1) FM(HCTS3_N_B) FM(RX3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR1_11_8 FM(MSIOF1_SYNC) FM(HRTS3_N_B) FM(RTS3_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR1_15_12 FM(MSIOF1_SCK) FM(HSCK3_B) FM(CTS3_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR1_19_16 FM(MSIOF1_TXD) FM(HRX3_B) FM(SCK3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR1_23_20 FM(MSIOF1_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR1_27_24 FM(MSIOF0_SS2) FM(HTX1_X) FM(TX1_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR1_31_28 FM(MSIOF0_SS1) FM(HRX1_X) FM(RX1_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR1_27_24 FM(MSIOF0_SS2) FM(HTX1_B) FM(TX1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR1_31_28 FM(MSIOF0_SS1) FM(HRX1_B) FM(RX1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP1SR1 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP1SR1_3_0 FM(MSIOF0_SYNC) FM(HCTS1_N_X) FM(CTS1_N_X) FM(CANFD5_TX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR1_7_4 FM(MSIOF0_TXD) FM(HRTS1_N_X) FM(RTS1_N_X) FM(CANFD5_RX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR1_11_8 FM(MSIOF0_SCK) FM(HSCK1_X) FM(SCK1_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR1_3_0 FM(MSIOF0_SYNC) FM(HCTS1_N_B) FM(CTS1_N_B) FM(CANFD5_TX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR1_7_4 FM(MSIOF0_TXD) FM(HRTS1_N_B) FM(RTS1_N_B) FM(CANFD5_RX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR1_11_8 FM(MSIOF0_SCK) FM(HSCK1_B) FM(SCK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR1_15_12 FM(MSIOF0_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR1_19_16 FM(HTX0) FM(TX0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR1_23_20 FM(HCTS0_N) FM(CTS0_N) FM(PWM8_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR1_27_24 FM(HRTS0_N) FM(RTS0_N) FM(PWM9_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR1_31_28 FM(HSCK0) FM(SCK0) FM(PWM0_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR1_23_20 FM(HCTS0_N) FM(CTS0_N) FM(PWM8) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR1_27_24 FM(HRTS0_N) FM(RTS0_N) FM(PWM9) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR1_31_28 FM(HSCK0) FM(SCK0) FM(PWM0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP2SR1 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ #define IP2SR1_3_0 FM(HRX0) FM(RX0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP2SR1_7_4 FM(SCIF_CLK) FM(IRQ4_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR1_11_8 FM(SSI_SCK) FM(TCLK3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR1_15_12 FM(SSI_WS) FM(TCLK4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR1_19_16 FM(SSI_SD) FM(IRQ0_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR1_23_20 FM(AUDIO_CLKOUT) FM(IRQ1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR1_11_8 FM(SSI_SCK) FM(TCLK3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR1_15_12 FM(SSI_WS) FM(TCLK4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR1_19_16 FM(SSI_SD) FM(IRQ0_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR1_23_20 FM(AUDIO_CLKOUT) FM(IRQ1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP2SR1_27_24 FM(AUDIO_CLKIN) FM(PWM3_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR1_31_28 F_(0, 0) FM(TCLK2) FM(MSIOF4_SS1) FM(IRQ3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR1_31_28 F_(0, 0) FM(TCLK2_A) FM(MSIOF4_SS1) FM(IRQ3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP3SR1 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP3SR1_3_0 FM(HRX3) FM(SCK3_A) FM(MSIOF4_SS2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP3SR1_7_4 FM(HSCK3) FM(CTS3_N_A) FM(MSIOF4_SCK) FM(TPU0TO0_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP3SR1_11_8 FM(HRTS3_N) FM(RTS3_N_A) FM(MSIOF4_TXD) FM(TPU0TO1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP3SR1_15_12 FM(HCTS3_N) FM(RX3_A) FM(MSIOF4_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP3SR1_19_16 FM(HTX3) FM(TX3_A) FM(MSIOF4_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP3SR1_3_0 FM(HRX3_A) FM(SCK3_A) FM(MSIOF4_SS2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP3SR1_7_4 FM(HSCK3_A) FM(CTS3_N_A) FM(MSIOF4_SCK) FM(TPU0TO0_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP3SR1_11_8 FM(HRTS3_N_A) FM(RTS3_N_A) FM(MSIOF4_TXD) FM(TPU0TO1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP3SR1_15_12 FM(HCTS3_N_A) FM(RX3_A) FM(MSIOF4_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP3SR1_19_16 FM(HTX3_A) FM(TX3_A) FM(MSIOF4_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* SR2 */ /* IP0SR2 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP0SR2_3_0 FM(FXR_TXDA) FM(CANFD1_TX) FM(TPU0TO2_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR2_7_4 FM(FXR_TXENA_N) FM(CANFD1_RX) FM(TPU0TO3_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR2_11_8 FM(RXDA_EXTFXR) FM(CANFD5_TX) FM(IRQ5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR2_15_12 FM(CLK_EXTFXR) FM(CANFD5_RX) FM(IRQ4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR2_3_0 FM(FXR_TXDA) FM(CANFD1_TX) FM(TPU0TO2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR2_7_4 FM(FXR_TXENA_N_A) FM(CANFD1_RX) FM(TPU0TO3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR2_11_8 FM(RXDA_EXTFXR) FM(CANFD5_TX_A) FM(IRQ5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR2_15_12 FM(CLK_EXTFXR) FM(CANFD5_RX_A) FM(IRQ4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR2_19_16 FM(RXDB_EXTFXR) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR2_23_20 FM(FXR_TXENB_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR2_23_20 FM(FXR_TXENB_N_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR2_27_24 FM(FXR_TXDB) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR2_31_28 FM(TPU0TO1) FM(CANFD6_TX) F_(0, 0) FM(TCLK2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR2_31_28 FM(TPU0TO1_A) FM(CANFD6_TX) F_(0, 0) FM(TCLK2_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP1SR2 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP1SR2_3_0 FM(TPU0TO0) FM(CANFD6_RX) F_(0, 0) FM(TCLK1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_7_4 FM(CAN_CLK) FM(FXR_TXENA_N_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_11_8 FM(CANFD0_TX) FM(FXR_TXENB_N_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_3_0 FM(TPU0TO0_A) FM(CANFD6_RX) F_(0, 0) FM(TCLK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_7_4 FM(CAN_CLK) FM(FXR_TXENA_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_11_8 FM(CANFD0_TX) FM(FXR_TXENB_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_15_12 FM(CANFD0_RX) FM(STPWT_EXTFXR) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_19_16 FM(CANFD2_TX) FM(TPU0TO2) F_(0, 0) FM(TCLK3_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_23_20 FM(CANFD2_RX) FM(TPU0TO3) FM(PWM1_B) FM(TCLK4_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_27_24 FM(CANFD3_TX) F_(0, 0) FM(PWM2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_19_16 FM(CANFD2_TX) FM(TPU0TO2_A) F_(0, 0) FM(TCLK3_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_23_20 FM(CANFD2_RX) FM(TPU0TO3_A) FM(PWM1_B) FM(TCLK4_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_27_24 FM(CANFD3_TX) F_(0, 0) FM(PWM2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_31_28 FM(CANFD3_RX) F_(0, 0) FM(PWM3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP2SR2 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ @@ -381,8 +381,8 @@ #define IP1SR3_11_8 FM(MMC_SD_CMD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR3_15_12 FM(SD_CD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR3_19_16 FM(SD_WP) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR3_23_20 FM(IPC_CLKIN) FM(IPC_CLKEN_IN) FM(PWM1_A) FM(TCLK3_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR3_27_24 FM(IPC_CLKOUT) FM(IPC_CLKEN_OUT) FM(ERROROUTC_N_A) FM(TCLK4_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR3_23_20 FM(IPC_CLKIN) FM(IPC_CLKEN_IN) FM(PWM1_A) FM(TCLK3_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR3_27_24 FM(IPC_CLKOUT) FM(IPC_CLKEN_OUT) FM(ERROROUTC_N_A) FM(TCLK4_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR3_31_28 FM(QSPI0_SSL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP2SR3 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ @@ -718,22 +718,22 @@ static const u16 pinmux_data[] = { /* IP0SR0 */ PINMUX_IPSR_GPSR(IP0SR0_3_0, ERROROUTC_N_B), - PINMUX_IPSR_GPSR(IP0SR0_3_0, TCLK2_A), + PINMUX_IPSR_GPSR(IP0SR0_3_0, TCLK2_B), PINMUX_IPSR_GPSR(IP0SR0_7_4, MSIOF3_SS1), PINMUX_IPSR_GPSR(IP0SR0_11_8, MSIOF3_SS2), - PINMUX_IPSR_GPSR(IP0SR0_15_12, IRQ3), + PINMUX_IPSR_GPSR(IP0SR0_15_12, IRQ3_A), PINMUX_IPSR_GPSR(IP0SR0_15_12, MSIOF3_SCK), - PINMUX_IPSR_GPSR(IP0SR0_19_16, IRQ2), + PINMUX_IPSR_GPSR(IP0SR0_19_16, IRQ2_A), PINMUX_IPSR_GPSR(IP0SR0_19_16, MSIOF3_TXD), - PINMUX_IPSR_GPSR(IP0SR0_23_20, IRQ1), + PINMUX_IPSR_GPSR(IP0SR0_23_20, IRQ1_A), PINMUX_IPSR_GPSR(IP0SR0_23_20, MSIOF3_RXD), - PINMUX_IPSR_GPSR(IP0SR0_27_24, IRQ0), + PINMUX_IPSR_GPSR(IP0SR0_27_24, IRQ0_A), PINMUX_IPSR_GPSR(IP0SR0_27_24, MSIOF3_SYNC), PINMUX_IPSR_GPSR(IP0SR0_31_28, MSIOF5_SS2), @@ -750,75 +750,75 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1SR0_19_16, MSIOF5_RXD), PINMUX_IPSR_GPSR(IP1SR0_23_20, MSIOF2_SS2), - PINMUX_IPSR_GPSR(IP1SR0_23_20, TCLK1), - PINMUX_IPSR_GPSR(IP1SR0_23_20, IRQ2_A), + PINMUX_IPSR_GPSR(IP1SR0_23_20, TCLK1_A), + PINMUX_IPSR_GPSR(IP1SR0_23_20, IRQ2_B), PINMUX_IPSR_GPSR(IP1SR0_27_24, MSIOF2_SS1), - PINMUX_IPSR_GPSR(IP1SR0_27_24, HTX1), - PINMUX_IPSR_GPSR(IP1SR0_27_24, TX1), + PINMUX_IPSR_GPSR(IP1SR0_27_24, HTX1_A), + PINMUX_IPSR_GPSR(IP1SR0_27_24, TX1_A), PINMUX_IPSR_GPSR(IP1SR0_31_28, MSIOF2_SYNC), - PINMUX_IPSR_GPSR(IP1SR0_31_28, HRX1), - PINMUX_IPSR_GPSR(IP1SR0_31_28, RX1), + PINMUX_IPSR_GPSR(IP1SR0_31_28, HRX1_A), + PINMUX_IPSR_GPSR(IP1SR0_31_28, RX1_A), /* IP2SR0 */ PINMUX_IPSR_GPSR(IP2SR0_3_0, MSIOF2_TXD), - PINMUX_IPSR_GPSR(IP2SR0_3_0, HCTS1_N), - PINMUX_IPSR_GPSR(IP2SR0_3_0, CTS1_N), + PINMUX_IPSR_GPSR(IP2SR0_3_0, HCTS1_N_A), + PINMUX_IPSR_GPSR(IP2SR0_3_0, CTS1_N_A), PINMUX_IPSR_GPSR(IP2SR0_7_4, MSIOF2_SCK), - PINMUX_IPSR_GPSR(IP2SR0_7_4, HRTS1_N), - PINMUX_IPSR_GPSR(IP2SR0_7_4, RTS1_N), + PINMUX_IPSR_GPSR(IP2SR0_7_4, HRTS1_N_A), + PINMUX_IPSR_GPSR(IP2SR0_7_4, RTS1_N_A), PINMUX_IPSR_GPSR(IP2SR0_11_8, MSIOF2_RXD), - PINMUX_IPSR_GPSR(IP2SR0_11_8, HSCK1), - PINMUX_IPSR_GPSR(IP2SR0_11_8, SCK1), + PINMUX_IPSR_GPSR(IP2SR0_11_8, HSCK1_A), + PINMUX_IPSR_GPSR(IP2SR0_11_8, SCK1_A), /* IP0SR1 */ PINMUX_IPSR_GPSR(IP0SR1_3_0, MSIOF1_SS2), - PINMUX_IPSR_GPSR(IP0SR1_3_0, HTX3_A), - PINMUX_IPSR_GPSR(IP0SR1_3_0, TX3), + PINMUX_IPSR_GPSR(IP0SR1_3_0, HTX3_B), + PINMUX_IPSR_GPSR(IP0SR1_3_0, TX3_B), PINMUX_IPSR_GPSR(IP0SR1_7_4, MSIOF1_SS1), - PINMUX_IPSR_GPSR(IP0SR1_7_4, HCTS3_N_A), - PINMUX_IPSR_GPSR(IP0SR1_7_4, RX3), + PINMUX_IPSR_GPSR(IP0SR1_7_4, HCTS3_N_B), + PINMUX_IPSR_GPSR(IP0SR1_7_4, RX3_B), PINMUX_IPSR_GPSR(IP0SR1_11_8, MSIOF1_SYNC), - PINMUX_IPSR_GPSR(IP0SR1_11_8, HRTS3_N_A), - PINMUX_IPSR_GPSR(IP0SR1_11_8, RTS3_N), + PINMUX_IPSR_GPSR(IP0SR1_11_8, HRTS3_N_B), + PINMUX_IPSR_GPSR(IP0SR1_11_8, RTS3_N_B), PINMUX_IPSR_GPSR(IP0SR1_15_12, MSIOF1_SCK), - PINMUX_IPSR_GPSR(IP0SR1_15_12, HSCK3_A), - PINMUX_IPSR_GPSR(IP0SR1_15_12, CTS3_N), + PINMUX_IPSR_GPSR(IP0SR1_15_12, HSCK3_B), + PINMUX_IPSR_GPSR(IP0SR1_15_12, CTS3_N_B), PINMUX_IPSR_GPSR(IP0SR1_19_16, MSIOF1_TXD), - PINMUX_IPSR_GPSR(IP0SR1_19_16, HRX3_A), - PINMUX_IPSR_GPSR(IP0SR1_19_16, SCK3), + PINMUX_IPSR_GPSR(IP0SR1_19_16, HRX3_B), + PINMUX_IPSR_GPSR(IP0SR1_19_16, SCK3_B), PINMUX_IPSR_GPSR(IP0SR1_23_20, MSIOF1_RXD), PINMUX_IPSR_GPSR(IP0SR1_27_24, MSIOF0_SS2), - PINMUX_IPSR_GPSR(IP0SR1_27_24, HTX1_X), - PINMUX_IPSR_GPSR(IP0SR1_27_24, TX1_X), + PINMUX_IPSR_GPSR(IP0SR1_27_24, HTX1_B), + PINMUX_IPSR_GPSR(IP0SR1_27_24, TX1_B), PINMUX_IPSR_GPSR(IP0SR1_31_28, MSIOF0_SS1), - PINMUX_IPSR_GPSR(IP0SR1_31_28, HRX1_X), - PINMUX_IPSR_GPSR(IP0SR1_31_28, RX1_X), + PINMUX_IPSR_GPSR(IP0SR1_31_28, HRX1_B), + PINMUX_IPSR_GPSR(IP0SR1_31_28, RX1_B), /* IP1SR1 */ PINMUX_IPSR_GPSR(IP1SR1_3_0, MSIOF0_SYNC), - PINMUX_IPSR_GPSR(IP1SR1_3_0, HCTS1_N_X), - PINMUX_IPSR_GPSR(IP1SR1_3_0, CTS1_N_X), + PINMUX_IPSR_GPSR(IP1SR1_3_0, HCTS1_N_B), + PINMUX_IPSR_GPSR(IP1SR1_3_0, CTS1_N_B), PINMUX_IPSR_GPSR(IP1SR1_3_0, CANFD5_TX_B), PINMUX_IPSR_GPSR(IP1SR1_7_4, MSIOF0_TXD), - PINMUX_IPSR_GPSR(IP1SR1_7_4, HRTS1_N_X), - PINMUX_IPSR_GPSR(IP1SR1_7_4, RTS1_N_X), + PINMUX_IPSR_GPSR(IP1SR1_7_4, HRTS1_N_B), + PINMUX_IPSR_GPSR(IP1SR1_7_4, RTS1_N_B), PINMUX_IPSR_GPSR(IP1SR1_7_4, CANFD5_RX_B), PINMUX_IPSR_GPSR(IP1SR1_11_8, MSIOF0_SCK), - PINMUX_IPSR_GPSR(IP1SR1_11_8, HSCK1_X), - PINMUX_IPSR_GPSR(IP1SR1_11_8, SCK1_X), + PINMUX_IPSR_GPSR(IP1SR1_11_8, HSCK1_B), + PINMUX_IPSR_GPSR(IP1SR1_11_8, SCK1_B), PINMUX_IPSR_GPSR(IP1SR1_15_12, MSIOF0_RXD), @@ -827,15 +827,15 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1SR1_23_20, HCTS0_N), PINMUX_IPSR_GPSR(IP1SR1_23_20, CTS0_N), - PINMUX_IPSR_GPSR(IP1SR1_23_20, PWM8_A), + PINMUX_IPSR_GPSR(IP1SR1_23_20, PWM8), PINMUX_IPSR_GPSR(IP1SR1_27_24, HRTS0_N), PINMUX_IPSR_GPSR(IP1SR1_27_24, RTS0_N), - PINMUX_IPSR_GPSR(IP1SR1_27_24, PWM9_A), + PINMUX_IPSR_GPSR(IP1SR1_27_24, PWM9), PINMUX_IPSR_GPSR(IP1SR1_31_28, HSCK0), PINMUX_IPSR_GPSR(IP1SR1_31_28, SCK0), - PINMUX_IPSR_GPSR(IP1SR1_31_28, PWM0_A), + PINMUX_IPSR_GPSR(IP1SR1_31_28, PWM0), /* IP2SR1 */ PINMUX_IPSR_GPSR(IP2SR1_3_0, HRX0), @@ -845,99 +845,99 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP2SR1_7_4, IRQ4_A), PINMUX_IPSR_GPSR(IP2SR1_11_8, SSI_SCK), - PINMUX_IPSR_GPSR(IP2SR1_11_8, TCLK3), + PINMUX_IPSR_GPSR(IP2SR1_11_8, TCLK3_B), PINMUX_IPSR_GPSR(IP2SR1_15_12, SSI_WS), - PINMUX_IPSR_GPSR(IP2SR1_15_12, TCLK4), + PINMUX_IPSR_GPSR(IP2SR1_15_12, TCLK4_B), PINMUX_IPSR_GPSR(IP2SR1_19_16, SSI_SD), - PINMUX_IPSR_GPSR(IP2SR1_19_16, IRQ0_A), + PINMUX_IPSR_GPSR(IP2SR1_19_16, IRQ0_B), PINMUX_IPSR_GPSR(IP2SR1_23_20, AUDIO_CLKOUT), - PINMUX_IPSR_GPSR(IP2SR1_23_20, IRQ1_A), + PINMUX_IPSR_GPSR(IP2SR1_23_20, IRQ1_B), PINMUX_IPSR_GPSR(IP2SR1_27_24, AUDIO_CLKIN), PINMUX_IPSR_GPSR(IP2SR1_27_24, PWM3_A), - PINMUX_IPSR_GPSR(IP2SR1_31_28, TCLK2), + PINMUX_IPSR_GPSR(IP2SR1_31_28, TCLK2_A), PINMUX_IPSR_GPSR(IP2SR1_31_28, MSIOF4_SS1), PINMUX_IPSR_GPSR(IP2SR1_31_28, IRQ3_B), /* IP3SR1 */ - PINMUX_IPSR_GPSR(IP3SR1_3_0, HRX3), + PINMUX_IPSR_GPSR(IP3SR1_3_0, HRX3_A), PINMUX_IPSR_GPSR(IP3SR1_3_0, SCK3_A), PINMUX_IPSR_GPSR(IP3SR1_3_0, MSIOF4_SS2), - PINMUX_IPSR_GPSR(IP3SR1_7_4, HSCK3), + PINMUX_IPSR_GPSR(IP3SR1_7_4, HSCK3_A), PINMUX_IPSR_GPSR(IP3SR1_7_4, CTS3_N_A), PINMUX_IPSR_GPSR(IP3SR1_7_4, MSIOF4_SCK), - PINMUX_IPSR_GPSR(IP3SR1_7_4, TPU0TO0_A), + PINMUX_IPSR_GPSR(IP3SR1_7_4, TPU0TO0_B), - PINMUX_IPSR_GPSR(IP3SR1_11_8, HRTS3_N), + PINMUX_IPSR_GPSR(IP3SR1_11_8, HRTS3_N_A), PINMUX_IPSR_GPSR(IP3SR1_11_8, RTS3_N_A), PINMUX_IPSR_GPSR(IP3SR1_11_8, MSIOF4_TXD), - PINMUX_IPSR_GPSR(IP3SR1_11_8, TPU0TO1_A), + PINMUX_IPSR_GPSR(IP3SR1_11_8, TPU0TO1_B), - PINMUX_IPSR_GPSR(IP3SR1_15_12, HCTS3_N), + PINMUX_IPSR_GPSR(IP3SR1_15_12, HCTS3_N_A), PINMUX_IPSR_GPSR(IP3SR1_15_12, RX3_A), PINMUX_IPSR_GPSR(IP3SR1_15_12, MSIOF4_RXD), - PINMUX_IPSR_GPSR(IP3SR1_19_16, HTX3), + PINMUX_IPSR_GPSR(IP3SR1_19_16, HTX3_A), PINMUX_IPSR_GPSR(IP3SR1_19_16, TX3_A), PINMUX_IPSR_GPSR(IP3SR1_19_16, MSIOF4_SYNC), /* IP0SR2 */ PINMUX_IPSR_GPSR(IP0SR2_3_0, FXR_TXDA), PINMUX_IPSR_GPSR(IP0SR2_3_0, CANFD1_TX), - PINMUX_IPSR_GPSR(IP0SR2_3_0, TPU0TO2_A), + PINMUX_IPSR_GPSR(IP0SR2_3_0, TPU0TO2_B), - PINMUX_IPSR_GPSR(IP0SR2_7_4, FXR_TXENA_N), + PINMUX_IPSR_GPSR(IP0SR2_7_4, FXR_TXENA_N_A), PINMUX_IPSR_GPSR(IP0SR2_7_4, CANFD1_RX), - PINMUX_IPSR_GPSR(IP0SR2_7_4, TPU0TO3_A), + PINMUX_IPSR_GPSR(IP0SR2_7_4, TPU0TO3_B), PINMUX_IPSR_GPSR(IP0SR2_11_8, RXDA_EXTFXR), - PINMUX_IPSR_GPSR(IP0SR2_11_8, CANFD5_TX), + PINMUX_IPSR_GPSR(IP0SR2_11_8, CANFD5_TX_A), PINMUX_IPSR_GPSR(IP0SR2_11_8, IRQ5), PINMUX_IPSR_GPSR(IP0SR2_15_12, CLK_EXTFXR), - PINMUX_IPSR_GPSR(IP0SR2_15_12, CANFD5_RX), + PINMUX_IPSR_GPSR(IP0SR2_15_12, CANFD5_RX_A), PINMUX_IPSR_GPSR(IP0SR2_15_12, IRQ4_B), PINMUX_IPSR_GPSR(IP0SR2_19_16, RXDB_EXTFXR), - PINMUX_IPSR_GPSR(IP0SR2_23_20, FXR_TXENB_N), + PINMUX_IPSR_GPSR(IP0SR2_23_20, FXR_TXENB_N_A), PINMUX_IPSR_GPSR(IP0SR2_27_24, FXR_TXDB), - PINMUX_IPSR_GPSR(IP0SR2_31_28, TPU0TO1), + PINMUX_IPSR_GPSR(IP0SR2_31_28, TPU0TO1_A), PINMUX_IPSR_GPSR(IP0SR2_31_28, CANFD6_TX), - PINMUX_IPSR_GPSR(IP0SR2_31_28, TCLK2_B), + PINMUX_IPSR_GPSR(IP0SR2_31_28, TCLK2_C), /* IP1SR2 */ - PINMUX_IPSR_GPSR(IP1SR2_3_0, TPU0TO0), + PINMUX_IPSR_GPSR(IP1SR2_3_0, TPU0TO0_A), PINMUX_IPSR_GPSR(IP1SR2_3_0, CANFD6_RX), - PINMUX_IPSR_GPSR(IP1SR2_3_0, TCLK1_A), + PINMUX_IPSR_GPSR(IP1SR2_3_0, TCLK1_B), PINMUX_IPSR_GPSR(IP1SR2_7_4, CAN_CLK), - PINMUX_IPSR_GPSR(IP1SR2_7_4, FXR_TXENA_N_X), + PINMUX_IPSR_GPSR(IP1SR2_7_4, FXR_TXENA_N_B), PINMUX_IPSR_GPSR(IP1SR2_11_8, CANFD0_TX), - PINMUX_IPSR_GPSR(IP1SR2_11_8, FXR_TXENB_N_X), + PINMUX_IPSR_GPSR(IP1SR2_11_8, FXR_TXENB_N_B), PINMUX_IPSR_GPSR(IP1SR2_15_12, CANFD0_RX), PINMUX_IPSR_GPSR(IP1SR2_15_12, STPWT_EXTFXR), PINMUX_IPSR_GPSR(IP1SR2_19_16, CANFD2_TX), - PINMUX_IPSR_GPSR(IP1SR2_19_16, TPU0TO2), - PINMUX_IPSR_GPSR(IP1SR2_19_16, TCLK3_A), + PINMUX_IPSR_GPSR(IP1SR2_19_16, TPU0TO2_A), + PINMUX_IPSR_GPSR(IP1SR2_19_16, TCLK3_C), PINMUX_IPSR_GPSR(IP1SR2_23_20, CANFD2_RX), - PINMUX_IPSR_GPSR(IP1SR2_23_20, TPU0TO3), + PINMUX_IPSR_GPSR(IP1SR2_23_20, TPU0TO3_A), PINMUX_IPSR_GPSR(IP1SR2_23_20, PWM1_B), - PINMUX_IPSR_GPSR(IP1SR2_23_20, TCLK4_A), + PINMUX_IPSR_GPSR(IP1SR2_23_20, TCLK4_C), PINMUX_IPSR_GPSR(IP1SR2_27_24, CANFD3_TX), - PINMUX_IPSR_GPSR(IP1SR2_27_24, PWM2_B), + PINMUX_IPSR_GPSR(IP1SR2_27_24, PWM2), PINMUX_IPSR_GPSR(IP1SR2_31_28, CANFD3_RX), PINMUX_IPSR_GPSR(IP1SR2_31_28, PWM3_B), @@ -979,12 +979,12 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1SR3_23_20, IPC_CLKIN), PINMUX_IPSR_GPSR(IP1SR3_23_20, IPC_CLKEN_IN), PINMUX_IPSR_GPSR(IP1SR3_23_20, PWM1_A), - PINMUX_IPSR_GPSR(IP1SR3_23_20, TCLK3_X), + PINMUX_IPSR_GPSR(IP1SR3_23_20, TCLK3_A), PINMUX_IPSR_GPSR(IP1SR3_27_24, IPC_CLKOUT), PINMUX_IPSR_GPSR(IP1SR3_27_24, IPC_CLKEN_OUT), PINMUX_IPSR_GPSR(IP1SR3_27_24, ERROROUTC_N_A), - PINMUX_IPSR_GPSR(IP1SR3_27_24, TCLK4_X), + PINMUX_IPSR_GPSR(IP1SR3_27_24, TCLK4_A), PINMUX_IPSR_GPSR(IP1SR3_31_28, QSPI0_SSL), @@ -1531,15 +1531,14 @@ static const unsigned int canfd4_data_mux[] = { }; /* - CANFD5 ----------------------------------------------------------------- */ -static const unsigned int canfd5_data_pins[] = { - /* CANFD5_TX, CANFD5_RX */ +static const unsigned int canfd5_data_a_pins[] = { + /* CANFD5_TX_A, CANFD5_RX_A */ RCAR_GP_PIN(2, 2), RCAR_GP_PIN(2, 3), }; -static const unsigned int canfd5_data_mux[] = { - CANFD5_TX_MARK, CANFD5_RX_MARK, +static const unsigned int canfd5_data_a_mux[] = { + CANFD5_TX_A_MARK, CANFD5_RX_A_MARK, }; -/* - CANFD5_B ----------------------------------------------------------------- */ static const unsigned int canfd5_data_b_pins[] = { /* CANFD5_TX_B, CANFD5_RX_B */ RCAR_GP_PIN(1, 8), RCAR_GP_PIN(1, 9), @@ -1599,49 +1598,48 @@ static const unsigned int hscif0_ctrl_mux[] = { }; /* - HSCIF1 ----------------------------------------------------------------- */ -static const unsigned int hscif1_data_pins[] = { - /* HRX1, HTX1 */ +static const unsigned int hscif1_data_a_pins[] = { + /* HRX1_A, HTX1_A */ RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 14), }; -static const unsigned int hscif1_data_mux[] = { - HRX1_MARK, HTX1_MARK, +static const unsigned int hscif1_data_a_mux[] = { + HRX1_A_MARK, HTX1_A_MARK, }; -static const unsigned int hscif1_clk_pins[] = { - /* HSCK1 */ +static const unsigned int hscif1_clk_a_pins[] = { + /* HSCK1_A */ RCAR_GP_PIN(0, 18), }; -static const unsigned int hscif1_clk_mux[] = { - HSCK1_MARK, +static const unsigned int hscif1_clk_a_mux[] = { + HSCK1_A_MARK, }; -static const unsigned int hscif1_ctrl_pins[] = { - /* HRTS1_N, HCTS1_N */ +static const unsigned int hscif1_ctrl_a_pins[] = { + /* HRTS1_N_A, HCTS1_N_A */ RCAR_GP_PIN(0, 17), RCAR_GP_PIN(0, 16), }; -static const unsigned int hscif1_ctrl_mux[] = { - HRTS1_N_MARK, HCTS1_N_MARK, +static const unsigned int hscif1_ctrl_a_mux[] = { + HRTS1_N_A_MARK, HCTS1_N_A_MARK, }; -/* - HSCIF1_X---------------------------------------------------------------- */ -static const unsigned int hscif1_data_x_pins[] = { - /* HRX1_X, HTX1_X */ +static const unsigned int hscif1_data_b_pins[] = { + /* HRX1_B, HTX1_B */ RCAR_GP_PIN(1, 7), RCAR_GP_PIN(1, 6), }; -static const unsigned int hscif1_data_x_mux[] = { - HRX1_X_MARK, HTX1_X_MARK, +static const unsigned int hscif1_data_b_mux[] = { + HRX1_B_MARK, HTX1_B_MARK, }; -static const unsigned int hscif1_clk_x_pins[] = { - /* HSCK1_X */ +static const unsigned int hscif1_clk_b_pins[] = { + /* HSCK1_B */ RCAR_GP_PIN(1, 10), }; -static const unsigned int hscif1_clk_x_mux[] = { - HSCK1_X_MARK, +static const unsigned int hscif1_clk_b_mux[] = { + HSCK1_B_MARK, }; -static const unsigned int hscif1_ctrl_x_pins[] = { - /* HRTS1_N_X, HCTS1_N_X */ +static const unsigned int hscif1_ctrl_b_pins[] = { + /* HRTS1_N_B, HCTS1_N_B */ RCAR_GP_PIN(1, 9), RCAR_GP_PIN(1, 8), }; -static const unsigned int hscif1_ctrl_x_mux[] = { - HRTS1_N_X_MARK, HCTS1_N_X_MARK, +static const unsigned int hscif1_ctrl_b_mux[] = { + HRTS1_N_B_MARK, HCTS1_N_B_MARK, }; /* - HSCIF2 ----------------------------------------------------------------- */ @@ -1668,51 +1666,50 @@ static const unsigned int hscif2_ctrl_mux[] = { }; /* - HSCIF3 ----------------------------------------------------------------- */ -static const unsigned int hscif3_data_pins[] = { - /* HRX3, HTX3 */ - RCAR_GP_PIN(1, 24), RCAR_GP_PIN(1, 28), -}; -static const unsigned int hscif3_data_mux[] = { - HRX3_MARK, HTX3_MARK, -}; -static const unsigned int hscif3_clk_pins[] = { - /* HSCK3 */ - RCAR_GP_PIN(1, 25), -}; -static const unsigned int hscif3_clk_mux[] = { - HSCK3_MARK, -}; -static const unsigned int hscif3_ctrl_pins[] = { - /* HRTS3_N, HCTS3_N */ - RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 27), -}; -static const unsigned int hscif3_ctrl_mux[] = { - HRTS3_N_MARK, HCTS3_N_MARK, -}; - -/* - HSCIF3_A ----------------------------------------------------------------- */ static const unsigned int hscif3_data_a_pins[] = { /* HRX3_A, HTX3_A */ - RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 0), + RCAR_GP_PIN(1, 24), RCAR_GP_PIN(1, 28), }; static const unsigned int hscif3_data_a_mux[] = { HRX3_A_MARK, HTX3_A_MARK, }; static const unsigned int hscif3_clk_a_pins[] = { /* HSCK3_A */ - RCAR_GP_PIN(1, 3), + RCAR_GP_PIN(1, 25), }; static const unsigned int hscif3_clk_a_mux[] = { HSCK3_A_MARK, }; static const unsigned int hscif3_ctrl_a_pins[] = { /* HRTS3_N_A, HCTS3_N_A */ - RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 1), + RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 27), }; static const unsigned int hscif3_ctrl_a_mux[] = { HRTS3_N_A_MARK, HCTS3_N_A_MARK, }; +static const unsigned int hscif3_data_b_pins[] = { + /* HRX3_B, HTX3_B */ + RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 0), +}; +static const unsigned int hscif3_data_b_mux[] = { + HRX3_B_MARK, HTX3_B_MARK, +}; +static const unsigned int hscif3_clk_b_pins[] = { + /* HSCK3_B */ + RCAR_GP_PIN(1, 3), +}; +static const unsigned int hscif3_clk_b_mux[] = { + HSCK3_B_MARK, +}; +static const unsigned int hscif3_ctrl_b_pins[] = { + /* HRTS3_N_B, HCTS3_N_B */ + RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 1), +}; +static const unsigned int hscif3_ctrl_b_mux[] = { + HRTS3_N_B_MARK, HCTS3_N_B_MARK, +}; + /* - I2C0 ------------------------------------------------------------------- */ static const unsigned int i2c0_pins[] = { /* SDA0, SCL0 */ @@ -1767,6 +1764,90 @@ static const unsigned int i2c5_mux[] = { SDA5_MARK, SCL5_MARK, }; +/* - INTC-EX ---------------------------------------------------------------- */ +static const unsigned int intc_ex_irq0_a_pins[] = { + /* IRQ0_A */ + RCAR_GP_PIN(0, 6), +}; +static const unsigned int intc_ex_irq0_a_mux[] = { + IRQ0_A_MARK, +}; +static const unsigned int intc_ex_irq0_b_pins[] = { + /* IRQ0_B */ + RCAR_GP_PIN(1, 20), +}; +static const unsigned int intc_ex_irq0_b_mux[] = { + IRQ0_B_MARK, +}; + +static const unsigned int intc_ex_irq1_a_pins[] = { + /* IRQ1_A */ + RCAR_GP_PIN(0, 5), +}; +static const unsigned int intc_ex_irq1_a_mux[] = { + IRQ1_A_MARK, +}; +static const unsigned int intc_ex_irq1_b_pins[] = { + /* IRQ1_B */ + RCAR_GP_PIN(1, 21), +}; +static const unsigned int intc_ex_irq1_b_mux[] = { + IRQ1_B_MARK, +}; + +static const unsigned int intc_ex_irq2_a_pins[] = { + /* IRQ2_A */ + RCAR_GP_PIN(0, 4), +}; +static const unsigned int intc_ex_irq2_a_mux[] = { + IRQ2_A_MARK, +}; +static const unsigned int intc_ex_irq2_b_pins[] = { + /* IRQ2_B */ + RCAR_GP_PIN(0, 13), +}; +static const unsigned int intc_ex_irq2_b_mux[] = { + IRQ2_B_MARK, +}; + +static const unsigned int intc_ex_irq3_a_pins[] = { + /* IRQ3_A */ + RCAR_GP_PIN(0, 3), +}; +static const unsigned int intc_ex_irq3_a_mux[] = { + IRQ3_A_MARK, +}; +static const unsigned int intc_ex_irq3_b_pins[] = { + /* IRQ3_B */ + RCAR_GP_PIN(1, 23), +}; +static const unsigned int intc_ex_irq3_b_mux[] = { + IRQ3_B_MARK, +}; + +static const unsigned int intc_ex_irq4_a_pins[] = { + /* IRQ4_A */ + RCAR_GP_PIN(1, 17), +}; +static const unsigned int intc_ex_irq4_a_mux[] = { + IRQ4_A_MARK, +}; +static const unsigned int intc_ex_irq4_b_pins[] = { + /* IRQ4_B */ + RCAR_GP_PIN(2, 3), +}; +static const unsigned int intc_ex_irq4_b_mux[] = { + IRQ4_B_MARK, +}; + +static const unsigned int intc_ex_irq5_pins[] = { + /* IRQ5 */ + RCAR_GP_PIN(2, 2), +}; +static const unsigned int intc_ex_irq5_mux[] = { + IRQ5_MARK, +}; + /* - MMC -------------------------------------------------------------------- */ static const unsigned int mmc_data_pins[] = { /* MMC_SD_D[0:3], MMC_D[4:7] */ @@ -2093,16 +2174,16 @@ static const unsigned int pcie1_clkreq_n_mux[] = { PCIE1_CLKREQ_N_MARK, }; -/* - PWM0_A ------------------------------------------------------------------- */ -static const unsigned int pwm0_a_pins[] = { - /* PWM0_A */ +/* - PWM0 ------------------------------------------------------------------- */ +static const unsigned int pwm0_pins[] = { + /* PWM0 */ RCAR_GP_PIN(1, 15), }; -static const unsigned int pwm0_a_mux[] = { - PWM0_A_MARK, +static const unsigned int pwm0_mux[] = { + PWM0_MARK, }; -/* - PWM1_A ------------------------------------------------------------------- */ +/* - PWM1 ------------------------------------------------------------------- */ static const unsigned int pwm1_a_pins[] = { /* PWM1_A */ RCAR_GP_PIN(3, 13), @@ -2111,7 +2192,6 @@ static const unsigned int pwm1_a_mux[] = { PWM1_A_MARK, }; -/* - PWM1_B ------------------------------------------------------------------- */ static const unsigned int pwm1_b_pins[] = { /* PWM1_B */ RCAR_GP_PIN(2, 13), @@ -2120,16 +2200,16 @@ static const unsigned int pwm1_b_mux[] = { PWM1_B_MARK, }; -/* - PWM2_B ------------------------------------------------------------------- */ -static const unsigned int pwm2_b_pins[] = { - /* PWM2_B */ +/* - PWM2 ------------------------------------------------------------------- */ +static const unsigned int pwm2_pins[] = { + /* PWM2 */ RCAR_GP_PIN(2, 14), }; -static const unsigned int pwm2_b_mux[] = { - PWM2_B_MARK, +static const unsigned int pwm2_mux[] = { + PWM2_MARK, }; -/* - PWM3_A ------------------------------------------------------------------- */ +/* - PWM3 ------------------------------------------------------------------- */ static const unsigned int pwm3_a_pins[] = { /* PWM3_A */ RCAR_GP_PIN(1, 22), @@ -2138,7 +2218,6 @@ static const unsigned int pwm3_a_mux[] = { PWM3_A_MARK, }; -/* - PWM3_B ------------------------------------------------------------------- */ static const unsigned int pwm3_b_pins[] = { /* PWM3_B */ RCAR_GP_PIN(2, 15), @@ -2183,22 +2262,22 @@ static const unsigned int pwm7_mux[] = { PWM7_MARK, }; -/* - PWM8_A ------------------------------------------------------------------- */ -static const unsigned int pwm8_a_pins[] = { - /* PWM8_A */ +/* - PWM8 ------------------------------------------------------------------- */ +static const unsigned int pwm8_pins[] = { + /* PWM8 */ RCAR_GP_PIN(1, 13), }; -static const unsigned int pwm8_a_mux[] = { - PWM8_A_MARK, +static const unsigned int pwm8_mux[] = { + PWM8_MARK, }; -/* - PWM9_A ------------------------------------------------------------------- */ -static const unsigned int pwm9_a_pins[] = { - /* PWM9_A */ +/* - PWM9 ------------------------------------------------------------------- */ +static const unsigned int pwm9_pins[] = { + /* PWM9 */ RCAR_GP_PIN(1, 14), }; -static const unsigned int pwm9_a_mux[] = { - PWM9_A_MARK, +static const unsigned int pwm9_mux[] = { + PWM9_MARK, }; /* - QSPI0 ------------------------------------------------------------------ */ @@ -2261,75 +2340,51 @@ static const unsigned int scif0_ctrl_mux[] = { }; /* - SCIF1 ------------------------------------------------------------------ */ -static const unsigned int scif1_data_pins[] = { - /* RX1, TX1 */ +static const unsigned int scif1_data_a_pins[] = { + /* RX1_A, TX1_A */ RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 14), }; -static const unsigned int scif1_data_mux[] = { - RX1_MARK, TX1_MARK, +static const unsigned int scif1_data_a_mux[] = { + RX1_A_MARK, TX1_A_MARK, }; -static const unsigned int scif1_clk_pins[] = { - /* SCK1 */ +static const unsigned int scif1_clk_a_pins[] = { + /* SCK1_A */ RCAR_GP_PIN(0, 18), }; -static const unsigned int scif1_clk_mux[] = { - SCK1_MARK, +static const unsigned int scif1_clk_a_mux[] = { + SCK1_A_MARK, }; -static const unsigned int scif1_ctrl_pins[] = { - /* RTS1_N, CTS1_N */ +static const unsigned int scif1_ctrl_a_pins[] = { + /* RTS1_N_A, CTS1_N_A */ RCAR_GP_PIN(0, 17), RCAR_GP_PIN(0, 16), }; -static const unsigned int scif1_ctrl_mux[] = { - RTS1_N_MARK, CTS1_N_MARK, +static const unsigned int scif1_ctrl_a_mux[] = { + RTS1_N_A_MARK, CTS1_N_A_MARK, }; -/* - SCIF1_X ------------------------------------------------------------------ */ -static const unsigned int scif1_data_x_pins[] = { - /* RX1_X, TX1_X */ +static const unsigned int scif1_data_b_pins[] = { + /* RX1_B, TX1_B */ RCAR_GP_PIN(1, 7), RCAR_GP_PIN(1, 6), }; -static const unsigned int scif1_data_x_mux[] = { - RX1_X_MARK, TX1_X_MARK, +static const unsigned int scif1_data_b_mux[] = { + RX1_B_MARK, TX1_B_MARK, }; -static const unsigned int scif1_clk_x_pins[] = { - /* SCK1_X */ +static const unsigned int scif1_clk_b_pins[] = { + /* SCK1_B */ RCAR_GP_PIN(1, 10), }; -static const unsigned int scif1_clk_x_mux[] = { - SCK1_X_MARK, +static const unsigned int scif1_clk_b_mux[] = { + SCK1_B_MARK, }; -static const unsigned int scif1_ctrl_x_pins[] = { - /* RTS1_N_X, CTS1_N_X */ +static const unsigned int scif1_ctrl_b_pins[] = { + /* RTS1_N_B, CTS1_N_B */ RCAR_GP_PIN(1, 9), RCAR_GP_PIN(1, 8), }; -static const unsigned int scif1_ctrl_x_mux[] = { - RTS1_N_X_MARK, CTS1_N_X_MARK, +static const unsigned int scif1_ctrl_b_mux[] = { + RTS1_N_B_MARK, CTS1_N_B_MARK, }; /* - SCIF3 ------------------------------------------------------------------ */ -static const unsigned int scif3_data_pins[] = { - /* RX3, TX3 */ - RCAR_GP_PIN(1, 1), RCAR_GP_PIN(1, 0), -}; -static const unsigned int scif3_data_mux[] = { - RX3_MARK, TX3_MARK, -}; -static const unsigned int scif3_clk_pins[] = { - /* SCK3 */ - RCAR_GP_PIN(1, 4), -}; -static const unsigned int scif3_clk_mux[] = { - SCK3_MARK, -}; -static const unsigned int scif3_ctrl_pins[] = { - /* RTS3_N, CTS3_N */ - RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3), -}; -static const unsigned int scif3_ctrl_mux[] = { - RTS3_N_MARK, CTS3_N_MARK, -}; - -/* - SCIF3_A ------------------------------------------------------------------ */ static const unsigned int scif3_data_a_pins[] = { /* RX3_A, TX3_A */ RCAR_GP_PIN(1, 27), RCAR_GP_PIN(1, 28), @@ -2352,6 +2407,28 @@ static const unsigned int scif3_ctrl_a_mux[] = { RTS3_N_A_MARK, CTS3_N_A_MARK, }; +static const unsigned int scif3_data_b_pins[] = { + /* RX3_B, TX3_B */ + RCAR_GP_PIN(1, 1), RCAR_GP_PIN(1, 0), +}; +static const unsigned int scif3_data_b_mux[] = { + RX3_B_MARK, TX3_B_MARK, +}; +static const unsigned int scif3_clk_b_pins[] = { + /* SCK3_B */ + RCAR_GP_PIN(1, 4), +}; +static const unsigned int scif3_clk_b_mux[] = { + SCK3_B_MARK, +}; +static const unsigned int scif3_ctrl_b_pins[] = { + /* RTS3_N_B, CTS3_N_B */ + RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3), +}; +static const unsigned int scif3_ctrl_b_mux[] = { + RTS3_N_B_MARK, CTS3_N_B_MARK, +}; + /* - SCIF4 ------------------------------------------------------------------ */ static const unsigned int scif4_data_pins[] = { /* RX4, TX4 */ @@ -2408,66 +2485,65 @@ static const unsigned int ssi_ctrl_mux[] = { SSI_SCK_MARK, SSI_WS_MARK, }; -/* - TPU ------------------------------------------------------------------- */ -static const unsigned int tpu_to0_pins[] = { - /* TPU0TO0 */ - RCAR_GP_PIN(2, 8), -}; -static const unsigned int tpu_to0_mux[] = { - TPU0TO0_MARK, -}; -static const unsigned int tpu_to1_pins[] = { - /* TPU0TO1 */ - RCAR_GP_PIN(2, 7), -}; -static const unsigned int tpu_to1_mux[] = { - TPU0TO1_MARK, -}; -static const unsigned int tpu_to2_pins[] = { - /* TPU0TO2 */ - RCAR_GP_PIN(2, 12), -}; -static const unsigned int tpu_to2_mux[] = { - TPU0TO2_MARK, -}; -static const unsigned int tpu_to3_pins[] = { - /* TPU0TO3 */ - RCAR_GP_PIN(2, 13), -}; -static const unsigned int tpu_to3_mux[] = { - TPU0TO3_MARK, -}; - -/* - TPU_A ------------------------------------------------------------------- */ +/* - TPU -------------------------------------------------------------------- */ static const unsigned int tpu_to0_a_pins[] = { /* TPU0TO0_A */ - RCAR_GP_PIN(1, 25), + RCAR_GP_PIN(2, 8), }; static const unsigned int tpu_to0_a_mux[] = { TPU0TO0_A_MARK, }; static const unsigned int tpu_to1_a_pins[] = { /* TPU0TO1_A */ - RCAR_GP_PIN(1, 26), + RCAR_GP_PIN(2, 7), }; static const unsigned int tpu_to1_a_mux[] = { TPU0TO1_A_MARK, }; static const unsigned int tpu_to2_a_pins[] = { /* TPU0TO2_A */ - RCAR_GP_PIN(2, 0), + RCAR_GP_PIN(2, 12), }; static const unsigned int tpu_to2_a_mux[] = { TPU0TO2_A_MARK, }; static const unsigned int tpu_to3_a_pins[] = { /* TPU0TO3_A */ - RCAR_GP_PIN(2, 1), + RCAR_GP_PIN(2, 13), }; static const unsigned int tpu_to3_a_mux[] = { TPU0TO3_A_MARK, }; +static const unsigned int tpu_to0_b_pins[] = { + /* TPU0TO0_B */ + RCAR_GP_PIN(1, 25), +}; +static const unsigned int tpu_to0_b_mux[] = { + TPU0TO0_B_MARK, +}; +static const unsigned int tpu_to1_b_pins[] = { + /* TPU0TO1_B */ + RCAR_GP_PIN(1, 26), +}; +static const unsigned int tpu_to1_b_mux[] = { + TPU0TO1_B_MARK, +}; +static const unsigned int tpu_to2_b_pins[] = { + /* TPU0TO2_B */ + RCAR_GP_PIN(2, 0), +}; +static const unsigned int tpu_to2_b_mux[] = { + TPU0TO2_B_MARK, +}; +static const unsigned int tpu_to3_b_pins[] = { + /* TPU0TO3_B */ + RCAR_GP_PIN(2, 1), +}; +static const unsigned int tpu_to3_b_mux[] = { + TPU0TO3_B_MARK, +}; + /* - TSN0 ------------------------------------------------ */ static const unsigned int tsn0_link_pins[] = { /* TSN0_LINK */ @@ -2578,8 +2654,8 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(canfd2_data), SH_PFC_PIN_GROUP(canfd3_data), SH_PFC_PIN_GROUP(canfd4_data), - SH_PFC_PIN_GROUP(canfd5_data), /* suffix might be updated */ - SH_PFC_PIN_GROUP(canfd5_data_b), /* suffix might be updated */ + SH_PFC_PIN_GROUP(canfd5_data_a), + SH_PFC_PIN_GROUP(canfd5_data_b), SH_PFC_PIN_GROUP(canfd6_data), SH_PFC_PIN_GROUP(canfd7_data), SH_PFC_PIN_GROUP(can_clk), @@ -2587,21 +2663,21 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(hscif0_data), SH_PFC_PIN_GROUP(hscif0_clk), SH_PFC_PIN_GROUP(hscif0_ctrl), - SH_PFC_PIN_GROUP(hscif1_data), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif1_clk), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif1_ctrl), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif1_data_x), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif1_clk_x), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif1_ctrl_x), /* suffix might be updated */ + SH_PFC_PIN_GROUP(hscif1_data_a), + SH_PFC_PIN_GROUP(hscif1_clk_a), + SH_PFC_PIN_GROUP(hscif1_ctrl_a), + SH_PFC_PIN_GROUP(hscif1_data_b), + SH_PFC_PIN_GROUP(hscif1_clk_b), + SH_PFC_PIN_GROUP(hscif1_ctrl_b), SH_PFC_PIN_GROUP(hscif2_data), SH_PFC_PIN_GROUP(hscif2_clk), SH_PFC_PIN_GROUP(hscif2_ctrl), - SH_PFC_PIN_GROUP(hscif3_data), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif3_clk), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif3_ctrl), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif3_data_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif3_clk_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif3_ctrl_a), /* suffix might be updated */ + SH_PFC_PIN_GROUP(hscif3_data_a), + SH_PFC_PIN_GROUP(hscif3_clk_a), + SH_PFC_PIN_GROUP(hscif3_ctrl_a), + SH_PFC_PIN_GROUP(hscif3_data_b), + SH_PFC_PIN_GROUP(hscif3_clk_b), + SH_PFC_PIN_GROUP(hscif3_ctrl_b), SH_PFC_PIN_GROUP(i2c0), SH_PFC_PIN_GROUP(i2c1), @@ -2610,6 +2686,18 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(i2c4), SH_PFC_PIN_GROUP(i2c5), + SH_PFC_PIN_GROUP(intc_ex_irq0_a), + SH_PFC_PIN_GROUP(intc_ex_irq0_b), + SH_PFC_PIN_GROUP(intc_ex_irq1_a), + SH_PFC_PIN_GROUP(intc_ex_irq1_b), + SH_PFC_PIN_GROUP(intc_ex_irq2_a), + SH_PFC_PIN_GROUP(intc_ex_irq2_b), + SH_PFC_PIN_GROUP(intc_ex_irq3_a), + SH_PFC_PIN_GROUP(intc_ex_irq3_b), + SH_PFC_PIN_GROUP(intc_ex_irq4_a), + SH_PFC_PIN_GROUP(intc_ex_irq4_b), + SH_PFC_PIN_GROUP(intc_ex_irq5), + BUS_DATA_PIN_GROUP(mmc_data, 1), BUS_DATA_PIN_GROUP(mmc_data, 4), BUS_DATA_PIN_GROUP(mmc_data, 8), @@ -2663,18 +2751,18 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(pcie0_clkreq_n), SH_PFC_PIN_GROUP(pcie1_clkreq_n), - SH_PFC_PIN_GROUP(pwm0_a), /* suffix might be updated */ + SH_PFC_PIN_GROUP(pwm0), SH_PFC_PIN_GROUP(pwm1_a), SH_PFC_PIN_GROUP(pwm1_b), - SH_PFC_PIN_GROUP(pwm2_b), /* suffix might be updated */ + SH_PFC_PIN_GROUP(pwm2), SH_PFC_PIN_GROUP(pwm3_a), SH_PFC_PIN_GROUP(pwm3_b), SH_PFC_PIN_GROUP(pwm4), SH_PFC_PIN_GROUP(pwm5), SH_PFC_PIN_GROUP(pwm6), SH_PFC_PIN_GROUP(pwm7), - SH_PFC_PIN_GROUP(pwm8_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(pwm9_a), /* suffix might be updated */ + SH_PFC_PIN_GROUP(pwm8), + SH_PFC_PIN_GROUP(pwm9), SH_PFC_PIN_GROUP(qspi0_ctrl), BUS_DATA_PIN_GROUP(qspi0_data, 2), @@ -2686,18 +2774,18 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(scif0_data), SH_PFC_PIN_GROUP(scif0_clk), SH_PFC_PIN_GROUP(scif0_ctrl), - SH_PFC_PIN_GROUP(scif1_data), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif1_clk), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif1_ctrl), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif1_data_x), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif1_clk_x), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif1_ctrl_x), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif3_data), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif3_clk), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif3_ctrl), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif3_data_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif3_clk_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif3_ctrl_a), /* suffix might be updated */ + SH_PFC_PIN_GROUP(scif1_data_a), + SH_PFC_PIN_GROUP(scif1_clk_a), + SH_PFC_PIN_GROUP(scif1_ctrl_a), + SH_PFC_PIN_GROUP(scif1_data_b), + SH_PFC_PIN_GROUP(scif1_clk_b), + SH_PFC_PIN_GROUP(scif1_ctrl_b), + SH_PFC_PIN_GROUP(scif3_data_a), + SH_PFC_PIN_GROUP(scif3_clk_a), + SH_PFC_PIN_GROUP(scif3_ctrl_a), + SH_PFC_PIN_GROUP(scif3_data_b), + SH_PFC_PIN_GROUP(scif3_clk_b), + SH_PFC_PIN_GROUP(scif3_ctrl_b), SH_PFC_PIN_GROUP(scif4_data), SH_PFC_PIN_GROUP(scif4_clk), SH_PFC_PIN_GROUP(scif4_ctrl), @@ -2707,14 +2795,14 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(ssi_data), SH_PFC_PIN_GROUP(ssi_ctrl), - SH_PFC_PIN_GROUP(tpu_to0), /* suffix might be updated */ - SH_PFC_PIN_GROUP(tpu_to0_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(tpu_to1), /* suffix might be updated */ - SH_PFC_PIN_GROUP(tpu_to1_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(tpu_to2), /* suffix might be updated */ - SH_PFC_PIN_GROUP(tpu_to2_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(tpu_to3), /* suffix might be updated */ - SH_PFC_PIN_GROUP(tpu_to3_a), /* suffix might be updated */ + SH_PFC_PIN_GROUP(tpu_to0_a), + SH_PFC_PIN_GROUP(tpu_to0_b), + SH_PFC_PIN_GROUP(tpu_to1_a), + SH_PFC_PIN_GROUP(tpu_to1_b), + SH_PFC_PIN_GROUP(tpu_to2_a), + SH_PFC_PIN_GROUP(tpu_to2_b), + SH_PFC_PIN_GROUP(tpu_to3_a), + SH_PFC_PIN_GROUP(tpu_to3_b), SH_PFC_PIN_GROUP(tsn0_link), SH_PFC_PIN_GROUP(tsn0_phy_int), @@ -2788,8 +2876,7 @@ static const char * const canfd4_groups[] = { }; static const char * const canfd5_groups[] = { - /* suffix might be updated */ - "canfd5_data", + "canfd5_data_a", "canfd5_data_b", }; @@ -2812,13 +2899,12 @@ static const char * const hscif0_groups[] = { }; static const char * const hscif1_groups[] = { - /* suffix might be updated */ - "hscif1_data", - "hscif1_clk", - "hscif1_ctrl", - "hscif1_data_x", - "hscif1_clk_x", - "hscif1_ctrl_x", + "hscif1_data_a", + "hscif1_clk_a", + "hscif1_ctrl_a", + "hscif1_data_b", + "hscif1_clk_b", + "hscif1_ctrl_b", }; static const char * const hscif2_groups[] = { @@ -2828,13 +2914,12 @@ static const char * const hscif2_groups[] = { }; static const char * const hscif3_groups[] = { - /* suffix might be updated */ - "hscif3_data", - "hscif3_clk", - "hscif3_ctrl", "hscif3_data_a", "hscif3_clk_a", "hscif3_ctrl_a", + "hscif3_data_b", + "hscif3_clk_b", + "hscif3_ctrl_b", }; static const char * const i2c0_groups[] = { @@ -2861,6 +2946,20 @@ static const char * const i2c5_groups[] = { "i2c5", }; +static const char * const intc_ex_groups[] = { + "intc_ex_irq0_a", + "intc_ex_irq0_b", + "intc_ex_irq1_a", + "intc_ex_irq1_b", + "intc_ex_irq2_a", + "intc_ex_irq2_b", + "intc_ex_irq3_a", + "intc_ex_irq3_b", + "intc_ex_irq4_a", + "intc_ex_irq4_b", + "intc_ex_irq5", +}; + static const char * const mmc_groups[] = { "mmc_data1", "mmc_data4", @@ -2931,8 +3030,7 @@ static const char * const pcie_groups[] = { }; static const char * const pwm0_groups[] = { - /* suffix might be updated */ - "pwm0_a", + "pwm0", }; static const char * const pwm1_groups[] = { @@ -2941,8 +3039,7 @@ static const char * const pwm1_groups[] = { }; static const char * const pwm2_groups[] = { - /* suffix might be updated */ - "pwm2_b", + "pwm2", }; static const char * const pwm3_groups[] = { @@ -2967,13 +3064,11 @@ static const char * const pwm7_groups[] = { }; static const char * const pwm8_groups[] = { - /* suffix might be updated */ - "pwm8_a", + "pwm8", }; static const char * const pwm9_groups[] = { - /* suffix might be updated */ - "pwm9_a", + "pwm9", }; static const char * const qspi0_groups[] = { @@ -2995,23 +3090,21 @@ static const char * const scif0_groups[] = { }; static const char * const scif1_groups[] = { - /* suffix might be updated */ - "scif1_data", - "scif1_clk", - "scif1_ctrl", - "scif1_data_x", - "scif1_clk_x", - "scif1_ctrl_x", + "scif1_data_a", + "scif1_clk_a", + "scif1_ctrl_a", + "scif1_data_b", + "scif1_clk_b", + "scif1_ctrl_b", }; static const char * const scif3_groups[] = { - /* suffix might be updated */ - "scif3_data", - "scif3_clk", - "scif3_ctrl", "scif3_data_a", "scif3_clk_a", "scif3_ctrl_a", + "scif3_data_b", + "scif3_clk_b", + "scif3_ctrl_b", }; static const char * const scif4_groups[] = { @@ -3034,15 +3127,14 @@ static const char * const ssi_groups[] = { }; static const char * const tpu_groups[] = { - /* suffix might be updated */ - "tpu_to0", "tpu_to0_a", - "tpu_to1", + "tpu_to0_b", "tpu_to1_a", - "tpu_to2", + "tpu_to1_b", "tpu_to2_a", - "tpu_to3", + "tpu_to2_b", "tpu_to3_a", + "tpu_to3_b", }; static const char * const tsn0_groups[] = { @@ -3085,6 +3177,8 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(i2c4), SH_PFC_FUNCTION(i2c5), + SH_PFC_FUNCTION(intc_ex), + SH_PFC_FUNCTION(mmc), SH_PFC_FUNCTION(msiof0), diff --git a/drivers/pinctrl/renesas/pfc-r8a779h0.c b/drivers/pinctrl/renesas/pfc-r8a779h0.c index 438d1f2739dd..48b1eef250d9 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779h0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779h0.c @@ -1236,6 +1236,30 @@ static const unsigned int avb0_mdio_pins[] = { static const unsigned int avb0_mdio_mux[] = { AVB0_MDC_MARK, AVB0_MDIO_MARK, }; +static const unsigned int avb0_mii_pins[] = { + /* + * AVB0_MII_TD0, AVB0_MII_TD1, AVB0_MII_TD2, + * AVB0_MII_TD3, AVB0_MII_RD0, AVB0_MII_RD1, + * AVB0_MII_RD2, AVB0_MII_RD3, AVB0_MII_TXC, + * AVB0_MII_TX_EN, AVB0_MII_TX_ER, AVB0_MII_RXC, + * AVB0_MII_RX_DV, AVB0_MII_RX_ER, AVB0_MII_CRS, + * AVB0_MII_COL + */ + RCAR_GP_PIN(7, 11), RCAR_GP_PIN(7, 7), RCAR_GP_PIN(7, 6), + RCAR_GP_PIN(7, 3), RCAR_GP_PIN(7, 18), RCAR_GP_PIN(7, 17), + RCAR_GP_PIN(7, 12), RCAR_GP_PIN(7, 8), RCAR_GP_PIN(7, 15), + RCAR_GP_PIN(7, 16), RCAR_GP_PIN(7, 4), RCAR_GP_PIN(7, 19), + RCAR_GP_PIN(7, 20), RCAR_GP_PIN(7, 2), RCAR_GP_PIN(7, 1), + RCAR_GP_PIN(7, 0), +}; +static const unsigned int avb0_mii_mux[] = { + AVB0_MII_TD0_MARK, AVB0_MII_TD1_MARK, AVB0_MII_TD2_MARK, + AVB0_MII_TD3_MARK, AVB0_MII_RD0_MARK, AVB0_MII_RD1_MARK, + AVB0_MII_RD2_MARK, AVB0_MII_RD3_MARK, AVB0_MII_TXC_MARK, + AVB0_MII_TX_EN_MARK, AVB0_MII_TX_ER_MARK, AVB0_MII_RXC_MARK, + AVB0_MII_RX_DV_MARK, AVB0_MII_RX_ER_MARK, AVB0_MII_CRS_MARK, + AVB0_MII_COL_MARK, +}; static const unsigned int avb0_rgmii_pins[] = { /* * AVB0_TX_CTL, AVB0_TXC, AVB0_TD0, AVB0_TD1, AVB0_TD2, AVB0_TD3, @@ -1314,6 +1338,30 @@ static const unsigned int avb1_mdio_pins[] = { static const unsigned int avb1_mdio_mux[] = { AVB1_MDC_MARK, AVB1_MDIO_MARK, }; +static const unsigned int avb1_mii_pins[] = { + /* + * AVB1_MII_TD0, AVB1_MII_TD1, AVB1_MII_TD2, + * AVB1_MII_TD3, AVB1_MII_RD0, AVB1_MII_RD1, + * AVB1_MII_RD2, AVB1_MII_RD3, AVB1_MII_TXC, + * AVB1_MII_TX_EN, AVB1_MII_TX_ER, AVB1_MII_RXC, + * AVB1_MII_RX_DV, AVB1_MII_RX_ER, AVB1_MII_CRS, + * AVB1_MII_COL + */ + RCAR_GP_PIN(6, 13), RCAR_GP_PIN(6, 12), RCAR_GP_PIN(6, 16), + RCAR_GP_PIN(6, 18), RCAR_GP_PIN(6, 15), RCAR_GP_PIN(6, 14), + RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 19), RCAR_GP_PIN(6, 6), + RCAR_GP_PIN(6, 7), RCAR_GP_PIN(6, 4), RCAR_GP_PIN(6, 8), + RCAR_GP_PIN(6, 9), RCAR_GP_PIN(6, 5), RCAR_GP_PIN(6, 11), + RCAR_GP_PIN(6, 10), +}; +static const unsigned int avb1_mii_mux[] = { + AVB1_MII_TD0_MARK, AVB1_MII_TD1_MARK, AVB1_MII_TD2_MARK, + AVB1_MII_TD3_MARK, AVB1_MII_RD0_MARK, AVB1_MII_RD1_MARK, + AVB1_MII_RD2_MARK, AVB1_MII_RD3_MARK, AVB1_MII_TXC_MARK, + AVB1_MII_TX_EN_MARK, AVB1_MII_TX_ER_MARK, AVB1_MII_RXC_MARK, + AVB1_MII_RX_DV_MARK, AVB1_MII_RX_ER_MARK, AVB1_MII_CRS_MARK, + AVB1_MII_COL_MARK, +}; static const unsigned int avb1_rgmii_pins[] = { /* * AVB1_TX_CTL, AVB1_TXC, AVB1_TD0, AVB1_TD1, AVB1_TD2, AVB1_TD3, @@ -1509,7 +1557,7 @@ static const unsigned int hscif0_ctrl_mux[] = { HRTS0_N_MARK, HCTS0_N_MARK, }; -/* - HSCIF1_A ----------------------------------------------------------------- */ +/* - HSCIF1 ------------------------------------------------------------------- */ static const unsigned int hscif1_data_a_pins[] = { /* HRX1_A, HTX1_A */ RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 14), @@ -1532,7 +1580,6 @@ static const unsigned int hscif1_ctrl_a_mux[] = { HRTS1_N_A_MARK, HCTS1_N_A_MARK, }; -/* - HSCIF1_B ---------------------------------------------------------------- */ static const unsigned int hscif1_data_b_pins[] = { /* HRX1_B, HTX1_B */ RCAR_GP_PIN(1, 7), RCAR_GP_PIN(1, 6), @@ -1578,7 +1625,7 @@ static const unsigned int hscif2_ctrl_mux[] = { HRTS2_N_MARK, HCTS2_N_MARK, }; -/* - HSCIF3_A ----------------------------------------------------------------- */ +/* - HSCIF3 ------------------------------------------------------------------- */ static const unsigned int hscif3_data_a_pins[] = { /* HRX3_A, HTX3_A */ RCAR_GP_PIN(1, 24), RCAR_GP_PIN(1, 28), @@ -1601,7 +1648,6 @@ static const unsigned int hscif3_ctrl_a_mux[] = { HRTS3_N_A_MARK, HCTS3_N_A_MARK, }; -/* - HSCIF3_B ----------------------------------------------------------------- */ static const unsigned int hscif3_data_b_pins[] = { /* HRX3_B, HTX3_B */ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 0), @@ -2061,7 +2107,7 @@ static const unsigned int pcie0_clkreq_n_mux[] = { PCIE0_CLKREQ_N_MARK, }; -/* - PWM0_A ------------------------------------------------------------------- */ +/* - PWM0 --------------------------------------------------------------------- */ static const unsigned int pwm0_a_pins[] = { /* PWM0_A */ RCAR_GP_PIN(1, 15), @@ -2070,7 +2116,6 @@ static const unsigned int pwm0_a_mux[] = { PWM0_A_MARK, }; -/* - PWM0_B ------------------------------------------------------------------- */ static const unsigned int pwm0_b_pins[] = { /* PWM0_B */ RCAR_GP_PIN(1, 14), @@ -2079,7 +2124,7 @@ static const unsigned int pwm0_b_mux[] = { PWM0_B_MARK, }; -/* - PWM1_A ------------------------------------------------------------------- */ +/* - PWM1 --------------------------------------------------------------------- */ static const unsigned int pwm1_a_pins[] = { /* PWM1_A */ RCAR_GP_PIN(3, 13), @@ -2088,7 +2133,6 @@ static const unsigned int pwm1_a_mux[] = { PWM1_A_MARK, }; -/* - PWM1_B ------------------------------------------------------------------- */ static const unsigned int pwm1_b_pins[] = { /* PWM1_B */ RCAR_GP_PIN(2, 13), @@ -2097,7 +2141,6 @@ static const unsigned int pwm1_b_mux[] = { PWM1_B_MARK, }; -/* - PWM1_C ------------------------------------------------------------------- */ static const unsigned int pwm1_c_pins[] = { /* PWM1_C */ RCAR_GP_PIN(2, 17), @@ -2106,7 +2149,7 @@ static const unsigned int pwm1_c_mux[] = { PWM1_C_MARK, }; -/* - PWM2_A ------------------------------------------------------------------- */ +/* - PWM2 --------------------------------------------------------------------- */ static const unsigned int pwm2_a_pins[] = { /* PWM2_A */ RCAR_GP_PIN(3, 14), @@ -2115,7 +2158,6 @@ static const unsigned int pwm2_a_mux[] = { PWM2_A_MARK, }; -/* - PWM2_B ------------------------------------------------------------------- */ static const unsigned int pwm2_b_pins[] = { /* PWM2_B */ RCAR_GP_PIN(2, 14), @@ -2124,7 +2166,6 @@ static const unsigned int pwm2_b_mux[] = { PWM2_B_MARK, }; -/* - PWM2_C ------------------------------------------------------------------- */ static const unsigned int pwm2_c_pins[] = { /* PWM2_C */ RCAR_GP_PIN(2, 19), @@ -2133,7 +2174,7 @@ static const unsigned int pwm2_c_mux[] = { PWM2_C_MARK, }; -/* - PWM3_A ------------------------------------------------------------------- */ +/* - PWM3 --------------------------------------------------------------------- */ static const unsigned int pwm3_a_pins[] = { /* PWM3_A */ RCAR_GP_PIN(4, 14), @@ -2142,7 +2183,6 @@ static const unsigned int pwm3_a_mux[] = { PWM3_A_MARK, }; -/* - PWM3_B ------------------------------------------------------------------- */ static const unsigned int pwm3_b_pins[] = { /* PWM3_B */ RCAR_GP_PIN(2, 15), @@ -2151,7 +2191,6 @@ static const unsigned int pwm3_b_mux[] = { PWM3_B_MARK, }; -/* - PWM3_C ------------------------------------------------------------------- */ static const unsigned int pwm3_c_pins[] = { /* PWM3_C */ RCAR_GP_PIN(1, 22), @@ -2228,7 +2267,7 @@ static const unsigned int scif0_ctrl_mux[] = { RTS0_N_MARK, CTS0_N_MARK, }; -/* - SCIF1_A ------------------------------------------------------------------ */ +/* - SCIF1 -------------------------------------------------------------------- */ static const unsigned int scif1_data_a_pins[] = { /* RX1_A, TX1_A */ RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 14), @@ -2251,7 +2290,6 @@ static const unsigned int scif1_ctrl_a_mux[] = { RTS1_N_A_MARK, CTS1_N_A_MARK, }; -/* - SCIF1_B ------------------------------------------------------------------ */ static const unsigned int scif1_data_b_pins[] = { /* RX1_B, TX1_B */ RCAR_GP_PIN(1, 7), RCAR_GP_PIN(1, 6), @@ -2274,7 +2312,7 @@ static const unsigned int scif1_ctrl_b_mux[] = { RTS1_N_B_MARK, CTS1_N_B_MARK, }; -/* - SCIF3_A ------------------------------------------------------------------ */ +/* - SCIF3 -------------------------------------------------------------------- */ static const unsigned int scif3_data_a_pins[] = { /* RX3_A, TX3_A */ RCAR_GP_PIN(1, 27), RCAR_GP_PIN(1, 28), @@ -2297,7 +2335,6 @@ static const unsigned int scif3_ctrl_a_mux[] = { RTS3_N_A_MARK, CTS3_N_A_MARK, }; -/* - SCIF3_B ------------------------------------------------------------------ */ static const unsigned int scif3_data_b_pins[] = { /* RX3_B, TX3_B */ RCAR_GP_PIN(1, 1), RCAR_GP_PIN(1, 0), @@ -2376,7 +2413,7 @@ static const unsigned int ssi_ctrl_mux[] = { SSI_SCK_MARK, SSI_WS_MARK, }; -/* - TPU_A ------------------------------------------------------------------- */ +/* - TPU --------------------------------------------------------------------- */ static const unsigned int tpu_to0_a_pins[] = { /* TPU0TO0_A */ RCAR_GP_PIN(2, 8), @@ -2406,7 +2443,6 @@ static const unsigned int tpu_to3_a_mux[] = { TPU0TO3_A_MARK, }; -/* - TPU_B ------------------------------------------------------------------- */ static const unsigned int tpu_to0_b_pins[] = { /* TPU0TO0_B */ RCAR_GP_PIN(1, 25), @@ -2444,6 +2480,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(avb0_magic), SH_PFC_PIN_GROUP(avb0_phy_int), SH_PFC_PIN_GROUP(avb0_mdio), + SH_PFC_PIN_GROUP(avb0_mii), SH_PFC_PIN_GROUP(avb0_rgmii), SH_PFC_PIN_GROUP(avb0_txcrefclk), SH_PFC_PIN_GROUP(avb0_avtp_pps), @@ -2454,6 +2491,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(avb1_magic), SH_PFC_PIN_GROUP(avb1_phy_int), SH_PFC_PIN_GROUP(avb1_mdio), + SH_PFC_PIN_GROUP(avb1_mii), SH_PFC_PIN_GROUP(avb1_rgmii), SH_PFC_PIN_GROUP(avb1_txcrefclk), SH_PFC_PIN_GROUP(avb1_avtp_pps), @@ -2628,6 +2666,7 @@ static const char * const avb0_groups[] = { "avb0_magic", "avb0_phy_int", "avb0_mdio", + "avb0_mii", "avb0_rgmii", "avb0_txcrefclk", "avb0_avtp_pps", @@ -2640,6 +2679,7 @@ static const char * const avb1_groups[] = { "avb1_magic", "avb1_phy_int", "avb1_mdio", + "avb1_mii", "avb1_rgmii", "avb1_txcrefclk", "avb1_avtp_pps", diff --git a/drivers/pinctrl/renesas/pfc-sh73a0.c b/drivers/pinctrl/renesas/pfc-sh73a0.c index ca5adf2095be..41587233aa44 100644 --- a/drivers/pinctrl/renesas/pfc-sh73a0.c +++ b/drivers/pinctrl/renesas/pfc-sh73a0.c @@ -4024,7 +4024,7 @@ static const struct pinmux_irq pinmux_irqs[] = { static void sh73a0_vccq_mc0_endisable(struct regulator_dev *reg, bool enable) { - struct sh_pfc *pfc = reg->reg_data; + struct sh_pfc *pfc = rdev_get_drvdata(reg); void __iomem *addr = pfc->windows[1].virt + 4; unsigned long flags; u32 value; @@ -4057,7 +4057,7 @@ static int sh73a0_vccq_mc0_disable(struct regulator_dev *reg) static int sh73a0_vccq_mc0_is_enabled(struct regulator_dev *reg) { - struct sh_pfc *pfc = reg->reg_data; + struct sh_pfc *pfc = rdev_get_drvdata(reg); void __iomem *addr = pfc->windows[1].virt + 4; unsigned long flags; u32 value; diff --git a/drivers/pinctrl/renesas/pinctrl-rza1.c b/drivers/pinctrl/renesas/pinctrl-rza1.c index edcbe7c9ad56..6527872813dc 100644 --- a/drivers/pinctrl/renesas/pinctrl-rza1.c +++ b/drivers/pinctrl/renesas/pinctrl-rza1.c @@ -852,7 +852,6 @@ static const struct gpio_chip rza1_gpiochip_template = { */ static int rza1_dt_node_pin_count(struct device_node *np) { - struct device_node *child; struct property *of_pins; unsigned int npins; @@ -861,12 +860,10 @@ static int rza1_dt_node_pin_count(struct device_node *np) return of_pins->length / sizeof(u32); npins = 0; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { of_pins = of_find_property(child, "pinmux", NULL); - if (!of_pins) { - of_node_put(child); + if (!of_pins) return -EINVAL; - } npins += of_pins->length / sizeof(u32); } @@ -986,7 +983,6 @@ static int rza1_dt_node_to_map(struct pinctrl_dev *pctldev, struct rza1_pinctrl *rza1_pctl = pinctrl_dev_get_drvdata(pctldev); struct rza1_mux_conf *mux_confs, *mux_conf; unsigned int *grpins, *grpin; - struct device_node *child; const char *grpname; const char **fngrps; int ret, npins; @@ -1023,13 +1019,11 @@ static int rza1_dt_node_to_map(struct pinctrl_dev *pctldev, ret = rza1_parse_pinmux_node(rza1_pctl, np, mux_conf, grpin); if (ret == -ENOENT) - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { ret = rza1_parse_pinmux_node(rza1_pctl, child, mux_conf, grpin); - if (ret < 0) { - of_node_put(child); + if (ret < 0) return ret; - } grpin += ret; mux_conf += ret; diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index 60be78da9f52..632180570b70 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -57,8 +57,14 @@ #define PIN_CFG_IOLH_C BIT(13) #define PIN_CFG_SOFT_PS BIT(14) #define PIN_CFG_OEN BIT(15) -#define PIN_CFG_VARIABLE BIT(16) -#define PIN_CFG_NOGPIO_INT BIT(17) +#define PIN_CFG_NOGPIO_INT BIT(16) +#define PIN_CFG_NOD BIT(17) /* N-ch Open Drain */ +#define PIN_CFG_SMT BIT(18) /* Schmitt-trigger input control */ +#define PIN_CFG_ELC BIT(19) +#define PIN_CFG_IOLH_RZV2H BIT(20) + +#define RZG2L_SINGLE_PIN BIT_ULL(63) /* Dedicated pin */ +#define RZG2L_VARIABLE_CFG BIT_ULL(62) /* Variable cfg for port pins */ #define RZG2L_MPXED_COMMON_PIN_FUNCS(group) \ (PIN_CFG_IOLH_##group | \ @@ -73,14 +79,19 @@ #define RZG3S_MPXED_PIN_FUNCS(group) (RZG2L_MPXED_COMMON_PIN_FUNCS(group) | \ PIN_CFG_SOFT_PS) +#define RZV2H_MPXED_PIN_FUNCS (RZG2L_MPXED_COMMON_PIN_FUNCS(RZV2H) | \ + PIN_CFG_NOD | \ + PIN_CFG_SR | \ + PIN_CFG_SMT) + #define RZG2L_MPXED_ETH_PIN_FUNCS(x) ((x) | \ PIN_CFG_FILONOFF | \ PIN_CFG_FILNUM | \ PIN_CFG_FILCLKSEL) -#define PIN_CFG_PIN_MAP_MASK GENMASK_ULL(35, 28) -#define PIN_CFG_PIN_REG_MASK GENMASK(27, 20) -#define PIN_CFG_MASK GENMASK(19, 0) +#define PIN_CFG_PIN_MAP_MASK GENMASK_ULL(61, 54) +#define PIN_CFG_PIN_REG_MASK GENMASK_ULL(53, 46) +#define PIN_CFG_MASK GENMASK_ULL(31, 0) /* * m indicates the bitmap of supported pins, a is the register index @@ -89,22 +100,25 @@ #define RZG2L_GPIO_PORT_SPARSE_PACK(m, a, f) (FIELD_PREP_CONST(PIN_CFG_PIN_MAP_MASK, (m)) | \ FIELD_PREP_CONST(PIN_CFG_PIN_REG_MASK, (a)) | \ FIELD_PREP_CONST(PIN_CFG_MASK, (f))) +#define RZG2L_GPIO_PORT_SPARSE_PACK_VARIABLE(m, a) \ + (RZG2L_VARIABLE_CFG | \ + RZG2L_GPIO_PORT_SPARSE_PACK(m, a, 0)) /* * n indicates number of pins in the port, a is the register index * and f is pin configuration capabilities supported. */ #define RZG2L_GPIO_PORT_PACK(n, a, f) RZG2L_GPIO_PORT_SPARSE_PACK((1ULL << (n)) - 1, (a), (f)) +#define RZG2L_GPIO_PORT_PACK_VARIABLE(n, a) (RZG2L_VARIABLE_CFG | \ + RZG2L_GPIO_PORT_PACK(n, a, 0)) +#define RZG2L_SINGLE_PIN_INDEX_MASK GENMASK_ULL(62, 56) +#define RZG2L_SINGLE_PIN_BITS_MASK GENMASK_ULL(55, 53) /* - * BIT(63) indicates dedicated pin, p is the register index while - * referencing to SR/IEN/IOLH/FILxx registers, b is the register bits - * (b * 8) and f is the pin configuration capabilities supported. + * p is the register index while referencing to SR/IEN/IOLH/FILxx + * registers, b is the register bits (b * 8) and f is the pin + * configuration capabilities supported. */ -#define RZG2L_SINGLE_PIN BIT_ULL(63) -#define RZG2L_SINGLE_PIN_INDEX_MASK GENMASK(30, 24) -#define RZG2L_SINGLE_PIN_BITS_MASK GENMASK(22, 20) - #define RZG2L_SINGLE_PIN_PACK(p, b, f) (RZG2L_SINGLE_PIN | \ FIELD_PREP_CONST(RZG2L_SINGLE_PIN_INDEX_MASK, (p)) | \ FIELD_PREP_CONST(RZG2L_SINGLE_PIN_BITS_MASK, (b)) | \ @@ -114,18 +128,28 @@ FIELD_GET(RZG2L_SINGLE_PIN_INDEX_MASK, (cfg)) : \ FIELD_GET(PIN_CFG_PIN_REG_MASK, (cfg))) +#define VARIABLE_PIN_CFG_PIN_MASK GENMASK_ULL(54, 52) +#define VARIABLE_PIN_CFG_PORT_MASK GENMASK_ULL(51, 47) +#define RZG2L_VARIABLE_PIN_CFG_PACK(port, pin, cfg) \ + (FIELD_PREP_CONST(VARIABLE_PIN_CFG_PIN_MASK, (pin)) | \ + FIELD_PREP_CONST(VARIABLE_PIN_CFG_PORT_MASK, (port)) | \ + FIELD_PREP_CONST(PIN_CFG_MASK, (cfg))) + #define P(off) (0x0000 + (off)) #define PM(off) (0x0100 + (off) * 2) #define PMC(off) (0x0200 + (off)) #define PFC(off) (0x0400 + (off) * 4) #define PIN(off) (0x0800 + (off)) #define IOLH(off) (0x1000 + (off) * 8) +#define SR(off) (0x1400 + (off) * 8) #define IEN(off) (0x1800 + (off) * 8) +#define PUPD(off) (0x1C00 + (off) * 8) #define ISEL(off) (0x2C00 + (off) * 8) #define SD_CH(off, ch) ((off) + (ch) * 4) #define ETH_POC(off, ch) ((off) + (ch) * 4) #define QSPI (0x3008) #define ETH_MODE (0x3018) +#define PFC_OEN (0x3C40) /* known on RZ/V2H(P) only */ #define PVDD_2500 2 /* I/O domain voltage 2.5V */ #define PVDD_1800 1 /* I/O domain voltage <= 1.8V */ @@ -133,11 +157,15 @@ #define PWPR_B0WI BIT(7) /* Bit Write Disable */ #define PWPR_PFCWE BIT(6) /* PFC Register Write Enable */ +#define PWPR_REGWE_A BIT(6) /* PFC and PMC Register Write Enable on RZ/V2H(P) */ +#define PWPR_REGWE_B BIT(5) /* OEN Register Write Enable, known only in RZ/V2H(P) */ #define PM_MASK 0x03 #define PFC_MASK 0x07 #define IEN_MASK 0x01 #define IOLH_MASK 0x03 +#define SR_MASK 0x01 +#define PUPD_MASK 0x03 #define PM_INPUT 0x1 #define PM_OUTPUT 0x2 @@ -149,6 +177,19 @@ #define RZG2L_TINT_IRQ_START_INDEX 9 #define RZG2L_PACK_HWIRQ(t, i) (((t) << 16) | (i)) +/* Custom pinconf parameters */ +#define RENESAS_RZV2H_PIN_CONFIG_OUTPUT_IMPEDANCE (PIN_CONFIG_END + 1) + +static const struct pinconf_generic_params renesas_rzv2h_custom_bindings[] = { + { "renesas,output-impedance", RENESAS_RZV2H_PIN_CONFIG_OUTPUT_IMPEDANCE, 1 }, +}; + +#ifdef CONFIG_DEBUG_FS +static const struct pin_config_item renesas_rzv2h_conf_items[] = { + PCONFDUMP(RENESAS_RZV2H_PIN_CONFIG_OUTPUT_IMPEDANCE, "output-impedance", "x", true), +}; +#endif + /* Read/write 8 bits register */ #define RZG2L_PCTRL_REG_ACCESS8(_read, _addr, _val) \ do { \ @@ -234,17 +275,7 @@ struct rzg2l_dedicated_configs { u64 config; }; -/** - * struct rzg2l_variable_pin_cfg - pin data cfg - * @cfg: port pin configuration - * @port: port number - * @pin: port pin - */ -struct rzg2l_variable_pin_cfg { - u32 cfg:20; - u32 port:5; - u32 pin:3; -}; +struct rzg2l_pinctrl; struct rzg2l_pinctrl_data { const char * const *port_pins; @@ -254,8 +285,19 @@ struct rzg2l_pinctrl_data { unsigned int n_port_pins; unsigned int n_dedicated_pins; const struct rzg2l_hwcfg *hwcfg; - const struct rzg2l_variable_pin_cfg *variable_pin_cfg; + const u64 *variable_pin_cfg; unsigned int n_variable_pin_cfg; + unsigned int num_custom_params; + const struct pinconf_generic_params *custom_params; +#ifdef CONFIG_DEBUG_FS + const struct pin_config_item *custom_conf_items; +#endif + void (*pwpr_pfc_lock_unlock)(struct rzg2l_pinctrl *pctrl, bool lock); + void (*pmc_writeb)(struct rzg2l_pinctrl *pctrl, u8 val, u16 offset); + u32 (*oen_read)(struct rzg2l_pinctrl *pctrl, unsigned int _pin); + int (*oen_write)(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen); + int (*hw_to_bias_param)(unsigned int val); + int (*bias_param_to_hw)(enum pin_config_param param); }; /** @@ -322,7 +364,6 @@ struct rzg2l_pinctrl { static const u16 available_ps[] = { 1800, 2500, 3300 }; -#ifdef CONFIG_RISCV static u64 rzg2l_pinctrl_get_variable_pin_cfg(struct rzg2l_pinctrl *pctrl, u64 pincfg, unsigned int port, @@ -331,138 +372,89 @@ static u64 rzg2l_pinctrl_get_variable_pin_cfg(struct rzg2l_pinctrl *pctrl, unsigned int i; for (i = 0; i < pctrl->data->n_variable_pin_cfg; i++) { - if (pctrl->data->variable_pin_cfg[i].port == port && - pctrl->data->variable_pin_cfg[i].pin == pin) - return (pincfg & ~PIN_CFG_VARIABLE) | pctrl->data->variable_pin_cfg[i].cfg; + u64 cfg = pctrl->data->variable_pin_cfg[i]; + + if (FIELD_GET(VARIABLE_PIN_CFG_PORT_MASK, cfg) == port && + FIELD_GET(VARIABLE_PIN_CFG_PIN_MASK, cfg) == pin) + return (pincfg & ~RZG2L_VARIABLE_CFG) | FIELD_GET(PIN_CFG_MASK, cfg); } return 0; } -static const struct rzg2l_variable_pin_cfg r9a07g043f_variable_pin_cfg[] = { - { - .port = 20, - .pin = 0, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_FILONOFF | PIN_CFG_FILNUM | PIN_CFG_FILCLKSEL | - PIN_CFG_IEN | PIN_CFG_NOGPIO_INT, - }, - { - .port = 20, - .pin = 1, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_FILONOFF | PIN_CFG_FILNUM | PIN_CFG_FILCLKSEL | - PIN_CFG_IEN | PIN_CFG_NOGPIO_INT, - }, - { - .port = 20, - .pin = 2, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_FILONOFF | PIN_CFG_FILNUM | PIN_CFG_FILCLKSEL | - PIN_CFG_IEN | PIN_CFG_NOGPIO_INT, - }, - { - .port = 20, - .pin = 3, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_IEN | PIN_CFG_NOGPIO_INT, - }, - { - .port = 20, - .pin = 4, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_IEN | PIN_CFG_NOGPIO_INT, - }, - { - .port = 20, - .pin = 5, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_IEN | PIN_CFG_NOGPIO_INT, - }, - { - .port = 20, - .pin = 6, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_IEN | PIN_CFG_NOGPIO_INT, - }, - { - .port = 20, - .pin = 7, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_IEN | PIN_CFG_NOGPIO_INT, - }, - { - .port = 23, - .pin = 1, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_NOGPIO_INT - }, - { - .port = 23, - .pin = 2, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_NOGPIO_INT, - }, - { - .port = 23, - .pin = 3, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_NOGPIO_INT, - }, - { - .port = 23, - .pin = 4, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_NOGPIO_INT, - }, - { - .port = 23, - .pin = 5, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_NOGPIO_INT, - }, - { - .port = 24, - .pin = 0, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_NOGPIO_INT, - }, - { - .port = 24, - .pin = 1, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_NOGPIO_INT, - }, - { - .port = 24, - .pin = 2, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_NOGPIO_INT, - }, - { - .port = 24, - .pin = 3, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_NOGPIO_INT, - }, - { - .port = 24, - .pin = 4, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_NOGPIO_INT, - }, - { - .port = 24, - .pin = 5, - .cfg = PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | - PIN_CFG_FILONOFF | PIN_CFG_FILNUM | PIN_CFG_FILCLKSEL | - PIN_CFG_NOGPIO_INT, - }, +static const u64 r9a09g057_variable_pin_cfg[] = { + RZG2L_VARIABLE_PIN_CFG_PACK(11, 0, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(11, 1, RZV2H_MPXED_PIN_FUNCS | PIN_CFG_IEN), + RZG2L_VARIABLE_PIN_CFG_PACK(11, 2, RZV2H_MPXED_PIN_FUNCS | PIN_CFG_IEN), + RZG2L_VARIABLE_PIN_CFG_PACK(11, 3, RZV2H_MPXED_PIN_FUNCS | PIN_CFG_IEN), + RZG2L_VARIABLE_PIN_CFG_PACK(11, 4, RZV2H_MPXED_PIN_FUNCS | PIN_CFG_IEN), + RZG2L_VARIABLE_PIN_CFG_PACK(11, 5, RZV2H_MPXED_PIN_FUNCS | PIN_CFG_IEN), +}; + +#ifdef CONFIG_RISCV +static const u64 r9a07g043f_variable_pin_cfg[] = { + RZG2L_VARIABLE_PIN_CFG_PACK(20, 0, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_FILONOFF | PIN_CFG_FILNUM | PIN_CFG_FILCLKSEL | + PIN_CFG_IEN | PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(20, 1, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_FILONOFF | PIN_CFG_FILNUM | PIN_CFG_FILCLKSEL | + PIN_CFG_IEN | PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(20, 2, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_FILONOFF | PIN_CFG_FILNUM | PIN_CFG_FILCLKSEL | + PIN_CFG_IEN | PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(20, 3, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_IEN | PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(20, 4, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_IEN | PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(20, 5, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_IEN | PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(20, 6, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_IEN | PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(20, 7, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_IEN | PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(23, 1, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(23, 2, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(23, 3, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(23, 4, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(23, 5, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(24, 0, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(24, 1, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(24, 2, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(24, 3, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(24, 4, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_NOGPIO_INT), + RZG2L_VARIABLE_PIN_CFG_PACK(24, 5, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | + PIN_CFG_FILONOFF | PIN_CFG_FILNUM | PIN_CFG_FILCLKSEL | + PIN_CFG_NOGPIO_INT), }; #endif +static void rzg2l_pmc_writeb(struct rzg2l_pinctrl *pctrl, u8 val, u16 offset) +{ + writeb(val, pctrl->base + offset); +} + +static void rzv2h_pmc_writeb(struct rzg2l_pinctrl *pctrl, u8 val, u16 offset) +{ + const struct rzg2l_register_offsets *regs = &pctrl->data->hwcfg->regs; + u8 pwpr; + + pwpr = readb(pctrl->base + regs->pwpr); + writeb(pwpr | PWPR_REGWE_A, pctrl->base + regs->pwpr); + writeb(val, pctrl->base + offset); + writeb(pwpr & ~PWPR_REGWE_A, pctrl->base + regs->pwpr); +} + static void rzg2l_pinctrl_set_pfc_mode(struct rzg2l_pinctrl *pctrl, u8 pin, u8 off, u8 func) { - const struct rzg2l_register_offsets *regs = &pctrl->data->hwcfg->regs; unsigned long flags; u32 reg; @@ -473,27 +465,23 @@ static void rzg2l_pinctrl_set_pfc_mode(struct rzg2l_pinctrl *pctrl, reg &= ~(PM_MASK << (pin * 2)); writew(reg, pctrl->base + PM(off)); + pctrl->data->pwpr_pfc_lock_unlock(pctrl, false); + /* Temporarily switch to GPIO mode with PMC register */ reg = readb(pctrl->base + PMC(off)); writeb(reg & ~BIT(pin), pctrl->base + PMC(off)); - /* Set the PWPR register to allow PFC register to write */ - writel(0x0, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=0 */ - writel(PWPR_PFCWE, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=1 */ - /* Select Pin function mode with PFC register */ reg = readl(pctrl->base + PFC(off)); reg &= ~(PFC_MASK << (pin * 4)); writel(reg | (func << (pin * 4)), pctrl->base + PFC(off)); - /* Set the PWPR register to be write-protected */ - writel(0x0, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=0 */ - writel(PWPR_B0WI, pctrl->base + regs->pwpr); /* B0WI=1, PFCWE=0 */ - /* Switch to Peripheral pin function with PMC register */ reg = readb(pctrl->base + PMC(off)); writeb(reg | BIT(pin), pctrl->base + PMC(off)); + pctrl->data->pwpr_pfc_lock_unlock(pctrl, true); + spin_unlock_irqrestore(&pctrl->lock, flags); }; @@ -599,7 +587,7 @@ static int rzg2l_dt_subnode_to_map(struct pinctrl_dev *pctldev, return -EINVAL; } - ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &num_configs); + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, &num_configs); if (ret < 0) return ret; @@ -745,7 +733,6 @@ static int rzg2l_dt_node_to_map(struct pinctrl_dev *pctldev, unsigned int *num_maps) { struct rzg2l_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - struct device_node *child; unsigned int index; int ret; @@ -753,13 +740,11 @@ static int rzg2l_dt_node_to_map(struct pinctrl_dev *pctldev, *num_maps = 0; index = 0; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { ret = rzg2l_dt_subnode_to_map(pctldev, child, np, map, num_maps, &index); - if (ret < 0) { - of_node_put(child); + if (ret < 0) goto done; - } } if (*num_maps == 0) { @@ -1014,53 +999,47 @@ static bool rzg2l_ds_is_supported(struct rzg2l_pinctrl *pctrl, u32 caps, return false; } -static bool rzg2l_oen_is_supported(u32 caps, u8 pin, u8 max_pin) +static int rzg2l_pin_to_oen_bit(struct rzg2l_pinctrl *pctrl, unsigned int _pin) { - if (!(caps & PIN_CFG_OEN)) - return false; + u64 *pin_data = pctrl->desc.pins[_pin].drv_data; + u64 caps = FIELD_GET(PIN_CFG_MASK, *pin_data); + u8 pin = RZG2L_PIN_ID_TO_PIN(_pin); - if (pin > max_pin) - return false; + if (pin > pctrl->data->hwcfg->oen_max_pin) + return -EINVAL; - return true; -} - -static u8 rzg2l_pin_to_oen_bit(u32 offset, u8 pin, u8 max_port) -{ - if (pin) - pin *= 2; - - if (offset / RZG2L_PINS_PER_PORT == max_port) - pin += 1; - - return pin; -} - -static u32 rzg2l_read_oen(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 pin) -{ - u8 max_port = pctrl->data->hwcfg->oen_max_port; - u8 max_pin = pctrl->data->hwcfg->oen_max_pin; - u8 bit; - - if (!rzg2l_oen_is_supported(caps, pin, max_pin)) + /* + * We can determine which Ethernet interface we're dealing with from + * the caps. + */ + if (caps & PIN_CFG_IO_VMC_ETH0) return 0; + if (caps & PIN_CFG_IO_VMC_ETH1) + return 1; - bit = rzg2l_pin_to_oen_bit(offset, pin, max_port); + return -EINVAL; +} + +static u32 rzg2l_read_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin) +{ + int bit; + + bit = rzg2l_pin_to_oen_bit(pctrl, _pin); + if (bit < 0) + return 0; return !(readb(pctrl->base + ETH_MODE) & BIT(bit)); } -static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 pin, u8 oen) +static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen) { - u8 max_port = pctrl->data->hwcfg->oen_max_port; - u8 max_pin = pctrl->data->hwcfg->oen_max_pin; unsigned long flags; - u8 val, bit; + int bit; + u8 val; - if (!rzg2l_oen_is_supported(caps, pin, max_pin)) - return -EINVAL; - - bit = rzg2l_pin_to_oen_bit(offset, pin, max_port); + bit = rzg2l_pin_to_oen_bit(pctrl, _pin); + if (bit < 0) + return bit; spin_lock_irqsave(&pctrl->lock, flags); val = readb(pctrl->base + ETH_MODE); @@ -1074,17 +1053,187 @@ static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 return 0; } +static int rzg3s_pin_to_oen_bit(struct rzg2l_pinctrl *pctrl, unsigned int _pin) +{ + u64 *pin_data = pctrl->desc.pins[_pin].drv_data; + u8 port, pin, bit; + + if (*pin_data & RZG2L_SINGLE_PIN) + return -EINVAL; + + port = RZG2L_PIN_ID_TO_PORT(_pin); + pin = RZG2L_PIN_ID_TO_PIN(_pin); + if (pin > pctrl->data->hwcfg->oen_max_pin) + return -EINVAL; + + bit = pin * 2; + if (port == pctrl->data->hwcfg->oen_max_port) + bit += 1; + + return bit; +} + +static u32 rzg3s_oen_read(struct rzg2l_pinctrl *pctrl, unsigned int _pin) +{ + int bit; + + bit = rzg3s_pin_to_oen_bit(pctrl, _pin); + if (bit < 0) + return bit; + + return !(readb(pctrl->base + ETH_MODE) & BIT(bit)); +} + +static int rzg3s_oen_write(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen) +{ + unsigned long flags; + int bit; + u8 val; + + bit = rzg3s_pin_to_oen_bit(pctrl, _pin); + if (bit < 0) + return bit; + + spin_lock_irqsave(&pctrl->lock, flags); + val = readb(pctrl->base + ETH_MODE); + if (oen) + val &= ~BIT(bit); + else + val |= BIT(bit); + writeb(val, pctrl->base + ETH_MODE); + spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static int rzg2l_hw_to_bias_param(unsigned int bias) +{ + switch (bias) { + case 0: + return PIN_CONFIG_BIAS_DISABLE; + case 1: + return PIN_CONFIG_BIAS_PULL_UP; + case 2: + return PIN_CONFIG_BIAS_PULL_DOWN; + default: + break; + } + + return -EINVAL; +} + +static int rzg2l_bias_param_to_hw(enum pin_config_param param) +{ + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + return 0; + case PIN_CONFIG_BIAS_PULL_UP: + return 1; + case PIN_CONFIG_BIAS_PULL_DOWN: + return 2; + default: + break; + } + + return -EINVAL; +} + +static int rzv2h_hw_to_bias_param(unsigned int bias) +{ + switch (bias) { + case 0: + case 1: + return PIN_CONFIG_BIAS_DISABLE; + case 2: + return PIN_CONFIG_BIAS_PULL_DOWN; + case 3: + return PIN_CONFIG_BIAS_PULL_UP; + default: + break; + } + + return -EINVAL; +} + +static int rzv2h_bias_param_to_hw(enum pin_config_param param) +{ + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + return 0; + case PIN_CONFIG_BIAS_PULL_DOWN: + return 2; + case PIN_CONFIG_BIAS_PULL_UP: + return 3; + default: + break; + } + + return -EINVAL; +} + +static u8 rzv2h_pin_to_oen_bit(struct rzg2l_pinctrl *pctrl, unsigned int _pin) +{ + static const char * const pin_names[] = { "ET0_TXC_TXCLK", "ET1_TXC_TXCLK", + "XSPI0_RESET0N", "XSPI0_CS0N", + "XSPI0_CKN", "XSPI0_CKP" }; + const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[_pin]; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pin_names); i++) { + if (!strcmp(pin_desc->name, pin_names[i])) + return i; + } + + /* Should not happen. */ + return 0; +} + +static u32 rzv2h_oen_read(struct rzg2l_pinctrl *pctrl, unsigned int _pin) +{ + u8 bit; + + bit = rzv2h_pin_to_oen_bit(pctrl, _pin); + + return !(readb(pctrl->base + PFC_OEN) & BIT(bit)); +} + +static int rzv2h_oen_write(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen) +{ + const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg; + const struct rzg2l_register_offsets *regs = &hwcfg->regs; + unsigned long flags; + u8 val, bit; + u8 pwpr; + + bit = rzv2h_pin_to_oen_bit(pctrl, _pin); + spin_lock_irqsave(&pctrl->lock, flags); + val = readb(pctrl->base + PFC_OEN); + if (oen) + val &= ~BIT(bit); + else + val |= BIT(bit); + + pwpr = readb(pctrl->base + regs->pwpr); + writeb(pwpr | PWPR_REGWE_B, pctrl->base + regs->pwpr); + writeb(val, pctrl->base + PFC_OEN); + writeb(pwpr & ~PWPR_REGWE_B, pctrl->base + regs->pwpr); + spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev, unsigned int _pin, unsigned long *config) { struct rzg2l_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - enum pin_config_param param = pinconf_to_config_param(*config); const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg; const struct pinctrl_pin_desc *pin = &pctrl->desc.pins[_pin]; + u32 param = pinconf_to_config_param(*config); u64 *pin_data = pin->drv_data; unsigned int arg = 0; - u32 off, cfg; + u32 off; + u32 cfg; int ret; u8 bit; @@ -1112,7 +1261,9 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev, break; case PIN_CONFIG_OUTPUT_ENABLE: - arg = rzg2l_read_oen(pctrl, cfg, _pin, bit); + if (!pctrl->data->oen_read || !(cfg & PIN_CFG_OEN)) + return -EOPNOTSUPP; + arg = pctrl->data->oen_read(pctrl, _pin); if (!arg) return -EINVAL; break; @@ -1124,6 +1275,30 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev, arg = ret; break; + case PIN_CONFIG_SLEW_RATE: + if (!(cfg & PIN_CFG_SR)) + return -EINVAL; + + arg = rzg2l_read_pin_config(pctrl, SR(off), bit, SR_MASK); + break; + + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + if (!(cfg & PIN_CFG_PUPD)) + return -EINVAL; + + arg = rzg2l_read_pin_config(pctrl, PUPD(off), bit, PUPD_MASK); + ret = pctrl->data->hw_to_bias_param(arg); + if (ret < 0) + return ret; + + if (ret != param) + return -EINVAL; + /* for PIN_CONFIG_BIAS_PULL_UP/DOWN when enabled we just return 1 */ + arg = 1; + break; + case PIN_CONFIG_DRIVE_STRENGTH: { unsigned int index; @@ -1167,6 +1342,13 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev, break; } + case RENESAS_RZV2H_PIN_CONFIG_OUTPUT_IMPEDANCE: + if (!(cfg & PIN_CFG_IOLH_RZV2H)) + return -EINVAL; + + arg = rzg2l_read_pin_config(pctrl, IOLH(off), bit, IOLH_MASK); + break; + default: return -ENOTSUPP; } @@ -1186,9 +1368,9 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev, const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg; struct rzg2l_pinctrl_pin_settings settings = pctrl->settings[_pin]; u64 *pin_data = pin->drv_data; - enum pin_config_param param; unsigned int i, arg, index; - u32 cfg, off; + u32 off, param; + u32 cfg; int ret; u8 bit; @@ -1220,7 +1402,9 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev, case PIN_CONFIG_OUTPUT_ENABLE: arg = pinconf_to_config_argument(_configs[i]); - ret = rzg2l_write_oen(pctrl, cfg, _pin, bit, !!arg); + if (!pctrl->data->oen_write || !(cfg & PIN_CFG_OEN)) + return -EOPNOTSUPP; + ret = pctrl->data->oen_write(pctrl, _pin, !!arg); if (ret) return ret; break; @@ -1229,6 +1413,28 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev, settings.power_source = pinconf_to_config_argument(_configs[i]); break; + case PIN_CONFIG_SLEW_RATE: + arg = pinconf_to_config_argument(_configs[i]); + + if (!(cfg & PIN_CFG_SR) || arg > 1) + return -EINVAL; + + rzg2l_rmw_pin_config(pctrl, SR(off), bit, SR_MASK, arg); + break; + + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + if (!(cfg & PIN_CFG_PUPD)) + return -EINVAL; + + ret = pctrl->data->bias_param_to_hw(param); + if (ret < 0) + return ret; + + rzg2l_rmw_pin_config(pctrl, PUPD(off), bit, PUPD_MASK, ret); + break; + case PIN_CONFIG_DRIVE_STRENGTH: arg = pinconf_to_config_argument(_configs[i]); @@ -1270,6 +1476,16 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev, rzg2l_rmw_pin_config(pctrl, IOLH(off), bit, IOLH_MASK, index); break; + case RENESAS_RZV2H_PIN_CONFIG_OUTPUT_IMPEDANCE: + if (!(cfg & PIN_CFG_IOLH_RZV2H)) + return -EINVAL; + + arg = pinconf_to_config_argument(_configs[i]); + if (arg > 3) + return -EINVAL; + rzg2l_rmw_pin_config(pctrl, IOLH(off), bit, IOLH_MASK, arg); + break; + default: return -EOPNOTSUPP; } @@ -1411,7 +1627,7 @@ static int rzg2l_gpio_request(struct gpio_chip *chip, unsigned int offset) /* Select GPIO mode in PMC Register */ reg8 = readb(pctrl->base + PMC(off)); reg8 &= ~BIT(bit); - writeb(reg8, pctrl->base + PMC(off)); + pctrl->data->pmc_writeb(pctrl, reg8, PMC(off)); spin_unlock_irqrestore(&pctrl->lock, flags); @@ -1613,7 +1829,7 @@ static const u64 r9a07g044_gpio_configs[] = { RZG2L_GPIO_PORT_PACK(3, 0x21, RZG2L_MPXED_PIN_FUNCS), RZG2L_GPIO_PORT_PACK(2, 0x22, RZG2L_MPXED_PIN_FUNCS), RZG2L_GPIO_PORT_PACK(2, 0x23, RZG2L_MPXED_PIN_FUNCS), - RZG2L_GPIO_PORT_PACK(3, 0x24, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), + RZG2L_GPIO_PORT_PACK(3, 0x24, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0) | PIN_CFG_OEN), RZG2L_GPIO_PORT_PACK(2, 0x25, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), RZG2L_GPIO_PORT_PACK(2, 0x26, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), RZG2L_GPIO_PORT_PACK(2, 0x27, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), @@ -1622,7 +1838,7 @@ static const u64 r9a07g044_gpio_configs[] = { RZG2L_GPIO_PORT_PACK(2, 0x2a, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), RZG2L_GPIO_PORT_PACK(2, 0x2b, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), RZG2L_GPIO_PORT_PACK(2, 0x2c, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), - RZG2L_GPIO_PORT_PACK(2, 0x2d, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)), + RZG2L_GPIO_PORT_PACK(2, 0x2d, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1) | PIN_CFG_OEN), RZG2L_GPIO_PORT_PACK(2, 0x2e, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)), RZG2L_GPIO_PORT_PACK(2, 0x2f, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)), RZG2L_GPIO_PORT_PACK(2, 0x30, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)), @@ -1646,13 +1862,13 @@ static const u64 r9a07g044_gpio_configs[] = { static const u64 r9a07g043_gpio_configs[] = { RZG2L_GPIO_PORT_PACK(4, 0x10, RZG2L_MPXED_PIN_FUNCS), - RZG2L_GPIO_PORT_PACK(5, 0x11, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), + RZG2L_GPIO_PORT_PACK(5, 0x11, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0) | PIN_CFG_OEN), RZG2L_GPIO_PORT_PACK(4, 0x12, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), RZG2L_GPIO_PORT_PACK(4, 0x13, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), RZG2L_GPIO_PORT_PACK(6, 0x14, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), RZG2L_GPIO_PORT_PACK(5, 0x15, RZG2L_MPXED_PIN_FUNCS), RZG2L_GPIO_PORT_PACK(5, 0x16, RZG2L_MPXED_PIN_FUNCS), - RZG2L_GPIO_PORT_PACK(5, 0x17, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)), + RZG2L_GPIO_PORT_PACK(5, 0x17, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1) | PIN_CFG_OEN), RZG2L_GPIO_PORT_PACK(5, 0x18, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)), RZG2L_GPIO_PORT_PACK(4, 0x19, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)), RZG2L_GPIO_PORT_PACK(5, 0x1a, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)), @@ -1669,13 +1885,13 @@ static const u64 r9a07g043_gpio_configs[] = { RZG2L_GPIO_PORT_SPARSE_PACK(0x2, 0x06, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | PIN_CFG_FILONOFF | PIN_CFG_FILNUM | PIN_CFG_FILCLKSEL | PIN_CFG_IEN | PIN_CFG_NOGPIO_INT), /* P19 */ - RZG2L_GPIO_PORT_PACK(8, 0x07, PIN_CFG_VARIABLE), /* P20 */ + RZG2L_GPIO_PORT_PACK_VARIABLE(8, 0x07), /* P20 */ RZG2L_GPIO_PORT_SPARSE_PACK(0x2, 0x08, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | PIN_CFG_IEN | PIN_CFG_NOGPIO_INT), /* P21 */ RZG2L_GPIO_PORT_PACK(4, 0x09, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_PUPD | PIN_CFG_IEN | PIN_CFG_NOGPIO_INT), /* P22 */ - RZG2L_GPIO_PORT_SPARSE_PACK(0x3e, 0x0a, PIN_CFG_VARIABLE), /* P23 */ - RZG2L_GPIO_PORT_PACK(6, 0x0b, PIN_CFG_VARIABLE), /* P24 */ + RZG2L_GPIO_PORT_SPARSE_PACK_VARIABLE(0x3e, 0x0a), /* P23 */ + RZG2L_GPIO_PORT_PACK_VARIABLE(6, 0x0b), /* P24 */ RZG2L_GPIO_PORT_SPARSE_PACK(0x2, 0x0c, PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_FILONOFF | PIN_CFG_FILNUM | PIN_CFG_FILCLKSEL | PIN_CFG_NOGPIO_INT), /* P25 */ @@ -1717,6 +1933,39 @@ static const u64 r9a08g045_gpio_configs[] = { RZG2L_GPIO_PORT_PACK(6, 0x2a, RZG3S_MPXED_PIN_FUNCS(A)), /* P18 */ }; +static const char * const rzv2h_gpio_names[] = { + "P00", "P01", "P02", "P03", "P04", "P05", "P06", "P07", + "P10", "P11", "P12", "P13", "P14", "P15", "P16", "P17", + "P20", "P21", "P22", "P23", "P24", "P25", "P26", "P27", + "P30", "P31", "P32", "P33", "P34", "P35", "P36", "P37", + "P40", "P41", "P42", "P43", "P44", "P45", "P46", "P47", + "P50", "P51", "P52", "P53", "P54", "P55", "P56", "P57", + "P60", "P61", "P62", "P63", "P64", "P65", "P66", "P67", + "P70", "P71", "P72", "P73", "P74", "P75", "P76", "P77", + "P80", "P81", "P82", "P83", "P84", "P85", "P86", "P87", + "P90", "P91", "P92", "P93", "P94", "P95", "P96", "P97", + "PA0", "PA1", "PA2", "PA3", "PA4", "PA5", "PA6", "PA7", + "PB0", "PB1", "PB2", "PB3", "PB4", "PB5", "PB6", "PB7", +}; + +static const u64 r9a09g057_gpio_configs[] = { + RZG2L_GPIO_PORT_PACK(8, 0x20, RZV2H_MPXED_PIN_FUNCS), /* P0 */ + RZG2L_GPIO_PORT_PACK(6, 0x21, RZV2H_MPXED_PIN_FUNCS), /* P1 */ + RZG2L_GPIO_PORT_PACK(2, 0x22, RZG2L_MPXED_COMMON_PIN_FUNCS(RZV2H) | + PIN_CFG_NOD), /* P2 */ + RZG2L_GPIO_PORT_PACK(8, 0x23, RZV2H_MPXED_PIN_FUNCS), /* P3 */ + RZG2L_GPIO_PORT_PACK(8, 0x24, RZV2H_MPXED_PIN_FUNCS), /* P4 */ + RZG2L_GPIO_PORT_PACK(8, 0x25, RZV2H_MPXED_PIN_FUNCS), /* P5 */ + RZG2L_GPIO_PORT_PACK(8, 0x26, RZV2H_MPXED_PIN_FUNCS | + PIN_CFG_ELC), /* P6 */ + RZG2L_GPIO_PORT_PACK(8, 0x27, RZV2H_MPXED_PIN_FUNCS), /* P7 */ + RZG2L_GPIO_PORT_PACK(8, 0x28, RZV2H_MPXED_PIN_FUNCS | + PIN_CFG_ELC), /* P8 */ + RZG2L_GPIO_PORT_PACK(8, 0x29, RZV2H_MPXED_PIN_FUNCS), /* P9 */ + RZG2L_GPIO_PORT_PACK(8, 0x2a, RZV2H_MPXED_PIN_FUNCS), /* PA */ + RZG2L_GPIO_PORT_PACK_VARIABLE(6, 0x2b), /* PB */ +}; + static const struct { struct rzg2l_dedicated_configs common[35]; struct rzg2l_dedicated_configs rzg2l_pins[7]; @@ -1843,6 +2092,138 @@ static const struct rzg2l_dedicated_configs rzg3s_dedicated_pins[] = { PIN_CFG_IO_VMC_SD1)) }, }; +static struct rzg2l_dedicated_configs rzv2h_dedicated_pins[] = { + { "NMI", RZG2L_SINGLE_PIN_PACK(0x1, 0, (PIN_CFG_FILONOFF | PIN_CFG_FILNUM | + PIN_CFG_FILCLKSEL)) }, + { "TMS_SWDIO", RZG2L_SINGLE_PIN_PACK(0x3, 0, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN)) }, + { "TDO", RZG2L_SINGLE_PIN_PACK(0x3, 2, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR)) }, + { "WDTUDFCA", RZG2L_SINGLE_PIN_PACK(0x5, 0, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD | PIN_CFG_NOD)) }, + { "WDTUDFCM", RZG2L_SINGLE_PIN_PACK(0x5, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD | PIN_CFG_NOD)) }, + { "SCIF_RXD", RZG2L_SINGLE_PIN_PACK(0x6, 0, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "SCIF_TXD", RZG2L_SINGLE_PIN_PACK(0x6, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "XSPI0_CKP", RZG2L_SINGLE_PIN_PACK(0x7, 0, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD | PIN_CFG_OEN)) }, + { "XSPI0_CKN", RZG2L_SINGLE_PIN_PACK(0x7, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD | PIN_CFG_OEN)) }, + { "XSPI0_CS0N", RZG2L_SINGLE_PIN_PACK(0x7, 2, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD | PIN_CFG_OEN)) }, + { "XSPI0_DS", RZG2L_SINGLE_PIN_PACK(0x7, 3, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "XSPI0_RESET0N", RZG2L_SINGLE_PIN_PACK(0x7, 4, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD | PIN_CFG_OEN)) }, + { "XSPI0_RSTO0N", RZG2L_SINGLE_PIN_PACK(0x7, 5, (PIN_CFG_PUPD)) }, + { "XSPI0_INT0N", RZG2L_SINGLE_PIN_PACK(0x7, 6, (PIN_CFG_PUPD)) }, + { "XSPI0_ECS0N", RZG2L_SINGLE_PIN_PACK(0x7, 7, (PIN_CFG_PUPD)) }, + { "XSPI0_IO0", RZG2L_SINGLE_PIN_PACK(0x8, 0, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "XSPI0_IO1", RZG2L_SINGLE_PIN_PACK(0x8, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "XSPI0_IO2", RZG2L_SINGLE_PIN_PACK(0x8, 2, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "XSPI0_IO3", RZG2L_SINGLE_PIN_PACK(0x8, 3, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "XSPI0_IO4", RZG2L_SINGLE_PIN_PACK(0x8, 4, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "XSPI0_IO5", RZG2L_SINGLE_PIN_PACK(0x8, 5, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "XSPI0_IO6", RZG2L_SINGLE_PIN_PACK(0x8, 6, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "XSPI0_IO7", RZG2L_SINGLE_PIN_PACK(0x8, 7, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "SD0CLK", RZG2L_SINGLE_PIN_PACK(0x9, 0, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR)) }, + { "SD0CMD", RZG2L_SINGLE_PIN_PACK(0x9, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "SD0RSTN", RZG2L_SINGLE_PIN_PACK(0x9, 2, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR)) }, + { "SD0DAT0", RZG2L_SINGLE_PIN_PACK(0xa, 0, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "SD0DAT1", RZG2L_SINGLE_PIN_PACK(0xa, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "SD0DAT2", RZG2L_SINGLE_PIN_PACK(0xa, 2, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "SD0DAT3", RZG2L_SINGLE_PIN_PACK(0xa, 3, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "SD0DAT4", RZG2L_SINGLE_PIN_PACK(0xa, 4, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "SD0DAT5", RZG2L_SINGLE_PIN_PACK(0xa, 5, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "SD0DAT6", RZG2L_SINGLE_PIN_PACK(0xa, 6, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "SD0DAT7", RZG2L_SINGLE_PIN_PACK(0xa, 7, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "SD1CLK", RZG2L_SINGLE_PIN_PACK(0xb, 0, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR)) }, + { "SD1CMD", RZG2L_SINGLE_PIN_PACK(0xb, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "SD1DAT0", RZG2L_SINGLE_PIN_PACK(0xc, 0, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "SD1DAT1", RZG2L_SINGLE_PIN_PACK(0xc, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "SD1DAT2", RZG2L_SINGLE_PIN_PACK(0xc, 2, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "SD1DAT3", RZG2L_SINGLE_PIN_PACK(0xc, 3, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "PCIE0_RSTOUTB", RZG2L_SINGLE_PIN_PACK(0xe, 0, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR)) }, + { "PCIE1_RSTOUTB", RZG2L_SINGLE_PIN_PACK(0xe, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR)) }, + { "ET0_MDIO", RZG2L_SINGLE_PIN_PACK(0xf, 0, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "ET0_MDC", RZG2L_SINGLE_PIN_PACK(0xf, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "ET0_RXCTL_RXDV", RZG2L_SINGLE_PIN_PACK(0x10, 0, (PIN_CFG_PUPD)) }, + { "ET0_TXCTL_TXEN", RZG2L_SINGLE_PIN_PACK(0x10, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "ET0_TXER", RZG2L_SINGLE_PIN_PACK(0x10, 2, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "ET0_RXER", RZG2L_SINGLE_PIN_PACK(0x10, 3, (PIN_CFG_PUPD)) }, + { "ET0_RXC_RXCLK", RZG2L_SINGLE_PIN_PACK(0x10, 4, (PIN_CFG_PUPD)) }, + { "ET0_TXC_TXCLK", RZG2L_SINGLE_PIN_PACK(0x10, 5, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD | PIN_CFG_OEN)) }, + { "ET0_CRS", RZG2L_SINGLE_PIN_PACK(0x10, 6, (PIN_CFG_PUPD)) }, + { "ET0_COL", RZG2L_SINGLE_PIN_PACK(0x10, 7, (PIN_CFG_PUPD)) }, + { "ET0_TXD0", RZG2L_SINGLE_PIN_PACK(0x11, 0, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "ET0_TXD1", RZG2L_SINGLE_PIN_PACK(0x11, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "ET0_TXD2", RZG2L_SINGLE_PIN_PACK(0x11, 2, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "ET0_TXD3", RZG2L_SINGLE_PIN_PACK(0x11, 3, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "ET0_RXD0", RZG2L_SINGLE_PIN_PACK(0x11, 4, (PIN_CFG_PUPD)) }, + { "ET0_RXD1", RZG2L_SINGLE_PIN_PACK(0x11, 5, (PIN_CFG_PUPD)) }, + { "ET0_RXD2", RZG2L_SINGLE_PIN_PACK(0x11, 6, (PIN_CFG_PUPD)) }, + { "ET0_RXD3", RZG2L_SINGLE_PIN_PACK(0x11, 7, (PIN_CFG_PUPD)) }, + { "ET1_MDIO", RZG2L_SINGLE_PIN_PACK(0x12, 0, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_IEN | PIN_CFG_PUPD)) }, + { "ET1_MDC", RZG2L_SINGLE_PIN_PACK(0x12, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "ET1_RXCTL_RXDV", RZG2L_SINGLE_PIN_PACK(0x13, 0, (PIN_CFG_PUPD)) }, + { "ET1_TXCTL_TXEN", RZG2L_SINGLE_PIN_PACK(0x13, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "ET1_TXER", RZG2L_SINGLE_PIN_PACK(0x13, 2, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "ET1_RXER", RZG2L_SINGLE_PIN_PACK(0x13, 3, (PIN_CFG_PUPD)) }, + { "ET1_RXC_RXCLK", RZG2L_SINGLE_PIN_PACK(0x13, 4, (PIN_CFG_PUPD)) }, + { "ET1_TXC_TXCLK", RZG2L_SINGLE_PIN_PACK(0x13, 5, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD | PIN_CFG_OEN)) }, + { "ET1_CRS", RZG2L_SINGLE_PIN_PACK(0x13, 6, (PIN_CFG_PUPD)) }, + { "ET1_COL", RZG2L_SINGLE_PIN_PACK(0x13, 7, (PIN_CFG_PUPD)) }, + { "ET1_TXD0", RZG2L_SINGLE_PIN_PACK(0x14, 0, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "ET1_TXD1", RZG2L_SINGLE_PIN_PACK(0x14, 1, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "ET1_TXD2", RZG2L_SINGLE_PIN_PACK(0x14, 2, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "ET1_TXD3", RZG2L_SINGLE_PIN_PACK(0x14, 3, (PIN_CFG_IOLH_RZV2H | PIN_CFG_SR | + PIN_CFG_PUPD)) }, + { "ET1_RXD0", RZG2L_SINGLE_PIN_PACK(0x14, 4, (PIN_CFG_PUPD)) }, + { "ET1_RXD1", RZG2L_SINGLE_PIN_PACK(0x14, 5, (PIN_CFG_PUPD)) }, + { "ET1_RXD2", RZG2L_SINGLE_PIN_PACK(0x14, 6, (PIN_CFG_PUPD)) }, + { "ET1_RXD3", RZG2L_SINGLE_PIN_PACK(0x14, 7, (PIN_CFG_PUPD)) }, +}; + static int rzg2l_gpio_get_gpioint(unsigned int virq, struct rzg2l_pinctrl *pctrl) { const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[virq]; @@ -2280,6 +2661,13 @@ static int rzg2l_pinctrl_register(struct rzg2l_pinctrl *pctrl) pctrl->desc.pmxops = &rzg2l_pinctrl_pmxops; pctrl->desc.confops = &rzg2l_pinctrl_confops; pctrl->desc.owner = THIS_MODULE; + if (pctrl->data->num_custom_params) { + pctrl->desc.num_custom_params = pctrl->data->num_custom_params; + pctrl->desc.custom_params = pctrl->data->custom_params; +#ifdef CONFIG_DEBUG_FS + pctrl->desc.custom_conf_items = pctrl->data->custom_conf_items; +#endif + } pins = devm_kcalloc(pctrl->dev, pctrl->desc.npins, sizeof(*pins), GFP_KERNEL); if (!pins) @@ -2299,13 +2687,11 @@ static int rzg2l_pinctrl_register(struct rzg2l_pinctrl *pctrl) if (i && !(i % RZG2L_PINS_PER_PORT)) j++; pin_data[i] = pctrl->data->port_pin_configs[j]; -#ifdef CONFIG_RISCV - if (pin_data[i] & PIN_CFG_VARIABLE) + if (pin_data[i] & RZG2L_VARIABLE_CFG) pin_data[i] = rzg2l_pinctrl_get_variable_pin_cfg(pctrl, pin_data[i], j, i % RZG2L_PINS_PER_PORT); -#endif pins[i].drv_data = &pin_data[i]; } @@ -2374,6 +2760,9 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev) BUILD_BUG_ON(ARRAY_SIZE(r9a08g045_gpio_configs) * RZG2L_PINS_PER_PORT > ARRAY_SIZE(rzg2l_gpio_names)); + BUILD_BUG_ON(ARRAY_SIZE(r9a09g057_gpio_configs) * RZG2L_PINS_PER_PORT > + ARRAY_SIZE(rzv2h_gpio_names)); + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); if (!pctrl) return -ENOMEM; @@ -2462,12 +2851,14 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen static void rzg2l_pinctrl_pm_setup_dedicated_regs(struct rzg2l_pinctrl *pctrl, bool suspend) { struct rzg2l_pinctrl_reg_cache *cache = pctrl->dedicated_cache; + u32 caps; + u32 i; /* * Make sure entries in pctrl->data->n_dedicated_pins[] having the same * port offset are close together. */ - for (u32 i = 0, caps = 0; i < pctrl->data->n_dedicated_pins; i++) { + for (i = 0, caps = 0; i < pctrl->data->n_dedicated_pins; i++) { bool has_iolh, has_ien; u32 off, next_off = 0; u64 cfg, next_cfg; @@ -2519,12 +2910,10 @@ static void rzg2l_pinctrl_pm_setup_dedicated_regs(struct rzg2l_pinctrl *pctrl, b static void rzg2l_pinctrl_pm_setup_pfc(struct rzg2l_pinctrl *pctrl) { u32 nports = pctrl->data->n_port_pins / RZG2L_PINS_PER_PORT; - const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg; - const struct rzg2l_register_offsets *regs = &hwcfg->regs; + unsigned long flags; - /* Set the PWPR register to allow PFC register to write. */ - writel(0x0, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=0 */ - writel(PWPR_PFCWE, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=1 */ + spin_lock_irqsave(&pctrl->lock, flags); + pctrl->data->pwpr_pfc_lock_unlock(pctrl, false); /* Restore port registers. */ for (u32 port = 0; port < nports; port++) { @@ -2567,9 +2956,8 @@ static void rzg2l_pinctrl_pm_setup_pfc(struct rzg2l_pinctrl *pctrl) } } - /* Set the PWPR register to be write-protected. */ - writel(0x0, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=0 */ - writel(PWPR_B0WI, pctrl->base + regs->pwpr); /* B0WI=1, PFCWE=0 */ + pctrl->data->pwpr_pfc_lock_unlock(pctrl, true); + spin_unlock_irqrestore(&pctrl->lock, flags); } static int rzg2l_pinctrl_suspend_noirq(struct device *dev) @@ -2583,8 +2971,10 @@ static int rzg2l_pinctrl_suspend_noirq(struct device *dev) rzg2l_pinctrl_pm_setup_dedicated_regs(pctrl, true); for (u8 i = 0; i < 2; i++) { - cache->sd_ch[i] = readb(pctrl->base + SD_CH(regs->sd_ch, i)); - cache->eth_poc[i] = readb(pctrl->base + ETH_POC(regs->eth_poc, i)); + if (regs->sd_ch) + cache->sd_ch[i] = readb(pctrl->base + SD_CH(regs->sd_ch, i)); + if (regs->eth_poc) + cache->eth_poc[i] = readb(pctrl->base + ETH_POC(regs->eth_poc, i)); } cache->qspi = readb(pctrl->base + QSPI); @@ -2615,8 +3005,10 @@ static int rzg2l_pinctrl_resume_noirq(struct device *dev) writeb(cache->qspi, pctrl->base + QSPI); writeb(cache->eth_mode, pctrl->base + ETH_MODE); for (u8 i = 0; i < 2; i++) { - writeb(cache->sd_ch[i], pctrl->base + SD_CH(regs->sd_ch, i)); - writeb(cache->eth_poc[i], pctrl->base + ETH_POC(regs->eth_poc, i)); + if (regs->sd_ch) + writeb(cache->sd_ch[i], pctrl->base + SD_CH(regs->sd_ch, i)); + if (regs->eth_poc) + writeb(cache->eth_poc[i], pctrl->base + ETH_POC(regs->eth_poc, i)); } rzg2l_pinctrl_pm_setup_pfc(pctrl); @@ -2627,6 +3019,37 @@ static int rzg2l_pinctrl_resume_noirq(struct device *dev) return 0; } +static void rzg2l_pwpr_pfc_lock_unlock(struct rzg2l_pinctrl *pctrl, bool lock) +{ + const struct rzg2l_register_offsets *regs = &pctrl->data->hwcfg->regs; + + if (lock) { + /* Set the PWPR register to be write-protected */ + writel(0x0, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=0 */ + writel(PWPR_B0WI, pctrl->base + regs->pwpr); /* B0WI=1, PFCWE=0 */ + } else { + /* Set the PWPR register to allow PFC register to write */ + writel(0x0, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=0 */ + writel(PWPR_PFCWE, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=1 */ + } +} + +static void rzv2h_pwpr_pfc_lock_unlock(struct rzg2l_pinctrl *pctrl, bool lock) +{ + const struct rzg2l_register_offsets *regs = &pctrl->data->hwcfg->regs; + u8 pwpr; + + if (lock) { + /* Set the PWPR register to be write-protected */ + pwpr = readb(pctrl->base + regs->pwpr); + writeb(pwpr & ~PWPR_REGWE_A, pctrl->base + regs->pwpr); + } else { + /* Set the PWPR register to allow PFC and PMC register to write */ + pwpr = readb(pctrl->base + regs->pwpr); + writeb(PWPR_REGWE_A | pwpr, pctrl->base + regs->pwpr); + } +} + static const struct rzg2l_hwcfg rzg2l_hwcfg = { .regs = { .pwpr = 0x3014, @@ -2638,6 +3061,7 @@ static const struct rzg2l_hwcfg rzg2l_hwcfg = { [RZG2L_IOLH_IDX_3V3] = 2000, 4000, 8000, 12000, }, .iolh_groupb_oi = { 100, 66, 50, 33, }, + .oen_max_pin = 0, }; static const struct rzg2l_hwcfg rzg3s_hwcfg = { @@ -2672,6 +3096,12 @@ static const struct rzg2l_hwcfg rzg3s_hwcfg = { .oen_max_port = 7, /* P7_1 is the maximum OEN port. */ }; +static const struct rzg2l_hwcfg rzv2h_hwcfg = { + .regs = { + .pwpr = 0x3c04, + }, +}; + static struct rzg2l_pinctrl_data r9a07g043_data = { .port_pins = rzg2l_gpio_names, .port_pin_configs = r9a07g043_gpio_configs, @@ -2684,6 +3114,12 @@ static struct rzg2l_pinctrl_data r9a07g043_data = { .variable_pin_cfg = r9a07g043f_variable_pin_cfg, .n_variable_pin_cfg = ARRAY_SIZE(r9a07g043f_variable_pin_cfg), #endif + .pwpr_pfc_lock_unlock = &rzg2l_pwpr_pfc_lock_unlock, + .pmc_writeb = &rzg2l_pmc_writeb, + .oen_read = &rzg2l_read_oen, + .oen_write = &rzg2l_write_oen, + .hw_to_bias_param = &rzg2l_hw_to_bias_param, + .bias_param_to_hw = &rzg2l_bias_param_to_hw, }; static struct rzg2l_pinctrl_data r9a07g044_data = { @@ -2695,6 +3131,12 @@ static struct rzg2l_pinctrl_data r9a07g044_data = { .n_dedicated_pins = ARRAY_SIZE(rzg2l_dedicated_pins.common) + ARRAY_SIZE(rzg2l_dedicated_pins.rzg2l_pins), .hwcfg = &rzg2l_hwcfg, + .pwpr_pfc_lock_unlock = &rzg2l_pwpr_pfc_lock_unlock, + .pmc_writeb = &rzg2l_pmc_writeb, + .oen_read = &rzg2l_read_oen, + .oen_write = &rzg2l_write_oen, + .hw_to_bias_param = &rzg2l_hw_to_bias_param, + .bias_param_to_hw = &rzg2l_bias_param_to_hw, }; static struct rzg2l_pinctrl_data r9a08g045_data = { @@ -2705,6 +3147,35 @@ static struct rzg2l_pinctrl_data r9a08g045_data = { .n_port_pins = ARRAY_SIZE(r9a08g045_gpio_configs) * RZG2L_PINS_PER_PORT, .n_dedicated_pins = ARRAY_SIZE(rzg3s_dedicated_pins), .hwcfg = &rzg3s_hwcfg, + .pwpr_pfc_lock_unlock = &rzg2l_pwpr_pfc_lock_unlock, + .pmc_writeb = &rzg2l_pmc_writeb, + .oen_read = &rzg3s_oen_read, + .oen_write = &rzg3s_oen_write, + .hw_to_bias_param = &rzg2l_hw_to_bias_param, + .bias_param_to_hw = &rzg2l_bias_param_to_hw, +}; + +static struct rzg2l_pinctrl_data r9a09g057_data = { + .port_pins = rzv2h_gpio_names, + .port_pin_configs = r9a09g057_gpio_configs, + .n_ports = ARRAY_SIZE(r9a09g057_gpio_configs), + .dedicated_pins = rzv2h_dedicated_pins, + .n_port_pins = ARRAY_SIZE(r9a09g057_gpio_configs) * RZG2L_PINS_PER_PORT, + .n_dedicated_pins = ARRAY_SIZE(rzv2h_dedicated_pins), + .hwcfg = &rzv2h_hwcfg, + .variable_pin_cfg = r9a09g057_variable_pin_cfg, + .n_variable_pin_cfg = ARRAY_SIZE(r9a09g057_variable_pin_cfg), + .num_custom_params = ARRAY_SIZE(renesas_rzv2h_custom_bindings), + .custom_params = renesas_rzv2h_custom_bindings, +#ifdef CONFIG_DEBUG_FS + .custom_conf_items = renesas_rzv2h_conf_items, +#endif + .pwpr_pfc_lock_unlock = &rzv2h_pwpr_pfc_lock_unlock, + .pmc_writeb = &rzv2h_pmc_writeb, + .oen_read = &rzv2h_oen_read, + .oen_write = &rzv2h_oen_write, + .hw_to_bias_param = &rzv2h_hw_to_bias_param, + .bias_param_to_hw = &rzv2h_bias_param_to_hw, }; static const struct of_device_id rzg2l_pinctrl_of_table[] = { @@ -2720,6 +3191,10 @@ static const struct of_device_id rzg2l_pinctrl_of_table[] = { .compatible = "renesas,r9a08g045-pinctrl", .data = &r9a08g045_data, }, + { + .compatible = "renesas,r9a09g057-pinctrl", + .data = &r9a09g057_data, + }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/renesas/pinctrl-rzn1.c b/drivers/pinctrl/renesas/pinctrl-rzn1.c index 4b2f107824fe..39af1fe79c84 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzn1.c +++ b/drivers/pinctrl/renesas/pinctrl-rzn1.c @@ -404,7 +404,6 @@ static int rzn1_dt_node_to_map(struct pinctrl_dev *pctldev, struct pinctrl_map **map, unsigned int *num_maps) { - struct device_node *child; int ret; *map = NULL; @@ -414,12 +413,10 @@ static int rzn1_dt_node_to_map(struct pinctrl_dev *pctldev, if (ret < 0) return ret; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { ret = rzn1_dt_node_to_map_one(pctldev, child, map, num_maps); - if (ret < 0) { - of_node_put(child); + if (ret < 0) return ret; - } } return 0; @@ -740,13 +737,12 @@ static int rzn1_pinctrl_parse_groups(struct device_node *np, static int rzn1_pinctrl_count_function_groups(struct device_node *np) { - struct device_node *child; int count = 0; if (of_property_count_u32_elems(np, RZN1_PINS_PROP) > 0) count++; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { if (of_property_count_u32_elems(child, RZN1_PINS_PROP) > 0) count++; } @@ -760,7 +756,6 @@ static int rzn1_pinctrl_parse_functions(struct device_node *np, { struct rzn1_pmx_func *func; struct rzn1_pin_group *grp; - struct device_node *child; unsigned int i = 0; int ret; @@ -793,15 +788,13 @@ static int rzn1_pinctrl_parse_functions(struct device_node *np, ipctl->ngroups++; } - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { func->groups[i] = child->name; grp = &ipctl->groups[ipctl->ngroups]; grp->func = func->name; ret = rzn1_pinctrl_parse_groups(child, grp, ipctl); - if (ret < 0) { - of_node_put(child); + if (ret < 0) return ret; - } i++; ipctl->ngroups++; } @@ -816,7 +809,6 @@ static int rzn1_pinctrl_probe_dt(struct platform_device *pdev, struct rzn1_pinctrl *ipctl) { struct device_node *np = pdev->dev.of_node; - struct device_node *child; unsigned int maxgroups = 0; unsigned int i = 0; int nfuncs = 0; @@ -834,7 +826,7 @@ static int rzn1_pinctrl_probe_dt(struct platform_device *pdev, return -ENOMEM; ipctl->ngroups = 0; - for_each_child_of_node(np, child) + for_each_child_of_node_scoped(np, child) maxgroups += rzn1_pinctrl_count_function_groups(child); ipctl->groups = devm_kmalloc_array(&pdev->dev, @@ -844,12 +836,10 @@ static int rzn1_pinctrl_probe_dt(struct platform_device *pdev, if (!ipctl->groups) return -ENOMEM; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { ret = rzn1_pinctrl_parse_functions(child, ipctl, i++); - if (ret < 0) { - of_node_put(child); + if (ret < 0) return ret; - } } return 0; diff --git a/drivers/pinctrl/renesas/pinctrl-rzv2m.c b/drivers/pinctrl/renesas/pinctrl-rzv2m.c index 0767a5ac23e0..0cae5472ac67 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzv2m.c +++ b/drivers/pinctrl/renesas/pinctrl-rzv2m.c @@ -388,7 +388,6 @@ static int rzv2m_dt_node_to_map(struct pinctrl_dev *pctldev, unsigned int *num_maps) { struct rzv2m_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - struct device_node *child; unsigned int index; int ret; @@ -396,13 +395,11 @@ static int rzv2m_dt_node_to_map(struct pinctrl_dev *pctldev, *num_maps = 0; index = 0; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { ret = rzv2m_dt_subnode_to_map(pctldev, child, np, map, num_maps, &index); - if (ret < 0) { - of_node_put(child); + if (ret < 0) goto done; - } } if (*num_maps == 0) { diff --git a/drivers/pinctrl/renesas/pinctrl.c b/drivers/pinctrl/renesas/pinctrl.c index 4d9d58fc1356..03e9bdbc82b9 100644 --- a/drivers/pinctrl/renesas/pinctrl.c +++ b/drivers/pinctrl/renesas/pinctrl.c @@ -241,7 +241,6 @@ static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev, { struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); struct device *dev = pmx->pfc->dev; - struct device_node *child; unsigned int index; int ret; @@ -249,13 +248,11 @@ static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev, *num_maps = 0; index = 0; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { ret = sh_pfc_dt_subnode_to_map(pctldev, child, map, num_maps, &index); - if (ret < 0) { - of_node_put(child); + if (ret < 0) goto done; - } } /* If no mapping has been found in child nodes try the config node. */ diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c index b8caaa5a2d4e..a8c5fe973cd4 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.c +++ b/drivers/pinctrl/spear/pinctrl-spear.c @@ -151,24 +151,19 @@ static int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, unsigned *num_maps) { struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); - struct device_node *np; struct property *prop; const char *function, *group; int ret, index = 0, count = 0; /* calculate number of maps required */ - for_each_child_of_node(np_config, np) { + for_each_child_of_node_scoped(np_config, np) { ret = of_property_read_string(np, "st,function", &function); - if (ret < 0) { - of_node_put(np); + if (ret < 0) return ret; - } ret = of_property_count_strings(np, "st,pins"); - if (ret < 0) { - of_node_put(np); + if (ret < 0) return ret; - } count += ret; } @@ -182,7 +177,7 @@ static int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, if (!*map) return -ENOMEM; - for_each_child_of_node(np_config, np) { + for_each_child_of_node_scoped(np_config, np) { of_property_read_string(np, "st,function", &function); of_property_for_each_string(np, "st,pins", prop, group) { (*map)[index].type = PIN_MAP_TYPE_MUX_GROUP; diff --git a/drivers/pinctrl/sprd/pinctrl-sprd.c b/drivers/pinctrl/sprd/pinctrl-sprd.c index d0b6d3e655a2..c4a1d99dfed0 100644 --- a/drivers/pinctrl/sprd/pinctrl-sprd.c +++ b/drivers/pinctrl/sprd/pinctrl-sprd.c @@ -934,7 +934,6 @@ static int sprd_pinctrl_parse_dt(struct sprd_pinctrl *sprd_pctl) { struct sprd_pinctrl_soc_info *info = sprd_pctl->info; struct device_node *np = sprd_pctl->dev->of_node; - struct device_node *child, *sub_child; struct sprd_pin_group *grp; const char **temp; int ret; @@ -962,25 +961,20 @@ static int sprd_pinctrl_parse_dt(struct sprd_pinctrl *sprd_pctl) temp = info->grp_names; grp = info->groups; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { ret = sprd_pinctrl_parse_groups(child, sprd_pctl, grp); - if (ret) { - of_node_put(child); + if (ret) return ret; - } *temp++ = grp->name; grp++; if (of_get_child_count(child) > 0) { - for_each_child_of_node(child, sub_child) { + for_each_child_of_node_scoped(child, sub_child) { ret = sprd_pinctrl_parse_groups(sub_child, sprd_pctl, grp); - if (ret) { - of_node_put(sub_child); - of_node_put(child); + if (ret) return ret; - } *temp++ = grp->name; grp++; diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c index 6df7a310c7ed..27f99183d994 100644 --- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c +++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c @@ -480,7 +480,6 @@ static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev, { struct starfive_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev); struct device *dev = sfp->gc.parent; - struct device_node *child; struct pinctrl_map *map; const char **pgnames; const char *grpname; @@ -492,20 +491,18 @@ static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev, nmaps = 0; ngroups = 0; - for_each_available_child_of_node(np, child) { + for_each_available_child_of_node_scoped(np, child) { int npinmux = of_property_count_u32_elems(child, "pinmux"); int npins = of_property_count_u32_elems(child, "pins"); if (npinmux > 0 && npins > 0) { dev_err(dev, "invalid pinctrl group %pOFn.%pOFn: both pinmux and pins set\n", np, child); - of_node_put(child); return -EINVAL; } if (npinmux == 0 && npins == 0) { dev_err(dev, "invalid pinctrl group %pOFn.%pOFn: neither pinmux nor pins set\n", np, child); - of_node_put(child); return -EINVAL; } @@ -527,14 +524,14 @@ static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev, nmaps = 0; ngroups = 0; mutex_lock(&sfp->mutex); - for_each_available_child_of_node(np, child) { + for_each_available_child_of_node_scoped(np, child) { int npins; int i; grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", np, child); if (!grpname) { ret = -ENOMEM; - goto put_child; + goto free_map; } pgnames[ngroups++] = grpname; @@ -543,18 +540,18 @@ static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev, pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); if (!pins) { ret = -ENOMEM; - goto put_child; + goto free_map; } pinmux = devm_kcalloc(dev, npins, sizeof(*pinmux), GFP_KERNEL); if (!pinmux) { ret = -ENOMEM; - goto put_child; + goto free_map; } ret = of_property_read_u32_array(child, "pinmux", pinmux, npins); if (ret) - goto put_child; + goto free_map; for (i = 0; i < npins; i++) { unsigned int gpio = starfive_pinmux_to_gpio(pinmux[i]); @@ -570,7 +567,7 @@ static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev, pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); if (!pins) { ret = -ENOMEM; - goto put_child; + goto free_map; } pinmux = NULL; @@ -580,18 +577,18 @@ static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev, ret = of_property_read_u32_index(child, "pins", i, &v); if (ret) - goto put_child; + goto free_map; pins[i] = v; } } else { ret = -EINVAL; - goto put_child; + goto free_map; } ret = pinctrl_generic_add_group(pctldev, grpname, pins, npins, pinmux); if (ret < 0) { dev_err(dev, "error adding group %s: %d\n", grpname, ret); - goto put_child; + goto free_map; } ret = pinconf_generic_parse_dt_config(child, pctldev, @@ -600,7 +597,7 @@ static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev, if (ret) { dev_err(dev, "error parsing pin config of group %s: %d\n", grpname, ret); - goto put_child; + goto free_map; } /* don't create a map if there are no pinconf settings */ @@ -623,8 +620,6 @@ static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev, mutex_unlock(&sfp->mutex); return 0; -put_child: - of_node_put(child); free_map: pinctrl_utils_free_map(pctldev, map, nmaps); mutex_unlock(&sfp->mutex); diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c index 9609eb1ecc3d..4ce080caa233 100644 --- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c +++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c @@ -150,7 +150,7 @@ static int jh7110_dt_node_to_map(struct pinctrl_dev *pctldev, nmaps = 0; ngroups = 0; mutex_lock(&sfp->mutex); - for_each_available_child_of_node(np, child) { + for_each_available_child_of_node_scoped(np, child) { int npins = of_property_count_u32_elems(child, "pinmux"); int *pins; u32 *pinmux; @@ -161,13 +161,13 @@ static int jh7110_dt_node_to_map(struct pinctrl_dev *pctldev, "invalid pinctrl group %pOFn.%pOFn: pinmux not set\n", np, child); ret = -EINVAL; - goto put_child; + goto free_map; } grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", np, child); if (!grpname) { ret = -ENOMEM; - goto put_child; + goto free_map; } pgnames[ngroups++] = grpname; @@ -175,18 +175,18 @@ static int jh7110_dt_node_to_map(struct pinctrl_dev *pctldev, pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); if (!pins) { ret = -ENOMEM; - goto put_child; + goto free_map; } pinmux = devm_kcalloc(dev, npins, sizeof(*pinmux), GFP_KERNEL); if (!pinmux) { ret = -ENOMEM; - goto put_child; + goto free_map; } ret = of_property_read_u32_array(child, "pinmux", pinmux, npins); if (ret) - goto put_child; + goto free_map; for (i = 0; i < npins; i++) pins[i] = jh7110_pinmux_pin(pinmux[i]); @@ -200,7 +200,7 @@ static int jh7110_dt_node_to_map(struct pinctrl_dev *pctldev, pins, npins, pinmux); if (ret < 0) { dev_err(dev, "error adding group %s: %d\n", grpname, ret); - goto put_child; + goto free_map; } ret = pinconf_generic_parse_dt_config(child, pctldev, @@ -209,7 +209,7 @@ static int jh7110_dt_node_to_map(struct pinctrl_dev *pctldev, if (ret) { dev_err(dev, "error parsing pin config of group %s: %d\n", grpname, ret); - goto put_child; + goto free_map; } /* don't create a map if there are no pinconf settings */ @@ -233,8 +233,6 @@ static int jh7110_dt_node_to_map(struct pinctrl_dev *pctldev, *num_maps = nmaps; return 0; -put_child: - of_node_put(child); free_map: pinctrl_utils_free_map(pctldev, map, nmaps); mutex_unlock(&sfp->mutex); diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c index 978ccdbaf3d3..a8673739871d 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -670,7 +670,6 @@ static int stm32_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps) { - struct device_node *np; unsigned reserved_maps; int ret; @@ -678,12 +677,11 @@ static int stm32_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, *num_maps = 0; reserved_maps = 0; - for_each_child_of_node(np_config, np) { + for_each_child_of_node_scoped(np_config, np) { ret = stm32_pctrl_dt_subnode_to_map(pctldev, np, map, &reserved_maps, num_maps); if (ret < 0) { pinctrl_utils_free_map(pctldev, *map, *num_maps); - of_node_put(np); return ret; } } diff --git a/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c b/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c index 96ef57a7d385..49c5edeba87f 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c @@ -238,20 +238,17 @@ static int tegra_xusb_padctl_dt_node_to_map(struct pinctrl_dev *pinctrl, { struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); unsigned int reserved_maps = 0; - struct device_node *np; int err; *num_maps = 0; *maps = NULL; - for_each_child_of_node(parent, np) { + for_each_child_of_node_scoped(parent, np) { err = tegra_xusb_padctl_parse_subnode(padctl, np, maps, &reserved_maps, num_maps); - if (err < 0) { - of_node_put(np); + if (err < 0) return err; - } } return 0; diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c index ccfa3870a67d..c83e5a65e680 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c @@ -188,20 +188,18 @@ static int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, unsigned *num_maps) { unsigned reserved_maps; - struct device_node *np; int ret; reserved_maps = 0; *map = NULL; *num_maps = 0; - for_each_child_of_node(np_config, np) { + for_each_child_of_node_scoped(np_config, np) { ret = tegra_pinctrl_dt_subnode_to_map(pctldev, np, map, &reserved_maps, num_maps); if (ret < 0) { pinctrl_utils_free_map(pctldev, *map, *num_maps); - of_node_put(np); return ret; } } diff --git a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c index 040f2c46a868..f5e5a23d2226 100644 --- a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c +++ b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c @@ -822,53 +822,48 @@ MODULE_DEVICE_TABLE(of, ti_iodelay_of_match); static int ti_iodelay_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = of_node_get(dev->of_node); + struct device_node *np __free(device_node) = of_node_get(dev->of_node); struct resource *res; struct ti_iodelay_device *iod; - int ret = 0; + int ret; if (!np) { - ret = -EINVAL; dev_err(dev, "No OF node\n"); - goto exit_out; + return -EINVAL; } iod = devm_kzalloc(dev, sizeof(*iod), GFP_KERNEL); - if (!iod) { - ret = -ENOMEM; - goto exit_out; - } + if (!iod) + return -ENOMEM; + iod->dev = dev; iod->reg_data = device_get_match_data(dev); if (!iod->reg_data) { - ret = -EINVAL; dev_err(dev, "No DATA match\n"); - goto exit_out; + return -EINVAL; } /* So far We can assume there is only 1 bank of registers */ iod->reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(iod->reg_base)) { - ret = PTR_ERR(iod->reg_base); - goto exit_out; - } + if (IS_ERR(iod->reg_base)) + return PTR_ERR(iod->reg_base); + iod->phys_base = res->start; iod->regmap = devm_regmap_init_mmio(dev, iod->reg_base, iod->reg_data->regmap_config); if (IS_ERR(iod->regmap)) { dev_err(dev, "Regmap MMIO init failed.\n"); - ret = PTR_ERR(iod->regmap); - goto exit_out; + return PTR_ERR(iod->regmap); } ret = ti_iodelay_pinconf_init_dev(iod); if (ret) - goto exit_out; + return ret; ret = ti_iodelay_alloc_pins(dev, iod, res->start); if (ret) - goto exit_out; + return ret; iod->desc.pctlops = &ti_iodelay_pinctrl_ops; /* no pinmux ops - we are pinconf */ @@ -876,19 +871,15 @@ static int ti_iodelay_probe(struct platform_device *pdev) iod->desc.name = dev_name(dev); iod->desc.owner = THIS_MODULE; - ret = pinctrl_register_and_init(&iod->desc, dev, iod, &iod->pctl); + ret = devm_pinctrl_register_and_init(dev, &iod->desc, iod, &iod->pctl); if (ret) { dev_err(dev, "Failed to register pinctrl\n"); - goto exit_out; + return ret; } platform_set_drvdata(pdev, iod); return pinctrl_enable(iod->pctl); - -exit_out: - of_node_put(np); - return ret; } /** @@ -899,9 +890,6 @@ static void ti_iodelay_remove(struct platform_device *pdev) { struct ti_iodelay_device *iod = platform_get_drvdata(pdev); - if (iod->pctl) - pinctrl_unregister(iod->pctl); - ti_iodelay_pinconf_deinit_dev(iod); /* Expect other allocations to be freed by devm */ diff --git a/drivers/platform/mips/cpu_hwmon.c b/drivers/platform/mips/cpu_hwmon.c index d8c5f9195f85..2ac2f31090f9 100644 --- a/drivers/platform/mips/cpu_hwmon.c +++ b/drivers/platform/mips/cpu_hwmon.c @@ -139,6 +139,9 @@ static int __init loongson_hwmon_init(void) csr_temp_enable = csr_readl(LOONGSON_CSR_FEATURES) & LOONGSON_CSRF_TEMP; + if (!csr_temp_enable && !loongson_chiptemp[0]) + return -ENODEV; + nr_packages = loongson_sysconf.nr_cpus / loongson_sysconf.cores_per_package; diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index a94ec6225d31..5f9e7e477078 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -364,7 +364,6 @@ static void tce_iommu_release(void *iommu_data) if (!tbl) continue; - tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size); tce_iommu_free_table(container, tbl); } @@ -720,6 +719,8 @@ static long tce_iommu_remove_window(struct tce_container *container, BUG_ON(!tbl->it_size); + tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size); + /* Detach groups from IOMMUs */ list_for_each_entry(tcegrp, &container->group_list, next) { table_group = iommu_group_get_iommudata(tcegrp->grp); @@ -738,7 +739,6 @@ static long tce_iommu_remove_window(struct tce_container *container, } /* Free table */ - tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size); tce_iommu_free_table(container, tbl); container->tables[num] = NULL; @@ -1197,9 +1197,14 @@ static void tce_iommu_release_ownership(struct tce_container *container, return; } - for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) - if (container->tables[i]) + for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { + if (container->tables[i]) { + tce_iommu_clear(container, container->tables[i], + container->tables[i]->it_offset, + container->tables[i]->it_size); table_group->ops->unset_window(table_group, i); + } + } } static long tce_iommu_take_ownership(struct tce_container *container, diff --git a/drivers/virt/coco/sev-guest/sev-guest.c b/drivers/virt/coco/sev-guest/sev-guest.c index f714009b9ff7..6fc7884ea0a1 100644 --- a/drivers/virt/coco/sev-guest/sev-guest.c +++ b/drivers/virt/coco/sev-guest/sev-guest.c @@ -30,8 +30,6 @@ #include #include -#include "sev-guest.h" - #define DEVICE_NAME "sev-guest" #define AAD_LEN 48 #define MSG_HDR_VER 1 diff --git a/drivers/virt/coco/sev-guest/sev-guest.h b/drivers/virt/coco/sev-guest/sev-guest.h deleted file mode 100644 index 21bda26fdb95..000000000000 --- a/drivers/virt/coco/sev-guest/sev-guest.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2021 Advanced Micro Devices, Inc. - * - * Author: Brijesh Singh - * - * SEV-SNP API spec is available at https://developer.amd.com/sev - */ - -#ifndef __VIRT_SEVGUEST_H__ -#define __VIRT_SEVGUEST_H__ - -#include - -#define MAX_AUTHTAG_LEN 32 - -/* See SNP spec SNP_GUEST_REQUEST section for the structure */ -enum msg_type { - SNP_MSG_TYPE_INVALID = 0, - SNP_MSG_CPUID_REQ, - SNP_MSG_CPUID_RSP, - SNP_MSG_KEY_REQ, - SNP_MSG_KEY_RSP, - SNP_MSG_REPORT_REQ, - SNP_MSG_REPORT_RSP, - SNP_MSG_EXPORT_REQ, - SNP_MSG_EXPORT_RSP, - SNP_MSG_IMPORT_REQ, - SNP_MSG_IMPORT_RSP, - SNP_MSG_ABSORB_REQ, - SNP_MSG_ABSORB_RSP, - SNP_MSG_VMRK_REQ, - SNP_MSG_VMRK_RSP, - - SNP_MSG_TYPE_MAX -}; - -enum aead_algo { - SNP_AEAD_INVALID, - SNP_AEAD_AES_256_GCM, -}; - -struct snp_guest_msg_hdr { - u8 authtag[MAX_AUTHTAG_LEN]; - u64 msg_seqno; - u8 rsvd1[8]; - u8 algo; - u8 hdr_version; - u16 hdr_sz; - u8 msg_type; - u8 msg_version; - u16 msg_sz; - u32 rsvd2; - u8 msg_vmpck; - u8 rsvd3[35]; -} __packed; - -struct snp_guest_msg { - struct snp_guest_msg_hdr hdr; - u8 payload[4000]; -} __packed; - -#endif /* __VIRT_SEVGUEST_H__ */ diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 021fa56e962e..7de015a578d3 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -122,7 +122,7 @@ config VIRTIO_BALLOON config VIRTIO_MEM tristate "Virtio mem driver" - depends on X86_64 || ARM64 + depends on X86_64 || ARM64 || RISCV depends on VIRTIO depends on MEMORY_HOTPLUG depends on MEMORY_HOTREMOVE diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index 6397fdefd876..c92937bed133 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -1359,7 +1359,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, target_tcon = tlink_tcon(smb_file_target->tlink); if (src_tcon->ses != target_tcon->ses) { - cifs_dbg(VFS, "source and target of copy not on same server\n"); + cifs_dbg(FYI, "source and target of copy not on same server\n"); goto out; } diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index a865941724c0..8e86fec7dcd2 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -290,7 +290,7 @@ struct smb_version_operations { int (*check_receive)(struct mid_q_entry *, struct TCP_Server_Info *, bool); void (*add_credits)(struct TCP_Server_Info *server, - const struct cifs_credits *credits, + struct cifs_credits *credits, const int optype); void (*set_credits)(struct TCP_Server_Info *, const int); int * (*get_credits_field)(struct TCP_Server_Info *, const int); @@ -550,8 +550,8 @@ struct smb_version_operations { size_t *, struct cifs_credits *); /* adjust previously taken mtu credits to request size */ int (*adjust_credits)(struct TCP_Server_Info *server, - struct cifs_credits *credits, - const unsigned int payload_size); + struct cifs_io_subrequest *subreq, + unsigned int /*enum smb3_rw_credits_trace*/ trace); /* check if we need to issue closedir */ bool (*dir_needs_close)(struct cifsFileInfo *); long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t, @@ -848,6 +848,9 @@ static inline void cifs_server_unlock(struct TCP_Server_Info *server) struct cifs_credits { unsigned int value; unsigned int instance; + unsigned int in_flight_check; + unsigned int rreq_debug_id; + unsigned int rreq_debug_index; }; static inline unsigned int @@ -873,7 +876,7 @@ has_credits(struct TCP_Server_Info *server, int *credits, int num_credits) } static inline void -add_credits(struct TCP_Server_Info *server, const struct cifs_credits *credits, +add_credits(struct TCP_Server_Info *server, struct cifs_credits *credits, const int optype) { server->ops->add_credits(server, credits, optype); @@ -897,11 +900,11 @@ set_credits(struct TCP_Server_Info *server, const int val) } static inline int -adjust_credits(struct TCP_Server_Info *server, struct cifs_credits *credits, - const unsigned int payload_size) +adjust_credits(struct TCP_Server_Info *server, struct cifs_io_subrequest *subreq, + unsigned int /* enum smb3_rw_credits_trace */ trace) { return server->ops->adjust_credits ? - server->ops->adjust_credits(server, credits, payload_size) : 0; + server->ops->adjust_credits(server, subreq, trace) : 0; } static inline __le64 diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 1374635e89fa..b2405dd4d4d4 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -80,6 +80,16 @@ retry: return netfs_prepare_write_failed(subreq); } + wdata->credits.rreq_debug_id = subreq->rreq->debug_id; + wdata->credits.rreq_debug_index = subreq->debug_index; + wdata->credits.in_flight_check = 1; + trace_smb3_rw_credits(wdata->rreq->debug_id, + wdata->subreq.debug_index, + wdata->credits.value, + server->credits, server->in_flight, + wdata->credits.value, + cifs_trace_rw_credits_write_prepare); + #ifdef CONFIG_CIFS_SMB_DIRECT if (server->smbd_conn) subreq->max_nr_segs = server->smbd_conn->max_frmr_depth; @@ -101,7 +111,7 @@ static void cifs_issue_write(struct netfs_io_subrequest *subreq) goto fail; } - rc = adjust_credits(wdata->server, &wdata->credits, wdata->subreq.len); + rc = adjust_credits(wdata->server, wdata, cifs_trace_rw_credits_issue_write_adjust); if (rc) goto fail; @@ -123,6 +133,11 @@ fail: goto out; } +static void cifs_netfs_invalidate_cache(struct netfs_io_request *wreq) +{ + cifs_invalidate_cache(wreq->inode, 0); +} + /* * Split the read up according to how many credits we can get for each piece. * It's okay to sleep here if we need to wait for more credit to become @@ -158,7 +173,18 @@ static bool cifs_clamp_length(struct netfs_io_subrequest *subreq) return false; } + rdata->credits.in_flight_check = 1; + rdata->credits.rreq_debug_id = rreq->debug_id; + rdata->credits.rreq_debug_index = subreq->debug_index; + + trace_smb3_rw_credits(rdata->rreq->debug_id, + rdata->subreq.debug_index, + rdata->credits.value, + server->credits, server->in_flight, 0, + cifs_trace_rw_credits_read_submit); + subreq->len = min_t(size_t, subreq->len, rsize); + #ifdef CONFIG_CIFS_SMB_DIRECT if (server->smbd_conn) subreq->max_nr_segs = server->smbd_conn->max_frmr_depth; @@ -289,6 +315,15 @@ static void cifs_free_subrequest(struct netfs_io_subrequest *subreq) #endif } + if (rdata->credits.value != 0) + trace_smb3_rw_credits(rdata->rreq->debug_id, + rdata->subreq.debug_index, + rdata->credits.value, + rdata->server ? rdata->server->credits : 0, + rdata->server ? rdata->server->in_flight : 0, + -rdata->credits.value, + cifs_trace_rw_credits_free_subreq); + add_credits_and_wake_if(rdata->server, &rdata->credits, 0); if (rdata->have_xid) free_xid(rdata->xid); @@ -307,6 +342,7 @@ const struct netfs_request_ops cifs_req_ops = { .begin_writeback = cifs_begin_writeback, .prepare_write = cifs_prepare_write, .issue_write = cifs_issue_write, + .invalidate_cache = cifs_netfs_invalidate_cache, }; /* @@ -2358,13 +2394,18 @@ void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t bool was_async) { struct netfs_io_request *wreq = wdata->rreq; - loff_t new_server_eof; + struct netfs_inode *ictx = netfs_inode(wreq->inode); + loff_t wrend; if (result > 0) { - new_server_eof = wdata->subreq.start + wdata->subreq.transferred + result; + wrend = wdata->subreq.start + wdata->subreq.transferred + result; - if (new_server_eof > netfs_inode(wreq->inode)->remote_i_size) - netfs_resize_file(netfs_inode(wreq->inode), new_server_eof, true); + if (wrend > ictx->zero_point && + (wdata->rreq->origin == NETFS_UNBUFFERED_WRITE || + wdata->rreq->origin == NETFS_DIO_WRITE)) + ictx->zero_point = wrend; + if (wrend > ictx->remote_i_size) + netfs_resize_file(ictx, wrend, true); } netfs_write_subrequest_terminated(&wdata->subreq, result, was_async); @@ -2877,6 +2918,7 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to) rc = netfs_start_io_direct(inode); if (rc < 0) goto out; + rc = -EACCES; down_read(&cinode->lock_sem); if (!cifs_find_lock_conflict( cfile, iocb->ki_pos, iov_iter_count(to), @@ -2889,6 +2931,7 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to) rc = netfs_start_io_read(inode); if (rc < 0) goto out; + rc = -EACCES; down_read(&cinode->lock_sem); if (!cifs_find_lock_conflict( cfile, iocb->ki_pos, iov_iter_count(to), diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index 212ec6f66ec6..e1f2feb56f45 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -108,7 +108,7 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer) static void cifs_add_credits(struct TCP_Server_Info *server, - const struct cifs_credits *credits, const int optype) + struct cifs_credits *credits, const int optype) { spin_lock(&server->req_lock); server->credits += credits->value; diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index c8e536540895..7fe59235f090 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -66,7 +66,7 @@ change_conf(struct TCP_Server_Info *server) static void smb2_add_credits(struct TCP_Server_Info *server, - const struct cifs_credits *credits, const int optype) + struct cifs_credits *credits, const int optype) { int *val, rc = -1; int scredits, in_flight; @@ -94,7 +94,21 @@ smb2_add_credits(struct TCP_Server_Info *server, server->conn_id, server->hostname, *val, add, server->in_flight); } - WARN_ON_ONCE(server->in_flight == 0); + if (credits->in_flight_check > 1) { + pr_warn_once("rreq R=%08x[%x] Credits not in flight\n", + credits->rreq_debug_id, credits->rreq_debug_index); + } else { + credits->in_flight_check = 2; + } + if (WARN_ON_ONCE(server->in_flight == 0)) { + pr_warn_once("rreq R=%08x[%x] Zero in_flight\n", + credits->rreq_debug_id, credits->rreq_debug_index); + trace_smb3_rw_credits(credits->rreq_debug_id, + credits->rreq_debug_index, + credits->value, + server->credits, server->in_flight, 0, + cifs_trace_rw_credits_zero_in_flight); + } server->in_flight--; if (server->in_flight == 0 && ((optype & CIFS_OP_MASK) != CIFS_NEG_OP) && @@ -283,16 +297,23 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, size_t size, static int smb2_adjust_credits(struct TCP_Server_Info *server, - struct cifs_credits *credits, - const unsigned int payload_size) + struct cifs_io_subrequest *subreq, + unsigned int /*enum smb3_rw_credits_trace*/ trace) { - int new_val = DIV_ROUND_UP(payload_size, SMB2_MAX_BUFFER_SIZE); + struct cifs_credits *credits = &subreq->credits; + int new_val = DIV_ROUND_UP(subreq->subreq.len, SMB2_MAX_BUFFER_SIZE); int scredits, in_flight; if (!credits->value || credits->value == new_val) return 0; if (credits->value < new_val) { + trace_smb3_rw_credits(subreq->rreq->debug_id, + subreq->subreq.debug_index, + credits->value, + server->credits, server->in_flight, + new_val - credits->value, + cifs_trace_rw_credits_no_adjust_up); trace_smb3_too_many_credits(server->CurrentMid, server->conn_id, server->hostname, 0, credits->value - new_val, 0); cifs_server_dbg(VFS, "request has less credits (%d) than required (%d)", @@ -308,6 +329,12 @@ smb2_adjust_credits(struct TCP_Server_Info *server, in_flight = server->in_flight; spin_unlock(&server->req_lock); + trace_smb3_rw_credits(subreq->rreq->debug_id, + subreq->subreq.debug_index, + credits->value, + server->credits, server->in_flight, + new_val - credits->value, + cifs_trace_rw_credits_old_session); trace_smb3_reconnect_detected(server->CurrentMid, server->conn_id, server->hostname, scredits, credits->value - new_val, in_flight); @@ -316,6 +343,11 @@ smb2_adjust_credits(struct TCP_Server_Info *server, return -EAGAIN; } + trace_smb3_rw_credits(subreq->rreq->debug_id, + subreq->subreq.debug_index, + credits->value, + server->credits, server->in_flight, + new_val - credits->value, trace); server->credits += credits->value - new_val; scredits = server->credits; in_flight = server->in_flight; diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 2ae2dbb6202b..9fc5b11c0b6c 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -4502,8 +4502,15 @@ smb2_readv_callback(struct mid_q_entry *mid) struct TCP_Server_Info *server = rdata->server; struct smb2_hdr *shdr = (struct smb2_hdr *)rdata->iov[0].iov_base; - struct cifs_credits credits = { .value = 0, .instance = 0 }; + struct cifs_credits credits = { + .value = 0, + .instance = 0, + .rreq_debug_id = rdata->rreq->debug_id, + .rreq_debug_index = rdata->subreq.debug_index, + }; struct smb_rqst rqst = { .rq_iov = &rdata->iov[1], .rq_nvec = 1 }; + unsigned int rreq_debug_id = rdata->rreq->debug_id; + unsigned int subreq_debug_index = rdata->subreq.debug_index; if (rdata->got_bytes) { rqst.rq_iter = rdata->subreq.io_iter; @@ -4587,10 +4594,16 @@ smb2_readv_callback(struct mid_q_entry *mid) if (rdata->subreq.start < rdata->subreq.rreq->i_size) rdata->result = 0; } + trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, rdata->credits.value, + server->credits, server->in_flight, + 0, cifs_trace_rw_credits_read_response_clear); rdata->credits.value = 0; INIT_WORK(&rdata->subreq.work, smb2_readv_worker); queue_work(cifsiod_wq, &rdata->subreq.work); release_mid(mid); + trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0, + server->credits, server->in_flight, + credits.value, cifs_trace_rw_credits_read_response_add); add_credits(server, &credits, 0); } @@ -4647,7 +4660,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) min_t(int, server->max_credits - server->credits, credit_request)); - rc = adjust_credits(server, &rdata->credits, rdata->subreq.len); + rc = adjust_credits(server, rdata, cifs_trace_rw_credits_call_readv_adjust); if (rc) goto async_readv_out; @@ -4766,7 +4779,14 @@ smb2_writev_callback(struct mid_q_entry *mid) struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink); struct TCP_Server_Info *server = wdata->server; struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf; - struct cifs_credits credits = { .value = 0, .instance = 0 }; + struct cifs_credits credits = { + .value = 0, + .instance = 0, + .rreq_debug_id = wdata->rreq->debug_id, + .rreq_debug_index = wdata->subreq.debug_index, + }; + unsigned int rreq_debug_id = wdata->rreq->debug_id; + unsigned int subreq_debug_index = wdata->subreq.debug_index; ssize_t result = 0; size_t written; @@ -4837,9 +4857,15 @@ smb2_writev_callback(struct mid_q_entry *mid) tcon->tid, tcon->ses->Suid, wdata->subreq.start, wdata->subreq.len); + trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, wdata->credits.value, + server->credits, server->in_flight, + 0, cifs_trace_rw_credits_write_response_clear); wdata->credits.value = 0; cifs_write_subrequest_terminated(wdata, result ?: written, true); release_mid(mid); + trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0, + server->credits, server->in_flight, + credits.value, cifs_trace_rw_credits_write_response_add); add_credits(server, &credits, 0); } @@ -4859,9 +4885,6 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) struct cifs_io_parms *io_parms = NULL; int credit_request; - if (!wdata->server || test_bit(NETFS_SREQ_RETRYING, &wdata->subreq.flags)) - server = wdata->server = cifs_pick_channel(tcon->ses); - /* * in future we may get cifs_io_parms passed in from the caller, * but for now we construct it here... @@ -4972,7 +4995,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) min_t(int, server->max_credits - server->credits, credit_request)); - rc = adjust_credits(server, &wdata->credits, io_parms->length); + rc = adjust_credits(server, wdata, cifs_trace_rw_credits_call_writev_adjust); if (rc) goto async_writev_out; @@ -4997,6 +5020,12 @@ async_writev_out: cifs_small_buf_release(req); out: if (rc) { + trace_smb3_rw_credits(wdata->rreq->debug_id, + wdata->subreq.debug_index, + wdata->credits.value, + server->credits, server->in_flight, + -(int)wdata->credits.value, + cifs_trace_rw_credits_write_response_clear); add_credits_and_wake_if(wdata->server, &wdata->credits, 0); cifs_write_subrequest_terminated(wdata, rc, true); } diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h index 36d47ce59631..36d5295c2a6f 100644 --- a/fs/smb/client/trace.h +++ b/fs/smb/client/trace.h @@ -20,6 +20,22 @@ /* * Specify enums for tracing information. */ +#define smb3_rw_credits_traces \ + EM(cifs_trace_rw_credits_call_readv_adjust, "rd-call-adj") \ + EM(cifs_trace_rw_credits_call_writev_adjust, "wr-call-adj") \ + EM(cifs_trace_rw_credits_free_subreq, "free-subreq") \ + EM(cifs_trace_rw_credits_issue_read_adjust, "rd-issu-adj") \ + EM(cifs_trace_rw_credits_issue_write_adjust, "wr-issu-adj") \ + EM(cifs_trace_rw_credits_no_adjust_up, "no-adj-up ") \ + EM(cifs_trace_rw_credits_old_session, "old-session") \ + EM(cifs_trace_rw_credits_read_response_add, "rd-resp-add") \ + EM(cifs_trace_rw_credits_read_response_clear, "rd-resp-clr") \ + EM(cifs_trace_rw_credits_read_submit, "rd-submit ") \ + EM(cifs_trace_rw_credits_write_prepare, "wr-prepare ") \ + EM(cifs_trace_rw_credits_write_response_add, "wr-resp-add") \ + EM(cifs_trace_rw_credits_write_response_clear, "wr-resp-clr") \ + E_(cifs_trace_rw_credits_zero_in_flight, "ZERO-IN-FLT") + #define smb3_tcon_ref_traces \ EM(netfs_trace_tcon_ref_dec_dfs_refer, "DEC DfsRef") \ EM(netfs_trace_tcon_ref_free, "FRE ") \ @@ -59,7 +75,8 @@ #define EM(a, b) a, #define E_(a, b) a -enum smb3_tcon_ref_trace { smb3_tcon_ref_traces } __mode(byte); +enum smb3_rw_credits_trace { smb3_rw_credits_traces } __mode(byte); +enum smb3_tcon_ref_trace { smb3_tcon_ref_traces } __mode(byte); #undef EM #undef E_ @@ -71,6 +88,7 @@ enum smb3_tcon_ref_trace { smb3_tcon_ref_traces } __mode(byte); #define EM(a, b) TRACE_DEFINE_ENUM(a); #define E_(a, b) TRACE_DEFINE_ENUM(a); +smb3_rw_credits_traces; smb3_tcon_ref_traces; #undef EM @@ -1316,6 +1334,41 @@ TRACE_EVENT(smb3_tcon_ref, __entry->ref) ); +TRACE_EVENT(smb3_rw_credits, + TP_PROTO(unsigned int rreq_debug_id, + unsigned int subreq_debug_index, + unsigned int subreq_credits, + unsigned int server_credits, + int server_in_flight, + int credit_change, + enum smb3_rw_credits_trace trace), + TP_ARGS(rreq_debug_id, subreq_debug_index, subreq_credits, + server_credits, server_in_flight, credit_change, trace), + TP_STRUCT__entry( + __field(unsigned int, rreq_debug_id) + __field(unsigned int, subreq_debug_index) + __field(unsigned int, subreq_credits) + __field(unsigned int, server_credits) + __field(int, in_flight) + __field(int, credit_change) + __field(enum smb3_rw_credits_trace, trace) + ), + TP_fast_assign( + __entry->rreq_debug_id = rreq_debug_id; + __entry->subreq_debug_index = subreq_debug_index; + __entry->subreq_credits = subreq_credits; + __entry->server_credits = server_credits; + __entry->in_flight = server_in_flight; + __entry->credit_change = credit_change; + __entry->trace = trace; + ), + TP_printk("R=%08x[%x] %s cred=%u chg=%d pool=%u ifl=%d", + __entry->rreq_debug_id, __entry->subreq_debug_index, + __print_symbolic(__entry->trace, smb3_rw_credits_traces), + __entry->subreq_credits, __entry->credit_change, + __entry->server_credits, __entry->in_flight) + ); + #undef EM #undef E_ diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 012b9bd06995..adfe0d058701 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -988,10 +988,10 @@ static void cifs_compound_callback(struct mid_q_entry *mid) { struct TCP_Server_Info *server = mid->server; - struct cifs_credits credits; - - credits.value = server->ops->get_credits(mid); - credits.instance = server->reconnect_instance; + struct cifs_credits credits = { + .value = server->ops->get_credits(mid), + .instance = server->reconnect_instance, + }; add_credits(server, &credits, mid->optype); diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h index c82d56768101..c6d18f50f671 100644 --- a/include/linux/arm_ffa.h +++ b/include/linux/arm_ffa.h @@ -212,6 +212,9 @@ bool ffa_device_is_valid(struct ffa_device *ffa_dev) { return false; } extern const struct bus_type ffa_bus_type; +/* The FF-A 1.0 partition structure lacks the uuid[4] */ +#define FFA_1_0_PARTITON_INFO_SZ (8) + /* FFA transport related */ struct ffa_partition_info { u16 id; diff --git a/include/linux/crc32.h b/include/linux/crc32.h index 9e8a032c1788..87f788c0d607 100644 --- a/include/linux/crc32.h +++ b/include/linux/crc32.h @@ -9,7 +9,9 @@ #include u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len); +u32 __pure crc32_le_base(u32 crc, unsigned char const *p, size_t len); u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len); +u32 __pure crc32_be_base(u32 crc, unsigned char const *p, size_t len); /** * crc32_le_combine - Combine two crc32 check values into one. For two @@ -37,6 +39,7 @@ static inline u32 crc32_le_combine(u32 crc1, u32 crc2, size_t len2) } u32 __pure __crc32c_le(u32 crc, unsigned char const *p, size_t len); +u32 __pure __crc32c_le_base(u32 crc, unsigned char const *p, size_t len); /** * __crc32c_le_combine - Combine two crc32c check values into one. For two diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 692c01e41a18..689e8be873a7 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -378,8 +378,10 @@ struct kvm_vcpu { bool dy_eligible; } spin_loop; #endif + bool wants_to_run; bool preempted; bool ready; + bool scheduled_out; struct kvm_vcpu_arch arch; struct kvm_vcpu_stat stat; char stats_id[KVM_STATS_NAME_SIZE]; @@ -1494,8 +1496,6 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg); int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu); -void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu); - void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu); void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu); int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id); @@ -1955,8 +1955,6 @@ struct _kvm_stats_desc { HALT_POLL_HIST_COUNT), \ STATS_DESC_IBOOLEAN(VCPU_GENERIC, blocking) -extern struct dentry *kvm_debugfs_dir; - ssize_t kvm_stats_read(char *id, const struct kvm_stats_header *header, const struct _kvm_stats_desc *desc, void *stats, size_t size_stats, @@ -2096,6 +2094,7 @@ int kvm_set_irq_routing(struct kvm *kvm, const struct kvm_irq_routing_entry *entries, unsigned nr, unsigned flags); +int kvm_init_irq_routing(struct kvm *kvm); int kvm_set_routing_entry(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *e, const struct kvm_irq_routing_entry *ue); @@ -2105,6 +2104,11 @@ void kvm_free_irq_routing(struct kvm *kvm); static inline void kvm_free_irq_routing(struct kvm *kvm) {} +static inline int kvm_init_irq_routing(struct kvm *kvm) +{ + return 0; +} + #endif int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi); @@ -2441,4 +2445,45 @@ static inline int kvm_gmem_get_pfn(struct kvm *kvm, } #endif /* CONFIG_KVM_PRIVATE_MEM */ +#ifdef CONFIG_HAVE_KVM_GMEM_PREPARE +int kvm_arch_gmem_prepare(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, int max_order); +bool kvm_arch_gmem_prepare_needed(struct kvm *kvm); +#endif + +/** + * kvm_gmem_populate() - Populate/prepare a GPA range with guest data + * + * @kvm: KVM instance + * @gfn: starting GFN to be populated + * @src: userspace-provided buffer containing data to copy into GFN range + * (passed to @post_populate, and incremented on each iteration + * if not NULL) + * @npages: number of pages to copy from userspace-buffer + * @post_populate: callback to issue for each gmem page that backs the GPA + * range + * @opaque: opaque data to pass to @post_populate callback + * + * This is primarily intended for cases where a gmem-backed GPA range needs + * to be initialized with userspace-provided data prior to being mapped into + * the guest as a private page. This should be called with the slots->lock + * held so that caller-enforced invariants regarding the expected memory + * attributes of the GPA range do not race with KVM_SET_MEMORY_ATTRIBUTES. + * + * Returns the number of pages that were populated. + */ +typedef int (*kvm_gmem_populate_cb)(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, + void __user *src, int order, void *opaque); + +long kvm_gmem_populate(struct kvm *kvm, gfn_t gfn, void __user *src, long npages, + kvm_gmem_populate_cb post_populate, void *opaque); + +#ifdef CONFIG_HAVE_KVM_GMEM_INVALIDATE +void kvm_arch_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end); +#endif + +#ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY +long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, + struct kvm_pre_fault_memory *range); +#endif + #endif diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index 947410faf9e2..35ca19ae21ae 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -308,32 +308,32 @@ static inline uint8_t cfi_read_query(struct map_info *map, uint32_t addr) { map_word val = map_read(map, addr); - if (map_bankwidth_is_1(map)) { + if (map_bankwidth_is_1(map)) return val.x[0]; - } else if (map_bankwidth_is_2(map)) { + if (map_bankwidth_is_2(map)) return cfi16_to_cpu(map, val.x[0]); - } else { - /* No point in a 64-bit byteswap since that would just be - swapping the responses from different chips, and we are - only interested in one chip (a representative sample) */ - return cfi32_to_cpu(map, val.x[0]); - } + /* + * No point in a 64-bit byteswap since that would just be + * swapping the responses from different chips, and we are + * only interested in one chip (a representative sample) + */ + return cfi32_to_cpu(map, val.x[0]); } static inline uint16_t cfi_read_query16(struct map_info *map, uint32_t addr) { map_word val = map_read(map, addr); - if (map_bankwidth_is_1(map)) { + if (map_bankwidth_is_1(map)) return val.x[0] & 0xff; - } else if (map_bankwidth_is_2(map)) { + if (map_bankwidth_is_2(map)) return cfi16_to_cpu(map, val.x[0]); - } else { - /* No point in a 64-bit byteswap since that would just be - swapping the responses from different chips, and we are - only interested in one chip (a representative sample) */ - return cfi32_to_cpu(map, val.x[0]); - } + /* + * No point in a 64-bit byteswap since that would just be + * swapping the responses from different chips, and we are + * only interested in one chip (a representative sample) + */ + return cfi32_to_cpu(map, val.x[0]); } void cfi_udelay(int us); diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index a0a026d2d244..2d72bd89bf7b 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -208,7 +208,8 @@ enum mapping_flags { AS_RELEASE_ALWAYS, /* Call ->release_folio(), even if no private data */ AS_STABLE_WRITES, /* must wait for writeback before modifying folio contents */ - AS_UNMOVABLE, /* The mapping cannot be moved, ever */ + AS_INACCESSIBLE, /* Do not attempt direct R/W access to the mapping, + including to move the mapping */ }; /** @@ -309,20 +310,20 @@ static inline void mapping_clear_stable_writes(struct address_space *mapping) clear_bit(AS_STABLE_WRITES, &mapping->flags); } -static inline void mapping_set_unmovable(struct address_space *mapping) +static inline void mapping_set_inaccessible(struct address_space *mapping) { /* - * It's expected unmovable mappings are also unevictable. Compaction + * It's expected inaccessible mappings are also unevictable. Compaction * migrate scanner (isolate_migratepages_block()) relies on this to * reduce page locking. */ set_bit(AS_UNEVICTABLE, &mapping->flags); - set_bit(AS_UNMOVABLE, &mapping->flags); + set_bit(AS_INACCESSIBLE, &mapping->flags); } -static inline bool mapping_unmovable(struct address_space *mapping) +static inline bool mapping_inaccessible(struct address_space *mapping) { - return test_bit(AS_UNMOVABLE, &mapping->flags); + return test_bit(AS_INACCESSIBLE, &mapping->flags); } static inline gfp_t mapping_gfp_mask(struct address_space * mapping) diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h index 3705c2044fc0..903ddfea8585 100644 --- a/include/linux/psp-sev.h +++ b/include/linux/psp-sev.h @@ -658,6 +658,7 @@ struct sev_data_snp_launch_update { * @id_auth_paddr: system physical address of ID block authentication structure * @id_block_en: indicates whether ID block is present * @auth_key_en: indicates whether author key is present in authentication structure + * @vcek_disabled: indicates whether use of VCEK is allowed for attestation reports * @rsvd: reserved * @host_data: host-supplied data for guest, not interpreted by firmware */ @@ -667,7 +668,8 @@ struct sev_data_snp_launch_finish { u64 id_auth_paddr; u8 id_block_en:1; u8 auth_key_en:1; - u64 rsvd:62; + u8 vcek_disabled:1; + u64 rsvd:61; u8 host_data[32]; } __packed; diff --git a/include/linux/srcu.h b/include/linux/srcu.h index 6f6cb5fc1242..835bbb2d1f88 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h @@ -378,6 +378,20 @@ static inline void smp_mb__after_srcu_read_unlock(void) /* __srcu_read_unlock has smp_mb() internally so nothing to do here. */ } +/** + * smp_mb__after_srcu_read_lock - ensure full ordering after srcu_read_lock + * + * Converts the preceding srcu_read_lock into a two-way memory barrier. + * + * Call this after srcu_read_lock, to guarantee that all memory operations + * that occur after smp_mb__after_srcu_read_lock will appear to happen after + * the preceding srcu_read_lock. + */ +static inline void smp_mb__after_srcu_read_lock(void) +{ + /* __srcu_read_lock has smp_mb() internally so nothing to do here. */ +} + DEFINE_LOCK_GUARD_1(srcu, struct srcu_struct, _T->idx = srcu_read_lock(_T->lock), srcu_read_unlock(_T->lock, _T->idx), diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h index 5ccc0d91b220..b108176deb22 100644 --- a/include/trace/events/firewire.h +++ b/include/trace/events/firewire.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright (c) 2024 Takashi Sakamoto +#undef TRACE_SYSTEM #define TRACE_SYSTEM firewire #if !defined(_FIREWIRE_TRACE_EVENT_H) || defined(TRACE_HEADER_MULTI_READ) @@ -11,7 +12,7 @@ #include -#include "../../../drivers/firewire/packet-header-definitions.h" +// Some macros are defined in 'drivers/firewire/packet-header-definitions.h'. // The content of TP_printk field is preprocessed, then put to the module binary. #define ASYNC_HEADER_GET_DESTINATION(header) \ @@ -366,6 +367,544 @@ TRACE_EVENT(bus_reset_handle, ) ); +// Some macros are defined in 'drivers/firewire/phy-packet-definitions.h'. + +// The content of TP_printk field is preprocessed, then put to the module binary. + +#define PHY_PACKET_SELF_ID_GET_PHY_ID(quads) \ + ((((const u32 *)quads)[0] & SELF_ID_PHY_ID_MASK) >> SELF_ID_PHY_ID_SHIFT) + +#define PHY_PACKET_SELF_ID_GET_LINK_ACTIVE(quads) \ + ((((const u32 *)quads)[0] & SELF_ID_ZERO_LINK_ACTIVE_MASK) >> SELF_ID_ZERO_LINK_ACTIVE_SHIFT) + +#define PHY_PACKET_SELF_ID_GET_GAP_COUNT(quads) \ + ((((const u32 *)quads)[0] & SELF_ID_ZERO_GAP_COUNT_MASK) >> SELF_ID_ZERO_GAP_COUNT_SHIFT) + +#define PHY_PACKET_SELF_ID_GET_SCODE(quads) \ + ((((const u32 *)quads)[0] & SELF_ID_ZERO_SCODE_MASK) >> SELF_ID_ZERO_SCODE_SHIFT) + +#define PHY_PACKET_SELF_ID_GET_CONTENDER(quads) \ + ((((const u32 *)quads)[0] & SELF_ID_ZERO_CONTENDER_MASK) >> SELF_ID_ZERO_CONTENDER_SHIFT) + +#define PHY_PACKET_SELF_ID_GET_POWER_CLASS(quads) \ + ((((const u32 *)quads)[0] & SELF_ID_ZERO_POWER_CLASS_MASK) >> SELF_ID_ZERO_POWER_CLASS_SHIFT) + +#define PHY_PACKET_SELF_ID_GET_INITIATED_RESET(quads) \ + ((((const u32 *)quads)[0] & SELF_ID_ZERO_INITIATED_RESET_MASK) >> SELF_ID_ZERO_INITIATED_RESET_SHIFT) + +TRACE_EVENT(self_id_sequence, + TP_PROTO(unsigned int card_index, const u32 *self_id_sequence, unsigned int quadlet_count, unsigned int generation), + TP_ARGS(card_index, self_id_sequence, quadlet_count, generation), + TP_STRUCT__entry( + __field(u8, card_index) + __field(u8, generation) + __dynamic_array(u8, port_status, self_id_sequence_get_port_capacity(quadlet_count)) + __dynamic_array(u32, self_id_sequence, quadlet_count) + ), + TP_fast_assign( + __entry->card_index = card_index; + __entry->generation = generation; + { + u8 *port_status = __get_dynamic_array(port_status); + unsigned int port_index; + + for (port_index = 0; port_index < __get_dynamic_array_len(port_status); ++port_index) { + port_status[port_index] = + self_id_sequence_get_port_status(self_id_sequence, + quadlet_count, port_index); + } + } + memcpy(__get_dynamic_array(self_id_sequence), self_id_sequence, + __get_dynamic_array_len(self_id_sequence)); + ), + TP_printk( + "card_index=%u generation=%u phy_id=0x%02x link_active=%s gap_count=%u scode=%u contender=%s power_class=%u initiated_reset=%s port_status=%s self_id_sequence=%s", + __entry->card_index, + __entry->generation, + PHY_PACKET_SELF_ID_GET_PHY_ID(__get_dynamic_array(self_id_sequence)), + PHY_PACKET_SELF_ID_GET_LINK_ACTIVE(__get_dynamic_array(self_id_sequence)) ? "true" : "false", + PHY_PACKET_SELF_ID_GET_GAP_COUNT(__get_dynamic_array(self_id_sequence)), + PHY_PACKET_SELF_ID_GET_SCODE(__get_dynamic_array(self_id_sequence)), + PHY_PACKET_SELF_ID_GET_CONTENDER(__get_dynamic_array(self_id_sequence)) ? "true" : "false", + PHY_PACKET_SELF_ID_GET_POWER_CLASS(__get_dynamic_array(self_id_sequence)), + PHY_PACKET_SELF_ID_GET_INITIATED_RESET(__get_dynamic_array(self_id_sequence)) ? "true" : "false", + __print_array(__get_dynamic_array(port_status), __get_dynamic_array_len(port_status), 1), + __print_array(__get_dynamic_array(self_id_sequence), + __get_dynamic_array_len(self_id_sequence) / QUADLET_SIZE, QUADLET_SIZE) + ) +); + +#undef PHY_PACKET_SELF_ID_GET_PHY_ID +#undef PHY_PACKET_SELF_ID_GET_LINK_ACTIVE +#undef PHY_PACKET_SELF_ID_GET_GAP_COUNT +#undef PHY_PACKET_SELF_ID_GET_SCODE +#undef PHY_PACKET_SELF_ID_GET_CONTENDER +#undef PHY_PACKET_SELF_ID_GET_POWER_CLASS +#undef PHY_PACKET_SELF_ID_GET_INITIATED_RESET + +TRACE_EVENT_CONDITION(isoc_outbound_allocate, + TP_PROTO(const struct fw_iso_context *ctx, unsigned int channel, unsigned int scode), + TP_ARGS(ctx, channel, scode), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_TRANSMIT), + TP_STRUCT__entry( + __field(u64, context) + __field(u8, card_index) + __field(u8, channel) + __field(u8, scode) + ), + TP_fast_assign( + __entry->context = (uintptr_t)ctx; + __entry->card_index = ctx->card->index; + __entry->channel = channel; + __entry->scode = scode; + ), + TP_printk( + "context=0x%llx card_index=%u channel=%u scode=%u", + __entry->context, + __entry->card_index, + __entry->channel, + __entry->scode + ) +); + +TRACE_EVENT_CONDITION(isoc_inbound_single_allocate, + TP_PROTO(const struct fw_iso_context *ctx, unsigned int channel, unsigned int header_size), + TP_ARGS(ctx, channel, header_size), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE), + TP_STRUCT__entry( + __field(u64, context) + __field(u8, card_index) + __field(u8, channel) + __field(u8, header_size) + ), + TP_fast_assign( + __entry->context = (uintptr_t)ctx; + __entry->card_index = ctx->card->index; + __entry->channel = channel; + __entry->header_size = header_size; + ), + TP_printk( + "context=0x%llx card_index=%u channel=%u header_size=%u", + __entry->context, + __entry->card_index, + __entry->channel, + __entry->header_size + ) +); + +TRACE_EVENT_CONDITION(isoc_inbound_multiple_allocate, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL), + TP_STRUCT__entry( + __field(u64, context) + __field(u8, card_index) + ), + TP_fast_assign( + __entry->context = (uintptr_t)ctx; + __entry->card_index = ctx->card->index; + ), + TP_printk( + "context=0x%llx card_index=%u", + __entry->context, + __entry->card_index + ) +); + +DECLARE_EVENT_CLASS(isoc_destroy_template, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_STRUCT__entry( + __field(u64, context) + __field(u8, card_index) + ), + TP_fast_assign( + __entry->context = (uintptr_t)ctx; + __entry->card_index = ctx->card->index; + ), + TP_printk( + "context=0x%llx card_index=%u", + __entry->context, + __entry->card_index + ) +) + +DEFINE_EVENT_CONDITION(isoc_destroy_template, isoc_outbound_destroy, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_TRANSMIT) +); + +DEFINE_EVENT_CONDITION(isoc_destroy_template, isoc_inbound_single_destroy, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE) +); + +DEFINE_EVENT_CONDITION(isoc_destroy_template, isoc_inbound_multiple_destroy, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL) +); + +TRACE_EVENT(isoc_inbound_multiple_channels, + TP_PROTO(const struct fw_iso_context *ctx, u64 channels), + TP_ARGS(ctx, channels), + TP_STRUCT__entry( + __field(u64, context) + __field(u8, card_index) + __field(u64, channels) + ), + TP_fast_assign( + __entry->context = (uintptr_t)ctx; + __entry->card_index = ctx->card->index; + __entry->channels = channels; + ), + TP_printk( + "context=0x%llx card_index=%u channels=0x%016llx", + __entry->context, + __entry->card_index, + __entry->channels + ) +); + +TRACE_EVENT_CONDITION(isoc_outbound_start, + TP_PROTO(const struct fw_iso_context *ctx, int cycle_match), + TP_ARGS(ctx, cycle_match), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_TRANSMIT), + TP_STRUCT__entry( + __field(u64, context) + __field(u8, card_index) + __field(bool, cycle_match) + __field(u16, cycle) + ), + TP_fast_assign( + __entry->context = (uintptr_t)ctx; + __entry->card_index = ctx->card->index; + __entry->cycle_match = cycle_match < 0 ? false : true; + __entry->cycle = __entry->cycle_match ? (u16)cycle_match : 0; + ), + TP_printk( + "context=0x%llx card_index=%u cycle_match=%s cycle=0x%04x", + __entry->context, + __entry->card_index, + __entry->cycle_match ? "true" : "false", + __entry->cycle + ) +); + +DECLARE_EVENT_CLASS(isoc_inbound_start_template, + TP_PROTO(const struct fw_iso_context *ctx, int cycle_match, unsigned int sync, unsigned int tags), + TP_ARGS(ctx, cycle_match, sync, tags), + TP_STRUCT__entry( + __field(u64, context) + __field(u8, card_index) + __field(bool, cycle_match) + __field(u16, cycle) + __field(u8, sync) + __field(u8, tags) + ), + TP_fast_assign( + __entry->context = (uintptr_t)ctx; + __entry->card_index = ctx->card->index; + __entry->cycle_match = cycle_match < 0 ? false : true; + __entry->cycle = __entry->cycle_match ? (u16)cycle_match : 0; + __entry->sync = sync; + __entry->tags = tags; + ), + TP_printk( + "context=0x%llx card_index=%u cycle_match=%s cycle=0x%04x sync=%u tags=%s", + __entry->context, + __entry->card_index, + __entry->cycle_match ? "true" : "false", + __entry->cycle, + __entry->sync, + __print_flags(__entry->tags, "|", + { FW_ISO_CONTEXT_MATCH_TAG0, "0" }, + { FW_ISO_CONTEXT_MATCH_TAG1, "1" }, + { FW_ISO_CONTEXT_MATCH_TAG2, "2" }, + { FW_ISO_CONTEXT_MATCH_TAG3, "3" } + ) + ) +); + +DEFINE_EVENT_CONDITION(isoc_inbound_start_template, isoc_inbound_single_start, + TP_PROTO(const struct fw_iso_context *ctx, int cycle_match, unsigned int sync, unsigned int tags), + TP_ARGS(ctx, cycle_match, sync, tags), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE) +); + +DEFINE_EVENT_CONDITION(isoc_inbound_start_template, isoc_inbound_multiple_start, + TP_PROTO(const struct fw_iso_context *ctx, int cycle_match, unsigned int sync, unsigned int tags), + TP_ARGS(ctx, cycle_match, sync, tags), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL) +); + +DECLARE_EVENT_CLASS(isoc_stop_template, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_STRUCT__entry( + __field(u64, context) + __field(u8, card_index) + ), + TP_fast_assign( + __entry->context = (uintptr_t)ctx; + __entry->card_index = ctx->card->index; + ), + TP_printk( + "context=0x%llx card_index=%u", + __entry->context, + __entry->card_index + ) +) + +DEFINE_EVENT_CONDITION(isoc_stop_template, isoc_outbound_stop, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_TRANSMIT) +); + +DEFINE_EVENT_CONDITION(isoc_stop_template, isoc_inbound_single_stop, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE) +); + +DEFINE_EVENT_CONDITION(isoc_stop_template, isoc_inbound_multiple_stop, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL) +); + +DECLARE_EVENT_CLASS(isoc_flush_template, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_STRUCT__entry( + __field(u64, context) + __field(u8, card_index) + ), + TP_fast_assign( + __entry->context = (uintptr_t)ctx; + __entry->card_index = ctx->card->index; + ), + TP_printk( + "context=0x%llx card_index=%u", + __entry->context, + __entry->card_index + ) +); + +DEFINE_EVENT_CONDITION(isoc_flush_template, isoc_outbound_flush, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_TRANSMIT) +); + +DEFINE_EVENT_CONDITION(isoc_flush_template, isoc_inbound_single_flush, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE) +); + +DEFINE_EVENT_CONDITION(isoc_flush_template, isoc_inbound_multiple_flush, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL) +); + +DECLARE_EVENT_CLASS(isoc_flush_completions_template, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_STRUCT__entry( + __field(u64, context) + __field(u8, card_index) + ), + TP_fast_assign( + __entry->context = (uintptr_t)ctx; + __entry->card_index = ctx->card->index; + ), + TP_printk( + "context=0x%llx card_index=%u", + __entry->context, + __entry->card_index + ) +); + +DEFINE_EVENT_CONDITION(isoc_flush_completions_template, isoc_outbound_flush_completions, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_TRANSMIT) +); + +DEFINE_EVENT_CONDITION(isoc_flush_completions_template, isoc_inbound_single_flush_completions, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE) +); + +DEFINE_EVENT_CONDITION(isoc_flush_completions_template, isoc_inbound_multiple_flush_completions, + TP_PROTO(const struct fw_iso_context *ctx), + TP_ARGS(ctx), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL) +); + +#define TP_STRUCT__entry_iso_packet(ctx, buffer_offset, packet) \ + TP_STRUCT__entry( \ + __field(u64, context) \ + __field(u8, card_index) \ + __field(u32, buffer_offset) \ + __field(bool, interrupt) \ + __field(bool, skip) \ + __field(u8, sy) \ + __field(u8, tag) \ + __dynamic_array(u32, header, packet->header_length / QUADLET_SIZE) \ + ) + +#define TP_fast_assign_iso_packet(ctx, buffer_offset, packet) \ + TP_fast_assign( \ + __entry->context = (uintptr_t)ctx; \ + __entry->card_index = ctx->card->index; \ + __entry->buffer_offset = buffer_offset; \ + __entry->interrupt = packet->interrupt; \ + __entry->skip = packet->skip; \ + __entry->sy = packet->sy; \ + __entry->tag = packet->tag; \ + memcpy(__get_dynamic_array(header), packet->header, \ + __get_dynamic_array_len(header)); \ + ) + +TRACE_EVENT_CONDITION(isoc_outbound_queue, + TP_PROTO(const struct fw_iso_context *ctx, unsigned long buffer_offset, const struct fw_iso_packet *packet), + TP_ARGS(ctx, buffer_offset, packet), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_TRANSMIT), + TP_STRUCT__entry_iso_packet(ctx, buffer_offset, packet), + TP_fast_assign_iso_packet(ctx, buffer_offset, packet), + TP_printk( + "context=0x%llx card_index=%u buffer_offset=0x%x interrupt=%s skip=%s sy=%d tag=%u header=%s", + __entry->context, + __entry->card_index, + __entry->buffer_offset, + __entry->interrupt ? "true" : "false", + __entry->skip ? "true" : "false", + __entry->sy, + __entry->tag, + __print_array(__get_dynamic_array(header), + __get_dynamic_array_len(header) / QUADLET_SIZE, QUADLET_SIZE) + ) +); + +TRACE_EVENT_CONDITION(isoc_inbound_single_queue, + TP_PROTO(const struct fw_iso_context *ctx, unsigned long buffer_offset, const struct fw_iso_packet *packet), + TP_ARGS(ctx, buffer_offset, packet), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE), + TP_STRUCT__entry_iso_packet(ctx, buffer_offset, packet), + TP_fast_assign_iso_packet(ctx, buffer_offset, packet), + TP_printk( + "context=0x%llx card_index=%u buffer_offset=0x%x interrupt=%s skip=%s", + __entry->context, + __entry->card_index, + __entry->buffer_offset, + __entry->interrupt ? "true" : "false", + __entry->skip ? "true" : "false" + ) +); + +TRACE_EVENT_CONDITION(isoc_inbound_multiple_queue, + TP_PROTO(const struct fw_iso_context *ctx, unsigned long buffer_offset, const struct fw_iso_packet *packet), + TP_ARGS(ctx, buffer_offset, packet), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL), + TP_STRUCT__entry_iso_packet(ctx, buffer_offset, packet), + TP_fast_assign_iso_packet(ctx, buffer_offset, packet), + TP_printk( + "context=0x%llx card_index=%u buffer_offset=0x%x interrupt=%s", + __entry->context, + __entry->card_index, + __entry->buffer_offset, + __entry->interrupt ? "true" : "false" + ) +); + +#undef TP_STRUCT__entry_iso_packet +#undef TP_fast_assign_iso_packet + +#ifndef show_cause +enum fw_iso_context_completions_cause { + FW_ISO_CONTEXT_COMPLETIONS_CAUSE_FLUSH = 0, + FW_ISO_CONTEXT_COMPLETIONS_CAUSE_IRQ, + FW_ISO_CONTEXT_COMPLETIONS_CAUSE_HEADER_OVERFLOW, +}; +#define show_cause(cause) \ + __print_symbolic(cause, \ + { FW_ISO_CONTEXT_COMPLETIONS_CAUSE_FLUSH, "FLUSH" }, \ + { FW_ISO_CONTEXT_COMPLETIONS_CAUSE_IRQ, "IRQ" }, \ + { FW_ISO_CONTEXT_COMPLETIONS_CAUSE_HEADER_OVERFLOW, "HEADER_OVERFLOW" } \ + ) +#endif + +DECLARE_EVENT_CLASS(isoc_single_completions_template, + TP_PROTO(const struct fw_iso_context *ctx, u16 timestamp, enum fw_iso_context_completions_cause cause, const u32 *header, unsigned int header_length), + TP_ARGS(ctx, timestamp, cause, header, header_length), + TP_STRUCT__entry( + __field(u64, context) + __field(u8, card_index) + __field(u16, timestamp) + __field(u8, cause) + __dynamic_array(u32, header, header_length / QUADLET_SIZE) + ), + TP_fast_assign( + __entry->context = (uintptr_t)ctx; + __entry->card_index = ctx->card->index; + __entry->timestamp = timestamp; + __entry->cause = cause; + memcpy(__get_dynamic_array(header), header, __get_dynamic_array_len(header)); + ), + TP_printk( + "context=0x%llx card_index=%u timestamp=0x%04x cause=%s header=%s", + __entry->context, + __entry->card_index, + __entry->timestamp, + show_cause(__entry->cause), + __print_array(__get_dynamic_array(header), + __get_dynamic_array_len(header) / QUADLET_SIZE, QUADLET_SIZE) + ) +) + +DEFINE_EVENT_CONDITION(isoc_single_completions_template, isoc_outbound_completions, + TP_PROTO(const struct fw_iso_context *ctx, u16 timestamp, enum fw_iso_context_completions_cause cause, const u32 *header, unsigned int header_length), + TP_ARGS(ctx, timestamp, cause, header, header_length), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_TRANSMIT) +); + +DEFINE_EVENT_CONDITION(isoc_single_completions_template, isoc_inbound_single_completions, + TP_PROTO(const struct fw_iso_context *ctx, u16 timestamp, enum fw_iso_context_completions_cause cause, const u32 *header, unsigned int header_length), + TP_ARGS(ctx, timestamp, cause, header, header_length), + TP_CONDITION(ctx->type == FW_ISO_CONTEXT_RECEIVE) +); + +TRACE_EVENT(isoc_inbound_multiple_completions, + TP_PROTO(const struct fw_iso_context *ctx, unsigned int completed, enum fw_iso_context_completions_cause cause), + TP_ARGS(ctx, completed, cause), + TP_STRUCT__entry( + __field(u64, context) + __field(u8, card_index) + __field(u16, completed) + __field(u8, cause) + ), + TP_fast_assign( + __entry->context = (uintptr_t)ctx; + __entry->card_index = ctx->card->index; + __entry->completed = completed; + __entry->cause = cause; + ), + TP_printk( + "context=0x%llx card_index=%u completed=%u cause=%s", + __entry->context, + __entry->card_index, + __entry->completed, + show_cause(__entry->cause) + ) +); + #undef QUADLET_SIZE #endif // _FIREWIRE_TRACE_EVENT_H diff --git a/include/trace/events/firewire_ohci.h b/include/trace/events/firewire_ohci.h new file mode 100644 index 000000000000..4f9a7f2577f3 --- /dev/null +++ b/include/trace/events/firewire_ohci.h @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2024 Takashi Sakamoto + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM firewire_ohci + +#if !defined(_FIREWIRE_OHCI_TRACE_EVENT_H) || defined(TRACE_HEADER_MULTI_READ) +#define _FIREWIRE_OHCI_TRACE_EVENT_H + +#include + +// Some macros and helper functions are defined in 'drivers/firewire/ohci.c'. + +TRACE_EVENT(irqs, + TP_PROTO(unsigned int card_index, u32 events), + TP_ARGS(card_index, events), + TP_STRUCT__entry( + __field(u8, card_index) + __field(u32, events) + ), + TP_fast_assign( + __entry->card_index = card_index; + __entry->events = events; + ), + TP_printk( + "card_index=%u events=%s", + __entry->card_index, + __print_flags(__entry->events, "|", + { OHCI1394_selfIDComplete, "selfIDComplete" }, + { OHCI1394_RQPkt, "RQPkt" }, + { OHCI1394_RSPkt, "RSPkt" }, + { OHCI1394_reqTxComplete, "reqTxComplete" }, + { OHCI1394_respTxComplete, "respTxComplete" }, + { OHCI1394_isochRx, "isochRx" }, + { OHCI1394_isochTx, "isochTx" }, + { OHCI1394_postedWriteErr, "postedWriteErr" }, + { OHCI1394_cycleTooLong, "cycleTooLong" }, + { OHCI1394_cycle64Seconds, "cycle64Seconds" }, + { OHCI1394_cycleInconsistent, "cycleInconsistent" }, + { OHCI1394_regAccessFail, "regAccessFail" }, + { OHCI1394_unrecoverableError, "unrecoverableError" }, + { OHCI1394_busReset, "busReset" } + ) + ) +); + +#define QUADLET_SIZE 4 + +#define SELF_ID_COUNT_IS_ERROR(reg) \ + (!!(((reg) & OHCI1394_SelfIDCount_selfIDError_MASK) >> OHCI1394_SelfIDCount_selfIDError_SHIFT)) + +#define SELF_ID_COUNT_GET_GENERATION(reg) \ + (((reg) & OHCI1394_SelfIDCount_selfIDGeneration_MASK) >> OHCI1394_SelfIDCount_selfIDGeneration_SHIFT) + +#define SELF_ID_RECEIVE_Q0_GET_GENERATION(quadlet) \ + (((quadlet) & OHCI1394_SELF_ID_RECEIVE_Q0_GENERATION_MASK) >> OHCI1394_SELF_ID_RECEIVE_Q0_GENERATION_SHIFT) + +#define SELF_ID_RECEIVE_Q0_GET_TIMESTAMP(quadlet) \ + (((quadlet) & OHCI1394_SELF_ID_RECEIVE_Q0_TIMESTAMP_MASK) >> OHCI1394_SELF_ID_RECEIVE_Q0_TIMESTAMP_SHIFT) + +TRACE_EVENT(self_id_complete, + TP_PROTO(unsigned int card_index, u32 reg, const __le32 *self_id_receive, bool has_be_header_quirk), + TP_ARGS(card_index, reg, self_id_receive, has_be_header_quirk), + TP_STRUCT__entry( + __field(u8, card_index) + __field(u32, reg) + __dynamic_array(u32, self_id_receive, ohci1394_self_id_count_get_size(reg)) + ), + TP_fast_assign( + __entry->card_index = card_index; + __entry->reg = reg; + { + u32 *ptr = __get_dynamic_array(self_id_receive); + int i; + + for (i = 0; i < __get_dynamic_array_len(self_id_receive) / QUADLET_SIZE; ++i) + ptr[i] = cond_le32_to_cpu(self_id_receive[i], has_be_header_quirk); + } + ), + TP_printk( + "card_index=%u is_error=%s generation_at_bus_reset=%u generation_at_completion=%u timestamp=0x%04x packet_data=%s", + __entry->card_index, + SELF_ID_COUNT_IS_ERROR(__entry->reg) ? "true" : "false", + SELF_ID_COUNT_GET_GENERATION(__entry->reg), + SELF_ID_RECEIVE_Q0_GET_GENERATION(((const u32 *)__get_dynamic_array(self_id_receive))[0]), + SELF_ID_RECEIVE_Q0_GET_TIMESTAMP(((const u32 *)__get_dynamic_array(self_id_receive))[0]), + __print_array(((const u32 *)__get_dynamic_array(self_id_receive)) + 1, + (__get_dynamic_array_len(self_id_receive) / QUADLET_SIZE) - 1, QUADLET_SIZE) + ) +); + +#undef SELF_ID_COUNT_IS_ERROR +#undef SELF_ID_COUNT_GET_GENERATION +#undef SELF_ID_RECEIVE_Q0_GET_GENERATION +#undef SELF_ID_RECEIVE_Q0_GET_TIMESTAMP + +#undef QUADLET_SIZE + +#endif // _FIREWIRE_OHCI_TRACE_EVENT_H + +#include diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index d03842abae57..637efc055145 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -192,11 +192,24 @@ struct kvm_xen_exit { /* Flags that describe what fields in emulation_failure hold valid data. */ #define KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES (1ULL << 0) +/* + * struct kvm_run can be modified by userspace at any time, so KVM must be + * careful to avoid TOCTOU bugs. In order to protect KVM, HINT_UNSAFE_IN_KVM() + * renames fields in struct kvm_run from to __unsafe when + * compiled into the kernel, ensuring that any use within KVM is obvious and + * gets extra scrutiny. + */ +#ifdef __KERNEL__ +#define HINT_UNSAFE_IN_KVM(_symbol) _symbol##__unsafe +#else +#define HINT_UNSAFE_IN_KVM(_symbol) _symbol +#endif + /* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */ struct kvm_run { /* in */ __u8 request_interrupt_window; - __u8 immediate_exit; + __u8 HINT_UNSAFE_IN_KVM(immediate_exit); __u8 padding1[6]; /* out */ @@ -917,6 +930,9 @@ struct kvm_enable_cap { #define KVM_CAP_MEMORY_ATTRIBUTES 233 #define KVM_CAP_GUEST_MEMFD 234 #define KVM_CAP_VM_TYPES 235 +#define KVM_CAP_PRE_FAULT_MEMORY 236 +#define KVM_CAP_X86_APIC_BUS_CYCLES_NS 237 +#define KVM_CAP_X86_GUEST_MODE 238 struct kvm_irq_routing_irqchip { __u32 irqchip; @@ -1548,4 +1564,13 @@ struct kvm_create_guest_memfd { __u64 reserved[6]; }; +#define KVM_PRE_FAULT_MEMORY _IOWR(KVMIO, 0xd5, struct kvm_pre_fault_memory) + +struct kvm_pre_fault_memory { + __u64 gpa; + __u64 size; + __u64 flags; + __u64 padding[5]; +}; + #endif /* __LINUX_KVM_H */ diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h index 68625e728f43..2c8dbc74b955 100644 --- a/include/uapi/linux/landlock.h +++ b/include/uapi/linux/landlock.h @@ -12,29 +12,36 @@ #include /** - * struct landlock_ruleset_attr - Ruleset definition + * struct landlock_ruleset_attr - Ruleset definition. * - * Argument of sys_landlock_create_ruleset(). This structure can grow in - * future versions. + * Argument of sys_landlock_create_ruleset(). + * + * This structure defines a set of *handled access rights*, a set of actions on + * different object types, which should be denied by default when the ruleset is + * enacted. Vice versa, access rights that are not specifically listed here are + * not going to be denied by this ruleset when it is enacted. + * + * For historical reasons, the %LANDLOCK_ACCESS_FS_REFER right is always denied + * by default, even when its bit is not set in @handled_access_fs. In order to + * add new rules with this access right, the bit must still be set explicitly + * (cf. `Filesystem flags`_). + * + * The explicit listing of *handled access rights* is required for backwards + * compatibility reasons. In most use cases, processes that use Landlock will + * *handle* a wide range or all access rights that they know about at build time + * (and that they have tested with a kernel that supported them all). + * + * This structure can grow in future Landlock versions. */ struct landlock_ruleset_attr { /** - * @handled_access_fs: Bitmask of actions (cf. `Filesystem flags`_) - * that is handled by this ruleset and should then be forbidden if no - * rule explicitly allow them: it is a deny-by-default list that should - * contain as much Landlock access rights as possible. Indeed, all - * Landlock filesystem access rights that are not part of - * handled_access_fs are allowed. This is needed for backward - * compatibility reasons. One exception is the - * %LANDLOCK_ACCESS_FS_REFER access right, which is always implicitly - * handled, but must still be explicitly handled to add new rules with - * this access right. + * @handled_access_fs: Bitmask of handled filesystem actions + * (cf. `Filesystem flags`_). */ __u64 handled_access_fs; /** - * @handled_access_net: Bitmask of actions (cf. `Network flags`_) - * that is handled by this ruleset and should then be forbidden if no - * rule explicitly allow them. + * @handled_access_net: Bitmask of handled network actions (cf. `Network + * flags`_). */ __u64 handled_access_net; }; @@ -97,20 +104,21 @@ struct landlock_path_beneath_attr { */ struct landlock_net_port_attr { /** - * @allowed_access: Bitmask of allowed access network for a port + * @allowed_access: Bitmask of allowed network actions for a port * (cf. `Network flags`_). */ __u64 allowed_access; /** * @port: Network port in host endianness. * - * It should be noted that port 0 passed to :manpage:`bind(2)` will - * bind to an available port from a specific port range. This can be - * configured thanks to the ``/proc/sys/net/ipv4/ip_local_port_range`` - * sysctl (also used for IPv6). A Landlock rule with port 0 and the - * ``LANDLOCK_ACCESS_NET_BIND_TCP`` right means that requesting to bind - * on port 0 is allowed and it will automatically translate to binding - * on the related port range. + * It should be noted that port 0 passed to :manpage:`bind(2)` will bind + * to an available port from the ephemeral port range. This can be + * configured with the ``/proc/sys/net/ipv4/ip_local_port_range`` sysctl + * (also used for IPv6). + * + * A Landlock rule with port 0 and the ``LANDLOCK_ACCESS_NET_BIND_TCP`` + * right means that requesting to bind on port 0 is allowed and it will + * automatically translate to binding on the related port range. */ __u64 port; }; @@ -131,10 +139,10 @@ struct landlock_net_port_attr { * The following access rights apply only to files: * * - %LANDLOCK_ACCESS_FS_EXECUTE: Execute a file. - * - %LANDLOCK_ACCESS_FS_WRITE_FILE: Open a file with write access. Note that - * you might additionally need the %LANDLOCK_ACCESS_FS_TRUNCATE right in order - * to overwrite files with :manpage:`open(2)` using ``O_TRUNC`` or - * :manpage:`creat(2)`. + * - %LANDLOCK_ACCESS_FS_WRITE_FILE: Open a file with write access. When + * opening files for writing, you will often additionally need the + * %LANDLOCK_ACCESS_FS_TRUNCATE right. In many cases, these system calls + * truncate existing files when overwriting them (e.g., :manpage:`creat(2)`). * - %LANDLOCK_ACCESS_FS_READ_FILE: Open a file with read access. * - %LANDLOCK_ACCESS_FS_TRUNCATE: Truncate a file with :manpage:`truncate(2)`, * :manpage:`ftruncate(2)`, :manpage:`creat(2)`, or :manpage:`open(2)` with @@ -256,7 +264,7 @@ struct landlock_net_port_attr { * These flags enable to restrict a sandboxed process to a set of network * actions. This is supported since the Landlock ABI version 4. * - * TCP sockets with allowed actions: + * The following access rights apply to TCP port numbers: * * - %LANDLOCK_ACCESS_NET_BIND_TCP: Bind a TCP socket to a local port. * - %LANDLOCK_ACCESS_NET_CONNECT_TCP: Connect an active TCP socket to diff --git a/include/uapi/linux/psp-sev.h b/include/uapi/linux/psp-sev.h index b7a2c2ee35b7..2289b7c76c59 100644 --- a/include/uapi/linux/psp-sev.h +++ b/include/uapi/linux/psp-sev.h @@ -31,6 +31,7 @@ enum { SNP_PLATFORM_STATUS, SNP_COMMIT, SNP_SET_CONFIG, + SNP_VLEK_LOAD, SEV_MAX, }; @@ -214,6 +215,32 @@ struct sev_user_data_snp_config { __u8 rsvd1[52]; } __packed; +/** + * struct sev_data_snp_vlek_load - SNP_VLEK_LOAD structure + * + * @len: length of the command buffer read by the PSP + * @vlek_wrapped_version: version of wrapped VLEK hashstick (Must be 0h) + * @rsvd: reserved + * @vlek_wrapped_address: address of a wrapped VLEK hashstick + * (struct sev_user_data_snp_wrapped_vlek_hashstick) + */ +struct sev_user_data_snp_vlek_load { + __u32 len; /* In */ + __u8 vlek_wrapped_version; /* In */ + __u8 rsvd[3]; /* In */ + __u64 vlek_wrapped_address; /* In */ +} __packed; + +/** + * struct sev_user_data_snp_vlek_wrapped_vlek_hashstick - Wrapped VLEK data + * + * @data: Opaque data provided by AMD KDS (as described in SEV-SNP Firmware ABI + * 1.54, SNP_VLEK_LOAD) + */ +struct sev_user_data_snp_wrapped_vlek_hashstick { + __u8 data[432]; /* In */ +} __packed; + /** * struct sev_issue_cmd - SEV ioctl parameters * diff --git a/include/uapi/linux/sev-guest.h b/include/uapi/linux/sev-guest.h index 154a87a1eca9..fcdfea767fca 100644 --- a/include/uapi/linux/sev-guest.h +++ b/include/uapi/linux/sev-guest.h @@ -89,6 +89,9 @@ struct snp_ext_report_req { #define SNP_GUEST_FW_ERR_MASK GENMASK_ULL(31, 0) #define SNP_GUEST_VMM_ERR_SHIFT 32 #define SNP_GUEST_VMM_ERR(x) (((u64)x) << SNP_GUEST_VMM_ERR_SHIFT) +#define SNP_GUEST_FW_ERR(x) ((x) & SNP_GUEST_FW_ERR_MASK) +#define SNP_GUEST_ERR(vmm_err, fw_err) (SNP_GUEST_VMM_ERR(vmm_err) | \ + SNP_GUEST_FW_ERR(fw_err)) #define SNP_GUEST_VMM_ERR_INVALID_LEN 1 #define SNP_GUEST_VMM_ERR_BUSY 2 diff --git a/mm/compaction.c b/mm/compaction.c index 739b1bf3d637..6cb901b63482 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -1179,22 +1179,22 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn, if (((mode & ISOLATE_ASYNC_MIGRATE) && is_dirty) || (mapping && is_unevictable)) { bool migrate_dirty = true; - bool is_unmovable; + bool is_inaccessible; /* * Only folios without mappings or that have * a ->migrate_folio callback are possible to migrate * without blocking. * - * Folios from unmovable mappings are not migratable. + * Folios from inaccessible mappings are not migratable. * * However, we can be racing with truncation, which can * free the mapping that we need to check. Truncation * holds the folio lock until after the folio is removed * from the page so holding it ourselves is sufficient. * - * To avoid locking the folio just to check unmovable, - * assume every unmovable folio is also unevictable, + * To avoid locking the folio just to check inaccessible, + * assume every inaccessible folio is also unevictable, * which is a cheaper test. If our assumption goes * wrong, it's not a correctness bug, just potentially * wasted cycles. @@ -1207,9 +1207,9 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn, migrate_dirty = !mapping || mapping->a_ops->migrate_folio; } - is_unmovable = mapping && mapping_unmovable(mapping); + is_inaccessible = mapping && mapping_inaccessible(mapping); folio_unlock(folio); - if (!migrate_dirty || is_unmovable) + if (!migrate_dirty || is_inaccessible) goto isolate_fail_put; } diff --git a/mm/migrate.c b/mm/migrate.c index a8c6f466e33a..ed3aac90cf4f 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -978,7 +978,7 @@ static int move_to_new_folio(struct folio *dst, struct folio *src, if (!mapping) rc = migrate_folio(mapping, dst, src, mode); - else if (mapping_unmovable(mapping)) + else if (mapping_inaccessible(mapping)) rc = -EOPNOTSUPP; else if (mapping->a_ops->migrate_folio) /* diff --git a/mm/truncate.c b/mm/truncate.c index e99085bf3d34..581977d2356f 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -233,7 +233,8 @@ bool truncate_inode_partial_folio(struct folio *folio, loff_t start, loff_t end) * doing a complex calculation here, and then doing the zeroing * anyway if the page split fails. */ - folio_zero_range(folio, offset, length); + if (!mapping_inaccessible(folio->mapping)) + folio_zero_range(folio, offset, length); if (folio_has_private(folio)) folio_invalidate(folio, offset, length); diff --git a/scripts/head-object-list.txt b/scripts/head-object-list.txt index 890f69005bab..fd5d00bac447 100644 --- a/scripts/head-object-list.txt +++ b/scripts/head-object-list.txt @@ -27,7 +27,6 @@ arch/mips/kernel/head.o arch/nios2/kernel/head.o arch/openrisc/kernel/head.o arch/parisc/kernel/head.o -arch/powerpc/kernel/head_40x.o arch/powerpc/kernel/head_44x.o arch/powerpc/kernel/head_64.o arch/powerpc/kernel/head_8xx.o diff --git a/security/landlock/limits.h b/security/landlock/limits.h index 20fdb5ff3514..4eb643077a2a 100644 --- a/security/landlock/limits.h +++ b/security/landlock/limits.h @@ -21,12 +21,10 @@ #define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_IOCTL_DEV #define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1) #define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS) -#define LANDLOCK_SHIFT_ACCESS_FS 0 #define LANDLOCK_LAST_ACCESS_NET LANDLOCK_ACCESS_NET_CONNECT_TCP #define LANDLOCK_MASK_ACCESS_NET ((LANDLOCK_LAST_ACCESS_NET << 1) - 1) #define LANDLOCK_NUM_ACCESS_NET __const_hweight64(LANDLOCK_MASK_ACCESS_NET) -#define LANDLOCK_SHIFT_ACCESS_NET LANDLOCK_NUM_ACCESS_FS /* clang-format on */ diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c index e0a5fbf9201a..6ff232f58618 100644 --- a/security/landlock/ruleset.c +++ b/security/landlock/ruleset.c @@ -169,13 +169,9 @@ static void build_check_ruleset(void) .num_rules = ~0, .num_layers = ~0, }; - typeof(ruleset.access_masks[0]) access_masks = ~0; BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES); BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS); - BUILD_BUG_ON(access_masks < - ((LANDLOCK_MASK_ACCESS_FS << LANDLOCK_SHIFT_ACCESS_FS) | - (LANDLOCK_MASK_ACCESS_NET << LANDLOCK_SHIFT_ACCESS_NET))); } /** diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h index c7f1526784fd..0f1b5b4c8f6b 100644 --- a/security/landlock/ruleset.h +++ b/security/landlock/ruleset.h @@ -39,10 +39,10 @@ static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_NET); static_assert(sizeof(unsigned long) >= sizeof(access_mask_t)); /* Ruleset access masks. */ -typedef u32 access_masks_t; -/* Makes sure all ruleset access rights can be stored. */ -static_assert(BITS_PER_TYPE(access_masks_t) >= - LANDLOCK_NUM_ACCESS_FS + LANDLOCK_NUM_ACCESS_NET); +struct access_masks { + access_mask_t fs : LANDLOCK_NUM_ACCESS_FS; + access_mask_t net : LANDLOCK_NUM_ACCESS_NET; +}; typedef u16 layer_mask_t; /* Makes sure all layers can be checked. */ @@ -226,7 +226,7 @@ struct landlock_ruleset { * layers are set once and never changed for the * lifetime of the ruleset. */ - access_masks_t access_masks[]; + struct access_masks access_masks[]; }; }; }; @@ -265,8 +265,7 @@ landlock_add_fs_access_mask(struct landlock_ruleset *const ruleset, /* Should already be checked in sys_landlock_create_ruleset(). */ WARN_ON_ONCE(fs_access_mask != fs_mask); - ruleset->access_masks[layer_level] |= - (fs_mask << LANDLOCK_SHIFT_ACCESS_FS); + ruleset->access_masks[layer_level].fs |= fs_mask; } static inline void @@ -278,17 +277,14 @@ landlock_add_net_access_mask(struct landlock_ruleset *const ruleset, /* Should already be checked in sys_landlock_create_ruleset(). */ WARN_ON_ONCE(net_access_mask != net_mask); - ruleset->access_masks[layer_level] |= - (net_mask << LANDLOCK_SHIFT_ACCESS_NET); + ruleset->access_masks[layer_level].net |= net_mask; } static inline access_mask_t landlock_get_raw_fs_access_mask(const struct landlock_ruleset *const ruleset, const u16 layer_level) { - return (ruleset->access_masks[layer_level] >> - LANDLOCK_SHIFT_ACCESS_FS) & - LANDLOCK_MASK_ACCESS_FS; + return ruleset->access_masks[layer_level].fs; } static inline access_mask_t @@ -304,9 +300,7 @@ static inline access_mask_t landlock_get_net_access_mask(const struct landlock_ruleset *const ruleset, const u16 layer_level) { - return (ruleset->access_masks[layer_level] >> - LANDLOCK_SHIFT_ACCESS_NET) & - LANDLOCK_MASK_ACCESS_NET; + return ruleset->access_masks[layer_level].net; } bool landlock_unmask_layers(const struct landlock_rule *const rule, diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c index 03b470f5a85a..ccc8bc6c1584 100644 --- a/security/landlock/syscalls.c +++ b/security/landlock/syscalls.c @@ -378,8 +378,7 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset, * with the new rule. * @rule_type: Identify the structure type pointed to by @rule_attr: * %LANDLOCK_RULE_PATH_BENEATH or %LANDLOCK_RULE_NET_PORT. - * @rule_attr: Pointer to a rule (only of type &struct - * landlock_path_beneath_attr for now). + * @rule_attr: Pointer to a rule (matching the @rule_type). * @flags: Must be 0. * * This system call enables to define a new rule and add it to an existing @@ -390,18 +389,20 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset, * - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time; * - %EAFNOSUPPORT: @rule_type is %LANDLOCK_RULE_NET_PORT but TCP/IP is not * supported by the running kernel; - * - %EINVAL: @flags is not 0, or inconsistent access in the rule (i.e. + * - %EINVAL: @flags is not 0; + * - %EINVAL: The rule accesses are inconsistent (i.e. * &landlock_path_beneath_attr.allowed_access or - * &landlock_net_port_attr.allowed_access is not a subset of the - * ruleset handled accesses), or &landlock_net_port_attr.port is - * greater than 65535; - * - %ENOMSG: Empty accesses (e.g. &landlock_path_beneath_attr.allowed_access); + * &landlock_net_port_attr.allowed_access is not a subset of the ruleset + * handled accesses) + * - %EINVAL: &landlock_net_port_attr.port is greater than 65535; + * - %ENOMSG: Empty accesses (e.g. &landlock_path_beneath_attr.allowed_access is + * 0); * - %EBADF: @ruleset_fd is not a file descriptor for the current thread, or a * member of @rule_attr is not a file descriptor as expected; * - %EBADFD: @ruleset_fd is not a ruleset file descriptor, or a member of * @rule_attr is not the expected file descriptor type; * - %EPERM: @ruleset_fd has no write access to the underlying ruleset; - * - %EFAULT: @rule_attr inconsistency. + * - %EFAULT: @rule_attr was not a valid address. */ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd, const enum landlock_rule_type, rule_type, diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index d03842abae57..e5af8c692dc0 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -917,6 +917,7 @@ struct kvm_enable_cap { #define KVM_CAP_MEMORY_ATTRIBUTES 233 #define KVM_CAP_GUEST_MEMFD 234 #define KVM_CAP_VM_TYPES 235 +#define KVM_CAP_PRE_FAULT_MEMORY 236 struct kvm_irq_routing_irqchip { __u32 irqchip; @@ -1548,4 +1549,13 @@ struct kvm_create_guest_memfd { __u64 reserved[6]; }; +#define KVM_PRE_FAULT_MEMORY _IOWR(KVMIO, 0xd5, struct kvm_pre_fault_memory) + +struct kvm_pre_fault_memory { + __u64 gpa; + __u64 size; + __u64 flags; + __u64 padding[5]; +}; + #endif /* __LINUX_KVM_H */ diff --git a/tools/perf/arch/loongarch/Makefile b/tools/perf/arch/loongarch/Makefile index 3992a67a87d9..c89d6bb6b184 100644 --- a/tools/perf/arch/loongarch/Makefile +++ b/tools/perf/arch/loongarch/Makefile @@ -4,6 +4,7 @@ PERF_HAVE_DWARF_REGS := 1 endif PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 PERF_HAVE_JITDUMP := 1 +HAVE_KVM_STAT_SUPPORT := 1 # # Syscall table generation for perf diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongarch/util/Build index 2386ebbf6dd4..b6b97de48233 100644 --- a/tools/perf/arch/loongarch/util/Build +++ b/tools/perf/arch/loongarch/util/Build @@ -1,5 +1,7 @@ +perf-util-y += header.o perf-util-y += perf_regs.o perf-util-$(CONFIG_DWARF) += dwarf-regs.o perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o +perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o diff --git a/tools/perf/arch/loongarch/util/header.c b/tools/perf/arch/loongarch/util/header.c new file mode 100644 index 000000000000..d962dff55512 --- /dev/null +++ b/tools/perf/arch/loongarch/util/header.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implementation of get_cpuid(). + * + * Author: Nikita Shubin + * Bibo Mao + * Huacai Chen + */ + +#include +#include +#include +#include +#include "util/debug.h" +#include "util/header.h" + +/* + * Output example from /proc/cpuinfo + * CPU Family : Loongson-64bit + * Model Name : Loongson-3C5000 + * CPU Revision : 0x10 + * FPU Revision : 0x01 + */ +#define CPUINFO_MODEL "Model Name" +#define CPUINFO "/proc/cpuinfo" + +static char *_get_field(const char *line) +{ + char *line2, *nl; + + line2 = strrchr(line, ' '); + if (!line2) + return NULL; + + line2++; + nl = strrchr(line, '\n'); + if (!nl) + return NULL; + + return strndup(line2, nl - line2); +} + +static char *_get_cpuid(void) +{ + unsigned long line_sz; + char *line, *model, *cpuid; + FILE *file; + + file = fopen(CPUINFO, "r"); + if (file == NULL) + return NULL; + + line = model = cpuid = NULL; + while (getline(&line, &line_sz, file) != -1) { + if (strncmp(line, CPUINFO_MODEL, strlen(CPUINFO_MODEL))) + continue; + + model = _get_field(line); + if (!model) + goto out_free; + break; + } + + if (model && (asprintf(&cpuid, "%s", model) < 0)) + cpuid = NULL; + +out_free: + fclose(file); + free(model); + return cpuid; +} + +int get_cpuid(char *buffer, size_t sz) +{ + int ret = 0; + char *cpuid = _get_cpuid(); + + if (!cpuid) + return EINVAL; + + if (sz < strlen(cpuid)) { + ret = ENOBUFS; + goto out_free; + } + + scnprintf(buffer, sz, "%s", cpuid); + +out_free: + free(cpuid); + return ret; +} + +char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused) +{ + return _get_cpuid(); +} diff --git a/tools/perf/arch/loongarch/util/kvm-stat.c b/tools/perf/arch/loongarch/util/kvm-stat.c new file mode 100644 index 000000000000..a7859a3a9a51 --- /dev/null +++ b/tools/perf/arch/loongarch/util/kvm-stat.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include "util/kvm-stat.h" +#include "util/parse-events.h" +#include "util/debug.h" +#include "util/evsel.h" +#include "util/evlist.h" +#include "util/pmus.h" + +#define LOONGARCH_EXCEPTION_INT 0 +#define LOONGARCH_EXCEPTION_PIL 1 +#define LOONGARCH_EXCEPTION_PIS 2 +#define LOONGARCH_EXCEPTION_PIF 3 +#define LOONGARCH_EXCEPTION_PME 4 +#define LOONGARCH_EXCEPTION_FPD 15 +#define LOONGARCH_EXCEPTION_SXD 16 +#define LOONGARCH_EXCEPTION_ASXD 17 +#define LOONGARCH_EXCEPTION_GSPR 22 +#define LOONGARCH_EXCEPTION_CPUCFG 100 +#define LOONGARCH_EXCEPTION_CSR 101 +#define LOONGARCH_EXCEPTION_IOCSR 102 +#define LOONGARCH_EXCEPTION_IDLE 103 +#define LOONGARCH_EXCEPTION_OTHERS 104 +#define LOONGARCH_EXCEPTION_HVC 23 + +#define loongarch_exception_type \ + {LOONGARCH_EXCEPTION_INT, "Interrupt" }, \ + {LOONGARCH_EXCEPTION_PIL, "Mem Read" }, \ + {LOONGARCH_EXCEPTION_PIS, "Mem Store" }, \ + {LOONGARCH_EXCEPTION_PIF, "Inst Fetch" }, \ + {LOONGARCH_EXCEPTION_PME, "Mem Modify" }, \ + {LOONGARCH_EXCEPTION_FPD, "FPU" }, \ + {LOONGARCH_EXCEPTION_SXD, "LSX" }, \ + {LOONGARCH_EXCEPTION_ASXD, "LASX" }, \ + {LOONGARCH_EXCEPTION_GSPR, "Privilege Error" }, \ + {LOONGARCH_EXCEPTION_HVC, "Hypercall" }, \ + {LOONGARCH_EXCEPTION_CPUCFG, "CPUCFG" }, \ + {LOONGARCH_EXCEPTION_CSR, "CSR" }, \ + {LOONGARCH_EXCEPTION_IOCSR, "IOCSR" }, \ + {LOONGARCH_EXCEPTION_IDLE, "Idle" }, \ + {LOONGARCH_EXCEPTION_OTHERS, "Others" } + +define_exit_reasons_table(loongarch_exit_reasons, loongarch_exception_type); + +const char *vcpu_id_str = "vcpu_id"; +const char *kvm_exit_reason = "reason"; +const char *kvm_entry_trace = "kvm:kvm_enter"; +const char *kvm_reenter_trace = "kvm:kvm_reenter"; +const char *kvm_exit_trace = "kvm:kvm_exit"; +const char *kvm_events_tp[] = { + "kvm:kvm_enter", + "kvm:kvm_reenter", + "kvm:kvm_exit", + "kvm:kvm_exit_gspr", + NULL, +}; + +static bool event_begin(struct evsel *evsel, + struct perf_sample *sample, struct event_key *key) +{ + return exit_event_begin(evsel, sample, key); +} + +static bool event_end(struct evsel *evsel, + struct perf_sample *sample __maybe_unused, + struct event_key *key __maybe_unused) +{ + /* + * LoongArch kvm is different with other architectures + * + * There is kvm:kvm_reenter or kvm:kvm_enter event adjacent with + * kvm:kvm_exit event. + * kvm:kvm_enter means returning to vmm and then to guest + * kvm:kvm_reenter means returning to guest immediately + */ + return evsel__name_is(evsel, kvm_entry_trace) || evsel__name_is(evsel, kvm_reenter_trace); +} + +static void event_gspr_get_key(struct evsel *evsel, + struct perf_sample *sample, struct event_key *key) +{ + unsigned int insn; + + key->key = LOONGARCH_EXCEPTION_OTHERS; + insn = evsel__intval(evsel, sample, "inst_word"); + + switch (insn >> 24) { + case 0: + /* CPUCFG inst trap */ + if ((insn >> 10) == 0x1b) + key->key = LOONGARCH_EXCEPTION_CPUCFG; + break; + case 4: + /* CSR inst trap */ + key->key = LOONGARCH_EXCEPTION_CSR; + break; + case 6: + /* IOCSR inst trap */ + if ((insn >> 15) == 0xc90) + key->key = LOONGARCH_EXCEPTION_IOCSR; + else if ((insn >> 15) == 0xc91) + /* Idle inst trap */ + key->key = LOONGARCH_EXCEPTION_IDLE; + break; + default: + key->key = LOONGARCH_EXCEPTION_OTHERS; + break; + } +} + +static struct child_event_ops child_events[] = { + { .name = "kvm:kvm_exit_gspr", .get_key = event_gspr_get_key }, + { NULL, NULL }, +}; + +static struct kvm_events_ops exit_events = { + .is_begin_event = event_begin, + .is_end_event = event_end, + .child_ops = child_events, + .decode_key = exit_event_decode_key, + .name = "VM-EXIT" +}; + +struct kvm_reg_events_ops kvm_reg_events_ops[] = { + { .name = "vmexit", .ops = &exit_events, }, + { NULL, NULL }, +}; + +const char * const kvm_skip_events[] = { + NULL, +}; + +int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused) +{ + kvm->exit_reasons_isa = "loongarch64"; + kvm->exit_reasons = loongarch_exit_reasons; + return 0; +} diff --git a/tools/perf/arch/riscv/Makefile b/tools/perf/arch/riscv/Makefile index a8d25d005207..90c3c476a242 100644 --- a/tools/perf/arch/riscv/Makefile +++ b/tools/perf/arch/riscv/Makefile @@ -3,3 +3,4 @@ PERF_HAVE_DWARF_REGS := 1 endif PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 PERF_HAVE_JITDUMP := 1 +HAVE_KVM_STAT_SUPPORT := 1 diff --git a/tools/perf/arch/riscv/util/Build b/tools/perf/arch/riscv/util/Build index 65ec3c66a375..f865cb0489ec 100644 --- a/tools/perf/arch/riscv/util/Build +++ b/tools/perf/arch/riscv/util/Build @@ -1,5 +1,6 @@ perf-util-y += perf_regs.o perf-util-y += header.o +perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o perf-util-$(CONFIG_DWARF) += dwarf-regs.o perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o diff --git a/tools/perf/arch/riscv/util/kvm-stat.c b/tools/perf/arch/riscv/util/kvm-stat.c new file mode 100644 index 000000000000..491aef449d1a --- /dev/null +++ b/tools/perf/arch/riscv/util/kvm-stat.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Arch specific functions for perf kvm stat. + * + * Copyright 2024 Beijing ESWIN Computing Technology Co., Ltd. + * + */ +#include +#include +#include "../../../util/evsel.h" +#include "../../../util/kvm-stat.h" +#include "riscv_exception_types.h" +#include "debug.h" + +define_exit_reasons_table(riscv_exit_reasons, kvm_riscv_exception_class); + +const char *vcpu_id_str = "id"; +const char *kvm_exit_reason = "scause"; +const char *kvm_entry_trace = "kvm:kvm_entry"; +const char *kvm_exit_trace = "kvm:kvm_exit"; + +const char *kvm_events_tp[] = { + "kvm:kvm_entry", + "kvm:kvm_exit", + NULL, +}; + +static void event_get_key(struct evsel *evsel, + struct perf_sample *sample, + struct event_key *key) +{ + key->info = 0; + key->key = evsel__intval(evsel, sample, kvm_exit_reason); + key->exit_reasons = riscv_exit_reasons; +} + +static bool event_begin(struct evsel *evsel, + struct perf_sample *sample __maybe_unused, + struct event_key *key __maybe_unused) +{ + return evsel__name_is(evsel, kvm_entry_trace); +} + +static bool event_end(struct evsel *evsel, + struct perf_sample *sample, + struct event_key *key) +{ + if (evsel__name_is(evsel, kvm_exit_trace)) { + event_get_key(evsel, sample, key); + return true; + } + return false; +} + +static struct kvm_events_ops exit_events = { + .is_begin_event = event_begin, + .is_end_event = event_end, + .decode_key = exit_event_decode_key, + .name = "VM-EXIT" +}; + +struct kvm_reg_events_ops kvm_reg_events_ops[] = { + { + .name = "vmexit", + .ops = &exit_events, + }, + { NULL, NULL }, +}; + +const char * const kvm_skip_events[] = { + NULL, +}; + +int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused) +{ + kvm->exit_reasons_isa = "riscv64"; + return 0; +} diff --git a/tools/perf/arch/riscv/util/riscv_exception_types.h b/tools/perf/arch/riscv/util/riscv_exception_types.h new file mode 100644 index 000000000000..c49b8fa5e847 --- /dev/null +++ b/tools/perf/arch/riscv/util/riscv_exception_types.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef ARCH_PERF_RISCV_EXCEPTION_TYPES_H +#define ARCH_PERF_RISCV_EXCEPTION_TYPES_H + +#define EXC_INST_MISALIGNED 0 +#define EXC_INST_ACCESS 1 +#define EXC_INST_ILLEGAL 2 +#define EXC_BREAKPOINT 3 +#define EXC_LOAD_MISALIGNED 4 +#define EXC_LOAD_ACCESS 5 +#define EXC_STORE_MISALIGNED 6 +#define EXC_STORE_ACCESS 7 +#define EXC_SYSCALL 8 +#define EXC_HYPERVISOR_SYSCALL 9 +#define EXC_SUPERVISOR_SYSCALL 10 +#define EXC_INST_PAGE_FAULT 12 +#define EXC_LOAD_PAGE_FAULT 13 +#define EXC_STORE_PAGE_FAULT 15 +#define EXC_INST_GUEST_PAGE_FAULT 20 +#define EXC_LOAD_GUEST_PAGE_FAULT 21 +#define EXC_VIRTUAL_INST_FAULT 22 +#define EXC_STORE_GUEST_PAGE_FAULT 23 + +#define EXC(x) {EXC_##x, #x } + +#define kvm_riscv_exception_class \ + EXC(INST_MISALIGNED), EXC(INST_ACCESS), EXC(INST_ILLEGAL), \ + EXC(BREAKPOINT), EXC(LOAD_MISALIGNED), EXC(LOAD_ACCESS), \ + EXC(STORE_MISALIGNED), EXC(STORE_ACCESS), EXC(SYSCALL), \ + EXC(HYPERVISOR_SYSCALL), EXC(SUPERVISOR_SYSCALL), \ + EXC(INST_PAGE_FAULT), EXC(LOAD_PAGE_FAULT), EXC(STORE_PAGE_FAULT), \ + EXC(INST_GUEST_PAGE_FAULT), EXC(LOAD_GUEST_PAGE_FAULT), \ + EXC(VIRTUAL_INST_FAULT), EXC(STORE_GUEST_PAGE_FAULT) + +#endif /* ARCH_PERF_RISCV_EXCEPTION_TYPES_H */ diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c index ea956082e6a4..e4313726fae3 100644 --- a/tools/testing/nvdimm/test/iomap.c +++ b/tools/testing/nvdimm/test/iomap.c @@ -407,4 +407,5 @@ union acpi_object * __wrap_acpi_evaluate_dsm(acpi_handle handle, const guid_t *g } EXPORT_SYMBOL(__wrap_acpi_evaluate_dsm); +MODULE_DESCRIPTION("NVDIMM unit test"); MODULE_LICENSE("GPL v2"); diff --git a/tools/testing/nvdimm/test/ndtest.c b/tools/testing/nvdimm/test/ndtest.c index b438f3d053ee..892e990c034a 100644 --- a/tools/testing/nvdimm/test/ndtest.c +++ b/tools/testing/nvdimm/test/ndtest.c @@ -987,5 +987,6 @@ static __exit void ndtest_exit(void) module_init(ndtest_init); module_exit(ndtest_exit); +MODULE_DESCRIPTION("Test non-NFIT devices"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("IBM Corporation"); diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index a61df347a33d..cfd4378e2129 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -3382,5 +3382,6 @@ static __exit void nfit_test_exit(void) module_init(nfit_test_init); module_exit(nfit_test_exit); +MODULE_DESCRIPTION("Test ACPI NFIT devices"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Intel Corporation"); diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index ac280dcba996..b084ba2262a0 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -112,6 +112,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/vmx_invalid_nested_guest_state TEST_GEN_PROGS_x86_64 += x86_64/vmx_set_nested_state_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_nested_tsc_scaling_test +TEST_GEN_PROGS_x86_64 += x86_64/apic_bus_clock_test TEST_GEN_PROGS_x86_64 += x86_64/xapic_ipi_test TEST_GEN_PROGS_x86_64 += x86_64/xapic_state_test TEST_GEN_PROGS_x86_64 += x86_64/xcr0_cpuid_test @@ -145,6 +146,7 @@ TEST_GEN_PROGS_x86_64 += set_memory_region_test TEST_GEN_PROGS_x86_64 += steal_time TEST_GEN_PROGS_x86_64 += kvm_binary_stats_test TEST_GEN_PROGS_x86_64 += system_counter_offset_test +TEST_GEN_PROGS_x86_64 += pre_fault_memory_test # Compiled outputs used by test targets TEST_GEN_PROGS_EXTENDED_x86_64 += x86_64/nx_huge_pages_test diff --git a/tools/testing/selftests/kvm/aarch64/set_id_regs.c b/tools/testing/selftests/kvm/aarch64/set_id_regs.c index a7de39fa2a0a..d20981663831 100644 --- a/tools/testing/selftests/kvm/aarch64/set_id_regs.c +++ b/tools/testing/selftests/kvm/aarch64/set_id_regs.c @@ -219,6 +219,7 @@ static void guest_code(void) GUEST_REG_SYNC(SYS_ID_AA64MMFR1_EL1); GUEST_REG_SYNC(SYS_ID_AA64MMFR2_EL1); GUEST_REG_SYNC(SYS_ID_AA64ZFR0_EL1); + GUEST_REG_SYNC(SYS_CTR_EL0); GUEST_DONE(); } @@ -490,11 +491,25 @@ static void test_clidr(struct kvm_vcpu *vcpu) test_reg_vals[encoding_to_range_idx(SYS_CLIDR_EL1)] = clidr; } +static void test_ctr(struct kvm_vcpu *vcpu) +{ + u64 ctr; + + vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_CTR_EL0), &ctr); + ctr &= ~CTR_EL0_DIC_MASK; + if (ctr & CTR_EL0_IminLine_MASK) + ctr--; + + vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_CTR_EL0), ctr); + test_reg_vals[encoding_to_range_idx(SYS_CTR_EL0)] = ctr; +} + static void test_vcpu_ftr_id_regs(struct kvm_vcpu *vcpu) { u64 val; test_clidr(vcpu); + test_ctr(vcpu); vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MPIDR_EL1), &val); val++; @@ -524,7 +539,9 @@ static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu) for (int i = 0; i < ARRAY_SIZE(test_regs); i++) test_assert_id_reg_unchanged(vcpu, test_regs[i].reg); + test_assert_id_reg_unchanged(vcpu, SYS_MPIDR_EL1); test_assert_id_reg_unchanged(vcpu, SYS_CLIDR_EL1); + test_assert_id_reg_unchanged(vcpu, SYS_CTR_EL0); ksft_test_result_pass("%s\n", __func__); } diff --git a/tools/testing/selftests/kvm/include/x86_64/apic.h b/tools/testing/selftests/kvm/include/x86_64/apic.h index bed316fdecd5..0f268b55fa06 100644 --- a/tools/testing/selftests/kvm/include/x86_64/apic.h +++ b/tools/testing/selftests/kvm/include/x86_64/apic.h @@ -60,6 +60,14 @@ #define APIC_VECTOR_MASK 0x000FF #define APIC_ICR2 0x310 #define SET_APIC_DEST_FIELD(x) ((x) << 24) +#define APIC_LVTT 0x320 +#define APIC_LVT_TIMER_ONESHOT (0 << 17) +#define APIC_LVT_TIMER_PERIODIC (1 << 17) +#define APIC_LVT_TIMER_TSCDEADLINE (2 << 17) +#define APIC_LVT_MASKED (1 << 16) +#define APIC_TMICT 0x380 +#define APIC_TMCCT 0x390 +#define APIC_TDCR 0x3E0 void apic_disable(void); void xapic_enable(void); diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index c0c7c1fe93f9..a0c1440017bb 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -23,6 +23,7 @@ extern bool host_cpu_is_intel; extern bool host_cpu_is_amd; +extern uint64_t guest_tsc_khz; /* Forced emulation prefix, used to invoke the emulator unconditionally. */ #define KVM_FEP "ud2; .byte 'k', 'v', 'm';" @@ -816,6 +817,23 @@ static inline void cpu_relax(void) asm volatile("rep; nop" ::: "memory"); } +static inline void udelay(unsigned long usec) +{ + uint64_t start, now, cycles; + + GUEST_ASSERT(guest_tsc_khz); + cycles = guest_tsc_khz / 1000 * usec; + + /* + * Deliberately don't PAUSE, a.k.a. cpu_relax(), so that the delay is + * as accurate as possible, e.g. doesn't trigger PAUSE-Loop VM-Exits. + */ + start = rdtsc(); + do { + now = rdtsc(); + } while (now - start < cycles); +} + #define ud2() \ __asm__ __volatile__( \ "ud2\n" \ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index ad00e4761886..56b170b725b3 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -21,6 +21,7 @@ uint32_t guest_random_seed; struct guest_random_state guest_rng; +static uint32_t last_guest_seed; static int vcpu_mmap_sz(void); @@ -434,7 +435,10 @@ struct kvm_vm *__vm_create(struct vm_shape shape, uint32_t nr_runnable_vcpus, slot0 = memslot2region(vm, 0); ucall_init(vm, slot0->region.guest_phys_addr + slot0->region.memory_size); - pr_info("Random seed: 0x%x\n", guest_random_seed); + if (guest_random_seed != last_guest_seed) { + pr_info("Random seed: 0x%x\n", guest_random_seed); + last_guest_seed = guest_random_seed; + } guest_rng = new_guest_random_state(guest_random_seed); sync_global_to_guest(vm, guest_rng); @@ -2319,7 +2323,8 @@ void __attribute((constructor)) kvm_selftest_init(void) /* Tell stdout not to buffer its content. */ setbuf(stdout, NULL); - guest_random_seed = random(); + guest_random_seed = last_guest_seed = random(); + pr_info("Random seed: 0x%x\n", guest_random_seed); kvm_selftest_arch_init(); } diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 594b061aef52..153739f2e201 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -25,6 +25,7 @@ vm_vaddr_t exception_handlers; bool host_cpu_is_amd; bool host_cpu_is_intel; bool is_forced_emulation_enabled; +uint64_t guest_tsc_khz; static void regs_dump(FILE *stream, struct kvm_regs *regs, uint8_t indent) { @@ -616,6 +617,11 @@ void assert_on_unhandled_exception(struct kvm_vcpu *vcpu) void kvm_arch_vm_post_create(struct kvm_vm *vm) { + int r; + + TEST_ASSERT(kvm_has_cap(KVM_CAP_GET_TSC_KHZ), + "Require KVM_GET_TSC_KHZ to provide udelay() to guest."); + vm_create_irqchip(vm); vm_init_descriptor_tables(vm); @@ -628,6 +634,11 @@ void kvm_arch_vm_post_create(struct kvm_vm *vm) vm_sev_ioctl(vm, KVM_SEV_INIT2, &init); } + + r = __vm_ioctl(vm, KVM_GET_TSC_KHZ, NULL); + TEST_ASSERT(r > 0, "KVM_GET_TSC_KHZ did not provide a valid TSC frequency."); + guest_tsc_khz = r; + sync_global_to_guest(vm, guest_tsc_khz); } void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code) diff --git a/tools/testing/selftests/kvm/memslot_modification_stress_test.c b/tools/testing/selftests/kvm/memslot_modification_stress_test.c index 05fcf902e067..49f162573126 100644 --- a/tools/testing/selftests/kvm/memslot_modification_stress_test.c +++ b/tools/testing/selftests/kvm/memslot_modification_stress_test.c @@ -53,12 +53,6 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args) } } -struct memslot_antagonist_args { - struct kvm_vm *vm; - useconds_t delay; - uint64_t nr_modifications; -}; - static void add_remove_memslot(struct kvm_vm *vm, useconds_t delay, uint64_t nr_modifications) { diff --git a/tools/testing/selftests/kvm/pre_fault_memory_test.c b/tools/testing/selftests/kvm/pre_fault_memory_test.c new file mode 100644 index 000000000000..0350a8896a2f --- /dev/null +++ b/tools/testing/selftests/kvm/pre_fault_memory_test.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024, Intel, Inc + * + * Author: + * Isaku Yamahata + */ +#include + +#include +#include +#include + +/* Arbitrarily chosen values */ +#define TEST_SIZE (SZ_2M + PAGE_SIZE) +#define TEST_NPAGES (TEST_SIZE / PAGE_SIZE) +#define TEST_SLOT 10 + +static void guest_code(uint64_t base_gpa) +{ + volatile uint64_t val __used; + int i; + + for (i = 0; i < TEST_NPAGES; i++) { + uint64_t *src = (uint64_t *)(base_gpa + i * PAGE_SIZE); + + val = *src; + } + + GUEST_DONE(); +} + +static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 gpa, u64 size, + u64 left) +{ + struct kvm_pre_fault_memory range = { + .gpa = gpa, + .size = size, + .flags = 0, + }; + u64 prev; + int ret, save_errno; + + do { + prev = range.size; + ret = __vcpu_ioctl(vcpu, KVM_PRE_FAULT_MEMORY, &range); + save_errno = errno; + TEST_ASSERT((range.size < prev) ^ (ret < 0), + "%sexpecting range.size to change on %s", + ret < 0 ? "not " : "", + ret < 0 ? "failure" : "success"); + } while (ret >= 0 ? range.size : save_errno == EINTR); + + TEST_ASSERT(range.size == left, + "Completed with %lld bytes left, expected %" PRId64, + range.size, left); + + if (left == 0) + __TEST_ASSERT_VM_VCPU_IOCTL(!ret, "KVM_PRE_FAULT_MEMORY", ret, vcpu->vm); + else + /* No memory slot causes RET_PF_EMULATE. it results in -ENOENT. */ + __TEST_ASSERT_VM_VCPU_IOCTL(ret && save_errno == ENOENT, + "KVM_PRE_FAULT_MEMORY", ret, vcpu->vm); +} + +static void __test_pre_fault_memory(unsigned long vm_type, bool private) +{ + const struct vm_shape shape = { + .mode = VM_MODE_DEFAULT, + .type = vm_type, + }; + struct kvm_vcpu *vcpu; + struct kvm_run *run; + struct kvm_vm *vm; + struct ucall uc; + + uint64_t guest_test_phys_mem; + uint64_t guest_test_virt_mem; + uint64_t alignment, guest_page_size; + + vm = vm_create_shape_with_one_vcpu(shape, &vcpu, guest_code); + + alignment = guest_page_size = vm_guest_mode_params[VM_MODE_DEFAULT].page_size; + guest_test_phys_mem = (vm->max_gfn - TEST_NPAGES) * guest_page_size; +#ifdef __s390x__ + alignment = max(0x100000UL, guest_page_size); +#else + alignment = SZ_2M; +#endif + guest_test_phys_mem = align_down(guest_test_phys_mem, alignment); + guest_test_virt_mem = guest_test_phys_mem & ((1ULL << (vm->va_bits - 1)) - 1); + + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, + guest_test_phys_mem, TEST_SLOT, TEST_NPAGES, + private ? KVM_MEM_GUEST_MEMFD : 0); + virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, TEST_NPAGES); + + if (private) + vm_mem_set_private(vm, guest_test_phys_mem, TEST_SIZE); + pre_fault_memory(vcpu, guest_test_phys_mem, SZ_2M, 0); + pre_fault_memory(vcpu, guest_test_phys_mem + SZ_2M, PAGE_SIZE * 2, PAGE_SIZE); + pre_fault_memory(vcpu, guest_test_phys_mem + TEST_SIZE, PAGE_SIZE, PAGE_SIZE); + + vcpu_args_set(vcpu, 1, guest_test_virt_mem); + vcpu_run(vcpu); + + run = vcpu->run; + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "Wanted KVM_EXIT_IO, got exit reason: %u (%s)", + run->exit_reason, exit_reason_str(run->exit_reason)); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + break; + case UCALL_DONE: + break; + default: + TEST_FAIL("Unknown ucall 0x%lx.", uc.cmd); + break; + } + + kvm_vm_free(vm); +} + +static void test_pre_fault_memory(unsigned long vm_type, bool private) +{ + if (vm_type && !(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(vm_type))) { + pr_info("Skipping tests for vm_type 0x%lx\n", vm_type); + return; + } + + __test_pre_fault_memory(vm_type, private); +} + +int main(int argc, char *argv[]) +{ + TEST_REQUIRE(kvm_check_cap(KVM_CAP_PRE_FAULT_MEMORY)); + + test_pre_fault_memory(0, false); +#ifdef __x86_64__ + test_pre_fault_memory(KVM_X86_SW_PROTECTED_VM, false); + test_pre_fault_memory(KVM_X86_SW_PROTECTED_VM, true); +#endif + return 0; +} diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c index 222198dd6d04..f92c2fb23fcd 100644 --- a/tools/testing/selftests/kvm/riscv/get-reg-list.c +++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c @@ -49,6 +49,7 @@ bool filter_reg(__u64 reg) case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SVNAPOT: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SVPBMT: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZACAS: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZAWRS: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZBA: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZBB: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZBC: @@ -56,6 +57,11 @@ bool filter_reg(__u64 reg) case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZBKC: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZBKX: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZBS: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZCA: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZCB: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZCD: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZCF: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZCMOP: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZFA: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZFH: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZFHMIN: @@ -68,6 +74,7 @@ bool filter_reg(__u64 reg) case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZIHINTNTL: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZIHINTPAUSE: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZIHPM: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZIMOP: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZKND: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZKNE: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZKNH: @@ -415,6 +422,7 @@ static const char *isa_ext_single_id_to_str(__u64 reg_off) KVM_ISA_EXT_ARR(SVNAPOT), KVM_ISA_EXT_ARR(SVPBMT), KVM_ISA_EXT_ARR(ZACAS), + KVM_ISA_EXT_ARR(ZAWRS), KVM_ISA_EXT_ARR(ZBA), KVM_ISA_EXT_ARR(ZBB), KVM_ISA_EXT_ARR(ZBC), @@ -422,6 +430,11 @@ static const char *isa_ext_single_id_to_str(__u64 reg_off) KVM_ISA_EXT_ARR(ZBKC), KVM_ISA_EXT_ARR(ZBKX), KVM_ISA_EXT_ARR(ZBS), + KVM_ISA_EXT_ARR(ZCA), + KVM_ISA_EXT_ARR(ZCB), + KVM_ISA_EXT_ARR(ZCD), + KVM_ISA_EXT_ARR(ZCF), + KVM_ISA_EXT_ARR(ZCMOP), KVM_ISA_EXT_ARR(ZFA), KVM_ISA_EXT_ARR(ZFH), KVM_ISA_EXT_ARR(ZFHMIN), @@ -434,6 +447,7 @@ static const char *isa_ext_single_id_to_str(__u64 reg_off) KVM_ISA_EXT_ARR(ZIHINTNTL), KVM_ISA_EXT_ARR(ZIHINTPAUSE), KVM_ISA_EXT_ARR(ZIHPM), + KVM_ISA_EXT_ARR(ZIMOP), KVM_ISA_EXT_ARR(ZKND), KVM_ISA_EXT_ARR(ZKNE), KVM_ISA_EXT_ARR(ZKNH), @@ -939,6 +953,7 @@ KVM_ISA_EXT_SIMPLE_CONFIG(svinval, SVINVAL); KVM_ISA_EXT_SIMPLE_CONFIG(svnapot, SVNAPOT); KVM_ISA_EXT_SIMPLE_CONFIG(svpbmt, SVPBMT); KVM_ISA_EXT_SIMPLE_CONFIG(zacas, ZACAS); +KVM_ISA_EXT_SIMPLE_CONFIG(zawrs, ZAWRS); KVM_ISA_EXT_SIMPLE_CONFIG(zba, ZBA); KVM_ISA_EXT_SIMPLE_CONFIG(zbb, ZBB); KVM_ISA_EXT_SIMPLE_CONFIG(zbc, ZBC); @@ -946,6 +961,11 @@ KVM_ISA_EXT_SIMPLE_CONFIG(zbkb, ZBKB); KVM_ISA_EXT_SIMPLE_CONFIG(zbkc, ZBKC); KVM_ISA_EXT_SIMPLE_CONFIG(zbkx, ZBKX); KVM_ISA_EXT_SIMPLE_CONFIG(zbs, ZBS); +KVM_ISA_EXT_SIMPLE_CONFIG(zca, ZCA), +KVM_ISA_EXT_SIMPLE_CONFIG(zcb, ZCB), +KVM_ISA_EXT_SIMPLE_CONFIG(zcd, ZCD), +KVM_ISA_EXT_SIMPLE_CONFIG(zcf, ZCF), +KVM_ISA_EXT_SIMPLE_CONFIG(zcmop, ZCMOP); KVM_ISA_EXT_SIMPLE_CONFIG(zfa, ZFA); KVM_ISA_EXT_SIMPLE_CONFIG(zfh, ZFH); KVM_ISA_EXT_SIMPLE_CONFIG(zfhmin, ZFHMIN); @@ -958,6 +978,7 @@ KVM_ISA_EXT_SIMPLE_CONFIG(zifencei, ZIFENCEI); KVM_ISA_EXT_SIMPLE_CONFIG(zihintntl, ZIHINTNTL); KVM_ISA_EXT_SIMPLE_CONFIG(zihintpause, ZIHINTPAUSE); KVM_ISA_EXT_SIMPLE_CONFIG(zihpm, ZIHPM); +KVM_ISA_EXT_SIMPLE_CONFIG(zimop, ZIMOP); KVM_ISA_EXT_SIMPLE_CONFIG(zknd, ZKND); KVM_ISA_EXT_SIMPLE_CONFIG(zkne, ZKNE); KVM_ISA_EXT_SIMPLE_CONFIG(zknh, ZKNH); @@ -995,6 +1016,7 @@ struct vcpu_reg_list *vcpu_configs[] = { &config_svnapot, &config_svpbmt, &config_zacas, + &config_zawrs, &config_zba, &config_zbb, &config_zbc, @@ -1002,6 +1024,11 @@ struct vcpu_reg_list *vcpu_configs[] = { &config_zbkc, &config_zbkx, &config_zbs, + &config_zca, + &config_zcb, + &config_zcd, + &config_zcf, + &config_zcmop, &config_zfa, &config_zfh, &config_zfhmin, @@ -1014,6 +1041,7 @@ struct vcpu_reg_list *vcpu_configs[] = { &config_zihintntl, &config_zihintpause, &config_zihpm, + &config_zimop, &config_zknd, &config_zkne, &config_zknh, diff --git a/tools/testing/selftests/kvm/x86_64/apic_bus_clock_test.c b/tools/testing/selftests/kvm/x86_64/apic_bus_clock_test.c new file mode 100644 index 000000000000..f8916bb34405 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/apic_bus_clock_test.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 Intel Corporation + * + * Verify KVM correctly emulates the APIC bus frequency when the VMM configures + * the frequency via KVM_CAP_X86_APIC_BUS_CYCLES_NS. Start the APIC timer by + * programming TMICT (timer initial count) to the largest value possible (so + * that the timer will not expire during the test). Then, after an arbitrary + * amount of time has elapsed, verify TMCCT (timer current count) is within 1% + * of the expected value based on the time elapsed, the APIC bus frequency, and + * the programmed TDCR (timer divide configuration register). + */ + +#include "apic.h" +#include "test_util.h" + +/* + * Possible TDCR values with matching divide count. Used to modify APIC + * timer frequency. + */ +static const struct { + const uint32_t tdcr; + const uint32_t divide_count; +} tdcrs[] = { + {0x0, 2}, + {0x1, 4}, + {0x2, 8}, + {0x3, 16}, + {0x8, 32}, + {0x9, 64}, + {0xa, 128}, + {0xb, 1}, +}; + +static bool is_x2apic; + +static void apic_enable(void) +{ + if (is_x2apic) + x2apic_enable(); + else + xapic_enable(); +} + +static uint32_t apic_read_reg(unsigned int reg) +{ + return is_x2apic ? x2apic_read_reg(reg) : xapic_read_reg(reg); +} + +static void apic_write_reg(unsigned int reg, uint32_t val) +{ + if (is_x2apic) + x2apic_write_reg(reg, val); + else + xapic_write_reg(reg, val); +} + +static void apic_guest_code(uint64_t apic_hz, uint64_t delay_ms) +{ + uint64_t tsc_hz = guest_tsc_khz * 1000; + const uint32_t tmict = ~0u; + uint64_t tsc0, tsc1, freq; + uint32_t tmcct; + int i; + + apic_enable(); + + /* + * Setup one-shot timer. The vector does not matter because the + * interrupt should not fire. + */ + apic_write_reg(APIC_LVTT, APIC_LVT_TIMER_ONESHOT | APIC_LVT_MASKED); + + for (i = 0; i < ARRAY_SIZE(tdcrs); i++) { + apic_write_reg(APIC_TDCR, tdcrs[i].tdcr); + apic_write_reg(APIC_TMICT, tmict); + + tsc0 = rdtsc(); + udelay(delay_ms * 1000); + tmcct = apic_read_reg(APIC_TMCCT); + tsc1 = rdtsc(); + + /* + * Stop the timer _after_ reading the current, final count, as + * writing the initial counter also modifies the current count. + */ + apic_write_reg(APIC_TMICT, 0); + + freq = (tmict - tmcct) * tdcrs[i].divide_count * tsc_hz / (tsc1 - tsc0); + /* Check if measured frequency is within 5% of configured frequency. */ + __GUEST_ASSERT(freq < apic_hz * 105 / 100 && freq > apic_hz * 95 / 100, + "Frequency = %lu (wanted %lu - %lu), bus = %lu, div = %u, tsc = %lu", + freq, apic_hz * 95 / 100, apic_hz * 105 / 100, + apic_hz, tdcrs[i].divide_count, tsc_hz); + } + + GUEST_DONE(); +} + +static void test_apic_bus_clock(struct kvm_vcpu *vcpu) +{ + bool done = false; + struct ucall uc; + + while (!done) { + vcpu_run(vcpu); + + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_DONE: + done = true; + break; + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + break; + default: + TEST_FAIL("Unknown ucall %lu", uc.cmd); + break; + } + } +} + +static void run_apic_bus_clock_test(uint64_t apic_hz, uint64_t delay_ms, + bool x2apic) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + int ret; + + is_x2apic = x2apic; + + vm = vm_create(1); + + sync_global_to_guest(vm, is_x2apic); + + vm_enable_cap(vm, KVM_CAP_X86_APIC_BUS_CYCLES_NS, + NSEC_PER_SEC / apic_hz); + + vcpu = vm_vcpu_add(vm, 0, apic_guest_code); + vcpu_args_set(vcpu, 2, apic_hz, delay_ms); + + ret = __vm_enable_cap(vm, KVM_CAP_X86_APIC_BUS_CYCLES_NS, + NSEC_PER_SEC / apic_hz); + TEST_ASSERT(ret < 0 && errno == EINVAL, + "Setting of APIC bus frequency after vCPU is created should fail."); + + if (!is_x2apic) + virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA); + + test_apic_bus_clock(vcpu); + kvm_vm_free(vm); +} + +static void help(char *name) +{ + puts(""); + printf("usage: %s [-h] [-d delay] [-f APIC bus freq]\n", name); + puts(""); + printf("-d: Delay (in msec) guest uses to measure APIC bus frequency.\n"); + printf("-f: The APIC bus frequency (in MHz) to be configured for the guest.\n"); + puts(""); +} + +int main(int argc, char *argv[]) +{ + /* + * Arbitrarilty default to 25MHz for the APIC bus frequency, which is + * different enough from the default 1GHz to be interesting. + */ + uint64_t apic_hz = 25 * 1000 * 1000; + uint64_t delay_ms = 100; + int opt; + + TEST_REQUIRE(kvm_has_cap(KVM_CAP_X86_APIC_BUS_CYCLES_NS)); + + while ((opt = getopt(argc, argv, "d:f:h")) != -1) { + switch (opt) { + case 'f': + apic_hz = atoi_positive("APIC bus frequency", optarg) * 1000 * 1000; + break; + case 'd': + delay_ms = atoi_positive("Delay in milliseconds", optarg); + break; + case 'h': + default: + help(argv[0]); + exit(KSFT_SKIP); + } + } + + run_apic_bus_clock_test(apic_hz, delay_ms, false); + run_apic_bus_clock_test(apic_hz, delay_ms, true); +} diff --git a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c index 3cc4b86832fe..7e2bfb3c3f3b 100644 --- a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c +++ b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c @@ -26,19 +26,37 @@ int main(int argc, char *argv[]) TEST_ASSERT(ret < 0, "Setting KVM_CAP_MAX_VCPU_ID beyond KVM cap should fail"); + /* Test BOOT_CPU_ID interaction (MAX_VCPU_ID cannot be lower) */ + if (kvm_has_cap(KVM_CAP_SET_BOOT_CPU_ID)) { + vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *)MAX_VCPU_ID); + + /* Try setting KVM_CAP_MAX_VCPU_ID below BOOT_CPU_ID */ + ret = __vm_enable_cap(vm, KVM_CAP_MAX_VCPU_ID, MAX_VCPU_ID - 1); + TEST_ASSERT(ret < 0, + "Setting KVM_CAP_MAX_VCPU_ID below BOOT_CPU_ID should fail"); + } + /* Set KVM_CAP_MAX_VCPU_ID */ vm_enable_cap(vm, KVM_CAP_MAX_VCPU_ID, MAX_VCPU_ID); - /* Try to set KVM_CAP_MAX_VCPU_ID again */ ret = __vm_enable_cap(vm, KVM_CAP_MAX_VCPU_ID, MAX_VCPU_ID + 1); TEST_ASSERT(ret < 0, "Setting KVM_CAP_MAX_VCPU_ID multiple times should fail"); - /* Create vCPU with id beyond KVM_CAP_MAX_VCPU_ID cap*/ + /* Create vCPU with id beyond KVM_CAP_MAX_VCPU_ID cap */ ret = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)MAX_VCPU_ID); TEST_ASSERT(ret < 0, "Creating vCPU with ID > MAX_VCPU_ID should fail"); + /* Create vCPU with bits 63:32 != 0, but an otherwise valid id */ + ret = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)(1L << 32)); + TEST_ASSERT(ret < 0, "Creating vCPU with ID[63:32] != 0 should fail"); + + /* Create vCPU with id within bounds */ + ret = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)0); + TEST_ASSERT(ret >= 0, "Creating vCPU with ID 0 should succeed"); + + close(ret); kvm_vm_free(vm); return 0; } diff --git a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c index 96446134c00b..698cb36989db 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c @@ -7,15 +7,28 @@ #include "pmu.h" #include "processor.h" -/* Number of LOOP instructions for the guest measurement payload. */ -#define NUM_BRANCHES 10 +/* Number of iterations of the loop for the guest measurement payload. */ +#define NUM_LOOPS 10 + +/* Each iteration of the loop retires one branch instruction. */ +#define NUM_BRANCH_INSNS_RETIRED (NUM_LOOPS) + +/* + * Number of instructions in each loop. 1 CLFLUSH/CLFLUSHOPT/NOP, 1 MFENCE, + * 1 LOOP. + */ +#define NUM_INSNS_PER_LOOP 3 + /* * Number of "extra" instructions that will be counted, i.e. the number of - * instructions that are needed to set up the loop and then disabled the - * counter. 1 CLFLUSH/CLFLUSHOPT/NOP, 1 MFENCE, 2 MOV, 2 XOR, 1 WRMSR. + * instructions that are needed to set up the loop and then disable the + * counter. 2 MOV, 2 XOR, 1 WRMSR. */ -#define NUM_EXTRA_INSNS 7 -#define NUM_INSNS_RETIRED (NUM_BRANCHES + NUM_EXTRA_INSNS) +#define NUM_EXTRA_INSNS 5 + +/* Total number of instructions retired within the measured section. */ +#define NUM_INSNS_RETIRED (NUM_LOOPS * NUM_INSNS_PER_LOOP + NUM_EXTRA_INSNS) + static uint8_t kvm_pmu_version; static bool kvm_has_perf_caps; @@ -100,7 +113,7 @@ static void guest_assert_event_count(uint8_t idx, GUEST_ASSERT_EQ(count, NUM_INSNS_RETIRED); break; case INTEL_ARCH_BRANCHES_RETIRED_INDEX: - GUEST_ASSERT_EQ(count, NUM_BRANCHES); + GUEST_ASSERT_EQ(count, NUM_BRANCH_INSNS_RETIRED); break; case INTEL_ARCH_LLC_REFERENCES_INDEX: case INTEL_ARCH_LLC_MISSES_INDEX: @@ -120,7 +133,7 @@ static void guest_assert_event_count(uint8_t idx, } sanity_checks: - __asm__ __volatile__("loop ." : "+c"((int){NUM_BRANCHES})); + __asm__ __volatile__("loop ." : "+c"((int){NUM_LOOPS})); GUEST_ASSERT_EQ(_rdpmc(pmc), count); wrmsr(pmc_msr, 0xdead); @@ -134,8 +147,8 @@ sanity_checks: * before the end of the sequence. * * If CLFUSH{,OPT} is supported, flush the cacheline containing (at least) the - * start of the loop to force LLC references and misses, i.e. to allow testing - * that those events actually count. + * CLFUSH{,OPT} instruction on each loop iteration to force LLC references and + * misses, i.e. to allow testing that those events actually count. * * If forced emulation is enabled (and specified), force emulation on a subset * of the measured code to verify that KVM correctly emulates instructions and @@ -145,10 +158,11 @@ sanity_checks: #define GUEST_MEASURE_EVENT(_msr, _value, clflush, FEP) \ do { \ __asm__ __volatile__("wrmsr\n\t" \ + " mov $" __stringify(NUM_LOOPS) ", %%ecx\n\t" \ + "1:\n\t" \ clflush "\n\t" \ "mfence\n\t" \ - "1: mov $" __stringify(NUM_BRANCHES) ", %%ecx\n\t" \ - FEP "loop .\n\t" \ + FEP "loop 1b\n\t" \ FEP "mov %%edi, %%ecx\n\t" \ FEP "xor %%eax, %%eax\n\t" \ FEP "xor %%edx, %%edx\n\t" \ @@ -163,9 +177,9 @@ do { \ wrmsr(pmc_msr, 0); \ \ if (this_cpu_has(X86_FEATURE_CLFLUSHOPT)) \ - GUEST_MEASURE_EVENT(_ctrl_msr, _value, "clflushopt 1f", FEP); \ + GUEST_MEASURE_EVENT(_ctrl_msr, _value, "clflushopt .", FEP); \ else if (this_cpu_has(X86_FEATURE_CLFLUSH)) \ - GUEST_MEASURE_EVENT(_ctrl_msr, _value, "clflush 1f", FEP); \ + GUEST_MEASURE_EVENT(_ctrl_msr, _value, "clflush .", FEP); \ else \ GUEST_MEASURE_EVENT(_ctrl_msr, _value, "nop", FEP); \ \ @@ -500,7 +514,7 @@ static void guest_test_fixed_counters(void) wrmsr(MSR_CORE_PERF_FIXED_CTR0 + i, 0); wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, FIXED_PMC_CTRL(i, FIXED_PMC_KERNEL)); wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, FIXED_PMC_GLOBAL_CTRL_ENABLE(i)); - __asm__ __volatile__("loop ." : "+c"((int){NUM_BRANCHES})); + __asm__ __volatile__("loop ." : "+c"((int){NUM_LOOPS})); wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0); val = rdmsr(MSR_CORE_PERF_FIXED_CTR0 + i); diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index 26b3e7efe5dd..c15513cd74d1 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -32,8 +32,8 @@ struct __kvm_pmu_event_filter { /* * This event list comprises Intel's known architectural events, plus AMD's - * "retired branch instructions" for Zen1-Zen3 (and* possibly other AMD CPUs). - * Note, AMD and Intel use the same encoding for instructions retired. + * Branch Instructions Retired for Zen CPUs. Note, AMD and Intel use the + * same encoding for Instructions Retired. */ kvm_static_assert(INTEL_ARCH_INSTRUCTIONS_RETIRED == AMD_ZEN_INSTRUCTIONS_RETIRED); @@ -353,38 +353,13 @@ static bool use_intel_pmu(void) kvm_pmu_has(X86_PMU_FEATURE_BRANCH_INSNS_RETIRED); } -static bool is_zen1(uint32_t family, uint32_t model) -{ - return family == 0x17 && model <= 0x0f; -} - -static bool is_zen2(uint32_t family, uint32_t model) -{ - return family == 0x17 && model >= 0x30 && model <= 0x3f; -} - -static bool is_zen3(uint32_t family, uint32_t model) -{ - return family == 0x19 && model <= 0x0f; -} - /* - * Determining AMD support for a PMU event requires consulting the AMD - * PPR for the CPU or reference material derived therefrom. The AMD - * test code herein has been verified to work on Zen1, Zen2, and Zen3. - * - * Feel free to add more AMD CPUs that are documented to support event - * select 0xc2 umask 0 as "retired branch instructions." + * On AMD, all Family 17h+ CPUs (Zen and its successors) use event encoding + * 0xc2,0 for Branch Instructions Retired. */ static bool use_amd_pmu(void) { - uint32_t family = kvm_cpu_family(); - uint32_t model = kvm_cpu_model(); - - return host_cpu_is_amd && - (is_zen1(family, model) || - is_zen2(family, model) || - is_zen3(family, model)); + return host_cpu_is_amd && kvm_cpu_family() >= 0x17; } /* diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index d691d86e5bc3..49913784bc82 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -33,6 +33,20 @@ static void guest_not_bsp_vcpu(void *arg) GUEST_DONE(); } +static void test_set_invalid_bsp(struct kvm_vm *vm) +{ + unsigned long max_vcpu_id = vm_check_cap(vm, KVM_CAP_MAX_VCPU_ID); + int r; + + if (max_vcpu_id) { + r = __vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *)(max_vcpu_id + 1)); + TEST_ASSERT(r == -1 && errno == EINVAL, "BSP with ID > MAX should fail"); + } + + r = __vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *)(1L << 32)); + TEST_ASSERT(r == -1 && errno == EINVAL, "BSP with ID[63:32]!=0 should fail"); +} + static void test_set_bsp_busy(struct kvm_vcpu *vcpu, const char *msg) { int r = __vm_ioctl(vcpu->vm, KVM_SET_BOOT_CPU_ID, @@ -80,6 +94,8 @@ static struct kvm_vm *create_vm(uint32_t nr_vcpus, uint32_t bsp_vcpu_id, vm = vm_create(nr_vcpus); + test_set_invalid_bsp(vm); + vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *)(unsigned long)bsp_vcpu_id); for (i = 0; i < nr_vcpus; i++) diff --git a/tools/testing/selftests/riscv/vector/vstate_prctl.c b/tools/testing/selftests/riscv/vector/vstate_prctl.c index 27668fb3b6d0..895177f6bf4c 100644 --- a/tools/testing/selftests/riscv/vector/vstate_prctl.c +++ b/tools/testing/selftests/riscv/vector/vstate_prctl.c @@ -88,16 +88,16 @@ int main(void) return -2; } - if (!(pair.value & RISCV_HWPROBE_IMA_V)) { + if (!(pair.value & RISCV_HWPROBE_EXT_ZVE32X)) { rc = prctl(PR_RISCV_V_GET_CONTROL); if (rc != -1 || errno != EINVAL) { - ksft_test_result_fail("GET_CONTROL should fail on kernel/hw without V\n"); + ksft_test_result_fail("GET_CONTROL should fail on kernel/hw without ZVE32X\n"); return -3; } rc = prctl(PR_RISCV_V_SET_CONTROL, PR_RISCV_V_VSTATE_CTRL_ON); if (rc != -1 || errno != EINVAL) { - ksft_test_result_fail("GET_CONTROL should fail on kernel/hw without V\n"); + ksft_test_result_fail("SET_CONTROL should fail on kernel/hw without ZVE32X\n"); return -4; } diff --git a/tools/testing/selftests/sigaltstack/current_stack_pointer.h b/tools/testing/selftests/sigaltstack/current_stack_pointer.h index ea9bdf3a90b1..09da8f1011ce 100644 --- a/tools/testing/selftests/sigaltstack/current_stack_pointer.h +++ b/tools/testing/selftests/sigaltstack/current_stack_pointer.h @@ -8,7 +8,7 @@ register unsigned long sp asm("sp"); register unsigned long sp asm("esp"); #elif __loongarch64 register unsigned long sp asm("$sp"); -#elif __ppc__ +#elif __powerpc__ register unsigned long sp asm("r1"); #elif __s390x__ register unsigned long sp asm("%15"); diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index 29b73eedfe74..b14e14cdbfb9 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -67,6 +67,9 @@ config HAVE_KVM_INVALID_WAKEUPS config KVM_GENERIC_DIRTYLOG_READ_PROTECT bool +config KVM_GENERIC_PRE_FAULT_MEMORY + bool + config KVM_COMPAT def_bool y depends on KVM && COMPAT && !(S390 || ARM64 || RISCV) @@ -109,3 +112,11 @@ config KVM_GENERIC_PRIVATE_MEM select KVM_GENERIC_MEMORY_ATTRIBUTES select KVM_PRIVATE_MEM bool + +config HAVE_KVM_GMEM_PREPARE + bool + depends on KVM_PRIVATE_MEM + +config HAVE_KVM_GMEM_INVALIDATE + bool + depends on KVM_PRIVATE_MEM diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index 99a63bad0306..0ee4816b079a 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -80,7 +80,6 @@ static void async_pf_execute(struct work_struct *work) spin_lock(&vcpu->async_pf.lock); first = list_empty(&vcpu->async_pf.done); list_add_tail(&apf->link, &vcpu->async_pf.done); - apf->vcpu = NULL; spin_unlock(&vcpu->async_pf.lock); /* @@ -120,8 +119,6 @@ static void kvm_flush_and_free_async_pf_work(struct kvm_async_pf *work) void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu) { - spin_lock(&vcpu->async_pf.lock); - /* cancel outstanding work queue item */ while (!list_empty(&vcpu->async_pf.queue)) { struct kvm_async_pf *work = @@ -129,23 +126,15 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu) typeof(*work), queue); list_del(&work->queue); - /* - * We know it's present in vcpu->async_pf.done, do - * nothing here. - */ - if (!work->vcpu) - continue; - - spin_unlock(&vcpu->async_pf.lock); #ifdef CONFIG_KVM_ASYNC_PF_SYNC flush_work(&work->work); #else if (cancel_work_sync(&work->work)) kmem_cache_free(async_pf_cache, work); #endif - spin_lock(&vcpu->async_pf.lock); } + spin_lock(&vcpu->async_pf.lock); while (!list_empty(&vcpu->async_pf.done)) { struct kvm_async_pf *work = list_first_entry(&vcpu->async_pf.done, diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c index 747fe251e445..1c509c351261 100644 --- a/virt/kvm/guest_memfd.c +++ b/virt/kvm/guest_memfd.c @@ -13,14 +13,50 @@ struct kvm_gmem { struct list_head entry; }; -static struct folio *kvm_gmem_get_folio(struct inode *inode, pgoff_t index) +static int kvm_gmem_prepare_folio(struct inode *inode, pgoff_t index, struct folio *folio) +{ +#ifdef CONFIG_HAVE_KVM_GMEM_PREPARE + struct list_head *gmem_list = &inode->i_mapping->i_private_list; + struct kvm_gmem *gmem; + + list_for_each_entry(gmem, gmem_list, entry) { + struct kvm_memory_slot *slot; + struct kvm *kvm = gmem->kvm; + struct page *page; + kvm_pfn_t pfn; + gfn_t gfn; + int rc; + + if (!kvm_arch_gmem_prepare_needed(kvm)) + continue; + + slot = xa_load(&gmem->bindings, index); + if (!slot) + continue; + + page = folio_file_page(folio, index); + pfn = page_to_pfn(page); + gfn = slot->base_gfn + index - slot->gmem.pgoff; + rc = kvm_arch_gmem_prepare(kvm, gfn, pfn, compound_order(compound_head(page))); + if (rc) { + pr_warn_ratelimited("gmem: Failed to prepare folio for index %lx GFN %llx PFN %llx error %d.\n", + index, gfn, pfn, rc); + return rc; + } + } + +#endif + return 0; +} + +static struct folio *kvm_gmem_get_folio(struct inode *inode, pgoff_t index, bool prepare) { struct folio *folio; /* TODO: Support huge pages. */ folio = filemap_grab_folio(inode->i_mapping, index); - if (IS_ERR_OR_NULL(folio)) - return NULL; + if (IS_ERR(folio)) + return folio; /* * Use the up-to-date flag to track whether or not the memory has been @@ -41,6 +77,15 @@ static struct folio *kvm_gmem_get_folio(struct inode *inode, pgoff_t index) folio_mark_uptodate(folio); } + if (prepare) { + int r = kvm_gmem_prepare_folio(inode, index, folio); + if (r < 0) { + folio_unlock(folio); + folio_put(folio); + return ERR_PTR(r); + } + } + /* * Ignore accessed, referenced, and dirty flags. The memory is * unevictable and there is no storage to write back to. @@ -145,9 +190,9 @@ static long kvm_gmem_allocate(struct inode *inode, loff_t offset, loff_t len) break; } - folio = kvm_gmem_get_folio(inode, index); - if (!folio) { - r = -ENOMEM; + folio = kvm_gmem_get_folio(inode, index, true); + if (IS_ERR(folio)) { + r = PTR_ERR(folio); break; } @@ -298,10 +343,24 @@ static int kvm_gmem_error_folio(struct address_space *mapping, struct folio *fol return MF_DELAYED; } +#ifdef CONFIG_HAVE_KVM_GMEM_INVALIDATE +static void kvm_gmem_free_folio(struct folio *folio) +{ + struct page *page = folio_page(folio, 0); + kvm_pfn_t pfn = page_to_pfn(page); + int order = folio_order(folio); + + kvm_arch_gmem_invalidate(pfn, pfn + (1ul << order)); +} +#endif + static const struct address_space_operations kvm_gmem_aops = { .dirty_folio = noop_dirty_folio, .migrate_folio = kvm_gmem_migrate_folio, .error_remove_folio = kvm_gmem_error_folio, +#ifdef CONFIG_HAVE_KVM_GMEM_INVALIDATE + .free_folio = kvm_gmem_free_folio, +#endif }; static int kvm_gmem_getattr(struct mnt_idmap *idmap, const struct path *path, @@ -360,7 +419,7 @@ static int __kvm_gmem_create(struct kvm *kvm, loff_t size, u64 flags) inode->i_mode |= S_IFREG; inode->i_size = size; mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER); - mapping_set_unmovable(inode->i_mapping); + mapping_set_inaccessible(inode->i_mapping); /* Unmovable mappings are supposed to be marked unevictable as well. */ WARN_ON_ONCE(!mapping_unevictable(inode->i_mapping)); @@ -482,38 +541,34 @@ void kvm_gmem_unbind(struct kvm_memory_slot *slot) fput(file); } -int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot, - gfn_t gfn, kvm_pfn_t *pfn, int *max_order) +static int __kvm_gmem_get_pfn(struct file *file, struct kvm_memory_slot *slot, + gfn_t gfn, kvm_pfn_t *pfn, int *max_order, bool prepare) { pgoff_t index = gfn - slot->base_gfn + slot->gmem.pgoff; - struct kvm_gmem *gmem; + struct kvm_gmem *gmem = file->private_data; struct folio *folio; struct page *page; - struct file *file; int r; - file = kvm_gmem_get_file(slot); - if (!file) + if (file != slot->gmem.file) { + WARN_ON_ONCE(slot->gmem.file); return -EFAULT; + } gmem = file->private_data; - - if (WARN_ON_ONCE(xa_load(&gmem->bindings, index) != slot)) { - r = -EIO; - goto out_fput; + if (xa_load(&gmem->bindings, index) != slot) { + WARN_ON_ONCE(xa_load(&gmem->bindings, index)); + return -EIO; } - folio = kvm_gmem_get_folio(file_inode(file), index); - if (!folio) { - r = -ENOMEM; - goto out_fput; - } + folio = kvm_gmem_get_folio(file_inode(file), index, prepare); + if (IS_ERR(folio)) + return PTR_ERR(folio); if (folio_test_hwpoison(folio)) { folio_unlock(folio); folio_put(folio); - r = -EHWPOISON; - goto out_fput; + return -EHWPOISON; } page = folio_file_page(folio, index); @@ -525,9 +580,78 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot, r = 0; folio_unlock(folio); -out_fput: - fput(file); return r; } + +int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot, + gfn_t gfn, kvm_pfn_t *pfn, int *max_order) +{ + struct file *file = kvm_gmem_get_file(slot); + int r; + + if (!file) + return -EFAULT; + + r = __kvm_gmem_get_pfn(file, slot, gfn, pfn, max_order, true); + fput(file); + return r; +} EXPORT_SYMBOL_GPL(kvm_gmem_get_pfn); + +long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long npages, + kvm_gmem_populate_cb post_populate, void *opaque) +{ + struct file *file; + struct kvm_memory_slot *slot; + void __user *p; + + int ret = 0, max_order; + long i; + + lockdep_assert_held(&kvm->slots_lock); + if (npages < 0) + return -EINVAL; + + slot = gfn_to_memslot(kvm, start_gfn); + if (!kvm_slot_can_be_private(slot)) + return -EINVAL; + + file = kvm_gmem_get_file(slot); + if (!file) + return -EFAULT; + + filemap_invalidate_lock(file->f_mapping); + + npages = min_t(ulong, slot->npages - (start_gfn - slot->base_gfn), npages); + for (i = 0; i < npages; i += (1 << max_order)) { + gfn_t gfn = start_gfn + i; + kvm_pfn_t pfn; + + if (signal_pending(current)) { + ret = -EINTR; + break; + } + + ret = __kvm_gmem_get_pfn(file, slot, gfn, &pfn, &max_order, false); + if (ret) + break; + + if (!IS_ALIGNED(gfn, (1 << max_order)) || + (npages - i) < (1 << max_order)) + max_order = 0; + + p = src ? src + i * PAGE_SIZE : NULL; + ret = post_populate(kvm, gfn, pfn, p, max_order, opaque); + + put_page(pfn_to_page(pfn)); + if (ret) + break; + } + + filemap_invalidate_unlock(file->f_mapping); + + fput(file); + return ret && !i ? ret : i; +} +EXPORT_SYMBOL_GPL(kvm_gmem_populate); diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c index 1e567d1f6d3d..162d8ed889f2 100644 --- a/virt/kvm/irqchip.c +++ b/virt/kvm/irqchip.c @@ -237,3 +237,27 @@ out: return r; } + +/* + * Allocate empty IRQ routing by default so that additional setup isn't needed + * when userspace-driven IRQ routing is activated, and so that kvm->irq_routing + * is guaranteed to be non-NULL. + */ +int kvm_init_irq_routing(struct kvm *kvm) +{ + struct kvm_irq_routing_table *new; + int chip_size; + + new = kzalloc(struct_size(new, map, 1), GFP_KERNEL_ACCOUNT); + if (!new) + return -ENOMEM; + + new->nr_rt_entries = 1; + + chip_size = sizeof(int) * KVM_NR_IRQCHIPS * KVM_IRQCHIP_NUM_PINS; + memset(new->chip, -1, chip_size); + + RCU_INIT_POINTER(kvm->irq_routing, new); + + return 0; +} diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 1192942aef91..d0788d0a72cc 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1,9 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Kernel-based Virtual Machine driver for Linux - * - * This module enables machines with Intel VT-x extensions to run virtual - * machines without emulation or binary translation. + * Kernel-based Virtual Machine (KVM) Hypervisor * * Copyright (C) 2006 Qumranet, Inc. * Copyright 2010 Red Hat, Inc. and/or its affiliates. @@ -74,6 +71,7 @@ #define ITOA_MAX_LEN 12 MODULE_AUTHOR("Qumranet"); +MODULE_DESCRIPTION("Kernel-based Virtual Machine (KVM) Hypervisor"); MODULE_LICENSE("GPL"); /* Architectures should define their poll value according to the halt latency */ @@ -91,8 +89,8 @@ unsigned int halt_poll_ns_grow_start = 10000; /* 10us */ module_param(halt_poll_ns_grow_start, uint, 0644); EXPORT_SYMBOL_GPL(halt_poll_ns_grow_start); -/* Default resets per-vcpu halt_poll_ns . */ -unsigned int halt_poll_ns_shrink; +/* Default halves per-vcpu halt_poll_ns. */ +unsigned int halt_poll_ns_shrink = 2; module_param(halt_poll_ns_shrink, uint, 0644); EXPORT_SYMBOL_GPL(halt_poll_ns_shrink); @@ -110,8 +108,7 @@ static struct kmem_cache *kvm_vcpu_cache; static __read_mostly struct preempt_ops kvm_preempt_ops; static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_running_vcpu); -struct dentry *kvm_debugfs_dir; -EXPORT_SYMBOL_GPL(kvm_debugfs_dir); +static struct dentry *kvm_debugfs_dir; static const struct file_operations stat_fops_per_vm; @@ -1145,8 +1142,7 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname) { struct kvm *kvm = kvm_arch_alloc_vm(); struct kvm_memslots *slots; - int r = -ENOMEM; - int i, j; + int r, i, j; if (!kvm) return ERR_PTR(-ENOMEM); @@ -1183,12 +1179,18 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname) snprintf(kvm->stats_id, sizeof(kvm->stats_id), "kvm-%d", task_pid_nr(current)); + r = -ENOMEM; if (init_srcu_struct(&kvm->srcu)) goto out_err_no_srcu; if (init_srcu_struct(&kvm->irq_srcu)) goto out_err_no_irq_srcu; + r = kvm_init_irq_routing(kvm); + if (r) + goto out_err_no_irq_routing; + refcount_set(&kvm->users_count, 1); + for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) { for (j = 0; j < 2; j++) { slots = &kvm->__memslots[i][j]; @@ -1206,6 +1208,7 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname) rcu_assign_pointer(kvm->memslots[i], &kvm->__memslots[i][0]); } + r = -ENOMEM; for (i = 0; i < KVM_NR_BUSES; i++) { rcu_assign_pointer(kvm->buses[i], kzalloc(sizeof(struct kvm_io_bus), GFP_KERNEL_ACCOUNT)); @@ -1267,6 +1270,8 @@ out_err_no_arch_destroy_vm: WARN_ON_ONCE(!refcount_dec_and_test(&kvm->users_count)); for (i = 0; i < KVM_NR_BUSES; i++) kfree(kvm_get_bus(kvm, i)); + kvm_free_irq_routing(kvm); +out_err_no_irq_routing: cleanup_srcu_struct(&kvm->irq_srcu); out_err_no_irq_srcu: cleanup_srcu_struct(&kvm->srcu); @@ -4202,12 +4207,21 @@ static void kvm_create_vcpu_debugfs(struct kvm_vcpu *vcpu) /* * Creates some virtual cpus. Good luck creating more than one. */ -static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) +static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id) { int r; struct kvm_vcpu *vcpu; struct page *page; + /* + * KVM tracks vCPU IDs as 'int', be kind to userspace and reject + * too-large values instead of silently truncating. + * + * Ensure KVM_MAX_VCPU_IDS isn't pushed above INT_MAX without first + * changing the storage type (at the very least, IDs should be tracked + * as unsigned ints). + */ + BUILD_BUG_ON(KVM_MAX_VCPU_IDS > INT_MAX); if (id >= KVM_MAX_VCPU_IDS) return -EINVAL; @@ -4375,6 +4389,52 @@ static int kvm_vcpu_ioctl_get_stats_fd(struct kvm_vcpu *vcpu) return fd; } +#ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY +static int kvm_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, + struct kvm_pre_fault_memory *range) +{ + int idx; + long r; + u64 full_size; + + if (range->flags) + return -EINVAL; + + if (!PAGE_ALIGNED(range->gpa) || + !PAGE_ALIGNED(range->size) || + range->gpa + range->size <= range->gpa) + return -EINVAL; + + vcpu_load(vcpu); + idx = srcu_read_lock(&vcpu->kvm->srcu); + + full_size = range->size; + do { + if (signal_pending(current)) { + r = -EINTR; + break; + } + + r = kvm_arch_vcpu_pre_fault_memory(vcpu, range); + if (WARN_ON_ONCE(r == 0 || r == -EIO)) + break; + + if (r < 0) + break; + + range->size -= r; + range->gpa += r; + cond_resched(); + } while (range->size); + + srcu_read_unlock(&vcpu->kvm->srcu, idx); + vcpu_put(vcpu); + + /* Return success if at least one page was mapped successfully. */ + return full_size == range->size ? r : 0; +} +#endif + static long kvm_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -4421,7 +4481,10 @@ static long kvm_vcpu_ioctl(struct file *filp, synchronize_rcu(); put_pid(oldpid); } + vcpu->wants_to_run = !READ_ONCE(vcpu->run->immediate_exit__unsafe); r = kvm_arch_vcpu_ioctl_run(vcpu); + vcpu->wants_to_run = false; + trace_kvm_userspace_exit(vcpu->run->exit_reason, r); break; } @@ -4575,6 +4638,20 @@ out_free1: r = kvm_vcpu_ioctl_get_stats_fd(vcpu); break; } +#ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY + case KVM_PRE_FAULT_MEMORY: { + struct kvm_pre_fault_memory range; + + r = -EFAULT; + if (copy_from_user(&range, argp, sizeof(range))) + break; + r = kvm_vcpu_pre_fault_memory(vcpu, &range); + /* Pass back leftover range. */ + if (copy_to_user(argp, &range, sizeof(range))) + r = -EFAULT; + break; + } +#endif default: r = kvm_arch_vcpu_ioctl(filp, ioctl, arg); } @@ -6287,8 +6364,9 @@ static void kvm_sched_in(struct preempt_notifier *pn, int cpu) WRITE_ONCE(vcpu->ready, false); __this_cpu_write(kvm_running_vcpu, vcpu); - kvm_arch_sched_in(vcpu, cpu); kvm_arch_vcpu_load(vcpu, cpu); + + WRITE_ONCE(vcpu->scheduled_out, false); } static void kvm_sched_out(struct preempt_notifier *pn, @@ -6296,7 +6374,9 @@ static void kvm_sched_out(struct preempt_notifier *pn, { struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn); - if (current->on_rq) { + WRITE_ONCE(vcpu->scheduled_out, true); + + if (current->on_rq && vcpu->wants_to_run) { WRITE_ONCE(vcpu->preempted, true); WRITE_ONCE(vcpu->ready, true); } diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index e3453e869e92..f0039efb9e1e 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -430,6 +430,9 @@ int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned long len) int kvm_gpc_activate_hva(struct gfn_to_pfn_cache *gpc, unsigned long uhva, unsigned long len) { + if (!access_ok((void __user *)uhva, len)) + return -EINVAL; + return __kvm_gpc_activate(gpc, INVALID_GPA, uhva, len); }