- 'of_property_for_each_string'
- 'of_property_for_each_u32'
- 'pci_bus_for_each_resource'
+ - 'pci_doe_for_each_off'
- 'pcl_for_each_chunk'
- 'pcl_for_each_segment'
- 'pcm_for_each_format'
all descendant memdevs for unbind. Writing '1' to this attribute
flushes that work.
+
What: /sys/bus/cxl/devices/memX/firmware_version
Date: December, 2020
KernelVersion: v5.12
Memory Device Output Payload in the CXL-2.0
specification.
+
What: /sys/bus/cxl/devices/memX/ram/size
Date: December, 2020
KernelVersion: v5.12
identically named field in the Identify Memory Device Output
Payload in the CXL-2.0 specification.
+
What: /sys/bus/cxl/devices/memX/pmem/size
Date: December, 2020
KernelVersion: v5.12
identically named field in the Identify Memory Device Output
Payload in the CXL-2.0 specification.
+
What: /sys/bus/cxl/devices/memX/serial
Date: January, 2022
KernelVersion: v5.18
capability. Mandatory for CXL devices, see CXL 2.0 8.1.12.2
Memory Device PCIe Capabilities and Extended Capabilities.
+
What: /sys/bus/cxl/devices/memX/numa_node
Date: January, 2022
KernelVersion: v5.18
host PCI device for this memory device, emit the CPU node
affinity for this device.
+
What: /sys/bus/cxl/devices/*/devtype
Date: June, 2021
KernelVersion: v5.14
Contact: linux-cxl@vger.kernel.org
Description:
- CXL device objects export the devtype attribute which mirrors
- the same value communicated in the DEVTYPE environment variable
- for uevents for devices on the "cxl" bus.
+ (RO) CXL device objects export the devtype attribute which
+ mirrors the same value communicated in the DEVTYPE environment
+ variable for uevents for devices on the "cxl" bus.
+
What: /sys/bus/cxl/devices/*/modalias
Date: December, 2021
KernelVersion: v5.18
Contact: linux-cxl@vger.kernel.org
Description:
- CXL device objects export the modalias attribute which mirrors
- the same value communicated in the MODALIAS environment variable
- for uevents for devices on the "cxl" bus.
+ (RO) CXL device objects export the modalias attribute which
+ mirrors the same value communicated in the MODALIAS environment
+ variable for uevents for devices on the "cxl" bus.
+
What: /sys/bus/cxl/devices/portX/uport
Date: June, 2021
KernelVersion: v5.14
Contact: linux-cxl@vger.kernel.org
Description:
- CXL port objects are enumerated from either a platform firmware
- device (ACPI0017 and ACPI0016) or PCIe switch upstream port with
- CXL component registers. The 'uport' symlink connects the CXL
- portX object to the device that published the CXL port
+ (RO) CXL port objects are enumerated from either a platform
+ firmware device (ACPI0017 and ACPI0016) or PCIe switch upstream
+ port with CXL component registers. The 'uport' symlink connects
+ the CXL portX object to the device that published the CXL port
capability.
+
What: /sys/bus/cxl/devices/portX/dportY
Date: June, 2021
KernelVersion: v5.14
Contact: linux-cxl@vger.kernel.org
Description:
- CXL port objects are enumerated from either a platform firmware
- device (ACPI0017 and ACPI0016) or PCIe switch upstream port with
- CXL component registers. The 'dportY' symlink identifies one or
- more downstream ports that the upstream port may target in its
- decode of CXL memory resources. The 'Y' integer reflects the
- hardware port unique-id used in the hardware decoder target
- list.
+ (RO) CXL port objects are enumerated from either a platform
+ firmware device (ACPI0017 and ACPI0016) or PCIe switch upstream
+ port with CXL component registers. The 'dportY' symlink
+ identifies one or more downstream ports that the upstream port
+ may target in its decode of CXL memory resources. The 'Y'
+ integer reflects the hardware port unique-id used in the
+ hardware decoder target list.
+
What: /sys/bus/cxl/devices/decoderX.Y
Date: June, 2021
KernelVersion: v5.14
Contact: linux-cxl@vger.kernel.org
Description:
- CXL decoder objects are enumerated from either a platform
+ (RO) CXL decoder objects are enumerated from either a platform
firmware description, or a CXL HDM decoder register set in a
PCIe device (see CXL 2.0 section 8.2.5.12 CXL HDM Decoder
Capability Structure). The 'X' in decoderX.Y represents the
cxl_port container of this decoder, and 'Y' represents the
instance id of a given decoder resource.
+
What: /sys/bus/cxl/devices/decoderX.Y/{start,size}
Date: June, 2021
KernelVersion: v5.14
Contact: linux-cxl@vger.kernel.org
Description:
- The 'start' and 'size' attributes together convey the physical
- address base and number of bytes mapped in the decoder's decode
- window. For decoders of devtype "cxl_decoder_root" the address
- range is fixed. For decoders of devtype "cxl_decoder_switch" the
- address is bounded by the decode range of the cxl_port ancestor
- of the decoder's cxl_port, and dynamically updates based on the
- active memory regions in that address space.
+ (RO) The 'start' and 'size' attributes together convey the
+ physical address base and number of bytes mapped in the
+ decoder's decode window. For decoders of devtype
+ "cxl_decoder_root" the address range is fixed. For decoders of
+ devtype "cxl_decoder_switch" the address is bounded by the
+ decode range of the cxl_port ancestor of the decoder's cxl_port,
+ and dynamically updates based on the active memory regions in
+ that address space.
+
What: /sys/bus/cxl/devices/decoderX.Y/locked
Date: June, 2021
KernelVersion: v5.14
Contact: linux-cxl@vger.kernel.org
Description:
- CXL HDM decoders have the capability to lock the configuration
- until the next device reset. For decoders of devtype
- "cxl_decoder_root" there is no standard facility to unlock them.
- For decoders of devtype "cxl_decoder_switch" a secondary bus
- reset, of the PCIe bridge that provides the bus for this
- decoders uport, unlocks / resets the decoder.
+ (RO) CXL HDM decoders have the capability to lock the
+ configuration until the next device reset. For decoders of
+ devtype "cxl_decoder_root" there is no standard facility to
+ unlock them. For decoders of devtype "cxl_decoder_switch" a
+ secondary bus reset, of the PCIe bridge that provides the bus
+ for this decoders uport, unlocks / resets the decoder.
+
What: /sys/bus/cxl/devices/decoderX.Y/target_list
Date: June, 2021
KernelVersion: v5.14
Contact: linux-cxl@vger.kernel.org
Description:
- Display a comma separated list of the current decoder target
- configuration. The list is ordered by the current configured
- interleave order of the decoder's dport instances. Each entry in
- the list is a dport id.
+ (RO) Display a comma separated list of the current decoder
+ target configuration. The list is ordered by the current
+ configured interleave order of the decoder's dport instances.
+ Each entry in the list is a dport id.
+
What: /sys/bus/cxl/devices/decoderX.Y/cap_{pmem,ram,type2,type3}
Date: June, 2021
KernelVersion: v5.14
Contact: linux-cxl@vger.kernel.org
Description:
- When a CXL decoder is of devtype "cxl_decoder_root", it
+ (RO) When a CXL decoder is of devtype "cxl_decoder_root", it
represents a fixed memory window identified by platform
firmware. A fixed window may only support a subset of memory
types. The 'cap_*' attributes indicate whether persistent
memory, volatile memory, accelerator memory, and / or expander
memory may be mapped behind this decoder's memory window.
+
What: /sys/bus/cxl/devices/decoderX.Y/target_type
Date: June, 2021
KernelVersion: v5.14
Contact: linux-cxl@vger.kernel.org
Description:
- When a CXL decoder is of devtype "cxl_decoder_switch", it can
- optionally decode either accelerator memory (type-2) or expander
- memory (type-3). The 'target_type' attribute indicates the
- current setting which may dynamically change based on what
+ (RO) When a CXL decoder is of devtype "cxl_decoder_switch", it
+ can optionally decode either accelerator memory (type-2) or
+ expander memory (type-3). The 'target_type' attribute indicates
+ the current setting which may dynamically change based on what
memory regions are activated in this decode hierarchy.
+
+
+What: /sys/bus/cxl/devices/endpointX/CDAT
+Date: July, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RO) If this sysfs entry is not present no DOE mailbox was
+ found to support CDAT data. If it is present and the length of
+ the data is 0 reading the CDAT data failed. Otherwise the CDAT
+ data is reported.
+
+
+What: /sys/bus/cxl/devices/decoderX.Y/mode
+Date: May, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RW) When a CXL decoder is of devtype "cxl_decoder_endpoint" it
+ translates from a host physical address range, to a device local
+ address range. Device-local address ranges are further split
+ into a 'ram' (volatile memory) range and 'pmem' (persistent
+ memory) range. The 'mode' attribute emits one of 'ram', 'pmem',
+ 'mixed', or 'none'. The 'mixed' indication is for error cases
+ when a decoder straddles the volatile/persistent partition
+ boundary, and 'none' indicates the decoder is not actively
+ decoding, or no DPA allocation policy has been set.
+
+ 'mode' can be written, when the decoder is in the 'disabled'
+ state, with either 'ram' or 'pmem' to set the boundaries for the
+ next allocation.
+
+
+What: /sys/bus/cxl/devices/decoderX.Y/dpa_resource
+Date: May, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RO) When a CXL decoder is of devtype "cxl_decoder_endpoint",
+ and its 'dpa_size' attribute is non-zero, this attribute
+ indicates the device physical address (DPA) base address of the
+ allocation.
+
+
+What: /sys/bus/cxl/devices/decoderX.Y/dpa_size
+Date: May, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RW) When a CXL decoder is of devtype "cxl_decoder_endpoint" it
+ translates from a host physical address range, to a device local
+ address range. The range, base address plus length in bytes, of
+ DPA allocated to this decoder is conveyed in these 2 attributes.
+ Allocations can be mutated as long as the decoder is in the
+ disabled state. A write to 'dpa_size' releases the previous DPA
+ allocation and then attempts to allocate from the free capacity
+ in the device partition referred to by 'decoderX.Y/mode'.
+ Allocate and free requests can only be performed on the highest
+ instance number disabled decoder with non-zero size. I.e.
+ allocations are enforced to occur in increasing 'decoderX.Y/id'
+ order and frees are enforced to occur in decreasing
+ 'decoderX.Y/id' order.
+
+
+What: /sys/bus/cxl/devices/decoderX.Y/interleave_ways
+Date: May, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RO) The number of targets across which this decoder's host
+ physical address (HPA) memory range is interleaved. The device
+ maps every Nth block of HPA (of size ==
+ 'interleave_granularity') to consecutive DPA addresses. The
+ decoder's position in the interleave is determined by the
+ device's (endpoint or switch) switch ancestry. For root
+ decoders their interleave is specified by platform firmware and
+ they only specify a downstream target order for host bridges.
+
+
+What: /sys/bus/cxl/devices/decoderX.Y/interleave_granularity
+Date: May, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RO) The number of consecutive bytes of host physical address
+ space this decoder claims at address N before the decode rotates
+ to the next target in the interleave at address N +
+ interleave_granularity (assuming N is aligned to
+ interleave_granularity).
+
+
+What: /sys/bus/cxl/devices/decoderX.Y/create_pmem_region
+Date: May, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RW) Write a string in the form 'regionZ' to start the process
+ of defining a new persistent memory region (interleave-set)
+ within the decode range bounded by root decoder 'decoderX.Y'.
+ The value written must match the current value returned from
+ reading this attribute. An atomic compare exchange operation is
+ done on write to assign the requested id to a region and
+ allocate the region-id for the next creation attempt. EBUSY is
+ returned if the region name written does not match the current
+ cached value.
+
+
+What: /sys/bus/cxl/devices/decoderX.Y/delete_region
+Date: May, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (WO) Write a string in the form 'regionZ' to delete that region,
+ provided it is currently idle / not bound to a driver.
+
+
+What: /sys/bus/cxl/devices/regionZ/uuid
+Date: May, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RW) Write a unique identifier for the region. This field must
+ be set for persistent regions and it must not conflict with the
+ UUID of another region.
+
+
+What: /sys/bus/cxl/devices/regionZ/interleave_granularity
+Date: May, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RW) Set the number of consecutive bytes each device in the
+ interleave set will claim. The possible interleave granularity
+ values are determined by the CXL spec and the participating
+ devices.
+
+
+What: /sys/bus/cxl/devices/regionZ/interleave_ways
+Date: May, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RW) Configures the number of devices participating in the
+ region is set by writing this value. Each device will provide
+ 1/interleave_ways of storage for the region.
+
+
+What: /sys/bus/cxl/devices/regionZ/size
+Date: May, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RW) System physical address space to be consumed by the region.
+ When written trigger the driver to allocate space out of the
+ parent root decoder's address space. When read the size of the
+ address space is reported and should match the span of the
+ region's resource attribute. Size shall be set after the
+ interleave configuration parameters. Once set it cannot be
+ changed, only freed by writing 0. The kernel makes no guarantees
+ that data is maintained over an address space freeing event, and
+ there is no guarantee that a free followed by an allocate
+ results in the same address being allocated.
+
+
+What: /sys/bus/cxl/devices/regionZ/resource
+Date: May, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RO) A region is a contiguous partition of a CXL root decoder
+ address space. Region capacity is allocated by writing to the
+ size attribute, the resulting physical address space determined
+ by the driver is reflected here. It is therefore not useful to
+ read this before writing a value to the size attribute.
+
+
+What: /sys/bus/cxl/devices/regionZ/target[0..N]
+Date: May, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RW) Write an endpoint decoder object name to 'targetX' where X
+ is the intended position of the endpoint device in the region
+ interleave and N is the 'interleave_ways' setting for the
+ region. ENXIO is returned if the write results in an impossible
+ to map decode scenario, like the endpoint is unreachable at that
+ position relative to the root decoder interleave. EBUSY is
+ returned if the position in the region is already occupied, or
+ if the region is not in a state to accept interleave
+ configuration changes. EINVAL is returned if the object name is
+ not an endpoint decoder. Once all positions have been
+ successfully written a final validation for decode conflicts is
+ performed before activating the region.
+
+
+What: /sys/bus/cxl/devices/regionZ/commit
+Date: May, 2022
+KernelVersion: v5.20
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RW) Write a boolean 'true' string value to this attribute to
+ trigger the region to transition from the software programmed
+ state to the actively decoding in hardware state. The commit
+ operation in addition to validating that the region is in proper
+ configured state, validates that the decoders are being
+ committed in spec mandated order (last committed decoder id +
+ 1), and checks that the hardware accepts the commit request.
+ Reading this value indicates whether the region is committed or
+ not.
'RSB filling' Protection of RSB on context switch enabled
============= ===========================================
+ - EIBRS Post-barrier Return Stack Buffer (PBRSB) protection status:
+
+ =========================== =======================================================
+ 'PBRSB-eIBRS: SW sequence' CPU is affected and protection of RSB on VMEXIT enabled
+ 'PBRSB-eIBRS: Vulnerable' CPU is vulnerable
+ 'PBRSB-eIBRS: Not affected' CPU is not affected by PBRSB
+ =========================== =======================================================
+
Full mitigation might require a microcode update from the CPU
vendor. When the necessary microcode is not available, the kernel will
report vulnerability.
nopku [X86] Disable Memory Protection Keys CPU feature found
in some Intel CPUs.
- <module>.async_probe [KNL]
- Enable asynchronous probe on this module.
+ <module>.async_probe[=<bool>] [KNL]
+ If no <bool> value is specified or if the value
+ specified is not a valid <bool>, enable asynchronous
+ probe on this module. Otherwise, enable/disable
+ asynchronous probe on this module as indicated by the
+ <bool> value. See also: module.async_probe
early_ioremap_debug [KNL]
Enable debug messages in early_ioremap support. This
For details see:
Documentation/admin-guide/hw-vuln/processor_mmio_stale_data.rst
+ module.async_probe=<bool>
+ [KNL] When set to true, modules will use async probing
+ by default. To enable/disable async probing for a
+ specific module, use the module specific control that
+ is documented under <module>.async_probe. When both
+ module.async_probe and <module>.async_probe are
+ specified, <module>.async_probe takes precedence for
+ the specific module.
+
module.sig_enforce
[KNL] When CONFIG_MODULE_SIG is set, this means that
modules without (valid) signatures will fail to load.
- description: v2 of CPUFREQ HW (EPSS)
items:
- enum:
+ - qcom,sm6375-cpufreq-epss
- qcom,sm8250-cpufreq-epss
- const: qcom,cpufreq-epss
compatible:
contains:
enum:
+ - qcom,apq8064
+ - qcom,apq8096
+ - qcom,ipq8064
+ - qcom,msm8939
+ - qcom,msm8960
+ - qcom,msm8974
+ - qcom,msm8996
- qcom,qcs404
required:
- compatible
oneOf:
- enum:
- x-powers,axp209-gpio
+ - x-powers,axp221-gpio
- x-powers,axp813-gpio
+ - items:
+ - enum:
+ - x-powers,axp223-gpio
+ - x-powers,axp809-gpio
+ - const: x-powers,axp221-gpio
- items:
- const: x-powers,axp803-gpio
- const: x-powers,axp813-gpio
property to uniquely identify the OPP nodes exists. Devices like power
domains must have another (implementation dependent) property.
+ Entries for multiple clocks shall be provided in the same field, as
+ array of frequencies. The OPP binding doesn't provide any provisions
+ to relate the values to their clocks or the order in which the clocks
+ need to be configured and that is left for the implementation
+ specific binding.
+ minItems: 1
+ maxItems: 16
+ items:
+ maxItems: 1
+
opp-microvolt:
description: |
Voltage for the OPP
capacity-dmips-mhz = <1024>;
clocks = <&kryocc 0>;
operating-points-v2 = <&cluster0_opp>;
+ power-domains = <&cpr>;
+ power-domain-names = "cpr";
#cooling-cells = <2>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
capacity-dmips-mhz = <1024>;
clocks = <&kryocc 0>;
operating-points-v2 = <&cluster0_opp>;
+ power-domains = <&cpr>;
+ power-domain-names = "cpr";
#cooling-cells = <2>;
next-level-cache = <&L2_0>;
};
capacity-dmips-mhz = <1024>;
clocks = <&kryocc 1>;
operating-points-v2 = <&cluster1_opp>;
+ power-domains = <&cpr>;
+ power-domain-names = "cpr";
#cooling-cells = <2>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
capacity-dmips-mhz = <1024>;
clocks = <&kryocc 1>;
operating-points-v2 = <&cluster1_opp>;
+ power-domains = <&cpr>;
+ power-domain-names = "cpr";
#cooling-cells = <2>;
next-level-cache = <&L2_1>;
};
opp-microvolt = <905000 905000 1140000>;
opp-supported-hw = <0x7>;
clock-latency-ns = <200000>;
+ required-opps = <&cpr_opp1>;
};
opp-1401600000 {
opp-hz = /bits/ 64 <1401600000>;
opp-microvolt = <1140000 905000 1140000>;
opp-supported-hw = <0x5>;
clock-latency-ns = <200000>;
+ required-opps = <&cpr_opp2>;
};
opp-1593600000 {
opp-hz = /bits/ 64 <1593600000>;
opp-microvolt = <1140000 905000 1140000>;
opp-supported-hw = <0x1>;
clock-latency-ns = <200000>;
+ required-opps = <&cpr_opp3>;
};
};
opp-microvolt = <905000 905000 1140000>;
opp-supported-hw = <0x7>;
clock-latency-ns = <200000>;
+ required-opps = <&cpr_opp1>;
};
opp-1804800000 {
opp-hz = /bits/ 64 <1804800000>;
opp-microvolt = <1140000 905000 1140000>;
opp-supported-hw = <0x6>;
clock-latency-ns = <200000>;
+ required-opps = <&cpr_opp4>;
};
opp-1900800000 {
opp-hz = /bits/ 64 <1900800000>;
opp-microvolt = <1140000 905000 1140000>;
opp-supported-hw = <0x4>;
clock-latency-ns = <200000>;
+ required-opps = <&cpr_opp5>;
};
opp-2150400000 {
opp-hz = /bits/ 64 <2150400000>;
opp-microvolt = <1140000 905000 1140000>;
opp-supported-hw = <0x1>;
clock-latency-ns = <200000>;
+ required-opps = <&cpr_opp6>;
};
};
- allwinner,sun8i-v3s-pinctrl
- allwinner,sun9i-a80-pinctrl
- allwinner,sun9i-a80-r-pinctrl
+ - allwinner,sun20i-d1-pinctrl
- allwinner,sun50i-a64-pinctrl
- allwinner,sun50i-a64-r-pinctrl
- allwinner,sun50i-a100-pinctrl
- const: hosc
- const: losc
- resets:
- maxItems: 1
-
gpio-controller: true
interrupt-controller: true
gpio-line-names: true
minItems: 7
maxItems: 7
+ - if:
+ properties:
+ compatible:
+ enum:
+ - allwinner,sun20i-d1-pinctrl
+
+ then:
+ properties:
+ interrupts:
+ minItems: 6
+ maxItems: 6
+
- if:
properties:
compatible:
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uid>, <&pinmux_uid>;
- uid {
+ button-uid {
label = "UID";
linux,code = <102>;
gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
gpio-ranges:
maxItems: 1
+ gpio-line-names: true
+
reg:
description: |
Physical address base for gpio base registers. There are 8 different GPIO
drive-strength:
enum: [2, 4, 6, 8, 10, 12, 14, 16]
- mediatek,drive-strength-adv:
- description: |
- Describe the specific driving setup property.
- For I2C pins, the existing generic driving setup can only support
- 2/4/6/8/10/12/14/16mA driving. But in specific driving setup, they
- can support 0.125/0.25/0.5/1mA adjustment. If we enable specific
- driving setup, the existing generic setup will be disabled.
- The specific driving setup is controlled by E1E0EN.
- When E1=0/E0=0, the strength is 0.125mA.
- When E1=0/E0=1, the strength is 0.25mA.
- When E1=1/E0=0, the strength is 0.5mA.
- When E1=1/E0=1, the strength is 1mA.
- EN is used to enable or disable the specific driving setup.
- Valid arguments are described as below:
- 0: (E1, E0, EN) = (0, 0, 0)
- 1: (E1, E0, EN) = (0, 0, 1)
- 2: (E1, E0, EN) = (0, 1, 0)
- 3: (E1, E0, EN) = (0, 1, 1)
- 4: (E1, E0, EN) = (1, 0, 0)
- 5: (E1, E0, EN) = (1, 0, 1)
- 6: (E1, E0, EN) = (1, 1, 0)
- 7: (E1, E0, EN) = (1, 1, 1)
- So the valid arguments are from 0 to 7.
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2, 3, 4, 5, 6, 7]
+ drive-strength-microamp:
+ enum: [125, 250, 500, 1000]
bias-pull-down:
oneOf:
pinmux = <PINMUX_GPIO127__FUNC_SCL0>,
<PINMUX_GPIO128__FUNC_SDA0>;
bias-pull-up = <MTK_PULL_SET_RSEL_001>;
- mediatek,drive-strength-adv = <7>;
+ drive-strength-microamp = <1000>;
};
};
};
dt-bindings/pinctrl/mt65xx.h. It can only support 2/4/6/8/10/12/14/16mA in mt8192.
enum: [2, 4, 6, 8, 10, 12, 14, 16]
- mediatek,drive-strength-adv:
- description: |
- Describe the specific driving setup property.
- For I2C pins, the existing generic driving setup can only support
- 2/4/6/8/10/12/14/16mA driving. But in specific driving setup, they
- can support 0.125/0.25/0.5/1mA adjustment. If we enable specific
- driving setup, the existing generic setup will be disabled.
- The specific driving setup is controlled by E1E0EN.
- When E1=0/E0=0, the strength is 0.125mA.
- When E1=0/E0=1, the strength is 0.25mA.
- When E1=1/E0=0, the strength is 0.5mA.
- When E1=1/E0=1, the strength is 1mA.
- EN is used to enable or disable the specific driving setup.
- Valid arguments are described as below:
- 0: (E1, E0, EN) = (0, 0, 0)
- 1: (E1, E0, EN) = (0, 0, 1)
- 2: (E1, E0, EN) = (0, 1, 0)
- 3: (E1, E0, EN) = (0, 1, 1)
- 4: (E1, E0, EN) = (1, 0, 0)
- 5: (E1, E0, EN) = (1, 0, 1)
- 6: (E1, E0, EN) = (1, 1, 0)
- 7: (E1, E0, EN) = (1, 1, 1)
- So the valid arguments are from 0 to 7.
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2, 3, 4, 5, 6, 7]
-
- mediatek,pull-up-adv:
- description: |
- Pull up settings for 2 pull resistors, R0 and R1. User can
- configure those special pins. Valid arguments are described as below:
- 0: (R1, R0) = (0, 0) which means R1 disabled and R0 disabled.
- 1: (R1, R0) = (0, 1) which means R1 disabled and R0 enabled.
- 2: (R1, R0) = (1, 0) which means R1 enabled and R0 disabled.
- 3: (R1, R0) = (1, 1) which means R1 enabled and R0 enabled.
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2, 3]
-
- bias-pull-down: true
-
- bias-pull-up: true
+ drive-strength-microamp:
+ enum: [125, 250, 500, 1000]
+
+ bias-pull-down:
+ oneOf:
+ - type: boolean
+ description: normal pull down.
+ - enum: [100, 101, 102, 103]
+ description: PUPD/R1/R0 pull down type. See MTK_PUPD_SET_R1R0_
+ defines in dt-bindings/pinctrl/mt65xx.h.
+ - enum: [200, 201, 202, 203]
+ description: RSEL pull down type. See MTK_PULL_SET_RSEL_
+ defines in dt-bindings/pinctrl/mt65xx.h.
+
+ bias-pull-up:
+ oneOf:
+ - type: boolean
+ description: normal pull up.
+ - enum: [100, 101, 102, 103]
+ description: PUPD/R1/R0 pull up type. See MTK_PUPD_SET_R1R0_
+ defines in dt-bindings/pinctrl/mt65xx.h.
+ - enum: [200, 201, 202, 203]
+ description: RSEL pull up type. See MTK_PULL_SET_RSEL_
+ defines in dt-bindings/pinctrl/mt65xx.h.
bias-disable: true
description: gpio valid number range.
maxItems: 1
+ gpio-line-names: true
+
reg:
description: |
Physical address base for gpio base registers. There are 8 GPIO
description: The interrupt outputs to sysirq.
maxItems: 1
- mediatek,rsel_resistance_in_si_unit:
+ mediatek,rsel-resistance-in-si-unit:
type: boolean
description: |
Identifying i2c pins pull up/down type which is RSEL. It can support
drive-strength:
enum: [2, 4, 6, 8, 10, 12, 14, 16]
- mediatek,drive-strength-adv:
- description: |
- Describe the specific driving setup property.
- For I2C pins, the existing generic driving setup can only support
- 2/4/6/8/10/12/14/16mA driving. But in specific driving setup, they
- can support 0.125/0.25/0.5/1mA adjustment. If we enable specific
- driving setup, the existing generic setup will be disabled.
- The specific driving setup is controlled by E1E0EN.
- When E1=0/E0=0, the strength is 0.125mA.
- When E1=0/E0=1, the strength is 0.25mA.
- When E1=1/E0=0, the strength is 0.5mA.
- When E1=1/E0=1, the strength is 1mA.
- EN is used to enable or disable the specific driving setup.
- Valid arguments are described as below:
- 0: (E1, E0, EN) = (0, 0, 0)
- 1: (E1, E0, EN) = (0, 0, 1)
- 2: (E1, E0, EN) = (0, 1, 0)
- 3: (E1, E0, EN) = (0, 1, 1)
- 4: (E1, E0, EN) = (1, 0, 0)
- 5: (E1, E0, EN) = (1, 0, 1)
- 6: (E1, E0, EN) = (1, 1, 0)
- 7: (E1, E0, EN) = (1, 1, 1)
- So the valid arguments are from 0 to 7.
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2, 3, 4, 5, 6, 7]
+ drive-strength-microamp:
+ enum: [125, 250, 500, 1000]
bias-pull-down:
oneOf:
"MTK_PUPD_SET_R1R0_11" define in mt8195.
For pull down type is RSEL, it can add RSEL define & resistance
value(ohm) to set different resistance by identifying property
- "mediatek,rsel_resistance_in_si_unit".
+ "mediatek,rsel-resistance-in-si-unit".
It can support "MTK_PULL_SET_RSEL_000" & "MTK_PULL_SET_RSEL_001"
& "MTK_PULL_SET_RSEL_010" & "MTK_PULL_SET_RSEL_011"
& "MTK_PULL_SET_RSEL_100" & "MTK_PULL_SET_RSEL_101"
};
An example of using si unit resistance value(ohm):
&pio {
- mediatek,rsel_resistance_in_si_unit;
+ mediatek,rsel-resistance-in-si-unit;
}
pincontroller {
i2c0_pin {
"MTK_PUPD_SET_R1R0_11" define in mt8195.
For pull up type is RSEL, it can add RSEL define & resistance
value(ohm) to set different resistance by identifying property
- "mediatek,rsel_resistance_in_si_unit".
+ "mediatek,rsel-resistance-in-si-unit".
It can support "MTK_PULL_SET_RSEL_000" & "MTK_PULL_SET_RSEL_001"
& "MTK_PULL_SET_RSEL_010" & "MTK_PULL_SET_RSEL_011"
& "MTK_PULL_SET_RSEL_100" & "MTK_PULL_SET_RSEL_101"
};
An example of using si unit resistance value(ohm):
&pio {
- mediatek,rsel_resistance_in_si_unit;
+ mediatek,rsel-resistance-in-si-unit;
}
pincontroller {
i2c0-pins {
pinmux = <PINMUX_GPIO8__FUNC_SDA0>,
<PINMUX_GPIO9__FUNC_SCL0>;
bias-disable;
- mediatek,drive-strength-adv = <7>;
+ drive-strength-microamp = <1000>;
};
};
};
--- /dev/null
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/qcom,msm8909-tlmm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Technologies, Inc. MSM8909 TLMM block
+
+maintainers:
+ - Stephan Gerhold <stephan@gerhold.net>
+
+description: |
+ This binding describes the Top Level Mode Multiplexer (TLMM) block found
+ in the MSM8909 platform.
+
+allOf:
+ - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml#
+
+properties:
+ compatible:
+ const: qcom,msm8909-tlmm
+
+ reg:
+ maxItems: 1
+
+ interrupts: true
+ interrupt-controller: true
+ '#interrupt-cells': true
+ gpio-controller: true
+ gpio-reserved-ranges: true
+ '#gpio-cells': true
+ gpio-ranges: true
+ wakeup-parent: true
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+patternProperties:
+ '-state$':
+ oneOf:
+ - $ref: "#/$defs/qcom-msm8909-tlmm-state"
+ - patternProperties:
+ ".*":
+ $ref: "#/$defs/qcom-msm8909-tlmm-state"
+
+$defs:
+ qcom-msm8909-tlmm-state:
+ type: object
+ description:
+ Pinctrl node's client devices use subnodes for desired pin configuration.
+ Client device subnodes use below standard properties.
+ $ref: "qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state"
+
+ properties:
+ pins:
+ description:
+ List of gpio pins affected by the properties specified in this
+ subnode.
+ items:
+ oneOf:
+ - pattern: "^gpio([0-9]|[1-9][0-9]|10[0-9]|11[0-7])$"
+ - enum: [ sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk, sdc2_cmd,
+ sdc2_data, qdsd_clk, qdsd_cmd, qdsd_data0, qdsd_data1,
+ qdsd_data2, qdsd_data3 ]
+ minItems: 1
+ maxItems: 16
+
+ function:
+ description:
+ Specify the alternative function to be configured for the specified
+ pins.
+ enum: [ adsp_ext, atest_bbrx0, atest_bbrx1, atest_char, atest_char0,
+ atest_char1, atest_char2, atest_char3, atest_combodac,
+ atest_gpsadc0, atest_gpsadc1, atest_wlan0, atest_wlan1,
+ bimc_dte0, bimc_dte1, blsp_i2c1, blsp_i2c2, blsp_i2c3,
+ blsp_i2c4, blsp_i2c5, blsp_i2c6, blsp_spi1, blsp_spi1_cs1,
+ blsp_spi1_cs2, blsp_spi1_cs3, blsp_spi2, blsp_spi2_cs1,
+ blsp_spi2_cs2, blsp_spi2_cs3, blsp_spi3, blsp_spi3_cs1,
+ blsp_spi3_cs2, blsp_spi3_cs3, blsp_spi4, blsp_spi5, blsp_spi6,
+ blsp_uart1, blsp_uart2, blsp_uim1, blsp_uim2, cam_mclk,
+ cci_async, cci_timer0, cci_timer1, cci_timer2, cdc_pdm0,
+ dbg_out, dmic0_clk, dmic0_data, ebi0_wrcdc, ebi2_a, ebi2_lcd,
+ ext_lpass, gcc_gp1_clk_a, gcc_gp1_clk_b, gcc_gp2_clk_a,
+ gcc_gp2_clk_b, gcc_gp3_clk_a, gcc_gp3_clk_b, gcc_plltest, gpio,
+ gsm0_tx, ldo_en, ldo_update, m_voc, mdp_vsync, modem_tsync,
+ nav_pps, nav_tsync, pa_indicator, pbs0, pbs1, pbs2,
+ pri_mi2s_data0_a, pri_mi2s_data0_b, pri_mi2s_data1_a,
+ pri_mi2s_data1_b, pri_mi2s_mclk_a, pri_mi2s_mclk_b,
+ pri_mi2s_sck_a, pri_mi2s_sck_b, pri_mi2s_ws_a, pri_mi2s_ws_b,
+ prng_rosc, pwr_crypto_enabled_a, pwr_crypto_enabled_b,
+ pwr_modem_enabled_a, pwr_modem_enabled_b, pwr_nav_enabled_a,
+ pwr_nav_enabled_b, qdss_cti_trig_in_a0, qdss_cti_trig_in_a1,
+ qdss_cti_trig_in_b0, qdss_cti_trig_in_b1, qdss_cti_trig_out_a0,
+ qdss_cti_trig_out_a1, qdss_cti_trig_out_b0,
+ qdss_cti_trig_out_b1, qdss_traceclk_a, qdss_tracectl_a,
+ qdss_tracedata_a, qdss_tracedata_b, sd_write, sec_mi2s,
+ smb_int, ssbi0, ssbi1, uim1_clk, uim1_data, uim1_present,
+ uim1_reset, uim2_clk, uim2_data, uim2_present, uim2_reset,
+ uim3_clk, uim3_data, uim3_present, uim3_reset, uim_batt,
+ wcss_bt, wcss_fm, wcss_wlan ]
+
+ bias-disable: true
+ bias-pull-down: true
+ bias-pull-up: true
+ drive-strength: true
+ input-enable: true
+ output-high: true
+ output-low: true
+
+ required:
+ - pins
+ - function
+
+ additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ pinctrl@1000000 {
+ compatible = "qcom,msm8909-tlmm";
+ reg = <0x1000000 0x300000>;
+ interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&tlmm 0 0 117>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ gpio-wo-subnode-state {
+ pins = "gpio1";
+ function = "gpio";
+ };
+
+ uart-w-subnodes-state {
+ rx {
+ pins = "gpio4";
+ function = "blsp_uart1";
+ bias-pull-up;
+ };
+
+ tx {
+ pins = "gpio5";
+ function = "blsp_uart1";
+ bias-disable;
+ };
+ };
+ };
+...
- qcom,pmi8998-gpio
- qcom,pmk8350-gpio
- qcom,pmm8155au-gpio
+ - qcom,pmp8074-gpio
- qcom,pmr735a-gpio
- qcom,pmr735b-gpio
- qcom,pms405-gpio
compatible:
contains:
enum:
+ - qcom,pm8226-gpio
- qcom,pm8350b-gpio
- qcom,pm8950-gpio
then:
- qcom,pm8150b-gpio
- qcom,pm8150l-gpio
- qcom,pmc8180c-gpio
+ - qcom,pmp8074-gpio
- qcom,pms405-gpio
then:
properties:
- gpio1-gpio10 for pmi8994
- gpio1-gpio4 for pmk8350
- gpio1-gpio10 for pmm8155au
+ - gpio1-gpio12 for pmp8074 (holes on gpio1 and gpio12)
- gpio1-gpio4 for pmr735a
- gpio1-gpio4 for pmr735b
- gpio1-gpio12 for pms405 (holes on gpio1, gpio9
compatible:
const: qcom,sc7280-lpass-lpi-pinctrl
+ qcom,adsp-bypass-mode:
+ description:
+ Tells ADSP is in bypass mode.
+ type: boolean
+
reg:
minItems: 2
maxItems: 2
--- /dev/null
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/qcom,sm6375-tlmm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Technologies, Inc. SM6375 TLMM block
+
+maintainers:
+ - Konrad Dybcio <konrad.dybcio@somainline.org>
+
+description: |
+ This binding describes the Top Level Mode Multiplexer (TLMM) block found
+ in the SM6375 platform.
+
+allOf:
+ - $ref: "pinctrl.yaml#"
+ - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml#
+
+properties:
+ compatible:
+ const: qcom,sm6375-tlmm
+
+ reg:
+ maxItems: 1
+
+ interrupts: true
+ interrupt-controller: true
+ '#interrupt-cells': true
+ gpio-controller: true
+ gpio-reserved-ranges: true
+ '#gpio-cells': true
+ gpio-ranges: true
+ wakeup-parent: true
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+patternProperties:
+ '-state$':
+ oneOf:
+ - $ref: "#/$defs/qcom-sm6375-tlmm-state"
+ - patternProperties:
+ ".*":
+ $ref: "#/$defs/qcom-sm6375-tlmm-state"
+
+$defs:
+ qcom-sm6375-tlmm-state:
+ type: object
+ description:
+ Pinctrl node's client devices use subnodes for desired pin configuration.
+ Client device subnodes use below standard properties.
+ $ref: "qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state"
+
+ properties:
+ pins:
+ description:
+ List of gpio pins affected by the properties specified in this
+ subnode.
+ items:
+ oneOf:
+ - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-4][0-9]|15[0-6])$"
+ - enum: [ ufs_reset, sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk,
+ sdc2_cmd, sdc2_data ]
+ minItems: 1
+ maxItems: 36
+
+ function:
+ description:
+ Specify the alternative function to be configured for the specified
+ pins.
+
+ enum: [ adsp_ext, agera_pll, atest_char, atest_char0, atest_char1,
+ atest_char2, atest_char3, atest_tsens, atest_tsens2,
+ atest_usb1, atest_usb10, atest_usb11, atest_usb12,
+ atest_usb13, atest_usb2, atest_usb20, atest_usb21,
+ atest_usb22, atest_usb23, audio_ref, btfm_slimbus, cam_mclk,
+ cci_async, cci_i2c, cci_timer0, cci_timer1, cci_timer2,
+ cci_timer3, cci_timer4, cri_trng, dbg_out, ddr_bist,
+ ddr_pxi0, ddr_pxi1, ddr_pxi2, ddr_pxi3, dp_hot, edp_lcd,
+ gcc_gp1, gcc_gp2, gcc_gp3, gp_pdm0, gp_pdm1, gp_pdm2, gpio,
+ gps_tx, ibi_i3c, jitter_bist, ldo_en, ldo_update, lpass_ext,
+ m_voc, mclk, mdp_vsync, mdp_vsync0, mdp_vsync1, mdp_vsync2,
+ mdp_vsync3, mi2s_0, mi2s_1, mi2s_2, mss_lte, nav_gpio,
+ nav_pps, pa_indicator, phase_flag0, phase_flag1, phase_flag10,
+ phase_flag11, phase_flag12, phase_flag13, phase_flag14,
+ phase_flag15, phase_flag16, phase_flag17, phase_flag18,
+ phase_flag19, phase_flag2, phase_flag20, phase_flag21,
+ phase_flag22, phase_flag23, phase_flag24, phase_flag25,
+ phase_flag26, phase_flag27, phase_flag28, phase_flag29,
+ phase_flag3, phase_flag30, phase_flag31, phase_flag4,
+ phase_flag5, phase_flag6, phase_flag7, phase_flag8,
+ phase_flag9, pll_bist, pll_bypassnl, pll_clk, pll_reset,
+ prng_rosc0, prng_rosc1, prng_rosc2, prng_rosc3, qdss_cti,
+ qdss_gpio, qdss_gpio0, qdss_gpio1, qdss_gpio10, qdss_gpio11,
+ qdss_gpio12, qdss_gpio13, qdss_gpio14, qdss_gpio15,
+ qdss_gpio2, qdss_gpio3, qdss_gpio4, qdss_gpio5, qdss_gpio6,
+ qdss_gpio7, qdss_gpio8, qdss_gpio9, qlink0_enable,
+ qlink0_request, qlink0_wmss, qlink1_enable, qlink1_request,
+ qlink1_wmss, qup00, qup01, qup02, qup10, qup11_f1, qup11_f2,
+ qup12, qup13_f1, qup13_f2, qup14, sd_write, sdc1_tb, sdc2_tb,
+ sp_cmu, tgu_ch0, tgu_ch1, tgu_ch2, tgu_ch3, tsense_pwm1,
+ tsense_pwm2, uim1_clk, uim1_data, uim1_present, uim1_reset,
+ uim2_clk, uim2_data, uim2_present, uim2_reset, usb2phy_ac,
+ usb_phy, vfr_1, vsense_trigger, wlan1_adc0, wlan1_adc1,
+ wlan2_adc0, wlan2_adc1 ]
+
+
+ bias-disable: true
+ bias-pull-down: true
+ bias-pull-up: true
+ drive-strength: true
+ input-enable: true
+ output-high: true
+ output-low: true
+
+ required:
+ - pins
+ - function
+
+ additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ pinctrl@500000 {
+ compatible = "qcom,sm6375-tlmm";
+ reg = <0x00500000 0x800000>;
+ interrupts = <GIC_SPI 227 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ gpio-ranges = <&tlmm 0 0 157>;
+
+ gpio-wo-subnode-state {
+ pins = "gpio1";
+ function = "gpio";
+ };
+
+ uart-w-subnodes-state {
+ rx {
+ pins = "gpio18";
+ function = "qup13_f2";
+ bias-pull-up;
+ };
+
+ tx {
+ pins = "gpio19";
+ function = "qup13_f2";
+ bias-disable;
+ };
+ };
+ };
+...
- renesas,pfc-r8a77995 # R-Car D3
- renesas,pfc-r8a779a0 # R-Car V3U
- renesas,pfc-r8a779f0 # R-Car S4-8
+ - renesas,pfc-r8a779g0 # R-Car V4H
- renesas,pfc-sh73a0 # SH-Mobile AG5
reg:
--- /dev/null
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/renesas,rzv2m-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/V2M combined Pin and GPIO controller
+
+maintainers:
+ - Geert Uytterhoeven <geert+renesas@glider.be>
+ - Phil Edworthy <phil.edworthy@renesas.com>
+
+description:
+ The Renesas RZ/V2M SoC features a combined Pin and GPIO controller.
+ Pin multiplexing and GPIO configuration is performed on a per-pin basis.
+ Each port features up to 16 pins, each of them configurable for GPIO function
+ (port mode) or in alternate function mode.
+ Up to 8 different alternate function modes exist for each single pin.
+
+properties:
+ compatible:
+ const: renesas,r9a09g011-pinctrl # RZ/V2M
+
+ reg:
+ maxItems: 1
+
+ gpio-controller: true
+
+ '#gpio-cells':
+ const: 2
+ description:
+ The first cell contains the global GPIO port index, constructed using the
+ RZV2M_GPIO() helper macro in <dt-bindings/pinctrl/rzv2m-pinctrl.h> and the
+ second cell represents consumer flag as mentioned in ../gpio/gpio.txt
+ E.g. "RZV2M_GPIO(8, 1)" for P8_1.
+
+ gpio-ranges:
+ maxItems: 1
+
+ interrupts:
+ description: INEXINT[0..38] corresponding to individual pin inputs.
+ maxItems: 39
+
+ clocks:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+additionalProperties:
+ anyOf:
+ - type: object
+ allOf:
+ - $ref: pincfg-node.yaml#
+ - $ref: pinmux-node.yaml#
+
+ description:
+ Pin controller client devices use pin configuration subnodes (children
+ and grandchildren) for desired pin configuration.
+ Client device subnodes use below standard properties.
+
+ properties:
+ phandle: true
+ pinmux:
+ description:
+ Values are constructed from GPIO port number, pin number, and
+ alternate function configuration number using the RZV2M_PORT_PINMUX()
+ helper macro in <dt-bindings/pinctrl/rzv2m-pinctrl.h>.
+ pins: true
+ bias-disable: true
+ bias-pull-down: true
+ bias-pull-up: true
+ drive-strength-microamp:
+ # Superset of supported values
+ enum: [ 1600, 1800, 2000, 3200, 3800, 4000, 6400, 7800, 8000,
+ 9000, 9600, 11000, 12000, 13000, 18000 ]
+ slew-rate:
+ description: 0 is slow slew rate, 1 is fast slew rate
+ enum: [ 0, 1 ]
+ gpio-hog: true
+ gpios: true
+ output-high: true
+ output-low: true
+ line-name: true
+
+ - type: object
+ properties:
+ phandle: true
+
+ additionalProperties:
+ $ref: "#/additionalProperties/anyOf/0"
+
+allOf:
+ - $ref: "pinctrl.yaml#"
+
+required:
+ - compatible
+ - reg
+ - gpio-controller
+ - '#gpio-cells'
+ - gpio-ranges
+ - interrupts
+ - clocks
+ - power-domains
+ - resets
+
+examples:
+ - |
+ #include <dt-bindings/pinctrl/rzv2m-pinctrl.h>
+ #include <dt-bindings/clock/r9a09g011-cpg.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ pinctrl: pinctrl@b6250000 {
+ compatible = "renesas,r9a09g011-pinctrl";
+ reg = <0xb6250000 0x800>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinctrl 0 0 352>;
+ interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD R9A09G011_PFC_PCLK>;
+ resets = <&cpg R9A09G011_PFC_PRESETN>;
+ power-domains = <&cpg>;
+
+ i2c2_pins: i2c2 {
+ pinmux = <RZV2M_PORT_PINMUX(3, 8, 2)>, /* SDA */
+ <RZV2M_PORT_PINMUX(3, 9, 2)>; /* SCL */
+ };
+ };
patternProperties:
'^gpio@[0-9a-f]*$':
type: object
+ additionalProperties: false
properties:
gpio-controller: true
'#gpio-cells':
maxItems: 1
clocks:
maxItems: 1
- reset:
- minItems: 1
+ resets:
maxItems: 1
gpio-ranges:
minItems: 1
additionalProperties: false
+allOf:
+ - $ref: "pinctrl.yaml#"
+
examples:
- |
#include <dt-bindings/pinctrl/sppctl-sp7021.h>
- pinctl@9c000100 {
+ pinctrl@9c000100 {
compatible = "sunplus,sp7021-pctl";
reg = <0x9c000100 0x100>, <0x9c000300 0x100>,
<0x9c0032e4 0x1c>, <0x9c000080 0x20>;
slew-rate:
enum: [0, 1]
+ output-enable:
+ description:
+ This will internally disable the tri-state for MIO pins.
+
drive-strength:
description:
Selects the drive strength for MIO pins, in mA.
enum:
- mediatek,mt8183-scp
- mediatek,mt8186-scp
+ - mediatek,mt8188-scp
- mediatek,mt8192-scp
- mediatek,mt8195-scp
enum:
- mediatek,mt8183-scp
- mediatek,mt8186-scp
+ - mediatek,mt8188-scp
then:
properties:
reg:
minItems: 1
maxItems: 8
+ interconnects:
+ maxItems: 1
+
interrupts:
minItems: 5
- maxItems: 6
+ items:
+ - description: Watchdog interrupt
+ - description: Fatal interrupt
+ - description: Ready interrupt
+ - description: Handover interrupt
+ - description: Stop acknowledge interrupt
+ - description: Shutdown acknowledge interrupt
interrupt-names:
minItems: 5
- maxItems: 6
+ items:
+ - const: wdog
+ - const: fatal
+ - const: ready
+ - const: handover
+ - const: stop-ack
+ - const: shutdown-ack
resets:
minItems: 1
- description: Stop the modem
qcom,smem-state-names:
- $ref: /schemas/types.yaml#/definitions/string-array
description: The names of the state bits used for SMP2P output
items:
- const: stop
three offsets within syscon for q6, modem and nc halt registers.
smd-edge:
- type: object
+ $ref: /schemas/remoteproc/qcom,smd-edge.yaml#
description:
Qualcomm Shared Memory subnode which represents communication edge,
channels and devices related to the ADSP.
glink-edge:
- type: object
+ $ref: /schemas/remoteproc/qcom,glink-edge.yaml#
description:
Qualcomm G-Link subnode which represents communication edge, channels
and devices related to the ADSP.
then:
properties:
interrupts:
- items:
- - description: Watchdog interrupt
- - description: Fatal interrupt
- - description: Ready interrupt
- - description: Handover interrupt
- - description: Stop acknowledge interrupt
+ maxItems: 5
interrupt-names:
- items:
- - const: wdog
- - const: fatal
- - const: ready
- - const: handover
- - const: stop-ack
+ maxItems: 5
- if:
properties:
then:
properties:
interrupts:
- items:
- - description: Watchdog interrupt
- - description: Fatal interrupt
- - description: Ready interrupt
- - description: Handover interrupt
- - description: Stop acknowledge interrupt
- - description: Shutdown acknowledge interrupt
+ minItems: 6
interrupt-names:
- items:
- - const: wdog
- - const: fatal
- - const: ready
- - const: handover
- - const: stop-ack
- - const: shutdown-ack
+ minItems: 6
- if:
properties:
- qcom,msm8226-adsp-pil
- qcom,msm8996-adsp-pil
- qcom,msm8998-adsp-pas
+ - qcom,sm8150-adsp-pas
+ - qcom,sm8150-cdsp-pas
then:
properties:
power-domains:
- const: cx
- const: mx
- - if:
- properties:
- compatible:
- contains:
- enum:
- - qcom,sm8150-adsp-pas
- - qcom,sm8150-cdsp-pas
- then:
- properties:
- power-domains:
- items:
- - description: CX power domain
-
- if:
properties:
compatible:
examples:
- |
#include <dt-bindings/clock/qcom,rpmcc.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
adsp {
compatible = "qcom,msm8974-adsp-pil";
- interrupts-extended = <&intc 0 162 IRQ_TYPE_EDGE_RISING>,
+ interrupts-extended = <&intc GIC_SPI 162 IRQ_TYPE_EDGE_RISING>,
<&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
<&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
<&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
qcom,smem-state-names = "stop";
smd-edge {
- interrupts = <0 156 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
qcom,ipc = <&apcs 8 8>;
qcom,smd-edge = <1>;
--- /dev/null
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/qcom,glink-edge.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm G-Link Edge communication channel nodes
+
+maintainers:
+ - Bjorn Andersson <bjorn.andersson@linaro.org>
+
+description:
+ Qualcomm G-Link subnode represents communication edge, channels and devices
+ related to the remote processor.
+
+properties:
+ $nodename:
+ const: "glink-edge"
+
+ apr:
+ $ref: /schemas/soc/qcom/qcom,apr.yaml#
+ description:
+ Qualcomm APR/GPR (Asynchronous/Generic Packet Router)
+
+ fastrpc:
+ type: object
+ description:
+ See Documentation/devicetree/bindings/misc/qcom,fastrpc.txt
+
+ interrupts:
+ maxItems: 1
+
+ label:
+ description: The names of the state bits used for SMP2P output
+
+ mboxes:
+ maxItems: 1
+
+ qcom,remote-pid:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ ID of the shared memory used by GLINK for communication with remote
+ processor.
+
+required:
+ - interrupts
+ - label
+ - mboxes
+ - qcom,remote-pid
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/mailbox/qcom-ipcc.h>
+
+ remoteproc@8a00000 {
+ reg = <0x08a00000 0x10000>;
+ // ...
+
+ glink-edge {
+ interrupts-extended = <&ipcc IPCC_CLIENT_WPSS
+ IPCC_MPROC_SIGNAL_GLINK_QMP
+ IRQ_TYPE_EDGE_RISING>;
+ mboxes = <&ipcc IPCC_CLIENT_WPSS
+ IPCC_MPROC_SIGNAL_GLINK_QMP>;
+
+ label = "wpss";
+ qcom,remote-pid = <13>;
+ };
+ };
"qcom,msm8974-mss-pil"
"qcom,msm8996-mss-pil"
"qcom,msm8998-mss-pil"
- "qcom,sc7180-mss-pil"
- "qcom,sc7280-mss-pil"
"qcom,sdm845-mss-pil"
- reg:
must be "wdog", "fatal", "ready", "handover", "stop-ack"
qcom,msm8996-mss-pil:
qcom,msm8998-mss-pil:
- qcom,sc7180-mss-pil:
- qcom,sc7280-mss-pil:
qcom,sdm845-mss-pil:
must be "wdog", "fatal", "ready", "handover", "stop-ack",
"shutdown-ack"
qcom,msm8998-mss-pil:
must be "iface", "bus", "mem", "xo", "gpll0_mss",
"snoc_axi", "mnoc_axi", "qdss"
- qcom,sc7180-mss-pil:
- must be "iface", "bus", "xo", "snoc_axi", "mnoc_axi",
- "nav"
- qcom,sc7280-mss-pil:
- must be "iface", "xo", "snoc_axi", "offline", "pka"
qcom,sdm845-mss-pil:
must be "iface", "bus", "mem", "xo", "gpll0_mss",
"snoc_axi", "mnoc_axi", "prng"
reference to the list of 3 reset-controllers for the
wcss sub-system
reference to the list of 2 reset-controllers for the modem
- sub-system on SC7180, SC7280, SDM845 SoCs
+ sub-system on SDM845 SoCs
- reset-names:
Usage: required
must be "wcss_aon_reset", "wcss_reset", "wcss_q6_reset"
for the wcss sub-system
must be "mss_restart", "pdc_reset" for the modem
- sub-system on SC7180, SC7280, SDM845 SoCs
+ sub-system on SDM845 SoCs
For devices where the mba and mpss sub-nodes are not specified, mba/mpss region
should be referenced as follows:
qcom,msm8996-mss-pil:
qcom,msm8998-mss-pil:
must be "cx", "mx"
- qcom,sc7180-mss-pil:
- must be "cx", "mx", "mss"
- qcom,sc7280-mss-pil:
- must be "cx", "mss"
qcom,sdm845-mss-pil:
must be "cx", "mx", "mss"
Definition: a phandle reference to a syscon representing TCSR followed
by the three offsets within syscon for q6, modem and nc
halt registers.
- a phandle reference to a syscon representing TCSR followed
- by the four offsets within syscon for q6, modem, nc and vq6
- halt registers on SC7280 SoCs.
-
-For the compatible strings below the following phandle references are required:
- "qcom,sc7180-mss-pil"
-- qcom,spare-regs:
- Usage: required
- Value type: <prop-encoded-array>
- Definition: a phandle reference to a syscon representing TCSR followed
- by the offset within syscon for conn_box_spare0 register
- used by the modem sub-system running on SC7180 SoC.
-
-For the compatible strings below the following phandle references are required:
- "qcom,sc7280-mss-pil"
-- qcom,ext-regs:
- Usage: required
- Value type: <prop-encoded-array>
- Definition: two phandle references to syscons representing TCSR_REG and
- TCSR register space followed by the two offsets within the syscon
- to force_clk_en/rscc_disable and axim1_clk_off/crypto_clk_off
- registers respectively.
-
-- qcom,qaccept-regs:
- Usage: required
- Value type: <prop-encoded-array>
- Definition: a phandle reference to a syscon representing TCSR followed
- by the three offsets within syscon for mdm, cx and axi
- qaccept registers used by the modem sub-system running on
- SC7280 SoC.
The Hexagon node must contain iommus property as described in ../iommu/iommu.txt
on platforms which do not have TrustZone.
The following example describes the resources needed to boot control the
Hexagon, as it is found on MSM8974 boards.
- modem-rproc@fc880000 {
- compatible = "qcom,q6v5-pil";
- reg = <0xfc880000 0x100>,
- <0xfc820000 0x020>;
+ remoteproc@fc880000 {
+ compatible = "qcom,msm8974-mss-pil";
+ reg = <0xfc880000 0x100>, <0xfc820000 0x020>;
reg-names = "qdsp6", "rmb";
- interrupts-extended = <&intc 0 24 1>,
- <&modem_smp2p_in 0 0>,
- <&modem_smp2p_in 1 0>,
- <&modem_smp2p_in 2 0>,
- <&modem_smp2p_in 3 0>;
- interrupt-names = "wdog",
- "fatal",
- "ready",
- "handover",
- "stop-ack";
+ interrupts-extended = <&intc GIC_SPI 24 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack";
clocks = <&gcc GCC_MSS_Q6_BIMC_AXI_CLK>,
<&gcc GCC_MSS_CFG_AHB_CLK>,
- <&gcc GCC_BOOT_ROM_AHB_CLK>;
- clock-names = "iface", "bus", "mem";
-
- qcom,halt-regs = <&tcsr_mutex_block 0x1180 0x1200 0x1280>;
+ <&gcc GCC_BOOT_ROM_AHB_CLK>,
+ <&xo_board>;
+ clock-names = "iface", "bus", "mem", "xo";
resets = <&gcc GCC_MSS_RESTART>;
reset-names = "mss_restart";
mx-supply = <&pm8841_s1>;
pll-supply = <&pm8941_l12>;
+ qcom,halt-regs = <&tcsr_mutex_block 0x1180 0x1200 0x1280>;
+
qcom,smem-states = <&modem_smp2p_out 0>;
qcom,smem-state-names = "stop";
mpss {
memory-region = <&mpss_region>;
};
+
+ smd-edge {
+ interrupts = <GIC_SPI 25 IRQ_TYPE_EDGE_RISING>;
+
+ qcom,ipc = <&apcs 8 12>;
+ qcom,smd-edge = <0>;
+
+ label = "modem";
+ };
};
- description: Stop the modem
qcom,smem-state-names:
- $ref: /schemas/types.yaml#/definitions/string
description: The names of the state bits used for SMP2P output
items:
- const: stop
--- /dev/null
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/qcom,sc7180-mss-pil.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SC7180 MSS Peripheral Image Loader
+
+maintainers:
+ - Sibi Sankar <quic_sibis@quicinc.com>
+
+description:
+ This document describes the hardware for a component that loads and boots firmware
+ on the Qualcomm Technology Inc. SC7180 Modem Hexagon Core.
+
+properties:
+ compatible:
+ enum:
+ - qcom,sc7180-mss-pil
+
+ reg:
+ items:
+ - description: MSS QDSP6 registers
+ - description: RMB registers
+
+ reg-names:
+ items:
+ - const: qdsp6
+ - const: rmb
+
+ iommus:
+ items:
+ - description: MSA Stream 1
+ - description: MSA Stream 2
+
+ interrupts:
+ items:
+ - description: Watchdog interrupt
+ - description: Fatal interrupt
+ - description: Ready interrupt
+ - description: Handover interrupt
+ - description: Stop acknowledge interrupt
+ - description: Shutdown acknowledge interrupt
+
+ interrupt-names:
+ items:
+ - const: wdog
+ - const: fatal
+ - const: ready
+ - const: handover
+ - const: stop-ack
+ - const: shutdown-ack
+
+ clocks:
+ items:
+ - description: GCC MSS IFACE clock
+ - description: GCC MSS BUS clock
+ - description: GCC MSS NAV clock
+ - description: GCC MSS SNOC_AXI clock
+ - description: GCC MSS MFAB_AXIS clock
+ - description: RPMH XO clock
+
+ clock-names:
+ items:
+ - const: iface
+ - const: bus
+ - const: nav
+ - const: snoc_axi
+ - const: mnoc_axi
+ - const: xo
+
+ power-domains:
+ items:
+ - description: CX power domain
+ - description: MX power domain
+ - description: MSS power domain
+
+ power-domain-names:
+ items:
+ - const: cx
+ - const: mx
+ - const: mss
+
+ resets:
+ items:
+ - description: AOSS restart
+ - description: PDC reset
+
+ reset-names:
+ items:
+ - const: mss_restart
+ - const: pdc_reset
+
+ memory-region:
+ items:
+ - description: MBA reserved region
+ - description: modem reserved region
+
+ firmware-name:
+ $ref: /schemas/types.yaml#/definitions/string-array
+ items:
+ - description: Name of MBA firmware
+ - description: Name of modem firmware
+
+ qcom,halt-regs:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description:
+ Halt registers are used to halt transactions of various sub-components
+ within MSS.
+ items:
+ - items:
+ - description: phandle to TCSR_MUTEX registers
+ - description: offset to the Q6 halt register
+ - description: offset to the modem halt register
+ - description: offset to the nc halt register
+
+ qcom,spare-regs:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description:
+ Spare registers are multipurpose registers used for errata
+ handling.
+ items:
+ - items:
+ - description: phandle to TCSR_MUTEX registers
+ - description: offset to the conn_box_spare0 register
+
+ qcom,qmp:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: Reference to the AOSS side-channel message RAM.
+
+ qcom,smem-states:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description: States used by the AP to signal the Hexagon core
+ items:
+ - description: Stop the modem
+
+ qcom,smem-state-names:
+ description: The names of the state bits used for SMP2P output
+ const: stop
+
+ glink-edge:
+ $ref: qcom,glink-edge.yaml#
+ description:
+ Qualcomm G-Link subnode which represents communication edge, channels
+ and devices related to the DSP.
+
+ properties:
+ interrupts:
+ items:
+ - description: IRQ from MSS to GLINK
+
+ mboxes:
+ items:
+ - description: Mailbox for communication between APPS and MSS
+
+ label:
+ const: modem
+
+ apr: false
+ fastrpc: false
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - iommus
+ - interrupts
+ - interrupt-names
+ - clocks
+ - clock-names
+ - power-domains
+ - power-domain-names
+ - resets
+ - reset-names
+ - qcom,halt-regs
+ - qcom,spare-regs
+ - memory-region
+ - qcom,qmp
+ - qcom,smem-states
+ - qcom,smem-state-names
+ - glink-edge
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,gcc-sc7180.h>
+ #include <dt-bindings/clock/qcom,rpmh.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+ #include <dt-bindings/reset/qcom,sdm845-aoss.h>
+ #include <dt-bindings/reset/qcom,sdm845-pdc.h>
+
+ remoteproc_mpss: remoteproc@4080000 {
+ compatible = "qcom,sc7180-mss-pil";
+ reg = <0x04080000 0x10000>, <0x04180000 0x48>;
+ reg-names = "qdsp6", "rmb";
+
+ iommus = <&apps_smmu 0x461 0x0>, <&apps_smmu 0x444 0x3>;
+
+ interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 3 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 7 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-names = "wdog", "fatal", "ready", "handover",
+ "stop-ack", "shutdown-ack";
+
+ clocks = <&gcc GCC_MSS_CFG_AHB_CLK>,
+ <&gcc GCC_MSS_Q6_MEMNOC_AXI_CLK>,
+ <&gcc GCC_MSS_NAV_AXI_CLK>,
+ <&gcc GCC_MSS_SNOC_AXI_CLK>,
+ <&gcc GCC_MSS_MFAB_AXIS_CLK>,
+ <&rpmhcc RPMH_CXO_CLK>;
+ clock-names = "iface", "bus", "nav", "snoc_axi",
+ "mnoc_axi", "xo";
+
+ power-domains = <&rpmhpd SC7180_CX>,
+ <&rpmhpd SC7180_MX>,
+ <&rpmhpd SC7180_MSS>;
+ power-domain-names = "cx", "mx", "mss";
+
+ memory-region = <&mba_mem>, <&mpss_mem>;
+
+ qcom,qmp = <&aoss_qmp>;
+
+ qcom,smem-states = <&modem_smp2p_out 0>;
+ qcom,smem-state-names = "stop";
+
+ resets = <&aoss_reset AOSS_CC_MSS_RESTART>,
+ <&pdc_reset PDC_MODEM_SYNC_RESET>;
+ reset-names = "mss_restart", "pdc_reset";
+
+ qcom,halt-regs = <&tcsr_mutex_regs 0x23000 0x25000 0x24000>;
+ qcom,spare-regs = <&tcsr_regs 0xb3e4>;
+
+ glink-edge {
+ interrupts = <GIC_SPI 449 IRQ_TYPE_EDGE_RISING>;
+ mboxes = <&apss_shared 12>;
+ qcom,remote-pid = <1>;
+ label = "modem";
+ };
+ };
--- /dev/null
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/qcom,sc7280-mss-pil.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SC7280 MSS Peripheral Image Loader
+
+maintainers:
+ - Sibi Sankar <quic_sibis@quicinc.com>
+
+description:
+ This document describes the hardware for a component that loads and boots firmware
+ on the Qualcomm Technology Inc. SC7280 Modem Hexagon Core.
+
+properties:
+ compatible:
+ enum:
+ - qcom,sc7280-mss-pil
+
+ reg:
+ items:
+ - description: MSS QDSP6 registers
+ - description: RMB registers
+
+ reg-names:
+ items:
+ - const: qdsp6
+ - const: rmb
+
+ iommus:
+ items:
+ - description: MSA Stream 1
+ - description: MSA Stream 2
+
+ interconnects:
+ items:
+ - description: Path leading to system memory
+
+ interrupts:
+ items:
+ - description: Watchdog interrupt
+ - description: Fatal interrupt
+ - description: Ready interrupt
+ - description: Handover interrupt
+ - description: Stop acknowledge interrupt
+ - description: Shutdown acknowledge interrupt
+
+ interrupt-names:
+ items:
+ - const: wdog
+ - const: fatal
+ - const: ready
+ - const: handover
+ - const: stop-ack
+ - const: shutdown-ack
+
+ clocks:
+ items:
+ - description: GCC MSS IFACE clock
+ - description: GCC MSS OFFLINE clock
+ - description: GCC MSS SNOC_AXI clock
+ - description: RPMH PKA clock
+ - description: RPMH XO clock
+
+ clock-names:
+ items:
+ - const: iface
+ - const: offline
+ - const: snoc_axi
+ - const: pka
+ - const: xo
+
+ power-domains:
+ items:
+ - description: CX power domain
+ - description: MSS power domain
+
+ power-domain-names:
+ items:
+ - const: cx
+ - const: mss
+
+ resets:
+ items:
+ - description: AOSS restart
+ - description: PDC reset
+
+ reset-names:
+ items:
+ - const: mss_restart
+ - const: pdc_reset
+
+ memory-region:
+ items:
+ - description: MBA reserved region
+ - description: modem reserved region
+
+ firmware-name:
+ $ref: /schemas/types.yaml#/definitions/string-array
+ items:
+ - description: Name of MBA firmware
+ - description: Name of modem firmware
+
+ qcom,halt-regs:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description:
+ Halt registers are used to halt transactions of various sub-components
+ within MSS.
+ items:
+ - items:
+ - description: phandle to TCSR_MUTEX registers
+ - description: offset to the Q6 halt register
+ - description: offset to the modem halt register
+ - description: offset to the nc halt register
+ - description: offset to the vq6 halt register
+
+ qcom,ext-regs:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description: EXT registers are used for various power related functionality
+ items:
+ - items:
+ - description: phandle to TCSR_REG registers
+ - description: offset to the force_clk_en register
+ - description: offset to the rscc_disable register
+ - items:
+ - description: phandle to TCSR_MUTEX registers
+ - description: offset to the axim1_clk_off register
+ - description: offset to the crypto_clk_off register
+
+ qcom,qaccept-regs:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description: QACCEPT registers are used to bring up/down Q-channels
+ items:
+ - items:
+ - description: phandle to TCSR_MUTEX registers
+ - description: offset to the mdm qaccept register
+ - description: offset to the cx qaccept register
+ - description: offset to the axi qaccept register
+
+ qcom,qmp:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: Reference to the AOSS side-channel message RAM.
+
+ qcom,smem-states:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description: States used by the AP to signal the Hexagon core
+ items:
+ - description: Stop the modem
+
+ qcom,smem-state-names:
+ description: The names of the state bits used for SMP2P output
+ const: stop
+
+ glink-edge:
+ $ref: qcom,glink-edge.yaml#
+ description:
+ Qualcomm G-Link subnode which represents communication edge, channels
+ and devices related to the DSP.
+
+ properties:
+ interrupts:
+ items:
+ - description: IRQ from MSS to GLINK
+
+ mboxes:
+ items:
+ - description: Mailbox for communication between APPS and MSS
+
+ label:
+ const: modem
+
+ apr: false
+ fastrpc: false
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - iommus
+ - interconnects
+ - interrupts
+ - interrupt-names
+ - clocks
+ - clock-names
+ - power-domains
+ - power-domain-names
+ - resets
+ - reset-names
+ - qcom,halt-regs
+ - qcom,ext-regs
+ - qcom,qaccept-regs
+ - memory-region
+ - qcom,qmp
+ - qcom,smem-states
+ - qcom,smem-state-names
+ - glink-edge
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,gcc-sc7280.h>
+ #include <dt-bindings/clock/qcom,rpmh.h>
+ #include <dt-bindings/interconnect/qcom,sc7280.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/mailbox/qcom-ipcc.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+ #include <dt-bindings/reset/qcom,sdm845-aoss.h>
+ #include <dt-bindings/reset/qcom,sdm845-pdc.h>
+
+ remoteproc_mpss: remoteproc@4080000 {
+ compatible = "qcom,sc7280-mss-pil";
+ reg = <0x04080000 0x10000>, <0x04180000 0x48>;
+ reg-names = "qdsp6", "rmb";
+
+ iommus = <&apps_smmu 0x124 0x0>, <&apps_smmu 0x488 0x7>;
+
+ interconnects = <&mc_virt MASTER_LLCC 0 &mc_virt SLAVE_EBI1 0>;
+
+ interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 3 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 7 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-names = "wdog", "fatal", "ready", "handover",
+ "stop-ack", "shutdown-ack";
+
+ clocks = <&gcc GCC_MSS_CFG_AHB_CLK>,
+ <&gcc GCC_MSS_OFFLINE_AXI_CLK>,
+ <&gcc GCC_MSS_SNOC_AXI_CLK>,
+ <&rpmhcc RPMH_PKA_CLK>,
+ <&rpmhcc RPMH_CXO_CLK>;
+ clock-names = "iface", "offline", "snoc_axi", "pka", "xo";
+
+ power-domains = <&rpmhpd SC7280_CX>,
+ <&rpmhpd SC7280_MSS>;
+ power-domain-names = "cx", "mss";
+
+ memory-region = <&mba_mem>, <&mpss_mem>;
+
+ qcom,qmp = <&aoss_qmp>;
+
+ qcom,smem-states = <&modem_smp2p_out 0>;
+ qcom,smem-state-names = "stop";
+
+ resets = <&aoss_reset AOSS_CC_MSS_RESTART>,
+ <&pdc_reset PDC_MODEM_SYNC_RESET>;
+ reset-names = "mss_restart", "pdc_reset";
+
+ qcom,halt-regs = <&tcsr_mutex 0x23000 0x25000 0x28000 0x33000>;
+ qcom,ext-regs = <&tcsr 0x10000 0x10004>, <&tcsr_mutex 0x26004 0x26008>;
+ qcom,qaccept-regs = <&tcsr_mutex 0x23030 0x23040 0x23020>;
+
+ glink-edge {
+ interrupts-extended = <&ipcc IPCC_CLIENT_MPSS
+ IPCC_MPROC_SIGNAL_GLINK_QMP
+ IRQ_TYPE_EDGE_RISING>;
+ mboxes = <&ipcc IPCC_CLIENT_MPSS
+ IPCC_MPROC_SIGNAL_GLINK_QMP>;
+ label = "modem";
+ qcom,remote-pid = <1>;
+ };
+ };
- const: pdc_sync
memory-region:
- $ref: /schemas/types.yaml#/definitions/phandle
+ maxItems: 1
description: Reference to the reserved-memory for the Hexagon core
firmware-name:
- description: Stop the modem
qcom,smem-state-names:
- $ref: /schemas/types.yaml#/definitions/string
description: The names of the state bits used for SMP2P output
const: stop
glink-edge:
- type: object
- description: |
+ $ref: qcom,glink-edge.yaml#
+ description:
Qualcomm G-Link subnode which represents communication edge, channels
and devices related to the ADSP.
- description: Mailbox for communication between APPS and WPSS
label:
- description: The names of the state bits used for SMP2P output
items:
- const: wpss
- qcom,remote-pid:
- $ref: /schemas/types.yaml#/definitions/uint32
- description: ID of the shared memory used by GLINK for communication with WPSS
-
- required:
- - interrupts
- - mboxes
- - label
- - qcom,remote-pid
-
- additionalProperties: false
+ apr: false
+ fastrpc: false
required:
- compatible
- description: Stop the modem
qcom,smem-state-names:
- $ref: /schemas/types.yaml#/definitions/string
description: The names of the state bits used for SMP2P output
items:
- const: stop
--- /dev/null
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/qcom,smd-edge.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SMD Edge communication channel nodes
+
+maintainers:
+ - Bjorn Andersson <bjorn.andersson@linaro.org>
+
+description:
+ Qualcomm SMD subnode represents a remote subsystem or a remote processor of
+ some sort - or in SMD language an "edge". The name of the edges are not
+ important.
+ See also Documentation/devicetree/bindings/soc/qcom/qcom,smd.yaml
+
+properties:
+ $nodename:
+ const: "smd-edge"
+
+ interrupts:
+ maxItems: 1
+
+ label:
+ description:
+ Name of the edge, used for debugging and identification purposes. The
+ node name will be used if this is not present.
+
+ mboxes:
+ maxItems: 1
+ description:
+ Reference to the mailbox representing the outgoing doorbell in APCS for
+ this client.
+
+ qcom,ipc:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ - items:
+ - description: phandle to a syscon node representing the APCS registers
+ - description: u32 representing offset to the register within the syscon
+ - description: u32 representing the ipc bit within the register
+ description:
+ Three entries specifying the outgoing ipc bit used for signaling the
+ remote processor.
+
+ qcom,smd-edge:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ The identifier of the remote processor in the smd channel allocation
+ table.
+
+ qcom,remote-pid:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ The identifier for the remote processor as known by the rest of the
+ system.
+
+required:
+ - interrupts
+ - qcom,smd-edge
+
+oneOf:
+ - required:
+ - mboxes
+ - required:
+ - qcom,ipc
+
+additionalProperties: true
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/mailbox/qcom-ipcc.h>
+
+ remoteproc {
+ // ...
+
+ smd-edge {
+ interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
+
+ qcom,ipc = <&apcs 8 8>;
+ qcom,smd-edge = <1>;
+ };
+ };
enum:
- ti,am3356-pru # for AM335x SoC family (AM3356+ SoCs only)
- ti,am4376-pru # for AM437x SoC family (AM4376+ SoCs only)
+ - ti,am5728-pru # for AM57xx SoC family
+ - ti,am625-pru # for PRUs in K3 AM62x SoC family
- ti,am642-pru # for PRUs in K3 AM64x SoC family
- ti,am642-rtu # for RTUs in K3 AM64x SoC family
- ti,am642-tx-pru # for Tx_PRUs in K3 AM64x SoC family
- - ti,am5728-pru # for AM57xx SoC family
- - ti,k2g-pru # for 66AK2G SoC family
- ti,am654-pru # for PRUs in K3 AM65x SoC family
- ti,am654-rtu # for RTUs in K3 AM65x SoC family
- ti,am654-tx-pru # for Tx_PRUs in K3 AM65x SR2.0 SoCs
- ti,j721e-pru # for PRUs in K3 J721E SoC family
- ti,j721e-rtu # for RTUs in K3 J721E SoC family
- ti,j721e-tx-pru # for Tx_PRUs in K3 J721E SoC family
+ - ti,k2g-pru # for 66AK2G SoC family
reg:
items:
edges are not important.
properties:
- interrupts:
- maxItems: 1
-
- label:
- $ref: /schemas/types.yaml#/definitions/string
- description:
- Name of the edge, used for debugging and identification purposes. The
- node name will be used if this is not present.
-
- mboxes:
- maxItems: 1
- description:
- Reference to the mailbox representing the outgoing doorbell in APCS for
- this client.
-
- qcom,ipc:
- $ref: /schemas/types.yaml#/definitions/phandle-array
- items:
- - items:
- - description: phandle to a syscon node representing the APCS registers
- - description: u32 representing offset to the register within the syscon
- - description: u32 representing the ipc bit within the register
- description:
- Three entries specifying the outgoing ipc bit used for signaling the
- remote processor.
-
- qcom,smd-edge:
- $ref: /schemas/types.yaml#/definitions/uint32
- description:
- The identifier of the remote processor in the smd channel allocation
- table.
-
- qcom,remote-pid:
- $ref: /schemas/types.yaml#/definitions/uint32
- description:
- The identifier for the remote processor as known by the rest of the
- system.
-
rpm-requests:
type: object
description:
additionalProperties: true
- required:
- - interrupts
- - qcom,smd-edge
-
- oneOf:
- - required:
- - mboxes
- - required:
- - qcom,ipc
-
- additionalProperties: false
+ unevaluatedProperties: false
required:
- compatible
- qcom,apss-wdt-sc8280xp
- qcom,apss-wdt-sdm845
- qcom,apss-wdt-sdx55
+ - qcom,apss-wdt-sdx65
- qcom,apss-wdt-sm6350
- qcom,apss-wdt-sm8150
- qcom,apss-wdt-sm8250
- realtek,rtl8380-wdt
- realtek,rtl8390-wdt
- realtek,rtl9300-wdt
+ - realtek,rtl9310-wdt
reg:
maxItems: 1
.. kernel-doc:: drivers/cxl/core/mbox.c
:doc: cxl mbox
+CXL Regions
+-----------
+.. kernel-doc:: drivers/cxl/core/region.c
+ :doc: cxl core region
+
+.. kernel-doc:: drivers/cxl/core/region.c
+ :identifiers:
+
External Interfaces
===================
default is 'N', setting it to 'Y' will disable disconnect
injection on the RPC server.
+- /sys/kernel/debug/fail_sunrpc/ignore-cache-wait:
+
+ Format: { 'Y' | 'N' }
+
+ default is 'N', setting it to 'Y' will disable cache wait
+ injection on the RPC server.
+
- /sys/kernel/debug/fail_function/inject:
Format: { 'function-name' | '!function-name' | '' }
Work on kconfig is welcomed on both areas of clarifying semantics and on
evaluating the use of a full SAT solver for it. A full SAT solver can be
desirable to enable more complex dependency mappings and / or queries,
-for instance on possible use case for a SAT solver could be that of handling
+for instance one possible use case for a SAT solver could be that of handling
the current known recursive dependency issues. It is not known if this would
address such issues but such evaluation is desirable. If support for a full SAT
solver proves too complex or that it cannot address recursive dependency issues
APPARMOR SECURITY MODULE
M: John Johansen <john.johansen@canonical.com>
-L: apparmor@lists.ubuntu.com (subscribers-only, general discussion)
+M: John Johansen <john@apparmor.net>
+L: apparmor@lists.ubuntu.com (moderated for non-subscribers)
S: Supported
-W: wiki.apparmor.net
+W: apparmor.net
+B: https://gitlab.com/apparmor/apparmor-kernel
+C: irc://irc.oftc.net/apparmor
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
+T: https://gitlab.com/apparmor/apparmor-kernel.git
F: Documentation/admin-guide/LSM/apparmor.rst
F: security/apparmor/
S: Maintained
F: Documentation/admin-guide/module-signing.rst
F: certs/
-F: scripts/check-blacklist-hashes.awk
F: scripts/sign-file.c
F: tools/certs/
L: linux-cifs@vger.kernel.org
S: Maintained
T: git git://git.samba.org/ksmbd.git
+F: Documentation/filesystems/cifs/ksmbd.rst
F: fs/ksmbd/
F: fs/smbfs_common/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git modules-next
F: include/linux/module.h
F: kernel/module/
+F: scripts/module*
MONOLITHIC POWER SYSTEM PMIC DRIVER
M: Saravanan Sekar <sravanhome@gmail.com>
F: Documentation/devicetree/bindings/pinctrl/
F: Documentation/driver-api/pin-control.rst
F: drivers/pinctrl/
+F: include/dt-bindings/pinctrl/
F: include/linux/pinctrl/
PIN CONTROLLER - AMD
$(if $(word 2, $(KBUILD_EXTMOD)), \
$(error building multiple external modules is not supported))
+$(foreach x, % :, $(if $(findstring $x, $(KBUILD_EXTMOD)), \
+ $(error module directory path cannot contain '$x')))
+
# Remove trailing slashes
ifneq ($(filter %/, $(KBUILD_EXTMOD)),)
KBUILD_EXTMOD := $(shell dirname $(KBUILD_EXTMOD).)
ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE
KBUILD_CFLAGS += -O2
-else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3
-KBUILD_CFLAGS += -O3
else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS += -Os
endif
ifneq ($(dtstree),)
-%.dtb: include/config/kernel.release scripts_dtc
+%.dtb: dtbs_prepare
$(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
-%.dtbo: include/config/kernel.release scripts_dtc
+%.dtbo: dtbs_prepare
$(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
-PHONY += dtbs dtbs_install dtbs_check
-dtbs: include/config/kernel.release scripts_dtc
+PHONY += dtbs dtbs_prepare dtbs_install dtbs_check
+dtbs: dtbs_prepare
$(Q)$(MAKE) $(build)=$(dtstree)
+# include/config/kernel.release is actually needed when installing DTBs because
+# INSTALL_DTBS_PATH contains $(KERNELRELEASE). However, we do not want to make
+# dtbs_install depend on it as dtbs_install may run as root.
+dtbs_prepare: include/config/kernel.release scripts_dtc
+
ifneq ($(filter dtbs_check, $(MAKECMDGOALS)),)
export CHECK_DTBS=y
dtbs: dt_binding_check
# CONFIG_UTS_NS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
CONFIG_EMBEDDED=y
CONFIG_PERF_EVENTS=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_UTS_NS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
CONFIG_EMBEDDED=y
CONFIG_PERF_EVENTS=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_UTS_NS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
CONFIG_EMBEDDED=y
CONFIG_PERF_EVENTS=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_UTS_NS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
CONFIG_EXPERT=y
CONFIG_PERF_EVENTS=y
# CONFIG_COMPAT_BRK is not set
# CONFIG_UTS_NS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
CONFIG_EMBEDDED=y
CONFIG_PERF_EVENTS=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
CONFIG_BLK_DEV_RAM=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
CONFIG_EMBEDDED=y
CONFIG_PERF_EVENTS=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_UTS_NS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
CONFIG_PERF_EVENTS=y
# CONFIG_UTS_NS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
CONFIG_PERF_EVENTS=y
# CONFIG_UTS_NS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
CONFIG_PERF_EVENTS=y
# CONFIG_UTS_NS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
CONFIG_PERF_EVENTS=y
# CONFIG_COMPAT_BRK is not set
CONFIG_KPROBES=y
CONFIG_INITRAMFS_ROOT_UID=2100
CONFIG_INITRAMFS_ROOT_GID=501
# CONFIG_RD_GZIP is not set
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_AIO is not set
CONFIG_EMBEDDED=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
CONFIG_EMBEDDED=y
CONFIG_PERF_EVENTS=y
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
CONFIG_EMBEDDED=y
CONFIG_PERF_EVENTS=y
# CONFIG_VM_EVENT_COUNTERS is not set
--- /dev/null
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2021
+ * Author(s): Jesse Taube <Mr.Bossman075@gmail.com>
+ */
+
+#ifndef _DT_BINDINGS_PINCTRL_IMXRT1170_PINFUNC_H
+#define _DT_BINDINGS_PINCTRL_IMXRT1170_PINFUNC_H
+
+#define IMX_PAD_SION 0x40000000
+
+/*
+ * The pin function ID is a tuple of
+ * <mux_reg conf_reg input_reg mux_mode input_val>
+ */
+
+#define IOMUXC_GPIO_LPSR_00_FLEXCAN3_TX 0x000 0x040 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_00_MIC_CLK 0x000 0x040 0x0 0x1 0x0
+#define IOMUXC_GPIO_LPSR_00_MQS_RIGHT 0x000 0x040 0x0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_00_ARM_CM4_EVENTO 0x000 0x040 0x0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_00_GPIO_MUX6_IO00 0x000 0x040 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_00_LPUART12_TXD 0x000 0x040 0x0B0 0x6 0x0
+#define IOMUXC_GPIO_LPSR_00_SAI4_MCLK 0x000 0x040 0x0C8 0x7 0x0
+#define IOMUXC_GPIO_LPSR_00_GPIO12_IO00 0x000 0x040 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_01_FLEXCAN3_RX 0x004 0x044 0x080 0x0 0x0
+#define IOMUXC_GPIO_LPSR_01_MIC_BITSTREAM0 0x004 0x044 0x0B4 0x1 0x0
+#define IOMUXC_GPIO_LPSR_01_MQS_LEFT 0x004 0x044 0x0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_01_ARM_CM4_EVENTI 0x004 0x044 0x0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_01_GPIO_MUX6_IO01 0x004 0x044 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_01_LPUART12_RXD 0x004 0x044 0x0AC 0x6 0x0
+#define IOMUXC_GPIO_LPSR_01_GPIO12_IO01 0x004 0x044 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_02_GPIO12_IO02 0x008 0x048 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_02_SRC_BOOT_MODE00 0x008 0x048 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_02_LPSPI5_SCK 0x008 0x048 0x098 0x1 0x0
+#define IOMUXC_GPIO_LPSR_02_SAI4_TX_DATA 0x008 0x048 0x0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_02_MQS_RIGHT 0x008 0x048 0x0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_02_GPIO_MUX6_IO02 0x008 0x048 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_LPSR_03_SRC_BOOT_MODE01 0x00C 0x04C 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_03_LPSPI5_PCS0 0x00C 0x04C 0x094 0x1 0x0
+#define IOMUXC_GPIO_LPSR_03_SAI4_TX_SYNC 0x00C 0x04C 0x0DC 0x2 0x0
+#define IOMUXC_GPIO_LPSR_03_MQS_LEFT 0x00C 0x04C 0x0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_03_GPIO_MUX6_IO03 0x00C 0x04C 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_03_GPIO12_IO03 0x00C 0x04C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_04_LPI2C5_SDA 0x010 0x050 0x088 0x0 0x0
+#define IOMUXC_GPIO_LPSR_04_LPSPI5_SOUT 0x010 0x050 0x0A0 0x1 0x0
+#define IOMUXC_GPIO_LPSR_04_SAI4_TX_BCLK 0x010 0x050 0x0D8 0x2 0x0
+#define IOMUXC_GPIO_LPSR_04_LPUART12_RTS_B 0x010 0x050 0x0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_04_GPIO_MUX6_IO04 0x010 0x050 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_04_LPUART11_TXD 0x010 0x050 0x0A8 0x6 0x0
+#define IOMUXC_GPIO_LPSR_04_GPIO12_IO04 0x010 0x050 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_05_GPIO12_IO05 0x014 0x054 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_05_LPI2C5_SCL 0x014 0x054 0x084 0x0 0x0
+#define IOMUXC_GPIO_LPSR_05_LPSPI5_SIN 0x014 0x054 0x09C 0x1 0x0
+#define IOMUXC_GPIO_LPSR_05_SAI4_MCLK 0x014 0x054 0x0C8 0x2 0x1
+#define IOMUXC_GPIO_LPSR_05_LPUART12_CTS_B 0x014 0x054 0x0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_05_GPIO_MUX6_IO05 0x014 0x054 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_05_LPUART11_RXD 0x014 0x054 0x0A4 0x6 0x0
+#define IOMUXC_GPIO_LPSR_05_NMI_GLUE_NMI 0x014 0x054 0x0C4 0x7 0x0
+
+#define IOMUXC_GPIO_LPSR_06_LPI2C6_SDA 0x018 0x058 0x090 0x0 0x0
+#define IOMUXC_GPIO_LPSR_06_SAI4_RX_DATA 0x018 0x058 0x0D0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_06_LPUART12_TXD 0x018 0x058 0x0B0 0x3 0x1
+#define IOMUXC_GPIO_LPSR_06_LPSPI6_PCS3 0x018 0x058 0x0 0x4 0x0
+#define IOMUXC_GPIO_LPSR_06_GPIO_MUX6_IO06 0x018 0x058 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_06_FLEXCAN3_TX 0x018 0x058 0x0 0x6 0x0
+#define IOMUXC_GPIO_LPSR_06_PIT2_TRIGGER3 0x018 0x058 0x0 0x7 0x0
+#define IOMUXC_GPIO_LPSR_06_LPSPI5_PCS1 0x018 0x058 0x0 0x8 0x0
+#define IOMUXC_GPIO_LPSR_06_GPIO12_IO06 0x018 0x058 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_07_LPI2C6_SCL 0x01C 0x05C 0x08C 0x0 0x0
+#define IOMUXC_GPIO_LPSR_07_SAI4_RX_BCLK 0x01C 0x05C 0x0CC 0x2 0x0
+#define IOMUXC_GPIO_LPSR_07_LPUART12_RXD 0x01C 0x05C 0x0AC 0x3 0x1
+#define IOMUXC_GPIO_LPSR_07_LPSPI6_PCS2 0x01C 0x05C 0x0 0x4 0x0
+#define IOMUXC_GPIO_LPSR_07_GPIO_MUX6_IO07 0x01C 0x05C 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_07_FLEXCAN3_RX 0x01C 0x05C 0x080 0x6 0x1
+#define IOMUXC_GPIO_LPSR_07_PIT2_TRIGGER2 0x01C 0x05C 0x0 0x7 0x0
+#define IOMUXC_GPIO_LPSR_07_LPSPI5_PCS2 0x01C 0x05C 0x0 0x8 0x0
+#define IOMUXC_GPIO_LPSR_07_GPIO12_IO07 0x01C 0x05C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_08_GPIO12_IO08 0x020 0x060 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_08_LPUART11_TXD 0x020 0x060 0x0A8 0x0 0x1
+#define IOMUXC_GPIO_LPSR_08_FLEXCAN3_TX 0x020 0x060 0x0 0x1 0x0
+#define IOMUXC_GPIO_LPSR_08_SAI4_RX_SYNC 0x020 0x060 0x0D4 0x2 0x0
+#define IOMUXC_GPIO_LPSR_08_MIC_CLK 0x020 0x060 0x0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_08_LPSPI6_PCS1 0x020 0x060 0x0 0x4 0x0
+#define IOMUXC_GPIO_LPSR_08_GPIO_MUX6_IO08 0x020 0x060 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_08_LPI2C5_SDA 0x020 0x060 0x088 0x6 0x1
+#define IOMUXC_GPIO_LPSR_08_PIT2_TRIGGER1 0x020 0x060 0x0 0x7 0x0
+#define IOMUXC_GPIO_LPSR_08_LPSPI5_PCS3 0x020 0x060 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_LPSR_09_GPIO12_IO09 0x024 0x064 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_09_LPUART11_RXD 0x024 0x064 0x0A4 0x0 0x1
+#define IOMUXC_GPIO_LPSR_09_FLEXCAN3_RX 0x024 0x064 0x080 0x1 0x2
+#define IOMUXC_GPIO_LPSR_09_PIT2_TRIGGER0 0x024 0x064 0x0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_09_MIC_BITSTREAM0 0x024 0x064 0x0B4 0x3 0x1
+#define IOMUXC_GPIO_LPSR_09_LPSPI6_PCS0 0x024 0x064 0x0 0x4 0x0
+#define IOMUXC_GPIO_LPSR_09_GPIO_MUX6_IO09 0x024 0x064 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_09_LPI2C5_SCL 0x024 0x064 0x084 0x6 0x1
+#define IOMUXC_GPIO_LPSR_09_SAI4_TX_DATA 0x024 0x064 0x0 0x7 0x0
+
+#define IOMUXC_GPIO_LPSR_10_GPIO12_IO10 0x028 0x068 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_10_JTAG_MUX_TRSTB 0x028 0x068 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_10_LPUART11_CTS_B 0x028 0x068 0x0 0x1 0x0
+#define IOMUXC_GPIO_LPSR_10_LPI2C6_SDA 0x028 0x068 0x090 0x2 0x1
+#define IOMUXC_GPIO_LPSR_10_MIC_BITSTREAM1 0x028 0x068 0x0B8 0x3 0x0
+#define IOMUXC_GPIO_LPSR_10_LPSPI6_SCK 0x028 0x068 0x0 0x4 0x0
+#define IOMUXC_GPIO_LPSR_10_GPIO_MUX6_IO10 0x028 0x068 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_10_LPI2C5_SCLS 0x028 0x068 0x0 0x6 0x0
+#define IOMUXC_GPIO_LPSR_10_SAI4_TX_SYNC 0x028 0x068 0x0DC 0x7 0x1
+#define IOMUXC_GPIO_LPSR_10_LPUART12_TXD 0x028 0x068 0x0B0 0x8 0x2
+
+#define IOMUXC_GPIO_LPSR_11_JTAG_MUX_TDO 0x02C 0x06C 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_11_LPUART11_RTS_B 0x02C 0x06C 0x0 0x1 0x0
+#define IOMUXC_GPIO_LPSR_11_LPI2C6_SCL 0x02C 0x06C 0x08C 0x2 0x1
+#define IOMUXC_GPIO_LPSR_11_MIC_BITSTREAM2 0x02C 0x06C 0x0BC 0x3 0x0
+#define IOMUXC_GPIO_LPSR_11_LPSPI6_SOUT 0x02C 0x06C 0x0 0x4 0x0
+#define IOMUXC_GPIO_LPSR_11_GPIO_MUX6_IO11 0x02C 0x06C 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_11_LPI2C5_SDAS 0x02C 0x06C 0x0 0x6 0x0
+#define IOMUXC_GPIO_LPSR_11_ARM_TRACE_SWO 0x02C 0x06C 0x0 0x7 0x0
+#define IOMUXC_GPIO_LPSR_11_LPUART12_RXD 0x02C 0x06C 0x0AC 0x8 0x2
+#define IOMUXC_GPIO_LPSR_11_GPIO12_IO11 0x02C 0x06C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_12_GPIO12_IO12 0x030 0x070 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_12_JTAG_MUX_TDI 0x030 0x070 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_12_PIT2_TRIGGER0 0x030 0x070 0x0 0x1 0x0
+#define IOMUXC_GPIO_LPSR_12_MIC_BITSTREAM3 0x030 0x070 0x0C0 0x3 0x0
+#define IOMUXC_GPIO_LPSR_12_LPSPI6_SIN 0x030 0x070 0x0 0x4 0x0
+#define IOMUXC_GPIO_LPSR_12_GPIO_MUX6_IO12 0x030 0x070 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_12_LPI2C5_HREQ 0x030 0x070 0x0 0x6 0x0
+#define IOMUXC_GPIO_LPSR_12_SAI4_TX_BCLK 0x030 0x070 0x0D8 0x7 0x1
+#define IOMUXC_GPIO_LPSR_12_LPSPI5_SCK 0x030 0x070 0x098 0x8 0x1
+
+#define IOMUXC_GPIO_LPSR_13_GPIO12_IO13 0x034 0x074 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_13_JTAG_MUX_MOD 0x034 0x074 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_13_MIC_BITSTREAM1 0x034 0x074 0x0B8 0x1 0x1
+#define IOMUXC_GPIO_LPSR_13_PIT2_TRIGGER1 0x034 0x074 0x0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_13_GPIO_MUX6_IO13 0x034 0x074 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_13_SAI4_RX_DATA 0x034 0x074 0x0D0 0x7 0x1
+#define IOMUXC_GPIO_LPSR_13_LPSPI5_PCS0 0x034 0x074 0x094 0x8 0x1
+
+#define IOMUXC_GPIO_LPSR_14_JTAG_MUX_TCK 0x038 0x078 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_14_MIC_BITSTREAM2 0x038 0x078 0x0BC 0x1 0x1
+#define IOMUXC_GPIO_LPSR_14_PIT2_TRIGGER2 0x038 0x078 0x0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_14_GPIO_MUX6_IO14 0x038 0x078 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_14_SAI4_RX_BCLK 0x038 0x078 0x0CC 0x7 0x1
+#define IOMUXC_GPIO_LPSR_14_LPSPI5_SOUT 0x038 0x078 0x0A0 0x8 0x1
+#define IOMUXC_GPIO_LPSR_14_GPIO12_IO14 0x038 0x078 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_LPSR_15_GPIO12_IO15 0x03C 0x07C 0x0 0xA 0x0
+#define IOMUXC_GPIO_LPSR_15_JTAG_MUX_TMS 0x03C 0x07C 0x0 0x0 0x0
+#define IOMUXC_GPIO_LPSR_15_MIC_BITSTREAM3 0x03C 0x07C 0x0C0 0x1 0x1
+#define IOMUXC_GPIO_LPSR_15_PIT2_TRIGGER3 0x03C 0x07C 0x0 0x2 0x0
+#define IOMUXC_GPIO_LPSR_15_GPIO_MUX6_IO15 0x03C 0x07C 0x0 0x5 0x0
+#define IOMUXC_GPIO_LPSR_15_SAI4_RX_SYNC 0x03C 0x07C 0x0D4 0x7 0x1
+#define IOMUXC_GPIO_LPSR_15_LPSPI5_SIN 0x03C 0x07C 0x09C 0x8 0x1
+
+#define IOMUXC_WAKEUP_DIG_GPIO13_IO00 0x40C94000 0x40C94040 0x0 0x5 0x0
+#define IOMUXC_WAKEUP_DIG_NMI_GLUE_NMI 0x40C94000 0x40C94040 0x0C4 0x7 0x1
+
+#define IOMUXC_PMIC_ON_REQ_DIG_SNVS_LP_PMIC_ON_REQ 0x40C94004 0x40C94044 0x0 0x0 0x0
+#define IOMUXC_PMIC_ON_REQ_DIG_GPIO13_IO01 0x40C94004 0x40C94044 0x0 0x5 0x0
+
+#define IOMUXC_PMIC_STBY_REQ_DIG_CCM_PMIC_VSTBY_REQ 0x40C94008 0x40C94048 0x0 0x0 0x0
+#define IOMUXC_PMIC_STBY_REQ_DIG_GPIO13_IO02 0x40C94008 0x40C94048 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_00_DIG_SNVS_TAMPER0 0x40C9400C 0x40C9404C 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_00_DIG_GPIO13_IO03 0x40C9400C 0x40C9404C 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_01_DIG_SNVS_TAMPER1 0x40C94010 0x40C94050 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_01_DIG_GPIO13_IO04 0x40C94010 0x40C94050 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_02_DIG_SNVS_TAMPER2 0x40C94014 0x40C94054 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_02_DIG_GPIO13_IO05 0x40C94014 0x40C94054 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_03_DIG_SNVS_TAMPER3 0x40C94018 0x40C94058 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_03_DIG_GPIO13_IO06 0x40C94018 0x40C94058 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_04_DIG_SNVS_TAMPER4 0x40C9401C 0x40C9405C 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_04_DIG_GPIO13_IO07 0x40C9401C 0x40C9405C 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_05_DIG_SNVS_TAMPER5 0x40C94020 0x40C94060 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_05_DIG_GPIO13_IO08 0x40C94020 0x40C94060 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_06_DIG_SNVS_TAMPER6 0x40C94024 0x40C94064 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_06_DIG_GPIO13_IO09 0x40C94024 0x40C94064 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_07_DIG_SNVS_TAMPER7 0x40C94028 0x40C94068 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_07_DIG_GPIO13_IO10 0x40C94028 0x40C94068 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_08_DIG_SNVS_TAMPER8 0x40C9402C 0x40C9406C 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_08_DIG_GPIO13_IO11 0x40C9402C 0x40C9406C 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SNVS_09_DIG_SNVS_TAMPER9 0x40C94030 0x40C94070 0x0 0x0 0x0
+#define IOMUXC_GPIO_SNVS_09_DIG_GPIO13_IO12 0x40C94030 0x40C94070 0x0 0x5 0x0
+
+#define IOMUXC_TEST_MODE_DIG 0x0 0x40C94034 0x0 0x0 0x0
+
+#define IOMUXC_POR_B_DIG 0x0 0x40C94038 0x0 0x0 0x0
+
+#define IOMUXC_ONOFF_DIG 0x0 0x40C9403C 0x0 0x0 0x0
+
+#define IOMUXC_GPIO_EMC_B1_00_SEMC_DATA00 0x010 0x254 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_00_FLEXPWM4_PWM0_A 0x010 0x254 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_00_GPIO_MUX1_IO00 0x010 0x254 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_00_FLEXIO1_D00 0x010 0x254 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_00_GPIO7_IO00 0x010 0x254 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_01_GPIO7_IO01 0x014 0x258 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_01_SEMC_DATA01 0x014 0x258 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_01_FLEXPWM4_PWM0_B 0x014 0x258 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_01_GPIO_MUX1_IO01 0x014 0x258 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_01_FLEXIO1_D01 0x014 0x258 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_02_SEMC_DATA02 0x018 0x25C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_02_FLEXPWM4_PWM1_A 0x018 0x25C 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_02_GPIO_MUX1_IO02 0x018 0x25C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_02_FLEXIO1_D02 0x018 0x25C 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_02_GPIO7_IO02 0x018 0x25C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_03_SEMC_DATA03 0x01C 0x260 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_03_FLEXPWM4_PWM1_B 0x01C 0x260 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_03_GPIO_MUX1_IO03 0x01C 0x260 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_03_FLEXIO1_D03 0x01C 0x260 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_03_GPIO7_IO03 0x01C 0x260 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_04_GPIO7_IO04 0x020 0x264 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_04_SEMC_DATA04 0x020 0x264 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_04_FLEXPWM4_PWM2_A 0x020 0x264 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_04_GPIO_MUX1_IO04 0x020 0x264 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_04_FLEXIO1_D04 0x020 0x264 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_05_SEMC_DATA05 0x024 0x268 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_05_FLEXPWM4_PWM2_B 0x024 0x268 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_05_GPIO_MUX1_IO05 0x024 0x268 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_05_FLEXIO1_D05 0x024 0x268 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_05_GPIO7_IO05 0x024 0x268 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_06_SEMC_DATA06 0x028 0x26C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_06_FLEXPWM2_PWM0_A 0x028 0x26C 0x518 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_06_GPIO_MUX1_IO06 0x028 0x26C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_06_FLEXIO1_D06 0x028 0x26C 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_06_GPIO7_IO06 0x028 0x26C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_07_GPIO7_IO07 0x02C 0x270 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_07_SEMC_DATA07 0x02C 0x270 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_07_FLEXPWM2_PWM0_B 0x02C 0x270 0x524 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_07_GPIO_MUX1_IO07 0x02C 0x270 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_07_FLEXIO1_D07 0x02C 0x270 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_08_SEMC_DM00 0x030 0x274 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_08_FLEXPWM2_PWM1_A 0x030 0x274 0x51C 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_08_GPIO_MUX1_IO08 0x030 0x274 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_08_FLEXIO1_D08 0x030 0x274 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_08_GPIO7_IO08 0x030 0x274 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_09_SEMC_ADDR00 0x034 0x278 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_09_FLEXPWM2_PWM1_B 0x034 0x278 0x528 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_09_GPT5_CAPTURE1 0x034 0x278 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_09_GPIO_MUX1_IO09 0x034 0x278 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_09_FLEXIO1_D09 0x034 0x278 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_09_GPIO7_IO09 0x034 0x278 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_10_SEMC_ADDR01 0x038 0x27C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_10_FLEXPWM2_PWM2_A 0x038 0x27C 0x520 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_10_GPT5_CAPTURE2 0x038 0x27C 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_10_GPIO_MUX1_IO10 0x038 0x27C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_10_FLEXIO1_D10 0x038 0x27C 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_10_GPIO7_IO10 0x038 0x27C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_11_GPIO7_IO11 0x03C 0x280 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_11_SEMC_ADDR02 0x03C 0x280 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_11_FLEXPWM2_PWM2_B 0x03C 0x280 0x52C 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_11_GPT5_COMPARE1 0x03C 0x280 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_11_GPIO_MUX1_IO11 0x03C 0x280 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_11_FLEXIO1_D11 0x03C 0x280 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_12_SEMC_ADDR03 0x040 0x284 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_12_XBAR1_INOUT04 0x040 0x284 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_12_GPT5_COMPARE2 0x040 0x284 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_12_GPIO_MUX1_IO12 0x040 0x284 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_12_FLEXIO1_D12 0x040 0x284 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_12_GPIO7_IO12 0x040 0x284 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_13_SEMC_ADDR04 0x044 0x288 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_13_XBAR1_INOUT05 0x044 0x288 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_13_GPT5_COMPARE3 0x044 0x288 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_13_GPIO_MUX1_IO13 0x044 0x288 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_13_FLEXIO1_D13 0x044 0x288 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_13_GPIO7_IO13 0x044 0x288 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_14_GPIO7_IO14 0x048 0x28C 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_14_SEMC_ADDR05 0x048 0x28C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_14_XBAR1_INOUT06 0x048 0x28C 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_14_GPT5_CLK 0x048 0x28C 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_14_GPIO_MUX1_IO14 0x048 0x28C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_14_FLEXIO1_D14 0x048 0x28C 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_15_SEMC_ADDR06 0x04C 0x290 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_15_XBAR1_INOUT07 0x04C 0x290 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_15_GPIO_MUX1_IO15 0x04C 0x290 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_15_FLEXIO1_D15 0x04C 0x290 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_15_GPIO7_IO15 0x04C 0x290 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_16_SEMC_ADDR07 0x050 0x294 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_16_XBAR1_INOUT08 0x050 0x294 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_16_GPIO_MUX1_IO16 0x050 0x294 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_16_FLEXIO1_D16 0x050 0x294 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_16_GPIO7_IO16 0x050 0x294 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_17_GPIO7_IO17 0x054 0x298 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_17_SEMC_ADDR08 0x054 0x298 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_17_FLEXPWM4_PWM3_A 0x054 0x298 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_17_TMR1_TIMER0 0x054 0x298 0x63C 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_17_GPIO_MUX1_IO17 0x054 0x298 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_17_FLEXIO1_D17 0x054 0x298 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_18_SEMC_ADDR09 0x058 0x29C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_18_FLEXPWM4_PWM3_B 0x058 0x29C 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_18_TMR2_TIMER0 0x058 0x29C 0x648 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_18_GPIO_MUX1_IO18 0x058 0x29C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_18_FLEXIO1_D18 0x058 0x29C 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_18_GPIO7_IO18 0x058 0x29C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_19_SEMC_ADDR11 0x05C 0x2A0 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_19_FLEXPWM2_PWM3_A 0x05C 0x2A0 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_19_TMR3_TIMER0 0x05C 0x2A0 0x654 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_19_GPIO_MUX1_IO19 0x05C 0x2A0 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_19_FLEXIO1_D19 0x05C 0x2A0 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_19_GPIO7_IO19 0x05C 0x2A0 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_20_SEMC_ADDR12 0x060 0x2A4 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_20_FLEXPWM2_PWM3_B 0x060 0x2A4 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_20_TMR4_TIMER0 0x060 0x2A4 0x660 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_20_GPIO_MUX1_IO20 0x060 0x2A4 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_20_FLEXIO1_D20 0x060 0x2A4 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_20_GPIO7_IO20 0x060 0x2A4 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_21_GPIO7_IO21 0x064 0x2A8 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_21_SEMC_BA0 0x064 0x2A8 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_21_FLEXPWM3_PWM3_A 0x064 0x2A8 0x53C 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_21_GPIO_MUX1_IO21 0x064 0x2A8 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_21_FLEXIO1_D21 0x064 0x2A8 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_22_GPIO7_IO22 0x068 0x2AC 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_22_SEMC_BA1 0x068 0x2AC 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_22_FLEXPWM3_PWM3_B 0x068 0x2AC 0x54C 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_22_GPIO_MUX1_IO22 0x068 0x2AC 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_22_FLEXIO1_D22 0x068 0x2AC 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_23_SEMC_ADDR10 0x06C 0x2B0 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_23_FLEXPWM1_PWM0_A 0x06C 0x2B0 0x500 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_23_GPIO_MUX1_IO23 0x06C 0x2B0 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_23_FLEXIO1_D23 0x06C 0x2B0 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_23_GPIO7_IO23 0x06C 0x2B0 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_24_GPIO7_IO24 0x070 0x2B4 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_24_SEMC_CAS 0x070 0x2B4 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_24_FLEXPWM1_PWM0_B 0x070 0x2B4 0x50C 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_24_GPIO_MUX1_IO24 0x070 0x2B4 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_24_FLEXIO1_D24 0x070 0x2B4 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_25_GPIO7_IO25 0x074 0x2B8 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_25_SEMC_RAS 0x074 0x2B8 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_25_FLEXPWM1_PWM1_A 0x074 0x2B8 0x504 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_25_GPIO_MUX1_IO25 0x074 0x2B8 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_25_FLEXIO1_D25 0x074 0x2B8 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_26_SEMC_CLK 0x078 0x2BC 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_26_FLEXPWM1_PWM1_B 0x078 0x2BC 0x510 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_26_GPIO_MUX1_IO26 0x078 0x2BC 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_26_FLEXIO1_D26 0x078 0x2BC 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_26_GPIO7_IO26 0x078 0x2BC 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_27_GPIO7_IO27 0x07C 0x2C0 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_27_SEMC_CKE 0x07C 0x2C0 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_27_FLEXPWM1_PWM2_A 0x07C 0x2C0 0x508 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_27_GPIO_MUX1_IO27 0x07C 0x2C0 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_27_FLEXIO1_D27 0x07C 0x2C0 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_28_GPIO7_IO28 0x080 0x2C4 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_28_SEMC_WE 0x080 0x2C4 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_28_FLEXPWM1_PWM2_B 0x080 0x2C4 0x514 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_28_GPIO_MUX1_IO28 0x080 0x2C4 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_28_FLEXIO1_D28 0x080 0x2C4 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_29_SEMC_CS0 0x084 0x2C8 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_29_FLEXPWM3_PWM0_A 0x084 0x2C8 0x530 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_29_GPIO_MUX1_IO29 0x084 0x2C8 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_29_FLEXIO1_D29 0x084 0x2C8 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_29_GPIO7_IO29 0x084 0x2C8 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_30_SEMC_DATA08 0x088 0x2CC 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_30_FLEXPWM3_PWM0_B 0x088 0x2CC 0x540 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_30_GPIO_MUX1_IO30 0x088 0x2CC 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_30_FLEXIO1_D30 0x088 0x2CC 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B1_30_GPIO7_IO30 0x088 0x2CC 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_31_GPIO7_IO31 0x08C 0x2D0 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_31_SEMC_DATA09 0x08C 0x2D0 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_31_FLEXPWM3_PWM1_A 0x08C 0x2D0 0x534 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_31_GPIO_MUX1_IO31 0x08C 0x2D0 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_31_FLEXIO1_D31 0x08C 0x2D0 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_EMC_B1_32_GPIO8_IO00 0x090 0x2D4 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_32_SEMC_DATA10 0x090 0x2D4 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_32_FLEXPWM3_PWM1_B 0x090 0x2D4 0x544 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_32_GPIO_MUX2_IO00 0x090 0x2D4 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_EMC_B1_33_SEMC_DATA11 0x094 0x2D8 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_33_FLEXPWM3_PWM2_A 0x094 0x2D8 0x538 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_33_GPIO_MUX2_IO01 0x094 0x2D8 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_33_GPIO8_IO01 0x094 0x2D8 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_34_GPIO8_IO02 0x098 0x2DC 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_34_SEMC_DATA12 0x098 0x2DC 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_34_FLEXPWM3_PWM2_B 0x098 0x2DC 0x548 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_34_GPIO_MUX2_IO02 0x098 0x2DC 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_EMC_B1_35_GPIO8_IO03 0x09C 0x2E0 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_35_SEMC_DATA13 0x09C 0x2E0 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_35_XBAR1_INOUT09 0x09C 0x2E0 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_35_GPIO_MUX2_IO03 0x09C 0x2E0 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_EMC_B1_36_SEMC_DATA14 0x0A0 0x2E4 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_36_XBAR1_INOUT10 0x0A0 0x2E4 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_36_GPIO_MUX2_IO04 0x0A0 0x2E4 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_36_GPIO8_IO04 0x0A0 0x2E4 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_37_GPIO8_IO05 0x0A4 0x2E8 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_37_SEMC_DATA15 0x0A4 0x2E8 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_37_XBAR1_INOUT11 0x0A4 0x2E8 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_37_GPIO_MUX2_IO05 0x0A4 0x2E8 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_EMC_B1_38_GPIO8_IO06 0x0A8 0x2EC 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_38_SEMC_DM01 0x0A8 0x2EC 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_38_FLEXPWM1_PWM3_A 0x0A8 0x2EC 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_38_TMR1_TIMER1 0x0A8 0x2EC 0x640 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_38_GPIO_MUX2_IO06 0x0A8 0x2EC 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_EMC_B1_39_SEMC_DQS 0x0AC 0x2F0 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_39_FLEXPWM1_PWM3_B 0x0AC 0x2F0 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_39_TMR2_TIMER1 0x0AC 0x2F0 0x64C 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_39_GPIO_MUX2_IO07 0x0AC 0x2F0 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_39_GPIO8_IO07 0x0AC 0x2F0 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_40_SEMC_RDY 0x0B0 0x2F4 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_40_XBAR1_INOUT12 0x0B0 0x2F4 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_40_MQS_RIGHT 0x0B0 0x2F4 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_40_LPUART6_TXD 0x0B0 0x2F4 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B1_40_GPIO_MUX2_IO08 0x0B0 0x2F4 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_40_ENET_1G_MDC 0x0B0 0x2F4 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B1_40_CCM_CLKO1 0x0B0 0x2F4 0x0 0x9 0x0
+#define IOMUXC_GPIO_EMC_B1_40_GPIO8_IO08 0x0B0 0x2F4 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B1_41_GPIO8_IO09 0x0B4 0x2F8 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B1_41_SEMC_CSX00 0x0B4 0x2F8 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B1_41_XBAR1_INOUT13 0x0B4 0x2F8 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B1_41_MQS_LEFT 0x0B4 0x2F8 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B1_41_LPUART6_RXD 0x0B4 0x2F8 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B1_41_FLEXSPI2_B_DATA07 0x0B4 0x2F8 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B1_41_GPIO_MUX2_IO09 0x0B4 0x2F8 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B1_41_ENET_1G_MDIO 0x0B4 0x2F8 0x4C8 0x7 0x0
+#define IOMUXC_GPIO_EMC_B1_41_CCM_CLKO2 0x0B4 0x2F8 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_EMC_B2_00_SEMC_DATA16 0x0B8 0x2FC 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_00_CCM_ENET_REF_CLK_25M 0x0B8 0x2FC 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_00_TMR3_TIMER1 0x0B8 0x2FC 0x658 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_00_LPUART6_CTS_B 0x0B8 0x2FC 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_00_FLEXSPI2_B_DATA06 0x0B8 0x2FC 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_00_GPIO_MUX2_IO10 0x0B8 0x2FC 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_00_XBAR1_INOUT20 0x0B8 0x2FC 0x6D8 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_00_ENET_QOS_1588_EVENT1_OUT 0x0B8 0x2FC 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_00_LPSPI1_SCK 0x0B8 0x2FC 0x5D0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_00_LPI2C2_SCL 0x0B8 0x2FC 0x5B4 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_00_GPIO8_IO10 0x0B8 0x2FC 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_00_FLEXPWM3_PWM0_A 0x0B8 0x2FC 0x530 0xB 0x1
+
+#define IOMUXC_GPIO_EMC_B2_01_SEMC_DATA17 0x0BC 0x300 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_01_USDHC2_CD_B 0x0BC 0x300 0x6D0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_01_TMR4_TIMER1 0x0BC 0x300 0x664 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_01_LPUART6_RTS_B 0x0BC 0x300 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_01_FLEXSPI2_B_DATA05 0x0BC 0x300 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_01_GPIO_MUX2_IO11 0x0BC 0x300 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_01_XBAR1_INOUT21 0x0BC 0x300 0x6DC 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_01_ENET_QOS_1588_EVENT1_IN 0x0BC 0x300 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_01_LPSPI1_PCS0 0x0BC 0x300 0x5CC 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_01_LPI2C2_SDA 0x0BC 0x300 0x5B8 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_01_GPIO8_IO11 0x0BC 0x300 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_01_FLEXPWM3_PWM0_B 0x0BC 0x300 0x540 0xB 0x1
+
+#define IOMUXC_GPIO_EMC_B2_02_SEMC_DATA18 0x0C0 0x304 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_02_USDHC2_WP 0x0C0 0x304 0x6D4 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_02_VIDEO_MUX_CSI_DATA23 0x0C0 0x304 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_02_FLEXSPI2_B_DATA04 0x0C0 0x304 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_02_GPIO_MUX2_IO12 0x0C0 0x304 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_02_XBAR1_INOUT22 0x0C0 0x304 0x6E0 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_02_ENET_QOS_1588_EVENT1_AUX_IN 0x0C0 0x304 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_02_LPSPI1_SOUT 0x0C0 0x304 0x5D8 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_02_GPIO8_IO12 0x0C0 0x304 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_02_FLEXPWM3_PWM1_A 0x0C0 0x304 0x534 0xB 0x1
+
+#define IOMUXC_GPIO_EMC_B2_03_SEMC_DATA19 0x0C4 0x308 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_03_USDHC2_VSELECT 0x0C4 0x308 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_03_VIDEO_MUX_CSI_DATA22 0x0C4 0x308 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_03_FLEXSPI2_B_DATA03 0x0C4 0x308 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_03_GPIO_MUX2_IO13 0x0C4 0x308 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_03_XBAR1_INOUT23 0x0C4 0x308 0x6E4 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_03_ENET_1G_TX_DATA03 0x0C4 0x308 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_03_LPSPI1_SIN 0x0C4 0x308 0x5D4 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_03_GPIO8_IO13 0x0C4 0x308 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_03_FLEXPWM3_PWM1_B 0x0C4 0x308 0x544 0xB 0x1
+
+#define IOMUXC_GPIO_EMC_B2_04_SEMC_DATA20 0x0C8 0x30C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_04_USDHC2_RESET_B 0x0C8 0x30C 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_04_SAI2_MCLK 0x0C8 0x30C 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_04_VIDEO_MUX_CSI_DATA21 0x0C8 0x30C 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_04_FLEXSPI2_B_DATA02 0x0C8 0x30C 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_04_GPIO_MUX2_IO14 0x0C8 0x30C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_04_XBAR1_INOUT24 0x0C8 0x30C 0x6E8 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_04_ENET_1G_TX_DATA02 0x0C8 0x30C 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_04_LPSPI3_SCK 0x0C8 0x30C 0x600 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_04_GPIO8_IO14 0x0C8 0x30C 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_04_FLEXPWM3_PWM2_A 0x0C8 0x30C 0x538 0xB 0x1
+
+#define IOMUXC_GPIO_EMC_B2_05_SEMC_DATA21 0x0CC 0x310 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_05_GPT3_CLK 0x0CC 0x310 0x598 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_05_SAI2_RX_SYNC 0x0CC 0x310 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_05_VIDEO_MUX_CSI_DATA20 0x0CC 0x310 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_05_FLEXSPI2_B_DATA01 0x0CC 0x310 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_05_GPIO_MUX2_IO15 0x0CC 0x310 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_05_XBAR1_INOUT25 0x0CC 0x310 0x6EC 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_05_ENET_1G_RX_CLK 0x0CC 0x310 0x4CC 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_05_LPSPI3_PCS0 0x0CC 0x310 0x5F0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_05_PIT1_TRIGGER0 0x0CC 0x310 0x0 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_05_GPIO8_IO15 0x0CC 0x310 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_05_FLEXPWM3_PWM2_B 0x0CC 0x310 0x548 0xB 0x1
+
+#define IOMUXC_GPIO_EMC_B2_06_SEMC_DATA22 0x0D0 0x314 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_06_GPT3_CAPTURE1 0x0D0 0x314 0x590 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_06_GPIO8_IO16 0x0D0 0x314 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_06_SAI2_RX_BCLK 0x0D0 0x314 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_06_FLEXPWM3_PWM3_A 0x0D0 0x314 0x53C 0xB 0x1
+#define IOMUXC_GPIO_EMC_B2_06_VIDEO_MUX_CSI_DATA19 0x0D0 0x314 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_06_FLEXSPI2_B_DATA00 0x0D0 0x314 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_06_GPIO_MUX2_IO16 0x0D0 0x314 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_06_XBAR1_INOUT26 0x0D0 0x314 0x6F0 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_06_ENET_1G_TX_ER 0x0D0 0x314 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_06_LPSPI3_SOUT 0x0D0 0x314 0x608 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_06_PIT1_TRIGGER1 0x0D0 0x314 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_EMC_B2_07_SEMC_DATA23 0x0D4 0x318 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_07_GPT3_CAPTURE2 0x0D4 0x318 0x594 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_07_SAI2_RX_DATA 0x0D4 0x318 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_07_VIDEO_MUX_CSI_DATA18 0x0D4 0x318 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_07_FLEXSPI2_B_DQS 0x0D4 0x318 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_07_GPIO_MUX2_IO17 0x0D4 0x318 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_07_XBAR1_INOUT27 0x0D4 0x318 0x6F4 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_07_ENET_1G_RX_DATA03 0x0D4 0x318 0x4DC 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_07_LPSPI3_SIN 0x0D4 0x318 0x604 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_07_PIT1_TRIGGER2 0x0D4 0x318 0x0 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_07_GPIO8_IO17 0x0D4 0x318 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_07_FLEXPWM3_PWM3_B 0x0D4 0x318 0x54C 0xB 0x1
+
+#define IOMUXC_GPIO_EMC_B2_08_SEMC_DM02 0x0D8 0x31C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_08_GPT3_COMPARE1 0x0D8 0x31C 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_08_SAI2_TX_DATA 0x0D8 0x31C 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_08_VIDEO_MUX_CSI_DATA17 0x0D8 0x31C 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_08_FLEXSPI2_B_SS0_B 0x0D8 0x31C 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_08_GPIO_MUX2_IO18 0x0D8 0x31C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_08_XBAR1_INOUT28 0x0D8 0x31C 0x6F8 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_08_ENET_1G_RX_DATA02 0x0D8 0x31C 0x4D8 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_08_LPSPI3_PCS1 0x0D8 0x31C 0x5F4 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_08_PIT1_TRIGGER3 0x0D8 0x31C 0x0 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_08_GPIO8_IO18 0x0D8 0x31C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B2_09_GPIO8_IO19 0x0DC 0x320 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_09_SEMC_DATA24 0x0DC 0x320 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_09_GPT3_COMPARE2 0x0DC 0x320 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_09_SAI2_TX_BCLK 0x0DC 0x320 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_09_VIDEO_MUX_CSI_DATA16 0x0DC 0x320 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_09_FLEXSPI2_B_SCLK 0x0DC 0x320 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_09_GPIO_MUX2_IO19 0x0DC 0x320 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_09_XBAR1_INOUT29 0x0DC 0x320 0x6FC 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_09_ENET_1G_CRS 0x0DC 0x320 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_09_LPSPI3_PCS2 0x0DC 0x320 0x5F8 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_09_TMR1_TIMER0 0x0DC 0x320 0x63C 0x9 0x1
+
+#define IOMUXC_GPIO_EMC_B2_10_GPIO8_IO20 0x0E0 0x324 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_10_SEMC_DATA25 0x0E0 0x324 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_10_GPT3_COMPARE3 0x0E0 0x324 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_10_SAI2_TX_SYNC 0x0E0 0x324 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_10_VIDEO_MUX_CSI_FIELD 0x0E0 0x324 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_10_FLEXSPI2_A_SCLK 0x0E0 0x324 0x58C 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_10_GPIO_MUX2_IO20 0x0E0 0x324 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_10_XBAR1_INOUT30 0x0E0 0x324 0x700 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_10_ENET_1G_COL 0x0E0 0x324 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_10_LPSPI3_PCS3 0x0E0 0x324 0x5FC 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_10_TMR1_TIMER1 0x0E0 0x324 0x640 0x9 0x1
+
+#define IOMUXC_GPIO_EMC_B2_11_SEMC_DATA26 0x0E4 0x328 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_11_SPDIF_IN 0x0E4 0x328 0x6B4 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_11_ENET_1G_TX_DATA00 0x0E4 0x328 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_11_SAI3_RX_SYNC 0x0E4 0x328 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_11_FLEXSPI2_A_SS0_B 0x0E4 0x328 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_11_GPIO_MUX2_IO21 0x0E4 0x328 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_11_XBAR1_INOUT31 0x0E4 0x328 0x704 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_11_EMVSIM1_IO 0x0E4 0x328 0x69C 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_11_TMR1_TIMER2 0x0E4 0x328 0x644 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_11_GPIO8_IO21 0x0E4 0x328 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B2_12_SEMC_DATA27 0x0E8 0x32C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_12_SPDIF_OUT 0x0E8 0x32C 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_12_ENET_1G_TX_DATA01 0x0E8 0x32C 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_12_SAI3_RX_BCLK 0x0E8 0x32C 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_12_FLEXSPI2_A_DQS 0x0E8 0x32C 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_12_GPIO_MUX2_IO22 0x0E8 0x32C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_12_XBAR1_INOUT32 0x0E8 0x32C 0x708 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_12_EMVSIM1_CLK 0x0E8 0x32C 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_12_TMR1_TIMER3 0x0E8 0x32C 0x0 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_12_GPIO8_IO22 0x0E8 0x32C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B2_13_GPIO8_IO23 0x0EC 0x330 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_13_SEMC_DATA28 0x0EC 0x330 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_13_ENET_1G_TX_EN 0x0EC 0x330 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_13_SAI3_RX_DATA 0x0EC 0x330 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_13_FLEXSPI2_A_DATA00 0x0EC 0x330 0x57C 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_13_GPIO_MUX2_IO23 0x0EC 0x330 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_13_XBAR1_INOUT33 0x0EC 0x330 0x70C 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_13_EMVSIM1_RST 0x0EC 0x330 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_13_TMR2_TIMER0 0x0EC 0x330 0x648 0x9 0x1
+
+#define IOMUXC_GPIO_EMC_B2_14_SEMC_DATA29 0x0F0 0x334 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_14_ENET_1G_TX_CLK_IO 0x0F0 0x334 0x4E8 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_14_SAI3_TX_DATA 0x0F0 0x334 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_14_FLEXSPI2_A_DATA01 0x0F0 0x334 0x580 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_14_GPIO_MUX2_IO24 0x0F0 0x334 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_14_XBAR1_INOUT34 0x0F0 0x334 0x710 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_14_SFA_ipp_do_atx_clk_under_test 0x0F0 0x334 0x0 0x7 0x0
+#define IOMUXC_GPIO_EMC_B2_14_EMVSIM1_SVEN 0x0F0 0x334 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_14_TMR2_TIMER1 0x0F0 0x334 0x64C 0x9 0x1
+#define IOMUXC_GPIO_EMC_B2_14_GPIO8_IO24 0x0F0 0x334 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B2_15_SEMC_DATA30 0x0F4 0x338 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_15_ENET_1G_RX_DATA00 0x0F4 0x338 0x4D0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_15_SAI3_TX_BCLK 0x0F4 0x338 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_15_FLEXSPI2_A_DATA02 0x0F4 0x338 0x584 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_15_GPIO_MUX2_IO25 0x0F4 0x338 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_15_XBAR1_INOUT35 0x0F4 0x338 0x714 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_15_EMVSIM1_PD 0x0F4 0x338 0x6A0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_15_TMR2_TIMER2 0x0F4 0x338 0x650 0x9 0x0
+#define IOMUXC_GPIO_EMC_B2_15_GPIO8_IO25 0x0F4 0x338 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B2_16_GPIO8_IO26 0x0F8 0x33C 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_16_SEMC_DATA31 0x0F8 0x33C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_16_XBAR1_INOUT14 0x0F8 0x33C 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_16_ENET_1G_RX_DATA01 0x0F8 0x33C 0x4D4 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_16_SAI3_TX_SYNC 0x0F8 0x33C 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_16_FLEXSPI2_A_DATA03 0x0F8 0x33C 0x588 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_16_GPIO_MUX2_IO26 0x0F8 0x33C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_16_EMVSIM1_POWER_FAIL 0x0F8 0x33C 0x6A4 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_16_TMR2_TIMER3 0x0F8 0x33C 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_EMC_B2_17_SEMC_DM03 0x0FC 0x340 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_17_XBAR1_INOUT15 0x0FC 0x340 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_17_ENET_1G_RX_EN 0x0FC 0x340 0x4E0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_17_SAI3_MCLK 0x0FC 0x340 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_17_FLEXSPI2_A_DATA04 0x0FC 0x340 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_17_GPIO_MUX2_IO27 0x0FC 0x340 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_17_WDOG1_ANY 0x0FC 0x340 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_17_TMR3_TIMER0 0x0FC 0x340 0x654 0x9 0x1
+#define IOMUXC_GPIO_EMC_B2_17_GPIO8_IO27 0x0FC 0x340 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B2_18_SEMC_DQS4 0x100 0x344 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_18_XBAR1_INOUT16 0x100 0x344 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_18_ENET_1G_RX_ER 0x100 0x344 0x4E4 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_18_EWM_OUT_B 0x100 0x344 0x0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_18_FLEXSPI2_A_DATA05 0x100 0x344 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_18_GPIO_MUX2_IO28 0x100 0x344 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_18_FLEXSPI1_A_DQS 0x100 0x344 0x550 0x6 0x0
+#define IOMUXC_GPIO_EMC_B2_18_WDOG1_B 0x100 0x344 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_18_TMR3_TIMER1 0x100 0x344 0x658 0x9 0x1
+#define IOMUXC_GPIO_EMC_B2_18_GPIO8_IO28 0x100 0x344 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_EMC_B2_19_GPIO8_IO29 0x104 0x348 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_19_SEMC_CLKX00 0x104 0x348 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_19_ENET_MDC 0x104 0x348 0x0 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_19_ENET_1G_MDC 0x104 0x348 0x0 0x2 0x0
+#define IOMUXC_GPIO_EMC_B2_19_ENET_1G_REF_CLK 0x104 0x348 0x4C4 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_19_FLEXSPI2_A_DATA06 0x104 0x348 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_19_GPIO_MUX2_IO29 0x104 0x348 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_19_ENET_QOS_MDC 0x104 0x348 0x0 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_19_TMR3_TIMER2 0x104 0x348 0x65C 0x9 0x0
+
+#define IOMUXC_GPIO_EMC_B2_20_GPIO8_IO30 0x108 0x34C 0x0 0xA 0x0
+#define IOMUXC_GPIO_EMC_B2_20_SEMC_CLKX01 0x108 0x34C 0x0 0x0 0x0
+#define IOMUXC_GPIO_EMC_B2_20_ENET_MDIO 0x108 0x34C 0x4AC 0x1 0x0
+#define IOMUXC_GPIO_EMC_B2_20_ENET_1G_MDIO 0x108 0x34C 0x4C8 0x2 0x1
+#define IOMUXC_GPIO_EMC_B2_20_ENET_QOS_REF_CLK 0x108 0x34C 0x4A0 0x3 0x0
+#define IOMUXC_GPIO_EMC_B2_20_FLEXSPI2_A_DATA07 0x108 0x34C 0x0 0x4 0x0
+#define IOMUXC_GPIO_EMC_B2_20_GPIO_MUX2_IO30 0x108 0x34C 0x0 0x5 0x0
+#define IOMUXC_GPIO_EMC_B2_20_ENET_QOS_MDIO 0x108 0x34C 0x4EC 0x8 0x0
+#define IOMUXC_GPIO_EMC_B2_20_TMR3_TIMER3 0x108 0x34C 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_00_GPIO8_IO31 0x10C 0x350 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_00_EMVSIM1_IO 0x10C 0x350 0x69C 0x0 0x1
+#define IOMUXC_GPIO_AD_00_FLEXCAN2_TX 0x10C 0x350 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_00_ENET_1G_1588_EVENT1_IN 0x10C 0x350 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_00_GPT2_CAPTURE1 0x10C 0x350 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_00_FLEXPWM1_PWM0_A 0x10C 0x350 0x500 0x4 0x1
+#define IOMUXC_GPIO_AD_00_GPIO_MUX2_IO31 0x10C 0x350 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_00_LPUART7_TXD 0x10C 0x350 0x630 0x6 0x0
+#define IOMUXC_GPIO_AD_00_FLEXIO2_D00 0x10C 0x350 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_00_FLEXSPI2_B_SS1_B 0x10C 0x350 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_01_GPIO9_IO00 0x110 0x354 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_01_EMVSIM1_CLK 0x110 0x354 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_01_FLEXCAN2_RX 0x110 0x354 0x49C 0x1 0x0
+#define IOMUXC_GPIO_AD_01_ENET_1G_1588_EVENT1_OUT 0x110 0x354 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_01_GPT2_CAPTURE2 0x110 0x354 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_01_FLEXPWM1_PWM0_B 0x110 0x354 0x50C 0x4 0x1
+#define IOMUXC_GPIO_AD_01_GPIO_MUX3_IO00 0x110 0x354 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_01_LPUART7_RXD 0x110 0x354 0x62C 0x6 0x0
+#define IOMUXC_GPIO_AD_01_FLEXIO2_D01 0x110 0x354 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_01_FLEXSPI2_A_SS1_B 0x110 0x354 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_02_GPIO9_IO01 0x114 0x358 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_02_EMVSIM1_RST 0x114 0x358 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_02_LPUART7_CTS_B 0x114 0x358 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_02_ENET_1G_1588_EVENT2_IN 0x114 0x358 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_02_GPT2_COMPARE1 0x114 0x358 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_02_FLEXPWM1_PWM1_A 0x114 0x358 0x504 0x4 0x1
+#define IOMUXC_GPIO_AD_02_GPIO_MUX3_IO01 0x114 0x358 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_02_LPUART8_TXD 0x114 0x358 0x638 0x6 0x0
+#define IOMUXC_GPIO_AD_02_FLEXIO2_D02 0x114 0x358 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_02_VIDEO_MUX_EXT_DCIC1 0x114 0x358 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_03_GPIO9_IO02 0x118 0x35C 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_03_EMVSIM1_SVEN 0x118 0x35C 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_03_LPUART7_RTS_B 0x118 0x35C 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_03_ENET_1G_1588_EVENT2_OUT 0x118 0x35C 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_03_GPT2_COMPARE2 0x118 0x35C 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_03_FLEXPWM1_PWM1_B 0x118 0x35C 0x510 0x4 0x1
+#define IOMUXC_GPIO_AD_03_GPIO_MUX3_IO02 0x118 0x35C 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_03_LPUART8_RXD 0x118 0x35C 0x634 0x6 0x0
+#define IOMUXC_GPIO_AD_03_FLEXIO2_D03 0x118 0x35C 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_03_VIDEO_MUX_EXT_DCIC2 0x118 0x35C 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_04_EMVSIM1_PD 0x11C 0x360 0x6A0 0x0 0x1
+#define IOMUXC_GPIO_AD_04_LPUART8_CTS_B 0x11C 0x360 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_04_ENET_1G_1588_EVENT3_IN 0x11C 0x360 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_04_GPT2_COMPARE3 0x11C 0x360 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_04_FLEXPWM1_PWM2_A 0x11C 0x360 0x508 0x4 0x1
+#define IOMUXC_GPIO_AD_04_GPIO_MUX3_IO03 0x11C 0x360 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_04_WDOG1_B 0x11C 0x360 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_04_FLEXIO2_D04 0x11C 0x360 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_04_TMR4_TIMER0 0x11C 0x360 0x660 0x9 0x1
+#define IOMUXC_GPIO_AD_04_GPIO9_IO03 0x11C 0x360 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_05_EMVSIM1_POWER_FAIL 0x120 0x364 0x6A4 0x0 0x1
+#define IOMUXC_GPIO_AD_05_LPUART8_RTS_B 0x120 0x364 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_05_ENET_1G_1588_EVENT3_OUT 0x120 0x364 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_05_GPT2_CLK 0x120 0x364 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_05_FLEXPWM1_PWM2_B 0x120 0x364 0x514 0x4 0x1
+#define IOMUXC_GPIO_AD_05_GPIO_MUX3_IO04 0x120 0x364 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_05_WDOG2_B 0x120 0x364 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_05_FLEXIO2_D05 0x120 0x364 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_05_TMR4_TIMER1 0x120 0x364 0x664 0x9 0x1
+#define IOMUXC_GPIO_AD_05_GPIO9_IO04 0x120 0x364 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_06_USB_OTG2_OC 0x124 0x368 0x6B8 0x0 0x0
+#define IOMUXC_GPIO_AD_06_FLEXCAN1_TX 0x124 0x368 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_06_EMVSIM2_IO 0x124 0x368 0x6A8 0x2 0x0
+#define IOMUXC_GPIO_AD_06_GPT3_CAPTURE1 0x124 0x368 0x590 0x3 0x1
+#define IOMUXC_GPIO_AD_06_VIDEO_MUX_CSI_DATA15 0x124 0x368 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_06_GPIO_MUX3_IO05 0x124 0x368 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_06_ENET_1588_EVENT1_IN 0x124 0x368 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_06_FLEXIO2_D06 0x124 0x368 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_06_TMR4_TIMER2 0x124 0x368 0x668 0x9 0x0
+#define IOMUXC_GPIO_AD_06_GPIO9_IO05 0x124 0x368 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_06_FLEXPWM1_PWM0_X 0x124 0x368 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_07_USB_OTG2_PWR 0x128 0x36C 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_07_FLEXCAN1_RX 0x128 0x36C 0x498 0x1 0x0
+#define IOMUXC_GPIO_AD_07_EMVSIM2_CLK 0x128 0x36C 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_07_GPT3_CAPTURE2 0x128 0x36C 0x594 0x3 0x1
+#define IOMUXC_GPIO_AD_07_VIDEO_MUX_CSI_DATA14 0x128 0x36C 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_07_GPIO_MUX3_IO06 0x128 0x36C 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_07_ENET_1588_EVENT1_OUT 0x128 0x36C 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_07_FLEXIO2_D07 0x128 0x36C 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_07_TMR4_TIMER3 0x128 0x36C 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_07_GPIO9_IO06 0x128 0x36C 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_07_FLEXPWM1_PWM1_X 0x128 0x36C 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_08_USBPHY2_OTG_ID 0x12C 0x370 0x6C4 0x0 0x0
+#define IOMUXC_GPIO_AD_08_LPI2C1_SCL 0x12C 0x370 0x5AC 0x1 0x0
+#define IOMUXC_GPIO_AD_08_EMVSIM2_RST 0x12C 0x370 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_08_GPT3_COMPARE1 0x12C 0x370 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_08_VIDEO_MUX_CSI_DATA13 0x12C 0x370 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_08_GPIO_MUX3_IO07 0x12C 0x370 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_08_ENET_1588_EVENT2_IN 0x12C 0x370 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_08_FLEXIO2_D08 0x12C 0x370 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_08_GPIO9_IO07 0x12C 0x370 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_08_FLEXPWM1_PWM2_X 0x12C 0x370 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_09_USBPHY1_OTG_ID 0x130 0x374 0x6C0 0x0 0x0
+#define IOMUXC_GPIO_AD_09_LPI2C1_SDA 0x130 0x374 0x5B0 0x1 0x0
+#define IOMUXC_GPIO_AD_09_EMVSIM2_SVEN 0x130 0x374 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_09_GPT3_COMPARE2 0x130 0x374 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_09_VIDEO_MUX_CSI_DATA12 0x130 0x374 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_09_GPIO_MUX3_IO08 0x130 0x374 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_09_ENET_1588_EVENT2_OUT 0x130 0x374 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_09_FLEXIO2_D09 0x130 0x374 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_09_GPIO9_IO08 0x130 0x374 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_09_FLEXPWM1_PWM3_X 0x130 0x374 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_10_USB_OTG1_PWR 0x134 0x378 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_10_LPI2C1_SCLS 0x134 0x378 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_10_EMVSIM2_PD 0x134 0x378 0x6AC 0x2 0x0
+#define IOMUXC_GPIO_AD_10_GPT3_COMPARE3 0x134 0x378 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_10_VIDEO_MUX_CSI_DATA11 0x134 0x378 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_10_GPIO_MUX3_IO09 0x134 0x378 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_10_ENET_1588_EVENT3_IN 0x134 0x378 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_10_FLEXIO2_D10 0x134 0x378 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_10_GPIO9_IO09 0x134 0x378 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_10_FLEXPWM2_PWM0_X 0x134 0x378 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_11_USB_OTG1_OC 0x138 0x37C 0x6BC 0x0 0x0
+#define IOMUXC_GPIO_AD_11_LPI2C1_SDAS 0x138 0x37C 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_11_EMVSIM2_POWER_FAIL 0x138 0x37C 0x6B0 0x2 0x0
+#define IOMUXC_GPIO_AD_11_GPT3_CLK 0x138 0x37C 0x598 0x3 0x1
+#define IOMUXC_GPIO_AD_11_VIDEO_MUX_CSI_DATA10 0x138 0x37C 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_11_GPIO_MUX3_IO10 0x138 0x37C 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_11_ENET_1588_EVENT3_OUT 0x138 0x37C 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_11_FLEXIO2_D11 0x138 0x37C 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_11_GPIO9_IO10 0x138 0x37C 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_11_FLEXPWM2_PWM1_X 0x138 0x37C 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_12_SPDIF_LOCK 0x13C 0x380 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_12_LPI2C1_HREQ 0x13C 0x380 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_12_GPT1_CAPTURE1 0x13C 0x380 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_12_FLEXSPI1_B_DATA03 0x13C 0x380 0x570 0x3 0x0
+#define IOMUXC_GPIO_AD_12_VIDEO_MUX_CSI_PIXCLK 0x13C 0x380 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_12_GPIO_MUX3_IO11 0x13C 0x380 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_12_ENET_TX_DATA03 0x13C 0x380 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_12_FLEXIO2_D12 0x13C 0x380 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_12_EWM_OUT_B 0x13C 0x380 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_12_GPIO9_IO11 0x13C 0x380 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_12_FLEXPWM2_PWM2_X 0x13C 0x380 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_13_SPDIF_SR_CLK 0x140 0x384 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_13_PIT1_TRIGGER0 0x140 0x384 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_13_GPT1_CAPTURE2 0x140 0x384 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_13_FLEXSPI1_B_DATA02 0x140 0x384 0x56C 0x3 0x0
+#define IOMUXC_GPIO_AD_13_VIDEO_MUX_CSI_MCLK 0x140 0x384 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_13_GPIO_MUX3_IO12 0x140 0x384 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_13_ENET_TX_DATA02 0x140 0x384 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_13_FLEXIO2_D13 0x140 0x384 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_13_REF_CLK_32K 0x140 0x384 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_13_GPIO9_IO12 0x140 0x384 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_13_FLEXPWM2_PWM3_X 0x140 0x384 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_14_SPDIF_EXT_CLK 0x144 0x388 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_14_REF_CLK_24M 0x144 0x388 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_14_GPT1_COMPARE1 0x144 0x388 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_14_FLEXSPI1_B_DATA01 0x144 0x388 0x568 0x3 0x0
+#define IOMUXC_GPIO_AD_14_VIDEO_MUX_CSI_VSYNC 0x144 0x388 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_14_GPIO_MUX3_IO13 0x144 0x388 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_14_ENET_RX_CLK 0x144 0x388 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_14_FLEXIO2_D14 0x144 0x388 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_14_CCM_ENET_REF_CLK_25M 0x144 0x388 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_14_GPIO9_IO13 0x144 0x388 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_14_FLEXPWM3_PWM0_X 0x144 0x388 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_15_GPIO9_IO14 0x148 0x38C 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_15_FLEXPWM3_PWM1_X 0x148 0x38C 0x0 0xB 0x0
+#define IOMUXC_GPIO_AD_15_SPDIF_IN 0x148 0x38C 0x6B4 0x0 0x1
+#define IOMUXC_GPIO_AD_15_LPUART10_TXD 0x148 0x38C 0x628 0x1 0x0
+#define IOMUXC_GPIO_AD_15_GPT1_COMPARE2 0x148 0x38C 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_15_FLEXSPI1_B_DATA00 0x148 0x38C 0x564 0x3 0x0
+#define IOMUXC_GPIO_AD_15_VIDEO_MUX_CSI_HSYNC 0x148 0x38C 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_15_GPIO_MUX3_IO14 0x148 0x38C 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_15_ENET_TX_ER 0x148 0x38C 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_15_FLEXIO2_D15 0x148 0x38C 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_AD_16_SPDIF_OUT 0x14C 0x390 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_16_LPUART10_RXD 0x14C 0x390 0x624 0x1 0x0
+#define IOMUXC_GPIO_AD_16_GPT1_COMPARE3 0x14C 0x390 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_16_FLEXSPI1_B_SCLK 0x14C 0x390 0x578 0x3 0x0
+#define IOMUXC_GPIO_AD_16_VIDEO_MUX_CSI_DATA09 0x14C 0x390 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_16_GPIO_MUX3_IO15 0x14C 0x390 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_16_ENET_RX_DATA03 0x14C 0x390 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_16_FLEXIO2_D16 0x14C 0x390 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_16_ENET_1G_MDC 0x14C 0x390 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_16_GPIO9_IO15 0x14C 0x390 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_16_FLEXPWM3_PWM2_X 0x14C 0x390 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_17_SAI1_MCLK 0x150 0x394 0x66C 0x0 0x0
+#define IOMUXC_GPIO_AD_17_ACMP1_OUT 0x150 0x394 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_17_GPT1_CLK 0x150 0x394 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_17_FLEXSPI1_A_DQS 0x150 0x394 0x550 0x3 0x1
+#define IOMUXC_GPIO_AD_17_VIDEO_MUX_CSI_DATA08 0x150 0x394 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_17_GPIO_MUX3_IO16 0x150 0x394 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_17_ENET_RX_DATA02 0x150 0x394 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_17_FLEXIO2_D17 0x150 0x394 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_17_ENET_1G_MDIO 0x150 0x394 0x4C8 0x9 0x2
+#define IOMUXC_GPIO_AD_17_GPIO9_IO16 0x150 0x394 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_17_FLEXPWM3_PWM3_X 0x150 0x394 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_18_GPIO9_IO17 0x154 0x398 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_18_FLEXPWM4_PWM0_X 0x154 0x398 0x0 0xB 0x0
+#define IOMUXC_GPIO_AD_18_SAI1_RX_SYNC 0x154 0x398 0x678 0x0 0x0
+#define IOMUXC_GPIO_AD_18_ACMP2_OUT 0x154 0x398 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_18_LPSPI1_PCS1 0x154 0x398 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_18_FLEXSPI1_A_SS0_B 0x154 0x398 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_18_VIDEO_MUX_CSI_DATA07 0x154 0x398 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_18_GPIO_MUX3_IO17 0x154 0x398 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_18_ENET_CRS 0x154 0x398 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_18_FLEXIO2_D18 0x154 0x398 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_18_LPI2C2_SCL 0x154 0x398 0x5B4 0x9 0x1
+
+#define IOMUXC_GPIO_AD_19_SAI1_RX_BCLK 0x158 0x39C 0x670 0x0 0x0
+#define IOMUXC_GPIO_AD_19_ACMP3_OUT 0x158 0x39C 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_19_LPSPI1_PCS2 0x158 0x39C 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_19_FLEXSPI1_A_SCLK 0x158 0x39C 0x574 0x3 0x0
+#define IOMUXC_GPIO_AD_19_VIDEO_MUX_CSI_DATA06 0x158 0x39C 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_19_GPIO_MUX3_IO18 0x158 0x39C 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_19_ENET_COL 0x158 0x39C 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_19_FLEXIO2_D19 0x158 0x39C 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_19_LPI2C2_SDA 0x158 0x39C 0x5B8 0x9 0x1
+#define IOMUXC_GPIO_AD_19_GPIO9_IO18 0x158 0x39C 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_19_FLEXPWM4_PWM1_X 0x158 0x39C 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_20_SAI1_RX_DATA00 0x15C 0x3A0 0x674 0x0 0x0
+#define IOMUXC_GPIO_AD_20_ACMP4_OUT 0x15C 0x3A0 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_20_LPSPI1_PCS3 0x15C 0x3A0 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_20_FLEXSPI1_A_DATA00 0x15C 0x3A0 0x554 0x3 0x0
+#define IOMUXC_GPIO_AD_20_VIDEO_MUX_CSI_DATA05 0x15C 0x3A0 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_20_GPIO_MUX3_IO19 0x15C 0x3A0 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_20_KPP_ROW07 0x15C 0x3A0 0x5A8 0x6 0x0
+#define IOMUXC_GPIO_AD_20_FLEXIO2_D20 0x15C 0x3A0 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_20_ENET_QOS_1588_EVENT2_OUT 0x15C 0x3A0 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_20_GPIO9_IO19 0x15C 0x3A0 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_20_FLEXPWM4_PWM2_X 0x15C 0x3A0 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_21_SAI1_TX_DATA00 0x160 0x3A4 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_21_LPSPI2_PCS1 0x160 0x3A4 0x5E0 0x2 0x0
+#define IOMUXC_GPIO_AD_21_FLEXSPI1_A_DATA01 0x160 0x3A4 0x558 0x3 0x0
+#define IOMUXC_GPIO_AD_21_VIDEO_MUX_CSI_DATA04 0x160 0x3A4 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_21_GPIO_MUX3_IO20 0x160 0x3A4 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_21_KPP_COL07 0x160 0x3A4 0x5A0 0x6 0x0
+#define IOMUXC_GPIO_AD_21_FLEXIO2_D21 0x160 0x3A4 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_21_ENET_QOS_1588_EVENT2_IN 0x160 0x3A4 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_21_GPIO9_IO20 0x160 0x3A4 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_21_FLEXPWM4_PWM3_X 0x160 0x3A4 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_22_GPIO9_IO21 0x164 0x3A8 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_22_SAI1_TX_BCLK 0x164 0x3A8 0x67C 0x0 0x0
+#define IOMUXC_GPIO_AD_22_LPSPI2_PCS2 0x164 0x3A8 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_22_FLEXSPI1_A_DATA02 0x164 0x3A8 0x55C 0x3 0x0
+#define IOMUXC_GPIO_AD_22_VIDEO_MUX_CSI_DATA03 0x164 0x3A8 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_22_GPIO_MUX3_IO21 0x164 0x3A8 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_22_KPP_ROW06 0x164 0x3A8 0x5A4 0x6 0x0
+#define IOMUXC_GPIO_AD_22_FLEXIO2_D22 0x164 0x3A8 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_22_ENET_QOS_1588_EVENT3_OUT 0x164 0x3A8 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_23_SAI1_TX_SYNC 0x168 0x3AC 0x680 0x0 0x0
+#define IOMUXC_GPIO_AD_23_LPSPI2_PCS3 0x168 0x3AC 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_23_FLEXSPI1_A_DATA03 0x168 0x3AC 0x560 0x3 0x0
+#define IOMUXC_GPIO_AD_23_VIDEO_MUX_CSI_DATA02 0x168 0x3AC 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_23_GPIO_MUX3_IO22 0x168 0x3AC 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_23_KPP_COL06 0x168 0x3AC 0x59C 0x6 0x0
+#define IOMUXC_GPIO_AD_23_FLEXIO2_D23 0x168 0x3AC 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_23_ENET_QOS_1588_EVENT3_IN 0x168 0x3AC 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_23_GPIO9_IO22 0x168 0x3AC 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_24_LPUART1_TXD 0x16C 0x3B0 0x620 0x0 0x0
+#define IOMUXC_GPIO_AD_24_LPSPI2_SCK 0x16C 0x3B0 0x5E4 0x1 0x0
+#define IOMUXC_GPIO_AD_24_VIDEO_MUX_CSI_DATA00 0x16C 0x3B0 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_24_ENET_RX_EN 0x16C 0x3B0 0x4B8 0x3 0x0
+#define IOMUXC_GPIO_AD_24_FLEXPWM2_PWM0_A 0x16C 0x3B0 0x518 0x4 0x1
+#define IOMUXC_GPIO_AD_24_GPIO_MUX3_IO23 0x16C 0x3B0 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_24_KPP_ROW05 0x16C 0x3B0 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_24_FLEXIO2_D24 0x16C 0x3B0 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_24_LPI2C4_SCL 0x16C 0x3B0 0x5C4 0x9 0x0
+#define IOMUXC_GPIO_AD_24_GPIO9_IO23 0x16C 0x3B0 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_25_GPIO9_IO24 0x170 0x3B4 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_25_LPUART1_RXD 0x170 0x3B4 0x61C 0x0 0x0
+#define IOMUXC_GPIO_AD_25_LPSPI2_PCS0 0x170 0x3B4 0x5DC 0x1 0x0
+#define IOMUXC_GPIO_AD_25_VIDEO_MUX_CSI_DATA01 0x170 0x3B4 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_25_ENET_RX_ER 0x170 0x3B4 0x4BC 0x3 0x0
+#define IOMUXC_GPIO_AD_25_FLEXPWM2_PWM0_B 0x170 0x3B4 0x524 0x4 0x1
+#define IOMUXC_GPIO_AD_25_GPIO_MUX3_IO24 0x170 0x3B4 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_25_KPP_COL05 0x170 0x3B4 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_25_FLEXIO2_D25 0x170 0x3B4 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_25_LPI2C4_SDA 0x170 0x3B4 0x5C8 0x9 0x0
+
+#define IOMUXC_GPIO_AD_26_LPUART1_CTS_B 0x174 0x3B8 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_26_LPSPI2_SOUT 0x174 0x3B8 0x5EC 0x1 0x0
+#define IOMUXC_GPIO_AD_26_SEMC_CSX01 0x174 0x3B8 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_26_ENET_RX_DATA00 0x174 0x3B8 0x4B0 0x3 0x0
+#define IOMUXC_GPIO_AD_26_FLEXPWM2_PWM1_A 0x174 0x3B8 0x51C 0x4 0x1
+#define IOMUXC_GPIO_AD_26_GPIO_MUX3_IO25 0x174 0x3B8 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_26_KPP_ROW04 0x174 0x3B8 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_26_FLEXIO2_D26 0x174 0x3B8 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_26_ENET_QOS_MDC 0x174 0x3B8 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_26_GPIO9_IO25 0x174 0x3B8 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_26_USDHC2_CD_B 0x174 0x3B8 0x6D0 0xB 0x1
+
+#define IOMUXC_GPIO_AD_27_LPUART1_RTS_B 0x178 0x3BC 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_27_LPSPI2_SIN 0x178 0x3BC 0x5E8 0x1 0x0
+#define IOMUXC_GPIO_AD_27_SEMC_CSX02 0x178 0x3BC 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_27_ENET_RX_DATA01 0x178 0x3BC 0x4B4 0x3 0x0
+#define IOMUXC_GPIO_AD_27_FLEXPWM2_PWM1_B 0x178 0x3BC 0x528 0x4 0x1
+#define IOMUXC_GPIO_AD_27_GPIO_MUX3_IO26 0x178 0x3BC 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_27_KPP_COL04 0x178 0x3BC 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_27_FLEXIO2_D27 0x178 0x3BC 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_27_ENET_QOS_MDIO 0x178 0x3BC 0x4EC 0x9 0x1
+#define IOMUXC_GPIO_AD_27_GPIO9_IO26 0x178 0x3BC 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_27_USDHC2_WP 0x178 0x3BC 0x6D4 0xB 0x1
+
+#define IOMUXC_GPIO_AD_28_GPIO9_IO27 0x17C 0x3C0 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_28_USDHC2_VSELECT 0x17C 0x3C0 0x0 0xB 0x0
+#define IOMUXC_GPIO_AD_28_LPSPI1_SCK 0x17C 0x3C0 0x5D0 0x0 0x1
+#define IOMUXC_GPIO_AD_28_LPUART5_TXD 0x17C 0x3C0 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_28_SEMC_CSX03 0x17C 0x3C0 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_28_ENET_TX_EN 0x17C 0x3C0 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_28_FLEXPWM2_PWM2_A 0x17C 0x3C0 0x520 0x4 0x1
+#define IOMUXC_GPIO_AD_28_GPIO_MUX3_IO27 0x17C 0x3C0 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_28_KPP_ROW03 0x17C 0x3C0 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_28_FLEXIO2_D28 0x17C 0x3C0 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_28_VIDEO_MUX_EXT_DCIC1 0x17C 0x3C0 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_29_LPSPI1_PCS0 0x180 0x3C4 0x5CC 0x0 0x1
+#define IOMUXC_GPIO_AD_29_LPUART5_RXD 0x180 0x3C4 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_29_ENET_REF_CLK 0x180 0x3C4 0x4A8 0x2 0x0
+#define IOMUXC_GPIO_AD_29_ENET_TX_CLK 0x180 0x3C4 0x4C0 0x3 0x0
+#define IOMUXC_GPIO_AD_29_FLEXPWM2_PWM2_B 0x180 0x3C4 0x52C 0x4 0x1
+#define IOMUXC_GPIO_AD_29_GPIO_MUX3_IO28 0x180 0x3C4 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_29_KPP_COL03 0x180 0x3C4 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_29_FLEXIO2_D29 0x180 0x3C4 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_29_VIDEO_MUX_EXT_DCIC2 0x180 0x3C4 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_29_GPIO9_IO28 0x180 0x3C4 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_29_USDHC2_RESET_B 0x180 0x3C4 0x0 0xB 0x0
+
+#define IOMUXC_GPIO_AD_30_LPSPI1_SOUT 0x184 0x3C8 0x5D8 0x0 0x1
+#define IOMUXC_GPIO_AD_30_USB_OTG2_OC 0x184 0x3C8 0x6B8 0x1 0x1
+#define IOMUXC_GPIO_AD_30_FLEXCAN2_TX 0x184 0x3C8 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_30_ENET_TX_DATA00 0x184 0x3C8 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_30_LPUART3_TXD 0x184 0x3C8 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_30_GPIO_MUX3_IO29 0x184 0x3C8 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_30_KPP_ROW02 0x184 0x3C8 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_30_FLEXIO2_D30 0x184 0x3C8 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_30_WDOG2_RESET_B_DEB 0x184 0x3C8 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_30_GPIO9_IO29 0x184 0x3C8 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_31_LPSPI1_SIN 0x188 0x3CC 0x5D4 0x0 0x1
+#define IOMUXC_GPIO_AD_31_USB_OTG2_PWR 0x188 0x3CC 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_31_FLEXCAN2_RX 0x188 0x3CC 0x49C 0x2 0x1
+#define IOMUXC_GPIO_AD_31_ENET_TX_DATA01 0x188 0x3CC 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_31_LPUART3_RXD 0x188 0x3CC 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_31_GPIO_MUX3_IO30 0x188 0x3CC 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_31_KPP_COL02 0x188 0x3CC 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_31_FLEXIO2_D31 0x188 0x3CC 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_31_WDOG1_RESET_B_DEB 0x188 0x3CC 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_31_GPIO9_IO30 0x188 0x3CC 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_32_GPIO9_IO31 0x18C 0x3D0 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_32_LPI2C1_SCL 0x18C 0x3D0 0x5AC 0x0 0x1
+#define IOMUXC_GPIO_AD_32_USBPHY2_OTG_ID 0x18C 0x3D0 0x6C4 0x1 0x1
+#define IOMUXC_GPIO_AD_32_PGMC_PMIC_RDY 0x18C 0x3D0 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_32_ENET_MDC 0x18C 0x3D0 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_32_USDHC1_CD_B 0x18C 0x3D0 0x6C8 0x4 0x0
+#define IOMUXC_GPIO_AD_32_GPIO_MUX3_IO31 0x18C 0x3D0 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_32_KPP_ROW01 0x18C 0x3D0 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_32_LPUART10_TXD 0x18C 0x3D0 0x628 0x8 0x1
+#define IOMUXC_GPIO_AD_32_ENET_1G_MDC 0x18C 0x3D0 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_AD_33_LPI2C1_SDA 0x190 0x3D4 0x5B0 0x0 0x1
+#define IOMUXC_GPIO_AD_33_USBPHY1_OTG_ID 0x190 0x3D4 0x6C0 0x1 0x1
+#define IOMUXC_GPIO_AD_33_XBAR1_INOUT17 0x190 0x3D4 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_33_ENET_MDIO 0x190 0x3D4 0x4AC 0x3 0x1
+#define IOMUXC_GPIO_AD_33_USDHC1_WP 0x190 0x3D4 0x6CC 0x4 0x0
+#define IOMUXC_GPIO_AD_33_GPIO_MUX4_IO00 0x190 0x3D4 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_33_KPP_COL01 0x190 0x3D4 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_33_LPUART10_RXD 0x190 0x3D4 0x624 0x8 0x1
+#define IOMUXC_GPIO_AD_33_ENET_1G_MDIO 0x190 0x3D4 0x4C8 0x9 0x3
+#define IOMUXC_GPIO_AD_33_GPIO10_IO00 0x190 0x3D4 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_34_ENET_1G_1588_EVENT0_IN 0x194 0x3D8 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_34_USB_OTG1_PWR 0x194 0x3D8 0x0 0x1 0x0
+#define IOMUXC_GPIO_AD_34_XBAR1_INOUT18 0x194 0x3D8 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_34_ENET_1588_EVENT0_IN 0x194 0x3D8 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_34_USDHC1_VSELECT 0x194 0x3D8 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_34_GPIO_MUX4_IO01 0x194 0x3D8 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_34_KPP_ROW00 0x194 0x3D8 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_34_LPUART10_CTS_B 0x194 0x3D8 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_34_WDOG1_ANY 0x194 0x3D8 0x0 0x9 0x0
+#define IOMUXC_GPIO_AD_34_GPIO10_IO01 0x194 0x3D8 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_AD_35_GPIO10_IO02 0x198 0x3DC 0x0 0xA 0x0
+#define IOMUXC_GPIO_AD_35_ENET_1G_1588_EVENT0_OUT 0x198 0x3DC 0x0 0x0 0x0
+#define IOMUXC_GPIO_AD_35_USB_OTG1_OC 0x198 0x3DC 0x6BC 0x1 0x1
+#define IOMUXC_GPIO_AD_35_XBAR1_INOUT19 0x198 0x3DC 0x0 0x2 0x0
+#define IOMUXC_GPIO_AD_35_ENET_1588_EVENT0_OUT 0x198 0x3DC 0x0 0x3 0x0
+#define IOMUXC_GPIO_AD_35_USDHC1_RESET_B 0x198 0x3DC 0x0 0x4 0x0
+#define IOMUXC_GPIO_AD_35_GPIO_MUX4_IO02 0x198 0x3DC 0x0 0x5 0x0
+#define IOMUXC_GPIO_AD_35_KPP_COL00 0x198 0x3DC 0x0 0x6 0x0
+#define IOMUXC_GPIO_AD_35_LPUART10_RTS_B 0x198 0x3DC 0x0 0x8 0x0
+#define IOMUXC_GPIO_AD_35_FLEXSPI1_B_SS1_B 0x198 0x3DC 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_SD_B1_00_USDHC1_CMD 0x19C 0x3E0 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B1_00_XBAR1_INOUT20 0x19C 0x3E0 0x6D8 0x2 0x1
+#define IOMUXC_GPIO_SD_B1_00_GPT4_CAPTURE1 0x19C 0x3E0 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B1_00_GPIO_MUX4_IO03 0x19C 0x3E0 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B1_00_FLEXSPI2_A_SS0_B 0x19C 0x3E0 0x0 0x6 0x0
+#define IOMUXC_GPIO_SD_B1_00_KPP_ROW07 0x19C 0x3E0 0x5A8 0x8 0x1
+#define IOMUXC_GPIO_SD_B1_00_GPIO10_IO03 0x19C 0x3E0 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_SD_B1_01_USDHC1_CLK 0x1A0 0x3E4 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B1_01_XBAR1_INOUT21 0x1A0 0x3E4 0x6DC 0x2 0x1
+#define IOMUXC_GPIO_SD_B1_01_GPT4_CAPTURE2 0x1A0 0x3E4 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B1_01_GPIO_MUX4_IO04 0x1A0 0x3E4 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B1_01_FLEXSPI2_A_SCLK 0x1A0 0x3E4 0x58C 0x6 0x1
+#define IOMUXC_GPIO_SD_B1_01_KPP_COL07 0x1A0 0x3E4 0x5A0 0x8 0x1
+#define IOMUXC_GPIO_SD_B1_01_GPIO10_IO04 0x1A0 0x3E4 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_SD_B1_02_GPIO10_IO05 0x1A4 0x3E8 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B1_02_USDHC1_DATA0 0x1A4 0x3E8 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B1_02_XBAR1_INOUT22 0x1A4 0x3E8 0x6E0 0x2 0x1
+#define IOMUXC_GPIO_SD_B1_02_GPT4_COMPARE1 0x1A4 0x3E8 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B1_02_GPIO_MUX4_IO05 0x1A4 0x3E8 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B1_02_FLEXSPI2_A_DATA00 0x1A4 0x3E8 0x57C 0x6 0x1
+#define IOMUXC_GPIO_SD_B1_02_KPP_ROW06 0x1A4 0x3E8 0x5A4 0x8 0x1
+#define IOMUXC_GPIO_SD_B1_02_FLEXSPI1_A_SS1_B 0x1A4 0x3E8 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_SD_B1_03_USDHC1_DATA1 0x1A8 0x3EC 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B1_03_XBAR1_INOUT23 0x1A8 0x3EC 0x6E4 0x2 0x1
+#define IOMUXC_GPIO_SD_B1_03_GPT4_COMPARE2 0x1A8 0x3EC 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B1_03_GPIO_MUX4_IO06 0x1A8 0x3EC 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B1_03_FLEXSPI2_A_DATA01 0x1A8 0x3EC 0x580 0x6 0x1
+#define IOMUXC_GPIO_SD_B1_03_KPP_COL06 0x1A8 0x3EC 0x59C 0x8 0x1
+#define IOMUXC_GPIO_SD_B1_03_FLEXSPI1_B_SS1_B 0x1A8 0x3EC 0x0 0x9 0x0
+#define IOMUXC_GPIO_SD_B1_03_GPIO10_IO06 0x1A8 0x3EC 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_SD_B1_04_USDHC1_DATA2 0x1AC 0x3F0 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B1_04_XBAR1_INOUT24 0x1AC 0x3F0 0x6E8 0x2 0x1
+#define IOMUXC_GPIO_SD_B1_04_GPT4_COMPARE3 0x1AC 0x3F0 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B1_04_GPIO_MUX4_IO07 0x1AC 0x3F0 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B1_04_FLEXSPI2_A_DATA02 0x1AC 0x3F0 0x584 0x6 0x1
+#define IOMUXC_GPIO_SD_B1_04_FLEXSPI1_B_SS0_B 0x1AC 0x3F0 0x0 0x8 0x0
+#define IOMUXC_GPIO_SD_B1_04_ENET_QOS_1588_EVENT2_AUX_IN 0x1AC 0x3F0 0x0 0x9 0x0
+#define IOMUXC_GPIO_SD_B1_04_GPIO10_IO07 0x1AC 0x3F0 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_SD_B1_05_GPIO10_IO08 0x1B0 0x3F4 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B1_05_USDHC1_DATA3 0x1B0 0x3F4 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B1_05_XBAR1_INOUT25 0x1B0 0x3F4 0x6EC 0x2 0x1
+#define IOMUXC_GPIO_SD_B1_05_GPT4_CLK 0x1B0 0x3F4 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B1_05_GPIO_MUX4_IO08 0x1B0 0x3F4 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B1_05_FLEXSPI2_A_DATA03 0x1B0 0x3F4 0x588 0x6 0x1
+#define IOMUXC_GPIO_SD_B1_05_FLEXSPI1_B_DQS 0x1B0 0x3F4 0x0 0x8 0x0
+#define IOMUXC_GPIO_SD_B1_05_ENET_QOS_1588_EVENT3_AUX_IN 0x1B0 0x3F4 0x0 0x9 0x0
+
+#define IOMUXC_GPIO_SD_B2_00_GPIO10_IO09 0x1B4 0x3F8 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_00_USDHC2_DATA3 0x1B4 0x3F8 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_00_FLEXSPI1_B_DATA03 0x1B4 0x3F8 0x570 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_00_ENET_1G_RX_EN 0x1B4 0x3F8 0x4E0 0x2 0x1
+#define IOMUXC_GPIO_SD_B2_00_LPUART9_TXD 0x1B4 0x3F8 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_00_LPSPI4_SCK 0x1B4 0x3F8 0x610 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_00_GPIO_MUX4_IO09 0x1B4 0x3F8 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SD_B2_01_USDHC2_DATA2 0x1B8 0x3FC 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_01_FLEXSPI1_B_DATA02 0x1B8 0x3FC 0x56C 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_01_ENET_1G_RX_CLK 0x1B8 0x3FC 0x4CC 0x2 0x1
+#define IOMUXC_GPIO_SD_B2_01_LPUART9_RXD 0x1B8 0x3FC 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_01_LPSPI4_PCS0 0x1B8 0x3FC 0x60C 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_01_GPIO_MUX4_IO10 0x1B8 0x3FC 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B2_01_GPIO10_IO10 0x1B8 0x3FC 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_SD_B2_02_GPIO10_IO11 0x1BC 0x400 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_02_USDHC2_DATA1 0x1BC 0x400 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_02_FLEXSPI1_B_DATA01 0x1BC 0x400 0x568 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_02_ENET_1G_RX_DATA00 0x1BC 0x400 0x4D0 0x2 0x1
+#define IOMUXC_GPIO_SD_B2_02_LPUART9_CTS_B 0x1BC 0x400 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_02_LPSPI4_SOUT 0x1BC 0x400 0x618 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_02_GPIO_MUX4_IO11 0x1BC 0x400 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SD_B2_03_GPIO10_IO12 0x1C0 0x404 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_03_USDHC2_DATA0 0x1C0 0x404 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_03_FLEXSPI1_B_DATA00 0x1C0 0x404 0x564 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_03_ENET_1G_RX_DATA01 0x1C0 0x404 0x4D4 0x2 0x1
+#define IOMUXC_GPIO_SD_B2_03_LPUART9_RTS_B 0x1C0 0x404 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_03_LPSPI4_SIN 0x1C0 0x404 0x614 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_03_GPIO_MUX4_IO12 0x1C0 0x404 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SD_B2_04_USDHC2_CLK 0x1C4 0x408 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_04_FLEXSPI1_B_SCLK 0x1C4 0x408 0x578 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_04_ENET_1G_RX_DATA02 0x1C4 0x408 0x4D8 0x2 0x1
+#define IOMUXC_GPIO_SD_B2_04_FLEXSPI1_A_SS1_B 0x1C4 0x408 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_04_LPSPI4_PCS1 0x1C4 0x408 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_04_GPIO_MUX4_IO13 0x1C4 0x408 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B2_04_GPIO10_IO13 0x1C4 0x408 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_SD_B2_05_GPIO10_IO14 0x1C8 0x40C 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_05_USDHC2_CMD 0x1C8 0x40C 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_05_FLEXSPI1_A_DQS 0x1C8 0x40C 0x550 0x1 0x2
+#define IOMUXC_GPIO_SD_B2_05_ENET_1G_RX_DATA03 0x1C8 0x40C 0x4DC 0x2 0x1
+#define IOMUXC_GPIO_SD_B2_05_FLEXSPI1_B_SS0_B 0x1C8 0x40C 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_05_LPSPI4_PCS2 0x1C8 0x40C 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_05_GPIO_MUX4_IO14 0x1C8 0x40C 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SD_B2_06_GPIO10_IO15 0x1CC 0x410 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_06_USDHC2_RESET_B 0x1CC 0x410 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_06_FLEXSPI1_A_SS0_B 0x1CC 0x410 0x0 0x1 0x0
+#define IOMUXC_GPIO_SD_B2_06_ENET_1G_TX_DATA03 0x1CC 0x410 0x0 0x2 0x0
+#define IOMUXC_GPIO_SD_B2_06_LPSPI4_PCS3 0x1CC 0x410 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_06_GPT6_CAPTURE1 0x1CC 0x410 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_06_GPIO_MUX4_IO15 0x1CC 0x410 0x0 0x5 0x0
+
+#define IOMUXC_GPIO_SD_B2_07_USDHC2_STROBE 0x1D0 0x414 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_07_FLEXSPI1_A_SCLK 0x1D0 0x414 0x574 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_07_ENET_1G_TX_DATA02 0x1D0 0x414 0x0 0x2 0x0
+#define IOMUXC_GPIO_SD_B2_07_LPUART3_CTS_B 0x1D0 0x414 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_07_GPT6_CAPTURE2 0x1D0 0x414 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_07_GPIO_MUX4_IO16 0x1D0 0x414 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B2_07_LPSPI2_SCK 0x1D0 0x414 0x5E4 0x6 0x1
+#define IOMUXC_GPIO_SD_B2_07_ENET_TX_ER 0x1D0 0x414 0x0 0x8 0x0
+#define IOMUXC_GPIO_SD_B2_07_ENET_QOS_REF_CLK 0x1D0 0x414 0x4A0 0x9 0x1
+#define IOMUXC_GPIO_SD_B2_07_GPIO10_IO16 0x1D0 0x414 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_SD_B2_08_GPIO10_IO17 0x1D4 0x418 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_08_USDHC2_DATA4 0x1D4 0x418 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_08_FLEXSPI1_A_DATA00 0x1D4 0x418 0x554 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_08_ENET_1G_TX_DATA01 0x1D4 0x418 0x0 0x2 0x0
+#define IOMUXC_GPIO_SD_B2_08_LPUART3_RTS_B 0x1D4 0x418 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_08_GPT6_COMPARE1 0x1D4 0x418 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_08_GPIO_MUX4_IO17 0x1D4 0x418 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B2_08_LPSPI2_PCS0 0x1D4 0x418 0x5DC 0x6 0x1
+
+#define IOMUXC_GPIO_SD_B2_09_GPIO10_IO18 0x1D8 0x41C 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_09_USDHC2_DATA5 0x1D8 0x41C 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_09_FLEXSPI1_A_DATA01 0x1D8 0x41C 0x558 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_09_ENET_1G_TX_DATA00 0x1D8 0x41C 0x0 0x2 0x0
+#define IOMUXC_GPIO_SD_B2_09_LPUART5_CTS_B 0x1D8 0x41C 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_09_GPT6_COMPARE2 0x1D8 0x41C 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_09_GPIO_MUX4_IO18 0x1D8 0x41C 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B2_09_LPSPI2_SOUT 0x1D8 0x41C 0x5EC 0x6 0x1
+
+#define IOMUXC_GPIO_SD_B2_10_GPIO10_IO19 0x1DC 0x420 0x0 0xA 0x0
+#define IOMUXC_GPIO_SD_B2_10_USDHC2_DATA6 0x1DC 0x420 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_10_FLEXSPI1_A_DATA02 0x1DC 0x420 0x55C 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_10_ENET_1G_TX_EN 0x1DC 0x420 0x0 0x2 0x0
+#define IOMUXC_GPIO_SD_B2_10_LPUART5_RTS_B 0x1DC 0x420 0x0 0x3 0x0
+#define IOMUXC_GPIO_SD_B2_10_GPT6_COMPARE3 0x1DC 0x420 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_10_GPIO_MUX4_IO19 0x1DC 0x420 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B2_10_LPSPI2_SIN 0x1DC 0x420 0x5E8 0x6 0x1
+
+#define IOMUXC_GPIO_SD_B2_11_USDHC2_DATA7 0x1E0 0x424 0x0 0x0 0x0
+#define IOMUXC_GPIO_SD_B2_11_FLEXSPI1_A_DATA03 0x1E0 0x424 0x560 0x1 0x1
+#define IOMUXC_GPIO_SD_B2_11_ENET_1G_TX_CLK_IO 0x1E0 0x424 0x4E8 0x2 0x1
+#define IOMUXC_GPIO_SD_B2_11_ENET_1G_REF_CLK 0x1E0 0x424 0x4C4 0x3 0x1
+#define IOMUXC_GPIO_SD_B2_11_GPT6_CLK 0x1E0 0x424 0x0 0x4 0x0
+#define IOMUXC_GPIO_SD_B2_11_GPIO_MUX4_IO20 0x1E0 0x424 0x0 0x5 0x0
+#define IOMUXC_GPIO_SD_B2_11_LPSPI2_PCS1 0x1E0 0x424 0x5E0 0x6 0x1
+#define IOMUXC_GPIO_SD_B2_11_GPIO10_IO20 0x1E0 0x424 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_00_VIDEO_MUX_LCDIF_CLK 0x1E4 0x428 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_00_ENET_1G_RX_EN 0x1E4 0x428 0x4E0 0x1 0x2
+#define IOMUXC_GPIO_DISP_B1_00_TMR1_TIMER0 0x1E4 0x428 0x63C 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_00_XBAR1_INOUT26 0x1E4 0x428 0x6F0 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_00_GPIO_MUX4_IO21 0x1E4 0x428 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_00_ENET_QOS_RX_EN 0x1E4 0x428 0x4F8 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_00_GPIO10_IO21 0x1E4 0x428 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_01_VIDEO_MUX_LCDIF_ENABLE 0x1E8 0x42C 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_01_ENET_1G_RX_CLK 0x1E8 0x42C 0x4CC 0x1 0x2
+#define IOMUXC_GPIO_DISP_B1_01_ENET_1G_RX_ER 0x1E8 0x42C 0x4E4 0x2 0x1
+#define IOMUXC_GPIO_DISP_B1_01_TMR1_TIMER1 0x1E8 0x42C 0x640 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_01_XBAR1_INOUT27 0x1E8 0x42C 0x6F4 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_01_GPIO_MUX4_IO22 0x1E8 0x42C 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_01_ENET_QOS_RX_CLK 0x1E8 0x42C 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_01_ENET_QOS_RX_ER 0x1E8 0x42C 0x4FC 0x9 0x0
+#define IOMUXC_GPIO_DISP_B1_01_GPIO10_IO22 0x1E8 0x42C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_02_GPIO10_IO23 0x1EC 0x430 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B1_02_VIDEO_MUX_LCDIF_HSYNC 0x1EC 0x430 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_02_ENET_1G_RX_DATA00 0x1EC 0x430 0x4D0 0x1 0x2
+#define IOMUXC_GPIO_DISP_B1_02_LPI2C3_SCL 0x1EC 0x430 0x5BC 0x2 0x0
+#define IOMUXC_GPIO_DISP_B1_02_TMR1_TIMER2 0x1EC 0x430 0x644 0x3 0x1
+#define IOMUXC_GPIO_DISP_B1_02_XBAR1_INOUT28 0x1EC 0x430 0x6F8 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_02_GPIO_MUX4_IO23 0x1EC 0x430 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_02_ENET_QOS_RX_DATA00 0x1EC 0x430 0x4F0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_02_LPUART1_TXD 0x1EC 0x430 0x620 0x9 0x1
+
+#define IOMUXC_GPIO_DISP_B1_03_VIDEO_MUX_LCDIF_VSYNC 0x1F0 0x434 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_03_ENET_1G_RX_DATA01 0x1F0 0x434 0x4D4 0x1 0x2
+#define IOMUXC_GPIO_DISP_B1_03_LPI2C3_SDA 0x1F0 0x434 0x5C0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B1_03_TMR2_TIMER0 0x1F0 0x434 0x648 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_03_XBAR1_INOUT29 0x1F0 0x434 0x6FC 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_03_GPIO_MUX4_IO24 0x1F0 0x434 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_03_ENET_QOS_RX_DATA01 0x1F0 0x434 0x4F4 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_03_LPUART1_RXD 0x1F0 0x434 0x61C 0x9 0x1
+#define IOMUXC_GPIO_DISP_B1_03_GPIO10_IO24 0x1F0 0x434 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_04_VIDEO_MUX_LCDIF_DATA00 0x1F4 0x438 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_04_ENET_1G_RX_DATA02 0x1F4 0x438 0x4D8 0x1 0x2
+#define IOMUXC_GPIO_DISP_B1_04_LPUART4_RXD 0x1F4 0x438 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B1_04_TMR2_TIMER1 0x1F4 0x438 0x64C 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_04_XBAR1_INOUT30 0x1F4 0x438 0x700 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_04_GPIO_MUX4_IO25 0x1F4 0x438 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_04_ENET_QOS_RX_DATA02 0x1F4 0x438 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_04_LPSPI3_SCK 0x1F4 0x438 0x600 0x9 0x1
+#define IOMUXC_GPIO_DISP_B1_04_GPIO10_IO25 0x1F4 0x438 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_05_GPIO10_IO26 0x1F8 0x43C 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B1_05_VIDEO_MUX_LCDIF_DATA01 0x1F8 0x43C 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_05_ENET_1G_RX_DATA03 0x1F8 0x43C 0x4DC 0x1 0x2
+#define IOMUXC_GPIO_DISP_B1_05_LPUART4_CTS_B 0x1F8 0x43C 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B1_05_TMR2_TIMER2 0x1F8 0x43C 0x650 0x3 0x1
+#define IOMUXC_GPIO_DISP_B1_05_XBAR1_INOUT31 0x1F8 0x43C 0x704 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_05_GPIO_MUX4_IO26 0x1F8 0x43C 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_05_ENET_QOS_RX_DATA03 0x1F8 0x43C 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_05_LPSPI3_SIN 0x1F8 0x43C 0x604 0x9 0x1
+
+#define IOMUXC_GPIO_DISP_B1_06_VIDEO_MUX_LCDIF_DATA02 0x1FC 0x440 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_06_ENET_1G_TX_DATA03 0x1FC 0x440 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B1_06_LPUART4_TXD 0x1FC 0x440 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B1_06_TMR3_TIMER0 0x1FC 0x440 0x654 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_06_XBAR1_INOUT32 0x1FC 0x440 0x708 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_06_GPIO_MUX4_IO27 0x1FC 0x440 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_06_SRC_BT_CFG00 0x1FC 0x440 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B1_06_ENET_QOS_TX_DATA03 0x1FC 0x440 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_06_LPSPI3_SOUT 0x1FC 0x440 0x608 0x9 0x1
+#define IOMUXC_GPIO_DISP_B1_06_GPIO10_IO27 0x1FC 0x440 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_07_VIDEO_MUX_LCDIF_DATA03 0x200 0x444 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_07_ENET_1G_TX_DATA02 0x200 0x444 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B1_07_LPUART4_RTS_B 0x200 0x444 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B1_07_TMR3_TIMER1 0x200 0x444 0x658 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_07_XBAR1_INOUT33 0x200 0x444 0x70C 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_07_GPIO_MUX4_IO28 0x200 0x444 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_07_SRC_BT_CFG01 0x200 0x444 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B1_07_ENET_QOS_TX_DATA02 0x200 0x444 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_07_LPSPI3_PCS0 0x200 0x444 0x5F0 0x9 0x1
+#define IOMUXC_GPIO_DISP_B1_07_GPIO10_IO28 0x200 0x444 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_08_GPIO10_IO29 0x204 0x448 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B1_08_VIDEO_MUX_LCDIF_DATA04 0x204 0x448 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_08_ENET_1G_TX_DATA01 0x204 0x448 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B1_08_USDHC1_CD_B 0x204 0x448 0x6C8 0x2 0x1
+#define IOMUXC_GPIO_DISP_B1_08_TMR3_TIMER2 0x204 0x448 0x65C 0x3 0x1
+#define IOMUXC_GPIO_DISP_B1_08_XBAR1_INOUT34 0x204 0x448 0x710 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_08_GPIO_MUX4_IO29 0x204 0x448 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_08_SRC_BT_CFG02 0x204 0x448 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B1_08_ENET_QOS_TX_DATA01 0x204 0x448 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_08_LPSPI3_PCS1 0x204 0x448 0x5F4 0x9 0x1
+
+#define IOMUXC_GPIO_DISP_B1_09_VIDEO_MUX_LCDIF_DATA05 0x208 0x44C 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_09_ENET_1G_TX_DATA00 0x208 0x44C 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B1_09_USDHC1_WP 0x208 0x44C 0x6CC 0x2 0x1
+#define IOMUXC_GPIO_DISP_B1_09_TMR4_TIMER0 0x208 0x44C 0x660 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_09_XBAR1_INOUT35 0x208 0x44C 0x714 0x4 0x1
+#define IOMUXC_GPIO_DISP_B1_09_GPIO_MUX4_IO30 0x208 0x44C 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_09_SRC_BT_CFG03 0x208 0x44C 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B1_09_ENET_QOS_TX_DATA00 0x208 0x44C 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_09_LPSPI3_PCS2 0x208 0x44C 0x5F8 0x9 0x1
+#define IOMUXC_GPIO_DISP_B1_09_GPIO10_IO30 0x208 0x44C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_10_VIDEO_MUX_LCDIF_DATA06 0x20C 0x450 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_10_ENET_1G_TX_EN 0x20C 0x450 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B1_10_USDHC1_RESET_B 0x20C 0x450 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B1_10_TMR4_TIMER1 0x20C 0x450 0x664 0x3 0x2
+#define IOMUXC_GPIO_DISP_B1_10_XBAR1_INOUT36 0x20C 0x450 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B1_10_GPIO_MUX4_IO31 0x20C 0x450 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_10_SRC_BT_CFG04 0x20C 0x450 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B1_10_ENET_QOS_TX_EN 0x20C 0x450 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_10_LPSPI3_PCS3 0x20C 0x450 0x5FC 0x9 0x1
+#define IOMUXC_GPIO_DISP_B1_10_GPIO10_IO31 0x20C 0x450 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B1_11_VIDEO_MUX_LCDIF_DATA07 0x210 0x454 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B1_11_ENET_1G_TX_CLK_IO 0x210 0x454 0x4E8 0x1 0x2
+#define IOMUXC_GPIO_DISP_B1_11_ENET_1G_REF_CLK 0x210 0x454 0x4C4 0x2 0x2
+#define IOMUXC_GPIO_DISP_B1_11_TMR4_TIMER2 0x210 0x454 0x668 0x3 0x1
+#define IOMUXC_GPIO_DISP_B1_11_XBAR1_INOUT37 0x210 0x454 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B1_11_GPIO_MUX5_IO00 0x210 0x454 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B1_11_SRC_BT_CFG05 0x210 0x454 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B1_11_ENET_QOS_TX_CLK 0x210 0x454 0x4A4 0x8 0x0
+#define IOMUXC_GPIO_DISP_B1_11_ENET_QOS_REF_CLK 0x210 0x454 0x4A0 0x9 0x2
+#define IOMUXC_GPIO_DISP_B1_11_GPIO11_IO00 0x210 0x454 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B2_00_GPIO11_IO01 0x214 0x458 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_00_VIDEO_MUX_LCDIF_DATA08 0x214 0x458 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_00_WDOG1_B 0x214 0x458 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_00_MQS_RIGHT 0x214 0x458 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_00_ENET_1G_TX_ER 0x214 0x458 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_00_SAI1_TX_DATA03 0x214 0x458 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_00_GPIO_MUX5_IO01 0x214 0x458 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_00_SRC_BT_CFG06 0x214 0x458 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B2_00_ENET_QOS_TX_ER 0x214 0x458 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_DISP_B2_01_VIDEO_MUX_LCDIF_DATA09 0x218 0x45C 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_01_USDHC1_VSELECT 0x218 0x45C 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_01_MQS_LEFT 0x218 0x45C 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_01_WDOG2_B 0x218 0x45C 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_01_SAI1_TX_DATA02 0x218 0x45C 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_01_GPIO_MUX5_IO02 0x218 0x45C 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_01_SRC_BT_CFG07 0x218 0x45C 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B2_01_EWM_OUT_B 0x218 0x45C 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B2_01_CCM_ENET_REF_CLK_25M 0x218 0x45C 0x0 0x9 0x0
+#define IOMUXC_GPIO_DISP_B2_01_GPIO11_IO02 0x218 0x45C 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B2_02_GPIO11_IO03 0x21C 0x460 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_02_VIDEO_MUX_LCDIF_DATA10 0x21C 0x460 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_02_ENET_TX_DATA00 0x21C 0x460 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_02_PIT1_TRIGGER3 0x21C 0x460 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_02_ARM_TRACE00 0x21C 0x460 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_02_SAI1_TX_DATA01 0x21C 0x460 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_02_GPIO_MUX5_IO03 0x21C 0x460 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_02_SRC_BT_CFG08 0x21C 0x460 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B2_02_ENET_QOS_TX_DATA00 0x21C 0x460 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_DISP_B2_03_GPIO11_IO04 0x220 0x464 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_03_VIDEO_MUX_LCDIF_DATA11 0x220 0x464 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_03_ENET_TX_DATA01 0x220 0x464 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_03_PIT1_TRIGGER2 0x220 0x464 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_03_ARM_TRACE01 0x220 0x464 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_03_SAI1_MCLK 0x220 0x464 0x66C 0x4 0x1
+#define IOMUXC_GPIO_DISP_B2_03_GPIO_MUX5_IO04 0x220 0x464 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_03_SRC_BT_CFG09 0x220 0x464 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B2_03_ENET_QOS_TX_DATA01 0x220 0x464 0x0 0x8 0x0
+
+#define IOMUXC_GPIO_DISP_B2_04_VIDEO_MUX_LCDIF_DATA12 0x224 0x468 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_04_ENET_TX_EN 0x224 0x468 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_04_PIT1_TRIGGER1 0x224 0x468 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_04_ARM_TRACE02 0x224 0x468 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_04_SAI1_RX_SYNC 0x224 0x468 0x678 0x4 0x1
+#define IOMUXC_GPIO_DISP_B2_04_GPIO_MUX5_IO05 0x224 0x468 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_04_SRC_BT_CFG10 0x224 0x468 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B2_04_ENET_QOS_TX_EN 0x224 0x468 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B2_04_GPIO11_IO05 0x224 0x468 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B2_05_GPIO11_IO06 0x228 0x46C 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_05_VIDEO_MUX_LCDIF_DATA13 0x228 0x46C 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_05_ENET_TX_CLK 0x228 0x46C 0x4C0 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_05_ENET_REF_CLK 0x228 0x46C 0x4A8 0x2 0x1
+#define IOMUXC_GPIO_DISP_B2_05_ARM_TRACE03 0x228 0x46C 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_05_SAI1_RX_BCLK 0x228 0x46C 0x670 0x4 0x1
+#define IOMUXC_GPIO_DISP_B2_05_GPIO_MUX5_IO06 0x228 0x46C 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_05_SRC_BT_CFG11 0x228 0x46C 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B2_05_ENET_QOS_TX_CLK 0x228 0x46C 0x4A4 0x8 0x1
+
+#define IOMUXC_GPIO_DISP_B2_06_GPIO11_IO07 0x22C 0x470 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_06_VIDEO_MUX_LCDIF_DATA14 0x22C 0x470 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_06_ENET_RX_DATA00 0x22C 0x470 0x4B0 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_06_LPUART7_TXD 0x22C 0x470 0x630 0x2 0x1
+#define IOMUXC_GPIO_DISP_B2_06_ARM_TRACE_CLK 0x22C 0x470 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_06_SAI1_RX_DATA00 0x22C 0x470 0x674 0x4 0x1
+#define IOMUXC_GPIO_DISP_B2_06_GPIO_MUX5_IO07 0x22C 0x470 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_06_ENET_QOS_RX_DATA00 0x22C 0x470 0x4F0 0x8 0x1
+
+#define IOMUXC_GPIO_DISP_B2_07_VIDEO_MUX_LCDIF_DATA15 0x230 0x474 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_07_ENET_RX_DATA01 0x230 0x474 0x4B4 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_07_LPUART7_RXD 0x230 0x474 0x62C 0x2 0x1
+#define IOMUXC_GPIO_DISP_B2_07_ARM_TRACE_SWO 0x230 0x474 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_07_SAI1_TX_DATA00 0x230 0x474 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_07_GPIO_MUX5_IO08 0x230 0x474 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_07_ENET_QOS_RX_DATA01 0x230 0x474 0x4F4 0x8 0x1
+#define IOMUXC_GPIO_DISP_B2_07_GPIO11_IO08 0x230 0x474 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B2_08_GPIO11_IO09 0x234 0x478 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_08_VIDEO_MUX_LCDIF_DATA16 0x234 0x478 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_08_ENET_RX_EN 0x234 0x478 0x4B8 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_08_LPUART8_TXD 0x234 0x478 0x638 0x2 0x1
+#define IOMUXC_GPIO_DISP_B2_08_ARM_CM7_EVENTO 0x234 0x478 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_08_SAI1_TX_BCLK 0x234 0x478 0x67C 0x4 0x1
+#define IOMUXC_GPIO_DISP_B2_08_GPIO_MUX5_IO09 0x234 0x478 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_08_ENET_QOS_RX_EN 0x234 0x478 0x4F8 0x8 0x1
+#define IOMUXC_GPIO_DISP_B2_08_LPUART1_TXD 0x234 0x478 0x620 0x9 0x2
+
+#define IOMUXC_GPIO_DISP_B2_09_GPIO11_IO10 0x238 0x47C 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_09_VIDEO_MUX_LCDIF_DATA17 0x238 0x47C 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_09_ENET_RX_ER 0x238 0x47C 0x4BC 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_09_LPUART8_RXD 0x238 0x47C 0x634 0x2 0x1
+#define IOMUXC_GPIO_DISP_B2_09_ARM_CM7_EVENTI 0x238 0x47C 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_09_SAI1_TX_SYNC 0x238 0x47C 0x680 0x4 0x1
+#define IOMUXC_GPIO_DISP_B2_09_GPIO_MUX5_IO10 0x238 0x47C 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_09_ENET_QOS_RX_ER 0x238 0x47C 0x4FC 0x8 0x1
+#define IOMUXC_GPIO_DISP_B2_09_LPUART1_RXD 0x238 0x47C 0x61C 0x9 0x2
+
+#define IOMUXC_GPIO_DISP_B2_10_GPIO11_IO11 0x23C 0x480 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_10_VIDEO_MUX_LCDIF_DATA18 0x23C 0x480 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_10_EMVSIM2_IO 0x23C 0x480 0x6A8 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_10_LPUART2_TXD 0x23C 0x480 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_10_WDOG2_RESET_B_DEB 0x23C 0x480 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_10_XBAR1_INOUT38 0x23C 0x480 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_10_GPIO_MUX5_IO11 0x23C 0x480 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_10_LPI2C3_SCL 0x23C 0x480 0x5BC 0x6 0x1
+#define IOMUXC_GPIO_DISP_B2_10_ENET_QOS_RX_ER 0x23C 0x480 0x4FC 0x8 0x2
+#define IOMUXC_GPIO_DISP_B2_10_SPDIF_IN 0x23C 0x480 0x6B4 0x9 0x2
+
+#define IOMUXC_GPIO_DISP_B2_11_VIDEO_MUX_LCDIF_DATA19 0x240 0x484 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_11_EMVSIM2_CLK 0x240 0x484 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_11_LPUART2_RXD 0x240 0x484 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_11_WDOG1_RESET_B_DEB 0x240 0x484 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_11_XBAR1_INOUT39 0x240 0x484 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_11_GPIO_MUX5_IO12 0x240 0x484 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_11_LPI2C3_SDA 0x240 0x484 0x5C0 0x6 0x1
+#define IOMUXC_GPIO_DISP_B2_11_ENET_QOS_CRS 0x240 0x484 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B2_11_SPDIF_OUT 0x240 0x484 0x0 0x9 0x0
+#define IOMUXC_GPIO_DISP_B2_11_GPIO11_IO12 0x240 0x484 0x0 0xA 0x0
+
+#define IOMUXC_GPIO_DISP_B2_12_GPIO11_IO13 0x244 0x488 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_12_VIDEO_MUX_LCDIF_DATA20 0x244 0x488 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_12_EMVSIM2_RST 0x244 0x488 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_12_FLEXCAN1_TX 0x244 0x488 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_12_LPUART2_CTS_B 0x244 0x488 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_12_XBAR1_INOUT40 0x244 0x488 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_12_GPIO_MUX5_IO13 0x244 0x488 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_12_LPI2C4_SCL 0x244 0x488 0x5C4 0x6 0x1
+#define IOMUXC_GPIO_DISP_B2_12_ENET_QOS_COL 0x244 0x488 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B2_12_LPSPI4_SCK 0x244 0x488 0x610 0x9 0x1
+
+#define IOMUXC_GPIO_DISP_B2_13_GPIO11_IO14 0x248 0x48C 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_13_VIDEO_MUX_LCDIF_DATA21 0x248 0x48C 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_13_EMVSIM2_SVEN 0x248 0x48C 0x0 0x1 0x0
+#define IOMUXC_GPIO_DISP_B2_13_FLEXCAN1_RX 0x248 0x48C 0x498 0x2 0x1
+#define IOMUXC_GPIO_DISP_B2_13_LPUART2_RTS_B 0x248 0x48C 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_13_ENET_REF_CLK 0x248 0x48C 0x4A8 0x4 0x2
+#define IOMUXC_GPIO_DISP_B2_13_GPIO_MUX5_IO14 0x248 0x48C 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_13_LPI2C4_SDA 0x248 0x48C 0x5C8 0x6 0x1
+#define IOMUXC_GPIO_DISP_B2_13_ENET_QOS_1588_EVENT0_OUT 0x248 0x48C 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B2_13_LPSPI4_SIN 0x248 0x48C 0x614 0x9 0x1
+
+#define IOMUXC_GPIO_DISP_B2_14_GPIO_MUX5_IO15 0x24C 0x490 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_14_FLEXCAN1_TX 0x24C 0x490 0x0 0x6 0x0
+#define IOMUXC_GPIO_DISP_B2_14_ENET_QOS_1588_EVENT0_IN 0x24C 0x490 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B2_14_LPSPI4_SOUT 0x24C 0x490 0x618 0x9 0x1
+#define IOMUXC_GPIO_DISP_B2_14_GPIO11_IO15 0x24C 0x490 0x0 0xA 0x0
+#define IOMUXC_GPIO_DISP_B2_14_VIDEO_MUX_LCDIF_DATA22 0x24C 0x490 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_14_EMVSIM2_PD 0x24C 0x490 0x6AC 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_14_WDOG2_B 0x24C 0x490 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_14_VIDEO_MUX_EXT_DCIC1 0x24C 0x490 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_14_ENET_1G_REF_CLK 0x24C 0x490 0x4C4 0x4 0x3
+
+#define IOMUXC_GPIO_DISP_B2_15_VIDEO_MUX_LCDIF_DATA23 0x250 0x494 0x0 0x0 0x0
+#define IOMUXC_GPIO_DISP_B2_15_EMVSIM2_POWER_FAIL 0x250 0x494 0x6B0 0x1 0x1
+#define IOMUXC_GPIO_DISP_B2_15_WDOG1_B 0x250 0x494 0x0 0x2 0x0
+#define IOMUXC_GPIO_DISP_B2_15_VIDEO_MUX_EXT_DCIC2 0x250 0x494 0x0 0x3 0x0
+#define IOMUXC_GPIO_DISP_B2_15_PIT1_TRIGGER0 0x250 0x494 0x0 0x4 0x0
+#define IOMUXC_GPIO_DISP_B2_15_GPIO_MUX5_IO16 0x250 0x494 0x0 0x5 0x0
+#define IOMUXC_GPIO_DISP_B2_15_FLEXCAN1_RX 0x250 0x494 0x498 0x6 0x2
+#define IOMUXC_GPIO_DISP_B2_15_ENET_QOS_1588_EVENT0_AUX_IN 0x250 0x494 0x0 0x8 0x0
+#define IOMUXC_GPIO_DISP_B2_15_LPSPI4_PCS0 0x250 0x494 0x60C 0x9 0x1
+#define IOMUXC_GPIO_DISP_B2_15_GPIO11_IO16 0x250 0x494 0x0 0xA 0x0
+
+#endif /* _DT_BINDINGS_PINCTRL_IMXRT1170_PINFUNC_H */
<GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&apb0_gates 0>, <&osc24M>, <&rtc CLK_OSC32K>;
clock-names = "apb", "hosc", "losc";
- resets = <&apb0_rst 0>;
gpio-controller;
interrupt-controller;
#interrupt-cells = <3>;
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&apb0_gates 0>, <&osc24M>, <&rtc CLK_OSC32K>;
clock-names = "apb", "hosc", "losc";
- resets = <&apb0_rst 0>;
gpio-controller;
interrupt-controller;
#interrupt-cells = <3>;
<GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&apbs_gates 0>, <&osc24M>, <&osc32k>;
clock-names = "apb", "hosc", "losc";
- resets = <&apbs_rst 0>;
gpio-controller;
interrupt-controller;
#interrupt-cells = <3>;
};
#endif /* MCFSDHC_BASE */
-#if IS_ENABLED(CONFIG_CAN_FLEXCAN)
+#ifdef MCFFLEXCAN_SIZE
#include <linux/can/platform/flexcan.h>
.resource = mcf5441x_flexcan0_resource,
.dev.platform_data = &mcf5441x_flexcan_info,
};
-#endif /* IS_ENABLED(CONFIG_CAN_FLEXCAN) */
+#endif /* MCFFLEXCAN_SIZE */
static struct platform_device *mcf_devices[] __initdata = {
&mcf_uart,
#ifdef MCFSDHC_BASE
&mcf_esdhc,
#endif
-#if IS_ENABLED(CONFIG_CAN_FLEXCAN)
+#ifdef MCFFLEXCAN_SIZE
&mcf_flexcan0,
#endif
};
* family, the 5270, 5271, 5274, 5275, and the 528x family which have two such
* controllers, and the 547x and 548x families which have only one of them.
*
- * The external 7 fixed interrupts are part the the Edge Port unit of these
+ * The external 7 fixed interrupts are part of the Edge Port unit of these
* ColdFire parts. They can be configured as level or edge triggered.
*
* (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com>
DEFINE_CLK(pll, "pll.0", MCF_CLK);
DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
-struct clk_lookup m523x_clk_lookup[] = {
+static struct clk_lookup m523x_clk_lookup[] = {
CLKDEV_INIT(NULL, "pll.0", &clk_pll),
CLKDEV_INIT(NULL, "sys.0", &clk_sys),
CLKDEV_INIT("mcfpit.0", NULL, &clk_pll),
{
return hot_add_scn_to_nid(start);
}
+EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
#endif
int __weak create_section_mapping(unsigned long start, unsigned long end,
#define X86_FEATURE_RETHUNK (11*32+14) /* "" Use REturn THUNK */
#define X86_FEATURE_UNRET (11*32+15) /* "" AMD BTB untrain return */
#define X86_FEATURE_USE_IBPB_FW (11*32+16) /* "" Use IBPB during runtime firmware calls */
+#define X86_FEATURE_RSB_VMEXIT_LITE (11*32+17) /* "" Fill RSB on VM exit when EIBRS is enabled */
/* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
#define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */
#define X86_BUG_SRBDS X86_BUG(24) /* CPU may leak RNG bits if not mitigated */
#define X86_BUG_MMIO_STALE_DATA X86_BUG(25) /* CPU is affected by Processor MMIO Stale Data vulnerabilities */
#define X86_BUG_RETBLEED X86_BUG(26) /* CPU is affected by RETBleed */
+#define X86_BUG_EIBRS_PBRSB X86_BUG(27) /* EIBRS is vulnerable to Post Barrier RSB Predictions */
#endif /* _ASM_X86_CPUFEATURES_H */
* are restricted to targets in
* kernel.
*/
+#define ARCH_CAP_PBRSB_NO BIT(24) /*
+ * Not susceptible to Post-Barrier
+ * Return Stack Buffer Predictions.
+ */
#define MSR_IA32_FLUSH_CMD 0x0000010b
#define L1D_FLUSH BIT(0) /*
774: \
add $(BITS_PER_LONG/8) * 2, sp; \
dec reg; \
- jnz 771b;
+ jnz 771b; \
+ /* barrier for jnz misprediction */ \
+ lfence;
#ifdef __ASSEMBLY__
#endif
.endm
+.macro ISSUE_UNBALANCED_RET_GUARD
+ ANNOTATE_INTRA_FUNCTION_CALL
+ call .Lunbalanced_ret_guard_\@
+ int3
+.Lunbalanced_ret_guard_\@:
+ add $(BITS_PER_LONG/8), %_ASM_SP
+ lfence
+.endm
+
/*
* A simpler FILL_RETURN_BUFFER macro. Don't make people use the CPP
* monstrosity above, manually.
*/
-.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req
+.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req ftr2
+.ifb \ftr2
ALTERNATIVE "jmp .Lskip_rsb_\@", "", \ftr
+.else
+ ALTERNATIVE_2 "jmp .Lskip_rsb_\@", "", \ftr, "jmp .Lunbalanced_\@", \ftr2
+.endif
__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)
+.Lunbalanced_\@:
+ ISSUE_UNBALANCED_RET_GUARD
.Lskip_rsb_\@:
.endm
}
}
+static void __init spectre_v2_determine_rsb_fill_type_at_vmexit(enum spectre_v2_mitigation mode)
+{
+ /*
+ * Similar to context switches, there are two types of RSB attacks
+ * after VM exit:
+ *
+ * 1) RSB underflow
+ *
+ * 2) Poisoned RSB entry
+ *
+ * When retpoline is enabled, both are mitigated by filling/clearing
+ * the RSB.
+ *
+ * When IBRS is enabled, while #1 would be mitigated by the IBRS branch
+ * prediction isolation protections, RSB still needs to be cleared
+ * because of #2. Note that SMEP provides no protection here, unlike
+ * user-space-poisoned RSB entries.
+ *
+ * eIBRS should protect against RSB poisoning, but if the EIBRS_PBRSB
+ * bug is present then a LITE version of RSB protection is required,
+ * just a single call needs to retire before a RET is executed.
+ */
+ switch (mode) {
+ case SPECTRE_V2_NONE:
+ return;
+
+ case SPECTRE_V2_EIBRS_LFENCE:
+ case SPECTRE_V2_EIBRS:
+ if (boot_cpu_has_bug(X86_BUG_EIBRS_PBRSB)) {
+ setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT_LITE);
+ pr_info("Spectre v2 / PBRSB-eIBRS: Retire a single CALL on VMEXIT\n");
+ }
+ return;
+
+ case SPECTRE_V2_EIBRS_RETPOLINE:
+ case SPECTRE_V2_RETPOLINE:
+ case SPECTRE_V2_LFENCE:
+ case SPECTRE_V2_IBRS:
+ setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT);
+ pr_info("Spectre v2 / SpectreRSB : Filling RSB on VMEXIT\n");
+ return;
+ }
+
+ pr_warn_once("Unknown Spectre v2 mode, disabling RSB mitigation at VM exit");
+ dump_stack();
+}
+
static void __init spectre_v2_select_mitigation(void)
{
enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW);
pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n");
- /*
- * Similar to context switches, there are two types of RSB attacks
- * after vmexit:
- *
- * 1) RSB underflow
- *
- * 2) Poisoned RSB entry
- *
- * When retpoline is enabled, both are mitigated by filling/clearing
- * the RSB.
- *
- * When IBRS is enabled, while #1 would be mitigated by the IBRS branch
- * prediction isolation protections, RSB still needs to be cleared
- * because of #2. Note that SMEP provides no protection here, unlike
- * user-space-poisoned RSB entries.
- *
- * eIBRS, on the other hand, has RSB-poisoning protections, so it
- * doesn't need RSB clearing after vmexit.
- */
- if (boot_cpu_has(X86_FEATURE_RETPOLINE) ||
- boot_cpu_has(X86_FEATURE_KERNEL_IBRS))
- setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT);
+ spectre_v2_determine_rsb_fill_type_at_vmexit(mode);
/*
* Retpoline protects the kernel, but doesn't protect firmware. IBRS
return "";
}
+static char *pbrsb_eibrs_state(void)
+{
+ if (boot_cpu_has_bug(X86_BUG_EIBRS_PBRSB)) {
+ if (boot_cpu_has(X86_FEATURE_RSB_VMEXIT_LITE) ||
+ boot_cpu_has(X86_FEATURE_RSB_VMEXIT))
+ return ", PBRSB-eIBRS: SW sequence";
+ else
+ return ", PBRSB-eIBRS: Vulnerable";
+ } else {
+ return ", PBRSB-eIBRS: Not affected";
+ }
+}
+
static ssize_t spectre_v2_show_state(char *buf)
{
if (spectre_v2_enabled == SPECTRE_V2_LFENCE)
spectre_v2_enabled == SPECTRE_V2_EIBRS_LFENCE)
return sprintf(buf, "Vulnerable: eIBRS+LFENCE with unprivileged eBPF and SMT\n");
- return sprintf(buf, "%s%s%s%s%s%s\n",
+ return sprintf(buf, "%s%s%s%s%s%s%s\n",
spectre_v2_strings[spectre_v2_enabled],
ibpb_state(),
boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "",
stibp_state(),
boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? ", RSB filling" : "",
+ pbrsb_eibrs_state(),
spectre_v2_module_string());
}
#define NO_SWAPGS BIT(6)
#define NO_ITLB_MULTIHIT BIT(7)
#define NO_SPECTRE_V2 BIT(8)
+#define NO_EIBRS_PBRSB BIT(9)
#define VULNWL(vendor, family, model, whitelist) \
X86_MATCH_VENDOR_FAM_MODEL(vendor, family, model, whitelist)
VULNWL_INTEL(ATOM_GOLDMONT, NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
VULNWL_INTEL(ATOM_GOLDMONT_D, NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
- VULNWL_INTEL(ATOM_GOLDMONT_PLUS, NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
+ VULNWL_INTEL(ATOM_GOLDMONT_PLUS, NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_EIBRS_PBRSB),
/*
* Technically, swapgs isn't serializing on AMD (despite it previously
* good enough for our purposes.
*/
- VULNWL_INTEL(ATOM_TREMONT_D, NO_ITLB_MULTIHIT),
+ VULNWL_INTEL(ATOM_TREMONT, NO_EIBRS_PBRSB),
+ VULNWL_INTEL(ATOM_TREMONT_L, NO_EIBRS_PBRSB),
+ VULNWL_INTEL(ATOM_TREMONT_D, NO_ITLB_MULTIHIT | NO_EIBRS_PBRSB),
/* AMD Family 0xf - 0x12 */
VULNWL_AMD(0x0f, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
setup_force_cpu_bug(X86_BUG_RETBLEED);
}
+ if (cpu_has(c, X86_FEATURE_IBRS_ENHANCED) &&
+ !cpu_matches(cpu_vuln_whitelist, NO_EIBRS_PBRSB) &&
+ !(ia32_cap & ARCH_CAP_PBRSB_NO))
+ setup_force_cpu_bug(X86_BUG_EIBRS_PBRSB);
+
if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN))
return;
* entries and (in some cases) RSB underflow.
*
* eIBRS has its own protection against poisoned RSB, so it doesn't
- * need the RSB filling sequence. But it does need to be enabled
- * before the first unbalanced RET.
+ * need the RSB filling sequence. But it does need to be enabled, and a
+ * single call to retire, before the first unbalanced RET.
*/
- FILL_RETURN_BUFFER %_ASM_CX, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_VMEXIT
+ FILL_RETURN_BUFFER %_ASM_CX, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_VMEXIT,\
+ X86_FEATURE_RSB_VMEXIT_LITE
+
pop %_ASM_ARG2 /* @flags */
pop %_ASM_ARG1 /* @vmx */
struct page **pages = (struct page **)bv;
ssize_t size, left;
unsigned len, i = 0;
- size_t offset;
+ size_t offset, trim;
int ret = 0;
/*
* result to ensure the bio's total size is correct. The remainder of
* the iov data will be picked up in the next bio iteration.
*/
- size = iov_iter_get_pages(iter, pages, UINT_MAX - bio->bi_iter.bi_size,
+ size = iov_iter_get_pages2(iter, pages, UINT_MAX - bio->bi_iter.bi_size,
nr_pages, &offset);
- if (size > 0) {
- nr_pages = DIV_ROUND_UP(offset + size, PAGE_SIZE);
- size = ALIGN_DOWN(size, bdev_logical_block_size(bio->bi_bdev));
- } else
- nr_pages = 0;
-
- if (unlikely(size <= 0)) {
- ret = size ? size : -EFAULT;
+ if (unlikely(size <= 0))
+ return size ? size : -EFAULT;
+
+ nr_pages = DIV_ROUND_UP(offset + size, PAGE_SIZE);
+
+ trim = size & (bdev_logical_block_size(bio->bi_bdev) - 1);
+ iov_iter_revert(iter, trim);
+
+ size -= trim;
+ if (unlikely(!size)) {
+ ret = -EFAULT;
goto out;
}
offset = 0;
}
- iov_iter_advance(iter, size - left);
+ iov_iter_revert(iter, left);
out:
while (i < nr_pages)
put_page(pages[i++]);
size_t offs, added = 0;
int npages;
- bytes = iov_iter_get_pages_alloc(iter, &pages, LONG_MAX, &offs);
+ bytes = iov_iter_get_pages_alloc2(iter, &pages, LONG_MAX, &offs);
if (unlikely(bytes <= 0)) {
ret = bytes ? bytes : -EFAULT;
goto out_unmap;
bytes -= n;
offs = 0;
}
- iov_iter_advance(iter, added);
}
/*
* release the pages we didn't map into the bio, if any
put_page(pages[j++]);
kvfree(pages);
/* couldn't stuff something into bio? */
- if (bytes)
+ if (bytes) {
+ iov_iter_revert(iter, bytes);
break;
+ }
}
ret = blk_rq_append_bio(rq, bio);
if (iov_iter_rw(iter) == READ) {
bio_init(&bio, bdev, vecs, nr_pages, REQ_OP_READ);
- if (iter_is_iovec(iter))
+ if (user_backed_iter(iter))
should_dirty = true;
} else {
bio_init(&bio, bdev, vecs, nr_pages, dio_bio_write_op(iocb));
}
dio->size = 0;
- if (is_read && iter_is_iovec(iter))
+ if (is_read && user_backed_iter(iter))
dio->flags |= DIO_SHOULD_DIRTY;
blk_start_plug(&plug);
dio->size = bio->bi_iter.bi_size;
if (is_read) {
- if (iter_is_iovec(iter)) {
+ if (user_backed_iter(iter)) {
dio->flags |= DIO_SHOULD_DIRTY;
bio_set_pages_dirty(bio);
}
#
obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
-obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o
+obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o blacklist_hashes.o
obj-$(CONFIG_SYSTEM_REVOCATION_LIST) += revocation_certificates.o
-ifneq ($(CONFIG_SYSTEM_BLACKLIST_HASH_LIST),)
$(obj)/blacklist_hashes.o: $(obj)/blacklist_hash_list
CFLAGS_blacklist_hashes.o := -I $(obj)
quiet_cmd_check_and_copy_blacklist_hash_list = GEN $@
cmd_check_and_copy_blacklist_hash_list = \
- $(AWK) -f $(srctree)/scripts/check-blacklist-hashes.awk $(CONFIG_SYSTEM_BLACKLIST_HASH_LIST) >&2; \
- cat $(CONFIG_SYSTEM_BLACKLIST_HASH_LIST) > $@
+ $(if $(CONFIG_SYSTEM_BLACKLIST_HASH_LIST), \
+ $(AWK) -f $(srctree)/$(src)/check-blacklist-hashes.awk $(CONFIG_SYSTEM_BLACKLIST_HASH_LIST) >&2; \
+ { cat $(CONFIG_SYSTEM_BLACKLIST_HASH_LIST); echo $(comma) NULL; } > $@, \
+ echo NULL > $@)
$(obj)/blacklist_hash_list: $(CONFIG_SYSTEM_BLACKLIST_HASH_LIST) FORCE
$(call if_changed,check_and_copy_blacklist_hash_list)
-obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_hashes.o
-else
-obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_nohashes.o
-endif
+
targets += blacklist_hash_list
quiet_cmd_extract_certs = CERT $@
const char __initconst *const blacklist_hashes[] = {
#include "blacklist_hash_list"
- , NULL
};
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0
-#include "blacklist.h"
-
-const char __initconst *const blacklist_hashes[] = {
- NULL
-};
--- /dev/null
+#!/usr/bin/awk -f
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright © 2020, Microsoft Corporation. All rights reserved.
+#
+# Author: Mickaël Salaün <mic@linux.microsoft.com>
+#
+# Check that a CONFIG_SYSTEM_BLACKLIST_HASH_LIST file contains a valid array of
+# hash strings. Such string must start with a prefix ("tbs" or "bin"), then a
+# colon (":"), and finally an even number of hexadecimal lowercase characters
+# (up to 128).
+
+BEGIN {
+ RS = ","
+}
+{
+ if (!match($0, "^[ \t\n\r]*\"([^\"]*)\"[ \t\n\r]*$", part1)) {
+ print "Not a string (item " NR "):", $0;
+ exit 1;
+ }
+ if (!match(part1[1], "^(tbs|bin):(.*)$", part2)) {
+ print "Unknown prefix (item " NR "):", part1[1];
+ exit 1;
+ }
+ if (!match(part2[2], "^([0-9a-f]+)$", part3)) {
+ print "Not a lowercase hexadecimal string (item " NR "):", part2[2];
+ exit 1;
+ }
+ if (length(part3[1]) > 128) {
+ print "Hash string too long (item " NR "):", part3[1];
+ exit 1;
+ }
+ if (length(part3[1]) % 2 == 1) {
+ print "Not an even number of hexadecimal characters (item " NR "):", part3[1];
+ exit 1;
+ }
+}
ssize_t n;
int npages, i;
- n = iov_iter_get_pages(iter, sgl->pages, len, ALG_MAX_PAGES, &off);
+ n = iov_iter_get_pages2(iter, sgl->pages, len, ALG_MAX_PAGES, &off);
if (n < 0)
return n;
len += err;
atomic_add(err, &ctx->rcvused);
rsgl->sg_num_bytes = err;
- iov_iter_advance(&msg->msg_iter, err);
}
*outlen = len;
err = crypto_wait_req(crypto_ahash_update(&ctx->req),
&ctx->wait);
af_alg_free_sg(&ctx->sgl);
- if (err)
+ if (err) {
+ iov_iter_revert(&msg->msg_iter, len);
goto unlock;
+ }
copied += len;
- iov_iter_advance(&msg->msg_iter, len);
}
err = 0;
cpumask_var_t cpus;
struct device *cpu_dev;
- struct opp_table *opp_table;
struct cpufreq_frequency_table *freq_table;
bool have_static_opps;
+ int opp_token;
};
static LIST_HEAD(priv_list);
struct private_data *priv;
struct device *cpu_dev;
bool fallback = false;
- const char *reg_name;
+ const char *reg_name[] = { NULL, NULL };
int ret;
/* Check if this CPU is already covered by some other policy */
* OPP layer will be taking care of regulators now, but it needs to know
* the name of the regulator first.
*/
- reg_name = find_supply_name(cpu_dev);
- if (reg_name) {
- priv->opp_table = dev_pm_opp_set_regulators(cpu_dev, ®_name,
- 1);
- if (IS_ERR(priv->opp_table)) {
- ret = PTR_ERR(priv->opp_table);
+ reg_name[0] = find_supply_name(cpu_dev);
+ if (reg_name[0]) {
+ priv->opp_token = dev_pm_opp_set_regulators(cpu_dev, reg_name);
+ if (priv->opp_token < 0) {
+ ret = priv->opp_token;
if (ret != -EPROBE_DEFER)
dev_err(cpu_dev, "failed to set regulators: %d\n",
ret);
out:
if (priv->have_static_opps)
dev_pm_opp_of_cpumask_remove_table(priv->cpus);
- dev_pm_opp_put_regulators(priv->opp_table);
+ dev_pm_opp_put_regulators(priv->opp_token);
free_cpumask:
free_cpumask_var(priv->cpus);
return ret;
dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &priv->freq_table);
if (priv->have_static_opps)
dev_pm_opp_of_cpumask_remove_table(priv->cpus);
- dev_pm_opp_put_regulators(priv->opp_table);
+ dev_pm_opp_put_regulators(priv->opp_token);
free_cpumask_var(priv->cpus);
list_del(&priv->node);
}
}
if (!new_policy && cpufreq_driver->online) {
+ /* Recover policy->cpus using related_cpus */
+ cpumask_copy(policy->cpus, policy->related_cpus);
+
ret = cpufreq_driver->online(policy);
if (ret) {
pr_debug("%s: %d: initialization failed\n", __func__,
__LINE__);
goto out_exit_policy;
}
-
- /* Recover policy->cpus using related_cpus */
- cpumask_copy(policy->cpus, policy->related_cpus);
} else {
cpumask_copy(policy->cpus, cpumask_of(cpu));
/* cpufreq-dt device registered by imx-cpufreq-dt */
static struct platform_device *cpufreq_dt_pdev;
-static struct opp_table *cpufreq_opp_table;
static struct device *cpu_dev;
+static int cpufreq_opp_token;
enum IMX7ULP_CPUFREQ_CLKS {
ARM,
dev_info(&pdev->dev, "cpu speed grade %d mkt segment %d supported-hw %#x %#x\n",
speed_grade, mkt_segment, supported_hw[0], supported_hw[1]);
- cpufreq_opp_table = dev_pm_opp_set_supported_hw(cpu_dev, supported_hw, 2);
- if (IS_ERR(cpufreq_opp_table)) {
- ret = PTR_ERR(cpufreq_opp_table);
+ cpufreq_opp_token = dev_pm_opp_set_supported_hw(cpu_dev, supported_hw, 2);
+ if (cpufreq_opp_token < 0) {
+ ret = cpufreq_opp_token;
dev_err(&pdev->dev, "Failed to set supported opp: %d\n", ret);
return ret;
}
cpufreq_dt_pdev = platform_device_register_data(
&pdev->dev, "cpufreq-dt", -1, NULL, 0);
if (IS_ERR(cpufreq_dt_pdev)) {
- dev_pm_opp_put_supported_hw(cpufreq_opp_table);
+ dev_pm_opp_put_supported_hw(cpufreq_opp_token);
ret = PTR_ERR(cpufreq_dt_pdev);
dev_err(&pdev->dev, "Failed to register cpufreq-dt: %d\n", ret);
return ret;
{
platform_device_unregister(cpufreq_dt_pdev);
if (!of_machine_is_compatible("fsl,imx7ulp"))
- dev_pm_opp_put_supported_hw(cpufreq_opp_table);
+ dev_pm_opp_put_supported_hw(cpufreq_opp_token);
else
clk_bulk_put(ARRAY_SIZE(imx7ulp_clks), imx7ulp_clks);
if (info->soc_data->ccifreq_supported) {
info->vproc_on_boot = regulator_get_voltage(info->proc_reg);
if (info->vproc_on_boot < 0) {
+ ret = info->vproc_on_boot;
dev_err(info->cpu_dev,
"invalid Vproc value: %d\n", info->vproc_on_boot);
goto out_disable_inter_clock;
#include <linux/pm_opp.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/units.h>
#define LUT_MAX_ENTRIES 40U
#define LUT_SRC GENMASK(31, 30)
#define GT_IRQ_STATUS BIT(2)
-#define HZ_PER_KHZ 1000
-
struct qcom_cpufreq_soc_data {
u32 reg_enable;
u32 reg_domain_state;
return 0;
}
- ret = irq_set_affinity_hint(data->throttle_irq, policy->cpus);
+ ret = irq_set_affinity_and_hint(data->throttle_irq, policy->cpus);
if (ret)
dev_err(&pdev->dev, "Failed to set CPU affinity of %s[%d]\n",
data->irq_name, data->throttle_irq);
if (data->throttle_irq <= 0)
return 0;
- ret = irq_set_affinity_hint(data->throttle_irq, policy->cpus);
+ mutex_lock(&data->throttle_lock);
+ data->cancel_throttle = false;
+ mutex_unlock(&data->throttle_lock);
+
+ ret = irq_set_affinity_and_hint(data->throttle_irq, policy->cpus);
if (ret)
dev_err(&pdev->dev, "Failed to set CPU affinity of %s[%d]\n",
data->irq_name, data->throttle_irq);
mutex_unlock(&data->throttle_lock);
cancel_delayed_work_sync(&data->throttle_work);
- irq_set_affinity_hint(data->throttle_irq, NULL);
+ irq_set_affinity_and_hint(data->throttle_irq, NULL);
+ disable_irq_nosync(data->throttle_irq);
return 0;
}
};
struct qcom_cpufreq_drv {
- struct opp_table **names_opp_tables;
- struct opp_table **hw_opp_tables;
- struct opp_table **genpd_opp_tables;
+ int *opp_tokens;
u32 versions;
const struct qcom_cpufreq_match_data *data;
};
}
of_node_put(np);
- drv->names_opp_tables = kcalloc(num_possible_cpus(),
- sizeof(*drv->names_opp_tables),
+ drv->opp_tokens = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tokens),
GFP_KERNEL);
- if (!drv->names_opp_tables) {
+ if (!drv->opp_tokens) {
ret = -ENOMEM;
goto free_drv;
}
- drv->hw_opp_tables = kcalloc(num_possible_cpus(),
- sizeof(*drv->hw_opp_tables),
- GFP_KERNEL);
- if (!drv->hw_opp_tables) {
- ret = -ENOMEM;
- goto free_opp_names;
- }
-
- drv->genpd_opp_tables = kcalloc(num_possible_cpus(),
- sizeof(*drv->genpd_opp_tables),
- GFP_KERNEL);
- if (!drv->genpd_opp_tables) {
- ret = -ENOMEM;
- goto free_opp;
- }
for_each_possible_cpu(cpu) {
+ struct dev_pm_opp_config config = {
+ .supported_hw = NULL,
+ };
+
cpu_dev = get_cpu_device(cpu);
if (NULL == cpu_dev) {
ret = -ENODEV;
- goto free_genpd_opp;
+ goto free_opp;
}
if (drv->data->get_version) {
+ config.supported_hw = &drv->versions;
+ config.supported_hw_count = 1;
- if (pvs_name) {
- drv->names_opp_tables[cpu] = dev_pm_opp_set_prop_name(
- cpu_dev,
- pvs_name);
- if (IS_ERR(drv->names_opp_tables[cpu])) {
- ret = PTR_ERR(drv->names_opp_tables[cpu]);
- dev_err(cpu_dev, "Failed to add OPP name %s\n",
- pvs_name);
- goto free_opp;
- }
- }
-
- drv->hw_opp_tables[cpu] = dev_pm_opp_set_supported_hw(
- cpu_dev, &drv->versions, 1);
- if (IS_ERR(drv->hw_opp_tables[cpu])) {
- ret = PTR_ERR(drv->hw_opp_tables[cpu]);
- dev_err(cpu_dev,
- "Failed to set supported hardware\n");
- goto free_genpd_opp;
- }
+ if (pvs_name)
+ config.prop_name = pvs_name;
}
if (drv->data->genpd_names) {
- drv->genpd_opp_tables[cpu] =
- dev_pm_opp_attach_genpd(cpu_dev,
- drv->data->genpd_names,
- NULL);
- if (IS_ERR(drv->genpd_opp_tables[cpu])) {
- ret = PTR_ERR(drv->genpd_opp_tables[cpu]);
- if (ret != -EPROBE_DEFER)
- dev_err(cpu_dev,
- "Could not attach to pm_domain: %d\n",
- ret);
- goto free_genpd_opp;
+ config.genpd_names = drv->data->genpd_names;
+ config.virt_devs = NULL;
+ }
+
+ if (config.supported_hw || config.genpd_names) {
+ drv->opp_tokens[cpu] = dev_pm_opp_set_config(cpu_dev, &config);
+ if (drv->opp_tokens[cpu] < 0) {
+ ret = drv->opp_tokens[cpu];
+ dev_err(cpu_dev, "Failed to set OPP config\n");
+ goto free_opp;
}
}
}
ret = PTR_ERR(cpufreq_dt_pdev);
dev_err(cpu_dev, "Failed to register platform device\n");
-free_genpd_opp:
- for_each_possible_cpu(cpu) {
- if (IS_ERR(drv->genpd_opp_tables[cpu]))
- break;
- dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
- }
- kfree(drv->genpd_opp_tables);
free_opp:
- for_each_possible_cpu(cpu) {
- if (IS_ERR(drv->names_opp_tables[cpu]))
- break;
- dev_pm_opp_put_prop_name(drv->names_opp_tables[cpu]);
- }
- for_each_possible_cpu(cpu) {
- if (IS_ERR(drv->hw_opp_tables[cpu]))
- break;
- dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
- }
- kfree(drv->hw_opp_tables);
-free_opp_names:
- kfree(drv->names_opp_tables);
+ for_each_possible_cpu(cpu)
+ dev_pm_opp_clear_config(drv->opp_tokens[cpu]);
+ kfree(drv->opp_tokens);
free_drv:
kfree(drv);
platform_device_unregister(cpufreq_dt_pdev);
- for_each_possible_cpu(cpu) {
- dev_pm_opp_put_supported_hw(drv->names_opp_tables[cpu]);
- dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
- dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
- }
+ for_each_possible_cpu(cpu)
+ dev_pm_opp_clear_config(drv->opp_tokens[cpu]);
- kfree(drv->names_opp_tables);
- kfree(drv->hw_opp_tables);
- kfree(drv->genpd_opp_tables);
+ kfree(drv->opp_tokens);
kfree(drv);
return 0;
unsigned int hw_info_offset;
unsigned int version[VERSION_ELEMENTS];
int pcode, substrate, major, minor;
- int ret;
+ int opp_token, ret;
char name[MAX_PCODE_NAME_LEN];
- struct opp_table *opp_table;
+ struct dev_pm_opp_config config = {
+ .supported_hw = version,
+ .supported_hw_count = ARRAY_SIZE(version),
+ .prop_name = name,
+ };
reg_fields = sti_cpufreq_match();
if (!reg_fields) {
snprintf(name, MAX_PCODE_NAME_LEN, "pcode%d", pcode);
- opp_table = dev_pm_opp_set_prop_name(dev, name);
- if (IS_ERR(opp_table)) {
- dev_err(dev, "Failed to set prop name\n");
- return PTR_ERR(opp_table);
- }
-
version[0] = BIT(major);
version[1] = BIT(minor);
version[2] = BIT(substrate);
- opp_table = dev_pm_opp_set_supported_hw(dev, version, VERSION_ELEMENTS);
- if (IS_ERR(opp_table)) {
- dev_err(dev, "Failed to set supported hardware\n");
- ret = PTR_ERR(opp_table);
- goto err_put_prop_name;
+ opp_token = dev_pm_opp_set_config(dev, &config);
+ if (opp_token < 0) {
+ dev_err(dev, "Failed to set OPP config\n");
+ return opp_token;
}
dev_dbg(dev, "pcode: %d major: %d minor: %d substrate: %d\n",
version[0], version[1], version[2]);
return 0;
-
-err_put_prop_name:
- dev_pm_opp_put_prop_name(opp_table);
- return ret;
}
static int sti_cpufreq_fetch_syscon_registers(void)
static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
{
- struct opp_table **opp_tables;
+ int *opp_tokens;
char name[MAX_NAME_LEN];
unsigned int cpu;
u32 speed = 0;
int ret;
- opp_tables = kcalloc(num_possible_cpus(), sizeof(*opp_tables),
+ opp_tokens = kcalloc(num_possible_cpus(), sizeof(*opp_tokens),
GFP_KERNEL);
- if (!opp_tables)
+ if (!opp_tokens)
return -ENOMEM;
ret = sun50i_cpufreq_get_efuse(&speed);
if (ret) {
- kfree(opp_tables);
+ kfree(opp_tokens);
return ret;
}
goto free_opp;
}
- opp_tables[cpu] = dev_pm_opp_set_prop_name(cpu_dev, name);
- if (IS_ERR(opp_tables[cpu])) {
- ret = PTR_ERR(opp_tables[cpu]);
+ opp_tokens[cpu] = dev_pm_opp_set_prop_name(cpu_dev, name);
+ if (opp_tokens[cpu] < 0) {
+ ret = opp_tokens[cpu];
pr_err("Failed to set prop name\n");
goto free_opp;
}
cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
NULL, 0);
if (!IS_ERR(cpufreq_dt_pdev)) {
- platform_set_drvdata(pdev, opp_tables);
+ platform_set_drvdata(pdev, opp_tokens);
return 0;
}
pr_err("Failed to register platform device\n");
free_opp:
- for_each_possible_cpu(cpu) {
- if (IS_ERR_OR_NULL(opp_tables[cpu]))
- break;
- dev_pm_opp_put_prop_name(opp_tables[cpu]);
- }
- kfree(opp_tables);
+ for_each_possible_cpu(cpu)
+ dev_pm_opp_put_prop_name(opp_tokens[cpu]);
+ kfree(opp_tokens);
return ret;
}
static int sun50i_cpufreq_nvmem_remove(struct platform_device *pdev)
{
- struct opp_table **opp_tables = platform_get_drvdata(pdev);
+ int *opp_tokens = platform_get_drvdata(pdev);
unsigned int cpu;
platform_device_unregister(cpufreq_dt_pdev);
for_each_possible_cpu(cpu)
- dev_pm_opp_put_prop_name(opp_tables[cpu]);
+ dev_pm_opp_put_prop_name(opp_tokens[cpu]);
- kfree(opp_tables);
+ kfree(opp_tokens);
return 0;
}
.set_cpu_ndiv = tegra234_set_cpu_ndiv,
};
-const struct tegra_cpufreq_soc tegra234_cpufreq_soc = {
+static const struct tegra_cpufreq_soc tegra234_cpufreq_soc = {
.ops = &tegra234_cpufreq_ops,
.actmon_cntr_base = 0x9000,
.maxcpus_per_cluster = 4,
.set_cpu_ndiv = tegra194_set_cpu_ndiv,
};
-const struct tegra_cpufreq_soc tegra194_cpufreq_soc = {
+static const struct tegra_cpufreq_soc tegra194_cpufreq_soc = {
.ops = &tegra194_cpufreq_ops,
.maxcpus_per_cluster = 2,
};
return ret;
}
-static void tegra20_cpufreq_put_supported_hw(void *opp_table)
+static void tegra20_cpufreq_put_supported_hw(void *opp_token)
{
- dev_pm_opp_put_supported_hw(opp_table);
+ dev_pm_opp_put_supported_hw((unsigned long) opp_token);
}
static void tegra20_cpufreq_dt_unregister(void *cpufreq_dt)
static int tegra20_cpufreq_probe(struct platform_device *pdev)
{
struct platform_device *cpufreq_dt;
- struct opp_table *opp_table;
struct device *cpu_dev;
u32 versions[2];
int err;
if (WARN_ON(!cpu_dev))
return -ENODEV;
- opp_table = dev_pm_opp_set_supported_hw(cpu_dev, versions, 2);
- err = PTR_ERR_OR_ZERO(opp_table);
- if (err) {
+ err = dev_pm_opp_set_supported_hw(cpu_dev, versions, 2);
+ if (err < 0) {
dev_err(&pdev->dev, "failed to set supported hw: %d\n", err);
return err;
}
err = devm_add_action_or_reset(&pdev->dev,
tegra20_cpufreq_put_supported_hw,
- opp_table);
+ (void *)((unsigned long) err));
if (err)
return err;
struct device_node *opp_node;
struct regmap *syscon;
const struct ti_cpufreq_soc_data *soc_data;
- struct opp_table *opp_table;
};
static unsigned long amx3_efuse_xlate(struct ti_cpufreq_data *opp_data,
* seems to always read as 0).
*/
-static const char * const omap3_reg_names[] = {"cpu0", "vbb"};
+static const char * const omap3_reg_names[] = {"cpu0", "vbb", NULL};
static struct ti_cpufreq_soc_data omap36xx_soc_data = {
.reg_names = omap3_reg_names,
{
u32 version[VERSION_COUNT];
const struct of_device_id *match;
- struct opp_table *ti_opp_table;
struct ti_cpufreq_data *opp_data;
- const char * const default_reg_names[] = {"vdd", "vbb"};
+ const char * const default_reg_names[] = {"vdd", "vbb", NULL};
int ret;
+ struct dev_pm_opp_config config = {
+ .supported_hw = version,
+ .supported_hw_count = ARRAY_SIZE(version),
+ };
match = dev_get_platdata(&pdev->dev);
if (!match)
if (ret)
goto fail_put_node;
- ti_opp_table = dev_pm_opp_set_supported_hw(opp_data->cpu_dev,
- version, VERSION_COUNT);
- if (IS_ERR(ti_opp_table)) {
- dev_err(opp_data->cpu_dev,
- "Failed to set supported hardware\n");
- ret = PTR_ERR(ti_opp_table);
- goto fail_put_node;
- }
-
- opp_data->opp_table = ti_opp_table;
-
if (opp_data->soc_data->multi_regulator) {
- const char * const *reg_names = default_reg_names;
-
if (opp_data->soc_data->reg_names)
- reg_names = opp_data->soc_data->reg_names;
- ti_opp_table = dev_pm_opp_set_regulators(opp_data->cpu_dev,
- reg_names,
- ARRAY_SIZE(default_reg_names));
- if (IS_ERR(ti_opp_table)) {
- dev_pm_opp_put_supported_hw(opp_data->opp_table);
- ret = PTR_ERR(ti_opp_table);
- goto fail_put_node;
- }
+ config.regulator_names = opp_data->soc_data->reg_names;
+ else
+ config.regulator_names = default_reg_names;
+ }
+
+ ret = dev_pm_opp_set_config(opp_data->cpu_dev, &config);
+ if (ret < 0) {
+ dev_err(opp_data->cpu_dev, "Failed to set OPP config\n");
+ goto fail_put_node;
}
of_node_put(opp_data->opp_node);
+
register_cpufreq_dt:
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
* This code is licenced under the GPL.
*/
+#include "linux/percpu-defs.h"
#include <linux/clockchips.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
/* Shallower states are enabled, so update. */
dev->states_usage[entered_state].above++;
+ trace_cpu_idle_miss(dev->cpu, entered_state, false);
break;
}
} else if (diff > delay) {
* Update if a deeper state would have been a
* better match for the observed idle duration.
*/
- if (diff - delay >= drv->states[i].target_residency_ns)
+ if (diff - delay >= drv->states[i].target_residency_ns) {
dev->states_usage[entered_state].below++;
+ trace_cpu_idle_miss(dev->cpu, entered_state, true);
+ }
break;
}
menuconfig CXL_BUS
tristate "CXL (Compute Express Link) Devices Support"
depends on PCI
+ select PCI_DOE
help
CXL is a bus that is electrically compatible with PCI Express, but
layers three protocols on that signalling (CXL.io, CXL.cache, and
def_bool y
depends on SUSPEND && CXL_MEM
+config CXL_REGION
+ bool
+ default CXL_BUS
+ # For MAX_PHYSMEM_BITS
+ depends on SPARSEMEM
+ select MEMREGION
+ select GET_FREE_REGION
+
endif
#include "cxlpci.h"
#include "cxl.h"
-/* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */
-#define CFMWS_INTERLEAVE_WAYS(x) (1 << (x)->interleave_ways)
-#define CFMWS_INTERLEAVE_GRANULARITY(x) ((x)->granularity + 8)
-
static unsigned long cfmws_to_decoder_flags(int restrictions)
{
unsigned long flags = CXL_DECODER_F_ENABLE;
static int cxl_acpi_cfmws_verify(struct device *dev,
struct acpi_cedt_cfmws *cfmws)
{
- int expected_len;
+ int rc, expected_len;
+ unsigned int ways;
if (cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_MODULO) {
dev_err(dev, "CFMWS Unsupported Interleave Arithmetic\n");
return -EINVAL;
}
- if (CFMWS_INTERLEAVE_WAYS(cfmws) > CXL_DECODER_MAX_INTERLEAVE) {
- dev_err(dev, "CFMWS Interleave Ways (%d) too large\n",
- CFMWS_INTERLEAVE_WAYS(cfmws));
+ rc = cxl_to_ways(cfmws->interleave_ways, &ways);
+ if (rc) {
+ dev_err(dev, "CFMWS Interleave Ways (%d) invalid\n",
+ cfmws->interleave_ways);
return -EINVAL;
}
- expected_len = struct_size((cfmws), interleave_targets,
- CFMWS_INTERLEAVE_WAYS(cfmws));
+ expected_len = struct_size(cfmws, interleave_targets, ways);
if (cfmws->header.length < expected_len) {
dev_err(dev, "CFMWS length %d less than expected %d\n",
struct cxl_cfmws_context {
struct device *dev;
struct cxl_port *root_port;
+ struct resource *cxl_res;
+ int id;
};
static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
int target_map[CXL_DECODER_MAX_INTERLEAVE];
struct cxl_cfmws_context *ctx = arg;
struct cxl_port *root_port = ctx->root_port;
+ struct resource *cxl_res = ctx->cxl_res;
+ struct cxl_root_decoder *cxlrd;
struct device *dev = ctx->dev;
struct acpi_cedt_cfmws *cfmws;
struct cxl_decoder *cxld;
- int rc, i;
+ unsigned int ways, i, ig;
+ struct resource *res;
+ int rc;
cfmws = (struct acpi_cedt_cfmws *) header;
return 0;
}
- for (i = 0; i < CFMWS_INTERLEAVE_WAYS(cfmws); i++)
+ rc = cxl_to_ways(cfmws->interleave_ways, &ways);
+ if (rc)
+ return rc;
+ rc = cxl_to_granularity(cfmws->granularity, &ig);
+ if (rc)
+ return rc;
+ for (i = 0; i < ways; i++)
target_map[i] = cfmws->interleave_targets[i];
- cxld = cxl_root_decoder_alloc(root_port, CFMWS_INTERLEAVE_WAYS(cfmws));
- if (IS_ERR(cxld))
+ res = kzalloc(sizeof(*res), GFP_KERNEL);
+ if (!res)
+ return -ENOMEM;
+
+ res->name = kasprintf(GFP_KERNEL, "CXL Window %d", ctx->id++);
+ if (!res->name)
+ goto err_name;
+
+ res->start = cfmws->base_hpa;
+ res->end = cfmws->base_hpa + cfmws->window_size - 1;
+ res->flags = IORESOURCE_MEM;
+
+ /* add to the local resource tracking to establish a sort order */
+ rc = insert_resource(cxl_res, res);
+ if (rc)
+ goto err_insert;
+
+ cxlrd = cxl_root_decoder_alloc(root_port, ways);
+ if (IS_ERR(cxlrd))
return 0;
+ cxld = &cxlrd->cxlsd.cxld;
cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
cxld->target_type = CXL_DECODER_EXPANDER;
- cxld->platform_res = (struct resource)DEFINE_RES_MEM(cfmws->base_hpa,
- cfmws->window_size);
- cxld->interleave_ways = CFMWS_INTERLEAVE_WAYS(cfmws);
- cxld->interleave_granularity = CFMWS_INTERLEAVE_GRANULARITY(cfmws);
+ cxld->hpa_range = (struct range) {
+ .start = res->start,
+ .end = res->end,
+ };
+ cxld->interleave_ways = ways;
+ /*
+ * Minimize the x1 granularity to advertise support for any
+ * valid region granularity
+ */
+ if (ways == 1)
+ ig = CXL_DECODER_MIN_GRANULARITY;
+ cxld->interleave_granularity = ig;
rc = cxl_decoder_add(cxld, target_map);
if (rc)
else
rc = cxl_decoder_autoremove(dev, cxld);
if (rc) {
- dev_err(dev, "Failed to add decoder for %pr\n",
- &cxld->platform_res);
+ dev_err(dev, "Failed to add decode range [%#llx - %#llx]\n",
+ cxld->hpa_range.start, cxld->hpa_range.end);
return 0;
}
- dev_dbg(dev, "add: %s node: %d range %pr\n", dev_name(&cxld->dev),
- phys_to_target_node(cxld->platform_res.start),
- &cxld->platform_res);
+ dev_dbg(dev, "add: %s node: %d range [%#llx - %#llx]\n",
+ dev_name(&cxld->dev),
+ phys_to_target_node(cxld->hpa_range.start),
+ cxld->hpa_range.start, cxld->hpa_range.end);
return 0;
+
+err_insert:
+ kfree(res->name);
+err_name:
+ kfree(res);
+ return -ENOMEM;
}
__mock struct acpi_device *to_cxl_host_bridge(struct device *host,
if (rc)
return rc;
- port = devm_cxl_add_port(host, match, dport->component_reg_phys,
- root_port);
+ port = devm_cxl_add_port(host, match, dport->component_reg_phys, dport);
if (IS_ERR(port))
return PTR_ERR(port);
dev_dbg(host, "%s: add: %s\n", dev_name(match), dev_name(&port->dev));
device_lock_reset_class(dev);
}
+static void del_cxl_resource(struct resource *res)
+{
+ kfree(res->name);
+ kfree(res);
+}
+
+static void cxl_set_public_resource(struct resource *priv, struct resource *pub)
+{
+ priv->desc = (unsigned long) pub;
+}
+
+static struct resource *cxl_get_public_resource(struct resource *priv)
+{
+ return (struct resource *) priv->desc;
+}
+
+static void remove_cxl_resources(void *data)
+{
+ struct resource *res, *next, *cxl = data;
+
+ for (res = cxl->child; res; res = next) {
+ struct resource *victim = cxl_get_public_resource(res);
+
+ next = res->sibling;
+ remove_resource(res);
+
+ if (victim) {
+ remove_resource(victim);
+ kfree(victim);
+ }
+
+ del_cxl_resource(res);
+ }
+}
+
+/**
+ * add_cxl_resources() - reflect CXL fixed memory windows in iomem_resource
+ * @cxl_res: A standalone resource tree where each CXL window is a sibling
+ *
+ * Walk each CXL window in @cxl_res and add it to iomem_resource potentially
+ * expanding its boundaries to ensure that any conflicting resources become
+ * children. If a window is expanded it may then conflict with a another window
+ * entry and require the window to be truncated or trimmed. Consider this
+ * situation:
+ *
+ * |-- "CXL Window 0" --||----- "CXL Window 1" -----|
+ * |--------------- "System RAM" -------------|
+ *
+ * ...where platform firmware has established as System RAM resource across 2
+ * windows, but has left some portion of window 1 for dynamic CXL region
+ * provisioning. In this case "Window 0" will span the entirety of the "System
+ * RAM" span, and "CXL Window 1" is truncated to the remaining tail past the end
+ * of that "System RAM" resource.
+ */
+static int add_cxl_resources(struct resource *cxl_res)
+{
+ struct resource *res, *new, *next;
+
+ for (res = cxl_res->child; res; res = next) {
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!new)
+ return -ENOMEM;
+ new->name = res->name;
+ new->start = res->start;
+ new->end = res->end;
+ new->flags = IORESOURCE_MEM;
+ new->desc = IORES_DESC_CXL;
+
+ /*
+ * Record the public resource in the private cxl_res tree for
+ * later removal.
+ */
+ cxl_set_public_resource(res, new);
+
+ insert_resource_expand_to_fit(&iomem_resource, new);
+
+ next = res->sibling;
+ while (next && resource_overlaps(new, next)) {
+ if (resource_contains(new, next)) {
+ struct resource *_next = next->sibling;
+
+ remove_resource(next);
+ del_cxl_resource(next);
+ next = _next;
+ } else
+ next->start = new->end + 1;
+ }
+ }
+ return 0;
+}
+
+static int pair_cxl_resource(struct device *dev, void *data)
+{
+ struct resource *cxl_res = data;
+ struct resource *p;
+
+ if (!is_root_decoder(dev))
+ return 0;
+
+ for (p = cxl_res->child; p; p = p->sibling) {
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+ struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
+ struct resource res = {
+ .start = cxld->hpa_range.start,
+ .end = cxld->hpa_range.end,
+ .flags = IORESOURCE_MEM,
+ };
+
+ if (resource_contains(p, &res)) {
+ cxlrd->res = cxl_get_public_resource(p);
+ break;
+ }
+ }
+
+ return 0;
+}
+
static int cxl_acpi_probe(struct platform_device *pdev)
{
int rc;
+ struct resource *cxl_res;
struct cxl_port *root_port;
struct device *host = &pdev->dev;
struct acpi_device *adev = ACPI_COMPANION(host);
if (rc)
return rc;
+ cxl_res = devm_kzalloc(host, sizeof(*cxl_res), GFP_KERNEL);
+ if (!cxl_res)
+ return -ENOMEM;
+ cxl_res->name = "CXL mem";
+ cxl_res->start = 0;
+ cxl_res->end = -1;
+ cxl_res->flags = IORESOURCE_MEM;
+
root_port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL);
if (IS_ERR(root_port))
return PTR_ERR(root_port);
if (rc < 0)
return rc;
+ rc = devm_add_action_or_reset(host, remove_cxl_resources, cxl_res);
+ if (rc)
+ return rc;
+
ctx = (struct cxl_cfmws_context) {
.dev = host,
.root_port = root_port,
+ .cxl_res = cxl_res,
};
- acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, cxl_parse_cfmws, &ctx);
+ rc = acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, cxl_parse_cfmws, &ctx);
+ if (rc < 0)
+ return -ENXIO;
+
+ rc = add_cxl_resources(cxl_res);
+ if (rc)
+ return rc;
+
+ /*
+ * Populate the root decoders with their related iomem resource,
+ * if present
+ */
+ device_for_each_child(&root_port->dev, cxl_res, pair_cxl_resource);
/*
* Root level scanned with host-bridge as dports, now scan host-bridges
};
MODULE_DEVICE_TABLE(acpi, cxl_acpi_ids);
+static const struct platform_device_id cxl_test_ids[] = {
+ { "cxl_acpi" },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, cxl_test_ids);
+
static struct platform_driver cxl_acpi_driver = {
.probe = cxl_acpi_probe,
.driver = {
.name = KBUILD_MODNAME,
.acpi_match_table = cxl_acpi_ids,
},
+ .id_table = cxl_test_ids,
};
module_platform_driver(cxl_acpi_driver);
cxl_core-y += mbox.o
cxl_core-y += pci.o
cxl_core-y += hdm.o
+cxl_core-$(CONFIG_CXL_REGION) += region.o
extern struct attribute_group cxl_base_attribute_group;
+#ifdef CONFIG_CXL_REGION
+extern struct device_attribute dev_attr_create_pmem_region;
+extern struct device_attribute dev_attr_delete_region;
+extern struct device_attribute dev_attr_region;
+extern const struct device_type cxl_pmem_region_type;
+extern const struct device_type cxl_region_type;
+void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled);
+#define CXL_REGION_ATTR(x) (&dev_attr_##x.attr)
+#define CXL_REGION_TYPE(x) (&cxl_region_type)
+#define SET_CXL_REGION_ATTR(x) (&dev_attr_##x.attr),
+#define CXL_PMEM_REGION_TYPE(x) (&cxl_pmem_region_type)
+int cxl_region_init(void);
+void cxl_region_exit(void);
+#else
+static inline void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled)
+{
+}
+static inline int cxl_region_init(void)
+{
+ return 0;
+}
+static inline void cxl_region_exit(void)
+{
+}
+#define CXL_REGION_ATTR(x) NULL
+#define CXL_REGION_TYPE(x) NULL
+#define SET_CXL_REGION_ATTR(x)
+#define CXL_PMEM_REGION_TYPE(x) NULL
+#endif
+
struct cxl_send_command;
struct cxl_mem_query_commands;
int cxl_query_cmd(struct cxl_memdev *cxlmd,
void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
resource_size_t length);
+struct dentry *cxl_debugfs_create_dir(const char *dir);
+int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled,
+ enum cxl_decoder_mode mode);
+int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, unsigned long long size);
+int cxl_dpa_free(struct cxl_endpoint_decoder *cxled);
+resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled);
+resource_size_t cxl_dpa_resource_start(struct cxl_endpoint_decoder *cxled);
+extern struct rw_semaphore cxl_dpa_rwsem;
+
+bool is_switch_decoder(struct device *dev);
+struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev);
+static inline struct cxl_ep *cxl_ep_load(struct cxl_port *port,
+ struct cxl_memdev *cxlmd)
+{
+ if (!port)
+ return NULL;
+
+ return xa_load(&port->endpoints, (unsigned long)&cxlmd->dev);
+}
+
int cxl_memdev_init(void);
void cxl_memdev_exit(void);
void cxl_mbox_init(void);
-void cxl_mbox_exit(void);
#endif /* __CXL_CORE_H__ */
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
#include <linux/io-64-nonatomic-hi-lo.h>
+#include <linux/seq_file.h>
#include <linux/device.h>
#include <linux/delay.h>
* for enumerating these registers and capabilities.
*/
+DECLARE_RWSEM(cxl_dpa_rwsem);
+
static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
int *target_map)
{
*/
int devm_cxl_add_passthrough_decoder(struct cxl_port *port)
{
- struct cxl_decoder *cxld;
- struct cxl_dport *dport;
+ struct cxl_switch_decoder *cxlsd;
+ struct cxl_dport *dport = NULL;
int single_port_map[1];
+ unsigned long index;
- cxld = cxl_switch_decoder_alloc(port, 1);
- if (IS_ERR(cxld))
- return PTR_ERR(cxld);
+ cxlsd = cxl_switch_decoder_alloc(port, 1);
+ if (IS_ERR(cxlsd))
+ return PTR_ERR(cxlsd);
device_lock_assert(&port->dev);
- dport = list_first_entry(&port->dports, typeof(*dport), list);
+ xa_for_each(&port->dports, index, dport)
+ break;
single_port_map[0] = dport->port_id;
- return add_hdm_decoder(port, cxld, single_port_map);
+ return add_hdm_decoder(port, &cxlsd->cxld, single_port_map);
}
EXPORT_SYMBOL_NS_GPL(devm_cxl_add_passthrough_decoder, CXL);
return ERR_PTR(-ENXIO);
}
+ dev_set_drvdata(dev, cxlhdm);
+
return cxlhdm;
}
EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_hdm, CXL);
-static int to_interleave_granularity(u32 ctrl)
+static void __cxl_dpa_debug(struct seq_file *file, struct resource *r, int depth)
+{
+ unsigned long long start = r->start, end = r->end;
+
+ seq_printf(file, "%*s%08llx-%08llx : %s\n", depth * 2, "", start, end,
+ r->name);
+}
+
+void cxl_dpa_debug(struct seq_file *file, struct cxl_dev_state *cxlds)
+{
+ struct resource *p1, *p2;
+
+ down_read(&cxl_dpa_rwsem);
+ for (p1 = cxlds->dpa_res.child; p1; p1 = p1->sibling) {
+ __cxl_dpa_debug(file, p1, 0);
+ for (p2 = p1->child; p2; p2 = p2->sibling)
+ __cxl_dpa_debug(file, p2, 1);
+ }
+ up_read(&cxl_dpa_rwsem);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_dpa_debug, CXL);
+
+/*
+ * Must be called in a context that synchronizes against this decoder's
+ * port ->remove() callback (like an endpoint decoder sysfs attribute)
+ */
+static void __cxl_dpa_release(struct cxl_endpoint_decoder *cxled)
+{
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct cxl_port *port = cxled_to_port(cxled);
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct resource *res = cxled->dpa_res;
+ resource_size_t skip_start;
+
+ lockdep_assert_held_write(&cxl_dpa_rwsem);
+
+ /* save @skip_start, before @res is released */
+ skip_start = res->start - cxled->skip;
+ __release_region(&cxlds->dpa_res, res->start, resource_size(res));
+ if (cxled->skip)
+ __release_region(&cxlds->dpa_res, skip_start, cxled->skip);
+ cxled->skip = 0;
+ cxled->dpa_res = NULL;
+ put_device(&cxled->cxld.dev);
+ port->hdm_end--;
+}
+
+static void cxl_dpa_release(void *cxled)
+{
+ down_write(&cxl_dpa_rwsem);
+ __cxl_dpa_release(cxled);
+ up_write(&cxl_dpa_rwsem);
+}
+
+/*
+ * Must be called from context that will not race port device
+ * unregistration, like decoder sysfs attribute methods
+ */
+static void devm_cxl_dpa_release(struct cxl_endpoint_decoder *cxled)
+{
+ struct cxl_port *port = cxled_to_port(cxled);
+
+ lockdep_assert_held_write(&cxl_dpa_rwsem);
+ devm_remove_action(&port->dev, cxl_dpa_release, cxled);
+ __cxl_dpa_release(cxled);
+}
+
+static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
+ resource_size_t base, resource_size_t len,
+ resource_size_t skipped)
+{
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct cxl_port *port = cxled_to_port(cxled);
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct device *dev = &port->dev;
+ struct resource *res;
+
+ lockdep_assert_held_write(&cxl_dpa_rwsem);
+
+ if (!len)
+ goto success;
+
+ if (cxled->dpa_res) {
+ dev_dbg(dev, "decoder%d.%d: existing allocation %pr assigned\n",
+ port->id, cxled->cxld.id, cxled->dpa_res);
+ return -EBUSY;
+ }
+
+ if (port->hdm_end + 1 != cxled->cxld.id) {
+ /*
+ * Assumes alloc and commit order is always in hardware instance
+ * order per expectations from 8.2.5.12.20 Committing Decoder
+ * Programming that enforce decoder[m] committed before
+ * decoder[m+1] commit start.
+ */
+ dev_dbg(dev, "decoder%d.%d: expected decoder%d.%d\n", port->id,
+ cxled->cxld.id, port->id, port->hdm_end + 1);
+ return -EBUSY;
+ }
+
+ if (skipped) {
+ res = __request_region(&cxlds->dpa_res, base - skipped, skipped,
+ dev_name(&cxled->cxld.dev), 0);
+ if (!res) {
+ dev_dbg(dev,
+ "decoder%d.%d: failed to reserve skipped space\n",
+ port->id, cxled->cxld.id);
+ return -EBUSY;
+ }
+ }
+ res = __request_region(&cxlds->dpa_res, base, len,
+ dev_name(&cxled->cxld.dev), 0);
+ if (!res) {
+ dev_dbg(dev, "decoder%d.%d: failed to reserve allocation\n",
+ port->id, cxled->cxld.id);
+ if (skipped)
+ __release_region(&cxlds->dpa_res, base - skipped,
+ skipped);
+ return -EBUSY;
+ }
+ cxled->dpa_res = res;
+ cxled->skip = skipped;
+
+ if (resource_contains(&cxlds->pmem_res, res))
+ cxled->mode = CXL_DECODER_PMEM;
+ else if (resource_contains(&cxlds->ram_res, res))
+ cxled->mode = CXL_DECODER_RAM;
+ else {
+ dev_dbg(dev, "decoder%d.%d: %pr mixed\n", port->id,
+ cxled->cxld.id, cxled->dpa_res);
+ cxled->mode = CXL_DECODER_MIXED;
+ }
+
+success:
+ port->hdm_end++;
+ get_device(&cxled->cxld.dev);
+ return 0;
+}
+
+static int devm_cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
+ resource_size_t base, resource_size_t len,
+ resource_size_t skipped)
{
- int val = FIELD_GET(CXL_HDM_DECODER0_CTRL_IG_MASK, ctrl);
+ struct cxl_port *port = cxled_to_port(cxled);
+ int rc;
+
+ down_write(&cxl_dpa_rwsem);
+ rc = __cxl_dpa_reserve(cxled, base, len, skipped);
+ up_write(&cxl_dpa_rwsem);
+
+ if (rc)
+ return rc;
- return 256 << val;
+ return devm_add_action_or_reset(&port->dev, cxl_dpa_release, cxled);
}
-static int to_interleave_ways(u32 ctrl)
+resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled)
{
- int val = FIELD_GET(CXL_HDM_DECODER0_CTRL_IW_MASK, ctrl);
+ resource_size_t size = 0;
+
+ down_read(&cxl_dpa_rwsem);
+ if (cxled->dpa_res)
+ size = resource_size(cxled->dpa_res);
+ up_read(&cxl_dpa_rwsem);
- switch (val) {
- case 0 ... 4:
- return 1 << val;
- case 8 ... 10:
- return 3 << (val - 8);
+ return size;
+}
+
+resource_size_t cxl_dpa_resource_start(struct cxl_endpoint_decoder *cxled)
+{
+ resource_size_t base = -1;
+
+ down_read(&cxl_dpa_rwsem);
+ if (cxled->dpa_res)
+ base = cxled->dpa_res->start;
+ up_read(&cxl_dpa_rwsem);
+
+ return base;
+}
+
+int cxl_dpa_free(struct cxl_endpoint_decoder *cxled)
+{
+ struct cxl_port *port = cxled_to_port(cxled);
+ struct device *dev = &cxled->cxld.dev;
+ int rc;
+
+ down_write(&cxl_dpa_rwsem);
+ if (!cxled->dpa_res) {
+ rc = 0;
+ goto out;
+ }
+ if (cxled->cxld.region) {
+ dev_dbg(dev, "decoder assigned to: %s\n",
+ dev_name(&cxled->cxld.region->dev));
+ rc = -EBUSY;
+ goto out;
+ }
+ if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) {
+ dev_dbg(dev, "decoder enabled\n");
+ rc = -EBUSY;
+ goto out;
+ }
+ if (cxled->cxld.id != port->hdm_end) {
+ dev_dbg(dev, "expected decoder%d.%d\n", port->id,
+ port->hdm_end);
+ rc = -EBUSY;
+ goto out;
+ }
+ devm_cxl_dpa_release(cxled);
+ rc = 0;
+out:
+ up_write(&cxl_dpa_rwsem);
+ return rc;
+}
+
+int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled,
+ enum cxl_decoder_mode mode)
+{
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct device *dev = &cxled->cxld.dev;
+ int rc;
+
+ switch (mode) {
+ case CXL_DECODER_RAM:
+ case CXL_DECODER_PMEM:
+ break;
default:
+ dev_dbg(dev, "unsupported mode: %d\n", mode);
+ return -EINVAL;
+ }
+
+ down_write(&cxl_dpa_rwsem);
+ if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) {
+ rc = -EBUSY;
+ goto out;
+ }
+
+ /*
+ * Only allow modes that are supported by the current partition
+ * configuration
+ */
+ if (mode == CXL_DECODER_PMEM && !resource_size(&cxlds->pmem_res)) {
+ dev_dbg(dev, "no available pmem capacity\n");
+ rc = -ENXIO;
+ goto out;
+ }
+ if (mode == CXL_DECODER_RAM && !resource_size(&cxlds->ram_res)) {
+ dev_dbg(dev, "no available ram capacity\n");
+ rc = -ENXIO;
+ goto out;
+ }
+
+ cxled->mode = mode;
+ rc = 0;
+out:
+ up_write(&cxl_dpa_rwsem);
+
+ return rc;
+}
+
+int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, unsigned long long size)
+{
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ resource_size_t free_ram_start, free_pmem_start;
+ struct cxl_port *port = cxled_to_port(cxled);
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct device *dev = &cxled->cxld.dev;
+ resource_size_t start, avail, skip;
+ struct resource *p, *last;
+ int rc;
+
+ down_write(&cxl_dpa_rwsem);
+ if (cxled->cxld.region) {
+ dev_dbg(dev, "decoder attached to %s\n",
+ dev_name(&cxled->cxld.region->dev));
+ rc = -EBUSY;
+ goto out;
+ }
+
+ if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) {
+ dev_dbg(dev, "decoder enabled\n");
+ rc = -EBUSY;
+ goto out;
+ }
+
+ for (p = cxlds->ram_res.child, last = NULL; p; p = p->sibling)
+ last = p;
+ if (last)
+ free_ram_start = last->end + 1;
+ else
+ free_ram_start = cxlds->ram_res.start;
+
+ for (p = cxlds->pmem_res.child, last = NULL; p; p = p->sibling)
+ last = p;
+ if (last)
+ free_pmem_start = last->end + 1;
+ else
+ free_pmem_start = cxlds->pmem_res.start;
+
+ if (cxled->mode == CXL_DECODER_RAM) {
+ start = free_ram_start;
+ avail = cxlds->ram_res.end - start + 1;
+ skip = 0;
+ } else if (cxled->mode == CXL_DECODER_PMEM) {
+ resource_size_t skip_start, skip_end;
+
+ start = free_pmem_start;
+ avail = cxlds->pmem_res.end - start + 1;
+ skip_start = free_ram_start;
+
+ /*
+ * If some pmem is already allocated, then that allocation
+ * already handled the skip.
+ */
+ if (cxlds->pmem_res.child &&
+ skip_start == cxlds->pmem_res.child->start)
+ skip_end = skip_start - 1;
+ else
+ skip_end = start - 1;
+ skip = skip_end - skip_start + 1;
+ } else {
+ dev_dbg(dev, "mode not set\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (size > avail) {
+ dev_dbg(dev, "%pa exceeds available %s capacity: %pa\n", &size,
+ cxled->mode == CXL_DECODER_RAM ? "ram" : "pmem",
+ &avail);
+ rc = -ENOSPC;
+ goto out;
+ }
+
+ rc = __cxl_dpa_reserve(cxled, start, size, skip);
+out:
+ up_write(&cxl_dpa_rwsem);
+
+ if (rc)
+ return rc;
+
+ return devm_add_action_or_reset(&port->dev, cxl_dpa_release, cxled);
+}
+
+static void cxld_set_interleave(struct cxl_decoder *cxld, u32 *ctrl)
+{
+ u16 eig;
+ u8 eiw;
+
+ /*
+ * Input validation ensures these warns never fire, but otherwise
+ * suppress unititalized variable usage warnings.
+ */
+ if (WARN_ONCE(ways_to_cxl(cxld->interleave_ways, &eiw),
+ "invalid interleave_ways: %d\n", cxld->interleave_ways))
+ return;
+ if (WARN_ONCE(granularity_to_cxl(cxld->interleave_granularity, &eig),
+ "invalid interleave_granularity: %d\n",
+ cxld->interleave_granularity))
+ return;
+
+ u32p_replace_bits(ctrl, eig, CXL_HDM_DECODER0_CTRL_IG_MASK);
+ u32p_replace_bits(ctrl, eiw, CXL_HDM_DECODER0_CTRL_IW_MASK);
+ *ctrl |= CXL_HDM_DECODER0_CTRL_COMMIT;
+}
+
+static void cxld_set_type(struct cxl_decoder *cxld, u32 *ctrl)
+{
+ u32p_replace_bits(ctrl, !!(cxld->target_type == 3),
+ CXL_HDM_DECODER0_CTRL_TYPE);
+}
+
+static int cxlsd_set_targets(struct cxl_switch_decoder *cxlsd, u64 *tgt)
+{
+ struct cxl_dport **t = &cxlsd->target[0];
+ int ways = cxlsd->cxld.interleave_ways;
+
+ if (dev_WARN_ONCE(&cxlsd->cxld.dev,
+ ways > 8 || ways > cxlsd->nr_targets,
+ "ways: %d overflows targets: %d\n", ways,
+ cxlsd->nr_targets))
+ return -ENXIO;
+
+ *tgt = FIELD_PREP(GENMASK(7, 0), t[0]->port_id);
+ if (ways > 1)
+ *tgt |= FIELD_PREP(GENMASK(15, 8), t[1]->port_id);
+ if (ways > 2)
+ *tgt |= FIELD_PREP(GENMASK(23, 16), t[2]->port_id);
+ if (ways > 3)
+ *tgt |= FIELD_PREP(GENMASK(31, 24), t[3]->port_id);
+ if (ways > 4)
+ *tgt |= FIELD_PREP(GENMASK_ULL(39, 32), t[4]->port_id);
+ if (ways > 5)
+ *tgt |= FIELD_PREP(GENMASK_ULL(47, 40), t[5]->port_id);
+ if (ways > 6)
+ *tgt |= FIELD_PREP(GENMASK_ULL(55, 48), t[6]->port_id);
+ if (ways > 7)
+ *tgt |= FIELD_PREP(GENMASK_ULL(63, 56), t[7]->port_id);
+
+ return 0;
+}
+
+/*
+ * Per CXL 2.0 8.2.5.12.20 Committing Decoder Programming, hardware must set
+ * committed or error within 10ms, but just be generous with 20ms to account for
+ * clock skew and other marginal behavior
+ */
+#define COMMIT_TIMEOUT_MS 20
+static int cxld_await_commit(void __iomem *hdm, int id)
+{
+ u32 ctrl;
+ int i;
+
+ for (i = 0; i < COMMIT_TIMEOUT_MS; i++) {
+ ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
+ if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMIT_ERROR, ctrl)) {
+ ctrl &= ~CXL_HDM_DECODER0_CTRL_COMMIT;
+ writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
+ return -EIO;
+ }
+ if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl))
+ return 0;
+ fsleep(1000);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int cxl_decoder_commit(struct cxl_decoder *cxld)
+{
+ struct cxl_port *port = to_cxl_port(cxld->dev.parent);
+ struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);
+ void __iomem *hdm = cxlhdm->regs.hdm_decoder;
+ int id = cxld->id, rc;
+ u64 base, size;
+ u32 ctrl;
+
+ if (cxld->flags & CXL_DECODER_F_ENABLE)
+ return 0;
+
+ if (port->commit_end + 1 != id) {
+ dev_dbg(&port->dev,
+ "%s: out of order commit, expected decoder%d.%d\n",
+ dev_name(&cxld->dev), port->id, port->commit_end + 1);
+ return -EBUSY;
+ }
+
+ down_read(&cxl_dpa_rwsem);
+ /* common decoder settings */
+ ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(cxld->id));
+ cxld_set_interleave(cxld, &ctrl);
+ cxld_set_type(cxld, &ctrl);
+ base = cxld->hpa_range.start;
+ size = range_len(&cxld->hpa_range);
+
+ writel(upper_32_bits(base), hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(id));
+ writel(lower_32_bits(base), hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(id));
+ writel(upper_32_bits(size), hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(id));
+ writel(lower_32_bits(size), hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(id));
+
+ if (is_switch_decoder(&cxld->dev)) {
+ struct cxl_switch_decoder *cxlsd =
+ to_cxl_switch_decoder(&cxld->dev);
+ void __iomem *tl_hi = hdm + CXL_HDM_DECODER0_TL_HIGH(id);
+ void __iomem *tl_lo = hdm + CXL_HDM_DECODER0_TL_LOW(id);
+ u64 targets;
+
+ rc = cxlsd_set_targets(cxlsd, &targets);
+ if (rc) {
+ dev_dbg(&port->dev, "%s: target configuration error\n",
+ dev_name(&cxld->dev));
+ goto err;
+ }
+
+ writel(upper_32_bits(targets), tl_hi);
+ writel(lower_32_bits(targets), tl_lo);
+ } else {
+ struct cxl_endpoint_decoder *cxled =
+ to_cxl_endpoint_decoder(&cxld->dev);
+ void __iomem *sk_hi = hdm + CXL_HDM_DECODER0_SKIP_HIGH(id);
+ void __iomem *sk_lo = hdm + CXL_HDM_DECODER0_SKIP_LOW(id);
+
+ writel(upper_32_bits(cxled->skip), sk_hi);
+ writel(lower_32_bits(cxled->skip), sk_lo);
+ }
+
+ writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
+ up_read(&cxl_dpa_rwsem);
+
+ port->commit_end++;
+ rc = cxld_await_commit(hdm, cxld->id);
+err:
+ if (rc) {
+ dev_dbg(&port->dev, "%s: error %d committing decoder\n",
+ dev_name(&cxld->dev), rc);
+ cxld->reset(cxld);
+ return rc;
+ }
+ cxld->flags |= CXL_DECODER_F_ENABLE;
+
+ return 0;
+}
+
+static int cxl_decoder_reset(struct cxl_decoder *cxld)
+{
+ struct cxl_port *port = to_cxl_port(cxld->dev.parent);
+ struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);
+ void __iomem *hdm = cxlhdm->regs.hdm_decoder;
+ int id = cxld->id;
+ u32 ctrl;
+
+ if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)
return 0;
+
+ if (port->commit_end != id) {
+ dev_dbg(&port->dev,
+ "%s: out of order reset, expected decoder%d.%d\n",
+ dev_name(&cxld->dev), port->id, port->commit_end);
+ return -EBUSY;
}
+
+ down_read(&cxl_dpa_rwsem);
+ ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
+ ctrl &= ~CXL_HDM_DECODER0_CTRL_COMMIT;
+ writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
+
+ writel(0, hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(id));
+ writel(0, hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(id));
+ writel(0, hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(id));
+ writel(0, hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(id));
+ up_read(&cxl_dpa_rwsem);
+
+ port->commit_end--;
+ cxld->flags &= ~CXL_DECODER_F_ENABLE;
+
+ return 0;
}
static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
- int *target_map, void __iomem *hdm, int which)
+ int *target_map, void __iomem *hdm, int which,
+ u64 *dpa_base)
{
- u64 size, base;
+ struct cxl_endpoint_decoder *cxled = NULL;
+ u64 size, base, skip, dpa_size;
+ bool committed;
+ u32 remainder;
+ int i, rc;
u32 ctrl;
- int i;
union {
u64 value;
unsigned char target_id[8];
} target_list;
+ if (is_endpoint_decoder(&cxld->dev))
+ cxled = to_cxl_endpoint_decoder(&cxld->dev);
+
ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(which));
base = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(which));
size = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(which));
+ committed = !!(ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED);
+ cxld->commit = cxl_decoder_commit;
+ cxld->reset = cxl_decoder_reset;
- if (!(ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED))
+ if (!committed)
size = 0;
if (base == U64_MAX || size == U64_MAX) {
dev_warn(&port->dev, "decoder%d.%d: Invalid resource range\n",
return -ENXIO;
}
- cxld->decoder_range = (struct range) {
+ cxld->hpa_range = (struct range) {
.start = base,
.end = base + size - 1,
};
- /* switch decoders are always enabled if committed */
- if (ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED) {
+ /* decoders are enabled if committed */
+ if (committed) {
cxld->flags |= CXL_DECODER_F_ENABLE;
if (ctrl & CXL_HDM_DECODER0_CTRL_LOCK)
cxld->flags |= CXL_DECODER_F_LOCK;
+ if (FIELD_GET(CXL_HDM_DECODER0_CTRL_TYPE, ctrl))
+ cxld->target_type = CXL_DECODER_EXPANDER;
+ else
+ cxld->target_type = CXL_DECODER_ACCELERATOR;
+ if (cxld->id != port->commit_end + 1) {
+ dev_warn(&port->dev,
+ "decoder%d.%d: Committed out of order\n",
+ port->id, cxld->id);
+ return -ENXIO;
+ }
+ port->commit_end = cxld->id;
+ } else {
+ /* unless / until type-2 drivers arrive, assume type-3 */
+ if (FIELD_GET(CXL_HDM_DECODER0_CTRL_TYPE, ctrl) == 0) {
+ ctrl |= CXL_HDM_DECODER0_CTRL_TYPE;
+ writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(which));
+ }
+ cxld->target_type = CXL_DECODER_EXPANDER;
}
- cxld->interleave_ways = to_interleave_ways(ctrl);
- if (!cxld->interleave_ways) {
+ rc = cxl_to_ways(FIELD_GET(CXL_HDM_DECODER0_CTRL_IW_MASK, ctrl),
+ &cxld->interleave_ways);
+ if (rc) {
dev_warn(&port->dev,
"decoder%d.%d: Invalid interleave ways (ctrl: %#x)\n",
port->id, cxld->id, ctrl);
- return -ENXIO;
+ return rc;
}
- cxld->interleave_granularity = to_interleave_granularity(ctrl);
+ rc = cxl_to_granularity(FIELD_GET(CXL_HDM_DECODER0_CTRL_IG_MASK, ctrl),
+ &cxld->interleave_granularity);
+ if (rc)
+ return rc;
- if (FIELD_GET(CXL_HDM_DECODER0_CTRL_TYPE, ctrl))
- cxld->target_type = CXL_DECODER_EXPANDER;
- else
- cxld->target_type = CXL_DECODER_ACCELERATOR;
+ if (!cxled) {
+ target_list.value =
+ ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which));
+ for (i = 0; i < cxld->interleave_ways; i++)
+ target_map[i] = target_list.target_id[i];
- if (is_endpoint_decoder(&cxld->dev))
return 0;
+ }
- target_list.value =
- ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which));
- for (i = 0; i < cxld->interleave_ways; i++)
- target_map[i] = target_list.target_id[i];
+ if (!committed)
+ return 0;
+ dpa_size = div_u64_rem(size, cxld->interleave_ways, &remainder);
+ if (remainder) {
+ dev_err(&port->dev,
+ "decoder%d.%d: invalid committed configuration size: %#llx ways: %d\n",
+ port->id, cxld->id, size, cxld->interleave_ways);
+ return -ENXIO;
+ }
+ skip = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SKIP_LOW(which));
+ rc = devm_cxl_dpa_reserve(cxled, *dpa_base + skip, dpa_size, skip);
+ if (rc) {
+ dev_err(&port->dev,
+ "decoder%d.%d: Failed to reserve DPA range %#llx - %#llx\n (%d)",
+ port->id, cxld->id, *dpa_base,
+ *dpa_base + dpa_size + skip - 1, rc);
+ return rc;
+ }
+ *dpa_base += dpa_size + skip;
return 0;
}
{
void __iomem *hdm = cxlhdm->regs.hdm_decoder;
struct cxl_port *port = cxlhdm->port;
- int i, committed, failed;
+ int i, committed;
+ u64 dpa_base = 0;
u32 ctrl;
/*
if (committed != cxlhdm->decoder_count)
msleep(20);
- for (i = 0, failed = 0; i < cxlhdm->decoder_count; i++) {
+ for (i = 0; i < cxlhdm->decoder_count; i++) {
int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 };
int rc, target_count = cxlhdm->target_count;
struct cxl_decoder *cxld;
- if (is_cxl_endpoint(port))
- cxld = cxl_endpoint_decoder_alloc(port);
- else
- cxld = cxl_switch_decoder_alloc(port, target_count);
- if (IS_ERR(cxld)) {
- dev_warn(&port->dev,
- "Failed to allocate the decoder\n");
- return PTR_ERR(cxld);
+ if (is_cxl_endpoint(port)) {
+ struct cxl_endpoint_decoder *cxled;
+
+ cxled = cxl_endpoint_decoder_alloc(port);
+ if (IS_ERR(cxled)) {
+ dev_warn(&port->dev,
+ "Failed to allocate the decoder\n");
+ return PTR_ERR(cxled);
+ }
+ cxld = &cxled->cxld;
+ } else {
+ struct cxl_switch_decoder *cxlsd;
+
+ cxlsd = cxl_switch_decoder_alloc(port, target_count);
+ if (IS_ERR(cxlsd)) {
+ dev_warn(&port->dev,
+ "Failed to allocate the decoder\n");
+ return PTR_ERR(cxlsd);
+ }
+ cxld = &cxlsd->cxld;
}
- rc = init_hdm_decoder(port, cxld, target_map,
- cxlhdm->regs.hdm_decoder, i);
+ rc = init_hdm_decoder(port, cxld, target_map, hdm, i, &dpa_base);
if (rc) {
put_device(&cxld->dev);
- failed++;
- continue;
+ return rc;
}
rc = add_hdm_decoder(port, cxld, target_map);
if (rc) {
}
}
- if (failed == cxlhdm->decoder_count) {
- dev_err(&port->dev, "No valid decoders found\n");
- return -ENXIO;
- }
-
return 0;
}
EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_decoders, CXL);
*/
static int cxl_mem_get_partition_info(struct cxl_dev_state *cxlds)
{
- struct cxl_mbox_get_partition_info {
- __le64 active_volatile_cap;
- __le64 active_persistent_cap;
- __le64 next_volatile_cap;
- __le64 next_persistent_cap;
- } __packed pi;
+ struct cxl_mbox_get_partition_info pi;
int rc;
rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_PARTITION_INFO, NULL, 0,
cxlds->partition_align_bytes =
le64_to_cpu(id.partition_align) * CXL_CAPACITY_MULTIPLIER;
- dev_dbg(cxlds->dev,
- "Identify Memory Device\n"
- " total_bytes = %#llx\n"
- " volatile_only_bytes = %#llx\n"
- " persistent_only_bytes = %#llx\n"
- " partition_align_bytes = %#llx\n",
- cxlds->total_bytes, cxlds->volatile_only_bytes,
- cxlds->persistent_only_bytes, cxlds->partition_align_bytes);
-
cxlds->lsa_size = le32_to_cpu(id.lsa_size);
memcpy(cxlds->firmware_version, id.fw_revision, sizeof(id.fw_revision));
}
EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL);
-int cxl_mem_create_range_info(struct cxl_dev_state *cxlds)
+static int add_dpa_res(struct device *dev, struct resource *parent,
+ struct resource *res, resource_size_t start,
+ resource_size_t size, const char *type)
{
int rc;
- if (cxlds->partition_align_bytes == 0) {
- cxlds->ram_range.start = 0;
- cxlds->ram_range.end = cxlds->volatile_only_bytes - 1;
- cxlds->pmem_range.start = cxlds->volatile_only_bytes;
- cxlds->pmem_range.end = cxlds->volatile_only_bytes +
- cxlds->persistent_only_bytes - 1;
+ res->name = type;
+ res->start = start;
+ res->end = start + size - 1;
+ res->flags = IORESOURCE_MEM;
+ if (resource_size(res) == 0) {
+ dev_dbg(dev, "DPA(%s): no capacity\n", res->name);
return 0;
}
-
- rc = cxl_mem_get_partition_info(cxlds);
+ rc = request_resource(parent, res);
if (rc) {
- dev_err(cxlds->dev, "Failed to query partition information\n");
+ dev_err(dev, "DPA(%s): failed to track %pr (%d)\n", res->name,
+ res, rc);
return rc;
}
- dev_dbg(cxlds->dev,
- "Get Partition Info\n"
- " active_volatile_bytes = %#llx\n"
- " active_persistent_bytes = %#llx\n"
- " next_volatile_bytes = %#llx\n"
- " next_persistent_bytes = %#llx\n",
- cxlds->active_volatile_bytes, cxlds->active_persistent_bytes,
- cxlds->next_volatile_bytes, cxlds->next_persistent_bytes);
+ dev_dbg(dev, "DPA(%s): %pr\n", res->name, res);
+
+ return 0;
+}
- cxlds->ram_range.start = 0;
- cxlds->ram_range.end = cxlds->active_volatile_bytes - 1;
+int cxl_mem_create_range_info(struct cxl_dev_state *cxlds)
+{
+ struct device *dev = cxlds->dev;
+ int rc;
- cxlds->pmem_range.start = cxlds->active_volatile_bytes;
- cxlds->pmem_range.end =
- cxlds->active_volatile_bytes + cxlds->active_persistent_bytes - 1;
+ cxlds->dpa_res =
+ (struct resource)DEFINE_RES_MEM(0, cxlds->total_bytes);
- return 0;
+ if (cxlds->partition_align_bytes == 0) {
+ rc = add_dpa_res(dev, &cxlds->dpa_res, &cxlds->ram_res, 0,
+ cxlds->volatile_only_bytes, "ram");
+ if (rc)
+ return rc;
+ return add_dpa_res(dev, &cxlds->dpa_res, &cxlds->pmem_res,
+ cxlds->volatile_only_bytes,
+ cxlds->persistent_only_bytes, "pmem");
+ }
+
+ rc = cxl_mem_get_partition_info(cxlds);
+ if (rc) {
+ dev_err(dev, "Failed to query partition information\n");
+ return rc;
+ }
+
+ rc = add_dpa_res(dev, &cxlds->dpa_res, &cxlds->ram_res, 0,
+ cxlds->active_volatile_bytes, "ram");
+ if (rc)
+ return rc;
+ return add_dpa_res(dev, &cxlds->dpa_res, &cxlds->pmem_res,
+ cxlds->active_volatile_bytes,
+ cxlds->active_persistent_bytes, "pmem");
}
EXPORT_SYMBOL_NS_GPL(cxl_mem_create_range_info, CXL);
}
EXPORT_SYMBOL_NS_GPL(cxl_dev_state_create, CXL);
-static struct dentry *cxl_debugfs;
-
void __init cxl_mbox_init(void)
{
struct dentry *mbox_debugfs;
- cxl_debugfs = debugfs_create_dir("cxl", NULL);
- mbox_debugfs = debugfs_create_dir("mbox", cxl_debugfs);
+ mbox_debugfs = cxl_debugfs_create_dir("mbox");
debugfs_create_bool("raw_allow_all", 0600, mbox_debugfs,
&cxl_raw_allow_all);
}
-
-void cxl_mbox_exit(void)
-{
- debugfs_remove_recursive(cxl_debugfs);
-}
{
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
struct cxl_dev_state *cxlds = cxlmd->cxlds;
- unsigned long long len = range_len(&cxlds->ram_range);
+ unsigned long long len = resource_size(&cxlds->ram_res);
return sysfs_emit(buf, "%#llx\n", len);
}
{
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
struct cxl_dev_state *cxlds = cxlmd->cxlds;
- unsigned long long len = range_len(&cxlds->pmem_range);
+ unsigned long long len = resource_size(&cxlds->pmem_res);
return sysfs_emit(buf, "%#llx\n", len);
}
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/pci.h>
+#include <linux/pci-doe.h>
#include <cxlpci.h>
#include <cxlmem.h>
#include <cxl.h>
{
struct range *dev_range = arg;
struct cxl_decoder *cxld;
- struct range root_range;
if (!is_root_decoder(dev))
return 0;
if (!(cxld->flags & CXL_DECODER_F_RAM))
return 0;
- root_range = (struct range) {
- .start = cxld->platform_res.start,
- .end = cxld->platform_res.end,
- };
-
- return range_contains(&root_range, dev_range);
+ return range_contains(&cxld->hpa_range, dev_range);
}
static void disable_hdm(void *_cxlhdm)
return 0;
}
EXPORT_SYMBOL_NS_GPL(cxl_hdm_decode_init, CXL);
+
+#define CXL_DOE_TABLE_ACCESS_REQ_CODE 0x000000ff
+#define CXL_DOE_TABLE_ACCESS_REQ_CODE_READ 0
+#define CXL_DOE_TABLE_ACCESS_TABLE_TYPE 0x0000ff00
+#define CXL_DOE_TABLE_ACCESS_TABLE_TYPE_CDATA 0
+#define CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE 0xffff0000
+#define CXL_DOE_TABLE_ACCESS_LAST_ENTRY 0xffff
+#define CXL_DOE_PROTOCOL_TABLE_ACCESS 2
+
+static struct pci_doe_mb *find_cdat_doe(struct device *uport)
+{
+ struct cxl_memdev *cxlmd;
+ struct cxl_dev_state *cxlds;
+ unsigned long index;
+ void *entry;
+
+ cxlmd = to_cxl_memdev(uport);
+ cxlds = cxlmd->cxlds;
+
+ xa_for_each(&cxlds->doe_mbs, index, entry) {
+ struct pci_doe_mb *cur = entry;
+
+ if (pci_doe_supports_prot(cur, PCI_DVSEC_VENDOR_ID_CXL,
+ CXL_DOE_PROTOCOL_TABLE_ACCESS))
+ return cur;
+ }
+
+ return NULL;
+}
+
+#define CDAT_DOE_REQ(entry_handle) \
+ (FIELD_PREP(CXL_DOE_TABLE_ACCESS_REQ_CODE, \
+ CXL_DOE_TABLE_ACCESS_REQ_CODE_READ) | \
+ FIELD_PREP(CXL_DOE_TABLE_ACCESS_TABLE_TYPE, \
+ CXL_DOE_TABLE_ACCESS_TABLE_TYPE_CDATA) | \
+ FIELD_PREP(CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE, (entry_handle)))
+
+static void cxl_doe_task_complete(struct pci_doe_task *task)
+{
+ complete(task->private);
+}
+
+struct cdat_doe_task {
+ u32 request_pl;
+ u32 response_pl[32];
+ struct completion c;
+ struct pci_doe_task task;
+};
+
+#define DECLARE_CDAT_DOE_TASK(req, cdt) \
+struct cdat_doe_task cdt = { \
+ .c = COMPLETION_INITIALIZER_ONSTACK(cdt.c), \
+ .request_pl = req, \
+ .task = { \
+ .prot.vid = PCI_DVSEC_VENDOR_ID_CXL, \
+ .prot.type = CXL_DOE_PROTOCOL_TABLE_ACCESS, \
+ .request_pl = &cdt.request_pl, \
+ .request_pl_sz = sizeof(cdt.request_pl), \
+ .response_pl = cdt.response_pl, \
+ .response_pl_sz = sizeof(cdt.response_pl), \
+ .complete = cxl_doe_task_complete, \
+ .private = &cdt.c, \
+ } \
+}
+
+static int cxl_cdat_get_length(struct device *dev,
+ struct pci_doe_mb *cdat_doe,
+ size_t *length)
+{
+ DECLARE_CDAT_DOE_TASK(CDAT_DOE_REQ(0), t);
+ int rc;
+
+ rc = pci_doe_submit_task(cdat_doe, &t.task);
+ if (rc < 0) {
+ dev_err(dev, "DOE submit failed: %d", rc);
+ return rc;
+ }
+ wait_for_completion(&t.c);
+ if (t.task.rv < sizeof(u32))
+ return -EIO;
+
+ *length = t.response_pl[1];
+ dev_dbg(dev, "CDAT length %zu\n", *length);
+
+ return 0;
+}
+
+static int cxl_cdat_read_table(struct device *dev,
+ struct pci_doe_mb *cdat_doe,
+ struct cxl_cdat *cdat)
+{
+ size_t length = cdat->length;
+ u32 *data = cdat->table;
+ int entry_handle = 0;
+
+ do {
+ DECLARE_CDAT_DOE_TASK(CDAT_DOE_REQ(entry_handle), t);
+ size_t entry_dw;
+ u32 *entry;
+ int rc;
+
+ rc = pci_doe_submit_task(cdat_doe, &t.task);
+ if (rc < 0) {
+ dev_err(dev, "DOE submit failed: %d", rc);
+ return rc;
+ }
+ wait_for_completion(&t.c);
+ /* 1 DW header + 1 DW data min */
+ if (t.task.rv < (2 * sizeof(u32)))
+ return -EIO;
+
+ /* Get the CXL table access header entry handle */
+ entry_handle = FIELD_GET(CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE,
+ t.response_pl[0]);
+ entry = t.response_pl + 1;
+ entry_dw = t.task.rv / sizeof(u32);
+ /* Skip Header */
+ entry_dw -= 1;
+ entry_dw = min(length / sizeof(u32), entry_dw);
+ /* Prevent length < 1 DW from causing a buffer overflow */
+ if (entry_dw) {
+ memcpy(data, entry, entry_dw * sizeof(u32));
+ length -= entry_dw * sizeof(u32);
+ data += entry_dw;
+ }
+ } while (entry_handle != CXL_DOE_TABLE_ACCESS_LAST_ENTRY);
+
+ return 0;
+}
+
+/**
+ * read_cdat_data - Read the CDAT data on this port
+ * @port: Port to read data from
+ *
+ * This call will sleep waiting for responses from the DOE mailbox.
+ */
+void read_cdat_data(struct cxl_port *port)
+{
+ struct pci_doe_mb *cdat_doe;
+ struct device *dev = &port->dev;
+ struct device *uport = port->uport;
+ size_t cdat_length;
+ int rc;
+
+ cdat_doe = find_cdat_doe(uport);
+ if (!cdat_doe) {
+ dev_dbg(dev, "No CDAT mailbox\n");
+ return;
+ }
+
+ port->cdat_available = true;
+
+ if (cxl_cdat_get_length(dev, cdat_doe, &cdat_length)) {
+ dev_dbg(dev, "No CDAT length\n");
+ return;
+ }
+
+ port->cdat.table = devm_kzalloc(dev, cdat_length, GFP_KERNEL);
+ if (!port->cdat.table)
+ return;
+
+ port->cdat.length = cdat_length;
+ rc = cxl_cdat_read_table(dev, cdat_doe, &port->cdat);
+ if (rc) {
+ /* Don't leave table data allocated on error */
+ devm_kfree(dev, port->cdat.table);
+ port->cdat.table = NULL;
+ port->cdat.length = 0;
+ dev_err(dev, "CDAT data read error\n");
+ }
+}
+EXPORT_SYMBOL_NS_GPL(read_cdat_data, CXL);
return is_cxl_nvdimm_bridge(dev);
}
-struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd)
+struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *start)
{
- struct cxl_port *port = find_cxl_root(&cxl_nvd->dev);
+ struct cxl_port *port = find_cxl_root(start);
struct device *dev;
if (!port)
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright(c) 2020 Intel Corporation. All rights reserved. */
#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/memregion.h>
#include <linux/workqueue.h>
+#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
return CXL_DEVICE_NVDIMM_BRIDGE;
if (dev->type == &cxl_nvdimm_type)
return CXL_DEVICE_NVDIMM;
+ if (dev->type == CXL_PMEM_REGION_TYPE())
+ return CXL_DEVICE_PMEM_REGION;
if (is_cxl_port(dev)) {
if (is_cxl_root(to_cxl_port(dev)))
return CXL_DEVICE_ROOT;
}
if (is_cxl_memdev(dev))
return CXL_DEVICE_MEMORY_EXPANDER;
+ if (dev->type == CXL_REGION_TYPE())
+ return CXL_DEVICE_REGION;
return 0;
}
char *buf)
{
struct cxl_decoder *cxld = to_cxl_decoder(dev);
- u64 start;
- if (is_root_decoder(dev))
- start = cxld->platform_res.start;
- else
- start = cxld->decoder_range.start;
-
- return sysfs_emit(buf, "%#llx\n", start);
+ return sysfs_emit(buf, "%#llx\n", cxld->hpa_range.start);
}
static DEVICE_ATTR_ADMIN_RO(start);
char *buf)
{
struct cxl_decoder *cxld = to_cxl_decoder(dev);
- u64 size;
-
- if (is_root_decoder(dev))
- size = resource_size(&cxld->platform_res);
- else
- size = range_len(&cxld->decoder_range);
- return sysfs_emit(buf, "%#llx\n", size);
+ return sysfs_emit(buf, "%#llx\n", range_len(&cxld->hpa_range));
}
static DEVICE_ATTR_RO(size);
}
static DEVICE_ATTR_RO(target_type);
-static ssize_t emit_target_list(struct cxl_decoder *cxld, char *buf)
+static ssize_t emit_target_list(struct cxl_switch_decoder *cxlsd, char *buf)
{
+ struct cxl_decoder *cxld = &cxlsd->cxld;
ssize_t offset = 0;
int i, rc = 0;
for (i = 0; i < cxld->interleave_ways; i++) {
- struct cxl_dport *dport = cxld->target[i];
+ struct cxl_dport *dport = cxlsd->target[i];
struct cxl_dport *next = NULL;
if (!dport)
break;
if (i + 1 < cxld->interleave_ways)
- next = cxld->target[i + 1];
+ next = cxlsd->target[i + 1];
rc = sysfs_emit_at(buf, offset, "%d%s", dport->port_id,
next ? "," : "");
if (rc < 0)
static ssize_t target_list_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct cxl_decoder *cxld = to_cxl_decoder(dev);
+ struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(dev);
ssize_t offset;
unsigned int seq;
int rc;
do {
- seq = read_seqbegin(&cxld->target_lock);
- rc = emit_target_list(cxld, buf);
- } while (read_seqretry(&cxld->target_lock, seq));
+ seq = read_seqbegin(&cxlsd->target_lock);
+ rc = emit_target_list(cxlsd, buf);
+ } while (read_seqretry(&cxlsd->target_lock, seq));
if (rc < 0)
return rc;
}
static DEVICE_ATTR_RO(target_list);
+static ssize_t mode_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+
+ switch (cxled->mode) {
+ case CXL_DECODER_RAM:
+ return sysfs_emit(buf, "ram\n");
+ case CXL_DECODER_PMEM:
+ return sysfs_emit(buf, "pmem\n");
+ case CXL_DECODER_NONE:
+ return sysfs_emit(buf, "none\n");
+ case CXL_DECODER_MIXED:
+ default:
+ return sysfs_emit(buf, "mixed\n");
+ }
+}
+
+static ssize_t mode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+ enum cxl_decoder_mode mode;
+ ssize_t rc;
+
+ if (sysfs_streq(buf, "pmem"))
+ mode = CXL_DECODER_PMEM;
+ else if (sysfs_streq(buf, "ram"))
+ mode = CXL_DECODER_RAM;
+ else
+ return -EINVAL;
+
+ rc = cxl_dpa_set_mode(cxled, mode);
+ if (rc)
+ return rc;
+
+ return len;
+}
+static DEVICE_ATTR_RW(mode);
+
+static ssize_t dpa_resource_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+ u64 base = cxl_dpa_resource_start(cxled);
+
+ return sysfs_emit(buf, "%#llx\n", base);
+}
+static DEVICE_ATTR_RO(dpa_resource);
+
+static ssize_t dpa_size_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+ resource_size_t size = cxl_dpa_size(cxled);
+
+ return sysfs_emit(buf, "%pa\n", &size);
+}
+
+static ssize_t dpa_size_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+ unsigned long long size;
+ ssize_t rc;
+
+ rc = kstrtoull(buf, 0, &size);
+ if (rc)
+ return rc;
+
+ if (!IS_ALIGNED(size, SZ_256M))
+ return -EINVAL;
+
+ rc = cxl_dpa_free(cxled);
+ if (rc)
+ return rc;
+
+ if (size == 0)
+ return len;
+
+ rc = cxl_dpa_alloc(cxled, size);
+ if (rc)
+ return rc;
+
+ return len;
+}
+static DEVICE_ATTR_RW(dpa_size);
+
+static ssize_t interleave_granularity_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_decoder *cxld = to_cxl_decoder(dev);
+
+ return sysfs_emit(buf, "%d\n", cxld->interleave_granularity);
+}
+
+static DEVICE_ATTR_RO(interleave_granularity);
+
+static ssize_t interleave_ways_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cxl_decoder *cxld = to_cxl_decoder(dev);
+
+ return sysfs_emit(buf, "%d\n", cxld->interleave_ways);
+}
+
+static DEVICE_ATTR_RO(interleave_ways);
+
static struct attribute *cxl_decoder_base_attrs[] = {
&dev_attr_start.attr,
&dev_attr_size.attr,
&dev_attr_locked.attr,
+ &dev_attr_interleave_granularity.attr,
+ &dev_attr_interleave_ways.attr,
NULL,
};
&dev_attr_cap_type2.attr,
&dev_attr_cap_type3.attr,
&dev_attr_target_list.attr,
+ SET_CXL_REGION_ATTR(create_pmem_region)
+ SET_CXL_REGION_ATTR(delete_region)
NULL,
};
+static bool can_create_pmem(struct cxl_root_decoder *cxlrd)
+{
+ unsigned long flags = CXL_DECODER_F_TYPE3 | CXL_DECODER_F_PMEM;
+
+ return (cxlrd->cxlsd.cxld.flags & flags) == flags;
+}
+
+static umode_t cxl_root_decoder_visible(struct kobject *kobj, struct attribute *a, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+
+ if (a == CXL_REGION_ATTR(create_pmem_region) && !can_create_pmem(cxlrd))
+ return 0;
+
+ if (a == CXL_REGION_ATTR(delete_region) && !can_create_pmem(cxlrd))
+ return 0;
+
+ return a->mode;
+}
+
static struct attribute_group cxl_decoder_root_attribute_group = {
.attrs = cxl_decoder_root_attrs,
+ .is_visible = cxl_root_decoder_visible,
};
static const struct attribute_group *cxl_decoder_root_attribute_groups[] = {
static struct attribute *cxl_decoder_switch_attrs[] = {
&dev_attr_target_type.attr,
&dev_attr_target_list.attr,
+ SET_CXL_REGION_ATTR(region)
NULL,
};
static struct attribute *cxl_decoder_endpoint_attrs[] = {
&dev_attr_target_type.attr,
+ &dev_attr_mode.attr,
+ &dev_attr_dpa_size.attr,
+ &dev_attr_dpa_resource.attr,
+ SET_CXL_REGION_ATTR(region)
NULL,
};
NULL,
};
-static void cxl_decoder_release(struct device *dev)
+static void __cxl_decoder_release(struct cxl_decoder *cxld)
{
- struct cxl_decoder *cxld = to_cxl_decoder(dev);
- struct cxl_port *port = to_cxl_port(dev->parent);
+ struct cxl_port *port = to_cxl_port(cxld->dev.parent);
ida_free(&port->decoder_ida, cxld->id);
- kfree(cxld);
put_device(&port->dev);
}
+static void cxl_endpoint_decoder_release(struct device *dev)
+{
+ struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+
+ __cxl_decoder_release(&cxled->cxld);
+ kfree(cxled);
+}
+
+static void cxl_switch_decoder_release(struct device *dev)
+{
+ struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(dev);
+
+ __cxl_decoder_release(&cxlsd->cxld);
+ kfree(cxlsd);
+}
+
+struct cxl_root_decoder *to_cxl_root_decoder(struct device *dev)
+{
+ if (dev_WARN_ONCE(dev, !is_root_decoder(dev),
+ "not a cxl_root_decoder device\n"))
+ return NULL;
+ return container_of(dev, struct cxl_root_decoder, cxlsd.cxld.dev);
+}
+EXPORT_SYMBOL_NS_GPL(to_cxl_root_decoder, CXL);
+
+static void cxl_root_decoder_release(struct device *dev)
+{
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+
+ if (atomic_read(&cxlrd->region_id) >= 0)
+ memregion_free(atomic_read(&cxlrd->region_id));
+ __cxl_decoder_release(&cxlrd->cxlsd.cxld);
+ kfree(cxlrd);
+}
+
static const struct device_type cxl_decoder_endpoint_type = {
.name = "cxl_decoder_endpoint",
- .release = cxl_decoder_release,
+ .release = cxl_endpoint_decoder_release,
.groups = cxl_decoder_endpoint_attribute_groups,
};
static const struct device_type cxl_decoder_switch_type = {
.name = "cxl_decoder_switch",
- .release = cxl_decoder_release,
+ .release = cxl_switch_decoder_release,
.groups = cxl_decoder_switch_attribute_groups,
};
static const struct device_type cxl_decoder_root_type = {
.name = "cxl_decoder_root",
- .release = cxl_decoder_release,
+ .release = cxl_root_decoder_release,
.groups = cxl_decoder_root_attribute_groups,
};
}
EXPORT_SYMBOL_NS_GPL(is_root_decoder, CXL);
-bool is_cxl_decoder(struct device *dev)
+bool is_switch_decoder(struct device *dev)
{
- return dev->type && dev->type->release == cxl_decoder_release;
+ return is_root_decoder(dev) || dev->type == &cxl_decoder_switch_type;
}
-EXPORT_SYMBOL_NS_GPL(is_cxl_decoder, CXL);
struct cxl_decoder *to_cxl_decoder(struct device *dev)
{
- if (dev_WARN_ONCE(dev, dev->type->release != cxl_decoder_release,
+ if (dev_WARN_ONCE(dev,
+ !is_switch_decoder(dev) && !is_endpoint_decoder(dev),
"not a cxl_decoder device\n"))
return NULL;
return container_of(dev, struct cxl_decoder, dev);
}
EXPORT_SYMBOL_NS_GPL(to_cxl_decoder, CXL);
+struct cxl_endpoint_decoder *to_cxl_endpoint_decoder(struct device *dev)
+{
+ if (dev_WARN_ONCE(dev, !is_endpoint_decoder(dev),
+ "not a cxl_endpoint_decoder device\n"))
+ return NULL;
+ return container_of(dev, struct cxl_endpoint_decoder, cxld.dev);
+}
+EXPORT_SYMBOL_NS_GPL(to_cxl_endpoint_decoder, CXL);
+
+struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev)
+{
+ if (dev_WARN_ONCE(dev, !is_switch_decoder(dev),
+ "not a cxl_switch_decoder device\n"))
+ return NULL;
+ return container_of(dev, struct cxl_switch_decoder, cxld.dev);
+}
+
static void cxl_ep_release(struct cxl_ep *ep)
{
- if (!ep)
- return;
- list_del(&ep->list);
put_device(ep->ep);
kfree(ep);
}
+static void cxl_ep_remove(struct cxl_port *port, struct cxl_ep *ep)
+{
+ if (!ep)
+ return;
+ xa_erase(&port->endpoints, (unsigned long) ep->ep);
+ cxl_ep_release(ep);
+}
+
static void cxl_port_release(struct device *dev)
{
struct cxl_port *port = to_cxl_port(dev);
- struct cxl_ep *ep, *_e;
+ unsigned long index;
+ struct cxl_ep *ep;
- device_lock(dev);
- list_for_each_entry_safe(ep, _e, &port->endpoints, list)
- cxl_ep_release(ep);
- device_unlock(dev);
+ xa_for_each(&port->endpoints, index, ep)
+ cxl_ep_remove(port, ep);
+ xa_destroy(&port->endpoints);
+ xa_destroy(&port->dports);
+ xa_destroy(&port->regions);
ida_free(&cxl_port_ida, port->id);
kfree(port);
}
lock_dev = &parent->dev;
device_lock_assert(lock_dev);
- port->uport = NULL;
+ port->dead = true;
device_unregister(&port->dev);
}
static struct cxl_port *cxl_port_alloc(struct device *uport,
resource_size_t component_reg_phys,
- struct cxl_port *parent_port)
+ struct cxl_dport *parent_dport)
{
struct cxl_port *port;
struct device *dev;
if (rc < 0)
goto err;
port->id = rc;
+ port->uport = uport;
/*
* The top-level cxl_port "cxl_root" does not have a cxl_port as
* description.
*/
dev = &port->dev;
- if (parent_port) {
+ if (parent_dport) {
+ struct cxl_port *parent_port = parent_dport->port;
+ struct cxl_port *iter;
+
dev->parent = &parent_port->dev;
port->depth = parent_port->depth + 1;
+ port->parent_dport = parent_dport;
+
+ /*
+ * walk to the host bridge, or the first ancestor that knows
+ * the host bridge
+ */
+ iter = port;
+ while (!iter->host_bridge &&
+ !is_cxl_root(to_cxl_port(iter->dev.parent)))
+ iter = to_cxl_port(iter->dev.parent);
+ if (iter->host_bridge)
+ port->host_bridge = iter->host_bridge;
+ else
+ port->host_bridge = iter->uport;
+ dev_dbg(uport, "host-bridge: %s\n", dev_name(port->host_bridge));
} else
dev->parent = uport;
- port->uport = uport;
port->component_reg_phys = component_reg_phys;
ida_init(&port->decoder_ida);
- INIT_LIST_HEAD(&port->dports);
- INIT_LIST_HEAD(&port->endpoints);
+ port->hdm_end = -1;
+ port->commit_end = -1;
+ xa_init(&port->dports);
+ xa_init(&port->endpoints);
+ xa_init(&port->regions);
device_initialize(dev);
lockdep_set_class_and_subclass(&dev->mutex, &cxl_port_key, port->depth);
* @host: host device for devm operations
* @uport: "physical" device implementing this upstream port
* @component_reg_phys: (optional) for configurable cxl_port instances
- * @parent_port: next hop up in the CXL memory decode hierarchy
+ * @parent_dport: next hop up in the CXL memory decode hierarchy
*/
struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
resource_size_t component_reg_phys,
- struct cxl_port *parent_port)
+ struct cxl_dport *parent_dport)
{
struct cxl_port *port;
struct device *dev;
int rc;
- port = cxl_port_alloc(uport, component_reg_phys, parent_port);
+ port = cxl_port_alloc(uport, component_reg_phys, parent_dport);
if (IS_ERR(port))
return port;
dev = &port->dev;
if (is_cxl_memdev(uport))
rc = dev_set_name(dev, "endpoint%d", port->id);
- else if (parent_port)
+ else if (parent_dport)
rc = dev_set_name(dev, "port%d", port->id);
else
rc = dev_set_name(dev, "root%d", port->id);
return 0;
port = to_cxl_port(dev);
- device_lock(dev);
- list_for_each_entry(dport, &port->dports, list) {
- iter = match;
- while (iter) {
- if (iter == dport->dport)
- goto out;
- iter = iter->parent;
- }
+ iter = match;
+ while (iter) {
+ dport = cxl_find_dport_by_dev(port, iter);
+ if (dport)
+ break;
+ iter = iter->parent;
}
-out:
- device_unlock(dev);
return !!iter;
}
static struct cxl_dport *find_dport(struct cxl_port *port, int id)
{
struct cxl_dport *dport;
+ unsigned long index;
device_lock_assert(&port->dev);
- list_for_each_entry (dport, &port->dports, list)
+ xa_for_each(&port->dports, index, dport)
if (dport->port_id == id)
return dport;
return NULL;
device_lock_assert(&port->dev);
dup = find_dport(port, new->port_id);
- if (dup)
+ if (dup) {
dev_err(&port->dev,
"unable to add dport%d-%s non-unique port id (%s)\n",
new->port_id, dev_name(new->dport),
dev_name(dup->dport));
- else
- list_add_tail(&new->list, &port->dports);
-
- return dup ? -EEXIST : 0;
+ return -EBUSY;
+ }
+ return xa_insert(&port->dports, (unsigned long)new->dport, new,
+ GFP_KERNEL);
}
/*
struct cxl_dport *dport = data;
struct cxl_port *port = dport->port;
+ xa_erase(&port->dports, (unsigned long) dport->dport);
put_device(dport->dport);
- cond_cxl_root_lock(port);
- list_del(&dport->list);
- cond_cxl_root_unlock(port);
}
static void cxl_dport_unlink(void *data)
if (!dport)
return ERR_PTR(-ENOMEM);
- INIT_LIST_HEAD(&dport->list);
dport->dport = dport_dev;
dport->port_id = port_id;
dport->component_reg_phys = component_reg_phys;
}
EXPORT_SYMBOL_NS_GPL(devm_cxl_add_dport, CXL);
-static struct cxl_ep *find_ep(struct cxl_port *port, struct device *ep_dev)
-{
- struct cxl_ep *ep;
-
- device_lock_assert(&port->dev);
- list_for_each_entry(ep, &port->endpoints, list)
- if (ep->ep == ep_dev)
- return ep;
- return NULL;
-}
-
-static int add_ep(struct cxl_port *port, struct cxl_ep *new)
+static int add_ep(struct cxl_ep *new)
{
- struct cxl_ep *dup;
+ struct cxl_port *port = new->dport->port;
+ int rc;
device_lock(&port->dev);
if (port->dead) {
device_unlock(&port->dev);
return -ENXIO;
}
- dup = find_ep(port, new->ep);
- if (!dup)
- list_add_tail(&new->list, &port->endpoints);
+ rc = xa_insert(&port->endpoints, (unsigned long)new->ep, new,
+ GFP_KERNEL);
device_unlock(&port->dev);
- return dup ? -EEXIST : 0;
+ return rc;
}
/**
* cxl_add_ep - register an endpoint's interest in a port
- * @port: a port in the endpoint's topology ancestry
+ * @dport: the dport that routes to @ep_dev
* @ep_dev: device representing the endpoint
*
* Intermediate CXL ports are scanned based on the arrival of endpoints.
* When those endpoints depart the port can be destroyed once all
* endpoints that care about that port have been removed.
*/
-static int cxl_add_ep(struct cxl_port *port, struct device *ep_dev)
+static int cxl_add_ep(struct cxl_dport *dport, struct device *ep_dev)
{
struct cxl_ep *ep;
int rc;
if (!ep)
return -ENOMEM;
- INIT_LIST_HEAD(&ep->list);
ep->ep = get_device(ep_dev);
+ ep->dport = dport;
- rc = add_ep(port, ep);
+ rc = add_ep(ep);
if (rc)
cxl_ep_release(ep);
return rc;
struct cxl_find_port_ctx {
const struct device *dport_dev;
const struct cxl_port *parent_port;
+ struct cxl_dport **dport;
};
static int match_port_by_dport(struct device *dev, const void *data)
{
const struct cxl_find_port_ctx *ctx = data;
+ struct cxl_dport *dport;
struct cxl_port *port;
if (!is_cxl_port(dev))
return 0;
port = to_cxl_port(dev);
- return cxl_find_dport_by_dev(port, ctx->dport_dev) != NULL;
+ dport = cxl_find_dport_by_dev(port, ctx->dport_dev);
+ if (ctx->dport)
+ *ctx->dport = dport;
+ return dport != NULL;
}
static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx)
return NULL;
}
-static struct cxl_port *find_cxl_port(struct device *dport_dev)
+static struct cxl_port *find_cxl_port(struct device *dport_dev,
+ struct cxl_dport **dport)
{
struct cxl_find_port_ctx ctx = {
.dport_dev = dport_dev,
+ .dport = dport,
};
+ struct cxl_port *port;
- return __find_cxl_port(&ctx);
+ port = __find_cxl_port(&ctx);
+ return port;
}
static struct cxl_port *find_cxl_port_at(struct cxl_port *parent_port,
- struct device *dport_dev)
+ struct device *dport_dev,
+ struct cxl_dport **dport)
{
struct cxl_find_port_ctx ctx = {
.dport_dev = dport_dev,
.parent_port = parent_port,
+ .dport = dport,
};
+ struct cxl_port *port;
- return __find_cxl_port(&ctx);
+ port = __find_cxl_port(&ctx);
+ return port;
}
/*
struct cxl_port *parent_port;
struct device *parent;
- parent_port = cxl_mem_find_port(cxlmd);
+ parent_port = cxl_mem_find_port(cxlmd, NULL);
if (!parent_port)
goto out;
parent = &parent_port->dev;
device_lock(parent);
- if (parent->driver && endpoint->uport) {
+ if (parent->driver && !endpoint->dead) {
devm_release_action(parent, cxl_unlink_uport, endpoint);
devm_release_action(parent, unregister_port, endpoint);
}
* for a port to be unregistered is when all memdevs beneath that port have gone
* through ->remove(). This "bottom-up" removal selectively removes individual
* child ports manually. This depends on devm_cxl_add_port() to not change is
- * devm action registration order.
+ * devm action registration order, and for dports to have already been
+ * destroyed by reap_dports().
*/
-static void delete_switch_port(struct cxl_port *port, struct list_head *dports)
+static void delete_switch_port(struct cxl_port *port)
+{
+ devm_release_action(port->dev.parent, cxl_unlink_uport, port);
+ devm_release_action(port->dev.parent, unregister_port, port);
+}
+
+static void reap_dports(struct cxl_port *port)
{
- struct cxl_dport *dport, *_d;
+ struct cxl_dport *dport;
+ unsigned long index;
+
+ device_lock_assert(&port->dev);
- list_for_each_entry_safe(dport, _d, dports, list) {
+ xa_for_each(&port->dports, index, dport) {
devm_release_action(&port->dev, cxl_dport_unlink, dport);
devm_release_action(&port->dev, cxl_dport_remove, dport);
devm_kfree(&port->dev, dport);
}
- devm_release_action(port->dev.parent, cxl_unlink_uport, port);
- devm_release_action(port->dev.parent, unregister_port, port);
}
+int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd,
+ struct cxl_dport *parent_dport)
+{
+ struct cxl_port *parent_port = parent_dport->port;
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct cxl_port *endpoint, *iter, *down;
+ int rc;
+
+ /*
+ * Now that the path to the root is established record all the
+ * intervening ports in the chain.
+ */
+ for (iter = parent_port, down = NULL; !is_cxl_root(iter);
+ down = iter, iter = to_cxl_port(iter->dev.parent)) {
+ struct cxl_ep *ep;
+
+ ep = cxl_ep_load(iter, cxlmd);
+ ep->next = down;
+ }
+
+ endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev,
+ cxlds->component_reg_phys, parent_dport);
+ if (IS_ERR(endpoint))
+ return PTR_ERR(endpoint);
+
+ dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev));
+
+ rc = cxl_endpoint_autoremove(cxlmd, endpoint);
+ if (rc)
+ return rc;
+
+ if (!endpoint->dev.driver) {
+ dev_err(&cxlmd->dev, "%s failed probe\n",
+ dev_name(&endpoint->dev));
+ return -ENXIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(devm_cxl_add_endpoint, CXL);
+
static void cxl_detach_ep(void *data)
{
struct cxl_memdev *cxlmd = data;
for (iter = &cxlmd->dev; iter; iter = grandparent(iter)) {
struct device *dport_dev = grandparent(iter);
struct cxl_port *port, *parent_port;
- LIST_HEAD(reap_dports);
struct cxl_ep *ep;
+ bool died = false;
if (!dport_dev)
break;
- port = find_cxl_port(dport_dev);
+ port = find_cxl_port(dport_dev, NULL);
if (!port)
continue;
}
device_lock(&port->dev);
- ep = find_ep(port, &cxlmd->dev);
+ ep = cxl_ep_load(port, cxlmd);
dev_dbg(&cxlmd->dev, "disconnect %s from %s\n",
ep ? dev_name(ep->ep) : "", dev_name(&port->dev));
- cxl_ep_release(ep);
- if (ep && !port->dead && list_empty(&port->endpoints) &&
+ cxl_ep_remove(port, ep);
+ if (ep && !port->dead && xa_empty(&port->endpoints) &&
!is_cxl_root(parent_port)) {
/*
* This was the last ep attached to a dynamically
* enumerated port. Block new cxl_add_ep() and garbage
* collect the port.
*/
+ died = true;
port->dead = true;
- list_splice_init(&port->dports, &reap_dports);
+ reap_dports(port);
}
device_unlock(&port->dev);
- if (!list_empty(&reap_dports)) {
+ if (died) {
dev_dbg(&cxlmd->dev, "delete %s\n",
dev_name(&port->dev));
- delete_switch_port(port, &reap_dports);
+ delete_switch_port(port);
}
put_device(&port->dev);
device_unlock(&parent_port->dev);
{
struct device *dparent = grandparent(dport_dev);
struct cxl_port *port, *parent_port = NULL;
+ struct cxl_dport *dport, *parent_dport;
resource_size_t component_reg_phys;
int rc;
return -ENXIO;
}
- parent_port = find_cxl_port(dparent);
+ parent_port = find_cxl_port(dparent, &parent_dport);
if (!parent_port) {
/* iterate to create this parent_port */
return -EAGAIN;
goto out;
}
- port = find_cxl_port_at(parent_port, dport_dev);
+ port = find_cxl_port_at(parent_port, dport_dev, &dport);
if (!port) {
component_reg_phys = find_component_registers(uport_dev);
port = devm_cxl_add_port(&parent_port->dev, uport_dev,
- component_reg_phys, parent_port);
+ component_reg_phys, parent_dport);
+ /* retry find to pick up the new dport information */
if (!IS_ERR(port))
- get_device(&port->dev);
+ port = find_cxl_port_at(parent_port, dport_dev, &dport);
}
out:
device_unlock(&parent_port->dev);
else {
dev_dbg(&cxlmd->dev, "add to new port %s:%s\n",
dev_name(&port->dev), dev_name(port->uport));
- rc = cxl_add_ep(port, &cxlmd->dev);
- if (rc == -EEXIST) {
+ rc = cxl_add_ep(dport, &cxlmd->dev);
+ if (rc == -EBUSY) {
/*
* "can't" happen, but this error code means
* something to the caller, so translate it.
for (iter = dev; iter; iter = grandparent(iter)) {
struct device *dport_dev = grandparent(iter);
struct device *uport_dev;
+ struct cxl_dport *dport;
struct cxl_port *port;
if (!dport_dev)
dev_dbg(dev, "scan: iter: %s dport_dev: %s parent: %s\n",
dev_name(iter), dev_name(dport_dev),
dev_name(uport_dev));
- port = find_cxl_port(dport_dev);
+ port = find_cxl_port(dport_dev, &dport);
if (port) {
dev_dbg(&cxlmd->dev,
"found already registered port %s:%s\n",
dev_name(&port->dev), dev_name(port->uport));
- rc = cxl_add_ep(port, &cxlmd->dev);
+ rc = cxl_add_ep(dport, &cxlmd->dev);
/*
* If the endpoint already exists in the port's list,
* the parent_port lock as the current port may be being
* reaped.
*/
- if (rc && rc != -EEXIST) {
+ if (rc && rc != -EBUSY) {
put_device(&port->dev);
return rc;
}
}
EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_ports, CXL);
-struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd)
+struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd,
+ struct cxl_dport **dport)
{
- return find_cxl_port(grandparent(&cxlmd->dev));
+ return find_cxl_port(grandparent(&cxlmd->dev), dport);
}
EXPORT_SYMBOL_NS_GPL(cxl_mem_find_port, CXL);
-struct cxl_dport *cxl_find_dport_by_dev(struct cxl_port *port,
- const struct device *dev)
-{
- struct cxl_dport *dport;
-
- device_lock(&port->dev);
- list_for_each_entry(dport, &port->dports, list)
- if (dport->dport == dev) {
- device_unlock(&port->dev);
- return dport;
- }
-
- device_unlock(&port->dev);
- return NULL;
-}
-EXPORT_SYMBOL_NS_GPL(cxl_find_dport_by_dev, CXL);
-
-static int decoder_populate_targets(struct cxl_decoder *cxld,
+static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd,
struct cxl_port *port, int *target_map)
{
int i, rc = 0;
device_lock_assert(&port->dev);
- if (list_empty(&port->dports))
+ if (xa_empty(&port->dports))
return -EINVAL;
- write_seqlock(&cxld->target_lock);
- for (i = 0; i < cxld->nr_targets; i++) {
+ write_seqlock(&cxlsd->target_lock);
+ for (i = 0; i < cxlsd->nr_targets; i++) {
struct cxl_dport *dport = find_dport(port, target_map[i]);
if (!dport) {
rc = -ENXIO;
break;
}
- cxld->target[i] = dport;
+ cxlsd->target[i] = dport;
}
- write_sequnlock(&cxld->target_lock);
+ write_sequnlock(&cxlsd->target_lock);
return rc;
}
+static struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos)
+{
+ struct cxl_switch_decoder *cxlsd = &cxlrd->cxlsd;
+ struct cxl_decoder *cxld = &cxlsd->cxld;
+ int iw;
+
+ iw = cxld->interleave_ways;
+ if (dev_WARN_ONCE(&cxld->dev, iw != cxlsd->nr_targets,
+ "misconfigured root decoder\n"))
+ return NULL;
+
+ return cxlrd->cxlsd.target[pos % iw];
+}
+
static struct lock_class_key cxl_decoder_key;
/**
- * cxl_decoder_alloc - Allocate a new CXL decoder
+ * cxl_decoder_init - Common decoder setup / initialization
* @port: owning port of this decoder
- * @nr_targets: downstream targets accessible by this decoder. All upstream
- * ports and root ports must have at least 1 target. Endpoint
- * devices will have 0 targets. Callers wishing to register an
- * endpoint device should specify 0.
- *
- * A port should contain one or more decoders. Each of those decoders enable
- * some address space for CXL.mem utilization. A decoder is expected to be
- * configured by the caller before registering.
+ * @cxld: common decoder properties to initialize
*
- * Return: A new cxl decoder to be registered by cxl_decoder_add(). The decoder
- * is initialized to be a "passthrough" decoder.
+ * A port may contain one or more decoders. Each of those decoders
+ * enable some address space for CXL.mem utilization. A decoder is
+ * expected to be configured by the caller before registering via
+ * cxl_decoder_add()
*/
-static struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port,
- unsigned int nr_targets)
+static int cxl_decoder_init(struct cxl_port *port, struct cxl_decoder *cxld)
{
- struct cxl_decoder *cxld;
struct device *dev;
- int rc = 0;
-
- if (nr_targets > CXL_DECODER_MAX_INTERLEAVE)
- return ERR_PTR(-EINVAL);
-
- cxld = kzalloc(struct_size(cxld, target, nr_targets), GFP_KERNEL);
- if (!cxld)
- return ERR_PTR(-ENOMEM);
+ int rc;
rc = ida_alloc(&port->decoder_ida, GFP_KERNEL);
if (rc < 0)
- goto err;
+ return rc;
/* need parent to stick around to release the id */
get_device(&port->dev);
cxld->id = rc;
- cxld->nr_targets = nr_targets;
- seqlock_init(&cxld->target_lock);
dev = &cxld->dev;
device_initialize(dev);
lockdep_set_class(&dev->mutex, &cxl_decoder_key);
device_set_pm_not_required(dev);
dev->parent = &port->dev;
dev->bus = &cxl_bus_type;
- if (is_cxl_root(port))
- cxld->dev.type = &cxl_decoder_root_type;
- else if (is_cxl_endpoint(port))
- cxld->dev.type = &cxl_decoder_endpoint_type;
- else
- cxld->dev.type = &cxl_decoder_switch_type;
/* Pre initialize an "empty" decoder */
cxld->interleave_ways = 1;
cxld->interleave_granularity = PAGE_SIZE;
cxld->target_type = CXL_DECODER_EXPANDER;
- cxld->platform_res = (struct resource)DEFINE_RES_MEM(0, 0);
+ cxld->hpa_range = (struct range) {
+ .start = 0,
+ .end = -1,
+ };
- return cxld;
-err:
- kfree(cxld);
- return ERR_PTR(rc);
+ return 0;
+}
+
+static int cxl_switch_decoder_init(struct cxl_port *port,
+ struct cxl_switch_decoder *cxlsd,
+ int nr_targets)
+{
+ if (nr_targets > CXL_DECODER_MAX_INTERLEAVE)
+ return -EINVAL;
+
+ cxlsd->nr_targets = nr_targets;
+ seqlock_init(&cxlsd->target_lock);
+ return cxl_decoder_init(port, &cxlsd->cxld);
}
/**
* firmware description of CXL resources into a CXL standard decode
* topology.
*/
-struct cxl_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
- unsigned int nr_targets)
+struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
+ unsigned int nr_targets)
{
+ struct cxl_root_decoder *cxlrd;
+ struct cxl_switch_decoder *cxlsd;
+ struct cxl_decoder *cxld;
+ int rc;
+
if (!is_cxl_root(port))
return ERR_PTR(-EINVAL);
- return cxl_decoder_alloc(port, nr_targets);
+ cxlrd = kzalloc(struct_size(cxlrd, cxlsd.target, nr_targets),
+ GFP_KERNEL);
+ if (!cxlrd)
+ return ERR_PTR(-ENOMEM);
+
+ cxlsd = &cxlrd->cxlsd;
+ rc = cxl_switch_decoder_init(port, cxlsd, nr_targets);
+ if (rc) {
+ kfree(cxlrd);
+ return ERR_PTR(rc);
+ }
+
+ cxlrd->calc_hb = cxl_hb_modulo;
+
+ cxld = &cxlsd->cxld;
+ cxld->dev.type = &cxl_decoder_root_type;
+ /*
+ * cxl_root_decoder_release() special cases negative ids to
+ * detect memregion_alloc() failures.
+ */
+ atomic_set(&cxlrd->region_id, -1);
+ rc = memregion_alloc(GFP_KERNEL);
+ if (rc < 0) {
+ put_device(&cxld->dev);
+ return ERR_PTR(rc);
+ }
+
+ atomic_set(&cxlrd->region_id, rc);
+ return cxlrd;
}
EXPORT_SYMBOL_NS_GPL(cxl_root_decoder_alloc, CXL);
* that sit between Switch Upstream Ports / Switch Downstream Ports and
* Host Bridges / Root Ports.
*/
-struct cxl_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
- unsigned int nr_targets)
+struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
+ unsigned int nr_targets)
{
+ struct cxl_switch_decoder *cxlsd;
+ struct cxl_decoder *cxld;
+ int rc;
+
if (is_cxl_root(port) || is_cxl_endpoint(port))
return ERR_PTR(-EINVAL);
- return cxl_decoder_alloc(port, nr_targets);
+ cxlsd = kzalloc(struct_size(cxlsd, target, nr_targets), GFP_KERNEL);
+ if (!cxlsd)
+ return ERR_PTR(-ENOMEM);
+
+ rc = cxl_switch_decoder_init(port, cxlsd, nr_targets);
+ if (rc) {
+ kfree(cxlsd);
+ return ERR_PTR(rc);
+ }
+
+ cxld = &cxlsd->cxld;
+ cxld->dev.type = &cxl_decoder_switch_type;
+ return cxlsd;
}
EXPORT_SYMBOL_NS_GPL(cxl_switch_decoder_alloc, CXL);
*
* Return: A new cxl decoder to be registered by cxl_decoder_add()
*/
-struct cxl_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port)
+struct cxl_endpoint_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port)
{
+ struct cxl_endpoint_decoder *cxled;
+ struct cxl_decoder *cxld;
+ int rc;
+
if (!is_cxl_endpoint(port))
return ERR_PTR(-EINVAL);
- return cxl_decoder_alloc(port, 0);
+ cxled = kzalloc(sizeof(*cxled), GFP_KERNEL);
+ if (!cxled)
+ return ERR_PTR(-ENOMEM);
+
+ cxled->pos = -1;
+ cxld = &cxled->cxld;
+ rc = cxl_decoder_init(port, cxld);
+ if (rc) {
+ kfree(cxled);
+ return ERR_PTR(rc);
+ }
+
+ cxld->dev.type = &cxl_decoder_endpoint_type;
+ return cxled;
}
EXPORT_SYMBOL_NS_GPL(cxl_endpoint_decoder_alloc, CXL);
/**
* cxl_decoder_add_locked - Add a decoder with targets
- * @cxld: The cxl decoder allocated by cxl_decoder_alloc()
+ * @cxld: The cxl decoder allocated by cxl_<type>_decoder_alloc()
* @target_map: A list of downstream ports that this decoder can direct memory
* traffic to. These numbers should correspond with the port number
* in the PCIe Link Capabilities structure.
port = to_cxl_port(cxld->dev.parent);
if (!is_endpoint_decoder(dev)) {
- rc = decoder_populate_targets(cxld, port, target_map);
+ struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(dev);
+
+ rc = decoder_populate_targets(cxlsd, port, target_map);
if (rc && (cxld->flags & CXL_DECODER_F_ENABLE)) {
dev_err(&port->dev,
"Failed to populate active decoder targets\n");
if (rc)
return rc;
- /*
- * Platform decoder resources should show up with a reasonable name. All
- * other resources are just sub ranges within the main decoder resource.
- */
- if (is_root_decoder(dev))
- cxld->platform_res.name = dev_name(dev);
-
return device_add(dev);
}
EXPORT_SYMBOL_NS_GPL(cxl_decoder_add_locked, CXL);
/**
* cxl_decoder_add - Add a decoder with targets
- * @cxld: The cxl decoder allocated by cxl_decoder_alloc()
+ * @cxld: The cxl decoder allocated by cxl_<type>_decoder_alloc()
* @target_map: A list of downstream ports that this decoder can direct memory
* traffic to. These numbers should correspond with the port number
* in the PCIe Link Capabilities structure.
static void cxld_unregister(void *dev)
{
+ struct cxl_endpoint_decoder *cxled;
+
+ if (is_endpoint_decoder(dev)) {
+ cxled = to_cxl_endpoint_decoder(dev);
+ cxl_decoder_kill_region(cxled);
+ }
+
device_unregister(dev);
}
};
EXPORT_SYMBOL_NS_GPL(cxl_bus_type, CXL);
+static struct dentry *cxl_debugfs;
+
+struct dentry *cxl_debugfs_create_dir(const char *dir)
+{
+ return debugfs_create_dir(dir, cxl_debugfs);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_debugfs_create_dir, CXL);
+
static __init int cxl_core_init(void)
{
int rc;
+ cxl_debugfs = debugfs_create_dir("cxl", NULL);
+
cxl_mbox_init();
rc = cxl_memdev_init();
if (rc)
goto err_bus;
+ rc = cxl_region_init();
+ if (rc)
+ goto err_region;
+
return 0;
+err_region:
+ bus_unregister(&cxl_bus_type);
err_bus:
destroy_workqueue(cxl_bus_wq);
err_wq:
cxl_memdev_exit();
- cxl_mbox_exit();
return rc;
}
static void cxl_core_exit(void)
{
+ cxl_region_exit();
bus_unregister(&cxl_bus_type);
destroy_workqueue(cxl_bus_wq);
cxl_memdev_exit();
- cxl_mbox_exit();
+ debugfs_remove_recursive(cxl_debugfs);
}
module_init(cxl_core_init);
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
+#include <linux/memregion.h>
+#include <linux/genalloc.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uuid.h>
+#include <linux/idr.h>
+#include <cxlmem.h>
+#include <cxl.h>
+#include "core.h"
+
+/**
+ * DOC: cxl core region
+ *
+ * CXL Regions represent mapped memory capacity in system physical address
+ * space. Whereas the CXL Root Decoders identify the bounds of potential CXL
+ * Memory ranges, Regions represent the active mapped capacity by the HDM
+ * Decoder Capability structures throughout the Host Bridges, Switches, and
+ * Endpoints in the topology.
+ *
+ * Region configuration has ordering constraints. UUID may be set at any time
+ * but is only visible for persistent regions.
+ * 1. Interleave granularity
+ * 2. Interleave size
+ * 3. Decoder targets
+ */
+
+/*
+ * All changes to the interleave configuration occur with this lock held
+ * for write.
+ */
+static DECLARE_RWSEM(cxl_region_rwsem);
+
+static struct cxl_region *to_cxl_region(struct device *dev);
+
+static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_region *cxlr = to_cxl_region(dev);
+ struct cxl_region_params *p = &cxlr->params;
+ ssize_t rc;
+
+ rc = down_read_interruptible(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+ rc = sysfs_emit(buf, "%pUb\n", &p->uuid);
+ up_read(&cxl_region_rwsem);
+
+ return rc;
+}
+
+static int is_dup(struct device *match, void *data)
+{
+ struct cxl_region_params *p;
+ struct cxl_region *cxlr;
+ uuid_t *uuid = data;
+
+ if (!is_cxl_region(match))
+ return 0;
+
+ lockdep_assert_held(&cxl_region_rwsem);
+ cxlr = to_cxl_region(match);
+ p = &cxlr->params;
+
+ if (uuid_equal(&p->uuid, uuid)) {
+ dev_dbg(match, "already has uuid: %pUb\n", uuid);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static ssize_t uuid_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct cxl_region *cxlr = to_cxl_region(dev);
+ struct cxl_region_params *p = &cxlr->params;
+ uuid_t temp;
+ ssize_t rc;
+
+ if (len != UUID_STRING_LEN + 1)
+ return -EINVAL;
+
+ rc = uuid_parse(buf, &temp);
+ if (rc)
+ return rc;
+
+ if (uuid_is_null(&temp))
+ return -EINVAL;
+
+ rc = down_write_killable(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+
+ if (uuid_equal(&p->uuid, &temp))
+ goto out;
+
+ rc = -EBUSY;
+ if (p->state >= CXL_CONFIG_ACTIVE)
+ goto out;
+
+ rc = bus_for_each_dev(&cxl_bus_type, NULL, &temp, is_dup);
+ if (rc < 0)
+ goto out;
+
+ uuid_copy(&p->uuid, &temp);
+out:
+ up_write(&cxl_region_rwsem);
+
+ if (rc)
+ return rc;
+ return len;
+}
+static DEVICE_ATTR_RW(uuid);
+
+static struct cxl_region_ref *cxl_rr_load(struct cxl_port *port,
+ struct cxl_region *cxlr)
+{
+ return xa_load(&port->regions, (unsigned long)cxlr);
+}
+
+static int cxl_region_decode_reset(struct cxl_region *cxlr, int count)
+{
+ struct cxl_region_params *p = &cxlr->params;
+ int i;
+
+ for (i = count - 1; i >= 0; i--) {
+ struct cxl_endpoint_decoder *cxled = p->targets[i];
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct cxl_port *iter = cxled_to_port(cxled);
+ struct cxl_ep *ep;
+ int rc;
+
+ while (!is_cxl_root(to_cxl_port(iter->dev.parent)))
+ iter = to_cxl_port(iter->dev.parent);
+
+ for (ep = cxl_ep_load(iter, cxlmd); iter;
+ iter = ep->next, ep = cxl_ep_load(iter, cxlmd)) {
+ struct cxl_region_ref *cxl_rr;
+ struct cxl_decoder *cxld;
+
+ cxl_rr = cxl_rr_load(iter, cxlr);
+ cxld = cxl_rr->decoder;
+ rc = cxld->reset(cxld);
+ if (rc)
+ return rc;
+ }
+
+ rc = cxled->cxld.reset(&cxled->cxld);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static int cxl_region_decode_commit(struct cxl_region *cxlr)
+{
+ struct cxl_region_params *p = &cxlr->params;
+ int i, rc = 0;
+
+ for (i = 0; i < p->nr_targets; i++) {
+ struct cxl_endpoint_decoder *cxled = p->targets[i];
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct cxl_region_ref *cxl_rr;
+ struct cxl_decoder *cxld;
+ struct cxl_port *iter;
+ struct cxl_ep *ep;
+
+ /* commit bottom up */
+ for (iter = cxled_to_port(cxled); !is_cxl_root(iter);
+ iter = to_cxl_port(iter->dev.parent)) {
+ cxl_rr = cxl_rr_load(iter, cxlr);
+ cxld = cxl_rr->decoder;
+ rc = cxld->commit(cxld);
+ if (rc)
+ break;
+ }
+
+ if (rc) {
+ /* programming @iter failed, teardown */
+ for (ep = cxl_ep_load(iter, cxlmd); ep && iter;
+ iter = ep->next, ep = cxl_ep_load(iter, cxlmd)) {
+ cxl_rr = cxl_rr_load(iter, cxlr);
+ cxld = cxl_rr->decoder;
+ cxld->reset(cxld);
+ }
+
+ cxled->cxld.reset(&cxled->cxld);
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ /* undo the targets that were successfully committed */
+ cxl_region_decode_reset(cxlr, i);
+ return rc;
+}
+
+static ssize_t commit_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct cxl_region *cxlr = to_cxl_region(dev);
+ struct cxl_region_params *p = &cxlr->params;
+ bool commit;
+ ssize_t rc;
+
+ rc = kstrtobool(buf, &commit);
+ if (rc)
+ return rc;
+
+ rc = down_write_killable(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+
+ /* Already in the requested state? */
+ if (commit && p->state >= CXL_CONFIG_COMMIT)
+ goto out;
+ if (!commit && p->state < CXL_CONFIG_COMMIT)
+ goto out;
+
+ /* Not ready to commit? */
+ if (commit && p->state < CXL_CONFIG_ACTIVE) {
+ rc = -ENXIO;
+ goto out;
+ }
+
+ if (commit)
+ rc = cxl_region_decode_commit(cxlr);
+ else {
+ p->state = CXL_CONFIG_RESET_PENDING;
+ up_write(&cxl_region_rwsem);
+ device_release_driver(&cxlr->dev);
+ down_write(&cxl_region_rwsem);
+
+ /*
+ * The lock was dropped, so need to revalidate that the reset is
+ * still pending.
+ */
+ if (p->state == CXL_CONFIG_RESET_PENDING)
+ rc = cxl_region_decode_reset(cxlr, p->interleave_ways);
+ }
+
+ if (rc)
+ goto out;
+
+ if (commit)
+ p->state = CXL_CONFIG_COMMIT;
+ else if (p->state == CXL_CONFIG_RESET_PENDING)
+ p->state = CXL_CONFIG_ACTIVE;
+
+out:
+ up_write(&cxl_region_rwsem);
+
+ if (rc)
+ return rc;
+ return len;
+}
+
+static ssize_t commit_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_region *cxlr = to_cxl_region(dev);
+ struct cxl_region_params *p = &cxlr->params;
+ ssize_t rc;
+
+ rc = down_read_interruptible(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+ rc = sysfs_emit(buf, "%d\n", p->state >= CXL_CONFIG_COMMIT);
+ up_read(&cxl_region_rwsem);
+
+ return rc;
+}
+static DEVICE_ATTR_RW(commit);
+
+static umode_t cxl_region_visible(struct kobject *kobj, struct attribute *a,
+ int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct cxl_region *cxlr = to_cxl_region(dev);
+
+ if (a == &dev_attr_uuid.attr && cxlr->mode != CXL_DECODER_PMEM)
+ return 0;
+ return a->mode;
+}
+
+static ssize_t interleave_ways_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cxl_region *cxlr = to_cxl_region(dev);
+ struct cxl_region_params *p = &cxlr->params;
+ ssize_t rc;
+
+ rc = down_read_interruptible(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+ rc = sysfs_emit(buf, "%d\n", p->interleave_ways);
+ up_read(&cxl_region_rwsem);
+
+ return rc;
+}
+
+static const struct attribute_group *get_cxl_region_target_group(void);
+
+static ssize_t interleave_ways_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev->parent);
+ struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
+ struct cxl_region *cxlr = to_cxl_region(dev);
+ struct cxl_region_params *p = &cxlr->params;
+ unsigned int val, save;
+ int rc;
+ u8 iw;
+
+ rc = kstrtouint(buf, 0, &val);
+ if (rc)
+ return rc;
+
+ rc = ways_to_cxl(val, &iw);
+ if (rc)
+ return rc;
+
+ /*
+ * Even for x3, x9, and x12 interleaves the region interleave must be a
+ * power of 2 multiple of the host bridge interleave.
+ */
+ if (!is_power_of_2(val / cxld->interleave_ways) ||
+ (val % cxld->interleave_ways)) {
+ dev_dbg(&cxlr->dev, "invalid interleave: %d\n", val);
+ return -EINVAL;
+ }
+
+ rc = down_write_killable(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+ if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) {
+ rc = -EBUSY;
+ goto out;
+ }
+
+ save = p->interleave_ways;
+ p->interleave_ways = val;
+ rc = sysfs_update_group(&cxlr->dev.kobj, get_cxl_region_target_group());
+ if (rc)
+ p->interleave_ways = save;
+out:
+ up_write(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+ return len;
+}
+static DEVICE_ATTR_RW(interleave_ways);
+
+static ssize_t interleave_granularity_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_region *cxlr = to_cxl_region(dev);
+ struct cxl_region_params *p = &cxlr->params;
+ ssize_t rc;
+
+ rc = down_read_interruptible(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+ rc = sysfs_emit(buf, "%d\n", p->interleave_granularity);
+ up_read(&cxl_region_rwsem);
+
+ return rc;
+}
+
+static ssize_t interleave_granularity_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev->parent);
+ struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
+ struct cxl_region *cxlr = to_cxl_region(dev);
+ struct cxl_region_params *p = &cxlr->params;
+ int rc, val;
+ u16 ig;
+
+ rc = kstrtoint(buf, 0, &val);
+ if (rc)
+ return rc;
+
+ rc = granularity_to_cxl(val, &ig);
+ if (rc)
+ return rc;
+
+ /*
+ * When the host-bridge is interleaved, disallow region granularity !=
+ * root granularity. Regions with a granularity less than the root
+ * interleave result in needing multiple endpoints to support a single
+ * slot in the interleave (possible to suport in the future). Regions
+ * with a granularity greater than the root interleave result in invalid
+ * DPA translations (invalid to support).
+ */
+ if (cxld->interleave_ways > 1 && val != cxld->interleave_granularity)
+ return -EINVAL;
+
+ rc = down_write_killable(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+ if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) {
+ rc = -EBUSY;
+ goto out;
+ }
+
+ p->interleave_granularity = val;
+out:
+ up_write(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+ return len;
+}
+static DEVICE_ATTR_RW(interleave_granularity);
+
+static ssize_t resource_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_region *cxlr = to_cxl_region(dev);
+ struct cxl_region_params *p = &cxlr->params;
+ u64 resource = -1ULL;
+ ssize_t rc;
+
+ rc = down_read_interruptible(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+ if (p->res)
+ resource = p->res->start;
+ rc = sysfs_emit(buf, "%#llx\n", resource);
+ up_read(&cxl_region_rwsem);
+
+ return rc;
+}
+static DEVICE_ATTR_RO(resource);
+
+static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size)
+{
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
+ struct cxl_region_params *p = &cxlr->params;
+ struct resource *res;
+ u32 remainder = 0;
+
+ lockdep_assert_held_write(&cxl_region_rwsem);
+
+ /* Nothing to do... */
+ if (p->res && resource_size(p->res) == size)
+ return 0;
+
+ /* To change size the old size must be freed first */
+ if (p->res)
+ return -EBUSY;
+
+ if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE)
+ return -EBUSY;
+
+ /* ways, granularity and uuid (if PMEM) need to be set before HPA */
+ if (!p->interleave_ways || !p->interleave_granularity ||
+ (cxlr->mode == CXL_DECODER_PMEM && uuid_is_null(&p->uuid)))
+ return -ENXIO;
+
+ div_u64_rem(size, SZ_256M * p->interleave_ways, &remainder);
+ if (remainder)
+ return -EINVAL;
+
+ res = alloc_free_mem_region(cxlrd->res, size, SZ_256M,
+ dev_name(&cxlr->dev));
+ if (IS_ERR(res)) {
+ dev_dbg(&cxlr->dev, "failed to allocate HPA: %ld\n",
+ PTR_ERR(res));
+ return PTR_ERR(res);
+ }
+
+ p->res = res;
+ p->state = CXL_CONFIG_INTERLEAVE_ACTIVE;
+
+ return 0;
+}
+
+static void cxl_region_iomem_release(struct cxl_region *cxlr)
+{
+ struct cxl_region_params *p = &cxlr->params;
+
+ if (device_is_registered(&cxlr->dev))
+ lockdep_assert_held_write(&cxl_region_rwsem);
+ if (p->res) {
+ remove_resource(p->res);
+ kfree(p->res);
+ p->res = NULL;
+ }
+}
+
+static int free_hpa(struct cxl_region *cxlr)
+{
+ struct cxl_region_params *p = &cxlr->params;
+
+ lockdep_assert_held_write(&cxl_region_rwsem);
+
+ if (!p->res)
+ return 0;
+
+ if (p->state >= CXL_CONFIG_ACTIVE)
+ return -EBUSY;
+
+ cxl_region_iomem_release(cxlr);
+ p->state = CXL_CONFIG_IDLE;
+ return 0;
+}
+
+static ssize_t size_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct cxl_region *cxlr = to_cxl_region(dev);
+ u64 val;
+ int rc;
+
+ rc = kstrtou64(buf, 0, &val);
+ if (rc)
+ return rc;
+
+ rc = down_write_killable(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+
+ if (val)
+ rc = alloc_hpa(cxlr, val);
+ else
+ rc = free_hpa(cxlr);
+ up_write(&cxl_region_rwsem);
+
+ if (rc)
+ return rc;
+
+ return len;
+}
+
+static ssize_t size_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_region *cxlr = to_cxl_region(dev);
+ struct cxl_region_params *p = &cxlr->params;
+ u64 size = 0;
+ ssize_t rc;
+
+ rc = down_read_interruptible(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+ if (p->res)
+ size = resource_size(p->res);
+ rc = sysfs_emit(buf, "%#llx\n", size);
+ up_read(&cxl_region_rwsem);
+
+ return rc;
+}
+static DEVICE_ATTR_RW(size);
+
+static struct attribute *cxl_region_attrs[] = {
+ &dev_attr_uuid.attr,
+ &dev_attr_commit.attr,
+ &dev_attr_interleave_ways.attr,
+ &dev_attr_interleave_granularity.attr,
+ &dev_attr_resource.attr,
+ &dev_attr_size.attr,
+ NULL,
+};
+
+static const struct attribute_group cxl_region_group = {
+ .attrs = cxl_region_attrs,
+ .is_visible = cxl_region_visible,
+};
+
+static size_t show_targetN(struct cxl_region *cxlr, char *buf, int pos)
+{
+ struct cxl_region_params *p = &cxlr->params;
+ struct cxl_endpoint_decoder *cxled;
+ int rc;
+
+ rc = down_read_interruptible(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+
+ if (pos >= p->interleave_ways) {
+ dev_dbg(&cxlr->dev, "position %d out of range %d\n", pos,
+ p->interleave_ways);
+ rc = -ENXIO;
+ goto out;
+ }
+
+ cxled = p->targets[pos];
+ if (!cxled)
+ rc = sysfs_emit(buf, "\n");
+ else
+ rc = sysfs_emit(buf, "%s\n", dev_name(&cxled->cxld.dev));
+out:
+ up_read(&cxl_region_rwsem);
+
+ return rc;
+}
+
+static int match_free_decoder(struct device *dev, void *data)
+{
+ struct cxl_decoder *cxld;
+ int *id = data;
+
+ if (!is_switch_decoder(dev))
+ return 0;
+
+ cxld = to_cxl_decoder(dev);
+
+ /* enforce ordered allocation */
+ if (cxld->id != *id)
+ return 0;
+
+ if (!cxld->region)
+ return 1;
+
+ (*id)++;
+
+ return 0;
+}
+
+static struct cxl_decoder *cxl_region_find_decoder(struct cxl_port *port,
+ struct cxl_region *cxlr)
+{
+ struct device *dev;
+ int id = 0;
+
+ dev = device_find_child(&port->dev, &id, match_free_decoder);
+ if (!dev)
+ return NULL;
+ /*
+ * This decoder is pinned registered as long as the endpoint decoder is
+ * registered, and endpoint decoder unregistration holds the
+ * cxl_region_rwsem over unregister events, so no need to hold on to
+ * this extra reference.
+ */
+ put_device(dev);
+ return to_cxl_decoder(dev);
+}
+
+static struct cxl_region_ref *alloc_region_ref(struct cxl_port *port,
+ struct cxl_region *cxlr)
+{
+ struct cxl_region_params *p = &cxlr->params;
+ struct cxl_region_ref *cxl_rr, *iter;
+ unsigned long index;
+ int rc;
+
+ xa_for_each(&port->regions, index, iter) {
+ struct cxl_region_params *ip = &iter->region->params;
+
+ if (ip->res->start > p->res->start) {
+ dev_dbg(&cxlr->dev,
+ "%s: HPA order violation %s:%pr vs %pr\n",
+ dev_name(&port->dev),
+ dev_name(&iter->region->dev), ip->res, p->res);
+ return ERR_PTR(-EBUSY);
+ }
+ }
+
+ cxl_rr = kzalloc(sizeof(*cxl_rr), GFP_KERNEL);
+ if (!cxl_rr)
+ return ERR_PTR(-ENOMEM);
+ cxl_rr->port = port;
+ cxl_rr->region = cxlr;
+ cxl_rr->nr_targets = 1;
+ xa_init(&cxl_rr->endpoints);
+
+ rc = xa_insert(&port->regions, (unsigned long)cxlr, cxl_rr, GFP_KERNEL);
+ if (rc) {
+ dev_dbg(&cxlr->dev,
+ "%s: failed to track region reference: %d\n",
+ dev_name(&port->dev), rc);
+ kfree(cxl_rr);
+ return ERR_PTR(rc);
+ }
+
+ return cxl_rr;
+}
+
+static void free_region_ref(struct cxl_region_ref *cxl_rr)
+{
+ struct cxl_port *port = cxl_rr->port;
+ struct cxl_region *cxlr = cxl_rr->region;
+ struct cxl_decoder *cxld = cxl_rr->decoder;
+
+ dev_WARN_ONCE(&cxlr->dev, cxld->region != cxlr, "region mismatch\n");
+ if (cxld->region == cxlr) {
+ cxld->region = NULL;
+ put_device(&cxlr->dev);
+ }
+
+ xa_erase(&port->regions, (unsigned long)cxlr);
+ xa_destroy(&cxl_rr->endpoints);
+ kfree(cxl_rr);
+}
+
+static int cxl_rr_ep_add(struct cxl_region_ref *cxl_rr,
+ struct cxl_endpoint_decoder *cxled)
+{
+ int rc;
+ struct cxl_port *port = cxl_rr->port;
+ struct cxl_region *cxlr = cxl_rr->region;
+ struct cxl_decoder *cxld = cxl_rr->decoder;
+ struct cxl_ep *ep = cxl_ep_load(port, cxled_to_memdev(cxled));
+
+ if (ep) {
+ rc = xa_insert(&cxl_rr->endpoints, (unsigned long)cxled, ep,
+ GFP_KERNEL);
+ if (rc)
+ return rc;
+ }
+ cxl_rr->nr_eps++;
+
+ if (!cxld->region) {
+ cxld->region = cxlr;
+ get_device(&cxlr->dev);
+ }
+
+ return 0;
+}
+
+/**
+ * cxl_port_attach_region() - track a region's interest in a port by endpoint
+ * @port: port to add a new region reference 'struct cxl_region_ref'
+ * @cxlr: region to attach to @port
+ * @cxled: endpoint decoder used to create or further pin a region reference
+ * @pos: interleave position of @cxled in @cxlr
+ *
+ * The attach event is an opportunity to validate CXL decode setup
+ * constraints and record metadata needed for programming HDM decoders,
+ * in particular decoder target lists.
+ *
+ * The steps are:
+ *
+ * - validate that there are no other regions with a higher HPA already
+ * associated with @port
+ * - establish a region reference if one is not already present
+ *
+ * - additionally allocate a decoder instance that will host @cxlr on
+ * @port
+ *
+ * - pin the region reference by the endpoint
+ * - account for how many entries in @port's target list are needed to
+ * cover all of the added endpoints.
+ */
+static int cxl_port_attach_region(struct cxl_port *port,
+ struct cxl_region *cxlr,
+ struct cxl_endpoint_decoder *cxled, int pos)
+{
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct cxl_ep *ep = cxl_ep_load(port, cxlmd);
+ struct cxl_region_ref *cxl_rr;
+ bool nr_targets_inc = false;
+ struct cxl_decoder *cxld;
+ unsigned long index;
+ int rc = -EBUSY;
+
+ lockdep_assert_held_write(&cxl_region_rwsem);
+
+ cxl_rr = cxl_rr_load(port, cxlr);
+ if (cxl_rr) {
+ struct cxl_ep *ep_iter;
+ int found = 0;
+
+ /*
+ * Walk the existing endpoints that have been attached to
+ * @cxlr at @port and see if they share the same 'next' port
+ * in the downstream direction. I.e. endpoints that share common
+ * upstream switch.
+ */
+ xa_for_each(&cxl_rr->endpoints, index, ep_iter) {
+ if (ep_iter == ep)
+ continue;
+ if (ep_iter->next == ep->next) {
+ found++;
+ break;
+ }
+ }
+
+ /*
+ * New target port, or @port is an endpoint port that always
+ * accounts its own local decode as a target.
+ */
+ if (!found || !ep->next) {
+ cxl_rr->nr_targets++;
+ nr_targets_inc = true;
+ }
+
+ /*
+ * The decoder for @cxlr was allocated when the region was first
+ * attached to @port.
+ */
+ cxld = cxl_rr->decoder;
+ } else {
+ cxl_rr = alloc_region_ref(port, cxlr);
+ if (IS_ERR(cxl_rr)) {
+ dev_dbg(&cxlr->dev,
+ "%s: failed to allocate region reference\n",
+ dev_name(&port->dev));
+ return PTR_ERR(cxl_rr);
+ }
+ nr_targets_inc = true;
+
+ if (port == cxled_to_port(cxled))
+ cxld = &cxled->cxld;
+ else
+ cxld = cxl_region_find_decoder(port, cxlr);
+ if (!cxld) {
+ dev_dbg(&cxlr->dev, "%s: no decoder available\n",
+ dev_name(&port->dev));
+ goto out_erase;
+ }
+
+ if (cxld->region) {
+ dev_dbg(&cxlr->dev, "%s: %s already attached to %s\n",
+ dev_name(&port->dev), dev_name(&cxld->dev),
+ dev_name(&cxld->region->dev));
+ rc = -EBUSY;
+ goto out_erase;
+ }
+
+ cxl_rr->decoder = cxld;
+ }
+
+ rc = cxl_rr_ep_add(cxl_rr, cxled);
+ if (rc) {
+ dev_dbg(&cxlr->dev,
+ "%s: failed to track endpoint %s:%s reference\n",
+ dev_name(&port->dev), dev_name(&cxlmd->dev),
+ dev_name(&cxld->dev));
+ goto out_erase;
+ }
+
+ dev_dbg(&cxlr->dev,
+ "%s:%s %s add: %s:%s @ %d next: %s nr_eps: %d nr_targets: %d\n",
+ dev_name(port->uport), dev_name(&port->dev),
+ dev_name(&cxld->dev), dev_name(&cxlmd->dev),
+ dev_name(&cxled->cxld.dev), pos,
+ ep ? ep->next ? dev_name(ep->next->uport) :
+ dev_name(&cxlmd->dev) :
+ "none",
+ cxl_rr->nr_eps, cxl_rr->nr_targets);
+
+ return 0;
+out_erase:
+ if (nr_targets_inc)
+ cxl_rr->nr_targets--;
+ if (cxl_rr->nr_eps == 0)
+ free_region_ref(cxl_rr);
+ return rc;
+}
+
+static void cxl_port_detach_region(struct cxl_port *port,
+ struct cxl_region *cxlr,
+ struct cxl_endpoint_decoder *cxled)
+{
+ struct cxl_region_ref *cxl_rr;
+ struct cxl_ep *ep = NULL;
+
+ lockdep_assert_held_write(&cxl_region_rwsem);
+
+ cxl_rr = cxl_rr_load(port, cxlr);
+ if (!cxl_rr)
+ return;
+
+ /*
+ * Endpoint ports do not carry cxl_ep references, and they
+ * never target more than one endpoint by definition
+ */
+ if (cxl_rr->decoder == &cxled->cxld)
+ cxl_rr->nr_eps--;
+ else
+ ep = xa_erase(&cxl_rr->endpoints, (unsigned long)cxled);
+ if (ep) {
+ struct cxl_ep *ep_iter;
+ unsigned long index;
+ int found = 0;
+
+ cxl_rr->nr_eps--;
+ xa_for_each(&cxl_rr->endpoints, index, ep_iter) {
+ if (ep_iter->next == ep->next) {
+ found++;
+ break;
+ }
+ }
+ if (!found)
+ cxl_rr->nr_targets--;
+ }
+
+ if (cxl_rr->nr_eps == 0)
+ free_region_ref(cxl_rr);
+}
+
+static int check_last_peer(struct cxl_endpoint_decoder *cxled,
+ struct cxl_ep *ep, struct cxl_region_ref *cxl_rr,
+ int distance)
+{
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct cxl_region *cxlr = cxl_rr->region;
+ struct cxl_region_params *p = &cxlr->params;
+ struct cxl_endpoint_decoder *cxled_peer;
+ struct cxl_port *port = cxl_rr->port;
+ struct cxl_memdev *cxlmd_peer;
+ struct cxl_ep *ep_peer;
+ int pos = cxled->pos;
+
+ /*
+ * If this position wants to share a dport with the last endpoint mapped
+ * then that endpoint, at index 'position - distance', must also be
+ * mapped by this dport.
+ */
+ if (pos < distance) {
+ dev_dbg(&cxlr->dev, "%s:%s: cannot host %s:%s at %d\n",
+ dev_name(port->uport), dev_name(&port->dev),
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos);
+ return -ENXIO;
+ }
+ cxled_peer = p->targets[pos - distance];
+ cxlmd_peer = cxled_to_memdev(cxled_peer);
+ ep_peer = cxl_ep_load(port, cxlmd_peer);
+ if (ep->dport != ep_peer->dport) {
+ dev_dbg(&cxlr->dev,
+ "%s:%s: %s:%s pos %d mismatched peer %s:%s\n",
+ dev_name(port->uport), dev_name(&port->dev),
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos,
+ dev_name(&cxlmd_peer->dev),
+ dev_name(&cxled_peer->cxld.dev));
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int cxl_port_setup_targets(struct cxl_port *port,
+ struct cxl_region *cxlr,
+ struct cxl_endpoint_decoder *cxled)
+{
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
+ int parent_iw, parent_ig, ig, iw, rc, inc = 0, pos = cxled->pos;
+ struct cxl_port *parent_port = to_cxl_port(port->dev.parent);
+ struct cxl_region_ref *cxl_rr = cxl_rr_load(port, cxlr);
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct cxl_ep *ep = cxl_ep_load(port, cxlmd);
+ struct cxl_region_params *p = &cxlr->params;
+ struct cxl_decoder *cxld = cxl_rr->decoder;
+ struct cxl_switch_decoder *cxlsd;
+ u16 eig, peig;
+ u8 eiw, peiw;
+
+ /*
+ * While root level decoders support x3, x6, x12, switch level
+ * decoders only support powers of 2 up to x16.
+ */
+ if (!is_power_of_2(cxl_rr->nr_targets)) {
+ dev_dbg(&cxlr->dev, "%s:%s: invalid target count %d\n",
+ dev_name(port->uport), dev_name(&port->dev),
+ cxl_rr->nr_targets);
+ return -EINVAL;
+ }
+
+ cxlsd = to_cxl_switch_decoder(&cxld->dev);
+ if (cxl_rr->nr_targets_set) {
+ int i, distance;
+
+ distance = p->nr_targets / cxl_rr->nr_targets;
+ for (i = 0; i < cxl_rr->nr_targets_set; i++)
+ if (ep->dport == cxlsd->target[i]) {
+ rc = check_last_peer(cxled, ep, cxl_rr,
+ distance);
+ if (rc)
+ return rc;
+ goto out_target_set;
+ }
+ goto add_target;
+ }
+
+ if (is_cxl_root(parent_port)) {
+ parent_ig = cxlrd->cxlsd.cxld.interleave_granularity;
+ parent_iw = cxlrd->cxlsd.cxld.interleave_ways;
+ /*
+ * For purposes of address bit routing, use power-of-2 math for
+ * switch ports.
+ */
+ if (!is_power_of_2(parent_iw))
+ parent_iw /= 3;
+ } else {
+ struct cxl_region_ref *parent_rr;
+ struct cxl_decoder *parent_cxld;
+
+ parent_rr = cxl_rr_load(parent_port, cxlr);
+ parent_cxld = parent_rr->decoder;
+ parent_ig = parent_cxld->interleave_granularity;
+ parent_iw = parent_cxld->interleave_ways;
+ }
+
+ rc = granularity_to_cxl(parent_ig, &peig);
+ if (rc) {
+ dev_dbg(&cxlr->dev, "%s:%s: invalid parent granularity: %d\n",
+ dev_name(parent_port->uport),
+ dev_name(&parent_port->dev), parent_ig);
+ return rc;
+ }
+
+ rc = ways_to_cxl(parent_iw, &peiw);
+ if (rc) {
+ dev_dbg(&cxlr->dev, "%s:%s: invalid parent interleave: %d\n",
+ dev_name(parent_port->uport),
+ dev_name(&parent_port->dev), parent_iw);
+ return rc;
+ }
+
+ iw = cxl_rr->nr_targets;
+ rc = ways_to_cxl(iw, &eiw);
+ if (rc) {
+ dev_dbg(&cxlr->dev, "%s:%s: invalid port interleave: %d\n",
+ dev_name(port->uport), dev_name(&port->dev), iw);
+ return rc;
+ }
+
+ /*
+ * If @parent_port is masking address bits, pick the next unused address
+ * bit to route @port's targets.
+ */
+ if (parent_iw > 1 && cxl_rr->nr_targets > 1) {
+ u32 address_bit = max(peig + peiw, eiw + peig);
+
+ eig = address_bit - eiw + 1;
+ } else {
+ eiw = peiw;
+ eig = peig;
+ }
+
+ rc = cxl_to_granularity(eig, &ig);
+ if (rc) {
+ dev_dbg(&cxlr->dev, "%s:%s: invalid interleave: %d\n",
+ dev_name(port->uport), dev_name(&port->dev),
+ 256 << eig);
+ return rc;
+ }
+
+ cxld->interleave_ways = iw;
+ cxld->interleave_granularity = ig;
+ cxld->hpa_range = (struct range) {
+ .start = p->res->start,
+ .end = p->res->end,
+ };
+ dev_dbg(&cxlr->dev, "%s:%s iw: %d ig: %d\n", dev_name(port->uport),
+ dev_name(&port->dev), iw, ig);
+add_target:
+ if (cxl_rr->nr_targets_set == cxl_rr->nr_targets) {
+ dev_dbg(&cxlr->dev,
+ "%s:%s: targets full trying to add %s:%s at %d\n",
+ dev_name(port->uport), dev_name(&port->dev),
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos);
+ return -ENXIO;
+ }
+ cxlsd->target[cxl_rr->nr_targets_set] = ep->dport;
+ inc = 1;
+out_target_set:
+ cxl_rr->nr_targets_set += inc;
+ dev_dbg(&cxlr->dev, "%s:%s target[%d] = %s for %s:%s @ %d\n",
+ dev_name(port->uport), dev_name(&port->dev),
+ cxl_rr->nr_targets_set - 1, dev_name(ep->dport->dport),
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos);
+
+ return 0;
+}
+
+static void cxl_port_reset_targets(struct cxl_port *port,
+ struct cxl_region *cxlr)
+{
+ struct cxl_region_ref *cxl_rr = cxl_rr_load(port, cxlr);
+ struct cxl_decoder *cxld;
+
+ /*
+ * After the last endpoint has been detached the entire cxl_rr may now
+ * be gone.
+ */
+ if (!cxl_rr)
+ return;
+ cxl_rr->nr_targets_set = 0;
+
+ cxld = cxl_rr->decoder;
+ cxld->hpa_range = (struct range) {
+ .start = 0,
+ .end = -1,
+ };
+}
+
+static void cxl_region_teardown_targets(struct cxl_region *cxlr)
+{
+ struct cxl_region_params *p = &cxlr->params;
+ struct cxl_endpoint_decoder *cxled;
+ struct cxl_memdev *cxlmd;
+ struct cxl_port *iter;
+ struct cxl_ep *ep;
+ int i;
+
+ for (i = 0; i < p->nr_targets; i++) {
+ cxled = p->targets[i];
+ cxlmd = cxled_to_memdev(cxled);
+
+ iter = cxled_to_port(cxled);
+ while (!is_cxl_root(to_cxl_port(iter->dev.parent)))
+ iter = to_cxl_port(iter->dev.parent);
+
+ for (ep = cxl_ep_load(iter, cxlmd); iter;
+ iter = ep->next, ep = cxl_ep_load(iter, cxlmd))
+ cxl_port_reset_targets(iter, cxlr);
+ }
+}
+
+static int cxl_region_setup_targets(struct cxl_region *cxlr)
+{
+ struct cxl_region_params *p = &cxlr->params;
+ struct cxl_endpoint_decoder *cxled;
+ struct cxl_memdev *cxlmd;
+ struct cxl_port *iter;
+ struct cxl_ep *ep;
+ int i, rc;
+
+ for (i = 0; i < p->nr_targets; i++) {
+ cxled = p->targets[i];
+ cxlmd = cxled_to_memdev(cxled);
+
+ iter = cxled_to_port(cxled);
+ while (!is_cxl_root(to_cxl_port(iter->dev.parent)))
+ iter = to_cxl_port(iter->dev.parent);
+
+ /*
+ * Descend the topology tree programming targets while
+ * looking for conflicts.
+ */
+ for (ep = cxl_ep_load(iter, cxlmd); iter;
+ iter = ep->next, ep = cxl_ep_load(iter, cxlmd)) {
+ rc = cxl_port_setup_targets(iter, cxlr, cxled);
+ if (rc) {
+ cxl_region_teardown_targets(cxlr);
+ return rc;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int cxl_region_attach(struct cxl_region *cxlr,
+ struct cxl_endpoint_decoder *cxled, int pos)
+{
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct cxl_port *ep_port, *root_port, *iter;
+ struct cxl_region_params *p = &cxlr->params;
+ struct cxl_dport *dport;
+ int i, rc = -ENXIO;
+
+ if (cxled->mode == CXL_DECODER_DEAD) {
+ dev_dbg(&cxlr->dev, "%s dead\n", dev_name(&cxled->cxld.dev));
+ return -ENODEV;
+ }
+
+ /* all full of members, or interleave config not established? */
+ if (p->state > CXL_CONFIG_INTERLEAVE_ACTIVE) {
+ dev_dbg(&cxlr->dev, "region already active\n");
+ return -EBUSY;
+ } else if (p->state < CXL_CONFIG_INTERLEAVE_ACTIVE) {
+ dev_dbg(&cxlr->dev, "interleave config missing\n");
+ return -ENXIO;
+ }
+
+ if (pos < 0 || pos >= p->interleave_ways) {
+ dev_dbg(&cxlr->dev, "position %d out of range %d\n", pos,
+ p->interleave_ways);
+ return -ENXIO;
+ }
+
+ if (p->targets[pos] == cxled)
+ return 0;
+
+ if (p->targets[pos]) {
+ struct cxl_endpoint_decoder *cxled_target = p->targets[pos];
+ struct cxl_memdev *cxlmd_target = cxled_to_memdev(cxled_target);
+
+ dev_dbg(&cxlr->dev, "position %d already assigned to %s:%s\n",
+ pos, dev_name(&cxlmd_target->dev),
+ dev_name(&cxled_target->cxld.dev));
+ return -EBUSY;
+ }
+
+ for (i = 0; i < p->interleave_ways; i++) {
+ struct cxl_endpoint_decoder *cxled_target;
+ struct cxl_memdev *cxlmd_target;
+
+ cxled_target = p->targets[pos];
+ if (!cxled_target)
+ continue;
+
+ cxlmd_target = cxled_to_memdev(cxled_target);
+ if (cxlmd_target == cxlmd) {
+ dev_dbg(&cxlr->dev,
+ "%s already specified at position %d via: %s\n",
+ dev_name(&cxlmd->dev), pos,
+ dev_name(&cxled_target->cxld.dev));
+ return -EBUSY;
+ }
+ }
+
+ ep_port = cxled_to_port(cxled);
+ root_port = cxlrd_to_port(cxlrd);
+ dport = cxl_find_dport_by_dev(root_port, ep_port->host_bridge);
+ if (!dport) {
+ dev_dbg(&cxlr->dev, "%s:%s invalid target for %s\n",
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+ dev_name(cxlr->dev.parent));
+ return -ENXIO;
+ }
+
+ if (cxlrd->calc_hb(cxlrd, pos) != dport) {
+ dev_dbg(&cxlr->dev, "%s:%s invalid target position for %s\n",
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+ dev_name(&cxlrd->cxlsd.cxld.dev));
+ return -ENXIO;
+ }
+
+ if (cxled->cxld.target_type != cxlr->type) {
+ dev_dbg(&cxlr->dev, "%s:%s type mismatch: %d vs %d\n",
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+ cxled->cxld.target_type, cxlr->type);
+ return -ENXIO;
+ }
+
+ if (!cxled->dpa_res) {
+ dev_dbg(&cxlr->dev, "%s:%s: missing DPA allocation.\n",
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev));
+ return -ENXIO;
+ }
+
+ if (resource_size(cxled->dpa_res) * p->interleave_ways !=
+ resource_size(p->res)) {
+ dev_dbg(&cxlr->dev,
+ "%s:%s: decoder-size-%#llx * ways-%d != region-size-%#llx\n",
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+ (u64)resource_size(cxled->dpa_res), p->interleave_ways,
+ (u64)resource_size(p->res));
+ return -EINVAL;
+ }
+
+ for (iter = ep_port; !is_cxl_root(iter);
+ iter = to_cxl_port(iter->dev.parent)) {
+ rc = cxl_port_attach_region(iter, cxlr, cxled, pos);
+ if (rc)
+ goto err;
+ }
+
+ p->targets[pos] = cxled;
+ cxled->pos = pos;
+ p->nr_targets++;
+
+ if (p->nr_targets == p->interleave_ways) {
+ rc = cxl_region_setup_targets(cxlr);
+ if (rc)
+ goto err_decrement;
+ p->state = CXL_CONFIG_ACTIVE;
+ }
+
+ cxled->cxld.interleave_ways = p->interleave_ways;
+ cxled->cxld.interleave_granularity = p->interleave_granularity;
+ cxled->cxld.hpa_range = (struct range) {
+ .start = p->res->start,
+ .end = p->res->end,
+ };
+
+ return 0;
+
+err_decrement:
+ p->nr_targets--;
+err:
+ for (iter = ep_port; !is_cxl_root(iter);
+ iter = to_cxl_port(iter->dev.parent))
+ cxl_port_detach_region(iter, cxlr, cxled);
+ return rc;
+}
+
+static int cxl_region_detach(struct cxl_endpoint_decoder *cxled)
+{
+ struct cxl_port *iter, *ep_port = cxled_to_port(cxled);
+ struct cxl_region *cxlr = cxled->cxld.region;
+ struct cxl_region_params *p;
+ int rc = 0;
+
+ lockdep_assert_held_write(&cxl_region_rwsem);
+
+ if (!cxlr)
+ return 0;
+
+ p = &cxlr->params;
+ get_device(&cxlr->dev);
+
+ if (p->state > CXL_CONFIG_ACTIVE) {
+ /*
+ * TODO: tear down all impacted regions if a device is
+ * removed out of order
+ */
+ rc = cxl_region_decode_reset(cxlr, p->interleave_ways);
+ if (rc)
+ goto out;
+ p->state = CXL_CONFIG_ACTIVE;
+ }
+
+ for (iter = ep_port; !is_cxl_root(iter);
+ iter = to_cxl_port(iter->dev.parent))
+ cxl_port_detach_region(iter, cxlr, cxled);
+
+ if (cxled->pos < 0 || cxled->pos >= p->interleave_ways ||
+ p->targets[cxled->pos] != cxled) {
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+
+ dev_WARN_ONCE(&cxlr->dev, 1, "expected %s:%s at position %d\n",
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+ cxled->pos);
+ goto out;
+ }
+
+ if (p->state == CXL_CONFIG_ACTIVE) {
+ p->state = CXL_CONFIG_INTERLEAVE_ACTIVE;
+ cxl_region_teardown_targets(cxlr);
+ }
+ p->targets[cxled->pos] = NULL;
+ p->nr_targets--;
+ cxled->cxld.hpa_range = (struct range) {
+ .start = 0,
+ .end = -1,
+ };
+
+ /* notify the region driver that one of its targets has departed */
+ up_write(&cxl_region_rwsem);
+ device_release_driver(&cxlr->dev);
+ down_write(&cxl_region_rwsem);
+out:
+ put_device(&cxlr->dev);
+ return rc;
+}
+
+void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled)
+{
+ down_write(&cxl_region_rwsem);
+ cxled->mode = CXL_DECODER_DEAD;
+ cxl_region_detach(cxled);
+ up_write(&cxl_region_rwsem);
+}
+
+static int attach_target(struct cxl_region *cxlr, const char *decoder, int pos)
+{
+ struct device *dev;
+ int rc;
+
+ dev = bus_find_device_by_name(&cxl_bus_type, NULL, decoder);
+ if (!dev)
+ return -ENODEV;
+
+ if (!is_endpoint_decoder(dev)) {
+ put_device(dev);
+ return -EINVAL;
+ }
+
+ rc = down_write_killable(&cxl_region_rwsem);
+ if (rc)
+ goto out;
+ down_read(&cxl_dpa_rwsem);
+ rc = cxl_region_attach(cxlr, to_cxl_endpoint_decoder(dev), pos);
+ up_read(&cxl_dpa_rwsem);
+ up_write(&cxl_region_rwsem);
+out:
+ put_device(dev);
+ return rc;
+}
+
+static int detach_target(struct cxl_region *cxlr, int pos)
+{
+ struct cxl_region_params *p = &cxlr->params;
+ int rc;
+
+ rc = down_write_killable(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+
+ if (pos >= p->interleave_ways) {
+ dev_dbg(&cxlr->dev, "position %d out of range %d\n", pos,
+ p->interleave_ways);
+ rc = -ENXIO;
+ goto out;
+ }
+
+ if (!p->targets[pos]) {
+ rc = 0;
+ goto out;
+ }
+
+ rc = cxl_region_detach(p->targets[pos]);
+out:
+ up_write(&cxl_region_rwsem);
+ return rc;
+}
+
+static size_t store_targetN(struct cxl_region *cxlr, const char *buf, int pos,
+ size_t len)
+{
+ int rc;
+
+ if (sysfs_streq(buf, "\n"))
+ rc = detach_target(cxlr, pos);
+ else
+ rc = attach_target(cxlr, buf, pos);
+
+ if (rc < 0)
+ return rc;
+ return len;
+}
+
+#define TARGET_ATTR_RW(n) \
+static ssize_t target##n##_show( \
+ struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ return show_targetN(to_cxl_region(dev), buf, (n)); \
+} \
+static ssize_t target##n##_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t len) \
+{ \
+ return store_targetN(to_cxl_region(dev), buf, (n), len); \
+} \
+static DEVICE_ATTR_RW(target##n)
+
+TARGET_ATTR_RW(0);
+TARGET_ATTR_RW(1);
+TARGET_ATTR_RW(2);
+TARGET_ATTR_RW(3);
+TARGET_ATTR_RW(4);
+TARGET_ATTR_RW(5);
+TARGET_ATTR_RW(6);
+TARGET_ATTR_RW(7);
+TARGET_ATTR_RW(8);
+TARGET_ATTR_RW(9);
+TARGET_ATTR_RW(10);
+TARGET_ATTR_RW(11);
+TARGET_ATTR_RW(12);
+TARGET_ATTR_RW(13);
+TARGET_ATTR_RW(14);
+TARGET_ATTR_RW(15);
+
+static struct attribute *target_attrs[] = {
+ &dev_attr_target0.attr,
+ &dev_attr_target1.attr,
+ &dev_attr_target2.attr,
+ &dev_attr_target3.attr,
+ &dev_attr_target4.attr,
+ &dev_attr_target5.attr,
+ &dev_attr_target6.attr,
+ &dev_attr_target7.attr,
+ &dev_attr_target8.attr,
+ &dev_attr_target9.attr,
+ &dev_attr_target10.attr,
+ &dev_attr_target11.attr,
+ &dev_attr_target12.attr,
+ &dev_attr_target13.attr,
+ &dev_attr_target14.attr,
+ &dev_attr_target15.attr,
+ NULL,
+};
+
+static umode_t cxl_region_target_visible(struct kobject *kobj,
+ struct attribute *a, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct cxl_region *cxlr = to_cxl_region(dev);
+ struct cxl_region_params *p = &cxlr->params;
+
+ if (n < p->interleave_ways)
+ return a->mode;
+ return 0;
+}
+
+static const struct attribute_group cxl_region_target_group = {
+ .attrs = target_attrs,
+ .is_visible = cxl_region_target_visible,
+};
+
+static const struct attribute_group *get_cxl_region_target_group(void)
+{
+ return &cxl_region_target_group;
+}
+
+static const struct attribute_group *region_groups[] = {
+ &cxl_base_attribute_group,
+ &cxl_region_group,
+ &cxl_region_target_group,
+ NULL,
+};
+
+static void cxl_region_release(struct device *dev)
+{
+ struct cxl_region *cxlr = to_cxl_region(dev);
+
+ memregion_free(cxlr->id);
+ kfree(cxlr);
+}
+
+const struct device_type cxl_region_type = {
+ .name = "cxl_region",
+ .release = cxl_region_release,
+ .groups = region_groups
+};
+
+bool is_cxl_region(struct device *dev)
+{
+ return dev->type == &cxl_region_type;
+}
+EXPORT_SYMBOL_NS_GPL(is_cxl_region, CXL);
+
+static struct cxl_region *to_cxl_region(struct device *dev)
+{
+ if (dev_WARN_ONCE(dev, dev->type != &cxl_region_type,
+ "not a cxl_region device\n"))
+ return NULL;
+
+ return container_of(dev, struct cxl_region, dev);
+}
+
+static void unregister_region(void *dev)
+{
+ struct cxl_region *cxlr = to_cxl_region(dev);
+
+ device_del(dev);
+ cxl_region_iomem_release(cxlr);
+ put_device(dev);
+}
+
+static struct lock_class_key cxl_region_key;
+
+static struct cxl_region *cxl_region_alloc(struct cxl_root_decoder *cxlrd, int id)
+{
+ struct cxl_region *cxlr;
+ struct device *dev;
+
+ cxlr = kzalloc(sizeof(*cxlr), GFP_KERNEL);
+ if (!cxlr) {
+ memregion_free(id);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ dev = &cxlr->dev;
+ device_initialize(dev);
+ lockdep_set_class(&dev->mutex, &cxl_region_key);
+ dev->parent = &cxlrd->cxlsd.cxld.dev;
+ device_set_pm_not_required(dev);
+ dev->bus = &cxl_bus_type;
+ dev->type = &cxl_region_type;
+ cxlr->id = id;
+
+ return cxlr;
+}
+
+/**
+ * devm_cxl_add_region - Adds a region to a decoder
+ * @cxlrd: root decoder
+ * @id: memregion id to create, or memregion_free() on failure
+ * @mode: mode for the endpoint decoders of this region
+ * @type: select whether this is an expander or accelerator (type-2 or type-3)
+ *
+ * This is the second step of region initialization. Regions exist within an
+ * address space which is mapped by a @cxlrd.
+ *
+ * Return: 0 if the region was added to the @cxlrd, else returns negative error
+ * code. The region will be named "regionZ" where Z is the unique region number.
+ */
+static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd,
+ int id,
+ enum cxl_decoder_mode mode,
+ enum cxl_decoder_type type)
+{
+ struct cxl_port *port = to_cxl_port(cxlrd->cxlsd.cxld.dev.parent);
+ struct cxl_region *cxlr;
+ struct device *dev;
+ int rc;
+
+ cxlr = cxl_region_alloc(cxlrd, id);
+ if (IS_ERR(cxlr))
+ return cxlr;
+ cxlr->mode = mode;
+ cxlr->type = type;
+
+ dev = &cxlr->dev;
+ rc = dev_set_name(dev, "region%d", id);
+ if (rc)
+ goto err;
+
+ rc = device_add(dev);
+ if (rc)
+ goto err;
+
+ rc = devm_add_action_or_reset(port->uport, unregister_region, cxlr);
+ if (rc)
+ return ERR_PTR(rc);
+
+ dev_dbg(port->uport, "%s: created %s\n",
+ dev_name(&cxlrd->cxlsd.cxld.dev), dev_name(dev));
+ return cxlr;
+
+err:
+ put_device(dev);
+ return ERR_PTR(rc);
+}
+
+static ssize_t create_pmem_region_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+
+ return sysfs_emit(buf, "region%u\n", atomic_read(&cxlrd->region_id));
+}
+
+static ssize_t create_pmem_region_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+ struct cxl_region *cxlr;
+ int id, rc;
+
+ rc = sscanf(buf, "region%d\n", &id);
+ if (rc != 1)
+ return -EINVAL;
+
+ rc = memregion_alloc(GFP_KERNEL);
+ if (rc < 0)
+ return rc;
+
+ if (atomic_cmpxchg(&cxlrd->region_id, id, rc) != id) {
+ memregion_free(rc);
+ return -EBUSY;
+ }
+
+ cxlr = devm_cxl_add_region(cxlrd, id, CXL_DECODER_PMEM,
+ CXL_DECODER_EXPANDER);
+ if (IS_ERR(cxlr))
+ return PTR_ERR(cxlr);
+
+ return len;
+}
+DEVICE_ATTR_RW(create_pmem_region);
+
+static ssize_t region_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_decoder *cxld = to_cxl_decoder(dev);
+ ssize_t rc;
+
+ rc = down_read_interruptible(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+
+ if (cxld->region)
+ rc = sysfs_emit(buf, "%s\n", dev_name(&cxld->region->dev));
+ else
+ rc = sysfs_emit(buf, "\n");
+ up_read(&cxl_region_rwsem);
+
+ return rc;
+}
+DEVICE_ATTR_RO(region);
+
+static struct cxl_region *
+cxl_find_region_by_name(struct cxl_root_decoder *cxlrd, const char *name)
+{
+ struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
+ struct device *region_dev;
+
+ region_dev = device_find_child_by_name(&cxld->dev, name);
+ if (!region_dev)
+ return ERR_PTR(-ENODEV);
+
+ return to_cxl_region(region_dev);
+}
+
+static ssize_t delete_region_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+ struct cxl_port *port = to_cxl_port(dev->parent);
+ struct cxl_region *cxlr;
+
+ cxlr = cxl_find_region_by_name(cxlrd, buf);
+ if (IS_ERR(cxlr))
+ return PTR_ERR(cxlr);
+
+ devm_release_action(port->uport, unregister_region, cxlr);
+ put_device(&cxlr->dev);
+
+ return len;
+}
+DEVICE_ATTR_WO(delete_region);
+
+static void cxl_pmem_region_release(struct device *dev)
+{
+ struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev);
+ int i;
+
+ for (i = 0; i < cxlr_pmem->nr_mappings; i++) {
+ struct cxl_memdev *cxlmd = cxlr_pmem->mapping[i].cxlmd;
+
+ put_device(&cxlmd->dev);
+ }
+
+ kfree(cxlr_pmem);
+}
+
+static const struct attribute_group *cxl_pmem_region_attribute_groups[] = {
+ &cxl_base_attribute_group,
+ NULL,
+};
+
+const struct device_type cxl_pmem_region_type = {
+ .name = "cxl_pmem_region",
+ .release = cxl_pmem_region_release,
+ .groups = cxl_pmem_region_attribute_groups,
+};
+
+bool is_cxl_pmem_region(struct device *dev)
+{
+ return dev->type == &cxl_pmem_region_type;
+}
+EXPORT_SYMBOL_NS_GPL(is_cxl_pmem_region, CXL);
+
+struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev)
+{
+ if (dev_WARN_ONCE(dev, !is_cxl_pmem_region(dev),
+ "not a cxl_pmem_region device\n"))
+ return NULL;
+ return container_of(dev, struct cxl_pmem_region, dev);
+}
+EXPORT_SYMBOL_NS_GPL(to_cxl_pmem_region, CXL);
+
+static struct lock_class_key cxl_pmem_region_key;
+
+static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr)
+{
+ struct cxl_region_params *p = &cxlr->params;
+ struct cxl_pmem_region *cxlr_pmem;
+ struct device *dev;
+ int i;
+
+ down_read(&cxl_region_rwsem);
+ if (p->state != CXL_CONFIG_COMMIT) {
+ cxlr_pmem = ERR_PTR(-ENXIO);
+ goto out;
+ }
+
+ cxlr_pmem = kzalloc(struct_size(cxlr_pmem, mapping, p->nr_targets),
+ GFP_KERNEL);
+ if (!cxlr_pmem) {
+ cxlr_pmem = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ cxlr_pmem->hpa_range.start = p->res->start;
+ cxlr_pmem->hpa_range.end = p->res->end;
+
+ /* Snapshot the region configuration underneath the cxl_region_rwsem */
+ cxlr_pmem->nr_mappings = p->nr_targets;
+ for (i = 0; i < p->nr_targets; i++) {
+ struct cxl_endpoint_decoder *cxled = p->targets[i];
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i];
+
+ m->cxlmd = cxlmd;
+ get_device(&cxlmd->dev);
+ m->start = cxled->dpa_res->start;
+ m->size = resource_size(cxled->dpa_res);
+ m->position = i;
+ }
+
+ dev = &cxlr_pmem->dev;
+ cxlr_pmem->cxlr = cxlr;
+ device_initialize(dev);
+ lockdep_set_class(&dev->mutex, &cxl_pmem_region_key);
+ device_set_pm_not_required(dev);
+ dev->parent = &cxlr->dev;
+ dev->bus = &cxl_bus_type;
+ dev->type = &cxl_pmem_region_type;
+out:
+ up_read(&cxl_region_rwsem);
+
+ return cxlr_pmem;
+}
+
+static void cxlr_pmem_unregister(void *dev)
+{
+ device_unregister(dev);
+}
+
+/**
+ * devm_cxl_add_pmem_region() - add a cxl_region-to-nd_region bridge
+ * @cxlr: parent CXL region for this pmem region bridge device
+ *
+ * Return: 0 on success negative error code on failure.
+ */
+static int devm_cxl_add_pmem_region(struct cxl_region *cxlr)
+{
+ struct cxl_pmem_region *cxlr_pmem;
+ struct device *dev;
+ int rc;
+
+ cxlr_pmem = cxl_pmem_region_alloc(cxlr);
+ if (IS_ERR(cxlr_pmem))
+ return PTR_ERR(cxlr_pmem);
+
+ dev = &cxlr_pmem->dev;
+ rc = dev_set_name(dev, "pmem_region%d", cxlr->id);
+ if (rc)
+ goto err;
+
+ rc = device_add(dev);
+ if (rc)
+ goto err;
+
+ dev_dbg(&cxlr->dev, "%s: register %s\n", dev_name(dev->parent),
+ dev_name(dev));
+
+ return devm_add_action_or_reset(&cxlr->dev, cxlr_pmem_unregister, dev);
+
+err:
+ put_device(dev);
+ return rc;
+}
+
+static int cxl_region_probe(struct device *dev)
+{
+ struct cxl_region *cxlr = to_cxl_region(dev);
+ struct cxl_region_params *p = &cxlr->params;
+ int rc;
+
+ rc = down_read_interruptible(&cxl_region_rwsem);
+ if (rc) {
+ dev_dbg(&cxlr->dev, "probe interrupted\n");
+ return rc;
+ }
+
+ if (p->state < CXL_CONFIG_COMMIT) {
+ dev_dbg(&cxlr->dev, "config state: %d\n", p->state);
+ rc = -ENXIO;
+ }
+
+ /*
+ * From this point on any path that changes the region's state away from
+ * CXL_CONFIG_COMMIT is also responsible for releasing the driver.
+ */
+ up_read(&cxl_region_rwsem);
+
+ switch (cxlr->mode) {
+ case CXL_DECODER_PMEM:
+ return devm_cxl_add_pmem_region(cxlr);
+ default:
+ dev_dbg(&cxlr->dev, "unsupported region mode: %d\n",
+ cxlr->mode);
+ return -ENXIO;
+ }
+}
+
+static struct cxl_driver cxl_region_driver = {
+ .name = "cxl_region",
+ .probe = cxl_region_probe,
+ .id = CXL_DEVICE_REGION,
+};
+
+int cxl_region_init(void)
+{
+ return cxl_driver_register(&cxl_region_driver);
+}
+
+void cxl_region_exit(void)
+{
+ cxl_driver_unregister(&cxl_region_driver);
+}
+
+MODULE_IMPORT_NS(CXL);
+MODULE_ALIAS_CXL(CXL_DEVICE_REGION);
#include <linux/libnvdimm.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
+#include <linux/log2.h>
#include <linux/io.h>
/**
#define CXL_HDM_DECODER0_CTRL_LOCK BIT(8)
#define CXL_HDM_DECODER0_CTRL_COMMIT BIT(9)
#define CXL_HDM_DECODER0_CTRL_COMMITTED BIT(10)
+#define CXL_HDM_DECODER0_CTRL_COMMIT_ERROR BIT(11)
#define CXL_HDM_DECODER0_CTRL_TYPE BIT(12)
#define CXL_HDM_DECODER0_TL_LOW(i) (0x20 * (i) + 0x24)
#define CXL_HDM_DECODER0_TL_HIGH(i) (0x20 * (i) + 0x28)
+#define CXL_HDM_DECODER0_SKIP_LOW(i) CXL_HDM_DECODER0_TL_LOW(i)
+#define CXL_HDM_DECODER0_SKIP_HIGH(i) CXL_HDM_DECODER0_TL_HIGH(i)
static inline int cxl_hdm_decoder_count(u32 cap_hdr)
{
return val ? val * 2 : 1;
}
+/* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */
+static inline int cxl_to_granularity(u16 ig, unsigned int *val)
+{
+ if (ig > 6)
+ return -EINVAL;
+ *val = 256 << ig;
+ return 0;
+}
+
+/* Encode defined in CXL ECN "3, 6, 12 and 16-way memory Interleaving" */
+static inline int cxl_to_ways(u8 eniw, unsigned int *val)
+{
+ switch (eniw) {
+ case 0 ... 4:
+ *val = 1 << eniw;
+ break;
+ case 8 ... 10:
+ *val = 3 << (eniw - 8);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static inline int granularity_to_cxl(int g, u16 *ig)
+{
+ if (g > SZ_16K || g < 256 || !is_power_of_2(g))
+ return -EINVAL;
+ *ig = ilog2(g) - 8;
+ return 0;
+}
+
+static inline int ways_to_cxl(unsigned int ways, u8 *iw)
+{
+ if (ways > 16)
+ return -EINVAL;
+ if (is_power_of_2(ways)) {
+ *iw = ilog2(ways);
+ return 0;
+ }
+ if (ways % 3)
+ return -EINVAL;
+ ways /= 3;
+ if (!is_power_of_2(ways))
+ return -EINVAL;
+ *iw = ilog2(ways) + 8;
+ return 0;
+}
+
/* CXL 2.0 8.2.8.1 Device Capabilities Array Register */
#define CXLDEV_CAP_ARRAY_OFFSET 0x0
#define CXLDEV_CAP_ARRAY_CAP_ID 0
*/
#define CXL_DECODER_MAX_INTERLEAVE 16
+#define CXL_DECODER_MIN_GRANULARITY 256
+
/**
- * struct cxl_decoder - CXL address range decode configuration
+ * struct cxl_decoder - Common CXL HDM Decoder Attributes
* @dev: this decoder's device
* @id: kernel device name id
- * @platform_res: address space resources considered by root decoder
- * @decoder_range: address space resources considered by midlevel decoder
+ * @hpa_range: Host physical address range mapped by this decoder
* @interleave_ways: number of cxl_dports in this decode
* @interleave_granularity: data stride per dport
* @target_type: accelerator vs expander (type2 vs type3) selector
+ * @region: currently assigned region for this decoder
* @flags: memory type capabilities and locking
- * @target_lock: coordinate coherent reads of the target list
- * @nr_targets: number of elements in @target
- * @target: active ordered target list in current decoder configuration
- */
+ * @commit: device/decoder-type specific callback to commit settings to hw
+ * @reset: device/decoder-type specific callback to reset hw settings
+*/
struct cxl_decoder {
struct device dev;
int id;
- union {
- struct resource platform_res;
- struct range decoder_range;
- };
+ struct range hpa_range;
int interleave_ways;
int interleave_granularity;
enum cxl_decoder_type target_type;
+ struct cxl_region *region;
unsigned long flags;
+ int (*commit)(struct cxl_decoder *cxld);
+ int (*reset)(struct cxl_decoder *cxld);
+};
+
+/*
+ * CXL_DECODER_DEAD prevents endpoints from being reattached to regions
+ * while cxld_unregister() is running
+ */
+enum cxl_decoder_mode {
+ CXL_DECODER_NONE,
+ CXL_DECODER_RAM,
+ CXL_DECODER_PMEM,
+ CXL_DECODER_MIXED,
+ CXL_DECODER_DEAD,
+};
+
+/**
+ * struct cxl_endpoint_decoder - Endpoint / SPA to DPA decoder
+ * @cxld: base cxl_decoder_object
+ * @dpa_res: actively claimed DPA span of this decoder
+ * @skip: offset into @dpa_res where @cxld.hpa_range maps
+ * @mode: which memory type / access-mode-partition this decoder targets
+ * @pos: interleave position in @cxld.region
+ */
+struct cxl_endpoint_decoder {
+ struct cxl_decoder cxld;
+ struct resource *dpa_res;
+ resource_size_t skip;
+ enum cxl_decoder_mode mode;
+ int pos;
+};
+
+/**
+ * struct cxl_switch_decoder - Switch specific CXL HDM Decoder
+ * @cxld: base cxl_decoder object
+ * @target_lock: coordinate coherent reads of the target list
+ * @nr_targets: number of elements in @target
+ * @target: active ordered target list in current decoder configuration
+ *
+ * The 'switch' decoder type represents the decoder instances of cxl_port's that
+ * route from the root of a CXL memory decode topology to the endpoints. They
+ * come in two flavors, root-level decoders, statically defined by platform
+ * firmware, and mid-level decoders, where interleave-granularity,
+ * interleave-width, and the target list are mutable.
+ */
+struct cxl_switch_decoder {
+ struct cxl_decoder cxld;
seqlock_t target_lock;
int nr_targets;
struct cxl_dport *target[];
};
+/**
+ * struct cxl_root_decoder - Static platform CXL address decoder
+ * @res: host / parent resource for region allocations
+ * @region_id: region id for next region provisioning event
+ * @calc_hb: which host bridge covers the n'th position by granularity
+ * @cxlsd: base cxl switch decoder
+ */
+struct cxl_root_decoder {
+ struct resource *res;
+ atomic_t region_id;
+ struct cxl_dport *(*calc_hb)(struct cxl_root_decoder *cxlrd, int pos);
+ struct cxl_switch_decoder cxlsd;
+};
+
+/*
+ * enum cxl_config_state - State machine for region configuration
+ * @CXL_CONFIG_IDLE: Any sysfs attribute can be written freely
+ * @CXL_CONFIG_INTERLEAVE_ACTIVE: region size has been set, no more
+ * changes to interleave_ways or interleave_granularity
+ * @CXL_CONFIG_ACTIVE: All targets have been added the region is now
+ * active
+ * @CXL_CONFIG_RESET_PENDING: see commit_store()
+ * @CXL_CONFIG_COMMIT: Soft-config has been committed to hardware
+ */
+enum cxl_config_state {
+ CXL_CONFIG_IDLE,
+ CXL_CONFIG_INTERLEAVE_ACTIVE,
+ CXL_CONFIG_ACTIVE,
+ CXL_CONFIG_RESET_PENDING,
+ CXL_CONFIG_COMMIT,
+};
+
+/**
+ * struct cxl_region_params - region settings
+ * @state: allow the driver to lockdown further parameter changes
+ * @uuid: unique id for persistent regions
+ * @interleave_ways: number of endpoints in the region
+ * @interleave_granularity: capacity each endpoint contributes to a stripe
+ * @res: allocated iomem capacity for this region
+ * @targets: active ordered targets in current decoder configuration
+ * @nr_targets: number of targets
+ *
+ * State transitions are protected by the cxl_region_rwsem
+ */
+struct cxl_region_params {
+ enum cxl_config_state state;
+ uuid_t uuid;
+ int interleave_ways;
+ int interleave_granularity;
+ struct resource *res;
+ struct cxl_endpoint_decoder *targets[CXL_DECODER_MAX_INTERLEAVE];
+ int nr_targets;
+};
+
+/**
+ * struct cxl_region - CXL region
+ * @dev: This region's device
+ * @id: This region's id. Id is globally unique across all regions
+ * @mode: Endpoint decoder allocation / access mode
+ * @type: Endpoint decoder target type
+ * @params: active + config params for the region
+ */
+struct cxl_region {
+ struct device dev;
+ int id;
+ enum cxl_decoder_mode mode;
+ enum cxl_decoder_type type;
+ struct cxl_region_params params;
+};
+
/**
* enum cxl_nvdimm_brige_state - state machine for managing bus rescans
* @CXL_NVB_NEW: Set at bridge create and after cxl_pmem_wq is destroyed
struct cxl_nvdimm {
struct device dev;
struct cxl_memdev *cxlmd;
- struct nvdimm *nvdimm;
+ struct cxl_nvdimm_bridge *bridge;
+ struct cxl_pmem_region *region;
+};
+
+struct cxl_pmem_region_mapping {
+ struct cxl_memdev *cxlmd;
+ struct cxl_nvdimm *cxl_nvd;
+ u64 start;
+ u64 size;
+ int position;
+};
+
+struct cxl_pmem_region {
+ struct device dev;
+ struct cxl_region *cxlr;
+ struct nd_region *nd_region;
+ struct cxl_nvdimm_bridge *bridge;
+ struct range hpa_range;
+ int nr_mappings;
+ struct cxl_pmem_region_mapping mapping[];
};
/**
* decode hierarchy.
* @dev: this port's device
* @uport: PCI or platform device implementing the upstream port capability
+ * @host_bridge: Shortcut to the platform attach point for this port
* @id: id for port device-name
* @dports: cxl_dport instances referenced by decoders
* @endpoints: cxl_ep instances, endpoints that are a descendant of this port
+ * @regions: cxl_region_ref instances, regions mapped by this port
+ * @parent_dport: dport that points to this port in the parent
* @decoder_ida: allocator for decoder ids
+ * @hdm_end: track last allocated HDM decoder instance for allocation ordering
+ * @commit_end: cursor to track highest committed decoder for commit ordering
* @component_reg_phys: component register capability base address (optional)
* @dead: last ep has been removed, force port re-creation
* @depth: How deep this port is relative to the root. depth 0 is the root.
+ * @cdat: Cached CDAT data
+ * @cdat_available: Should a CDAT attribute be available in sysfs
*/
struct cxl_port {
struct device dev;
struct device *uport;
+ struct device *host_bridge;
int id;
- struct list_head dports;
- struct list_head endpoints;
+ struct xarray dports;
+ struct xarray endpoints;
+ struct xarray regions;
+ struct cxl_dport *parent_dport;
struct ida decoder_ida;
+ int hdm_end;
+ int commit_end;
resource_size_t component_reg_phys;
bool dead;
unsigned int depth;
+ struct cxl_cdat {
+ void *table;
+ size_t length;
+ } cdat;
+ bool cdat_available;
};
+static inline struct cxl_dport *
+cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev)
+{
+ return xa_load(&port->dports, (unsigned long)dport_dev);
+}
+
/**
* struct cxl_dport - CXL downstream port
* @dport: PCI bridge or firmware device representing the downstream link
* @port_id: unique hardware identifier for dport in decoder target list
* @component_reg_phys: downstream port component registers
* @port: reference to cxl_port that contains this downstream port
- * @list: node for a cxl_port's list of cxl_dport instances
*/
struct cxl_dport {
struct device *dport;
int port_id;
resource_size_t component_reg_phys;
struct cxl_port *port;
- struct list_head list;
};
/**
* struct cxl_ep - track an endpoint's interest in a port
* @ep: device that hosts a generic CXL endpoint (expander or accelerator)
- * @list: node on port->endpoints list
+ * @dport: which dport routes to this endpoint on @port
+ * @next: cxl switch port across the link attached to @dport NULL if
+ * attached to an endpoint
*/
struct cxl_ep {
struct device *ep;
- struct list_head list;
+ struct cxl_dport *dport;
+ struct cxl_port *next;
+};
+
+/**
+ * struct cxl_region_ref - track a region's interest in a port
+ * @port: point in topology to install this reference
+ * @decoder: decoder assigned for @region in @port
+ * @region: region for this reference
+ * @endpoints: cxl_ep references for region members beneath @port
+ * @nr_targets_set: track how many targets have been programmed during setup
+ * @nr_eps: number of endpoints beneath @port
+ * @nr_targets: number of distinct targets needed to reach @nr_eps
+ */
+struct cxl_region_ref {
+ struct cxl_port *port;
+ struct cxl_decoder *decoder;
+ struct cxl_region *region;
+ struct xarray endpoints;
+ int nr_targets_set;
+ int nr_eps;
+ int nr_targets;
};
/*
struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port);
struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
resource_size_t component_reg_phys,
- struct cxl_port *parent_port);
+ struct cxl_dport *parent_dport);
+int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd,
+ struct cxl_dport *parent_dport);
struct cxl_port *find_cxl_root(struct device *dev);
int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
int cxl_bus_rescan(void);
-struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd);
+struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd,
+ struct cxl_dport **dport);
bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd);
struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port,
struct device *dport, int port_id,
resource_size_t component_reg_phys);
-struct cxl_dport *cxl_find_dport_by_dev(struct cxl_port *port,
- const struct device *dev);
struct cxl_decoder *to_cxl_decoder(struct device *dev);
+struct cxl_root_decoder *to_cxl_root_decoder(struct device *dev);
+struct cxl_endpoint_decoder *to_cxl_endpoint_decoder(struct device *dev);
bool is_root_decoder(struct device *dev);
bool is_endpoint_decoder(struct device *dev);
-bool is_cxl_decoder(struct device *dev);
-struct cxl_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
- unsigned int nr_targets);
-struct cxl_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
- unsigned int nr_targets);
+struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
+ unsigned int nr_targets);
+struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
+ unsigned int nr_targets);
int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map);
-struct cxl_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port);
+struct cxl_endpoint_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port);
int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map);
int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld);
int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint);
int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm);
int devm_cxl_add_passthrough_decoder(struct cxl_port *port);
+bool is_cxl_region(struct device *dev);
+
extern struct bus_type cxl_bus_type;
struct cxl_driver {
#define CXL_DEVICE_PORT 3
#define CXL_DEVICE_ROOT 4
#define CXL_DEVICE_MEMORY_EXPANDER 5
+#define CXL_DEVICE_REGION 6
+#define CXL_DEVICE_PMEM_REGION 7
#define MODULE_ALIAS_CXL(type) MODULE_ALIAS("cxl:t" __stringify(type) "*")
#define CXL_MODALIAS_FMT "cxl:t%d"
bool is_cxl_nvdimm(struct device *dev);
bool is_cxl_nvdimm_bridge(struct device *dev);
int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd);
-struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd);
+struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *dev);
+
+#ifdef CONFIG_CXL_REGION
+bool is_cxl_pmem_region(struct device *dev);
+struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev);
+#else
+static inline bool is_cxl_pmem_region(struct device *dev)
+{
+ return false;
+}
+static inline struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev)
+{
+ return NULL;
+}
+#endif
/*
* Unit test builds overrides this to __weak, find the 'strong' version
return container_of(dev, struct cxl_memdev, dev);
}
+static inline struct cxl_port *cxled_to_port(struct cxl_endpoint_decoder *cxled)
+{
+ return to_cxl_port(cxled->cxld.dev.parent);
+}
+
+static inline struct cxl_port *cxlrd_to_port(struct cxl_root_decoder *cxlrd)
+{
+ return to_cxl_port(cxlrd->cxlsd.cxld.dev.parent);
+}
+
+static inline struct cxl_memdev *
+cxled_to_memdev(struct cxl_endpoint_decoder *cxled)
+{
+ struct cxl_port *port = to_cxl_port(cxled->cxld.dev.parent);
+
+ return to_cxl_memdev(port->uport);
+}
+
bool is_cxl_memdev(struct device *dev);
static inline bool is_cxl_endpoint(struct cxl_port *port)
{
* @firmware_version: Firmware version for the memory device.
* @enabled_cmds: Hardware commands found enabled in CEL.
* @exclusive_cmds: Commands that are kernel-internal only
- * @pmem_range: Active Persistent memory capacity configuration
- * @ram_range: Active Volatile memory capacity configuration
+ * @dpa_res: Overall DPA resource tree for the device
+ * @pmem_res: Active Persistent memory capacity configuration
+ * @ram_res: Active Volatile memory capacity configuration
* @total_bytes: sum of all possible capacities
* @volatile_only_bytes: hard volatile capacity
* @persistent_only_bytes: hard persistent capacity
* @component_reg_phys: register base of component registers
* @info: Cached DVSEC information about the device.
* @serial: PCIe Device Serial Number
+ * @doe_mbs: PCI DOE mailbox array
* @mbox_send: @dev specific transport for transmitting mailbox commands
*
* See section 8.2.9.5.2 Capacity Configuration and Label Storage for
DECLARE_BITMAP(enabled_cmds, CXL_MEM_COMMAND_ID_MAX);
DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX);
- struct range pmem_range;
- struct range ram_range;
+ struct resource dpa_res;
+ struct resource pmem_res;
+ struct resource ram_res;
u64 total_bytes;
u64 volatile_only_bytes;
u64 persistent_only_bytes;
resource_size_t component_reg_phys;
u64 serial;
+ struct xarray doe_mbs;
+
int (*mbox_send)(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd);
};
u8 qos_telemetry_caps;
} __packed;
+struct cxl_mbox_get_partition_info {
+ __le64 active_volatile_cap;
+ __le64 active_persistent_cap;
+ __le64 next_volatile_cap;
+ __le64 next_persistent_cap;
+} __packed;
+
struct cxl_mbox_get_lsa {
__le32 offset;
__le32 length;
unsigned int interleave_mask;
struct cxl_port *port;
};
+
+struct seq_file;
+struct dentry *cxl_debugfs_create_dir(const char *dir);
+void cxl_dpa_debug(struct seq_file *file, struct cxl_dev_state *cxlds);
#endif /* __CXL_MEM_H__ */
int devm_cxl_port_enumerate_dports(struct cxl_port *port);
struct cxl_dev_state;
int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm);
+void read_cdat_data(struct cxl_port *port);
#endif /* __CXL_PCI_H__ */
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
+#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
* in higher level operations.
*/
-static int create_endpoint(struct cxl_memdev *cxlmd,
- struct cxl_port *parent_port)
+static void enable_suspend(void *data)
{
- struct cxl_dev_state *cxlds = cxlmd->cxlds;
- struct cxl_port *endpoint;
- int rc;
+ cxl_mem_active_dec();
+}
- endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev,
- cxlds->component_reg_phys, parent_port);
- if (IS_ERR(endpoint))
- return PTR_ERR(endpoint);
+static void remove_debugfs(void *dentry)
+{
+ debugfs_remove_recursive(dentry);
+}
- dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev));
+static int cxl_mem_dpa_show(struct seq_file *file, void *data)
+{
+ struct device *dev = file->private;
+ struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
- rc = cxl_endpoint_autoremove(cxlmd, endpoint);
- if (rc)
- return rc;
-
- if (!endpoint->dev.driver) {
- dev_err(&cxlmd->dev, "%s failed probe\n",
- dev_name(&endpoint->dev));
- return -ENXIO;
- }
+ cxl_dpa_debug(file, cxlmd->cxlds);
return 0;
}
-static void enable_suspend(void *data)
-{
- cxl_mem_active_dec();
-}
-
static int cxl_mem_probe(struct device *dev)
{
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
struct cxl_port *parent_port;
+ struct cxl_dport *dport;
+ struct dentry *dentry;
int rc;
/*
if (work_pending(&cxlmd->detach_work))
return -EBUSY;
+ dentry = cxl_debugfs_create_dir(dev_name(dev));
+ debugfs_create_devm_seqfile(dev, "dpamem", dentry, cxl_mem_dpa_show);
+ rc = devm_add_action_or_reset(dev, remove_debugfs, dentry);
+ if (rc)
+ return rc;
+
rc = devm_cxl_enumerate_ports(cxlmd);
if (rc)
return rc;
- parent_port = cxl_mem_find_port(cxlmd);
+ parent_port = cxl_mem_find_port(cxlmd, &dport);
if (!parent_port) {
dev_err(dev, "CXL port topology not found\n");
return -ENXIO;
goto unlock;
}
- rc = create_endpoint(cxlmd, parent_port);
+ rc = devm_cxl_add_endpoint(cxlmd, dport);
unlock:
device_unlock(&parent_port->dev);
put_device(&parent_port->dev);
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/pci.h>
+#include <linux/pci-doe.h>
#include <linux/io.h>
#include "cxlmem.h"
#include "cxlpci.h"
return rc;
}
+static void cxl_pci_destroy_doe(void *mbs)
+{
+ xa_destroy(mbs);
+}
+
+static void devm_cxl_pci_create_doe(struct cxl_dev_state *cxlds)
+{
+ struct device *dev = cxlds->dev;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ u16 off = 0;
+
+ xa_init(&cxlds->doe_mbs);
+ if (devm_add_action(&pdev->dev, cxl_pci_destroy_doe, &cxlds->doe_mbs)) {
+ dev_err(dev, "Failed to create XArray for DOE's\n");
+ return;
+ }
+
+ /*
+ * Mailbox creation is best effort. Higher layers must determine if
+ * the lack of a mailbox for their protocol is a device failure or not.
+ */
+ pci_doe_for_each_off(pdev, off) {
+ struct pci_doe_mb *doe_mb;
+
+ doe_mb = pcim_doe_create_mb(pdev, off);
+ if (IS_ERR(doe_mb)) {
+ dev_err(dev, "Failed to create MB object for MB @ %x\n",
+ off);
+ continue;
+ }
+
+ if (xa_insert(&cxlds->doe_mbs, off, doe_mb, GFP_KERNEL)) {
+ dev_err(dev, "xa_insert failed to insert MB @ %x\n",
+ off);
+ continue;
+ }
+
+ dev_dbg(dev, "Created DOE mailbox @%x\n", off);
+ }
+}
+
static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct cxl_register_map map;
cxlds->component_reg_phys = cxl_regmap_to_base(pdev, &map);
+ devm_cxl_pci_create_doe(cxlds);
+
rc = cxl_pci_setup_mailbox(cxlds);
if (rc)
return rc;
if (IS_ERR(cxlmd))
return PTR_ERR(cxlmd);
- if (range_len(&cxlds->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM))
+ if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM))
rc = devm_cxl_add_nvdimm(&pdev->dev, cxlmd);
return rc;
#include <linux/ndctl.h>
#include <linux/async.h>
#include <linux/slab.h>
+#include <linux/nd.h>
#include "cxlmem.h"
#include "cxl.h"
static void unregister_nvdimm(void *nvdimm)
{
+ struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
+ struct cxl_nvdimm_bridge *cxl_nvb = cxl_nvd->bridge;
+ struct cxl_pmem_region *cxlr_pmem;
+
+ device_lock(&cxl_nvb->dev);
+ cxlr_pmem = cxl_nvd->region;
+ dev_set_drvdata(&cxl_nvd->dev, NULL);
+ cxl_nvd->region = NULL;
+ device_unlock(&cxl_nvb->dev);
+
+ if (cxlr_pmem) {
+ device_release_driver(&cxlr_pmem->dev);
+ put_device(&cxlr_pmem->dev);
+ }
+
nvdimm_delete(nvdimm);
+ cxl_nvd->bridge = NULL;
}
static int cxl_nvdimm_probe(struct device *dev)
struct nvdimm *nvdimm;
int rc;
- cxl_nvb = cxl_find_nvdimm_bridge(cxl_nvd);
+ cxl_nvb = cxl_find_nvdimm_bridge(dev);
if (!cxl_nvb)
return -ENXIO;
}
dev_set_drvdata(dev, nvdimm);
+ cxl_nvd->bridge = cxl_nvb;
rc = devm_add_action_or_reset(dev, unregister_nvdimm, nvdimm);
out:
device_unlock(&cxl_nvb->dev);
return cxl_nvb->nvdimm_bus != NULL;
}
-static int cxl_nvdimm_release_driver(struct device *dev, void *data)
+static int cxl_nvdimm_release_driver(struct device *dev, void *cxl_nvb)
{
+ struct cxl_nvdimm *cxl_nvd;
+
if (!is_cxl_nvdimm(dev))
return 0;
+
+ cxl_nvd = to_cxl_nvdimm(dev);
+ if (cxl_nvd->bridge != cxl_nvb)
+ return 0;
+
device_release_driver(dev);
return 0;
}
-static void offline_nvdimm_bus(struct nvdimm_bus *nvdimm_bus)
+static int cxl_pmem_region_release_driver(struct device *dev, void *cxl_nvb)
+{
+ struct cxl_pmem_region *cxlr_pmem;
+
+ if (!is_cxl_pmem_region(dev))
+ return 0;
+
+ cxlr_pmem = to_cxl_pmem_region(dev);
+ if (cxlr_pmem->bridge != cxl_nvb)
+ return 0;
+
+ device_release_driver(dev);
+ return 0;
+}
+
+static void offline_nvdimm_bus(struct cxl_nvdimm_bridge *cxl_nvb,
+ struct nvdimm_bus *nvdimm_bus)
{
if (!nvdimm_bus)
return;
* nvdimm_bus_unregister() rips the nvdimm objects out from
* underneath them.
*/
- bus_for_each_dev(&cxl_bus_type, NULL, NULL, cxl_nvdimm_release_driver);
+ bus_for_each_dev(&cxl_bus_type, NULL, cxl_nvb,
+ cxl_pmem_region_release_driver);
+ bus_for_each_dev(&cxl_bus_type, NULL, cxl_nvb,
+ cxl_nvdimm_release_driver);
nvdimm_bus_unregister(nvdimm_bus);
}
dev_dbg(&cxl_nvb->dev, "rescan: %d\n", rc);
}
- offline_nvdimm_bus(victim_bus);
+ offline_nvdimm_bus(cxl_nvb, victim_bus);
put_device(&cxl_nvb->dev);
}
.id = CXL_DEVICE_NVDIMM_BRIDGE,
};
+static int match_cxl_nvdimm(struct device *dev, void *data)
+{
+ return is_cxl_nvdimm(dev);
+}
+
+static void unregister_nvdimm_region(void *nd_region)
+{
+ struct cxl_nvdimm_bridge *cxl_nvb;
+ struct cxl_pmem_region *cxlr_pmem;
+ int i;
+
+ cxlr_pmem = nd_region_provider_data(nd_region);
+ cxl_nvb = cxlr_pmem->bridge;
+ device_lock(&cxl_nvb->dev);
+ for (i = 0; i < cxlr_pmem->nr_mappings; i++) {
+ struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i];
+ struct cxl_nvdimm *cxl_nvd = m->cxl_nvd;
+
+ if (cxl_nvd->region) {
+ put_device(&cxlr_pmem->dev);
+ cxl_nvd->region = NULL;
+ }
+ }
+ device_unlock(&cxl_nvb->dev);
+
+ nvdimm_region_delete(nd_region);
+}
+
+static void cxlr_pmem_remove_resource(void *res)
+{
+ remove_resource(res);
+}
+
+struct cxl_pmem_region_info {
+ u64 offset;
+ u64 serial;
+};
+
+static int cxl_pmem_region_probe(struct device *dev)
+{
+ struct nd_mapping_desc mappings[CXL_DECODER_MAX_INTERLEAVE];
+ struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev);
+ struct cxl_region *cxlr = cxlr_pmem->cxlr;
+ struct cxl_pmem_region_info *info = NULL;
+ struct cxl_nvdimm_bridge *cxl_nvb;
+ struct nd_interleave_set *nd_set;
+ struct nd_region_desc ndr_desc;
+ struct cxl_nvdimm *cxl_nvd;
+ struct nvdimm *nvdimm;
+ struct resource *res;
+ int rc, i = 0;
+
+ cxl_nvb = cxl_find_nvdimm_bridge(&cxlr_pmem->mapping[0].cxlmd->dev);
+ if (!cxl_nvb) {
+ dev_dbg(dev, "bridge not found\n");
+ return -ENXIO;
+ }
+ cxlr_pmem->bridge = cxl_nvb;
+
+ device_lock(&cxl_nvb->dev);
+ if (!cxl_nvb->nvdimm_bus) {
+ dev_dbg(dev, "nvdimm bus not found\n");
+ rc = -ENXIO;
+ goto err;
+ }
+
+ memset(&mappings, 0, sizeof(mappings));
+ memset(&ndr_desc, 0, sizeof(ndr_desc));
+
+ res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
+ if (!res) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ res->name = "Persistent Memory";
+ res->start = cxlr_pmem->hpa_range.start;
+ res->end = cxlr_pmem->hpa_range.end;
+ res->flags = IORESOURCE_MEM;
+ res->desc = IORES_DESC_PERSISTENT_MEMORY;
+
+ rc = insert_resource(&iomem_resource, res);
+ if (rc)
+ goto err;
+
+ rc = devm_add_action_or_reset(dev, cxlr_pmem_remove_resource, res);
+ if (rc)
+ goto err;
+
+ ndr_desc.res = res;
+ ndr_desc.provider_data = cxlr_pmem;
+
+ ndr_desc.numa_node = memory_add_physaddr_to_nid(res->start);
+ ndr_desc.target_node = phys_to_target_node(res->start);
+ if (ndr_desc.target_node == NUMA_NO_NODE) {
+ ndr_desc.target_node = ndr_desc.numa_node;
+ dev_dbg(&cxlr->dev, "changing target node from %d to %d",
+ NUMA_NO_NODE, ndr_desc.target_node);
+ }
+
+ nd_set = devm_kzalloc(dev, sizeof(*nd_set), GFP_KERNEL);
+ if (!nd_set) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ ndr_desc.memregion = cxlr->id;
+ set_bit(ND_REGION_CXL, &ndr_desc.flags);
+ set_bit(ND_REGION_PERSIST_MEMCTRL, &ndr_desc.flags);
+
+ info = kmalloc_array(cxlr_pmem->nr_mappings, sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < cxlr_pmem->nr_mappings; i++) {
+ struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i];
+ struct cxl_memdev *cxlmd = m->cxlmd;
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct device *d;
+
+ d = device_find_child(&cxlmd->dev, NULL, match_cxl_nvdimm);
+ if (!d) {
+ dev_dbg(dev, "[%d]: %s: no cxl_nvdimm found\n", i,
+ dev_name(&cxlmd->dev));
+ rc = -ENODEV;
+ goto err;
+ }
+
+ /* safe to drop ref now with bridge lock held */
+ put_device(d);
+
+ cxl_nvd = to_cxl_nvdimm(d);
+ nvdimm = dev_get_drvdata(&cxl_nvd->dev);
+ if (!nvdimm) {
+ dev_dbg(dev, "[%d]: %s: no nvdimm found\n", i,
+ dev_name(&cxlmd->dev));
+ rc = -ENODEV;
+ goto err;
+ }
+ cxl_nvd->region = cxlr_pmem;
+ get_device(&cxlr_pmem->dev);
+ m->cxl_nvd = cxl_nvd;
+ mappings[i] = (struct nd_mapping_desc) {
+ .nvdimm = nvdimm,
+ .start = m->start,
+ .size = m->size,
+ .position = i,
+ };
+ info[i].offset = m->start;
+ info[i].serial = cxlds->serial;
+ }
+ ndr_desc.num_mappings = cxlr_pmem->nr_mappings;
+ ndr_desc.mapping = mappings;
+
+ /*
+ * TODO enable CXL labels which skip the need for 'interleave-set cookie'
+ */
+ nd_set->cookie1 =
+ nd_fletcher64(info, sizeof(*info) * cxlr_pmem->nr_mappings, 0);
+ nd_set->cookie2 = nd_set->cookie1;
+ ndr_desc.nd_set = nd_set;
+
+ cxlr_pmem->nd_region =
+ nvdimm_pmem_region_create(cxl_nvb->nvdimm_bus, &ndr_desc);
+ if (!cxlr_pmem->nd_region) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ rc = devm_add_action_or_reset(dev, unregister_nvdimm_region,
+ cxlr_pmem->nd_region);
+out:
+ kfree(info);
+ device_unlock(&cxl_nvb->dev);
+ put_device(&cxl_nvb->dev);
+
+ return rc;
+
+err:
+ dev_dbg(dev, "failed to create nvdimm region\n");
+ for (i--; i >= 0; i--) {
+ nvdimm = mappings[i].nvdimm;
+ cxl_nvd = nvdimm_provider_data(nvdimm);
+ put_device(&cxl_nvd->region->dev);
+ cxl_nvd->region = NULL;
+ }
+ goto out;
+}
+
+static struct cxl_driver cxl_pmem_region_driver = {
+ .name = "cxl_pmem_region",
+ .probe = cxl_pmem_region_probe,
+ .id = CXL_DEVICE_PMEM_REGION,
+};
+
/*
* Return all bridges to the CXL_NVB_NEW state to invalidate any
* ->state_work referring to the now destroyed cxl_pmem_wq.
if (rc)
goto err_nvdimm;
+ rc = cxl_driver_register(&cxl_pmem_region_driver);
+ if (rc)
+ goto err_region;
+
return 0;
+err_region:
+ cxl_driver_unregister(&cxl_nvdimm_driver);
err_nvdimm:
cxl_driver_unregister(&cxl_nvdimm_bridge_driver);
err_bridge:
static __exit void cxl_pmem_exit(void)
{
+ cxl_driver_unregister(&cxl_pmem_region_driver);
cxl_driver_unregister(&cxl_nvdimm_driver);
cxl_driver_unregister(&cxl_nvdimm_bridge_driver);
destroy_cxl_pmem_wq();
MODULE_IMPORT_NS(CXL);
MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM_BRIDGE);
MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM);
+MODULE_ALIAS_CXL(CXL_DEVICE_PMEM_REGION);
struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport);
struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ /* Cache the data early to ensure is_visible() works */
+ read_cdat_data(port);
+
get_device(&cxlmd->dev);
rc = devm_add_action_or_reset(dev, schedule_detach, cxlmd);
if (rc)
return 0;
}
+static ssize_t CDAT_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t offset, size_t count)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct cxl_port *port = to_cxl_port(dev);
+
+ if (!port->cdat_available)
+ return -ENXIO;
+
+ if (!port->cdat.table)
+ return 0;
+
+ return memory_read_from_buffer(buf, count, &offset,
+ port->cdat.table,
+ port->cdat.length);
+}
+
+static BIN_ATTR_ADMIN_RO(CDAT, 0);
+
+static umode_t cxl_port_bin_attr_is_visible(struct kobject *kobj,
+ struct bin_attribute *attr, int i)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct cxl_port *port = to_cxl_port(dev);
+
+ if ((attr == &bin_attr_CDAT) && port->cdat_available)
+ return attr->attr.mode;
+
+ return 0;
+}
+
+static struct bin_attribute *cxl_cdat_bin_attributes[] = {
+ &bin_attr_CDAT,
+ NULL,
+};
+
+static struct attribute_group cxl_cdat_attribute_group = {
+ .bin_attrs = cxl_cdat_bin_attributes,
+ .is_bin_visible = cxl_port_bin_attr_is_visible,
+};
+
+static const struct attribute_group *cxl_port_attribute_groups[] = {
+ &cxl_cdat_attribute_group,
+ NULL,
+};
+
static struct cxl_driver cxl_port_driver = {
.name = "cxl_port",
.probe = cxl_port_probe,
.id = CXL_DEVICE_PORT,
+ .drv = {
+ .dev_groups = cxl_port_attribute_groups,
+ },
};
module_cxl_driver(cxl_port_driver);
unsigned long curr_freq;
- struct opp_table *opp_table;
+ int opp_token;
struct clk *clk;
unsigned int ratio;
};
dev_pm_opp_of_remove_table(dev);
clk_disable_unprepare(bus->clk);
- dev_pm_opp_put_regulators(bus->opp_table);
- bus->opp_table = NULL;
+ dev_pm_opp_put_regulators(bus->opp_token);
}
static void exynos_bus_passive_exit(struct device *dev)
struct exynos_bus *bus)
{
struct device *dev = bus->dev;
- struct opp_table *opp_table;
- const char *vdd = "vdd";
+ const char *supplies[] = { "vdd", NULL };
int i, ret, count, size;
- opp_table = dev_pm_opp_set_regulators(dev, &vdd, 1);
- if (IS_ERR(opp_table)) {
- ret = PTR_ERR(opp_table);
+ ret = dev_pm_opp_set_regulators(dev, supplies);
+ if (ret < 0) {
dev_err(dev, "failed to set regulators %d\n", ret);
return ret;
}
- bus->opp_table = opp_table;
+ bus->opp_token = ret;
/*
* Get the devfreq-event devices to get the current utilization of
return 0;
err_regulator:
- dev_pm_opp_put_regulators(bus->opp_table);
- bus->opp_table = NULL;
+ dev_pm_opp_put_regulators(bus->opp_token);
return ret;
}
dev_pm_opp_of_remove_table(dev);
clk_disable_unprepare(bus->clk);
err_reg:
- dev_pm_opp_put_regulators(bus->opp_table);
- bus->opp_table = NULL;
+ dev_pm_opp_put_regulators(bus->opp_token);
return ret;
}
return err;
}
+static int tegra_devfreq_config_clks_nop(struct device *dev,
+ struct opp_table *opp_table,
+ struct dev_pm_opp *opp, void *data,
+ bool scaling_down)
+{
+ /* We want to skip clk configuration via dev_pm_opp_set_opp() */
+ return 0;
+}
+
static int tegra_devfreq_probe(struct platform_device *pdev)
{
u32 hw_version = BIT(tegra_sku_info.soc_speedo_id);
unsigned int i;
long rate;
int err;
+ const char *clk_names[] = { "actmon", NULL };
+ struct dev_pm_opp_config config = {
+ .supported_hw = &hw_version,
+ .supported_hw_count = 1,
+ .clk_names = clk_names,
+ .config_clks = tegra_devfreq_config_clks_nop,
+ };
tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
if (!tegra)
return err;
}
- err = devm_pm_opp_set_supported_hw(&pdev->dev, &hw_version, 1);
+ err = devm_pm_opp_set_config(&pdev->dev, &config);
if (err) {
- dev_err(&pdev->dev, "Failed to set supported HW: %d\n", err);
+ dev_err(&pdev->dev, "Failed to set OPP config: %d\n", err);
return err;
}
- err = devm_pm_opp_of_add_table_noclk(&pdev->dev, 0);
+ err = devm_pm_opp_of_add_table_indexed(&pdev->dev, 0);
if (err) {
dev_err(&pdev->dev, "Failed to add OPP table: %d\n", err);
return err;
struct dev_pm_opp *opp;
unsigned long cur_freq;
int ret;
+ const char *regulator_names[] = { "mali", NULL };
+ const char *clk_names[] = { "core", NULL };
+ struct dev_pm_opp_config config = {
+ .regulator_names = regulator_names,
+ .clk_names = clk_names,
+ };
if (!device_property_present(dev, "operating-points-v2"))
/* Optional, continue without devfreq */
spin_lock_init(&ldevfreq->lock);
- ret = devm_pm_opp_set_clkname(dev, "core");
- if (ret)
- return ret;
-
- ret = devm_pm_opp_set_regulators(dev, (const char *[]){ "mali" }, 1);
+ ret = devm_pm_opp_set_config(dev, &config);
if (ret) {
/* Continue if the optional regulator is missing */
if (ret != -ENODEV)
return 0;
}
- ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names,
- pfdev->comp->num_supplies);
+ ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names);
if (ret) {
/* Continue if the optional regulator is missing */
if (ret != -ENODEV) {
return 0;
}
-static const char * const default_supplies[] = { "mali" };
+/*
+ * The OPP core wants the supply names to be NULL terminated, but we need the
+ * correct num_supplies value for regulator core. Hence, we NULL terminate here
+ * and then initialize num_supplies with ARRAY_SIZE - 1.
+ */
+static const char * const default_supplies[] = { "mali", NULL };
static const struct panfrost_compatible default_data = {
- .num_supplies = ARRAY_SIZE(default_supplies),
+ .num_supplies = ARRAY_SIZE(default_supplies) - 1,
.supply_names = default_supplies,
.num_pm_domains = 1, /* optional */
.pm_domain_names = NULL,
};
static const struct panfrost_compatible amlogic_data = {
- .num_supplies = ARRAY_SIZE(default_supplies),
+ .num_supplies = ARRAY_SIZE(default_supplies) - 1,
.supply_names = default_supplies,
.vendor_quirk = panfrost_gpu_amlogic_quirk,
};
-static const char * const mediatek_mt8183_supplies[] = { "mali", "sram" };
+static const char * const mediatek_mt8183_supplies[] = { "mali", "sram", NULL };
static const char * const mediatek_mt8183_pm_domains[] = { "core0", "core1", "core2" };
static const struct panfrost_compatible mediatek_mt8183_data = {
- .num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies),
+ .num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies) - 1,
.supply_names = mediatek_mt8183_supplies,
.num_pm_domains = ARRAY_SIZE(mediatek_mt8183_pm_domains),
.pm_domain_names = mediatek_mt8183_pm_domains,
}
skip_pmdomains:
- if (!core->has_opp_table)
+ if (!core->res->opp_pmdomain)
return 0;
/* Attach the power domain for setting performance state */
if (ret)
return ret;
+ ret = vcodec_domains_get(core);
+ if (ret)
+ return ret;
+
if (core->res->opp_pmdomain) {
ret = devm_pm_opp_of_add_table(dev);
if (!ret) {
}
}
- ret = vcodec_domains_get(core);
- if (ret)
- return ret;
-
return 0;
}
static int tegra_emc_opp_table_init(struct tegra_emc *emc)
{
u32 hw_version = BIT(tegra_sku_info.soc_speedo_id);
- struct opp_table *hw_opp_table;
- int err;
+ int opp_token, err;
- hw_opp_table = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1);
- err = PTR_ERR_OR_ZERO(hw_opp_table);
- if (err) {
+ err = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1);
+ if (err < 0) {
dev_err(emc->dev, "failed to set OPP supported HW: %d\n", err);
return err;
}
+ opp_token = err;
err = dev_pm_opp_of_add_table(emc->dev);
if (err) {
remove_table:
dev_pm_opp_of_remove_table(emc->dev);
put_hw_table:
- dev_pm_opp_put_supported_hw(hw_opp_table);
+ dev_pm_opp_put_supported_hw(opp_token);
return err;
}
put_device(&nvdimm->dev);
}
free_percpu(nd_region->lane);
- memregion_free(nd_region->id);
+ if (!test_bit(ND_REGION_CXL, &nd_region->flags))
+ memregion_free(nd_region->id);
kfree(nd_region);
}
if (!nd_region)
return NULL;
- nd_region->id = memregion_alloc(GFP_KERNEL);
- if (nd_region->id < 0)
- goto err_id;
+ /* CXL pre-assigns memregion ids before creating nvdimm regions */
+ if (test_bit(ND_REGION_CXL, &ndr_desc->flags)) {
+ nd_region->id = ndr_desc->memregion;
+ } else {
+ nd_region->id = memregion_alloc(GFP_KERNEL);
+ if (nd_region->id < 0)
+ goto err_id;
+ }
nd_region->lane = alloc_percpu(struct nd_percpu_lane);
if (!nd_region->lane)
return nd_region;
- err_percpu:
- memregion_free(nd_region->id);
- err_id:
+err_percpu:
+ if (!test_bit(ND_REGION_CXL, &ndr_desc->flags))
+ memregion_free(nd_region->id);
+err_id:
kfree(nd_region);
return NULL;
}
}
EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create);
+void nvdimm_region_delete(struct nd_region *nd_region)
+{
+ if (nd_region)
+ nd_device_unregister(&nd_region->dev, ND_SYNC);
+}
+EXPORT_SYMBOL_GPL(nvdimm_region_delete);
+
int nvdimm_flush(struct nd_region *nd_region, struct bio *bio)
{
int rc = 0;
#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/err.h>
-#include <linux/slab.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/pm_domain.h>
#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/xarray.h>
#include "opp.h"
/* Flag indicating that opp_tables list is being updated at the moment */
static bool opp_tables_busy;
+/* OPP ID allocator */
+static DEFINE_XARRAY_ALLOC1(opp_configs);
+
static bool _find_opp_dev(const struct device *dev, struct opp_table *opp_table)
{
struct opp_device *opp_dev;
return opp_table;
}
+/*
+ * Returns true if multiple clocks aren't there, else returns false with WARN.
+ *
+ * We don't force clk_count == 1 here as there are users who don't have a clock
+ * representation in the OPP table and manage the clock configuration themselves
+ * in an platform specific way.
+ */
+static bool assert_single_clk(struct opp_table *opp_table)
+{
+ return !WARN_ON(opp_table->clk_count > 1);
+}
+
/**
* dev_pm_opp_get_voltage() - Gets the voltage corresponding to an opp
* @opp: opp for which voltage has to be returned for
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage);
+/**
+ * dev_pm_opp_get_supplies() - Gets the supply information corresponding to an opp
+ * @opp: opp for which voltage has to be returned for
+ * @supplies: Placeholder for copying the supply information.
+ *
+ * Return: negative error number on failure, 0 otherwise on success after
+ * setting @supplies.
+ *
+ * This can be used for devices with any number of power supplies. The caller
+ * must ensure the @supplies array must contain space for each regulator.
+ */
+int dev_pm_opp_get_supplies(struct dev_pm_opp *opp,
+ struct dev_pm_opp_supply *supplies)
+{
+ if (IS_ERR_OR_NULL(opp) || !supplies) {
+ pr_err("%s: Invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ memcpy(supplies, opp->supplies,
+ sizeof(*supplies) * opp->opp_table->regulator_count);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_get_supplies);
+
/**
* dev_pm_opp_get_power() - Gets the power corresponding to an opp
* @opp: opp for which power has to be returned for
return 0;
}
- return opp->rate;
+ if (!assert_single_clk(opp->opp_table))
+ return 0;
+
+ return opp->rates[0];
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
+/* Helpers to read keys */
+static unsigned long _read_freq(struct dev_pm_opp *opp, int index)
+{
+ return opp->rates[0];
+}
+
+static unsigned long _read_level(struct dev_pm_opp *opp, int index)
+{
+ return opp->level;
+}
+
+static unsigned long _read_bw(struct dev_pm_opp *opp, int index)
+{
+ return opp->bandwidth[index].peak;
+}
+
+/* Generic comparison helpers */
+static bool _compare_exact(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
+ unsigned long opp_key, unsigned long key)
+{
+ if (opp_key == key) {
+ *opp = temp_opp;
+ return true;
+ }
+
+ return false;
+}
+
+static bool _compare_ceil(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
+ unsigned long opp_key, unsigned long key)
+{
+ if (opp_key >= key) {
+ *opp = temp_opp;
+ return true;
+ }
+
+ return false;
+}
+
+static bool _compare_floor(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
+ unsigned long opp_key, unsigned long key)
+{
+ if (opp_key > key)
+ return true;
+
+ *opp = temp_opp;
+ return false;
+}
+
+/* Generic key finding helpers */
+static struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table,
+ unsigned long *key, int index, bool available,
+ unsigned long (*read)(struct dev_pm_opp *opp, int index),
+ bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
+ unsigned long opp_key, unsigned long key),
+ bool (*assert)(struct opp_table *opp_table))
+{
+ struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
+
+ /* Assert that the requirement is met */
+ if (assert && !assert(opp_table))
+ return ERR_PTR(-EINVAL);
+
+ mutex_lock(&opp_table->lock);
+
+ list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
+ if (temp_opp->available == available) {
+ if (compare(&opp, temp_opp, read(temp_opp, index), *key))
+ break;
+ }
+ }
+
+ /* Increment the reference count of OPP */
+ if (!IS_ERR(opp)) {
+ *key = read(opp, index);
+ dev_pm_opp_get(opp);
+ }
+
+ mutex_unlock(&opp_table->lock);
+
+ return opp;
+}
+
+static struct dev_pm_opp *
+_find_key(struct device *dev, unsigned long *key, int index, bool available,
+ unsigned long (*read)(struct dev_pm_opp *opp, int index),
+ bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
+ unsigned long opp_key, unsigned long key),
+ bool (*assert)(struct opp_table *opp_table))
+{
+ struct opp_table *opp_table;
+ struct dev_pm_opp *opp;
+
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table)) {
+ dev_err(dev, "%s: OPP table not found (%ld)\n", __func__,
+ PTR_ERR(opp_table));
+ return ERR_CAST(opp_table);
+ }
+
+ opp = _opp_table_find_key(opp_table, key, index, available, read,
+ compare, assert);
+
+ dev_pm_opp_put_opp_table(opp_table);
+
+ return opp;
+}
+
+static struct dev_pm_opp *_find_key_exact(struct device *dev,
+ unsigned long key, int index, bool available,
+ unsigned long (*read)(struct dev_pm_opp *opp, int index),
+ bool (*assert)(struct opp_table *opp_table))
+{
+ /*
+ * The value of key will be updated here, but will be ignored as the
+ * caller doesn't need it.
+ */
+ return _find_key(dev, &key, index, available, read, _compare_exact,
+ assert);
+}
+
+static struct dev_pm_opp *_opp_table_find_key_ceil(struct opp_table *opp_table,
+ unsigned long *key, int index, bool available,
+ unsigned long (*read)(struct dev_pm_opp *opp, int index),
+ bool (*assert)(struct opp_table *opp_table))
+{
+ return _opp_table_find_key(opp_table, key, index, available, read,
+ _compare_ceil, assert);
+}
+
+static struct dev_pm_opp *_find_key_ceil(struct device *dev, unsigned long *key,
+ int index, bool available,
+ unsigned long (*read)(struct dev_pm_opp *opp, int index),
+ bool (*assert)(struct opp_table *opp_table))
+{
+ return _find_key(dev, key, index, available, read, _compare_ceil,
+ assert);
+}
+
+static struct dev_pm_opp *_find_key_floor(struct device *dev,
+ unsigned long *key, int index, bool available,
+ unsigned long (*read)(struct dev_pm_opp *opp, int index),
+ bool (*assert)(struct opp_table *opp_table))
+{
+ return _find_key(dev, key, index, available, read, _compare_floor,
+ assert);
+}
+
/**
* dev_pm_opp_find_freq_exact() - search for an exact frequency
* @dev: device for which we do this operation
* use.
*/
struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
- unsigned long freq,
- bool available)
+ unsigned long freq, bool available)
{
- struct opp_table *opp_table;
- struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
-
- opp_table = _find_opp_table(dev);
- if (IS_ERR(opp_table)) {
- int r = PTR_ERR(opp_table);
-
- dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r);
- return ERR_PTR(r);
- }
-
- mutex_lock(&opp_table->lock);
-
- list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
- if (temp_opp->available == available &&
- temp_opp->rate == freq) {
- opp = temp_opp;
-
- /* Increment the reference count of OPP */
- dev_pm_opp_get(opp);
- break;
- }
- }
-
- mutex_unlock(&opp_table->lock);
- dev_pm_opp_put_opp_table(opp_table);
-
- return opp;
+ return _find_key_exact(dev, freq, 0, available, _read_freq,
+ assert_single_clk);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
unsigned long *freq)
{
- struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
-
- mutex_lock(&opp_table->lock);
-
- list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
- if (temp_opp->available && temp_opp->rate >= *freq) {
- opp = temp_opp;
- *freq = opp->rate;
-
- /* Increment the reference count of OPP */
- dev_pm_opp_get(opp);
- break;
- }
- }
-
- mutex_unlock(&opp_table->lock);
-
- return opp;
+ return _opp_table_find_key_ceil(opp_table, freq, 0, true, _read_freq,
+ assert_single_clk);
}
/**
struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
unsigned long *freq)
{
- struct opp_table *opp_table;
- struct dev_pm_opp *opp;
-
- if (!dev || !freq) {
- dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
- return ERR_PTR(-EINVAL);
- }
-
- opp_table = _find_opp_table(dev);
- if (IS_ERR(opp_table))
- return ERR_CAST(opp_table);
-
- opp = _find_freq_ceil(opp_table, freq);
-
- dev_pm_opp_put_opp_table(opp_table);
-
- return opp;
+ return _find_key_ceil(dev, freq, 0, true, _read_freq, assert_single_clk);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
unsigned long *freq)
{
- struct opp_table *opp_table;
- struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
-
- if (!dev || !freq) {
- dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
- return ERR_PTR(-EINVAL);
- }
-
- opp_table = _find_opp_table(dev);
- if (IS_ERR(opp_table))
- return ERR_CAST(opp_table);
-
- mutex_lock(&opp_table->lock);
-
- list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
- if (temp_opp->available) {
- /* go to the next node, before choosing prev */
- if (temp_opp->rate > *freq)
- break;
- else
- opp = temp_opp;
- }
- }
-
- /* Increment the reference count of OPP */
- if (!IS_ERR(opp))
- dev_pm_opp_get(opp);
- mutex_unlock(&opp_table->lock);
- dev_pm_opp_put_opp_table(opp_table);
-
- if (!IS_ERR(opp))
- *freq = opp->rate;
-
- return opp;
+ return _find_key_floor(dev, freq, 0, true, _read_freq, assert_single_clk);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
-/**
- * dev_pm_opp_find_freq_ceil_by_volt() - Find OPP with highest frequency for
- * target voltage.
- * @dev: Device for which we do this operation.
- * @u_volt: Target voltage.
- *
- * Search for OPP with highest (ceil) frequency and has voltage <= u_volt.
- *
- * Return: matching *opp, else returns ERR_PTR in case of error which should be
- * handled using IS_ERR.
- *
- * Error return values can be:
- * EINVAL: bad parameters
- *
- * The callers are required to call dev_pm_opp_put() for the returned OPP after
- * use.
- */
-struct dev_pm_opp *dev_pm_opp_find_freq_ceil_by_volt(struct device *dev,
- unsigned long u_volt)
-{
- struct opp_table *opp_table;
- struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
-
- if (!dev || !u_volt) {
- dev_err(dev, "%s: Invalid argument volt=%lu\n", __func__,
- u_volt);
- return ERR_PTR(-EINVAL);
- }
-
- opp_table = _find_opp_table(dev);
- if (IS_ERR(opp_table))
- return ERR_CAST(opp_table);
-
- mutex_lock(&opp_table->lock);
-
- list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
- if (temp_opp->available) {
- if (temp_opp->supplies[0].u_volt > u_volt)
- break;
- opp = temp_opp;
- }
- }
-
- /* Increment the reference count of OPP */
- if (!IS_ERR(opp))
- dev_pm_opp_get(opp);
-
- mutex_unlock(&opp_table->lock);
- dev_pm_opp_put_opp_table(opp_table);
-
- return opp;
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil_by_volt);
-
/**
* dev_pm_opp_find_level_exact() - search for an exact level
* @dev: device for which we do this operation
struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev,
unsigned int level)
{
- struct opp_table *opp_table;
- struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
-
- opp_table = _find_opp_table(dev);
- if (IS_ERR(opp_table)) {
- int r = PTR_ERR(opp_table);
-
- dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r);
- return ERR_PTR(r);
- }
-
- mutex_lock(&opp_table->lock);
-
- list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
- if (temp_opp->level == level) {
- opp = temp_opp;
-
- /* Increment the reference count of OPP */
- dev_pm_opp_get(opp);
- break;
- }
- }
-
- mutex_unlock(&opp_table->lock);
- dev_pm_opp_put_opp_table(opp_table);
-
- return opp;
+ return _find_key_exact(dev, level, 0, true, _read_level, NULL);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_find_level_exact);
struct dev_pm_opp *dev_pm_opp_find_level_ceil(struct device *dev,
unsigned int *level)
{
- struct opp_table *opp_table;
- struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
-
- opp_table = _find_opp_table(dev);
- if (IS_ERR(opp_table)) {
- int r = PTR_ERR(opp_table);
-
- dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r);
- return ERR_PTR(r);
- }
-
- mutex_lock(&opp_table->lock);
-
- list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
- if (temp_opp->available && temp_opp->level >= *level) {
- opp = temp_opp;
- *level = opp->level;
-
- /* Increment the reference count of OPP */
- dev_pm_opp_get(opp);
- break;
- }
- }
-
- mutex_unlock(&opp_table->lock);
- dev_pm_opp_put_opp_table(opp_table);
+ unsigned long temp = *level;
+ struct dev_pm_opp *opp;
+ opp = _find_key_ceil(dev, &temp, 0, true, _read_level, NULL);
+ *level = temp;
return opp;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_find_level_ceil);
/**
* dev_pm_opp_find_bw_ceil() - Search for a rounded ceil bandwidth
* @dev: device for which we do this operation
- * @freq: start bandwidth
+ * @bw: start bandwidth
* @index: which bandwidth to compare, in case of OPPs with several values
*
* Search for the matching floor *available* OPP from a starting bandwidth
* The callers are required to call dev_pm_opp_put() for the returned OPP after
* use.
*/
-struct dev_pm_opp *dev_pm_opp_find_bw_ceil(struct device *dev,
- unsigned int *bw, int index)
+struct dev_pm_opp *dev_pm_opp_find_bw_ceil(struct device *dev, unsigned int *bw,
+ int index)
{
- struct opp_table *opp_table;
- struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
+ unsigned long temp = *bw;
+ struct dev_pm_opp *opp;
- if (!dev || !bw) {
- dev_err(dev, "%s: Invalid argument bw=%p\n", __func__, bw);
- return ERR_PTR(-EINVAL);
- }
-
- opp_table = _find_opp_table(dev);
- if (IS_ERR(opp_table))
- return ERR_CAST(opp_table);
-
- if (index >= opp_table->path_count)
- return ERR_PTR(-EINVAL);
-
- mutex_lock(&opp_table->lock);
-
- list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
- if (temp_opp->available && temp_opp->bandwidth) {
- if (temp_opp->bandwidth[index].peak >= *bw) {
- opp = temp_opp;
- *bw = opp->bandwidth[index].peak;
-
- /* Increment the reference count of OPP */
- dev_pm_opp_get(opp);
- break;
- }
- }
- }
-
- mutex_unlock(&opp_table->lock);
- dev_pm_opp_put_opp_table(opp_table);
-
- return opp;
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_find_bw_ceil);
+ opp = _find_key_ceil(dev, &temp, index, true, _read_bw, NULL);
+ *bw = temp;
+ return opp;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_find_bw_ceil);
/**
* dev_pm_opp_find_bw_floor() - Search for a rounded floor bandwidth
* @dev: device for which we do this operation
- * @freq: start bandwidth
+ * @bw: start bandwidth
* @index: which bandwidth to compare, in case of OPPs with several values
*
* Search for the matching floor *available* OPP from a starting bandwidth
struct dev_pm_opp *dev_pm_opp_find_bw_floor(struct device *dev,
unsigned int *bw, int index)
{
- struct opp_table *opp_table;
- struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
-
- if (!dev || !bw) {
- dev_err(dev, "%s: Invalid argument bw=%p\n", __func__, bw);
- return ERR_PTR(-EINVAL);
- }
-
- opp_table = _find_opp_table(dev);
- if (IS_ERR(opp_table))
- return ERR_CAST(opp_table);
-
- if (index >= opp_table->path_count)
- return ERR_PTR(-EINVAL);
-
- mutex_lock(&opp_table->lock);
-
- list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
- if (temp_opp->available && temp_opp->bandwidth) {
- /* go to the next node, before choosing prev */
- if (temp_opp->bandwidth[index].peak > *bw)
- break;
- opp = temp_opp;
- }
- }
-
- /* Increment the reference count of OPP */
- if (!IS_ERR(opp))
- dev_pm_opp_get(opp);
- mutex_unlock(&opp_table->lock);
- dev_pm_opp_put_opp_table(opp_table);
-
- if (!IS_ERR(opp))
- *bw = opp->bandwidth[index].peak;
+ unsigned long temp = *bw;
+ struct dev_pm_opp *opp;
+ opp = _find_key_floor(dev, &temp, index, true, _read_bw, NULL);
+ *bw = temp;
return opp;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_find_bw_floor);
return ret;
}
-static inline int _generic_set_opp_clk_only(struct device *dev, struct clk *clk,
- unsigned long freq)
+static int
+_opp_config_clk_single(struct device *dev, struct opp_table *opp_table,
+ struct dev_pm_opp *opp, void *data, bool scaling_down)
{
+ unsigned long *target = data;
+ unsigned long freq;
int ret;
- /* We may reach here for devices which don't change frequency */
- if (IS_ERR(clk))
- return 0;
+ /* One of target and opp must be available */
+ if (target) {
+ freq = *target;
+ } else if (opp) {
+ freq = opp->rates[0];
+ } else {
+ WARN_ON(1);
+ return -EINVAL;
+ }
- ret = clk_set_rate(clk, freq);
+ ret = clk_set_rate(opp_table->clk, freq);
if (ret) {
dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
ret);
+ } else {
+ opp_table->rate_clk_single = freq;
}
return ret;
}
-static int _generic_set_opp_regulator(struct opp_table *opp_table,
- struct device *dev,
- struct dev_pm_opp *opp,
- unsigned long freq,
- int scaling_down)
+/*
+ * Simple implementation for configuring multiple clocks. Configure clocks in
+ * the order in which they are present in the array while scaling up.
+ */
+int dev_pm_opp_config_clks_simple(struct device *dev,
+ struct opp_table *opp_table, struct dev_pm_opp *opp, void *data,
+ bool scaling_down)
{
- struct regulator *reg = opp_table->regulators[0];
- struct dev_pm_opp *old_opp = opp_table->current_opp;
+ int ret, i;
+
+ if (scaling_down) {
+ for (i = opp_table->clk_count - 1; i >= 0; i--) {
+ ret = clk_set_rate(opp_table->clks[i], opp->rates[i]);
+ if (ret) {
+ dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
+ ret);
+ return ret;
+ }
+ }
+ } else {
+ for (i = 0; i < opp_table->clk_count; i++) {
+ ret = clk_set_rate(opp_table->clks[i], opp->rates[i]);
+ if (ret) {
+ dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
+ ret);
+ return ret;
+ }
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_config_clks_simple);
+
+static int _opp_config_regulator_single(struct device *dev,
+ struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp,
+ struct regulator **regulators, unsigned int count)
+{
+ struct regulator *reg = regulators[0];
int ret;
/* This function only supports single regulator per device */
- if (WARN_ON(opp_table->regulator_count > 1)) {
+ if (WARN_ON(count > 1)) {
dev_err(dev, "multiple regulators are not supported\n");
return -EINVAL;
}
- /* Scaling up? Scale voltage before frequency */
- if (!scaling_down) {
- ret = _set_opp_voltage(dev, reg, opp->supplies);
- if (ret)
- goto restore_voltage;
- }
-
- /* Change frequency */
- ret = _generic_set_opp_clk_only(dev, opp_table->clk, freq);
+ ret = _set_opp_voltage(dev, reg, new_opp->supplies);
if (ret)
- goto restore_voltage;
-
- /* Scaling down? Scale voltage after frequency */
- if (scaling_down) {
- ret = _set_opp_voltage(dev, reg, opp->supplies);
- if (ret)
- goto restore_freq;
- }
+ return ret;
/*
* Enable the regulator after setting its voltages, otherwise it breaks
* some boot-enabled regulators.
*/
- if (unlikely(!opp_table->enabled)) {
+ if (unlikely(!new_opp->opp_table->enabled)) {
ret = regulator_enable(reg);
if (ret < 0)
dev_warn(dev, "Failed to enable regulator: %d", ret);
}
return 0;
-
-restore_freq:
- if (_generic_set_opp_clk_only(dev, opp_table->clk, old_opp->rate))
- dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
- __func__, old_opp->rate);
-restore_voltage:
- /* This shouldn't harm even if the voltages weren't updated earlier */
- _set_opp_voltage(dev, reg, old_opp->supplies);
-
- return ret;
}
static int _set_opp_bw(const struct opp_table *opp_table,
return 0;
}
-static int _set_opp_custom(const struct opp_table *opp_table,
- struct device *dev, struct dev_pm_opp *opp,
- unsigned long freq)
-{
- struct dev_pm_set_opp_data *data = opp_table->set_opp_data;
- struct dev_pm_opp *old_opp = opp_table->current_opp;
- int size;
-
- /*
- * We support this only if dev_pm_opp_set_regulators() was called
- * earlier.
- */
- if (opp_table->sod_supplies) {
- size = sizeof(*old_opp->supplies) * opp_table->regulator_count;
- memcpy(data->old_opp.supplies, old_opp->supplies, size);
- memcpy(data->new_opp.supplies, opp->supplies, size);
- data->regulator_count = opp_table->regulator_count;
- } else {
- data->regulator_count = 0;
- }
-
- data->regulators = opp_table->regulators;
- data->clk = opp_table->clk;
- data->dev = dev;
- data->old_opp.rate = old_opp->rate;
- data->new_opp.rate = freq;
-
- return opp_table->set_opp(data);
-}
-
static int _set_required_opp(struct device *dev, struct device *pd_dev,
struct dev_pm_opp *opp, int i)
{
ret = dev_pm_genpd_set_performance_state(pd_dev, pstate);
if (ret) {
- dev_err(dev, "Failed to set performance rate of %s: %d (%d)\n",
+ dev_err(dev, "Failed to set performance state of %s: %d (%d)\n",
dev_name(pd_dev), pstate, ret);
}
}
static int _set_opp(struct device *dev, struct opp_table *opp_table,
- struct dev_pm_opp *opp, unsigned long freq)
+ struct dev_pm_opp *opp, void *clk_data, bool forced)
{
struct dev_pm_opp *old_opp;
int scaling_down, ret;
old_opp = opp_table->current_opp;
/* Return early if nothing to do */
- if (old_opp == opp && opp_table->current_rate == freq &&
- opp_table->enabled) {
+ if (!forced && old_opp == opp && opp_table->enabled) {
dev_dbg(dev, "%s: OPPs are same, nothing to do\n", __func__);
return 0;
}
dev_dbg(dev, "%s: switching OPP: Freq %lu -> %lu Hz, Level %u -> %u, Bw %u -> %u\n",
- __func__, opp_table->current_rate, freq, old_opp->level,
+ __func__, old_opp->rates[0], opp->rates[0], old_opp->level,
opp->level, old_opp->bandwidth ? old_opp->bandwidth[0].peak : 0,
opp->bandwidth ? opp->bandwidth[0].peak : 0);
- scaling_down = _opp_compare_key(old_opp, opp);
+ scaling_down = _opp_compare_key(opp_table, old_opp, opp);
if (scaling_down == -1)
scaling_down = 0;
dev_err(dev, "Failed to set bw: %d\n", ret);
return ret;
}
- }
- if (opp_table->set_opp) {
- ret = _set_opp_custom(opp_table, dev, opp, freq);
- } else if (opp_table->regulators) {
- ret = _generic_set_opp_regulator(opp_table, dev, opp, freq,
- scaling_down);
- } else {
- /* Only frequency scaling */
- ret = _generic_set_opp_clk_only(dev, opp_table->clk, freq);
+ if (opp_table->config_regulators) {
+ ret = opp_table->config_regulators(dev, old_opp, opp,
+ opp_table->regulators,
+ opp_table->regulator_count);
+ if (ret) {
+ dev_err(dev, "Failed to set regulator voltages: %d\n",
+ ret);
+ return ret;
+ }
+ }
}
- if (ret)
- return ret;
+ if (opp_table->config_clks) {
+ ret = opp_table->config_clks(dev, opp_table, opp, clk_data, scaling_down);
+ if (ret)
+ return ret;
+ }
/* Scaling down? Configure required OPPs after frequency */
if (scaling_down) {
+ if (opp_table->config_regulators) {
+ ret = opp_table->config_regulators(dev, old_opp, opp,
+ opp_table->regulators,
+ opp_table->regulator_count);
+ if (ret) {
+ dev_err(dev, "Failed to set regulator voltages: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
ret = _set_opp_bw(opp_table, opp, dev);
if (ret) {
dev_err(dev, "Failed to set bw: %d\n", ret);
/* Make sure current_opp doesn't get freed */
dev_pm_opp_get(opp);
opp_table->current_opp = opp;
- opp_table->current_rate = freq;
return ret;
}
struct opp_table *opp_table;
unsigned long freq = 0, temp_freq;
struct dev_pm_opp *opp = NULL;
+ bool forced = false;
int ret;
opp_table = _find_opp_table(dev);
* equivalent to a clk_set_rate()
*/
if (!_get_opp_count(opp_table)) {
- ret = _generic_set_opp_clk_only(dev, opp_table->clk, target_freq);
+ ret = opp_table->config_clks(dev, opp_table, NULL,
+ &target_freq, false);
goto put_opp_table;
}
__func__, freq, ret);
goto put_opp_table;
}
+
+ /*
+ * An OPP entry specifies the highest frequency at which other
+ * properties of the OPP entry apply. Even if the new OPP is
+ * same as the old one, we may still reach here for a different
+ * value of the frequency. In such a case, do not abort but
+ * configure the hardware to the desired frequency forcefully.
+ */
+ forced = opp_table->rate_clk_single != target_freq;
}
- ret = _set_opp(dev, opp_table, opp, freq);
+ ret = _set_opp(dev, opp_table, opp, &target_freq, forced);
if (target_freq)
dev_pm_opp_put(opp);
+
put_opp_table:
dev_pm_opp_put_opp_table(opp_table);
return ret;
return PTR_ERR(opp_table);
}
- ret = _set_opp(dev, opp_table, opp, opp ? opp->rate : 0);
+ ret = _set_opp(dev, opp_table, opp, NULL, false);
dev_pm_opp_put_opp_table(opp_table);
return ret;
INIT_LIST_HEAD(&opp_table->dev_list);
INIT_LIST_HEAD(&opp_table->lazy);
+ opp_table->clk = ERR_PTR(-ENODEV);
+
/* Mark regulator count uninitialized */
opp_table->regulator_count = -1;
int ret;
/*
- * Return early if we don't need to get clk or we have already tried it
+ * Return early if we don't need to get clk or we have already done it
* earlier.
*/
- if (!getclk || IS_ERR(opp_table) || opp_table->clk)
+ if (!getclk || IS_ERR(opp_table) || !IS_ERR(opp_table->clk) ||
+ opp_table->clks)
return opp_table;
/* Find clk for the device */
opp_table->clk = clk_get(dev, NULL);
ret = PTR_ERR_OR_ZERO(opp_table->clk);
- if (!ret)
+ if (!ret) {
+ opp_table->config_clks = _opp_config_clk_single;
+ opp_table->clk_count = 1;
return opp_table;
+ }
if (ret == -ENOENT) {
+ /*
+ * There are few platforms which don't want the OPP core to
+ * manage device's clock settings. In such cases neither the
+ * platform provides the clks explicitly to us, nor the DT
+ * contains a valid clk entry. The OPP nodes in DT may still
+ * contain "opp-hz" property though, which we need to parse and
+ * allow the platform to find an OPP based on freq later on.
+ *
+ * This is a simple solution to take care of such corner cases,
+ * i.e. make the clk_count 1, which lets us allocate space for
+ * frequency in opp->rates and also parse the entries in DT.
+ */
+ opp_table->clk_count = 1;
+
dev_dbg(dev, "%s: Couldn't find clock: %d\n", __func__, ret);
return opp_table;
}
_of_clear_opp_table(opp_table);
- /* Release clk */
+ /* Release automatically acquired single clk */
if (!IS_ERR(opp_table->clk))
clk_put(opp_table->clk);
* frequency/voltage list.
*/
blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_REMOVE, opp);
- _of_opp_free_required_opps(opp_table, opp);
+ _of_clear_opp(opp_table, opp);
opp_debug_remove_one(opp);
kfree(opp);
}
if (IS_ERR(opp_table))
return;
+ if (!assert_single_clk(opp_table))
+ goto put_table;
+
mutex_lock(&opp_table->lock);
list_for_each_entry(iter, &opp_table->opp_list, node) {
- if (iter->rate == freq) {
+ if (iter->rates[0] == freq) {
opp = iter;
break;
}
__func__, freq);
}
+put_table:
/* Drop the reference taken by _find_opp_table() */
dev_pm_opp_put_opp_table(opp_table);
}
}
EXPORT_SYMBOL_GPL(dev_pm_opp_remove_all_dynamic);
-struct dev_pm_opp *_opp_allocate(struct opp_table *table)
+struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table)
{
struct dev_pm_opp *opp;
- int supply_count, supply_size, icc_size;
+ int supply_count, supply_size, icc_size, clk_size;
/* Allocate space for at least one supply */
- supply_count = table->regulator_count > 0 ? table->regulator_count : 1;
+ supply_count = opp_table->regulator_count > 0 ?
+ opp_table->regulator_count : 1;
supply_size = sizeof(*opp->supplies) * supply_count;
- icc_size = sizeof(*opp->bandwidth) * table->path_count;
+ clk_size = sizeof(*opp->rates) * opp_table->clk_count;
+ icc_size = sizeof(*opp->bandwidth) * opp_table->path_count;
/* allocate new OPP node and supplies structures */
- opp = kzalloc(sizeof(*opp) + supply_size + icc_size, GFP_KERNEL);
-
+ opp = kzalloc(sizeof(*opp) + supply_size + clk_size + icc_size, GFP_KERNEL);
if (!opp)
return NULL;
- /* Put the supplies at the end of the OPP structure as an empty array */
+ /* Put the supplies, bw and clock at the end of the OPP structure */
opp->supplies = (struct dev_pm_opp_supply *)(opp + 1);
+
+ opp->rates = (unsigned long *)(opp->supplies + supply_count);
+
if (icc_size)
- opp->bandwidth = (struct dev_pm_opp_icc_bw *)(opp->supplies + supply_count);
+ opp->bandwidth = (struct dev_pm_opp_icc_bw *)(opp->rates + opp_table->clk_count);
+
INIT_LIST_HEAD(&opp->node);
return opp;
return true;
}
-int _opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2)
+static int _opp_compare_rate(struct opp_table *opp_table,
+ struct dev_pm_opp *opp1, struct dev_pm_opp *opp2)
{
- if (opp1->rate != opp2->rate)
- return opp1->rate < opp2->rate ? -1 : 1;
- if (opp1->bandwidth && opp2->bandwidth &&
- opp1->bandwidth[0].peak != opp2->bandwidth[0].peak)
- return opp1->bandwidth[0].peak < opp2->bandwidth[0].peak ? -1 : 1;
+ int i;
+
+ for (i = 0; i < opp_table->clk_count; i++) {
+ if (opp1->rates[i] != opp2->rates[i])
+ return opp1->rates[i] < opp2->rates[i] ? -1 : 1;
+ }
+
+ /* Same rates for both OPPs */
+ return 0;
+}
+
+static int _opp_compare_bw(struct opp_table *opp_table, struct dev_pm_opp *opp1,
+ struct dev_pm_opp *opp2)
+{
+ int i;
+
+ for (i = 0; i < opp_table->path_count; i++) {
+ if (opp1->bandwidth[i].peak != opp2->bandwidth[i].peak)
+ return opp1->bandwidth[i].peak < opp2->bandwidth[i].peak ? -1 : 1;
+ }
+
+ /* Same bw for both OPPs */
+ return 0;
+}
+
+/*
+ * Returns
+ * 0: opp1 == opp2
+ * 1: opp1 > opp2
+ * -1: opp1 < opp2
+ */
+int _opp_compare_key(struct opp_table *opp_table, struct dev_pm_opp *opp1,
+ struct dev_pm_opp *opp2)
+{
+ int ret;
+
+ ret = _opp_compare_rate(opp_table, opp1, opp2);
+ if (ret)
+ return ret;
+
+ ret = _opp_compare_bw(opp_table, opp1, opp2);
+ if (ret)
+ return ret;
+
if (opp1->level != opp2->level)
return opp1->level < opp2->level ? -1 : 1;
+
+ /* Duplicate OPPs */
return 0;
}
* loop.
*/
list_for_each_entry(opp, &opp_table->opp_list, node) {
- opp_cmp = _opp_compare_key(new_opp, opp);
+ opp_cmp = _opp_compare_key(opp_table, new_opp, opp);
if (opp_cmp > 0) {
*head = &opp->node;
continue;
/* Duplicate OPPs */
dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n",
- __func__, opp->rate, opp->supplies[0].u_volt,
- opp->available, new_opp->rate,
+ __func__, opp->rates[0], opp->supplies[0].u_volt,
+ opp->available, new_opp->rates[0],
new_opp->supplies[0].u_volt, new_opp->available);
/* Should we compare voltages for all regulators here ? */
opp->available = false;
pr_warn("%s: OPP not supported by required OPP %pOF (%lu)\n",
- __func__, opp->required_opps[i]->np, opp->rate);
+ __func__, opp->required_opps[i]->np, opp->rates[0]);
return;
}
}
* should be considered an error by the callers of _opp_add().
*/
int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
- struct opp_table *opp_table, bool rate_not_available)
+ struct opp_table *opp_table)
{
struct list_head *head;
int ret;
if (!_opp_supported_by_regulators(new_opp, opp_table)) {
new_opp->available = false;
dev_warn(dev, "%s: OPP not supported by regulators (%lu)\n",
- __func__, new_opp->rate);
+ __func__, new_opp->rates[0]);
}
/* required-opps not fully initialized yet */
unsigned long tol;
int ret;
+ if (!assert_single_clk(opp_table))
+ return -EINVAL;
+
new_opp = _opp_allocate(opp_table);
if (!new_opp)
return -ENOMEM;
/* populate the opp table */
- new_opp->rate = freq;
+ new_opp->rates[0] = freq;
tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
new_opp->supplies[0].u_volt = u_volt;
new_opp->supplies[0].u_volt_min = u_volt - tol;
new_opp->available = true;
new_opp->dynamic = dynamic;
- ret = _opp_add(dev, new_opp, opp_table, false);
+ ret = _opp_add(dev, new_opp, opp_table);
if (ret) {
/* Don't return error for duplicate OPPs */
if (ret == -EBUSY)
}
/**
- * dev_pm_opp_set_supported_hw() - Set supported platforms
+ * _opp_set_supported_hw() - Set supported platforms
* @dev: Device for which supported-hw has to be set.
* @versions: Array of hierarchy of versions to match.
* @count: Number of elements in the array.
* OPPs, which are available for those versions, based on its 'opp-supported-hw'
* property.
*/
-struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
- const u32 *versions, unsigned int count)
+static int _opp_set_supported_hw(struct opp_table *opp_table,
+ const u32 *versions, unsigned int count)
{
- struct opp_table *opp_table;
-
- opp_table = _add_opp_table(dev, false);
- if (IS_ERR(opp_table))
- return opp_table;
-
- /* Make sure there are no concurrent readers while updating opp_table */
- WARN_ON(!list_empty(&opp_table->opp_list));
-
/* Another CPU that shares the OPP table has set the property ? */
if (opp_table->supported_hw)
- return opp_table;
+ return 0;
opp_table->supported_hw = kmemdup(versions, count * sizeof(*versions),
GFP_KERNEL);
- if (!opp_table->supported_hw) {
- dev_pm_opp_put_opp_table(opp_table);
- return ERR_PTR(-ENOMEM);
- }
+ if (!opp_table->supported_hw)
+ return -ENOMEM;
opp_table->supported_hw_count = count;
- return opp_table;
+ return 0;
}
-EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw);
/**
- * dev_pm_opp_put_supported_hw() - Releases resources blocked for supported hw
- * @opp_table: OPP table returned by dev_pm_opp_set_supported_hw().
+ * _opp_put_supported_hw() - Releases resources blocked for supported hw
+ * @opp_table: OPP table returned by _opp_set_supported_hw().
*
* This is required only for the V2 bindings, and is called for a matching
- * dev_pm_opp_set_supported_hw(). Until this is called, the opp_table structure
+ * _opp_set_supported_hw(). Until this is called, the opp_table structure
* will not be freed.
*/
-void dev_pm_opp_put_supported_hw(struct opp_table *opp_table)
-{
- if (unlikely(!opp_table))
- return;
-
- kfree(opp_table->supported_hw);
- opp_table->supported_hw = NULL;
- opp_table->supported_hw_count = 0;
-
- dev_pm_opp_put_opp_table(opp_table);
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw);
-
-static void devm_pm_opp_supported_hw_release(void *data)
-{
- dev_pm_opp_put_supported_hw(data);
-}
-
-/**
- * devm_pm_opp_set_supported_hw() - Set supported platforms
- * @dev: Device for which supported-hw has to be set.
- * @versions: Array of hierarchy of versions to match.
- * @count: Number of elements in the array.
- *
- * This is a resource-managed variant of dev_pm_opp_set_supported_hw().
- *
- * Return: 0 on success and errorno otherwise.
- */
-int devm_pm_opp_set_supported_hw(struct device *dev, const u32 *versions,
- unsigned int count)
+static void _opp_put_supported_hw(struct opp_table *opp_table)
{
- struct opp_table *opp_table;
-
- opp_table = dev_pm_opp_set_supported_hw(dev, versions, count);
- if (IS_ERR(opp_table))
- return PTR_ERR(opp_table);
-
- return devm_add_action_or_reset(dev, devm_pm_opp_supported_hw_release,
- opp_table);
+ if (opp_table->supported_hw) {
+ kfree(opp_table->supported_hw);
+ opp_table->supported_hw = NULL;
+ opp_table->supported_hw_count = 0;
+ }
}
-EXPORT_SYMBOL_GPL(devm_pm_opp_set_supported_hw);
/**
- * dev_pm_opp_set_prop_name() - Set prop-extn name
+ * _opp_set_prop_name() - Set prop-extn name
* @dev: Device for which the prop-name has to be set.
* @name: name to postfix to properties.
*
* which the extension will apply are opp-microvolt and opp-microamp. OPP core
* should postfix the property name with -<name> while looking for them.
*/
-struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
+static int _opp_set_prop_name(struct opp_table *opp_table, const char *name)
{
- struct opp_table *opp_table;
-
- opp_table = _add_opp_table(dev, false);
- if (IS_ERR(opp_table))
- return opp_table;
-
- /* Make sure there are no concurrent readers while updating opp_table */
- WARN_ON(!list_empty(&opp_table->opp_list));
-
/* Another CPU that shares the OPP table has set the property ? */
- if (opp_table->prop_name)
- return opp_table;
-
- opp_table->prop_name = kstrdup(name, GFP_KERNEL);
if (!opp_table->prop_name) {
- dev_pm_opp_put_opp_table(opp_table);
- return ERR_PTR(-ENOMEM);
+ opp_table->prop_name = kstrdup(name, GFP_KERNEL);
+ if (!opp_table->prop_name)
+ return -ENOMEM;
}
- return opp_table;
+ return 0;
}
-EXPORT_SYMBOL_GPL(dev_pm_opp_set_prop_name);
/**
- * dev_pm_opp_put_prop_name() - Releases resources blocked for prop-name
- * @opp_table: OPP table returned by dev_pm_opp_set_prop_name().
+ * _opp_put_prop_name() - Releases resources blocked for prop-name
+ * @opp_table: OPP table returned by _opp_set_prop_name().
*
* This is required only for the V2 bindings, and is called for a matching
- * dev_pm_opp_set_prop_name(). Until this is called, the opp_table structure
+ * _opp_set_prop_name(). Until this is called, the opp_table structure
* will not be freed.
*/
-void dev_pm_opp_put_prop_name(struct opp_table *opp_table)
+static void _opp_put_prop_name(struct opp_table *opp_table)
{
- if (unlikely(!opp_table))
- return;
-
- kfree(opp_table->prop_name);
- opp_table->prop_name = NULL;
-
- dev_pm_opp_put_opp_table(opp_table);
+ if (opp_table->prop_name) {
+ kfree(opp_table->prop_name);
+ opp_table->prop_name = NULL;
+ }
}
-EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
/**
- * dev_pm_opp_set_regulators() - Set regulator names for the device
+ * _opp_set_regulators() - Set regulator names for the device
* @dev: Device for which regulator name is being set.
* @names: Array of pointers to the names of the regulator.
* @count: Number of regulators.
*
* This must be called before any OPPs are initialized for the device.
*/
-struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
- const char * const names[],
- unsigned int count)
+static int _opp_set_regulators(struct opp_table *opp_table, struct device *dev,
+ const char * const names[])
{
- struct dev_pm_opp_supply *supplies;
- struct opp_table *opp_table;
+ const char * const *temp = names;
struct regulator *reg;
- int ret, i;
+ int count = 0, ret, i;
- opp_table = _add_opp_table(dev, false);
- if (IS_ERR(opp_table))
- return opp_table;
+ /* Count number of regulators */
+ while (*temp++)
+ count++;
- /* This should be called before OPPs are initialized */
- if (WARN_ON(!list_empty(&opp_table->opp_list))) {
- ret = -EBUSY;
- goto err;
- }
+ if (!count)
+ return -EINVAL;
/* Another CPU that shares the OPP table has set the regulators ? */
if (opp_table->regulators)
- return opp_table;
+ return 0;
opp_table->regulators = kmalloc_array(count,
sizeof(*opp_table->regulators),
GFP_KERNEL);
- if (!opp_table->regulators) {
- ret = -ENOMEM;
- goto err;
- }
+ if (!opp_table->regulators)
+ return -ENOMEM;
for (i = 0; i < count; i++) {
reg = regulator_get_optional(dev, names[i]);
opp_table->regulator_count = count;
- supplies = kmalloc_array(count * 2, sizeof(*supplies), GFP_KERNEL);
- if (!supplies) {
- ret = -ENOMEM;
- goto free_regulators;
- }
-
- mutex_lock(&opp_table->lock);
- opp_table->sod_supplies = supplies;
- if (opp_table->set_opp_data) {
- opp_table->set_opp_data->old_opp.supplies = supplies;
- opp_table->set_opp_data->new_opp.supplies = supplies + count;
- }
- mutex_unlock(&opp_table->lock);
+ /* Set generic config_regulators() for single regulators here */
+ if (count == 1)
+ opp_table->config_regulators = _opp_config_regulator_single;
- return opp_table;
+ return 0;
free_regulators:
while (i != 0)
kfree(opp_table->regulators);
opp_table->regulators = NULL;
opp_table->regulator_count = -1;
-err:
- dev_pm_opp_put_opp_table(opp_table);
- return ERR_PTR(ret);
+ return ret;
}
-EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulators);
/**
- * dev_pm_opp_put_regulators() - Releases resources blocked for regulator
- * @opp_table: OPP table returned from dev_pm_opp_set_regulators().
+ * _opp_put_regulators() - Releases resources blocked for regulator
+ * @opp_table: OPP table returned from _opp_set_regulators().
*/
-void dev_pm_opp_put_regulators(struct opp_table *opp_table)
+static void _opp_put_regulators(struct opp_table *opp_table)
{
int i;
- if (unlikely(!opp_table))
- return;
-
if (!opp_table->regulators)
- goto put_opp_table;
+ return;
if (opp_table->enabled) {
for (i = opp_table->regulator_count - 1; i >= 0; i--)
for (i = opp_table->regulator_count - 1; i >= 0; i--)
regulator_put(opp_table->regulators[i]);
- mutex_lock(&opp_table->lock);
- if (opp_table->set_opp_data) {
- opp_table->set_opp_data->old_opp.supplies = NULL;
- opp_table->set_opp_data->new_opp.supplies = NULL;
- }
-
- kfree(opp_table->sod_supplies);
- opp_table->sod_supplies = NULL;
- mutex_unlock(&opp_table->lock);
-
kfree(opp_table->regulators);
opp_table->regulators = NULL;
opp_table->regulator_count = -1;
-
-put_opp_table:
- dev_pm_opp_put_opp_table(opp_table);
}
-EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);
-static void devm_pm_opp_regulators_release(void *data)
-{
- dev_pm_opp_put_regulators(data);
-}
-
-/**
- * devm_pm_opp_set_regulators() - Set regulator names for the device
- * @dev: Device for which regulator name is being set.
- * @names: Array of pointers to the names of the regulator.
- * @count: Number of regulators.
- *
- * This is a resource-managed variant of dev_pm_opp_set_regulators().
- *
- * Return: 0 on success and errorno otherwise.
- */
-int devm_pm_opp_set_regulators(struct device *dev,
- const char * const names[],
- unsigned int count)
+static void _put_clks(struct opp_table *opp_table, int count)
{
- struct opp_table *opp_table;
+ int i;
- opp_table = dev_pm_opp_set_regulators(dev, names, count);
- if (IS_ERR(opp_table))
- return PTR_ERR(opp_table);
+ for (i = count - 1; i >= 0; i--)
+ clk_put(opp_table->clks[i]);
- return devm_add_action_or_reset(dev, devm_pm_opp_regulators_release,
- opp_table);
+ kfree(opp_table->clks);
+ opp_table->clks = NULL;
}
-EXPORT_SYMBOL_GPL(devm_pm_opp_set_regulators);
/**
- * dev_pm_opp_set_clkname() - Set clk name for the device
- * @dev: Device for which clk name is being set.
- * @name: Clk name.
- *
- * In order to support OPP switching, OPP layer needs to get pointer to the
- * clock for the device. Simple cases work fine without using this routine (i.e.
- * by passing connection-id as NULL), but for a device with multiple clocks
- * available, the OPP core needs to know the exact name of the clk to use.
+ * _opp_set_clknames() - Set clk names for the device
+ * @dev: Device for which clk names is being set.
+ * @names: Clk names.
+ *
+ * In order to support OPP switching, OPP layer needs to get pointers to the
+ * clocks for the device. Simple cases work fine without using this routine
+ * (i.e. by passing connection-id as NULL), but for a device with multiple
+ * clocks available, the OPP core needs to know the exact names of the clks to
+ * use.
*
* This must be called before any OPPs are initialized for the device.
*/
-struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name)
+static int _opp_set_clknames(struct opp_table *opp_table, struct device *dev,
+ const char * const names[],
+ config_clks_t config_clks)
{
- struct opp_table *opp_table;
- int ret;
+ const char * const *temp = names;
+ int count = 0, ret, i;
+ struct clk *clk;
- opp_table = _add_opp_table(dev, false);
- if (IS_ERR(opp_table))
- return opp_table;
+ /* Count number of clks */
+ while (*temp++)
+ count++;
- /* This should be called before OPPs are initialized */
- if (WARN_ON(!list_empty(&opp_table->opp_list))) {
- ret = -EBUSY;
- goto err;
- }
+ /*
+ * This is a special case where we have a single clock, whose connection
+ * id name is NULL, i.e. first two entries are NULL in the array.
+ */
+ if (!count && !names[1])
+ count = 1;
- /* clk shouldn't be initialized at this point */
- if (WARN_ON(opp_table->clk)) {
- ret = -EBUSY;
- goto err;
- }
+ /* Fail early for invalid configurations */
+ if (!count || (!config_clks && count > 1))
+ return -EINVAL;
- /* Find clk for the device */
- opp_table->clk = clk_get(dev, name);
- if (IS_ERR(opp_table->clk)) {
- ret = dev_err_probe(dev, PTR_ERR(opp_table->clk),
- "%s: Couldn't find clock\n", __func__);
- goto err;
- }
+ /* Another CPU that shares the OPP table has set the clkname ? */
+ if (opp_table->clks)
+ return 0;
- return opp_table;
+ opp_table->clks = kmalloc_array(count, sizeof(*opp_table->clks),
+ GFP_KERNEL);
+ if (!opp_table->clks)
+ return -ENOMEM;
-err:
- dev_pm_opp_put_opp_table(opp_table);
+ /* Find clks for the device */
+ for (i = 0; i < count; i++) {
+ clk = clk_get(dev, names[i]);
+ if (IS_ERR(clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(clk),
+ "%s: Couldn't find clock with name: %s\n",
+ __func__, names[i]);
+ goto free_clks;
+ }
- return ERR_PTR(ret);
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_set_clkname);
+ opp_table->clks[i] = clk;
+ }
-/**
- * dev_pm_opp_put_clkname() - Releases resources blocked for clk.
- * @opp_table: OPP table returned from dev_pm_opp_set_clkname().
- */
-void dev_pm_opp_put_clkname(struct opp_table *opp_table)
-{
- if (unlikely(!opp_table))
- return;
+ opp_table->clk_count = count;
+ opp_table->config_clks = config_clks;
- clk_put(opp_table->clk);
- opp_table->clk = ERR_PTR(-EINVAL);
+ /* Set generic single clk set here */
+ if (count == 1) {
+ if (!opp_table->config_clks)
+ opp_table->config_clks = _opp_config_clk_single;
- dev_pm_opp_put_opp_table(opp_table);
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_put_clkname);
+ /*
+ * We could have just dropped the "clk" field and used "clks"
+ * everywhere. Instead we kept the "clk" field around for
+ * following reasons:
+ *
+ * - avoiding clks[0] everywhere else.
+ * - not running single clk helpers for multiple clk usecase by
+ * mistake.
+ *
+ * Since this is single-clk case, just update the clk pointer
+ * too.
+ */
+ opp_table->clk = opp_table->clks[0];
+ }
-static void devm_pm_opp_clkname_release(void *data)
-{
- dev_pm_opp_put_clkname(data);
+ return 0;
+
+free_clks:
+ _put_clks(opp_table, i);
+ return ret;
}
/**
- * devm_pm_opp_set_clkname() - Set clk name for the device
- * @dev: Device for which clk name is being set.
- * @name: Clk name.
- *
- * This is a resource-managed variant of dev_pm_opp_set_clkname().
- *
- * Return: 0 on success and errorno otherwise.
+ * _opp_put_clknames() - Releases resources blocked for clks.
+ * @opp_table: OPP table returned from _opp_set_clknames().
*/
-int devm_pm_opp_set_clkname(struct device *dev, const char *name)
+static void _opp_put_clknames(struct opp_table *opp_table)
{
- struct opp_table *opp_table;
+ if (!opp_table->clks)
+ return;
- opp_table = dev_pm_opp_set_clkname(dev, name);
- if (IS_ERR(opp_table))
- return PTR_ERR(opp_table);
+ opp_table->config_clks = NULL;
+ opp_table->clk = ERR_PTR(-ENODEV);
- return devm_add_action_or_reset(dev, devm_pm_opp_clkname_release,
- opp_table);
+ _put_clks(opp_table, opp_table->clk_count);
}
-EXPORT_SYMBOL_GPL(devm_pm_opp_set_clkname);
/**
- * dev_pm_opp_register_set_opp_helper() - Register custom set OPP helper
+ * _opp_set_config_regulators_helper() - Register custom set regulator helper.
* @dev: Device for which the helper is getting registered.
- * @set_opp: Custom set OPP helper.
+ * @config_regulators: Custom set regulator helper.
*
- * This is useful to support complex platforms (like platforms with multiple
- * regulators per device), instead of the generic OPP set rate helper.
+ * This is useful to support platforms with multiple regulators per device.
*
* This must be called before any OPPs are initialized for the device.
*/
-struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev,
- int (*set_opp)(struct dev_pm_set_opp_data *data))
+static int _opp_set_config_regulators_helper(struct opp_table *opp_table,
+ struct device *dev, config_regulators_t config_regulators)
{
- struct dev_pm_set_opp_data *data;
- struct opp_table *opp_table;
-
- if (!set_opp)
- return ERR_PTR(-EINVAL);
-
- opp_table = _add_opp_table(dev, false);
- if (IS_ERR(opp_table))
- return opp_table;
-
- /* This should be called before OPPs are initialized */
- if (WARN_ON(!list_empty(&opp_table->opp_list))) {
- dev_pm_opp_put_opp_table(opp_table);
- return ERR_PTR(-EBUSY);
- }
-
/* Another CPU that shares the OPP table has set the helper ? */
- if (opp_table->set_opp)
- return opp_table;
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data)
- return ERR_PTR(-ENOMEM);
-
- mutex_lock(&opp_table->lock);
- opp_table->set_opp_data = data;
- if (opp_table->sod_supplies) {
- data->old_opp.supplies = opp_table->sod_supplies;
- data->new_opp.supplies = opp_table->sod_supplies +
- opp_table->regulator_count;
- }
- mutex_unlock(&opp_table->lock);
-
- opp_table->set_opp = set_opp;
-
- return opp_table;
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_opp_helper);
-
-/**
- * dev_pm_opp_unregister_set_opp_helper() - Releases resources blocked for
- * set_opp helper
- * @opp_table: OPP table returned from dev_pm_opp_register_set_opp_helper().
- *
- * Release resources blocked for platform specific set_opp helper.
- */
-void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table)
-{
- if (unlikely(!opp_table))
- return;
-
- opp_table->set_opp = NULL;
+ if (!opp_table->config_regulators)
+ opp_table->config_regulators = config_regulators;
- mutex_lock(&opp_table->lock);
- kfree(opp_table->set_opp_data);
- opp_table->set_opp_data = NULL;
- mutex_unlock(&opp_table->lock);
-
- dev_pm_opp_put_opp_table(opp_table);
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_unregister_set_opp_helper);
-
-static void devm_pm_opp_unregister_set_opp_helper(void *data)
-{
- dev_pm_opp_unregister_set_opp_helper(data);
+ return 0;
}
/**
- * devm_pm_opp_register_set_opp_helper() - Register custom set OPP helper
- * @dev: Device for which the helper is getting registered.
- * @set_opp: Custom set OPP helper.
- *
- * This is a resource-managed version of dev_pm_opp_register_set_opp_helper().
+ * _opp_put_config_regulators_helper() - Releases resources blocked for
+ * config_regulators helper.
+ * @opp_table: OPP table returned from _opp_set_config_regulators_helper().
*
- * Return: 0 on success and errorno otherwise.
+ * Release resources blocked for platform specific config_regulators helper.
*/
-int devm_pm_opp_register_set_opp_helper(struct device *dev,
- int (*set_opp)(struct dev_pm_set_opp_data *data))
+static void _opp_put_config_regulators_helper(struct opp_table *opp_table)
{
- struct opp_table *opp_table;
-
- opp_table = dev_pm_opp_register_set_opp_helper(dev, set_opp);
- if (IS_ERR(opp_table))
- return PTR_ERR(opp_table);
-
- return devm_add_action_or_reset(dev, devm_pm_opp_unregister_set_opp_helper,
- opp_table);
+ if (opp_table->config_regulators)
+ opp_table->config_regulators = NULL;
}
-EXPORT_SYMBOL_GPL(devm_pm_opp_register_set_opp_helper);
-static void _opp_detach_genpd(struct opp_table *opp_table)
+static void _detach_genpd(struct opp_table *opp_table)
{
int index;
}
/**
- * dev_pm_opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer
+ * _opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer
* @dev: Consumer device for which the genpd is getting attached.
* @names: Null terminated array of pointers containing names of genpd to attach.
* @virt_devs: Pointer to return the array of virtual devices.
* The order of entries in the names array must match the order in which
* "required-opps" are added in DT.
*/
-struct opp_table *dev_pm_opp_attach_genpd(struct device *dev,
- const char * const *names, struct device ***virt_devs)
+static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
+ const char * const *names, struct device ***virt_devs)
{
- struct opp_table *opp_table;
struct device *virt_dev;
int index = 0, ret = -EINVAL;
const char * const *name = names;
- opp_table = _add_opp_table(dev, false);
- if (IS_ERR(opp_table))
- return opp_table;
-
if (opp_table->genpd_virt_devs)
- return opp_table;
+ return 0;
/*
* If the genpd's OPP table isn't already initialized, parsing of the
* required-opps fail for dev. We should retry this after genpd's OPP
* table is added.
*/
- if (!opp_table->required_opp_count) {
- ret = -EPROBE_DEFER;
- goto put_table;
- }
+ if (!opp_table->required_opp_count)
+ return -EPROBE_DEFER;
mutex_lock(&opp_table->genpd_virt_dev_lock);
}
virt_dev = dev_pm_domain_attach_by_name(dev, *name);
- if (IS_ERR(virt_dev)) {
- ret = PTR_ERR(virt_dev);
+ if (IS_ERR_OR_NULL(virt_dev)) {
+ ret = PTR_ERR(virt_dev) ? : -ENODEV;
dev_err(dev, "Couldn't attach to pm_domain: %d\n", ret);
goto err;
}
*virt_devs = opp_table->genpd_virt_devs;
mutex_unlock(&opp_table->genpd_virt_dev_lock);
- return opp_table;
+ return 0;
err:
- _opp_detach_genpd(opp_table);
+ _detach_genpd(opp_table);
unlock:
mutex_unlock(&opp_table->genpd_virt_dev_lock);
+ return ret;
-put_table:
- dev_pm_opp_put_opp_table(opp_table);
-
- return ERR_PTR(ret);
}
-EXPORT_SYMBOL_GPL(dev_pm_opp_attach_genpd);
/**
- * dev_pm_opp_detach_genpd() - Detach genpd(s) from the device.
- * @opp_table: OPP table returned by dev_pm_opp_attach_genpd().
+ * _opp_detach_genpd() - Detach genpd(s) from the device.
+ * @opp_table: OPP table returned by _opp_attach_genpd().
*
* This detaches the genpd(s), resets the virtual device pointers, and puts the
* OPP table.
*/
-void dev_pm_opp_detach_genpd(struct opp_table *opp_table)
+static void _opp_detach_genpd(struct opp_table *opp_table)
{
- if (unlikely(!opp_table))
- return;
-
/*
* Acquire genpd_virt_dev_lock to make sure virt_dev isn't getting
* used in parallel.
*/
mutex_lock(&opp_table->genpd_virt_dev_lock);
- _opp_detach_genpd(opp_table);
+ _detach_genpd(opp_table);
mutex_unlock(&opp_table->genpd_virt_dev_lock);
-
- dev_pm_opp_put_opp_table(opp_table);
}
-EXPORT_SYMBOL_GPL(dev_pm_opp_detach_genpd);
-static void devm_pm_opp_detach_genpd(void *data)
+static void _opp_clear_config(struct opp_config_data *data)
{
- dev_pm_opp_detach_genpd(data);
+ if (data->flags & OPP_CONFIG_GENPD)
+ _opp_detach_genpd(data->opp_table);
+ if (data->flags & OPP_CONFIG_REGULATOR)
+ _opp_put_regulators(data->opp_table);
+ if (data->flags & OPP_CONFIG_SUPPORTED_HW)
+ _opp_put_supported_hw(data->opp_table);
+ if (data->flags & OPP_CONFIG_REGULATOR_HELPER)
+ _opp_put_config_regulators_helper(data->opp_table);
+ if (data->flags & OPP_CONFIG_PROP_NAME)
+ _opp_put_prop_name(data->opp_table);
+ if (data->flags & OPP_CONFIG_CLK)
+ _opp_put_clknames(data->opp_table);
+
+ dev_pm_opp_put_opp_table(data->opp_table);
+ kfree(data);
}
/**
- * devm_pm_opp_attach_genpd - Attach genpd(s) for the device and save virtual
- * device pointer
- * @dev: Consumer device for which the genpd is getting attached.
- * @names: Null terminated array of pointers containing names of genpd to attach.
- * @virt_devs: Pointer to return the array of virtual devices.
+ * dev_pm_opp_set_config() - Set OPP configuration for the device.
+ * @dev: Device for which configuration is being set.
+ * @config: OPP configuration.
*
- * This is a resource-managed version of dev_pm_opp_attach_genpd().
+ * This allows all device OPP configurations to be performed at once.
*
- * Return: 0 on success and errorno otherwise.
+ * This must be called before any OPPs are initialized for the device. This may
+ * be called multiple times for the same OPP table, for example once for each
+ * CPU that share the same table. This must be balanced by the same number of
+ * calls to dev_pm_opp_clear_config() in order to free the OPP table properly.
+ *
+ * This returns a token to the caller, which must be passed to
+ * dev_pm_opp_clear_config() to free the resources later. The value of the
+ * returned token will be >= 1 for success and negative for errors. The minimum
+ * value of 1 is chosen here to make it easy for callers to manage the resource.
*/
-int devm_pm_opp_attach_genpd(struct device *dev, const char * const *names,
- struct device ***virt_devs)
+int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
{
struct opp_table *opp_table;
+ struct opp_config_data *data;
+ unsigned int id;
+ int ret;
- opp_table = dev_pm_opp_attach_genpd(dev, names, virt_devs);
- if (IS_ERR(opp_table))
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ opp_table = _add_opp_table(dev, false);
+ if (IS_ERR(opp_table)) {
+ kfree(data);
return PTR_ERR(opp_table);
+ }
+
+ data->opp_table = opp_table;
+ data->flags = 0;
+
+ /* This should be called before OPPs are initialized */
+ if (WARN_ON(!list_empty(&opp_table->opp_list))) {
+ ret = -EBUSY;
+ goto err;
+ }
+
+ /* Configure clocks */
+ if (config->clk_names) {
+ ret = _opp_set_clknames(opp_table, dev, config->clk_names,
+ config->config_clks);
+ if (ret)
+ goto err;
+
+ data->flags |= OPP_CONFIG_CLK;
+ } else if (config->config_clks) {
+ /* Don't allow config callback without clocks */
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Configure property names */
+ if (config->prop_name) {
+ ret = _opp_set_prop_name(opp_table, config->prop_name);
+ if (ret)
+ goto err;
+
+ data->flags |= OPP_CONFIG_PROP_NAME;
+ }
+
+ /* Configure config_regulators helper */
+ if (config->config_regulators) {
+ ret = _opp_set_config_regulators_helper(opp_table, dev,
+ config->config_regulators);
+ if (ret)
+ goto err;
+
+ data->flags |= OPP_CONFIG_REGULATOR_HELPER;
+ }
+
+ /* Configure supported hardware */
+ if (config->supported_hw) {
+ ret = _opp_set_supported_hw(opp_table, config->supported_hw,
+ config->supported_hw_count);
+ if (ret)
+ goto err;
+
+ data->flags |= OPP_CONFIG_SUPPORTED_HW;
+ }
+
+ /* Configure supplies */
+ if (config->regulator_names) {
+ ret = _opp_set_regulators(opp_table, dev,
+ config->regulator_names);
+ if (ret)
+ goto err;
+
+ data->flags |= OPP_CONFIG_REGULATOR;
+ }
+
+ /* Attach genpds */
+ if (config->genpd_names) {
+ ret = _opp_attach_genpd(opp_table, dev, config->genpd_names,
+ config->virt_devs);
+ if (ret)
+ goto err;
+
+ data->flags |= OPP_CONFIG_GENPD;
+ }
+
+ ret = xa_alloc(&opp_configs, &id, data, XA_LIMIT(1, INT_MAX),
+ GFP_KERNEL);
+ if (ret)
+ goto err;
+
+ return id;
+
+err:
+ _opp_clear_config(data);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_set_config);
+
+/**
+ * dev_pm_opp_clear_config() - Releases resources blocked for OPP configuration.
+ * @opp_table: OPP table returned from dev_pm_opp_set_config().
+ *
+ * This allows all device OPP configurations to be cleared at once. This must be
+ * called once for each call made to dev_pm_opp_set_config(), in order to free
+ * the OPPs properly.
+ *
+ * Currently the first call itself ends up freeing all the OPP configurations,
+ * while the later ones only drop the OPP table reference. This works well for
+ * now as we would never want to use an half initialized OPP table and want to
+ * remove the configurations together.
+ */
+void dev_pm_opp_clear_config(int token)
+{
+ struct opp_config_data *data;
+
+ /*
+ * This lets the callers call this unconditionally and keep their code
+ * simple.
+ */
+ if (unlikely(token <= 0))
+ return;
+
+ data = xa_erase(&opp_configs, token);
+ if (WARN_ON(!data))
+ return;
+
+ _opp_clear_config(data);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_clear_config);
+
+static void devm_pm_opp_config_release(void *token)
+{
+ dev_pm_opp_clear_config((unsigned long)token);
+}
+
+/**
+ * devm_pm_opp_set_config() - Set OPP configuration for the device.
+ * @dev: Device for which configuration is being set.
+ * @config: OPP configuration.
+ *
+ * This allows all device OPP configurations to be performed at once.
+ * This is a resource-managed variant of dev_pm_opp_set_config().
+ *
+ * Return: 0 on success and errorno otherwise.
+ */
+int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
+{
+ int token = dev_pm_opp_set_config(dev, config);
- return devm_add_action_or_reset(dev, devm_pm_opp_detach_genpd,
- opp_table);
+ if (token < 0)
+ return token;
+
+ return devm_add_action_or_reset(dev, devm_pm_opp_config_release,
+ (void *) ((unsigned long) token));
}
-EXPORT_SYMBOL_GPL(devm_pm_opp_attach_genpd);
+EXPORT_SYMBOL_GPL(devm_pm_opp_set_config);
/**
* dev_pm_opp_xlate_required_opp() - Find required OPP for @src_table OPP.
return r;
}
+ if (!assert_single_clk(opp_table)) {
+ r = -EINVAL;
+ goto put_table;
+ }
+
mutex_lock(&opp_table->lock);
/* Do we have the frequency? */
list_for_each_entry(tmp_opp, &opp_table->opp_list, node) {
- if (tmp_opp->rate == freq) {
+ if (tmp_opp->rates[0] == freq) {
opp = tmp_opp;
break;
}
return r;
}
+ if (!assert_single_clk(opp_table)) {
+ r = -EINVAL;
+ goto put_table;
+ }
+
mutex_lock(&opp_table->lock);
/* Do we have the frequency? */
list_for_each_entry(tmp_opp, &opp_table->opp_list, node) {
- if (tmp_opp->rate == freq) {
+ if (tmp_opp->rates[0] == freq) {
opp = tmp_opp;
break;
}
opp);
dev_pm_opp_put(opp);
- goto adjust_put_table;
+ goto put_table;
adjust_unlock:
mutex_unlock(&opp_table->lock);
-adjust_put_table:
+put_table:
dev_pm_opp_put_opp_table(opp_table);
return r;
}
* the table if any of the mentioned functions have been invoked in the interim.
*/
int dev_pm_opp_init_cpufreq_table(struct device *dev,
- struct cpufreq_frequency_table **table)
+ struct cpufreq_frequency_table **opp_table)
{
struct dev_pm_opp *opp;
struct cpufreq_frequency_table *freq_table = NULL;
freq_table[i].driver_data = i;
freq_table[i].frequency = CPUFREQ_TABLE_END;
- *table = &freq_table[0];
+ *opp_table = &freq_table[0];
out:
if (ret)
* Free up the table allocated by dev_pm_opp_init_cpufreq_table
*/
void dev_pm_opp_free_cpufreq_table(struct device *dev,
- struct cpufreq_frequency_table **table)
+ struct cpufreq_frequency_table **opp_table)
{
- if (!table)
+ if (!opp_table)
return;
- kfree(*table);
- *table = NULL;
+ kfree(*opp_table);
+ *opp_table = NULL;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
#endif /* CONFIG_CPU_FREQ */
}
}
+static void opp_debug_create_clks(struct dev_pm_opp *opp,
+ struct opp_table *opp_table,
+ struct dentry *pdentry)
+{
+ char name[12];
+ int i;
+
+ if (opp_table->clk_count == 1) {
+ debugfs_create_ulong("rate_hz", S_IRUGO, pdentry, &opp->rates[0]);
+ return;
+ }
+
+ for (i = 0; i < opp_table->clk_count; i++) {
+ snprintf(name, sizeof(name), "rate_hz_%d", i);
+ debugfs_create_ulong(name, S_IRUGO, pdentry, &opp->rates[i]);
+ }
+}
+
static void opp_debug_create_supplies(struct dev_pm_opp *opp,
struct opp_table *opp_table,
struct dentry *pdentry)
* Get directory name for OPP.
*
* - Normally rate is unique to each OPP, use it to get unique opp-name.
- * - For some devices rate isn't available, use index instead.
+ * - For some devices rate isn't available or there are multiple, use
+ * index instead for them.
*/
- if (likely(opp->rate))
- id = opp->rate;
+ if (likely(opp_table->clk_count == 1 && opp->rates[0]))
+ id = opp->rates[0];
else
id = _get_opp_count(opp_table);
debugfs_create_bool("turbo", S_IRUGO, d, &opp->turbo);
debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend);
debugfs_create_u32("performance_state", S_IRUGO, d, &opp->pstate);
- debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate);
debugfs_create_u32("level", S_IRUGO, d, &opp->level);
debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
&opp->clock_latency_ns);
opp->of_name = of_node_full_name(opp->np);
debugfs_create_str("of_name", S_IRUGO, d, (char **)&opp->of_name);
+ opp_debug_create_clks(opp, opp_table, d);
opp_debug_create_supplies(opp, opp_table, d);
opp_debug_create_bw(opp, opp_table, d);
opp_table->np = opp_np;
_opp_table_alloc_required_tables(opp_table, dev, opp_np);
- of_node_put(opp_np);
}
void _of_clear_opp_table(struct opp_table *opp_table)
{
_opp_table_free_required_tables(opp_table);
+ of_node_put(opp_table->np);
}
/*
* Release all resources previously acquired with a call to
* _of_opp_alloc_required_opps().
*/
-void _of_opp_free_required_opps(struct opp_table *opp_table,
- struct dev_pm_opp *opp)
+static void _of_opp_free_required_opps(struct opp_table *opp_table,
+ struct dev_pm_opp *opp)
{
struct dev_pm_opp **required_opps = opp->required_opps;
int i;
kfree(required_opps);
}
+void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp)
+{
+ _of_opp_free_required_opps(opp_table, opp);
+ of_node_put(opp->np);
+}
+
/* Populate all required OPPs which are part of "required-opps" list */
static int _of_opp_alloc_required_opps(struct opp_table *opp_table,
struct dev_pm_opp *opp)
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
-static int _read_bw(struct dev_pm_opp *new_opp, struct opp_table *table,
+static int _read_rate(struct dev_pm_opp *new_opp, struct opp_table *opp_table,
+ struct device_node *np)
+{
+ struct property *prop;
+ int i, count, ret;
+ u64 *rates;
+
+ prop = of_find_property(np, "opp-hz", NULL);
+ if (!prop)
+ return -ENODEV;
+
+ count = prop->length / sizeof(u64);
+ if (opp_table->clk_count != count) {
+ pr_err("%s: Count mismatch between opp-hz and clk_count (%d %d)\n",
+ __func__, count, opp_table->clk_count);
+ return -EINVAL;
+ }
+
+ rates = kmalloc_array(count, sizeof(*rates), GFP_KERNEL);
+ if (!rates)
+ return -ENOMEM;
+
+ ret = of_property_read_u64_array(np, "opp-hz", rates, count);
+ if (ret) {
+ pr_err("%s: Error parsing opp-hz: %d\n", __func__, ret);
+ } else {
+ /*
+ * Rate is defined as an unsigned long in clk API, and so
+ * casting explicitly to its type. Must be fixed once rate is 64
+ * bit guaranteed in clk API.
+ */
+ for (i = 0; i < count; i++) {
+ new_opp->rates[i] = (unsigned long)rates[i];
+
+ /* This will happen for frequencies > 4.29 GHz */
+ WARN_ON(new_opp->rates[i] != rates[i]);
+ }
+ }
+
+ kfree(rates);
+
+ return ret;
+}
+
+static int _read_bw(struct dev_pm_opp *new_opp, struct opp_table *opp_table,
struct device_node *np, bool peak)
{
const char *name = peak ? "opp-peak-kBps" : "opp-avg-kBps";
return -ENODEV;
count = prop->length / sizeof(u32);
- if (table->path_count != count) {
+ if (opp_table->path_count != count) {
pr_err("%s: Mismatch between %s and paths (%d %d)\n",
- __func__, name, count, table->path_count);
+ __func__, name, count, opp_table->path_count);
return -EINVAL;
}
return ret;
}
-static int _read_opp_key(struct dev_pm_opp *new_opp, struct opp_table *table,
- struct device_node *np, bool *rate_not_available)
+static int _read_opp_key(struct dev_pm_opp *new_opp,
+ struct opp_table *opp_table, struct device_node *np)
{
bool found = false;
- u64 rate;
int ret;
- ret = of_property_read_u64(np, "opp-hz", &rate);
- if (!ret) {
- /*
- * Rate is defined as an unsigned long in clk API, and so
- * casting explicitly to its type. Must be fixed once rate is 64
- * bit guaranteed in clk API.
- */
- new_opp->rate = (unsigned long)rate;
+ ret = _read_rate(new_opp, opp_table, np);
+ if (!ret)
found = true;
- }
- *rate_not_available = !!ret;
+ else if (ret != -ENODEV)
+ return ret;
/*
* Bandwidth consists of peak and average (optional) values:
* opp-peak-kBps = <path1_value path2_value>;
* opp-avg-kBps = <path1_value path2_value>;
*/
- ret = _read_bw(new_opp, table, np, true);
+ ret = _read_bw(new_opp, opp_table, np, true);
if (!ret) {
found = true;
- ret = _read_bw(new_opp, table, np, false);
+ ret = _read_bw(new_opp, opp_table, np, false);
}
/* The properties were found but we failed to parse them */
struct dev_pm_opp *new_opp;
u32 val;
int ret;
- bool rate_not_available = false;
new_opp = _opp_allocate(opp_table);
if (!new_opp)
return ERR_PTR(-ENOMEM);
- ret = _read_opp_key(new_opp, opp_table, np, &rate_not_available);
+ ret = _read_opp_key(new_opp, opp_table, np);
if (ret < 0) {
dev_err(dev, "%s: opp key field not found\n", __func__);
goto free_opp;
/* Check if the OPP supports hardware's hierarchy of versions or not */
if (!_opp_is_supported(dev, opp_table, np)) {
- dev_dbg(dev, "OPP not supported by hardware: %lu\n",
- new_opp->rate);
+ dev_dbg(dev, "OPP not supported by hardware: %s\n",
+ of_node_full_name(np));
goto free_opp;
}
new_opp->turbo = of_property_read_bool(np, "turbo-mode");
- new_opp->np = np;
+ new_opp->np = of_node_get(np);
new_opp->dynamic = false;
new_opp->available = true;
if (opp_table->is_genpd)
new_opp->pstate = pm_genpd_opp_to_performance_state(dev, new_opp);
- ret = _opp_add(dev, new_opp, opp_table, rate_not_available);
+ ret = _opp_add(dev, new_opp, opp_table);
if (ret) {
/* Don't return error for duplicate OPPs */
if (ret == -EBUSY)
/* OPP to select on device suspend */
if (of_property_read_bool(np, "opp-suspend")) {
if (opp_table->suspend_opp) {
- /* Pick the OPP with higher rate as suspend OPP */
- if (new_opp->rate > opp_table->suspend_opp->rate) {
+ /* Pick the OPP with higher rate/bw/level as suspend OPP */
+ if (_opp_compare_key(opp_table, new_opp, opp_table->suspend_opp) == 1) {
opp_table->suspend_opp->suspend = false;
new_opp->suspend = true;
opp_table->suspend_opp = new_opp;
opp_table->clock_latency_ns_max = new_opp->clock_latency_ns;
pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu level:%u\n",
- __func__, new_opp->turbo, new_opp->rate,
+ __func__, new_opp->turbo, new_opp->rates[0],
new_opp->supplies[0].u_volt, new_opp->supplies[0].u_volt_min,
new_opp->supplies[0].u_volt_max, new_opp->clock_latency_ns,
new_opp->level);
return ret;
}
-static int _of_add_table_indexed(struct device *dev, int index, bool getclk)
+static int _of_add_table_indexed(struct device *dev, int index)
{
struct opp_table *opp_table;
int ret, count;
index = 0;
}
- opp_table = _add_opp_table_indexed(dev, index, getclk);
+ opp_table = _add_opp_table_indexed(dev, index, true);
if (IS_ERR(opp_table))
return PTR_ERR(opp_table);
dev_pm_opp_of_remove_table(data);
}
-static int _devm_of_add_table_indexed(struct device *dev, int index, bool getclk)
+static int _devm_of_add_table_indexed(struct device *dev, int index)
{
int ret;
- ret = _of_add_table_indexed(dev, index, getclk);
+ ret = _of_add_table_indexed(dev, index);
if (ret)
return ret;
*/
int devm_pm_opp_of_add_table(struct device *dev)
{
- return _devm_of_add_table_indexed(dev, 0, true);
+ return _devm_of_add_table_indexed(dev, 0);
}
EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table);
*/
int dev_pm_opp_of_add_table(struct device *dev)
{
- return _of_add_table_indexed(dev, 0, true);
+ return _of_add_table_indexed(dev, 0);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
*/
int dev_pm_opp_of_add_table_indexed(struct device *dev, int index)
{
- return _of_add_table_indexed(dev, index, true);
+ return _of_add_table_indexed(dev, index);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed);
*/
int devm_pm_opp_of_add_table_indexed(struct device *dev, int index)
{
- return _devm_of_add_table_indexed(dev, index, true);
+ return _devm_of_add_table_indexed(dev, index);
}
EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table_indexed);
-/**
- * dev_pm_opp_of_add_table_noclk() - Initialize indexed opp table from device
- * tree without getting clk for device.
- * @dev: device pointer used to lookup OPP table.
- * @index: Index number.
- *
- * Register the initial OPP table with the OPP library for given device only
- * using the "operating-points-v2" property. Do not try to get the clk for the
- * device.
- *
- * Return: Refer to dev_pm_opp_of_add_table() for return values.
- */
-int dev_pm_opp_of_add_table_noclk(struct device *dev, int index)
-{
- return _of_add_table_indexed(dev, index, false);
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_noclk);
-
-/**
- * devm_pm_opp_of_add_table_noclk() - Initialize indexed opp table from device
- * tree without getting clk for device.
- * @dev: device pointer used to lookup OPP table.
- * @index: Index number.
- *
- * This is a resource-managed variant of dev_pm_opp_of_add_table_noclk().
- */
-int devm_pm_opp_of_add_table_noclk(struct device *dev, int index)
-{
- return _devm_of_add_table_indexed(dev, index, false);
-}
-EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table_noclk);
-
/* CPU device specific helpers */
/**
extern struct list_head opp_tables, lazy_opp_tables;
+/* OPP Config flags */
+#define OPP_CONFIG_CLK BIT(0)
+#define OPP_CONFIG_REGULATOR BIT(1)
+#define OPP_CONFIG_REGULATOR_HELPER BIT(2)
+#define OPP_CONFIG_PROP_NAME BIT(3)
+#define OPP_CONFIG_SUPPORTED_HW BIT(4)
+#define OPP_CONFIG_GENPD BIT(5)
+
+/**
+ * struct opp_config_data - data for set config operations
+ * @opp_table: OPP table
+ * @flags: OPP config flags
+ *
+ * This structure stores the OPP config information for each OPP table
+ * configuration by the callers.
+ */
+struct opp_config_data {
+ struct opp_table *opp_table;
+ unsigned int flags;
+};
+
/*
* Internal data structure organization with the OPP layer library is as
* follows:
* @suspend: true if suspend OPP
* @removed: flag indicating that OPP's reference is dropped by OPP core.
* @pstate: Device's power domain's performance state.
- * @rate: Frequency in hertz
+ * @rates: Frequencies in hertz
* @level: Performance level
* @supplies: Power supplies voltage/current values
* @bandwidth: Interconnect bandwidth values
bool suspend;
bool removed;
unsigned int pstate;
- unsigned long rate;
+ unsigned long *rates;
unsigned int level;
struct dev_pm_opp_supply *supplies;
* @clock_latency_ns_max: Max clock latency in nanoseconds.
* @parsed_static_opps: Count of devices for which OPPs are initialized from DT.
* @shared_opp: OPP is shared between multiple devices.
- * @current_rate: Currently configured frequency.
+ * @rate_clk_single: Currently configured frequency for single clk.
* @current_opp: Currently configured OPP for the table.
* @suspend_opp: Pointer to OPP to be used during device suspend.
* @genpd_virt_dev_lock: Mutex protecting the genpd virtual device pointers.
* @supported_hw: Array of version number to support.
* @supported_hw_count: Number of elements in supported_hw array.
* @prop_name: A name to postfix to many DT properties, while parsing them.
- * @clk: Device's clock handle
+ * @config_clks: Platform specific config_clks() callback.
+ * @clks: Device's clock handles, for multiple clocks.
+ * @clk: Device's clock handle, for single clock.
+ * @clk_count: Number of clocks.
+ * @config_regulators: Platform specific config_regulators() callback.
* @regulators: Supply regulators
* @regulator_count: Number of power supply regulators. Its value can be -1
* (uninitialized), 0 (no opp-microvolt property) or > 0 (has opp-microvolt
* @enabled: Set to true if the device's resources are enabled/configured.
* @genpd_performance_state: Device's power domain support performance state.
* @is_genpd: Marks if the OPP table belongs to a genpd.
- * @set_opp: Platform specific set_opp callback
- * @sod_supplies: Set opp data supplies
- * @set_opp_data: Data to be passed to set_opp callback
* @dentry: debugfs dentry pointer of the real device directory (not links).
* @dentry_name: Name of the real dentry.
*
unsigned int parsed_static_opps;
enum opp_table_access shared_opp;
- unsigned long current_rate;
+ unsigned long rate_clk_single;
struct dev_pm_opp *current_opp;
struct dev_pm_opp *suspend_opp;
unsigned int *supported_hw;
unsigned int supported_hw_count;
const char *prop_name;
+ config_clks_t config_clks;
+ struct clk **clks;
struct clk *clk;
+ int clk_count;
+ config_regulators_t config_regulators;
struct regulator **regulators;
int regulator_count;
struct icc_path **paths;
bool genpd_performance_state;
bool is_genpd;
- int (*set_opp)(struct dev_pm_set_opp_data *data);
- struct dev_pm_opp_supply *sod_supplies;
- struct dev_pm_set_opp_data *set_opp_data;
-
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;
char dentry_name[NAME_MAX];
struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table);
struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table);
void _opp_free(struct dev_pm_opp *opp);
-int _opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2);
-int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available);
+int _opp_compare_key(struct opp_table *opp_table, struct dev_pm_opp *opp1, struct dev_pm_opp *opp2);
+int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table);
int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic);
void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu);
struct opp_table *_add_opp_table_indexed(struct device *dev, int index, bool getclk);
void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index);
void _of_clear_opp_table(struct opp_table *opp_table);
struct opp_table *_managed_opp(struct device *dev, int index);
-void _of_opp_free_required_opps(struct opp_table *opp_table,
- struct dev_pm_opp *opp);
+void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp);
#else
static inline void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index) {}
static inline void _of_clear_opp_table(struct opp_table *opp_table) {}
static inline struct opp_table *_managed_opp(struct device *dev, int index) { return NULL; }
-static inline void _of_opp_free_required_opps(struct opp_table *opp_table,
- struct dev_pm_opp *opp) {}
+static inline void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp) {}
#endif
#ifdef CONFIG_DEBUG_FS
* @vdd_table: Optimized voltage mapping table
* @num_vdd_table: number of entries in vdd_table
* @vdd_absolute_max_voltage_uv: absolute maximum voltage in UV for the supply
+ * @old_supplies: Placeholder for supplies information for old OPP.
+ * @new_supplies: Placeholder for supplies information for new OPP.
*/
struct ti_opp_supply_data {
struct ti_opp_supply_optimum_voltage_table *vdd_table;
u32 num_vdd_table;
u32 vdd_absolute_max_voltage_uv;
+ struct dev_pm_opp_supply old_supplies[2];
+ struct dev_pm_opp_supply new_supplies[2];
};
static struct ti_opp_supply_data opp_data;
return 0;
}
-/**
- * ti_opp_supply_set_opp() - do the opp supply transition
- * @data: information on regulators and new and old opps provided by
- * opp core to use in transition
- *
- * Return: If successful, 0, else appropriate error value.
- */
-static int ti_opp_supply_set_opp(struct dev_pm_set_opp_data *data)
+/* Do the opp supply transition */
+static int ti_opp_config_regulators(struct device *dev,
+ struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp,
+ struct regulator **regulators, unsigned int count)
{
- struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0];
- struct dev_pm_opp_supply *old_supply_vbb = &data->old_opp.supplies[1];
- struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0];
- struct dev_pm_opp_supply *new_supply_vbb = &data->new_opp.supplies[1];
- struct device *dev = data->dev;
- unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate;
- struct clk *clk = data->clk;
- struct regulator *vdd_reg = data->regulators[0];
- struct regulator *vbb_reg = data->regulators[1];
+ struct dev_pm_opp_supply *old_supply_vdd = &opp_data.old_supplies[0];
+ struct dev_pm_opp_supply *old_supply_vbb = &opp_data.old_supplies[1];
+ struct dev_pm_opp_supply *new_supply_vdd = &opp_data.new_supplies[0];
+ struct dev_pm_opp_supply *new_supply_vbb = &opp_data.new_supplies[1];
+ struct regulator *vdd_reg = regulators[0];
+ struct regulator *vbb_reg = regulators[1];
+ unsigned long old_freq, freq;
int vdd_uv;
int ret;
+ /* We must have two regulators here */
+ WARN_ON(count != 2);
+
+ /* Fetch supplies and freq information from OPP core */
+ ret = dev_pm_opp_get_supplies(new_opp, opp_data.new_supplies);
+ WARN_ON(ret);
+
+ old_freq = dev_pm_opp_get_freq(old_opp);
+ freq = dev_pm_opp_get_freq(new_opp);
+ WARN_ON(!old_freq || !freq);
+
vdd_uv = _get_optimal_vdd_voltage(dev, &opp_data,
new_supply_vdd->u_volt);
ret = _opp_set_voltage(dev, new_supply_vbb, 0, vbb_reg, "vbb");
if (ret)
goto restore_voltage;
- }
-
- /* Change frequency */
- dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n",
- __func__, old_freq, freq);
-
- ret = clk_set_rate(clk, freq);
- if (ret) {
- dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
- ret);
- goto restore_voltage;
- }
-
- /* Scaling down? Scale voltage after frequency */
- if (freq < old_freq) {
+ } else {
ret = _opp_set_voltage(dev, new_supply_vbb, 0, vbb_reg, "vbb");
if (ret)
- goto restore_freq;
+ goto restore_voltage;
ret = _opp_set_voltage(dev, new_supply_vdd, vdd_uv, vdd_reg,
"vdd");
if (ret)
- goto restore_freq;
+ goto restore_voltage;
}
return 0;
-restore_freq:
- ret = clk_set_rate(clk, old_freq);
- if (ret)
- dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
- __func__, old_freq);
restore_voltage:
+ /* Fetch old supplies information only if required */
+ ret = dev_pm_opp_get_supplies(old_opp, opp_data.old_supplies);
+ WARN_ON(ret);
+
/* This shouldn't harm even if the voltages weren't updated earlier */
if (old_supply_vdd->u_volt) {
ret = _opp_set_voltage(dev, old_supply_vbb, 0, vbb_reg, "vbb");
return ret;
}
- ret = PTR_ERR_OR_ZERO(dev_pm_opp_register_set_opp_helper(cpu_dev,
- ti_opp_supply_set_opp));
- if (ret)
+ ret = dev_pm_opp_set_config_regulators(cpu_dev, ti_opp_config_regulators);
+ if (ret < 0)
_free_optimized_voltages(dev, &opp_data);
return ret;
config PCI_ATS
bool
+config PCI_DOE
+ bool
+
config PCI_ECAM
bool
obj-$(CONFIG_PCI_P2PDMA) += p2pdma.o
obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
obj-$(CONFIG_VGA_ARB) += vgaarb.o
+obj-$(CONFIG_PCI_DOE) += doe.o
# Endpoint library must be initialized before its users
obj-$(CONFIG_PCI_ENDPOINT) += endpoint/
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Data Object Exchange
+ * PCIe r6.0, sec 6.30 DOE
+ *
+ * Copyright (C) 2021 Huawei
+ * Jonathan Cameron <Jonathan.Cameron@huawei.com>
+ *
+ * Copyright (C) 2022 Intel Corporation
+ * Ira Weiny <ira.weiny@intel.com>
+ */
+
+#define dev_fmt(fmt) "DOE: " fmt
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/pci-doe.h>
+#include <linux/workqueue.h>
+
+#define PCI_DOE_PROTOCOL_DISCOVERY 0
+
+/* Timeout of 1 second from 6.30.2 Operation, PCI Spec r6.0 */
+#define PCI_DOE_TIMEOUT HZ
+#define PCI_DOE_POLL_INTERVAL (PCI_DOE_TIMEOUT / 128)
+
+#define PCI_DOE_FLAG_CANCEL 0
+#define PCI_DOE_FLAG_DEAD 1
+
+/**
+ * struct pci_doe_mb - State for a single DOE mailbox
+ *
+ * This state is used to manage a single DOE mailbox capability. All fields
+ * should be considered opaque to the consumers and the structure passed into
+ * the helpers below after being created by devm_pci_doe_create()
+ *
+ * @pdev: PCI device this mailbox belongs to
+ * @cap_offset: Capability offset
+ * @prots: Array of protocols supported (encoded as long values)
+ * @wq: Wait queue for work item
+ * @work_queue: Queue of pci_doe_work items
+ * @flags: Bit array of PCI_DOE_FLAG_* flags
+ */
+struct pci_doe_mb {
+ struct pci_dev *pdev;
+ u16 cap_offset;
+ struct xarray prots;
+
+ wait_queue_head_t wq;
+ struct workqueue_struct *work_queue;
+ unsigned long flags;
+};
+
+static int pci_doe_wait(struct pci_doe_mb *doe_mb, unsigned long timeout)
+{
+ if (wait_event_timeout(doe_mb->wq,
+ test_bit(PCI_DOE_FLAG_CANCEL, &doe_mb->flags),
+ timeout))
+ return -EIO;
+ return 0;
+}
+
+static void pci_doe_write_ctrl(struct pci_doe_mb *doe_mb, u32 val)
+{
+ struct pci_dev *pdev = doe_mb->pdev;
+ int offset = doe_mb->cap_offset;
+
+ pci_write_config_dword(pdev, offset + PCI_DOE_CTRL, val);
+}
+
+static int pci_doe_abort(struct pci_doe_mb *doe_mb)
+{
+ struct pci_dev *pdev = doe_mb->pdev;
+ int offset = doe_mb->cap_offset;
+ unsigned long timeout_jiffies;
+
+ pci_dbg(pdev, "[%x] Issuing Abort\n", offset);
+
+ timeout_jiffies = jiffies + PCI_DOE_TIMEOUT;
+ pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_ABORT);
+
+ do {
+ int rc;
+ u32 val;
+
+ rc = pci_doe_wait(doe_mb, PCI_DOE_POLL_INTERVAL);
+ if (rc)
+ return rc;
+ pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
+
+ /* Abort success! */
+ if (!FIELD_GET(PCI_DOE_STATUS_ERROR, val) &&
+ !FIELD_GET(PCI_DOE_STATUS_BUSY, val))
+ return 0;
+
+ } while (!time_after(jiffies, timeout_jiffies));
+
+ /* Abort has timed out and the MB is dead */
+ pci_err(pdev, "[%x] ABORT timed out\n", offset);
+ return -EIO;
+}
+
+static int pci_doe_send_req(struct pci_doe_mb *doe_mb,
+ struct pci_doe_task *task)
+{
+ struct pci_dev *pdev = doe_mb->pdev;
+ int offset = doe_mb->cap_offset;
+ u32 val;
+ int i;
+
+ /*
+ * Check the DOE busy bit is not set. If it is set, this could indicate
+ * someone other than Linux (e.g. firmware) is using the mailbox. Note
+ * it is expected that firmware and OS will negotiate access rights via
+ * an, as yet to be defined, method.
+ */
+ pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
+ if (FIELD_GET(PCI_DOE_STATUS_BUSY, val))
+ return -EBUSY;
+
+ if (FIELD_GET(PCI_DOE_STATUS_ERROR, val))
+ return -EIO;
+
+ /* Write DOE Header */
+ val = FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_VID, task->prot.vid) |
+ FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, task->prot.type);
+ pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, val);
+ /* Length is 2 DW of header + length of payload in DW */
+ pci_write_config_dword(pdev, offset + PCI_DOE_WRITE,
+ FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH,
+ 2 + task->request_pl_sz /
+ sizeof(u32)));
+ for (i = 0; i < task->request_pl_sz / sizeof(u32); i++)
+ pci_write_config_dword(pdev, offset + PCI_DOE_WRITE,
+ task->request_pl[i]);
+
+ pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_GO);
+
+ return 0;
+}
+
+static bool pci_doe_data_obj_ready(struct pci_doe_mb *doe_mb)
+{
+ struct pci_dev *pdev = doe_mb->pdev;
+ int offset = doe_mb->cap_offset;
+ u32 val;
+
+ pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
+ if (FIELD_GET(PCI_DOE_STATUS_DATA_OBJECT_READY, val))
+ return true;
+ return false;
+}
+
+static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *task)
+{
+ struct pci_dev *pdev = doe_mb->pdev;
+ int offset = doe_mb->cap_offset;
+ size_t length, payload_length;
+ u32 val;
+ int i;
+
+ /* Read the first dword to get the protocol */
+ pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
+ if ((FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_VID, val) != task->prot.vid) ||
+ (FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, val) != task->prot.type)) {
+ dev_err_ratelimited(&pdev->dev, "[%x] expected [VID, Protocol] = [%04x, %02x], got [%04x, %02x]\n",
+ doe_mb->cap_offset, task->prot.vid, task->prot.type,
+ FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_VID, val),
+ FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, val));
+ return -EIO;
+ }
+
+ pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
+ /* Read the second dword to get the length */
+ pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
+ pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
+
+ length = FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, val);
+ if (length > SZ_1M || length < 2)
+ return -EIO;
+
+ /* First 2 dwords have already been read */
+ length -= 2;
+ payload_length = min(length, task->response_pl_sz / sizeof(u32));
+ /* Read the rest of the response payload */
+ for (i = 0; i < payload_length; i++) {
+ pci_read_config_dword(pdev, offset + PCI_DOE_READ,
+ &task->response_pl[i]);
+ /* Prior to the last ack, ensure Data Object Ready */
+ if (i == (payload_length - 1) && !pci_doe_data_obj_ready(doe_mb))
+ return -EIO;
+ pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
+ }
+
+ /* Flush excess length */
+ for (; i < length; i++) {
+ pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
+ pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
+ }
+
+ /* Final error check to pick up on any since Data Object Ready */
+ pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
+ if (FIELD_GET(PCI_DOE_STATUS_ERROR, val))
+ return -EIO;
+
+ return min(length, task->response_pl_sz / sizeof(u32)) * sizeof(u32);
+}
+
+static void signal_task_complete(struct pci_doe_task *task, int rv)
+{
+ task->rv = rv;
+ task->complete(task);
+}
+
+static void signal_task_abort(struct pci_doe_task *task, int rv)
+{
+ struct pci_doe_mb *doe_mb = task->doe_mb;
+ struct pci_dev *pdev = doe_mb->pdev;
+
+ if (pci_doe_abort(doe_mb)) {
+ /*
+ * If the device can't process an abort; set the mailbox dead
+ * - no more submissions
+ */
+ pci_err(pdev, "[%x] Abort failed marking mailbox dead\n",
+ doe_mb->cap_offset);
+ set_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags);
+ }
+ signal_task_complete(task, rv);
+}
+
+static void doe_statemachine_work(struct work_struct *work)
+{
+ struct pci_doe_task *task = container_of(work, struct pci_doe_task,
+ work);
+ struct pci_doe_mb *doe_mb = task->doe_mb;
+ struct pci_dev *pdev = doe_mb->pdev;
+ int offset = doe_mb->cap_offset;
+ unsigned long timeout_jiffies;
+ u32 val;
+ int rc;
+
+ if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags)) {
+ signal_task_complete(task, -EIO);
+ return;
+ }
+
+ /* Send request */
+ rc = pci_doe_send_req(doe_mb, task);
+ if (rc) {
+ /*
+ * The specification does not provide any guidance on how to
+ * resolve conflicting requests from other entities.
+ * Furthermore, it is likely that busy will not be detected
+ * most of the time. Flag any detection of status busy with an
+ * error.
+ */
+ if (rc == -EBUSY)
+ dev_err_ratelimited(&pdev->dev, "[%x] busy detected; another entity is sending conflicting requests\n",
+ offset);
+ signal_task_abort(task, rc);
+ return;
+ }
+
+ timeout_jiffies = jiffies + PCI_DOE_TIMEOUT;
+ /* Poll for response */
+retry_resp:
+ pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
+ if (FIELD_GET(PCI_DOE_STATUS_ERROR, val)) {
+ signal_task_abort(task, -EIO);
+ return;
+ }
+
+ if (!FIELD_GET(PCI_DOE_STATUS_DATA_OBJECT_READY, val)) {
+ if (time_after(jiffies, timeout_jiffies)) {
+ signal_task_abort(task, -EIO);
+ return;
+ }
+ rc = pci_doe_wait(doe_mb, PCI_DOE_POLL_INTERVAL);
+ if (rc) {
+ signal_task_abort(task, rc);
+ return;
+ }
+ goto retry_resp;
+ }
+
+ rc = pci_doe_recv_resp(doe_mb, task);
+ if (rc < 0) {
+ signal_task_abort(task, rc);
+ return;
+ }
+
+ signal_task_complete(task, rc);
+}
+
+static void pci_doe_task_complete(struct pci_doe_task *task)
+{
+ complete(task->private);
+}
+
+static int pci_doe_discovery(struct pci_doe_mb *doe_mb, u8 *index, u16 *vid,
+ u8 *protocol)
+{
+ u32 request_pl = FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX,
+ *index);
+ u32 response_pl;
+ DECLARE_COMPLETION_ONSTACK(c);
+ struct pci_doe_task task = {
+ .prot.vid = PCI_VENDOR_ID_PCI_SIG,
+ .prot.type = PCI_DOE_PROTOCOL_DISCOVERY,
+ .request_pl = &request_pl,
+ .request_pl_sz = sizeof(request_pl),
+ .response_pl = &response_pl,
+ .response_pl_sz = sizeof(response_pl),
+ .complete = pci_doe_task_complete,
+ .private = &c,
+ };
+ int rc;
+
+ rc = pci_doe_submit_task(doe_mb, &task);
+ if (rc < 0)
+ return rc;
+
+ wait_for_completion(&c);
+
+ if (task.rv != sizeof(response_pl))
+ return -EIO;
+
+ *vid = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID, response_pl);
+ *protocol = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL,
+ response_pl);
+ *index = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_NEXT_INDEX,
+ response_pl);
+
+ return 0;
+}
+
+static void *pci_doe_xa_prot_entry(u16 vid, u8 prot)
+{
+ return xa_mk_value((vid << 8) | prot);
+}
+
+static int pci_doe_cache_protocols(struct pci_doe_mb *doe_mb)
+{
+ u8 index = 0;
+ u8 xa_idx = 0;
+
+ do {
+ int rc;
+ u16 vid;
+ u8 prot;
+
+ rc = pci_doe_discovery(doe_mb, &index, &vid, &prot);
+ if (rc)
+ return rc;
+
+ pci_dbg(doe_mb->pdev,
+ "[%x] Found protocol %d vid: %x prot: %x\n",
+ doe_mb->cap_offset, xa_idx, vid, prot);
+
+ rc = xa_insert(&doe_mb->prots, xa_idx++,
+ pci_doe_xa_prot_entry(vid, prot), GFP_KERNEL);
+ if (rc)
+ return rc;
+ } while (index);
+
+ return 0;
+}
+
+static void pci_doe_xa_destroy(void *mb)
+{
+ struct pci_doe_mb *doe_mb = mb;
+
+ xa_destroy(&doe_mb->prots);
+}
+
+static void pci_doe_destroy_workqueue(void *mb)
+{
+ struct pci_doe_mb *doe_mb = mb;
+
+ destroy_workqueue(doe_mb->work_queue);
+}
+
+static void pci_doe_flush_mb(void *mb)
+{
+ struct pci_doe_mb *doe_mb = mb;
+
+ /* Stop all pending work items from starting */
+ set_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags);
+
+ /* Cancel an in progress work item, if necessary */
+ set_bit(PCI_DOE_FLAG_CANCEL, &doe_mb->flags);
+ wake_up(&doe_mb->wq);
+
+ /* Flush all work items */
+ flush_workqueue(doe_mb->work_queue);
+}
+
+/**
+ * pcim_doe_create_mb() - Create a DOE mailbox object
+ *
+ * @pdev: PCI device to create the DOE mailbox for
+ * @cap_offset: Offset of the DOE mailbox
+ *
+ * Create a single mailbox object to manage the mailbox protocol at the
+ * cap_offset specified.
+ *
+ * RETURNS: created mailbox object on success
+ * ERR_PTR(-errno) on failure
+ */
+struct pci_doe_mb *pcim_doe_create_mb(struct pci_dev *pdev, u16 cap_offset)
+{
+ struct pci_doe_mb *doe_mb;
+ struct device *dev = &pdev->dev;
+ int rc;
+
+ doe_mb = devm_kzalloc(dev, sizeof(*doe_mb), GFP_KERNEL);
+ if (!doe_mb)
+ return ERR_PTR(-ENOMEM);
+
+ doe_mb->pdev = pdev;
+ doe_mb->cap_offset = cap_offset;
+ init_waitqueue_head(&doe_mb->wq);
+
+ xa_init(&doe_mb->prots);
+ rc = devm_add_action(dev, pci_doe_xa_destroy, doe_mb);
+ if (rc)
+ return ERR_PTR(rc);
+
+ doe_mb->work_queue = alloc_ordered_workqueue("%s %s DOE [%x]", 0,
+ dev_driver_string(&pdev->dev),
+ pci_name(pdev),
+ doe_mb->cap_offset);
+ if (!doe_mb->work_queue) {
+ pci_err(pdev, "[%x] failed to allocate work queue\n",
+ doe_mb->cap_offset);
+ return ERR_PTR(-ENOMEM);
+ }
+ rc = devm_add_action_or_reset(dev, pci_doe_destroy_workqueue, doe_mb);
+ if (rc)
+ return ERR_PTR(rc);
+
+ /* Reset the mailbox by issuing an abort */
+ rc = pci_doe_abort(doe_mb);
+ if (rc) {
+ pci_err(pdev, "[%x] failed to reset mailbox with abort command : %d\n",
+ doe_mb->cap_offset, rc);
+ return ERR_PTR(rc);
+ }
+
+ /*
+ * The state machine and the mailbox should be in sync now;
+ * Set up mailbox flush prior to using the mailbox to query protocols.
+ */
+ rc = devm_add_action_or_reset(dev, pci_doe_flush_mb, doe_mb);
+ if (rc)
+ return ERR_PTR(rc);
+
+ rc = pci_doe_cache_protocols(doe_mb);
+ if (rc) {
+ pci_err(pdev, "[%x] failed to cache protocols : %d\n",
+ doe_mb->cap_offset, rc);
+ return ERR_PTR(rc);
+ }
+
+ return doe_mb;
+}
+EXPORT_SYMBOL_GPL(pcim_doe_create_mb);
+
+/**
+ * pci_doe_supports_prot() - Return if the DOE instance supports the given
+ * protocol
+ * @doe_mb: DOE mailbox capability to query
+ * @vid: Protocol Vendor ID
+ * @type: Protocol type
+ *
+ * RETURNS: True if the DOE mailbox supports the protocol specified
+ */
+bool pci_doe_supports_prot(struct pci_doe_mb *doe_mb, u16 vid, u8 type)
+{
+ unsigned long index;
+ void *entry;
+
+ /* The discovery protocol must always be supported */
+ if (vid == PCI_VENDOR_ID_PCI_SIG && type == PCI_DOE_PROTOCOL_DISCOVERY)
+ return true;
+
+ xa_for_each(&doe_mb->prots, index, entry)
+ if (entry == pci_doe_xa_prot_entry(vid, type))
+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(pci_doe_supports_prot);
+
+/**
+ * pci_doe_submit_task() - Submit a task to be processed by the state machine
+ *
+ * @doe_mb: DOE mailbox capability to submit to
+ * @task: task to be queued
+ *
+ * Submit a DOE task (request/response) to the DOE mailbox to be processed.
+ * Returns upon queueing the task object. If the queue is full this function
+ * will sleep until there is room in the queue.
+ *
+ * task->complete will be called when the state machine is done processing this
+ * task.
+ *
+ * Excess data will be discarded.
+ *
+ * RETURNS: 0 when task has been successfully queued, -ERRNO on error
+ */
+int pci_doe_submit_task(struct pci_doe_mb *doe_mb, struct pci_doe_task *task)
+{
+ if (!pci_doe_supports_prot(doe_mb, task->prot.vid, task->prot.type))
+ return -EINVAL;
+
+ /*
+ * DOE requests must be a whole number of DW and the response needs to
+ * be big enough for at least 1 DW
+ */
+ if (task->request_pl_sz % sizeof(u32) ||
+ task->response_pl_sz < sizeof(u32))
+ return -EINVAL;
+
+ if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags))
+ return -EIO;
+
+ task->doe_mb = doe_mb;
+ INIT_WORK(&task->work, doe_statemachine_work);
+ queue_work(doe_mb->work_queue, &task->work);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pci_doe_submit_task);
static bool pci_bus_crs_vendor_id(u32 l)
{
- return (l & 0xffff) == 0x0001;
+ return (l & 0xffff) == PCI_VENDOR_ID_PCI_SIG;
}
static bool pci_bus_wait_crs(struct pci_bus *bus, int devfn, u32 *l,
LED controller.
config PINCTRL_OCELOT
- bool "Pinctrl driver for the Microsemi Ocelot and Jaguar2 SoCs"
+ tristate "Pinctrl driver for the Microsemi Ocelot and Jaguar2 SoCs"
depends on OF
depends on HAS_IOMEM
select GPIOLIB
SIG_EXPR_LIST_ALIAS(pin, sig, group)
/**
- * Similar to the above, but for pins with a dual expressions (DE) and
+ * Similar to the above, but for pins with a dual expressions (DE)
* and a single group (SG) of pins.
*
* @pin: The pin the signal will be routed to
}
}
-static void bcm2835_gpio_irq_enable(struct irq_data *data)
+static void bcm2835_gpio_irq_unmask(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
unsigned bank = GPIO_REG_OFFSET(gpio);
unsigned long flags;
+ gpiochip_enable_irq(chip, gpio);
+
raw_spin_lock_irqsave(&pc->irq_lock[bank], flags);
set_bit(offset, &pc->enabled_irq_map[bank]);
bcm2835_gpio_irq_config(pc, gpio, true);
raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
}
-static void bcm2835_gpio_irq_disable(struct irq_data *data)
+static void bcm2835_gpio_irq_mask(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
bcm2835_gpio_set_bit(pc, GPEDS0, gpio);
clear_bit(offset, &pc->enabled_irq_map[bank]);
raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
+
+ gpiochip_disable_irq(chip, gpio);
}
static int __bcm2835_gpio_irq_set_type_disabled(struct bcm2835_pinctrl *pc,
return ret;
}
-static struct irq_chip bcm2835_gpio_irq_chip = {
+static const struct irq_chip bcm2835_gpio_irq_chip = {
.name = MODULE_NAME,
- .irq_enable = bcm2835_gpio_irq_enable,
- .irq_disable = bcm2835_gpio_irq_disable,
.irq_set_type = bcm2835_gpio_irq_set_type,
.irq_ack = bcm2835_gpio_irq_ack,
- .irq_mask = bcm2835_gpio_irq_disable,
- .irq_unmask = bcm2835_gpio_irq_enable,
+ .irq_mask = bcm2835_gpio_irq_mask,
+ .irq_unmask = bcm2835_gpio_irq_unmask,
.irq_set_wake = bcm2835_gpio_irq_set_wake,
- .flags = IRQCHIP_MASK_ON_SUSPEND,
+ .flags = (IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE),
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static int bcm2835_pctl_get_groups_count(struct pinctrl_dev *pctldev)
pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
girq = &pc->gpio_chip.irq;
- girq->chip = &bcm2835_gpio_irq_chip;
+ gpio_irq_chip_set_chip(girq, &bcm2835_gpio_irq_chip);
girq->parent_handler = bcm2835_gpio_irq_handler;
girq->num_parents = BCM2835_NUM_IRQS;
girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS,
mutex_lock(&pinctrldev_list_mutex);
list_for_each_entry(pctldev, &pinctrldev_list, node)
- if (pctldev->dev->of_node == np) {
+ if (device_match_of_node(pctldev->dev, np)) {
mutex_unlock(&pinctrldev_list_mutex);
return pctldev;
}
{ .compatible = "fsl,imx93-iomuxc", },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, imx93_pinctrl_of_match);
static int imx93_pinctrl_probe(struct platform_device *pdev)
{
This pinctrl driver provides an interface that allows configuring
of Intel Lewisburg pins and using them as GPIOs.
+config PINCTRL_METEORLAKE
+ tristate "Intel Meteor Lake pinctrl and GPIO driver"
+ depends on ACPI
+ select PINCTRL_INTEL
+ help
+ This pinctrl driver provides an interface that allows configuring
+ of Intel Meteor Lake pins and using them as GPIOs.
+
config PINCTRL_SUNRISEPOINT
tristate "Intel Sunrisepoint pinctrl and GPIO driver"
depends on ACPI
obj-$(CONFIG_PINCTRL_JASPERLAKE) += pinctrl-jasperlake.o
obj-$(CONFIG_PINCTRL_LAKEFIELD) += pinctrl-lakefield.o
obj-$(CONFIG_PINCTRL_LEWISBURG) += pinctrl-lewisburg.o
+obj-$(CONFIG_PINCTRL_METEORLAKE) += pinctrl-meteorlake.o
obj-$(CONFIG_PINCTRL_SUNRISEPOINT) += pinctrl-sunrisepoint.o
obj-$(CONFIG_PINCTRL_TIGERLAKE) += pinctrl-tigerlake.o
{
struct intel_pinctrl *vg = pinctrl_dev_get_drvdata(pctldev);
- return vg->soc->groups[selector].name;
+ return vg->soc->groups[selector].grp.name;
}
static int byt_get_group_pins(struct pinctrl_dev *pctldev,
{
struct intel_pinctrl *vg = pinctrl_dev_get_drvdata(pctldev);
- *pins = vg->soc->groups[selector].pins;
- *num_pins = vg->soc->groups[selector].npins;
+ *pins = vg->soc->groups[selector].grp.pins;
+ *num_pins = vg->soc->groups[selector].grp.npins;
return 0;
}
raw_spin_lock_irqsave(&byt_lock, flags);
- for (i = 0; i < group.npins; i++) {
+ for (i = 0; i < group.grp.npins; i++) {
void __iomem *padcfg0;
u32 value;
- padcfg0 = byt_gpio_reg(vg, group.pins[i], BYT_CONF0_REG);
+ padcfg0 = byt_gpio_reg(vg, group.grp.pins[i], BYT_CONF0_REG);
if (!padcfg0) {
dev_warn(vg->dev,
"Group %s, pin %i not muxed (no padcfg0)\n",
- group.name, i);
+ group.grp.name, i);
continue;
}
raw_spin_lock_irqsave(&byt_lock, flags);
- for (i = 0; i < group.npins; i++) {
+ for (i = 0; i < group.grp.npins; i++) {
void __iomem *padcfg0;
u32 value;
- padcfg0 = byt_gpio_reg(vg, group.pins[i], BYT_CONF0_REG);
+ padcfg0 = byt_gpio_reg(vg, group.grp.pins[i], BYT_CONF0_REG);
if (!padcfg0) {
dev_warn(vg->dev,
"Group %s, pin %i not muxed (no padcfg0)\n",
- group.name, i);
+ group.grp.name, i);
continue;
}
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
- return pctrl->soc->groups[group].name;
+ return pctrl->soc->groups[group].grp.name;
}
static int chv_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
- *pins = pctrl->soc->groups[group].pins;
- *npins = pctrl->soc->groups[group].npins;
+ *pins = pctrl->soc->groups[group].grp.pins;
+ *npins = pctrl->soc->groups[group].grp.npins;
return 0;
}
raw_spin_lock_irqsave(&chv_lock, flags);
/* Check first that the pad is not locked */
- for (i = 0; i < grp->npins; i++) {
- if (chv_pad_locked(pctrl, grp->pins[i])) {
+ for (i = 0; i < grp->grp.npins; i++) {
+ if (chv_pad_locked(pctrl, grp->grp.pins[i])) {
raw_spin_unlock_irqrestore(&chv_lock, flags);
- dev_warn(dev, "unable to set mode for locked pin %u\n", grp->pins[i]);
+ dev_warn(dev, "unable to set mode for locked pin %u\n", grp->grp.pins[i]);
return -EBUSY;
}
}
- for (i = 0; i < grp->npins; i++) {
- int pin = grp->pins[i];
+ for (i = 0; i < grp->grp.npins; i++) {
+ int pin = grp->grp.pins[i];
unsigned int mode;
bool invert_oe;
u32 value;
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
- return pctrl->soc->groups[group].name;
+ return pctrl->soc->groups[group].grp.name;
}
static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
- *pins = pctrl->soc->groups[group].pins;
- *npins = pctrl->soc->groups[group].npins;
+ *pins = pctrl->soc->groups[group].grp.pins;
+ *npins = pctrl->soc->groups[group].grp.npins;
return 0;
}
* All pins in the groups needs to be accessible and writable
* before we can enable the mux for this group.
*/
- for (i = 0; i < grp->npins; i++) {
- if (!intel_pad_usable(pctrl, grp->pins[i])) {
+ for (i = 0; i < grp->grp.npins; i++) {
+ if (!intel_pad_usable(pctrl, grp->grp.pins[i])) {
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
return -EBUSY;
}
}
/* Now enable the mux setting for each pin in the group */
- for (i = 0; i < grp->npins; i++) {
+ for (i = 0; i < grp->grp.npins; i++) {
void __iomem *padcfg0;
u32 value;
- padcfg0 = intel_get_padcfg(pctrl, grp->pins[i], PADCFG0);
+ padcfg0 = intel_get_padcfg(pctrl, grp->grp.pins[i], PADCFG0);
value = readl(padcfg0);
value &= ~PADCFG0_PMODE_MASK;
/**
* struct intel_pingroup - Description about group of pins
- * @name: Name of the groups
- * @pins: All pins in this group
- * @npins: Number of pins in this groups
- * @mode: Native mode in which the group is muxed out @pins. Used if @modes
- * is %NULL.
+ * @grp: Generic data of the pin group (name and pins)
+ * @mode: Native mode in which the group is muxed out @pins. Used if @modes is %NULL.
* @modes: If not %NULL this will hold mode for each pin in @pins
*/
struct intel_pingroup {
- const char *name;
- const unsigned int *pins;
- size_t npins;
+ struct pingroup grp;
unsigned short mode;
const unsigned int *modes;
};
* a single integer or an array of integers in which case mode is per
* pin.
*/
-#define PIN_GROUP(n, p, m) \
- { \
- .name = (n), \
- .pins = (p), \
- .npins = ARRAY_SIZE((p)), \
- .mode = __builtin_choose_expr( \
- __builtin_constant_p((m)), (m), 0), \
- .modes = __builtin_choose_expr( \
- __builtin_constant_p((m)), NULL, (m)), \
+#define PIN_GROUP(n, p, m) \
+ { \
+ .grp = PINCTRL_PINGROUP((n), (p), ARRAY_SIZE((p))), \
+ .mode = __builtin_choose_expr(__builtin_constant_p((m)), (m), 0), \
+ .modes = __builtin_choose_expr(__builtin_constant_p((m)), NULL, (m)), \
}
#define FUNCTION(n, g) \
{
struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev);
- return lg->soc->groups[selector].name;
+ return lg->soc->groups[selector].grp.name;
}
static int lp_get_group_pins(struct pinctrl_dev *pctldev,
{
struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev);
- *pins = lg->soc->groups[selector].pins;
- *num_pins = lg->soc->groups[selector].npins;
+ *pins = lg->soc->groups[selector].grp.pins;
+ *num_pins = lg->soc->groups[selector].grp.npins;
return 0;
}
raw_spin_lock_irqsave(&lg->lock, flags);
/* Now enable the mux setting for each pin in the group */
- for (i = 0; i < grp->npins; i++) {
- void __iomem *reg = lp_gpio_reg(&lg->chip, grp->pins[i], LP_CONFIG1);
+ for (i = 0; i < grp->grp.npins; i++) {
+ void __iomem *reg = lp_gpio_reg(&lg->chip, grp->grp.pins[i], LP_CONFIG1);
u32 value;
value = ioread32(reg);
{
struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
- return mp->groups[group].name;
+ return mp->groups[group].grp.name;
}
static int mrfld_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
{
struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
- *pins = mp->groups[group].pins;
- *npins = mp->groups[group].npins;
+ *pins = mp->groups[group].grp.pins;
+ *npins = mp->groups[group].grp.npins;
return 0;
}
* All pins in the groups needs to be accessible and writable
* before we can enable the mux for this group.
*/
- for (i = 0; i < grp->npins; i++) {
- if (!mrfld_buf_available(mp, grp->pins[i]))
+ for (i = 0; i < grp->grp.npins; i++) {
+ if (!mrfld_buf_available(mp, grp->grp.pins[i]))
return -EBUSY;
}
/* Now enable the mux setting for each pin in the group */
raw_spin_lock_irqsave(&mp->lock, flags);
- for (i = 0; i < grp->npins; i++)
- mrfld_update_bufcfg(mp, grp->pins[i], bits, mask);
+ for (i = 0; i < grp->grp.npins; i++)
+ mrfld_update_bufcfg(mp, grp->grp.pins[i], bits, mask);
raw_spin_unlock_irqrestore(&mp->lock, flags);
return 0;
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Meteor Lake PCH pinctrl/GPIO driver
+ *
+ * Copyright (C) 2022, Intel Corporation
+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-intel.h"
+
+#define MTL_PAD_OWN 0x0b0
+#define MTL_PADCFGLOCK 0x110
+#define MTL_HOSTSW_OWN 0x140
+#define MTL_GPI_IS 0x200
+#define MTL_GPI_IE 0x210
+
+#define MTL_GPP(r, s, e, g) \
+ { \
+ .reg_num = (r), \
+ .base = (s), \
+ .size = ((e) - (s) + 1), \
+ .gpio_base = (g), \
+ }
+
+#define MTL_COMMUNITY(b, s, e, g) \
+ { \
+ .barno = (b), \
+ .padown_offset = MTL_PAD_OWN, \
+ .padcfglock_offset = MTL_PADCFGLOCK, \
+ .hostown_offset = MTL_HOSTSW_OWN, \
+ .is_offset = MTL_GPI_IS, \
+ .ie_offset = MTL_GPI_IE, \
+ .pin_base = (s), \
+ .npins = ((e) - (s) + 1), \
+ .gpps = (g), \
+ .ngpps = ARRAY_SIZE(g), \
+ }
+
+/* Meteor Lake-P */
+static const struct pinctrl_pin_desc mtlp_pins[] = {
+ /* CPU */
+ PINCTRL_PIN(0, "PECI"),
+ PINCTRL_PIN(1, "UFS_RESET_B"),
+ PINCTRL_PIN(2, "VIDSOUT"),
+ PINCTRL_PIN(3, "VIDSCK"),
+ PINCTRL_PIN(4, "VIDALERT_B"),
+ /* GPP_V */
+ PINCTRL_PIN(5, "BATLOW_B"),
+ PINCTRL_PIN(6, "AC_PRESENT"),
+ PINCTRL_PIN(7, "SOC_WAKE_B"),
+ PINCTRL_PIN(8, "PWRBTN_B"),
+ PINCTRL_PIN(9, "SLP_S3_B"),
+ PINCTRL_PIN(10, "SLP_S4_B"),
+ PINCTRL_PIN(11, "SLP_A_B"),
+ PINCTRL_PIN(12, "GPP_V_7"),
+ PINCTRL_PIN(13, "SUSCLK"),
+ PINCTRL_PIN(14, "SLP_WLAN_B"),
+ PINCTRL_PIN(15, "SLP_S5_B"),
+ PINCTRL_PIN(16, "LANPHYPC"),
+ PINCTRL_PIN(17, "SLP_LAN_B"),
+ PINCTRL_PIN(18, "GPP_V_13"),
+ PINCTRL_PIN(19, "WAKE_B"),
+ PINCTRL_PIN(20, "GPP_V_15"),
+ PINCTRL_PIN(21, "GPP_V_16"),
+ PINCTRL_PIN(22, "GPP_V_17"),
+ PINCTRL_PIN(23, "GPP_V_18"),
+ PINCTRL_PIN(24, "CATERR_B"),
+ PINCTRL_PIN(25, "PROCHOT_B"),
+ PINCTRL_PIN(26, "THERMTRIP_B"),
+ PINCTRL_PIN(27, "DSI_DE_TE_2_GENLOCK_REF"),
+ PINCTRL_PIN(28, "DSI_DE_TE_1_DISP_UTILS"),
+ /* GPP_C */
+ PINCTRL_PIN(29, "SMBCLK"),
+ PINCTRL_PIN(30, "SMBDATA"),
+ PINCTRL_PIN(31, "SMBALERT_B"),
+ PINCTRL_PIN(32, "SML0CLK"),
+ PINCTRL_PIN(33, "SML0DATA"),
+ PINCTRL_PIN(34, "GPP_C_5"),
+ PINCTRL_PIN(35, "GPP_C_6"),
+ PINCTRL_PIN(36, "GPP_C_7"),
+ PINCTRL_PIN(37, "GPP_C_8"),
+ PINCTRL_PIN(38, "GPP_C_9"),
+ PINCTRL_PIN(39, "GPP_C_10"),
+ PINCTRL_PIN(40, "GPP_C_11"),
+ PINCTRL_PIN(41, "GPP_C_12"),
+ PINCTRL_PIN(42, "GPP_C_13"),
+ PINCTRL_PIN(43, "GPP_C_14"),
+ PINCTRL_PIN(44, "GPP_C_15"),
+ PINCTRL_PIN(45, "GPP_C_16"),
+ PINCTRL_PIN(46, "GPP_C_17"),
+ PINCTRL_PIN(47, "GPP_C_18"),
+ PINCTRL_PIN(48, "GPP_C_19"),
+ PINCTRL_PIN(49, "GPP_C_20"),
+ PINCTRL_PIN(50, "GPP_C_21"),
+ PINCTRL_PIN(51, "GPP_C_22"),
+ PINCTRL_PIN(52, "GPP_C_23"),
+ /* GPP_A */
+ PINCTRL_PIN(53, "ESPI_IO_0"),
+ PINCTRL_PIN(54, "ESPI_IO_1"),
+ PINCTRL_PIN(55, "ESPI_IO_2"),
+ PINCTRL_PIN(56, "ESPI_IO_3"),
+ PINCTRL_PIN(57, "ESPI_CS0_B"),
+ PINCTRL_PIN(58, "ESPI_CLK"),
+ PINCTRL_PIN(59, "ESPI_RESET_B"),
+ PINCTRL_PIN(60, "GPP_A_7"),
+ PINCTRL_PIN(61, "GPP_A_8"),
+ PINCTRL_PIN(62, "GPP_A_9"),
+ PINCTRL_PIN(63, "GPP_A_10"),
+ PINCTRL_PIN(64, "GPP_A_11"),
+ PINCTRL_PIN(65, "GPP_A_12"),
+ PINCTRL_PIN(66, "ESPI_CS1_B"),
+ PINCTRL_PIN(67, "ESPI_CS2_B"),
+ PINCTRL_PIN(68, "ESPI_CS3_B"),
+ PINCTRL_PIN(69, "ESPI_ALERT0_B"),
+ PINCTRL_PIN(70, "ESPI_ALERT1_B"),
+ PINCTRL_PIN(71, "ESPI_ALERT2_B"),
+ PINCTRL_PIN(72, "ESPI_ALERT3_B"),
+ PINCTRL_PIN(73, "GPP_A_20"),
+ PINCTRL_PIN(74, "GPP_A_21"),
+ PINCTRL_PIN(75, "GPP_A_22"),
+ PINCTRL_PIN(76, "GPP_A_23"),
+ PINCTRL_PIN(77, "ESPI_CLK_LOOPBK"),
+ /* GPP_E */
+ PINCTRL_PIN(78, "GPP_E_0"),
+ PINCTRL_PIN(79, "GPP_E_1"),
+ PINCTRL_PIN(80, "GPP_E_2"),
+ PINCTRL_PIN(81, "GPP_E_3"),
+ PINCTRL_PIN(82, "GPP_E_4"),
+ PINCTRL_PIN(83, "GPP_E_5"),
+ PINCTRL_PIN(84, "GPP_E_6"),
+ PINCTRL_PIN(85, "GPP_E_7"),
+ PINCTRL_PIN(86, "GPP_E_8"),
+ PINCTRL_PIN(87, "GPP_E_9"),
+ PINCTRL_PIN(88, "GPP_E_10"),
+ PINCTRL_PIN(89, "GPP_E_11"),
+ PINCTRL_PIN(90, "GPP_E_12"),
+ PINCTRL_PIN(91, "GPP_E_13"),
+ PINCTRL_PIN(92, "GPP_E_14"),
+ PINCTRL_PIN(93, "SLP_DRAM_B"),
+ PINCTRL_PIN(94, "GPP_E_16"),
+ PINCTRL_PIN(95, "GPP_E_17"),
+ PINCTRL_PIN(96, "GPP_E_18"),
+ PINCTRL_PIN(97, "GPP_E_19"),
+ PINCTRL_PIN(98, "GPP_E_20"),
+ PINCTRL_PIN(99, "GPP_E_21"),
+ PINCTRL_PIN(100, "DNX_FORCE_RELOAD"),
+ PINCTRL_PIN(101, "GPP_E_23"),
+ PINCTRL_PIN(102, "THC0_GSPI0_CLK_LOOPBK"),
+ /* GPP_H */
+ PINCTRL_PIN(103, "GPP_H_0"),
+ PINCTRL_PIN(104, "GPP_H_1"),
+ PINCTRL_PIN(105, "GPP_H_2"),
+ PINCTRL_PIN(106, "GPP_H_3"),
+ PINCTRL_PIN(107, "GPP_H_4"),
+ PINCTRL_PIN(108, "GPP_H_5"),
+ PINCTRL_PIN(109, "GPP_H_6"),
+ PINCTRL_PIN(110, "GPP_H_7"),
+ PINCTRL_PIN(111, "GPP_H_8"),
+ PINCTRL_PIN(112, "GPP_H_9"),
+ PINCTRL_PIN(113, "GPP_H_10"),
+ PINCTRL_PIN(114, "GPP_H_11"),
+ PINCTRL_PIN(115, "GPP_H_12"),
+ PINCTRL_PIN(116, "CPU_C10_GATE_B"),
+ PINCTRL_PIN(117, "GPP_H_14"),
+ PINCTRL_PIN(118, "GPP_H_15"),
+ PINCTRL_PIN(119, "GPP_H_16"),
+ PINCTRL_PIN(120, "GPP_H_17"),
+ PINCTRL_PIN(121, "GPP_H_18"),
+ PINCTRL_PIN(122, "GPP_H_19"),
+ PINCTRL_PIN(123, "GPP_H_20"),
+ PINCTRL_PIN(124, "GPP_H_21"),
+ PINCTRL_PIN(125, "GPP_H_22"),
+ PINCTRL_PIN(126, "GPP_H_23"),
+ PINCTRL_PIN(127, "LPI3C1_CLK_LOOPBK"),
+ PINCTRL_PIN(128, "I3C0_CLK_LOOPBK"),
+ /* GPP_F */
+ PINCTRL_PIN(129, "CNV_BRI_DT"),
+ PINCTRL_PIN(130, "CNV_BRI_RSP"),
+ PINCTRL_PIN(131, "CNV_RGI_DT"),
+ PINCTRL_PIN(132, "CNV_RGI_RSP"),
+ PINCTRL_PIN(133, "CNV_RF_RESET_B"),
+ PINCTRL_PIN(134, "CRF_CLKREQ"),
+ PINCTRL_PIN(135, "GPP_F_6"),
+ PINCTRL_PIN(136, "FUSA_DIAGTEST_EN"),
+ PINCTRL_PIN(137, "FUSA_DIAGTEST_MODE"),
+ PINCTRL_PIN(138, "BOOTMPC"),
+ PINCTRL_PIN(139, "GPP_F_10"),
+ PINCTRL_PIN(140, "GPP_F_11"),
+ PINCTRL_PIN(141, "GSXDOUT"),
+ PINCTRL_PIN(142, "GSXSLOAD"),
+ PINCTRL_PIN(143, "GSXDIN"),
+ PINCTRL_PIN(144, "GSXSRESETB"),
+ PINCTRL_PIN(145, "GSXCLK"),
+ PINCTRL_PIN(146, "GMII_MDC_0"),
+ PINCTRL_PIN(147, "GMII_MDIO_0"),
+ PINCTRL_PIN(148, "GPP_F_19"),
+ PINCTRL_PIN(149, "GPP_F_20"),
+ PINCTRL_PIN(150, "GPP_F_21"),
+ PINCTRL_PIN(151, "GPP_F_22"),
+ PINCTRL_PIN(152, "GPP_F_23"),
+ PINCTRL_PIN(153, "THC1_GSPI1_CLK_LOOPBK"),
+ PINCTRL_PIN(154, "GSPI0A_CLK_LOOPBK"),
+ /* SPI0 */
+ PINCTRL_PIN(155, "SPI0_IO_2"),
+ PINCTRL_PIN(156, "SPI0_IO_3"),
+ PINCTRL_PIN(157, "SPI0_MOSI_IO_0"),
+ PINCTRL_PIN(158, "SPI0_MISO_IO_1"),
+ PINCTRL_PIN(159, "SPI0_TPM_CS_B"),
+ PINCTRL_PIN(160, "SPI0_FLASH_0_CS_B"),
+ PINCTRL_PIN(161, "SPI0_FLASH_1_CS_B"),
+ PINCTRL_PIN(162, "SPI0_CLK"),
+ PINCTRL_PIN(163, "L_BKLTEN"),
+ PINCTRL_PIN(164, "L_BKLTCTL"),
+ PINCTRL_PIN(165, "L_VDDEN"),
+ PINCTRL_PIN(166, "SYS_PWROK"),
+ PINCTRL_PIN(167, "SYS_RESET_B"),
+ PINCTRL_PIN(168, "MLK_RST_B"),
+ PINCTRL_PIN(169, "SPI0_CLK_LOOPBK"),
+ /* vGPIO_3 */
+ PINCTRL_PIN(170, "ESPI_USB_OCB_0"),
+ PINCTRL_PIN(171, "ESPI_USB_OCB_1"),
+ PINCTRL_PIN(172, "ESPI_USB_OCB_2"),
+ PINCTRL_PIN(173, "ESPI_USB_OCB_3"),
+ PINCTRL_PIN(174, "USB_CPU_OCB_0"),
+ PINCTRL_PIN(175, "USB_CPU_OCB_1"),
+ PINCTRL_PIN(176, "USB_CPU_OCB_2"),
+ PINCTRL_PIN(177, "USB_CPU_OCB_3"),
+ PINCTRL_PIN(178, "TS0_IN_INT"),
+ PINCTRL_PIN(179, "TS1_IN_INT"),
+ PINCTRL_PIN(180, "THC0_WOT_INT"),
+ PINCTRL_PIN(181, "THC1_WOT_INT"),
+ PINCTRL_PIN(182, "THC0_WHC_INT"),
+ PINCTRL_PIN(183, "THC1_WHC_INT"),
+ /* GPP_S */
+ PINCTRL_PIN(184, "GPP_S_0"),
+ PINCTRL_PIN(185, "GPP_S_1"),
+ PINCTRL_PIN(186, "GPP_S_2"),
+ PINCTRL_PIN(187, "GPP_S_3"),
+ PINCTRL_PIN(188, "GPP_S_4"),
+ PINCTRL_PIN(189, "GPP_S_5"),
+ PINCTRL_PIN(190, "GPP_S_6"),
+ PINCTRL_PIN(191, "GPP_S_7"),
+ /* JTAG */
+ PINCTRL_PIN(192, "JTAG_MBPB0"),
+ PINCTRL_PIN(193, "JTAG_MBPB1"),
+ PINCTRL_PIN(194, "JTAG_MBPB2"),
+ PINCTRL_PIN(195, "JTAG_MBPB3"),
+ PINCTRL_PIN(196, "JTAG_TDO"),
+ PINCTRL_PIN(197, "PRDY_B"),
+ PINCTRL_PIN(198, "PREQ_B"),
+ PINCTRL_PIN(199, "JTAG_TDI"),
+ PINCTRL_PIN(200, "JTAG_TMS"),
+ PINCTRL_PIN(201, "JTAG_TCK"),
+ PINCTRL_PIN(202, "DBG_PMODE"),
+ PINCTRL_PIN(203, "JTAG_TRST_B"),
+ /* GPP_B */
+ PINCTRL_PIN(204, "ADM_VID_0"),
+ PINCTRL_PIN(205, "ADM_VID_1"),
+ PINCTRL_PIN(206, "GPP_B_2"),
+ PINCTRL_PIN(207, "GPP_B_3"),
+ PINCTRL_PIN(208, "GPP_B_4"),
+ PINCTRL_PIN(209, "GPP_B_5"),
+ PINCTRL_PIN(210, "GPP_B_6"),
+ PINCTRL_PIN(211, "GPP_B_7"),
+ PINCTRL_PIN(212, "GPP_B_8"),
+ PINCTRL_PIN(213, "GPP_B_9"),
+ PINCTRL_PIN(214, "GPP_B_10"),
+ PINCTRL_PIN(215, "GPP_B_11"),
+ PINCTRL_PIN(216, "SLP_S0_B"),
+ PINCTRL_PIN(217, "PLTRST_B"),
+ PINCTRL_PIN(218, "GPP_B_14"),
+ PINCTRL_PIN(219, "GPP_B_15"),
+ PINCTRL_PIN(220, "GPP_B_16"),
+ PINCTRL_PIN(221, "GPP_B_17"),
+ PINCTRL_PIN(222, "GPP_B_18"),
+ PINCTRL_PIN(223, "GPP_B_19"),
+ PINCTRL_PIN(224, "GPP_B_20"),
+ PINCTRL_PIN(225, "GPP_B_21"),
+ PINCTRL_PIN(226, "GPP_B_22"),
+ PINCTRL_PIN(227, "GPP_B_23"),
+ PINCTRL_PIN(228, "ISH_I3C0_CLK_LOOPBK"),
+ /* GPP_D */
+ PINCTRL_PIN(229, "GPP_D_0"),
+ PINCTRL_PIN(230, "GPP_D_1"),
+ PINCTRL_PIN(231, "GPP_D_2"),
+ PINCTRL_PIN(232, "GPP_D_3"),
+ PINCTRL_PIN(233, "GPP_D_4"),
+ PINCTRL_PIN(234, "GPP_D_5"),
+ PINCTRL_PIN(235, "GPP_D_6"),
+ PINCTRL_PIN(236, "GPP_D_7"),
+ PINCTRL_PIN(237, "GPP_D_8"),
+ PINCTRL_PIN(238, "GPP_D_9"),
+ PINCTRL_PIN(239, "HDA_BCLK"),
+ PINCTRL_PIN(240, "HDA_SYNC"),
+ PINCTRL_PIN(241, "HDA_SDO"),
+ PINCTRL_PIN(242, "HDA_SDI_0"),
+ PINCTRL_PIN(243, "GPP_D_14"),
+ PINCTRL_PIN(244, "GPP_D_15"),
+ PINCTRL_PIN(245, "GPP_D_16"),
+ PINCTRL_PIN(246, "HDA_RST_B"),
+ PINCTRL_PIN(247, "GPP_D_18"),
+ PINCTRL_PIN(248, "GPP_D_19"),
+ PINCTRL_PIN(249, "GPP_D_20"),
+ PINCTRL_PIN(250, "UFS_REFCLK"),
+ PINCTRL_PIN(251, "BPKI3C_SDA"),
+ PINCTRL_PIN(252, "BPKI3C_SCL"),
+ PINCTRL_PIN(253, "BOOTHALT_B"),
+ /* vGPIO */
+ PINCTRL_PIN(254, "CNV_BTEN"),
+ PINCTRL_PIN(255, "CNV_BT_HOST_WAKEB"),
+ PINCTRL_PIN(256, "CNV_BT_IF_SELECT"),
+ PINCTRL_PIN(257, "vCNV_BT_UART_TXD"),
+ PINCTRL_PIN(258, "vCNV_BT_UART_RXD"),
+ PINCTRL_PIN(259, "vCNV_BT_UART_CTS_B"),
+ PINCTRL_PIN(260, "vCNV_BT_UART_RTS_B"),
+ PINCTRL_PIN(261, "vCNV_MFUART1_TXD"),
+ PINCTRL_PIN(262, "vCNV_MFUART1_RXD"),
+ PINCTRL_PIN(263, "vCNV_MFUART1_CTS_B"),
+ PINCTRL_PIN(264, "vCNV_MFUART1_RTS_B"),
+ PINCTRL_PIN(265, "vUART0_TXD"),
+ PINCTRL_PIN(266, "vUART0_RXD"),
+ PINCTRL_PIN(267, "vUART0_CTS_B"),
+ PINCTRL_PIN(268, "vUART0_RTS_B"),
+ PINCTRL_PIN(269, "vISH_UART0_TXD"),
+ PINCTRL_PIN(270, "vISH_UART0_RXD"),
+ PINCTRL_PIN(271, "vISH_UART0_CTS_B"),
+ PINCTRL_PIN(272, "vISH_UART0_RTS_B"),
+ PINCTRL_PIN(273, "vCNV_BT_I2S_BCLK"),
+ PINCTRL_PIN(274, "vCNV_BT_I2S_WS_SYNC"),
+ PINCTRL_PIN(275, "vCNV_BT_I2S_SDO"),
+ PINCTRL_PIN(276, "vCNV_BT_I2S_SDI"),
+ PINCTRL_PIN(277, "vI2S2_SCLK"),
+ PINCTRL_PIN(278, "vI2S2_SFRM"),
+ PINCTRL_PIN(279, "vI2S2_TXD"),
+ PINCTRL_PIN(280, "vI2S2_RXD"),
+ PINCTRL_PIN(281, "vCNV_BT_I2S_BCLK_2"),
+ PINCTRL_PIN(282, "vCNV_BT_I2S_WS_SYNC_2"),
+ PINCTRL_PIN(283, "vCNV_BT_I2S_SDO_2"),
+ PINCTRL_PIN(284, "vCNV_BT_I2S_SDI_2"),
+ PINCTRL_PIN(285, "vI2S2_SCLK_2"),
+ PINCTRL_PIN(286, "vI2S2_SFRM_2"),
+ PINCTRL_PIN(287, "vI2S2_TXD_2"),
+ PINCTRL_PIN(288, "vI2S2_RXD_2"),
+};
+
+static const struct intel_padgroup mtlp_community0_gpps[] = {
+ MTL_GPP(0, 0, 4, 0), /* CPU */
+ MTL_GPP(1, 5, 28, 32), /* GPP_V */
+ MTL_GPP(2, 29, 52, 64), /* GPP_C */
+};
+
+static const struct intel_padgroup mtlp_community1_gpps[] = {
+ MTL_GPP(0, 53, 77, 96), /* GPP_A */
+ MTL_GPP(1, 78, 102, 128), /* GPP_E */
+};
+
+static const struct intel_padgroup mtlp_community3_gpps[] = {
+ MTL_GPP(0, 103, 128, 160), /* GPP_H */
+ MTL_GPP(1, 129, 154, 192), /* GPP_F */
+ MTL_GPP(2, 155, 169, 224), /* SPI0 */
+ MTL_GPP(3, 170, 183, 256), /* vGPIO_3 */
+};
+
+static const struct intel_padgroup mtlp_community4_gpps[] = {
+ MTL_GPP(0, 184, 191, 288), /* GPP_S */
+ MTL_GPP(1, 192, 203, 320), /* JTAG */
+};
+
+static const struct intel_padgroup mtlp_community5_gpps[] = {
+ MTL_GPP(0, 204, 228, 352), /* GPP_B */
+ MTL_GPP(1, 229, 253, 384), /* GPP_D */
+ MTL_GPP(2, 254, 285, 416), /* vGPIO_0 */
+ MTL_GPP(3, 286, 288, 448), /* vGPIO_1 */
+};
+
+static const struct intel_community mtlp_communities[] = {
+ MTL_COMMUNITY(0, 0, 52, mtlp_community0_gpps),
+ MTL_COMMUNITY(1, 53, 102, mtlp_community1_gpps),
+ MTL_COMMUNITY(2, 103, 183, mtlp_community3_gpps),
+ MTL_COMMUNITY(3, 184, 203, mtlp_community4_gpps),
+ MTL_COMMUNITY(4, 204, 288, mtlp_community5_gpps),
+};
+
+static const struct intel_pinctrl_soc_data mtlp_soc_data = {
+ .pins = mtlp_pins,
+ .npins = ARRAY_SIZE(mtlp_pins),
+ .communities = mtlp_communities,
+ .ncommunities = ARRAY_SIZE(mtlp_communities),
+};
+
+static const struct acpi_device_id mtl_pinctrl_acpi_match[] = {
+ { "INTC1083", (kernel_ulong_t)&mtlp_soc_data },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, mtl_pinctrl_acpi_match);
+
+static INTEL_PINCTRL_PM_OPS(mtl_pinctrl_pm_ops);
+
+static struct platform_driver mtl_pinctrl_driver = {
+ .probe = intel_pinctrl_probe_by_hid,
+ .driver = {
+ .name = "meteorlake-pinctrl",
+ .acpi_match_table = mtl_pinctrl_acpi_match,
+ .pm = &mtl_pinctrl_pm_ops,
+ },
+};
+module_platform_driver(mtl_pinctrl_driver);
+
+MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
+MODULE_DESCRIPTION("Intel Meteor Lake PCH pinctrl/GPIO driver");
+MODULE_LICENSE("GPL v2");
PIN_FIELD_BASE(54, 54, 1, 0x0060, 0x10, 2, 1),
PIN_FIELD_BASE(55, 55, 1, 0x0060, 0x10, 4, 1),
PIN_FIELD_BASE(56, 56, 1, 0x0060, 0x10, 3, 1),
- PIN_FIELD_BASE(118, 118, 4, 0x00e0, 0x10, 31, 1),
- PIN_FIELD_BASE(119, 119, 4, 0x00e0, 0x10, 31, 1),
- PIN_FIELD_BASE(120, 120, 4, 0x00e0, 0x10, 31, 1),
- PIN_FIELD_BASE(121, 121, 4, 0x00e0, 0x10, 31, 1),
- PIN_FIELD_BASE(122, 122, 4, 0x00e0, 0x10, 31, 1),
- PIN_FIELD_BASE(123, 123, 4, 0x00e0, 0x10, 31, 1),
- PIN_FIELD_BASE(124, 124, 4, 0x00e0, 0x10, 31, 1),
- PIN_FIELD_BASE(125, 125, 4, 0x00e0, 0x10, 31, 1),
- PIN_FIELD_BASE(139, 139, 4, 0x00e0, 0x10, 31, 1),
- PIN_FIELD_BASE(140, 140, 4, 0x00e0, 0x10, 31, 1),
- PIN_FIELD_BASE(141, 141, 4, 0x00e0, 0x10, 31, 1),
- PIN_FIELD_BASE(142, 142, 4, 0x00e0, 0x10, 31, 1),
PIN_FIELD_BASE(152, 152, 7, 0x0090, 0x10, 3, 1),
PIN_FIELD_BASE(153, 153, 7, 0x0090, 0x10, 2, 1),
PIN_FIELD_BASE(154, 154, 7, 0x0090, 0x10, 0, 1),
PIN_FIELD_BASE(155, 155, 7, 0x0090, 0x10, 1, 1),
- PIN_FIELD_BASE(160, 160, 7, 0x00f0, 0x10, 31, 1),
- PIN_FIELD_BASE(161, 161, 7, 0x00f0, 0x10, 31, 1),
PIN_FIELD_BASE(183, 183, 9, 0x0030, 0x10, 1, 1),
PIN_FIELD_BASE(184, 184, 9, 0x0030, 0x10, 2, 1),
PIN_FIELD_BASE(185, 185, 9, 0x0030, 0x10, 4, 1),
PIN_FIELD_BASE(192, 192, 9, 0x0030, 0x10, 0, 1),
PIN_FIELD_BASE(193, 193, 9, 0x0030, 0x10, 5, 1),
PIN_FIELD_BASE(194, 194, 9, 0x0030, 0x10, 11, 1),
- PIN_FIELD_BASE(200, 200, 8, 0x0070, 0x10, 31, 1),
- PIN_FIELD_BASE(201, 201, 8, 0x0070, 0x10, 31, 1),
- PIN_FIELD_BASE(202, 202, 5, 0x0070, 0x10, 31, 1),
- PIN_FIELD_BASE(203, 203, 5, 0x0070, 0x10, 31, 1),
- PIN_FIELD_BASE(204, 204, 8, 0x0070, 0x10, 31, 1),
- PIN_FIELD_BASE(205, 205, 8, 0x0070, 0x10, 31, 1),
};
static const struct mtk_pin_field_calc mt8192_pin_r0_range[] = {
PIN_FIELD_BASE(54, 54, 1, 0x0080, 0x10, 2, 1),
PIN_FIELD_BASE(55, 55, 1, 0x0080, 0x10, 4, 1),
PIN_FIELD_BASE(56, 56, 1, 0x0080, 0x10, 3, 1),
- PIN_FIELD_BASE(118, 118, 4, 0x00e0, 0x10, 0, 1),
- PIN_FIELD_BASE(119, 119, 4, 0x00e0, 0x10, 12, 1),
- PIN_FIELD_BASE(120, 120, 4, 0x00e0, 0x10, 10, 1),
- PIN_FIELD_BASE(121, 121, 4, 0x00e0, 0x10, 22, 1),
- PIN_FIELD_BASE(122, 122, 4, 0x00e0, 0x10, 8, 1),
- PIN_FIELD_BASE(123, 123, 4, 0x00e0, 0x10, 20, 1),
- PIN_FIELD_BASE(124, 124, 4, 0x00e0, 0x10, 6, 1),
- PIN_FIELD_BASE(125, 125, 4, 0x00e0, 0x10, 18, 1),
- PIN_FIELD_BASE(139, 139, 4, 0x00e0, 0x10, 4, 1),
- PIN_FIELD_BASE(140, 140, 4, 0x00e0, 0x10, 16, 1),
- PIN_FIELD_BASE(141, 141, 4, 0x00e0, 0x10, 2, 1),
- PIN_FIELD_BASE(142, 142, 4, 0x00e0, 0x10, 14, 1),
PIN_FIELD_BASE(152, 152, 7, 0x00c0, 0x10, 3, 1),
PIN_FIELD_BASE(153, 153, 7, 0x00c0, 0x10, 2, 1),
PIN_FIELD_BASE(154, 154, 7, 0x00c0, 0x10, 0, 1),
PIN_FIELD_BASE(155, 155, 7, 0x00c0, 0x10, 1, 1),
- PIN_FIELD_BASE(160, 160, 7, 0x00f0, 0x10, 0, 1),
- PIN_FIELD_BASE(161, 161, 7, 0x00f0, 0x10, 2, 1),
PIN_FIELD_BASE(183, 183, 9, 0x0040, 0x10, 1, 1),
PIN_FIELD_BASE(184, 184, 9, 0x0040, 0x10, 2, 1),
PIN_FIELD_BASE(185, 185, 9, 0x0040, 0x10, 4, 1),
PIN_FIELD_BASE(192, 192, 9, 0x0040, 0x10, 0, 1),
PIN_FIELD_BASE(193, 193, 9, 0x0040, 0x10, 5, 1),
PIN_FIELD_BASE(194, 194, 9, 0x0040, 0x10, 11, 1),
- PIN_FIELD_BASE(200, 200, 8, 0x0070, 0x10, 2, 1),
- PIN_FIELD_BASE(201, 201, 8, 0x0070, 0x10, 6, 1),
- PIN_FIELD_BASE(202, 202, 5, 0x0070, 0x10, 0, 1),
- PIN_FIELD_BASE(203, 203, 5, 0x0070, 0x10, 2, 1),
- PIN_FIELD_BASE(204, 204, 8, 0x0070, 0x10, 0, 1),
- PIN_FIELD_BASE(205, 205, 8, 0x0070, 0x10, 4, 1),
};
static const struct mtk_pin_field_calc mt8192_pin_r1_range[] = {
PIN_FIELD_BASE(54, 54, 1, 0x0090, 0x10, 2, 1),
PIN_FIELD_BASE(55, 55, 1, 0x0090, 0x10, 4, 1),
PIN_FIELD_BASE(56, 56, 1, 0x0090, 0x10, 3, 1),
- PIN_FIELD_BASE(118, 118, 4, 0x00e0, 0x10, 1, 1),
- PIN_FIELD_BASE(119, 119, 4, 0x00e0, 0x10, 13, 1),
- PIN_FIELD_BASE(120, 120, 4, 0x00e0, 0x10, 11, 1),
- PIN_FIELD_BASE(121, 121, 4, 0x00e0, 0x10, 23, 1),
- PIN_FIELD_BASE(122, 122, 4, 0x00e0, 0x10, 9, 1),
- PIN_FIELD_BASE(123, 123, 4, 0x00e0, 0x10, 21, 1),
- PIN_FIELD_BASE(124, 124, 4, 0x00e0, 0x10, 7, 1),
- PIN_FIELD_BASE(125, 125, 4, 0x00e0, 0x10, 19, 1),
- PIN_FIELD_BASE(139, 139, 4, 0x00e0, 0x10, 5, 1),
- PIN_FIELD_BASE(140, 140, 4, 0x00e0, 0x10, 17, 1),
- PIN_FIELD_BASE(141, 141, 4, 0x00e0, 0x10, 3, 1),
- PIN_FIELD_BASE(142, 142, 4, 0x00e0, 0x10, 15, 1),
PIN_FIELD_BASE(152, 152, 7, 0x00d0, 0x10, 3, 1),
PIN_FIELD_BASE(153, 153, 7, 0x00d0, 0x10, 2, 1),
PIN_FIELD_BASE(154, 154, 7, 0x00d0, 0x10, 0, 1),
PIN_FIELD_BASE(155, 155, 7, 0x00d0, 0x10, 1, 1),
- PIN_FIELD_BASE(160, 160, 7, 0x00f0, 0x10, 1, 1),
- PIN_FIELD_BASE(161, 161, 7, 0x00f0, 0x10, 3, 1),
PIN_FIELD_BASE(183, 183, 9, 0x0050, 0x10, 1, 1),
PIN_FIELD_BASE(184, 184, 9, 0x0050, 0x10, 2, 1),
PIN_FIELD_BASE(185, 185, 9, 0x0050, 0x10, 4, 1),
PIN_FIELD_BASE(192, 192, 9, 0x0050, 0x10, 0, 1),
PIN_FIELD_BASE(193, 193, 9, 0x0050, 0x10, 5, 1),
PIN_FIELD_BASE(194, 194, 9, 0x0050, 0x10, 11, 1),
- PIN_FIELD_BASE(200, 200, 8, 0x0070, 0x10, 3, 1),
- PIN_FIELD_BASE(201, 201, 8, 0x0070, 0x10, 7, 1),
- PIN_FIELD_BASE(202, 202, 5, 0x0070, 0x10, 1, 1),
- PIN_FIELD_BASE(203, 203, 5, 0x0070, 0x10, 3, 1),
- PIN_FIELD_BASE(204, 204, 8, 0x0070, 0x10, 1, 1),
- PIN_FIELD_BASE(205, 205, 8, 0x0070, 0x10, 5, 1),
};
-static const struct mtk_pin_field_calc mt8192_pin_e1e0en_range[] = {
- PIN_FIELD_BASE(118, 118, 4, 0x0040, 0x10, 0, 1),
- PIN_FIELD_BASE(119, 119, 4, 0x0040, 0x10, 18, 1),
- PIN_FIELD_BASE(120, 120, 4, 0x0040, 0x10, 15, 1),
- PIN_FIELD_BASE(121, 121, 4, 0x0050, 0x10, 3, 1),
- PIN_FIELD_BASE(122, 122, 4, 0x0040, 0x10, 12, 1),
- PIN_FIELD_BASE(123, 123, 4, 0x0050, 0x10, 0, 1),
- PIN_FIELD_BASE(124, 124, 4, 0x0040, 0x10, 9, 1),
- PIN_FIELD_BASE(125, 125, 4, 0x0040, 0x10, 27, 1),
- PIN_FIELD_BASE(139, 139, 4, 0x0040, 0x10, 6, 1),
- PIN_FIELD_BASE(140, 140, 4, 0x0040, 0x10, 24, 1),
- PIN_FIELD_BASE(141, 141, 4, 0x0040, 0x10, 3, 1),
- PIN_FIELD_BASE(142, 142, 4, 0x0040, 0x10, 21, 1),
- PIN_FIELD_BASE(160, 160, 7, 0x0030, 0x10, 0, 1),
- PIN_FIELD_BASE(161, 161, 7, 0x0030, 0x10, 3, 1),
- PIN_FIELD_BASE(200, 200, 8, 0x0010, 0x10, 3, 1),
- PIN_FIELD_BASE(201, 201, 8, 0x0010, 0x10, 9, 1),
- PIN_FIELD_BASE(202, 202, 5, 0x0020, 0x10, 0, 1),
- PIN_FIELD_BASE(203, 203, 5, 0x0020, 0x10, 3, 1),
- PIN_FIELD_BASE(204, 204, 8, 0x0010, 0x10, 0, 1),
- PIN_FIELD_BASE(205, 205, 8, 0x0010, 0x10, 6, 1),
-};
+static const struct mtk_pin_field_calc mt8192_pin_drv_adv_range[] = {
+ PIN_FIELD_BASE(89, 89, 2, 0x0040, 0x10, 0, 5),
+ PIN_FIELD_BASE(90, 90, 2, 0x0040, 0x10, 5, 5),
-static const struct mtk_pin_field_calc mt8192_pin_e0_range[] = {
- PIN_FIELD_BASE(118, 118, 4, 0x0040, 0x10, 1, 1),
- PIN_FIELD_BASE(119, 119, 4, 0x0040, 0x10, 19, 1),
- PIN_FIELD_BASE(120, 120, 4, 0x0040, 0x10, 16, 1),
- PIN_FIELD_BASE(121, 121, 4, 0x0050, 0x10, 4, 1),
- PIN_FIELD_BASE(122, 122, 4, 0x0040, 0x10, 13, 1),
- PIN_FIELD_BASE(123, 123, 4, 0x0050, 0x10, 1, 1),
- PIN_FIELD_BASE(124, 124, 4, 0x0040, 0x10, 10, 1),
- PIN_FIELD_BASE(125, 125, 4, 0x0040, 0x10, 28, 1),
- PIN_FIELD_BASE(139, 139, 4, 0x0040, 0x10, 7, 1),
- PIN_FIELD_BASE(140, 140, 4, 0x0040, 0x10, 25, 1),
- PIN_FIELD_BASE(141, 141, 4, 0x0040, 0x10, 4, 1),
- PIN_FIELD_BASE(142, 142, 4, 0x0040, 0x10, 22, 1),
- PIN_FIELD_BASE(160, 160, 7, 0x0030, 0x10, 1, 1),
- PIN_FIELD_BASE(161, 161, 7, 0x0030, 0x10, 4, 1),
- PIN_FIELD_BASE(200, 200, 8, 0x0010, 0x10, 4, 1),
- PIN_FIELD_BASE(201, 201, 8, 0x0010, 0x10, 10, 1),
- PIN_FIELD_BASE(202, 202, 5, 0x0020, 0x10, 1, 1),
- PIN_FIELD_BASE(203, 203, 5, 0x0020, 0x10, 4, 1),
- PIN_FIELD_BASE(204, 204, 8, 0x0010, 0x10, 1, 1),
- PIN_FIELD_BASE(205, 205, 8, 0x0010, 0x10, 7, 1),
+ PIN_FIELD_BASE(118, 118, 4, 0x0040, 0x10, 0, 3),
+ PIN_FIELD_BASE(119, 119, 4, 0x0040, 0x10, 18, 3),
+ PIN_FIELD_BASE(120, 120, 4, 0x0040, 0x10, 15, 3),
+ PIN_FIELD_BASE(121, 121, 4, 0x0050, 0x10, 3, 3),
+ PIN_FIELD_BASE(122, 122, 4, 0x0040, 0x10, 12, 3),
+ PIN_FIELD_BASE(123, 123, 4, 0x0050, 0x10, 0, 3),
+ PIN_FIELD_BASE(124, 124, 4, 0x0040, 0x10, 9, 3),
+ PIN_FIELD_BASE(125, 125, 4, 0x0040, 0x10, 27, 3),
+ PIN_FIELD_BASE(139, 139, 4, 0x0040, 0x10, 6, 3),
+ PIN_FIELD_BASE(140, 140, 4, 0x0040, 0x10, 24, 3),
+ PIN_FIELD_BASE(141, 141, 4, 0x0040, 0x10, 3, 3),
+ PIN_FIELD_BASE(142, 142, 4, 0x0040, 0x10, 21, 3),
+ PIN_FIELD_BASE(160, 160, 7, 0x0030, 0x10, 0, 3),
+ PIN_FIELD_BASE(161, 161, 7, 0x0030, 0x10, 3, 3),
+ PIN_FIELD_BASE(200, 200, 8, 0x0010, 0x10, 3, 3),
+ PIN_FIELD_BASE(201, 201, 8, 0x0010, 0x10, 9, 3),
+ PIN_FIELD_BASE(202, 202, 5, 0x0020, 0x10, 0, 3),
+ PIN_FIELD_BASE(203, 203, 5, 0x0020, 0x10, 3, 3),
+ PIN_FIELD_BASE(204, 204, 8, 0x0010, 0x10, 0, 3),
+ PIN_FIELD_BASE(205, 205, 8, 0x0010, 0x10, 6, 3),
};
-static const struct mtk_pin_field_calc mt8192_pin_e1_range[] = {
- PIN_FIELD_BASE(118, 118, 4, 0x0040, 0x10, 2, 1),
- PIN_FIELD_BASE(119, 119, 4, 0x0040, 0x10, 20, 1),
- PIN_FIELD_BASE(120, 120, 4, 0x0040, 0x10, 17, 1),
- PIN_FIELD_BASE(121, 121, 4, 0x0050, 0x10, 5, 1),
- PIN_FIELD_BASE(122, 122, 4, 0x0040, 0x10, 14, 1),
- PIN_FIELD_BASE(123, 123, 4, 0x0050, 0x10, 2, 1),
- PIN_FIELD_BASE(124, 124, 4, 0x0040, 0x10, 11, 1),
- PIN_FIELD_BASE(125, 125, 4, 0x0040, 0x10, 29, 1),
- PIN_FIELD_BASE(139, 139, 4, 0x0040, 0x10, 8, 1),
- PIN_FIELD_BASE(140, 140, 4, 0x0040, 0x10, 26, 1),
- PIN_FIELD_BASE(141, 141, 4, 0x0040, 0x10, 5, 1),
- PIN_FIELD_BASE(142, 142, 4, 0x0040, 0x10, 23, 1),
- PIN_FIELD_BASE(160, 160, 7, 0x0030, 0x10, 2, 1),
- PIN_FIELD_BASE(161, 161, 7, 0x0030, 0x10, 5, 1),
- PIN_FIELD_BASE(200, 200, 8, 0x0010, 0x10, 5, 1),
- PIN_FIELD_BASE(201, 201, 8, 0x0010, 0x10, 11, 1),
- PIN_FIELD_BASE(202, 202, 5, 0x0020, 0x10, 2, 1),
- PIN_FIELD_BASE(203, 203, 5, 0x0020, 0x10, 5, 1),
- PIN_FIELD_BASE(204, 204, 8, 0x0010, 0x10, 2, 1),
- PIN_FIELD_BASE(205, 205, 8, 0x0010, 0x10, 8, 1),
+static const struct mtk_pin_field_calc mt8192_pin_rsel_range[] = {
+ PIN_FIELD_BASE(118, 118, 4, 0x00e0, 0x10, 0, 2),
+ PIN_FIELD_BASE(119, 119, 4, 0x00e0, 0x10, 12, 2),
+ PIN_FIELD_BASE(120, 120, 4, 0x00e0, 0x10, 10, 2),
+ PIN_FIELD_BASE(121, 121, 4, 0x00e0, 0x10, 22, 2),
+ PIN_FIELD_BASE(122, 122, 4, 0x00e0, 0x10, 8, 2),
+ PIN_FIELD_BASE(123, 123, 4, 0x00e0, 0x10, 20, 2),
+ PIN_FIELD_BASE(124, 124, 4, 0x00e0, 0x10, 6, 2),
+ PIN_FIELD_BASE(125, 125, 4, 0x00e0, 0x10, 18, 2),
+ PIN_FIELD_BASE(139, 139, 4, 0x00e0, 0x10, 4, 2),
+ PIN_FIELD_BASE(140, 140, 4, 0x00e0, 0x10, 16, 2),
+ PIN_FIELD_BASE(141, 141, 4, 0x00e0, 0x10, 2, 2),
+ PIN_FIELD_BASE(142, 142, 4, 0x00e0, 0x10, 14, 2),
+ PIN_FIELD_BASE(160, 160, 7, 0x00f0, 0x10, 0, 2),
+ PIN_FIELD_BASE(161, 161, 7, 0x00f0, 0x10, 2, 2),
+ PIN_FIELD_BASE(200, 200, 8, 0x0070, 0x10, 2, 2),
+ PIN_FIELD_BASE(201, 201, 8, 0x0070, 0x10, 6, 2),
+ PIN_FIELD_BASE(202, 202, 5, 0x0070, 0x10, 0, 2),
+ PIN_FIELD_BASE(203, 203, 5, 0x0070, 0x10, 2, 2),
+ PIN_FIELD_BASE(204, 204, 8, 0x0070, 0x10, 0, 2),
+ PIN_FIELD_BASE(205, 205, 8, 0x0070, 0x10, 4, 2),
};
+static const unsigned int mt8192_pull_type[] = {
+ MTK_PULL_PU_PD_TYPE,/*0*/ MTK_PULL_PU_PD_TYPE,/*1*/
+ MTK_PULL_PU_PD_TYPE,/*2*/ MTK_PULL_PU_PD_TYPE,/*3*/
+ MTK_PULL_PU_PD_TYPE,/*4*/ MTK_PULL_PU_PD_TYPE,/*5*/
+ MTK_PULL_PU_PD_TYPE,/*6*/ MTK_PULL_PU_PD_TYPE,/*7*/
+ MTK_PULL_PU_PD_TYPE,/*8*/ MTK_PULL_PU_PD_TYPE,/*9*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*10*/ MTK_PULL_PUPD_R1R0_TYPE,/*11*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*12*/ MTK_PULL_PUPD_R1R0_TYPE,/*13*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*14*/ MTK_PULL_PUPD_R1R0_TYPE,/*15*/
+ MTK_PULL_PU_PD_TYPE,/*16*/ MTK_PULL_PU_PD_TYPE,/*17*/
+ MTK_PULL_PU_PD_TYPE,/*18*/ MTK_PULL_PU_PD_TYPE,/*19*/
+ MTK_PULL_PU_PD_TYPE,/*20*/ MTK_PULL_PU_PD_TYPE,/*21*/
+ MTK_PULL_PU_PD_TYPE,/*22*/ MTK_PULL_PU_PD_TYPE,/*23*/
+ MTK_PULL_PU_PD_TYPE,/*24*/ MTK_PULL_PU_PD_TYPE,/*25*/
+ MTK_PULL_PU_PD_TYPE,/*26*/ MTK_PULL_PU_PD_TYPE,/*27*/
+ MTK_PULL_PU_PD_TYPE,/*28*/ MTK_PULL_PU_PD_TYPE,/*29*/
+ MTK_PULL_PU_PD_TYPE,/*30*/ MTK_PULL_PU_PD_TYPE,/*31*/
+ MTK_PULL_PU_PD_TYPE,/*32*/ MTK_PULL_PU_PD_TYPE,/*33*/
+ MTK_PULL_PU_PD_TYPE,/*34*/ MTK_PULL_PU_PD_TYPE,/*35*/
+ MTK_PULL_PU_PD_TYPE,/*36*/ MTK_PULL_PU_PD_TYPE,/*37*/
+ MTK_PULL_PU_PD_TYPE,/*38*/ MTK_PULL_PU_PD_TYPE,/*39*/
+ MTK_PULL_PU_PD_TYPE,/*40*/ MTK_PULL_PU_PD_TYPE,/*41*/
+ MTK_PULL_PU_PD_TYPE,/*42*/ MTK_PULL_PU_PD_TYPE,/*43*/
+ MTK_PULL_PU_PD_TYPE,/*44*/ MTK_PULL_PUPD_R1R0_TYPE,/*45*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*46*/ MTK_PULL_PUPD_R1R0_TYPE,/*47*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*48*/ MTK_PULL_PUPD_R1R0_TYPE,/*49*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*50*/ MTK_PULL_PUPD_R1R0_TYPE,/*51*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*52*/ MTK_PULL_PUPD_R1R0_TYPE,/*53*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*54*/ MTK_PULL_PUPD_R1R0_TYPE,/*55*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*56*/ MTK_PULL_PU_PD_TYPE,/*57*/
+ MTK_PULL_PU_PD_TYPE,/*58*/ MTK_PULL_PU_PD_TYPE,/*59*/
+ MTK_PULL_PU_PD_TYPE,/*60*/ MTK_PULL_PU_PD_TYPE,/*61*/
+ MTK_PULL_PU_PD_TYPE,/*62*/ MTK_PULL_PU_PD_TYPE,/*63*/
+ MTK_PULL_PU_PD_TYPE,/*64*/ MTK_PULL_PU_PD_TYPE,/*65*/
+ MTK_PULL_PU_PD_TYPE,/*66*/ MTK_PULL_PU_PD_TYPE,/*67*/
+ MTK_PULL_PU_PD_TYPE,/*68*/ MTK_PULL_PU_PD_TYPE,/*69*/
+ MTK_PULL_PU_PD_TYPE,/*70*/ MTK_PULL_PU_PD_TYPE,/*71*/
+ MTK_PULL_PU_PD_TYPE,/*72*/ MTK_PULL_PU_PD_TYPE,/*73*/
+ MTK_PULL_PU_PD_TYPE,/*74*/ MTK_PULL_PU_PD_TYPE,/*75*/
+ MTK_PULL_PU_PD_TYPE,/*76*/ MTK_PULL_PU_PD_TYPE,/*77*/
+ MTK_PULL_PU_PD_TYPE,/*78*/ MTK_PULL_PU_PD_TYPE,/*79*/
+ MTK_PULL_PU_PD_TYPE,/*80*/ MTK_PULL_PU_PD_TYPE,/*81*/
+ MTK_PULL_PU_PD_TYPE,/*82*/ MTK_PULL_PU_PD_TYPE,/*83*/
+ MTK_PULL_PU_PD_TYPE,/*84*/ MTK_PULL_PU_PD_TYPE,/*85*/
+ MTK_PULL_PU_PD_TYPE,/*86*/ MTK_PULL_PU_PD_TYPE,/*87*/
+ MTK_PULL_PU_PD_TYPE,/*88*/ MTK_PULL_PU_PD_TYPE,/*89*/
+ MTK_PULL_PU_PD_TYPE,/*90*/ MTK_PULL_PU_PD_TYPE,/*91*/
+ MTK_PULL_PU_PD_TYPE,/*92*/ MTK_PULL_PU_PD_TYPE,/*93*/
+ MTK_PULL_PU_PD_TYPE,/*94*/ MTK_PULL_PU_PD_TYPE,/*95*/
+ MTK_PULL_PU_PD_TYPE,/*96*/ MTK_PULL_PU_PD_TYPE,/*97*/
+ MTK_PULL_PU_PD_TYPE,/*98*/ MTK_PULL_PU_PD_TYPE,/*99*/
+ MTK_PULL_PU_PD_TYPE,/*100*/ MTK_PULL_PU_PD_TYPE,/*101*/
+ MTK_PULL_PU_PD_TYPE,/*102*/ MTK_PULL_PU_PD_TYPE,/*103*/
+ MTK_PULL_PU_PD_TYPE,/*104*/ MTK_PULL_PU_PD_TYPE,/*105*/
+ MTK_PULL_PU_PD_TYPE,/*106*/ MTK_PULL_PU_PD_TYPE,/*107*/
+ MTK_PULL_PU_PD_TYPE,/*108*/ MTK_PULL_PU_PD_TYPE,/*109*/
+ MTK_PULL_PU_PD_TYPE,/*110*/ MTK_PULL_PU_PD_TYPE,/*111*/
+ MTK_PULL_PU_PD_TYPE,/*112*/ MTK_PULL_PU_PD_TYPE,/*113*/
+ MTK_PULL_PU_PD_TYPE,/*114*/ MTK_PULL_PU_PD_TYPE,/*115*/
+ MTK_PULL_PU_PD_TYPE,/*116*/ MTK_PULL_PU_PD_TYPE,/*117*/
+ MTK_PULL_PU_PD_RSEL_TYPE,/*118*/ MTK_PULL_PU_PD_RSEL_TYPE,/*119*/
+ MTK_PULL_PU_PD_RSEL_TYPE,/*120*/ MTK_PULL_PU_PD_RSEL_TYPE,/*121*/
+ MTK_PULL_PU_PD_RSEL_TYPE,/*122*/ MTK_PULL_PU_PD_RSEL_TYPE,/*123*/
+ MTK_PULL_PU_PD_RSEL_TYPE,/*124*/ MTK_PULL_PU_PD_RSEL_TYPE,/*125*/
+ MTK_PULL_PU_PD_TYPE,/*126*/ MTK_PULL_PU_PD_TYPE,/*127*/
+ MTK_PULL_PU_PD_TYPE,/*128*/ MTK_PULL_PU_PD_TYPE,/*129*/
+ MTK_PULL_PU_PD_TYPE,/*130*/ MTK_PULL_PU_PD_TYPE,/*131*/
+ MTK_PULL_PU_PD_TYPE,/*132*/ MTK_PULL_PU_PD_TYPE,/*133*/
+ MTK_PULL_PU_PD_TYPE,/*134*/ MTK_PULL_PU_PD_TYPE,/*135*/
+ MTK_PULL_PU_PD_TYPE,/*136*/ MTK_PULL_PU_PD_TYPE,/*137*/
+ MTK_PULL_PU_PD_TYPE,/*138*/ MTK_PULL_PU_PD_RSEL_TYPE,/*139*/
+ MTK_PULL_PU_PD_RSEL_TYPE,/*140*/ MTK_PULL_PU_PD_RSEL_TYPE,/*141*/
+ MTK_PULL_PU_PD_RSEL_TYPE,/*142*/ MTK_PULL_PU_PD_TYPE,/*143*/
+ MTK_PULL_PU_PD_TYPE,/*144*/ MTK_PULL_PU_PD_TYPE,/*145*/
+ MTK_PULL_PU_PD_TYPE,/*146*/ MTK_PULL_PU_PD_TYPE,/*147*/
+ MTK_PULL_PU_PD_TYPE,/*148*/ MTK_PULL_PU_PD_TYPE,/*149*/
+ MTK_PULL_PU_PD_TYPE,/*150*/ MTK_PULL_PU_PD_TYPE,/*151*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*152*/ MTK_PULL_PUPD_R1R0_TYPE,/*153*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*154*/ MTK_PULL_PUPD_R1R0_TYPE,/*155*/
+ MTK_PULL_PU_PD_TYPE,/*156*/ MTK_PULL_PU_PD_TYPE,/*157*/
+ MTK_PULL_PU_PD_TYPE,/*158*/ MTK_PULL_PU_PD_TYPE,/*159*/
+ MTK_PULL_PU_PD_RSEL_TYPE,/*160*/ MTK_PULL_PU_PD_RSEL_TYPE,/*161*/
+ MTK_PULL_PU_PD_TYPE,/*162*/ MTK_PULL_PU_PD_TYPE,/*163*/
+ MTK_PULL_PU_PD_TYPE,/*164*/ MTK_PULL_PU_PD_TYPE,/*165*/
+ MTK_PULL_PU_PD_TYPE,/*166*/ MTK_PULL_PU_PD_TYPE,/*167*/
+ MTK_PULL_PU_PD_TYPE,/*168*/ MTK_PULL_PU_PD_TYPE,/*169*/
+ MTK_PULL_PU_PD_TYPE,/*170*/ MTK_PULL_PU_PD_TYPE,/*171*/
+ MTK_PULL_PU_PD_TYPE,/*172*/ MTK_PULL_PU_PD_TYPE,/*173*/
+ MTK_PULL_PU_PD_TYPE,/*174*/ MTK_PULL_PU_PD_TYPE,/*175*/
+ MTK_PULL_PU_PD_TYPE,/*176*/ MTK_PULL_PU_PD_TYPE,/*177*/
+ MTK_PULL_PU_PD_TYPE,/*178*/ MTK_PULL_PU_PD_TYPE,/*179*/
+ MTK_PULL_PU_PD_TYPE,/*180*/ MTK_PULL_PU_PD_TYPE,/*181*/
+ MTK_PULL_PU_PD_TYPE,/*182*/ MTK_PULL_PUPD_R1R0_TYPE,/*183*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*184*/ MTK_PULL_PUPD_R1R0_TYPE,/*185*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*186*/ MTK_PULL_PUPD_R1R0_TYPE,/*187*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*188*/ MTK_PULL_PUPD_R1R0_TYPE,/*189*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*190*/ MTK_PULL_PUPD_R1R0_TYPE,/*191*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*192*/ MTK_PULL_PUPD_R1R0_TYPE,/*193*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*194*/ MTK_PULL_PU_PD_TYPE,/*195*/
+ MTK_PULL_PU_PD_TYPE,/*196*/ MTK_PULL_PU_PD_TYPE,/*197*/
+ MTK_PULL_PU_PD_TYPE,/*198*/ MTK_PULL_PU_PD_TYPE,/*199*/
+ MTK_PULL_PU_PD_RSEL_TYPE,/*200*/ MTK_PULL_PU_PD_RSEL_TYPE,/*201*/
+ MTK_PULL_PU_PD_RSEL_TYPE,/*202*/ MTK_PULL_PU_PD_RSEL_TYPE,/*203*/
+ MTK_PULL_PU_PD_RSEL_TYPE,/*204*/ MTK_PULL_PU_PD_RSEL_TYPE,/*205*/
+ MTK_PULL_PU_PD_TYPE,/*206*/ MTK_PULL_PU_PD_TYPE,/*207*/
+ MTK_PULL_PU_PD_TYPE,/*208*/ MTK_PULL_PU_PD_TYPE,/*209*/
+ MTK_PULL_PU_PD_TYPE,/*210*/ MTK_PULL_PU_PD_TYPE,/*211*/
+ MTK_PULL_PU_PD_TYPE,/*212*/ MTK_PULL_PU_PD_TYPE,/*213*/
+ MTK_PULL_PU_PD_TYPE,/*214*/ MTK_PULL_PU_PD_TYPE,/*215*/
+ MTK_PULL_PU_PD_TYPE,/*216*/ MTK_PULL_PU_PD_TYPE,/*217*/
+ MTK_PULL_PU_PD_TYPE,/*218*/ MTK_PULL_PU_PD_TYPE,/*219*/
+};
static const char * const mt8192_pinctrl_register_base_names[] = {
"iocfg0", "iocfg_rm", "iocfg_bm", "iocfg_bl", "iocfg_br",
[PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt8192_pin_pupd_range),
[PINCTRL_PIN_REG_R0] = MTK_RANGE(mt8192_pin_r0_range),
[PINCTRL_PIN_REG_R1] = MTK_RANGE(mt8192_pin_r1_range),
- [PINCTRL_PIN_REG_DRV_EN] = MTK_RANGE(mt8192_pin_e1e0en_range),
- [PINCTRL_PIN_REG_DRV_E0] = MTK_RANGE(mt8192_pin_e0_range),
- [PINCTRL_PIN_REG_DRV_E1] = MTK_RANGE(mt8192_pin_e1_range),
+ [PINCTRL_PIN_REG_DRV_ADV] = MTK_RANGE(mt8192_pin_drv_adv_range),
+ [PINCTRL_PIN_REG_RSEL] = MTK_RANGE(mt8192_pin_rsel_range),
};
static const struct mtk_pin_soc mt8192_data = {
.ngrps = ARRAY_SIZE(mtk_pins_mt8192),
.base_names = mt8192_pinctrl_register_base_names,
.nbase_names = ARRAY_SIZE(mt8192_pinctrl_register_base_names),
+ .pull_type = mt8192_pull_type,
.eint_hw = &mt8192_eint_hw,
.nfuncs = 8,
.gpio_m = 0,
.bias_set_combo = mtk_pinconf_bias_set_combo,
.bias_get_combo = mtk_pinconf_bias_get_combo,
- .drive_set = mtk_pinconf_drive_set_raw,
- .drive_get = mtk_pinconf_drive_get_raw,
- .adv_pull_get = mtk_pinconf_adv_pull_get,
- .adv_pull_set = mtk_pinconf_adv_pull_set,
- .adv_drive_get = mtk_pinconf_adv_drive_get,
- .adv_drive_set = mtk_pinconf_adv_drive_set,
+ .drive_set = mtk_pinconf_drive_set_rev1,
+ .drive_get = mtk_pinconf_drive_get_rev1,
+ .adv_drive_get = mtk_pinconf_adv_drive_get_raw,
+ .adv_drive_set = mtk_pinconf_adv_drive_set_raw,
};
static const struct of_device_id mt8192_pinctrl_of_match[] = {
struct mvebu_pinctrl *pctl, const char *name)
{
unsigned n;
+
for (n = 0; n < pctl->num_groups; n++) {
if (strcmp(name, pctl->groups[n].name) == 0)
return &pctl->groups[n];
}
+
return NULL;
}
unsigned long config)
{
unsigned n;
+
for (n = 0; n < grp->num_settings; n++) {
if (config == grp->settings[n].val) {
if (!pctl->variant || (pctl->variant &
return &grp->settings[n];
}
}
+
return NULL;
}
const char *name)
{
unsigned n;
+
for (n = 0; n < grp->num_settings; n++) {
if (strcmp(name, grp->settings[n].name) == 0) {
if (!pctl->variant || (pctl->variant &
return &grp->settings[n];
}
}
+
return NULL;
}
struct mvebu_pinctrl *pctl, struct mvebu_pinctrl_group *grp)
{
unsigned n;
+
for (n = 0; n < grp->num_settings; n++) {
if (grp->settings[n].flags &
(MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) {
return &grp->settings[n];
}
}
+
return NULL;
}
struct mvebu_pinctrl *pctl, const char *name)
{
unsigned n;
+
for (n = 0; n < pctl->num_functions; n++) {
if (strcmp(name, pctl->functions[n].name) == 0)
return &pctl->functions[n];
}
+
return NULL;
}
has_config = nmk_pinctrl_dt_get_config(np, &configs);
np_config = of_parse_phandle(np, "ste,config", 0);
- if (np_config)
+ if (np_config) {
has_config |= nmk_pinctrl_dt_get_config(np_config, &configs);
+ of_node_put(np_config);
+ }
if (has_config) {
const char *gpio_name;
const char *pin;
* Authors: Ken Xue <Ken.Xue@amd.com>
* Wu, Jeff <Jeff.Wu@amd.com>
*
- * Contact Information: Nehal Shah <Nehal-bakulchandra.Shah@amd.com>
- * Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
*/
#include <linux/err.h>
#include <linux/bitops.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
#include "core.h"
#include "pinctrl-utils.h"
struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
bool tmr_out_unit;
- unsigned int time;
- unsigned int unit;
bool tmr_large;
char *level_trig;
char *pull_up_sel;
char *pull_up_enable;
char *pull_down_enable;
- char *output_value;
- char *output_enable;
+ char *orientation;
char debounce_value[40];
char *debounce_enable;
for (bank = 0; bank < gpio_dev->hwbank_num; bank++) {
- seq_printf(s, "GPIO bank%d\t", bank);
+ unsigned int time = 0;
+ unsigned int unit = 0;
switch (bank) {
case 0:
/* Illegal bank number, ignore */
continue;
}
+ seq_printf(s, "GPIO bank%d\n", bank);
for (; i < pin_num; i++) {
- seq_printf(s, "pin%d\t", i);
+ seq_printf(s, "📌%d\t", i);
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
pin_reg = readl(gpio_dev->base + i * 4);
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
if (pin_reg & BIT(INTERRUPT_ENABLE_OFF)) {
u8 level = (pin_reg >> ACTIVE_LEVEL_OFF) &
ACTIVE_LEVEL_MASK;
- interrupt_enable = "interrupt is enabled|";
+ interrupt_enable = "+";
if (level == ACTIVE_LEVEL_HIGH)
- active_level = "Active high|";
+ active_level = "↑";
else if (level == ACTIVE_LEVEL_LOW)
- active_level = "Active low|";
+ active_level = "↓";
else if (!(pin_reg & BIT(LEVEL_TRIG_OFF)) &&
level == ACTIVE_LEVEL_BOTH)
- active_level = "Active on both|";
+ active_level = "b";
else
- active_level = "Unknown Active level|";
+ active_level = "?";
if (pin_reg & BIT(LEVEL_TRIG_OFF))
- level_trig = "Level trigger|";
+ level_trig = "level";
else
- level_trig = "Edge trigger|";
+ level_trig = " edge";
} else {
- interrupt_enable =
- "interrupt is disabled|";
- active_level = " ";
- level_trig = " ";
+ interrupt_enable = "∅";
+ active_level = "∅";
+ level_trig = " ∅";
}
if (pin_reg & BIT(INTERRUPT_MASK_OFF))
- interrupt_mask =
- "interrupt is unmasked|";
+ interrupt_mask = "-";
else
- interrupt_mask =
- "interrupt is masked|";
+ interrupt_mask = "+";
+ seq_printf(s, "int %s (🎭 %s)| active-%s| %s-🔫| ",
+ interrupt_enable,
+ interrupt_mask,
+ active_level,
+ level_trig);
if (pin_reg & BIT(WAKE_CNTRL_OFF_S0I3))
- wake_cntrl0 = "enable wakeup in S0i3 state|";
+ wake_cntrl0 = "+";
else
- wake_cntrl0 = "disable wakeup in S0i3 state|";
+ wake_cntrl0 = "∅";
+ seq_printf(s, "S0i3 🌅 %s| ", wake_cntrl0);
if (pin_reg & BIT(WAKE_CNTRL_OFF_S3))
- wake_cntrl1 = "enable wakeup in S3 state|";
+ wake_cntrl1 = "+";
else
- wake_cntrl1 = "disable wakeup in S3 state|";
+ wake_cntrl1 = "∅";
+ seq_printf(s, "S3 🌅 %s| ", wake_cntrl1);
if (pin_reg & BIT(WAKE_CNTRL_OFF_S4))
- wake_cntrl2 = "enable wakeup in S4/S5 state|";
+ wake_cntrl2 = "+";
else
- wake_cntrl2 = "disable wakeup in S4/S5 state|";
+ wake_cntrl2 = "∅";
+ seq_printf(s, "S4/S5 🌅 %s| ", wake_cntrl2);
if (pin_reg & BIT(PULL_UP_ENABLE_OFF)) {
- pull_up_enable = "pull-up is enabled|";
+ pull_up_enable = "+";
if (pin_reg & BIT(PULL_UP_SEL_OFF))
- pull_up_sel = "8k pull-up|";
+ pull_up_sel = "8k";
else
- pull_up_sel = "4k pull-up|";
+ pull_up_sel = "4k";
} else {
- pull_up_enable = "pull-up is disabled|";
- pull_up_sel = " ";
+ pull_up_enable = "∅";
+ pull_up_sel = " ";
}
+ seq_printf(s, "pull-↑ %s (%s)| ",
+ pull_up_enable,
+ pull_up_sel);
if (pin_reg & BIT(PULL_DOWN_ENABLE_OFF))
- pull_down_enable = "pull-down is enabled|";
+ pull_down_enable = "+";
else
- pull_down_enable = "Pull-down is disabled|";
+ pull_down_enable = "∅";
+ seq_printf(s, "pull-↓ %s| ", pull_down_enable);
if (pin_reg & BIT(OUTPUT_ENABLE_OFF)) {
- pin_sts = " ";
- output_enable = "output is enabled|";
+ pin_sts = "output";
if (pin_reg & BIT(OUTPUT_VALUE_OFF))
- output_value = "output is high|";
+ orientation = "↑";
else
- output_value = "output is low|";
+ orientation = "↓";
} else {
- output_enable = "output is disabled|";
- output_value = " ";
-
+ pin_sts = "input ";
if (pin_reg & BIT(PIN_STS_OFF))
- pin_sts = "input is high|";
+ orientation = "↑";
else
- pin_sts = "input is low|";
+ orientation = "↓";
}
+ seq_printf(s, "%s %s| ", pin_sts, orientation);
db_cntrl = (DB_CNTRl_MASK << DB_CNTRL_OFF) & pin_reg;
if (db_cntrl) {
unit = 61;
}
if ((DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF) == db_cntrl)
- debounce_enable = "debouncing filter (high and low) enabled|";
+ debounce_enable = "b +";
else if ((DB_TYPE_PRESERVE_LOW_GLITCH << DB_CNTRL_OFF) == db_cntrl)
- debounce_enable = "debouncing filter (low) enabled|";
+ debounce_enable = "↓ +";
else
- debounce_enable = "debouncing filter (high) enabled|";
+ debounce_enable = "↑ +";
- snprintf(debounce_value, sizeof(debounce_value),
- "debouncing timeout is %u (us)|", time * unit);
} else {
- debounce_enable = "debouncing filter disabled|";
- snprintf(debounce_value, sizeof(debounce_value), " ");
+ debounce_enable = " ∅";
}
-
- seq_printf(s, "%s %s %s %s %s %s\n"
- " %s %s %s %s %s %s %s %s %s 0x%x\n",
- level_trig, active_level, interrupt_enable,
- interrupt_mask, wake_cntrl0, wake_cntrl1,
- wake_cntrl2, pin_sts, pull_up_sel,
- pull_up_enable, pull_down_enable,
- output_value, output_enable,
- debounce_enable, debounce_value, pin_reg);
+ snprintf(debounce_value, sizeof(debounce_value), "%u", time * unit);
+ seq_printf(s, "debounce %s (⏰ %sus)| ", debounce_enable, debounce_value);
+ seq_printf(s, " 0x%x\n", pin_reg);
}
}
}
{
struct amd_gpio *gpio_dev = dev_get_drvdata(dev);
struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
+ unsigned long flags;
int i;
for (i = 0; i < desc->npins; i++) {
if (!amd_gpio_should_save(gpio_dev, pin))
continue;
- gpio_dev->saved_regs[i] = readl(gpio_dev->base + pin*4);
+ raw_spin_lock_irqsave(&gpio_dev->lock, flags);
+ gpio_dev->saved_regs[i] = readl(gpio_dev->base + pin * 4) & ~PIN_IRQ_PENDING;
+ raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
}
return 0;
{
struct amd_gpio *gpio_dev = dev_get_drvdata(dev);
struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
+ unsigned long flags;
int i;
for (i = 0; i < desc->npins; i++) {
if (!amd_gpio_should_save(gpio_dev, pin))
continue;
- writel(gpio_dev->saved_regs[i], gpio_dev->base + pin*4);
+ raw_spin_lock_irqsave(&gpio_dev->lock, flags);
+ gpio_dev->saved_regs[i] |= readl(gpio_dev->base + pin * 4) & PIN_IRQ_PENDING;
+ writel(gpio_dev->saved_regs[i], gpio_dev->base + pin * 4);
+ raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
}
return 0;
};
#endif
+static int amd_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(pmx_functions);
+}
+
+static const char *amd_get_fname(struct pinctrl_dev *pctrldev, unsigned int selector)
+{
+ return pmx_functions[selector].name;
+}
+
+static int amd_get_groups(struct pinctrl_dev *pctrldev, unsigned int selector,
+ const char * const **groups,
+ unsigned int * const num_groups)
+{
+ struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctrldev);
+
+ if (!gpio_dev->iomux_base) {
+ dev_err(&gpio_dev->pdev->dev, "iomux function %d group not supported\n", selector);
+ return -EINVAL;
+ }
+
+ *groups = pmx_functions[selector].groups;
+ *num_groups = pmx_functions[selector].ngroups;
+ return 0;
+}
+
+static int amd_set_mux(struct pinctrl_dev *pctrldev, unsigned int function, unsigned int group)
+{
+ struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctrldev);
+ struct device *dev = &gpio_dev->pdev->dev;
+ struct pin_desc *pd;
+ int ind, index;
+
+ if (!gpio_dev->iomux_base)
+ return -EINVAL;
+
+ for (index = 0; index < NSELECTS; index++) {
+ if (strcmp(gpio_dev->groups[group].name, pmx_functions[function].groups[index]))
+ continue;
+
+ if (readb(gpio_dev->iomux_base + pmx_functions[function].index) ==
+ FUNCTION_INVALID) {
+ dev_err(dev, "IOMUX_GPIO 0x%x not present or supported\n",
+ pmx_functions[function].index);
+ return -EINVAL;
+ }
+
+ writeb(index, gpio_dev->iomux_base + pmx_functions[function].index);
+
+ if (index != (readb(gpio_dev->iomux_base + pmx_functions[function].index) &
+ FUNCTION_MASK)) {
+ dev_err(dev, "IOMUX_GPIO 0x%x not present or supported\n",
+ pmx_functions[function].index);
+ return -EINVAL;
+ }
+
+ for (ind = 0; ind < gpio_dev->groups[group].npins; ind++) {
+ if (strncmp(gpio_dev->groups[group].name, "IMX_F", strlen("IMX_F")))
+ continue;
+
+ pd = pin_desc_get(gpio_dev->pctrl, gpio_dev->groups[group].pins[ind]);
+ pd->mux_owner = gpio_dev->groups[group].name;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static const struct pinmux_ops amd_pmxops = {
+ .get_functions_count = amd_get_functions_count,
+ .get_function_name = amd_get_fname,
+ .get_function_groups = amd_get_groups,
+ .set_mux = amd_set_mux,
+};
+
static struct pinctrl_desc amd_pinctrl_desc = {
.pins = kerncz_pins,
.npins = ARRAY_SIZE(kerncz_pins),
.pctlops = &amd_pinctrl_ops,
+ .pmxops = &amd_pmxops,
.confops = &amd_pinconf_ops,
.owner = THIS_MODULE,
};
+static void amd_get_iomux_res(struct amd_gpio *gpio_dev)
+{
+ struct pinctrl_desc *desc = &amd_pinctrl_desc;
+ struct device *dev = &gpio_dev->pdev->dev;
+ int index;
+
+ index = device_property_match_string(dev, "pinctrl-resource-names", "iomux");
+ if (index < 0) {
+ dev_warn(dev, "failed to get iomux index\n");
+ goto out_no_pinmux;
+ }
+
+ gpio_dev->iomux_base = devm_platform_ioremap_resource(gpio_dev->pdev, index);
+ if (IS_ERR(gpio_dev->iomux_base)) {
+ dev_warn(dev, "Failed to get iomux %d io resource\n", index);
+ goto out_no_pinmux;
+ }
+
+ return;
+
+out_no_pinmux:
+ desc->pmxops = NULL;
+}
+
static int amd_gpio_probe(struct platform_device *pdev)
{
int ret = 0;
raw_spin_lock_init(&gpio_dev->lock);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
+ gpio_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(gpio_dev->base)) {
dev_err(&pdev->dev, "Failed to get gpio io resource.\n");
- return -EINVAL;
+ return PTR_ERR(gpio_dev->base);
}
- gpio_dev->base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!gpio_dev->base)
- return -ENOMEM;
-
gpio_dev->irq = platform_get_irq(pdev, 0);
if (gpio_dev->irq < 0)
return gpio_dev->irq;
gpio_dev->ngroups = ARRAY_SIZE(kerncz_groups);
amd_pinctrl_desc.name = dev_name(&pdev->dev);
+ amd_get_iomux_res(gpio_dev);
gpio_dev->pctrl = devm_pinctrl_register(&pdev->dev, &amd_pinctrl_desc,
gpio_dev);
if (IS_ERR(gpio_dev->pctrl)) {
#define CLR_INTR_STAT 0x1UL
-struct amd_pingroup {
- const char *name;
- const unsigned *pins;
- unsigned npins;
-};
+#define NSELECTS 0x4
+
+#define FUNCTION_MASK GENMASK(1, 0)
+#define FUNCTION_INVALID GENMASK(7, 0)
struct amd_function {
const char *name;
- const char * const *groups;
+ const char * const groups[NSELECTS];
unsigned ngroups;
+ int index;
};
struct amd_gpio {
raw_spinlock_t lock;
void __iomem *base;
+ void __iomem *iomux_base;
- const struct amd_pingroup *groups;
+ const struct pingroup *groups;
u32 ngroups;
struct pinctrl_dev *pctrl;
struct gpio_chip gc;
PINCTRL_PIN(183, "GPIO_183"),
};
-static const unsigned i2c0_pins[] = {145, 146};
-static const unsigned i2c1_pins[] = {147, 148};
-static const unsigned i2c2_pins[] = {113, 114};
-static const unsigned i2c3_pins[] = {19, 20};
+#define AMD_PINS(...) (const unsigned int []){__VA_ARGS__}
+
+enum amd_functions {
+ IMX_F0_GPIO0,
+ IMX_F1_GPIO0,
+ IMX_F2_GPIO0,
+ IMX_F3_GPIO0,
+ IMX_F0_GPIO1,
+ IMX_F1_GPIO1,
+ IMX_F2_GPIO1,
+ IMX_F3_GPIO1,
+ IMX_F0_GPIO2,
+ IMX_F1_GPIO2,
+ IMX_F2_GPIO2,
+ IMX_F3_GPIO2,
+ IMX_F0_GPIO3,
+ IMX_F1_GPIO3,
+ IMX_F2_GPIO3,
+ IMX_F3_GPIO3,
+ IMX_F0_GPIO4,
+ IMX_F1_GPIO4,
+ IMX_F2_GPIO4,
+ IMX_F3_GPIO4,
+ IMX_F0_GPIO5,
+ IMX_F1_GPIO5,
+ IMX_F2_GPIO5,
+ IMX_F3_GPIO5,
+ IMX_F0_GPIO6,
+ IMX_F1_GPIO6,
+ IMX_F2_GPIO6,
+ IMX_F3_GPIO6,
+ IMX_F0_GPIO7,
+ IMX_F1_GPIO7,
+ IMX_F2_GPIO7,
+ IMX_F3_GPIO7,
+ IMX_F0_GPIO8,
+ IMX_F1_GPIO8,
+ IMX_F2_GPIO8,
+ IMX_F3_GPIO8,
+ IMX_F0_GPIO9,
+ IMX_F1_GPIO9,
+ IMX_F2_GPIO9,
+ IMX_F3_GPIO9,
+ IMX_F0_GPIO10,
+ IMX_F1_GPIO10,
+ IMX_F2_GPIO10,
+ IMX_F3_GPIO10,
+ IMX_F0_GPIO11,
+ IMX_F1_GPIO11,
+ IMX_F2_GPIO11,
+ IMX_F3_GPIO11,
+ IMX_F0_GPIO12,
+ IMX_F1_GPIO12,
+ IMX_F2_GPIO12,
+ IMX_F3_GPIO12,
+ IMX_F0_GPIO13,
+ IMX_F1_GPIO13,
+ IMX_F2_GPIO13,
+ IMX_F3_GPIO13,
+ IMX_F0_GPIO14,
+ IMX_F1_GPIO14,
+ IMX_F2_GPIO14,
+ IMX_F3_GPIO14,
+ IMX_F0_GPIO15,
+ IMX_F1_GPIO15,
+ IMX_F2_GPIO15,
+ IMX_F3_GPIO15,
+ IMX_F0_GPIO16,
+ IMX_F1_GPIO16,
+ IMX_F2_GPIO16,
+ IMX_F3_GPIO16,
+ IMX_F0_GPIO17,
+ IMX_F1_GPIO17,
+ IMX_F2_GPIO17,
+ IMX_F3_GPIO17,
+ IMX_F0_GPIO18,
+ IMX_F1_GPIO18,
+ IMX_F2_GPIO18,
+ IMX_F3_GPIO18,
+ IMX_F0_GPIO19,
+ IMX_F1_GPIO19,
+ IMX_F2_GPIO19,
+ IMX_F3_GPIO19,
+ IMX_F0_GPIO20,
+ IMX_F1_GPIO20,
+ IMX_F2_GPIO20,
+ IMX_F3_GPIO20,
+ IMX_F0_GPIO21,
+ IMX_F1_GPIO21,
+ IMX_F2_GPIO21,
+ IMX_F3_GPIO21,
+ IMX_F0_GPIO22,
+ IMX_F1_GPIO22,
+ IMX_F2_GPIO22,
+ IMX_F3_GPIO22,
+ IMX_F0_GPIO23,
+ IMX_F1_GPIO23,
+ IMX_F2_GPIO23,
+ IMX_F3_GPIO23,
+ IMX_F0_GPIO24,
+ IMX_F1_GPIO24,
+ IMX_F2_GPIO24,
+ IMX_F3_GPIO24,
+ IMX_F0_GPIO25,
+ IMX_F1_GPIO25,
+ IMX_F2_GPIO25,
+ IMX_F3_GPIO25,
+ IMX_F0_GPIO26,
+ IMX_F1_GPIO26,
+ IMX_F2_GPIO26,
+ IMX_F3_GPIO26,
+ IMX_F0_GPIO27,
+ IMX_F1_GPIO27,
+ IMX_F2_GPIO27,
+ IMX_F3_GPIO27,
+ IMX_F0_GPIO28,
+ IMX_F1_GPIO28,
+ IMX_F2_GPIO28,
+ IMX_F3_GPIO28,
+ IMX_F0_GPIO29,
+ IMX_F1_GPIO29,
+ IMX_F2_GPIO29,
+ IMX_F3_GPIO29,
+ IMX_F0_GPIO30,
+ IMX_F1_GPIO30,
+ IMX_F2_GPIO30,
+ IMX_F3_GPIO30,
+ IMX_F0_GPIO31,
+ IMX_F1_GPIO31,
+ IMX_F2_GPIO31,
+ IMX_F3_GPIO31,
+ IMX_F0_GPIO32,
+ IMX_F1_GPIO32,
+ IMX_F2_GPIO32,
+ IMX_F3_GPIO32,
+ IMX_F0_GPIO33,
+ IMX_F1_GPIO33,
+ IMX_F2_GPIO33,
+ IMX_F3_GPIO33,
+ IMX_F0_GPIO34,
+ IMX_F1_GPIO34,
+ IMX_F2_GPIO34,
+ IMX_F3_GPIO34,
+ IMX_F0_GPIO35,
+ IMX_F1_GPIO35,
+ IMX_F2_GPIO35,
+ IMX_F3_GPIO35,
+ IMX_F0_GPIO36,
+ IMX_F1_GPIO36,
+ IMX_F2_GPIO36,
+ IMX_F3_GPIO36,
+ IMX_F0_GPIO37,
+ IMX_F1_GPIO37,
+ IMX_F2_GPIO37,
+ IMX_F3_GPIO37,
+ IMX_F0_GPIO38,
+ IMX_F1_GPIO38,
+ IMX_F2_GPIO38,
+ IMX_F3_GPIO38,
+ IMX_F0_GPIO39,
+ IMX_F1_GPIO39,
+ IMX_F2_GPIO39,
+ IMX_F3_GPIO39,
+ IMX_F0_GPIO40,
+ IMX_F1_GPIO40,
+ IMX_F2_GPIO40,
+ IMX_F3_GPIO40,
+ IMX_F0_GPIO41,
+ IMX_F1_GPIO41,
+ IMX_F2_GPIO41,
+ IMX_F3_GPIO41,
+ IMX_F0_GPIO42,
+ IMX_F1_GPIO42,
+ IMX_F2_GPIO42,
+ IMX_F3_GPIO42,
+ IMX_F0_GPIO43,
+ IMX_F1_GPIO43,
+ IMX_F2_GPIO43,
+ IMX_F3_GPIO43,
+ IMX_F0_GPIO44,
+ IMX_F1_GPIO44,
+ IMX_F2_GPIO44,
+ IMX_F3_GPIO44,
+ IMX_F0_GPIO45,
+ IMX_F1_GPIO45,
+ IMX_F2_GPIO45,
+ IMX_F3_GPIO45,
+ IMX_F0_GPIO46,
+ IMX_F1_GPIO46,
+ IMX_F2_GPIO46,
+ IMX_F3_GPIO46,
+ IMX_F0_GPIO47,
+ IMX_F1_GPIO47,
+ IMX_F2_GPIO47,
+ IMX_F3_GPIO47,
+ IMX_F0_GPIO48,
+ IMX_F1_GPIO48,
+ IMX_F2_GPIO48,
+ IMX_F3_GPIO48,
+ IMX_F0_GPIO49,
+ IMX_F1_GPIO49,
+ IMX_F2_GPIO49,
+ IMX_F3_GPIO49,
+ IMX_F0_GPIO50,
+ IMX_F1_GPIO50,
+ IMX_F2_GPIO50,
+ IMX_F3_GPIO50,
+ IMX_F0_GPIO51,
+ IMX_F1_GPIO51,
+ IMX_F2_GPIO51,
+ IMX_F3_GPIO51,
+ IMX_F0_GPIO52,
+ IMX_F1_GPIO52,
+ IMX_F2_GPIO52,
+ IMX_F3_GPIO52,
+ IMX_F0_GPIO53,
+ IMX_F1_GPIO53,
+ IMX_F2_GPIO53,
+ IMX_F3_GPIO53,
+ IMX_F0_GPIO54,
+ IMX_F1_GPIO54,
+ IMX_F2_GPIO54,
+ IMX_F3_GPIO54,
+ IMX_F0_GPIO55,
+ IMX_F1_GPIO55,
+ IMX_F2_GPIO55,
+ IMX_F3_GPIO55,
+ IMX_F0_GPIO56,
+ IMX_F1_GPIO56,
+ IMX_F2_GPIO56,
+ IMX_F3_GPIO56,
+ IMX_F0_GPIO57,
+ IMX_F1_GPIO57,
+ IMX_F2_GPIO57,
+ IMX_F3_GPIO57,
+ IMX_F0_GPIO58,
+ IMX_F1_GPIO58,
+ IMX_F2_GPIO58,
+ IMX_F3_GPIO58,
+ IMX_F0_GPIO59,
+ IMX_F1_GPIO59,
+ IMX_F2_GPIO59,
+ IMX_F3_GPIO59,
+ IMX_F0_GPIO60,
+ IMX_F1_GPIO60,
+ IMX_F2_GPIO60,
+ IMX_F3_GPIO60,
+ IMX_F0_GPIO61,
+ IMX_F1_GPIO61,
+ IMX_F2_GPIO61,
+ IMX_F3_GPIO61,
+ IMX_F0_GPIO62,
+ IMX_F1_GPIO62,
+ IMX_F2_GPIO62,
+ IMX_F3_GPIO62,
+ IMX_F0_GPIO64,
+ IMX_F1_GPIO64,
+ IMX_F2_GPIO64,
+ IMX_F3_GPIO64,
+ IMX_F0_GPIO65,
+ IMX_F1_GPIO65,
+ IMX_F2_GPIO65,
+ IMX_F3_GPIO65,
+ IMX_F0_GPIO66,
+ IMX_F1_GPIO66,
+ IMX_F2_GPIO66,
+ IMX_F3_GPIO66,
+ IMX_F0_GPIO67,
+ IMX_F1_GPIO67,
+ IMX_F2_GPIO67,
+ IMX_F3_GPIO67,
+ IMX_F0_GPIO68,
+ IMX_F1_GPIO68,
+ IMX_F2_GPIO68,
+ IMX_F3_GPIO68,
+ IMX_F0_GPIO69,
+ IMX_F1_GPIO69,
+ IMX_F2_GPIO69,
+ IMX_F3_GPIO69,
+ IMX_F0_GPIO70,
+ IMX_F1_GPIO70,
+ IMX_F2_GPIO70,
+ IMX_F3_GPIO70,
+ IMX_F0_GPIO71,
+ IMX_F1_GPIO71,
+ IMX_F2_GPIO71,
+ IMX_F3_GPIO71,
+ IMX_F0_GPIO72,
+ IMX_F1_GPIO72,
+ IMX_F2_GPIO72,
+ IMX_F3_GPIO72,
+ IMX_F0_GPIO73,
+ IMX_F1_GPIO73,
+ IMX_F2_GPIO73,
+ IMX_F3_GPIO73,
+ IMX_F0_GPIO74,
+ IMX_F1_GPIO74,
+ IMX_F2_GPIO74,
+ IMX_F3_GPIO74,
+ IMX_F0_GPIO75,
+ IMX_F1_GPIO75,
+ IMX_F2_GPIO75,
+ IMX_F3_GPIO75,
+ IMX_F0_GPIO76,
+ IMX_F1_GPIO76,
+ IMX_F2_GPIO76,
+ IMX_F3_GPIO76,
+ IMX_F0_GPIO77,
+ IMX_F1_GPIO77,
+ IMX_F2_GPIO77,
+ IMX_F3_GPIO77,
+ IMX_F0_GPIO78,
+ IMX_F1_GPIO78,
+ IMX_F2_GPIO78,
+ IMX_F3_GPIO78,
+ IMX_F0_GPIO79,
+ IMX_F1_GPIO79,
+ IMX_F2_GPIO79,
+ IMX_F3_GPIO79,
+ IMX_F0_GPIO80,
+ IMX_F1_GPIO80,
+ IMX_F2_GPIO80,
+ IMX_F3_GPIO80,
+ IMX_F0_GPIO81,
+ IMX_F1_GPIO81,
+ IMX_F2_GPIO81,
+ IMX_F3_GPIO81,
+ IMX_F0_GPIO82,
+ IMX_F1_GPIO82,
+ IMX_F2_GPIO82,
+ IMX_F3_GPIO82,
+ IMX_F0_GPIO83,
+ IMX_F1_GPIO83,
+ IMX_F2_GPIO83,
+ IMX_F3_GPIO83,
+ IMX_F0_GPIO84,
+ IMX_F1_GPIO84,
+ IMX_F2_GPIO84,
+ IMX_F3_GPIO84,
+ IMX_F0_GPIO85,
+ IMX_F1_GPIO85,
+ IMX_F2_GPIO85,
+ IMX_F3_GPIO85,
+ IMX_F0_GPIO86,
+ IMX_F1_GPIO86,
+ IMX_F2_GPIO86,
+ IMX_F3_GPIO86,
+ IMX_F0_GPIO87,
+ IMX_F1_GPIO87,
+ IMX_F2_GPIO87,
+ IMX_F3_GPIO87,
+ IMX_F0_GPIO88,
+ IMX_F1_GPIO88,
+ IMX_F2_GPIO88,
+ IMX_F3_GPIO88,
+ IMX_F0_GPIO89,
+ IMX_F1_GPIO89,
+ IMX_F2_GPIO89,
+ IMX_F3_GPIO89,
+ IMX_F0_GPIO90,
+ IMX_F1_GPIO90,
+ IMX_F2_GPIO90,
+ IMX_F3_GPIO90,
+ IMX_F0_GPIO91,
+ IMX_F1_GPIO91,
+ IMX_F2_GPIO91,
+ IMX_F3_GPIO91,
+ IMX_F0_GPIO92,
+ IMX_F1_GPIO92,
+ IMX_F2_GPIO92,
+ IMX_F3_GPIO92,
+ IMX_F0_GPIO93,
+ IMX_F1_GPIO93,
+ IMX_F2_GPIO93,
+ IMX_F3_GPIO93,
+ IMX_F0_GPIO94,
+ IMX_F1_GPIO94,
+ IMX_F2_GPIO94,
+ IMX_F3_GPIO94,
+ IMX_F0_GPIO95,
+ IMX_F1_GPIO95,
+ IMX_F2_GPIO95,
+ IMX_F3_GPIO95,
+ IMX_F0_GPIO96,
+ IMX_F1_GPIO96,
+ IMX_F2_GPIO96,
+ IMX_F3_GPIO96,
+ IMX_F0_GPIO97,
+ IMX_F1_GPIO97,
+ IMX_F2_GPIO97,
+ IMX_F3_GPIO97,
+ IMX_F0_GPIO98,
+ IMX_F1_GPIO98,
+ IMX_F2_GPIO98,
+ IMX_F3_GPIO98,
+ IMX_F0_GPIO99,
+ IMX_F1_GPIO99,
+ IMX_F2_GPIO99,
+ IMX_F3_GPIO99,
+ IMX_F0_GPIO100,
+ IMX_F1_GPIO100,
+ IMX_F2_GPIO100,
+ IMX_F3_GPIO100,
+ IMX_F0_GPIO101,
+ IMX_F1_GPIO101,
+ IMX_F2_GPIO101,
+ IMX_F3_GPIO101,
+ IMX_F0_GPIO102,
+ IMX_F1_GPIO102,
+ IMX_F2_GPIO102,
+ IMX_F3_GPIO102,
+ IMX_F0_GPIO103,
+ IMX_F1_GPIO103,
+ IMX_F2_GPIO103,
+ IMX_F3_GPIO103,
+ IMX_F0_GPIO104,
+ IMX_F1_GPIO104,
+ IMX_F2_GPIO104,
+ IMX_F3_GPIO104,
+ IMX_F0_GPIO105,
+ IMX_F1_GPIO105,
+ IMX_F2_GPIO105,
+ IMX_F3_GPIO105,
+ IMX_F0_GPIO106,
+ IMX_F1_GPIO106,
+ IMX_F2_GPIO106,
+ IMX_F3_GPIO106,
+ IMX_F0_GPIO107,
+ IMX_F1_GPIO107,
+ IMX_F2_GPIO107,
+ IMX_F3_GPIO107,
+ IMX_F0_GPIO108,
+ IMX_F1_GPIO108,
+ IMX_F2_GPIO108,
+ IMX_F3_GPIO108,
+ IMX_F0_GPIO109,
+ IMX_F1_GPIO109,
+ IMX_F2_GPIO109,
+ IMX_F3_GPIO109,
+ IMX_F0_GPIO110,
+ IMX_F1_GPIO110,
+ IMX_F2_GPIO110,
+ IMX_F3_GPIO110,
+ IMX_F0_GPIO111,
+ IMX_F1_GPIO111,
+ IMX_F2_GPIO111,
+ IMX_F3_GPIO111,
+ IMX_F0_GPIO112,
+ IMX_F1_GPIO112,
+ IMX_F2_GPIO112,
+ IMX_F3_GPIO112,
+ IMX_F0_GPIO113,
+ IMX_F1_GPIO113,
+ IMX_F2_GPIO113,
+ IMX_F3_GPIO113,
+ IMX_F0_GPIO114,
+ IMX_F1_GPIO114,
+ IMX_F2_GPIO114,
+ IMX_F3_GPIO114,
+ IMX_F0_GPIO115,
+ IMX_F1_GPIO115,
+ IMX_F2_GPIO115,
+ IMX_F3_GPIO115,
+ IMX_F0_GPIO116,
+ IMX_F1_GPIO116,
+ IMX_F2_GPIO116,
+ IMX_F3_GPIO116,
+ IMX_F0_GPIO117,
+ IMX_F1_GPIO117,
+ IMX_F2_GPIO117,
+ IMX_F3_GPIO117,
+ IMX_F0_GPIO118,
+ IMX_F1_GPIO118,
+ IMX_F2_GPIO118,
+ IMX_F3_GPIO118,
+ IMX_F0_GPIO119,
+ IMX_F1_GPIO119,
+ IMX_F2_GPIO119,
+ IMX_F3_GPIO119,
+ IMX_F0_GPIO120,
+ IMX_F1_GPIO120,
+ IMX_F2_GPIO120,
+ IMX_F3_GPIO120,
+ IMX_F0_GPIO121,
+ IMX_F1_GPIO121,
+ IMX_F2_GPIO121,
+ IMX_F3_GPIO121,
+ IMX_F0_GPIO122,
+ IMX_F1_GPIO122,
+ IMX_F2_GPIO122,
+ IMX_F3_GPIO122,
+ IMX_F0_GPIO123,
+ IMX_F1_GPIO123,
+ IMX_F2_GPIO123,
+ IMX_F3_GPIO123,
+ IMX_F0_GPIO124,
+ IMX_F1_GPIO124,
+ IMX_F2_GPIO124,
+ IMX_F3_GPIO124,
+ IMX_F0_GPIO125,
+ IMX_F1_GPIO125,
+ IMX_F2_GPIO125,
+ IMX_F3_GPIO125,
+ IMX_F0_GPIO126,
+ IMX_F1_GPIO126,
+ IMX_F2_GPIO126,
+ IMX_F3_GPIO126,
+ IMX_F0_GPIO127,
+ IMX_F1_GPIO127,
+ IMX_F2_GPIO127,
+ IMX_F3_GPIO127,
+ IMX_F0_GPIO128,
+ IMX_F1_GPIO128,
+ IMX_F2_GPIO128,
+ IMX_F3_GPIO128,
+ IMX_F0_GPIO129,
+ IMX_F1_GPIO129,
+ IMX_F2_GPIO129,
+ IMX_F3_GPIO129,
+ IMX_F0_GPIO130,
+ IMX_F1_GPIO130,
+ IMX_F2_GPIO130,
+ IMX_F3_GPIO130,
+ IMX_F0_GPIO131,
+ IMX_F1_GPIO131,
+ IMX_F2_GPIO131,
+ IMX_F3_GPIO131,
+ IMX_F0_GPIO132,
+ IMX_F1_GPIO132,
+ IMX_F2_GPIO132,
+ IMX_F3_GPIO132,
+ IMX_F0_GPIO133,
+ IMX_F1_GPIO133,
+ IMX_F2_GPIO133,
+ IMX_F3_GPIO133,
+ IMX_F0_GPIO134,
+ IMX_F1_GPIO134,
+ IMX_F2_GPIO134,
+ IMX_F3_GPIO134,
+ IMX_F0_GPIO135,
+ IMX_F1_GPIO135,
+ IMX_F2_GPIO135,
+ IMX_F3_GPIO135,
+ IMX_F0_GPIO136,
+ IMX_F1_GPIO136,
+ IMX_F2_GPIO136,
+ IMX_F3_GPIO136,
+ IMX_F0_GPIO137,
+ IMX_F1_GPIO137,
+ IMX_F2_GPIO137,
+ IMX_F3_GPIO137,
+ IMX_F0_GPIO138,
+ IMX_F1_GPIO138,
+ IMX_F2_GPIO138,
+ IMX_F3_GPIO138,
+ IMX_F0_GPIO139,
+ IMX_F1_GPIO139,
+ IMX_F2_GPIO139,
+ IMX_F3_GPIO139,
+ IMX_F0_GPIO140,
+ IMX_F1_GPIO140,
+ IMX_F2_GPIO140,
+ IMX_F3_GPIO140,
+ IMX_F0_GPIO141,
+ IMX_F1_GPIO141,
+ IMX_F2_GPIO141,
+ IMX_F3_GPIO141,
+ IMX_F0_GPIO142,
+ IMX_F1_GPIO142,
+ IMX_F2_GPIO142,
+ IMX_F3_GPIO142,
+ IMX_F0_GPIO143,
+ IMX_F1_GPIO143,
+ IMX_F2_GPIO143,
+ IMX_F3_GPIO143,
+ IMX_F0_GPIO144,
+ IMX_F1_GPIO144,
+ IMX_F2_GPIO144,
+ IMX_F3_GPIO144,
+};
+
+#define AMD_PINCTRL_FUNC_GRP(_number, _func) \
+ [IMX_F##_func##_GPIO##_number] = \
+ PINCTRL_PINGROUP("IMX_F"#_func "_GPIO"#_number, AMD_PINS(_number), 1)
+
+static const struct pingroup kerncz_groups[] = {
+ AMD_PINCTRL_FUNC_GRP(0, 0),
+ AMD_PINCTRL_FUNC_GRP(0, 1),
+ AMD_PINCTRL_FUNC_GRP(0, 2),
+ AMD_PINCTRL_FUNC_GRP(0, 3),
+ AMD_PINCTRL_FUNC_GRP(1, 0),
+ AMD_PINCTRL_FUNC_GRP(1, 1),
+ AMD_PINCTRL_FUNC_GRP(1, 2),
+ AMD_PINCTRL_FUNC_GRP(1, 3),
+ AMD_PINCTRL_FUNC_GRP(2, 0),
+ AMD_PINCTRL_FUNC_GRP(2, 1),
+ AMD_PINCTRL_FUNC_GRP(2, 2),
+ AMD_PINCTRL_FUNC_GRP(2, 3),
+ AMD_PINCTRL_FUNC_GRP(3, 0),
+ AMD_PINCTRL_FUNC_GRP(3, 1),
+ AMD_PINCTRL_FUNC_GRP(3, 2),
+ AMD_PINCTRL_FUNC_GRP(3, 3),
+ AMD_PINCTRL_FUNC_GRP(4, 0),
+ AMD_PINCTRL_FUNC_GRP(4, 1),
+ AMD_PINCTRL_FUNC_GRP(4, 2),
+ AMD_PINCTRL_FUNC_GRP(4, 3),
+ AMD_PINCTRL_FUNC_GRP(5, 0),
+ AMD_PINCTRL_FUNC_GRP(5, 1),
+ AMD_PINCTRL_FUNC_GRP(5, 2),
+ AMD_PINCTRL_FUNC_GRP(5, 3),
+ AMD_PINCTRL_FUNC_GRP(6, 0),
+ AMD_PINCTRL_FUNC_GRP(6, 1),
+ AMD_PINCTRL_FUNC_GRP(6, 2),
+ AMD_PINCTRL_FUNC_GRP(6, 3),
+ AMD_PINCTRL_FUNC_GRP(7, 0),
+ AMD_PINCTRL_FUNC_GRP(7, 1),
+ AMD_PINCTRL_FUNC_GRP(7, 2),
+ AMD_PINCTRL_FUNC_GRP(7, 3),
+ AMD_PINCTRL_FUNC_GRP(8, 0),
+ AMD_PINCTRL_FUNC_GRP(8, 1),
+ AMD_PINCTRL_FUNC_GRP(8, 2),
+ AMD_PINCTRL_FUNC_GRP(8, 3),
+ AMD_PINCTRL_FUNC_GRP(9, 0),
+ AMD_PINCTRL_FUNC_GRP(9, 1),
+ AMD_PINCTRL_FUNC_GRP(9, 2),
+ AMD_PINCTRL_FUNC_GRP(9, 3),
+ AMD_PINCTRL_FUNC_GRP(10, 0),
+ AMD_PINCTRL_FUNC_GRP(10, 1),
+ AMD_PINCTRL_FUNC_GRP(10, 2),
+ AMD_PINCTRL_FUNC_GRP(10, 3),
+ AMD_PINCTRL_FUNC_GRP(11, 0),
+ AMD_PINCTRL_FUNC_GRP(11, 1),
+ AMD_PINCTRL_FUNC_GRP(11, 2),
+ AMD_PINCTRL_FUNC_GRP(11, 3),
+ AMD_PINCTRL_FUNC_GRP(12, 0),
+ AMD_PINCTRL_FUNC_GRP(12, 1),
+ AMD_PINCTRL_FUNC_GRP(12, 2),
+ AMD_PINCTRL_FUNC_GRP(12, 3),
+ AMD_PINCTRL_FUNC_GRP(13, 0),
+ AMD_PINCTRL_FUNC_GRP(13, 1),
+ AMD_PINCTRL_FUNC_GRP(13, 2),
+ AMD_PINCTRL_FUNC_GRP(13, 3),
+ AMD_PINCTRL_FUNC_GRP(14, 0),
+ AMD_PINCTRL_FUNC_GRP(14, 1),
+ AMD_PINCTRL_FUNC_GRP(14, 2),
+ AMD_PINCTRL_FUNC_GRP(14, 3),
+ AMD_PINCTRL_FUNC_GRP(15, 0),
+ AMD_PINCTRL_FUNC_GRP(15, 1),
+ AMD_PINCTRL_FUNC_GRP(15, 2),
+ AMD_PINCTRL_FUNC_GRP(15, 3),
+ AMD_PINCTRL_FUNC_GRP(16, 0),
+ AMD_PINCTRL_FUNC_GRP(16, 1),
+ AMD_PINCTRL_FUNC_GRP(16, 2),
+ AMD_PINCTRL_FUNC_GRP(16, 3),
+ AMD_PINCTRL_FUNC_GRP(17, 0),
+ AMD_PINCTRL_FUNC_GRP(17, 1),
+ AMD_PINCTRL_FUNC_GRP(17, 2),
+ AMD_PINCTRL_FUNC_GRP(17, 3),
+ AMD_PINCTRL_FUNC_GRP(18, 0),
+ AMD_PINCTRL_FUNC_GRP(18, 1),
+ AMD_PINCTRL_FUNC_GRP(18, 2),
+ AMD_PINCTRL_FUNC_GRP(18, 3),
+ AMD_PINCTRL_FUNC_GRP(19, 0),
+ AMD_PINCTRL_FUNC_GRP(19, 1),
+ AMD_PINCTRL_FUNC_GRP(19, 2),
+ AMD_PINCTRL_FUNC_GRP(19, 3),
+ AMD_PINCTRL_FUNC_GRP(20, 0),
+ AMD_PINCTRL_FUNC_GRP(20, 1),
+ AMD_PINCTRL_FUNC_GRP(20, 2),
+ AMD_PINCTRL_FUNC_GRP(20, 3),
+ AMD_PINCTRL_FUNC_GRP(21, 0),
+ AMD_PINCTRL_FUNC_GRP(21, 1),
+ AMD_PINCTRL_FUNC_GRP(21, 2),
+ AMD_PINCTRL_FUNC_GRP(21, 3),
+ AMD_PINCTRL_FUNC_GRP(22, 0),
+ AMD_PINCTRL_FUNC_GRP(22, 1),
+ AMD_PINCTRL_FUNC_GRP(22, 2),
+ AMD_PINCTRL_FUNC_GRP(22, 3),
+ AMD_PINCTRL_FUNC_GRP(23, 0),
+ AMD_PINCTRL_FUNC_GRP(23, 1),
+ AMD_PINCTRL_FUNC_GRP(23, 2),
+ AMD_PINCTRL_FUNC_GRP(23, 3),
+ AMD_PINCTRL_FUNC_GRP(24, 0),
+ AMD_PINCTRL_FUNC_GRP(24, 1),
+ AMD_PINCTRL_FUNC_GRP(24, 2),
+ AMD_PINCTRL_FUNC_GRP(24, 3),
+ AMD_PINCTRL_FUNC_GRP(25, 0),
+ AMD_PINCTRL_FUNC_GRP(25, 1),
+ AMD_PINCTRL_FUNC_GRP(25, 2),
+ AMD_PINCTRL_FUNC_GRP(25, 3),
+ AMD_PINCTRL_FUNC_GRP(26, 0),
+ AMD_PINCTRL_FUNC_GRP(26, 1),
+ AMD_PINCTRL_FUNC_GRP(26, 2),
+ AMD_PINCTRL_FUNC_GRP(26, 3),
+ AMD_PINCTRL_FUNC_GRP(27, 0),
+ AMD_PINCTRL_FUNC_GRP(27, 1),
+ AMD_PINCTRL_FUNC_GRP(27, 2),
+ AMD_PINCTRL_FUNC_GRP(27, 3),
+ AMD_PINCTRL_FUNC_GRP(28, 0),
+ AMD_PINCTRL_FUNC_GRP(28, 1),
+ AMD_PINCTRL_FUNC_GRP(28, 2),
+ AMD_PINCTRL_FUNC_GRP(28, 3),
+ AMD_PINCTRL_FUNC_GRP(29, 0),
+ AMD_PINCTRL_FUNC_GRP(29, 1),
+ AMD_PINCTRL_FUNC_GRP(29, 2),
+ AMD_PINCTRL_FUNC_GRP(29, 3),
+ AMD_PINCTRL_FUNC_GRP(30, 0),
+ AMD_PINCTRL_FUNC_GRP(30, 1),
+ AMD_PINCTRL_FUNC_GRP(30, 2),
+ AMD_PINCTRL_FUNC_GRP(30, 3),
+ AMD_PINCTRL_FUNC_GRP(31, 0),
+ AMD_PINCTRL_FUNC_GRP(31, 1),
+ AMD_PINCTRL_FUNC_GRP(31, 2),
+ AMD_PINCTRL_FUNC_GRP(31, 3),
+ AMD_PINCTRL_FUNC_GRP(32, 0),
+ AMD_PINCTRL_FUNC_GRP(32, 1),
+ AMD_PINCTRL_FUNC_GRP(32, 2),
+ AMD_PINCTRL_FUNC_GRP(32, 3),
+ AMD_PINCTRL_FUNC_GRP(33, 0),
+ AMD_PINCTRL_FUNC_GRP(33, 1),
+ AMD_PINCTRL_FUNC_GRP(33, 2),
+ AMD_PINCTRL_FUNC_GRP(33, 3),
+ AMD_PINCTRL_FUNC_GRP(34, 0),
+ AMD_PINCTRL_FUNC_GRP(34, 1),
+ AMD_PINCTRL_FUNC_GRP(34, 2),
+ AMD_PINCTRL_FUNC_GRP(34, 3),
+ AMD_PINCTRL_FUNC_GRP(35, 0),
+ AMD_PINCTRL_FUNC_GRP(35, 1),
+ AMD_PINCTRL_FUNC_GRP(35, 2),
+ AMD_PINCTRL_FUNC_GRP(35, 3),
+ AMD_PINCTRL_FUNC_GRP(36, 0),
+ AMD_PINCTRL_FUNC_GRP(36, 1),
+ AMD_PINCTRL_FUNC_GRP(36, 2),
+ AMD_PINCTRL_FUNC_GRP(36, 3),
+ AMD_PINCTRL_FUNC_GRP(37, 0),
+ AMD_PINCTRL_FUNC_GRP(37, 1),
+ AMD_PINCTRL_FUNC_GRP(37, 2),
+ AMD_PINCTRL_FUNC_GRP(37, 3),
+ AMD_PINCTRL_FUNC_GRP(38, 0),
+ AMD_PINCTRL_FUNC_GRP(38, 1),
+ AMD_PINCTRL_FUNC_GRP(38, 2),
+ AMD_PINCTRL_FUNC_GRP(38, 3),
+ AMD_PINCTRL_FUNC_GRP(39, 0),
+ AMD_PINCTRL_FUNC_GRP(39, 1),
+ AMD_PINCTRL_FUNC_GRP(39, 2),
+ AMD_PINCTRL_FUNC_GRP(39, 3),
+ AMD_PINCTRL_FUNC_GRP(40, 0),
+ AMD_PINCTRL_FUNC_GRP(40, 1),
+ AMD_PINCTRL_FUNC_GRP(40, 2),
+ AMD_PINCTRL_FUNC_GRP(40, 3),
+ AMD_PINCTRL_FUNC_GRP(41, 0),
+ AMD_PINCTRL_FUNC_GRP(41, 1),
+ AMD_PINCTRL_FUNC_GRP(41, 2),
+ AMD_PINCTRL_FUNC_GRP(41, 3),
+ AMD_PINCTRL_FUNC_GRP(42, 0),
+ AMD_PINCTRL_FUNC_GRP(42, 1),
+ AMD_PINCTRL_FUNC_GRP(42, 2),
+ AMD_PINCTRL_FUNC_GRP(42, 3),
+ AMD_PINCTRL_FUNC_GRP(43, 0),
+ AMD_PINCTRL_FUNC_GRP(43, 1),
+ AMD_PINCTRL_FUNC_GRP(43, 2),
+ AMD_PINCTRL_FUNC_GRP(43, 3),
+ AMD_PINCTRL_FUNC_GRP(44, 0),
+ AMD_PINCTRL_FUNC_GRP(44, 1),
+ AMD_PINCTRL_FUNC_GRP(44, 2),
+ AMD_PINCTRL_FUNC_GRP(44, 3),
+ AMD_PINCTRL_FUNC_GRP(45, 0),
+ AMD_PINCTRL_FUNC_GRP(45, 1),
+ AMD_PINCTRL_FUNC_GRP(45, 2),
+ AMD_PINCTRL_FUNC_GRP(45, 3),
+ AMD_PINCTRL_FUNC_GRP(46, 0),
+ AMD_PINCTRL_FUNC_GRP(46, 1),
+ AMD_PINCTRL_FUNC_GRP(46, 2),
+ AMD_PINCTRL_FUNC_GRP(46, 3),
+ AMD_PINCTRL_FUNC_GRP(47, 0),
+ AMD_PINCTRL_FUNC_GRP(47, 1),
+ AMD_PINCTRL_FUNC_GRP(47, 2),
+ AMD_PINCTRL_FUNC_GRP(47, 3),
+ AMD_PINCTRL_FUNC_GRP(48, 0),
+ AMD_PINCTRL_FUNC_GRP(48, 1),
+ AMD_PINCTRL_FUNC_GRP(48, 2),
+ AMD_PINCTRL_FUNC_GRP(48, 3),
+ AMD_PINCTRL_FUNC_GRP(49, 0),
+ AMD_PINCTRL_FUNC_GRP(49, 1),
+ AMD_PINCTRL_FUNC_GRP(49, 2),
+ AMD_PINCTRL_FUNC_GRP(49, 3),
+ AMD_PINCTRL_FUNC_GRP(50, 0),
+ AMD_PINCTRL_FUNC_GRP(50, 1),
+ AMD_PINCTRL_FUNC_GRP(50, 2),
+ AMD_PINCTRL_FUNC_GRP(50, 3),
+ AMD_PINCTRL_FUNC_GRP(51, 0),
+ AMD_PINCTRL_FUNC_GRP(51, 1),
+ AMD_PINCTRL_FUNC_GRP(51, 2),
+ AMD_PINCTRL_FUNC_GRP(51, 3),
+ AMD_PINCTRL_FUNC_GRP(52, 0),
+ AMD_PINCTRL_FUNC_GRP(52, 1),
+ AMD_PINCTRL_FUNC_GRP(52, 2),
+ AMD_PINCTRL_FUNC_GRP(52, 3),
+ AMD_PINCTRL_FUNC_GRP(53, 0),
+ AMD_PINCTRL_FUNC_GRP(53, 1),
+ AMD_PINCTRL_FUNC_GRP(53, 2),
+ AMD_PINCTRL_FUNC_GRP(53, 3),
+ AMD_PINCTRL_FUNC_GRP(54, 0),
+ AMD_PINCTRL_FUNC_GRP(54, 1),
+ AMD_PINCTRL_FUNC_GRP(54, 2),
+ AMD_PINCTRL_FUNC_GRP(54, 3),
+ AMD_PINCTRL_FUNC_GRP(55, 0),
+ AMD_PINCTRL_FUNC_GRP(55, 1),
+ AMD_PINCTRL_FUNC_GRP(55, 2),
+ AMD_PINCTRL_FUNC_GRP(55, 3),
+ AMD_PINCTRL_FUNC_GRP(56, 0),
+ AMD_PINCTRL_FUNC_GRP(56, 1),
+ AMD_PINCTRL_FUNC_GRP(56, 2),
+ AMD_PINCTRL_FUNC_GRP(56, 3),
+ AMD_PINCTRL_FUNC_GRP(57, 0),
+ AMD_PINCTRL_FUNC_GRP(57, 1),
+ AMD_PINCTRL_FUNC_GRP(57, 2),
+ AMD_PINCTRL_FUNC_GRP(57, 3),
+ AMD_PINCTRL_FUNC_GRP(58, 0),
+ AMD_PINCTRL_FUNC_GRP(58, 1),
+ AMD_PINCTRL_FUNC_GRP(58, 2),
+ AMD_PINCTRL_FUNC_GRP(58, 3),
+ AMD_PINCTRL_FUNC_GRP(59, 0),
+ AMD_PINCTRL_FUNC_GRP(59, 1),
+ AMD_PINCTRL_FUNC_GRP(59, 2),
+ AMD_PINCTRL_FUNC_GRP(59, 3),
+ AMD_PINCTRL_FUNC_GRP(60, 0),
+ AMD_PINCTRL_FUNC_GRP(60, 1),
+ AMD_PINCTRL_FUNC_GRP(60, 2),
+ AMD_PINCTRL_FUNC_GRP(60, 3),
+ AMD_PINCTRL_FUNC_GRP(61, 0),
+ AMD_PINCTRL_FUNC_GRP(61, 1),
+ AMD_PINCTRL_FUNC_GRP(61, 2),
+ AMD_PINCTRL_FUNC_GRP(61, 3),
+ AMD_PINCTRL_FUNC_GRP(62, 0),
+ AMD_PINCTRL_FUNC_GRP(62, 1),
+ AMD_PINCTRL_FUNC_GRP(62, 2),
+ AMD_PINCTRL_FUNC_GRP(62, 3),
+ AMD_PINCTRL_FUNC_GRP(64, 0),
+ AMD_PINCTRL_FUNC_GRP(64, 1),
+ AMD_PINCTRL_FUNC_GRP(64, 2),
+ AMD_PINCTRL_FUNC_GRP(64, 3),
+ AMD_PINCTRL_FUNC_GRP(65, 0),
+ AMD_PINCTRL_FUNC_GRP(65, 1),
+ AMD_PINCTRL_FUNC_GRP(65, 2),
+ AMD_PINCTRL_FUNC_GRP(65, 3),
+ AMD_PINCTRL_FUNC_GRP(66, 0),
+ AMD_PINCTRL_FUNC_GRP(66, 1),
+ AMD_PINCTRL_FUNC_GRP(66, 2),
+ AMD_PINCTRL_FUNC_GRP(66, 3),
+ AMD_PINCTRL_FUNC_GRP(67, 0),
+ AMD_PINCTRL_FUNC_GRP(67, 1),
+ AMD_PINCTRL_FUNC_GRP(67, 2),
+ AMD_PINCTRL_FUNC_GRP(67, 3),
+ AMD_PINCTRL_FUNC_GRP(68, 0),
+ AMD_PINCTRL_FUNC_GRP(68, 1),
+ AMD_PINCTRL_FUNC_GRP(68, 2),
+ AMD_PINCTRL_FUNC_GRP(68, 3),
+ AMD_PINCTRL_FUNC_GRP(69, 0),
+ AMD_PINCTRL_FUNC_GRP(69, 1),
+ AMD_PINCTRL_FUNC_GRP(69, 2),
+ AMD_PINCTRL_FUNC_GRP(69, 3),
+ AMD_PINCTRL_FUNC_GRP(70, 0),
+ AMD_PINCTRL_FUNC_GRP(70, 1),
+ AMD_PINCTRL_FUNC_GRP(70, 2),
+ AMD_PINCTRL_FUNC_GRP(70, 3),
+ AMD_PINCTRL_FUNC_GRP(71, 0),
+ AMD_PINCTRL_FUNC_GRP(71, 1),
+ AMD_PINCTRL_FUNC_GRP(71, 2),
+ AMD_PINCTRL_FUNC_GRP(71, 3),
+ AMD_PINCTRL_FUNC_GRP(72, 0),
+ AMD_PINCTRL_FUNC_GRP(72, 1),
+ AMD_PINCTRL_FUNC_GRP(72, 2),
+ AMD_PINCTRL_FUNC_GRP(72, 3),
+ AMD_PINCTRL_FUNC_GRP(73, 0),
+ AMD_PINCTRL_FUNC_GRP(73, 1),
+ AMD_PINCTRL_FUNC_GRP(73, 2),
+ AMD_PINCTRL_FUNC_GRP(73, 3),
+ AMD_PINCTRL_FUNC_GRP(74, 0),
+ AMD_PINCTRL_FUNC_GRP(74, 1),
+ AMD_PINCTRL_FUNC_GRP(74, 2),
+ AMD_PINCTRL_FUNC_GRP(74, 3),
+ AMD_PINCTRL_FUNC_GRP(75, 0),
+ AMD_PINCTRL_FUNC_GRP(75, 1),
+ AMD_PINCTRL_FUNC_GRP(75, 2),
+ AMD_PINCTRL_FUNC_GRP(75, 3),
+ AMD_PINCTRL_FUNC_GRP(76, 0),
+ AMD_PINCTRL_FUNC_GRP(76, 1),
+ AMD_PINCTRL_FUNC_GRP(76, 2),
+ AMD_PINCTRL_FUNC_GRP(76, 3),
+ AMD_PINCTRL_FUNC_GRP(77, 0),
+ AMD_PINCTRL_FUNC_GRP(77, 1),
+ AMD_PINCTRL_FUNC_GRP(77, 2),
+ AMD_PINCTRL_FUNC_GRP(77, 3),
+ AMD_PINCTRL_FUNC_GRP(78, 0),
+ AMD_PINCTRL_FUNC_GRP(78, 1),
+ AMD_PINCTRL_FUNC_GRP(78, 2),
+ AMD_PINCTRL_FUNC_GRP(78, 3),
+ AMD_PINCTRL_FUNC_GRP(79, 0),
+ AMD_PINCTRL_FUNC_GRP(79, 1),
+ AMD_PINCTRL_FUNC_GRP(79, 2),
+ AMD_PINCTRL_FUNC_GRP(79, 3),
+ AMD_PINCTRL_FUNC_GRP(80, 0),
+ AMD_PINCTRL_FUNC_GRP(80, 1),
+ AMD_PINCTRL_FUNC_GRP(80, 2),
+ AMD_PINCTRL_FUNC_GRP(80, 3),
+ AMD_PINCTRL_FUNC_GRP(81, 0),
+ AMD_PINCTRL_FUNC_GRP(81, 1),
+ AMD_PINCTRL_FUNC_GRP(81, 2),
+ AMD_PINCTRL_FUNC_GRP(81, 3),
+ AMD_PINCTRL_FUNC_GRP(82, 0),
+ AMD_PINCTRL_FUNC_GRP(82, 1),
+ AMD_PINCTRL_FUNC_GRP(82, 2),
+ AMD_PINCTRL_FUNC_GRP(82, 3),
+ AMD_PINCTRL_FUNC_GRP(83, 0),
+ AMD_PINCTRL_FUNC_GRP(83, 1),
+ AMD_PINCTRL_FUNC_GRP(83, 2),
+ AMD_PINCTRL_FUNC_GRP(83, 3),
+ AMD_PINCTRL_FUNC_GRP(84, 0),
+ AMD_PINCTRL_FUNC_GRP(84, 1),
+ AMD_PINCTRL_FUNC_GRP(84, 2),
+ AMD_PINCTRL_FUNC_GRP(84, 3),
+ AMD_PINCTRL_FUNC_GRP(85, 0),
+ AMD_PINCTRL_FUNC_GRP(85, 1),
+ AMD_PINCTRL_FUNC_GRP(85, 2),
+ AMD_PINCTRL_FUNC_GRP(85, 3),
+ AMD_PINCTRL_FUNC_GRP(86, 0),
+ AMD_PINCTRL_FUNC_GRP(86, 1),
+ AMD_PINCTRL_FUNC_GRP(86, 2),
+ AMD_PINCTRL_FUNC_GRP(86, 3),
+ AMD_PINCTRL_FUNC_GRP(87, 0),
+ AMD_PINCTRL_FUNC_GRP(87, 1),
+ AMD_PINCTRL_FUNC_GRP(87, 2),
+ AMD_PINCTRL_FUNC_GRP(87, 3),
+ AMD_PINCTRL_FUNC_GRP(88, 0),
+ AMD_PINCTRL_FUNC_GRP(88, 1),
+ AMD_PINCTRL_FUNC_GRP(88, 2),
+ AMD_PINCTRL_FUNC_GRP(88, 3),
+ AMD_PINCTRL_FUNC_GRP(89, 0),
+ AMD_PINCTRL_FUNC_GRP(89, 1),
+ AMD_PINCTRL_FUNC_GRP(89, 2),
+ AMD_PINCTRL_FUNC_GRP(89, 3),
+ AMD_PINCTRL_FUNC_GRP(90, 0),
+ AMD_PINCTRL_FUNC_GRP(90, 1),
+ AMD_PINCTRL_FUNC_GRP(90, 2),
+ AMD_PINCTRL_FUNC_GRP(90, 3),
+ AMD_PINCTRL_FUNC_GRP(91, 0),
+ AMD_PINCTRL_FUNC_GRP(91, 1),
+ AMD_PINCTRL_FUNC_GRP(91, 2),
+ AMD_PINCTRL_FUNC_GRP(91, 3),
+ AMD_PINCTRL_FUNC_GRP(92, 0),
+ AMD_PINCTRL_FUNC_GRP(92, 1),
+ AMD_PINCTRL_FUNC_GRP(92, 2),
+ AMD_PINCTRL_FUNC_GRP(92, 3),
+ AMD_PINCTRL_FUNC_GRP(93, 0),
+ AMD_PINCTRL_FUNC_GRP(93, 1),
+ AMD_PINCTRL_FUNC_GRP(93, 2),
+ AMD_PINCTRL_FUNC_GRP(93, 3),
+ AMD_PINCTRL_FUNC_GRP(94, 0),
+ AMD_PINCTRL_FUNC_GRP(94, 1),
+ AMD_PINCTRL_FUNC_GRP(94, 2),
+ AMD_PINCTRL_FUNC_GRP(94, 3),
+ AMD_PINCTRL_FUNC_GRP(95, 0),
+ AMD_PINCTRL_FUNC_GRP(95, 1),
+ AMD_PINCTRL_FUNC_GRP(95, 2),
+ AMD_PINCTRL_FUNC_GRP(95, 3),
+ AMD_PINCTRL_FUNC_GRP(96, 0),
+ AMD_PINCTRL_FUNC_GRP(96, 1),
+ AMD_PINCTRL_FUNC_GRP(96, 2),
+ AMD_PINCTRL_FUNC_GRP(96, 3),
+ AMD_PINCTRL_FUNC_GRP(97, 0),
+ AMD_PINCTRL_FUNC_GRP(97, 1),
+ AMD_PINCTRL_FUNC_GRP(97, 2),
+ AMD_PINCTRL_FUNC_GRP(97, 3),
+ AMD_PINCTRL_FUNC_GRP(98, 0),
+ AMD_PINCTRL_FUNC_GRP(98, 1),
+ AMD_PINCTRL_FUNC_GRP(98, 2),
+ AMD_PINCTRL_FUNC_GRP(98, 3),
+ AMD_PINCTRL_FUNC_GRP(99, 0),
+ AMD_PINCTRL_FUNC_GRP(99, 1),
+ AMD_PINCTRL_FUNC_GRP(99, 2),
+ AMD_PINCTRL_FUNC_GRP(99, 3),
+ AMD_PINCTRL_FUNC_GRP(100, 0),
+ AMD_PINCTRL_FUNC_GRP(100, 1),
+ AMD_PINCTRL_FUNC_GRP(100, 2),
+ AMD_PINCTRL_FUNC_GRP(100, 3),
+ AMD_PINCTRL_FUNC_GRP(101, 0),
+ AMD_PINCTRL_FUNC_GRP(101, 1),
+ AMD_PINCTRL_FUNC_GRP(101, 2),
+ AMD_PINCTRL_FUNC_GRP(101, 3),
+ AMD_PINCTRL_FUNC_GRP(102, 0),
+ AMD_PINCTRL_FUNC_GRP(102, 1),
+ AMD_PINCTRL_FUNC_GRP(102, 2),
+ AMD_PINCTRL_FUNC_GRP(102, 3),
+ AMD_PINCTRL_FUNC_GRP(103, 0),
+ AMD_PINCTRL_FUNC_GRP(103, 1),
+ AMD_PINCTRL_FUNC_GRP(103, 2),
+ AMD_PINCTRL_FUNC_GRP(103, 3),
+ AMD_PINCTRL_FUNC_GRP(104, 0),
+ AMD_PINCTRL_FUNC_GRP(104, 1),
+ AMD_PINCTRL_FUNC_GRP(104, 2),
+ AMD_PINCTRL_FUNC_GRP(104, 3),
+ AMD_PINCTRL_FUNC_GRP(105, 0),
+ AMD_PINCTRL_FUNC_GRP(105, 1),
+ AMD_PINCTRL_FUNC_GRP(105, 2),
+ AMD_PINCTRL_FUNC_GRP(105, 3),
+ AMD_PINCTRL_FUNC_GRP(106, 0),
+ AMD_PINCTRL_FUNC_GRP(106, 1),
+ AMD_PINCTRL_FUNC_GRP(106, 2),
+ AMD_PINCTRL_FUNC_GRP(106, 3),
+ AMD_PINCTRL_FUNC_GRP(107, 0),
+ AMD_PINCTRL_FUNC_GRP(107, 1),
+ AMD_PINCTRL_FUNC_GRP(107, 2),
+ AMD_PINCTRL_FUNC_GRP(107, 3),
+ AMD_PINCTRL_FUNC_GRP(108, 0),
+ AMD_PINCTRL_FUNC_GRP(108, 1),
+ AMD_PINCTRL_FUNC_GRP(108, 2),
+ AMD_PINCTRL_FUNC_GRP(108, 3),
+ AMD_PINCTRL_FUNC_GRP(109, 0),
+ AMD_PINCTRL_FUNC_GRP(109, 1),
+ AMD_PINCTRL_FUNC_GRP(109, 2),
+ AMD_PINCTRL_FUNC_GRP(109, 3),
+ AMD_PINCTRL_FUNC_GRP(110, 0),
+ AMD_PINCTRL_FUNC_GRP(110, 1),
+ AMD_PINCTRL_FUNC_GRP(110, 2),
+ AMD_PINCTRL_FUNC_GRP(110, 3),
+ AMD_PINCTRL_FUNC_GRP(111, 0),
+ AMD_PINCTRL_FUNC_GRP(111, 1),
+ AMD_PINCTRL_FUNC_GRP(111, 2),
+ AMD_PINCTRL_FUNC_GRP(111, 3),
+ AMD_PINCTRL_FUNC_GRP(112, 0),
+ AMD_PINCTRL_FUNC_GRP(112, 1),
+ AMD_PINCTRL_FUNC_GRP(112, 2),
+ AMD_PINCTRL_FUNC_GRP(112, 3),
+ AMD_PINCTRL_FUNC_GRP(113, 0),
+ AMD_PINCTRL_FUNC_GRP(113, 1),
+ AMD_PINCTRL_FUNC_GRP(113, 2),
+ AMD_PINCTRL_FUNC_GRP(113, 3),
+ AMD_PINCTRL_FUNC_GRP(114, 0),
+ AMD_PINCTRL_FUNC_GRP(114, 1),
+ AMD_PINCTRL_FUNC_GRP(114, 2),
+ AMD_PINCTRL_FUNC_GRP(114, 3),
+ AMD_PINCTRL_FUNC_GRP(115, 0),
+ AMD_PINCTRL_FUNC_GRP(115, 1),
+ AMD_PINCTRL_FUNC_GRP(115, 2),
+ AMD_PINCTRL_FUNC_GRP(115, 3),
+ AMD_PINCTRL_FUNC_GRP(116, 0),
+ AMD_PINCTRL_FUNC_GRP(116, 1),
+ AMD_PINCTRL_FUNC_GRP(116, 2),
+ AMD_PINCTRL_FUNC_GRP(116, 3),
+ AMD_PINCTRL_FUNC_GRP(117, 0),
+ AMD_PINCTRL_FUNC_GRP(117, 1),
+ AMD_PINCTRL_FUNC_GRP(117, 2),
+ AMD_PINCTRL_FUNC_GRP(117, 3),
+ AMD_PINCTRL_FUNC_GRP(118, 0),
+ AMD_PINCTRL_FUNC_GRP(118, 1),
+ AMD_PINCTRL_FUNC_GRP(118, 2),
+ AMD_PINCTRL_FUNC_GRP(118, 3),
+ AMD_PINCTRL_FUNC_GRP(119, 0),
+ AMD_PINCTRL_FUNC_GRP(119, 1),
+ AMD_PINCTRL_FUNC_GRP(119, 2),
+ AMD_PINCTRL_FUNC_GRP(119, 3),
+ AMD_PINCTRL_FUNC_GRP(120, 0),
+ AMD_PINCTRL_FUNC_GRP(120, 1),
+ AMD_PINCTRL_FUNC_GRP(120, 2),
+ AMD_PINCTRL_FUNC_GRP(120, 3),
+ AMD_PINCTRL_FUNC_GRP(121, 0),
+ AMD_PINCTRL_FUNC_GRP(121, 1),
+ AMD_PINCTRL_FUNC_GRP(121, 2),
+ AMD_PINCTRL_FUNC_GRP(121, 3),
+ AMD_PINCTRL_FUNC_GRP(122, 0),
+ AMD_PINCTRL_FUNC_GRP(122, 1),
+ AMD_PINCTRL_FUNC_GRP(122, 2),
+ AMD_PINCTRL_FUNC_GRP(122, 3),
+ AMD_PINCTRL_FUNC_GRP(123, 0),
+ AMD_PINCTRL_FUNC_GRP(123, 1),
+ AMD_PINCTRL_FUNC_GRP(123, 2),
+ AMD_PINCTRL_FUNC_GRP(123, 3),
+ AMD_PINCTRL_FUNC_GRP(124, 0),
+ AMD_PINCTRL_FUNC_GRP(124, 1),
+ AMD_PINCTRL_FUNC_GRP(124, 2),
+ AMD_PINCTRL_FUNC_GRP(124, 3),
+ AMD_PINCTRL_FUNC_GRP(125, 0),
+ AMD_PINCTRL_FUNC_GRP(125, 1),
+ AMD_PINCTRL_FUNC_GRP(125, 2),
+ AMD_PINCTRL_FUNC_GRP(125, 3),
+ AMD_PINCTRL_FUNC_GRP(126, 0),
+ AMD_PINCTRL_FUNC_GRP(126, 1),
+ AMD_PINCTRL_FUNC_GRP(126, 2),
+ AMD_PINCTRL_FUNC_GRP(126, 3),
+ AMD_PINCTRL_FUNC_GRP(127, 0),
+ AMD_PINCTRL_FUNC_GRP(127, 1),
+ AMD_PINCTRL_FUNC_GRP(127, 2),
+ AMD_PINCTRL_FUNC_GRP(127, 3),
+ AMD_PINCTRL_FUNC_GRP(128, 0),
+ AMD_PINCTRL_FUNC_GRP(128, 1),
+ AMD_PINCTRL_FUNC_GRP(128, 2),
+ AMD_PINCTRL_FUNC_GRP(128, 3),
+ AMD_PINCTRL_FUNC_GRP(129, 0),
+ AMD_PINCTRL_FUNC_GRP(129, 1),
+ AMD_PINCTRL_FUNC_GRP(129, 2),
+ AMD_PINCTRL_FUNC_GRP(129, 3),
+ AMD_PINCTRL_FUNC_GRP(130, 0),
+ AMD_PINCTRL_FUNC_GRP(130, 1),
+ AMD_PINCTRL_FUNC_GRP(130, 2),
+ AMD_PINCTRL_FUNC_GRP(130, 3),
+ AMD_PINCTRL_FUNC_GRP(131, 0),
+ AMD_PINCTRL_FUNC_GRP(131, 1),
+ AMD_PINCTRL_FUNC_GRP(131, 2),
+ AMD_PINCTRL_FUNC_GRP(131, 3),
+ AMD_PINCTRL_FUNC_GRP(132, 0),
+ AMD_PINCTRL_FUNC_GRP(132, 1),
+ AMD_PINCTRL_FUNC_GRP(132, 2),
+ AMD_PINCTRL_FUNC_GRP(132, 3),
+ AMD_PINCTRL_FUNC_GRP(133, 0),
+ AMD_PINCTRL_FUNC_GRP(133, 1),
+ AMD_PINCTRL_FUNC_GRP(133, 2),
+ AMD_PINCTRL_FUNC_GRP(133, 3),
+ AMD_PINCTRL_FUNC_GRP(134, 0),
+ AMD_PINCTRL_FUNC_GRP(134, 1),
+ AMD_PINCTRL_FUNC_GRP(134, 2),
+ AMD_PINCTRL_FUNC_GRP(134, 3),
+ AMD_PINCTRL_FUNC_GRP(135, 0),
+ AMD_PINCTRL_FUNC_GRP(135, 1),
+ AMD_PINCTRL_FUNC_GRP(135, 2),
+ AMD_PINCTRL_FUNC_GRP(135, 3),
+ AMD_PINCTRL_FUNC_GRP(136, 0),
+ AMD_PINCTRL_FUNC_GRP(136, 1),
+ AMD_PINCTRL_FUNC_GRP(136, 2),
+ AMD_PINCTRL_FUNC_GRP(136, 3),
+ AMD_PINCTRL_FUNC_GRP(137, 0),
+ AMD_PINCTRL_FUNC_GRP(137, 1),
+ AMD_PINCTRL_FUNC_GRP(137, 2),
+ AMD_PINCTRL_FUNC_GRP(137, 3),
+ AMD_PINCTRL_FUNC_GRP(138, 0),
+ AMD_PINCTRL_FUNC_GRP(138, 1),
+ AMD_PINCTRL_FUNC_GRP(138, 2),
+ AMD_PINCTRL_FUNC_GRP(138, 3),
+ AMD_PINCTRL_FUNC_GRP(139, 0),
+ AMD_PINCTRL_FUNC_GRP(139, 1),
+ AMD_PINCTRL_FUNC_GRP(139, 2),
+ AMD_PINCTRL_FUNC_GRP(139, 3),
+ AMD_PINCTRL_FUNC_GRP(140, 0),
+ AMD_PINCTRL_FUNC_GRP(140, 1),
+ AMD_PINCTRL_FUNC_GRP(140, 2),
+ AMD_PINCTRL_FUNC_GRP(140, 3),
+ AMD_PINCTRL_FUNC_GRP(141, 0),
+ AMD_PINCTRL_FUNC_GRP(141, 1),
+ AMD_PINCTRL_FUNC_GRP(141, 2),
+ AMD_PINCTRL_FUNC_GRP(141, 3),
+ AMD_PINCTRL_FUNC_GRP(142, 0),
+ AMD_PINCTRL_FUNC_GRP(142, 1),
+ AMD_PINCTRL_FUNC_GRP(142, 2),
+ AMD_PINCTRL_FUNC_GRP(142, 3),
+ AMD_PINCTRL_FUNC_GRP(143, 0),
+ AMD_PINCTRL_FUNC_GRP(143, 1),
+ AMD_PINCTRL_FUNC_GRP(143, 2),
+ AMD_PINCTRL_FUNC_GRP(143, 3),
+ AMD_PINCTRL_FUNC_GRP(144, 0),
+ AMD_PINCTRL_FUNC_GRP(144, 1),
+ AMD_PINCTRL_FUNC_GRP(144, 2),
+ AMD_PINCTRL_FUNC_GRP(144, 3),
+
+ PINCTRL_PINGROUP("i2c0", AMD_PINS(145, 146), 2),
+ PINCTRL_PINGROUP("i2c1", AMD_PINS(147, 148), 2),
+ PINCTRL_PINGROUP("i2c2", AMD_PINS(113, 114), 2),
+ PINCTRL_PINGROUP("i2c3", AMD_PINS(19, 20), 2),
+ PINCTRL_PINGROUP("uart0", AMD_PINS(135, 136, 137, 138, 139), 5),
+ PINCTRL_PINGROUP("uart1", AMD_PINS(140, 141, 142, 143, 144), 5),
+};
-static const unsigned uart0_pins[] = {135, 136, 137, 138, 139};
-static const unsigned uart1_pins[] = {140, 141, 142, 143, 144};
+#define AMD_PMUX_FUNC(_number) { \
+ .name = "iomux_gpio_"#_number, \
+ .groups = { \
+ "IMX_F0_GPIO"#_number, "IMX_F1_GPIO"#_number, \
+ "IMX_F2_GPIO"#_number, "IMX_F3_GPIO"#_number, \
+ }, \
+ .index = _number, \
+ .ngroups = NSELECTS, \
+}
-static const struct amd_pingroup kerncz_groups[] = {
- {
- .name = "i2c0",
- .pins = i2c0_pins,
- .npins = 2,
- },
- {
- .name = "i2c1",
- .pins = i2c1_pins,
- .npins = 2,
- },
- {
- .name = "i2c2",
- .pins = i2c2_pins,
- .npins = 2,
- },
- {
- .name = "i2c3",
- .pins = i2c3_pins,
- .npins = 2,
- },
- {
- .name = "uart0",
- .pins = uart0_pins,
- .npins = 5,
- },
- {
- .name = "uart1",
- .pins = uart1_pins,
- .npins = 5,
- },
+static const struct amd_function pmx_functions[] = {
+ AMD_PMUX_FUNC(0),
+ AMD_PMUX_FUNC(1),
+ AMD_PMUX_FUNC(2),
+ AMD_PMUX_FUNC(3),
+ AMD_PMUX_FUNC(4),
+ AMD_PMUX_FUNC(5),
+ AMD_PMUX_FUNC(6),
+ AMD_PMUX_FUNC(7),
+ AMD_PMUX_FUNC(8),
+ AMD_PMUX_FUNC(9),
+ AMD_PMUX_FUNC(10),
+ AMD_PMUX_FUNC(11),
+ AMD_PMUX_FUNC(12),
+ AMD_PMUX_FUNC(13),
+ AMD_PMUX_FUNC(14),
+ AMD_PMUX_FUNC(15),
+ AMD_PMUX_FUNC(16),
+ AMD_PMUX_FUNC(17),
+ AMD_PMUX_FUNC(18),
+ AMD_PMUX_FUNC(19),
+ AMD_PMUX_FUNC(20),
+ AMD_PMUX_FUNC(21),
+ AMD_PMUX_FUNC(22),
+ AMD_PMUX_FUNC(23),
+ AMD_PMUX_FUNC(24),
+ AMD_PMUX_FUNC(25),
+ AMD_PMUX_FUNC(26),
+ AMD_PMUX_FUNC(27),
+ AMD_PMUX_FUNC(28),
+ AMD_PMUX_FUNC(29),
+ AMD_PMUX_FUNC(30),
+ AMD_PMUX_FUNC(31),
+ AMD_PMUX_FUNC(32),
+ AMD_PMUX_FUNC(33),
+ AMD_PMUX_FUNC(34),
+ AMD_PMUX_FUNC(35),
+ AMD_PMUX_FUNC(36),
+ AMD_PMUX_FUNC(37),
+ AMD_PMUX_FUNC(38),
+ AMD_PMUX_FUNC(39),
+ AMD_PMUX_FUNC(40),
+ AMD_PMUX_FUNC(41),
+ AMD_PMUX_FUNC(42),
+ AMD_PMUX_FUNC(43),
+ AMD_PMUX_FUNC(44),
+ AMD_PMUX_FUNC(45),
+ AMD_PMUX_FUNC(46),
+ AMD_PMUX_FUNC(47),
+ AMD_PMUX_FUNC(48),
+ AMD_PMUX_FUNC(49),
+ AMD_PMUX_FUNC(50),
+ AMD_PMUX_FUNC(51),
+ AMD_PMUX_FUNC(52),
+ AMD_PMUX_FUNC(53),
+ AMD_PMUX_FUNC(54),
+ AMD_PMUX_FUNC(55),
+ AMD_PMUX_FUNC(56),
+ AMD_PMUX_FUNC(57),
+ AMD_PMUX_FUNC(58),
+ AMD_PMUX_FUNC(59),
+ AMD_PMUX_FUNC(60),
+ AMD_PMUX_FUNC(61),
+ AMD_PMUX_FUNC(62),
+ AMD_PMUX_FUNC(64),
+ AMD_PMUX_FUNC(65),
+ AMD_PMUX_FUNC(66),
+ AMD_PMUX_FUNC(67),
+ AMD_PMUX_FUNC(68),
+ AMD_PMUX_FUNC(69),
+ AMD_PMUX_FUNC(70),
+ AMD_PMUX_FUNC(71),
+ AMD_PMUX_FUNC(72),
+ AMD_PMUX_FUNC(73),
+ AMD_PMUX_FUNC(74),
+ AMD_PMUX_FUNC(75),
+ AMD_PMUX_FUNC(76),
+ AMD_PMUX_FUNC(77),
+ AMD_PMUX_FUNC(78),
+ AMD_PMUX_FUNC(79),
+ AMD_PMUX_FUNC(80),
+ AMD_PMUX_FUNC(81),
+ AMD_PMUX_FUNC(82),
+ AMD_PMUX_FUNC(83),
+ AMD_PMUX_FUNC(84),
+ AMD_PMUX_FUNC(85),
+ AMD_PMUX_FUNC(86),
+ AMD_PMUX_FUNC(87),
+ AMD_PMUX_FUNC(88),
+ AMD_PMUX_FUNC(89),
+ AMD_PMUX_FUNC(90),
+ AMD_PMUX_FUNC(91),
+ AMD_PMUX_FUNC(92),
+ AMD_PMUX_FUNC(93),
+ AMD_PMUX_FUNC(94),
+ AMD_PMUX_FUNC(95),
+ AMD_PMUX_FUNC(96),
+ AMD_PMUX_FUNC(97),
+ AMD_PMUX_FUNC(98),
+ AMD_PMUX_FUNC(99),
+ AMD_PMUX_FUNC(100),
+ AMD_PMUX_FUNC(101),
+ AMD_PMUX_FUNC(102),
+ AMD_PMUX_FUNC(103),
+ AMD_PMUX_FUNC(104),
+ AMD_PMUX_FUNC(105),
+ AMD_PMUX_FUNC(106),
+ AMD_PMUX_FUNC(107),
+ AMD_PMUX_FUNC(108),
+ AMD_PMUX_FUNC(109),
+ AMD_PMUX_FUNC(110),
+ AMD_PMUX_FUNC(111),
+ AMD_PMUX_FUNC(112),
+ AMD_PMUX_FUNC(113),
+ AMD_PMUX_FUNC(114),
+ AMD_PMUX_FUNC(115),
+ AMD_PMUX_FUNC(116),
+ AMD_PMUX_FUNC(117),
+ AMD_PMUX_FUNC(118),
+ AMD_PMUX_FUNC(119),
+ AMD_PMUX_FUNC(120),
+ AMD_PMUX_FUNC(121),
+ AMD_PMUX_FUNC(122),
+ AMD_PMUX_FUNC(123),
+ AMD_PMUX_FUNC(124),
+ AMD_PMUX_FUNC(125),
+ AMD_PMUX_FUNC(126),
+ AMD_PMUX_FUNC(127),
+ AMD_PMUX_FUNC(128),
+ AMD_PMUX_FUNC(129),
+ AMD_PMUX_FUNC(130),
+ AMD_PMUX_FUNC(131),
+ AMD_PMUX_FUNC(132),
+ AMD_PMUX_FUNC(133),
+ AMD_PMUX_FUNC(134),
+ AMD_PMUX_FUNC(135),
+ AMD_PMUX_FUNC(136),
+ AMD_PMUX_FUNC(137),
+ AMD_PMUX_FUNC(138),
+ AMD_PMUX_FUNC(139),
+ AMD_PMUX_FUNC(140),
+ AMD_PMUX_FUNC(141),
+ AMD_PMUX_FUNC(142),
+ AMD_PMUX_FUNC(143),
+ AMD_PMUX_FUNC(144),
};
#endif
BIT(pin->line));
}
-#ifdef CONFIG_PM_SLEEP
-
static int atmel_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
{
struct atmel_pioctrl *atmel_pioctrl = irq_data_get_irq_chip_data(d);
return 0;
}
-#else
-#define atmel_gpio_irq_set_wake NULL
-#endif /* CONFIG_PM_SLEEP */
static struct irq_chip atmel_gpio_irq_chip = {
.name = "GPIO",
.irq_mask = atmel_gpio_irq_mask,
.irq_unmask = atmel_gpio_irq_unmask,
.irq_set_type = atmel_gpio_irq_set_type,
- .irq_set_wake = atmel_gpio_irq_set_wake,
+ .irq_set_wake = pm_sleep_ptr(atmel_gpio_irq_set_wake),
};
static int atmel_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
/* the interrupt is already cleared before by reading ISR */
}
-#ifdef CONFIG_PM
-
static u32 wakeups[MAX_GPIO_BANKS];
static u32 backups[MAX_GPIO_BANKS];
}
}
-#else
-#define gpio_irq_set_wake NULL
-#endif /* CONFIG_PM */
-
static void gpio_irq_handler(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
gpio_irqchip->irq_disable = gpio_irq_mask;
gpio_irqchip->irq_mask = gpio_irq_mask;
gpio_irqchip->irq_unmask = gpio_irq_unmask;
- gpio_irqchip->irq_set_wake = gpio_irq_set_wake;
+ gpio_irqchip->irq_set_wake = pm_ptr(gpio_irq_set_wake);
gpio_irqchip->irq_set_type = at91_gpio->ops->irq_type;
/* Disable irqs of this PIO controller */
writel_relaxed(~0, at91_gpio->regbase + PIO_IDR);
/*
- * Let the generic code handle this edge IRQ, the the chained
+ * Let the generic code handle this edge IRQ, the chained
* handler will perform the actual work of handling the parent
* interrupt.
*/
PINCTRL_PIN(2, "GPIO2"),
};
-static const struct pinctrl_pin_desc axp813_pins[] = {
+static const struct pinctrl_pin_desc axp22x_pins[] = {
PINCTRL_PIN(0, "GPIO0"),
PINCTRL_PIN(1, "GPIO1"),
};
.adc_mux = AXP20X_MUX_ADC,
};
+static const struct axp20x_pctrl_desc axp22x_data = {
+ .pins = axp22x_pins,
+ .npins = ARRAY_SIZE(axp22x_pins),
+ .ldo_mask = BIT(0) | BIT(1),
+ .gpio_status_offset = 0,
+};
+
static const struct axp20x_pctrl_desc axp813_data = {
- .pins = axp813_pins,
- .npins = ARRAY_SIZE(axp813_pins),
+ .pins = axp22x_pins,
+ .npins = ARRAY_SIZE(axp22x_pins),
.ldo_mask = BIT(0) | BIT(1),
.adc_mask = BIT(0),
.gpio_status_offset = 0,
static const struct of_device_id axp20x_pctl_match[] = {
{ .compatible = "x-powers,axp209-gpio", .data = &axp20x_data, },
+ { .compatible = "x-powers,axp221-gpio", .data = &axp22x_data, },
{ .compatible = "x-powers,axp813-gpio", .data = &axp813_data, },
{ }
};
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/seq_file.h>
#include <linux/slab.h>
#include "core.h"
struct ingenic_gpio_chip {
struct ingenic_pinctrl *jzpc;
struct gpio_chip gc;
- struct irq_chip irq_chip;
unsigned int irq, reg_base;
};
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
- int irq = irqd->hwirq;
+ irq_hw_number_t irq = irqd_to_hwirq(irqd);
if (is_soc_or_above(jzgc->jzpc, ID_JZ4740))
ingenic_gpio_set_bit(jzgc, GPIO_MSK, irq, true);
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
- int irq = irqd->hwirq;
+ irq_hw_number_t irq = irqd_to_hwirq(irqd);
if (is_soc_or_above(jzgc->jzpc, ID_JZ4740))
ingenic_gpio_set_bit(jzgc, GPIO_MSK, irq, false);
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
- int irq = irqd->hwirq;
+ irq_hw_number_t irq = irqd_to_hwirq(irqd);
+
+ gpiochip_enable_irq(gc, irq);
if (is_soc_or_above(jzgc->jzpc, ID_JZ4770))
ingenic_gpio_set_bit(jzgc, JZ4770_GPIO_INT, irq, true);
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
- int irq = irqd->hwirq;
+ irq_hw_number_t irq = irqd_to_hwirq(irqd);
ingenic_gpio_irq_mask(irqd);
ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, false);
else
ingenic_gpio_set_bit(jzgc, JZ4730_GPIO_GPIER, irq, false);
+
+ gpiochip_disable_irq(gc, irq);
}
static void ingenic_gpio_irq_ack(struct irq_data *irqd)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
- int irq = irqd->hwirq;
+ irq_hw_number_t irq = irqd_to_hwirq(irqd);
bool high;
if ((irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) &&
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+ irq_hw_number_t irq = irqd_to_hwirq(irqd);
switch (type) {
case IRQ_TYPE_EDGE_BOTH:
* best we can do is to set up a single-edge interrupt and then
* switch to the opposing edge when ACKing the interrupt.
*/
- bool high = ingenic_gpio_get_value(jzgc, irqd->hwirq);
+ bool high = ingenic_gpio_get_value(jzgc, irq);
type = high ? IRQ_TYPE_LEVEL_LOW : IRQ_TYPE_LEVEL_HIGH;
}
- irq_set_type(jzgc, irqd->hwirq, type);
+ irq_set_type(jzgc, irq, type);
return 0;
}
static int ingenic_gpio_irq_request(struct irq_data *data)
{
struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
+ irq_hw_number_t irq = irqd_to_hwirq(data);
int ret;
- ret = ingenic_gpio_direction_input(gpio_chip, data->hwirq);
+ ret = ingenic_gpio_direction_input(gpio_chip, irq);
if (ret)
return ret;
- return gpiochip_reqres_irq(gpio_chip, data->hwirq);
+ return gpiochip_reqres_irq(gpio_chip, irq);
}
static void ingenic_gpio_irq_release(struct irq_data *data)
+{
+ struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
+ irq_hw_number_t irq = irqd_to_hwirq(data);
+
+ return gpiochip_relres_irq(gpio_chip, irq);
+}
+
+static void ingenic_gpio_irq_print_chip(struct irq_data *data, struct seq_file *p)
{
struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
- return gpiochip_relres_irq(gpio_chip, data->hwirq);
+ seq_printf(p, "%s", gpio_chip->label);
}
+static const struct irq_chip ingenic_gpio_irqchip = {
+ .irq_enable = ingenic_gpio_irq_enable,
+ .irq_disable = ingenic_gpio_irq_disable,
+ .irq_unmask = ingenic_gpio_irq_unmask,
+ .irq_mask = ingenic_gpio_irq_mask,
+ .irq_ack = ingenic_gpio_irq_ack,
+ .irq_set_type = ingenic_gpio_irq_set_type,
+ .irq_set_wake = ingenic_gpio_irq_set_wake,
+ .irq_request_resources = ingenic_gpio_irq_request,
+ .irq_release_resources = ingenic_gpio_irq_release,
+ .irq_print_chip = ingenic_gpio_irq_print_chip,
+ .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE,
+};
+
static int ingenic_pinmux_set_pin_fn(struct ingenic_pinctrl *jzpc,
int pin, int func)
{
if (!jzgc->irq)
return -EINVAL;
- jzgc->irq_chip.name = jzgc->gc.label;
- jzgc->irq_chip.irq_enable = ingenic_gpio_irq_enable;
- jzgc->irq_chip.irq_disable = ingenic_gpio_irq_disable;
- jzgc->irq_chip.irq_unmask = ingenic_gpio_irq_unmask;
- jzgc->irq_chip.irq_mask = ingenic_gpio_irq_mask;
- jzgc->irq_chip.irq_ack = ingenic_gpio_irq_ack;
- jzgc->irq_chip.irq_set_type = ingenic_gpio_irq_set_type;
- jzgc->irq_chip.irq_set_wake = ingenic_gpio_irq_set_wake;
- jzgc->irq_chip.irq_request_resources = ingenic_gpio_irq_request;
- jzgc->irq_chip.irq_release_resources = ingenic_gpio_irq_release;
- jzgc->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND;
-
girq = &jzgc->gc.irq;
- girq->chip = &jzgc->irq_chip;
+ gpio_irq_chip_set_chip(girq, &ingenic_gpio_irqchip);
girq->parent_handler = ingenic_gpio_irq_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
{ .compatible = "microchip,lan966x-pinctrl", .data = &lan966x_desc },
{},
};
+MODULE_DEVICE_TABLE(of, ocelot_pinctrl_of_match);
static struct regmap *ocelot_pinctrl_create_pincfg(struct platform_device *pdev,
const struct ocelot_pinctrl *info)
},
.probe = ocelot_pinctrl_probe,
};
-builtin_platform_driver(ocelot_pinctrl_driver);
+module_platform_driver(ocelot_pinctrl_driver);
+MODULE_LICENSE("Dual MIT/GPL");
void __iomem *base;
void __iomem *padctl;
struct pinctrl_dev *pctl;
+ struct mutex mutex; /* serialize adding groups and functions */
};
static inline unsigned int starfive_pin_to_gpio(const struct starfive_pinctrl *sfp,
nmaps = 0;
ngroups = 0;
+ mutex_lock(&sfp->mutex);
for_each_child_of_node(np, child) {
int npins;
int i;
*maps = map;
*num_maps = nmaps;
+ 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);
return ret;
}
platform_set_drvdata(pdev, sfp);
sfp->gc.parent = dev;
raw_spin_lock_init(&sfp->lock);
+ mutex_init(&sfp->mutex);
ret = devm_pinctrl_register_and_init(dev, &starfive_desc, sfp, &sfp->pctl);
if (ret)
* @num_groups: Number of function groups.
*
* Get function's group count and group names.
+ *
+ * Return: 0
*/
static int zynqmp_pmux_get_function_groups(struct pinctrl_dev *pctldev,
unsigned int selector,
break;
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ param = PM_PINCTRL_CONFIG_TRI_STATE;
+ arg = PM_PINCTRL_TRI_STATE_ENABLE;
+ ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+ break;
case PIN_CONFIG_MODE_LOW_POWER:
/*
* These cases are mentioned in dts but configurable
*/
ret = 0;
break;
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ param = PM_PINCTRL_CONFIG_TRI_STATE;
+ arg = PM_PINCTRL_TRI_STATE_DISABLE;
+ ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+ break;
default:
dev_warn(pctldev->dev,
"unsupported configuration parameter '%u'\n",
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm TLMM block found in the Qualcomm 8974 platform.
+config PINCTRL_MSM8909
+ tristate "Qualcomm 8909 pin controller driver"
+ depends on OF
+ depends on PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm TLMM block found on the Qualcomm MSM8909 platform.
+
config PINCTRL_MSM8916
tristate "Qualcomm 8916 pin controller driver"
depends on OF
Qualcomm Technologies Inc TLMM block found on the Qualcomm
Technologies Inc SM6350 platform.
+config PINCTRL_SM6375
+ tristate "Qualcomm Technologies Inc SM6375 pin controller driver"
+ depends on GPIOLIB && OF
+ depends on PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc TLMM block found on the Qualcomm
+ Technologies Inc SM6375 platform.
+
config PINCTRL_SDX65
tristate "Qualcomm Technologies Inc SDX65 pin controller driver"
depends on GPIOLIB && OF
config PINCTRL_SM8450
tristate "Qualcomm Technologies Inc SM8450 pin controller driver"
depends on GPIOLIB && OF
- select PINCTRL_MSM
+ depends on PINCTRL_MSM
help
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm Technologies Inc TLMM block found on the Qualcomm
obj-$(CONFIG_PINCTRL_MSM8660) += pinctrl-msm8660.o
obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o
obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o
+obj-$(CONFIG_PINCTRL_MSM8909) += pinctrl-msm8909.o
obj-$(CONFIG_PINCTRL_MSM8916) += pinctrl-msm8916.o
obj-$(CONFIG_PINCTRL_MSM8953) += pinctrl-msm8953.o
obj-$(CONFIG_PINCTRL_MSM8976) += pinctrl-msm8976.o
obj-$(CONFIG_PINCTRL_SM6115) += pinctrl-sm6115.o
obj-$(CONFIG_PINCTRL_SM6125) += pinctrl-sm6125.o
obj-$(CONFIG_PINCTRL_SM6350) += pinctrl-sm6350.o
+obj-$(CONFIG_PINCTRL_SM6375) += pinctrl-sm6375.o
obj-$(CONFIG_PINCTRL_SDX65) += pinctrl-sdx65.o
obj-$(CONFIG_PINCTRL_SM8150) += pinctrl-sm8150.o
obj-$(CONFIG_PINCTRL_SM8250) += pinctrl-sm8250.o
return dev_err_probe(dev, PTR_ERR(pctrl->slew_base),
"Slew resource not provided\n");
- if (data->is_clk_optional)
+ if (of_property_read_bool(dev->of_node, "qcom,adsp-bypass-mode"))
ret = devm_clk_bulk_get_optional(dev, MAX_LPI_NUM_CLKS, pctrl->clks);
else
ret = devm_clk_bulk_get(dev, MAX_LPI_NUM_CLKS, pctrl->clks);
int ngroups;
const struct lpi_function *functions;
int nfunctions;
- bool is_clk_optional;
};
int lpi_pinctrl_probe(struct platform_device *pdev);
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2022, Kernkonzept GmbH.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname) \
+ [msm_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9, \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = REG_SIZE * id, \
+ .io_reg = 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = 0x8 + REG_SIZE * id, \
+ .intr_status_reg = 0xc + REG_SIZE * id, \
+ .intr_target_reg = 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 4, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+static const struct pinctrl_pin_desc msm8909_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "SDC1_CLK"),
+ PINCTRL_PIN(114, "SDC1_CMD"),
+ PINCTRL_PIN(115, "SDC1_DATA"),
+ PINCTRL_PIN(116, "SDC2_CLK"),
+ PINCTRL_PIN(117, "SDC2_CMD"),
+ PINCTRL_PIN(118, "SDC2_DATA"),
+ PINCTRL_PIN(119, "QDSD_CLK"),
+ PINCTRL_PIN(120, "QDSD_CMD"),
+ PINCTRL_PIN(121, "QDSD_DATA0"),
+ PINCTRL_PIN(122, "QDSD_DATA1"),
+ PINCTRL_PIN(123, "QDSD_DATA2"),
+ PINCTRL_PIN(124, "QDSD_DATA3"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+
+static const unsigned int sdc1_clk_pins[] = { 113 };
+static const unsigned int sdc1_cmd_pins[] = { 114 };
+static const unsigned int sdc1_data_pins[] = { 115 };
+static const unsigned int sdc2_clk_pins[] = { 116 };
+static const unsigned int sdc2_cmd_pins[] = { 117 };
+static const unsigned int sdc2_data_pins[] = { 118 };
+static const unsigned int qdsd_clk_pins[] = { 119 };
+static const unsigned int qdsd_cmd_pins[] = { 120 };
+static const unsigned int qdsd_data0_pins[] = { 121 };
+static const unsigned int qdsd_data1_pins[] = { 122 };
+static const unsigned int qdsd_data2_pins[] = { 123 };
+static const unsigned int qdsd_data3_pins[] = { 124 };
+
+enum msm8909_functions {
+ msm_mux_gpio,
+ msm_mux_adsp_ext,
+ msm_mux_atest_bbrx0,
+ msm_mux_atest_bbrx1,
+ msm_mux_atest_char,
+ msm_mux_atest_char0,
+ msm_mux_atest_char1,
+ msm_mux_atest_char2,
+ msm_mux_atest_char3,
+ msm_mux_atest_combodac,
+ msm_mux_atest_gpsadc0,
+ msm_mux_atest_gpsadc1,
+ msm_mux_atest_wlan0,
+ msm_mux_atest_wlan1,
+ msm_mux_bimc_dte0,
+ msm_mux_bimc_dte1,
+ msm_mux_blsp_i2c1,
+ msm_mux_blsp_i2c2,
+ msm_mux_blsp_i2c3,
+ msm_mux_blsp_i2c4,
+ msm_mux_blsp_i2c5,
+ msm_mux_blsp_i2c6,
+ msm_mux_blsp_spi1,
+ msm_mux_blsp_spi1_cs1,
+ msm_mux_blsp_spi1_cs2,
+ msm_mux_blsp_spi1_cs3,
+ msm_mux_blsp_spi2,
+ msm_mux_blsp_spi2_cs1,
+ msm_mux_blsp_spi2_cs2,
+ msm_mux_blsp_spi2_cs3,
+ msm_mux_blsp_spi3,
+ msm_mux_blsp_spi3_cs1,
+ msm_mux_blsp_spi3_cs2,
+ msm_mux_blsp_spi3_cs3,
+ msm_mux_blsp_spi4,
+ msm_mux_blsp_spi5,
+ msm_mux_blsp_spi6,
+ msm_mux_blsp_uart1,
+ msm_mux_blsp_uart2,
+ msm_mux_blsp_uim1,
+ msm_mux_blsp_uim2,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async,
+ msm_mux_cci_timer0,
+ msm_mux_cci_timer1,
+ msm_mux_cci_timer2,
+ msm_mux_cdc_pdm0,
+ msm_mux_dbg_out,
+ msm_mux_dmic0_clk,
+ msm_mux_dmic0_data,
+ msm_mux_ebi0_wrcdc,
+ msm_mux_ebi2_a,
+ msm_mux_ebi2_lcd,
+ msm_mux_ext_lpass,
+ msm_mux_gcc_gp1_clk_a,
+ msm_mux_gcc_gp1_clk_b,
+ msm_mux_gcc_gp2_clk_a,
+ msm_mux_gcc_gp2_clk_b,
+ msm_mux_gcc_gp3_clk_a,
+ msm_mux_gcc_gp3_clk_b,
+ msm_mux_gcc_plltest,
+ msm_mux_gsm0_tx,
+ msm_mux_ldo_en,
+ msm_mux_ldo_update,
+ msm_mux_m_voc,
+ msm_mux_mdp_vsync,
+ msm_mux_modem_tsync,
+ msm_mux_nav_pps,
+ msm_mux_nav_tsync,
+ msm_mux_pa_indicator,
+ msm_mux_pbs0,
+ msm_mux_pbs1,
+ msm_mux_pbs2,
+ msm_mux_pri_mi2s_data0_a,
+ msm_mux_pri_mi2s_data0_b,
+ msm_mux_pri_mi2s_data1_a,
+ msm_mux_pri_mi2s_data1_b,
+ msm_mux_pri_mi2s_mclk_a,
+ msm_mux_pri_mi2s_mclk_b,
+ msm_mux_pri_mi2s_sck_a,
+ msm_mux_pri_mi2s_sck_b,
+ msm_mux_pri_mi2s_ws_a,
+ msm_mux_pri_mi2s_ws_b,
+ msm_mux_prng_rosc,
+ msm_mux_pwr_crypto_enabled_a,
+ msm_mux_pwr_crypto_enabled_b,
+ msm_mux_pwr_modem_enabled_a,
+ msm_mux_pwr_modem_enabled_b,
+ msm_mux_pwr_nav_enabled_a,
+ msm_mux_pwr_nav_enabled_b,
+ msm_mux_qdss_cti_trig_in_a0,
+ msm_mux_qdss_cti_trig_in_a1,
+ msm_mux_qdss_cti_trig_in_b0,
+ msm_mux_qdss_cti_trig_in_b1,
+ msm_mux_qdss_cti_trig_out_a0,
+ msm_mux_qdss_cti_trig_out_a1,
+ msm_mux_qdss_cti_trig_out_b0,
+ msm_mux_qdss_cti_trig_out_b1,
+ msm_mux_qdss_traceclk_a,
+ msm_mux_qdss_tracectl_a,
+ msm_mux_qdss_tracedata_a,
+ msm_mux_qdss_tracedata_b,
+ msm_mux_sd_write,
+ msm_mux_sec_mi2s,
+ msm_mux_smb_int,
+ msm_mux_ssbi0,
+ msm_mux_ssbi1,
+ msm_mux_uim1_clk,
+ msm_mux_uim1_data,
+ msm_mux_uim1_present,
+ msm_mux_uim1_reset,
+ msm_mux_uim2_clk,
+ msm_mux_uim2_data,
+ msm_mux_uim2_present,
+ msm_mux_uim2_reset,
+ msm_mux_uim3_clk,
+ msm_mux_uim3_data,
+ msm_mux_uim3_present,
+ msm_mux_uim3_reset,
+ msm_mux_uim_batt,
+ msm_mux_wcss_bt,
+ msm_mux_wcss_fm,
+ msm_mux_wcss_wlan,
+ msm_mux__,
+};
+
+static const char * const adsp_ext_groups[] = { "gpio38" };
+static const char * const atest_bbrx0_groups[] = { "gpio37" };
+static const char * const atest_bbrx1_groups[] = { "gpio36" };
+static const char * const atest_char0_groups[] = { "gpio62" };
+static const char * const atest_char1_groups[] = { "gpio61" };
+static const char * const atest_char2_groups[] = { "gpio60" };
+static const char * const atest_char3_groups[] = { "gpio59" };
+static const char * const atest_char_groups[] = { "gpio63" };
+static const char * const atest_combodac_groups[] = {
+ "gpio32", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43",
+ "gpio44", "gpio45", "gpio47", "gpio48", "gpio66", "gpio81", "gpio83",
+ "gpio84", "gpio85", "gpio86", "gpio94", "gpio95", "gpio110"
+};
+static const char * const atest_gpsadc0_groups[] = { "gpio65" };
+static const char * const atest_gpsadc1_groups[] = { "gpio79" };
+static const char * const atest_wlan0_groups[] = { "gpio96" };
+static const char * const atest_wlan1_groups[] = { "gpio97" };
+static const char * const bimc_dte0_groups[] = { "gpio6", "gpio59" };
+static const char * const bimc_dte1_groups[] = { "gpio7", "gpio60" };
+static const char * const blsp_i2c1_groups[] = { "gpio6", "gpio7" };
+static const char * const blsp_i2c2_groups[] = { "gpio111", "gpio112" };
+static const char * const blsp_i2c3_groups[] = { "gpio29", "gpio30" };
+static const char * const blsp_i2c4_groups[] = { "gpio14", "gpio15" };
+static const char * const blsp_i2c5_groups[] = { "gpio18", "gpio19" };
+static const char * const blsp_i2c6_groups[] = { "gpio10", "gpio11" };
+static const char * const blsp_spi1_cs1_groups[] = { "gpio97" };
+static const char * const blsp_spi1_cs2_groups[] = { "gpio37" };
+static const char * const blsp_spi1_cs3_groups[] = { "gpio65" };
+static const char * const blsp_spi1_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7"
+};
+static const char * const blsp_spi2_cs1_groups[] = { "gpio98" };
+static const char * const blsp_spi2_cs2_groups[] = { "gpio17" };
+static const char * const blsp_spi2_cs3_groups[] = { "gpio5" };
+static const char * const blsp_spi2_groups[] = {
+ "gpio20", "gpio21", "gpio111", "gpio112"
+};
+static const char * const blsp_spi3_cs1_groups[] = { "gpio95" };
+static const char * const blsp_spi3_cs2_groups[] = { "gpio65" };
+static const char * const blsp_spi3_cs3_groups[] = { "gpio4" };
+static const char * const blsp_spi3_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3"
+};
+static const char * const blsp_spi4_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio15"
+};
+static const char * const blsp_spi5_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19"
+};
+static const char * const blsp_spi6_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11"
+};
+static const char * const blsp_uart1_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7"
+};
+static const char * const blsp_uart2_groups[] = {
+ "gpio20", "gpio21", "gpio111", "gpio112"
+};
+static const char * const blsp_uim1_groups[] = { "gpio4", "gpio5" };
+static const char * const blsp_uim2_groups[] = { "gpio20", "gpio21" };
+static const char * const cam_mclk_groups[] = { "gpio26", "gpio27" };
+static const char * const cci_async_groups[] = { "gpio33" };
+static const char * const cci_timer0_groups[] = { "gpio31" };
+static const char * const cci_timer1_groups[] = { "gpio32" };
+static const char * const cci_timer2_groups[] = { "gpio38" };
+static const char * const cdc_pdm0_groups[] = {
+ "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", "gpio64"
+};
+static const char * const dbg_out_groups[] = { "gpio10" };
+static const char * const dmic0_clk_groups[] = { "gpio4" };
+static const char * const dmic0_data_groups[] = { "gpio5" };
+static const char * const ebi0_wrcdc_groups[] = { "gpio64" };
+static const char * const ebi2_a_groups[] = { "gpio99" };
+static const char * const ebi2_lcd_groups[] = {
+ "gpio24", "gpio24", "gpio25", "gpio95"
+};
+static const char * const ext_lpass_groups[] = { "gpio45" };
+static const char * const gcc_gp1_clk_a_groups[] = { "gpio49" };
+static const char * const gcc_gp1_clk_b_groups[] = { "gpio14" };
+static const char * const gcc_gp2_clk_a_groups[] = { "gpio50" };
+static const char * const gcc_gp2_clk_b_groups[] = { "gpio12" };
+static const char * const gcc_gp3_clk_a_groups[] = { "gpio51" };
+static const char * const gcc_gp3_clk_b_groups[] = { "gpio13" };
+static const char * const gcc_plltest_groups[] = { "gpio66", "gpio67" };
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+ "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+ "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+ "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+ "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+ "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+ "gpio111", "gpio112"
+};
+static const char * const gsm0_tx_groups[] = { "gpio85" };
+static const char * const ldo_en_groups[] = { "gpio99" };
+static const char * const ldo_update_groups[] = { "gpio98" };
+static const char * const m_voc_groups[] = { "gpio8", "gpio95" };
+static const char * const mdp_vsync_groups[] = { "gpio24", "gpio25" };
+static const char * const modem_tsync_groups[] = { "gpio83" };
+static const char * const nav_pps_groups[] = { "gpio83" };
+static const char * const nav_tsync_groups[] = { "gpio83" };
+static const char * const pa_indicator_groups[] = { "gpio82" };
+static const char * const pbs0_groups[] = { "gpio90" };
+static const char * const pbs1_groups[] = { "gpio91" };
+static const char * const pbs2_groups[] = { "gpio92" };
+static const char * const pri_mi2s_data0_a_groups[] = { "gpio62" };
+static const char * const pri_mi2s_data0_b_groups[] = { "gpio95" };
+static const char * const pri_mi2s_data1_a_groups[] = { "gpio63" };
+static const char * const pri_mi2s_data1_b_groups[] = { "gpio96" };
+static const char * const pri_mi2s_mclk_a_groups[] = { "gpio59" };
+static const char * const pri_mi2s_mclk_b_groups[] = { "gpio98" };
+static const char * const pri_mi2s_sck_a_groups[] = { "gpio60" };
+static const char * const pri_mi2s_sck_b_groups[] = { "gpio94" };
+static const char * const pri_mi2s_ws_a_groups[] = { "gpio61" };
+static const char * const pri_mi2s_ws_b_groups[] = { "gpio110" };
+static const char * const prng_rosc_groups[] = { "gpio43" };
+static const char * const pwr_crypto_enabled_a_groups[] = { "gpio35" };
+static const char * const pwr_crypto_enabled_b_groups[] = { "gpio96" };
+static const char * const pwr_modem_enabled_a_groups[] = { "gpio28" };
+static const char * const pwr_modem_enabled_b_groups[] = { "gpio94" };
+static const char * const pwr_nav_enabled_a_groups[] = { "gpio34" };
+static const char * const pwr_nav_enabled_b_groups[] = { "gpio95" };
+static const char * const qdss_cti_trig_in_a0_groups[] = { "gpio20" };
+static const char * const qdss_cti_trig_in_a1_groups[] = { "gpio49" };
+static const char * const qdss_cti_trig_in_b0_groups[] = { "gpio21" };
+static const char * const qdss_cti_trig_in_b1_groups[] = { "gpio50" };
+static const char * const qdss_cti_trig_out_a0_groups[] = { "gpio23" };
+static const char * const qdss_cti_trig_out_a1_groups[] = { "gpio52" };
+static const char * const qdss_cti_trig_out_b0_groups[] = { "gpio22" };
+static const char * const qdss_cti_trig_out_b1_groups[] = { "gpio51" };
+static const char * const qdss_traceclk_a_groups[] = { "gpio46" };
+static const char * const qdss_tracectl_a_groups[] = { "gpio45" };
+static const char * const qdss_tracedata_a_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio47", "gpio48", "gpio58", "gpio65", "gpio94", "gpio96",
+ "gpio97"
+};
+static const char * const qdss_tracedata_b_groups[] = {
+ "gpio14", "gpio16", "gpio17", "gpio29", "gpio30", "gpio31", "gpio32",
+ "gpio33", "gpio34", "gpio35", "gpio36", "gpio37", "gpio93"
+};
+static const char * const sd_write_groups[] = { "gpio99" };
+static const char * const sec_mi2s_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio98"
+};
+static const char * const smb_int_groups[] = { "gpio58" };
+static const char * const ssbi0_groups[] = { "gpio88" };
+static const char * const ssbi1_groups[] = { "gpio89" };
+static const char * const uim1_clk_groups[] = { "gpio54" };
+static const char * const uim1_data_groups[] = { "gpio53" };
+static const char * const uim1_present_groups[] = { "gpio56" };
+static const char * const uim1_reset_groups[] = { "gpio55" };
+static const char * const uim2_clk_groups[] = { "gpio50" };
+static const char * const uim2_data_groups[] = { "gpio49" };
+static const char * const uim2_present_groups[] = { "gpio52" };
+static const char * const uim2_reset_groups[] = { "gpio51" };
+static const char * const uim3_clk_groups[] = { "gpio23" };
+static const char * const uim3_data_groups[] = { "gpio20" };
+static const char * const uim3_present_groups[] = { "gpio21" };
+static const char * const uim3_reset_groups[] = { "gpio22" };
+static const char * const uim_batt_groups[] = { "gpio57" };
+static const char * const wcss_bt_groups[] = { "gpio39", "gpio47", "gpio48" };
+static const char * const wcss_fm_groups[] = { "gpio45", "gpio46" };
+static const char * const wcss_wlan_groups[] = {
+ "gpio40", "gpio41", "gpio42", "gpio43", "gpio44"
+};
+
+static const struct msm_function msm8909_functions[] = {
+ FUNCTION(adsp_ext),
+ FUNCTION(atest_bbrx0),
+ FUNCTION(atest_bbrx1),
+ FUNCTION(atest_char),
+ FUNCTION(atest_char0),
+ FUNCTION(atest_char1),
+ FUNCTION(atest_char2),
+ FUNCTION(atest_char3),
+ FUNCTION(atest_combodac),
+ FUNCTION(atest_gpsadc0),
+ FUNCTION(atest_gpsadc1),
+ FUNCTION(atest_wlan0),
+ FUNCTION(atest_wlan1),
+ FUNCTION(bimc_dte0),
+ FUNCTION(bimc_dte1),
+ FUNCTION(blsp_i2c1),
+ FUNCTION(blsp_i2c2),
+ FUNCTION(blsp_i2c3),
+ FUNCTION(blsp_i2c4),
+ FUNCTION(blsp_i2c5),
+ FUNCTION(blsp_i2c6),
+ FUNCTION(blsp_spi1),
+ FUNCTION(blsp_spi1_cs1),
+ FUNCTION(blsp_spi1_cs2),
+ FUNCTION(blsp_spi1_cs3),
+ FUNCTION(blsp_spi2),
+ FUNCTION(blsp_spi2_cs1),
+ FUNCTION(blsp_spi2_cs2),
+ FUNCTION(blsp_spi2_cs3),
+ FUNCTION(blsp_spi3),
+ FUNCTION(blsp_spi3_cs1),
+ FUNCTION(blsp_spi3_cs2),
+ FUNCTION(blsp_spi3_cs3),
+ FUNCTION(blsp_spi4),
+ FUNCTION(blsp_spi5),
+ FUNCTION(blsp_spi6),
+ FUNCTION(blsp_uart1),
+ FUNCTION(blsp_uart2),
+ FUNCTION(blsp_uim1),
+ FUNCTION(blsp_uim2),
+ FUNCTION(cam_mclk),
+ FUNCTION(cci_async),
+ FUNCTION(cci_timer0),
+ FUNCTION(cci_timer1),
+ FUNCTION(cci_timer2),
+ FUNCTION(cdc_pdm0),
+ FUNCTION(dbg_out),
+ FUNCTION(dmic0_clk),
+ FUNCTION(dmic0_data),
+ FUNCTION(ebi0_wrcdc),
+ FUNCTION(ebi2_a),
+ FUNCTION(ebi2_lcd),
+ FUNCTION(ext_lpass),
+ FUNCTION(gcc_gp1_clk_a),
+ FUNCTION(gcc_gp1_clk_b),
+ FUNCTION(gcc_gp2_clk_a),
+ FUNCTION(gcc_gp2_clk_b),
+ FUNCTION(gcc_gp3_clk_a),
+ FUNCTION(gcc_gp3_clk_b),
+ FUNCTION(gcc_plltest),
+ FUNCTION(gpio),
+ FUNCTION(gsm0_tx),
+ FUNCTION(ldo_en),
+ FUNCTION(ldo_update),
+ FUNCTION(m_voc),
+ FUNCTION(mdp_vsync),
+ FUNCTION(modem_tsync),
+ FUNCTION(nav_pps),
+ FUNCTION(nav_tsync),
+ FUNCTION(pa_indicator),
+ FUNCTION(pbs0),
+ FUNCTION(pbs1),
+ FUNCTION(pbs2),
+ FUNCTION(pri_mi2s_data0_a),
+ FUNCTION(pri_mi2s_data0_b),
+ FUNCTION(pri_mi2s_data1_a),
+ FUNCTION(pri_mi2s_data1_b),
+ FUNCTION(pri_mi2s_mclk_a),
+ FUNCTION(pri_mi2s_mclk_b),
+ FUNCTION(pri_mi2s_sck_a),
+ FUNCTION(pri_mi2s_sck_b),
+ FUNCTION(pri_mi2s_ws_a),
+ FUNCTION(pri_mi2s_ws_b),
+ FUNCTION(prng_rosc),
+ FUNCTION(pwr_crypto_enabled_a),
+ FUNCTION(pwr_crypto_enabled_b),
+ FUNCTION(pwr_modem_enabled_a),
+ FUNCTION(pwr_modem_enabled_b),
+ FUNCTION(pwr_nav_enabled_a),
+ FUNCTION(pwr_nav_enabled_b),
+ FUNCTION(qdss_cti_trig_in_a0),
+ FUNCTION(qdss_cti_trig_in_a1),
+ FUNCTION(qdss_cti_trig_in_b0),
+ FUNCTION(qdss_cti_trig_in_b1),
+ FUNCTION(qdss_cti_trig_out_a0),
+ FUNCTION(qdss_cti_trig_out_a1),
+ FUNCTION(qdss_cti_trig_out_b0),
+ FUNCTION(qdss_cti_trig_out_b1),
+ FUNCTION(qdss_traceclk_a),
+ FUNCTION(qdss_tracectl_a),
+ FUNCTION(qdss_tracedata_a),
+ FUNCTION(qdss_tracedata_b),
+ FUNCTION(sd_write),
+ FUNCTION(sec_mi2s),
+ FUNCTION(smb_int),
+ FUNCTION(ssbi0),
+ FUNCTION(ssbi1),
+ FUNCTION(uim1_clk),
+ FUNCTION(uim1_data),
+ FUNCTION(uim1_present),
+ FUNCTION(uim1_reset),
+ FUNCTION(uim2_clk),
+ FUNCTION(uim2_data),
+ FUNCTION(uim2_present),
+ FUNCTION(uim2_reset),
+ FUNCTION(uim3_clk),
+ FUNCTION(uim3_data),
+ FUNCTION(uim3_present),
+ FUNCTION(uim3_reset),
+ FUNCTION(uim_batt),
+ FUNCTION(wcss_bt),
+ FUNCTION(wcss_fm),
+ FUNCTION(wcss_wlan),
+};
+
+static const struct msm_pingroup msm8909_groups[] = {
+ PINGROUP(0, blsp_spi3, sec_mi2s, _, _, _, _, _, _, _),
+ PINGROUP(1, blsp_spi3, sec_mi2s, _, _, _, _, _, _, _),
+ PINGROUP(2, blsp_spi3, sec_mi2s, _, _, _, _, _, _, _),
+ PINGROUP(3, blsp_spi3, sec_mi2s, _, _, _, _, _, _, _),
+ PINGROUP(4, blsp_spi1, blsp_uart1, blsp_uim1, blsp_spi3_cs3, dmic0_clk, _, _, _, _),
+ PINGROUP(5, blsp_spi1, blsp_uart1, blsp_uim1, blsp_spi2_cs3, dmic0_data, _, _, _, _),
+ PINGROUP(6, blsp_spi1, blsp_uart1, blsp_i2c1, _, _, _, _, _, bimc_dte0),
+ PINGROUP(7, blsp_spi1, blsp_uart1, blsp_i2c1, _, _, _, _, _, bimc_dte1),
+ PINGROUP(8, blsp_spi6, m_voc, _, _, _, _, _, qdss_tracedata_a, _),
+ PINGROUP(9, blsp_spi6, _, _, _, _, _, qdss_tracedata_a, _, _),
+ PINGROUP(10, blsp_spi6, blsp_i2c6, dbg_out, qdss_tracedata_a, _, _, _, _, _),
+ PINGROUP(11, blsp_spi6, blsp_i2c6, _, _, _, _, _, _, _),
+ PINGROUP(12, blsp_spi4, gcc_gp2_clk_b, _, _, _, _, _, _, _),
+ PINGROUP(13, blsp_spi4, gcc_gp3_clk_b, _, _, _, _, _, _, _),
+ PINGROUP(14, blsp_spi4, blsp_i2c4, gcc_gp1_clk_b, _, _, _, _, _, qdss_tracedata_b),
+ PINGROUP(15, blsp_spi4, blsp_i2c4, _, _, _, _, _, _, _),
+ PINGROUP(16, blsp_spi5, _, _, _, _, _, qdss_tracedata_b, _, _),
+ PINGROUP(17, blsp_spi5, blsp_spi2_cs2, _, _, _, _, _, qdss_tracedata_b, _),
+ PINGROUP(18, blsp_spi5, blsp_i2c5, _, _, _, _, _, _, _),
+ PINGROUP(19, blsp_spi5, blsp_i2c5, _, _, _, _, _, _, _),
+ PINGROUP(20, uim3_data, blsp_spi2, blsp_uart2, blsp_uim2, _, qdss_cti_trig_in_a0, _, _, _),
+ PINGROUP(21, uim3_present, blsp_spi2, blsp_uart2, blsp_uim2, _, qdss_cti_trig_in_b0, _, _, _),
+ PINGROUP(22, uim3_reset, _, qdss_cti_trig_out_b0, _, _, _, _, _, _),
+ PINGROUP(23, uim3_clk, qdss_cti_trig_out_a0, _, _, _, _, _, _, _),
+ PINGROUP(24, mdp_vsync, ebi2_lcd, ebi2_lcd, _, _, _, _, _, _),
+ PINGROUP(25, mdp_vsync, ebi2_lcd, _, _, _, _, _, _, _),
+ PINGROUP(26, cam_mclk, _, _, _, _, _, _, _, _),
+ PINGROUP(27, cam_mclk, _, _, _, _, _, _, _, _),
+ PINGROUP(28, _, pwr_modem_enabled_a, _, _, _, _, _, _, _),
+ PINGROUP(29, blsp_i2c3, _, _, _, _, _, qdss_tracedata_b, _, _),
+ PINGROUP(30, blsp_i2c3, _, _, _, _, _, qdss_tracedata_b, _, _),
+ PINGROUP(31, cci_timer0, _, _, _, _, _, _, qdss_tracedata_b, _),
+ PINGROUP(32, cci_timer1, _, qdss_tracedata_b, _, atest_combodac, _, _, _, _),
+ PINGROUP(33, cci_async, qdss_tracedata_b, _, _, _, _, _, _, _),
+ PINGROUP(34, pwr_nav_enabled_a, qdss_tracedata_b, _, _, _, _, _, _, _),
+ PINGROUP(35, pwr_crypto_enabled_a, qdss_tracedata_b, _, _, _, _, _, _, _),
+ PINGROUP(36, qdss_tracedata_b, _, atest_bbrx1, _, _, _, _, _, _),
+ PINGROUP(37, blsp_spi1_cs2, qdss_tracedata_b, _, atest_bbrx0, _, _, _, _, _),
+ PINGROUP(38, cci_timer2, adsp_ext, _, atest_combodac, _, _, _, _, _),
+ PINGROUP(39, wcss_bt, qdss_tracedata_a, _, atest_combodac, _, _, _, _, _),
+ PINGROUP(40, wcss_wlan, qdss_tracedata_a, _, atest_combodac, _, _, _, _, _),
+ PINGROUP(41, wcss_wlan, qdss_tracedata_a, _, atest_combodac, _, _, _, _, _),
+ PINGROUP(42, wcss_wlan, qdss_tracedata_a, _, atest_combodac, _, _, _, _, _),
+ PINGROUP(43, wcss_wlan, prng_rosc, qdss_tracedata_a, _, atest_combodac, _, _, _, _),
+ PINGROUP(44, wcss_wlan, _, atest_combodac, _, _, _, _, _, _),
+ PINGROUP(45, wcss_fm, ext_lpass, qdss_tracectl_a, _, atest_combodac, _, _, _, _),
+ PINGROUP(46, wcss_fm, qdss_traceclk_a, _, _, _, _, _, _, _),
+ PINGROUP(47, wcss_bt, qdss_tracedata_a, _, atest_combodac, _, _, _, _, _),
+ PINGROUP(48, wcss_bt, qdss_tracedata_a, _, atest_combodac, _, _, _, _, _),
+ PINGROUP(49, uim2_data, gcc_gp1_clk_a, qdss_cti_trig_in_a1, _, _, _, _, _, _),
+ PINGROUP(50, uim2_clk, gcc_gp2_clk_a, qdss_cti_trig_in_b1, _, _, _, _, _, _),
+ PINGROUP(51, uim2_reset, gcc_gp3_clk_a, qdss_cti_trig_out_b1, _, _, _, _, _, _),
+ PINGROUP(52, uim2_present, qdss_cti_trig_out_a1, _, _, _, _, _, _, _),
+ PINGROUP(53, uim1_data, _, _, _, _, _, _, _, _),
+ PINGROUP(54, uim1_clk, _, _, _, _, _, _, _, _),
+ PINGROUP(55, uim1_reset, _, _, _, _, _, _, _, _),
+ PINGROUP(56, uim1_present, _, _, _, _, _, _, _, _),
+ PINGROUP(57, uim_batt, _, _, _, _, _, _, _, _),
+ PINGROUP(58, qdss_tracedata_a, smb_int, _, _, _, _, _, _, _),
+ PINGROUP(59, cdc_pdm0, pri_mi2s_mclk_a, atest_char3, _, _, _, _, _, bimc_dte0),
+ PINGROUP(60, cdc_pdm0, pri_mi2s_sck_a, atest_char2, _, _, _, _, _, bimc_dte1),
+ PINGROUP(61, cdc_pdm0, pri_mi2s_ws_a, atest_char1, _, _, _, _, _, _),
+ PINGROUP(62, cdc_pdm0, pri_mi2s_data0_a, atest_char0, _, _, _, _, _, _),
+ PINGROUP(63, cdc_pdm0, pri_mi2s_data1_a, atest_char, _, _, _, _, _, _),
+ PINGROUP(64, cdc_pdm0, _, _, _, _, _, ebi0_wrcdc, _, _),
+ PINGROUP(65, blsp_spi3_cs2, blsp_spi1_cs3, qdss_tracedata_a, _, atest_gpsadc0, _, _, _, _),
+ PINGROUP(66, _, gcc_plltest, _, atest_combodac, _, _, _, _, _),
+ PINGROUP(67, _, gcc_plltest, _, _, _, _, _, _, _),
+ PINGROUP(68, _, _, _, _, _, _, _, _, _),
+ PINGROUP(69, _, _, _, _, _, _, _, _, _),
+ PINGROUP(70, _, _, _, _, _, _, _, _, _),
+ PINGROUP(71, _, _, _, _, _, _, _, _, _),
+ PINGROUP(72, _, _, _, _, _, _, _, _, _),
+ PINGROUP(73, _, _, _, _, _, _, _, _, _),
+ PINGROUP(74, _, _, _, _, _, _, _, _, _),
+ PINGROUP(75, _, _, _, _, _, _, _, _, _),
+ PINGROUP(76, _, _, _, _, _, _, _, _, _),
+ PINGROUP(77, _, _, _, _, _, _, _, _, _),
+ PINGROUP(78, _, _, _, _, _, _, _, _, _),
+ PINGROUP(79, _, _, atest_gpsadc1, _, _, _, _, _, _),
+ PINGROUP(80, _, _, _, _, _, _, _, _, _),
+ PINGROUP(81, _, _, _, atest_combodac, _, _, _, _, _),
+ PINGROUP(82, _, pa_indicator, _, _, _, _, _, _, _),
+ PINGROUP(83, _, modem_tsync, nav_tsync, nav_pps, _, atest_combodac, _, _, _),
+ PINGROUP(84, _, _, atest_combodac, _, _, _, _, _, _),
+ PINGROUP(85, gsm0_tx, _, _, atest_combodac, _, _, _, _, _),
+ PINGROUP(86, _, _, atest_combodac, _, _, _, _, _, _),
+ PINGROUP(87, _, _, _, _, _, _, _, _, _),
+ PINGROUP(88, _, ssbi0, _, _, _, _, _, _, _),
+ PINGROUP(89, _, ssbi1, _, _, _, _, _, _, _),
+ PINGROUP(90, pbs0, _, _, _, _, _, _, _, _),
+ PINGROUP(91, pbs1, _, _, _, _, _, _, _, _),
+ PINGROUP(92, pbs2, _, _, _, _, _, _, _, _),
+ PINGROUP(93, qdss_tracedata_b, _, _, _, _, _, _, _, _),
+ PINGROUP(94, pri_mi2s_sck_b, pwr_modem_enabled_b, qdss_tracedata_a, _, atest_combodac, _, _, _, _),
+ PINGROUP(95, blsp_spi3_cs1, pri_mi2s_data0_b, ebi2_lcd, m_voc, pwr_nav_enabled_b, _, atest_combodac, _, _),
+ PINGROUP(96, pri_mi2s_data1_b, _, pwr_crypto_enabled_b, qdss_tracedata_a, _, atest_wlan0, _, _, _),
+ PINGROUP(97, blsp_spi1_cs1, qdss_tracedata_a, _, atest_wlan1, _, _, _, _, _),
+ PINGROUP(98, sec_mi2s, pri_mi2s_mclk_b, blsp_spi2_cs1, ldo_update, _, _, _, _, _),
+ PINGROUP(99, ebi2_a, sd_write, ldo_en, _, _, _, _, _, _),
+ PINGROUP(100, _, _, _, _, _, _, _, _, _),
+ PINGROUP(101, _, _, _, _, _, _, _, _, _),
+ PINGROUP(102, _, _, _, _, _, _, _, _, _),
+ PINGROUP(103, _, _, _, _, _, _, _, _, _),
+ PINGROUP(104, _, _, _, _, _, _, _, _, _),
+ PINGROUP(105, _, _, _, _, _, _, _, _, _),
+ PINGROUP(106, _, _, _, _, _, _, _, _, _),
+ PINGROUP(107, _, _, _, _, _, _, _, _, _),
+ PINGROUP(108, _, _, _, _, _, _, _, _, _),
+ PINGROUP(109, _, _, _, _, _, _, _, _, _),
+ PINGROUP(110, pri_mi2s_ws_b, _, atest_combodac, _, _, _, _, _, _),
+ PINGROUP(111, blsp_spi2, blsp_uart2, blsp_i2c2, _, _, _, _, _, _),
+ PINGROUP(112, blsp_spi2, blsp_uart2, blsp_i2c2, _, _, _, _, _, _),
+ SDC_QDSD_PINGROUP(sdc1_clk, 0x10a000, 13, 6),
+ SDC_QDSD_PINGROUP(sdc1_cmd, 0x10a000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc1_data, 0x10a000, 9, 0),
+ SDC_QDSD_PINGROUP(sdc2_clk, 0x109000, 14, 6),
+ SDC_QDSD_PINGROUP(sdc2_cmd, 0x109000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc2_data, 0x109000, 9, 0),
+ SDC_QDSD_PINGROUP(qdsd_clk, 0x19c000, 3, 0),
+ SDC_QDSD_PINGROUP(qdsd_cmd, 0x19c000, 8, 5),
+ SDC_QDSD_PINGROUP(qdsd_data0, 0x19c000, 13, 10),
+ SDC_QDSD_PINGROUP(qdsd_data1, 0x19c000, 18, 15),
+ SDC_QDSD_PINGROUP(qdsd_data2, 0x19c000, 23, 20),
+ SDC_QDSD_PINGROUP(qdsd_data3, 0x19c000, 28, 25),
+};
+
+static const struct msm_gpio_wakeirq_map msm8909_mpm_map[] = {
+ { 65, 3 }, { 5, 4 }, { 11, 5 }, { 12, 6 }, { 64, 7 }, { 58, 8 },
+ { 50, 9 }, { 13, 10 }, { 49, 11 }, { 20, 12 }, { 21, 13 }, { 25, 14 },
+ { 46, 15 }, { 45, 16 }, { 28, 17 }, { 44, 18 }, { 31, 19 }, { 43, 20 },
+ { 42, 21 }, { 34, 22 }, { 35, 23 }, { 36, 24 }, { 37, 25 }, { 38, 26 },
+ { 39, 27 }, { 40, 28 }, { 41, 29 }, { 90, 30 }, { 91, 32 }, { 92, 33 },
+ { 94, 34 }, { 95, 35 }, { 96, 36 }, { 97, 37 }, { 98, 38 },
+ { 110, 39 }, { 111, 40 }, { 112, 41 }, { 105, 42 }, { 107, 43 },
+ { 47, 50 }, { 48, 51 },
+};
+
+static const struct msm_pinctrl_soc_data msm8909_pinctrl = {
+ .pins = msm8909_pins,
+ .npins = ARRAY_SIZE(msm8909_pins),
+ .functions = msm8909_functions,
+ .nfunctions = ARRAY_SIZE(msm8909_functions),
+ .groups = msm8909_groups,
+ .ngroups = ARRAY_SIZE(msm8909_groups),
+ .ngpios = 113,
+ .wakeirq_map = msm8909_mpm_map,
+ .nwakeirq_map = ARRAY_SIZE(msm8909_mpm_map),
+};
+
+static int msm8909_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &msm8909_pinctrl);
+}
+
+static const struct of_device_id msm8909_pinctrl_of_match[] = {
+ { .compatible = "qcom,msm8909-tlmm", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, msm8909_pinctrl_of_match);
+
+static struct platform_driver msm8909_pinctrl_driver = {
+ .driver = {
+ .name = "msm8909-pinctrl",
+ .of_match_table = msm8909_pinctrl_of_match,
+ },
+ .probe = msm8909_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init msm8909_pinctrl_init(void)
+{
+ return platform_driver_register(&msm8909_pinctrl_driver);
+}
+arch_initcall(msm8909_pinctrl_init);
+
+static void __exit msm8909_pinctrl_exit(void)
+{
+ platform_driver_unregister(&msm8909_pinctrl_driver);
+}
+module_exit(msm8909_pinctrl_exit);
+
+MODULE_DESCRIPTION("Qualcomm MSM8909 TLMM pinctrl driver");
+MODULE_LICENSE("GPL");
PINGROUP(28, pwr_modem_enabled_a, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, atest_combodac),
PINGROUP(29, cci_i2c, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, atest_combodac),
PINGROUP(30, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b),
- PINGROUP(31, cci_timer0, NA, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(32, cci_timer1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(31, cci_timer0, flash_strobe, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(32, cci_timer1, flash_strobe, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(33, cci_async, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b),
PINGROUP(34, pwr_nav_enabled_a, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b),
PINGROUP(35, pwr_crypto_enabled_a, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b),
.ngroups = ARRAY_SIZE(sc7280_groups),
.functions = sc7280_functions,
.nfunctions = ARRAY_SIZE(sc7280_functions),
- .is_clk_optional = true,
};
static const struct of_device_id lpi_pinctrl_of_match[] = {
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Konrad Dybcio <konrad.dybcio@somainline.org>
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname) \
+ [msm_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define REG_BASE 0x100000
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = REG_SIZE * id, \
+ .io_reg = REG_SIZE * id + 0x4, \
+ .intr_cfg_reg = REG_SIZE * id + 0x8, \
+ .intr_status_reg = REG_SIZE * id + 0xc, \
+ .intr_target_reg = REG_SIZE * id + 0x8, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .egpio_enable = 12, \
+ .egpio_present = 11, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 3, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+#define UFS_RESET(pg_name, offset) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = offset, \
+ .io_reg = offset + 0x4, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+static const struct pinctrl_pin_desc sm6375_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "GPIO_122"),
+ PINCTRL_PIN(123, "GPIO_123"),
+ PINCTRL_PIN(124, "GPIO_124"),
+ PINCTRL_PIN(125, "GPIO_125"),
+ PINCTRL_PIN(126, "GPIO_126"),
+ PINCTRL_PIN(127, "GPIO_127"),
+ PINCTRL_PIN(128, "GPIO_128"),
+ PINCTRL_PIN(129, "GPIO_129"),
+ PINCTRL_PIN(130, "GPIO_130"),
+ PINCTRL_PIN(131, "GPIO_131"),
+ PINCTRL_PIN(132, "GPIO_132"),
+ PINCTRL_PIN(133, "GPIO_133"),
+ PINCTRL_PIN(134, "GPIO_134"),
+ PINCTRL_PIN(135, "GPIO_135"),
+ PINCTRL_PIN(136, "GPIO_136"),
+ PINCTRL_PIN(137, "GPIO_137"),
+ PINCTRL_PIN(138, "GPIO_138"),
+ PINCTRL_PIN(139, "GPIO_139"),
+ PINCTRL_PIN(140, "GPIO_140"),
+ PINCTRL_PIN(141, "GPIO_141"),
+ PINCTRL_PIN(142, "GPIO_142"),
+ PINCTRL_PIN(143, "GPIO_143"),
+ PINCTRL_PIN(144, "GPIO_144"),
+ PINCTRL_PIN(145, "GPIO_145"),
+ PINCTRL_PIN(146, "GPIO_146"),
+ PINCTRL_PIN(147, "GPIO_147"),
+ PINCTRL_PIN(148, "GPIO_148"),
+ PINCTRL_PIN(149, "GPIO_149"),
+ PINCTRL_PIN(150, "GPIO_150"),
+ PINCTRL_PIN(151, "GPIO_151"),
+ PINCTRL_PIN(152, "GPIO_152"),
+ PINCTRL_PIN(153, "GPIO_153"),
+ PINCTRL_PIN(154, "GPIO_154"),
+ PINCTRL_PIN(155, "GPIO_155"),
+ PINCTRL_PIN(156, "UFS_RESET"),
+ PINCTRL_PIN(157, "SDC1_RCLK"),
+ PINCTRL_PIN(158, "SDC1_CLK"),
+ PINCTRL_PIN(159, "SDC1_CMD"),
+ PINCTRL_PIN(160, "SDC1_DATA"),
+ PINCTRL_PIN(161, "SDC2_CLK"),
+ PINCTRL_PIN(162, "SDC2_CMD"),
+ PINCTRL_PIN(163, "SDC2_DATA"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+DECLARE_MSM_GPIO_PINS(149);
+DECLARE_MSM_GPIO_PINS(150);
+DECLARE_MSM_GPIO_PINS(151);
+DECLARE_MSM_GPIO_PINS(152);
+DECLARE_MSM_GPIO_PINS(153);
+DECLARE_MSM_GPIO_PINS(154);
+DECLARE_MSM_GPIO_PINS(155);
+
+
+static const unsigned int sdc1_rclk_pins[] = { 157 };
+static const unsigned int sdc1_clk_pins[] = { 158 };
+static const unsigned int sdc1_cmd_pins[] = { 159 };
+static const unsigned int sdc1_data_pins[] = { 160 };
+static const unsigned int sdc2_clk_pins[] = { 161 };
+static const unsigned int sdc2_cmd_pins[] = { 162 };
+static const unsigned int sdc2_data_pins[] = { 163 };
+static const unsigned int ufs_reset_pins[] = { 156 };
+
+enum sm6375_functions {
+ msm_mux_adsp_ext,
+ msm_mux_agera_pll,
+ msm_mux_atest_char,
+ msm_mux_atest_char0,
+ msm_mux_atest_char1,
+ msm_mux_atest_char2,
+ msm_mux_atest_char3,
+ msm_mux_atest_tsens,
+ msm_mux_atest_tsens2,
+ msm_mux_atest_usb1,
+ msm_mux_atest_usb10,
+ msm_mux_atest_usb11,
+ msm_mux_atest_usb12,
+ msm_mux_atest_usb13,
+ msm_mux_atest_usb2,
+ msm_mux_atest_usb20,
+ msm_mux_atest_usb21,
+ msm_mux_atest_usb22,
+ msm_mux_atest_usb23,
+ msm_mux_audio_ref,
+ msm_mux_btfm_slimbus,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async,
+ msm_mux_cci_i2c,
+ msm_mux_cci_timer0,
+ msm_mux_cci_timer1,
+ msm_mux_cci_timer2,
+ msm_mux_cci_timer3,
+ msm_mux_cci_timer4,
+ msm_mux_cri_trng,
+ msm_mux_dbg_out,
+ msm_mux_ddr_bist,
+ msm_mux_ddr_pxi0,
+ msm_mux_ddr_pxi1,
+ msm_mux_ddr_pxi2,
+ msm_mux_ddr_pxi3,
+ msm_mux_dp_hot,
+ msm_mux_edp_lcd,
+ msm_mux_gcc_gp1,
+ msm_mux_gcc_gp2,
+ msm_mux_gcc_gp3,
+ msm_mux_gp_pdm0,
+ msm_mux_gp_pdm1,
+ msm_mux_gp_pdm2,
+ msm_mux_gpio,
+ msm_mux_gps_tx,
+ msm_mux_ibi_i3c,
+ msm_mux_jitter_bist,
+ msm_mux_ldo_en,
+ msm_mux_ldo_update,
+ msm_mux_lpass_ext,
+ msm_mux_m_voc,
+ msm_mux_mclk,
+ msm_mux_mdp_vsync,
+ msm_mux_mdp_vsync0,
+ msm_mux_mdp_vsync1,
+ msm_mux_mdp_vsync2,
+ msm_mux_mdp_vsync3,
+ msm_mux_mi2s_0,
+ msm_mux_mi2s_1,
+ msm_mux_mi2s_2,
+ msm_mux_mss_lte,
+ msm_mux_nav_gpio,
+ msm_mux_nav_pps,
+ msm_mux_pa_indicator,
+ msm_mux_phase_flag0,
+ msm_mux_phase_flag1,
+ msm_mux_phase_flag10,
+ msm_mux_phase_flag11,
+ msm_mux_phase_flag12,
+ msm_mux_phase_flag13,
+ msm_mux_phase_flag14,
+ msm_mux_phase_flag15,
+ msm_mux_phase_flag16,
+ msm_mux_phase_flag17,
+ msm_mux_phase_flag18,
+ msm_mux_phase_flag19,
+ msm_mux_phase_flag2,
+ msm_mux_phase_flag20,
+ msm_mux_phase_flag21,
+ msm_mux_phase_flag22,
+ msm_mux_phase_flag23,
+ msm_mux_phase_flag24,
+ msm_mux_phase_flag25,
+ msm_mux_phase_flag26,
+ msm_mux_phase_flag27,
+ msm_mux_phase_flag28,
+ msm_mux_phase_flag29,
+ msm_mux_phase_flag3,
+ msm_mux_phase_flag30,
+ msm_mux_phase_flag31,
+ msm_mux_phase_flag4,
+ msm_mux_phase_flag5,
+ msm_mux_phase_flag6,
+ msm_mux_phase_flag7,
+ msm_mux_phase_flag8,
+ msm_mux_phase_flag9,
+ msm_mux_pll_bist,
+ msm_mux_pll_bypassnl,
+ msm_mux_pll_clk,
+ msm_mux_pll_reset,
+ msm_mux_prng_rosc0,
+ msm_mux_prng_rosc1,
+ msm_mux_prng_rosc2,
+ msm_mux_prng_rosc3,
+ msm_mux_qdss_cti,
+ msm_mux_qdss_gpio,
+ msm_mux_qdss_gpio0,
+ msm_mux_qdss_gpio1,
+ msm_mux_qdss_gpio10,
+ msm_mux_qdss_gpio11,
+ msm_mux_qdss_gpio12,
+ msm_mux_qdss_gpio13,
+ msm_mux_qdss_gpio14,
+ msm_mux_qdss_gpio15,
+ msm_mux_qdss_gpio2,
+ msm_mux_qdss_gpio3,
+ msm_mux_qdss_gpio4,
+ msm_mux_qdss_gpio5,
+ msm_mux_qdss_gpio6,
+ msm_mux_qdss_gpio7,
+ msm_mux_qdss_gpio8,
+ msm_mux_qdss_gpio9,
+ msm_mux_qlink0_enable,
+ msm_mux_qlink0_request,
+ msm_mux_qlink0_wmss,
+ msm_mux_qlink1_enable,
+ msm_mux_qlink1_request,
+ msm_mux_qlink1_wmss,
+ msm_mux_qup00,
+ msm_mux_qup01,
+ msm_mux_qup02,
+ msm_mux_qup10,
+ msm_mux_qup11_f1,
+ msm_mux_qup11_f2,
+ msm_mux_qup12,
+ msm_mux_qup13_f1,
+ msm_mux_qup13_f2,
+ msm_mux_qup14,
+ msm_mux_sd_write,
+ msm_mux_sdc1_tb,
+ msm_mux_sdc2_tb,
+ msm_mux_sp_cmu,
+ msm_mux_tgu_ch0,
+ msm_mux_tgu_ch1,
+ msm_mux_tgu_ch2,
+ msm_mux_tgu_ch3,
+ msm_mux_tsense_pwm1,
+ msm_mux_tsense_pwm2,
+ msm_mux_uim1_clk,
+ msm_mux_uim1_data,
+ msm_mux_uim1_present,
+ msm_mux_uim1_reset,
+ msm_mux_uim2_clk,
+ msm_mux_uim2_data,
+ msm_mux_uim2_present,
+ msm_mux_uim2_reset,
+ msm_mux_usb2phy_ac,
+ msm_mux_usb_phy,
+ msm_mux_vfr_1,
+ msm_mux_vsense_trigger,
+ msm_mux_wlan1_adc0,
+ msm_mux_wlan1_adc1,
+ msm_mux_wlan2_adc0,
+ msm_mux_wlan2_adc1,
+ msm_mux__,
+};
+
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15",
+ "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", "gpio22",
+ "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29",
+ "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36",
+ "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43",
+ "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49", "gpio50",
+ "gpio51", "gpio52", "gpio53", "gpio56", "gpio57", "gpio58", "gpio59",
+ "gpio60", "gpio61", "gpio62", "gpio63", "gpio64", "gpio65", "gpio66",
+ "gpio67", "gpio68", "gpio69", "gpio75", "gpio76", "gpio77", "gpio78",
+ "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84", "gpio85",
+ "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91", "gpio92",
+ "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98", "gpio99",
+ "gpio100", "gpio101", "gpio102", "gpio103", "gpio104", "gpio105",
+ "gpio106", "gpio107", "gpio108", "gpio109", "gpio110", "gpio111",
+ "gpio112", "gpio113", "gpio114", "gpio115", "gpio116", "gpio117",
+ "gpio118", "gpio119", "gpio120", "gpio124", "gpio125", "gpio126",
+ "gpio127", "gpio128", "gpio129", "gpio130", "gpio131", "gpio132",
+ "gpio133", "gpio134", "gpio135", "gpio136", "gpio141", "gpio142",
+ "gpio143", "gpio150", "gpio151", "gpio152", "gpio153", "gpio154",
+ "gpio155",
+};
+static const char * const agera_pll_groups[] = {
+ "gpio89",
+};
+static const char * const cci_async_groups[] = {
+ "gpio35", "gpio36", "gpio48", "gpio52", "gpio53",
+};
+static const char * const cci_i2c_groups[] = {
+ "gpio2", "gpio3", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43",
+ "gpio44",
+};
+static const char * const gps_tx_groups[] = {
+ "gpio101", "gpio102", "gpio107", "gpio108",
+};
+static const char * const gp_pdm0_groups[] = {
+ "gpio37", "gpio68",
+};
+static const char * const gp_pdm1_groups[] = {
+ "gpio8", "gpio52",
+};
+static const char * const gp_pdm2_groups[] = {
+ "gpio57",
+};
+static const char * const jitter_bist_groups[] = {
+ "gpio90",
+};
+static const char * const mclk_groups[] = {
+ "gpio93",
+};
+static const char * const mdp_vsync_groups[] = {
+ "gpio6", "gpio23", "gpio24", "gpio27", "gpio28",
+};
+static const char * const mss_lte_groups[] = {
+ "gpio65", "gpio66",
+};
+static const char * const nav_pps_groups[] = {
+ "gpio101", "gpio101", "gpio102", "gpio102",
+};
+static const char * const pll_bist_groups[] = {
+ "gpio27",
+};
+static const char * const qlink0_wmss_groups[] = {
+ "gpio103",
+};
+static const char * const qlink1_wmss_groups[] = {
+ "gpio106",
+};
+static const char * const usb_phy_groups[] = {
+ "gpio124",
+};
+static const char * const adsp_ext_groups[] = {
+ "gpio87",
+};
+static const char * const atest_char_groups[] = {
+ "gpio95",
+};
+static const char * const atest_char0_groups[] = {
+ "gpio96",
+};
+static const char * const atest_char1_groups[] = {
+ "gpio97",
+};
+static const char * const atest_char2_groups[] = {
+ "gpio98",
+};
+static const char * const atest_char3_groups[] = {
+ "gpio99",
+};
+static const char * const atest_tsens_groups[] = {
+ "gpio92",
+};
+static const char * const atest_tsens2_groups[] = {
+ "gpio93",
+};
+static const char * const atest_usb1_groups[] = {
+ "gpio83",
+};
+static const char * const atest_usb10_groups[] = {
+ "gpio84",
+};
+static const char * const atest_usb11_groups[] = {
+ "gpio85",
+};
+static const char * const atest_usb12_groups[] = {
+ "gpio86",
+};
+static const char * const atest_usb13_groups[] = {
+ "gpio87",
+};
+static const char * const atest_usb2_groups[] = {
+ "gpio88",
+};
+static const char * const atest_usb20_groups[] = {
+ "gpio89",
+};
+static const char * const atest_usb21_groups[] = {
+ "gpio90",
+};
+static const char * const atest_usb22_groups[] = {
+ "gpio91",
+};
+static const char * const atest_usb23_groups[] = {
+ "gpio92",
+};
+static const char * const audio_ref_groups[] = {
+ "gpio60",
+};
+static const char * const btfm_slimbus_groups[] = {
+ "gpio67", "gpio68", "gpio86", "gpio87",
+};
+static const char * const cam_mclk_groups[] = {
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33",
+};
+static const char * const cci_timer0_groups[] = {
+ "gpio34",
+};
+static const char * const cci_timer1_groups[] = {
+ "gpio35",
+};
+static const char * const cci_timer2_groups[] = {
+ "gpio36",
+};
+static const char * const cci_timer3_groups[] = {
+ "gpio37",
+};
+static const char * const cci_timer4_groups[] = {
+ "gpio38",
+};
+static const char * const cri_trng_groups[] = {
+ "gpio0", "gpio1", "gpio2",
+};
+static const char * const dbg_out_groups[] = {
+ "gpio3",
+};
+static const char * const ddr_bist_groups[] = {
+ "gpio19", "gpio20", "gpio21", "gpio22",
+};
+static const char * const ddr_pxi0_groups[] = {
+ "gpio86", "gpio90",
+};
+static const char * const ddr_pxi1_groups[] = {
+ "gpio87", "gpio91",
+};
+static const char * const ddr_pxi2_groups[] = {
+ "gpio88", "gpio92",
+};
+static const char * const ddr_pxi3_groups[] = {
+ "gpio89", "gpio93",
+};
+static const char * const dp_hot_groups[] = {
+ "gpio12", "gpio118",
+};
+static const char * const edp_lcd_groups[] = {
+ "gpio23",
+};
+static const char * const gcc_gp1_groups[] = {
+ "gpio48", "gpio58",
+};
+static const char * const gcc_gp2_groups[] = {
+ "gpio21",
+};
+static const char * const gcc_gp3_groups[] = {
+ "gpio22",
+};
+static const char * const ibi_i3c_groups[] = {
+ "gpio0", "gpio1",
+};
+static const char * const ldo_en_groups[] = {
+ "gpio95",
+};
+static const char * const ldo_update_groups[] = {
+ "gpio96",
+};
+static const char * const lpass_ext_groups[] = {
+ "gpio60", "gpio93",
+};
+static const char * const m_voc_groups[] = {
+ "gpio12",
+};
+static const char * const mdp_vsync0_groups[] = {
+ "gpio47",
+};
+static const char * const mdp_vsync1_groups[] = {
+ "gpio48",
+};
+static const char * const mdp_vsync2_groups[] = {
+ "gpio56",
+};
+static const char * const mdp_vsync3_groups[] = {
+ "gpio57",
+};
+static const char * const mi2s_0_groups[] = {
+ "gpio88", "gpio89", "gpio90", "gpio91",
+};
+static const char * const mi2s_1_groups[] = {
+ "gpio67", "gpio68", "gpio86", "gpio87",
+};
+static const char * const mi2s_2_groups[] = {
+ "gpio60",
+};
+static const char * const nav_gpio_groups[] = {
+ "gpio101", "gpio102",
+};
+static const char * const pa_indicator_groups[] = {
+ "gpio118",
+};
+static const char * const phase_flag0_groups[] = {
+ "gpio12",
+};
+static const char * const phase_flag1_groups[] = {
+ "gpio17",
+};
+static const char * const phase_flag10_groups[] = {
+ "gpio41",
+};
+static const char * const phase_flag11_groups[] = {
+ "gpio42",
+};
+static const char * const phase_flag12_groups[] = {
+ "gpio43",
+};
+static const char * const phase_flag13_groups[] = {
+ "gpio44",
+};
+static const char * const phase_flag14_groups[] = {
+ "gpio45",
+};
+static const char * const phase_flag15_groups[] = {
+ "gpio46",
+};
+static const char * const phase_flag16_groups[] = {
+ "gpio47",
+};
+static const char * const phase_flag17_groups[] = {
+ "gpio48",
+};
+static const char * const phase_flag18_groups[] = {
+ "gpio49",
+};
+static const char * const phase_flag19_groups[] = {
+ "gpio50",
+};
+static const char * const phase_flag2_groups[] = {
+ "gpio18",
+};
+static const char * const phase_flag20_groups[] = {
+ "gpio51",
+};
+static const char * const phase_flag21_groups[] = {
+ "gpio52",
+};
+static const char * const phase_flag22_groups[] = {
+ "gpio53",
+};
+static const char * const phase_flag23_groups[] = {
+ "gpio56",
+};
+static const char * const phase_flag24_groups[] = {
+ "gpio57",
+};
+static const char * const phase_flag25_groups[] = {
+ "gpio60",
+};
+static const char * const phase_flag26_groups[] = {
+ "gpio61",
+};
+static const char * const phase_flag27_groups[] = {
+ "gpio62",
+};
+static const char * const phase_flag28_groups[] = {
+ "gpio63",
+};
+static const char * const phase_flag29_groups[] = {
+ "gpio64",
+};
+static const char * const phase_flag3_groups[] = {
+ "gpio34",
+};
+static const char * const phase_flag30_groups[] = {
+ "gpio67",
+};
+static const char * const phase_flag31_groups[] = {
+ "gpio68",
+};
+static const char * const phase_flag4_groups[] = {
+ "gpio35",
+};
+static const char * const phase_flag5_groups[] = {
+ "gpio36",
+};
+static const char * const phase_flag6_groups[] = {
+ "gpio37",
+};
+static const char * const phase_flag7_groups[] = {
+ "gpio38",
+};
+static const char * const phase_flag8_groups[] = {
+ "gpio39",
+};
+static const char * const phase_flag9_groups[] = {
+ "gpio40",
+};
+static const char * const pll_bypassnl_groups[] = {
+ "gpio13",
+};
+static const char * const pll_clk_groups[] = {
+ "gpio98",
+};
+static const char * const pll_reset_groups[] = {
+ "gpio14",
+};
+static const char * const prng_rosc0_groups[] = {
+ "gpio97",
+};
+static const char * const prng_rosc1_groups[] = {
+ "gpio98",
+};
+static const char * const prng_rosc2_groups[] = {
+ "gpio99",
+};
+static const char * const prng_rosc3_groups[] = {
+ "gpio100",
+};
+static const char * const qdss_cti_groups[] = {
+ "gpio2", "gpio3", "gpio6", "gpio7", "gpio61", "gpio62", "gpio86",
+ "gpio87",
+};
+static const char * const qdss_gpio_groups[] = {
+ "gpio8", "gpio9", "gpio63", "gpio64",
+};
+static const char * const qdss_gpio0_groups[] = {
+ "gpio39", "gpio65",
+};
+static const char * const qdss_gpio1_groups[] = {
+ "gpio40", "gpio66",
+};
+static const char * const qdss_gpio10_groups[] = {
+ "gpio50", "gpio56",
+};
+static const char * const qdss_gpio11_groups[] = {
+ "gpio51", "gpio57",
+};
+static const char * const qdss_gpio12_groups[] = {
+ "gpio34", "gpio52",
+};
+static const char * const qdss_gpio13_groups[] = {
+ "gpio35", "gpio53",
+};
+static const char * const qdss_gpio14_groups[] = {
+ "gpio27", "gpio36",
+};
+static const char * const qdss_gpio15_groups[] = {
+ "gpio28", "gpio37",
+};
+static const char * const qdss_gpio2_groups[] = {
+ "gpio38", "gpio41",
+};
+static const char * const qdss_gpio3_groups[] = {
+ "gpio42", "gpio47",
+};
+static const char * const qdss_gpio4_groups[] = {
+ "gpio43", "gpio88",
+};
+static const char * const qdss_gpio5_groups[] = {
+ "gpio44", "gpio89",
+};
+static const char * const qdss_gpio6_groups[] = {
+ "gpio45", "gpio90",
+};
+static const char * const qdss_gpio7_groups[] = {
+ "gpio46", "gpio91",
+};
+static const char * const qdss_gpio8_groups[] = {
+ "gpio48", "gpio92",
+};
+static const char * const qdss_gpio9_groups[] = {
+ "gpio49", "gpio93",
+};
+static const char * const qlink0_enable_groups[] = {
+ "gpio105",
+};
+static const char * const qlink0_request_groups[] = {
+ "gpio104",
+};
+static const char * const qlink1_enable_groups[] = {
+ "gpio108",
+};
+static const char * const qlink1_request_groups[] = {
+ "gpio107",
+};
+static const char * const qup00_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const qup01_groups[] = {
+ "gpio61", "gpio62", "gpio63", "gpio64",
+};
+static const char * const qup02_groups[] = {
+ "gpio45", "gpio46", "gpio48", "gpio56", "gpio57",
+};
+static const char * const qup10_groups[] = {
+ "gpio13", "gpio14", "gpio15", "gpio16", "gpio17",
+};
+static const char * const qup11_f1_groups[] = {
+ "gpio27", "gpio28",
+};
+static const char * const qup11_f2_groups[] = {
+ "gpio27", "gpio28",
+};
+
+static const char * const qup12_groups[] = {
+ "gpio19", "gpio19", "gpio20", "gpio20",
+};
+static const char * const qup13_f1_groups[] = {
+ "gpio25", "gpio26",
+};
+static const char * const qup13_f2_groups[] = {
+ "gpio25", "gpio26",
+};
+static const char * const qup14_groups[] = {
+ "gpio4", "gpio4", "gpio5", "gpio5",
+};
+static const char * const sd_write_groups[] = {
+ "gpio85",
+};
+static const char * const sdc1_tb_groups[] = {
+ "gpio4",
+};
+static const char * const sdc2_tb_groups[] = {
+ "gpio5",
+};
+static const char * const sp_cmu_groups[] = {
+ "gpio3",
+};
+static const char * const tgu_ch0_groups[] = {
+ "gpio61",
+};
+static const char * const tgu_ch1_groups[] = {
+ "gpio62",
+};
+static const char * const tgu_ch2_groups[] = {
+ "gpio63",
+};
+static const char * const tgu_ch3_groups[] = {
+ "gpio64",
+};
+static const char * const tsense_pwm1_groups[] = {
+ "gpio88",
+};
+static const char * const tsense_pwm2_groups[] = {
+ "gpio88",
+};
+static const char * const uim1_clk_groups[] = {
+ "gpio80",
+};
+static const char * const uim1_data_groups[] = {
+ "gpio79",
+};
+static const char * const uim1_present_groups[] = {
+ "gpio82",
+};
+static const char * const uim1_reset_groups[] = {
+ "gpio81",
+};
+static const char * const uim2_clk_groups[] = {
+ "gpio76",
+};
+static const char * const uim2_data_groups[] = {
+ "gpio75",
+};
+static const char * const uim2_present_groups[] = {
+ "gpio78",
+};
+static const char * const uim2_reset_groups[] = {
+ "gpio77",
+};
+static const char * const usb2phy_ac_groups[] = {
+ "gpio47",
+};
+static const char * const vfr_1_groups[] = {
+ "gpio49",
+};
+static const char * const vsense_trigger_groups[] = {
+ "gpio89",
+};
+static const char * const wlan1_adc0_groups[] = {
+ "gpio90",
+};
+static const char * const wlan1_adc1_groups[] = {
+ "gpio92",
+};
+static const char * const wlan2_adc0_groups[] = {
+ "gpio91",
+};
+static const char * const wlan2_adc1_groups[] = {
+ "gpio93",
+};
+
+static const struct msm_function sm6375_functions[] = {
+ FUNCTION(adsp_ext),
+ FUNCTION(agera_pll),
+ FUNCTION(atest_char),
+ FUNCTION(atest_char0),
+ FUNCTION(atest_char1),
+ FUNCTION(atest_char2),
+ FUNCTION(atest_char3),
+ FUNCTION(atest_tsens),
+ FUNCTION(atest_tsens2),
+ FUNCTION(atest_usb1),
+ FUNCTION(atest_usb10),
+ FUNCTION(atest_usb11),
+ FUNCTION(atest_usb12),
+ FUNCTION(atest_usb13),
+ FUNCTION(atest_usb2),
+ FUNCTION(atest_usb20),
+ FUNCTION(atest_usb21),
+ FUNCTION(atest_usb22),
+ FUNCTION(atest_usb23),
+ FUNCTION(audio_ref),
+ FUNCTION(btfm_slimbus),
+ FUNCTION(cam_mclk),
+ FUNCTION(cci_async),
+ FUNCTION(cci_i2c),
+ FUNCTION(cci_timer0),
+ FUNCTION(cci_timer1),
+ FUNCTION(cci_timer2),
+ FUNCTION(cci_timer3),
+ FUNCTION(cci_timer4),
+ FUNCTION(cri_trng),
+ FUNCTION(dbg_out),
+ FUNCTION(ddr_bist),
+ FUNCTION(ddr_pxi0),
+ FUNCTION(ddr_pxi1),
+ FUNCTION(ddr_pxi2),
+ FUNCTION(ddr_pxi3),
+ FUNCTION(dp_hot),
+ FUNCTION(edp_lcd),
+ FUNCTION(gcc_gp1),
+ FUNCTION(gcc_gp2),
+ FUNCTION(gcc_gp3),
+ FUNCTION(gp_pdm0),
+ FUNCTION(gp_pdm1),
+ FUNCTION(gp_pdm2),
+ FUNCTION(gpio),
+ FUNCTION(gps_tx),
+ FUNCTION(ibi_i3c),
+ FUNCTION(jitter_bist),
+ FUNCTION(ldo_en),
+ FUNCTION(ldo_update),
+ FUNCTION(lpass_ext),
+ FUNCTION(m_voc),
+ FUNCTION(mclk),
+ FUNCTION(mdp_vsync),
+ FUNCTION(mdp_vsync0),
+ FUNCTION(mdp_vsync1),
+ FUNCTION(mdp_vsync2),
+ FUNCTION(mdp_vsync3),
+ FUNCTION(mi2s_0),
+ FUNCTION(mi2s_1),
+ FUNCTION(mi2s_2),
+ FUNCTION(mss_lte),
+ FUNCTION(nav_gpio),
+ FUNCTION(nav_pps),
+ FUNCTION(pa_indicator),
+ FUNCTION(phase_flag0),
+ FUNCTION(phase_flag1),
+ FUNCTION(phase_flag10),
+ FUNCTION(phase_flag11),
+ FUNCTION(phase_flag12),
+ FUNCTION(phase_flag13),
+ FUNCTION(phase_flag14),
+ FUNCTION(phase_flag15),
+ FUNCTION(phase_flag16),
+ FUNCTION(phase_flag17),
+ FUNCTION(phase_flag18),
+ FUNCTION(phase_flag19),
+ FUNCTION(phase_flag2),
+ FUNCTION(phase_flag20),
+ FUNCTION(phase_flag21),
+ FUNCTION(phase_flag22),
+ FUNCTION(phase_flag23),
+ FUNCTION(phase_flag24),
+ FUNCTION(phase_flag25),
+ FUNCTION(phase_flag26),
+ FUNCTION(phase_flag27),
+ FUNCTION(phase_flag28),
+ FUNCTION(phase_flag29),
+ FUNCTION(phase_flag3),
+ FUNCTION(phase_flag30),
+ FUNCTION(phase_flag31),
+ FUNCTION(phase_flag4),
+ FUNCTION(phase_flag5),
+ FUNCTION(phase_flag6),
+ FUNCTION(phase_flag7),
+ FUNCTION(phase_flag8),
+ FUNCTION(phase_flag9),
+ FUNCTION(pll_bist),
+ FUNCTION(pll_bypassnl),
+ FUNCTION(pll_clk),
+ FUNCTION(pll_reset),
+ FUNCTION(prng_rosc0),
+ FUNCTION(prng_rosc1),
+ FUNCTION(prng_rosc2),
+ FUNCTION(prng_rosc3),
+ FUNCTION(qdss_cti),
+ FUNCTION(qdss_gpio),
+ FUNCTION(qdss_gpio0),
+ FUNCTION(qdss_gpio1),
+ FUNCTION(qdss_gpio10),
+ FUNCTION(qdss_gpio11),
+ FUNCTION(qdss_gpio12),
+ FUNCTION(qdss_gpio13),
+ FUNCTION(qdss_gpio14),
+ FUNCTION(qdss_gpio15),
+ FUNCTION(qdss_gpio2),
+ FUNCTION(qdss_gpio3),
+ FUNCTION(qdss_gpio4),
+ FUNCTION(qdss_gpio5),
+ FUNCTION(qdss_gpio6),
+ FUNCTION(qdss_gpio7),
+ FUNCTION(qdss_gpio8),
+ FUNCTION(qdss_gpio9),
+ FUNCTION(qlink0_enable),
+ FUNCTION(qlink0_request),
+ FUNCTION(qlink0_wmss),
+ FUNCTION(qlink1_enable),
+ FUNCTION(qlink1_request),
+ FUNCTION(qlink1_wmss),
+ FUNCTION(qup00),
+ FUNCTION(qup01),
+ FUNCTION(qup02),
+ FUNCTION(qup10),
+ FUNCTION(qup11_f1),
+ FUNCTION(qup11_f2),
+ FUNCTION(qup12),
+ FUNCTION(qup13_f1),
+ FUNCTION(qup13_f2),
+ FUNCTION(qup14),
+ FUNCTION(sd_write),
+ FUNCTION(sdc1_tb),
+ FUNCTION(sdc2_tb),
+ FUNCTION(sp_cmu),
+ FUNCTION(tgu_ch0),
+ FUNCTION(tgu_ch1),
+ FUNCTION(tgu_ch2),
+ FUNCTION(tgu_ch3),
+ FUNCTION(tsense_pwm1),
+ FUNCTION(tsense_pwm2),
+ FUNCTION(uim1_clk),
+ FUNCTION(uim1_data),
+ FUNCTION(uim1_present),
+ FUNCTION(uim1_reset),
+ FUNCTION(uim2_clk),
+ FUNCTION(uim2_data),
+ FUNCTION(uim2_present),
+ FUNCTION(uim2_reset),
+ FUNCTION(usb2phy_ac),
+ FUNCTION(usb_phy),
+ FUNCTION(vfr_1),
+ FUNCTION(vsense_trigger),
+ FUNCTION(wlan1_adc0),
+ FUNCTION(wlan1_adc1),
+ FUNCTION(wlan2_adc0),
+ FUNCTION(wlan2_adc1),
+};
+
+/*
+ * Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
+static const struct msm_pingroup sm6375_groups[] = {
+ [0] = PINGROUP(0, ibi_i3c, qup00, cri_trng, _, _, _, _, _, _),
+ [1] = PINGROUP(1, ibi_i3c, qup00, cri_trng, _, _, _, _, _, _),
+ [2] = PINGROUP(2, qup00, cci_i2c, cri_trng, qdss_cti, _, _, _, _, _),
+ [3] = PINGROUP(3, qup00, cci_i2c, sp_cmu, dbg_out, qdss_cti, _, _, _, _),
+ [4] = PINGROUP(4, qup14, qup14, sdc1_tb, _, _, _, _, _, _),
+ [5] = PINGROUP(5, qup14, qup14, sdc2_tb, _, _, _, _, _, _),
+ [6] = PINGROUP(6, mdp_vsync, qdss_cti, _, _, _, _, _, _, _),
+ [7] = PINGROUP(7, qdss_cti, _, _, _, _, _, _, _, _),
+ [8] = PINGROUP(8, gp_pdm1, qdss_gpio, _, _, _, _, _, _, _),
+ [9] = PINGROUP(9, qdss_gpio, _, _, _, _, _, _, _, _),
+ [10] = PINGROUP(10, _, _, _, _, _, _, _, _, _),
+ [11] = PINGROUP(11, _, _, _, _, _, _, _, _, _),
+ [12] = PINGROUP(12, m_voc, dp_hot, _, phase_flag0, _, _, _, _, _),
+ [13] = PINGROUP(13, qup10, pll_bypassnl, _, _, _, _, _, _, _),
+ [14] = PINGROUP(14, qup10, pll_reset, _, _, _, _, _, _, _),
+ [15] = PINGROUP(15, qup10, _, _, _, _, _, _, _, _),
+ [16] = PINGROUP(16, qup10, _, _, _, _, _, _, _, _),
+ [17] = PINGROUP(17, _, phase_flag1, qup10, _, _, _, _, _, _),
+ [18] = PINGROUP(18, _, phase_flag2, _, _, _, _, _, _, _),
+ [19] = PINGROUP(19, qup12, qup12, ddr_bist, _, _, _, _, _, _),
+ [20] = PINGROUP(20, qup12, qup12, ddr_bist, _, _, _, _, _, _),
+ [21] = PINGROUP(21, gcc_gp2, ddr_bist, _, _, _, _, _, _, _),
+ [22] = PINGROUP(22, gcc_gp3, ddr_bist, _, _, _, _, _, _, _),
+ [23] = PINGROUP(23, mdp_vsync, edp_lcd, _, _, _, _, _, _, _),
+ [24] = PINGROUP(24, mdp_vsync, _, _, _, _, _, _, _, _),
+ [25] = PINGROUP(25, qup13_f1, qup13_f2, _, _, _, _, _, _, _),
+ [26] = PINGROUP(26, qup13_f1, qup13_f2, _, _, _, _, _, _, _),
+ [27] = PINGROUP(27, qup11_f1, qup11_f2, mdp_vsync, pll_bist, _, qdss_gpio14, _, _, _),
+ [28] = PINGROUP(28, qup11_f1, qup11_f2, mdp_vsync, _, qdss_gpio15, _, _, _, _),
+ [29] = PINGROUP(29, cam_mclk, _, _, _, _, _, _, _, _),
+ [30] = PINGROUP(30, cam_mclk, _, _, _, _, _, _, _, _),
+ [31] = PINGROUP(31, cam_mclk, _, _, _, _, _, _, _, _),
+ [32] = PINGROUP(32, cam_mclk, _, _, _, _, _, _, _, _),
+ [33] = PINGROUP(33, cam_mclk, _, _, _, _, _, _, _, _),
+ [34] = PINGROUP(34, cci_timer0, _, phase_flag3, qdss_gpio12, _, _, _, _, _),
+ [35] = PINGROUP(35, cci_timer1, cci_async, _, phase_flag4, qdss_gpio13, _, _, _, _),
+ [36] = PINGROUP(36, cci_timer2, cci_async, _, phase_flag5, qdss_gpio14, _, _, _, _),
+ [37] = PINGROUP(37, cci_timer3, gp_pdm0, _, phase_flag6, qdss_gpio15, _, _, _, _),
+ [38] = PINGROUP(38, cci_timer4, _, phase_flag7, qdss_gpio2, _, _, _, _, _),
+ [39] = PINGROUP(39, cci_i2c, _, phase_flag8, qdss_gpio0, _, _, _, _, _),
+ [40] = PINGROUP(40, cci_i2c, _, phase_flag9, qdss_gpio1, _, _, _, _, _),
+ [41] = PINGROUP(41, cci_i2c, _, phase_flag10, qdss_gpio2, _, _, _, _, _),
+ [42] = PINGROUP(42, cci_i2c, _, phase_flag11, qdss_gpio3, _, _, _, _, _),
+ [43] = PINGROUP(43, cci_i2c, _, phase_flag12, qdss_gpio4, _, _, _, _, _),
+ [44] = PINGROUP(44, cci_i2c, _, phase_flag13, qdss_gpio5, _, _, _, _, _),
+ [45] = PINGROUP(45, qup02, _, phase_flag14, qdss_gpio6, _, _, _, _, _),
+ [46] = PINGROUP(46, qup02, _, phase_flag15, qdss_gpio7, _, _, _, _, _),
+ [47] = PINGROUP(47, mdp_vsync0, _, phase_flag16, qdss_gpio3, _, _, usb2phy_ac, _, _),
+ [48] = PINGROUP(48, cci_async, mdp_vsync1, gcc_gp1, _, phase_flag17, qdss_gpio8, qup02,
+ _, _),
+ [49] = PINGROUP(49, vfr_1, _, phase_flag18, qdss_gpio9, _, _, _, _, _),
+ [50] = PINGROUP(50, _, phase_flag19, qdss_gpio10, _, _, _, _, _, _),
+ [51] = PINGROUP(51, _, phase_flag20, qdss_gpio11, _, _, _, _, _, _),
+ [52] = PINGROUP(52, cci_async, gp_pdm1, _, phase_flag21, qdss_gpio12, _, _, _, _),
+ [53] = PINGROUP(53, cci_async, _, phase_flag22, qdss_gpio13, _, _, _, _, _),
+ [54] = PINGROUP(54, _, _, _, _, _, _, _, _, _),
+ [55] = PINGROUP(55, _, _, _, _, _, _, _, _, _),
+ [56] = PINGROUP(56, qup02, mdp_vsync2, _, phase_flag23, qdss_gpio10, _, _, _, _),
+ [57] = PINGROUP(57, qup02, mdp_vsync3, gp_pdm2, _, phase_flag24, qdss_gpio11, _, _, _),
+ [58] = PINGROUP(58, gcc_gp1, _, _, _, _, _, _, _, _),
+ [59] = PINGROUP(59, _, _, _, _, _, _, _, _, _),
+ [60] = PINGROUP(60, audio_ref, lpass_ext, mi2s_2, _, phase_flag25, _, _, _, _),
+ [61] = PINGROUP(61, qup01, tgu_ch0, _, phase_flag26, qdss_cti, _, _, _, _),
+ [62] = PINGROUP(62, qup01, tgu_ch1, _, phase_flag27, qdss_cti, _, _, _, _),
+ [63] = PINGROUP(63, qup01, tgu_ch2, _, phase_flag28, qdss_gpio, _, _, _, _),
+ [64] = PINGROUP(64, qup01, tgu_ch3, _, phase_flag29, qdss_gpio, _, _, _, _),
+ [65] = PINGROUP(65, mss_lte, _, qdss_gpio0, _, _, _, _, _, _),
+ [66] = PINGROUP(66, mss_lte, _, qdss_gpio1, _, _, _, _, _, _),
+ [67] = PINGROUP(67, btfm_slimbus, mi2s_1, _, phase_flag30, _, _, _, _, _),
+ [68] = PINGROUP(68, btfm_slimbus, mi2s_1, gp_pdm0, _, phase_flag31, _, _, _, _),
+ [69] = PINGROUP(69, _, _, _, _, _, _, _, _, _),
+ [70] = PINGROUP(70, _, _, _, _, _, _, _, _, _),
+ [71] = PINGROUP(71, _, _, _, _, _, _, _, _, _),
+ [72] = PINGROUP(72, _, _, _, _, _, _, _, _, _),
+ [73] = PINGROUP(73, _, _, _, _, _, _, _, _, _),
+ [74] = PINGROUP(74, _, _, _, _, _, _, _, _, _),
+ [75] = PINGROUP(75, uim2_data, _, _, _, _, _, _, _, _),
+ [76] = PINGROUP(76, uim2_clk, _, _, _, _, _, _, _, _),
+ [77] = PINGROUP(77, uim2_reset, _, _, _, _, _, _, _, _),
+ [78] = PINGROUP(78, uim2_present, _, _, _, _, _, _, _, _),
+ [79] = PINGROUP(79, uim1_data, _, _, _, _, _, _, _, _),
+ [80] = PINGROUP(80, uim1_clk, _, _, _, _, _, _, _, _),
+ [81] = PINGROUP(81, uim1_reset, _, _, _, _, _, _, _, _),
+ [82] = PINGROUP(82, uim1_present, _, _, _, _, _, _, _, _),
+ [83] = PINGROUP(83, atest_usb1, _, _, _, _, _, _, _, _),
+ [84] = PINGROUP(84, _, atest_usb10, _, _, _, _, _, _, _),
+ [85] = PINGROUP(85, sd_write, _, atest_usb11, _, _, _, _, _, _),
+ [86] = PINGROUP(86, btfm_slimbus, mi2s_1, _, qdss_cti, atest_usb12, ddr_pxi0, _, _, _),
+ [87] = PINGROUP(87, btfm_slimbus, mi2s_1, adsp_ext, _, qdss_cti, atest_usb13, ddr_pxi1, _,
+ _),
+ [88] = PINGROUP(88, mi2s_0, _, qdss_gpio4, _, atest_usb2, ddr_pxi2, tsense_pwm1,
+ tsense_pwm2, _),
+ [89] = PINGROUP(89, mi2s_0, agera_pll, _, qdss_gpio5, _, vsense_trigger, atest_usb20,
+ ddr_pxi3, _),
+ [90] = PINGROUP(90, mi2s_0, jitter_bist, _, qdss_gpio6, _, wlan1_adc0, atest_usb21,
+ ddr_pxi0, _),
+ [91] = PINGROUP(91, mi2s_0, _, qdss_gpio7, _, wlan2_adc0, atest_usb22, ddr_pxi1, _, _),
+ [92] = PINGROUP(92, _, qdss_gpio8, atest_tsens, wlan1_adc1, atest_usb23, ddr_pxi2, _, _,
+ _),
+ [93] = PINGROUP(93, mclk, lpass_ext, _, qdss_gpio9, atest_tsens2, wlan2_adc1, ddr_pxi3,
+ _, _),
+ [94] = PINGROUP(94, _, _, _, _, _, _, _, _, _),
+ [95] = PINGROUP(95, ldo_en, _, atest_char, _, _, _, _, _, _),
+ [96] = PINGROUP(96, ldo_update, _, atest_char0, _, _, _, _, _, _),
+ [97] = PINGROUP(97, prng_rosc0, _, atest_char1, _, _, _, _, _, _),
+ [98] = PINGROUP(98, _, atest_char2, _, _, prng_rosc1, pll_clk, _, _, _),
+ [99] = PINGROUP(99, _, atest_char3, _, _, prng_rosc2, _, _, _, _),
+ [100] = PINGROUP(100, _, _, prng_rosc3, _, _, _, _, _, _),
+ [101] = PINGROUP(101, nav_gpio, nav_pps, nav_pps, gps_tx, _, _, _, _, _),
+ [102] = PINGROUP(102, nav_gpio, nav_pps, nav_pps, gps_tx, _, _, _, _, _),
+ [103] = PINGROUP(103, qlink0_wmss, _, _, _, _, _, _, _, _),
+ [104] = PINGROUP(104, qlink0_request, _, _, _, _, _, _, _, _),
+ [105] = PINGROUP(105, qlink0_enable, _, _, _, _, _, _, _, _),
+ [106] = PINGROUP(106, qlink1_wmss, _, _, _, _, _, _, _, _),
+ [107] = PINGROUP(107, qlink1_request, gps_tx, _, _, _, _, _, _, _),
+ [108] = PINGROUP(108, qlink1_enable, gps_tx, _, _, _, _, _, _, _),
+ [109] = PINGROUP(109, _, _, _, _, _, _, _, _, _),
+ [110] = PINGROUP(110, _, _, _, _, _, _, _, _, _),
+ [111] = PINGROUP(111, _, _, _, _, _, _, _, _, _),
+ [112] = PINGROUP(112, _, _, _, _, _, _, _, _, _),
+ [113] = PINGROUP(113, _, _, _, _, _, _, _, _, _),
+ [114] = PINGROUP(114, _, _, _, _, _, _, _, _, _),
+ [115] = PINGROUP(115, _, _, _, _, _, _, _, _, _),
+ [116] = PINGROUP(116, _, _, _, _, _, _, _, _, _),
+ [117] = PINGROUP(117, _, _, _, _, _, _, _, _, _),
+ [118] = PINGROUP(118, _, _, pa_indicator, dp_hot, _, _, _, _, _),
+ [119] = PINGROUP(119, _, _, _, _, _, _, _, _, _),
+ [120] = PINGROUP(120, _, _, _, _, _, _, _, _, _),
+ [121] = PINGROUP(121, _, _, _, _, _, _, _, _, _),
+ [122] = PINGROUP(122, _, _, _, _, _, _, _, _, _),
+ [123] = PINGROUP(123, _, _, _, _, _, _, _, _, _),
+ [124] = PINGROUP(124, usb_phy, _, _, _, _, _, _, _, _),
+ [125] = PINGROUP(125, _, _, _, _, _, _, _, _, _),
+ [126] = PINGROUP(126, _, _, _, _, _, _, _, _, _),
+ [127] = PINGROUP(127, _, _, _, _, _, _, _, _, _),
+ [128] = PINGROUP(128, _, _, _, _, _, _, _, _, _),
+ [129] = PINGROUP(129, _, _, _, _, _, _, _, _, _),
+ [130] = PINGROUP(130, _, _, _, _, _, _, _, _, _),
+ [131] = PINGROUP(131, _, _, _, _, _, _, _, _, _),
+ [132] = PINGROUP(132, _, _, _, _, _, _, _, _, _),
+ [133] = PINGROUP(133, _, _, _, _, _, _, _, _, _),
+ [134] = PINGROUP(134, _, _, _, _, _, _, _, _, _),
+ [135] = PINGROUP(135, _, _, _, _, _, _, _, _, _),
+ [136] = PINGROUP(136, _, _, _, _, _, _, _, _, _),
+ [137] = PINGROUP(137, _, _, _, _, _, _, _, _, _),
+ [138] = PINGROUP(138, _, _, _, _, _, _, _, _, _),
+ [139] = PINGROUP(139, _, _, _, _, _, _, _, _, _),
+ [140] = PINGROUP(140, _, _, _, _, _, _, _, _, _),
+ [141] = PINGROUP(141, _, _, _, _, _, _, _, _, _),
+ [142] = PINGROUP(142, _, _, _, _, _, _, _, _, _),
+ [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _),
+ [144] = PINGROUP(144, _, _, _, _, _, _, _, _, _),
+ [145] = PINGROUP(145, _, _, _, _, _, _, _, _, _),
+ [146] = PINGROUP(146, _, _, _, _, _, _, _, _, _),
+ [147] = PINGROUP(147, _, _, _, _, _, _, _, _, _),
+ [148] = PINGROUP(148, _, _, _, _, _, _, _, _, _),
+ [149] = PINGROUP(149, _, _, _, _, _, _, _, _, _),
+ [150] = PINGROUP(150, _, _, _, _, _, _, _, _, _),
+ [151] = PINGROUP(151, _, _, _, _, _, _, _, _, _),
+ [152] = PINGROUP(152, _, _, _, _, _, _, _, _, _),
+ [153] = PINGROUP(153, _, _, _, _, _, _, _, _, _),
+ [154] = PINGROUP(154, _, _, _, _, _, _, _, _, _),
+ [155] = PINGROUP(155, _, _, _, _, _, _, _, _, _),
+ [156] = UFS_RESET(ufs_reset, 0x1ae000),
+ [157] = SDC_PINGROUP(sdc1_rclk, 0x1a1000, 0, 0),
+ [158] = SDC_PINGROUP(sdc1_clk, 0x1a0000, 13, 6),
+ [159] = SDC_PINGROUP(sdc1_cmd, 0x1a0000, 11, 3),
+ [160] = SDC_PINGROUP(sdc1_data, 0x1a0000, 9, 0),
+ [161] = SDC_PINGROUP(sdc2_clk, 0x1a2000, 14, 6),
+ [162] = SDC_PINGROUP(sdc2_cmd, 0x1a2000, 11, 3),
+ [163] = SDC_PINGROUP(sdc2_data, 0x1a2000, 9, 0),
+};
+
+static const struct msm_gpio_wakeirq_map sm6375_mpm_map[] = {
+ { 0, 84 }, { 3, 6 }, { 4, 7 }, { 7, 8 }, { 8, 9 }, { 9, 10 }, { 11, 11 }, { 12, 13 },
+ { 13, 14 }, { 16, 16 }, { 17, 17 }, { 18, 18 }, { 19, 19 }, { 21, 20 }, { 22, 21 },
+ { 23, 23 }, { 24, 24 }, { 25, 25 }, { 27, 26 }, { 28, 27 }, { 37, 28 }, { 38, 29 },
+ { 48, 30 }, { 50, 31 }, { 51, 32 }, { 52, 33 }, { 57, 34 }, { 59, 35 }, { 60, 37 },
+ { 61, 38 }, { 62, 39 }, { 64, 40 }, { 66, 41 }, { 67, 42 }, { 68, 43 }, { 69, 44 },
+ { 78, 45 }, { 82, 36 }, { 83, 47 }, { 84, 48 }, { 85, 49 }, { 87, 50 }, { 88, 51 },
+ { 91, 52 }, { 94, 53 }, { 95, 54 }, { 96, 55 }, { 97, 56 }, { 98, 57 }, { 99, 58 },
+ { 100, 59 }, { 104, 60 }, { 107, 61 }, { 118, 62 }, { 124, 63 }, { 125, 64 }, { 126, 65 },
+ { 128, 66 }, { 129, 67 }, { 131, 69 }, { 133, 70 }, { 134, 71 }, { 136, 73 }, { 142, 74 },
+ { 150, 75 }, { 153, 76 }, { 155, 77 },
+};
+
+static const struct msm_pinctrl_soc_data sm6375_tlmm = {
+ .pins = sm6375_pins,
+ .npins = ARRAY_SIZE(sm6375_pins),
+ .functions = sm6375_functions,
+ .nfunctions = ARRAY_SIZE(sm6375_functions),
+ .groups = sm6375_groups,
+ .ngroups = ARRAY_SIZE(sm6375_groups),
+ .ngpios = 157,
+ .wakeirq_map = sm6375_mpm_map,
+ .nwakeirq_map = ARRAY_SIZE(sm6375_mpm_map),
+};
+
+static int sm6375_tlmm_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &sm6375_tlmm);
+}
+
+static const struct of_device_id sm6375_tlmm_of_match[] = {
+ { .compatible = "qcom,sm6375-tlmm", },
+ { },
+};
+
+static struct platform_driver sm6375_tlmm_driver = {
+ .driver = {
+ .name = "sm6375-tlmm",
+ .of_match_table = sm6375_tlmm_of_match,
+ },
+ .probe = sm6375_tlmm_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init sm6375_tlmm_init(void)
+{
+ return platform_driver_register(&sm6375_tlmm_driver);
+}
+arch_initcall(sm6375_tlmm_init);
+
+static void __exit sm6375_tlmm_exit(void)
+{
+ platform_driver_unregister(&sm6375_tlmm_driver);
+}
+module_exit(sm6375_tlmm_exit);
+
+MODULE_DESCRIPTION("QTI SM6375 TLMM driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, sm6375_tlmm_of_match);
static const struct msm_gpio_wakeirq_map sm8250_pdc_map[] = {
{ 0, 79 }, { 1, 84 }, { 2, 80 }, { 3, 82 }, { 4, 107 }, { 7, 43 },
{ 11, 42 }, { 14, 44 }, { 15, 52 }, { 19, 67 }, { 23, 68 }, { 24, 105 },
- { 27, 92 }, { 28, 106 }, { 31, 69 }, { 35, 70 }, { 39, 37 },
+ { 27, 92 }, { 28, 106 }, { 31, 69 }, { 35, 70 }, { 39, 73 },
{ 40, 108 }, { 43, 71 }, { 45, 72 }, { 47, 83 }, { 51, 74 }, { 55, 77 },
{ 59, 78 }, { 63, 75 }, { 64, 81 }, { 65, 87 }, { 66, 88 }, { 67, 89 },
{ 68, 54 }, { 70, 85 }, { 77, 46 }, { 80, 90 }, { 81, 91 }, { 83, 97 },
/* pm8150l has 12 GPIOs with holes on 7 */
{ .compatible = "qcom,pm8150l-gpio", .data = (void *) 12 },
{ .compatible = "qcom,pmc8180c-gpio", .data = (void *) 12 },
+ { .compatible = "qcom,pm8226-gpio", .data = (void *) 8 },
{ .compatible = "qcom,pm8350-gpio", .data = (void *) 10 },
{ .compatible = "qcom,pm8350b-gpio", .data = (void *) 8 },
{ .compatible = "qcom,pm8350c-gpio", .data = (void *) 9 },
{ .compatible = "qcom,pmi8998-gpio", .data = (void *) 14 },
{ .compatible = "qcom,pmk8350-gpio", .data = (void *) 4 },
{ .compatible = "qcom,pmm8155au-gpio", .data = (void *) 10 },
+ /* pmp8074 has 12 GPIOs with holes on 1 and 12 */
+ { .compatible = "qcom,pmp8074-gpio", .data = (void *) 12 },
{ .compatible = "qcom,pmr735a-gpio", .data = (void *) 4 },
{ .compatible = "qcom,pmr735b-gpio", .data = (void *) 4 },
/* pms405 has 12 GPIOs with holes on 1, 9, and 10 */
select PINCTRL_PFC_R8A77995 if ARCH_R8A77995
select PINCTRL_PFC_R8A779A0 if ARCH_R8A779A0
select PINCTRL_PFC_R8A779F0 if ARCH_R8A779F0
+ select PINCTRL_PFC_R8A779G0 if ARCH_R8A779G0
select PINCTRL_RZG2L if ARCH_RZG2L
+ select PINCTRL_RZV2M if ARCH_R9A09G011
select PINCTRL_PFC_SH7203 if CPU_SUBTYPE_SH7203
select PINCTRL_PFC_SH7264 if CPU_SUBTYPE_SH7264
select PINCTRL_PFC_SH7269 if CPU_SUBTYPE_SH7269
bool "pin control support for R-Car V3U" if COMPILE_TEST
select PINCTRL_SH_PFC
+config PINCTRL_PFC_R8A779G0
+ bool "pin control support for R-Car V4H" if COMPILE_TEST
+ select PINCTRL_SH_PFC
+
config PINCTRL_PFC_R8A7740
bool "pin control support for R-Mobile A1" if COMPILE_TEST
select PINCTRL_SH_PFC_GPIO
help
This selects pinctrl driver for Renesas RZ/N1 devices.
+config PINCTRL_RZV2M
+ bool "pin control support for RZ/V2M"
+ depends on OF
+ depends on ARCH_R9A09G011 || COMPILE_TEST
+ select GPIOLIB
+ select GENERIC_PINCTRL_GROUPS
+ select GENERIC_PINMUX_FUNCTIONS
+ select GENERIC_PINCONF
+ help
+ This selects GPIO and pinctrl driver for Renesas RZ/V2M
+ platforms.
+
config PINCTRL_PFC_SH7203
bool "pin control support for SH7203" if COMPILE_TEST
select PINCTRL_SH_FUNC_GPIO
obj-$(CONFIG_PINCTRL_PFC_R8A77995) += pfc-r8a77995.o
obj-$(CONFIG_PINCTRL_PFC_R8A779A0) += pfc-r8a779a0.o
obj-$(CONFIG_PINCTRL_PFC_R8A779F0) += pfc-r8a779f0.o
+obj-$(CONFIG_PINCTRL_PFC_R8A779G0) += pfc-r8a779g0.o
obj-$(CONFIG_PINCTRL_PFC_SH7203) += pfc-sh7203.o
obj-$(CONFIG_PINCTRL_PFC_SH7264) += pfc-sh7264.o
obj-$(CONFIG_PINCTRL_PFC_SH7269) += pfc-sh7269.o
obj-$(CONFIG_PINCTRL_RZA2) += pinctrl-rza2.o
obj-$(CONFIG_PINCTRL_RZG2L) += pinctrl-rzg2l.o
obj-$(CONFIG_PINCTRL_RZN1) += pinctrl-rzn1.o
+obj-$(CONFIG_PINCTRL_RZV2M) += pinctrl-rzv2m.o
ifeq ($(CONFIG_COMPILE_TEST),y)
CFLAGS_pfc-sh7203.o += -I$(srctree)/arch/sh/include/cpu-sh2a
.data = &r8a779f0_pinmux_info,
},
#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A779G0
+ {
+ .compatible = "renesas,pfc-r8a779g0",
+ .data = &r8a779g0_pinmux_info,
+ },
+#endif
#ifdef CONFIG_PINCTRL_PFC_SH73A0
{
.compatible = "renesas,pfc-sh73a0",
enum ioctrl_regs {
POC0,
POC1,
- POC2,
POC3,
TD0SEL1,
};
static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = {
[POC0] = { 0xe60500a0, },
[POC1] = { 0xe60508a0, },
- [POC2] = { 0xe60510a0, },
[POC3] = { 0xe60518a0, },
[TD0SEL1] = { 0xe6050920, },
{ /* sentinel */ },
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * R8A779A0 processor support - PFC hardware block.
+ *
+ * Copyright (C) 2021 Renesas Electronics Corp.
+ *
+ * This file is based on the drivers/pinctrl/renesas/pfc-r8a779a0.c
+ */
+
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+
+#include "sh_pfc.h"
+
+#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN)
+
+#define CPU_ALL_GP(fn, sfx) \
+ PORT_GP_CFG_19(0, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33), \
+ PORT_GP_CFG_23(1, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33), \
+ PORT_GP_CFG_1(1, 23, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(1, 24, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(1, 25, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(1, 26, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(1, 27, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(1, 28, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_20(2, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_13(3, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33), \
+ PORT_GP_CFG_1(3, 13, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 14, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 15, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 16, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 17, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 18, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 19, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 20, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 21, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 22, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 23, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 24, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 25, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 26, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 27, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 28, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(3, 29, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_25(4, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_21(5, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_21(6, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_21(7, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_14(8, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33)
+
+/* GPSR0 */
+#define GPSR0_18 F_(MSIOF2_RXD, IP2SR0_11_8)
+#define GPSR0_17 F_(MSIOF2_SCK, IP2SR0_7_4)
+#define GPSR0_16 F_(MSIOF2_TXD, IP2SR0_3_0)
+#define GPSR0_15 F_(MSIOF2_SYNC, IP1SR0_31_28)
+#define GPSR0_14 F_(MSIOF2_SS1, IP1SR0_27_24)
+#define GPSR0_13 F_(MSIOF2_SS2, IP1SR0_23_20)
+#define GPSR0_12 F_(MSIOF5_RXD, IP1SR0_19_16)
+#define GPSR0_11 F_(MSIOF5_SCK, IP1SR0_15_12)
+#define GPSR0_10 F_(MSIOF5_TXD, IP1SR0_11_8)
+#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_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_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)
+#define GPSR1_20 F_(SSI_SD, IP2SR1_19_16)
+#define GPSR1_19 F_(SSI_WS, IP2SR1_15_12)
+#define GPSR1_18 F_(SSI_SCK, IP2SR1_11_8)
+#define GPSR1_17 F_(SCIF_CLK, IP2SR1_7_4)
+#define GPSR1_16 F_(HRX0, IP2SR1_3_0)
+#define GPSR1_15 F_(HSCK0, IP1SR1_31_28)
+#define GPSR1_14 F_(HRTS0_N, IP1SR1_27_24)
+#define GPSR1_13 F_(HCTS0_N, IP1SR1_23_20)
+#define GPSR1_12 F_(HTX0, IP1SR1_19_16)
+#define GPSR1_11 F_(MSIOF0_RXD, IP1SR1_15_12)
+#define GPSR1_10 F_(MSIOF0_SCK, IP1SR1_11_8)
+#define GPSR1_9 F_(MSIOF0_TXD, IP1SR1_7_4)
+#define GPSR1_8 F_(MSIOF0_SYNC, IP1SR1_3_0)
+#define GPSR1_7 F_(MSIOF0_SS1, IP0SR1_31_28)
+#define GPSR1_6 F_(MSIOF0_SS2, IP0SR1_27_24)
+#define GPSR1_5 F_(MSIOF1_RXD, IP0SR1_23_20)
+#define GPSR1_4 F_(MSIOF1_TXD, IP0SR1_19_16)
+#define GPSR1_3 F_(MSIOF1_SCK, IP0SR1_15_12)
+#define GPSR1_2 F_(MSIOF1_SYNC, IP0SR1_11_8)
+#define GPSR1_1 F_(MSIOF1_SS1, IP0SR1_7_4)
+#define GPSR1_0 F_(MSIOF1_SS2, IP0SR1_3_0)
+
+/* GPSR2 */
+#define GPSR2_19 F_(CANFD7_RX, IP2SR2_15_12)
+#define GPSR2_18 F_(CANFD7_TX, IP2SR2_11_8)
+#define GPSR2_17 F_(CANFD4_RX, IP2SR2_7_4)
+#define GPSR2_16 F_(CANFD4_TX, IP2SR2_3_0)
+#define GPSR2_15 F_(CANFD3_RX, IP1SR2_31_28)
+#define GPSR2_14 F_(CANFD3_TX, IP1SR2_27_24)
+#define GPSR2_13 F_(CANFD2_RX, IP1SR2_23_20)
+#define GPSR2_12 F_(CANFD2_TX, IP1SR2_19_16)
+#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_6 F_(FXR_TXDB, IP0SR2_27_24)
+#define GPSR2_5 F_(FXR_TXENB_N, 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_0 F_(FXR_TXDA, IP0SR2_3_0)
+
+/* GPSR3 */
+#define GPSR3_29 F_(RPC_INT_N, IP3SR3_23_20)
+#define GPSR3_28 F_(RPC_WP_N, IP3SR3_19_16)
+#define GPSR3_27 F_(RPC_RESET_N, IP3SR3_15_12)
+#define GPSR3_26 F_(QSPI1_IO3, IP3SR3_11_8)
+#define GPSR3_25 F_(QSPI1_SSL, IP3SR3_7_4)
+#define GPSR3_24 F_(QSPI1_IO2, IP3SR3_3_0)
+#define GPSR3_23 F_(QSPI1_MISO_IO1, IP2SR3_31_28)
+#define GPSR3_22 F_(QSPI1_SPCLK, IP2SR3_27_24)
+#define GPSR3_21 F_(QSPI1_MOSI_IO0, IP2SR3_23_20)
+#define GPSR3_20 F_(QSPI0_SPCLK, IP2SR3_19_16)
+#define GPSR3_19 F_(QSPI0_MOSI_IO0, IP2SR3_15_12)
+#define GPSR3_18 F_(QSPI0_MISO_IO1, IP2SR3_11_8)
+#define GPSR3_17 F_(QSPI0_IO2, IP2SR3_7_4)
+#define GPSR3_16 F_(QSPI0_IO3, IP2SR3_3_0)
+#define GPSR3_15 F_(QSPI0_SSL, IP1SR3_31_28)
+#define GPSR3_14 F_(IPC_CLKOUT, IP1SR3_27_24)
+#define GPSR3_13 F_(IPC_CLKIN, IP1SR3_23_20)
+#define GPSR3_12 F_(SD_WP, IP1SR3_19_16)
+#define GPSR3_11 F_(SD_CD, IP1SR3_15_12)
+#define GPSR3_10 F_(MMC_SD_CMD, IP1SR3_11_8)
+#define GPSR3_9 F_(MMC_D6, IP1SR3_7_4)
+#define GPSR3_8 F_(MMC_D7, IP1SR3_3_0)
+#define GPSR3_7 F_(MMC_D4, IP0SR3_31_28)
+#define GPSR3_6 F_(MMC_D5, IP0SR3_27_24)
+#define GPSR3_5 F_(MMC_SD_D3, IP0SR3_23_20)
+#define GPSR3_4 F_(MMC_DS, IP0SR3_19_16)
+#define GPSR3_3 F_(MMC_SD_CLK, IP0SR3_15_12)
+#define GPSR3_2 F_(MMC_SD_D2, IP0SR3_11_8)
+#define GPSR3_1 F_(MMC_SD_D0, IP0SR3_7_4)
+#define GPSR3_0 F_(MMC_SD_D1, IP0SR3_3_0)
+
+/* GPSR4 */
+#define GPSR4_24 FM(AVS1)
+#define GPSR4_23 FM(AVS0)
+#define GPSR4_22 FM(PCIE1_CLKREQ_N)
+#define GPSR4_21 FM(PCIE0_CLKREQ_N)
+#define GPSR4_20 FM(TSN0_TXCREFCLK)
+#define GPSR4_19 FM(TSN0_TD2)
+#define GPSR4_18 FM(TSN0_TD3)
+#define GPSR4_17 FM(TSN0_RD2)
+#define GPSR4_16 FM(TSN0_RD3)
+#define GPSR4_15 FM(TSN0_TD0)
+#define GPSR4_14 FM(TSN0_TD1)
+#define GPSR4_13 FM(TSN0_RD1)
+#define GPSR4_12 FM(TSN0_TXC)
+#define GPSR4_11 FM(TSN0_RXC)
+#define GPSR4_10 FM(TSN0_RD0)
+#define GPSR4_9 FM(TSN0_TX_CTL)
+#define GPSR4_8 FM(TSN0_AVTP_PPS0)
+#define GPSR4_7 FM(TSN0_RX_CTL)
+#define GPSR4_6 FM(TSN0_AVTP_CAPTURE)
+#define GPSR4_5 FM(TSN0_AVTP_MATCH)
+#define GPSR4_4 FM(TSN0_LINK)
+#define GPSR4_3 FM(TSN0_PHY_INT)
+#define GPSR4_2 FM(TSN0_AVTP_PPS1)
+#define GPSR4_1 FM(TSN0_MDC)
+#define GPSR4_0 FM(TSN0_MDIO)
+
+/* GPSR 5 */
+#define GPSR5_20 FM(AVB2_RX_CTL)
+#define GPSR5_19 FM(AVB2_TX_CTL)
+#define GPSR5_18 FM(AVB2_RXC)
+#define GPSR5_17 FM(AVB2_RD0)
+#define GPSR5_16 FM(AVB2_TXC)
+#define GPSR5_15 FM(AVB2_TD0)
+#define GPSR5_14 FM(AVB2_RD1)
+#define GPSR5_13 FM(AVB2_RD2)
+#define GPSR5_12 FM(AVB2_TD1)
+#define GPSR5_11 FM(AVB2_TD2)
+#define GPSR5_10 FM(AVB2_MDIO)
+#define GPSR5_9 FM(AVB2_RD3)
+#define GPSR5_8 FM(AVB2_TD3)
+#define GPSR5_7 FM(AVB2_TXCREFCLK)
+#define GPSR5_6 FM(AVB2_MDC)
+#define GPSR5_5 FM(AVB2_MAGIC)
+#define GPSR5_4 FM(AVB2_PHY_INT)
+#define GPSR5_3 FM(AVB2_LINK)
+#define GPSR5_2 FM(AVB2_AVTP_MATCH)
+#define GPSR5_1 FM(AVB2_AVTP_CAPTURE)
+#define GPSR5_0 FM(AVB2_AVTP_PPS)
+
+/* GPSR 6 */
+#define GPSR6_20 F_(AVB1_TXCREFCLK, IP2SR6_19_16)
+#define GPSR6_19 F_(AVB1_RD3, IP2SR6_15_12)
+#define GPSR6_18 F_(AVB1_TD3, IP2SR6_11_8)
+#define GPSR6_17 F_(AVB1_RD2, IP2SR6_7_4)
+#define GPSR6_16 F_(AVB1_TD2, IP2SR6_3_0)
+#define GPSR6_15 F_(AVB1_RD0, IP1SR6_31_28)
+#define GPSR6_14 F_(AVB1_RD1, IP1SR6_27_24)
+#define GPSR6_13 F_(AVB1_TD0, IP1SR6_23_20)
+#define GPSR6_12 F_(AVB1_TD1, IP1SR6_19_16)
+#define GPSR6_11 F_(AVB1_AVTP_CAPTURE, IP1SR6_15_12)
+#define GPSR6_10 F_(AVB1_AVTP_PPS, IP1SR6_11_8)
+#define GPSR6_9 F_(AVB1_RX_CTL, IP1SR6_7_4)
+#define GPSR6_8 F_(AVB1_RXC, IP1SR6_3_0)
+#define GPSR6_7 F_(AVB1_TX_CTL, IP0SR6_31_28)
+#define GPSR6_6 F_(AVB1_TXC, IP0SR6_27_24)
+#define GPSR6_5 F_(AVB1_AVTP_MATCH, IP0SR6_23_20)
+#define GPSR6_4 F_(AVB1_LINK, IP0SR6_19_16)
+#define GPSR6_3 F_(AVB1_PHY_INT, IP0SR6_15_12)
+#define GPSR6_2 F_(AVB1_MDC, IP0SR6_11_8)
+#define GPSR6_1 F_(AVB1_MAGIC, IP0SR6_7_4)
+#define GPSR6_0 F_(AVB1_MDIO, IP0SR6_3_0)
+
+/* GPSR7 */
+#define GPSR7_20 F_(AVB0_RX_CTL, IP2SR7_19_16)
+#define GPSR7_19 F_(AVB0_RXC, IP2SR7_15_12)
+#define GPSR7_18 F_(AVB0_RD0, IP2SR7_11_8)
+#define GPSR7_17 F_(AVB0_RD1, IP2SR7_7_4)
+#define GPSR7_16 F_(AVB0_TX_CTL, IP2SR7_3_0)
+#define GPSR7_15 F_(AVB0_TXC, IP1SR7_31_28)
+#define GPSR7_14 F_(AVB0_MDIO, IP1SR7_27_24)
+#define GPSR7_13 F_(AVB0_MDC, IP1SR7_23_20)
+#define GPSR7_12 F_(AVB0_RD2, IP1SR7_19_16)
+#define GPSR7_11 F_(AVB0_TD0, IP1SR7_15_12)
+#define GPSR7_10 F_(AVB0_MAGIC, IP1SR7_11_8)
+#define GPSR7_9 F_(AVB0_TXCREFCLK, IP1SR7_7_4)
+#define GPSR7_8 F_(AVB0_RD3, IP1SR7_3_0)
+#define GPSR7_7 F_(AVB0_TD1, IP0SR7_31_28)
+#define GPSR7_6 F_(AVB0_TD2, IP0SR7_27_24)
+#define GPSR7_5 F_(AVB0_PHY_INT, IP0SR7_23_20)
+#define GPSR7_4 F_(AVB0_LINK, IP0SR7_19_16)
+#define GPSR7_3 F_(AVB0_TD3, IP0SR7_15_12)
+#define GPSR7_2 F_(AVB0_AVTP_MATCH, IP0SR7_11_8)
+#define GPSR7_1 F_(AVB0_AVTP_CAPTURE, IP0SR7_7_4)
+#define GPSR7_0 F_(AVB0_AVTP_PPS, IP0SR7_3_0)
+
+/* GPSR8 */
+#define GPSR8_13 F_(GP8_13, IP1SR8_23_20)
+#define GPSR8_12 F_(GP8_12, IP1SR8_19_16)
+#define GPSR8_11 F_(SDA5, IP1SR8_15_12)
+#define GPSR8_10 F_(SCL5, IP1SR8_11_8)
+#define GPSR8_9 F_(SDA4, IP1SR8_7_4)
+#define GPSR8_8 F_(SCL4, IP1SR8_3_0)
+#define GPSR8_7 F_(SDA3, IP0SR8_31_28)
+#define GPSR8_6 F_(SCL3, IP0SR8_27_24)
+#define GPSR8_5 F_(SDA2, IP0SR8_23_20)
+#define GPSR8_4 F_(SCL2, IP0SR8_19_16)
+#define GPSR8_3 F_(SDA1, IP0SR8_15_12)
+#define GPSR8_2 F_(SCL1, IP0SR8_11_8)
+#define GPSR8_1 F_(SDA0, IP0SR8_7_4)
+#define GPSR8_0 F_(SCL0, IP0SR8_3_0)
+
+/* 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_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_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_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 */
+#define IP1SR0_3_0 FM(MSIOF5_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) F_(0, 0)
+#define IP1SR0_7_4 FM(MSIOF5_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) F_(0, 0)
+#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)
+
+/* 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)
+
+/* 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_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)
+
+/* 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_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)
+
+/* 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_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)
+
+/* 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)
+
+/* 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_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_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)
+
+/* 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_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_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 */
+#define IP2SR2_3_0 FM(CANFD4_TX) F_(0, 0) FM(PWM4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR2_7_4 FM(CANFD4_RX) F_(0, 0) FM(PWM5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR2_11_8 FM(CANFD7_TX) F_(0, 0) FM(PWM6) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR2_15_12 FM(CANFD7_RX) F_(0, 0) FM(PWM7) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* SR3 */
+/* IP0SR3 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define IP0SR3_3_0 FM(MMC_SD_D1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR3_7_4 FM(MMC_SD_D0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR3_11_8 FM(MMC_SD_D2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR3_15_12 FM(MMC_SD_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR3_19_16 FM(MMC_DS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR3_23_20 FM(MMC_SD_D3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR3_27_24 FM(MMC_D5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR3_31_28 FM(MMC_D4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP1SR3 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define IP1SR3_3_0 FM(MMC_D7) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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_7_4 FM(MMC_D6) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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_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_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_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 */
+#define IP2SR3_3_0 FM(QSPI0_IO3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR3_7_4 FM(QSPI0_IO2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR3_11_8 FM(QSPI0_MISO_IO1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR3_15_12 FM(QSPI0_MOSI_IO0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR3_19_16 FM(QSPI0_SPCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR3_23_20 FM(QSPI1_MOSI_IO0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR3_27_24 FM(QSPI1_SPCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR3_31_28 FM(QSPI1_MISO_IO1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP3SR3 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define IP3SR3_3_0 FM(QSPI1_IO2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP3SR3_7_4 FM(QSPI1_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)
+#define IP3SR3_11_8 FM(QSPI1_IO3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP3SR3_15_12 FM(RPC_RESET_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 IP3SR3_19_16 FM(RPC_WP_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 IP3SR3_23_20 FM(RPC_INT_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)
+
+/* SR6 */
+/* IP0SR6 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define IP0SR6_3_0 FM(AVB1_MDIO) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR6_7_4 FM(AVB1_MAGIC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR6_11_8 FM(AVB1_MDC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR6_15_12 FM(AVB1_PHY_INT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR6_19_16 FM(AVB1_LINK) FM(AVB1_MII_TX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR6_23_20 FM(AVB1_AVTP_MATCH) FM(AVB1_MII_RX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR6_27_24 FM(AVB1_TXC) FM(AVB1_MII_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR6_31_28 FM(AVB1_TX_CTL) FM(AVB1_MII_TX_EN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP1SR6 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define IP1SR6_3_0 FM(AVB1_RXC) FM(AVB1_MII_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR6_7_4 FM(AVB1_RX_CTL) FM(AVB1_MII_RX_DV) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR6_11_8 FM(AVB1_AVTP_PPS) FM(AVB1_MII_COL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR6_15_12 FM(AVB1_AVTP_CAPTURE) FM(AVB1_MII_CRS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR6_19_16 FM(AVB1_TD1) FM(AVB1_MII_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR6_23_20 FM(AVB1_TD0) FM(AVB1_MII_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR6_27_24 FM(AVB1_RD1) FM(AVB1_MII_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR6_31_28 FM(AVB1_RD0) FM(AVB1_MII_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP2SR6 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define IP2SR6_3_0 FM(AVB1_TD2) FM(AVB1_MII_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR6_7_4 FM(AVB1_RD2) FM(AVB1_MII_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR6_11_8 FM(AVB1_TD3) FM(AVB1_MII_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR6_15_12 FM(AVB1_RD3) FM(AVB1_MII_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR6_19_16 FM(AVB1_TXCREFCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* SR7 */
+/* IP0SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define IP0SR7_3_0 FM(AVB0_AVTP_PPS) FM(AVB0_MII_COL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR7_7_4 FM(AVB0_AVTP_CAPTURE) FM(AVB0_MII_CRS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR7_11_8 FM(AVB0_AVTP_MATCH) FM(AVB0_MII_RX_ER) FM(CC5_OSCOUT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR7_15_12 FM(AVB0_TD3) FM(AVB0_MII_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR7_19_16 FM(AVB0_LINK) FM(AVB0_MII_TX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR7_23_20 FM(AVB0_PHY_INT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR7_27_24 FM(AVB0_TD2) FM(AVB0_MII_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR7_31_28 FM(AVB0_TD1) FM(AVB0_MII_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP1SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define IP1SR7_3_0 FM(AVB0_RD3) FM(AVB0_MII_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR7_7_4 FM(AVB0_TXCREFCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR7_11_8 FM(AVB0_MAGIC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR7_15_12 FM(AVB0_TD0) FM(AVB0_MII_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR7_19_16 FM(AVB0_RD2) FM(AVB0_MII_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR7_23_20 FM(AVB0_MDC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR7_27_24 FM(AVB0_MDIO) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR7_31_28 FM(AVB0_TXC) FM(AVB0_MII_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP2SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define IP2SR7_3_0 FM(AVB0_TX_CTL) FM(AVB0_MII_TX_EN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR7_7_4 FM(AVB0_RD1) FM(AVB0_MII_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR7_11_8 FM(AVB0_RD0) FM(AVB0_MII_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR7_15_12 FM(AVB0_RXC) FM(AVB0_MII_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR7_19_16 FM(AVB0_RX_CTL) FM(AVB0_MII_RX_DV) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* SR8 */
+/* IP0SR8 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define IP0SR8_3_0 FM(SCL0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR8_7_4 FM(SDA0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR8_11_8 FM(SCL1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR8_15_12 FM(SDA1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR8_19_16 FM(SCL2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR8_23_20 FM(SDA2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR8_27_24 FM(SCL3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR8_31_28 FM(SDA3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* IP1SR8 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define IP1SR8_3_0 FM(SCL4) FM(HRX2) FM(SCK4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR8_7_4 FM(SDA4) FM(HTX2) FM(CTS4_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 IP1SR8_11_8 FM(SCL5) FM(HRTS2_N) FM(RTS4_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 IP1SR8_15_12 FM(SDA5) FM(SCIF_CLK2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR8_19_16 F_(0, 0) FM(HCTS2_N) FM(TX4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR8_23_20 F_(0, 0) FM(HSCK2) FM(RX4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 PINMUX_GPSR \
+ GPSR3_29 \
+ GPSR1_28 GPSR3_28 \
+ GPSR1_27 GPSR3_27 \
+ GPSR1_26 GPSR3_26 \
+ GPSR1_25 GPSR3_25 \
+ GPSR1_24 GPSR3_24 GPSR4_24 \
+ GPSR1_23 GPSR3_23 GPSR4_23 \
+ GPSR1_22 GPSR3_22 GPSR4_22 \
+ GPSR1_21 GPSR3_21 GPSR4_21 \
+ GPSR1_20 GPSR3_20 GPSR4_20 GPSR5_20 GPSR6_20 GPSR7_20 \
+ GPSR1_19 GPSR2_19 GPSR3_19 GPSR4_19 GPSR5_19 GPSR6_19 GPSR7_19 \
+GPSR0_18 GPSR1_18 GPSR2_18 GPSR3_18 GPSR4_18 GPSR5_18 GPSR6_18 GPSR7_18 \
+GPSR0_17 GPSR1_17 GPSR2_17 GPSR3_17 GPSR4_17 GPSR5_17 GPSR6_17 GPSR7_17 \
+GPSR0_16 GPSR1_16 GPSR2_16 GPSR3_16 GPSR4_16 GPSR5_16 GPSR6_16 GPSR7_16 \
+GPSR0_15 GPSR1_15 GPSR2_15 GPSR3_15 GPSR4_15 GPSR5_15 GPSR6_15 GPSR7_15 \
+GPSR0_14 GPSR1_14 GPSR2_14 GPSR3_14 GPSR4_14 GPSR5_14 GPSR6_14 GPSR7_14 \
+GPSR0_13 GPSR1_13 GPSR2_13 GPSR3_13 GPSR4_13 GPSR5_13 GPSR6_13 GPSR7_13 GPSR8_13 \
+GPSR0_12 GPSR1_12 GPSR2_12 GPSR3_12 GPSR4_12 GPSR5_12 GPSR6_12 GPSR7_12 GPSR8_12 \
+GPSR0_11 GPSR1_11 GPSR2_11 GPSR3_11 GPSR4_11 GPSR5_11 GPSR6_11 GPSR7_11 GPSR8_11 \
+GPSR0_10 GPSR1_10 GPSR2_10 GPSR3_10 GPSR4_10 GPSR5_10 GPSR6_10 GPSR7_10 GPSR8_10 \
+GPSR0_9 GPSR1_9 GPSR2_9 GPSR3_9 GPSR4_9 GPSR5_9 GPSR6_9 GPSR7_9 GPSR8_9 \
+GPSR0_8 GPSR1_8 GPSR2_8 GPSR3_8 GPSR4_8 GPSR5_8 GPSR6_8 GPSR7_8 GPSR8_8 \
+GPSR0_7 GPSR1_7 GPSR2_7 GPSR3_7 GPSR4_7 GPSR5_7 GPSR6_7 GPSR7_7 GPSR8_7 \
+GPSR0_6 GPSR1_6 GPSR2_6 GPSR3_6 GPSR4_6 GPSR5_6 GPSR6_6 GPSR7_6 GPSR8_6 \
+GPSR0_5 GPSR1_5 GPSR2_5 GPSR3_5 GPSR4_5 GPSR5_5 GPSR6_5 GPSR7_5 GPSR8_5 \
+GPSR0_4 GPSR1_4 GPSR2_4 GPSR3_4 GPSR4_4 GPSR5_4 GPSR6_4 GPSR7_4 GPSR8_4 \
+GPSR0_3 GPSR1_3 GPSR2_3 GPSR3_3 GPSR4_3 GPSR5_3 GPSR6_3 GPSR7_3 GPSR8_3 \
+GPSR0_2 GPSR1_2 GPSR2_2 GPSR3_2 GPSR4_2 GPSR5_2 GPSR6_2 GPSR7_2 GPSR8_2 \
+GPSR0_1 GPSR1_1 GPSR2_1 GPSR3_1 GPSR4_1 GPSR5_1 GPSR6_1 GPSR7_1 GPSR8_1 \
+GPSR0_0 GPSR1_0 GPSR2_0 GPSR3_0 GPSR4_0 GPSR5_0 GPSR6_0 GPSR7_0 GPSR8_0
+
+#define PINMUX_IPSR \
+\
+FM(IP0SR0_3_0) IP0SR0_3_0 FM(IP1SR0_3_0) IP1SR0_3_0 FM(IP2SR0_3_0) IP2SR0_3_0 \
+FM(IP0SR0_7_4) IP0SR0_7_4 FM(IP1SR0_7_4) IP1SR0_7_4 FM(IP2SR0_7_4) IP2SR0_7_4 \
+FM(IP0SR0_11_8) IP0SR0_11_8 FM(IP1SR0_11_8) IP1SR0_11_8 FM(IP2SR0_11_8) IP2SR0_11_8 \
+FM(IP0SR0_15_12) IP0SR0_15_12 FM(IP1SR0_15_12) IP1SR0_15_12 \
+FM(IP0SR0_19_16) IP0SR0_19_16 FM(IP1SR0_19_16) IP1SR0_19_16 \
+FM(IP0SR0_23_20) IP0SR0_23_20 FM(IP1SR0_23_20) IP1SR0_23_20 \
+FM(IP0SR0_27_24) IP0SR0_27_24 FM(IP1SR0_27_24) IP1SR0_27_24 \
+FM(IP0SR0_31_28) IP0SR0_31_28 FM(IP1SR0_31_28) IP1SR0_31_28 \
+\
+FM(IP0SR1_3_0) IP0SR1_3_0 FM(IP1SR1_3_0) IP1SR1_3_0 FM(IP2SR1_3_0) IP2SR1_3_0 FM(IP3SR1_3_0) IP3SR1_3_0 \
+FM(IP0SR1_7_4) IP0SR1_7_4 FM(IP1SR1_7_4) IP1SR1_7_4 FM(IP2SR1_7_4) IP2SR1_7_4 FM(IP3SR1_7_4) IP3SR1_7_4 \
+FM(IP0SR1_11_8) IP0SR1_11_8 FM(IP1SR1_11_8) IP1SR1_11_8 FM(IP2SR1_11_8) IP2SR1_11_8 FM(IP3SR1_11_8) IP3SR1_11_8 \
+FM(IP0SR1_15_12) IP0SR1_15_12 FM(IP1SR1_15_12) IP1SR1_15_12 FM(IP2SR1_15_12) IP2SR1_15_12 FM(IP3SR1_15_12) IP3SR1_15_12 \
+FM(IP0SR1_19_16) IP0SR1_19_16 FM(IP1SR1_19_16) IP1SR1_19_16 FM(IP2SR1_19_16) IP2SR1_19_16 FM(IP3SR1_19_16) IP3SR1_19_16 \
+FM(IP0SR1_23_20) IP0SR1_23_20 FM(IP1SR1_23_20) IP1SR1_23_20 FM(IP2SR1_23_20) IP2SR1_23_20 \
+FM(IP0SR1_27_24) IP0SR1_27_24 FM(IP1SR1_27_24) IP1SR1_27_24 FM(IP2SR1_27_24) IP2SR1_27_24 \
+FM(IP0SR1_31_28) IP0SR1_31_28 FM(IP1SR1_31_28) IP1SR1_31_28 FM(IP2SR1_31_28) IP2SR1_31_28 \
+\
+FM(IP0SR2_3_0) IP0SR2_3_0 FM(IP1SR2_3_0) IP1SR2_3_0 FM(IP2SR2_3_0) IP2SR2_3_0 \
+FM(IP0SR2_7_4) IP0SR2_7_4 FM(IP1SR2_7_4) IP1SR2_7_4 FM(IP2SR2_7_4) IP2SR2_7_4 \
+FM(IP0SR2_11_8) IP0SR2_11_8 FM(IP1SR2_11_8) IP1SR2_11_8 FM(IP2SR2_11_8) IP2SR2_11_8 \
+FM(IP0SR2_15_12) IP0SR2_15_12 FM(IP1SR2_15_12) IP1SR2_15_12 FM(IP2SR2_15_12) IP2SR2_15_12 \
+FM(IP0SR2_19_16) IP0SR2_19_16 FM(IP1SR2_19_16) IP1SR2_19_16 \
+FM(IP0SR2_23_20) IP0SR2_23_20 FM(IP1SR2_23_20) IP1SR2_23_20 \
+FM(IP0SR2_27_24) IP0SR2_27_24 FM(IP1SR2_27_24) IP1SR2_27_24 \
+FM(IP0SR2_31_28) IP0SR2_31_28 FM(IP1SR2_31_28) IP1SR2_31_28 \
+\
+FM(IP0SR3_3_0) IP0SR3_3_0 FM(IP1SR3_3_0) IP1SR3_3_0 FM(IP2SR3_3_0) IP2SR3_3_0 FM(IP3SR3_3_0) IP3SR3_3_0 \
+FM(IP0SR3_7_4) IP0SR3_7_4 FM(IP1SR3_7_4) IP1SR3_7_4 FM(IP2SR3_7_4) IP2SR3_7_4 FM(IP3SR3_7_4) IP3SR3_7_4 \
+FM(IP0SR3_11_8) IP0SR3_11_8 FM(IP1SR3_11_8) IP1SR3_11_8 FM(IP2SR3_11_8) IP2SR3_11_8 FM(IP3SR3_11_8) IP3SR3_11_8 \
+FM(IP0SR3_15_12) IP0SR3_15_12 FM(IP1SR3_15_12) IP1SR3_15_12 FM(IP2SR3_15_12) IP2SR3_15_12 FM(IP3SR3_15_12) IP3SR3_15_12 \
+FM(IP0SR3_19_16) IP0SR3_19_16 FM(IP1SR3_19_16) IP1SR3_19_16 FM(IP2SR3_19_16) IP2SR3_19_16 FM(IP3SR3_19_16) IP3SR3_19_16 \
+FM(IP0SR3_23_20) IP0SR3_23_20 FM(IP1SR3_23_20) IP1SR3_23_20 FM(IP2SR3_23_20) IP2SR3_23_20 FM(IP3SR3_23_20) IP3SR3_23_20 \
+FM(IP0SR3_27_24) IP0SR3_27_24 FM(IP1SR3_27_24) IP1SR3_27_24 FM(IP2SR3_27_24) IP2SR3_27_24 \
+FM(IP0SR3_31_28) IP0SR3_31_28 FM(IP1SR3_31_28) IP1SR3_31_28 FM(IP2SR3_31_28) IP2SR3_31_28 \
+\
+FM(IP0SR6_3_0) IP0SR6_3_0 FM(IP1SR6_3_0) IP1SR6_3_0 FM(IP2SR6_3_0) IP2SR6_3_0 \
+FM(IP0SR6_7_4) IP0SR6_7_4 FM(IP1SR6_7_4) IP1SR6_7_4 FM(IP2SR6_7_4) IP2SR6_7_4 \
+FM(IP0SR6_11_8) IP0SR6_11_8 FM(IP1SR6_11_8) IP1SR6_11_8 FM(IP2SR6_11_8) IP2SR6_11_8 \
+FM(IP0SR6_15_12) IP0SR6_15_12 FM(IP1SR6_15_12) IP1SR6_15_12 FM(IP2SR6_15_12) IP2SR6_15_12 \
+FM(IP0SR6_19_16) IP0SR6_19_16 FM(IP1SR6_19_16) IP1SR6_19_16 FM(IP2SR6_19_16) IP2SR6_19_16 \
+FM(IP0SR6_23_20) IP0SR6_23_20 FM(IP1SR6_23_20) IP1SR6_23_20 \
+FM(IP0SR6_27_24) IP0SR6_27_24 FM(IP1SR6_27_24) IP1SR6_27_24 \
+FM(IP0SR6_31_28) IP0SR6_31_28 FM(IP1SR6_31_28) IP1SR6_31_28 \
+\
+FM(IP0SR7_3_0) IP0SR7_3_0 FM(IP1SR7_3_0) IP1SR7_3_0 FM(IP2SR7_3_0) IP2SR7_3_0 \
+FM(IP0SR7_7_4) IP0SR7_7_4 FM(IP1SR7_7_4) IP1SR7_7_4 FM(IP2SR7_7_4) IP2SR7_7_4 \
+FM(IP0SR7_11_8) IP0SR7_11_8 FM(IP1SR7_11_8) IP1SR7_11_8 FM(IP2SR7_11_8) IP2SR7_11_8 \
+FM(IP0SR7_15_12) IP0SR7_15_12 FM(IP1SR7_15_12) IP1SR7_15_12 FM(IP2SR7_15_12) IP2SR7_15_12 \
+FM(IP0SR7_19_16) IP0SR7_19_16 FM(IP1SR7_19_16) IP1SR7_19_16 FM(IP2SR7_19_16) IP2SR7_19_16 \
+FM(IP0SR7_23_20) IP0SR7_23_20 FM(IP1SR7_23_20) IP1SR7_23_20 \
+FM(IP0SR7_27_24) IP0SR7_27_24 FM(IP1SR7_27_24) IP1SR7_27_24 \
+FM(IP0SR7_31_28) IP0SR7_31_28 FM(IP1SR7_31_28) IP1SR7_31_28 \
+\
+FM(IP0SR8_3_0) IP0SR8_3_0 FM(IP1SR8_3_0) IP1SR8_3_0 \
+FM(IP0SR8_7_4) IP0SR8_7_4 FM(IP1SR8_7_4) IP1SR8_7_4 \
+FM(IP0SR8_11_8) IP0SR8_11_8 FM(IP1SR8_11_8) IP1SR8_11_8 \
+FM(IP0SR8_15_12) IP0SR8_15_12 FM(IP1SR8_15_12) IP1SR8_15_12 \
+FM(IP0SR8_19_16) IP0SR8_19_16 FM(IP1SR8_19_16) IP1SR8_19_16 \
+FM(IP0SR8_23_20) IP0SR8_23_20 FM(IP1SR8_23_20) IP1SR8_23_20 \
+FM(IP0SR8_27_24) IP0SR8_27_24 \
+FM(IP0SR8_31_28) IP0SR8_31_28
+
+/* MOD_SEL4 */ /* 0 */ /* 1 */
+#define MOD_SEL4_19 FM(SEL_TSN0_TD2_0) FM(SEL_TSN0_TD2_1)
+#define MOD_SEL4_18 FM(SEL_TSN0_TD3_0) FM(SEL_TSN0_TD3_1)
+#define MOD_SEL4_15 FM(SEL_TSN0_TD0_0) FM(SEL_TSN0_TD0_1)
+#define MOD_SEL4_14 FM(SEL_TSN0_TD1_0) FM(SEL_TSN0_TD1_1)
+#define MOD_SEL4_12 FM(SEL_TSN0_TXC_0) FM(SEL_TSN0_TXC_1)
+#define MOD_SEL4_9 FM(SEL_TSN0_TX_CTL_0) FM(SEL_TSN0_TX_CTL_1)
+#define MOD_SEL4_8 FM(SEL_TSN0_AVTP_PPS0_0) FM(SEL_TSN0_AVTP_PPS0_1)
+#define MOD_SEL4_5 FM(SEL_TSN0_AVTP_MATCH_0) FM(SEL_TSN0_AVTP_MATCH_1)
+#define MOD_SEL4_2 FM(SEL_TSN0_AVTP_PPS1_0) FM(SEL_TSN0_AVTP_PPS1_1)
+#define MOD_SEL4_1 FM(SEL_TSN0_MDC_0) FM(SEL_TSN0_MDC_1)
+
+/* MOD_SEL5 */ /* 0 */ /* 1 */
+#define MOD_SEL5_19 FM(SEL_AVB2_TX_CTL_0) FM(SEL_AVB2_TX_CTL_1)
+#define MOD_SEL5_16 FM(SEL_AVB2_TXC_0) FM(SEL_AVB2_TXC_1)
+#define MOD_SEL5_15 FM(SEL_AVB2_TD0_0) FM(SEL_AVB2_TD0_1)
+#define MOD_SEL5_12 FM(SEL_AVB2_TD1_0) FM(SEL_AVB2_TD1_1)
+#define MOD_SEL5_11 FM(SEL_AVB2_TD2_0) FM(SEL_AVB2_TD2_1)
+#define MOD_SEL5_8 FM(SEL_AVB2_TD3_0) FM(SEL_AVB2_TD3_1)
+#define MOD_SEL5_6 FM(SEL_AVB2_MDC_0) FM(SEL_AVB2_MDC_1)
+#define MOD_SEL5_5 FM(SEL_AVB2_MAGIC_0) FM(SEL_AVB2_MAGIC_1)
+#define MOD_SEL5_2 FM(SEL_AVB2_AVTP_MATCH_0) FM(SEL_AVB2_AVTP_MATCH_1)
+#define MOD_SEL5_0 FM(SEL_AVB2_AVTP_PPS_0) FM(SEL_AVB2_AVTP_PPS_1)
+
+/* MOD_SEL6 */ /* 0 */ /* 1 */
+#define MOD_SEL6_18 FM(SEL_AVB1_TD3_0) FM(SEL_AVB1_TD3_1)
+#define MOD_SEL6_16 FM(SEL_AVB1_TD2_0) FM(SEL_AVB1_TD2_1)
+#define MOD_SEL6_13 FM(SEL_AVB1_TD0_0) FM(SEL_AVB1_TD0_1)
+#define MOD_SEL6_12 FM(SEL_AVB1_TD1_0) FM(SEL_AVB1_TD1_1)
+#define MOD_SEL6_10 FM(SEL_AVB1_AVTP_PPS_0) FM(SEL_AVB1_AVTP_PPS_1)
+#define MOD_SEL6_7 FM(SEL_AVB1_TX_CTL_0) FM(SEL_AVB1_TX_CTL_1)
+#define MOD_SEL6_6 FM(SEL_AVB1_TXC_0) FM(SEL_AVB1_TXC_1)
+#define MOD_SEL6_5 FM(SEL_AVB1_AVTP_MATCH_0) FM(SEL_AVB1_AVTP_MATCH_1)
+#define MOD_SEL6_2 FM(SEL_AVB1_MDC_0) FM(SEL_AVB1_MDC_1)
+#define MOD_SEL6_1 FM(SEL_AVB1_MAGIC_0) FM(SEL_AVB1_MAGIC_1)
+
+/* MOD_SEL7 */ /* 0 */ /* 1 */
+#define MOD_SEL7_16 FM(SEL_AVB0_TX_CTL_0) FM(SEL_AVB0_TX_CTL_1)
+#define MOD_SEL7_15 FM(SEL_AVB0_TXC_0) FM(SEL_AVB0_TXC_1)
+#define MOD_SEL7_13 FM(SEL_AVB0_MDC_0) FM(SEL_AVB0_MDC_1)
+#define MOD_SEL7_11 FM(SEL_AVB0_TD0_0) FM(SEL_AVB0_TD0_1)
+#define MOD_SEL7_10 FM(SEL_AVB0_MAGIC_0) FM(SEL_AVB0_MAGIC_1)
+#define MOD_SEL7_7 FM(SEL_AVB0_TD1_0) FM(SEL_AVB0_TD1_1)
+#define MOD_SEL7_6 FM(SEL_AVB0_TD2_0) FM(SEL_AVB0_TD2_1)
+#define MOD_SEL7_3 FM(SEL_AVB0_TD3_0) FM(SEL_AVB0_TD3_1)
+#define MOD_SEL7_2 FM(SEL_AVB0_AVTP_MATCH_0) FM(SEL_AVB0_AVTP_MATCH_1)
+#define MOD_SEL7_0 FM(SEL_AVB0_AVTP_PPS_0) FM(SEL_AVB0_AVTP_PPS_1)
+
+/* MOD_SEL8 */ /* 0 */ /* 1 */
+#define MOD_SEL8_11 FM(SEL_SDA5_0) FM(SEL_SDA5_1)
+#define MOD_SEL8_10 FM(SEL_SCL5_0) FM(SEL_SCL5_1)
+#define MOD_SEL8_9 FM(SEL_SDA4_0) FM(SEL_SDA4_1)
+#define MOD_SEL8_8 FM(SEL_SCL4_0) FM(SEL_SCL4_1)
+#define MOD_SEL8_7 FM(SEL_SDA3_0) FM(SEL_SDA3_1)
+#define MOD_SEL8_6 FM(SEL_SCL3_0) FM(SEL_SCL3_1)
+#define MOD_SEL8_5 FM(SEL_SDA2_0) FM(SEL_SDA2_1)
+#define MOD_SEL8_4 FM(SEL_SCL2_0) FM(SEL_SCL2_1)
+#define MOD_SEL8_3 FM(SEL_SDA1_0) FM(SEL_SDA1_1)
+#define MOD_SEL8_2 FM(SEL_SCL1_0) FM(SEL_SCL1_1)
+#define MOD_SEL8_1 FM(SEL_SDA0_0) FM(SEL_SDA0_1)
+#define MOD_SEL8_0 FM(SEL_SCL0_0) FM(SEL_SCL0_1)
+
+#define PINMUX_MOD_SELS \
+\
+MOD_SEL4_19 MOD_SEL5_19 \
+MOD_SEL4_18 MOD_SEL6_18 \
+ \
+ MOD_SEL5_16 MOD_SEL6_16 MOD_SEL7_16 \
+MOD_SEL4_15 MOD_SEL5_15 MOD_SEL7_15 \
+MOD_SEL4_14 \
+ MOD_SEL6_13 MOD_SEL7_13 \
+MOD_SEL4_12 MOD_SEL5_12 MOD_SEL6_12 \
+ MOD_SEL5_11 MOD_SEL7_11 MOD_SEL8_11 \
+ MOD_SEL6_10 MOD_SEL7_10 MOD_SEL8_10 \
+MOD_SEL4_9 MOD_SEL8_9 \
+MOD_SEL4_8 MOD_SEL5_8 MOD_SEL8_8 \
+ MOD_SEL6_7 MOD_SEL7_7 MOD_SEL8_7 \
+ MOD_SEL5_6 MOD_SEL6_6 MOD_SEL7_6 MOD_SEL8_6 \
+MOD_SEL4_5 MOD_SEL5_5 MOD_SEL6_5 MOD_SEL8_5 \
+ MOD_SEL8_4 \
+ MOD_SEL7_3 MOD_SEL8_3 \
+MOD_SEL4_2 MOD_SEL5_2 MOD_SEL6_2 MOD_SEL7_2 MOD_SEL8_2 \
+MOD_SEL4_1 MOD_SEL6_1 MOD_SEL8_1 \
+ MOD_SEL5_0 MOD_SEL7_0 MOD_SEL8_0
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ GP_ALL(DATA),
+ PINMUX_DATA_END,
+
+#define F_(x, y)
+#define FM(x) FN_##x,
+ PINMUX_FUNCTION_BEGIN,
+ GP_ALL(FN),
+ PINMUX_GPSR
+ PINMUX_IPSR
+ PINMUX_MOD_SELS
+ PINMUX_FUNCTION_END,
+#undef F_
+#undef FM
+
+#define F_(x, y)
+#define FM(x) x##_MARK,
+ PINMUX_MARK_BEGIN,
+ PINMUX_GPSR
+ PINMUX_IPSR
+ PINMUX_MOD_SELS
+ PINMUX_MARK_END,
+#undef F_
+#undef FM
+};
+
+static const u16 pinmux_data[] = {
+ PINMUX_DATA_GP_ALL(),
+
+ PINMUX_SINGLE(AVS1),
+ PINMUX_SINGLE(AVS0),
+ PINMUX_SINGLE(PCIE1_CLKREQ_N),
+ PINMUX_SINGLE(PCIE0_CLKREQ_N),
+
+ /* TSN0 without MODSEL4 */
+ PINMUX_SINGLE(TSN0_TXCREFCLK),
+ PINMUX_SINGLE(TSN0_RD2),
+ PINMUX_SINGLE(TSN0_RD3),
+ PINMUX_SINGLE(TSN0_RD1),
+ PINMUX_SINGLE(TSN0_RXC),
+ PINMUX_SINGLE(TSN0_RD0),
+ PINMUX_SINGLE(TSN0_RX_CTL),
+ PINMUX_SINGLE(TSN0_AVTP_CAPTURE),
+ PINMUX_SINGLE(TSN0_LINK),
+ PINMUX_SINGLE(TSN0_PHY_INT),
+ PINMUX_SINGLE(TSN0_MDIO),
+ /* TSN0 with MODSEL4 */
+ PINMUX_IPSR_NOGM(0, TSN0_TD2, SEL_TSN0_TD2_1),
+ PINMUX_IPSR_NOGM(0, TSN0_TD3, SEL_TSN0_TD3_1),
+ PINMUX_IPSR_NOGM(0, TSN0_TD0, SEL_TSN0_TD0_1),
+ PINMUX_IPSR_NOGM(0, TSN0_TD1, SEL_TSN0_TD1_1),
+ PINMUX_IPSR_NOGM(0, TSN0_TXC, SEL_TSN0_TXC_1),
+ PINMUX_IPSR_NOGM(0, TSN0_TX_CTL, SEL_TSN0_TX_CTL_1),
+ PINMUX_IPSR_NOGM(0, TSN0_AVTP_PPS0, SEL_TSN0_AVTP_PPS0_1),
+ PINMUX_IPSR_NOGM(0, TSN0_AVTP_MATCH, SEL_TSN0_AVTP_MATCH_1),
+ PINMUX_IPSR_NOGM(0, TSN0_AVTP_PPS1, SEL_TSN0_AVTP_PPS1_1),
+ PINMUX_IPSR_NOGM(0, TSN0_MDC, SEL_TSN0_MDC_1),
+
+ /* TSN0 without MODSEL5 */
+ PINMUX_SINGLE(AVB2_RX_CTL),
+ PINMUX_SINGLE(AVB2_RXC),
+ PINMUX_SINGLE(AVB2_RD0),
+ PINMUX_SINGLE(AVB2_RD1),
+ PINMUX_SINGLE(AVB2_RD2),
+ PINMUX_SINGLE(AVB2_MDIO),
+ PINMUX_SINGLE(AVB2_RD3),
+ PINMUX_SINGLE(AVB2_TXCREFCLK),
+ PINMUX_SINGLE(AVB2_PHY_INT),
+ PINMUX_SINGLE(AVB2_LINK),
+ PINMUX_SINGLE(AVB2_AVTP_CAPTURE),
+ /* TSN0 with MODSEL5 */
+ PINMUX_IPSR_NOGM(0, AVB2_TX_CTL, SEL_AVB2_TX_CTL_1),
+ PINMUX_IPSR_NOGM(0, AVB2_TXC, SEL_AVB2_TXC_1),
+ PINMUX_IPSR_NOGM(0, AVB2_TD0, SEL_AVB2_TD0_1),
+ PINMUX_IPSR_NOGM(0, AVB2_TD1, SEL_AVB2_TD1_1),
+ PINMUX_IPSR_NOGM(0, AVB2_TD2, SEL_AVB2_TD2_1),
+ PINMUX_IPSR_NOGM(0, AVB2_TD3, SEL_AVB2_TD3_1),
+ PINMUX_IPSR_NOGM(0, AVB2_MDC, SEL_AVB2_MDC_1),
+ PINMUX_IPSR_NOGM(0, AVB2_MAGIC, SEL_AVB2_MAGIC_1),
+ PINMUX_IPSR_NOGM(0, AVB2_AVTP_MATCH, SEL_AVB2_AVTP_MATCH_1),
+ PINMUX_IPSR_NOGM(0, AVB2_AVTP_PPS, SEL_AVB2_AVTP_PPS_1),
+
+ /* IP0SR0 */
+ PINMUX_IPSR_GPSR(IP0SR0_3_0, ERROROUTC_B),
+ PINMUX_IPSR_GPSR(IP0SR0_3_0, TCLK2_A),
+
+ 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, MSIOF3_SCK),
+
+ PINMUX_IPSR_GPSR(IP0SR0_19_16, IRQ2),
+ PINMUX_IPSR_GPSR(IP0SR0_19_16, MSIOF3_TXD),
+
+ PINMUX_IPSR_GPSR(IP0SR0_23_20, IRQ1),
+ PINMUX_IPSR_GPSR(IP0SR0_23_20, MSIOF3_RXD),
+
+ PINMUX_IPSR_GPSR(IP0SR0_27_24, IRQ0),
+ PINMUX_IPSR_GPSR(IP0SR0_27_24, MSIOF3_SYNC),
+
+ PINMUX_IPSR_GPSR(IP0SR0_31_28, MSIOF5_SS2),
+
+ /* IP1SR0 */
+ PINMUX_IPSR_GPSR(IP1SR0_3_0, MSIOF5_SS1),
+
+ PINMUX_IPSR_GPSR(IP1SR0_7_4, MSIOF5_SYNC),
+
+ PINMUX_IPSR_GPSR(IP1SR0_11_8, MSIOF5_TXD),
+
+ PINMUX_IPSR_GPSR(IP1SR0_15_12, MSIOF5_SCK),
+
+ 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_27_24, MSIOF2_SS1),
+ PINMUX_IPSR_GPSR(IP1SR0_27_24, HTX1),
+ PINMUX_IPSR_GPSR(IP1SR0_27_24, TX1),
+
+ PINMUX_IPSR_GPSR(IP1SR0_31_28, MSIOF2_SYNC),
+ PINMUX_IPSR_GPSR(IP1SR0_31_28, HRX1),
+ PINMUX_IPSR_GPSR(IP1SR0_31_28, RX1),
+
+ /* 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_7_4, MSIOF2_SCK),
+ PINMUX_IPSR_GPSR(IP2SR0_7_4, HRTS1_N),
+ PINMUX_IPSR_GPSR(IP2SR0_7_4, RTS1_N),
+
+ PINMUX_IPSR_GPSR(IP2SR0_11_8, MSIOF2_RXD),
+ PINMUX_IPSR_GPSR(IP2SR0_11_8, HSCK1),
+ PINMUX_IPSR_GPSR(IP2SR0_11_8, SCK1),
+
+ /* 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_7_4, MSIOF1_SS1),
+ PINMUX_IPSR_GPSR(IP0SR1_7_4, HCTS3_N_A),
+ PINMUX_IPSR_GPSR(IP0SR1_7_4, RX3),
+
+ 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_15_12, MSIOF1_SCK),
+ PINMUX_IPSR_GPSR(IP0SR1_15_12, HSCK3_A),
+ PINMUX_IPSR_GPSR(IP0SR1_15_12, CTS3_N),
+
+ 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_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_31_28, MSIOF0_SS1),
+ PINMUX_IPSR_GPSR(IP0SR1_31_28, HRX1_X),
+ PINMUX_IPSR_GPSR(IP0SR1_31_28, RX1_X),
+
+ /* 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, 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, 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_15_12, MSIOF0_RXD),
+
+ PINMUX_IPSR_GPSR(IP1SR1_19_16, HTX0),
+ PINMUX_IPSR_GPSR(IP1SR1_19_16, TX0),
+
+ 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_27_24, HRTS0_N),
+ PINMUX_IPSR_GPSR(IP1SR1_27_24, RTS0_N),
+ PINMUX_IPSR_GPSR(IP1SR1_27_24, PWM9_A),
+
+ PINMUX_IPSR_GPSR(IP1SR1_31_28, HSCK0),
+ PINMUX_IPSR_GPSR(IP1SR1_31_28, SCK0),
+ PINMUX_IPSR_GPSR(IP1SR1_31_28, PWM0_A),
+
+ /* IP2SR1 */
+ PINMUX_IPSR_GPSR(IP2SR1_3_0, HRX0),
+ PINMUX_IPSR_GPSR(IP2SR1_3_0, RX0),
+
+ PINMUX_IPSR_GPSR(IP2SR1_7_4, SCIF_CLK),
+ 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_15_12, SSI_WS),
+ PINMUX_IPSR_GPSR(IP2SR1_15_12, TCLK4),
+
+ PINMUX_IPSR_GPSR(IP2SR1_19_16, SSI_SD),
+ PINMUX_IPSR_GPSR(IP2SR1_19_16, IRQ0_A),
+
+ PINMUX_IPSR_GPSR(IP2SR1_23_20, AUDIO_CLKOUT),
+ PINMUX_IPSR_GPSR(IP2SR1_23_20, IRQ1_A),
+
+ 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, MSIOF4_SS1),
+ PINMUX_IPSR_GPSR(IP2SR1_31_28, IRQ3_B),
+
+ /* IP3SR1 */
+ PINMUX_IPSR_GPSR(IP3SR1_3_0, HRX3),
+ 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, CTS3_N_A),
+ PINMUX_IPSR_GPSR(IP3SR1_7_4, MSIOF4_SCK),
+ PINMUX_IPSR_GPSR(IP3SR1_7_4, TPU0TO0_A),
+
+ PINMUX_IPSR_GPSR(IP3SR1_11_8, HRTS3_N),
+ 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_15_12, HCTS3_N),
+ 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, 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_7_4, FXR_TXENA_N),
+ PINMUX_IPSR_GPSR(IP0SR2_7_4, CANFD1_RX),
+ PINMUX_IPSR_GPSR(IP0SR2_7_4, TPU0TO3_A),
+
+ PINMUX_IPSR_GPSR(IP0SR2_11_8, RXDA_EXTFXR),
+ PINMUX_IPSR_GPSR(IP0SR2_11_8, CANFD5_TX),
+ 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, IRQ4_B),
+
+ PINMUX_IPSR_GPSR(IP0SR2_19_16, RXDB_EXTFXR),
+
+ PINMUX_IPSR_GPSR(IP0SR2_23_20, FXR_TXENB_N),
+
+ PINMUX_IPSR_GPSR(IP0SR2_27_24, FXR_TXDB),
+
+ PINMUX_IPSR_GPSR(IP0SR2_31_28, TPU0TO1),
+ PINMUX_IPSR_GPSR(IP0SR2_31_28, CANFD6_TX),
+ PINMUX_IPSR_GPSR(IP0SR2_31_28, TCLK2_B),
+
+ /* IP1SR2 */
+ PINMUX_IPSR_GPSR(IP1SR2_3_0, TPU0TO0),
+ PINMUX_IPSR_GPSR(IP1SR2_3_0, CANFD6_RX),
+ PINMUX_IPSR_GPSR(IP1SR2_3_0, TCLK1_A),
+
+ PINMUX_IPSR_GPSR(IP1SR2_7_4, CAN_CLK),
+ PINMUX_IPSR_GPSR(IP1SR2_7_4, FXR_TXENA_N_X),
+
+ PINMUX_IPSR_GPSR(IP1SR2_11_8, CANFD0_TX),
+ PINMUX_IPSR_GPSR(IP1SR2_11_8, FXR_TXENB_N_X),
+
+ 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_23_20, CANFD2_RX),
+ PINMUX_IPSR_GPSR(IP1SR2_23_20, TPU0TO3),
+ PINMUX_IPSR_GPSR(IP1SR2_23_20, PWM1_B),
+ PINMUX_IPSR_GPSR(IP1SR2_23_20, TCLK4_A),
+
+ PINMUX_IPSR_GPSR(IP1SR2_27_24, CANFD3_TX),
+ PINMUX_IPSR_GPSR(IP1SR2_27_24, PWM2_B),
+
+ PINMUX_IPSR_GPSR(IP1SR2_31_28, CANFD3_RX),
+ PINMUX_IPSR_GPSR(IP1SR2_31_28, PWM3_B),
+
+ /* IP2SR2 */
+ PINMUX_IPSR_GPSR(IP2SR2_3_0, CANFD4_TX),
+ PINMUX_IPSR_GPSR(IP2SR2_3_0, PWM4),
+
+ PINMUX_IPSR_GPSR(IP2SR2_7_4, CANFD4_RX),
+ PINMUX_IPSR_GPSR(IP2SR2_7_4, PWM5),
+
+ PINMUX_IPSR_GPSR(IP2SR2_11_8, CANFD7_TX),
+ PINMUX_IPSR_GPSR(IP2SR2_11_8, PWM6),
+
+ PINMUX_IPSR_GPSR(IP2SR2_15_12, CANFD7_RX),
+ PINMUX_IPSR_GPSR(IP2SR2_15_12, PWM7),
+
+ /* IP0SR3 */
+ PINMUX_IPSR_GPSR(IP0SR3_3_0, MMC_SD_D1),
+ PINMUX_IPSR_GPSR(IP0SR3_7_4, MMC_SD_D0),
+ PINMUX_IPSR_GPSR(IP0SR3_11_8, MMC_SD_D2),
+ PINMUX_IPSR_GPSR(IP0SR3_15_12, MMC_SD_CLK),
+ PINMUX_IPSR_GPSR(IP0SR3_19_16, MMC_DS),
+ PINMUX_IPSR_GPSR(IP0SR3_23_20, MMC_SD_D3),
+ PINMUX_IPSR_GPSR(IP0SR3_27_24, MMC_D5),
+ PINMUX_IPSR_GPSR(IP0SR3_31_28, MMC_D4),
+
+ /* IP1SR3 */
+ PINMUX_IPSR_GPSR(IP1SR3_3_0, MMC_D7),
+
+ PINMUX_IPSR_GPSR(IP1SR3_7_4, MMC_D6),
+
+ PINMUX_IPSR_GPSR(IP1SR3_11_8, MMC_SD_CMD),
+
+ PINMUX_IPSR_GPSR(IP1SR3_15_12, SD_CD),
+
+ PINMUX_IPSR_GPSR(IP1SR3_19_16, SD_WP),
+
+ 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_27_24, IPC_CLKOUT),
+ PINMUX_IPSR_GPSR(IP1SR3_27_24, IPC_CLKEN_OUT),
+ PINMUX_IPSR_GPSR(IP1SR3_27_24, ERROROUTC_A),
+ PINMUX_IPSR_GPSR(IP1SR3_27_24, TCLK4_X),
+
+ PINMUX_IPSR_GPSR(IP1SR3_31_28, QSPI0_SSL),
+
+ /* IP2SR3 */
+ PINMUX_IPSR_GPSR(IP2SR3_3_0, QSPI0_IO3),
+ PINMUX_IPSR_GPSR(IP2SR3_7_4, QSPI0_IO2),
+ PINMUX_IPSR_GPSR(IP2SR3_11_8, QSPI0_MISO_IO1),
+ PINMUX_IPSR_GPSR(IP2SR3_15_12, QSPI0_MOSI_IO0),
+ PINMUX_IPSR_GPSR(IP2SR3_19_16, QSPI0_SPCLK),
+ PINMUX_IPSR_GPSR(IP2SR3_23_20, QSPI1_MOSI_IO0),
+ PINMUX_IPSR_GPSR(IP2SR3_27_24, QSPI1_SPCLK),
+ PINMUX_IPSR_GPSR(IP2SR3_31_28, QSPI1_MISO_IO1),
+
+ /* IP3SR3 */
+ PINMUX_IPSR_GPSR(IP3SR3_3_0, QSPI1_IO2),
+ PINMUX_IPSR_GPSR(IP3SR3_7_4, QSPI1_SSL),
+ PINMUX_IPSR_GPSR(IP3SR3_11_8, QSPI1_IO3),
+ PINMUX_IPSR_GPSR(IP3SR3_15_12, RPC_RESET_N),
+ PINMUX_IPSR_GPSR(IP3SR3_19_16, RPC_WP_N),
+ PINMUX_IPSR_GPSR(IP3SR3_23_20, RPC_INT_N),
+
+ /* IP0SR6 */
+ PINMUX_IPSR_GPSR(IP0SR6_3_0, AVB1_MDIO),
+
+ PINMUX_IPSR_MSEL(IP0SR6_7_4, AVB1_MAGIC, SEL_AVB1_MAGIC_1),
+
+ PINMUX_IPSR_MSEL(IP0SR6_11_8, AVB1_MDC, SEL_AVB1_MDC_1),
+
+ PINMUX_IPSR_GPSR(IP0SR6_15_12, AVB1_PHY_INT),
+
+ PINMUX_IPSR_GPSR(IP0SR6_19_16, AVB1_LINK),
+ PINMUX_IPSR_GPSR(IP0SR6_19_16, AVB1_MII_TX_ER),
+
+ PINMUX_IPSR_MSEL(IP0SR6_23_20, AVB1_AVTP_MATCH, SEL_AVB1_AVTP_MATCH_1),
+ PINMUX_IPSR_MSEL(IP0SR6_23_20, AVB1_MII_RX_ER, SEL_AVB1_AVTP_MATCH_0),
+
+ PINMUX_IPSR_MSEL(IP0SR6_27_24, AVB1_TXC, SEL_AVB1_TXC_1),
+ PINMUX_IPSR_MSEL(IP0SR6_27_24, AVB1_MII_TXC, SEL_AVB1_TXC_0),
+
+ PINMUX_IPSR_MSEL(IP0SR6_31_28, AVB1_TX_CTL, SEL_AVB1_TX_CTL_1),
+ PINMUX_IPSR_MSEL(IP0SR6_31_28, AVB1_MII_TX_EN, SEL_AVB1_TX_CTL_0),
+
+ /* IP1SR6 */
+ PINMUX_IPSR_GPSR(IP1SR6_3_0, AVB1_RXC),
+ PINMUX_IPSR_GPSR(IP1SR6_3_0, AVB1_MII_RXC),
+
+ PINMUX_IPSR_GPSR(IP1SR6_7_4, AVB1_RX_CTL),
+ PINMUX_IPSR_GPSR(IP1SR6_7_4, AVB1_MII_RX_DV),
+
+ PINMUX_IPSR_MSEL(IP1SR6_11_8, AVB1_AVTP_PPS, SEL_AVB1_AVTP_PPS_1),
+ PINMUX_IPSR_MSEL(IP1SR6_11_8, AVB1_MII_COL, SEL_AVB1_AVTP_PPS_0),
+
+ PINMUX_IPSR_GPSR(IP1SR6_15_12, AVB1_AVTP_CAPTURE),
+ PINMUX_IPSR_GPSR(IP1SR6_15_12, AVB1_MII_CRS),
+
+ PINMUX_IPSR_MSEL(IP1SR6_19_16, AVB1_TD1, SEL_AVB1_TD1_1),
+ PINMUX_IPSR_MSEL(IP1SR6_19_16, AVB1_MII_TD1, SEL_AVB1_TD1_0),
+
+ PINMUX_IPSR_MSEL(IP1SR6_23_20, AVB1_TD0, SEL_AVB1_TD0_1),
+ PINMUX_IPSR_MSEL(IP1SR6_23_20, AVB1_MII_TD0, SEL_AVB1_TD0_0),
+
+ PINMUX_IPSR_GPSR(IP1SR6_27_24, AVB1_RD1),
+ PINMUX_IPSR_GPSR(IP1SR6_27_24, AVB1_MII_RD1),
+
+ PINMUX_IPSR_GPSR(IP1SR6_31_28, AVB1_RD0),
+ PINMUX_IPSR_GPSR(IP1SR6_31_28, AVB1_MII_RD0),
+
+ /* IP2SR6 */
+ PINMUX_IPSR_MSEL(IP2SR6_3_0, AVB1_TD2, SEL_AVB1_TD2_1),
+ PINMUX_IPSR_MSEL(IP2SR6_3_0, AVB1_MII_TD2, SEL_AVB1_TD2_0),
+
+ PINMUX_IPSR_GPSR(IP2SR6_7_4, AVB1_RD2),
+ PINMUX_IPSR_GPSR(IP2SR6_7_4, AVB1_MII_RD2),
+
+ PINMUX_IPSR_MSEL(IP2SR6_11_8, AVB1_TD3, SEL_AVB1_TD3_1),
+ PINMUX_IPSR_MSEL(IP2SR6_11_8, AVB1_MII_TD3, SEL_AVB1_TD3_0),
+
+ PINMUX_IPSR_GPSR(IP2SR6_15_12, AVB1_RD3),
+ PINMUX_IPSR_GPSR(IP2SR6_15_12, AVB1_MII_RD3),
+
+ PINMUX_IPSR_GPSR(IP2SR6_19_16, AVB1_TXCREFCLK),
+
+ /* IP0SR7 */
+ PINMUX_IPSR_MSEL(IP0SR7_3_0, AVB0_AVTP_PPS, SEL_AVB0_AVTP_PPS_1),
+ PINMUX_IPSR_MSEL(IP0SR7_3_0, AVB0_MII_COL, SEL_AVB0_AVTP_PPS_0),
+
+ PINMUX_IPSR_GPSR(IP0SR7_7_4, AVB0_AVTP_CAPTURE),
+ PINMUX_IPSR_GPSR(IP0SR7_7_4, AVB0_MII_CRS),
+
+ PINMUX_IPSR_MSEL(IP0SR7_11_8, AVB0_AVTP_MATCH, SEL_AVB0_AVTP_MATCH_1),
+ PINMUX_IPSR_MSEL(IP0SR7_11_8, AVB0_MII_RX_ER, SEL_AVB0_AVTP_MATCH_0),
+ PINMUX_IPSR_MSEL(IP0SR7_11_8, CC5_OSCOUT, SEL_AVB0_AVTP_MATCH_0),
+
+ PINMUX_IPSR_MSEL(IP0SR7_15_12, AVB0_TD3, SEL_AVB0_TD3_1),
+ PINMUX_IPSR_MSEL(IP0SR7_15_12, AVB0_MII_TD3, SEL_AVB0_TD3_0),
+
+ PINMUX_IPSR_GPSR(IP0SR7_19_16, AVB0_LINK),
+ PINMUX_IPSR_GPSR(IP0SR7_19_16, AVB0_MII_TX_ER),
+
+ PINMUX_IPSR_GPSR(IP0SR7_23_20, AVB0_PHY_INT),
+
+ PINMUX_IPSR_MSEL(IP0SR7_27_24, AVB0_TD2, SEL_AVB0_TD2_1),
+ PINMUX_IPSR_MSEL(IP0SR7_27_24, AVB0_MII_TD2, SEL_AVB0_TD2_0),
+
+ PINMUX_IPSR_MSEL(IP0SR7_31_28, AVB0_TD1, SEL_AVB0_TD1_1),
+ PINMUX_IPSR_MSEL(IP0SR7_31_28, AVB0_MII_TD1, SEL_AVB0_TD1_0),
+
+ /* IP1SR7 */
+ PINMUX_IPSR_GPSR(IP1SR7_3_0, AVB0_RD3),
+ PINMUX_IPSR_GPSR(IP1SR7_3_0, AVB0_MII_RD3),
+
+ PINMUX_IPSR_GPSR(IP1SR7_7_4, AVB0_TXCREFCLK),
+
+ PINMUX_IPSR_MSEL(IP1SR7_11_8, AVB0_MAGIC, SEL_AVB0_MAGIC_1),
+
+ PINMUX_IPSR_MSEL(IP1SR7_15_12, AVB0_TD0, SEL_AVB0_TD0_1),
+ PINMUX_IPSR_MSEL(IP1SR7_15_12, AVB0_MII_TD0, SEL_AVB0_TD0_0),
+
+ PINMUX_IPSR_GPSR(IP1SR7_19_16, AVB0_RD2),
+ PINMUX_IPSR_GPSR(IP1SR7_19_16, AVB0_MII_RD2),
+
+ PINMUX_IPSR_MSEL(IP1SR7_23_20, AVB0_MDC, SEL_AVB0_MDC_1),
+
+ PINMUX_IPSR_GPSR(IP1SR7_27_24, AVB0_MDIO),
+
+ PINMUX_IPSR_MSEL(IP1SR7_31_28, AVB0_TXC, SEL_AVB0_TXC_1),
+ PINMUX_IPSR_MSEL(IP1SR7_31_28, AVB0_MII_TXC, SEL_AVB0_TXC_0),
+
+ /* IP2SR7 */
+ PINMUX_IPSR_MSEL(IP2SR7_3_0, AVB0_TX_CTL, SEL_AVB0_TX_CTL_1),
+ PINMUX_IPSR_MSEL(IP2SR7_3_0, AVB0_MII_TX_EN, SEL_AVB0_TX_CTL_0),
+
+ PINMUX_IPSR_GPSR(IP2SR7_7_4, AVB0_RD1),
+ PINMUX_IPSR_GPSR(IP2SR7_7_4, AVB0_MII_RD1),
+
+ PINMUX_IPSR_GPSR(IP2SR7_11_8, AVB0_RD0),
+ PINMUX_IPSR_GPSR(IP2SR7_11_8, AVB0_MII_RD0),
+
+ PINMUX_IPSR_GPSR(IP2SR7_15_12, AVB0_RXC),
+ PINMUX_IPSR_GPSR(IP2SR7_15_12, AVB0_MII_RXC),
+
+ PINMUX_IPSR_GPSR(IP2SR7_19_16, AVB0_RX_CTL),
+ PINMUX_IPSR_GPSR(IP2SR7_19_16, AVB0_MII_RX_DV),
+
+ /* IP0SR8 */
+ PINMUX_IPSR_MSEL(IP0SR8_3_0, SCL0, SEL_SCL0_0),
+ PINMUX_IPSR_MSEL(IP0SR8_7_4, SDA0, SEL_SDA0_0),
+ PINMUX_IPSR_MSEL(IP0SR8_11_8, SCL1, SEL_SCL1_0),
+ PINMUX_IPSR_MSEL(IP0SR8_15_12, SDA1, SEL_SDA1_0),
+ PINMUX_IPSR_MSEL(IP0SR8_19_16, SCL2, SEL_SCL2_0),
+ PINMUX_IPSR_MSEL(IP0SR8_23_20, SDA2, SEL_SDA2_0),
+ PINMUX_IPSR_MSEL(IP0SR8_27_24, SCL3, SEL_SCL3_0),
+ PINMUX_IPSR_MSEL(IP0SR8_31_28, SDA3, SEL_SDA3_0),
+
+ /* IP1SR8 */
+ PINMUX_IPSR_MSEL(IP1SR8_3_0, SCL4, SEL_SCL4_0),
+ PINMUX_IPSR_MSEL(IP1SR8_3_0, HRX2, SEL_SCL4_0),
+ PINMUX_IPSR_MSEL(IP1SR8_3_0, SCK4, SEL_SCL4_0),
+
+ PINMUX_IPSR_MSEL(IP1SR8_7_4, SDA4, SEL_SDA4_0),
+ PINMUX_IPSR_MSEL(IP1SR8_7_4, HTX2, SEL_SDA4_0),
+ PINMUX_IPSR_MSEL(IP1SR8_7_4, CTS4_N, SEL_SDA4_0),
+
+ PINMUX_IPSR_MSEL(IP1SR8_11_8, SCL5, SEL_SCL5_0),
+ PINMUX_IPSR_MSEL(IP1SR8_11_8, HRTS2_N, SEL_SCL5_0),
+ PINMUX_IPSR_MSEL(IP1SR8_11_8, RTS4_N, SEL_SCL5_0),
+
+ PINMUX_IPSR_MSEL(IP1SR8_15_12, SDA5, SEL_SDA5_0),
+ PINMUX_IPSR_MSEL(IP1SR8_15_12, SCIF_CLK2, SEL_SDA5_0),
+
+ PINMUX_IPSR_GPSR(IP1SR8_19_16, HCTS2_N),
+ PINMUX_IPSR_GPSR(IP1SR8_19_16, TX4),
+
+ PINMUX_IPSR_GPSR(IP1SR8_23_20, HSCK2),
+ PINMUX_IPSR_GPSR(IP1SR8_23_20, RX4),
+};
+
+/*
+ * Pins not associated with a GPIO port.
+ */
+enum {
+ GP_ASSIGN_LAST(),
+};
+
+static const struct sh_pfc_pin pinmux_pins[] = {
+ PINMUX_GPIO_GP_ALL(),
+};
+
+/* - AVB0 ------------------------------------------------ */
+static const unsigned int avb0_link_pins[] = {
+ /* AVB0_LINK */
+ RCAR_GP_PIN(7, 4),
+};
+static const unsigned int avb0_link_mux[] = {
+ AVB0_LINK_MARK,
+};
+static const unsigned int avb0_magic_pins[] = {
+ /* AVB0_MAGIC */
+ RCAR_GP_PIN(7, 10),
+};
+static const unsigned int avb0_magic_mux[] = {
+ AVB0_MAGIC_MARK,
+};
+static const unsigned int avb0_phy_int_pins[] = {
+ /* AVB0_PHY_INT */
+ RCAR_GP_PIN(7, 5),
+};
+static const unsigned int avb0_phy_int_mux[] = {
+ AVB0_PHY_INT_MARK,
+};
+static const unsigned int avb0_mdio_pins[] = {
+ /* AVB0_MDC, AVB0_MDIO */
+ RCAR_GP_PIN(7, 13), RCAR_GP_PIN(7, 14),
+};
+static const unsigned int avb0_mdio_mux[] = {
+ AVB0_MDC_MARK, AVB0_MDIO_MARK,
+};
+static const unsigned int avb0_rgmii_pins[] = {
+ /*
+ * AVB0_TX_CTL, AVB0_TXC, AVB0_TD0, AVB0_TD1, AVB0_TD2, AVB0_TD3,
+ * AVB0_RX_CTL, AVB0_RXC, AVB0_RD0, AVB0_RD1, AVB0_RD2, AVB0_RD3,
+ */
+ RCAR_GP_PIN(7, 16), RCAR_GP_PIN(7, 15),
+ RCAR_GP_PIN(7, 11), RCAR_GP_PIN(7, 7),
+ RCAR_GP_PIN(7, 6), RCAR_GP_PIN(7, 3),
+ RCAR_GP_PIN(7, 20), RCAR_GP_PIN(7, 19),
+ RCAR_GP_PIN(7, 18), RCAR_GP_PIN(7, 17),
+ RCAR_GP_PIN(7, 12), RCAR_GP_PIN(7, 8),
+};
+static const unsigned int avb0_rgmii_mux[] = {
+ AVB0_TX_CTL_MARK, AVB0_TXC_MARK,
+ AVB0_TD0_MARK, AVB0_TD1_MARK,
+ AVB0_TD2_MARK, AVB0_TD3_MARK,
+ AVB0_RX_CTL_MARK, AVB0_RXC_MARK,
+ AVB0_RD0_MARK, AVB0_RD1_MARK,
+ AVB0_RD2_MARK, AVB0_RD3_MARK,
+};
+static const unsigned int avb0_txcrefclk_pins[] = {
+ /* AVB0_TXCREFCLK */
+ RCAR_GP_PIN(7, 9),
+};
+static const unsigned int avb0_txcrefclk_mux[] = {
+ AVB0_TXCREFCLK_MARK,
+};
+static const unsigned int avb0_avtp_pps_pins[] = {
+ /* AVB0_AVTP_PPS */
+ RCAR_GP_PIN(7, 0),
+};
+static const unsigned int avb0_avtp_pps_mux[] = {
+ AVB0_AVTP_PPS_MARK,
+};
+static const unsigned int avb0_avtp_capture_pins[] = {
+ /* AVB0_AVTP_CAPTURE */
+ RCAR_GP_PIN(7, 1),
+};
+static const unsigned int avb0_avtp_capture_mux[] = {
+ AVB0_AVTP_CAPTURE_MARK,
+};
+static const unsigned int avb0_avtp_match_pins[] = {
+ /* AVB0_AVTP_MATCH */
+ RCAR_GP_PIN(7, 2),
+};
+static const unsigned int avb0_avtp_match_mux[] = {
+ AVB0_AVTP_MATCH_MARK,
+};
+
+/* - AVB1 ------------------------------------------------ */
+static const unsigned int avb1_link_pins[] = {
+ /* AVB1_LINK */
+ RCAR_GP_PIN(6, 4),
+};
+static const unsigned int avb1_link_mux[] = {
+ AVB1_LINK_MARK,
+};
+static const unsigned int avb1_magic_pins[] = {
+ /* AVB1_MAGIC */
+ RCAR_GP_PIN(6, 1),
+};
+static const unsigned int avb1_magic_mux[] = {
+ AVB1_MAGIC_MARK,
+};
+static const unsigned int avb1_phy_int_pins[] = {
+ /* AVB1_PHY_INT */
+ RCAR_GP_PIN(6, 3),
+};
+static const unsigned int avb1_phy_int_mux[] = {
+ AVB1_PHY_INT_MARK,
+};
+static const unsigned int avb1_mdio_pins[] = {
+ /* AVB1_MDC, AVB1_MDIO */
+ RCAR_GP_PIN(6, 2), RCAR_GP_PIN(6, 0),
+};
+static const unsigned int avb1_mdio_mux[] = {
+ AVB1_MDC_MARK, AVB1_MDIO_MARK,
+};
+static const unsigned int avb1_rgmii_pins[] = {
+ /*
+ * AVB1_TX_CTL, AVB1_TXC, AVB1_TD0, AVB1_TD1, AVB1_TD2, AVB1_TD3,
+ * AVB1_RX_CTL, AVB1_RXC, AVB1_RD0, AVB1_RD1, AVB1_RD2, AVB1_RD3,
+ */
+ RCAR_GP_PIN(6, 7), RCAR_GP_PIN(6, 6),
+ RCAR_GP_PIN(6, 13), RCAR_GP_PIN(6, 12),
+ RCAR_GP_PIN(6, 16), RCAR_GP_PIN(6, 18),
+ RCAR_GP_PIN(6, 9), RCAR_GP_PIN(6, 8),
+ RCAR_GP_PIN(6, 15), RCAR_GP_PIN(6, 14),
+ RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 19),
+};
+static const unsigned int avb1_rgmii_mux[] = {
+ AVB1_TX_CTL_MARK, AVB1_TXC_MARK,
+ AVB1_TD0_MARK, AVB1_TD1_MARK,
+ AVB1_TD2_MARK, AVB1_TD3_MARK,
+ AVB1_RX_CTL_MARK, AVB1_RXC_MARK,
+ AVB1_RD0_MARK, AVB1_RD1_MARK,
+ AVB1_RD2_MARK, AVB1_RD3_MARK,
+};
+static const unsigned int avb1_txcrefclk_pins[] = {
+ /* AVB1_TXCREFCLK */
+ RCAR_GP_PIN(6, 20),
+};
+static const unsigned int avb1_txcrefclk_mux[] = {
+ AVB1_TXCREFCLK_MARK,
+};
+static const unsigned int avb1_avtp_pps_pins[] = {
+ /* AVB1_AVTP_PPS */
+ RCAR_GP_PIN(6, 10),
+};
+static const unsigned int avb1_avtp_pps_mux[] = {
+ AVB1_AVTP_PPS_MARK,
+};
+static const unsigned int avb1_avtp_capture_pins[] = {
+ /* AVB1_AVTP_CAPTURE */
+ RCAR_GP_PIN(6, 11),
+};
+static const unsigned int avb1_avtp_capture_mux[] = {
+ AVB1_AVTP_CAPTURE_MARK,
+};
+static const unsigned int avb1_avtp_match_pins[] = {
+ /* AVB1_AVTP_MATCH */
+ RCAR_GP_PIN(6, 5),
+};
+static const unsigned int avb1_avtp_match_mux[] = {
+ AVB1_AVTP_MATCH_MARK,
+};
+
+/* - AVB2 ------------------------------------------------ */
+static const unsigned int avb2_link_pins[] = {
+ /* AVB2_LINK */
+ RCAR_GP_PIN(5, 3),
+};
+static const unsigned int avb2_link_mux[] = {
+ AVB2_LINK_MARK,
+};
+static const unsigned int avb2_magic_pins[] = {
+ /* AVB2_MAGIC */
+ RCAR_GP_PIN(5, 5),
+};
+static const unsigned int avb2_magic_mux[] = {
+ AVB2_MAGIC_MARK,
+};
+static const unsigned int avb2_phy_int_pins[] = {
+ /* AVB2_PHY_INT */
+ RCAR_GP_PIN(5, 4),
+};
+static const unsigned int avb2_phy_int_mux[] = {
+ AVB2_PHY_INT_MARK,
+};
+static const unsigned int avb2_mdio_pins[] = {
+ /* AVB2_MDC, AVB2_MDIO */
+ RCAR_GP_PIN(5, 6), RCAR_GP_PIN(5, 10),
+};
+static const unsigned int avb2_mdio_mux[] = {
+ AVB2_MDC_MARK, AVB2_MDIO_MARK,
+};
+static const unsigned int avb2_rgmii_pins[] = {
+ /*
+ * AVB2_TX_CTL, AVB2_TXC, AVB2_TD0, AVB2_TD1, AVB2_TD2, AVB2_TD3,
+ * AVB2_RX_CTL, AVB2_RXC, AVB2_RD0, AVB2_RD1, AVB2_RD2, AVB2_RD3,
+ */
+ RCAR_GP_PIN(5, 19), RCAR_GP_PIN(5, 16),
+ RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 12),
+ RCAR_GP_PIN(5, 11), RCAR_GP_PIN(5, 8),
+ RCAR_GP_PIN(5, 20), RCAR_GP_PIN(5, 18),
+ RCAR_GP_PIN(5, 17), RCAR_GP_PIN(5, 14),
+ RCAR_GP_PIN(5, 13), RCAR_GP_PIN(5, 9),
+};
+static const unsigned int avb2_rgmii_mux[] = {
+ AVB2_TX_CTL_MARK, AVB2_TXC_MARK,
+ AVB2_TD0_MARK, AVB2_TD1_MARK,
+ AVB2_TD2_MARK, AVB2_TD3_MARK,
+ AVB2_RX_CTL_MARK, AVB2_RXC_MARK,
+ AVB2_RD0_MARK, AVB2_RD1_MARK,
+ AVB2_RD2_MARK, AVB2_RD3_MARK,
+};
+static const unsigned int avb2_txcrefclk_pins[] = {
+ /* AVB2_TXCREFCLK */
+ RCAR_GP_PIN(5, 7),
+};
+static const unsigned int avb2_txcrefclk_mux[] = {
+ AVB2_TXCREFCLK_MARK,
+};
+static const unsigned int avb2_avtp_pps_pins[] = {
+ /* AVB2_AVTP_PPS */
+ RCAR_GP_PIN(5, 0),
+};
+static const unsigned int avb2_avtp_pps_mux[] = {
+ AVB2_AVTP_PPS_MARK,
+};
+static const unsigned int avb2_avtp_capture_pins[] = {
+ /* AVB2_AVTP_CAPTURE */
+ RCAR_GP_PIN(5, 1),
+};
+static const unsigned int avb2_avtp_capture_mux[] = {
+ AVB2_AVTP_CAPTURE_MARK,
+};
+static const unsigned int avb2_avtp_match_pins[] = {
+ /* AVB2_AVTP_MATCH */
+ RCAR_GP_PIN(5, 2),
+};
+static const unsigned int avb2_avtp_match_mux[] = {
+ AVB2_AVTP_MATCH_MARK,
+};
+
+/* - CANFD0 ----------------------------------------------------------------- */
+static const unsigned int canfd0_data_pins[] = {
+ /* CANFD0_TX, CANFD0_RX */
+ RCAR_GP_PIN(2, 10), RCAR_GP_PIN(2, 11),
+};
+static const unsigned int canfd0_data_mux[] = {
+ CANFD0_TX_MARK, CANFD0_RX_MARK,
+};
+
+/* - CANFD1 ----------------------------------------------------------------- */
+static const unsigned int canfd1_data_pins[] = {
+ /* CANFD1_TX, CANFD1_RX */
+ RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1),
+};
+static const unsigned int canfd1_data_mux[] = {
+ CANFD1_TX_MARK, CANFD1_RX_MARK,
+};
+
+/* - CANFD2 ----------------------------------------------------------------- */
+static const unsigned int canfd2_data_pins[] = {
+ /* CANFD2_TX, CANFD2_RX */
+ RCAR_GP_PIN(2, 12), RCAR_GP_PIN(2, 13),
+};
+static const unsigned int canfd2_data_mux[] = {
+ CANFD2_TX_MARK, CANFD2_RX_MARK,
+};
+
+/* - CANFD3 ----------------------------------------------------------------- */
+static const unsigned int canfd3_data_pins[] = {
+ /* CANFD3_TX, CANFD3_RX */
+ RCAR_GP_PIN(2, 14), RCAR_GP_PIN(2, 15),
+};
+static const unsigned int canfd3_data_mux[] = {
+ CANFD3_TX_MARK, CANFD3_RX_MARK,
+};
+
+/* - CANFD4 ----------------------------------------------------------------- */
+static const unsigned int canfd4_data_pins[] = {
+ /* CANFD4_TX, CANFD4_RX */
+ RCAR_GP_PIN(2, 16), RCAR_GP_PIN(2, 17),
+};
+static const unsigned int canfd4_data_mux[] = {
+ CANFD4_TX_MARK, CANFD4_RX_MARK,
+};
+
+/* - CANFD5 ----------------------------------------------------------------- */
+static const unsigned int canfd5_data_pins[] = {
+ /* CANFD5_TX, CANFD5_RX */
+ RCAR_GP_PIN(2, 2), RCAR_GP_PIN(2, 3),
+};
+static const unsigned int canfd5_data_mux[] = {
+ CANFD5_TX_MARK, CANFD5_RX_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),
+};
+static const unsigned int canfd5_data_b_mux[] = {
+ CANFD5_TX_B_MARK, CANFD5_RX_B_MARK,
+};
+
+/* - CANFD6 ----------------------------------------------------------------- */
+static const unsigned int canfd6_data_pins[] = {
+ /* CANFD6_TX, CANFD6_RX */
+ RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 8),
+};
+static const unsigned int canfd6_data_mux[] = {
+ CANFD6_TX_MARK, CANFD6_RX_MARK,
+};
+
+/* - CANFD7 ----------------------------------------------------------------- */
+static const unsigned int canfd7_data_pins[] = {
+ /* CANFD7_TX, CANFD7_RX */
+ RCAR_GP_PIN(2, 18), RCAR_GP_PIN(2, 19),
+};
+static const unsigned int canfd7_data_mux[] = {
+ CANFD7_TX_MARK, CANFD7_RX_MARK,
+};
+
+/* - CANFD Clock ------------------------------------------------------------ */
+static const unsigned int can_clk_pins[] = {
+ /* CAN_CLK */
+ RCAR_GP_PIN(2, 9),
+};
+static const unsigned int can_clk_mux[] = {
+ CAN_CLK_MARK,
+};
+
+/* - HSCIF0 ----------------------------------------------------------------- */
+static const unsigned int hscif0_data_pins[] = {
+ /* HRX0, HTX0 */
+ RCAR_GP_PIN(1, 16), RCAR_GP_PIN(1, 12),
+};
+static const unsigned int hscif0_data_mux[] = {
+ HRX0_MARK, HTX0_MARK,
+};
+static const unsigned int hscif0_clk_pins[] = {
+ /* HSCK0 */
+ RCAR_GP_PIN(1, 15),
+};
+static const unsigned int hscif0_clk_mux[] = {
+ HSCK0_MARK,
+};
+static const unsigned int hscif0_ctrl_pins[] = {
+ /* HRTS0_N, HCTS0_N */
+ RCAR_GP_PIN(1, 14), RCAR_GP_PIN(1, 13),
+};
+static const unsigned int hscif0_ctrl_mux[] = {
+ HRTS0_N_MARK, HCTS0_N_MARK,
+};
+
+/* - HSCIF1 ----------------------------------------------------------------- */
+static const unsigned int hscif1_data_pins[] = {
+ /* HRX1, HTX1 */
+ 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_clk_pins[] = {
+ /* HSCK1 */
+ RCAR_GP_PIN(0, 18),
+};
+static const unsigned int hscif1_clk_mux[] = {
+ HSCK1_MARK,
+};
+static const unsigned int hscif1_ctrl_pins[] = {
+ /* HRTS1_N, HCTS1_N */
+ RCAR_GP_PIN(0, 17), RCAR_GP_PIN(0, 16),
+};
+static const unsigned int hscif1_ctrl_mux[] = {
+ HRTS1_N_MARK, HCTS1_N_MARK,
+};
+
+/* - HSCIF1_X---------------------------------------------------------------- */
+static const unsigned int hscif1_data_x_pins[] = {
+ /* HRX1_X, HTX1_X */
+ 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_clk_x_pins[] = {
+ /* HSCK1_X */
+ RCAR_GP_PIN(1, 10),
+};
+static const unsigned int hscif1_clk_x_mux[] = {
+ HSCK1_X_MARK,
+};
+static const unsigned int hscif1_ctrl_x_pins[] = {
+ /* HRTS1_N_X, HCTS1_N_X */
+ 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,
+};
+
+/* - HSCIF2 ----------------------------------------------------------------- */
+static const unsigned int hscif2_data_pins[] = {
+ /* HRX2, HTX2 */
+ RCAR_GP_PIN(8, 8), RCAR_GP_PIN(8, 9),
+};
+static const unsigned int hscif2_data_mux[] = {
+ HRX2_MARK, HTX2_MARK,
+};
+static const unsigned int hscif2_clk_pins[] = {
+ /* HSCK2 */
+ RCAR_GP_PIN(8, 13),
+};
+static const unsigned int hscif2_clk_mux[] = {
+ HSCK2_MARK,
+};
+static const unsigned int hscif2_ctrl_pins[] = {
+ /* HRTS2_N, HCTS2_N */
+ RCAR_GP_PIN(8, 10), RCAR_GP_PIN(8, 12),
+};
+static const unsigned int hscif2_ctrl_mux[] = {
+ HRTS2_N_MARK, HCTS2_N_MARK,
+};
+
+/* - 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),
+};
+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),
+};
+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),
+};
+static const unsigned int hscif3_ctrl_a_mux[] = {
+ HRTS3_N_A_MARK, HCTS3_N_A_MARK,
+};
+
+/* - I2C0 ------------------------------------------------------------------- */
+static const unsigned int i2c0_pins[] = {
+ /* SDA0, SCL0 */
+ RCAR_GP_PIN(8, 1), RCAR_GP_PIN(8, 0),
+};
+static const unsigned int i2c0_mux[] = {
+ SDA0_MARK, SCL0_MARK,
+};
+
+/* - I2C1 ------------------------------------------------------------------- */
+static const unsigned int i2c1_pins[] = {
+ /* SDA1, SCL1 */
+ RCAR_GP_PIN(8, 3), RCAR_GP_PIN(8, 2),
+};
+static const unsigned int i2c1_mux[] = {
+ SDA1_MARK, SCL1_MARK,
+};
+
+/* - I2C2 ------------------------------------------------------------------- */
+static const unsigned int i2c2_pins[] = {
+ /* SDA2, SCL2 */
+ RCAR_GP_PIN(8, 5), RCAR_GP_PIN(8, 4),
+};
+static const unsigned int i2c2_mux[] = {
+ SDA2_MARK, SCL2_MARK,
+};
+
+/* - I2C3 ------------------------------------------------------------------- */
+static const unsigned int i2c3_pins[] = {
+ /* SDA3, SCL3 */
+ RCAR_GP_PIN(8, 7), RCAR_GP_PIN(8, 6),
+};
+static const unsigned int i2c3_mux[] = {
+ SDA3_MARK, SCL3_MARK,
+};
+
+/* - I2C4 ------------------------------------------------------------------- */
+static const unsigned int i2c4_pins[] = {
+ /* SDA4, SCL4 */
+ RCAR_GP_PIN(8, 9), RCAR_GP_PIN(8, 8),
+};
+static const unsigned int i2c4_mux[] = {
+ SDA4_MARK, SCL4_MARK,
+};
+
+/* - I2C5 ------------------------------------------------------------------- */
+static const unsigned int i2c5_pins[] = {
+ /* SDA5, SCL5 */
+ RCAR_GP_PIN(8, 11), RCAR_GP_PIN(8, 10),
+};
+static const unsigned int i2c5_mux[] = {
+ SDA5_MARK, SCL5_MARK,
+};
+
+/* - MMC -------------------------------------------------------------------- */
+static const unsigned int mmc_data_pins[] = {
+ /* MMC_SD_D[0:3], MMC_D[4:7] */
+ RCAR_GP_PIN(3, 1), RCAR_GP_PIN(3, 0),
+ RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 5),
+ RCAR_GP_PIN(3, 7), RCAR_GP_PIN(3, 6),
+ RCAR_GP_PIN(3, 9), RCAR_GP_PIN(3, 8),
+};
+static const unsigned int mmc_data_mux[] = {
+ MMC_SD_D0_MARK, MMC_SD_D1_MARK,
+ MMC_SD_D2_MARK, MMC_SD_D3_MARK,
+ MMC_D4_MARK, MMC_D5_MARK,
+ MMC_D6_MARK, MMC_D7_MARK,
+};
+static const unsigned int mmc_ctrl_pins[] = {
+ /* MMC_SD_CLK, MMC_SD_CMD */
+ RCAR_GP_PIN(3, 3), RCAR_GP_PIN(3, 10),
+};
+static const unsigned int mmc_ctrl_mux[] = {
+ MMC_SD_CLK_MARK, MMC_SD_CMD_MARK,
+};
+static const unsigned int mmc_cd_pins[] = {
+ /* SD_CD */
+ RCAR_GP_PIN(3, 11),
+};
+static const unsigned int mmc_cd_mux[] = {
+ SD_CD_MARK,
+};
+static const unsigned int mmc_wp_pins[] = {
+ /* SD_WP */
+ RCAR_GP_PIN(3, 12),
+};
+static const unsigned int mmc_wp_mux[] = {
+ SD_WP_MARK,
+};
+static const unsigned int mmc_ds_pins[] = {
+ /* MMC_DS */
+ RCAR_GP_PIN(3, 4),
+};
+static const unsigned int mmc_ds_mux[] = {
+ MMC_DS_MARK,
+};
+
+/* - MSIOF0 ----------------------------------------------------------------- */
+static const unsigned int msiof0_clk_pins[] = {
+ /* MSIOF0_SCK */
+ RCAR_GP_PIN(1, 10),
+};
+static const unsigned int msiof0_clk_mux[] = {
+ MSIOF0_SCK_MARK,
+};
+static const unsigned int msiof0_sync_pins[] = {
+ /* MSIOF0_SYNC */
+ RCAR_GP_PIN(1, 8),
+};
+static const unsigned int msiof0_sync_mux[] = {
+ MSIOF0_SYNC_MARK,
+};
+static const unsigned int msiof0_ss1_pins[] = {
+ /* MSIOF0_SS1 */
+ RCAR_GP_PIN(1, 7),
+};
+static const unsigned int msiof0_ss1_mux[] = {
+ MSIOF0_SS1_MARK,
+};
+static const unsigned int msiof0_ss2_pins[] = {
+ /* MSIOF0_SS2 */
+ RCAR_GP_PIN(1, 6),
+};
+static const unsigned int msiof0_ss2_mux[] = {
+ MSIOF0_SS2_MARK,
+};
+static const unsigned int msiof0_txd_pins[] = {
+ /* MSIOF0_TXD */
+ RCAR_GP_PIN(1, 9),
+};
+static const unsigned int msiof0_txd_mux[] = {
+ MSIOF0_TXD_MARK,
+};
+static const unsigned int msiof0_rxd_pins[] = {
+ /* MSIOF0_RXD */
+ RCAR_GP_PIN(1, 11),
+};
+static const unsigned int msiof0_rxd_mux[] = {
+ MSIOF0_RXD_MARK,
+};
+
+/* - MSIOF1 ----------------------------------------------------------------- */
+static const unsigned int msiof1_clk_pins[] = {
+ /* MSIOF1_SCK */
+ RCAR_GP_PIN(1, 3),
+};
+static const unsigned int msiof1_clk_mux[] = {
+ MSIOF1_SCK_MARK,
+};
+static const unsigned int msiof1_sync_pins[] = {
+ /* MSIOF1_SYNC */
+ RCAR_GP_PIN(1, 2),
+};
+static const unsigned int msiof1_sync_mux[] = {
+ MSIOF1_SYNC_MARK,
+};
+static const unsigned int msiof1_ss1_pins[] = {
+ /* MSIOF1_SS1 */
+ RCAR_GP_PIN(1, 1),
+};
+static const unsigned int msiof1_ss1_mux[] = {
+ MSIOF1_SS1_MARK,
+};
+static const unsigned int msiof1_ss2_pins[] = {
+ /* MSIOF1_SS2 */
+ RCAR_GP_PIN(1, 0),
+};
+static const unsigned int msiof1_ss2_mux[] = {
+ MSIOF1_SS2_MARK,
+};
+static const unsigned int msiof1_txd_pins[] = {
+ /* MSIOF1_TXD */
+ RCAR_GP_PIN(1, 4),
+};
+static const unsigned int msiof1_txd_mux[] = {
+ MSIOF1_TXD_MARK,
+};
+static const unsigned int msiof1_rxd_pins[] = {
+ /* MSIOF1_RXD */
+ RCAR_GP_PIN(1, 5),
+};
+static const unsigned int msiof1_rxd_mux[] = {
+ MSIOF1_RXD_MARK,
+};
+
+/* - MSIOF2 ----------------------------------------------------------------- */
+static const unsigned int msiof2_clk_pins[] = {
+ /* MSIOF2_SCK */
+ RCAR_GP_PIN(0, 17),
+};
+static const unsigned int msiof2_clk_mux[] = {
+ MSIOF2_SCK_MARK,
+};
+static const unsigned int msiof2_sync_pins[] = {
+ /* MSIOF2_SYNC */
+ RCAR_GP_PIN(0, 15),
+};
+static const unsigned int msiof2_sync_mux[] = {
+ MSIOF2_SYNC_MARK,
+};
+static const unsigned int msiof2_ss1_pins[] = {
+ /* MSIOF2_SS1 */
+ RCAR_GP_PIN(0, 14),
+};
+static const unsigned int msiof2_ss1_mux[] = {
+ MSIOF2_SS1_MARK,
+};
+static const unsigned int msiof2_ss2_pins[] = {
+ /* MSIOF2_SS2 */
+ RCAR_GP_PIN(0, 13),
+};
+static const unsigned int msiof2_ss2_mux[] = {
+ MSIOF2_SS2_MARK,
+};
+static const unsigned int msiof2_txd_pins[] = {
+ /* MSIOF2_TXD */
+ RCAR_GP_PIN(0, 16),
+};
+static const unsigned int msiof2_txd_mux[] = {
+ MSIOF2_TXD_MARK,
+};
+static const unsigned int msiof2_rxd_pins[] = {
+ /* MSIOF2_RXD */
+ RCAR_GP_PIN(0, 18),
+};
+static const unsigned int msiof2_rxd_mux[] = {
+ MSIOF2_RXD_MARK,
+};
+
+/* - MSIOF3 ----------------------------------------------------------------- */
+static const unsigned int msiof3_clk_pins[] = {
+ /* MSIOF3_SCK */
+ RCAR_GP_PIN(0, 3),
+};
+static const unsigned int msiof3_clk_mux[] = {
+ MSIOF3_SCK_MARK,
+};
+static const unsigned int msiof3_sync_pins[] = {
+ /* MSIOF3_SYNC */
+ RCAR_GP_PIN(0, 6),
+};
+static const unsigned int msiof3_sync_mux[] = {
+ MSIOF3_SYNC_MARK,
+};
+static const unsigned int msiof3_ss1_pins[] = {
+ /* MSIOF3_SS1 */
+ RCAR_GP_PIN(0, 1),
+};
+static const unsigned int msiof3_ss1_mux[] = {
+ MSIOF3_SS1_MARK,
+};
+static const unsigned int msiof3_ss2_pins[] = {
+ /* MSIOF3_SS2 */
+ RCAR_GP_PIN(0, 2),
+};
+static const unsigned int msiof3_ss2_mux[] = {
+ MSIOF3_SS2_MARK,
+};
+static const unsigned int msiof3_txd_pins[] = {
+ /* MSIOF3_TXD */
+ RCAR_GP_PIN(0, 4),
+};
+static const unsigned int msiof3_txd_mux[] = {
+ MSIOF3_TXD_MARK,
+};
+static const unsigned int msiof3_rxd_pins[] = {
+ /* MSIOF3_RXD */
+ RCAR_GP_PIN(0, 5),
+};
+static const unsigned int msiof3_rxd_mux[] = {
+ MSIOF3_RXD_MARK,
+};
+
+/* - MSIOF4 ----------------------------------------------------------------- */
+static const unsigned int msiof4_clk_pins[] = {
+ /* MSIOF4_SCK */
+ RCAR_GP_PIN(1, 25),
+};
+static const unsigned int msiof4_clk_mux[] = {
+ MSIOF4_SCK_MARK,
+};
+static const unsigned int msiof4_sync_pins[] = {
+ /* MSIOF4_SYNC */
+ RCAR_GP_PIN(1, 28),
+};
+static const unsigned int msiof4_sync_mux[] = {
+ MSIOF4_SYNC_MARK,
+};
+static const unsigned int msiof4_ss1_pins[] = {
+ /* MSIOF4_SS1 */
+ RCAR_GP_PIN(1, 23),
+};
+static const unsigned int msiof4_ss1_mux[] = {
+ MSIOF4_SS1_MARK,
+};
+static const unsigned int msiof4_ss2_pins[] = {
+ /* MSIOF4_SS2 */
+ RCAR_GP_PIN(1, 24),
+};
+static const unsigned int msiof4_ss2_mux[] = {
+ MSIOF4_SS2_MARK,
+};
+static const unsigned int msiof4_txd_pins[] = {
+ /* MSIOF4_TXD */
+ RCAR_GP_PIN(1, 26),
+};
+static const unsigned int msiof4_txd_mux[] = {
+ MSIOF4_TXD_MARK,
+};
+static const unsigned int msiof4_rxd_pins[] = {
+ /* MSIOF4_RXD */
+ RCAR_GP_PIN(1, 27),
+};
+static const unsigned int msiof4_rxd_mux[] = {
+ MSIOF4_RXD_MARK,
+};
+
+/* - MSIOF5 ----------------------------------------------------------------- */
+static const unsigned int msiof5_clk_pins[] = {
+ /* MSIOF5_SCK */
+ RCAR_GP_PIN(0, 11),
+};
+static const unsigned int msiof5_clk_mux[] = {
+ MSIOF5_SCK_MARK,
+};
+static const unsigned int msiof5_sync_pins[] = {
+ /* MSIOF5_SYNC */
+ RCAR_GP_PIN(0, 9),
+};
+static const unsigned int msiof5_sync_mux[] = {
+ MSIOF5_SYNC_MARK,
+};
+static const unsigned int msiof5_ss1_pins[] = {
+ /* MSIOF5_SS1 */
+ RCAR_GP_PIN(0, 8),
+};
+static const unsigned int msiof5_ss1_mux[] = {
+ MSIOF5_SS1_MARK,
+};
+static const unsigned int msiof5_ss2_pins[] = {
+ /* MSIOF5_SS2 */
+ RCAR_GP_PIN(0, 7),
+};
+static const unsigned int msiof5_ss2_mux[] = {
+ MSIOF5_SS2_MARK,
+};
+static const unsigned int msiof5_txd_pins[] = {
+ /* MSIOF5_TXD */
+ RCAR_GP_PIN(0, 10),
+};
+static const unsigned int msiof5_txd_mux[] = {
+ MSIOF5_TXD_MARK,
+};
+static const unsigned int msiof5_rxd_pins[] = {
+ /* MSIOF5_RXD */
+ RCAR_GP_PIN(0, 12),
+};
+static const unsigned int msiof5_rxd_mux[] = {
+ MSIOF5_RXD_MARK,
+};
+
+/* - PCIE ------------------------------------------------------------------- */
+static const unsigned int pcie0_clkreq_n_pins[] = {
+ /* PCIE0_CLKREQ_N */
+ RCAR_GP_PIN(4, 21),
+};
+
+static const unsigned int pcie0_clkreq_n_mux[] = {
+ PCIE0_CLKREQ_N_MARK,
+};
+
+static const unsigned int pcie1_clkreq_n_pins[] = {
+ /* PCIE1_CLKREQ_N */
+ RCAR_GP_PIN(4, 22),
+};
+
+static const unsigned int pcie1_clkreq_n_mux[] = {
+ PCIE1_CLKREQ_N_MARK,
+};
+
+/* - PWM0_A ------------------------------------------------------------------- */
+static const unsigned int pwm0_a_pins[] = {
+ /* PWM0_A */
+ RCAR_GP_PIN(1, 15),
+};
+static const unsigned int pwm0_a_mux[] = {
+ PWM0_A_MARK,
+};
+
+/* - PWM1_A ------------------------------------------------------------------- */
+static const unsigned int pwm1_a_pins[] = {
+ /* PWM1_A */
+ RCAR_GP_PIN(3, 13),
+};
+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),
+};
+static const unsigned int pwm1_b_mux[] = {
+ PWM1_B_MARK,
+};
+
+/* - PWM2_B ------------------------------------------------------------------- */
+static const unsigned int pwm2_b_pins[] = {
+ /* PWM2_B */
+ RCAR_GP_PIN(2, 14),
+};
+static const unsigned int pwm2_b_mux[] = {
+ PWM2_B_MARK,
+};
+
+/* - PWM3_A ------------------------------------------------------------------- */
+static const unsigned int pwm3_a_pins[] = {
+ /* PWM3_A */
+ RCAR_GP_PIN(1, 22),
+};
+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),
+};
+static const unsigned int pwm3_b_mux[] = {
+ PWM3_B_MARK,
+};
+
+/* - PWM4 ------------------------------------------------------------------- */
+static const unsigned int pwm4_pins[] = {
+ /* PWM4 */
+ RCAR_GP_PIN(2, 16),
+};
+static const unsigned int pwm4_mux[] = {
+ PWM4_MARK,
+};
+
+/* - PWM5 ------------------------------------------------------------------- */
+static const unsigned int pwm5_pins[] = {
+ /* PWM5 */
+ RCAR_GP_PIN(2, 17),
+};
+static const unsigned int pwm5_mux[] = {
+ PWM5_MARK,
+};
+
+/* - PWM6 ------------------------------------------------------------------- */
+static const unsigned int pwm6_pins[] = {
+ /* PWM6 */
+ RCAR_GP_PIN(2, 18),
+};
+static const unsigned int pwm6_mux[] = {
+ PWM6_MARK,
+};
+
+/* - PWM7 ------------------------------------------------------------------- */
+static const unsigned int pwm7_pins[] = {
+ /* PWM7 */
+ RCAR_GP_PIN(2, 19),
+};
+static const unsigned int pwm7_mux[] = {
+ PWM7_MARK,
+};
+
+/* - PWM8_A ------------------------------------------------------------------- */
+static const unsigned int pwm8_a_pins[] = {
+ /* PWM8_A */
+ RCAR_GP_PIN(1, 13),
+};
+static const unsigned int pwm8_a_mux[] = {
+ PWM8_A_MARK,
+};
+
+/* - PWM9_A ------------------------------------------------------------------- */
+static const unsigned int pwm9_a_pins[] = {
+ /* PWM9_A */
+ RCAR_GP_PIN(1, 14),
+};
+static const unsigned int pwm9_a_mux[] = {
+ PWM9_A_MARK,
+};
+
+/* - QSPI0 ------------------------------------------------------------------ */
+static const unsigned int qspi0_ctrl_pins[] = {
+ /* SPCLK, SSL */
+ RCAR_GP_PIN(3, 20), RCAR_GP_PIN(3, 15),
+};
+static const unsigned int qspi0_ctrl_mux[] = {
+ QSPI0_SPCLK_MARK, QSPI0_SSL_MARK,
+};
+static const unsigned int qspi0_data_pins[] = {
+ /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+ RCAR_GP_PIN(3, 19), RCAR_GP_PIN(3, 18),
+ RCAR_GP_PIN(3, 17), RCAR_GP_PIN(3, 16),
+};
+static const unsigned int qspi0_data_mux[] = {
+ QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK,
+ QSPI0_IO2_MARK, QSPI0_IO3_MARK
+};
+
+/* - QSPI1 ------------------------------------------------------------------ */
+static const unsigned int qspi1_ctrl_pins[] = {
+ /* SPCLK, SSL */
+ RCAR_GP_PIN(3, 22), RCAR_GP_PIN(3, 25),
+};
+static const unsigned int qspi1_ctrl_mux[] = {
+ QSPI1_SPCLK_MARK, QSPI1_SSL_MARK,
+};
+static const unsigned int qspi1_data_pins[] = {
+ /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+ RCAR_GP_PIN(3, 21), RCAR_GP_PIN(3, 23),
+ RCAR_GP_PIN(3, 24), RCAR_GP_PIN(3, 26),
+};
+static const unsigned int qspi1_data_mux[] = {
+ QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK,
+ QSPI1_IO2_MARK, QSPI1_IO3_MARK
+};
+
+/* - SCIF0 ------------------------------------------------------------------ */
+static const unsigned int scif0_data_pins[] = {
+ /* RX0, TX0 */
+ RCAR_GP_PIN(1, 16), RCAR_GP_PIN(1, 12),
+};
+static const unsigned int scif0_data_mux[] = {
+ RX0_MARK, TX0_MARK,
+};
+static const unsigned int scif0_clk_pins[] = {
+ /* SCK0 */
+ RCAR_GP_PIN(1, 15),
+};
+static const unsigned int scif0_clk_mux[] = {
+ SCK0_MARK,
+};
+static const unsigned int scif0_ctrl_pins[] = {
+ /* RTS0_N, CTS0_N */
+ RCAR_GP_PIN(1, 14), RCAR_GP_PIN(1, 13),
+};
+static const unsigned int scif0_ctrl_mux[] = {
+ RTS0_N_MARK, CTS0_N_MARK,
+};
+
+/* - SCIF1 ------------------------------------------------------------------ */
+static const unsigned int scif1_data_pins[] = {
+ /* RX1, TX1 */
+ 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_clk_pins[] = {
+ /* SCK1 */
+ RCAR_GP_PIN(0, 18),
+};
+static const unsigned int scif1_clk_mux[] = {
+ SCK1_MARK,
+};
+static const unsigned int scif1_ctrl_pins[] = {
+ /* RTS1_N, CTS1_N */
+ RCAR_GP_PIN(0, 17), RCAR_GP_PIN(0, 16),
+};
+static const unsigned int scif1_ctrl_mux[] = {
+ RTS1_N_MARK, CTS1_N_MARK,
+};
+
+/* - SCIF1_X ------------------------------------------------------------------ */
+static const unsigned int scif1_data_x_pins[] = {
+ /* RX1_X, TX1_X */
+ 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_clk_x_pins[] = {
+ /* SCK1_X */
+ RCAR_GP_PIN(1, 10),
+};
+static const unsigned int scif1_clk_x_mux[] = {
+ SCK1_X_MARK,
+};
+static const unsigned int scif1_ctrl_x_pins[] = {
+ /* RTS1_N_X, CTS1_N_X */
+ 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,
+};
+
+/* - 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),
+};
+static const unsigned int scif3_data_a_mux[] = {
+ RX3_A_MARK, TX3_A_MARK,
+};
+static const unsigned int scif3_clk_a_pins[] = {
+ /* SCK3_A */
+ RCAR_GP_PIN(1, 24),
+};
+static const unsigned int scif3_clk_a_mux[] = {
+ SCK3_A_MARK,
+};
+static const unsigned int scif3_ctrl_a_pins[] = {
+ /* RTS3_N_A, CTS3_N_A */
+ RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 25),
+};
+static const unsigned int scif3_ctrl_a_mux[] = {
+ RTS3_N_A_MARK, CTS3_N_A_MARK,
+};
+
+/* - SCIF4 ------------------------------------------------------------------ */
+static const unsigned int scif4_data_pins[] = {
+ /* RX4, TX4 */
+ RCAR_GP_PIN(8, 13), RCAR_GP_PIN(8, 12),
+};
+static const unsigned int scif4_data_mux[] = {
+ RX4_MARK, TX4_MARK,
+};
+static const unsigned int scif4_clk_pins[] = {
+ /* SCK4 */
+ RCAR_GP_PIN(8, 8),
+};
+static const unsigned int scif4_clk_mux[] = {
+ SCK4_MARK,
+};
+static const unsigned int scif4_ctrl_pins[] = {
+ /* RTS4_N, CTS4_N */
+ RCAR_GP_PIN(8, 10), RCAR_GP_PIN(8, 9),
+};
+static const unsigned int scif4_ctrl_mux[] = {
+ RTS4_N_MARK, CTS4_N_MARK,
+};
+
+/* - SCIF Clock ------------------------------------------------------------- */
+static const unsigned int scif_clk_pins[] = {
+ /* SCIF_CLK */
+ RCAR_GP_PIN(1, 17),
+};
+static const unsigned int scif_clk_mux[] = {
+ SCIF_CLK_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 ------------------------------------------------------------------- */
+static const unsigned int tpu_to0_a_pins[] = {
+ /* TPU0TO0_A */
+ RCAR_GP_PIN(1, 25),
+};
+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),
+};
+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),
+};
+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),
+};
+static const unsigned int tpu_to3_a_mux[] = {
+ TPU0TO3_A_MARK,
+};
+
+/* - TSN0 ------------------------------------------------ */
+static const unsigned int tsn0_link_pins[] = {
+ /* TSN0_LINK */
+ RCAR_GP_PIN(4, 4),
+};
+static const unsigned int tsn0_link_mux[] = {
+ TSN0_LINK_MARK,
+};
+static const unsigned int tsn0_phy_int_pins[] = {
+ /* TSN0_PHY_INT */
+ RCAR_GP_PIN(4, 3),
+};
+static const unsigned int tsn0_phy_int_mux[] = {
+ TSN0_PHY_INT_MARK,
+};
+static const unsigned int tsn0_mdio_pins[] = {
+ /* TSN0_MDC, TSN0_MDIO */
+ RCAR_GP_PIN(4, 1), RCAR_GP_PIN(4, 0),
+};
+static const unsigned int tsn0_mdio_mux[] = {
+ TSN0_MDC_MARK, TSN0_MDIO_MARK,
+};
+static const unsigned int tsn0_rgmii_pins[] = {
+ /*
+ * TSN0_TX_CTL, TSN0_TXC, TSN0_TD0, TSN0_TD1, TSN0_TD2, TSN0_TD3,
+ * TSN0_RX_CTL, TSN0_RXC, TSN0_RD0, TSN0_RD1, TSN0_RD2, TSN0_RD3,
+ */
+ RCAR_GP_PIN(4, 9), RCAR_GP_PIN(4, 12),
+ RCAR_GP_PIN(4, 15), RCAR_GP_PIN(4, 14),
+ RCAR_GP_PIN(4, 19), RCAR_GP_PIN(4, 18),
+ RCAR_GP_PIN(4, 7), RCAR_GP_PIN(4, 11),
+ RCAR_GP_PIN(4, 10), RCAR_GP_PIN(4, 13),
+ RCAR_GP_PIN(4, 17), RCAR_GP_PIN(4, 16),
+};
+static const unsigned int tsn0_rgmii_mux[] = {
+ TSN0_TX_CTL_MARK, TSN0_TXC_MARK,
+ TSN0_TD0_MARK, TSN0_TD1_MARK,
+ TSN0_TD2_MARK, TSN0_TD3_MARK,
+ TSN0_RX_CTL_MARK, TSN0_RXC_MARK,
+ TSN0_RD0_MARK, TSN0_RD1_MARK,
+ TSN0_RD2_MARK, TSN0_RD3_MARK,
+};
+static const unsigned int tsn0_txcrefclk_pins[] = {
+ /* TSN0_TXCREFCLK */
+ RCAR_GP_PIN(4, 20),
+};
+static const unsigned int tsn0_txcrefclk_mux[] = {
+ TSN0_TXCREFCLK_MARK,
+};
+static const unsigned int tsn0_avtp_pps_pins[] = {
+ /* TSN0_AVTP_PPS0, TSN0_AVTP_PPS1 */
+ RCAR_GP_PIN(4, 8), RCAR_GP_PIN(4, 2),
+};
+static const unsigned int tsn0_avtp_pps_mux[] = {
+ TSN0_AVTP_PPS0_MARK, TSN0_AVTP_PPS1_MARK,
+};
+static const unsigned int tsn0_avtp_capture_pins[] = {
+ /* TSN0_AVTP_CAPTURE */
+ RCAR_GP_PIN(4, 6),
+};
+static const unsigned int tsn0_avtp_capture_mux[] = {
+ TSN0_AVTP_CAPTURE_MARK,
+};
+static const unsigned int tsn0_avtp_match_pins[] = {
+ /* TSN0_AVTP_MATCH */
+ RCAR_GP_PIN(4, 5),
+};
+static const unsigned int tsn0_avtp_match_mux[] = {
+ TSN0_AVTP_MATCH_MARK,
+};
+
+static const struct sh_pfc_pin_group pinmux_groups[] = {
+ SH_PFC_PIN_GROUP(avb0_link),
+ SH_PFC_PIN_GROUP(avb0_magic),
+ SH_PFC_PIN_GROUP(avb0_phy_int),
+ SH_PFC_PIN_GROUP(avb0_mdio),
+ SH_PFC_PIN_GROUP(avb0_rgmii),
+ SH_PFC_PIN_GROUP(avb0_txcrefclk),
+ SH_PFC_PIN_GROUP(avb0_avtp_pps),
+ SH_PFC_PIN_GROUP(avb0_avtp_capture),
+ SH_PFC_PIN_GROUP(avb0_avtp_match),
+
+ SH_PFC_PIN_GROUP(avb1_link),
+ SH_PFC_PIN_GROUP(avb1_magic),
+ SH_PFC_PIN_GROUP(avb1_phy_int),
+ SH_PFC_PIN_GROUP(avb1_mdio),
+ SH_PFC_PIN_GROUP(avb1_rgmii),
+ SH_PFC_PIN_GROUP(avb1_txcrefclk),
+ SH_PFC_PIN_GROUP(avb1_avtp_pps),
+ SH_PFC_PIN_GROUP(avb1_avtp_capture),
+ SH_PFC_PIN_GROUP(avb1_avtp_match),
+
+ SH_PFC_PIN_GROUP(avb2_link),
+ SH_PFC_PIN_GROUP(avb2_magic),
+ SH_PFC_PIN_GROUP(avb2_phy_int),
+ SH_PFC_PIN_GROUP(avb2_mdio),
+ SH_PFC_PIN_GROUP(avb2_rgmii),
+ SH_PFC_PIN_GROUP(avb2_txcrefclk),
+ SH_PFC_PIN_GROUP(avb2_avtp_pps),
+ SH_PFC_PIN_GROUP(avb2_avtp_capture),
+ SH_PFC_PIN_GROUP(avb2_avtp_match),
+
+ SH_PFC_PIN_GROUP(canfd0_data),
+ SH_PFC_PIN_GROUP(canfd1_data),
+ 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(canfd6_data),
+ SH_PFC_PIN_GROUP(canfd7_data),
+ SH_PFC_PIN_GROUP(can_clk),
+
+ 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(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(i2c0),
+ SH_PFC_PIN_GROUP(i2c1),
+ SH_PFC_PIN_GROUP(i2c2),
+ SH_PFC_PIN_GROUP(i2c3),
+ SH_PFC_PIN_GROUP(i2c4),
+ SH_PFC_PIN_GROUP(i2c5),
+
+ BUS_DATA_PIN_GROUP(mmc_data, 1),
+ BUS_DATA_PIN_GROUP(mmc_data, 4),
+ BUS_DATA_PIN_GROUP(mmc_data, 8),
+ SH_PFC_PIN_GROUP(mmc_ctrl),
+ SH_PFC_PIN_GROUP(mmc_cd),
+ SH_PFC_PIN_GROUP(mmc_wp),
+ SH_PFC_PIN_GROUP(mmc_ds),
+
+ SH_PFC_PIN_GROUP(msiof0_clk),
+ SH_PFC_PIN_GROUP(msiof0_sync),
+ SH_PFC_PIN_GROUP(msiof0_ss1),
+ SH_PFC_PIN_GROUP(msiof0_ss2),
+ SH_PFC_PIN_GROUP(msiof0_txd),
+ SH_PFC_PIN_GROUP(msiof0_rxd),
+
+ SH_PFC_PIN_GROUP(msiof1_clk),
+ SH_PFC_PIN_GROUP(msiof1_sync),
+ SH_PFC_PIN_GROUP(msiof1_ss1),
+ SH_PFC_PIN_GROUP(msiof1_ss2),
+ SH_PFC_PIN_GROUP(msiof1_txd),
+ SH_PFC_PIN_GROUP(msiof1_rxd),
+
+ SH_PFC_PIN_GROUP(msiof2_clk),
+ SH_PFC_PIN_GROUP(msiof2_sync),
+ SH_PFC_PIN_GROUP(msiof2_ss1),
+ SH_PFC_PIN_GROUP(msiof2_ss2),
+ SH_PFC_PIN_GROUP(msiof2_txd),
+ SH_PFC_PIN_GROUP(msiof2_rxd),
+
+ SH_PFC_PIN_GROUP(msiof3_clk),
+ SH_PFC_PIN_GROUP(msiof3_sync),
+ SH_PFC_PIN_GROUP(msiof3_ss1),
+ SH_PFC_PIN_GROUP(msiof3_ss2),
+ SH_PFC_PIN_GROUP(msiof3_txd),
+ SH_PFC_PIN_GROUP(msiof3_rxd),
+
+ SH_PFC_PIN_GROUP(msiof4_clk),
+ SH_PFC_PIN_GROUP(msiof4_sync),
+ SH_PFC_PIN_GROUP(msiof4_ss1),
+ SH_PFC_PIN_GROUP(msiof4_ss2),
+ SH_PFC_PIN_GROUP(msiof4_txd),
+ SH_PFC_PIN_GROUP(msiof4_rxd),
+
+ SH_PFC_PIN_GROUP(msiof5_clk),
+ SH_PFC_PIN_GROUP(msiof5_sync),
+ SH_PFC_PIN_GROUP(msiof5_ss1),
+ SH_PFC_PIN_GROUP(msiof5_ss2),
+ SH_PFC_PIN_GROUP(msiof5_txd),
+ SH_PFC_PIN_GROUP(msiof5_rxd),
+
+ 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(pwm1_a),
+ SH_PFC_PIN_GROUP(pwm1_b),
+ SH_PFC_PIN_GROUP(pwm2_b), /* suffix might be updated */
+ 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(qspi0_ctrl),
+ BUS_DATA_PIN_GROUP(qspi0_data, 2),
+ BUS_DATA_PIN_GROUP(qspi0_data, 4),
+ SH_PFC_PIN_GROUP(qspi1_ctrl),
+ BUS_DATA_PIN_GROUP(qspi1_data, 2),
+ BUS_DATA_PIN_GROUP(qspi1_data, 4),
+
+ 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(scif4_data),
+ SH_PFC_PIN_GROUP(scif4_clk),
+ SH_PFC_PIN_GROUP(scif4_ctrl),
+ SH_PFC_PIN_GROUP(scif_clk),
+
+ 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(tsn0_link),
+ SH_PFC_PIN_GROUP(tsn0_phy_int),
+ SH_PFC_PIN_GROUP(tsn0_mdio),
+ SH_PFC_PIN_GROUP(tsn0_rgmii),
+ SH_PFC_PIN_GROUP(tsn0_txcrefclk),
+ SH_PFC_PIN_GROUP(tsn0_avtp_pps),
+ SH_PFC_PIN_GROUP(tsn0_avtp_capture),
+ SH_PFC_PIN_GROUP(tsn0_avtp_match),
+};
+
+static const char * const avb0_groups[] = {
+ "avb0_link",
+ "avb0_magic",
+ "avb0_phy_int",
+ "avb0_mdio",
+ "avb0_rgmii",
+ "avb0_txcrefclk",
+ "avb0_avtp_pps",
+ "avb0_avtp_capture",
+ "avb0_avtp_match",
+};
+
+static const char * const avb1_groups[] = {
+ "avb1_link",
+ "avb1_magic",
+ "avb1_phy_int",
+ "avb1_mdio",
+ "avb1_rgmii",
+ "avb1_txcrefclk",
+ "avb1_avtp_pps",
+ "avb1_avtp_capture",
+ "avb1_avtp_match",
+};
+
+static const char * const avb2_groups[] = {
+ "avb2_link",
+ "avb2_magic",
+ "avb2_phy_int",
+ "avb2_mdio",
+ "avb2_rgmii",
+ "avb2_txcrefclk",
+ "avb2_avtp_pps",
+ "avb2_avtp_capture",
+ "avb2_avtp_match",
+};
+
+static const char * const canfd0_groups[] = {
+ "canfd0_data",
+};
+
+static const char * const canfd1_groups[] = {
+ "canfd1_data",
+};
+
+static const char * const canfd2_groups[] = {
+ "canfd2_data",
+};
+
+static const char * const canfd3_groups[] = {
+ "canfd3_data",
+};
+
+static const char * const canfd4_groups[] = {
+ "canfd4_data",
+};
+
+static const char * const canfd5_groups[] = {
+ /* suffix might be updated */
+ "canfd5_data",
+ "canfd5_data_b",
+};
+
+static const char * const canfd6_groups[] = {
+ "canfd6_data",
+};
+
+static const char * const canfd7_groups[] = {
+ "canfd7_data",
+};
+
+static const char * const can_clk_groups[] = {
+ "can_clk",
+};
+
+static const char * const hscif0_groups[] = {
+ "hscif0_data",
+ "hscif0_clk",
+ "hscif0_ctrl",
+};
+
+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",
+};
+
+static const char * const hscif2_groups[] = {
+ "hscif2_data",
+ "hscif2_clk",
+ "hscif2_ctrl",
+};
+
+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",
+};
+
+static const char * const i2c0_groups[] = {
+ "i2c0",
+};
+
+static const char * const i2c1_groups[] = {
+ "i2c1",
+};
+
+static const char * const i2c2_groups[] = {
+ "i2c2",
+};
+
+static const char * const i2c3_groups[] = {
+ "i2c3",
+};
+
+static const char * const i2c4_groups[] = {
+ "i2c4",
+};
+
+static const char * const i2c5_groups[] = {
+ "i2c5",
+};
+
+static const char * const mmc_groups[] = {
+ "mmc_data1",
+ "mmc_data4",
+ "mmc_data8",
+ "mmc_ctrl",
+ "mmc_cd",
+ "mmc_wp",
+ "mmc_ds",
+};
+
+static const char * const msiof0_groups[] = {
+ "msiof0_clk",
+ "msiof0_sync",
+ "msiof0_ss1",
+ "msiof0_ss2",
+ "msiof0_txd",
+ "msiof0_rxd",
+};
+
+static const char * const msiof1_groups[] = {
+ "msiof1_clk",
+ "msiof1_sync",
+ "msiof1_ss1",
+ "msiof1_ss2",
+ "msiof1_txd",
+ "msiof1_rxd",
+};
+
+static const char * const msiof2_groups[] = {
+ "msiof2_clk",
+ "msiof2_sync",
+ "msiof2_ss1",
+ "msiof2_ss2",
+ "msiof2_txd",
+ "msiof2_rxd",
+};
+
+static const char * const msiof3_groups[] = {
+ "msiof3_clk",
+ "msiof3_sync",
+ "msiof3_ss1",
+ "msiof3_ss2",
+ "msiof3_txd",
+ "msiof3_rxd",
+};
+
+static const char * const msiof4_groups[] = {
+ "msiof4_clk",
+ "msiof4_sync",
+ "msiof4_ss1",
+ "msiof4_ss2",
+ "msiof4_txd",
+ "msiof4_rxd",
+};
+
+static const char * const msiof5_groups[] = {
+ "msiof5_clk",
+ "msiof5_sync",
+ "msiof5_ss1",
+ "msiof5_ss2",
+ "msiof5_txd",
+ "msiof5_rxd",
+};
+
+static const char * const pcie_groups[] = {
+ "pcie0_clkreq_n",
+ "pcie1_clkreq_n",
+};
+
+static const char * const pwm0_groups[] = {
+ /* suffix might be updated */
+ "pwm0_a",
+};
+
+static const char * const pwm1_groups[] = {
+ "pwm1_a",
+ "pwm1_b",
+};
+
+static const char * const pwm2_groups[] = {
+ /* suffix might be updated */
+ "pwm2_b",
+};
+
+static const char * const pwm3_groups[] = {
+ "pwm3_a",
+ "pwm3_b",
+};
+
+static const char * const pwm4_groups[] = {
+ "pwm4",
+};
+
+static const char * const pwm5_groups[] = {
+ "pwm5",
+};
+
+static const char * const pwm6_groups[] = {
+ "pwm6",
+};
+
+static const char * const pwm7_groups[] = {
+ "pwm7",
+};
+
+static const char * const pwm8_groups[] = {
+ /* suffix might be updated */
+ "pwm8_a",
+};
+
+static const char * const pwm9_groups[] = {
+ /* suffix might be updated */
+ "pwm9_a",
+};
+
+static const char * const qspi0_groups[] = {
+ "qspi0_ctrl",
+ "qspi0_data2",
+ "qspi0_data4",
+};
+
+static const char * const qspi1_groups[] = {
+ "qspi1_ctrl",
+ "qspi1_data2",
+ "qspi1_data4",
+};
+
+static const char * const scif0_groups[] = {
+ "scif0_data",
+ "scif0_clk",
+ "scif0_ctrl",
+};
+
+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",
+};
+
+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",
+};
+
+static const char * const scif4_groups[] = {
+ "scif4_data",
+ "scif4_clk",
+ "scif4_ctrl",
+};
+
+static const char * const scif_clk_groups[] = {
+ "scif_clk",
+};
+
+static const char * const tpu_groups[] = {
+ /* suffix might be updated */
+ "tpu_to0",
+ "tpu_to0_a",
+ "tpu_to1",
+ "tpu_to1_a",
+ "tpu_to2",
+ "tpu_to2_a",
+ "tpu_to3",
+ "tpu_to3_a",
+};
+
+static const char * const tsn0_groups[] = {
+ "tsn0_link",
+ "tsn0_phy_int",
+ "tsn0_mdio",
+ "tsn0_rgmii",
+ "tsn0_txcrefclk",
+ "tsn0_avtp_pps",
+ "tsn0_avtp_capture",
+ "tsn0_avtp_match",
+};
+
+static const struct sh_pfc_function pinmux_functions[] = {
+ SH_PFC_FUNCTION(avb0),
+ SH_PFC_FUNCTION(avb1),
+ SH_PFC_FUNCTION(avb2),
+
+ SH_PFC_FUNCTION(canfd0),
+ SH_PFC_FUNCTION(canfd1),
+ SH_PFC_FUNCTION(canfd2),
+ SH_PFC_FUNCTION(canfd3),
+ SH_PFC_FUNCTION(canfd4),
+ SH_PFC_FUNCTION(canfd5),
+ SH_PFC_FUNCTION(canfd6),
+ SH_PFC_FUNCTION(canfd7),
+ SH_PFC_FUNCTION(can_clk),
+
+ SH_PFC_FUNCTION(hscif0),
+ SH_PFC_FUNCTION(hscif1),
+ SH_PFC_FUNCTION(hscif2),
+ SH_PFC_FUNCTION(hscif3),
+
+ SH_PFC_FUNCTION(i2c0),
+ SH_PFC_FUNCTION(i2c1),
+ SH_PFC_FUNCTION(i2c2),
+ SH_PFC_FUNCTION(i2c3),
+ SH_PFC_FUNCTION(i2c4),
+ SH_PFC_FUNCTION(i2c5),
+
+ SH_PFC_FUNCTION(mmc),
+
+ SH_PFC_FUNCTION(msiof0),
+ SH_PFC_FUNCTION(msiof1),
+ SH_PFC_FUNCTION(msiof2),
+ SH_PFC_FUNCTION(msiof3),
+ SH_PFC_FUNCTION(msiof4),
+ SH_PFC_FUNCTION(msiof5),
+
+ SH_PFC_FUNCTION(pcie),
+
+ SH_PFC_FUNCTION(pwm0),
+ SH_PFC_FUNCTION(pwm1),
+ SH_PFC_FUNCTION(pwm2),
+ SH_PFC_FUNCTION(pwm3),
+ SH_PFC_FUNCTION(pwm4),
+ SH_PFC_FUNCTION(pwm5),
+ SH_PFC_FUNCTION(pwm6),
+ SH_PFC_FUNCTION(pwm7),
+ SH_PFC_FUNCTION(pwm8),
+ SH_PFC_FUNCTION(pwm9),
+
+ SH_PFC_FUNCTION(qspi0),
+ SH_PFC_FUNCTION(qspi1),
+
+ SH_PFC_FUNCTION(scif0),
+ SH_PFC_FUNCTION(scif1),
+ SH_PFC_FUNCTION(scif3),
+ SH_PFC_FUNCTION(scif4),
+ SH_PFC_FUNCTION(scif_clk),
+
+ SH_PFC_FUNCTION(tpu),
+
+ SH_PFC_FUNCTION(tsn0),
+};
+
+static const struct pinmux_cfg_reg pinmux_config_regs[] = {
+#define F_(x, y) FN_##y
+#define FM(x) FN_##x
+ { PINMUX_CFG_REG_VAR("GPSR0", 0xE6050040, 32,
+ GROUP(-13, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP0_31_19 RESERVED */
+ GP_0_18_FN, GPSR0_18,
+ GP_0_17_FN, GPSR0_17,
+ GP_0_16_FN, GPSR0_16,
+ GP_0_15_FN, GPSR0_15,
+ GP_0_14_FN, GPSR0_14,
+ GP_0_13_FN, GPSR0_13,
+ GP_0_12_FN, GPSR0_12,
+ GP_0_11_FN, GPSR0_11,
+ GP_0_10_FN, GPSR0_10,
+ GP_0_9_FN, GPSR0_9,
+ GP_0_8_FN, GPSR0_8,
+ GP_0_7_FN, GPSR0_7,
+ GP_0_6_FN, GPSR0_6,
+ GP_0_5_FN, GPSR0_5,
+ GP_0_4_FN, GPSR0_4,
+ GP_0_3_FN, GPSR0_3,
+ GP_0_2_FN, GPSR0_2,
+ GP_0_1_FN, GPSR0_1,
+ GP_0_0_FN, GPSR0_0, ))
+ },
+ { PINMUX_CFG_REG("GPSR1", 0xE6050840, 32, 1, GROUP(
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ GP_1_28_FN, GPSR1_28,
+ GP_1_27_FN, GPSR1_27,
+ GP_1_26_FN, GPSR1_26,
+ GP_1_25_FN, GPSR1_25,
+ GP_1_24_FN, GPSR1_24,
+ GP_1_23_FN, GPSR1_23,
+ GP_1_22_FN, GPSR1_22,
+ GP_1_21_FN, GPSR1_21,
+ GP_1_20_FN, GPSR1_20,
+ GP_1_19_FN, GPSR1_19,
+ GP_1_18_FN, GPSR1_18,
+ GP_1_17_FN, GPSR1_17,
+ GP_1_16_FN, GPSR1_16,
+ GP_1_15_FN, GPSR1_15,
+ GP_1_14_FN, GPSR1_14,
+ GP_1_13_FN, GPSR1_13,
+ GP_1_12_FN, GPSR1_12,
+ GP_1_11_FN, GPSR1_11,
+ GP_1_10_FN, GPSR1_10,
+ GP_1_9_FN, GPSR1_9,
+ GP_1_8_FN, GPSR1_8,
+ GP_1_7_FN, GPSR1_7,
+ GP_1_6_FN, GPSR1_6,
+ GP_1_5_FN, GPSR1_5,
+ GP_1_4_FN, GPSR1_4,
+ GP_1_3_FN, GPSR1_3,
+ GP_1_2_FN, GPSR1_2,
+ GP_1_1_FN, GPSR1_1,
+ GP_1_0_FN, GPSR1_0, ))
+ },
+ { PINMUX_CFG_REG_VAR("GPSR2", 0xE6058040, 32,
+ GROUP(-12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP2_31_20 RESERVED */
+ GP_2_19_FN, GPSR2_19,
+ GP_2_18_FN, GPSR2_18,
+ GP_2_17_FN, GPSR2_17,
+ GP_2_16_FN, GPSR2_16,
+ GP_2_15_FN, GPSR2_15,
+ GP_2_14_FN, GPSR2_14,
+ GP_2_13_FN, GPSR2_13,
+ GP_2_12_FN, GPSR2_12,
+ GP_2_11_FN, GPSR2_11,
+ GP_2_10_FN, GPSR2_10,
+ GP_2_9_FN, GPSR2_9,
+ GP_2_8_FN, GPSR2_8,
+ GP_2_7_FN, GPSR2_7,
+ GP_2_6_FN, GPSR2_6,
+ GP_2_5_FN, GPSR2_5,
+ GP_2_4_FN, GPSR2_4,
+ GP_2_3_FN, GPSR2_3,
+ GP_2_2_FN, GPSR2_2,
+ GP_2_1_FN, GPSR2_1,
+ GP_2_0_FN, GPSR2_0, ))
+ },
+ { PINMUX_CFG_REG("GPSR3", 0xE6058840, 32, 1, GROUP(
+ 0, 0,
+ 0, 0,
+ GP_3_29_FN, GPSR3_29,
+ GP_3_28_FN, GPSR3_28,
+ GP_3_27_FN, GPSR3_27,
+ GP_3_26_FN, GPSR3_26,
+ GP_3_25_FN, GPSR3_25,
+ GP_3_24_FN, GPSR3_24,
+ GP_3_23_FN, GPSR3_23,
+ GP_3_22_FN, GPSR3_22,
+ GP_3_21_FN, GPSR3_21,
+ GP_3_20_FN, GPSR3_20,
+ GP_3_19_FN, GPSR3_19,
+ GP_3_18_FN, GPSR3_18,
+ GP_3_17_FN, GPSR3_17,
+ GP_3_16_FN, GPSR3_16,
+ GP_3_15_FN, GPSR3_15,
+ GP_3_14_FN, GPSR3_14,
+ GP_3_13_FN, GPSR3_13,
+ GP_3_12_FN, GPSR3_12,
+ GP_3_11_FN, GPSR3_11,
+ GP_3_10_FN, GPSR3_10,
+ GP_3_9_FN, GPSR3_9,
+ GP_3_8_FN, GPSR3_8,
+ GP_3_7_FN, GPSR3_7,
+ GP_3_6_FN, GPSR3_6,
+ GP_3_5_FN, GPSR3_5,
+ GP_3_4_FN, GPSR3_4,
+ GP_3_3_FN, GPSR3_3,
+ GP_3_2_FN, GPSR3_2,
+ GP_3_1_FN, GPSR3_1,
+ GP_3_0_FN, GPSR3_0, ))
+ },
+ { PINMUX_CFG_REG("GPSR4", 0xE6060040, 32, 1, GROUP(
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ GP_4_24_FN, GPSR4_24,
+ GP_4_23_FN, GPSR4_23,
+ GP_4_22_FN, GPSR4_22,
+ GP_4_21_FN, GPSR4_21,
+ GP_4_20_FN, GPSR4_20,
+ GP_4_19_FN, GPSR4_19,
+ GP_4_18_FN, GPSR4_18,
+ GP_4_17_FN, GPSR4_17,
+ GP_4_16_FN, GPSR4_16,
+ GP_4_15_FN, GPSR4_15,
+ GP_4_14_FN, GPSR4_14,
+ GP_4_13_FN, GPSR4_13,
+ GP_4_12_FN, GPSR4_12,
+ GP_4_11_FN, GPSR4_11,
+ GP_4_10_FN, GPSR4_10,
+ GP_4_9_FN, GPSR4_9,
+ GP_4_8_FN, GPSR4_8,
+ GP_4_7_FN, GPSR4_7,
+ GP_4_6_FN, GPSR4_6,
+ GP_4_5_FN, GPSR4_5,
+ GP_4_4_FN, GPSR4_4,
+ GP_4_3_FN, GPSR4_3,
+ GP_4_2_FN, GPSR4_2,
+ GP_4_1_FN, GPSR4_1,
+ GP_4_0_FN, GPSR4_0, ))
+ },
+ { PINMUX_CFG_REG_VAR("GPSR5", 0xE6060840, 32,
+ GROUP(-11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP5_31_21 RESERVED */
+ GP_5_20_FN, GPSR5_20,
+ GP_5_19_FN, GPSR5_19,
+ GP_5_18_FN, GPSR5_18,
+ GP_5_17_FN, GPSR5_17,
+ GP_5_16_FN, GPSR5_16,
+ GP_5_15_FN, GPSR5_15,
+ GP_5_14_FN, GPSR5_14,
+ GP_5_13_FN, GPSR5_13,
+ GP_5_12_FN, GPSR5_12,
+ GP_5_11_FN, GPSR5_11,
+ GP_5_10_FN, GPSR5_10,
+ GP_5_9_FN, GPSR5_9,
+ GP_5_8_FN, GPSR5_8,
+ GP_5_7_FN, GPSR5_7,
+ GP_5_6_FN, GPSR5_6,
+ GP_5_5_FN, GPSR5_5,
+ GP_5_4_FN, GPSR5_4,
+ GP_5_3_FN, GPSR5_3,
+ GP_5_2_FN, GPSR5_2,
+ GP_5_1_FN, GPSR5_1,
+ GP_5_0_FN, GPSR5_0, ))
+ },
+ { PINMUX_CFG_REG_VAR("GPSR6", 0xE6061040, 32,
+ GROUP(-11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP6_31_21 RESERVED */
+ GP_6_20_FN, GPSR6_20,
+ GP_6_19_FN, GPSR6_19,
+ GP_6_18_FN, GPSR6_18,
+ GP_6_17_FN, GPSR6_17,
+ GP_6_16_FN, GPSR6_16,
+ GP_6_15_FN, GPSR6_15,
+ GP_6_14_FN, GPSR6_14,
+ GP_6_13_FN, GPSR6_13,
+ GP_6_12_FN, GPSR6_12,
+ GP_6_11_FN, GPSR6_11,
+ GP_6_10_FN, GPSR6_10,
+ GP_6_9_FN, GPSR6_9,
+ GP_6_8_FN, GPSR6_8,
+ GP_6_7_FN, GPSR6_7,
+ GP_6_6_FN, GPSR6_6,
+ GP_6_5_FN, GPSR6_5,
+ GP_6_4_FN, GPSR6_4,
+ GP_6_3_FN, GPSR6_3,
+ GP_6_2_FN, GPSR6_2,
+ GP_6_1_FN, GPSR6_1,
+ GP_6_0_FN, GPSR6_0, ))
+ },
+ { PINMUX_CFG_REG_VAR("GPSR7", 0xE6061840, 32,
+ GROUP(-11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP7_31_21 RESERVED */
+ GP_7_20_FN, GPSR7_20,
+ GP_7_19_FN, GPSR7_19,
+ GP_7_18_FN, GPSR7_18,
+ GP_7_17_FN, GPSR7_17,
+ GP_7_16_FN, GPSR7_16,
+ GP_7_15_FN, GPSR7_15,
+ GP_7_14_FN, GPSR7_14,
+ GP_7_13_FN, GPSR7_13,
+ GP_7_12_FN, GPSR7_12,
+ GP_7_11_FN, GPSR7_11,
+ GP_7_10_FN, GPSR7_10,
+ GP_7_9_FN, GPSR7_9,
+ GP_7_8_FN, GPSR7_8,
+ GP_7_7_FN, GPSR7_7,
+ GP_7_6_FN, GPSR7_6,
+ GP_7_5_FN, GPSR7_5,
+ GP_7_4_FN, GPSR7_4,
+ GP_7_3_FN, GPSR7_3,
+ GP_7_2_FN, GPSR7_2,
+ GP_7_1_FN, GPSR7_1,
+ GP_7_0_FN, GPSR7_0, ))
+ },
+ { PINMUX_CFG_REG_VAR("GPSR8", 0xE6068040, 32,
+ GROUP(-18, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP8_31_14 RESERVED */
+ GP_8_13_FN, GPSR8_13,
+ GP_8_12_FN, GPSR8_12,
+ GP_8_11_FN, GPSR8_11,
+ GP_8_10_FN, GPSR8_10,
+ GP_8_9_FN, GPSR8_9,
+ GP_8_8_FN, GPSR8_8,
+ GP_8_7_FN, GPSR8_7,
+ GP_8_6_FN, GPSR8_6,
+ GP_8_5_FN, GPSR8_5,
+ GP_8_4_FN, GPSR8_4,
+ GP_8_3_FN, GPSR8_3,
+ GP_8_2_FN, GPSR8_2,
+ GP_8_1_FN, GPSR8_1,
+ GP_8_0_FN, GPSR8_0, ))
+ },
+#undef F_
+#undef FM
+
+#define F_(x, y) x,
+#define FM(x) FN_##x,
+ { PINMUX_CFG_REG("IP0SR0", 0xE6050060, 32, 4, GROUP(
+ IP0SR0_31_28
+ IP0SR0_27_24
+ IP0SR0_23_20
+ IP0SR0_19_16
+ IP0SR0_15_12
+ IP0SR0_11_8
+ IP0SR0_7_4
+ IP0SR0_3_0))
+ },
+ { PINMUX_CFG_REG("IP1SR0", 0xE6050064, 32, 4, GROUP(
+ IP1SR0_31_28
+ IP1SR0_27_24
+ IP1SR0_23_20
+ IP1SR0_19_16
+ IP1SR0_15_12
+ IP1SR0_11_8
+ IP1SR0_7_4
+ IP1SR0_3_0))
+ },
+ { PINMUX_CFG_REG_VAR("IP2SR0", 0xE6050068, 32,
+ GROUP(-20, 4, 4, 4),
+ GROUP(
+ /* IP2SR0_31_12 RESERVED */
+ IP2SR0_11_8
+ IP2SR0_7_4
+ IP2SR0_3_0))
+ },
+ { PINMUX_CFG_REG("IP0SR1", 0xE6050860, 32, 4, GROUP(
+ IP0SR1_31_28
+ IP0SR1_27_24
+ IP0SR1_23_20
+ IP0SR1_19_16
+ IP0SR1_15_12
+ IP0SR1_11_8
+ IP0SR1_7_4
+ IP0SR1_3_0))
+ },
+ { PINMUX_CFG_REG("IP1SR1", 0xE6050864, 32, 4, GROUP(
+ IP1SR1_31_28
+ IP1SR1_27_24
+ IP1SR1_23_20
+ IP1SR1_19_16
+ IP1SR1_15_12
+ IP1SR1_11_8
+ IP1SR1_7_4
+ IP1SR1_3_0))
+ },
+ { PINMUX_CFG_REG("IP2SR1", 0xE6050868, 32, 4, GROUP(
+ IP2SR1_31_28
+ IP2SR1_27_24
+ IP2SR1_23_20
+ IP2SR1_19_16
+ IP2SR1_15_12
+ IP2SR1_11_8
+ IP2SR1_7_4
+ IP2SR1_3_0))
+ },
+ { PINMUX_CFG_REG_VAR("IP3SR1", 0xE605086C, 32,
+ GROUP(-12, 4, 4, 4, 4, 4),
+ GROUP(
+ /* IP3SR1_31_20 RESERVED */
+ IP3SR1_19_16
+ IP3SR1_15_12
+ IP3SR1_11_8
+ IP3SR1_7_4
+ IP3SR1_3_0))
+ },
+ { PINMUX_CFG_REG("IP0SR2", 0xE6058060, 32, 4, GROUP(
+ IP0SR2_31_28
+ IP0SR2_27_24
+ IP0SR2_23_20
+ IP0SR2_19_16
+ IP0SR2_15_12
+ IP0SR2_11_8
+ IP0SR2_7_4
+ IP0SR2_3_0))
+ },
+ { PINMUX_CFG_REG("IP1SR2", 0xE6058064, 32, 4, GROUP(
+ IP1SR2_31_28
+ IP1SR2_27_24
+ IP1SR2_23_20
+ IP1SR2_19_16
+ IP1SR2_15_12
+ IP1SR2_11_8
+ IP1SR2_7_4
+ IP1SR2_3_0))
+ },
+ { PINMUX_CFG_REG_VAR("IP2SR2", 0xE6058068, 32,
+ GROUP(-16, 4, 4, 4, 4),
+ GROUP(
+ /* IP2SR2_31_16 RESERVED */
+ IP2SR2_15_12
+ IP2SR2_11_8
+ IP2SR2_7_4
+ IP2SR2_3_0))
+ },
+ { PINMUX_CFG_REG("IP0SR3", 0xE6058860, 32, 4, GROUP(
+ IP0SR3_31_28
+ IP0SR3_27_24
+ IP0SR3_23_20
+ IP0SR3_19_16
+ IP0SR3_15_12
+ IP0SR3_11_8
+ IP0SR3_7_4
+ IP0SR3_3_0))
+ },
+ { PINMUX_CFG_REG("IP1SR3", 0xE6058864, 32, 4, GROUP(
+ IP1SR3_31_28
+ IP1SR3_27_24
+ IP1SR3_23_20
+ IP1SR3_19_16
+ IP1SR3_15_12
+ IP1SR3_11_8
+ IP1SR3_7_4
+ IP1SR3_3_0))
+ },
+ { PINMUX_CFG_REG("IP2SR3", 0xE6058868, 32, 4, GROUP(
+ IP2SR3_31_28
+ IP2SR3_27_24
+ IP2SR3_23_20
+ IP2SR3_19_16
+ IP2SR3_15_12
+ IP2SR3_11_8
+ IP2SR3_7_4
+ IP2SR3_3_0))
+ },
+ { PINMUX_CFG_REG_VAR("IP3SR3", 0xE605886C, 32,
+ GROUP(-8, 4, 4, 4, 4, 4, 4),
+ GROUP(
+ /* IP3SR3_31_24 RESERVED */
+ IP3SR3_23_20
+ IP3SR3_19_16
+ IP3SR3_15_12
+ IP3SR3_11_8
+ IP3SR3_7_4
+ IP3SR3_3_0))
+ },
+ { PINMUX_CFG_REG("IP0SR6", 0xE6061060, 32, 4, GROUP(
+ IP0SR6_31_28
+ IP0SR6_27_24
+ IP0SR6_23_20
+ IP0SR6_19_16
+ IP0SR6_15_12
+ IP0SR6_11_8
+ IP0SR6_7_4
+ IP0SR6_3_0))
+ },
+ { PINMUX_CFG_REG("IP1SR6", 0xE6061064, 32, 4, GROUP(
+ IP1SR6_31_28
+ IP1SR6_27_24
+ IP1SR6_23_20
+ IP1SR6_19_16
+ IP1SR6_15_12
+ IP1SR6_11_8
+ IP1SR6_7_4
+ IP1SR6_3_0))
+ },
+ { PINMUX_CFG_REG_VAR("IP2SR6", 0xE6061068, 32,
+ GROUP(-12, 4, 4, 4, 4, 4),
+ GROUP(
+ /* IP2SR6_31_20 RESERVED */
+ IP2SR6_19_16
+ IP2SR6_15_12
+ IP2SR6_11_8
+ IP2SR6_7_4
+ IP2SR6_3_0))
+ },
+ { PINMUX_CFG_REG("IP0SR7", 0xE6061860, 32, 4, GROUP(
+ IP0SR7_31_28
+ IP0SR7_27_24
+ IP0SR7_23_20
+ IP0SR7_19_16
+ IP0SR7_15_12
+ IP0SR7_11_8
+ IP0SR7_7_4
+ IP0SR7_3_0))
+ },
+ { PINMUX_CFG_REG("IP1SR7", 0xE6061864, 32, 4, GROUP(
+ IP1SR7_31_28
+ IP1SR7_27_24
+ IP1SR7_23_20
+ IP1SR7_19_16
+ IP1SR7_15_12
+ IP1SR7_11_8
+ IP1SR7_7_4
+ IP1SR7_3_0))
+ },
+ { PINMUX_CFG_REG_VAR("IP2SR7", 0xE6061868, 32,
+ GROUP(-12, 4, 4, 4, 4, 4),
+ GROUP(
+ /* IP2SR7_31_20 RESERVED */
+ IP2SR7_19_16
+ IP2SR7_15_12
+ IP2SR7_11_8
+ IP2SR7_7_4
+ IP2SR7_3_0))
+ },
+ { PINMUX_CFG_REG("IP0SR8", 0xE6068060, 32, 4, GROUP(
+ IP0SR8_31_28
+ IP0SR8_27_24
+ IP0SR8_23_20
+ IP0SR8_19_16
+ IP0SR8_15_12
+ IP0SR8_11_8
+ IP0SR8_7_4
+ IP0SR8_3_0))
+ },
+ { PINMUX_CFG_REG_VAR("IP1SR8", 0xE6068064, 32,
+ GROUP(-8, 4, 4, 4, 4, 4, 4),
+ GROUP(
+ /* IP1SR8_31_24 RESERVED */
+ IP1SR8_23_20
+ IP1SR8_19_16
+ IP1SR8_15_12
+ IP1SR8_11_8
+ IP1SR8_7_4
+ IP1SR8_3_0))
+ },
+#undef F_
+#undef FM
+
+#define F_(x, y) x,
+#define FM(x) FN_##x,
+ { PINMUX_CFG_REG_VAR("MOD_SEL4", 0xE6060100, 32,
+ GROUP(-12, 1, 1, -2, 1, 1, -1, 1, -2, 1, 1, -2, 1,
+ -2, 1, 1, -1),
+ GROUP(
+ /* RESERVED 31-20 */
+ MOD_SEL4_19
+ MOD_SEL4_18
+ /* RESERVED 17-16 */
+ MOD_SEL4_15
+ MOD_SEL4_14
+ /* RESERVED 13 */
+ MOD_SEL4_12
+ /* RESERVED 11-10 */
+ MOD_SEL4_9
+ MOD_SEL4_8
+ /* RESERVED 7-6 */
+ MOD_SEL4_5
+ /* RESERVED 4-3 */
+ MOD_SEL4_2
+ MOD_SEL4_1
+ /* RESERVED 0 */
+ ))
+ },
+ { PINMUX_CFG_REG_VAR("MOD_SEL5", 0xE6060900, 32,
+ GROUP(-12, 1, -2, 1, 1, -2, 1, 1, -2, 1, -1,
+ 1, 1, -2, 1, -1, 1),
+ GROUP(
+ /* RESERVED 31-20 */
+ MOD_SEL5_19
+ /* RESERVED 18-17 */
+ MOD_SEL5_16
+ MOD_SEL5_15
+ /* RESERVED 14-13 */
+ MOD_SEL5_12
+ MOD_SEL5_11
+ /* RESERVED 10-9 */
+ MOD_SEL5_8
+ /* RESERVED 7 */
+ MOD_SEL5_6
+ MOD_SEL5_5
+ /* RESERVED 4-3 */
+ MOD_SEL5_2
+ /* RESERVED 1 */
+ MOD_SEL5_0))
+ },
+ { PINMUX_CFG_REG_VAR("MOD_SEL6", 0xE6061100, 32,
+ GROUP(-13, 1, -1, 1, -2, 1, 1,
+ -1, 1, -2, 1, 1, 1, -2, 1, 1, -1),
+ GROUP(
+ /* RESERVED 31-19 */
+ MOD_SEL6_18
+ /* RESERVED 17 */
+ MOD_SEL6_16
+ /* RESERVED 15-14 */
+ MOD_SEL6_13
+ MOD_SEL6_12
+ /* RESERVED 11 */
+ MOD_SEL6_10
+ /* RESERVED 9-8 */
+ MOD_SEL6_7
+ MOD_SEL6_6
+ MOD_SEL6_5
+ /* RESERVED 4-3 */
+ MOD_SEL6_2
+ MOD_SEL6_1
+ /* RESERVED 0 */
+ ))
+ },
+ { PINMUX_CFG_REG_VAR("MOD_SEL7", 0xE6061900, 32,
+ GROUP(-15, 1, 1, -1, 1, -1, 1, 1, -2, 1, 1,
+ -2, 1, 1, -1, 1),
+ GROUP(
+ /* RESERVED 31-17 */
+ MOD_SEL7_16
+ MOD_SEL7_15
+ /* RESERVED 14 */
+ MOD_SEL7_13
+ /* RESERVED 12 */
+ MOD_SEL7_11
+ MOD_SEL7_10
+ /* RESERVED 9-8 */
+ MOD_SEL7_7
+ MOD_SEL7_6
+ /* RESERVED 5-4 */
+ MOD_SEL7_3
+ MOD_SEL7_2
+ /* RESERVED 1 */
+ MOD_SEL7_0))
+ },
+ { PINMUX_CFG_REG_VAR("MOD_SEL8", 0xE6068100, 32,
+ GROUP(-20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* RESERVED 31-12 */
+ MOD_SEL8_11
+ MOD_SEL8_10
+ MOD_SEL8_9
+ MOD_SEL8_8
+ MOD_SEL8_7
+ MOD_SEL8_6
+ MOD_SEL8_5
+ MOD_SEL8_4
+ MOD_SEL8_3
+ MOD_SEL8_2
+ MOD_SEL8_1
+ MOD_SEL8_0))
+ },
+ { },
+};
+
+static const struct pinmux_drive_reg pinmux_drive_regs[] = {
+ { PINMUX_DRIVE_REG("DRV0CTRL0", 0xE6050080) {
+ { RCAR_GP_PIN(0, 7), 28, 3 }, /* MSIOF5_SS2 */
+ { RCAR_GP_PIN(0, 6), 24, 3 }, /* IRQ0 */
+ { RCAR_GP_PIN(0, 5), 20, 3 }, /* IRQ1 */
+ { RCAR_GP_PIN(0, 4), 16, 3 }, /* IRQ2 */
+ { RCAR_GP_PIN(0, 3), 12, 3 }, /* IRQ3 */
+ { RCAR_GP_PIN(0, 2), 8, 3 }, /* GP0_02 */
+ { RCAR_GP_PIN(0, 1), 4, 3 }, /* GP0_01 */
+ { RCAR_GP_PIN(0, 0), 0, 3 }, /* GP0_00 */
+ } },
+ { PINMUX_DRIVE_REG("DRV1CTRL0", 0xE6050084) {
+ { RCAR_GP_PIN(0, 15), 28, 3 }, /* MSIOF2_SYNC */
+ { RCAR_GP_PIN(0, 14), 24, 3 }, /* MSIOF2_SS1 */
+ { RCAR_GP_PIN(0, 13), 20, 3 }, /* MSIOF2_SS2 */
+ { RCAR_GP_PIN(0, 12), 16, 3 }, /* MSIOF5_RXD */
+ { RCAR_GP_PIN(0, 11), 12, 3 }, /* MSIOF5_SCK */
+ { RCAR_GP_PIN(0, 10), 8, 3 }, /* MSIOF5_TXD */
+ { RCAR_GP_PIN(0, 9), 4, 3 }, /* MSIOF5_SYNC */
+ { RCAR_GP_PIN(0, 8), 0, 3 }, /* MSIOF5_SS1 */
+ } },
+ { PINMUX_DRIVE_REG("DRV2CTRL0", 0xE6050088) {
+ { RCAR_GP_PIN(0, 18), 8, 3 }, /* MSIOF2_RXD */
+ { RCAR_GP_PIN(0, 17), 4, 3 }, /* MSIOF2_SCK */
+ { RCAR_GP_PIN(0, 16), 0, 3 }, /* MSIOF2_TXD */
+ } },
+ { PINMUX_DRIVE_REG("DRV0CTRL1", 0xE6050880) {
+ { RCAR_GP_PIN(1, 7), 28, 3 }, /* MSIOF0_SS1 */
+ { RCAR_GP_PIN(1, 6), 24, 3 }, /* MSIOF0_SS2 */
+ { RCAR_GP_PIN(1, 5), 20, 3 }, /* MSIOF1_RXD */
+ { RCAR_GP_PIN(1, 4), 16, 3 }, /* MSIOF1_TXD */
+ { RCAR_GP_PIN(1, 3), 12, 3 }, /* MSIOF1_SCK */
+ { RCAR_GP_PIN(1, 2), 8, 3 }, /* MSIOF1_SYNC */
+ { RCAR_GP_PIN(1, 1), 4, 3 }, /* MSIOF1_SS1 */
+ { RCAR_GP_PIN(1, 0), 0, 3 }, /* MSIOF1_SS2 */
+ } },
+ { PINMUX_DRIVE_REG("DRV1CTRL1", 0xE6050884) {
+ { RCAR_GP_PIN(1, 15), 28, 3 }, /* HSCK0 */
+ { RCAR_GP_PIN(1, 14), 24, 3 }, /* HRTS0_N */
+ { RCAR_GP_PIN(1, 13), 20, 3 }, /* HCTS0_N */
+ { RCAR_GP_PIN(1, 12), 16, 3 }, /* HTX0 */
+ { RCAR_GP_PIN(1, 11), 12, 3 }, /* MSIOF0_RXD */
+ { RCAR_GP_PIN(1, 10), 8, 3 }, /* MSIOF0_SCK */
+ { RCAR_GP_PIN(1, 9), 4, 3 }, /* MSIOF0_TXD */
+ { RCAR_GP_PIN(1, 8), 0, 3 }, /* MSIOF0_SYNC */
+ } },
+ { PINMUX_DRIVE_REG("DRV2CTRL1", 0xE6050888) {
+ { RCAR_GP_PIN(1, 23), 28, 3 }, /* GP1_23 */
+ { RCAR_GP_PIN(1, 22), 24, 3 }, /* AUDIO_CLKIN */
+ { RCAR_GP_PIN(1, 21), 20, 3 }, /* AUDIO_CLKOUT */
+ { RCAR_GP_PIN(1, 20), 16, 3 }, /* SSI_SD */
+ { RCAR_GP_PIN(1, 19), 12, 3 }, /* SSI_WS */
+ { RCAR_GP_PIN(1, 18), 8, 3 }, /* SSI_SCK */
+ { RCAR_GP_PIN(1, 17), 4, 3 }, /* SCIF_CLK */
+ { RCAR_GP_PIN(1, 16), 0, 3 }, /* HRX0 */
+ } },
+ { PINMUX_DRIVE_REG("DRV3CTRL1", 0xE605088C) {
+ { RCAR_GP_PIN(1, 28), 16, 3 }, /* HTX3 */
+ { RCAR_GP_PIN(1, 27), 12, 3 }, /* HCTS3_N */
+ { RCAR_GP_PIN(1, 26), 8, 3 }, /* HRTS3_N */
+ { RCAR_GP_PIN(1, 25), 4, 3 }, /* HSCK3 */
+ { RCAR_GP_PIN(1, 24), 0, 3 }, /* HRX3 */
+ } },
+ { PINMUX_DRIVE_REG("DRV0CTRL2", 0xE6058080) {
+ { RCAR_GP_PIN(2, 7), 28, 3 }, /* TPU0TO1 */
+ { RCAR_GP_PIN(2, 6), 24, 3 }, /* FXR_TXDB */
+ { RCAR_GP_PIN(2, 5), 20, 3 }, /* FXR_TXENB_N */
+ { RCAR_GP_PIN(2, 4), 16, 3 }, /* RXDB_EXTFXR */
+ { RCAR_GP_PIN(2, 3), 12, 3 }, /* CLK_EXTFXR */
+ { RCAR_GP_PIN(2, 2), 8, 3 }, /* RXDA_EXTFXR */
+ { RCAR_GP_PIN(2, 1), 4, 3 }, /* FXR_TXENA_N */
+ { RCAR_GP_PIN(2, 0), 0, 3 }, /* FXR_TXDA */
+ } },
+ { PINMUX_DRIVE_REG("DRV1CTRL2", 0xE6058084) {
+ { RCAR_GP_PIN(2, 15), 28, 3 }, /* CANFD3_RX */
+ { RCAR_GP_PIN(2, 14), 24, 3 }, /* CANFD3_TX */
+ { RCAR_GP_PIN(2, 13), 20, 3 }, /* CANFD2_RX */
+ { RCAR_GP_PIN(2, 12), 16, 3 }, /* CANFD2_TX */
+ { RCAR_GP_PIN(2, 11), 12, 3 }, /* CANFD0_RX */
+ { RCAR_GP_PIN(2, 10), 8, 3 }, /* CANFD0_TX */
+ { RCAR_GP_PIN(2, 9), 4, 3 }, /* CAN_CLK */
+ { RCAR_GP_PIN(2, 8), 0, 3 }, /* TPU0TO0 */
+ } },
+ { PINMUX_DRIVE_REG("DRV2CTRL2", 0xE6058088) {
+ { RCAR_GP_PIN(2, 19), 12, 3 }, /* CANFD7_RX */
+ { RCAR_GP_PIN(2, 18), 8, 3 }, /* CANFD7_TX */
+ { RCAR_GP_PIN(2, 17), 4, 3 }, /* CANFD4_RX */
+ { RCAR_GP_PIN(2, 16), 0, 3 }, /* CANFD4_TX */
+ } },
+ { PINMUX_DRIVE_REG("DRV0CTRL3", 0xE6058880) {
+ { RCAR_GP_PIN(3, 7), 28, 3 }, /* MMC_D4 */
+ { RCAR_GP_PIN(3, 6), 24, 3 }, /* MMC_D5 */
+ { RCAR_GP_PIN(3, 5), 20, 3 }, /* MMC_SD_D3 */
+ { RCAR_GP_PIN(3, 4), 16, 3 }, /* MMC_DS */
+ { RCAR_GP_PIN(3, 3), 12, 3 }, /* MMC_SD_CLK */
+ { RCAR_GP_PIN(3, 2), 8, 3 }, /* MMC_SD_D2 */
+ { RCAR_GP_PIN(3, 1), 4, 3 }, /* MMC_SD_D0 */
+ { RCAR_GP_PIN(3, 0), 0, 3 }, /* MMC_SD_D1 */
+ } },
+ { PINMUX_DRIVE_REG("DRV1CTRL3", 0xE6058884) {
+ { RCAR_GP_PIN(3, 15), 28, 2 }, /* QSPI0_SSL */
+ { RCAR_GP_PIN(3, 14), 24, 2 }, /* IPC_CLKOUT */
+ { RCAR_GP_PIN(3, 13), 20, 2 }, /* IPC_CLKIN */
+ { RCAR_GP_PIN(3, 12), 16, 3 }, /* SD_WP */
+ { RCAR_GP_PIN(3, 11), 12, 3 }, /* SD_CD */
+ { RCAR_GP_PIN(3, 10), 8, 3 }, /* MMC_SD_CMD */
+ { RCAR_GP_PIN(3, 9), 4, 3 }, /* MMC_D6*/
+ { RCAR_GP_PIN(3, 8), 0, 3 }, /* MMC_D7 */
+ } },
+ { PINMUX_DRIVE_REG("DRV2CTRL3", 0xE6058888) {
+ { RCAR_GP_PIN(3, 23), 28, 2 }, /* QSPI1_MISO_IO1 */
+ { RCAR_GP_PIN(3, 22), 24, 2 }, /* QSPI1_SPCLK */
+ { RCAR_GP_PIN(3, 21), 20, 2 }, /* QSPI1_MOSI_IO0 */
+ { RCAR_GP_PIN(3, 20), 16, 2 }, /* QSPI0_SPCLK */
+ { RCAR_GP_PIN(3, 19), 12, 2 }, /* QSPI0_MOSI_IO0 */
+ { RCAR_GP_PIN(3, 18), 8, 2 }, /* QSPI0_MISO_IO1 */
+ { RCAR_GP_PIN(3, 17), 4, 2 }, /* QSPI0_IO2 */
+ { RCAR_GP_PIN(3, 16), 0, 2 }, /* QSPI0_IO3 */
+ } },
+ { PINMUX_DRIVE_REG("DRV3CTRL3", 0xE605888C) {
+ { RCAR_GP_PIN(3, 29), 20, 2 }, /* RPC_INT_N */
+ { RCAR_GP_PIN(3, 28), 16, 2 }, /* RPC_WP_N */
+ { RCAR_GP_PIN(3, 27), 12, 2 }, /* RPC_RESET_N */
+ { RCAR_GP_PIN(3, 26), 8, 2 }, /* QSPI1_IO3 */
+ { RCAR_GP_PIN(3, 25), 4, 2 }, /* QSPI1_SSL */
+ { RCAR_GP_PIN(3, 24), 0, 2 }, /* QSPI1_IO2 */
+ } },
+ { PINMUX_DRIVE_REG("DRV0CTRL4", 0xE6060080) {
+ { RCAR_GP_PIN(4, 7), 28, 3 }, /* TSN0_RX_CTL */
+ { RCAR_GP_PIN(4, 6), 24, 3 }, /* TSN0_AVTP_CAPTURE */
+ { RCAR_GP_PIN(4, 5), 20, 3 }, /* TSN0_AVTP_MATCH */
+ { RCAR_GP_PIN(4, 4), 16, 3 }, /* TSN0_LINK */
+ { RCAR_GP_PIN(4, 3), 12, 3 }, /* TSN0_PHY_INT */
+ { RCAR_GP_PIN(4, 2), 8, 3 }, /* TSN0_AVTP_PPS1 */
+ { RCAR_GP_PIN(4, 1), 4, 3 }, /* TSN0_MDC */
+ { RCAR_GP_PIN(4, 0), 0, 3 }, /* TSN0_MDIO */
+ } },
+ { PINMUX_DRIVE_REG("DRV1CTRL4", 0xE6060084) {
+ { RCAR_GP_PIN(4, 15), 28, 3 }, /* TSN0_TD0 */
+ { RCAR_GP_PIN(4, 14), 24, 3 }, /* TSN0_TD1 */
+ { RCAR_GP_PIN(4, 13), 20, 3 }, /* TSN0_RD1 */
+ { RCAR_GP_PIN(4, 12), 16, 3 }, /* TSN0_TXC */
+ { RCAR_GP_PIN(4, 11), 12, 3 }, /* TSN0_RXC */
+ { RCAR_GP_PIN(4, 10), 8, 3 }, /* TSN0_RD0 */
+ { RCAR_GP_PIN(4, 9), 4, 3 }, /* TSN0_TX_CTL */
+ { RCAR_GP_PIN(4, 8), 0, 3 }, /* TSN0_AVTP_PPS0 */
+ } },
+ { PINMUX_DRIVE_REG("DRV2CTRL4", 0xE6060088) {
+ { RCAR_GP_PIN(4, 23), 28, 3 }, /* AVS0 */
+ { RCAR_GP_PIN(4, 22), 24, 3 }, /* PCIE1_CLKREQ_N */
+ { RCAR_GP_PIN(4, 21), 20, 3 }, /* PCIE0_CLKREQ_N */
+ { RCAR_GP_PIN(4, 20), 16, 3 }, /* TSN0_TXCREFCLK */
+ { RCAR_GP_PIN(4, 19), 12, 3 }, /* TSN0_TD2 */
+ { RCAR_GP_PIN(4, 18), 8, 3 }, /* TSN0_TD3 */
+ { RCAR_GP_PIN(4, 17), 4, 3 }, /* TSN0_RD2 */
+ { RCAR_GP_PIN(4, 16), 0, 3 }, /* TSN0_RD3 */
+ } },
+ { PINMUX_DRIVE_REG("DRV3CTRL4", 0xE606008C) {
+ { RCAR_GP_PIN(4, 24), 0, 3 }, /* AVS1 */
+ } },
+ { PINMUX_DRIVE_REG("DRV0CTRL5", 0xE6060880) {
+ { RCAR_GP_PIN(5, 7), 28, 3 }, /* AVB2_TXCREFCLK */
+ { RCAR_GP_PIN(5, 6), 24, 3 }, /* AVB2_MDC */
+ { RCAR_GP_PIN(5, 5), 20, 3 }, /* AVB2_MAGIC */
+ { RCAR_GP_PIN(5, 4), 16, 3 }, /* AVB2_PHY_INT */
+ { RCAR_GP_PIN(5, 3), 12, 3 }, /* AVB2_LINK */
+ { RCAR_GP_PIN(5, 2), 8, 3 }, /* AVB2_AVTP_MATCH */
+ { RCAR_GP_PIN(5, 1), 4, 3 }, /* AVB2_AVTP_CAPTURE */
+ { RCAR_GP_PIN(5, 0), 0, 3 }, /* AVB2_AVTP_PPS */
+ } },
+ { PINMUX_DRIVE_REG("DRV1CTRL5", 0xE6060884) {
+ { RCAR_GP_PIN(5, 15), 28, 3 }, /* AVB2_TD0 */
+ { RCAR_GP_PIN(5, 14), 24, 3 }, /* AVB2_RD1 */
+ { RCAR_GP_PIN(5, 13), 20, 3 }, /* AVB2_RD2 */
+ { RCAR_GP_PIN(5, 12), 16, 3 }, /* AVB2_TD1 */
+ { RCAR_GP_PIN(5, 11), 12, 3 }, /* AVB2_TD2 */
+ { RCAR_GP_PIN(5, 10), 8, 3 }, /* AVB2_MDIO */
+ { RCAR_GP_PIN(5, 9), 4, 3 }, /* AVB2_RD3 */
+ { RCAR_GP_PIN(5, 8), 0, 3 }, /* AVB2_TD3 */
+ } },
+ { PINMUX_DRIVE_REG("DRV2CTRL5", 0xE6060888) {
+ { RCAR_GP_PIN(5, 20), 16, 3 }, /* AVB2_RX_CTL */
+ { RCAR_GP_PIN(5, 19), 12, 3 }, /* AVB2_TX_CTL */
+ { RCAR_GP_PIN(5, 18), 8, 3 }, /* AVB2_RXC */
+ { RCAR_GP_PIN(5, 17), 4, 3 }, /* AVB2_RD0 */
+ { RCAR_GP_PIN(5, 16), 0, 3 }, /* AVB2_TXC */
+ } },
+ { PINMUX_DRIVE_REG("DRV0CTRL6", 0xE6061080) {
+ { RCAR_GP_PIN(6, 7), 28, 3 }, /* AVB1_TX_CTL */
+ { RCAR_GP_PIN(6, 6), 24, 3 }, /* AVB1_TXC */
+ { RCAR_GP_PIN(6, 5), 20, 3 }, /* AVB1_AVTP_MATCH */
+ { RCAR_GP_PIN(6, 4), 16, 3 }, /* AVB1_LINK */
+ { RCAR_GP_PIN(6, 3), 12, 3 }, /* AVB1_PHY_INT */
+ { RCAR_GP_PIN(6, 2), 8, 3 }, /* AVB1_MDC */
+ { RCAR_GP_PIN(6, 1), 4, 3 }, /* AVB1_MAGIC */
+ { RCAR_GP_PIN(6, 0), 0, 3 }, /* AVB1_MDIO */
+ } },
+ { PINMUX_DRIVE_REG("DRV1CTRL6", 0xE6061084) {
+ { RCAR_GP_PIN(6, 15), 28, 3 }, /* AVB1_RD0 */
+ { RCAR_GP_PIN(6, 14), 24, 3 }, /* AVB1_RD1 */
+ { RCAR_GP_PIN(6, 13), 20, 3 }, /* AVB1_TD0 */
+ { RCAR_GP_PIN(6, 12), 16, 3 }, /* AVB1_TD1 */
+ { RCAR_GP_PIN(6, 11), 12, 3 }, /* AVB1_AVTP_CAPTURE */
+ { RCAR_GP_PIN(6, 10), 8, 3 }, /* AVB1_AVTP_PPS */
+ { RCAR_GP_PIN(6, 9), 4, 3 }, /* AVB1_RX_CTL */
+ { RCAR_GP_PIN(6, 8), 0, 3 }, /* AVB1_RXC */
+ } },
+ { PINMUX_DRIVE_REG("DRV2CTRL6", 0xE6061088) {
+ { RCAR_GP_PIN(6, 20), 16, 3 }, /* AVB1_TXCREFCLK */
+ { RCAR_GP_PIN(6, 19), 12, 3 }, /* AVB1_RD3 */
+ { RCAR_GP_PIN(6, 18), 8, 3 }, /* AVB1_TD3 */
+ { RCAR_GP_PIN(6, 17), 4, 3 }, /* AVB1_RD2 */
+ { RCAR_GP_PIN(6, 16), 0, 3 }, /* AVB1_TD2 */
+ } },
+ { PINMUX_DRIVE_REG("DRV0CTRL7", 0xE6061880) {
+ { RCAR_GP_PIN(7, 7), 28, 3 }, /* AVB0_TD1 */
+ { RCAR_GP_PIN(7, 6), 24, 3 }, /* AVB0_TD2 */
+ { RCAR_GP_PIN(7, 5), 20, 3 }, /* AVB0_PHY_INT */
+ { RCAR_GP_PIN(7, 4), 16, 3 }, /* AVB0_LINK */
+ { RCAR_GP_PIN(7, 3), 12, 3 }, /* AVB0_TD3 */
+ { RCAR_GP_PIN(7, 2), 8, 3 }, /* AVB0_AVTP_MATCH */
+ { RCAR_GP_PIN(7, 1), 4, 3 }, /* AVB0_AVTP_CAPTURE */
+ { RCAR_GP_PIN(7, 0), 0, 3 }, /* AVB0_AVTP_PPS */
+ } },
+ { PINMUX_DRIVE_REG("DRV1CTRL7", 0xE6061884) {
+ { RCAR_GP_PIN(7, 15), 28, 3 }, /* AVB0_TXC */
+ { RCAR_GP_PIN(7, 14), 24, 3 }, /* AVB0_MDIO */
+ { RCAR_GP_PIN(7, 13), 20, 3 }, /* AVB0_MDC */
+ { RCAR_GP_PIN(7, 12), 16, 3 }, /* AVB0_RD2 */
+ { RCAR_GP_PIN(7, 11), 12, 3 }, /* AVB0_TD0 */
+ { RCAR_GP_PIN(7, 10), 8, 3 }, /* AVB0_MAGIC */
+ { RCAR_GP_PIN(7, 9), 4, 3 }, /* AVB0_TXCREFCLK */
+ { RCAR_GP_PIN(7, 8), 0, 3 }, /* AVB0_RD3 */
+ } },
+ { PINMUX_DRIVE_REG("DRV2CTRL7", 0xE6061888) {
+ { RCAR_GP_PIN(7, 20), 16, 3 }, /* AVB0_RX_CTL */
+ { RCAR_GP_PIN(7, 19), 12, 3 }, /* AVB0_RXC */
+ { RCAR_GP_PIN(7, 18), 8, 3 }, /* AVB0_RD0 */
+ { RCAR_GP_PIN(7, 17), 4, 3 }, /* AVB0_RD1 */
+ { RCAR_GP_PIN(7, 16), 0, 3 }, /* AVB0_TX_CTL */
+ } },
+ { PINMUX_DRIVE_REG("DRV0CTRL8", 0xE6068080) {
+ { RCAR_GP_PIN(8, 7), 28, 3 }, /* SDA3 */
+ { RCAR_GP_PIN(8, 6), 24, 3 }, /* SCL3 */
+ { RCAR_GP_PIN(8, 5), 20, 3 }, /* SDA2 */
+ { RCAR_GP_PIN(8, 4), 16, 3 }, /* SCL2 */
+ { RCAR_GP_PIN(8, 3), 12, 3 }, /* SDA1 */
+ { RCAR_GP_PIN(8, 2), 8, 3 }, /* SCL1 */
+ { RCAR_GP_PIN(8, 1), 4, 3 }, /* SDA0 */
+ { RCAR_GP_PIN(8, 0), 0, 3 }, /* SCL0 */
+ } },
+ { PINMUX_DRIVE_REG("DRV1CTRL8", 0xE6068084) {
+ { RCAR_GP_PIN(8, 13), 20, 3 }, /* GP8_13 */
+ { RCAR_GP_PIN(8, 12), 16, 3 }, /* GP8_12 */
+ { RCAR_GP_PIN(8, 11), 12, 3 }, /* SDA5 */
+ { RCAR_GP_PIN(8, 10), 8, 3 }, /* SCL5 */
+ { RCAR_GP_PIN(8, 9), 4, 3 }, /* SDA4 */
+ { RCAR_GP_PIN(8, 8), 0, 3 }, /* SCL4 */
+ } },
+ { },
+};
+
+enum ioctrl_regs {
+ POC0,
+ POC1,
+ POC3,
+ POC4,
+ POC5,
+ POC6,
+ POC7,
+ POC8,
+};
+
+static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = {
+ [POC0] = { 0xE60500A0, },
+ [POC1] = { 0xE60508A0, },
+ [POC3] = { 0xE60588A0, },
+ [POC4] = { 0xE60600A0, },
+ [POC5] = { 0xE60608A0, },
+ [POC6] = { 0xE60610A0, },
+ [POC7] = { 0xE60618A0, },
+ [POC8] = { 0xE60680A0, },
+ { /* sentinel */ },
+};
+
+static int r8a779g0_pin_to_pocctrl(unsigned int pin, u32 *pocctrl)
+{
+ int bit = pin & 0x1f;
+
+ *pocctrl = pinmux_ioctrl_regs[POC0].reg;
+ if (pin >= RCAR_GP_PIN(0, 0) && pin <= RCAR_GP_PIN(0, 18))
+ return bit;
+
+ *pocctrl = pinmux_ioctrl_regs[POC1].reg;
+ if (pin >= RCAR_GP_PIN(1, 0) && pin <= RCAR_GP_PIN(1, 22))
+ return bit;
+
+ *pocctrl = pinmux_ioctrl_regs[POC3].reg;
+ if (pin >= RCAR_GP_PIN(3, 0) && pin <= RCAR_GP_PIN(3, 12))
+ return bit;
+
+ *pocctrl = pinmux_ioctrl_regs[POC8].reg;
+ if (pin >= RCAR_GP_PIN(8, 0) && pin <= RCAR_GP_PIN(8, 13))
+ return bit;
+
+ return -EINVAL;
+}
+
+static const struct pinmux_bias_reg pinmux_bias_regs[] = {
+ { PINMUX_BIAS_REG("PUEN0", 0xE60500C0, "PUD0", 0xE60500E0) {
+ [ 0] = RCAR_GP_PIN(0, 0), /* GP0_00 */
+ [ 1] = RCAR_GP_PIN(0, 1), /* GP0_01 */
+ [ 2] = RCAR_GP_PIN(0, 2), /* GP0_02 */
+ [ 3] = RCAR_GP_PIN(0, 3), /* IRQ3 */
+ [ 4] = RCAR_GP_PIN(0, 4), /* IRQ2 */
+ [ 5] = RCAR_GP_PIN(0, 5), /* IRQ1 */
+ [ 6] = RCAR_GP_PIN(0, 6), /* IRQ0 */
+ [ 7] = RCAR_GP_PIN(0, 7), /* MSIOF5_SS2 */
+ [ 8] = RCAR_GP_PIN(0, 8), /* MSIOF5_SS1 */
+ [ 9] = RCAR_GP_PIN(0, 9), /* MSIOF5_SYNC */
+ [10] = RCAR_GP_PIN(0, 10), /* MSIOF5_TXD */
+ [11] = RCAR_GP_PIN(0, 11), /* MSIOF5_SCK */
+ [12] = RCAR_GP_PIN(0, 12), /* MSIOF5_RXD */
+ [13] = RCAR_GP_PIN(0, 13), /* MSIOF2_SS2 */
+ [14] = RCAR_GP_PIN(0, 14), /* MSIOF2_SS1 */
+ [15] = RCAR_GP_PIN(0, 15), /* MSIOF2_SYNC */
+ [16] = RCAR_GP_PIN(0, 16), /* MSIOF2_TXD */
+ [17] = RCAR_GP_PIN(0, 17), /* MSIOF2_SCK */
+ [18] = RCAR_GP_PIN(0, 18), /* MSIOF2_RXD */
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("PUEN1", 0xE60508C0, "PUD1", 0xE60508E0) {
+ [ 0] = RCAR_GP_PIN(1, 0), /* MSIOF1_SS2 */
+ [ 1] = RCAR_GP_PIN(1, 1), /* MSIOF1_SS1 */
+ [ 2] = RCAR_GP_PIN(1, 2), /* MSIOF1_SYNC */
+ [ 3] = RCAR_GP_PIN(1, 3), /* MSIOF1_SCK */
+ [ 4] = RCAR_GP_PIN(1, 4), /* MSIOF1_TXD */
+ [ 5] = RCAR_GP_PIN(1, 5), /* MSIOF1_RXD */
+ [ 6] = RCAR_GP_PIN(1, 6), /* MSIOF0_SS2 */
+ [ 7] = RCAR_GP_PIN(1, 7), /* MSIOF0_SS1 */
+ [ 8] = RCAR_GP_PIN(1, 8), /* MSIOF0_SYNC */
+ [ 9] = RCAR_GP_PIN(1, 9), /* MSIOF0_TXD */
+ [10] = RCAR_GP_PIN(1, 10), /* MSIOF0_SCK */
+ [11] = RCAR_GP_PIN(1, 11), /* MSIOF0_RXD */
+ [12] = RCAR_GP_PIN(1, 12), /* HTX0 */
+ [13] = RCAR_GP_PIN(1, 13), /* HCTS0_N */
+ [14] = RCAR_GP_PIN(1, 14), /* HRTS0_N */
+ [15] = RCAR_GP_PIN(1, 15), /* HSCK0 */
+ [16] = RCAR_GP_PIN(1, 16), /* HRX0 */
+ [17] = RCAR_GP_PIN(1, 17), /* SCIF_CLK */
+ [18] = RCAR_GP_PIN(1, 18), /* SSI_SCK */
+ [19] = RCAR_GP_PIN(1, 19), /* SSI_WS */
+ [20] = RCAR_GP_PIN(1, 20), /* SSI_SD */
+ [21] = RCAR_GP_PIN(1, 21), /* AUDIO_CLKOUT */
+ [22] = RCAR_GP_PIN(1, 22), /* AUDIO_CLKIN */
+ [23] = RCAR_GP_PIN(1, 23), /* GP1_23 */
+ [24] = RCAR_GP_PIN(1, 24), /* HRX3 */
+ [25] = RCAR_GP_PIN(1, 25), /* HSCK3 */
+ [26] = RCAR_GP_PIN(1, 26), /* HRTS3_N */
+ [27] = RCAR_GP_PIN(1, 27), /* HCTS3_N */
+ [28] = RCAR_GP_PIN(1, 28), /* HTX3 */
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("PUEN2", 0xE60580C0, "PUD2", 0xE60580E0) {
+ [ 0] = RCAR_GP_PIN(2, 0), /* FXR_TXDA */
+ [ 1] = RCAR_GP_PIN(2, 1), /* FXR_TXENA_N */
+ [ 2] = RCAR_GP_PIN(2, 2), /* RXDA_EXTFXR */
+ [ 3] = RCAR_GP_PIN(2, 3), /* CLK_EXTFXR */
+ [ 4] = RCAR_GP_PIN(2, 4), /* RXDB_EXTFXR */
+ [ 5] = RCAR_GP_PIN(2, 5), /* FXR_TXENB_N */
+ [ 6] = RCAR_GP_PIN(2, 6), /* FXR_TXDB */
+ [ 7] = RCAR_GP_PIN(2, 7), /* TPU0TO1 */
+ [ 8] = RCAR_GP_PIN(2, 8), /* TPU0TO0 */
+ [ 9] = RCAR_GP_PIN(2, 9), /* CAN_CLK */
+ [10] = RCAR_GP_PIN(2, 10), /* CANFD0_TX */
+ [11] = RCAR_GP_PIN(2, 11), /* CANFD0_RX */
+ [12] = RCAR_GP_PIN(2, 12), /* CANFD2_TX */
+ [13] = RCAR_GP_PIN(2, 13), /* CANFD2_RX */
+ [14] = RCAR_GP_PIN(2, 14), /* CANFD3_TX */
+ [15] = RCAR_GP_PIN(2, 15), /* CANFD3_RX */
+ [16] = RCAR_GP_PIN(2, 16), /* CANFD4_TX */
+ [17] = RCAR_GP_PIN(2, 17), /* CANFD4_RX */
+ [18] = RCAR_GP_PIN(2, 18), /* CANFD7_TX */
+ [19] = RCAR_GP_PIN(2, 19), /* CANFD7_RX */
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("PUEN3", 0xE60588C0, "PUD3", 0xE60588E0) {
+ [ 0] = RCAR_GP_PIN(3, 0), /* MMC_SD_D1 */
+ [ 1] = RCAR_GP_PIN(3, 1), /* MMC_SD_D0 */
+ [ 2] = RCAR_GP_PIN(3, 2), /* MMC_SD_D2 */
+ [ 3] = RCAR_GP_PIN(3, 3), /* MMC_SD_CLK */
+ [ 4] = RCAR_GP_PIN(3, 4), /* MMC_DS */
+ [ 5] = RCAR_GP_PIN(3, 5), /* MMC_SD_D3 */
+ [ 6] = RCAR_GP_PIN(3, 6), /* MMC_D5 */
+ [ 7] = RCAR_GP_PIN(3, 7), /* MMC_D4 */
+ [ 8] = RCAR_GP_PIN(3, 8), /* MMC_D7 */
+ [ 9] = RCAR_GP_PIN(3, 9), /* MMC_D6 */
+ [10] = RCAR_GP_PIN(3, 10), /* MMC_SD_CMD */
+ [11] = RCAR_GP_PIN(3, 11), /* SD_CD */
+ [12] = RCAR_GP_PIN(3, 12), /* SD_WP */
+ [13] = RCAR_GP_PIN(3, 13), /* IPC_CLKIN */
+ [14] = RCAR_GP_PIN(3, 14), /* IPC_CLKOUT */
+ [15] = RCAR_GP_PIN(3, 15), /* QSPI0_SSL */
+ [16] = RCAR_GP_PIN(3, 16), /* QSPI0_IO3 */
+ [17] = RCAR_GP_PIN(3, 17), /* QSPI0_IO2 */
+ [18] = RCAR_GP_PIN(3, 18), /* QSPI0_MISO_IO1 */
+ [19] = RCAR_GP_PIN(3, 19), /* QSPI0_MOSI_IO0 */
+ [20] = RCAR_GP_PIN(3, 20), /* QSPI0_SPCLK */
+ [21] = RCAR_GP_PIN(3, 21), /* QSPI1_MOSI_IO0 */
+ [22] = RCAR_GP_PIN(3, 22), /* QSPI1_SPCLK */
+ [23] = RCAR_GP_PIN(3, 23), /* QSPI1_MISO_IO1 */
+ [24] = RCAR_GP_PIN(3, 24), /* QSPI1_IO2 */
+ [25] = RCAR_GP_PIN(3, 25), /* QSPI1_SSL */
+ [26] = RCAR_GP_PIN(3, 26), /* QSPI1_IO3 */
+ [27] = RCAR_GP_PIN(3, 27), /* RPC_RESET_N */
+ [28] = RCAR_GP_PIN(3, 28), /* RPC_WP_N */
+ [29] = RCAR_GP_PIN(3, 29), /* RPC_INT_N */
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("PUEN4", 0xE60600C0, "PUD4", 0xE60600E0) {
+ [ 0] = RCAR_GP_PIN(4, 0), /* TSN0_MDIO */
+ [ 1] = RCAR_GP_PIN(4, 1), /* TSN0_MDC */
+ [ 2] = RCAR_GP_PIN(4, 2), /* TSN0_AVTP_PPS1 */
+ [ 3] = RCAR_GP_PIN(4, 3), /* TSN0_PHY_INT */
+ [ 4] = RCAR_GP_PIN(4, 4), /* TSN0_LINK */
+ [ 5] = RCAR_GP_PIN(4, 5), /* TSN0_AVTP_MATCH */
+ [ 6] = RCAR_GP_PIN(4, 6), /* TSN0_AVTP_CAPTURE */
+ [ 7] = RCAR_GP_PIN(4, 7), /* TSN0_RX_CTL */
+ [ 8] = RCAR_GP_PIN(4, 8), /* TSN0_AVTP_PPS0 */
+ [ 9] = RCAR_GP_PIN(4, 9), /* TSN0_TX_CTL */
+ [10] = RCAR_GP_PIN(4, 10), /* TSN0_RD0 */
+ [11] = RCAR_GP_PIN(4, 11), /* TSN0_RXC */
+ [12] = RCAR_GP_PIN(4, 12), /* TSN0_TXC */
+ [13] = RCAR_GP_PIN(4, 13), /* TSN0_RD1 */
+ [14] = RCAR_GP_PIN(4, 14), /* TSN0_TD1 */
+ [15] = RCAR_GP_PIN(4, 15), /* TSN0_TD0 */
+ [16] = RCAR_GP_PIN(4, 16), /* TSN0_RD3 */
+ [17] = RCAR_GP_PIN(4, 17), /* TSN0_RD2 */
+ [18] = RCAR_GP_PIN(4, 18), /* TSN0_TD3 */
+ [19] = RCAR_GP_PIN(4, 19), /* TSN0_TD2 */
+ [20] = RCAR_GP_PIN(4, 20), /* TSN0_TXCREFCLK */
+ [21] = RCAR_GP_PIN(4, 21), /* PCIE0_CLKREQ_N */
+ [22] = RCAR_GP_PIN(4, 22), /* PCIE1_CLKREQ_N */
+ [23] = RCAR_GP_PIN(4, 23), /* AVS0 */
+ [24] = RCAR_GP_PIN(4, 24), /* AVS1 */
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("PUEN5", 0xE60608C0, "PUD5", 0xE60608E0) {
+ [ 0] = RCAR_GP_PIN(5, 0), /* AVB2_AVTP_PPS */
+ [ 1] = RCAR_GP_PIN(5, 1), /* AVB0_AVTP_CAPTURE */
+ [ 2] = RCAR_GP_PIN(5, 2), /* AVB2_AVTP_MATCH */
+ [ 3] = RCAR_GP_PIN(5, 3), /* AVB2_LINK */
+ [ 4] = RCAR_GP_PIN(5, 4), /* AVB2_PHY_INT */
+ [ 5] = RCAR_GP_PIN(5, 5), /* AVB2_MAGIC */
+ [ 6] = RCAR_GP_PIN(5, 6), /* AVB2_MDC */
+ [ 7] = RCAR_GP_PIN(5, 7), /* AVB2_TXCREFCLK */
+ [ 8] = RCAR_GP_PIN(5, 8), /* AVB2_TD3 */
+ [ 9] = RCAR_GP_PIN(5, 9), /* AVB2_RD3 */
+ [10] = RCAR_GP_PIN(5, 10), /* AVB2_MDIO */
+ [11] = RCAR_GP_PIN(5, 11), /* AVB2_TD2 */
+ [12] = RCAR_GP_PIN(5, 12), /* AVB2_TD1 */
+ [13] = RCAR_GP_PIN(5, 13), /* AVB2_RD2 */
+ [14] = RCAR_GP_PIN(5, 14), /* AVB2_RD1 */
+ [15] = RCAR_GP_PIN(5, 15), /* AVB2_TD0 */
+ [16] = RCAR_GP_PIN(5, 16), /* AVB2_TXC */
+ [17] = RCAR_GP_PIN(5, 17), /* AVB2_RD0 */
+ [18] = RCAR_GP_PIN(5, 18), /* AVB2_RXC */
+ [19] = RCAR_GP_PIN(5, 19), /* AVB2_TX_CTL */
+ [20] = RCAR_GP_PIN(5, 20), /* AVB2_RX_CTL */
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("PUEN6", 0xE60610C0, "PUD6", 0xE60610E0) {
+ [ 0] = RCAR_GP_PIN(6, 0), /* AVB1_MDIO */
+ [ 1] = RCAR_GP_PIN(6, 1), /* AVB1_MAGIC */
+ [ 2] = RCAR_GP_PIN(6, 2), /* AVB1_MDC */
+ [ 3] = RCAR_GP_PIN(6, 3), /* AVB1_PHY_INT */
+ [ 4] = RCAR_GP_PIN(6, 4), /* AVB1_LINK */
+ [ 5] = RCAR_GP_PIN(6, 5), /* AVB1_AVTP_MATCH */
+ [ 6] = RCAR_GP_PIN(6, 6), /* AVB1_TXC */
+ [ 7] = RCAR_GP_PIN(6, 7), /* AVB1_TX_CTL */
+ [ 8] = RCAR_GP_PIN(6, 8), /* AVB1_RXC */
+ [ 9] = RCAR_GP_PIN(6, 9), /* AVB1_RX_CTL */
+ [10] = RCAR_GP_PIN(6, 10), /* AVB1_AVTP_PPS */
+ [11] = RCAR_GP_PIN(6, 11), /* AVB1_AVTP_CAPTURE */
+ [12] = RCAR_GP_PIN(6, 12), /* AVB1_TD1 */
+ [13] = RCAR_GP_PIN(6, 13), /* AVB1_TD0 */
+ [14] = RCAR_GP_PIN(6, 14), /* AVB1_RD1*/
+ [15] = RCAR_GP_PIN(6, 15), /* AVB1_RD0 */
+ [16] = RCAR_GP_PIN(6, 16), /* AVB1_TD2 */
+ [17] = RCAR_GP_PIN(6, 17), /* AVB1_RD2 */
+ [18] = RCAR_GP_PIN(6, 18), /* AVB1_TD3 */
+ [19] = RCAR_GP_PIN(6, 19), /* AVB1_RD3 */
+ [20] = RCAR_GP_PIN(6, 20), /* AVB1_TXCREFCLK */
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("PUEN7", 0xE60618C0, "PUD7", 0xE60618E0) {
+ [ 0] = RCAR_GP_PIN(7, 0), /* AVB0_AVTP_PPS */
+ [ 1] = RCAR_GP_PIN(7, 1), /* AVB0_AVTP_CAPTURE */
+ [ 2] = RCAR_GP_PIN(7, 2), /* AVB0_AVTP_MATCH */
+ [ 3] = RCAR_GP_PIN(7, 3), /* AVB0_TD3 */
+ [ 4] = RCAR_GP_PIN(7, 4), /* AVB0_LINK */
+ [ 5] = RCAR_GP_PIN(7, 5), /* AVB0_PHY_INT */
+ [ 6] = RCAR_GP_PIN(7, 6), /* AVB0_TD2 */
+ [ 7] = RCAR_GP_PIN(7, 7), /* AVB0_TD1 */
+ [ 8] = RCAR_GP_PIN(7, 8), /* AVB0_RD3 */
+ [ 9] = RCAR_GP_PIN(7, 9), /* AVB0_TXCREFCLK */
+ [10] = RCAR_GP_PIN(7, 10), /* AVB0_MAGIC */
+ [11] = RCAR_GP_PIN(7, 11), /* AVB0_TD0 */
+ [12] = RCAR_GP_PIN(7, 12), /* AVB0_RD2 */
+ [13] = RCAR_GP_PIN(7, 13), /* AVB0_MDC */
+ [14] = RCAR_GP_PIN(7, 14), /* AVB0_MDIO */
+ [15] = RCAR_GP_PIN(7, 15), /* AVB0_TXC */
+ [16] = RCAR_GP_PIN(7, 16), /* AVB0_TX_CTL */
+ [17] = RCAR_GP_PIN(7, 17), /* AVB0_RD1 */
+ [18] = RCAR_GP_PIN(7, 18), /* AVB0_RD0 */
+ [19] = RCAR_GP_PIN(7, 19), /* AVB0_RXC */
+ [20] = RCAR_GP_PIN(7, 20), /* AVB0_RX_CTL */
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("PUEN8", 0xE60680C0, "PUD8", 0xE60680E0) {
+ [ 0] = RCAR_GP_PIN(8, 0), /* SCL0 */
+ [ 1] = RCAR_GP_PIN(8, 1), /* SDA0 */
+ [ 2] = RCAR_GP_PIN(8, 2), /* SCL1 */
+ [ 3] = RCAR_GP_PIN(8, 3), /* SDA1 */
+ [ 4] = RCAR_GP_PIN(8, 4), /* SCL2 */
+ [ 5] = RCAR_GP_PIN(8, 5), /* SDA2 */
+ [ 6] = RCAR_GP_PIN(8, 6), /* SCL3 */
+ [ 7] = RCAR_GP_PIN(8, 7), /* SDA3 */
+ [ 8] = RCAR_GP_PIN(8, 8), /* SCL4 */
+ [ 9] = RCAR_GP_PIN(8, 9), /* SDA4 */
+ [10] = RCAR_GP_PIN(8, 10), /* SCL5 */
+ [11] = RCAR_GP_PIN(8, 11), /* SDA5 */
+ [12] = RCAR_GP_PIN(8, 12), /* GP8_12 */
+ [13] = RCAR_GP_PIN(8, 13), /* GP8_13 */
+ [14] = SH_PFC_PIN_NONE,
+ [15] = SH_PFC_PIN_NONE,
+ [16] = SH_PFC_PIN_NONE,
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { /* sentinel */ },
+};
+
+static const struct sh_pfc_soc_operations r8a779g0_pin_ops = {
+ .pin_to_pocctrl = r8a779g0_pin_to_pocctrl,
+ .get_bias = rcar_pinmux_get_bias,
+ .set_bias = rcar_pinmux_set_bias,
+};
+
+const struct sh_pfc_soc_info r8a779g0_pinmux_info = {
+ .name = "r8a779g0_pfc",
+ .ops = &r8a779g0_pin_ops,
+ .unlock_reg = 0x1ff, /* PMMRn mask */
+
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .pins = pinmux_pins,
+ .nr_pins = ARRAY_SIZE(pinmux_pins),
+ .groups = pinmux_groups,
+ .nr_groups = ARRAY_SIZE(pinmux_groups),
+ .functions = pinmux_functions,
+ .nr_functions = ARRAY_SIZE(pinmux_functions),
+
+ .cfg_regs = pinmux_config_regs,
+ .drive_regs = pinmux_drive_regs,
+ .bias_regs = pinmux_bias_regs,
+ .ioctrl_regs = pinmux_ioctrl_regs,
+
+ .pinmux_data = pinmux_data,
+ .pinmux_data_size = ARRAY_SIZE(pinmux_data),
+};
if (!(cfg & PIN_CFG_IEN))
return -EINVAL;
arg = rzg2l_read_pin_config(pctrl, IEN(port_offset), bit, IEN_MASK);
+ if (!arg)
+ return -EINVAL;
break;
case PIN_CONFIG_POWER_SOURCE: {
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/V2M Pin Control and GPIO driver core
+ *
+ * Based on:
+ * Renesas RZ/G2L Pin Control and GPIO driver core
+ *
+ * Copyright (C) 2022 Renesas Electronics Corporation.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/spinlock.h>
+
+#include <dt-bindings/pinctrl/rzv2m-pinctrl.h>
+
+#include "../core.h"
+#include "../pinconf.h"
+#include "../pinmux.h"
+
+#define DRV_NAME "pinctrl-rzv2m"
+
+/*
+ * Use 16 lower bits [15:0] for pin identifier
+ * Use 16 higher bits [31:16] for pin mux function
+ */
+#define MUX_PIN_ID_MASK GENMASK(15, 0)
+#define MUX_FUNC_MASK GENMASK(31, 16)
+#define MUX_FUNC(pinconf) FIELD_GET(MUX_FUNC_MASK, (pinconf))
+
+/* PIN capabilities */
+#define PIN_CFG_GRP_1_8V_2 1
+#define PIN_CFG_GRP_1_8V_3 2
+#define PIN_CFG_GRP_SWIO_1 3
+#define PIN_CFG_GRP_SWIO_2 4
+#define PIN_CFG_GRP_3_3V 5
+#define PIN_CFG_GRP_MASK GENMASK(2, 0)
+#define PIN_CFG_BIAS BIT(3)
+#define PIN_CFG_DRV BIT(4)
+#define PIN_CFG_SLEW BIT(5)
+
+#define RZV2M_MPXED_PIN_FUNCS (PIN_CFG_BIAS | \
+ PIN_CFG_DRV | \
+ PIN_CFG_SLEW)
+
+/*
+ * n indicates number of pins in the port, a is the register index
+ * and f is pin configuration capabilities supported.
+ */
+#define RZV2M_GPIO_PORT_PACK(n, a, f) (((n) << 24) | ((a) << 16) | (f))
+#define RZV2M_GPIO_PORT_GET_PINCNT(x) FIELD_GET(GENMASK(31, 24), (x))
+#define RZV2M_GPIO_PORT_GET_INDEX(x) FIELD_GET(GENMASK(23, 16), (x))
+#define RZV2M_GPIO_PORT_GET_CFGS(x) FIELD_GET(GENMASK(15, 0), (x))
+
+#define RZV2M_DEDICATED_PORT_IDX 22
+
+/*
+ * BIT(31) indicates dedicated pin, b is the register bits (b * 16)
+ * and f is the pin configuration capabilities supported.
+ */
+#define RZV2M_SINGLE_PIN BIT(31)
+#define RZV2M_SINGLE_PIN_PACK(b, f) (RZV2M_SINGLE_PIN | \
+ ((RZV2M_DEDICATED_PORT_IDX) << 24) | \
+ ((b) << 16) | (f))
+#define RZV2M_SINGLE_PIN_GET_PORT(x) FIELD_GET(GENMASK(30, 24), (x))
+#define RZV2M_SINGLE_PIN_GET_BIT(x) FIELD_GET(GENMASK(23, 16), (x))
+#define RZV2M_SINGLE_PIN_GET_CFGS(x) FIELD_GET(GENMASK(15, 0), (x))
+
+#define RZV2M_PIN_ID_TO_PORT(id) ((id) / RZV2M_PINS_PER_PORT)
+#define RZV2M_PIN_ID_TO_PIN(id) ((id) % RZV2M_PINS_PER_PORT)
+
+#define DO(n) (0x00 + (n) * 0x40)
+#define OE(n) (0x04 + (n) * 0x40)
+#define IE(n) (0x08 + (n) * 0x40)
+#define PFSEL(n) (0x10 + (n) * 0x40)
+#define DI(n) (0x20 + (n) * 0x40)
+#define PUPD(n) (0x24 + (n) * 0x40)
+#define DRV(n) ((n) < RZV2M_DEDICATED_PORT_IDX ? (0x28 + (n) * 0x40) \
+ : 0x590)
+#define SR(n) ((n) < RZV2M_DEDICATED_PORT_IDX ? (0x2c + (n) * 0x40) \
+ : 0x594)
+#define DI_MSK(n) (0x30 + (n) * 0x40)
+#define EN_MSK(n) (0x34 + (n) * 0x40)
+
+#define PFC_MASK 0x07
+#define PUPD_MASK 0x03
+#define DRV_MASK 0x03
+
+struct rzv2m_dedicated_configs {
+ const char *name;
+ u32 config;
+};
+
+struct rzv2m_pinctrl_data {
+ const char * const *port_pins;
+ const u32 *port_pin_configs;
+ const struct rzv2m_dedicated_configs *dedicated_pins;
+ unsigned int n_port_pins;
+ unsigned int n_dedicated_pins;
+};
+
+struct rzv2m_pinctrl {
+ struct pinctrl_dev *pctl;
+ struct pinctrl_desc desc;
+ struct pinctrl_pin_desc *pins;
+
+ const struct rzv2m_pinctrl_data *data;
+ void __iomem *base;
+ struct device *dev;
+ struct clk *clk;
+
+ struct gpio_chip gpio_chip;
+ struct pinctrl_gpio_range gpio_range;
+
+ spinlock_t lock;
+};
+
+static const unsigned int drv_1_8V_group2_uA[] = { 1800, 3800, 7800, 11000 };
+static const unsigned int drv_1_8V_group3_uA[] = { 1600, 3200, 6400, 9600 };
+static const unsigned int drv_SWIO_group2_3_3V_uA[] = { 9000, 11000, 13000, 18000 };
+static const unsigned int drv_3_3V_group_uA[] = { 2000, 4000, 8000, 12000 };
+
+/* Helper for registers that have a write enable bit in the upper word */
+static void rzv2m_writel_we(void __iomem *addr, u8 shift, u8 value)
+{
+ writel((BIT(16) | value) << shift, addr);
+}
+
+static void rzv2m_pinctrl_set_pfc_mode(struct rzv2m_pinctrl *pctrl,
+ u8 port, u8 pin, u8 func)
+{
+ void __iomem *addr;
+
+ /* Mask input/output */
+ rzv2m_writel_we(pctrl->base + DI_MSK(port), pin, 1);
+ rzv2m_writel_we(pctrl->base + EN_MSK(port), pin, 1);
+
+ /* Select the function and set the write enable bits */
+ addr = pctrl->base + PFSEL(port) + (pin / 4) * 4;
+ writel(((PFC_MASK << 16) | func) << ((pin % 4) * 4), addr);
+
+ /* Unmask input/output */
+ rzv2m_writel_we(pctrl->base + EN_MSK(port), pin, 0);
+ rzv2m_writel_we(pctrl->base + DI_MSK(port), pin, 0);
+};
+
+static int rzv2m_pinctrl_set_mux(struct pinctrl_dev *pctldev,
+ unsigned int func_selector,
+ unsigned int group_selector)
+{
+ struct rzv2m_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ struct function_desc *func;
+ unsigned int i, *psel_val;
+ struct group_desc *group;
+ int *pins;
+
+ func = pinmux_generic_get_function(pctldev, func_selector);
+ if (!func)
+ return -EINVAL;
+ group = pinctrl_generic_get_group(pctldev, group_selector);
+ if (!group)
+ return -EINVAL;
+
+ psel_val = func->data;
+ pins = group->pins;
+
+ for (i = 0; i < group->num_pins; i++) {
+ dev_dbg(pctrl->dev, "port:%u pin: %u PSEL:%u\n",
+ RZV2M_PIN_ID_TO_PORT(pins[i]), RZV2M_PIN_ID_TO_PIN(pins[i]),
+ psel_val[i]);
+ rzv2m_pinctrl_set_pfc_mode(pctrl, RZV2M_PIN_ID_TO_PORT(pins[i]),
+ RZV2M_PIN_ID_TO_PIN(pins[i]), psel_val[i]);
+ }
+
+ return 0;
+};
+
+static int rzv2m_map_add_config(struct pinctrl_map *map,
+ const char *group_or_pin,
+ enum pinctrl_map_type type,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ unsigned long *cfgs;
+
+ cfgs = kmemdup(configs, num_configs * sizeof(*cfgs),
+ GFP_KERNEL);
+ if (!cfgs)
+ return -ENOMEM;
+
+ map->type = type;
+ map->data.configs.group_or_pin = group_or_pin;
+ map->data.configs.configs = cfgs;
+ map->data.configs.num_configs = num_configs;
+
+ return 0;
+}
+
+static int rzv2m_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **map,
+ unsigned int *num_maps,
+ unsigned int *index)
+{
+ struct rzv2m_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ struct pinctrl_map *maps = *map;
+ unsigned int nmaps = *num_maps;
+ unsigned long *configs = NULL;
+ unsigned int *pins, *psel_val;
+ unsigned int num_pinmux = 0;
+ unsigned int idx = *index;
+ unsigned int num_pins, i;
+ unsigned int num_configs;
+ struct property *pinmux;
+ struct property *prop;
+ int ret, gsel, fsel;
+ const char **pin_fn;
+ const char *pin;
+
+ pinmux = of_find_property(np, "pinmux", NULL);
+ if (pinmux)
+ num_pinmux = pinmux->length / sizeof(u32);
+
+ ret = of_property_count_strings(np, "pins");
+ if (ret == -EINVAL) {
+ num_pins = 0;
+ } else if (ret < 0) {
+ dev_err(pctrl->dev, "Invalid pins list in DT\n");
+ return ret;
+ } else {
+ num_pins = ret;
+ }
+
+ if (!num_pinmux && !num_pins)
+ return 0;
+
+ if (num_pinmux && num_pins) {
+ dev_err(pctrl->dev,
+ "DT node must contain either a pinmux or pins and not both\n");
+ return -EINVAL;
+ }
+
+ ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &num_configs);
+ if (ret < 0)
+ return ret;
+
+ if (num_pins && !num_configs) {
+ dev_err(pctrl->dev, "DT node must contain a config\n");
+ ret = -ENODEV;
+ goto done;
+ }
+
+ if (num_pinmux)
+ nmaps += 1;
+
+ if (num_pins)
+ nmaps += num_pins;
+
+ maps = krealloc_array(maps, nmaps, sizeof(*maps), GFP_KERNEL);
+ if (!maps) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ *map = maps;
+ *num_maps = nmaps;
+ if (num_pins) {
+ of_property_for_each_string(np, "pins", prop, pin) {
+ ret = rzv2m_map_add_config(&maps[idx], pin,
+ PIN_MAP_TYPE_CONFIGS_PIN,
+ configs, num_configs);
+ if (ret < 0)
+ goto done;
+
+ idx++;
+ }
+ ret = 0;
+ goto done;
+ }
+
+ pins = devm_kcalloc(pctrl->dev, num_pinmux, sizeof(*pins), GFP_KERNEL);
+ psel_val = devm_kcalloc(pctrl->dev, num_pinmux, sizeof(*psel_val),
+ GFP_KERNEL);
+ pin_fn = devm_kzalloc(pctrl->dev, sizeof(*pin_fn), GFP_KERNEL);
+ if (!pins || !psel_val || !pin_fn) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Collect pin locations and mux settings from DT properties */
+ for (i = 0; i < num_pinmux; ++i) {
+ u32 value;
+
+ ret = of_property_read_u32_index(np, "pinmux", i, &value);
+ if (ret)
+ goto done;
+ pins[i] = value & MUX_PIN_ID_MASK;
+ psel_val[i] = MUX_FUNC(value);
+ }
+
+ /* Register a single pin group listing all the pins we read from DT */
+ gsel = pinctrl_generic_add_group(pctldev, np->name, pins, num_pinmux, NULL);
+ if (gsel < 0) {
+ ret = gsel;
+ goto done;
+ }
+
+ /*
+ * Register a single group function where the 'data' is an array PSEL
+ * register values read from DT.
+ */
+ pin_fn[0] = np->name;
+ fsel = pinmux_generic_add_function(pctldev, np->name, pin_fn, 1,
+ psel_val);
+ if (fsel < 0) {
+ ret = fsel;
+ goto remove_group;
+ }
+
+ maps[idx].type = PIN_MAP_TYPE_MUX_GROUP;
+ maps[idx].data.mux.group = np->name;
+ maps[idx].data.mux.function = np->name;
+ idx++;
+
+ dev_dbg(pctrl->dev, "Parsed %pOF with %d pins\n", np, num_pinmux);
+ ret = 0;
+ goto done;
+
+remove_group:
+ pinctrl_generic_remove_group(pctldev, gsel);
+done:
+ *index = idx;
+ kfree(configs);
+ return ret;
+}
+
+static void rzv2m_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map,
+ unsigned int num_maps)
+{
+ unsigned int i;
+
+ if (!map)
+ return;
+
+ for (i = 0; i < num_maps; ++i) {
+ if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP ||
+ map[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
+ kfree(map[i].data.configs.configs);
+ }
+ kfree(map);
+}
+
+static int rzv2m_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **map,
+ unsigned int *num_maps)
+{
+ struct rzv2m_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ struct device_node *child;
+ unsigned int index;
+ int ret;
+
+ *map = NULL;
+ *num_maps = 0;
+ index = 0;
+
+ for_each_child_of_node(np, child) {
+ ret = rzv2m_dt_subnode_to_map(pctldev, child, map,
+ num_maps, &index);
+ if (ret < 0) {
+ of_node_put(child);
+ goto done;
+ }
+ }
+
+ if (*num_maps == 0) {
+ ret = rzv2m_dt_subnode_to_map(pctldev, np, map,
+ num_maps, &index);
+ if (ret < 0)
+ goto done;
+ }
+
+ if (*num_maps)
+ return 0;
+
+ dev_err(pctrl->dev, "no mapping found in node %pOF\n", np);
+ ret = -EINVAL;
+
+done:
+ if (ret < 0)
+ rzv2m_dt_free_map(pctldev, *map, *num_maps);
+
+ return ret;
+}
+
+static int rzv2m_validate_gpio_pin(struct rzv2m_pinctrl *pctrl,
+ u32 cfg, u32 port, u8 bit)
+{
+ u8 pincount = RZV2M_GPIO_PORT_GET_PINCNT(cfg);
+ u32 port_index = RZV2M_GPIO_PORT_GET_INDEX(cfg);
+ u32 data;
+
+ if (bit >= pincount || port >= pctrl->data->n_port_pins)
+ return -EINVAL;
+
+ data = pctrl->data->port_pin_configs[port];
+ if (port_index != RZV2M_GPIO_PORT_GET_INDEX(data))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void rzv2m_rmw_pin_config(struct rzv2m_pinctrl *pctrl, u32 offset,
+ u8 shift, u32 mask, u32 val)
+{
+ void __iomem *addr = pctrl->base + offset;
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+ reg = readl(addr) & ~(mask << shift);
+ writel(reg | (val << shift), addr);
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+}
+
+static int rzv2m_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
+ unsigned int _pin,
+ unsigned long *config)
+{
+ struct rzv2m_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ const struct pinctrl_pin_desc *pin = &pctrl->desc.pins[_pin];
+ unsigned int *pin_data = pin->drv_data;
+ unsigned int arg = 0;
+ u32 port;
+ u32 cfg;
+ u8 bit;
+ u32 val;
+
+ if (!pin_data)
+ return -EINVAL;
+
+ if (*pin_data & RZV2M_SINGLE_PIN) {
+ port = RZV2M_SINGLE_PIN_GET_PORT(*pin_data);
+ cfg = RZV2M_SINGLE_PIN_GET_CFGS(*pin_data);
+ bit = RZV2M_SINGLE_PIN_GET_BIT(*pin_data);
+ } else {
+ cfg = RZV2M_GPIO_PORT_GET_CFGS(*pin_data);
+ port = RZV2M_PIN_ID_TO_PORT(_pin);
+ bit = RZV2M_PIN_ID_TO_PIN(_pin);
+
+ if (rzv2m_validate_gpio_pin(pctrl, *pin_data, RZV2M_PIN_ID_TO_PORT(_pin), bit))
+ return -EINVAL;
+ }
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ case PIN_CONFIG_BIAS_PULL_DOWN: {
+ enum pin_config_param bias;
+
+ if (!(cfg & PIN_CFG_BIAS))
+ return -EINVAL;
+
+ /* PUPD uses 2-bits per pin */
+ bit *= 2;
+
+ switch ((readl(pctrl->base + PUPD(port)) >> bit) & PUPD_MASK) {
+ case 0:
+ bias = PIN_CONFIG_BIAS_PULL_DOWN;
+ break;
+ case 2:
+ bias = PIN_CONFIG_BIAS_PULL_UP;
+ break;
+ default:
+ bias = PIN_CONFIG_BIAS_DISABLE;
+ }
+
+ if (bias != param)
+ return -EINVAL;
+ break;
+ }
+
+ case PIN_CONFIG_DRIVE_STRENGTH_UA:
+ if (!(cfg & PIN_CFG_DRV))
+ return -EINVAL;
+
+ /* DRV uses 2-bits per pin */
+ bit *= 2;
+
+ val = (readl(pctrl->base + DRV(port)) >> bit) & DRV_MASK;
+
+ switch (cfg & PIN_CFG_GRP_MASK) {
+ case PIN_CFG_GRP_1_8V_2:
+ arg = drv_1_8V_group2_uA[val];
+ break;
+ case PIN_CFG_GRP_1_8V_3:
+ arg = drv_1_8V_group3_uA[val];
+ break;
+ case PIN_CFG_GRP_SWIO_2:
+ arg = drv_SWIO_group2_3_3V_uA[val];
+ break;
+ case PIN_CFG_GRP_SWIO_1:
+ case PIN_CFG_GRP_3_3V:
+ arg = drv_3_3V_group_uA[val];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ break;
+
+ case PIN_CONFIG_SLEW_RATE:
+ if (!(cfg & PIN_CFG_SLEW))
+ return -EINVAL;
+
+ arg = readl(pctrl->base + SR(port)) & BIT(bit);
+ break;
+
+ default:
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+
+ return 0;
+};
+
+static int rzv2m_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
+ unsigned int _pin,
+ unsigned long *_configs,
+ unsigned int num_configs)
+{
+ struct rzv2m_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const struct pinctrl_pin_desc *pin = &pctrl->desc.pins[_pin];
+ unsigned int *pin_data = pin->drv_data;
+ enum pin_config_param param;
+ u32 port;
+ unsigned int i;
+ u32 cfg;
+ u8 bit;
+ u32 val;
+
+ if (!pin_data)
+ return -EINVAL;
+
+ if (*pin_data & RZV2M_SINGLE_PIN) {
+ port = RZV2M_SINGLE_PIN_GET_PORT(*pin_data);
+ cfg = RZV2M_SINGLE_PIN_GET_CFGS(*pin_data);
+ bit = RZV2M_SINGLE_PIN_GET_BIT(*pin_data);
+ } else {
+ cfg = RZV2M_GPIO_PORT_GET_CFGS(*pin_data);
+ port = RZV2M_PIN_ID_TO_PORT(_pin);
+ bit = RZV2M_PIN_ID_TO_PIN(_pin);
+
+ if (rzv2m_validate_gpio_pin(pctrl, *pin_data, RZV2M_PIN_ID_TO_PORT(_pin), bit))
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_configs; i++) {
+ param = pinconf_to_config_param(_configs[i]);
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (!(cfg & PIN_CFG_BIAS))
+ return -EINVAL;
+
+ /* PUPD uses 2-bits per pin */
+ bit *= 2;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ val = 0;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ val = 2;
+ break;
+ default:
+ val = 1;
+ }
+
+ rzv2m_rmw_pin_config(pctrl, PUPD(port), bit, PUPD_MASK, val);
+ break;
+
+ case PIN_CONFIG_DRIVE_STRENGTH_UA: {
+ unsigned int arg = pinconf_to_config_argument(_configs[i]);
+ const unsigned int *drv_strengths;
+ unsigned int index;
+
+ if (!(cfg & PIN_CFG_DRV))
+ return -EINVAL;
+
+ switch (cfg & PIN_CFG_GRP_MASK) {
+ case PIN_CFG_GRP_1_8V_2:
+ drv_strengths = drv_1_8V_group2_uA;
+ break;
+ case PIN_CFG_GRP_1_8V_3:
+ drv_strengths = drv_1_8V_group3_uA;
+ break;
+ case PIN_CFG_GRP_SWIO_2:
+ drv_strengths = drv_SWIO_group2_3_3V_uA;
+ break;
+ case PIN_CFG_GRP_SWIO_1:
+ case PIN_CFG_GRP_3_3V:
+ drv_strengths = drv_3_3V_group_uA;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (index = 0; index < 4; index++) {
+ if (arg == drv_strengths[index])
+ break;
+ }
+ if (index >= 4)
+ return -EINVAL;
+
+ /* DRV uses 2-bits per pin */
+ bit *= 2;
+
+ rzv2m_rmw_pin_config(pctrl, DRV(port), bit, DRV_MASK, index);
+ break;
+ }
+
+ case PIN_CONFIG_SLEW_RATE: {
+ unsigned int arg = pinconf_to_config_argument(_configs[i]);
+
+ if (!(cfg & PIN_CFG_SLEW))
+ return -EINVAL;
+
+ rzv2m_writel_we(pctrl->base + SR(port), bit, !arg);
+ break;
+ }
+
+ default:
+ return -EOPNOTSUPP;
+ }
+ }
+
+ return 0;
+}
+
+static int rzv2m_pinctrl_pinconf_group_set(struct pinctrl_dev *pctldev,
+ unsigned int group,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ const unsigned int *pins;
+ unsigned int i, npins;
+ int ret;
+
+ ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < npins; i++) {
+ ret = rzv2m_pinctrl_pinconf_set(pctldev, pins[i], configs,
+ num_configs);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+};
+
+static int rzv2m_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev,
+ unsigned int group,
+ unsigned long *config)
+{
+ const unsigned int *pins;
+ unsigned int i, npins, prev_config = 0;
+ int ret;
+
+ ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < npins; i++) {
+ ret = rzv2m_pinctrl_pinconf_get(pctldev, pins[i], config);
+ if (ret)
+ return ret;
+
+ /* Check config matches previous pins */
+ if (i && prev_config != *config)
+ return -EOPNOTSUPP;
+
+ prev_config = *config;
+ }
+
+ return 0;
+};
+
+static const struct pinctrl_ops rzv2m_pinctrl_pctlops = {
+ .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 = rzv2m_dt_node_to_map,
+ .dt_free_map = rzv2m_dt_free_map,
+};
+
+static const struct pinmux_ops rzv2m_pinctrl_pmxops = {
+ .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 = rzv2m_pinctrl_set_mux,
+ .strict = true,
+};
+
+static const struct pinconf_ops rzv2m_pinctrl_confops = {
+ .is_generic = true,
+ .pin_config_get = rzv2m_pinctrl_pinconf_get,
+ .pin_config_set = rzv2m_pinctrl_pinconf_set,
+ .pin_config_group_set = rzv2m_pinctrl_pinconf_group_set,
+ .pin_config_group_get = rzv2m_pinctrl_pinconf_group_get,
+ .pin_config_config_dbg_show = pinconf_generic_dump_config,
+};
+
+static int rzv2m_gpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+ struct rzv2m_pinctrl *pctrl = gpiochip_get_data(chip);
+ u32 port = RZV2M_PIN_ID_TO_PORT(offset);
+ u8 bit = RZV2M_PIN_ID_TO_PIN(offset);
+ int ret;
+
+ ret = pinctrl_gpio_request(chip->base + offset);
+ if (ret)
+ return ret;
+
+ rzv2m_pinctrl_set_pfc_mode(pctrl, port, bit, 0);
+
+ return 0;
+}
+
+static void rzv2m_gpio_set_direction(struct rzv2m_pinctrl *pctrl, u32 port,
+ u8 bit, bool output)
+{
+ rzv2m_writel_we(pctrl->base + OE(port), bit, output);
+ rzv2m_writel_we(pctrl->base + IE(port), bit, !output);
+}
+
+static int rzv2m_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+ struct rzv2m_pinctrl *pctrl = gpiochip_get_data(chip);
+ u32 port = RZV2M_PIN_ID_TO_PORT(offset);
+ u8 bit = RZV2M_PIN_ID_TO_PIN(offset);
+
+ if (!(readl(pctrl->base + IE(port)) & BIT(bit)))
+ return GPIO_LINE_DIRECTION_OUT;
+
+ return GPIO_LINE_DIRECTION_IN;
+}
+
+static int rzv2m_gpio_direction_input(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct rzv2m_pinctrl *pctrl = gpiochip_get_data(chip);
+ u32 port = RZV2M_PIN_ID_TO_PORT(offset);
+ u8 bit = RZV2M_PIN_ID_TO_PIN(offset);
+
+ rzv2m_gpio_set_direction(pctrl, port, bit, false);
+
+ return 0;
+}
+
+static void rzv2m_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct rzv2m_pinctrl *pctrl = gpiochip_get_data(chip);
+ u32 port = RZV2M_PIN_ID_TO_PORT(offset);
+ u8 bit = RZV2M_PIN_ID_TO_PIN(offset);
+
+ rzv2m_writel_we(pctrl->base + DO(port), bit, !!value);
+}
+
+static int rzv2m_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ struct rzv2m_pinctrl *pctrl = gpiochip_get_data(chip);
+ u32 port = RZV2M_PIN_ID_TO_PORT(offset);
+ u8 bit = RZV2M_PIN_ID_TO_PIN(offset);
+
+ rzv2m_gpio_set(chip, offset, value);
+ rzv2m_gpio_set_direction(pctrl, port, bit, true);
+
+ return 0;
+}
+
+static int rzv2m_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct rzv2m_pinctrl *pctrl = gpiochip_get_data(chip);
+ u32 port = RZV2M_PIN_ID_TO_PORT(offset);
+ u8 bit = RZV2M_PIN_ID_TO_PIN(offset);
+ int direction = rzv2m_gpio_get_direction(chip, offset);
+
+ if (direction == GPIO_LINE_DIRECTION_IN)
+ return !!(readl(pctrl->base + DI(port)) & BIT(bit));
+ else
+ return !!(readl(pctrl->base + DO(port)) & BIT(bit));
+}
+
+static void rzv2m_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+ pinctrl_gpio_free(chip->base + offset);
+
+ /*
+ * Set the GPIO as an input to ensure that the next GPIO request won't
+ * drive the GPIO pin as an output.
+ */
+ rzv2m_gpio_direction_input(chip, offset);
+}
+
+static const char * const rzv2m_gpio_names[] = {
+ "P0_0", "P0_1", "P0_2", "P0_3", "P0_4", "P0_5", "P0_6", "P0_7",
+ "P0_8", "P0_9", "P0_10", "P0_11", "P0_12", "P0_13", "P0_14", "P0_15",
+ "P1_0", "P1_1", "P1_2", "P1_3", "P1_4", "P1_5", "P1_6", "P1_7",
+ "P1_8", "P1_9", "P1_10", "P1_11", "P1_12", "P1_13", "P1_14", "P1_15",
+ "P2_0", "P2_1", "P2_2", "P2_3", "P2_4", "P2_5", "P2_6", "P2_7",
+ "P2_8", "P2_9", "P2_10", "P2_11", "P2_12", "P2_13", "P2_14", "P2_15",
+ "P3_0", "P3_1", "P3_2", "P3_3", "P3_4", "P3_5", "P3_6", "P3_7",
+ "P3_8", "P3_9", "P3_10", "P3_11", "P3_12", "P3_13", "P3_14", "P3_15",
+ "P4_0", "P4_1", "P4_2", "P4_3", "P4_4", "P4_5", "P4_6", "P4_7",
+ "P4_8", "P4_9", "P4_10", "P4_11", "P4_12", "P4_13", "P4_14", "P4_15",
+ "P5_0", "P5_1", "P5_2", "P5_3", "P5_4", "P5_5", "P5_6", "P5_7",
+ "P5_8", "P5_9", "P5_10", "P5_11", "P5_12", "P5_13", "P5_14", "P5_15",
+ "P6_0", "P6_1", "P6_2", "P6_3", "P6_4", "P6_5", "P6_6", "P6_7",
+ "P6_8", "P6_9", "P6_10", "P6_11", "P6_12", "P6_13", "P6_14", "P6_15",
+ "P7_0", "P7_1", "P7_2", "P7_3", "P7_4", "P7_5", "P7_6", "P7_7",
+ "P7_8", "P7_9", "P7_10", "P7_11", "P7_12", "P7_13", "P7_14", "P7_15",
+ "P8_0", "P8_1", "P8_2", "P8_3", "P8_4", "P8_5", "P8_6", "P8_7",
+ "P8_8", "P8_9", "P8_10", "P8_11", "P8_12", "P8_13", "P8_14", "P8_15",
+ "P9_0", "P9_1", "P9_2", "P9_3", "P9_4", "P9_5", "P9_6", "P9_7",
+ "P9_8", "P9_9", "P9_10", "P9_11", "P9_12", "P9_13", "P9_14", "P9_15",
+ "P10_0", "P10_1", "P10_2", "P10_3", "P10_4", "P10_5", "P10_6", "P10_7",
+ "P10_8", "P10_9", "P10_10", "P10_11", "P10_12", "P10_13", "P10_14", "P10_15",
+ "P11_0", "P11_1", "P11_2", "P11_3", "P11_4", "P11_5", "P11_6", "P11_7",
+ "P11_8", "P11_9", "P11_10", "P11_11", "P11_12", "P11_13", "P11_14", "P11_15",
+ "P12_0", "P12_1", "P12_2", "P12_3", "P12_4", "P12_5", "P12_6", "P12_7",
+ "P12_8", "P12_9", "P12_10", "P12_11", "P12_12", "P12_13", "P12_14", "P12_15",
+ "P13_0", "P13_1", "P13_2", "P13_3", "P13_4", "P13_5", "P13_6", "P13_7",
+ "P13_8", "P13_9", "P13_10", "P13_11", "P13_12", "P13_13", "P13_14", "P13_15",
+ "P14_0", "P14_1", "P14_2", "P14_3", "P14_4", "P14_5", "P14_6", "P14_7",
+ "P14_8", "P14_9", "P14_10", "P14_11", "P14_12", "P14_13", "P14_14", "P14_15",
+ "P15_0", "P15_1", "P15_2", "P15_3", "P15_4", "P15_5", "P15_6", "P15_7",
+ "P15_8", "P15_9", "P15_10", "P15_11", "P15_12", "P15_13", "P15_14", "P15_15",
+ "P16_0", "P16_1", "P16_2", "P16_3", "P16_4", "P16_5", "P16_6", "P16_7",
+ "P16_8", "P16_9", "P16_10", "P16_11", "P16_12", "P16_13", "P16_14", "P16_15",
+ "P17_0", "P17_1", "P17_2", "P17_3", "P17_4", "P17_5", "P17_6", "P17_7",
+ "P17_8", "P17_9", "P17_10", "P17_11", "P17_12", "P17_13", "P17_14", "P17_15",
+ "P18_0", "P18_1", "P18_2", "P18_3", "P18_4", "P18_5", "P18_6", "P18_7",
+ "P18_8", "P18_9", "P18_10", "P18_11", "P18_12", "P18_13", "P18_14", "P18_15",
+ "P19_0", "P19_1", "P19_2", "P19_3", "P19_4", "P19_5", "P19_6", "P19_7",
+ "P19_8", "P19_9", "P19_10", "P19_11", "P19_12", "P19_13", "P19_14", "P19_15",
+ "P20_0", "P20_1", "P20_2", "P20_3", "P20_4", "P20_5", "P20_6", "P20_7",
+ "P20_8", "P20_9", "P20_10", "P20_11", "P20_12", "P20_13", "P20_14", "P20_15",
+ "P21_0", "P21_1", "P21_2", "P21_3", "P21_4", "P21_5", "P21_6", "P21_7",
+ "P21_8", "P21_9", "P21_10", "P21_11", "P21_12", "P21_13", "P21_14", "P21_15",
+};
+
+static const u32 rzv2m_gpio_configs[] = {
+ RZV2M_GPIO_PORT_PACK(14, 0, PIN_CFG_GRP_SWIO_2 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(16, 1, PIN_CFG_GRP_SWIO_1 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(8, 2, PIN_CFG_GRP_1_8V_3 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(16, 3, PIN_CFG_GRP_SWIO_1 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(8, 4, PIN_CFG_GRP_SWIO_1 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(4, 5, PIN_CFG_GRP_1_8V_3 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(12, 6, PIN_CFG_GRP_SWIO_1 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(6, 7, PIN_CFG_GRP_SWIO_1 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(8, 8, PIN_CFG_GRP_SWIO_2 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(8, 9, PIN_CFG_GRP_SWIO_2 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(9, 10, PIN_CFG_GRP_SWIO_1 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(9, 11, PIN_CFG_GRP_SWIO_1 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(4, 12, PIN_CFG_GRP_3_3V | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(12, 13, PIN_CFG_GRP_3_3V | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(8, 14, PIN_CFG_GRP_3_3V | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(16, 15, PIN_CFG_GRP_SWIO_2 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(14, 16, PIN_CFG_GRP_SWIO_2 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(1, 17, PIN_CFG_GRP_SWIO_2 | RZV2M_MPXED_PIN_FUNCS),
+ RZV2M_GPIO_PORT_PACK(0, 18, 0),
+ RZV2M_GPIO_PORT_PACK(0, 19, 0),
+ RZV2M_GPIO_PORT_PACK(3, 20, PIN_CFG_GRP_1_8V_2 | PIN_CFG_DRV),
+ RZV2M_GPIO_PORT_PACK(1, 21, PIN_CFG_GRP_SWIO_1 | PIN_CFG_DRV | PIN_CFG_SLEW),
+};
+
+static const struct rzv2m_dedicated_configs rzv2m_dedicated_pins[] = {
+ { "NAWPN", RZV2M_SINGLE_PIN_PACK(0,
+ (PIN_CFG_GRP_SWIO_2 | PIN_CFG_DRV | PIN_CFG_SLEW)) },
+ { "IM0CLK", RZV2M_SINGLE_PIN_PACK(1,
+ (PIN_CFG_GRP_SWIO_1 | PIN_CFG_DRV | PIN_CFG_SLEW)) },
+ { "IM1CLK", RZV2M_SINGLE_PIN_PACK(2,
+ (PIN_CFG_GRP_SWIO_1 | PIN_CFG_DRV | PIN_CFG_SLEW)) },
+ { "DETDO", RZV2M_SINGLE_PIN_PACK(5,
+ (PIN_CFG_GRP_1_8V_3 | PIN_CFG_DRV | PIN_CFG_SLEW)) },
+ { "DETMS", RZV2M_SINGLE_PIN_PACK(6,
+ (PIN_CFG_GRP_1_8V_3 | PIN_CFG_DRV | PIN_CFG_SLEW)) },
+ { "PCRSTOUTB", RZV2M_SINGLE_PIN_PACK(12,
+ (PIN_CFG_GRP_3_3V | PIN_CFG_DRV | PIN_CFG_SLEW)) },
+ { "USPWEN", RZV2M_SINGLE_PIN_PACK(14,
+ (PIN_CFG_GRP_3_3V | PIN_CFG_DRV | PIN_CFG_SLEW)) },
+};
+
+static int rzv2m_gpio_register(struct rzv2m_pinctrl *pctrl)
+{
+ struct device_node *np = pctrl->dev->of_node;
+ struct gpio_chip *chip = &pctrl->gpio_chip;
+ const char *name = dev_name(pctrl->dev);
+ struct of_phandle_args of_args;
+ int ret;
+
+ ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &of_args);
+ if (ret) {
+ dev_err(pctrl->dev, "Unable to parse gpio-ranges\n");
+ return ret;
+ }
+
+ if (of_args.args[0] != 0 || of_args.args[1] != 0 ||
+ of_args.args[2] != pctrl->data->n_port_pins) {
+ dev_err(pctrl->dev, "gpio-ranges does not match selected SOC\n");
+ return -EINVAL;
+ }
+
+ chip->names = pctrl->data->port_pins;
+ chip->request = rzv2m_gpio_request;
+ chip->free = rzv2m_gpio_free;
+ chip->get_direction = rzv2m_gpio_get_direction;
+ chip->direction_input = rzv2m_gpio_direction_input;
+ chip->direction_output = rzv2m_gpio_direction_output;
+ chip->get = rzv2m_gpio_get;
+ chip->set = rzv2m_gpio_set;
+ chip->label = name;
+ chip->parent = pctrl->dev;
+ chip->owner = THIS_MODULE;
+ chip->base = -1;
+ chip->ngpio = of_args.args[2];
+
+ pctrl->gpio_range.id = 0;
+ pctrl->gpio_range.pin_base = 0;
+ pctrl->gpio_range.base = 0;
+ pctrl->gpio_range.npins = chip->ngpio;
+ pctrl->gpio_range.name = chip->label;
+ pctrl->gpio_range.gc = chip;
+ ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl);
+ if (ret) {
+ dev_err(pctrl->dev, "failed to add GPIO controller\n");
+ return ret;
+ }
+
+ dev_dbg(pctrl->dev, "Registered gpio controller\n");
+
+ return 0;
+}
+
+static int rzv2m_pinctrl_register(struct rzv2m_pinctrl *pctrl)
+{
+ struct pinctrl_pin_desc *pins;
+ unsigned int i, j;
+ u32 *pin_data;
+ int ret;
+
+ pctrl->desc.name = DRV_NAME;
+ pctrl->desc.npins = pctrl->data->n_port_pins + pctrl->data->n_dedicated_pins;
+ pctrl->desc.pctlops = &rzv2m_pinctrl_pctlops;
+ pctrl->desc.pmxops = &rzv2m_pinctrl_pmxops;
+ pctrl->desc.confops = &rzv2m_pinctrl_confops;
+ pctrl->desc.owner = THIS_MODULE;
+
+ pins = devm_kcalloc(pctrl->dev, pctrl->desc.npins, sizeof(*pins), GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ pin_data = devm_kcalloc(pctrl->dev, pctrl->desc.npins,
+ sizeof(*pin_data), GFP_KERNEL);
+ if (!pin_data)
+ return -ENOMEM;
+
+ pctrl->pins = pins;
+ pctrl->desc.pins = pins;
+
+ for (i = 0, j = 0; i < pctrl->data->n_port_pins; i++) {
+ pins[i].number = i;
+ pins[i].name = pctrl->data->port_pins[i];
+ if (i && !(i % RZV2M_PINS_PER_PORT))
+ j++;
+ pin_data[i] = pctrl->data->port_pin_configs[j];
+ pins[i].drv_data = &pin_data[i];
+ }
+
+ for (i = 0; i < pctrl->data->n_dedicated_pins; i++) {
+ unsigned int index = pctrl->data->n_port_pins + i;
+
+ pins[index].number = index;
+ pins[index].name = pctrl->data->dedicated_pins[i].name;
+ pin_data[index] = pctrl->data->dedicated_pins[i].config;
+ pins[index].drv_data = &pin_data[index];
+ }
+
+ ret = devm_pinctrl_register_and_init(pctrl->dev, &pctrl->desc, pctrl,
+ &pctrl->pctl);
+ if (ret) {
+ dev_err(pctrl->dev, "pinctrl registration failed\n");
+ return ret;
+ }
+
+ ret = pinctrl_enable(pctrl->pctl);
+ if (ret) {
+ dev_err(pctrl->dev, "pinctrl enable failed\n");
+ return ret;
+ }
+
+ ret = rzv2m_gpio_register(pctrl);
+ if (ret) {
+ dev_err(pctrl->dev, "failed to add GPIO chip: %i\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void rzv2m_pinctrl_clk_disable(void *data)
+{
+ clk_disable_unprepare(data);
+}
+
+static int rzv2m_pinctrl_probe(struct platform_device *pdev)
+{
+ struct rzv2m_pinctrl *pctrl;
+ int ret;
+
+ pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
+ if (!pctrl)
+ return -ENOMEM;
+
+ pctrl->dev = &pdev->dev;
+
+ pctrl->data = of_device_get_match_data(&pdev->dev);
+ if (!pctrl->data)
+ return -EINVAL;
+
+ pctrl->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(pctrl->base))
+ return PTR_ERR(pctrl->base);
+
+ pctrl->clk = devm_clk_get(pctrl->dev, NULL);
+ if (IS_ERR(pctrl->clk)) {
+ ret = PTR_ERR(pctrl->clk);
+ dev_err(pctrl->dev, "failed to get GPIO clk : %i\n", ret);
+ return ret;
+ }
+
+ spin_lock_init(&pctrl->lock);
+
+ platform_set_drvdata(pdev, pctrl);
+
+ ret = clk_prepare_enable(pctrl->clk);
+ if (ret) {
+ dev_err(pctrl->dev, "failed to enable GPIO clk: %i\n", ret);
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(&pdev->dev, rzv2m_pinctrl_clk_disable,
+ pctrl->clk);
+ if (ret) {
+ dev_err(pctrl->dev,
+ "failed to register GPIO clk disable action, %i\n",
+ ret);
+ return ret;
+ }
+
+ ret = rzv2m_pinctrl_register(pctrl);
+ if (ret)
+ return ret;
+
+ dev_info(pctrl->dev, "%s support registered\n", DRV_NAME);
+ return 0;
+}
+
+static struct rzv2m_pinctrl_data r9a09g011_data = {
+ .port_pins = rzv2m_gpio_names,
+ .port_pin_configs = rzv2m_gpio_configs,
+ .dedicated_pins = rzv2m_dedicated_pins,
+ .n_port_pins = ARRAY_SIZE(rzv2m_gpio_configs) * RZV2M_PINS_PER_PORT,
+ .n_dedicated_pins = ARRAY_SIZE(rzv2m_dedicated_pins),
+};
+
+static const struct of_device_id rzv2m_pinctrl_of_table[] = {
+ {
+ .compatible = "renesas,r9a09g011-pinctrl",
+ .data = &r9a09g011_data,
+ },
+ { /* sentinel */ }
+};
+
+static struct platform_driver rzv2m_pinctrl_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = of_match_ptr(rzv2m_pinctrl_of_table),
+ },
+ .probe = rzv2m_pinctrl_probe,
+};
+
+static int __init rzv2m_pinctrl_init(void)
+{
+ return platform_driver_register(&rzv2m_pinctrl_driver);
+}
+core_initcall(rzv2m_pinctrl_init);
+
+MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
+MODULE_DESCRIPTION("Pin and gpio controller driver for RZ/V2M");
+MODULE_LICENSE("GPL");
extern const struct sh_pfc_soc_info r8a77995_pinmux_info;
extern const struct sh_pfc_soc_info r8a779a0_pinmux_info;
extern const struct sh_pfc_soc_info r8a779f0_pinmux_info;
+extern const struct sh_pfc_soc_info r8a779g0_pinmux_info;
extern const struct sh_pfc_soc_info sh7203_pinmux_info;
extern const struct sh_pfc_soc_info sh7264_pinmux_info;
extern const struct sh_pfc_soc_info sh7269_pinmux_info;
PORT_GP_CFG_1(bank, 11, fn, sfx, cfg)
#define PORT_GP_12(bank, fn, sfx) PORT_GP_CFG_12(bank, fn, sfx, 0)
-#define PORT_GP_CFG_14(bank, fn, sfx, cfg) \
+#define PORT_GP_CFG_13(bank, fn, sfx, cfg) \
PORT_GP_CFG_12(bank, fn, sfx, cfg), \
- PORT_GP_CFG_1(bank, 12, fn, sfx, cfg), \
+ PORT_GP_CFG_1(bank, 12, fn, sfx, cfg)
+#define PORT_GP_13(bank, fn, sfx) PORT_GP_CFG_13(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_14(bank, fn, sfx, cfg) \
+ PORT_GP_CFG_13(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 13, fn, sfx, cfg)
#define PORT_GP_14(bank, fn, sfx) PORT_GP_CFG_14(bank, fn, sfx, 0)
#include <linux/soc/samsung/exynos-pmu.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
-#include <dt-bindings/pinctrl/samsung.h>
-
#include "pinctrl-samsung.h"
#include "pinctrl-exynos.h"
con = readl(bank->pctl_base + reg_con);
con &= ~(mask << shift);
- con |= EXYNOS_PIN_FUNC_EINT << shift;
+ con |= EXYNOS_PIN_CON_FUNC_EINT << shift;
writel(con, bank->pctl_base + reg_con);
raw_spin_unlock_irqrestore(&bank->slock, flags);
con = readl(bank->pctl_base + reg_con);
con &= ~(mask << shift);
- con |= EXYNOS_PIN_FUNC_INPUT << shift;
+ con |= PIN_CON_FUNC_INPUT << shift;
writel(con, bank->pctl_base + reg_con);
raw_spin_unlock_irqrestore(&bank->slock, flags);
#ifndef __PINCTRL_SAMSUNG_EXYNOS_H
#define __PINCTRL_SAMSUNG_EXYNOS_H
+/* Values for the pin CON register */
+#define EXYNOS_PIN_CON_FUNC_EINT 0xf
+
/* External GPIO and wakeup interrupt related definitions */
#define EXYNOS_GPIO_ECON_OFFSET 0x700
#define EXYNOS_GPIO_EFLTCON_OFFSET 0x800
#include <linux/of_device.h>
#include <linux/spinlock.h>
-#include <dt-bindings/pinctrl/samsung.h>
-
#include "../core.h"
#include "pinctrl-samsung.h"
data = readl(reg);
data &= ~(mask << shift);
if (!input)
- data |= EXYNOS_PIN_FUNC_OUTPUT << shift;
+ data |= PIN_CON_FUNC_OUTPUT << shift;
writel(data, reg);
return 0;
#define PINCFG_UNPACK_TYPE(cfg) ((cfg) & PINCFG_TYPE_MASK)
#define PINCFG_UNPACK_VALUE(cfg) (((cfg) & PINCFG_VALUE_MASK) >> \
PINCFG_VALUE_SHIFT)
+/*
+ * Values for the pin CON register, choosing pin function.
+ * The basic set (input and output) are same between: S3C24xx, S3C64xx, S5PV210,
+ * Exynos ARMv7, Exynos ARMv8, Tesla FSD.
+ */
+#define PIN_CON_FUNC_INPUT 0x0
+#define PIN_CON_FUNC_OUTPUT 0x1
+
/**
* enum eint_type - possible external interrupt types.
* @EINT_TYPE_NONE: bank does not support external interrupts
config PINCTRL_SUN6I_A31_R
bool "Support for the Allwinner A31 R-PIO"
default MACH_SUN6I
- depends on RESET_CONTROLLER
select PINCTRL_SUNXI
config PINCTRL_SUN8I_A23
config PINCTRL_SUN8I_A23_R
bool "Support for the Allwinner A23 and A33 R-PIO"
default MACH_SUN8I
- depends on RESET_CONTROLLER
select PINCTRL_SUNXI
config PINCTRL_SUN8I_H3
config PINCTRL_SUN9I_A80_R
bool "Support for the Allwinner A80 R-PIO"
default MACH_SUN9I
- depends on RESET_CONTROLLER
+ select PINCTRL_SUNXI
+
+config PINCTRL_SUN20I_D1
+ bool "Support for the Allwinner D1 PIO"
+ default MACH_SUN8I || (RISCV && ARCH_SUNXI)
select PINCTRL_SUNXI
config PINCTRL_SUN50I_A64
obj-$(CONFIG_PINCTRL_SUN8I_H3) += pinctrl-sun8i-h3.o
obj-$(CONFIG_PINCTRL_SUN8I_H3_R) += pinctrl-sun8i-h3-r.o
obj-$(CONFIG_PINCTRL_SUN8I_V3S) += pinctrl-sun8i-v3s.o
+obj-$(CONFIG_PINCTRL_SUN20I_D1) += pinctrl-sun20i-d1.o
obj-$(CONFIG_PINCTRL_SUN50I_H5) += pinctrl-sun50i-h5.o
obj-$(CONFIG_PINCTRL_SUN50I_H6) += pinctrl-sun50i-h6.o
obj-$(CONFIG_PINCTRL_SUN50I_H6_R) += pinctrl-sun50i-h6-r.o
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Allwinner D1 SoC pinctrl driver.
+ *
+ * Copyright (c) 2020 wuyan@allwinnertech.com
+ * Copyright (c) 2021-2022 Samuel Holland <samuel@sholland.org>
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin d1_pins[] = {
+ /* PB */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "pwm3"),
+ SUNXI_FUNCTION(0x3, "ir"), /* TX */
+ SUNXI_FUNCTION(0x4, "i2c2"), /* SCK */
+ SUNXI_FUNCTION(0x5, "spi1"), /* WP */
+ SUNXI_FUNCTION(0x6, "uart0"), /* TX */
+ SUNXI_FUNCTION(0x7, "uart2"), /* TX */
+ SUNXI_FUNCTION(0x8, "spdif"), /* OUT */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 0)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "pwm4"),
+ SUNXI_FUNCTION(0x3, "i2s2_dout"), /* DOUT3 */
+ SUNXI_FUNCTION(0x4, "i2c2"), /* SDA */
+ SUNXI_FUNCTION(0x5, "i2s2_din"), /* DIN3 */
+ SUNXI_FUNCTION(0x6, "uart0"), /* RX */
+ SUNXI_FUNCTION(0x7, "uart2"), /* RX */
+ SUNXI_FUNCTION(0x8, "ir"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 1)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D0 */
+ SUNXI_FUNCTION(0x3, "i2s2_dout"), /* DOUT2 */
+ SUNXI_FUNCTION(0x4, "i2c0"), /* SDA */
+ SUNXI_FUNCTION(0x5, "i2s2_din"), /* DIN2 */
+ SUNXI_FUNCTION(0x6, "lcd0"), /* D18 */
+ SUNXI_FUNCTION(0x7, "uart4"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 2)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D1 */
+ SUNXI_FUNCTION(0x3, "i2s2_dout"), /* DOUT1 */
+ SUNXI_FUNCTION(0x4, "i2c0"), /* SCK */
+ SUNXI_FUNCTION(0x5, "i2s2_din"), /* DIN0 */
+ SUNXI_FUNCTION(0x6, "lcd0"), /* D19 */
+ SUNXI_FUNCTION(0x7, "uart4"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 3)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D8 */
+ SUNXI_FUNCTION(0x3, "i2s2_dout"), /* DOUT0 */
+ SUNXI_FUNCTION(0x4, "i2c1"), /* SCK */
+ SUNXI_FUNCTION(0x5, "i2s2_din"), /* DIN1 */
+ SUNXI_FUNCTION(0x6, "lcd0"), /* D20 */
+ SUNXI_FUNCTION(0x7, "uart5"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 4)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D9 */
+ SUNXI_FUNCTION(0x3, "i2s2"), /* BCLK */
+ SUNXI_FUNCTION(0x4, "i2c1"), /* SDA */
+ SUNXI_FUNCTION(0x5, "pwm0"),
+ SUNXI_FUNCTION(0x6, "lcd0"), /* D21 */
+ SUNXI_FUNCTION(0x7, "uart5"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 5)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D16 */
+ SUNXI_FUNCTION(0x3, "i2s2"), /* LRCK */
+ SUNXI_FUNCTION(0x4, "i2c3"), /* SCK */
+ SUNXI_FUNCTION(0x5, "pwm1"),
+ SUNXI_FUNCTION(0x6, "lcd0"), /* D22 */
+ SUNXI_FUNCTION(0x7, "uart3"), /* TX */
+ SUNXI_FUNCTION(0x8, "bist0"), /* BIST_RESULT0 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 6)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D17 */
+ SUNXI_FUNCTION(0x3, "i2s2"), /* MCLK */
+ SUNXI_FUNCTION(0x4, "i2c3"), /* SDA */
+ SUNXI_FUNCTION(0x5, "ir"), /* RX */
+ SUNXI_FUNCTION(0x6, "lcd0"), /* D23 */
+ SUNXI_FUNCTION(0x7, "uart3"), /* RX */
+ SUNXI_FUNCTION(0x8, "bist1"), /* BIST_RESULT1 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 7)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "dmic"), /* DATA3 */
+ SUNXI_FUNCTION(0x3, "pwm5"),
+ SUNXI_FUNCTION(0x4, "i2c2"), /* SCK */
+ SUNXI_FUNCTION(0x5, "spi1"), /* HOLD */
+ SUNXI_FUNCTION(0x6, "uart0"), /* TX */
+ SUNXI_FUNCTION(0x7, "uart1"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 8)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "dmic"), /* DATA2 */
+ SUNXI_FUNCTION(0x3, "pwm6"),
+ SUNXI_FUNCTION(0x4, "i2c2"), /* SDA */
+ SUNXI_FUNCTION(0x5, "spi1"), /* MISO */
+ SUNXI_FUNCTION(0x6, "uart0"), /* RX */
+ SUNXI_FUNCTION(0x7, "uart1"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 9)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "dmic"), /* DATA1 */
+ SUNXI_FUNCTION(0x3, "pwm7"),
+ SUNXI_FUNCTION(0x4, "i2c0"), /* SCK */
+ SUNXI_FUNCTION(0x5, "spi1"), /* MOSI */
+ SUNXI_FUNCTION(0x6, "clk"), /* FANOUT0 */
+ SUNXI_FUNCTION(0x7, "uart1"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 10)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "dmic"), /* DATA0 */
+ SUNXI_FUNCTION(0x3, "pwm2"),
+ SUNXI_FUNCTION(0x4, "i2c0"), /* SDA */
+ SUNXI_FUNCTION(0x5, "spi1"), /* CLK */
+ SUNXI_FUNCTION(0x6, "clk"), /* FANOUT1 */
+ SUNXI_FUNCTION(0x7, "uart1"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 11)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "dmic"), /* CLK */
+ SUNXI_FUNCTION(0x3, "pwm0"),
+ SUNXI_FUNCTION(0x4, "spdif"), /* IN */
+ SUNXI_FUNCTION(0x5, "spi1"), /* CS0 */
+ SUNXI_FUNCTION(0x6, "clk"), /* FANOUT2 */
+ SUNXI_FUNCTION(0x7, "ir"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 0, 12)),
+ /* PC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* TX */
+ SUNXI_FUNCTION(0x3, "i2c2"), /* SCK */
+ SUNXI_FUNCTION(0x4, "ledc"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 0)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RX */
+ SUNXI_FUNCTION(0x3, "i2c2"), /* SDA */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 1)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "mmc2"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 2)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* CS0 */
+ SUNXI_FUNCTION(0x3, "mmc2"), /* CMD */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 3)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* MOSI */
+ SUNXI_FUNCTION(0x3, "mmc2"), /* D2 */
+ SUNXI_FUNCTION(0x4, "boot"), /* SEL0 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 4)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* MISO */
+ SUNXI_FUNCTION(0x3, "mmc2"), /* D1 */
+ SUNXI_FUNCTION(0x4, "boot"), /* SEL1 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 5)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* WP */
+ SUNXI_FUNCTION(0x3, "mmc2"), /* D0 */
+ SUNXI_FUNCTION(0x4, "uart3"), /* TX */
+ SUNXI_FUNCTION(0x5, "i2c3"), /* SCK */
+ SUNXI_FUNCTION(0x6, "pll"), /* DBG-CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 6)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* HOLD */
+ SUNXI_FUNCTION(0x3, "mmc2"), /* D3 */
+ SUNXI_FUNCTION(0x4, "uart3"), /* RX */
+ SUNXI_FUNCTION(0x5, "i2c3"), /* SDA */
+ SUNXI_FUNCTION(0x6, "tcon"), /* TRIG0 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 1, 7)),
+ /* PD */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* V0P */
+ SUNXI_FUNCTION(0x4, "dsi"), /* D0P */
+ SUNXI_FUNCTION(0x5, "i2c0"), /* SCK */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 0)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* V0N */
+ SUNXI_FUNCTION(0x4, "dsi"), /* D0N */
+ SUNXI_FUNCTION(0x5, "uart2"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 1)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* V1P */
+ SUNXI_FUNCTION(0x4, "dsi"), /* D1P */
+ SUNXI_FUNCTION(0x5, "uart2"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 2)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* V1N */
+ SUNXI_FUNCTION(0x4, "dsi"), /* D1N */
+ SUNXI_FUNCTION(0x5, "uart2"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 3)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* V2P */
+ SUNXI_FUNCTION(0x4, "dsi"), /* CKP */
+ SUNXI_FUNCTION(0x5, "uart2"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 4)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* V2N */
+ SUNXI_FUNCTION(0x4, "dsi"), /* CKN */
+ SUNXI_FUNCTION(0x5, "uart5"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 5)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* CKP */
+ SUNXI_FUNCTION(0x4, "dsi"), /* D2P */
+ SUNXI_FUNCTION(0x5, "uart5"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 6)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* CKN */
+ SUNXI_FUNCTION(0x4, "dsi"), /* D2N */
+ SUNXI_FUNCTION(0x5, "uart4"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 7)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* V3P */
+ SUNXI_FUNCTION(0x4, "dsi"), /* D3P */
+ SUNXI_FUNCTION(0x5, "uart4"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 8)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */
+ SUNXI_FUNCTION(0x3, "lvds0"), /* V3N */
+ SUNXI_FUNCTION(0x4, "dsi"), /* D3N */
+ SUNXI_FUNCTION(0x5, "pwm6"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 9)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D14 */
+ SUNXI_FUNCTION(0x3, "lvds1"), /* V0P */
+ SUNXI_FUNCTION(0x4, "spi1"), /* CS0 */
+ SUNXI_FUNCTION(0x5, "uart3"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 10)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D15 */
+ SUNXI_FUNCTION(0x3, "lvds1"), /* V0N */
+ SUNXI_FUNCTION(0x4, "spi1"), /* CLK */
+ SUNXI_FUNCTION(0x5, "uart3"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 11)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */
+ SUNXI_FUNCTION(0x3, "lvds1"), /* V1P */
+ SUNXI_FUNCTION(0x4, "spi1"), /* MOSI */
+ SUNXI_FUNCTION(0x5, "i2c0"), /* SDA */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 12)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */
+ SUNXI_FUNCTION(0x3, "lvds1"), /* V1N */
+ SUNXI_FUNCTION(0x4, "spi1"), /* MISO */
+ SUNXI_FUNCTION(0x5, "uart3"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 13)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D20 */
+ SUNXI_FUNCTION(0x3, "lvds1"), /* V2P */
+ SUNXI_FUNCTION(0x4, "spi1"), /* HOLD */
+ SUNXI_FUNCTION(0x5, "uart3"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 14)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D21 */
+ SUNXI_FUNCTION(0x3, "lvds1"), /* V2N */
+ SUNXI_FUNCTION(0x4, "spi1"), /* WP */
+ SUNXI_FUNCTION(0x5, "ir"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 15)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D22 */
+ SUNXI_FUNCTION(0x3, "lvds1"), /* CKP */
+ SUNXI_FUNCTION(0x4, "dmic"), /* DATA3 */
+ SUNXI_FUNCTION(0x5, "pwm0"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 16)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D23 */
+ SUNXI_FUNCTION(0x3, "lvds1"), /* CKN */
+ SUNXI_FUNCTION(0x4, "dmic"), /* DATA2 */
+ SUNXI_FUNCTION(0x5, "pwm1"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 17)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "lvds1"), /* V3P */
+ SUNXI_FUNCTION(0x4, "dmic"), /* DATA1 */
+ SUNXI_FUNCTION(0x5, "pwm2"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 18)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* DE */
+ SUNXI_FUNCTION(0x3, "lvds1"), /* V3N */
+ SUNXI_FUNCTION(0x4, "dmic"), /* DATA0 */
+ SUNXI_FUNCTION(0x5, "pwm3"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 19)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* HSYNC */
+ SUNXI_FUNCTION(0x3, "i2c2"), /* SCK */
+ SUNXI_FUNCTION(0x4, "dmic"), /* CLK */
+ SUNXI_FUNCTION(0x5, "pwm4"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 20)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* VSYNC */
+ SUNXI_FUNCTION(0x3, "i2c2"), /* SDA */
+ SUNXI_FUNCTION(0x4, "uart1"), /* TX */
+ SUNXI_FUNCTION(0x5, "pwm5"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 21)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spdif"), /* OUT */
+ SUNXI_FUNCTION(0x3, "ir"), /* RX */
+ SUNXI_FUNCTION(0x4, "uart1"), /* RX */
+ SUNXI_FUNCTION(0x5, "pwm7"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 2, 22)),
+ /* PE */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ncsi0"), /* HSYNC */
+ SUNXI_FUNCTION(0x3, "uart2"), /* RTS */
+ SUNXI_FUNCTION(0x4, "i2c1"), /* SCK */
+ SUNXI_FUNCTION(0x5, "lcd0"), /* HSYNC */
+ SUNXI_FUNCTION(0x8, "emac"), /* RXCTL/CRS_DV */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 0)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ncsi0"), /* VSYNC */
+ SUNXI_FUNCTION(0x3, "uart2"), /* CTS */
+ SUNXI_FUNCTION(0x4, "i2c1"), /* SDA */
+ SUNXI_FUNCTION(0x5, "lcd0"), /* VSYNC */
+ SUNXI_FUNCTION(0x8, "emac"), /* RXD0 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 1)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ncsi0"), /* PCLK */
+ SUNXI_FUNCTION(0x3, "uart2"), /* TX */
+ SUNXI_FUNCTION(0x4, "i2c0"), /* SCK */
+ SUNXI_FUNCTION(0x5, "clk"), /* FANOUT0 */
+ SUNXI_FUNCTION(0x6, "uart0"), /* TX */
+ SUNXI_FUNCTION(0x8, "emac"), /* RXD1 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 2)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ncsi0"), /* MCLK */
+ SUNXI_FUNCTION(0x3, "uart2"), /* RX */
+ SUNXI_FUNCTION(0x4, "i2c0"), /* SDA */
+ SUNXI_FUNCTION(0x5, "clk"), /* FANOUT1 */
+ SUNXI_FUNCTION(0x6, "uart0"), /* RX */
+ SUNXI_FUNCTION(0x8, "emac"), /* TXCK */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 3)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ncsi0"), /* D0 */
+ SUNXI_FUNCTION(0x3, "uart4"), /* TX */
+ SUNXI_FUNCTION(0x4, "i2c2"), /* SCK */
+ SUNXI_FUNCTION(0x5, "clk"), /* FANOUT2 */
+ SUNXI_FUNCTION(0x6, "d_jtag"), /* MS */
+ SUNXI_FUNCTION(0x7, "r_jtag"), /* MS */
+ SUNXI_FUNCTION(0x8, "emac"), /* TXD0 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 4)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ncsi0"), /* D1 */
+ SUNXI_FUNCTION(0x3, "uart4"), /* RX */
+ SUNXI_FUNCTION(0x4, "i2c2"), /* SDA */
+ SUNXI_FUNCTION(0x5, "ledc"),
+ SUNXI_FUNCTION(0x6, "d_jtag"), /* DI */
+ SUNXI_FUNCTION(0x7, "r_jtag"), /* DI */
+ SUNXI_FUNCTION(0x8, "emac"), /* TXD1 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 5)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ncsi0"), /* D2 */
+ SUNXI_FUNCTION(0x3, "uart5"), /* TX */
+ SUNXI_FUNCTION(0x4, "i2c3"), /* SCK */
+ SUNXI_FUNCTION(0x5, "spdif"), /* IN */
+ SUNXI_FUNCTION(0x6, "d_jtag"), /* DO */
+ SUNXI_FUNCTION(0x7, "r_jtag"), /* DO */
+ SUNXI_FUNCTION(0x8, "emac"), /* TXCTL/TXEN */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 6)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ncsi0"), /* D3 */
+ SUNXI_FUNCTION(0x3, "uart5"), /* RX */
+ SUNXI_FUNCTION(0x4, "i2c3"), /* SDA */
+ SUNXI_FUNCTION(0x5, "spdif"), /* OUT */
+ SUNXI_FUNCTION(0x6, "d_jtag"), /* CK */
+ SUNXI_FUNCTION(0x7, "r_jtag"), /* CK */
+ SUNXI_FUNCTION(0x8, "emac"), /* CK */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 7)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ncsi0"), /* D4 */
+ SUNXI_FUNCTION(0x3, "uart1"), /* RTS */
+ SUNXI_FUNCTION(0x4, "pwm2"),
+ SUNXI_FUNCTION(0x5, "uart3"), /* TX */
+ SUNXI_FUNCTION(0x6, "jtag"), /* MS */
+ SUNXI_FUNCTION(0x8, "emac"), /* MDC */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 8)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ncsi0"), /* D5 */
+ SUNXI_FUNCTION(0x3, "uart1"), /* CTS */
+ SUNXI_FUNCTION(0x4, "pwm3"),
+ SUNXI_FUNCTION(0x5, "uart3"), /* RX */
+ SUNXI_FUNCTION(0x6, "jtag"), /* DI */
+ SUNXI_FUNCTION(0x8, "emac"), /* MDIO */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 9)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ncsi0"), /* D6 */
+ SUNXI_FUNCTION(0x3, "uart1"), /* TX */
+ SUNXI_FUNCTION(0x4, "pwm4"),
+ SUNXI_FUNCTION(0x5, "ir"), /* RX */
+ SUNXI_FUNCTION(0x6, "jtag"), /* DO */
+ SUNXI_FUNCTION(0x8, "emac"), /* EPHY-25M */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 10)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ncsi0"), /* D7 */
+ SUNXI_FUNCTION(0x3, "uart1"), /* RX */
+ SUNXI_FUNCTION(0x4, "i2s0_dout"), /* DOUT3 */
+ SUNXI_FUNCTION(0x5, "i2s0_din"), /* DIN3 */
+ SUNXI_FUNCTION(0x6, "jtag"), /* CK */
+ SUNXI_FUNCTION(0x8, "emac"), /* TXD2 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 11)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c2"), /* SCK */
+ SUNXI_FUNCTION(0x3, "ncsi0"), /* FIELD */
+ SUNXI_FUNCTION(0x4, "i2s0_dout"), /* DOUT2 */
+ SUNXI_FUNCTION(0x5, "i2s0_din"), /* DIN2 */
+ SUNXI_FUNCTION(0x8, "emac"), /* TXD3 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 12)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c2"), /* SDA */
+ SUNXI_FUNCTION(0x3, "pwm5"),
+ SUNXI_FUNCTION(0x4, "i2s0_dout"), /* DOUT0 */
+ SUNXI_FUNCTION(0x5, "i2s0_din"), /* DIN1 */
+ SUNXI_FUNCTION(0x6, "dmic"), /* DATA3 */
+ SUNXI_FUNCTION(0x8, "emac"), /* RXD2 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 13)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1"), /* SCK */
+ SUNXI_FUNCTION(0x3, "d_jtag"), /* MS */
+ SUNXI_FUNCTION(0x4, "i2s0_dout"), /* DOUT1 */
+ SUNXI_FUNCTION(0x5, "i2s0_din"), /* DIN0 */
+ SUNXI_FUNCTION(0x6, "dmic"), /* DATA2 */
+ SUNXI_FUNCTION(0x8, "emac"), /* RXD3 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 14)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1"), /* SDA */
+ SUNXI_FUNCTION(0x3, "d_jtag"), /* DI */
+ SUNXI_FUNCTION(0x4, "pwm6"),
+ SUNXI_FUNCTION(0x5, "i2s0"), /* LRCK */
+ SUNXI_FUNCTION(0x6, "dmic"), /* DATA1 */
+ SUNXI_FUNCTION(0x8, "emac"), /* RXCK */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 15)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c3"), /* SCK */
+ SUNXI_FUNCTION(0x3, "d_jtag"), /* DO */
+ SUNXI_FUNCTION(0x4, "pwm7"),
+ SUNXI_FUNCTION(0x5, "i2s0"), /* BCLK */
+ SUNXI_FUNCTION(0x6, "dmic"), /* DATA0 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 16)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c3"), /* SDA */
+ SUNXI_FUNCTION(0x3, "d_jtag"), /* CK */
+ SUNXI_FUNCTION(0x4, "ir"), /* TX */
+ SUNXI_FUNCTION(0x5, "i2s0"), /* MCLK */
+ SUNXI_FUNCTION(0x6, "dmic"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 3, 17)),
+ /* PF */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */
+ SUNXI_FUNCTION(0x3, "jtag"), /* MS */
+ SUNXI_FUNCTION(0x4, "r_jtag"), /* MS */
+ SUNXI_FUNCTION(0x5, "i2s2_dout"), /* DOUT1 */
+ SUNXI_FUNCTION(0x6, "i2s2_din"), /* DIN0 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 0)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */
+ SUNXI_FUNCTION(0x3, "jtag"), /* DI */
+ SUNXI_FUNCTION(0x4, "r_jtag"), /* DI */
+ SUNXI_FUNCTION(0x5, "i2s2_dout"), /* DOUT0 */
+ SUNXI_FUNCTION(0x6, "i2s2_din"), /* DIN1 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 1)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "uart0"), /* TX */
+ SUNXI_FUNCTION(0x4, "i2c0"), /* SCK */
+ SUNXI_FUNCTION(0x5, "ledc"),
+ SUNXI_FUNCTION(0x6, "spdif"), /* IN */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 2)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */
+ SUNXI_FUNCTION(0x3, "jtag"), /* DO */
+ SUNXI_FUNCTION(0x4, "r_jtag"), /* DO */
+ SUNXI_FUNCTION(0x5, "i2s2"), /* BCLK */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 3)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */
+ SUNXI_FUNCTION(0x3, "uart0"), /* RX */
+ SUNXI_FUNCTION(0x4, "i2c0"), /* SDA */
+ SUNXI_FUNCTION(0x5, "pwm6"),
+ SUNXI_FUNCTION(0x6, "ir"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 4)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */
+ SUNXI_FUNCTION(0x3, "jtag"), /* CK */
+ SUNXI_FUNCTION(0x4, "r_jtag"), /* CK */
+ SUNXI_FUNCTION(0x5, "i2s2"), /* LRCK */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 5)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "spdif"), /* OUT */
+ SUNXI_FUNCTION(0x4, "ir"), /* RX */
+ SUNXI_FUNCTION(0x5, "i2s2"), /* MCLK */
+ SUNXI_FUNCTION(0x6, "pwm5"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 4, 6)),
+ /* PG */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */
+ SUNXI_FUNCTION(0x3, "uart3"), /* TX */
+ SUNXI_FUNCTION(0x4, "emac"), /* RXCTRL/CRS_DV */
+ SUNXI_FUNCTION(0x5, "pwm7"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 0)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */
+ SUNXI_FUNCTION(0x3, "uart3"), /* RX */
+ SUNXI_FUNCTION(0x4, "emac"), /* RXD0 */
+ SUNXI_FUNCTION(0x5, "pwm6"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 1)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D0 */
+ SUNXI_FUNCTION(0x3, "uart3"), /* RTS */
+ SUNXI_FUNCTION(0x4, "emac"), /* RXD1 */
+ SUNXI_FUNCTION(0x5, "uart4"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 2)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */
+ SUNXI_FUNCTION(0x3, "uart3"), /* CTS */
+ SUNXI_FUNCTION(0x4, "emac"), /* TXCK */
+ SUNXI_FUNCTION(0x5, "uart4"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 3)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */
+ SUNXI_FUNCTION(0x3, "uart5"), /* TX */
+ SUNXI_FUNCTION(0x4, "emac"), /* TXD0 */
+ SUNXI_FUNCTION(0x5, "pwm5"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 4)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */
+ SUNXI_FUNCTION(0x3, "uart5"), /* RX */
+ SUNXI_FUNCTION(0x4, "emac"), /* TXD1 */
+ SUNXI_FUNCTION(0x5, "pwm4"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 5)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* TX */
+ SUNXI_FUNCTION(0x3, "i2c2"), /* SCK */
+ SUNXI_FUNCTION(0x4, "emac"), /* TXD2 */
+ SUNXI_FUNCTION(0x5, "pwm1"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 6)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* RX */
+ SUNXI_FUNCTION(0x3, "i2c2"), /* SDA */
+ SUNXI_FUNCTION(0x4, "emac"), /* TXD3 */
+ SUNXI_FUNCTION(0x5, "spdif"), /* IN */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 7)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* RTS */
+ SUNXI_FUNCTION(0x3, "i2c1"), /* SCK */
+ SUNXI_FUNCTION(0x4, "emac"), /* RXD2 */
+ SUNXI_FUNCTION(0x5, "uart3"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 8)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* CTS */
+ SUNXI_FUNCTION(0x3, "i2c1"), /* SDA */
+ SUNXI_FUNCTION(0x4, "emac"), /* RXD3 */
+ SUNXI_FUNCTION(0x5, "uart3"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 9)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "pwm3"),
+ SUNXI_FUNCTION(0x3, "i2c3"), /* SCK */
+ SUNXI_FUNCTION(0x4, "emac"), /* RXCK */
+ SUNXI_FUNCTION(0x5, "clk"), /* FANOUT0 */
+ SUNXI_FUNCTION(0x6, "ir"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 10)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* MCLK */
+ SUNXI_FUNCTION(0x3, "i2c3"), /* SDA */
+ SUNXI_FUNCTION(0x4, "emac"), /* EPHY-25M */
+ SUNXI_FUNCTION(0x5, "clk"), /* FANOUT1 */
+ SUNXI_FUNCTION(0x6, "tcon"), /* TRIG0 */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 11)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* LRCK */
+ SUNXI_FUNCTION(0x3, "i2c0"), /* SCK */
+ SUNXI_FUNCTION(0x4, "emac"), /* TXCTL/TXEN */
+ SUNXI_FUNCTION(0x5, "clk"), /* FANOUT2 */
+ SUNXI_FUNCTION(0x6, "pwm0"),
+ SUNXI_FUNCTION(0x7, "uart1"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 12)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* BCLK */
+ SUNXI_FUNCTION(0x3, "i2c0"), /* SDA */
+ SUNXI_FUNCTION(0x4, "emac"), /* CLKIN/RXER */
+ SUNXI_FUNCTION(0x5, "pwm2"),
+ SUNXI_FUNCTION(0x6, "ledc"),
+ SUNXI_FUNCTION(0x7, "uart1"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 13)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1_din"), /* DIN0 */
+ SUNXI_FUNCTION(0x3, "i2c2"), /* SCK */
+ SUNXI_FUNCTION(0x4, "emac"), /* MDC */
+ SUNXI_FUNCTION(0x5, "i2s1_dout"), /* DOUT1 */
+ SUNXI_FUNCTION(0x6, "spi0"), /* WP */
+ SUNXI_FUNCTION(0x7, "uart1"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 14)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1_dout"), /* DOUT0 */
+ SUNXI_FUNCTION(0x3, "i2c2"), /* SDA */
+ SUNXI_FUNCTION(0x4, "emac"), /* MDIO */
+ SUNXI_FUNCTION(0x5, "i2s1_din"), /* DIN1 */
+ SUNXI_FUNCTION(0x6, "spi0"), /* HOLD */
+ SUNXI_FUNCTION(0x7, "uart1"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 15)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ir"), /* RX */
+ SUNXI_FUNCTION(0x3, "tcon"), /* TRIG0 */
+ SUNXI_FUNCTION(0x4, "pwm5"),
+ SUNXI_FUNCTION(0x5, "clk"), /* FANOUT2 */
+ SUNXI_FUNCTION(0x6, "spdif"), /* IN */
+ SUNXI_FUNCTION(0x7, "ledc"),
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 16)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* TX */
+ SUNXI_FUNCTION(0x3, "i2c3"), /* SCK */
+ SUNXI_FUNCTION(0x4, "pwm7"),
+ SUNXI_FUNCTION(0x5, "clk"), /* FANOUT0 */
+ SUNXI_FUNCTION(0x6, "ir"), /* TX */
+ SUNXI_FUNCTION(0x7, "uart0"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 17)),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RX */
+ SUNXI_FUNCTION(0x3, "i2c3"), /* SDA */
+ SUNXI_FUNCTION(0x4, "pwm6"),
+ SUNXI_FUNCTION(0x5, "clk"), /* FANOUT1 */
+ SUNXI_FUNCTION(0x6, "spdif"), /* OUT */
+ SUNXI_FUNCTION(0x7, "uart0"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0xe, 5, 18)),
+};
+
+static const unsigned int d1_irq_bank_map[] = { 1, 2, 3, 4, 5, 6 };
+
+static const struct sunxi_pinctrl_desc d1_pinctrl_data = {
+ .pins = d1_pins,
+ .npins = ARRAY_SIZE(d1_pins),
+ .irq_banks = ARRAY_SIZE(d1_irq_bank_map),
+ .irq_bank_map = d1_irq_bank_map,
+ .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_CTL,
+};
+
+static int d1_pinctrl_probe(struct platform_device *pdev)
+{
+ unsigned long variant = (unsigned long)of_device_get_match_data(&pdev->dev);
+
+ return sunxi_pinctrl_init_with_variant(pdev, &d1_pinctrl_data, variant);
+}
+
+static const struct of_device_id d1_pinctrl_match[] = {
+ {
+ .compatible = "allwinner,sun20i-d1-pinctrl",
+ .data = (void *)PINCTRL_SUN20I_D1
+ },
+ {}
+};
+
+static struct platform_driver d1_pinctrl_driver = {
+ .probe = d1_pinctrl_probe,
+ .driver = {
+ .name = "sun20i-d1-pinctrl",
+ .of_match_table = d1_pinctrl_match,
+ },
+};
+builtin_platform_driver(d1_pinctrl_driver);
.npins = ARRAY_SIZE(a100_r_pins),
.pin_base = PL_BASE,
.irq_banks = 1,
+ .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_CTL,
};
static int a100_r_pinctrl_probe(struct platform_device *pdev)
.npins = ARRAY_SIZE(a100_pins),
.irq_banks = 7,
.irq_bank_map = a100_irq_bank_map,
- .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_SEL,
+ .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_CTL,
};
static int a100_pinctrl_probe(struct platform_device *pdev)
#include <linux/of_device.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
-#include <linux/reset.h>
#include "pinctrl-sunxi.h"
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/pinctrl.h>
-#include <linux/reset.h>
#include "pinctrl-sunxi.h"
.npins = ARRAY_SIZE(sun50i_h6_r_pins),
.pin_base = PL_BASE,
.irq_banks = 2,
+ .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_SEL,
};
static int sun50i_h6_r_pinctrl_probe(struct platform_device *pdev)
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/pinctrl.h>
-#include <linux/reset.h>
#include "pinctrl-sunxi.h"
.irq_banks = ARRAY_SIZE(h616_irq_bank_map),
.irq_bank_map = h616_irq_bank_map,
.irq_read_needs_mux = true,
- .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_SEL,
+ .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_CTL,
};
static int h616_pinctrl_probe(struct platform_device *pdev)
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/pinctrl.h>
-#include <linux/reset.h>
#include "pinctrl-sunxi.h"
static int sun6i_a31_r_pinctrl_probe(struct platform_device *pdev)
{
- struct reset_control *rstc;
- int ret;
-
- rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
- if (IS_ERR(rstc)) {
- dev_err(&pdev->dev, "Reset controller missing\n");
- return PTR_ERR(rstc);
- }
-
- ret = reset_control_deassert(rstc);
- if (ret)
- return ret;
-
- ret = sunxi_pinctrl_init(pdev,
- &sun6i_a31_r_pinctrl_data);
-
- if (ret)
- reset_control_assert(rstc);
-
- return ret;
+ return sunxi_pinctrl_init(pdev, &sun6i_a31_r_pinctrl_data);
}
static const struct of_device_id sun6i_a31_r_pinctrl_match[] = {
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/pinctrl.h>
-#include <linux/reset.h>
#include "pinctrl-sunxi.h"
static int sun8i_a23_r_pinctrl_probe(struct platform_device *pdev)
{
- struct reset_control *rstc;
- int ret;
-
- rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
- if (IS_ERR(rstc)) {
- ret = PTR_ERR(rstc);
- if (ret == -EPROBE_DEFER)
- return ret;
- dev_err(&pdev->dev, "Reset controller missing err=%d\n", ret);
- return ret;
- }
-
- ret = reset_control_deassert(rstc);
- if (ret)
- return ret;
-
- ret = sunxi_pinctrl_init(pdev,
- &sun8i_a23_r_pinctrl_data);
-
- if (ret)
- reset_control_assert(rstc);
-
- return ret;
+ return sunxi_pinctrl_init(pdev, &sun8i_a23_r_pinctrl_data);
}
static const struct of_device_id sun8i_a23_r_pinctrl_match[] = {
#include <linux/of_device.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
-#include <linux/reset.h>
#include "pinctrl-sunxi.h"
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/pinctrl.h>
-#include <linux/reset.h>
#include "pinctrl-sunxi.h"
static struct irq_chip sunxi_pinctrl_edge_irq_chip;
static struct irq_chip sunxi_pinctrl_level_irq_chip;
+/*
+ * The sunXi PIO registers are organized as a series of banks, with registers
+ * for each bank in the following order:
+ * - Mux config
+ * - Data value
+ * - Drive level
+ * - Pull direction
+ *
+ * Multiple consecutive registers are used for fields wider than one bit.
+ *
+ * The following functions calculate the register and the bit offset to access.
+ * They take a pin number which is relative to the start of the current device.
+ */
+static void sunxi_mux_reg(const struct sunxi_pinctrl *pctl,
+ u32 pin, u32 *reg, u32 *shift, u32 *mask)
+{
+ u32 bank = pin / PINS_PER_BANK;
+ u32 offset = pin % PINS_PER_BANK * MUX_FIELD_WIDTH;
+
+ *reg = bank * pctl->bank_mem_size + MUX_REGS_OFFSET +
+ offset / BITS_PER_TYPE(u32) * sizeof(u32);
+ *shift = offset % BITS_PER_TYPE(u32);
+ *mask = (BIT(MUX_FIELD_WIDTH) - 1) << *shift;
+}
+
+static void sunxi_data_reg(const struct sunxi_pinctrl *pctl,
+ u32 pin, u32 *reg, u32 *shift, u32 *mask)
+{
+ u32 bank = pin / PINS_PER_BANK;
+ u32 offset = pin % PINS_PER_BANK * DATA_FIELD_WIDTH;
+
+ *reg = bank * pctl->bank_mem_size + DATA_REGS_OFFSET +
+ offset / BITS_PER_TYPE(u32) * sizeof(u32);
+ *shift = offset % BITS_PER_TYPE(u32);
+ *mask = (BIT(DATA_FIELD_WIDTH) - 1) << *shift;
+}
+
+static void sunxi_dlevel_reg(const struct sunxi_pinctrl *pctl,
+ u32 pin, u32 *reg, u32 *shift, u32 *mask)
+{
+ u32 bank = pin / PINS_PER_BANK;
+ u32 offset = pin % PINS_PER_BANK * pctl->dlevel_field_width;
+
+ *reg = bank * pctl->bank_mem_size + DLEVEL_REGS_OFFSET +
+ offset / BITS_PER_TYPE(u32) * sizeof(u32);
+ *shift = offset % BITS_PER_TYPE(u32);
+ *mask = (BIT(pctl->dlevel_field_width) - 1) << *shift;
+}
+
+static void sunxi_pull_reg(const struct sunxi_pinctrl *pctl,
+ u32 pin, u32 *reg, u32 *shift, u32 *mask)
+{
+ u32 bank = pin / PINS_PER_BANK;
+ u32 offset = pin % PINS_PER_BANK * PULL_FIELD_WIDTH;
+
+ *reg = bank * pctl->bank_mem_size + pctl->pull_regs_offset +
+ offset / BITS_PER_TYPE(u32) * sizeof(u32);
+ *shift = offset % BITS_PER_TYPE(u32);
+ *mask = (BIT(PULL_FIELD_WIDTH) - 1) << *shift;
+}
+
static struct sunxi_pinctrl_group *
sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group)
{
.get_group_pins = sunxi_pctrl_get_group_pins,
};
-static int sunxi_pconf_reg(unsigned pin, enum pin_config_param param,
- u32 *offset, u32 *shift, u32 *mask)
+static int sunxi_pconf_reg(const struct sunxi_pinctrl *pctl,
+ u32 pin, enum pin_config_param param,
+ u32 *reg, u32 *shift, u32 *mask)
{
switch (param) {
case PIN_CONFIG_DRIVE_STRENGTH:
- *offset = sunxi_dlevel_reg(pin);
- *shift = sunxi_dlevel_offset(pin);
- *mask = DLEVEL_PINS_MASK;
+ sunxi_dlevel_reg(pctl, pin, reg, shift, mask);
break;
case PIN_CONFIG_BIAS_PULL_UP:
case PIN_CONFIG_BIAS_PULL_DOWN:
case PIN_CONFIG_BIAS_DISABLE:
- *offset = sunxi_pull_reg(pin);
- *shift = sunxi_pull_offset(pin);
- *mask = PULL_PINS_MASK;
+ sunxi_pull_reg(pctl, pin, reg, shift, mask);
break;
default:
{
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param = pinconf_to_config_param(*config);
- u32 offset, shift, mask, val;
+ u32 reg, shift, mask, val;
u16 arg;
int ret;
pin -= pctl->desc->pin_base;
- ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
+ ret = sunxi_pconf_reg(pctl, pin, param, ®, &shift, &mask);
if (ret < 0)
return ret;
- val = (readl(pctl->membase + offset) >> shift) & mask;
+ val = (readl(pctl->membase + reg) & mask) >> shift;
switch (pinconf_to_config_param(*config)) {
case PIN_CONFIG_DRIVE_STRENGTH:
pin -= pctl->desc->pin_base;
for (i = 0; i < num_configs; i++) {
+ u32 arg, reg, shift, mask, val;
enum pin_config_param param;
unsigned long flags;
- u32 offset, shift, mask, reg;
- u32 arg, val;
int ret;
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
- ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
+ ret = sunxi_pconf_reg(pctl, pin, param, ®, &shift, &mask);
if (ret < 0)
return ret;
}
raw_spin_lock_irqsave(&pctl->lock, flags);
- reg = readl(pctl->membase + offset);
- reg &= ~(mask << shift);
- writel(reg | val << shift, pctl->membase + offset);
+ writel((readl(pctl->membase + reg) & ~mask) | val << shift,
+ pctl->membase + reg);
raw_spin_unlock_irqrestore(&pctl->lock, flags);
} /* for each config */
unsigned pin,
struct regulator *supply)
{
- unsigned short bank = pin / PINS_PER_BANK;
+ unsigned short bank;
unsigned long flags;
u32 val, reg;
int uV;
if (uV == 0)
return 0;
+ pin -= pctl->desc->pin_base;
+ bank = pin / PINS_PER_BANK;
+
switch (pctl->desc->io_bias_cfg_variant) {
case BIAS_VOLTAGE_GRP_CONFIG:
/*
else
val = 0xD; /* 3.3V */
- pin -= pctl->desc->pin_base;
-
reg = readl(pctl->membase + sunxi_grp_config_reg(pin));
reg &= ~IO_BIAS_MASK;
writel(reg | val, pctl->membase + sunxi_grp_config_reg(pin));
return 0;
+ case BIAS_VOLTAGE_PIO_POW_MODE_CTL:
+ val = uV > 1800000 && uV <= 2500000 ? BIT(bank) : 0;
+
+ raw_spin_lock_irqsave(&pctl->lock, flags);
+ reg = readl(pctl->membase + PIO_POW_MOD_CTL_REG);
+ reg &= ~BIT(bank);
+ writel(reg | val, pctl->membase + PIO_POW_MOD_CTL_REG);
+ raw_spin_unlock_irqrestore(&pctl->lock, flags);
+
+ fallthrough;
case BIAS_VOLTAGE_PIO_POW_MODE_SEL:
val = uV <= 1800000 ? 1 : 0;
u8 config)
{
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ u32 reg, shift, mask;
unsigned long flags;
- u32 val, mask;
+
+ pin -= pctl->desc->pin_base;
+ sunxi_mux_reg(pctl, pin, ®, &shift, &mask);
raw_spin_lock_irqsave(&pctl->lock, flags);
- pin -= pctl->desc->pin_base;
- val = readl(pctl->membase + sunxi_mux_reg(pin));
- mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
- writel((val & ~mask) | config << sunxi_mux_offset(pin),
- pctl->membase + sunxi_mux_reg(pin));
+ writel((readl(pctl->membase + reg) & ~mask) | config << shift,
+ pctl->membase + reg);
raw_spin_unlock_irqrestore(&pctl->lock, flags);
}
static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
- u32 reg = sunxi_data_reg(offset);
- u8 index = sunxi_data_offset(offset);
bool set_mux = pctl->desc->irq_read_needs_mux &&
gpiochip_line_is_irq(chip, offset);
u32 pin = offset + chip->base;
- u32 val;
+ u32 reg, shift, mask, val;
+
+ sunxi_data_reg(pctl, offset, ®, &shift, &mask);
if (set_mux)
sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_INPUT);
- val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
+ val = (readl(pctl->membase + reg) & mask) >> shift;
if (set_mux)
sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_IRQ);
- return !!val;
+ return val;
}
static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
unsigned offset, int value)
{
struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
- u32 reg = sunxi_data_reg(offset);
- u8 index = sunxi_data_offset(offset);
+ u32 reg, shift, mask, val;
unsigned long flags;
- u32 regval;
+
+ sunxi_data_reg(pctl, offset, ®, &shift, &mask);
raw_spin_lock_irqsave(&pctl->lock, flags);
- regval = readl(pctl->membase + reg);
+ val = readl(pctl->membase + reg);
if (value)
- regval |= BIT(index);
+ val |= mask;
else
- regval &= ~(BIT(index));
+ val &= ~mask;
- writel(regval, pctl->membase + reg);
+ writel(val, pctl->membase + reg);
raw_spin_unlock_irqrestore(&pctl->lock, flags);
}
/*
* Find an upper bound for the maximum number of functions: in
- * the worst case we have gpio_in, gpio_out, irq and up to four
+ * the worst case we have gpio_in, gpio_out, irq and up to seven
* special functions per pin, plus one entry for the sentinel.
* We'll reallocate that later anyway.
*/
- pctl->functions = kcalloc(4 * pctl->ngroups + 4,
+ pctl->functions = kcalloc(7 * pctl->ngroups + 4,
sizeof(*pctl->functions),
GFP_KERNEL);
if (!pctl->functions)
pctl->dev = &pdev->dev;
pctl->desc = desc;
pctl->variant = variant;
+ if (pctl->variant >= PINCTRL_SUN20I_D1) {
+ pctl->bank_mem_size = D1_BANK_MEM_SIZE;
+ pctl->pull_regs_offset = D1_PULL_REGS_OFFSET;
+ pctl->dlevel_field_width = D1_DLEVEL_FIELD_WIDTH;
+ } else {
+ pctl->bank_mem_size = BANK_MEM_SIZE;
+ pctl->pull_regs_offset = PULL_REGS_OFFSET;
+ pctl->dlevel_field_width = DLEVEL_FIELD_WIDTH;
+ }
pctl->irq_array = devm_kcalloc(&pdev->dev,
IRQ_PER_BANK * pctl->desc->irq_banks,
#define BANK_MEM_SIZE 0x24
#define MUX_REGS_OFFSET 0x0
+#define MUX_FIELD_WIDTH 4
#define DATA_REGS_OFFSET 0x10
+#define DATA_FIELD_WIDTH 1
#define DLEVEL_REGS_OFFSET 0x14
+#define DLEVEL_FIELD_WIDTH 2
#define PULL_REGS_OFFSET 0x1c
+#define PULL_FIELD_WIDTH 2
+
+#define D1_BANK_MEM_SIZE 0x30
+#define D1_DLEVEL_FIELD_WIDTH 4
+#define D1_PULL_REGS_OFFSET 0x24
#define PINS_PER_BANK 32
-#define MUX_PINS_PER_REG 8
-#define MUX_PINS_BITS 4
-#define MUX_PINS_MASK 0x0f
-#define DATA_PINS_PER_REG 32
-#define DATA_PINS_BITS 1
-#define DATA_PINS_MASK 0x01
-#define DLEVEL_PINS_PER_REG 16
-#define DLEVEL_PINS_BITS 2
-#define DLEVEL_PINS_MASK 0x03
-#define PULL_PINS_PER_REG 16
-#define PULL_PINS_BITS 2
-#define PULL_PINS_MASK 0x03
#define IRQ_PER_BANK 32
#define PINCTRL_SUN8I_R40 BIT(8)
#define PINCTRL_SUN8I_V3 BIT(9)
#define PINCTRL_SUN8I_V3S BIT(10)
+/* Variants below here have an updated register layout. */
+#define PINCTRL_SUN20I_D1 BIT(11)
#define PIO_POW_MOD_SEL_REG 0x340
+#define PIO_POW_MOD_CTL_REG 0x344
enum sunxi_desc_bias_voltage {
BIAS_VOLTAGE_NONE,
* register, as seen on H6 SoC, for example.
*/
BIAS_VOLTAGE_PIO_POW_MODE_SEL,
+ /*
+ * Bias voltage is set through PIO_POW_MOD_SEL_REG
+ * and PIO_POW_MOD_CTL_REG register, as seen on
+ * A100 and D1 SoC, for example.
+ */
+ BIAS_VOLTAGE_PIO_POW_MODE_CTL,
};
struct sunxi_desc_function {
raw_spinlock_t lock;
struct pinctrl_dev *pctl_dev;
unsigned long variant;
+ u32 bank_mem_size;
+ u32 pull_regs_offset;
+ u32 dlevel_field_width;
};
#define SUNXI_PIN(_pin, ...) \
.irqnum = _irq, \
}
-/*
- * The sunXi PIO registers are organized as is:
- * 0x00 - 0x0c Muxing values.
- * 8 pins per register, each pin having a 4bits value
- * 0x10 Pin values
- * 32 bits per register, each pin corresponding to one bit
- * 0x14 - 0x18 Drive level
- * 16 pins per register, each pin having a 2bits value
- * 0x1c - 0x20 Pull-Up values
- * 16 pins per register, each pin having a 2bits value
- *
- * This is for the first bank. Each bank will have the same layout,
- * with an offset being a multiple of 0x24.
- *
- * The following functions calculate from the pin number the register
- * and the bit offset that we should access.
- */
-static inline u32 sunxi_mux_reg(u16 pin)
-{
- u8 bank = pin / PINS_PER_BANK;
- u32 offset = bank * BANK_MEM_SIZE;
- offset += MUX_REGS_OFFSET;
- offset += pin % PINS_PER_BANK / MUX_PINS_PER_REG * 0x04;
- return round_down(offset, 4);
-}
-
-static inline u32 sunxi_mux_offset(u16 pin)
-{
- u32 pin_num = pin % MUX_PINS_PER_REG;
- return pin_num * MUX_PINS_BITS;
-}
-
-static inline u32 sunxi_data_reg(u16 pin)
-{
- u8 bank = pin / PINS_PER_BANK;
- u32 offset = bank * BANK_MEM_SIZE;
- offset += DATA_REGS_OFFSET;
- offset += pin % PINS_PER_BANK / DATA_PINS_PER_REG * 0x04;
- return round_down(offset, 4);
-}
-
-static inline u32 sunxi_data_offset(u16 pin)
-{
- u32 pin_num = pin % DATA_PINS_PER_REG;
- return pin_num * DATA_PINS_BITS;
-}
-
-static inline u32 sunxi_dlevel_reg(u16 pin)
-{
- u8 bank = pin / PINS_PER_BANK;
- u32 offset = bank * BANK_MEM_SIZE;
- offset += DLEVEL_REGS_OFFSET;
- offset += pin % PINS_PER_BANK / DLEVEL_PINS_PER_REG * 0x04;
- return round_down(offset, 4);
-}
-
-static inline u32 sunxi_dlevel_offset(u16 pin)
-{
- u32 pin_num = pin % DLEVEL_PINS_PER_REG;
- return pin_num * DLEVEL_PINS_BITS;
-}
-
-static inline u32 sunxi_pull_reg(u16 pin)
-{
- u8 bank = pin / PINS_PER_BANK;
- u32 offset = bank * BANK_MEM_SIZE;
- offset += PULL_REGS_OFFSET;
- offset += pin % PINS_PER_BANK / PULL_PINS_PER_REG * 0x04;
- return round_down(offset, 4);
-}
-
-static inline u32 sunxi_pull_offset(u16 pin)
-{
- u32 pin_num = pin % PULL_PINS_PER_REG;
- return pin_num * PULL_PINS_BITS;
-}
-
static inline u32 sunxi_irq_hw_bank_num(const struct sunxi_pinctrl_desc *desc, u8 bank)
{
if (!desc->irq_bank_map)
node = of_parse_phandle(np, "memory-region", a);
/* Not map vdevbuffer, vdevring region */
- if (!strncmp(node->name, "vdev", strlen("vdev")))
+ if (!strncmp(node->name, "vdev", strlen("vdev"))) {
+ of_node_put(node);
continue;
+ }
err = of_address_to_resource(node, 0, &res);
+ of_node_put(node);
if (err) {
dev_err(dev, "unable to resolve memory region\n");
return err;
}
- of_node_put(node);
-
if (b >= IMX_RPROC_MEM_MAX)
break;
/* enable clock for accessing DSP internal memories */
pm_runtime_enable(dev);
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0) {
dev_err(dev, "failed to enable clock, status = %d\n", ret);
- pm_runtime_put_noidle(dev);
goto disable_rpm;
}
writel(0x0, scp->reg_base + MT8186_SCP_L1_SRAM_PD_P1);
writel(0x0, scp->reg_base + MT8186_SCP_L1_SRAM_PD_p2);
+ /*
+ * Set I-cache and D-cache size before loading SCP FW.
+ * SCP SRAM logical address may change when cache size setting differs.
+ */
+ writel(MT8183_SCP_CACHE_CON_WAYEN | MT8183_SCP_CACHESIZE_8KB,
+ scp->reg_base + MT8183_SCP_CACHE_CON);
+ writel(MT8183_SCP_CACHESIZE_8KB, scp->reg_base + MT8183_SCP_DCACHE_CON);
+
return 0;
}
.scp_da_to_va = mt8183_scp_da_to_va,
.host_to_scp_reg = MT8183_HOST_TO_SCP,
.host_to_scp_int_bit = MT8183_HOST_IPC_INT_BIT,
- .ipi_buf_offset = 0x7bdb0,
+ .ipi_buf_offset = 0x3bdb0,
+};
+
+static const struct mtk_scp_of_data mt8188_of_data = {
+ .scp_clk_get = mt8195_scp_clk_get,
+ .scp_before_load = mt8192_scp_before_load,
+ .scp_irq_handler = mt8192_scp_irq_handler,
+ .scp_reset_assert = mt8192_scp_reset_assert,
+ .scp_reset_deassert = mt8192_scp_reset_deassert,
+ .scp_stop = mt8192_scp_stop,
+ .scp_da_to_va = mt8192_scp_da_to_va,
+ .host_to_scp_reg = MT8192_GIPC_IN_SET,
+ .host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT,
};
static const struct mtk_scp_of_data mt8192_of_data = {
static const struct of_device_id mtk_scp_of_match[] = {
{ .compatible = "mediatek,mt8183-scp", .data = &mt8183_of_data },
{ .compatible = "mediatek,mt8186-scp", .data = &mt8186_of_data },
+ { .compatible = "mediatek,mt8188-scp", .data = &mt8188_of_data },
{ .compatible = "mediatek,mt8192-scp", .data = &mt8192_of_data },
{ .compatible = "mediatek,mt8195-scp", .data = &mt8195_of_data },
{},
* omap_rproc_ack_timer_irq() - acknowledge a timer irq
* @timer: handle to a OMAP rproc timer
*
- * This function is used to clear the irq associated with a watchdog timer. The
+ * This function is used to clear the irq associated with a watchdog timer.
* The function is called by the OMAP remoteproc upon a watchdog event on the
* remote processor to clear the interrupt status of the watchdog timer.
*/
* @configure: boolean flag used to acquire and configure the timer handle
*
* This function is used primarily to enable the timers associated with
- * a remoteproc. The configure flag is provided to allow the driver to
+ * a remoteproc. The configure flag is provided to allow the driver
* to either acquire and start a timer (during device initialization) or
* to just start a timer (during a resume operation).
*
* @configure: boolean flag used to release the timer handle
*
* This function is used primarily to disable the timers associated with
- * a remoteproc. The configure flag is provided to allow the driver to
+ * a remoteproc. The configure flag is provided to allow the driver
* to either stop and release a timer (during device shutdown) or to just
* stop a timer (during a suspend operation).
*
{ .compatible = "ti,j721e-pru", .data = &k3_pru_data },
{ .compatible = "ti,j721e-rtu", .data = &k3_rtu_data },
{ .compatible = "ti,j721e-tx-pru", .data = &k3_tx_pru_data },
+ { .compatible = "ti,am625-pru", .data = &k3_pru_data },
{},
};
MODULE_DEVICE_TABLE(of, pru_rproc_match);
};
/**
- * struct minidump_subsystem_toc: Subsystem's SMEM Table of content
+ * struct minidump_subsystem - Subsystem's SMEM Table of content
* @status : Subsystem toc init status
* @enabled : if set to 1, this region would be copied during coredump
* @encryption_status: Encryption status for this subsystem
};
/**
- * struct minidump_global_toc: Global Table of Content
+ * struct minidump_global_toc - Global Table of Content
* @status : Global Minidump init status
* @md_revision : Minidump revision
* @enabled : Minidump enable status
else
dev_err(q6v5->dev, "watchdog without message\n");
+ q6v5->running = false;
rproc_report_crash(q6v5->rproc, RPROC_WATCHDOG);
return IRQ_HANDLED;
size_t len;
char *msg;
+ if (!q6v5->running)
+ return IRQ_HANDLED;
+
msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len);
if (!IS_ERR(msg) && len > 0 && msg[0])
dev_err(q6v5->dev, "fatal error received: %s\n", msg);
for (i = 0; i < pd_count; i++) {
dev_pm_genpd_set_performance_state(pds[i], INT_MAX);
- ret = pm_runtime_get_sync(pds[i]);
+ ret = pm_runtime_resume_and_get(pds[i]);
if (ret < 0) {
- pm_runtime_put_noidle(pds[i]);
dev_pm_genpd_set_performance_state(pds[i], 0);
goto unroll_pd_votes;
}
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/devcoredump.h>
+#include <linux/dma-map-ops.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw,
const char *fw_name)
{
- unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
+ unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_KERNEL_MAPPING;
+ unsigned long flags = VM_DMA_COHERENT | VM_FLUSH_RESET_PERMS;
+ struct page **pages;
+ struct page *page;
dma_addr_t phys;
void *metadata;
int mdata_perm;
int xferop_ret;
size_t size;
- void *ptr;
+ void *vaddr;
+ int count;
int ret;
+ int i;
metadata = qcom_mdt_read_metadata(fw, &size, fw_name, qproc->dev);
if (IS_ERR(metadata))
return PTR_ERR(metadata);
- ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
- if (!ptr) {
+ page = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
+ if (!page) {
kfree(metadata);
dev_err(qproc->dev, "failed to allocate mdt buffer\n");
return -ENOMEM;
}
- memcpy(ptr, metadata, size);
+ count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ pages = kmalloc_array(count, sizeof(struct page *), GFP_KERNEL);
+ if (!pages) {
+ ret = -ENOMEM;
+ goto free_dma_attrs;
+ }
+
+ for (i = 0; i < count; i++)
+ pages[i] = nth_page(page, i);
+
+ vaddr = vmap(pages, count, flags, pgprot_dmacoherent(PAGE_KERNEL));
+ kfree(pages);
+ if (!vaddr) {
+ dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n", &phys, size);
+ ret = -EBUSY;
+ goto free_dma_attrs;
+ }
+
+ memcpy(vaddr, metadata, size);
+
+ vunmap(vaddr);
/* Hypervisor mapping to access metadata by modem */
mdata_perm = BIT(QCOM_SCM_VMID_HLOS);
"mdt buffer not reclaimed system may become unstable\n");
free_dma_attrs:
- dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs);
+ dma_free_attrs(qproc->dev, size, page, phys, dma_attrs);
kfree(metadata);
return ret < 0 ? ret : 0;
if (ret)
goto reclaim_mba;
+ if (qproc->has_mba_logs)
+ qcom_pil_info_store("mba", qproc->mba_phys, MBA_LOG_SIZE);
+
ret = q6v5_rmb_mba_wait(qproc, 0, 5000);
if (ret == -ETIMEDOUT) {
dev_err(qproc->dev, "MBA boot timed out\n");
return ret;
}
+static unsigned long q6v5_panic(struct rproc *rproc)
+{
+ struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
+
+ return qcom_q6v5_panic(&qproc->q6v5);
+}
+
static const struct rproc_ops q6v5_ops = {
.start = q6v5_start,
.stop = q6v5_stop,
.parse_fw = qcom_q6v5_register_dump_segments,
.load = q6v5_load,
+ .panic = q6v5_panic,
};
static void qcom_msa_handover(struct qcom_q6v5 *q6v5)
"mnoc_axi",
NULL
},
+ .proxy_pd_names = (char*[]){
+ "mx",
+ "cx",
+ NULL
+ },
.need_mem_protection = true,
.has_alt_reset = false,
.has_mba_logs = false,
*/
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include "qcom_q6v5.h"
#include "remoteproc_internal.h"
+#define ADSP_DECRYPT_SHUTDOWN_DELAY_MS 100
+
struct adsp_data {
int crash_reason_smem;
const char *firmware_name;
unsigned int minidump_id;
bool has_aggre2_clk;
bool auto_boot;
+ bool decrypt_shutdown;
char **proxy_pd_names;
unsigned int minidump_id;
int crash_reason_smem;
bool has_aggre2_clk;
+ bool decrypt_shutdown;
const char *info_name;
struct completion start_done;
{
struct qcom_adsp *adsp = rproc->priv;
+ if (rproc->dump_conf == RPROC_COREDUMP_DISABLED)
+ return;
+
qcom_minidump(rproc, adsp->minidump_id);
}
}
}
+static int adsp_shutdown_poll_decrypt(struct qcom_adsp *adsp)
+{
+ unsigned int retry_num = 50;
+ int ret;
+
+ do {
+ msleep(ADSP_DECRYPT_SHUTDOWN_DELAY_MS);
+ ret = qcom_scm_pas_shutdown(adsp->pas_id);
+ } while (ret == -EINVAL && --retry_num);
+
+ return ret;
+}
+
static int adsp_unprepare(struct rproc *rproc)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
if (ret)
goto disable_xo_clk;
- ret = regulator_enable(adsp->cx_supply);
- if (ret)
- goto disable_aggre2_clk;
+ if (adsp->cx_supply) {
+ ret = regulator_enable(adsp->cx_supply);
+ if (ret)
+ goto disable_aggre2_clk;
+ }
- ret = regulator_enable(adsp->px_supply);
- if (ret)
- goto disable_cx_supply;
+ if (adsp->px_supply) {
+ ret = regulator_enable(adsp->px_supply);
+ if (ret)
+ goto disable_cx_supply;
+ }
ret = qcom_scm_pas_auth_and_reset(adsp->pas_id);
if (ret) {
return 0;
disable_px_supply:
- regulator_disable(adsp->px_supply);
+ if (adsp->px_supply)
+ regulator_disable(adsp->px_supply);
disable_cx_supply:
- regulator_disable(adsp->cx_supply);
+ if (adsp->cx_supply)
+ regulator_disable(adsp->cx_supply);
disable_aggre2_clk:
clk_disable_unprepare(adsp->aggre2_clk);
disable_xo_clk:
{
struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5);
- regulator_disable(adsp->px_supply);
- regulator_disable(adsp->cx_supply);
+ if (adsp->px_supply)
+ regulator_disable(adsp->px_supply);
+ if (adsp->cx_supply)
+ regulator_disable(adsp->cx_supply);
clk_disable_unprepare(adsp->aggre2_clk);
clk_disable_unprepare(adsp->xo);
adsp_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
dev_err(adsp->dev, "timed out on wait\n");
ret = qcom_scm_pas_shutdown(adsp->pas_id);
+ if (ret && adsp->decrypt_shutdown)
+ ret = adsp_shutdown_poll_decrypt(adsp);
+
if (ret)
dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
if (offset < 0 || offset + len > adsp->mem_size)
return NULL;
+ if (is_iomem)
+ *is_iomem = true;
+
return adsp->mem_region + offset;
}
static int adsp_init_regulator(struct qcom_adsp *adsp)
{
- adsp->cx_supply = devm_regulator_get(adsp->dev, "cx");
- if (IS_ERR(adsp->cx_supply))
- return PTR_ERR(adsp->cx_supply);
+ adsp->cx_supply = devm_regulator_get_optional(adsp->dev, "cx");
+ if (IS_ERR(adsp->cx_supply)) {
+ if (PTR_ERR(adsp->cx_supply) == -ENODEV)
+ adsp->cx_supply = NULL;
+ else
+ return PTR_ERR(adsp->cx_supply);
+ }
- regulator_set_load(adsp->cx_supply, 100000);
+ if (adsp->cx_supply)
+ regulator_set_load(adsp->cx_supply, 100000);
- adsp->px_supply = devm_regulator_get(adsp->dev, "px");
- return PTR_ERR_OR_ZERO(adsp->px_supply);
+ adsp->px_supply = devm_regulator_get_optional(adsp->dev, "px");
+ if (IS_ERR(adsp->px_supply)) {
+ if (PTR_ERR(adsp->px_supply) == -ENODEV)
+ adsp->px_supply = NULL;
+ else
+ return PTR_ERR(adsp->px_supply);
+ }
+
+ return 0;
}
static int adsp_pds_attach(struct device *dev, struct device **devs,
adsp->pas_id = desc->pas_id;
adsp->has_aggre2_clk = desc->has_aggre2_clk;
adsp->info_name = desc->sysmon_name;
+ adsp->decrypt_shutdown = desc->decrypt_shutdown;
platform_set_drvdata(pdev, adsp);
- device_wakeup_enable(adsp->dev);
+ ret = device_init_wakeup(adsp->dev, true);
+ if (ret)
+ goto free_rproc;
ret = adsp_alloc_memory_region(adsp);
if (ret)
.ssctl_id = 0x22,
};
+static const struct adsp_data sm8450_mpss_resource = {
+ .crash_reason_smem = 421,
+ .firmware_name = "modem.mdt",
+ .pas_id = 4,
+ .minidump_id = 3,
+ .has_aggre2_clk = false,
+ .auto_boot = false,
+ .decrypt_shutdown = true,
+ .proxy_pd_names = (char*[]){
+ "cx",
+ "mss",
+ NULL
+ },
+ .load_state = "modem",
+ .ssr_name = "mpss",
+ .sysmon_name = "modem",
+ .ssctl_id = 0x12,
+};
+
static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,msm8226-adsp-pil", .data = &adsp_resource_init},
{ .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init},
{ .compatible = "qcom,sm8450-adsp-pas", .data = &sm8350_adsp_resource},
{ .compatible = "qcom,sm8450-cdsp-pas", .data = &sm8350_cdsp_resource},
{ .compatible = "qcom,sm8450-slpi-pas", .data = &sm8350_slpi_resource},
- { .compatible = "qcom,sm8450-mpss-pas", .data = &mpss_resource_init},
+ { .compatible = "qcom,sm8450-mpss-pas", .data = &sm8450_mpss_resource},
{ },
};
MODULE_DEVICE_TABLE(of, adsp_of_match);
struct completion comp;
struct completion ind_comp;
struct completion shutdown_comp;
+ struct completion ssctl_comp;
struct mutex lock;
bool ssr_ack;
svc->priv = sysmon;
+ complete(&sysmon->ssctl_comp);
+
return 0;
}
.ssr_event = SSCTL_SSR_EVENT_AFTER_POWERUP
};
+ reinit_completion(&sysmon->ssctl_comp);
mutex_lock(&sysmon->state_lock);
sysmon->state = SSCTL_SSR_EVENT_AFTER_POWERUP;
blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event);
mutex_lock(&sysmon_lock);
list_for_each_entry(target, &sysmon_list, node) {
- if (target == sysmon)
+ mutex_lock(&target->state_lock);
+ if (target == sysmon || target->state != SSCTL_SSR_EVENT_AFTER_POWERUP) {
+ mutex_unlock(&target->state_lock);
continue;
+ }
- mutex_lock(&target->state_lock);
event.subsys_name = target->name;
event.ssr_event = target->state;
if (crashed)
return;
+ if (sysmon->ssctl_instance) {
+ if (!wait_for_completion_timeout(&sysmon->ssctl_comp, HZ / 2))
+ dev_err(sysmon->dev, "timeout waiting for ssctl service\n");
+ }
+
if (sysmon->ssctl_version)
sysmon->shutdown_acked = ssctl_request_shutdown(sysmon);
else if (sysmon->ept)
init_completion(&sysmon->comp);
init_completion(&sysmon->ind_comp);
init_completion(&sysmon->shutdown_comp);
+ init_completion(&sysmon->ssctl_comp);
mutex_init(&sysmon->lock);
mutex_init(&sysmon->state_lock);
irq_handler_t thread_fn)
{
int ret;
+ int irq_number;
ret = platform_get_irq_byname(pdev, name);
if (ret < 0 && optional) {
return ret;
}
+ irq_number = ret;
+
ret = devm_request_threaded_irq(&pdev->dev, ret,
NULL, thread_fn,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"wcnss", wcnss);
- if (ret)
+ if (ret) {
dev_err(&pdev->dev, "request %s IRQ failed\n", name);
+ return ret;
+ }
- return ret;
+ /* Return the IRQ number if the IRQ was successfully acquired */
+ return irq_number;
}
static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss)
/* Unique indices for remoteproc devices */
static DEFINE_IDA(rproc_dev_index);
+static struct workqueue_struct *rproc_recovery_wq;
static const char * const rproc_crash_names[] = {
[RPROC_MMUFAULT] = "mmufault",
struct rproc_vdev *rvdev = container_of(dev, struct rproc_vdev, dev);
of_reserved_mem_device_release(dev);
+ dma_release_coherent_memory(dev);
kfree(rvdev);
}
return 0;
}
- /* Register carveout in in list */
+ /* Register carveout in list */
carveout = rproc_mem_entry_init(dev, NULL, 0, rsc->len, rsc->da,
rproc_alloc_carveout,
rproc_release_carveout, rsc->name);
idr_destroy(&rproc->notifyids);
if (rproc->index >= 0)
- ida_simple_remove(&rproc_dev_index, rproc->index);
+ ida_free(&rproc_dev_index, rproc->index);
kfree_const(rproc->firmware);
kfree_const(rproc->name);
goto put_device;
/* Assign a unique device index and name */
- rproc->index = ida_simple_get(&rproc_dev_index, 0, 0, GFP_KERNEL);
+ rproc->index = ida_alloc(&rproc_dev_index, GFP_KERNEL);
if (rproc->index < 0) {
- dev_err(dev, "ida_simple_get failed: %d\n", rproc->index);
+ dev_err(dev, "ida_alloc failed: %d\n", rproc->index);
goto put_device;
}
dev_err(&rproc->dev, "crash detected in %s: type %s\n",
rproc->name, rproc_crash_to_string(type));
- /* Have a worker handle the error; ensure system is not suspended */
- queue_work(system_freezable_wq, &rproc->crash_handler);
+ queue_work(rproc_recovery_wq, &rproc->crash_handler);
}
EXPORT_SYMBOL(rproc_report_crash);
static int __init remoteproc_init(void)
{
+ rproc_recovery_wq = alloc_workqueue("rproc_recovery_wq",
+ WQ_UNBOUND | WQ_FREEZABLE, 0);
+ if (!rproc_recovery_wq) {
+ pr_err("remoteproc: creation of rproc_recovery_wq failed\n");
+ return -ENOMEM;
+ }
+
rproc_init_sysfs();
rproc_init_debugfs();
rproc_init_cdev();
{
ida_destroy(&rproc_dev_index);
+ if (!rproc_recovery_wq)
+ return;
+
rproc_exit_panic();
rproc_exit_debugfs();
rproc_exit_sysfs();
+ destroy_workqueue(rproc_recovery_wq);
}
module_exit(remoteproc_exit);
if (!cpdev) {
ret = -ENODEV;
dev_err(dev, "could not get R5 core platform device\n");
+ of_node_put(child);
goto fail;
}
dev_err(dev, "k3_r5_core_of_init failed, ret = %d\n",
ret);
put_device(&cpdev->dev);
+ of_node_put(child);
goto fail;
}
if (info->registered)
continue;
+ mutex_unlock(&subdev->channels_lock);
ret = mtk_rpmsg_register_device(subdev, &info->info);
+ mutex_lock(&subdev->channels_lock);
if (ret) {
dev_err(&pdev->dev, "Can't create rpmsg_device\n");
continue;
struct qcom_glink {
struct device *dev;
- const char *name;
-
struct mbox_client mbox_client;
struct mbox_chan *mbox_chan;
cancel_work_sync(&channel->intent_work);
if (channel->rpdev) {
- strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
+ strscpy_pad(chinfo.name, channel->name, sizeof(chinfo.name));
chinfo.src = RPMSG_ADDR_ANY;
chinfo.dst = RPMSG_ADDR_ANY;
if (ret < 0)
name = dev->of_node->name;
- return snprintf(buf, RPMSG_NAME_SIZE, "%s\n", name);
+ return sysfs_emit(buf, "%s\n", name);
}
static DEVICE_ATTR_RO(rpmsg_name);
if (ret)
dev_err(dev, "failed to add groups\n");
- ret = of_property_read_string(dev->of_node, "label", &glink->name);
- if (ret < 0)
- glink->name = dev->of_node->name;
-
glink->mbox_client.dev = dev;
glink->mbox_client.knows_txdone = true;
glink->mbox_chan = mbox_request_channel(&glink->mbox_client, 0);
__le32 seq_num;
};
-/**
+/*
* G-Link SSR protocol commands
*/
#define GLINK_SSR_DO_CLEANUP 0
}
/**
- * qcom_smd_send - write data to smd channel
+ * __qcom_smd_send - write data to smd channel
* @channel: channel handle
* @data: buffer of data to write
* @len: number of bytes to write
- * @wait: flag to indicate if write has ca wait
+ * @wait: flag to indicate if write can wait
*
* This is a blocking write of len bytes into the channel's tx ring buffer and
* signal the remote end. It will sleep until there is enough space available
/* Assign public information to the rpmsg_device */
rpdev = &qsdev->rpdev;
- strncpy(rpdev->id.name, channel->name, RPMSG_NAME_SIZE);
+ strscpy_pad(rpdev->id.name, channel->name, RPMSG_NAME_SIZE);
rpdev->src = RPMSG_ADDR_ANY;
rpdev->dst = RPMSG_ADDR_ANY;
spin_unlock_irqrestore(&edge->channels_lock, flags);
- strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
+ strscpy_pad(chinfo.name, channel->name, sizeof(chinfo.name));
chinfo.src = RPMSG_ADDR_ANY;
chinfo.dst = RPMSG_ADDR_ANY;
rpmsg_unregister_device(&edge->dev, &chinfo);
}
edge->ipc_regmap = syscon_node_to_regmap(syscon_np);
+ of_node_put(syscon_np);
if (IS_ERR(edge->ipc_regmap)) {
ret = PTR_ERR(edge->ipc_regmap);
goto put_node;
struct rpmsg_device *rpdev = eptdev->rpdev;
struct device *dev = &eptdev->dev;
- if (eptdev->ept)
+ mutex_lock(&eptdev->ept_lock);
+ if (eptdev->ept) {
+ mutex_unlock(&eptdev->ept_lock);
return -EBUSY;
+ }
get_device(dev);
if (!ept) {
dev_err(dev, "failed to open %s\n", eptdev->chinfo.name);
put_device(dev);
+ mutex_unlock(&eptdev->ept_lock);
return -EINVAL;
}
eptdev->ept = ept;
filp->private_data = eptdev;
+ mutex_unlock(&eptdev->ept_lock);
return 0;
}
int ret;
if (driver_override)
- strcpy(rpdev->id.name, driver_override);
+ strscpy_pad(rpdev->id.name, driver_override, RPMSG_NAME_SIZE);
dev_set_name(dev, "%s.%s.%d.%d", dev_name(dev->parent),
rpdev->id.name, rpdev->src, rpdev->dst);
strlen(driver_override));
if (ret) {
dev_err(dev, "device_set_override failed: %d\n", ret);
+ put_device(dev);
return ret;
}
}
rpmsg_rx_cb_t cb, void *priv,
struct rpmsg_channel_info chinfo);
- int (*announce_create)(struct rpmsg_device *ept);
- int (*announce_destroy)(struct rpmsg_device *ept);
+ int (*announce_create)(struct rpmsg_device *rpdev);
+ int (*announce_destroy)(struct rpmsg_device *rpdev);
};
/**
{
u32 hw_version;
int err;
-
- err = devm_pm_opp_set_clkname(dev, NULL);
- if (err) {
- dev_err(dev, "failed to set OPP clk: %d\n", err);
- return err;
- }
-
- /* Tegra114+ doesn't support OPP yet */
- if (!of_machine_is_compatible("nvidia,tegra20") &&
- !of_machine_is_compatible("nvidia,tegra30"))
- return -ENODEV;
-
- if (of_machine_is_compatible("nvidia,tegra20"))
+ /*
+ * The clk's connection id to set is NULL and this is a NULL terminated
+ * array, hence two NULL entries.
+ */
+ const char *clk_names[] = { NULL, NULL };
+ struct dev_pm_opp_config config = {
+ /*
+ * For some devices we don't have any OPP table in the DT, and
+ * in order to use the same code path for all the devices, we
+ * create a dummy OPP table for them via this. The dummy OPP
+ * table is only capable of doing clk_set_rate() on invocation
+ * of dev_pm_opp_set_rate() and doesn't provide any other
+ * functionality.
+ */
+ .clk_names = clk_names,
+ };
+
+ if (of_machine_is_compatible("nvidia,tegra20")) {
hw_version = BIT(tegra_sku_info.soc_process_id);
- else
+ config.supported_hw = &hw_version;
+ config.supported_hw_count = 1;
+ } else if (of_machine_is_compatible("nvidia,tegra30")) {
hw_version = BIT(tegra_sku_info.soc_speedo_id);
+ config.supported_hw = &hw_version;
+ config.supported_hw_count = 1;
+ }
- err = devm_pm_opp_set_supported_hw(dev, &hw_version, 1);
+ err = devm_pm_opp_set_config(dev, &config);
if (err) {
- dev_err(dev, "failed to set OPP supported HW: %d\n", err);
+ dev_err(dev, "failed to set OPP config: %d\n", err);
return err;
}
+ /*
+ * Tegra114+ doesn't support OPP yet, return early for non tegra20/30
+ * case.
+ */
+ if (!config.supported_hw)
+ return -ENODEV;
+
/*
* Older device-trees have an empty OPP table, we will get
* -ENODEV from devm_pm_opp_of_add_table() in this case.
static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
{
struct generic_pm_domain *genpd;
- const char *rname = "core";
+ const char *rname[] = { "core", NULL};
int err;
genpd = devm_kzalloc(pmc->dev, sizeof(*genpd), GFP_KERNEL);
genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state;
genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state;
- err = devm_pm_opp_set_regulators(pmc->dev, &rname, 1);
+ err = devm_pm_opp_set_regulators(pmc->dev, rname);
if (err)
return dev_err_probe(pmc->dev, err,
"failed to set core OPP regulator\n");
config THERMAL_MMIO
tristate "Generic Thermal MMIO driver"
- depends on OF || COMPILE_TEST
+ depends on OF
depends on HAS_IOMEM
help
This option enables the generic thermal MMIO driver that will use
config KHADAS_MCU_FAN_THERMAL
tristate "Khadas MCU controller FAN cooling support"
- depends on OF || COMPILE_TEST
+ depends on OF
depends on MFD_KHADAS_MCU
select MFD_CORE
select REGMAP
X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL),
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, NULL),
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, NULL),
+ X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, NULL),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, NULL),
+ X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, NULL),
{}
};
static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
{
+ const struct attribute_group *stats_attr_group = NULL;
struct cooling_dev_stats *stats;
unsigned long states;
int var;
if (cdev->ops->get_max_state(cdev, &states))
- return;
+ goto out;
states++; /* Total number of states is highest state + 1 */
stats = kzalloc(var, GFP_KERNEL);
if (!stats)
- return;
+ goto out;
stats->time_in_state = (ktime_t *)(stats + 1);
stats->trans_table = (unsigned int *)(stats->time_in_state + states);
spin_lock_init(&stats->lock);
+ stats_attr_group = &cooling_device_stats_attr_group;
+
+out:
/* Fill the empty slot left in cooling_device_attr_groups */
var = ARRAY_SIZE(cooling_device_attr_groups) - 2;
- cooling_device_attr_groups[var] = &cooling_device_stats_attr_group;
+ cooling_device_attr_groups[var] = stats_attr_group;
}
static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev)
size_t offset;
unsigned int npages = 0;
- bytes = iov_iter_get_pages(iter, pages, LONG_MAX,
+ bytes = iov_iter_get_pages2(iter, pages, LONG_MAX,
VHOST_SCSI_PREALLOC_UPAGES, &offset);
/* No pages were pinned */
if (bytes <= 0)
return bytes < 0 ? bytes : -EFAULT;
- iov_iter_advance(iter, bytes);
-
while (bytes) {
unsigned n = min_t(unsigned, PAGE_SIZE - offset, bytes);
sg_set_page(sg++, pages[npages++], n, offset);
if (!res)
return -ENODEV;
dev->reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!dev->reg)
+ return -ENOMEM;
/* init clock */
dev->clk = devm_clk_get(&pdev->dev, NULL);
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int bcm7038_wdt_suspend(struct device *dev)
{
struct bcm7038_watchdog *wdt = dev_get_drvdata(dev);
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(bcm7038_wdt_pm_ops, bcm7038_wdt_suspend,
- bcm7038_wdt_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(bcm7038_wdt_pm_ops,
+ bcm7038_wdt_suspend, bcm7038_wdt_resume);
static const struct of_device_id bcm7038_wdt_match[] = {
{ .compatible = "brcm,bcm6345-wdt" },
.driver = {
.name = "bcm7038-wdt",
.of_match_table = bcm7038_wdt_match,
- .pm = &bcm7038_wdt_pm_ops,
+ .pm = pm_sleep_ptr(&bcm7038_wdt_pm_ops),
}
};
module_platform_driver(bcm7038_wdt_driver);
/*
* This procedure will find the highest period which will give a timeout
* greater than the one required. e.g. for a bus speed of 66666666 and
- * and a parameter of 2 secs, then this procedure will return a value of 38.
+ * a parameter of 2 secs, then this procedure will return a value of 38.
*/
static unsigned int sec_to_period(unsigned int secs)
{
/*
* Set the new value in the watchdog. Some versions of dw_wdt
- * have have TOPINIT in the TIMEOUT_RANGE register (as per
+ * have TOPINIT in the TIMEOUT_RANGE register (as per
* CP_WDT_DUAL_TOP in WDT_COMP_PARAMS_1). On those we
* effectively get a pat of the watchdog right here.
*/
return IRQ_HANDLED;
}
-#ifdef CONFIG_PM_SLEEP
static int dw_wdt_suspend(struct device *dev)
{
struct dw_wdt *dw_wdt = dev_get_drvdata(dev);
return 0;
}
-#endif /* CONFIG_PM_SLEEP */
-static SIMPLE_DEV_PM_OPS(dw_wdt_pm_ops, dw_wdt_suspend, dw_wdt_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(dw_wdt_pm_ops, dw_wdt_suspend, dw_wdt_resume);
/*
* In case if DW WDT IP core is synthesized with fixed TOP feature disabled the
.driver = {
.name = "dw_wdt",
.of_match_table = of_match_ptr(dw_wdt_of_match),
- .pm = &dw_wdt_pm_ops,
+ .pm = pm_sleep_ptr(&dw_wdt_pm_ops),
},
};
pdata.type = ret;
- platform_driver_register(&fintek_wdt_driver);
+ ret = platform_driver_register(&fintek_wdt_driver);
+ if (ret)
+ return ret;
wdt_res.name = "superio port";
wdt_res.flags = IORESOURCE_IO;
* Copyright (C) 2022 Luca Ceresoli
*
* Author: Laxman Dewangan <ldewangan@nvidia.com>
- * Author: Luca Ceresoli <luca@lucaceresoli.net>
+ * Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
*/
#include <linux/err.h>
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
-MODULE_AUTHOR("Luca Ceresoli <luca@lucaceresoli.net>");
+MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");
MODULE_LICENSE("GPL v2");
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int mtk_wdt_suspend(struct device *dev)
{
struct mtk_wdt_dev *mtk_wdt = dev_get_drvdata(dev);
return 0;
}
-#endif
static const struct of_device_id mtk_wdt_dt_ids[] = {
{ .compatible = "mediatek,mt2712-wdt", .data = &mt2712_data },
};
MODULE_DEVICE_TABLE(of, mtk_wdt_dt_ids);
-static const struct dev_pm_ops mtk_wdt_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(mtk_wdt_suspend,
- mtk_wdt_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(mtk_wdt_pm_ops,
+ mtk_wdt_suspend, mtk_wdt_resume);
static struct platform_driver mtk_wdt_driver = {
.probe = mtk_wdt_probe,
.driver = {
.name = DRV_NAME,
- .pm = &mtk_wdt_pm_ops,
+ .pm = pm_sleep_ptr(&mtk_wdt_pm_ops),
.of_match_table = mtk_wdt_dt_ids,
},
};
}
}
-/* -- Notifier funtions -----------------------------------------*/
+/* -- Notifier functions -----------------------------------------*/
/**
* pc87413_notify_sys:
#include <linux/regmap.h>
#include <linux/watchdog.h>
+#define PON_POFF_REASON1 0x0c
+#define PON_POFF_REASON1_PMIC_WD BIT(2)
+#define PON_POFF_REASON2 0x0d
+#define PON_POFF_REASON2_UVLO BIT(5)
+#define PON_POFF_REASON2_OTST3 BIT(6)
+
#define PON_INT_RT_STS 0x10
#define PMIC_WD_BARK_STS_BIT BIT(6)
{
struct pm8916_wdt *wdt = watchdog_get_drvdata(wdev);
- return regmap_update_bits(wdt->regmap,
- wdt->baseaddr + PON_PMIC_WD_RESET_PET,
- WATCHDOG_PET_BIT, WATCHDOG_PET_BIT);
+ return regmap_write(wdt->regmap, wdt->baseaddr + PON_PMIC_WD_RESET_PET,
+ WATCHDOG_PET_BIT);
}
static int pm8916_wdt_configure_timers(struct watchdog_device *wdev)
}
static const struct watchdog_info pm8916_wdt_ident = {
- .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE |
+ WDIOF_OVERHEAT | WDIOF_CARDRESET | WDIOF_POWERUNDER,
.identity = "QCOM PM8916 PON WDT",
};
static const struct watchdog_info pm8916_wdt_pt_ident = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE |
+ WDIOF_OVERHEAT | WDIOF_CARDRESET | WDIOF_POWERUNDER |
WDIOF_PRETIMEOUT,
.identity = "QCOM PM8916 PON WDT",
};
struct device *dev = &pdev->dev;
struct pm8916_wdt *wdt;
struct device *parent;
+ unsigned int val;
int err, irq;
+ u8 poff[2];
wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
if (!wdt)
wdt->wdev.info = &pm8916_wdt_ident;
}
+ err = regmap_bulk_read(wdt->regmap, wdt->baseaddr + PON_POFF_REASON1,
+ &poff, ARRAY_SIZE(poff));
+ if (err) {
+ dev_err(dev, "failed to read POFF reason: %d\n", err);
+ return err;
+ }
+
+ dev_dbg(dev, "POFF reason: %#x %#x\n", poff[0], poff[1]);
+ if (poff[0] & PON_POFF_REASON1_PMIC_WD)
+ wdt->wdev.bootstatus |= WDIOF_CARDRESET;
+ if (poff[1] & PON_POFF_REASON2_UVLO)
+ wdt->wdev.bootstatus |= WDIOF_POWERUNDER;
+ if (poff[1] & PON_POFF_REASON2_OTST3)
+ wdt->wdev.bootstatus |= WDIOF_OVERHEAT;
+
+ err = regmap_read(wdt->regmap, wdt->baseaddr + PON_PMIC_WD_RESET_S2_CTL2,
+ &val);
+ if (err) {
+ dev_err(dev, "failed to check if watchdog is active: %d\n", err);
+ return err;
+ }
+ if (val & S2_RESET_EN_BIT)
+ set_bit(WDOG_HW_RUNNING, &wdt->wdev.status);
+
/* Configure watchdog to hard-reset mode */
err = regmap_write(wdt->regmap,
wdt->baseaddr + PON_PMIC_WD_RESET_S2_CTL,
{ .compatible = "realtek,rtl8380-wdt" },
{ .compatible = "realtek,rtl8390-wdt" },
{ .compatible = "realtek,rtl9300-wdt" },
+ { .compatible = "realtek,rtl9310-wdt" },
{ }
};
MODULE_DEVICE_TABLE(of, otto_wdt_ids);
s3c2410wdt_stop(&wdt->wdt_device);
}
-#ifdef CONFIG_PM_SLEEP
-
static int s3c2410wdt_suspend(struct device *dev)
{
int ret;
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops, s3c2410wdt_suspend,
- s3c2410wdt_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops,
+ s3c2410wdt_suspend, s3c2410wdt_resume);
static struct platform_driver s3c2410wdt_driver = {
.probe = s3c2410wdt_probe,
.id_table = s3c2410_wdt_ids,
.driver = {
.name = "s3c2410-wdt",
- .pm = &s3c2410wdt_pm_ops,
+ .pm = pm_sleep_ptr(&s3c2410wdt_pm_ops),
.of_match_table = of_match_ptr(s3c2410_wdt_match),
},
};
};
MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match);
-#ifdef CONFIG_PM_SLEEP
static int sama5d4_wdt_suspend_late(struct device *dev)
{
struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
return 0;
}
-#endif
static const struct dev_pm_ops sama5d4_wdt_pm_ops = {
- SET_LATE_SYSTEM_SLEEP_PM_OPS(sama5d4_wdt_suspend_late,
- sama5d4_wdt_resume_early)
+ LATE_SYSTEM_SLEEP_PM_OPS(sama5d4_wdt_suspend_late,
+ sama5d4_wdt_resume_early)
};
static struct platform_driver sama5d4_wdt_driver = {
.probe = sama5d4_wdt_probe,
.driver = {
.name = "sama5d4_wdt",
- .pm = &sama5d4_wdt_pm_ops,
+ .pm = pm_sleep_ptr(&sama5d4_wdt_pm_ops),
.of_match_table = sama5d4_wdt_of_match,
}
};
iounmap(addr);
release_resource(res);
+ kfree(res);
return ret;
}
+// SPDX-License-Identifier: GPL-2.0+
/*
* drivers/char/watchdog/sp805-wdt.c
*
.id = 0x00141805,
.mask = 0x00ffffff,
},
+ {
+ .id = 0x001bb824,
+ .mask = 0x00ffffff,
+ },
{ 0, 0 },
};
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int st_wdog_suspend(struct device *dev)
{
struct st_wdog *st_wdog = watchdog_get_drvdata(&st_wdog_dev);
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(st_wdog_pm_ops,
- st_wdog_suspend,
- st_wdog_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(st_wdog_pm_ops,
+ st_wdog_suspend, st_wdog_resume);
static struct platform_driver st_wdog_driver = {
.driver = {
.name = "st-lpc-wdt",
- .pm = &st_wdog_pm_ops,
+ .pm = pm_sleep_ptr(&st_wdog_pm_ops),
.of_match_table = st_wdog_match,
},
.probe = st_wdog_probe,
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int tegra_wdt_runtime_suspend(struct device *dev)
+static int tegra_wdt_suspend(struct device *dev)
{
struct tegra_wdt *wdt = dev_get_drvdata(dev);
return 0;
}
-static int tegra_wdt_runtime_resume(struct device *dev)
+static int tegra_wdt_resume(struct device *dev)
{
struct tegra_wdt *wdt = dev_get_drvdata(dev);
return 0;
}
-#endif
static const struct of_device_id tegra_wdt_of_match[] = {
{ .compatible = "nvidia,tegra30-timer", },
};
MODULE_DEVICE_TABLE(of, tegra_wdt_of_match);
-static const struct dev_pm_ops tegra_wdt_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(tegra_wdt_runtime_suspend,
- tegra_wdt_runtime_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(tegra_wdt_pm_ops,
+ tegra_wdt_suspend, tegra_wdt_resume);
static struct platform_driver tegra_wdt_driver = {
.probe = tegra_wdt_probe,
.driver = {
.name = "tegra-wdt",
- .pm = &tegra_wdt_pm_ops,
+ .pm = pm_sleep_ptr(&tegra_wdt_pm_ops),
.of_match_table = tegra_wdt_of_match,
},
};
return devm_watchdog_register_device(dev, &wdat->wdd);
}
-#ifdef CONFIG_PM_SLEEP
static int wdat_wdt_suspend_noirq(struct device *dev)
{
struct wdat_wdt *wdat = dev_get_drvdata(dev);
return wdat_wdt_start(&wdat->wdd);
}
-#endif
static const struct dev_pm_ops wdat_wdt_pm_ops = {
- SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(wdat_wdt_suspend_noirq,
- wdat_wdt_resume_noirq)
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(wdat_wdt_suspend_noirq, wdat_wdt_resume_noirq)
};
static struct platform_driver wdat_wdt_driver = {
.probe = wdat_wdt_probe,
.driver = {
.name = "wdat_wdt",
- .pm = &wdat_wdt_pm_ops,
+ .pm = pm_sleep_ptr(&wdat_wdt_pm_ops),
},
};
cell->name[i] = tolower(name[i]);
cell->name[i] = 0;
- atomic_set(&cell->ref, 1);
+ refcount_set(&cell->ref, 1);
atomic_set(&cell->active, 0);
INIT_WORK(&cell->manager, afs_manage_cell_work);
cell->volumes = RB_ROOT;
cell = candidate;
candidate = NULL;
atomic_set(&cell->active, 2);
- trace_afs_cell(cell->debug_id, atomic_read(&cell->ref), 2, afs_cell_trace_insert);
+ trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), 2, afs_cell_trace_insert);
rb_link_node_rcu(&cell->net_node, parent, pp);
rb_insert_color(&cell->net_node, &net->cells);
up_write(&net->cells_lock);
afs_queue_cell(cell, afs_cell_trace_get_queue_new);
wait_for_cell:
- trace_afs_cell(cell->debug_id, atomic_read(&cell->ref), atomic_read(&cell->active),
+ trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), atomic_read(&cell->active),
afs_cell_trace_wait);
_debug("wait_for_cell");
wait_var_event(&cell->state,
{
struct afs_cell *cell = container_of(rcu, struct afs_cell, rcu);
struct afs_net *net = cell->net;
- int u;
+ int r;
_enter("%p{%s}", cell, cell->name);
- u = atomic_read(&cell->ref);
- ASSERTCMP(u, ==, 0);
- trace_afs_cell(cell->debug_id, u, atomic_read(&cell->active), afs_cell_trace_free);
+ r = refcount_read(&cell->ref);
+ ASSERTCMP(r, ==, 0);
+ trace_afs_cell(cell->debug_id, r, atomic_read(&cell->active), afs_cell_trace_free);
afs_put_vlserverlist(net, rcu_access_pointer(cell->vl_servers));
afs_unuse_cell(net, cell->alias_of, afs_cell_trace_unuse_alias);
*/
struct afs_cell *afs_get_cell(struct afs_cell *cell, enum afs_cell_trace reason)
{
- int u;
+ int r;
- if (atomic_read(&cell->ref) <= 0)
- BUG();
-
- u = atomic_inc_return(&cell->ref);
- trace_afs_cell(cell->debug_id, u, atomic_read(&cell->active), reason);
+ __refcount_inc(&cell->ref, &r);
+ trace_afs_cell(cell->debug_id, r + 1, atomic_read(&cell->active), reason);
return cell;
}
{
if (cell) {
unsigned int debug_id = cell->debug_id;
- unsigned int u, a;
+ unsigned int a;
+ bool zero;
+ int r;
a = atomic_read(&cell->active);
- u = atomic_dec_return(&cell->ref);
- trace_afs_cell(debug_id, u, a, reason);
- if (u == 0) {
+ zero = __refcount_dec_and_test(&cell->ref, &r);
+ trace_afs_cell(debug_id, r - 1, a, reason);
+ if (zero) {
a = atomic_read(&cell->active);
WARN(a != 0, "Cell active count %u > 0\n", a);
call_rcu(&cell->rcu, afs_cell_destroy);
*/
struct afs_cell *afs_use_cell(struct afs_cell *cell, enum afs_cell_trace reason)
{
- int u, a;
-
- if (atomic_read(&cell->ref) <= 0)
- BUG();
+ int r, a;
- u = atomic_read(&cell->ref);
+ r = refcount_read(&cell->ref);
+ WARN_ON(r == 0);
a = atomic_inc_return(&cell->active);
- trace_afs_cell(cell->debug_id, u, a, reason);
+ trace_afs_cell(cell->debug_id, r, a, reason);
return cell;
}
{
unsigned int debug_id;
time64_t now, expire_delay;
- int u, a;
+ int r, a;
if (!cell)
return;
expire_delay = afs_cell_gc_delay;
debug_id = cell->debug_id;
- u = atomic_read(&cell->ref);
+ r = refcount_read(&cell->ref);
a = atomic_dec_return(&cell->active);
- trace_afs_cell(debug_id, u, a, reason);
+ trace_afs_cell(debug_id, r, a, reason);
WARN_ON(a == 0);
if (a == 1)
/* 'cell' may now be garbage collected. */
*/
void afs_see_cell(struct afs_cell *cell, enum afs_cell_trace reason)
{
- int u, a;
+ int r, a;
- u = atomic_read(&cell->ref);
+ r = refcount_read(&cell->ref);
a = atomic_read(&cell->active);
- trace_afs_cell(cell->debug_id, u, a, reason);
+ trace_afs_cell(cell->debug_id, r, a, reason);
}
/*
active = 1;
if (atomic_try_cmpxchg_relaxed(&cell->active, &active, 0)) {
rb_erase(&cell->net_node, &net->cells);
- trace_afs_cell(cell->debug_id, atomic_read(&cell->ref), 0,
+ trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), 0,
afs_cell_trace_unuse_delete);
smp_store_release(&cell->state, AFS_CELL_REMOVED);
}
bool sched_cell = false;
active = atomic_read(&cell->active);
- trace_afs_cell(cell->debug_id, atomic_read(&cell->ref),
+ trace_afs_cell(cell->debug_id, refcount_read(&cell->ref),
active, afs_cell_trace_manage);
ASSERTCMP(active, >=, 1);
if (purging) {
if (test_and_clear_bit(AFS_CELL_FL_NO_GC, &cell->flags)) {
active = atomic_dec_return(&cell->active);
- trace_afs_cell(cell->debug_id, atomic_read(&cell->ref),
+ trace_afs_cell(cell->debug_id, refcount_read(&cell->ref),
active, afs_cell_trace_unuse_pin);
}
}
* to maintain cache coherency.
*/
if (call->server) {
- trace_afs_server(call->server,
- atomic_read(&call->server->ref),
+ trace_afs_server(call->server->debug_id,
+ refcount_read(&call->server->ref),
atomic_read(&call->server->active),
afs_server_trace_callback);
afs_break_callbacks(call->server, call->count, call->request);
};
struct afs_operation *op;
unsigned int server_index;
- atomic_t usage;
+ refcount_t ref;
enum afs_call_state state;
spinlock_t state_lock;
int error; /* error code */
struct hlist_node proc_link; /* /proc cell list link */
time64_t dns_expiry; /* Time AFSDB/SRV record expires */
time64_t last_inactive; /* Time of last drop of usage count */
- atomic_t ref; /* Struct refcount */
+ refcount_t ref; /* Struct refcount */
atomic_t active; /* Active usage counter */
unsigned long flags;
#define AFS_CELL_FL_NO_GC 0 /* The cell was added manually, don't auto-gc */
#define AFS_VLSERVER_FL_IS_YFS 2 /* Server is YFS not AFS */
#define AFS_VLSERVER_FL_RESPONDING 3 /* VL server is responding */
rwlock_t lock; /* Lock on addresses */
- atomic_t usage;
+ refcount_t ref;
unsigned int rtt; /* Server's current RTT in uS */
/* Probe state */
struct afs_vlserver_list {
struct rcu_head rcu;
- atomic_t usage;
+ refcount_t ref;
u8 nr_servers;
u8 index; /* Server currently in use */
u8 preferred; /* Preferred server */
#define AFS_SERVER_FL_NO_IBULK 17 /* Fileserver doesn't support FS.InlineBulkStatus */
#define AFS_SERVER_FL_NO_RM2 18 /* Fileserver doesn't support YFS.RemoveFile2 */
#define AFS_SERVER_FL_HAS_FS64 19 /* Fileserver supports FS.{Fetch,Store}Data64 */
- atomic_t ref; /* Object refcount */
+ refcount_t ref; /* Object refcount */
atomic_t active; /* Active user count */
u32 addr_version; /* Address list version */
unsigned int rtt; /* Server's current RTT in uS */
struct rcu_head rcu;
afs_volid_t vid; /* volume ID */
};
- atomic_t usage;
+ refcount_t ref;
time64_t update_at; /* Time at which to next update */
struct afs_cell *cell; /* Cell to which belongs (pins ref) */
struct rb_node cell_node; /* Link in cell->volumes */
*/
static inline struct afs_vlserver *afs_get_vlserver(struct afs_vlserver *vlserver)
{
- atomic_inc(&vlserver->usage);
+ refcount_inc(&vlserver->ref);
return vlserver;
}
static inline struct afs_vlserver_list *afs_get_vlserverlist(struct afs_vlserver_list *vllist)
{
if (vllist)
- atomic_inc(&vllist->usage);
+ refcount_inc(&vllist->ref);
return vllist;
}
/* display one cell per line on subsequent lines */
seq_printf(m, "%3u %3u %6lld %2u %2u %s\n",
- atomic_read(&cell->ref),
+ refcount_read(&cell->ref),
atomic_read(&cell->active),
cell->dns_expiry - ktime_get_real_seconds(),
vllist ? vllist->nr_servers : 0,
}
seq_printf(m, "%3d %08llx %s %s\n",
- atomic_read(&vol->usage), vol->vid,
+ refcount_read(&vol->ref), vol->vid,
afs_vol_types[vol->type],
vol->name);
alist = rcu_dereference(server->addresses);
seq_printf(m, "%pU %3d %3d\n",
&server->uuid,
- atomic_read(&server->ref),
+ refcount_read(&server->ref),
atomic_read(&server->active));
seq_printf(m, " - info: fl=%lx rtt=%u brk=%x\n",
server->flags, server->rtt, server->cb_s_break);
call->type = type;
call->net = net;
call->debug_id = atomic_inc_return(&rxrpc_debug_id);
- atomic_set(&call->usage, 1);
+ refcount_set(&call->ref, 1);
INIT_WORK(&call->async_work, afs_process_async_call);
init_waitqueue_head(&call->waitq);
spin_lock_init(&call->state_lock);
call->iter = &call->def_iter;
o = atomic_inc_return(&net->nr_outstanding_calls);
- trace_afs_call(call, afs_call_trace_alloc, 1, o,
+ trace_afs_call(call->debug_id, afs_call_trace_alloc, 1, o,
__builtin_return_address(0));
return call;
}
void afs_put_call(struct afs_call *call)
{
struct afs_net *net = call->net;
- int n = atomic_dec_return(&call->usage);
- int o = atomic_read(&net->nr_outstanding_calls);
+ unsigned int debug_id = call->debug_id;
+ bool zero;
+ int r, o;
- trace_afs_call(call, afs_call_trace_put, n, o,
+ zero = __refcount_dec_and_test(&call->ref, &r);
+ o = atomic_read(&net->nr_outstanding_calls);
+ trace_afs_call(debug_id, afs_call_trace_put, r - 1, o,
__builtin_return_address(0));
- ASSERTCMP(n, >=, 0);
- if (n == 0) {
+ if (zero) {
ASSERT(!work_pending(&call->async_work));
ASSERT(call->type->name != NULL);
afs_put_addrlist(call->alist);
kfree(call->request);
- trace_afs_call(call, afs_call_trace_free, 0, o,
+ trace_afs_call(call->debug_id, afs_call_trace_free, 0, o,
__builtin_return_address(0));
kfree(call);
static struct afs_call *afs_get_call(struct afs_call *call,
enum afs_call_trace why)
{
- int u = atomic_inc_return(&call->usage);
+ int r;
- trace_afs_call(call, why, u,
+ __refcount_inc(&call->ref, &r);
+
+ trace_afs_call(call->debug_id, why, r + 1,
atomic_read(&call->net->nr_outstanding_calls),
__builtin_return_address(0));
return call;
unsigned long call_user_ID)
{
struct afs_call *call = (struct afs_call *)call_user_ID;
- int u;
+ int r;
trace_afs_notify_call(rxcall, call);
call->need_attention = true;
- u = atomic_fetch_add_unless(&call->usage, 1, 0);
- if (u != 0) {
- trace_afs_call(call, afs_call_trace_wake, u + 1,
+ if (__refcount_inc_not_zero(&call->ref, &r)) {
+ trace_afs_call(call->debug_id, afs_call_trace_wake, r + 1,
atomic_read(&call->net->nr_outstanding_calls),
__builtin_return_address(0));
if (!server)
goto enomem;
- atomic_set(&server->ref, 1);
+ refcount_set(&server->ref, 1);
atomic_set(&server->active, 1);
server->debug_id = atomic_inc_return(&afs_server_debug_id);
RCU_INIT_POINTER(server->addresses, alist);
server->rtt = UINT_MAX;
afs_inc_servers_outstanding(net);
- trace_afs_server(server, 1, 1, afs_server_trace_alloc);
+ trace_afs_server(server->debug_id, 1, 1, afs_server_trace_alloc);
_leave(" = %p", server);
return server;
struct afs_server *afs_get_server(struct afs_server *server,
enum afs_server_trace reason)
{
- unsigned int u = atomic_inc_return(&server->ref);
+ unsigned int a;
+ int r;
- trace_afs_server(server, u, atomic_read(&server->active), reason);
+ __refcount_inc(&server->ref, &r);
+ a = atomic_read(&server->active);
+ trace_afs_server(server->debug_id, r + 1, a, reason);
return server;
}
static struct afs_server *afs_maybe_use_server(struct afs_server *server,
enum afs_server_trace reason)
{
- unsigned int r = atomic_fetch_add_unless(&server->ref, 1, 0);
unsigned int a;
+ int r;
- if (r == 0)
+ if (!__refcount_inc_not_zero(&server->ref, &r))
return NULL;
a = atomic_inc_return(&server->active);
- trace_afs_server(server, r, a, reason);
+ trace_afs_server(server->debug_id, r + 1, a, reason);
return server;
}
*/
struct afs_server *afs_use_server(struct afs_server *server, enum afs_server_trace reason)
{
- unsigned int r = atomic_inc_return(&server->ref);
- unsigned int a = atomic_inc_return(&server->active);
+ unsigned int a;
+ int r;
- trace_afs_server(server, r, a, reason);
+ __refcount_inc(&server->ref, &r);
+ a = atomic_inc_return(&server->active);
+
+ trace_afs_server(server->debug_id, r + 1, a, reason);
return server;
}
void afs_put_server(struct afs_net *net, struct afs_server *server,
enum afs_server_trace reason)
{
- unsigned int usage;
+ unsigned int a, debug_id = server->debug_id;
+ bool zero;
+ int r;
if (!server)
return;
- usage = atomic_dec_return(&server->ref);
- trace_afs_server(server, usage, atomic_read(&server->active), reason);
- if (unlikely(usage == 0))
+ a = atomic_inc_return(&server->active);
+ zero = __refcount_dec_and_test(&server->ref, &r);
+ trace_afs_server(debug_id, r - 1, a, reason);
+ if (unlikely(zero))
__afs_put_server(net, server);
}
{
struct afs_server *server = container_of(rcu, struct afs_server, rcu);
- trace_afs_server(server, atomic_read(&server->ref),
+ trace_afs_server(server->debug_id, refcount_read(&server->ref),
atomic_read(&server->active), afs_server_trace_free);
afs_put_addrlist(rcu_access_pointer(server->addresses));
kfree(server);
active = atomic_read(&server->active);
if (active == 0) {
- trace_afs_server(server, atomic_read(&server->ref),
+ trace_afs_server(server->debug_id, refcount_read(&server->ref),
active, afs_server_trace_gc);
next = rcu_dereference_protected(
server->uuid_next, lockdep_is_held(&net->fs_lock.lock));
_debug("manage %pU %u", &server->uuid, active);
if (purging) {
- trace_afs_server(server, atomic_read(&server->ref),
+ trace_afs_server(server->debug_id, refcount_read(&server->ref),
active, afs_server_trace_purging);
if (active != 0)
pr_notice("Can't purge s=%08x\n", server->debug_id);
_enter("");
- trace_afs_server(server, atomic_read(&server->ref), atomic_read(&server->active),
+ trace_afs_server(server->debug_id, refcount_read(&server->ref),
+ atomic_read(&server->active),
afs_server_trace_update);
alist = afs_vl_lookup_addrs(op->volume->cell, op->key, &server->uuid);
vlserver = kzalloc(struct_size(vlserver, name, name_len + 1),
GFP_KERNEL);
if (vlserver) {
- atomic_set(&vlserver->usage, 1);
+ refcount_set(&vlserver->ref, 1);
rwlock_init(&vlserver->lock);
init_waitqueue_head(&vlserver->probe_wq);
spin_lock_init(&vlserver->probe_lock);
void afs_put_vlserver(struct afs_net *net, struct afs_vlserver *vlserver)
{
- if (vlserver) {
- unsigned int u = atomic_dec_return(&vlserver->usage);
- //_debug("VL PUT %p{%u}", vlserver, u);
-
- if (u == 0)
- call_rcu(&vlserver->rcu, afs_vlserver_rcu);
- }
+ if (vlserver &&
+ refcount_dec_and_test(&vlserver->ref))
+ call_rcu(&vlserver->rcu, afs_vlserver_rcu);
}
struct afs_vlserver_list *afs_alloc_vlserver_list(unsigned int nr_servers)
vllist = kzalloc(struct_size(vllist, servers, nr_servers), GFP_KERNEL);
if (vllist) {
- atomic_set(&vllist->usage, 1);
+ refcount_set(&vllist->ref, 1);
rwlock_init(&vllist->lock);
}
void afs_put_vlserverlist(struct afs_net *net, struct afs_vlserver_list *vllist)
{
if (vllist) {
- unsigned int u = atomic_dec_return(&vllist->usage);
-
- //_debug("VLLS PUT %p{%u}", vllist, u);
- if (u == 0) {
+ if (refcount_dec_and_test(&vllist->ref)) {
int i;
for (i = 0; i < vllist->nr_servers; i++) {
struct afs_cell *cell = volume->cell;
if (!hlist_unhashed(&volume->proc_link)) {
- trace_afs_volume(volume->vid, atomic_read(&volume->usage),
+ trace_afs_volume(volume->vid, refcount_read(&cell->ref),
afs_volume_trace_remove);
write_seqlock(&cell->volume_lock);
hlist_del_rcu(&volume->proc_link);
volume->type_force = params->force;
volume->name_len = vldb->name_len;
- atomic_set(&volume->usage, 1);
+ refcount_set(&volume->ref, 1);
INIT_HLIST_NODE(&volume->proc_link);
rwlock_init(&volume->servers_lock);
rwlock_init(&volume->cb_v_break_lock);
afs_remove_volume_from_cell(volume);
afs_put_serverlist(net, rcu_access_pointer(volume->servers));
afs_put_cell(volume->cell, afs_cell_trace_put_vol);
- trace_afs_volume(volume->vid, atomic_read(&volume->usage),
+ trace_afs_volume(volume->vid, refcount_read(&volume->ref),
afs_volume_trace_free);
kfree_rcu(volume, rcu);
enum afs_volume_trace reason)
{
if (volume) {
- int u = atomic_inc_return(&volume->usage);
- trace_afs_volume(volume->vid, u, reason);
+ int r;
+
+ __refcount_inc(&volume->ref, &r);
+ trace_afs_volume(volume->vid, r + 1, reason);
}
return volume;
}
{
if (volume) {
afs_volid_t vid = volume->vid;
- int u = atomic_dec_return(&volume->usage);
- trace_afs_volume(vid, u, reason);
- if (u == 0)
+ bool zero;
+ int r;
+
+ zero = __refcount_dec_and_test(&volume->ref, &r);
+ trace_afs_volume(vid, r - 1, reason);
+ if (zero)
afs_destroy_volume(net, volume);
}
}
dout("%s: pos=%llu orig_len=%zu len=%llu\n", __func__, subreq->start, subreq->len, len);
iov_iter_xarray(&iter, READ, &rreq->mapping->i_pages, subreq->start, len);
- err = iov_iter_get_pages_alloc(&iter, &pages, len, &page_off);
+ err = iov_iter_get_pages_alloc2(&iter, &pages, len, &page_off);
if (err < 0) {
dout("%s: iov_ter_get_pages_alloc returned %d\n", __func__, err);
goto out;
size_t start;
int idx = 0;
- bytes = iov_iter_get_pages(iter, pages, maxsize - size,
+ bytes = iov_iter_get_pages2(iter, pages, maxsize - size,
ITER_GET_BVECS_PAGES, &start);
if (bytes < 0)
return size ?: bytes;
- iov_iter_advance(iter, bytes);
size += bytes;
for ( ; bytes; idx++, bvec_idx++) {
/* Directories always inherit the setgid bit. */
if (S_ISDIR(mode))
mode |= S_ISGID;
- else if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) &&
- !in_group_p(dir->i_gid) &&
- !capable_wrt_inode_uidgid(&init_user_ns, dir, CAP_FSETID))
- mode &= ~S_ISGID;
} else {
in.gid = cpu_to_le32(from_kgid(&init_user_ns, current_fsgid()));
}
size_t count = iov_iter_count(iter);
loff_t pos = iocb->ki_pos;
bool write = iov_iter_rw(iter) == WRITE;
- bool should_dirty = !write && iter_is_iovec(iter);
+ bool should_dirty = !write && user_backed_iter(iter);
if (write && ceph_snap(file_inode(file)) != CEPH_NOSNAP)
return -EROFS;
if (ctx->direct_io) {
ssize_t result;
- result = iov_iter_get_pages_alloc(
+ result = iov_iter_get_pages_alloc2(
from, &pagevec, cur_len, &start);
if (result < 0) {
cifs_dbg(VFS,
break;
}
cur_len = (size_t)result;
- iov_iter_advance(from, cur_len);
nr_pages =
(cur_len + start + PAGE_SIZE - 1) / PAGE_SIZE;
if (ctx->direct_io) {
ssize_t result;
- result = iov_iter_get_pages_alloc(
+ result = iov_iter_get_pages_alloc2(
&direct_iov, &pagevec,
cur_len, &start);
if (result < 0) {
break;
}
cur_len = (size_t)result;
- iov_iter_advance(&direct_iov, cur_len);
rdata = cifs_readdata_direct_alloc(
pagevec, cifs_uncached_readv_complete);
if (!is_sync_kiocb(iocb))
ctx->iocb = iocb;
- if (iter_is_iovec(to))
+ if (user_backed_iter(to))
ctx->should_dirty = true;
if (direct) {
saved_len = count;
while (count && npages < max_pages) {
- rc = iov_iter_get_pages(iter, pages, count, max_pages, &start);
+ rc = iov_iter_get_pages2(iter, pages, count, max_pages, &start);
if (rc < 0) {
cifs_dbg(VFS, "Couldn't get user pages (rc=%zd)\n", rc);
break;
break;
}
- iov_iter_advance(iter, rc);
count -= rc;
rc += start;
cur_npages = DIV_ROUND_UP(rc, PAGE_SIZE);
const enum req_op dio_op = dio->opf & REQ_OP_MASK;
ssize_t ret;
- ret = iov_iter_get_pages(sdio->iter, dio->pages, LONG_MAX, DIO_PAGES,
+ ret = iov_iter_get_pages2(sdio->iter, dio->pages, LONG_MAX, DIO_PAGES,
&sdio->from);
if (ret < 0 && sdio->blocks_available && dio_op == REQ_OP_WRITE) {
}
if (ret >= 0) {
- iov_iter_advance(sdio->iter, ret);
ret += sdio->from;
sdio->head = 0;
sdio->tail = (ret + PAGE_SIZE - 1) / PAGE_SIZE;
spin_lock_init(&dio->bio_lock);
dio->refcount = 1;
- dio->should_dirty = iter_is_iovec(iter) && iov_iter_rw(iter) == READ;
+ dio->should_dirty = user_backed_iter(iter) && iov_iter_rw(iter) == READ;
sdio.iter = iter;
sdio.final_block_in_request = end >> blkbits;
{
clear_bit(FSCACHE_COOKIE_IS_CACHING, &cookie->flags);
fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_FAILED);
+ trace_fscache_cookie(cookie->debug_id, refcount_read(&cookie->ref),
+ fscache_cookie_failed);
}
EXPORT_SYMBOL(fscache_caching_failed);
fallthrough;
case FSCACHE_COOKIE_STATE_FAILED:
+ if (test_and_clear_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags))
+ fscache_end_cookie_access(cookie, fscache_access_invalidate_cookie_end);
+
if (atomic_read(&cookie->n_accesses) != 0)
break;
if (test_bit(FSCACHE_COOKIE_DO_RELINQUISH, &cookie->flags)) {
return;
case FSCACHE_COOKIE_STATE_LOOKING_UP:
- __fscache_begin_cookie_access(cookie, fscache_access_invalidate_cookie);
- set_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags);
+ if (!test_and_set_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags))
+ __fscache_begin_cookie_access(cookie, fscache_access_invalidate_cookie);
fallthrough;
case FSCACHE_COOKIE_STATE_CREATING:
spin_unlock(&cookie->lock);
}
} else {
size_t off;
- err = iov_iter_get_pages(cs->iter, &page, PAGE_SIZE, 1, &off);
+ err = iov_iter_get_pages2(cs->iter, &page, PAGE_SIZE, 1, &off);
if (err < 0)
return err;
BUG_ON(!err);
cs->len = err;
cs->offset = off;
cs->pg = page;
- iov_iter_advance(cs->iter, err);
}
return lock_request(cs->req);
if (!fud)
return -EPERM;
- if (!iter_is_iovec(to))
+ if (!user_backed_iter(to))
return -EINVAL;
fuse_copy_init(&cs, 1, to);
if (!fud)
return -EPERM;
- if (!iter_is_iovec(from))
+ if (!user_backed_iter(from))
return -EINVAL;
fuse_copy_init(&cs, 0, from);
while (nbytes < *nbytesp && ap->num_pages < max_pages) {
unsigned npages;
size_t start;
- ret = iov_iter_get_pages(ii, &ap->pages[ap->num_pages],
+ ret = iov_iter_get_pages2(ii, &ap->pages[ap->num_pages],
*nbytesp - nbytes,
max_pages - ap->num_pages,
&start);
if (ret < 0)
break;
- iov_iter_advance(ii, ret);
nbytes += ret;
ret += start;
inode_unlock(inode);
}
- io->should_dirty = !write && iter_is_iovec(iter);
+ io->should_dirty = !write && user_backed_iter(iter);
while (count) {
ssize_t nres;
fl_owner_t owner = current->files;
if (!count)
return false;
- if (!iter_is_iovec(i))
+ if (!user_backed_iter(i))
return false;
size = PAGE_SIZE;
}
#endif
-static size_t
-hugetlbfs_read_actor(struct page *page, unsigned long offset,
- struct iov_iter *to, unsigned long size)
-{
- size_t copied = 0;
- int i, chunksize;
-
- /* Find which 4k chunk and offset with in that chunk */
- i = offset >> PAGE_SHIFT;
- offset = offset & ~PAGE_MASK;
-
- while (size) {
- size_t n;
- chunksize = PAGE_SIZE;
- if (offset)
- chunksize -= offset;
- if (chunksize > size)
- chunksize = size;
- n = copy_page_to_iter(&page[i], offset, chunksize, to);
- copied += n;
- if (n != chunksize)
- return copied;
- offset = 0;
- size -= chunksize;
- i++;
- }
- return copied;
-}
-
/*
* Support for read() - Find the page attached to f_mapping and copy out the
* data. This provides functionality similar to filemap_read().
/*
* We have the page, copy it to user space buffer.
*/
- copied = hugetlbfs_read_actor(page, offset, to, nr);
+ copied = copy_page_to_iter(page, offset, nr, to);
put_page(page);
}
offset += copied;
/* Directories are special, and always inherit S_ISGID */
if (S_ISDIR(mode))
mode |= S_ISGID;
- else if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) &&
- !in_group_p(i_gid_into_mnt(mnt_userns, dir)) &&
- !capable_wrt_inode_uidgid(mnt_userns, dir, CAP_FSETID))
- mode &= ~S_ISGID;
} else
inode_fsgid_set(inode, mnt_userns);
inode->i_mode = mode;
return timestamp_truncate(now, inode);
}
EXPORT_SYMBOL(current_time);
+
+/**
+ * mode_strip_sgid - handle the sgid bit for non-directories
+ * @mnt_userns: User namespace of the mount the inode was created from
+ * @dir: parent directory inode
+ * @mode: mode of the file to be created in @dir
+ *
+ * If the @mode of the new file has both the S_ISGID and S_IXGRP bit
+ * raised and @dir has the S_ISGID bit raised ensure that the caller is
+ * either in the group of the parent directory or they have CAP_FSETID
+ * in their user namespace and are privileged over the parent directory.
+ * In all other cases, strip the S_ISGID bit from @mode.
+ *
+ * Return: the new mode to use for the file
+ */
+umode_t mode_strip_sgid(struct user_namespace *mnt_userns,
+ const struct inode *dir, umode_t mode)
+{
+ if ((mode & (S_ISGID | S_IXGRP)) != (S_ISGID | S_IXGRP))
+ return mode;
+ if (S_ISDIR(mode) || !dir || !(dir->i_mode & S_ISGID))
+ return mode;
+ if (in_group_p(i_gid_into_mnt(mnt_userns, dir)))
+ return mode;
+ if (capable_wrt_inode_uidgid(mnt_userns, dir, CAP_FSETID))
+ return mode;
+
+ return mode & ~S_ISGID;
+}
+EXPORT_SYMBOL(mode_strip_sgid);
iomi.flags |= IOMAP_NOWAIT;
}
- if (iter_is_iovec(iter))
+ if (user_backed_iter(iter))
dio->flags |= IOMAP_DIO_DIRTY;
} else {
iomi.flags |= IOMAP_WRITE;
return rc;
}
-static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash,
- char *dname)
+static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+ char *ntlmv2_hash, char *dname)
{
int ret, len, conv_len;
wchar_t *domain = NULL;
}
conv_len = smb_strtoUTF16(uniname, user_name(sess->user), len,
- sess->conn->local_nls);
+ conn->local_nls);
if (conv_len < 0 || conv_len > len) {
ret = -EINVAL;
goto out;
}
conv_len = smb_strtoUTF16((__le16 *)domain, dname, len,
- sess->conn->local_nls);
+ conn->local_nls);
if (conv_len < 0 || conv_len > len) {
ret = -EINVAL;
goto out;
*
* Return: 0 on success, error number on error
*/
-int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
- int blen, char *domain_name, char *cryptkey)
+int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+ struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
+ char *cryptkey)
{
char ntlmv2_hash[CIFS_ENCPWD_SIZE];
char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
return -ENOMEM;
}
- rc = calc_ntlmv2_hash(sess, ntlmv2_hash, domain_name);
+ rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name);
if (rc) {
ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc);
goto out;
/* process NTLMv2 authentication */
ksmbd_debug(AUTH, "decode_ntlmssp_authenticate_blob dname%s\n",
domain_name);
- ret = ksmbd_auth_ntlmv2(sess, (struct ntlmv2_resp *)((char *)authblob + nt_off),
+ ret = ksmbd_auth_ntlmv2(conn, sess,
+ (struct ntlmv2_resp *)((char *)authblob + nt_off),
nt_len - CIFS_ENCPWD_SIZE,
domain_name, conn->ntlmssp.cryptkey);
kfree(domain_name);
bool binding;
};
-static int generate_key(struct ksmbd_session *sess, struct kvec label,
- struct kvec context, __u8 *key, unsigned int key_size)
+static int generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+ struct kvec label, struct kvec context, __u8 *key,
+ unsigned int key_size)
{
unsigned char zero = 0x0;
__u8 i[4] = {0, 0, 0, 1};
goto smb3signkey_ret;
}
- if (sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
- sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
+ if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
+ conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L256, 4);
else
rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L128, 4);
if (!chann)
return 0;
- if (sess->conn->dialect >= SMB30_PROT_ID && signing->binding)
+ if (conn->dialect >= SMB30_PROT_ID && signing->binding)
key = chann->smb3signingkey;
else
key = sess->smb3signingkey;
- rc = generate_key(sess, signing->label, signing->context, key,
+ rc = generate_key(conn, sess, signing->label, signing->context, key,
SMB3_SIGN_KEY_SIZE);
if (rc)
return rc;
- if (!(sess->conn->dialect >= SMB30_PROT_ID && signing->binding))
+ if (!(conn->dialect >= SMB30_PROT_ID && signing->binding))
memcpy(chann->smb3signingkey, key, SMB3_SIGN_KEY_SIZE);
ksmbd_debug(AUTH, "dumping generated AES signing keys\n");
struct derivation decryption;
};
-static int generate_smb3encryptionkey(struct ksmbd_session *sess,
+static int generate_smb3encryptionkey(struct ksmbd_conn *conn,
+ struct ksmbd_session *sess,
const struct derivation_twin *ptwin)
{
int rc;
- rc = generate_key(sess, ptwin->encryption.label,
+ rc = generate_key(conn, sess, ptwin->encryption.label,
ptwin->encryption.context, sess->smb3encryptionkey,
SMB3_ENC_DEC_KEY_SIZE);
if (rc)
return rc;
- rc = generate_key(sess, ptwin->decryption.label,
+ rc = generate_key(conn, sess, ptwin->decryption.label,
ptwin->decryption.context,
sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE);
if (rc)
return rc;
ksmbd_debug(AUTH, "dumping generated AES encryption keys\n");
- ksmbd_debug(AUTH, "Cipher type %d\n", sess->conn->cipher_type);
+ ksmbd_debug(AUTH, "Cipher type %d\n", conn->cipher_type);
ksmbd_debug(AUTH, "Session Id %llu\n", sess->id);
ksmbd_debug(AUTH, "Session Key %*ph\n",
SMB2_NTLMV2_SESSKEY_SIZE, sess->sess_key);
- if (sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
- sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) {
+ if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
+ conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) {
ksmbd_debug(AUTH, "ServerIn Key %*ph\n",
SMB3_GCM256_CRYPTKEY_SIZE, sess->smb3encryptionkey);
ksmbd_debug(AUTH, "ServerOut Key %*ph\n",
return 0;
}
-int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess)
+int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn,
+ struct ksmbd_session *sess)
{
struct derivation_twin twin;
struct derivation *d;
d->context.iov_base = "ServerIn ";
d->context.iov_len = 10;
- return generate_smb3encryptionkey(sess, &twin);
+ return generate_smb3encryptionkey(conn, sess, &twin);
}
-int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess)
+int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn,
+ struct ksmbd_session *sess)
{
struct derivation_twin twin;
struct derivation *d;
d->context.iov_base = sess->Preauth_HashValue;
d->context.iov_len = 64;
- return generate_smb3encryptionkey(sess, &twin);
+ return generate_smb3encryptionkey(conn, sess, &twin);
}
int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
unsigned int nvec, int enc);
void ksmbd_copy_gss_neg_header(void *buf);
-int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
- int blen, char *domain_name, char *cryptkey);
+int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+ struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
+ char *cryptkey);
int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
int blob_len, struct ksmbd_conn *conn,
struct ksmbd_session *sess);
struct ksmbd_conn *conn);
int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess,
struct ksmbd_conn *conn);
-int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess);
-int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess);
+int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn,
+ struct ksmbd_session *sess);
+int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn,
+ struct ksmbd_session *sess);
int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
__u8 *pi_hash);
int ksmbd_gen_sd_hash(struct ksmbd_conn *conn, char *sd_buf, int len,
list_del(&conn->conns_list);
write_unlock(&conn_list_lock);
+ xa_destroy(&conn->sessions);
kvfree(conn->request_buf);
kfree(conn->preauth_info);
kfree(conn);
conn->outstanding_credits = 0;
init_waitqueue_head(&conn->req_running_q);
+ init_waitqueue_head(&conn->r_count_q);
INIT_LIST_HEAD(&conn->conns_list);
- INIT_LIST_HEAD(&conn->sessions);
INIT_LIST_HEAD(&conn->requests);
INIT_LIST_HEAD(&conn->async_requests);
spin_lock_init(&conn->request_lock);
spin_lock_init(&conn->credits_lock);
ida_init(&conn->async_ida);
+ xa_init(&conn->sessions);
spin_lock_init(&conn->llist_lock);
INIT_LIST_HEAD(&conn->lock_list);
struct kvec iov[3];
int iov_idx = 0;
- ksmbd_conn_try_dequeue_request(work);
if (!work->response_buf) {
pr_err("NULL response header\n");
return -EINVAL;
out:
/* Wait till all reference dropped to the Server object*/
- while (atomic_read(&conn->r_count) > 0)
- schedule_timeout(HZ);
+ wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0);
+
unload_nls(conn->local_nls);
if (default_conn_ops.terminate_fn)
#define KSMBD_SOCKET_BACKLOG 16
-/*
- * WARNING
- *
- * This is nothing but a HACK. Session status should move to channel
- * or to session. As of now we have 1 tcp_conn : 1 ksmbd_session, but
- * we need to change it to 1 tcp_conn : N ksmbd_sessions.
- */
enum {
KSMBD_SESS_NEW = 0,
KSMBD_SESS_GOOD,
struct nls_table *local_nls;
struct list_head conns_list;
/* smb session 1 per user */
- struct list_head sessions;
+ struct xarray sessions;
unsigned long last_active;
/* How many request are running currently */
atomic_t req_running;
unsigned int outstanding_credits;
spinlock_t credits_lock;
wait_queue_head_t req_running_q;
+ wait_queue_head_t r_count_q;
/* Lock to protect requests list*/
spinlock_t request_lock;
struct list_head requests;
}
return false;
}
-
-void ksmbd_share_configs_cleanup(void)
-{
- struct ksmbd_share_config *share;
- struct hlist_node *tmp;
- int i;
-
- down_write(&shares_table_lock);
- hash_for_each_safe(shares_table, i, tmp, share, hlist) {
- hash_del(&share->hlist);
- kill_share(share);
- }
- up_write(&shares_table_lock);
-}
struct ksmbd_share_config *ksmbd_share_config_get(char *name);
bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
const char *filename);
-void ksmbd_share_configs_cleanup(void);
-
#endif /* __SHARE_CONFIG_MANAGEMENT_H__ */
#include "user_session.h"
struct ksmbd_tree_conn_status
-ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name)
+ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+ char *share_name)
{
struct ksmbd_tree_conn_status status = {-EINVAL, NULL};
struct ksmbd_tree_connect_response *resp = NULL;
goto out_error;
}
- peer_addr = KSMBD_TCP_PEER_SOCKADDR(sess->conn);
+ peer_addr = KSMBD_TCP_PEER_SOCKADDR(conn);
resp = ksmbd_ipc_tree_connect_request(sess,
sc,
tree_conn,
struct ksmbd_share_config;
struct ksmbd_user;
+struct ksmbd_conn;
struct ksmbd_tree_connect {
int id;
struct ksmbd_session;
struct ksmbd_tree_conn_status
-ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name);
+ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+ char *share_name);
int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
struct ksmbd_tree_connect *tree_conn);
{
struct channel *chann, *tmp;
+ write_lock(&sess->chann_lock);
list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
chann_list) {
list_del(&chann->chann_list);
kfree(chann);
}
+ write_unlock(&sess->chann_lock);
}
static void __session_rpc_close(struct ksmbd_session *sess,
if (!sess)
return;
- if (!atomic_dec_and_test(&sess->refcnt))
- return;
-
- list_del(&sess->sessions_entry);
-
down_write(&sessions_table_lock);
hash_del(&sess->hlist);
up_write(&sessions_table_lock);
return NULL;
}
-void ksmbd_session_register(struct ksmbd_conn *conn,
- struct ksmbd_session *sess)
+int ksmbd_session_register(struct ksmbd_conn *conn,
+ struct ksmbd_session *sess)
{
- sess->conn = conn;
- list_add(&sess->sessions_entry, &conn->sessions);
+ sess->dialect = conn->dialect;
+ memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
+ return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL));
}
-void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
+static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
{
- struct ksmbd_session *sess;
-
- while (!list_empty(&conn->sessions)) {
- sess = list_entry(conn->sessions.next,
- struct ksmbd_session,
- sessions_entry);
+ struct channel *chann, *tmp;
- ksmbd_session_destroy(sess);
+ write_lock(&sess->chann_lock);
+ list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
+ chann_list) {
+ if (chann->conn == conn) {
+ list_del(&chann->chann_list);
+ kfree(chann);
+ write_unlock(&sess->chann_lock);
+ return 0;
+ }
}
-}
+ write_unlock(&sess->chann_lock);
-static bool ksmbd_session_id_match(struct ksmbd_session *sess,
- unsigned long long id)
-{
- return sess->id == id;
+ return -ENOENT;
}
-struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
- unsigned long long id)
+void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
{
- struct ksmbd_session *sess = NULL;
+ struct ksmbd_session *sess;
- list_for_each_entry(sess, &conn->sessions, sessions_entry) {
- if (ksmbd_session_id_match(sess, id))
- return sess;
+ if (conn->binding) {
+ int bkt;
+
+ down_write(&sessions_table_lock);
+ hash_for_each(sessions_table, bkt, sess, hlist) {
+ if (!ksmbd_chann_del(conn, sess)) {
+ up_write(&sessions_table_lock);
+ goto sess_destroy;
+ }
+ }
+ up_write(&sessions_table_lock);
+ } else {
+ unsigned long id;
+
+ xa_for_each(&conn->sessions, id, sess) {
+ if (!ksmbd_chann_del(conn, sess))
+ goto sess_destroy;
+ }
}
- return NULL;
-}
-int get_session(struct ksmbd_session *sess)
-{
- return atomic_inc_not_zero(&sess->refcnt);
+ return;
+
+sess_destroy:
+ if (list_empty(&sess->ksmbd_chann_list)) {
+ xa_erase(&conn->sessions, sess->id);
+ ksmbd_session_destroy(sess);
+ }
}
-void put_session(struct ksmbd_session *sess)
+struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
+ unsigned long long id)
{
- if (atomic_dec_and_test(&sess->refcnt))
- pr_err("get/%s seems to be mismatched.", __func__);
+ return xa_load(&conn->sessions, id);
}
struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
down_read(&sessions_table_lock);
sess = __session_lookup(id);
- if (sess) {
- if (!get_session(sess))
- sess = NULL;
- }
up_read(&sessions_table_lock);
return sess;
sess = ksmbd_session_lookup(conn, id);
if (!sess && conn->binding)
sess = ksmbd_session_lookup_slowpath(id);
+ if (sess && sess->state != SMB2_SESSION_VALID)
+ sess = NULL;
return sess;
}
goto error;
set_session_flag(sess, protocol);
- INIT_LIST_HEAD(&sess->sessions_entry);
xa_init(&sess->tree_conns);
INIT_LIST_HEAD(&sess->ksmbd_chann_list);
INIT_LIST_HEAD(&sess->rpc_handle_list);
sess->sequence_number = 1;
- atomic_set(&sess->refcnt, 1);
+ rwlock_init(&sess->chann_lock);
switch (protocol) {
case CIFDS_SESSION_FLAG_SMB2:
struct ksmbd_session {
u64 id;
+ __u16 dialect;
+ char ClientGUID[SMB2_CLIENT_GUID_SIZE];
+
struct ksmbd_user *user;
- struct ksmbd_conn *conn;
unsigned int sequence_number;
unsigned int flags;
char sess_key[CIFS_KEY_SIZE];
struct hlist_node hlist;
+ rwlock_t chann_lock;
struct list_head ksmbd_chann_list;
struct xarray tree_conns;
struct ida tree_conn_ida;
__u8 smb3decryptionkey[SMB3_ENC_DEC_KEY_SIZE];
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
- struct list_head sessions_entry;
struct ksmbd_file_table file_table;
- atomic_t refcnt;
};
static inline int test_session_flag(struct ksmbd_session *sess, int bit)
struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id);
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
unsigned long long id);
-void ksmbd_session_register(struct ksmbd_conn *conn,
- struct ksmbd_session *sess);
+int ksmbd_session_register(struct ksmbd_conn *conn,
+ struct ksmbd_session *sess);
void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
unsigned long long id);
int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name);
void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id);
int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id);
-int get_session(struct ksmbd_session *sess);
-void put_session(struct ksmbd_session *sess);
#endif /* __USER_SESSION_MANAGEMENT_H__ */
static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
u64 id, __u16 Tid)
{
+ struct ksmbd_conn *conn = work->conn;
struct ksmbd_session *sess = work->sess;
struct oplock_info *opinfo;
return NULL;
opinfo->sess = sess;
- opinfo->conn = sess->conn;
+ opinfo->conn = conn;
opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
opinfo->op_state = OPLOCK_STATE_NONE;
opinfo->pending_break = 0;
struct ksmbd_file *fp;
fp = ksmbd_lookup_durable_fd(br_info->fid);
- if (!fp) {
- atomic_dec(&conn->r_count);
- ksmbd_free_work_struct(work);
- return;
- }
+ if (!fp)
+ goto out;
if (allocate_oplock_break_buf(work)) {
pr_err("smb2_allocate_rsp_buf failed! ");
- atomic_dec(&conn->r_count);
ksmbd_fd_put(work, fp);
- ksmbd_free_work_struct(work);
- return;
+ goto out;
}
rsp_hdr = smb2_get_msg(work->response_buf);
ksmbd_fd_put(work, fp);
ksmbd_conn_write(work);
+
+out:
ksmbd_free_work_struct(work);
- atomic_dec(&conn->r_count);
+ /*
+ * Checking waitqueue to dropping pending requests on
+ * disconnection. waitqueue_active is safe because it
+ * uses atomic operation for condition.
+ */
+ if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
+ wake_up(&conn->r_count_q);
}
/**
if (allocate_oplock_break_buf(work)) {
ksmbd_debug(OPLOCK, "smb2_allocate_rsp_buf failed! ");
- ksmbd_free_work_struct(work);
- atomic_dec(&conn->r_count);
- return;
+ goto out;
}
rsp_hdr = smb2_get_msg(work->response_buf);
inc_rfc1001_len(work->response_buf, 44);
ksmbd_conn_write(work);
+
+out:
ksmbd_free_work_struct(work);
- atomic_dec(&conn->r_count);
+ /*
+ * Checking waitqueue to dropping pending requests on
+ * disconnection. waitqueue_active is safe because it
+ * uses atomic operation for condition.
+ */
+ if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
+ wake_up(&conn->r_count_q);
}
/**
}
list_for_each_entry(lb, &lease_table_list, l_entry) {
- if (!memcmp(lb->client_guid, sess->conn->ClientGUID,
+ if (!memcmp(lb->client_guid, sess->ClientGUID,
SMB2_CLIENT_GUID_SIZE))
goto found;
}
rcu_read_unlock();
if (opinfo->o_fp->f_ci == ci)
goto op_next;
- err = compare_guid_key(opinfo, sess->conn->ClientGUID,
+ err = compare_guid_key(opinfo, sess->ClientGUID,
lctx->lease_key);
if (err) {
err = -EINVAL;
struct oplock_info *m_opinfo;
/* is lease already granted ? */
- m_opinfo = same_client_has_lease(ci, sess->conn->ClientGUID,
+ m_opinfo = same_client_has_lease(ci, sess->ClientGUID,
lctx);
if (m_opinfo) {
copy_lease(m_opinfo, opinfo);
{
struct oplock_info *op, *brk_op;
struct ksmbd_inode *ci;
- struct ksmbd_conn *conn = work->sess->conn;
+ struct ksmbd_conn *conn = work->conn;
if (!test_share_config_flag(work->tcon->share_conf,
KSMBD_SHARE_FLAG_OPLOCKS))
ksmbd_conn_try_dequeue_request(work);
ksmbd_free_work_struct(work);
- atomic_dec(&conn->r_count);
+ /*
+ * Checking waitqueue to dropping pending requests on
+ * disconnection. waitqueue_active is safe because it
+ * uses atomic operation for condition.
+ */
+ if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
+ wake_up(&conn->r_count_q);
}
/**
*off = 0;
*len = 0;
- /* error reqeusts do not have data area */
- if (hdr->Status && hdr->Status != STATUS_MORE_PROCESSING_REQUIRED &&
- (((struct smb2_err_rsp *)hdr)->StructureSize) == SMB2_ERROR_STRUCTURE_SIZE2_LE)
- return ret;
-
/*
* Following commands have data areas so we have to get the location
* of the data buffer offset and data buffer length for the particular
*len = le16_to_cpu(((struct smb2_read_req *)hdr)->ReadChannelInfoLength);
break;
case SMB2_WRITE:
- if (((struct smb2_write_req *)hdr)->DataOffset) {
- *off = le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset);
+ if (((struct smb2_write_req *)hdr)->DataOffset ||
+ ((struct smb2_write_req *)hdr)->Length) {
+ *off = max_t(unsigned int,
+ le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset),
+ offsetof(struct smb2_write_req, Buffer));
*len = le32_to_cpu(((struct smb2_write_req *)hdr)->Length);
break;
}
struct smb2_query_info_req *req;
req = smb2_get_msg(work->request_buf);
- if (req->InfoType == SMB2_O_INFO_FILE &&
- (req->FileInfoClass == FILE_FULL_EA_INFORMATION ||
- req->FileInfoClass == FILE_ALL_INFORMATION))
+ if ((req->InfoType == SMB2_O_INFO_FILE &&
+ (req->FileInfoClass == FILE_FULL_EA_INFORMATION ||
+ req->FileInfoClass == FILE_ALL_INFORMATION)) ||
+ req->InfoType == SMB2_O_INFO_SECURITY)
sz = large_sz;
}
return -EINVAL;
}
-static void destroy_previous_session(struct ksmbd_user *user, u64 id)
+static void destroy_previous_session(struct ksmbd_conn *conn,
+ struct ksmbd_user *user, u64 id)
{
struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id);
struct ksmbd_user *prev_user;
+ struct channel *chann;
if (!prev_sess)
return;
if (!prev_user ||
strcmp(user->name, prev_user->name) ||
user->passkey_sz != prev_user->passkey_sz ||
- memcmp(user->passkey, prev_user->passkey, user->passkey_sz)) {
- put_session(prev_sess);
+ memcmp(user->passkey, prev_user->passkey, user->passkey_sz))
return;
- }
- put_session(prev_sess);
- ksmbd_session_destroy(prev_sess);
+ prev_sess->state = SMB2_SESSION_EXPIRED;
+ write_lock(&prev_sess->chann_lock);
+ list_for_each_entry(chann, &prev_sess->ksmbd_chann_list, chann_list)
+ chann->conn->status = KSMBD_SESS_EXITING;
+ write_unlock(&prev_sess->chann_lock);
}
/**
status);
rsp->hdr.Status = status;
rc = -EINVAL;
+ kfree(conn->preauth_info);
+ conn->preauth_info = NULL;
goto err_out;
}
rc = init_smb3_11_server(conn);
if (rc < 0) {
rsp->hdr.Status = STATUS_INVALID_PARAMETER;
+ kfree(conn->preauth_info);
+ conn->preauth_info = NULL;
goto err_out;
}
/* Check for previous session */
prev_id = le64_to_cpu(req->PreviousSessionId);
if (prev_id && prev_id != sess->id)
- destroy_previous_session(user, prev_id);
+ destroy_previous_session(conn, user, prev_id);
if (sess->state == SMB2_SESSION_VALID) {
/*
if (smb3_encryption_negotiated(conn) &&
!(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
- rc = conn->ops->generate_encryptionkey(sess);
+ rc = conn->ops->generate_encryptionkey(conn, sess);
if (rc) {
ksmbd_debug(SMB,
"SMB3 encryption key generation failed\n");
binding_session:
if (conn->dialect >= SMB30_PROT_ID) {
+ read_lock(&sess->chann_lock);
chann = lookup_chann_list(sess, conn);
+ read_unlock(&sess->chann_lock);
if (!chann) {
chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
if (!chann)
chann->conn = conn;
INIT_LIST_HEAD(&chann->chann_list);
+ write_lock(&sess->chann_lock);
list_add(&chann->chann_list, &sess->ksmbd_chann_list);
+ write_unlock(&sess->chann_lock);
}
}
/* Check previous session */
prev_sess_id = le64_to_cpu(req->PreviousSessionId);
if (prev_sess_id && prev_sess_id != sess->id)
- destroy_previous_session(sess->user, prev_sess_id);
+ destroy_previous_session(conn, sess->user, prev_sess_id);
if (sess->state == SMB2_SESSION_VALID)
ksmbd_free_user(sess->user);
sess->sign = true;
if (smb3_encryption_negotiated(conn)) {
- retval = conn->ops->generate_encryptionkey(sess);
+ retval = conn->ops->generate_encryptionkey(conn, sess);
if (retval) {
ksmbd_debug(SMB,
"SMB3 encryption key generation failed\n");
}
if (conn->dialect >= SMB30_PROT_ID) {
+ read_lock(&sess->chann_lock);
chann = lookup_chann_list(sess, conn);
+ read_unlock(&sess->chann_lock);
if (!chann) {
chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
if (!chann)
chann->conn = conn;
INIT_LIST_HEAD(&chann->chann_list);
+ write_lock(&sess->chann_lock);
list_add(&chann->chann_list, &sess->ksmbd_chann_list);
+ write_unlock(&sess->chann_lock);
}
}
goto out_err;
}
rsp->hdr.SessionId = cpu_to_le64(sess->id);
- ksmbd_session_register(conn, sess);
+ rc = ksmbd_session_register(conn, sess);
+ if (rc)
+ goto out_err;
} else if (conn->dialect >= SMB30_PROT_ID &&
(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
req->Flags & SMB2_SESSION_REQ_FLAG_BINDING) {
goto out_err;
}
- if (conn->dialect != sess->conn->dialect) {
+ if (conn->dialect != sess->dialect) {
rc = -EINVAL;
goto out_err;
}
goto out_err;
}
- if (strncmp(conn->ClientGUID, sess->conn->ClientGUID,
+ if (strncmp(conn->ClientGUID, sess->ClientGUID,
SMB2_CLIENT_GUID_SIZE)) {
rc = -ENOENT;
goto out_err;
if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION)
try_delay = true;
+ xa_erase(&conn->sessions, sess->id);
ksmbd_session_destroy(sess);
work->sess = NULL;
if (try_delay)
ksmbd_debug(SMB, "tree connect request for tree %s treename %s\n",
name, treename);
- status = ksmbd_tree_conn_connect(sess, name);
+ status = ksmbd_tree_conn_connect(conn, sess, name);
if (status.ret == KSMBD_TREE_CONN_STATUS_OK)
rsp->hdr.Id.SyncId.TreeId = cpu_to_le32(status.tree_conn->id);
else
ksmbd_close_tree_conn_fds(work);
ksmbd_tree_conn_disconnect(sess, tcon);
+ work->tcon = NULL;
return 0;
}
goto err_out;
rc = build_sec_desc(user_ns,
- pntsd, NULL,
+ pntsd, NULL, 0,
OWNER_SECINFO |
GROUP_SECINFO |
DACL_SECINFO,
return 0;
}
+static int smb2_resp_buf_len(struct ksmbd_work *work, unsigned short hdr2_len)
+{
+ int free_len;
+
+ free_len = (int)(work->response_sz -
+ (get_rfc1002_len(work->response_buf) + 4)) - hdr2_len;
+ return free_len;
+}
+
static int smb2_calc_max_out_buf_len(struct ksmbd_work *work,
unsigned short hdr2_len,
unsigned int out_buf_len)
if (out_buf_len > work->conn->vals->max_trans_size)
return -EINVAL;
- free_len = (int)(work->response_sz -
- (get_rfc1002_len(work->response_buf) + 4)) -
- hdr2_len;
+ free_len = smb2_resp_buf_len(work, hdr2_len);
if (free_len < 0)
return -EINVAL;
struct smb2_query_info_rsp *rsp)
{
struct ksmbd_session *sess = work->sess;
- struct ksmbd_conn *conn = sess->conn;
+ struct ksmbd_conn *conn = work->conn;
struct ksmbd_share_config *share = work->tcon->share_conf;
int fsinfoclass = 0;
struct kstatfs stfs;
struct smb_ntsd *pntsd = (struct smb_ntsd *)rsp->Buffer, *ppntsd = NULL;
struct smb_fattr fattr = {{0}};
struct inode *inode;
- __u32 secdesclen;
+ __u32 secdesclen = 0;
unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
int addition_info = le32_to_cpu(req->AdditionalInformation);
- int rc;
+ int rc = 0, ppntsd_size = 0;
if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO |
PROTECTED_DACL_SECINFO |
if (test_share_config_flag(work->tcon->share_conf,
KSMBD_SHARE_FLAG_ACL_XATTR))
- ksmbd_vfs_get_sd_xattr(work->conn, user_ns,
- fp->filp->f_path.dentry, &ppntsd);
-
- rc = build_sec_desc(user_ns, pntsd, ppntsd, addition_info,
- &secdesclen, &fattr);
+ ppntsd_size = ksmbd_vfs_get_sd_xattr(work->conn, user_ns,
+ fp->filp->f_path.dentry,
+ &ppntsd);
+
+ /* Check if sd buffer size exceeds response buffer size */
+ if (smb2_resp_buf_len(work, 8) > ppntsd_size)
+ rc = build_sec_desc(user_ns, pntsd, ppntsd, ppntsd_size,
+ addition_info, &secdesclen, &fattr);
posix_acl_release(fattr.cf_acls);
posix_acl_release(fattr.cf_dacls);
kfree(ppntsd);
}
next:
return smb2_rename(work, fp, user_ns, rename_info,
- work->sess->conn->local_nls);
+ work->conn->local_nls);
}
static int set_file_disposition_info(struct ksmbd_file *fp,
return smb2_create_link(work, work->tcon->share_conf,
(struct smb2_file_link_info *)req->Buffer,
buf_len, fp->filp,
- work->sess->conn->local_nls);
+ work->conn->local_nls);
}
case FILE_DISPOSITION_INFORMATION:
{
writethrough = true;
if (is_rdma_channel == false) {
- if ((u64)le16_to_cpu(req->DataOffset) + length >
- get_rfc1002_len(work->request_buf)) {
- pr_err("invalid write data offset %u, smb_len %u\n",
- le16_to_cpu(req->DataOffset),
- get_rfc1002_len(work->request_buf));
+ if (le16_to_cpu(req->DataOffset) <
+ offsetof(struct smb2_write_req, Buffer)) {
err = -EINVAL;
goto out;
}
+
data_buf = (char *)(((char *)&req->hdr.ProtocolId) +
le16_to_cpu(req->DataOffset));
if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
signing_key = work->sess->smb3signingkey;
} else {
+ read_lock(&work->sess->chann_lock);
chann = lookup_chann_list(work->sess, conn);
- if (!chann)
+ if (!chann) {
+ read_unlock(&work->sess->chann_lock);
return 0;
+ }
signing_key = chann->smb3signingkey;
+ read_unlock(&work->sess->chann_lock);
}
if (!signing_key) {
le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
signing_key = work->sess->smb3signingkey;
} else {
+ read_lock(&work->sess->chann_lock);
chann = lookup_chann_list(work->sess, work->conn);
- if (!chann)
+ if (!chann) {
+ read_unlock(&work->sess->chann_lock);
return;
+ }
signing_key = chann->smb3signingkey;
+ read_unlock(&work->sess->chann_lock);
}
if (!signing_key)
int (*check_sign_req)(struct ksmbd_work *work);
void (*set_sign_rsp)(struct ksmbd_work *work);
int (*generate_signingkey)(struct ksmbd_session *sess, struct ksmbd_conn *conn);
- int (*generate_encryptionkey)(struct ksmbd_session *sess);
+ int (*generate_encryptionkey)(struct ksmbd_conn *conn, struct ksmbd_session *sess);
bool (*is_transform_hdr)(void *buf);
int (*decrypt_req)(struct ksmbd_work *work);
int (*encrypt_resp)(struct ksmbd_work *work);
static void set_ntacl_dacl(struct user_namespace *user_ns,
struct smb_acl *pndacl,
struct smb_acl *nt_dacl,
+ unsigned int aces_size,
const struct smb_sid *pownersid,
const struct smb_sid *pgrpsid,
struct smb_fattr *fattr)
if (nt_num_aces) {
ntace = (struct smb_ace *)((char *)nt_dacl + sizeof(struct smb_acl));
for (i = 0; i < nt_num_aces; i++) {
- memcpy((char *)pndace + size, ntace, le16_to_cpu(ntace->size));
- size += le16_to_cpu(ntace->size);
- ntace = (struct smb_ace *)((char *)ntace + le16_to_cpu(ntace->size));
+ unsigned short nt_ace_size;
+
+ if (offsetof(struct smb_ace, access_req) > aces_size)
+ break;
+
+ nt_ace_size = le16_to_cpu(ntace->size);
+ if (nt_ace_size > aces_size)
+ break;
+
+ memcpy((char *)pndace + size, ntace, nt_ace_size);
+ size += nt_ace_size;
+ aces_size -= nt_ace_size;
+ ntace = (struct smb_ace *)((char *)ntace + nt_ace_size);
num_aces++;
}
}
/* Convert permission bits from mode to equivalent CIFS ACL */
int build_sec_desc(struct user_namespace *user_ns,
struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd,
- int addition_info, __u32 *secdesclen,
+ int ppntsd_size, int addition_info, __u32 *secdesclen,
struct smb_fattr *fattr)
{
int rc = 0;
if (!ppntsd) {
set_mode_dacl(user_ns, dacl_ptr, fattr);
- } else if (!ppntsd->dacloffset) {
- goto out;
} else {
struct smb_acl *ppdacl_ptr;
+ unsigned int dacl_offset = le32_to_cpu(ppntsd->dacloffset);
+ int ppdacl_size, ntacl_size = ppntsd_size - dacl_offset;
+
+ if (!dacl_offset ||
+ (dacl_offset + sizeof(struct smb_acl) > ppntsd_size))
+ goto out;
+
+ ppdacl_ptr = (struct smb_acl *)((char *)ppntsd + dacl_offset);
+ ppdacl_size = le16_to_cpu(ppdacl_ptr->size);
+ if (ppdacl_size > ntacl_size ||
+ ppdacl_size < sizeof(struct smb_acl))
+ goto out;
- ppdacl_ptr = (struct smb_acl *)((char *)ppntsd +
- le32_to_cpu(ppntsd->dacloffset));
set_ntacl_dacl(user_ns, dacl_ptr, ppdacl_ptr,
- nowner_sid_ptr, ngroup_sid_ptr, fattr);
+ ntacl_size - sizeof(struct smb_acl),
+ nowner_sid_ptr, ngroup_sid_ptr,
+ fattr);
}
pntsd->dacloffset = cpu_to_le32(offset);
offset += le16_to_cpu(dacl_ptr->size);
struct smb_sid owner_sid, group_sid;
struct dentry *parent = path->dentry->d_parent;
struct user_namespace *user_ns = mnt_user_ns(path->mnt);
- int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0;
- int rc = 0, num_aces, dacloffset, pntsd_type, acl_len;
+ int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0, pdacl_size;
+ int rc = 0, num_aces, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size;
char *aces_base;
bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode);
- acl_len = ksmbd_vfs_get_sd_xattr(conn, user_ns,
- parent, &parent_pntsd);
- if (acl_len <= 0)
+ pntsd_size = ksmbd_vfs_get_sd_xattr(conn, user_ns,
+ parent, &parent_pntsd);
+ if (pntsd_size <= 0)
return -ENOENT;
dacloffset = le32_to_cpu(parent_pntsd->dacloffset);
- if (!dacloffset) {
+ if (!dacloffset || (dacloffset + sizeof(struct smb_acl) > pntsd_size)) {
rc = -EINVAL;
goto free_parent_pntsd;
}
parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset);
+ acl_len = pntsd_size - dacloffset;
num_aces = le32_to_cpu(parent_pdacl->num_aces);
pntsd_type = le16_to_cpu(parent_pntsd->type);
+ pdacl_size = le16_to_cpu(parent_pdacl->size);
+
+ if (pdacl_size > acl_len || pdacl_size < sizeof(struct smb_acl)) {
+ rc = -EINVAL;
+ goto free_parent_pntsd;
+ }
aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, GFP_KERNEL);
if (!aces_base) {
aces = (struct smb_ace *)aces_base;
parent_aces = (struct smb_ace *)((char *)parent_pdacl +
sizeof(struct smb_acl));
+ aces_size = acl_len - sizeof(struct smb_acl);
if (pntsd_type & DACL_AUTO_INHERITED)
inherited_flags = INHERITED_ACE;
for (i = 0; i < num_aces; i++) {
+ int pace_size;
+
+ if (offsetof(struct smb_ace, access_req) > aces_size)
+ break;
+
+ pace_size = le16_to_cpu(parent_aces->size);
+ if (pace_size > aces_size)
+ break;
+
+ aces_size -= pace_size;
+
flags = parent_aces->flags;
if (!smb_inherit_flags(flags, is_dir))
goto pass;
aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces->size));
ace_cnt++;
pass:
- parent_aces =
- (struct smb_ace *)((char *)parent_aces + le16_to_cpu(parent_aces->size));
+ parent_aces = (struct smb_ace *)((char *)parent_aces + pace_size);
}
if (nt_size > 0) {
struct smb_ntsd *pntsd = NULL;
struct smb_acl *pdacl;
struct posix_acl *posix_acls;
- int rc = 0, acl_size;
+ int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size, dacl_offset;
struct smb_sid sid;
int granted = le32_to_cpu(*pdaccess & ~FILE_MAXIMAL_ACCESS_LE);
struct smb_ace *ace;
struct smb_ace *others_ace = NULL;
struct posix_acl_entry *pa_entry;
unsigned int sid_type = SIDOWNER;
- char *end_of_acl;
+ unsigned short ace_size;
ksmbd_debug(SMB, "check permission using windows acl\n");
- acl_size = ksmbd_vfs_get_sd_xattr(conn, user_ns,
- path->dentry, &pntsd);
- if (acl_size <= 0 || !pntsd || !pntsd->dacloffset) {
- kfree(pntsd);
- return 0;
- }
+ pntsd_size = ksmbd_vfs_get_sd_xattr(conn, user_ns,
+ path->dentry, &pntsd);
+ if (pntsd_size <= 0 || !pntsd)
+ goto err_out;
+
+ dacl_offset = le32_to_cpu(pntsd->dacloffset);
+ if (!dacl_offset ||
+ (dacl_offset + sizeof(struct smb_acl) > pntsd_size))
+ goto err_out;
pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset));
- end_of_acl = ((char *)pntsd) + acl_size;
- if (end_of_acl <= (char *)pdacl) {
- kfree(pntsd);
- return 0;
- }
+ acl_size = pntsd_size - dacl_offset;
+ pdacl_size = le16_to_cpu(pdacl->size);
- if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size) ||
- le16_to_cpu(pdacl->size) < sizeof(struct smb_acl)) {
- kfree(pntsd);
- return 0;
- }
+ if (pdacl_size > acl_size || pdacl_size < sizeof(struct smb_acl))
+ goto err_out;
if (!pdacl->num_aces) {
- if (!(le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) &&
+ if (!(pdacl_size - sizeof(struct smb_acl)) &&
*pdaccess & ~(FILE_READ_CONTROL_LE | FILE_WRITE_DAC_LE)) {
rc = -EACCES;
goto err_out;
}
- kfree(pntsd);
- return 0;
+ goto err_out;
}
if (*pdaccess & FILE_MAXIMAL_ACCESS_LE) {
DELETE;
ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
+ aces_size = acl_size - sizeof(struct smb_acl);
for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) {
+ if (offsetof(struct smb_ace, access_req) > aces_size)
+ break;
+ ace_size = le16_to_cpu(ace->size);
+ if (ace_size > aces_size)
+ break;
+ aces_size -= ace_size;
granted |= le32_to_cpu(ace->access_req);
ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size));
- if (end_of_acl < (char *)ace)
- goto err_out;
}
if (!pdacl->num_aces)
id_to_sid(uid, sid_type, &sid);
ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
+ aces_size = acl_size - sizeof(struct smb_acl);
for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) {
+ if (offsetof(struct smb_ace, access_req) > aces_size)
+ break;
+ ace_size = le16_to_cpu(ace->size);
+ if (ace_size > aces_size)
+ break;
+ aces_size -= ace_size;
+
if (!compare_sids(&sid, &ace->sid) ||
!compare_sids(&sid_unix_NFS_mode, &ace->sid)) {
found = 1;
others_ace = ace;
ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size));
- if (end_of_acl < (char *)ace)
- goto err_out;
}
if (*pdaccess & FILE_MAXIMAL_ACCESS_LE && found) {
int parse_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd,
int acl_len, struct smb_fattr *fattr);
int build_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd,
- struct smb_ntsd *ppntsd, int addition_info,
+ struct smb_ntsd *ppntsd, int ppntsd_size, int addition_info,
__u32 *secdesclen, struct smb_fattr *fattr);
int init_acl_state(struct posix_acl_state *state, int cnt);
void free_acl_state(struct posix_acl_state *state);
char *buf, size_t count, loff_t *pos, bool sync,
ssize_t *written)
{
- struct ksmbd_session *sess = work->sess;
struct file *filp;
loff_t offset = *pos;
int err = 0;
- if (sess->conn->connection_type) {
+ if (work->conn->connection_type) {
if (!(fp->daccess & FILE_WRITE_DATA_LE)) {
pr_err("no right to write(%pd)\n",
fp->filp->f_path.dentry);
}
*pntsd = acl.sd_buf;
+ if (acl.sd_size < sizeof(struct smb_ntsd)) {
+ pr_err("sd size is invalid\n");
+ goto out_free;
+ }
+
(*pntsd)->osidoffset = cpu_to_le32(le32_to_cpu((*pntsd)->osidoffset) -
NDR_NTSD_OFFSETOF);
(*pntsd)->gsidoffset = cpu_to_le32(le32_to_cpu((*pntsd)->gsidoffset) -
atomic_set(&fp->refcount, 1);
fp->filp = filp;
- fp->conn = work->sess->conn;
+ fp->conn = work->conn;
fp->tcon = work->tcon;
fp->volatile_id = KSMBD_NO_FID;
fp->persistent_id = KSMBD_NO_FID;
if (!nlmsvc_ops)
return nlm_lck_denied_nolocks;
+ if (lock->lock_start > OFFSET_MAX ||
+ (lock->lock_len && ((lock->lock_len - 1) > (OFFSET_MAX - lock->lock_start))))
+ return nlm4_fbig;
+
/* Obtain host handle */
if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
|| (argp->monitor && nsm_monitor(host) < 0))
/* Set up the missing parts of the file_lock structure */
lock->fl.fl_file = file->f_file[mode];
lock->fl.fl_pid = current->tgid;
+ lock->fl.fl_start = (loff_t)lock->lock_start;
+ lock->fl.fl_end = lock->lock_len ?
+ (loff_t)(lock->lock_start + lock->lock_len - 1) :
+ OFFSET_MAX;
lock->fl.fl_lmops = &nlmsvc_lock_operations;
nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid);
if (!lock->fl.fl_owner) {
struct nlm_args *argp = rqstp->rq_argp;
struct nlm_host *host;
struct nlm_file *file;
+ struct nlm_lockowner *test_owner;
__be32 rc = rpc_success;
dprintk("lockd: TEST4 called\n");
if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+ test_owner = argp->lock.fl.fl_owner;
/* Now check for conflicting locks */
resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie);
if (resp->status == nlm_drop_reply)
else
dprintk("lockd: TEST4 status %d\n", ntohl(resp->status));
- nlmsvc_release_lockowner(&argp->lock);
+ nlmsvc_put_lockowner(test_owner);
nlmsvc_release_host(host);
nlm_release_file(file);
return rc;
return lockowner;
}
-static void nlmsvc_put_lockowner(struct nlm_lockowner *lockowner)
+void nlmsvc_put_lockowner(struct nlm_lockowner *lockowner)
{
if (!refcount_dec_and_lock(&lockowner->count, &lockowner->host->h_lock))
return;
int error;
int mode;
__be32 ret;
- struct nlm_lockowner *test_owner;
dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
nlmsvc_file_inode(file)->i_sb->s_id,
goto out;
}
- /* If there's a conflicting lock, remember to clean up the test lock */
- test_owner = (struct nlm_lockowner *)lock->fl.fl_owner;
-
mode = lock_to_openmode(&lock->fl);
error = vfs_test_lock(file->f_file[mode], &lock->fl);
if (error) {
conflock->fl.fl_end = lock->fl.fl_end;
locks_release_private(&lock->fl);
- /* Clean up the test lock */
- lock->fl.fl_owner = NULL;
- nlmsvc_put_lockowner(test_owner);
-
ret = nlm_lck_denied;
out:
return ret;
struct nlm_args *argp = rqstp->rq_argp;
struct nlm_host *host;
struct nlm_file *file;
+ struct nlm_lockowner *test_owner;
__be32 rc = rpc_success;
dprintk("lockd: TEST called\n");
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+ test_owner = argp->lock.fl.fl_owner;
+
/* Now check for conflicting locks */
resp->status = cast_status(nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie));
if (resp->status == nlm_drop_reply)
dprintk("lockd: TEST status %d vers %d\n",
ntohl(resp->status), rqstp->rq_vers);
- nlmsvc_release_lockowner(&argp->lock);
+ nlmsvc_put_lockowner(test_owner);
nlmsvc_release_host(host);
nlm_release_file(file);
return rc;
#include "svcxdr.h"
-static inline loff_t
-s64_to_loff_t(__s64 offset)
-{
- return (loff_t)offset;
-}
-
-
static inline s64
loff_t_to_s64(loff_t offset)
{
svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
{
struct file_lock *fl = &lock->fl;
- u64 len, start;
- s64 end;
if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
return false;
return false;
if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
return false;
- if (xdr_stream_decode_u64(xdr, &start) < 0)
+ if (xdr_stream_decode_u64(xdr, &lock->lock_start) < 0)
return false;
- if (xdr_stream_decode_u64(xdr, &len) < 0)
+ if (xdr_stream_decode_u64(xdr, &lock->lock_len) < 0)
return false;
locks_init_lock(fl);
fl->fl_flags = FL_POSIX;
fl->fl_type = F_RDLCK;
- end = start + len - 1;
- fl->fl_start = s64_to_loff_t(start);
- if (len == 0 || end < 0)
- fl->fl_end = OFFSET_MAX;
- else
- fl->fl_end = s64_to_loff_t(end);
return true;
}
}
EXPORT_SYMBOL(unlock_rename);
+/**
+ * mode_strip_umask - handle vfs umask stripping
+ * @dir: parent directory of the new inode
+ * @mode: mode of the new inode to be created in @dir
+ *
+ * Umask stripping depends on whether or not the filesystem supports POSIX
+ * ACLs. If the filesystem doesn't support it umask stripping is done directly
+ * in here. If the filesystem does support POSIX ACLs umask stripping is
+ * deferred until the filesystem calls posix_acl_create().
+ *
+ * Returns: mode
+ */
+static inline umode_t mode_strip_umask(const struct inode *dir, umode_t mode)
+{
+ if (!IS_POSIXACL(dir))
+ mode &= ~current_umask();
+ return mode;
+}
+
+/**
+ * vfs_prepare_mode - prepare the mode to be used for a new inode
+ * @mnt_userns: user namespace of the mount the inode was found from
+ * @dir: parent directory of the new inode
+ * @mode: mode of the new inode
+ * @mask_perms: allowed permission by the vfs
+ * @type: type of file to be created
+ *
+ * This helper consolidates and enforces vfs restrictions on the @mode of a new
+ * object to be created.
+ *
+ * Umask stripping depends on whether the filesystem supports POSIX ACLs (see
+ * the kernel documentation for mode_strip_umask()). Moving umask stripping
+ * after setgid stripping allows the same ordering for both non-POSIX ACL and
+ * POSIX ACL supporting filesystems.
+ *
+ * Note that it's currently valid for @type to be 0 if a directory is created.
+ * Filesystems raise that flag individually and we need to check whether each
+ * filesystem can deal with receiving S_IFDIR from the vfs before we enforce a
+ * non-zero type.
+ *
+ * Returns: mode to be passed to the filesystem
+ */
+static inline umode_t vfs_prepare_mode(struct user_namespace *mnt_userns,
+ const struct inode *dir, umode_t mode,
+ umode_t mask_perms, umode_t type)
+{
+ mode = mode_strip_sgid(mnt_userns, dir, mode);
+ mode = mode_strip_umask(dir, mode);
+
+ /*
+ * Apply the vfs mandated allowed permission mask and set the type of
+ * file to be created before we call into the filesystem.
+ */
+ mode &= (mask_perms & ~S_IFMT);
+ mode |= (type & S_IFMT);
+
+ return mode;
+}
+
/**
* vfs_create - create new file
* @mnt_userns: user namespace of the mount the inode was found from
if (!dir->i_op->create)
return -EACCES; /* shouldn't it be ENOSYS? */
- mode &= S_IALLUGO;
- mode |= S_IFREG;
+
+ mode = vfs_prepare_mode(mnt_userns, dir, mode, S_IALLUGO, S_IFREG);
error = security_inode_create(dir, dentry, mode);
if (error)
return error;
if (open_flag & O_CREAT) {
if (open_flag & O_EXCL)
open_flag &= ~O_TRUNC;
- if (!IS_POSIXACL(dir->d_inode))
- mode &= ~current_umask();
+ mode = vfs_prepare_mode(mnt_userns, dir->d_inode, mode, mode, mode);
if (likely(got_write))
create_error = may_o_create(mnt_userns, &nd->path,
dentry, mode);
child = d_alloc(dentry, &slash_name);
if (unlikely(!child))
goto out_err;
+ mode = vfs_prepare_mode(mnt_userns, dir, mode, mode, mode);
error = dir->i_op->tmpfile(mnt_userns, dir, child, mode);
if (error)
goto out_err;
if (!dir->i_op->mknod)
return -EPERM;
+ mode = vfs_prepare_mode(mnt_userns, dir, mode, mode, mode);
error = devcgroup_inode_mknod(mode, dev);
if (error)
return error;
if (IS_ERR(dentry))
goto out1;
- if (!IS_POSIXACL(path.dentry->d_inode))
- mode &= ~current_umask();
- error = security_path_mknod(&path, dentry, mode, dev);
+ error = security_path_mknod(&path, dentry,
+ mode_strip_umask(path.dentry->d_inode, mode), dev);
if (error)
goto out2;
if (!dir->i_op->mkdir)
return -EPERM;
- mode &= (S_IRWXUGO|S_ISVTX);
+ mode = vfs_prepare_mode(mnt_userns, dir, mode, S_IRWXUGO | S_ISVTX, 0);
error = security_inode_mkdir(dir, dentry, mode);
if (error)
return error;
if (IS_ERR(dentry))
goto out_putname;
- if (!IS_POSIXACL(path.dentry->d_inode))
- mode &= ~current_umask();
- error = security_path_mkdir(&path, dentry, mode);
+ error = security_path_mkdir(&path, dentry,
+ mode_strip_umask(path.dentry->d_inode, mode));
if (!error) {
struct user_namespace *mnt_userns;
mnt_userns = mnt_user_ns(path.mnt);
size_t pgbase;
unsigned npages, i;
- result = iov_iter_get_pages_alloc(iter, &pagevec,
+ result = iov_iter_get_pages_alloc2(iter, &pagevec,
rsize, &pgbase);
if (result < 0)
break;
bytes = result;
- iov_iter_advance(iter, bytes);
npages = (result + pgbase + PAGE_SIZE - 1) / PAGE_SIZE;
for (i = 0; i < npages; i++) {
struct nfs_page *req;
if (!is_sync_kiocb(iocb))
dreq->iocb = iocb;
- if (iter_is_iovec(iter))
+ if (user_backed_iter(iter))
dreq->flags = NFS_ODIRECT_SHOULD_DIRTY;
if (!swap)
size_t pgbase;
unsigned npages, i;
- result = iov_iter_get_pages_alloc(iter, &pagevec,
+ result = iov_iter_get_pages_alloc2(iter, &pagevec,
wsize, &pgbase);
if (result < 0)
break;
bytes = result;
- iov_iter_advance(iter, bytes);
npages = (result + pgbase + PAGE_SIZE - 1) / PAGE_SIZE;
for (i = 0; i < npages; i++) {
struct nfs_page *req;
struct nfs4_acl;
struct svc_fh;
struct svc_rqst;
+struct nfsd_attrs;
+enum nfs_ftype4;
int nfs4_acl_bytes(int entries);
int nfs4_acl_get_whotype(char *, u32);
int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
struct nfs4_acl **acl);
-__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
- struct nfs4_acl *acl);
+__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl,
+ struct nfsd_attrs *attr);
#endif /* LINUX_NFS4_ACL_H */
#include <linux/fsnotify_backend.h>
#include <linux/fsnotify.h>
#include <linux/seq_file.h>
+#include <linux/rhashtable.h>
#include "vfs.h"
#include "nfsd.h"
#include "filecache.h"
#include "trace.h"
-#define NFSDDBG_FACILITY NFSDDBG_FH
-
-/* FIXME: dynamically size this for the machine somehow? */
-#define NFSD_FILE_HASH_BITS 12
-#define NFSD_FILE_HASH_SIZE (1 << NFSD_FILE_HASH_BITS)
#define NFSD_LAUNDRETTE_DELAY (2 * HZ)
-#define NFSD_FILE_SHUTDOWN (1)
-#define NFSD_FILE_LRU_THRESHOLD (4096UL)
-#define NFSD_FILE_LRU_LIMIT (NFSD_FILE_LRU_THRESHOLD << 2)
+#define NFSD_FILE_CACHE_UP (0)
/* We only care about NFSD_MAY_READ/WRITE for this cache */
#define NFSD_FILE_MAY_MASK (NFSD_MAY_READ|NFSD_MAY_WRITE)
-struct nfsd_fcache_bucket {
- struct hlist_head nfb_head;
- spinlock_t nfb_lock;
- unsigned int nfb_count;
- unsigned int nfb_maxcount;
-};
-
static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits);
+static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions);
+static DEFINE_PER_CPU(unsigned long, nfsd_file_releases);
+static DEFINE_PER_CPU(unsigned long, nfsd_file_total_age);
+static DEFINE_PER_CPU(unsigned long, nfsd_file_pages_flushed);
+static DEFINE_PER_CPU(unsigned long, nfsd_file_evictions);
struct nfsd_fcache_disposal {
struct work_struct work;
static struct kmem_cache *nfsd_file_slab;
static struct kmem_cache *nfsd_file_mark_slab;
-static struct nfsd_fcache_bucket *nfsd_file_hashtbl;
static struct list_lru nfsd_file_lru;
-static long nfsd_file_lru_flags;
+static unsigned long nfsd_file_flags;
static struct fsnotify_group *nfsd_file_fsnotify_group;
-static atomic_long_t nfsd_filecache_count;
static struct delayed_work nfsd_filecache_laundrette;
+static struct rhashtable nfsd_file_rhash_tbl
+ ____cacheline_aligned_in_smp;
+
+enum nfsd_file_lookup_type {
+ NFSD_FILE_KEY_INODE,
+ NFSD_FILE_KEY_FULL,
+};
+
+struct nfsd_file_lookup_key {
+ struct inode *inode;
+ struct net *net;
+ const struct cred *cred;
+ unsigned char need;
+ enum nfsd_file_lookup_type type;
+};
+
+/*
+ * The returned hash value is based solely on the address of an in-code
+ * inode, a pointer to a slab-allocated object. The entropy in such a
+ * pointer is concentrated in its middle bits.
+ */
+static u32 nfsd_file_inode_hash(const struct inode *inode, u32 seed)
+{
+ unsigned long ptr = (unsigned long)inode;
+ u32 k;
+
+ k = ptr >> L1_CACHE_SHIFT;
+ k &= 0x00ffffff;
+ return jhash2(&k, 1, seed);
+}
+
+/**
+ * nfsd_file_key_hashfn - Compute the hash value of a lookup key
+ * @data: key on which to compute the hash value
+ * @len: rhash table's key_len parameter (unused)
+ * @seed: rhash table's random seed of the day
+ *
+ * Return value:
+ * Computed 32-bit hash value
+ */
+static u32 nfsd_file_key_hashfn(const void *data, u32 len, u32 seed)
+{
+ const struct nfsd_file_lookup_key *key = data;
+
+ return nfsd_file_inode_hash(key->inode, seed);
+}
+
+/**
+ * nfsd_file_obj_hashfn - Compute the hash value of an nfsd_file
+ * @data: object on which to compute the hash value
+ * @len: rhash table's key_len parameter (unused)
+ * @seed: rhash table's random seed of the day
+ *
+ * Return value:
+ * Computed 32-bit hash value
+ */
+static u32 nfsd_file_obj_hashfn(const void *data, u32 len, u32 seed)
+{
+ const struct nfsd_file *nf = data;
+
+ return nfsd_file_inode_hash(nf->nf_inode, seed);
+}
-static void nfsd_file_gc(void);
+static bool
+nfsd_match_cred(const struct cred *c1, const struct cred *c2)
+{
+ int i;
+
+ if (!uid_eq(c1->fsuid, c2->fsuid))
+ return false;
+ if (!gid_eq(c1->fsgid, c2->fsgid))
+ return false;
+ if (c1->group_info == NULL || c2->group_info == NULL)
+ return c1->group_info == c2->group_info;
+ if (c1->group_info->ngroups != c2->group_info->ngroups)
+ return false;
+ for (i = 0; i < c1->group_info->ngroups; i++) {
+ if (!gid_eq(c1->group_info->gid[i], c2->group_info->gid[i]))
+ return false;
+ }
+ return true;
+}
+
+/**
+ * nfsd_file_obj_cmpfn - Match a cache item against search criteria
+ * @arg: search criteria
+ * @ptr: cache item to check
+ *
+ * Return values:
+ * %0 - Item matches search criteria
+ * %1 - Item does not match search criteria
+ */
+static int nfsd_file_obj_cmpfn(struct rhashtable_compare_arg *arg,
+ const void *ptr)
+{
+ const struct nfsd_file_lookup_key *key = arg->key;
+ const struct nfsd_file *nf = ptr;
+
+ switch (key->type) {
+ case NFSD_FILE_KEY_INODE:
+ if (nf->nf_inode != key->inode)
+ return 1;
+ break;
+ case NFSD_FILE_KEY_FULL:
+ if (nf->nf_inode != key->inode)
+ return 1;
+ if (nf->nf_may != key->need)
+ return 1;
+ if (nf->nf_net != key->net)
+ return 1;
+ if (!nfsd_match_cred(nf->nf_cred, key->cred))
+ return 1;
+ if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0)
+ return 1;
+ break;
+ }
+ return 0;
+}
+
+static const struct rhashtable_params nfsd_file_rhash_params = {
+ .key_len = sizeof_field(struct nfsd_file, nf_inode),
+ .key_offset = offsetof(struct nfsd_file, nf_inode),
+ .head_offset = offsetof(struct nfsd_file, nf_rhash),
+ .hashfn = nfsd_file_key_hashfn,
+ .obj_hashfn = nfsd_file_obj_hashfn,
+ .obj_cmpfn = nfsd_file_obj_cmpfn,
+ /* Reduce resizing churn on light workloads */
+ .min_size = 512, /* buckets */
+ .automatic_shrinking = true,
+};
static void
nfsd_file_schedule_laundrette(void)
{
- long count = atomic_long_read(&nfsd_filecache_count);
-
- if (count == 0 || test_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags))
+ if ((atomic_read(&nfsd_file_rhash_tbl.nelems) == 0) ||
+ test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 0)
return;
queue_delayed_work(system_wq, &nfsd_filecache_laundrette,
}
static struct nfsd_file_mark *
-nfsd_file_mark_find_or_create(struct nfsd_file *nf)
+nfsd_file_mark_find_or_create(struct nfsd_file *nf, struct inode *inode)
{
int err;
struct fsnotify_mark *mark;
struct nfsd_file_mark *nfm = NULL, *new;
- struct inode *inode = nf->nf_inode;
do {
fsnotify_group_lock(nfsd_file_fsnotify_group);
}
static struct nfsd_file *
-nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval,
- struct net *net)
+nfsd_file_alloc(struct nfsd_file_lookup_key *key, unsigned int may)
{
struct nfsd_file *nf;
nf = kmem_cache_alloc(nfsd_file_slab, GFP_KERNEL);
if (nf) {
- INIT_HLIST_NODE(&nf->nf_node);
INIT_LIST_HEAD(&nf->nf_lru);
+ nf->nf_birthtime = ktime_get();
nf->nf_file = NULL;
nf->nf_cred = get_current_cred();
- nf->nf_net = net;
+ nf->nf_net = key->net;
nf->nf_flags = 0;
- nf->nf_inode = inode;
- nf->nf_hashval = hashval;
- refcount_set(&nf->nf_ref, 1);
- nf->nf_may = may & NFSD_FILE_MAY_MASK;
- if (may & NFSD_MAY_NOT_BREAK_LEASE) {
- if (may & NFSD_MAY_WRITE)
- __set_bit(NFSD_FILE_BREAK_WRITE, &nf->nf_flags);
- if (may & NFSD_MAY_READ)
- __set_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags);
- }
+ __set_bit(NFSD_FILE_HASHED, &nf->nf_flags);
+ __set_bit(NFSD_FILE_PENDING, &nf->nf_flags);
+ nf->nf_inode = key->inode;
+ /* nf_ref is pre-incremented for hash table */
+ refcount_set(&nf->nf_ref, 2);
+ nf->nf_may = key->need;
nf->nf_mark = NULL;
- trace_nfsd_file_alloc(nf);
}
return nf;
}
static bool
nfsd_file_free(struct nfsd_file *nf)
{
+ s64 age = ktime_to_ms(ktime_sub(ktime_get(), nf->nf_birthtime));
bool flush = false;
+ this_cpu_inc(nfsd_file_releases);
+ this_cpu_add(nfsd_file_total_age, age);
+
trace_nfsd_file_put_final(nf);
if (nf->nf_mark)
nfsd_file_mark_put(nf->nf_mark);
fput(nf->nf_file);
flush = true;
}
+
+ /*
+ * If this item is still linked via nf_lru, that's a bug.
+ * WARN and leak it to preserve system stability.
+ */
+ if (WARN_ON_ONCE(!list_empty(&nf->nf_lru)))
+ return flush;
+
call_rcu(&nf->nf_rcu, nfsd_file_slab_free);
return flush;
}
static void
nfsd_file_flush(struct nfsd_file *nf)
{
- if (nf->nf_file && vfs_fsync(nf->nf_file, 1) != 0)
+ struct file *file = nf->nf_file;
+
+ if (!file || !(file->f_mode & FMODE_WRITE))
+ return;
+ this_cpu_add(nfsd_file_pages_flushed, file->f_mapping->nrpages);
+ if (vfs_fsync(file, 1) != 0)
nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id));
}
-static void
-nfsd_file_do_unhash(struct nfsd_file *nf)
+static void nfsd_file_lru_add(struct nfsd_file *nf)
{
- lockdep_assert_held(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock);
+ set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
+ if (list_lru_add(&nfsd_file_lru, &nf->nf_lru))
+ trace_nfsd_file_lru_add(nf);
+}
+static void nfsd_file_lru_remove(struct nfsd_file *nf)
+{
+ if (list_lru_del(&nfsd_file_lru, &nf->nf_lru))
+ trace_nfsd_file_lru_del(nf);
+}
+
+static void
+nfsd_file_hash_remove(struct nfsd_file *nf)
+{
trace_nfsd_file_unhash(nf);
if (nfsd_file_check_write_error(nf))
nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id));
- --nfsd_file_hashtbl[nf->nf_hashval].nfb_count;
- hlist_del_rcu(&nf->nf_node);
- atomic_long_dec(&nfsd_filecache_count);
+ rhashtable_remove_fast(&nfsd_file_rhash_tbl, &nf->nf_rhash,
+ nfsd_file_rhash_params);
}
static bool
nfsd_file_unhash(struct nfsd_file *nf)
{
if (test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
- nfsd_file_do_unhash(nf);
- if (!list_empty(&nf->nf_lru))
- list_lru_del(&nfsd_file_lru, &nf->nf_lru);
+ nfsd_file_hash_remove(nf);
return true;
}
return false;
* Return true if the file was unhashed.
*/
static bool
-nfsd_file_unhash_and_release_locked(struct nfsd_file *nf, struct list_head *dispose)
+nfsd_file_unhash_and_dispose(struct nfsd_file *nf, struct list_head *dispose)
{
- lockdep_assert_held(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock);
-
- trace_nfsd_file_unhash_and_release_locked(nf);
+ trace_nfsd_file_unhash_and_dispose(nf);
if (!nfsd_file_unhash(nf))
return false;
/* keep final reference for nfsd_file_lru_dispose */
if (refcount_dec_not_one(&nf->nf_ref))
return true;
+ nfsd_file_lru_remove(nf);
list_add(&nf->nf_lru, dispose);
return true;
}
if (refcount_dec_and_test(&nf->nf_ref)) {
WARN_ON(test_bit(NFSD_FILE_HASHED, &nf->nf_flags));
+ nfsd_file_lru_remove(nf);
nfsd_file_free(nf);
}
}
{
might_sleep();
- set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
+ nfsd_file_lru_add(nf);
if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) {
nfsd_file_flush(nf);
nfsd_file_put_noref(nf);
nfsd_file_schedule_laundrette();
} else
nfsd_file_put_noref(nf);
+}
- if (atomic_long_read(&nfsd_filecache_count) >= NFSD_FILE_LRU_LIMIT)
- nfsd_file_gc();
+/**
+ * nfsd_file_close - Close an nfsd_file
+ * @nf: nfsd_file to close
+ *
+ * If this is the final reference for @nf, free it immediately.
+ * This reflects an on-the-wire CLOSE or DELEGRETURN into the
+ * VFS and exported filesystem.
+ */
+void nfsd_file_close(struct nfsd_file *nf)
+{
+ nfsd_file_put(nf);
+ if (refcount_dec_if_one(&nf->nf_ref)) {
+ nfsd_file_unhash(nf);
+ nfsd_file_lru_remove(nf);
+ nfsd_file_free(nf);
+ }
}
struct nfsd_file *
while(!list_empty(dispose)) {
nf = list_first_entry(dispose, struct nfsd_file, nf_lru);
- list_del(&nf->nf_lru);
+ list_del_init(&nf->nf_lru);
nfsd_file_flush(nf);
nfsd_file_put_noref(nf);
}
while(!list_empty(dispose)) {
nf = list_first_entry(dispose, struct nfsd_file, nf_lru);
- list_del(&nf->nf_lru);
+ list_del_init(&nf->nf_lru);
nfsd_file_flush(nf);
if (!refcount_dec_and_test(&nf->nf_ref))
continue;
}
}
-/*
+/**
+ * nfsd_file_lru_cb - Examine an entry on the LRU list
+ * @item: LRU entry to examine
+ * @lru: controlling LRU
+ * @lock: LRU list lock (unused)
+ * @arg: dispose list
+ *
* Note this can deadlock with nfsd_file_cache_purge.
+ *
+ * Return values:
+ * %LRU_REMOVED: @item was removed from the LRU
+ * %LRU_ROTATE: @item is to be moved to the LRU tail
+ * %LRU_SKIP: @item cannot be evicted
*/
static enum lru_status
nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru,
* counter. Here we check the counter and then test and clear the flag.
* That order is deliberate to ensure that we can do this locklessly.
*/
- if (refcount_read(&nf->nf_ref) > 1)
- goto out_skip;
+ if (refcount_read(&nf->nf_ref) > 1) {
+ list_lru_isolate(lru, &nf->nf_lru);
+ trace_nfsd_file_gc_in_use(nf);
+ return LRU_REMOVED;
+ }
/*
* Don't throw out files that are still undergoing I/O or
* that have uncleared errors pending.
*/
- if (nfsd_file_check_writeback(nf))
- goto out_skip;
+ if (nfsd_file_check_writeback(nf)) {
+ trace_nfsd_file_gc_writeback(nf);
+ return LRU_SKIP;
+ }
- if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags))
- goto out_skip;
+ if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags)) {
+ trace_nfsd_file_gc_referenced(nf);
+ return LRU_ROTATE;
+ }
- if (!test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags))
- goto out_skip;
+ if (!test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
+ trace_nfsd_file_gc_hashed(nf);
+ return LRU_SKIP;
+ }
list_lru_isolate_move(lru, &nf->nf_lru, head);
+ this_cpu_inc(nfsd_file_evictions);
+ trace_nfsd_file_gc_disposed(nf);
return LRU_REMOVED;
-out_skip:
- return LRU_SKIP;
}
-static unsigned long
-nfsd_file_lru_walk_list(struct shrink_control *sc)
+/*
+ * Unhash items on @dispose immediately, then queue them on the
+ * disposal workqueue to finish releasing them in the background.
+ *
+ * cel: Note that between the time list_lru_shrink_walk runs and
+ * now, these items are in the hash table but marked unhashed.
+ * Why release these outside of lru_cb ? There's no lock ordering
+ * problem since lru_cb currently takes no lock.
+ */
+static void nfsd_file_gc_dispose_list(struct list_head *dispose)
{
- LIST_HEAD(head);
struct nfsd_file *nf;
- unsigned long ret;
- if (sc)
- ret = list_lru_shrink_walk(&nfsd_file_lru, sc,
- nfsd_file_lru_cb, &head);
- else
- ret = list_lru_walk(&nfsd_file_lru,
- nfsd_file_lru_cb,
- &head, LONG_MAX);
- list_for_each_entry(nf, &head, nf_lru) {
- spin_lock(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock);
- nfsd_file_do_unhash(nf);
- spin_unlock(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock);
- }
- nfsd_file_dispose_list_delayed(&head);
- return ret;
+ list_for_each_entry(nf, dispose, nf_lru)
+ nfsd_file_hash_remove(nf);
+ nfsd_file_dispose_list_delayed(dispose);
}
static void
nfsd_file_gc(void)
{
- nfsd_file_lru_walk_list(NULL);
+ LIST_HEAD(dispose);
+ unsigned long ret;
+
+ ret = list_lru_walk(&nfsd_file_lru, nfsd_file_lru_cb,
+ &dispose, list_lru_count(&nfsd_file_lru));
+ trace_nfsd_file_gc_removed(ret, list_lru_count(&nfsd_file_lru));
+ nfsd_file_gc_dispose_list(&dispose);
}
static void
static unsigned long
nfsd_file_lru_scan(struct shrinker *s, struct shrink_control *sc)
{
- return nfsd_file_lru_walk_list(sc);
+ LIST_HEAD(dispose);
+ unsigned long ret;
+
+ ret = list_lru_shrink_walk(&nfsd_file_lru, sc,
+ nfsd_file_lru_cb, &dispose);
+ trace_nfsd_file_shrinker_removed(ret, list_lru_count(&nfsd_file_lru));
+ nfsd_file_gc_dispose_list(&dispose);
+ return ret;
}
static struct shrinker nfsd_file_shrinker = {
.seeks = 1,
};
-static void
-__nfsd_file_close_inode(struct inode *inode, unsigned int hashval,
- struct list_head *dispose)
+/*
+ * Find all cache items across all net namespaces that match @inode and
+ * move them to @dispose. The lookup is atomic wrt nfsd_file_acquire().
+ */
+static unsigned int
+__nfsd_file_close_inode(struct inode *inode, struct list_head *dispose)
{
- struct nfsd_file *nf;
- struct hlist_node *tmp;
+ struct nfsd_file_lookup_key key = {
+ .type = NFSD_FILE_KEY_INODE,
+ .inode = inode,
+ };
+ unsigned int count = 0;
+ struct nfsd_file *nf;
- spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock);
- hlist_for_each_entry_safe(nf, tmp, &nfsd_file_hashtbl[hashval].nfb_head, nf_node) {
- if (inode == nf->nf_inode)
- nfsd_file_unhash_and_release_locked(nf, dispose);
- }
- spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock);
+ rcu_read_lock();
+ do {
+ nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key,
+ nfsd_file_rhash_params);
+ if (!nf)
+ break;
+ nfsd_file_unhash_and_dispose(nf, dispose);
+ count++;
+ } while (1);
+ rcu_read_unlock();
+ return count;
}
/**
* nfsd_file_close_inode_sync - attempt to forcibly close a nfsd_file
* @inode: inode of the file to attempt to remove
*
- * Walk the whole hash bucket, looking for any files that correspond to "inode".
- * If any do, then unhash them and put the hashtable reference to them and
- * destroy any that had their last reference put. Also ensure that any of the
- * fputs also have their final __fput done as well.
+ * Unhash and put, then flush and fput all cache items associated with @inode.
*/
void
nfsd_file_close_inode_sync(struct inode *inode)
{
- unsigned int hashval = (unsigned int)hash_long(inode->i_ino,
- NFSD_FILE_HASH_BITS);
LIST_HEAD(dispose);
+ unsigned int count;
- __nfsd_file_close_inode(inode, hashval, &dispose);
- trace_nfsd_file_close_inode_sync(inode, hashval, !list_empty(&dispose));
+ count = __nfsd_file_close_inode(inode, &dispose);
+ trace_nfsd_file_close_inode_sync(inode, count);
nfsd_file_dispose_list_sync(&dispose);
}
* nfsd_file_close_inode - attempt a delayed close of a nfsd_file
* @inode: inode of the file to attempt to remove
*
- * Walk the whole hash bucket, looking for any files that correspond to "inode".
- * If any do, then unhash them and put the hashtable reference to them and
- * destroy any that had their last reference put.
+ * Unhash and put all cache item associated with @inode.
*/
static void
nfsd_file_close_inode(struct inode *inode)
{
- unsigned int hashval = (unsigned int)hash_long(inode->i_ino,
- NFSD_FILE_HASH_BITS);
LIST_HEAD(dispose);
+ unsigned int count;
- __nfsd_file_close_inode(inode, hashval, &dispose);
- trace_nfsd_file_close_inode(inode, hashval, !list_empty(&dispose));
+ count = __nfsd_file_close_inode(inode, &dispose);
+ trace_nfsd_file_close_inode(inode, count);
nfsd_file_dispose_list_delayed(&dispose);
}
int
nfsd_file_cache_init(void)
{
- int ret = -ENOMEM;
- unsigned int i;
+ int ret;
- clear_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags);
-
- if (nfsd_file_hashtbl)
+ lockdep_assert_held(&nfsd_mutex);
+ if (test_and_set_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1)
return 0;
+ ret = rhashtable_init(&nfsd_file_rhash_tbl, &nfsd_file_rhash_params);
+ if (ret)
+ return ret;
+
+ ret = -ENOMEM;
nfsd_filecache_wq = alloc_workqueue("nfsd_filecache", 0, 0);
if (!nfsd_filecache_wq)
goto out;
- nfsd_file_hashtbl = kvcalloc(NFSD_FILE_HASH_SIZE,
- sizeof(*nfsd_file_hashtbl), GFP_KERNEL);
- if (!nfsd_file_hashtbl) {
- pr_err("nfsd: unable to allocate nfsd_file_hashtbl\n");
- goto out_err;
- }
-
nfsd_file_slab = kmem_cache_create("nfsd_file",
sizeof(struct nfsd_file), 0, 0, NULL);
if (!nfsd_file_slab) {
goto out_notifier;
}
- for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) {
- INIT_HLIST_HEAD(&nfsd_file_hashtbl[i].nfb_head);
- spin_lock_init(&nfsd_file_hashtbl[i].nfb_lock);
- }
-
INIT_DELAYED_WORK(&nfsd_filecache_laundrette, nfsd_file_gc_worker);
out:
return ret;
nfsd_file_slab = NULL;
kmem_cache_destroy(nfsd_file_mark_slab);
nfsd_file_mark_slab = NULL;
- kvfree(nfsd_file_hashtbl);
- nfsd_file_hashtbl = NULL;
destroy_workqueue(nfsd_filecache_wq);
nfsd_filecache_wq = NULL;
+ rhashtable_destroy(&nfsd_file_rhash_tbl);
goto out;
}
/*
* Note this can deadlock with nfsd_file_lru_cb.
*/
-void
-nfsd_file_cache_purge(struct net *net)
+static void
+__nfsd_file_cache_purge(struct net *net)
{
- unsigned int i;
- struct nfsd_file *nf;
- struct hlist_node *next;
+ struct rhashtable_iter iter;
+ struct nfsd_file *nf;
LIST_HEAD(dispose);
bool del;
- if (!nfsd_file_hashtbl)
- return;
-
- for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) {
- struct nfsd_fcache_bucket *nfb = &nfsd_file_hashtbl[i];
+ rhashtable_walk_enter(&nfsd_file_rhash_tbl, &iter);
+ do {
+ rhashtable_walk_start(&iter);
- spin_lock(&nfb->nfb_lock);
- hlist_for_each_entry_safe(nf, next, &nfb->nfb_head, nf_node) {
+ nf = rhashtable_walk_next(&iter);
+ while (!IS_ERR_OR_NULL(nf)) {
if (net && nf->nf_net != net)
continue;
- del = nfsd_file_unhash_and_release_locked(nf, &dispose);
+ del = nfsd_file_unhash_and_dispose(nf, &dispose);
/*
* Deadlock detected! Something marked this entry as
* unhased, but hasn't removed it from the hash list.
*/
WARN_ON_ONCE(!del);
+
+ nf = rhashtable_walk_next(&iter);
}
- spin_unlock(&nfb->nfb_lock);
- nfsd_file_dispose_list(&dispose);
- }
+
+ rhashtable_walk_stop(&iter);
+ } while (nf == ERR_PTR(-EAGAIN));
+ rhashtable_walk_exit(&iter);
+
+ nfsd_file_dispose_list(&dispose);
}
static struct nfsd_fcache_disposal *
return nn->fcache_disposal ? 0 : -ENOMEM;
}
+/**
+ * nfsd_file_cache_purge - Remove all cache items associated with @net
+ * @net: target net namespace
+ *
+ */
+void
+nfsd_file_cache_purge(struct net *net)
+{
+ lockdep_assert_held(&nfsd_mutex);
+ if (test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1)
+ __nfsd_file_cache_purge(net);
+}
+
void
nfsd_file_cache_shutdown_net(struct net *net)
{
void
nfsd_file_cache_shutdown(void)
{
- set_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags);
+ int i;
+
+ lockdep_assert_held(&nfsd_mutex);
+ if (test_and_clear_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 0)
+ return;
lease_unregister_notifier(&nfsd_file_lease_notifier);
unregister_shrinker(&nfsd_file_shrinker);
* calling nfsd_file_cache_purge
*/
cancel_delayed_work_sync(&nfsd_filecache_laundrette);
- nfsd_file_cache_purge(NULL);
+ __nfsd_file_cache_purge(NULL);
list_lru_destroy(&nfsd_file_lru);
rcu_barrier();
fsnotify_put_group(nfsd_file_fsnotify_group);
fsnotify_wait_marks_destroyed();
kmem_cache_destroy(nfsd_file_mark_slab);
nfsd_file_mark_slab = NULL;
- kvfree(nfsd_file_hashtbl);
- nfsd_file_hashtbl = NULL;
destroy_workqueue(nfsd_filecache_wq);
nfsd_filecache_wq = NULL;
-}
-
-static bool
-nfsd_match_cred(const struct cred *c1, const struct cred *c2)
-{
- int i;
-
- if (!uid_eq(c1->fsuid, c2->fsuid))
- return false;
- if (!gid_eq(c1->fsgid, c2->fsgid))
- return false;
- if (c1->group_info == NULL || c2->group_info == NULL)
- return c1->group_info == c2->group_info;
- if (c1->group_info->ngroups != c2->group_info->ngroups)
- return false;
- for (i = 0; i < c1->group_info->ngroups; i++) {
- if (!gid_eq(c1->group_info->gid[i], c2->group_info->gid[i]))
- return false;
- }
- return true;
-}
-
-static struct nfsd_file *
-nfsd_file_find_locked(struct inode *inode, unsigned int may_flags,
- unsigned int hashval, struct net *net)
-{
- struct nfsd_file *nf;
- unsigned char need = may_flags & NFSD_FILE_MAY_MASK;
-
- hlist_for_each_entry_rcu(nf, &nfsd_file_hashtbl[hashval].nfb_head,
- nf_node, lockdep_is_held(&nfsd_file_hashtbl[hashval].nfb_lock)) {
- if (nf->nf_may != need)
- continue;
- if (nf->nf_inode != inode)
- continue;
- if (nf->nf_net != net)
- continue;
- if (!nfsd_match_cred(nf->nf_cred, current_cred()))
- continue;
- if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags))
- continue;
- if (nfsd_file_get(nf) != NULL)
- return nf;
+ rhashtable_destroy(&nfsd_file_rhash_tbl);
+
+ for_each_possible_cpu(i) {
+ per_cpu(nfsd_file_cache_hits, i) = 0;
+ per_cpu(nfsd_file_acquisitions, i) = 0;
+ per_cpu(nfsd_file_releases, i) = 0;
+ per_cpu(nfsd_file_total_age, i) = 0;
+ per_cpu(nfsd_file_pages_flushed, i) = 0;
+ per_cpu(nfsd_file_evictions, i) = 0;
}
- return NULL;
}
/**
- * nfsd_file_is_cached - are there any cached open files for this fh?
- * @inode: inode of the file to check
+ * nfsd_file_is_cached - are there any cached open files for this inode?
+ * @inode: inode to check
+ *
+ * The lookup matches inodes in all net namespaces and is atomic wrt
+ * nfsd_file_acquire().
*
- * Scan the hashtable for open files that match this fh. Returns true if there
- * are any, and false if not.
+ * Return values:
+ * %true: filecache contains at least one file matching this inode
+ * %false: filecache contains no files matching this inode
*/
bool
nfsd_file_is_cached(struct inode *inode)
{
- bool ret = false;
- struct nfsd_file *nf;
- unsigned int hashval;
-
- hashval = (unsigned int)hash_long(inode->i_ino, NFSD_FILE_HASH_BITS);
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(nf, &nfsd_file_hashtbl[hashval].nfb_head,
- nf_node) {
- if (inode == nf->nf_inode) {
- ret = true;
- break;
- }
- }
- rcu_read_unlock();
- trace_nfsd_file_is_cached(inode, hashval, (int)ret);
+ struct nfsd_file_lookup_key key = {
+ .type = NFSD_FILE_KEY_INODE,
+ .inode = inode,
+ };
+ bool ret = false;
+
+ if (rhashtable_lookup_fast(&nfsd_file_rhash_tbl, &key,
+ nfsd_file_rhash_params) != NULL)
+ ret = true;
+ trace_nfsd_file_is_cached(inode, (int)ret);
return ret;
}
static __be32
-nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
+nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
unsigned int may_flags, struct nfsd_file **pnf, bool open)
{
- __be32 status;
- struct net *net = SVC_NET(rqstp);
+ struct nfsd_file_lookup_key key = {
+ .type = NFSD_FILE_KEY_FULL,
+ .need = may_flags & NFSD_FILE_MAY_MASK,
+ .net = SVC_NET(rqstp),
+ };
struct nfsd_file *nf, *new;
- struct inode *inode;
- unsigned int hashval;
bool retry = true;
+ __be32 status;
- /* FIXME: skip this if fh_dentry is already set? */
status = fh_verify(rqstp, fhp, S_IFREG,
may_flags|NFSD_MAY_OWNER_OVERRIDE);
if (status != nfs_ok)
return status;
+ key.inode = d_inode(fhp->fh_dentry);
+ key.cred = get_current_cred();
- inode = d_inode(fhp->fh_dentry);
- hashval = (unsigned int)hash_long(inode->i_ino, NFSD_FILE_HASH_BITS);
retry:
- rcu_read_lock();
- nf = nfsd_file_find_locked(inode, may_flags, hashval, net);
- rcu_read_unlock();
+ /* Avoid allocation if the item is already in cache */
+ nf = rhashtable_lookup_fast(&nfsd_file_rhash_tbl, &key,
+ nfsd_file_rhash_params);
+ if (nf)
+ nf = nfsd_file_get(nf);
if (nf)
goto wait_for_construction;
- new = nfsd_file_alloc(inode, may_flags, hashval, net);
+ new = nfsd_file_alloc(&key, may_flags);
if (!new) {
- trace_nfsd_file_acquire(rqstp, hashval, inode, may_flags,
- NULL, nfserr_jukebox);
- return nfserr_jukebox;
+ status = nfserr_jukebox;
+ goto out_status;
}
- spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock);
- nf = nfsd_file_find_locked(inode, may_flags, hashval, net);
- if (nf == NULL)
+ nf = rhashtable_lookup_get_insert_key(&nfsd_file_rhash_tbl,
+ &key, &new->nf_rhash,
+ nfsd_file_rhash_params);
+ if (!nf) {
+ nf = new;
goto open_file;
- spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock);
+ }
+ if (IS_ERR(nf))
+ goto insert_err;
+ nf = nfsd_file_get(nf);
+ if (nf == NULL) {
+ nf = new;
+ goto open_file;
+ }
nfsd_file_slab_free(&new->nf_rcu);
wait_for_construction:
/* Did construction of this file fail? */
if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
+ trace_nfsd_file_cons_err(rqstp, key.inode, may_flags, nf);
if (!retry) {
status = nfserr_jukebox;
goto out;
goto retry;
}
+ nfsd_file_lru_remove(nf);
this_cpu_inc(nfsd_file_cache_hits);
- if (!(may_flags & NFSD_MAY_NOT_BREAK_LEASE)) {
- bool write = (may_flags & NFSD_MAY_WRITE);
-
- if (test_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags) ||
- (test_bit(NFSD_FILE_BREAK_WRITE, &nf->nf_flags) && write)) {
- status = nfserrno(nfsd_open_break_lease(
- file_inode(nf->nf_file), may_flags));
- if (status == nfs_ok) {
- clear_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags);
- if (write)
- clear_bit(NFSD_FILE_BREAK_WRITE,
- &nf->nf_flags);
- }
- }
- }
+ status = nfserrno(nfsd_open_break_lease(file_inode(nf->nf_file), may_flags));
out:
if (status == nfs_ok) {
+ if (open)
+ this_cpu_inc(nfsd_file_acquisitions);
*pnf = nf;
} else {
nfsd_file_put(nf);
nf = NULL;
}
- trace_nfsd_file_acquire(rqstp, hashval, inode, may_flags, nf, status);
+out_status:
+ put_cred(key.cred);
+ if (open)
+ trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status);
return status;
+
open_file:
- nf = new;
- /* Take reference for the hashtable */
- refcount_inc(&nf->nf_ref);
- __set_bit(NFSD_FILE_HASHED, &nf->nf_flags);
- __set_bit(NFSD_FILE_PENDING, &nf->nf_flags);
- list_lru_add(&nfsd_file_lru, &nf->nf_lru);
- hlist_add_head_rcu(&nf->nf_node, &nfsd_file_hashtbl[hashval].nfb_head);
- ++nfsd_file_hashtbl[hashval].nfb_count;
- nfsd_file_hashtbl[hashval].nfb_maxcount = max(nfsd_file_hashtbl[hashval].nfb_maxcount,
- nfsd_file_hashtbl[hashval].nfb_count);
- spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock);
- if (atomic_long_inc_return(&nfsd_filecache_count) >= NFSD_FILE_LRU_THRESHOLD)
- nfsd_file_gc();
-
- nf->nf_mark = nfsd_file_mark_find_or_create(nf);
+ trace_nfsd_file_alloc(nf);
+ nf->nf_mark = nfsd_file_mark_find_or_create(nf, key.inode);
if (nf->nf_mark) {
if (open) {
status = nfsd_open_verified(rqstp, fhp, may_flags,
* If construction failed, or we raced with a call to unlink()
* then unhash.
*/
- if (status != nfs_ok || inode->i_nlink == 0) {
- bool do_free;
- spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock);
- do_free = nfsd_file_unhash(nf);
- spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock);
- if (do_free)
+ if (status != nfs_ok || key.inode->i_nlink == 0)
+ if (nfsd_file_unhash(nf))
nfsd_file_put_noref(nf);
- }
clear_bit_unlock(NFSD_FILE_PENDING, &nf->nf_flags);
smp_mb__after_atomic();
wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING);
goto out;
+
+insert_err:
+ nfsd_file_slab_free(&new->nf_rcu);
+ trace_nfsd_file_insert_err(rqstp, key.inode, may_flags, PTR_ERR(nf));
+ nf = NULL;
+ status = nfserr_jukebox;
+ goto out_status;
}
/**
nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
unsigned int may_flags, struct nfsd_file **pnf)
{
- return nfsd_do_file_acquire(rqstp, fhp, may_flags, pnf, true);
+ return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true);
}
/**
nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
unsigned int may_flags, struct nfsd_file **pnf)
{
- return nfsd_do_file_acquire(rqstp, fhp, may_flags, pnf, false);
+ return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, false);
}
/*
*/
static int nfsd_file_cache_stats_show(struct seq_file *m, void *v)
{
- unsigned int i, count = 0, longest = 0;
- unsigned long hits = 0;
+ unsigned long releases = 0, pages_flushed = 0, evictions = 0;
+ unsigned long hits = 0, acquisitions = 0;
+ unsigned int i, count = 0, buckets = 0;
+ unsigned long lru = 0, total_age = 0;
- /*
- * No need for spinlocks here since we're not terribly interested in
- * accuracy. We do take the nfsd_mutex simply to ensure that we
- * don't end up racing with server shutdown
- */
+ /* Serialize with server shutdown */
mutex_lock(&nfsd_mutex);
- if (nfsd_file_hashtbl) {
- for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) {
- count += nfsd_file_hashtbl[i].nfb_count;
- longest = max(longest, nfsd_file_hashtbl[i].nfb_count);
- }
+ if (test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1) {
+ struct bucket_table *tbl;
+ struct rhashtable *ht;
+
+ lru = list_lru_count(&nfsd_file_lru);
+
+ rcu_read_lock();
+ ht = &nfsd_file_rhash_tbl;
+ count = atomic_read(&ht->nelems);
+ tbl = rht_dereference_rcu(ht->tbl, ht);
+ buckets = tbl->size;
+ rcu_read_unlock();
}
mutex_unlock(&nfsd_mutex);
- for_each_possible_cpu(i)
+ for_each_possible_cpu(i) {
hits += per_cpu(nfsd_file_cache_hits, i);
+ acquisitions += per_cpu(nfsd_file_acquisitions, i);
+ releases += per_cpu(nfsd_file_releases, i);
+ total_age += per_cpu(nfsd_file_total_age, i);
+ evictions += per_cpu(nfsd_file_evictions, i);
+ pages_flushed += per_cpu(nfsd_file_pages_flushed, i);
+ }
seq_printf(m, "total entries: %u\n", count);
- seq_printf(m, "longest chain: %u\n", longest);
+ seq_printf(m, "hash buckets: %u\n", buckets);
+ seq_printf(m, "lru entries: %lu\n", lru);
seq_printf(m, "cache hits: %lu\n", hits);
+ seq_printf(m, "acquisitions: %lu\n", acquisitions);
+ seq_printf(m, "releases: %lu\n", releases);
+ seq_printf(m, "evictions: %lu\n", evictions);
+ if (releases)
+ seq_printf(m, "mean age (ms): %ld\n", total_age / releases);
+ else
+ seq_printf(m, "mean age (ms): -\n");
+ seq_printf(m, "pages flushed: %lu\n", pages_flushed);
return 0;
}
* never be dereferenced, only used for comparison.
*/
struct nfsd_file {
- struct hlist_node nf_node;
+ struct rhash_head nf_rhash;
struct list_head nf_lru;
struct rcu_head nf_rcu;
struct file *nf_file;
struct net *nf_net;
#define NFSD_FILE_HASHED (0)
#define NFSD_FILE_PENDING (1)
-#define NFSD_FILE_BREAK_READ (2)
-#define NFSD_FILE_BREAK_WRITE (3)
-#define NFSD_FILE_REFERENCED (4)
+#define NFSD_FILE_REFERENCED (2)
unsigned long nf_flags;
- struct inode *nf_inode;
- unsigned int nf_hashval;
+ struct inode *nf_inode; /* don't deref */
refcount_t nf_ref;
unsigned char nf_may;
struct nfsd_file_mark *nf_mark;
+ ktime_t nf_birthtime;
};
int nfsd_file_cache_init(void);
int nfsd_file_cache_start_net(struct net *net);
void nfsd_file_cache_shutdown_net(struct net *net);
void nfsd_file_put(struct nfsd_file *nf);
+void nfsd_file_close(struct nfsd_file *nf);
struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
void nfsd_file_close_inode_sync(struct inode *inode);
bool nfsd_file_is_cached(struct inode *inode);
struct nfsd_fcache_disposal *fcache_disposal;
siphash_key_t siphash_key;
+
+ atomic_t nfs4_client_count;
+ int nfs4_max_clients;
};
/* Simple check to find out if a given net was properly initialized */
if (error)
goto out_errno;
- fh_lock(fh);
+ inode_lock(inode);
error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
argp->acl_access);
if (error)
goto out_drop_lock;
- fh_unlock(fh);
+ inode_unlock(inode);
fh_drop_write(fh);
return rpc_success;
out_drop_lock:
- fh_unlock(fh);
+ inode_unlock(inode);
fh_drop_write(fh);
out_errno:
resp->status = nfserrno(error);
if (error)
goto out_errno;
- fh_lock(fh);
+ inode_lock(inode);
error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
argp->acl_access);
argp->acl_default);
out_drop_lock:
- fh_unlock(fh);
+ inode_unlock(inode);
fh_drop_write(fh);
out_errno:
resp->status = nfserrno(error);
{
struct nfsd3_sattrargs *argp = rqstp->rq_argp;
struct nfsd3_attrstat *resp = rqstp->rq_resp;
+ struct nfsd_attrs attrs = {
+ .na_iattr = &argp->attrs,
+ };
dprintk("nfsd: SETATTR(3) %s\n",
SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh);
- resp->status = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,
+ resp->status = nfsd_setattr(rqstp, &resp->fh, &attrs,
argp->check_guard, argp->guardtime);
return rpc_success;
}
{
struct iattr *iap = &argp->attrs;
struct dentry *parent, *child;
+ struct nfsd_attrs attrs = {
+ .na_iattr = iap,
+ };
__u32 v_mtime, v_atime;
struct inode *inode;
__be32 status;
if (host_err)
return nfserrno(host_err);
- fh_lock_nested(fhp, I_MUTEX_PARENT);
+ inode_lock_nested(inode, I_MUTEX_PARENT);
child = lookup_one_len(argp->name, parent, argp->len);
if (IS_ERR(child)) {
if (!IS_POSIXACL(inode))
iap->ia_mode &= ~current_umask();
+ fh_fill_pre_attrs(fhp);
host_err = vfs_create(&init_user_ns, inode, child, iap->ia_mode, true);
if (host_err < 0) {
status = nfserrno(host_err);
goto out;
}
+ fh_fill_post_attrs(fhp);
/* A newly created file already has a file size of zero. */
if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
}
set_attr:
- status = nfsd_create_setattr(rqstp, fhp, resfhp, iap);
+ status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs);
out:
- fh_unlock(fhp);
+ inode_unlock(inode);
if (child && !IS_ERR(child))
dput(child);
fh_drop_write(fhp);
{
struct nfsd3_createargs *argp = rqstp->rq_argp;
struct nfsd3_diropres *resp = rqstp->rq_resp;
+ struct nfsd_attrs attrs = {
+ .na_iattr = &argp->attrs,
+ };
dprintk("nfsd: MKDIR(3) %s %.*s\n",
SVCFH_fmt(&argp->fh),
fh_copy(&resp->dirfh, &argp->fh);
fh_init(&resp->fh, NFS3_FHSIZE);
resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
- &argp->attrs, S_IFDIR, 0, &resp->fh);
- fh_unlock(&resp->dirfh);
+ &attrs, S_IFDIR, 0, &resp->fh);
return rpc_success;
}
{
struct nfsd3_symlinkargs *argp = rqstp->rq_argp;
struct nfsd3_diropres *resp = rqstp->rq_resp;
+ struct nfsd_attrs attrs = {
+ .na_iattr = &argp->attrs,
+ };
if (argp->tlen == 0) {
resp->status = nfserr_inval;
fh_copy(&resp->dirfh, &argp->ffh);
fh_init(&resp->fh, NFS3_FHSIZE);
resp->status = nfsd_symlink(rqstp, &resp->dirfh, argp->fname,
- argp->flen, argp->tname, &resp->fh);
+ argp->flen, argp->tname, &attrs, &resp->fh);
kfree(argp->tname);
out:
return rpc_success;
{
struct nfsd3_mknodargs *argp = rqstp->rq_argp;
struct nfsd3_diropres *resp = rqstp->rq_resp;
+ struct nfsd_attrs attrs = {
+ .na_iattr = &argp->attrs,
+ };
int type;
dev_t rdev = 0;
type = nfs3_ftypes[argp->ftype];
resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
- &argp->attrs, type, rdev, &resp->fh);
- fh_unlock(&resp->dirfh);
+ &attrs, type, rdev, &resp->fh);
out:
return rpc_success;
}
fh_copy(&resp->fh, &argp->fh);
resp->status = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR,
argp->name, argp->len);
- fh_unlock(&resp->fh);
return rpc_success;
}
fh_copy(&resp->fh, &argp->fh);
resp->status = nfsd_unlink(rqstp, &resp->fh, S_IFDIR,
argp->name, argp->len);
- fh_unlock(&resp->fh);
return rpc_success;
}
return ret;
}
-__be32
-nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
- struct nfs4_acl *acl)
+__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl,
+ struct nfsd_attrs *attr)
{
- __be32 error;
int host_error;
- struct dentry *dentry;
- struct inode *inode;
- struct posix_acl *pacl = NULL, *dpacl = NULL;
unsigned int flags = 0;
- /* Get inode */
- error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
- if (error)
- return error;
-
- dentry = fhp->fh_dentry;
- inode = d_inode(dentry);
+ if (!acl)
+ return nfs_ok;
- if (S_ISDIR(inode->i_mode))
+ if (type == NF4DIR)
flags = NFS4_ACL_DIR;
- host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
+ host_error = nfs4_acl_nfsv4_to_posix(acl, &attr->na_pacl,
+ &attr->na_dpacl, flags);
if (host_error == -EINVAL)
return nfserr_attrnotsupp;
- if (host_error < 0)
- goto out_nfserr;
-
- fh_lock(fhp);
-
- host_error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS, pacl);
- if (host_error < 0)
- goto out_drop_lock;
-
- if (S_ISDIR(inode->i_mode)) {
- host_error = set_posix_acl(&init_user_ns, inode,
- ACL_TYPE_DEFAULT, dpacl);
- }
-
-out_drop_lock:
- fh_unlock(fhp);
-
- posix_acl_release(pacl);
- posix_acl_release(dpacl);
-out_nfserr:
- if (host_error == -EOPNOTSUPP)
- return nfserr_attrnotsupp;
else
return nfserrno(host_error);
}
-
static short
ace2type(struct nfs4_ace *ace)
{
* case NFS4_OK:
* write_response4 coa_resok4;
* default:
- * length4 coa_bytes_copied;
+ * length4 coa_bytes_copied;
* };
* struct CB_OFFLOAD4args {
* nfs_fh4 coa_fh;
* };
*/
static void encode_offload_info4(struct xdr_stream *xdr,
- __be32 nfserr,
- const struct nfsd4_copy *cp)
+ const struct nfsd4_cb_offload *cbo)
{
__be32 *p;
p = xdr_reserve_space(xdr, 4);
- *p++ = nfserr;
- if (!nfserr) {
+ *p = cbo->co_nfserr;
+ switch (cbo->co_nfserr) {
+ case nfs_ok:
p = xdr_reserve_space(xdr, 4 + 8 + 4 + NFS4_VERIFIER_SIZE);
p = xdr_encode_empty_array(p);
- p = xdr_encode_hyper(p, cp->cp_res.wr_bytes_written);
- *p++ = cpu_to_be32(cp->cp_res.wr_stable_how);
- p = xdr_encode_opaque_fixed(p, cp->cp_res.wr_verifier.data,
+ p = xdr_encode_hyper(p, cbo->co_res.wr_bytes_written);
+ *p++ = cpu_to_be32(cbo->co_res.wr_stable_how);
+ p = xdr_encode_opaque_fixed(p, cbo->co_res.wr_verifier.data,
NFS4_VERIFIER_SIZE);
- } else {
+ break;
+ default:
p = xdr_reserve_space(xdr, 8);
/* We always return success if bytes were written */
p = xdr_encode_hyper(p, 0);
}
static void encode_cb_offload4args(struct xdr_stream *xdr,
- __be32 nfserr,
- const struct knfsd_fh *fh,
- const struct nfsd4_copy *cp,
+ const struct nfsd4_cb_offload *cbo,
struct nfs4_cb_compound_hdr *hdr)
{
__be32 *p;
p = xdr_reserve_space(xdr, 4);
- *p++ = cpu_to_be32(OP_CB_OFFLOAD);
- encode_nfs_fh4(xdr, fh);
- encode_stateid4(xdr, &cp->cp_res.cb_stateid);
- encode_offload_info4(xdr, nfserr, cp);
+ *p = cpu_to_be32(OP_CB_OFFLOAD);
+ encode_nfs_fh4(xdr, &cbo->co_fh);
+ encode_stateid4(xdr, &cbo->co_res.cb_stateid);
+ encode_offload_info4(xdr, cbo);
hdr->nops++;
}
const void *data)
{
const struct nfsd4_callback *cb = data;
- const struct nfsd4_copy *cp =
- container_of(cb, struct nfsd4_copy, cp_cb);
+ const struct nfsd4_cb_offload *cbo =
+ container_of(cb, struct nfsd4_cb_offload, co_cb);
struct nfs4_cb_compound_hdr hdr = {
.ident = 0,
.minorversion = cb->cb_clp->cl_minorversion,
encode_cb_compound4args(xdr, &hdr);
encode_cb_sequence4args(xdr, cb, &hdr);
- encode_cb_offload4args(xdr, cp->nfserr, &cp->fh, cp, &hdr);
+ encode_cb_offload4args(xdr, cbo, &hdr);
encode_cb_nops(&hdr);
}
"idle msecs before unmount export from source server");
#endif
-#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
-#include <linux/security.h>
-
-static inline void
-nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval)
-{
- struct inode *inode = d_inode(resfh->fh_dentry);
- int status;
-
- inode_lock(inode);
- status = security_inode_setsecctx(resfh->fh_dentry,
- label->data, label->len);
- inode_unlock(inode);
-
- if (status)
- /*
- * XXX: We should really fail the whole open, but we may
- * already have created a new file, so it may be too
- * late. For now this seems the least of evils:
- */
- bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
-
- return;
-}
-#else
-static inline void
-nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval)
-{ }
-#endif
-
#define NFSDDBG_FACILITY NFSDDBG_PROC
static u32 nfsd_attrmask[] = {
|| open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1);
}
-/*
- * if error occurs when setting the acl, just clear the acl bit
- * in the returned attr bitmap.
- */
-static void
-do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
- struct nfs4_acl *acl, u32 *bmval)
-{
- __be32 status;
-
- status = nfsd4_set_nfs4_acl(rqstp, fhp, acl);
- if (status)
- /*
- * We should probably fail the whole open at this point,
- * but we've already created the file, so it's too late;
- * So this seems the least of evils:
- */
- bmval[0] &= ~FATTR4_WORD0_ACL;
-}
-
static inline void
fh_dup2(struct svc_fh *dst, struct svc_fh *src)
{
struct svc_fh *resfhp, struct nfsd4_open *open)
{
struct iattr *iap = &open->op_iattr;
+ struct nfsd_attrs attrs = {
+ .na_iattr = iap,
+ .na_seclabel = &open->op_label,
+ };
struct dentry *parent, *child;
__u32 v_mtime, v_atime;
struct inode *inode;
if (host_err)
return nfserrno(host_err);
- fh_lock_nested(fhp, I_MUTEX_PARENT);
+ if (is_create_with_attrs(open))
+ nfsd4_acl_to_attr(NF4REG, open->op_acl, &attrs);
+
+ inode_lock_nested(inode, I_MUTEX_PARENT);
child = lookup_one_len(open->op_fname, parent, open->op_fnamelen);
if (IS_ERR(child)) {
if (d_really_is_positive(child)) {
status = nfs_ok;
+ /* NFSv4 protocol requires change attributes even though
+ * no change happened.
+ */
+ fh_fill_both_attrs(fhp);
+
switch (open->op_createmode) {
case NFS4_CREATE_UNCHECKED:
if (!d_is_reg(child))
if (!IS_POSIXACL(inode))
iap->ia_mode &= ~current_umask();
+ fh_fill_pre_attrs(fhp);
status = nfsd4_vfs_create(fhp, child, open);
if (status != nfs_ok)
goto out;
open->op_created = true;
+ fh_fill_post_attrs(fhp);
/* A newly created file already has a file size of zero. */
if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
}
set_attr:
- status = nfsd_create_setattr(rqstp, fhp, resfhp, iap);
+ status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs);
+ if (attrs.na_labelerr)
+ open->op_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+ if (attrs.na_aclerr)
+ open->op_bmval[0] &= ~FATTR4_WORD0_ACL;
out:
- fh_unlock(fhp);
+ inode_unlock(inode);
+ nfsd_attrs_free(&attrs);
if (child && !IS_ERR(child))
dput(child);
fh_drop_write(fhp);
status = nfsd4_create_file(rqstp, current_fh, *resfh, open);
current->fs->umask = 0;
- if (!status && open->op_label.len)
- nfsd4_security_inode_setsecctx(*resfh, &open->op_label, open->op_bmval);
-
/*
* Following rfc 3530 14.2.16, and rfc 5661 18.16.4
* use the returned bitmask to indicate which attributes
if (nfsd4_create_is_exclusive(open->op_createmode) && status == 0)
open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS |
FATTR4_WORD1_TIME_MODIFY);
- } else
- /*
- * Note this may exit with the parent still locked.
- * We will hold the lock until nfsd4_open's final
- * lookup, to prevent renames or unlinks until we've had
- * a chance to an acquire a delegation if appropriate.
- */
+ } else {
status = nfsd_lookup(rqstp, current_fh,
open->op_fname, open->op_fnamelen, *resfh);
+ if (!status)
+ /* NFSv4 protocol requires change attributes even though
+ * no change happened.
+ */
+ fh_fill_both_attrs(current_fh);
+ }
if (status)
goto out;
status = nfsd_check_obj_isreg(*resfh);
if (status)
goto out;
- if (is_create_with_attrs(open) && open->op_acl != NULL)
- do_set_nfs4_acl(rqstp, *resfh, open->op_acl, open->op_bmval);
-
nfsd4_set_open_owner_reply_cache(cstate, open, *resfh);
accmode = NFSD_MAY_NOP;
if (open->op_created ||
open->op_openowner);
open->op_filp = NULL;
+ open->op_rqstp = rqstp;
/* This check required by spec. */
if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
}
status = nfsd4_process_open2(rqstp, resfh, open);
- WARN(status && open->op_created,
- "nfsd4_process_open2 failed to open newly-created file! status=%u\n",
- be32_to_cpu(status));
+ if (status && open->op_created)
+ pr_warn("nfsd4_process_open2 failed to open newly-created file: status=%u\n",
+ be32_to_cpu(status));
if (reclaim && !status)
nn->somebody_reclaimed = true;
out:
union nfsd4_op_u *u)
{
struct nfsd4_create *create = &u->create;
+ struct nfsd_attrs attrs = {
+ .na_iattr = &create->cr_iattr,
+ .na_seclabel = &create->cr_label,
+ };
struct svc_fh resfh;
__be32 status;
dev_t rdev;
if (status)
return status;
+ status = nfsd4_acl_to_attr(create->cr_type, create->cr_acl, &attrs);
current->fs->umask = create->cr_umask;
switch (create->cr_type) {
case NF4LNK:
status = nfsd_symlink(rqstp, &cstate->current_fh,
create->cr_name, create->cr_namelen,
- create->cr_data, &resfh);
+ create->cr_data, &attrs, &resfh);
break;
case NF4BLK:
goto out_umask;
status = nfsd_create(rqstp, &cstate->current_fh,
create->cr_name, create->cr_namelen,
- &create->cr_iattr, S_IFBLK, rdev, &resfh);
+ &attrs, S_IFBLK, rdev, &resfh);
break;
case NF4CHR:
goto out_umask;
status = nfsd_create(rqstp, &cstate->current_fh,
create->cr_name, create->cr_namelen,
- &create->cr_iattr,S_IFCHR, rdev, &resfh);
+ &attrs, S_IFCHR, rdev, &resfh);
break;
case NF4SOCK:
status = nfsd_create(rqstp, &cstate->current_fh,
create->cr_name, create->cr_namelen,
- &create->cr_iattr, S_IFSOCK, 0, &resfh);
+ &attrs, S_IFSOCK, 0, &resfh);
break;
case NF4FIFO:
status = nfsd_create(rqstp, &cstate->current_fh,
create->cr_name, create->cr_namelen,
- &create->cr_iattr, S_IFIFO, 0, &resfh);
+ &attrs, S_IFIFO, 0, &resfh);
break;
case NF4DIR:
create->cr_iattr.ia_valid &= ~ATTR_SIZE;
status = nfsd_create(rqstp, &cstate->current_fh,
create->cr_name, create->cr_namelen,
- &create->cr_iattr, S_IFDIR, 0, &resfh);
+ &attrs, S_IFDIR, 0, &resfh);
break;
default:
if (status)
goto out;
- if (create->cr_label.len)
- nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval);
-
- if (create->cr_acl != NULL)
- do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
- create->cr_bmval);
-
- fh_unlock(&cstate->current_fh);
+ if (attrs.na_labelerr)
+ create->cr_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+ if (attrs.na_aclerr)
+ create->cr_bmval[0] &= ~FATTR4_WORD0_ACL;
set_change_info(&create->cr_cinfo, &cstate->current_fh);
fh_dup2(&cstate->current_fh, &resfh);
out:
fh_put(&resfh);
out_umask:
current->fs->umask = 0;
+ nfsd_attrs_free(&attrs);
return status;
}
return nfserr_grace;
status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
remove->rm_name, remove->rm_namelen);
- if (!status) {
- fh_unlock(&cstate->current_fh);
+ if (!status)
set_change_info(&remove->rm_cinfo, &cstate->current_fh);
- }
return status;
}
&exp, &dentry);
if (err)
return err;
- fh_unlock(&cstate->current_fh);
if (d_really_is_negative(dentry)) {
exp_put(exp);
err = nfserr_noent;
union nfsd4_op_u *u)
{
struct nfsd4_setattr *setattr = &u->setattr;
+ struct nfsd_attrs attrs = {
+ .na_iattr = &setattr->sa_iattr,
+ .na_seclabel = &setattr->sa_label,
+ };
+ struct inode *inode;
__be32 status = nfs_ok;
int err;
if (status)
goto out;
- if (setattr->sa_acl != NULL)
- status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
- setattr->sa_acl);
- if (status)
- goto out;
- if (setattr->sa_label.len)
- status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh,
- &setattr->sa_label);
+ inode = cstate->current_fh.fh_dentry->d_inode;
+ status = nfsd4_acl_to_attr(S_ISDIR(inode->i_mode) ? NF4DIR : NF4REG,
+ setattr->sa_acl, &attrs);
+
if (status)
goto out;
- status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
+ status = nfsd_setattr(rqstp, &cstate->current_fh, &attrs,
0, (time64_t)0);
+ if (!status)
+ status = nfserrno(attrs.na_labelerr);
out:
+ nfsd_attrs_free(&attrs);
fh_drop_write(&cstate->current_fh);
return status;
}
return status;
}
-void nfs4_put_copy(struct nfsd4_copy *copy)
+static void nfs4_put_copy(struct nfsd4_copy *copy)
{
if (!refcount_dec_and_test(©->refcount))
return;
+ kfree(copy->cp_src);
kfree(copy);
}
-static bool
-check_and_set_stop_copy(struct nfsd4_copy *copy)
-{
- bool value;
-
- spin_lock(©->cp_clp->async_lock);
- value = copy->stopped;
- if (!copy->stopped)
- copy->stopped = true;
- spin_unlock(©->cp_clp->async_lock);
- return value;
-}
-
static void nfsd4_stop_copy(struct nfsd4_copy *copy)
{
- /* only 1 thread should stop the copy */
- if (!check_and_set_stop_copy(copy))
+ if (!test_and_set_bit(NFSD4_COPY_F_STOPPED, ©->cp_flags))
kthread_stop(copy->copy_task);
nfs4_put_copy(copy);
}
return 0;
}
if (work) {
- strncpy(work->nsui_ipaddr, ipaddr, sizeof(work->nsui_ipaddr));
+ strlcpy(work->nsui_ipaddr, ipaddr, sizeof(work->nsui_ipaddr) - 1);
refcount_set(&work->nsui_refcnt, 2);
work->nsui_busy = true;
list_add_tail(&work->nsui_list, &nn->nfsd_ssc_mount_list);
if (status)
goto out;
- status = nfsd4_interssc_connect(©->cp_src, rqstp, mount);
+ status = nfsd4_interssc_connect(copy->cp_src, rqstp, mount);
if (status)
goto out;
}
static void
-nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
+nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp,
struct nfsd_file *dst)
{
bool found = false;
struct nfsd4_ssc_umount_item *ni = NULL;
struct nfsd_net *nn = net_generic(dst->nf_net, nfsd_net_id);
- nfs42_ssc_close(src->nf_file);
+ nfs42_ssc_close(filp);
nfsd_file_put(dst);
- fput(src->nf_file);
+ fput(filp);
if (!nn) {
mntput(ss_mnt);
}
static void
-nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
+nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp,
struct nfsd_file *dst)
{
}
static void nfsd4_cb_offload_release(struct nfsd4_callback *cb)
{
- struct nfsd4_copy *copy = container_of(cb, struct nfsd4_copy, cp_cb);
+ struct nfsd4_cb_offload *cbo =
+ container_of(cb, struct nfsd4_cb_offload, co_cb);
- nfs4_put_copy(copy);
+ kfree(cbo);
}
static int nfsd4_cb_offload_done(struct nfsd4_callback *cb,
static void nfsd4_init_copy_res(struct nfsd4_copy *copy, bool sync)
{
copy->cp_res.wr_stable_how =
- copy->committed ? NFS_FILE_SYNC : NFS_UNSTABLE;
- copy->cp_synchronous = sync;
+ test_bit(NFSD4_COPY_F_COMMITTED, ©->cp_flags) ?
+ NFS_FILE_SYNC : NFS_UNSTABLE;
+ nfsd4_copy_set_sync(copy, sync);
gen_boot_verifier(©->cp_res.wr_verifier, copy->cp_clp->net);
}
-static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)
+static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy,
+ struct file *dst,
+ struct file *src)
{
- struct file *dst = copy->nf_dst->nf_file;
- struct file *src = copy->nf_src->nf_file;
errseq_t since;
ssize_t bytes_copied = 0;
u64 bytes_total = copy->cp_count;
copy->cp_res.wr_bytes_written += bytes_copied;
src_pos += bytes_copied;
dst_pos += bytes_copied;
- } while (bytes_total > 0 && !copy->cp_synchronous);
+ } while (bytes_total > 0 && nfsd4_copy_is_async(copy));
/* for a non-zero asynchronous copy do a commit of data */
- if (!copy->cp_synchronous && copy->cp_res.wr_bytes_written > 0) {
+ if (nfsd4_copy_is_async(copy) && copy->cp_res.wr_bytes_written > 0) {
since = READ_ONCE(dst->f_wb_err);
status = vfs_fsync_range(dst, copy->cp_dst_pos,
copy->cp_res.wr_bytes_written, 0);
if (!status)
status = filemap_check_wb_err(dst->f_mapping, since);
if (!status)
- copy->committed = true;
+ set_bit(NFSD4_COPY_F_COMMITTED, ©->cp_flags);
}
return bytes_copied;
}
-static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync)
+static __be32 nfsd4_do_copy(struct nfsd4_copy *copy,
+ struct file *src, struct file *dst,
+ bool sync)
{
__be32 status;
ssize_t bytes;
- bytes = _nfsd_copy_file_range(copy);
+ bytes = _nfsd_copy_file_range(copy, dst, src);
+
/* for async copy, we ignore the error, client can always retry
* to get the error
*/
nfsd4_init_copy_res(copy, sync);
status = nfs_ok;
}
-
- if (!copy->cp_intra) /* Inter server SSC */
- nfsd4_cleanup_inter_ssc(copy->ss_mnt, copy->nf_src,
- copy->nf_dst);
- else
- nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst);
-
return status;
}
dst->cp_src_pos = src->cp_src_pos;
dst->cp_dst_pos = src->cp_dst_pos;
dst->cp_count = src->cp_count;
- dst->cp_synchronous = src->cp_synchronous;
+ dst->cp_flags = src->cp_flags;
memcpy(&dst->cp_res, &src->cp_res, sizeof(src->cp_res));
memcpy(&dst->fh, &src->fh, sizeof(src->fh));
dst->cp_clp = src->cp_clp;
dst->nf_dst = nfsd_file_get(src->nf_dst);
- dst->cp_intra = src->cp_intra;
- if (src->cp_intra) /* for inter, file_src doesn't exist yet */
+ /* for inter, nf_src doesn't exist yet */
+ if (!nfsd4_ssc_is_inter(src))
dst->nf_src = nfsd_file_get(src->nf_src);
memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid));
- memcpy(&dst->cp_src, &src->cp_src, sizeof(struct nl4_server));
+ memcpy(dst->cp_src, src->cp_src, sizeof(struct nl4_server));
memcpy(&dst->stateid, &src->stateid, sizeof(src->stateid));
memcpy(&dst->c_fh, &src->c_fh, sizeof(src->c_fh));
dst->ss_mnt = src->ss_mnt;
{
nfs4_free_copy_state(copy);
nfsd_file_put(copy->nf_dst);
- if (copy->cp_intra)
+ if (!nfsd4_ssc_is_inter(copy))
nfsd_file_put(copy->nf_src);
spin_lock(©->cp_clp->async_lock);
list_del(©->copies);
nfs4_put_copy(copy);
}
+static void nfsd4_send_cb_offload(struct nfsd4_copy *copy, __be32 nfserr)
+{
+ struct nfsd4_cb_offload *cbo;
+
+ cbo = kzalloc(sizeof(*cbo), GFP_KERNEL);
+ if (!cbo)
+ return;
+
+ memcpy(&cbo->co_res, ©->cp_res, sizeof(copy->cp_res));
+ memcpy(&cbo->co_fh, ©->fh, sizeof(copy->fh));
+ cbo->co_nfserr = nfserr;
+
+ nfsd4_init_cb(&cbo->co_cb, copy->cp_clp, &nfsd4_cb_offload_ops,
+ NFSPROC4_CLNT_CB_OFFLOAD);
+ trace_nfsd_cb_offload(copy->cp_clp, &cbo->co_res.cb_stateid,
+ &cbo->co_fh, copy->cp_count, nfserr);
+ nfsd4_run_cb(&cbo->co_cb);
+}
+
+/**
+ * nfsd4_do_async_copy - kthread function for background server-side COPY
+ * @data: arguments for COPY operation
+ *
+ * Return values:
+ * %0: Copy operation is done.
+ */
static int nfsd4_do_async_copy(void *data)
{
struct nfsd4_copy *copy = (struct nfsd4_copy *)data;
- struct nfsd4_copy *cb_copy;
+ __be32 nfserr;
- if (!copy->cp_intra) { /* Inter server SSC */
- copy->nf_src = kzalloc(sizeof(struct nfsd_file), GFP_KERNEL);
- if (!copy->nf_src) {
- copy->nfserr = nfserr_serverfault;
- nfsd4_interssc_disconnect(copy->ss_mnt);
- goto do_callback;
- }
- copy->nf_src->nf_file = nfs42_ssc_open(copy->ss_mnt, ©->c_fh,
- ©->stateid);
- if (IS_ERR(copy->nf_src->nf_file)) {
- copy->nfserr = nfserr_offload_denied;
+ if (nfsd4_ssc_is_inter(copy)) {
+ struct file *filp;
+
+ filp = nfs42_ssc_open(copy->ss_mnt, ©->c_fh,
+ ©->stateid);
+ if (IS_ERR(filp)) {
+ nfserr = nfserr_offload_denied;
nfsd4_interssc_disconnect(copy->ss_mnt);
goto do_callback;
}
+ nfserr = nfsd4_do_copy(copy, filp, copy->nf_dst->nf_file,
+ false);
+ nfsd4_cleanup_inter_ssc(copy->ss_mnt, filp, copy->nf_dst);
+ } else {
+ nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file,
+ copy->nf_dst->nf_file, false);
+ nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst);
}
- copy->nfserr = nfsd4_do_copy(copy, 0);
do_callback:
- cb_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
- if (!cb_copy)
- goto out;
- refcount_set(&cb_copy->refcount, 1);
- memcpy(&cb_copy->cp_res, ©->cp_res, sizeof(copy->cp_res));
- cb_copy->cp_clp = copy->cp_clp;
- cb_copy->nfserr = copy->nfserr;
- memcpy(&cb_copy->fh, ©->fh, sizeof(copy->fh));
- nfsd4_init_cb(&cb_copy->cp_cb, cb_copy->cp_clp,
- &nfsd4_cb_offload_ops, NFSPROC4_CLNT_CB_OFFLOAD);
- trace_nfsd_cb_offload(copy->cp_clp, ©->cp_res.cb_stateid,
- ©->fh, copy->cp_count, copy->nfserr);
- nfsd4_run_cb(&cb_copy->cp_cb);
-out:
- if (!copy->cp_intra)
- kfree(copy->nf_src);
+ nfsd4_send_cb_offload(copy, nfserr);
cleanup_async_copy(copy);
return 0;
}
__be32 status;
struct nfsd4_copy *async_copy = NULL;
- if (!copy->cp_intra) { /* Inter server SSC */
- if (!inter_copy_offload_enable || copy->cp_synchronous) {
+ if (nfsd4_ssc_is_inter(copy)) {
+ if (!inter_copy_offload_enable || nfsd4_copy_is_sync(copy)) {
status = nfserr_notsupp;
goto out;
}
copy->cp_clp = cstate->clp;
memcpy(©->fh, &cstate->current_fh.fh_handle,
sizeof(struct knfsd_fh));
- if (!copy->cp_synchronous) {
+ if (nfsd4_copy_is_async(copy)) {
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
status = nfserrno(-ENOMEM);
async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
if (!async_copy)
goto out_err;
+ async_copy->cp_src = kmalloc(sizeof(*async_copy->cp_src), GFP_KERNEL);
+ if (!async_copy->cp_src)
+ goto out_err;
if (!nfs4_init_copy_state(nn, copy))
goto out_err;
refcount_set(&async_copy->refcount, 1);
wake_up_process(async_copy->copy_task);
status = nfs_ok;
} else {
- status = nfsd4_do_copy(copy, 1);
+ status = nfsd4_do_copy(copy, copy->nf_src->nf_file,
+ copy->nf_dst->nf_file, true);
+ nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst);
}
out:
return status;
if (async_copy)
cleanup_async_copy(async_copy);
status = nfserrno(-ENOMEM);
- if (!copy->cp_intra)
+ if (nfsd4_ssc_is_inter(copy))
nfsd4_interssc_disconnect(copy->ss_mnt);
goto out;
}
/* For now, only return one server address in cpn_src, the
* address used by the client to connect to this server.
*/
- cn->cpn_src.nl4_type = NL4_NETADDR;
+ cn->cpn_src->nl4_type = NL4_NETADDR;
status = nfsd4_set_netaddr((struct sockaddr *)&rqstp->rq_daddr,
- &cn->cpn_src.u.nl4_addr);
+ &cn->cpn_src->u.nl4_addr);
WARN_ON_ONCE(status);
if (status) {
nfs4_put_cpntf_state(nn, cps);
return;
}
putfh = (struct nfsd4_putfh *)&saved_op->u;
- if (!copy->cp_intra)
+ if (nfsd4_ssc_is_inter(copy))
putfh->no_verify = true;
}
}
if (op->opdesc->op_flags & OP_MODIFIES_SOMETHING) {
/*
* Don't execute this op if we couldn't encode a
- * succesful reply:
+ * successful reply:
*/
u32 plen = op->opdesc->op_rsize_bop(rqstp, op);
/*
swap(f2, fp->fi_fds[O_RDWR]);
spin_unlock(&fp->fi_lock);
if (f1)
- nfsd_file_put(f1);
+ nfsd_file_close(f1);
if (f2)
- nfsd_file_put(f2);
+ nfsd_file_close(f2);
}
}
static struct nfs4_delegation *
alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp,
- struct svc_fh *current_fh,
struct nfs4_clnt_odstate *odstate)
{
struct nfs4_delegation *dp;
n = atomic_long_inc_return(&num_delegations);
if (n < 0 || n > max_delegations)
goto out_dec;
- if (delegation_blocked(¤t_fh->fh_handle))
+ if (delegation_blocked(&fp->fi_fhandle))
goto out_dec;
dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg));
if (dp == NULL)
* This type of memory management is somewhat inefficient, but we use it
* anyway since SETCLIENTID is not a common operation.
*/
-static struct nfs4_client *alloc_client(struct xdr_netobj name)
+static struct nfs4_client *alloc_client(struct xdr_netobj name,
+ struct nfsd_net *nn)
{
struct nfs4_client *clp;
int i;
+ if (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients) {
+ mod_delayed_work(laundry_wq, &nn->laundromat_work, 0);
+ return NULL;
+ }
clp = kmem_cache_zalloc(client_slab, GFP_KERNEL);
if (clp == NULL)
return NULL;
atomic_set(&clp->cl_rpc_users, 0);
clp->cl_cb_state = NFSD4_CB_UNKNOWN;
clp->cl_state = NFSD4_ACTIVE;
+ atomic_inc(&nn->nfs4_client_count);
atomic_set(&clp->cl_delegs_in_recall, 0);
INIT_LIST_HEAD(&clp->cl_idhash);
INIT_LIST_HEAD(&clp->cl_openowners);
static void
__destroy_client(struct nfs4_client *clp)
{
+ struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
int i;
struct nfs4_openowner *oo;
struct nfs4_delegation *dp;
nfsd4_shutdown_callback(clp);
if (clp->cl_cb_conn.cb_xprt)
svc_xprt_put(clp->cl_cb_conn.cb_xprt);
+ atomic_add_unless(&nn->nfs4_client_count, -1, 0);
free_client(clp);
wake_up_all(&expiry_wq);
}
static void nfs4_show_superblock(struct seq_file *s, struct nfsd_file *f)
{
- struct inode *inode = f->nf_inode;
+ struct inode *inode = file_inode(f->nf_file);
seq_printf(s, "superblock: \"%02x:%02x:%ld\"",
MAJOR(inode->i_sb->s_dev),
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
struct dentry *dentries[ARRAY_SIZE(client_files)];
- clp = alloc_client(name);
+ clp = alloc_client(name, nn);
if (clp == NULL)
return NULL;
return -ENOMEM;
}
+void nfsd4_init_leases_net(struct nfsd_net *nn)
+{
+ struct sysinfo si;
+ u64 max_clients;
+
+ nn->nfsd4_lease = 90; /* default lease time */
+ nn->nfsd4_grace = 90;
+ nn->somebody_reclaimed = false;
+ nn->track_reclaim_completes = false;
+ nn->clverifier_counter = prandom_u32();
+ nn->clientid_base = prandom_u32();
+ nn->clientid_counter = nn->clientid_base + 1;
+ nn->s2s_cp_cl_id = nn->clientid_counter++;
+
+ atomic_set(&nn->nfs4_client_count, 0);
+ si_meminfo(&si);
+ max_clients = (u64)si.totalram * si.mem_unit / (1024 * 1024 * 1024);
+ max_clients *= NFS4_CLIENTS_PER_GB;
+ nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB);
+}
+
static void init_nfs4_replay(struct nfs4_replay *rp)
{
rp->rp_status = nfserr_serverfault;
.ia_valid = ATTR_SIZE,
.ia_size = 0,
};
+ struct nfsd_attrs attrs = {
+ .na_iattr = &iattr,
+ };
if (!open->op_truncate)
return 0;
if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
return nfserr_inval;
- return nfsd_setattr(rqstp, fh, &iattr, 0, (time64_t)0);
+ return nfsd_setattr(rqstp, fh, &attrs, 0, (time64_t)0);
}
static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
goto out_put_access;
nf->nf_file = open->op_filp;
open->op_filp = NULL;
+ trace_nfsd_file_create(rqstp, access, nf);
}
spin_lock(&fp->fi_lock);
return 0;
}
+/*
+ * It's possible that between opening the dentry and setting the delegation,
+ * that it has been renamed or unlinked. Redo the lookup to verify that this
+ * hasn't happened.
+ */
+static int
+nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp,
+ struct svc_fh *parent)
+{
+ struct svc_export *exp;
+ struct dentry *child;
+ __be32 err;
+
+ err = nfsd_lookup_dentry(open->op_rqstp, parent,
+ open->op_fname, open->op_fnamelen,
+ &exp, &child);
+
+ if (err)
+ return -EAGAIN;
+
+ dput(child);
+ if (child != file_dentry(fp->fi_deleg_file->nf_file))
+ return -EAGAIN;
+
+ return 0;
+}
+
static struct nfs4_delegation *
-nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
- struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
+nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
+ struct svc_fh *parent)
{
int status = 0;
+ struct nfs4_client *clp = stp->st_stid.sc_client;
+ struct nfs4_file *fp = stp->st_stid.sc_file;
+ struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
struct nfs4_delegation *dp;
struct nfsd_file *nf;
struct file_lock *fl;
return ERR_PTR(status);
status = -ENOMEM;
- dp = alloc_init_deleg(clp, fp, fh, odstate);
+ dp = alloc_init_deleg(clp, fp, odstate);
if (!dp)
goto out_delegees;
locks_free_lock(fl);
if (status)
goto out_clnt_odstate;
+
+ if (parent) {
+ status = nfsd4_verify_deleg_dentry(open, fp, parent);
+ if (status)
+ goto out_unlock;
+ }
+
status = nfsd4_check_conflicting_opens(clp, fp);
if (status)
goto out_unlock;
* proper support for them.
*/
static void
-nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
- struct nfs4_ol_stateid *stp)
+nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
+ struct svc_fh *currentfh)
{
struct nfs4_delegation *dp;
struct nfs4_openowner *oo = openowner(stp->st_stateowner);
struct nfs4_client *clp = stp->st_stid.sc_client;
+ struct svc_fh *parent = NULL;
int cb_up;
int status = 0;
goto out_no_deleg;
break;
case NFS4_OPEN_CLAIM_NULL:
+ parent = currentfh;
+ fallthrough;
case NFS4_OPEN_CLAIM_FH:
/*
* Let's not give out any delegations till everyone's
default:
goto out_no_deleg;
}
- dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate);
+ dp = nfs4_set_delegation(open, stp, parent);
if (IS_ERR(dp))
goto out_no_deleg;
* Attempt to hand out a delegation. No error return, because the
* OPEN succeeds even if we fail.
*/
- nfs4_open_delegation(current_fh, open, stp);
+ nfs4_open_delegation(open, stp, &resp->cstate.current_fh);
nodeleg:
status = nfs_ok;
trace_nfsd_open(&stp->st_stid.sc_stateid);
nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
struct laundry_time *lt)
{
+ unsigned int maxreap, reapcnt = 0;
struct list_head *pos, *next;
struct nfs4_client *clp;
+ maxreap = (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients) ?
+ NFSD_CLIENT_MAX_TRIM_PER_RUN : 0;
INIT_LIST_HEAD(reaplist);
spin_lock(&nn->client_lock);
list_for_each_safe(pos, next, &nn->client_lru) {
break;
if (!atomic_read(&clp->cl_rpc_users))
clp->cl_state = NFSD4_COURTESY;
- if (!client_has_state(clp) ||
- ktime_get_boottime_seconds() >=
- (clp->cl_time + NFSD_COURTESY_CLIENT_TIMEOUT))
+ if (!client_has_state(clp))
goto exp_client;
- if (nfs4_anylock_blockers(clp)) {
+ if (!nfs4_anylock_blockers(clp))
+ if (reapcnt >= maxreap)
+ continue;
exp_client:
- if (!mark_client_expired_locked(clp))
- list_add(&clp->cl_lru, reaplist);
+ if (!mark_client_expired_locked(clp)) {
+ list_add(&clp->cl_lru, reaplist);
+ reapcnt++;
}
}
spin_unlock(&nn->client_lock);
static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
{
struct nfsd_file *nf;
+ struct inode *inode;
__be32 err;
err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf);
if (err)
return err;
- fh_lock(fhp); /* to block new leases till after test_lock: */
- err = nfserrno(nfsd_open_break_lease(fhp->fh_dentry->d_inode,
- NFSD_MAY_READ));
+ inode = fhp->fh_dentry->d_inode;
+ inode_lock(inode); /* to block new leases till after test_lock: */
+ err = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ));
if (err)
goto out;
lock->fl_file = nf->nf_file;
err = nfserrno(vfs_test_lock(nf->nf_file, lock));
lock->fl_file = NULL;
out:
- fh_unlock(fhp);
+ inode_unlock(inode);
nfsd_file_put(nf);
return err;
}
for (i = 0; i < test_stateid->ts_num_ids; i++) {
stateid = svcxdr_tmpalloc(argp, sizeof(*stateid));
if (!stateid)
- return nfserrno(-ENOMEM); /* XXX: not jukebox? */
+ return nfserr_jukebox;
INIT_LIST_HEAD(&stateid->ts_id_list);
list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list);
status = nfsd4_decode_stateid4(argp, &stateid->ts_id_stateid);
static __be32
nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
{
+ u32 consecutive, i, count, sync;
struct nl4_server *ns_dummy;
- u32 consecutive, i, count;
__be32 status;
status = nfsd4_decode_stateid4(argp, ©->cp_src_stateid);
/* ca_consecutive: we always do consecutive copies */
if (xdr_stream_decode_u32(argp->xdr, &consecutive) < 0)
return nfserr_bad_xdr;
- if (xdr_stream_decode_u32(argp->xdr, ©->cp_synchronous) < 0)
+ if (xdr_stream_decode_bool(argp->xdr, &sync) < 0)
return nfserr_bad_xdr;
+ nfsd4_copy_set_sync(copy, sync);
if (xdr_stream_decode_u32(argp->xdr, &count) < 0)
return nfserr_bad_xdr;
- copy->cp_intra = false;
+ copy->cp_src = svcxdr_tmpalloc(argp, sizeof(*copy->cp_src));
+ if (copy->cp_src == NULL)
+ return nfserr_jukebox;
if (count == 0) { /* intra-server copy */
- copy->cp_intra = true;
+ __set_bit(NFSD4_COPY_F_INTRA, ©->cp_flags);
return nfs_ok;
}
/* decode all the supplied server addresses but use only the first */
- status = nfsd4_decode_nl4_server(argp, ©->cp_src);
+ status = nfsd4_decode_nl4_server(argp, copy->cp_src);
if (status)
return status;
ns_dummy = kmalloc(sizeof(struct nl4_server), GFP_KERNEL);
if (ns_dummy == NULL)
- return nfserrno(-ENOMEM); /* XXX: jukebox? */
+ return nfserr_jukebox;
for (i = 0; i < count - 1; i++) {
status = nfsd4_decode_nl4_server(argp, ns_dummy);
if (status) {
{
__be32 status;
+ cn->cpn_src = svcxdr_tmpalloc(argp, sizeof(*cn->cpn_src));
+ if (cn->cpn_src == NULL)
+ return nfserr_jukebox;
+ cn->cpn_dst = svcxdr_tmpalloc(argp, sizeof(*cn->cpn_dst));
+ if (cn->cpn_dst == NULL)
+ return nfserr_jukebox;
+
status = nfsd4_decode_stateid4(argp, &cn->cpn_src_stateid);
if (status)
return status;
- return nfsd4_decode_nl4_server(argp, &cn->cpn_dst);
+ return nfsd4_decode_nl4_server(argp, cn->cpn_dst);
}
static __be32
struct kstat stat;
struct svc_fh *tempfh = NULL;
struct kstatfs statfs;
- __be32 *p;
+ __be32 *p, *attrlen_p;
int starting_len = xdr->buf->len;
int attrlen_offset;
- __be32 attrlen;
u32 dummy;
u64 dummy64;
u32 rdattr_err = 0;
goto out;
attrlen_offset = xdr->buf->len;
- p = xdr_reserve_space(xdr, 4);
- if (!p)
+ attrlen_p = xdr_reserve_space(xdr, XDR_UNIT);
+ if (!attrlen_p)
goto out_resource;
- p++; /* to be backfilled later */
if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
u32 supp[3];
*p++ = cpu_to_be32(err == 0);
}
- attrlen = htonl(xdr->buf->len - attrlen_offset - 4);
- write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4);
+ *attrlen_p = cpu_to_be32(xdr->buf->len - attrlen_offset - XDR_UNIT);
status = nfs_ok;
out:
struct xdr_stream *xdr = resp->xdr;
struct xdr_buf *buf = xdr->buf;
int status, space_left;
- u32 eof;
__be32 nfserr;
- __be32 *p = xdr->p - 2;
/* Make sure there will be room for padding if needed */
if (xdr->end - xdr->p < 1)
return nfserr_resource;
nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp,
- file, read->rd_offset, &maxcount, &eof);
+ file, read->rd_offset, &maxcount,
+ &read->rd_eof);
read->rd_length = maxcount;
if (nfserr)
goto out_err;
goto out_err;
}
- *(p++) = htonl(eof);
- *(p++) = htonl(maxcount);
-
buf->page_len = maxcount;
buf->len += maxcount;
xdr->page_ptr += (buf->page_base + maxcount + PAGE_SIZE - 1)
struct file *file, unsigned long maxcount)
{
struct xdr_stream *xdr = resp->xdr;
- u32 eof;
- int starting_len = xdr->buf->len - 8;
+ unsigned int starting_len = xdr->buf->len;
+ __be32 zero = xdr_zero;
__be32 nfserr;
- __be32 tmp;
- int pad;
read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, maxcount);
if (read->rd_vlen < 0)
nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
resp->rqstp->rq_vec, read->rd_vlen, &maxcount,
- &eof);
+ &read->rd_eof);
read->rd_length = maxcount;
if (nfserr)
return nfserr;
- if (svc_encode_result_payload(resp->rqstp, starting_len + 8, maxcount))
+ if (svc_encode_result_payload(resp->rqstp, starting_len, maxcount))
return nfserr_io;
- xdr_truncate_encode(xdr, starting_len + 8 + xdr_align_size(maxcount));
-
- tmp = htonl(eof);
- write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4);
- tmp = htonl(maxcount);
- write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
-
- tmp = xdr_zero;
- pad = (maxcount&3) ? 4 - (maxcount&3) : 0;
- write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount,
- &tmp, pad);
- return 0;
+ xdr_truncate_encode(xdr, starting_len + xdr_align_size(maxcount));
+ write_bytes_to_xdr_buf(xdr->buf, starting_len + maxcount, &zero,
+ xdr_pad_size(maxcount));
+ return nfs_ok;
}
static __be32
nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_read *read)
{
+ bool splice_ok = test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags);
unsigned long maxcount;
struct xdr_stream *xdr = resp->xdr;
struct file *file;
p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
if (!p) {
- WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags));
+ WARN_ON_ONCE(splice_ok);
return nfserr_resource;
}
- if (resp->xdr->buf->page_len &&
- test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) {
+ if (resp->xdr->buf->page_len && splice_ok) {
WARN_ON_ONCE(1);
return nfserr_resource;
}
maxcount = min_t(unsigned long, read->rd_length,
(xdr->buf->buflen - xdr->buf->len));
- if (file->f_op->splice_read &&
- test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
+ if (file->f_op->splice_read && splice_ok)
nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
else
nfserr = nfsd4_encode_readv(resp, read, file, maxcount);
-
- if (nfserr)
+ if (nfserr) {
xdr_truncate_encode(xdr, starting_len);
+ return nfserr;
+ }
- return nfserr;
+ p = xdr_encode_bool(p, read->rd_eof);
+ *p = cpu_to_be32(read->rd_length);
+ return nfs_ok;
}
static __be32
nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
{
- int maxcount;
- __be32 wire_count;
- int zero = 0;
+ __be32 *p, *maxcount_p, zero = xdr_zero;
struct xdr_stream *xdr = resp->xdr;
int length_offset = xdr->buf->len;
- int status;
- __be32 *p;
+ int maxcount, status;
- p = xdr_reserve_space(xdr, 4);
- if (!p)
+ maxcount_p = xdr_reserve_space(xdr, XDR_UNIT);
+ if (!maxcount_p)
return nfserr_resource;
maxcount = PAGE_SIZE;
nfserr = nfserrno(status);
goto out_err;
}
-
- wire_count = htonl(maxcount);
- write_bytes_to_xdr_buf(xdr->buf, length_offset, &wire_count, 4);
- xdr_truncate_encode(xdr, length_offset + 4 + ALIGN(maxcount, 4));
- if (maxcount & 3)
- write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount,
- &zero, 4 - (maxcount&3));
- return 0;
+ *maxcount_p = cpu_to_be32(maxcount);
+ xdr_truncate_encode(xdr, length_offset + 4 + xdr_align_size(maxcount));
+ write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount, &zero,
+ xdr_pad_size(maxcount));
+ return nfs_ok;
out_err:
xdr_truncate_encode(xdr, length_offset);
__be32 *p;
nfserr = nfsd42_encode_write_res(resp, ©->cp_res,
- !!copy->cp_synchronous);
+ nfsd4_copy_is_sync(copy));
if (nfserr)
return nfserr;
p = xdr_reserve_space(resp->xdr, 4 + 4);
*p++ = xdr_one; /* cr_consecutive */
- *p++ = cpu_to_be32(copy->cp_synchronous);
+ *p = nfsd4_copy_is_sync(copy) ? xdr_one : xdr_zero;
return 0;
}
*p++ = cpu_to_be32(1);
- return nfsd42_encode_nl4_server(resp, &cn->cpn_src);
+ nfserr = nfsd42_encode_nl4_server(resp, cn->cpn_src);
+ return nfserr;
}
static __be32
so->so_replay.rp_buf, len);
}
status:
- /* Note that op->status is already in network byte order: */
- write_bytes_to_xdr_buf(xdr->buf, post_err_offset - 4, &op->status, 4);
+ *p = op->status;
}
/*
#include "state.h"
#include "netns.h"
#include "pnfs.h"
+#include "filecache.h"
/*
* We have a single directory with several nodes in it.
NFSD_Ports,
NFSD_MaxBlkSize,
NFSD_MaxConnections,
+ NFSD_Filecache,
NFSD_SupportedEnctypes,
/*
* The below MUST come last. Otherwise we leave a hole in nfsd_files[]
.release = single_release,
};
+static const struct file_operations filecache_ops = {
+ .open = nfsd_file_cache_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/*----------------------------------------------------------------------------*/
/*
* payload - write methods
}
/* Now write current state into reply buffer */
- len = 0;
sep = "";
remaining = SIMPLE_TRANSACTION_LIMIT;
for (num=2 ; num <= 4 ; num++) {
[NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
[NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
[NFSD_MaxConnections] = {"max_connections", &transaction_ops, S_IWUSR|S_IRUGO},
+ [NFSD_Filecache] = {"filecache", &filecache_ops, S_IRUGO},
#if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
[NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO},
#endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
retval = nfsd_reply_cache_init(nn);
if (retval)
goto out_drc_error;
- nn->nfsd4_lease = 90; /* default lease time */
- nn->nfsd4_grace = 90;
- nn->somebody_reclaimed = false;
- nn->track_reclaim_completes = false;
- nn->clverifier_counter = prandom_u32();
- nn->clientid_base = prandom_u32();
- nn->clientid_counter = nn->clientid_base + 1;
- nn->s2s_cp_cl_id = nn->clientid_counter++;
+ nfsd4_init_leases_net(nn);
get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key));
seqlock_init(&nn->writeverf_lock);
static int __init init_nfsd(void)
{
int retval;
- printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
retval = nfsd4_init_slabs();
if (retval)
#define NFSD_LAUNDROMAT_MINTIMEOUT 1 /* seconds */
#define NFSD_COURTESY_CLIENT_TIMEOUT (24 * 60 * 60) /* seconds */
+#define NFSD_CLIENT_MAX_TRIM_PER_RUN 128
+#define NFS4_CLIENTS_PER_GB 1024
/*
* The following attributes are currently not supported by the NFSv4 server:
extern void nfsd4_ssc_init_umount_work(struct nfsd_net *nn);
#endif
+extern void nfsd4_init_leases_net(struct nfsd_net *nn);
+
#else /* CONFIG_NFSD_V4 */
static inline int nfsd4_is_junction(struct dentry *dentry)
{
return 0;
}
+static inline void nfsd4_init_leases_net(struct nfsd_net *nn) {};
+
#define register_cld_notifier() 0
#define unregister_cld_notifier() do { } while(0)
struct dentry *dentry;
__be32 error;
- dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
-
if (!fhp->fh_dentry) {
error = nfsd_set_fh_dentry(rqstp, fhp);
if (error)
}
dentry = fhp->fh_dentry;
exp = fhp->fh_export;
+
+ trace_nfsd_fh_verify(rqstp, fhp, type, access);
+
/*
* We still have to do all these permission checks, even when
* fh_dentry is already set:
if (ref_fh == fhp)
fh_put(ref_fh);
- if (fhp->fh_locked || fhp->fh_dentry) {
+ if (fhp->fh_dentry) {
printk(KERN_ERR "fh_compose: fh %pd2 not initialized!\n",
dentry);
}
nfsd4_change_attribute(&fhp->fh_post_attr, inode);
}
+/**
+ * fh_fill_both_attrs - Fill pre-op and post-op attributes
+ * @fhp: file handle to be updated
+ *
+ * This is used when the directory wasn't changed, but wcc attributes
+ * are needed anyway.
+ */
+void fh_fill_both_attrs(struct svc_fh *fhp)
+{
+ fh_fill_post_attrs(fhp);
+ if (!fhp->fh_post_saved)
+ return;
+ fhp->fh_pre_change = fhp->fh_post_change;
+ fhp->fh_pre_mtime = fhp->fh_post_attr.mtime;
+ fhp->fh_pre_ctime = fhp->fh_post_attr.ctime;
+ fhp->fh_pre_size = fhp->fh_post_attr.size;
+ fhp->fh_pre_saved = true;
+}
+
/*
* Release a file handle.
*/
struct dentry * dentry = fhp->fh_dentry;
struct svc_export * exp = fhp->fh_export;
if (dentry) {
- fh_unlock(fhp);
fhp->fh_dentry = NULL;
dput(dentry);
fh_clear_pre_post_attrs(fhp);
struct dentry * fh_dentry; /* validated dentry */
struct svc_export * fh_export; /* export pointer */
- bool fh_locked; /* inode locked by us */
bool fh_want_write; /* remount protection taken */
bool fh_no_wcc; /* no wcc data needed */
bool fh_no_atomic_attr;
bool fh_post_saved; /* post-op attrs saved */
bool fh_pre_saved; /* pre-op attrs saved */
- /* Pre-op attributes saved during fh_lock */
+ /* Pre-op attributes saved when inode is locked */
__u64 fh_pre_size; /* size before operation */
struct timespec64 fh_pre_mtime; /* mtime before oper */
struct timespec64 fh_pre_ctime; /* ctime before oper */
*/
u64 fh_pre_change;
- /* Post-op attributes saved in fh_unlock */
+ /* Post-op attributes saved in fh_fill_post_attrs() */
struct kstat fh_post_attr; /* full attrs after operation */
u64 fh_post_change; /* nfsv4 change; see above */
} svc_fh;
static __inline__ struct svc_fh *
fh_copy(struct svc_fh *dst, struct svc_fh *src)
{
- WARN_ON(src->fh_dentry || src->fh_locked);
-
+ WARN_ON(src->fh_dentry);
+
*dst = *src;
return dst;
}
extern void fh_fill_pre_attrs(struct svc_fh *fhp);
extern void fh_fill_post_attrs(struct svc_fh *fhp);
-
-
-/*
- * Lock a file handle/inode
- * NOTE: both fh_lock and fh_unlock are done "by hand" in
- * vfs.c:nfsd_rename as it needs to grab 2 i_mutex's at once
- * so, any changes here should be reflected there.
- */
-
-static inline void
-fh_lock_nested(struct svc_fh *fhp, unsigned int subclass)
-{
- struct dentry *dentry = fhp->fh_dentry;
- struct inode *inode;
-
- BUG_ON(!dentry);
-
- if (fhp->fh_locked) {
- printk(KERN_WARNING "fh_lock: %pd2 already locked!\n",
- dentry);
- return;
- }
-
- inode = d_inode(dentry);
- inode_lock_nested(inode, subclass);
- fh_fill_pre_attrs(fhp);
- fhp->fh_locked = true;
-}
-
-static inline void
-fh_lock(struct svc_fh *fhp)
-{
- fh_lock_nested(fhp, I_MUTEX_NORMAL);
-}
-
-/*
- * Unlock a file handle/inode
- */
-static inline void
-fh_unlock(struct svc_fh *fhp)
-{
- if (fhp->fh_locked) {
- fh_fill_post_attrs(fhp);
- inode_unlock(d_inode(fhp->fh_dentry));
- fhp->fh_locked = false;
- }
-}
-
+extern void fh_fill_both_attrs(struct svc_fh *fhp);
#endif /* _LINUX_NFSD_NFSFH_H */
struct nfsd_sattrargs *argp = rqstp->rq_argp;
struct nfsd_attrstat *resp = rqstp->rq_resp;
struct iattr *iap = &argp->attrs;
+ struct nfsd_attrs attrs = {
+ .na_iattr = iap,
+ };
struct svc_fh *fhp;
dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n",
}
}
- resp->status = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0);
+ resp->status = nfsd_setattr(rqstp, fhp, &attrs, 0, (time64_t)0);
if (resp->status != nfs_ok)
goto out;
svc_fh *dirfhp = &argp->fh;
svc_fh *newfhp = &resp->fh;
struct iattr *attr = &argp->attrs;
+ struct nfsd_attrs attrs = {
+ .na_iattr = attr,
+ };
struct inode *inode;
struct dentry *dchild;
int type, mode;
goto done;
}
- fh_lock_nested(dirfhp, I_MUTEX_PARENT);
+ inode_lock_nested(dirfhp->fh_dentry->d_inode, I_MUTEX_PARENT);
dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
if (IS_ERR(dchild)) {
resp->status = nfserrno(PTR_ERR(dchild));
if (!inode) {
/* File doesn't exist. Create it and set attrs */
resp->status = nfsd_create_locked(rqstp, dirfhp, argp->name,
- argp->len, attr, type, rdev,
+ argp->len, &attrs, type, rdev,
newfhp);
} else if (type == S_IFREG) {
dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
*/
attr->ia_valid &= ATTR_SIZE;
if (attr->ia_valid)
- resp->status = nfsd_setattr(rqstp, newfhp, attr, 0,
+ resp->status = nfsd_setattr(rqstp, newfhp, &attrs, 0,
(time64_t)0);
}
out_unlock:
- /* We don't really need to unlock, as fh_put does it. */
- fh_unlock(dirfhp);
+ inode_unlock(dirfhp->fh_dentry->d_inode);
fh_drop_write(dirfhp);
done:
fh_put(dirfhp);
{
struct nfsd_symlinkargs *argp = rqstp->rq_argp;
struct nfsd_stat *resp = rqstp->rq_resp;
+ struct nfsd_attrs attrs = {
+ .na_iattr = &argp->attrs,
+ };
struct svc_fh newfh;
if (argp->tlen > NFS_MAXPATHLEN) {
fh_init(&newfh, NFS_FHSIZE);
resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
- argp->tname, &newfh);
+ argp->tname, &attrs, &newfh);
kfree(argp->tname);
fh_put(&argp->ffh);
{
struct nfsd_createargs *argp = rqstp->rq_argp;
struct nfsd_diropres *resp = rqstp->rq_resp;
+ struct nfsd_attrs attrs = {
+ .na_iattr = &argp->attrs,
+ };
dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
argp->attrs.ia_valid &= ~ATTR_SIZE;
fh_init(&resp->fh, NFS_FHSIZE);
resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
- &argp->attrs, S_IFDIR, 0, &resp->fh);
+ &attrs, S_IFDIR, 0, &resp->fh);
fh_put(&argp->fh);
if (resp->status != nfs_ok)
goto out;
extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn);
void put_nfs4_file(struct nfs4_file *fi);
-extern void nfs4_put_copy(struct nfsd4_copy *copy);
extern struct nfsd4_copy *
find_async_copy(struct nfs4_client *clp, stateid_t *staetid);
extern void nfs4_put_cpntf_state(struct nfsd_net *nn,
__entry->opnum, __entry->status)
);
+#define show_fs_file_type(x) \
+ __print_symbolic(x, \
+ { S_IFLNK, "LNK" }, \
+ { S_IFREG, "REG" }, \
+ { S_IFDIR, "DIR" }, \
+ { S_IFCHR, "CHR" }, \
+ { S_IFBLK, "BLK" }, \
+ { S_IFIFO, "FIFO" }, \
+ { S_IFSOCK, "SOCK" })
+
+TRACE_EVENT(nfsd_fh_verify,
+ TP_PROTO(
+ const struct svc_rqst *rqstp,
+ const struct svc_fh *fhp,
+ umode_t type,
+ int access
+ ),
+ TP_ARGS(rqstp, fhp, type, access),
+ TP_STRUCT__entry(
+ __field(unsigned int, netns_ino)
+ __sockaddr(server, rqstp->rq_xprt->xpt_remotelen)
+ __sockaddr(client, rqstp->rq_xprt->xpt_remotelen)
+ __field(u32, xid)
+ __field(u32, fh_hash)
+ __field(void *, inode)
+ __field(unsigned long, type)
+ __field(unsigned long, access)
+ ),
+ TP_fast_assign(
+ __entry->netns_ino = SVC_NET(rqstp)->ns.inum;
+ __assign_sockaddr(server, &rqstp->rq_xprt->xpt_local,
+ rqstp->rq_xprt->xpt_locallen);
+ __assign_sockaddr(client, &rqstp->rq_xprt->xpt_remote,
+ rqstp->rq_xprt->xpt_remotelen);
+ __entry->xid = be32_to_cpu(rqstp->rq_xid);
+ __entry->fh_hash = knfsd_fh_hash(&fhp->fh_handle);
+ __entry->inode = d_inode(fhp->fh_dentry);
+ __entry->type = type;
+ __entry->access = access;
+ ),
+ TP_printk("xid=0x%08x fh_hash=0x%08x inode=%p type=%s access=%s",
+ __entry->xid, __entry->fh_hash, __entry->inode,
+ show_fs_file_type(__entry->type),
+ show_nfsd_may_flags(__entry->access)
+ )
+);
DECLARE_EVENT_CLASS(nfsd_fh_err_class,
TP_PROTO(struct svc_rqst *rqstp,
__print_flags(val, "|", \
{ 1 << NFSD_FILE_HASHED, "HASHED" }, \
{ 1 << NFSD_FILE_PENDING, "PENDING" }, \
- { 1 << NFSD_FILE_BREAK_READ, "BREAK_READ" }, \
- { 1 << NFSD_FILE_BREAK_WRITE, "BREAK_WRITE" }, \
{ 1 << NFSD_FILE_REFERENCED, "REFERENCED"})
DECLARE_EVENT_CLASS(nfsd_file_class,
TP_PROTO(struct nfsd_file *nf),
TP_ARGS(nf),
TP_STRUCT__entry(
- __field(unsigned int, nf_hashval)
__field(void *, nf_inode)
__field(int, nf_ref)
__field(unsigned long, nf_flags)
__field(struct file *, nf_file)
),
TP_fast_assign(
- __entry->nf_hashval = nf->nf_hashval;
__entry->nf_inode = nf->nf_inode;
__entry->nf_ref = refcount_read(&nf->nf_ref);
__entry->nf_flags = nf->nf_flags;
__entry->nf_may = nf->nf_may;
__entry->nf_file = nf->nf_file;
),
- TP_printk("hash=0x%x inode=%p ref=%d flags=%s may=%s file=%p",
- __entry->nf_hashval,
+ TP_printk("inode=%p ref=%d flags=%s may=%s nf_file=%p",
__entry->nf_inode,
__entry->nf_ref,
show_nf_flags(__entry->nf_flags),
TP_PROTO(struct nfsd_file *nf), \
TP_ARGS(nf))
-DEFINE_NFSD_FILE_EVENT(nfsd_file_alloc);
DEFINE_NFSD_FILE_EVENT(nfsd_file_put_final);
DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash);
DEFINE_NFSD_FILE_EVENT(nfsd_file_put);
-DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_release_locked);
+DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_dispose);
+
+TRACE_EVENT(nfsd_file_alloc,
+ TP_PROTO(
+ const struct nfsd_file *nf
+ ),
+ TP_ARGS(nf),
+ TP_STRUCT__entry(
+ __field(const void *, nf_inode)
+ __field(unsigned long, nf_flags)
+ __field(unsigned long, nf_may)
+ __field(unsigned int, nf_ref)
+ ),
+ TP_fast_assign(
+ __entry->nf_inode = nf->nf_inode;
+ __entry->nf_flags = nf->nf_flags;
+ __entry->nf_ref = refcount_read(&nf->nf_ref);
+ __entry->nf_may = nf->nf_may;
+ ),
+ TP_printk("inode=%p ref=%u flags=%s may=%s",
+ __entry->nf_inode, __entry->nf_ref,
+ show_nf_flags(__entry->nf_flags),
+ show_nfsd_may_flags(__entry->nf_may)
+ )
+);
TRACE_EVENT(nfsd_file_acquire,
- TP_PROTO(struct svc_rqst *rqstp, unsigned int hash,
- struct inode *inode, unsigned int may_flags,
- struct nfsd_file *nf, __be32 status),
+ TP_PROTO(
+ const struct svc_rqst *rqstp,
+ const struct inode *inode,
+ unsigned int may_flags,
+ const struct nfsd_file *nf,
+ __be32 status
+ ),
- TP_ARGS(rqstp, hash, inode, may_flags, nf, status),
+ TP_ARGS(rqstp, inode, may_flags, nf, status),
TP_STRUCT__entry(
__field(u32, xid)
- __field(unsigned int, hash)
- __field(void *, inode)
+ __field(const void *, inode)
__field(unsigned long, may_flags)
- __field(int, nf_ref)
+ __field(unsigned int, nf_ref)
__field(unsigned long, nf_flags)
__field(unsigned long, nf_may)
- __field(struct file *, nf_file)
+ __field(const void *, nf_file)
__field(u32, status)
),
TP_fast_assign(
__entry->xid = be32_to_cpu(rqstp->rq_xid);
- __entry->hash = hash;
__entry->inode = inode;
__entry->may_flags = may_flags;
__entry->nf_ref = nf ? refcount_read(&nf->nf_ref) : 0;
__entry->status = be32_to_cpu(status);
),
- TP_printk("xid=0x%x hash=0x%x inode=%p may_flags=%s ref=%d nf_flags=%s nf_may=%s nf_file=%p status=%u",
- __entry->xid, __entry->hash, __entry->inode,
+ TP_printk("xid=0x%x inode=%p may_flags=%s ref=%u nf_flags=%s nf_may=%s nf_file=%p status=%u",
+ __entry->xid, __entry->inode,
show_nfsd_may_flags(__entry->may_flags),
__entry->nf_ref, show_nf_flags(__entry->nf_flags),
show_nfsd_may_flags(__entry->nf_may),
- __entry->nf_file, __entry->status)
+ __entry->nf_file, __entry->status
+ )
+);
+
+TRACE_EVENT(nfsd_file_create,
+ TP_PROTO(
+ const struct svc_rqst *rqstp,
+ unsigned int may_flags,
+ const struct nfsd_file *nf
+ ),
+
+ TP_ARGS(rqstp, may_flags, nf),
+
+ TP_STRUCT__entry(
+ __field(const void *, nf_inode)
+ __field(const void *, nf_file)
+ __field(unsigned long, may_flags)
+ __field(unsigned long, nf_flags)
+ __field(unsigned long, nf_may)
+ __field(unsigned int, nf_ref)
+ __field(u32, xid)
+ ),
+
+ TP_fast_assign(
+ __entry->nf_inode = nf->nf_inode;
+ __entry->nf_file = nf->nf_file;
+ __entry->may_flags = may_flags;
+ __entry->nf_flags = nf->nf_flags;
+ __entry->nf_may = nf->nf_may;
+ __entry->nf_ref = refcount_read(&nf->nf_ref);
+ __entry->xid = be32_to_cpu(rqstp->rq_xid);
+ ),
+
+ TP_printk("xid=0x%x inode=%p may_flags=%s ref=%u nf_flags=%s nf_may=%s nf_file=%p",
+ __entry->xid, __entry->nf_inode,
+ show_nfsd_may_flags(__entry->may_flags),
+ __entry->nf_ref, show_nf_flags(__entry->nf_flags),
+ show_nfsd_may_flags(__entry->nf_may), __entry->nf_file
+ )
+);
+
+TRACE_EVENT(nfsd_file_insert_err,
+ TP_PROTO(
+ const struct svc_rqst *rqstp,
+ const struct inode *inode,
+ unsigned int may_flags,
+ long error
+ ),
+ TP_ARGS(rqstp, inode, may_flags, error),
+ TP_STRUCT__entry(
+ __field(u32, xid)
+ __field(const void *, inode)
+ __field(unsigned long, may_flags)
+ __field(long, error)
+ ),
+ TP_fast_assign(
+ __entry->xid = be32_to_cpu(rqstp->rq_xid);
+ __entry->inode = inode;
+ __entry->may_flags = may_flags;
+ __entry->error = error;
+ ),
+ TP_printk("xid=0x%x inode=%p may_flags=%s error=%ld",
+ __entry->xid, __entry->inode,
+ show_nfsd_may_flags(__entry->may_flags),
+ __entry->error
+ )
+);
+
+TRACE_EVENT(nfsd_file_cons_err,
+ TP_PROTO(
+ const struct svc_rqst *rqstp,
+ const struct inode *inode,
+ unsigned int may_flags,
+ const struct nfsd_file *nf
+ ),
+ TP_ARGS(rqstp, inode, may_flags, nf),
+ TP_STRUCT__entry(
+ __field(u32, xid)
+ __field(const void *, inode)
+ __field(unsigned long, may_flags)
+ __field(unsigned int, nf_ref)
+ __field(unsigned long, nf_flags)
+ __field(unsigned long, nf_may)
+ __field(const void *, nf_file)
+ ),
+ TP_fast_assign(
+ __entry->xid = be32_to_cpu(rqstp->rq_xid);
+ __entry->inode = inode;
+ __entry->may_flags = may_flags;
+ __entry->nf_ref = refcount_read(&nf->nf_ref);
+ __entry->nf_flags = nf->nf_flags;
+ __entry->nf_may = nf->nf_may;
+ __entry->nf_file = nf->nf_file;
+ ),
+ TP_printk("xid=0x%x inode=%p may_flags=%s ref=%u nf_flags=%s nf_may=%s nf_file=%p",
+ __entry->xid, __entry->inode,
+ show_nfsd_may_flags(__entry->may_flags), __entry->nf_ref,
+ show_nf_flags(__entry->nf_flags),
+ show_nfsd_may_flags(__entry->nf_may), __entry->nf_file
+ )
);
TRACE_EVENT(nfsd_file_open,
TP_PROTO(struct nfsd_file *nf, __be32 status),
TP_ARGS(nf, status),
TP_STRUCT__entry(
- __field(unsigned int, nf_hashval)
__field(void *, nf_inode) /* cannot be dereferenced */
__field(int, nf_ref)
__field(unsigned long, nf_flags)
__field(void *, nf_file) /* cannot be dereferenced */
),
TP_fast_assign(
- __entry->nf_hashval = nf->nf_hashval;
__entry->nf_inode = nf->nf_inode;
__entry->nf_ref = refcount_read(&nf->nf_ref);
__entry->nf_flags = nf->nf_flags;
__entry->nf_may = nf->nf_may;
__entry->nf_file = nf->nf_file;
),
- TP_printk("hash=0x%x inode=%p ref=%d flags=%s may=%s file=%p",
- __entry->nf_hashval,
+ TP_printk("inode=%p ref=%d flags=%s may=%s file=%p",
__entry->nf_inode,
__entry->nf_ref,
show_nf_flags(__entry->nf_flags),
)
DECLARE_EVENT_CLASS(nfsd_file_search_class,
- TP_PROTO(struct inode *inode, unsigned int hash, int found),
- TP_ARGS(inode, hash, found),
+ TP_PROTO(
+ const struct inode *inode,
+ unsigned int count
+ ),
+ TP_ARGS(inode, count),
TP_STRUCT__entry(
- __field(struct inode *, inode)
- __field(unsigned int, hash)
- __field(int, found)
+ __field(const struct inode *, inode)
+ __field(unsigned int, count)
),
TP_fast_assign(
__entry->inode = inode;
- __entry->hash = hash;
- __entry->found = found;
+ __entry->count = count;
),
- TP_printk("hash=0x%x inode=%p found=%d", __entry->hash,
- __entry->inode, __entry->found)
+ TP_printk("inode=%p count=%u",
+ __entry->inode, __entry->count)
);
#define DEFINE_NFSD_FILE_SEARCH_EVENT(name) \
DEFINE_EVENT(nfsd_file_search_class, name, \
- TP_PROTO(struct inode *inode, unsigned int hash, int found), \
- TP_ARGS(inode, hash, found))
+ TP_PROTO( \
+ const struct inode *inode, \
+ unsigned int count \
+ ), \
+ TP_ARGS(inode, count))
DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_close_inode_sync);
DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_close_inode);
-DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_is_cached);
+
+TRACE_EVENT(nfsd_file_is_cached,
+ TP_PROTO(
+ const struct inode *inode,
+ int found
+ ),
+ TP_ARGS(inode, found),
+ TP_STRUCT__entry(
+ __field(const struct inode *, inode)
+ __field(int, found)
+ ),
+ TP_fast_assign(
+ __entry->inode = inode;
+ __entry->found = found;
+ ),
+ TP_printk("inode=%p is %scached",
+ __entry->inode,
+ __entry->found ? "" : "not "
+ )
+);
TRACE_EVENT(nfsd_file_fsnotify_handle_event,
TP_PROTO(struct inode *inode, u32 mask),
__entry->nlink, __entry->mode, __entry->mask)
);
+DECLARE_EVENT_CLASS(nfsd_file_gc_class,
+ TP_PROTO(
+ const struct nfsd_file *nf
+ ),
+ TP_ARGS(nf),
+ TP_STRUCT__entry(
+ __field(void *, nf_inode)
+ __field(void *, nf_file)
+ __field(int, nf_ref)
+ __field(unsigned long, nf_flags)
+ ),
+ TP_fast_assign(
+ __entry->nf_inode = nf->nf_inode;
+ __entry->nf_file = nf->nf_file;
+ __entry->nf_ref = refcount_read(&nf->nf_ref);
+ __entry->nf_flags = nf->nf_flags;
+ ),
+ TP_printk("inode=%p ref=%d nf_flags=%s nf_file=%p",
+ __entry->nf_inode, __entry->nf_ref,
+ show_nf_flags(__entry->nf_flags),
+ __entry->nf_file
+ )
+);
+
+#define DEFINE_NFSD_FILE_GC_EVENT(name) \
+DEFINE_EVENT(nfsd_file_gc_class, name, \
+ TP_PROTO( \
+ const struct nfsd_file *nf \
+ ), \
+ TP_ARGS(nf))
+
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_add);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_add_disposed);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_del);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_del_disposed);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_in_use);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_writeback);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_referenced);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_hashed);
+DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_disposed);
+
+DECLARE_EVENT_CLASS(nfsd_file_lruwalk_class,
+ TP_PROTO(
+ unsigned long removed,
+ unsigned long remaining
+ ),
+ TP_ARGS(removed, remaining),
+ TP_STRUCT__entry(
+ __field(unsigned long, removed)
+ __field(unsigned long, remaining)
+ ),
+ TP_fast_assign(
+ __entry->removed = removed;
+ __entry->remaining = remaining;
+ ),
+ TP_printk("%lu entries removed, %lu remaining",
+ __entry->removed, __entry->remaining)
+);
+
+#define DEFINE_NFSD_FILE_LRUWALK_EVENT(name) \
+DEFINE_EVENT(nfsd_file_lruwalk_class, name, \
+ TP_PROTO( \
+ unsigned long removed, \
+ unsigned long remaining \
+ ), \
+ TP_ARGS(removed, remaining))
+
+DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_gc_removed);
+DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_shrinker_removed);
+
#include "cache.h"
TRACE_DEFINE_ENUM(RC_DROPIT);
goto out_nfserr;
}
} else {
- /*
- * In the nfsd4_open() case, this may be held across
- * subsequent open and delegation acquisition which may
- * need to take the child's i_mutex:
- */
- fh_lock_nested(fhp, I_MUTEX_PARENT);
- dentry = lookup_one_len(name, dparent, len);
+ dentry = lookup_one_len_unlocked(name, dparent, len);
host_err = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto out_nfserr;
if (nfsd_mountpoint(dentry, exp)) {
- /*
- * We don't need the i_mutex after all. It's
- * still possible we could open this (regular
- * files can be mountpoints too), but the
- * i_mutex is just there to prevent renames of
- * something that we might be about to delegate,
- * and a mountpoint won't be renamed:
- */
- fh_unlock(fhp);
- if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
+ host_err = nfsd_cross_mnt(rqstp, &dentry, &exp);
+ if (host_err) {
dput(dentry);
goto out_nfserr;
}
return nfserrno(host_err);
}
-/*
+/**
+ * nfsd_lookup - look up a single path component for nfsd
+ *
+ * @rqstp: the request context
+ * @fhp: the file handle of the directory
+ * @name: the component name, or %NULL to look up parent
+ * @len: length of name to examine
+ * @resfh: pointer to pre-initialised filehandle to hold result.
+ *
* Look up one component of a pathname.
* N.B. After this call _both_ fhp and resfh need an fh_put
*
* returned. Otherwise the covered directory is returned.
* NOTE: this mountpoint crossing is not supported properly by all
* clients and is explicitly disallowed for NFSv3
- * NeilBrown <neilb@cse.unsw.edu.au>
+ *
*/
__be32
nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
- unsigned int len, struct svc_fh *resfh)
+ unsigned int len, struct svc_fh *resfh)
{
struct svc_export *exp;
struct dentry *dentry;
* Set various file attributes. After this call fhp needs an fh_put.
*/
__be32
-nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
+nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ struct nfsd_attrs *attr,
int check_guard, time64_t guardtime)
{
struct dentry *dentry;
struct inode *inode;
+ struct iattr *iap = attr->na_iattr;
int accmode = NFSD_MAY_SATTR;
umode_t ftype = 0;
__be32 err;
return err;
}
- fh_lock(fhp);
+ inode_lock(inode);
if (size_change) {
/*
* RFC5661, Section 18.30.4:
host_err = notify_change(&init_user_ns, dentry, iap, NULL);
out_unlock:
- fh_unlock(fhp);
+ if (attr->na_seclabel && attr->na_seclabel->len)
+ attr->na_labelerr = security_inode_setsecctx(dentry,
+ attr->na_seclabel->data, attr->na_seclabel->len);
+ if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && attr->na_pacl)
+ attr->na_aclerr = set_posix_acl(&init_user_ns,
+ inode, ACL_TYPE_ACCESS,
+ attr->na_pacl);
+ if (IS_ENABLED(CONFIG_FS_POSIX_ACL) &&
+ !attr->na_aclerr && attr->na_dpacl && S_ISDIR(inode->i_mode))
+ attr->na_aclerr = set_posix_acl(&init_user_ns,
+ inode, ACL_TYPE_DEFAULT,
+ attr->na_dpacl);
+ inode_unlock(inode);
if (size_change)
put_write_access(inode);
out:
return 0;
return 1;
}
-#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
-__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
- struct xdr_netobj *label)
-{
- __be32 error;
- int host_error;
- struct dentry *dentry;
-
- error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR);
- if (error)
- return error;
-
- dentry = fhp->fh_dentry;
-
- inode_lock(d_inode(dentry));
- host_error = security_inode_setsecctx(dentry, label->data, label->len);
- inode_unlock(d_inode(dentry));
- return nfserrno(host_error);
-}
-#else
-__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
- struct xdr_netobj *label)
-{
- return nfserr_notsupp;
-}
-#endif
static struct nfsd4_compound_state *nfsd4_get_cstate(struct svc_rqst *rqstp)
{
* @rqstp: RPC transaction being executed
* @fhp: NFS filehandle of parent directory
* @resfhp: NFS filehandle of new object
- * @iap: requested attributes of new object
+ * @attrs: requested attributes of new object
*
* Returns nfs_ok on success, or an nfsstat in network byte order.
*/
__be32
nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
- struct svc_fh *resfhp, struct iattr *iap)
+ struct svc_fh *resfhp, struct nfsd_attrs *attrs)
{
+ struct iattr *iap = attrs->na_iattr;
__be32 status;
/*
* if the attributes have not changed.
*/
if (iap->ia_valid)
- status = nfsd_setattr(rqstp, resfhp, iap, 0, (time64_t)0);
+ status = nfsd_setattr(rqstp, resfhp, attrs, 0, (time64_t)0);
else
status = nfserrno(commit_metadata(resfhp));
/* The parent directory should already be locked: */
__be32
nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
- char *fname, int flen, struct iattr *iap,
- int type, dev_t rdev, struct svc_fh *resfhp)
+ char *fname, int flen, struct nfsd_attrs *attrs,
+ int type, dev_t rdev, struct svc_fh *resfhp)
{
struct dentry *dentry, *dchild;
struct inode *dirp;
+ struct iattr *iap = attrs->na_iattr;
__be32 err;
int host_err;
dirp = d_inode(dentry);
dchild = dget(resfhp->fh_dentry);
- if (!fhp->fh_locked) {
- WARN_ONCE(1, "nfsd_create: parent %pd2 not locked!\n",
- dentry);
- err = nfserr_io;
- goto out;
- }
-
err = nfsd_permission(rqstp, fhp->fh_export, dentry, NFSD_MAY_CREATE);
if (err)
goto out;
if (host_err < 0)
goto out_nfserr;
- err = nfsd_create_setattr(rqstp, fhp, resfhp, iap);
+ err = nfsd_create_setattr(rqstp, fhp, resfhp, attrs);
out:
dput(dchild);
*/
__be32
nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
- char *fname, int flen, struct iattr *iap,
- int type, dev_t rdev, struct svc_fh *resfhp)
+ char *fname, int flen, struct nfsd_attrs *attrs,
+ int type, dev_t rdev, struct svc_fh *resfhp)
{
struct dentry *dentry, *dchild = NULL;
__be32 err;
if (host_err)
return nfserrno(host_err);
- fh_lock_nested(fhp, I_MUTEX_PARENT);
+ inode_lock_nested(dentry->d_inode, I_MUTEX_PARENT);
dchild = lookup_one_len(fname, dentry, flen);
host_err = PTR_ERR(dchild);
- if (IS_ERR(dchild))
- return nfserrno(host_err);
+ if (IS_ERR(dchild)) {
+ err = nfserrno(host_err);
+ goto out_unlock;
+ }
err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
/*
* We unconditionally drop our ref to dchild as fh_compose will have
*/
dput(dchild);
if (err)
- return err;
- return nfsd_create_locked(rqstp, fhp, fname, flen, iap, type,
- rdev, resfhp);
+ goto out_unlock;
+ fh_fill_pre_attrs(fhp);
+ err = nfsd_create_locked(rqstp, fhp, fname, flen, attrs, type,
+ rdev, resfhp);
+ fh_fill_post_attrs(fhp);
+out_unlock:
+ inode_unlock(dentry->d_inode);
+ return err;
}
/*
return 0;
}
-/*
- * Create a symlink and look up its inode
+/**
+ * nfsd_symlink - Create a symlink and look up its inode
+ * @rqstp: RPC transaction being executed
+ * @fhp: NFS filehandle of parent directory
+ * @fname: filename of the new symlink
+ * @flen: length of @fname
+ * @path: content of the new symlink (NUL-terminated)
+ * @attrs: requested attributes of new object
+ * @resfhp: NFS filehandle of new object
+ *
* N.B. After this call _both_ fhp and resfhp need an fh_put
+ *
+ * Returns nfs_ok on success, or an nfsstat in network byte order.
*/
__be32
nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
- char *fname, int flen,
- char *path,
- struct svc_fh *resfhp)
+ char *fname, int flen,
+ char *path, struct nfsd_attrs *attrs,
+ struct svc_fh *resfhp)
{
struct dentry *dentry, *dnew;
__be32 err, cerr;
goto out;
host_err = fh_want_write(fhp);
- if (host_err)
- goto out_nfserr;
+ if (host_err) {
+ err = nfserrno(host_err);
+ goto out;
+ }
- fh_lock(fhp);
dentry = fhp->fh_dentry;
+ inode_lock_nested(dentry->d_inode, I_MUTEX_PARENT);
dnew = lookup_one_len(fname, dentry, flen);
- host_err = PTR_ERR(dnew);
- if (IS_ERR(dnew))
- goto out_nfserr;
-
+ if (IS_ERR(dnew)) {
+ err = nfserrno(PTR_ERR(dnew));
+ inode_unlock(dentry->d_inode);
+ goto out_drop_write;
+ }
+ fh_fill_pre_attrs(fhp);
host_err = vfs_symlink(&init_user_ns, d_inode(dentry), dnew, path);
err = nfserrno(host_err);
- fh_unlock(fhp);
+ cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
+ if (!err)
+ nfsd_create_setattr(rqstp, fhp, resfhp, attrs);
+ fh_fill_post_attrs(fhp);
+ inode_unlock(dentry->d_inode);
if (!err)
err = nfserrno(commit_metadata(fhp));
-
- fh_drop_write(fhp);
-
- cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
dput(dnew);
if (err==0) err = cerr;
+out_drop_write:
+ fh_drop_write(fhp);
out:
return err;
-
-out_nfserr:
- err = nfserrno(host_err);
- goto out;
}
/*
goto out;
}
- fh_lock_nested(ffhp, I_MUTEX_PARENT);
ddir = ffhp->fh_dentry;
dirp = d_inode(ddir);
+ inode_lock_nested(dirp, I_MUTEX_PARENT);
dnew = lookup_one_len(name, ddir, len);
- host_err = PTR_ERR(dnew);
- if (IS_ERR(dnew))
- goto out_nfserr;
+ if (IS_ERR(dnew)) {
+ err = nfserrno(PTR_ERR(dnew));
+ goto out_unlock;
+ }
dold = tfhp->fh_dentry;
err = nfserr_noent;
if (d_really_is_negative(dold))
goto out_dput;
+ fh_fill_pre_attrs(ffhp);
host_err = vfs_link(dold, &init_user_ns, dirp, dnew, NULL);
- fh_unlock(ffhp);
+ fh_fill_post_attrs(ffhp);
+ inode_unlock(dirp);
if (!host_err) {
err = nfserrno(commit_metadata(ffhp));
if (!err)
else
err = nfserrno(host_err);
}
-out_dput:
dput(dnew);
-out_unlock:
- fh_unlock(ffhp);
+out_drop_write:
fh_drop_write(tfhp);
out:
return err;
-out_nfserr:
- err = nfserrno(host_err);
- goto out_unlock;
+out_dput:
+ dput(dnew);
+out_unlock:
+ inode_unlock(dirp);
+ goto out_drop_write;
}
static void
goto out;
}
- /* cannot use fh_lock as we need deadlock protective ordering
- * so do it by hand */
trap = lock_rename(tdentry, fdentry);
- ffhp->fh_locked = tfhp->fh_locked = true;
fh_fill_pre_attrs(ffhp);
fh_fill_pre_attrs(tfhp);
dput(odentry);
out_nfserr:
err = nfserrno(host_err);
- /*
- * We cannot rely on fh_unlock on the two filehandles,
- * as that would do the wrong thing if the two directories
- * were the same, so again we do it by hand.
- */
+
if (!close_cached) {
fh_fill_post_attrs(ffhp);
fh_fill_post_attrs(tfhp);
}
unlock_rename(tdentry, fdentry);
- ffhp->fh_locked = tfhp->fh_locked = false;
fh_drop_write(ffhp);
/*
if (host_err)
goto out_nfserr;
- fh_lock_nested(fhp, I_MUTEX_PARENT);
dentry = fhp->fh_dentry;
dirp = d_inode(dentry);
+ inode_lock_nested(dirp, I_MUTEX_PARENT);
rdentry = lookup_one_len(fname, dentry, flen);
host_err = PTR_ERR(rdentry);
if (IS_ERR(rdentry))
- goto out_drop_write;
+ goto out_unlock;
if (d_really_is_negative(rdentry)) {
dput(rdentry);
host_err = -ENOENT;
- goto out_drop_write;
+ goto out_unlock;
}
rinode = d_inode(rdentry);
ihold(rinode);
if (!type)
type = d_inode(rdentry)->i_mode & S_IFMT;
+ fh_fill_pre_attrs(fhp);
if (type != S_IFDIR) {
if (rdentry->d_sb->s_export_op->flags & EXPORT_OP_CLOSE_BEFORE_UNLINK)
nfsd_close_cached_files(rdentry);
} else {
host_err = vfs_rmdir(&init_user_ns, dirp, rdentry);
}
+ fh_fill_post_attrs(fhp);
- fh_unlock(fhp);
+ inode_unlock(dirp);
if (!host_err)
host_err = commit_metadata(fhp);
dput(rdentry);
}
out:
return err;
+out_unlock:
+ inode_unlock(dirp);
+ goto out_drop_write;
}
/*
return err;
}
-/*
- * Removexattr and setxattr need to call fh_lock to both lock the inode
- * and set the change attribute. Since the top-level vfs_removexattr
- * and vfs_setxattr calls already do their own inode_lock calls, call
- * the _locked variant. Pass in a NULL pointer for delegated_inode,
- * and let the client deal with NFS4ERR_DELAY (same as with e.g.
- * setattr and remove).
+/**
+ * nfsd_removexattr - Remove an extended attribute
+ * @rqstp: RPC transaction being executed
+ * @fhp: NFS filehandle of object with xattr to remove
+ * @name: name of xattr to remove (NUL-terminate)
+ *
+ * Pass in a NULL pointer for delegated_inode, and let the client deal
+ * with NFS4ERR_DELAY (same as with e.g. setattr and remove).
+ *
+ * Returns nfs_ok on success, or an nfsstat in network byte order.
*/
__be32
nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name)
if (ret)
return nfserrno(ret);
- fh_lock(fhp);
+ inode_lock(fhp->fh_dentry->d_inode);
+ fh_fill_pre_attrs(fhp);
ret = __vfs_removexattr_locked(&init_user_ns, fhp->fh_dentry,
name, NULL);
- fh_unlock(fhp);
+ fh_fill_post_attrs(fhp);
+ inode_unlock(fhp->fh_dentry->d_inode);
fh_drop_write(fhp);
return nfsd_xattr_errno(ret);
ret = fh_want_write(fhp);
if (ret)
return nfserrno(ret);
- fh_lock(fhp);
+ inode_lock(fhp->fh_dentry->d_inode);
+ fh_fill_pre_attrs(fhp);
ret = __vfs_setxattr_locked(&init_user_ns, fhp->fh_dentry, name, buf,
len, flags, NULL);
-
- fh_unlock(fhp);
+ fh_fill_post_attrs(fhp);
+ inode_unlock(fhp->fh_dentry->d_inode);
fh_drop_write(fhp);
return nfsd_xattr_errno(ret);
#ifndef LINUX_NFSD_VFS_H
#define LINUX_NFSD_VFS_H
+#include <linux/fs.h>
+#include <linux/posix_acl.h>
#include "nfsfh.h"
#include "nfsd.h"
typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
/* nfsd/vfs.c */
+struct nfsd_attrs {
+ struct iattr *na_iattr; /* input */
+ struct xdr_netobj *na_seclabel; /* input */
+ struct posix_acl *na_pacl; /* input */
+ struct posix_acl *na_dpacl; /* input */
+
+ int na_labelerr; /* output */
+ int na_aclerr; /* output */
+};
+
+static inline void nfsd_attrs_free(struct nfsd_attrs *attrs)
+{
+ posix_acl_release(attrs->na_pacl);
+ posix_acl_release(attrs->na_dpacl);
+}
+
int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
struct svc_export **expp);
__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
const char *, unsigned int,
struct svc_export **, struct dentry **);
__be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *,
- struct iattr *, int, time64_t);
+ struct nfsd_attrs *, int, time64_t);
int nfsd_mountpoint(struct dentry *, struct svc_export *);
#ifdef CONFIG_NFSD_V4
-__be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
- struct xdr_netobj *);
__be32 nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *,
struct file *, loff_t, loff_t, int);
__be32 nfsd4_clone_file_range(struct svc_rqst *rqstp,
u64 count, bool sync);
#endif /* CONFIG_NFSD_V4 */
__be32 nfsd_create_locked(struct svc_rqst *, struct svc_fh *,
- char *name, int len, struct iattr *attrs,
+ char *name, int len, struct nfsd_attrs *attrs,
int type, dev_t rdev, struct svc_fh *res);
__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
- char *name, int len, struct iattr *attrs,
+ char *name, int len, struct nfsd_attrs *attrs,
int type, dev_t rdev, struct svc_fh *res);
__be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
__be32 nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
- struct svc_fh *resfhp, struct iattr *iap);
+ struct svc_fh *resfhp, struct nfsd_attrs *iap);
__be32 nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp,
u64 offset, u32 count, __be32 *verf);
#ifdef CONFIG_NFSD_V4
__be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *,
char *, int *);
__be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
- char *name, int len, char *path,
- struct svc_fh *res);
+ char *name, int len, char *path,
+ struct nfsd_attrs *attrs,
+ struct svc_fh *res);
__be32 nfsd_link(struct svc_rqst *, struct svc_fh *,
char *, int, struct svc_fh *);
ssize_t nfsd_copy_file_range(struct file *, u64,
struct nfs4_clnt_odstate *op_odstate; /* used during processing */
struct nfs4_acl *op_acl;
struct xdr_netobj op_label;
+ struct svc_rqst *op_rqstp;
};
struct nfsd4_open_confirm {
u32 rd_length; /* request */
int rd_vlen;
struct nfsd_file *rd_nf;
-
+
struct svc_rqst *rd_rqstp; /* response */
- struct svc_fh *rd_fhp; /* response */
+ struct svc_fh *rd_fhp; /* response */
+ u32 rd_eof; /* response */
};
struct nfsd4_readdir {
stateid_t cb_stateid;
};
+struct nfsd4_cb_offload {
+ struct nfsd4_callback co_cb;
+ struct nfsd42_write_res co_res;
+ __be32 co_nfserr;
+ struct knfsd_fh co_fh;
+};
+
struct nfsd4_copy {
/* request */
stateid_t cp_src_stateid;
u64 cp_src_pos;
u64 cp_dst_pos;
u64 cp_count;
- struct nl4_server cp_src;
- bool cp_intra;
+ struct nl4_server *cp_src;
- /* both */
- u32 cp_synchronous;
+ unsigned long cp_flags;
+#define NFSD4_COPY_F_STOPPED (0)
+#define NFSD4_COPY_F_INTRA (1)
+#define NFSD4_COPY_F_SYNCHRONOUS (2)
+#define NFSD4_COPY_F_COMMITTED (3)
/* response */
struct nfsd42_write_res cp_res;
-
- /* for cb_offload */
- struct nfsd4_callback cp_cb;
- __be32 nfserr;
struct knfsd_fh fh;
struct nfs4_client *cp_clp;
struct list_head copies;
struct task_struct *copy_task;
refcount_t refcount;
- bool stopped;
struct vfsmount *ss_mnt;
struct nfs_fh c_fh;
nfs4_stateid stateid;
- bool committed;
};
+static inline void nfsd4_copy_set_sync(struct nfsd4_copy *copy, bool sync)
+{
+ if (sync)
+ set_bit(NFSD4_COPY_F_SYNCHRONOUS, ©->cp_flags);
+ else
+ clear_bit(NFSD4_COPY_F_SYNCHRONOUS, ©->cp_flags);
+}
+
+static inline bool nfsd4_copy_is_sync(const struct nfsd4_copy *copy)
+{
+ return test_bit(NFSD4_COPY_F_SYNCHRONOUS, ©->cp_flags);
+}
+
+static inline bool nfsd4_copy_is_async(const struct nfsd4_copy *copy)
+{
+ return !test_bit(NFSD4_COPY_F_SYNCHRONOUS, ©->cp_flags);
+}
+
+static inline bool nfsd4_ssc_is_inter(const struct nfsd4_copy *copy)
+{
+ return !test_bit(NFSD4_COPY_F_INTRA, ©->cp_flags);
+}
+
struct nfsd4_seek {
/* request */
stateid_t seek_stateid;
struct nfsd4_copy_notify {
/* request */
stateid_t cpn_src_stateid;
- struct nl4_server cpn_dst;
+ struct nl4_server *cpn_dst;
/* response */
stateid_t cpn_cnr_stateid;
u64 cpn_sec;
u32 cpn_nsec;
- struct nl4_server cpn_src;
+ struct nl4_server *cpn_src;
};
struct nfsd4_op {
u32 opnum;
- const struct nfsd4_operation * opdesc;
__be32 status;
+ const struct nfsd4_operation *opdesc;
+ struct nfs4_replay *replay;
union nfsd4_op_u {
struct nfsd4_access access;
struct nfsd4_close close;
struct nfsd4_listxattrs listxattrs;
struct nfsd4_removexattr removexattr;
} u;
- struct nfs4_replay * replay;
};
bool nfsd4_cache_this_op(struct nfsd4_op *);
* callers. */
if (S_ISDIR(mode))
set_nlink(inode, 2);
+ mode = mode_strip_sgid(&init_user_ns, dir, mode);
inode_init_owner(&init_user_ns, inode, dir, mode);
status = dquot_initialize(inode);
if (status)
static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
{
- struct iovec iov = { .iov_base = buf, .iov_len = len };
struct kiocb kiocb;
struct iov_iter iter;
ssize_t ret;
init_sync_kiocb(&kiocb, filp);
kiocb.ki_pos = (ppos ? *ppos : 0);
- iov_iter_init(&iter, READ, &iov, 1, len);
+ iov_iter_ubuf(&iter, READ, buf, len);
ret = call_read_iter(filp, &kiocb, &iter);
BUG_ON(ret == -EIOCBQUEUED);
static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
- struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
struct kiocb kiocb;
struct iov_iter iter;
ssize_t ret;
init_sync_kiocb(&kiocb, filp);
kiocb.ki_pos = (ppos ? *ppos : 0);
- iov_iter_init(&iter, WRITE, &iov, 1, len);
+ iov_iter_ubuf(&iter, WRITE, (void __user *)buf, len);
ret = call_write_iter(filp, &kiocb, &iter);
BUG_ON(ret == -EIOCBQUEUED);
{
struct iov_iter to;
struct kiocb kiocb;
- unsigned int i_head;
int ret;
iov_iter_pipe(&to, READ, pipe, len);
- i_head = to.head;
init_sync_kiocb(&kiocb, in);
kiocb.ki_pos = *ppos;
ret = call_read_iter(in, &kiocb, &to);
*ppos = kiocb.ki_pos;
file_accessed(in);
} else if (ret < 0) {
- to.head = i_head;
- to.iov_offset = 0;
- iov_iter_advance(&to, 0); /* to free what was emitted */
+ /* free what was emitted */
+ pipe_discard_from(pipe, to.start_head);
/*
* callers of ->splice_read() expect -EAGAIN on
* "can't put anything in there", rather than -EFAULT.
};
size_t total = 0;
int ret = 0;
- bool failed = false;
- while (iov_iter_count(from) && !failed) {
+ while (iov_iter_count(from)) {
struct page *pages[16];
- ssize_t copied;
+ ssize_t left;
size_t start;
- int n;
+ int i, n;
- copied = iov_iter_get_pages(from, pages, ~0UL, 16, &start);
- if (copied <= 0) {
- ret = copied;
+ left = iov_iter_get_pages2(from, pages, ~0UL, 16, &start);
+ if (left <= 0) {
+ ret = left;
break;
}
- for (n = 0; copied; n++, start = 0) {
- int size = min_t(int, copied, PAGE_SIZE - start);
- if (!failed) {
- buf.page = pages[n];
- buf.offset = start;
- buf.len = size;
- ret = add_to_pipe(pipe, &buf);
- if (unlikely(ret < 0)) {
- failed = true;
- } else {
- iov_iter_advance(from, ret);
- total += ret;
- }
- } else {
- put_page(pages[n]);
+ n = DIV_ROUND_UP(left + start, PAGE_SIZE);
+ for (i = 0; i < n; i++) {
+ int size = min_t(int, left, PAGE_SIZE - start);
+
+ buf.page = pages[i];
+ buf.offset = start;
+ buf.len = size;
+ ret = add_to_pipe(pipe, &buf);
+ if (unlikely(ret < 0)) {
+ iov_iter_revert(from, left);
+ // this one got dropped by add_to_pipe()
+ while (++i < n)
+ put_page(pages[i]);
+ goto out;
}
- copied -= size;
+ total += ret;
+ left -= size;
+ start = 0;
}
}
+out:
return total ? total : ret;
}
/*
* Convert a port and pin label to its global pin index
*/
- #define RZA2_PIN(port, pin) ((port) * RZA2_PINS_PER_PORT + (pin))
+#define RZA2_PIN(port, pin) ((port) * RZA2_PINS_PER_PORT + (pin))
#endif /* __DT_BINDINGS_PINCTRL_RENESAS_RZA2_H */
#define RZG2L_PORT_PINMUX(b, p, f) ((b) * RZG2L_PINS_PER_PORT + (p) | ((f) << 16))
/* Convert a port and pin label to its global pin index */
- #define RZG2L_GPIO(port, pin) ((port) * RZG2L_PINS_PER_PORT + (pin))
+#define RZG2L_GPIO(port, pin) ((port) * RZG2L_PINS_PER_PORT + (pin))
#endif /* __DT_BINDINGS_RZG2L_PINCTRL_H */
--- /dev/null
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * This header provides constants for Renesas RZ/V2M pinctrl bindings.
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ *
+ */
+
+#ifndef __DT_BINDINGS_RZV2M_PINCTRL_H
+#define __DT_BINDINGS_RZV2M_PINCTRL_H
+
+#define RZV2M_PINS_PER_PORT 16
+
+/*
+ * Create the pin index from its bank and position numbers and store in
+ * the upper 16 bits the alternate function identifier
+ */
+#define RZV2M_PORT_PINMUX(b, p, f) ((b) * RZV2M_PINS_PER_PORT + (p) | ((f) << 16))
+
+/* Convert a port and pin label to its global pin index */
+#define RZV2M_GPIO(port, pin) ((port) * RZV2M_PINS_PER_PORT + (pin))
+
+#endif /* __DT_BINDINGS_RZV2M_PINCTRL_H */
* of the form "mark_buffer_foo()". These are higher-level functions which
* do something in addition to setting a b_state bit.
*/
-BUFFER_FNS(Uptodate, uptodate)
BUFFER_FNS(Dirty, dirty)
TAS_BUFFER_FNS(Dirty, dirty)
BUFFER_FNS(Lock, locked)
BUFFER_FNS(Prio, prio)
BUFFER_FNS(Defer_Completion, defer_completion)
+static __always_inline void set_buffer_uptodate(struct buffer_head *bh)
+{
+ /*
+ * make it consistent with folio_mark_uptodate
+ * pairs with smp_load_acquire in buffer_uptodate
+ */
+ smp_mb__before_atomic();
+ set_bit(BH_Uptodate, &bh->b_state);
+}
+
+static __always_inline void clear_buffer_uptodate(struct buffer_head *bh)
+{
+ clear_bit(BH_Uptodate, &bh->b_state);
+}
+
+static __always_inline int buffer_uptodate(const struct buffer_head *bh)
+{
+ /*
+ * make it consistent with folio_test_uptodate
+ * pairs with smp_mb__before_atomic in set_buffer_uptodate
+ */
+ return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0;
+}
+
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK)
/* If we *know* page->private refers to buffer_heads */
#ifdef CONFIG_DMA_DECLARE_COHERENT
int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
dma_addr_t device_addr, size_t size);
+void dma_release_coherent_memory(struct device *dev);
int dma_alloc_from_dev_coherent(struct device *dev, ssize_t size,
dma_addr_t *dma_handle, void **ret);
int dma_release_from_dev_coherent(struct device *dev, int order, void *vaddr);
{
return -ENOSYS;
}
+
#define dma_alloc_from_dev_coherent(dev, size, handle, ret) (0)
#define dma_release_from_dev_coherent(dev, order, vaddr) (0)
#define dma_mmap_from_dev_coherent(dev, vma, vaddr, order, ret) (0)
+static inline void dma_release_coherent_memory(struct device *dev) { }
#endif /* CONFIG_DMA_DECLARE_COHERENT */
#ifdef CONFIG_DMA_GLOBAL_POOL
PM_PINCTRL_DRIVE_STRENGTH_12MA = 3,
};
+enum pm_pinctrl_tri_state {
+ PM_PINCTRL_TRI_STATE_DISABLE = 0,
+ PM_PINCTRL_TRI_STATE_ENABLE = 1,
+};
+
enum zynqmp_pm_shutdown_type {
ZYNQMP_PM_SHUTDOWN_TYPE_SHUTDOWN = 0,
ZYNQMP_PM_SHUTDOWN_TYPE_RESET = 1,
void inode_init_owner(struct user_namespace *mnt_userns, struct inode *inode,
const struct inode *dir, umode_t mode);
extern bool may_open_dev(const struct path *path);
+umode_t mode_strip_sgid(struct user_namespace *mnt_userns,
+ const struct inode *dir, umode_t mode);
/*
* This is the "filldir" function type, used by readdir() to let
IORES_DESC_DEVICE_PRIVATE_MEMORY = 6,
IORES_DESC_RESERVED = 7,
IORES_DESC_SOFT_RESERVED = 8,
+ IORES_DESC_CXL = 9,
};
/*
struct resource *base, unsigned long size);
struct resource *request_free_mem_region(struct resource *base,
unsigned long size, const char *name);
+struct resource *alloc_free_mem_region(struct resource *base,
+ unsigned long size, unsigned long align, const char *name);
static inline void irqresource_disabled(struct resource *res, u32 irq)
{
/* Platform provides asynchronous flush mechanism */
ND_REGION_ASYNC = 3,
+ /* Region was created by CXL subsystem */
+ ND_REGION_CXL = 4,
+
/* mark newly adjusted resources as requiring a label update */
DPA_RESOURCE_ADJUSTED = 1 << 0,
};
int numa_node;
int target_node;
unsigned long flags;
+ int memregion;
struct device_node *of_node;
int (*flush)(struct nd_region *nd_region, struct bio *bio);
};
cmd_mask, num_flush, flush_wpq, NULL, NULL, NULL);
}
void nvdimm_delete(struct nvdimm *nvdimm);
+void nvdimm_region_delete(struct nd_region *nd_region);
const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd);
const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd);
__be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
struct nlm_lock *);
void nlm_release_file(struct nlm_file *);
+void nlmsvc_put_lockowner(struct nlm_lockowner *);
void nlmsvc_release_lockowner(struct nlm_lock *);
void nlmsvc_mark_resources(struct net *);
void nlmsvc_free_host_resources(struct nlm_host *);
struct nfs_fh fh;
struct xdr_netobj oh;
u32 svid;
+ u64 lock_start;
+ u64 lock_len;
struct file_lock fl;
};
refcount_t nsui_refcnt;
unsigned long nsui_expire;
struct vfsmount *nsui_vfsmount;
- char nsui_ipaddr[RPC_MAX_ADDRBUFLEN];
+ char nsui_ipaddr[RPC_MAX_ADDRBUFLEN + 1];
};
#endif
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Data Object Exchange
+ * PCIe r6.0, sec 6.30 DOE
+ *
+ * Copyright (C) 2021 Huawei
+ * Jonathan Cameron <Jonathan.Cameron@huawei.com>
+ *
+ * Copyright (C) 2022 Intel Corporation
+ * Ira Weiny <ira.weiny@intel.com>
+ */
+
+#ifndef LINUX_PCI_DOE_H
+#define LINUX_PCI_DOE_H
+
+struct pci_doe_protocol {
+ u16 vid;
+ u8 type;
+};
+
+struct pci_doe_mb;
+
+/**
+ * struct pci_doe_task - represents a single query/response
+ *
+ * @prot: DOE Protocol
+ * @request_pl: The request payload
+ * @request_pl_sz: Size of the request payload (bytes)
+ * @response_pl: The response payload
+ * @response_pl_sz: Size of the response payload (bytes)
+ * @rv: Return value. Length of received response or error (bytes)
+ * @complete: Called when task is complete
+ * @private: Private data for the consumer
+ * @work: Used internally by the mailbox
+ * @doe_mb: Used internally by the mailbox
+ *
+ * The payload sizes and rv are specified in bytes with the following
+ * restrictions concerning the protocol.
+ *
+ * 1) The request_pl_sz must be a multiple of double words (4 bytes)
+ * 2) The response_pl_sz must be >= a single double word (4 bytes)
+ * 3) rv is returned as bytes but it will be a multiple of double words
+ *
+ * NOTE there is no need for the caller to initialize work or doe_mb.
+ */
+struct pci_doe_task {
+ struct pci_doe_protocol prot;
+ u32 *request_pl;
+ size_t request_pl_sz;
+ u32 *response_pl;
+ size_t response_pl_sz;
+ int rv;
+ void (*complete)(struct pci_doe_task *task);
+ void *private;
+
+ /* No need for the user to initialize these fields */
+ struct work_struct work;
+ struct pci_doe_mb *doe_mb;
+};
+
+/**
+ * pci_doe_for_each_off - Iterate each DOE capability
+ * @pdev: struct pci_dev to iterate
+ * @off: u16 of config space offset of each mailbox capability found
+ */
+#define pci_doe_for_each_off(pdev, off) \
+ for (off = pci_find_next_ext_capability(pdev, off, \
+ PCI_EXT_CAP_ID_DOE); \
+ off > 0; \
+ off = pci_find_next_ext_capability(pdev, off, \
+ PCI_EXT_CAP_ID_DOE))
+
+struct pci_doe_mb *pcim_doe_create_mb(struct pci_dev *pdev, u16 cap_offset);
+bool pci_doe_supports_prot(struct pci_doe_mb *doe_mb, u16 vid, u8 type);
+int pci_doe_submit_task(struct pci_doe_mb *doe_mb, struct pci_doe_task *task);
+
+#endif
#define PCI_CLASS_OTHERS 0xff
/* Vendors and devices. Sort key: vendor first, device next. */
+#define PCI_VENDOR_ID_PCI_SIG 0x0001
#define PCI_VENDOR_ID_LOONGSON 0x0014
struct gpio_chip;
struct device_node;
+/**
+ * struct pingroup - provides information on pingroup
+ * @name: a name for pingroup
+ * @pins: an array of pins in the pingroup
+ * @npins: number of pins in the pingroup
+ */
+struct pingroup {
+ const char *name;
+ const unsigned int *pins;
+ size_t npins;
+};
+
+/* Convenience macro to define a single named or anonymous pingroup */
+#define PINCTRL_PINGROUP(_name, _pins, _npins) \
+(struct pingroup){ \
+ .name = _name, \
+ .pins = _pins, \
+ .npins = _npins, \
+}
+
/**
* struct pinctrl_pin_desc - boards/machines provide information on their
* pins, pads or other muxable units in this struct
return pipe_occupancy(head, tail) >= limit;
}
-/**
- * pipe_space_for_user - Return number of slots available to userspace
- * @head: The pipe ring head pointer
- * @tail: The pipe ring tail pointer
- * @pipe: The pipe info structure
- */
-static inline unsigned int pipe_space_for_user(unsigned int head, unsigned int tail,
- struct pipe_inode_info *pipe)
-{
- unsigned int p_occupancy, p_space;
-
- p_occupancy = pipe_occupancy(head, tail);
- if (p_occupancy >= pipe->max_usage)
- return 0;
- p_space = pipe->ring_size - p_occupancy;
- if (p_space > pipe->max_usage)
- p_space = pipe->max_usage;
- return p_space;
-}
-
/**
* pipe_buf_get - get a reference to a pipe_buffer
* @pipe: the pipe that the buffer belongs to
u32 peak;
};
-/**
- * struct dev_pm_opp_info - OPP freq/voltage/current values
- * @rate: Target clk rate in hz
- * @supplies: Array of voltage/current values for all power supplies
- *
- * This structure stores the freq/voltage/current values for a single OPP.
- */
-struct dev_pm_opp_info {
- unsigned long rate;
- struct dev_pm_opp_supply *supplies;
-};
+typedef int (*config_regulators_t)(struct device *dev,
+ struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp,
+ struct regulator **regulators, unsigned int count);
+
+typedef int (*config_clks_t)(struct device *dev, struct opp_table *opp_table,
+ struct dev_pm_opp *opp, void *data, bool scaling_down);
/**
- * struct dev_pm_set_opp_data - Set OPP data
- * @old_opp: Old OPP info
- * @new_opp: New OPP info
- * @regulators: Array of regulator pointers
- * @regulator_count: Number of regulators
- * @clk: Pointer to clk
- * @dev: Pointer to the struct device
+ * struct dev_pm_opp_config - Device OPP configuration values
+ * @clk_names: Clk names, NULL terminated array.
+ * @config_clks: Custom set clk helper.
+ * @prop_name: Name to postfix to properties.
+ * @config_regulators: Custom set regulator helper.
+ * @supported_hw: Array of hierarchy of versions to match.
+ * @supported_hw_count: Number of elements in the array.
+ * @regulator_names: Array of pointers to the names of the regulator, NULL terminated.
+ * @genpd_names: Null terminated array of pointers containing names of genpd to
+ * attach.
+ * @virt_devs: Pointer to return the array of virtual devices.
*
- * This structure contains all information required for setting an OPP.
+ * This structure contains platform specific OPP configurations for the device.
*/
-struct dev_pm_set_opp_data {
- struct dev_pm_opp_info old_opp;
- struct dev_pm_opp_info new_opp;
-
- struct regulator **regulators;
- unsigned int regulator_count;
- struct clk *clk;
- struct device *dev;
+struct dev_pm_opp_config {
+ /* NULL terminated */
+ const char * const *clk_names;
+ config_clks_t config_clks;
+ const char *prop_name;
+ config_regulators_t config_regulators;
+ const unsigned int *supported_hw;
+ unsigned int supported_hw_count;
+ const char * const *regulator_names;
+ const char * const *genpd_names;
+ struct device ***virt_devs;
};
#if defined(CONFIG_PM_OPP)
unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
+int dev_pm_opp_get_supplies(struct dev_pm_opp *opp, struct dev_pm_opp_supply *supplies);
+
unsigned long dev_pm_opp_get_power(struct dev_pm_opp *opp);
unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp);
bool available);
struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
unsigned long *freq);
-struct dev_pm_opp *dev_pm_opp_find_freq_ceil_by_volt(struct device *dev,
- unsigned long u_volt);
struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev,
unsigned int level);
int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb);
int dev_pm_opp_unregister_notifier(struct device *dev, struct notifier_block *nb);
-struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count);
-void dev_pm_opp_put_supported_hw(struct opp_table *opp_table);
-int devm_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count);
-struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name);
-void dev_pm_opp_put_prop_name(struct opp_table *opp_table);
-struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
-void dev_pm_opp_put_regulators(struct opp_table *opp_table);
-int devm_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
-struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name);
-void dev_pm_opp_put_clkname(struct opp_table *opp_table);
-int devm_pm_opp_set_clkname(struct device *dev, const char *name);
-struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
-void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table);
-int devm_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
-struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char * const *names, struct device ***virt_devs);
-void dev_pm_opp_detach_genpd(struct opp_table *opp_table);
-int devm_pm_opp_attach_genpd(struct device *dev, const char * const *names, struct device ***virt_devs);
+int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config);
+int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config);
+void dev_pm_opp_clear_config(int token);
+int dev_pm_opp_config_clks_simple(struct device *dev,
+ struct opp_table *opp_table, struct dev_pm_opp *opp, void *data,
+ bool scaling_down);
+
struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, struct opp_table *dst_table, struct dev_pm_opp *src_opp);
int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate);
int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
return 0;
}
+static inline int dev_pm_opp_get_supplies(struct dev_pm_opp *opp, struct dev_pm_opp_supply *supplies)
+{
+ return -EOPNOTSUPP;
+}
+
static inline unsigned long dev_pm_opp_get_power(struct dev_pm_opp *opp)
{
return 0;
return ERR_PTR(-EOPNOTSUPP);
}
-static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil_by_volt(struct device *dev,
- unsigned long u_volt)
-{
- return ERR_PTR(-EOPNOTSUPP);
-}
-
static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
unsigned long *freq)
{
return -EOPNOTSUPP;
}
-static inline struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
- const u32 *versions,
- unsigned int count)
-{
- return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) {}
-
-static inline int devm_pm_opp_set_supported_hw(struct device *dev,
- const u32 *versions,
- unsigned int count)
-{
- return -EOPNOTSUPP;
-}
-
-static inline struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev,
- int (*set_opp)(struct dev_pm_set_opp_data *data))
-{
- return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) {}
-
-static inline int devm_pm_opp_register_set_opp_helper(struct device *dev,
- int (*set_opp)(struct dev_pm_set_opp_data *data))
-{
- return -EOPNOTSUPP;
-}
-
-static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
-{
- return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void dev_pm_opp_put_prop_name(struct opp_table *opp_table) {}
-
-static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count)
-{
- return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void dev_pm_opp_put_regulators(struct opp_table *opp_table) {}
-
-static inline int devm_pm_opp_set_regulators(struct device *dev,
- const char * const names[],
- unsigned int count)
+static inline int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
{
return -EOPNOTSUPP;
}
-static inline struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name)
-{
- return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void dev_pm_opp_put_clkname(struct opp_table *opp_table) {}
-
-static inline int devm_pm_opp_set_clkname(struct device *dev, const char *name)
+static inline int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
{
return -EOPNOTSUPP;
}
-static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char * const *names, struct device ***virt_devs)
-{
- return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void dev_pm_opp_detach_genpd(struct opp_table *opp_table) {}
+static inline void dev_pm_opp_clear_config(int token) {}
-static inline int devm_pm_opp_attach_genpd(struct device *dev,
- const char * const *names,
- struct device ***virt_devs)
+static inline int dev_pm_opp_config_clks_simple(struct device *dev,
+ struct opp_table *opp_table, struct dev_pm_opp *opp, void *data,
+ bool scaling_down)
{
return -EOPNOTSUPP;
}
int dev_pm_opp_of_add_table(struct device *dev);
int dev_pm_opp_of_add_table_indexed(struct device *dev, int index);
int devm_pm_opp_of_add_table_indexed(struct device *dev, int index);
-int dev_pm_opp_of_add_table_noclk(struct device *dev, int index);
-int devm_pm_opp_of_add_table_noclk(struct device *dev, int index);
void dev_pm_opp_of_remove_table(struct device *dev);
int devm_pm_opp_of_add_table(struct device *dev);
int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask);
return -EOPNOTSUPP;
}
-static inline int dev_pm_opp_of_add_table_noclk(struct device *dev, int index)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int devm_pm_opp_of_add_table_noclk(struct device *dev, int index)
-{
- return -EOPNOTSUPP;
-}
-
static inline void dev_pm_opp_of_remove_table(struct device *dev)
{
}
}
#endif
+/* OPP Configuration helpers */
+
+/* Regulators helpers */
+static inline int dev_pm_opp_set_regulators(struct device *dev,
+ const char * const names[])
+{
+ struct dev_pm_opp_config config = {
+ .regulator_names = names,
+ };
+
+ return dev_pm_opp_set_config(dev, &config);
+}
+
+static inline void dev_pm_opp_put_regulators(int token)
+{
+ dev_pm_opp_clear_config(token);
+}
+
+static inline int devm_pm_opp_set_regulators(struct device *dev,
+ const char * const names[])
+{
+ struct dev_pm_opp_config config = {
+ .regulator_names = names,
+ };
+
+ return devm_pm_opp_set_config(dev, &config);
+}
+
+/* Supported-hw helpers */
+static inline int dev_pm_opp_set_supported_hw(struct device *dev,
+ const u32 *versions,
+ unsigned int count)
+{
+ struct dev_pm_opp_config config = {
+ .supported_hw = versions,
+ .supported_hw_count = count,
+ };
+
+ return dev_pm_opp_set_config(dev, &config);
+}
+
+static inline void dev_pm_opp_put_supported_hw(int token)
+{
+ dev_pm_opp_clear_config(token);
+}
+
+static inline int devm_pm_opp_set_supported_hw(struct device *dev,
+ const u32 *versions,
+ unsigned int count)
+{
+ struct dev_pm_opp_config config = {
+ .supported_hw = versions,
+ .supported_hw_count = count,
+ };
+
+ return devm_pm_opp_set_config(dev, &config);
+}
+
+/* clkname helpers */
+static inline int dev_pm_opp_set_clkname(struct device *dev, const char *name)
+{
+ const char *names[] = { name, NULL };
+ struct dev_pm_opp_config config = {
+ .clk_names = names,
+ };
+
+ return dev_pm_opp_set_config(dev, &config);
+}
+
+static inline void dev_pm_opp_put_clkname(int token)
+{
+ dev_pm_opp_clear_config(token);
+}
+
+static inline int devm_pm_opp_set_clkname(struct device *dev, const char *name)
+{
+ const char *names[] = { name, NULL };
+ struct dev_pm_opp_config config = {
+ .clk_names = names,
+ };
+
+ return devm_pm_opp_set_config(dev, &config);
+}
+
+/* config-regulators helpers */
+static inline int dev_pm_opp_set_config_regulators(struct device *dev,
+ config_regulators_t helper)
+{
+ struct dev_pm_opp_config config = {
+ .config_regulators = helper,
+ };
+
+ return dev_pm_opp_set_config(dev, &config);
+}
+
+static inline void dev_pm_opp_put_config_regulators(int token)
+{
+ dev_pm_opp_clear_config(token);
+}
+
+/* genpd helpers */
+static inline int dev_pm_opp_attach_genpd(struct device *dev,
+ const char * const *names,
+ struct device ***virt_devs)
+{
+ struct dev_pm_opp_config config = {
+ .genpd_names = names,
+ .virt_devs = virt_devs,
+ };
+
+ return dev_pm_opp_set_config(dev, &config);
+}
+
+static inline void dev_pm_opp_detach_genpd(int token)
+{
+ dev_pm_opp_clear_config(token);
+}
+
+static inline int devm_pm_opp_attach_genpd(struct device *dev,
+ const char * const *names,
+ struct device ***virt_devs)
+{
+ struct dev_pm_opp_config config = {
+ .genpd_names = names,
+ .virt_devs = virt_devs,
+ };
+
+ return devm_pm_opp_set_config(dev, &config);
+}
+
+/* prop-name helpers */
+static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
+{
+ struct dev_pm_opp_config config = {
+ .prop_name = name,
+ };
+
+ return dev_pm_opp_set_config(dev, &config);
+}
+
+static inline void dev_pm_opp_put_prop_name(int token)
+{
+ dev_pm_opp_clear_config(token);
+}
+
#endif /* __LINUX_OPP_H__ */
*/
static inline __be32 *xdr_encode_bool(__be32 *p, u32 n)
{
- *p = n ? xdr_one : xdr_zero;
- return p++;
+ *p++ = n ? xdr_one : xdr_zero;
+ return p;
}
/**
#define BIN_ATTR_RW(_name, _size) \
struct bin_attribute bin_attr_##_name = __BIN_ATTR_RW(_name, _size)
+
+#define __BIN_ATTR_ADMIN_RO(_name, _size) { \
+ .attr = { .name = __stringify(_name), .mode = 0400 }, \
+ .read = _name##_read, \
+ .size = _size, \
+}
+
+#define __BIN_ATTR_ADMIN_RW(_name, _size) \
+ __BIN_ATTR(_name, 0600, _name##_read, _name##_write, _size)
+
+#define BIN_ATTR_ADMIN_RO(_name, _size) \
+struct bin_attribute bin_attr_##_name = __BIN_ATTR_ADMIN_RO(_name, _size)
+
+#define BIN_ATTR_ADMIN_RW(_name, _size) \
+struct bin_attribute bin_attr_##_name = __BIN_ATTR_ADMIN_RW(_name, _size)
+
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *, char *);
ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
ITER_PIPE,
ITER_XARRAY,
ITER_DISCARD,
+ ITER_UBUF,
};
struct iov_iter_state {
u8 iter_type;
bool nofault;
bool data_source;
- size_t iov_offset;
+ bool user_backed;
+ union {
+ size_t iov_offset;
+ int last_offset;
+ };
size_t count;
union {
const struct iovec *iov;
const struct bio_vec *bvec;
struct xarray *xarray;
struct pipe_inode_info *pipe;
+ void __user *ubuf;
};
union {
unsigned long nr_segs;
state->nr_segs = iter->nr_segs;
}
+static inline bool iter_is_ubuf(const struct iov_iter *i)
+{
+ return iov_iter_type(i) == ITER_UBUF;
+}
+
static inline bool iter_is_iovec(const struct iov_iter *i)
{
return iov_iter_type(i) == ITER_IOVEC;
return i->data_source ? WRITE : READ;
}
+static inline bool user_backed_iter(const struct iov_iter *i)
+{
+ return i->user_backed;
+}
+
/*
* Total number of bytes covered by an iovec.
*
void iov_iter_discard(struct iov_iter *i, unsigned int direction, size_t count);
void iov_iter_xarray(struct iov_iter *i, unsigned int direction, struct xarray *xarray,
loff_t start, size_t count);
-ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages,
+ssize_t iov_iter_get_pages2(struct iov_iter *i, struct page **pages,
size_t maxsize, unsigned maxpages, size_t *start);
-ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages,
+ssize_t iov_iter_get_pages_alloc2(struct iov_iter *i, struct page ***pages,
size_t maxsize, size_t *start);
int iov_iter_npages(const struct iov_iter *i, int maxpages);
void iov_iter_restore(struct iov_iter *i, struct iov_iter_state *state);
int import_single_range(int type, void __user *buf, size_t len,
struct iovec *iov, struct iov_iter *i);
+static inline void iov_iter_ubuf(struct iov_iter *i, unsigned int direction,
+ void __user *buf, size_t count)
+{
+ WARN_ON(direction & ~(READ | WRITE));
+ *i = (struct iov_iter) {
+ .iter_type = ITER_UBUF,
+ .user_backed = true,
+ .data_source = direction,
+ .ubuf = buf,
+ .count = count
+ };
+}
+
#endif
);
TRACE_EVENT(afs_call,
- TP_PROTO(struct afs_call *call, enum afs_call_trace op,
- int usage, int outstanding, const void *where),
+ TP_PROTO(unsigned int call_debug_id, enum afs_call_trace op,
+ int ref, int outstanding, const void *where),
- TP_ARGS(call, op, usage, outstanding, where),
+ TP_ARGS(call_debug_id, op, ref, outstanding, where),
TP_STRUCT__entry(
__field(unsigned int, call )
__field(int, op )
- __field(int, usage )
+ __field(int, ref )
__field(int, outstanding )
__field(const void *, where )
),
TP_fast_assign(
- __entry->call = call->debug_id;
+ __entry->call = call_debug_id;
__entry->op = op;
- __entry->usage = usage;
+ __entry->ref = ref;
__entry->outstanding = outstanding;
__entry->where = where;
),
- TP_printk("c=%08x %s u=%d o=%d sp=%pSR",
+ TP_printk("c=%08x %s r=%d o=%d sp=%pSR",
__entry->call,
__print_symbolic(__entry->op, afs_call_traces),
- __entry->usage,
+ __entry->ref,
__entry->outstanding,
__entry->where)
);
);
TRACE_EVENT(afs_server,
- TP_PROTO(struct afs_server *server, int ref, int active,
+ TP_PROTO(unsigned int server_debug_id, int ref, int active,
enum afs_server_trace reason),
- TP_ARGS(server, ref, active, reason),
+ TP_ARGS(server_debug_id, ref, active, reason),
TP_STRUCT__entry(
__field(unsigned int, server )
),
TP_fast_assign(
- __entry->server = server->debug_id;
+ __entry->server = server_debug_id;
__entry->ref = ref;
__entry->active = active;
__entry->reason = reason;
__entry->reason = reason;
),
- TP_printk("V=%llx %s u=%d",
+ TP_printk("V=%llx %s ur=%d",
__entry->vid,
__print_symbolic(__entry->reason, afs_volume_traces),
__entry->ref)
);
TRACE_EVENT(afs_cell,
- TP_PROTO(unsigned int cell_debug_id, int usage, int active,
+ TP_PROTO(unsigned int cell_debug_id, int ref, int active,
enum afs_cell_trace reason),
- TP_ARGS(cell_debug_id, usage, active, reason),
+ TP_ARGS(cell_debug_id, ref, active, reason),
TP_STRUCT__entry(
__field(unsigned int, cell )
- __field(int, usage )
+ __field(int, ref )
__field(int, active )
__field(int, reason )
),
TP_fast_assign(
__entry->cell = cell_debug_id;
- __entry->usage = usage;
+ __entry->ref = ref;
__entry->active = active;
__entry->reason = reason;
),
- TP_printk("L=%08x %s u=%d a=%d",
+ TP_printk("L=%08x %s r=%d a=%d",
__entry->cell,
__print_symbolic(__entry->reason, afs_cell_traces),
- __entry->usage,
+ __entry->ref,
__entry->active)
);
enum fscache_cookie_trace {
fscache_cookie_collision,
fscache_cookie_discard,
+ fscache_cookie_failed,
fscache_cookie_get_attach_object,
fscache_cookie_get_end_access,
fscache_cookie_get_hash_collision,
#define fscache_cookie_traces \
EM(fscache_cookie_collision, "*COLLIDE*") \
EM(fscache_cookie_discard, "DISCARD ") \
+ EM(fscache_cookie_failed, "FAILED ") \
EM(fscache_cookie_get_attach_object, "GET attch") \
EM(fscache_cookie_get_hash_collision, "GET hcoll") \
EM(fscache_cookie_get_end_access, "GQ endac") \
TP_ARGS(state, cpu_id)
);
+TRACE_EVENT(cpu_idle_miss,
+
+ TP_PROTO(unsigned int cpu_id, unsigned int state, bool below),
+
+ TP_ARGS(cpu_id, state, below),
+
+ TP_STRUCT__entry(
+ __field(u32, cpu_id)
+ __field(u32, state)
+ __field(bool, below)
+ ),
+
+ TP_fast_assign(
+ __entry->cpu_id = cpu_id;
+ __entry->state = state;
+ __entry->below = below;
+ ),
+
+ TP_printk("cpu_id=%lu state=%lu type=%s", (unsigned long)__entry->cpu_id,
+ (unsigned long)__entry->state, (__entry->below)?"below":"above")
+);
+
TRACE_EVENT(powernv_throttle,
TP_PROTO(int chip_id, const char *reason, int pmax),
TRACE_EVENT(svc_alloc_arg_err,
TP_PROTO(
- unsigned int pages
+ unsigned int requested,
+ unsigned int allocated
),
- TP_ARGS(pages),
+ TP_ARGS(requested, allocated),
TP_STRUCT__entry(
- __field(unsigned int, pages)
+ __field(unsigned int, requested)
+ __field(unsigned int, allocated)
),
TP_fast_assign(
- __entry->pages = pages;
+ __entry->requested = requested;
+ __entry->allocated = allocated;
),
- TP_printk("pages=%u", __entry->pages)
+ TP_printk("requested=%u allocated=%u",
+ __entry->requested, __entry->allocated)
);
DECLARE_EVENT_CLASS(svc_deferred_event,
#define PCI_EXT_CAP_ID_DVSEC 0x23 /* Designated Vendor-Specific */
#define PCI_EXT_CAP_ID_DLF 0x25 /* Data Link Feature */
#define PCI_EXT_CAP_ID_PL_16GT 0x26 /* Physical Layer 16.0 GT/s */
-#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PL_16GT
+#define PCI_EXT_CAP_ID_DOE 0x2E /* Data Object Exchange */
+#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_DOE
#define PCI_EXT_CAP_DSN_SIZEOF 12
#define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
#define PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK 0x000000F0
#define PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT 4
+/* Data Object Exchange */
+#define PCI_DOE_CAP 0x04 /* DOE Capabilities Register */
+#define PCI_DOE_CAP_INT_SUP 0x00000001 /* Interrupt Support */
+#define PCI_DOE_CAP_INT_MSG_NUM 0x00000ffe /* Interrupt Message Number */
+#define PCI_DOE_CTRL 0x08 /* DOE Control Register */
+#define PCI_DOE_CTRL_ABORT 0x00000001 /* DOE Abort */
+#define PCI_DOE_CTRL_INT_EN 0x00000002 /* DOE Interrupt Enable */
+#define PCI_DOE_CTRL_GO 0x80000000 /* DOE Go */
+#define PCI_DOE_STATUS 0x0c /* DOE Status Register */
+#define PCI_DOE_STATUS_BUSY 0x00000001 /* DOE Busy */
+#define PCI_DOE_STATUS_INT_STATUS 0x00000002 /* DOE Interrupt Status */
+#define PCI_DOE_STATUS_ERROR 0x00000004 /* DOE Error */
+#define PCI_DOE_STATUS_DATA_OBJECT_READY 0x80000000 /* Data Object Ready */
+#define PCI_DOE_WRITE 0x10 /* DOE Write Data Mailbox Register */
+#define PCI_DOE_READ 0x14 /* DOE Read Data Mailbox Register */
+
+/* DOE Data Object - note not actually registers */
+#define PCI_DOE_DATA_OBJECT_HEADER_1_VID 0x0000ffff
+#define PCI_DOE_DATA_OBJECT_HEADER_1_TYPE 0x00ff0000
+#define PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH 0x0003ffff
+
+#define PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX 0x000000ff
+#define PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID 0x0000ffff
+#define PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL 0x00ff0000
+#define PCI_DOE_DATA_OBJECT_DISC_RSP_3_NEXT_INDEX 0xff000000
+
#endif /* LINUX_PCI_REGS_H */
with the "-O2" compiler flag for best performance and most
helpful compile-time warnings.
-config CC_OPTIMIZE_FOR_PERFORMANCE_O3
- bool "Optimize more for performance (-O3)"
- depends on ARC
- help
- Choosing this option will pass "-O3" to your compiler to optimize
- the kernel yet more for performance.
-
config CC_OPTIMIZE_FOR_SIZE
bool "Optimize for size (-Os)"
help
help
Normally kallsyms only contains the symbols of functions for nicer
OOPS messages and backtraces (i.e., symbols from the text and inittext
- sections). This is sufficient for most cases. And only in very rare
- cases (e.g., when a debugger is used) all symbols are required (e.g.,
- names of variables from the data sections, etc).
+ sections). This is sufficient for most cases. And only if you want to
+ enable kernel live patching, or other less common use cases (e.g.,
+ when a debugger is used) all symbols are required (i.e., names of
+ variables from the data sections, etc).
This option makes sure that all symbols are loaded into the kernel
image (i.e., symbols from all sections) in cost of increased kernel
size (depending on the kernel configuration, it may be 300KiB or
something like this).
- Say N unless you really need all symbols.
+ Say N unless you really need all symbols, or kernel live patching.
config KALLSYMS_ABSOLUTE_PERCPU
bool
def_bool n
select SYSTEM_DATA_VERIFICATION
-menuconfig MODULES
- bool "Enable loadable module support"
- modules
- help
- Kernel modules are small pieces of compiled code which can
- be inserted in the running kernel, rather than being
- permanently built into the kernel. You use the "modprobe"
- tool to add (and sometimes remove) them. If you say Y here,
- many parts of the kernel can be built as modules (by
- answering M instead of Y where indicated): this is most
- useful for infrequently used options which are not required
- for booting. For more information, see the man pages for
- modprobe, lsmod, modinfo, insmod and rmmod.
-
- If you say Y here, you will need to run "make
- modules_install" to put the modules under /lib/modules/
- where modprobe can find them (you may need to be root to do
- this).
-
- If unsure, say Y.
-
-if MODULES
-
-config MODULE_FORCE_LOAD
- bool "Forced module loading"
- default n
- help
- Allow loading of modules without version information (ie. modprobe
- --force). Forced module loading sets the 'F' (forced) taint flag and
- is usually a really bad idea.
-
-config MODULE_UNLOAD
- bool "Module unloading"
- help
- Without this option you will not be able to unload any
- modules (note that some modules may not be unloadable
- anyway), which makes your kernel smaller, faster
- and simpler. If unsure, say Y.
-
-config MODULE_FORCE_UNLOAD
- bool "Forced module unloading"
- depends on MODULE_UNLOAD
- help
- This option allows you to force a module to unload, even if the
- kernel believes it is unsafe: the kernel will remove the module
- without waiting for anyone to stop using it (using the -f option to
- rmmod). This is mainly for kernel developers and desperate users.
- If unsure, say N.
-
-config MODULE_UNLOAD_TAINT_TRACKING
- bool "Tainted module unload tracking"
- depends on MODULE_UNLOAD
- default n
- help
- This option allows you to maintain a record of each unloaded
- module that tainted the kernel. In addition to displaying a
- list of linked (or loaded) modules e.g. on detection of a bad
- page (see bad_page()), the aforementioned details are also
- shown. If unsure, say N.
-
-config MODVERSIONS
- bool "Module versioning support"
- help
- Usually, you have to use modules compiled with your kernel.
- Saying Y here makes it sometimes possible to use modules
- compiled for different kernels, by adding enough information
- to the modules to (hopefully) spot any changes which would
- make them incompatible with the kernel you are running. If
- unsure, say N.
-
-config ASM_MODVERSIONS
- bool
- default HAVE_ASM_MODVERSIONS && MODVERSIONS
- help
- This enables module versioning for exported symbols also from
- assembly. This can be enabled only when the target architecture
- supports it.
-
-config MODULE_SRCVERSION_ALL
- bool "Source checksum for all modules"
- help
- Modules which contain a MODULE_VERSION get an extra "srcversion"
- field inserted into their modinfo section, which contains a
- sum of the source files which made it. This helps maintainers
- see exactly which source was used to build a module (since
- others sometimes change the module source without updating
- the version). With this option, such a "srcversion" field
- will be created for all modules. If unsure, say N.
-
-config MODULE_SIG
- bool "Module signature verification"
- select MODULE_SIG_FORMAT
- help
- Check modules for valid signatures upon load: the signature
- is simply appended to the module. For more information see
- <file:Documentation/admin-guide/module-signing.rst>.
-
- Note that this option adds the OpenSSL development packages as a
- kernel build dependency so that the signing tool can use its crypto
- library.
-
- You should enable this option if you wish to use either
- CONFIG_SECURITY_LOCKDOWN_LSM or lockdown functionality imposed via
- another LSM - otherwise unsigned modules will be loadable regardless
- of the lockdown policy.
-
- !!!WARNING!!! If you enable this option, you MUST make sure that the
- module DOES NOT get stripped after being signed. This includes the
- debuginfo strip done by some packagers (such as rpmbuild) and
- inclusion into an initramfs that wants the module size reduced.
-
-config MODULE_SIG_FORCE
- bool "Require modules to be validly signed"
- depends on MODULE_SIG
- help
- Reject unsigned modules or signed modules for which we don't have a
- key. Without this, such modules will simply taint the kernel.
-
-config MODULE_SIG_ALL
- bool "Automatically sign all modules"
- default y
- depends on MODULE_SIG || IMA_APPRAISE_MODSIG
- help
- Sign all modules during make modules_install. Without this option,
- modules must be signed manually, using the scripts/sign-file tool.
-
-comment "Do not forget to sign required modules with scripts/sign-file"
- depends on MODULE_SIG_FORCE && !MODULE_SIG_ALL
-
-choice
- prompt "Which hash algorithm should modules be signed with?"
- depends on MODULE_SIG || IMA_APPRAISE_MODSIG
- help
- This determines which sort of hashing algorithm will be used during
- signature generation. This algorithm _must_ be built into the kernel
- directly so that signature verification can take place. It is not
- possible to load a signed module containing the algorithm to check
- the signature on that module.
-
-config MODULE_SIG_SHA1
- bool "Sign modules with SHA-1"
- select CRYPTO_SHA1
-
-config MODULE_SIG_SHA224
- bool "Sign modules with SHA-224"
- select CRYPTO_SHA256
-
-config MODULE_SIG_SHA256
- bool "Sign modules with SHA-256"
- select CRYPTO_SHA256
-
-config MODULE_SIG_SHA384
- bool "Sign modules with SHA-384"
- select CRYPTO_SHA512
-
-config MODULE_SIG_SHA512
- bool "Sign modules with SHA-512"
- select CRYPTO_SHA512
-
-endchoice
-
-config MODULE_SIG_HASH
- string
- depends on MODULE_SIG || IMA_APPRAISE_MODSIG
- default "sha1" if MODULE_SIG_SHA1
- default "sha224" if MODULE_SIG_SHA224
- default "sha256" if MODULE_SIG_SHA256
- default "sha384" if MODULE_SIG_SHA384
- default "sha512" if MODULE_SIG_SHA512
-
-choice
- prompt "Module compression mode"
- help
- This option allows you to choose the algorithm which will be used to
- compress modules when 'make modules_install' is run. (or, you can
- choose to not compress modules at all.)
-
- External modules will also be compressed in the same way during the
- installation.
-
- For modules inside an initrd or initramfs, it's more efficient to
- compress the whole initrd or initramfs instead.
-
- This is fully compatible with signed modules.
-
- Please note that the tool used to load modules needs to support the
- corresponding algorithm. module-init-tools MAY support gzip, and kmod
- MAY support gzip, xz and zstd.
-
- Your build system needs to provide the appropriate compression tool
- to compress the modules.
-
- If in doubt, select 'None'.
-
-config MODULE_COMPRESS_NONE
- bool "None"
- help
- Do not compress modules. The installed modules are suffixed
- with .ko.
-
-config MODULE_COMPRESS_GZIP
- bool "GZIP"
- help
- Compress modules with GZIP. The installed modules are suffixed
- with .ko.gz.
-
-config MODULE_COMPRESS_XZ
- bool "XZ"
- help
- Compress modules with XZ. The installed modules are suffixed
- with .ko.xz.
-
-config MODULE_COMPRESS_ZSTD
- bool "ZSTD"
- help
- Compress modules with ZSTD. The installed modules are suffixed
- with .ko.zst.
-
-endchoice
-
-config MODULE_DECOMPRESS
- bool "Support in-kernel module decompression"
- depends on MODULE_COMPRESS_GZIP || MODULE_COMPRESS_XZ
- select ZLIB_INFLATE if MODULE_COMPRESS_GZIP
- select XZ_DEC if MODULE_COMPRESS_XZ
- help
-
- Support for decompressing kernel modules by the kernel itself
- instead of relying on userspace to perform this task. Useful when
- load pinning security policy is enabled.
-
- If unsure, say N.
-
-config MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
- bool "Allow loading of modules with missing namespace imports"
- help
- Symbols exported with EXPORT_SYMBOL_NS*() are considered exported in
- a namespace. A module that makes use of a symbol exported with such a
- namespace is required to import the namespace via MODULE_IMPORT_NS().
- There is no technical reason to enforce correct namespace imports,
- but it creates consistency between symbols defining namespaces and
- users importing namespaces they make use of. This option relaxes this
- requirement and lifts the enforcement when loading a module.
-
- If unsure, say N.
-
-config MODPROBE_PATH
- string "Path to modprobe binary"
- default "/sbin/modprobe"
- help
- When kernel code requests a module, it does so by calling
- the "modprobe" userspace utility. This option allows you to
- set the path where that binary is found. This can be changed
- at runtime via the sysctl file
- /proc/sys/kernel/modprobe. Setting this to the empty string
- removes the kernel's ability to request modules (but
- userspace can still load modules explicitly).
-
-config TRIM_UNUSED_KSYMS
- bool "Trim unused exported kernel symbols" if EXPERT
- depends on !COMPILE_TEST
- help
- The kernel and some modules make many symbols available for
- other modules to use via EXPORT_SYMBOL() and variants. Depending
- on the set of modules being selected in your kernel configuration,
- many of those exported symbols might never be used.
-
- This option allows for unused exported symbols to be dropped from
- the build. In turn, this provides the compiler more opportunities
- (especially when using LTO) for optimizing the code and reducing
- binary size. This might have some security advantages as well.
-
- If unsure, or if you need to build out-of-tree modules, say N.
-
-config UNUSED_KSYMS_WHITELIST
- string "Whitelist of symbols to keep in ksymtab"
- depends on TRIM_UNUSED_KSYMS
- help
- By default, all unused exported symbols will be un-exported from the
- build when TRIM_UNUSED_KSYMS is selected.
-
- UNUSED_KSYMS_WHITELIST allows to whitelist symbols that must be kept
- exported at all times, even in absence of in-tree users. The value to
- set here is the path to a text file containing the list of symbols,
- one per line. The path can be absolute, or relative to the kernel
- source tree.
-
-endif # MODULES
-
-config MODULES_TREE_LOOKUP
- def_bool y
- depends on PERF_EVENTS || TRACING || CFI_CLANG
+source "kernel/module/Kconfig"
config INIT_ALL_POSSIBLE
bool
return ERR_PTR(-ENOMEM);
}
-static void dma_release_coherent_memory(struct dma_coherent_mem *mem)
+static void _dma_release_coherent_memory(struct dma_coherent_mem *mem)
{
if (!mem)
return;
ret = dma_assign_coherent_memory(dev, mem);
if (ret)
- dma_release_coherent_memory(mem);
+ _dma_release_coherent_memory(mem);
return ret;
}
+void dma_release_coherent_memory(struct device *dev)
+{
+ if (dev)
+ _dma_release_coherent_memory(dev->dma_mem);
+}
+
static void *__dma_alloc_from_coherent(struct device *dev,
struct dma_coherent_mem *mem,
ssize_t size, dma_addr_t *dma_handle)
--- /dev/null
+# SPDX-License-Identifier: GPL-2.0-only
+menuconfig MODULES
+ bool "Enable loadable module support"
+ modules
+ help
+ Kernel modules are small pieces of compiled code which can
+ be inserted in the running kernel, rather than being
+ permanently built into the kernel. You use the "modprobe"
+ tool to add (and sometimes remove) them. If you say Y here,
+ many parts of the kernel can be built as modules (by
+ answering M instead of Y where indicated): this is most
+ useful for infrequently used options which are not required
+ for booting. For more information, see the man pages for
+ modprobe, lsmod, modinfo, insmod and rmmod.
+
+ If you say Y here, you will need to run "make
+ modules_install" to put the modules under /lib/modules/
+ where modprobe can find them (you may need to be root to do
+ this).
+
+ If unsure, say Y.
+
+if MODULES
+
+config MODULE_FORCE_LOAD
+ bool "Forced module loading"
+ default n
+ help
+ Allow loading of modules without version information (ie. modprobe
+ --force). Forced module loading sets the 'F' (forced) taint flag and
+ is usually a really bad idea.
+
+config MODULE_UNLOAD
+ bool "Module unloading"
+ help
+ Without this option you will not be able to unload any
+ modules (note that some modules may not be unloadable
+ anyway), which makes your kernel smaller, faster
+ and simpler. If unsure, say Y.
+
+config MODULE_FORCE_UNLOAD
+ bool "Forced module unloading"
+ depends on MODULE_UNLOAD
+ help
+ This option allows you to force a module to unload, even if the
+ kernel believes it is unsafe: the kernel will remove the module
+ without waiting for anyone to stop using it (using the -f option to
+ rmmod). This is mainly for kernel developers and desperate users.
+ If unsure, say N.
+
+config MODULE_UNLOAD_TAINT_TRACKING
+ bool "Tainted module unload tracking"
+ depends on MODULE_UNLOAD
+ default n
+ help
+ This option allows you to maintain a record of each unloaded
+ module that tainted the kernel. In addition to displaying a
+ list of linked (or loaded) modules e.g. on detection of a bad
+ page (see bad_page()), the aforementioned details are also
+ shown. If unsure, say N.
+
+config MODVERSIONS
+ bool "Module versioning support"
+ help
+ Usually, you have to use modules compiled with your kernel.
+ Saying Y here makes it sometimes possible to use modules
+ compiled for different kernels, by adding enough information
+ to the modules to (hopefully) spot any changes which would
+ make them incompatible with the kernel you are running. If
+ unsure, say N.
+
+config ASM_MODVERSIONS
+ bool
+ default HAVE_ASM_MODVERSIONS && MODVERSIONS
+ help
+ This enables module versioning for exported symbols also from
+ assembly. This can be enabled only when the target architecture
+ supports it.
+
+config MODULE_SRCVERSION_ALL
+ bool "Source checksum for all modules"
+ help
+ Modules which contain a MODULE_VERSION get an extra "srcversion"
+ field inserted into their modinfo section, which contains a
+ sum of the source files which made it. This helps maintainers
+ see exactly which source was used to build a module (since
+ others sometimes change the module source without updating
+ the version). With this option, such a "srcversion" field
+ will be created for all modules. If unsure, say N.
+
+config MODULE_SIG
+ bool "Module signature verification"
+ select MODULE_SIG_FORMAT
+ help
+ Check modules for valid signatures upon load: the signature
+ is simply appended to the module. For more information see
+ <file:Documentation/admin-guide/module-signing.rst>.
+
+ Note that this option adds the OpenSSL development packages as a
+ kernel build dependency so that the signing tool can use its crypto
+ library.
+
+ You should enable this option if you wish to use either
+ CONFIG_SECURITY_LOCKDOWN_LSM or lockdown functionality imposed via
+ another LSM - otherwise unsigned modules will be loadable regardless
+ of the lockdown policy.
+
+ !!!WARNING!!! If you enable this option, you MUST make sure that the
+ module DOES NOT get stripped after being signed. This includes the
+ debuginfo strip done by some packagers (such as rpmbuild) and
+ inclusion into an initramfs that wants the module size reduced.
+
+config MODULE_SIG_FORCE
+ bool "Require modules to be validly signed"
+ depends on MODULE_SIG
+ help
+ Reject unsigned modules or signed modules for which we don't have a
+ key. Without this, such modules will simply taint the kernel.
+
+config MODULE_SIG_ALL
+ bool "Automatically sign all modules"
+ default y
+ depends on MODULE_SIG || IMA_APPRAISE_MODSIG
+ help
+ Sign all modules during make modules_install. Without this option,
+ modules must be signed manually, using the scripts/sign-file tool.
+
+comment "Do not forget to sign required modules with scripts/sign-file"
+ depends on MODULE_SIG_FORCE && !MODULE_SIG_ALL
+
+choice
+ prompt "Which hash algorithm should modules be signed with?"
+ depends on MODULE_SIG || IMA_APPRAISE_MODSIG
+ help
+ This determines which sort of hashing algorithm will be used during
+ signature generation. This algorithm _must_ be built into the kernel
+ directly so that signature verification can take place. It is not
+ possible to load a signed module containing the algorithm to check
+ the signature on that module.
+
+config MODULE_SIG_SHA1
+ bool "Sign modules with SHA-1"
+ select CRYPTO_SHA1
+
+config MODULE_SIG_SHA224
+ bool "Sign modules with SHA-224"
+ select CRYPTO_SHA256
+
+config MODULE_SIG_SHA256
+ bool "Sign modules with SHA-256"
+ select CRYPTO_SHA256
+
+config MODULE_SIG_SHA384
+ bool "Sign modules with SHA-384"
+ select CRYPTO_SHA512
+
+config MODULE_SIG_SHA512
+ bool "Sign modules with SHA-512"
+ select CRYPTO_SHA512
+
+endchoice
+
+config MODULE_SIG_HASH
+ string
+ depends on MODULE_SIG || IMA_APPRAISE_MODSIG
+ default "sha1" if MODULE_SIG_SHA1
+ default "sha224" if MODULE_SIG_SHA224
+ default "sha256" if MODULE_SIG_SHA256
+ default "sha384" if MODULE_SIG_SHA384
+ default "sha512" if MODULE_SIG_SHA512
+
+choice
+ prompt "Module compression mode"
+ help
+ This option allows you to choose the algorithm which will be used to
+ compress modules when 'make modules_install' is run. (or, you can
+ choose to not compress modules at all.)
+
+ External modules will also be compressed in the same way during the
+ installation.
+
+ For modules inside an initrd or initramfs, it's more efficient to
+ compress the whole initrd or initramfs instead.
+
+ This is fully compatible with signed modules.
+
+ Please note that the tool used to load modules needs to support the
+ corresponding algorithm. module-init-tools MAY support gzip, and kmod
+ MAY support gzip, xz and zstd.
+
+ Your build system needs to provide the appropriate compression tool
+ to compress the modules.
+
+ If in doubt, select 'None'.
+
+config MODULE_COMPRESS_NONE
+ bool "None"
+ help
+ Do not compress modules. The installed modules are suffixed
+ with .ko.
+
+config MODULE_COMPRESS_GZIP
+ bool "GZIP"
+ help
+ Compress modules with GZIP. The installed modules are suffixed
+ with .ko.gz.
+
+config MODULE_COMPRESS_XZ
+ bool "XZ"
+ help
+ Compress modules with XZ. The installed modules are suffixed
+ with .ko.xz.
+
+config MODULE_COMPRESS_ZSTD
+ bool "ZSTD"
+ help
+ Compress modules with ZSTD. The installed modules are suffixed
+ with .ko.zst.
+
+endchoice
+
+config MODULE_DECOMPRESS
+ bool "Support in-kernel module decompression"
+ depends on MODULE_COMPRESS_GZIP || MODULE_COMPRESS_XZ
+ select ZLIB_INFLATE if MODULE_COMPRESS_GZIP
+ select XZ_DEC if MODULE_COMPRESS_XZ
+ help
+
+ Support for decompressing kernel modules by the kernel itself
+ instead of relying on userspace to perform this task. Useful when
+ load pinning security policy is enabled.
+
+ If unsure, say N.
+
+config MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
+ bool "Allow loading of modules with missing namespace imports"
+ help
+ Symbols exported with EXPORT_SYMBOL_NS*() are considered exported in
+ a namespace. A module that makes use of a symbol exported with such a
+ namespace is required to import the namespace via MODULE_IMPORT_NS().
+ There is no technical reason to enforce correct namespace imports,
+ but it creates consistency between symbols defining namespaces and
+ users importing namespaces they make use of. This option relaxes this
+ requirement and lifts the enforcement when loading a module.
+
+ If unsure, say N.
+
+config MODPROBE_PATH
+ string "Path to modprobe binary"
+ default "/sbin/modprobe"
+ help
+ When kernel code requests a module, it does so by calling
+ the "modprobe" userspace utility. This option allows you to
+ set the path where that binary is found. This can be changed
+ at runtime via the sysctl file
+ /proc/sys/kernel/modprobe. Setting this to the empty string
+ removes the kernel's ability to request modules (but
+ userspace can still load modules explicitly).
+
+config TRIM_UNUSED_KSYMS
+ bool "Trim unused exported kernel symbols" if EXPERT
+ depends on !COMPILE_TEST
+ help
+ The kernel and some modules make many symbols available for
+ other modules to use via EXPORT_SYMBOL() and variants. Depending
+ on the set of modules being selected in your kernel configuration,
+ many of those exported symbols might never be used.
+
+ This option allows for unused exported symbols to be dropped from
+ the build. In turn, this provides the compiler more opportunities
+ (especially when using LTO) for optimizing the code and reducing
+ binary size. This might have some security advantages as well.
+
+ If unsure, or if you need to build out-of-tree modules, say N.
+
+config UNUSED_KSYMS_WHITELIST
+ string "Whitelist of symbols to keep in ksymtab"
+ depends on TRIM_UNUSED_KSYMS
+ help
+ By default, all unused exported symbols will be un-exported from the
+ build when TRIM_UNUSED_KSYMS is selected.
+
+ UNUSED_KSYMS_WHITELIST allows to whitelist symbols that must be kept
+ exported at all times, even in absence of in-tree users. The value to
+ set here is the path to a text file containing the list of symbols,
+ one per line. The path can be absolute, or relative to the kernel
+ source tree.
+
+config MODULES_TREE_LOOKUP
+ def_bool y
+ depends on PERF_EVENTS || TRACING || CFI_CLANG
+
+endif # MODULES
goto out_inflate_end;
}
- s.next_out = kmap(page);
+ s.next_out = kmap_local_page(page);
s.avail_out = PAGE_SIZE;
rc = zlib_inflate(&s, 0);
- kunmap(page);
+ kunmap_local(s.next_out);
new_size += PAGE_SIZE - s.avail_out;
} while (rc == Z_OK);
goto out;
}
- xz_buf.out = kmap(page);
+ xz_buf.out = kmap_local_page(page);
xz_buf.out_pos = 0;
xz_buf.out_size = PAGE_SIZE;
xz_ret = xz_dec_run(xz_dec, &xz_buf);
- kunmap(page);
+ kunmap_local(xz_buf.out);
new_size += xz_buf.out_pos;
} while (xz_buf.out_pos == PAGE_SIZE && xz_ret == XZ_OK);
int cmp_name(const void *name, const void *sym);
long module_get_offset(struct module *mod, unsigned int *size, Elf_Shdr *sechdr,
unsigned int section);
-char *module_flags(struct module *mod, char *buf);
+char *module_flags(struct module *mod, char *buf, bool show_state);
size_t module_flags_taint(unsigned long taints, char *buf);
static inline void module_assert_mutex_or_preempt(void)
return 0;
}
-/* Look for this name: can be of form module:name. */
-unsigned long module_kallsyms_lookup_name(const char *name)
+static unsigned long __module_kallsyms_lookup_name(const char *name)
{
struct module *mod;
char *colon;
- unsigned long ret = 0;
+
+ colon = strnchr(name, MODULE_NAME_LEN, ':');
+ if (colon) {
+ mod = find_module_all(name, colon - name, false);
+ if (mod)
+ return find_kallsyms_symbol_value(mod, colon + 1);
+ return 0;
+ }
+
+ list_for_each_entry_rcu(mod, &modules, list) {
+ unsigned long ret;
+
+ if (mod->state == MODULE_STATE_UNFORMED)
+ continue;
+ ret = find_kallsyms_symbol_value(mod, name);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+/* Look for this name: can be of form module:name. */
+unsigned long module_kallsyms_lookup_name(const char *name)
+{
+ unsigned long ret;
/* Don't lock: we're in enough trouble already. */
preempt_disable();
- if ((colon = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) {
- if ((mod = find_module_all(name, colon - name, false)) != NULL)
- ret = find_kallsyms_symbol_value(mod, colon + 1);
- } else {
- list_for_each_entry_rcu(mod, &modules, list) {
- if (mod->state == MODULE_STATE_UNFORMED)
- continue;
- if ((ret = find_kallsyms_symbol_value(mod, name)) != 0)
- break;
- }
- }
+ ret = __module_kallsyms_lookup_name(name);
preempt_enable();
return ret;
}
}
/* Block module loading/unloading? */
-int modules_disabled = 0;
+int modules_disabled;
core_param(nomodule, modules_disabled, bint, 0);
/* Waiting for a module to finish initializing? */
MODINFO_ATTR(version);
MODINFO_ATTR(srcversion);
-static char last_unloaded_module[MODULE_NAME_LEN+1];
+static struct {
+ char name[MODULE_NAME_LEN + 1];
+ char taints[MODULE_FLAGS_BUF_SIZE];
+} last_unloaded_module;
#ifdef CONFIG_MODULE_UNLOAD
{
struct module *mod;
char name[MODULE_NAME_LEN];
+ char buf[MODULE_FLAGS_BUF_SIZE];
int ret, forced = 0;
if (!capable(CAP_SYS_MODULE) || modules_disabled)
async_synchronize_full();
- /* Store the name of the last unloaded module for diagnostic purposes */
- strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
+ /* Store the name and taints of the last unloaded module for diagnostic purposes */
+ strscpy(last_unloaded_module.name, mod->name, sizeof(last_unloaded_module.name));
+ strscpy(last_unloaded_module.taints, module_flags(mod, buf, false), sizeof(last_unloaded_module.taints));
free_module(mod);
/* someone could wait for the module in add_unformed_module() */
#ifdef CONFIG_ARCH_WANTS_MODULES_DATA_IN_VMALLOC
/* Do the allocs. */
- ptr = vmalloc(mod->data_layout.size);
+ ptr = vzalloc(mod->data_layout.size);
/*
* The pointer to this block is stored in the module structure
* which is inside the block. Just mark it as not being a
return -ENOMEM;
}
- memset(ptr, 0, mod->data_layout.size);
mod->data_layout.base = ptr;
#endif
/* Transfer each section which specifies SHF_ALLOC */
}
}
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "module."
+/* Default value for module->async_probe_requested */
+static bool async_probe;
+module_param(async_probe, bool, 0644);
+
/*
* This is where the real work happens.
*
int ret;
if (strcmp(param, "async_probe") == 0) {
- mod->async_probe_requested = true;
+ if (strtobool(val, &mod->async_probe_requested))
+ mod->async_probe_requested = true;
return 0;
}
if (err)
goto bug_cleanup;
+ mod->async_probe_requested = async_probe;
+
/* Module is ready to execute: parsing args may do that. */
after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
-32768, 32767, mod,
}
/* Keep in sync with MODULE_FLAGS_BUF_SIZE !!! */
-char *module_flags(struct module *mod, char *buf)
+char *module_flags(struct module *mod, char *buf, bool show_state)
{
int bx = 0;
BUG_ON(mod->state == MODULE_STATE_UNFORMED);
+ if (!mod->taints && !show_state)
+ goto out;
if (mod->taints ||
mod->state == MODULE_STATE_GOING ||
mod->state == MODULE_STATE_COMING) {
buf[bx++] = '(';
bx += module_flags_taint(mod->taints, buf + bx);
/* Show a - for module-is-being-unloaded */
- if (mod->state == MODULE_STATE_GOING)
+ if (mod->state == MODULE_STATE_GOING && show_state)
buf[bx++] = '-';
/* Show a + for module-is-being-loaded */
- if (mod->state == MODULE_STATE_COMING)
+ if (mod->state == MODULE_STATE_COMING && show_state)
buf[bx++] = '+';
buf[bx++] = ')';
}
+out:
buf[bx] = '\0';
return buf;
list_for_each_entry_rcu(mod, &modules, list) {
if (mod->state == MODULE_STATE_UNFORMED)
continue;
- pr_cont(" %s%s", mod->name, module_flags(mod, buf));
+ pr_cont(" %s%s", mod->name, module_flags(mod, buf, true));
}
print_unloaded_tainted_modules();
preempt_enable();
- if (last_unloaded_module[0])
- pr_cont(" [last unloaded: %s]", last_unloaded_module);
+ if (last_unloaded_module.name[0])
+ pr_cont(" [last unloaded: %s%s]", last_unloaded_module.name,
+ last_unloaded_module.taints);
pr_cont("\n");
}
/* Taints info */
if (mod->taints)
- seq_printf(m, " %s", module_flags(mod, buf));
+ seq_printf(m, " %s", module_flags(mod, buf, true));
seq_puts(m, "\n");
return 0;
}
EXPORT_SYMBOL_GPL(page_is_ram);
-static int __region_intersects(resource_size_t start, size_t size,
- unsigned long flags, unsigned long desc)
+static int __region_intersects(struct resource *parent, resource_size_t start,
+ size_t size, unsigned long flags,
+ unsigned long desc)
{
struct resource res;
int type = 0; int other = 0;
res.start = start;
res.end = start + size - 1;
- for (p = iomem_resource.child; p ; p = p->sibling) {
+ for (p = parent->child; p ; p = p->sibling) {
bool is_type = (((p->flags & flags) == flags) &&
((desc == IORES_DESC_NONE) ||
(desc == p->desc)));
int ret;
read_lock(&resource_lock);
- ret = __region_intersects(start, size, flags, desc);
+ ret = __region_intersects(&iomem_resource, start, size, flags, desc);
read_unlock(&resource_lock);
return ret;
}
write_unlock(&resource_lock);
}
+/*
+ * Not for general consumption, only early boot memory map parsing, PCI
+ * resource discovery, and late discovery of CXL resources are expected
+ * to use this interface. The former are built-in and only the latter,
+ * CXL, is a module.
+ */
+EXPORT_SYMBOL_NS_GPL(insert_resource_expand_to_fit, CXL);
/**
* remove_resource - Remove a resource in the resource tree
}
EXPORT_SYMBOL(resource_list_free);
-#ifdef CONFIG_DEVICE_PRIVATE
-static struct resource *__request_free_mem_region(struct device *dev,
- struct resource *base, unsigned long size, const char *name)
+#ifdef CONFIG_GET_FREE_REGION
+#define GFR_DESCENDING (1UL << 0)
+#define GFR_REQUEST_REGION (1UL << 1)
+#define GFR_DEFAULT_ALIGN (1UL << PA_SECTION_SHIFT)
+
+static resource_size_t gfr_start(struct resource *base, resource_size_t size,
+ resource_size_t align, unsigned long flags)
+{
+ if (flags & GFR_DESCENDING) {
+ resource_size_t end;
+
+ end = min_t(resource_size_t, base->end,
+ (1ULL << MAX_PHYSMEM_BITS) - 1);
+ return end - size + 1;
+ }
+
+ return ALIGN(base->start, align);
+}
+
+static bool gfr_continue(struct resource *base, resource_size_t addr,
+ resource_size_t size, unsigned long flags)
+{
+ if (flags & GFR_DESCENDING)
+ return addr > size && addr >= base->start;
+ /*
+ * In the ascend case be careful that the last increment by
+ * @size did not wrap 0.
+ */
+ return addr > addr - size &&
+ addr <= min_t(resource_size_t, base->end,
+ (1ULL << MAX_PHYSMEM_BITS) - 1);
+}
+
+static resource_size_t gfr_next(resource_size_t addr, resource_size_t size,
+ unsigned long flags)
{
- resource_size_t end, addr;
+ if (flags & GFR_DESCENDING)
+ return addr - size;
+ return addr + size;
+}
+
+static void remove_free_mem_region(void *_res)
+{
+ struct resource *res = _res;
+
+ if (res->parent)
+ remove_resource(res);
+ free_resource(res);
+}
+
+static struct resource *
+get_free_mem_region(struct device *dev, struct resource *base,
+ resource_size_t size, const unsigned long align,
+ const char *name, const unsigned long desc,
+ const unsigned long flags)
+{
+ resource_size_t addr;
struct resource *res;
struct region_devres *dr = NULL;
- size = ALIGN(size, 1UL << PA_SECTION_SHIFT);
- end = min_t(unsigned long, base->end, (1UL << MAX_PHYSMEM_BITS) - 1);
- addr = end - size + 1UL;
+ size = ALIGN(size, align);
res = alloc_resource(GFP_KERNEL);
if (!res)
return ERR_PTR(-ENOMEM);
- if (dev) {
+ if (dev && (flags & GFR_REQUEST_REGION)) {
dr = devres_alloc(devm_region_release,
sizeof(struct region_devres), GFP_KERNEL);
if (!dr) {
free_resource(res);
return ERR_PTR(-ENOMEM);
}
+ } else if (dev) {
+ if (devm_add_action_or_reset(dev, remove_free_mem_region, res))
+ return ERR_PTR(-ENOMEM);
}
write_lock(&resource_lock);
- for (; addr > size && addr >= base->start; addr -= size) {
- if (__region_intersects(addr, size, 0, IORES_DESC_NONE) !=
- REGION_DISJOINT)
+ for (addr = gfr_start(base, size, align, flags);
+ gfr_continue(base, addr, size, flags);
+ addr = gfr_next(addr, size, flags)) {
+ if (__region_intersects(base, addr, size, 0, IORES_DESC_NONE) !=
+ REGION_DISJOINT)
continue;
- if (__request_region_locked(res, &iomem_resource, addr, size,
- name, 0))
- break;
+ if (flags & GFR_REQUEST_REGION) {
+ if (__request_region_locked(res, &iomem_resource, addr,
+ size, name, 0))
+ break;
- if (dev) {
- dr->parent = &iomem_resource;
- dr->start = addr;
- dr->n = size;
- devres_add(dev, dr);
- }
+ if (dev) {
+ dr->parent = &iomem_resource;
+ dr->start = addr;
+ dr->n = size;
+ devres_add(dev, dr);
+ }
- res->desc = IORES_DESC_DEVICE_PRIVATE_MEMORY;
- write_unlock(&resource_lock);
+ res->desc = desc;
+ write_unlock(&resource_lock);
+
+
+ /*
+ * A driver is claiming this region so revoke any
+ * mappings.
+ */
+ revoke_iomem(res);
+ } else {
+ res->start = addr;
+ res->end = addr + size - 1;
+ res->name = name;
+ res->desc = desc;
+ res->flags = IORESOURCE_MEM;
+
+ /*
+ * Only succeed if the resource hosts an exclusive
+ * range after the insert
+ */
+ if (__insert_resource(base, res) || res->child)
+ break;
+
+ write_unlock(&resource_lock);
+ }
- /*
- * A driver is claiming this region so revoke any mappings.
- */
- revoke_iomem(res);
return res;
}
write_unlock(&resource_lock);
- free_resource(res);
- if (dr)
+ if (flags & GFR_REQUEST_REGION) {
+ free_resource(res);
devres_free(dr);
+ } else if (dev)
+ devm_release_action(dev, remove_free_mem_region, res);
return ERR_PTR(-ERANGE);
}
struct resource *devm_request_free_mem_region(struct device *dev,
struct resource *base, unsigned long size)
{
- return __request_free_mem_region(dev, base, size, dev_name(dev));
+ unsigned long flags = GFR_DESCENDING | GFR_REQUEST_REGION;
+
+ return get_free_mem_region(dev, base, size, GFR_DEFAULT_ALIGN,
+ dev_name(dev),
+ IORES_DESC_DEVICE_PRIVATE_MEMORY, flags);
}
EXPORT_SYMBOL_GPL(devm_request_free_mem_region);
struct resource *request_free_mem_region(struct resource *base,
unsigned long size, const char *name)
{
- return __request_free_mem_region(NULL, base, size, name);
+ unsigned long flags = GFR_DESCENDING | GFR_REQUEST_REGION;
+
+ return get_free_mem_region(NULL, base, size, GFR_DEFAULT_ALIGN, name,
+ IORES_DESC_DEVICE_PRIVATE_MEMORY, flags);
}
EXPORT_SYMBOL_GPL(request_free_mem_region);
-#endif /* CONFIG_DEVICE_PRIVATE */
+/**
+ * alloc_free_mem_region - find a free region relative to @base
+ * @base: resource that will parent the new resource
+ * @size: size in bytes of memory to allocate from @base
+ * @align: alignment requirements for the allocation
+ * @name: resource name
+ *
+ * Buses like CXL, that can dynamically instantiate new memory regions,
+ * need a method to allocate physical address space for those regions.
+ * Allocate and insert a new resource to cover a free, unclaimed by a
+ * descendant of @base, range in the span of @base.
+ */
+struct resource *alloc_free_mem_region(struct resource *base,
+ unsigned long size, unsigned long align,
+ const char *name)
+{
+ /* Default of ascending direction and insert resource */
+ unsigned long flags = 0;
+
+ return get_free_mem_region(NULL, base, size, align, name,
+ IORES_DESC_NONE, flags);
+}
+EXPORT_SYMBOL_NS_GPL(alloc_free_mem_region, CXL);
+#endif /* CONFIG_GET_FREE_REGION */
static int __init strict_iomem(char *str)
{
int *i, vleft, first = 1, err = 0;
size_t left;
char *p;
-
+
if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) {
*lenp = 0;
return 0;
}
-
+
i = (int *) tbl_data;
vleft = table->maxlen / sizeof(*i);
left = *lenp;
* @ppos: file position
*
* Reads/writes up to table->maxlen/sizeof(unsigned int) integer
- * values from/to the user buffer, treated as an ASCII string.
+ * values from/to the user buffer, treated as an ASCII string.
*
* Returns 0 on success.
*/
* @ppos: file position
*
* Reads/writes up to table->maxlen/sizeof(unsigned int) integer
- * values from/to the user buffer, treated as an ASCII string.
+ * values from/to the user buffer, treated as an ASCII string.
* The values read are assumed to be in seconds, and are converted into
* jiffies.
*
* @ppos: pointer to the file position
*
* Reads/writes up to table->maxlen/sizeof(unsigned int) integer
- * values from/to the user buffer, treated as an ASCII string.
- * The values read are assumed to be in 1/USER_HZ seconds, and
+ * values from/to the user buffer, treated as an ASCII string.
+ * The values read are assumed to be in 1/USER_HZ seconds, and
* are converted into jiffies.
*
* Returns 0 on success.
int proc_dointvec_userhz_jiffies(struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
- return do_proc_dointvec(table,write,buffer,lenp,ppos,
- do_proc_dointvec_userhz_jiffies_conv,NULL);
+ return do_proc_dointvec(table, write, buffer, lenp, ppos,
+ do_proc_dointvec_userhz_jiffies_conv, NULL);
}
/**
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE,
},
-#if defined(CONFIG_TREE_RCU)
+#ifdef CONFIG_TREE_RCU
{
.procname = "panic_on_rcu_stall",
.data = &sysctl_panic_on_rcu_stall,
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE,
},
-#endif
-#if defined(CONFIG_TREE_RCU)
{
.procname = "max_rcu_stall_to_panic",
.data = &sysctl_max_rcu_stall_to_panic,
#define PIPE_PARANOIA /* for now */
+/* covers ubuf and kbuf alike */
+#define iterate_buf(i, n, base, len, off, __p, STEP) { \
+ size_t __maybe_unused off = 0; \
+ len = n; \
+ base = __p + i->iov_offset; \
+ len -= (STEP); \
+ i->iov_offset += len; \
+ n = len; \
+}
+
/* covers iovec and kvec alike */
#define iterate_iovec(i, n, base, len, off, __p, STEP) { \
size_t off = 0; \
if (unlikely(i->count < n)) \
n = i->count; \
if (likely(n)) { \
- if (likely(iter_is_iovec(i))) { \
+ if (likely(iter_is_ubuf(i))) { \
+ void __user *base; \
+ size_t len; \
+ iterate_buf(i, n, base, len, off, \
+ i->ubuf, (I)) \
+ } else if (likely(iter_is_iovec(i))) { \
const struct iovec *iov = i->iov; \
void __user *base; \
size_t len; \
return n;
}
+static inline struct pipe_buffer *pipe_buf(const struct pipe_inode_info *pipe,
+ unsigned int slot)
+{
+ return &pipe->bufs[slot & (pipe->ring_size - 1)];
+}
+
#ifdef PIPE_PARANOIA
static bool sanity(const struct iov_iter *i)
{
struct pipe_inode_info *pipe = i->pipe;
unsigned int p_head = pipe->head;
unsigned int p_tail = pipe->tail;
- unsigned int p_mask = pipe->ring_size - 1;
unsigned int p_occupancy = pipe_occupancy(p_head, p_tail);
unsigned int i_head = i->head;
unsigned int idx;
- if (i->iov_offset) {
+ if (i->last_offset) {
struct pipe_buffer *p;
if (unlikely(p_occupancy == 0))
goto Bad; // pipe must be non-empty
if (unlikely(i_head != p_head - 1))
goto Bad; // must be at the last buffer...
- p = &pipe->bufs[i_head & p_mask];
- if (unlikely(p->offset + p->len != i->iov_offset))
+ p = pipe_buf(pipe, i_head);
+ if (unlikely(p->offset + p->len != abs(i->last_offset)))
goto Bad; // ... at the end of segment
} else {
if (i_head != p_head)
}
return true;
Bad:
- printk(KERN_ERR "idx = %d, offset = %zd\n", i_head, i->iov_offset);
+ printk(KERN_ERR "idx = %d, offset = %d\n", i_head, i->last_offset);
printk(KERN_ERR "head = %d, tail = %d, buffers = %d\n",
p_head, p_tail, pipe->ring_size);
for (idx = 0; idx < pipe->ring_size; idx++)
#define sanity(i) true
#endif
+static struct page *push_anon(struct pipe_inode_info *pipe, unsigned size)
+{
+ struct page *page = alloc_page(GFP_USER);
+ if (page) {
+ struct pipe_buffer *buf = pipe_buf(pipe, pipe->head++);
+ *buf = (struct pipe_buffer) {
+ .ops = &default_pipe_buf_ops,
+ .page = page,
+ .offset = 0,
+ .len = size
+ };
+ }
+ return page;
+}
+
+static void push_page(struct pipe_inode_info *pipe, struct page *page,
+ unsigned int offset, unsigned int size)
+{
+ struct pipe_buffer *buf = pipe_buf(pipe, pipe->head++);
+ *buf = (struct pipe_buffer) {
+ .ops = &page_cache_pipe_buf_ops,
+ .page = page,
+ .offset = offset,
+ .len = size
+ };
+ get_page(page);
+}
+
+static inline int last_offset(const struct pipe_buffer *buf)
+{
+ if (buf->ops == &default_pipe_buf_ops)
+ return buf->len; // buf->offset is 0 for those
+ else
+ return -(buf->offset + buf->len);
+}
+
+static struct page *append_pipe(struct iov_iter *i, size_t size,
+ unsigned int *off)
+{
+ struct pipe_inode_info *pipe = i->pipe;
+ int offset = i->last_offset;
+ struct pipe_buffer *buf;
+ struct page *page;
+
+ if (offset > 0 && offset < PAGE_SIZE) {
+ // some space in the last buffer; add to it
+ buf = pipe_buf(pipe, pipe->head - 1);
+ size = min_t(size_t, size, PAGE_SIZE - offset);
+ buf->len += size;
+ i->last_offset += size;
+ i->count -= size;
+ *off = offset;
+ return buf->page;
+ }
+ // OK, we need a new buffer
+ *off = 0;
+ size = min_t(size_t, size, PAGE_SIZE);
+ if (pipe_full(pipe->head, pipe->tail, pipe->max_usage))
+ return NULL;
+ page = push_anon(pipe, size);
+ if (!page)
+ return NULL;
+ i->head = pipe->head - 1;
+ i->last_offset = size;
+ i->count -= size;
+ return page;
+}
+
static size_t copy_page_to_iter_pipe(struct page *page, size_t offset, size_t bytes,
struct iov_iter *i)
{
struct pipe_inode_info *pipe = i->pipe;
- struct pipe_buffer *buf;
- unsigned int p_tail = pipe->tail;
- unsigned int p_mask = pipe->ring_size - 1;
- unsigned int i_head = i->head;
- size_t off;
+ unsigned int head = pipe->head;
if (unlikely(bytes > i->count))
bytes = i->count;
if (!sanity(i))
return 0;
- off = i->iov_offset;
- buf = &pipe->bufs[i_head & p_mask];
- if (off) {
- if (offset == off && buf->page == page) {
- /* merge with the last one */
+ if (offset && i->last_offset == -offset) { // could we merge it?
+ struct pipe_buffer *buf = pipe_buf(pipe, head - 1);
+ if (buf->page == page) {
buf->len += bytes;
- i->iov_offset += bytes;
- goto out;
+ i->last_offset -= bytes;
+ i->count -= bytes;
+ return bytes;
}
- i_head++;
- buf = &pipe->bufs[i_head & p_mask];
}
- if (pipe_full(i_head, p_tail, pipe->max_usage))
+ if (pipe_full(pipe->head, pipe->tail, pipe->max_usage))
return 0;
- buf->ops = &page_cache_pipe_buf_ops;
- buf->flags = 0;
- get_page(page);
- buf->page = page;
- buf->offset = offset;
- buf->len = bytes;
-
- pipe->head = i_head + 1;
- i->iov_offset = offset + bytes;
- i->head = i_head;
-out:
+ push_page(pipe, page, offset, bytes);
+ i->last_offset = -(offset + bytes);
+ i->head = head;
i->count -= bytes;
return bytes;
}
*/
size_t fault_in_iov_iter_readable(const struct iov_iter *i, size_t size)
{
- if (iter_is_iovec(i)) {
+ if (iter_is_ubuf(i)) {
+ size_t n = min(size, iov_iter_count(i));
+ n -= fault_in_readable(i->ubuf + i->iov_offset, n);
+ return size - n;
+ } else if (iter_is_iovec(i)) {
size_t count = min(size, iov_iter_count(i));
const struct iovec *p;
size_t skip;
*/
size_t fault_in_iov_iter_writeable(const struct iov_iter *i, size_t size)
{
- if (iter_is_iovec(i)) {
+ if (iter_is_ubuf(i)) {
+ size_t n = min(size, iov_iter_count(i));
+ n -= fault_in_safe_writeable(i->ubuf + i->iov_offset, n);
+ return size - n;
+ } else if (iter_is_iovec(i)) {
size_t count = min(size, iov_iter_count(i));
const struct iovec *p;
size_t skip;
*i = (struct iov_iter) {
.iter_type = ITER_IOVEC,
.nofault = false,
+ .user_backed = true,
.data_source = direction,
.iov = iov,
.nr_segs = nr_segs,
}
EXPORT_SYMBOL(iov_iter_init);
-static inline bool allocated(struct pipe_buffer *buf)
-{
- return buf->ops == &default_pipe_buf_ops;
-}
-
-static inline void data_start(const struct iov_iter *i,
- unsigned int *iter_headp, size_t *offp)
-{
- unsigned int p_mask = i->pipe->ring_size - 1;
- unsigned int iter_head = i->head;
- size_t off = i->iov_offset;
-
- if (off && (!allocated(&i->pipe->bufs[iter_head & p_mask]) ||
- off == PAGE_SIZE)) {
- iter_head++;
- off = 0;
- }
- *iter_headp = iter_head;
- *offp = off;
-}
-
-static size_t push_pipe(struct iov_iter *i, size_t size,
- int *iter_headp, size_t *offp)
+// returns the offset in partial buffer (if any)
+static inline unsigned int pipe_npages(const struct iov_iter *i, int *npages)
{
struct pipe_inode_info *pipe = i->pipe;
- unsigned int p_tail = pipe->tail;
- unsigned int p_mask = pipe->ring_size - 1;
- unsigned int iter_head;
- size_t off;
- ssize_t left;
+ int used = pipe->head - pipe->tail;
+ int off = i->last_offset;
- if (unlikely(size > i->count))
- size = i->count;
- if (unlikely(!size))
- return 0;
+ *npages = max((int)pipe->max_usage - used, 0);
- left = size;
- data_start(i, &iter_head, &off);
- *iter_headp = iter_head;
- *offp = off;
- if (off) {
- left -= PAGE_SIZE - off;
- if (left <= 0) {
- pipe->bufs[iter_head & p_mask].len += size;
- return size;
- }
- pipe->bufs[iter_head & p_mask].len = PAGE_SIZE;
- iter_head++;
+ if (off > 0 && off < PAGE_SIZE) { // anon and not full
+ (*npages)++;
+ return off;
}
- while (!pipe_full(iter_head, p_tail, pipe->max_usage)) {
- struct pipe_buffer *buf = &pipe->bufs[iter_head & p_mask];
- struct page *page = alloc_page(GFP_USER);
- if (!page)
- break;
-
- buf->ops = &default_pipe_buf_ops;
- buf->flags = 0;
- buf->page = page;
- buf->offset = 0;
- buf->len = min_t(ssize_t, left, PAGE_SIZE);
- left -= buf->len;
- iter_head++;
- pipe->head = iter_head;
-
- if (left == 0)
- return size;
- }
- return size - left;
+ return 0;
}
static size_t copy_pipe_to_iter(const void *addr, size_t bytes,
struct iov_iter *i)
{
- struct pipe_inode_info *pipe = i->pipe;
- unsigned int p_mask = pipe->ring_size - 1;
- unsigned int i_head;
- size_t n, off;
+ unsigned int off, chunk;
- if (!sanity(i))
+ if (unlikely(bytes > i->count))
+ bytes = i->count;
+ if (unlikely(!bytes))
return 0;
- bytes = n = push_pipe(i, bytes, &i_head, &off);
- if (unlikely(!n))
+ if (!sanity(i))
return 0;
- do {
- size_t chunk = min_t(size_t, n, PAGE_SIZE - off);
- memcpy_to_page(pipe->bufs[i_head & p_mask].page, off, addr, chunk);
- i->head = i_head;
- i->iov_offset = off + chunk;
- n -= chunk;
+
+ for (size_t n = bytes; n; n -= chunk) {
+ struct page *page = append_pipe(i, n, &off);
+ chunk = min_t(size_t, n, PAGE_SIZE - off);
+ if (!page)
+ return bytes - n;
+ memcpy_to_page(page, off, addr, chunk);
addr += chunk;
- off = 0;
- i_head++;
- } while (n);
- i->count -= bytes;
+ }
return bytes;
}
static size_t csum_and_copy_to_pipe_iter(const void *addr, size_t bytes,
struct iov_iter *i, __wsum *sump)
{
- struct pipe_inode_info *pipe = i->pipe;
- unsigned int p_mask = pipe->ring_size - 1;
__wsum sum = *sump;
size_t off = 0;
- unsigned int i_head;
- size_t r;
+ unsigned int chunk, r;
+
+ if (unlikely(bytes > i->count))
+ bytes = i->count;
+ if (unlikely(!bytes))
+ return 0;
if (!sanity(i))
return 0;
- bytes = push_pipe(i, bytes, &i_head, &r);
while (bytes) {
- size_t chunk = min_t(size_t, bytes, PAGE_SIZE - r);
- char *p = kmap_local_page(pipe->bufs[i_head & p_mask].page);
+ struct page *page = append_pipe(i, bytes, &r);
+ char *p;
+
+ if (!page)
+ break;
+ chunk = min_t(size_t, bytes, PAGE_SIZE - r);
+ p = kmap_local_page(page);
sum = csum_and_memcpy(p + r, addr + off, chunk, sum, off);
kunmap_local(p);
- i->head = i_head;
- i->iov_offset = r + chunk;
- bytes -= chunk;
off += chunk;
- r = 0;
- i_head++;
+ bytes -= chunk;
}
*sump = sum;
- i->count -= off;
return off;
}
{
if (unlikely(iov_iter_is_pipe(i)))
return copy_pipe_to_iter(addr, bytes, i);
- if (iter_is_iovec(i))
+ if (user_backed_iter(i))
might_fault();
iterate_and_advance(i, bytes, base, len, off,
copyout(base, addr + off, len),
static size_t copy_mc_pipe_to_iter(const void *addr, size_t bytes,
struct iov_iter *i)
{
- struct pipe_inode_info *pipe = i->pipe;
- unsigned int p_mask = pipe->ring_size - 1;
- unsigned int i_head;
- unsigned int valid = pipe->head;
- size_t n, off, xfer = 0;
+ size_t xfer = 0;
+ unsigned int off, chunk;
+
+ if (unlikely(bytes > i->count))
+ bytes = i->count;
+ if (unlikely(!bytes))
+ return 0;
if (!sanity(i))
return 0;
- n = push_pipe(i, bytes, &i_head, &off);
- while (n) {
- size_t chunk = min_t(size_t, n, PAGE_SIZE - off);
- char *p = kmap_local_page(pipe->bufs[i_head & p_mask].page);
+ while (bytes) {
+ struct page *page = append_pipe(i, bytes, &off);
unsigned long rem;
+ char *p;
+
+ if (!page)
+ break;
+ chunk = min_t(size_t, bytes, PAGE_SIZE - off);
+ p = kmap_local_page(page);
rem = copy_mc_to_kernel(p + off, addr + xfer, chunk);
chunk -= rem;
kunmap_local(p);
- if (chunk) {
- i->head = i_head;
- i->iov_offset = off + chunk;
- xfer += chunk;
- valid = i_head + 1;
- }
+ xfer += chunk;
+ bytes -= chunk;
if (rem) {
- pipe->bufs[i_head & p_mask].len -= rem;
- pipe_discard_from(pipe, valid);
+ iov_iter_revert(i, rem);
break;
}
- n -= chunk;
- off = 0;
- i_head++;
}
- i->count -= xfer;
return xfer;
}
{
if (unlikely(iov_iter_is_pipe(i)))
return copy_mc_pipe_to_iter(addr, bytes, i);
- if (iter_is_iovec(i))
+ if (user_backed_iter(i))
might_fault();
__iterate_and_advance(i, bytes, base, len, off,
copyout_mc(base, addr + off, len),
WARN_ON(1);
return 0;
}
- if (iter_is_iovec(i))
+ if (user_backed_iter(i))
might_fault();
iterate_and_advance(i, bytes, base, len, off,
copyin(addr + off, base, len),
return false;
}
-static size_t __copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
- struct iov_iter *i)
-{
- if (unlikely(iov_iter_is_pipe(i))) {
- return copy_page_to_iter_pipe(page, offset, bytes, i);
- } else {
- void *kaddr = kmap_local_page(page);
- size_t wanted = _copy_to_iter(kaddr + offset, bytes, i);
- kunmap_local(kaddr);
- return wanted;
- }
-}
-
size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
struct iov_iter *i)
{
size_t res = 0;
if (unlikely(!page_copy_sane(page, offset, bytes)))
return 0;
+ if (unlikely(iov_iter_is_pipe(i)))
+ return copy_page_to_iter_pipe(page, offset, bytes, i);
page += offset / PAGE_SIZE; // first subpage
offset %= PAGE_SIZE;
while (1) {
- size_t n = __copy_page_to_iter(page, offset,
- min(bytes, (size_t)PAGE_SIZE - offset), i);
+ void *kaddr = kmap_local_page(page);
+ size_t n = min(bytes, (size_t)PAGE_SIZE - offset);
+ n = _copy_to_iter(kaddr + offset, n, i);
+ kunmap_local(kaddr);
res += n;
bytes -= n;
if (!bytes || !n)
size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
struct iov_iter *i)
{
- if (page_copy_sane(page, offset, bytes)) {
+ size_t res = 0;
+ if (!page_copy_sane(page, offset, bytes))
+ return 0;
+ page += offset / PAGE_SIZE; // first subpage
+ offset %= PAGE_SIZE;
+ while (1) {
void *kaddr = kmap_local_page(page);
- size_t wanted = _copy_from_iter(kaddr + offset, bytes, i);
+ size_t n = min(bytes, (size_t)PAGE_SIZE - offset);
+ n = _copy_from_iter(kaddr + offset, n, i);
kunmap_local(kaddr);
- return wanted;
+ res += n;
+ bytes -= n;
+ if (!bytes || !n)
+ break;
+ offset += n;
+ if (offset == PAGE_SIZE) {
+ page++;
+ offset = 0;
+ }
}
- return 0;
+ return res;
}
EXPORT_SYMBOL(copy_page_from_iter);
static size_t pipe_zero(size_t bytes, struct iov_iter *i)
{
- struct pipe_inode_info *pipe = i->pipe;
- unsigned int p_mask = pipe->ring_size - 1;
- unsigned int i_head;
- size_t n, off;
+ unsigned int chunk, off;
- if (!sanity(i))
+ if (unlikely(bytes > i->count))
+ bytes = i->count;
+ if (unlikely(!bytes))
return 0;
- bytes = n = push_pipe(i, bytes, &i_head, &off);
- if (unlikely(!n))
+ if (!sanity(i))
return 0;
- do {
- size_t chunk = min_t(size_t, n, PAGE_SIZE - off);
- char *p = kmap_local_page(pipe->bufs[i_head & p_mask].page);
+ for (size_t n = bytes; n; n -= chunk) {
+ struct page *page = append_pipe(i, n, &off);
+ char *p;
+
+ if (!page)
+ return bytes - n;
+ chunk = min_t(size_t, n, PAGE_SIZE - off);
+ p = kmap_local_page(page);
memset(p + off, 0, chunk);
kunmap_local(p);
- i->head = i_head;
- i->iov_offset = off + chunk;
- n -= chunk;
- off = 0;
- i_head++;
- } while (n);
- i->count -= bytes;
+ }
return bytes;
}
}
EXPORT_SYMBOL(copy_page_from_iter_atomic);
-static inline void pipe_truncate(struct iov_iter *i)
-{
- struct pipe_inode_info *pipe = i->pipe;
- unsigned int p_tail = pipe->tail;
- unsigned int p_head = pipe->head;
- unsigned int p_mask = pipe->ring_size - 1;
-
- if (!pipe_empty(p_head, p_tail)) {
- struct pipe_buffer *buf;
- unsigned int i_head = i->head;
- size_t off = i->iov_offset;
-
- if (off) {
- buf = &pipe->bufs[i_head & p_mask];
- buf->len = off - buf->offset;
- i_head++;
- }
- while (p_head != i_head) {
- p_head--;
- pipe_buf_release(pipe, &pipe->bufs[p_head & p_mask]);
- }
-
- pipe->head = p_head;
- }
-}
-
static void pipe_advance(struct iov_iter *i, size_t size)
{
struct pipe_inode_info *pipe = i->pipe;
- if (size) {
- struct pipe_buffer *buf;
- unsigned int p_mask = pipe->ring_size - 1;
- unsigned int i_head = i->head;
- size_t off = i->iov_offset, left = size;
+ int off = i->last_offset;
+ if (!off && !size) {
+ pipe_discard_from(pipe, i->start_head); // discard everything
+ return;
+ }
+ i->count -= size;
+ while (1) {
+ struct pipe_buffer *buf = pipe_buf(pipe, i->head);
if (off) /* make it relative to the beginning of buffer */
- left += off - pipe->bufs[i_head & p_mask].offset;
- while (1) {
- buf = &pipe->bufs[i_head & p_mask];
- if (left <= buf->len)
- break;
- left -= buf->len;
- i_head++;
+ size += abs(off) - buf->offset;
+ if (size <= buf->len) {
+ buf->len = size;
+ i->last_offset = last_offset(buf);
+ break;
}
- i->head = i_head;
- i->iov_offset = buf->offset + left;
+ size -= buf->len;
+ i->head++;
+ off = 0;
}
- i->count -= size;
- /* ... and discard everything past that point */
- pipe_truncate(i);
+ pipe_discard_from(pipe, i->head + 1); // discard everything past this one
}
static void iov_iter_bvec_advance(struct iov_iter *i, size_t size)
{
if (unlikely(i->count < size))
size = i->count;
- if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i))) {
+ if (likely(iter_is_ubuf(i)) || unlikely(iov_iter_is_xarray(i))) {
+ i->iov_offset += size;
+ i->count -= size;
+ } else if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i))) {
/* iovec and kvec have identical layouts */
iov_iter_iovec_advance(i, size);
} else if (iov_iter_is_bvec(i)) {
iov_iter_bvec_advance(i, size);
} else if (iov_iter_is_pipe(i)) {
pipe_advance(i, size);
- } else if (unlikely(iov_iter_is_xarray(i))) {
- i->iov_offset += size;
- i->count -= size;
} else if (iov_iter_is_discard(i)) {
i->count -= size;
}
i->count += unroll;
if (unlikely(iov_iter_is_pipe(i))) {
struct pipe_inode_info *pipe = i->pipe;
- unsigned int p_mask = pipe->ring_size - 1;
- unsigned int i_head = i->head;
- size_t off = i->iov_offset;
- while (1) {
- struct pipe_buffer *b = &pipe->bufs[i_head & p_mask];
- size_t n = off - b->offset;
- if (unroll < n) {
- off -= unroll;
- break;
- }
- unroll -= n;
- if (!unroll && i_head == i->start_head) {
- off = 0;
- break;
+ unsigned int head = pipe->head;
+
+ while (head > i->start_head) {
+ struct pipe_buffer *b = pipe_buf(pipe, --head);
+ if (unroll < b->len) {
+ b->len -= unroll;
+ i->last_offset = last_offset(b);
+ i->head = head;
+ return;
}
- i_head--;
- b = &pipe->bufs[i_head & p_mask];
- off = b->offset + b->len;
+ unroll -= b->len;
+ pipe_buf_release(pipe, b);
+ pipe->head--;
}
- i->iov_offset = off;
- i->head = i_head;
- pipe_truncate(i);
+ i->last_offset = 0;
+ i->head = head;
return;
}
if (unlikely(iov_iter_is_discard(i)))
return;
}
unroll -= i->iov_offset;
- if (iov_iter_is_xarray(i)) {
+ if (iov_iter_is_xarray(i) || iter_is_ubuf(i)) {
BUG(); /* We should never go beyond the start of the specified
* range since we might then be straying into pages that
* aren't pinned.
.pipe = pipe,
.head = pipe->head,
.start_head = pipe->head,
- .iov_offset = 0,
+ .last_offset = 0,
.count = count
};
}
bool iov_iter_is_aligned(const struct iov_iter *i, unsigned addr_mask,
unsigned len_mask)
{
+ if (likely(iter_is_ubuf(i))) {
+ if (i->count & len_mask)
+ return false;
+ if ((unsigned long)(i->ubuf + i->iov_offset) & addr_mask)
+ return false;
+ return true;
+ }
+
if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i)))
return iov_iter_aligned_iovec(i, addr_mask, len_mask);
return iov_iter_aligned_bvec(i, addr_mask, len_mask);
if (iov_iter_is_pipe(i)) {
- unsigned int p_mask = i->pipe->ring_size - 1;
size_t size = i->count;
if (size & len_mask)
return false;
- if (size && allocated(&i->pipe->bufs[i->head & p_mask])) {
- if (i->iov_offset & addr_mask)
+ if (size && i->last_offset > 0) {
+ if (i->last_offset & addr_mask)
return false;
}
unsigned long iov_iter_alignment(const struct iov_iter *i)
{
+ if (likely(iter_is_ubuf(i))) {
+ size_t size = i->count;
+ if (size)
+ return ((unsigned long)i->ubuf + i->iov_offset) | size;
+ return 0;
+ }
+
/* iovec and kvec have identical layouts */
if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i)))
return iov_iter_alignment_iovec(i);
return iov_iter_alignment_bvec(i);
if (iov_iter_is_pipe(i)) {
- unsigned int p_mask = i->pipe->ring_size - 1;
size_t size = i->count;
- if (size && i->iov_offset && allocated(&i->pipe->bufs[i->head & p_mask]))
- return size | i->iov_offset;
+ if (size && i->last_offset > 0)
+ return size | i->last_offset;
return size;
}
size_t size = i->count;
unsigned k;
+ if (iter_is_ubuf(i))
+ return 0;
+
if (WARN_ON(!iter_is_iovec(i)))
return ~0U;
}
EXPORT_SYMBOL(iov_iter_gap_alignment);
-static inline ssize_t __pipe_get_pages(struct iov_iter *i,
- size_t maxsize,
- struct page **pages,
- int iter_head,
- size_t *start)
+static int want_pages_array(struct page ***res, size_t size,
+ size_t start, unsigned int maxpages)
{
- struct pipe_inode_info *pipe = i->pipe;
- unsigned int p_mask = pipe->ring_size - 1;
- ssize_t n = push_pipe(i, maxsize, &iter_head, start);
- if (!n)
- return -EFAULT;
+ unsigned int count = DIV_ROUND_UP(size + start, PAGE_SIZE);
- maxsize = n;
- n += *start;
- while (n > 0) {
- get_page(*pages++ = pipe->bufs[iter_head & p_mask].page);
- iter_head++;
- n -= PAGE_SIZE;
+ if (count > maxpages)
+ count = maxpages;
+ WARN_ON(!count); // caller should've prevented that
+ if (!*res) {
+ *res = kvmalloc_array(count, sizeof(struct page *), GFP_KERNEL);
+ if (!*res)
+ return 0;
}
-
- return maxsize;
+ return count;
}
static ssize_t pipe_get_pages(struct iov_iter *i,
- struct page **pages, size_t maxsize, unsigned maxpages,
+ struct page ***pages, size_t maxsize, unsigned maxpages,
size_t *start)
{
- unsigned int iter_head, npages;
- size_t capacity;
+ unsigned int npages, count, off, chunk;
+ struct page **p;
+ size_t left;
if (!sanity(i))
return -EFAULT;
- data_start(i, &iter_head, start);
- /* Amount of free space: some of this one + all after this one */
- npages = pipe_space_for_user(iter_head, i->pipe->tail, i->pipe);
- capacity = min(npages, maxpages) * PAGE_SIZE - *start;
-
- return __pipe_get_pages(i, min(maxsize, capacity), pages, iter_head, start);
+ *start = off = pipe_npages(i, &npages);
+ if (!npages)
+ return -EFAULT;
+ count = want_pages_array(pages, maxsize, off, min(npages, maxpages));
+ if (!count)
+ return -ENOMEM;
+ p = *pages;
+ for (npages = 0, left = maxsize ; npages < count; npages++, left -= chunk) {
+ struct page *page = append_pipe(i, left, &off);
+ if (!page)
+ break;
+ chunk = min_t(size_t, left, PAGE_SIZE - off);
+ get_page(*p++ = page);
+ }
+ if (!npages)
+ return -EFAULT;
+ return maxsize - left;
}
static ssize_t iter_xarray_populate_pages(struct page **pages, struct xarray *xa,
}
static ssize_t iter_xarray_get_pages(struct iov_iter *i,
- struct page **pages, size_t maxsize,
+ struct page ***pages, size_t maxsize,
unsigned maxpages, size_t *_start_offset)
{
- unsigned nr, offset;
- pgoff_t index, count;
- size_t size = maxsize;
+ unsigned nr, offset, count;
+ pgoff_t index;
loff_t pos;
- if (!size || !maxpages)
- return 0;
-
pos = i->xarray_start + i->iov_offset;
index = pos >> PAGE_SHIFT;
offset = pos & ~PAGE_MASK;
*_start_offset = offset;
- count = 1;
- if (size > PAGE_SIZE - offset) {
- size -= PAGE_SIZE - offset;
- count += size >> PAGE_SHIFT;
- size &= ~PAGE_MASK;
- if (size)
- count++;
- }
-
- if (count > maxpages)
- count = maxpages;
-
- nr = iter_xarray_populate_pages(pages, i->xarray, index, count);
+ count = want_pages_array(pages, maxsize, offset, maxpages);
+ if (!count)
+ return -ENOMEM;
+ nr = iter_xarray_populate_pages(*pages, i->xarray, index, count);
if (nr == 0)
return 0;
- return min_t(size_t, nr * PAGE_SIZE - offset, maxsize);
+ maxsize = min_t(size_t, nr * PAGE_SIZE - offset, maxsize);
+ i->iov_offset += maxsize;
+ i->count -= maxsize;
+ return maxsize;
}
-/* must be done on non-empty ITER_IOVEC one */
+/* must be done on non-empty ITER_UBUF or ITER_IOVEC one */
static unsigned long first_iovec_segment(const struct iov_iter *i, size_t *size)
{
size_t skip;
long k;
+ if (iter_is_ubuf(i))
+ return (unsigned long)i->ubuf + i->iov_offset;
+
for (k = 0, skip = i->iov_offset; k < i->nr_segs; k++, skip = 0) {
size_t len = i->iov[k].iov_len - skip;
return page;
}
-ssize_t iov_iter_get_pages(struct iov_iter *i,
- struct page **pages, size_t maxsize, unsigned maxpages,
- size_t *start)
+static ssize_t __iov_iter_get_pages_alloc(struct iov_iter *i,
+ struct page ***pages, size_t maxsize,
+ unsigned int maxpages, size_t *start)
{
- int n, res;
+ unsigned int n;
if (maxsize > i->count)
maxsize = i->count;
if (maxsize > MAX_RW_COUNT)
maxsize = MAX_RW_COUNT;
- if (likely(iter_is_iovec(i))) {
+ if (likely(user_backed_iter(i))) {
unsigned int gup_flags = 0;
unsigned long addr;
+ int res;
if (iov_iter_rw(i) != WRITE)
gup_flags |= FOLL_WRITE;
addr = first_iovec_segment(i, &maxsize);
*start = addr % PAGE_SIZE;
addr &= PAGE_MASK;
- n = DIV_ROUND_UP(maxsize + *start, PAGE_SIZE);
- if (n > maxpages)
- n = maxpages;
- res = get_user_pages_fast(addr, n, gup_flags, pages);
+ n = want_pages_array(pages, maxsize, *start, maxpages);
+ if (!n)
+ return -ENOMEM;
+ res = get_user_pages_fast(addr, n, gup_flags, *pages);
if (unlikely(res <= 0))
return res;
- return min_t(size_t, maxsize, res * PAGE_SIZE - *start);
+ maxsize = min_t(size_t, maxsize, res * PAGE_SIZE - *start);
+ iov_iter_advance(i, maxsize);
+ return maxsize;
}
if (iov_iter_is_bvec(i)) {
+ struct page **p;
struct page *page;
page = first_bvec_segment(i, &maxsize, start);
- n = DIV_ROUND_UP(maxsize + *start, PAGE_SIZE);
- if (n > maxpages)
- n = maxpages;
+ n = want_pages_array(pages, maxsize, *start, maxpages);
+ if (!n)
+ return -ENOMEM;
+ p = *pages;
for (int k = 0; k < n; k++)
- get_page(*pages++ = page++);
- return min_t(size_t, maxsize, n * PAGE_SIZE - *start);
+ get_page(p[k] = page + k);
+ maxsize = min_t(size_t, maxsize, n * PAGE_SIZE - *start);
+ i->count -= maxsize;
+ i->iov_offset += maxsize;
+ if (i->iov_offset == i->bvec->bv_len) {
+ i->iov_offset = 0;
+ i->bvec++;
+ i->nr_segs--;
+ }
+ return maxsize;
}
if (iov_iter_is_pipe(i))
return pipe_get_pages(i, pages, maxsize, maxpages, start);
return iter_xarray_get_pages(i, pages, maxsize, maxpages, start);
return -EFAULT;
}
-EXPORT_SYMBOL(iov_iter_get_pages);
-static struct page **get_pages_array(size_t n)
-{
- return kvmalloc_array(n, sizeof(struct page *), GFP_KERNEL);
-}
-
-static ssize_t pipe_get_pages_alloc(struct iov_iter *i,
- struct page ***pages, size_t maxsize,
+ssize_t iov_iter_get_pages2(struct iov_iter *i,
+ struct page **pages, size_t maxsize, unsigned maxpages,
size_t *start)
{
- struct page **p;
- unsigned int iter_head, npages;
- ssize_t n;
-
- if (!sanity(i))
- return -EFAULT;
-
- data_start(i, &iter_head, start);
- /* Amount of free space: some of this one + all after this one */
- npages = pipe_space_for_user(iter_head, i->pipe->tail, i->pipe);
- n = npages * PAGE_SIZE - *start;
- if (maxsize > n)
- maxsize = n;
- else
- npages = DIV_ROUND_UP(maxsize + *start, PAGE_SIZE);
- p = get_pages_array(npages);
- if (!p)
- return -ENOMEM;
- n = __pipe_get_pages(i, maxsize, p, iter_head, start);
- if (n > 0)
- *pages = p;
- else
- kvfree(p);
- return n;
-}
-
-static ssize_t iter_xarray_get_pages_alloc(struct iov_iter *i,
- struct page ***pages, size_t maxsize,
- size_t *_start_offset)
-{
- struct page **p;
- unsigned nr, offset;
- pgoff_t index, count;
- size_t size = maxsize;
- loff_t pos;
-
- if (!size)
+ if (!maxpages)
return 0;
+ BUG_ON(!pages);
- pos = i->xarray_start + i->iov_offset;
- index = pos >> PAGE_SHIFT;
- offset = pos & ~PAGE_MASK;
- *_start_offset = offset;
-
- count = 1;
- if (size > PAGE_SIZE - offset) {
- size -= PAGE_SIZE - offset;
- count += size >> PAGE_SHIFT;
- size &= ~PAGE_MASK;
- if (size)
- count++;
- }
-
- p = get_pages_array(count);
- if (!p)
- return -ENOMEM;
- *pages = p;
-
- nr = iter_xarray_populate_pages(p, i->xarray, index, count);
- if (nr == 0)
- return 0;
-
- return min_t(size_t, nr * PAGE_SIZE - offset, maxsize);
+ return __iov_iter_get_pages_alloc(i, &pages, maxsize, maxpages, start);
}
+EXPORT_SYMBOL(iov_iter_get_pages2);
-ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
+ssize_t iov_iter_get_pages_alloc2(struct iov_iter *i,
struct page ***pages, size_t maxsize,
size_t *start)
{
- struct page **p;
- int n, res;
+ ssize_t len;
- if (maxsize > i->count)
- maxsize = i->count;
- if (!maxsize)
- return 0;
- if (maxsize > MAX_RW_COUNT)
- maxsize = MAX_RW_COUNT;
-
- if (likely(iter_is_iovec(i))) {
- unsigned int gup_flags = 0;
- unsigned long addr;
-
- if (iov_iter_rw(i) != WRITE)
- gup_flags |= FOLL_WRITE;
- if (i->nofault)
- gup_flags |= FOLL_NOFAULT;
-
- addr = first_iovec_segment(i, &maxsize);
- *start = addr % PAGE_SIZE;
- addr &= PAGE_MASK;
- n = DIV_ROUND_UP(maxsize + *start, PAGE_SIZE);
- p = get_pages_array(n);
- if (!p)
- return -ENOMEM;
- res = get_user_pages_fast(addr, n, gup_flags, p);
- if (unlikely(res <= 0)) {
- kvfree(p);
- *pages = NULL;
- return res;
- }
- *pages = p;
- return min_t(size_t, maxsize, res * PAGE_SIZE - *start);
- }
- if (iov_iter_is_bvec(i)) {
- struct page *page;
+ *pages = NULL;
- page = first_bvec_segment(i, &maxsize, start);
- n = DIV_ROUND_UP(maxsize + *start, PAGE_SIZE);
- *pages = p = get_pages_array(n);
- if (!p)
- return -ENOMEM;
- for (int k = 0; k < n; k++)
- get_page(*p++ = page++);
- return min_t(size_t, maxsize, n * PAGE_SIZE - *start);
+ len = __iov_iter_get_pages_alloc(i, pages, maxsize, ~0U, start);
+ if (len <= 0) {
+ kvfree(*pages);
+ *pages = NULL;
}
- if (iov_iter_is_pipe(i))
- return pipe_get_pages_alloc(i, pages, maxsize, start);
- if (iov_iter_is_xarray(i))
- return iter_xarray_get_pages_alloc(i, pages, maxsize, start);
- return -EFAULT;
+ return len;
}
-EXPORT_SYMBOL(iov_iter_get_pages_alloc);
+EXPORT_SYMBOL(iov_iter_get_pages_alloc2);
size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
struct iov_iter *i)
{
if (unlikely(!i->count))
return 0;
+ if (likely(iter_is_ubuf(i))) {
+ unsigned offs = offset_in_page(i->ubuf + i->iov_offset);
+ int npages = DIV_ROUND_UP(offs + i->count, PAGE_SIZE);
+ return min(npages, maxpages);
+ }
/* iovec and kvec have identical layouts */
if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i)))
return iov_npages(i, maxpages);
if (iov_iter_is_bvec(i))
return bvec_npages(i, maxpages);
if (iov_iter_is_pipe(i)) {
- unsigned int iter_head;
int npages;
- size_t off;
if (!sanity(i))
return 0;
- data_start(i, &iter_head, &off);
- /* some of this one + all after this one */
- npages = pipe_space_for_user(iter_head, i->pipe->tail, i->pipe);
+ pipe_npages(i, &npages);
return min(npages, maxpages);
}
if (iov_iter_is_xarray(i)) {
WARN_ON(1);
return NULL;
}
- if (unlikely(iov_iter_is_discard(new) || iov_iter_is_xarray(new)))
- return NULL;
if (iov_iter_is_bvec(new))
return new->bvec = kmemdup(new->bvec,
new->nr_segs * sizeof(struct bio_vec),
flags);
- else
+ else if (iov_iter_is_kvec(new) || iter_is_iovec(new))
/* iovec and kvec have identical layout */
return new->iov = kmemdup(new->iov,
new->nr_segs * sizeof(struct iovec),
flags);
+ return NULL;
}
EXPORT_SYMBOL(dup_iter);
void iov_iter_restore(struct iov_iter *i, struct iov_iter_state *state)
{
if (WARN_ON_ONCE(!iov_iter_is_bvec(i) && !iter_is_iovec(i)) &&
- !iov_iter_is_kvec(i))
+ !iov_iter_is_kvec(i) && !iter_is_ubuf(i))
return;
i->iov_offset = state->iov_offset;
i->count = state->count;
+ if (iter_is_ubuf(i))
+ return;
/*
* For the *vec iters, nr_segs + iov is constant - if we increment
* the vec, then we also decrement the nr_segs count. Hence we don't
bool
depends on MMU
+config GET_FREE_REGION
+ depends on SPARSEMEM
+ bool
+
config DEVICE_PRIVATE
bool "Unaddressable device memory (GPU memory, ...)"
depends on ZONE_DEVICE
+ select GET_FREE_REGION
help
Allows creation of struct pages to represent unaddressable device
type->total_size = size;
return 0;
}
+
+ /*
+ * The worst case is when new range overlaps all existing regions,
+ * then we'll need type->cnt + 1 empty regions in @type. So if
+ * type->cnt * 2 + 1 is less than type->max, we know
+ * that there is enough empty regions in @type, and we can insert
+ * regions directly.
+ */
+ if (type->cnt * 2 + 1 < type->max)
+ insert = true;
+
repeat:
/*
* The following is executed twice. Once with %false @insert and
ret = copy_page_to_iter(page, offset, nr, to);
put_page(page);
- } else if (iter_is_iovec(to)) {
+ } else if (user_backed_iter(to)) {
/*
* Copy to user tends to be so well optimized, but
* clear_user() not so much, that it is noticeably
struct p9_client *clnt = fid->clnt;
struct p9_req_t *req;
int count = iov_iter_count(to);
- int rsize, non_zc = 0;
+ int rsize, received, non_zc = 0;
char *dataptr;
*err = 0;
}
if (IS_ERR(req)) {
*err = PTR_ERR(req);
+ if (!non_zc)
+ iov_iter_revert(to, count - iov_iter_count(to));
return 0;
}
*err = p9pdu_readf(&req->rc, clnt->proto_version,
- "D", &count, &dataptr);
+ "D", &received, &dataptr);
if (*err) {
+ if (!non_zc)
+ iov_iter_revert(to, count - iov_iter_count(to));
trace_9p_protocol_dump(clnt, &req->rc);
p9_req_put(clnt, req);
return 0;
}
- if (rsize < count) {
- pr_err("bogus RREAD count (%d > %d)\n", count, rsize);
- count = rsize;
+ if (rsize < received) {
+ pr_err("bogus RREAD count (%d > %d)\n", received, rsize);
+ received = rsize;
}
p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
if (non_zc) {
- int n = copy_to_iter(dataptr, count, to);
+ int n = copy_to_iter(dataptr, received, to);
- if (n != count) {
+ if (n != received) {
*err = -EFAULT;
p9_req_put(clnt, req);
return n;
}
} else {
- iov_iter_advance(to, count);
+ iov_iter_revert(to, count - received - iov_iter_count(to));
}
p9_req_put(clnt, req);
- return count;
+ return received;
}
EXPORT_SYMBOL(p9_client_read_once);
while (iov_iter_count(from)) {
int count = iov_iter_count(from);
int rsize = fid->iounit;
+ int written;
if (!rsize || rsize > clnt->msize - P9_IOHDRSZ)
rsize = clnt->msize - P9_IOHDRSZ;
offset, rsize, from);
}
if (IS_ERR(req)) {
+ iov_iter_revert(from, count - iov_iter_count(from));
*err = PTR_ERR(req);
break;
}
- *err = p9pdu_readf(&req->rc, clnt->proto_version, "d", &count);
+ *err = p9pdu_readf(&req->rc, clnt->proto_version, "d", &written);
if (*err) {
+ iov_iter_revert(from, count - iov_iter_count(from));
trace_9p_protocol_dump(clnt, &req->rc);
p9_req_put(clnt, req);
break;
}
- if (rsize < count) {
- pr_err("bogus RWRITE count (%d > %d)\n", count, rsize);
- count = rsize;
+ if (rsize < written) {
+ pr_err("bogus RWRITE count (%d > %d)\n", written, rsize);
+ written = rsize;
}
p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", count);
p9_req_put(clnt, req);
- iov_iter_advance(from, count);
- total += count;
- offset += count;
+ iov_iter_revert(from, count - written - iov_iter_count(from));
+ total += written;
+ offset += written;
}
return total;
}
pdu_write_u(struct p9_fcall *pdu, struct iov_iter *from, size_t size)
{
size_t len = min(pdu->capacity - pdu->size, size);
- struct iov_iter i = *from;
- if (!copy_from_iter_full(&pdu->sdata[pdu->size], len, &i))
+ if (!copy_from_iter_full(&pdu->sdata[pdu->size], len, from))
len = 0;
pdu->size += len;
if (err == -ERESTARTSYS)
return err;
}
- n = iov_iter_get_pages_alloc(data, pages, count, offs);
+ n = iov_iter_get_pages_alloc2(data, pages, count, offs);
if (n < 0)
return n;
*need_drop = 1;
(*pages)[index] = kmap_to_page(p);
p += PAGE_SIZE;
}
+ iov_iter_advance(data, len);
return len;
}
}
if (frag == MAX_SKB_FRAGS)
return -EMSGSIZE;
- copied = iov_iter_get_pages(from, pages, length,
+ copied = iov_iter_get_pages2(from, pages, length,
MAX_SKB_FRAGS - frag, &start);
if (copied < 0)
return -EFAULT;
- iov_iter_advance(from, copied);
length -= copied;
truesize = PAGE_ALIGN(copied + start);
goto out;
}
- copied = iov_iter_get_pages(from, pages, bytes, maxpages,
+ copied = iov_iter_get_pages2(from, pages, bytes, maxpages,
&offset);
if (copied <= 0) {
ret = -EFAULT;
goto out;
}
- iov_iter_advance(from, copied);
bytes -= copied;
msg->sg.size += copied;
size_t start;
ssize_t copied;
- copied = iov_iter_get_pages(from, &pages, PAGE_SIZE,
+ copied = iov_iter_get_pages2(from, &pages, PAGE_SIZE,
1, &start);
if (copied < 0) {
struct mmpin *mmp;
goto err;
}
total_copied += copied;
- iov_iter_advance(from, copied);
length -= copied;
sg_set_page(sg, pages, copied, start);
rm->data.op_nents++;
set_current_state(TASK_RUNNING);
return -EINTR;
}
- trace_svc_alloc_arg_err(pages);
+ trace_svc_alloc_arg_err(pages, ret);
memalloc_retry_wait(GFP_KERNEL);
}
rqstp->rq_page_end = &rqstp->rq_pages[pages];
rc = -EFAULT;
goto out;
}
- copied = iov_iter_get_pages(from, pages,
+ copied = iov_iter_get_pages2(from, pages,
length,
maxpages, &offset);
if (copied <= 0) {
goto out;
}
- iov_iter_advance(from, copied);
-
length -= copied;
size += copied;
while (copied) {
# $(cc-option,<flag>)
# Return y if the compiler supports <flag>, n otherwise
-cc-option = $(success,mkdir .tmp_$$$$; trap "rm -rf .tmp_$$$$" EXIT; $(CC) -Werror $(CLANG_FLAGS) $(1) -c -x c /dev/null -o .tmp_$$$$/tmp.o)
+cc-option = $(success,trap "rm -rf .tmp_$$" EXIT; mkdir .tmp_$$; $(CC) -Werror $(CLANG_FLAGS) $(1) -c -x c /dev/null -o .tmp_$$/tmp.o)
# $(ld-option,<flag>)
# Return y if the linker supports <flag>, n otherwise
quiet_cmd_ar_builtin = AR $@
cmd_ar_builtin = rm -f $@; \
- echo $(patsubst $(obj)/%,%,$(real-prereqs)) | \
- sed -E 's:([^ ]+):$(obj)/\1:g' | \
- xargs $(AR) cDPrST $@
+ $(if $(real-prereqs), printf "$(obj)/%s " $(patsubst $(obj)/%,%,$(real-prereqs)) | xargs) \
+ $(AR) cDPrST $@
$(obj)/built-in.a: $(real-obj-y) FORCE
$(call if_changed,ar_builtin)
# automatically cleaned up.
try-run = $(shell set -e; \
TMP=$(TMPOUT)/tmp; \
- mkdir -p $(TMPOUT); \
trap "rm -rf $(TMPOUT)" EXIT; \
+ mkdir -p $(TMPOUT); \
if ($(1)) >/dev/null 2>&1; \
then echo "$(2)"; \
else echo "$(3)"; \
ifdef CONFIG_CC_IS_CLANG
KBUILD_CFLAGS += -Wno-initializer-overrides
-KBUILD_CFLAGS += -Wno-format
KBUILD_CFLAGS += -Wno-sign-compare
KBUILD_CFLAGS += -Wno-format-zero-length
KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast)
dst := $(MODLIB)/$(INSTALL_MOD_DIR)
endif
+$(foreach x, % :, $(if $(findstring $x, $(dst)), \
+ $(error module installation path cannot contain '$x')))
+
suffix-y :=
suffix-$(CONFIG_MODULE_COMPRESS_GZIP) := .gz
suffix-$(CONFIG_MODULE_COMPRESS_XZ) := .xz
$(MAKE) clean
$(CONFIG_SHELL) $(MKSPEC) >$(objtree)/kernel.spec
$(call cmd,src_tar,$(KERNELPATH),kernel.spec)
- +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz \
+ +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE)-linux -ta $(KERNELPATH).tar.gz \
--define='_smp_mflags %{nil}'
# binrpm-pkg
$(MAKE) -f $(srctree)/Makefile
$(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/binkernel.spec
+rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \
- $(UTS_MACHINE) -bb $(objtree)/binkernel.spec
+ $(UTS_MACHINE)-linux -bb $(objtree)/binkernel.spec
PHONY += deb-pkg
deb-pkg:
+++ /dev/null
-#!/usr/bin/awk -f
-# SPDX-License-Identifier: GPL-2.0
-#
-# Copyright © 2020, Microsoft Corporation. All rights reserved.
-#
-# Author: Mickaël Salaün <mic@linux.microsoft.com>
-#
-# Check that a CONFIG_SYSTEM_BLACKLIST_HASH_LIST file contains a valid array of
-# hash strings. Such string must start with a prefix ("tbs" or "bin"), then a
-# colon (":"), and finally an even number of hexadecimal lowercase characters
-# (up to 128).
-
-BEGIN {
- RS = ","
-}
-{
- if (!match($0, "^[ \t\n\r]*\"([^\"]*)\"[ \t\n\r]*$", part1)) {
- print "Not a string (item " NR "):", $0;
- exit 1;
- }
- if (!match(part1[1], "^(tbs|bin):(.*)$", part2)) {
- print "Unknown prefix (item " NR "):", part1[1];
- exit 1;
- }
- if (!match(part2[2], "^([0-9a-f]+)$", part3)) {
- print "Not a lowercase hexadecimal string (item " NR "):", part2[2];
- exit 1;
- }
- if (length(part3[1]) > 128) {
- print "Hash string too long (item " NR "):", part3[1];
- exit 1;
- }
- if (length(part3[1]) % 2 == 1) {
- print "Not an even number of hexadecimal characters (item " NR "):", part3[1];
- exit 1;
- }
-}
# AArch64, PARISC ports by Kyle McMartin
# sparc port by Martin Habets <errandir_news@mph.eclipse.co.uk>
# ppc64le port by Breno Leitao <leitao@debian.org>
+# riscv port by Wadim Mueller <wafgo01@gmail.com>
#
# Usage:
# objdump -d vmlinux | scripts/checkstack.pl [arch]
} elsif ($arch eq 'sparc' || $arch eq 'sparc64') {
# f0019d10: 9d e3 bf 90 save %sp, -112, %sp
$re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o;
+ } elsif ($arch =~ /^riscv(64)?$/) {
+ #ffffffff8036e868: c2010113 addi sp,sp,-992
+ $re = qr/.*addi.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
} else {
print("wrong or unknown architecture \"$arch\"\n");
exit
# To set GCC_PLUGINS
if arg_contain -print-file-name=plugin "$@"; then
- plugin_dir=$(mktemp -d)
-
- mkdir -p $plugin_dir/include
- touch $plugin_dir/include/plugin-version.h
-
- echo $plugin_dir
+ # Use $0 to find the in-tree dummy directory
+ echo "$(dirname "$(readlink -f "$0")")/dummy-plugin-dir"
exit 0
fi
#
# The format is <file-name>:<CONFIG-option> in each line.
config_leak_ignores="
-arch/alpha/include/uapi/asm/setup.h:CONFIG_ALPHA_LEGACY_START_ADDRESS
arch/arc/include/uapi/asm/page.h:CONFIG_ARC_PAGE_SIZE_16K
arch/arc/include/uapi/asm/page.h:CONFIG_ARC_PAGE_SIZE_4K
arch/arc/include/uapi/asm/swab.h:CONFIG_ARC_HAS_SWAPE
arch/x86/include/uapi/asm/auxvec.h:CONFIG_IA32_EMULATION
arch/x86/include/uapi/asm/auxvec.h:CONFIG_X86_64
arch/x86/include/uapi/asm/mman.h:CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
-include/uapi/asm-generic/fcntl.h:CONFIG_64BIT
include/uapi/linux/atmdev.h:CONFIG_COMPAT
include/uapi/linux/eventpoll.h:CONFIG_PM_SLEEP
include/uapi/linux/hw_breakpoint.h:CONFIG_HAVE_MIXED_BREAKPOINTS_REGS
echo >&2 "*"
echo >&2 "* Could not find Qt5 via ${HOSTPKG_CONFIG}."
echo >&2 "* Please install Qt5 and make sure it's in PKG_CONFIG_PATH"
+echo >&2 "* You need $PKG"
echo >&2 "*"
exit 1
zeros = calloc(1, sym->st_size);
symval = zeros;
} else {
- symval = (void *)info->hdr
- + info->sechdrs[get_secindex(info, sym)].sh_offset
- + sym->st_value;
+ symval = sym_get_data(info, sym);
}
/* First handle the "special" cases */
{
Elf_Shdr *sechdr = &info->sechdrs[secindex];
- if (info->hdr->e_type != ET_REL)
- offset -= sechdr->sh_addr;
-
return (void *)info->hdr + sechdr->sh_offset + offset;
}
-static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
+void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
{
return sym_get_data_by_offset(info, get_secindex(info, sym),
sym->st_value);
sechdr->sh_name);
}
-static const char *sec_name(const struct elf_info *info, int secindex)
+static const char *sec_name(const struct elf_info *info, unsigned int secindex)
{
+ /*
+ * If sym->st_shndx is a special section index, there is no
+ * corresponding section header.
+ * Return "" if the index is out of range of info->sechdrs[] array.
+ */
+ if (secindex >= info->num_sections)
+ return "";
+
return sech_name(info, &info->sechdrs[secindex]);
}
sechdrs = (void *)hdr + hdr->e_shoff;
info->sechdrs = sechdrs;
+ /* modpost only works for relocatable objects */
+ if (hdr->e_type != ET_REL)
+ fatal("%s: not relocatable object.", filename);
+
/* Check if file offset is correct */
if (hdr->e_shoff > info->size) {
fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n",
return false;
}
+/* useful to pass patterns to match() directly */
+#define PATTERNS(...) \
+ ({ \
+ static const char *const patterns[] = {__VA_ARGS__, NULL}; \
+ patterns; \
+ })
+
/* sections that we do not want to do full section mismatch check on */
static const char *const section_white_list[] =
{
".comment*",
".debug*",
- ".cranges", /* sh64 */
".zdebug*", /* Compressed debug sections. */
".GCC.command.line", /* record-gcc-switches */
".mdebug*", /* alpha, score, mips etc. */
/* all init sections */
static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
-/* All init and exit sections (code + data) */
-static const char *const init_exit_sections[] =
- {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
-
/* all text sections */
static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
/* data section */
static const char *const data_sections[] = { DATA_SECTIONS, NULL };
-
-/* symbols in .data that may refer to init/exit sections */
-#define DEFAULT_SYMBOL_WHITE_LIST \
- "*driver", \
- "*_template", /* scsi uses *_template a lot */ \
- "*_timer", /* arm uses ops structures named _timer a lot */ \
- "*_sht", /* scsi also used *_sht to some extent */ \
- "*_ops", \
- "*_probe", \
- "*_probe_one", \
- "*_console"
-
static const char *const head_sections[] = { ".head.text*", NULL };
static const char *const linker_symbols[] =
{ "__init_begin", "_sinittext", "_einittext", NULL };
*
* @mismatch: Type of mismatch.
*
- * @symbol_white_list: Do not match a relocation to a symbol in this list
- * even if it is targeting a section in @bad_to_sec.
- *
* @handler: Specific handler to call when a match is found. If NULL,
* default_mismatch_handler() will be called.
*
const char *bad_tosec[20];
const char *good_tosec[20];
enum mismatch mismatch;
- const char *symbol_white_list[20];
void (*handler)(const char *modname, struct elf_info *elf,
const struct sectioncheck* const mismatch,
Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
.fromsec = { TEXT_SECTIONS, NULL },
.bad_tosec = { ALL_INIT_SECTIONS, NULL },
.mismatch = TEXT_TO_ANY_INIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
{
.fromsec = { DATA_SECTIONS, NULL },
.bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
.mismatch = DATA_TO_ANY_INIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
{
.fromsec = { DATA_SECTIONS, NULL },
.bad_tosec = { INIT_SECTIONS, NULL },
.mismatch = DATA_TO_ANY_INIT,
- .symbol_white_list = {
- "*_template", "*_timer", "*_sht", "*_ops",
- "*_probe", "*_probe_one", "*_console", NULL
- },
},
{
.fromsec = { TEXT_SECTIONS, NULL },
.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
.mismatch = TEXT_TO_ANY_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
{
.fromsec = { DATA_SECTIONS, NULL },
.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
.mismatch = DATA_TO_ANY_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not reference init code/data from meminit code/data */
{
.fromsec = { ALL_XXXINIT_SECTIONS, NULL },
.bad_tosec = { INIT_SECTIONS, NULL },
.mismatch = XXXINIT_TO_SOME_INIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not reference exit code/data from memexit code/data */
{
.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
.bad_tosec = { EXIT_SECTIONS, NULL },
.mismatch = XXXEXIT_TO_SOME_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not use exit code/data from init code */
{
.fromsec = { ALL_INIT_SECTIONS, NULL },
.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
.mismatch = ANY_INIT_TO_ANY_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not use init code/data from exit code */
{
.fromsec = { ALL_EXIT_SECTIONS, NULL },
.bad_tosec = { ALL_INIT_SECTIONS, NULL },
.mismatch = ANY_EXIT_TO_ANY_INIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
{
.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
.bad_tosec = { INIT_SECTIONS, NULL },
.mismatch = ANY_INIT_TO_ANY_EXIT,
- .symbol_white_list = { NULL },
},
/* Do not export init/exit functions or data */
{
.fromsec = { "___ksymtab*", NULL },
.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
.mismatch = EXPORT_TO_INIT_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
{
.fromsec = { "__ex_table", NULL },
* fromsec = .data*
* atsym = __param_ops_*
*
- * Pattern 2:
- * Many drivers utilise a *driver container with references to
- * add, remove, probe functions etc.
- * the pattern is identified by:
- * tosec = init or exit section
- * fromsec = data section
- * atsym = *driver, *_template, *_sht, *_ops, *_probe,
- * *probe_one, *_console, *_timer
- *
* Pattern 3:
* Whitelist all references from .head.text to any init section
*
strstarts(fromsym, "__param_ops_"))
return 0;
- /* Check for pattern 2 */
- if (match(tosec, init_exit_sections) &&
- match(fromsec, data_sections) &&
- match(fromsym, mismatch->symbol_white_list))
+ /* symbols in data sections that may refer to any init/exit sections */
+ if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
+ match(tosec, PATTERNS(ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
+ match(fromsym, PATTERNS("*_template", // scsi uses *_template a lot
+ "*_timer", // arm uses ops structures named _timer a lot
+ "*_sht", // scsi also used *_sht to some extent
+ "*_ops",
+ "*_probe",
+ "*_probe_one",
+ "*_console")))
+ return 0;
+
+ /* symbols in data sections that may refer to meminit/exit sections */
+ if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
+ match(tosec, PATTERNS(ALL_XXXINIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
+ match(fromsym, PATTERNS("*driver")))
return 0;
/* Check for pattern 3 */
return near;
}
-/*
- * Convert a section name to the function/data attribute
- * .init.text => __init
- * .memexitconst => __memconst
- * etc.
- *
- * The memory of returned value has been allocated on a heap. The user of this
- * method should free it after usage.
-*/
-static char *sec2annotation(const char *s)
-{
- if (match(s, init_exit_sections)) {
- char *p = NOFAIL(malloc(20));
- char *r = p;
-
- *p++ = '_';
- *p++ = '_';
- if (*s == '.')
- s++;
- while (*s && *s != '.')
- *p++ = *s++;
- *p = '\0';
- if (*s == '.')
- s++;
- if (strstr(s, "rodata") != NULL)
- strcat(p, "const ");
- else if (strstr(s, "data") != NULL)
- strcat(p, "data ");
- else
- strcat(p, " ");
- return r;
- } else {
- return NOFAIL(strdup(""));
- }
-}
-
static int is_function(Elf_Sym *sym)
{
if (sym)
return -1;
}
-static void print_section_list(const char * const list[20])
-{
- const char *const *s = list;
-
- while (*s) {
- fprintf(stderr, "%s", *s);
- s++;
- if (*s)
- fprintf(stderr, ", ");
- }
- fprintf(stderr, "\n");
-}
-
static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
{
switch (is_func) {
static void report_sec_mismatch(const char *modname,
const struct sectioncheck *mismatch,
const char *fromsec,
- unsigned long long fromaddr,
const char *fromsym,
- int from_is_func,
- const char *tosec, const char *tosym,
- int to_is_func)
+ const char *tosec, const char *tosym)
{
- const char *from, *from_p;
- const char *to, *to_p;
- char *prl_from;
- char *prl_to;
-
sec_mismatch_count++;
- get_pretty_name(from_is_func, &from, &from_p);
- get_pretty_name(to_is_func, &to, &to_p);
-
- warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
- "to the %s %s:%s%s\n",
- modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
- tosym, to_p);
-
switch (mismatch->mismatch) {
case TEXT_TO_ANY_INIT:
- prl_from = sec2annotation(fromsec);
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The function %s%s() references\n"
- "the %s %s%s%s.\n"
- "This is often because %s lacks a %s\n"
- "annotation or the annotation of %s is wrong.\n",
- prl_from, fromsym,
- to, prl_to, tosym, to_p,
- fromsym, prl_to, tosym);
- free(prl_from);
- free(prl_to);
- break;
- case DATA_TO_ANY_INIT: {
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The variable %s references\n"
- "the %s %s%s%s\n"
- "If the reference is valid then annotate the\n"
- "variable with __init* or __refdata (see linux/init.h) "
- "or name the variable:\n",
- fromsym, to, prl_to, tosym, to_p);
- print_section_list(mismatch->symbol_white_list);
- free(prl_to);
- break;
- }
+ case DATA_TO_ANY_INIT:
case TEXT_TO_ANY_EXIT:
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The function %s() references a %s in an exit section.\n"
- "Often the %s %s%s has valid usage outside the exit section\n"
- "and the fix is to remove the %sannotation of %s.\n",
- fromsym, to, to, tosym, to_p, prl_to, tosym);
- free(prl_to);
- break;
- case DATA_TO_ANY_EXIT: {
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The variable %s references\n"
- "the %s %s%s%s\n"
- "If the reference is valid then annotate the\n"
- "variable with __exit* (see linux/init.h) or "
- "name the variable:\n",
- fromsym, to, prl_to, tosym, to_p);
- print_section_list(mismatch->symbol_white_list);
- free(prl_to);
- break;
- }
+ case DATA_TO_ANY_EXIT:
case XXXINIT_TO_SOME_INIT:
case XXXEXIT_TO_SOME_EXIT:
- prl_from = sec2annotation(fromsec);
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The %s %s%s%s references\n"
- "a %s %s%s%s.\n"
- "If %s is only used by %s then\n"
- "annotate %s with a matching annotation.\n",
- from, prl_from, fromsym, from_p,
- to, prl_to, tosym, to_p,
- tosym, fromsym, tosym);
- free(prl_from);
- free(prl_to);
- break;
case ANY_INIT_TO_ANY_EXIT:
- prl_from = sec2annotation(fromsec);
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The %s %s%s%s references\n"
- "a %s %s%s%s.\n"
- "This is often seen when error handling "
- "in the init function\n"
- "uses functionality in the exit path.\n"
- "The fix is often to remove the %sannotation of\n"
- "%s%s so it may be used outside an exit section.\n",
- from, prl_from, fromsym, from_p,
- to, prl_to, tosym, to_p,
- prl_to, tosym, to_p);
- free(prl_from);
- free(prl_to);
- break;
case ANY_EXIT_TO_ANY_INIT:
- prl_from = sec2annotation(fromsec);
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The %s %s%s%s references\n"
- "a %s %s%s%s.\n"
- "This is often seen when error handling "
- "in the exit function\n"
- "uses functionality in the init path.\n"
- "The fix is often to remove the %sannotation of\n"
- "%s%s so it may be used outside an init section.\n",
- from, prl_from, fromsym, from_p,
- to, prl_to, tosym, to_p,
- prl_to, tosym, to_p);
- free(prl_from);
- free(prl_to);
+ warn("%s: section mismatch in reference: %s (section: %s) -> %s (section: %s)\n",
+ modname, fromsym, fromsec, tosym, tosec);
break;
case EXPORT_TO_INIT_EXIT:
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The symbol %s is exported and annotated %s\n"
- "Fix this by removing the %sannotation of %s "
- "or drop the export.\n",
- tosym, prl_to, prl_to, tosym);
- free(prl_to);
+ warn("%s: EXPORT_SYMBOL used for init/exit symbol: %s (section: %s)\n",
+ modname, tosym, tosec);
break;
case EXTABLE_TO_NON_TEXT:
- fatal("There's a special handler for this mismatch type, "
- "we should never get here.");
+ fatal("There's a special handler for this mismatch type, we should never get here.\n");
break;
}
- fprintf(stderr, "\n");
}
static void default_mismatch_handler(const char *modname, struct elf_info *elf,
from = find_elf_symbol2(elf, r->r_offset, fromsec);
fromsym = sym_name(elf, from);
- if (strstarts(fromsym, "reference___initcall"))
- return;
-
tosec = sec_name(elf, get_secindex(elf, sym));
to = find_elf_symbol(elf, r->r_addend, sym);
tosym = sym_name(elf, to);
if (secref_whitelist(mismatch,
fromsec, fromsym, tosec, tosym)) {
report_sec_mismatch(modname, mismatch,
- fromsec, r->r_offset, fromsym,
- is_function(from), tosec, tosym,
- is_function(to));
+ fromsec, fromsym, tosec, tosym);
}
}
break;
case R_386_PC32:
r->r_addend = TO_NATIVE(*location) + 4;
- /* For CONFIG_RELOCATABLE=y */
- if (elf->hdr->e_type == ET_EXEC)
- r->r_addend += r->r_offset;
break;
}
return 0;
Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
Elf_Rela *stop = (void *)start + sechdr->sh_size;
- fromsec = sech_name(elf, sechdr);
- fromsec += strlen(".rela");
+ fromsec = sec_name(elf, sechdr->sh_info);
/* if from section (name) is know good then skip it */
if (match(fromsec, section_white_list))
return;
Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
Elf_Rel *stop = (void *)start + sechdr->sh_size;
- fromsec = sech_name(elf, sechdr);
- fromsec += strlen(".rel");
+ fromsec = sec_name(elf, sechdr->sh_info);
/* if from section (name) is know good then skip it */
if (match(fromsec, section_white_list))
return;
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Addr Elf32_Addr
-#define Elf_Sword Elf64_Sword
#define Elf_Section Elf32_Half
#define ELF_ST_BIND ELF32_ST_BIND
#define ELF_ST_TYPE ELF32_ST_TYPE
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Addr Elf64_Addr
-#define Elf_Sword Elf64_Sxword
#define Elf_Section Elf64_Half
#define ELF_ST_BIND ELF64_ST_BIND
#define ELF_ST_TYPE ELF64_ST_TYPE
return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;
}
-/*
- * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
- * the way to -256..-1, to avoid conflicting with real section
- * indices.
- */
-#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1))
-
/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */
static inline unsigned int get_secindex(const struct elf_info *info,
const Elf_Sym *sym)
{
- if (is_shndx_special(sym->st_shndx))
- return SPECIAL(sym->st_shndx);
- if (sym->st_shndx != SHN_XINDEX)
- return sym->st_shndx;
- return info->symtab_shndx_start[sym - info->symtab_start];
+ unsigned int index = sym->st_shndx;
+
+ /*
+ * Elf{32,64}_Sym::st_shndx is 2 byte. Big section numbers are available
+ * in the .symtab_shndx section.
+ */
+ if (index == SHN_XINDEX)
+ return info->symtab_shndx_start[sym - info->symtab_start];
+
+ /*
+ * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
+ * the way to UINT_MAX-255..UINT_MAX, to avoid conflicting with real
+ * section indices.
+ */
+ if (index >= SHN_LORESERVE && index <= SHN_HIRESERVE)
+ return index - SHN_HIRESERVE - 1;
+
+ return index;
}
/* file2alias.c */
/* from modpost.c */
char *read_text_file(const char *filename);
char *get_line(char **stringp);
+void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym);
enum loglevel {
LOG_WARN,
.ctors 0 : ALIGN(8) { *(SORT(.ctors.*)) *(.ctors) }
.init_array 0 : ALIGN(8) { *(SORT(.init_array.*)) *(.init_array) }
+ .altinstructions 0 : ALIGN(8) { KEEP(*(.altinstructions)) }
+ __bug_table 0 : ALIGN(8) { KEEP(*(__bug_table)) }
__jump_table 0 : ALIGN(8) { KEEP(*(__jump_table)) }
__patchable_function_entries : { *(__patchable_function_entries) }
URL: https://www.kernel.org
$S Source: kernel-$__KERNELRELEASE.tar.gz
Provides: $PROVIDES
+ # $UTS_MACHINE as a fallback of _arch in case
+ # /usr/lib/rpm/platform/*/macros was not included.
+ %define _arch %{?_arch:$UTS_MACHINE}
%define __spec_install_post /usr/lib/rpm/brp-compress || :
%define debug_package %{nil}
select SECURITY_PATH
select SECURITYFS
select SECURITY_NETWORK
- select ZLIB_INFLATE
- select ZLIB_DEFLATE
default n
help
This enables the AppArmor security module.
If you are unsure how to answer this question, answer N.
-config SECURITY_APPARMOR_HASH
- bool "Enable introspection of sha1 hashes for loaded profiles"
- depends on SECURITY_APPARMOR
- select CRYPTO
- select CRYPTO_SHA1
- default y
- help
- This option selects whether introspection of loaded policy
- is available to userspace via the apparmor filesystem.
-
-config SECURITY_APPARMOR_HASH_DEFAULT
- bool "Enable policy hash introspection by default"
- depends on SECURITY_APPARMOR_HASH
- default y
- help
- This option selects whether sha1 hashing of loaded policy
- is enabled by default. The generation of sha1 hashes for
- loaded policy provide system administrators a quick way
- to verify that policy in the kernel matches what is expected,
- however it can slow down policy load on some devices. In
- these cases policy hashing can be disabled by default and
- enabled only if needed.
-
config SECURITY_APPARMOR_DEBUG
bool "Build AppArmor with debug code"
depends on SECURITY_APPARMOR
When enabled, various debug messages will be logged to
the kernel message buffer.
+config SECURITY_APPARMOR_INTROSPECT_POLICY
+ bool "Allow loaded policy to be introspected"
+ depends on SECURITY_APPARMOR
+ default y
+ help
+ This option selects whether introspection of loaded policy
+ is available to userspace via the apparmor filesystem. This
+ adds to kernel memory usage. It is required for introspection
+ of loaded policy, and check point and restore support. It
+ can be disabled for embedded systems where reducing memory and
+ cpu is paramount.
+
+config SECURITY_APPARMOR_HASH
+ bool "Enable introspection of sha1 hashes for loaded profiles"
+ depends on SECURITY_APPARMOR_INTROSPECT_POLICY
+ select CRYPTO
+ select CRYPTO_SHA1
+ default y
+ help
+ This option selects whether introspection of loaded policy
+ hashes is available to userspace via the apparmor
+ filesystem. This option provides a light weight means of
+ checking loaded policy. This option adds to policy load
+ time and can be disabled for small embedded systems.
+
+config SECURITY_APPARMOR_HASH_DEFAULT
+ bool "Enable policy hash introspection by default"
+ depends on SECURITY_APPARMOR_HASH
+ default y
+ help
+ This option selects whether sha1 hashing of loaded policy
+ is enabled by default. The generation of sha1 hashes for
+ loaded policy provide system administrators a quick way
+ to verify that policy in the kernel matches what is expected,
+ however it can slow down policy load on some devices. In
+ these cases policy hashing can be disabled by default and
+ enabled only if needed.
+
+config SECURITY_APPARMOR_EXPORT_BINARY
+ bool "Allow exporting the raw binary policy"
+ depends on SECURITY_APPARMOR_INTROSPECT_POLICY
+ select ZLIB_INFLATE
+ select ZLIB_DEFLATE
+ default y
+ help
+ This option allows reading back binary policy as it was loaded.
+ It increases the amount of kernel memory needed by policy and
+ also increases policy load time. This option is required for
+ checkpoint and restore support, and debugging of loaded policy.
+
+config SECURITY_APPARMOR_PARANOID_LOAD
+ bool "Perform full verification of loaded policy"
+ depends on SECURITY_APPARMOR
+ default y
+ help
+ This options allows controlling whether apparmor does a full
+ verification of loaded policy. This should not be disabled
+ except for embedded systems where the image is read only,
+ includes policy, and has some form of integrity check.
+ Disabling the check will speed up policy loads.
+
config SECURITY_APPARMOR_KUNIT_TEST
bool "Build KUnit tests for policy_unpack.c" if !KUNIT_ALL_TESTS
depends on KUNIT=y && SECURITY_APPARMOR
#include "include/policy_ns.h"
#include "include/resource.h"
#include "include/policy_unpack.h"
+#include "include/task.h"
/*
* The apparmor filesystem interface used for policy load and introspection
struct aa_loaddata *loaddata;
};
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
#define RAWDATA_F_DATA_BUF(p) (char *)(p + 1)
static void rawdata_f_data_free(struct rawdata_f_data *private)
return ret;
}
+#endif
/**
- * aa_mangle_name - mangle a profile name to std profile layout form
+ * mangle_name - mangle a profile name to std profile layout form
* @name: profile name to mangle (NOT NULL)
* @target: buffer to store mangled name, same length as @name (MAYBE NULL)
*
data->size = copy_size;
if (copy_from_user(data->data, userbuf, copy_size)) {
- kvfree(data);
+ aa_put_loaddata(data);
return ERR_PTR(-EFAULT);
}
/* policy/raw_data/ * file ops */
-
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
#define SEQ_RAWDATA_FOPS(NAME) \
static int seq_rawdata_ ##NAME ##_open(struct inode *inode, struct file *file)\
{ \
static int deflate_decompress(char *src, size_t slen, char *dst, size_t dlen)
{
- int error;
- struct z_stream_s strm;
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
+ if (aa_g_rawdata_compression_level != 0) {
+ int error = 0;
+ struct z_stream_s strm;
- if (aa_g_rawdata_compression_level == 0) {
- if (dlen < slen)
- return -EINVAL;
- memcpy(dst, src, slen);
- return 0;
- }
+ memset(&strm, 0, sizeof(strm));
- memset(&strm, 0, sizeof(strm));
+ strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
+ if (!strm.workspace)
+ return -ENOMEM;
- strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
- if (!strm.workspace)
- return -ENOMEM;
-
- strm.next_in = src;
- strm.avail_in = slen;
+ strm.next_in = src;
+ strm.avail_in = slen;
- error = zlib_inflateInit(&strm);
- if (error != Z_OK) {
- error = -ENOMEM;
- goto fail_inflate_init;
- }
+ error = zlib_inflateInit(&strm);
+ if (error != Z_OK) {
+ error = -ENOMEM;
+ goto fail_inflate_init;
+ }
- strm.next_out = dst;
- strm.avail_out = dlen;
+ strm.next_out = dst;
+ strm.avail_out = dlen;
- error = zlib_inflate(&strm, Z_FINISH);
- if (error != Z_STREAM_END)
- error = -EINVAL;
- else
- error = 0;
+ error = zlib_inflate(&strm, Z_FINISH);
+ if (error != Z_STREAM_END)
+ error = -EINVAL;
+ else
+ error = 0;
- zlib_inflateEnd(&strm);
+ zlib_inflateEnd(&strm);
fail_inflate_init:
- kvfree(strm.workspace);
- return error;
+ kvfree(strm.workspace);
+
+ return error;
+ }
+#endif
+
+ if (dlen < slen)
+ return -EINVAL;
+ memcpy(dst, src, slen);
+ return 0;
}
static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size,
return PTR_ERR(dent);
}
+#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */
+
/** fns to setup dynamic per profile/namespace files **/
-/**
+/*
*
* Requires: @profile->ns->lock held
*/
}
}
-/**
+/*
*
* Requires: @old->ns->lock held
*/
return dent;
}
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
static int profile_depth(struct aa_profile *profile)
{
int depth = 0;
static const struct inode_operations rawdata_link_data_iops = {
.get_link = rawdata_get_link_data,
};
-
+#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */
/*
* Requires: @profile->ns->lock held
profile->dents[AAFS_PROF_HASH] = dent;
}
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
if (profile->rawdata) {
- dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir,
- profile->label.proxy, NULL, NULL,
- &rawdata_link_sha1_iops);
- if (IS_ERR(dent))
- goto fail;
- aa_get_proxy(profile->label.proxy);
- profile->dents[AAFS_PROF_RAW_HASH] = dent;
-
+ if (aa_g_hash_policy) {
+ dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir,
+ profile->label.proxy, NULL, NULL,
+ &rawdata_link_sha1_iops);
+ if (IS_ERR(dent))
+ goto fail;
+ aa_get_proxy(profile->label.proxy);
+ profile->dents[AAFS_PROF_RAW_HASH] = dent;
+ }
dent = aafs_create("raw_abi", S_IFLNK | 0444, dir,
profile->label.proxy, NULL, NULL,
&rawdata_link_abi_iops);
aa_get_proxy(profile->label.proxy);
profile->dents[AAFS_PROF_RAW_DATA] = dent;
}
+#endif /*CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */
list_for_each_entry(child, &profile->base.profiles, base.list) {
error = __aafs_profile_mkdir(child, prof_child_dir(profile));
__aa_fs_remove_rawdata(ent);
}
-/**
+/*
*
* Requires: @ns->lock held
*/
AA_SFS_FILE_BOOLEAN("v6", 1),
AA_SFS_FILE_BOOLEAN("v7", 1),
AA_SFS_FILE_BOOLEAN("v8", 1),
+ AA_SFS_FILE_BOOLEAN("v9", 1),
{ }
};
}
if (AUDIT_MODE(profile) == AUDIT_QUIET ||
(type == AUDIT_APPARMOR_DENIED &&
- AUDIT_MODE(profile) == AUDIT_QUIET))
+ AUDIT_MODE(profile) == AUDIT_QUIET_DENIED))
return aad(sa)->error;
if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
* @profile: profile to find perms for
* @label: label to check access permissions for
* @stack: whether this is a stacking request
- * @start: state to start match in
+ * @state: state to start match in
* @subns: whether to do permission checks on components in a subns
* @request: permissions to request
* @perms: perms struct to set
* xattrs, or a longer match
*/
candidate = profile;
- candidate_len = profile->xmatch_len;
+ candidate_len = max(count, profile->xmatch_len);
candidate_xattrs = ret;
conflict = false;
}
/**
* aa_change_profile - perform a one-way profile transition
* @fqname: name of profile may include namespace (NOT NULL)
- * @onexec: whether this transition is to take place immediately or at exec
* @flags: flags affecting change behavior
*
* Change to new profile @name. Unlike with hats, there is no way
extern bool aa_g_audit_header;
extern bool aa_g_debug;
extern bool aa_g_hash_policy;
+extern bool aa_g_export_binary;
extern int aa_g_rawdata_compression_level;
extern bool aa_g_lock_policy;
extern bool aa_g_logsyscall;
struct dentry *dent);
struct aa_loaddata;
+
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata);
int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata);
+#else
+static inline void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata)
+{
+ /* empty stub */
+}
+
+static inline int __aa_fs_create_rawdata(struct aa_ns *ns,
+ struct aa_loaddata *rawdata)
+{
+ return 0;
+}
+#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */
#endif /* __AA_APPARMORFS_H */
*/
#define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \
((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
+#define dfa_user_xbits(dfa, state) (((ACCEPT_TABLE(dfa)[state]) >> 7) & 0x7f)
#define dfa_user_audit(dfa, state) ((ACCEPT_TABLE2(dfa)[state]) & 0x7f)
#define dfa_user_quiet(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 7) & 0x7f)
#define dfa_user_xindex(dfa, state) \
#define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \
0x7f) | \
((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
+#define dfa_other_xbits(dfa, state) \
+ ((((ACCEPT_TABLE(dfa)[state]) >> 7) >> 14) & 0x7f)
#define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f)
#define dfa_other_quiet(dfa, state) \
((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f)
#include <linux/sched.h>
-struct aa_profile;
-
-#define AA_PTRACE_TRACE MAY_WRITE
-#define AA_PTRACE_READ MAY_READ
-#define AA_MAY_BE_TRACED AA_MAY_APPEND
-#define AA_MAY_BE_READ AA_MAY_CREATE
-#define PTRACE_PERM_SHIFT 2
-
-#define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \
- AA_MAY_BE_READ | AA_MAY_BE_TRACED)
-#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE)
-
-#define AA_SFS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \
- "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \
- "xcpu xfsz vtalrm prof winch io pwr sys emt lost"
-
-int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
- u32 request);
int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig);
#endif /* __AA_IPC_H */
FLAG_STALE = 0x800, /* replaced/removed */
FLAG_RENAMED = 0x1000, /* label has renaming in it */
FLAG_REVOKED = 0x2000, /* label has revocation in it */
+ FLAG_DEBUG1 = 0x4000,
+ FLAG_DEBUG2 = 0x8000,
/* These flags must correspond with PATH_flags */
/* TODO: add new path flags */
*/
#define DEBUG_ON (aa_g_debug)
+/*
+ * split individual debug cases out in preparation for finer grained
+ * debug controls in the future.
+ */
+#define AA_DEBUG_LABEL DEBUG_ON
#define dbg_printk(__fmt, __args...) pr_debug(__fmt, ##__args)
#define AA_DEBUG(fmt, args...) \
do { \
PATH_CHROOT_REL = 0x8, /* do path lookup relative to chroot */
PATH_CHROOT_NSCONNECT = 0x10, /* connect paths that are at ns root */
- PATH_DELEGATE_DELETED = 0x08000, /* delegate deleted files */
- PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */
+ PATH_DELEGATE_DELETED = 0x10000, /* delegate deleted files */
+ PATH_MEDIATE_DELETED = 0x20000, /* mediate deleted paths */
};
int aa_path_name(const struct path *path, int flags, char *buffer,
#define PROFILE_IS_HAT(_profile) ((_profile)->label.flags & FLAG_HAT)
+#define CHECK_DEBUG1(_profile) ((_profile)->label.flags & FLAG_DEBUG1)
+
+#define CHECK_DEBUG2(_profile) ((_profile)->label.flags & FLAG_DEBUG2)
+
#define profile_is_stale(_profile) (label_is_stale(&(_profile)->label))
#define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2)
const char *attach;
struct aa_dfa *xmatch;
- int xmatch_len;
+ unsigned int xmatch_len;
enum audit_mode audit;
long mode;
u32 path_flags;
struct dentry *dents[AAFS_NS_SIZEOF];
};
+extern struct aa_label *kernel_t;
extern struct aa_ns *root_ns;
extern const char *aa_hidden_ns_name;
struct aa_load_ent *aa_load_ent_alloc(void);
#define PACKED_FLAG_HAT 1
+#define PACKED_FLAG_DEBUG1 2
+#define PACKED_FLAG_DEBUG2 4
#define PACKED_MODE_ENFORCE 0
#define PACKED_MODE_COMPLAIN 1
/* secid value that matches any other secid */
#define AA_SECID_WILDCARD 1
+/* sysctl to enable displaying mode when converting secid to secctx */
+extern int apparmor_display_secid_mode;
+
struct aa_label *aa_secid_to_label(u32 secid);
int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void aa_free_secid(u32 secid);
void aa_secid_update(u32 secid, struct aa_label *label);
-void aa_secids_init(void);
-
#endif /* __AA_SECID_H */
ctx->token = 0;
}
+#define AA_PTRACE_TRACE MAY_WRITE
+#define AA_PTRACE_READ MAY_READ
+#define AA_MAY_BE_TRACED AA_MAY_APPEND
+#define AA_MAY_BE_READ AA_MAY_CREATE
+#define PTRACE_PERM_SHIFT 2
+
+#define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \
+ AA_MAY_BE_READ | AA_MAY_BE_TRACED)
+#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE)
+
+#define AA_SFS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \
+ "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \
+ "xcpu xfsz vtalrm prof winch io pwr sys emt lost"
+
+int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
+ u32 request);
+
+
#endif /* __AA_TASK_H */
*/
#include <linux/gfp.h>
-#include <linux/ptrace.h>
#include "include/audit.h"
#include "include/capability.h"
#include "include/ipc.h"
#include "include/sig_names.h"
-/**
- * audit_ptrace_mask - convert mask to permission string
- * @mask: permission mask to convert
- *
- * Returns: pointer to static string
- */
-static const char *audit_ptrace_mask(u32 mask)
-{
- switch (mask) {
- case MAY_READ:
- return "read";
- case MAY_WRITE:
- return "trace";
- case AA_MAY_BE_READ:
- return "readby";
- case AA_MAY_BE_TRACED:
- return "tracedby";
- }
- return "";
-}
-
-/* call back to audit ptrace fields */
-static void audit_ptrace_cb(struct audit_buffer *ab, void *va)
-{
- struct common_audit_data *sa = va;
-
- if (aad(sa)->request & AA_PTRACE_PERM_MASK) {
- audit_log_format(ab, " requested_mask=\"%s\"",
- audit_ptrace_mask(aad(sa)->request));
-
- if (aad(sa)->denied & AA_PTRACE_PERM_MASK) {
- audit_log_format(ab, " denied_mask=\"%s\"",
- audit_ptrace_mask(aad(sa)->denied));
- }
- }
- audit_log_format(ab, " peer=");
- aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
- FLAGS_NONE, GFP_ATOMIC);
-}
-
-/* assumes check for PROFILE_MEDIATES is already done */
-/* TODO: conditionals */
-static int profile_ptrace_perm(struct aa_profile *profile,
- struct aa_label *peer, u32 request,
- struct common_audit_data *sa)
-{
- struct aa_perms perms = { };
-
- aad(sa)->peer = peer;
- aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request,
- &perms);
- aa_apply_modes_to_perms(profile, &perms);
- return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb);
-}
-
-static int profile_tracee_perm(struct aa_profile *tracee,
- struct aa_label *tracer, u32 request,
- struct common_audit_data *sa)
-{
- if (profile_unconfined(tracee) || unconfined(tracer) ||
- !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE))
- return 0;
-
- return profile_ptrace_perm(tracee, tracer, request, sa);
-}
-
-static int profile_tracer_perm(struct aa_profile *tracer,
- struct aa_label *tracee, u32 request,
- struct common_audit_data *sa)
-{
- if (profile_unconfined(tracer))
- return 0;
-
- if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE))
- return profile_ptrace_perm(tracer, tracee, request, sa);
-
- /* profile uses the old style capability check for ptrace */
- if (&tracer->label == tracee)
- return 0;
-
- aad(sa)->label = &tracer->label;
- aad(sa)->peer = tracee;
- aad(sa)->request = 0;
- aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE,
- CAP_OPT_NONE);
-
- return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb);
-}
-
-/**
- * aa_may_ptrace - test if tracer task can trace the tracee
- * @tracer: label of the task doing the tracing (NOT NULL)
- * @tracee: task label to be traced
- * @request: permission request
- *
- * Returns: %0 else error code if permission denied or error
- */
-int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
- u32 request)
-{
- struct aa_profile *profile;
- u32 xrequest = request << PTRACE_PERM_SHIFT;
- DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE);
-
- return xcheck_labels(tracer, tracee, profile,
- profile_tracer_perm(profile, tracee, request, &sa),
- profile_tracee_perm(profile, tracer, xrequest, &sa));
-}
-
static inline int map_signal_num(int sig)
{
return false;
}
-static bool vec_unconfined(struct aa_profile **vec, int n)
+static long union_vec_flags(struct aa_profile **vec, int n, long mask)
{
+ long u = 0;
int i;
AA_BUG(!vec);
for (i = 0; i < n; i++) {
- if (!profile_unconfined(vec[i]))
- return false;
+ u |= vec[i]->label.flags & mask;
}
- return true;
+ return u;
}
static int sort_cmp(const void *a, const void *b)
}
/**
- * aa_label_next_not_in_set - return the next profile of @sub not in @set
+ * __aa_label_next_not_in_set - return the next profile of @sub not in @set
* @I: label iterator
* @set: label to test against
* @sub: label to if is subset of @set
else if (k == b->size)
return aa_get_label(b);
}
- if (vec_unconfined(new->vec, new->size))
- new->flags |= FLAG_UNCONFINED;
+ new->flags |= union_vec_flags(new->vec, new->size, FLAG_UNCONFINED |
+ FLAG_DEBUG1 | FLAG_DEBUG2);
ls = labels_set(new);
write_lock_irqsave(&ls->lock, flags);
label = __label_insert(labels_set(new), new, false);
AA_BUG(!str && size != 0);
AA_BUG(!label);
- if (flags & FLAG_ABS_ROOT) {
+ if (AA_DEBUG_LABEL && (flags & FLAG_ABS_ROOT)) {
ns = root_ns;
- len = snprintf(str, size, "=");
+ len = snprintf(str, size, "_");
update_for_len(total, len, size, str);
} else if (!ns) {
ns = labels_ns(label);
if (!use_label_hname(ns, label, flags) ||
display_mode(ns, label, flags)) {
len = aa_label_asxprint(&name, ns, label, flags, gfp);
- if (len == -1) {
+ if (len < 0) {
AA_DEBUG("label print error");
return;
}
int len;
len = aa_label_asxprint(&str, ns, label, flags, gfp);
- if (len == -1) {
+ if (len < 0) {
AA_DEBUG("label print error");
return;
}
int len;
len = aa_label_asxprint(&str, ns, label, flags, gfp);
- if (len == -1) {
+ if (len < 0) {
AA_DEBUG("label print error");
return;
}
AA_BUG(!str);
str = skipn_spaces(str, n);
- if (str == NULL || (*str == '=' && base != &root_ns->unconfined->label))
+ if (str == NULL || (AA_DEBUG_LABEL && *str == '_' &&
+ base != &root_ns->unconfined->label))
return ERR_PTR(-EINVAL);
len = label_count_strn_entries(str, end - str);
}
/**
- * __aa_labelset_udate_subtree - update all labels with a stale component
+ * __aa_labelset_update_subtree - update all labels with a stale component
* @ns: ns to start update at (NOT NULL)
*
* Requires: @ns lock be held
{
struct counted_str *str;
- str = kmalloc(sizeof(struct counted_str) + size, gfp);
+ str = kmalloc(struct_size(str, name, size), gfp);
if (!str)
return NULL;
((x & 0x60) << 19); /* SETOPT/GETOPT */
}
+static u32 map_xbits(u32 x)
+{
+ return ((x & 0x1) << 7) |
+ ((x & 0x7e) << 9);
+}
+
void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
struct aa_perms *perms)
{
+ /* This mapping is convulated due to history.
+ * v1-v4: only file perms
+ * v5: added policydb which dropped in perm user conditional to
+ * gain new perm bits, but had to map around the xbits because
+ * the userspace compiler was still munging them.
+ * v9: adds using the xbits in policydb because the compiler now
+ * supports treating policydb permission bits different.
+ * Unfortunately there is not way to force auditing on the
+ * perms represented by the xbits
+ */
*perms = (struct aa_perms) {
- .allow = dfa_user_allow(dfa, state),
+ .allow = dfa_user_allow(dfa, state) |
+ map_xbits(dfa_user_xbits(dfa, state)),
.audit = dfa_user_audit(dfa, state),
- .quiet = dfa_user_quiet(dfa, state),
+ .quiet = dfa_user_quiet(dfa, state) |
+ map_xbits(dfa_other_xbits(dfa, state)),
};
- /* for v5 perm mapping in the policydb, the other set is used
+ /* for v5-v9 perm mapping in the policydb, the other set is used
* to extend the general perm set
*/
perms->allow |= map_other(dfa_other_allow(dfa, state));
perms->audit |= map_other(dfa_other_audit(dfa, state));
perms->quiet |= map_other(dfa_other_quiet(dfa, state));
-// perms->xindex = dfa_user_xindex(dfa, state);
}
/**
}
/**
- * apparmor_clone_security - clone the sk_security field
+ * apparmor_sk_clone_security - clone the sk_security field
*/
static void apparmor_sk_clone_security(const struct sock *sk,
struct sock *newsk)
struct aa_label *label;
if (kern) {
- struct aa_ns *ns = aa_get_current_ns();
-
- label = aa_get_label(ns_unconfined(ns));
- aa_put_ns(ns);
+ label = aa_get_label(kernel_t);
} else
label = aa_get_current_label();
}
/**
- * apparmor_socket_list - check perms before allowing listen
+ * apparmor_socket_listen - check perms before allowing listen
*/
static int apparmor_socket_listen(struct socket *sock, int backlog)
{
}
/**
- * apparmor_getsockopt - check perms before getting socket options
+ * apparmor_socket_getsockopt - check perms before getting socket options
*/
static int apparmor_socket_getsockopt(struct socket *sock, int level,
int optname)
}
/**
- * apparmor_setsockopt - check perms before setting socket options
+ * apparmor_socket_setsockopt - check perms before setting socket options
*/
static int apparmor_socket_setsockopt(struct socket *sock, int level,
int optname)
#ifdef CONFIG_NETWORK_SECMARK
/**
- * apparmor_socket_sock_recv_skb - check perms before associating skb to sk
+ * apparmor_socket_sock_rcv_skb - check perms before associating skb to sk
*
* Note: can not sleep may be called with locks held
*
module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR);
#endif
+/* whether policy exactly as loaded is retained for debug and checkpointing */
+bool aa_g_export_binary = IS_ENABLED(CONFIG_SECURITY_APPARMOR_EXPORT_BINARY);
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
+module_param_named(export_binary, aa_g_export_binary, aabool, 0600);
+#endif
+
/* policy loaddata compression level */
int aa_g_rawdata_compression_level = Z_DEFAULT_COMPRESSION;
module_param_named(rawdata_compression_level, aa_g_rawdata_compression_level,
* DEPRECATED: read only as strict checking of load is always done now
* that none root users (user namespaces) can load policy.
*/
-bool aa_g_paranoid_load = true;
+bool aa_g_paranoid_load = IS_ENABLED(CONFIG_SECURITY_APPARMOR_PARANOID_LOAD);
module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO);
static int param_get_aaintbool(char *buffer, const struct kernel_param *kp);
.mode = 0600,
.proc_handler = apparmor_dointvec,
},
+ {
+ .procname = "apparmor_display_secid_mode",
+ .data = &apparmor_display_secid_mode,
+ .maxlen = sizeof(int),
+ .mode = 0600,
+ .proc_handler = apparmor_dointvec,
+ },
+
{ }
};
static int __net_init apparmor_nf_register(struct net *net)
{
- int ret;
-
- ret = nf_register_net_hooks(net, apparmor_nf_ops,
+ return nf_register_net_hooks(net, apparmor_nf_ops,
ARRAY_SIZE(apparmor_nf_ops));
- return ret;
}
static void __net_exit apparmor_nf_unregister(struct net *net)
{
int error;
- aa_secids_init();
-
error = aa_setup_dfa_engine();
if (error) {
AA_ERROR("Unable to setup dfa engine\n");
.allow = dfa_user_allow(dfa, state),
.audit = dfa_user_audit(dfa, state),
.quiet = dfa_user_quiet(dfa, state),
- .xindex = dfa_user_xindex(dfa, state),
};
return perms;
"failed srcname match",
"failed type match",
"failed flags match",
- "failed data match"
+ "failed data match",
+ "failed perms check"
};
/*
return 0;
}
- /* failed at end of flags match */
- return 4;
+ /* failed at perms check, don't confuse with flags match */
+ return 6;
}
* @profile: the confining profile
* @mntpath: for the mntpnt (NOT NULL)
* @buffer: buffer to be used to lookup mntpath
- * @devnme: string for the devname/src_name (MAY BE NULL OR ERRPTR)
+ * @devname: string for the devname/src_name (MAY BE NULL OR ERRPTR)
* @type: string for the dev type (MAYBE NULL)
* @flags: mount flags to match
* @data: fs mount data (MAYBE NULL)
/**
* match_mnt - handle path matching for mount
* @profile: the confining profile
- * @mntpath: for the mntpnt (NOT NULL)
+ * @path: for the mntpnt (NOT NULL)
* @buffer: buffer to be used to lookup mntpath
* @devpath: path devname/src_name (MAYBE NULL)
* @devbuffer: buffer to be used to lookup devname/src_name
aa_put_label(target);
goto out;
}
+ aa_put_label(target);
} else
/* already audited error */
error = PTR_ERR(target);
static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request,
struct sock *sk)
{
+ struct aa_sk_ctx *ctx = SK_CTX(sk);
int error = 0;
AA_BUG(!label);
AA_BUG(!sk);
- if (!unconfined(label)) {
+ if (ctx->label != kernel_t && !unconfined(label)) {
struct aa_profile *profile;
DEFINE_AUDIT_SK(sa, op, sk);
}
/**
- * aa_lookup_profile - find a profile by its full or partial name
+ * aa_lookupn_profile - find a profile by its full or partial name
* @ns: the namespace to start from (NOT NULL)
* @hname: name to do lookup on. Does not contain namespace prefix (NOT NULL)
* @n: size of @hname
mutex_lock_nested(&ns->lock, ns->level);
/* check for duplicate rawdata blobs: space and file dedup */
- list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) {
- if (aa_rawdata_eq(rawdata_ent, udata)) {
- struct aa_loaddata *tmp;
-
- tmp = __aa_get_loaddata(rawdata_ent);
- /* check we didn't fail the race */
- if (tmp) {
- aa_put_loaddata(udata);
- udata = tmp;
- break;
+ if (!list_empty(&ns->rawdata_list)) {
+ list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) {
+ if (aa_rawdata_eq(rawdata_ent, udata)) {
+ struct aa_loaddata *tmp;
+
+ tmp = __aa_get_loaddata(rawdata_ent);
+ /* check we didn't fail the race */
+ if (tmp) {
+ aa_put_loaddata(udata);
+ udata = tmp;
+ break;
+ }
}
}
}
list_for_each_entry(ent, &lh, list) {
struct aa_policy *policy;
- ent->new->rawdata = aa_get_loaddata(udata);
+ if (aa_g_export_binary)
+ ent->new->rawdata = aa_get_loaddata(udata);
error = __lookup_replace(ns, ent->new->base.hname,
!(mask & AA_MAY_REPLACE_POLICY),
&ent->old, &info);
}
/* create new fs entries for introspection if needed */
- if (!udata->dents[AAFS_LOADDATA_DIR]) {
+ if (!udata->dents[AAFS_LOADDATA_DIR] && aa_g_export_binary) {
error = __aa_fs_create_rawdata(ns, udata);
if (error) {
info = "failed to create raw_data dir and files";
/* Done with checks that may fail - do actual replacement */
__aa_bump_ns_revision(ns);
- __aa_loaddata_update(udata, ns->revision);
+ if (aa_g_export_binary)
+ __aa_loaddata_update(udata, ns->revision);
list_for_each_entry_safe(ent, tmp, &lh, list) {
list_del_init(&ent->list);
op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL;
- if (ent->old && ent->old->rawdata == ent->new->rawdata) {
+ if (ent->old && ent->old->rawdata == ent->new->rawdata &&
+ ent->new->rawdata) {
/* dedup actual profile replacement */
audit_policy(label, op, ns_name, ent->new->base.hname,
"same as current profile, skipping",
#include "include/label.h"
#include "include/policy.h"
+/* kernel label */
+struct aa_label *kernel_t;
+
/* root profile namespace */
struct aa_ns *root_ns;
const char *aa_hidden_ns_name = "---";
}
/**
- * aa_na_name - Find the ns name to display for @view from @curr
- * @curr - current namespace (NOT NULL)
- * @view - namespace attempting to view (NOT NULL)
- * @subns - are subns visible
+ * aa_ns_name - Find the ns name to display for @view from @curr
+ * @curr: current namespace (NOT NULL)
+ * @view: namespace attempting to view (NOT NULL)
+ * @subns: are subns visible
*
* Returns: name of @view visible from @curr
*/
return aa_hidden_ns_name;
}
+static struct aa_profile *alloc_unconfined(const char *name)
+{
+ struct aa_profile *profile;
+
+ profile = aa_alloc_profile(name, NULL, GFP_KERNEL);
+ if (!profile)
+ return NULL;
+
+ profile->label.flags |= FLAG_IX_ON_NAME_ERROR |
+ FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED;
+ profile->mode = APPARMOR_UNCONFINED;
+ profile->file.dfa = aa_get_dfa(nulldfa);
+ profile->policy.dfa = aa_get_dfa(nulldfa);
+
+ return profile;
+}
+
/**
* alloc_ns - allocate, initialize and return a new namespace
* @prefix: parent namespace name (MAYBE NULL)
init_waitqueue_head(&ns->wait);
/* released by aa_free_ns() */
- ns->unconfined = aa_alloc_profile("unconfined", NULL, GFP_KERNEL);
+ ns->unconfined = alloc_unconfined("unconfined");
if (!ns->unconfined)
goto fail_unconfined;
-
- ns->unconfined->label.flags |= FLAG_IX_ON_NAME_ERROR |
- FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED;
- ns->unconfined->mode = APPARMOR_UNCONFINED;
- ns->unconfined->file.dfa = aa_get_dfa(nulldfa);
- ns->unconfined->policy.dfa = aa_get_dfa(nulldfa);
-
/* ns and ns->unconfined share ns->unconfined refcount */
ns->unconfined->ns = ns;
/**
* __aa_lookupn_ns - lookup the namespace matching @hname
- * @base: base list to start looking up profile name from (NOT NULL)
+ * @view: namespace to search in (NOT NULL)
* @hname: hierarchical ns name (NOT NULL)
* @n: length of @hname
*
}
/**
- * aa_create_ns - create an ns, fail if it already exists
+ * __aa_find_or_create_ns - create an ns, fail if it already exists
* @parent: the parent of the namespace being created
* @name: the name of the namespace
* @dir: if not null the dir to put the ns entries in
*/
int __init aa_alloc_root_ns(void)
{
+ struct aa_profile *kernel_p;
+
/* released by aa_free_root_ns - used as list ref*/
root_ns = alloc_ns(NULL, "root");
if (!root_ns)
return -ENOMEM;
+ kernel_p = alloc_unconfined("kernel_t");
+ if (!kernel_p) {
+ destroy_ns(root_ns);
+ aa_free_ns(root_ns);
+ return -ENOMEM;
+ }
+ kernel_t = &kernel_p->label;
+ root_ns->unconfined->ns = aa_get_ns(root_ns);
+
return 0;
}
root_ns = NULL;
+ aa_label_free(kernel_t);
destroy_ns(ns);
aa_put_ns(ns);
}
{
AA_BUG(!data);
AA_BUG(!data->ns);
- AA_BUG(!data->dents[AAFS_LOADDATA_REVISION]);
AA_BUG(!mutex_is_locked(&data->ns->lock));
AA_BUG(data->revision > revision);
data->revision = revision;
- d_inode(data->dents[AAFS_LOADDATA_DIR])->i_mtime =
- current_time(d_inode(data->dents[AAFS_LOADDATA_DIR]));
- d_inode(data->dents[AAFS_LOADDATA_REVISION])->i_mtime =
- current_time(d_inode(data->dents[AAFS_LOADDATA_REVISION]));
+ if ((data->dents[AAFS_LOADDATA_REVISION])) {
+ d_inode(data->dents[AAFS_LOADDATA_DIR])->i_mtime =
+ current_time(d_inode(data->dents[AAFS_LOADDATA_DIR]));
+ d_inode(data->dents[AAFS_LOADDATA_REVISION])->i_mtime =
+ current_time(d_inode(data->dents[AAFS_LOADDATA_REVISION]));
+ }
}
bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r)
}
/**
- * aa_u16_chunck - test and do bounds checking for a u16 size based chunk
+ * unpack_u16_chunk - test and do bounds checking for a u16 size based chunk
* @e: serialized data read head (NOT NULL)
* @chunk: start address for chunk of data (NOT NULL)
*
((e->pos - e->start) & 7);
size_t pad = ALIGN(sz, 8) - sz;
int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) |
- TO_ACCEPT2_FLAG(YYTD_DATA32) | DFA_FLAG_VERIFY_STATES;
+ TO_ACCEPT2_FLAG(YYTD_DATA32);
+ if (aa_g_paranoid_load)
+ flags |= DFA_FLAG_VERIFY_STATES;
dfa = aa_dfa_unpack(blob + pad, size - pad, flags);
if (IS_ERR(dfa))
/**
* unpack_profile - unpack a serialized profile
* @e: serialized data extent information (NOT NULL)
+ * @ns_name: pointer of newly allocated copy of %NULL in case of error
*
* NOTE: unpack profile sets audit struct if there is a failure
*/
goto fail;
if (tmp & PACKED_FLAG_HAT)
profile->label.flags |= FLAG_HAT;
+ if (tmp & PACKED_FLAG_DEBUG1)
+ profile->label.flags |= FLAG_DEBUG1;
+ if (tmp & PACKED_FLAG_DEBUG2)
+ profile->label.flags |= FLAG_DEBUG2;
if (!unpack_u32(e, &tmp, NULL))
goto fail;
- if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG))
+ if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) {
profile->mode = APPARMOR_COMPLAIN;
- else if (tmp == PACKED_MODE_ENFORCE)
+ } else if (tmp == PACKED_MODE_ENFORCE) {
profile->mode = APPARMOR_ENFORCE;
- else if (tmp == PACKED_MODE_KILL)
+ } else if (tmp == PACKED_MODE_KILL) {
profile->mode = APPARMOR_KILL;
- else if (tmp == PACKED_MODE_UNCONFINED)
+ } else if (tmp == PACKED_MODE_UNCONFINED) {
profile->mode = APPARMOR_UNCONFINED;
- else
+ profile->label.flags |= FLAG_UNCONFINED;
+ } else {
goto fail;
+ }
if (!unpack_u32(e, &tmp, NULL))
goto fail;
if (tmp)
}
/**
- * verify_head - unpack serialized stream header
+ * verify_header - unpack serialized stream header
* @e: serialized data read head (NOT NULL)
* @required: whether the header is required or optional
* @ns: Returns - namespace if one is specified else NULL (NOT NULL)
static int deflate_compress(const char *src, size_t slen, char **dst,
size_t *dlen)
{
+#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
int error;
struct z_stream_s strm;
void *stgbuf, *dstbuf;
fail_deflate:
kvfree(stgbuf);
goto fail_stg_alloc;
+#else
+ *dlen = slen;
+ return 0;
+#endif
}
static int compress_loaddata(struct aa_loaddata *data)
if (error)
return error;
- kvfree(udata);
+ if (udata != data->data)
+ kvfree(udata);
} else
data->compressed_size = data->size;
goto fail;
}
}
- error = compress_loaddata(udata);
- if (error)
- goto fail;
+
+ if (aa_g_export_binary) {
+ error = compress_loaddata(udata);
+ if (error)
+ goto fail;
+ }
return 0;
fail_profile:
size_t e_size;
};
-struct aa_ext *build_aa_ext_struct(struct policy_unpack_fixture *puf,
- struct kunit *test, size_t buf_size)
+static struct aa_ext *build_aa_ext_struct(struct policy_unpack_fixture *puf,
+ struct kunit *test, size_t buf_size)
{
char *buf;
struct aa_ext *e;
{
struct policy_unpack_fixture *puf = test->priv;
bool success;
- u32 data;
+ u32 data = 0;
puf->e->pos += TEST_U32_BUF_OFFSET;
struct policy_unpack_fixture *puf = test->priv;
const char name[] = TEST_U32_NAME;
bool success;
- u32 data;
+ u32 data = 0;
puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
struct policy_unpack_fixture *puf = test->priv;
const char name[] = TEST_U32_NAME;
bool success;
- u32 data;
+ u32 data = 0;
puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
puf->e->end = puf->e->start + TEST_U32_BUF_OFFSET + sizeof(u32);
{
struct policy_unpack_fixture *puf = test->priv;
bool success;
- u64 data;
+ u64 data = 0;
puf->e->pos += TEST_U64_BUF_OFFSET;
struct policy_unpack_fixture *puf = test->priv;
const char name[] = TEST_U64_NAME;
bool success;
- u64 data;
+ u64 data = 0;
puf->e->pos += TEST_NAMED_U64_BUF_OFFSET;
struct policy_unpack_fixture *puf = test->priv;
const char name[] = TEST_U64_NAME;
bool success;
- u64 data;
+ u64 data = 0;
puf->e->pos += TEST_NAMED_U64_BUF_OFFSET;
puf->e->end = puf->e->start + TEST_U64_BUF_OFFSET + sizeof(u64);
}
/**
- * aa_setprocattr_chagnehat - handle procattr interface to change_hat
+ * aa_setprocattr_changehat - handle procattr interface to change_hat
* @args: args received from writing to /proc/<pid>/attr/current (NOT NULL)
* @size: size of the args
* @flags: set of flags governing behavior
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/gfp.h>
-#include <linux/idr.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/xarray.h>
#include "include/cred.h"
#include "include/lib.h"
*/
#define AA_FIRST_SECID 2
-static DEFINE_IDR(aa_secids);
-static DEFINE_SPINLOCK(secid_lock);
+static DEFINE_XARRAY_FLAGS(aa_secids, XA_FLAGS_LOCK_IRQ | XA_FLAGS_TRACK_FREE);
+
+int apparmor_display_secid_mode;
/*
* TODO: allow policy to reserve a secid range?
{
unsigned long flags;
- spin_lock_irqsave(&secid_lock, flags);
- idr_replace(&aa_secids, label, secid);
- spin_unlock_irqrestore(&secid_lock, flags);
+ xa_lock_irqsave(&aa_secids, flags);
+ __xa_store(&aa_secids, secid, label, 0);
+ xa_unlock_irqrestore(&aa_secids, flags);
}
/**
*/
struct aa_label *aa_secid_to_label(u32 secid)
{
- struct aa_label *label;
-
- rcu_read_lock();
- label = idr_find(&aa_secids, secid);
- rcu_read_unlock();
-
- return label;
+ return xa_load(&aa_secids, secid);
}
int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
/* TODO: cache secctx and ref count so we don't have to recreate */
struct aa_label *label = aa_secid_to_label(secid);
+ int flags = FLAG_VIEW_SUBNS | FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT;
int len;
AA_BUG(!seclen);
if (!label)
return -EINVAL;
+ if (apparmor_display_secid_mode)
+ flags |= FLAG_SHOW_MODE;
+
if (secdata)
len = aa_label_asxprint(secdata, root_ns, label,
- FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
- FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT,
- GFP_ATOMIC);
+ flags, GFP_ATOMIC);
else
- len = aa_label_snxprint(NULL, 0, root_ns, label,
- FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
- FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT);
+ len = aa_label_snxprint(NULL, 0, root_ns, label, flags);
+
if (len < 0)
return -ENOMEM;
unsigned long flags;
int ret;
- idr_preload(gfp);
- spin_lock_irqsave(&secid_lock, flags);
- ret = idr_alloc(&aa_secids, label, AA_FIRST_SECID, 0, GFP_ATOMIC);
- spin_unlock_irqrestore(&secid_lock, flags);
- idr_preload_end();
+ xa_lock_irqsave(&aa_secids, flags);
+ ret = __xa_alloc(&aa_secids, &label->secid, label,
+ XA_LIMIT(AA_FIRST_SECID, INT_MAX), gfp);
+ xa_unlock_irqrestore(&aa_secids, flags);
if (ret < 0) {
label->secid = AA_SECID_INVALID;
return ret;
}
- AA_BUG(ret == AA_SECID_INVALID);
- label->secid = ret;
return 0;
}
{
unsigned long flags;
- spin_lock_irqsave(&secid_lock, flags);
- idr_remove(&aa_secids, secid);
- spin_unlock_irqrestore(&secid_lock, flags);
-}
-
-void aa_secids_init(void)
-{
- idr_init_base(&aa_secids, AA_FIRST_SECID);
+ xa_lock_irqsave(&aa_secids, flags);
+ __xa_erase(&aa_secids, secid);
+ xa_unlock_irqrestore(&aa_secids, flags);
}
* should return to the previous cred if it has not been modified.
*/
+#include <linux/gfp.h>
+#include <linux/ptrace.h>
+
+#include "include/audit.h"
#include "include/cred.h"
+#include "include/policy.h"
#include "include/task.h"
/**
return 0;
}
+
+/**
+ * audit_ptrace_mask - convert mask to permission string
+ * @mask: permission mask to convert
+ *
+ * Returns: pointer to static string
+ */
+static const char *audit_ptrace_mask(u32 mask)
+{
+ switch (mask) {
+ case MAY_READ:
+ return "read";
+ case MAY_WRITE:
+ return "trace";
+ case AA_MAY_BE_READ:
+ return "readby";
+ case AA_MAY_BE_TRACED:
+ return "tracedby";
+ }
+ return "";
+}
+
+/* call back to audit ptrace fields */
+static void audit_ptrace_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+
+ if (aad(sa)->request & AA_PTRACE_PERM_MASK) {
+ audit_log_format(ab, " requested_mask=\"%s\"",
+ audit_ptrace_mask(aad(sa)->request));
+
+ if (aad(sa)->denied & AA_PTRACE_PERM_MASK) {
+ audit_log_format(ab, " denied_mask=\"%s\"",
+ audit_ptrace_mask(aad(sa)->denied));
+ }
+ }
+ audit_log_format(ab, " peer=");
+ aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
+ FLAGS_NONE, GFP_ATOMIC);
+}
+
+/* assumes check for PROFILE_MEDIATES is already done */
+/* TODO: conditionals */
+static int profile_ptrace_perm(struct aa_profile *profile,
+ struct aa_label *peer, u32 request,
+ struct common_audit_data *sa)
+{
+ struct aa_perms perms = { };
+
+ aad(sa)->peer = peer;
+ aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request,
+ &perms);
+ aa_apply_modes_to_perms(profile, &perms);
+ return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb);
+}
+
+static int profile_tracee_perm(struct aa_profile *tracee,
+ struct aa_label *tracer, u32 request,
+ struct common_audit_data *sa)
+{
+ if (profile_unconfined(tracee) || unconfined(tracer) ||
+ !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE))
+ return 0;
+
+ return profile_ptrace_perm(tracee, tracer, request, sa);
+}
+
+static int profile_tracer_perm(struct aa_profile *tracer,
+ struct aa_label *tracee, u32 request,
+ struct common_audit_data *sa)
+{
+ if (profile_unconfined(tracer))
+ return 0;
+
+ if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE))
+ return profile_ptrace_perm(tracer, tracee, request, sa);
+
+ /* profile uses the old style capability check for ptrace */
+ if (&tracer->label == tracee)
+ return 0;
+
+ aad(sa)->label = &tracer->label;
+ aad(sa)->peer = tracee;
+ aad(sa)->request = 0;
+ aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE,
+ CAP_OPT_NONE);
+
+ return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb);
+}
+
+/**
+ * aa_may_ptrace - test if tracer task can trace the tracee
+ * @tracer: label of the task doing the tracing (NOT NULL)
+ * @tracee: task label to be traced
+ * @request: permission request
+ *
+ * Returns: %0 else error code if permission denied or error
+ */
+int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
+ u32 request)
+{
+ struct aa_profile *profile;
+ u32 xrequest = request << PTRACE_PERM_SHIFT;
+ DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE);
+
+ return xcheck_labels(tracer, tracee, profile,
+ profile_tracer_perm(profile, tracee, request, &sa),
+ profile_tracee_perm(profile, tracer, xrequest, &sa));
+}
#define X86_FEATURE_RETHUNK (11*32+14) /* "" Use REturn THUNK */
#define X86_FEATURE_UNRET (11*32+15) /* "" AMD BTB untrain return */
#define X86_FEATURE_USE_IBPB_FW (11*32+16) /* "" Use IBPB during runtime firmware calls */
+#define X86_FEATURE_RSB_VMEXIT_LITE (11*32+17) /* "" Fill RSB on VM-Exit when EIBRS is enabled */
/* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
#define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */
* are restricted to targets in
* kernel.
*/
+#define ARCH_CAP_PBRSB_NO BIT(24) /*
+ * Not susceptible to Post-Barrier
+ * Return Stack Buffer Predictions.
+ */
#define MSR_IA32_FLUSH_CMD 0x0000010b
#define L1D_FLUSH BIT(0) /*
cxl_core-y += $(CXL_CORE_SRC)/mbox.o
cxl_core-y += $(CXL_CORE_SRC)/pci.o
cxl_core-y += $(CXL_CORE_SRC)/hdm.o
+cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o
cxl_core-y += config_check.o
obj-m += test/
#define NR_CXL_HOST_BRIDGES 2
#define NR_CXL_ROOT_PORTS 2
#define NR_CXL_SWITCH_PORTS 2
-#define NR_CXL_PORT_DECODERS 2
+#define NR_CXL_PORT_DECODERS 8
static struct platform_device *cxl_acpi;
static struct platform_device *cxl_host_bridge[NR_CXL_HOST_BRIDGES];
.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
.qtg_id = 0,
- .window_size = SZ_256M,
+ .window_size = SZ_256M * 4UL,
},
.target = { 0 },
},
.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
.qtg_id = 1,
- .window_size = SZ_256M * 2,
+ .window_size = SZ_256M * 8UL,
},
.target = { 0, 1, },
},
.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
ACPI_CEDT_CFMWS_RESTRICT_PMEM,
.qtg_id = 2,
- .window_size = SZ_256M,
+ .window_size = SZ_256M * 4UL,
},
.target = { 0 },
},
.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
ACPI_CEDT_CFMWS_RESTRICT_PMEM,
.qtg_id = 3,
- .window_size = SZ_256M * 2,
+ .window_size = SZ_256M * 8UL,
},
.target = { 0, 1, },
},
return 0;
}
+static int mock_decoder_commit(struct cxl_decoder *cxld)
+{
+ struct cxl_port *port = to_cxl_port(cxld->dev.parent);
+ int id = cxld->id;
+
+ if (cxld->flags & CXL_DECODER_F_ENABLE)
+ return 0;
+
+ dev_dbg(&port->dev, "%s commit\n", dev_name(&cxld->dev));
+ if (port->commit_end + 1 != id) {
+ dev_dbg(&port->dev,
+ "%s: out of order commit, expected decoder%d.%d\n",
+ dev_name(&cxld->dev), port->id, port->commit_end + 1);
+ return -EBUSY;
+ }
+
+ port->commit_end++;
+ cxld->flags |= CXL_DECODER_F_ENABLE;
+
+ return 0;
+}
+
+static int mock_decoder_reset(struct cxl_decoder *cxld)
+{
+ struct cxl_port *port = to_cxl_port(cxld->dev.parent);
+ int id = cxld->id;
+
+ if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)
+ return 0;
+
+ dev_dbg(&port->dev, "%s reset\n", dev_name(&cxld->dev));
+ if (port->commit_end != id) {
+ dev_dbg(&port->dev,
+ "%s: out of order reset, expected decoder%d.%d\n",
+ dev_name(&cxld->dev), port->id, port->commit_end);
+ return -EBUSY;
+ }
+
+ port->commit_end--;
+ cxld->flags &= ~CXL_DECODER_F_ENABLE;
+
+ return 0;
+}
+
static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
{
struct cxl_port *port = cxlhdm->port;
struct cxl_decoder *cxld;
int rc;
- if (target_count)
- cxld = cxl_switch_decoder_alloc(port, target_count);
- else
- cxld = cxl_endpoint_decoder_alloc(port);
- if (IS_ERR(cxld)) {
- dev_warn(&port->dev,
- "Failed to allocate the decoder\n");
- return PTR_ERR(cxld);
+ if (target_count) {
+ struct cxl_switch_decoder *cxlsd;
+
+ cxlsd = cxl_switch_decoder_alloc(port, target_count);
+ if (IS_ERR(cxlsd)) {
+ dev_warn(&port->dev,
+ "Failed to allocate the decoder\n");
+ return PTR_ERR(cxlsd);
+ }
+ cxld = &cxlsd->cxld;
+ } else {
+ struct cxl_endpoint_decoder *cxled;
+
+ cxled = cxl_endpoint_decoder_alloc(port);
+
+ if (IS_ERR(cxled)) {
+ dev_warn(&port->dev,
+ "Failed to allocate the decoder\n");
+ return PTR_ERR(cxled);
+ }
+ cxld = &cxled->cxld;
}
- cxld->decoder_range = (struct range) {
+ cxld->hpa_range = (struct range) {
.start = 0,
.end = -1,
};
- cxld->flags = CXL_DECODER_F_ENABLE;
cxld->interleave_ways = min_not_zero(target_count, 1);
cxld->interleave_granularity = SZ_4K;
cxld->target_type = CXL_DECODER_EXPANDER;
+ cxld->commit = mock_decoder_commit;
+ cxld->reset = mock_decoder_reset;
if (target_count) {
rc = device_for_each_child(port->uport, &ctx,
#define SZ_512G (SZ_64G * 8)
#endif
-static struct platform_device *alloc_memdev(int id)
-{
- struct resource res[] = {
- [0] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .flags = IORESOURCE_MEM,
- .desc = IORES_DESC_PERSISTENT_MEMORY,
- },
- };
- struct platform_device *pdev;
- int i, rc;
-
- for (i = 0; i < ARRAY_SIZE(res); i++) {
- struct cxl_mock_res *r = alloc_mock_res(SZ_256M);
-
- if (!r)
- return NULL;
- res[i].start = r->range.start;
- res[i].end = r->range.end;
- }
-
- pdev = platform_device_alloc("cxl_mem", id);
- if (!pdev)
- return NULL;
-
- rc = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
- if (rc)
- goto err;
-
- return pdev;
-
-err:
- platform_device_put(pdev);
- return NULL;
-}
-
static __init int cxl_test_init(void)
{
int rc, i;
goto err_gen_pool_create;
}
- rc = gen_pool_add(cxl_mock_pool, SZ_512G, SZ_64G, NUMA_NO_NODE);
+ rc = gen_pool_add(cxl_mock_pool, iomem_resource.end + 1 - SZ_64G,
+ SZ_64G, NUMA_NO_NODE);
if (rc)
goto err_gen_pool_add;
struct platform_device *dport = cxl_switch_dport[i];
struct platform_device *pdev;
- pdev = alloc_memdev(i);
+ pdev = platform_device_alloc("cxl_mem", i);
if (!pdev)
goto err_mem;
pdev->dev.parent = &dport->dev;
#include <cxlmem.h>
#define LSA_SIZE SZ_128K
+#define DEV_SIZE SZ_2G
#define EFFECT(x) (1U << x)
static struct cxl_cel_entry mock_cel[] = {
.opcode = cpu_to_le16(CXL_MBOX_OP_GET_LSA),
.effect = cpu_to_le16(0),
},
+ {
+ .opcode = cpu_to_le16(CXL_MBOX_OP_GET_PARTITION_INFO),
+ .effect = cpu_to_le16(0),
+ },
{
.opcode = cpu_to_le16(CXL_MBOX_OP_SET_LSA),
.effect = cpu_to_le16(EFFECT(1) | EFFECT(2)),
static int mock_id(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
{
- struct platform_device *pdev = to_platform_device(cxlds->dev);
struct cxl_mbox_identify id = {
.fw_revision = { "mock fw v1 " },
.lsa_size = cpu_to_le32(LSA_SIZE),
- /* FIXME: Add partition support */
- .partition_align = cpu_to_le64(0),
+ .partition_align =
+ cpu_to_le64(SZ_256M / CXL_CAPACITY_MULTIPLIER),
+ .total_capacity =
+ cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER),
};
- u64 capacity = 0;
- int i;
if (cmd->size_out < sizeof(id))
return -EINVAL;
- for (i = 0; i < 2; i++) {
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (!res)
- break;
-
- capacity += resource_size(res) / CXL_CAPACITY_MULTIPLIER;
+ memcpy(cmd->payload_out, &id, sizeof(id));
- if (le64_to_cpu(id.partition_align))
- continue;
+ return 0;
+}
- if (res->desc == IORES_DESC_PERSISTENT_MEMORY)
- id.persistent_capacity = cpu_to_le64(
- resource_size(res) / CXL_CAPACITY_MULTIPLIER);
- else
- id.volatile_capacity = cpu_to_le64(
- resource_size(res) / CXL_CAPACITY_MULTIPLIER);
- }
+static int mock_partition_info(struct cxl_dev_state *cxlds,
+ struct cxl_mbox_cmd *cmd)
+{
+ struct cxl_mbox_get_partition_info pi = {
+ .active_volatile_cap =
+ cpu_to_le64(DEV_SIZE / 2 / CXL_CAPACITY_MULTIPLIER),
+ .active_persistent_cap =
+ cpu_to_le64(DEV_SIZE / 2 / CXL_CAPACITY_MULTIPLIER),
+ };
- id.total_capacity = cpu_to_le64(capacity);
+ if (cmd->size_out < sizeof(pi))
+ return -EINVAL;
- memcpy(cmd->payload_out, &id, sizeof(id));
+ memcpy(cmd->payload_out, &pi, sizeof(pi));
return 0;
}
case CXL_MBOX_OP_GET_LSA:
rc = mock_get_lsa(cxlds, cmd);
break;
+ case CXL_MBOX_OP_GET_PARTITION_INFO:
+ rc = mock_partition_info(cxlds, cmd);
+ break;
case CXL_MBOX_OP_SET_LSA:
rc = mock_set_lsa(cxlds, cmd);
break;
if (IS_ERR(cxlmd))
return PTR_ERR(cxlmd);
- if (range_len(&cxlds->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM))
+ if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM))
rc = devm_cxl_add_nvdimm(dev, cxlmd);
return 0;
}
EXPORT_SYMBOL_NS_GPL(__wrap_cxl_await_media_ready, CXL);
-bool __wrap_cxl_hdm_decode_init(struct cxl_dev_state *cxlds,
- struct cxl_hdm *cxlhdm)
+int __wrap_cxl_hdm_decode_init(struct cxl_dev_state *cxlds,
+ struct cxl_hdm *cxlhdm)
{
int rc = 0, index;
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
- if (!ops || !ops->is_mock_dev(cxlds->dev))
+ if (ops && ops->is_mock_dev(cxlds->dev))
+ rc = 0;
+ else
rc = cxl_hdm_decode_init(cxlds, cxlhdm);
put_cxl_mock_ops(index);
@echo ' clean - Remove generated files and symlinks in the directory'
@echo ''
@echo 'Configuration:'
+ @echo ' make MEMBLOCK_DEBUG=1 - enable memblock_dbg() messages'
@echo ' make NUMA=1 - simulate enabled NUMA'
- @echo ' make MOVABLE_NODE=1 - override `movable_node_is_enabled`'
- @echo ' definition to simulate movable NUMA nodes'
@echo ' make 32BIT_PHYS_ADDR_T=1 - Use 32 bit physical addresses'
vpath %.c ../../lib
$ make && ./main
-A successful run produces no output. It is also possible to override different
-configuration parameters. For example, to simulate enabled NUMA, use:
+A successful run produces no output. It is possible to control the behavior
+by passing options from command line. For example, to include verbose output,
+append the `-v` options when you run the tests:
+
+$ ./main -v
+
+This will print information about which functions are being tested and the
+number of test cases that passed.
+
+For the full list of options from command line, see `./main --help`.
+
+It is also possible to override different configuration parameters to change
+the test functions. For example, to simulate enabled NUMA, use:
$ make NUMA=1
-For the full list of options, see `make help`.
+For the full list of build options, see `make help`.
Project structure
=================
TODO
=====
-1. Add verbose output (e.g., what is being tested and how many tests cases are
- passing)
-
-2. Add flags to Makefile:
- + verbosity level
- + enable memblock_dbg() messages (i.e. pass "-D CONFIG_DEBUG_MEMORY_INIT"
- flag)
-
-3. Add tests trying to memblock_add() or memblock_reserve() 129th region.
+1. Add tests trying to memblock_add() or memblock_reserve() 129th region.
This will trigger memblock_double_array(), make sure it succeeds.
*Important:* These tests require valid memory ranges, use dummy physical
memory block from common.c to implement them. It is also very
likely that the current MEM_SIZE won't be enough for these
test cases. Use realloc to adjust the size accordingly.
-4. Add test cases using this functions (implement them for both directions):
+2. Add test cases using this functions (implement them for both directions):
+ memblock_alloc_raw()
+ memblock_alloc_exact_nid_raw()
+ memblock_alloc_try_nid_raw()
-5. Add tests for memblock_alloc_node() to check if the correct NUMA node is set
+3. Add tests for memblock_alloc_node() to check if the correct NUMA node is set
for the new region
#ifndef _MM_INTERNAL_H
#define _MM_INTERNAL_H
+/*
+ * Enable memblock_dbg() messages
+ */
+#ifdef MEMBLOCK_DEBUG
+static int memblock_debug = 1;
+#endif
+
+#define pr_warn_ratelimited(fmt, ...) printf(fmt, ##__VA_ARGS__)
+
+bool mirrored_kernelcore = false;
+
struct page {};
void memblock_free_pages(struct page *page, unsigned long pfn,
#include <linux/cache.h>
#include <linux/types.h>
+extern bool movable_node_enabled;
+
static inline bool movable_node_is_enabled(void)
{
-#ifdef MOVABLE_NODE
- return true;
-#else
- return false;
-#endif
+ return movable_node_enabled;
}
#endif
#include "tests/alloc_api.h"
#include "tests/alloc_helpers_api.h"
#include "tests/alloc_nid_api.h"
+#include "tests/common.h"
int main(int argc, char **argv)
{
+ parse_args(argc, argv);
memblock_basic_checks();
memblock_alloc_checks();
memblock_alloc_helpers_checks();
CFLAGS += -D CONFIG_NUMA
endif
-# Simulate movable NUMA memory regions
-ifeq ($(MOVABLE_NODE), 1)
- CFLAGS += -D MOVABLE_NODE
-endif
-
# Use 32 bit physical addresses.
# Remember to install 32-bit version of dependencies.
ifeq ($(32BIT_PHYS_ADDR_T), 1)
CFLAGS += -m32 -U CONFIG_PHYS_ADDR_T_64BIT
LDFLAGS += -m32
endif
+
+# Enable memblock_dbg() messages
+ifeq ($(MEMBLOCK_DEBUG), 1)
+ CFLAGS += -D MEMBLOCK_DEBUG
+endif
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_2;
phys_addr_t expected_start;
allocated_ptr = memblock_alloc(size, SMP_CACHE_BYTES);
- assert(allocated_ptr);
- assert(rgn->size == size);
- assert(rgn->base == expected_start);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, expected_start);
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ test_pass_pop();
return 0;
}
struct region r1;
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t r2_size = SZ_16;
/* Use custom alignment */
phys_addr_t alignment = SMP_CACHE_BYTES * 2;
allocated_ptr = memblock_alloc(r2_size, alignment);
- assert(allocated_ptr);
- assert(rgn1->size == r1.size);
- assert(rgn1->base == r1.base);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn1->size, r1.size);
+ ASSERT_EQ(rgn1->base, r1.base);
- assert(rgn2->size == r2_size);
- assert(rgn2->base == expected_start);
+ ASSERT_EQ(rgn2->size, r2_size);
+ ASSERT_EQ(rgn2->base, expected_start);
- assert(memblock.reserved.cnt == 2);
- assert(memblock.reserved.total_size == total_size);
+ ASSERT_EQ(memblock.reserved.cnt, 2);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
return 0;
}
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
/*
* The first region ends at the aligned address to test region merging
*/
allocated_ptr = memblock_alloc(r2_size, SMP_CACHE_BYTES);
- assert(allocated_ptr);
- assert(rgn->size == total_size);
- assert(rgn->base == memblock_end_of_DRAM() - total_size);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->size, total_size);
+ ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - total_size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == total_size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
return 0;
}
struct region r1;
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t r2_size = SZ_512;
phys_addr_t total_size;
allocated_ptr = memblock_alloc(r2_size, SMP_CACHE_BYTES);
- assert(allocated_ptr);
- assert(rgn->size == total_size);
- assert(rgn->base == r1.base - r2_size);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->size, total_size);
+ ASSERT_EQ(rgn->base, r1.base - r2_size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == total_size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
return 0;
}
struct region r1, r2;
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t r3_size = SZ_1K;
phys_addr_t total_size;
allocated_ptr = memblock_alloc(r3_size, SMP_CACHE_BYTES);
- assert(allocated_ptr);
- assert(rgn->size == r2.size + r3_size);
- assert(rgn->base == r2.base - r3_size);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->size, r2.size + r3_size);
+ ASSERT_EQ(rgn->base, r2.base - r3_size);
- assert(memblock.reserved.cnt == 2);
- assert(memblock.reserved.total_size == total_size);
+ ASSERT_EQ(memblock.reserved.cnt, 2);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
return 0;
}
struct region r1, r2;
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t gap_size = SMP_CACHE_BYTES;
phys_addr_t r3_size = SZ_64;
/*
allocated_ptr = memblock_alloc(r3_size, SMP_CACHE_BYTES);
- assert(allocated_ptr);
- assert(rgn->size == total_size);
- assert(rgn->base == r1.base - r2.size - r3_size);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->size, total_size);
+ ASSERT_EQ(rgn->base, r1.base - r2.size - r3_size);
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == total_size);
+ test_pass_pop();
return 0;
}
{
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t region_size = SZ_1K;
phys_addr_t gap_size = SZ_256;
phys_addr_t region_end;
allocated_ptr = memblock_alloc(region_size, SMP_CACHE_BYTES);
- assert(!allocated_ptr);
+ ASSERT_EQ(allocated_ptr, NULL);
+
+ test_pass_pop();
return 0;
}
{
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
setup_memblock();
/* Simulate full memory */
allocated_ptr = memblock_alloc(SZ_256, SMP_CACHE_BYTES);
- assert(!allocated_ptr);
+ ASSERT_EQ(allocated_ptr, NULL);
+
+ test_pass_pop();
return 0;
}
{
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
setup_memblock();
phys_addr_t available_size = SZ_256;
allocated_ptr = memblock_alloc(SZ_1K, SMP_CACHE_BYTES);
- assert(!allocated_ptr);
+ ASSERT_EQ(allocated_ptr, NULL);
+
+ test_pass_pop();
return 0;
}
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t available_size = SZ_256;
phys_addr_t reserved_size = MEM_SIZE - available_size;
allocated_ptr = memblock_alloc(available_size, SMP_CACHE_BYTES);
- assert(allocated_ptr);
- assert(rgn->size == MEM_SIZE);
- assert(rgn->base == memblock_start_of_DRAM());
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->size, MEM_SIZE);
+ ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, MEM_SIZE);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == MEM_SIZE);
+ test_pass_pop();
return 0;
}
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
reset_memblock_regions();
allocated_ptr = memblock_alloc(SZ_1K, SMP_CACHE_BYTES);
- assert(!allocated_ptr);
- assert(rgn->size == 0);
- assert(rgn->base == 0);
- assert(memblock.reserved.total_size == 0);
+ ASSERT_EQ(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->size, 0);
+ ASSERT_EQ(rgn->base, 0);
+ ASSERT_EQ(memblock.reserved.total_size, 0);
+
+ test_pass_pop();
return 0;
}
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
setup_memblock();
allocated_ptr = memblock_alloc(SZ_2, SMP_CACHE_BYTES);
- assert(allocated_ptr);
- assert(rgn->size == SZ_2);
- assert(rgn->base == memblock_start_of_DRAM());
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->size, SZ_2);
+ ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == SZ_2);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, SZ_2);
+
+ test_pass_pop();
return 0;
}
struct region r1;
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t r2_size = SZ_16;
/* Use custom alignment */
phys_addr_t alignment = SMP_CACHE_BYTES * 2;
allocated_ptr = memblock_alloc(r2_size, alignment);
- assert(allocated_ptr);
+ ASSERT_NE(allocated_ptr, NULL);
- assert(rgn1->size == r1.size);
- assert(rgn1->base == r1.base);
+ ASSERT_EQ(rgn1->size, r1.size);
+ ASSERT_EQ(rgn1->base, r1.base);
- assert(rgn2->size == r2_size);
- assert(rgn2->base == expected_start);
+ ASSERT_EQ(rgn2->size, r2_size);
+ ASSERT_EQ(rgn2->base, expected_start);
- assert(memblock.reserved.cnt == 2);
- assert(memblock.reserved.total_size == total_size);
+ ASSERT_EQ(memblock.reserved.cnt, 2);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
return 0;
}
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t r1_size = SZ_512;
phys_addr_t r2_size = SZ_128;
phys_addr_t total_size = r1_size + r2_size;
allocated_ptr = memblock_alloc(r1_size, SMP_CACHE_BYTES);
- assert(allocated_ptr);
- assert(rgn->size == total_size);
- assert(rgn->base == memblock_start_of_DRAM());
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->size, total_size);
+ ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == total_size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
return 0;
}
struct region r1;
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t r2_size = SZ_512;
phys_addr_t total_size;
allocated_ptr = memblock_alloc(r2_size, SMP_CACHE_BYTES);
- assert(allocated_ptr);
- assert(rgn->size == total_size);
- assert(rgn->base == r1.base);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->size, total_size);
+ ASSERT_EQ(rgn->base, r1.base);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == total_size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
return 0;
}
struct region r1, r2;
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t r3_size = SZ_1K;
phys_addr_t total_size;
allocated_ptr = memblock_alloc(r3_size, SMP_CACHE_BYTES);
- assert(allocated_ptr);
- assert(rgn->size == r2.size + r3_size);
- assert(rgn->base == r2.base);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->size, r2.size + r3_size);
+ ASSERT_EQ(rgn->base, r2.base);
- assert(memblock.reserved.cnt == 2);
- assert(memblock.reserved.total_size == total_size);
+ ASSERT_EQ(memblock.reserved.cnt, 2);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
return 0;
}
/* Test case wrappers */
static int alloc_simple_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_top_down_simple_check();
memblock_set_bottom_up(true);
static int alloc_disjoint_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_top_down_disjoint_check();
memblock_set_bottom_up(true);
static int alloc_before_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_top_down_before_check();
memblock_set_bottom_up(true);
static int alloc_after_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_top_down_after_check();
memblock_set_bottom_up(true);
static int alloc_in_between_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_in_between_generic_check();
memblock_set_bottom_up(true);
static int alloc_second_fit_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_top_down_second_fit_check();
memblock_set_bottom_up(true);
static int alloc_small_gaps_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_small_gaps_generic_check();
memblock_set_bottom_up(true);
static int alloc_all_reserved_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_all_reserved_generic_check();
memblock_set_bottom_up(true);
static int alloc_no_space_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_no_space_generic_check();
memblock_set_bottom_up(true);
static int alloc_limited_space_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_limited_space_generic_check();
memblock_set_bottom_up(true);
static int alloc_no_memory_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_no_memory_generic_check();
memblock_set_bottom_up(true);
int memblock_alloc_checks(void)
{
+ const char *func_testing = "memblock_alloc";
+
+ prefix_reset();
+ prefix_push(func_testing);
+ test_print("Running %s tests...\n", func_testing);
+
reset_memblock_attributes();
dummy_physical_memory_init();
dummy_physical_memory_cleanup();
+ prefix_pop();
+
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_16;
phys_addr_t min_addr;
allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, min_addr);
- assert(rgn->size == size);
- assert(rgn->base == min_addr);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ test_pass_pop();
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_32;
phys_addr_t min_addr;
allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
- assert(rgn->size == size);
- assert(rgn->base == memblock_end_of_DRAM() - SMP_CACHE_BYTES);
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - SMP_CACHE_BYTES);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
+
+ test_pass_pop();
return 0;
}
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_32;
phys_addr_t min_addr;
allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
- assert(allocated_ptr);
- assert(rgn->size == size);
- assert(rgn->base == memblock_end_of_DRAM() - SMP_CACHE_BYTES);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - SMP_CACHE_BYTES);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
+
+ test_pass_pop();
return 0;
}
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t r1_size = SZ_64;
phys_addr_t r2_size = SZ_2;
phys_addr_t total_size = r1_size + r2_size;
allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
- assert(allocated_ptr);
- assert(rgn->base == min_addr - r1_size);
- assert(rgn->size == total_size);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->base, min_addr - r1_size);
+ ASSERT_EQ(rgn->size, total_size);
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == total_size);
+ test_pass_pop();
return 0;
}
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t r1_size = SZ_64;
phys_addr_t min_addr;
phys_addr_t start_addr;
allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
- assert(allocated_ptr);
- assert(rgn->base == start_addr);
- assert(rgn->size == MEM_SIZE);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->base, start_addr);
+ ASSERT_EQ(rgn->size, MEM_SIZE);
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, MEM_SIZE);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == MEM_SIZE);
+ test_pass_pop();
return 0;
}
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_32;
phys_addr_t min_addr;
allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
- assert(allocated_ptr);
- assert(rgn->size == size);
- assert(rgn->base == memblock_start_of_DRAM());
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ test_pass_pop();
return 0;
}
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t r1_size = SZ_64;
phys_addr_t min_addr;
phys_addr_t r2_size;
allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
- assert(allocated_ptr);
- assert(rgn->base == memblock_start_of_DRAM());
- assert(rgn->size == r1_size);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
+ ASSERT_EQ(rgn->size, r1_size);
- assert(memblock.reserved.cnt == 2);
- assert(memblock.reserved.total_size == r1_size + r2_size);
+ ASSERT_EQ(memblock.reserved.cnt, 2);
+ ASSERT_EQ(memblock.reserved.total_size, r1_size + r2_size);
+
+ test_pass_pop();
return 0;
}
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t r1_size = SZ_64;
phys_addr_t min_addr;
phys_addr_t start_addr;
allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
- assert(allocated_ptr);
- assert(rgn->base == start_addr);
- assert(rgn->size == r1_size);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(rgn->base, start_addr);
+ ASSERT_EQ(rgn->size, r1_size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == r1_size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, r1_size);
+
+ test_pass_pop();
return 0;
}
/* Test case wrappers */
static int alloc_from_simple_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_from_simple_generic_check();
memblock_set_bottom_up(true);
static int alloc_from_misaligned_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_from_misaligned_generic_check();
memblock_set_bottom_up(true);
static int alloc_from_high_addr_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_from_top_down_high_addr_check();
memblock_set_bottom_up(true);
static int alloc_from_no_space_above_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_from_top_down_no_space_above_check();
memblock_set_bottom_up(true);
static int alloc_from_min_addr_cap_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_from_top_down_min_addr_cap_check();
memblock_set_bottom_up(true);
int memblock_alloc_helpers_checks(void)
{
+ const char *func_testing = "memblock_alloc_from";
+
+ prefix_reset();
+ prefix_push(func_testing);
+ test_print("Running %s tests...\n", func_testing);
+
reset_memblock_attributes();
dummy_physical_memory_init();
dummy_physical_memory_cleanup();
+ prefix_pop();
+
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_128;
phys_addr_t min_addr;
phys_addr_t max_addr;
b = (char *)allocated_ptr;
rgn_end = rgn->base + rgn->size;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, max_addr - size);
+ ASSERT_EQ(rgn_end, max_addr);
- assert(rgn->size == size);
- assert(rgn->base == max_addr - size);
- assert(rgn_end == max_addr);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ test_pass_pop();
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_128;
phys_addr_t misalign = SZ_2;
phys_addr_t min_addr;
b = (char *)allocated_ptr;
rgn_end = rgn->base + rgn->size;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
- assert(rgn->size == size);
- assert(rgn->base == max_addr - size - misalign);
- assert(rgn_end < max_addr);
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, max_addr - size - misalign);
+ ASSERT_LT(rgn_end, max_addr);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
+
+ test_pass_pop();
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_1K;
phys_addr_t min_addr;
phys_addr_t max_addr;
b = (char *)allocated_ptr;
rgn_end = rgn->base + rgn->size;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, min_addr);
+ ASSERT_EQ(rgn_end, max_addr);
- assert(rgn->size == size);
- assert(rgn->base == min_addr);
- assert(rgn_end == max_addr);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ test_pass_pop();
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_256;
phys_addr_t min_addr;
phys_addr_t max_addr;
min_addr, max_addr, NUMA_NO_NODE);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, max_addr - size);
- assert(rgn->size == size);
- assert(rgn->base == max_addr - size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ test_pass_pop();
return 0;
}
{
void *allocated_ptr = NULL;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_1K;
phys_addr_t min_addr;
phys_addr_t max_addr;
allocated_ptr = memblock_alloc_try_nid(size, SMP_CACHE_BYTES,
min_addr, max_addr, NUMA_NO_NODE);
- assert(!allocated_ptr);
+ ASSERT_EQ(allocated_ptr, NULL);
+
+ test_pass_pop();
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t r1_size = SZ_128;
phys_addr_t r2_size = SZ_64;
phys_addr_t total_size = r1_size + r2_size;
min_addr, max_addr, NUMA_NO_NODE);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
- assert(rgn->size == total_size);
- assert(rgn->base == reserved_base);
+ ASSERT_EQ(rgn->size, total_size);
+ ASSERT_EQ(rgn->base, reserved_base);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == total_size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t r1_size = SZ_64;
phys_addr_t r2_size = SZ_128;
phys_addr_t total_size = r1_size + r2_size;
min_addr, max_addr, NUMA_NO_NODE);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
+
+ ASSERT_EQ(rgn->size, total_size);
+ ASSERT_EQ(rgn->base, min_addr);
- assert(rgn->size == total_size);
- assert(rgn->base == min_addr);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == total_size);
+ test_pass_pop();
return 0;
}
char *b;
struct region r1, r2;
+ PREFIX_PUSH();
+
phys_addr_t r3_size = SZ_64;
phys_addr_t gap_size = SMP_CACHE_BYTES;
phys_addr_t total_size;
min_addr, max_addr, NUMA_NO_NODE);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
+
+ ASSERT_EQ(rgn1->size, r1.size + r3_size);
+ ASSERT_EQ(rgn1->base, max_addr - r3_size);
- assert(rgn1->size == r1.size + r3_size);
- assert(rgn1->base == max_addr - r3_size);
+ ASSERT_EQ(rgn2->size, r2.size);
+ ASSERT_EQ(rgn2->base, r2.base);
- assert(rgn2->size == r2.size);
- assert(rgn2->base == r2.base);
+ ASSERT_EQ(memblock.reserved.cnt, 2);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
- assert(memblock.reserved.cnt == 2);
- assert(memblock.reserved.total_size == total_size);
+ test_pass_pop();
return 0;
}
char *b;
struct region r1, r2;
+ PREFIX_PUSH();
+
phys_addr_t r3_size = SZ_64;
phys_addr_t total_size;
phys_addr_t max_addr;
min_addr, max_addr, NUMA_NO_NODE);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
- assert(rgn->size == total_size);
- assert(rgn->base == r2.base);
+ ASSERT_EQ(rgn->size, total_size);
+ ASSERT_EQ(rgn->base, r2.base);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == total_size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
return 0;
}
char *b;
struct region r1, r2;
+ PREFIX_PUSH();
+
phys_addr_t r3_size = SZ_256;
phys_addr_t gap_size = SMP_CACHE_BYTES;
phys_addr_t total_size;
min_addr, max_addr, NUMA_NO_NODE);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
+
+ ASSERT_EQ(rgn1->size, r1.size);
+ ASSERT_EQ(rgn1->base, r1.base);
- assert(rgn1->size == r1.size);
- assert(rgn1->base == r1.base);
+ ASSERT_EQ(rgn2->size, r2.size + r3_size);
+ ASSERT_EQ(rgn2->base, r2.base - r3_size);
- assert(rgn2->size == r2.size + r3_size);
- assert(rgn2->base == r2.base - r3_size);
+ ASSERT_EQ(memblock.reserved.cnt, 2);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
- assert(memblock.reserved.cnt == 2);
- assert(memblock.reserved.total_size == total_size);
+ test_pass_pop();
return 0;
}
void *allocated_ptr = NULL;
struct region r1, r2;
+ PREFIX_PUSH();
+
phys_addr_t r3_size = SZ_256;
phys_addr_t gap_size = SMP_CACHE_BYTES;
phys_addr_t max_addr;
allocated_ptr = memblock_alloc_try_nid(r3_size, SMP_CACHE_BYTES,
min_addr, max_addr, NUMA_NO_NODE);
- assert(!allocated_ptr);
+ ASSERT_EQ(allocated_ptr, NULL);
+
+ test_pass_pop();
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_256;
phys_addr_t min_addr;
phys_addr_t max_addr;
min_addr, max_addr, NUMA_NO_NODE);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - size);
- assert(rgn->size == size);
- assert(rgn->base == memblock_end_of_DRAM() - size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ test_pass_pop();
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_1K;
phys_addr_t min_addr;
phys_addr_t max_addr;
min_addr, max_addr, NUMA_NO_NODE);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
- assert(rgn->size == size);
- assert(rgn->base == memblock_end_of_DRAM() - size);
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
+
+ test_pass_pop();
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_128;
phys_addr_t min_addr;
phys_addr_t max_addr;
b = (char *)allocated_ptr;
rgn_end = rgn->base + rgn->size;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, min_addr);
+ ASSERT_LT(rgn_end, max_addr);
- assert(rgn->size == size);
- assert(rgn->base == min_addr);
- assert(rgn_end < max_addr);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ test_pass_pop();
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_128;
phys_addr_t misalign = SZ_2;
phys_addr_t min_addr;
b = (char *)allocated_ptr;
rgn_end = rgn->base + rgn->size;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, min_addr + (SMP_CACHE_BYTES - misalign));
+ ASSERT_LT(rgn_end, max_addr);
- assert(rgn->size == size);
- assert(rgn->base == min_addr + (SMP_CACHE_BYTES - misalign));
- assert(rgn_end < max_addr);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ test_pass_pop();
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_256;
phys_addr_t min_addr;
phys_addr_t max_addr;
NUMA_NO_NODE);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
- assert(rgn->size == size);
- assert(rgn->base == memblock_start_of_DRAM());
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
+
+ test_pass_pop();
return 0;
}
char *b;
struct region r1, r2;
+ PREFIX_PUSH();
+
phys_addr_t r3_size = SZ_64;
phys_addr_t gap_size = SMP_CACHE_BYTES;
phys_addr_t total_size;
NUMA_NO_NODE);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
- assert(rgn1->size == r1.size);
- assert(rgn1->base == max_addr);
+ ASSERT_EQ(rgn1->size, r1.size);
+ ASSERT_EQ(rgn1->base, max_addr);
- assert(rgn2->size == r2.size + r3_size);
- assert(rgn2->base == r2.base);
+ ASSERT_EQ(rgn2->size, r2.size + r3_size);
+ ASSERT_EQ(rgn2->base, r2.base);
- assert(memblock.reserved.cnt == 2);
- assert(memblock.reserved.total_size == total_size);
+ ASSERT_EQ(memblock.reserved.cnt, 2);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
return 0;
}
char *b;
struct region r1, r2;
+ PREFIX_PUSH();
+
phys_addr_t r3_size = SZ_256;
phys_addr_t gap_size = SMP_CACHE_BYTES;
phys_addr_t total_size;
NUMA_NO_NODE);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
+
+ ASSERT_EQ(rgn3->size, r3_size);
+ ASSERT_EQ(rgn3->base, memblock_start_of_DRAM());
- assert(rgn3->size == r3_size);
- assert(rgn3->base == memblock_start_of_DRAM());
+ ASSERT_EQ(rgn2->size, r2.size);
+ ASSERT_EQ(rgn2->base, r2.base);
- assert(rgn2->size == r2.size);
- assert(rgn2->base == r2.base);
+ ASSERT_EQ(rgn1->size, r1.size);
+ ASSERT_EQ(rgn1->base, r1.base);
- assert(rgn1->size == r1.size);
- assert(rgn1->base == r1.base);
+ ASSERT_EQ(memblock.reserved.cnt, 3);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
- assert(memblock.reserved.cnt == 3);
- assert(memblock.reserved.total_size == total_size);
+ test_pass_pop();
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_256;
phys_addr_t min_addr;
phys_addr_t max_addr;
NUMA_NO_NODE);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, min_addr);
- assert(rgn->size == size);
- assert(rgn->base == min_addr);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ test_pass_pop();
return 0;
}
void *allocated_ptr = NULL;
char *b;
+ PREFIX_PUSH();
+
phys_addr_t size = SZ_1K;
phys_addr_t min_addr;
phys_addr_t max_addr;
NUMA_NO_NODE);
b = (char *)allocated_ptr;
- assert(allocated_ptr);
- assert(*b == 0);
+ ASSERT_NE(allocated_ptr, NULL);
+ ASSERT_EQ(*b, 0);
+
+ ASSERT_EQ(rgn->size, size);
+ ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
- assert(rgn->size == size);
- assert(rgn->base == memblock_start_of_DRAM());
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == size);
+ test_pass_pop();
return 0;
}
/* Test case wrappers */
static int alloc_try_nid_simple_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_try_nid_top_down_simple_check();
memblock_set_bottom_up(true);
static int alloc_try_nid_misaligned_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_try_nid_top_down_end_misaligned_check();
memblock_set_bottom_up(true);
static int alloc_try_nid_narrow_range_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_try_nid_top_down_narrow_range_check();
memblock_set_bottom_up(true);
static int alloc_try_nid_reserved_with_space_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_try_nid_top_down_reserved_with_space_check();
memblock_set_bottom_up(true);
static int alloc_try_nid_reserved_no_space_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_try_nid_top_down_reserved_no_space_check();
memblock_set_bottom_up(true);
static int alloc_try_nid_cap_max_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_try_nid_top_down_cap_max_check();
memblock_set_bottom_up(true);
static int alloc_try_nid_cap_min_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_try_nid_top_down_cap_min_check();
memblock_set_bottom_up(true);
static int alloc_try_nid_min_reserved_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_try_nid_min_reserved_generic_check();
memblock_set_bottom_up(true);
static int alloc_try_nid_max_reserved_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_try_nid_max_reserved_generic_check();
memblock_set_bottom_up(true);
static int alloc_try_nid_exact_address_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_try_nid_exact_address_generic_check();
memblock_set_bottom_up(true);
static int alloc_try_nid_reserved_full_merge_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_try_nid_reserved_full_merge_generic_check();
memblock_set_bottom_up(true);
static int alloc_try_nid_reserved_all_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_try_nid_reserved_all_generic_check();
memblock_set_bottom_up(true);
static int alloc_try_nid_low_max_check(void)
{
+ test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_try_nid_low_max_generic_check();
memblock_set_bottom_up(true);
int memblock_alloc_nid_checks(void)
{
+ const char *func_testing = "memblock_alloc_try_nid";
+
+ prefix_reset();
+ prefix_push(func_testing);
+ test_print("Running %s tests...\n", func_testing);
+
reset_memblock_attributes();
dummy_physical_memory_init();
dummy_physical_memory_cleanup();
+ prefix_pop();
+
return 0;
}
#include "basic_api.h"
#define EXPECTED_MEMBLOCK_REGIONS 128
+#define FUNC_ADD "memblock_add"
+#define FUNC_RESERVE "memblock_reserve"
+#define FUNC_REMOVE "memblock_remove"
+#define FUNC_FREE "memblock_free"
static int memblock_initialization_check(void)
{
- assert(memblock.memory.regions);
- assert(memblock.memory.cnt == 1);
- assert(memblock.memory.max == EXPECTED_MEMBLOCK_REGIONS);
- assert(strcmp(memblock.memory.name, "memory") == 0);
+ PREFIX_PUSH();
- assert(memblock.reserved.regions);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.memory.max == EXPECTED_MEMBLOCK_REGIONS);
- assert(strcmp(memblock.reserved.name, "reserved") == 0);
+ ASSERT_NE(memblock.memory.regions, NULL);
+ ASSERT_EQ(memblock.memory.cnt, 1);
+ ASSERT_EQ(memblock.memory.max, EXPECTED_MEMBLOCK_REGIONS);
+ ASSERT_EQ(strcmp(memblock.memory.name, "memory"), 0);
- assert(!memblock.bottom_up);
- assert(memblock.current_limit == MEMBLOCK_ALLOC_ANYWHERE);
+ ASSERT_NE(memblock.reserved.regions, NULL);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.memory.max, EXPECTED_MEMBLOCK_REGIONS);
+ ASSERT_EQ(strcmp(memblock.reserved.name, "reserved"), 0);
+
+ ASSERT_EQ(memblock.bottom_up, false);
+ ASSERT_EQ(memblock.current_limit, MEMBLOCK_ALLOC_ANYWHERE);
+
+ test_pass_pop();
return 0;
}
.size = SZ_4M
};
+ PREFIX_PUSH();
+
reset_memblock_regions();
memblock_add(r.base, r.size);
- assert(rgn->base == r.base);
- assert(rgn->size == r.size);
+ ASSERT_EQ(rgn->base, r.base);
+ ASSERT_EQ(rgn->size, r.size);
+
+ ASSERT_EQ(memblock.memory.cnt, 1);
+ ASSERT_EQ(memblock.memory.total_size, r.size);
- assert(memblock.memory.cnt == 1);
- assert(memblock.memory.total_size == r.size);
+ test_pass_pop();
return 0;
}
.size = SZ_16M
};
+ PREFIX_PUSH();
+
reset_memblock_regions();
memblock_add_node(r.base, r.size, 1, MEMBLOCK_HOTPLUG);
- assert(rgn->base == r.base);
- assert(rgn->size == r.size);
+ ASSERT_EQ(rgn->base, r.base);
+ ASSERT_EQ(rgn->size, r.size);
#ifdef CONFIG_NUMA
- assert(rgn->nid == 1);
+ ASSERT_EQ(rgn->nid, 1);
#endif
- assert(rgn->flags == MEMBLOCK_HOTPLUG);
+ ASSERT_EQ(rgn->flags, MEMBLOCK_HOTPLUG);
+
+ ASSERT_EQ(memblock.memory.cnt, 1);
+ ASSERT_EQ(memblock.memory.total_size, r.size);
- assert(memblock.memory.cnt == 1);
- assert(memblock.memory.total_size == r.size);
+ test_pass_pop();
return 0;
}
.size = SZ_8K
};
+ PREFIX_PUSH();
+
reset_memblock_regions();
memblock_add(r1.base, r1.size);
memblock_add(r2.base, r2.size);
- assert(rgn1->base == r1.base);
- assert(rgn1->size == r1.size);
+ ASSERT_EQ(rgn1->base, r1.base);
+ ASSERT_EQ(rgn1->size, r1.size);
+
+ ASSERT_EQ(rgn2->base, r2.base);
+ ASSERT_EQ(rgn2->size, r2.size);
- assert(rgn2->base == r2.base);
- assert(rgn2->size == r2.size);
+ ASSERT_EQ(memblock.memory.cnt, 2);
+ ASSERT_EQ(memblock.memory.total_size, r1.size + r2.size);
- assert(memblock.memory.cnt == 2);
- assert(memblock.memory.total_size == r1.size + r2.size);
+ test_pass_pop();
return 0;
}
.size = SZ_512M
};
+ PREFIX_PUSH();
+
total_size = (r1.base - r2.base) + r1.size;
reset_memblock_regions();
memblock_add(r1.base, r1.size);
memblock_add(r2.base, r2.size);
- assert(rgn->base == r2.base);
- assert(rgn->size == total_size);
+ ASSERT_EQ(rgn->base, r2.base);
+ ASSERT_EQ(rgn->size, total_size);
+
+ ASSERT_EQ(memblock.memory.cnt, 1);
+ ASSERT_EQ(memblock.memory.total_size, total_size);
- assert(memblock.memory.cnt == 1);
- assert(memblock.memory.total_size == total_size);
+ test_pass_pop();
return 0;
}
.size = SZ_1G
};
+ PREFIX_PUSH();
+
total_size = (r2.base - r1.base) + r2.size;
reset_memblock_regions();
memblock_add(r1.base, r1.size);
memblock_add(r2.base, r2.size);
- assert(rgn->base == r1.base);
- assert(rgn->size == total_size);
+ ASSERT_EQ(rgn->base, r1.base);
+ ASSERT_EQ(rgn->size, total_size);
+
+ ASSERT_EQ(memblock.memory.cnt, 1);
+ ASSERT_EQ(memblock.memory.total_size, total_size);
- assert(memblock.memory.cnt == 1);
- assert(memblock.memory.total_size == total_size);
+ test_pass_pop();
return 0;
}
.size = SZ_1M
};
+ PREFIX_PUSH();
+
reset_memblock_regions();
memblock_add(r1.base, r1.size);
memblock_add(r2.base, r2.size);
- assert(rgn->base == r1.base);
- assert(rgn->size == r1.size);
+ ASSERT_EQ(rgn->base, r1.base);
+ ASSERT_EQ(rgn->size, r1.size);
+
+ ASSERT_EQ(memblock.memory.cnt, 1);
+ ASSERT_EQ(memblock.memory.total_size, r1.size);
- assert(memblock.memory.cnt == 1);
- assert(memblock.memory.total_size == r1.size);
+ test_pass_pop();
return 0;
}
.size = SZ_2M
};
+ PREFIX_PUSH();
+
reset_memblock_regions();
memblock_add(r.base, r.size);
memblock_add(r.base, r.size);
- assert(memblock.memory.cnt == 1);
- assert(memblock.memory.total_size == r.size);
+ ASSERT_EQ(memblock.memory.cnt, 1);
+ ASSERT_EQ(memblock.memory.total_size, r.size);
+
+ test_pass_pop();
return 0;
}
static int memblock_add_checks(void)
{
+ prefix_reset();
+ prefix_push(FUNC_ADD);
+ test_print("Running %s tests...\n", FUNC_ADD);
+
memblock_add_simple_check();
memblock_add_node_simple_check();
memblock_add_disjoint_check();
memblock_add_within_check();
memblock_add_twice_check();
+ prefix_pop();
+
return 0;
}
.size = SZ_128M
};
+ PREFIX_PUSH();
+
reset_memblock_regions();
memblock_reserve(r.base, r.size);
- assert(rgn->base == r.base);
- assert(rgn->size == r.size);
+ ASSERT_EQ(rgn->base, r.base);
+ ASSERT_EQ(rgn->size, r.size);
+
+ test_pass_pop();
return 0;
}
.size = SZ_512M
};
+ PREFIX_PUSH();
+
reset_memblock_regions();
memblock_reserve(r1.base, r1.size);
memblock_reserve(r2.base, r2.size);
- assert(rgn1->base == r1.base);
- assert(rgn1->size == r1.size);
+ ASSERT_EQ(rgn1->base, r1.base);
+ ASSERT_EQ(rgn1->size, r1.size);
+
+ ASSERT_EQ(rgn2->base, r2.base);
+ ASSERT_EQ(rgn2->size, r2.size);
- assert(rgn2->base == r2.base);
- assert(rgn2->size == r2.size);
+ ASSERT_EQ(memblock.reserved.cnt, 2);
+ ASSERT_EQ(memblock.reserved.total_size, r1.size + r2.size);
- assert(memblock.reserved.cnt == 2);
- assert(memblock.reserved.total_size == r1.size + r2.size);
+ test_pass_pop();
return 0;
}
.size = SZ_1G
};
+ PREFIX_PUSH();
+
total_size = (r1.base - r2.base) + r1.size;
reset_memblock_regions();
memblock_reserve(r1.base, r1.size);
memblock_reserve(r2.base, r2.size);
- assert(rgn->base == r2.base);
- assert(rgn->size == total_size);
+ ASSERT_EQ(rgn->base, r2.base);
+ ASSERT_EQ(rgn->size, total_size);
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == total_size);
+ test_pass_pop();
return 0;
}
.size = SZ_128K
};
+ PREFIX_PUSH();
+
total_size = (r2.base - r1.base) + r2.size;
reset_memblock_regions();
memblock_reserve(r1.base, r1.size);
memblock_reserve(r2.base, r2.size);
- assert(rgn->base == r1.base);
- assert(rgn->size == total_size);
+ ASSERT_EQ(rgn->base, r1.base);
+ ASSERT_EQ(rgn->size, total_size);
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == total_size);
+ test_pass_pop();
return 0;
}
.size = SZ_64K
};
+ PREFIX_PUSH();
+
reset_memblock_regions();
memblock_reserve(r1.base, r1.size);
memblock_reserve(r2.base, r2.size);
- assert(rgn->base == r1.base);
- assert(rgn->size == r1.size);
+ ASSERT_EQ(rgn->base, r1.base);
+ ASSERT_EQ(rgn->size, r1.size);
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, r1.size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == r1.size);
+ test_pass_pop();
return 0;
}
.size = SZ_2M
};
+ PREFIX_PUSH();
+
reset_memblock_regions();
memblock_reserve(r.base, r.size);
memblock_reserve(r.base, r.size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == r.size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, r.size);
+
+ test_pass_pop();
return 0;
}
static int memblock_reserve_checks(void)
{
+ prefix_reset();
+ prefix_push(FUNC_RESERVE);
+ test_print("Running %s tests...\n", FUNC_RESERVE);
+
memblock_reserve_simple_check();
memblock_reserve_disjoint_check();
memblock_reserve_overlap_top_check();
memblock_reserve_within_check();
memblock_reserve_twice_check();
+ prefix_pop();
+
return 0;
}
.size = SZ_4M
};
+ PREFIX_PUSH();
+
reset_memblock_regions();
memblock_add(r1.base, r1.size);
memblock_add(r2.base, r2.size);
memblock_remove(r1.base, r1.size);
- assert(rgn->base == r2.base);
- assert(rgn->size == r2.size);
+ ASSERT_EQ(rgn->base, r2.base);
+ ASSERT_EQ(rgn->size, r2.size);
- assert(memblock.memory.cnt == 1);
- assert(memblock.memory.total_size == r2.size);
+ ASSERT_EQ(memblock.memory.cnt, 1);
+ ASSERT_EQ(memblock.memory.total_size, r2.size);
+
+ test_pass_pop();
return 0;
}
.size = SZ_1G
};
+ PREFIX_PUSH();
+
reset_memblock_regions();
memblock_add(r1.base, r1.size);
memblock_remove(r2.base, r2.size);
- assert(rgn->base == r1.base);
- assert(rgn->size == r1.size);
+ ASSERT_EQ(rgn->base, r1.base);
+ ASSERT_EQ(rgn->size, r1.size);
+
+ ASSERT_EQ(memblock.memory.cnt, 1);
+ ASSERT_EQ(memblock.memory.total_size, r1.size);
- assert(memblock.memory.cnt == 1);
- assert(memblock.memory.total_size == r1.size);
+ test_pass_pop();
return 0;
}
.size = SZ_32M
};
+ PREFIX_PUSH();
+
r1_end = r1.base + r1.size;
r2_end = r2.base + r2.size;
total_size = r1_end - r2_end;
memblock_add(r1.base, r1.size);
memblock_remove(r2.base, r2.size);
- assert(rgn->base == r1.base + r2.base);
- assert(rgn->size == total_size);
+ ASSERT_EQ(rgn->base, r1.base + r2.base);
+ ASSERT_EQ(rgn->size, total_size);
+
+ ASSERT_EQ(memblock.memory.cnt, 1);
+ ASSERT_EQ(memblock.memory.total_size, total_size);
- assert(memblock.memory.cnt == 1);
- assert(memblock.memory.total_size == total_size);
+ test_pass_pop();
return 0;
}
.size = SZ_256M
};
+ PREFIX_PUSH();
+
total_size = r2.base - r1.base;
reset_memblock_regions();
memblock_add(r1.base, r1.size);
memblock_remove(r2.base, r2.size);
- assert(rgn->base == r1.base);
- assert(rgn->size == total_size);
+ ASSERT_EQ(rgn->base, r1.base);
+ ASSERT_EQ(rgn->size, total_size);
+
+ ASSERT_EQ(memblock.memory.cnt, 1);
+ ASSERT_EQ(memblock.memory.total_size, total_size);
+
+ test_pass_pop();
- assert(memblock.memory.cnt == 1);
- assert(memblock.memory.total_size == total_size);
return 0;
}
.size = SZ_1M
};
+ PREFIX_PUSH();
+
r1_size = r2.base - r1.base;
r2_size = (r1.base + r1.size) - (r2.base + r2.size);
total_size = r1_size + r2_size;
memblock_add(r1.base, r1.size);
memblock_remove(r2.base, r2.size);
- assert(rgn1->base == r1.base);
- assert(rgn1->size == r1_size);
+ ASSERT_EQ(rgn1->base, r1.base);
+ ASSERT_EQ(rgn1->size, r1_size);
+
+ ASSERT_EQ(rgn2->base, r2.base + r2.size);
+ ASSERT_EQ(rgn2->size, r2_size);
- assert(rgn2->base == r2.base + r2.size);
- assert(rgn2->size == r2_size);
+ ASSERT_EQ(memblock.memory.cnt, 2);
+ ASSERT_EQ(memblock.memory.total_size, total_size);
- assert(memblock.memory.cnt == 2);
- assert(memblock.memory.total_size == total_size);
+ test_pass_pop();
return 0;
}
static int memblock_remove_checks(void)
{
+ prefix_reset();
+ prefix_push(FUNC_REMOVE);
+ test_print("Running %s tests...\n", FUNC_REMOVE);
+
memblock_remove_simple_check();
memblock_remove_absent_check();
memblock_remove_overlap_top_check();
memblock_remove_overlap_bottom_check();
memblock_remove_within_check();
+ prefix_pop();
+
return 0;
}
.size = SZ_1M
};
+ PREFIX_PUSH();
+
reset_memblock_regions();
memblock_reserve(r1.base, r1.size);
memblock_reserve(r2.base, r2.size);
memblock_free((void *)r1.base, r1.size);
- assert(rgn->base == r2.base);
- assert(rgn->size == r2.size);
+ ASSERT_EQ(rgn->base, r2.base);
+ ASSERT_EQ(rgn->size, r2.size);
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, r2.size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == r2.size);
+ test_pass_pop();
return 0;
}
.size = SZ_128M
};
+ PREFIX_PUSH();
+
reset_memblock_regions();
memblock_reserve(r1.base, r1.size);
memblock_free((void *)r2.base, r2.size);
- assert(rgn->base == r1.base);
- assert(rgn->size == r1.size);
+ ASSERT_EQ(rgn->base, r1.base);
+ ASSERT_EQ(rgn->size, r1.size);
+
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, r1.size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == r1.size);
+ test_pass_pop();
return 0;
}
.size = SZ_8M
};
+ PREFIX_PUSH();
+
total_size = (r1.size + r1.base) - (r2.base + r2.size);
reset_memblock_regions();
memblock_reserve(r1.base, r1.size);
memblock_free((void *)r2.base, r2.size);
- assert(rgn->base == r2.base + r2.size);
- assert(rgn->size == total_size);
+ ASSERT_EQ(rgn->base, r2.base + r2.size);
+ ASSERT_EQ(rgn->size, total_size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == total_size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
return 0;
}
.size = SZ_32M
};
+ PREFIX_PUSH();
+
total_size = r2.base - r1.base;
reset_memblock_regions();
memblock_reserve(r1.base, r1.size);
memblock_free((void *)r2.base, r2.size);
- assert(rgn->base == r1.base);
- assert(rgn->size == total_size);
+ ASSERT_EQ(rgn->base, r1.base);
+ ASSERT_EQ(rgn->size, total_size);
- assert(memblock.reserved.cnt == 1);
- assert(memblock.reserved.total_size == total_size);
+ ASSERT_EQ(memblock.reserved.cnt, 1);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
return 0;
}
.size = SZ_1M
};
+ PREFIX_PUSH();
+
r1_size = r2.base - r1.base;
r2_size = (r1.base + r1.size) - (r2.base + r2.size);
total_size = r1_size + r2_size;
memblock_reserve(r1.base, r1.size);
memblock_free((void *)r2.base, r2.size);
- assert(rgn1->base == r1.base);
- assert(rgn1->size == r1_size);
+ ASSERT_EQ(rgn1->base, r1.base);
+ ASSERT_EQ(rgn1->size, r1_size);
- assert(rgn2->base == r2.base + r2.size);
- assert(rgn2->size == r2_size);
+ ASSERT_EQ(rgn2->base, r2.base + r2.size);
+ ASSERT_EQ(rgn2->size, r2_size);
- assert(memblock.reserved.cnt == 2);
- assert(memblock.reserved.total_size == total_size);
+ ASSERT_EQ(memblock.reserved.cnt, 2);
+ ASSERT_EQ(memblock.reserved.total_size, total_size);
+
+ test_pass_pop();
return 0;
}
static int memblock_free_checks(void)
{
+ prefix_reset();
+ prefix_push(FUNC_FREE);
+ test_print("Running %s tests...\n", FUNC_FREE);
+
memblock_free_simple_check();
memblock_free_absent_check();
memblock_free_overlap_top_check();
memblock_free_overlap_bottom_check();
memblock_free_within_check();
+ prefix_pop();
+
return 0;
}
// SPDX-License-Identifier: GPL-2.0-or-later
#include "tests/common.h"
#include <string.h>
+#include <getopt.h>
+#include <linux/memory_hotplug.h>
+#include <linux/build_bug.h>
#define INIT_MEMBLOCK_REGIONS 128
#define INIT_MEMBLOCK_RESERVED_REGIONS INIT_MEMBLOCK_REGIONS
+#define PREFIXES_MAX 15
+#define DELIM ": "
static struct test_memory memory_block;
+static const char __maybe_unused *prefixes[PREFIXES_MAX];
+static int __maybe_unused nr_prefixes;
+
+static const char *short_opts = "mv";
+static const struct option long_opts[] = {
+ {"movable-node", 0, NULL, 'm'},
+ {"verbose", 0, NULL, 'v'},
+ {NULL, 0, NULL, 0}
+};
+
+static const char * const help_opts[] = {
+ "disallow allocations from regions marked as hotplugged\n\t\t\t"
+ "by simulating enabling the \"movable_node\" kernel\n\t\t\t"
+ "parameter",
+ "enable verbose output, which includes the name of the\n\t\t\t"
+ "memblock function being tested, the name of the test,\n\t\t\t"
+ "and whether the test passed or failed."
+};
+
+static int verbose;
+
+/* sets global variable returned by movable_node_is_enabled() stub */
+bool movable_node_enabled;
void reset_memblock_regions(void)
{
{
free(memory_block.base);
}
+
+static void usage(const char *prog)
+{
+ BUILD_BUG_ON(ARRAY_SIZE(help_opts) != ARRAY_SIZE(long_opts) - 1);
+
+ printf("Usage: %s [-%s]\n", prog, short_opts);
+
+ for (int i = 0; long_opts[i].name; i++) {
+ printf(" -%c, --%-12s\t%s\n", long_opts[i].val,
+ long_opts[i].name, help_opts[i]);
+ }
+
+ exit(1);
+}
+
+void parse_args(int argc, char **argv)
+{
+ int c;
+
+ while ((c = getopt_long_only(argc, argv, short_opts, long_opts,
+ NULL)) != -1) {
+ switch (c) {
+ case 'm':
+ movable_node_enabled = true;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+}
+
+void print_prefixes(const char *postfix)
+{
+ for (int i = 0; i < nr_prefixes; i++)
+ test_print("%s%s", prefixes[i], DELIM);
+ test_print(postfix);
+}
+
+void test_fail(void)
+{
+ if (verbose) {
+ ksft_test_result_fail(": ");
+ print_prefixes("failed\n");
+ }
+}
+
+void test_pass(void)
+{
+ if (verbose) {
+ ksft_test_result_pass(": ");
+ print_prefixes("passed\n");
+ }
+}
+
+void test_print(const char *fmt, ...)
+{
+ if (verbose) {
+ int saved_errno = errno;
+ va_list args;
+
+ va_start(args, fmt);
+ errno = saved_errno;
+ vprintf(fmt, args);
+ va_end(args);
+ }
+}
+
+void prefix_reset(void)
+{
+ memset(prefixes, 0, PREFIXES_MAX * sizeof(char *));
+ nr_prefixes = 0;
+}
+
+void prefix_push(const char *prefix)
+{
+ assert(nr_prefixes < PREFIXES_MAX);
+ prefixes[nr_prefixes] = prefix;
+ nr_prefixes++;
+}
+
+void prefix_pop(void)
+{
+ if (nr_prefixes > 0) {
+ prefixes[nr_prefixes - 1] = 0;
+ nr_prefixes--;
+ }
+}
#include <linux/types.h>
#include <linux/memblock.h>
#include <linux/sizes.h>
+#include <linux/printk.h>
+#include <../selftests/kselftest.h>
#define MEM_SIZE SZ_16K
+/**
+ * ASSERT_EQ():
+ * Check the condition
+ * @_expected == @_seen
+ * If false, print failed test message (if in VERBOSE mode) and then assert
+ */
+#define ASSERT_EQ(_expected, _seen) do { \
+ if ((_expected) != (_seen)) \
+ test_fail(); \
+ assert((_expected) == (_seen)); \
+} while (0)
+
+/**
+ * ASSERT_NE():
+ * Check the condition
+ * @_expected != @_seen
+ * If false, print failed test message (if in VERBOSE mode) and then assert
+ */
+#define ASSERT_NE(_expected, _seen) do { \
+ if ((_expected) == (_seen)) \
+ test_fail(); \
+ assert((_expected) != (_seen)); \
+} while (0)
+
+/**
+ * ASSERT_LT():
+ * Check the condition
+ * @_expected < @_seen
+ * If false, print failed test message (if in VERBOSE mode) and then assert
+ */
+#define ASSERT_LT(_expected, _seen) do { \
+ if ((_expected) >= (_seen)) \
+ test_fail(); \
+ assert((_expected) < (_seen)); \
+} while (0)
+
+#define PREFIX_PUSH() prefix_push(__func__)
+
/*
* Available memory registered with memblock needs to be valid for allocs
* test to run. This is a convenience wrapper for memory allocated in
void setup_memblock(void);
void dummy_physical_memory_init(void);
void dummy_physical_memory_cleanup(void);
+void parse_args(int argc, char **argv);
+
+void test_fail(void);
+void test_pass(void);
+void test_print(const char *fmt, ...);
+void prefix_reset(void);
+void prefix_push(const char *prefix);
+void prefix_pop(void);
+
+static inline void test_pass_pop(void)
+{
+ test_pass();
+ prefix_pop();
+}
#endif
#include <stdint.h>
#include <dirent.h>
#include <libintl.h>
+#include <limits.h>
#include <ctype.h>
#include <time.h>
#include <syslog.h>
{
FILE *fd;
int ret = -1;
- char filepath[256];
+ char filepath[PATH_MAX + 2]; /* NUL and '/' */
- snprintf(filepath, 256, "%s/%s", path, filename);
+ snprintf(filepath, sizeof(filepath), "%s/%s", path, filename);
fd = fopen(filepath, "w");
if (!fd) {
{
FILE *fd;
int ret = -1;
- char filepath[256];
+ char filepath[PATH_MAX + 2]; /* NUL and '/' */
- snprintf(filepath, 256, "%s/%s", path, filename);
+ snprintf(filepath, sizeof(filepath), "%s/%s", path, filename);
fd = fopen(filepath, "r");
if (!fd) {
{
FILE *fd;
int ret = -1;
- char filepath[256];
+ char filepath[PATH_MAX + 2]; /* NUL and '/' */
- snprintf(filepath, 256, "%s/%s", path, filename);
+ snprintf(filepath, sizeof(filepath), "%s/%s", path, filename);
fd = fopen(filepath, "r");
if (!fd) {
{
unsigned long trip_instance = 0;
char cdev_name_linked[256];
- char cdev_name[256];
- char cdev_trip_name[256];
+ char cdev_name[PATH_MAX];
+ char cdev_trip_name[PATH_MAX];
int cdev_id;
if (nl->d_type == DT_LNK) {
return -EINVAL;
}
/* find the link to real cooling device record binding */
- snprintf(cdev_name, 256, "%s/%s", tz_name, nl->d_name);
+ snprintf(cdev_name, sizeof(cdev_name) - 2, "%s/%s",
+ tz_name, nl->d_name);
memset(cdev_name_linked, 0, sizeof(cdev_name_linked));
if (readlink(cdev_name, cdev_name_linked,
sizeof(cdev_name_linked) - 1) != -1) {
/* find the trip point in which the cdev is binded to
* in this tzone
*/
- snprintf(cdev_trip_name, 256, "%s%s", nl->d_name,
- "_trip_point");
+ snprintf(cdev_trip_name, sizeof(cdev_trip_name) - 1,
+ "%s%s", nl->d_name, "_trip_point");
sysfs_get_ulong(tz_name, cdev_trip_name,
&trip_instance);
/* validate trip point range, e.g. trip could return -1